diff options
author | Rizwan Qureshi <rizwan.qureshi@intel.com> | 2017-04-26 21:06:35 +0530 |
---|---|---|
committer | Martin Roth <martinroth@google.com> | 2017-05-18 06:07:15 +0200 |
commit | ae6a4b6d3ca60fc697103cbdaaf5df84502f554e (patch) | |
tree | 60053ac5506eb928c49bdd958f2648972a6c52ac /src/soc/intel | |
parent | 36b09b8a6c3367dded5c3f0c6a1dc1d16d9a1335 (diff) | |
download | coreboot-ae6a4b6d3ca60fc697103cbdaaf5df84502f554e.tar.xz |
intel/common/block/i2c: Add common block for I2C and use the same in SoCs
In the intel/common/block
* Move I2C common code from intel/common to intel/common/block.
* Split the code into common, early init and post mem init stages and put it
in lpss_i2c.c, i2c_early.c and i2c.c respectively.
* Declare functions for getting platform specific i2c bus config and
mapping bus to devfn and vice versa, that have to be implemented by SoC.
In skylake/apollolake
* Stop using code from soc/intel/common/lpss_i2c.c.
* Remove early i2c initialization code from bootblock.
* Refactor i2c.c file to implement SoC specific methods
required by the I2C IP block.
Change-Id: I4d91a04c22e181e3a995112cce6d5f0324130b81
Signed-off-by: Rizwan Qureshi <rizwan.qureshi@intel.com>
Reviewed-on: https://review.coreboot.org/19468
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'src/soc/intel')
20 files changed, 468 insertions, 541 deletions
diff --git a/src/soc/intel/apollolake/Kconfig b/src/soc/intel/apollolake/Kconfig index 5e800a315f..56f0d203b2 100644 --- a/src/soc/intel/apollolake/Kconfig +++ b/src/soc/intel/apollolake/Kconfig @@ -56,6 +56,7 @@ config CPU_SPECIFIC_OPTIONS select SOC_INTEL_COMMON_BLOCK select SOC_INTEL_COMMON_BLOCK_FAST_SPI select SOC_INTEL_COMMON_BLOCK_ITSS + select SOC_INTEL_COMMON_BLOCK_I2C select SOC_INTEL_COMMON_BLOCK_LPSS select SOC_INTEL_COMMON_BLOCK_PCR select SOC_INTEL_COMMON_BLOCK_SA @@ -64,7 +65,6 @@ config CPU_SPECIFIC_OPTIONS select SOC_INTEL_COMMON_BLOCK_UART select SOC_INTEL_COMMON_BLOCK_XDCI select SOC_INTEL_COMMON_BLOCK_XHCI - select SOC_INTEL_COMMON_LPSS_I2C select SOC_INTEL_COMMON_SMI select SOC_INTEL_COMMON_SPI_FLASH_PROTECT select UDELAY_TSC diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc index 50d323fb4a..9b1f44022d 100644 --- a/src/soc/intel/apollolake/Makefile.inc +++ b/src/soc/intel/apollolake/Makefile.inc @@ -13,6 +13,7 @@ bootblock-y += bootblock/bootblock.c bootblock-y += car.c bootblock-y += gpio.c bootblock-y += heci.c +bootblock-y += i2c.c bootblock-y += lpc_lib.c bootblock-y += mmap_boot.c bootblock-y += pmutil.c @@ -25,7 +26,7 @@ romstage-y += car.c romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += romstage.c romstage-y += gpio.c romstage-y += heci.c -romstage-y += i2c_early.c +romstage-y += i2c.c romstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c romstage-y += lpc_lib.c romstage-y += memmap.c @@ -83,7 +84,7 @@ postcar-y += tsc_freq.c postcar-$(CONFIG_FSP_CAR) += exit_car_fsp.S verstage-y += car.c -verstage-y += i2c_early.c +verstage-y += i2c.c verstage-y += heci.c verstage-y += memmap.c verstage-y += mmap_boot.c diff --git a/src/soc/intel/apollolake/chip.h b/src/soc/intel/apollolake/chip.h index 3221be7ac8..bf25009f86 100644 --- a/src/soc/intel/apollolake/chip.h +++ b/src/soc/intel/apollolake/chip.h @@ -21,7 +21,7 @@ #include <soc/gpe.h> #include <soc/gpio_defs.h> #include <soc/gpio.h> -#include <soc/intel/common/lpss_i2c.h> +#include <intelblocks/lpss_i2c.h> #include <device/i2c.h> #include <soc/pm.h> #include <soc/usb.h> diff --git a/src/soc/intel/apollolake/i2c.c b/src/soc/intel/apollolake/i2c.c index 9aadc78b8c..2b6cbf95b2 100644 --- a/src/soc/intel/apollolake/i2c.c +++ b/src/soc/intel/apollolake/i2c.c @@ -13,102 +13,52 @@ * GNU General Public License for more details. */ -#include <arch/acpi_device.h> -#include <arch/acpigen.h> +#include <console/console.h> #include <device/device.h> -#include <device/i2c.h> -#include <device/pci.h> #include <device/pci_def.h> -#include <device/pci_ids.h> -#include <soc/i2c.h> -#include <soc/intel/common/lpss_i2c.h> +#include <intelblocks/lpss_i2c.h> +#include <soc/iomap.h> #include <soc/pci_devs.h> -#include <soc/pci_ids.h> #include "chip.h" -uintptr_t lpss_i2c_base_address(unsigned int bus) +const struct lpss_i2c_bus_config *i2c_get_soc_cfg(unsigned int bus, + const struct device *dev) { - unsigned int devfn; - struct device *dev; - struct resource *res; - - /* bus -> devfn */ - devfn = i2c_bus_to_devfn(bus); - if (devfn >= 0) { - /* devfn -> dev */ - dev = dev_find_slot(0, devfn); - if (dev) { - /* dev -> bar0 */ - res = find_resource(dev, PCI_BASE_ADDRESS_0); - if (res) - return res->base; - } + const struct soc_intel_apollolake_config *config; + if (!dev || !dev->chip_info) { + printk(BIOS_ERR, "%s: Could not find SoC devicetree config!\n", + __func__); + return NULL; } - return (uintptr_t)NULL; + config = dev->chip_info; + + return &config->i2c[bus]; } -static int i2c_dev_to_bus(struct device *dev) +uintptr_t i2c_get_soc_early_base(unsigned int bus) { - return i2c_devfn_to_bus(dev->path.pci.devfn); + return PRERAM_I2C_BASE_ADDRESS(bus); } -/* - * The device should already be enabled and out of reset, - * either from early init in coreboot or FSP-S. - */ -static void i2c_dev_init(struct device *dev) +/* Convert I2C bus number to PCI device and function */ +int i2c_soc_bus_to_devfn(unsigned int bus) { - struct soc_intel_apollolake_config *config = dev->chip_info; - int bus = i2c_dev_to_bus(dev); - - if (!config || bus < 0) - return; - - lpss_i2c_init(bus, &config->i2c[bus]); + if (bus >= 0 && bus <= 3) + return PCI_DEVFN(PCH_DEV_SLOT_SIO1, bus); + else if (bus >= 4 && bus <= 7) + return PCI_DEVFN(PCH_DEV_SLOT_SIO2, (bus - 4)); + else + return -1; } -static void i2c_fill_ssdt(struct device *dev) +/* Convert PCI device and function to I2C bus number */ +int i2c_soc_devfn_to_bus(unsigned int devfn) { - struct soc_intel_apollolake_config *config = dev->chip_info; - int bus = i2c_dev_to_bus(dev); - - if (!config || bus < 0) - return; - - acpigen_write_scope(acpi_device_path(dev)); - lpss_i2c_acpi_fill_ssdt(bus, &config->i2c[bus]); - acpigen_pop_len(); + if (PCI_SLOT(devfn) == PCH_DEV_SLOT_SIO1) + return PCI_FUNC(devfn); + else if (PCI_SLOT(devfn) == PCH_DEV_SLOT_SIO2) + return PCI_FUNC(devfn) + 4; + else + return -1; } - -static struct i2c_bus_operations i2c_bus_ops = { - .dev_to_bus = &i2c_dev_to_bus, -}; - -static struct device_operations i2c_dev_ops = { - .read_resources = &pci_dev_read_resources, - .set_resources = &pci_dev_set_resources, - .enable_resources = &pci_dev_enable_resources, - .scan_bus = &scan_smbus, - .ops_i2c_bus = &i2c_bus_ops, - .init = &i2c_dev_init, - .acpi_fill_ssdt_generator = &i2c_fill_ssdt, -}; - -static const unsigned short pci_device_ids[] = { - PCI_DEVICE_ID_APOLLOLAKE_I2C0, - PCI_DEVICE_ID_APOLLOLAKE_I2C1, - PCI_DEVICE_ID_APOLLOLAKE_I2C2, - PCI_DEVICE_ID_APOLLOLAKE_I2C3, - PCI_DEVICE_ID_APOLLOLAKE_I2C4, - PCI_DEVICE_ID_APOLLOLAKE_I2C5, - PCI_DEVICE_ID_APOLLOLAKE_I2C6, - PCI_DEVICE_ID_APOLLOLAKE_I2C7, - 0, -}; - -static const struct pci_driver pch_i2c __pci_driver = { - .ops = &i2c_dev_ops, - .vendor = PCI_VENDOR_ID_INTEL, - .devices = pci_device_ids, -}; diff --git a/src/soc/intel/apollolake/include/soc/i2c.h b/src/soc/intel/apollolake/include/soc/i2c.h deleted file mode 100644 index 8839f1460a..0000000000 --- a/src/soc/intel/apollolake/include/soc/i2c.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ - -#ifndef _SOC_APOLLOLAKE_I2C_H_ -#define _SOC_APOLLOLAKE_I2C_H_ - -#include <device/pci_def.h> -#include <soc/pci_devs.h> - -/* Convert I2C bus number to PCI device and function */ -static inline int i2c_bus_to_devfn(unsigned int bus) -{ - if (bus >= 0 && bus <= 3) - return PCI_DEVFN(PCH_DEV_SLOT_SIO1, bus); - else if (bus >= 4 && bus <= 7) - return PCI_DEVFN(PCH_DEV_SLOT_SIO2, (bus - 4)); - else - return -1; -} - -/* Convert PCI device and function to I2C bus number */ -static inline int i2c_devfn_to_bus(unsigned int devfn) -{ - if (PCI_SLOT(devfn) == PCH_DEV_SLOT_SIO1) - return PCI_FUNC(devfn); - else if (PCI_SLOT(devfn) == PCH_DEV_SLOT_SIO2) - return PCI_FUNC(devfn) + 4; - else - return -1; -} - -#endif /* _SOC_APOLLOLAKE_I2C_H_ */ diff --git a/src/soc/intel/common/Makefile.inc b/src/soc/intel/common/Makefile.inc index b01fc8a70e..340e001d2d 100644 --- a/src/soc/intel/common/Makefile.inc +++ b/src/soc/intel/common/Makefile.inc @@ -5,14 +5,11 @@ subdirs-y += block/ bootblock-y += util.c -verstage-$(CONFIG_SOC_INTEL_COMMON_LPSS_I2C) += lpss_i2c.c verstage-$(CONFIG_SOC_INTEL_COMMON_RESET) += reset.c bootblock-$(CONFIG_SOC_INTEL_COMMON_RESET) += reset.c -bootblock-$(CONFIG_SOC_INTEL_COMMON_LPSS_I2C) += lpss_i2c.c romstage-$(CONFIG_CACHE_MRC_SETTINGS) += mrc_cache.c -romstage-$(CONFIG_SOC_INTEL_COMMON_LPSS_I2C) += lpss_i2c.c romstage-$(CONFIG_SOC_INTEL_COMMON_RESET) += reset.c romstage-y += util.c romstage-$(CONFIG_MMA) += mma.c @@ -25,7 +22,6 @@ ramstage-y += hda_verb.c ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += mrc_cache.c ramstage-$(CONFIG_CACHE_MRC_SETTINGS) += nvm.c ramstage-$(CONFIG_SOC_INTEL_COMMON_SPI_FLASH_PROTECT) += spi_flash.c -ramstage-$(CONFIG_SOC_INTEL_COMMON_LPSS_I2C) += lpss_i2c.c ramstage-$(CONFIG_SOC_INTEL_COMMON_RESET) += reset.c ramstage-y += util.c ramstage-$(CONFIG_MMA) += mma.c diff --git a/src/soc/intel/common/block/i2c/Kconfig b/src/soc/intel/common/block/i2c/Kconfig new file mode 100644 index 0000000000..7718f05c58 --- /dev/null +++ b/src/soc/intel/common/block/i2c/Kconfig @@ -0,0 +1,4 @@ +config SOC_INTEL_COMMON_BLOCK_I2C + bool + help + Intel Processor Common I2C support diff --git a/src/soc/intel/common/block/i2c/Makefile.inc b/src/soc/intel/common/block/i2c/Makefile.inc new file mode 100644 index 0000000000..24755c47d3 --- /dev/null +++ b/src/soc/intel/common/block/i2c/Makefile.inc @@ -0,0 +1,11 @@ +bootblock-$(CONFIG_SOC_INTEL_COMMON_BLOCK_I2C) += lpss_i2c.c +bootblock-$(CONFIG_SOC_INTEL_COMMON_BLOCK_I2C) += i2c_early.c + +romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_I2C) += lpss_i2c.c +romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_I2C) += i2c_early.c + +verstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_I2C) += lpss_i2c.c +verstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_I2C) += i2c_early.c + +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_I2C) += lpss_i2c.c +ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_I2C) += i2c.c diff --git a/src/soc/intel/common/block/i2c/i2c.c b/src/soc/intel/common/block/i2c/i2c.c new file mode 100644 index 0000000000..9d608d8a76 --- /dev/null +++ b/src/soc/intel/common/block/i2c/i2c.c @@ -0,0 +1,183 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017 Intel Corporation. + * + * 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/acpigen.h> +#include <device/i2c.h> +#include <device/pci.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <intelblocks/lpss_i2c.h> +#include "lpss_i2c.h" + +static int lpss_i2c_dev_to_bus(struct device *dev) +{ + pci_devfn_t devfn = dev->path.pci.devfn; + return i2c_soc_devfn_to_bus(devfn); +} + +uintptr_t lpss_i2c_base_address(unsigned int bus) +{ + int devfn; + struct device *dev; + struct resource *res; + + /* bus -> devfn */ + devfn = i2c_soc_bus_to_devfn(bus); + + if (devfn < 0) + return (uintptr_t)NULL; + + /* devfn -> dev */ + dev = dev_find_slot(0, devfn); + if (!dev) + return (uintptr_t)NULL; + + /* dev -> bar0 */ + res = find_resource(dev, PCI_BASE_ADDRESS_0); + if (res) + return res->base; + + return (uintptr_t)NULL; +} + +/* + * Write ACPI object to describe speed configuration. + * + * ACPI Object: Name ("xxxx", Package () { scl_lcnt, scl_hcnt, sda_hold } + * + * SSCN: I2C_SPEED_STANDARD + * FMCN: I2C_SPEED_FAST + * FPCN: I2C_SPEED_FAST_PLUS + * HSCN: I2C_SPEED_HIGH + */ +static void lpss_i2c_acpi_write_speed_config( + const struct lpss_i2c_speed_config *config) +{ + if (!config) + return; + if (!config->scl_lcnt && !config->scl_hcnt && !config->sda_hold) + return; + + if (config->speed >= I2C_SPEED_HIGH) + acpigen_write_name("HSCN"); + else if (config->speed >= I2C_SPEED_FAST_PLUS) + acpigen_write_name("FPCN"); + else if (config->speed >= I2C_SPEED_FAST) + acpigen_write_name("FMCN"); + else + acpigen_write_name("SSCN"); + + /* Package () { scl_lcnt, scl_hcnt, sda_hold } */ + acpigen_write_package(3); + acpigen_write_word(config->scl_hcnt); + acpigen_write_word(config->scl_lcnt); + acpigen_write_dword(config->sda_hold); + acpigen_pop_len(); +} + +/* + * The device should already be enabled and out of reset, + * either from early init in coreboot or SiliconInit in FSP. + */ +static void lpss_i2c_dev_init(struct device *dev) +{ + const struct lpss_i2c_bus_config *config; + int bus = lpss_i2c_dev_to_bus(dev); + + config = i2c_get_soc_cfg(bus, dev); + + if (!config || bus < 0) + return; + + lpss_i2c_init(bus, config); +} + +/* + * Generate I2C timing information into the SSDT for the OS driver to consume, + * optionally applying override values provided by the caller. + */ +static void lpss_i2c_acpi_fill_ssdt(struct device *dev) +{ + const struct lpss_i2c_bus_config *bcfg; + struct lpss_i2c_regs *regs; + struct lpss_i2c_speed_config sgen; + enum i2c_speed speeds[LPSS_I2C_SPEED_CONFIG_COUNT] = { + I2C_SPEED_STANDARD, + I2C_SPEED_FAST, + I2C_SPEED_FAST_PLUS, + I2C_SPEED_HIGH, + }; + int i, bus = lpss_i2c_dev_to_bus(dev); + + bcfg = i2c_get_soc_cfg(bus, dev); + + if (!bcfg) + return; + + regs = (struct lpss_i2c_regs *)lpss_i2c_base_address(bus); + if (!regs) + return; + + acpigen_write_scope(acpi_device_path(dev)); + + /* Report timing values for the OS driver */ + for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) { + /* Generate speed config. */ + if (lpss_i2c_gen_speed_config(regs, speeds[i], bcfg, &sgen) < 0) + continue; + + /* Generate ACPI based on selected speed config */ + lpss_i2c_acpi_write_speed_config(&sgen); + } + + acpigen_pop_len(); +} + +static struct i2c_bus_operations i2c_bus_ops = { + .dev_to_bus = &lpss_i2c_dev_to_bus, +}; + +static struct device_operations i2c_dev_ops = { + .read_resources = &pci_dev_read_resources, + .set_resources = &pci_dev_set_resources, + .enable_resources = &pci_dev_enable_resources, + .scan_bus = &scan_smbus, + .ops_i2c_bus = &i2c_bus_ops, + .init = &lpss_i2c_dev_init, + .acpi_fill_ssdt_generator = &lpss_i2c_acpi_fill_ssdt, +}; + +static const unsigned short pci_device_ids[] = { + PCI_DEVICE_ID_INTEL_SPT_I2C0, + PCI_DEVICE_ID_INTEL_SPT_I2C1, + PCI_DEVICE_ID_INTEL_SPT_I2C2, + PCI_DEVICE_ID_INTEL_SPT_I2C3, + PCI_DEVICE_ID_INTEL_SPT_I2C4, + PCI_DEVICE_ID_INTEL_SPT_I2C5, + PCI_DEVICE_ID_INTEL_APL_I2C0, + PCI_DEVICE_ID_INTEL_APL_I2C1, + PCI_DEVICE_ID_INTEL_APL_I2C2, + PCI_DEVICE_ID_INTEL_APL_I2C3, + PCI_DEVICE_ID_INTEL_APL_I2C4, + PCI_DEVICE_ID_INTEL_APL_I2C5, + PCI_DEVICE_ID_INTEL_APL_I2C6, + PCI_DEVICE_ID_INTEL_APL_I2C7, +}; + +static const struct pci_driver pch_i2c __pci_driver = { + .ops = &i2c_dev_ops, + .vendor = PCI_VENDOR_ID_INTEL, + .devices = pci_device_ids, +}; diff --git a/src/soc/intel/apollolake/i2c_early.c b/src/soc/intel/common/block/i2c/i2c_early.c index 871c7621a9..7c9ce60513 100644 --- a/src/soc/intel/apollolake/i2c_early.c +++ b/src/soc/intel/common/block/i2c/i2c_early.c @@ -2,6 +2,7 @@ * This file is part of the coreboot project. * * Copyright 2016 Google Inc. + * Copyright 2017 Intel Corporation. * * 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 @@ -14,28 +15,25 @@ */ #include <arch/io.h> -#include <commonlib/helpers.h> #include <console/console.h> #include <device/device.h> #include <device/i2c.h> +#include <device/pci.h> #include <device/pci_def.h> #include <intelblocks/lpss.h> -#include <soc/intel/common/lpss_i2c.h> -#include <soc/i2c.h> -#include <soc/iomap.h> -#include <soc/pci_devs.h> -#include "chip.h" +#include <intelblocks/lpss_i2c.h> +#include "lpss_i2c.h" -static int i2c_early_init_bus(unsigned int bus) +static int lpss_i2c_early_init_bus(unsigned int bus) { - DEVTREE_CONST struct soc_intel_apollolake_config *config; - DEVTREE_CONST struct device *tree_dev; + const struct lpss_i2c_bus_config *config; + const struct device *tree_dev; pci_devfn_t dev; int devfn; uintptr_t base; /* Find the PCI device for this bus controller */ - devfn = i2c_bus_to_devfn(bus); + devfn = i2c_soc_bus_to_devfn(bus); if (devfn < 0) { printk(BIOS_ERR, "I2C%u device not found\n", bus); return -1; @@ -50,14 +48,14 @@ static int i2c_early_init_bus(unsigned int bus) } /* Skip if not enabled for early init */ - config = tree_dev->chip_info; - if (!config || !config->i2c[bus].early_init) { - printk(BIOS_ERR, "I2C%u not enabled for early init\n", bus); + config = i2c_get_soc_cfg(bus, tree_dev); + if (!config || !config->early_init) { + printk(BIOS_DEBUG, "I2C%u not enabled for early init\n", bus); return -1; } /* Prepare early base address for access before memory */ - base = PRERAM_I2C_BASE_ADDRESS(bus); + base = i2c_get_soc_early_base(bus); pci_write_config32(dev, PCI_BASE_ADDRESS_0, base); pci_write_config32(dev, PCI_COMMAND, PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); @@ -66,7 +64,7 @@ static int i2c_early_init_bus(unsigned int bus) lpss_reset_release(base); /* Initialize the controller */ - if (lpss_i2c_init(bus, &config->i2c[bus]) < 0) { + if (lpss_i2c_init(bus, config) < 0) { printk(BIOS_ERR, "I2C%u failed to initialize\n", bus); return -1; } @@ -76,12 +74,12 @@ static int i2c_early_init_bus(unsigned int bus) uintptr_t lpss_i2c_base_address(unsigned int bus) { - unsigned int devfn; + int devfn; pci_devfn_t dev; uintptr_t base; /* Find device+function for this controller */ - devfn = i2c_bus_to_devfn(bus); + devfn = i2c_soc_bus_to_devfn(bus); if (devfn < 0) return (uintptr_t)NULL; @@ -92,9 +90,8 @@ uintptr_t lpss_i2c_base_address(unsigned int bus) base = ALIGN_DOWN(pci_read_config32(dev, PCI_BASE_ADDRESS_0), 16); /* Attempt to initialize bus if base is not set yet */ - if (!base && !i2c_early_init_bus(bus)) + if (!base && !lpss_i2c_early_init_bus(bus)) base = ALIGN_DOWN(pci_read_config32(dev, PCI_BASE_ADDRESS_0), 16); - return base; } diff --git a/src/soc/intel/common/lpss_i2c.c b/src/soc/intel/common/block/i2c/lpss_i2c.c index b61c24afd7..27c7b7f040 100644 --- a/src/soc/intel/common/lpss_i2c.c +++ b/src/soc/intel/common/block/i2c/lpss_i2c.c @@ -16,65 +16,17 @@ #include <arch/acpigen.h> #include <arch/io.h> -#include <commonlib/helpers.h> #include <console/console.h> #include <device/device.h> #include <device/i2c.h> +#include <device/pci.h> +#include <device/pci_def.h> +#include <device/pci_ids.h> +#include <intelblocks/lpss_i2c.h> #include <string.h> #include <timer.h> #include "lpss_i2c.h" -#define LPSS_DEBUG BIOS_NEVER - -struct lpss_i2c_regs { - uint32_t control; - uint32_t target_addr; - uint32_t slave_addr; - uint32_t master_addr; - uint32_t cmd_data; - uint32_t ss_scl_hcnt; - uint32_t ss_scl_lcnt; - uint32_t fs_scl_hcnt; - uint32_t fs_scl_lcnt; - uint32_t hs_scl_hcnt; - uint32_t hs_scl_lcnt; - uint32_t intr_stat; - uint32_t intr_mask; - uint32_t raw_intr_stat; - uint32_t rx_thresh; - uint32_t tx_thresh; - uint32_t clear_intr; - uint32_t clear_rx_under_intr; - uint32_t clear_rx_over_intr; - uint32_t clear_tx_over_intr; - uint32_t clear_rd_req_intr; - uint32_t clear_tx_abrt_intr; - uint32_t clear_rx_done_intr; - uint32_t clear_activity_intr; - uint32_t clear_stop_det_intr; - uint32_t clear_start_det_intr; - uint32_t clear_gen_call_intr; - uint32_t enable; - uint32_t status; - uint32_t tx_level; - uint32_t rx_level; - uint32_t sda_hold; - uint32_t tx_abort_source; - uint32_t slv_data_nak_only; - uint32_t dma_cr; - uint32_t dma_tdlr; - uint32_t dma_rdlr; - uint32_t sda_setup; - uint32_t ack_general_call; - uint32_t enable_status; - uint32_t fs_spklen; - uint32_t hs_spklen; - uint32_t clr_restart_det; - uint32_t comp_param1; - uint32_t comp_version; - uint32_t comp_type; -} __attribute__((packed)); - /* Use a ~10ms timeout for various operations */ #define LPSS_I2C_TIMEOUT_US 10000 @@ -103,6 +55,57 @@ struct freq { uint32_t ns; }; +/* Control register definitions */ +enum { + CONTROL_MASTER_MODE = (1 << 0), + CONTROL_SPEED_SS = (1 << 1), + CONTROL_SPEED_FS = (1 << 2), + CONTROL_SPEED_HS = (3 << 1), + CONTROL_SPEED_MASK = (3 << 1), + CONTROL_10BIT_SLAVE = (1 << 3), + CONTROL_10BIT_MASTER = (1 << 4), + CONTROL_RESTART_ENABLE = (1 << 5), + CONTROL_SLAVE_DISABLE = (1 << 6), +}; + +/* Command/Data register definitions */ +enum { + CMD_DATA_CMD = (1 << 8), + CMD_DATA_STOP = (1 << 9), +}; + +/* Status register definitions */ +enum { + STATUS_ACTIVITY = (1 << 0), + STATUS_TX_FIFO_NOT_FULL = (1 << 1), + STATUS_TX_FIFO_EMPTY = (1 << 2), + STATUS_RX_FIFO_NOT_EMPTY = (1 << 3), + STATUS_RX_FIFO_FULL = (1 << 4), + STATUS_MASTER_ACTIVITY = (1 << 5), + STATUS_SLAVE_ACTIVITY = (1 << 6), +}; + +/* Enable register definitions */ +enum { + ENABLE_CONTROLLER = (1 << 0), +}; + +/* Interrupt status register definitions */ +enum { + INTR_STAT_RX_UNDER = (1 << 0), + INTR_STAT_RX_OVER = (1 << 1), + INTR_STAT_RX_FULL = (1 << 2), + INTR_STAT_TX_OVER = (1 << 3), + INTR_STAT_TX_EMPTY = (1 << 4), + INTR_STAT_RD_REQ = (1 << 5), + INTR_STAT_TX_ABORT = (1 << 6), + INTR_STAT_RX_DONE = (1 << 7), + INTR_STAT_ACTIVITY = (1 << 8), + INTR_STAT_STOP_DET = (1 << 9), + INTR_STAT_START_DET = (1 << 10), + INTR_STAT_GEN_CALL = (1 << 11), +}; + static const struct i2c_descriptor { enum i2c_speed speed; struct freq freq; @@ -168,57 +171,6 @@ static const struct soc_clock { }, }; -/* Control register definitions */ -enum { - CONTROL_MASTER_MODE = (1 << 0), - CONTROL_SPEED_SS = (1 << 1), - CONTROL_SPEED_FS = (1 << 2), - CONTROL_SPEED_HS = (3 << 1), - CONTROL_SPEED_MASK = (3 << 1), - CONTROL_10BIT_SLAVE = (1 << 3), - CONTROL_10BIT_MASTER = (1 << 4), - CONTROL_RESTART_ENABLE = (1 << 5), - CONTROL_SLAVE_DISABLE = (1 << 6), -}; - -/* Command/Data register definitions */ -enum { - CMD_DATA_CMD = (1 << 8), - CMD_DATA_STOP = (1 << 9), -}; - -/* Status register definitions */ -enum { - STATUS_ACTIVITY = (1 << 0), - STATUS_TX_FIFO_NOT_FULL = (1 << 1), - STATUS_TX_FIFO_EMPTY = (1 << 2), - STATUS_RX_FIFO_NOT_EMPTY = (1 << 3), - STATUS_RX_FIFO_FULL = (1 << 4), - STATUS_MASTER_ACTIVITY = (1 << 5), - STATUS_SLAVE_ACTIVITY = (1 << 6), -}; - -/* Enable register definitions */ -enum { - ENABLE_CONTROLLER = (1 << 0), -}; - -/* Interrupt status register definitions */ -enum { - INTR_STAT_RX_UNDER = (1 << 0), - INTR_STAT_RX_OVER = (1 << 1), - INTR_STAT_RX_FULL = (1 << 2), - INTR_STAT_TX_OVER = (1 << 3), - INTR_STAT_TX_EMPTY = (1 << 4), - INTR_STAT_RD_REQ = (1 << 5), - INTR_STAT_TX_ABORT = (1 << 6), - INTR_STAT_RX_DONE = (1 << 7), - INTR_STAT_ACTIVITY = (1 << 8), - INTR_STAT_STOP_DET = (1 << 9), - INTR_STAT_START_DET = (1 << 10), - INTR_STAT_GEN_CALL = (1 << 11), -}; - static const struct i2c_descriptor *get_bus_descriptor(enum i2c_speed speed) { size_t i; @@ -441,41 +393,6 @@ out: return ret; } -/* - * Write ACPI object to describe speed configuration. - * - * ACPI Object: Name ("xxxx", Package () { scl_lcnt, scl_hcnt, sda_hold } - * - * SSCN: I2C_SPEED_STANDARD - * FMCN: I2C_SPEED_FAST - * FPCN: I2C_SPEED_FAST_PLUS - * HSCN: I2C_SPEED_HIGH - */ -static void lpss_i2c_acpi_write_speed_config( - const struct lpss_i2c_speed_config *config) -{ - if (!config) - return; - if (!config->scl_lcnt && !config->scl_hcnt && !config->sda_hold) - return; - - if (config->speed >= I2C_SPEED_HIGH) - acpigen_write_name("HSCN"); - else if (config->speed >= I2C_SPEED_FAST_PLUS) - acpigen_write_name("FPCN"); - else if (config->speed >= I2C_SPEED_FAST) - acpigen_write_name("FMCN"); - else - acpigen_write_name("SSCN"); - - /* Package () { scl_lcnt, scl_hcnt, sda_hold } */ - acpigen_write_package(3); - acpigen_write_word(config->scl_hcnt); - acpigen_write_word(config->scl_lcnt); - acpigen_write_dword(config->sda_hold); - acpigen_pop_len(); -} - static int lpss_i2c_set_speed_config(unsigned int bus, const struct lpss_i2c_speed_config *config) { @@ -606,7 +523,7 @@ static int lpss_i2c_gen_config_rise_fall_time(struct lpss_i2c_regs *regs, return 0; } -static int lpss_i2c_gen_speed_config(struct lpss_i2c_regs *regs, +int lpss_i2c_gen_speed_config(struct lpss_i2c_regs *regs, enum i2c_speed speed, const struct lpss_i2c_bus_config *bcfg, struct lpss_i2c_speed_config *config) @@ -697,37 +614,13 @@ static int lpss_i2c_set_speed(unsigned int bus, enum i2c_speed speed, return 0; } -void lpss_i2c_acpi_fill_ssdt(unsigned int bus, - const struct lpss_i2c_bus_config *bcfg) -{ - struct lpss_i2c_regs *regs; - struct lpss_i2c_speed_config sgen; - enum i2c_speed speeds[LPSS_I2C_SPEED_CONFIG_COUNT] = { - I2C_SPEED_STANDARD, - I2C_SPEED_FAST, - I2C_SPEED_FAST_PLUS, - I2C_SPEED_HIGH, - }; - int i; - - if (!bcfg) - return; - - regs = (struct lpss_i2c_regs *)lpss_i2c_base_address(bus); - if (!regs) - return; - - /* Report timing values for the OS driver */ - for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) { - /* Generate speed config. */ - if (lpss_i2c_gen_speed_config(regs, speeds[i], bcfg, &sgen) < 0) - continue; - - /* Generate ACPI based on selected speed config */ - lpss_i2c_acpi_write_speed_config(&sgen); - } -} +/* + * Initialize this bus controller and set the speed. + * + * The bus speed can be passed in Hz or using values from device/i2c.h and + * will default to I2C_SPEED_FAST if it is not provided. + */ int lpss_i2c_init(unsigned int bus, const struct lpss_i2c_bus_config *bcfg) { struct lpss_i2c_regs *regs; diff --git a/src/soc/intel/common/block/i2c/lpss_i2c.h b/src/soc/intel/common/block/i2c/lpss_i2c.h new file mode 100644 index 0000000000..8a53660fbd --- /dev/null +++ b/src/soc/intel/common/block/i2c/lpss_i2c.h @@ -0,0 +1,90 @@ +/* + * This file is part of the coreboot project. + * + * Copyright 2017 Intel Corporation. + * + * 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 <intelblocks/lpss_i2c.h> + +#define LPSS_DEBUG BIOS_NEVER + +/* I2C Controller MMIO register space */ +struct lpss_i2c_regs { + uint32_t control; + uint32_t target_addr; + uint32_t slave_addr; + uint32_t master_addr; + uint32_t cmd_data; + uint32_t ss_scl_hcnt; + uint32_t ss_scl_lcnt; + uint32_t fs_scl_hcnt; + uint32_t fs_scl_lcnt; + uint32_t hs_scl_hcnt; + uint32_t hs_scl_lcnt; + uint32_t intr_stat; + uint32_t intr_mask; + uint32_t raw_intr_stat; + uint32_t rx_thresh; + uint32_t tx_thresh; + uint32_t clear_intr; + uint32_t clear_rx_under_intr; + uint32_t clear_rx_over_intr; + uint32_t clear_tx_over_intr; + uint32_t clear_rd_req_intr; + uint32_t clear_tx_abrt_intr; + uint32_t clear_rx_done_intr; + uint32_t clear_activity_intr; + uint32_t clear_stop_det_intr; + uint32_t clear_start_det_intr; + uint32_t clear_gen_call_intr; + uint32_t enable; + uint32_t status; + uint32_t tx_level; + uint32_t rx_level; + uint32_t sda_hold; + uint32_t tx_abort_source; + uint32_t slv_data_nak_only; + uint32_t dma_cr; + uint32_t dma_tdlr; + uint32_t dma_rdlr; + uint32_t sda_setup; + uint32_t ack_general_call; + uint32_t enable_status; + uint32_t fs_spklen; + uint32_t hs_spklen; + uint32_t clr_restart_det; + uint32_t comp_param1; + uint32_t comp_version; + uint32_t comp_type; +} __attribute__((packed)); + +/* Get I2C controller base address */ +uintptr_t lpss_i2c_base_address(unsigned int bus); + +/* + * Initialize this bus controller and set the speed + * Return value: + * -1 = failure + * 0 = success +*/ +int lpss_i2c_init(unsigned int bus, const struct lpss_i2c_bus_config *bcfg); + +/* + * Generate speed cofnig based on clock + * Return value: + * -1 = failure + * 0 = success +*/ +int lpss_i2c_gen_speed_config(struct lpss_i2c_regs *regs, + enum i2c_speed speed, + const struct lpss_i2c_bus_config *bcfg, + struct lpss_i2c_speed_config *config); diff --git a/src/soc/intel/common/lpss_i2c.h b/src/soc/intel/common/block/include/intelblocks/lpss_i2c.h index b46e657fd6..2f60d654b1 100644 --- a/src/soc/intel/common/lpss_i2c.h +++ b/src/soc/intel/common/block/include/intelblocks/lpss_i2c.h @@ -13,8 +13,8 @@ * GNU General Public License for more details. */ -#ifndef SOC_INTEL_COMMON_LPSS_I2C_H -#define SOC_INTEL_COMMON_LPSS_I2C_H +#ifndef SOC_INTEL_COMMON_BLOCK_LPSS_I2C_H +#define SOC_INTEL_COMMON_BLOCK_LPSS_I2C_H #include <device/i2c.h> #include <stdint.h> @@ -74,30 +74,32 @@ struct lpss_i2c_bus_config { .sda_hold = (hold), \ } +/* Functions to be implemented by SoC code */ + +/* Get base address for early init of I2C controllers. */ +uintptr_t i2c_get_soc_early_base(unsigned int bus); + /* - * Return the base address for this bus controller. - * - * This function *must* be implemented by the SOC and return the appropriate - * base address for the I2C registers that correspond to the provided bus. + * Map given I2C bus number to devfn. + * Return value: + * -1 = error + * otherwise, devfn(>=0) corresponding to I2C bus number. */ -uintptr_t lpss_i2c_base_address(unsigned int bus); +int i2c_soc_devfn_to_bus(unsigned int devfn); /* - * Generate I2C timing information into the SSDT for the OS driver to consume, - * optionally applying override values provided by the caller. + * Map given bus number to a I2C Controller. + * Return value: + * -1 = error + * otherwise, devfn(>=0) corresponding to I2C bus number. */ -void lpss_i2c_acpi_fill_ssdt(unsigned int bus, - const struct lpss_i2c_bus_config *bcfg); +int i2c_soc_bus_to_devfn(unsigned int bus); /* - * Initialize this bus controller and set the speed. + * SoC implemented callback for getting I2C bus configuration. * - * The bus speed can be passed in Hz or using values from device/i2c.h and - * will default to I2C_SPEED_FAST if it is not provided. - * - * The SOC *must* define CONFIG_SOC_INTEL_COMMON_LPSS_I2C_CLOCK for the - * bus speed calculation to be correct. + * Returns NULL if i2c config is not found */ -int lpss_i2c_init(unsigned int bus, const struct lpss_i2c_bus_config *bcfg); - -#endif +const struct lpss_i2c_bus_config *i2c_get_soc_cfg(unsigned int bus, + const struct device *dev); +#endif /* SOC_INTEL_COMMON_BLOCK_LPSS_I2C_H */ diff --git a/src/soc/intel/skylake/Kconfig b/src/soc/intel/skylake/Kconfig index 475c88311c..2bfa61c2ef 100644 --- a/src/soc/intel/skylake/Kconfig +++ b/src/soc/intel/skylake/Kconfig @@ -54,6 +54,7 @@ config CPU_SPECIFIC_OPTIONS select SOC_INTEL_COMMON_BLOCK_FAST_SPI select SOC_INTEL_COMMON_BLOCK_GSPI select SOC_INTEL_COMMON_BLOCK_ITSS + select SOC_INTEL_COMMON_BLOCK_I2C select SOC_INTEL_COMMON_BLOCK_LPSS select SOC_INTEL_COMMON_BLOCK_PCR select SOC_INTEL_COMMON_BLOCK_RTC @@ -61,7 +62,6 @@ config CPU_SPECIFIC_OPTIONS select SOC_INTEL_COMMON_BLOCK_SMBUS select SOC_INTEL_COMMON_BLOCK_UART select SOC_INTEL_COMMON_BLOCK_XHCI - select SOC_INTEL_COMMON_LPSS_I2C select SOC_INTEL_COMMON_NHLT select SOC_INTEL_COMMON_RESET select SOC_INTEL_COMMON_SPI_FLASH_PROTECT diff --git a/src/soc/intel/skylake/Makefile.inc b/src/soc/intel/skylake/Makefile.inc index d25332c93a..6f1d1d5112 100644 --- a/src/soc/intel/skylake/Makefile.inc +++ b/src/soc/intel/skylake/Makefile.inc @@ -11,7 +11,7 @@ subdirs-y += ../../../cpu/x86/tsc bootblock-y += bootblock/bootblock.c bootblock-y += bootblock/cpu.c -bootblock-y += bootblock/i2c.c +bootblock-y += i2c.c bootblock-y += bootblock/pch.c bootblock-y += bootblock/report_platform.c bootblock-$(CONFIG_UART_DEBUG) += bootblock/uart.c @@ -29,13 +29,13 @@ verstage-y += monotonic_timer.c verstage-y += pch.c verstage-$(CONFIG_UART_DEBUG) += uart_debug.c verstage-y += pmutil.c -verstage-y += bootblock/i2c.c +verstage-y += i2c.c verstage-y += spi.c verstage-y += tsc_freq.c romstage-y += gpio.c romstage-y += gspi.c -romstage-y += bootblock/i2c.c +romstage-y += i2c.c romstage-y += memmap.c romstage-y += monotonic_timer.c romstage-y += me.c diff --git a/src/soc/intel/skylake/bootblock/bootblock.c b/src/soc/intel/skylake/bootblock/bootblock.c index f386f96360..cbe3dd2fdc 100644 --- a/src/soc/intel/skylake/bootblock/bootblock.c +++ b/src/soc/intel/skylake/bootblock/bootblock.c @@ -15,6 +15,7 @@ #include <bootblock_common.h> #include <intelblocks/gspi.h> +#include <intelblocks/lpss_i2c.h> #include <soc/bootblock.h> asmlinkage void bootblock_c_entry(uint64_t base_timestamp) @@ -48,6 +49,6 @@ void bootblock_soc_init(void) report_platform_info(); set_max_freq(); pch_early_init(); - i2c_early_init(); + gspi_early_bar_init(); } diff --git a/src/soc/intel/skylake/bootblock/i2c.c b/src/soc/intel/skylake/bootblock/i2c.c deleted file mode 100644 index f8859a4607..0000000000 --- a/src/soc/intel/skylake/bootblock/i2c.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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 <intelblocks/lpss.h> -#include <soc/intel/common/lpss_i2c.h> -#include <soc/iomap.h> -#include <soc/pci_devs.h> -#include <soc/bootblock.h> -#include "chip.h" - -uintptr_t lpss_i2c_base_address(unsigned int bus) -{ - int 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 int bus) -{ - DEVTREE_CONST struct soc_intel_skylake_config *config; - DEVTREE_CONST struct device *tree_dev; - pci_devfn_t dev; - int devfn; - uintptr_t base; - - /* 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 */ - lpss_reset_release(base); - - /* Initialize the controller */ - lpss_i2c_init(bus, &config->i2c[bus]); -} - -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/chip.h b/src/soc/intel/skylake/chip.h index 43c921e8e6..a42e771ccd 100644 --- a/src/soc/intel/skylake/chip.h +++ b/src/soc/intel/skylake/chip.h @@ -22,11 +22,11 @@ #include <arch/acpi_device.h> #include <device/i2c.h> #include <intelblocks/gspi.h> +#include <intelblocks/lpss_i2c.h> #include <stdint.h> #include <soc/gpio_defs.h> #include <soc/gpe.h> #include <soc/irq.h> -#include <soc/intel/common/lpss_i2c.h> #include <soc/pci_devs.h> #include <soc/pmc.h> #include <soc/serialio.h> diff --git a/src/soc/intel/skylake/i2c.c b/src/soc/intel/skylake/i2c.c index 25cc8e89bc..dce83e7dda 100644 --- a/src/soc/intel/skylake/i2c.c +++ b/src/soc/intel/skylake/i2c.c @@ -13,92 +13,55 @@ * GNU General Public License for more details. */ -#include <arch/acpigen.h> +#include <console/console.h> #include <device/device.h> -#include <device/i2c.h> -#include <device/pci.h> -#include <device/pci_def.h> -#include <device/pci_ids.h> -#include <soc/intel/common/lpss_i2c.h> -#include <soc/ramstage.h> +#include <intelblocks/lpss_i2c.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include "chip.h" -uintptr_t lpss_i2c_base_address(unsigned int bus) +const struct lpss_i2c_bus_config *i2c_get_soc_cfg(unsigned int bus, + const struct device *dev) { - int devfn; - struct device *dev; - struct resource *res; - - /* bus -> devfn */ - devfn = i2c_bus_to_devfn(bus); - if (devfn >= 0) { - /* devfn -> dev */ - dev = dev_find_slot(0, devfn); - if (dev) { - /* dev -> bar0 */ - res = find_resource(dev, PCI_BASE_ADDRESS_0); - if (res) - return res->base; - } + const struct soc_intel_skylake_config *config; + if (!dev || !dev->chip_info) { + printk(BIOS_ERR, "%s: Could not find SoC devicetree config!\n", + __func__); + return NULL; } - return (uintptr_t)NULL; + config = dev->chip_info; + + return &config->i2c[bus]; } -static int i2c_dev_to_bus(struct device *dev) +uintptr_t i2c_get_soc_early_base(unsigned int bus) { - return i2c_devfn_to_bus(dev->path.pci.devfn); + return EARLY_I2C_BASE(bus); } -/* - * The device should already be enabled and out of reset, - * either from early init in coreboot or SiliconInit in FSP. - */ -static void i2c_dev_init(struct device *dev) +int i2c_soc_devfn_to_bus(unsigned int devfn) { - struct soc_intel_skylake_config *config = dev->chip_info; - int bus = i2c_dev_to_bus(dev); - - if (!config || bus < 0) - return; - - lpss_i2c_init(bus, &config->i2c[bus]); + switch (devfn) { + case PCH_DEVFN_I2C0: return 0; + case PCH_DEVFN_I2C1: return 1; + case PCH_DEVFN_I2C2: return 2; + case PCH_DEVFN_I2C3: return 3; + case PCH_DEVFN_I2C4: return 4; + case PCH_DEVFN_I2C5: return 5; + } + return -1; } -/* Generate ACPI I2C device objects */ -static void i2c_fill_ssdt(struct device *dev) +int i2c_soc_bus_to_devfn(unsigned int bus) { - struct soc_intel_skylake_config *config = dev->chip_info; - int bus = i2c_dev_to_bus(dev); - - if (!config || bus < 0) - return; - - acpigen_write_scope(acpi_device_path(dev)); - lpss_i2c_acpi_fill_ssdt(bus, &config->i2c[bus]); - acpigen_pop_len(); + switch (bus) { + case 0: return PCH_DEVFN_I2C0; + case 1: return PCH_DEVFN_I2C1; + case 2: return PCH_DEVFN_I2C2; + case 3: return PCH_DEVFN_I2C3; + case 4: return PCH_DEVFN_I2C4; + case 5: return PCH_DEVFN_I2C5; + } + return -1; } - -static struct i2c_bus_operations i2c_bus_ops = { - .dev_to_bus = &i2c_dev_to_bus, -}; - -static struct device_operations i2c_dev_ops = { - .read_resources = &pci_dev_read_resources, - .set_resources = &pci_dev_set_resources, - .enable_resources = &pci_dev_enable_resources, - .scan_bus = &scan_smbus, - .ops_pci = &soc_pci_ops, - .ops_i2c_bus = &i2c_bus_ops, - .init = &i2c_dev_init, - .acpi_fill_ssdt_generator = &i2c_fill_ssdt, -}; - -static const unsigned short pci_device_ids[] = { - 0x9d60, 0x9d61, 0x9d62, 0x9d63, 0x9d64, 0x9d65, 0 -}; - -static const struct pci_driver pch_i2c __pci_driver = { - .ops = &i2c_dev_ops, - .vendor = PCI_VENDOR_ID_INTEL, - .devices = pci_device_ids, -}; diff --git a/src/soc/intel/skylake/include/soc/pci_devs.h b/src/soc/intel/skylake/include/soc/pci_devs.h index 13114f1f95..f51691c80b 100644 --- a/src/soc/intel/skylake/include/soc/pci_devs.h +++ b/src/soc/intel/skylake/include/soc/pci_devs.h @@ -148,34 +148,6 @@ #define PCH_DEV_SPI _PCH_DEV(LPC, 5) #define PCH_DEV_GBE _PCH_DEV(LPC, 6) -/* Convert I2C bus number to PCI device and function */ -static inline int i2c_bus_to_devfn(unsigned int bus) -{ - switch (bus) { - case 0: return PCH_DEVFN_I2C0; - case 1: return PCH_DEVFN_I2C1; - case 2: return PCH_DEVFN_I2C2; - case 3: return PCH_DEVFN_I2C3; - case 4: return PCH_DEVFN_I2C4; - case 5: return PCH_DEVFN_I2C5; - } - return -1; -} - -/* Convert PCI device and function to I2C bus number */ -static inline int i2c_devfn_to_bus(unsigned int devfn) -{ - switch (devfn) { - case PCH_DEVFN_I2C0: return 0; - case PCH_DEVFN_I2C1: return 1; - case PCH_DEVFN_I2C2: return 2; - case PCH_DEVFN_I2C3: return 3; - case PCH_DEVFN_I2C4: return 4; - case PCH_DEVFN_I2C5: return 5; - } - return -1; -} - static inline int spi_devfn_to_bus(unsigned int devfn) { switch (devfn) { |