xref: /linux/drivers/firmware/imx/imx-scu-soc.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
1a24015faSAnson Huang // SPDX-License-Identifier: GPL-2.0
2a24015faSAnson Huang /*
3a24015faSAnson Huang  * Copyright 2019 NXP.
4a24015faSAnson Huang  */
5a24015faSAnson Huang 
6a24015faSAnson Huang #include <dt-bindings/firmware/imx/rsrc.h>
7a24015faSAnson Huang #include <linux/firmware/imx/sci.h>
8a24015faSAnson Huang #include <linux/slab.h>
9a24015faSAnson Huang #include <linux/sys_soc.h>
10a24015faSAnson Huang #include <linux/platform_device.h>
11a24015faSAnson Huang #include <linux/of.h>
12a24015faSAnson Huang 
13a24015faSAnson Huang static struct imx_sc_ipc *imx_sc_soc_ipc_handle;
14a24015faSAnson Huang 
15a24015faSAnson Huang struct imx_sc_msg_misc_get_soc_id {
16a24015faSAnson Huang 	struct imx_sc_rpc_msg hdr;
17a24015faSAnson Huang 	union {
18a24015faSAnson Huang 		struct {
19a24015faSAnson Huang 			u32 control;
20a24015faSAnson Huang 			u16 resource;
21a24015faSAnson Huang 		} __packed req;
22a24015faSAnson Huang 		struct {
23a24015faSAnson Huang 			u32 id;
24a24015faSAnson Huang 		} resp;
25a24015faSAnson Huang 	} data;
26a24015faSAnson Huang } __packed __aligned(4);
27a24015faSAnson Huang 
28a24015faSAnson Huang struct imx_sc_msg_misc_get_soc_uid {
29a24015faSAnson Huang 	struct imx_sc_rpc_msg hdr;
30a24015faSAnson Huang 	u32 uid_low;
31a24015faSAnson Huang 	u32 uid_high;
32a24015faSAnson Huang } __packed;
33a24015faSAnson Huang 
imx_scu_soc_uid(u64 * soc_uid)34a24015faSAnson Huang static int imx_scu_soc_uid(u64 *soc_uid)
35a24015faSAnson Huang {
36a24015faSAnson Huang 	struct imx_sc_msg_misc_get_soc_uid msg;
37a24015faSAnson Huang 	struct imx_sc_rpc_msg *hdr = &msg.hdr;
38a24015faSAnson Huang 	int ret;
39a24015faSAnson Huang 
40a24015faSAnson Huang 	hdr->ver = IMX_SC_RPC_VERSION;
41a24015faSAnson Huang 	hdr->svc = IMX_SC_RPC_SVC_MISC;
42a24015faSAnson Huang 	hdr->func = IMX_SC_MISC_FUNC_UNIQUE_ID;
43a24015faSAnson Huang 	hdr->size = 1;
44a24015faSAnson Huang 
45a24015faSAnson Huang 	ret = imx_scu_call_rpc(imx_sc_soc_ipc_handle, &msg, true);
46a24015faSAnson Huang 	if (ret) {
47a24015faSAnson Huang 		pr_err("%s: get soc uid failed, ret %d\n", __func__, ret);
48a24015faSAnson Huang 		return ret;
49a24015faSAnson Huang 	}
50a24015faSAnson Huang 
51a24015faSAnson Huang 	*soc_uid = msg.uid_high;
52a24015faSAnson Huang 	*soc_uid <<= 32;
53a24015faSAnson Huang 	*soc_uid |= msg.uid_low;
54a24015faSAnson Huang 
55a24015faSAnson Huang 	return 0;
56a24015faSAnson Huang }
57a24015faSAnson Huang 
imx_scu_soc_id(void)58a24015faSAnson Huang static int imx_scu_soc_id(void)
59a24015faSAnson Huang {
60a24015faSAnson Huang 	struct imx_sc_msg_misc_get_soc_id msg;
61a24015faSAnson Huang 	struct imx_sc_rpc_msg *hdr = &msg.hdr;
62a24015faSAnson Huang 	int ret;
63a24015faSAnson Huang 
64a24015faSAnson Huang 	hdr->ver = IMX_SC_RPC_VERSION;
65a24015faSAnson Huang 	hdr->svc = IMX_SC_RPC_SVC_MISC;
66a24015faSAnson Huang 	hdr->func = IMX_SC_MISC_FUNC_GET_CONTROL;
67a24015faSAnson Huang 	hdr->size = 3;
68a24015faSAnson Huang 
69a24015faSAnson Huang 	msg.data.req.control = IMX_SC_C_ID;
70a24015faSAnson Huang 	msg.data.req.resource = IMX_SC_R_SYSTEM;
71a24015faSAnson Huang 
72a24015faSAnson Huang 	ret = imx_scu_call_rpc(imx_sc_soc_ipc_handle, &msg, true);
73a24015faSAnson Huang 	if (ret) {
74a24015faSAnson Huang 		pr_err("%s: get soc info failed, ret %d\n", __func__, ret);
75a24015faSAnson Huang 		return ret;
76a24015faSAnson Huang 	}
77a24015faSAnson Huang 
78a24015faSAnson Huang 	return msg.data.resp.id;
79a24015faSAnson Huang }
80a24015faSAnson Huang 
imx_scu_soc_name(u32 id)81*150019deSPeng Fan static const char *imx_scu_soc_name(u32 id)
82*150019deSPeng Fan {
83*150019deSPeng Fan 	switch (id) {
84*150019deSPeng Fan 	case 0x1:
85*150019deSPeng Fan 		return "i.MX8QM";
86*150019deSPeng Fan 	case 0x2:
87*150019deSPeng Fan 		return "i.MX8QXP";
88*150019deSPeng Fan 	case 0xe:
89*150019deSPeng Fan 		return "i.MX8DXL";
90*150019deSPeng Fan 	default:
91*150019deSPeng Fan 		break;
92*150019deSPeng Fan 	}
93*150019deSPeng Fan 
94*150019deSPeng Fan 	return "NULL";
95*150019deSPeng Fan }
96*150019deSPeng Fan 
imx_scu_soc_init(struct device * dev)97a24015faSAnson Huang int imx_scu_soc_init(struct device *dev)
98a24015faSAnson Huang {
99a24015faSAnson Huang 	struct soc_device_attribute *soc_dev_attr;
100a24015faSAnson Huang 	struct soc_device *soc_dev;
101a24015faSAnson Huang 	int id, ret;
102a24015faSAnson Huang 	u64 uid = 0;
103a24015faSAnson Huang 	u32 val;
104a24015faSAnson Huang 
105a24015faSAnson Huang 	ret = imx_scu_get_handle(&imx_sc_soc_ipc_handle);
106a24015faSAnson Huang 	if (ret)
107a24015faSAnson Huang 		return ret;
108a24015faSAnson Huang 
109a24015faSAnson Huang 	soc_dev_attr = devm_kzalloc(dev, sizeof(*soc_dev_attr),
110a24015faSAnson Huang 				    GFP_KERNEL);
111a24015faSAnson Huang 	if (!soc_dev_attr)
112a24015faSAnson Huang 		return -ENOMEM;
113a24015faSAnson Huang 
114a24015faSAnson Huang 	soc_dev_attr->family = "Freescale i.MX";
115a24015faSAnson Huang 
116a24015faSAnson Huang 	ret = of_property_read_string(of_root,
117a24015faSAnson Huang 				      "model",
118a24015faSAnson Huang 				      &soc_dev_attr->machine);
119a24015faSAnson Huang 	if (ret)
120a24015faSAnson Huang 		return ret;
121a24015faSAnson Huang 
122a24015faSAnson Huang 	id = imx_scu_soc_id();
123a24015faSAnson Huang 	if (id < 0)
124a24015faSAnson Huang 		return -EINVAL;
125a24015faSAnson Huang 
126a24015faSAnson Huang 	ret = imx_scu_soc_uid(&uid);
127a24015faSAnson Huang 	if (ret < 0)
128a24015faSAnson Huang 		return -EINVAL;
129a24015faSAnson Huang 
130a24015faSAnson Huang 	/* format soc_id value passed from SCU firmware */
131a24015faSAnson Huang 	val = id & 0x1f;
132*150019deSPeng Fan 	soc_dev_attr->soc_id = imx_scu_soc_name(val);
133a24015faSAnson Huang 
134a24015faSAnson Huang 	/* format revision value passed from SCU firmware */
135a24015faSAnson Huang 	val = (id >> 5) & 0xf;
136a24015faSAnson Huang 	val = (((val >> 2) + 1) << 4) | (val & 0x3);
137a24015faSAnson Huang 	soc_dev_attr->revision = devm_kasprintf(dev, GFP_KERNEL, "%d.%d",
138a24015faSAnson Huang 						(val >> 4) & 0xf, val & 0xf);
139a24015faSAnson Huang 	if (!soc_dev_attr->revision)
140a24015faSAnson Huang 		return -ENOMEM;
141a24015faSAnson Huang 
142a24015faSAnson Huang 	soc_dev_attr->serial_number = devm_kasprintf(dev, GFP_KERNEL,
143a24015faSAnson Huang 						     "%016llX", uid);
144a24015faSAnson Huang 	if (!soc_dev_attr->serial_number)
145a24015faSAnson Huang 		return -ENOMEM;
146a24015faSAnson Huang 
147a24015faSAnson Huang 	soc_dev = soc_device_register(soc_dev_attr);
148a24015faSAnson Huang 	if (IS_ERR(soc_dev))
149a24015faSAnson Huang 		return PTR_ERR(soc_dev);
150a24015faSAnson Huang 
151a24015faSAnson Huang 	return 0;
152a24015faSAnson Huang }
153