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>&copy; 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