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 }