1 // SPDX-License-Identifier: Apache-2.0
2 /*
3 * Copyright 2019 Wistron Corp.
4 * Copyright 2017 IBM Corp.
5 */
6
7 #include <skiboot.h>
8 #include <device.h>
9 #include <console.h>
10 #include <chip.h>
11 #include <ipmi.h>
12 #include <psi.h>
13 #include <npu-regs.h>
14 #include <npu2.h>
15 #include <pci.h>
16 #include <pci-cfg.h>
17
18 #include <timebase.h>
19
20 #include "astbmc.h"
21
22 /* IPMI message code for Riser-F query (OEM). */
23 #define IPMI_RISERF_QUERY IPMI_CODE(0x32, 0x01)
24
25 static bool mihawk_riserF_found = false;
26 static bool bmc_query_waiting = false;
27
28 #define OPAL_ID_SLOT2 0x01
29 #define OPAL_ID_SLOT4 0x03
30 #define OPAL_ID_SLOT7 0x31
31 #define OPAL_ID_SLOT9 0x33
32
33 /* nvme backplane slots */
34 static const struct slot_table_entry hdd_bay_s2_slots[] = {
35 SW_PLUGGABLE("nvme13", 0x0),
36 SW_PLUGGABLE("nvme14", 0x1),
37 SW_PLUGGABLE("nvme15", 0x2),
38 SW_PLUGGABLE("nvme16", 0x3),
39
40 { .etype = st_end },
41 };
42
43 static const struct slot_table_entry hdd_bay_s4_slots[] = {
44 SW_PLUGGABLE("nvme17", 0x0),
45 SW_PLUGGABLE("nvme18", 0x1),
46 SW_PLUGGABLE("nvme19", 0x2),
47 SW_PLUGGABLE("nvme20", 0x3),
48 SW_PLUGGABLE("nvme21", 0x4),
49 SW_PLUGGABLE("nvme22", 0x5),
50 SW_PLUGGABLE("nvme23", 0x6),
51 SW_PLUGGABLE("nvme24", 0x7),
52
53 { .etype = st_end },
54 };
55
56 static const struct slot_table_entry hdd_bay_s7_slots[] = {
57 SW_PLUGGABLE("nvme9", 0x0),
58 SW_PLUGGABLE("nvme10", 0x1),
59 SW_PLUGGABLE("nvme11", 0x2),
60 SW_PLUGGABLE("nvme12", 0x3),
61
62 { .etype = st_end },
63 };
64
65 static const struct slot_table_entry hdd_bay_s9_slots[] = {
66 SW_PLUGGABLE("nvme1", 0x0),
67 SW_PLUGGABLE("nvme2", 0x1),
68 SW_PLUGGABLE("nvme3", 0x2),
69 SW_PLUGGABLE("nvme4", 0x3),
70 SW_PLUGGABLE("nvme5", 0x4),
71 SW_PLUGGABLE("nvme6", 0x5),
72 SW_PLUGGABLE("nvme7", 0x6),
73 SW_PLUGGABLE("nvme8", 0x7),
74
75 { .etype = st_end },
76 };
77
mihawk_get_slot_info(struct phb * phb,struct pci_device * pd)78 static void mihawk_get_slot_info(struct phb *phb, struct pci_device *pd)
79 {
80 const struct slot_table_entry *ent = NULL;
81
82 if (!pd || pd->slot)
83 return;
84
85 /*
86 * If we find a 8533 or c012 switch then assume it's the NVMe Rack.
87 * This might break if we have another switch with the same vdid in
88 * the system for some reason. This is a really dumb hack, but until
89 * we get query the BMC about wether we have a HDD rack or not we
90 * don't have much of a choice.
91 */
92 if (pd->dev_type == PCIE_TYPE_SWITCH_DNPORT) {
93 if (pd->vdid == 0x853311f8) { // for microsemi controller
94 for (ent = hdd_bay_s9_slots; ent->etype != st_end; ent++)
95 if (ent->location == (pd->bdfn & 0xff))
96 break;
97 } else if (pd->vdid == 0xc0121000) { // for broadcom nvme hba
98 switch (phb->opal_id) {
99 case OPAL_ID_SLOT2:
100 ent = hdd_bay_s2_slots;
101 break;
102 case OPAL_ID_SLOT4:
103 ent = hdd_bay_s4_slots;
104 break;
105 case OPAL_ID_SLOT7:
106 ent = hdd_bay_s7_slots;
107 break;
108 case OPAL_ID_SLOT9:
109 default:
110 ent = hdd_bay_s9_slots;
111 break;
112 }
113
114 for (; ent->etype != st_end; ent++)
115 if (ent->location == (pd->bdfn & 0xff))
116 break;
117 }
118 }
119
120 if (ent)
121 slot_table_add_slot_info(pd, ent);
122 else
123 slot_table_get_slot_info(phb, pd);
124 }
125
mihawk_ocapi_slot_label(uint32_t chip_id,uint32_t brick_index)126 static const char *mihawk_ocapi_slot_label(uint32_t chip_id,
127 uint32_t brick_index)
128 {
129 const char *name = NULL;
130
131 if (chip_id == 0) {
132 if (brick_index == 2)
133 name = "JP90NVB1";
134 else
135 name = "JP90NVT1";
136 } else {
137 if (brick_index == 2)
138 name = "JP91NVB1";
139 else
140 name = "JP91NVT1";
141 }
142 return name;
143 }
144
145 static const struct ocapi_phy_setup mihawk_phy = {
146 .tx_ffe_pre_coeff = 0x3,
147 .tx_ffe_post_coeff = 0x14,
148 .tx_ffe_boost_en = 0,
149 };
150
151 static const struct platform_ocapi mihawk_ocapi = {
152 .i2c_engine = 1,
153 .i2c_port = 4,
154 .i2c_reset_addr = 0x20,
155 .i2c_reset_brick2 = (1 << 1),
156 .i2c_reset_brick3 = (1 << 6),
157 .i2c_reset_brick4 = 0, /* unused */
158 .i2c_reset_brick5 = 0, /* unused */
159 .i2c_presence_addr = 0x20,
160 .i2c_presence_brick2 = (1 << 2), /* bottom connector */
161 .i2c_presence_brick3 = (1 << 7), /* top connector */
162 .i2c_presence_brick4 = 0, /* unused */
163 .i2c_presence_brick5 = 0, /* unused */
164 .odl_phy_swap = true,
165 .ocapi_slot_label = mihawk_ocapi_slot_label,
166 .phy_setup = &mihawk_phy,
167 };
168
169 static const struct slot_table_entry P1E1A_x8_PLX8748_RiserA_down[] = {
170 SW_PLUGGABLE("Slot7", 0x10),
171 SW_PLUGGABLE("Slot8", 0x8),
172 SW_PLUGGABLE("Slot10", 0x9),
173
174 { .etype = st_end }
175 };
176
177 static const struct slot_table_entry P1E1A_x8_PLX8748_RiserA_up[] = {
178 {
179 .etype = st_builtin_dev,
180 .location = ST_LOC_DEVFN(0,0),
181 .children = P1E1A_x8_PLX8748_RiserA_down,
182 },
183 { .etype = st_end }
184 };
185
186 static const struct slot_table_entry p1phb1_rA_slot[] = {
187 {
188 .etype = st_builtin_dev,
189 .location = ST_LOC_DEVFN(0,0),
190 .children = P1E1A_x8_PLX8748_RiserA_up,
191 },
192 { .etype = st_end },
193 };
194
195 static const struct slot_table_entry P0E1A_x8_PLX8748_RiserA_down[] = {
196 SW_PLUGGABLE("Slot2", 0x10),
197 SW_PLUGGABLE("Slot3", 0x8),
198 SW_PLUGGABLE("Slot5", 0x9),
199
200 { .etype = st_end }
201 };
202
203 static const struct slot_table_entry P0E1A_x8_PLX8748_RiserA_up[] = {
204 {
205 .etype = st_builtin_dev,
206 .location = ST_LOC_DEVFN(0,0),
207 .children = P0E1A_x8_PLX8748_RiserA_down,
208 },
209 { .etype = st_end }
210 };
211
212 static const struct slot_table_entry p0phb1_rA_slot[] = {
213 {
214 .etype = st_builtin_dev,
215 .location = ST_LOC_DEVFN(0,0),
216 .children = P0E1A_x8_PLX8748_RiserA_up,
217 },
218 { .etype = st_end },
219 };
220
221 static const struct slot_table_entry P1E1A_x8_PLX8748_RiserF_down[] = {
222 SW_PLUGGABLE("Slot7", 0x10),
223 SW_PLUGGABLE("Slot10", 0x9),
224
225 { .etype = st_end }
226 };
227
228 static const struct slot_table_entry P1E1A_x8_PLX8748_RiserF_up[] = {
229 {
230 .etype = st_builtin_dev,
231 .location = ST_LOC_DEVFN(0,0),
232 .children = P1E1A_x8_PLX8748_RiserF_down,
233 },
234 { .etype = st_end }
235 };
236
237 static const struct slot_table_entry p1phb1_rF_slot[] = {
238 {
239 .etype = st_builtin_dev,
240 .location = ST_LOC_DEVFN(0,0),
241 .children = P1E1A_x8_PLX8748_RiserF_up,
242 },
243 { .etype = st_end },
244 };
245
246 static const struct slot_table_entry P0E1A_x8_PLX8748_RiserF_down[] = {
247 SW_PLUGGABLE("Slot2", 0x10),
248 SW_PLUGGABLE("Slot5", 0x9),
249
250 { .etype = st_end }
251 };
252
253 static const struct slot_table_entry P0E1A_x8_PLX8748_RiserF_up[] = {
254 {
255 .etype = st_builtin_dev,
256 .location = ST_LOC_DEVFN(0,0),
257 .children = P0E1A_x8_PLX8748_RiserF_down,
258 },
259 { .etype = st_end }
260 };
261
262 static const struct slot_table_entry p0phb1_rF_slot[] = {
263 {
264 .etype = st_builtin_dev,
265 .location = ST_LOC_DEVFN(0,0),
266 .children = P0E1A_x8_PLX8748_RiserF_up,
267 },
268 { .etype = st_end },
269 };
270
271 static const struct slot_table_entry P1E2_x16_Switch_down[] = {
272 SW_PLUGGABLE("Slot8", 0x1),
273 SW_PLUGGABLE("Slot9", 0x0),
274
275 { .etype = st_end }
276 };
277
278 static const struct slot_table_entry P1E2_x16_Switch_up[] = {
279 {
280 .etype = st_builtin_dev,
281 .location = ST_LOC_DEVFN(0,0),
282 .children = P1E2_x16_Switch_down,
283 },
284 { .etype = st_end }
285 };
286
287 static const struct slot_table_entry p1phb3_switch_slot[] = {
288 {
289 .etype = st_builtin_dev,
290 .location = ST_LOC_DEVFN(0,0),
291 .children = P1E2_x16_Switch_up,
292 },
293 { .etype = st_end },
294 };
295
296 static const struct slot_table_entry P0E2_x16_Switch_down[] = {
297 SW_PLUGGABLE("Slot3", 0x1),
298 SW_PLUGGABLE("Slot4", 0x0),
299
300 { .etype = st_end }
301 };
302
303 static const struct slot_table_entry P0E2_x16_Switch_up[] = {
304 {
305 .etype = st_builtin_dev,
306 .location = ST_LOC_DEVFN(0,0),
307 .children = P0E2_x16_Switch_down,
308 },
309 { .etype = st_end }
310 };
311
312 static const struct slot_table_entry p0phb3_switch_slot[] = {
313 {
314 .etype = st_builtin_dev,
315 .location = ST_LOC_DEVFN(0,0),
316 .children = P0E2_x16_Switch_up,
317 },
318 { .etype = st_end },
319 };
320
321 ST_PLUGGABLE(p0phb0_slot, "Slot1");
322 ST_PLUGGABLE(p0phb3_slot, "Slot4");
323 ST_PLUGGABLE(p1phb0_slot, "Slot6");
324 ST_PLUGGABLE(p1phb3_slot, "Slot9");
325
326 static const struct slot_table_entry mihawk_riserA_phb_table[] = {
327 /* ==== CPU0 ==== */
328 ST_PHB_ENTRY(0, 0, p0phb0_slot), /* P0E0_x16_Slot1 */
329 ST_PHB_ENTRY(0, 1, p0phb1_rA_slot), /* P0E1A_x8_PLX8748-1_Slot2-3-5 */
330 //ST_PHB_ENTRY(0, 2, p0phb2_slot), /* P0E1B_x8_USBTI7340 */
331 ST_PHB_ENTRY(0, 3, p0phb3_slot), /* P0E2_x16_Slot4 */
332
333 /* ==== CPU1 ==== */
334 ST_PHB_ENTRY(8, 0, p1phb0_slot), /* P1E0_x16_Slot6 */
335 ST_PHB_ENTRY(8, 1, p1phb1_rA_slot), /* P1E1A_x8_PLX8748-2_Slot7-8-10 */
336 //ST_PHB_ENTRY(8, 2, p1phb2_slot), /* P1E1B_x8_NA */
337 ST_PHB_ENTRY(8, 3, p1phb3_slot), /* P1E2_x16_Slot9 */
338
339 { .etype = st_end },
340 };
341
342 static const struct slot_table_entry mihawk_riserF_phb_table[] = {
343 /* ==== CPU0 ==== */
344 ST_PHB_ENTRY(0, 0, p0phb0_slot), /* P0E0_x16_Slot1 */
345 ST_PHB_ENTRY(0, 1, p0phb1_rF_slot), /* P0E1A_x8_PLX8748-1_Slot2-5 */
346 //ST_PHB_ENTRY(0, 2, p0phb2_slot), /* P0E1B_x8_USBTI7340 */
347 ST_PHB_ENTRY(0, 3, p0phb3_switch_slot),/* P0E2_x16_SWITCH_Slot3-4 */
348
349 /* ==== CPU1 ==== */
350 ST_PHB_ENTRY(8, 0, p1phb0_slot), /* P1E0_x16_Slot6 */
351 ST_PHB_ENTRY(8, 1, p1phb1_rF_slot), /* P1E1A_x8_PLX8748-2_Slot7-10 */
352 //ST_PHB_ENTRY(8, 2, p1phb2_slot), /* P1E1B_x8_NA */
353 ST_PHB_ENTRY(8, 3, p1phb3_switch_slot),/* P1E2_x16_SWITCH_Slot8-9 */
354
355 { .etype = st_end },
356 };
357
358 #define NPU_BASE 0x5011000
359 #define NPU_SIZE 0x2c
360 #define NPU_INDIRECT0 0x8000000009010c3fUL /* OB0 - no OB3 on Mihawk */
361
362 /* OpenCAPI only */
create_link(struct dt_node * npu,int group,int index)363 static void create_link(struct dt_node *npu, int group, int index)
364 {
365 struct dt_node *link;
366 uint32_t lane_mask;
367 char namebuf[32];
368
369 snprintf(namebuf, sizeof(namebuf), "link@%x", index);
370 link = dt_new(npu, namebuf);
371 assert(link);
372
373 dt_add_property_string(link, "compatible", "ibm,npu-link");
374 dt_add_property_cells(link, "ibm,npu-link-index", index);
375
376 switch (index) {
377 case 2:
378 lane_mask = 0xf1e000; /* 0-3, 7-10 */
379 break;
380 case 3:
381 lane_mask = 0x00078f; /* 13-16, 20-23 */
382 break;
383 default:
384 assert(0);
385 }
386
387 dt_add_property_u64s(link, "ibm,npu-phy", NPU_INDIRECT0);
388 dt_add_property_cells(link, "ibm,npu-lane-mask", lane_mask);
389 dt_add_property_cells(link, "ibm,npu-group-id", group);
390 dt_add_property_u64s(link, "ibm,link-speed", 25000000000ul);
391 }
392
393 /* FIXME: Get rid of this after we get NPU information properly via HDAT/MRW */
mihawk_create_npu(void)394 static void mihawk_create_npu(void)
395 {
396 struct dt_node *xscom, *npu;
397 int npu_index = 0;
398 char namebuf[32];
399
400 /* Return if there's already an NPU in the device tree */
401 if (dt_find_compatible_node(dt_root, NULL, "ibm,power9-npu"))
402 return;
403
404 prlog(PR_DEBUG, "OCAPI: Adding NPU device nodes\n");
405 dt_for_each_compatible(dt_root, xscom, "ibm,xscom") {
406 snprintf(namebuf, sizeof(namebuf), "npu@%x", NPU_BASE);
407 npu = dt_new(xscom, namebuf);
408 dt_add_property_cells(npu, "reg", NPU_BASE, NPU_SIZE);
409 dt_add_property_strings(npu, "compatible", "ibm,power9-npu");
410 dt_add_property_cells(npu, "ibm,npu-index", npu_index++);
411 dt_add_property_cells(npu, "ibm,npu-links", 2);
412 create_link(npu, 1, 2);
413 create_link(npu, 2, 3);
414 }
415 }
416
417 /* FIXME: Get rid of this after we get NPU information properly via HDAT/MRW */
mihawk_create_ocapi_i2c_bus(void)418 static void mihawk_create_ocapi_i2c_bus(void)
419 {
420 struct dt_node *xscom, *i2cm, *i2c_bus;
421 prlog(PR_DEBUG, "OCAPI: Adding I2C bus device node for OCAPI reset\n");
422 dt_for_each_compatible(dt_root, xscom, "ibm,xscom") {
423 i2cm = dt_find_by_name(xscom, "i2cm@a1000");
424 if (!i2cm) {
425 prlog(PR_ERR, "OCAPI: Failed to get I2C bus device node\n");
426 continue;
427 }
428
429 if (dt_find_by_name(i2cm, "i2c-bus@4"))
430 continue;
431
432 i2c_bus = dt_new_addr(i2cm, "i2c-bus", 4);
433 dt_add_property_cells(i2c_bus, "reg", 4);
434 dt_add_property_cells(i2c_bus, "bus-frequency", 0x61a80);
435 dt_add_property_strings(i2c_bus, "compatible",
436 "ibm,opal-i2c", "ibm,power8-i2c-port",
437 "ibm,power9-i2c-port");
438 }
439 }
440
441 /*
442 * HACK: Hostboot doesn't export the correct data for the system VPD EEPROM
443 * for this system. So we need to work around it here.
444 */
vpd_dt_fixup(void)445 static void vpd_dt_fixup(void)
446 {
447 struct dt_node *n = dt_find_by_path(dt_root,
448 "/xscom@603fc00000000/i2cm@a2000/i2c-bus@0/eeprom@50");
449
450 if (n) {
451 dt_check_del_prop(n, "compatible");
452 dt_add_property_string(n, "compatible", "atmel,24c512");
453
454 dt_check_del_prop(n, "label");
455 dt_add_property_string(n, "label", "system-vpd");
456 }
457 }
458
mihawk_probe(void)459 static bool mihawk_probe(void)
460 {
461 if (!dt_node_is_compatible(dt_root, "ibm,mihawk") &&
462 !dt_node_is_compatible(dt_root, "wistron,mihawk"))
463 return false;
464
465 /* Lot of common early inits here */
466 astbmc_early_init();
467
468 /* Setup UART for use by OPAL (Linux hvc) */
469 uart_set_console_policy(UART_CONSOLE_OPAL);
470
471 vpd_dt_fixup();
472
473 mihawk_create_npu();
474 mihawk_create_ocapi_i2c_bus();
475
476 return true;
477 }
478
mihawk_riser_query_complete(struct ipmi_msg * msg)479 static void mihawk_riser_query_complete(struct ipmi_msg *msg)
480 {
481 uint8_t *riser_state;
482
483 if (msg->cc != IPMI_CC_NO_ERROR) {
484 prlog(PR_ERR, "Mihawk: IPMI riser query returned error. cmd=0x%02x,"
485 " netfn=0x%02x, rc=0x%x\n", msg->cmd, msg->netfn, msg->cc);
486 bmc_query_waiting = false;
487 ipmi_free_msg(msg);
488 return;
489 }
490
491 prlog(PR_DEBUG, "Mihawk: IPMI Got riser query result. p0:%02x, p1:%02x\n"
492 , msg->data[0], msg->data[1]);
493
494 riser_state = (uint8_t*)msg->user_data;
495 lwsync();
496 *riser_state = msg->data[0] << 4 | msg->data[1];
497
498 bmc_query_waiting = false;
499 ipmi_free_msg(msg);
500 }
501
mihawk_init(void)502 static void mihawk_init(void)
503 {
504 struct ipmi_msg *ipmi_msg;
505 uint8_t riser_state = 0;
506 int timeout_ms = 3000;
507
508 astbmc_init();
509
510 /*
511 * We use IPMI to ask BMC if Riser-F is installed and set up the
512 * corresponding slot table.
513 */
514 ipmi_msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
515 IPMI_RISERF_QUERY,
516 mihawk_riser_query_complete,
517 &riser_state, NULL, 0, 2);
518
519 if (!ipmi_msg) {
520 prlog(PR_ERR, "Mihawk: Couldn't create ipmi msg.");
521 } else {
522 ipmi_msg->error = mihawk_riser_query_complete;
523 ipmi_queue_msg(ipmi_msg);
524 bmc_query_waiting = true;
525
526 prlog(PR_DEBUG, "Mihawk: Requesting IPMI_RISERF_QUERY (netfn "
527 "%02x, cmd %02x)\n", ipmi_msg->netfn, ipmi_msg->cmd);
528
529 while (bmc_query_waiting) {
530 time_wait_ms(10);
531 timeout_ms -= 10;
532
533 if (timeout_ms == 0)
534 break;
535 }
536 }
537
538 prlog(PR_DEBUG, "Mihawk: IPMI_RISERF_QUERY finish. riser_state: %02x"
539 ", waiting: %d\n", riser_state, bmc_query_waiting);
540
541 if (riser_state != 0) {
542 mihawk_riserF_found = true;
543 slot_table_init(mihawk_riserF_phb_table);
544 prlog(PR_DEBUG, "Mihawk: Detect Riser-F via IPMI\n");
545 } else {
546 slot_table_init(mihawk_riserA_phb_table);
547 prlog(PR_DEBUG, "Mihawk: No Riser-F found, use Riser-A table\n");
548 }
549 }
550
551 DECLARE_PLATFORM(mihawk) = {
552 .name = "Mihawk",
553 .probe = mihawk_probe,
554 .init = mihawk_init,
555 .start_preload_resource = flash_start_preload_resource,
556 .resource_loaded = flash_resource_loaded,
557 .bmc = &bmc_plat_ast2500_openbmc,
558 .pci_get_slot_info = mihawk_get_slot_info,
559 .pci_probe_complete = check_all_slot_table,
560 .cec_power_down = astbmc_ipmi_power_down,
561 .cec_reboot = astbmc_ipmi_reboot,
562 .elog_commit = ipmi_elog_commit,
563 .exit = ipmi_wdt_final_reset,
564 .terminate = ipmi_terminate,
565 .ocapi = &mihawk_ocapi,
566 .npu2_device_detect = npu2_i2c_presence_detect,
567 };
568