aboutsummaryrefslogtreecommitdiff
path: root/src/mcu/peripheral/rtl876x_gdma.c
blob: 1d8601d1ed7321bfb5e00767b693f8331e9f90ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
/**
*********************************************************************************************************
*               Copyright(c) 2020, Realtek Semiconductor Corporation. All rights reserved.
**********************************************************************************************************
* @file     rtl876x_gdma.c
* @brief    This file provides all the DMA firmware functions.
* @details
* @author   Yuan
* @date     2020-11-09
* @version  v1.0.1
*********************************************************************************************************
*/

/* Includes ------------------------------------------------------------------*/
#include "rtl876x_rcc.h"
#include "rtl876x_gdma.h"

/*fifo depth*/
#define UART_RX_FIFO_DEPTH      32
#define UART_TX_FIFO_DEPTH      16
#define SPI_RX_FIFO_DEPTH       36
#define SPI_TX_FIFO_DEPTH       36
#define I2C_RX_FIFO_DEPTH       16
#define I2C_TX_FIFO_DEPTH       24

#define REG_GDMA_TIMER          *((volatile uint32_t *)0x40006024UL)

/**
  * @brief  Deinitializes the GDMA registers to their default reset values.
  * @param  None
  * @return None
  */
void GDMA_DeInit(void)
{
    /* Disable GDMA block in REG_SOC_FUNC_EN */
    RCC_PeriphClockCmd(APBPeriph_GDMA, APBPeriph_GDMA_CLOCK, DISABLE);
}

/**
  * @brief  Initializes the GDMA Channelx according to the specified
  *         parameters in the GDMA_InitStruct.
  * @param  GDMA_Channelx: where x can be 0 to 3  to select the DMA Channel.
  * @param  GDMA_InitStruct: pointer to a GDMA_InitTypeDef structure that
  *         contains the configuration information for the specified DMA Channel.
  * @return None
  */
void GDMA_Init(GDMA_ChannelTypeDef *GDMA_Channelx, GDMA_InitTypeDef *GDMA_InitStruct)
{
    uint32_t temp_bit = 0;
    uint32_t autoreload_temp;
    uint32_t llp_temp;

    /* Check the parameters */
    assert_param(IS_GDMA_ALL_PERIPH(GDMA_Channelx));
    assert_param(IS_GDMA_ChannelNum(GDMA_InitStruct->GDMA_ChannelNum));
    assert_param(IS_GDMA_DIR(GDMA_InitStruct->GDMA_DIR));
    assert_param(IS_GDMA_SourceInc(GDMA_InitStruct->GDMA_SourceInc));
    assert_param(IS_GDMA_DestinationInc(GDMA_InitStruct->GDMA_DestinationInc));
    assert_param(IS_GDMA_DATA_SIZE(GDMA_InitStruct->GDMA_SourceDataSize));
    assert_param(IS_GDMA_DATA_SIZE(GDMA_InitStruct->GDMA_DestinationDataSize));

    /*------------------configure source and destination address of GDMA---------*/
    /* program SARx register to set source address */
    GDMA_Channelx->SAR = GDMA_InitStruct->GDMA_SourceAddr;
    /* program DARx register to set destination address */
    GDMA_Channelx->DAR = GDMA_InitStruct->GDMA_DestinationAddr;

    /* Enable GDMA in DmaCfgReg*/
    GDMA_BASE->DmaCfgReg = 0x01;

    /* read ChEnReg to check channel is busy or not */
    if (GDMA_BASE->ChEnReg & BIT(GDMA_InitStruct->GDMA_ChannelNum))
    {
        //channel is be used
        //error handle code
        //while (1);
    }

    /*--------------------------- GDMA Configuration -----------------*/
    /* clear pending interrupts of corresponding GDMA channel */
    temp_bit = BIT(GDMA_InitStruct->GDMA_ChannelNum);
    GDMA_BASE->CLEAR_TFR |= temp_bit;
    GDMA_BASE->CLEAR_BLOCK |= temp_bit;
    GDMA_BASE->CLEAR_DST_TRAN |= temp_bit;
    GDMA_BASE->CLEAR_SRC_TRAN |= temp_bit;
    GDMA_BASE->CLEAR_ERR |= temp_bit;

    /* mask pending interrupts of corresponding GDMA channel */
    temp_bit = BIT(GDMA_InitStruct->GDMA_ChannelNum + 8);
    GDMA_BASE->MASK_TFR = temp_bit;
    GDMA_BASE->MASK_BLOCK = temp_bit;
    GDMA_BASE->MASK_DST_TRAN = temp_bit;
    GDMA_BASE->MASK_SRC_TRAN = temp_bit;
    GDMA_BASE->MASK_ERR = temp_bit;

    /*---------------------------- configure CTL register --------------------------------*/

    /* configure low 32 bit of CTL register */
    GDMA_Channelx->CTL_LOW = BIT(0)
                             | (GDMA_InitStruct->GDMA_DestinationDataSize << 1)
                             | (GDMA_InitStruct->GDMA_SourceDataSize << 4)
                             | (GDMA_InitStruct->GDMA_DestinationInc << 7)
                             | (GDMA_InitStruct->GDMA_SourceInc << 9)
                             | (GDMA_InitStruct->GDMA_DestinationMsize << 11)
                             | (GDMA_InitStruct->GDMA_SourceMsize << 14)
                             | (GDMA_InitStruct->GDMA_DIR << 20);
    /* configure high 32 bit of CTL register */
    GDMA_Channelx->CTL_HIGH = GDMA_InitStruct->GDMA_BufferSize;

    /*---------------------------- configure CFG register --------------------------------*/

    switch (GDMA_InitStruct->GDMA_DIR)
    {
    case GDMA_DIR_MemoryToMemory:
        GDMA_Channelx->CFG_LOW = (0x03 << 10);
        break;
    case GDMA_DIR_MemoryToPeripheral:
        GDMA_Channelx->CFG_LOW = BIT11;
        break;
    case GDMA_DIR_PeripheralToMemory:
        GDMA_Channelx->CFG_LOW = BIT10;
        break;
    case GDMA_DIR_PeripheralToPeripheral:
        GDMA_Channelx->CFG_LOW = 0;
        break;
    default:
        GDMA_Channelx->CFG_LOW = 0;
        break;
    }

    if (GDMA_InitStruct->GDMA_Multi_Block_En == 1 &&
        ((GDMA_Channelx == GDMA_Channel0) | (GDMA_Channelx == GDMA_Channel1)))
    {
        /* Config multi-block mode */
        GDMA_Channelx->CFG_LOW &= ~AUTO_RELOAD_SELECTED_BIT;
        GDMA_Channelx->CTL_LOW &= ~LLP_SELECTED_BIT;
        autoreload_temp = (GDMA_InitStruct->GDMA_Multi_Block_Mode & AUTO_RELOAD_SELECTED_BIT);
        llp_temp = (GDMA_InitStruct->GDMA_Multi_Block_Mode & LLP_SELECTED_BIT);
        if (llp_temp)
        {
            GDMA_Channelx->LLP = GDMA_InitStruct->GDMA_Multi_Block_Struct;
            GDMA_Channelx->CTL_LOW |= llp_temp;
        }
        GDMA_Channelx->CFG_LOW |= autoreload_temp;
    }

    /* Set Vendor register about timer handshake */
    if ((GDMA_InitStruct->GDMA_DestHandshake == 2) || (GDMA_InitStruct->GDMA_DestHandshake == 3))
    {
        REG_GDMA_TIMER |= BIT(GDMA_InitStruct->GDMA_DestHandshake + 20);
    }
    else if ((GDMA_InitStruct->GDMA_DestHandshake >= 24) && (GDMA_InitStruct->GDMA_DestHandshake <= 26))
    {
        REG_GDMA_TIMER |= BIT(GDMA_InitStruct->GDMA_DestHandshake - 8);
    }
    else if ((GDMA_InitStruct->GDMA_DestHandshake >= 29) && (GDMA_InitStruct->GDMA_DestHandshake <= 31))
    {
        REG_GDMA_TIMER |= BIT(GDMA_InitStruct->GDMA_DestHandshake - 10);
    }

    /* configure peripheral parameters and configure source or destination hardware handshaking interface */
    GDMA_Channelx->CFG_HIGH &=  ~(0x03ff << 7);

    GDMA_Channelx->CFG_HIGH |= (((((GDMA_InitStruct->GDMA_SourceHandshake) & 0x10) << 4) \
                                 | ((GDMA_InitStruct->GDMA_SourceHandshake) & 0x0f)) << 7);
    GDMA_Channelx->CFG_HIGH |= (((((GDMA_InitStruct->GDMA_DestHandshake) & 0x10) << 1) \
                                 | ((GDMA_InitStruct->GDMA_DestHandshake) & 0x0f)) << 11);

    /* Enable FIFO mode and Flow control mode */
    GDMA_Channelx->CFG_HIGH &= ~0x03;
    GDMA_Channelx->CFG_HIGH |= 0x02;

    /* ---------------clear pending interrupts of corresponding GDMA channel------------------ */
    temp_bit = BIT(GDMA_InitStruct->GDMA_ChannelNum);
    GDMA_BASE->CLEAR_TFR |= temp_bit;
    GDMA_BASE->CLEAR_BLOCK |= temp_bit;
    GDMA_BASE->CLEAR_DST_TRAN |= temp_bit;
    GDMA_BASE->CLEAR_SRC_TRAN |= temp_bit;
    GDMA_BASE->CLEAR_ERR |= temp_bit;
}

/**
  * @brief  Fills each GDMA_InitStruct member with its default value.
  * @param  GDMA_InitStruct : pointer to a GDMA_InitTypeDef structure which will
  *         be initialized.
  * @return None
  */
void GDMA_StructInit(GDMA_InitTypeDef *GDMA_InitStruct)
{
    /*-------------- Reset DMA init structure parameters values ------------------*/
    GDMA_InitStruct->GDMA_ChannelNum      = 0;
    GDMA_InitStruct->GDMA_DIR             = GDMA_DIR_PeripheralToMemory;
    GDMA_InitStruct->GDMA_BufferSize      = 200;
    GDMA_InitStruct->GDMA_SourceInc       = DMA_SourceInc_Fix;
    GDMA_InitStruct->GDMA_DestinationInc  = DMA_DestinationInc_Inc;
    GDMA_InitStruct->GDMA_SourceDataSize  = GDMA_DataSize_Byte;
    GDMA_InitStruct->GDMA_DestinationDataSize   = GDMA_DataSize_Byte;
    GDMA_InitStruct->GDMA_SourceMsize           = GDMA_Msize_1;
    GDMA_InitStruct->GDMA_DestinationMsize      = GDMA_Msize_1;
    GDMA_InitStruct->GDMA_SourceAddr      = 0;
    GDMA_InitStruct->GDMA_DestinationAddr = 0;
    GDMA_InitStruct->GDMA_SourceHandshake = 0;
    GDMA_InitStruct->GDMA_DestHandshake   = 0;
    GDMA_InitStruct->GDMA_ChannelPriority = 0;

    GDMA_InitStruct->GDMA_Multi_Block_En   = DISABLE;
    GDMA_InitStruct->GDMA_Multi_Block_Mode = LLI_TRANSFER;
}

/**
  * @brief  Enables or disables the specified GDMA Channelx.
  * @param  GDMA_Channelx: x can be 0 to 3 to select the DMA Channel.
  * @param  NewState: new state of the DMA Channelx.
  *         This parameter can be: ENABLE or DISABLE.
  * @return None
  */
void GDMA_Cmd(uint8_t GDMA_ChannelNum, FunctionalState NewState)
{
    /* Check the parameters */
    assert_param(IS_GDMA_ChannelNum(GDMA_ChannelNum));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    GDMA_ChannelTypeDef *GDMA_Channelx;
    GDMA_Channelx = (GDMA_ChannelTypeDef *)DMA_CH_BASE(GDMA_ChannelNum);

    uint8_t bit_need_set_times = 10;
    uint8_t bit_need_check_times = 50;
    uint8_t timeout = bit_need_check_times ;
    uint8_t bit_set_time = 0;

    if (NewState != DISABLE)
    {
        /* Enable the selected DMAy Channelx */
        GDMA_BASE->ChEnReg |= BIT(GDMA_ChannelNum) | BIT(GDMA_ChannelNum + 8);
    }
    else
    {
        /*gdma transfor not finished */
        if (GDMA_BASE->ChEnReg & BIT(GDMA_ChannelNum))
            /* suspend gdma channel */
        {
            GDMA_Channelx->CFG_LOW |= GDMA_SUSPEND_TRANSMISSSION;
        }
        /* Disable the selected DMAy Channelx */
        /* polling fifo empty */
        while ((GDMA_GetSuspendChannelStatus(GDMA_Channelx) != SET) && --timeout);
        /*cfg bit0 not set */
        if (GDMA_GetSuspendChannelStatus(GDMA_Channelx) != SET)
        {
            timeout = bit_need_check_times;
            /*polling cfg[1:2] 10 times set in 100timer check */
            while (--timeout)
            {
                if ((GDMA_Channelx->CFG_LOW & BIT1) && (GDMA_Channelx->CFG_LOW & BIT2))
                {
                    bit_set_time++;
                    if (bit_set_time >= bit_need_set_times)
                    {
                        break;
                    }
                }
            }
//              if (timeout == 0)
//              {
//                  /*abort disable dma return fail*/
//                  return GDMA_DISABLE_FAIL;
//              }
        }

        /* Disable the selected DMAy Channelx */
        GDMA_BASE->ChEnReg = BIT(GDMA_ChannelNum + 8);
        /* unsuspend dma channel */
        GDMA_Channelx->CFG_LOW &= ~(GDMA_SUSPEND_TRANSMISSSION);
    }
}

/**
  * @brief  Enables or disables the specified DMA Channelx interrupts.
  * @param  GDMA_Channelx: where x can be 0 to 3 to select the GDMA Channel.
  * @param  GDMA_IT: specifies the GDMA interrupts sources to be enabled or disabled.
  *         This parameter can be any combination of the following values:
  *         @arg GDMA_INT_Transfer:  Transfer complete interrupt unmask
  *         @arg GDMA_INT_Block:  Block transfer interrupt unmask
  *         @arg GDMA_INT_SrcTransfer:  SourceTransfer interrupt unmask
  *         @arg GDMA_INT_DstTransfer:  Destination Transfer interrupt unmask
  *         @arg GDMA_INT_Error:  Transfer error interrupt unmask
  * @param  NewState: new state of the specified DMA interrupts.
  *         This parameter can be: ENABLE or DISABLE.
  * @return None
  */
void GDMA_INTConfig(uint8_t GDMA_ChannelNum, uint32_t GDMA_IT, FunctionalState NewState)
{
    uint32_t temp_bit = 0;

    /* Check the parameters */
    assert_param(IS_GDMA_ChannelNum(GDMA_ChannelNum));
    assert_param(IS_GDMA_CONFIG_IT(GDMA_IT));
    assert_param(IS_FUNCTIONAL_STATE(NewState));

    if (NewState != DISABLE)
    {
        /* Enable the selected DMA interrupts */
        temp_bit = BIT(GDMA_ChannelNum) | BIT(GDMA_ChannelNum + 8);

        if (GDMA_IT & GDMA_INT_Transfer)
        {
            GDMA_BASE->MASK_TFR |= temp_bit;
        }
        if (GDMA_IT & GDMA_INT_Block)
        {
            GDMA_BASE->MASK_BLOCK |= temp_bit;
        }
        if (GDMA_IT & GDMA_INT_SrcTransfer)
        {
            GDMA_BASE->MASK_SRC_TRAN |= temp_bit;
        }
        if (GDMA_IT & GDMA_INT_DstTransfer)
        {
            GDMA_BASE->MASK_DST_TRAN |= temp_bit;
        }
        if (GDMA_IT & GDMA_INT_Error)
        {
            GDMA_BASE->MASK_ERR |= temp_bit;
        }
    }
    else
    {
        /* Disable the selected DMA interrupts */
        temp_bit = BIT(GDMA_ChannelNum + 8);
        if (GDMA_IT & GDMA_INT_Transfer)
        {
            GDMA_BASE->MASK_TFR = temp_bit;
        }
        if (GDMA_IT & GDMA_INT_Block)
        {
            GDMA_BASE->MASK_BLOCK = temp_bit;
        }
        if (GDMA_IT & GDMA_INT_SrcTransfer)
        {
            GDMA_BASE->MASK_SRC_TRAN = temp_bit;
        }
        if (GDMA_IT & GDMA_INT_DstTransfer)
        {
            GDMA_BASE->MASK_DST_TRAN = temp_bit;
        }
        if (GDMA_IT & GDMA_INT_Error)
        {
            GDMA_BASE->MASK_ERR = temp_bit;
        }
    }
}

/**
  * @brief  Enables or disables the specified DMA Channelx interrupts.
  * @param  GDMA_Channelx: where x can be 0 to 3 to select the GDMA Channel.
  * @param  GDMA_IT: specifies the GDMA interrupts sources to be enabled
  *   or disabled.
  *   This parameter can be any combination of the following values:
  *     @arg GDMA_INT_Transfer:  clear transfer complete interrupt
  *     @arg GDMA_INT_Block:  clear Block transfer interrupt
  *     @arg GDMA_INT_SrcTransfer:  clear SourceTransfer interrupt
  *     @arg GDMA_INT_DstTransfer:  clear Destination Transfer interrupt
  *     @arg GDMA_INT_Error:  clear Transfer error interrupt
  * @param  NewState: new state of the specified DMA interrupts.
  *   This parameter can be: ENABLE or DISABLE.
  * @return None
  */
void GDMA_ClearINTPendingBit(uint8_t GDMA_ChannelNum, uint32_t GDMA_IT)
{
    uint32_t temp_bit = 0;

    /* Check the parameters */
    assert_param(IS_GDMA_ChannelNum(GDMA_ChannelNum));
    assert_param(IS_GDMA_CONFIG_IT(GDMA_IT));

    /* clear the selected DMA interrupts */
    //temp_bit = BIT(GDMA_ChannelNum) | BIT(GDMA_ChannelNum + 8);
    temp_bit = BIT(GDMA_ChannelNum);

    if (GDMA_IT & GDMA_INT_Transfer)
    {
        GDMA_BASE->CLEAR_TFR = temp_bit;
    }
    if (GDMA_IT & GDMA_INT_Block)
    {
        GDMA_BASE->CLEAR_BLOCK = temp_bit;
    }
    if (GDMA_IT & GDMA_INT_SrcTransfer)
    {
        GDMA_BASE->CLEAR_SRC_TRAN = temp_bit;
    }
    if (GDMA_IT & GDMA_INT_DstTransfer)
    {
        GDMA_BASE->CLEAR_DST_TRAN = temp_bit;
    }
    if (GDMA_IT & GDMA_INT_Error)
    {
        GDMA_BASE->CLEAR_ERR = temp_bit;
    }
}

/******************* (C) COPYRIGHT 2020 Realtek Semiconductor Corporation *****END OF FILE****/