// SPDX-License-Identifier: Apache-2.0 /* Copyright 2016-2019 IBM Corp. */ #include #include #include #include #include #include #include #include #include #include #include "ibm-fsp.h" #include "lxvpd.h" static const char *zz_ocapi_slot_label(uint32_t chip_id, uint32_t brick_index) { const char *name = NULL; if (chip_id == 0) { if (brick_index == 2) name = "P1-T5"; else name = "P1-T6"; } else { if (brick_index == 2) name = "P1-T7"; else name = "P1-T8"; } return name; } /* We don't yet create NPU device nodes on ZZ, but these values are correct */ static const struct platform_ocapi zz_ocapi = { .i2c_engine = 1, .i2c_port = 4, .i2c_reset_addr = 0x20, .i2c_reset_brick2 = (1 << 1), .i2c_reset_brick3 = (1 << 6), .i2c_reset_brick4 = 0, /* unused */ .i2c_reset_brick5 = 0, /* unused */ .i2c_presence_addr = 0x20, .i2c_presence_brick2 = (1 << 2), /* bottom connector */ .i2c_presence_brick3 = (1 << 7), /* top connector */ .i2c_presence_brick4 = 0, /* unused */ .i2c_presence_brick5 = 0, /* unused */ .odl_phy_swap = true, .ocapi_slot_label = zz_ocapi_slot_label, }; #define NPU_BASE 0x5011000 #define NPU_SIZE 0x2c #define NPU_INDIRECT0 0x8000000009010c3f /* OB0 - no OB3 on ZZ */ static void create_link(struct dt_node *npu, int group, int index) { struct dt_node *link; uint32_t lane_mask; switch (index) { case 2: lane_mask = 0xf1e000; /* 0-3, 7-10 */ break; case 3: lane_mask = 0x00078f; /* 13-16, 20-23 */ break; default: assert(0); } link = dt_new_addr(npu, "link", index); dt_add_property_string(link, "compatible", "ibm,npu-link"); dt_add_property_cells(link, "ibm,npu-link-index", index); dt_add_property_u64s(link, "ibm,npu-phy", NPU_INDIRECT0); dt_add_property_cells(link, "ibm,npu-lane-mask", lane_mask); dt_add_property_cells(link, "ibm,npu-group-id", group); dt_add_property_u64s(link, "ibm,link-speed", 25000000000ul); } static void add_opencapi_dt_nodes(void) { struct dt_node *npu, *xscom; int npu_index = 0; /* * In an ideal world, we should get all the NPU links * information from HDAT. But after some effort, HDAT is still * giving incorrect information for opencapi. As of this * writing: * 1. link usage is wrong for most FPGA cards (0xFFFF vs. 2) * 2. the 24-bit lane mask is aligned differently than on * other platforms (witherspoon) * 3. connecting a link entry in HDAT to the real physical * link will need extra work: * - HDAT does presence detection and only lists links with * an adapter, so we cannot use default ordering like on * witherspoon * - best option is probably the brick ID field (offset 8). * It's coming straight from the MRW, but seems to match * what we expect (2 or 3). Would need to be checked. * * To make things more fun, any change in the HDAT data needs * to be coordinated with PHYP, which is using (some of) those * fields. * * As a consequence: * 1. the hdat parsing code in skiboot remains disabled (for * opencapi) * 2. we hard-code the NPU and links entries in the device * tree. * * Getting the data from HDAT would have the advantage of * providing the real link speed (20.0 vs. 25.78125 gbps), * which is useful as there's one speed-dependent setting we * need to do when initializing the NPU. Our hard coded * definition assumes the higher speed and may need tuning in * debug scenario using a lower link speed. */ dt_for_each_compatible(dt_root, xscom, "ibm,xscom") { /* * our hdat parsing code may create NPU nodes with no * links, so let's make sure we start from a clean * state */ npu = dt_find_by_name_addr(xscom, "npu", NPU_BASE); if (npu) dt_free(npu); npu = dt_new_addr(xscom, "npu", NPU_BASE); dt_add_property_cells(npu, "reg", NPU_BASE, NPU_SIZE); dt_add_property_strings(npu, "compatible", "ibm,power9-npu"); dt_add_property_cells(npu, "ibm,npu-index", npu_index++); dt_add_property_cells(npu, "ibm,npu-links", 2); create_link(npu, 1, 2); create_link(npu, 2, 3); } } static bool zz_probe(void) { /* FIXME: make this neater when the dust settles */ if (dt_node_is_compatible(dt_root, "ibm,zz-1s2u") || dt_node_is_compatible(dt_root, "ibm,zz-1s4u") || dt_node_is_compatible(dt_root, "ibm,zz-2s2u") || dt_node_is_compatible(dt_root, "ibm,zz-2s4u") || dt_node_is_compatible(dt_root, "ibm,zz-1s4u+gen4") || dt_node_is_compatible(dt_root, "ibm,zz-2s2u+gen4") || dt_node_is_compatible(dt_root, "ibm,zz-2s4u+gen4")) { add_opencapi_dt_nodes(); return true; } return false; } static uint32_t ibm_fsp_occ_timeout(void) { /* Use a fixed 60s value for now */ return 60; } static void zz_init(void) { ibm_fsp_init(); hservice_fsp_init(); } DECLARE_PLATFORM(zz) = { .name = "ZZ", .psi = &fsp_platform_psi, .prd = &fsp_platform_prd, .probe = zz_probe, .init = zz_init, .fast_reboot_init = fsp_console_reset, .finalise_dt = ibm_fsp_finalise_dt, .exit = ibm_fsp_exit, .cec_power_down = ibm_fsp_cec_power_down, .cec_reboot = ibm_fsp_cec_reboot, .pci_setup_phb = firenze_pci_setup_phb, .pci_get_slot_info = firenze_pci_get_slot_info, .pci_probe_complete = firenze_pci_send_inventory, .nvram_info = fsp_nvram_info, .nvram_start_read = fsp_nvram_start_read, .nvram_write = fsp_nvram_write, .occ_timeout = ibm_fsp_occ_timeout, .elog_commit = elog_fsp_commit, .start_preload_resource = fsp_start_preload_resource, .resource_loaded = fsp_resource_loaded, .sensor_read = ibm_fsp_sensor_read, .terminate = ibm_fsp_terminate, .ocapi = &zz_ocapi, .npu2_device_detect = npu2_i2c_presence_detect, .op_display = fsp_op_display, .vpd_iohub_load = vpd_iohub_load, .heartbeat_time = fsp_heartbeat_time, };