Branch data Line data Source code
1 : : // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 : : /* Copyright 2017-2019 IBM Corp. */
3 : :
4 : : #include <device.h>
5 : : #include <cpu.h>
6 : : #include <vpd.h>
7 : : #include <interrupts.h>
8 : : #include <ccan/str/str.h>
9 : : #include <chip.h>
10 : : #include <i2c.h>
11 : :
12 : : #include "spira.h"
13 : : #include "hdata.h"
14 : :
15 : : /*
16 : : * These should probably be in hw/p8-i2c.c. However, that would require the HDAT
17 : : * test to #include hw/p8-i2c.c which is probably going to be more trouble than
18 : : * it's worth. So these helpers are here instead.
19 : : */
20 : 0 : struct dt_node *p8_i2c_add_master_node(struct dt_node *xscom, int eng_id)
21 : : {
22 : : uint64_t clk, size, xscom_base;
23 : : struct dt_node *i2cm;
24 : :
25 : 0 : dt_for_each_compatible(xscom, i2cm, "ibm,power8-i2cm")
26 : 0 : if (dt_prop_get_u32(i2cm, "chip-engine#") == eng_id)
27 : 0 : return i2cm;
28 : :
29 : : /* XXX: Might need to be updated for new chips */
30 : 0 : if (proc_gen >= proc_gen_p9)
31 : 0 : size = 0x1000;
32 : : else
33 : 0 : size = 0x20;
34 : :
35 : 0 : xscom_base = 0xa0000 + size * eng_id;
36 : :
37 : 0 : i2cm = dt_new_addr(xscom, "i2cm", xscom_base);
38 : 0 : if (!i2cm)
39 : 0 : return NULL;
40 : :
41 : 0 : if (proc_gen >= proc_gen_p9) {
42 : 0 : dt_add_property_strings(i2cm, "compatible", "ibm,power8-i2cm",
43 : : "ibm,power9-i2cm");
44 : : } else {
45 : 0 : dt_add_property_strings(i2cm, "compatible", "ibm,power8-i2cm");
46 : : }
47 : :
48 : 0 : dt_add_property_cells(i2cm, "reg", xscom_base, size);
49 : 0 : dt_add_property_cells(i2cm, "#size-cells", 0);
50 : 0 : dt_add_property_cells(i2cm, "#address-cells", 1);
51 : 0 : dt_add_property_cells(i2cm, "chip-engine#", eng_id);
52 : :
53 : : /*
54 : : * The i2cm runs at 1/4th the PIB frequency. If we don't know the PIB
55 : : * frequency then pick 150MHz which should be in the right ballpark.
56 : : */
57 : 0 : clk = dt_prop_get_u64_def(xscom, "bus-frequency", 0);
58 : 0 : if (clk)
59 : 0 : dt_add_property_cells(i2cm, "clock-frequency", clk / 4);
60 : : else
61 : 0 : dt_add_property_cells(i2cm, "clock-frequency", 150000000);
62 : :
63 : 0 : return i2cm;
64 : : }
65 : :
66 : 0 : struct dt_node *__p8_i2c_add_port_node(struct dt_node *master, int port_id,
67 : : uint32_t bus_speed)
68 : : {
69 : : struct dt_node *port;
70 : : uint32_t speed;
71 : :
72 : 0 : dt_for_each_child(master, port)
73 : 0 : if (dt_prop_get_u32(port, "reg") == port_id)
74 : 0 : goto check_speed;
75 : :
76 : 0 : port = dt_new_addr(master, "i2c-bus", port_id);
77 : 0 : if (!port)
78 : 0 : return NULL;
79 : :
80 : 0 : dt_add_property_cells(port, "reg", port_id);
81 : 0 : dt_add_property_cells(port, "#size-cells", 0);
82 : 0 : dt_add_property_cells(port, "#address-cells", 1);
83 : :
84 : : /* The P9 I2C master is fully compatible with the P8 one */
85 : 0 : if (proc_gen >= proc_gen_p9) {
86 : 0 : dt_add_property_strings(port, "compatible", "ibm,opal-i2c",
87 : : "ibm,power8-i2c-port", "ibm,power9-i2c-port");
88 : : } else {
89 : 0 : dt_add_property_strings(port, "compatible", "ibm,opal-i2c",
90 : : "ibm,power8-i2c-port");
91 : : }
92 : :
93 : 0 : check_speed:
94 : 0 : speed = dt_prop_get_u32_def(port, "bus-frequency", 0xffffffff);
95 : 0 : if (bus_speed < speed) {
96 : 0 : dt_check_del_prop(port, "bus-frequency");
97 : 0 : dt_add_property_cells(port, "bus-frequency", bus_speed);
98 : : }
99 : :
100 : 0 : return port;
101 : : }
102 : :
103 : :
104 : 0 : struct dt_node *p8_i2c_add_port_node(struct dt_node *xscom, int eng_id,
105 : : int port_id, uint32_t bus_freq)
106 : : {
107 : : struct dt_node *i2cm;
108 : :
109 : 0 : i2cm = p8_i2c_add_master_node(xscom, eng_id);
110 : 0 : if (!i2cm)
111 : 0 : return NULL;
112 : :
113 : 0 : return __p8_i2c_add_port_node(i2cm, port_id, bus_freq);
114 : : }
115 : :
116 : : struct i2c_dev {
117 : : uint8_t i2cm_engine;
118 : : uint8_t i2cm_port;
119 : : __be16 i2c_bus_freq;
120 : :
121 : : /* i2c slave info */
122 : : uint8_t type;
123 : : uint8_t dev_addr;
124 : : uint8_t dev_port;
125 : : uint8_t __reserved;
126 : :
127 : : __be32 purpose;
128 : : __be32 i2c_link;
129 : : __be16 slca_index;
130 : : };
131 : :
132 : : struct hdat_i2c_type {
133 : : uint32_t id;
134 : : const char *name;
135 : : const char *compat;
136 : : };
137 : :
138 : : static struct hdat_i2c_type hdat_i2c_devs[] = {
139 : : { 0x1, "gpio", "nxp,pca9551" },
140 : : /* XXX: Please verify that all VPD EEPROMs are of this type */
141 : : { 0x2, "eeprom", "atmel,24c128" },
142 : : { 0x3, "tpm", "nuvoton,npct650" },
143 : : { 0x4, "i2c", NULL }, /* MEX-FPGA */
144 : : { 0x5, "i2c", NULL }, /* UCX90xx devs for PCI Hotplug */
145 : : { 0x6, "gpio", "nxp,pca9552" },
146 : : { 0x7, "gpio", "nxp,pca9553" },
147 : : { 0x8, "gpio", "nxp,pca9554" },
148 : : { 0x9, "gpio", "nxp,pca9555" },
149 : : { 0xa, "i2c", NULL }, /* SMP/OpenCAPI Cable */
150 : : { 0xb, "eeprom", "atmel,24c256" },
151 : : { 0xc, "i2c", NULL }, /* Thermal Sensor */
152 : : { 0xd, "eeprom", "atmel,24c04" },
153 : : { 0xe, "eeprom", "atmel,24c512" },
154 : : { 0xf, "eeprom", "atmel,24c32" },
155 : : { 0x10, "eeprom", "atmel,24c64" },
156 : : { 0x11, "eeprom", "atmel,24c16" },
157 : : { 0x12, "i2c", NULL }, /* NVDIA GPU */
158 : : { 0x13, "i2c", "nxp,lpc11u35" },
159 : : };
160 : :
161 : : struct hdat_i2c_info {
162 : : uint32_t id;
163 : : bool allowed; /* true if the host may use the device */
164 : : const char *label;
165 : : };
166 : :
167 : : static struct hdat_i2c_info hdat_i2c_extra_info[] = {
168 : : { 0x1, false, "led-controller" },
169 : : { 0x2, false, "pci-hotplug-pgood" },
170 : : { 0x3, false, "pci-hotplug-control" },
171 : : { 0x4, true, "tpm" },
172 : : { 0x5, true, "module-vpd" },
173 : : { 0x6, true, "dimm-spd" },
174 : : { 0x7, true, "proc-vpd" },
175 : : { 0x8, false, "sbe-eeprom"},
176 : : { 0x9, true, "planar-vpd" },
177 : : { 0xa, false, "opencapi-topology" },
178 : : { 0xb, false, "opencapi-micro-reset" },
179 : : { 0xc, false, "nvlink-cable" },
180 : : { 0xd, false, "secure-window-open" },
181 : : { 0xe, false, "physical-presence" },
182 : : { 0xf, false, "mex-fpga" },
183 : : { 0x10, false, "thermal-sensor" },
184 : : { 0x11, false, "host-i2c-enable" },
185 : : { 0x12, false, "gpu-config" },
186 : : };
187 : :
188 : : /*
189 : : * this is pretty half-assed, to generate the labels properly we need to look
190 : : * up associated SLCA index and determine what kind of module the device is on
191 : : * and why
192 : : */
193 : 0 : static struct hdat_i2c_type *map_type(uint32_t type)
194 : : {
195 : : int i;
196 : :
197 : 0 : for (i = 0; i < ARRAY_SIZE(hdat_i2c_devs); i++)
198 : 0 : if (hdat_i2c_devs[i].id == type)
199 : 0 : return &hdat_i2c_devs[i];
200 : :
201 : 0 : return NULL;
202 : : }
203 : :
204 : 0 : static struct hdat_i2c_info *get_info(uint32_t type)
205 : : {
206 : : static struct hdat_i2c_info no_info =
207 : : { .id = 0x0, .allowed = false, .label = "" };
208 : : int i;
209 : :
210 : 0 : for (i = 0; i < ARRAY_SIZE(hdat_i2c_extra_info); i++)
211 : 0 : if (hdat_i2c_extra_info[i].id == type)
212 : 0 : return &hdat_i2c_extra_info[i];
213 : :
214 : 0 : return &no_info;
215 : : }
216 : :
217 : 0 : static bool is_zeros(const void *p, size_t size)
218 : : {
219 : 0 : const char *c = p;
220 : : size_t i;
221 : :
222 : 0 : for (i = 0; i < size; i++)
223 : 0 : if (c[i] != 0)
224 : 0 : return false;
225 : :
226 : 0 : return true;
227 : : }
228 : :
229 : : struct host_i2c_hdr {
230 : : const struct HDIF_array_hdr hdr;
231 : : __be32 version;
232 : : } __packed __align(0x4);
233 : :
234 : 0 : int parse_i2c_devs(const struct HDIF_common_hdr *hdr, int idata_index,
235 : : struct dt_node *xscom)
236 : : {
237 : : struct dt_node *bus, *node;
238 : : const struct hdat_i2c_type *type;
239 : : const struct hdat_i2c_info *info;
240 : : const struct i2c_dev *dev;
241 : : const char *name, *compat;
242 : : const struct host_i2c_hdr *ahdr;
243 : : uint32_t dev_addr;
244 : : uint32_t version;
245 : : uint32_t size;
246 : : uint32_t purpose;
247 : : int i, count;
248 : :
249 : : /*
250 : : * This code makes a few assumptions about XSCOM addrs, etc
251 : : * and will need updating for new processors
252 : : */
253 : 0 : assert(proc_gen == proc_gen_p9 || proc_gen == proc_gen_p10);
254 : :
255 : : /*
256 : : * Emit an error if we get a newer version. This is an interim measure
257 : : * until the new version format is finalised.
258 : : */
259 : 0 : ahdr = HDIF_get_idata(hdr, idata_index, &size);
260 : 0 : if (!ahdr || !size)
261 : 0 : return -1;
262 : :
263 : : /*
264 : : * Some hostboots don't correctly fill the version field. On these
265 : : * the offset from the start of the header to the start of the array
266 : : * is 16 bytes.
267 : : */
268 : 0 : if (be32_to_cpu(ahdr->hdr.offset) == 16) {
269 : 0 : version = 1;
270 : 0 : prerror("I2C: HDAT device array has no version! Assuming v1\n");
271 : : } else {
272 : 0 : version = be32_to_cpu(ahdr->version);
273 : : }
274 : :
275 : 0 : if (version == 2) {
276 : 0 : prlog(PR_INFO, "I2C: v%d found, but not supported. Parsing as v1\n",
277 : : version);
278 : 0 : } else if (version > 2) {
279 : 0 : prerror("I2C: v%d found, but not supported! THIS IS A BUG\n",
280 : : version);
281 : 0 : return -1;
282 : : }
283 : :
284 : 0 : count = HDIF_get_iarray_size(hdr, idata_index);
285 : 0 : for (i = 0; i < count; i++) {
286 : 0 : dev = HDIF_get_iarray_item(hdr, idata_index, i, &size);
287 : :
288 : : /*
289 : : * XXX: Some broken hostboots populate i2c devs with zeros.
290 : : * Workaround them for now.
291 : : */
292 : 0 : if (is_zeros(dev, size)) {
293 : 0 : prerror("I2C: Ignoring broken i2c dev %d\n", i);
294 : 0 : continue;
295 : : }
296 : :
297 : : /*
298 : : * On some systems the CFAM I2C master is represented in the
299 : : * host I2C table as engine 6. There are only 4 (0, 1, 2, 3)
300 : : * engines accessible to the host via XSCOM so filter out
301 : : * engines outside this range so we don't create bogus
302 : : * i2cm@<addr> nodes.
303 : : */
304 : 0 : if (dev->i2cm_engine >= 4 &&
305 : 0 : (proc_gen == proc_gen_p9 || proc_gen == proc_gen_p10))
306 : 0 : continue;
307 : :
308 : 0 : bus = p8_i2c_add_port_node(xscom, dev->i2cm_engine, dev->i2cm_port,
309 : 0 : be16_to_cpu(dev->i2c_bus_freq) * 1000);
310 : :
311 : 0 : if (!bus) {
312 : 0 : prerror("Unable to add node for e%dp%d under %s\n",
313 : : dev->i2cm_engine, dev->i2cm_port, xscom->name);
314 : 0 : continue;
315 : : }
316 : :
317 : : /*
318 : : * Looks like hostboot gives the address as an 8 bit, left
319 : : * justified quantity (i.e it includes the R/W bit). So we need
320 : : * to strip it off to get an address linux can use.
321 : : */
322 : 0 : dev_addr = dev->dev_addr >> 1;
323 : :
324 : 0 : purpose = be32_to_cpu(dev->purpose);
325 : 0 : type = map_type(dev->type);
326 : 0 : info = get_info(purpose);
327 : :
328 : : /* HACK: Hostboot doesn't export the correct type information
329 : : * for the DIMM SPD EEPROMs. This is a problem because SPD
330 : : * EEPROMs have a different wire protocol to the atmel,24XXXX
331 : : * series. The main difference being that SPD EEPROMs have an
332 : : * 8bit offset rather than a 16bit offset. This means that the
333 : : * driver will send 2 bytes when doing a random read,
334 : : * potentially overwriting part of the SPD information.
335 : : *
336 : : * Just to make things interested the FSP also gets the device
337 : : * type wrong. To work around both just set the device-type to
338 : : * "spd" for anything in the 0x50 to 0x57 range since that's the
339 : : * SPD eeprom range.
340 : : *
341 : : * XXX: Future chips might not use engine 3 for the DIMM buses.
342 : : */
343 : 0 : if (dev->i2cm_engine == 3 && dev_addr >= 0x50
344 : 0 : && dev_addr < 0x58) {
345 : 0 : compat = "spd";
346 : 0 : name = "eeprom";
347 : 0 : } else if (type) {
348 : 0 : compat = type->compat;
349 : 0 : name = type->name;
350 : : } else {
351 : 0 : name = "unknown";
352 : 0 : compat = NULL;
353 : : }
354 : :
355 : : /*
356 : : * An i2c device is unknown if either the i2c device list is
357 : : * outdated or the device is marked as unknown (0xFF) in the
358 : : * hdat. Log both cases to see what/where/why.
359 : : */
360 : 0 : if (!type || dev->type == 0xFF) {
361 : 0 : prlog(PR_NOTICE, "HDAT I2C: found e%dp%d - %s@%x dp:%02x (%#x:%s)\n",
362 : : dev->i2cm_engine, dev->i2cm_port, name, dev_addr,
363 : : dev->dev_port, purpose, info->label);
364 : 0 : continue;
365 : : }
366 : :
367 : 0 : prlog(PR_DEBUG, "HDAT I2C: found e%dp%d - %s@%x dp:%02x (%#x:%s)\n",
368 : : dev->i2cm_engine, dev->i2cm_port, name, dev_addr,
369 : : dev->dev_port, purpose, info->label);
370 : :
371 : : /*
372 : : * Multi-port device require special handling since we need to
373 : : * generate the device-specific DT bindings. For now we're just
374 : : * going to ignore them since these devices are owned by FW
375 : : * any way.
376 : : */
377 : 0 : if (dev->dev_port != 0xff)
378 : 0 : continue;
379 : :
380 : 0 : node = dt_new_addr(bus, name, dev_addr);
381 : 0 : if (!node)
382 : 0 : continue;
383 : :
384 : 0 : dt_add_property_cells(node, "reg", dev_addr);
385 : 0 : dt_add_property_cells(node, "link-id",
386 : : be32_to_cpu(dev->i2c_link));
387 : 0 : if (compat)
388 : 0 : dt_add_property_string(node, "compatible", compat);
389 : 0 : if (info->label)
390 : 0 : dt_add_property_string(node, "label", info->label);
391 : 0 : if (!info->allowed)
392 : 0 : dt_add_property_string(node, "status", "reserved");
393 : :
394 : : /*
395 : : * Set a default timeout of 2s on the ports with a TPM. This is
396 : : * to work around a bug with certain TPM firmwares that can
397 : : * clock stretch for long periods of time and will lock up
398 : : * until they are power cycled if a STOP condition is sent
399 : : * during this period.
400 : : */
401 : 0 : if (dev->type == 0x3)
402 : 0 : dt_add_property_cells(bus, "timeout-ms", 2000);
403 : :
404 : : /* XXX: SLCA index? */
405 : : }
406 : :
407 : 0 : return 0;
408 : : }
|