aboutsummaryrefslogtreecommitdiff
path: root/platforms
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2015-07-01 13:58:48 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2015-07-01 13:58:48 +1000
commit6be837c7ef0da5407d523c746e8a35da31e53f08 (patch)
tree255cdfc6a437a3299e7b369fd6132650e913dddf /platforms
parent6c458a0369494a7f0ae2e6352850502c5e393f8f (diff)
parent200df96fb4ce9e2845cdb5f18f01d4c1ff82baeb (diff)
downloadskiboot-6be837c7ef0da5407d523c746e8a35da31e53f08.zip
skiboot-6be837c7ef0da5407d523c746e8a35da31e53f08.tar.gz
skiboot-6be837c7ef0da5407d523c746e8a35da31e53f08.tar.bz2
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.c149
1 files changed, 144 insertions, 5 deletions
diff --git a/platforms/ibm-fsp/firenze.c b/platforms/ibm-fsp/firenze.c
index 9fbc104..507841d 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;