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#include <soc/brcmstb/common.h>
15
16static u32 family_id;
17static u32 product_id;
18
19static const struct of_device_id brcmstb_machine_match[] = {
20	{ .compatible = "brcm,brcmstb", },
21	{ }
22};
23
24bool soc_is_brcmstb(void)
25{
26	const struct of_device_id *match;
27	struct device_node *root;
28
29	root = of_find_node_by_path("/");
30	if (!root)
31		return false;
32
33	match = of_match_node(brcmstb_machine_match, root);
34	of_node_put(root);
35
36	return match != NULL;
37}
38
39u32 brcmstb_get_family_id(void)
40{
41	return family_id;
42}
43EXPORT_SYMBOL(brcmstb_get_family_id);
44
45u32 brcmstb_get_product_id(void)
46{
47	return product_id;
48}
49EXPORT_SYMBOL(brcmstb_get_product_id);
50
51static const struct of_device_id sun_top_ctrl_match[] = {
52	{ .compatible = "brcm,bcm7125-sun-top-ctrl", },
53	{ .compatible = "brcm,bcm7346-sun-top-ctrl", },
54	{ .compatible = "brcm,bcm7358-sun-top-ctrl", },
55	{ .compatible = "brcm,bcm7360-sun-top-ctrl", },
56	{ .compatible = "brcm,bcm7362-sun-top-ctrl", },
57	{ .compatible = "brcm,bcm7420-sun-top-ctrl", },
58	{ .compatible = "brcm,bcm7425-sun-top-ctrl", },
59	{ .compatible = "brcm,bcm7429-sun-top-ctrl", },
60	{ .compatible = "brcm,bcm7435-sun-top-ctrl", },
61	{ .compatible = "brcm,brcmstb-sun-top-ctrl", },
62	{ }
63};
64
65static int __init brcmstb_soc_device_early_init(void)
66{
67	struct device_node *sun_top_ctrl;
68	void __iomem *sun_top_ctrl_base;
69	int ret = 0;
70
71	/* We could be on a multi-platform kernel, don't make this fatal but
72	 * bail out early
73	 */
74	sun_top_ctrl = of_find_matching_node(NULL, sun_top_ctrl_match);
75	if (!sun_top_ctrl)
76		return ret;
77
78	sun_top_ctrl_base = of_iomap(sun_top_ctrl, 0);
79	if (!sun_top_ctrl_base) {
80		ret = -ENODEV;
81		goto out;
82	}
83
84	family_id = readl(sun_top_ctrl_base);
85	product_id = readl(sun_top_ctrl_base + 0x4);
86	iounmap(sun_top_ctrl_base);
87out:
88	of_node_put(sun_top_ctrl);
89	return ret;
90}
91early_initcall(brcmstb_soc_device_early_init);
92
93static int __init brcmstb_soc_device_init(void)
94{
95	struct soc_device_attribute *soc_dev_attr;
96	struct device_node *sun_top_ctrl;
97	struct soc_device *soc_dev;
98	int ret = 0;
99
100	/* We could be on a multi-platform kernel, don't make this fatal but
101	 * bail out early
102	 */
103	sun_top_ctrl = of_find_matching_node(NULL, sun_top_ctrl_match);
104	if (!sun_top_ctrl)
105		return ret;
106
107	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
108	if (!soc_dev_attr) {
109		ret = -ENOMEM;
110		goto out;
111	}
112
113	soc_dev_attr->family = kasprintf(GFP_KERNEL, "%x",
114					 family_id >> 28 ?
115					 family_id >> 16 : family_id >> 8);
116	soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%x",
117					 product_id >> 28 ?
118					 product_id >> 16 : product_id >> 8);
119	soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c%d",
120					 ((product_id & 0xf0) >> 4) + 'A',
121					   product_id & 0xf);
122
123	soc_dev = soc_device_register(soc_dev_attr);
124	if (IS_ERR(soc_dev)) {
125		kfree(soc_dev_attr->family);
126		kfree(soc_dev_attr->soc_id);
127		kfree(soc_dev_attr->revision);
128		kfree(soc_dev_attr);
129		ret = -ENOMEM;
130	}
131out:
132	of_node_put(sun_top_ctrl);
133	return ret;
134}
135arch_initcall(brcmstb_soc_device_init);
136