File Index
Files and directories
Sign in
FILE

soc-imx9.c

File preview with syntax highlighting.

linux-6.19.14/drivers/soc/imx/soc-imx9.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright 2024 NXP
  4 */
  5
  6#include <linux/arm-smccc.h>
  7#include <linux/init.h>
  8#include <linux/module.h>
  9#include <linux/of.h>
 10#include <linux/platform_device.h>
 11#include <linux/slab.h>
 12#include <linux/sys_soc.h>
 13
 14#define IMX_SIP_GET_SOC_INFO	0xc2000006
 15#define SOC_ID(x)		(((x) & 0xFFFF) >> 8)
 16#define SOC_REV_MAJOR(x)	((((x) >> 28) & 0xF) - 0x9)
 17#define SOC_REV_MINOR(x)	(((x) >> 24) & 0xF)
 18
 19static int imx9_soc_probe(struct platform_device *pdev)
 20{
 21	struct soc_device_attribute *attr;
 22	struct arm_smccc_res res;
 23	struct soc_device *sdev;
 24	u32 soc_id, rev_major, rev_minor;
 25	u64 uid127_64, uid63_0;
 26	int err;
 27
 28	attr = kzalloc(sizeof(*attr), GFP_KERNEL);
 29	if (!attr)
 30		return -ENOMEM;
 31
 32	err = of_property_read_string(of_root, "model", &attr->machine);
 33	if (err) {
 34		pr_err("%s: missing model property: %d\n", __func__, err);
 35		goto attr;
 36	}
 37
 38	attr->family = kasprintf(GFP_KERNEL, "Freescale i.MX");
 39
 40	/*
 41	 * Retrieve the soc id, rev & uid info:
 42	 * res.a1[31:16]: soc revision;
 43	 * res.a1[15:0]: soc id;
 44	 * res.a2: uid[127:64];
 45	 * res.a3: uid[63:0];
 46	 */
 47	arm_smccc_smc(IMX_SIP_GET_SOC_INFO, 0, 0, 0, 0, 0, 0, 0, &res);
 48	if (res.a0 != SMCCC_RET_SUCCESS) {
 49		pr_err("%s: SMC failed: 0x%lx\n", __func__, res.a0);
 50		err = -EINVAL;
 51		goto family;
 52	}
 53
 54	soc_id = SOC_ID(res.a1);
 55	rev_major = SOC_REV_MAJOR(res.a1);
 56	rev_minor = SOC_REV_MINOR(res.a1);
 57
 58	attr->soc_id = kasprintf(GFP_KERNEL, "i.MX%2x", soc_id);
 59	attr->revision = kasprintf(GFP_KERNEL, "%d.%d", rev_major, rev_minor);
 60
 61	uid127_64 = res.a2;
 62	uid63_0 = res.a3;
 63	attr->serial_number = kasprintf(GFP_KERNEL, "%016llx%016llx", uid127_64, uid63_0);
 64
 65	sdev = soc_device_register(attr);
 66	if (IS_ERR(sdev)) {
 67		err = PTR_ERR(sdev);
 68		pr_err("%s failed to register SoC as a device: %d\n", __func__, err);
 69		goto serial_number;
 70	}
 71
 72	return 0;
 73
 74serial_number:
 75	kfree(attr->serial_number);
 76	kfree(attr->revision);
 77	kfree(attr->soc_id);
 78family:
 79	kfree(attr->family);
 80attr:
 81	kfree(attr);
 82	return err;
 83}
 84
 85static __maybe_unused const struct of_device_id imx9_soc_match[] = {
 86	{ .compatible = "fsl,imx93", },
 87	{ .compatible = "fsl,imx95", },
 88	{ }
 89};
 90
 91#define IMX_SOC_DRIVER	"imx9-soc"
 92
 93static struct platform_driver imx9_soc_driver = {
 94	.probe = imx9_soc_probe,
 95	.driver = {
 96		.name = IMX_SOC_DRIVER,
 97	},
 98};
 99
100static int __init imx9_soc_init(void)
101{
102	int ret;
103	struct platform_device *pdev;
104
105	/* No match means it is not an i.MX 9 series SoC, do nothing. */
106	if (!of_match_node(imx9_soc_match, of_root))
107		return 0;
108
109	ret = platform_driver_register(&imx9_soc_driver);
110	if (ret) {
111		pr_err("failed to register imx9_soc platform driver: %d\n", ret);
112		return ret;
113	}
114
115	pdev = platform_device_register_simple(IMX_SOC_DRIVER, -1, NULL, 0);
116	if (IS_ERR(pdev)) {
117		pr_err("failed to register imx9_soc platform device: %ld\n", PTR_ERR(pdev));
118		platform_driver_unregister(&imx9_soc_driver);
119		return PTR_ERR(pdev);
120	}
121
122	return 0;
123}
124device_initcall(imx9_soc_init);
125
126MODULE_AUTHOR("NXP");
127MODULE_DESCRIPTION("NXP i.MX9 SoC");
128MODULE_LICENSE("GPL");
~/ Read-only file preview.