1// Copyright 2017 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#pragma once 6 7#include <ddk/device.h> 8#include <fbl/mutex.h> 9#include <fbl/type_support.h> 10#include <fbl/unique_ptr.h> 11#include <stdint.h> 12#include <lib/zx/handle.h> 13#include <zircon/assert.h> 14#include <zircon/thread_annotations.h> 15#include <zircon/types.h> 16 17#include "tpm.h" 18 19namespace tpm { 20 21class I2cCr50Interface : public HardwareInterface { 22public: 23 // Creates a new I2cCr50Interface from the given |i2c_dev|. This will issue an 24 // I2C transaction to determine support. 25 static zx_status_t Create(zx_device_t* i2c_dev, zx::handle irq, 26 fbl::unique_ptr<I2cCr50Interface>* out); 27 virtual ~I2cCr50Interface(); 28 29 zx_status_t Validate() override; 30 31 zx_status_t ReadAccess(Locality loc, uint8_t* access) override; 32 zx_status_t WriteAccess(Locality loc, uint8_t access) override; 33 34 zx_status_t ReadStatus(Locality loc, uint32_t* sts) override; 35 zx_status_t WriteStatus(Locality loc, uint32_t sts) override; 36 37 zx_status_t ReadDidVid(uint16_t* vid, uint16_t* did) override; 38 39 zx_status_t ReadDataFifo(Locality loc, uint8_t* buf, size_t len) override; 40 zx_status_t WriteDataFifo(Locality loc, const uint8_t* buf, size_t len) override; 41 42private: 43 template <typename T> struct I2cRegister { 44 explicit constexpr I2cRegister(uint8_t addr) : addr(addr) { } 45 const uint8_t addr; 46 }; 47 48 // Timeout to use if this device does not have an IRQ wired up. 49 static constexpr zx::duration kNoIrqTimeout = zx::msec(20); 50 // Delay to use between retries if an I2C operation errors. 51 static constexpr zx::duration kI2cRetryDelay = zx::usec(50); 52 53 I2cCr50Interface(zx_device_t* i2c_dev, zx::handle irq); 54 55 // Block until the controller signals it is ready. May return spuriously, 56 // so the condition being waited on should be checked after return. 57 zx_status_t WaitForIrqLocked() TA_REQ(lock_); 58 59 // Template for enforcing correct access size for each register read 60 template <typename T> 61 zx_status_t RegisterRead(const I2cRegister<T>& reg, T* out) { 62 // TODO(teisenbe): If we ever support a big-endian host, we need to do 63 // endianness swapping here. 64 static_assert(fbl::is_integral<T>::value, "T must be integral"); 65 return RegisterRead(I2cRegister<uint8_t[]>(reg.addr), reinterpret_cast<uint8_t*>(out), 66 sizeof(T)); 67 } 68 69 // Template for enforcing correct access size for each register write 70 template <typename T> 71 zx_status_t RegisterWrite(const I2cRegister<T>& reg, const T& val) { 72 static_assert(fbl::is_integral<T>::value, "T must be integral"); 73 return RegisterWrite(I2cRegister<uint8_t[]>(reg.addr), 74 reinterpret_cast<const uint8_t*>(&val), sizeof(T)); 75 } 76 77 // Perform an I2C read cycle 78 zx_status_t I2cReadLocked(uint8_t* val, size_t len) TA_REQ(lock_); 79 // Perform an I2C write cycle 80 zx_status_t I2cWriteLocked(const uint8_t* val, size_t len) TA_REQ(lock_); 81 82 // Perform a register read/write for an unsized register (indicated 83 // by T=uint8_t[]). 84 zx_status_t RegisterWrite(const I2cRegister<uint8_t[]>& reg, 85 const uint8_t* val, size_t len) TA_EXCL(lock_); 86 zx_status_t RegisterRead(const I2cRegister<uint8_t[]>& reg, 87 uint8_t* out, size_t len) TA_EXCL(lock_); 88 89 // Compute the register address prefix for the given locality 90 static constexpr uint8_t LocToPrefix(Locality loc) { 91 ZX_DEBUG_ASSERT(loc <= 4); 92 return static_cast<uint8_t>(loc << 4); 93 } 94 95 // These methods return an object usable with RegisterRead/RegisterWrite representing 96 // the specified register and locality. 97 static constexpr I2cRegister<uint8_t> RegisterAccess(Locality loc) { 98 return I2cRegister<uint8_t>(static_cast<uint8_t>(LocToPrefix(loc) | 0x0u)); 99 } 100 static constexpr I2cRegister<uint32_t> RegisterStatus(Locality loc) { 101 ZX_DEBUG_ASSERT(loc <= 4); 102 return I2cRegister<uint32_t>(static_cast<uint8_t>(LocToPrefix(loc) | 0x1u)); 103 } 104 static constexpr I2cRegister<uint8_t[]> RegisterDataFifo(Locality loc) { 105 ZX_DEBUG_ASSERT(loc <= 4); 106 return I2cRegister<uint8_t[]>(static_cast<uint8_t>(LocToPrefix(loc) | 0x5u)); 107 } 108 static constexpr I2cRegister<uint32_t> RegisterDidVid(Locality loc) { 109 ZX_DEBUG_ASSERT(loc <= 4); 110 return I2cRegister<uint32_t>(static_cast<uint8_t>(LocToPrefix(loc) | 0x6u)); 111 } 112 113 fbl::Mutex lock_; 114 115 // The upstream i2c device 116 zx_device_t* i2c_ TA_GUARDED(lock_) = nullptr; 117 zx::handle irq_ TA_GUARDED(lock_); 118}; 119 120} // namespace tpm 121