mail.coreboot.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2024
November
October
September
August
July
June
May
April
March
February
January
2023
December
November
October
September
August
July
June
May
April
March
February
January
2022
December
November
October
September
August
July
June
May
April
March
February
January
2021
December
November
October
September
August
July
June
May
April
March
February
January
2020
December
November
October
September
August
July
June
May
April
March
February
January
2019
December
November
October
September
August
July
June
May
April
March
February
January
2018
December
November
October
September
August
July
June
May
April
March
February
January
2017
December
November
October
September
August
July
June
May
April
March
February
January
2016
December
November
October
September
August
July
June
May
April
March
February
January
2015
December
November
October
September
August
July
June
May
April
March
February
January
2014
December
November
October
September
August
July
June
May
April
March
February
January
2013
December
November
October
September
August
July
June
May
April
March
List overview
Download
coreboot-gerrit
September 2016
----- 2024 -----
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
----- 2021 -----
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
----- 2020 -----
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
----- 2019 -----
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
----- 2018 -----
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
----- 2017 -----
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
----- 2016 -----
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
----- 2015 -----
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
----- 2014 -----
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
----- 2013 -----
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
coreboot-gerrit@coreboot.org
1 participants
1340 discussions
Start a n
N
ew thread
Patch set updated for coreboot: drivers/i2c/tpm: Add support for cr50 TPM
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16396
-gerrit commit 7e555db4ce69be8e3bc3d71ac4e8be68fdee6e0e Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Thu Sep 1 15:50:22 2016 -0700 drivers/i2c/tpm: Add support for cr50 TPM Add support for the cr50 TPM used in apollolake chromebooks. This requires custom handling due to chip limitations, which may be revisited but are needed to get things working today. - timeouts need to be longer - must use the older style write+wait+read read protocol - all 4 bytes of status register must be read at once - same limitation applies when reading burst count from status reg - burst count max is 63 bytes, and burst count behaves slightly differently than other I2C TPMs - TPM expects the host to drain the full burst count (63 bytes) from the FIFO on a read Luckily the existing driver provides most abstraction needed to make this work seamlessly. To maximize code re-use the support for cr50 is added directly instead of as a separate driver and the style is kept similar to the rest of the driver code. This was tested with the cr50 TPM on a reef board with vboot use of TPM for secdata storage and factory initialization. Change-Id: I9b0bc282e41e779da8bf9184be0a11649735a101 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/drivers/i2c/tpm/tpm.c | 202 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 191 insertions(+), 11 deletions(-) diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c index 0534c63..60d1127 100644 --- a/src/drivers/i2c/tpm/tpm.c +++ b/src/drivers/i2c/tpm/tpm.c @@ -36,11 +36,15 @@ #include <console/console.h> #include <device/i2c.h> #include <endian.h> +#include <timer.h> #include "tpm.h" /* max. number of iterations after I2C NAK */ #define MAX_COUNT 3 +/* cr50 max burst count */ +#define CR50_MAX_BURSTCOUNT 63 + #define SLEEP_DURATION 60 /* in usec */ #define SLEEP_DURATION_LONG 210 /* in usec */ #define SLEEP_DURATION_SAFE 750 /* in usec */ @@ -55,16 +59,19 @@ /* expected value for DIDVID register */ #define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L #define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L +#define TPM_TIS_I2C_DID_VID_CR50 0x00281ae0L enum i2c_chip_type { SLB9635, SLB9645, + CR50, UNKNOWN, }; static const char * const chip_name[] = { [SLB9635] = "slb9635tt", [SLB9645] = "slb9645tt", + [CR50] = "cr50", [UNKNOWN] = "unknown/fallback to slb9635", }; @@ -102,8 +109,11 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) if (tpm_dev->addr == 0) return -1; - if ((tpm_dev->chip_type == SLB9635) || - (tpm_dev->chip_type == UNKNOWN)) { + + switch (tpm_dev->chip_type) { + case SLB9635: + case CR50: + case UNKNOWN: /* slb9635 protocol should work in both cases */ for (count = 0; count < MAX_COUNT; count++) { rc = i2c_write_raw(tpm_dev->bus, tpm_dev->addr, @@ -129,7 +139,10 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) break; /* success, break to skip sleep */ } - } else { + break; + + default: + { /* use a combined read for newer chips * unfortunately the smbus functions are not suitable due to * the 32 byte limit of the smbus. @@ -148,6 +161,7 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) udelay(tpm_dev->sleep_short); } } + } /* take care of 'guard time' */ udelay(tpm_dev->sleep_short); @@ -483,6 +497,162 @@ out_err: return -1; } +/* + * cr50 is a TPM 2.0 capable device that requries special + * handling for the I2C interface. + */ + +/* cr50 requires all 4 bytes of status register to be read */ +static uint8_t cr50_tis_i2c_status(struct tpm_chip *chip) +{ + uint8_t buf[4]; + if (iic_tpm_read(TPM_STS(chip->vendor.locality), buf, sizeof(buf)) < 0) + return 0; + return buf[0]; +} + +/* cr50 requires all 4 bytes of status register to be written */ +static void cr50_tis_i2c_ready(struct tpm_chip *chip) +{ + uint8_t buf[4] = { TPM_STS_COMMAND_READY }; + iic_tpm_write_long(TPM_STS(chip->vendor.locality), buf, sizeof(buf)); +} + +/* cr50 uses bytes 3:2 of status register for burst count and + * all 4 bytes must be read */ +static ssize_t cr50_get_burstcount(struct tpm_chip *chip) +{ + uint8_t buf[4]; + ssize_t burstcnt; + struct stopwatch sw; + + stopwatch_init_usecs_expire(&sw, 10 * SLEEP_DURATION_SAFE); + + while (!stopwatch_expired(&sw)) { + if (iic_tpm_read(TPM_STS(chip->vendor.locality), + buf, sizeof(buf)) != 0) + return -1; + + burstcnt = (buf[2] << 8) + buf[1]; + if (burstcnt > 0 && burstcnt <= CR50_MAX_BURSTCOUNT) + return burstcnt; + + udelay(SLEEP_DURATION_SAFE); + } + + return -1; +} + +static int cr50_tis_i2c_recv(struct tpm_chip *chip, uint8_t *buf, + size_t buf_len) +{ + uint32_t expected_buf; + ssize_t burstcnt; + size_t current, len, expected; + int status; + uint8_t addr = TPM_DATA_FIFO(chip->vendor.locality); + uint8_t extra[CR50_MAX_BURSTCOUNT]; + + if (buf_len < TPM_HEADER_SIZE) + goto out; + + burstcnt = cr50_get_burstcount(chip); + if (burstcnt <= 0 || burstcnt > buf_len) + goto out; + + /* Read first chunk of burstcnt bytes */ + if (iic_tpm_read(addr, buf, burstcnt) != 0) + goto out; + + memcpy(&expected_buf, buf + TPM_RSP_SIZE_BYTE, sizeof(expected_buf)); + expected = (size_t)be32_to_cpu(expected_buf); + if (expected > buf_len) + goto out; + + /* Now read the rest of the data */ + current = burstcnt; + while (current < expected) { + len = min(burstcnt, expected - current); + + if (iic_tpm_read(addr, buf + current, len) != 0) + goto out; + + current += len; + } + + /* cr50 expects the host to drain the FIFO */ + len = current % burstcnt; + if (len && iic_tpm_read(addr, extra, len) != 0) + goto out; + + wait_for_stat(chip, TPM_STS_VALID, &status); + if (status & TPM_STS_DATA_AVAIL) { + printk(BIOS_ERR, "TPM: Data Still Available\n"); + goto out; + } + + cr50_tis_i2c_ready(chip); + return current; + +out: + printk(BIOS_ERR, "%s failed\n", __func__); + cr50_tis_i2c_ready(chip); + return -1; +} + +static int cr50_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len) +{ + int status; + ssize_t burstcnt; + size_t sent = 0; + uint8_t tpm_go[4] = { TPM_STS_GO }; + + if (len > TPM_BUFSIZE) + return -1; + + /* Wait until TPM is ready for a command */ + status = chip->vendor.status(chip); + if ((status & TPM_STS_COMMAND_READY) == 0) { + cr50_tis_i2c_ready(chip); + if (wait_for_stat(chip, TPM_STS_COMMAND_READY, &status) < 0) { + printk(BIOS_ERR, "TPM: Command Ready Timeout\n"); + goto out; + } + } + + /* Get the burst count */ + burstcnt = cr50_get_burstcount(chip); + if (burstcnt < 0) + goto out; + + while (len > 0) { + ssize_t limit = min(burstcnt - 1, len); + + if (iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), + &(buf[sent]), limit) != 0) + goto out; + + sent += limit; + len -= limit; + } + + /* Ensure TPM is not expecting more data */ + wait_for_stat(chip, TPM_STS_VALID, &status); + if ((status & TPM_STS_DATA_EXPECT) != 0) { + printk(BIOS_ERR, "TPM: Data Still Expected\n"); + goto out; + } + + /* Start the TPM command */ + iic_tpm_write(TPM_STS(chip->vendor.locality), tpm_go, sizeof(tpm_go)); + return sent; + +out: + printk(BIOS_ERR, "%s failed\n", __func__); + cr50_tis_i2c_ready(chip); + return -1; +} + /* Initialization of I2C TPM */ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) @@ -505,10 +675,6 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) memset(&chip->vendor, 0, sizeof(struct tpm_vendor_specific)); chip->is_open = 1; - chip->vendor.status = &tpm_tis_i2c_status; - chip->vendor.recv = &tpm_tis_i2c_recv; - chip->vendor.send = &tpm_tis_i2c_send; - chip->vendor.cancel = &tpm_tis_i2c_ready; chip->vendor.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; chip->vendor.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID; chip->vendor.req_canceled = TPM_STS_COMMAND_READY; @@ -527,16 +693,30 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) tpm_dev->chip_type = SLB9645; } else if (be32_to_cpu(vendor) == TPM_TIS_I2C_DID_VID_9635) { tpm_dev->chip_type = SLB9635; + } else if (vendor == TPM_TIS_I2C_DID_VID_CR50) { + tpm_dev->chip_type = CR50; } else { printk(BIOS_DEBUG, "Vendor ID 0x%08x not recognized.\n", vendor); goto out_err; } - tpm_dev->sleep_short = SLEEP_DURATION; - tpm_dev->sleep_long = SLEEP_DURATION_LONG; + if (tpm_dev->chip_type == CR50) { + chip->vendor.status = &cr50_tis_i2c_status; + chip->vendor.recv = &cr50_tis_i2c_recv; + chip->vendor.send = &cr50_tis_i2c_send; + chip->vendor.cancel = &cr50_tis_i2c_ready; + } else { + tpm_dev->sleep_short = SLEEP_DURATION; + tpm_dev->sleep_long = SLEEP_DURATION_LONG; + chip->vendor.status = &tpm_tis_i2c_status; + chip->vendor.recv = &tpm_tis_i2c_recv; + chip->vendor.send = &tpm_tis_i2c_send; + chip->vendor.cancel = &tpm_tis_i2c_ready; + } - printk(BIOS_DEBUG, "1.2 TPM (chip type %s device-id 0x%X)\n", - chip_name[tpm_dev->chip_type], vendor >> 16); + printk(BIOS_DEBUG, "I2C TPM %u:%02x (chip type %s device-id 0x%X)\n", + tpm_dev->bus, tpm_dev->addr, + chip_name[tpm_dev->chip_type], vendor >> 16); /* * A timeout query to TPM can be placed here.
1
0
0
0
Patch set updated for coreboot: drivers/i2c/tpm: Allow sleep durations to be set by the chip
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16395
-gerrit commit 103a15c8b3c93c7a22dedcccf5b471e51ceb3280 Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Wed Aug 31 14:48:12 2016 -0700 drivers/i2c/tpm: Allow sleep durations to be set by the chip Allow the sleep durations used by the driver to be set by the specific chip so they can be tuned appropriately. Since we need to read the chip id to know the values use very conservative defaults for the first command and then set it to the current values by default. Change-Id: Ic64159328b18a1471eb06fa8b52b589eec1e1ca2 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/drivers/i2c/tpm/tpm.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c index ead99f1..e3a6b50 100644 --- a/src/drivers/i2c/tpm/tpm.c +++ b/src/drivers/i2c/tpm/tpm.c @@ -42,6 +42,8 @@ #define MAX_COUNT 3 #define SLEEP_DURATION 60 /* in usec */ +#define SLEEP_DURATION_LONG 210 /* in usec */ +#define SLEEP_DURATION_SAFE 750 /* in usec */ /* max. number of iterations after I2C NAK for 'long' commands * we need this especially for sending TPM_READY, since the cleanup after the @@ -50,8 +52,6 @@ */ #define MAX_COUNT_LONG 50 -#define SLEEP_DURATION_LONG 210 /* in usec */ - /* expected value for DIDVID register */ #define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L #define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L @@ -72,6 +72,8 @@ static const char * const chip_name[] = { struct tpm_inf_dev { int bus; unsigned int addr; + unsigned int sleep_short; /* Short sleep duration in usec */ + unsigned int sleep_long; /* Long sleep duration in usec */ uint8_t buf[TPM_BUFSIZE + sizeof(uint8_t)]; // max. buffer size + addr enum i2c_chip_type chip_type; }; @@ -109,7 +111,7 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) if (rc == 0) break; /* success, break to skip sleep */ - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); } if (rc) @@ -120,7 +122,7 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) * retrieving the data */ for (count = 0; count < MAX_COUNT; count++) { - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); rc = i2c_read_raw(tpm_dev->bus, tpm_dev->addr, buffer, len); if (rc == 0) @@ -143,12 +145,12 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) i2c_transfer(tpm_dev->bus, &dseg, 1); if (rc == 0) break; /* break here to skip sleep */ - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); } } /* take care of 'guard time' */ - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); if (rc) return -1; @@ -184,7 +186,7 @@ static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, } /* take care of 'guard time' */ - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); if (rc) return -1; @@ -209,7 +211,8 @@ static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, */ static int iic_tpm_write(uint8_t addr, uint8_t *buffer, size_t len) { - return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION, + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); + return iic_tpm_write_generic(addr, buffer, len, tpm_dev->sleep_short, MAX_COUNT); } @@ -219,7 +222,8 @@ static int iic_tpm_write(uint8_t addr, uint8_t *buffer, size_t len) * */ static int iic_tpm_write_long(uint8_t addr, uint8_t *buffer, size_t len) { - return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG, + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); + return iic_tpm_write_generic(addr, buffer, len, tpm_dev->sleep_long, MAX_COUNT_LONG); } @@ -492,6 +496,10 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) tpm_dev->addr = dev_addr; tpm_dev->bus = bus; + /* Use conservative values to read chip id */ + tpm_dev->sleep_short = SLEEP_DURATION_SAFE; + tpm_dev->sleep_long = SLEEP_DURATION_SAFE * 2; + memset(&chip->vendor, 0, sizeof(struct tpm_vendor_specific)); chip->is_open = 1; @@ -522,6 +530,9 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) goto out_release; } + tpm_dev->sleep_short = SLEEP_DURATION; + tpm_dev->sleep_long = SLEEP_DURATION_LONG; + printk(BIOS_DEBUG, "1.2 TPM (chip type %s device-id 0x%X)\n", chip_name[tpm_dev->chip_type], vendor >> 16);
1
0
0
0
Patch set updated for coreboot: drivers/i2c/tpm: Make driver safe for use in x86 pre-ram
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16394
-gerrit commit 32ec21d07379be071fbad7f459bca7202e4e1663 Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Wed Aug 31 13:51:14 2016 -0700 drivers/i2c/tpm: Make driver safe for use in x86 pre-ram Use CAR accessors where needed for accessing static data. In some cases this required some minor restructuring to pass in a variable instead of use a global one. Tested by enabling I2C TPM on reef and compiling successfully. Change-Id: I8e02fbcebf5fe10c4122632eda1c48b247478289 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/drivers/i2c/tpm/tis.c | 24 +++++++------- src/drivers/i2c/tpm/tpm.c | 79 ++++++++++++++++++++++------------------------- src/drivers/i2c/tpm/tpm.h | 8 ++--- 3 files changed, 54 insertions(+), 57 deletions(-) diff --git a/src/drivers/i2c/tpm/tis.c b/src/drivers/i2c/tpm/tis.c index 0404109..c6173b4 100644 --- a/src/drivers/i2c/tpm/tis.c +++ b/src/drivers/i2c/tpm/tis.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include <arch/early_variables.h> #include <stdint.h> #include <string.h> #include <assert.h> @@ -26,7 +27,7 @@ #include <console/console.h> /* global structure for tpm chip data */ -struct tpm_chip g_chip; +static struct tpm_chip g_chip CAR_GLOBAL; #define TPM_CMD_COUNT_BYTE 2 #define TPM_CMD_ORDINAL_BYTE 6 @@ -34,18 +35,18 @@ struct tpm_chip g_chip; int tis_open(void) { + struct tpm_chip *chip = car_get_var_ptr(&g_chip); int rc; - if (g_chip.is_open) { + if (chip->is_open) { printk(BIOS_DEBUG, "tis_open() called twice.\n"); return -1; } - rc = tpm_vendor_init(CONFIG_DRIVER_TPM_I2C_BUS, - CONFIG_DRIVER_TPM_I2C_ADDR); - + rc = tpm_vendor_init(chip, CONFIG_DRIVER_TPM_I2C_BUS, + CONFIG_DRIVER_TPM_I2C_ADDR); if (rc < 0) - g_chip.is_open = 0; + chip->is_open = 0; if (rc) { return -1; @@ -56,9 +57,11 @@ int tis_open(void) int tis_close(void) { - if (g_chip.is_open) { - tpm_vendor_cleanup(&g_chip); - g_chip.is_open = 0; + struct tpm_chip *chip = car_get_var_ptr(&g_chip); + + if (chip->is_open) { + tpm_vendor_cleanup(chip); + chip->is_open = 0; } return 0; @@ -104,8 +107,7 @@ static ssize_t tpm_transmit(const uint8_t *buf, size_t bufsiz) { int rc; uint32_t count, ordinal; - - struct tpm_chip *chip = &g_chip; + struct tpm_chip *chip = car_get_var_ptr(&g_chip); memcpy(&count, buf + TPM_CMD_COUNT_BYTE, sizeof(count)); count = be32_to_cpu(count); diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c index 306005f..ead99f1 100644 --- a/src/drivers/i2c/tpm/tpm.c +++ b/src/drivers/i2c/tpm/tpm.c @@ -28,6 +28,7 @@ * GNU General Public License for more details. */ +#include <arch/early_variables.h> #include <stdint.h> #include <string.h> #include <types.h> @@ -37,9 +38,6 @@ #include <endian.h> #include "tpm.h" -/* Address of the TPM on the I2C bus */ -#define TPM_I2C_ADDR 0x20 - /* max. number of iterations after I2C NAK */ #define MAX_COUNT 3 @@ -78,10 +76,7 @@ struct tpm_inf_dev { enum i2c_chip_type chip_type; }; -static struct tpm_inf_dev tpm_dev = { - .bus = -1, - .addr = TPM_I2C_ADDR -}; +static struct tpm_inf_dev g_tpm_dev CAR_GLOBAL; /* * iic_tpm_read() - read from TPM register @@ -99,15 +94,18 @@ static struct tpm_inf_dev tpm_dev = { */ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) { + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); int rc; int count; - if (tpm_dev.bus < 0) + if (tpm_dev->addr == 0) return -1; - if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) { + if ((tpm_dev->chip_type == SLB9635) || + (tpm_dev->chip_type == UNKNOWN)) { /* slb9635 protocol should work in both cases */ for (count = 0; count < MAX_COUNT; count++) { - rc = i2c_write_raw(tpm_dev.bus, tpm_dev.addr, &addr, 1); + rc = i2c_write_raw(tpm_dev->bus, tpm_dev->addr, + &addr, 1); if (rc == 0) break; /* success, break to skip sleep */ @@ -123,7 +121,7 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) */ for (count = 0; count < MAX_COUNT; count++) { udelay(SLEEP_DURATION); - rc = i2c_read_raw(tpm_dev.bus, tpm_dev.addr, + rc = i2c_read_raw(tpm_dev->bus, tpm_dev->addr, buffer, len); if (rc == 0) break; /* success, break to skip sleep */ @@ -136,13 +134,13 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) * retries should usually not be needed, but are kept just to * be safe on the safe side. */ - struct i2c_seg aseg = { .read = 0, .chip = tpm_dev.addr, + struct i2c_seg aseg = { .read = 0, .chip = tpm_dev->addr, .buf = &addr, .len = 1 }; - struct i2c_seg dseg = { .read = 1, .chip = tpm_dev.addr, + struct i2c_seg dseg = { .read = 1, .chip = tpm_dev->addr, .buf = buffer, .len = len }; for (count = 0; count < MAX_COUNT; count++) { - rc = i2c_transfer(tpm_dev.bus, &aseg, 1) || - i2c_transfer(tpm_dev.bus, &dseg, 1); + rc = i2c_transfer(tpm_dev->bus, &aseg, 1) || + i2c_transfer(tpm_dev->bus, &dseg, 1); if (rc == 0) break; /* break here to skip sleep */ udelay(SLEEP_DURATION); @@ -161,6 +159,7 @@ static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, unsigned int sleep_time, uint8_t max_count) { + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); int rc = 0; int count; @@ -170,14 +169,14 @@ static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, } /* prepare send buffer */ - tpm_dev.buf[0] = addr; - memcpy(&(tpm_dev.buf[1]), buffer, len); + tpm_dev->buf[0] = addr; + memcpy(&(tpm_dev->buf[1]), buffer, len); - if (tpm_dev.bus < 0) + if (tpm_dev->addr == 0) return -1; for (count = 0; count < max_count; count++) { - rc = i2c_write_raw(tpm_dev.bus, tpm_dev.addr, - tpm_dev.buf, len + 1); + rc = i2c_write_raw(tpm_dev->bus, tpm_dev->addr, + tpm_dev->buf, len + 1); if (rc == 0) break; /* success, break to skip sleep */ @@ -480,34 +479,30 @@ out_err: return -1; } -static struct tpm_vendor_specific tpm_tis_i2c = { - .status = tpm_tis_i2c_status, - .recv = tpm_tis_i2c_recv, - .send = tpm_tis_i2c_send, - .cancel = tpm_tis_i2c_ready, - .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_canceled = TPM_STS_COMMAND_READY, -}; - /* Initialization of I2C TPM */ -int tpm_vendor_init(unsigned bus, uint32_t dev_addr) +int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) { + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); uint32_t vendor; unsigned int old_addr; - struct tpm_chip *chip; - extern struct tpm_chip g_chip; - old_addr = tpm_dev.addr; + old_addr = tpm_dev->addr; if (dev_addr != 0) - tpm_dev.addr = dev_addr; - tpm_dev.bus = bus; + tpm_dev->addr = dev_addr; + tpm_dev->bus = bus; - chip = &g_chip; - memcpy(&chip->vendor, &tpm_tis_i2c, sizeof(struct tpm_vendor_specific)); + memset(&chip->vendor, 0, sizeof(struct tpm_vendor_specific)); chip->is_open = 1; + chip->vendor.status = &tpm_tis_i2c_status; + chip->vendor.recv = &tpm_tis_i2c_recv; + chip->vendor.send = &tpm_tis_i2c_send; + chip->vendor.cancel = &tpm_tis_i2c_ready; + chip->vendor.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; + chip->vendor.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID; + chip->vendor.req_canceled = TPM_STS_COMMAND_READY; + /* Disable interrupts (not supported) */ chip->vendor.irq = 0; @@ -519,16 +514,16 @@ int tpm_vendor_init(unsigned bus, uint32_t dev_addr) goto out_release; if (vendor == TPM_TIS_I2C_DID_VID_9645) { - tpm_dev.chip_type = SLB9645; + tpm_dev->chip_type = SLB9645; } else if (be32_to_cpu(vendor) == TPM_TIS_I2C_DID_VID_9635) { - tpm_dev.chip_type = SLB9635; + tpm_dev->chip_type = SLB9635; } else { printk(BIOS_DEBUG, "Vendor ID 0x%08x not recognized.\n", vendor); goto out_release; } printk(BIOS_DEBUG, "1.2 TPM (chip type %s device-id 0x%X)\n", - chip_name[tpm_dev.chip_type], vendor >> 16); + chip_name[tpm_dev->chip_type], vendor >> 16); /* * A timeout query to TPM can be placed here. @@ -541,7 +536,7 @@ out_release: release_locality(chip, 0, 1); out_err: - tpm_dev.addr = old_addr; + tpm_dev->addr = old_addr; return -1; } diff --git a/src/drivers/i2c/tpm/tpm.h b/src/drivers/i2c/tpm/tpm.h index 625679d..7dfd594 100644 --- a/src/drivers/i2c/tpm/tpm.h +++ b/src/drivers/i2c/tpm/tpm.h @@ -47,9 +47,9 @@ enum tpm_timeout { struct tpm_chip; struct tpm_vendor_specific { - const uint8_t req_complete_mask; - const uint8_t req_complete_val; - const uint8_t req_canceled; + uint8_t req_complete_mask; + uint8_t req_complete_val; + uint8_t req_canceled; int irq; int (*recv)(struct tpm_chip *, uint8_t *, size_t); int (*send)(struct tpm_chip *, uint8_t *, size_t); @@ -121,7 +121,7 @@ struct tpm_cmd_t { /* ---------- Interface for TPM vendor ------------ */ -int tpm_vendor_init(unsigned bus, uint32_t dev_addr); +int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr); void tpm_vendor_cleanup(struct tpm_chip *chip);
1
0
0
0
Patch set updated for coreboot: google/reef: Fix indent in devicetree.cb
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16399
-gerrit commit ec6b53bff88679ec0ebfccf680fcd4d8a24c6278 Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Thu Sep 1 16:00:39 2016 -0700 google/reef: Fix indent in devicetree.cb Indent the I2C device for touchscreen with tabs so it aligns properly. Change-Id: Id9b2d26a4acdd6fe6c69055907258df3cc035b31 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/mainboard/google/reef/devicetree.cb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mainboard/google/reef/devicetree.cb b/src/mainboard/google/reef/devicetree.cb index ac69406..9a7c2d1 100644 --- a/src/mainboard/google/reef/devicetree.cb +++ b/src/mainboard/google/reef/devicetree.cb @@ -108,10 +108,10 @@ chip soc/intel/apollolake end # - I2C 2 device pci 16.3 on chip drivers/i2c/generic - register "hid" = ""ELAN0001"" - register "desc" = ""ELAN Touchscreen"" - register "irq" = "IRQ_EDGE_LOW(GPIO_21_IRQ)" - device i2c 10 on end + register "hid" = ""ELAN0001"" + register "desc" = ""ELAN Touchscreen"" + register "irq" = "IRQ_EDGE_LOW(GPIO_21_IRQ)" + device i2c 10 on end end end # - I2C 3 device pci 17.0 on
1
0
0
0
Patch set updated for coreboot: google/reef: Enable I2C TPM
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16398
-gerrit commit ed8a22546618718190ca8d661bd53bd13827a635 Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Thu Sep 1 16:00:05 2016 -0700 google/reef: Enable I2C TPM Enable the I2C based TPM on the reef board at bus 2 and address 0x50. This makes vboot functional without needing MOCK_TPM and results in the following in the SSDT: Device (TPMI) { Name (_HID, "GOOG0005") // _HID: Hardware ID Name (_UID, Zero) // _UID: Unique ID Name (_DDN, "I2C TPM") // _DDN: DOS Device Name Method (_STA, 0, NotSerialized) // _STA: Status { Return (0x0F) } Name (_CRS, ResourceTemplate () // _CRS: Current Resource Settings { I2cSerialBus (0x0050, ControllerInitiated, 0x00061A80, AddressingMode7Bit, "\\_SB.PCI0.I2C2", 0x00, ResourceConsumer) Interrupt (ResourceConsumer, Edge, ActiveLow, Exclusive) { 0x00000039 } }) } Change-Id: Ia9775caabeac3e6a3bd72de38f9611b4cea7cea4 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/mainboard/google/reef/Kconfig | 10 +++++++++- src/mainboard/google/reef/devicetree.cb | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/mainboard/google/reef/Kconfig b/src/mainboard/google/reef/Kconfig index 0464e2d..08a5c6a 100644 --- a/src/mainboard/google/reef/Kconfig +++ b/src/mainboard/google/reef/Kconfig @@ -9,8 +9,16 @@ config BOARD_SPECIFIC_OPTIONS select HAVE_ACPI_RESUME select HAVE_ACPI_TABLES select MAINBOARD_HAS_CHROMEOS - select MAINBOARD_HAS_LPC_TPM + select MAINBOARD_HAS_TPM2 select SYSTEM_TYPE_LAPTOP + select TPM2 + select I2C_TPM + +config DRIVER_TPM_I2C_BUS + hex "0x2" + +config DRIVER_TPM_I2C_ADDR + hex "0x50" config CHROMEOS select LID_SWITCH diff --git a/src/mainboard/google/reef/devicetree.cb b/src/mainboard/google/reef/devicetree.cb index 4d08fae..ac69406 100644 --- a/src/mainboard/google/reef/devicetree.cb +++ b/src/mainboard/google/reef/devicetree.cb @@ -99,7 +99,13 @@ chip soc/intel/apollolake end end device pci 16.1 on end # - I2C 1 - device pci 16.2 on end # - I2C 2 + device pci 16.2 on + chip drivers/i2c/tpm + register "hid" = ""GOOG0005"" + register "irq" = "IRQ_EDGE_LOW(GPIO_28_IRQ)" + device i2c 50 on end + end + end # - I2C 2 device pci 16.3 on chip drivers/i2c/generic register "hid" = ""ELAN0001""
1
0
0
0
Patch set updated for coreboot: drivers/i2c/tpm: Add support for generating ACPI table
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16397
-gerrit commit 58257f4f9567fbec9efea3525054a04774688caf Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Thu Sep 1 15:56:44 2016 -0700 drivers/i2c/tpm: Add support for generating ACPI table Add code to generate an ACPI descriptor for an I2C TPM based on the device as described in devicetree.cb. This currently requires the devicetree to provide the HID, since we don't currently talk to the TPM in ramstage and I didn't want to add yet another init path for it here. This was tested on a reef board to ensure that the device is described properly in the SSDT. Change-Id: I43d7f6192f48e99a4074baa4e52f0a9ee554a250 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/drivers/i2c/tpm/Kconfig | 5 +++ src/drivers/i2c/tpm/Makefile.inc | 2 + src/drivers/i2c/tpm/chip.c | 89 ++++++++++++++++++++++++++++++++++++++++ src/drivers/i2c/tpm/chip.h | 10 +++++ 4 files changed, 106 insertions(+) diff --git a/src/drivers/i2c/tpm/Kconfig b/src/drivers/i2c/tpm/Kconfig index 594ffd5..903fc3b 100644 --- a/src/drivers/i2c/tpm/Kconfig +++ b/src/drivers/i2c/tpm/Kconfig @@ -11,3 +11,8 @@ config DRIVER_TPM_I2C_ADDR hex "I2C TPM chip address" default 2 # FIXME, workaround for Kconfig BS depends on I2C_TPM + +config DRIVER_I2C_TPM_ACPI + bool "Generate I2C TPM ACPI device" + default y if ARCH_X86 && I2C_TPM + default n diff --git a/src/drivers/i2c/tpm/Makefile.inc b/src/drivers/i2c/tpm/Makefile.inc index 4f5913f..0efe34a 100644 --- a/src/drivers/i2c/tpm/Makefile.inc +++ b/src/drivers/i2c/tpm/Makefile.inc @@ -2,3 +2,5 @@ ramstage-$(CONFIG_I2C_TPM) += tis.c tpm.c romstage-$(CONFIG_I2C_TPM) += tis.c tpm.c verstage-$(CONFIG_I2C_TPM) += tis.c tpm.c bootblock-$(CONFIG_I2C_TPM) += tis.c tpm.c + +ramstage-$(CONFIG_DRIVERS_I2C_TPM_ACPI) += chip.c diff --git a/src/drivers/i2c/tpm/chip.c b/src/drivers/i2c/tpm/chip.c new file mode 100644 index 0000000..1781e99 --- /dev/null +++ b/src/drivers/i2c/tpm/chip.c @@ -0,0 +1,89 @@ +/* + * 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 <console/console.h> +#include <device/i2c.h> +#include <device/device.h> +#include <device/path.h> +#include <stdint.h> +#include <string.h> +#include "tpm.h" +#include "chip.h" + +static void i2c_tpm_fill_ssdt(struct device *dev) +{ + struct drivers_i2c_tpm_config *config = dev->chip_info; + const char *scope = acpi_device_scope(dev); + struct acpi_i2c i2c = { + .address = dev->path.i2c.device, + .mode_10bit = dev->path.i2c.mode_10bit, + .speed = config->speed ? : I2C_SPEED_FAST, + .resource = scope, + }; + + if (!dev->enabled || !scope) + return; + + if (!config->hid) { + printk(BIOS_ERR, "%s: ERROR: HID required\n", dev_path(dev)); + return; + } + + /* Device */ + acpigen_write_scope(scope); + acpigen_write_device(acpi_device_name(dev)); + acpigen_write_name_string("_HID", config->hid); + acpigen_write_name_integer("_UID", config->uid); + acpigen_write_name_string("_DDN", dev->chip_ops->name); + acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON); + + /* Resources */ + acpigen_write_name("_CRS"); + acpigen_write_resourcetemplate_header(); + acpi_device_write_i2c(&i2c); + acpi_device_write_interrupt(&config->irq); + acpigen_write_resourcetemplate_footer(); + + acpigen_pop_len(); /* Device */ + acpigen_pop_len(); /* Scope */ + + printk(BIOS_INFO, "%s: %s at %s\n", acpi_device_path(dev), + dev->chip_ops->name, dev_path(dev)); +} + +static const char *i2c_tpm_acpi_name(struct device *dev) +{ + return "TPMI"; +} + +static struct device_operations i2c_tpm_ops = { + .read_resources = DEVICE_NOOP, + .set_resources = DEVICE_NOOP, + .enable_resources = DEVICE_NOOP, + .acpi_name = &i2c_tpm_acpi_name, + .acpi_fill_ssdt_generator = &i2c_tpm_fill_ssdt, +}; + +static void i2c_tpm_enable(struct device *dev) +{ + dev->ops = &i2c_tpm_ops; +} + +struct chip_operations drivers_i2c_tpm_ops = { + CHIP_NAME("I2C TPM") + .enable_dev = &i2c_tpm_enable +}; diff --git a/src/drivers/i2c/tpm/chip.h b/src/drivers/i2c/tpm/chip.h new file mode 100644 index 0000000..14103c7 --- /dev/null +++ b/src/drivers/i2c/tpm/chip.h @@ -0,0 +1,10 @@ +#include <arch/acpi_device.h> +#include <device/i2c.h> + +struct drivers_i2c_tpm_config { + const char *hid; /* ACPI _HID (required) */ + const char *desc; /* Device Description */ + unsigned uid; /* ACPI _UID */ + enum i2c_speed speed; /* Bus speed in Hz, default is I2C_SPEED_FAST */ + struct acpi_irq irq; /* Interrupt */ +};
1
0
0
0
Patch set updated for coreboot: drivers/i2c/tpm: Add support for cr50 TPM
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16396
-gerrit commit 50392285d54b693d7242a6bb2795e6d71ccb4407 Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Thu Sep 1 15:50:22 2016 -0700 drivers/i2c/tpm: Add support for cr50 TPM Add support for the cr50 TPM used in apollolake chromebooks. This requires custom handling due to chip limitations, which may be revisited but are needed to get things working today. - timeouts need to be longer - must use the older style write+wait+read read protocol - all 4 bytes of status register must be read at once - same limitation applies when reading burst count from status reg - burst count max is 63 bytes, and burst count behaves slightly differently than other I2C TPMs - TPM expects the host to drain the full burst count (63 bytes) from the FIFO on a read Luckily the existing driver provides most abstraction needed to make this work seamlessly. To maximize code re-use the support for cr50 is added directly instead of as a separate driver and the style is kept similar to the rest of the driver code. This was tested with the cr50 TPM on a reef board with vboot use of TPM for secdata storage and factory initialization. Change-Id: I9b0bc282e41e779da8bf9184be0a11649735a101 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/drivers/i2c/tpm/tpm.c | 202 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 191 insertions(+), 11 deletions(-) diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c index e3a6b50..34c00aa 100644 --- a/src/drivers/i2c/tpm/tpm.c +++ b/src/drivers/i2c/tpm/tpm.c @@ -36,11 +36,15 @@ #include <console/console.h> #include <device/i2c.h> #include <endian.h> +#include <timer.h> #include "tpm.h" /* max. number of iterations after I2C NAK */ #define MAX_COUNT 3 +/* cr50 max burst count */ +#define CR50_MAX_BURSTCOUNT 63 + #define SLEEP_DURATION 60 /* in usec */ #define SLEEP_DURATION_LONG 210 /* in usec */ #define SLEEP_DURATION_SAFE 750 /* in usec */ @@ -55,16 +59,19 @@ /* expected value for DIDVID register */ #define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L #define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L +#define TPM_TIS_I2C_DID_VID_CR50 0x00281ae0L enum i2c_chip_type { SLB9635, SLB9645, + CR50, UNKNOWN, }; static const char * const chip_name[] = { [SLB9635] = "slb9635tt", [SLB9645] = "slb9645tt", + [CR50] = "cr50", [UNKNOWN] = "unknown/fallback to slb9635", }; @@ -102,8 +109,11 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) if (tpm_dev->addr == 0) return -1; - if ((tpm_dev->chip_type == SLB9635) || - (tpm_dev->chip_type == UNKNOWN)) { + + switch (tpm_dev->chip_type) { + case SLB9635: + case CR50: + case UNKNOWN: /* slb9635 protocol should work in both cases */ for (count = 0; count < MAX_COUNT; count++) { rc = i2c_write_raw(tpm_dev->bus, tpm_dev->addr, @@ -129,7 +139,10 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) break; /* success, break to skip sleep */ } - } else { + break; + + default: + { /* use a combined read for newer chips * unfortunately the smbus functions are not suitable due to * the 32 byte limit of the smbus. @@ -148,6 +161,7 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) udelay(tpm_dev->sleep_short); } } + } /* take care of 'guard time' */ udelay(tpm_dev->sleep_short); @@ -483,6 +497,162 @@ out_err: return -1; } +/* + * cr50 is a TPM 2.0 capable device that requries special + * handling for the I2C interface. + */ + +/* cr50 requires all 4 bytes of status register to be read */ +static uint8_t cr50_tis_i2c_status(struct tpm_chip *chip) +{ + uint8_t buf[4]; + if (iic_tpm_read(TPM_STS(chip->vendor.locality), buf, sizeof(buf)) < 0) + return 0; + return buf[0]; +} + +/* cr50 requires all 4 bytes of status register to be written */ +static void cr50_tis_i2c_ready(struct tpm_chip *chip) +{ + uint8_t buf[4] = { TPM_STS_COMMAND_READY }; + iic_tpm_write_long(TPM_STS(chip->vendor.locality), buf, sizeof(buf)); +} + +/* cr50 uses bytes 3:2 of status register for burst count and + * all 4 bytes must be read */ +static ssize_t cr50_get_burstcount(struct tpm_chip *chip) +{ + uint8_t buf[4]; + ssize_t burstcnt; + struct stopwatch sw; + + stopwatch_init_usecs_expire(&sw, 10 * SLEEP_DURATION_SAFE); + + while (!stopwatch_expired(&sw)) { + if (iic_tpm_read(TPM_STS(chip->vendor.locality), + buf, sizeof(buf)) != 0) + return -1; + + burstcnt = (buf[2] << 8) + buf[1]; + if (burstcnt > 0 && burstcnt <= CR50_MAX_BURSTCOUNT) + return burstcnt; + + udelay(SLEEP_DURATION_SAFE); + } + + return -1; +} + +static int cr50_tis_i2c_recv(struct tpm_chip *chip, uint8_t *buf, + size_t buf_len) +{ + uint32_t expected_buf; + ssize_t burstcnt; + size_t current, len, expected; + int status; + uint8_t addr = TPM_DATA_FIFO(chip->vendor.locality); + uint8_t extra[CR50_MAX_BURSTCOUNT]; + + if (buf_len < TPM_HEADER_SIZE) + goto out; + + burstcnt = cr50_get_burstcount(chip); + if (burstcnt <= 0 || burstcnt > buf_len) + goto out; + + /* Read first chunk of burstcnt bytes */ + if (iic_tpm_read(addr, buf, burstcnt) != 0) + goto out; + + memcpy(&expected_buf, buf + TPM_RSP_SIZE_BYTE, sizeof(expected_buf)); + expected = (size_t)be32_to_cpu(expected_buf); + if (expected > buf_len) + goto out; + + /* Now read the rest of the data */ + current = burstcnt; + while (current < expected) { + len = min(burstcnt, expected - current); + + if (iic_tpm_read(addr, buf + current, len) != 0) + goto out; + + current += len; + } + + /* cr50 expects the host to drain the FIFO */ + len = current % burstcnt; + if (len && iic_tpm_read(addr, extra, len) != 0) + goto out; + + wait_for_stat(chip, TPM_STS_VALID, &status); + if (status & TPM_STS_DATA_AVAIL) { + printk(BIOS_ERR, "TPM: Data Still Available\n"); + goto out; + } + + cr50_tis_i2c_ready(chip); + return current; + +out: + printk(BIOS_ERR, "%s failed\n", __func__); + cr50_tis_i2c_ready(chip); + return -1; +} + +static int cr50_tis_i2c_send(struct tpm_chip *chip, uint8_t *buf, size_t len) +{ + int status; + ssize_t burstcnt; + size_t sent = 0; + uint8_t tpm_go[4] = { TPM_STS_GO }; + + if (len > TPM_BUFSIZE) + return -1; + + /* Wait until TPM is ready for a command */ + status = chip->vendor.status(chip); + if ((status & TPM_STS_COMMAND_READY) == 0) { + cr50_tis_i2c_ready(chip); + if (wait_for_stat(chip, TPM_STS_COMMAND_READY, &status) < 0) { + printk(BIOS_ERR, "TPM: Command Ready Timeout\n"); + goto out; + } + } + + /* Get the burst count */ + burstcnt = cr50_get_burstcount(chip); + if (burstcnt < 0) + goto out; + + while (len > 0) { + ssize_t limit = min(burstcnt - 1, len); + + if (iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), + &(buf[sent]), limit) != 0) + goto out; + + sent += limit; + len -= limit; + } + + /* Ensure TPM is not expecting more data */ + wait_for_stat(chip, TPM_STS_VALID, &status); + if ((status & TPM_STS_DATA_EXPECT) != 0) { + printk(BIOS_ERR, "TPM: Data Still Expected\n"); + goto out; + } + + /* Start the TPM command */ + iic_tpm_write(TPM_STS(chip->vendor.locality), tpm_go, sizeof(tpm_go)); + return sent; + +out: + printk(BIOS_ERR, "%s failed\n", __func__); + cr50_tis_i2c_ready(chip); + return -1; +} + /* Initialization of I2C TPM */ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) @@ -503,10 +673,6 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) memset(&chip->vendor, 0, sizeof(struct tpm_vendor_specific)); chip->is_open = 1; - chip->vendor.status = &tpm_tis_i2c_status; - chip->vendor.recv = &tpm_tis_i2c_recv; - chip->vendor.send = &tpm_tis_i2c_send; - chip->vendor.cancel = &tpm_tis_i2c_ready; chip->vendor.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; chip->vendor.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID; chip->vendor.req_canceled = TPM_STS_COMMAND_READY; @@ -525,16 +691,30 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) tpm_dev->chip_type = SLB9645; } else if (be32_to_cpu(vendor) == TPM_TIS_I2C_DID_VID_9635) { tpm_dev->chip_type = SLB9635; + } else if (vendor == TPM_TIS_I2C_DID_VID_CR50) { + tpm_dev->chip_type = CR50; } else { printk(BIOS_DEBUG, "Vendor ID 0x%08x not recognized.\n", vendor); goto out_release; } - tpm_dev->sleep_short = SLEEP_DURATION; - tpm_dev->sleep_long = SLEEP_DURATION_LONG; + if (tpm_dev->chip_type == CR50) { + chip->vendor.status = &cr50_tis_i2c_status; + chip->vendor.recv = &cr50_tis_i2c_recv; + chip->vendor.send = &cr50_tis_i2c_send; + chip->vendor.cancel = &cr50_tis_i2c_ready; + } else { + tpm_dev->sleep_short = SLEEP_DURATION; + tpm_dev->sleep_long = SLEEP_DURATION_LONG; + chip->vendor.status = &tpm_tis_i2c_status; + chip->vendor.recv = &tpm_tis_i2c_recv; + chip->vendor.send = &tpm_tis_i2c_send; + chip->vendor.cancel = &tpm_tis_i2c_ready; + } - printk(BIOS_DEBUG, "1.2 TPM (chip type %s device-id 0x%X)\n", - chip_name[tpm_dev->chip_type], vendor >> 16); + printk(BIOS_DEBUG, "I2C TPM %u:%02x (chip type %s device-id 0x%X)\n", + tpm_dev->bus, tpm_dev->addr, + chip_name[tpm_dev->chip_type], vendor >> 16); /* * A timeout query to TPM can be placed here.
1
0
0
0
Patch set updated for coreboot: drivers/i2c/tpm: Allow sleep durations to be set by the chip
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16395
-gerrit commit f7071df777a7e4e83b2059aac22f236f1dc42a13 Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Wed Aug 31 14:48:12 2016 -0700 drivers/i2c/tpm: Allow sleep durations to be set by the chip Allow the sleep durations used by the driver to be set by the specific chip so they can be tuned appropriately. Since we need to read the chip id to know the values use very conservative defaults for the first command and then set it to the current values by default. Change-Id: Ic64159328b18a1471eb06fa8b52b589eec1e1ca2 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/drivers/i2c/tpm/tpm.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c index c62ab69..7f871a7 100644 --- a/src/drivers/i2c/tpm/tpm.c +++ b/src/drivers/i2c/tpm/tpm.c @@ -45,6 +45,8 @@ #define MAX_COUNT 3 #define SLEEP_DURATION 60 /* in usec */ +#define SLEEP_DURATION_LONG 210 /* in usec */ +#define SLEEP_DURATION_SAFE 750 /* in usec */ /* max. number of iterations after I2C NAK for 'long' commands * we need this especially for sending TPM_READY, since the cleanup after the @@ -53,8 +55,6 @@ */ #define MAX_COUNT_LONG 50 -#define SLEEP_DURATION_LONG 210 /* in usec */ - /* expected value for DIDVID register */ #define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L #define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L @@ -75,6 +75,8 @@ static const char * const chip_name[] = { struct tpm_inf_dev { int bus; unsigned int addr; + unsigned int sleep_short; /* Short sleep duration in usec */ + unsigned int sleep_long; /* Long sleep duration in usec */ uint8_t buf[TPM_BUFSIZE + sizeof(uint8_t)]; // max. buffer size + addr enum i2c_chip_type chip_type; }; @@ -112,7 +114,7 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) if (rc == 0) break; /* success, break to skip sleep */ - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); } if (rc) @@ -123,7 +125,7 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) * retrieving the data */ for (count = 0; count < MAX_COUNT; count++) { - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); rc = i2c_read_raw(tpm_dev->bus, tpm_dev->addr, buffer, len); if (rc == 0) @@ -146,12 +148,12 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) i2c_transfer(tpm_dev->bus, &dseg, 1); if (rc == 0) break; /* break here to skip sleep */ - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); } } /* take care of 'guard time' */ - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); if (rc) return -1; @@ -187,7 +189,7 @@ static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, } /* take care of 'guard time' */ - udelay(SLEEP_DURATION); + udelay(tpm_dev->sleep_short); if (rc) return -1; @@ -212,7 +214,8 @@ static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, */ static int iic_tpm_write(uint8_t addr, uint8_t *buffer, size_t len) { - return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION, + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); + return iic_tpm_write_generic(addr, buffer, len, tpm_dev->sleep_short, MAX_COUNT); } @@ -222,7 +225,8 @@ static int iic_tpm_write(uint8_t addr, uint8_t *buffer, size_t len) * */ static int iic_tpm_write_long(uint8_t addr, uint8_t *buffer, size_t len) { - return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG, + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); + return iic_tpm_write_generic(addr, buffer, len, tpm_dev->sleep_long, MAX_COUNT_LONG); } @@ -495,6 +499,10 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) tpm_dev->addr = dev_addr; tpm_dev->bus = bus; + /* Use conservative values to read chip id */ + tpm_dev->sleep_short = SLEEP_DURATION_SAFE; + tpm_dev->sleep_long = SLEEP_DURATION_SAFE * 2; + memset(&chip->vendor, 0, sizeof(struct tpm_vendor_specific)); chip->is_open = 1; @@ -525,6 +533,9 @@ int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) goto out_release; } + tpm_dev->sleep_short = SLEEP_DURATION; + tpm_dev->sleep_long = SLEEP_DURATION_LONG; + printk(BIOS_DEBUG, "1.2 TPM (chip type %s device-id 0x%X)\n", chip_name[tpm_dev->chip_type], vendor >> 16);
1
0
0
0
Patch set updated for coreboot: drivers/i2c/tpm: Make driver safe for use in x86 pre-ram
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16394
-gerrit commit 89d95fde8c507a243d21ae21d02b5b86a6b50d62 Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Wed Aug 31 13:51:14 2016 -0700 drivers/i2c/tpm: Make driver safe for use in x86 pre-ram Use CAR accessors where needed for accessing static data. In some cases this required some minor restructuring to pass in a variable instead of use a global one. Tested by enabling I2C TPM on reef and compiling successfully. Change-Id: I8e02fbcebf5fe10c4122632eda1c48b247478289 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/drivers/i2c/tpm/tis.c | 24 ++++++++------- src/drivers/i2c/tpm/tpm.c | 76 +++++++++++++++++++++++------------------------ src/drivers/i2c/tpm/tpm.h | 8 ++--- 3 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/drivers/i2c/tpm/tis.c b/src/drivers/i2c/tpm/tis.c index 0404109..c6173b4 100644 --- a/src/drivers/i2c/tpm/tis.c +++ b/src/drivers/i2c/tpm/tis.c @@ -13,6 +13,7 @@ * GNU General Public License for more details. */ +#include <arch/early_variables.h> #include <stdint.h> #include <string.h> #include <assert.h> @@ -26,7 +27,7 @@ #include <console/console.h> /* global structure for tpm chip data */ -struct tpm_chip g_chip; +static struct tpm_chip g_chip CAR_GLOBAL; #define TPM_CMD_COUNT_BYTE 2 #define TPM_CMD_ORDINAL_BYTE 6 @@ -34,18 +35,18 @@ struct tpm_chip g_chip; int tis_open(void) { + struct tpm_chip *chip = car_get_var_ptr(&g_chip); int rc; - if (g_chip.is_open) { + if (chip->is_open) { printk(BIOS_DEBUG, "tis_open() called twice.\n"); return -1; } - rc = tpm_vendor_init(CONFIG_DRIVER_TPM_I2C_BUS, - CONFIG_DRIVER_TPM_I2C_ADDR); - + rc = tpm_vendor_init(chip, CONFIG_DRIVER_TPM_I2C_BUS, + CONFIG_DRIVER_TPM_I2C_ADDR); if (rc < 0) - g_chip.is_open = 0; + chip->is_open = 0; if (rc) { return -1; @@ -56,9 +57,11 @@ int tis_open(void) int tis_close(void) { - if (g_chip.is_open) { - tpm_vendor_cleanup(&g_chip); - g_chip.is_open = 0; + struct tpm_chip *chip = car_get_var_ptr(&g_chip); + + if (chip->is_open) { + tpm_vendor_cleanup(chip); + chip->is_open = 0; } return 0; @@ -104,8 +107,7 @@ static ssize_t tpm_transmit(const uint8_t *buf, size_t bufsiz) { int rc; uint32_t count, ordinal; - - struct tpm_chip *chip = &g_chip; + struct tpm_chip *chip = car_get_var_ptr(&g_chip); memcpy(&count, buf + TPM_CMD_COUNT_BYTE, sizeof(count)); count = be32_to_cpu(count); diff --git a/src/drivers/i2c/tpm/tpm.c b/src/drivers/i2c/tpm/tpm.c index 306005f..c62ab69 100644 --- a/src/drivers/i2c/tpm/tpm.c +++ b/src/drivers/i2c/tpm/tpm.c @@ -28,6 +28,7 @@ * GNU General Public License for more details. */ +#include <arch/early_variables.h> #include <stdint.h> #include <string.h> #include <types.h> @@ -78,10 +79,7 @@ struct tpm_inf_dev { enum i2c_chip_type chip_type; }; -static struct tpm_inf_dev tpm_dev = { - .bus = -1, - .addr = TPM_I2C_ADDR -}; +static struct tpm_inf_dev g_tpm_dev CAR_GLOBAL; /* * iic_tpm_read() - read from TPM register @@ -99,15 +97,18 @@ static struct tpm_inf_dev tpm_dev = { */ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) { + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); int rc; int count; - if (tpm_dev.bus < 0) + if (tpm_dev->addr == 0) return -1; - if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) { + if ((tpm_dev->chip_type == SLB9635) || + (tpm_dev->chip_type == UNKNOWN)) { /* slb9635 protocol should work in both cases */ for (count = 0; count < MAX_COUNT; count++) { - rc = i2c_write_raw(tpm_dev.bus, tpm_dev.addr, &addr, 1); + rc = i2c_write_raw(tpm_dev->bus, tpm_dev->addr, + &addr, 1); if (rc == 0) break; /* success, break to skip sleep */ @@ -123,7 +124,7 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) */ for (count = 0; count < MAX_COUNT; count++) { udelay(SLEEP_DURATION); - rc = i2c_read_raw(tpm_dev.bus, tpm_dev.addr, + rc = i2c_read_raw(tpm_dev->bus, tpm_dev->addr, buffer, len); if (rc == 0) break; /* success, break to skip sleep */ @@ -136,13 +137,13 @@ static int iic_tpm_read(uint8_t addr, uint8_t *buffer, size_t len) * retries should usually not be needed, but are kept just to * be safe on the safe side. */ - struct i2c_seg aseg = { .read = 0, .chip = tpm_dev.addr, + struct i2c_seg aseg = { .read = 0, .chip = tpm_dev->addr, .buf = &addr, .len = 1 }; - struct i2c_seg dseg = { .read = 1, .chip = tpm_dev.addr, + struct i2c_seg dseg = { .read = 1, .chip = tpm_dev->addr, .buf = buffer, .len = len }; for (count = 0; count < MAX_COUNT; count++) { - rc = i2c_transfer(tpm_dev.bus, &aseg, 1) || - i2c_transfer(tpm_dev.bus, &dseg, 1); + rc = i2c_transfer(tpm_dev->bus, &aseg, 1) || + i2c_transfer(tpm_dev->bus, &dseg, 1); if (rc == 0) break; /* break here to skip sleep */ udelay(SLEEP_DURATION); @@ -161,6 +162,7 @@ static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, unsigned int sleep_time, uint8_t max_count) { + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); int rc = 0; int count; @@ -170,14 +172,14 @@ static int iic_tpm_write_generic(uint8_t addr, uint8_t *buffer, size_t len, } /* prepare send buffer */ - tpm_dev.buf[0] = addr; - memcpy(&(tpm_dev.buf[1]), buffer, len); + tpm_dev->buf[0] = addr; + memcpy(&(tpm_dev->buf[1]), buffer, len); - if (tpm_dev.bus < 0) + if (tpm_dev->addr == 0) return -1; for (count = 0; count < max_count; count++) { - rc = i2c_write_raw(tpm_dev.bus, tpm_dev.addr, - tpm_dev.buf, len + 1); + rc = i2c_write_raw(tpm_dev->bus, tpm_dev->addr, + tpm_dev->buf, len + 1); if (rc == 0) break; /* success, break to skip sleep */ @@ -480,34 +482,30 @@ out_err: return -1; } -static struct tpm_vendor_specific tpm_tis_i2c = { - .status = tpm_tis_i2c_status, - .recv = tpm_tis_i2c_recv, - .send = tpm_tis_i2c_send, - .cancel = tpm_tis_i2c_ready, - .req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID, - .req_canceled = TPM_STS_COMMAND_READY, -}; - /* Initialization of I2C TPM */ -int tpm_vendor_init(unsigned bus, uint32_t dev_addr) +int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr) { + struct tpm_inf_dev *tpm_dev = car_get_var_ptr(&g_tpm_dev); uint32_t vendor; unsigned int old_addr; - struct tpm_chip *chip; - extern struct tpm_chip g_chip; - old_addr = tpm_dev.addr; + old_addr = tpm_dev->addr; if (dev_addr != 0) - tpm_dev.addr = dev_addr; - tpm_dev.bus = bus; + tpm_dev->addr = dev_addr; + tpm_dev->bus = bus; - chip = &g_chip; - memcpy(&chip->vendor, &tpm_tis_i2c, sizeof(struct tpm_vendor_specific)); + memset(&chip->vendor, 0, sizeof(struct tpm_vendor_specific)); chip->is_open = 1; + chip->vendor.status = &tpm_tis_i2c_status; + chip->vendor.recv = &tpm_tis_i2c_recv; + chip->vendor.send = &tpm_tis_i2c_send; + chip->vendor.cancel = &tpm_tis_i2c_ready; + chip->vendor.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; + chip->vendor.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID; + chip->vendor.req_canceled = TPM_STS_COMMAND_READY; + /* Disable interrupts (not supported) */ chip->vendor.irq = 0; @@ -519,16 +517,16 @@ int tpm_vendor_init(unsigned bus, uint32_t dev_addr) goto out_release; if (vendor == TPM_TIS_I2C_DID_VID_9645) { - tpm_dev.chip_type = SLB9645; + tpm_dev->chip_type = SLB9645; } else if (be32_to_cpu(vendor) == TPM_TIS_I2C_DID_VID_9635) { - tpm_dev.chip_type = SLB9635; + tpm_dev->chip_type = SLB9635; } else { printk(BIOS_DEBUG, "Vendor ID 0x%08x not recognized.\n", vendor); goto out_release; } printk(BIOS_DEBUG, "1.2 TPM (chip type %s device-id 0x%X)\n", - chip_name[tpm_dev.chip_type], vendor >> 16); + chip_name[tpm_dev->chip_type], vendor >> 16); /* * A timeout query to TPM can be placed here. @@ -541,7 +539,7 @@ out_release: release_locality(chip, 0, 1); out_err: - tpm_dev.addr = old_addr; + tpm_dev->addr = old_addr; return -1; } diff --git a/src/drivers/i2c/tpm/tpm.h b/src/drivers/i2c/tpm/tpm.h index 625679d..7dfd594 100644 --- a/src/drivers/i2c/tpm/tpm.h +++ b/src/drivers/i2c/tpm/tpm.h @@ -47,9 +47,9 @@ enum tpm_timeout { struct tpm_chip; struct tpm_vendor_specific { - const uint8_t req_complete_mask; - const uint8_t req_complete_val; - const uint8_t req_canceled; + uint8_t req_complete_mask; + uint8_t req_complete_val; + uint8_t req_canceled; int irq; int (*recv)(struct tpm_chip *, uint8_t *, size_t); int (*send)(struct tpm_chip *, uint8_t *, size_t); @@ -121,7 +121,7 @@ struct tpm_cmd_t { /* ---------- Interface for TPM vendor ------------ */ -int tpm_vendor_init(unsigned bus, uint32_t dev_addr); +int tpm_vendor_init(struct tpm_chip *chip, unsigned bus, uint32_t dev_addr); void tpm_vendor_cleanup(struct tpm_chip *chip);
1
0
0
0
Patch set updated for coreboot: google/reef: Fix indent in devicetree.cb
by Duncan Laurie
02 Sep '16
02 Sep '16
Duncan Laurie (dlaurie(a)chromium.org) just uploaded a new patch set to gerrit, which you can find at
https://review.coreboot.org/16399
-gerrit commit 8d5ddb2208abe1a52873f9b7dae3e5de43afe799 Author: Duncan Laurie <dlaurie(a)chromium.org> Date: Thu Sep 1 16:00:39 2016 -0700 google/reef: Fix indent in devicetree.cb Indent the I2C device for touchscreen with tabs so it aligns properly. Change-Id: Id9b2d26a4acdd6fe6c69055907258df3cc035b31 Signed-off-by: Duncan Laurie <dlaurie(a)chromium.org> --- src/mainboard/google/reef/devicetree.cb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mainboard/google/reef/devicetree.cb b/src/mainboard/google/reef/devicetree.cb index ac69406..9a7c2d1 100644 --- a/src/mainboard/google/reef/devicetree.cb +++ b/src/mainboard/google/reef/devicetree.cb @@ -108,10 +108,10 @@ chip soc/intel/apollolake end # - I2C 2 device pci 16.3 on chip drivers/i2c/generic - register "hid" = ""ELAN0001"" - register "desc" = ""ELAN Touchscreen"" - register "irq" = "IRQ_EDGE_LOW(GPIO_21_IRQ)" - device i2c 10 on end + register "hid" = ""ELAN0001"" + register "desc" = ""ELAN Touchscreen"" + register "irq" = "IRQ_EDGE_LOW(GPIO_21_IRQ)" + device i2c 10 on end end end # - I2C 3 device pci 17.0 on
1
0
0
0
← Newer
1
...
127
128
129
130
131
132
133
134
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
Results per page:
10
25
50
100
200