From ff8bce0a5f53652d4d26cb501159e8711f79eb9b Mon Sep 17 00:00:00 2001 From: Duncan Laurie Date: Mon, 27 Jun 2016 10:57:13 -0700 Subject: 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 Reviewed-on: https://review.coreboot.org/15480 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin --- src/soc/intel/apollolake/i2c.c | 126 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/soc/intel/apollolake/i2c.c (limited to 'src/soc/intel/apollolake/i2c.c') diff --git a/src/soc/intel/apollolake/i2c.c b/src/soc/intel/apollolake/i2c.c new file mode 100644 index 0000000000..1c16a06058 --- /dev/null +++ b/src/soc/intel/apollolake/i2c.c @@ -0,0 +1,126 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; + int bus = i2c_dev_to_bus(dev); + + if (!config || bus < 0) + return; + + acpigen_write_scope(acpi_device_path(dev)); + lpss_i2c_acpi_fill_ssdt(config->i2c[bus].speed_config); + 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, +}; -- cgit v1.2.3