aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/soc/imx/Kconfig9
-rw-r--r--drivers/soc/imx/Makefile1
-rw-r--r--drivers/soc/imx/soc-imx-scu.c144
-rw-r--r--drivers/soc/imx/soc-imx8.c63
4 files changed, 204 insertions, 13 deletions
diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig
index ade1b46d669c..8aaebf13e2e6 100644
--- a/drivers/soc/imx/Kconfig
+++ b/drivers/soc/imx/Kconfig
@@ -8,4 +8,13 @@ config IMX_GPCV2_PM_DOMAINS
8 select PM_GENERIC_DOMAINS 8 select PM_GENERIC_DOMAINS
9 default y if SOC_IMX7D 9 default y if SOC_IMX7D
10 10
11config IMX_SCU_SOC
12 bool "i.MX System Controller Unit SoC info support"
13 depends on IMX_SCU
14 select SOC_BUS
15 help
16 If you say yes here you get support for the NXP i.MX System
17 Controller Unit SoC info module, it will provide the SoC info
18 like SoC family, ID and revision etc.
19
11endmenu 20endmenu
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
index caa8653600f2..cf9ca42ff739 100644
--- a/drivers/soc/imx/Makefile
+++ b/drivers/soc/imx/Makefile
@@ -2,3 +2,4 @@
2obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o 2obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
3obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o 3obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
4obj-$(CONFIG_ARCH_MXC) += soc-imx8.o 4obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
5obj-$(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 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright 2019 NXP.
4 */
5
6#include <dt-bindings/firmware/imx/rsrc.h>
7#include <linux/firmware/imx/sci.h>
8#include <linux/slab.h>
9#include <linux/sys_soc.h>
10#include <linux/platform_device.h>
11#include <linux/of.h>
12
13#define IMX_SCU_SOC_DRIVER_NAME "imx-scu-soc"
14
15static struct imx_sc_ipc *soc_ipc_handle;
16
17struct imx_sc_msg_misc_get_soc_id {
18 struct imx_sc_rpc_msg hdr;
19 union {
20 struct {
21 u32 control;
22 u16 resource;
23 } __packed req;
24 struct {
25 u32 id;
26 } resp;
27 } data;
28} __packed;
29
30static int imx_scu_soc_id(void)
31{
32 struct imx_sc_msg_misc_get_soc_id msg;
33 struct imx_sc_rpc_msg *hdr = &msg.hdr;
34 int ret;
35
36 hdr->ver = IMX_SC_RPC_VERSION;
37 hdr->svc = IMX_SC_RPC_SVC_MISC;
38 hdr->func = IMX_SC_MISC_FUNC_GET_CONTROL;
39 hdr->size = 3;
40
41 msg.data.req.control = IMX_SC_C_ID;
42 msg.data.req.resource = IMX_SC_R_SYSTEM;
43
44 ret = imx_scu_call_rpc(soc_ipc_handle, &msg, true);
45 if (ret) {
46 pr_err("%s: get soc info failed, ret %d\n", __func__, ret);
47 return ret;
48 }
49
50 return msg.data.resp.id;
51}
52
53static int imx_scu_soc_probe(struct platform_device *pdev)
54{
55 struct soc_device_attribute *soc_dev_attr;
56 struct soc_device *soc_dev;
57 int id, ret;
58 u32 val;
59
60 ret = imx_scu_get_handle(&soc_ipc_handle);
61 if (ret)
62 return ret;
63
64 soc_dev_attr = devm_kzalloc(&pdev->dev, sizeof(*soc_dev_attr),
65 GFP_KERNEL);
66 if (!soc_dev_attr)
67 return -ENOMEM;
68
69 soc_dev_attr->family = "Freescale i.MX";
70
71 ret = of_property_read_string(of_root,
72 "model",
73 &soc_dev_attr->machine);
74 if (ret)
75 return ret;
76
77 id = imx_scu_soc_id();
78 if (id < 0)
79 return -EINVAL;
80
81 /* format soc_id value passed from SCU firmware */
82 val = id & 0x1f;
83 soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "0x%x", val);
84 if (!soc_dev_attr->soc_id)
85 return -ENOMEM;
86
87 /* format revision value passed from SCU firmware */
88 val = (id >> 5) & 0xf;
89 val = (((val >> 2) + 1) << 4) | (val & 0x3);
90 soc_dev_attr->revision = kasprintf(GFP_KERNEL,
91 "%d.%d",
92 (val >> 4) & 0xf,
93 val & 0xf);
94 if (!soc_dev_attr->revision) {
95 ret = -ENOMEM;
96 goto free_soc_id;
97 }
98
99 soc_dev = soc_device_register(soc_dev_attr);
100 if (IS_ERR(soc_dev)) {
101 ret = PTR_ERR(soc_dev);
102 goto free_revision;
103 }
104
105 return 0;
106
107free_revision:
108 kfree(soc_dev_attr->revision);
109free_soc_id:
110 kfree(soc_dev_attr->soc_id);
111 return ret;
112}
113
114static struct platform_driver imx_scu_soc_driver = {
115 .driver = {
116 .name = IMX_SCU_SOC_DRIVER_NAME,
117 },
118 .probe = imx_scu_soc_probe,
119};
120
121static int __init imx_scu_soc_init(void)
122{
123 struct platform_device *pdev;
124 struct device_node *np;
125 int ret;
126
127 np = of_find_compatible_node(NULL, NULL, "fsl,imx-scu");
128 if (!np)
129 return -ENODEV;
130
131 of_node_put(np);
132
133 ret = platform_driver_register(&imx_scu_soc_driver);
134 if (ret)
135 return ret;
136
137 pdev = platform_device_register_simple(IMX_SCU_SOC_DRIVER_NAME,
138 -1, NULL, 0);
139 if (IS_ERR(pdev))
140 platform_driver_unregister(&imx_scu_soc_driver);
141
142 return PTR_ERR_OR_ZERO(pdev);
143}
144device_initcall(imx_scu_soc_init);
diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c
index fc6429f9170a..9fb5293469f8 100644
--- a/drivers/soc/imx/soc-imx8.c
+++ b/drivers/soc/imx/soc-imx8.c
@@ -16,6 +16,9 @@
16#define IMX8MQ_SW_INFO_B1 0x40 16#define IMX8MQ_SW_INFO_B1 0x40
17#define IMX8MQ_SW_MAGIC_B1 0xff0055aa 17#define IMX8MQ_SW_MAGIC_B1 0xff0055aa
18 18
19/* Same as ANADIG_DIGPROG_IMX7D */
20#define ANADIG_DIGPROG_IMX8MM 0x800
21
19struct imx8_soc_data { 22struct imx8_soc_data {
20 char *name; 23 char *name;
21 u32 (*soc_revision)(void); 24 u32 (*soc_revision)(void);
@@ -46,13 +49,45 @@ out:
46 return rev; 49 return rev;
47} 50}
48 51
52static u32 __init imx8mm_soc_revision(void)
53{
54 struct device_node *np;
55 void __iomem *anatop_base;
56 u32 rev;
57
58 np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
59 if (!np)
60 return 0;
61
62 anatop_base = of_iomap(np, 0);
63 WARN_ON(!anatop_base);
64
65 rev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM);
66
67 iounmap(anatop_base);
68 of_node_put(np);
69 return rev;
70}
71
49static const struct imx8_soc_data imx8mq_soc_data = { 72static const struct imx8_soc_data imx8mq_soc_data = {
50 .name = "i.MX8MQ", 73 .name = "i.MX8MQ",
51 .soc_revision = imx8mq_soc_revision, 74 .soc_revision = imx8mq_soc_revision,
52}; 75};
53 76
77static const struct imx8_soc_data imx8mm_soc_data = {
78 .name = "i.MX8MM",
79 .soc_revision = imx8mm_soc_revision,
80};
81
82static const struct imx8_soc_data imx8mn_soc_data = {
83 .name = "i.MX8MN",
84 .soc_revision = imx8mm_soc_revision,
85};
86
54static const struct of_device_id imx8_soc_match[] = { 87static const struct of_device_id imx8_soc_match[] = {
55 { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, }, 88 { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
89 { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, },
90 { .compatible = "fsl,imx8mn", .data = &imx8mn_soc_data, },
56 { } 91 { }
57}; 92};
58 93
@@ -65,7 +100,6 @@ static int __init imx8_soc_init(void)
65{ 100{
66 struct soc_device_attribute *soc_dev_attr; 101 struct soc_device_attribute *soc_dev_attr;
67 struct soc_device *soc_dev; 102 struct soc_device *soc_dev;
68 struct device_node *root;
69 const struct of_device_id *id; 103 const struct of_device_id *id;
70 u32 soc_rev = 0; 104 u32 soc_rev = 0;
71 const struct imx8_soc_data *data; 105 const struct imx8_soc_data *data;
@@ -73,20 +107,19 @@ static int __init imx8_soc_init(void)
73 107
74 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 108 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
75 if (!soc_dev_attr) 109 if (!soc_dev_attr)
76 return -ENODEV; 110 return -ENOMEM;
77 111
78 soc_dev_attr->family = "Freescale i.MX"; 112 soc_dev_attr->family = "Freescale i.MX";
79 113
80 root = of_find_node_by_path("/"); 114 ret = of_property_read_string(of_root, "model", &soc_dev_attr->machine);
81 ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
82 if (ret) 115 if (ret)
83 goto free_soc; 116 goto free_soc;
84 117
85 id = of_match_node(imx8_soc_match, root); 118 id = of_match_node(imx8_soc_match, of_root);
86 if (!id) 119 if (!id) {
120 ret = -ENODEV;
87 goto free_soc; 121 goto free_soc;
88 122 }
89 of_node_put(root);
90 123
91 data = id->data; 124 data = id->data;
92 if (data) { 125 if (data) {
@@ -96,20 +129,24 @@ static int __init imx8_soc_init(void)
96 } 129 }
97 130
98 soc_dev_attr->revision = imx8_revision(soc_rev); 131 soc_dev_attr->revision = imx8_revision(soc_rev);
99 if (!soc_dev_attr->revision) 132 if (!soc_dev_attr->revision) {
133 ret = -ENOMEM;
100 goto free_soc; 134 goto free_soc;
135 }
101 136
102 soc_dev = soc_device_register(soc_dev_attr); 137 soc_dev = soc_device_register(soc_dev_attr);
103 if (IS_ERR(soc_dev)) 138 if (IS_ERR(soc_dev)) {
139 ret = PTR_ERR(soc_dev);
104 goto free_rev; 140 goto free_rev;
141 }
105 142
106 return 0; 143 return 0;
107 144
108free_rev: 145free_rev:
109 kfree(soc_dev_attr->revision); 146 if (strcmp(soc_dev_attr->revision, "unknown"))
147 kfree(soc_dev_attr->revision);
110free_soc: 148free_soc:
111 kfree(soc_dev_attr); 149 kfree(soc_dev_attr);
112 of_node_put(root); 150 return ret;
113 return -ENODEV;
114} 151}
115device_initcall(imx8_soc_init); 152device_initcall(imx8_soc_init);