1*c2e9c5bbSJustin Hibbits /*- 2*c2e9c5bbSJustin Hibbits * Copyright (c) 2023 Juniper Networks, Inc. 3*c2e9c5bbSJustin Hibbits * All rights reserved. 4*c2e9c5bbSJustin Hibbits * 5*c2e9c5bbSJustin Hibbits * Redistribution and use in source and binary forms, with or without 6*c2e9c5bbSJustin Hibbits * modification, are permitted provided that the following conditions 7*c2e9c5bbSJustin Hibbits * are met: 8*c2e9c5bbSJustin Hibbits * 1. Redistributions of source code must retain the above copyright 9*c2e9c5bbSJustin Hibbits * notice, this list of conditions and the following disclaimer. 10*c2e9c5bbSJustin Hibbits * 2. Redistributions in binary form must reproduce the above copyright 11*c2e9c5bbSJustin Hibbits * notice, this list of conditions and the following disclaimer in the 12*c2e9c5bbSJustin Hibbits * documentation and/or other materials provided with the distribution. 13*c2e9c5bbSJustin Hibbits * 14*c2e9c5bbSJustin Hibbits * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15*c2e9c5bbSJustin Hibbits * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16*c2e9c5bbSJustin Hibbits * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17*c2e9c5bbSJustin Hibbits * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18*c2e9c5bbSJustin Hibbits * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19*c2e9c5bbSJustin Hibbits * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20*c2e9c5bbSJustin Hibbits * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21*c2e9c5bbSJustin Hibbits * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22*c2e9c5bbSJustin Hibbits * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23*c2e9c5bbSJustin Hibbits * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24*c2e9c5bbSJustin Hibbits * POSSIBILITY OF SUCH DAMAGE. 25*c2e9c5bbSJustin Hibbits */ 26*c2e9c5bbSJustin Hibbits 27*c2e9c5bbSJustin Hibbits #include <sys/cdefs.h> 28*c2e9c5bbSJustin Hibbits #include <sys/types.h> 29*c2e9c5bbSJustin Hibbits #include <sys/bus.h> 30*c2e9c5bbSJustin Hibbits 31*c2e9c5bbSJustin Hibbits #include <dev/spibus/spi.h> 32*c2e9c5bbSJustin Hibbits #include "spibus_if.h" 33*c2e9c5bbSJustin Hibbits #include "tpm_if.h" 34*c2e9c5bbSJustin Hibbits #include "tpm20.h" 35*c2e9c5bbSJustin Hibbits 36*c2e9c5bbSJustin Hibbits #define TPM_BASE_ADDR 0xD40000 37*c2e9c5bbSJustin Hibbits #define TPM_SPI_HEADER_SIZE 4 38*c2e9c5bbSJustin Hibbits #define TPM_WAIT_STATES 50 39*c2e9c5bbSJustin Hibbits 40*c2e9c5bbSJustin Hibbits static void 41*c2e9c5bbSJustin Hibbits tpm_insert_wait(device_t dev) 42*c2e9c5bbSJustin Hibbits { 43*c2e9c5bbSJustin Hibbits device_t parent = device_get_parent(dev); 44*c2e9c5bbSJustin Hibbits int wait = TPM_WAIT_STATES; 45*c2e9c5bbSJustin Hibbits struct spi_command spic = SPI_COMMAND_INITIALIZER; 46*c2e9c5bbSJustin Hibbits 47*c2e9c5bbSJustin Hibbits uint8_t txb = 0; 48*c2e9c5bbSJustin Hibbits uint8_t rxb = 0; 49*c2e9c5bbSJustin Hibbits 50*c2e9c5bbSJustin Hibbits spic.tx_cmd = &txb; 51*c2e9c5bbSJustin Hibbits spic.rx_cmd = &rxb; 52*c2e9c5bbSJustin Hibbits spic.tx_cmd_sz = 1; 53*c2e9c5bbSJustin Hibbits spic.rx_cmd_sz = 1; 54*c2e9c5bbSJustin Hibbits spic.flags = SPI_FLAG_KEEP_CS; 55*c2e9c5bbSJustin Hibbits do { 56*c2e9c5bbSJustin Hibbits SPIBUS_TRANSFER(parent, dev, &spic); 57*c2e9c5bbSJustin Hibbits } while (--wait > 0 && (rxb & 0x1) == 0); 58*c2e9c5bbSJustin Hibbits } 59*c2e9c5bbSJustin Hibbits 60*c2e9c5bbSJustin Hibbits static inline int 61*c2e9c5bbSJustin Hibbits tpm_spi_read_n(device_t dev, bus_size_t off, void *buf, size_t size) 62*c2e9c5bbSJustin Hibbits { 63*c2e9c5bbSJustin Hibbits struct spi_command spic = SPI_COMMAND_INITIALIZER; 64*c2e9c5bbSJustin Hibbits uint8_t tx[4] = {0}; 65*c2e9c5bbSJustin Hibbits uint8_t rx[4] = {0}; 66*c2e9c5bbSJustin Hibbits int err; 67*c2e9c5bbSJustin Hibbits 68*c2e9c5bbSJustin Hibbits if (size > sizeof(rx)) 69*c2e9c5bbSJustin Hibbits return (EINVAL); 70*c2e9c5bbSJustin Hibbits off += TPM_BASE_ADDR; 71*c2e9c5bbSJustin Hibbits tx[0] = 0x80 | (size - 1); /* Write (size) bytes */ 72*c2e9c5bbSJustin Hibbits tx[1] = (off >> 16) & 0xff; 73*c2e9c5bbSJustin Hibbits tx[2] = (off >> 8) & 0xff; 74*c2e9c5bbSJustin Hibbits tx[3] = off & 0xff; 75*c2e9c5bbSJustin Hibbits 76*c2e9c5bbSJustin Hibbits spic.tx_cmd = tx; 77*c2e9c5bbSJustin Hibbits spic.tx_cmd_sz = sizeof(tx); 78*c2e9c5bbSJustin Hibbits spic.rx_cmd = rx; 79*c2e9c5bbSJustin Hibbits spic.rx_cmd_sz = sizeof(tx); 80*c2e9c5bbSJustin Hibbits spic.flags = SPI_FLAG_KEEP_CS; 81*c2e9c5bbSJustin Hibbits 82*c2e9c5bbSJustin Hibbits err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic); 83*c2e9c5bbSJustin Hibbits 84*c2e9c5bbSJustin Hibbits if (!(rx[3] & 0x1)) { 85*c2e9c5bbSJustin Hibbits tpm_insert_wait(dev); 86*c2e9c5bbSJustin Hibbits } 87*c2e9c5bbSJustin Hibbits memset(tx, 0, sizeof(tx)); 88*c2e9c5bbSJustin Hibbits spic.tx_cmd_sz = spic.rx_cmd_sz = size; 89*c2e9c5bbSJustin Hibbits spic.flags = 0; 90*c2e9c5bbSJustin Hibbits err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic); 91*c2e9c5bbSJustin Hibbits memcpy(buf, &rx[0], size); 92*c2e9c5bbSJustin Hibbits 93*c2e9c5bbSJustin Hibbits return (err); 94*c2e9c5bbSJustin Hibbits } 95*c2e9c5bbSJustin Hibbits 96*c2e9c5bbSJustin Hibbits static inline int 97*c2e9c5bbSJustin Hibbits tpm_spi_write_n(device_t dev, bus_size_t off, void *buf, size_t size) 98*c2e9c5bbSJustin Hibbits { 99*c2e9c5bbSJustin Hibbits struct spi_command spic = SPI_COMMAND_INITIALIZER; 100*c2e9c5bbSJustin Hibbits uint8_t tx[8] = {0}; 101*c2e9c5bbSJustin Hibbits uint8_t rx[8] = {0}; 102*c2e9c5bbSJustin Hibbits int err; 103*c2e9c5bbSJustin Hibbits 104*c2e9c5bbSJustin Hibbits off += TPM_BASE_ADDR; 105*c2e9c5bbSJustin Hibbits tx[0] = 0x00 | (size - 1); /* Write (size) bytes */ 106*c2e9c5bbSJustin Hibbits tx[1] = (off >> 16) & 0xff; 107*c2e9c5bbSJustin Hibbits tx[2] = (off >> 8) & 0xff; 108*c2e9c5bbSJustin Hibbits tx[3] = off & 0xff; 109*c2e9c5bbSJustin Hibbits 110*c2e9c5bbSJustin Hibbits memcpy(&tx[4], buf, size); 111*c2e9c5bbSJustin Hibbits 112*c2e9c5bbSJustin Hibbits spic.tx_cmd = tx; 113*c2e9c5bbSJustin Hibbits spic.tx_cmd_sz = size + TPM_SPI_HEADER_SIZE; 114*c2e9c5bbSJustin Hibbits spic.rx_cmd = rx; 115*c2e9c5bbSJustin Hibbits spic.rx_cmd_sz = size + TPM_SPI_HEADER_SIZE; 116*c2e9c5bbSJustin Hibbits 117*c2e9c5bbSJustin Hibbits err = SPIBUS_TRANSFER(device_get_parent(dev), dev, &spic); 118*c2e9c5bbSJustin Hibbits 119*c2e9c5bbSJustin Hibbits return (err); 120*c2e9c5bbSJustin Hibbits } 121*c2e9c5bbSJustin Hibbits 122*c2e9c5bbSJustin Hibbits /* Override accessors */ 123*c2e9c5bbSJustin Hibbits static inline uint8_t 124*c2e9c5bbSJustin Hibbits spi_read_1(device_t dev, bus_size_t off) 125*c2e9c5bbSJustin Hibbits { 126*c2e9c5bbSJustin Hibbits uint8_t rx_byte; 127*c2e9c5bbSJustin Hibbits 128*c2e9c5bbSJustin Hibbits tpm_spi_read_n(dev, off, &rx_byte, 1); 129*c2e9c5bbSJustin Hibbits 130*c2e9c5bbSJustin Hibbits return (rx_byte); 131*c2e9c5bbSJustin Hibbits } 132*c2e9c5bbSJustin Hibbits 133*c2e9c5bbSJustin Hibbits static inline uint32_t 134*c2e9c5bbSJustin Hibbits spi_read_4(device_t dev, bus_size_t off) 135*c2e9c5bbSJustin Hibbits { 136*c2e9c5bbSJustin Hibbits uint32_t rx_word = 0; 137*c2e9c5bbSJustin Hibbits 138*c2e9c5bbSJustin Hibbits tpm_spi_read_n(dev, off, &rx_word, 4); 139*c2e9c5bbSJustin Hibbits rx_word = le32toh(rx_word); 140*c2e9c5bbSJustin Hibbits 141*c2e9c5bbSJustin Hibbits return (rx_word); 142*c2e9c5bbSJustin Hibbits } 143*c2e9c5bbSJustin Hibbits 144*c2e9c5bbSJustin Hibbits static inline void 145*c2e9c5bbSJustin Hibbits spi_write_1(device_t dev, bus_size_t off, uint8_t val) 146*c2e9c5bbSJustin Hibbits { 147*c2e9c5bbSJustin Hibbits tpm_spi_write_n(dev, off, &val, 1); 148*c2e9c5bbSJustin Hibbits } 149*c2e9c5bbSJustin Hibbits 150*c2e9c5bbSJustin Hibbits static inline void 151*c2e9c5bbSJustin Hibbits spi_write_4(device_t dev, bus_size_t off, uint32_t val) 152*c2e9c5bbSJustin Hibbits { 153*c2e9c5bbSJustin Hibbits uint32_t tmp = htole32(val); 154*c2e9c5bbSJustin Hibbits tpm_spi_write_n(dev, off, &tmp, 4); 155*c2e9c5bbSJustin Hibbits } 156*c2e9c5bbSJustin Hibbits 157*c2e9c5bbSJustin Hibbits static device_method_t tpm_spibus_methods[] = { 158*c2e9c5bbSJustin Hibbits DEVMETHOD(tpm_read_4, spi_read_4), 159*c2e9c5bbSJustin Hibbits DEVMETHOD(tpm_read_1, spi_read_1), 160*c2e9c5bbSJustin Hibbits DEVMETHOD(tpm_write_4, spi_write_4), 161*c2e9c5bbSJustin Hibbits DEVMETHOD(tpm_write_1, spi_write_1), 162*c2e9c5bbSJustin Hibbits DEVMETHOD_END 163*c2e9c5bbSJustin Hibbits }; 164*c2e9c5bbSJustin Hibbits 165*c2e9c5bbSJustin Hibbits DEFINE_CLASS_0(tpm_spi, tpm_spi_driver, tpm_spibus_methods, 166*c2e9c5bbSJustin Hibbits sizeof(struct tpm_sc)); 167