1 // SPDX-License-Identifier: GPL-2.0
6 #include <linux/init.h>
8 #include <linux/of_address.h>
9 #include <linux/slab.h>
10 #include <linux/sys_soc.h>
11 #include <linux/platform_device.h>
16 #define IMX8MQ_SW_INFO_B1 0x40
17 #define IMX8MQ_SW_MAGIC_B1 0xff0055aa
19 /* Same as ANADIG_DIGPROG_IMX7D */
20 #define ANADIG_DIGPROG_IMX8MM 0x800
22 struct imx8_soc_data {
24 u32 (*soc_revision)(void);
27 static u32 __init imx8mq_soc_revision(void)
29 struct device_node *np;
30 void __iomem *ocotp_base;
34 np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
38 ocotp_base = of_iomap(np, 0);
41 magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
42 if (magic == IMX8MQ_SW_MAGIC_B1)
52 static u32 __init imx8mm_soc_revision(void)
54 struct device_node *np;
55 void __iomem *anatop_base;
58 np = of_find_compatible_node(NULL, NULL, "fsl,imx8mm-anatop");
62 anatop_base = of_iomap(np, 0);
63 WARN_ON(!anatop_base);
65 rev = readl_relaxed(anatop_base + ANADIG_DIGPROG_IMX8MM);
72 static const struct imx8_soc_data imx8mq_soc_data = {
74 .soc_revision = imx8mq_soc_revision,
77 static const struct imx8_soc_data imx8mm_soc_data = {
79 .soc_revision = imx8mm_soc_revision,
82 static const struct imx8_soc_data imx8mn_soc_data = {
84 .soc_revision = imx8mm_soc_revision,
87 static const struct of_device_id imx8_soc_match[] = {
88 { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
89 { .compatible = "fsl,imx8mm", .data = &imx8mm_soc_data, },
90 { .compatible = "fsl,imx8mn", .data = &imx8mn_soc_data, },
94 #define imx8_revision(soc_rev) \
96 kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \
99 static int __init imx8_soc_init(void)
101 struct soc_device_attribute *soc_dev_attr;
102 struct soc_device *soc_dev;
103 const struct of_device_id *id;
105 const struct imx8_soc_data *data;
108 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
112 soc_dev_attr->family = "Freescale i.MX";
114 ret = of_property_read_string(of_root, "model", &soc_dev_attr->machine);
118 id = of_match_node(imx8_soc_match, of_root);
126 soc_dev_attr->soc_id = data->name;
127 if (data->soc_revision)
128 soc_rev = data->soc_revision();
131 soc_dev_attr->revision = imx8_revision(soc_rev);
132 if (!soc_dev_attr->revision) {
137 soc_dev = soc_device_register(soc_dev_attr);
138 if (IS_ERR(soc_dev)) {
139 ret = PTR_ERR(soc_dev);
143 if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT))
144 platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0);
149 if (strcmp(soc_dev_attr->revision, "unknown"))
150 kfree(soc_dev_attr->revision);
155 device_initcall(imx8_soc_init);