]>
Commit | Line | Data |
---|---|---|
d2912cb1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
f956a785 LW |
2 | /* |
3 | * Copyright (C) 2014 Linaro Ltd. | |
4 | * | |
5 | * Author: Linus Walleij <linus.walleij@linaro.org> | |
f956a785 LW |
6 | */ |
7 | #include <linux/init.h> | |
8 | #include <linux/io.h> | |
9 | #include <linux/slab.h> | |
10 | #include <linux/sys_soc.h> | |
11 | #include <linux/platform_device.h> | |
12 | #include <linux/mfd/syscon.h> | |
13 | #include <linux/regmap.h> | |
14 | #include <linux/of.h> | |
15 | ||
16 | #define INTEGRATOR_HDR_ID_OFFSET 0x00 | |
17 | ||
18 | static u32 integrator_coreid; | |
19 | ||
20 | static const struct of_device_id integrator_cm_match[] = { | |
21 | { .compatible = "arm,core-module-integrator", }, | |
c7478038 | 22 | { } |
f956a785 LW |
23 | }; |
24 | ||
25 | static const char *integrator_arch_str(u32 id) | |
26 | { | |
27 | switch ((id >> 16) & 0xff) { | |
28 | case 0x00: | |
29 | return "ASB little-endian"; | |
30 | case 0x01: | |
31 | return "AHB little-endian"; | |
32 | case 0x03: | |
33 | return "AHB-Lite system bus, bi-endian"; | |
34 | case 0x04: | |
35 | return "AHB"; | |
36 | case 0x08: | |
37 | return "AHB system bus, ASB processor bus"; | |
38 | default: | |
39 | return "Unknown"; | |
40 | } | |
41 | } | |
42 | ||
43 | static const char *integrator_fpga_str(u32 id) | |
44 | { | |
45 | switch ((id >> 12) & 0xf) { | |
46 | case 0x01: | |
47 | return "XC4062"; | |
48 | case 0x02: | |
49 | return "XC4085"; | |
50 | case 0x03: | |
51 | return "XVC600"; | |
52 | case 0x04: | |
53 | return "EPM7256AE (Altera PLD)"; | |
54 | default: | |
55 | return "Unknown"; | |
56 | } | |
57 | } | |
58 | ||
734776eb SH |
59 | static ssize_t |
60 | manufacturer_show(struct device *dev, struct device_attribute *attr, char *buf) | |
f956a785 LW |
61 | { |
62 | return sprintf(buf, "%02x\n", integrator_coreid >> 24); | |
63 | } | |
64 | ||
734776eb | 65 | static DEVICE_ATTR_RO(manufacturer); |
f956a785 | 66 | |
734776eb SH |
67 | static ssize_t |
68 | arch_show(struct device *dev, struct device_attribute *attr, char *buf) | |
f956a785 LW |
69 | { |
70 | return sprintf(buf, "%s\n", integrator_arch_str(integrator_coreid)); | |
71 | } | |
72 | ||
734776eb | 73 | static DEVICE_ATTR_RO(arch); |
f956a785 | 74 | |
734776eb SH |
75 | static ssize_t |
76 | fpga_show(struct device *dev, struct device_attribute *attr, char *buf) | |
f956a785 LW |
77 | { |
78 | return sprintf(buf, "%s\n", integrator_fpga_str(integrator_coreid)); | |
79 | } | |
80 | ||
734776eb | 81 | static DEVICE_ATTR_RO(fpga); |
f956a785 | 82 | |
734776eb SH |
83 | static ssize_t |
84 | build_show(struct device *dev, struct device_attribute *attr, char *buf) | |
f956a785 LW |
85 | { |
86 | return sprintf(buf, "%02x\n", (integrator_coreid >> 4) & 0xFF); | |
87 | } | |
88 | ||
734776eb | 89 | static DEVICE_ATTR_RO(build); |
f956a785 | 90 | |
be0db32f SH |
91 | static struct attribute *integrator_attrs[] = { |
92 | &dev_attr_manufacturer.attr, | |
93 | &dev_attr_arch.attr, | |
94 | &dev_attr_fpga.attr, | |
95 | &dev_attr_build.attr, | |
96 | NULL | |
97 | }; | |
98 | ||
99 | ATTRIBUTE_GROUPS(integrator); | |
100 | ||
f956a785 LW |
101 | static int __init integrator_soc_init(void) |
102 | { | |
9f467393 | 103 | struct regmap *syscon_regmap; |
f956a785 LW |
104 | struct soc_device *soc_dev; |
105 | struct soc_device_attribute *soc_dev_attr; | |
106 | struct device_node *np; | |
107 | struct device *dev; | |
108 | u32 val; | |
109 | int ret; | |
110 | ||
111 | np = of_find_matching_node(NULL, integrator_cm_match); | |
112 | if (!np) | |
113 | return -ENODEV; | |
114 | ||
115 | syscon_regmap = syscon_node_to_regmap(np); | |
116 | if (IS_ERR(syscon_regmap)) | |
117 | return PTR_ERR(syscon_regmap); | |
118 | ||
119 | ret = regmap_read(syscon_regmap, INTEGRATOR_HDR_ID_OFFSET, | |
120 | &val); | |
121 | if (ret) | |
122 | return -ENODEV; | |
123 | integrator_coreid = val; | |
124 | ||
125 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); | |
126 | if (!soc_dev_attr) | |
127 | return -ENOMEM; | |
128 | ||
129 | soc_dev_attr->soc_id = "Integrator"; | |
130 | soc_dev_attr->machine = "Integrator"; | |
131 | soc_dev_attr->family = "Versatile"; | |
be0db32f | 132 | soc_dev_attr->custom_attr_group = integrator_groups[0]; |
f956a785 LW |
133 | soc_dev = soc_device_register(soc_dev_attr); |
134 | if (IS_ERR(soc_dev)) { | |
135 | kfree(soc_dev_attr); | |
136 | return -ENODEV; | |
137 | } | |
138 | dev = soc_device_to_device(soc_dev); | |
139 | ||
f956a785 LW |
140 | dev_info(dev, "Detected ARM core module:\n"); |
141 | dev_info(dev, " Manufacturer: %02x\n", (val >> 24)); | |
142 | dev_info(dev, " Architecture: %s\n", integrator_arch_str(val)); | |
143 | dev_info(dev, " FPGA: %s\n", integrator_fpga_str(val)); | |
144 | dev_info(dev, " Build: %02x\n", (val >> 4) & 0xFF); | |
145 | dev_info(dev, " Rev: %c\n", ('A' + (val & 0x03))); | |
146 | ||
147 | return 0; | |
148 | } | |
149 | device_initcall(integrator_soc_init); |