xref: /linux/drivers/soc/bcm/brcmstb/common.c (revision bba2c3615bd6cfee7456d1130f2e6b01b3f4e9ba)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright © 2014 NVIDIA Corporation
4  * Copyright © 2015 Broadcom Corporation
5  */
6 
7 #include <linux/io.h>
8 #include <linux/of.h>
9 #include <linux/of_address.h>
10 #include <linux/slab.h>
11 #include <linux/soc/brcmstb/brcmstb.h>
12 #include <linux/sys_soc.h>
13 
14 struct brcmstb_soc_info {
15 	u32 family_id;
16 	u32 product_id;
17 };
18 
19 static struct brcmstb_soc_info *soc_info;
20 
21 u32 brcmstb_get_family_id(void)
22 {
23 	return soc_info ? soc_info->family_id : 0;
24 }
25 EXPORT_SYMBOL(brcmstb_get_family_id);
26 
27 u32 brcmstb_get_product_id(void)
28 {
29 	return soc_info ? soc_info->product_id : 0;
30 }
31 EXPORT_SYMBOL(brcmstb_get_product_id);
32 
33 static const struct of_device_id sun_top_ctrl_match[] = {
34 	{ .compatible = "brcm,bcm7125-sun-top-ctrl", },
35 	{ .compatible = "brcm,bcm7346-sun-top-ctrl", },
36 	{ .compatible = "brcm,bcm7358-sun-top-ctrl", },
37 	{ .compatible = "brcm,bcm7360-sun-top-ctrl", },
38 	{ .compatible = "brcm,bcm7362-sun-top-ctrl", },
39 	{ .compatible = "brcm,bcm7420-sun-top-ctrl", },
40 	{ .compatible = "brcm,bcm7425-sun-top-ctrl", },
41 	{ .compatible = "brcm,bcm7429-sun-top-ctrl", },
42 	{ .compatible = "brcm,bcm7435-sun-top-ctrl", },
43 	{ .compatible = "brcm,brcmstb-sun-top-ctrl", },
44 	{ }
45 };
46 
47 static int __init brcmstb_soc_device_init(void)
48 {
49 	struct soc_device_attribute *soc_dev_attr;
50 	struct device_node *sun_top_ctrl;
51 	void __iomem *sun_top_ctrl_base;
52 	struct soc_device *soc_dev;
53 	int ret = 0;
54 
55 	/* We could be on a multi-platform kernel, don't make this fatal but
56 	 * bail out early
57 	 */
58 	sun_top_ctrl = of_find_matching_node(NULL, sun_top_ctrl_match);
59 	if (!sun_top_ctrl)
60 		return 0;
61 
62 	sun_top_ctrl_base = of_iomap(sun_top_ctrl, 0);
63 	if (!sun_top_ctrl_base) {
64 		ret = -ENODEV;
65 		goto out_put_node;
66 	}
67 
68 	soc_info = kzalloc(sizeof(*soc_info), GFP_KERNEL);
69 	if (!soc_info) {
70 		ret = -ENOMEM;
71 		goto out_unmap;
72 	}
73 
74 	soc_info->family_id = readl(sun_top_ctrl_base);
75 	soc_info->product_id = readl(sun_top_ctrl_base + 0x4);
76 
77 	soc_dev_attr = kzalloc_obj(*soc_dev_attr);
78 	if (!soc_dev_attr) {
79 		ret = -ENOMEM;
80 		goto out_free_info;
81 	}
82 
83 	soc_dev_attr->family = kasprintf(GFP_KERNEL, "%x",
84 					 soc_info->family_id >> 28 ?
85 					 soc_info->family_id >> 16 : soc_info->family_id >> 8);
86 	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%x",
87 					 soc_info->product_id >> 28 ?
88 					 soc_info->product_id >> 16 : soc_info->product_id >> 8);
89 	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c%d",
90 					 ((soc_info->product_id & 0xf0) >> 4) + 'A',
91 					   soc_info->product_id & 0xf);
92 
93 	soc_dev = soc_device_register(soc_dev_attr);
94 	if (IS_ERR(soc_dev)) {
95 		ret = PTR_ERR(soc_dev);
96 		goto out_free_attr;
97 	}
98 
99 	iounmap(sun_top_ctrl_base);
100 	of_node_put(sun_top_ctrl);
101 	return 0;
102 
103 out_free_attr:
104 	kfree(soc_dev_attr->revision);
105 	kfree(soc_dev_attr->soc_id);
106 	kfree(soc_dev_attr->family);
107 	kfree(soc_dev_attr);
108 out_free_info:
109 	kfree(soc_info);
110 	soc_info = NULL;
111 out_unmap:
112 	iounmap(sun_top_ctrl_base);
113 out_put_node:
114 	of_node_put(sun_top_ctrl);
115 	return ret;
116 }
117 early_initcall(brcmstb_soc_device_init);
118