mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'soc-drivers-6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC driver updates from Arnd Bergmann:
"These are changes to SoC specific drivers and DT bindings that don't
have a separate subsystem tree, or that get grouped here for
simplicity.
Nothing out of the ordinary for the 6.14 release here:
- Most of the updates are for Qualcomm specific drivers, adding
support for additional SoCs in the exssting drivers, and support
for wrapped encryption key access in the SCM firmware.
- The Arm SCMI firmware code gains support for having multiple
instances of firmware running, and better module auto loading.
- A few minor updates for litex, samsung, ti, tegra, mediatek, imx
and renesas platforms.
- Reset controller updates for amlogic, to add support for the A1 soc
and clean up the existing code.
- Memory controller updates for ti davinci aemif, refactoring the
code and adding a few interfaces to other drivers"
* tag 'soc-drivers-6.14' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (58 commits)
drivers/soc/litex: Use devm_register_restart_handler()
reset: amlogic: aux: drop aux registration helper
reset: amlogic: aux: get regmap through parent device
reset: amlogic: add support for A1 SoC in auxiliary reset driver
dt-bindings: reset: add bindings for A1 SoC audio reset controller
soc/tegra: fuse: Update Tegra234 nvmem keepout list
soc/tegra: Fix spelling error in tegra234_lookup_slave_timeout()
soc/tegra: cbb: Drop unnecessary debugfs error handling
firmware: qcom: scm: add calls for wrapped key support
soc: qcom: pd_mapper: Add SM7225 compatible
dt-bindings: firmware: qcom,scm: Document ipq5424 SCM
soc: qcom: llcc: Update configuration data for IPQ5424
dt-bindings: cache: qcom,llcc: Add IPQ5424 compatible
soc: mediatek: mtk-devapc: Fix leaking IO map on driver remove
soc: mediatek: mtk-devapc: Fix leaking IO map on error paths
firmware: qcom: scm: smc: Narrow 'mempool' variable scope
firmware: qcom: scm: smc: Handle missing SCM device
firmware: qcom: scm: Cleanup global '__scm' on probe failures
firmware: qcom: scm: Fix missing read barrier in qcom_scm_get_tzmem_pool()
firmware: qcom: scm: Fix missing read barrier in qcom_scm_is_available()
...
This commit is contained in:
@@ -20,6 +20,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,ipq5424-llcc
|
||||
- qcom,qcs615-llcc
|
||||
- qcom,qcs8300-llcc
|
||||
- qcom,qdu1000-llcc
|
||||
@@ -42,11 +43,11 @@ properties:
|
||||
- qcom,x1e80100-llcc
|
||||
|
||||
reg:
|
||||
minItems: 2
|
||||
minItems: 1
|
||||
maxItems: 10
|
||||
|
||||
reg-names:
|
||||
minItems: 2
|
||||
minItems: 1
|
||||
maxItems: 10
|
||||
|
||||
interrupts:
|
||||
@@ -66,6 +67,21 @@ required:
|
||||
- reg-names
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,ipq5424-llcc
|
||||
then:
|
||||
properties:
|
||||
reg:
|
||||
items:
|
||||
- description: LLCC0 base register region
|
||||
reg-names:
|
||||
items:
|
||||
- const: llcc0_base
|
||||
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
|
||||
@@ -26,6 +26,7 @@ properties:
|
||||
- qcom,scm-ipq4019
|
||||
- qcom,scm-ipq5018
|
||||
- qcom,scm-ipq5332
|
||||
- qcom,scm-ipq5424
|
||||
- qcom,scm-ipq6018
|
||||
- qcom,scm-ipq806x
|
||||
- qcom,scm-ipq8074
|
||||
@@ -42,6 +43,7 @@ properties:
|
||||
- qcom,scm-msm8996
|
||||
- qcom,scm-msm8998
|
||||
- qcom,scm-qcm2290
|
||||
- qcom,scm-qcs615
|
||||
- qcom,scm-qcs8300
|
||||
- qcom,scm-qdu1000
|
||||
- qcom,scm-sa8255p
|
||||
|
||||
@@ -26,6 +26,7 @@ properties:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,qcm2290-cpu-bwmon
|
||||
- qcom,qcs615-cpu-bwmon
|
||||
- qcom,qcs8300-cpu-bwmon
|
||||
- qcom,sa8775p-cpu-bwmon
|
||||
- qcom,sc7180-cpu-bwmon
|
||||
@@ -41,6 +42,7 @@ properties:
|
||||
- const: qcom,sdm845-bwmon # BWMON v4, unified register space
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,qcs615-llcc-bwmon
|
||||
- qcom,qcs8300-llcc-bwmon
|
||||
- qcom,sa8775p-llcc-bwmon
|
||||
- qcom,sc7180-llcc-bwmon
|
||||
|
||||
@@ -25,6 +25,7 @@ properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- qcom,qcs615-aoss-qmp
|
||||
- qcom,qcs8300-aoss-qmp
|
||||
- qcom,qdu1000-aoss-qmp
|
||||
- qcom,sa8255p-aoss-qmp
|
||||
|
||||
@@ -64,6 +64,7 @@ properties:
|
||||
|
||||
samsung,mode:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
enum: [0, 1, 2, 3]
|
||||
description:
|
||||
Selects USI function (which serial protocol to use). Refer to
|
||||
<include/dt-bindings/soc/samsung,exynos-usi.h> for valid USI mode values.
|
||||
|
||||
@@ -21,6 +21,10 @@ properties:
|
||||
- samsung,exynos3-sysreg
|
||||
- samsung,exynos4-sysreg
|
||||
- samsung,exynos5-sysreg
|
||||
- samsung,exynos8895-fsys0-sysreg
|
||||
- samsung,exynos8895-fsys1-sysreg
|
||||
- samsung,exynos8895-peric0-sysreg
|
||||
- samsung,exynos8895-peric1-sysreg
|
||||
- samsung,exynosautov920-peric0-sysreg
|
||||
- samsung,exynosautov920-peric1-sysreg
|
||||
- tesla,fsd-cam-sysreg
|
||||
@@ -79,6 +83,10 @@ allOf:
|
||||
- samsung,exynos850-cmgp-sysreg
|
||||
- samsung,exynos850-peri-sysreg
|
||||
- samsung,exynos850-sysreg
|
||||
- samsung,exynos8895-fsys0-sysreg
|
||||
- samsung,exynos8895-fsys1-sysreg
|
||||
- samsung,exynos8895-peric0-sysreg
|
||||
- samsung,exynos8895-peric1-sysreg
|
||||
then:
|
||||
required:
|
||||
- clocks
|
||||
|
||||
@@ -23661,6 +23661,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git
|
||||
F: Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml
|
||||
F: drivers/pmdomain/ti/omap_prm.c
|
||||
F: drivers/soc/ti/*
|
||||
F: include/linux/pruss_driver.h
|
||||
|
||||
TI LM49xxx FAMILY ASoC CODEC DRIVERS
|
||||
M: M R Swami Reddy <mr.swami.reddy@ti.com>
|
||||
|
||||
@@ -442,7 +442,7 @@ struct scmi_transport_core_operations {
|
||||
*/
|
||||
struct scmi_transport {
|
||||
struct device *supplier;
|
||||
struct scmi_desc *desc;
|
||||
struct scmi_desc desc;
|
||||
struct scmi_transport_core_operations **core_ops;
|
||||
};
|
||||
|
||||
@@ -468,7 +468,7 @@ static int __tag##_probe(struct platform_device *pdev) \
|
||||
device_set_of_node_from_dev(&spdev->dev, dev); \
|
||||
\
|
||||
strans.supplier = dev; \
|
||||
strans.desc = &(__desc); \
|
||||
memcpy(&strans.desc, &(__desc), sizeof(strans.desc)); \
|
||||
strans.core_ops = &(__core_ops); \
|
||||
\
|
||||
ret = platform_device_add_data(spdev, &strans, sizeof(strans)); \
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/io-64-nonatomic-hi-lo.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/list.h>
|
||||
@@ -43,6 +44,8 @@
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/scmi.h>
|
||||
|
||||
#define SCMI_VENDOR_MODULE_ALIAS_FMT "scmi-protocol-0x%02x-%s"
|
||||
|
||||
static DEFINE_IDA(scmi_id);
|
||||
|
||||
static DEFINE_XARRAY(scmi_protocols);
|
||||
@@ -275,6 +278,44 @@ scmi_vendor_protocol_lookup(int protocol_id, char *vendor_id,
|
||||
return proto;
|
||||
}
|
||||
|
||||
static const struct scmi_protocol *
|
||||
scmi_vendor_protocol_get(int protocol_id, struct scmi_revision_info *version)
|
||||
{
|
||||
const struct scmi_protocol *proto;
|
||||
|
||||
proto = scmi_vendor_protocol_lookup(protocol_id, version->vendor_id,
|
||||
version->sub_vendor_id,
|
||||
version->impl_ver);
|
||||
if (!proto) {
|
||||
int ret;
|
||||
|
||||
pr_debug("Looking for '" SCMI_VENDOR_MODULE_ALIAS_FMT "'\n",
|
||||
protocol_id, version->vendor_id);
|
||||
|
||||
/* Note that vendor_id is mandatory for vendor protocols */
|
||||
ret = request_module(SCMI_VENDOR_MODULE_ALIAS_FMT,
|
||||
protocol_id, version->vendor_id);
|
||||
if (ret) {
|
||||
pr_warn("Problem loading module for protocol 0x%x\n",
|
||||
protocol_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Lookup again, once modules loaded */
|
||||
proto = scmi_vendor_protocol_lookup(protocol_id,
|
||||
version->vendor_id,
|
||||
version->sub_vendor_id,
|
||||
version->impl_ver);
|
||||
}
|
||||
|
||||
if (proto)
|
||||
pr_info("Loaded SCMI Vendor Protocol 0x%x - %s %s %X\n",
|
||||
protocol_id, proto->vendor_id ?: "",
|
||||
proto->sub_vendor_id ?: "", proto->impl_ver);
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
static const struct scmi_protocol *
|
||||
scmi_protocol_get(int protocol_id, struct scmi_revision_info *version)
|
||||
{
|
||||
@@ -283,10 +324,8 @@ scmi_protocol_get(int protocol_id, struct scmi_revision_info *version)
|
||||
if (protocol_id < SCMI_PROTOCOL_VENDOR_BASE)
|
||||
proto = xa_load(&scmi_protocols, protocol_id);
|
||||
else
|
||||
proto = scmi_vendor_protocol_lookup(protocol_id,
|
||||
version->vendor_id,
|
||||
version->sub_vendor_id,
|
||||
version->impl_ver);
|
||||
proto = scmi_vendor_protocol_get(protocol_id, version);
|
||||
|
||||
if (!proto || !try_module_get(proto->owner)) {
|
||||
pr_warn("SCMI Protocol 0x%x not found!\n", protocol_id);
|
||||
return NULL;
|
||||
@@ -294,11 +333,6 @@ scmi_protocol_get(int protocol_id, struct scmi_revision_info *version)
|
||||
|
||||
pr_debug("Found SCMI Protocol 0x%x\n", protocol_id);
|
||||
|
||||
if (protocol_id >= SCMI_PROTOCOL_VENDOR_BASE)
|
||||
pr_info("Loaded SCMI Vendor Protocol 0x%x - %s %s %X\n",
|
||||
protocol_id, proto->vendor_id ?: "",
|
||||
proto->sub_vendor_id ?: "", proto->impl_ver);
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
@@ -366,7 +400,9 @@ int scmi_protocol_register(const struct scmi_protocol *proto)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pr_debug("Registered SCMI Protocol 0x%x\n", proto->id);
|
||||
pr_debug("Registered SCMI Protocol 0x%x - %s %s 0x%08X\n",
|
||||
proto->id, proto->vendor_id, proto->sub_vendor_id,
|
||||
proto->impl_ver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -3028,7 +3064,7 @@ static const struct scmi_desc *scmi_transport_setup(struct device *dev)
|
||||
int ret;
|
||||
|
||||
trans = dev_get_platdata(dev);
|
||||
if (!trans || !trans->desc || !trans->supplier || !trans->core_ops)
|
||||
if (!trans || !trans->supplier || !trans->core_ops)
|
||||
return NULL;
|
||||
|
||||
if (!device_link_add(dev, trans->supplier, DL_FLAG_AUTOREMOVE_CONSUMER)) {
|
||||
@@ -3043,33 +3079,33 @@ static const struct scmi_desc *scmi_transport_setup(struct device *dev)
|
||||
dev_info(dev, "Using %s\n", dev_driver_string(trans->supplier));
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "arm,max-rx-timeout-ms",
|
||||
&trans->desc->max_rx_timeout_ms);
|
||||
&trans->desc.max_rx_timeout_ms);
|
||||
if (ret && ret != -EINVAL)
|
||||
dev_err(dev, "Malformed arm,max-rx-timeout-ms DT property.\n");
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "arm,max-msg-size",
|
||||
&trans->desc->max_msg_size);
|
||||
&trans->desc.max_msg_size);
|
||||
if (ret && ret != -EINVAL)
|
||||
dev_err(dev, "Malformed arm,max-msg-size DT property.\n");
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "arm,max-msg",
|
||||
&trans->desc->max_msg);
|
||||
&trans->desc.max_msg);
|
||||
if (ret && ret != -EINVAL)
|
||||
dev_err(dev, "Malformed arm,max-msg DT property.\n");
|
||||
|
||||
dev_info(dev,
|
||||
"SCMI max-rx-timeout: %dms / max-msg-size: %dbytes / max-msg: %d\n",
|
||||
trans->desc->max_rx_timeout_ms, trans->desc->max_msg_size,
|
||||
trans->desc->max_msg);
|
||||
trans->desc.max_rx_timeout_ms, trans->desc.max_msg_size,
|
||||
trans->desc.max_msg);
|
||||
|
||||
/* System wide atomic threshold for atomic ops .. if any */
|
||||
if (!of_property_read_u32(dev->of_node, "atomic-threshold-us",
|
||||
&trans->desc->atomic_threshold))
|
||||
&trans->desc.atomic_threshold))
|
||||
dev_info(dev,
|
||||
"SCMI System wide atomic threshold set to %u us\n",
|
||||
trans->desc->atomic_threshold);
|
||||
trans->desc.atomic_threshold);
|
||||
|
||||
return trans->desc;
|
||||
return &trans->desc;
|
||||
}
|
||||
|
||||
static int scmi_probe(struct platform_device *pdev)
|
||||
|
||||
@@ -378,6 +378,7 @@ static const struct of_device_id scmi_of_match[] = {
|
||||
{ .compatible = "arm,scmi" },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, scmi_of_match);
|
||||
|
||||
DEFINE_SCMI_TRANSPORT_DRIVER(scmi_mailbox, scmi_mailbox_driver,
|
||||
scmi_mailbox_desc, scmi_of_match, core);
|
||||
|
||||
@@ -301,6 +301,7 @@ static const struct of_device_id scmi_of_match[] = {
|
||||
{ .compatible = "qcom,scmi-smc" },
|
||||
{ /* Sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, scmi_of_match);
|
||||
|
||||
DEFINE_SCMI_TRANSPORT_DRIVER(scmi_smc, scmi_smc_driver, scmi_smc_desc,
|
||||
scmi_of_match, core);
|
||||
|
||||
@@ -921,6 +921,7 @@ static const struct virtio_device_id id_table[] = {
|
||||
{ VIRTIO_ID_SCMI, VIRTIO_DEV_ANY_ID },
|
||||
{ 0 }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(virtio, id_table);
|
||||
|
||||
static struct virtio_driver virtio_scmi_driver = {
|
||||
.driver.name = "scmi-virtio",
|
||||
|
||||
@@ -374,10 +374,11 @@ static const struct scmi_protocol scmi_imx_bbm = {
|
||||
.ops = &scmi_imx_bbm_proto_ops,
|
||||
.events = &scmi_imx_bbm_protocol_events,
|
||||
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||
.vendor_id = "NXP",
|
||||
.sub_vendor_id = "IMX",
|
||||
.vendor_id = SCMI_IMX_VENDOR,
|
||||
.sub_vendor_id = SCMI_IMX_SUBVENDOR,
|
||||
};
|
||||
module_scmi_protocol(scmi_imx_bbm);
|
||||
|
||||
MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_BBM) "-" SCMI_IMX_VENDOR);
|
||||
MODULE_DESCRIPTION("i.MX SCMI BBM driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -309,10 +309,11 @@ static const struct scmi_protocol scmi_imx_misc = {
|
||||
.ops = &scmi_imx_misc_proto_ops,
|
||||
.events = &scmi_imx_misc_protocol_events,
|
||||
.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,
|
||||
.vendor_id = "NXP",
|
||||
.sub_vendor_id = "IMX",
|
||||
.vendor_id = SCMI_IMX_VENDOR,
|
||||
.sub_vendor_id = SCMI_IMX_SUBVENDOR,
|
||||
};
|
||||
module_scmi_protocol(scmi_imx_misc);
|
||||
|
||||
MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_MISC) "-" SCMI_IMX_VENDOR);
|
||||
MODULE_DESCRIPTION("i.MX SCMI MISC driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -152,7 +152,6 @@ int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
|
||||
enum qcom_scm_convention qcom_convention,
|
||||
struct qcom_scm_res *res, bool atomic)
|
||||
{
|
||||
struct qcom_tzmem_pool *mempool = qcom_scm_get_tzmem_pool();
|
||||
int arglen = desc->arginfo & 0xf;
|
||||
int i, ret;
|
||||
void *args_virt __free(qcom_tzmem) = NULL;
|
||||
@@ -173,6 +172,11 @@ int __scm_smc_call(struct device *dev, const struct qcom_scm_desc *desc,
|
||||
smc.args[i + SCM_SMC_FIRST_REG_IDX] = desc->args[i];
|
||||
|
||||
if (unlikely(arglen > SCM_SMC_N_REG_ARGS)) {
|
||||
struct qcom_tzmem_pool *mempool = qcom_scm_get_tzmem_pool();
|
||||
|
||||
if (!mempool)
|
||||
return -EINVAL;
|
||||
|
||||
args_virt = qcom_tzmem_alloc(mempool,
|
||||
SCM_SMC_N_EXT_ARGS * sizeof(u64),
|
||||
flag);
|
||||
|
||||
@@ -217,7 +217,10 @@ static DEFINE_SPINLOCK(scm_query_lock);
|
||||
|
||||
struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void)
|
||||
{
|
||||
return __scm ? __scm->mempool : NULL;
|
||||
if (!qcom_scm_is_available())
|
||||
return NULL;
|
||||
|
||||
return __scm->mempool;
|
||||
}
|
||||
|
||||
static enum qcom_scm_convention __get_convention(void)
|
||||
@@ -1279,6 +1282,220 @@ int qcom_scm_ice_set_key(u32 index, const u8 *key, u32 key_size,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_ice_set_key);
|
||||
|
||||
bool qcom_scm_has_wrapped_key_support(void)
|
||||
{
|
||||
return __qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
|
||||
QCOM_SCM_ES_DERIVE_SW_SECRET) &&
|
||||
__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
|
||||
QCOM_SCM_ES_GENERATE_ICE_KEY) &&
|
||||
__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
|
||||
QCOM_SCM_ES_PREPARE_ICE_KEY) &&
|
||||
__qcom_scm_is_call_available(__scm->dev, QCOM_SCM_SVC_ES,
|
||||
QCOM_SCM_ES_IMPORT_ICE_KEY);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_has_wrapped_key_support);
|
||||
|
||||
/**
|
||||
* qcom_scm_derive_sw_secret() - Derive software secret from wrapped key
|
||||
* @eph_key: an ephemerally-wrapped key
|
||||
* @eph_key_size: size of @eph_key in bytes
|
||||
* @sw_secret: output buffer for the software secret
|
||||
* @sw_secret_size: size of the software secret to derive in bytes
|
||||
*
|
||||
* Derive a software secret from an ephemerally-wrapped key for software crypto
|
||||
* operations. This is done by calling into the secure execution environment,
|
||||
* which then calls into the hardware to unwrap and derive the secret.
|
||||
*
|
||||
* For more information on sw_secret, see the "Hardware-wrapped keys" section of
|
||||
* Documentation/block/inline-encryption.rst.
|
||||
*
|
||||
* Return: 0 on success; -errno on failure.
|
||||
*/
|
||||
int qcom_scm_derive_sw_secret(const u8 *eph_key, size_t eph_key_size,
|
||||
u8 *sw_secret, size_t sw_secret_size)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_ES,
|
||||
.cmd = QCOM_SCM_ES_DERIVE_SW_SECRET,
|
||||
.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RW, QCOM_SCM_VAL,
|
||||
QCOM_SCM_RW, QCOM_SCM_VAL),
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
int ret;
|
||||
|
||||
void *eph_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
eph_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!eph_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
void *sw_secret_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
sw_secret_size,
|
||||
GFP_KERNEL);
|
||||
if (!sw_secret_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(eph_key_buf, eph_key, eph_key_size);
|
||||
desc.args[0] = qcom_tzmem_to_phys(eph_key_buf);
|
||||
desc.args[1] = eph_key_size;
|
||||
desc.args[2] = qcom_tzmem_to_phys(sw_secret_buf);
|
||||
desc.args[3] = sw_secret_size;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
if (!ret)
|
||||
memcpy(sw_secret, sw_secret_buf, sw_secret_size);
|
||||
|
||||
memzero_explicit(eph_key_buf, eph_key_size);
|
||||
memzero_explicit(sw_secret_buf, sw_secret_size);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_derive_sw_secret);
|
||||
|
||||
/**
|
||||
* qcom_scm_generate_ice_key() - Generate a wrapped key for storage encryption
|
||||
* @lt_key: output buffer for the long-term wrapped key
|
||||
* @lt_key_size: size of @lt_key in bytes. Must be the exact wrapped key size
|
||||
* used by the SoC.
|
||||
*
|
||||
* Generate a key using the built-in HW module in the SoC. The resulting key is
|
||||
* returned wrapped with the platform-specific Key Encryption Key.
|
||||
*
|
||||
* Return: 0 on success; -errno on failure.
|
||||
*/
|
||||
int qcom_scm_generate_ice_key(u8 *lt_key, size_t lt_key_size)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_ES,
|
||||
.cmd = QCOM_SCM_ES_GENERATE_ICE_KEY,
|
||||
.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL),
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
int ret;
|
||||
|
||||
void *lt_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
lt_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!lt_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
desc.args[0] = qcom_tzmem_to_phys(lt_key_buf);
|
||||
desc.args[1] = lt_key_size;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
if (!ret)
|
||||
memcpy(lt_key, lt_key_buf, lt_key_size);
|
||||
|
||||
memzero_explicit(lt_key_buf, lt_key_size);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_generate_ice_key);
|
||||
|
||||
/**
|
||||
* qcom_scm_prepare_ice_key() - Re-wrap a key with the per-boot ephemeral key
|
||||
* @lt_key: a long-term wrapped key
|
||||
* @lt_key_size: size of @lt_key in bytes
|
||||
* @eph_key: output buffer for the ephemerally-wrapped key
|
||||
* @eph_key_size: size of @eph_key in bytes. Must be the exact wrapped key size
|
||||
* used by the SoC.
|
||||
*
|
||||
* Given a long-term wrapped key, re-wrap it with the per-boot ephemeral key for
|
||||
* added protection. The resulting key will only be valid for the current boot.
|
||||
*
|
||||
* Return: 0 on success; -errno on failure.
|
||||
*/
|
||||
int qcom_scm_prepare_ice_key(const u8 *lt_key, size_t lt_key_size,
|
||||
u8 *eph_key, size_t eph_key_size)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_ES,
|
||||
.cmd = QCOM_SCM_ES_PREPARE_ICE_KEY,
|
||||
.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, QCOM_SCM_VAL,
|
||||
QCOM_SCM_RW, QCOM_SCM_VAL),
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
int ret;
|
||||
|
||||
void *lt_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
lt_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!lt_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
void *eph_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
eph_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!eph_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(lt_key_buf, lt_key, lt_key_size);
|
||||
desc.args[0] = qcom_tzmem_to_phys(lt_key_buf);
|
||||
desc.args[1] = lt_key_size;
|
||||
desc.args[2] = qcom_tzmem_to_phys(eph_key_buf);
|
||||
desc.args[3] = eph_key_size;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
if (!ret)
|
||||
memcpy(eph_key, eph_key_buf, eph_key_size);
|
||||
|
||||
memzero_explicit(lt_key_buf, lt_key_size);
|
||||
memzero_explicit(eph_key_buf, eph_key_size);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_prepare_ice_key);
|
||||
|
||||
/**
|
||||
* qcom_scm_import_ice_key() - Import key for storage encryption
|
||||
* @raw_key: the raw key to import
|
||||
* @raw_key_size: size of @raw_key in bytes
|
||||
* @lt_key: output buffer for the long-term wrapped key
|
||||
* @lt_key_size: size of @lt_key in bytes. Must be the exact wrapped key size
|
||||
* used by the SoC.
|
||||
*
|
||||
* Import a raw key and return a long-term wrapped key. Uses the SoC's HWKM to
|
||||
* wrap the raw key using the platform-specific Key Encryption Key.
|
||||
*
|
||||
* Return: 0 on success; -errno on failure.
|
||||
*/
|
||||
int qcom_scm_import_ice_key(const u8 *raw_key, size_t raw_key_size,
|
||||
u8 *lt_key, size_t lt_key_size)
|
||||
{
|
||||
struct qcom_scm_desc desc = {
|
||||
.svc = QCOM_SCM_SVC_ES,
|
||||
.cmd = QCOM_SCM_ES_IMPORT_ICE_KEY,
|
||||
.arginfo = QCOM_SCM_ARGS(4, QCOM_SCM_RO, QCOM_SCM_VAL,
|
||||
QCOM_SCM_RW, QCOM_SCM_VAL),
|
||||
.owner = ARM_SMCCC_OWNER_SIP,
|
||||
};
|
||||
int ret;
|
||||
|
||||
void *raw_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
raw_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!raw_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
void *lt_key_buf __free(qcom_tzmem) = qcom_tzmem_alloc(__scm->mempool,
|
||||
lt_key_size,
|
||||
GFP_KERNEL);
|
||||
if (!lt_key_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(raw_key_buf, raw_key, raw_key_size);
|
||||
desc.args[0] = qcom_tzmem_to_phys(raw_key_buf);
|
||||
desc.args[1] = raw_key_size;
|
||||
desc.args[2] = qcom_tzmem_to_phys(lt_key_buf);
|
||||
desc.args[3] = lt_key_size;
|
||||
|
||||
ret = qcom_scm_call(__scm->dev, &desc, NULL);
|
||||
if (!ret)
|
||||
memcpy(lt_key, lt_key_buf, lt_key_size);
|
||||
|
||||
memzero_explicit(raw_key_buf, raw_key_size);
|
||||
memzero_explicit(lt_key_buf, lt_key_size);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_import_ice_key);
|
||||
|
||||
/**
|
||||
* qcom_scm_hdcp_available() - Check if secure environment supports HDCP.
|
||||
*
|
||||
@@ -1768,18 +1985,23 @@ EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send);
|
||||
+ any potential issues with this, only allow validated machines for now.
|
||||
*/
|
||||
static const struct of_device_id qcom_scm_qseecom_allowlist[] __maybe_unused = {
|
||||
{ .compatible = "asus,vivobook-s15" },
|
||||
{ .compatible = "dell,xps13-9345" },
|
||||
{ .compatible = "hp,omnibook-x14" },
|
||||
{ .compatible = "huawei,gaokun3" },
|
||||
{ .compatible = "lenovo,flex-5g" },
|
||||
{ .compatible = "lenovo,thinkpad-t14s" },
|
||||
{ .compatible = "lenovo,thinkpad-x13s", },
|
||||
{ .compatible = "lenovo,yoga-slim7x" },
|
||||
{ .compatible = "microsoft,arcata", },
|
||||
{ .compatible = "microsoft,blackrock" },
|
||||
{ .compatible = "microsoft,romulus13", },
|
||||
{ .compatible = "microsoft,romulus15", },
|
||||
{ .compatible = "qcom,sc8180x-primus" },
|
||||
{ .compatible = "qcom,x1e001de-devkit" },
|
||||
{ .compatible = "qcom,x1e80100-crd" },
|
||||
{ .compatible = "qcom,x1e80100-qcp" },
|
||||
{ .compatible = "qcom,x1p42100-crd" },
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -1867,7 +2089,8 @@ static int qcom_scm_qseecom_init(struct qcom_scm *scm)
|
||||
*/
|
||||
bool qcom_scm_is_available(void)
|
||||
{
|
||||
return !!READ_ONCE(__scm);
|
||||
/* Paired with smp_store_release() in qcom_scm_probe */
|
||||
return !!smp_load_acquire(&__scm);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_scm_is_available);
|
||||
|
||||
@@ -2024,18 +2247,22 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Let all above stores be available after this */
|
||||
/* Paired with smp_load_acquire() in qcom_scm_is_available(). */
|
||||
smp_store_release(&__scm, scm);
|
||||
|
||||
irq = platform_get_irq_optional(pdev, 0);
|
||||
if (irq < 0) {
|
||||
if (irq != -ENXIO)
|
||||
return irq;
|
||||
if (irq != -ENXIO) {
|
||||
ret = irq;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
ret = devm_request_threaded_irq(__scm->dev, irq, NULL, qcom_scm_irq_handler,
|
||||
IRQF_ONESHOT, "qcom-scm", __scm);
|
||||
if (ret < 0)
|
||||
return dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n");
|
||||
if (ret < 0) {
|
||||
dev_err_probe(scm->dev, ret, "Failed to request qcom-scm irq\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
__get_convention();
|
||||
@@ -2054,14 +2281,18 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
||||
qcom_scm_disable_sdi();
|
||||
|
||||
ret = of_reserved_mem_device_init(__scm->dev);
|
||||
if (ret && ret != -ENODEV)
|
||||
return dev_err_probe(__scm->dev, ret,
|
||||
"Failed to setup the reserved memory region for TZ mem\n");
|
||||
if (ret && ret != -ENODEV) {
|
||||
dev_err_probe(__scm->dev, ret,
|
||||
"Failed to setup the reserved memory region for TZ mem\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = qcom_tzmem_enable(__scm->dev);
|
||||
if (ret)
|
||||
return dev_err_probe(__scm->dev, ret,
|
||||
"Failed to enable the TrustZone memory allocator\n");
|
||||
if (ret) {
|
||||
dev_err_probe(__scm->dev, ret,
|
||||
"Failed to enable the TrustZone memory allocator\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
memset(&pool_config, 0, sizeof(pool_config));
|
||||
pool_config.initial_size = 0;
|
||||
@@ -2069,9 +2300,11 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
||||
pool_config.max_size = SZ_256K;
|
||||
|
||||
__scm->mempool = devm_qcom_tzmem_pool_new(__scm->dev, &pool_config);
|
||||
if (IS_ERR(__scm->mempool))
|
||||
return dev_err_probe(__scm->dev, PTR_ERR(__scm->mempool),
|
||||
"Failed to create the SCM memory pool\n");
|
||||
if (IS_ERR(__scm->mempool)) {
|
||||
dev_err_probe(__scm->dev, PTR_ERR(__scm->mempool),
|
||||
"Failed to create the SCM memory pool\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the QSEECOM interface.
|
||||
@@ -2087,6 +2320,12 @@ static int qcom_scm_probe(struct platform_device *pdev)
|
||||
WARN(ret < 0, "failed to initialize qseecom: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
/* Paired with smp_load_acquire() in qcom_scm_is_available(). */
|
||||
smp_store_release(&__scm, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void qcom_scm_shutdown(struct platform_device *pdev)
|
||||
|
||||
@@ -128,6 +128,10 @@ struct qcom_tzmem_pool *qcom_scm_get_tzmem_pool(void);
|
||||
#define QCOM_SCM_SVC_ES 0x10 /* Enterprise Security */
|
||||
#define QCOM_SCM_ES_INVALIDATE_ICE_KEY 0x03
|
||||
#define QCOM_SCM_ES_CONFIG_SET_ICE_KEY 0x04
|
||||
#define QCOM_SCM_ES_DERIVE_SW_SECRET 0x07
|
||||
#define QCOM_SCM_ES_GENERATE_ICE_KEY 0x08
|
||||
#define QCOM_SCM_ES_PREPARE_ICE_KEY 0x09
|
||||
#define QCOM_SCM_ES_IMPORT_ICE_KEY 0x0a
|
||||
|
||||
#define QCOM_SCM_SVC_HDCP 0x11
|
||||
#define QCOM_SCM_HDCP_INVOKE 0x01
|
||||
|
||||
@@ -358,17 +358,6 @@ static unsigned int gpmc_ps_to_ticks(unsigned int time_ps)
|
||||
return (time_ps + tick_ps - 1) / tick_ps;
|
||||
}
|
||||
|
||||
static unsigned int gpmc_clk_ticks_to_ns(unsigned int ticks, int cs,
|
||||
enum gpmc_clk_domain cd)
|
||||
{
|
||||
return ticks * gpmc_get_clk_period(cs, cd) / 1000;
|
||||
}
|
||||
|
||||
unsigned int gpmc_ticks_to_ns(unsigned int ticks)
|
||||
{
|
||||
return gpmc_clk_ticks_to_ns(ticks, /* any CS */ 0, GPMC_CD_FCLK);
|
||||
}
|
||||
|
||||
static unsigned int gpmc_ticks_to_ps(unsigned int ticks)
|
||||
{
|
||||
return ticks * gpmc_get_fclk_period();
|
||||
@@ -415,6 +404,13 @@ static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OMAP_GPMC_DEBUG
|
||||
|
||||
static unsigned int gpmc_clk_ticks_to_ns(unsigned int ticks, int cs,
|
||||
enum gpmc_clk_domain cd)
|
||||
{
|
||||
return ticks * gpmc_get_clk_period(cs, cd) / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_gpmc_timing_reg - read a timing parameter and print DTS settings for it.
|
||||
* @cs: Chip Select Region
|
||||
@@ -1295,21 +1291,6 @@ int gpmc_omap_onenand_set_timings(struct device *dev, int cs, int freq,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(gpmc_omap_onenand_set_timings);
|
||||
|
||||
int gpmc_get_client_irq(unsigned int irq_config)
|
||||
{
|
||||
if (!gpmc_irq_domain) {
|
||||
pr_warn("%s called before GPMC IRQ domain available\n",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we restrict this to NAND IRQs only */
|
||||
if (irq_config >= GPMC_NR_NAND_IRQS)
|
||||
return 0;
|
||||
|
||||
return irq_create_mapping(gpmc_irq_domain, irq_config);
|
||||
}
|
||||
|
||||
static int gpmc_irq_endis(unsigned long hwirq, bool endis)
|
||||
{
|
||||
u32 regval;
|
||||
|
||||
@@ -474,14 +474,15 @@ tegra_emc_find_node_by_ram_code(struct tegra_emc *emc)
|
||||
|
||||
ram_code = tegra_read_ram_code();
|
||||
|
||||
for (np = of_find_node_by_name(dev->of_node, "emc-tables"); np;
|
||||
np = of_find_node_by_name(np, "emc-tables")) {
|
||||
for_each_child_of_node(dev->of_node, np) {
|
||||
if (!of_node_name_eq(np, "emc-tables"))
|
||||
continue;
|
||||
err = of_property_read_u32(np, "nvidia,ram-code", &value);
|
||||
if (err || value != ram_code) {
|
||||
struct device_node *lpddr2_np;
|
||||
bool cfg_mismatches = false;
|
||||
|
||||
lpddr2_np = of_find_node_by_name(np, "lpddr2");
|
||||
lpddr2_np = of_get_child_by_name(np, "lpddr2");
|
||||
if (lpddr2_np) {
|
||||
const struct lpddr2_info *info;
|
||||
|
||||
@@ -518,7 +519,6 @@ tegra_emc_find_node_by_ram_code(struct tegra_emc *emc)
|
||||
}
|
||||
|
||||
if (cfg_mismatches) {
|
||||
of_node_put(np);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/memory/ti-aemif.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/platform_device.h>
|
||||
@@ -69,39 +71,27 @@
|
||||
#define ACR_SSTROBE_MASK BIT(31)
|
||||
#define ASIZE_16BIT 1
|
||||
|
||||
#define CONFIG_MASK (TA(TA_MAX) | \
|
||||
RHOLD(RHOLD_MAX) | \
|
||||
RSTROBE(RSTROBE_MAX) | \
|
||||
RSETUP(RSETUP_MAX) | \
|
||||
WHOLD(WHOLD_MAX) | \
|
||||
WSTROBE(WSTROBE_MAX) | \
|
||||
WSETUP(WSETUP_MAX) | \
|
||||
EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | \
|
||||
ASIZE_MAX)
|
||||
#define TIMINGS_MASK (TA(TA_MAX) | \
|
||||
RHOLD(RHOLD_MAX) | \
|
||||
RSTROBE(RSTROBE_MAX) | \
|
||||
RSETUP(RSETUP_MAX) | \
|
||||
WHOLD(WHOLD_MAX) | \
|
||||
WSTROBE(WSTROBE_MAX) | \
|
||||
WSETUP(WSETUP_MAX))
|
||||
|
||||
#define CONFIG_MASK (EW(EW_MAX) | SSTROBE(SSTROBE_MAX) | ASIZE_MAX)
|
||||
|
||||
/**
|
||||
* struct aemif_cs_data: structure to hold cs parameters
|
||||
* struct aemif_cs_data: structure to hold CS parameters
|
||||
* @timings: timings configuration
|
||||
* @cs: chip-select number
|
||||
* @wstrobe: write strobe width, ns
|
||||
* @rstrobe: read strobe width, ns
|
||||
* @wsetup: write setup width, ns
|
||||
* @whold: write hold width, ns
|
||||
* @rsetup: read setup width, ns
|
||||
* @rhold: read hold width, ns
|
||||
* @ta: minimum turn around time, ns
|
||||
* @enable_ss: enable/disable select strobe mode
|
||||
* @enable_ew: enable/disable extended wait mode
|
||||
* @asize: width of the asynchronous device's data bus
|
||||
*/
|
||||
struct aemif_cs_data {
|
||||
struct aemif_cs_timings timings;
|
||||
u8 cs;
|
||||
u16 wstrobe;
|
||||
u16 rstrobe;
|
||||
u8 wsetup;
|
||||
u8 whold;
|
||||
u8 rsetup;
|
||||
u8 rhold;
|
||||
u8 ta;
|
||||
u8 enable_ss;
|
||||
u8 enable_ew;
|
||||
u8 asize;
|
||||
@@ -115,6 +105,7 @@ struct aemif_cs_data {
|
||||
* @num_cs: number of assigned chip-selects
|
||||
* @cs_offset: start number of cs nodes
|
||||
* @cs_data: array of chip-select settings
|
||||
* @config_cs_lock: lock used to access CS configuration
|
||||
*/
|
||||
struct aemif_device {
|
||||
void __iomem *base;
|
||||
@@ -123,20 +114,94 @@ struct aemif_device {
|
||||
u8 num_cs;
|
||||
int cs_offset;
|
||||
struct aemif_cs_data cs_data[NUM_CS];
|
||||
struct mutex config_cs_lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* aemif_check_cs_timings() - Check the validity of a CS timing configuration.
|
||||
* @timings: timings configuration
|
||||
*
|
||||
* @return: 0 if the timing configuration is valid, negative error number otherwise.
|
||||
*/
|
||||
int aemif_check_cs_timings(struct aemif_cs_timings *timings)
|
||||
{
|
||||
if (timings->ta > TA_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->rhold > RHOLD_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->rstrobe > RSTROBE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->rsetup > RSETUP_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->whold > WHOLD_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->wstrobe > WSTROBE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
if (timings->wsetup > WSETUP_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(aemif_check_cs_timings);
|
||||
|
||||
/**
|
||||
* aemif_set_cs_timings() - Set the timing configuration of a given chip select.
|
||||
* @aemif: aemif device to configure
|
||||
* @cs: index of the chip select to configure
|
||||
* @timings: timings configuration to set
|
||||
*
|
||||
* @return: 0 on success, else negative errno.
|
||||
*/
|
||||
int aemif_set_cs_timings(struct aemif_device *aemif, u8 cs,
|
||||
struct aemif_cs_timings *timings)
|
||||
{
|
||||
unsigned int offset;
|
||||
u32 val, set;
|
||||
int ret;
|
||||
|
||||
if (!timings || !aemif)
|
||||
return -EINVAL;
|
||||
|
||||
if (cs > aemif->num_cs)
|
||||
return -EINVAL;
|
||||
|
||||
ret = aemif_check_cs_timings(timings);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
set = TA(timings->ta) | RHOLD(timings->rhold) | RSTROBE(timings->rstrobe) |
|
||||
RSETUP(timings->rsetup) | WHOLD(timings->whold) |
|
||||
WSTROBE(timings->wstrobe) | WSETUP(timings->wsetup);
|
||||
|
||||
offset = A1CR_OFFSET + cs * 4;
|
||||
|
||||
mutex_lock(&aemif->config_cs_lock);
|
||||
val = readl(aemif->base + offset);
|
||||
val &= ~TIMINGS_MASK;
|
||||
val |= set;
|
||||
writel(val, aemif->base + offset);
|
||||
mutex_unlock(&aemif->config_cs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(aemif_set_cs_timings);
|
||||
|
||||
/**
|
||||
* aemif_calc_rate - calculate timing data.
|
||||
* @pdev: platform device to calculate for
|
||||
* @wanted: The cycle time needed in nanoseconds.
|
||||
* @clk: The input clock rate in kHz.
|
||||
* @max: The maximum divider value that can be programmed.
|
||||
*
|
||||
* On success, returns the calculated timing value minus 1 for easy
|
||||
* programming into AEMIF timing registers, else negative errno.
|
||||
* @return: the calculated timing value minus 1 for easy
|
||||
* programming into AEMIF timing registers.
|
||||
*/
|
||||
static int aemif_calc_rate(struct platform_device *pdev, int wanted,
|
||||
unsigned long clk, int max)
|
||||
static u32 aemif_calc_rate(struct platform_device *pdev, int wanted, unsigned long clk)
|
||||
{
|
||||
int result;
|
||||
|
||||
@@ -149,10 +214,6 @@ static int aemif_calc_rate(struct platform_device *pdev, int wanted,
|
||||
if (result < 0)
|
||||
result = 0;
|
||||
|
||||
/* ... But configuring tighter timings is not an option. */
|
||||
else if (result > max)
|
||||
result = -EINVAL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -174,48 +235,25 @@ static int aemif_config_abus(struct platform_device *pdev, int csnum)
|
||||
{
|
||||
struct aemif_device *aemif = platform_get_drvdata(pdev);
|
||||
struct aemif_cs_data *data = &aemif->cs_data[csnum];
|
||||
int ta, rhold, rstrobe, rsetup, whold, wstrobe, wsetup;
|
||||
unsigned long clk_rate = aemif->clk_rate;
|
||||
unsigned offset;
|
||||
u32 set, val;
|
||||
|
||||
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
|
||||
|
||||
ta = aemif_calc_rate(pdev, data->ta, clk_rate, TA_MAX);
|
||||
rhold = aemif_calc_rate(pdev, data->rhold, clk_rate, RHOLD_MAX);
|
||||
rstrobe = aemif_calc_rate(pdev, data->rstrobe, clk_rate, RSTROBE_MAX);
|
||||
rsetup = aemif_calc_rate(pdev, data->rsetup, clk_rate, RSETUP_MAX);
|
||||
whold = aemif_calc_rate(pdev, data->whold, clk_rate, WHOLD_MAX);
|
||||
wstrobe = aemif_calc_rate(pdev, data->wstrobe, clk_rate, WSTROBE_MAX);
|
||||
wsetup = aemif_calc_rate(pdev, data->wsetup, clk_rate, WSETUP_MAX);
|
||||
|
||||
if (ta < 0 || rhold < 0 || rstrobe < 0 || rsetup < 0 ||
|
||||
whold < 0 || wstrobe < 0 || wsetup < 0) {
|
||||
dev_err(&pdev->dev, "%s: cannot get suitable timings\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
set = TA(ta) | RHOLD(rhold) | RSTROBE(rstrobe) | RSETUP(rsetup) |
|
||||
WHOLD(whold) | WSTROBE(wstrobe) | WSETUP(wsetup);
|
||||
|
||||
set |= (data->asize & ACR_ASIZE_MASK);
|
||||
set = (data->asize & ACR_ASIZE_MASK);
|
||||
if (data->enable_ew)
|
||||
set |= ACR_EW_MASK;
|
||||
if (data->enable_ss)
|
||||
set |= ACR_SSTROBE_MASK;
|
||||
|
||||
mutex_lock(&aemif->config_cs_lock);
|
||||
val = readl(aemif->base + offset);
|
||||
val &= ~CONFIG_MASK;
|
||||
val |= set;
|
||||
writel(val, aemif->base + offset);
|
||||
mutex_unlock(&aemif->config_cs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int aemif_cycles_to_nsec(int val, unsigned long clk_rate)
|
||||
{
|
||||
return ((val + 1) * NSEC_PER_MSEC) / clk_rate;
|
||||
return aemif_set_cs_timings(aemif, data->cs - aemif->cs_offset, &data->timings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,19 +269,18 @@ static void aemif_get_hw_params(struct platform_device *pdev, int csnum)
|
||||
{
|
||||
struct aemif_device *aemif = platform_get_drvdata(pdev);
|
||||
struct aemif_cs_data *data = &aemif->cs_data[csnum];
|
||||
unsigned long clk_rate = aemif->clk_rate;
|
||||
u32 val, offset;
|
||||
|
||||
offset = A1CR_OFFSET + (data->cs - aemif->cs_offset) * 4;
|
||||
val = readl(aemif->base + offset);
|
||||
|
||||
data->ta = aemif_cycles_to_nsec(TA_VAL(val), clk_rate);
|
||||
data->rhold = aemif_cycles_to_nsec(RHOLD_VAL(val), clk_rate);
|
||||
data->rstrobe = aemif_cycles_to_nsec(RSTROBE_VAL(val), clk_rate);
|
||||
data->rsetup = aemif_cycles_to_nsec(RSETUP_VAL(val), clk_rate);
|
||||
data->whold = aemif_cycles_to_nsec(WHOLD_VAL(val), clk_rate);
|
||||
data->wstrobe = aemif_cycles_to_nsec(WSTROBE_VAL(val), clk_rate);
|
||||
data->wsetup = aemif_cycles_to_nsec(WSETUP_VAL(val), clk_rate);
|
||||
data->timings.ta = TA_VAL(val);
|
||||
data->timings.rhold = RHOLD_VAL(val);
|
||||
data->timings.rstrobe = RSTROBE_VAL(val);
|
||||
data->timings.rsetup = RSETUP_VAL(val);
|
||||
data->timings.whold = WHOLD_VAL(val);
|
||||
data->timings.wstrobe = WSTROBE_VAL(val);
|
||||
data->timings.wsetup = WSETUP_VAL(val);
|
||||
data->enable_ew = EW_VAL(val);
|
||||
data->enable_ss = SSTROBE_VAL(val);
|
||||
data->asize = val & ASIZE_MAX;
|
||||
@@ -261,6 +298,7 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
|
||||
struct device_node *np)
|
||||
{
|
||||
struct aemif_device *aemif = platform_get_drvdata(pdev);
|
||||
unsigned long clk_rate = aemif->clk_rate;
|
||||
struct aemif_cs_data *data;
|
||||
u32 cs;
|
||||
u32 val;
|
||||
@@ -288,32 +326,33 @@ static int of_aemif_parse_abus_config(struct platform_device *pdev,
|
||||
|
||||
/* override the values from device node */
|
||||
if (!of_property_read_u32(np, "ti,cs-min-turnaround-ns", &val))
|
||||
data->ta = val;
|
||||
data->timings.ta = aemif_calc_rate(pdev, val, clk_rate);
|
||||
|
||||
if (!of_property_read_u32(np, "ti,cs-read-hold-ns", &val))
|
||||
data->rhold = val;
|
||||
data->timings.rhold = aemif_calc_rate(pdev, val, clk_rate);
|
||||
|
||||
if (!of_property_read_u32(np, "ti,cs-read-strobe-ns", &val))
|
||||
data->rstrobe = val;
|
||||
data->timings.rstrobe = aemif_calc_rate(pdev, val, clk_rate);
|
||||
|
||||
if (!of_property_read_u32(np, "ti,cs-read-setup-ns", &val))
|
||||
data->rsetup = val;
|
||||
data->timings.rsetup = aemif_calc_rate(pdev, val, clk_rate);
|
||||
|
||||
if (!of_property_read_u32(np, "ti,cs-write-hold-ns", &val))
|
||||
data->whold = val;
|
||||
data->timings.whold = aemif_calc_rate(pdev, val, clk_rate);
|
||||
|
||||
if (!of_property_read_u32(np, "ti,cs-write-strobe-ns", &val))
|
||||
data->wstrobe = val;
|
||||
data->timings.wstrobe = aemif_calc_rate(pdev, val, clk_rate);
|
||||
|
||||
if (!of_property_read_u32(np, "ti,cs-write-setup-ns", &val))
|
||||
data->wsetup = val;
|
||||
data->timings.wsetup = aemif_calc_rate(pdev, val, clk_rate);
|
||||
|
||||
if (!of_property_read_u32(np, "ti,cs-bus-width", &val))
|
||||
if (val == 16)
|
||||
data->asize = 1;
|
||||
data->enable_ew = of_property_read_bool(np, "ti,cs-extended-wait-mode");
|
||||
data->enable_ss = of_property_read_bool(np, "ti,cs-select-strobe-mode");
|
||||
return 0;
|
||||
|
||||
return aemif_check_cs_timings(&data->timings);
|
||||
}
|
||||
|
||||
static const struct of_device_id aemif_of_match[] = {
|
||||
@@ -351,6 +390,7 @@ static int aemif_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(aemif->base))
|
||||
return PTR_ERR(aemif->base);
|
||||
|
||||
mutex_init(&aemif->config_cs_lock);
|
||||
if (np) {
|
||||
/*
|
||||
* For every controller device node, there is a cs device node
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user