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