236 lines
6.3 KiB
C
236 lines
6.3 KiB
C
/* Copyright 2013-2014 IBM Corp.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
* implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
|
|
#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_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,
|
|
};
|