diff options
Diffstat (limited to 'src/soc/intel/skylake/romstage')
-rw-r--r-- | src/soc/intel/skylake/romstage/Makefile.inc | 2 | ||||
-rw-r--r-- | src/soc/intel/skylake/romstage/i2c.c | 97 | ||||
-rw-r--r-- | src/soc/intel/skylake/romstage/romstage.c | 1 |
3 files changed, 100 insertions, 0 deletions
diff --git a/src/soc/intel/skylake/romstage/Makefile.inc b/src/soc/intel/skylake/romstage/Makefile.inc index 194091f811..6ae81378a4 100644 --- a/src/soc/intel/skylake/romstage/Makefile.inc +++ b/src/soc/intel/skylake/romstage/Makefile.inc @@ -1,4 +1,5 @@ verstage-y += cpu.c +verstage-y += i2c.c verstage-y += pch.c verstage-y += power_state.c verstage-y += report_platform.c @@ -9,6 +10,7 @@ verstage-y += systemagent.c verstage-y += uart.c romstage-y += cpu.c +romstage-y += i2c.c romstage-y += pch.c romstage-y += power_state.c romstage-y += report_platform.c diff --git a/src/soc/intel/skylake/romstage/i2c.c b/src/soc/intel/skylake/romstage/i2c.c new file mode 100644 index 0000000000..64e692420e --- /dev/null +++ b/src/soc/intel/skylake/romstage/i2c.c @@ -0,0 +1,97 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2016 Google Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <arch/io.h> +#include <commonlib/helpers.h> +#include <device/device.h> +#include <device/i2c.h> +#include <device/pci_def.h> +#include <soc/intel/common/lpss_i2c.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <soc/romstage.h> +#include <soc/serialio.h> +#include "chip.h" + +uintptr_t lpss_i2c_base_address(unsigned bus) +{ + unsigned devfn; + pci_devfn_t dev; + + /* Find device+function for this controller */ + devfn = i2c_bus_to_devfn(bus); + if (devfn < 0) + return 0; + + /* Form a PCI address for this device */ + dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + /* Read the first base address for this device */ + return ALIGN_DOWN(pci_read_config32(dev, PCI_BASE_ADDRESS_0), 16); +} + +static void i2c_early_init_bus(unsigned bus) +{ + ROMSTAGE_CONST struct soc_intel_skylake_config *config; + ROMSTAGE_CONST struct device *tree_dev; + pci_devfn_t dev; + unsigned devfn; + uintptr_t base; + uint32_t value; + void *reg; + + /* Find the PCI device for this bus controller */ + devfn = i2c_bus_to_devfn(bus); + if (devfn < 0) + return; + + /* Look up the controller device in the devicetree */ + dev = PCI_DEV(0, PCI_SLOT(devfn), PCI_FUNC(devfn)); + tree_dev = dev_find_slot(0, devfn); + if (!tree_dev || !tree_dev->enabled) + return; + + /* Skip if not enabled for early init */ + config = tree_dev->chip_info; + if (!config) + return; + if (!config->i2c[bus].early_init) + return; + + /* Prepare early base address for access before memory */ + base = EARLY_I2C_BASE(bus); + pci_write_config32(dev, PCI_BASE_ADDRESS_0, base); + pci_write_config32(dev, PCI_COMMAND, + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + + /* Take device out of reset */ + reg = (void *)(base + SIO_REG_PPR_RESETS); + value = read32(reg); + value |= SIO_REG_PPR_RESETS_FUNC | SIO_REG_PPR_RESETS_APB | + SIO_REG_PPR_RESETS_IDMA; + write32(reg, value); + + /* Initialize the controller */ + lpss_i2c_init(bus, config->i2c[bus].speed ? : I2C_SPEED_FAST); +} + +void i2c_early_init(void) +{ + int bus; + + /* Initialize I2C controllers that are enabled in devicetree */ + for (bus = 0; bus < SKYLAKE_I2C_DEV_MAX; bus++) + i2c_early_init_bus(bus); +} diff --git a/src/soc/intel/skylake/romstage/romstage.c b/src/soc/intel/skylake/romstage/romstage.c index 9c61095214..8375ccde76 100644 --- a/src/soc/intel/skylake/romstage/romstage.c +++ b/src/soc/intel/skylake/romstage/romstage.c @@ -64,6 +64,7 @@ void car_soc_post_console_init(void) report_platform_info(); set_max_freq(); pch_early_init(); + i2c_early_init(); } int get_sw_write_protect_state(void) |