From 15f5276a2fb1ad70d7a8e6321dd751c3d081e422 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Fri, 24 May 2019 01:52:36 +0000 Subject: soc: imx: Add SCU SoC info driver support Add i.MX SCU SoC info driver to support i.MX8QXP SoC, introduce driver dependency into Kconfig as CONFIG_IMX_SCU must be selected to support i.MX SCU SoC driver, also need to use platform driver model to make sure IMX_SCU driver is probed before i.MX SCU 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 0x2 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 Reviewed-by: Abel Vesa Reviewed-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/soc/imx/Kconfig | 9 +++ drivers/soc/imx/Makefile | 1 + drivers/soc/imx/soc-imx-scu.c | 144 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 drivers/soc/imx/soc-imx-scu.c (limited to 'drivers/soc/imx') diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index d80f899d22f9..cbc1a411ed87 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -7,4 +7,13 @@ config IMX_GPCV2_PM_DOMAINS select PM_GENERIC_DOMAINS default y if SOC_IMX7D +config IMX_SCU_SOC + bool "i.MX System Controller Unit SoC info support" + depends on IMX_SCU + select SOC_BUS + help + If you say yes here you get support for the NXP i.MX System + Controller Unit SoC info module, it will provide the SoC info + like SoC family, ID and revision etc. + endmenu diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index d6b529e06d9a..ddf343d6982d 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o obj-$(CONFIG_ARCH_MXC) += soc-imx8.o +obj-$(CONFIG_IMX_SCU_SOC) += soc-imx-scu.o diff --git a/drivers/soc/imx/soc-imx-scu.c b/drivers/soc/imx/soc-imx-scu.c new file mode 100644 index 000000000000..676f612f6488 --- /dev/null +++ b/drivers/soc/imx/soc-imx-scu.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP. + */ + +#include +#include +#include +#include +#include +#include + +#define IMX_SCU_SOC_DRIVER_NAME "imx-scu-soc" + +static struct imx_sc_ipc *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; + +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(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; +} + +static int imx_scu_soc_probe(struct platform_device *pdev) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + int id, ret; + u32 val; + + ret = imx_scu_get_handle(&soc_ipc_handle); + if (ret) + return ret; + + soc_dev_attr = devm_kzalloc(&pdev->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; + + /* format soc_id value passed from SCU firmware */ + val = id & 0x1f; + soc_dev_attr->soc_id = kasprintf(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 = kasprintf(GFP_KERNEL, + "%d.%d", + (val >> 4) & 0xf, + val & 0xf); + if (!soc_dev_attr->revision) { + ret = -ENOMEM; + goto free_soc_id; + } + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + ret = PTR_ERR(soc_dev); + goto free_revision; + } + + return 0; + +free_revision: + kfree(soc_dev_attr->revision); +free_soc_id: + kfree(soc_dev_attr->soc_id); + return ret; +} + +static struct platform_driver imx_scu_soc_driver = { + .driver = { + .name = IMX_SCU_SOC_DRIVER_NAME, + }, + .probe = imx_scu_soc_probe, +}; + +static int __init imx_scu_soc_init(void) +{ + struct platform_device *pdev; + struct device_node *np; + int ret; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx-scu"); + if (!np) + return -ENODEV; + + of_node_put(np); + + ret = platform_driver_register(&imx_scu_soc_driver); + if (ret) + return ret; + + pdev = platform_device_register_simple(IMX_SCU_SOC_DRIVER_NAME, + -1, NULL, 0); + if (IS_ERR(pdev)) + platform_driver_unregister(&imx_scu_soc_driver); + + return PTR_ERR_OR_ZERO(pdev); +} +device_initcall(imx_scu_soc_init); -- cgit v1.2.3