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 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 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 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 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