blob: b08448bb0ae4fa13d928ae9b03e560f698b204ab [file] [log] [blame]
Kévin Redon69b92d92019-01-24 16:39:20 +01001
2/**
3 * \file
4 *
5 * \brief Generic DMAC related functionality.
6 *
7 * Copyright (c) 2016-2018 Microchip Technology Inc. and its subsidiaries.
8 *
9 * \asf_license_start
10 *
11 * \page License
12 *
13 * Subject to your compliance with these terms, you may use Microchip
14 * software and any derivatives exclusively with Microchip products.
15 * It is your responsibility to comply with third party license terms applicable
16 * to your use of third party software (including open source software) that
17 * may accompany Microchip software.
18 *
19 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
21 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
22 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
23 * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
24 * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
25 * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
26 * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
27 * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
28 * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
29 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
30 *
31 * \asf_license_stop
32 *
33 */
34#include <hpl_dma.h>
35#include <utils_assert.h>
36#include <utils.h>
37#include <hpl_dmac_config.h>
38#include <utils_repeat_macro.h>
39
40#if CONF_DMAC_ENABLE
41/* Section containing first descriptors for all DMAC channels */
42COMPILER_ALIGNED(16)
43DmacDescriptor _descriptor_section[DMAC_CH_NUM];
44
45/* Section containing current descriptors for all DMAC channels */
46COMPILER_ALIGNED(16)
47DmacDescriptor _write_back_section[DMAC_CH_NUM];
48
49/* Array containing callbacks for DMAC channels */
50static struct _dma_resource _resources[DMAC_CH_NUM];
51
52/* DMAC interrupt handler */
53static void _dmac_handler(void);
54
55/* This macro DMAC configuration */
56#define DMAC_CHANNEL_CFG(i, n) \
57 {(CONF_DMAC_RUNSTDBY_##n << DMAC_CHCTRLA_RUNSTDBY_Pos) | DMAC_CHCTRLA_TRIGACT(CONF_DMAC_TRIGACT_##n) \
58 | DMAC_CHCTRLA_TRIGSRC(CONF_DMAC_TRIGSRC_##n), \
59 DMAC_CHPRILVL_PRILVL(CONF_DMAC_LVL_##n), \
60 (CONF_DMAC_EVIE_##n << DMAC_CHEVCTRL_EVIE_Pos) | (CONF_DMAC_EVOE_##n << DMAC_CHEVCTRL_EVOE_Pos) \
61 | (CONF_DMAC_EVACT_##n << DMAC_CHEVCTRL_EVACT_Pos), \
62 DMAC_BTCTRL_STEPSIZE(CONF_DMAC_STEPSIZE_##n) | (CONF_DMAC_STEPSEL_##n << DMAC_BTCTRL_STEPSEL_Pos) \
63 | (CONF_DMAC_DSTINC_##n << DMAC_BTCTRL_DSTINC_Pos) | (CONF_DMAC_SRCINC_##n << DMAC_BTCTRL_SRCINC_Pos) \
64 | DMAC_BTCTRL_BEATSIZE(CONF_DMAC_BEATSIZE_##n) | DMAC_BTCTRL_BLOCKACT(CONF_DMAC_BLOCKACT_##n) \
65 | DMAC_BTCTRL_EVOSEL(CONF_DMAC_EVOSEL_##n)},
66
67/* DMAC channel configuration */
68struct dmac_channel_cfg {
69 uint32_t ctrla;
70 uint8_t prilvl;
71 uint8_t evctrl;
72 uint16_t btctrl;
73};
74
75/* DMAC channel configurations */
76const static struct dmac_channel_cfg _cfgs[] = {REPEAT_MACRO(DMAC_CHANNEL_CFG, i, DMAC_CH_NUM)};
77
78/**
79 * \brief Initialize DMAC
80 */
81int32_t _dma_init(void)
82{
83 uint8_t i;
84
85 hri_dmac_clear_CTRL_DMAENABLE_bit(DMAC);
86 hri_dmac_clear_CRCCTRL_reg(DMAC, DMAC_CRCCTRL_CRCSRC_Msk);
87 hri_dmac_set_CTRL_SWRST_bit(DMAC);
88 while (hri_dmac_get_CTRL_SWRST_bit(DMAC))
89 ;
90
91 hri_dmac_write_CTRL_reg(DMAC,
92 (CONF_DMAC_LVLEN0 << DMAC_CTRL_LVLEN0_Pos) | (CONF_DMAC_LVLEN1 << DMAC_CTRL_LVLEN1_Pos)
93 | (CONF_DMAC_LVLEN2 << DMAC_CTRL_LVLEN2_Pos)
94 | (CONF_DMAC_LVLEN3 << DMAC_CTRL_LVLEN3_Pos));
95 hri_dmac_write_DBGCTRL_DBGRUN_bit(DMAC, CONF_DMAC_DBGRUN);
96
97 hri_dmac_write_PRICTRL0_reg(
98 DMAC,
99 DMAC_PRICTRL0_LVLPRI0(CONF_DMAC_LVLPRI0) | DMAC_PRICTRL0_LVLPRI1(CONF_DMAC_LVLPRI1)
100 | DMAC_PRICTRL0_LVLPRI2(CONF_DMAC_LVLPRI2) | DMAC_PRICTRL0_LVLPRI3(CONF_DMAC_LVLPRI3)
101 | (CONF_DMAC_RRLVLEN0 << DMAC_PRICTRL0_RRLVLEN0_Pos) | (CONF_DMAC_RRLVLEN1 << DMAC_PRICTRL0_RRLVLEN1_Pos)
102 | (CONF_DMAC_RRLVLEN2 << DMAC_PRICTRL0_RRLVLEN2_Pos) | (CONF_DMAC_RRLVLEN3 << DMAC_PRICTRL0_RRLVLEN3_Pos));
103 hri_dmac_write_BASEADDR_reg(DMAC, (uint32_t)_descriptor_section);
104 hri_dmac_write_WRBADDR_reg(DMAC, (uint32_t)_write_back_section);
105
106 for (i = 0; i < DMAC_CH_NUM; i++) {
107 hri_dmac_write_CHCTRLA_reg(DMAC, i, _cfgs[i].ctrla);
108 hri_dmac_write_CHPRILVL_reg(DMAC, i, _cfgs[i].prilvl);
109 hri_dmac_write_CHEVCTRL_reg(DMAC, i, _cfgs[i].evctrl);
110 hri_dmacdescriptor_write_BTCTRL_reg(&_descriptor_section[i], _cfgs[i].btctrl);
Kévin Redona562a142019-04-17 02:21:00 +0200111 hri_dmacdescriptor_write_DESCADDR_reg(&_descriptor_section[i], 0x0);
Kévin Redon69b92d92019-01-24 16:39:20 +0100112 }
113
114 for (i = 0; i < 5; i++) {
115 NVIC_DisableIRQ(DMAC_0_IRQn + i);
116 NVIC_ClearPendingIRQ(DMAC_0_IRQn + i);
117 NVIC_EnableIRQ(DMAC_0_IRQn + i);
118 }
119
120 hri_dmac_set_CTRL_DMAENABLE_bit(DMAC);
121
122 return ERR_NONE;
123}
124
125/**
126 * \brief Enable/disable DMA interrupt
127 */
128void _dma_set_irq_state(const uint8_t channel, const enum _dma_callback_type type, const bool state)
129{
130 if (DMA_TRANSFER_COMPLETE_CB == type) {
131 hri_dmac_write_CHINTEN_TCMPL_bit(DMAC, channel, state);
132 } else if (DMA_TRANSFER_ERROR_CB == type) {
133 hri_dmac_write_CHINTEN_TERR_bit(DMAC, channel, state);
134 }
135}
136
137int32_t _dma_set_destination_address(const uint8_t channel, const void *const dst)
138{
139 hri_dmacdescriptor_write_DSTADDR_reg(&_descriptor_section[channel], (uint32_t)dst);
140
141 return ERR_NONE;
142}
143
144int32_t _dma_set_source_address(const uint8_t channel, const void *const src)
145{
146 hri_dmacdescriptor_write_SRCADDR_reg(&_descriptor_section[channel], (uint32_t)src);
147
148 return ERR_NONE;
149}
150
151int32_t _dma_set_next_descriptor(const uint8_t current_channel, const uint8_t next_channel)
152{
153 hri_dmacdescriptor_write_DESCADDR_reg(&_descriptor_section[current_channel],
154 (uint32_t)&_descriptor_section[next_channel]);
155
156 return ERR_NONE;
157}
158
159int32_t _dma_srcinc_enable(const uint8_t channel, const bool enable)
160{
161 hri_dmacdescriptor_write_BTCTRL_SRCINC_bit(&_descriptor_section[channel], enable);
162
163 return ERR_NONE;
164}
165
166int32_t _dma_set_data_amount(const uint8_t channel, const uint32_t amount)
167{
168 uint32_t address = hri_dmacdescriptor_read_DSTADDR_reg(&_descriptor_section[channel]);
169 uint8_t beat_size = hri_dmacdescriptor_read_BTCTRL_BEATSIZE_bf(&_descriptor_section[channel]);
170
171 if (hri_dmacdescriptor_get_BTCTRL_DSTINC_bit(&_descriptor_section[channel])) {
172 hri_dmacdescriptor_write_DSTADDR_reg(&_descriptor_section[channel], address + amount * (1 << beat_size));
173 }
174
175 address = hri_dmacdescriptor_read_SRCADDR_reg(&_descriptor_section[channel]);
176
177 if (hri_dmacdescriptor_get_BTCTRL_SRCINC_bit(&_descriptor_section[channel])) {
178 hri_dmacdescriptor_write_SRCADDR_reg(&_descriptor_section[channel], address + amount * (1 << beat_size));
179 }
180
181 hri_dmacdescriptor_write_BTCNT_reg(&_descriptor_section[channel], amount);
182
183 return ERR_NONE;
184}
185
186int32_t _dma_enable_transaction(const uint8_t channel, const bool software_trigger)
187{
188 hri_dmacdescriptor_set_BTCTRL_VALID_bit(&_descriptor_section[channel]);
189 hri_dmac_set_CHCTRLA_ENABLE_bit(DMAC, channel);
190
191 if (software_trigger) {
192 hri_dmac_set_SWTRIGCTRL_reg(DMAC, 1 << channel);
193 }
194
195 return ERR_NONE;
196}
197
198int32_t _dma_get_channel_resource(struct _dma_resource **resource, const uint8_t channel)
199{
200 *resource = &_resources[channel];
201
202 return ERR_NONE;
203}
204
205int32_t _dma_dstinc_enable(const uint8_t channel, const bool enable)
206{
207 hri_dmacdescriptor_write_BTCTRL_DSTINC_bit(&_descriptor_section[channel], enable);
208
209 return ERR_NONE;
210}
211/**
212 * \internal DMAC interrupt handler
213 */
214static void _dmac_handler(void)
215{
216 uint8_t channel = hri_dmac_get_INTPEND_reg(DMAC, DMAC_INTPEND_ID_Msk);
217 struct _dma_resource *tmp_resource = &_resources[channel];
218
219 if (hri_dmac_get_CHINTFLAG_TERR_bit(DMAC, channel)) {
220 hri_dmac_clear_CHINTFLAG_TERR_bit(DMAC, channel);
221 tmp_resource->dma_cb.error(tmp_resource);
222 } else if (hri_dmac_get_CHINTFLAG_TCMPL_bit(DMAC, channel)) {
223 hri_dmac_clear_CHINTFLAG_TCMPL_bit(DMAC, channel);
224 tmp_resource->dma_cb.transfer_done(tmp_resource);
225 }
226}
227/**
228 * \brief DMAC interrupt handler
229 */
230void DMAC_0_Handler(void)
231{
232 _dmac_handler();
233}
234/**
235 * \brief DMAC interrupt handler
236 */
237void DMAC_1_Handler(void)
238{
239 _dmac_handler();
240}
241/**
242 * \brief DMAC interrupt handler
243 */
244void DMAC_2_Handler(void)
245{
246 _dmac_handler();
247}
248/**
249 * \brief DMAC interrupt handler
250 */
251void DMAC_3_Handler(void)
252{
253 _dmac_handler();
254}
255/**
256 * \brief DMAC interrupt handler
257 */
258void DMAC_4_Handler(void)
259{
260 _dmac_handler();
261}
262
263#endif /* CONF_DMAC_ENABLE */