1 #include "bflb_platform_dma.h"
2 #include "bflb_l1c.h"
3 #include "hardware/platform_dma_reg.h"
4 
5 struct bflb_platform_dma_env_tag dma_env;
6 
bflb_platform_dma_init(struct bflb_device_s * dev)7 void bflb_platform_dma_init(struct bflb_device_s *dev)
8 {
9     memset(dma_env.last_dma, 0, sizeof(dma_env.last_dma));
10 
11     // configure the channel priorities
12     putreg32(0x0C, dev->reg_base + DMA_ARBITRATION_OFFSET);
13 
14     putreg32(0x04, dev->reg_base + 0x44);
15 
16     // configure the interrupts (enable all interrupts)
17     putreg32(DMA_ERROR_BIT | DMA_LLI_IRQ_MASK, dev->reg_base + DMA_INT_UNMASK_SET_OFFSET);
18 }
19 
bflb_platform_dma_push(struct bflb_device_s * dev,struct bflb_platform_dma_desc * first,struct bflb_platform_dma_desc * last)20 void bflb_platform_dma_push(struct bflb_device_s *dev, struct bflb_platform_dma_desc *first, struct bflb_platform_dma_desc *last)
21 {
22     uint32_t value;
23     uintptr_t flag;
24     uint32_t channel_idx;
25 
26     channel_idx = dev->idx;
27 
28     // current DMA descriptor is pushed at the end of the list
29     last->next = 0;
30 
31     // prevent accesses to the same DMA channel from both BK and IRQ simultaneously
32     flag = bflb_irq_save();
33 
34     // set the MUTEX
35     putreg32(1 << channel_idx, dev->reg_base + DMA_CHANNEL_MUTEX_SET_OFFSET);
36 
37     // read the root in the DMA HW
38     if (channel_idx == 4) {
39         value = getreg32(dev->reg_base + DMA_CH4_LLI_ROOT_OFFSET);
40     } else {
41         value = getreg32(dev->reg_base + DMA_CH_LLI_ROOT_OFFSET + channel_idx * 4);
42     }
43 
44     // check if the root is empty
45     if (value) {
46         // append the descriptor to the last LLI of the list
47         dma_env.last_dma[channel_idx]->next = (uint32_t)first;
48 
49         // clear the MUTEX
50         putreg32(1 << channel_idx, dev->reg_base + DMA_CHANNEL_MUTEX_CLEAR_OFFSET);
51     } else {
52         // write directly the DMA to the root
53         if (channel_idx == 4) {
54             putreg32((uint32_t)first, dev->reg_base + DMA_CH4_LLI_ROOT_OFFSET);
55         } else {
56             putreg32((uint32_t)first, dev->reg_base + DMA_CH_LLI_ROOT_OFFSET + channel_idx * 4);
57         }
58     }
59 
60     // save the new last LLI descriptor on this channel
61     dma_env.last_dma[channel_idx] = last;
62 
63     bflb_irq_restore(flag);
64 }
65 
bflb_platform_dma_buserr_isr(struct bflb_device_s * dev)66 void bflb_platform_dma_buserr_isr(struct bflb_device_s *dev)
67 {
68     // For now consider this error as a fatal one
69     while (1) {
70     }
71 }
72 
bflb_platform_dma_wait_eot(struct bflb_device_s * dev)73 void bflb_platform_dma_wait_eot(struct bflb_device_s *dev)
74 {
75     uint32_t channel_idx;
76 
77     channel_idx = dev->idx;
78     uint32_t stopped = 0;
79     if (channel_idx < 5) {
80         do {
81             stopped = getreg32(dev->reg_base + DMA_INT_RAWSTATUS_OFFSET);
82             stopped = (stopped >> (20 + channel_idx)) & 0x01;
83         } while (!stopped);
84     }
85 }
86 
bflb_platform_dma_clear_eot(struct bflb_device_s * dev)87 void bflb_platform_dma_clear_eot(struct bflb_device_s *dev)
88 {
89     uint32_t channel_idx;
90 
91     channel_idx = dev->idx;
92     if (channel_idx < 5) {
93         putreg32(1 << (20 + channel_idx), dev->reg_base + DMA_INT_ACK_OFFSET);
94     }
95 }