From 4e9838c102e8575fbff3944e1596a53ec579844a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Tue, 11 Aug 2015 08:33:29 -0600 Subject: dm: Use dev_get_addr() where possible This is a convenient way for a driver to get the hardware address of a device, when regmap or syscon are not being used. Change existing callers to use it as an example to others. Signed-off-by: Simon Glass Reviewed-by: Joe Hershberger Acked-by: Stephen Warren --- drivers/core/device.c | 2 ++ drivers/gpio/s5p_gpio.c | 3 +-- drivers/gpio/sunxi_gpio.c | 3 +-- drivers/gpio/tegra_gpio.c | 3 +-- drivers/i2c/s3c24x0_i2c.c | 6 ++---- drivers/i2c/tegra_i2c.c | 2 +- drivers/serial/ns16550.c | 2 +- drivers/serial/serial_arc.c | 3 +-- drivers/serial/serial_pl01x.c | 2 +- drivers/serial/serial_s5p.c | 2 +- drivers/spi/designware_spi.c | 2 +- drivers/spi/exynos_spi.c | 2 +- drivers/spi/fsl_dspi.c | 2 +- drivers/spi/tegra114_spi.c | 2 +- drivers/spi/tegra20_sflash.c | 2 +- drivers/spi/tegra20_slink.c | 2 +- drivers/spi/zynq_spi.c | 2 +- drivers/usb/host/ehci-tegra.c | 8 +++++--- drivers/usb/host/xhci-exynos5.c | 2 +- drivers/video/tegra124/dp.c | 3 +-- 20 files changed, 26 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/core/device.c b/drivers/core/device.c index a31e25f6b5..826d82c617 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -575,8 +575,10 @@ fdt_addr_t dev_get_addr(struct udevice *dev) addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); if (addr != FDT_ADDR_T_NONE) { +#ifndef CONFIG_SPL_BUILD if (device_get_uclass_id(dev->parent) == UCLASS_SIMPLE_BUS) addr = simple_bus_translate(dev->parent, addr); +#endif } return addr; diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c index 49b1054660..17fcfbf4d3 100644 --- a/drivers/gpio/s5p_gpio.c +++ b/drivers/gpio/s5p_gpio.c @@ -327,8 +327,7 @@ static int gpio_exynos_bind(struct udevice *parent) if (plat) return 0; - base = (struct s5p_gpio_bank *)fdtdec_get_addr(gd->fdt_blob, - parent->of_offset, "reg"); + base = (struct s5p_gpio_bank *)dev_get_addr(parent); for (node = fdt_first_subnode(blob, parent->of_offset), bank = base; node > 0; node = fdt_next_subnode(blob, node), bank++) { diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 57b78e55e2..9d8f11ef30 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -285,8 +285,7 @@ static int gpio_sunxi_bind(struct udevice *parent) no_banks = SUNXI_GPIO_BANKS; } - ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob, - parent->of_offset, "reg"); + ctlr = (struct sunxi_gpio_reg *)dev_get_addr(parent); for (bank = 0; bank < no_banks; bank++) { struct sunxi_gpio_platdata *plat; struct udevice *dev; diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c index 8017e359f5..4921f0ff42 100644 --- a/drivers/gpio/tegra_gpio.c +++ b/drivers/gpio/tegra_gpio.c @@ -343,8 +343,7 @@ static int gpio_tegra_bind(struct udevice *parent) if (!fdt_getprop(gd->fdt_blob, parent->of_offset, "interrupts", &len)) return -EINVAL; bank_count = len / 3 / sizeof(u32); - ctlr = (struct gpio_ctlr *)fdtdec_get_addr(gd->fdt_blob, - parent->of_offset, "reg"); + ctlr = (struct gpio_ctlr *)dev_get_addr(parent); } #endif for (bank = 0; bank < bank_count; bank++) { diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c index ae6f436385..dc9b661c1c 100644 --- a/drivers/i2c/s3c24x0_i2c.c +++ b/drivers/i2c/s3c24x0_i2c.c @@ -1397,12 +1397,10 @@ static int s3c_i2c_ofdata_to_platdata(struct udevice *dev) if (i2c_bus->is_highspeed) { flags = PINMUX_FLAG_HS_MODE; - i2c_bus->hsregs = (struct exynos5_hsi2c *) - fdtdec_get_addr(blob, node, "reg"); + i2c_bus->hsregs = (struct exynos5_hsi2c *)dev_get_addr(dev); } else { flags = 0; - i2c_bus->regs = (struct s3c24x0_i2c *) - fdtdec_get_addr(blob, node, "reg"); + i2c_bus->regs = (struct s3c24x0_i2c *)dev_get_addr(dev); } i2c_bus->id = pinmux_decode_periph_id(blob, node); diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c index a4289788a6..2fa07f9c57 100644 --- a/drivers/i2c/tegra_i2c.c +++ b/drivers/i2c/tegra_i2c.c @@ -339,7 +339,7 @@ static int tegra_i2c_probe(struct udevice *dev) i2c_bus->id = dev->seq; i2c_bus->type = dev_get_driver_data(dev); - i2c_bus->regs = (struct i2c_ctlr *)fdtdec_get_addr(blob, node, "reg"); + i2c_bus->regs = (struct i2c_ctlr *)dev_get_addr(dev); /* * We don't have a binding for pinmux yet. Leave it out for now. So diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c index 2b6d1e4638..6275a11a0c 100644 --- a/drivers/serial/ns16550.c +++ b/drivers/serial/ns16550.c @@ -364,7 +364,7 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev) fdt_addr_t addr; /* try Processor Local Bus device first */ - addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + addr = dev_get_addr(dev); #ifdef CONFIG_PCI if (addr == FDT_ADDR_T_NONE) { /* then try pci device */ diff --git a/drivers/serial/serial_arc.c b/drivers/serial/serial_arc.c index 54e596c4ed..7dbb49f814 100644 --- a/drivers/serial/serial_arc.c +++ b/drivers/serial/serial_arc.c @@ -133,8 +133,7 @@ static int arc_serial_ofdata_to_platdata(struct udevice *dev) struct arc_serial_platdata *plat = dev_get_platdata(dev); DECLARE_GLOBAL_DATA_PTR; - plat->reg = (struct arc_serial_regs *)fdtdec_get_addr(gd->fdt_blob, - dev->of_offset, "reg"); + plat->reg = (struct arc_serial_regs *)dev_get_addr(dev); plat->uartclk = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "clock-frequency", 0); diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index 917b6034d3..ecf3bc0240 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -365,7 +365,7 @@ static int pl01x_serial_ofdata_to_platdata(struct udevice *dev) struct pl01x_serial_platdata *plat = dev_get_platdata(dev); fdt_addr_t addr; - addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + addr = dev_get_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c index 21cb566c29..3f0b588254 100644 --- a/drivers/serial/serial_s5p.c +++ b/drivers/serial/serial_s5p.c @@ -169,7 +169,7 @@ static int s5p_serial_ofdata_to_platdata(struct udevice *dev) struct s5p_serial_platdata *plat = dev->platdata; fdt_addr_t addr; - addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg"); + addr = dev_get_addr(dev); if (addr == FDT_ADDR_T_NONE) return -EINVAL; diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c index 8f5c0fc802..86ee90f4be 100644 --- a/drivers/spi/designware_spi.c +++ b/drivers/spi/designware_spi.c @@ -134,7 +134,7 @@ static int dw_spi_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = bus->of_offset; - plat->regs = (struct dw_spi *)fdtdec_get_addr(blob, node, "reg"); + plat->regs = (struct dw_spi *)dev_get_addr(bus); /* Use 500KHz as a suitable default */ plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index 418b48120a..44948c3736 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -255,7 +255,7 @@ static int exynos_spi_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = bus->of_offset; - plat->regs = (struct exynos_spi *)fdtdec_get_addr(blob, node, "reg"); + plat->regs = (struct exynos_spi *)dev_get_addr(bus); plat->periph_id = pinmux_decode_periph_id(blob, node); if (plat->periph_id == PERIPH_ID_NONE) { diff --git a/drivers/spi/fsl_dspi.c b/drivers/spi/fsl_dspi.c index 3881b2e8a5..887edd801a 100644 --- a/drivers/spi/fsl_dspi.c +++ b/drivers/spi/fsl_dspi.c @@ -654,7 +654,7 @@ static int fsl_dspi_ofdata_to_platdata(struct udevice *bus) plat->num_chipselect = fdtdec_get_int(blob, node, "num-cs", FSL_DSPI_MAX_CHIPSELECT); - addr = fdtdec_get_addr(blob, node, "reg"); + addr = dev_get_addr(bus); if (addr == FDT_ADDR_T_NONE) { debug("DSPI: Can't get base address or size\n"); return -ENOMEM; diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c index d7eecd5bc6..a965f80aeb 100644 --- a/drivers/spi/tegra114_spi.c +++ b/drivers/spi/tegra114_spi.c @@ -118,7 +118,7 @@ static int tegra114_spi_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = bus->of_offset; - plat->base = fdtdec_get_addr(blob, node, "reg"); + plat->base = dev_get_addr(bus); plat->periph_id = clock_decode_periph_id(blob, node); if (plat->periph_id == PERIPH_ID_NONE) { diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c index 82c1b84f3b..afa0848dcb 100644 --- a/drivers/spi/tegra20_sflash.c +++ b/drivers/spi/tegra20_sflash.c @@ -90,7 +90,7 @@ static int tegra20_sflash_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = bus->of_offset; - plat->base = fdtdec_get_addr(blob, node, "reg"); + plat->base = dev_get_addr(bus); plat->periph_id = clock_decode_periph_id(blob, node); if (plat->periph_id == PERIPH_ID_NONE) { diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c index f6fb89b393..fbb665b86f 100644 --- a/drivers/spi/tegra20_slink.c +++ b/drivers/spi/tegra20_slink.c @@ -106,7 +106,7 @@ static int tegra30_spi_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = bus->of_offset; - plat->base = fdtdec_get_addr(blob, node, "reg"); + plat->base = dev_get_addr(bus); plat->periph_id = clock_decode_periph_id(blob, node); if (plat->periph_id == PERIPH_ID_NONE) { diff --git a/drivers/spi/zynq_spi.c b/drivers/spi/zynq_spi.c index 7ae1f0ec9a..310fb69c8d 100644 --- a/drivers/spi/zynq_spi.c +++ b/drivers/spi/zynq_spi.c @@ -72,7 +72,7 @@ static int zynq_spi_ofdata_to_platdata(struct udevice *bus) const void *blob = gd->fdt_blob; int node = bus->of_offset; - plat->regs = (struct zynq_spi_regs *)fdtdec_get_addr(blob, node, "reg"); + plat->regs = (struct zynq_spi_regs *)dev_get_addr(bus); /* FIXME: Use 250MHz as a suitable default */ plat->frequency = fdtdec_get_int(blob, node, "spi-max-frequency", diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 4a4f5593e9..31d54ab285 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -684,11 +684,13 @@ static void config_clock(const u32 timing[]) timing[PARAM_CPCON], timing[PARAM_LFCON]); } -static int fdt_decode_usb(const void *blob, int node, struct fdt_usb *config) +static int fdt_decode_usb(struct udevice *dev, struct fdt_usb *config) { + const void *blob = gd->fdt_blob; + int node = dev->of_offset; const char *phy, *mode; - config->reg = (struct usb_ctlr *)fdtdec_get_addr(blob, node, "reg"); + config->reg = (struct usb_ctlr *)dev_get_addr(dev); mode = fdt_getprop(blob, node, "dr_mode", NULL); if (mode) { if (0 == strcmp(mode, "host")) @@ -812,7 +814,7 @@ static int ehci_usb_ofdata_to_platdata(struct udevice *dev) struct fdt_usb *priv = dev_get_priv(dev); int ret; - ret = fdt_decode_usb(gd->fdt_blob, dev->of_offset, priv); + ret = fdt_decode_usb(dev, priv); if (ret) return ret; diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c index 251885b28b..28416ed106 100644 --- a/drivers/usb/host/xhci-exynos5.c +++ b/drivers/usb/host/xhci-exynos5.c @@ -61,7 +61,7 @@ static int xhci_usb_ofdata_to_platdata(struct udevice *dev) /* * Get the base address for XHCI controller from the device node */ - plat->hcd_base = fdtdec_get_addr(blob, dev->of_offset, "reg"); + plat->hcd_base = dev_get_addr(dev); if (plat->hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the XHCI register base address\n"); return -ENXIO; diff --git a/drivers/video/tegra124/dp.c b/drivers/video/tegra124/dp.c index 3c0b721e3b..1bf92020ae 100644 --- a/drivers/video/tegra124/dp.c +++ b/drivers/video/tegra124/dp.c @@ -1555,9 +1555,8 @@ error_enable: static int tegra_dp_ofdata_to_platdata(struct udevice *dev) { struct tegra_dp_plat *plat = dev_get_platdata(dev); - const void *blob = gd->fdt_blob; - plat->base = fdtdec_get_addr(blob, dev->of_offset, "reg"); + plat->base = dev_get_addr(dev); return 0; } -- cgit v1.2.1 From 628d792c0775ff4b0d373494d075dd7fcb74bb76 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Mon, 3 Aug 2015 01:15:48 +0200 Subject: dm: core: Add Kconfig for simple bus driver Add Kconfig entries for the simple-bus driver, both for U-Boot and for SPL. The simple-bus is enabled by default in U-Boot and disabled by default in SPL to preserve the original behavior. Signed-off-by: Marek Vasut Cc: Simon Glass Acked-by: Simon Glass Modified to fit on top of Masahiro's $(SPL) setup: Signed-off-by: Simon Glass --- drivers/core/Kconfig | 15 +++++++++++++++ drivers/core/Makefile | 4 +--- drivers/core/device.c | 4 +--- 3 files changed, 17 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig index 788f8b739b..41f4e695e8 100644 --- a/drivers/core/Kconfig +++ b/drivers/core/Kconfig @@ -105,4 +105,19 @@ config DEBUG_DEVRES If you are unsure about this, Say N here. +config SIMPLE_BUS + bool "Support simple-bus driver" + depends on DM && OF_CONTROL + default y + help + Supports the 'simple-bus' driver, which is used on some systems. + +config SPL_SIMPLE_BUS + bool "Support simple-bus driver in SPL" + depends on SPL_DM && SPL_OF_CONTROL + default n + help + Supports the 'simple-bus' driver, which is used on some systems + in SPL. + endmenu diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 11e0276e56..f19f67d30f 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -6,10 +6,8 @@ obj-y += device.o lists.o root.o uclass.o util.o obj-$(CONFIG_DEVRES) += devres.o -ifndef CONFIG_SPL_BUILD -obj-$(CONFIG_$(SPL_)OF_CONTROL) += simple-bus.o -endif obj-$(CONFIG_$(SPL_)DM_DEVICE_REMOVE) += device-remove.o +obj-$(CONFIG_$(SPL_)SIMPLE_BUS) += simple-bus.o obj-$(CONFIG_DM) += dump.o obj-$(CONFIG_REGMAP) += regmap.o obj-$(CONFIG_SYSCON) += syscon-uclass.o diff --git a/drivers/core/device.c b/drivers/core/device.c index 826d82c617..01f664796d 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -574,11 +574,9 @@ 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) { -#ifndef CONFIG_SPL_BUILD + 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); -#endif } return addr; -- cgit v1.2.1 From 776d2ef06bb627b410f4f2aa6a21ceb24a92b260 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 20 Aug 2015 22:44:14 -0700 Subject: drivers: kconfig: Move "Generic Driver Options" menu to the top Make "Generic Driver Options" menu show on the top in the Kconfig. Signed-off-by: Bin Meng Acked-by: Simon Glass --- drivers/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index 092bc02b30..b25c59cf79 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -1,9 +1,9 @@ menu "Device Drivers" -source "drivers/clk/Kconfig" - source "drivers/core/Kconfig" +source "drivers/clk/Kconfig" + source "drivers/cpu/Kconfig" source "drivers/demo/Kconfig" -- cgit v1.2.1 From 99385b6b670c3d4d4336e84eb6a81492c01f9a5a Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 20 Aug 2015 22:44:15 -0700 Subject: drivers: kconfig: Move PHYS_TO_BUS to "Device Drivers" menu Right now PHYS_TO_BUS shows in the Kconfig main menu, move it. Signed-off-by: Bin Meng Acked-by: Simon Glass --- drivers/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index b25c59cf79..9d0df9b8c1 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -60,8 +60,6 @@ source "drivers/crypto/Kconfig" source "drivers/thermal/Kconfig" -endmenu - config PHYS_TO_BUS bool "Custom physical to bus address mapping" help @@ -69,3 +67,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 -- cgit v1.2.1 From e0bb89b14bb670db51d3bf0ea2253dae7dc24a92 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 20 Aug 2015 22:44:16 -0700 Subject: drivers: kconfig: Sort driver menu in alphabetical order Sort different types of drivers in alphabetical order. Signed-off-by: Bin Meng Acked-by: Simon Glass --- drivers/Kconfig | 50 ++++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index 9d0df9b8c1..524d73e64c 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -2,63 +2,65 @@ menu "Device Drivers" 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/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/spi/Kconfig" -source "drivers/mmc/Kconfig" +source "drivers/thermal/Kconfig" -source "drivers/rtc/Kconfig" +source "drivers/tpm/Kconfig" -source "drivers/dma/Kconfig" +source "drivers/usb/Kconfig" -source "drivers/crypto/Kconfig" +source "drivers/video/Kconfig" -source "drivers/thermal/Kconfig" +source "drivers/watchdog/Kconfig" config PHYS_TO_BUS bool "Custom physical to bus address mapping" -- cgit v1.2.1 From 3a3f8e946bd77a2978731793eb287ec6099c4a52 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:17 -0600 Subject: tpm: Remove old pre-driver-model I2C code This is not used anymore by any board so drop it. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/tpm.c | 108 ++-------------------------------------------- drivers/tpm/tpm_private.h | 4 +- drivers/tpm/tpm_tis_i2c.c | 74 +------------------------------ 3 files changed, 7 insertions(+), 179 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm.c b/drivers/tpm/tpm.c index a650892f09..24997f6702 100644 --- a/drivers/tpm/tpm.c +++ b/drivers/tpm/tpm.c @@ -49,13 +49,7 @@ 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; @@ -441,7 +435,6 @@ out: return rc; } -#ifdef CONFIG_DM_I2C static int tpm_open_dev(struct udevice *dev) { int rc; @@ -449,24 +442,12 @@ static int tpm_open_dev(struct udevice *dev) debug("%s: start\n", __func__); if (g_chip.is_open) return -EBUSY; - rc = tpm_vendor_init_dev(dev); + rc = tpm_vendor_init(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) { @@ -475,42 +456,6 @@ static void tpm_close(void) } } -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. * @@ -520,8 +465,11 @@ static int tpm_deselect(void) static int tpm_decode_config(struct tpm *dev) { const void *blob = gd->fdt_blob; + struct udevice *bus; + int chip_addr; int parent; int node; + int ret; node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM); if (node < 0) { @@ -537,10 +485,6 @@ static int tpm_decode_config(struct tpm *dev) 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 @@ -569,15 +513,6 @@ static int tpm_decode_config(struct tpm *dev) 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; } @@ -602,22 +537,6 @@ int tis_init(void) 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; @@ -632,16 +551,7 @@ int tis_open(void) 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; } @@ -651,13 +561,8 @@ int tis_close(void) if (!tpm.inited) return -1; - if (tpm_select()) - return -1; - tpm_close(); - tpm_deselect(); - return 0; } @@ -675,13 +580,8 @@ int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, 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; diff --git a/drivers/tpm/tpm_private.h b/drivers/tpm/tpm_private.h index 8894c98e6a..daaf8b8029 100644 --- a/drivers/tpm/tpm_private.h +++ b/drivers/tpm/tpm_private.h @@ -129,10 +129,8 @@ struct tpm_cmd_t { struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *); -int tpm_vendor_init(uint32_t dev_addr); - struct udevice; -int tpm_vendor_init_dev(struct udevice *dev); +int tpm_vendor_init(struct udevice *dev); void tpm_vendor_cleanup(struct tpm_chip *chip); diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index cc740e9c21..b6eaef18f5 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -50,9 +50,6 @@ 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 @@ -73,13 +70,6 @@ DECLARE_GLOBAL_DATA_PTR; #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, @@ -123,21 +113,11 @@ static const char * const chip_name[] = { /* 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; /* @@ -163,12 +143,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) { /* slb9635 protocol should work in both cases */ for (count = 0; count < MAX_COUNT; count++) { -#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 if (rc == 0) break; /* Success, break to skip sleep */ udelay(SLEEP_DURATION); @@ -182,11 +157,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) */ 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 if (rc == 0) break; /* success, break to skip sleep */ } @@ -199,11 +170,7 @@ 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 if (rc == 0) break; /* break here to skip sleep */ udelay(SLEEP_DURATION); @@ -224,20 +191,8 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, 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 - 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 if (rc == 0) break; /* Success, break to skip sleep */ udelay(sleep_time); @@ -597,12 +552,13 @@ static enum i2c_chip_type tpm_vendor_chip_type(void) return UNKNOWN; } -static int tpm_vendor_init_common(void) +int tpm_vendor_init(struct udevice *dev) { struct tpm_chip *chip; u32 vendor; u32 expected_did_vid; + tpm_dev.dev = dev; tpm_dev.chip_type = tpm_vendor_chip_type(); chip = tpm_register_hardware(&tpm_tis_i2c); @@ -651,32 +607,6 @@ 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) -{ - tpm_dev.dev = dev; - return tpm_vendor_init_common(); -} -#else -/* Initialisation of i2c tpm */ -int tpm_vendor_init(uint32_t dev_addr) -{ - uint old_addr; - int rc = 0; - - old_addr = tpm_dev.addr; - if (dev_addr != 0) - tpm_dev.addr = dev_addr; - - rc = tpm_vendor_init_common(); - if (rc) - tpm_dev.addr = old_addr; - - return rc; -} -#endif - void tpm_vendor_cleanup(struct tpm_chip *chip) { release_locality(chip, chip->vendor.locality, 1); -- cgit v1.2.1 From a7d660bc4982fea59d14d30eb79e77499d1074ef Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:19 -0600 Subject: tpm: Add Kconfig options for TPMs Add new Kconfig options for TPMs in preparation for moving boards to use Kconfig for TPM configuration. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/Kconfig | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'drivers') diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index f408b8a81d..9101fc26b9 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -1,7 +1,67 @@ +# +# TPM subsystem configuration +# + +menu "TPM support" + 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 -- cgit v1.2.1 From 07470d6f5bf7fa608cdf30263dd045dd9f51d50d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:21 -0600 Subject: tpm: Convert drivers to use SPDX Add an SPDX header to two drivers that don't have it. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_atmel_twi.c | 15 +++------------ drivers/tpm/tpm_tis_i2c.c | 18 +----------------- 2 files changed, 4 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_atmel_twi.c b/drivers/tpm/tpm_atmel_twi.c index 361a7720fa..205d7a5d97 100644 --- a/drivers/tpm/tpm_atmel_twi.c +++ b/drivers/tpm/tpm_atmel_twi.c @@ -1,18 +1,9 @@ /* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. + * Copyright (C) 2013 Guntermann & Drunck, GmbH * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Written by Dirk Eibach * - * 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 diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index b6eaef18f5..438a221607 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -17,23 +17,7 @@ * * 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 -- cgit v1.2.1 From 4cd7b7834c19903504d76542fb0240cde34853f5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:22 -0600 Subject: tpm: Move the I2C TPM code into one file The current Infineon I2C TPM driver is written in two parts, intended to support use with other I2C devices. However we don't have any users and the Atmel I2C TPM device does not use this file. We should simplify this and remove the unused abstration. As a first step, move the code into one file. Also the name tpm_private.h suggests that the header file is generic to all TPMs but it is not. Rename it indicate that it relates only to this driver Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- drivers/tpm/Makefile | 2 - drivers/tpm/tpm.c | 594 ---------------------------------------------- drivers/tpm/tpm_private.h | 138 ----------- drivers/tpm/tpm_tis_i2c.c | 548 +++++++++++++++++++++++++++++++++++++++++- drivers/tpm/tpm_tis_i2c.h | 120 ++++++++++ 5 files changed, 667 insertions(+), 735 deletions(-) delete mode 100644 drivers/tpm/tpm.c delete mode 100644 drivers/tpm/tpm_private.h create mode 100644 drivers/tpm/tpm_tis_i2c.h (limited to 'drivers') diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index 150570ee7e..597966ce1f 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -3,9 +3,7 @@ # SPDX-License-Identifier: GPL-2.0+ # -# TODO: Merge tpm_tis_lpc.c with tpm.c 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.c b/drivers/tpm/tpm.c deleted file mode 100644 index 24997f6702..0000000000 --- a/drivers/tpm/tpm.c +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Copyright (C) 2011 Infineon Technologies - * - * Authors: - * Peter Huewe - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tpm_private.h" - -DECLARE_GLOBAL_DATA_PTR; - -/* TPM configuration */ -struct tpm { - struct udevice *dev; - 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; -} - -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); - if (rc < 0) - g_chip.is_open = 0; - return rc; -} - -static void tpm_close(void) -{ - if (g_chip.is_open) { - tpm_vendor_cleanup(&g_chip); - g_chip.is_open = 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; - struct udevice *bus; - int chip_addr; - int parent; - int node; - int ret; - - 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; - } - - /* - * 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; - } - - 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; - - debug("%s: done\n", __func__); - - tpm.inited = 1; - - return 0; -} - -int tis_open(void) -{ - int rc; - - if (!tpm.inited) - return -1; - - rc = tpm_open_dev(tpm.dev); - - return rc; -} - -int tis_close(void) -{ - if (!tpm.inited) - return -1; - - tpm_close(); - - 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); - - len = tpm_transmit(buf, sbuf_size); - - if (len < 10) { - *rbuf_len = 0; - return -1; - } - - memcpy(recvbuf, buf, len); - *rbuf_len = len; - - return 0; -} diff --git a/drivers/tpm/tpm_private.h b/drivers/tpm/tpm_private.h deleted file mode 100644 index daaf8b8029..0000000000 --- a/drivers/tpm/tpm_private.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2011 Infineon Technologies - * - * Authors: - * Peter Huewe - * - * Version: 2.1.1 - * - * 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. - * - * - * 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 - */ - -#ifndef _TPM_PRIVATE_H_ -#define _TPM_PRIVATE_H_ - -#include -#include - -enum tpm_timeout { - TPM_TIMEOUT = 5, /* msecs */ -}; - -/* Size of external transmit buffer (used in tpm_transmit)*/ -#define TPM_BUFSIZE 4096 - -/* Index of Count field in TPM response buffer */ -#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 */ -}; - -struct tpm_chip { - int is_open; - struct tpm_vendor_specific vendor; -}; - -struct tpm_input_header { - __be16 tag; - __be32 length; - __be32 ordinal; -} __packed; - -struct tpm_output_header { - __be16 tag; - __be32 length; - __be32 return_code; -} __packed; - -struct timeout_t { - __be32 a; - __be32 b; - __be32 c; - __be32 d; -} __packed; - -struct duration_t { - __be32 tpm_short; - __be32 tpm_medium; - __be32 tpm_long; -} __packed; - -union cap_t { - struct timeout_t timeout; - struct duration_t duration; -}; - -struct tpm_getcap_params_in { - __be32 cap; - __be32 subcap_size; - __be32 subcap; -} __packed; - -struct tpm_getcap_params_out { - __be32 cap_size; - union cap_t cap; -} __packed; - -union tpm_cmd_header { - struct tpm_input_header in; - struct tpm_output_header out; -}; - -union tpm_cmd_params { - struct tpm_getcap_params_out getcap_out; - struct tpm_getcap_params_in getcap_in; -}; - -struct tpm_cmd_t { - union tpm_cmd_header header; - union tpm_cmd_params params; -} __packed; - -struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *); - -struct udevice; -int tpm_vendor_init(struct udevice *dev); - -void tpm_vendor_cleanup(struct tpm_chip *chip); - - -#endif diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 438a221607..e547f0ad9f 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -30,7 +30,7 @@ #include #include -#include "tpm_private.h" +#include "tpm_tis_i2c.h" DECLARE_GLOBAL_DATA_PTR; @@ -95,6 +95,304 @@ static const char * const chip_name[] = { #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) +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, +}; + +/* TPM configuration */ +struct tpm { + struct udevice *dev; + char inited; +} tpm; + +/* Global structure for tpm chip data */ +static struct tpm_chip g_chip; + /* Structure to store I2C TPM specific stuff */ struct tpm_dev { struct udevice *dev; @@ -595,3 +893,251 @@ void tpm_vendor_cleanup(struct tpm_chip *chip) { release_locality(chip, chip->vendor.locality, 1); } + +/* 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; +} + +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); + if (rc < 0) + g_chip.is_open = 0; + return rc; +} + +static void tpm_close(void) +{ + if (g_chip.is_open) { + tpm_vendor_cleanup(&g_chip); + g_chip.is_open = 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; + struct udevice *bus; + int chip_addr; + int parent; + int node; + int ret; + + 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; + } + + /* + * 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; + } + + 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; + + debug("%s: done\n", __func__); + + tpm.inited = 1; + + return 0; +} + +int tis_open(void) +{ + int rc; + + if (!tpm.inited) + return -1; + + rc = tpm_open_dev(tpm.dev); + + return rc; +} + +int tis_close(void) +{ + if (!tpm.inited) + return -1; + + tpm_close(); + + 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); + + len = tpm_transmit(buf, sbuf_size); + + if (len < 10) { + *rbuf_len = 0; + return -1; + } + + memcpy(recvbuf, buf, len); + *rbuf_len = len; + + return 0; +} diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h new file mode 100644 index 0000000000..75fa829e3d --- /dev/null +++ b/drivers/tpm/tpm_tis_i2c.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2011 Infineon Technologies + * + * Authors: + * Peter Huewe + * + * Version: 2.1.1 + * + * 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. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +#ifndef _TPM_TIS_I2C_H +#define _TPM_TIS_I2C_H + +#include +#include + +enum tpm_timeout { + TPM_TIMEOUT = 5, /* msecs */ +}; + +/* Size of external transmit buffer (used in tpm_transmit)*/ +#define TPM_BUFSIZE 4096 + +/* Index of Count field in TPM response buffer */ +#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 */ +}; + +struct tpm_chip { + int is_open; + struct tpm_vendor_specific vendor; +}; + +struct tpm_input_header { + __be16 tag; + __be32 length; + __be32 ordinal; +} __packed; + +struct tpm_output_header { + __be16 tag; + __be32 length; + __be32 return_code; +} __packed; + +struct timeout_t { + __be32 a; + __be32 b; + __be32 c; + __be32 d; +} __packed; + +struct duration_t { + __be32 tpm_short; + __be32 tpm_medium; + __be32 tpm_long; +} __packed; + +union cap_t { + struct timeout_t timeout; + struct duration_t duration; +}; + +struct tpm_getcap_params_in { + __be32 cap; + __be32 subcap_size; + __be32 subcap; +} __packed; + +struct tpm_getcap_params_out { + __be32 cap_size; + union cap_t cap; +} __packed; + +union tpm_cmd_header { + struct tpm_input_header in; + struct tpm_output_header out; +}; + +union tpm_cmd_params { + struct tpm_getcap_params_out getcap_out; + struct tpm_getcap_params_in getcap_in; +}; + +struct tpm_cmd_t { + union tpm_cmd_header header; + union tpm_cmd_params params; +} __packed; + +struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *); + +struct udevice; +int tpm_vendor_init(struct udevice *dev); + +void tpm_vendor_cleanup(struct tpm_chip *chip); + +#endif -- cgit v1.2.1 From b382e02124710d8964fe75b94046a7708c55216c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:23 -0600 Subject: tpm: tpm_tis_i2c: Drop unnecessary methods The function methods in struct tpm_vendor_specific just call local functions. Change the code to use a direct call. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_i2c.c | 12 ++++-------- drivers/tpm/tpm_tis_i2c.h | 4 ---- 2 files changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index e547f0ad9f..6a3991f987 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -810,10 +810,6 @@ out_err: } 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, @@ -940,7 +936,7 @@ static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) } debug("Calling send\n"); - rc = chip->vendor.send(chip, (u8 *)buf, count); + rc = tpm_tis_i2c_send(chip, (u8 *)buf, count); debug(" ... done calling send\n"); if (rc < 0) { error("tpm_transmit: tpm_send: error %d\n", rc); @@ -954,7 +950,7 @@ static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) stop = tpm_calc_ordinal_duration(chip, ordinal); do { debug("waiting for status... %ld %ld\n", start, stop); - u8 status = chip->vendor.status(chip); + u8 status = tpm_tis_i2c_status(chip); if ((status & chip->vendor.req_complete_mask) == chip->vendor.req_complete_val) { debug("...got it;\n"); @@ -969,14 +965,14 @@ static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) udelay(TPM_TIMEOUT * 1000); } while (get_timer(start) < stop); - chip->vendor.cancel(chip); + tpm_tis_i2c_ready(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); + rc = tpm_tis_i2c_recv(chip, (u8 *)buf, TPM_BUFSIZE); if (rc < 0) error("tpm_transmit: tpm_recv: error %d\n", rc); diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h index 75fa829e3d..426c519811 100644 --- a/drivers/tpm/tpm_tis_i2c.h +++ b/drivers/tpm/tpm_tis_i2c.h @@ -40,10 +40,6 @@ struct tpm_vendor_specific { 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 */ -- cgit v1.2.1 From 7c73537e8e4a296bb2780c1fadb2b82cd2c38185 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:24 -0600 Subject: tpm: tpm_tis_i2c: Drop struct tpm_vendor_specific This function is misnamed since it only applies to a single driver. Merge its fields into its parent. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_i2c.c | 79 ++++++++++++++++++----------------------------- drivers/tpm/tpm_tis_i2c.h | 16 +++------- 2 files changed, 35 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 6a3991f987..3ae1a4e436 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -531,7 +531,7 @@ static int check_locality(struct tpm_chip *chip, int loc) return rc; if ((buf & mask) == mask) { - chip->vendor.locality = loc; + chip->locality = loc; return loc; } @@ -567,7 +567,7 @@ static int request_locality(struct tpm_chip *chip, int loc) /* Wait for burstcount */ start = get_timer(0); - stop = chip->vendor.timeout_a; + stop = chip->timeout_a; do { if (check_locality(chip, loc) >= 0) return loc; @@ -582,7 +582,7 @@ static u8 tpm_tis_i2c_status(struct tpm_chip *chip) /* 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 (iic_tpm_read(TPM_STS(chip->locality), &buf, 1) < 0) return 0; else return buf; @@ -596,7 +596,7 @@ static void tpm_tis_i2c_ready(struct tpm_chip *chip) u8 buf = TPM_STS_COMMAND_READY; debug("%s\n", __func__); - rc = iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); + rc = iic_tpm_write_long(TPM_STS(chip->locality), &buf, 1); if (rc) debug("%s: rc=%d\n", __func__, rc); } @@ -610,10 +610,10 @@ 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; + addr = TPM_STS(chip->locality) + 1; if (iic_tpm_read(addr, buf, 3) < 0) burstcnt = 0; else @@ -666,7 +666,7 @@ 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), + rc = iic_tpm_read(TPM_DATA_FIFO(chip->locality), &(buf[size]), burstcnt); if (rc == 0) size += burstcnt; @@ -708,7 +708,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) goto out; } - wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); + wait_for_stat(chip, TPM_STS_VALID, chip->timeout_c, &status); if (status & TPM_STS_DATA_AVAIL) { /* Retry? */ error("Error left over data\n"); size = -EIO; @@ -722,7 +722,7 @@ out: * so we sleep rather than keeping the bus busy */ udelay(2000); - release_locality(chip, chip->vendor.locality, 0); + release_locality(chip, chip->locality, 0); return size; } @@ -746,7 +746,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) 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) { + chip->timeout_b, &status) < 0) { rc = -ETIME; goto out_err; } @@ -768,7 +768,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION; #endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */ - rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), + rc = iic_tpm_write(TPM_DATA_FIFO(chip->locality), &(buf[count]), burstcnt); if (rc == 0) count += burstcnt; @@ -779,7 +779,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) goto out_err; } rc = wait_for_stat(chip, TPM_STS_VALID, - chip->vendor.timeout_c, &status); + chip->timeout_c, &status); if (rc) goto out_err; @@ -791,7 +791,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) } /* Go and do it */ - iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); + iic_tpm_write(TPM_STS(chip->locality), &sts, 1); debug("done\n"); return len; @@ -804,18 +804,11 @@ out_err: * so we sleep rather than keeping the bus busy */ udelay(2000); - release_locality(chip, chip->vendor.locality, 0); + release_locality(chip, chip->locality, 0); return rc; } -static struct tpm_vendor_specific tpm_tis_i2c = { - .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) @@ -832,25 +825,25 @@ static enum i2c_chip_type tpm_vendor_chip_type(void) int tpm_vendor_init(struct udevice *dev) { - struct tpm_chip *chip; + struct tpm_chip *chip = &g_chip; u32 vendor; u32 expected_did_vid; tpm_dev.dev = dev; tpm_dev.chip_type = tpm_vendor_chip_type(); - - chip = tpm_register_hardware(&tpm_tis_i2c); - if (chip < 0) - return -ENODEV; + chip->is_open = 1; /* Disable interrupts (not supported) */ - chip->vendor.irq = 0; + chip->irq = 0; /* 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; + chip->timeout_a = TIS_SHORT_TIMEOUT; + chip->timeout_b = TIS_LONG_TIMEOUT; + chip->timeout_c = TIS_SHORT_TIMEOUT; + chip->timeout_d = TIS_SHORT_TIMEOUT; + chip->req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; + chip->req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID; + chip->req_canceled = TPM_STS_COMMAND_READY; if (request_locality(chip, 0) < 0) return -ENODEV; @@ -887,7 +880,7 @@ int tpm_vendor_init(struct udevice *dev) void tpm_vendor_cleanup(struct tpm_chip *chip) { - release_locality(chip, chip->vendor.locality, 1); + release_locality(chip, chip->locality, 1); } /* Returns max number of milliseconds to wait */ @@ -906,7 +899,7 @@ static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, } if (duration_idx != TPM_UNDEFINED) - duration = chip->vendor.duration[duration_idx]; + duration = chip->duration[duration_idx]; if (duration <= 0) return 2 * 60 * HZ; /* Two minutes timeout */ @@ -943,7 +936,7 @@ static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) goto out; } - if (chip->vendor.irq) + if (chip->irq) goto out_recv; start = get_timer(0); @@ -951,13 +944,13 @@ static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) do { debug("waiting for status... %ld %ld\n", start, stop); u8 status = tpm_tis_i2c_status(chip); - if ((status & chip->vendor.req_complete_mask) == - chip->vendor.req_complete_val) { + if ((status & chip->req_complete_mask) == + chip->req_complete_val) { debug("...got it;\n"); goto out_recv; } - if (status == chip->vendor.req_canceled) { + if (status == chip->req_canceled) { error("Operation Canceled\n"); rc = -ECANCELED; goto out; @@ -1062,18 +1055,6 @@ static int tpm_decode_config(struct tpm *dev) 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) diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h index 426c519811..2a4ad77429 100644 --- a/drivers/tpm/tpm_tis_i2c.h +++ b/drivers/tpm/tpm_tis_i2c.h @@ -35,21 +35,17 @@ enum tpm_timeout { struct tpm_chip; -struct tpm_vendor_specific { - const u8 req_complete_mask; - const u8 req_complete_val; - const u8 req_canceled; +struct tpm_chip { + int is_open; + u8 req_complete_mask; + u8 req_complete_val; + u8 req_canceled; int irq; int locality; unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ unsigned long duration[3]; /* msec */ }; -struct tpm_chip { - int is_open; - struct tpm_vendor_specific vendor; -}; - struct tpm_input_header { __be16 tag; __be32 length; @@ -106,8 +102,6 @@ struct tpm_cmd_t { union tpm_cmd_params params; } __packed; -struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *); - struct udevice; int tpm_vendor_init(struct udevice *dev); -- cgit v1.2.1 From 13932b09bb19898a5c64bf7a48448855200c63f5 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:25 -0600 Subject: tpm: tpm_tis_i2c: Merge struct tpm_dev into tpm_chip There are too many structures storing the same sort of information. Move the fields from struct tpm_dev into struct tpm_chip and remove the former struct. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_i2c.c | 52 +++++++++++++---------------------------------- drivers/tpm/tpm_tis_i2c.h | 17 ++++++++++------ 2 files changed, 25 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 3ae1a4e436..81a3bb5981 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -34,9 +34,6 @@ DECLARE_GLOBAL_DATA_PTR; -/* Max buffer size supported by our tpm */ -#define TPM_DEV_BUFSIZE 1260 - /* Max number of iterations after i2c NAK */ #define MAX_COUNT 3 @@ -78,12 +75,6 @@ enum tis_defaults { #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", @@ -390,18 +381,8 @@ struct tpm { char inited; } tpm; -/* Global structure for tpm chip data */ static struct tpm_chip g_chip; -/* Structure to store I2C TPM specific stuff */ -struct tpm_dev { - struct udevice *dev; - u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ - enum i2c_chip_type chip_type; -}; - -static struct tpm_dev tpm_dev; - /* * iic_tpm_read() - read from TPM register * @addr: register address to read from @@ -422,10 +403,10 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) int count; uint32_t addrbuf = addr; - if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) { + if ((g_chip.chip_type == SLB9635) || (g_chip.chip_type == UNKNOWN)) { /* slb9635 protocol should work in both cases */ for (count = 0; count < MAX_COUNT; count++) { - rc = dm_i2c_write(tpm_dev.dev, 0, (uchar *)&addrbuf, 1); + rc = dm_i2c_write(g_chip.dev, 0, (uchar *)&addrbuf, 1); if (rc == 0) break; /* Success, break to skip sleep */ udelay(SLEEP_DURATION); @@ -439,7 +420,7 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) */ for (count = 0; count < MAX_COUNT; count++) { udelay(SLEEP_DURATION); - rc = dm_i2c_read(tpm_dev.dev, 0, buffer, len); + rc = dm_i2c_read(g_chip.dev, 0, buffer, len); if (rc == 0) break; /* success, break to skip sleep */ } @@ -452,7 +433,7 @@ 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++) { - rc = dm_i2c_read(tpm_dev.dev, addr, buffer, len); + rc = dm_i2c_read(g_chip.dev, addr, buffer, len); if (rc == 0) break; /* break here to skip sleep */ udelay(SLEEP_DURATION); @@ -474,7 +455,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, int count; for (count = 0; count < max_count; count++) { - rc = dm_i2c_write(tpm_dev.dev, addr, buffer, len); + rc = dm_i2c_write(g_chip.dev, addr, buffer, len); if (rc == 0) break; /* Success, break to skip sleep */ udelay(sleep_time); @@ -809,7 +790,7 @@ out_err: return rc; } -static enum i2c_chip_type tpm_vendor_chip_type(void) +static enum i2c_chip_type tpm_tis_i2c_chip_type(void) { #if CONFIG_IS_ENABLED(OF_CONTROL) const void *blob = gd->fdt_blob; @@ -823,14 +804,14 @@ static enum i2c_chip_type tpm_vendor_chip_type(void) return UNKNOWN; } -int tpm_vendor_init(struct udevice *dev) +static int tpm_tis_i2c_init(struct udevice *dev) { struct tpm_chip *chip = &g_chip; u32 vendor; u32 expected_did_vid; - tpm_dev.dev = dev; - tpm_dev.chip_type = tpm_vendor_chip_type(); + g_chip.dev = dev; + g_chip.chip_type = tpm_tis_i2c_chip_type(); chip->is_open = 1; /* Disable interrupts (not supported) */ @@ -854,7 +835,7 @@ int tpm_vendor_init(struct udevice *dev) return -EIO; } - if (tpm_dev.chip_type == SLB9635) { + if (g_chip.chip_type == SLB9635) { vendor = be32_to_cpu(vendor); expected_did_vid = TPM_TIS_I2C_DID_VID_9635; } else { @@ -862,13 +843,13 @@ int tpm_vendor_init(struct udevice *dev) expected_did_vid = TPM_TIS_I2C_DID_VID_9645; } - if (tpm_dev.chip_type != UNKNOWN && vendor != expected_did_vid) { + if (g_chip.chip_type != UNKNOWN && vendor != expected_did_vid) { error("Vendor id did not match! ID was %08x\n", vendor); return -ENODEV; } debug("1.2 TPM (chip type %s device-id 0x%X)\n", - chip_name[tpm_dev.chip_type], vendor >> 16); + chip_name[g_chip.chip_type], vendor >> 16); /* * A timeout query to TPM can be placed here. @@ -878,11 +859,6 @@ int tpm_vendor_init(struct udevice *dev) return 0; } -void tpm_vendor_cleanup(struct tpm_chip *chip) -{ - release_locality(chip, chip->locality, 1); -} - /* Returns max number of milliseconds to wait */ static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) @@ -980,7 +956,7 @@ static int tpm_open_dev(struct udevice *dev) debug("%s: start\n", __func__); if (g_chip.is_open) return -EBUSY; - rc = tpm_vendor_init(dev); + rc = tpm_tis_i2c_init(dev); if (rc < 0) g_chip.is_open = 0; return rc; @@ -989,7 +965,7 @@ static int tpm_open_dev(struct udevice *dev) static void tpm_close(void) { if (g_chip.is_open) { - tpm_vendor_cleanup(&g_chip); + release_locality(&g_chip, g_chip.locality, 1); g_chip.is_open = 0; } } diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h index 2a4ad77429..0fec4640d8 100644 --- a/drivers/tpm/tpm_tis_i2c.h +++ b/drivers/tpm/tpm_tis_i2c.h @@ -33,7 +33,14 @@ enum tpm_timeout { #define TPM_RSP_SIZE_BYTE 2 #define TPM_RSP_RC_BYTE 6 -struct tpm_chip; +/* Max buffer size supported by our tpm */ +#define TPM_DEV_BUFSIZE 1260 + +enum i2c_chip_type { + SLB9635, + SLB9645, + UNKNOWN, +}; struct tpm_chip { int is_open; @@ -44,6 +51,9 @@ struct tpm_chip { int locality; unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ unsigned long duration[3]; /* msec */ + struct udevice *dev; + u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ + enum i2c_chip_type chip_type; }; struct tpm_input_header { @@ -102,9 +112,4 @@ struct tpm_cmd_t { union tpm_cmd_params params; } __packed; -struct udevice; -int tpm_vendor_init(struct udevice *dev); - -void tpm_vendor_cleanup(struct tpm_chip *chip); - #endif -- cgit v1.2.1 From 605152a80371c494b1735f6ef8d296e141b1eadf Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:26 -0600 Subject: tpm: tpm_tis_i2c: Merge struct tpm into tpm_chip There are too many structures storing the same sort of information. Move the fields from struct tpm into struct tpm_chip and remove the former struct. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_i2c.c | 24 +++++++++--------------- drivers/tpm/tpm_tis_i2c.h | 1 + 2 files changed, 10 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 81a3bb5981..046e282ccc 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -375,12 +375,6 @@ static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { TPM_MEDIUM, }; -/* TPM configuration */ -struct tpm { - struct udevice *dev; - char inited; -} tpm; - static struct tpm_chip g_chip; /* @@ -976,7 +970,7 @@ static void tpm_close(void) * @param dev Returns a configuration of TPM device * @return 0 if ok, -1 on error */ -static int tpm_decode_config(struct tpm *dev) +static int tpm_decode_config(struct tpm_chip *chip) { const void *blob = gd->fdt_blob; struct udevice *bus; @@ -1021,7 +1015,7 @@ static int tpm_decode_config(struct tpm *dev) * 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); + ret = i2c_get_chip(bus, chip_addr, 1, &chip->dev); if (ret) { debug("Cannot find device for node '%s: ret=%d'\n", fdt_get_name(blob, node, NULL), ret); @@ -1033,15 +1027,15 @@ static int tpm_decode_config(struct tpm *dev) int tis_init(void) { - if (tpm.inited) + if (g_chip.inited) return 0; - if (tpm_decode_config(&tpm)) + if (tpm_decode_config(&g_chip)) return -1; debug("%s: done\n", __func__); - tpm.inited = 1; + g_chip.inited = 1; return 0; } @@ -1050,17 +1044,17 @@ int tis_open(void) { int rc; - if (!tpm.inited) + if (!g_chip.inited) return -1; - rc = tpm_open_dev(tpm.dev); + rc = tpm_open_dev(g_chip.dev); return rc; } int tis_close(void) { - if (!tpm.inited) + if (!g_chip.inited) return -1; tpm_close(); @@ -1074,7 +1068,7 @@ int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, int len; uint8_t buf[4096]; - if (!tpm.inited) + if (!g_chip.inited) return -1; if (sizeof(buf) < sbuf_size) diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h index 0fec4640d8..161e63b5ff 100644 --- a/drivers/tpm/tpm_tis_i2c.h +++ b/drivers/tpm/tpm_tis_i2c.h @@ -43,6 +43,7 @@ enum i2c_chip_type { }; struct tpm_chip { + bool inited; int is_open; u8 req_complete_mask; u8 req_complete_val; -- cgit v1.2.1 From 13894bdba4a4b1a5c073ac8a109805c99abe0979 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:27 -0600 Subject: tpm: tpm_tis_i2c: Move definitions into the header file Some definitions are in the C file and some are in the header file. Move everything into the header file for consistency and to reduce clutter. Signed-off-by: Simon Glass Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_i2c.c | 335 ---------------------------------------------- drivers/tpm/tpm_tis_i2c.h | 335 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 335 insertions(+), 335 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 046e282ccc..39652a977c 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -34,347 +34,12 @@ DECLARE_GLOBAL_DATA_PTR; -/* 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 - -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 - 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)) - -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, -}; - static struct tpm_chip g_chip; /* diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h index 161e63b5ff..db992000e4 100644 --- a/drivers/tpm/tpm_tis_i2c.h +++ b/drivers/tpm/tpm_tis_i2c.h @@ -113,4 +113,339 @@ struct tpm_cmd_t { union tpm_cmd_params params; } __packed; +/* 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 + +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 + +#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)) + +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, +}; + #endif -- cgit v1.2.1 From a53b79a25502b78d6e8b00b90f0fde14c9ccb20d Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:28 -0600 Subject: tpm: tpm_tis_i2c: Simplify init code Move all the init and uninit code into one place. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_i2c.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 39652a977c..9dd40dd3cf 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -608,27 +608,6 @@ out: return rc; } -static int tpm_open_dev(struct udevice *dev) -{ - int rc; - - debug("%s: start\n", __func__); - if (g_chip.is_open) - return -EBUSY; - rc = tpm_tis_i2c_init(dev); - if (rc < 0) - g_chip.is_open = 0; - return rc; -} - -static void tpm_close(void) -{ - if (g_chip.is_open) { - release_locality(&g_chip, g_chip.locality, 1); - g_chip.is_open = 0; - } -} - /** * Decode TPM configuration. * @@ -712,7 +691,12 @@ int tis_open(void) if (!g_chip.inited) return -1; - rc = tpm_open_dev(g_chip.dev); + debug("%s: start\n", __func__); + if (g_chip.is_open) + return -EBUSY; + rc = tpm_tis_i2c_init(g_chip.dev); + if (rc < 0) + g_chip.is_open = 0; return rc; } @@ -722,7 +706,10 @@ int tis_close(void) if (!g_chip.inited) return -1; - tpm_close(); + if (g_chip.is_open) { + release_locality(&g_chip, g_chip.locality, 1); + g_chip.is_open = 0; + } return 0; } -- cgit v1.2.1 From e56e20eb860cadc4cc28d275f025fc8977b306ce Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:29 -0600 Subject: tpm: tpm_tis_i2c: Use a consistent tpm_tis_i2c_ prefix Use the same prefix on each function for consistency. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_i2c.c | 113 ++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 55 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 9dd40dd3cf..e04e8f547b 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -43,7 +43,7 @@ static const char * const chip_name[] = { static struct tpm_chip g_chip; /* - * 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 @@ -56,7 +56,7 @@ static struct tpm_chip g_chip; * * 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(u8 addr, u8 *buffer, size_t len) { int rc; int count; @@ -107,8 +107,8 @@ static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) 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(u8 addr, u8 *buffer, size_t len, + unsigned int sleep_time, u8 max_count) { int rc = 0; int count; @@ -129,7 +129,7 @@ static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, } /* - * 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 @@ -140,13 +140,13 @@ 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(u8 addr, u8 *buffer, size_t len) { - return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION, + return tpm_tis_i2c_write_generic(addr, buffer, len, SLEEP_DURATION, MAX_COUNT); } @@ -154,19 +154,19 @@ static int iic_tpm_write(u8 addr, u8 *buffer, size_t len) * 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(u8 addr, u8 *buffer, size_t len) { - return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG, + return tpm_tis_i2c_write_generic(addr, buffer, len, SLEEP_DURATION_LONG, MAX_COUNT_LONG); } -static int check_locality(struct tpm_chip *chip, int loc) +static int tpm_tis_i2c_check_locality(struct tpm_chip *chip, int loc) { const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID; u8 buf; int rc; - rc = iic_tpm_read(TPM_ACCESS(loc), &buf, 1); + rc = tpm_tis_i2c_read(TPM_ACCESS(loc), &buf, 1); if (rc < 0) return rc; @@ -178,30 +178,31 @@ static int check_locality(struct tpm_chip *chip, int loc) return -1; } -static void release_locality(struct tpm_chip *chip, int loc, int force) +static void tpm_tis_i2c_release_locality(struct tpm_chip *chip, 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(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(TPM_ACCESS(loc), &buf, 1); } } -static int request_locality(struct tpm_chip *chip, int loc) +static int tpm_tis_i2c_request_locality(struct tpm_chip *chip, int loc) { unsigned long start, stop; u8 buf = TPM_ACCESS_REQUEST_USE; int rc; - if (check_locality(chip, loc) >= 0) + if (tpm_tis_i2c_check_locality(chip, loc) >= 0) return loc; /* We already have the locality */ - rc = iic_tpm_write(TPM_ACCESS(loc), &buf, 1); + rc = tpm_tis_i2c_write(TPM_ACCESS(loc), &buf, 1); if (rc) return rc; @@ -209,7 +210,7 @@ static int request_locality(struct tpm_chip *chip, int loc) start = get_timer(0); stop = chip->timeout_a; do { - if (check_locality(chip, loc) >= 0) + if (tpm_tis_i2c_check_locality(chip, loc) >= 0) return loc; udelay(TPM_TIMEOUT * 1000); } while (get_timer(start) < stop); @@ -222,7 +223,7 @@ static u8 tpm_tis_i2c_status(struct tpm_chip *chip) /* NOTE: Since i2c read may fail, return 0 in this case --> time-out */ u8 buf; - if (iic_tpm_read(TPM_STS(chip->locality), &buf, 1) < 0) + if (tpm_tis_i2c_read(TPM_STS(chip->locality), &buf, 1) < 0) return 0; else return buf; @@ -236,12 +237,12 @@ static void tpm_tis_i2c_ready(struct tpm_chip *chip) u8 buf = TPM_STS_COMMAND_READY; debug("%s\n", __func__); - rc = iic_tpm_write_long(TPM_STS(chip->locality), &buf, 1); + rc = tpm_tis_i2c_write_long(TPM_STS(chip->locality), &buf, 1); if (rc) debug("%s: rc=%d\n", __func__, rc); } -static ssize_t get_burstcount(struct tpm_chip *chip) +static ssize_t tpm_tis_i2c_get_burstcount(struct tpm_chip *chip) { unsigned long start, stop; ssize_t burstcnt; @@ -254,7 +255,7 @@ static ssize_t get_burstcount(struct tpm_chip *chip) do { /* Note: STS is little endian */ addr = TPM_STS(chip->locality) + 1; - if (iic_tpm_read(addr, buf, 3) < 0) + if (tpm_tis_i2c_read(addr, buf, 3) < 0) burstcnt = 0; else burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; @@ -267,8 +268,8 @@ static ssize_t get_burstcount(struct tpm_chip *chip) 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 tpm_chip *chip, u8 mask, + unsigned long timeout, int *status) { unsigned long start, stop; @@ -289,14 +290,14 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, return -ETIME; } -static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) +static int tpm_tis_i2c_recv_data(struct tpm_chip *chip, u8 *buf, size_t count) { size_t size = 0; ssize_t burstcnt; int rc; while (size < count) { - burstcnt = get_burstcount(chip); + burstcnt = tpm_tis_i2c_get_burstcount(chip); /* burstcount < 0 -> tpm is busy */ if (burstcnt < 0) @@ -306,7 +307,7 @@ 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->locality), + rc = tpm_tis_i2c_read(TPM_DATA_FIFO(chip->locality), &(buf[size]), burstcnt); if (rc == 0) size += burstcnt; @@ -326,7 +327,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) } /* Read first 10 bytes, including tag, paramsize, and result */ - size = recv_data(chip, buf, TPM_HEADER_SIZE); + size = tpm_tis_i2c_recv_data(chip, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { error("Unable to read header\n"); goto out; @@ -340,15 +341,16 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) goto out; } - size += recv_data(chip, &buf[TPM_HEADER_SIZE], - expected - TPM_HEADER_SIZE); + size += tpm_tis_i2c_recv_data(chip, &buf[TPM_HEADER_SIZE], + expected - TPM_HEADER_SIZE); if (size < expected) { error("Unable to read remainder of result\n"); size = -ETIME; goto out; } - wait_for_stat(chip, TPM_STS_VALID, chip->timeout_c, &status); + tpm_tis_i2c_wait_for_stat(chip, TPM_STS_VALID, chip->timeout_c, + &status); if (status & TPM_STS_DATA_AVAIL) { /* Retry? */ error("Error left over data\n"); size = -EIO; @@ -362,7 +364,7 @@ out: * so we sleep rather than keeping the bus busy */ udelay(2000); - release_locality(chip, chip->locality, 0); + tpm_tis_i2c_release_locality(chip, chip->locality, 0); return size; } @@ -379,20 +381,20 @@ 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(chip, 0) < 0) return -EBUSY; status = tpm_tis_i2c_status(chip); if ((status & TPM_STS_COMMAND_READY) == 0) { tpm_tis_i2c_ready(chip); - if (wait_for_stat(chip, TPM_STS_COMMAND_READY, - chip->timeout_b, &status) < 0) { + if (tpm_tis_i2c_wait_for_stat(chip, TPM_STS_COMMAND_READY, + chip->timeout_b, &status) < 0) { rc = -ETIME; goto out_err; } } - burstcnt = get_burstcount(chip); + burstcnt = tpm_tis_i2c_get_burstcount(chip); /* burstcount < 0 -> tpm is busy */ if (burstcnt < 0) @@ -408,7 +410,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION; #endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */ - rc = iic_tpm_write(TPM_DATA_FIFO(chip->locality), + rc = tpm_tis_i2c_write(TPM_DATA_FIFO(chip->locality), &(buf[count]), burstcnt); if (rc == 0) count += burstcnt; @@ -418,8 +420,9 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) rc = -EIO; goto out_err; } - rc = wait_for_stat(chip, TPM_STS_VALID, - chip->timeout_c, &status); + rc = tpm_tis_i2c_wait_for_stat(chip, TPM_STS_VALID, + chip->timeout_c, + &status); if (rc) goto out_err; @@ -431,7 +434,7 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) } /* Go and do it */ - iic_tpm_write(TPM_STS(chip->locality), &sts, 1); + tpm_tis_i2c_write(TPM_STS(chip->locality), &sts, 1); debug("done\n"); return len; @@ -444,7 +447,7 @@ out_err: * so we sleep rather than keeping the bus busy */ udelay(2000); - release_locality(chip, chip->locality, 0); + tpm_tis_i2c_release_locality(chip, chip->locality, 0); return rc; } @@ -476,7 +479,7 @@ static int tpm_tis_i2c_init(struct udevice *dev) /* Disable interrupts (not supported) */ chip->irq = 0; - /* Default timeouts */ + /* Default timeouts - these could move to the device tree */ chip->timeout_a = TIS_SHORT_TIMEOUT; chip->timeout_b = TIS_LONG_TIMEOUT; chip->timeout_c = TIS_SHORT_TIMEOUT; @@ -485,12 +488,12 @@ static int tpm_tis_i2c_init(struct udevice *dev) chip->req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID; chip->req_canceled = TPM_STS_COMMAND_READY; - if (request_locality(chip, 0) < 0) + if (tpm_tis_i2c_request_locality(chip, 0) < 0) return -ENODEV; /* 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(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) { + tpm_tis_i2c_release_locality(chip, 0, 1); return -EIO; } @@ -519,8 +522,8 @@ static int tpm_tis_i2c_init(struct udevice *dev) } /* Returns max number of milliseconds to wait */ -static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, - u32 ordinal) +static unsigned long tpm_tis_i2c_calc_ordinal_duration(struct tpm_chip *chip, + u32 ordinal) { int duration_idx = TPM_UNDEFINED; int duration = 0; @@ -542,7 +545,7 @@ static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, return duration; } -static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) +static ssize_t tpm_tis_i2c_transmit(const unsigned char *buf, size_t bufsiz) { int rc; u32 count, ordinal; @@ -575,7 +578,7 @@ static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) goto out_recv; start = get_timer(0); - stop = tpm_calc_ordinal_duration(chip, ordinal); + stop = tpm_tis_i2c_calc_ordinal_duration(chip, ordinal); do { debug("waiting for status... %ld %ld\n", start, stop); u8 status = tpm_tis_i2c_status(chip); @@ -614,7 +617,7 @@ out: * @param dev Returns a configuration of TPM device * @return 0 if ok, -1 on error */ -static int tpm_decode_config(struct tpm_chip *chip) +static int tpm_tis_i2c_decode_config(struct tpm_chip *chip) { const void *blob = gd->fdt_blob; struct udevice *bus; @@ -657,7 +660,7 @@ static int tpm_decode_config(struct tpm_chip *chip) } /* * 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. + * in tpm_tis_i2c_read() so the offset length needs to be 0 here. */ ret = i2c_get_chip(bus, chip_addr, 1, &chip->dev); if (ret) { @@ -674,7 +677,7 @@ int tis_init(void) if (g_chip.inited) return 0; - if (tpm_decode_config(&g_chip)) + if (tpm_tis_i2c_decode_config(&g_chip)) return -1; debug("%s: done\n", __func__); @@ -707,7 +710,7 @@ int tis_close(void) return -1; if (g_chip.is_open) { - release_locality(&g_chip, g_chip.locality, 1); + tpm_tis_i2c_release_locality(&g_chip, g_chip.locality, 1); g_chip.is_open = 0; } @@ -728,7 +731,7 @@ int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, memcpy(buf, sendbuf, sbuf_size); - len = tpm_transmit(buf, sbuf_size); + len = tpm_tis_i2c_transmit(buf, sbuf_size); if (len < 10) { *rbuf_len = 0; -- cgit v1.2.1 From 42c8ec56c531c99e2a346358a12ba5b69481f9de Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:30 -0600 Subject: tpm: tpm_tis_i2c: Tidy up delays Use a _US suffix for microseconds and a _MS suffic for milliseconds. Move all timeouts and delays into one place. Use mdelay() instead of udelay() where appropriate. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_i2c.c | 43 ++++++++++++++++++++++--------------------- drivers/tpm/tpm_tis_i2c.h | 16 ++++++---------- 2 files changed, 28 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index e04e8f547b..4b2ef94aa7 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -68,7 +68,7 @@ static int tpm_tis_i2c_read(u8 addr, u8 *buffer, size_t len) rc = dm_i2c_write(g_chip.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; @@ -78,7 +78,7 @@ static int tpm_tis_i2c_read(u8 addr, u8 *buffer, size_t len) * retrieving the data */ for (count = 0; count < MAX_COUNT; count++) { - udelay(SLEEP_DURATION); + udelay(SLEEP_DURATION_US); rc = dm_i2c_read(g_chip.dev, 0, buffer, len); if (rc == 0) break; /* success, break to skip sleep */ @@ -95,12 +95,12 @@ static int tpm_tis_i2c_read(u8 addr, u8 *buffer, size_t len) rc = dm_i2c_read(g_chip.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; @@ -108,7 +108,7 @@ static int tpm_tis_i2c_read(u8 addr, u8 *buffer, size_t len) } static int tpm_tis_i2c_write_generic(u8 addr, u8 *buffer, size_t len, - unsigned int sleep_time, u8 max_count) + unsigned int sleep_time_us, u8 max_count) { int rc = 0; int count; @@ -117,11 +117,11 @@ static int tpm_tis_i2c_write_generic(u8 addr, u8 *buffer, size_t len, rc = dm_i2c_write(g_chip.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; @@ -146,8 +146,8 @@ static int tpm_tis_i2c_write_generic(u8 addr, u8 *buffer, size_t len, */ static int tpm_tis_i2c_write(u8 addr, u8 *buffer, size_t len) { - return tpm_tis_i2c_write_generic(addr, buffer, len, SLEEP_DURATION, - MAX_COUNT); + return tpm_tis_i2c_write_generic(addr, buffer, len, SLEEP_DURATION_US, + MAX_COUNT); } /* @@ -156,8 +156,9 @@ static int tpm_tis_i2c_write(u8 addr, u8 *buffer, size_t len) */ static int tpm_tis_i2c_write_long(u8 addr, u8 *buffer, size_t len) { - return tpm_tis_i2c_write_generic(addr, buffer, len, SLEEP_DURATION_LONG, - MAX_COUNT_LONG); + return tpm_tis_i2c_write_generic(addr, buffer, len, + SLEEP_DURATION_LONG_US, + MAX_COUNT_LONG); } static int tpm_tis_i2c_check_locality(struct tpm_chip *chip, int loc) @@ -212,7 +213,7 @@ static int tpm_tis_i2c_request_locality(struct tpm_chip *chip, int loc) do { if (tpm_tis_i2c_check_locality(chip, loc) >= 0) return loc; - udelay(TPM_TIMEOUT * 1000); + mdelay(TPM_TIMEOUT_MS); } while (get_timer(start) < stop); return -1; @@ -262,7 +263,7 @@ static ssize_t tpm_tis_i2c_get_burstcount(struct tpm_chip *chip) if (burstcnt) return burstcnt; - udelay(TPM_TIMEOUT * 1000); + mdelay(TPM_TIMEOUT_MS); } while (get_timer(start) < stop); return -EBUSY; @@ -281,7 +282,7 @@ static int tpm_tis_i2c_wait_for_stat(struct tpm_chip *chip, u8 mask, start = get_timer(0); stop = timeout; do { - udelay(TPM_TIMEOUT * 1000); + mdelay(TPM_TIMEOUT_MS); *status = tpm_tis_i2c_status(chip); if ((*status & mask) == mask) return 0; @@ -363,7 +364,7 @@ out: * The TPM needs some time to clean up here, * so we sleep rather than keeping the bus busy */ - udelay(2000); + mdelay(2); tpm_tis_i2c_release_locality(chip, chip->locality, 0); return size; @@ -446,7 +447,7 @@ out_err: * The TPM needs some time to clean up here, * so we sleep rather than keeping the bus busy */ - udelay(2000); + mdelay(2); tpm_tis_i2c_release_locality(chip, chip->locality, 0); return rc; @@ -480,10 +481,10 @@ static int tpm_tis_i2c_init(struct udevice *dev) chip->irq = 0; /* Default timeouts - these could move to the device tree */ - chip->timeout_a = TIS_SHORT_TIMEOUT; - chip->timeout_b = TIS_LONG_TIMEOUT; - chip->timeout_c = TIS_SHORT_TIMEOUT; - chip->timeout_d = TIS_SHORT_TIMEOUT; + 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; chip->req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; chip->req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID; chip->req_canceled = TPM_STS_COMMAND_READY; @@ -593,7 +594,7 @@ static ssize_t tpm_tis_i2c_transmit(const unsigned char *buf, size_t bufsiz) rc = -ECANCELED; goto out; } - udelay(TPM_TIMEOUT * 1000); + mdelay(TPM_TIMEOUT_MS); } while (get_timer(start) < stop); tpm_tis_i2c_ready(chip); diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h index db992000e4..ecdaf0cbd9 100644 --- a/drivers/tpm/tpm_tis_i2c.h +++ b/drivers/tpm/tpm_tis_i2c.h @@ -23,7 +23,11 @@ #include 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)*/ @@ -125,9 +129,6 @@ struct tpm_cmd_t { */ #define MAX_COUNT_LONG 50 -#define SLEEP_DURATION 60 /* in usec */ -#define SLEEP_DURATION_LONG 210 /* in usec */ - #define TPM_HEADER_SIZE 10 enum tis_access { @@ -145,11 +146,6 @@ enum tis_status { 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 @@ -169,7 +165,7 @@ enum tpm_duration { /* Extended error numbers from linux (see errno.h) */ #define ECANCELED 125 /* Operation Canceled */ -/* Timer frequency. Corresponds to msec timer resolution*/ +/* Timer frequency. Corresponds to msec timer resolution */ #define HZ 1000 #define TPM_MAX_ORDINAL 243 -- cgit v1.2.1 From f255d31f9063e50b56208fff439b63039cfd7ac6 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:31 -0600 Subject: dm: tpm: Add a uclass for Trusted Platform Modules Add a new uclass for TPMs which uses almost the same TIS (TPM Interface Specification) as is currently implemented. Since init() is handled by the normal driver model probe() method, we don't need to implement that. Also rename the transfer method to xfer() which is a less clumbsy name. Once all drivers and users are converted to driver model we can remove the old code. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/Kconfig | 9 ++ drivers/tpm/Makefile | 2 + drivers/tpm/tpm-uclass.c | 133 +++++++++++++++++++++ drivers/tpm/tpm_internal.h | 287 +++++++++++++++++++++++++++++++++++++++++++++ drivers/tpm/tpm_tis_i2c.c | 2 + drivers/tpm/tpm_tis_i2c.h | 283 -------------------------------------------- drivers/tpm/tpm_tis_lpc.c | 4 +- 7 files changed, 434 insertions(+), 286 deletions(-) create mode 100644 drivers/tpm/tpm-uclass.c create mode 100644 drivers/tpm/tpm_internal.h (limited to 'drivers') diff --git a/drivers/tpm/Kconfig b/drivers/tpm/Kconfig index 9101fc26b9..6bc8fddbd1 100644 --- a/drivers/tpm/Kconfig +++ b/drivers/tpm/Kconfig @@ -4,6 +4,15 @@ 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 diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index 597966ce1f..0d328f8d9d 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -3,6 +3,8 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_DM_TPM) += tpm-uclass.o + obj-$(CONFIG_TPM_ATMEL_TWI) += tpm_atmel_twi.o obj-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o obj-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o diff --git a/drivers/tpm/tpm-uclass.c b/drivers/tpm/tpm-uclass.c new file mode 100644 index 0000000000..b6e1fc5e62 --- /dev/null +++ b/drivers/tpm/tpm-uclass.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#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_internal.h b/drivers/tpm/tpm_internal.h new file mode 100644 index 0000000000..cd29dba0b6 --- /dev/null +++ b/drivers/tpm/tpm_internal.h @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2015 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __tpm_internal_h +#define __tpm_internal_h + +enum { + TPM_MAX_ORDINAL = 243, + TPM_MAX_PROTECTED_ORDINAL = 12, + TPM_PROTECTED_ORDINAL_MASK = 0xff, + TPM_CMD_COUNT_BYTE = 2, + TPM_CMD_ORDINAL_BYTE = 6, +}; + +/* + * Array with one entry per ordinal defining the maximum amount + * of time the chip could take to return the result. The ordinal + * designation of short, medium or long is defined in a table in + * TCG Specification TPM Main Part 2 TPM Structures Section 17. The + * values of the SHORT, MEDIUM, and LONG durations are retrieved + * from the chip during initialization with a call to tpm_get_timeouts. + */ +static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = { + TPM_UNDEFINED, /* 0 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 5 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 10 */ + TPM_SHORT, +}; + +static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { + TPM_UNDEFINED, /* 0 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 5 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 10 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_LONG, + TPM_LONG, + TPM_MEDIUM, /* 15 */ + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, + TPM_LONG, + TPM_SHORT, /* 20 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, /* 25 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 30 */ + TPM_LONG, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 35 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 40 */ + TPM_LONG, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 45 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_LONG, + TPM_MEDIUM, /* 50 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 55 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 60 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 65 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 70 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 75 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 80 */ + TPM_UNDEFINED, + TPM_MEDIUM, + TPM_LONG, + TPM_SHORT, + TPM_UNDEFINED, /* 85 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 90 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 95 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 100 */ + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 105 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 110 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 115 */ + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 120 */ + TPM_LONG, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 125 */ + TPM_SHORT, + TPM_LONG, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, /* 130 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_SHORT, + TPM_MEDIUM, + TPM_UNDEFINED, /* 135 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 140 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 145 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 150 */ + TPM_MEDIUM, + TPM_MEDIUM, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 155 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 160 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 165 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_LONG, /* 170 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 175 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_MEDIUM, /* 180 */ + TPM_SHORT, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, /* 185 */ + TPM_SHORT, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 190 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 195 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 200 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 205 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_MEDIUM, /* 210 */ + TPM_UNDEFINED, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_MEDIUM, + TPM_UNDEFINED, /* 215 */ + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, + TPM_SHORT, /* 220 */ + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_SHORT, + TPM_UNDEFINED, /* 225 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 230 */ + TPM_LONG, + TPM_MEDIUM, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, /* 235 */ + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_UNDEFINED, + TPM_SHORT, /* 240 */ + TPM_UNDEFINED, + TPM_MEDIUM, +}; + +#endif diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 4b2ef94aa7..645f702215 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -25,12 +25,14 @@ #include #include #include +#include #include #include #include #include #include "tpm_tis_i2c.h" +#include "tpm_internal.h" DECLARE_GLOBAL_DATA_PTR; diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h index ecdaf0cbd9..02cc2eba42 100644 --- a/drivers/tpm/tpm_tis_i2c.h +++ b/drivers/tpm/tpm_tis_i2c.h @@ -155,293 +155,10 @@ enum tis_status { #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) -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, -}; - #endif diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c index d09f8cee05..3109c504f3 100644 --- a/drivers/tpm/tpm_tis_lpc.c +++ b/drivers/tpm/tpm_tis_lpc.c @@ -15,6 +15,7 @@ #include #include +#include #include #define PREFIX "lpc_tpm: " @@ -426,9 +427,6 @@ int tis_open(void) { u8 locality = 0; /* we use locality zero for everything. */ - if (tis_close()) - return TPM_DRIVER_ERR; - /* now request access to locality. */ tpm_write_word(TIS_ACCESS_REQUEST_USE, &lpc_tpm_dev[locality].access); -- cgit v1.2.1 From 21baf15b4e638cf7719994fe6ac86e0d0e93aa78 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:35 -0600 Subject: dm: tpm: sandbox: Convert TPM driver to driver model Convert the sandbox TPM driver to use driver model. Add it to the device tree so that it can be found on start-up. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_sandbox.c | 57 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_sandbox.c b/drivers/tpm/tpm_tis_sandbox.c index ed4b039127..9ea98075b3 100644 --- a/drivers/tpm/tpm_tis_sandbox.c +++ b/drivers/tpm/tpm_tis_sandbox.c @@ -5,6 +5,8 @@ */ #include +#include +#include #include #include #include @@ -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), +}; -- cgit v1.2.1 From b697e0ff5b8d92c9544960fd99dbfd9558c0ee6f Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:38 -0600 Subject: dm: tpm: Convert I2C driver to driver model Convert the tpm_tis_i2c driver to use driver model and update boards which use it. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_i2c.c | 529 ++++++++++++++++++---------------------------- drivers/tpm/tpm_tis_i2c.h | 20 +- 2 files changed, 203 insertions(+), 346 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 645f702215..9afe46c1e9 100644 --- a/drivers/tpm/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -23,11 +23,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include @@ -42,8 +42,6 @@ static const char * const chip_name[] = { [UNKNOWN] = "unknown/fallback to slb9635", }; -static struct tpm_chip g_chip; - /* * tpm_tis_i2c_read() - read from TPM register * @addr: register address to read from @@ -58,22 +56,24 @@ static struct tpm_chip g_chip; * * Return -EIO on error, 0 on success. */ -static int tpm_tis_i2c_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 ((g_chip.chip_type == SLB9635) || (g_chip.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++) { - rc = dm_i2c_write(g_chip.dev, 0, (uchar *)&addrbuf, 1); + rc = dm_i2c_write(dev, 0, (uchar *)&addrbuf, 1); if (rc == 0) break; /* Success, break to skip sleep */ 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 @@ -81,7 +81,7 @@ static int tpm_tis_i2c_read(u8 addr, u8 *buffer, size_t len) */ for (count = 0; count < MAX_COUNT; count++) { udelay(SLEEP_DURATION_US); - rc = dm_i2c_read(g_chip.dev, 0, buffer, len); + rc = dm_i2c_read(dev, 0, buffer, len); if (rc == 0) break; /* success, break to skip sleep */ } @@ -94,7 +94,7 @@ static int tpm_tis_i2c_read(u8 addr, u8 *buffer, size_t len) * be safe on the safe side. */ for (count = 0; count < MAX_COUNT; count++) { - rc = dm_i2c_read(g_chip.dev, addr, buffer, len); + rc = dm_i2c_read(dev, addr, buffer, len); if (rc == 0) break; /* break here to skip sleep */ udelay(SLEEP_DURATION_US); @@ -104,19 +104,31 @@ static int tpm_tis_i2c_read(u8 addr, u8 *buffer, size_t len) /* Take care of 'guard time' */ udelay(SLEEP_DURATION_US); if (rc) - return -rc; + return rc; return 0; } -static int tpm_tis_i2c_write_generic(u8 addr, u8 *buffer, size_t len, +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; + 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++) { - rc = dm_i2c_write(g_chip.dev, addr, buffer, len); + rc = dm_i2c_write(dev, addr, buffer, len); if (rc == 0) break; /* Success, break to skip sleep */ udelay(sleep_time_us); @@ -125,7 +137,7 @@ static int tpm_tis_i2c_write_generic(u8 addr, u8 *buffer, size_t len, /* take care of 'guard time' */ udelay(sleep_time_us); if (rc) - return -rc; + return rc; return 0; } @@ -146,30 +158,33 @@ static int tpm_tis_i2c_write_generic(u8 addr, u8 *buffer, size_t len, * * Return -EIO on error, 0 on success */ -static int tpm_tis_i2c_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 tpm_tis_i2c_write_generic(addr, buffer, len, SLEEP_DURATION_US, - 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 tpm_tis_i2c_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 tpm_tis_i2c_write_generic(addr, buffer, len, + return tpm_tis_i2c_write_generic(dev, addr, buffer, len, SLEEP_DURATION_LONG_US, MAX_COUNT_LONG); } -static int tpm_tis_i2c_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 = tpm_tis_i2c_read(TPM_ACCESS(loc), &buf, 1); + rc = tpm_tis_i2c_read(dev, TPM_ACCESS(loc), &buf, 1); if (rc < 0) return rc; @@ -178,75 +193,96 @@ static int tpm_tis_i2c_check_locality(struct tpm_chip *chip, int loc) return loc; } - return -1; + return -ENOENT; } -static void tpm_tis_i2c_release_locality(struct tpm_chip *chip, int loc, +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 (tpm_tis_i2c_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; - tpm_tis_i2c_write(TPM_ACCESS(loc), &buf, 1); + tpm_tis_i2c_write(dev, TPM_ACCESS(loc), &buf, 1); } } -static int tpm_tis_i2c_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 (tpm_tis_i2c_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 = tpm_tis_i2c_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->timeout_a; do { - if (tpm_tis_i2c_check_locality(chip, loc) >= 0) + rc = tpm_tis_i2c_check_locality(dev, loc); + if (rc >= 0) { + debug("%s: Have locality\n", __func__); return loc; + } 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 (tpm_tis_i2c_read(TPM_STS(chip->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 = tpm_tis_i2c_write_long(TPM_STS(chip->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 tpm_tis_i2c_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]; @@ -258,7 +294,7 @@ static ssize_t tpm_tis_i2c_get_burstcount(struct tpm_chip *chip) do { /* Note: STS is little endian */ addr = TPM_STS(chip->locality) + 1; - if (tpm_tis_i2c_read(addr, buf, 3) < 0) + if (tpm_tis_i2c_read(dev, addr, buf, 3) < 0) burstcnt = 0; else burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; @@ -271,13 +307,13 @@ static ssize_t tpm_tis_i2c_get_burstcount(struct tpm_chip *chip) return -EBUSY; } -static int tpm_tis_i2c_wait_for_stat(struct tpm_chip *chip, u8 mask, +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; @@ -285,22 +321,23 @@ static int tpm_tis_i2c_wait_for_stat(struct tpm_chip *chip, u8 mask, stop = timeout; do { mdelay(TPM_TIMEOUT_MS); - *status = tpm_tis_i2c_status(chip); + *status = tpm_tis_i2c_status(dev); if ((*status & mask) == mask) return 0; } while (get_timer(start) < stop); - return -ETIME; + return -ETIMEDOUT; } -static int tpm_tis_i2c_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 = tpm_tis_i2c_get_burstcount(chip); + burstcnt = tpm_tis_i2c_get_burstcount(dev); /* burstcount < 0 -> tpm is busy */ if (burstcnt < 0) @@ -310,8 +347,8 @@ static int tpm_tis_i2c_recv_data(struct tpm_chip *chip, u8 *buf, size_t count) if (burstcnt > (count - size)) burstcnt = count - size; - rc = tpm_tis_i2c_read(TPM_DATA_FIFO(chip->locality), - &(buf[size]), burstcnt); + rc = tpm_tis_i2c_read(dev, TPM_DATA_FIFO(chip->locality), + &(buf[size]), burstcnt); if (rc == 0) size += burstcnt; } @@ -319,61 +356,58 @@ static int tpm_tis_i2c_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 = tpm_tis_i2c_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 += tpm_tis_i2c_recv_data(chip, &buf[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; } - tpm_tis_i2c_wait_for_stat(chip, TPM_STS_VALID, chip->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 - */ - mdelay(2); - tpm_tis_i2c_release_locality(chip, chip->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; @@ -384,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 (tpm_tis_i2c_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 (tpm_tis_i2c_wait_for_stat(chip, TPM_STS_COMMAND_READY, - chip->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 = tpm_tis_i2c_get_burstcount(chip); + burstcnt = tpm_tis_i2c_get_burstcount(dev); /* burstcount < 0 -> tpm is busy */ if (burstcnt < 0) @@ -409,98 +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 = tpm_tis_i2c_write(TPM_DATA_FIFO(chip->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 = tpm_tis_i2c_wait_for_stat(chip, TPM_STS_VALID, + 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 */ - tpm_tis_i2c_write(TPM_STS(chip->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 */ mdelay(2); - tpm_tis_i2c_release_locality(chip, chip->locality, 0); + tpm_tis_i2c_release_locality(dev, chip->locality, 0); - return rc; -} - -static enum i2c_chip_type tpm_tis_i2c_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_tis_i2c_init(struct udevice *dev) { - struct tpm_chip *chip = &g_chip; + struct tpm_chip *chip = dev_get_priv(dev); u32 vendor; u32 expected_did_vid; + int rc; - g_chip.dev = dev; - g_chip.chip_type = tpm_tis_i2c_chip_type(); chip->is_open = 1; - /* Disable interrupts (not supported) */ - chip->irq = 0; - /* 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; - chip->req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID; - chip->req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID; - chip->req_canceled = TPM_STS_COMMAND_READY; - if (tpm_tis_i2c_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 (tpm_tis_i2c_read(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) { - tpm_tis_i2c_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 (g_chip.chip_type == SLB9635) { + if (chip->chip_type == SLB9635) { vendor = be32_to_cpu(vendor); expected_did_vid = TPM_TIS_I2C_DID_VID_9635; } else { @@ -508,13 +524,14 @@ static int tpm_tis_i2c_init(struct udevice *dev) expected_did_vid = TPM_TIS_I2C_DID_VID_9645; } - if (g_chip.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[g_chip.chip_type], vendor >> 16); + chip_name[chip->chip_type], vendor >> 16); /* * A timeout query to TPM can be placed here. @@ -524,225 +541,83 @@ static int tpm_tis_i2c_init(struct udevice *dev) return 0; } -/* Returns max number of milliseconds to wait */ -static unsigned long tpm_tis_i2c_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->duration[duration_idx]; - - if (duration <= 0) - return 2 * 60 * HZ; /* Two minutes timeout */ - else - return duration; -} - -static ssize_t tpm_tis_i2c_transmit(const unsigned char *buf, size_t bufsiz) +static int tpm_tis_i2c_open(struct udevice *dev) { + struct tpm_chip *chip = dev_get_priv(dev); 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 = tpm_tis_i2c_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->irq) - goto out_recv; - - start = get_timer(0); - stop = tpm_tis_i2c_calc_ordinal_duration(chip, ordinal); - do { - debug("waiting for status... %ld %ld\n", start, stop); - u8 status = tpm_tis_i2c_status(chip); - if ((status & chip->req_complete_mask) == - chip->req_complete_val) { - debug("...got it;\n"); - goto out_recv; - } - - if (status == chip->req_canceled) { - error("Operation Canceled\n"); - rc = -ECANCELED; - goto out; - } - mdelay(TPM_TIMEOUT_MS); - } while (get_timer(start) < stop); - - tpm_tis_i2c_ready(chip); - error("Operation Timed out\n"); - rc = -ETIME; - goto out; - -out_recv: - debug("out_recv: reading response...\n"); - rc = tpm_tis_i2c_recv(chip, (u8 *)buf, TPM_BUFSIZE); + debug("%s: start\n", __func__); + if (chip->is_open) + return -EBUSY; + rc = tpm_tis_i2c_init(dev); if (rc < 0) - error("tpm_transmit: tpm_recv: error %d\n", rc); + chip->is_open = 0; -out: return rc; } -/** - * Decode TPM configuration. - * - * @param dev Returns a configuration of TPM device - * @return 0 if ok, -1 on error - */ -static int tpm_tis_i2c_decode_config(struct tpm_chip *chip) +static int tpm_tis_i2c_close(struct udevice *dev) { - const void *blob = gd->fdt_blob; - struct udevice *bus; - int chip_addr; - int parent; - int node; - int ret; - - 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; - } + struct tpm_chip *chip = dev_get_priv(dev); - /* - * 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 tpm_tis_i2c_read() so the offset length needs to be 0 here. - */ - ret = i2c_get_chip(bus, chip_addr, 1, &chip->dev); - if (ret) { - debug("Cannot find device for node '%s: ret=%d'\n", - fdt_get_name(blob, node, NULL), ret); - return ret; + if (chip->is_open) { + tpm_tis_i2c_release_locality(dev, chip->locality, 1); + chip->is_open = 0; + chip->vend_dev = 0; } return 0; } -int tis_init(void) +static int tpm_tis_get_desc(struct udevice *dev, char *buf, int size) { - if (g_chip.inited) - return 0; - - if (tpm_tis_i2c_decode_config(&g_chip)) - return -1; - - debug("%s: done\n", __func__); + struct tpm_chip *chip = dev_get_priv(dev); - g_chip.inited = 1; + if (size < 50) + return -ENOSPC; - return 0; + 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); } -int tis_open(void) +static int tpm_tis_i2c_probe(struct udevice *dev) { - int rc; - - if (!g_chip.inited) - return -1; - - debug("%s: start\n", __func__); - if (g_chip.is_open) - return -EBUSY; - rc = tpm_tis_i2c_init(g_chip.dev); - if (rc < 0) - g_chip.is_open = 0; - - return rc; -} + struct tpm_chip_priv *uc_priv = dev_get_uclass_priv(dev); + struct tpm_chip *chip = dev_get_priv(dev); -int tis_close(void) -{ - if (!g_chip.inited) - return -1; + chip->chip_type = dev_get_driver_data(dev); - if (g_chip.is_open) { - tpm_tis_i2c_release_locality(&g_chip, g_chip.locality, 1); - g_chip.is_open = 0; - } + /* 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; } -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 (!g_chip.inited) - return -1; - - if (sizeof(buf) < sbuf_size) - return -1; - - memcpy(buf, sendbuf, sbuf_size); - - len = tpm_tis_i2c_transmit(buf, sbuf_size); - - if (len < 10) { - *rbuf_len = 0; - return -1; - } +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, +}; - memcpy(recvbuf, buf, len); - *rbuf_len = len; +static const struct udevice_id tpm_tis_i2c_ids[] = { + { .compatible = "infineon,slb9635tt", .data = SLB9635 }, + { .compatible = "infineon,slb9645tt", .data = SLB9645 }, + { } +}; - return 0; -} +U_BOOT_DRIVER(tpm_tis_i2c) = { + .name = "tpm_tis_i2c", + .id = UCLASS_TPM, + .of_match = tpm_tis_i2c_ids, + .ops = &tpm_tis_i2c_ops, + .probe = tpm_tis_i2c_probe, + .priv_auto_alloc_size = sizeof(struct tpm_chip), +}; diff --git a/drivers/tpm/tpm_tis_i2c.h b/drivers/tpm/tpm_tis_i2c.h index 02cc2eba42..3b510d101e 100644 --- a/drivers/tpm/tpm_tis_i2c.h +++ b/drivers/tpm/tpm_tis_i2c.h @@ -37,9 +37,6 @@ enum tpm_timeout { #define TPM_RSP_SIZE_BYTE 2 #define TPM_RSP_RC_BYTE 6 -/* Max buffer size supported by our tpm */ -#define TPM_DEV_BUFSIZE 1260 - enum i2c_chip_type { SLB9635, SLB9645, @@ -47,17 +44,10 @@ enum i2c_chip_type { }; struct tpm_chip { - bool inited; int is_open; - u8 req_complete_mask; - u8 req_complete_val; - u8 req_canceled; - int irq; int locality; + u32 vend_dev; unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ - unsigned long duration[3]; /* msec */ - struct udevice *dev; - u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ enum i2c_chip_type chip_type; }; @@ -129,8 +119,6 @@ struct tpm_cmd_t { */ #define MAX_COUNT_LONG 50 -#define TPM_HEADER_SIZE 10 - enum tis_access { TPM_ACCESS_VALID = 0x80, TPM_ACCESS_ACTIVE_LOCALITY = 0x20, @@ -155,10 +143,4 @@ enum tis_status { #define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) #define TPM_DID_VID(l) (0x0006 | ((l) << 4)) -/* Extended error numbers from linux (see errno.h) */ -#define ECANCELED 125 /* Operation Canceled */ - -/* Timer frequency. Corresponds to msec timer resolution */ -#define HZ 1000 - #endif -- cgit v1.2.1 From d616ba5f5b2a119b597b9974e2bb62e25c933fc8 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Sat, 22 Aug 2015 18:31:39 -0600 Subject: dm: tpm: Convert LPC driver to driver model Convert the tpm_tis_lpc driver to use driver model and update boards which use it. Signed-off-by: Simon Glass Acked-by: Christophe Ricard Reviewed-by: Heiko Schocher --- drivers/tpm/tpm_tis_lpc.c | 286 +++++++++++++++++++++------------------------- 1 file changed, 131 insertions(+), 155 deletions(-) (limited to 'drivers') diff --git a/drivers/tpm/tpm_tis_lpc.c b/drivers/tpm/tpm_tis_lpc.c index 3109c504f3..b41c3cec37 100644 --- a/drivers/tpm/tpm_tis_lpc.c +++ b/drivers/tpm/tpm_tis_lpc.c @@ -14,9 +14,11 @@ */ #include -#include +#include +#include #include #include +#include #define PREFIX "lpc_tpm: " @@ -37,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 */ @@ -64,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); } @@ -157,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; } @@ -229,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, ®s[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); @@ -257,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, + ®s[locality].tpm_status)); } max_cycles = 0; @@ -277,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++], + ®s[locality].data); - value = tis_wait_reg(&lpc_tpm_dev[locality].tpm_status, + value = tis_wait_reg(priv, ®s[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); @@ -301,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++], ®s[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, ®s[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, ®s[locality].tpm_status); return 0; } @@ -329,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, ®s[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 { @@ -355,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, ®s[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, + ®s[locality].data); if (offset == 6) { /* @@ -383,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, ®s[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) @@ -413,65 +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, + ®s[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. */ + 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, ®s[locality].access); /* did we get a lock? */ - if (tis_wait_reg(&lpc_tpm_dev[locality].access, + ret = tis_wait_reg(priv, ®s[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, + ®s[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, ®s[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, + ®s[locality].access); - if (tis_wait_reg(&lpc_tpm_dev[locality].access, - TIS_ACCESS_ACTIVE_LOCALITY, 0) == - TPM_TIMEOUT_ERR) { + if (tis_wait_reg(priv, ®s[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), +}; -- cgit v1.2.1 From e6cabe4a6d142ab981bd31bff0795ed230caf151 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 27 Aug 2015 12:44:28 +0900 Subject: dm: core: allow device_bind() to not return a device pointer This is useful when we want to bind a device, but do not need the pointer to the device. Signed-off-by: Masahiro Yamada Acked-by: Simon Glass --- drivers/core/device.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/core/device.c b/drivers/core/device.c index 01f664796d..afa4b4fda9 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -32,7 +32,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 +134,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; -- cgit v1.2.1 From d90a5a30dec16442fc64154e40018bdbb37776a9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 27 Aug 2015 12:44:29 +0900 Subject: pinctrl: add pin control uclass support This creates a new framework for handling of pin control devices, i.e. devices that control different aspects of package pins. This uclass handles pinmuxing and pin configuration; pinmuxing controls switching among silicon blocks that share certain physical pins, pin configuration handles electronic properties such as pin- biasing, load capacitance etc. This framework can support the same device tree bindings, but if you do not need full interface support, you can disable some features to reduce memory foot print. Typically around 1.5KB is necessary to include full-featured uclass support on ARM board (CONFIG_PINCTRL + CONFIG_PINCTRL_FULL + CONFIG_PINCTRL_GENERIC + CONFIG_PINCTRL_PINMUX), for example. We are often limited on code size for SPL. Besides, we still have many boards that do not support device tree configuration. The full pinctrl, which requires OF_CONTROL, does not make sense for those boards. So, this framework also has a Do-It-Yourself (let's say simple pinctrl) interface. With CONFIG_PINCTRL_FULL disabled, the uclass itself provides no systematic mechanism for identifying the peripheral device, applying pinctrl settings, etc. They must be done in each low-level driver. In return, you can save much memory footprint and it might be useful especially for SPL. Signed-off-by: Masahiro Yamada Acked-by: Simon Glass --- drivers/Kconfig | 2 + drivers/Makefile | 1 + drivers/core/device.c | 4 + drivers/pinctrl/Kconfig | 101 +++++++++++ drivers/pinctrl/Makefile | 2 + drivers/pinctrl/pinctrl-generic.c | 359 ++++++++++++++++++++++++++++++++++++++ drivers/pinctrl/pinctrl-uclass.c | 240 +++++++++++++++++++++++++ 7 files changed, 709 insertions(+) create mode 100644 drivers/pinctrl/Kconfig create mode 100644 drivers/pinctrl/Makefile create mode 100644 drivers/pinctrl/pinctrl-generic.c create mode 100644 drivers/pinctrl/pinctrl-uclass.c (limited to 'drivers') diff --git a/drivers/Kconfig b/drivers/Kconfig index 524d73e64c..63c92c594a 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -40,6 +40,8 @@ source "drivers/pci/Kconfig" source "drivers/pcmcia/Kconfig" +source "drivers/pinctrl/Kconfig" + source "drivers/power/Kconfig" source "drivers/ram/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index a721ec86df..9d0a5959a8 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_$(SPL_)DM) += core/ obj-$(CONFIG_$(SPL_)CLK) += clk/ obj-$(CONFIG_$(SPL_)LED) += led/ +obj-$(CONFIG_$(SPL_)PINCTRL) += pinctrl/ obj-$(CONFIG_$(SPL_)RAM) += ram/ ifdef CONFIG_SPL_BUILD diff --git a/drivers/core/device.c b/drivers/core/device.c index afa4b4fda9..a6cd93698f 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -286,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; diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig new file mode 100644 index 0000000000..6ac56ebe7d --- /dev/null +++ b/drivers/pinctrl/Kconfig @@ -0,0 +1,101 @@ +# +# 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 + +endif + +endmenu diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile new file mode 100644 index 0000000000..a713c7db90 --- /dev/null +++ b/drivers/pinctrl/Makefile @@ -0,0 +1,2 @@ +obj-y += pinctrl-uclass.o +obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC) += pinctrl-generic.o diff --git a/drivers/pinctrl/pinctrl-generic.c b/drivers/pinctrl/pinctrl-generic.c new file mode 100644 index 0000000000..e86b72a8de --- /dev/null +++ b/drivers/pinctrl/pinctrl-generic.c @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +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-uclass.c b/drivers/pinctrl/pinctrl-uclass.c new file mode 100644 index 0000000000..d96c201e83 --- /dev/null +++ b/drivers/pinctrl/pinctrl-uclass.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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", +}; -- cgit v1.2.1 From 9c6a3c6772c4aa53bed0b233621637af2e3eb83e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 27 Aug 2015 12:44:30 +0900 Subject: pinctrl: sandbox: add sandbox pinctrl driver This driver actually does nothing but test pinctrl uclass, and demonstrate how things work. To try this driver, uncomment /* #define DEBUG */ in the drivers/pinctrl/pinctrl-sandbox.c, and debug messages will be displayed. DRAM: 128 MiB sandbox pinmux: group = 1 (serial_a), function = 1 (serial) Using default environment In: cros-ec-keyb Out: lcd Err: lcd Net: Net Initialization Skipped eth0: eth@10002000, eth1: eth@80000000, eth5: eth@90000000 => i2c dev 0 Setting bus to 0 sandbox pinmux: group = 0 (i2c), function = 0 (i2c) sandbox pinconf: group = 0 (i2c), param = 3, arg = 1 Signed-off-by: Masahiro Yamada Acked-by: Simon Glass --- drivers/pinctrl/Kconfig | 8 +++ drivers/pinctrl/Makefile | 2 + drivers/pinctrl/pinctrl-sandbox.c | 147 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 157 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-sandbox.c (limited to 'drivers') diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 6ac56ebe7d..30b8e452ef 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -96,6 +96,14 @@ config SPL_PINCONF 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 index a713c7db90..35decf49c3 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -1,2 +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-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c new file mode 100644 index 0000000000..ab03d8bad4 --- /dev/null +++ b/drivers/pinctrl/pinctrl-sandbox.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* #define DEBUG */ + +#include +#include +#include + +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, +}; -- cgit v1.2.1