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/common | |
parent | 36b09b8a6c3367dded5c3f0c6a1dc1d16d9a1335 (diff) |
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/common')
-rw-r--r-- | src/soc/intel/common/Makefile.inc | 4 | ||||
-rw-r--r-- | src/soc/intel/common/block/i2c/Kconfig | 4 | ||||
-rw-r--r-- | src/soc/intel/common/block/i2c/Makefile.inc | 11 | ||||
-rw-r--r-- | src/soc/intel/common/block/i2c/i2c.c | 183 | ||||
-rw-r--r-- | src/soc/intel/common/block/i2c/i2c_early.c | 97 | ||||
-rw-r--r-- | src/soc/intel/common/block/i2c/lpss_i2c.c (renamed from src/soc/intel/common/lpss_i2c.c) | 231 | ||||
-rw-r--r-- | src/soc/intel/common/block/i2c/lpss_i2c.h | 90 | ||||
-rw-r--r-- | src/soc/intel/common/block/include/intelblocks/lpss_i2c.h (renamed from src/soc/intel/common/lpss_i2c.h) | 42 |
8 files changed, 469 insertions, 193 deletions
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/common/block/i2c/i2c_early.c b/src/soc/intel/common/block/i2c/i2c_early.c new file mode 100644 index 0000000000..7c9ce60513 --- /dev/null +++ b/src/soc/intel/common/block/i2c/i2c_early.c @@ -0,0 +1,97 @@ +/* + * 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 + * 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 <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 <intelblocks/lpss_i2c.h> +#include "lpss_i2c.h" + +static int lpss_i2c_early_init_bus(unsigned int bus) +{ + 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_soc_bus_to_devfn(bus); + if (devfn < 0) { + printk(BIOS_ERR, "I2C%u device not found\n", bus); + return -1; + } + + /* 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) { + printk(BIOS_ERR, "I2C%u device not enabled\n", bus); + return -1; + } + + /* Skip if not enabled for early init */ + 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 = 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); + + /* Take device out of reset */ + lpss_reset_release(base); + + /* Initialize the controller */ + if (lpss_i2c_init(bus, config) < 0) { + printk(BIOS_ERR, "I2C%u failed to initialize\n", bus); + return -1; + } + + return 0; +} + +uintptr_t lpss_i2c_base_address(unsigned int bus) +{ + int devfn; + pci_devfn_t dev; + uintptr_t base; + + /* Find device+function for this controller */ + devfn = i2c_soc_bus_to_devfn(bus); + if (devfn < 0) + return (uintptr_t)NULL; + + /* 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 */ + base = ALIGN_DOWN(pci_read_config32(dev, PCI_BASE_ADDRESS_0), 16); + + /* Attempt to initialize bus if base is not set yet */ + 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 */ |