1 // Copyright 2018 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/protocol/platform/bus.h> 8 #include <ddktl/device.h> 9 #include <ddktl/mmio.h> 10 #include <ddktl/protocol/gpioimpl.h> 11 #include <ddktl/protocol/platform/device.h> 12 #include <fbl/array.h> 13 #include <fbl/mutex.h> 14 #include <fbl/vector.h> 15 #include <hw/reg.h> 16 #include <inttypes.h> 17 18 #include <utility> 19 20 namespace gpio { 21 22 constexpr int kPinsPerBlock = 32; 23 constexpr uint64_t kAltFunctionMax = 6; 24 25 struct AmlGpioBlock { 26 uint32_t pin_count; 27 uint32_t oen_offset; 28 uint32_t input_offset; 29 uint32_t output_offset; 30 uint32_t output_shift; // Used for GPIOAO block 31 uint32_t output_write_shift = 0; 32 uint32_t mmio_index; 33 uint32_t pull_offset; 34 uint32_t pull_en_offset; 35 uint32_t pin_start; 36 }; 37 38 struct AmlPinMux { 39 // pinmux register offsets for the alternate functions. 40 // zero means alternate function not supported. 41 uint8_t regs[kAltFunctionMax]; 42 // bit number to set/clear to enable/disable alternate function 43 uint8_t bits[kAltFunctionMax]; 44 }; 45 46 struct AmlPinMuxBlock { 47 AmlPinMux mux[kPinsPerBlock]; 48 }; 49 50 struct AmlGpioInterrupt { 51 uint32_t pin_0_3_select_offset; 52 uint32_t pin_4_7_select_offset; 53 uint32_t edge_polarity_offset; 54 uint32_t filter_select_offset; 55 uint32_t status_offset; 56 uint32_t mask_offset; 57 }; 58 59 class AmlGxlGpio; 60 using DeviceType = ddk::Device<AmlGxlGpio, ddk::Unbindable>; 61 62 class AmlGxlGpio : public DeviceType, 63 public ddk::GpioImplProtocol<AmlGxlGpio, ddk::base_protocol> { 64 65 public: 66 static zx_status_t Create(zx_device_t* parent); 67 68 zx_status_t GpioImplConfigIn(uint32_t index, uint32_t flags); 69 zx_status_t GpioImplConfigOut(uint32_t index, uint8_t initial_value); 70 zx_status_t GpioImplSetAltFunction(uint32_t pin, uint64_t function); 71 zx_status_t GpioImplRead(uint32_t pin, uint8_t* out_value); 72 zx_status_t GpioImplWrite(uint32_t pin, uint8_t value); 73 zx_status_t GpioImplGetInterrupt(uint32_t pin, uint32_t flags, zx::interrupt* out_irq); 74 zx_status_t GpioImplReleaseInterrupt(uint32_t pin); 75 zx_status_t GpioImplSetPolarity(uint32_t pin, uint32_t polarity); 76 DdkUnbind()77 void DdkUnbind() { DdkRemove(); } DdkRelease()78 void DdkRelease() { delete this; } 79 80 private: AmlGxlGpio(zx_device_t * parent,const pdev_protocol_t & pdev,ddk::MmioBuffer mmio_gpio,ddk::MmioBuffer mmio_gpio_a0,ddk::MmioBuffer mmio_interrupt,const AmlGpioBlock * gpio_blocks,const AmlGpioInterrupt * gpio_interrupt,const AmlPinMuxBlock * pinmux_blocks,size_t block_count,fbl::Array<fbl::Mutex> block_locks,fbl::Array<uint16_t> irq_info)81 AmlGxlGpio(zx_device_t* parent, const pdev_protocol_t& pdev, 82 ddk::MmioBuffer mmio_gpio, ddk::MmioBuffer mmio_gpio_a0, 83 ddk::MmioBuffer mmio_interrupt, const AmlGpioBlock* gpio_blocks, 84 const AmlGpioInterrupt* gpio_interrupt, const AmlPinMuxBlock* pinmux_blocks, 85 size_t block_count, fbl::Array<fbl::Mutex> block_locks, 86 fbl::Array<uint16_t> irq_info) 87 : DeviceType(parent), pdev_(pdev), mmios_{std::move(mmio_gpio), std::move(mmio_gpio_a0)}, 88 mmio_interrupt_(std::move(mmio_interrupt)), gpio_blocks_(gpio_blocks), 89 gpio_interrupt_(gpio_interrupt), pinmux_blocks_(pinmux_blocks), block_count_(block_count), 90 block_locks_(std::move(block_locks)), irq_info_(std::move(irq_info)), irq_status_(0) {} 91 92 // Note: The out_pin_index returned by this API is not the index of the pin 93 // in the particular GPIO block. eg. if its 7, its not GPIOH7 94 // It is the index of the bit corresponding to the GPIO in consideration in a 95 // particular INPUT/OUTPUT/PULL-UP/PULL-DOWN/PULL-ENABLE/ENABLE register 96 // out_block and out_lock are owned by the AmlGxlGpio instance and should not be deleted by 97 // callers. 98 zx_status_t AmlPinToBlock(const uint32_t pin, const AmlGpioBlock** out_block, 99 uint32_t* out_pin_index, fbl::Mutex** out_lock) const; 100 101 void Bind(const pbus_protocol_t& pbus); 102 Read32GpioReg(int index,uint32_t offset)103 inline uint32_t Read32GpioReg(int index, uint32_t offset) { 104 return mmios_[index].Read32(offset << 2); 105 } 106 Write32GpioReg(int index,uint32_t offset,uint32_t value)107 inline void Write32GpioReg(int index, uint32_t offset, uint32_t value) { 108 mmios_[index].Write32(value, offset << 2); 109 } 110 Read32GpioInterruptReg(uint32_t offset)111 inline uint32_t Read32GpioInterruptReg(uint32_t offset) { 112 return mmio_interrupt_.Read32(offset << 2); 113 } 114 Write32GpioInterruptReg(uint32_t offset,uint32_t value)115 inline void Write32GpioInterruptReg(uint32_t offset, uint32_t value) { 116 mmio_interrupt_.Write32(value, offset << 2); 117 } 118 119 pdev_protocol_t pdev_; 120 ddk::MmioBuffer mmios_[2]; // separate MMIO for AO domain 121 ddk::MmioBuffer mmio_interrupt_; 122 const AmlGpioBlock* gpio_blocks_; 123 const AmlGpioInterrupt* gpio_interrupt_; 124 const AmlPinMuxBlock* pinmux_blocks_; 125 size_t block_count_; 126 const fbl::Array<fbl::Mutex> block_locks_; 127 fbl::Mutex interrupt_lock_; 128 fbl::Mutex pinmux_lock_; 129 fbl::Array<uint16_t> irq_info_; 130 uint8_t irq_status_; 131 }; 132 133 } // namespace gpio 134