]> git.karo-electronics.de Git - karo-tx-uboot.git/commitdiff
Merge git://git.denx.de/u-boot-dm
authorTom Rini <trini@konsulko.com>
Mon, 31 Aug 2015 15:43:47 +0000 (11:43 -0400)
committerTom Rini <trini@konsulko.com>
Mon, 31 Aug 2015 15:43:47 +0000 (11:43 -0400)
83 files changed:
README
arch/arm/dts/exynos5250-snow.dts
arch/arm/dts/exynos5250-spring.dts
arch/arm/dts/exynos5420-peach-pit.dts
arch/arm/dts/exynos5800-peach-pi.dts
arch/sandbox/dts/sandbox.dts
arch/x86/dts/chromebook_link.dts
arch/x86/dts/chromebox_panther.dts
board/samsung/common/exynos5-dt.c
common/Kconfig
common/Makefile
common/cmd_i2c.c
common/cmd_tpm.c
common/cmd_tpm_test.c [new file with mode: 0644]
configs/chromebook_link_defconfig
configs/chromebox_panther_defconfig
configs/controlcenterd_36BIT_SDCARD_DEVELOP_defconfig
configs/controlcenterd_36BIT_SDCARD_defconfig
configs/controlcenterd_TRAILBLAZER_DEVELOP_defconfig
configs/controlcenterd_TRAILBLAZER_defconfig
configs/coreboot-x86_defconfig
configs/nyan-big_defconfig
configs/peach-pi_defconfig
configs/peach-pit_defconfig
configs/sandbox_defconfig
configs/snow_defconfig
configs/spring_defconfig
drivers/Kconfig
drivers/Makefile
drivers/core/Kconfig
drivers/core/Makefile
drivers/core/device.c
drivers/gpio/s5p_gpio.c
drivers/gpio/sunxi_gpio.c
drivers/gpio/tegra_gpio.c
drivers/i2c/s3c24x0_i2c.c
drivers/i2c/tegra_i2c.c
drivers/pinctrl/Kconfig [new file with mode: 0644]
drivers/pinctrl/Makefile [new file with mode: 0644]
drivers/pinctrl/pinctrl-generic.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-sandbox.c [new file with mode: 0644]
drivers/pinctrl/pinctrl-uclass.c [new file with mode: 0644]
drivers/serial/ns16550.c
drivers/serial/serial_arc.c
drivers/serial/serial_pl01x.c
drivers/serial/serial_s5p.c
drivers/spi/designware_spi.c
drivers/spi/exynos_spi.c
drivers/spi/fsl_dspi.c
drivers/spi/tegra114_spi.c
drivers/spi/tegra20_sflash.c
drivers/spi/tegra20_slink.c
drivers/spi/zynq_spi.c
drivers/tpm/Kconfig
drivers/tpm/Makefile
drivers/tpm/tpm-uclass.c [new file with mode: 0644]
drivers/tpm/tpm.c [deleted file]
drivers/tpm/tpm_atmel_twi.c
drivers/tpm/tpm_internal.h [new file with mode: 0644]
drivers/tpm/tpm_tis_i2c.c
drivers/tpm/tpm_tis_i2c.h [moved from drivers/tpm/tpm_private.h with 54% similarity]
drivers/tpm/tpm_tis_lpc.c
drivers/tpm/tpm_tis_sandbox.c
drivers/usb/host/ehci-tegra.c
drivers/usb/host/xhci-exynos5.c
drivers/video/tegra124/dp.c
dts/Kconfig
include/configs/controlcenterd.h
include/configs/efi-x86.h
include/configs/exynos5-common.h
include/configs/x86-common.h
include/dm/device-internal.h
include/dm/lists.h
include/dm/pinctrl.h [new file with mode: 0644]
include/dm/uclass-id.h
include/dm/uclass.h
include/fdtdec.h
include/tis.h
include/tpm.h
lib/Kconfig
lib/fdtdec.c
lib/tpm.c
tools/patman/series.py

diff --git a/README b/README
index a52ff46c213d9afe4fa9b624679582f319515b61..1acc3559680c73c8e116a8be57a7d97d65c6d18e 100644 (file)
--- 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
 
index 32c0098bd8be7138925d867a387cd31bd701a203..bda549998861c65b6cfd66c9c29a4fc68996c3fb 100644 (file)
                };
        };
 
+       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 {
index 76d5323dc314ab7aedbcd910995fdb09f9aa1345..81b3d29f9cf032d962f1e41c8dc0168e8079d654 100644 (file)
                                         <&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>;
index 2d2b7c9bdea544ba9e15047cb383828c26d7c520..16d52f4928121afce9ca12c4d263c6ae6ddfea67 100644 (file)
 
        i2c@12E10000 { /* i2c9 */
                clock-frequency = <400000>;
-                tpm@20 {
-                        compatible = "infineon,slb9645tt";
-                        reg = <0x20>;
+               tpm@20 {
+                       compatible = "infineon,slb9645tt";
+                       reg = <0x20>;
                };
        };
 
index 600c2948cf3eebdce9be99b91e2ffcbe4224d6f9..1d7ff23c933cbeef16c088be12030b069b08c761 100644 (file)
@@ -72,9 +72,9 @@
 
        i2c@12E10000 { /* i2c9 */
                clock-frequency = <400000>;
-                tpm@20 {
-                        compatible = "infineon,slb9645tt";
-                        reg = <0x20>;
+               tpm@20 {
+                       compatible = "infineon,slb9645tt";
+                       reg = <0x20>;
                };
        };
 
index 89275271413095e2d4d6242ee523e4206070ac8c..65b9125f5fcc753f87f85cf964c9b8f013986307 100644 (file)
@@ -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";
                };
        };
 
+       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>;
                sides = <4>;
        };
 
+       tpm {
+               compatible = "google,sandbox-tpm";
+       };
+
        triangle {
                compatible = "demo-shape";
                colour = "cyan";
        uart0: serial {
                compatible = "sandbox,serial";
                sandbox,text-colour = "cyan";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_serial0>;
        };
 
        usb@0 {
index ad390bf11721a3b161c3b55a1c517ddf1e55eb5b..4291141dfee898a642394f65b51c911825371259 100644 (file)
                };
        };
 
+       tpm {
+               reg = <0xfed40000 0x5000>;
+               compatible = "infineon,slb9635lpc";
+       };
+
        microcode {
                update@0 {
 #include "microcode/m12306a9_0000001b.dtsi"
index 84eae3ab6513ac0990ebab28255936d24ff684c0..36feb96a94d09ee2fcabe315be1f59ca3feba95b 100644 (file)
@@ -62,4 +62,9 @@
                };
        };
 
+       tpm {
+               reg = <0xfed40000 0x5000>;
+               compatible = "infineon,slb9635lpc";
+       };
+
 };
index 7d1b88a9b8a17d5094d01831d268418a35814960..4250f722da7bd5160bb5a74e112d201b9a101f5a 100644 (file)
@@ -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);
index 88dc0160796e745a8ec7f683591e75f45fa0c758..2c42b8e4d0346e339543e908f8d76636f39b7332 100644 (file)
@@ -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
index dc82433e90dee24e41423a1e7042313126c24d79..f4ba8782f543594a94c0ee995f293875b4ca1a20 100644 (file)
@@ -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
index 1bc0db860c3344dad85466fc52c0c61cddca3998..864b2596cca515d3e442a25a586fb79f56c33081 100644 (file)
@@ -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)
index 0294952e69a73849293d43a9974d1d2a1bbdecfc..97501cc3d1896342c4b5da6372bf10c177274e75 100644 (file)
@@ -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 (file)
index 0000000..65332d1
--- /dev/null
@@ -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");
index b987f3f52f690c30afffe6ffcf7f10f22b53dd11..985573667ac9697ce06ee6f24d0b18b6a79bab53 100644 (file)
@@ -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
index e82c8ecf64e90e44795e0ec2a662917f3ed2c4b1..c75b20d24db737ac705157bb4adef3fa643b1baf 100644 (file)
@@ -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
index 37ead03a43258416b15d4f5692e1def5662e650d..c8ab862edccf448e635a0b2e41a86e3c48698844 100644 (file)
@@ -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
index 7166edbf9d4a6e467a3f45e252c50b277937f0ac..21c0eab53dcc9f28396687969917e80faa199c4d 100644 (file)
@@ -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
index d99fcd45135560589b63c4f6fe1f3d58cf73f608..c3a0920d7cdcfe3e680a4e78180fdadb5a319858 100644 (file)
@@ -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
index 3557aea1ebb57ec29311952f8eb362cb05cb3ff6..08aae9ae2dbd8aaabd68baa2bddb7af93998b7b6 100644 (file)
@@ -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
index df3a624ecd119dc320d4d1db3001bcf176e9018b..ebaf86bc7fb80a5a9e4dea3bfa47b169ad64e87b 100644 (file)
@@ -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
index 274e955a37bef53df540bb617469a9541dea2708..6464c379a4dad0f3417d0eb0778134d92f63481f 100644 (file)
@@ -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) # "
index 323a2d38b3de6772eac6383a6233b3e6176b07ec..56a518556c67bb06ca13faff3cc1b03366ca8f40 100644 (file)
@@ -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 # "
index 6a082968b9ee83e77008327784985c13a2fa7ebb..1934bf38a1b175f846b827fb3d28428c4a2647f5 100644 (file)
@@ -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 # "
index 85ff95df79622cf756a306fda7967cfcddb72089..e9e1597f9acfb247f9141983020b053d630ef3db 100644 (file)
@@ -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
index f5decd5c69f02ff6681bcfd3c06b23b08be15d68..32c7c5deab076e8531ef6fc85fdc9cacb154ee8d 100644 (file)
@@ -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
index f1d9a58ad159d3f6caf75672636338b967743dd0..b20bfed0964b02458c870f446957670330bbce52 100644 (file)
@@ -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
index 092bc02b304ef6dc9f8cfd6230a5c1ebbf653618..63c92c594a7dfe2cd0defd13eb3eee219b649368 100644 (file)
@@ -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
index a721ec86dfefb580bf14eed7e6b9faab12306d52..9d0a5959a8ef0079a7d4268b89000be663385415 100644 (file)
@@ -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
index 788f8b739bf40f8aca95f98466f9a3f77f03639e..41f4e695e8af8a8035f605049771b96dc4462203 100644 (file)
@@ -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
index 11e0276e56b289114a28cfe13a321079dbef8541..f19f67d30f76b17571a362c9fd360a7312800a90 100644 (file)
@@ -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
index a31e25f6b5c5b30b92c2d0251c5dd083f3939de2..a6cd93698f5df210fa5d1d3f5e11f0bef22d5e05 100644 (file)
@@ -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);
        }
index 49b1054660ac81d467c6f0d7684d8269ff8a1092..17fcfbf4d3f62ac144152f908852ac034b363a17 100644 (file)
@@ -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++) {
index 57b78e55e23b9ef048bb4edd69ad110443ec9384..9d8f11ef302ac960d0a8ad1e36181508d05db83f 100644 (file)
@@ -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;
index 8017e359f543dffb77ce17c97411414ed09afdd7..4921f0ff42e9706957ae6ca785187a3dcfc8e9ec 100644 (file)
@@ -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++) {
index ae6f436385a616479db3096256613657c3d14665..dc9b661c1cf754632cc7d673c024f860332e60b4 100644 (file)
@@ -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);
index a4289788a65cb7ae8e9583a03299c2b1b992ef41..2fa07f9c57c455d96121183eff05c02ba7d72b40 100644 (file)
@@ -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 (file)
index 0000000..30b8e45
--- /dev/null
@@ -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 (file)
index 0000000..35decf4
--- /dev/null
@@ -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 (file)
index 0000000..e86b72a
--- /dev/null
@@ -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 (file)
index 0000000..ab03d8b
--- /dev/null
@@ -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 (file)
index 0000000..d96c201
--- /dev/null
@@ -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",
+};
index 2b6d1e46386b0ee895ef10f77b14e550cb50e4c2..6275a11a0c8c28b530c6897196172ea0c627083e 100644 (file)
@@ -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 */
index 54e596c4ed624d9b952f7ebf3f06d607cd9d1c90..7dbb49f81464c1dffbc949c91e88000da3bc0691 100644 (file)
@@ -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);
 
index 917b6034d360e824bdfa6fd95e8ae82224f08fa8..ecf3bc02409e4a741353cd97404f827ea18e7896 100644 (file)
@@ -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;
 
index 21cb566c2906cb01d9dd911c3581bd9458122359..3f0b5882541bfe9a320e01972af6ff4c1e095d58 100644 (file)
@@ -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;
 
index 8f5c0fc8029d6b862bbbf1962ae55a27d80ec531..86ee90f4be50f796550ed17437d68b357f0ba861 100644 (file)
@@ -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",
index 418b48120a30b5fc63ed3e93748a9d30e1734129..44948c37364d27d42138fd824145e426ad56acdf 100644 (file)
@@ -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) {
index 3881b2e8a54630938667d08ca911a5f06854542d..887edd801a42d1a87662ca7e3f0f036f19e50cc2 100644 (file)
@@ -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;
index d7eecd5bc606888982ae5b3ed6ff320c8dab41af..a965f80aebb5b5f5e95a27e80395d2651a09b09a 100644 (file)
@@ -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) {
index 82c1b84f3bd953ec50dfdb0b4197448da3043584..afa0848dcb0357c8dd26991d9741c049448e9be1 100644 (file)
@@ -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) {
index f6fb89b393f0881e624e006baf9f16cd056d2474..fbb665b86f3f3faa4d2cd4dcbcca21c0da799790 100644 (file)
@@ -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) {
index 7ae1f0ec9aeade68a873356dcecdebf28e0cf604..310fb69c8d76d2d036a202b2b3db5c231e253e13 100644 (file)
@@ -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",
index f408b8a81d1e7d2f438c1ce20590f8563920d002..6bc8fddbd16b7368d2b43e611e0cac01935c2f47 100644 (file)
@@ -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
index 150570ee7e4d94c096ad2b2340cfef13c043fc51..0d328f8d9d35110a0037400e71ea51a4df7906dc 100644 (file)
@@ -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 (file)
index 0000000..b6e1fc5
--- /dev/null
@@ -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 (file)
index a650892..0000000
+++ /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;
-}
index 361a7720fa547816c04818ccc0640188384cd759..205d7a5d97db9a5ac9e5f5dd59e0ff05f82100dd 100644 (file)
@@ -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 (file)
index 0000000..cd29dba
--- /dev/null
@@ -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
index cc740e9c21beb16510c73897416f998993a9573f..9afe46c1e90c28cd7f321be876eaf51c447260f8 100644 (file)
  *
  * 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),
+};
similarity index 54%
rename from drivers/tpm/tpm_private.h
rename to drivers/tpm/tpm_tis_i2c.h
index 8894c98e6a87dc6aad2e01ef57a29d1467527d2f..3b510d101e773baf3aa6db107d8e78cc5ca2a6fe 100644 (file)
  * 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
index d09f8cee05b0940ea32c7707e5aeb4a1e6d2e90e..b41c3cec37525f313797e45b6096bc221dc36cc8 100644 (file)
  */
 
 #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),
+};
index ed4b0391278307c77ffefcd6f7464b30527149d6..9ea98075b3071b8c594d75fe6b344114f2bad520 100644 (file)
@@ -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),
+};
index 4a4f5593e9da0718c91915b7d7d4b557765c5bfe..31d54ab285bf01c9ea0e864559413f880868b46e 100644 (file)
@@ -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;
 
index 251885b28b3a9a1e16d6e34edb4ca7ff993e4ce2..28416ed1064914bbdf8c8fce1258381c182d1115 100644 (file)
@@ -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;
index 3c0b721e3b8226d024d39a31270ceed2d69fab2d..1bf92020ae6deb0b7c0afb5944752041045814b6 100644 (file)
@@ -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;
 }
index d72a90905f5b95ca7de5e10aebb863761ceecf84..a04bb962af81c260d414c9d049a45643ce72cc3b 100644 (file)
@@ -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
index 8f829eddb1d908170aa2d8c537ef52c67b11c629..9a1f6d0782c6b93f760a326832b7472996a25476 100644 (file)
 #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
index 5779cfdb66b5f6a0b694368b3df442342bf8603f..1c955d9e37a69f2281465d8f6476a6a6734535c9 100644 (file)
@@ -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
index e710f41f79e2bc9adc32645fd8d88eb4638bfd74..4866836d55261ce2405c256bdf6a993c56115411 100644 (file)
 #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
index 217312e5b72bad5ea22a12ddc9442a923ce4447b..3f153f24aeaa1bbd4a1b882cbd6cbd595854d0f3 100644 (file)
@@ -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
 
 /*-----------------------------------------------------------------------
index 04884f18057e3a3ca2da81f4e2094433dbf6b4c1..322d35a4789c2f81a1401d066af09f3a47b22983 100644 (file)
@@ -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,
index 61610e69aa551532927f7875227c31f3c980784a..4513d6a311a7e80daebd6bb1bd32a0e2e92701d3 100644 (file)
@@ -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 (file)
index 0000000..bc6fdb4
--- /dev/null
@@ -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 */
index c744044bb8aa5f80718a4926c9dc7952996e4b43..1eeec74964356fe9a4bbce9195d8fcc4693bf649 100644 (file)
@@ -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 */
index d56877c89825e432b64cff0d17a5dab830ec2303..d214b887341b9b8711fc1e71ec4c2568c3367c71 100644 (file)
@@ -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
index 0cb6fa0075028ecc08f44c7e0d9a463a9c7ae0ce..3e237312a7289b550b1bccb9f97bdfd753b3c163 100644 (file)
@@ -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 */
index 40a1f867627a66209618048257077452ecfa143f..1985d9e60e67475eabf2451a816380b854961ee6 100644 (file)
@@ -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 */
index 88aeba28e33b59637c411325504458ad9e08c10f..086b672718e1dcc98ed157e282e547311cce87d1 100644 (file)
  * 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 */
index 884218a3c667f53877c84b462344cfaa1e651ef5..067307276ecf69229c53d26d994136ec9ff8d9fd 100644 (file)
@@ -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
index 81b54f88e88722eab0458d83fce8684072baaffc..29c5ccb2144404f75ce72e73544a46eb2ca80dd7 100644 (file)
@@ -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"),
index d9789b022ab3e9c507f4d2983da1bb6c746c90a9..5d5f707e3721374fddc70d4fe6d2e6ce708be62e 100644 (file)
--- 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
 
 /**
index a17a7d1de7b1a69bd5257cbbc004a84b149c0ca5..3399f2c8ddc34b7e81b7a050c0fda83538c74c14 100644 (file)
@@ -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.