aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mainboard/siemens/mc_tcu3/mainboard.c6
-rw-r--r--src/mainboard/siemens/mc_tcu3/ptn3460.c79
-rw-r--r--src/soc/intel/fsp_baytrail/Kconfig9
-rw-r--r--src/soc/intel/fsp_baytrail/Makefile.inc3
-rw-r--r--src/soc/intel/fsp_baytrail/chip.h4
-rw-r--r--src/soc/intel/fsp_baytrail/i2c.c456
-rw-r--r--src/soc/intel/fsp_baytrail/include/soc/i2c.h116
-rw-r--r--src/soc/intel/fsp_baytrail/include/soc/iomap.h2
-rw-r--r--src/soc/intel/fsp_baytrail/lpss.c49
9 files changed, 308 insertions, 416 deletions
diff --git a/src/mainboard/siemens/mc_tcu3/mainboard.c b/src/mainboard/siemens/mc_tcu3/mainboard.c
index 9e12aa588f..e77c0b1e29 100644
--- a/src/mainboard/siemens/mc_tcu3/mainboard.c
+++ b/src/mainboard/siemens/mc_tcu3/mainboard.c
@@ -70,9 +70,15 @@ enum cb_err mainboard_get_mac_address(struct device *dev, uint8_t mac[6])
*/
static void mainboard_enable(struct device *dev)
{
+
+}
+
+static void mainboard_final(void *chip_info)
+{
setup_lcd_panel();
}
struct chip_operations mainboard_ops = {
.enable_dev = mainboard_enable,
+ .final = mainboard_final,
};
diff --git a/src/mainboard/siemens/mc_tcu3/ptn3460.c b/src/mainboard/siemens/mc_tcu3/ptn3460.c
index 414baeb089..56f51f9647 100644
--- a/src/mainboard/siemens/mc_tcu3/ptn3460.c
+++ b/src/mainboard/siemens/mc_tcu3/ptn3460.c
@@ -1,7 +1,7 @@
/*
* This file is part of the coreboot project.
*
- * Copyright (C) 2014 Siemens AG
+ * Copyright (C) 2014-2019 Siemens AG
*
* 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
@@ -18,7 +18,7 @@
#include <string.h>
#include <delay.h>
#include <types.h>
-
+#include <device/i2c_simple.h>
#include "soc/i2c.h"
#include "ptn3460.h"
@@ -34,6 +34,7 @@ int ptn3460_init(char *hwi_block)
uint8_t disp_con = 0, color_depth = 0;
uint8_t edid_data[0x80];
uint8_t hwid[4], tcu31_hwid[4] = {7, 9, 2, 0};
+ uint8_t i;
if (!hwi_block || hwilib_find_blocks(hwi_block) != CB_SUCCESS) {
printk(BIOS_ERR, "LCD: Info block \"%s\" not found!\n",
@@ -41,10 +42,6 @@ int ptn3460_init(char *hwi_block)
return 1;
}
- status = i2c_init(PTN_I2C_CONTROLLER);
- if (status)
- return (PTN_BUS_ERROR | status);
-
/* Get all needed information from hwinfo block */
if (hwilib_get_field(Edid, edid_data, 0x80) != sizeof(edid_data)) {
printk(BIOS_ERR, "LCD: No EDID data available in %s\n",
@@ -69,8 +66,8 @@ int ptn3460_init(char *hwi_block)
/* Select this table to be emulated */
ptn_select_edid(6);
/* Read PTN configuration data */
- status = i2c_read(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF,
- (u8*)&cfg, PTN_CONFIG_LEN);
+ status = i2c_read_bytes(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF, (u8 *) &cfg,
+ sizeof(struct ptn_3460_config));
if (status)
return (PTN_BUS_ERROR | status);
@@ -81,7 +78,6 @@ int ptn3460_init(char *hwi_block)
cfg.lvds_interface_ctrl1 |= 0x0b; /* Turn on dual LVDS lane and clock */
if (color_depth == PF_COLOR_DEPTH_6BIT)
cfg.lvds_interface_ctrl1 |= 0x20; /* Use 18 bits per pixel */
-
cfg.lvds_interface_ctrl2 = 0x03; /* no clock spreading, 300 mV LVDS swing */
/* Swap LVDS even and odd lanes for HW-ID 7.9.2.0 only. */
if (hwilib_get_field(HWID, hwid, sizeof(hwid)) == sizeof(hwid) &&
@@ -89,20 +85,22 @@ int ptn3460_init(char *hwi_block)
cfg.lvds_interface_ctrl3 = 0x01; /* swap LVDS even and odd */
} else
cfg.lvds_interface_ctrl3 = 0x00; /* no LVDS signal swap */
- cfg.t2_delay = 1; /* Delay T2 (VDD to LVDS active) by 16 ms */
- cfg.t3_timing = 10; /* 500 ms from LVDS to backlight active */
- cfg.t12_timing = 20; /* 1 second re-power delay */
- cfg.t4_timing = 3; /* 150 ms backlight off to LVDS inactive */
- cfg.t5_delay = 1; /* Delay T5 (LVDS to VDD inactive) by 16 ms */
- cfg.backlight_ctrl = 0; /* Enable backlight control */
+ cfg.t2_delay = 1; /* Delay T2 (VDD to LVDS active) by 16 ms */
+ cfg.t3_timing = 10; /* 500 ms from LVDS to backlight active */
+ cfg.t12_timing = 20; /* 1 second re-power delay */
+ cfg.t4_timing = 3; /* 150 ms backlight off to LVDS inactive */
+ cfg.t5_delay = 1; /* Delay T5 (LVDS to VDD inactive) by 16 ms */
+ cfg.backlight_ctrl = 0; /* Enable backlight control */
/* Write back configuration data to PTN3460 */
- status = i2c_write(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF,
- (u8*)&cfg, PTN_CONFIG_LEN);
- if (status)
- return (PTN_BUS_ERROR | status);
- else
- return PTN_NO_ERROR;
+ for (i = 0; i < sizeof(struct ptn_3460_config); i++) {
+ status = i2c_writeb(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF + i,
+ *(((uint8_t *) &cfg) + i));
+ if (status)
+ return (PTN_BUS_ERROR | status);
+ }
+
+ return PTN_NO_ERROR;
}
/** \brief This functions reads one desired EDID data structure from PTN3460
@@ -117,14 +115,13 @@ int ptn3460_read_edid(u8 edid_num, u8 *data)
if (edid_num > PTN_MAX_EDID_NUM)
return PTN_INVALID_EDID;
/* First enable access to the desired EDID table */
- status = i2c_write(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF + 5,
- &edid_num, 1);
+ status = i2c_writeb(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF + 5, edid_num);
if (status)
return (PTN_BUS_ERROR | status);
/* Now we can simply read back EDID-data */
- status = i2c_read(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_EDID_OFF,
- data, PTN_EDID_LEN);
+ status = i2c_read_bytes(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_EDID_OFF, data,
+ PTN_EDID_LEN);
if (status)
return (PTN_BUS_ERROR | status);
else
@@ -139,22 +136,24 @@ int ptn3460_read_edid(u8 edid_num, u8 *data)
int ptn3460_write_edid(u8 edid_num, u8 *data)
{
int status;
+ int i;
if (edid_num > PTN_MAX_EDID_NUM)
return PTN_INVALID_EDID;
+
/* First enable access to the desired EDID table */
- status = i2c_write(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF + 5,
- &edid_num, 1);
+ status = i2c_writeb(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF + 5, edid_num);
if (status)
return (PTN_BUS_ERROR | status);
/* Now we can simply write EDID-data to ptn3460 */
- status = i2c_write(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_EDID_OFF,
- data, PTN_EDID_LEN);
- if (status)
- return (PTN_BUS_ERROR | status);
- else
- return PTN_NO_ERROR;
+ for (i = 0; i < PTN_EDID_LEN; i++) {
+ status = i2c_writeb(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_EDID_OFF + i,
+ data[i]);
+ if (status)
+ return (PTN_BUS_ERROR | status);
+ }
+ return PTN_NO_ERROR;
}
/** \brief This functions selects one of 7 EDID-tables inside PTN3460
@@ -171,8 +170,7 @@ int ptn_select_edid (u8 edid_num)
return PTN_INVALID_EDID;
/* Enable emulation of the desired EDID table */
val = (edid_num << 1) | 1;
- status = i2c_write(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF + 4,
- &val, 1);
+ status = i2c_writeb(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_CONFIG_OFF + 4, val);
if (status)
return (PTN_BUS_ERROR | status);
else
@@ -188,14 +186,19 @@ int ptn_select_edid (u8 edid_num)
*/
int ptn3460_flash_config(void)
{
- int status;
+ int status, i;
struct ptn_3460_flash flash;
flash.cmd = 0x01; /* perform erase and flash cycle */
flash.magic = 0x7845; /* Magic number to protect flash operation */
flash.trigger = 0x56; /* This value starts flash operation */
- status = i2c_write(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_FLASH_CFG_OFF,
- (u8*)&flash, PTN_FLASH_CFG_LEN);
+
+ for (i = 0; i < sizeof(struct ptn_3460_flash); i++) {
+ status = i2c_writeb(PTN_I2C_CONTROLLER, PTN_SLAVE_ADR, PTN_FLASH_CFG_OFF+i,
+ *(((uint8_t *) &flash) + i));
+ if (status)
+ return (PTN_BUS_ERROR | status);
+ }
if (status) {
return (PTN_BUS_ERROR | status);
} else {
diff --git a/src/soc/intel/fsp_baytrail/Kconfig b/src/soc/intel/fsp_baytrail/Kconfig
index 072df295a5..efe12da480 100644
--- a/src/soc/intel/fsp_baytrail/Kconfig
+++ b/src/soc/intel/fsp_baytrail/Kconfig
@@ -44,6 +44,7 @@ config CPU_SPECIFIC_OPTIONS
select MICROCODE_BLOB_NOT_HOOKED_UP
select INTEL_DESCRIPTOR_MODE_CAPABLE
select HAVE_SPI_CONSOLE_SUPPORT
+ select DRIVERS_I2C_DESIGNWARE
# Microcode header files are delivered in FSP package
select USES_MICROCODE_HEADER_FILES if HAVE_FSP_BIN
@@ -103,6 +104,14 @@ config CPU_MICROCODE_HEADER_FILES
string
default "../intel/cpu/baytrail/microcode/M0130673322.h ../intel/cpu/baytrail/microcode/M0130679901.h ../intel/cpu/baytrail/microcode/M0230672228.h"
+config DRIVERS_I2C_DESIGNWARE_CLOCK_MHZ
+ int
+ default 133
+
+config SOC_INTEL_I2C_DEV_MAX
+ int
+ default 7
+
## Baytrail Specific FSP Kconfig
source src/soc/intel/fsp_baytrail/fsp/Kconfig
diff --git a/src/soc/intel/fsp_baytrail/Makefile.inc b/src/soc/intel/fsp_baytrail/Makefile.inc
index fa719320ee..0d89832f7d 100644
--- a/src/soc/intel/fsp_baytrail/Makefile.inc
+++ b/src/soc/intel/fsp_baytrail/Makefile.inc
@@ -3,7 +3,7 @@
#
# Copyright (C) 2010 Google Inc.
# Copyright (C) 2013-2014 Sage Electronic Engineering, LLC.
-# Copyright (C) 2016 Siemens AG
+# Copyright (C) 2016-2019 Siemens AG
#
# 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
@@ -34,6 +34,7 @@ romstage-y += memmap.c
romstage-y += pmutil.c
romstage-y += spi.c
romstage-y += tsc_freq.c
+romstage-y += i2c.c
postcar-y += tsc_freq.c
diff --git a/src/soc/intel/fsp_baytrail/chip.h b/src/soc/intel/fsp_baytrail/chip.h
index b73aa14904..e3167885b2 100644
--- a/src/soc/intel/fsp_baytrail/chip.h
+++ b/src/soc/intel/fsp_baytrail/chip.h
@@ -20,6 +20,7 @@
#include <arch/acpi.h>
#include <drivers/intel/fsp1_0/fsp_values.h>
+#include <drivers/i2c/designware/dw_i2c.h>
/* The devicetree parser expects chip.h to reside directly in the path
* specified by the devicetree. */
@@ -346,6 +347,9 @@ struct soc_intel_fsp_baytrail_config {
int lpe_codec_clk_freq; /* 19 or 25 are valid. */
int lpe_codec_clk_num; /* Platform clock pins. [0:5] are valid. */
+ /* Structure for designware I2C controller */
+ struct dw_i2c_bus_config i2c[CONFIG_SOC_INTEL_I2C_DEV_MAX];
+
/* ***** ACPI configuration ***** */
/* Options for these are in src/arch/x86/include/arch/acpi.h */
uint8_t fadt_pm_profile;
diff --git a/src/soc/intel/fsp_baytrail/i2c.c b/src/soc/intel/fsp_baytrail/i2c.c
index 5f6ca467ea..37ce2d0b21 100644
--- a/src/soc/intel/fsp_baytrail/i2c.c
+++ b/src/soc/intel/fsp_baytrail/i2c.c
@@ -1,7 +1,7 @@
/*
* This file is part of the coreboot project.
*
- * Copyright (C) 2014 Siemens AG
+ * Copyright (C) 2014-2019 Siemens AG
*
* 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
@@ -13,258 +13,282 @@
* GNU General Public License for more details.
*/
-#include <device/pci.h>
-#include <device/pci_ops.h>
+#include <cbmem.h>
#include <console/console.h>
-#include <soc/baytrail.h>
-#include <soc/pci_devs.h>
-#include <soc/iosf.h>
-#include <device/mmio.h>
-#include <delay.h>
+#include <device/device.h>
+#include <device/pci_def.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <drivers/i2c/designware/dw_i2c.h>
#include <soc/i2c.h>
+#include <soc/iosf.h>
+#include <soc/iomap.h>
+#include <soc/nvs.h>
+#include <soc/pci_devs.h>
-/* Wait for the transmit FIFO till there is at least one slot empty.
- * FIFO stall due to transmit abort will be checked and resolved
- */
-static int wait_tx_fifo(char *base_adr)
+#include "chip.h"
+
+/* Convert I2C bus number to PCI device and function */
+int dw_i2c_soc_bus_to_devfn(unsigned int bus)
{
- int i;
- u32 as;
-
- as = read32(base_adr + I2C_ABORT_SOURCE) & 0x1ffff;
- if (as) {
- /* Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO */
- i = read32(base_adr + I2C_CLR_TX_ABRT);
- return I2C_ERR_ABORT | as;
- }
+ if (bus <= 6)
+ return PCI_DEVFN(SIO1_DEV, bus + 1);
+ else
+ return -1;
+}
+
+/* Convert PCI device and function to I2C bus number */
+int dw_i2c_soc_dev_to_bus(struct device *dev)
+{
+ pci_devfn_t devfn = dev->path.pci.devfn;
+ if ((devfn >= SOC_DEVFN_I2C1) && (devfn <= SOC_DEVFN_I2C7))
+ return PCI_FUNC(devfn) - 1;
+ else
+ return -1;
+}
+
+/* Getting I2C bus configuration from devicetree config */
+const struct dw_i2c_bus_config *dw_i2c_get_soc_cfg(unsigned int bus)
+{
+ const struct soc_intel_fsp_baytrail_config *config;
+ const struct device *dev = pcidev_path_on_root(SOC_DEVFN_SOC);
- /* Wait here for a free slot in TX-FIFO */
- i = I2C_TIMEOUT_US;
- while (!(read32(base_adr + I2C_STATUS) & I2C_TFNF)) {
- udelay(1);
- if (!--i)
- return I2C_ERR_TIMEOUT;
+ if (dev && dev->chip_info) {
+ config = dev->chip_info;
+ return &config->i2c[bus];
}
- return I2C_SUCCESS;
+ die("Could not find SA_DEV_ROOT devicetree config!\n");
}
-/* Wait for the receive FIFO till there is at least one valid entry to read.
- * FIFO stall due to transmit abort will be checked and resolved
- */
-static int wait_rx_fifo(char *base_adr)
+#if !ENV_RAMSTAGE
+static int lpss_i2c_early_init_bus(unsigned int bus)
{
- int i;
- u32 as;
-
- as = read32(base_adr + I2C_ABORT_SOURCE) & 0x1ffff;
- if (as) {
- /* Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO */
- i = read32(base_adr + I2C_CLR_TX_ABRT);
- return I2C_ERR_ABORT | as;
+ const struct dw_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 = dw_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 = pcidev_path_on_root(devfn);
+ if (!tree_dev || !tree_dev->enabled) {
+ printk(BIOS_ERR, "I2C%u device not enabled\n", bus);
+ return -1;
}
- /* Wait here for a received entry in RX-FIFO */
- i = I2C_TIMEOUT_US;
- while (!(read32(base_adr + I2C_STATUS) & I2C_RFNE)) {
- udelay(1);
- if (!--i)
- return I2C_ERR_TIMEOUT;
+ /* Skip if not enabled for early init */
+ config = dw_i2c_get_soc_cfg(bus);
+ 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 = 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 */
+ write32((void *)((uint32_t)base + I2C_SOFTWARE_RESET), I2C_RESET_APB | I2C_RESET_FUNC);
+
+ /* Initialize the controller */
+ if (dw_i2c_init(bus, config) < 0) {
+ printk(BIOS_ERR, "I2C%u failed to initialize\n", bus);
+ return -1;
}
- return I2C_SUCCESS;
+ return 0;
}
-/* When there will be a fast switch between send and receive, one have
- * to wait until the first operation is completely finished
- * before starting the second operation
- */
-static int wait_for_idle(char *base_adr)
+uintptr_t dw_i2c_base_address(unsigned int bus)
{
- int i;
- int status;
-
- /* For IDLE, increase timeout by ten times */
- i = I2C_TIMEOUT_US * 10;
- status = read32(base_adr + I2C_STATUS);
- while (((status & I2C_MST_ACTIVITY) || (!(status & I2C_TFE)))) {
- status = read32(base_adr + I2C_STATUS);
- udelay(1);
- if (!--i)
- return I2C_ERR_TIMEOUT;
- }
+ int devfn;
+ pci_devfn_t dev;
+ uintptr_t base;
+
+ /* Find device+function for this controller */
+ devfn = dw_i2c_soc_bus_to_devfn(bus);
+ if (devfn < 0)
+ return 0;
- return I2C_SUCCESS;
+ /* 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 = pci_read_config32(dev, PCI_BASE_ADDRESS_0) & 0xfffffff0;
+
+ /* Attempt to initialize bus if base is not set yet */
+ if (!base && !lpss_i2c_early_init_bus(bus))
+ base = pci_read_config32(dev, PCI_BASE_ADDRESS_0) & 0xfffffff0;
+ return base;
}
+#else
-/** \brief Enables I2C-controller, sets up BAR and timing parameters
- * @param bus Number of the I2C-controller to use (0...6)
- * @return I2C_SUCCESS on success, otherwise error code
- */
-int i2c_init(unsigned bus)
+uintptr_t dw_i2c_base_address(unsigned int bus)
{
+ int devfn;
struct device *dev;
- int base_adr[7] = {I2C0_MEM_BASE, I2C1_MEM_BASE, I2C2_MEM_BASE,
- I2C3_MEM_BASE, I2C4_MEM_BASE, I2C5_MEM_BASE,
- I2C6_MEM_BASE};
- char *base_ptr;
-
- /* Ensure the desired device is valid */
- if (bus >= ARRAY_SIZE(base_adr)) {
- printk(BIOS_ERR, "I2C: Only I2C controllers 0...6 are available.\n");
- return I2C_ERR;
+ struct resource *bar = NULL;
+
+ /* bus -> devfn */
+ devfn = dw_i2c_soc_bus_to_devfn(bus);
+
+ if (devfn < 0)
+ return (uintptr_t)NULL;
+
+ /* devfn -> dev */
+ dev = pcidev_path_on_root(devfn);
+ if (dev && dev->enabled) {
+ /* dev -> bar0 */
+ bar = find_resource(dev, PCI_BASE_ADDRESS_0);
}
- base_ptr = (char*)base_adr[bus];
- /* Set the I2C-device the user wants to use */
- dev = pcidev_on_root(PCH_DEV_SLOT_I2C1, bus + 1);
+ if (bar)
+ return bar->base;
+ else
+ return (uintptr_t)NULL;
+}
- /* Ensure we have the right PCI device */
- if ((pci_read_config16(dev, 0x0) != I2C_PCI_VENDOR_ID) ||
- (pci_read_config16(dev, 0x2) != (I2C0_PCI_DEV_ID + bus))) {
- printk(BIOS_ERR, "I2C: Controller %d not found!\n", bus);
- return I2C_ERR;
+static void i2c_enable_acpi_mode(struct device *dev, int iosf_reg, int nvs_index)
+{
+ struct resource *bar;
+ global_nvs_t *gnvs;
+ uint32_t val;
+
+ /* Find ACPI NVS to update BARs */
+ gnvs = (global_nvs_t *)cbmem_find(CBMEM_ID_ACPI_GNVS);
+ if (!gnvs) {
+ printk(BIOS_ERR, "Unable to locate Global NVS\n");
+ return;
}
- /* Set memory base */
- pci_write_config32(dev, PCI_BASE_ADDRESS_0, (int)base_ptr);
+ /* Save BAR0 and BAR1 to ACPI NVS */
+ bar = find_resource(dev, PCI_BASE_ADDRESS_0);
+ if (bar)
+ gnvs->dev.lpss_bar0[nvs_index] = (uint32_t)bar->base;
+
+ bar = find_resource(dev, PCI_BASE_ADDRESS_1);
+ if (bar)
+ gnvs->dev.lpss_bar1[nvs_index] = (uint32_t)bar->base;
+
+ /* Device is enabled in ACPI mode */
+ gnvs->dev.lpss_en[nvs_index] = 1;
+
+ /* Put device in ACPI mode */
+ val = iosf_lpss_read(iosf_reg);
+ val |= (LPSS_CTL_PCI_CFG_DIS | LPSS_CTL_ACPI_INT_EN);
+ iosf_lpss_write(iosf_reg, val);
+ val = pci_read_config32(dev, PCI_COMMAND);
+ val |= PCI_COMMAND_INT_DISABLE;
+ pci_write_config32(dev, PCI_COMMAND, val);
+}
- /* Enable memory space */
- pci_write_config32(dev, PCI_COMMAND,
- (pci_read_config32(dev, PCI_COMMAND) | 0x2));
-
- /* Set up some settings of I2C controller */
- write32(base_ptr + I2C_CTRL,
- I2C_RESTART_EN | (I2C_STANDARD_MODE << 1) | I2C_MASTER_ENABLE);
- /* Adjust frequency for standard mode to 100 kHz */
- /* The counter value can be computed by N=100MHz/2/I2C_CLK */
- /* Thus, for 100 kHz I2C_CLK, N is 0x1F4 */
- write32(base_ptr + I2C_SS_SCL_HCNT, 0x1f4);
- write32(base_ptr + I2C_SS_SCL_LCNT, 0x1f4);
- /* For 400 kHz, the counter value is 0x7d */
- write32(base_ptr + I2C_FS_SCL_HCNT, 0x7d);
- write32(base_ptr + I2C_FS_SCL_LCNT, 0x7d);
- /* no interrupts in BIOS */
- write32(base_ptr + I2C_INTR_MASK, 0);
-
- /* Enable the I2C controller for operation */
- write32(base_ptr + I2C_ENABLE, 0x1);
-
- printk(BIOS_INFO, "I2C: Controller %d enabled.\n", bus);
- return I2C_SUCCESS;
+static void dev_enable_snoop_and_pm(struct device *dev, int iosf_reg)
+{
+ uint32_t val;
+
+ val = iosf_lpss_read(iosf_reg);
+ val &= ~(LPSS_CTL_SNOOP | LPSS_CTL_NOSNOOP);
+ val |= (LPSS_CTL_SNOOP | LPSS_CTL_PM_CAP_PRSNT);
+ iosf_lpss_write(iosf_reg, val);
}
-/** \brief Read bytes over I2C-Bus from a slave. This function tries only one
- * time to transmit data. In case of an error (abort) error code is
- * returned. Retransmission has to be done from caller!
- * @param bus Number of the I2C-controller to use (0...6)
- * @param chip 7 Bit of the slave address on I2C bus
- * @param addr Address inside slave where to read from
- * @param *buf Pointer to the buffer where to store read data
- * @param len Number of bytes to read
- * @return I2C_SUCCESS when read was successful, otherwise error code
- */
-int i2c_read(unsigned bus, unsigned chip, unsigned addr,
- uint8_t *buf, unsigned len)
+static void dev_ctl_reg(struct device *dev, int *iosf_reg, int *nvs_index)
{
- int i = 0;
- char *base_ptr = NULL;
- struct device *dev;
- unsigned int val;
- int stat;
-
- /* Get base address of desired I2C-controller */
- dev = pcidev_on_root(PCH_DEV_SLOT_I2C1, bus + 1);
- base_ptr = (char *)pci_read_config32(dev, PCI_BASE_ADDRESS_0);
- if (base_ptr == NULL) {
- printk(BIOS_INFO, "I2C: Invalid Base address\n");
- return I2C_ERR_INVALID_ADR;
- }
+ int bus;
- /* Ensure I2C controller is not active before setting slave address */
- stat = wait_for_idle(base_ptr);
- if (stat != I2C_SUCCESS)
- return stat;
-
- /* clear any abort status from a previous transaction */
- read32(base_ptr + I2C_CLR_TX_ABRT);
-
- /* Now we can program the desired slave address and start transfer */
- write32(base_ptr + I2C_TARGET_ADR, chip & 0xff);
- /* Send address inside slave to read from */
- write32(base_ptr + I2C_DATA_CMD, addr & 0xff);
-
- /* For the next byte we need a repeated start condition */
- val = I2C_RW_CMD | I2C_RESTART;
- /* Now we can read desired amount of data over I2C */
- for (i = 0; i < len; i++) {
- /* A read is initiated by writing dummy data to the DATA-register */
- write32(base_ptr + I2C_DATA_CMD, val);
- stat = wait_rx_fifo(base_ptr);
- if (stat)
- return stat;
- buf[i] = read32(base_ptr + I2C_DATA_CMD) & 0xff;
- val = I2C_RW_CMD;
- if (i == (len - 2)) {
- /* For the last byte we need a stop condition to be generated */
- val |= I2C_STOP;
- }
+ bus = dw_i2c_soc_dev_to_bus(dev);
+ if (bus >= 0) {
+ *iosf_reg = LPSS_I2C1_CTL + (bus * 8);
+ *nvs_index = bus + 1;
+ } else {
+
+ *iosf_reg = -1;
+ *nvs_index = -1;
}
- return I2C_SUCCESS;
}
-/** \brief Write bytes over I2C-Bus from a slave. This function tries only one
- * time to transmit data. In case of an error (abort) error code is
- * returned. Retransmission has to be done from caller!
- * @param bus Number of the I2C-controller to use (0...6)
- * @param chip 7 Bit of the slave address on I2C bus
- * @param addr Address inside slave where to write to
- * @param *buf Pointer to the buffer where data to write is stored
- * @param len Number of bytes to write
- * @return I2C_SUCCESS when read was successful, otherwise error code
- */
-int i2c_write(unsigned bus, unsigned chip, unsigned addr,
- const uint8_t *buf, unsigned len)
+static void i2c_disable_resets(struct device *dev)
{
- int i;
- char *base_ptr;
- struct device *dev;
- unsigned int val;
- int stat;
-
- /* Get base address of desired I2C-controller */
- dev = pcidev_on_root(PCH_DEV_SLOT_I2C1, bus + 1);
- base_ptr = (char *)pci_read_config32(dev, PCI_BASE_ADDRESS_0);
- if (base_ptr == NULL) {
- return I2C_ERR_INVALID_ADR;
- }
+ uint32_t base;
- /* Ensure I2C controller is not active yet */
- stat = wait_for_idle(base_ptr);
- if (stat) {
- return stat;
- }
+ printk(BIOS_DEBUG, "Releasing I2C device from reset.\n");
+ base = pci_read_config32(dev, PCI_BASE_ADDRESS_0) & 0xfffffff0;
+ write32((void *)(base + I2C_SOFTWARE_RESET), I2C_RESET_APB | I2C_RESET_FUNC);
+}
- /* clear any abort status from a previous transaction */
- read32(base_ptr + I2C_CLR_TX_ABRT);
-
- /* Program slave address to use for this transfer */
- write32(base_ptr + I2C_TARGET_ADR, chip & 0xff);
-
- /* Send address inside slave to write data to */
- write32(base_ptr + I2C_DATA_CMD, addr & 0xff);
-
- for (i = 0; i < len; i++) {
- val = (unsigned int)(buf[i] & 0xff); /* Take only 8 bits */
- if (i == (len - 1)) {
- /* For the last byte we need a stop condition */
- val |= I2C_STOP;
- }
- stat = wait_tx_fifo(base_ptr);
- if (stat) {
- return stat;
- }
- write32(base_ptr + I2C_DATA_CMD, val);
+static void i2c_lpss_init(struct device *dev)
+{
+ struct soc_intel_fsp_baytrail_config *config = dev->chip_info;
+ int iosf_reg, nvs_index;
+
+ dev_ctl_reg(dev, &iosf_reg, &nvs_index);
+
+ if (iosf_reg < 0) {
+ int slot = PCI_SLOT(dev->path.pci.devfn);
+ int func = PCI_FUNC(dev->path.pci.devfn);
+ printk(BIOS_DEBUG, "Could not find iosf_reg for %02x.%01x\n",
+ slot, func);
+ return;
}
- return I2C_SUCCESS;
+ dev_enable_snoop_and_pm(dev, iosf_reg);
+ i2c_disable_resets(dev);
+
+ if (config && (config->PcdLpssSioEnablePciMode == LPSS_PCI_MODE_DISABLE))
+ i2c_enable_acpi_mode(dev, iosf_reg, nvs_index);
}
+/*
+ * This function ensures that the device is actually out of reset and
+ * it is ready for initialization sequence.
+ */
+static void dw_i2c_device_init(struct device *dev)
+{
+ int bus = dw_i2c_soc_dev_to_bus(dev);
+
+ if (bus < 0)
+ return;
+
+ if (!dw_i2c_base_address(bus))
+ return;
+ i2c_lpss_init(dev);
+ dw_i2c_dev_init(dev);
+}
+
+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 = &dw_i2c_bus_ops,
+ .ops_pci = &pci_dev_ops_pci,
+ .init = dw_i2c_device_init,
+ .acpi_fill_ssdt_generator = dw_i2c_acpi_fill_ssdt,
+};
+
+static const unsigned short pci_device_ids[] = {
+ I2C1_DEVID,
+ I2C2_DEVID,
+ I2C3_DEVID,
+ I2C4_DEVID,
+ I2C5_DEVID,
+ I2C6_DEVID,
+ I2C7_DEVID,
+ 0
+};
+
+static const struct pci_driver pch_i2c __pci_driver = {
+ .ops = &i2c_dev_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .devices = pci_device_ids,
+};
+#endif
diff --git a/src/soc/intel/fsp_baytrail/include/soc/i2c.h b/src/soc/intel/fsp_baytrail/include/soc/i2c.h
index f0ae0b37ad..3a4ff2c32b 100644
--- a/src/soc/intel/fsp_baytrail/include/soc/i2c.h
+++ b/src/soc/intel/fsp_baytrail/include/soc/i2c.h
@@ -1,7 +1,7 @@
/*
* This file is part of the coreboot project.
*
- * Copyright (C) 2014 Siemens AG
+ * Copyright (C) 2014-2019 Siemens AG
*
* 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
@@ -16,116 +16,8 @@
#ifndef __SOC_INTEL_FSP_BAYTRAIL_I2C_H__
#define __SOC_INTEL_FSP_BAYTRAIL_I2C_H__
-#include <device/pci_def.h>
-#include <stdlib.h>
-
-/* SMBus controller settings in PCI configuration space */
-#define I2C_PCI_VENDOR_ID 0x8086
-#define I2C0_PCI_DEV_ID 0x0f41
-#define I2C1_PCI_DEV_ID 0x0f42
-#define I2C2_PCI_DEV_ID 0x0f43
-#define I2C3_PCI_DEV_ID 0x0f44
-#define I2C4_PCI_DEV_ID 0x0f45
-#define I2C5_PCI_DEV_ID 0x0f46
-#define I2C6_PCI_DEV_ID 0x0f47
-
-#define I2C0_MEM_BASE 0xd0921000
-#define I2C1_MEM_BASE 0xd0923000
-#define I2C2_MEM_BASE 0xd0925000
-#define I2C3_MEM_BASE 0xd0927000
-#define I2C4_MEM_BASE 0xd0929000
-#define I2C5_MEM_BASE 0xd092b000
-#define I2C6_MEM_BASE 0xd092d000
-
-#define I2C_STANDARD_MODE 0x1
-#define I2C_FAST_MODE 0x2
-
-/* Define relevant registers in PCI space */
-#define I2C_PCI_COMMAND 0x4
-#define I2C_PCI_STATUS 0x6
-
-/* Define memory mapped registers */
-#define I2C_CTRL 0x0
-#define I2C_SLAVE_DISABLE 0x40
-#define I2C_RESTART_EN 0x20
-#define I2C_ADR_MODE 0x10
-#define I2C_SPEED_MASK 0x6
-#define I2C_STD_MODE 0x1
-#define I2C_FAST_MODE 0x2
-#define I2C_MASTER_ENABLE 0x1
-
-#define I2C_TARGET_ADR 0x4
-#define I2C_TARGET_ADR_MASK 0x3ff
-
-#define I2C_DATA_CMD 0x10
-#define I2C_RESTART 0x400
-#define I2C_STOP 0x200
-#define I2C_RW_CMD 0x100
-
-#define I2C_SS_SCL_HCNT 0x14 /* Counter for high period for 100 kHz SCL */
-#define I2C_SS_SCL_LCNT 0x18 /* Counter for low period for 100 kHz SCL */
-#define I2C_FS_SCL_HCNT 0x1c /* Counter for high period for 400 kHz SCL */
-#define I2C_FS_SCL_LCNT 0x20 /* Counter for low period for 400 kHz SCL */
-
-#define I2C_INTR_STAT 0x2c /* Interrupt status register, read only */
-#define I2C_INTR_MASK 0x30 /* Interrupt mask register */
-#define I2C_RAW_INTR_STAT 0x34 /* Raw interrupt status, read only */
-#define I2C_START_DETECT 0x400
-#define I2C_STOP_DETECT 0x200
-#define I2C_ACTIVITY 0x100
-#define I2C_TX_ABORT 0x40
-#define I2C_RD_REQ 0x20 /* Read request in slave mode */
-#define I2C_TX_EMPTY 0x10
-#define I2C_TX_OVERFLOW 0x8
-#define I2C_RX_FULL 0x4
-#define I2C_RX_OVERFLOW 0x2
-#define I2C_RX_UNDERFLOW 0x1
-
-#define I2C_RX_TL 0x38 /* Rx FIFO threshold level 0..255 */
-#define I2C_TX_TL 0x3c /* Tx FIFO threshold level 0..255 */
-#define I2C_CLR_INTR 0x40 /* Clear all events with a read */
-#define I2C_CLR_TX_ABRT 0x54 /* Clear TX-Abort event with a read */
-
-/* There are a bunch of interrupt clearing registers now which are not used! */
-/* So proceed somewhat later with definition */
-#define I2C_ENABLE 0x6c /* 0: disable I2C controller, 1: enable */
-#define I2C_STATUS 0x70
-#define I2C_MST_ACTIVITY 0x20 /* Master FSM activity */
-#define I2C_RFF 0x10 /* Receive FIFO completely full */
-#define I2C_RFNE 0x8 /* Receive FIFO not empty */
-#define I2C_TFE 0x4 /* Transmit FIFO completely empty */
-#define I2C_TFNF 0x2 /* Transmit FIFO not full */
-#define I2C_ACTIVE 0x1 /* 1: I2C currently in operation */
-
-#define I2C_TXFLR 0x74 /* Current transmit FIFO level */
-#define I2C_RXFLR 0x78 /* Current receive FIFO level */
-#define I2C_SDA_HOLD 0x7c /* Data hold time after SCL goes low */
-#define I2C_ABORT_SOURCE 0x80
-#define I2C_ARB_LOST 0x1000 /* Arbitration lost */
-#define I2C_MASTER_DIS 0x800 /* Master was disabled by user */
-#define I2C_10B_RD_NORSTRT 0x400 /* 10 bit address read and RESTART disabled */
-#define I2C_SBYTE_NORSTRT 0x200 /* START with RESTART disabled */
-#define I2C_START_ACKDET 0x80 /* START byte was acknowledged */
-#define I2C_TX_DATA_NOACK 0x8 /* TX data not acknowledged */
-#define I2C_10B_ADR2_NOACK 0x4 /* Second address byte in 10 bit mode NACK */
-#define I2C_10B_ADR1_NOACK 0x2 /* First address byte in 10 bit NACK */
-#define I2C_7B_ADDR_NACK 0x1 /* 7 bit address byte not acknowledged */
-
-#define I2C_ENABLE_STATUS 0x9c
-
-/* Define some status and error values */
-#define I2C_ERR_INVALID_ADR 0x1000000
-#define I2C_ERR_TIMEOUT 0x2000000
-#define I2C_ERR_ABORT 0x4000000
-#define I2C_ERR 0x8000000
-#define I2C_SUCCESS 0x0000000
-
-
-#define I2C_TIMEOUT_US 2000 /* Use 2000 us as time */
-
-/* Prototype section*/
-int i2c_init(unsigned bus);
-int i2c_read(unsigned bus, unsigned chip, unsigned addr, uint8_t *buf, unsigned len);
-int i2c_write(unsigned bus, unsigned chip, unsigned addr, const uint8_t *buf, unsigned len);
+#define I2C_SOFTWARE_RESET 0x804
+#define I2C_RESET_APB (1 << 1)
+#define I2C_RESET_FUNC (1 << 0)
#endif /* __SOC_INTEL_FSP_BAYTRAIL_I2C_H__ */
diff --git a/src/soc/intel/fsp_baytrail/include/soc/iomap.h b/src/soc/intel/fsp_baytrail/include/soc/iomap.h
index 11c01e311d..d54d3fcc29 100644
--- a/src/soc/intel/fsp_baytrail/include/soc/iomap.h
+++ b/src/soc/intel/fsp_baytrail/include/soc/iomap.h
@@ -65,6 +65,8 @@
/* Temporary Base Address */
#define TEMP_BASE_ADDRESS 0xfd000000
+#define EARLY_I2C_BASE_ADDRESS 0xfe020000
+#define EARLY_I2C_BASE(x) (EARLY_I2C_BASE_ADDRESS + (0x2000 * (x)))
/*
* IO Port bases.
diff --git a/src/soc/intel/fsp_baytrail/lpss.c b/src/soc/intel/fsp_baytrail/lpss.c
index 154a70ad19..2ad6fb3804 100644
--- a/src/soc/intel/fsp_baytrail/lpss.c
+++ b/src/soc/intel/fsp_baytrail/lpss.c
@@ -89,20 +89,6 @@ static void dev_ctl_reg(struct device *dev, int *iosf_reg, int *nvs_index)
switch (dev->path.pci.devfn) {
SET_IOSF_REG(SIO_DMA1);
break;
- SET_IOSF_REG(I2C1);
- break;
- SET_IOSF_REG(I2C2);
- break;
- SET_IOSF_REG(I2C3);
- break;
- SET_IOSF_REG(I2C4);
- break;
- SET_IOSF_REG(I2C5);
- break;
- SET_IOSF_REG(I2C6);
- break;
- SET_IOSF_REG(I2C7);
- break;
SET_IOSF_REG(SIO_DMA2);
break;
SET_IOSF_REG(PWM1);
@@ -118,33 +104,6 @@ static void dev_ctl_reg(struct device *dev, int *iosf_reg, int *nvs_index)
}
}
-static void i2c_disable_resets(struct device *dev)
-{
- /* Release the I2C devices from reset. */
- static const struct reg_script ops[] = {
- REG_RES_WRITE32(PCI_BASE_ADDRESS_0, 0x804, 0x3),
- REG_SCRIPT_END,
- };
-
-#define CASE_I2C(name_) \
- case PCI_DEVFN(name_ ## _DEV, name_ ## _FUNC)
-
- switch (dev->path.pci.devfn) {
- CASE_I2C(I2C1):
- CASE_I2C(I2C2):
- CASE_I2C(I2C3):
- CASE_I2C(I2C4):
- CASE_I2C(I2C5):
- CASE_I2C(I2C6):
- CASE_I2C(I2C7):
- printk(BIOS_DEBUG, "Releasing I2C device from reset.\n");
- reg_script_run_on_dev(dev, ops);
- break;
- default:
- return;
- }
-}
-
static void lpss_init(struct device *dev)
{
struct soc_intel_fsp_baytrail_config *config = config_of(dev);
@@ -160,7 +119,6 @@ static void lpss_init(struct device *dev)
return;
}
dev_enable_snoop_and_pm(dev, iosf_reg);
- i2c_disable_resets(dev);
if (config->PcdLpssSioEnablePciMode == LPSS_PCI_MODE_DISABLE)
dev_enable_acpi_mode(dev, iosf_reg, nvs_index);
@@ -178,13 +136,6 @@ static struct device_operations device_ops = {
static const unsigned short pci_device_ids[] = {
SIO_DMA1_DEVID,
- I2C1_DEVID,
- I2C2_DEVID,
- I2C3_DEVID,
- I2C4_DEVID,
- I2C5_DEVID,
- I2C6_DEVID,
- I2C7_DEVID,
SIO_DMA2_DEVID,
PWM1_DEVID,
PWM2_DEVID,