summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2015-08-31 11:43:47 -0400
committerTom Rini <trini@konsulko.com>2015-08-31 11:43:47 -0400
commit80cd58b99e8690b05e8537dbf76276e24fcfa652 (patch)
tree0684c14480ab87bb3a74c1c70275b5fdc9c8e3c9
parent7c0e5d865ff0b86dfce492b656238919c659d756 (diff)
parent897705ec39682ab3bf5bb87bc49d7a491d522051 (diff)
Merge git://git.denx.de/u-boot-dm
-rw-r--r--README6
-rw-r--r--arch/arm/dts/exynos5250-snow.dts9
-rw-r--r--arch/arm/dts/exynos5250-spring.dts8
-rw-r--r--arch/arm/dts/exynos5420-peach-pit.dts6
-rw-r--r--arch/arm/dts/exynos5800-peach-pi.dts6
-rw-r--r--arch/sandbox/dts/sandbox.dts23
-rw-r--r--arch/x86/dts/chromebook_link.dts5
-rw-r--r--arch/x86/dts/chromebox_panther.dts5
-rw-r--r--board/samsung/common/exynos5-dt.c7
-rw-r--r--common/Kconfig22
-rw-r--r--common/Makefile1
-rw-r--r--common/cmd_i2c.c33
-rw-r--r--common/cmd_tpm.c100
-rw-r--r--common/cmd_tpm_test.c564
-rw-r--r--configs/chromebook_link_defconfig5
-rw-r--r--configs/chromebox_panther_defconfig5
-rw-r--r--configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig4
-rw-r--r--configs/controlcenterd_36BIT_SDCARD_defconfig4
-rw-r--r--configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig4
-rw-r--r--configs/controlcenterd_TRAILBLAZER_defconfig4
-rw-r--r--configs/coreboot-x86_defconfig5
-rw-r--r--configs/nyan-big_defconfig5
-rw-r--r--configs/peach-pi_defconfig5
-rw-r--r--configs/peach-pit_defconfig5
-rw-r--r--configs/sandbox_defconfig7
-rw-r--r--configs/snow_defconfig5
-rw-r--r--configs/spring_defconfig5
-rw-r--r--drivers/Kconfig60
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/core/Kconfig15
-rw-r--r--drivers/core/Makefile4
-rw-r--r--drivers/core/device.c12
-rw-r--r--drivers/gpio/s5p_gpio.c3
-rw-r--r--drivers/gpio/sunxi_gpio.c3
-rw-r--r--drivers/gpio/tegra_gpio.c3
-rw-r--r--drivers/i2c/s3c24x0_i2c.c6
-rw-r--r--drivers/i2c/tegra_i2c.c2
-rw-r--r--drivers/pinctrl/Kconfig109
-rw-r--r--drivers/pinctrl/Makefile4
-rw-r--r--drivers/pinctrl/pinctrl-generic.c359
-rw-r--r--drivers/pinctrl/pinctrl-sandbox.c147
-rw-r--r--drivers/pinctrl/pinctrl-uclass.c240
-rw-r--r--drivers/serial/ns16550.c2
-rw-r--r--drivers/serial/serial_arc.c3
-rw-r--r--drivers/serial/serial_pl01x.c2
-rw-r--r--drivers/serial/serial_s5p.c2
-rw-r--r--drivers/spi/designware_spi.c2
-rw-r--r--drivers/spi/exynos_spi.c2
-rw-r--r--drivers/spi/fsl_dspi.c2
-rw-r--r--drivers/spi/tegra114_spi.c2
-rw-r--r--drivers/spi/tegra20_sflash.c2
-rw-r--r--drivers/spi/tegra20_slink.c2
-rw-r--r--drivers/spi/zynq_spi.c2
-rw-r--r--drivers/tpm/Kconfig69
-rw-r--r--drivers/tpm/Makefile4
-rw-r--r--drivers/tpm/tpm-uclass.c133
-rw-r--r--drivers/tpm/tpm.c694
-rw-r--r--drivers/tpm/tpm_atmel_twi.c15
-rw-r--r--drivers/tpm/tpm_internal.h287
-rw-r--r--drivers/tpm/tpm_tis_i2c.c572
-rw-r--r--drivers/tpm/tpm_tis_i2c.h (renamed from drivers/tpm/tpm_private.h)88
-rw-r--r--drivers/tpm/tpm_tis_lpc.c290
-rw-r--r--drivers/tpm/tpm_tis_sandbox.c57
-rw-r--r--drivers/usb/host/ehci-tegra.c8
-rw-r--r--drivers/usb/host/xhci-exynos5.c2
-rw-r--r--drivers/video/tegra124/dp.c3
-rw-r--r--dts/Kconfig2
-rw-r--r--include/configs/controlcenterd.h7
-rw-r--r--include/configs/efi-x86.h2
-rw-r--r--include/configs/exynos5-common.h7
-rw-r--r--include/configs/x86-common.h2
-rw-r--r--include/dm/device-internal.h4
-rw-r--r--include/dm/lists.h4
-rw-r--r--include/dm/pinctrl.h227
-rw-r--r--include/dm/uclass-id.h3
-rw-r--r--include/dm/uclass.h9
-rw-r--r--include/fdtdec.h2
-rw-r--r--include/tis.h3
-rw-r--r--include/tpm.h243
-rw-r--r--lib/Kconfig10
-rw-r--r--lib/fdtdec.c2
-rw-r--r--lib/tpm.c82
-rw-r--r--tools/patman/series.py2
83 files changed, 3305 insertions, 1377 deletions
diff --git a/README b/README
index a52ff46c21..1acc355968 100644
--- a/README
+++ b/README
@@ -1494,12 +1494,6 @@ The following options need to be configured:
Support for i2c bus TPM devices. Only one device
per system is supported at this time.
- CONFIG_TPM_TIS_I2C_BUS_NUMBER
- Define the the i2c bus number for the TPM device
-
- CONFIG_TPM_TIS_I2C_SLAVE_ADDRESS
- Define the TPM's address on the i2c bus
-
CONFIG_TPM_TIS_I2C_BURST_LIMITATION
Define the burst count bytes upper limit
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts
index 32c0098bd8..bda5499988 100644
--- a/arch/arm/dts/exynos5250-snow.dts
+++ b/arch/arm/dts/exynos5250-snow.dts
@@ -206,6 +206,15 @@
};
};
+ i2c@12C90000 {
+ clock-frequency = <100000>;
+ tpm@20 {
+ reg = <0x20>;
+ u-boot,i2c-offset-len = <0>;
+ compatible = "infineon,slb9635tt";
+ };
+ };
+
spi@12d30000 {
spi-max-frequency = <50000000>;
firmware_storage_spi: flash@0 {
diff --git a/arch/arm/dts/exynos5250-spring.dts b/arch/arm/dts/exynos5250-spring.dts
index 76d5323dc3..81b3d29f9c 100644
--- a/arch/arm/dts/exynos5250-spring.dts
+++ b/arch/arm/dts/exynos5250-spring.dts
@@ -59,6 +59,14 @@
<&gpy4 2 0>;
};
+ i2c@12C90000 {
+ clock-frequency = <100000>;
+ tpm@20 {
+ reg = <0x20>;
+ compatible = "infineon,slb9645tt";
+ };
+ };
+
mmc@12200000 {
samsung,bus-width = <8>;
samsung,timing = <1 3 3>;
diff --git a/arch/arm/dts/exynos5420-peach-pit.dts b/arch/arm/dts/exynos5420-peach-pit.dts
index 2d2b7c9bde..16d52f4928 100644
--- a/arch/arm/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/dts/exynos5420-peach-pit.dts
@@ -197,9 +197,9 @@
i2c@12E10000 { /* i2c9 */
clock-frequency = <400000>;
- tpm@20 {
- compatible = "infineon,slb9645tt";
- reg = <0x20>;
+ tpm@20 {
+ compatible = "infineon,slb9645tt";
+ reg = <0x20>;
};
};
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts
index 600c2948cf..1d7ff23c93 100644
--- a/arch/arm/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/dts/exynos5800-peach-pi.dts
@@ -72,9 +72,9 @@
i2c@12E10000 { /* i2c9 */
clock-frequency = <400000>;
- tpm@20 {
- compatible = "infineon,slb9645tt";
- reg = <0x20>;
+ tpm@20 {
+ compatible = "infineon,slb9645tt";
+ reg = <0x20>;
};
};
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 8927527141..65b9125f5f 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -92,6 +92,8 @@
reg = <0 0>;
compatible = "sandbox,i2c";
clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
eeprom@2c {
reg = <0x2c>;
compatible = "i2c-eeprom";
@@ -136,6 +138,21 @@
};
};
+ pinctrl {
+ compatible = "sandbox,pinctrl";
+
+ pinctrl_i2c0: i2c0 {
+ groups = "i2c";
+ function = "i2c";
+ bias-pull-up;
+ };
+
+ pinctrl_serial0: uart0 {
+ groups = "serial_a";
+ function = "serial";
+ };
+ };
+
spi@0 {
#address-cells = <1>;
#size-cells = <0>;
@@ -156,6 +173,10 @@
sides = <4>;
};
+ tpm {
+ compatible = "google,sandbox-tpm";
+ };
+
triangle {
compatible = "demo-shape";
colour = "cyan";
@@ -168,6 +189,8 @@
uart0: serial {
compatible = "sandbox,serial";
sandbox,text-colour = "cyan";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_serial0>;
};
usb@0 {
diff --git a/arch/x86/dts/chromebook_link.dts b/arch/x86/dts/chromebook_link.dts
index ad390bf117..4291141dfe 100644
--- a/arch/x86/dts/chromebook_link.dts
+++ b/arch/x86/dts/chromebook_link.dts
@@ -237,6 +237,11 @@
};
};
+ tpm {
+ reg = <0xfed40000 0x5000>;
+ compatible = "infineon,slb9635lpc";
+ };
+
microcode {
update@0 {
#include "microcode/m12306a9_0000001b.dtsi"
diff --git a/arch/x86/dts/chromebox_panther.dts b/arch/x86/dts/chromebox_panther.dts
index 84eae3ab65..36feb96a94 100644
--- a/arch/x86/dts/chromebox_panther.dts
+++ b/arch/x86/dts/chromebox_panther.dts
@@ -62,4 +62,9 @@
};
};
+ tpm {
+ reg = <0xfed40000 0x5000>;
+ compatible = "infineon,slb9635lpc";
+ };
+
};
diff --git a/board/samsung/common/exynos5-dt.c b/board/samsung/common/exynos5-dt.c
index 7d1b88a9b8..4250f722da 100644
--- a/board/samsung/common/exynos5-dt.c
+++ b/board/samsung/common/exynos5-dt.c
@@ -121,11 +121,12 @@ int exynos_power_init(void)
return ret;
/*
- * This would normally be 1.3V, but since we are running slowly 1V
+ * This would normally be 1.3V, but since we are running slowly 1.1V
* is enough. For spring it helps reduce CPU temperature and avoid
- * hangs with the case open.
+ * hangs with the case open. 1.1V is minimum voltage borderline for
+ * chained bootloaders.
*/
- ret = exynos_set_regulator("vdd_arm", 1000000);
+ ret = exynos_set_regulator("vdd_arm", 1100000);
if (ret)
return ret;
ret = exynos_set_regulator("vdd_int", 1012500);
diff --git a/common/Kconfig b/common/Kconfig
index 88dc016079..2c42b8e4d0 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -625,4 +625,26 @@ config CMD_REGULATOR
endmenu
+menu "Security commands"
+config CMD_TPM
+ bool "Enable the 'tpm' command"
+ depends on TPM
+ help
+ This provides a means to talk to a TPM from the command line. A wide
+ range of commands if provided - see 'tpm help' for details. The
+ command requires a suitable TPM on your board and the correct driver
+ must be enabled.
+
+config CMD_TPM_TEST
+ bool "Enable the 'tpm test' command"
+ depends on CMD_TPM
+ help
+ This provides a a series of tests to confirm that the TPM is working
+ correctly. The tests cover initialisation, non-volatile RAM, extend,
+ global lock and checking that timing is within expectations. The
+ tests pass correctly on Infineon TPMs but may need to be adjusted
+ for other devices.
+
+endmenu
+
endmenu
diff --git a/common/Makefile b/common/Makefile
index dc82433e90..f4ba8782f5 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -169,6 +169,7 @@ obj-$(CONFIG_CMD_TIME) += cmd_time.o
obj-$(CONFIG_CMD_TRACE) += cmd_trace.o
obj-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o
obj-$(CONFIG_CMD_TPM) += cmd_tpm.o
+obj-$(CONFIG_CMD_TPM_TEST) += cmd_tpm_test.o
obj-$(CONFIG_CMD_TSI148) += cmd_tsi148.o
obj-$(CONFIG_CMD_UBI) += cmd_ubi.o
obj-$(CONFIG_CMD_UBIFS) += cmd_ubifs.o
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index 1bc0db860c..864b2596cc 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -453,6 +453,37 @@ static int do_i2c_flags(cmd_tbl_t *cmdtp, int flag, int argc,
return 0;
}
+
+static int do_i2c_olen(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+ struct udevice *dev;
+ uint olen;
+ int chip;
+ int ret;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ chip = simple_strtoul(argv[1], NULL, 16);
+ ret = i2c_get_cur_bus_chip(chip, &dev);
+ if (ret)
+ return i2c_report_err(ret, I2C_ERR_READ);
+
+ if (argc > 2) {
+ olen = simple_strtoul(argv[2], NULL, 16);
+ ret = i2c_set_chip_offset_len(dev, olen);
+ } else {
+ ret = i2c_get_chip_offset_len(dev);
+ if (ret >= 0) {
+ printf("%x\n", ret);
+ ret = 0;
+ }
+ }
+ if (ret)
+ return i2c_report_err(ret, I2C_ERR_READ);
+
+ return 0;
+}
#endif
/**
@@ -1903,6 +1934,7 @@ static cmd_tbl_t cmd_i2c_sub[] = {
U_BOOT_CMD_MKENT(write, 6, 0, do_i2c_write, "", ""),
#ifdef CONFIG_DM_I2C
U_BOOT_CMD_MKENT(flags, 2, 1, do_i2c_flags, "", ""),
+ U_BOOT_CMD_MKENT(olen, 2, 1, do_i2c_olen, "", ""),
#endif
U_BOOT_CMD_MKENT(reset, 0, 1, do_i2c_reset, "", ""),
#if defined(CONFIG_CMD_SDRAM)
@@ -1971,6 +2003,7 @@ static char i2c_help_text[] =
" to I2C; the -s option selects bulk write in a single transaction\n"
#ifdef CONFIG_DM_I2C
"i2c flags chip [flags] - set or get chip flags\n"
+ "i2c olen chip [offset_length] - set or get chip offset length\n"
#endif
"i2c reset - re-init the I2C Controller\n"
#if defined(CONFIG_CMD_SDRAM)
diff --git a/common/cmd_tpm.c b/common/cmd_tpm.c
index 0294952e69..97501cc3d1 100644
--- a/common/cmd_tpm.c
+++ b/common/cmd_tpm.c
@@ -6,6 +6,7 @@
#include <common.h>
#include <command.h>
+#include <dm.h>
#include <malloc.h>
#include <tpm.h>
#include <asm/unaligned.h>
@@ -57,6 +58,8 @@ static void *parse_byte_string(char *bytes, uint8_t *data, size_t *count_ptr)
size_t count, length;
int i;
+ if (!bytes)
+ return NULL;
length = strlen(bytes);
count = length / 2;
@@ -79,17 +82,19 @@ static void *parse_byte_string(char *bytes, uint8_t *data, size_t *count_ptr)
}
/**
- * Convert TPM command return code to U-Boot command error codes.
+ * report_return_code() - Report any error and return failure or success
*
* @param return_code TPM command return code
* @return value of enum command_ret_t
*/
-static int convert_return_code(uint32_t return_code)
+static int report_return_code(int return_code)
{
- if (return_code)
+ if (return_code) {
+ printf("Error: %d\n", return_code);
return CMD_RET_FAILURE;
- else
+ } else {
return CMD_RET_SUCCESS;
+ }
}
/**
@@ -251,7 +256,7 @@ static int do_tpm_startup(cmd_tbl_t *cmdtp, int flag,
return CMD_RET_FAILURE;
}
- return convert_return_code(tpm_startup(mode));
+ return report_return_code(tpm_startup(mode));
}
static int do_tpm_nv_define_space(cmd_tbl_t *cmdtp, int flag,
@@ -265,7 +270,7 @@ static int do_tpm_nv_define_space(cmd_tbl_t *cmdtp, int flag,
perm = simple_strtoul(argv[2], NULL, 0);
size = simple_strtoul(argv[3], NULL, 0);
- return convert_return_code(tpm_nv_define_space(index, perm, size));
+ return report_return_code(tpm_nv_define_space(index, perm, size));
}
static int do_tpm_nv_read_value(cmd_tbl_t *cmdtp, int flag,
@@ -286,7 +291,7 @@ static int do_tpm_nv_read_value(cmd_tbl_t *cmdtp, int flag,
print_byte_string(data, count);
}
- return convert_return_code(rc);
+ return report_return_code(rc);
}
static int do_tpm_nv_write_value(cmd_tbl_t *cmdtp, int flag,
@@ -308,7 +313,7 @@ static int do_tpm_nv_write_value(cmd_tbl_t *cmdtp, int flag,
rc = tpm_nv_write_value(index, data, count);
free(data);
- return convert_return_code(rc);
+ return report_return_code(rc);
}
static int do_tpm_extend(cmd_tbl_t *cmdtp, int flag,
@@ -331,7 +336,7 @@ static int do_tpm_extend(cmd_tbl_t *cmdtp, int flag,
print_byte_string(out_digest, sizeof(out_digest));
}
- return convert_return_code(rc);
+ return report_return_code(rc);
}
static int do_tpm_pcr_read(cmd_tbl_t *cmdtp, int flag,
@@ -352,7 +357,7 @@ static int do_tpm_pcr_read(cmd_tbl_t *cmdtp, int flag,
print_byte_string(data, count);
}
- return convert_return_code(rc);
+ return report_return_code(rc);
}
static int do_tpm_tsc_physical_presence(cmd_tbl_t *cmdtp, int flag,
@@ -364,7 +369,7 @@ static int do_tpm_tsc_physical_presence(cmd_tbl_t *cmdtp, int flag,
return CMD_RET_USAGE;
presence = (uint16_t)simple_strtoul(argv[1], NULL, 0);
- return convert_return_code(tpm_tsc_physical_presence(presence));
+ return report_return_code(tpm_tsc_physical_presence(presence));
}
static int do_tpm_read_pubek(cmd_tbl_t *cmdtp, int flag,
@@ -384,7 +389,7 @@ static int do_tpm_read_pubek(cmd_tbl_t *cmdtp, int flag,
print_byte_string(data, count);
}
- return convert_return_code(rc);
+ return report_return_code(rc);
}
static int do_tpm_physical_set_deactivated(cmd_tbl_t *cmdtp, int flag,
@@ -396,7 +401,7 @@ static int do_tpm_physical_set_deactivated(cmd_tbl_t *cmdtp, int flag,
return CMD_RET_USAGE;
state = (uint8_t)simple_strtoul(argv[1], NULL, 0);
- return convert_return_code(tpm_physical_set_deactivated(state));
+ return report_return_code(tpm_physical_set_deactivated(state));
}
static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag,
@@ -419,7 +424,7 @@ static int do_tpm_get_capability(cmd_tbl_t *cmdtp, int flag,
print_byte_string(cap, count);
}
- return convert_return_code(rc);
+ return report_return_code(rc);
}
#define TPM_COMMAND_NO_ARG(cmd) \
@@ -428,7 +433,7 @@ static int do_##cmd(cmd_tbl_t *cmdtp, int flag, \
{ \
if (argc != 1) \
return CMD_RET_USAGE; \
- return convert_return_code(cmd()); \
+ return report_return_code(cmd()); \
}
TPM_COMMAND_NO_ARG(tpm_init)
@@ -438,6 +443,41 @@ TPM_COMMAND_NO_ARG(tpm_force_clear)
TPM_COMMAND_NO_ARG(tpm_physical_enable)
TPM_COMMAND_NO_ARG(tpm_physical_disable)
+#ifdef CONFIG_DM_TPM
+static int get_tpm(struct udevice **devp)
+{
+ int rc;
+
+ rc = uclass_first_device(UCLASS_TPM, devp);
+ if (rc) {
+ printf("Could not find TPM (ret=%d)\n", rc);
+ return CMD_RET_FAILURE;
+ }
+
+ return 0;
+}
+
+static int do_tpm_info(cmd_tbl_t *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ struct udevice *dev;
+ char buf[80];
+ int rc;
+
+ rc = get_tpm(&dev);
+ if (rc)
+ return rc;
+ rc = tpm_get_desc(dev, buf, sizeof(buf));
+ if (rc < 0) {
+ printf("Couldn't get TPM info (%d)\n", rc);
+ return CMD_RET_FAILURE;
+ }
+ printf("%s\n", buf);
+
+ return 0;
+}
+#endif
+
static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag,
int argc, char * const argv[])
{
@@ -452,14 +492,24 @@ static int do_tpm_raw_transfer(cmd_tbl_t *cmdtp, int flag,
return CMD_RET_FAILURE;
}
+#ifdef CONFIG_DM_TPM
+ struct udevice *dev;
+
+ rc = get_tpm(&dev);
+ if (rc)
+ return rc;
+
+ rc = tpm_xfer(dev, command, count, response, &response_length);
+#else
rc = tis_sendrecv(command, count, response, &response_length);
+#endif
free(command);
if (!rc) {
puts("tpm response:\n");
print_byte_string(response, response_length);
}
- return convert_return_code(rc);
+ return report_return_code(rc);
}
static int do_tpm_nv_define(cmd_tbl_t *cmdtp, int flag,
@@ -477,7 +527,7 @@ static int do_tpm_nv_define(cmd_tbl_t *cmdtp, int flag,
index = simple_strtoul(argv[2], NULL, 0);
perm = simple_strtoul(argv[3], NULL, 0);
- return convert_return_code(tpm_nv_define_space(index, perm, size));
+ return report_return_code(tpm_nv_define_space(index, perm, size));
}
static int do_tpm_nv_read(cmd_tbl_t *cmdtp, int flag,
@@ -506,7 +556,7 @@ static int do_tpm_nv_read(cmd_tbl_t *cmdtp, int flag,
}
free(data);
- return convert_return_code(err);
+ return report_return_code(err);
}
static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag,
@@ -534,7 +584,7 @@ static int do_tpm_nv_write(cmd_tbl_t *cmdtp, int flag,
err = tpm_nv_write_value(index, data, count);
free(data);
- return convert_return_code(err);
+ return report_return_code(err);
}
#ifdef CONFIG_TPM_AUTH_SESSIONS
@@ -546,7 +596,7 @@ static int do_tpm_oiap(cmd_tbl_t *cmdtp, int flag,
err = tpm_oiap(&auth_handle);
- return convert_return_code(err);
+ return report_return_code(err);
}
static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag,
@@ -571,7 +621,7 @@ static int do_tpm_load_key2_oiap(cmd_tbl_t *cmdtp, int flag,
if (!err)
printf("Key handle is 0x%x\n", key_handle);
- return convert_return_code(err);
+ return report_return_code(err);
}
static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag,
@@ -596,7 +646,7 @@ static int do_tpm_get_pub_key_oiap(cmd_tbl_t *cmdtp, int flag,
printf("dump of received pub key structure:\n");
print_byte_string(pub_key_buffer, pub_key_len);
}
- return convert_return_code(err);
+ return report_return_code(err);
}
TPM_COMMAND_NO_ARG(tpm_end_oiap)
@@ -607,6 +657,9 @@ TPM_COMMAND_NO_ARG(tpm_end_oiap)
U_BOOT_CMD_MKENT(cmd, 0, 1, do_tpm_ ## cmd, "", "")
static cmd_tbl_t tpm_commands[] = {
+#ifdef CONFIG_DM_TPM
+ U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
+#endif
U_BOOT_CMD_MKENT(init, 0, 1,
do_tpm_init, "", ""),
U_BOOT_CMD_MKENT(startup, 0, 1,
@@ -677,6 +730,9 @@ U_BOOT_CMD(tpm, CONFIG_SYS_MAXARGS, 1, do_tpm,
"cmd args...\n"
" - Issue TPM command <cmd> with arguments <args...>.\n"
"Admin Startup and State Commands:\n"
+#ifdef CONFIG_DM_TPM
+" info - Show information about the TPM\n"
+#endif
" init\n"
" - Put TPM into a state where it waits for 'startup' command.\n"
" startup mode\n"
diff --git a/common/cmd_tpm_test.c b/common/cmd_tpm_test.c
new file mode 100644
index 0000000000..65332d1117
--- /dev/null
+++ b/common/cmd_tpm_test.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <environment.h>
+#include <tpm.h>
+
+/* Prints error and returns on failure */
+#define TPM_CHECK(tpm_command) do { \
+ uint32_t result; \
+ \
+ result = (tpm_command); \
+ if (result != TPM_SUCCESS) { \
+ printf("TEST FAILED: line %d: " #tpm_command ": 0x%x\n", \
+ __LINE__, result); \
+ return result; \
+ } \
+} while (0)
+
+#define INDEX0 0xda70
+#define INDEX1 0xda71
+#define INDEX2 0xda72
+#define INDEX3 0xda73
+#define INDEX_INITIALISED 0xda80
+#define PHYS_PRESENCE 4
+#define PRESENCE 8
+
+static uint32_t TlclStartupIfNeeded(void)
+{
+ uint32_t result = tpm_startup(TPM_ST_CLEAR);
+
+ return result == TPM_INVALID_POSTINIT ? TPM_SUCCESS : result;
+}
+
+static int test_timer(void)
+{
+ printf("get_timer(0) = %lu\n", get_timer(0));
+ return 0;
+}
+
+static uint32_t tpm_get_flags(uint8_t *disable, uint8_t *deactivated,
+ uint8_t *nvlocked)
+{
+ struct tpm_permanent_flags pflags;
+ uint32_t result;
+
+ result = tpm_get_permanent_flags(&pflags);
+ if (result)
+ return result;
+ if (disable)
+ *disable = pflags.disable;
+ if (deactivated)
+ *deactivated = pflags.deactivated;
+ if (nvlocked)
+ *nvlocked = pflags.nv_locked;
+ debug("TPM: Got flags disable=%d, deactivated=%d, nvlocked=%d\n",
+ pflags.disable, pflags.deactivated, pflags.nv_locked);
+
+ return 0;
+}
+
+static uint32_t tpm_set_global_lock(void)
+{
+ uint32_t x;
+
+ debug("TPM: Set global lock\n");
+ return tpm_nv_write_value(INDEX0, (uint8_t *)&x, 0);
+}
+
+static uint32_t tpm_nv_write_value_lock(uint32_t index)
+{
+ debug("TPM: Write lock 0x%x\n", index);
+
+ return tpm_nv_write_value(index, NULL, 0);
+}
+
+static uint32_t tpm_nv_set_locked(void)
+{
+ debug("TPM: Set NV locked\n");
+
+ return tpm_nv_define_space(TPM_NV_INDEX_LOCK, 0, 0);
+}
+
+static int tpm_is_owned(void)
+{
+ uint8_t response[TPM_PUBEK_SIZE];
+ uint32_t result;
+
+ result = tpm_read_pubek(response, sizeof(response));
+
+ return result != TPM_SUCCESS;
+}
+
+static int test_early_extend(void)
+{
+ uint8_t value_in[20];
+ uint8_t value_out[20];
+
+ printf("Testing earlyextend ...");
+ tpm_init();
+ TPM_CHECK(tpm_startup(TPM_ST_CLEAR));
+ TPM_CHECK(tpm_continue_self_test());
+ TPM_CHECK(tpm_extend(1, value_in, value_out));
+ printf("done\n");
+ return 0;
+}
+
+static int test_early_nvram(void)
+{
+ uint32_t x;
+
+ printf("Testing earlynvram ...");
+ tpm_init();
+ TPM_CHECK(tpm_startup(TPM_ST_CLEAR));
+ TPM_CHECK(tpm_continue_self_test());
+ TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+ TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+ printf("done\n");
+ return 0;
+}
+
+static int test_early_nvram2(void)
+{
+ uint32_t x;
+
+ printf("Testing earlynvram2 ...");
+ tpm_init();
+ TPM_CHECK(tpm_startup(TPM_ST_CLEAR));
+ TPM_CHECK(tpm_continue_self_test());
+ TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+ TPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+ printf("done\n");
+ return 0;
+}
+
+static int test_enable(void)
+{
+ uint8_t disable = 0, deactivated = 0;
+
+ printf("Testing enable ...\n");
+ tpm_init();
+ TPM_CHECK(TlclStartupIfNeeded());
+ TPM_CHECK(tpm_self_test_full());
+ TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+ TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+ printf("\tdisable is %d, deactivated is %d\n", disable, deactivated);
+ TPM_CHECK(tpm_physical_enable());
+ TPM_CHECK(tpm_physical_set_deactivated(0));
+ TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+ printf("\tdisable is %d, deactivated is %d\n", disable, deactivated);
+ if (disable == 1 || deactivated == 1)
+ printf("\tfailed to enable or activate\n");
+ printf("\tdone\n");
+ return 0;
+}
+
+#define reboot() do { \
+ printf("\trebooting...\n"); \
+ reset_cpu(0); \
+} while (0)
+
+static int test_fast_enable(void)
+{
+ uint8_t disable = 0, deactivated = 0;
+ int i;
+
+ printf("Testing fastenable ...\n");
+ tpm_init();
+ TPM_CHECK(TlclStartupIfNeeded());
+ TPM_CHECK(tpm_self_test_full());
+ TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+ TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+ printf("\tdisable is %d, deactivated is %d\n", disable, deactivated);
+ for (i = 0; i < 2; i++) {
+ TPM_CHECK(tpm_force_clear());
+ TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+ printf("\tdisable is %d, deactivated is %d\n", disable,
+ deactivated);
+ assert(disable == 1 && deactivated == 1);
+ TPM_CHECK(tpm_physical_enable());
+ TPM_CHECK(tpm_physical_set_deactivated(0));
+ TPM_CHECK(tpm_get_flags(&disable, &deactivated, NULL));
+ printf("\tdisable is %d, deactivated is %d\n", disable,
+ deactivated);
+ assert(disable == 0 && deactivated == 0);
+ }
+ printf("\tdone\n");
+ return 0;
+}
+
+static int test_global_lock(void)
+{
+ uint32_t zero = 0;
+ uint32_t result;
+ uint32_t x;
+
+ printf("Testing globallock ...\n");
+ tpm_init();
+ TPM_CHECK(TlclStartupIfNeeded());
+ TPM_CHECK(tpm_self_test_full());
+ TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+ TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+ TPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&zero,
+ sizeof(uint32_t)));
+ TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+ TPM_CHECK(tpm_nv_write_value(INDEX1, (uint8_t *)&zero,
+ sizeof(uint32_t)));
+ TPM_CHECK(tpm_set_global_lock());
+ /* Verifies that write to index0 fails */
+ x = 1;
+ result = tpm_nv_write_value(INDEX0, (uint8_t *)&x, sizeof(x));
+ assert(result == TPM_AREA_LOCKED);
+ TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+ assert(x == 0);
+ /* Verifies that write to index1 is still possible */
+ x = 2;
+ TPM_CHECK(tpm_nv_write_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+ TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+ assert(x == 2);
+ /* Turns off PP */
+ tpm_tsc_physical_presence(PHYS_PRESENCE);
+ /* Verifies that write to index1 fails */
+ x = 3;
+ result = tpm_nv_write_value(INDEX1, (uint8_t *)&x, sizeof(x));
+ assert(result == TPM_BAD_PRESENCE);
+ TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+ assert(x == 2);
+ printf("\tdone\n");
+ return 0;
+}
+
+static int test_lock(void)
+{
+ printf("Testing lock ...\n");
+ tpm_init();
+ tpm_startup(TPM_ST_CLEAR);
+ tpm_self_test_full();
+ tpm_tsc_physical_presence(PRESENCE);
+ tpm_nv_write_value_lock(INDEX0);
+ printf("\tLocked 0x%x\n", INDEX0);
+ printf("\tdone\n");
+ return 0;
+}
+
+static void initialise_spaces(void)
+{
+ uint32_t zero = 0;
+ uint32_t perm = TPM_NV_PER_WRITE_STCLEAR | TPM_NV_PER_PPWRITE;
+
+ printf("\tInitialising spaces\n");
+ tpm_nv_set_locked(); /* useful only the first time */
+ tpm_nv_define_space(INDEX0, perm, 4);
+ tpm_nv_write_value(INDEX0, (uint8_t *)&zero, 4);
+ tpm_nv_define_space(INDEX1, perm, 4);
+ tpm_nv_write_value(INDEX1, (uint8_t *)&zero, 4);
+ tpm_nv_define_space(INDEX2, perm, 4);
+ tpm_nv_write_value(INDEX2, (uint8_t *)&zero, 4);
+ tpm_nv_define_space(INDEX3, perm, 4);
+ tpm_nv_write_value(INDEX3, (uint8_t *)&zero, 4);
+ perm = TPM_NV_PER_READ_STCLEAR | TPM_NV_PER_WRITE_STCLEAR |
+ TPM_NV_PER_PPWRITE;
+ tpm_nv_define_space(INDEX_INITIALISED, perm, 1);
+}
+
+static int test_readonly(void)
+{
+ uint8_t c;
+ uint32_t index_0, index_1, index_2, index_3;
+ int read0, read1, read2, read3;
+
+ printf("Testing readonly ...\n");
+ tpm_init();
+ tpm_startup(TPM_ST_CLEAR);
+ tpm_self_test_full();
+ tpm_tsc_physical_presence(PRESENCE);
+ /*
+ * Checks if initialisation has completed by trying to read-lock a
+ * space that's created at the end of initialisation
+ */
+ if (tpm_nv_read_value(INDEX_INITIALISED, &c, 0) == TPM_BADINDEX) {
+ /* The initialisation did not complete */
+ initialise_spaces();
+ }
+
+ /* Checks if spaces are OK or messed up */
+ read0 = tpm_nv_read_value(INDEX0, (uint8_t *)&index_0, sizeof(index_0));
+ read1 = tpm_nv_read_value(INDEX1, (uint8_t *)&index_1, sizeof(index_1));
+ read2 = tpm_nv_read_value(INDEX2, (uint8_t *)&index_2, sizeof(index_2));
+ read3 = tpm_nv_read_value(INDEX3, (uint8_t *)&index_3, sizeof(index_3));
+ if (read0 || read1 || read2 || read3) {
+ printf("Invalid contents\n");
+ return 0;
+ }
+
+ /*
+ * Writes space, and locks it. Then attempts to write again.
+ * I really wish I could use the imperative.
+ */
+ index_0 += 1;
+ if (tpm_nv_write_value(INDEX0, (uint8_t *)&index_0, sizeof(index_0) !=
+ TPM_SUCCESS)) {
+ error("\tcould not write index 0\n");
+ }
+ tpm_nv_write_value_lock(INDEX0);
+ if (tpm_nv_write_value(INDEX0, (uint8_t *)&index_0, sizeof(index_0)) ==
+ TPM_SUCCESS)
+ error("\tindex 0 is not locked\n");
+
+ printf("\tdone\n");
+ return 0;
+}
+
+static int test_redefine_unowned(void)
+{
+ uint32_t perm;
+ uint32_t result;
+ uint32_t x;
+
+ printf("Testing redefine_unowned ...");
+ tpm_init();
+ TPM_CHECK(TlclStartupIfNeeded());
+ TPM_CHECK(tpm_self_test_full());
+ TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+ assert(!tpm_is_owned());
+
+ /* Ensures spaces exist. */
+ TPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)));
+ TPM_CHECK(tpm_nv_read_value(INDEX1, (uint8_t *)&x, sizeof(x)));
+
+ /* Redefines spaces a couple of times. */
+ perm = TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK;
+ TPM_CHECK(tpm_nv_define_space(INDEX0, perm, 2 * sizeof(uint32_t)));
+ TPM_CHECK(tpm_nv_define_space(INDEX0, perm, sizeof(uint32_t)));
+ perm = TPM_NV_PER_PPWRITE;
+ TPM_CHECK(tpm_nv_define_space(INDEX1, perm, 2 * sizeof(uint32_t)));
+ TPM_CHECK(tpm_nv_define_space(INDEX1, perm, sizeof(uint32_t)));
+
+ /* Sets the global lock */
+ tpm_set_global_lock();
+
+ /* Verifies that index0 cannot be redefined */
+ result = tpm_nv_define_space(INDEX0, perm, sizeof(uint32_t));
+ assert(result == TPM_AREA_LOCKED);
+
+ /* Checks that index1 can */
+ TPM_CHECK(tpm_nv_define_space(INDEX1, perm, 2 * sizeof(uint32_t)));
+ TPM_CHECK(tpm_nv_define_space(INDEX1, perm, sizeof(uint32_t)));
+
+ /* Turns off PP */
+ tpm_tsc_physical_presence(PHYS_PRESENCE);
+
+ /* Verifies that neither index0 nor index1 can be redefined */
+ result = tpm_nv_define_space(INDEX0, perm, sizeof(uint32_t));
+ assert(result == TPM_BAD_PRESENCE);
+ result = tpm_nv_define_space(INDEX1, perm, sizeof(uint32_t));
+ assert(result == TPM_BAD_PRESENCE);
+
+ printf("done\n");
+ return 0;
+}
+
+#define PERMPPGL (TPM_NV_PER_PPWRITE | TPM_NV_PER_GLOBALLOCK)
+#define PERMPP TPM_NV_PER_PPWRITE
+
+static int test_space_perm(void)
+{
+ uint32_t perm;
+
+ printf("Testing spaceperm ...");
+ tpm_init();
+ TPM_CHECK(TlclStartupIfNeeded());
+ TPM_CHECK(tpm_continue_self_test());
+ TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+ TPM_CHECK(tpm_get_permissions(INDEX0, &perm));
+ assert((perm & PERMPPGL) == PERMPPGL);
+ TPM_CHECK(tpm_get_permissions(INDEX1, &perm));
+ assert((perm & PERMPP) == PERMPP);
+ printf("done\n");
+ return 0;
+}
+
+static int test_startup(void)
+{
+ uint32_t result;
+ printf("Testing startup ...\n");
+
+ tpm_init();
+ result = tpm_startup(TPM_ST_CLEAR);
+ if (result != 0 && result != TPM_INVALID_POSTINIT)
+ printf("\ttpm startup failed with 0x%x\n", result);
+ result = tpm_get_flags(NULL, NULL, NULL);
+ if (result != 0)
+ printf("\ttpm getflags failed with 0x%x\n", result);
+ printf("\texecuting SelfTestFull\n");
+ tpm_self_test_full();
+ result = tpm_get_flags(NULL, NULL, NULL);
+ if (result != 0)
+ printf("\ttpm getflags failed with 0x%x\n", result);
+ printf("\tdone\n");
+ return 0;
+}
+
+/*
+ * Runs [op] and ensures it returns success and doesn't run longer than
+ * [time_limit] in milliseconds.
+ */
+#define TTPM_CHECK(op, time_limit) do { \
+ ulong start, time; \
+ uint32_t __result; \
+ \
+ start = get_timer(0); \
+ __result = op; \
+ if (__result != TPM_SUCCESS) { \
+ printf("\t" #op ": error 0x%x\n", __result); \
+ return -1; \
+ } \
+ time = get_timer(start); \
+ printf("\t" #op ": %lu ms\n", time); \
+ if (time > (ulong)time_limit) { \
+ printf("\t" #op " exceeded " #time_limit " ms\n"); \
+ } \
+} while (0)
+
+
+static int test_timing(void)
+{
+ uint32_t x;
+ uint8_t in[20], out[20];
+
+ printf("Testing timing ...");
+ tpm_init();
+ TTPM_CHECK(TlclStartupIfNeeded(), 50);
+ TTPM_CHECK(tpm_continue_self_test(), 100);
+ TTPM_CHECK(tpm_self_test_full(), 1000);
+ TTPM_CHECK(tpm_tsc_physical_presence(PRESENCE), 100);
+ TTPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&x, sizeof(x)), 100);
+ TTPM_CHECK(tpm_nv_read_value(INDEX0, (uint8_t *)&x, sizeof(x)), 100);
+ TTPM_CHECK(tpm_extend(0, in, out), 200);
+ TTPM_CHECK(tpm_set_global_lock(), 50);
+ TTPM_CHECK(tpm_tsc_physical_presence(PHYS_PRESENCE), 100);
+ printf("done\n");
+ return 0;
+}
+
+#define TPM_MAX_NV_WRITES_NOOWNER 64
+
+static int test_write_limit(void)
+{
+ printf("Testing writelimit ...\n");
+ int i;
+ uint32_t result;
+
+ tpm_init();
+ TPM_CHECK(TlclStartupIfNeeded());
+ TPM_CHECK(tpm_self_test_full());
+ TPM_CHECK(tpm_tsc_physical_presence(PRESENCE));
+ TPM_CHECK(tpm_force_clear());
+ TPM_CHECK(tpm_physical_enable());
+ TPM_CHECK(tpm_physical_set_deactivated(0));
+
+ for (i = 0; i < TPM_MAX_NV_WRITES_NOOWNER + 2; i++) {
+ printf("\twriting %d\n", i);
+ result = tpm_nv_write_value(INDEX0, (uint8_t *)&i, sizeof(i));
+ switch (result) {
+ case TPM_SUCCESS:
+ break;
+ case TPM_MAXNVWRITES:
+ assert(i >= TPM_MAX_NV_WRITES_NOOWNER);
+ default:
+ error("\tunexpected error code %d (0x%x)\n",
+ result, result);
+ }
+ }
+
+ /* Reset write count */
+ TPM_CHECK(tpm_force_clear());
+ TPM_CHECK(tpm_physical_enable());
+ TPM_CHECK(tpm_physical_set_deactivated(0));
+
+ /* Try writing again. */
+ TPM_CHECK(tpm_nv_write_value(INDEX0, (uint8_t *)&i, sizeof(i)));
+ printf("\tdone\n");
+ return 0;
+}
+
+#define VOIDTEST(XFUNC) \
+ int do_test_##XFUNC(cmd_tbl_t *cmd_tbl, int flag, int argc, \
+ char * const argv[]) \
+ { \
+ return test_##XFUNC(); \
+ }
+
+#define VOIDENT(XNAME) \
+ U_BOOT_CMD_MKENT(XNAME, 0, 1, do_test_##XNAME, "", ""),
+
+VOIDTEST(early_extend)
+VOIDTEST(early_nvram)
+VOIDTEST(early_nvram2)
+VOIDTEST(enable)
+VOIDTEST(fast_enable)
+VOIDTEST(global_lock)
+VOIDTEST(lock)
+VOIDTEST(readonly)
+VOIDTEST(redefine_unowned)
+VOIDTEST(space_perm)
+VOIDTEST(startup)
+VOIDTEST(timing)
+VOIDTEST(write_limit)
+VOIDTEST(timer)
+
+static cmd_tbl_t cmd_cros_tpm_sub[] = {
+ VOIDENT(early_extend)
+ VOIDENT(early_nvram)
+ VOIDENT(early_nvram2)
+ VOIDENT(enable)
+ VOIDENT(fast_enable)
+ VOIDENT(global_lock)
+ VOIDENT(lock)
+ VOIDENT(readonly)
+ VOIDENT(redefine_unowned)
+ VOIDENT(space_perm)
+ VOIDENT(startup)
+ VOIDENT(timing)
+ VOIDENT(write_limit)
+ VOIDENT(timer)
+};
+
+static int do_tpmtest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ cmd_tbl_t *c;
+
+ printf("argc = %d, argv = ", argc);
+ do {
+ int i = 0;
+
+ for (i = 0; i < argc; i++)
+ printf(" %s", argv[i]);
+ printf("\n------\n");
+ } while (0);
+ argc--;
+ argv++;
+ c = find_cmd_tbl(argv[0], cmd_cros_tpm_sub,
+ ARRAY_SIZE(cmd_cros_tpm_sub));
+ return c ? c->cmd(cmdtp, flag, argc, argv) : cmd_usage(cmdtp);
+}
+
+U_BOOT_CMD(tpmtest, 2, 1, do_tpmtest, "TPM tests",
+ "\n\tearly_extend\n"
+ "\tearly_nvram\n"
+ "\tearly_nvram2\n"
+ "\tenable\n"
+ "\tfast_enable\n"
+ "\tglobal_lock\n"
+ "\tlock\n"
+ "\treadonly\n"
+ "\tredefine_unowned\n"
+ "\tspace_perm\n"
+ "\tstartup\n"
+ "\ttiming\n"
+ "\twrite_limit\n");
diff --git a/configs/chromebook_link_defconfig b/configs/chromebook_link_defconfig
index b987f3f52f..985573667a 100644
--- a/configs/chromebook_link_defconfig
+++ b/configs/chromebook_link_defconfig
@@ -11,15 +11,20 @@ CONFIG_HAVE_VGA_BIOS=y
CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
CONFIG_OF_CONTROL=y
CONFIG_DM_PCI=y
CONFIG_SPI_FLASH=y
CONFIG_CMD_CROS_EC=y
CONFIG_CROS_EC=y
CONFIG_CROS_EC_LPC=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_LPC=y
CONFIG_VIDEO_VESA=y
CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
CONFIG_FRAMEBUFFER_VESA_MODE_11A=y
CONFIG_DM_RTC=y
CONFIG_USE_PRIVATE_LIBGCC=y
CONFIG_SYS_VSNPRINTF=y
+CONFIG_TPM=y
diff --git a/configs/chromebox_panther_defconfig b/configs/chromebox_panther_defconfig
index e82c8ecf64..c75b20d24d 100644
--- a/configs/chromebox_panther_defconfig
+++ b/configs/chromebox_panther_defconfig
@@ -11,15 +11,20 @@ CONFIG_HAVE_VGA_BIOS=y
CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
CONFIG_OF_CONTROL=y
CONFIG_DM_PCI=y
CONFIG_SPI_FLASH=y
CONFIG_CMD_CROS_EC=y
CONFIG_CROS_EC=y
CONFIG_CROS_EC_LPC=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_LPC=y
CONFIG_VIDEO_VESA=y
CONFIG_FRAMEBUFFER_SET_VESA_MODE=y
CONFIG_FRAMEBUFFER_VESA_MODE_11A=y
CONFIG_DM_RTC=y
CONFIG_USE_PRIVATE_LIBGCC=y
CONFIG_SYS_VSNPRINTF=y
+CONFIG_TPM=y
diff --git a/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig b/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig
index 37ead03a43..c8ab862edc 100644
--- a/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig
+++ b/configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig
@@ -4,4 +4,8 @@ CONFIG_TARGET_CONTROLCENTERD=y
CONFIG_SYS_EXTRA_OPTIONS="36BIT,SDCARD,DEVELOP"
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_TPM=y
CONFIG_SPI_FLASH=y
+CONFIG_TPM_ATMEL_TWI=y
+CONFIG_TPM_AUTH_SESSIONS=y
+CONFIG_TPM=y
diff --git a/configs/controlcenterd_36BIT_SDCARD_defconfig b/configs/controlcenterd_36BIT_SDCARD_defconfig
index 7166edbf9d..21c0eab53d 100644
--- a/configs/controlcenterd_36BIT_SDCARD_defconfig
+++ b/configs/controlcenterd_36BIT_SDCARD_defconfig
@@ -4,4 +4,8 @@ CONFIG_TARGET_CONTROLCENTERD=y
CONFIG_SYS_EXTRA_OPTIONS="36BIT,SDCARD"
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_TPM=y
CONFIG_SPI_FLASH=y
+CONFIG_TPM_ATMEL_TWI=y
+CONFIG_TPM_AUTH_SESSIONS=y
+CONFIG_TPM=y
diff --git a/configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig b/configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig
index d99fcd4513..c3a0920d7c 100644
--- a/configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig
+++ b/configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig
@@ -6,3 +6,7 @@ CONFIG_SYS_EXTRA_OPTIONS="TRAILBLAZER,SPIFLASH,DEVELOP"
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_TPM=y
+CONFIG_TPM_ATMEL_TWI=y
+CONFIG_TPM_AUTH_SESSIONS=y
+CONFIG_TPM=y
diff --git a/configs/controlcenterd_TRAILBLAZER_defconfig b/configs/controlcenterd_TRAILBLAZER_defconfig
index 3557aea1eb..08aae9ae2d 100644
--- a/configs/controlcenterd_TRAILBLAZER_defconfig
+++ b/configs/controlcenterd_TRAILBLAZER_defconfig
@@ -6,3 +6,7 @@ CONFIG_SYS_EXTRA_OPTIONS="TRAILBLAZER,SPIFLASH"
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_TPM=y
+CONFIG_TPM_ATMEL_TWI=y
+CONFIG_TPM_AUTH_SESSIONS=y
+CONFIG_TPM=y
diff --git a/configs/coreboot-x86_defconfig b/configs/coreboot-x86_defconfig
index df3a624ecd..ebaf86bc7f 100644
--- a/configs/coreboot-x86_defconfig
+++ b/configs/coreboot-x86_defconfig
@@ -9,10 +9,15 @@ CONFIG_TSC_CALIBRATION_BYPASS=y
CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
CONFIG_OF_CONTROL=y
CONFIG_DM_PCI=y
CONFIG_SPI_FLASH=y
CONFIG_NETDEVICES=y
CONFIG_E1000=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_LPC=y
CONFIG_USE_PRIVATE_LIBGCC=y
CONFIG_SYS_VSNPRINTF=y
+CONFIG_TPM=y
diff --git a/configs/nyan-big_defconfig b/configs/nyan-big_defconfig
index 274e955a37..6464c379a4 100644
--- a/configs/nyan-big_defconfig
+++ b/configs/nyan-big_defconfig
@@ -9,16 +9,21 @@ CONFIG_DEFAULT_DEVICE_TREE="tegra124-nyan-big"
# CONFIG_CMD_FPGA is not set
# CONFIG_CMD_SETEXPR is not set
# CONFIG_CMD_NFS is not set
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
CONFIG_SPL_DM=y
CONFIG_SPI_FLASH=y
CONFIG_CMD_CROS_EC=y
CONFIG_CROS_EC=y
CONFIG_CROS_EC_SPI=y
CONFIG_CROS_EC_KEYB=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
CONFIG_TEGRA114_SPI=y
CONFIG_DISPLAY_PORT=y
CONFIG_VIDEO_TEGRA124=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_TPM=y
CONFIG_USE_PRIVATE_LIBGCC=y
CONFIG_SYS_PROMPT="Tegra124 (Nyan-big) # "
diff --git a/configs/peach-pi_defconfig b/configs/peach-pi_defconfig
index 323a2d38b3..56a518556c 100644
--- a/configs/peach-pi_defconfig
+++ b/configs/peach-pi_defconfig
@@ -7,11 +7,15 @@ CONFIG_SPL=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
CONFIG_SPI_FLASH=y
CONFIG_CMD_CROS_EC=y
CONFIG_CROS_EC=y
CONFIG_CROS_EC_SPI=y
CONFIG_CROS_EC_KEYB=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
CONFIG_DM_I2C=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_I2C_CROS_EC_TUNNEL=y
@@ -30,5 +34,6 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_TPM=y
CONFIG_ERRNO_STR=y
CONFIG_SYS_PROMPT="Peach-Pi # "
diff --git a/configs/peach-pit_defconfig b/configs/peach-pit_defconfig
index 6a082968b9..1934bf38a1 100644
--- a/configs/peach-pit_defconfig
+++ b/configs/peach-pit_defconfig
@@ -7,11 +7,15 @@ CONFIG_SPL=y
# CONFIG_CMD_SETEXPR is not set
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
CONFIG_SPI_FLASH=y
CONFIG_CMD_CROS_EC=y
CONFIG_CROS_EC=y
CONFIG_CROS_EC_SPI=y
CONFIG_CROS_EC_KEYB=y
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
CONFIG_DM_I2C=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_I2C_CROS_EC_TUNNEL=y
@@ -30,5 +34,6 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_TPM=y
CONFIG_ERRNO_STR=y
CONFIG_SYS_PROMPT="Peach-Pit # "
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 85ff95df79..e9e1597f9a 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -11,6 +11,8 @@ CONFIG_BOOTSTAGE=y
CONFIG_BOOTSTAGE_REPORT=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
CONFIG_OF_CONTROL=y
CONFIG_OF_HOSTFILE=y
CONFIG_CLK=y
@@ -30,9 +32,13 @@ CONFIG_CROS_EC_KEYB=y
CONFIG_LED=y
CONFIG_LED_GPIO=y
CONFIG_SANDBOX_SERIAL=y
+CONFIG_DM_TPM=y
CONFIG_TPM_TIS_SANDBOX=y
CONFIG_SYS_I2C_SANDBOX=y
CONFIG_SANDBOX_SPI=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_PINCTRL_SANDBOX=y
CONFIG_SANDBOX_GPIO=y
CONFIG_DM_PMIC=y
CONFIG_DM_PMIC_SANDBOX=y
@@ -49,6 +55,7 @@ CONFIG_DM_MMC=y
CONFIG_DM_RTC=y
CONFIG_SYS_VSNPRINTF=y
CONFIG_CMD_DHRYSTONE=y
+CONFIG_TPM=y
CONFIG_ERRNO_STR=y
CONFIG_UNIT_TEST=y
CONFIG_UT_TIME=y
diff --git a/configs/snow_defconfig b/configs/snow_defconfig
index f5decd5c69..32c7c5deab 100644
--- a/configs/snow_defconfig
+++ b/configs/snow_defconfig
@@ -8,6 +8,8 @@ CONFIG_SPL=y
CONFIG_CMD_SOUND=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
CONFIG_SPI_FLASH=y
CONFIG_CMD_CROS_EC=y
CONFIG_CROS_EC=y
@@ -17,6 +19,8 @@ CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_S5P=y
CONFIG_DEBUG_UART_BASE=0x12c30000
CONFIG_DEBUG_UART_CLOCK=100000000
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
CONFIG_DM_I2C=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_I2C_CROS_EC_LDO=y
@@ -41,4 +45,5 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_TPM=y
CONFIG_ERRNO_STR=y
diff --git a/configs/spring_defconfig b/configs/spring_defconfig
index f1d9a58ad1..b20bfed096 100644
--- a/configs/spring_defconfig
+++ b/configs/spring_defconfig
@@ -8,6 +8,8 @@ CONFIG_SPL=y
CONFIG_CMD_SOUND=y
CONFIG_CMD_PMIC=y
CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
CONFIG_SPI_FLASH=y
CONFIG_CMD_CROS_EC=y
CONFIG_CROS_EC=y
@@ -17,6 +19,8 @@ CONFIG_DEBUG_UART=y
CONFIG_DEBUG_UART_S5P=y
CONFIG_DEBUG_UART_BASE=0x12c30000
CONFIG_DEBUG_UART_CLOCK=100000000
+CONFIG_DM_TPM=y
+CONFIG_TPM_TIS_I2C=y
CONFIG_DM_I2C=y
CONFIG_DM_I2C_COMPAT=y
CONFIG_I2C_CROS_EC_LDO=y
@@ -40,4 +44,5 @@ CONFIG_SOUND_MAX98095=y
CONFIG_SOUND_WM8994=y
CONFIG_USB=y
CONFIG_DM_USB=y
+CONFIG_TPM=y
CONFIG_ERRNO_STR=y
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 092bc02b30..63c92c594a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,66 +1,68 @@
menu "Device Drivers"
-source "drivers/clk/Kconfig"
-
source "drivers/core/Kconfig"
+# types of drivers sorted in alphabetical order
+
+source "drivers/block/Kconfig"
+
+source "drivers/clk/Kconfig"
+
source "drivers/cpu/Kconfig"
-source "drivers/demo/Kconfig"
+source "drivers/crypto/Kconfig"
-source "drivers/pci/Kconfig"
+source "drivers/demo/Kconfig"
-source "drivers/pcmcia/Kconfig"
+source "drivers/dfu/Kconfig"
-source "drivers/mtd/Kconfig"
+source "drivers/dma/Kconfig"
-source "drivers/block/Kconfig"
+source "drivers/gpio/Kconfig"
-source "drivers/misc/Kconfig"
+source "drivers/hwmon/Kconfig"
-source "drivers/net/Kconfig"
+source "drivers/i2c/Kconfig"
source "drivers/input/Kconfig"
source "drivers/led/Kconfig"
-source "drivers/serial/Kconfig"
+source "drivers/misc/Kconfig"
-source "drivers/tpm/Kconfig"
+source "drivers/mmc/Kconfig"
-source "drivers/i2c/Kconfig"
+source "drivers/mtd/Kconfig"
-source "drivers/spi/Kconfig"
+source "drivers/net/Kconfig"
-source "drivers/gpio/Kconfig"
+source "drivers/pci/Kconfig"
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pinctrl/Kconfig"
source "drivers/power/Kconfig"
source "drivers/ram/Kconfig"
-source "drivers/hwmon/Kconfig"
-
-source "drivers/watchdog/Kconfig"
+source "drivers/rtc/Kconfig"
-source "drivers/video/Kconfig"
+source "drivers/serial/Kconfig"
source "drivers/sound/Kconfig"
-source "drivers/usb/Kconfig"
-
-source "drivers/dfu/Kconfig"
-
-source "drivers/mmc/Kconfig"
+source "drivers/spi/Kconfig"
-source "drivers/rtc/Kconfig"
+source "drivers/thermal/Kconfig"
-source "drivers/dma/Kconfig"
+source "drivers/tpm/Kconfig"
-source "drivers/crypto/Kconfig"
+source "drivers/usb/Kconfig"
-source "drivers/thermal/Kconfig"
+source "drivers/video/Kconfig"
-endmenu
+source "drivers/watchdog/Kconfig"
config PHYS_TO_BUS
bool "Custom physical to bus address mapping"
@@ -69,3 +71,5 @@ config PHYS_TO_BUS
peripheral DMA master accesses. If yours does, select this option in
your platform's Kconfig, and implement the appropriate mapping
functions in your platform's support code.
+
+endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index a721ec86df..9d0a5959a8 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_$(SPL_)DM) += core/
obj-$(CONFIG_$(SPL_)CLK) += clk/
obj-$(CONFIG_$(SPL_)LED) += led/
+obj-$(CONFIG_$(SPL_)PINCTRL) += pinctrl/
obj-$(CONFIG_$(SPL_)RAM) += ram/
ifdef CONFIG_SPL_BUILD
diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 788f8b739b..41f4e695e8 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -105,4 +105,19 @@ config DEBUG_DEVRES
If you are unsure about this, Say N here.
+config SIMPLE_BUS
+ bool "Support simple-bus driver"
+ depends on DM && OF_CONTROL
+ default y
+ help
+ Supports the 'simple-bus' driver, which is used on some systems.
+
+config SPL_SIMPLE_BUS
+ bool "Support simple-bus driver in SPL"
+ depends on SPL_DM && SPL_OF_CONTROL
+ default n
+ help
+ Supports the 'simple-bus' driver, which is used on some systems
+ in SPL.
+
endmenu
diff --git a/drivers/core/Makefile b/drivers/core/Makefile
index 11e0276e56..f19f67d30f 100644
--- a/drivers/core/Makefile
+++ b/drivers/core/Makefile
@@ -6,10 +6,8 @@
obj-y += device.o lists.o root.o uclass.o util.o
obj-$(CONFIG_DEVRES) += devres.o
-ifndef CONFIG_SPL_BUILD
-obj-$(CONFIG_$(SPL_)OF_CONTROL) += simple-bus.o
-endif
obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE) += device-remove.o
+obj-$(CONFIG_$(SPL_)SIMPLE_BUS) += simple-bus.o
obj-$(CONFIG_DM) += dump.o
obj-$(CONFIG_REGMAP) += regmap.o
obj-$(CONFIG_SYSCON) += syscon-uclass.o
diff --git a/drivers/core/device.c b/drivers/core/device.c
index a31e25f6b5..a6cd93698f 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -15,6 +15,7 @@
#include <dm/device.h>
#include <dm/device-internal.h>
#include <dm/lists.h>
+#include <dm/pinctrl.h>
#include <dm/platdata.h>
#include <dm/uclass.h>
#include <dm/uclass-internal.h>
@@ -32,7 +33,8 @@ int device_bind(struct udevice *parent, const struct driver *drv,
struct uclass *uc;
int size, ret = 0;
- *devp = NULL;
+ if (devp)
+ *devp = NULL;
if (!name)
return -EINVAL;
@@ -133,7 +135,8 @@ int device_bind(struct udevice *parent, const struct driver *drv,
if (parent)
dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
- *devp = dev;
+ if (devp)
+ *devp = dev;
dev->flags |= DM_FLAG_BOUND;
@@ -284,6 +287,9 @@ int device_probe_child(struct udevice *dev, void *parent_priv)
dev->flags |= DM_FLAG_ACTIVATED;
+ /* continue regardless of the result of pinctrl */
+ pinctrl_select_state(dev, "default");
+
ret = uclass_pre_probe_device(dev);
if (ret)
goto fail;
@@ -574,7 +580,7 @@ fdt_addr_t dev_get_addr(struct udevice *dev)
fdt_addr_t addr;
addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
- if (addr != FDT_ADDR_T_NONE) {
+ if (CONFIG_IS_ENABLED(SIMPLE_BUS) && addr != FDT_ADDR_T_NONE) {
if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS)
addr = simple_bus_translate(dev->parent, addr);
}
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
index 49b1054660..17fcfbf4d3 100644
--- a/drivers/gpio/s5p_gpio.c
+++ b/drivers/gpio/s5p_gpio.c
@@ -327,8 +327,7 @@ static int gpio_exynos_bind(struct udevice *parent)
if (plat)
return 0;
- base = (struct s5p_gpio_bank *)fdtdec_get_addr(gd->fdt_blob,
- parent->of_offset, "reg");
+ base = (struct s5p_gpio_bank *)dev_get_addr(parent);
for (node = fdt_first_subnode(blob, parent->of_offset), bank = base;
node > 0;
node = fdt_next_subnode(blob, node), bank++) {
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c
index 57b78e55e2..9d8f11ef30 100644
--- a/drivers/gpio/sunxi_gpio.c
+++ b/drivers/gpio/sunxi_gpio.c
@@ -285,8 +285,7 @@ static int gpio_sunxi_bind(struct udevice *parent)
no_banks = SUNXI_GPIO_BANKS;
}
- ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob,
- parent->of_offset, "reg");
+ ctlr = (struct sunxi_gpio_reg *)dev_get_addr(parent);
for (bank = 0; bank < no_banks; bank++) {
struct sunxi_gpio_platdata *plat;
struct udevice *dev;
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c
index 8017e359f5..4921f0ff42 100644
--- a/drivers/gpio/tegra_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -343,8 +343,7 @@ static int gpio_tegra_bind(struct udevice *parent)
if (!fdt_getprop(gd->fdt_blob, parent->of_offset, "interrupts", &len))
return -EINVAL;
bank_count = len / 3 / sizeof(u32);
- ctlr = (struct gpio_ctlr *)fdtdec_get_addr(gd->fdt_blob,
- parent->of_offset, "reg");
+ ctlr = (struct gpio_ctlr *)dev_get_addr(parent);
}
#endif
for (bank = 0; bank < bank_count; bank++) {
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index ae6f436385..dc9b661c1c 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -1397,12 +1397,10 @@ static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
if (i2c_bus->is_highspeed) {
flags = PINMUX_FLAG_HS_MODE;
- i2c_bus->hsregs = (struct exynos5_hsi2c *)
- fdtdec_get_addr(blob, node, "reg");
+ i2c_bus->hsregs = (struct exynos5_hsi2c *)dev_get_addr(dev);
} else {
flags = 0;
- i2c_bus->regs = (struct s3c24x0_i2c *)
- fdtdec_get_addr(blob, node, "reg");
+ i2c_bus->regs = (struct s3c24x0_i2c *)dev_get_addr(dev);
}
i2c_bus->id = pinmux_decode_periph_id(blob, node);
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index a4289788a6..2fa07f9c57 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -339,7 +339,7 @@ static int tegra_i2c_probe(struct udevice *dev)
i2c_bus->id = dev->seq;
i2c_bus->type = dev_get_driver_data(dev);
- i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg");
+ i2c_bus->regs = (struct i2c_ctlr *)dev_get_addr(dev);
/*
* We don't have a binding for pinmux yet. Leave it out for now. So
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
new file mode 100644
index 0000000000..30b8e452ef
--- /dev/null
+++ b/drivers/pinctrl/Kconfig
@@ -0,0 +1,109 @@
+#
+# PINCTRL infrastructure and drivers
+#
+
+menu "Pin controllers"
+
+config PINCTRL
+ bool "Support pin controllers"
+ depends on DM
+ help
+ This enables the basic support for pinctrl framework. You may want
+ to enable some more options depending on what you want to do.
+
+config PINCTRL_FULL
+ bool "Support full pin controllers"
+ depends on PINCTRL && OF_CONTROL
+ default y
+ help
+ This provides Linux-compatible device tree interface for the pinctrl
+ subsystem. This feature depends on device tree configuration because
+ it parses a device tree to look for the pinctrl device which the
+ peripheral device is associated with.
+
+ If this option is disabled (it is the only possible choice for non-DT
+ boards), the pinctrl core provides no systematic mechanism for
+ identifying peripheral devices, applying needed pinctrl settings.
+ It is totally up to the implementation of each low-level driver.
+ You can save memory footprint in return for some limitations.
+
+config PINCTRL_GENERIC
+ bool "Support generic pin controllers"
+ depends on PINCTRL_FULL
+ default y
+ help
+ Say Y here if you want to use the pinctrl subsystem through the
+ generic DT interface. If enabled, some functions become available
+ to parse common properties such as "pins", "groups", "functions" and
+ some pin configuration parameters. It would be easier if you only
+ need the generic DT interface for pin muxing and pin configuration.
+ If you need to handle vendor-specific DT properties, you can disable
+ this option and implement your own set_state callback in the pinctrl
+ operations.
+
+config PINMUX
+ bool "Support pin multiplexing controllers"
+ depends on PINCTRL_GENERIC
+ default y
+ help
+ This option enables pin multiplexing through the generic pinctrl
+ framework.
+
+config PINCONF
+ bool "Support pin configuration controllers"
+ depends on PINCTRL_GENERIC
+ help
+ This option enables pin configuration through the generic pinctrl
+ framework.
+
+config SPL_PINCTRL
+ bool "Support pin controlloers in SPL"
+ depends on SPL && SPL_DM
+ help
+ This option is an SPL-variant of the PINCTRL option.
+ See the help of PINCTRL for details.
+
+config SPL_PINCTRL_FULL
+ bool "Support full pin controllers in SPL"
+ depends on SPL_PINCTRL && SPL_OF_CONTROL
+ default y
+ help
+ This option is an SPL-variant of the PINCTRL_FULL option.
+ See the help of PINCTRL_FULL for details.
+
+config SPL_PINCTRL_GENERIC
+ bool "Support generic pin controllers in SPL"
+ depends on SPL_PINCTRL_FULL
+ default y
+ help
+ This option is an SPL-variant of the PINCTRL_GENERIC option.
+ See the help of PINCTRL_GENERIC for details.
+
+config SPL_PINMUX
+ bool "Support pin multiplexing controllers in SPL"
+ depends on SPL_PINCTRL_GENERIC
+ default y
+ help
+ This option is an SPL-variant of the PINMUX option.
+ See the help of PINMUX for details.
+
+config SPL_PINCONF
+ bool "Support pin configuration controllers in SPL"
+ depends on SPL_PINCTRL_GENERIC
+ help
+ This option is an SPL-variant of the PINCONF option.
+ See the help of PINCONF for details.
+
+if PINCTRL || SPL_PINCTRL
+
+config PINCTRL_SANDBOX
+ bool "Sandbox pinctrl driver"
+ depends on SANDBOX
+ help
+ This enables pinctrl driver for sandbox. Currently, this driver
+ actually does nothing but print debug messages when pinctrl
+ operations are invoked.
+
+endif
+
+endmenu
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
new file mode 100644
index 0000000000..35decf49c3
--- /dev/null
+++ b/drivers/pinctrl/Makefile
@@ -0,0 +1,4 @@
+obj-y += pinctrl-uclass.o
+obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o
+
+obj-$(CONFIG_PINCTRL_SANDBOX) += pinctrl-sandbox.o
diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c
new file mode 100644
index 0000000000..e86b72a8de
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-generic.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compat.h>
+#include <dm/device.h>
+#include <dm/pinctrl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * pinctrl_pin_name_to_selector() - return the pin selector for a pin
+ *
+ * @dev: pin controller device
+ * @pin: the pin name to look up
+ * @return: pin selector, or negative error code on failure
+ */
+static int pinctrl_pin_name_to_selector(struct udevice *dev, const char *pin)
+{
+ const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+ unsigned npins, selector;
+
+ if (!ops->get_pins_count || !ops->get_pin_name) {
+ dev_dbg(dev, "get_pins_count or get_pin_name missing\n");
+ return -ENOSYS;
+ }
+
+ npins = ops->get_pins_count(dev);
+
+ /* See if this pctldev has this pin */
+ for (selector = 0; selector < npins; selector++) {
+ const char *pname = ops->get_pin_name(dev, selector);
+
+ if (!strcmp(pin, pname))
+ return selector;
+ }
+
+ return -ENOSYS;
+}
+
+/**
+ * pinctrl_group_name_to_selector() - return the group selector for a group
+ *
+ * @dev: pin controller device
+ * @group: the pin group name to look up
+ * @return: pin group selector, or negative error code on failure
+ */
+static int pinctrl_group_name_to_selector(struct udevice *dev,
+ const char *group)
+{
+ const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+ unsigned ngroups, selector;
+
+ if (!ops->get_groups_count || !ops->get_group_name) {
+ dev_dbg(dev, "get_groups_count or get_group_name missing\n");
+ return -ENOSYS;
+ }
+
+ ngroups = ops->get_groups_count(dev);
+
+ /* See if this pctldev has this group */
+ for (selector = 0; selector < ngroups; selector++) {
+ const char *gname = ops->get_group_name(dev, selector);
+
+ if (!strcmp(group, gname))
+ return selector;
+ }
+
+ return -ENOSYS;
+}
+
+#if CONFIG_IS_ENABLED(PINMUX)
+/**
+ * pinmux_func_name_to_selector() - return the function selector for a function
+ *
+ * @dev: pin controller device
+ * @function: the function name to look up
+ * @return: function selector, or negative error code on failure
+ */
+static int pinmux_func_name_to_selector(struct udevice *dev,
+ const char *function)
+{
+ const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+ unsigned nfuncs, selector = 0;
+
+ if (!ops->get_functions_count || !ops->get_function_name) {
+ dev_dbg(dev,
+ "get_functions_count or get_function_name missing\n");
+ return -ENOSYS;
+ }
+
+ nfuncs = ops->get_functions_count(dev);
+
+ /* See if this pctldev has this function */
+ for (selector = 0; selector < nfuncs; selector++) {
+ const char *fname = ops->get_function_name(dev, selector);
+
+ if (!strcmp(function, fname))
+ return selector;
+ }
+
+ return -ENOSYS;
+}
+
+/**
+ * pinmux_enable_setting() - enable pin-mux setting for a certain pin/group
+ *
+ * @dev: pin controller device
+ * @is_group: target of operation (true: pin group, false: pin)
+ * @selector: pin selector or group selector, depending on @is_group
+ * @func_selector: function selector
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinmux_enable_setting(struct udevice *dev, bool is_group,
+ unsigned selector, unsigned func_selector)
+{
+ const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+ if (is_group) {
+ if (!ops->pinmux_group_set) {
+ dev_dbg(dev, "pinmux_group_set op missing\n");
+ return -ENOSYS;
+ }
+
+ return ops->pinmux_group_set(dev, selector, func_selector);
+ } else {
+ if (!ops->pinmux_set) {
+ dev_dbg(dev, "pinmux_set op missing\n");
+ return -ENOSYS;
+ }
+ return ops->pinmux_set(dev, selector, func_selector);
+ }
+}
+#else
+static int pinmux_func_name_to_selector(struct udevice *dev,
+ const char *function)
+{
+ return 0;
+}
+
+static int pinmux_enable_setting(struct udevice *dev, bool is_group,
+ unsigned selector, unsigned func_selector)
+{
+ return 0;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(PINCONF)
+/**
+ * pinconf_prop_name_to_param() - return parameter ID for a property name
+ *
+ * @dev: pin controller device
+ * @property: property name in DTS, such as "bias-pull-up", "slew-rate", etc.
+ * @default_value: return default value in case no value is specified in DTS
+ * @return: return pamater ID, or negative error code on failure
+ */
+static int pinconf_prop_name_to_param(struct udevice *dev,
+ const char *property, u32 *default_value)
+{
+ const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+ const struct pinconf_param *p, *end;
+
+ if (!ops->pinconf_num_params || !ops->pinconf_params) {
+ dev_dbg(dev, "pinconf_num_params or pinconf_params missing\n");
+ return -ENOSYS;
+ }
+
+ p = ops->pinconf_params;
+ end = p + ops->pinconf_num_params;
+
+ /* See if this pctldev supports this parameter */
+ for (; p < end; p++) {
+ if (!strcmp(property, p->property)) {
+ *default_value = p->default_value;
+ return p->param;
+ }
+ }
+
+ return -ENOSYS;
+}
+
+/**
+ * pinconf_enable_setting() - apply pin configuration for a certain pin/group
+ *
+ * @dev: pin controller device
+ * @is_group: target of operation (true: pin group, false: pin)
+ * @selector: pin selector or group selector, depending on @is_group
+ * @param: configuration paramter
+ * @argument: argument taken by some configuration parameters
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinconf_enable_setting(struct udevice *dev, bool is_group,
+ unsigned selector, unsigned param,
+ u32 argument)
+{
+ const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+ if (is_group) {
+ if (!ops->pinconf_group_set) {
+ dev_dbg(dev, "pinconf_group_set op missing\n");
+ return -ENOSYS;
+ }
+
+ return ops->pinconf_group_set(dev, selector, param,
+ argument);
+ } else {
+ if (!ops->pinconf_set) {
+ dev_dbg(dev, "pinconf_set op missing\n");
+ return -ENOSYS;
+ }
+ return ops->pinconf_set(dev, selector, param, argument);
+ }
+}
+#else
+static int pinconf_prop_name_to_param(struct udevice *dev,
+ const char *property, u32 *default_value)
+{
+ return -ENOSYS;
+}
+
+static int pinconf_enable_setting(struct udevice *dev, bool is_group,
+ unsigned selector, unsigned param,
+ u32 argument)
+{
+ return 0;
+}
+#endif
+
+/**
+ * pinctrl_generic_set_state_one() - set state for a certain pin/group
+ * Apply all pin multiplexing and pin configurations specified by @config
+ * for a given pin or pin group.
+ *
+ * @dev: pin controller device
+ * @config: pseudo device pointing to config node
+ * @is_group: target of operation (true: pin group, false: pin)
+ * @selector: pin selector or group selector, depending on @is_group
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_generic_set_state_one(struct udevice *dev,
+ struct udevice *config,
+ bool is_group, unsigned selector)
+{
+ const void *fdt = gd->fdt_blob;
+ int node_offset = config->of_offset;
+ const char *propname;
+ const void *value;
+ int prop_offset, len, func_selector, param, ret;
+ u32 arg, default_val;
+
+ for (prop_offset = fdt_first_property_offset(fdt, node_offset);
+ prop_offset > 0;
+ prop_offset = fdt_next_property_offset(fdt, prop_offset)) {
+ value = fdt_getprop_by_offset(fdt, prop_offset,
+ &propname, &len);
+ if (!value)
+ return -EINVAL;
+
+ if (!strcmp(propname, "function")) {
+ func_selector = pinmux_func_name_to_selector(dev,
+ value);
+ if (func_selector < 0)
+ return func_selector;
+ ret = pinmux_enable_setting(dev, is_group,
+ selector,
+ func_selector);
+ } else {
+ param = pinconf_prop_name_to_param(dev, propname,
+ &default_val);
+ if (param < 0)
+ continue; /* just skip unknown properties */
+
+ if (len >= sizeof(fdt32_t))
+ arg = fdt32_to_cpu(*(fdt32_t *)value);
+ else
+ arg = default_val;
+
+ ret = pinconf_enable_setting(dev, is_group,
+ selector, param, arg);
+ }
+
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * pinctrl_generic_set_state_subnode() - apply all settings in config node
+ *
+ * @dev: pin controller device
+ * @config: pseudo device pointing to config node
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_generic_set_state_subnode(struct udevice *dev,
+ struct udevice *config)
+{
+ const void *fdt = gd->fdt_blob;
+ int node = config->of_offset;
+ const char *subnode_target_type = "pins";
+ bool is_group = false;
+ const char *name;
+ int strings_count, selector, i, ret;
+
+ strings_count = fdt_count_strings(fdt, node, subnode_target_type);
+ if (strings_count < 0) {
+ subnode_target_type = "groups";
+ is_group = true;
+ strings_count = fdt_count_strings(fdt, node,
+ subnode_target_type);
+ if (strings_count < 0)
+ return -EINVAL;
+ }
+
+ for (i = 0; i < strings_count; i++) {
+ ret = fdt_get_string_index(fdt, node, subnode_target_type,
+ i, &name);
+ if (ret < 0)
+ return -EINVAL;
+
+ if (is_group)
+ selector = pinctrl_group_name_to_selector(dev, name);
+ else
+ selector = pinctrl_pin_name_to_selector(dev, name);
+ if (selector < 0)
+ return selector;
+
+ ret = pinctrl_generic_set_state_one(dev, config,
+ is_group, selector);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int pinctrl_generic_set_state(struct udevice *dev, struct udevice *config)
+{
+ struct udevice *child;
+ int ret;
+
+ ret = pinctrl_generic_set_state_subnode(dev, config);
+ if (ret)
+ return ret;
+
+ for (device_find_first_child(config, &child);
+ child;
+ device_find_next_child(&child)) {
+ ret = pinctrl_generic_set_state_subnode(dev, child);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/pinctrl/pinctrl-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c
new file mode 100644
index 0000000000..ab03d8bad4
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-sandbox.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <dm/device.h>
+#include <dm/pinctrl.h>
+
+static const char * const sandbox_pins[] = {
+ "SCL",
+ "SDA",
+ "TX",
+ "RX",
+};
+
+static const char * const sandbox_groups[] = {
+ "i2c",
+ "serial_a",
+ "serial_b",
+ "spi",
+};
+
+static const char * const sandbox_functions[] = {
+ "i2c",
+ "serial",
+ "spi",
+};
+
+static const struct pinconf_param sandbox_conf_params[] = {
+ { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
+ { "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
+ { "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
+ { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
+ { "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
+ { "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
+ { "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
+ { "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
+ { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
+ { "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
+ { "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
+};
+
+static int sandbox_get_pins_count(struct udevice *dev)
+{
+ return ARRAY_SIZE(sandbox_pins);
+}
+
+static const char *sandbox_get_pin_name(struct udevice *dev, unsigned selector)
+{
+ return sandbox_pins[selector];
+}
+
+static int sandbox_get_groups_count(struct udevice *dev)
+{
+ return ARRAY_SIZE(sandbox_groups);
+}
+
+static const char *sandbox_get_group_name(struct udevice *dev,
+ unsigned selector)
+{
+ return sandbox_groups[selector];
+}
+
+static int sandbox_get_functions_count(struct udevice *dev)
+{
+ return ARRAY_SIZE(sandbox_functions);
+}
+
+static const char *sandbox_get_function_name(struct udevice *dev,
+ unsigned selector)
+{
+ return sandbox_functions[selector];
+}
+
+static int sandbox_pinmux_set(struct udevice *dev, unsigned pin_selector,
+ unsigned func_selector)
+{
+ debug("sandbox pinmux: pin = %d (%s), function = %d (%s)\n",
+ pin_selector, sandbox_get_pin_name(dev, pin_selector),
+ func_selector, sandbox_get_function_name(dev, func_selector));
+
+ return 0;
+}
+
+static int sandbox_pinmux_group_set(struct udevice *dev,
+ unsigned group_selector,
+ unsigned func_selector)
+{
+ debug("sandbox pinmux: group = %d (%s), function = %d (%s)\n",
+ group_selector, sandbox_get_group_name(dev, group_selector),
+ func_selector, sandbox_get_function_name(dev, func_selector));
+
+ return 0;
+}
+
+static int sandbox_pinconf_set(struct udevice *dev, unsigned pin_selector,
+ unsigned param, unsigned argument)
+{
+ debug("sandbox pinconf: pin = %d (%s), param = %d, arg = %d\n",
+ pin_selector, sandbox_get_pin_name(dev, pin_selector),
+ param, argument);
+
+ return 0;
+}
+
+static int sandbox_pinconf_group_set(struct udevice *dev,
+ unsigned group_selector,
+ unsigned param, unsigned argument)
+{
+ debug("sandbox pinconf: group = %d (%s), param = %d, arg = %d\n",
+ group_selector, sandbox_get_group_name(dev, group_selector),
+ param, argument);
+
+ return 0;
+}
+
+const struct pinctrl_ops sandbox_pinctrl_ops = {
+ .get_pins_count = sandbox_get_pins_count,
+ .get_pin_name = sandbox_get_pin_name,
+ .get_groups_count = sandbox_get_groups_count,
+ .get_group_name = sandbox_get_group_name,
+ .get_functions_count = sandbox_get_functions_count,
+ .get_function_name = sandbox_get_function_name,
+ .pinmux_set = sandbox_pinmux_set,
+ .pinmux_group_set = sandbox_pinmux_group_set,
+ .pinconf_num_params = ARRAY_SIZE(sandbox_conf_params),
+ .pinconf_params = sandbox_conf_params,
+ .pinconf_set = sandbox_pinconf_set,
+ .pinconf_group_set = sandbox_pinconf_group_set,
+ .set_state = pinctrl_generic_set_state,
+};
+
+static const struct udevice_id sandbox_pinctrl_match[] = {
+ { .compatible = "sandbox,pinctrl" },
+ { /* sentinel */ }
+};
+
+U_BOOT_DRIVER(sandbox_pinctrl) = {
+ .name = "sandbox_pinctrl",
+ .id = UCLASS_PINCTRL,
+ .of_match = sandbox_pinctrl_match,
+ .ops = &sandbox_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
new file mode 100644
index 0000000000..d96c201e83
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <linux/err.h>
+#include <linux/list.h>
+#include <dm/device.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <dm/uclass.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_IS_ENABLED(PINCTRL_FULL)
+/**
+ * pinctrl_config_one() - apply pinctrl settings for a single node
+ *
+ * @config: pin configuration node
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_config_one(struct udevice *config)
+{
+ struct udevice *pctldev;
+ const struct pinctrl_ops *ops;
+
+ pctldev = config;
+ for (;;) {
+ pctldev = dev_get_parent(pctldev);
+ if (!pctldev) {
+ dev_err(config, "could not find pctldev\n");
+ return -EINVAL;
+ }
+ if (pctldev->uclass->uc_drv->id == UCLASS_PINCTRL)
+ break;
+ }
+
+ ops = pinctrl_get_ops(pctldev);
+ return ops->set_state(pctldev, config);
+}
+
+/**
+ * pinctrl_select_state_full() - full implementation of pinctrl_select_state
+ *
+ * @dev: peripheral device
+ * @statename: state name, like "default"
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
+{
+ const void *fdt = gd->fdt_blob;
+ int node = dev->of_offset;
+ char propname[32]; /* long enough */
+ const fdt32_t *list;
+ uint32_t phandle;
+ int config_node;
+ struct udevice *config;
+ int state, size, i, ret;
+
+ state = fdt_find_string(fdt, node, "pinctrl-names", statename);
+ if (state < 0) {
+ char *end;
+ /*
+ * If statename is not found in "pinctrl-names",
+ * assume statename is just the integer state ID.
+ */
+ state = simple_strtoul(statename, &end, 10);
+ if (*end)
+ return -EINVAL;
+ }
+
+ snprintf(propname, sizeof(propname), "pinctrl-%d", state);
+ list = fdt_getprop(fdt, node, propname, &size);
+ if (!list)
+ return -EINVAL;
+
+ size /= sizeof(*list);
+ for (i = 0; i < size; i++) {
+ phandle = fdt32_to_cpu(*list++);
+
+ config_node = fdt_node_offset_by_phandle(fdt, phandle);
+ if (config_node < 0) {
+ dev_err(dev, "prop %s index %d invalid phandle\n",
+ propname, i);
+ return -EINVAL;
+ }
+ ret = uclass_get_device_by_of_offset(UCLASS_PINCONFIG,
+ config_node, &config);
+ if (ret)
+ return ret;
+
+ ret = pinctrl_config_one(config);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * pinconfig_post-bind() - post binding for PINCONFIG uclass
+ * Recursively bind its children as pinconfig devices.
+ *
+ * @dev: pinconfig device
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinconfig_post_bind(struct udevice *dev)
+{
+ const void *fdt = gd->fdt_blob;
+ int offset = dev->of_offset;
+ const char *name;
+ int ret;
+
+ for (offset = fdt_first_subnode(fdt, offset);
+ offset > 0;
+ offset = fdt_next_subnode(fdt, offset)) {
+ /*
+ * If this node has "compatible" property, this is not
+ * a pin configuration node, but a normal device. skip.
+ */
+ fdt_get_property(fdt, offset, "compatible", &ret);
+ if (ret >= 0)
+ continue;
+
+ if (ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ name = fdt_get_name(fdt, offset, NULL);
+ if (!name)
+ return -EINVAL;
+ ret = device_bind_driver_to_node(dev, "pinconfig", name,
+ offset, NULL);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+UCLASS_DRIVER(pinconfig) = {
+ .id = UCLASS_PINCONFIG,
+ .post_bind = pinconfig_post_bind,
+ .name = "pinconfig",
+};
+
+U_BOOT_DRIVER(pinconfig_generic) = {
+ .name = "pinconfig",
+ .id = UCLASS_PINCONFIG,
+};
+
+#else
+static int pinctrl_select_state_full(struct udevice *dev, const char *statename)
+{
+ return -ENODEV;
+}
+
+static int pinconfig_post_bind(struct udevice *dev)
+{
+ return 0;
+}
+#endif
+
+/**
+ * pinctrl_select_state_simple() - simple implementation of pinctrl_select_state
+ *
+ * @dev: peripheral device
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_select_state_simple(struct udevice *dev)
+{
+ struct udevice *pctldev;
+ struct pinctrl_ops *ops;
+ int ret;
+
+ /*
+ * For simplicity, assume the first device of PINCTRL uclass
+ * is the correct one. This is most likely OK as there is
+ * usually only one pinctrl device on the system.
+ */
+ ret = uclass_get_device(UCLASS_PINCTRL, 0, &pctldev);
+ if (ret)
+ return ret;
+
+ ops = pinctrl_get_ops(pctldev);
+ if (!ops->set_state_simple) {
+ dev_dbg(dev, "set_state_simple op missing\n");
+ return -ENOSYS;
+ }
+
+ return ops->set_state_simple(pctldev, dev);
+}
+
+int pinctrl_select_state(struct udevice *dev, const char *statename)
+{
+ /*
+ * Try full-implemented pinctrl first.
+ * If it fails or is not implemented, try simple one.
+ */
+ if (pinctrl_select_state_full(dev, statename))
+ return pinctrl_select_state_simple(dev);
+
+ return 0;
+}
+
+/**
+ * pinconfig_post-bind() - post binding for PINCTRL uclass
+ * Recursively bind child nodes as pinconfig devices in case of full pinctrl.
+ *
+ * @dev: pinctrl device
+ * @return: 0 on success, or negative error code on failure
+ */
+static int pinctrl_post_bind(struct udevice *dev)
+{
+ const struct pinctrl_ops *ops = pinctrl_get_ops(dev);
+
+ if (!ops) {
+ dev_dbg(dev, "ops is not set. Do not bind.\n");
+ return -EINVAL;
+ }
+
+ /*
+ * If set_state callback is set, we assume this pinctrl driver is the
+ * full implementation. In this case, its child nodes should be bound
+ * so that peripheral devices can easily search in parent devices
+ * during later DT-parsing.
+ */
+ if (ops->set_state)
+ return pinconfig_post_bind(dev);
+
+ return 0;
+}
+
+UCLASS_DRIVER(pinctrl) = {
+ .id = UCLASS_PINCTRL,
+ .post_bind = pinctrl_post_bind,
+ .name = "pinctrl",
+};
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 2b6d1e4638..6275a11a0c 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -364,7 +364,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
fdt_addr_t addr;
/* try Processor Local Bus device first */
- addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+ addr = dev_get_addr(dev);
#ifdef CONFIG_PCI
if (addr == FDT_ADDR_T_NONE) {
/* then try pci device */
diff --git a/drivers/serial/serial_arc.c b/drivers/serial/serial_arc.c
index 54e596c4ed..7dbb49f814 100644
--- a/drivers/serial/serial_arc.c
+++ b/drivers/serial/serial_arc.c
@@ -133,8 +133,7 @@ static int arc_serial_ofdata_to_platdata(struct udevice *dev)
struct arc_serial_platdata *plat = dev_get_platdata(dev);
DECLARE_GLOBAL_DATA_PTR;
- plat->reg = (struct arc_serial_regs *)fdtdec_get_addr(gd->fdt_blob,
- dev->of_offset, "reg");
+ plat->reg = (struct arc_serial_regs *)dev_get_addr(dev);
plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"clock-frequency", 0);
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index 917b6034d3..ecf3bc0240 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -365,7 +365,7 @@ static int pl01x_serial_ofdata_to_platdata(struct udevice *dev)
struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
fdt_addr_t addr;
- addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+ addr = dev_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c
index 21cb566c29..3f0b588254 100644
--- a/drivers/serial/serial_s5p.c
+++ b/drivers/serial/serial_s5p.c
@@ -169,7 +169,7 @@ static int s5p_serial_ofdata_to_platdata(struct udevice *dev)
struct s5p_serial_platdata *plat = dev->platdata;
fdt_addr_t addr;
- addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+ addr = dev_get_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 8f5c0fc802..86ee90f4be 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -134,7 +134,7 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus)
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
- plat->regs = (struct dw_spi *)fdtdec_get_addr(blob, node, "reg");
+ plat->regs = (struct dw_spi *)dev_get_addr(bus);
/* Use 500KHz as a suitable default */
plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index 418b48120a..44948c3736 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -255,7 +255,7 @@ static int exynos_spi_ofdata_to_platdata(struct udevice *bus)
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
- plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg");
+ plat->regs = (struct exynos_spi *)dev_get_addr(bus);
plat->periph_id = pinmux_decode_periph_id(blob, node);
if (plat->periph_id == PERIPH_ID_NONE) {
diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c
index 3881b2e8a5..887edd801a 100644
--- a/drivers/spi/fsl_dspi.c
+++ b/drivers/spi/fsl_dspi.c
@@ -654,7 +654,7 @@ static int fsl_dspi_ofdata_to_platdata(struct udevice *bus)
plat->num_chipselect =
fdtdec_get_int(blob, node, "num-cs", FSL_DSPI_MAX_CHIPSELECT);
- addr = fdtdec_get_addr(blob, node, "reg");
+ addr = dev_get_addr(bus);
if (addr == FDT_ADDR_T_NONE) {
debug("DSPI: Can't get base address or size\n");
return -ENOMEM;
diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c
index d7eecd5bc6..a965f80aeb 100644
--- a/drivers/spi/tegra114_spi.c
+++ b/drivers/spi/tegra114_spi.c
@@ -118,7 +118,7 @@ static int tegra114_spi_ofdata_to_platdata(struct udevice *bus)
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
- plat->base = fdtdec_get_addr(blob, node, "reg");
+ plat->base = dev_get_addr(bus);
plat->periph_id = clock_decode_periph_id(blob, node);
if (plat->periph_id == PERIPH_ID_NONE) {
diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c
index 82c1b84f3b..afa0848dcb 100644
--- a/drivers/spi/tegra20_sflash.c
+++ b/drivers/spi/tegra20_sflash.c
@@ -90,7 +90,7 @@ static int tegra20_sflash_ofdata_to_platdata(struct udevice *bus)
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
- plat->base = fdtdec_get_addr(blob, node, "reg");
+ plat->base = dev_get_addr(bus);
plat->periph_id = clock_decode_periph_id(blob, node);
if (plat->periph_id == PERIPH_ID_NONE) {
diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c
index f6fb89b393..fbb665b86f 100644
--- a/drivers/spi/tegra20_slink.c
+++ b/drivers/spi/tegra20_slink.c
@@ -106,7 +106,7 @@ static int tegra30_spi_ofdata_to_platdata(struct udevice *bus)
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
- plat->base = fdtdec_get_addr(blob, node, "reg");
+ plat->base = dev_get_addr(bus);
plat->periph_id = clock_decode_periph_id(blob, node);
if (plat->periph_id == PERIPH_ID_NONE) {
diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c
index 7ae1f0ec9a..310fb69c8d 100644
--- a/drivers/spi/zynq_spi.c
+++ b/drivers/spi/zynq_spi.c
@@ -72,7 +72,7 @@ static int zynq_spi_ofdata_to_platdata(struct udevice *bus)
const void *blob = gd->fdt_blob;
int node = bus->of_offset;
- plat->regs = (struct zynq_spi_regs *)fdtdec_get_addr(blob, node, "reg");
+ plat->regs = (struct zynq_spi_regs *)dev_get_addr(bus);
/* FIXME: Use 250MHz as a suitable default */
plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency",
diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig
index f408b8a81d..6bc8fddbd1 100644
--- a/drivers/tpm/Kconfig
+++ b/drivers/tpm/Kconfig
@@ -1,7 +1,76 @@
+#
+# TPM subsystem configuration
+#
+
+menu "TPM support"
+
+config DM_TPM
+ bool "Enable driver model for Trusted Platform Module drivers"
+ depends on DM && TPM
+ help
+ Enable driver model for TPMs. The TIS interface (tis_open(),
+ tis_sendrecv(), etc.) is then implemented by the TPM uclass. Note
+ that even with driver model only a single TPM is currently
+ supported, since the tpm library assumes this.
+
config TPM_TIS_SANDBOX
bool "Enable sandbox TPM driver"
+ depends on SANDBOX
help
This driver emulates a TPM, providing access to base functions
such as reading and writing TPM private data. This is enough to
support Chrome OS verified boot. Extend functionality is not
implemented.
+
+config TPM_ATMEL_TWI
+ bool "Enable Atmel TWI TPM device driver"
+ depends on TPM
+ help
+ This driver supports an Atmel TPM device connected on the I2C bus.
+ The usual tpm operations and the 'tpm' command can be used to talk
+ to the device using the standard TPM Interface Specification (TIS)
+ protocol
+
+config TPM_TIS_I2C
+ bool "Enable support for Infineon SLB9635/45 TPMs on I2C"
+ depends on TPM && DM_I2C
+ help
+ This driver supports Infineon TPM devices connected on the I2C bus.
+ The usual tpm operations and the 'tpm' command can be used to talk
+ to the device using the standard TPM Interface Specification (TIS)
+ protocol
+
+config TPM_TIS_I2C_BURST_LIMITATION
+ bool "Enable I2C burst length limitation"
+ depends on TPM_TIS_I2C
+ help
+ Some broken TPMs have a limitation on the number of bytes they can
+ receive in one message. Enable this option to allow you to set this
+ option. The can allow a broken TPM to be used by splitting messages
+ into separate pieces.
+
+config TPM_TIS_I2C_BURST_LIMITATION_LEN
+ int "Length"
+ depends on TPM_TIS_I2C_BURST_LIMITATION
+ help
+ Use this to set the burst limitation length
+
+config TPM_TIS_LPC
+ bool "Enable support for Infineon SLB9635/45 TPMs on LPC"
+ depends on TPM && X86
+ help
+ This driver supports Infineon TPM devices connected on the I2C bus.
+ The usual tpm operations and the 'tpm' command can be used to talk
+ to the device using the standard TPM Interface Specification (TIS)
+ protocol
+
+config TPM_AUTH_SESSIONS
+ bool "Enable TPM authentication session support"
+ depends on TPM
+ help
+ Enable support for authorised (AUTH1) commands as specified in the
+ TCG Main Specification 1.2. OIAP-authorised versions of the commands
+ TPM_LoadKey2 and TPM_GetPubKey are provided. Both features are
+ available using the 'tpm' command, too.
+
+endmenu
diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile
index 150570ee7e..0d328f8d9d 100644
--- a/drivers/tpm/Makefile
+++ b/drivers/tpm/Makefile
@@ -3,9 +3,9 @@
# SPDX-License-Identifier: GPL-2.0+
#
-# TODO: Merge tpm_tis_lpc.c with tpm.c
+obj-$(CONFIG_DM_TPM) += tpm-uclass.o
+
obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o
-obj-$(CONFIG_TPM_TIS_I2C) += tpm.o
obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o
obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o
obj-$(CONFIG_TPM_TIS_SANDBOX) += tpm_tis_sandbox.o
diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c
new file mode 100644
index 0000000000..b6e1fc5e62
--- /dev/null
+++ b/drivers/tpm/tpm-uclass.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <tpm.h>
+#include <linux/unaligned/be_byteshift.h>
+#include "tpm_internal.h"
+
+int tpm_open(struct udevice *dev)
+{
+ struct tpm_ops *ops = tpm_get_ops(dev);
+
+ if (!ops->open)
+ return -ENOSYS;
+
+ return ops->open(dev);
+}
+
+int tpm_close(struct udevice *dev)
+{
+ struct tpm_ops *ops = tpm_get_ops(dev);
+
+ if (!ops->close)
+ return -ENOSYS;
+
+ return ops->close(dev);
+}
+
+int tpm_get_desc(struct udevice *dev, char *buf, int size)
+{
+ struct tpm_ops *ops = tpm_get_ops(dev);
+
+ if (!ops->get_desc)
+ return -ENOSYS;
+
+ return ops->get_desc(dev, buf, size);
+}
+
+/* Returns max number of milliseconds to wait */
+static ulong tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip_priv *priv,
+ u32 ordinal)
+{
+ int duration_idx = TPM_UNDEFINED;
+ int duration = 0;
+
+ if (ordinal < TPM_MAX_ORDINAL) {
+ duration_idx = tpm_ordinal_duration[ordinal];
+ } else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
+ TPM_MAX_PROTECTED_ORDINAL) {
+ duration_idx = tpm_protected_ordinal_duration[
+ ordinal & TPM_PROTECTED_ORDINAL_MASK];
+ }
+
+ if (duration_idx != TPM_UNDEFINED)
+ duration = priv->duration_ms[duration_idx];
+
+ if (duration <= 0)
+ return 2 * 60 * 1000; /* Two minutes timeout */
+ else
+ return duration;
+}
+
+int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size,
+ uint8_t *recvbuf, size_t *recv_size)
+{
+ struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+ struct tpm_ops *ops = tpm_get_ops(dev);
+ ulong start, stop;
+ uint count, ordinal;
+ int ret, ret2;
+
+ if (ops->xfer)
+ return ops->xfer(dev, sendbuf, send_size, recvbuf, recv_size);
+
+ if (!ops->send || !ops->recv)
+ return -ENOSYS;
+
+ /* switch endianess: big->little */
+ count = get_unaligned_be32(sendbuf + TPM_CMD_COUNT_BYTE);
+ ordinal = get_unaligned_be32(sendbuf + TPM_CMD_ORDINAL_BYTE);
+
+ if (count == 0) {
+ debug("no data\n");
+ return -ENODATA;
+ }
+ if (count > send_size) {
+ debug("invalid count value %x %zx\n", count, send_size);
+ return -E2BIG;
+ }
+
+ debug("%s: Calling send\n", __func__);
+ ret = ops->send(dev, sendbuf, send_size);
+ if (ret < 0)
+ return ret;
+
+ start = get_timer(0);
+ stop = tpm_tis_i2c_calc_ordinal_duration(priv, ordinal);
+ do {
+ ret = ops->recv(dev, priv->buf, sizeof(priv->buf));
+ if (ret >= 0) {
+ if (ret > *recv_size)
+ return -ENOSPC;
+ memcpy(recvbuf, priv->buf, ret);
+ *recv_size = ret;
+ ret = 0;
+ break;
+ } else if (ret != -EAGAIN) {
+ return ret;
+ }
+
+ mdelay(priv->retry_time_ms);
+ if (get_timer(start) > stop) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ } while (ret);
+
+ ret2 = ops->cleanup ? ops->cleanup(dev) : 0;
+
+ return ret2 ? ret2 : ret;
+}
+
+UCLASS_DRIVER(tpm) = {
+ .id = UCLASS_TPM,
+ .name = "tpm",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .per_device_auto_alloc_size = sizeof(struct tpm_chip_priv),
+};
diff --git a/drivers/tpm/tpm.c b/drivers/tpm/tpm.c
deleted file mode 100644
index a650892f09..0000000000
--- a/drivers/tpm/tpm.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * Copyright (C) 2011 Infineon Technologies
- *
- * Authors:
- * Peter Huewe <huewe.external@infineon.com>
- *
- * Description:
- * Device driver for TCG/TCPA TPM (trusted platform module).
- * Specifications at www.trustedcomputinggroup.org
- *
- * It is based on the Linux kernel driver tpm.c from Leendert van
- * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
- *
- * Version: 2.1.1
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-
-#include <config.h>
-#include <common.h>
-#include <dm.h>
-#include <linux/compiler.h>
-#include <fdtdec.h>
-#include <i2c.h>
-#include <tpm.h>
-#include <asm-generic/errno.h>
-#include <linux/types.h>
-#include <linux/unaligned/be_byteshift.h>
-
-#include "tpm_private.h"
-
-DECLARE_GLOBAL_DATA_PTR;
-
-/* TPM configuration */
-struct tpm {
-#ifdef CONFIG_DM_I2C
- struct udevice *dev;
-#else
- int i2c_bus;
- int slave_addr;
- int old_bus;
-#endif
- char inited;
-} tpm;
-
-/* Global structure for tpm chip data */
-static struct tpm_chip g_chip;
-
-enum tpm_duration {
- TPM_SHORT = 0,
- TPM_MEDIUM = 1,
- TPM_LONG = 2,
- TPM_UNDEFINED,
-};
-
-/* Extended error numbers from linux (see errno.h) */
-#define ECANCELED 125 /* Operation Canceled */
-
-/* Timer frequency. Corresponds to msec timer resolution*/
-#define HZ 1000
-
-#define TPM_MAX_ORDINAL 243
-#define TPM_MAX_PROTECTED_ORDINAL 12
-#define TPM_PROTECTED_ORDINAL_MASK 0xFF
-
-#define TPM_CMD_COUNT_BYTE 2
-#define TPM_CMD_ORDINAL_BYTE 6
-
-/*
- * Array with one entry per ordinal defining the maximum amount
- * of time the chip could take to return the result. The ordinal
- * designation of short, medium or long is defined in a table in
- * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
- * values of the SHORT, MEDIUM, and LONG durations are retrieved
- * from the chip during initialization with a call to tpm_get_timeouts.
- */
-static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
- TPM_UNDEFINED, /* 0 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 5 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 10 */
- TPM_SHORT,
-};
-
-static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
- TPM_UNDEFINED, /* 0 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 5 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 10 */
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_LONG,
- TPM_LONG,
- TPM_MEDIUM, /* 15 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_LONG,
- TPM_SHORT, /* 20 */
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_SHORT, /* 25 */
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_MEDIUM, /* 30 */
- TPM_LONG,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT, /* 35 */
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_MEDIUM, /* 40 */
- TPM_LONG,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT, /* 45 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_LONG,
- TPM_MEDIUM, /* 50 */
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 55 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_MEDIUM, /* 60 */
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_MEDIUM, /* 65 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 70 */
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 75 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_LONG, /* 80 */
- TPM_UNDEFINED,
- TPM_MEDIUM,
- TPM_LONG,
- TPM_SHORT,
- TPM_UNDEFINED, /* 85 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 90 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED, /* 95 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_MEDIUM, /* 100 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 105 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 110 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT, /* 115 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_LONG, /* 120 */
- TPM_LONG,
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_SHORT,
- TPM_SHORT, /* 125 */
- TPM_SHORT,
- TPM_LONG,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT, /* 130 */
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_UNDEFINED, /* 135 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 140 */
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 145 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 150 */
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED, /* 155 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 160 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 165 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_LONG, /* 170 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 175 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_MEDIUM, /* 180 */
- TPM_SHORT,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_MEDIUM, /* 185 */
- TPM_SHORT,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 190 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 195 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 200 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT,
- TPM_SHORT, /* 205 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_MEDIUM, /* 210 */
- TPM_UNDEFINED,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_MEDIUM,
- TPM_UNDEFINED, /* 215 */
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT,
- TPM_SHORT, /* 220 */
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_SHORT,
- TPM_UNDEFINED, /* 225 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 230 */
- TPM_LONG,
- TPM_MEDIUM,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED, /* 235 */
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_UNDEFINED,
- TPM_SHORT, /* 240 */
- TPM_UNDEFINED,
- TPM_MEDIUM,
-};
-
-/* Returns max number of milliseconds to wait */
-static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
- u32 ordinal)
-{
- int duration_idx = TPM_UNDEFINED;
- int duration = 0;
-
- if (ordinal < TPM_MAX_ORDINAL) {
- duration_idx = tpm_ordinal_duration[ordinal];
- } else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
- TPM_MAX_PROTECTED_ORDINAL) {
- duration_idx = tpm_protected_ordinal_duration[
- ordinal & TPM_PROTECTED_ORDINAL_MASK];
- }
-
- if (duration_idx != TPM_UNDEFINED)
- duration = chip->vendor.duration[duration_idx];
-
- if (duration <= 0)
- return 2 * 60 * HZ; /* Two minutes timeout */
- else
- return duration;
-}
-
-static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz)
-{
- int rc;
- u32 count, ordinal;
- unsigned long start, stop;
-
- struct tpm_chip *chip = &g_chip;
-
- /* switch endianess: big->little */
- count = get_unaligned_be32(buf + TPM_CMD_COUNT_BYTE);
- ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE);
-
- if (count == 0) {
- error("no data\n");
- return -ENODATA;
- }
- if (count > bufsiz) {
- error("invalid count value %x %zx\n", count, bufsiz);
- return -E2BIG;
- }
-
- debug("Calling send\n");
- rc = chip->vendor.send(chip, (u8 *)buf, count);
- debug(" ... done calling send\n");
- if (rc < 0) {
- error("tpm_transmit: tpm_send: error %d\n", rc);
- goto out;
- }
-
- if (chip->vendor.irq)
- goto out_recv;
-
- start = get_timer(0);
- stop = tpm_calc_ordinal_duration(chip, ordinal);
- do {
- debug("waiting for status... %ld %ld\n", start, stop);
- u8 status = chip->vendor.status(chip);
- if ((status & chip->vendor.req_complete_mask) ==
- chip->vendor.req_complete_val) {
- debug("...got it;\n");
- goto out_recv;
- }
-
- if (status == chip->vendor.req_canceled) {
- error("Operation Canceled\n");
- rc = -ECANCELED;
- goto out;
- }
- udelay(TPM_TIMEOUT * 1000);
- } while (get_timer(start) < stop);
-
- chip->vendor.cancel(chip);
- error("Operation Timed out\n");
- rc = -ETIME;
- goto out;
-
-out_recv:
- debug("out_recv: reading response...\n");
- rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE);
- if (rc < 0)
- error("tpm_transmit: tpm_recv: error %d\n", rc);
-
-out:
- return rc;
-}
-
-#ifdef CONFIG_DM_I2C
-static int tpm_open_dev(struct udevice *dev)
-{
- int rc;
-
- debug("%s: start\n", __func__);
- if (g_chip.is_open)
- return -EBUSY;
- rc = tpm_vendor_init_dev(dev);
- if (rc < 0)
- g_chip.is_open = 0;
- return rc;
-}
-#else
-static int tpm_open(uint32_t dev_addr)
-{
- int rc;
-
- if (g_chip.is_open)
- return -EBUSY;
- rc = tpm_vendor_init(dev_addr);
- if (rc < 0)
- g_chip.is_open = 0;
- return rc;
-}
-#endif
-static void tpm_close(void)
-{
- if (g_chip.is_open) {
- tpm_vendor_cleanup(&g_chip);
- g_chip.is_open = 0;
- }
-}
-
-static int tpm_select(void)
-{
-#ifndef CONFIG_DM_I2C
- int ret;
-
- tpm.old_bus = i2c_get_bus_num();
- if (tpm.old_bus != tpm.i2c_bus) {
- ret = i2c_set_bus_num(tpm.i2c_bus);
- if (ret) {
- debug("%s: Fail to set i2c bus %d\n", __func__,
- tpm.i2c_bus);
- return -1;
- }
- }
-#endif
- return 0;
-}
-
-static int tpm_deselect(void)
-{
-#ifndef CONFIG_DM_I2C
- int ret;
-
- if (tpm.old_bus != i2c_get_bus_num()) {
- ret = i2c_set_bus_num(tpm.old_bus);
- if (ret) {
- debug("%s: Fail to restore i2c bus %d\n",
- __func__, tpm.old_bus);
- return -1;
- }
- }
- tpm.old_bus = -1;
-#endif
- return 0;
-}
-
-/**
- * Decode TPM configuration.
- *
- * @param dev Returns a configuration of TPM device
- * @return 0 if ok, -1 on error
- */
-static int tpm_decode_config(struct tpm *dev)
-{
- const void *blob = gd->fdt_blob;
- int parent;
- int node;
-
- node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM);
- if (node < 0) {
- node = fdtdec_next_compatible(blob, 0,
- COMPAT_INFINEON_SLB9645_TPM);
- }
- if (node < 0) {
- debug("%s: Node not found\n", __func__);
- return -1;
- }
- parent = fdt_parent_offset(blob, node);
- if (parent < 0) {
- debug("%s: Cannot find node parent\n", __func__);
- return -1;
- }
-#ifdef CONFIG_DM_I2C
- struct udevice *bus;
- int chip_addr;
- int ret;
-
- /*
- * TODO(sjg@chromium.org): Remove this when driver model supports
- * TPMs
- */
- ret = uclass_get_device_by_of_offset(UCLASS_I2C, parent, &bus);
- if (ret) {
- debug("Cannot find bus for node '%s: ret=%d'\n",
- fdt_get_name(blob, parent, NULL), ret);
- return ret;
- }
-
- chip_addr = fdtdec_get_int(blob, node, "reg", -1);
- if (chip_addr == -1) {
- debug("Cannot find reg property for node '%s: ret=%d'\n",
- fdt_get_name(blob, node, NULL), ret);
- return ret;
- }
- /*
- * TODO(sjg@chromium.org): Older TPMs will need to use the older method
- * in iic_tpm_read() so the offset length needs to be 0 here.
- */
- ret = i2c_get_chip(bus, chip_addr, 1, &dev->dev);
- if (ret) {
- debug("Cannot find device for node '%s: ret=%d'\n",
- fdt_get_name(blob, node, NULL), ret);
- return ret;
- }
-#else
- int i2c_bus;
-
- i2c_bus = i2c_get_bus_num_fdt(parent);
- if (i2c_bus < 0)
- return -1;
- dev->i2c_bus = i2c_bus;
- dev->slave_addr = fdtdec_get_addr(blob, node, "reg");
-#endif
-
- return 0;
-}
-
-struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry)
-{
- struct tpm_chip *chip;
-
- /* Driver specific per-device data */
- chip = &g_chip;
- memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
- chip->is_open = 1;
-
- return chip;
-}
-
-int tis_init(void)
-{
- if (tpm.inited)
- return 0;
-
- if (tpm_decode_config(&tpm))
- return -1;
-
- if (tpm_select())
- return -1;
-
-#ifndef CONFIG_DM_I2C
- /*
- * Probe TPM twice; the first probing might fail because TPM is asleep,
- * and the probing can wake up TPM.
- */
- if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) {
- debug("%s: fail to probe i2c addr 0x%x\n", __func__,
- tpm.slave_addr);
- return -1;
- }
-#endif
-
- tpm_deselect();
- debug("%s: done\n", __func__);
-
- tpm.inited = 1;
-
- return 0;
-}
-
-int tis_open(void)
-{
- int rc;
-
- if (!tpm.inited)
- return -1;
-
- if (tpm_select())
- return -1;
-
-#ifdef CONFIG_DM_I2C
- rc = tpm_open_dev(tpm.dev);
-#else
- rc = tpm_open(tpm.slave_addr);
-#endif
-
- tpm_deselect();
-
- return rc;
-}
-
-int tis_close(void)
-{
- if (!tpm.inited)
- return -1;
-
- if (tpm_select())
- return -1;
-
- tpm_close();
-
- tpm_deselect();
-
- return 0;
-}
-
-int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
- uint8_t *recvbuf, size_t *rbuf_len)
-{
- int len;
- uint8_t buf[4096];
-
- if (!tpm.inited)
- return -1;
-
- if (sizeof(buf) < sbuf_size)
- return -1;
-
- memcpy(buf, sendbuf, sbuf_size);
-
- if (tpm_select())
- return -1;
-
- len = tpm_transmit(buf, sbuf_size);
-
- tpm_deselect();
-
- if (len < 10) {
- *rbuf_len = 0;
- return -1;
- }
-
- memcpy(recvbuf, buf, len);
- *rbuf_len = len;
-
- return 0;
-}
diff --git a/drivers/tpm/tpm_atmel_twi.c b/drivers/tpm/tpm_atmel_twi.c
index 361a7720fa..205d7a5d97 100644
--- a/drivers/tpm/tpm_atmel_twi.c
+++ b/drivers/tpm/tpm_atmel_twi.c
@@ -1,18 +1,9 @@
/*
- * 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.
+ * Copyright (C) 2013 Guntermann & Drunck, GmbH
*
- * 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.
+ * Written by Dirk Eibach <eibach@gdsys.de>
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
diff --git a/drivers/tpm/tpm_internal.h b/drivers/tpm/tpm_internal.h
new file mode 100644
index 0000000000..cd29dba0b6
--- /dev/null
+++ b/drivers/tpm/tpm_internal.h
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __tpm_internal_h
+#define __tpm_internal_h
+
+enum {
+ TPM_MAX_ORDINAL = 243,
+ TPM_MAX_PROTECTED_ORDINAL = 12,
+ TPM_PROTECTED_ORDINAL_MASK = 0xff,
+ TPM_CMD_COUNT_BYTE = 2,
+ TPM_CMD_ORDINAL_BYTE = 6,
+};
+
+/*
+ * Array with one entry per ordinal defining the maximum amount
+ * of time the chip could take to return the result. The ordinal
+ * designation of short, medium or long is defined in a table in
+ * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
+ * values of the SHORT, MEDIUM, and LONG durations are retrieved
+ * from the chip during initialization with a call to tpm_get_timeouts.
+ */
+static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
+ TPM_UNDEFINED, /* 0 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 5 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 10 */
+ TPM_SHORT,
+};
+
+static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
+ TPM_UNDEFINED, /* 0 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 5 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 10 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_LONG,
+ TPM_LONG,
+ TPM_MEDIUM, /* 15 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_LONG,
+ TPM_SHORT, /* 20 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_SHORT, /* 25 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM, /* 30 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 35 */
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 40 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 45 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_LONG,
+ TPM_MEDIUM, /* 50 */
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 55 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 60 */
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM, /* 65 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 70 */
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 75 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_LONG, /* 80 */
+ TPM_UNDEFINED,
+ TPM_MEDIUM,
+ TPM_LONG,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 85 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 90 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 95 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 100 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 105 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 110 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 115 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_LONG, /* 120 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_SHORT, /* 125 */
+ TPM_SHORT,
+ TPM_LONG,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT, /* 130 */
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_UNDEFINED, /* 135 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 140 */
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 145 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 150 */
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 155 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 160 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 165 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_LONG, /* 170 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 175 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_MEDIUM, /* 180 */
+ TPM_SHORT,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM, /* 185 */
+ TPM_SHORT,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 190 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 195 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 200 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_SHORT, /* 205 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_MEDIUM, /* 210 */
+ TPM_UNDEFINED,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_MEDIUM,
+ TPM_UNDEFINED, /* 215 */
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT,
+ TPM_SHORT, /* 220 */
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_SHORT,
+ TPM_UNDEFINED, /* 225 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 230 */
+ TPM_LONG,
+ TPM_MEDIUM,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED, /* 235 */
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_UNDEFINED,
+ TPM_SHORT, /* 240 */
+ TPM_UNDEFINED,
+ TPM_MEDIUM,
+};
+
+#endif
diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c
index cc740e9c21..9afe46c1e9 100644
--- a/drivers/tpm/tpm_tis_i2c.c
+++ b/drivers/tpm/tpm_tis_i2c.c
@@ -17,131 +17,33 @@
*
* Version: 2.1.1
*
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0
*/
#include <common.h>
#include <dm.h>
#include <fdtdec.h>
-#include <linux/compiler.h>
#include <i2c.h>
+#include <tis.h>
#include <tpm.h>
#include <asm-generic/errno.h>
+#include <linux/compiler.h>
#include <linux/types.h>
#include <linux/unaligned/be_byteshift.h>
-#include "tpm_private.h"
+#include "tpm_tis_i2c.h"
+#include "tpm_internal.h"
DECLARE_GLOBAL_DATA_PTR;
-/* Address of the TPM on the I2C bus */
-#define TPM_I2C_ADDR 0x20
-
-/* Max buffer size supported by our tpm */
-#define TPM_DEV_BUFSIZE 1260
-
-/* Max number of iterations after i2c NAK */
-#define MAX_COUNT 3
-
-/*
- * Max number of iterations after i2c NAK for 'long' commands
- *
- * We need this especially for sending TPM_READY, since the cleanup after the
- * transtion to the ready state may take some time, but it is unpredictable
- * how long it will take.
- */
-#define MAX_COUNT_LONG 50
-
-#define SLEEP_DURATION 60 /* in usec */
-#define SLEEP_DURATION_LONG 210 /* in usec */
-
-#define TPM_HEADER_SIZE 10
-
-/*
- * Expected value for DIDVID register
- *
- * The only device the system knows about at this moment is Infineon slb9635.
- */
-#define TPM_TIS_I2C_DID_VID 0x000b15d1L
-
-enum tis_access {
- TPM_ACCESS_VALID = 0x80,
- TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
- TPM_ACCESS_REQUEST_PENDING = 0x04,
- TPM_ACCESS_REQUEST_USE = 0x02,
-};
-
-enum tis_status {
- TPM_STS_VALID = 0x80,
- TPM_STS_COMMAND_READY = 0x40,
- TPM_STS_GO = 0x20,
- TPM_STS_DATA_AVAIL = 0x10,
- TPM_STS_DATA_EXPECT = 0x08,
-};
-
-enum tis_defaults {
- TIS_SHORT_TIMEOUT = 750, /* ms */
- TIS_LONG_TIMEOUT = 2000, /* ms */
-};
-
-/* expected value for DIDVID register */
-#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L
-#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
-
-enum i2c_chip_type {
- SLB9635,
- SLB9645,
- UNKNOWN,
-};
-
static const char * const chip_name[] = {
[SLB9635] = "slb9635tt",
[SLB9645] = "slb9645tt",
[UNKNOWN] = "unknown/fallback to slb9635",
};
-#define TPM_ACCESS(l) (0x0000 | ((l) << 4))
-#define TPM_STS(l) (0x0001 | ((l) << 4))
-#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4))
-#define TPM_DID_VID(l) (0x0006 | ((l) << 4))
-
-/* Structure to store I2C TPM specific stuff */
-struct tpm_dev {
-#ifdef CONFIG_DM_I2C
- struct udevice *dev;
-#else
- uint addr;
-#endif
- u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */
- enum i2c_chip_type chip_type;
-};
-
-static struct tpm_dev tpm_dev = {
-#ifndef CONFIG_DM_I2C
- .addr = TPM_I2C_ADDR
-#endif
-};
-
-static struct tpm_dev tpm_dev;
-
/*
- * iic_tpm_read() - read from TPM register
+ * tpm_tis_i2c_read() - read from TPM register
* @addr: register address to read from
* @buffer: provided by caller
* @len: number of bytes to read
@@ -154,39 +56,32 @@ static struct tpm_dev tpm_dev;
*
* Return -EIO on error, 0 on success.
*/
-static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
+static int tpm_tis_i2c_read(struct udevice *dev, u8 addr, u8 *buffer,
+ size_t len)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
int rc;
int count;
uint32_t addrbuf = addr;
- if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) {
+ if ((chip->chip_type == SLB9635) || (chip->chip_type == UNKNOWN)) {
/* slb9635 protocol should work in both cases */
for (count = 0; count < MAX_COUNT; count++) {
-#ifdef CONFIG_DM_I2C
- rc = dm_i2c_write(tpm_dev.dev, 0, (uchar *)&addrbuf, 1);
-#else
- rc = i2c_write(tpm_dev.addr, 0, 0,
- (uchar *)&addrbuf, 1);
-#endif
+ rc = dm_i2c_write(dev, 0, (uchar *)&addrbuf, 1);
if (rc == 0)
break; /* Success, break to skip sleep */
- udelay(SLEEP_DURATION);
+ udelay(SLEEP_DURATION_US);
}
if (rc)
- return -rc;
+ return rc;
/* After the TPM has successfully received the register address
* it needs some time, thus we're sleeping here again, before
* retrieving the data
*/
for (count = 0; count < MAX_COUNT; count++) {
- udelay(SLEEP_DURATION);
-#ifdef CONFIG_DM_I2C
- rc = dm_i2c_read(tpm_dev.dev, 0, buffer, len);
-#else
- rc = i2c_read(tpm_dev.addr, 0, 0, buffer, len);
-#endif
+ udelay(SLEEP_DURATION_US);
+ rc = dm_i2c_read(dev, 0, buffer, len);
if (rc == 0)
break; /* success, break to skip sleep */
}
@@ -199,60 +94,56 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len)
* be safe on the safe side.
*/
for (count = 0; count < MAX_COUNT; count++) {
-#ifdef CONFIG_DM_I2C
- rc = dm_i2c_read(tpm_dev.dev, addr, buffer, len);
-#else
- rc = i2c_read(tpm_dev.addr, addr, 1, buffer, len);
-#endif
+ rc = dm_i2c_read(dev, addr, buffer, len);
if (rc == 0)
break; /* break here to skip sleep */
- udelay(SLEEP_DURATION);
+ udelay(SLEEP_DURATION_US);
}
}
/* Take care of 'guard time' */
- udelay(SLEEP_DURATION);
+ udelay(SLEEP_DURATION_US);
if (rc)
- return -rc;
+ return rc;
return 0;
}
-static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
- unsigned int sleep_time, u8 max_count)
+static int tpm_tis_i2c_write_generic(struct udevice *dev, u8 addr,
+ const u8 *buffer, size_t len,
+ unsigned int sleep_time_us, u8 max_count)
{
+ struct tpm_chip_priv *priv = dev_get_uclass_priv(dev);
+ struct tpm_chip *chip = dev_get_priv(dev);
int rc = 0;
int count;
- /* Prepare send buffer */
-#ifndef CONFIG_DM_I2C
- tpm_dev.buf[0] = addr;
- memcpy(&(tpm_dev.buf[1]), buffer, len);
- buffer = tpm_dev.buf;
- len++;
-#endif
+ if (chip->chip_type == SLB9635) {
+ /* Prepare send buffer to include the address */
+ priv->buf[0] = addr;
+ memcpy(&(priv->buf[1]), buffer, len);
+ buffer = priv->buf;
+ len++;
+ addr = 0;
+ }
for (count = 0; count < max_count; count++) {
-#ifdef CONFIG_DM_I2C
- rc = dm_i2c_write(tpm_dev.dev, addr, buffer, len);
-#else
- rc = i2c_write(tpm_dev.addr, 0, 0, buffer, len);
-#endif
+ rc = dm_i2c_write(dev, addr, buffer, len);
if (rc == 0)
break; /* Success, break to skip sleep */
- udelay(sleep_time);
+ udelay(sleep_time_us);
}
/* take care of 'guard time' */
- udelay(sleep_time);
+ udelay(sleep_time_us);
if (rc)
- return -rc;
+ return rc;
return 0;
}
/*
- * iic_tpm_write() - write to TPM register
+ * tpm_tis_i2c_write() - write to TPM register
* @addr: register address to write to
* @buffer: containing data to be written
* @len: number of bytes to write
@@ -263,109 +154,135 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len,
* NOTE: TPM is big-endian for multi-byte values. Multi-byte
* values have to be swapped.
*
- * NOTE: use this function instead of the iic_tpm_write_generic function.
+ * NOTE: use this function instead of the tpm_tis_i2c_write_generic function.
*
* Return -EIO on error, 0 on success
*/
-static int iic_tpm_write(u8 addr, u8 *buffer, size_t len)
+static int tpm_tis_i2c_write(struct udevice *dev, u8 addr, const u8 *buffer,
+ size_t len)
{
- return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION,
- MAX_COUNT);
+ return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
+ SLEEP_DURATION_US, MAX_COUNT);
}
/*
* This function is needed especially for the cleanup situation after
* sending TPM_READY
*/
-static int iic_tpm_write_long(u8 addr, u8 *buffer, size_t len)
+static int tpm_tis_i2c_write_long(struct udevice *dev, u8 addr, u8 *buffer,
+ size_t len)
{
- return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG,
- MAX_COUNT_LONG);
+ return tpm_tis_i2c_write_generic(dev, addr, buffer, len,
+ SLEEP_DURATION_LONG_US,
+ MAX_COUNT_LONG);
}
-static int check_locality(struct tpm_chip *chip, int loc)
+static int tpm_tis_i2c_check_locality(struct udevice *dev, int loc)
{
const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID;
+ struct tpm_chip *chip = dev_get_priv(dev);
u8 buf;
int rc;
- rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1);
+ rc = tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1);
if (rc < 0)
return rc;
if ((buf & mask) == mask) {
- chip->vendor.locality = loc;
+ chip->locality = loc;
return loc;
}
- return -1;
+ return -ENOENT;
}
-static void release_locality(struct tpm_chip *chip, int loc, int force)
+static void tpm_tis_i2c_release_locality(struct udevice *dev, int loc,
+ int force)
{
const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID;
u8 buf;
- if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0)
+ if (tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1) < 0)
return;
if (force || (buf & mask) == mask) {
buf = TPM_ACCESS_ACTIVE_LOCALITY;
- iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
+ tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1);
}
}
-static int request_locality(struct tpm_chip *chip, int loc)
+static int tpm_tis_i2c_request_locality(struct udevice *dev, int loc)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
unsigned long start, stop;
u8 buf = TPM_ACCESS_REQUEST_USE;
int rc;
- if (check_locality(chip, loc) >= 0)
+ rc = tpm_tis_i2c_check_locality(dev, loc);
+ if (rc >= 0) {
+ debug("%s: Already have locality\n", __func__);
return loc; /* We already have the locality */
+ } else if (rc != -ENOENT) {
+ debug("%s: Failed to get locality: %d\n", __func__, rc);
+ return rc;
+ }
- rc = iic_tpm_write(TPM_ACCESS(loc), &buf, 1);
- if (rc)
+ rc = tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1);
+ if (rc) {
+ debug("%s: Failed to write to TPM: %d\n", __func__, rc);
return rc;
+ }
/* Wait for burstcount */
start = get_timer(0);
- stop = chip->vendor.timeout_a;
+ stop = chip->timeout_a;
do {
- if (check_locality(chip, loc) >= 0)
+ rc = tpm_tis_i2c_check_locality(dev, loc);
+ if (rc >= 0) {
+ debug("%s: Have locality\n", __func__);
return loc;
- udelay(TPM_TIMEOUT * 1000);
+ } else if (rc != -ENOENT) {
+ debug("%s: Failed to get locality: %d\n", __func__, rc);
+ return rc;
+ }
+ mdelay(TPM_TIMEOUT_MS);
} while (get_timer(start) < stop);
+ debug("%s: Timeout getting locality: %d\n", __func__, rc);
- return -1;
+ return rc;
}
-static u8 tpm_tis_i2c_status(struct tpm_chip *chip)
+static u8 tpm_tis_i2c_status(struct udevice *dev)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
/* NOTE: Since i2c read may fail, return 0 in this case --> time-out */
u8 buf;
- if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0)
+ if (tpm_tis_i2c_read(dev, TPM_STS(chip->locality), &buf, 1) < 0)
return 0;
else
return buf;
}
-static void tpm_tis_i2c_ready(struct tpm_chip *chip)
+static int tpm_tis_i2c_ready(struct udevice *dev)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
int rc;
/* This causes the current command to be aborted */
u8 buf = TPM_STS_COMMAND_READY;
debug("%s\n", __func__);
- rc = iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1);
+ rc = tpm_tis_i2c_write_long(dev, TPM_STS(chip->locality), &buf, 1);
if (rc)
debug("%s: rc=%d\n", __func__, rc);
+
+ return rc;
}
-static ssize_t get_burstcount(struct tpm_chip *chip)
+static ssize_t tpm_tis_i2c_get_burstcount(struct udevice *dev)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
unsigned long start, stop;
ssize_t burstcnt;
u8 addr, buf[3];
@@ -373,53 +290,54 @@ static ssize_t get_burstcount(struct tpm_chip *chip)
/* Wait for burstcount */
/* XXX: Which timeout value? Spec has 2 answers (c & d) */
start = get_timer(0);
- stop = chip->vendor.timeout_d;
+ stop = chip->timeout_d;
do {
/* Note: STS is little endian */
- addr = TPM_STS(chip->vendor.locality) + 1;
- if (iic_tpm_read(addr, buf, 3) < 0)
+ addr = TPM_STS(chip->locality) + 1;
+ if (tpm_tis_i2c_read(dev, addr, buf, 3) < 0)
burstcnt = 0;
else
burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0];
if (burstcnt)
return burstcnt;
- udelay(TPM_TIMEOUT * 1000);
+ mdelay(TPM_TIMEOUT_MS);
} while (get_timer(start) < stop);
return -EBUSY;
}
-static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
- int *status)
+static int tpm_tis_i2c_wait_for_stat(struct udevice *dev, u8 mask,
+ unsigned long timeout, int *status)
{
unsigned long start, stop;
/* Check current status */
- *status = tpm_tis_i2c_status(chip);
+ *status = tpm_tis_i2c_status(dev);
if ((*status & mask) == mask)
return 0;
start = get_timer(0);
stop = timeout;
do {
- udelay(TPM_TIMEOUT * 1000);
- *status = tpm_tis_i2c_status(chip);
+ mdelay(TPM_TIMEOUT_MS);
+ *status = tpm_tis_i2c_status(dev);
if ((*status & mask) == mask)
return 0;
} while (get_timer(start) < stop);
- return -ETIME;
+ return -ETIMEDOUT;
}
-static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
+static int tpm_tis_i2c_recv_data(struct udevice *dev, u8 *buf, size_t count)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
size_t size = 0;
ssize_t burstcnt;
int rc;
while (size < count) {
- burstcnt = get_burstcount(chip);
+ burstcnt = tpm_tis_i2c_get_burstcount(dev);
/* burstcount < 0 -> tpm is busy */
if (burstcnt < 0)
@@ -429,8 +347,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
if (burstcnt > (count - size))
burstcnt = count - size;
- rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality),
- &(buf[size]), burstcnt);
+ rc = tpm_tis_i2c_read(dev, TPM_DATA_FIFO(chip->locality),
+ &(buf[size]), burstcnt);
if (rc == 0)
size += burstcnt;
}
@@ -438,60 +356,58 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
return size;
}
-static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+static int tpm_tis_i2c_recv(struct udevice *dev, u8 *buf, size_t count)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
int size = 0;
int expected, status;
+ int rc;
- if (count < TPM_HEADER_SIZE) {
- size = -EIO;
- goto out;
- }
+ status = tpm_tis_i2c_status(dev);
+ if (status == TPM_STS_COMMAND_READY)
+ return -EINTR;
+ if ((status & (TPM_STS_DATA_AVAIL | TPM_STS_VALID)) !=
+ (TPM_STS_DATA_AVAIL | TPM_STS_VALID))
+ return -EAGAIN;
+
+ debug("...got it;\n");
/* Read first 10 bytes, including tag, paramsize, and result */
- size = recv_data(chip, buf, TPM_HEADER_SIZE);
+ size = tpm_tis_i2c_recv_data(dev, buf, TPM_HEADER_SIZE);
if (size < TPM_HEADER_SIZE) {
- error("Unable to read header\n");
- goto out;
+ debug("Unable to read header\n");
+ return size < 0 ? size : -EIO;
}
expected = get_unaligned_be32(buf + TPM_RSP_SIZE_BYTE);
if ((size_t)expected > count) {
- error("Error size=%x, expected=%x, count=%x\n", size, expected,
+ debug("Error size=%x, expected=%x, count=%x\n", size, expected,
count);
- size = -EIO;
- goto out;
+ return -ENOSPC;
}
- size += recv_data(chip, &buf[TPM_HEADER_SIZE],
- expected - TPM_HEADER_SIZE);
+ size += tpm_tis_i2c_recv_data(dev, &buf[TPM_HEADER_SIZE],
+ expected - TPM_HEADER_SIZE);
if (size < expected) {
- error("Unable to read remainder of result\n");
- size = -ETIME;
- goto out;
+ debug("Unable to read remainder of result\n");
+ return -ETIMEDOUT;
}
- wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
+ rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID, chip->timeout_c,
+ &status);
+ if (rc)
+ return rc;
if (status & TPM_STS_DATA_AVAIL) { /* Retry? */
- error("Error left over data\n");
- size = -EIO;
- goto out;
+ debug("Error left over data\n");
+ return -EIO;
}
-out:
- tpm_tis_i2c_ready(chip);
- /*
- * The TPM needs some time to clean up here,
- * so we sleep rather than keeping the bus busy
- */
- udelay(2000);
- release_locality(chip, chip->vendor.locality, 0);
-
return size;
}
-static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
+static int tpm_tis_i2c_send(struct udevice *dev, const u8 *buf, size_t len)
{
+ struct tpm_chip *chip = dev_get_priv(dev);
int rc, status;
size_t burstcnt;
size_t count = 0;
@@ -502,20 +418,21 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
if (len > TPM_DEV_BUFSIZE)
return -E2BIG; /* Command is too long for our tpm, sorry */
- if (request_locality(chip, 0) < 0)
+ if (tpm_tis_i2c_request_locality(dev, 0) < 0)
return -EBUSY;
- status = tpm_tis_i2c_status(chip);
+ status = tpm_tis_i2c_status(dev);
if ((status & TPM_STS_COMMAND_READY) == 0) {
- tpm_tis_i2c_ready(chip);
- if (wait_for_stat(chip, TPM_STS_COMMAND_READY,
- chip->vendor.timeout_b, &status) < 0) {
- rc = -ETIME;
- goto out_err;
- }
+ rc = tpm_tis_i2c_ready(dev);
+ if (rc)
+ return rc;
+ rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_COMMAND_READY,
+ chip->timeout_b, &status);
+ if (rc)
+ return rc;
}
- burstcnt = get_burstcount(chip);
+ burstcnt = tpm_tis_i2c_get_burstcount(dev);
/* burstcount < 0 -> tpm is busy */
if (burstcnt < 0)
@@ -527,107 +444,79 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len)
burstcnt = len - count;
#ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION
- if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION)
- burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION;
+ if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN)
+ burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION_LEN;
#endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */
- rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality),
- &(buf[count]), burstcnt);
+ rc = tpm_tis_i2c_write(dev, TPM_DATA_FIFO(chip->locality),
+ &(buf[count]), burstcnt);
if (rc == 0)
count += burstcnt;
else {
debug("%s: error\n", __func__);
- if (retry++ > 10) {
- rc = -EIO;
- goto out_err;
- }
- rc = wait_for_stat(chip, TPM_STS_VALID,
- chip->vendor.timeout_c, &status);
+ if (retry++ > 10)
+ return -EIO;
+ rc = tpm_tis_i2c_wait_for_stat(dev, TPM_STS_VALID,
+ chip->timeout_c,
+ &status);
if (rc)
- goto out_err;
+ return rc;
- if ((status & TPM_STS_DATA_EXPECT) == 0) {
- rc = -EIO;
- goto out_err;
- }
+ if ((status & TPM_STS_DATA_EXPECT) == 0)
+ return -EIO;
}
}
/* Go and do it */
- iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1);
- debug("done\n");
+ rc = tpm_tis_i2c_write(dev, TPM_STS(chip->locality), &sts, 1);
+ if (rc < 0)
+ return rc;
+ debug("%s: done, rc=%d\n", __func__, rc);
return len;
+}
+
+static int tpm_tis_i2c_cleanup(struct udevice *dev)
+{
+ struct tpm_chip *chip = dev_get_priv(dev);
-out_err:
- debug("%s: out_err\n", __func__);
- tpm_tis_i2c_ready(chip);
+ tpm_tis_i2c_ready(dev);
/*
* The TPM needs some time to clean up here,
* so we sleep rather than keeping the bus busy
*/
- udelay(2000);
- release_locality(chip, chip->vendor.locality, 0);
-
- return rc;
-}
+ mdelay(2);
+ tpm_tis_i2c_release_locality(dev, chip->locality, 0);
-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,
-};
-
-
-static enum i2c_chip_type tpm_vendor_chip_type(void)
-{
-#if CONFIG_IS_ENABLED(OF_CONTROL)
- const void *blob = gd->fdt_blob;
-
- if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9645_TPM) >= 0)
- return SLB9645;
-
- if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM) >= 0)
- return SLB9635;
-#endif
- return UNKNOWN;
+ return 0;
}
-static int tpm_vendor_init_common(void)
+static int tpm_tis_i2c_init(struct udevice *dev)
{
- struct tpm_chip *chip;
+ struct tpm_chip *chip = dev_get_priv(dev);
u32 vendor;
u32 expected_did_vid;
+ int rc;
- tpm_dev.chip_type = tpm_vendor_chip_type();
-
- chip = tpm_register_hardware(&tpm_tis_i2c);
- if (chip < 0)
- return -ENODEV;
-
- /* Disable interrupts (not supported) */
- chip->vendor.irq = 0;
+ chip->is_open = 1;
- /* Default timeouts */
- chip->vendor.timeout_a = TIS_SHORT_TIMEOUT;
- chip->vendor.timeout_b = TIS_LONG_TIMEOUT;
- chip->vendor.timeout_c = TIS_SHORT_TIMEOUT;
- chip->vendor.timeout_d = TIS_SHORT_TIMEOUT;
+ /* Default timeouts - these could move to the device tree */
+ chip->timeout_a = TIS_SHORT_TIMEOUT_MS;
+ chip->timeout_b = TIS_LONG_TIMEOUT_MS;
+ chip->timeout_c = TIS_SHORT_TIMEOUT_MS;
+ chip->timeout_d = TIS_SHORT_TIMEOUT_MS;
- if (request_locality(chip, 0) < 0)
- return -ENODEV;
+ rc = tpm_tis_i2c_request_locality(dev, 0);
+ if (rc < 0)
+ return rc;
/* Read four bytes from DID_VID register */
- if (iic_tpm_read(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
- release_locality(chip, 0, 1);
+ if (tpm_tis_i2c_read(dev, TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) {
+ tpm_tis_i2c_release_locality(dev, 0, 1);
return -EIO;
}
- if (tpm_dev.chip_type == SLB9635) {
+ if (chip->chip_type == SLB9635) {
vendor = be32_to_cpu(vendor);
expected_did_vid = TPM_TIS_I2C_DID_VID_9635;
} else {
@@ -635,13 +524,14 @@ static int tpm_vendor_init_common(void)
expected_did_vid = TPM_TIS_I2C_DID_VID_9645;
}
- if (tpm_dev.chip_type != UNKNOWN && vendor != expected_did_vid) {
+ if (chip->chip_type != UNKNOWN && vendor != expected_did_vid) {
error("Vendor id did not match! ID was %08x\n", vendor);
return -ENODEV;
}
+ chip->vend_dev = vendor;
debug("1.2 TPM (chip type %s device-id 0x%X)\n",
- chip_name[tpm_dev.chip_type], vendor >> 16);
+ chip_name[chip->chip_type], vendor >> 16);
/*
* A timeout query to TPM can be placed here.
@@ -651,33 +541,83 @@ static int tpm_vendor_init_common(void)
return 0;
}
-#ifdef CONFIG_DM_I2C
-/* Initialisation of i2c tpm */
-int tpm_vendor_init_dev(struct udevice *dev)
+static int tpm_tis_i2c_open(struct udevice *dev)
{
- tpm_dev.dev = dev;
- return tpm_vendor_init_common();
+ struct tpm_chip *chip = dev_get_priv(dev);
+ int rc;
+
+ debug("%s: start\n", __func__);
+ if (chip->is_open)
+ return -EBUSY;
+ rc = tpm_tis_i2c_init(dev);
+ if (rc < 0)
+ chip->is_open = 0;
+
+ return rc;
}
-#else
-/* Initialisation of i2c tpm */
-int tpm_vendor_init(uint32_t dev_addr)
+
+static int tpm_tis_i2c_close(struct udevice *dev)
{
- uint old_addr;
- int rc = 0;
+ struct tpm_chip *chip = dev_get_priv(dev);
- old_addr = tpm_dev.addr;
- if (dev_addr != 0)
- tpm_dev.addr = dev_addr;
+ if (chip->is_open) {
+ tpm_tis_i2c_release_locality(dev, chip->locality, 1);
+ chip->is_open = 0;
+ chip->vend_dev = 0;
+ }
- rc = tpm_vendor_init_common();
- if (rc)
- tpm_dev.addr = old_addr;
+ return 0;
+}
- return rc;
+static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size)
+{
+ struct tpm_chip *chip = dev_get_priv(dev);
+
+ if (size < 50)
+ return -ENOSPC;
+
+ return snprintf(buf, size, "1.2 TPM (%s, chip type %s device-id 0x%x)",
+ chip->is_open ? "open" : "closed",
+ chip_name[chip->chip_type],
+ chip->vend_dev >> 16);
}
-#endif
-void tpm_vendor_cleanup(struct tpm_chip *chip)
+static int tpm_tis_i2c_probe(struct udevice *dev)
{
- release_locality(chip, chip->vendor.locality, 1);
+ struct tpm_chip_priv *uc_priv = dev_get_uclass_priv(dev);
+ struct tpm_chip *chip = dev_get_priv(dev);
+
+ chip->chip_type = dev_get_driver_data(dev);
+
+ /* TODO: These need to be checked and tuned */
+ uc_priv->duration_ms[TPM_SHORT] = TIS_SHORT_TIMEOUT_MS;
+ uc_priv->duration_ms[TPM_MEDIUM] = TIS_LONG_TIMEOUT_MS;
+ uc_priv->duration_ms[TPM_LONG] = TIS_LONG_TIMEOUT_MS;
+ uc_priv->retry_time_ms = TPM_TIMEOUT_MS;
+
+ return 0;
}
+
+static const struct tpm_ops tpm_tis_i2c_ops = {
+ .open = tpm_tis_i2c_open,
+ .close = tpm_tis_i2c_close,
+ .get_desc = tpm_tis_get_desc,
+ .send = tpm_tis_i2c_send,
+ .recv = tpm_tis_i2c_recv,
+ .cleanup = tpm_tis_i2c_cleanup,
+};
+
+static const struct udevice_id tpm_tis_i2c_ids[] = {
+ { .compatible = "infineon,slb9635tt", .data = SLB9635 },
+ { .compatible = "infineon,slb9645tt", .data = SLB9645 },
+ { }
+};
+
+U_BOOT_DRIVER(tpm_tis_i2c) = {
+ .name = "tpm_tis_i2c",
+ .id = UCLASS_TPM,
+ .of_match = tpm_tis_i2c_ids,
+ .ops = &tpm_tis_i2c_ops,
+ .probe = tpm_tis_i2c_probe,
+ .priv_auto_alloc_size = sizeof(struct tpm_chip),
+};
diff --git a/drivers/tpm/tpm_private.h b/drivers/tpm/tpm_tis_i2c.h
index 8894c98e6a..3b510d101e 100644
--- a/drivers/tpm/tpm_private.h
+++ b/drivers/tpm/tpm_tis_i2c.h
@@ -13,34 +13,21 @@
* It is based on the Linux kernel driver tpm.c from Leendert van
* Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall.
*
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0
*/
-#ifndef _TPM_PRIVATE_H_
-#define _TPM_PRIVATE_H_
+#ifndef _TPM_TIS_I2C_H
+#define _TPM_TIS_I2C_H
#include <linux/compiler.h>
#include <linux/types.h>
enum tpm_timeout {
- TPM_TIMEOUT = 5, /* msecs */
+ TPM_TIMEOUT_MS = 5,
+ TIS_SHORT_TIMEOUT_MS = 750,
+ TIS_LONG_TIMEOUT_MS = 2000,
+ SLEEP_DURATION_US = 60,
+ SLEEP_DURATION_LONG_US = 210,
};
/* Size of external transmit buffer (used in tpm_transmit)*/
@@ -50,25 +37,18 @@ enum tpm_timeout {
#define TPM_RSP_SIZE_BYTE 2
#define TPM_RSP_RC_BYTE 6
-struct tpm_chip;
-
-struct tpm_vendor_specific {
- const u8 req_complete_mask;
- const u8 req_complete_val;
- const u8 req_canceled;
- int irq;
- int (*recv) (struct tpm_chip *, u8 *, size_t);
- int (*send) (struct tpm_chip *, u8 *, size_t);
- void (*cancel) (struct tpm_chip *);
- u8(*status) (struct tpm_chip *);
- int locality;
- unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */
- unsigned long duration[3]; /* msec */
+enum i2c_chip_type {
+ SLB9635,
+ SLB9645,
+ UNKNOWN,
};
struct tpm_chip {
int is_open;
- struct tpm_vendor_specific vendor;
+ int locality;
+ u32 vend_dev;
+ unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */
+ enum i2c_chip_type chip_type;
};
struct tpm_input_header {
@@ -127,14 +107,40 @@ struct tpm_cmd_t {
union tpm_cmd_params params;
} __packed;
-struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *);
+/* Max number of iterations after i2c NAK */
+#define MAX_COUNT 3
-int tpm_vendor_init(uint32_t dev_addr);
+/*
+ * Max number of iterations after i2c NAK for 'long' commands
+ *
+ * We need this especially for sending TPM_READY, since the cleanup after the
+ * transtion to the ready state may take some time, but it is unpredictable
+ * how long it will take.
+ */
+#define MAX_COUNT_LONG 50
-struct udevice;
-int tpm_vendor_init_dev(struct udevice *dev);
+enum tis_access {
+ TPM_ACCESS_VALID = 0x80,
+ TPM_ACCESS_ACTIVE_LOCALITY = 0x20,
+ TPM_ACCESS_REQUEST_PENDING = 0x04,
+ TPM_ACCESS_REQUEST_USE = 0x02,
+};
+
+enum tis_status {
+ TPM_STS_VALID = 0x80,
+ TPM_STS_COMMAND_READY = 0x40,
+ TPM_STS_GO = 0x20,
+ TPM_STS_DATA_AVAIL = 0x10,
+ TPM_STS_DATA_EXPECT = 0x08,
+};
-void tpm_vendor_cleanup(struct tpm_chip *chip);
+/* expected value for DIDVID register */
+#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L
+#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L
+#define TPM_ACCESS(l) (0x0000 | ((l) << 4))
+#define TPM_STS(l) (0x0001 | ((l) << 4))
+#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4))
+#define TPM_DID_VID(l) (0x0006 | ((l) << 4))
#endif
diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c
index d09f8cee05..b41c3cec37 100644
--- a/drivers/tpm/tpm_tis_lpc.c
+++ b/drivers/tpm/tpm_tis_lpc.c
@@ -14,8 +14,11 @@
*/
#include <common.h>
-#include <asm/io.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <tis.h>
#include <tpm.h>
+#include <asm/io.h>
#define PREFIX "lpc_tpm: "
@@ -36,13 +39,15 @@ struct tpm_locality {
u8 padding4[251];
};
+struct tpm_tis_lpc_priv {
+ struct tpm_locality *regs;
+};
+
/*
* This pointer refers to the TPM chip, 5 of its localities are mapped as an
* array.
*/
#define TPM_TOTAL_LOCALITIES 5
-static struct tpm_locality *lpc_tpm_dev =
- (struct tpm_locality *)CONFIG_TPM_TIS_BASE_ADDRESS;
/* Some registers' bit field definitions */
#define TIS_STS_VALID (1 << 7) /* 0x80 */
@@ -63,85 +68,45 @@ static struct tpm_locality *lpc_tpm_dev =
#define TIS_STS_BURST_COUNT_MASK (0xffff)
#define TIS_STS_BURST_COUNT_SHIFT (8)
-/*
- * Error value returned if a tpm register does not enter the expected state
- * after continuous polling. No actual TPM register reading ever returns -1,
- * so this value is a safe error indication to be mixed with possible status
- * register values.
- */
-#define TPM_TIMEOUT_ERR (-1)
-
-/* Error value returned on various TPM driver errors. */
-#define TPM_DRIVER_ERR (1)
-
/* 1 second is plenty for anything TPM does. */
#define MAX_DELAY_US (1000 * 1000)
/* Retrieve burst count value out of the status register contents. */
static u16 burst_count(u32 status)
{
- return (status >> TIS_STS_BURST_COUNT_SHIFT) & TIS_STS_BURST_COUNT_MASK;
+ return (status >> TIS_STS_BURST_COUNT_SHIFT) &
+ TIS_STS_BURST_COUNT_MASK;
}
-/*
- * Structures defined below allow creating descriptions of TPM vendor/device
- * ID information for run time discovery. The only device the system knows
- * about at this time is Infineon slb9635.
- */
-struct device_name {
- u16 dev_id;
- const char * const dev_name;
-};
-
-struct vendor_name {
- u16 vendor_id;
- const char *vendor_name;
- const struct device_name *dev_names;
-};
-
-static const struct device_name infineon_devices[] = {
- {0xb, "SLB9635 TT 1.2"},
- {0}
-};
-
-static const struct vendor_name vendor_names[] = {
- {0x15d1, "Infineon", infineon_devices},
-};
-
-/*
- * Cached vendor/device ID pair to indicate that the device has been already
- * discovered.
- */
-static u32 vendor_dev_id;
-
/* TPM access wrappers to support tracing */
-static u8 tpm_read_byte(const u8 *ptr)
+static u8 tpm_read_byte(struct tpm_tis_lpc_priv *priv, const u8 *ptr)
{
u8 ret = readb(ptr);
debug(PREFIX "Read reg 0x%4.4x returns 0x%2.2x\n",
- (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret);
+ (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret);
return ret;
}
-static u32 tpm_read_word(const u32 *ptr)
+static u32 tpm_read_word(struct tpm_tis_lpc_priv *priv, const u32 *ptr)
{
u32 ret = readl(ptr);
debug(PREFIX "Read reg 0x%4.4x returns 0x%8.8x\n",
- (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, ret);
+ (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, ret);
return ret;
}
-static void tpm_write_byte(u8 value, u8 *ptr)
+static void tpm_write_byte(struct tpm_tis_lpc_priv *priv, u8 value, u8 *ptr)
{
debug(PREFIX "Write reg 0x%4.4x with 0x%2.2x\n",
- (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value);
+ (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value);
writeb(value, ptr);
}
-static void tpm_write_word(u32 value, u32 *ptr)
+static void tpm_write_word(struct tpm_tis_lpc_priv *priv, u32 value,
+ u32 *ptr)
{
debug(PREFIX "Write reg 0x%4.4x with 0x%8.8x\n",
- (u32)(uintptr_t)ptr - (u32)(uintptr_t)lpc_tpm_dev, value);
+ (u32)(uintptr_t)ptr - (u32)(uintptr_t)priv->regs, value);
writel(value, ptr);
}
@@ -156,67 +121,51 @@ static void tpm_write_word(u32 value, u32 *ptr)
* @expected - value the field(s) are supposed to be set to
*
* Returns the register contents in case the expected value was found in the
- * appropriate register bits, or TPM_TIMEOUT_ERR on timeout.
+ * appropriate register bits, or -ETIMEDOUT on timeout.
*/
-static u32 tis_wait_reg(u32 *reg, u8 mask, u8 expected)
+static int tis_wait_reg(struct tpm_tis_lpc_priv *priv, u32 *reg, u8 mask,
+ u8 expected)
{
u32 time_us = MAX_DELAY_US;
while (time_us > 0) {
- u32 value = tpm_read_word(reg);
+ u32 value = tpm_read_word(priv, reg);
if ((value & mask) == expected)
return value;
udelay(1); /* 1 us */
time_us--;
}
- return TPM_TIMEOUT_ERR;
+
+ return -ETIMEDOUT;
}
/*
* Probe the TPM device and try determining its manufacturer/device name.
*
- * Returns 0 on success (the device is found or was found during an earlier
- * invocation) or TPM_DRIVER_ERR if the device is not found.
+ * Returns 0 on success, -ve on error
*/
-int tis_init(void)
+static int tpm_tis_lpc_probe(struct udevice *dev)
{
- u32 didvid = tpm_read_word(&lpc_tpm_dev[0].did_vid);
- int i;
- const char *device_name = "unknown";
- const char *vendor_name = device_name;
- u16 vid, did;
-
- if (vendor_dev_id)
- return 0; /* Already probed. */
-
- if (!didvid || (didvid == 0xffffffff)) {
- printf("%s: No TPM device found\n", __func__);
- return TPM_DRIVER_ERR;
- }
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ u32 vid, did;
+ fdt_addr_t addr;
+ u32 didvid;
- vendor_dev_id = didvid;
+ addr = dev_get_addr(dev);
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
+ priv->regs = map_sysmem(addr, 0);
+ didvid = tpm_read_word(priv, &priv->regs[0].did_vid);
vid = didvid & 0xffff;
did = (didvid >> 16) & 0xffff;
- for (i = 0; i < ARRAY_SIZE(vendor_names); i++) {
- int j = 0;
- u16 known_did;
-
- if (vid == vendor_names[i].vendor_id)
- vendor_name = vendor_names[i].vendor_name;
-
- while ((known_did = vendor_names[i].dev_names[j].dev_id) != 0) {
- if (known_did == did) {
- device_name =
- vendor_names[i].dev_names[j].dev_name;
- break;
- }
- j++;
- }
- break;
+ if (vid != 0x15d1 || did != 0xb) {
+ debug("Invalid vendor/device ID %04x/%04x\n", vid, did);
+ return -ENOSYS;
}
- printf("Found TPM %s by %s\n", device_name, vendor_name);
+ debug("Found TPM %s by %s\n", "SLB9635 TT 1.2", "Infineon");
+
return 0;
}
@@ -228,23 +177,25 @@ int tis_init(void)
* @data - address of the data to send, byte by byte
* @len - length of the data to send
*
- * Returns 0 on success, TPM_DRIVER_ERR on error (in case the device does
- * not accept the entire command).
+ * Returns 0 on success, -ve on error (in case the device does not accept
+ * the entire command).
*/
-static u32 tis_senddata(const u8 * const data, u32 len)
+static int tis_senddata(struct udevice *dev, const u8 *data, size_t len)
{
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ struct tpm_locality *regs = priv->regs;
u32 offset = 0;
u16 burst = 0;
u32 max_cycles = 0;
u8 locality = 0;
u32 value;
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
TIS_STS_COMMAND_READY, TIS_STS_COMMAND_READY);
- if (value == TPM_TIMEOUT_ERR) {
+ if (value == -ETIMEDOUT) {
printf("%s:%d - failed to get 'command_ready' status\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return value;
}
burst = burst_count(value);
@@ -256,11 +207,11 @@ static u32 tis_senddata(const u8 * const data, u32 len)
if (max_cycles++ == MAX_DELAY_US) {
printf("%s:%d failed to feed %d bytes of %d\n",
__FILE__, __LINE__, len - offset, len);
- return TPM_DRIVER_ERR;
+ return -ETIMEDOUT;
}
udelay(1);
- burst = burst_count(tpm_read_word(&lpc_tpm_dev
- [locality].tpm_status));
+ burst = burst_count(tpm_read_word(priv,
+ &regs[locality].tpm_status));
}
max_cycles = 0;
@@ -276,16 +227,16 @@ static u32 tis_senddata(const u8 * const data, u32 len)
*/
count = min((u32)burst, len - offset - 1);
while (count--)
- tpm_write_byte(data[offset++],
- &lpc_tpm_dev[locality].data);
+ tpm_write_byte(priv, data[offset++],
+ &regs[locality].data);
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
TIS_STS_VALID, TIS_STS_VALID);
- if ((value == TPM_TIMEOUT_ERR) || !(value & TIS_STS_EXPECT)) {
+ if ((value == -ETIMEDOUT) || !(value & TIS_STS_EXPECT)) {
printf("%s:%d TPM command feed overflow\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return value == -ETIMEDOUT ? value : -EIO;
}
burst = burst_count(value);
@@ -300,21 +251,21 @@ static u32 tis_senddata(const u8 * const data, u32 len)
}
/* Send the last byte. */
- tpm_write_byte(data[offset++], &lpc_tpm_dev[locality].data);
+ tpm_write_byte(priv, data[offset++], &regs[locality].data);
/*
* Verify that TPM does not expect any more data as part of this
* command.
*/
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
TIS_STS_VALID, TIS_STS_VALID);
- if ((value == TPM_TIMEOUT_ERR) || (value & TIS_STS_EXPECT)) {
+ if ((value == -ETIMEDOUT) || (value & TIS_STS_EXPECT)) {
printf("%s:%d unexpected TPM status 0x%x\n",
__FILE__, __LINE__, value);
- return TPM_DRIVER_ERR;
+ return value == -ETIMEDOUT ? value : -EIO;
}
/* OK, sitting pretty, let's start the command execution. */
- tpm_write_word(TIS_STS_TPM_GO, &lpc_tpm_dev[locality].tpm_status);
+ tpm_write_word(priv, TIS_STS_TPM_GO, &regs[locality].tpm_status);
return 0;
}
@@ -328,25 +279,27 @@ static u32 tis_senddata(const u8 * const data, u32 len)
*
* On success stores the number of received bytes to len and returns 0. On
* errors (misformatted TPM data or synchronization problems) returns
- * TPM_DRIVER_ERR.
+ * -ve value.
*/
-static u32 tis_readresponse(u8 *buffer, u32 *len)
+static int tis_readresponse(struct udevice *dev, u8 *buffer, size_t len)
{
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ struct tpm_locality *regs = priv->regs;
u16 burst;
u32 value;
u32 offset = 0;
u8 locality = 0;
const u32 has_data = TIS_STS_DATA_AVAILABLE | TIS_STS_VALID;
- u32 expected_count = *len;
+ u32 expected_count = len;
int max_cycles = 0;
/* Wait for the TPM to process the command. */
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
has_data, has_data);
- if (value == TPM_TIMEOUT_ERR) {
+ if (value == -ETIMEDOUT) {
printf("%s:%d failed processing command\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return value;
}
do {
@@ -354,18 +307,17 @@ static u32 tis_readresponse(u8 *buffer, u32 *len)
if (max_cycles++ == MAX_DELAY_US) {
printf("%s:%d TPM stuck on read\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return -EIO;
}
udelay(1);
- value = tpm_read_word(&lpc_tpm_dev
- [locality].tpm_status);
+ value = tpm_read_word(priv, &regs[locality].tpm_status);
}
max_cycles = 0;
while (burst-- && (offset < expected_count)) {
- buffer[offset++] = tpm_read_byte(&lpc_tpm_dev
- [locality].data);
+ buffer[offset++] = tpm_read_byte(priv,
+ &regs[locality].data);
if (offset == 6) {
/*
@@ -382,22 +334,22 @@ static u32 tis_readresponse(u8 *buffer, u32 *len)
expected_count = be32_to_cpu(real_length);
if ((expected_count < offset) ||
- (expected_count > *len)) {
+ (expected_count > len)) {
printf("%s:%d bad response size %d\n",
__FILE__, __LINE__,
expected_count);
- return TPM_DRIVER_ERR;
+ return -ENOSPC;
}
}
}
/* Wait for the next portion. */
- value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status,
+ value = tis_wait_reg(priv, &regs[locality].tpm_status,
TIS_STS_VALID, TIS_STS_VALID);
- if (value == TPM_TIMEOUT_ERR) {
+ if (value == -ETIMEDOUT) {
printf("%s:%d failed to read response\n",
__FILE__, __LINE__);
- return TPM_DRIVER_ERR;
+ return value;
}
if (offset == expected_count)
@@ -412,68 +364,90 @@ static u32 tis_readresponse(u8 *buffer, u32 *len)
if (value & TIS_STS_DATA_AVAILABLE) {
printf("%s:%d wrong receive status %x\n",
__FILE__, __LINE__, value);
- return TPM_DRIVER_ERR;
+ return -EBADMSG;
}
/* Tell the TPM that we are done. */
- tpm_write_word(TIS_STS_COMMAND_READY, &lpc_tpm_dev
- [locality].tpm_status);
- *len = offset;
- return 0;
+ tpm_write_word(priv, TIS_STS_COMMAND_READY,
+ &regs[locality].tpm_status);
+
+ return offset;
}
-int tis_open(void)
+static int tpm_tis_lpc_open(struct udevice *dev)
{
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ struct tpm_locality *regs = priv->regs;
u8 locality = 0; /* we use locality zero for everything. */
-
- if (tis_close())
- return TPM_DRIVER_ERR;
+ int ret;
/* now request access to locality. */
- tpm_write_word(TIS_ACCESS_REQUEST_USE, &lpc_tpm_dev[locality].access);
+ tpm_write_word(priv, TIS_ACCESS_REQUEST_USE, &regs[locality].access);
/* did we get a lock? */
- if (tis_wait_reg(&lpc_tpm_dev[locality].access,
+ ret = tis_wait_reg(priv, &regs[locality].access,
TIS_ACCESS_ACTIVE_LOCALITY,
- TIS_ACCESS_ACTIVE_LOCALITY) == TPM_TIMEOUT_ERR) {
+ TIS_ACCESS_ACTIVE_LOCALITY);
+ if (ret == -ETIMEDOUT) {
printf("%s:%d - failed to lock locality %d\n",
__FILE__, __LINE__, locality);
- return TPM_DRIVER_ERR;
+ return ret;
}
- tpm_write_word(TIS_STS_COMMAND_READY,
- &lpc_tpm_dev[locality].tpm_status);
+ tpm_write_word(priv, TIS_STS_COMMAND_READY,
+ &regs[locality].tpm_status);
return 0;
}
-int tis_close(void)
+static int tpm_tis_lpc_close(struct udevice *dev)
{
+ struct tpm_tis_lpc_priv *priv = dev_get_priv(dev);
+ struct tpm_locality *regs = priv->regs;
u8 locality = 0;
- if (tpm_read_word(&lpc_tpm_dev[locality].access) &
+ if (tpm_read_word(priv, &regs[locality].access) &
TIS_ACCESS_ACTIVE_LOCALITY) {
- tpm_write_word(TIS_ACCESS_ACTIVE_LOCALITY,
- &lpc_tpm_dev[locality].access);
+ tpm_write_word(priv, TIS_ACCESS_ACTIVE_LOCALITY,
+ &regs[locality].access);
- if (tis_wait_reg(&lpc_tpm_dev[locality].access,
- TIS_ACCESS_ACTIVE_LOCALITY, 0) ==
- TPM_TIMEOUT_ERR) {
+ if (tis_wait_reg(priv, &regs[locality].access,
+ TIS_ACCESS_ACTIVE_LOCALITY, 0) == -ETIMEDOUT) {
printf("%s:%d - failed to release locality %d\n",
__FILE__, __LINE__, locality);
- return TPM_DRIVER_ERR;
+ return -ETIMEDOUT;
}
}
return 0;
}
-int tis_sendrecv(const u8 *sendbuf, size_t send_size,
- u8 *recvbuf, size_t *recv_len)
+static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size)
{
- if (tis_senddata(sendbuf, send_size)) {
- printf("%s:%d failed sending data to TPM\n",
- __FILE__, __LINE__);
- return TPM_DRIVER_ERR;
- }
+ if (size < 50)
+ return -ENOSPC;
- return tis_readresponse(recvbuf, (u32 *)recv_len);
+ return snprintf(buf, size, "1.2 TPM (vendor %s, chip %s)",
+ "Infineon", "SLB9635 TT 1.2");
}
+
+
+static const struct tpm_ops tpm_tis_lpc_ops = {
+ .open = tpm_tis_lpc_open,
+ .close = tpm_tis_lpc_close,
+ .get_desc = tpm_tis_get_desc,
+ .send = tis_senddata,
+ .recv = tis_readresponse,
+};
+
+static const struct udevice_id tpm_tis_lpc_ids[] = {
+ { .compatible = "infineon,slb9635lpc" },
+ { }
+};
+
+U_BOOT_DRIVER(tpm_tis_lpc) = {
+ .name = "tpm_tis_lpc",
+ .id = UCLASS_TPM,
+ .of_match = tpm_tis_lpc_ids,
+ .ops = &tpm_tis_lpc_ops,
+ .probe = tpm_tis_lpc_probe,
+ .priv_auto_alloc_size = sizeof(struct tpm_tis_lpc_priv),
+};
diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c
index ed4b039127..9ea98075b3 100644
--- a/drivers/tpm/tpm_tis_sandbox.c
+++ b/drivers/tpm/tpm_tis_sandbox.c
@@ -5,6 +5,8 @@
*/
#include <common.h>
+#include <dm.h>
+#include <tpm.h>
#include <asm/state.h>
#include <asm/unaligned.h>
#include <linux/crc8.h>
@@ -56,7 +58,7 @@ enum {
*/
static struct tpm_state {
uint8_t nvdata[NV_SEQ_COUNT][NV_DATA_SIZE];
-} state;
+} g_state;
/**
* sandbox_tpm_read_state() - read the sandbox EC state from the state file
@@ -82,7 +84,7 @@ static int sandbox_tpm_read_state(const void *blob, int node)
sprintf(prop_name, "nvdata%d", i);
prop = fdt_getprop(blob, node, prop_name, &len);
if (prop && len == NV_DATA_SIZE)
- memcpy(state.nvdata[i], prop, NV_DATA_SIZE);
+ memcpy(g_state.nvdata[i], prop, NV_DATA_SIZE);
}
return 0;
@@ -110,7 +112,7 @@ static int sandbox_tpm_write_state(void *blob, int node)
char prop_name[20];
sprintf(prop_name, "nvdata%d", i);
- fdt_setprop(blob, node, prop_name, state.nvdata[i],
+ fdt_setprop(blob, node, prop_name, g_state.nvdata[i],
NV_DATA_SIZE);
}
@@ -135,10 +137,11 @@ static int index_to_seq(uint32_t index)
return -1;
}
-int tis_sendrecv(const u8 *sendbuf, size_t send_size,
- u8 *recvbuf, size_t *recv_len)
+static int sandbox_tpm_xfer(struct udevice *dev, const uint8_t *sendbuf,
+ size_t send_size, uint8_t *recvbuf,
+ size_t *recv_len)
{
- struct tpm_state *tpm = &state;
+ struct tpm_state *tpm = dev_get_priv(dev);
uint32_t code, index, length, type;
uint8_t *data;
int seq;
@@ -241,20 +244,50 @@ int tis_sendrecv(const u8 *sendbuf, size_t send_size,
return 0;
}
-int tis_open(void)
+static int sandbox_tpm_get_desc(struct udevice *dev, char *buf, int size)
{
- printf("%s\n", __func__);
+ if (size < 15)
+ return -ENOSPC;
+
+ return snprintf(buf, size, "sandbox TPM");
+}
+
+static int sandbox_tpm_probe(struct udevice *dev)
+{
+ struct tpm_state *tpm = dev_get_priv(dev);
+
+ memcpy(tpm, &g_state, sizeof(*tpm));
+
return 0;
}
-int tis_close(void)
+static int sandbox_tpm_open(struct udevice *dev)
{
- printf("%s\n", __func__);
return 0;
}
-int tis_init(void)
+static int sandbox_tpm_close(struct udevice *dev)
{
- printf("%s\n", __func__);
return 0;
}
+
+static const struct tpm_ops sandbox_tpm_ops = {
+ .open = sandbox_tpm_open,
+ .close = sandbox_tpm_close,
+ .get_desc = sandbox_tpm_get_desc,
+ .xfer = sandbox_tpm_xfer,
+};
+
+static const struct udevice_id sandbox_tpm_ids[] = {
+ { .compatible = "google,sandbox-tpm" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_tpm) = {
+ .name = "sandbox_tpm",
+ .id = UCLASS_TPM,
+ .of_match = sandbox_tpm_ids,
+ .ops = &sandbox_tpm_ops,
+ .probe = sandbox_tpm_probe,
+ .priv_auto_alloc_size = sizeof(struct tpm_state),
+};
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 4a4f5593e9..31d54ab285 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -684,11 +684,13 @@ static void config_clock(const u32 timing[])
timing[PARAM_CPCON], timing[PARAM_LFCON]);
}
-static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config)
+static int fdt_decode_usb(struct udevice *dev, struct fdt_usb *config)
{
+ const void *blob = gd->fdt_blob;
+ int node = dev->of_offset;
const char *phy, *mode;
- config->reg = (struct usb_ctlr *)fdtdec_get_addr(blob, node, "reg");
+ config->reg = (struct usb_ctlr *)dev_get_addr(dev);
mode = fdt_getprop(blob, node, "dr_mode", NULL);
if (mode) {
if (0 == strcmp(mode, "host"))
@@ -812,7 +814,7 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev)
struct fdt_usb *priv = dev_get_priv(dev);
int ret;
- ret = fdt_decode_usb(gd->fdt_blob, dev->of_offset, priv);
+ ret = fdt_decode_usb(dev, priv);
if (ret)
return ret;
diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
index 251885b28b..28416ed106 100644
--- a/drivers/usb/host/xhci-exynos5.c
+++ b/drivers/usb/host/xhci-exynos5.c
@@ -61,7 +61,7 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev)
/*
* Get the base address for XHCI controller from the device node
*/
- plat->hcd_base = fdtdec_get_addr(blob, dev->of_offset, "reg");
+ plat->hcd_base = dev_get_addr(dev);
if (plat->hcd_base == FDT_ADDR_T_NONE) {
debug("Can't get the XHCI register base address\n");
return -ENXIO;
diff --git a/drivers/video/tegra124/dp.c b/drivers/video/tegra124/dp.c
index 3c0b721e3b..1bf92020ae 100644
--- a/drivers/video/tegra124/dp.c
+++ b/drivers/video/tegra124/dp.c
@@ -1555,9 +1555,8 @@ error_enable:
static int tegra_dp_ofdata_to_platdata(struct udevice *dev)
{
struct tegra_dp_plat *plat = dev_get_platdata(dev);
- const void *blob = gd->fdt_blob;
- plat->base = fdtdec_get_addr(blob, dev->of_offset, "reg");
+ plat->base = dev_get_addr(dev);
return 0;
}
diff --git a/dts/Kconfig b/dts/Kconfig
index d72a90905f..a04bb962af 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -58,7 +58,7 @@ config DEFAULT_DEVICE_TREE
config OF_SPL_REMOVE_PROPS
string "List of device tree properties to drop for SPL"
- depends on OF_CONTROL && SPL
+ depends on SPL_OF_CONTROL
default "pinctrl-0 pinctrl-names clocks clock-names interrupt-parent"
help
Since SPL normally runs in a reduced memory space, the device tree
diff --git a/include/configs/controlcenterd.h b/include/configs/controlcenterd.h
index 8f829eddb1..9a1f6d0782 100644
--- a/include/configs/controlcenterd.h
+++ b/include/configs/controlcenterd.h
@@ -226,14 +226,7 @@
#define CONFIG_SF_DEFAULT_MODE 0
#endif
-/*
- * TPM
- */
-#define CONFIG_TPM_ATMEL_TWI
-#define CONFIG_TPM
-#define CONFIG_TPM_AUTH_SESSIONS
#define CONFIG_SHA1
-#define CONFIG_CMD_TPM
/*
* MMC
diff --git a/include/configs/efi-x86.h b/include/configs/efi-x86.h
index 5779cfdb66..1c955d9e37 100644
--- a/include/configs/efi-x86.h
+++ b/include/configs/efi-x86.h
@@ -11,8 +11,6 @@
#undef CONFIG_CMD_SF_TEST
-#undef CONFIG_TPM
-#undef CONFIG_TPM_TIS_LPC
#undef CONFIG_TPM_TIS_BASE_ADDRESS
#undef CONFIG_CMD_IMLS
diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h
index e710f41f79..4866836d55 100644
--- a/include/configs/exynos5-common.h
+++ b/include/configs/exynos5-common.h
@@ -54,13 +54,6 @@
#define CONFIG_CMD_DTT
#define CONFIG_TMU_CMD_DTT
-/* TPM */
-#define CONFIG_TPM
-#define CONFIG_CMD_TPM
-#define CONFIG_TPM_TIS_I2C
-#define CONFIG_TPM_TIS_I2C_BUS_NUMBER 3
-#define CONFIG_TPM_TIS_I2C_SLAVE_ADDR 0x20
-
/* MMC SPL */
#define COPY_BL2_FNPTR_ADDR 0x02020030
#define CONFIG_SUPPORT_EMMC_BOOT
diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h
index 217312e5b7..3f153f24ae 100644
--- a/include/configs/x86-common.h
+++ b/include/configs/x86-common.h
@@ -47,8 +47,6 @@
#endif
/* Generic TPM interfaced through LPC bus */
-#define CONFIG_TPM
-#define CONFIG_TPM_TIS_LPC
#define CONFIG_TPM_TIS_BASE_ADDRESS 0xfed40000
/*-----------------------------------------------------------------------
diff --git a/include/dm/device-internal.h b/include/dm/device-internal.h
index 04884f1805..322d35a478 100644
--- a/include/dm/device-internal.h
+++ b/include/dm/device-internal.h
@@ -31,7 +31,7 @@ struct udevice;
* devices which use device tree.
* @of_offset: Offset of device tree node for this device. This is -1 for
* devices which don't use device tree.
- * @devp: Returns a pointer to the bound device
+ * @devp: if non-NULL, returns a pointer to the bound device
* @return 0 if OK, -ve on error
*/
int device_bind(struct udevice *parent, const struct driver *drv,
@@ -48,7 +48,7 @@ int device_bind(struct udevice *parent, const struct driver *drv,
* @pre_reloc_only: If true, bind the driver only if its DM_INIT_F flag is set.
* If false bind the driver always.
* @info: Name and platdata for this device
- * @devp: Returns a pointer to the bound device
+ * @devp: if non-NULL, returns a pointer to the bound device
* @return 0 if OK, -ve on error
*/
int device_bind_by_name(struct udevice *parent, bool pre_reloc_only,
diff --git a/include/dm/lists.h b/include/dm/lists.h
index 61610e69aa..4513d6a311 100644
--- a/include/dm/lists.h
+++ b/include/dm/lists.h
@@ -68,7 +68,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset,
* @parent: Parent device
* @drv_name: Name of driver to attach to this parent
* @dev_name: Name of the new device thus created
- * @devp: Returns the newly bound device
+ * @devp: If non-NULL, returns the newly bound device
*/
int device_bind_driver(struct udevice *parent, const char *drv_name,
const char *dev_name, struct udevice **devp);
@@ -83,7 +83,7 @@ int device_bind_driver(struct udevice *parent, const char *drv_name,
* @drv_name: Name of driver to attach to this parent
* @dev_name: Name of the new device thus created
* @node: Device tree node
- * @devp: Returns the newly bound device
+ * @devp: If non-NULL, returns the newly bound device
*/
int device_bind_driver_to_node(struct udevice *parent, const char *drv_name,
const char *dev_name, int node,
diff --git a/include/dm/pinctrl.h b/include/dm/pinctrl.h
new file mode 100644
index 0000000000..bc6fdb4a1f
--- /dev/null
+++ b/include/dm/pinctrl.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __PINCTRL_H
+#define __PINCTRL_H
+
+/**
+ * struct pinconf_param - pin config parameters
+ *
+ * @property: property name in DT nodes
+ * @param: ID for this config parameter
+ * @default_value: default value for this config parameter used in case
+ * no value is specified in DT nodes
+ */
+struct pinconf_param {
+ const char * const property;
+ unsigned int param;
+ u32 default_value;
+};
+
+/**
+ * struct pinctrl_ops - pin control operations, to be implemented by
+ * pin controller drivers.
+ *
+ * The @set_state is the only mandatory operation. You can implement your
+ * pinctrl driver with its own @set_state. In this case, the other callbacks
+ * are not required. Otherwise, generic pinctrl framework is also available;
+ * use pinctrl_generic_set_state for @set_state, and implement other operations
+ * depending on your necessity.
+ *
+ * @get_pins_count: return number of selectable named pins available
+ * in this driver. (necessary to parse "pins" property in DTS)
+ * @get_pin_name: return the pin name of the pin selector,
+ * called by the core to figure out which pin it shall do
+ * operations to. (necessary to parse "pins" property in DTS)
+ * @get_groups_count: return number of selectable named groups available
+ * in this driver. (necessary to parse "groups" property in DTS)
+ * @get_group_name: return the group name of the group selector,
+ * called by the core to figure out which pin group it shall do
+ * operations to. (necessary to parse "groups" property in DTS)
+ * @get_functions_count: return number of selectable named functions available
+ * in this driver. (necessary for pin-muxing)
+ * @get_function_name: return the function name of the muxing selector,
+ * called by the core to figure out which mux setting it shall map a
+ * certain device to. (necessary for pin-muxing)
+ * @pinmux_set: enable a certain muxing function with a certain pin.
+ * The @func_selector selects a certain function whereas @pin_selector
+ * selects a certain pin to be used. On simple controllers one of them
+ * may be ignored. (necessary for pin-muxing against a single pin)
+ * @pinmux_group_set: enable a certain muxing function with a certain pin
+ * group. The @func_selector selects a certain function whereas
+ * @group_selector selects a certain set of pins to be used. On simple
+ * controllers one of them may be ignored.
+ * (necessary for pin-muxing against a pin group)
+ * @pinconf_num_params: number of driver-specific parameters to be parsed
+ * from device trees (necessary for pin-configuration)
+ * @pinconf_params: list of driver_specific parameters to be parsed from
+ * device trees (necessary for pin-configuration)
+ * @pinconf_set: configure an individual pin with a given parameter.
+ * (necessary for pin-configuration against a single pin)
+ * @pinconf_group_set: configure all pins in a group with a given parameter.
+ * (necessary for pin-configuration against a pin group)
+ * @set_state: do pinctrl operations specified by @config, a pseudo device
+ * pointing a config node. (necessary for pinctrl_full)
+ * @set_state_simple: do needed pinctrl operations for a peripherl @periph.
+ * (necessary for pinctrl_simple)
+ */
+struct pinctrl_ops {
+ int (*get_pins_count)(struct udevice *dev);
+ const char *(*get_pin_name)(struct udevice *dev, unsigned selector);
+ int (*get_groups_count)(struct udevice *dev);
+ const char *(*get_group_name)(struct udevice *dev, unsigned selector);
+ int (*get_functions_count)(struct udevice *dev);
+ const char *(*get_function_name)(struct udevice *dev,
+ unsigned selector);
+ int (*pinmux_set)(struct udevice *dev, unsigned pin_selector,
+ unsigned func_selector);
+ int (*pinmux_group_set)(struct udevice *dev, unsigned group_selector,
+ unsigned func_selector);
+ unsigned int pinconf_num_params;
+ const struct pinconf_param *pinconf_params;
+ int (*pinconf_set)(struct udevice *dev, unsigned pin_selector,
+ unsigned param, unsigned argument);
+ int (*pinconf_group_set)(struct udevice *dev, unsigned group_selector,
+ unsigned param, unsigned argument);
+ int (*set_state)(struct udevice *dev, struct udevice *config);
+ int (*set_state_simple)(struct udevice *dev, struct udevice *periph);
+};
+
+#define pinctrl_get_ops(dev) ((struct pinctrl_ops *)(dev)->driver->ops)
+
+/**
+ * Generic pin configuration paramters
+ *
+ * @PIN_CONFIG_BIAS_DISABLE: disable any pin bias on the pin, a
+ * transition from say pull-up to pull-down implies that you disable
+ * pull-up in the process, this setting disables all biasing.
+ * @PIN_CONFIG_BIAS_HIGH_IMPEDANCE: the pin will be set to a high impedance
+ * mode, also know as "third-state" (tristate) or "high-Z" or "floating".
+ * On output pins this effectively disconnects the pin, which is useful
+ * if for example some other pin is going to drive the signal connected
+ * to it for a while. Pins used for input are usually always high
+ * impedance.
+ * @PIN_CONFIG_BIAS_BUS_HOLD: the pin will be set to weakly latch so that it
+ * weakly drives the last value on a tristate bus, also known as a "bus
+ * holder", "bus keeper" or "repeater". This allows another device on the
+ * bus to change the value by driving the bus high or low and switching to
+ * tristate. The argument is ignored.
+ * @PIN_CONFIG_BIAS_PULL_UP: the pin will be pulled up (usually with high
+ * impedance to VDD). If the argument is != 0 pull-up is enabled,
+ * if it is 0, pull-up is total, i.e. the pin is connected to VDD.
+ * @PIN_CONFIG_BIAS_PULL_DOWN: the pin will be pulled down (usually with high
+ * impedance to GROUND). If the argument is != 0 pull-down is enabled,
+ * if it is 0, pull-down is total, i.e. the pin is connected to GROUND.
+ * @PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: the pin will be pulled up or down based
+ * on embedded knowledge of the controller hardware, like current mux
+ * function. The pull direction and possibly strength too will normally
+ * be decided completely inside the hardware block and not be readable
+ * from the kernel side.
+ * If the argument is != 0 pull up/down is enabled, if it is 0, the
+ * configuration is ignored. The proper way to disable it is to use
+ * @PIN_CONFIG_BIAS_DISABLE.
+ * @PIN_CONFIG_DRIVE_PUSH_PULL: the pin will be driven actively high and
+ * low, this is the most typical case and is typically achieved with two
+ * active transistors on the output. Setting this config will enable
+ * push-pull mode, the argument is ignored.
+ * @PIN_CONFIG_DRIVE_OPEN_DRAIN: the pin will be driven with open drain (open
+ * collector) which means it is usually wired with other output ports
+ * which are then pulled up with an external resistor. Setting this
+ * config will enable open drain mode, the argument is ignored.
+ * @PIN_CONFIG_DRIVE_OPEN_SOURCE: the pin will be driven with open source
+ * (open emitter). Setting this config will enable open source mode, the
+ * argument is ignored.
+ * @PIN_CONFIG_DRIVE_STRENGTH: the pin will sink or source at most the current
+ * passed as argument. The argument is in mA.
+ * @PIN_CONFIG_INPUT_ENABLE: enable the pin's input. Note that this does not
+ * affect the pin's ability to drive output. 1 enables input, 0 disables
+ * input.
+ * @PIN_CONFIG_INPUT_SCHMITT_ENABLE: control schmitt-trigger mode on the pin.
+ * If the argument != 0, schmitt-trigger mode is enabled. If it's 0,
+ * schmitt-trigger mode is disabled.
+ * @PIN_CONFIG_INPUT_SCHMITT: this will configure an input pin to run in
+ * schmitt-trigger mode. If the schmitt-trigger has adjustable hysteresis,
+ * the threshold value is given on a custom format as argument when
+ * setting pins to this mode.
+ * @PIN_CONFIG_INPUT_DEBOUNCE: this will configure the pin to debounce mode,
+ * which means it will wait for signals to settle when reading inputs. The
+ * argument gives the debounce time in usecs. Setting the
+ * argument to zero turns debouncing off.
+ * @PIN_CONFIG_POWER_SOURCE: if the pin can select between different power
+ * supplies, the argument to this parameter (on a custom format) tells
+ * the driver which alternative power source to use.
+ * @PIN_CONFIG_SLEW_RATE: if the pin can select slew rate, the argument to
+ * this parameter (on a custom format) tells the driver which alternative
+ * slew rate to use.
+ * @PIN_CONFIG_LOW_POWER_MODE: this will configure the pin for low power
+ * operation, if several modes of operation are supported these can be
+ * passed in the argument on a custom form, else just use argument 1
+ * to indicate low power mode, argument 0 turns low power mode off.
+ * @PIN_CONFIG_OUTPUT: this will configure the pin as an output. Use argument
+ * 1 to indicate high level, argument 0 to indicate low level. (Please
+ * see Documentation/pinctrl.txt, section "GPIO mode pitfalls" for a
+ * discussion around this parameter.)
+ * @PIN_CONFIG_END: this is the last enumerator for pin configurations, if
+ * you need to pass in custom configurations to the pin controller, use
+ * PIN_CONFIG_END+1 as the base offset.
+ */
+#define PIN_CONFIG_BIAS_DISABLE 0
+#define PIN_CONFIG_BIAS_HIGH_IMPEDANCE 1
+#define PIN_CONFIG_BIAS_BUS_HOLD 2
+#define PIN_CONFIG_BIAS_PULL_UP 3
+#define PIN_CONFIG_BIAS_PULL_DOWN 4
+#define PIN_CONFIG_BIAS_PULL_PIN_DEFAULT 5
+#define PIN_CONFIG_DRIVE_PUSH_PULL 6
+#define PIN_CONFIG_DRIVE_OPEN_DRAIN 7
+#define PIN_CONFIG_DRIVE_OPEN_SOURCE 8
+#define PIN_CONFIG_DRIVE_STRENGTH 9
+#define PIN_CONFIG_INPUT_ENABLE 10
+#define PIN_CONFIG_INPUT_SCHMITT_ENABLE 11
+#define PIN_CONFIG_INPUT_SCHMITT 12
+#define PIN_CONFIG_INPUT_DEBOUNCE 13
+#define PIN_CONFIG_POWER_SOURCE 14
+#define PIN_CONFIG_SLEW_RATE 15
+#define PIN_CONFIG_LOW_POWER_MODE 16
+#define PIN_CONFIG_OUTPUT 17
+#define PIN_CONFIG_END 0x7FFF
+
+#if CONFIG_IS_ENABLED(PINCTRL_GENERIC)
+/**
+ * pinctrl_generic_set_state() - generic set_state operation
+ * Parse the DT node of @config and its children and handle generic properties
+ * such as "pins", "groups", "functions", and pin configuration parameters.
+ *
+ * @pctldev: pinctrl device
+ * @config: config device (pseudo device), pointing a config node in DTS
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_generic_set_state(struct udevice *pctldev, struct udevice *config);
+#else
+static inline int pinctrl_generic_set_state(struct udevice *pctldev,
+ struct udevice *config)
+{
+ return -EINVAL;
+}
+#endif
+
+#if CONFIG_IS_ENABLED(PINCTRL)
+/**
+ * pinctrl_select_state() - set a device to a given state
+ *
+ * @dev: peripheral device
+ * @statename: state name, like "default"
+ * @return: 0 on success, or negative error code on failure
+ */
+int pinctrl_select_state(struct udevice *dev, const char *statename);
+#else
+static inline int pinctrl_select_state(struct udevice *dev,
+ const char *statename)
+{
+ return -EINVAL;
+}
+#endif
+
+#endif /* __PINCTRL_H */
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index c744044bb8..1eeec74964 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -44,6 +44,8 @@ enum uclass_id {
UCLASS_PCH, /* x86 platform controller hub */
UCLASS_PCI, /* PCI bus */
UCLASS_PCI_GENERIC, /* Generic PCI bus device */
+ UCLASS_PINCTRL, /* Pinctrl (pin muxing/configuration) device */
+ UCLASS_PINCONFIG, /* Pin configuration node device */
UCLASS_PMIC, /* PMIC I/O device */
UCLASS_REGULATOR, /* Regulator device */
UCLASS_RESET, /* Reset device */
@@ -54,6 +56,7 @@ enum uclass_id {
UCLASS_SPI_GENERIC, /* Generic SPI flash target */
UCLASS_SYSCON, /* System configuration device */
UCLASS_THERMAL, /* Thermal sensor */
+ UCLASS_TPM, /* Trusted Platform Module TIS interface */
UCLASS_USB, /* USB bus */
UCLASS_USB_DEV_GENERIC, /* USB generic device */
UCLASS_USB_HUB, /* USB hub */
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index d56877c898..d214b88734 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -240,12 +240,7 @@ int uclass_resolve_seq(struct udevice *dev);
* are no more devices.
* @uc: uclass to scan
*/
-#define uclass_foreach_dev(pos, uc) \
- for (pos = list_entry((&(uc)->dev_head)->next, typeof(*pos), \
- uclass_node); \
- prefetch(pos->uclass_node.next), \
- &pos->uclass_node != (&(uc)->dev_head); \
- pos = list_entry(pos->uclass_node.next, typeof(*pos), \
- uclass_node))
+#define uclass_foreach_dev(pos, uc) \
+ list_for_each_entry(pos, &uc->dev_head, uclass_node)
#endif
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 0cb6fa0075..3e237312a7 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -154,8 +154,6 @@ enum fdt_compat_id {
COMPAT_MAXIM_MAX77686_PMIC, /* MAX77686 PMIC */
COMPAT_GENERIC_SPI_FLASH, /* Generic SPI Flash chip */
COMPAT_MAXIM_98095_CODEC, /* MAX98095 Codec */
- COMPAT_INFINEON_SLB9635_TPM, /* Infineon SLB9635 TPM */
- COMPAT_INFINEON_SLB9645_TPM, /* Infineon SLB9645 TPM */
COMPAT_SAMSUNG_EXYNOS5_I2C, /* Exynos5 High Speed I2C Controller */
COMPAT_SANDBOX_LCD_SDL, /* Sandbox LCD emulation with SDL */
COMPAT_SAMSUNG_EXYNOS_SYSMMU, /* Exynos sysmmu */
diff --git a/include/tis.h b/include/tis.h
index 40a1f86762..1985d9e60e 100644
--- a/include/tis.h
+++ b/include/tis.h
@@ -7,6 +7,8 @@
#ifndef __TIS_H
#define __TIS_H
+#ifndef CONFIG_DM_TPM
+
#include <common.h>
/* Low-level interface to access TPM */
@@ -53,5 +55,6 @@ int tis_close(void);
*/
int tis_sendrecv(const uint8_t *sendbuf, size_t send_size, uint8_t *recvbuf,
size_t *recv_len);
+#endif
#endif /* __TIS_H */
diff --git a/include/tpm.h b/include/tpm.h
index 88aeba28e3..086b672718 100644
--- a/include/tpm.h
+++ b/include/tpm.h
@@ -15,6 +15,17 @@
* Specification for definitions of TPM commands.
*/
+#define TPM_HEADER_SIZE 10
+
+enum tpm_duration {
+ TPM_SHORT = 0,
+ TPM_MEDIUM = 1,
+ TPM_LONG = 2,
+ TPM_UNDEFINED,
+
+ TPM_DURATION_COUNT,
+};
+
enum tpm_startup_type {
TPM_ST_CLEAR = 0x0001,
TPM_ST_STATE = 0x0002,
@@ -38,6 +49,15 @@ enum tpm_nv_index {
TPM_NV_INDEX_DIR = 0x10000001,
};
+#define TPM_NV_PER_GLOBALLOCK (1U << 15)
+#define TPM_NV_PER_PPWRITE (1U << 0)
+#define TPM_NV_PER_READ_STCLEAR (1U << 31)
+#define TPM_NV_PER_WRITE_STCLEAR (1U << 14)
+
+enum {
+ TPM_PUBEK_SIZE = 256,
+};
+
/**
* TPM return codes as defined in the TCG Main specification
* (TPM Main Part 2 Structures; Specification version 1.2)
@@ -152,12 +172,217 @@ enum tpm_return_code {
TPM_DEFEND_LOCK_RUNNING = TPM_BASE + TPM_NON_FATAL + 3,
};
+struct tpm_permanent_flags {
+ __be16 tag;
+ u8 disable;
+ u8 ownership;
+ u8 deactivated;
+ u8 read_pubek;
+ u8 disable_owner_clear;
+ u8 allow_maintenance;
+ u8 physical_presence_lifetime_lock;
+ u8 physical_presence_hw_enable;
+ u8 physical_presence_cmd_enable;
+ u8 cekp_used;
+ u8 tpm_post;
+ u8 tpm_post_lock;
+ u8 fips;
+ u8 operator;
+ u8 enable_revoke_ek;
+ u8 nv_locked;
+ u8 read_srk_pub;
+ u8 tpm_established;
+ u8 maintenance_done;
+ u8 disable_full_da_logic_info;
+} __packed;
+
+#ifdef CONFIG_DM_TPM
+
+/* Max buffer size supported by our tpm */
+#define TPM_DEV_BUFSIZE 1260
+
+/**
+ * struct tpm_chip_priv - Information about a TPM, stored by the uclass
+ *
+ * These values must be set up by the device's probe() method before
+ * communcation is attempted. If the device has an xfer() method, this is
+ * not needed. There is no need to set up @buf.
+ *
+ * @duration_ms: Length of each duration type in milliseconds
+ * @retry_time_ms: Time to wait before retrying receive
+ */
+struct tpm_chip_priv {
+ uint duration_ms[TPM_DURATION_COUNT];
+ uint retry_time_ms;
+ u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */
+};
+
+/**
+ * struct tpm_ops - low-level TPM operations
+ *
+ * These are designed to avoid loops and delays in the driver itself. These
+ * should be handled in the uclass.
+ *
+ * In gneral you should implement everything except xfer(). Where you need
+ * complete control of the transfer, then xfer() can be provided and will
+ * override the other methods.
+ *
+ * This interface is for low-level TPM access. It does not understand the
+ * concept of localities or the various TPM messages. That interface is
+ * defined in the functions later on in this file, but they all translate
+ * to bytes which are sent and received.
+ */
+struct tpm_ops {
+ /**
+ * open() - Request access to locality 0 for the caller
+ *
+ * After all commands have been completed the caller should call
+ * close().
+ *
+ * @dev: Device to close
+ * @return 0 ok OK, -ve on error
+ */
+ int (*open)(struct udevice *dev);
+
+ /**
+ * close() - Close the current session
+ *
+ * Releasing the locked locality. Returns 0 on success, -ve 1 on
+ * failure (in case lock removal did not succeed).
+ *
+ * @dev: Device to close
+ * @return 0 ok OK, -ve on error
+ */
+ int (*close)(struct udevice *dev);
+
+ /**
+ * get_desc() - Get a text description of the TPM
+ *
+ * @dev: Device to check
+ * @buf: Buffer to put the string
+ * @size: Maximum size of buffer
+ * @return length of string, or -ENOSPC it no space
+ */
+ int (*get_desc)(struct udevice *dev, char *buf, int size);
+
+ /**
+ * send() - send data to the TPM
+ *
+ * @dev: Device to talk to
+ * @sendbuf: Buffer of the data to send
+ * @send_size: Size of the data to send
+ *
+ * Returns 0 on success or -ve on failure.
+ */
+ int (*send)(struct udevice *dev, const uint8_t *sendbuf,
+ size_t send_size);
+
+ /**
+ * recv() - receive a response from the TPM
+ *
+ * @dev: Device to talk to
+ * @recvbuf: Buffer to save the response to
+ * @max_size: Maximum number of bytes to receive
+ *
+ * Returns number of bytes received on success, -EAGAIN if the TPM
+ * response is not ready, -EINTR if cancelled, or other -ve value on
+ * failure.
+ */
+ int (*recv)(struct udevice *dev, uint8_t *recvbuf, size_t max_size);
+
+ /**
+ * cleanup() - clean up after an operation in progress
+ *
+ * This is called if receiving times out. The TPM may need to abort
+ * the current transaction if it did not complete, and make itself
+ * ready for another.
+ *
+ * @dev: Device to talk to
+ */
+ int (*cleanup)(struct udevice *dev);
+
+ /**
+ * xfer() - send data to the TPM and get response
+ *
+ * This method is optional. If it exists it is used in preference
+ * to send(), recv() and cleanup(). It should handle all aspects of
+ * TPM communication for a single transfer.
+ *
+ * @dev: Device to talk to
+ * @sendbuf: Buffer of the data to send
+ * @send_size: Size of the data to send
+ * @recvbuf: Buffer to save the response to
+ * @recv_size: Pointer to the size of the response buffer
+ *
+ * Returns 0 on success (and places the number of response bytes at
+ * recv_size) or -ve on failure.
+ */
+ int (*xfer)(struct udevice *dev, const uint8_t *sendbuf,
+ size_t send_size, uint8_t *recvbuf, size_t *recv_size);
+};
+
+#define tpm_get_ops(dev) ((struct tpm_ops *)device_get_ops(dev))
+
+/**
+ * tpm_open() - Request access to locality 0 for the caller
+ *
+ * After all commands have been completed the caller is supposed to
+ * call tpm_close().
+ *
+ * Returns 0 on success, -ve on failure.
+ */
+int tpm_open(struct udevice *dev);
+
+/**
+ * tpm_close() - Close the current session
+ *
+ * Releasing the locked locality. Returns 0 on success, -ve 1 on
+ * failure (in case lock removal did not succeed).
+ */
+int tpm_close(struct udevice *dev);
+
+/**
+ * tpm_get_desc() - Get a text description of the TPM
+ *
+ * @dev: Device to check
+ * @buf: Buffer to put the string
+ * @size: Maximum size of buffer
+ * @return length of string, or -ENOSPC it no space
+ */
+int tpm_get_desc(struct udevice *dev, char *buf, int size);
+
+/**
+ * tpm_xfer() - send data to the TPM and get response
+ *
+ * This first uses the device's send() method to send the bytes. Then it calls
+ * recv() to get the reply. If recv() returns -EAGAIN then it will delay a
+ * short time and then call recv() again.
+ *
+ * Regardless of whether recv() completes successfully, it will then call
+ * cleanup() to finish the transaction.
+ *
+ * Note that the outgoing data is inspected to determine command type
+ * (ordinal) and a timeout is used for that command type.
+ *
+ * @sendbuf - buffer of the data to send
+ * @send_size size of the data to send
+ * @recvbuf - memory to save the response to
+ * @recv_len - pointer to the size of the response buffer
+ *
+ * Returns 0 on success (and places the number of response bytes at
+ * recv_len) or -ve on failure.
+ */
+int tpm_xfer(struct udevice *dev, const uint8_t *sendbuf, size_t send_size,
+ uint8_t *recvbuf, size_t *recv_size);
+
+#endif /* CONFIG_DM_TPM */
+
/**
* Initialize TPM device. It must be called before any TPM commands.
*
* @return 0 on success, non-0 on error.
*/
-uint32_t tpm_init(void);
+int tpm_init(void);
/**
* Issue a TPM_Startup command.
@@ -359,4 +584,20 @@ uint32_t tpm_load_key2_oiap(uint32_t parent_handle,
uint32_t tpm_get_pub_key_oiap(uint32_t key_handle, const void *usage_auth,
void *pubkey, size_t *pubkey_len);
+/**
+ * Get the TPM permanent flags value
+ *
+ * @param pflags Place to put permanent flags
+ * @return return code of the operation
+ */
+uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags);
+
+/**
+ * Get the TPM permissions
+ *
+ * @param perm Returns permissions value
+ * @return return code of the operation
+ */
+uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm);
+
#endif /* __TPM_H */
diff --git a/lib/Kconfig b/lib/Kconfig
index 884218a3c6..067307276e 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -54,6 +54,16 @@ source lib/dhry/Kconfig
source lib/rsa/Kconfig
+config TPM
+ bool "Trusted Platform Module (TPM) Support"
+ help
+ This enables support for TPMs which can be used to provide security
+ features for your board. The TPM can be connected via LPC or I2C
+ and a sandbox TPM is provided for testing purposes. Use the 'tpm'
+ command to interactive the TPM. Driver model support is provided
+ for the low-level TPM interface, but only one TPM is supported at
+ a time by the TPM library.
+
menu "Hashing Support"
config SHA1
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 81b54f88e8..29c5ccb214 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -58,8 +58,6 @@ static const char * const compat_names[COMPAT_COUNT] = {
COMPAT(MAXIM_MAX77686_PMIC, "maxim,max77686"),
COMPAT(GENERIC_SPI_FLASH, "spi-flash"),
COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"),
- COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"),
- COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645tt"),
COMPAT(SAMSUNG_EXYNOS5_I2C, "samsung,exynos5-hsi2c"),
COMPAT(SANDBOX_LCD_SDL, "sandbox,lcd-sdl"),
COMPAT(SAMSUNG_EXYNOS_SYSMMU, "samsung,sysmmu-v3.3"),
diff --git a/lib/tpm.c b/lib/tpm.c
index d9789b022a..5d5f707e37 100644
--- a/lib/tpm.c
+++ b/lib/tpm.c
@@ -6,10 +6,11 @@
*/
#include <common.h>
-#include <stdarg.h>
-#include <u-boot/sha1.h>
+#include <dm.h>
+#include <tis.h>
#include <tpm.h>
#include <asm/unaligned.h>
+#include <u-boot/sha1.h>
/* Internal error of TPM command library */
#define TPM_LIB_ERROR ((uint32_t)~0u)
@@ -17,7 +18,6 @@
/* Useful constants */
enum {
COMMAND_BUFFER_SIZE = 256,
- TPM_PUBEK_SIZE = 256,
TPM_REQUEST_HEADER_LENGTH = 10,
TPM_RESPONSE_HEADER_LENGTH = 10,
PCR_DIGEST_LENGTH = 20,
@@ -240,9 +240,20 @@ static uint32_t tpm_sendrecv_command(const void *command,
response = response_buffer;
response_length = sizeof(response_buffer);
}
+#ifdef CONFIG_DM_TPM
+ struct udevice *dev;
+ int ret;
+
+ ret = uclass_first_device(UCLASS_TPM, &dev);
+ if (ret)
+ return ret;
+ err = tpm_xfer(dev, command, tpm_command_size(command),
+ response, &response_length);
+#else
err = tis_sendrecv(command, tpm_command_size(command),
response, &response_length);
- if (err)
+#endif
+ if (err < 0)
return TPM_LIB_ERROR;
if (size_ptr)
*size_ptr = response_length;
@@ -250,15 +261,24 @@ static uint32_t tpm_sendrecv_command(const void *command,
return tpm_return_code(response);
}
-uint32_t tpm_init(void)
+int tpm_init(void)
{
- uint32_t err;
+ int err;
+
+#ifdef CONFIG_DM_TPM
+ struct udevice *dev;
+ err = uclass_first_device(UCLASS_TPM, &dev);
+ if (err)
+ return err;
+ return tpm_open(dev);
+#else
err = tis_init();
if (err)
return err;
return tis_open();
+#endif
}
uint32_t tpm_startup(enum tpm_startup_type mode)
@@ -589,6 +609,56 @@ uint32_t tpm_get_capability(uint32_t cap_area, uint32_t sub_cap,
return 0;
}
+uint32_t tpm_get_permanent_flags(struct tpm_permanent_flags *pflags)
+{
+ const uint8_t command[22] = {
+ 0x0, 0xc1, /* TPM_TAG */
+ 0x0, 0x0, 0x0, 0x16, /* parameter size */
+ 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
+ 0x0, 0x0, 0x0, 0x4, /* TPM_CAP_FLAG_PERM */
+ 0x0, 0x0, 0x0, 0x4, /* subcap size */
+ 0x0, 0x0, 0x1, 0x8, /* subcap value */
+ };
+ uint8_t response[COMMAND_BUFFER_SIZE];
+ size_t response_length = sizeof(response);
+ uint32_t err;
+
+ err = tpm_sendrecv_command(command, response, &response_length);
+ if (err)
+ return err;
+ memcpy(pflags, response + TPM_HEADER_SIZE, sizeof(*pflags));
+
+ return 0;
+}
+
+uint32_t tpm_get_permissions(uint32_t index, uint32_t *perm)
+{
+ const uint8_t command[22] = {
+ 0x0, 0xc1, /* TPM_TAG */
+ 0x0, 0x0, 0x0, 0x16, /* parameter size */
+ 0x0, 0x0, 0x0, 0x65, /* TPM_COMMAND_CODE */
+ 0x0, 0x0, 0x0, 0x11,
+ 0x0, 0x0, 0x0, 0x4,
+ };
+ const size_t index_offset = 18;
+ const size_t perm_offset = 60;
+ uint8_t buf[COMMAND_BUFFER_SIZE], response[COMMAND_BUFFER_SIZE];
+ size_t response_length = sizeof(response);
+ uint32_t err;
+
+ if (pack_byte_string(buf, sizeof(buf), "d", 0, command, sizeof(command),
+ index_offset, index))
+ return TPM_LIB_ERROR;
+ err = tpm_sendrecv_command(buf, response, &response_length);
+ if (err)
+ return err;
+ if (unpack_byte_string(response, response_length, "d",
+ perm_offset, perm))
+ return TPM_LIB_ERROR;
+
+ return 0;
+}
+
#ifdef CONFIG_TPM_AUTH_SESSIONS
/**
diff --git a/tools/patman/series.py b/tools/patman/series.py
index a17a7d1de7..3399f2c8dd 100644
--- a/tools/patman/series.py
+++ b/tools/patman/series.py
@@ -12,7 +12,7 @@ import terminal
# Series-xxx tags that we understand
valid_series = ['to', 'cc', 'version', 'changes', 'prefix', 'notes', 'name',
- 'cover-cc', 'process_log']
+ 'cover_cc', 'process_log']
class Series(dict):
"""Holds information about a patch series, including all tags.