diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2015-07-01 13:58:48 +1000 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2015-07-01 13:58:48 +1000 |
commit | 6be837c7ef0da5407d523c746e8a35da31e53f08 (patch) | |
tree | 255cdfc6a437a3299e7b369fd6132650e913dddf /platforms | |
parent | 6c458a0369494a7f0ae2e6352850502c5e393f8f (diff) | |
parent | 200df96fb4ce9e2845cdb5f18f01d4c1ff82baeb (diff) | |
download | talos-skiboot-6be837c7ef0da5407d523c746e8a35da31e53f08.tar.gz talos-skiboot-6be837c7ef0da5407d523c746e8a35da31e53f08.zip |
Merge branch 'update-2.1.1.1' into mergeback
Complex merge fixups
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'platforms')
-rw-r--r-- | platforms/ibm-fsp/firenze.c | 149 |
1 files changed, 144 insertions, 5 deletions
diff --git a/platforms/ibm-fsp/firenze.c b/platforms/ibm-fsp/firenze.c index 9fbc1049..507841d9 100644 --- a/platforms/ibm-fsp/firenze.c +++ b/platforms/ibm-fsp/firenze.c @@ -21,6 +21,8 @@ #include <pci.h> #include <pci-cfg.h> #include <chip.h> +#include <i2c.h> +#include <timebase.h> #include <hostservices.h> #include "ibm-fsp.h" @@ -48,6 +50,7 @@ struct fsp_pcie_inventory { static struct fsp_pcie_inventory *fsp_pcie_inv; static unsigned int fsp_pcie_inv_alloc_count; #define FSP_PCIE_INV_ALLOC_CHUNK 4 +static uint64_t lx_vpd_id; struct lock fsp_pcie_inv_lock = LOCK_UNLOCKED; @@ -110,6 +113,44 @@ static struct dt_node *dt_create_i2c_device(struct dt_node *bus, uint8_t addr, return dev; } +static struct i2c_bus *firenze_pci_find_i2c_bus(uint8_t chip, uint8_t eng, uint8_t port) +{ + struct dt_node *np, *child; + uint32_t reg; + + /* Iterate I2C masters */ + dt_for_each_compatible(dt_root, np, "ibm,power8-i2cm") { + if (!np->parent || + !dt_node_is_compatible(np->parent, "ibm,power8-xscom")) + continue; + + /* Check chip index */ + reg = dt_prop_get_u32(np->parent, "ibm,chip-id"); + if (reg != chip) + continue; + + /* Check I2C master index */ + reg = dt_prop_get_u32(np, "chip-engine#"); + if (reg != eng) + continue; + + /* Iterate I2C buses */ + dt_for_each_child(np, child) { + if (!dt_node_is_compatible(child, "ibm,power8-i2c-port")) + continue; + + /* Check I2C port index */ + reg = dt_prop_get_u32(child, "reg"); + if (reg != port) + continue; + + reg = dt_prop_get_u32(child, "ibm,opal-id"); + return i2c_find_bus_by_id(reg); + } + } + return NULL; +} + static void firenze_dt_fixup_i2cm(void) { struct dt_node *master, *bus, *dev; @@ -272,6 +313,102 @@ static void firenze_send_pci_inventory(void) fsp_pcie_inv = NULL; } +static void firenze_i2c_complete(int rc, struct i2c_request *req) +{ + *(int *)req->user_data = rc; +} + +static void firenze_do_i2c_byte(uint8_t chip, uint8_t eng, uint8_t port, + uint8_t addr, uint8_t reg, uint8_t data) +{ + struct i2c_bus *bus; + struct i2c_request *req; + uint8_t verif; + int rc; + + bus = firenze_pci_find_i2c_bus(chip, eng, port); + if (!bus) { + prerror("FIRENZE: Failed to find i2c (%d/%d/%d)\n", chip, eng, port); + return; + } + req = i2c_alloc_req(bus); + if (!req) { + prerror("FIRENZE: Failed to allocate i2c request\n"); + return; + } + req->op = SMBUS_WRITE; + req->dev_addr = addr >> 1; + req->offset_bytes = 1; + req->offset = reg; + req->rw_buf = &data; + req->rw_len = 1; + req->completion = firenze_i2c_complete; + req->user_data = &rc; + rc = 1; + i2c_queue_req(req); + while(rc == 1) { + time_wait_us(10); + } + if (rc != 0) { + prerror("FIRENZE: I2C error %d writing byte\n", rc); + return; + } + req->op = SMBUS_READ; + req->dev_addr = addr >> 1; + req->offset_bytes = 1; + req->offset = reg; + req->rw_buf = &verif; + req->rw_len = 1; + req->completion = firenze_i2c_complete; + req->user_data = &rc; + rc = 1; + i2c_queue_req(req); + while(rc == 1) { + time_wait_us(10); + } + if (rc != 0) { + prerror("FIRENZE: I2C error %d reading byte\n", rc); + return; + } + if (verif != data) { + prerror("FIRENZE: I2C miscompare want %02x got %02x\n", data, verif); + } +} + +static void firenze_fixup_pcie_slot_power(struct pci_device * pd) +{ + const char *label = pd->slot_info->label; + + if (!pd->slot_info->pluggable) + return; + + if (lx_vpd_id != LX_VPD_2S4U_BACKPLANE && + lx_vpd_id != LX_VPD_1S4U_BACKPLANE) + return; + + printf("FIRENZE: Checking slot %s for power fixup\n", label); + + /* Note: We apply the settings twice for C6/C7 but that shouldn't + * be a problem + */ + if (!strncmp(label, "C6 ", 3) || !strncmp(label, "C7 ", 3)) { + printf("FIRENZE: Fixing power on %s...\n", label); + firenze_do_i2c_byte(0, 1, 0, 0x6a, 0x5e, 0xfa); + firenze_do_i2c_byte(0, 1, 0, 0x6a, 0x5a, 0xff); + firenze_do_i2c_byte(0, 1, 0, 0x6a, 0x5b, 0xff); + } + if (!strncmp(label, "C5 ", 3)) { + printf("FIRENZE: Fixing power on %s...\n", label); + firenze_do_i2c_byte(0, 1, 0, 0x72, 0x5e, 0xfb); + firenze_do_i2c_byte(0, 1, 0, 0x72, 0x5b, 0xff); + } + if (!strncmp(label, "C3 ", 3)) { + printf("FIRENZE: Fixing power on %s...\n", label); + firenze_do_i2c_byte(0, 1, 0, 0x74, 0x5e, 0xfb); + firenze_do_i2c_byte(0, 1, 0, 0x74, 0x5b, 0xff); + } +} + static void firenze_add_pcidev_to_fsp_inventory(struct phb *phb, struct pci_device *pd) { @@ -353,17 +490,19 @@ static void firenze_get_slot_info(struct phb *phb, struct pci_device * pd) * - Slot entry says pluggable * - Aren't an upstream switch that has slot info */ - if (!pd || !pd->parent) - return; - if (pd->bdfn & 7) + if (!pd) return; if (pd->dev_type == PCIE_TYPE_ROOT_PORT || - pd->dev_type == PCIE_TYPE_SWITCH_DNPORT) + pd->dev_type == PCIE_TYPE_SWITCH_DNPORT) { + firenze_fixup_pcie_slot_power(pd); + return; + } + if (pd->bdfn & 7) return; if (pd->dev_type == PCIE_TYPE_SWITCH_UPPORT && pd->slot_info) return; - if (!pd->parent->slot_info) + if (!pd->parent || !pd->parent->slot_info) return; if (!pd->parent->slot_info->pluggable) return; |