1 /**
2   ******************************************************************************
3   * @file    rtl8721dhp_audio.c
4   * @author
5   * @version V1.0.0
6   * @date    2017-12-13
7   * @brief   This file provides firmware functions to manage the following
8   *          functionalities of the Audio codec peripheral:
9   *           - SPORT Initialization
10   *           - SPORT parameters management
11   *           - Data transfers configuration
12   *           - GDMA configuration
13   *
14   ******************************************************************************
15   * @attention
16   *
17   * This module is a confidential and proprietary property of RealTek and
18   * possession or use of this module requires written permission of RealTek.
19   *
20   * Copyright(c) 2017, Realtek Semiconductor Corporation. All rights reserved.
21   ******************************************************************************
22   */
23 #include "ameba_soc.h"
24 
25 const AUDIO_DevTable AUDIO_DEV_TABLE[1] = {
26 		{AUDIO_SPORT_DEV, GDMA_HANDSHAKE_INTERFACE_AUDIO_TX, GDMA_HANDSHAKE_INTERFACE_AUDIO_RX},   /*audio sport */
27 };
28 
29 /**
30   * @brief  Fills each SP_StructInit member with its default value.
31   * @param  SP_StructInit: pointer to an SP_StructInit structure which will be
32   *         initialized.
33   * @retval None
34   */
AUDIO_SP_StructInit(SP_InitTypeDef * SP_InitStruct)35 void AUDIO_SP_StructInit(SP_InitTypeDef* SP_InitStruct)
36 {
37 	SP_InitStruct->SP_WordLen = SP_WL_16;
38 	SP_InitStruct->SP_DataFormat = SP_DF_I2S;
39 	SP_InitStruct->SP_MonoStereo = SP_CH_STEREO;
40 	SP_InitStruct->SP_SelRxCh = SP_RX_CH_LR;
41 }
42 
43 /**
44   * @brief  Initializes the AUDIO SPORT registers according to the specified parameters
45   *         in SP_InitStruct.
46   * @param  SPORTx: pointer to the base addr of AUDIO SPORT peripheral.
47   * @param  SP_InitStruct: pointer to an SP_InitTypeDef structure that contains
48   *         the configuration information for the specified AUDIO SPORT peripheral
49   * @note   AUDIO SPORT has two clock sources, one is 98.304MHz, the other is 45.1584MHz.
50   *         BIT_CTRL_CTLX_I2S_CLK_SRC can used to select the clock source.
51   * @retval None
52   */
AUDIO_SP_Init(AUDIO_SPORT_TypeDef * SPORTx,SP_InitTypeDef * SP_InitStruct)53 void AUDIO_SP_Init(AUDIO_SPORT_TypeDef* SPORTx, SP_InitTypeDef* SP_InitStruct)
54 {
55 	u32 Tmp;
56 
57 	/* Check the parameters */
58 	assert_param(IS_SP_WORD_LEN(SP_InitStruct->SP_WordLen));
59 	assert_param(IS_SP_DATA_FMT(SP_InitStruct->SP_DataFormat));
60 	assert_param(IS_SP_CHN_NUM(SP_InitStruct->SP_MonoStereo));
61 	assert_param(IS_SP_SEL_RX_CH(SP_InitStruct->SP_SelRxCh));
62 
63 	/* Reset SPORT module */
64 	SPORTx->SP_CTRLR0 |= SP_CTRLR0_RST;
65 	SPORTx->SP_CTRLR0 &= ~ SP_CTRLR0_RST;
66 
67 	/* Configure parameters: BCLK = 16*16K */
68 	SPORTx->SP_CLK_DIV = 0x271 | (0x10 << 16) | SP_CLK_MI_NI_UPDATE;
69 
70 	/* Configure parameters: disable RX, disable TX, AUDIO SPORT mode */
71 	AUDIO_SP_TxStart(SPORTx, DISABLE);
72 	AUDIO_SP_RxStart(SPORTx, DISABLE);
73 
74 	/* Configure parameters: data format, word length, channel number, etc */
75 	Tmp = SPORTx->SP_CTRLR0;
76 	Tmp &= ~(SP_CTRLR0_DATA_LEN_SEL |SP_CTRLR0_DATA_FORMAT_SEL | SP_CTRLR0_EN_I2S_MONO | SP_CTRLR0_SEL_I2S_RX_CH);
77 	Tmp |= ((SP_InitStruct->SP_WordLen << 12) |
78 		(SP_InitStruct->SP_DataFormat << 8) |
79 		(SP_InitStruct->SP_MonoStereo << 11) |
80 		(SP_InitStruct->SP_SelRxCh << 28));
81 	SPORTx->SP_CTRLR0 = Tmp;
82 }
83 
84 /**
85   * @brief  Start or stop SPORT Tx.
86   * @param  SPORTx: pointer to the base addr of AUDIO SPORT peripheral.
87   * @param  NewState: new state of the SPORT Tx.
88   *         This parameter can be: ENABLE or DISABLE.
89   * @retval None
90   */
AUDIO_SP_TxStart(AUDIO_SPORT_TypeDef * SPORTx,u32 NewState)91 void AUDIO_SP_TxStart(AUDIO_SPORT_TypeDef* SPORTx, u32 NewState)
92 {
93 	if (NewState == ENABLE) {
94 		SPORTx->SP_CTRLR0 &= ~ SP_CTRLR0_TX_DISABLE;
95 		SPORTx->SP_CTRLR0 |= SP_CTRLR0_START_TX;
96 	} else {
97 		SPORTx->SP_CTRLR0 |= SP_CTRLR0_TX_DISABLE;
98 		SPORTx->SP_CTRLR0 &= ~ SP_CTRLR0_START_TX;
99 	}
100 }
101 
102 /**
103   * @brief  Start or stop SPORT Rx.
104   * @param  SPORTx: pointer to the base addr of AUDIO SPORT peripheral.
105   * @param  NewState: new state of the SPORT Rx.
106   *         This parameter can be: ENABLE or DISABLE.
107   * @retval None
108   */
AUDIO_SP_RxStart(AUDIO_SPORT_TypeDef * SPORTx,u32 NewState)109 void AUDIO_SP_RxStart(AUDIO_SPORT_TypeDef* SPORTx, u32 NewState)
110 {
111 	if (NewState == ENABLE) {
112 		SPORTx->SP_CTRLR0 &= ~ SP_CTRLR0_RX_DISABLE;
113 		SPORTx->SP_CTRLR0 |= SP_CTRLR0_START_RX;
114 	} else {
115 		SPORTx->SP_CTRLR0 |= SP_CTRLR0_RX_DISABLE;
116 		SPORTx->SP_CTRLR0 &= ~ SP_CTRLR0_START_RX;
117 	}
118 }
119 
120 /**
121   * @brief  SPORT Tx DMA request on or off.
122   * @param  SPORTx: pointer to the base addr of AUDIO SPORT peripheral.
123   * @param  NewState: new state of the SPORT Tx DMA request.
124   *         This parameter can be: ENABLE or DISABLE.
125   * @note If Tx DMA request is not enable, then should start Tx when GDMA complete every time.
126   * @retval None
127   */
AUDIO_SP_TdmaCmd(AUDIO_SPORT_TypeDef * SPORTx,u32 NewState)128 void AUDIO_SP_TdmaCmd(AUDIO_SPORT_TypeDef* SPORTx, u32 NewState)
129 {
130 	if (NewState == ENABLE) {
131 		SPORTx->SP_CTRLR1 |= SP_CTRLR1_TDMA_REQ;
132 		SPORTx->SP_DSP_INT_CR &= ~ SP_TX_DMA_SINGLE_NO_REQ;
133 	} else {
134 		SPORTx->SP_CTRLR1 &= ~ SP_CTRLR1_TDMA_REQ;
135 		SPORTx->SP_DSP_INT_CR |= SP_TX_DMA_SINGLE_NO_REQ;
136 	}
137 }
138 
139 /**
140   * @brief  SPORT Rx DMA request on or off.
141   * @param  SPORTx: pointer to the base addr of AUDIO SPORT peripheral.
142   * @param  NewState: new state of the SPORT Rx DMA request.
143   *         This parameter can be: ENABLE or DISABLE.
144   * @note If Rx DMA request is not enable, then should start Rx when GDMA complete every time.
145   * @retval None
146   */
AUDIO_SP_RdmaCmd(AUDIO_SPORT_TypeDef * SPORTx,u32 NewState)147 void AUDIO_SP_RdmaCmd(AUDIO_SPORT_TypeDef* SPORTx, u32 NewState)
148 {
149 	if (NewState == ENABLE) {
150 		SPORTx->SP_CTRLR1 |= SP_CTRLR1_RDMA_REQ;
151 		SPORTx->SP_DSP_INT_CR &= ~ SP_RX_DMA_SINGLE_NO_REQ;
152 	} else {
153 		SPORTx->SP_CTRLR1 &= ~ SP_CTRLR1_RDMA_REQ;
154 		SPORTx->SP_DSP_INT_CR |= SP_RX_DMA_SINGLE_NO_REQ;
155 	}
156 }
157 
158 /**
159   * @brief  Set the AUDIO SPORT word length.
160   * @param  SPORTx: pointer to the base addr of AUDIO SPORT peripheral.
161   * @param  SP_WordLen: the value of word length.
162   *          This parameter can be one of the following values:
163   *            @arg SP_WL_16: sample bit is 16 bit
164   *            @arg SP_WL_24: sample bit is 24 bit
165   *            @arg SP_WL_8: sample bit is 8 bit
166   * @retval None
167   */
AUDIO_SP_SetWordLen(AUDIO_SPORT_TypeDef * SPORTx,u32 SP_WordLen)168 void AUDIO_SP_SetWordLen(AUDIO_SPORT_TypeDef* SPORTx, u32 SP_WordLen)
169 {
170 	u32 reg_value;
171 	assert_param(IS_SP_WORD_LEN(SP_WordLen));
172 
173 	reg_value = SPORTx->SP_CTRLR0;
174 	reg_value &= ~(SP_CTRLR0_DATA_LEN_SEL);
175 	reg_value |= (SP_WordLen << 12);
176 	SPORTx->SP_CTRLR0 = reg_value;
177 }
178 
179 /**
180   * @brief Get AUDIO SPORT word length.
181   * @param  SPORTx: pointer to the base addr of AUDIO SPORT peripheral.
182   * @retval the value of word length.
183   *            @arg 0: sample bit is 16 bit
184   *            @arg 2: sample bit is 24 bit
185   *            @arg 3: sample bit is 8 bit
186   */
187 
AUDIO_SP_GetWordLen(AUDIO_SPORT_TypeDef * SPORTx)188 u32 AUDIO_SP_GetWordLen(AUDIO_SPORT_TypeDef* SPORTx)
189 {
190 	u32 len = ((SPORTx->SP_CTRLR0) & SP_CTRLR0_DATA_LEN_SEL) >> 12;
191 	return len;
192 }
193 
194 /**
195   * @brief  Set the AUDIO SPORT channel number.
196   * @param  SPORTx: pointer to the base addr of AUDIO SPORT peripheral.
197   * @param  SP_MonoStereo: mono or stereo.
198   *          This parameter can be one of the following values:
199   *            @arg SP_CH_STEREO: stereo channel, channel number is 2
200   *            @arg SP_CH_MONO: mono channel, channel number is 1
201   * @retval None
202   */
AUDIO_SP_SetMonoStereo(AUDIO_SPORT_TypeDef * SPORTx,u32 SP_MonoStereo)203 void AUDIO_SP_SetMonoStereo(AUDIO_SPORT_TypeDef* SPORTx, u32 SP_MonoStereo)
204 {
205 	u32 reg_value;
206 	assert_param(IS_SP_CHN_NUM(SP_MonoStereo));
207 
208 	reg_value = SPORTx->SP_CTRLR0;
209 	reg_value &= ~(SP_CTRLR0_EN_I2S_MONO);
210 	reg_value |= (SP_MonoStereo << 11);
211 	SPORTx->SP_CTRLR0 = reg_value;
212 }
213 
214 /**
215   * @brief    Initialize GDMA peripheral for sending data.
216   * @param  Index: 0.
217   * @param  GDMA_InitStruct: pointer to a GDMA_InitTypeDef structure that contains
218   *         the configuration information for the GDMA peripheral.
219   * @param  CallbackData: GDMA callback data.
220   * @param  CallbackFunc: GDMA callback function.
221   * @param  pTxData: Tx Buffer.
222   * @param  Length: Tx Count.
223   * @retval   TRUE/FLASE
224   */
AUDIO_SP_TXGDMA_Init(u32 Index,GDMA_InitTypeDef * GDMA_InitStruct,void * CallbackData,IRQ_FUN CallbackFunc,u8 * pTxData,u32 Length)225 BOOL AUDIO_SP_TXGDMA_Init(
226 	u32 Index,
227 	GDMA_InitTypeDef *GDMA_InitStruct,
228 	void *CallbackData,
229 	IRQ_FUN CallbackFunc,
230 	u8 *pTxData,
231 	u32 Length
232 	)
233 {
234 	u8 GdmaChnl;
235 	AUDIO_SPORT_TypeDef *SPORTx = AUDIO_DEV_TABLE[Index].SPORTx;
236 	u32 WordLen = AUDIO_SP_GetWordLen(SPORTx);
237 
238 	assert_param(GDMA_InitStruct != NULL);
239 	/*obtain a DMA channel and register DMA interrupt handler*/
240 	GdmaChnl = GDMA_ChnlAlloc(0, CallbackFunc, (u32)CallbackData, 12);
241 	if (GdmaChnl == 0xFF) {
242 		// No Available DMA channel
243 		return _FALSE;
244 	}
245 
246 	_memset((void *)GDMA_InitStruct, 0, sizeof(GDMA_InitTypeDef));
247 
248 	/*set GDMA initial structure member value*/
249 	GDMA_InitStruct->MuliBlockCunt = 0;
250 	GDMA_InitStruct->GDMA_ReloadSrc = 0;
251 	GDMA_InitStruct->MaxMuliBlock = 1;
252 	GDMA_InitStruct->GDMA_DIR = TTFCMemToPeri;
253 	GDMA_InitStruct->GDMA_DstHandshakeInterface = AUDIO_DEV_TABLE[Index].Tx_HandshakeInterface;
254 	GDMA_InitStruct->GDMA_DstAddr = (u32)&AUDIO_DEV_TABLE[Index].SPORTx->SP_TX_DR;
255 	GDMA_InitStruct->GDMA_Index = 0;
256 	GDMA_InitStruct->GDMA_ChNum = GdmaChnl;
257 	GDMA_InitStruct->GDMA_IsrType = (BlockType|TransferType|ErrType);
258 	GDMA_InitStruct->GDMA_DstInc = NoChange;
259 	GDMA_InitStruct->GDMA_SrcInc = IncType;
260 
261 	/*  Cofigure GDMA transfer */
262 	if (WordLen == SP_WL_8) {
263 		/*  8bits mode */
264 		if (((Length & 0x03)==0) && (((u32)(pTxData) & 0x03)==0)) {
265 			/*  4-bytes aligned, move 4 bytes each transfer */
266 			GDMA_InitStruct->GDMA_SrcMsize   = MsizeOne;
267 			GDMA_InitStruct->GDMA_SrcDataWidth = TrWidthFourBytes;
268 			GDMA_InitStruct->GDMA_BlockSize = Length >> 2;
269 		} else {
270 			GDMA_InitStruct->GDMA_SrcMsize   = MsizeFour;
271 			GDMA_InitStruct->GDMA_SrcDataWidth = TrWidthOneByte;
272 			GDMA_InitStruct->GDMA_BlockSize = Length;
273 		}
274 		GDMA_InitStruct->GDMA_DstMsize = MsizeFour;
275 		GDMA_InitStruct->GDMA_DstDataWidth = TrWidthOneByte;
276 	} else  {
277 		/*  24bits or 16bits mode */
278 		if (((Length & 0x03)==0) && (((u32)(pTxData) & 0x03)==0)) {
279 			/*  4-bytes aligned, move 4 bytes each transfer */
280 			GDMA_InitStruct->GDMA_SrcMsize   = MsizeFour;
281 			GDMA_InitStruct->GDMA_SrcDataWidth = TrWidthFourBytes;
282 			GDMA_InitStruct->GDMA_BlockSize = Length >> 2;
283 		} else if (((Length & 0x01)==0) && (((u32)(pTxData) & 0x01)==0)) {
284 			/*  2-bytes aligned, move 2 bytes each transfer */
285 			GDMA_InitStruct->GDMA_SrcMsize   = MsizeEight;
286 			GDMA_InitStruct->GDMA_SrcDataWidth = TrWidthTwoBytes;
287 			GDMA_InitStruct->GDMA_BlockSize = Length >> 1;
288 		} else {
289 			DBG_8195A("AUDIO_SP_TXGDMA_Init: Aligment Err: pTxData=0x%x,  Length=%d\n", pTxData, Length);
290 			return _FALSE;
291 		}
292 		GDMA_InitStruct->GDMA_DstMsize = MsizeFour;
293 		GDMA_InitStruct->GDMA_DstDataWidth = TrWidthFourBytes;
294 	}
295 
296 	/*check GDMA block size*/
297 	assert_param(GDMA_InitStruct->GDMA_BlockSize <= 4096);
298 
299 	/*configure GDMA source address */
300 	GDMA_InitStruct->GDMA_SrcAddr = (u32)pTxData;
301 
302 	/*  Enable GDMA for TX */
303 	GDMA_Init(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, GDMA_InitStruct);
304 	DCache_CleanInvalidate((u32)pTxData, Length);
305 	GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, ENABLE);
306 
307 	return _TRUE;
308 }
309 
310 /**
311   * @brief    Initialize GDMA peripheral for receiving data.
312   * @param  Index: 0.
313   * @param  GDMA_InitStruct: pointer to a GDMA_InitTypeDef structure that contains
314   *         the configuration information for the GDMA peripheral.
315   * @param  CallbackData: GDMA callback data.
316   * @param  CallbackFunc: GDMA callback function.
317   * @param  pRxData: Rx Buffer.
318   * @param  Length: Rx Count.
319   * @retval   TRUE/FLASE
320   */
AUDIO_SP_RXGDMA_Init(u32 Index,GDMA_InitTypeDef * GDMA_InitStruct,void * CallbackData,IRQ_FUN CallbackFunc,u8 * pRxData,u32 Length)321 BOOL AUDIO_SP_RXGDMA_Init(
322 	u32 Index,
323 	GDMA_InitTypeDef *GDMA_InitStruct,
324 	void *CallbackData,
325 	IRQ_FUN CallbackFunc,
326 	u8 *pRxData,
327 	u32 Length
328 	)
329 {
330 	u8 GdmaChnl;
331 	AUDIO_SPORT_TypeDef *SPORTx = AUDIO_DEV_TABLE[Index].SPORTx;
332 	u32 WordLen = AUDIO_SP_GetWordLen(SPORTx);
333 
334 	assert_param(GDMA_InitStruct != NULL);
335 	/*obtain a DMA channel and register DMA interrupt handler*/
336 	GdmaChnl = GDMA_ChnlAlloc(0, CallbackFunc, (u32)CallbackData, 12);
337 	if (GdmaChnl == 0xFF) {
338 		// No Available DMA channel
339 		return _FALSE;
340 	}
341 
342 	_memset((void *)GDMA_InitStruct, 0, sizeof(GDMA_InitTypeDef));
343 
344 	/*set GDMA initial structure member value*/
345 	GDMA_InitStruct->MuliBlockCunt = 0;
346 	GDMA_InitStruct->GDMA_ReloadSrc = 0;
347 	GDMA_InitStruct->MaxMuliBlock = 1;
348 	GDMA_InitStruct->GDMA_DIR = TTFCPeriToMem;
349 	GDMA_InitStruct->GDMA_SrcHandshakeInterface = AUDIO_DEV_TABLE[Index].Rx_HandshakeInterface;
350 	GDMA_InitStruct->GDMA_SrcAddr = (u32)&AUDIO_DEV_TABLE[Index].SPORTx->SP_RX_DR;
351 	GDMA_InitStruct->GDMA_Index = 0;
352 	GDMA_InitStruct->GDMA_ChNum = GdmaChnl;
353 	GDMA_InitStruct->GDMA_IsrType = (BlockType|TransferType|ErrType);
354 	GDMA_InitStruct->GDMA_DstInc = IncType;
355 	GDMA_InitStruct->GDMA_SrcInc = NoChange;
356 
357 	/*  Cofigure GDMA transfer */
358 	if (WordLen == SP_WL_8)  {
359 		GDMA_InitStruct->GDMA_SrcDataWidth = TrWidthOneByte;
360 		GDMA_InitStruct->GDMA_SrcMsize = MsizeFour;
361 
362 		GDMA_InitStruct->GDMA_DstMsize = MsizeOne;
363 		GDMA_InitStruct->GDMA_DstDataWidth = TrWidthFourBytes;
364 		GDMA_InitStruct->GDMA_BlockSize = Length;
365 	} else {
366 		GDMA_InitStruct->GDMA_SrcDataWidth = TrWidthFourBytes;
367 		GDMA_InitStruct->GDMA_SrcMsize = MsizeEight;
368 
369 		GDMA_InitStruct->GDMA_DstMsize = MsizeEight;
370 		GDMA_InitStruct->GDMA_DstDataWidth = TrWidthFourBytes;
371 		GDMA_InitStruct->GDMA_BlockSize = Length >> 2;
372 	}
373 
374 	/*check GDMA block size*/
375 	assert_param(GDMA_InitStruct->GDMA_BlockSize <= 4096);
376 
377 	/*configure GDMA destination address */
378 	GDMA_InitStruct->GDMA_DstAddr = (u32)pRxData;
379 
380 	/*  Enable GDMA for RX */
381 	GDMA_Init(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, GDMA_InitStruct);
382 	DCache_CleanInvalidate((u32)pRxData, Length);
383 	GDMA_Cmd(GDMA_InitStruct->GDMA_Index, GDMA_InitStruct->GDMA_ChNum, ENABLE);
384 
385 	return _TRUE;
386 }
387 
388 /**
389   * @brief  Audio GDMA Tx restart in isr
390   * @param  GDMA_Index: GDMA index used in this routine.
391   * @param  GDMA_ChNum: GDMA channel number used in this routine.
392   * @param  tx_addr: Address of data to be sent.
393   * @param  tx_length: Length of data to be sent.
394   * @retval TRUE
395   */
AUDIO_SP_TXGDMA_Restart(u8 GDMA_Index,u8 GDMA_ChNum,u32 tx_addr,u32 tx_length)396 BOOL AUDIO_SP_TXGDMA_Restart(
397 	u8 GDMA_Index,
398 	u8 GDMA_ChNum,
399 	u32 tx_addr,
400 	u32 tx_length
401 	)
402 {
403 	GDMA_SetSrcAddr(GDMA_Index, GDMA_ChNum, tx_addr);
404 	GDMA_SetBlkSize(GDMA_Index, GDMA_ChNum, tx_length>>2);
405 	DCache_CleanInvalidate(tx_addr, tx_length);
406 	GDMA_Cmd(GDMA_Index, GDMA_ChNum, ENABLE);
407 
408 	return _TRUE;
409 }
410 
411 /**
412   * @brief  Audio GDMA Rx restart in isr
413   * @param  GDMA_Index: GDMA index used in this routine.
414   * @param  GDMA_ChNum: GDMA channel number used in this routine.
415   * @param  tx_addr: Address of data to be received.
416   * @param  tx_length: Length of data to be received.
417   * @retval TRUE
418   */
AUDIO_SP_RXGDMA_Restart(u8 GDMA_Index,u8 GDMA_ChNum,u32 rx_addr,u32 rx_length)419 BOOL AUDIO_SP_RXGDMA_Restart(
420 	u8 GDMA_Index,
421 	u8 GDMA_ChNum,
422 	u32 rx_addr,
423 	u32 rx_length
424 	)
425 {
426 	GDMA_SetDstAddr(GDMA_Index, GDMA_ChNum, rx_addr);
427 	GDMA_SetBlkSize(GDMA_Index, GDMA_ChNum, rx_length>>2);
428 	DCache_CleanInvalidate(rx_addr, rx_length);
429 	GDMA_Cmd(GDMA_Index, GDMA_ChNum, ENABLE);
430 
431 	return _TRUE;
432 }
433 /******************* (C) COPYRIGHT 2017 Realtek Semiconductor *****END OF FILE****/
434