^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0-only */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2005 IBM Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Authors:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Kylene Hall <kjhall@us.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Maintained by: <tpmdd-devel@lists.sourceforge.net>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Device driver for TCG/TCPA TPM (trusted platform module).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Specifications at www.trustedcomputinggroup.org
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * These difference are required on power because the device must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * discovered through the device tree and iomap must be used to get
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * around the need for holes in the io_page_mask. This does not happen
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * automatically because the tpm is not a normal pci device and lives
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * under the root node.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct tpm_atmel_priv {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) int region_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) int have_region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) unsigned long base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) void __iomem *iobase;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #ifdef CONFIG_PPC64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <asm/prom.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define atmel_getb(priv, offset) readb(priv->iobase + offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define atmel_putb(val, priv, offset) writeb(val, priv->iobase + offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define atmel_request_region request_mem_region
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define atmel_release_region release_mem_region
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static inline void atmel_put_base_addr(void __iomem *iobase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) iounmap(iobase);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) struct device_node *dn;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) unsigned long address, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) const unsigned int *reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) int reglen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) int naddrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int nsizec;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) dn = of_find_node_by_name(NULL, "tpm");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (!dn)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (!of_device_is_compatible(dn, "AT97SC3201")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) of_node_put(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) reg = of_get_property(dn, "reg", ®len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) naddrc = of_n_addr_cells(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) nsizec = of_n_size_cells(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) of_node_put(dn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (naddrc == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) address = ((unsigned long) reg[0] << 32) | reg[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) address = reg[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (nsizec == 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) size =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ((unsigned long) reg[naddrc] << 32) | reg[naddrc + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) size = reg[naddrc];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) *base = address;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) *region_size = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return ioremap(*base, *region_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) #define atmel_getb(chip, offset) inb(atmel_get_priv(chip)->base + offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define atmel_putb(val, chip, offset) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) outb(val, atmel_get_priv(chip)->base + offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) #define atmel_request_region request_region
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #define atmel_release_region release_region
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) /* Atmel definitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) enum tpm_atmel_addr {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) TPM_ATMEL_BASE_ADDR_LO = 0x08,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) TPM_ATMEL_BASE_ADDR_HI = 0x09
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static inline int tpm_read_index(int base, int index)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) outb(index, base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return inb(base+1) & 0xFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /* Verify this is a 1.1 Atmel TPM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int atmel_verify_tpm11(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /* verify that it is an Atmel part */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (tpm_read_index(TPM_ADDR, 4) != 'A' ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) tpm_read_index(TPM_ADDR, 5) != 'T' ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) tpm_read_index(TPM_ADDR, 6) != 'M' ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) tpm_read_index(TPM_ADDR, 7) != 'L')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) /* query chip for its version number */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (tpm_read_index(TPM_ADDR, 0x00) != 1 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) tpm_read_index(TPM_ADDR, 0x01) != 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* This is an atmel supported part */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static inline void atmel_put_base_addr(void __iomem *iobase)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /* Determine where to talk to device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static void __iomem * atmel_get_base_addr(unsigned long *base, int *region_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) int lo, hi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (atmel_verify_tpm11() != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) *base = (hi << 8) | lo;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) *region_size = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return ioport_map(*base, *region_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) #endif