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 <assert.h> 8 #include <ddktl/mmio.h> 9 #include <fbl/unique_ptr.h> 10 #include <soc/aml-common/aml-audio-regs.h> 11 12 #include <utility> 13 14 class AmlTdmDevice { 15 16 public: 17 18 DISALLOW_COPY_ASSIGN_AND_MOVE(AmlTdmDevice); 19 20 static constexpr int32_t kMclkDivBits = 16; 21 static constexpr int32_t kSclkDivBits = 10; 22 static constexpr int32_t kLRclkDivBits = 10; 23 24 static fbl::unique_ptr<AmlTdmDevice> Create(ddk::MmioBuffer mmio, 25 ee_audio_mclk_src_t src, 26 aml_tdm_out_t tdm_dev, 27 aml_frddr_t frddr_dev, 28 aml_tdm_mclk_t mclk); 29 30 //Configure an mclk channel divider 31 zx_status_t SetMclkDiv(uint32_t div); 32 //Configure an sclk/lclk generator block 33 zx_status_t SetSclkDiv(uint32_t sdiv, uint32_t lrduty, uint32_t lrdiv); 34 // Configures the mclk pad. 35 zx_status_t SetMClkPad(aml_tdm_mclk_pad_t mclk_pad); 36 37 // Configures placement of data on the tdm bus 38 void ConfigTdmOutSlot(uint8_t bit_offset, uint8_t num_slots, uint8_t bits_per_slot, 39 uint8_t bits_per_sample, uint8_t mix_mask); 40 41 // Configures Lanes. 42 zx_status_t ConfigTdmOutLane(size_t lane, uint32_t mask); 43 44 // Configures TDM swaps. 45 void ConfigTdmOutSwaps(uint32_t swaps); 46 47 // Sets the buffer/length pointers for dma engine 48 // must resize in lower 32-bits of address space 49 zx_status_t SetBuffer(zx_paddr_t buf, size_t len); 50 51 /* 52 Returns offset of dma pointer in the ring buffer 53 */ 54 uint32_t GetRingPosition(); 55 56 /* 57 Resets state of dma mechanisms and starts clocking data 58 onto tdm bus with data fetched from beginning of buffer 59 */ 60 uint64_t Start(); 61 62 /* 63 Stops clocking data out on the TDM bus 64 (physical tdm bus signals remain active) 65 */ 66 void Stop(); 67 68 /* 69 Synchronize the state of TDM bus signals with fifo/dma engine 70 */ 71 void Sync(); 72 73 /* 74 Stops the clocking data, shuts down frddr, and quiets output signals 75 */ 76 void Shutdown(); 77 fifo_depth()78 uint32_t fifo_depth() const { return fifo_depth_;}; 79 80 private: 81 const uint32_t fifo_depth_; // in bytes. 82 const aml_tdm_out_t tdm_ch_; // tdm output block used by this instance 83 const aml_frddr_t frddr_ch_; // fromddr channel used by this instance 84 const aml_tdm_mclk_t mclk_ch_; // mclk channel used by this instance 85 const ee_audio_mclk_src_t clk_src_; 86 const zx_off_t frddr_base_; // base offset of frddr ch used by this instance 87 const zx_off_t tdm_base_; // base offset of our tdmout block 88 const ddk::MmioBuffer mmio_; 89 friend class fbl::unique_ptr<AmlTdmDevice>; 90 AmlTdmDevice(ddk::MmioBuffer mmio,ee_audio_mclk_src_t clk_src,aml_tdm_out_t tdm,aml_frddr_t frddr,aml_tdm_mclk_t mclk,uint32_t fifo_depth)91 AmlTdmDevice(ddk::MmioBuffer mmio, ee_audio_mclk_src_t clk_src, 92 aml_tdm_out_t tdm, aml_frddr_t frddr, aml_tdm_mclk_t mclk, 93 uint32_t fifo_depth) : 94 fifo_depth_(fifo_depth), 95 tdm_ch_(tdm), 96 frddr_ch_(frddr), 97 mclk_ch_(mclk), 98 clk_src_(clk_src), 99 frddr_base_(GetFrddrBase(frddr)), 100 tdm_base_(GetTdmBase(tdm)), 101 mmio_(std::move(mmio)) {}; 102 103 ~AmlTdmDevice() = default; 104 105 /* Get the register block offset for our ddr block */ GetFrddrBase(aml_frddr_t ch)106 static zx_off_t GetFrddrBase(aml_frddr_t ch) { 107 switch (ch) { 108 case FRDDR_A: 109 return EE_AUDIO_FRDDR_A_CTRL0; 110 case FRDDR_B: 111 return EE_AUDIO_FRDDR_B_CTRL0; 112 case FRDDR_C: 113 return EE_AUDIO_FRDDR_C_CTRL0; 114 } 115 //We should never get here, but if we do, make it obvious 116 assert(0); 117 return 0; 118 } 119 /* Get the register block offset for our tdm block */ GetTdmBase(aml_tdm_out_t ch)120 static zx_off_t GetTdmBase(aml_tdm_out_t ch) { 121 switch (ch) { 122 case TDM_OUT_A: 123 return EE_AUDIO_TDMOUT_A_CTRL0; 124 case TDM_OUT_B: 125 return EE_AUDIO_TDMOUT_B_CTRL0; 126 case TDM_OUT_C: 127 return EE_AUDIO_TDMOUT_C_CTRL0; 128 } 129 //We should never get here, but if we do, make it obvious 130 assert(0); 131 return 0; 132 } 133 134 void AudioClkEna(uint32_t audio_blk_mask); 135 void AudioClkDis(uint32_t audio_blk_mask); 136 void InitRegs(); 137 void FRDDREnable(); 138 void FRDDRDisable(); 139 void TdmOutDisable(); 140 void TdmOutEnable(); 141 142 /* Get the register block offset for our ddr block */ GetFrddrOffset(zx_off_t off)143 zx_off_t GetFrddrOffset(zx_off_t off) { 144 return frddr_base_ + off; 145 } 146 /* Get the register block offset for our tdm block */ GetTdmOffset(zx_off_t off)147 zx_off_t GetTdmOffset(zx_off_t off) { 148 return tdm_base_ + off; 149 } 150 }; 151