Messages in this thread Patch in this message |  | | From | Anson Huang <> | Subject | [PATCH 1/2] soc: imx: add i.MX8QXP SoC driver support | Date | Mon, 22 Apr 2019 04:54:15 +0000 |
| |
Add i.MX8QXP SoC driver support, introduce driver dependency into Kconfig as CONFIG_IMX_SCU must be selected to support i.MX8QXP, also need to use platform driver model to make sure IMX_SCU driver is probed before i.MX8 SoC driver.
With this patch, SoC info can be read from sysfs:
i.mx8qxp-mek# cat /sys/devices/soc0/family Freescale i.MX
i.mx8qxp-mek# cat /sys/devices/soc0/soc_id i.MX8QXP
i.mx8qxp-mek# cat /sys/devices/soc0/machine Freescale i.MX8QXP MEK
i.mx8qxp-mek# cat /sys/devices/soc0/revision 1.1
Signed-off-by: Anson Huang <Anson.Huang@nxp.com> --- drivers/soc/imx/Kconfig | 4 ++ drivers/soc/imx/Makefile | 2 +- drivers/soc/imx/soc-imx8.c | 126 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 124 insertions(+), 8 deletions(-)
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index d80f899..a4353f9 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -7,4 +7,8 @@ config IMX_GPCV2_PM_DOMAINS select PM_GENERIC_DOMAINS default y if SOC_IMX7D +config IMX8_SOC + bool "i.MX8 SoC driver" + depends on ARCH_MXC && IMX_SCU + endmenu diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index d6b529e0..5bf23f8 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o -obj-$(CONFIG_ARCH_MXC) += soc-imx8.o +obj-$(CONFIG_IMX8_SOC) += soc-imx8.o diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c index fc6429f..3ad0b1c 100644 --- a/drivers/soc/imx/soc-imx8.c +++ b/drivers/soc/imx/soc-imx8.c @@ -3,8 +3,11 @@ * Copyright 2019 NXP. */ +#include <dt-bindings/firmware/imx/rsrc.h> +#include <linux/firmware/imx/sci.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/of_address.h> #include <linux/slab.h> #include <linux/sys_soc.h> @@ -16,12 +19,61 @@ #define IMX8MQ_SW_INFO_B1 0x40 #define IMX8MQ_SW_MAGIC_B1 0xff0055aa +#define IMX8_SOC_DRIVER_NAME "imx8-soc" + +static struct imx_sc_ipc *soc_ipc_handle; +static struct platform_device *imx8_soc_pdev; + +struct imx_sc_msg_misc_get_soc_id { + struct imx_sc_rpc_msg hdr; + union { + struct { + u32 control; + u16 resource; + } send; + struct { + u32 id; + u16 reserved; + } resp; + } data; +}; + struct imx8_soc_data { char *name; u32 (*soc_revision)(void); + bool have_imx_scu; }; -static u32 __init imx8mq_soc_revision(void) +static u32 imx8qxp_soc_revision(void) +{ + struct imx_sc_msg_misc_get_soc_id msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + u32 rev = 0; + 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.send.control = IMX_SC_C_ID; + msg.data.send.resource = IMX_SC_R_SYSTEM; + + ret = imx_scu_call_rpc(soc_ipc_handle, &msg, true); + if (ret) { + dev_err(&imx8_soc_pdev->dev, + "misc get control failed, ret %d\n", ret); + return rev; + } + + /* format revision value passed from SCU firmware */ + rev = (msg.data.resp.id >> 5) & 0xf; + rev = (((rev >> 2) + 1) << 4) | (rev & 0x3); + + return rev; +} + +static u32 imx8mq_soc_revision(void) { struct device_node *np; void __iomem *ocotp_base; @@ -49,10 +101,18 @@ static u32 __init imx8mq_soc_revision(void) static const struct imx8_soc_data imx8mq_soc_data = { .name = "i.MX8MQ", .soc_revision = imx8mq_soc_revision, + .have_imx_scu = false, +}; + +static const struct imx8_soc_data imx8qxp_soc_data = { + .name = "i.MX8QXP", + .soc_revision = imx8qxp_soc_revision, + .have_imx_scu = true, }; static const struct of_device_id imx8_soc_match[] = { { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, }, + { .compatible = "fsl,imx8qxp", .data = &imx8qxp_soc_data, }, { } }; @@ -61,7 +121,7 @@ static const struct of_device_id imx8_soc_match[] = { kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \ "unknown" -static int __init imx8_soc_init(void) +static int imx8_soc_probe(struct platform_device *pdev) { struct soc_device_attribute *soc_dev_attr; struct soc_device *soc_dev; @@ -83,25 +143,37 @@ static int __init imx8_soc_init(void) goto free_soc; id = of_match_node(imx8_soc_match, root); - if (!id) + if (!id) { + ret = -ENODEV; goto free_soc; + } of_node_put(root); data = id->data; if (data) { + if (data->have_imx_scu) { + ret = imx_scu_get_handle(&soc_ipc_handle); + if (ret) + goto free_soc; + } + soc_dev_attr->soc_id = data->name; if (data->soc_revision) soc_rev = data->soc_revision(); } soc_dev_attr->revision = imx8_revision(soc_rev); - if (!soc_dev_attr->revision) + if (!soc_dev_attr->revision) { + ret = -ENODEV; goto free_soc; + } soc_dev = soc_device_register(soc_dev_attr); - if (IS_ERR(soc_dev)) + if (IS_ERR(soc_dev)) { + ret = -ENODEV; goto free_rev; + } return 0; @@ -110,6 +182,46 @@ static int __init imx8_soc_init(void) free_soc: kfree(soc_dev_attr); of_node_put(root); - return -ENODEV; + return ret; } -device_initcall(imx8_soc_init); + +static struct platform_driver imx8_soc_driver = { + .driver = { + .name = IMX8_SOC_DRIVER_NAME, + }, + .probe = imx8_soc_probe, +}; + +static int __init imx8_soc_init(void) +{ + int ret; + + ret = platform_driver_register(&imx8_soc_driver); + if (ret) + return ret; + + imx8_soc_pdev = + platform_device_register_simple(IMX8_SOC_DRIVER_NAME, + -1, + NULL, + 0); + if (IS_ERR(imx8_soc_pdev)) { + ret = PTR_ERR(imx8_soc_pdev); + goto unreg_platform_driver; + } + + return 0; + +unreg_platform_driver: + platform_driver_unregister(&imx8_soc_driver); + return ret; +} + +static void __exit imx8_soc_exit(void) +{ + platform_device_unregister(imx8_soc_pdev); + platform_driver_unregister(&imx8_soc_driver); +} + +module_init(imx8_soc_init); +module_exit(imx8_soc_exit); -- 2.7.4
|  |