diff options
Diffstat (limited to 'firmware/target/arm/imx233/dma-imx233.c')
-rw-r--r-- | firmware/target/arm/imx233/dma-imx233.c | 48 |
1 files changed, 47 insertions, 1 deletions
diff --git a/firmware/target/arm/imx233/dma-imx233.c b/firmware/target/arm/imx233/dma-imx233.c index d75c334aeb..8a42bd12da 100644 --- a/firmware/target/arm/imx233/dma-imx233.c +++ b/firmware/target/arm/imx233/dma-imx233.c | |||
@@ -106,8 +106,54 @@ bool imx233_dma_is_channel_error_irq(unsigned chan) | |||
106 | HW_APBH_CTRL2__CHx_ERROR_IRQ(APB_GET_DMA_CHANNEL(chan))); | 106 | HW_APBH_CTRL2__CHx_ERROR_IRQ(APB_GET_DMA_CHANNEL(chan))); |
107 | } | 107 | } |
108 | 108 | ||
109 | /* Commit and/or discard all DMA descriptors and buffers pointed by them, | ||
110 | * handle circular lists */ | ||
111 | static void imx233_dma_commit_and_discard(struct apb_dma_command_t *cmd) | ||
112 | { | ||
113 | /* We handle circular descriptors by using unused bits: | ||
114 | * bits 8-11 are not used by the hardware so we first go through the whole | ||
115 | * list and mark them all a special value at the same time we commit buffers | ||
116 | * and then we go through the list another time to clear the mark and | ||
117 | * commit the descriptors */ | ||
118 | struct apb_dma_command_t *cur = cmd; | ||
119 | |||
120 | while((cur->cmd & HW_APB_CHx_CMD__UNUSED_BM) != HW_APB_CHx_CMD__UNUSED_MAGIC) | ||
121 | { | ||
122 | cur->cmd = (cur->cmd & ~HW_APB_CHx_CMD__UNUSED_BM) | HW_APB_CHx_CMD__UNUSED_MAGIC; | ||
123 | int op = cur->cmd & HW_APB_CHx_CMD__COMMAND_BM; | ||
124 | int sz = (cur->cmd & HW_APB_CHx_CMD__XFER_COUNT_BM) >> HW_APB_CHx_CMD__XFER_COUNT_BP; | ||
125 | /* device > host: discard */ | ||
126 | if(op == HW_APB_CHx_CMD__COMMAND__WRITE) | ||
127 | discard_dcache_range(cur->buffer, sz); | ||
128 | /* host > device: commit and discard */ | ||
129 | else if(op == HW_APB_CHx_CMD__COMMAND__READ) | ||
130 | commit_discard_dcache_range(cur->buffer, sz); | ||
131 | /* chain ? */ | ||
132 | if(cur->cmd & HW_APB_CHx_CMD__CHAIN) | ||
133 | cur = cur->next; | ||
134 | else | ||
135 | break; | ||
136 | } | ||
137 | |||
138 | cur = cmd; | ||
139 | while((cur->cmd & HW_APB_CHx_CMD__UNUSED_BM) != 0) | ||
140 | { | ||
141 | cur->cmd = cur->cmd & ~HW_APB_CHx_CMD__UNUSED_BM; | ||
142 | int sz = (cur->cmd & HW_APB_CHx_CMD__CMDWORDS_BM) >> HW_APB_CHx_CMD__CMDWORDS_BP; | ||
143 | /* commit descriptor (don't discard since we access it after) */ | ||
144 | commit_dcache_range(cur, | ||
145 | sizeof(struct apb_dma_command_t) + sizeof(uint32_t) * sz); | ||
146 | /* chain ? */ | ||
147 | if(cur->cmd & HW_APB_CHx_CMD__CHAIN) | ||
148 | cur = cur->next; | ||
149 | else | ||
150 | break; | ||
151 | } | ||
152 | } | ||
153 | |||
109 | void imx233_dma_start_command(unsigned chan, struct apb_dma_command_t *cmd) | 154 | void imx233_dma_start_command(unsigned chan, struct apb_dma_command_t *cmd) |
110 | { | 155 | { |
156 | imx233_dma_commit_and_discard(cmd); | ||
111 | if(APB_IS_APBX_CHANNEL(chan)) | 157 | if(APB_IS_APBX_CHANNEL(chan)) |
112 | { | 158 | { |
113 | HW_APBX_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)cmd; | 159 | HW_APBX_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)cmd; |
@@ -129,5 +175,5 @@ void imx233_dma_wait_completion(unsigned chan) | |||
129 | sema = &HW_APBH_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)); | 175 | sema = &HW_APBH_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)); |
130 | 176 | ||
131 | while(*sema & HW_APB_CHx_SEMA__PHORE_BM) | 177 | while(*sema & HW_APB_CHx_SEMA__PHORE_BM) |
132 | ; | 178 | yield(); |
133 | } | 179 | } |