1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* Copyright 2019 IBM Corp. */ |
3 | |
4 | #include <linux/io.h> |
5 | #include <linux/of.h> |
6 | #include <linux/of_address.h> |
7 | #include <linux/of_platform.h> |
8 | #include <linux/platform_device.h> |
9 | #include <linux/slab.h> |
10 | #include <linux/sys_soc.h> |
11 | |
12 | static struct { |
13 | const char *name; |
14 | const u32 id; |
15 | } const rev_table[] = { |
16 | /* AST2400 */ |
17 | { "AST2400" , 0x02000303 }, |
18 | { "AST1400" , 0x02010103 }, |
19 | { "AST1250" , 0x02010303 }, |
20 | /* AST2500 */ |
21 | { "AST2500" , 0x04000303 }, |
22 | { "AST2510" , 0x04000103 }, |
23 | { "AST2520" , 0x04000203 }, |
24 | { "AST2530" , 0x04000403 }, |
25 | /* AST2600 */ |
26 | { "AST2600" , 0x05000303 }, |
27 | { "AST2620" , 0x05010203 }, |
28 | { "AST2605" , 0x05030103 }, |
29 | { "AST2625" , 0x05030403 }, |
30 | }; |
31 | |
32 | static const char *siliconid_to_name(u32 siliconid) |
33 | { |
34 | unsigned int id = siliconid & 0xff00ffff; |
35 | unsigned int i; |
36 | |
37 | for (i = 0 ; i < ARRAY_SIZE(rev_table) ; ++i) { |
38 | if (rev_table[i].id == id) |
39 | return rev_table[i].name; |
40 | } |
41 | |
42 | return "Unknown" ; |
43 | } |
44 | |
45 | static const char *siliconid_to_rev(u32 siliconid) |
46 | { |
47 | unsigned int rev = (siliconid >> 16) & 0xff; |
48 | unsigned int gen = (siliconid >> 24) & 0xff; |
49 | |
50 | if (gen < 0x5) { |
51 | /* AST2500 and below */ |
52 | switch (rev) { |
53 | case 0: |
54 | return "A0" ; |
55 | case 1: |
56 | return "A1" ; |
57 | case 3: |
58 | return "A2" ; |
59 | } |
60 | } else { |
61 | /* AST2600 */ |
62 | switch (rev) { |
63 | case 0: |
64 | return "A0" ; |
65 | case 1: |
66 | return "A1" ; |
67 | case 2: |
68 | return "A2" ; |
69 | case 3: |
70 | return "A3" ; |
71 | } |
72 | } |
73 | |
74 | return "??" ; |
75 | } |
76 | |
77 | static int __init aspeed_socinfo_init(void) |
78 | { |
79 | struct soc_device_attribute *attrs; |
80 | struct soc_device *soc_dev; |
81 | struct device_node *np; |
82 | void __iomem *reg; |
83 | bool has_chipid = false; |
84 | u32 siliconid; |
85 | u32 chipid[2]; |
86 | const char *machine = NULL; |
87 | |
88 | np = of_find_compatible_node(NULL, NULL, compat: "aspeed,silicon-id" ); |
89 | if (!of_device_is_available(device: np)) { |
90 | of_node_put(node: np); |
91 | return -ENODEV; |
92 | } |
93 | |
94 | reg = of_iomap(node: np, index: 0); |
95 | if (!reg) { |
96 | of_node_put(node: np); |
97 | return -ENODEV; |
98 | } |
99 | siliconid = readl(addr: reg); |
100 | iounmap(addr: reg); |
101 | |
102 | /* This is optional, the ast2400 does not have it */ |
103 | reg = of_iomap(node: np, index: 1); |
104 | if (reg) { |
105 | has_chipid = true; |
106 | chipid[0] = readl(addr: reg); |
107 | chipid[1] = readl(addr: reg + 4); |
108 | iounmap(addr: reg); |
109 | } |
110 | of_node_put(node: np); |
111 | |
112 | attrs = kzalloc(size: sizeof(*attrs), GFP_KERNEL); |
113 | if (!attrs) |
114 | return -ENODEV; |
115 | |
116 | /* |
117 | * Machine: Romulus BMC |
118 | * Family: AST2500 |
119 | * Revision: A1 |
120 | * SoC ID: raw silicon revision id |
121 | * Serial Number: 64-bit chipid |
122 | */ |
123 | |
124 | np = of_find_node_by_path(path: "/" ); |
125 | of_property_read_string(np, propname: "model" , out_string: &machine); |
126 | if (machine) |
127 | attrs->machine = kstrdup(s: machine, GFP_KERNEL); |
128 | of_node_put(node: np); |
129 | |
130 | attrs->family = siliconid_to_name(siliconid); |
131 | attrs->revision = siliconid_to_rev(siliconid); |
132 | attrs->soc_id = kasprintf(GFP_KERNEL, fmt: "%08x" , siliconid); |
133 | |
134 | if (has_chipid) |
135 | attrs->serial_number = kasprintf(GFP_KERNEL, fmt: "%08x%08x" , |
136 | chipid[1], chipid[0]); |
137 | |
138 | soc_dev = soc_device_register(soc_plat_dev_attr: attrs); |
139 | if (IS_ERR(ptr: soc_dev)) { |
140 | kfree(objp: attrs->machine); |
141 | kfree(objp: attrs->soc_id); |
142 | kfree(objp: attrs->serial_number); |
143 | kfree(objp: attrs); |
144 | return PTR_ERR(ptr: soc_dev); |
145 | } |
146 | |
147 | pr_info("ASPEED %s rev %s (%s)\n" , |
148 | attrs->family, |
149 | attrs->revision, |
150 | attrs->soc_id); |
151 | |
152 | return 0; |
153 | } |
154 | early_initcall(aspeed_socinfo_init); |
155 | |