| // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later |
| /* Copyright 2013-2019 IBM Corp. */ |
| |
| #include <skiboot.h> |
| #include <device.h> |
| #include <fsp.h> |
| #include <pci.h> |
| #include <pci-cfg.h> |
| #include <chip.h> |
| #include <i2c.h> |
| #include <timebase.h> |
| #include <hostservices.h> |
| |
| #include "ibm-fsp.h" |
| #include "lxvpd.h" |
| |
| static struct dt_node *dt_create_i2c_master(struct dt_node *n, uint32_t eng_id) |
| { |
| struct dt_node *i2cm; |
| uint64_t freq; |
| uint32_t clock; |
| |
| /* Each master registers set is of length 0x20 */ |
| i2cm = dt_new_addr(n, "i2cm", 0xa0000 + eng_id * 0x20); |
| if (!i2cm) |
| return NULL; |
| |
| dt_add_property_string(i2cm, "compatible", |
| "ibm,power8-i2cm"); |
| dt_add_property_cells(i2cm, "reg", 0xa0000 + eng_id * 0x20, |
| 0x20); |
| dt_add_property_cells(i2cm, "chip-engine#", eng_id); |
| dt_add_property_cells(i2cm, "#address-cells", 1); |
| dt_add_property_cells(i2cm, "#size-cells", 0); |
| |
| /* Derive the clock source frequency */ |
| freq = dt_prop_get_u64_def(n, "bus-frequency", 0); |
| clock = (u32)(freq / 4); |
| if (clock) |
| dt_add_property_cells(i2cm, "clock-frequency", clock); |
| else |
| dt_add_property_cells(i2cm, "clock-frequency", 125000000); |
| return i2cm; |
| } |
| |
| static struct dt_node *dt_create_i2c_bus(struct dt_node *i2cm, |
| const char *port_name, uint32_t port_id) |
| { |
| static struct dt_node *port; |
| |
| port = dt_new_addr(i2cm, "i2c-bus", port_id); |
| if (!port) |
| return NULL; |
| |
| dt_add_property_strings(port, "compatible", "ibm,power8-i2c-port", |
| "ibm,opal-i2c"); |
| dt_add_property_string(port, "ibm,port-name", port_name); |
| dt_add_property_cells(port, "reg", port_id); |
| dt_add_property_cells(port, "bus-frequency", 400000); |
| dt_add_property_cells(port, "#address-cells", 1); |
| dt_add_property_cells(port, "#size-cells", 0); |
| |
| return port; |
| } |
| |
| static struct dt_node *dt_create_i2c_device(struct dt_node *bus, uint8_t addr, |
| const char *name, const char *compat, |
| const char *label) |
| { |
| struct dt_node *dev; |
| |
| dev = dt_new_addr(bus, name, addr); |
| if (!dev) |
| return NULL; |
| |
| dt_add_property_string(dev, "compatible", compat); |
| dt_add_property_string(dev, "label", label); |
| dt_add_property_cells(dev, "reg", addr); |
| dt_add_property_string(dev, "status", "reserved"); |
| |
| return dev; |
| } |
| |
| static void firenze_dt_fixup_i2cm(void) |
| { |
| struct dt_node *master, *bus, *dev; |
| struct proc_chip *c; |
| const uint32_t *p; |
| char name[32]; |
| uint64_t lx; |
| |
| if (dt_find_compatible_node(dt_root, NULL, "ibm,power8-i2cm")) |
| return; |
| |
| p = dt_prop_get_def(dt_root, "ibm,vpd-lx-info", NULL); |
| if (!p) |
| return; |
| |
| lx = ((uint64_t)p[1] << 32) | p[2]; |
| |
| switch (lx) { |
| case LX_VPD_2S4U_BACKPLANE: |
| case LX_VPD_2S2U_BACKPLANE: |
| case LX_VPD_SHARK_BACKPLANE: /* XXX confirm ? */ |
| /* i2c nodes on chip 0x10 */ |
| c = get_chip(0x10); |
| if (c) { |
| /* Engine 1 */ |
| master = dt_create_i2c_master(c->devnode, 1); |
| assert(master); |
| snprintf(name, sizeof(name), "p8_%08x_e%dp%d", c->id, 1, 0); |
| bus = dt_create_i2c_bus(master, name, 0); |
| assert(bus); |
| dev = dt_create_i2c_device(bus, 0x39, "power-control", |
| "maxim,5961", "pcie-hotplug"); |
| assert(dev); |
| dt_add_property_strings(dev, "target-list", "slot-C4", |
| "slot-C5"); |
| |
| dev = dt_create_i2c_device(bus, 0x3a, "power-control", |
| "maxim,5961", "pcie-hotplug"); |
| assert(dev); |
| dt_add_property_strings(dev, "target-list", "slot-C2", |
| "slot-C3"); |
| } else { |
| prlog(PR_INFO, "PLAT: Chip not found for the id 0x10\n"); |
| } |
| |
| /* Fall through */ |
| case LX_VPD_1S4U_BACKPLANE: |
| case LX_VPD_1S2U_BACKPLANE: |
| /* i2c nodes on chip 0 */ |
| c = get_chip(0); |
| if (!c) { |
| prlog(PR_INFO, "PLAT: Chip not found for the id 0x0\n"); |
| break; |
| } |
| |
| /* Engine 1*/ |
| master = dt_create_i2c_master(c->devnode, 1); |
| assert(master); |
| snprintf(name, sizeof(name), "p8_%08x_e%dp%d", c->id, 1, 0); |
| bus = dt_create_i2c_bus(master, name, 0); |
| assert(bus); |
| dev = dt_create_i2c_device(bus, 0x32, "power-control", |
| "maxim,5961", "pcie-hotplug"); |
| assert(dev); |
| dt_add_property_strings(dev, "target-list", "slot-C10", "slot-C11"); |
| |
| dev = dt_create_i2c_device(bus, 0x35, "power-control", |
| "maxim,5961", "pcie-hotplug"); |
| assert(dev); |
| dt_add_property_strings(dev, "target-list", "slot-C6", "slot-C7"); |
| |
| dev = dt_create_i2c_device(bus, 0x36, "power-control", |
| "maxim,5961", "pcie-hotplug"); |
| assert(dev); |
| dt_add_property_strings(dev, "target-list", "slot-C8", "slot-C9"); |
| |
| dev = dt_create_i2c_device(bus, 0x39, "power-control", "maxim,5961", |
| "pcie-hotplug"); |
| assert(dev); |
| dt_add_property_strings(dev, "target-list", "slot-C12"); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| static bool firenze_probe(void) |
| { |
| if (!dt_node_is_compatible(dt_root, "ibm,firenze")) |
| return false; |
| |
| firenze_dt_fixup_i2cm(); |
| |
| return true; |
| } |
| |
| static uint32_t ibm_fsp_occ_timeout(void) |
| { |
| /* Use a fixed 60s value for now */ |
| return 60; |
| } |
| |
| static void firenze_init(void) |
| { |
| /* We call hservices_init to relocate the hbrt image now, as the FSP |
| * may request an OCC load any time after ibm_fsp_init. |
| */ |
| hservices_init(); |
| |
| ibm_fsp_init(); |
| } |
| |
| DECLARE_PLATFORM(firenze) = { |
| .name = "Firenze", |
| .psi = &fsp_platform_psi, |
| .prd = &fsp_platform_prd, |
| .probe = firenze_probe, |
| .init = firenze_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_add_loc_code = firenze_pci_add_loc_code, |
| .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, |
| .op_display = fsp_op_display, |
| .vpd_iohub_load = vpd_iohub_load, |
| .heartbeat_time = fsp_heartbeat_time, |
| }; |