1 /** @file sdio.c
2  *
3  *  @brief  This file provides sdio related Generic API
4  *
5  *  Copyright 2021-2024 NXP
6  *
7  *  SPDX-License-Identifier: BSD-3-Clause
8  *
9  */
10 #include <osa.h>
11 #include <mlan_sdio_api.h>
12 
13 #if (CONFIG_XZ_DECOMPRESSION)
14 #include <xz.h>
15 #include <decompress.h>
16 #endif /* CONFIG_XZ_DECOMPRESSION */
17 
18 /* Additional WMSDK header files */
19 #include "mlan_main_defs.h"
20 #include "mlan_sdio_defs.h"
21 #include "type_decls.h"
22 #include "sdio.h"
23 #include "firmware_dnld.h"
24 
25 /*
26  * Used to authorize the SDIO interrupt handler to accept the incoming
27  * packet from the SDIO interface. If this flag is set a semaphore is
28  * signalled.
29  */
30 
31 /* @brief decription about the read/write buffer
32  * The size of the read/write buffer should be a multiple of 512, since SDHC/SDXC card uses 512-byte fixed
33  * block length and this driver example is enabled with a SDHC/SDXC card.If you are using a SDSC card, you
34  * can define the block length by yourself if the card supports partial access.
35  * The address of the read/write buffer should align to the specific DMA data buffer address align value if
36  * DMA transfer is used, otherwise the buffer address is not important.
37  * At the same time buffer address/size should be aligned to the cache line size if cache is supported.
38  */
39 
40 #define BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE 32
41 /*! @brief Data written to the card */
42 #if CONFIG_SDIO_MULTI_PORT_TX_AGGR
43 SDK_ALIGN(uint8_t outbuf[SDIO_MP_AGGR_DEF_PKT_LIMIT * 2 * DATA_BUFFER_SIZE], BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE);
44 #else
45 SDK_ALIGN(uint8_t outbuf[DATA_BUFFER_SIZE + DATA_BUFFER_SIZE / 2], BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE);
46 #endif
47 
48 /*! @brief Data read from the card */
49 #if (CONFIG_SDIO_MULTI_PORT_RX_AGGR) && !(FSL_USDHC_ENABLE_SCATTER_GATHER_TRANSFER)
50 SDK_ALIGN(uint8_t inbuf[SDIO_MP_AGGR_DEF_PKT_LIMIT * 2 * DATA_BUFFER_SIZE], BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE);
51 #else
52 SDK_ALIGN(uint8_t inbuf[2 * DATA_BUFFER_SIZE], BOARD_SDMMC_DATA_BUFFER_ALIGN_SIZE);
53 #endif /*CONFIG_SDIO_MULTI_PORT_RX_AGGR*/
54 
55 t_u32 ioport_g = 0;
56 
57 /**
58  * Function to set mlan ioport.
59  * A weak definition of this is added here for compilation of
60  * bt ble apps/non wifi apps
61  * This funciton is defined in wifi-sdio.c as of this writing
62  * for wifi files.
63  */
set_ioport_inmlan(t_u32 port)64 WEAK void set_ioport_inmlan(t_u32 port)
65 {
66     return;
67 }
68 
wifi_get_sdio_ioport()69 unsigned int wifi_get_sdio_ioport()
70 {
71     return ioport_g;
72 }
wifi_get_sdio_outbuf(uint32_t * outbuf_len)73 uint8_t *wifi_get_sdio_outbuf(uint32_t *outbuf_len)
74 {
75     *outbuf_len = sizeof(outbuf);
76     return outbuf;
77 }
78 
79 /**
80  *  @brief This function reads the CARD_TO_HOST_EVENT_REG and
81  *  checks if input bits are set
82  *  @param bits		bits to check status against
83  *  @return		true if bits are set
84  *                      SDIO_POLLING_STATUS_TIMEOUT if bits
85  *                      aren't set
86  */
wlan_card_status(t_u8 bits)87 bool wlan_card_status(t_u8 bits)
88 {
89     uint32_t resp = 0;
90     t_u32 tries;
91 
92     for (tries = 0; tries < MAX_POLL_TRIES; tries++)
93     {
94         if (!(sdio_drv_creg_read(CARD_TO_HOST_EVENT_REG, 1, &resp)))
95         {
96             return false;
97         }
98         if ((resp & bits) == bits)
99         {
100             return true;
101         }
102         OSA_TimeDelay(1U);
103     }
104     return false;
105 }
106 
107 #define SDIO_BLOCK_SIZE 256U
108 
calculate_sdio_write_params(t_u32 txlen,t_u32 * tx_blocks,t_u32 * buflen)109 void calculate_sdio_write_params(t_u32 txlen, t_u32 *tx_blocks, t_u32 *buflen)
110 {
111     *tx_blocks = (txlen + SDIO_BLOCK_SIZE - 1) / SDIO_BLOCK_SIZE;
112 
113     *buflen = SDIO_BLOCK_SIZE;
114 }
115 
wlan_card_read_scratch_reg(void)116 static uint32_t wlan_card_read_scratch_reg(void)
117 {
118     uint32_t val    = 0;
119     uint32_t rd_len = 0;
120 
121     (void)sdio_drv_creg_read(0x64, 1, &val);
122     rd_len = (val & 0xffU);
123     (void)sdio_drv_creg_read(0x65, 1, &val);
124     rd_len |= ((val & 0xffU) << 8);
125     (void)sdio_drv_creg_read(0x66, 1, &val);
126     rd_len |= ((val & 0xffU) << 16);
127     (void)sdio_drv_creg_read(0x67, 1, &val);
128     rd_len |= ((val & 0xffU) << 24);
129 
130     return rd_len;
131 }
132 
wlan_sdio_init_ioport(void)133 static void wlan_sdio_init_ioport(void)
134 {
135     uint32_t resp = 0;
136     t_u8 data;
137 
138 #if defined(SD8978) || defined(SD8987) || defined(SD8997) || defined(SD9097) || defined(SD9098) || defined(SD9177)
139     ioport_g = MEM_PORT;
140 
141     sdio_io_d("IOPORT : (0x%x)", ioport_g);
142 
143     (void)sdio_drv_creg_write(HOST_INT_MASK_REG, 1, 0x0, &resp);
144 
145     /* Enable sdio cmd53 new mode */
146     (void)sdio_drv_creg_read(CARD_CONFIG_2_1_REG, 1, &resp);
147     data = (t_u8)((resp & 0xff) | CMD53_NEW_MODE);
148     (void)sdio_drv_creg_write(CARD_CONFIG_2_1_REG, 1, data, &resp);
149     (void)sdio_drv_creg_read(CARD_CONFIG_2_1_REG, 1, &resp);
150 
151     /* configure cmd port  */
152     /* enable reading rx length from the register  */
153     (void)sdio_drv_creg_read(CMD_CONFIG_0, 1, &resp);
154     data = (t_u8)((resp & 0xff) | CMD_PORT_RD_LEN_EN);
155     (void)sdio_drv_creg_write(CMD_CONFIG_0, 1, data, &resp);
156     (void)sdio_drv_creg_read(CMD_CONFIG_0, 1, &resp);
157 
158     /* enable Dnld/Upld ready auto reset for cmd port
159      * after cmd53 is completed */
160     (void)sdio_drv_creg_read(CMD_CONFIG_1, 1, &resp);
161     data = (t_u8)((resp & 0xff) | CMD_PORT_AUTO_EN);
162     (void)sdio_drv_creg_write(CMD_CONFIG_1, 1, data, &resp);
163     (void)sdio_drv_creg_read(CMD_CONFIG_1, 1, &resp);
164 #elif defined(SD8801)
165     sdio_drv_creg_write(HOST_INT_MASK_REG, 1, 0x0, &resp);
166 
167     /* Read the PORT regs for IOPORT address */
168     sdio_drv_creg_read(IO_PORT_0_REG, 1, &resp);
169     ioport_g = (resp & 0xff);
170 
171     sdio_drv_creg_read(IO_PORT_1_REG, 1, &resp);
172     ioport_g |= ((resp & 0xff) << 8);
173 
174     sdio_drv_creg_read(IO_PORT_2_REG, 1, &resp);
175     ioport_g |= ((resp & 0xff) << 16);
176 
177     sdio_io_d("IOPORT : (0x%x)", ioport_g);
178 #endif
179 
180     /* Set Host interrupt reset to read to clear */
181     (void)sdio_drv_creg_read(HOST_INT_RSR_REG, 1, &resp);
182     data = (t_u8)((resp & 0xff) | HOST_INT_RSR_MASK);
183     (void)sdio_drv_creg_write(HOST_INT_RSR_REG, 1, data, &resp);
184 
185     /* Dnld/Upld ready set to auto reset */
186     (void)sdio_drv_creg_read(CARD_MISC_CFG_REG, 1, &resp);
187     data = (t_u8)((resp & 0xff) | AUTO_RE_ENABLE_INT);
188     (void)sdio_drv_creg_write(CARD_MISC_CFG_REG, 1, data, &resp);
189     set_ioport_inmlan(ioport_g);
190 }
191 
wlan_card_read_f1_base_regs(void)192 t_u16 wlan_card_read_f1_base_regs(void)
193 {
194     t_u16 reg;
195     uint32_t resp = 0;
196 
197     (void)sdio_drv_creg_read(READ_BASE_0_REG, 1, &resp);
198     reg = (t_u16)(resp & 0xffU);
199     (void)sdio_drv_creg_read(READ_BASE_1_REG, 1, &resp);
200     reg |= (t_u16)((resp & 0xffU) << 8);
201 
202     return reg;
203 }
204 
sdio_init(void)205 int sdio_init(void)
206 {
207     uint32_t resp = 0;
208     /* Initialize SDIO driver */
209     int rv = sdio_drv_init(NULL);
210     if (rv != WM_SUCCESS)
211     {
212         sdio_io_e("SDIO driver init failed.");
213         return -1;
214     }
215 
216 #if 0
217 	sdio_drv = sdio_drv_open("MDEV_SDIO");
218 	if (!sdio_drv) {
219 		sdio_io_e("SDIO driver open failed.");
220 		return -1;
221 	}
222 #endif
223     int ret = 0;
224     bool wlan_card_stat;
225     ret = sdio_drv_creg_read(CARD_TO_HOST_EVENT_REG, 1, &resp);
226     if (ret && (resp & (DN_LD_CARD_RDY)) == 0U)
227     {
228         wlan_card_stat = wlan_card_status(UP_LD_CARD_RDY);
229         if (wlan_card_stat != false)
230         {
231             uint32_t rd_len;
232             rd_len = wlan_card_read_scratch_reg();
233             if (rd_len > 0U)
234             {
235                 (void)sdio_drv_creg_write(FN1_BLOCK_SIZE_0, 0, 0x8, &resp);
236                 (void)sdio_drv_creg_write(FN1_BLOCK_SIZE_1, 0, 0x0, &resp);
237 
238                 uint8_t buf[256];
239                 ret = sdio_drv_read(0x10000, 1, rd_len, 8, buf, &resp);
240                 if (!ret)
241                 {
242                     sdio_io_e(
243                         "SDIO read failed, "
244                         "resp:%x",
245                         resp);
246                     return -1;
247                 }
248             }
249         }
250     }
251     else if (!ret)
252     {
253         sdio_io_e("failed to read EVENT_REG");
254         return -1;
255     }
256     else
257     { /* Do Nothing */
258     }
259     return 0;
260 }
261 
sdio_ioport_init(void)262 int sdio_ioport_init(void)
263 {
264     /* this sets intmask on card and makes interrupts repeatable */
265     wlan_sdio_init_ioport();
266 
267     return 0;
268 }
269 
270 /**
271  * Interrupt callback handler registered with the SDIO driver.
272  * A weak definition of this is added here for compilation of
273  * bt ble apps/non wifi apps
274  * This funciton is defined in wifi-sdio.c as of this writing
275  * for wifi files.
276  */
handle_cdint(int error)277 WEAK void handle_cdint(int error)
278 {
279     return;
280 }
281