Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15521
-gerrit
commit 0df10ca9f1b2bd3de43f46c62121194865a1acbc
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Thu Jun 30 14:37:37 2016 -0700
acpi_device: Have acpi_device_scope() use a separate buffer
Have the different acpi_device_ path functions use a different static
buffer so they can be called interchangeably.
Change-Id: I270a80f66880861d5847bd586a16a73f8f1e2511
Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org>
---
src/arch/x86/acpi_device.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/arch/x86/acpi_device.c b/src/arch/x86/acpi_device.c
index 69d44f3..1f0ab37 100644
--- a/src/arch/x86/acpi_device.c
+++ b/src/arch/x86/acpi_device.c
@@ -121,10 +121,15 @@ const char *acpi_device_path(struct device *dev)
/* Return the path of the parent device as the ACPI Scope for this device */
const char *acpi_device_scope(struct device *dev)
{
+ static char buf[DEVICE_PATH_MAX] = {};
+
if (!dev || !dev->bus || !dev->bus->dev)
return NULL;
- return acpi_device_path(dev->bus->dev);
+ if (acpi_device_path_fill(dev->bus->dev, buf, sizeof(buf), 0) <= 0)
+ return NULL;
+
+ return buf;
}
/* Concatentate the device path and provided name suffix */
the following patch was just integrated into master:
commit be87f73c68a81b48aec0d651a8bde52aa37f3690
Author: Furquan Shaikh <furquan(a)google.com>
Date: Wed Jun 29 11:26:27 2016 -0700
vbnv: Do not initialize vbnv_copy in vbnv layer
If read_vbnv finds that the vbnv_copy is not valid, it initializes it
with the correct HEADER_SIGNATURE and other attributes. However, the
vbnv copy is checked for validity and initialized at the vboot layer as
well. Since, vboot is the owner of this data, it should be the one
initializing it. Thus, if read_vbnv sees that the data is not valid,
simply reset it to all 0s and let vboot layer take care of it. This also
removes the need for additional checks to ensure that the dirty vbnv
copy is properly updated on storage.
Change-Id: I6101ac41f31f720a6e357c9c56e571d62e0f2f47
Signed-off-by: Furquan Shaikh <furquan(a)google.com>
Reviewed-on: https://review.coreboot.org/15498
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
Reviewed-by: Julius Werner <jwerner(a)chromium.org>
See https://review.coreboot.org/15498 for details.
-gerrit
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15520
-gerrit
commit c726d92dedca057db79e1863372764e62bf2b035
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Thu Jun 30 09:34:24 2016 -0700
soc/intel/skylake: Add function for gpio_t to ACPI pin translation
Add the function defined in gpio.h to translate a gpio_t into a
value for use in an ACPI GPIO pin table.
For skylake this just returns the gpio_t value as the pins are
translated directly and they are all in the same ACPI device.
Change-Id: I00fad1cafec2f2d63dce9f7779063be0532649c7
Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org>
---
src/soc/intel/skylake/gpio.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/soc/intel/skylake/gpio.c b/src/soc/intel/skylake/gpio.c
index 78495c6..5b9babf 100644
--- a/src/soc/intel/skylake/gpio.c
+++ b/src/soc/intel/skylake/gpio.c
@@ -408,3 +408,8 @@ const char *gpio_acpi_path(gpio_t gpio_num)
{
return "\\_SB.PCI0.GPIO";
}
+
+uint16_t gpio_acpi_pin(gpio_t gpio_num)
+{
+ return gpio_num;
+}
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15512
-gerrit
commit 0a37a380949d588bdc8a2b31d7f2e67c0aafbef0
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Wed Jun 29 10:47:22 2016 -0700
gpio: Add support for translating gpio_t into ACPI pin
Add a function for an SOC to define that will allow it to map the
SOC-specific gpio_t value into an appropriate ACPI pin. The exact
behavior depends on the GPIO implementation in the SOC, but it can
be used to provide a pin number that is relative to the community or
bank that a GPIO resides in.
Change-Id: Icb97ccf7d6a9034877614d49166bc9e4fe659bcf
Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org>
---
src/arch/x86/acpi_device.c | 9 +++++++--
src/include/gpio.h | 10 ++++++++++
src/lib/gpio.c | 6 ++++++
3 files changed, 23 insertions(+), 2 deletions(-)
diff --git a/src/arch/x86/acpi_device.c b/src/arch/x86/acpi_device.c
index 69d44f3..940d871 100644
--- a/src/arch/x86/acpi_device.c
+++ b/src/arch/x86/acpi_device.c
@@ -314,8 +314,13 @@ void acpi_device_write_gpio(const struct acpi_gpio *gpio)
acpi_device_fill_from_len(pin_table_offset, start);
/* Pin Table, one word for each pin */
- for (pin = 0; pin < gpio->pin_count; pin++)
- acpigen_emit_word(gpio->pins[pin]);
+ for (pin = 0; pin < gpio->pin_count; pin++) {
+ uint16_t acpi_pin = gpio->pins[pin];
+#if IS_ENABLED(CONFIG_GENERIC_GPIO_LIB)
+ acpi_pin = gpio_acpi_pin(acpi_pin);
+#endif
+ acpigen_emit_word(acpi_pin);
+ }
/* Fill in Resource Source Name Offset */
acpi_device_fill_from_len(resource_offset, start);
diff --git a/src/include/gpio.h b/src/include/gpio.h
index 3f462df..69a0828 100644
--- a/src/include/gpio.h
+++ b/src/include/gpio.h
@@ -41,6 +41,16 @@ int _gpio_base3_value(gpio_t gpio[], int num_gpio, int binary_first);
const char *gpio_acpi_path(gpio_t gpio);
/*
+ * This function may be implemented by SoC/board code to provide
+ * a mapping from the internal representation of a GPIO to the 16bit
+ * value used in an ACPI GPIO pin table entry.
+ *
+ * If not implemented by the SOC the default handler will return 0
+ * because the underlying type of gpio_t is unknown.
+ */
+uint16_t gpio_acpi_pin(gpio_t gpio);
+
+/*
* Read the value presented by the set of GPIOs, when each pin is interpreted
* as a base-2 digit (LOW = 0, HIGH = 1).
*
diff --git a/src/lib/gpio.c b/src/lib/gpio.c
index b0a5f4d..81d6f6b 100644
--- a/src/lib/gpio.c
+++ b/src/lib/gpio.c
@@ -145,3 +145,9 @@ __attribute__((weak)) const char *gpio_acpi_path(gpio_t gpio)
{
return NULL;
}
+
+/* Default handler returns 0 because type of gpio_t is unknown */
+__attribute__((weak)) uint16_t gpio_acpi_pin(gpio_t gpio)
+{
+ return 0;
+}
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15513
-gerrit
commit c3e2fbef77e90f6a459e638f21ed9bba8f14b4ad
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Wed Jun 29 10:47:48 2016 -0700
soc/intel/apollolake: Add function to translate gpio_t into ACPI pin
There are four GPIO communities in this SOC and they are implemented
as separate ACPI devices. This means the pin number that is used in
an ACPI GPIO declaration needs to be relative to the community that
the pin resides in. Also select GENERIC_GPIO_LIB in the SOC Kconfig
so this function actually gets used.
This was tested on the reef mainboard by verifying the output of the
SSDT for the Maxim 98357A codec that the assigned GPIO_76 is listed
as pin 0x24 which is the value relative to the Northwest community.
Change-Id: Iad2ab8eccf4c91185a075ffce8d41c81f06c1113
Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org>
---
src/soc/intel/apollolake/Kconfig | 1 +
src/soc/intel/apollolake/gpio.c | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/src/soc/intel/apollolake/Kconfig b/src/soc/intel/apollolake/Kconfig
index 749c15b..8fd2967 100644
--- a/src/soc/intel/apollolake/Kconfig
+++ b/src/soc/intel/apollolake/Kconfig
@@ -21,6 +21,7 @@ config CPU_SPECIFIC_OPTIONS
select C_ENVIRONMENT_BOOTBLOCK
select COLLECT_TIMESTAMPS
select COMMON_FADT
+ select GENERIC_GPIO_LIB
select HAVE_INTEL_FIRMWARE
select HAVE_SMI_HANDLER
select MMCONF_SUPPORT
diff --git a/src/soc/intel/apollolake/gpio.c b/src/soc/intel/apollolake/gpio.c
index d0ef648..ac0d83b 100644
--- a/src/soc/intel/apollolake/gpio.c
+++ b/src/soc/intel/apollolake/gpio.c
@@ -132,3 +132,21 @@ const char *gpio_acpi_path(gpio_t gpio_num)
return NULL;
}
+
+uint16_t gpio_acpi_pin(gpio_t gpio_num)
+{
+ const struct pad_community *comm = gpio_get_community(gpio_num);
+
+ switch (comm->port) {
+ case GPIO_NORTH:
+ return PAD_N(gpio_num);
+ case GPIO_NORTHWEST:
+ return PAD_NW(gpio_num);
+ case GPIO_WEST:
+ return PAD_W(gpio_num);
+ case GPIO_SOUTHWEST:
+ return PAD_SW(gpio_num);
+ }
+
+ return gpio_num;
+}
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15514
-gerrit
commit 8691a16ba90f0544b14fce2a9728d8fb510d1d0f
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Wed Jun 29 22:34:01 2016 -0700
drivers/generic/max98357a: Fix naming and ACPI path handling
The upstream kernel driver is not using the of-style naming for
sdmode-gpio so remove the maxim prefix, and remove the duplicate
entry for the sdmode-delay value as well.
Also fix the usage of the path variable, since the device path uses
a static variable it can't be assigned that early or it will be
overwritten by later calls.
This results in the following output for the _DSD when tested on
reef mainboard:
Name (_DSD, Package (0x02)
{
ToUUID ("daffd814-6eba-4d8c-8a91-bc9bbf4aa301")
Package (0x02)
{
Package (0x02)
{
"sdmode-gpio",
Package (0x04)
{
\_SB.PCI0.HDAS.MAXM,
Zero,
Zero,
Zero
}
},
Package (0x02)
{
"sdmode-delay",
Zero
}
}
})
Change-Id: Iab33182a5f64c89151966f5e79f4f7c30840c46f
Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org>
---
src/drivers/generic/max98357a/max98357a.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/src/drivers/generic/max98357a/max98357a.c b/src/drivers/generic/max98357a/max98357a.c
index cbd7efd..0d522d4 100644
--- a/src/drivers/generic/max98357a/max98357a.c
+++ b/src/drivers/generic/max98357a/max98357a.c
@@ -31,9 +31,9 @@
static void max98357a_fill_ssdt(struct device *dev)
{
struct drivers_generic_max98357a_config *config = dev->chip_info;
- const char *path = acpi_device_path(dev);
+ const char *path;
- if (!dev->enabled || !path || !config)
+ if (!dev->enabled || !config)
return;
/* Device */
@@ -53,10 +53,8 @@ static void max98357a_fill_ssdt(struct device *dev)
/* _DSD for devicetree properties */
acpi_dp_write_header();
/* This points to the first pin in the first gpio entry in _CRS */
- acpi_dp_write_gpio("maxim,sdmode-gpio", path, 0, 0, 0);
- /* This is the correctly formatted Device Property name */
- acpi_dp_write_integer("maxim,sdmode-delay", config->sdmode_delay);
- /* This is used by the chromium kernel but is not upstream */
+ path = acpi_device_path(dev);
+ acpi_dp_write_gpio("sdmode-gpio", path, 0, 0, 0);
acpi_dp_write_integer("sdmode-delay", config->sdmode_delay);
acpi_dp_write_footer();
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15481
-gerrit
commit cab49758d4b161081d3b3b56855a295be0cce3d7
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Mon Jun 27 11:05:16 2016 -0700
google/reef: ACPI: Move touchpad to SSDT and remove TPM
Instantiate the touchpad using the drivers/i2c/generic device driver
to generate the ACPI object in the SSDT.
There is not currently a separate wake pin for this device, this will
be added in EVT hardware.
This was tested on the reef board by ensuring that the touchpad device
continues to work in the OS.
Also remove the LPC TPM from the DSDT as it is not present.
Change-Id: I3151a28f628e66f63033398d6fab9fd8f5dfc37b
Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org>
---
src/mainboard/google/reef/Kconfig | 3 ++
src/mainboard/google/reef/acpi/mainboard.asl | 48 +---------------------------
src/mainboard/google/reef/devicetree.cb | 9 +++++-
3 files changed, 12 insertions(+), 48 deletions(-)
diff --git a/src/mainboard/google/reef/Kconfig b/src/mainboard/google/reef/Kconfig
index d64598d..c271f78 100644
--- a/src/mainboard/google/reef/Kconfig
+++ b/src/mainboard/google/reef/Kconfig
@@ -25,6 +25,9 @@ config CHROMEOS
select VBOOT_OPROM_MATTERS
select VIRTUAL_DEV_SWITCH
+config DRIVERS_I2C_GENERIC
+ default y
+
config MAINBOARD_DIR
string
default google/reef
diff --git a/src/mainboard/google/reef/acpi/mainboard.asl b/src/mainboard/google/reef/acpi/mainboard.asl
index 5471488..5b6e976 100644
--- a/src/mainboard/google/reef/acpi/mainboard.asl
+++ b/src/mainboard/google/reef/acpi/mainboard.asl
@@ -33,54 +33,8 @@ Scope (\_SB)
}
}
-Scope (\_SB.PCI0.I2C4)
-{
- /* Standard Mode: HCNT, LCNT, SDA Hold Register */
- /* SDA Hold register value of 40 indicates
- * sda hold time of 0.3us for ic_clk of 133MHz
- */
- Name (SSCN, Package () { 0, 0, 40 })
-
- /* Fast Mode: HCNT, LCNT, SDA Hold Register */
- /* SDA Hold register value of 40 indicates
- * sda hold time of 0.3us for ic_clk of 133MHz
- */
- Name (FMCN, Package () { 0, 0, 40 })
-
- Device (ETPA)
- {
- Name (_HID, "ELAN0000")
- Name (_DDN, "Elan Touchpad")
- Name (_UID, 1)
- Name (ISTP, 1) /* Touchpad */
-
- Name (_CRS, ResourceTemplate()
- {
- I2cSerialBus (
- 0x15, // SlaveAddress
- ControllerInitiated, // SlaveMode
- 400000, // ConnectionSpeed
- AddressingMode7Bit, // AddressingMode
- "\\_SB.PCI0.I2C4", // ResourceSource
- )
- Interrupt (ResourceConsumer, Edge, ActiveLow)
- {
- TOUCHPAD_INT
- }
- })
-
- Method (_STA)
- {
- Return (0xF)
- }
- }
-}
-
-/*
- * LPC Trusted Platform Module
- */
Scope (\_SB.PCI0.LPCB)
{
- #include <drivers/pc80/tpm/acpi/tpm.asl>
+ /* Chrome OS Embedded Controller */
#include "ec.asl"
}
diff --git a/src/mainboard/google/reef/devicetree.cb b/src/mainboard/google/reef/devicetree.cb
index d2b295f..e0831f4 100644
--- a/src/mainboard/google/reef/devicetree.cb
+++ b/src/mainboard/google/reef/devicetree.cb
@@ -61,7 +61,14 @@ chip soc/intel/apollolake
device pci 16.1 on end # - I2C 1
device pci 16.2 on end # - I2C 2
device pci 16.3 on end # - I2C 3
- device pci 17.0 on end # - I2C 4
+ device pci 17.0 on
+ chip drivers/i2c/generic
+ register "hid" = ""ELAN0000""
+ register "desc" = ""ELAN Touchpad""
+ register "irq" = "IRQ_EDGE_LOW(GPIO_18_IRQ)"
+ device i2c 15 on end
+ end
+ end # - I2C 4
device pci 17.1 on end # - I2C 5
device pci 17.2 on end # - I2C 6
device pci 17.3 on end # - I2C 7
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/15480
-gerrit
commit 9f05b482405ce7c57f17a089b1fb3ad38e59b934
Author: Duncan Laurie <dlaurie(a)chromium.org>
Date: Mon Jun 27 10:57:13 2016 -0700
soc/intel/apollolake: Add support for LPSS I2C driver
Support the I2C interfaces on this SOC using the Intel common lpss_i2c
driver. The controllers are supported in pre-ram environments by
setting a temporary base address in bootblock and in ramstage using
the naturally enumerated base address.
The base speed of this controller is 133MHz and the SCL/SDA timing
values that are reported to the OS are calculated using that clock.
This was tested on a google/reef board doing I2C transactions to the
trackpad both in verstage and in ramstage.
Change-Id: I0a9d62cd1007caa95cdf4754f30c30aaff9f78f9
Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org>
---
src/soc/intel/apollolake/Kconfig | 8 +-
src/soc/intel/apollolake/Makefile.inc | 3 +
src/soc/intel/apollolake/chip.h | 17 +++
src/soc/intel/apollolake/i2c.c | 154 +++++++++++++++++++++++++++
src/soc/intel/apollolake/i2c_early.c | 116 ++++++++++++++++++++
src/soc/intel/apollolake/include/soc/i2c.h | 50 +++++++++
src/soc/intel/apollolake/include/soc/iomap.h | 5 +-
7 files changed, 351 insertions(+), 2 deletions(-)
diff --git a/src/soc/intel/apollolake/Kconfig b/src/soc/intel/apollolake/Kconfig
index 98ce7d8..749c15b 100644
--- a/src/soc/intel/apollolake/Kconfig
+++ b/src/soc/intel/apollolake/Kconfig
@@ -38,8 +38,9 @@ config CPU_SPECIFIC_OPTIONS
select RELOCATABLE_RAMSTAGE # Build fails if this is not selected
select SMM_TSEG
select SOC_INTEL_COMMON
- select SOC_INTEL_COMMON_SMI
select SOC_INTEL_COMMON_ACPI
+ select SOC_INTEL_COMMON_LPSS_I2C
+ select SOC_INTEL_COMMON_SMI
select SPI_FLASH
select UDELAY_TSC
select TSC_CONSTANT_RATE
@@ -93,6 +94,11 @@ config CPU_ADDR_BITS
int
default 36
+config SOC_INTEL_COMMON_LPSS_I2C_CLOCK_MHZ
+ depends on SOC_INTEL_COMMON_LPSS_I2C
+ int
+ default 133
+
config CONSOLE_UART_BASE_ADDRESS
depends on CONSOLE_SERIAL
hex "MMIO base address for UART"
diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc
index 7326f14..c639eec 100644
--- a/src/soc/intel/apollolake/Makefile.inc
+++ b/src/soc/intel/apollolake/Makefile.inc
@@ -23,6 +23,7 @@ bootblock-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
romstage-y += car.c
romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += romstage.c
romstage-y += gpio.c
+romstage-y += i2c_early.c
romstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
romstage-y += lpc_lib.c
romstage-y += memmap.c
@@ -45,6 +46,7 @@ ramstage-y += cpu.c
ramstage-y += chip.c
ramstage-y += gpio.c
ramstage-y += graphics.c
+ramstage-y += i2c.c
ramstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
ramstage-y += lpc.c
ramstage-y += lpc_lib.c
@@ -68,6 +70,7 @@ postcar-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
postcar-y += tsc_freq.c
verstage-y += car.c
+verstage-y += i2c_early.c
verstage-y += memmap.c
verstage-y += mmap_boot.c
verstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
diff --git a/src/soc/intel/apollolake/chip.h b/src/soc/intel/apollolake/chip.h
index ef82c53..c83f973 100644
--- a/src/soc/intel/apollolake/chip.h
+++ b/src/soc/intel/apollolake/chip.h
@@ -18,7 +18,21 @@
#ifndef _SOC_APOLLOLAKE_CHIP_H_
#define _SOC_APOLLOLAKE_CHIP_H_
+#include <soc/gpio.h>
+#include <soc/intel/common/lpss_i2c.h>
+#include <device/i2c.h>
+
#define CLKREQ_DISABLED 0xf
+#define APOLLOLAKE_I2C_DEV_MAX 8
+
+struct apollolake_i2c_config {
+ /* Bus should be enabled prior to ramstage with temporary base */
+ int early_init;
+ /* Bus speed in Hz, default is I2C_SPEED_FAST (400 KHz) */
+ enum i2c_speed speed;
+ /* Specific bus speed configuration */
+ struct lpss_i2c_speed_config speed_config[LPSS_I2C_SPEED_CONFIG_COUNT];
+};
/* Serial IRQ control. SERIRQ_QUIET is the default (0). */
enum serirq_mode {
@@ -79,6 +93,9 @@ struct soc_intel_apollolake_config {
/* Integrated Sensor Hub */
uint8_t integrated_sensor_hub_enable;
+
+ /* I2C bus configuration */
+ struct apollolake_i2c_config i2c[APOLLOLAKE_I2C_DEV_MAX];
};
#endif /* _SOC_APOLLOLAKE_CHIP_H_ */
diff --git a/src/soc/intel/apollolake/i2c.c b/src/soc/intel/apollolake/i2c.c
new file mode 100644
index 0000000..78f8911
--- /dev/null
+++ b/src/soc/intel/apollolake/i2c.c
@@ -0,0 +1,154 @@
+/*
+ * 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/acpi_device.h>
+#include <arch/acpigen.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 <soc/pci_devs.h>
+#include <soc/pci_ids.h>
+#include <string.h>
+#include "chip.h"
+
+uintptr_t lpss_i2c_base_address(unsigned bus)
+{
+ unsigned 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;
+ }
+ }
+
+ return (uintptr_t)NULL;
+}
+
+static int i2c_dev_to_bus(struct device *dev)
+{
+ return i2c_devfn_to_bus(dev->path.pci.devfn);
+}
+
+/*
+ * 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)
+{
+ struct soc_intel_apollolake_config *config = dev->chip_info;
+ const struct lpss_i2c_speed_config *sptr;
+ enum i2c_speed speed;
+ int i, bus = i2c_dev_to_bus(dev);
+
+ if (!config || bus < 0)
+ return;
+
+ speed = config->i2c[bus].speed ? : I2C_SPEED_FAST;
+ lpss_i2c_init(bus, speed);
+
+ /* Apply custom speed config if it has been set by the board */
+ for (i = 0; i < LPSS_I2C_SPEED_CONFIG_COUNT; i++) {
+ sptr = &config->i2c[bus].speed_config[i];
+ if (sptr->speed == speed) {
+ lpss_i2c_set_speed_config(bus, sptr);
+ break;
+ }
+ }
+}
+
+static void i2c_fill_ssdt(struct device *dev)
+{
+ struct soc_intel_apollolake_config *config = dev->chip_info;
+ struct lpss_i2c_speed_config *sptr, sgen;
+ int i, bus = i2c_dev_to_bus(dev);
+ enum i2c_speed speeds[LPSS_I2C_SPEED_CONFIG_COUNT] = {
+ I2C_SPEED_STANDARD,
+ I2C_SPEED_FAST,
+ I2C_SPEED_FAST_PLUS,
+ I2C_SPEED_HIGH,
+ };
+
+ if (!config || bus < 0)
+ return;
+
+ /* I2C device is defined in the DSDT so use existing device scope */
+ 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 for default case */
+ if (lpss_i2c_gen_speed_config(speeds[i], &sgen) < 0)
+ continue;
+
+ /* Apply board specific override for this speed if found */
+ for (sptr = config->i2c[bus].speed_config;
+ sptr && sptr->speed; sptr++) {
+ if (sptr->speed == speeds[i]) {
+ memcpy(&sgen, sptr, sizeof(sgen));
+ break;
+ }
+ }
+
+ /* 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 = &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/i2c_early.c b/src/soc/intel/apollolake/i2c_early.c
new file mode 100644
index 0000000..968e993
--- /dev/null
+++ b/src/soc/intel/apollolake/i2c_early.c
@@ -0,0 +1,116 @@
+/*
+ * 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 <console/console.h>
+#include <device/device.h>
+#include <device/i2c.h>
+#include <device/pci_def.h>
+#include <soc/intel/common/lpss_i2c.h>
+#include <soc/i2c.h>
+#include <soc/iomap.h>
+#include <soc/pci_devs.h>
+#include "chip.h"
+
+static int i2c_early_init_bus(unsigned bus)
+{
+ ROMSTAGE_CONST struct soc_intel_apollolake_config *config;
+ ROMSTAGE_CONST struct device *tree_dev;
+ const struct lpss_i2c_speed_config *sptr;
+ enum i2c_speed speed;
+ pci_devfn_t dev;
+ unsigned devfn;
+ uintptr_t base;
+ uint32_t value;
+ void *reg;
+
+ /* Find the PCI device for this bus controller */
+ devfn = i2c_bus_to_devfn(bus);
+ if (devfn < 0) {
+ 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 = tree_dev->chip_info;
+ if (!config || !config->i2c[bus].early_init) {
+ printk(BIOS_ERR, "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);
+ pci_write_config32(dev, PCI_BASE_ADDRESS_0, base);
+ pci_write_config32(dev, PCI_COMMAND,
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+
+ /* Take device out of reset */
+ reg = (void *)(base + I2C_LPSS_REG_RESET);
+ value = read32(reg);
+ value |= I2C_LPSS_RESET_RELEASE_HC;
+ write32(reg, value);
+
+ /* Initialize the controller */
+ speed = config->i2c[bus].speed ? : I2C_SPEED_FAST;
+ if (lpss_i2c_init(bus, speed) < 0) {
+ printk(BIOS_ERR, "I2C%u failed to initialize\n", bus);
+ return -1;
+ }
+
+ /* Apply custom speed config if it has been set by the board */
+ for (value = 0; value < LPSS_I2C_SPEED_CONFIG_COUNT; value++) {
+ sptr = &config->i2c[bus].speed_config[value];
+ if (sptr->speed == speed) {
+ lpss_i2c_set_speed_config(bus, sptr);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+uintptr_t lpss_i2c_base_address(unsigned bus)
+{
+ unsigned devfn;
+ pci_devfn_t dev;
+ uintptr_t base;
+
+ /* Find device+function for this controller */
+ devfn = i2c_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 && !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/apollolake/include/soc/i2c.h b/src/soc/intel/apollolake/include/soc/i2c.h
new file mode 100644
index 0000000..da700f2
--- /dev/null
+++ b/src/soc/intel/apollolake/include/soc/i2c.h
@@ -0,0 +1,50 @@
+/*
+ * 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>
+
+/* I2C Controller Reset in MMIO private region */
+#define I2C_LPSS_REG_RESET 0x204
+#define I2C_LPSS_RESET_RELEASE_HC ((1 << 1) | (1 << 0))
+#define I2C_LPSS_RESET_RELEASE_IDMA (1 << 2)
+
+/* Convert I2C bus number to PCI device and function */
+static inline int i2c_bus_to_devfn(unsigned bus)
+{
+ if (bus >= 0 && bus <= 3)
+ return PCI_DEVFN(LPSS_DEV_SLOT_I2C_D0, bus);
+ else if (bus >= 4 && bus <= 7)
+ return PCI_DEVFN(LPSS_DEV_SLOT_I2C_D1, (bus - 4));
+ else
+ return -1;
+}
+
+/* Convert PCI device and function to I2C bus number */
+static inline int i2c_devfn_to_bus(unsigned devfn)
+{
+ if (PCI_SLOT(devfn) == LPSS_DEV_SLOT_I2C_D0)
+ return PCI_FUNC(devfn);
+ else if (PCI_SLOT(devfn) == LPSS_DEV_SLOT_I2C_D1)
+ return PCI_FUNC(devfn) + 4;
+ else
+ return -1;
+}
+
+#endif /* _SOC_APOLLOLAKE_I2C_H_ */
diff --git a/src/soc/intel/apollolake/include/soc/iomap.h b/src/soc/intel/apollolake/include/soc/iomap.h
index 716c2a6..e9caeca 100644
--- a/src/soc/intel/apollolake/include/soc/iomap.h
+++ b/src/soc/intel/apollolake/include/soc/iomap.h
@@ -31,6 +31,9 @@
#define PMC_BAR1 0xfe044000
/* Temporary BAR for SPI until PCI enumeration assigns a BAR in ramstage. */
-#define PRERAM_SPI_BASE_ADDRESS 0xfe010000
+#define PRERAM_SPI_BASE_ADDRESS 0xfe010000
+
+/* Temporary BAR for early I2C bus access */
+#define PRERAM_I2C_BASE_ADDRESS(x) (0xfe020000 + (0x1000 * (x)))
#endif /* _SOC_APOLLOLAKE_IOMAP_H_ */