1*36e3d877SAbhi.Singh /* 2*36e3d877SAbhi.Singh * Copyright (c) 2025, Arm Limited. All rights reserved. 3*36e3d877SAbhi.Singh * 4*36e3d877SAbhi.Singh * SPDX-License-Identifier: BSD-3-Clause 5*36e3d877SAbhi.Singh */ 6*36e3d877SAbhi.Singh #include <lib/libc/endian.h> 7*36e3d877SAbhi.Singh 8*36e3d877SAbhi.Singh #include <drivers/delay_timer.h> 9*36e3d877SAbhi.Singh #include <drivers/tpm/tpm2.h> 10*36e3d877SAbhi.Singh #include <drivers/tpm/tpm2_chip.h> 11*36e3d877SAbhi.Singh #include <drivers/tpm/tpm2_interface.h> 12*36e3d877SAbhi.Singh 13*36e3d877SAbhi.Singh #define LOCALITY_START_ADDRESS(x, y) \ 14*36e3d877SAbhi.Singh ((uint16_t)(x->address + (0x1000 * y))) 15*36e3d877SAbhi.Singh 16*36e3d877SAbhi.Singh static int tpm2_get_info(struct tpm_chip_data *chip_data, uint8_t locality) 17*36e3d877SAbhi.Singh { 18*36e3d877SAbhi.Singh uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality); 19*36e3d877SAbhi.Singh uint32_t vid_did; 20*36e3d877SAbhi.Singh uint8_t revision; 21*36e3d877SAbhi.Singh int err; 22*36e3d877SAbhi.Singh 23*36e3d877SAbhi.Singh err = tpm2_fifo_read_chunk(tpm_base_addr + TPM_FIFO_REG_VENDID, DWORD, &vid_did); 24*36e3d877SAbhi.Singh if (err < 0) { 25*36e3d877SAbhi.Singh return err; 26*36e3d877SAbhi.Singh } 27*36e3d877SAbhi.Singh 28*36e3d877SAbhi.Singh err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_REVID, &revision); 29*36e3d877SAbhi.Singh if (err < 0) { 30*36e3d877SAbhi.Singh return err; 31*36e3d877SAbhi.Singh } 32*36e3d877SAbhi.Singh 33*36e3d877SAbhi.Singh INFO("TPM Chip: vendor-id 0x%x, device-id 0x%x, revision-id: 0x%x\n", 34*36e3d877SAbhi.Singh 0xFFFF & vid_did, vid_did >> 16, revision); 35*36e3d877SAbhi.Singh 36*36e3d877SAbhi.Singh return TPM_SUCCESS; 37*36e3d877SAbhi.Singh } 38*36e3d877SAbhi.Singh 39*36e3d877SAbhi.Singh static int tpm2_wait_reg_bits(uint16_t reg, uint8_t set, unsigned long timeout, uint8_t *status) 40*36e3d877SAbhi.Singh { 41*36e3d877SAbhi.Singh int err; 42*36e3d877SAbhi.Singh uint64_t timeout_delay = timeout_init_us(timeout * 1000); 43*36e3d877SAbhi.Singh 44*36e3d877SAbhi.Singh do { 45*36e3d877SAbhi.Singh err = tpm2_fifo_read_byte(reg, status); 46*36e3d877SAbhi.Singh if (err < 0) { 47*36e3d877SAbhi.Singh return err; 48*36e3d877SAbhi.Singh } 49*36e3d877SAbhi.Singh if ((*status & set) == set) { 50*36e3d877SAbhi.Singh return TPM_SUCCESS; 51*36e3d877SAbhi.Singh } 52*36e3d877SAbhi.Singh } while (!timeout_elapsed(timeout_delay)); 53*36e3d877SAbhi.Singh 54*36e3d877SAbhi.Singh return TPM_ERR_TIMEOUT; 55*36e3d877SAbhi.Singh } 56*36e3d877SAbhi.Singh 57*36e3d877SAbhi.Singh static int tpm2_fifo_request_access(struct tpm_chip_data *chip_data, uint8_t locality) 58*36e3d877SAbhi.Singh { 59*36e3d877SAbhi.Singh uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality); 60*36e3d877SAbhi.Singh uint8_t status; 61*36e3d877SAbhi.Singh int err; 62*36e3d877SAbhi.Singh 63*36e3d877SAbhi.Singh err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, TPM_ACCESS_REQUEST_USE); 64*36e3d877SAbhi.Singh if (err < 0) { 65*36e3d877SAbhi.Singh return err; 66*36e3d877SAbhi.Singh } 67*36e3d877SAbhi.Singh 68*36e3d877SAbhi.Singh err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_ACCESS, 69*36e3d877SAbhi.Singh TPM_ACCESS_ACTIVE_LOCALITY, 70*36e3d877SAbhi.Singh chip_data->timeout_msec_a, &status); 71*36e3d877SAbhi.Singh if (err == 0) { 72*36e3d877SAbhi.Singh chip_data->locality = locality; 73*36e3d877SAbhi.Singh return TPM_SUCCESS; 74*36e3d877SAbhi.Singh } 75*36e3d877SAbhi.Singh 76*36e3d877SAbhi.Singh return err; 77*36e3d877SAbhi.Singh } 78*36e3d877SAbhi.Singh 79*36e3d877SAbhi.Singh static int tpm2_fifo_release_locality(struct tpm_chip_data *chip_data, uint8_t locality) 80*36e3d877SAbhi.Singh { 81*36e3d877SAbhi.Singh uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, locality); 82*36e3d877SAbhi.Singh uint8_t buf; 83*36e3d877SAbhi.Singh int err; 84*36e3d877SAbhi.Singh 85*36e3d877SAbhi.Singh err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, &buf); 86*36e3d877SAbhi.Singh if (err < 0) { 87*36e3d877SAbhi.Singh return err; 88*36e3d877SAbhi.Singh } 89*36e3d877SAbhi.Singh 90*36e3d877SAbhi.Singh if (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) { 91*36e3d877SAbhi.Singh return tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_ACCESS, 92*36e3d877SAbhi.Singh TPM_ACCESS_RELINQUISH_LOCALITY); 93*36e3d877SAbhi.Singh } 94*36e3d877SAbhi.Singh 95*36e3d877SAbhi.Singh ERROR("%s: Unable to release locality\n", __func__); 96*36e3d877SAbhi.Singh return TPM_ERR_RESPONSE; 97*36e3d877SAbhi.Singh } 98*36e3d877SAbhi.Singh 99*36e3d877SAbhi.Singh static int tpm2_fifo_prepare(struct tpm_chip_data *chip_data) 100*36e3d877SAbhi.Singh { 101*36e3d877SAbhi.Singh uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality); 102*36e3d877SAbhi.Singh uint8_t status; 103*36e3d877SAbhi.Singh int err; 104*36e3d877SAbhi.Singh 105*36e3d877SAbhi.Singh err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_COMMAND_READY); 106*36e3d877SAbhi.Singh if (err < 0) { 107*36e3d877SAbhi.Singh return err; 108*36e3d877SAbhi.Singh } 109*36e3d877SAbhi.Singh 110*36e3d877SAbhi.Singh err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS, 111*36e3d877SAbhi.Singh TPM_STAT_COMMAND_READY, 112*36e3d877SAbhi.Singh chip_data->timeout_msec_b, &status); 113*36e3d877SAbhi.Singh if (err < 0) { 114*36e3d877SAbhi.Singh ERROR("%s: TPM Status Busy\n", __func__); 115*36e3d877SAbhi.Singh return err; 116*36e3d877SAbhi.Singh } 117*36e3d877SAbhi.Singh 118*36e3d877SAbhi.Singh return TPM_SUCCESS; 119*36e3d877SAbhi.Singh } 120*36e3d877SAbhi.Singh 121*36e3d877SAbhi.Singh static int tpm2_fifo_get_burstcount(struct tpm_chip_data *chip_data, uint16_t *burstcount) 122*36e3d877SAbhi.Singh { 123*36e3d877SAbhi.Singh uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality); 124*36e3d877SAbhi.Singh uint64_t timeout_delay = timeout_init_us(chip_data->timeout_msec_a * 1000); 125*36e3d877SAbhi.Singh int err; 126*36e3d877SAbhi.Singh 127*36e3d877SAbhi.Singh if (burstcount == NULL) { 128*36e3d877SAbhi.Singh return TPM_INVALID_PARAM; 129*36e3d877SAbhi.Singh } 130*36e3d877SAbhi.Singh 131*36e3d877SAbhi.Singh do { 132*36e3d877SAbhi.Singh uint8_t byte0, byte1; 133*36e3d877SAbhi.Singh 134*36e3d877SAbhi.Singh err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_LO, &byte0); 135*36e3d877SAbhi.Singh if (err < 0) { 136*36e3d877SAbhi.Singh return err; 137*36e3d877SAbhi.Singh } 138*36e3d877SAbhi.Singh 139*36e3d877SAbhi.Singh err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_BURST_COUNT_HI, &byte1); 140*36e3d877SAbhi.Singh if (err < 0) { 141*36e3d877SAbhi.Singh return err; 142*36e3d877SAbhi.Singh } 143*36e3d877SAbhi.Singh 144*36e3d877SAbhi.Singh *burstcount = (uint16_t)((byte1 << 8) + byte0); 145*36e3d877SAbhi.Singh if (*burstcount != 0U) { 146*36e3d877SAbhi.Singh return TPM_SUCCESS; 147*36e3d877SAbhi.Singh } 148*36e3d877SAbhi.Singh } while (!timeout_elapsed(timeout_delay)); 149*36e3d877SAbhi.Singh 150*36e3d877SAbhi.Singh return TPM_ERR_TIMEOUT; 151*36e3d877SAbhi.Singh } 152*36e3d877SAbhi.Singh 153*36e3d877SAbhi.Singh static int tpm2_fifo_send(struct tpm_chip_data *chip_data, const tpm_cmd *buf) 154*36e3d877SAbhi.Singh { 155*36e3d877SAbhi.Singh uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality); 156*36e3d877SAbhi.Singh uint8_t status; 157*36e3d877SAbhi.Singh uint16_t burstcnt; 158*36e3d877SAbhi.Singh int err; 159*36e3d877SAbhi.Singh uint32_t len, index; 160*36e3d877SAbhi.Singh 161*36e3d877SAbhi.Singh if (sizeof(buf->header) != TPM_HEADER_SIZE) { 162*36e3d877SAbhi.Singh ERROR("%s: invalid command header size.\n", __func__); 163*36e3d877SAbhi.Singh return TPM_INVALID_PARAM; 164*36e3d877SAbhi.Singh } 165*36e3d877SAbhi.Singh 166*36e3d877SAbhi.Singh err = tpm2_fifo_read_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, &status); 167*36e3d877SAbhi.Singh if (err < 0) { 168*36e3d877SAbhi.Singh return err; 169*36e3d877SAbhi.Singh } 170*36e3d877SAbhi.Singh 171*36e3d877SAbhi.Singh if (!(status & TPM_STAT_COMMAND_READY)) { 172*36e3d877SAbhi.Singh err = tpm2_fifo_prepare(chip_data); 173*36e3d877SAbhi.Singh if (err < 0) { 174*36e3d877SAbhi.Singh return err; 175*36e3d877SAbhi.Singh } 176*36e3d877SAbhi.Singh } 177*36e3d877SAbhi.Singh 178*36e3d877SAbhi.Singh /* write the command header to the TPM first */ 179*36e3d877SAbhi.Singh const uint8_t *header_data = (const uint8_t *)&buf->header; 180*36e3d877SAbhi.Singh 181*36e3d877SAbhi.Singh for (index = 0; index < TPM_HEADER_SIZE; index++) { 182*36e3d877SAbhi.Singh err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO, 183*36e3d877SAbhi.Singh header_data[index]); 184*36e3d877SAbhi.Singh if (err < 0) { 185*36e3d877SAbhi.Singh return err; 186*36e3d877SAbhi.Singh } 187*36e3d877SAbhi.Singh } 188*36e3d877SAbhi.Singh 189*36e3d877SAbhi.Singh len = be32toh(buf->header.cmd_size); 190*36e3d877SAbhi.Singh 191*36e3d877SAbhi.Singh while (index < len) { 192*36e3d877SAbhi.Singh err = tpm2_fifo_get_burstcount(chip_data, &burstcnt); 193*36e3d877SAbhi.Singh if (err < 0) { 194*36e3d877SAbhi.Singh return err; 195*36e3d877SAbhi.Singh } 196*36e3d877SAbhi.Singh 197*36e3d877SAbhi.Singh for (; burstcnt > 0U && index < len; burstcnt--) { 198*36e3d877SAbhi.Singh err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_DATA_FIFO, 199*36e3d877SAbhi.Singh buf->data[index - TPM_HEADER_SIZE]); 200*36e3d877SAbhi.Singh if (err < 0) { 201*36e3d877SAbhi.Singh return err; 202*36e3d877SAbhi.Singh } 203*36e3d877SAbhi.Singh index++; 204*36e3d877SAbhi.Singh } 205*36e3d877SAbhi.Singh } 206*36e3d877SAbhi.Singh 207*36e3d877SAbhi.Singh err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS, 208*36e3d877SAbhi.Singh TPM_STAT_VALID, 209*36e3d877SAbhi.Singh chip_data->timeout_msec_c, 210*36e3d877SAbhi.Singh &status); 211*36e3d877SAbhi.Singh if (err < 0) { 212*36e3d877SAbhi.Singh return err; 213*36e3d877SAbhi.Singh } 214*36e3d877SAbhi.Singh 215*36e3d877SAbhi.Singh if (status & TPM_STAT_EXPECT) { 216*36e3d877SAbhi.Singh ERROR("%s: TPM is still expecting data after command buffer is sent\n", __func__); 217*36e3d877SAbhi.Singh return TPM_ERR_TRANSFER; 218*36e3d877SAbhi.Singh } 219*36e3d877SAbhi.Singh 220*36e3d877SAbhi.Singh err = tpm2_fifo_write_byte(tpm_base_addr + TPM_FIFO_REG_STATUS, TPM_STAT_GO); 221*36e3d877SAbhi.Singh if (err < 0) { 222*36e3d877SAbhi.Singh return err; 223*36e3d877SAbhi.Singh } 224*36e3d877SAbhi.Singh 225*36e3d877SAbhi.Singh return TPM_SUCCESS; 226*36e3d877SAbhi.Singh } 227*36e3d877SAbhi.Singh 228*36e3d877SAbhi.Singh static int tpm2_fifo_read_data(struct tpm_chip_data *chip_data, tpm_cmd *buf, 229*36e3d877SAbhi.Singh uint16_t tpm_base_addr, uint8_t *status, int *size, int bytes_expected) 230*36e3d877SAbhi.Singh { 231*36e3d877SAbhi.Singh int err, read_size, loop_index; 232*36e3d877SAbhi.Singh uint16_t burstcnt; 233*36e3d877SAbhi.Singh uint8_t *read_data; 234*36e3d877SAbhi.Singh 235*36e3d877SAbhi.Singh if (bytes_expected == TPM_READ_HEADER) { 236*36e3d877SAbhi.Singh /* read the response header from the TPM first */ 237*36e3d877SAbhi.Singh read_data = (uint8_t *)&buf->header; 238*36e3d877SAbhi.Singh read_size = TPM_HEADER_SIZE; 239*36e3d877SAbhi.Singh loop_index = *size; 240*36e3d877SAbhi.Singh } else { 241*36e3d877SAbhi.Singh /* process the rest of the mssg with bytes_expected */ 242*36e3d877SAbhi.Singh read_data = buf->data; 243*36e3d877SAbhi.Singh read_size = bytes_expected; 244*36e3d877SAbhi.Singh loop_index = *size - TPM_HEADER_SIZE; 245*36e3d877SAbhi.Singh } 246*36e3d877SAbhi.Singh 247*36e3d877SAbhi.Singh err = tpm2_wait_reg_bits(tpm_base_addr + TPM_FIFO_REG_STATUS, 248*36e3d877SAbhi.Singh TPM_STAT_AVAIL, 249*36e3d877SAbhi.Singh chip_data->timeout_msec_c, 250*36e3d877SAbhi.Singh status); 251*36e3d877SAbhi.Singh if (err < 0) { 252*36e3d877SAbhi.Singh return err; 253*36e3d877SAbhi.Singh } 254*36e3d877SAbhi.Singh 255*36e3d877SAbhi.Singh while (*size < read_size) { 256*36e3d877SAbhi.Singh err = tpm2_fifo_get_burstcount(chip_data, &burstcnt); 257*36e3d877SAbhi.Singh if (err < 0) { 258*36e3d877SAbhi.Singh ERROR("%s: TPM burst count error\n", __func__); 259*36e3d877SAbhi.Singh return err; 260*36e3d877SAbhi.Singh } 261*36e3d877SAbhi.Singh 262*36e3d877SAbhi.Singh for (; burstcnt > 0U && loop_index < read_size; 263*36e3d877SAbhi.Singh burstcnt--, loop_index++, (*size)++) { 264*36e3d877SAbhi.Singh err = tpm2_fifo_read_byte( 265*36e3d877SAbhi.Singh tpm_base_addr + TPM_FIFO_REG_DATA_FIFO, 266*36e3d877SAbhi.Singh (void *)&read_data[loop_index]); 267*36e3d877SAbhi.Singh if (err < 0) { 268*36e3d877SAbhi.Singh return err; 269*36e3d877SAbhi.Singh } 270*36e3d877SAbhi.Singh } 271*36e3d877SAbhi.Singh } 272*36e3d877SAbhi.Singh 273*36e3d877SAbhi.Singh return TPM_SUCCESS; 274*36e3d877SAbhi.Singh } 275*36e3d877SAbhi.Singh 276*36e3d877SAbhi.Singh static int tpm2_fifo_receive(struct tpm_chip_data *chip_data, tpm_cmd *buf) 277*36e3d877SAbhi.Singh { 278*36e3d877SAbhi.Singh uint16_t tpm_base_addr = LOCALITY_START_ADDRESS(chip_data, chip_data->locality); 279*36e3d877SAbhi.Singh int size = 0, bytes_expected, err; 280*36e3d877SAbhi.Singh uint8_t status; 281*36e3d877SAbhi.Singh 282*36e3d877SAbhi.Singh err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, TPM_READ_HEADER); 283*36e3d877SAbhi.Singh if (err < 0) { 284*36e3d877SAbhi.Singh return err; 285*36e3d877SAbhi.Singh } 286*36e3d877SAbhi.Singh 287*36e3d877SAbhi.Singh bytes_expected = be32toh(buf->header.cmd_size); 288*36e3d877SAbhi.Singh if (bytes_expected > sizeof(*buf)) { 289*36e3d877SAbhi.Singh ERROR("%s: tpm response buffer cannot store expected response\n", __func__); 290*36e3d877SAbhi.Singh return TPM_INVALID_PARAM; 291*36e3d877SAbhi.Singh } 292*36e3d877SAbhi.Singh 293*36e3d877SAbhi.Singh if (size == bytes_expected) { 294*36e3d877SAbhi.Singh return size; 295*36e3d877SAbhi.Singh } 296*36e3d877SAbhi.Singh 297*36e3d877SAbhi.Singh err = tpm2_fifo_read_data(chip_data, buf, tpm_base_addr, &status, &size, bytes_expected); 298*36e3d877SAbhi.Singh if (err < 0) { 299*36e3d877SAbhi.Singh return err; 300*36e3d877SAbhi.Singh } 301*36e3d877SAbhi.Singh 302*36e3d877SAbhi.Singh if (size < bytes_expected) { 303*36e3d877SAbhi.Singh ERROR("%s: response buffer size is less than expected\n", __func__); 304*36e3d877SAbhi.Singh return TPM_ERR_RESPONSE; 305*36e3d877SAbhi.Singh } 306*36e3d877SAbhi.Singh 307*36e3d877SAbhi.Singh return TPM_SUCCESS; 308*36e3d877SAbhi.Singh } 309*36e3d877SAbhi.Singh 310*36e3d877SAbhi.Singh static interface_ops_t fifo_ops = { 311*36e3d877SAbhi.Singh .get_info = tpm2_get_info, 312*36e3d877SAbhi.Singh .send = tpm2_fifo_send, 313*36e3d877SAbhi.Singh .receive = tpm2_fifo_receive, 314*36e3d877SAbhi.Singh .request_access = tpm2_fifo_request_access, 315*36e3d877SAbhi.Singh .release_locality = tpm2_fifo_release_locality, 316*36e3d877SAbhi.Singh }; 317*36e3d877SAbhi.Singh 318*36e3d877SAbhi.Singh struct interface_ops * 319*36e3d877SAbhi.Singh tpm_interface_getops(struct tpm_chip_data *chip_data, uint8_t locality) 320*36e3d877SAbhi.Singh { 321*36e3d877SAbhi.Singh return &fifo_ops; 322*36e3d877SAbhi.Singh } 323