Commit | Line | Data |
---|---|---|
58391efd | 1 | // SPDX-License-Identifier: GPL-2.0 |
554c0a3a HG |
2 | /****************************************************************************** |
3 | * | |
4 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. | |
5 | * | |
554c0a3a HG |
6 | *******************************************************************************/ |
7 | #define _SDIO_OPS_C_ | |
8 | ||
9 | #include <drv_types.h> | |
10 | #include <rtw_debug.h> | |
11 | #include <rtl8723b_hal.h> | |
12 | ||
13 | /* define SDIO_DEBUG_IO 1 */ | |
14 | ||
15 | ||
16 | /* */ | |
17 | /* Description: */ | |
18 | /* The following mapping is for SDIO host local register space. */ | |
19 | /* */ | |
20 | /* Creadted by Roger, 2011.01.31. */ | |
21 | /* */ | |
22 | static void HalSdioGetCmdAddr8723BSdio( | |
2a734e17 SP |
23 | struct adapter *adapter, |
24 | u8 device_id, | |
25 | u32 addr, | |
26 | u32 *cmdaddr | |
554c0a3a HG |
27 | ) |
28 | { | |
2a734e17 | 29 | switch (device_id) { |
554c0a3a | 30 | case SDIO_LOCAL_DEVICE_ID: |
2a734e17 | 31 | *cmdaddr = ((SDIO_LOCAL_DEVICE_ID << 13) | (addr & SDIO_LOCAL_MSK)); |
554c0a3a HG |
32 | break; |
33 | ||
34 | case WLAN_IOREG_DEVICE_ID: | |
2a734e17 | 35 | *cmdaddr = ((WLAN_IOREG_DEVICE_ID << 13) | (addr & WLAN_IOREG_MSK)); |
554c0a3a HG |
36 | break; |
37 | ||
38 | case WLAN_TX_HIQ_DEVICE_ID: | |
2a734e17 | 39 | *cmdaddr = ((WLAN_TX_HIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK)); |
554c0a3a HG |
40 | break; |
41 | ||
42 | case WLAN_TX_MIQ_DEVICE_ID: | |
2a734e17 | 43 | *cmdaddr = ((WLAN_TX_MIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK)); |
554c0a3a HG |
44 | break; |
45 | ||
46 | case WLAN_TX_LOQ_DEVICE_ID: | |
2a734e17 | 47 | *cmdaddr = ((WLAN_TX_LOQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK)); |
554c0a3a HG |
48 | break; |
49 | ||
50 | case WLAN_RX0FF_DEVICE_ID: | |
2a734e17 | 51 | *cmdaddr = ((WLAN_RX0FF_DEVICE_ID << 13) | (addr & WLAN_RX0FF_MSK)); |
554c0a3a HG |
52 | break; |
53 | ||
54 | default: | |
55 | break; | |
56 | } | |
57 | } | |
58 | ||
59 | static u8 get_deviceid(u32 addr) | |
60 | { | |
2a734e17 SP |
61 | u8 devide_id; |
62 | u16 pseudo_id; | |
554c0a3a HG |
63 | |
64 | ||
2a734e17 SP |
65 | pseudo_id = (u16)(addr >> 16); |
66 | switch (pseudo_id) { | |
554c0a3a | 67 | case 0x1025: |
2a734e17 | 68 | devide_id = SDIO_LOCAL_DEVICE_ID; |
554c0a3a HG |
69 | break; |
70 | ||
71 | case 0x1026: | |
2a734e17 | 72 | devide_id = WLAN_IOREG_DEVICE_ID; |
554c0a3a HG |
73 | break; |
74 | ||
75 | /* case 0x1027: */ | |
2a734e17 | 76 | /* devide_id = SDIO_FIRMWARE_FIFO; */ |
554c0a3a HG |
77 | /* break; */ |
78 | ||
79 | case 0x1031: | |
2a734e17 | 80 | devide_id = WLAN_TX_HIQ_DEVICE_ID; |
554c0a3a HG |
81 | break; |
82 | ||
83 | case 0x1032: | |
2a734e17 | 84 | devide_id = WLAN_TX_MIQ_DEVICE_ID; |
554c0a3a HG |
85 | break; |
86 | ||
87 | case 0x1033: | |
2a734e17 | 88 | devide_id = WLAN_TX_LOQ_DEVICE_ID; |
554c0a3a HG |
89 | break; |
90 | ||
91 | case 0x1034: | |
2a734e17 | 92 | devide_id = WLAN_RX0FF_DEVICE_ID; |
554c0a3a HG |
93 | break; |
94 | ||
95 | default: | |
2a734e17 SP |
96 | /* devide_id = (u8)((addr >> 13) & 0xF); */ |
97 | devide_id = WLAN_IOREG_DEVICE_ID; | |
554c0a3a HG |
98 | break; |
99 | } | |
100 | ||
2a734e17 | 101 | return devide_id; |
554c0a3a HG |
102 | } |
103 | ||
104 | /* | |
105 | * Ref: | |
106 | *HalSdioGetCmdAddr8723BSdio() | |
107 | */ | |
2a734e17 | 108 | static u32 _cvrt2ftaddr(const u32 addr, u8 *pdevice_id, u16 *poffset) |
554c0a3a | 109 | { |
2a734e17 | 110 | u8 device_id; |
554c0a3a HG |
111 | u16 offset; |
112 | u32 ftaddr; | |
113 | ||
114 | ||
2a734e17 | 115 | device_id = get_deviceid(addr); |
554c0a3a HG |
116 | offset = 0; |
117 | ||
2a734e17 | 118 | switch (device_id) { |
554c0a3a HG |
119 | case SDIO_LOCAL_DEVICE_ID: |
120 | offset = addr & SDIO_LOCAL_MSK; | |
121 | break; | |
122 | ||
123 | case WLAN_TX_HIQ_DEVICE_ID: | |
124 | case WLAN_TX_MIQ_DEVICE_ID: | |
125 | case WLAN_TX_LOQ_DEVICE_ID: | |
126 | offset = addr & WLAN_FIFO_MSK; | |
127 | break; | |
128 | ||
129 | case WLAN_RX0FF_DEVICE_ID: | |
130 | offset = addr & WLAN_RX0FF_MSK; | |
131 | break; | |
132 | ||
133 | case WLAN_IOREG_DEVICE_ID: | |
134 | default: | |
2a734e17 | 135 | device_id = WLAN_IOREG_DEVICE_ID; |
554c0a3a HG |
136 | offset = addr & WLAN_IOREG_MSK; |
137 | break; | |
138 | } | |
2a734e17 | 139 | ftaddr = (device_id << 13) | offset; |
554c0a3a | 140 | |
2a734e17 SP |
141 | if (pdevice_id) |
142 | *pdevice_id = device_id; | |
554c0a3a HG |
143 | if (poffset) |
144 | *poffset = offset; | |
145 | ||
146 | return ftaddr; | |
147 | } | |
148 | ||
2a734e17 | 149 | static u8 sdio_read8(struct intf_hdl *intfhdl, u32 addr) |
554c0a3a HG |
150 | { |
151 | u32 ftaddr; | |
554c0a3a | 152 | ftaddr = _cvrt2ftaddr(addr, NULL, NULL); |
5826e028 | 153 | |
2a734e17 | 154 | return sd_read8(intfhdl, ftaddr, NULL); |
554c0a3a HG |
155 | } |
156 | ||
2a734e17 | 157 | static u16 sdio_read16(struct intf_hdl *intfhdl, u32 addr) |
554c0a3a HG |
158 | { |
159 | u32 ftaddr; | |
554c0a3a HG |
160 | __le16 le_tmp; |
161 | ||
162 | ftaddr = _cvrt2ftaddr(addr, NULL, NULL); | |
2a734e17 | 163 | sd_cmd52_read(intfhdl, ftaddr, 2, (u8 *)&le_tmp); |
5826e028 SP |
164 | |
165 | return le16_to_cpu(le_tmp); | |
554c0a3a HG |
166 | } |
167 | ||
2a734e17 | 168 | static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr) |
554c0a3a | 169 | { |
2a734e17 SP |
170 | struct adapter *adapter; |
171 | u8 mac_pwr_ctrl_on; | |
172 | u8 device_id; | |
554c0a3a HG |
173 | u16 offset; |
174 | u32 ftaddr; | |
175 | u8 shift; | |
176 | u32 val; | |
177 | s32 err; | |
178 | __le32 le_tmp; | |
179 | ||
2a734e17 SP |
180 | adapter = intfhdl->padapter; |
181 | ftaddr = _cvrt2ftaddr(addr, &device_id, &offset); | |
554c0a3a | 182 | |
2a734e17 | 183 | rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); |
554c0a3a | 184 | if ( |
2a734e17 SP |
185 | ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || |
186 | (!mac_pwr_ctrl_on) || | |
187 | (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) | |
554c0a3a | 188 | ) { |
2a734e17 | 189 | err = sd_cmd52_read(intfhdl, ftaddr, 4, (u8 *)&le_tmp); |
554c0a3a HG |
190 | #ifdef SDIO_DEBUG_IO |
191 | if (!err) { | |
192 | #endif | |
5826e028 | 193 | return le32_to_cpu(le_tmp); |
554c0a3a HG |
194 | #ifdef SDIO_DEBUG_IO |
195 | } | |
196 | ||
197 | DBG_8192C(KERN_ERR "%s: Mac Power off, Read FAIL(%d)! addr = 0x%x\n", __func__, err, addr); | |
198 | return SDIO_ERR_VAL32; | |
199 | #endif | |
200 | } | |
201 | ||
202 | /* 4 bytes alignment */ | |
203 | shift = ftaddr & 0x3; | |
204 | if (shift == 0) { | |
2a734e17 | 205 | val = sd_read32(intfhdl, ftaddr, NULL); |
554c0a3a | 206 | } else { |
2a734e17 | 207 | u8 *tmpbuf; |
554c0a3a | 208 | |
2a734e17 | 209 | tmpbuf = rtw_malloc(8); |
9d03032d | 210 | if (!tmpbuf) { |
554c0a3a HG |
211 | DBG_8192C(KERN_ERR "%s: Allocate memory FAIL!(size =8) addr = 0x%x\n", __func__, addr); |
212 | return SDIO_ERR_VAL32; | |
213 | } | |
214 | ||
215 | ftaddr &= ~(u16)0x3; | |
2a734e17 SP |
216 | sd_read(intfhdl, ftaddr, 8, tmpbuf); |
217 | memcpy(&le_tmp, tmpbuf+shift, 4); | |
554c0a3a HG |
218 | val = le32_to_cpu(le_tmp); |
219 | ||
2a734e17 | 220 | kfree(tmpbuf); |
554c0a3a HG |
221 | } |
222 | return val; | |
223 | } | |
224 | ||
2a734e17 | 225 | static s32 sdio_readN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf) |
554c0a3a | 226 | { |
2a734e17 SP |
227 | struct adapter *adapter; |
228 | u8 mac_pwr_ctrl_on; | |
229 | u8 device_id; | |
554c0a3a HG |
230 | u16 offset; |
231 | u32 ftaddr; | |
232 | u8 shift; | |
233 | s32 err; | |
234 | ||
2a734e17 | 235 | adapter = intfhdl->padapter; |
554c0a3a HG |
236 | err = 0; |
237 | ||
2a734e17 | 238 | ftaddr = _cvrt2ftaddr(addr, &device_id, &offset); |
554c0a3a | 239 | |
2a734e17 | 240 | rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); |
554c0a3a | 241 | if ( |
2a734e17 SP |
242 | ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || |
243 | (!mac_pwr_ctrl_on) || | |
244 | (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) | |
5826e028 | 245 | ) |
2a734e17 | 246 | return sd_cmd52_read(intfhdl, ftaddr, cnt, buf); |
554c0a3a HG |
247 | |
248 | /* 4 bytes alignment */ | |
249 | shift = ftaddr & 0x3; | |
250 | if (shift == 0) { | |
2a734e17 | 251 | err = sd_read(intfhdl, ftaddr, cnt, buf); |
554c0a3a | 252 | } else { |
2a734e17 | 253 | u8 *tmpbuf; |
554c0a3a HG |
254 | u32 n; |
255 | ||
256 | ftaddr &= ~(u16)0x3; | |
257 | n = cnt + shift; | |
2a734e17 | 258 | tmpbuf = rtw_malloc(n); |
9d03032d | 259 | if (!tmpbuf) |
554c0a3a HG |
260 | return -1; |
261 | ||
2a734e17 | 262 | err = sd_read(intfhdl, ftaddr, n, tmpbuf); |
554c0a3a | 263 | if (!err) |
2a734e17 SP |
264 | memcpy(buf, tmpbuf+shift, cnt); |
265 | kfree(tmpbuf); | |
554c0a3a HG |
266 | } |
267 | return err; | |
268 | } | |
269 | ||
2a734e17 | 270 | static s32 sdio_write8(struct intf_hdl *intfhdl, u32 addr, u8 val) |
554c0a3a HG |
271 | { |
272 | u32 ftaddr; | |
273 | s32 err; | |
274 | ||
275 | ftaddr = _cvrt2ftaddr(addr, NULL, NULL); | |
2a734e17 | 276 | sd_write8(intfhdl, ftaddr, val, &err); |
554c0a3a HG |
277 | |
278 | return err; | |
279 | } | |
280 | ||
2a734e17 | 281 | static s32 sdio_write16(struct intf_hdl *intfhdl, u32 addr, u16 val) |
554c0a3a HG |
282 | { |
283 | u32 ftaddr; | |
554c0a3a HG |
284 | __le16 le_tmp; |
285 | ||
286 | ftaddr = _cvrt2ftaddr(addr, NULL, NULL); | |
287 | le_tmp = cpu_to_le16(val); | |
2a734e17 | 288 | return sd_cmd52_write(intfhdl, ftaddr, 2, (u8 *)&le_tmp); |
554c0a3a HG |
289 | } |
290 | ||
2a734e17 | 291 | static s32 sdio_write32(struct intf_hdl *intfhdl, u32 addr, u32 val) |
554c0a3a | 292 | { |
2a734e17 SP |
293 | struct adapter *adapter; |
294 | u8 mac_pwr_ctrl_on; | |
295 | u8 device_id; | |
554c0a3a HG |
296 | u16 offset; |
297 | u32 ftaddr; | |
298 | u8 shift; | |
299 | s32 err; | |
300 | __le32 le_tmp; | |
301 | ||
2a734e17 | 302 | adapter = intfhdl->padapter; |
554c0a3a HG |
303 | err = 0; |
304 | ||
2a734e17 | 305 | ftaddr = _cvrt2ftaddr(addr, &device_id, &offset); |
554c0a3a | 306 | |
2a734e17 | 307 | rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); |
554c0a3a | 308 | if ( |
2a734e17 SP |
309 | ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || |
310 | (!mac_pwr_ctrl_on) || | |
311 | (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) | |
554c0a3a HG |
312 | ) { |
313 | le_tmp = cpu_to_le32(val); | |
5826e028 | 314 | |
2a734e17 | 315 | return sd_cmd52_write(intfhdl, ftaddr, 4, (u8 *)&le_tmp); |
554c0a3a HG |
316 | } |
317 | ||
318 | /* 4 bytes alignment */ | |
319 | shift = ftaddr & 0x3; | |
320 | if (shift == 0) { | |
2a734e17 | 321 | sd_write32(intfhdl, ftaddr, val, &err); |
554c0a3a HG |
322 | } else { |
323 | le_tmp = cpu_to_le32(val); | |
2a734e17 | 324 | err = sd_cmd52_write(intfhdl, ftaddr, 4, (u8 *)&le_tmp); |
554c0a3a HG |
325 | } |
326 | return err; | |
327 | } | |
328 | ||
2a734e17 | 329 | static s32 sdio_writeN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf) |
554c0a3a | 330 | { |
2a734e17 SP |
331 | struct adapter *adapter; |
332 | u8 mac_pwr_ctrl_on; | |
333 | u8 device_id; | |
554c0a3a HG |
334 | u16 offset; |
335 | u32 ftaddr; | |
336 | u8 shift; | |
337 | s32 err; | |
338 | ||
2a734e17 | 339 | adapter = intfhdl->padapter; |
554c0a3a HG |
340 | err = 0; |
341 | ||
2a734e17 | 342 | ftaddr = _cvrt2ftaddr(addr, &device_id, &offset); |
554c0a3a | 343 | |
2a734e17 | 344 | rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); |
554c0a3a | 345 | if ( |
2a734e17 SP |
346 | ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || |
347 | (!mac_pwr_ctrl_on) || | |
348 | (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) | |
5826e028 | 349 | ) |
2a734e17 | 350 | return sd_cmd52_write(intfhdl, ftaddr, cnt, buf); |
554c0a3a HG |
351 | |
352 | shift = ftaddr & 0x3; | |
353 | if (shift == 0) { | |
2a734e17 | 354 | err = sd_write(intfhdl, ftaddr, cnt, buf); |
554c0a3a | 355 | } else { |
2a734e17 | 356 | u8 *tmpbuf; |
554c0a3a HG |
357 | u32 n; |
358 | ||
359 | ftaddr &= ~(u16)0x3; | |
360 | n = cnt + shift; | |
2a734e17 | 361 | tmpbuf = rtw_malloc(n); |
9d03032d | 362 | if (!tmpbuf) |
554c0a3a | 363 | return -1; |
2a734e17 | 364 | err = sd_read(intfhdl, ftaddr, 4, tmpbuf); |
554c0a3a | 365 | if (err) { |
2a734e17 | 366 | kfree(tmpbuf); |
554c0a3a HG |
367 | return err; |
368 | } | |
2a734e17 SP |
369 | memcpy(tmpbuf+shift, buf, cnt); |
370 | err = sd_write(intfhdl, ftaddr, n, tmpbuf); | |
371 | kfree(tmpbuf); | |
554c0a3a HG |
372 | } |
373 | return err; | |
374 | } | |
375 | ||
2a734e17 | 376 | static u8 sdio_f0_read8(struct intf_hdl *intfhdl, u32 addr) |
554c0a3a | 377 | { |
2a734e17 | 378 | return sd_f0_read8(intfhdl, addr, NULL); |
554c0a3a HG |
379 | } |
380 | ||
381 | static void sdio_read_mem( | |
2a734e17 | 382 | struct intf_hdl *intfhdl, |
554c0a3a HG |
383 | u32 addr, |
384 | u32 cnt, | |
385 | u8 *rmem | |
386 | ) | |
387 | { | |
388 | s32 err; | |
389 | ||
2a734e17 | 390 | err = sdio_readN(intfhdl, addr, cnt, rmem); |
554c0a3a HG |
391 | /* TODO: Report error is err not zero */ |
392 | } | |
393 | ||
394 | static void sdio_write_mem( | |
2a734e17 | 395 | struct intf_hdl *intfhdl, |
554c0a3a HG |
396 | u32 addr, |
397 | u32 cnt, | |
398 | u8 *wmem | |
399 | ) | |
400 | { | |
2a734e17 | 401 | sdio_writeN(intfhdl, addr, cnt, wmem); |
554c0a3a HG |
402 | } |
403 | ||
404 | /* | |
405 | * Description: | |
406 | *Read from RX FIFO | |
407 | *Round read size to block size, | |
408 | *and make sure data transfer will be done in one command. | |
409 | * | |
410 | * Parameters: | |
2a734e17 | 411 | *intfhdl a pointer of intf_hdl |
554c0a3a HG |
412 | *addr port ID |
413 | *cnt size to read | |
414 | *rmem address to put data | |
415 | * | |
416 | * Return: | |
417 | *_SUCCESS(1) Success | |
418 | *_FAIL(0) Fail | |
419 | */ | |
420 | static u32 sdio_read_port( | |
2a734e17 | 421 | struct intf_hdl *intfhdl, |
554c0a3a HG |
422 | u32 addr, |
423 | u32 cnt, | |
424 | u8 *mem | |
425 | ) | |
426 | { | |
2a734e17 | 427 | struct adapter *adapter; |
554c0a3a | 428 | PSDIO_DATA psdio; |
2a734e17 | 429 | struct hal_com_data *hal; |
554c0a3a HG |
430 | u32 oldcnt; |
431 | #ifdef SDIO_DYNAMIC_ALLOC_MEM | |
432 | u8 *oldmem; | |
433 | #endif | |
434 | s32 err; | |
435 | ||
436 | ||
2a734e17 SP |
437 | adapter = intfhdl->padapter; |
438 | psdio = &adapter_to_dvobj(adapter)->intf_data; | |
439 | hal = GET_HAL_DATA(adapter); | |
554c0a3a | 440 | |
2a734e17 | 441 | HalSdioGetCmdAddr8723BSdio(adapter, addr, hal->SdioRxFIFOCnt++, &addr); |
554c0a3a HG |
442 | |
443 | oldcnt = cnt; | |
444 | if (cnt > psdio->block_transfer_len) | |
445 | cnt = _RND(cnt, psdio->block_transfer_len); | |
446 | /* cnt = sdio_align_size(cnt); */ | |
447 | ||
2a734e17 | 448 | err = _sd_read(intfhdl, addr, cnt, mem); |
554c0a3a HG |
449 | |
450 | #ifdef SDIO_DYNAMIC_ALLOC_MEM | |
451 | if ((oldcnt != cnt) && (oldmem)) { | |
452 | memcpy(oldmem, mem, oldcnt); | |
453 | kfree(mem); | |
454 | } | |
455 | #endif | |
456 | ||
457 | if (err) | |
458 | return _FAIL; | |
459 | return _SUCCESS; | |
460 | } | |
461 | ||
462 | /* | |
463 | * Description: | |
464 | *Write to TX FIFO | |
465 | *Align write size block size, | |
466 | *and make sure data could be written in one command. | |
467 | * | |
468 | * Parameters: | |
2a734e17 | 469 | *intfhdl a pointer of intf_hdl |
554c0a3a HG |
470 | *addr port ID |
471 | *cnt size to write | |
472 | *wmem data pointer to write | |
473 | * | |
474 | * Return: | |
475 | *_SUCCESS(1) Success | |
476 | *_FAIL(0) Fail | |
477 | */ | |
478 | static u32 sdio_write_port( | |
2a734e17 | 479 | struct intf_hdl *intfhdl, |
554c0a3a HG |
480 | u32 addr, |
481 | u32 cnt, | |
482 | u8 *mem | |
483 | ) | |
484 | { | |
2a734e17 | 485 | struct adapter *adapter; |
554c0a3a HG |
486 | PSDIO_DATA psdio; |
487 | s32 err; | |
488 | struct xmit_buf *xmitbuf = (struct xmit_buf *)mem; | |
489 | ||
2a734e17 SP |
490 | adapter = intfhdl->padapter; |
491 | psdio = &adapter_to_dvobj(adapter)->intf_data; | |
554c0a3a | 492 | |
2a734e17 SP |
493 | if (!adapter->hw_init_completed) { |
494 | DBG_871X("%s [addr = 0x%x cnt =%d] adapter->hw_init_completed == false\n", __func__, addr, cnt); | |
554c0a3a HG |
495 | return _FAIL; |
496 | } | |
497 | ||
498 | cnt = _RND4(cnt); | |
2a734e17 | 499 | HalSdioGetCmdAddr8723BSdio(adapter, addr, cnt >> 2, &addr); |
554c0a3a HG |
500 | |
501 | if (cnt > psdio->block_transfer_len) | |
502 | cnt = _RND(cnt, psdio->block_transfer_len); | |
503 | /* cnt = sdio_align_size(cnt); */ | |
504 | ||
2a734e17 | 505 | err = sd_write(intfhdl, addr, cnt, xmitbuf->pdata); |
554c0a3a HG |
506 | |
507 | rtw_sctx_done_err( | |
508 | &xmitbuf->sctx, | |
509 | err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS | |
510 | ); | |
511 | ||
512 | if (err) | |
513 | return _FAIL; | |
514 | return _SUCCESS; | |
515 | } | |
516 | ||
2a734e17 | 517 | void sdio_set_intf_ops(struct adapter *adapter, struct _io_ops *ops) |
554c0a3a | 518 | { |
2a734e17 SP |
519 | ops->_read8 = &sdio_read8; |
520 | ops->_read16 = &sdio_read16; | |
521 | ops->_read32 = &sdio_read32; | |
522 | ops->_read_mem = &sdio_read_mem; | |
523 | ops->_read_port = &sdio_read_port; | |
524 | ||
525 | ops->_write8 = &sdio_write8; | |
526 | ops->_write16 = &sdio_write16; | |
527 | ops->_write32 = &sdio_write32; | |
528 | ops->_writeN = &sdio_writeN; | |
529 | ops->_write_mem = &sdio_write_mem; | |
530 | ops->_write_port = &sdio_write_port; | |
531 | ||
532 | ops->_sd_f0_read8 = sdio_f0_read8; | |
554c0a3a HG |
533 | } |
534 | ||
535 | /* | |
536 | * Todo: align address to 4 bytes. | |
537 | */ | |
538 | static s32 _sdio_local_read( | |
2a734e17 | 539 | struct adapter *adapter, |
554c0a3a HG |
540 | u32 addr, |
541 | u32 cnt, | |
2a734e17 | 542 | u8 *buf |
554c0a3a HG |
543 | ) |
544 | { | |
2a734e17 SP |
545 | struct intf_hdl *intfhdl; |
546 | u8 mac_pwr_ctrl_on; | |
554c0a3a | 547 | s32 err; |
2a734e17 | 548 | u8 *tmpbuf; |
554c0a3a HG |
549 | u32 n; |
550 | ||
551 | ||
2a734e17 | 552 | intfhdl = &adapter->iopriv.intf; |
554c0a3a | 553 | |
2a734e17 | 554 | HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); |
554c0a3a | 555 | |
2a734e17 SP |
556 | rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); |
557 | if (!mac_pwr_ctrl_on) | |
558 | return _sd_cmd52_read(intfhdl, addr, cnt, buf); | |
554c0a3a HG |
559 | |
560 | n = RND4(cnt); | |
2a734e17 SP |
561 | tmpbuf = rtw_malloc(n); |
562 | if (!tmpbuf) | |
554c0a3a HG |
563 | return (-1); |
564 | ||
2a734e17 | 565 | err = _sd_read(intfhdl, addr, n, tmpbuf); |
554c0a3a | 566 | if (!err) |
2a734e17 | 567 | memcpy(buf, tmpbuf, cnt); |
554c0a3a | 568 | |
2a734e17 | 569 | kfree(tmpbuf); |
554c0a3a HG |
570 | |
571 | return err; | |
572 | } | |
573 | ||
574 | /* | |
575 | * Todo: align address to 4 bytes. | |
576 | */ | |
577 | s32 sdio_local_read( | |
2a734e17 | 578 | struct adapter *adapter, |
554c0a3a HG |
579 | u32 addr, |
580 | u32 cnt, | |
2a734e17 | 581 | u8 *buf |
554c0a3a HG |
582 | ) |
583 | { | |
2a734e17 SP |
584 | struct intf_hdl *intfhdl; |
585 | u8 mac_pwr_ctrl_on; | |
554c0a3a | 586 | s32 err; |
2a734e17 | 587 | u8 *tmpbuf; |
554c0a3a HG |
588 | u32 n; |
589 | ||
2a734e17 | 590 | intfhdl = &adapter->iopriv.intf; |
554c0a3a | 591 | |
2a734e17 | 592 | HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); |
554c0a3a | 593 | |
2a734e17 | 594 | rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); |
554c0a3a | 595 | if ( |
2a734e17 SP |
596 | (!mac_pwr_ctrl_on) || |
597 | (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) | |
5826e028 | 598 | ) |
2a734e17 | 599 | return sd_cmd52_read(intfhdl, addr, cnt, buf); |
554c0a3a HG |
600 | |
601 | n = RND4(cnt); | |
2a734e17 SP |
602 | tmpbuf = rtw_malloc(n); |
603 | if (!tmpbuf) | |
554c0a3a HG |
604 | return (-1); |
605 | ||
2a734e17 | 606 | err = sd_read(intfhdl, addr, n, tmpbuf); |
554c0a3a | 607 | if (!err) |
2a734e17 | 608 | memcpy(buf, tmpbuf, cnt); |
554c0a3a | 609 | |
2a734e17 | 610 | kfree(tmpbuf); |
554c0a3a HG |
611 | |
612 | return err; | |
613 | } | |
614 | ||
615 | /* | |
616 | * Todo: align address to 4 bytes. | |
617 | */ | |
618 | s32 sdio_local_write( | |
2a734e17 | 619 | struct adapter *adapter, |
554c0a3a HG |
620 | u32 addr, |
621 | u32 cnt, | |
2a734e17 | 622 | u8 *buf |
554c0a3a HG |
623 | ) |
624 | { | |
2a734e17 SP |
625 | struct intf_hdl *intfhdl; |
626 | u8 mac_pwr_ctrl_on; | |
554c0a3a | 627 | s32 err; |
2a734e17 | 628 | u8 *tmpbuf; |
554c0a3a HG |
629 | |
630 | if (addr & 0x3) | |
631 | DBG_8192C("%s, address must be 4 bytes alignment\n", __func__); | |
632 | ||
633 | if (cnt & 0x3) | |
634 | DBG_8192C("%s, size must be the multiple of 4\n", __func__); | |
635 | ||
2a734e17 | 636 | intfhdl = &adapter->iopriv.intf; |
554c0a3a | 637 | |
2a734e17 | 638 | HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); |
554c0a3a | 639 | |
2a734e17 | 640 | rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); |
554c0a3a | 641 | if ( |
2a734e17 SP |
642 | (!mac_pwr_ctrl_on) || |
643 | (adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) | |
5826e028 | 644 | ) |
2a734e17 | 645 | return sd_cmd52_write(intfhdl, addr, cnt, buf); |
554c0a3a | 646 | |
2a734e17 SP |
647 | tmpbuf = rtw_malloc(cnt); |
648 | if (!tmpbuf) | |
554c0a3a HG |
649 | return (-1); |
650 | ||
2a734e17 | 651 | memcpy(tmpbuf, buf, cnt); |
554c0a3a | 652 | |
2a734e17 | 653 | err = sd_write(intfhdl, addr, cnt, tmpbuf); |
554c0a3a | 654 | |
2a734e17 | 655 | kfree(tmpbuf); |
554c0a3a HG |
656 | |
657 | return err; | |
658 | } | |
659 | ||
2a734e17 | 660 | u8 SdioLocalCmd52Read1Byte(struct adapter *adapter, u32 addr) |
554c0a3a HG |
661 | { |
662 | u8 val = 0; | |
2a734e17 | 663 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
554c0a3a | 664 | |
2a734e17 SP |
665 | HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); |
666 | sd_cmd52_read(intfhdl, addr, 1, &val); | |
554c0a3a HG |
667 | |
668 | return val; | |
669 | } | |
670 | ||
2a734e17 | 671 | static u16 SdioLocalCmd52Read2Byte(struct adapter *adapter, u32 addr) |
554c0a3a HG |
672 | { |
673 | __le16 val = 0; | |
2a734e17 | 674 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
554c0a3a | 675 | |
2a734e17 SP |
676 | HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); |
677 | sd_cmd52_read(intfhdl, addr, 2, (u8 *)&val); | |
554c0a3a HG |
678 | |
679 | return le16_to_cpu(val); | |
680 | } | |
681 | ||
2a734e17 | 682 | static u32 SdioLocalCmd53Read4Byte(struct adapter *adapter, u32 addr) |
554c0a3a HG |
683 | { |
684 | ||
2a734e17 | 685 | u8 mac_pwr_ctrl_on; |
554c0a3a | 686 | u32 val = 0; |
2a734e17 | 687 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
554c0a3a HG |
688 | __le32 le_tmp; |
689 | ||
2a734e17 SP |
690 | HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); |
691 | rtw_hal_get_hwreg(adapter, HW_VAR_APFM_ON_MAC, &mac_pwr_ctrl_on); | |
692 | if (!mac_pwr_ctrl_on || adapter_to_pwrctl(adapter)->bFwCurrentInPSMode) { | |
693 | sd_cmd52_read(intfhdl, addr, 4, (u8 *)&le_tmp); | |
554c0a3a HG |
694 | val = le32_to_cpu(le_tmp); |
695 | } else { | |
2a734e17 | 696 | val = sd_read32(intfhdl, addr, NULL); |
554c0a3a HG |
697 | } |
698 | return val; | |
699 | } | |
700 | ||
2a734e17 | 701 | void SdioLocalCmd52Write1Byte(struct adapter *adapter, u32 addr, u8 v) |
554c0a3a | 702 | { |
2a734e17 | 703 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
554c0a3a | 704 | |
2a734e17 SP |
705 | HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); |
706 | sd_cmd52_write(intfhdl, addr, 1, &v); | |
554c0a3a HG |
707 | } |
708 | ||
2a734e17 | 709 | static void SdioLocalCmd52Write4Byte(struct adapter *adapter, u32 addr, u32 v) |
554c0a3a | 710 | { |
2a734e17 | 711 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
554c0a3a HG |
712 | __le32 le_tmp; |
713 | ||
2a734e17 | 714 | HalSdioGetCmdAddr8723BSdio(adapter, SDIO_LOCAL_DEVICE_ID, addr, &addr); |
554c0a3a | 715 | le_tmp = cpu_to_le32(v); |
2a734e17 | 716 | sd_cmd52_write(intfhdl, addr, 4, (u8 *)&le_tmp); |
554c0a3a HG |
717 | } |
718 | ||
2a734e17 | 719 | static s32 ReadInterrupt8723BSdio(struct adapter *adapter, u32 *phisr) |
554c0a3a HG |
720 | { |
721 | u32 hisr, himr; | |
722 | u8 val8, hisr_len; | |
723 | ||
724 | ||
9d03032d | 725 | if (!phisr) |
554c0a3a HG |
726 | return false; |
727 | ||
2a734e17 | 728 | himr = GET_HAL_DATA(adapter)->sdio_himr; |
554c0a3a HG |
729 | |
730 | /* decide how many bytes need to be read */ | |
731 | hisr_len = 0; | |
732 | while (himr) { | |
733 | hisr_len++; | |
734 | himr >>= 8; | |
735 | } | |
736 | ||
737 | hisr = 0; | |
738 | while (hisr_len != 0) { | |
739 | hisr_len--; | |
2a734e17 | 740 | val8 = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HISR+hisr_len); |
554c0a3a HG |
741 | hisr |= (val8 << (8*hisr_len)); |
742 | } | |
743 | ||
744 | *phisr = hisr; | |
745 | ||
746 | return true; | |
747 | } | |
748 | ||
749 | /* */ | |
750 | /* Description: */ | |
751 | /* Initialize SDIO Host Interrupt Mask configuration variables for future use. */ | |
752 | /* */ | |
753 | /* Assumption: */ | |
754 | /* Using SDIO Local register ONLY for configuration. */ | |
755 | /* */ | |
756 | /* Created by Roger, 2011.02.11. */ | |
757 | /* */ | |
2a734e17 | 758 | void InitInterrupt8723BSdio(struct adapter *adapter) |
554c0a3a | 759 | { |
2a734e17 | 760 | struct hal_com_data *haldata; |
554c0a3a HG |
761 | |
762 | ||
2a734e17 SP |
763 | haldata = GET_HAL_DATA(adapter); |
764 | haldata->sdio_himr = (u32)( \ | |
554c0a3a HG |
765 | SDIO_HIMR_RX_REQUEST_MSK | |
766 | SDIO_HIMR_AVAL_MSK | | |
767 | /* SDIO_HIMR_TXERR_MSK | */ | |
768 | /* SDIO_HIMR_RXERR_MSK | */ | |
769 | /* SDIO_HIMR_TXFOVW_MSK | */ | |
770 | /* SDIO_HIMR_RXFOVW_MSK | */ | |
771 | /* SDIO_HIMR_TXBCNOK_MSK | */ | |
772 | /* SDIO_HIMR_TXBCNERR_MSK | */ | |
773 | /* SDIO_HIMR_BCNERLY_INT_MSK | */ | |
774 | /* SDIO_HIMR_C2HCMD_MSK | */ | |
775 | /* SDIO_HIMR_HSISR_IND_MSK | */ | |
776 | /* SDIO_HIMR_GTINT3_IND_MSK | */ | |
777 | /* SDIO_HIMR_GTINT4_IND_MSK | */ | |
778 | /* SDIO_HIMR_PSTIMEOUT_MSK | */ | |
779 | /* SDIO_HIMR_OCPINT_MSK | */ | |
780 | /* SDIO_HIMR_ATIMEND_MSK | */ | |
781 | /* SDIO_HIMR_ATIMEND_E_MSK | */ | |
782 | /* SDIO_HIMR_CTWEND_MSK | */ | |
783 | 0); | |
784 | } | |
785 | ||
786 | /* */ | |
787 | /* Description: */ | |
788 | /* Initialize System Host Interrupt Mask configuration variables for future use. */ | |
789 | /* */ | |
790 | /* Created by Roger, 2011.08.03. */ | |
791 | /* */ | |
2a734e17 | 792 | void InitSysInterrupt8723BSdio(struct adapter *adapter) |
554c0a3a | 793 | { |
2a734e17 | 794 | struct hal_com_data *haldata; |
554c0a3a HG |
795 | |
796 | ||
2a734e17 | 797 | haldata = GET_HAL_DATA(adapter); |
554c0a3a | 798 | |
2a734e17 | 799 | haldata->SysIntrMask = ( \ |
554c0a3a HG |
800 | /* HSIMR_GPIO12_0_INT_EN | */ |
801 | /* HSIMR_SPS_OCP_INT_EN | */ | |
802 | /* HSIMR_RON_INT_EN | */ | |
803 | /* HSIMR_PDNINT_EN | */ | |
804 | /* HSIMR_GPIO9_INT_EN | */ | |
805 | 0); | |
806 | } | |
807 | ||
808 | #ifdef CONFIG_WOWLAN | |
809 | /* */ | |
810 | /* Description: */ | |
811 | /* Clear corresponding SDIO Host ISR interrupt service. */ | |
812 | /* */ | |
813 | /* Assumption: */ | |
814 | /* Using SDIO Local register ONLY for configuration. */ | |
815 | /* */ | |
816 | /* Created by Roger, 2011.02.11. */ | |
817 | /* */ | |
2a734e17 | 818 | void clearinterrupt8723bsdio(struct adapter *adapter) |
554c0a3a | 819 | { |
2a734e17 | 820 | struct hal_com_data *haldata; |
554c0a3a HG |
821 | u8 *clear; |
822 | ||
2a734e17 | 823 | if (adapter->bSurpriseRemoved) |
554c0a3a HG |
824 | return; |
825 | ||
2a734e17 | 826 | haldata = GET_HAL_DATA(adapter); |
554c0a3a HG |
827 | clear = rtw_zmalloc(4); |
828 | ||
829 | /* Clear corresponding HISR Content if needed */ | |
2a734e17 | 830 | *(__le32 *)clear = cpu_to_le32(haldata->sdio_hisr & MASK_SDIO_HISR_CLEAR); |
554c0a3a HG |
831 | if (*(__le32 *)clear) { |
832 | /* Perform write one clear operation */ | |
833 | sdio_local_write(padapter, SDIO_REG_HISR, 4, clear); | |
834 | } | |
835 | ||
836 | kfree(clear); | |
837 | } | |
838 | #endif | |
839 | ||
840 | /* */ | |
841 | /* Description: */ | |
842 | /* Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */ | |
843 | /* */ | |
844 | /* Assumption: */ | |
845 | /* 1. Using SDIO Local register ONLY for configuration. */ | |
846 | /* 2. PASSIVE LEVEL */ | |
847 | /* */ | |
848 | /* Created by Roger, 2011.02.11. */ | |
849 | /* */ | |
2a734e17 | 850 | void EnableInterrupt8723BSdio(struct adapter *adapter) |
554c0a3a | 851 | { |
2a734e17 | 852 | struct hal_com_data *haldata; |
554c0a3a HG |
853 | __le32 himr; |
854 | u32 tmp; | |
855 | ||
2a734e17 | 856 | haldata = GET_HAL_DATA(adapter); |
554c0a3a | 857 | |
2a734e17 SP |
858 | himr = cpu_to_le32(haldata->sdio_himr); |
859 | sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&himr); | |
554c0a3a HG |
860 | |
861 | RT_TRACE( | |
862 | _module_hci_ops_c_, | |
863 | _drv_notice_, | |
864 | ( | |
865 | "%s: enable SDIO HIMR = 0x%08X\n", | |
866 | __func__, | |
2a734e17 | 867 | haldata->sdio_himr |
554c0a3a HG |
868 | ) |
869 | ); | |
870 | ||
871 | /* Update current system IMR settings */ | |
2a734e17 SP |
872 | tmp = rtw_read32(adapter, REG_HSIMR); |
873 | rtw_write32(adapter, REG_HSIMR, tmp | haldata->SysIntrMask); | |
554c0a3a HG |
874 | |
875 | RT_TRACE( | |
876 | _module_hci_ops_c_, | |
877 | _drv_notice_, | |
878 | ( | |
879 | "%s: enable HSIMR = 0x%08X\n", | |
880 | __func__, | |
2a734e17 | 881 | haldata->SysIntrMask |
554c0a3a HG |
882 | ) |
883 | ); | |
884 | ||
885 | /* */ | |
886 | /* <Roger_Notes> There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. */ | |
887 | /* So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. */ | |
888 | /* 2011.10.19. */ | |
889 | /* */ | |
2a734e17 | 890 | rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); |
554c0a3a HG |
891 | } |
892 | ||
893 | /* */ | |
894 | /* Description: */ | |
895 | /* Disable SDIO Host IMR configuration to mask unnecessary interrupt service. */ | |
896 | /* */ | |
897 | /* Assumption: */ | |
898 | /* Using SDIO Local register ONLY for configuration. */ | |
899 | /* */ | |
900 | /* Created by Roger, 2011.02.11. */ | |
901 | /* */ | |
2a734e17 | 902 | void DisableInterrupt8723BSdio(struct adapter *adapter) |
554c0a3a HG |
903 | { |
904 | __le32 himr; | |
905 | ||
906 | himr = cpu_to_le32(SDIO_HIMR_DISABLED); | |
2a734e17 | 907 | sdio_local_write(adapter, SDIO_REG_HIMR, 4, (u8 *)&himr); |
554c0a3a HG |
908 | } |
909 | ||
910 | /* */ | |
911 | /* Description: */ | |
912 | /* Using 0x100 to check the power status of FW. */ | |
913 | /* */ | |
914 | /* Assumption: */ | |
915 | /* Using SDIO Local register ONLY for configuration. */ | |
916 | /* */ | |
917 | /* Created by Isaac, 2013.09.10. */ | |
918 | /* */ | |
2a734e17 | 919 | u8 CheckIPSStatus(struct adapter *adapter) |
554c0a3a HG |
920 | { |
921 | DBG_871X( | |
922 | "%s(): Read 0x100 = 0x%02x 0x86 = 0x%02x\n", | |
923 | __func__, | |
2a734e17 SP |
924 | rtw_read8(adapter, 0x100), |
925 | rtw_read8(adapter, 0x86) | |
554c0a3a HG |
926 | ); |
927 | ||
2a734e17 | 928 | if (rtw_read8(adapter, 0x100) == 0xEA) |
554c0a3a HG |
929 | return true; |
930 | else | |
931 | return false; | |
932 | } | |
933 | ||
2a734e17 | 934 | static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size) |
554c0a3a HG |
935 | { |
936 | u32 readsize, ret; | |
2a734e17 SP |
937 | u8 *readbuf; |
938 | struct recv_priv *recv_priv; | |
939 | struct recv_buf *recvbuf; | |
554c0a3a HG |
940 | |
941 | ||
942 | /* Patch for some SDIO Host 4 bytes issue */ | |
943 | /* ex. RK3188 */ | |
944 | readsize = RND4(size); | |
945 | ||
946 | /* 3 1. alloc recvbuf */ | |
2a734e17 SP |
947 | recv_priv = &adapter->recvpriv; |
948 | recvbuf = rtw_dequeue_recvbuf(&recv_priv->free_recv_buf_queue); | |
9d03032d | 949 | if (!recvbuf) { |
554c0a3a HG |
950 | DBG_871X_LEVEL(_drv_err_, "%s: alloc recvbuf FAIL!\n", __func__); |
951 | return NULL; | |
952 | } | |
953 | ||
954 | /* 3 2. alloc skb */ | |
9d03032d | 955 | if (!recvbuf->pskb) { |
554c0a3a HG |
956 | SIZE_PTR tmpaddr = 0; |
957 | SIZE_PTR alignment = 0; | |
958 | ||
2a734e17 | 959 | recvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); |
554c0a3a | 960 | |
2a734e17 SP |
961 | if (recvbuf->pskb) { |
962 | recvbuf->pskb->dev = adapter->pnetdev; | |
554c0a3a | 963 | |
2a734e17 | 964 | tmpaddr = (SIZE_PTR)recvbuf->pskb->data; |
554c0a3a | 965 | alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1); |
2a734e17 | 966 | skb_reserve(recvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment)); |
554c0a3a HG |
967 | } |
968 | ||
9d03032d | 969 | if (!recvbuf->pskb) { |
554c0a3a HG |
970 | DBG_871X("%s: alloc_skb fail! read =%d\n", __func__, readsize); |
971 | return NULL; | |
972 | } | |
973 | } | |
974 | ||
975 | /* 3 3. read data from rxfifo */ | |
2a734e17 SP |
976 | readbuf = recvbuf->pskb->data; |
977 | ret = sdio_read_port(&adapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, readsize, readbuf); | |
554c0a3a HG |
978 | if (ret == _FAIL) { |
979 | RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("%s: read port FAIL!\n", __func__)); | |
980 | return NULL; | |
981 | } | |
982 | ||
983 | ||
984 | /* 3 4. init recvbuf */ | |
2a734e17 SP |
985 | recvbuf->len = size; |
986 | recvbuf->phead = recvbuf->pskb->head; | |
987 | recvbuf->pdata = recvbuf->pskb->data; | |
988 | skb_set_tail_pointer(recvbuf->pskb, size); | |
989 | recvbuf->ptail = skb_tail_pointer(recvbuf->pskb); | |
990 | recvbuf->pend = skb_end_pointer(recvbuf->pskb); | |
991 | ||
992 | return recvbuf; | |
554c0a3a HG |
993 | } |
994 | ||
2a734e17 | 995 | static void sd_rxhandler(struct adapter *adapter, struct recv_buf *recvbuf) |
554c0a3a | 996 | { |
2a734e17 SP |
997 | struct recv_priv *recv_priv; |
998 | struct __queue *pending_queue; | |
554c0a3a | 999 | |
2a734e17 SP |
1000 | recv_priv = &adapter->recvpriv; |
1001 | pending_queue = &recv_priv->recv_buf_pending_queue; | |
554c0a3a HG |
1002 | |
1003 | /* 3 1. enqueue recvbuf */ | |
2a734e17 | 1004 | rtw_enqueue_recvbuf(recvbuf, pending_queue); |
554c0a3a HG |
1005 | |
1006 | /* 3 2. schedule tasklet */ | |
2a734e17 | 1007 | tasklet_schedule(&recv_priv->recv_tasklet); |
554c0a3a HG |
1008 | } |
1009 | ||
2a734e17 | 1010 | void sd_int_dpc(struct adapter *adapter) |
554c0a3a | 1011 | { |
2a734e17 | 1012 | struct hal_com_data *hal; |
554c0a3a | 1013 | struct dvobj_priv *dvobj; |
2a734e17 | 1014 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
554c0a3a HG |
1015 | struct pwrctrl_priv *pwrctl; |
1016 | ||
1017 | ||
2a734e17 SP |
1018 | hal = GET_HAL_DATA(adapter); |
1019 | dvobj = adapter_to_dvobj(adapter); | |
554c0a3a HG |
1020 | pwrctl = dvobj_to_pwrctl(dvobj); |
1021 | ||
2a734e17 | 1022 | if (hal->sdio_hisr & SDIO_HISR_AVAL) { |
554c0a3a HG |
1023 | u8 freepage[4]; |
1024 | ||
2a734e17 | 1025 | _sdio_local_read(adapter, SDIO_REG_FREE_TXPG, 4, freepage); |
09a8ea34 | 1026 | complete(&(adapter->xmitpriv.xmit_comp)); |
554c0a3a HG |
1027 | } |
1028 | ||
2a734e17 | 1029 | if (hal->sdio_hisr & SDIO_HISR_CPWM1) { |
554c0a3a HG |
1030 | struct reportpwrstate_parm report; |
1031 | ||
1032 | u8 bcancelled; | |
1033 | _cancel_timer(&(pwrctl->pwr_rpwm_timer), &bcancelled); | |
1034 | ||
2a734e17 | 1035 | report.state = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HCPWM1_8723B); |
554c0a3a | 1036 | |
2a734e17 | 1037 | /* cpwm_int_hdl(adapter, &report); */ |
554c0a3a HG |
1038 | _set_workitem(&(pwrctl->cpwm_event)); |
1039 | } | |
1040 | ||
2a734e17 | 1041 | if (hal->sdio_hisr & SDIO_HISR_TXERR) { |
554c0a3a HG |
1042 | u8 *status; |
1043 | u32 addr; | |
1044 | ||
1045 | status = rtw_malloc(4); | |
1046 | if (status) { | |
1047 | addr = REG_TXDMA_STATUS; | |
2a734e17 SP |
1048 | HalSdioGetCmdAddr8723BSdio(adapter, WLAN_IOREG_DEVICE_ID, addr, &addr); |
1049 | _sd_read(intfhdl, addr, 4, status); | |
1050 | _sd_write(intfhdl, addr, 4, status); | |
554c0a3a HG |
1051 | DBG_8192C("%s: SDIO_HISR_TXERR (0x%08x)\n", __func__, le32_to_cpu(*(u32 *)status)); |
1052 | kfree(status); | |
1053 | } else { | |
1054 | DBG_8192C("%s: SDIO_HISR_TXERR, but can't allocate memory to read status!\n", __func__); | |
1055 | } | |
1056 | } | |
1057 | ||
2a734e17 | 1058 | if (hal->sdio_hisr & SDIO_HISR_TXBCNOK) { |
554c0a3a HG |
1059 | DBG_8192C("%s: SDIO_HISR_TXBCNOK\n", __func__); |
1060 | } | |
1061 | ||
2a734e17 | 1062 | if (hal->sdio_hisr & SDIO_HISR_TXBCNERR) { |
554c0a3a HG |
1063 | DBG_8192C("%s: SDIO_HISR_TXBCNERR\n", __func__); |
1064 | } | |
1065 | #ifndef CONFIG_C2H_PACKET_EN | |
2a734e17 | 1066 | if (hal->sdio_hisr & SDIO_HISR_C2HCMD) { |
554c0a3a HG |
1067 | struct c2h_evt_hdr_88xx *c2h_evt; |
1068 | ||
1069 | DBG_8192C("%s: C2H Command\n", __func__); | |
2ef2b7c2 | 1070 | c2h_evt = rtw_zmalloc(16); |
554c0a3a | 1071 | if (c2h_evt != NULL) { |
2a734e17 | 1072 | if (rtw_hal_c2h_evt_read(adapter, (u8 *)c2h_evt) == _SUCCESS) { |
554c0a3a HG |
1073 | if (c2h_id_filter_ccx_8723b((u8 *)c2h_evt)) { |
1074 | /* Handle CCX report here */ | |
2a734e17 | 1075 | rtw_hal_c2h_handler(adapter, (u8 *)c2h_evt); |
554c0a3a HG |
1076 | kfree((u8 *)c2h_evt); |
1077 | } else { | |
2a734e17 | 1078 | rtw_c2h_wk_cmd(adapter, (u8 *)c2h_evt); |
554c0a3a HG |
1079 | } |
1080 | } | |
1081 | } else { | |
1082 | /* Error handling for malloc fail */ | |
2a734e17 | 1083 | if (rtw_cbuf_push(adapter->evtpriv.c2h_queue, NULL) != _SUCCESS) |
554c0a3a | 1084 | DBG_871X("%s rtw_cbuf_push fail\n", __func__); |
2a734e17 | 1085 | _set_workitem(&adapter->evtpriv.c2h_wk); |
554c0a3a HG |
1086 | } |
1087 | } | |
1088 | #endif | |
1089 | ||
2a734e17 | 1090 | if (hal->sdio_hisr & SDIO_HISR_RXFOVW) { |
554c0a3a HG |
1091 | DBG_8192C("%s: Rx Overflow\n", __func__); |
1092 | } | |
1093 | ||
2a734e17 | 1094 | if (hal->sdio_hisr & SDIO_HISR_RXERR) { |
554c0a3a HG |
1095 | DBG_8192C("%s: Rx Error\n", __func__); |
1096 | } | |
1097 | ||
2a734e17 SP |
1098 | if (hal->sdio_hisr & SDIO_HISR_RX_REQUEST) { |
1099 | struct recv_buf *recvbuf; | |
554c0a3a HG |
1100 | int alloc_fail_time = 0; |
1101 | u32 hisr; | |
1102 | ||
2a734e17 SP |
1103 | /* DBG_8192C("%s: RX Request, size =%d\n", __func__, hal->SdioRxFIFOSize); */ |
1104 | hal->sdio_hisr ^= SDIO_HISR_RX_REQUEST; | |
554c0a3a | 1105 | do { |
2a734e17 SP |
1106 | hal->SdioRxFIFOSize = SdioLocalCmd52Read2Byte(adapter, SDIO_REG_RX0_REQ_LEN); |
1107 | if (hal->SdioRxFIFOSize != 0) { | |
1108 | recvbuf = sd_recv_rxfifo(adapter, hal->SdioRxFIFOSize); | |
1109 | if (recvbuf) | |
1110 | sd_rxhandler(adapter, recvbuf); | |
554c0a3a HG |
1111 | else { |
1112 | alloc_fail_time++; | |
2a734e17 | 1113 | DBG_871X("recvbuf is Null for %d times because alloc memory failed\n", alloc_fail_time); |
554c0a3a HG |
1114 | if (alloc_fail_time >= 10) |
1115 | break; | |
1116 | } | |
2a734e17 | 1117 | hal->SdioRxFIFOSize = 0; |
554c0a3a HG |
1118 | } else |
1119 | break; | |
1120 | ||
1121 | hisr = 0; | |
2a734e17 | 1122 | ReadInterrupt8723BSdio(adapter, &hisr); |
554c0a3a HG |
1123 | hisr &= SDIO_HISR_RX_REQUEST; |
1124 | if (!hisr) | |
1125 | break; | |
1126 | } while (1); | |
1127 | ||
1128 | if (alloc_fail_time == 10) | |
1129 | DBG_871X("exit because alloc memory failed more than 10 times\n"); | |
1130 | ||
1131 | } | |
1132 | } | |
1133 | ||
2a734e17 | 1134 | void sd_int_hdl(struct adapter *adapter) |
554c0a3a | 1135 | { |
2a734e17 | 1136 | struct hal_com_data *hal; |
554c0a3a HG |
1137 | |
1138 | ||
1139 | if ( | |
2a734e17 | 1140 | (adapter->bDriverStopped) || (adapter->bSurpriseRemoved) |
554c0a3a HG |
1141 | ) |
1142 | return; | |
1143 | ||
2a734e17 | 1144 | hal = GET_HAL_DATA(adapter); |
554c0a3a | 1145 | |
2a734e17 SP |
1146 | hal->sdio_hisr = 0; |
1147 | ReadInterrupt8723BSdio(adapter, &hal->sdio_hisr); | |
554c0a3a | 1148 | |
2a734e17 | 1149 | if (hal->sdio_hisr & hal->sdio_himr) { |
554c0a3a HG |
1150 | u32 v32; |
1151 | ||
2a734e17 | 1152 | hal->sdio_hisr &= hal->sdio_himr; |
554c0a3a HG |
1153 | |
1154 | /* clear HISR */ | |
2a734e17 | 1155 | v32 = hal->sdio_hisr & MASK_SDIO_HISR_CLEAR; |
554c0a3a | 1156 | if (v32) { |
2a734e17 | 1157 | SdioLocalCmd52Write4Byte(adapter, SDIO_REG_HISR, v32); |
554c0a3a HG |
1158 | } |
1159 | ||
2a734e17 | 1160 | sd_int_dpc(adapter); |
554c0a3a HG |
1161 | } else { |
1162 | RT_TRACE(_module_hci_ops_c_, _drv_err_, | |
1163 | ("%s: HISR(0x%08x) and HIMR(0x%08x) not match!\n", | |
2a734e17 | 1164 | __func__, hal->sdio_hisr, hal->sdio_himr)); |
554c0a3a HG |
1165 | } |
1166 | } | |
1167 | ||
1168 | /* */ | |
1169 | /* Description: */ | |
1170 | /* Query SDIO Local register to query current the number of Free TxPacketBuffer page. */ | |
1171 | /* */ | |
1172 | /* Assumption: */ | |
1173 | /* 1. Running at PASSIVE_LEVEL */ | |
1174 | /* 2. RT_TX_SPINLOCK is NOT acquired. */ | |
1175 | /* */ | |
1176 | /* Created by Roger, 2011.01.28. */ | |
1177 | /* */ | |
2a734e17 | 1178 | u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter) |
554c0a3a | 1179 | { |
2a734e17 SP |
1180 | struct hal_com_data *hal; |
1181 | u32 numof_free_page; | |
1182 | /* _irql irql; */ | |
554c0a3a HG |
1183 | |
1184 | ||
2a734e17 | 1185 | hal = GET_HAL_DATA(adapter); |
554c0a3a | 1186 | |
2a734e17 | 1187 | numof_free_page = SdioLocalCmd53Read4Byte(adapter, SDIO_REG_FREE_TXPG); |
554c0a3a HG |
1188 | |
1189 | /* spin_lock_bh(&phal->SdioTxFIFOFreePageLock); */ | |
2a734e17 | 1190 | memcpy(hal->SdioTxFIFOFreePage, &numof_free_page, 4); |
554c0a3a HG |
1191 | RT_TRACE(_module_hci_ops_c_, _drv_notice_, |
1192 | ("%s: Free page for HIQ(%#x), MIDQ(%#x), LOWQ(%#x), PUBQ(%#x)\n", | |
1193 | __func__, | |
2a734e17 SP |
1194 | hal->SdioTxFIFOFreePage[HI_QUEUE_IDX], |
1195 | hal->SdioTxFIFOFreePage[MID_QUEUE_IDX], | |
1196 | hal->SdioTxFIFOFreePage[LOW_QUEUE_IDX], | |
1197 | hal->SdioTxFIFOFreePage[PUBLIC_QUEUE_IDX])); | |
1198 | /* spin_unlock_bh(&hal->SdioTxFIFOFreePageLock); */ | |
554c0a3a HG |
1199 | |
1200 | return true; | |
1201 | } | |
1202 | ||
1203 | /* */ | |
1204 | /* Description: */ | |
1205 | /* Query SDIO Local register to get the current number of TX OQT Free Space. */ | |
1206 | /* */ | |
2a734e17 | 1207 | u8 HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter) |
554c0a3a | 1208 | { |
2a734e17 | 1209 | struct hal_com_data *haldata = GET_HAL_DATA(adapter); |
554c0a3a | 1210 | |
2a734e17 | 1211 | haldata->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_OQT_FREE_PG); |
554c0a3a HG |
1212 | return true; |
1213 | } | |
1214 | ||
1215 | #if defined(CONFIG_WOWLAN) || defined(CONFIG_AP_WOWLAN) | |
2a734e17 | 1216 | u8 RecvOnePkt(struct adapter *adapter, u32 size) |
554c0a3a | 1217 | { |
2a734e17 SP |
1218 | struct recv_buf *recvbuf; |
1219 | struct dvobj_priv *sddev; | |
554c0a3a HG |
1220 | PSDIO_DATA psdio_data; |
1221 | struct sdio_func *func; | |
1222 | ||
1223 | u8 res = false; | |
1224 | ||
1225 | DBG_871X("+%s: size: %d+\n", __func__, size); | |
1226 | ||
9d03032d | 1227 | if (!adapter) { |
2a734e17 | 1228 | DBG_871X(KERN_ERR "%s: adapter is NULL!\n", __func__); |
554c0a3a HG |
1229 | return false; |
1230 | } | |
1231 | ||
2a734e17 SP |
1232 | sddev = adapter_to_dvobj(adapter); |
1233 | psdio_data = &sddev->intf_data; | |
554c0a3a HG |
1234 | func = psdio_data->func; |
1235 | ||
1236 | if (size) { | |
1237 | sdio_claim_host(func); | |
2a734e17 | 1238 | recvbuf = sd_recv_rxfifo(adapter, size); |
554c0a3a | 1239 | |
2a734e17 | 1240 | if (recvbuf) { |
554c0a3a | 1241 | /* printk("Completed Recv One Pkt.\n"); */ |
2a734e17 | 1242 | sd_rxhandler(adapter, recvbuf); |
554c0a3a HG |
1243 | res = true; |
1244 | } else { | |
1245 | res = false; | |
1246 | } | |
1247 | sdio_release_host(func); | |
1248 | } | |
1249 | DBG_871X("-%s-\n", __func__); | |
1250 | return res; | |
1251 | } | |
1252 | #endif /* CONFIG_WOWLAN */ |