1 /**
2 ******************************************************************************
3 * @file bflb_sdio2.c
4 * @version V1.0
5 * @date 2022-10-12
6 * @brief This file is the low hardware abstraction layer file
7 ******************************************************************************
8 * @attention
9 *
10 * <h2><center>© COPYRIGHT(c) 2022 Bouffalo Lab</center></h2>
11 *
12 * Redistribution and use in source and binary forms, with or without modification,
13 * are permitted provided that the following conditions are met:
14 * 1. Redistributions of source code must retain the above copyright notice,
15 * this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright notice,
17 * this list of conditions and the following disclaimer in the documentation
18 * and/or other materials provided with the distribution.
19 * 3. Neither the name of Bouffalo Lab nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 ******************************************************************************
35 */
36
37 #include "../include/bflb_sdio2.h"
38 #include "../include/hardware/sdio2_reg.h"
39
40 //#define SDIO2_DRV_DBG(a, ...) printf(a, ##__VA_ARGS__)
41 #define SDIO2_DRV_DBG(a, ...)
42 #ifndef BOOTROM
43 #define SDIO2_DRV_ERR(a, ...) printf("[Error]:" a, ##__VA_ARGS__)
44 #else
45 extern void bflb_bootrom_printf(char *fmt, ...);
46 #define SDIO2_DRV_ERR(a, ...) bflb_bootrom_printf("[Error]:" a, ##__VA_ARGS__)
47 #endif
48 #define SDU_INT_HOST 0
49
50 static uintptr_t local_tx_buf[SDIO2_MAX_PORT_NUM][SDIO2_BYTE_PER_BUF / sizeof(uintptr_t)] ATTR_NOCACHE_RAM_SECTION;
51 static uintptr_t local_rx_buf[SDIO2_MAX_PORT_NUM][SDIO2_BYTE_PER_BUF / sizeof(uintptr_t)] ATTR_NOCACHE_RAM_SECTION;
52
53 /****************************************************************************/ /**
54 * @brief Get sdio2 block size
55 *
56 * @param dev SDIO device pointer
57 *
58 * @return Block size
59 *
60 *******************************************************************************/
bflb_sdio2_get_block_size(struct bflb_device_s * dev)61 uint32_t bflb_sdio2_get_block_size(struct bflb_device_s *dev)
62 {
63 uint16_t blk_size = 0;
64 uint32_t reg_base = dev->reg_base;
65
66 blk_size = getreg8(reg_base + SDIO2_FN1_BLK_SIZE_0_OFFSET);
67 blk_size |= ((getreg8(reg_base + SDIO2_FN1_BLK_SIZE_1_OFFSET) & SDIO2_FN1_BLK_SIZE_1_MASK) << 8);
68
69 return blk_size;
70 }
71
72 /****************************************************************************/ /**
73 * @brief sdio2 init
74 *
75 * @param dev: SDIO device pointer
76 *
77 * @return BFLB_RET:0 means success and other value means error
78 *
79 *******************************************************************************/
bflb_sdio2_init(struct bflb_device_s * dev)80 int bflb_sdio2_init(struct bflb_device_s *dev)
81 {
82 uint32_t reg_base = dev->reg_base;
83 uint32_t regval = 0;
84
85 putreg16(0, reg_base + SDIO2_RD_BIT_MAP_OFFSET);
86 putreg16(0, reg_base + SDIO2_WR_BIT_MAP_OFFSET);
87
88 /* toggle SDIO_CCR_CIC_DnLdOvr on WL_SDIO_CCR_CARD_INT_CAUSE */
89 putreg8(SDIO2_CCR_CIC_DnLdOvr, reg_base + SDIO2_CARD_INT_STATUS_OFFSET);
90 putreg8(0, reg_base + SDIO2_CARD_INT_STATUS_OFFSET);
91
92 if (1) {
93 /* multiport */
94 regval = getreg32(reg_base + SDIO2_CONFIG2_OFFSET);
95 putreg32(regval | SDIO2_CONFIG2_MSK, reg_base + SDIO2_CONFIG2_OFFSET);
96 regval = getreg8(reg_base + SDIO2_CONFIG_OFFSET);
97 putreg8(regval | 0x00000010, reg_base + SDIO2_CONFIG_OFFSET);
98 }
99
100 /* unmask the interrupts */
101 putreg8(SDIO2_CCR_CIM_MASK, reg_base + SDIO2_CARD_INT_MASK_OFFSET);
102 /* select interrupt reset mode */
103 putreg8(0, reg_base + SDIO2_CARD_INT_MODE_OFFSET);
104
105 bflb_sdio2_tx_rx_queue_init(dev);
106
107 bflb_irq_attach(dev->irq_num, bflb_sdio2_isr, dev);
108 bflb_irq_enable(dev->irq_num);
109
110 return 0;
111 }
112
113 /****************************************************************************/ /**
114 * @brief SDIO2 tx and rx queue init
115 *
116 * @param dev: SDIO device pointer
117 *
118 * @return BFLB_RET:0 means success and other value means error
119 *
120 *******************************************************************************/
bflb_sdio2_tx_rx_queue_init(struct bflb_device_s * dev)121 int bflb_sdio2_tx_rx_queue_init(struct bflb_device_s *dev)
122 {
123 uint32_t reg_base = dev->reg_base;
124 uint16_t wr_bit_map = getreg16(reg_base + SDIO2_WR_BIT_MAP_OFFSET);
125
126 for (uint8_t i = 0; i < SDIO2_MAX_PORT_NUM; i++) {
127 if (!(wr_bit_map & (1 << i))) {
128 /* attach new buffer */
129 putreg8(i, reg_base + SDIO2_WRITE_INDEX_OFFSET);
130 putreg32((uint32_t)&local_rx_buf[i][0], reg_base + SDIO2_SQ_WRITE_BASE_OFFSET);
131 putreg16(1 << i, reg_base + SDIO2_WR_BIT_MAP_OFFSET);
132 #if SDU_INT_HOST
133 putreg8((SDIO2_CCR_CS_ReadCISRdy | SDIO2_CCR_CS_DnLdRdy | SDIO2_CCR_CS_IORdy),
134 reg_base + SDIO2_CARD_TO_HOST_EVENT_OFFSET);
135 #endif
136 }
137 }
138 return 0;
139 }
140
141 /****************************************************************************/ /**
142 * @brief SDIO2 check host ready
143 *
144 * @param dev: SDIO device pointer
145 *
146 * @return 1 for host ready, 0 for not
147 *
148 *******************************************************************************/
bflb_sdio2_check_host_ready(struct bflb_device_s * dev)149 int bflb_sdio2_check_host_ready(struct bflb_device_s *dev)
150 {
151 uint32_t reg_base = dev->reg_base;
152 uint32_t regval = 0;
153
154 regval = getreg8(reg_base + SDIO2_SCRATCH_OFFSET);
155
156 if (regval != 0) {
157 return 1;
158
159 } else {
160 return 0;
161 }
162 }
163
164 /****************************************************************************/ /**
165 * @brief SDIO2 send data,this function can be in user app context
166 *
167 * @param dev: SDIO device pointer
168 * @param qos: qos number for this data buffer to send
169 * @param buff: data buffer pointer
170 * @param len: data length
171 *
172 * @return BFLB_RET:0 means success and other value means error
173 *
174 *******************************************************************************/
bflb_sdio2_send_data(struct bflb_device_s * dev,int qos,uintptr_t * buff,int len)175 int bflb_sdio2_send_data(struct bflb_device_s *dev, int qos, uintptr_t *buff, int len)
176 {
177 uint32_t reg_base = dev->reg_base;
178 uint16_t rd_bit_map = getreg16(reg_base + SDIO2_RD_BIT_MAP_OFFSET);
179 static uint8_t curr_upld_port = 0;
180
181 if (rd_bit_map & (1 << curr_upld_port)) {
182 return -1;
183 }
184 arch_memcpy_fast(local_tx_buf[curr_upld_port], buff, len);
185 SDIO2_DRV_DBG("Copy port=%d,index=%d\r\n",curr_upld_port,local_tx_buf[curr_upld_port][0]);
186 putreg8(curr_upld_port, reg_base + SDIO2_READ_INDEX_OFFSET);
187 putreg16(SDIO2_BYTE_PER_BUF, reg_base + SDIO2_RD_LEN_OFFSET + curr_upld_port * 2);
188 putreg32((uint32_t)&local_tx_buf[curr_upld_port][0], reg_base + SDIO2_SQ_READ_BASE_OFFSET);
189 putreg16(1 << curr_upld_port, reg_base + SDIO2_RD_BIT_MAP_OFFSET);
190 #if SDU_INT_HOST
191 putreg8(SDIO2_CCR_CS_UpLdRdy, reg_base + SDIO2_CARD_TO_HOST_EVENT_OFFSET);
192 #endif
193 curr_upld_port++;
194 if(curr_upld_port == SDIO2_MAX_PORT_NUM){
195 curr_upld_port = 0;
196 }
197 return 0;
198 }
199
200 /****************************************************************************/ /**
201 * @brief SDIO2 receive data,this function can be in user app context
202 *
203 * @param dev: SDIO device pointer
204 * @param qos: qos number for this data buffer to receive
205 * @param buff: data buffer pointer
206 * @param len: data length
207 *
208 * @return BFLB_RET:0 means success and other value means error
209 *
210 *******************************************************************************/
bflb_sdio2_recv_data(struct bflb_device_s * dev,int qos,uintptr_t * buff,int * len)211 int bflb_sdio2_recv_data(struct bflb_device_s *dev, int qos, uintptr_t *buff, int *len)
212 {
213 static uint16_t curr_dnld_port = 0;
214 uint32_t reg_base = dev->reg_base;
215 uint16_t wr_bit_map = getreg16(reg_base + SDIO2_WR_BIT_MAP_OFFSET);
216 uint8_t crcerror = 0;
217 #if 0
218 uint8_t card_status = 0;
219
220 /* get card status */
221 card_status = getreg8(reg_base + SDIO2_CARD_INT_STATUS_OFFSET);
222 #endif
223
224 /* get erro */
225 crcerror = getreg8(reg_base + SDIO2_HOST_TRANS_STATUS_OFFSET);
226
227 #if 0
228 if (!(card_status & SDIO2_CCR_CIC_DnLdOvr)){
229 SDIO2_DRV_DBG("No data come from host\r\n");
230 return -1;
231 }
232 #endif
233 if (crcerror & SDIO2_CCR_HOST_INT_DnLdCRC_err) {
234 SDIO2_DRV_ERR("RX CRC error\r\n");
235 }
236
237 if (!(wr_bit_map & (1 << curr_dnld_port))) {
238 arch_memcpy_fast(buff, local_rx_buf[curr_dnld_port], SDIO2_BYTE_PER_BUF);
239 SDIO2_DRV_DBG("Copy port=%d,index=%d\r\n",curr_dnld_port,buff[0]);
240 *len = SDIO2_BYTE_PER_BUF;
241 /* attach new buffer */
242 putreg8(curr_dnld_port, reg_base + SDIO2_WRITE_INDEX_OFFSET);
243 putreg32((uint32_t)&local_rx_buf[curr_dnld_port][0], reg_base + SDIO2_SQ_WRITE_BASE_OFFSET);
244 putreg16(1 << curr_dnld_port, reg_base + SDIO2_WR_BIT_MAP_OFFSET);
245 #if SDU_INT_HOST
246 putreg8((SDIO2_CCR_CS_ReadCISRdy | SDIO2_CCR_CS_DnLdRdy | SDIO2_CCR_CS_IORdy),
247 reg_base + SDIO2_CARD_TO_HOST_EVENT_OFFSET);
248 #endif
249 /* go to next */
250 curr_dnld_port++;
251 if (curr_dnld_port == SDIO2_MAX_PORT_NUM) {
252 curr_dnld_port = 0;
253 }
254 return 0;
255 }else{
256 return -1;
257 }
258 }
259
260 /****************************************************************************/ /**
261 * @brief sdio2 irq handler
262 *
263 * @param irq: sdio3 interrupt type
264 * @param arg: arg for callback
265 *
266 * @return None
267 *
268 *******************************************************************************/
bflb_sdio2_isr(int irq,void * arg)269 void bflb_sdio2_isr(int irq, void *arg)
270 {
271 struct bflb_device_s *dev = (struct bflb_device_s *)arg;
272 uint32_t reg_base = 0;
273 uint32_t regval = 0;
274 uint8_t crcerror = 0;
275
276 reg_base = dev->reg_base;
277 regval = getreg8(reg_base + SDIO2_CARD_INT_STATUS_OFFSET);
278
279 /* clear interrupt */
280 putreg8(~regval | SDIO2_CCR_CIC_PwrUp, reg_base + SDIO2_CARD_INT_STATUS_OFFSET);
281 /* get erro */
282 crcerror = getreg8(reg_base + SDIO2_HOST_TRANS_STATUS_OFFSET);
283
284 if ((regval & SDIO2_CCR_CIC_UpLdOvr)) {
285 SDIO2_DRV_DBG("TX interrupt come\r\n");
286 }
287
288 if ((regval & SDIO2_CCR_CIC_DnLdOvr) &&
289 !(crcerror & SDIO2_CCR_HOST_INT_DnLdCRC_err)) {
290 SDIO2_DRV_DBG("RX interrupt come\r\n");
291 }
292
293 if (crcerror & SDIO2_CCR_HOST_INT_DnLdCRC_err) {
294 SDIO2_DRV_ERR("RX CRC error\r\n");
295 }
296 }
297