diff options
author | Arnd Bergmann <arnd@arndb.de> | 2020-07-22 22:35:21 +0200 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2020-07-22 22:35:21 +0200 |
commit | e2837df66837736fab6253133f7b6f9d0e6e0810 (patch) | |
tree | cf1e4cca23828b9b0e715e44e0017a22873012cc /drivers/firmware | |
parent | 9e586c84312778cf132086a296fb96e72aa207fc (diff) | |
parent | d82bcef5157de1368c08244a846ab968b3e5cb7e (diff) | |
download | linux-e2837df66837736fab6253133f7b6f9d0e6e0810.tar.bz2 |
Merge tag 'imx-drivers-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux into arm/drivers
i.MX drivers change for 5.9:
- Update SCU irq code to call pm_system_wakeup() in general MU IRQ
handler, so that system can be waked up when MU IRQ arrives.
- Move i.MX SCU soc driver into imx firmware folder to get it
initialized from i.MX SCU firmware driver.
- Clean up soc-imx-scu driver a bit by using devm_kasprintf().
- Correct postfix setting for cm40 power domain in scu-pd driver.
- Add resource management support for IMX_SCU firmware driver.
- Add more cm4 resources to i.MX SCU power domain driver.
- Select ARM_GIC_V3 from SOC_IMX8M for being able to use GICv3 driver
in AARCH32 mode Linux on AARCH64 hardware.
* tag 'imx-drivers-5.9' of git://git.kernel.org/pub/scm/linux/kernel/git/shawnguo/linux:
soc: imx: select ARM_GIC_V3 for i.MX8M
firmware: imx: Move i.MX SCU soc driver into imx firmware folder
firmware: imx: scu-pd: add more cm4 resources
firmware: imx: add resource management api
firmware: imx: scu-pd: fix cm40 power domain
soc: imx: scu: use devm_kasprintf
firmware: imx: make sure MU irq can wake up system from suspend mode
Link: https://lore.kernel.org/r/20200720085536.24138-1-shawnguo@kernel.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/imx/Makefile | 2 | ||||
-rw-r--r-- | drivers/firmware/imx/imx-scu-irq.c | 2 | ||||
-rw-r--r-- | drivers/firmware/imx/imx-scu-soc.c | 138 | ||||
-rw-r--r-- | drivers/firmware/imx/imx-scu.c | 4 | ||||
-rw-r--r-- | drivers/firmware/imx/rm.c | 45 | ||||
-rw-r--r-- | drivers/firmware/imx/scu-pd.c | 14 |
6 files changed, 202 insertions, 3 deletions
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 08bc9ddfbdfb..b76acbade2a0 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile @@ -1,4 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_IMX_DSP) += imx-dsp.o -obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o +obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c index db655e87cdc8..d9dcc20945c6 100644 --- a/drivers/firmware/imx/imx-scu-irq.c +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -10,6 +10,7 @@ #include <linux/firmware/imx/ipc.h> #include <linux/firmware/imx/sci.h> #include <linux/mailbox_client.h> +#include <linux/suspend.h> #define IMX_SC_IRQ_FUNC_ENABLE 1 #define IMX_SC_IRQ_FUNC_STATUS 2 @@ -91,6 +92,7 @@ static void imx_scu_irq_work_handler(struct work_struct *work) if (!irq_status) continue; + pm_system_wakeup(); imx_scu_irq_notifier_call_chain(irq_status, &i); } } diff --git a/drivers/firmware/imx/imx-scu-soc.c b/drivers/firmware/imx/imx-scu-soc.c new file mode 100644 index 000000000000..2f32353de2c9 --- /dev/null +++ b/drivers/firmware/imx/imx-scu-soc.c @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP. + */ + +#include <dt-bindings/firmware/imx/rsrc.h> +#include <linux/firmware/imx/sci.h> +#include <linux/slab.h> +#include <linux/sys_soc.h> +#include <linux/platform_device.h> +#include <linux/of.h> + +static struct imx_sc_ipc *imx_sc_soc_ipc_handle; + +struct imx_sc_msg_misc_get_soc_id { + struct imx_sc_rpc_msg hdr; + union { + struct { + u32 control; + u16 resource; + } __packed req; + struct { + u32 id; + } resp; + } data; +} __packed __aligned(4); + +struct imx_sc_msg_misc_get_soc_uid { + struct imx_sc_rpc_msg hdr; + u32 uid_low; + u32 uid_high; +} __packed; + +static int imx_scu_soc_uid(u64 *soc_uid) +{ + struct imx_sc_msg_misc_get_soc_uid msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_MISC; + hdr->func = IMX_SC_MISC_FUNC_UNIQUE_ID; + hdr->size = 1; + + ret = imx_scu_call_rpc(imx_sc_soc_ipc_handle, &msg, true); + if (ret) { + pr_err("%s: get soc uid failed, ret %d\n", __func__, ret); + return ret; + } + + *soc_uid = msg.uid_high; + *soc_uid <<= 32; + *soc_uid |= msg.uid_low; + + return 0; +} + +static int imx_scu_soc_id(void) +{ + struct imx_sc_msg_misc_get_soc_id msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_MISC; + hdr->func = IMX_SC_MISC_FUNC_GET_CONTROL; + hdr->size = 3; + + msg.data.req.control = IMX_SC_C_ID; + msg.data.req.resource = IMX_SC_R_SYSTEM; + + ret = imx_scu_call_rpc(imx_sc_soc_ipc_handle, &msg, true); + if (ret) { + pr_err("%s: get soc info failed, ret %d\n", __func__, ret); + return ret; + } + + return msg.data.resp.id; +} + +int imx_scu_soc_init(struct device *dev) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + int id, ret; + u64 uid = 0; + u32 val; + + ret = imx_scu_get_handle(&imx_sc_soc_ipc_handle); + if (ret) + return ret; + + soc_dev_attr = devm_kzalloc(dev, sizeof(*soc_dev_attr), + GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = "Freescale i.MX"; + + ret = of_property_read_string(of_root, + "model", + &soc_dev_attr->machine); + if (ret) + return ret; + + id = imx_scu_soc_id(); + if (id < 0) + return -EINVAL; + + ret = imx_scu_soc_uid(&uid); + if (ret < 0) + return -EINVAL; + + /* format soc_id value passed from SCU firmware */ + val = id & 0x1f; + soc_dev_attr->soc_id = devm_kasprintf(dev, GFP_KERNEL, "0x%x", val); + if (!soc_dev_attr->soc_id) + return -ENOMEM; + + /* format revision value passed from SCU firmware */ + val = (id >> 5) & 0xf; + val = (((val >> 2) + 1) << 4) | (val & 0x3); + soc_dev_attr->revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d", + (val >> 4) & 0xf, val & 0xf); + if (!soc_dev_attr->revision) + return -ENOMEM; + + soc_dev_attr->serial_number = devm_kasprintf(dev, GFP_KERNEL, + "%016llX", uid); + if (!soc_dev_attr->serial_number) + return -ENOMEM; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) + return PTR_ERR(soc_dev); + + return 0; +} diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 2ab048222fe9..dca79caccd01 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -328,6 +328,10 @@ static int imx_scu_probe(struct platform_device *pdev) imx_sc_ipc_handle = sc_ipc; + ret = imx_scu_soc_init(dev); + if (ret) + dev_warn(dev, "failed to initialize SoC info: %d\n", ret); + ret = imx_scu_enable_general_irq_channel(dev); if (ret) dev_warn(dev, diff --git a/drivers/firmware/imx/rm.c b/drivers/firmware/imx/rm.c new file mode 100644 index 000000000000..a12db6ff323b --- /dev/null +++ b/drivers/firmware/imx/rm.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + * + * File containing client-side RPC functions for the RM service. These + * function are ported to clients that communicate to the SC. + */ + +#include <linux/firmware/imx/svc/rm.h> + +struct imx_sc_msg_rm_rsrc_owned { + struct imx_sc_rpc_msg hdr; + u16 resource; +} __packed __aligned(4); + +/* + * This function check @resource is owned by current partition or not + * + * @param[in] ipc IPC handle + * @param[in] resource resource the control is associated with + * + * @return Returns 0 for not owned and 1 for owned. + */ +bool imx_sc_rm_is_resource_owned(struct imx_sc_ipc *ipc, u16 resource) +{ + struct imx_sc_msg_rm_rsrc_owned msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_RM; + hdr->func = IMX_SC_RM_FUNC_IS_RESOURCE_OWNED; + hdr->size = 2; + + msg.resource = resource; + + /* + * SCU firmware only returns value 0 or 1 + * for resource owned check which means not owned or owned. + * So it is always successful. + */ + imx_scu_call_rpc(ipc, &msg, true); + + return hdr->func; +} +EXPORT_SYMBOL(imx_sc_rm_is_resource_owned); diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index fb5523aa16ee..af3d6d9ead28 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -167,8 +167,18 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 }, /* CM40 SS */ - { "cm40_i2c", IMX_SC_R_M4_0_I2C, 1, 0 }, - { "cm40_intmux", IMX_SC_R_M4_0_INTMUX, 1, 0 }, + { "cm40-i2c", IMX_SC_R_M4_0_I2C, 1, false, 0 }, + { "cm40-intmux", IMX_SC_R_M4_0_INTMUX, 1, false, 0 }, + { "cm40-pid", IMX_SC_R_M4_0_PID0, 5, true, 0}, + { "cm40-mu-a1", IMX_SC_R_M4_0_MU_1A, 1, false, 0}, + { "cm40-lpuart", IMX_SC_R_M4_0_UART, 1, false, 0}, + + /* CM41 SS */ + { "cm41-i2c", IMX_SC_R_M4_1_I2C, 1, false, 0 }, + { "cm41-intmux", IMX_SC_R_M4_1_INTMUX, 1, false, 0 }, + { "cm41-pid", IMX_SC_R_M4_1_PID0, 5, true, 0}, + { "cm41-mu-a1", IMX_SC_R_M4_1_MU_1A, 1, false, 0}, + { "cm41-lpuart", IMX_SC_R_M4_1_UART, 1, false, 0}, }; static const struct imx_sc_pd_soc imx8qxp_scu_pd = { |