diff --git a/src/mainboard/siemens/mc_tcu3/mainboard.c b/src/mainboard/siemens/mc_tcu3/mainboard.c index 9e12aa588fb..e77c0b1e296 100644 --- a/src/mainboard/siemens/mc_tcu3/mainboard.c +++ b/src/mainboard/siemens/mc_tcu3/mainboard.c @@ -69,10 +69,16 @@ enum cb_err mainboard_get_mac_address(struct device *dev, uint8_t mac[6]) * This is the earliest point to add customization. */ 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 414baeb089b..56f51f96474 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 #include #include - +#include #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 072df295a50..efe12da4802 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 fa719320ee3..0d89832f7da 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 b73aa149043..e3167885b21 100644 --- a/src/soc/intel/fsp_baytrail/chip.h +++ b/src/soc/intel/fsp_baytrail/chip.h @@ -20,6 +20,7 @@ #include #include +#include /* 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 5f6ca467ea4..37ce2d0b211 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 -#include +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include -/* 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 f0ae0b37ad3..3a4ff2c32b9 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 -#include - -/* 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 11c01e311d4..d54d3fcc294 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 154a70ad197..2ad6fb3804f 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,