1
2 /**
3 * \file
4 *
5 * \brief SAM DMA Controller (XDMAC) Interface
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
35 #include <hpl_dma.h>
36 #include <hpl_xdmac_config.h>
37 #include <peripheral_clk_config.h>
38 #include <utils.h>
39 #include <utils_assert.h>
40 #include <utils_repeat_macro.h>
41
42 #if CONF_DMA_ENABLE
43 #define DMAC_CH_NUM 24
44
45 /* Array containing callbacks for DMAC channels */
46 static struct _dma_resource _resources[DMAC_CH_NUM];
47
48 /* This macro DMAC configuration */
49 #define DMAC_CHANNEL_CFG(i, n) \
50 {XDMAC_CC_MBSIZE(CONF_DMAC_BURSTSIZE_##n) | XDMAC_CC_CSIZE(CONF_DMAC_CHUNKSIZE_##n) \
51 | XDMAC_CC_DWIDTH(CONF_DMAC_BEATSIZE_##n) | (CONF_DMAC_SRC_INTERFACE_##n << XDMAC_CC_SIF_Pos) \
52 | (CONF_DMAC_DES_INTERFACE_##n << XDMAC_CC_DIF_Pos) \
53 | XDMAC_CC_SAM((CONF_DMAC_SRC_STRIDE_##n == -1) ? 3 : CONF_DMAC_SRCINC_##n) \
54 | XDMAC_CC_DAM((CONF_DMAC_DES_STRIDE_##n == -1) ? 3 : CONF_DMAC_DSTINC_##n) \
55 | (CONF_DMAC_TYPE_##n << XDMAC_CC_TYPE_Pos) | (CONF_DMAC_DSYNC_##n << XDMAC_CC_DSYNC_Pos) \
56 | (CONF_DMAC_SWREQ_##n << XDMAC_CC_SWREQ_Pos) \
57 | ((!CONF_DMAC_SWREQ_##n) ? XDMAC_CC_PERID(CONF_DMAC_TRIGSRC_##n) : 0x0), \
58 XDMAC_CDS_MSP_SDS_MSP(CONF_DMAC_SRC_STRIDE_##n) | XDMAC_CDS_MSP_DDS_MSP(CONF_DMAC_DES_STRIDE_##n)},
59
60 /* DMAC channel configuration */
61 struct dmac_channel_cfg {
62 uint32_t config_reg;
63 uint32_t cds_msp;
64 };
65
66 /* DMAC channel configurations */
67 const static struct dmac_channel_cfg _cfgs[] = {REPEAT_MACRO(DMAC_CHANNEL_CFG, i, DMAC_CH_NUM)};
68
_dma_init(void)69 int32_t _dma_init(void)
70 {
71 uint8_t i;
72
73 /* Clear the pending Interrupt Status bit */
74 for (i = 0; i < DMAC_CH_NUM; i++) {
75 hri_xdmac_read_CIS_reg(XDMAC, i);
76 }
77 /* Configuration Registers */
78 for (i = 0; i < DMAC_CH_NUM; i++) {
79 hri_xdmac_write_CNDC_reg(XDMAC, i, 0x0);
80 hri_xdmac_write_CBC_reg(XDMAC, i, 0x0);
81 hri_xdmac_write_CSUS_reg(XDMAC, i, 0x0);
82 hri_xdmac_write_CDUS_reg(XDMAC, i, 0x0);
83 hri_xdmac_write_CC_reg(XDMAC, i, _cfgs[i].config_reg);
84 hri_xdmac_write_CDS_MSP_reg(XDMAC, i, _cfgs[i].cds_msp);
85 }
86
87 NVIC_DisableIRQ(XDMAC_IRQn);
88 NVIC_ClearPendingIRQ(XDMAC_IRQn);
89 NVIC_EnableIRQ(XDMAC_IRQn);
90
91 return ERR_NONE;
92 }
93
_dma_set_destination_address(const uint8_t channel,const void * const dst)94 int32_t _dma_set_destination_address(const uint8_t channel, const void *const dst)
95 {
96 hri_xdmac_write_CDA_reg(XDMAC, channel, (uint32_t)dst);
97
98 return ERR_NONE;
99 }
100
_dma_set_source_address(const uint8_t channel,const void * const src)101 int32_t _dma_set_source_address(const uint8_t channel, const void *const src)
102 {
103 hri_xdmac_write_CSA_reg(XDMAC, channel, (uint32_t)src);
104
105 return ERR_NONE;
106 }
107
_dma_srcinc_enable(const uint8_t channel,const bool enable)108 int32_t _dma_srcinc_enable(const uint8_t channel, const bool enable)
109 {
110 if (!enable && (hri_xdmac_read_CC_DWIDTH_bf(XDMAC, channel) != XDMAC_CC_DWIDTH_WORD_Val)) {
111 /* Errata: If XDMA is used to transfer 8-bit or 16-bit data in fixed source
112 * address or fixed destination address mode, source and destination addresses
113 * are incremented by 8-bit or 16-bit.
114 * Workaround: The user can fix the problem by setting the source addressing
115 * mode to use micro block and data striding with micro block stride set to 0 and
116 * data stride set to -1.
117 */
118 hri_xdmac_write_CC_SAM_bf(XDMAC, channel, XDMAC_CC_SAM_UBS_DS_AM_Val);
119 hri_xdmac_write_CDS_MSP_SDS_MSP_bf(XDMAC, channel, (int16_t)(-1));
120 } else {
121 hri_xdmac_write_CC_SAM_bf(XDMAC, channel, enable);
122 }
123
124 return ERR_NONE;
125 }
126
_dma_dstinc_enable(const uint8_t channel,const bool enable)127 int32_t _dma_dstinc_enable(const uint8_t channel, const bool enable)
128 {
129 if (!enable && (hri_xdmac_read_CC_DWIDTH_bf(XDMAC, channel) != XDMAC_CC_DWIDTH_WORD_Val)) {
130 /* Errata: If XDMA is used to transfer 8-bit or 16-bit data in fixed source
131 * address or fixed destination address mode, source and destination addresses
132 * are incremented by 8-bit or 16-bit.
133 * Workaround: The user can fix the problem by setting the source addressing
134 * mode to use micro block and data striding with micro block stride set to 0 and
135 * data stride set to -1.
136 */
137 hri_xdmac_write_CC_DAM_bf(XDMAC, channel, XDMAC_CC_DAM_UBS_DS_AM_Val);
138 hri_xdmac_write_CDS_MSP_SDS_MSP_bf(XDMAC, channel, (int16_t)(-1));
139 } else {
140 hri_xdmac_write_CC_DAM_bf(XDMAC, channel, enable);
141 }
142
143 return ERR_NONE;
144 }
145
_dma_set_data_amount(const uint8_t channel,const uint32_t amount)146 int32_t _dma_set_data_amount(const uint8_t channel, const uint32_t amount)
147 {
148 uint8_t width;
149
150 width = hri_xdmac_get_CC_DWIDTH_bf(XDMAC, channel, 0x3);
151 hri_xdmac_write_CUBC_reg(XDMAC, channel, amount >> width);
152
153 return ERR_NONE;
154 }
155
_dma_enable_transaction(const uint8_t channel,const bool software_trigger)156 int32_t _dma_enable_transaction(const uint8_t channel, const bool software_trigger)
157 {
158 hri_xdmac_set_GS_reg(XDMAC, 1 << channel);
159
160 if (software_trigger) {
161 hri_xdmac_write_GSWR_reg(XDMAC, 1 << channel);
162 }
163
164 return ERR_NONE;
165 }
166
_dma_get_channel_resource(struct _dma_resource ** resource,const uint8_t channel)167 int32_t _dma_get_channel_resource(struct _dma_resource **resource, const uint8_t channel)
168 {
169 *resource = &_resources[channel];
170
171 return ERR_NONE;
172 }
173
_dma_set_irq_state(const uint8_t channel,const enum _dma_callback_type type,const bool state)174 void _dma_set_irq_state(const uint8_t channel, const enum _dma_callback_type type, const bool state)
175 {
176 if (state) {
177 if (type == DMA_TRANSFER_COMPLETE_CB) {
178 hri_xdmac_set_CIM_reg(XDMAC, channel, XDMAC_CIE_BIE);
179 } else if (type == DMA_TRANSFER_ERROR_CB) {
180 hri_xdmac_set_CIM_reg(XDMAC, channel, XDMAC_CIE_RBIE | XDMAC_CIE_WBIE | XDMAC_CIE_ROIE);
181 }
182 hri_xdmac_set_GIM_reg(XDMAC, (1 << channel));
183 } else {
184 if (type == DMA_TRANSFER_COMPLETE_CB) {
185 hri_xdmac_clear_CIM_reg(XDMAC, channel, XDMAC_CID_BID);
186 } else if (type == DMA_TRANSFER_ERROR_CB) {
187 hri_xdmac_clear_CIM_reg(XDMAC, channel, XDMAC_CID_RBEID | XDMAC_CID_WBEID | XDMAC_CID_ROID);
188 }
189 hri_xdmac_clear_GIM_reg(XDMAC, (1 << channel));
190 }
191 }
192
193 /**
194 * \internal XDMAC interrupt handler
195 */
XDMAC_Handler(void)196 void XDMAC_Handler(void)
197 {
198 uint32_t status;
199 struct _dma_resource *tmp_resource;
200 int8_t channel = -1;
201 uint32_t pend;
202
203 pend = hri_xdmac_read_GIS_reg(XDMAC);
204
205 /* Get the first pending channel ID */
206 for (uint8_t i = 0; i < DMAC_CH_NUM; i++) {
207 if ((pend >> i) & 1) {
208 channel = i;
209 break;
210 }
211 }
212
213 if (channel < 0) {
214 return;
215 }
216
217 tmp_resource = &_resources[channel];
218 status = hri_xdmac_read_CIS_reg(XDMAC, channel);
219
220 if (status & (XDMAC_CIS_RBEIS | XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) {
221 tmp_resource->dma_cb.error(tmp_resource);
222 } else if (status & XDMAC_CIS_BIS) {
223 tmp_resource->dma_cb.transfer_done(tmp_resource);
224 }
225 }
226
227 #endif /* CONF_DMA_ENABLE */
228