1 
2 /**
3  * \file
4  *
5  * \brief Generic DMAC related functionality.
6  *
7  * Copyright (C) 2016 - 2017 Atmel Corporation. All rights reserved.
8  *
9  * \asf_license_start
10  *
11  * \page License
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions are met:
15  *
16  * 1. Redistributions of source code must retain the above copyright notice,
17  *    this list of conditions and the following disclaimer.
18  *
19  * 2. Redistributions in binary form must reproduce the above copyright notice,
20  *    this list of conditions and the following disclaimer in the documentation
21  *    and/or other materials provided with the distribution.
22  *
23  * 3. The name of Atmel may not be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * 4. This software may only be redistributed and used in connection with an
27  *    Atmel microcontroller product.
28  *
29  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
30  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
31  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
32  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
33  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
38  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39  * POSSIBILITY OF SUCH DAMAGE.
40  *
41  * \asf_license_stop
42  *
43  */
44 #include <compiler.h>
45 #include <hpl_dma.h>
46 #include <hpl_dmac_config.h>
47 #include <utils.h>
48 #include <utils_assert.h>
49 #include <utils_repeat_macro.h>
50 
51 #if CONF_DMAC_ENABLE
52 
53 #ifndef SECTION_DMAC_DESCRIPTOR
54 #define SECTION_DMAC_DESCRIPTOR
55 #warning Please double confirm if your DMA descriptor needs specific RAM
56 #endif
57 
58 /* Section containing first descriptors for all DMAC channels */
59 COMPILER_ALIGNED(16)
60 static DmacDescriptor _descriptor_section[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR;
61 
62 /* Section containing current descriptors for all DMAC channels */
63 COMPILER_ALIGNED(16)
64 static DmacDescriptor _write_back_section[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR;
65 
66 /* Array containing callbacks for DMAC channels */
67 static struct _dma_resource _resources[DMAC_CH_NUM];
68 
69 /* This macro DMAC configuration */
70 #define DMAC_CHANNEL_CFG(i, n)                                                                                         \
71 	{(CONF_DMAC_RUNSTDBY_##n << DMAC_CHCTRLA_RUNSTDBY_Pos) | (CONF_DMAC_ENABLE_##n << DMAC_CHCTRLA_ENABLE_Pos),        \
72 	 DMAC_CHCTRLB_TRIGACT(CONF_DMAC_TRIGACT_##n) | DMAC_CHCTRLB_TRIGSRC(CONF_DMAC_TRIGSRC_##n)                         \
73 	     | DMAC_CHCTRLB_LVL(CONF_DMAC_LVL_##n)                                                                         \
74 	     | (CONF_DMAC_EVOE_##n << DMAC_CHCTRLB_EVOE_Pos)                                                               \
75 	     | (CONF_DMAC_EVIE_##n << DMAC_CHCTRLB_EVIE_Pos)                                                               \
76 	     | DMAC_CHCTRLB_EVACT(CONF_DMAC_EVACT_##n),                                                                    \
77 	 DMAC_BTCTRL_STEPSIZE(CONF_DMAC_STEPSIZE_##n) | (CONF_DMAC_STEPSEL_##n << DMAC_BTCTRL_STEPSEL_Pos)                 \
78 	     | (CONF_DMAC_DSTINC_##n << DMAC_BTCTRL_DSTINC_Pos)                                                            \
79 	     | (CONF_DMAC_SRCINC_##n << DMAC_BTCTRL_SRCINC_Pos)                                                            \
80 	     | DMAC_BTCTRL_BEATSIZE(CONF_DMAC_BEATSIZE_##n)                                                                \
81 	     | DMAC_BTCTRL_BLOCKACT(CONF_DMAC_BLOCKACT_##n)                                                                \
82 	     | DMAC_BTCTRL_EVOSEL(CONF_DMAC_EVOSEL_##n)},
83 
84 /* DMAC channel configuration */
85 struct dmac_channel_cfg {
86 	uint8_t  ctrla;
87 	uint32_t ctrlb;
88 	uint16_t btctrl;
89 };
90 
91 /* DMAC channel configurations */
92 const static struct dmac_channel_cfg _cfgs[] = {REPEAT_MACRO(DMAC_CHANNEL_CFG, i, DMAC_CH_NUM)};
93 
94 /**
95  * \brief Initialize DMAC
96  */
_dma_init(void)97 int32_t _dma_init(void)
98 {
99 	uint8_t i = 0;
100 
101 	hri_dmac_clear_CTRL_DMAENABLE_bit(DMAC);
102 	hri_dmac_clear_CTRL_CRCENABLE_bit(DMAC);
103 	hri_dmac_set_CHCTRLA_SWRST_bit(DMAC);
104 
105 	hri_dmac_write_CTRL_reg(DMAC,
106 	                        (CONF_DMAC_LVLEN0 << DMAC_CTRL_LVLEN0_Pos) | (CONF_DMAC_LVLEN1 << DMAC_CTRL_LVLEN1_Pos)
107 	                            | (CONF_DMAC_LVLEN2 << DMAC_CTRL_LVLEN2_Pos)
108 	                            | (CONF_DMAC_LVLEN3 << DMAC_CTRL_LVLEN3_Pos));
109 	hri_dmac_write_DBGCTRL_DBGRUN_bit(DMAC, CONF_DMAC_DBGRUN);
110 
111 	hri_dmac_write_QOSCTRL_reg(DMAC,
112 	                           DMAC_QOSCTRL_WRBQOS(CONF_DMAC_WRBQOS) | DMAC_QOSCTRL_FQOS(CONF_DMAC_FQOS)
113 	                               | DMAC_QOSCTRL_DQOS(CONF_DMAC_DQOS));
114 
115 	hri_dmac_write_PRICTRL0_reg(DMAC,
116 	                            DMAC_PRICTRL0_LVLPRI0(CONF_DMAC_LVLPRI0) | DMAC_PRICTRL0_LVLPRI1(CONF_DMAC_LVLPRI1)
117 	                                | DMAC_PRICTRL0_LVLPRI2(CONF_DMAC_LVLPRI2)
118 	                                | DMAC_PRICTRL0_LVLPRI3(CONF_DMAC_LVLPRI3)
119 	                                | (CONF_DMAC_RRLVLEN0 << DMAC_PRICTRL0_RRLVLEN0_Pos)
120 	                                | (CONF_DMAC_RRLVLEN1 << DMAC_PRICTRL0_RRLVLEN1_Pos)
121 	                                | (CONF_DMAC_RRLVLEN2 << DMAC_PRICTRL0_RRLVLEN2_Pos)
122 	                                | (CONF_DMAC_RRLVLEN3 << DMAC_PRICTRL0_RRLVLEN3_Pos));
123 	hri_dmac_write_BASEADDR_reg(DMAC, (uint32_t)_descriptor_section);
124 	hri_dmac_write_WRBADDR_reg(DMAC, (uint32_t)_write_back_section);
125 
126 	for (; i < DMAC_CH_NUM; i++) {
127 		hri_dmac_write_CHID_reg(DMAC, i);
128 
129 		hri_dmac_write_CHCTRLA_RUNSTDBY_bit(DMAC, _cfgs[i].ctrla & DMAC_CHCTRLA_RUNSTDBY);
130 
131 		hri_dmac_write_CHCTRLB_reg(DMAC, _cfgs[i].ctrlb);
132 		hri_dmacdescriptor_write_BTCTRL_reg(&_descriptor_section[i], _cfgs[i].btctrl);
133 	}
134 
135 	NVIC_DisableIRQ(DMAC_IRQn);
136 	NVIC_ClearPendingIRQ(DMAC_IRQn);
137 	NVIC_EnableIRQ(DMAC_IRQn);
138 
139 	hri_dmac_set_CTRL_DMAENABLE_bit(DMAC);
140 
141 	return ERR_NONE;
142 }
143 
144 /**
145  * \brief Enable/disable DMA interrupt
146  */
_dma_set_irq_state(const uint8_t channel,const enum _dma_callback_type type,const bool state)147 void _dma_set_irq_state(const uint8_t channel, const enum _dma_callback_type type, const bool state)
148 {
149 	hri_dmac_write_CHID_reg(DMAC, channel);
150 
151 	if (DMA_TRANSFER_COMPLETE_CB == type) {
152 		hri_dmac_write_CHINTEN_TCMPL_bit(DMAC, state);
153 	} else if (DMA_TRANSFER_ERROR_CB == type) {
154 		hri_dmac_write_CHINTEN_TERR_bit(DMAC, state);
155 	}
156 }
157 
_dma_set_destination_address(const uint8_t channel,const void * const dst)158 int32_t _dma_set_destination_address(const uint8_t channel, const void *const dst)
159 {
160 	hri_dmacdescriptor_write_DSTADDR_reg(&_descriptor_section[channel], (uint32_t)dst);
161 
162 	return ERR_NONE;
163 }
164 
_dma_set_source_address(const uint8_t channel,const void * const src)165 int32_t _dma_set_source_address(const uint8_t channel, const void *const src)
166 {
167 	hri_dmacdescriptor_write_SRCADDR_reg(&_descriptor_section[channel], (uint32_t)src);
168 
169 	return ERR_NONE;
170 }
171 
_dma_srcinc_enable(const uint8_t channel,const bool enable)172 int32_t _dma_srcinc_enable(const uint8_t channel, const bool enable)
173 {
174 	hri_dmacdescriptor_write_BTCTRL_SRCINC_bit(&_descriptor_section[channel], enable);
175 
176 	return ERR_NONE;
177 }
178 
_dma_set_data_amount(const uint8_t channel,const uint32_t amount)179 int32_t _dma_set_data_amount(const uint8_t channel, const uint32_t amount)
180 {
181 	uint32_t address   = hri_dmacdescriptor_read_DSTADDR_reg(&_descriptor_section[channel]);
182 	uint8_t  beat_size = hri_dmacdescriptor_read_BTCTRL_BEATSIZE_bf(&_descriptor_section[channel]);
183 
184 	if (hri_dmacdescriptor_get_BTCTRL_DSTINC_bit(&_descriptor_section[channel])) {
185 		hri_dmacdescriptor_write_DSTADDR_reg(&_descriptor_section[channel], address + amount * (1 << beat_size));
186 	}
187 
188 	address = hri_dmacdescriptor_read_SRCADDR_reg(&_descriptor_section[channel]);
189 
190 	if (hri_dmacdescriptor_get_BTCTRL_SRCINC_bit(&_descriptor_section[channel])) {
191 		hri_dmacdescriptor_write_SRCADDR_reg(&_descriptor_section[channel], address + amount * (1 << beat_size));
192 	}
193 
194 	hri_dmacdescriptor_write_BTCNT_reg(&_descriptor_section[channel], amount);
195 
196 	return ERR_NONE;
197 }
198 
_dma_enable_transaction(const uint8_t channel,const bool software_trigger)199 int32_t _dma_enable_transaction(const uint8_t channel, const bool software_trigger)
200 {
201 	hri_dmac_write_CHID_reg(DMAC, channel);
202 	hri_dmacdescriptor_set_BTCTRL_VALID_bit(&_descriptor_section[channel]);
203 	hri_dmac_set_CHCTRLA_ENABLE_bit(DMAC);
204 	if (software_trigger) {
205 		hri_dmac_set_SWTRIGCTRL_reg(DMAC, 1 << channel);
206 	}
207 
208 	return ERR_NONE;
209 }
210 
_dma_get_channel_resource(struct _dma_resource ** resource,const uint8_t channel)211 int32_t _dma_get_channel_resource(struct _dma_resource **resource, const uint8_t channel)
212 {
213 	*resource = &_resources[channel];
214 
215 	return ERR_NONE;
216 }
217 
218 /**
219  * \internal DMAC interrupt handler
220  */
DMAC_Handler(void)221 void DMAC_Handler(void)
222 {
223 	uint8_t               channel      = hri_dmac_read_INTPEND_ID_bf(DMAC);
224 	struct _dma_resource *tmp_resource = &_resources[channel];
225 
226 	hri_dmac_write_CHID_reg(DMAC, channel);
227 
228 	if (hri_dmac_get_CHINTFLAG_TERR_bit(DMAC)) {
229 		hri_dmac_clear_CHINTFLAG_TERR_bit(DMAC);
230 		tmp_resource->dma_cb.error(tmp_resource);
231 	} else if (hri_dmac_get_CHINTFLAG_TCMPL_bit(DMAC)) {
232 		hri_dmac_clear_CHINTFLAG_TCMPL_bit(DMAC);
233 		tmp_resource->dma_cb.transfer_done(tmp_resource);
234 	}
235 }
236 
237 #endif /* CONF_DMAC_ENABLE */
238