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