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