1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved. |
5 | * |
6 | *******************************************************************************/ |
7 | #include <drv_types.h> |
8 | #include <rtw_debug.h> |
9 | #include <rtl8723b_hal.h> |
10 | |
11 | /* */ |
12 | /* Description: */ |
13 | /* The following mapping is for SDIO host local register space. */ |
14 | /* */ |
15 | /* Creadted by Roger, 2011.01.31. */ |
16 | /* */ |
17 | static void hal_sdio_get_cmd_addr_8723b( |
18 | struct adapter *adapter, |
19 | u8 device_id, |
20 | u32 addr, |
21 | u32 *cmdaddr |
22 | ) |
23 | { |
24 | switch (device_id) { |
25 | case SDIO_LOCAL_DEVICE_ID: |
26 | *cmdaddr = ((SDIO_LOCAL_DEVICE_ID << 13) | (addr & SDIO_LOCAL_MSK)); |
27 | break; |
28 | |
29 | case WLAN_IOREG_DEVICE_ID: |
30 | *cmdaddr = ((WLAN_IOREG_DEVICE_ID << 13) | (addr & WLAN_IOREG_MSK)); |
31 | break; |
32 | |
33 | case WLAN_TX_HIQ_DEVICE_ID: |
34 | *cmdaddr = ((WLAN_TX_HIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK)); |
35 | break; |
36 | |
37 | case WLAN_TX_MIQ_DEVICE_ID: |
38 | *cmdaddr = ((WLAN_TX_MIQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK)); |
39 | break; |
40 | |
41 | case WLAN_TX_LOQ_DEVICE_ID: |
42 | *cmdaddr = ((WLAN_TX_LOQ_DEVICE_ID << 13) | (addr & WLAN_FIFO_MSK)); |
43 | break; |
44 | |
45 | case WLAN_RX0FF_DEVICE_ID: |
46 | *cmdaddr = ((WLAN_RX0FF_DEVICE_ID << 13) | (addr & WLAN_RX0FF_MSK)); |
47 | break; |
48 | |
49 | default: |
50 | break; |
51 | } |
52 | } |
53 | |
54 | static u8 get_deviceid(u32 addr) |
55 | { |
56 | u8 devide_id; |
57 | u16 pseudo_id; |
58 | |
59 | pseudo_id = (u16)(addr >> 16); |
60 | switch (pseudo_id) { |
61 | case 0x1025: |
62 | devide_id = SDIO_LOCAL_DEVICE_ID; |
63 | break; |
64 | |
65 | case 0x1026: |
66 | devide_id = WLAN_IOREG_DEVICE_ID; |
67 | break; |
68 | |
69 | case 0x1031: |
70 | devide_id = WLAN_TX_HIQ_DEVICE_ID; |
71 | break; |
72 | |
73 | case 0x1032: |
74 | devide_id = WLAN_TX_MIQ_DEVICE_ID; |
75 | break; |
76 | |
77 | case 0x1033: |
78 | devide_id = WLAN_TX_LOQ_DEVICE_ID; |
79 | break; |
80 | |
81 | case 0x1034: |
82 | devide_id = WLAN_RX0FF_DEVICE_ID; |
83 | break; |
84 | |
85 | default: |
86 | devide_id = WLAN_IOREG_DEVICE_ID; |
87 | break; |
88 | } |
89 | |
90 | return devide_id; |
91 | } |
92 | |
93 | static u32 _cvrt2ftaddr(const u32 addr, u8 *pdevice_id, u16 *poffset) |
94 | { |
95 | u8 device_id; |
96 | u16 offset; |
97 | u32 ftaddr; |
98 | |
99 | device_id = get_deviceid(addr); |
100 | offset = 0; |
101 | |
102 | switch (device_id) { |
103 | case SDIO_LOCAL_DEVICE_ID: |
104 | offset = addr & SDIO_LOCAL_MSK; |
105 | break; |
106 | |
107 | case WLAN_TX_HIQ_DEVICE_ID: |
108 | case WLAN_TX_MIQ_DEVICE_ID: |
109 | case WLAN_TX_LOQ_DEVICE_ID: |
110 | offset = addr & WLAN_FIFO_MSK; |
111 | break; |
112 | |
113 | case WLAN_RX0FF_DEVICE_ID: |
114 | offset = addr & WLAN_RX0FF_MSK; |
115 | break; |
116 | |
117 | case WLAN_IOREG_DEVICE_ID: |
118 | default: |
119 | device_id = WLAN_IOREG_DEVICE_ID; |
120 | offset = addr & WLAN_IOREG_MSK; |
121 | break; |
122 | } |
123 | ftaddr = (device_id << 13) | offset; |
124 | |
125 | if (pdevice_id) |
126 | *pdevice_id = device_id; |
127 | if (poffset) |
128 | *poffset = offset; |
129 | |
130 | return ftaddr; |
131 | } |
132 | |
133 | static u8 sdio_read8(struct intf_hdl *intfhdl, u32 addr) |
134 | { |
135 | u32 ftaddr; |
136 | ftaddr = _cvrt2ftaddr(addr, NULL, NULL); |
137 | |
138 | return sd_read8(pintfhdl: intfhdl, addr: ftaddr, NULL); |
139 | } |
140 | |
141 | static u16 sdio_read16(struct intf_hdl *intfhdl, u32 addr) |
142 | { |
143 | u32 ftaddr; |
144 | __le16 le_tmp; |
145 | |
146 | ftaddr = _cvrt2ftaddr(addr, NULL, NULL); |
147 | sd_cmd52_read(pintfhdl: intfhdl, addr: ftaddr, cnt: 2, pdata: (u8 *)&le_tmp); |
148 | |
149 | return le16_to_cpu(le_tmp); |
150 | } |
151 | |
152 | static u32 sdio_read32(struct intf_hdl *intfhdl, u32 addr) |
153 | { |
154 | struct adapter *adapter; |
155 | u8 mac_pwr_ctrl_on; |
156 | u8 device_id; |
157 | u16 offset; |
158 | u32 ftaddr; |
159 | u8 shift; |
160 | u32 val; |
161 | s32 __maybe_unused err; |
162 | __le32 le_tmp; |
163 | |
164 | adapter = intfhdl->padapter; |
165 | ftaddr = _cvrt2ftaddr(addr, pdevice_id: &device_id, poffset: &offset); |
166 | |
167 | rtw_hal_get_hwreg(padapter: adapter, variable: HW_VAR_APFM_ON_MAC, val: &mac_pwr_ctrl_on); |
168 | if ( |
169 | ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || |
170 | (!mac_pwr_ctrl_on) || |
171 | (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) |
172 | ) { |
173 | err = sd_cmd52_read(pintfhdl: intfhdl, addr: ftaddr, cnt: 4, pdata: (u8 *)&le_tmp); |
174 | return le32_to_cpu(le_tmp); |
175 | } |
176 | |
177 | /* 4 bytes alignment */ |
178 | shift = ftaddr & 0x3; |
179 | if (shift == 0) { |
180 | val = sd_read32(pintfhdl: intfhdl, addr: ftaddr, NULL); |
181 | } else { |
182 | u8 *tmpbuf; |
183 | |
184 | tmpbuf = rtw_malloc(8); |
185 | if (!tmpbuf) |
186 | return SDIO_ERR_VAL32; |
187 | |
188 | ftaddr &= ~(u16)0x3; |
189 | sd_read(pintfhdl: intfhdl, addr: ftaddr, cnt: 8, pdata: tmpbuf); |
190 | memcpy(&le_tmp, tmpbuf + shift, 4); |
191 | val = le32_to_cpu(le_tmp); |
192 | |
193 | kfree(objp: tmpbuf); |
194 | } |
195 | return val; |
196 | } |
197 | |
198 | static s32 sdio_readN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf) |
199 | { |
200 | struct adapter *adapter; |
201 | u8 mac_pwr_ctrl_on; |
202 | u8 device_id; |
203 | u16 offset; |
204 | u32 ftaddr; |
205 | u8 shift; |
206 | s32 err; |
207 | |
208 | adapter = intfhdl->padapter; |
209 | err = 0; |
210 | |
211 | ftaddr = _cvrt2ftaddr(addr, pdevice_id: &device_id, poffset: &offset); |
212 | |
213 | rtw_hal_get_hwreg(padapter: adapter, variable: HW_VAR_APFM_ON_MAC, val: &mac_pwr_ctrl_on); |
214 | if ( |
215 | ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || |
216 | (!mac_pwr_ctrl_on) || |
217 | (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) |
218 | ) |
219 | return sd_cmd52_read(pintfhdl: intfhdl, addr: ftaddr, cnt, pdata: buf); |
220 | |
221 | /* 4 bytes alignment */ |
222 | shift = ftaddr & 0x3; |
223 | if (shift == 0) { |
224 | err = sd_read(pintfhdl: intfhdl, addr: ftaddr, cnt, pdata: buf); |
225 | } else { |
226 | u8 *tmpbuf; |
227 | u32 n; |
228 | |
229 | ftaddr &= ~(u16)0x3; |
230 | n = cnt + shift; |
231 | tmpbuf = rtw_malloc(n); |
232 | if (!tmpbuf) |
233 | return -1; |
234 | |
235 | err = sd_read(pintfhdl: intfhdl, addr: ftaddr, cnt: n, pdata: tmpbuf); |
236 | if (!err) |
237 | memcpy(buf, tmpbuf + shift, cnt); |
238 | kfree(objp: tmpbuf); |
239 | } |
240 | return err; |
241 | } |
242 | |
243 | static s32 sdio_write8(struct intf_hdl *intfhdl, u32 addr, u8 val) |
244 | { |
245 | u32 ftaddr; |
246 | s32 err; |
247 | |
248 | ftaddr = _cvrt2ftaddr(addr, NULL, NULL); |
249 | sd_write8(pintfhdl: intfhdl, addr: ftaddr, v: val, err: &err); |
250 | |
251 | return err; |
252 | } |
253 | |
254 | static s32 sdio_write16(struct intf_hdl *intfhdl, u32 addr, u16 val) |
255 | { |
256 | u32 ftaddr; |
257 | __le16 le_tmp; |
258 | |
259 | ftaddr = _cvrt2ftaddr(addr, NULL, NULL); |
260 | le_tmp = cpu_to_le16(val); |
261 | return sd_cmd52_write(pintfhdl: intfhdl, addr: ftaddr, cnt: 2, pdata: (u8 *)&le_tmp); |
262 | } |
263 | |
264 | static s32 sdio_write32(struct intf_hdl *intfhdl, u32 addr, u32 val) |
265 | { |
266 | struct adapter *adapter; |
267 | u8 mac_pwr_ctrl_on; |
268 | u8 device_id; |
269 | u16 offset; |
270 | u32 ftaddr; |
271 | u8 shift; |
272 | s32 err; |
273 | __le32 le_tmp; |
274 | |
275 | adapter = intfhdl->padapter; |
276 | err = 0; |
277 | |
278 | ftaddr = _cvrt2ftaddr(addr, pdevice_id: &device_id, poffset: &offset); |
279 | |
280 | rtw_hal_get_hwreg(padapter: adapter, variable: HW_VAR_APFM_ON_MAC, val: &mac_pwr_ctrl_on); |
281 | if ( |
282 | ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || |
283 | (!mac_pwr_ctrl_on) || |
284 | (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) |
285 | ) { |
286 | le_tmp = cpu_to_le32(val); |
287 | |
288 | return sd_cmd52_write(pintfhdl: intfhdl, addr: ftaddr, cnt: 4, pdata: (u8 *)&le_tmp); |
289 | } |
290 | |
291 | /* 4 bytes alignment */ |
292 | shift = ftaddr & 0x3; |
293 | if (shift == 0) { |
294 | sd_write32(pintfhdl: intfhdl, addr: ftaddr, v: val, err: &err); |
295 | } else { |
296 | le_tmp = cpu_to_le32(val); |
297 | err = sd_cmd52_write(pintfhdl: intfhdl, addr: ftaddr, cnt: 4, pdata: (u8 *)&le_tmp); |
298 | } |
299 | return err; |
300 | } |
301 | |
302 | static s32 sdio_writeN(struct intf_hdl *intfhdl, u32 addr, u32 cnt, u8 *buf) |
303 | { |
304 | struct adapter *adapter; |
305 | u8 mac_pwr_ctrl_on; |
306 | u8 device_id; |
307 | u16 offset; |
308 | u32 ftaddr; |
309 | u8 shift; |
310 | s32 err; |
311 | |
312 | adapter = intfhdl->padapter; |
313 | err = 0; |
314 | |
315 | ftaddr = _cvrt2ftaddr(addr, pdevice_id: &device_id, poffset: &offset); |
316 | |
317 | rtw_hal_get_hwreg(padapter: adapter, variable: HW_VAR_APFM_ON_MAC, val: &mac_pwr_ctrl_on); |
318 | if ( |
319 | ((device_id == WLAN_IOREG_DEVICE_ID) && (offset < 0x100)) || |
320 | (!mac_pwr_ctrl_on) || |
321 | (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) |
322 | ) |
323 | return sd_cmd52_write(pintfhdl: intfhdl, addr: ftaddr, cnt, pdata: buf); |
324 | |
325 | shift = ftaddr & 0x3; |
326 | if (shift == 0) { |
327 | err = sd_write(pintfhdl: intfhdl, addr: ftaddr, cnt, pdata: buf); |
328 | } else { |
329 | u8 *tmpbuf; |
330 | u32 n; |
331 | |
332 | ftaddr &= ~(u16)0x3; |
333 | n = cnt + shift; |
334 | tmpbuf = rtw_malloc(n); |
335 | if (!tmpbuf) |
336 | return -1; |
337 | err = sd_read(pintfhdl: intfhdl, addr: ftaddr, cnt: 4, pdata: tmpbuf); |
338 | if (err) { |
339 | kfree(objp: tmpbuf); |
340 | return err; |
341 | } |
342 | memcpy(tmpbuf + shift, buf, cnt); |
343 | err = sd_write(pintfhdl: intfhdl, addr: ftaddr, cnt: n, pdata: tmpbuf); |
344 | kfree(objp: tmpbuf); |
345 | } |
346 | return err; |
347 | } |
348 | |
349 | static void sdio_read_mem( |
350 | struct intf_hdl *intfhdl, |
351 | u32 addr, |
352 | u32 cnt, |
353 | u8 *rmem |
354 | ) |
355 | { |
356 | sdio_readN(intfhdl, addr, cnt, buf: rmem); |
357 | } |
358 | |
359 | static void sdio_write_mem( |
360 | struct intf_hdl *intfhdl, |
361 | u32 addr, |
362 | u32 cnt, |
363 | u8 *wmem |
364 | ) |
365 | { |
366 | sdio_writeN(intfhdl, addr, cnt, buf: wmem); |
367 | } |
368 | |
369 | /* |
370 | * Description: |
371 | *Read from RX FIFO |
372 | *Round read size to block size, |
373 | *and make sure data transfer will be done in one command. |
374 | * |
375 | * Parameters: |
376 | *intfhdl a pointer of intf_hdl |
377 | *addr port ID |
378 | *cnt size to read |
379 | *rmem address to put data |
380 | * |
381 | * Return: |
382 | *_SUCCESS(1) Success |
383 | *_FAIL(0) Fail |
384 | */ |
385 | static u32 sdio_read_port( |
386 | struct intf_hdl *intfhdl, |
387 | u32 addr, |
388 | u32 cnt, |
389 | u8 *mem |
390 | ) |
391 | { |
392 | struct adapter *adapter; |
393 | struct sdio_data *psdio; |
394 | struct hal_com_data *hal; |
395 | s32 err; |
396 | |
397 | adapter = intfhdl->padapter; |
398 | psdio = &adapter_to_dvobj(adapter)->intf_data; |
399 | hal = GET_HAL_DATA(adapter); |
400 | |
401 | hal_sdio_get_cmd_addr_8723b(adapter, device_id: addr, addr: hal->SdioRxFIFOCnt++, cmdaddr: &addr); |
402 | |
403 | if (cnt > psdio->block_transfer_len) |
404 | cnt = _RND(cnt, psdio->block_transfer_len); |
405 | |
406 | err = _sd_read(pintfhdl: intfhdl, addr, cnt, pdata: mem); |
407 | |
408 | if (err) |
409 | return _FAIL; |
410 | return _SUCCESS; |
411 | } |
412 | |
413 | /* |
414 | * Description: |
415 | *Write to TX FIFO |
416 | *Align write size block size, |
417 | *and make sure data could be written in one command. |
418 | * |
419 | * Parameters: |
420 | *intfhdl a pointer of intf_hdl |
421 | *addr port ID |
422 | *cnt size to write |
423 | *wmem data pointer to write |
424 | * |
425 | * Return: |
426 | *_SUCCESS(1) Success |
427 | *_FAIL(0) Fail |
428 | */ |
429 | static u32 sdio_write_port( |
430 | struct intf_hdl *intfhdl, |
431 | u32 addr, |
432 | u32 cnt, |
433 | u8 *mem |
434 | ) |
435 | { |
436 | struct adapter *adapter; |
437 | struct sdio_data *psdio; |
438 | s32 err; |
439 | struct xmit_buf *xmitbuf = (struct xmit_buf *)mem; |
440 | |
441 | adapter = intfhdl->padapter; |
442 | psdio = &adapter_to_dvobj(adapter)->intf_data; |
443 | |
444 | if (!adapter->hw_init_completed) |
445 | return _FAIL; |
446 | |
447 | cnt = round_up(cnt, 4); |
448 | hal_sdio_get_cmd_addr_8723b(adapter, device_id: addr, addr: cnt >> 2, cmdaddr: &addr); |
449 | |
450 | if (cnt > psdio->block_transfer_len) |
451 | cnt = _RND(cnt, psdio->block_transfer_len); |
452 | |
453 | err = sd_write(pintfhdl: intfhdl, addr, cnt, pdata: xmitbuf->pdata); |
454 | |
455 | rtw_sctx_done_err( |
456 | sctx: &xmitbuf->sctx, |
457 | status: err ? RTW_SCTX_DONE_WRITE_PORT_ERR : RTW_SCTX_DONE_SUCCESS |
458 | ); |
459 | |
460 | if (err) |
461 | return _FAIL; |
462 | return _SUCCESS; |
463 | } |
464 | |
465 | void sdio_set_intf_ops(struct adapter *adapter, struct _io_ops *ops) |
466 | { |
467 | ops->_read8 = &sdio_read8; |
468 | ops->_read16 = &sdio_read16; |
469 | ops->_read32 = &sdio_read32; |
470 | ops->_read_mem = &sdio_read_mem; |
471 | ops->_read_port = &sdio_read_port; |
472 | |
473 | ops->_write8 = &sdio_write8; |
474 | ops->_write16 = &sdio_write16; |
475 | ops->_write32 = &sdio_write32; |
476 | ops->_writeN = &sdio_writeN; |
477 | ops->_write_mem = &sdio_write_mem; |
478 | ops->_write_port = &sdio_write_port; |
479 | } |
480 | |
481 | /* |
482 | * Todo: align address to 4 bytes. |
483 | */ |
484 | static s32 _sdio_local_read( |
485 | struct adapter *adapter, |
486 | u32 addr, |
487 | u32 cnt, |
488 | u8 *buf |
489 | ) |
490 | { |
491 | struct intf_hdl *intfhdl; |
492 | u8 mac_pwr_ctrl_on; |
493 | s32 err; |
494 | u8 *tmpbuf; |
495 | u32 n; |
496 | |
497 | intfhdl = &adapter->iopriv.intf; |
498 | |
499 | hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, cmdaddr: &addr); |
500 | |
501 | rtw_hal_get_hwreg(padapter: adapter, variable: HW_VAR_APFM_ON_MAC, val: &mac_pwr_ctrl_on); |
502 | if (!mac_pwr_ctrl_on) |
503 | return _sd_cmd52_read(pintfhdl: intfhdl, addr, cnt, pdata: buf); |
504 | |
505 | n = round_up(cnt, 4); |
506 | tmpbuf = rtw_malloc(n); |
507 | if (!tmpbuf) |
508 | return -1; |
509 | |
510 | err = _sd_read(pintfhdl: intfhdl, addr, cnt: n, pdata: tmpbuf); |
511 | if (!err) |
512 | memcpy(buf, tmpbuf, cnt); |
513 | |
514 | kfree(objp: tmpbuf); |
515 | |
516 | return err; |
517 | } |
518 | |
519 | /* |
520 | * Todo: align address to 4 bytes. |
521 | */ |
522 | s32 sdio_local_read( |
523 | struct adapter *adapter, |
524 | u32 addr, |
525 | u32 cnt, |
526 | u8 *buf |
527 | ) |
528 | { |
529 | struct intf_hdl *intfhdl; |
530 | u8 mac_pwr_ctrl_on; |
531 | s32 err; |
532 | u8 *tmpbuf; |
533 | u32 n; |
534 | |
535 | intfhdl = &adapter->iopriv.intf; |
536 | |
537 | hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, cmdaddr: &addr); |
538 | |
539 | rtw_hal_get_hwreg(padapter: adapter, variable: HW_VAR_APFM_ON_MAC, val: &mac_pwr_ctrl_on); |
540 | if ( |
541 | (!mac_pwr_ctrl_on) || |
542 | (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) |
543 | ) |
544 | return sd_cmd52_read(pintfhdl: intfhdl, addr, cnt, pdata: buf); |
545 | |
546 | n = round_up(cnt, 4); |
547 | tmpbuf = rtw_malloc(n); |
548 | if (!tmpbuf) |
549 | return -1; |
550 | |
551 | err = sd_read(pintfhdl: intfhdl, addr, cnt: n, pdata: tmpbuf); |
552 | if (!err) |
553 | memcpy(buf, tmpbuf, cnt); |
554 | |
555 | kfree(objp: tmpbuf); |
556 | |
557 | return err; |
558 | } |
559 | |
560 | /* |
561 | * Todo: align address to 4 bytes. |
562 | */ |
563 | s32 sdio_local_write( |
564 | struct adapter *adapter, |
565 | u32 addr, |
566 | u32 cnt, |
567 | u8 *buf |
568 | ) |
569 | { |
570 | struct intf_hdl *intfhdl; |
571 | u8 mac_pwr_ctrl_on; |
572 | s32 err; |
573 | u8 *tmpbuf; |
574 | |
575 | intfhdl = &adapter->iopriv.intf; |
576 | |
577 | hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, cmdaddr: &addr); |
578 | |
579 | rtw_hal_get_hwreg(padapter: adapter, variable: HW_VAR_APFM_ON_MAC, val: &mac_pwr_ctrl_on); |
580 | if ( |
581 | (!mac_pwr_ctrl_on) || |
582 | (adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) |
583 | ) |
584 | return sd_cmd52_write(pintfhdl: intfhdl, addr, cnt, pdata: buf); |
585 | |
586 | tmpbuf = rtw_malloc(cnt); |
587 | if (!tmpbuf) |
588 | return -1; |
589 | |
590 | memcpy(tmpbuf, buf, cnt); |
591 | |
592 | err = sd_write(pintfhdl: intfhdl, addr, cnt, pdata: tmpbuf); |
593 | |
594 | kfree(objp: tmpbuf); |
595 | |
596 | return err; |
597 | } |
598 | |
599 | u8 SdioLocalCmd52Read1Byte(struct adapter *adapter, u32 addr) |
600 | { |
601 | u8 val = 0; |
602 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
603 | |
604 | hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, cmdaddr: &addr); |
605 | sd_cmd52_read(pintfhdl: intfhdl, addr, cnt: 1, pdata: &val); |
606 | |
607 | return val; |
608 | } |
609 | |
610 | static u16 sdio_local_cmd52_read2byte(struct adapter *adapter, u32 addr) |
611 | { |
612 | __le16 val = 0; |
613 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
614 | |
615 | hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, cmdaddr: &addr); |
616 | sd_cmd52_read(pintfhdl: intfhdl, addr, cnt: 2, pdata: (u8 *)&val); |
617 | |
618 | return le16_to_cpu(val); |
619 | } |
620 | |
621 | static u32 sdio_local_cmd53_read4byte(struct adapter *adapter, u32 addr) |
622 | { |
623 | |
624 | u8 mac_pwr_ctrl_on; |
625 | u32 val = 0; |
626 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
627 | __le32 le_tmp; |
628 | |
629 | hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, cmdaddr: &addr); |
630 | rtw_hal_get_hwreg(padapter: adapter, variable: HW_VAR_APFM_ON_MAC, val: &mac_pwr_ctrl_on); |
631 | if (!mac_pwr_ctrl_on || adapter_to_pwrctl(adapter)->fw_current_in_ps_mode) { |
632 | sd_cmd52_read(pintfhdl: intfhdl, addr, cnt: 4, pdata: (u8 *)&le_tmp); |
633 | val = le32_to_cpu(le_tmp); |
634 | } else { |
635 | val = sd_read32(pintfhdl: intfhdl, addr, NULL); |
636 | } |
637 | return val; |
638 | } |
639 | |
640 | void SdioLocalCmd52Write1Byte(struct adapter *adapter, u32 addr, u8 v) |
641 | { |
642 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
643 | |
644 | hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, cmdaddr: &addr); |
645 | sd_cmd52_write(pintfhdl: intfhdl, addr, cnt: 1, pdata: &v); |
646 | } |
647 | |
648 | static void sdio_local_cmd52_write4byte(struct adapter *adapter, u32 addr, u32 v) |
649 | { |
650 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
651 | __le32 le_tmp; |
652 | |
653 | hal_sdio_get_cmd_addr_8723b(adapter, SDIO_LOCAL_DEVICE_ID, addr, cmdaddr: &addr); |
654 | le_tmp = cpu_to_le32(v); |
655 | sd_cmd52_write(pintfhdl: intfhdl, addr, cnt: 4, pdata: (u8 *)&le_tmp); |
656 | } |
657 | |
658 | static s32 read_interrupt_8723b_sdio(struct adapter *adapter, u32 *phisr) |
659 | { |
660 | u32 hisr, himr; |
661 | u8 val8, hisr_len; |
662 | |
663 | if (!phisr) |
664 | return false; |
665 | |
666 | himr = GET_HAL_DATA(adapter)->sdio_himr; |
667 | |
668 | /* decide how many bytes need to be read */ |
669 | hisr_len = 0; |
670 | while (himr) { |
671 | hisr_len++; |
672 | himr >>= 8; |
673 | } |
674 | |
675 | hisr = 0; |
676 | while (hisr_len != 0) { |
677 | hisr_len--; |
678 | val8 = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HISR + hisr_len); |
679 | hisr |= (val8 << (8 * hisr_len)); |
680 | } |
681 | |
682 | *phisr = hisr; |
683 | |
684 | return true; |
685 | } |
686 | |
687 | /* */ |
688 | /* Description: */ |
689 | /* Initialize SDIO Host Interrupt Mask configuration variables for future use. */ |
690 | /* */ |
691 | /* Assumption: */ |
692 | /* Using SDIO Local register ONLY for configuration. */ |
693 | /* */ |
694 | /* Created by Roger, 2011.02.11. */ |
695 | /* */ |
696 | void InitInterrupt8723BSdio(struct adapter *adapter) |
697 | { |
698 | struct hal_com_data *haldata; |
699 | |
700 | haldata = GET_HAL_DATA(adapter); |
701 | haldata->sdio_himr = (u32)(SDIO_HIMR_RX_REQUEST_MSK | |
702 | SDIO_HIMR_AVAL_MSK | |
703 | 0); |
704 | } |
705 | |
706 | /* */ |
707 | /* Description: */ |
708 | /* Initialize System Host Interrupt Mask configuration variables for future use. */ |
709 | /* */ |
710 | /* Created by Roger, 2011.08.03. */ |
711 | /* */ |
712 | void InitSysInterrupt8723BSdio(struct adapter *adapter) |
713 | { |
714 | struct hal_com_data *haldata; |
715 | |
716 | haldata = GET_HAL_DATA(adapter); |
717 | |
718 | haldata->SysIntrMask = (0); |
719 | } |
720 | |
721 | /* */ |
722 | /* Description: */ |
723 | /* Enalbe SDIO Host Interrupt Mask configuration on SDIO local domain. */ |
724 | /* */ |
725 | /* Assumption: */ |
726 | /* 1. Using SDIO Local register ONLY for configuration. */ |
727 | /* 2. PASSIVE LEVEL */ |
728 | /* */ |
729 | /* Created by Roger, 2011.02.11. */ |
730 | /* */ |
731 | void EnableInterrupt8723BSdio(struct adapter *adapter) |
732 | { |
733 | struct hal_com_data *haldata; |
734 | __le32 himr; |
735 | u32 tmp; |
736 | |
737 | haldata = GET_HAL_DATA(adapter); |
738 | |
739 | himr = cpu_to_le32(haldata->sdio_himr); |
740 | sdio_local_write(adapter, SDIO_REG_HIMR, cnt: 4, buf: (u8 *)&himr); |
741 | |
742 | /* Update current system IMR settings */ |
743 | tmp = rtw_read32(adapter, REG_HSIMR); |
744 | rtw_write32(adapter, REG_HSIMR, val: tmp | haldata->SysIntrMask); |
745 | |
746 | /* */ |
747 | /* <Roger_Notes> There are some C2H CMDs have been sent before system interrupt is enabled, e.g., C2H, CPWM. */ |
748 | /* So we need to clear all C2H events that FW has notified, otherwise FW won't schedule any commands anymore. */ |
749 | /* 2011.10.19. */ |
750 | /* */ |
751 | rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE); |
752 | } |
753 | |
754 | /* */ |
755 | /* Description: */ |
756 | /* Disable SDIO Host IMR configuration to mask unnecessary interrupt service. */ |
757 | /* */ |
758 | /* Assumption: */ |
759 | /* Using SDIO Local register ONLY for configuration. */ |
760 | /* */ |
761 | /* Created by Roger, 2011.02.11. */ |
762 | /* */ |
763 | void DisableInterrupt8723BSdio(struct adapter *adapter) |
764 | { |
765 | __le32 himr; |
766 | |
767 | himr = cpu_to_le32(SDIO_HIMR_DISABLED); |
768 | sdio_local_write(adapter, SDIO_REG_HIMR, cnt: 4, buf: (u8 *)&himr); |
769 | } |
770 | |
771 | /* */ |
772 | /* Description: */ |
773 | /* Using 0x100 to check the power status of FW. */ |
774 | /* */ |
775 | /* Assumption: */ |
776 | /* Using SDIO Local register ONLY for configuration. */ |
777 | /* */ |
778 | /* Created by Isaac, 2013.09.10. */ |
779 | /* */ |
780 | u8 CheckIPSStatus(struct adapter *adapter) |
781 | { |
782 | if (rtw_read8(adapter, addr: 0x100) == 0xEA) |
783 | return true; |
784 | else |
785 | return false; |
786 | } |
787 | |
788 | static struct recv_buf *sd_recv_rxfifo(struct adapter *adapter, u32 size) |
789 | { |
790 | u32 readsize, ret; |
791 | u8 *readbuf; |
792 | struct recv_priv *recv_priv; |
793 | struct recv_buf *recvbuf; |
794 | |
795 | /* Patch for some SDIO Host 4 bytes issue */ |
796 | /* ex. RK3188 */ |
797 | readsize = round_up(size, 4); |
798 | |
799 | /* 3 1. alloc recvbuf */ |
800 | recv_priv = &adapter->recvpriv; |
801 | recvbuf = rtw_dequeue_recvbuf(queue: &recv_priv->free_recv_buf_queue); |
802 | if (!recvbuf) { |
803 | netdev_err(dev: adapter->pnetdev, format: "%s: alloc recvbuf FAIL!\n" , |
804 | __func__); |
805 | return NULL; |
806 | } |
807 | |
808 | /* 3 2. alloc skb */ |
809 | if (!recvbuf->pskb) { |
810 | SIZE_PTR tmpaddr = 0; |
811 | SIZE_PTR alignment = 0; |
812 | |
813 | recvbuf->pskb = rtw_skb_alloc(MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ); |
814 | if (!recvbuf->pskb) |
815 | return NULL; |
816 | |
817 | recvbuf->pskb->dev = adapter->pnetdev; |
818 | |
819 | tmpaddr = (SIZE_PTR)recvbuf->pskb->data; |
820 | alignment = tmpaddr & (RECVBUFF_ALIGN_SZ - 1); |
821 | skb_reserve(skb: recvbuf->pskb, len: (RECVBUFF_ALIGN_SZ - alignment)); |
822 | } |
823 | |
824 | /* 3 3. read data from rxfifo */ |
825 | readbuf = recvbuf->pskb->data; |
826 | ret = sdio_read_port(intfhdl: &adapter->iopriv.intf, WLAN_RX0FF_DEVICE_ID, cnt: readsize, mem: readbuf); |
827 | if (ret == _FAIL) |
828 | return NULL; |
829 | |
830 | /* 3 4. init recvbuf */ |
831 | recvbuf->len = size; |
832 | recvbuf->phead = recvbuf->pskb->head; |
833 | recvbuf->pdata = recvbuf->pskb->data; |
834 | skb_set_tail_pointer(skb: recvbuf->pskb, offset: size); |
835 | recvbuf->ptail = skb_tail_pointer(skb: recvbuf->pskb); |
836 | recvbuf->pend = skb_end_pointer(skb: recvbuf->pskb); |
837 | |
838 | return recvbuf; |
839 | } |
840 | |
841 | static void sd_rxhandler(struct adapter *adapter, struct recv_buf *recvbuf) |
842 | { |
843 | struct recv_priv *recv_priv; |
844 | struct __queue *pending_queue; |
845 | |
846 | recv_priv = &adapter->recvpriv; |
847 | pending_queue = &recv_priv->recv_buf_pending_queue; |
848 | |
849 | /* 3 1. enqueue recvbuf */ |
850 | rtw_enqueue_recvbuf(precvbuf: recvbuf, queue: pending_queue); |
851 | |
852 | /* 3 2. schedule tasklet */ |
853 | tasklet_schedule(t: &recv_priv->recv_tasklet); |
854 | } |
855 | |
856 | void sd_int_dpc(struct adapter *adapter) |
857 | { |
858 | struct hal_com_data *hal; |
859 | struct dvobj_priv *dvobj; |
860 | struct intf_hdl *intfhdl = &adapter->iopriv.intf; |
861 | struct pwrctrl_priv *pwrctl; |
862 | |
863 | hal = GET_HAL_DATA(adapter); |
864 | dvobj = adapter_to_dvobj(adapter); |
865 | pwrctl = dvobj_to_pwrctl(dvobj); |
866 | |
867 | if (hal->sdio_hisr & SDIO_HISR_AVAL) { |
868 | u8 freepage[4]; |
869 | |
870 | _sdio_local_read(adapter, SDIO_REG_FREE_TXPG, cnt: 4, buf: freepage); |
871 | complete(&(adapter->xmitpriv.xmit_comp)); |
872 | } |
873 | |
874 | if (hal->sdio_hisr & SDIO_HISR_CPWM1) { |
875 | del_timer_sync(timer: &(pwrctl->pwr_rpwm_timer)); |
876 | |
877 | SdioLocalCmd52Read1Byte(adapter, SDIO_REG_HCPWM1_8723B); |
878 | |
879 | _set_workitem(pwork: &(pwrctl->cpwm_event)); |
880 | } |
881 | |
882 | if (hal->sdio_hisr & SDIO_HISR_TXERR) { |
883 | u8 *status; |
884 | u32 addr; |
885 | |
886 | status = rtw_malloc(4); |
887 | if (status) { |
888 | addr = REG_TXDMA_STATUS; |
889 | hal_sdio_get_cmd_addr_8723b(adapter, WLAN_IOREG_DEVICE_ID, addr, cmdaddr: &addr); |
890 | _sd_read(pintfhdl: intfhdl, addr, cnt: 4, pdata: status); |
891 | _sd_write(pintfhdl: intfhdl, addr, cnt: 4, pdata: status); |
892 | kfree(objp: status); |
893 | } |
894 | } |
895 | |
896 | if (hal->sdio_hisr & SDIO_HISR_C2HCMD) { |
897 | struct c2h_evt_hdr_88xx *c2h_evt; |
898 | |
899 | c2h_evt = rtw_zmalloc(16); |
900 | if (c2h_evt) { |
901 | if (c2h_evt_read_88xx(adapter, buf: (u8 *)c2h_evt) == _SUCCESS) { |
902 | if (c2h_id_filter_ccx_8723b(buf: (u8 *)c2h_evt)) { |
903 | /* Handle CCX report here */ |
904 | rtw_hal_c2h_handler(adapter, c2h_evt: (u8 *)c2h_evt); |
905 | kfree(objp: c2h_evt); |
906 | } else { |
907 | rtw_c2h_wk_cmd(padapter: adapter, c2h_evt: (u8 *)c2h_evt); |
908 | } |
909 | } else { |
910 | kfree(objp: c2h_evt); |
911 | } |
912 | } else { |
913 | /* Error handling for malloc fail */ |
914 | rtw_cbuf_push(cbuf: adapter->evtpriv.c2h_queue, NULL); |
915 | _set_workitem(pwork: &adapter->evtpriv.c2h_wk); |
916 | } |
917 | } |
918 | |
919 | if (hal->sdio_hisr & SDIO_HISR_RX_REQUEST) { |
920 | struct recv_buf *recvbuf; |
921 | int alloc_fail_time = 0; |
922 | u32 hisr; |
923 | |
924 | hal->sdio_hisr ^= SDIO_HISR_RX_REQUEST; |
925 | do { |
926 | hal->SdioRxFIFOSize = sdio_local_cmd52_read2byte(adapter, SDIO_REG_RX0_REQ_LEN); |
927 | if (hal->SdioRxFIFOSize != 0) { |
928 | recvbuf = sd_recv_rxfifo(adapter, size: hal->SdioRxFIFOSize); |
929 | if (recvbuf) |
930 | sd_rxhandler(adapter, recvbuf); |
931 | else { |
932 | alloc_fail_time++; |
933 | if (alloc_fail_time >= 10) |
934 | break; |
935 | } |
936 | hal->SdioRxFIFOSize = 0; |
937 | } else |
938 | break; |
939 | |
940 | hisr = 0; |
941 | read_interrupt_8723b_sdio(adapter, phisr: &hisr); |
942 | hisr &= SDIO_HISR_RX_REQUEST; |
943 | if (!hisr) |
944 | break; |
945 | } while (1); |
946 | } |
947 | } |
948 | |
949 | void sd_int_hdl(struct adapter *adapter) |
950 | { |
951 | struct hal_com_data *hal; |
952 | |
953 | if ( |
954 | (adapter->bDriverStopped) || (adapter->bSurpriseRemoved) |
955 | ) |
956 | return; |
957 | |
958 | hal = GET_HAL_DATA(adapter); |
959 | |
960 | hal->sdio_hisr = 0; |
961 | read_interrupt_8723b_sdio(adapter, phisr: &hal->sdio_hisr); |
962 | |
963 | if (hal->sdio_hisr & hal->sdio_himr) { |
964 | u32 v32; |
965 | |
966 | hal->sdio_hisr &= hal->sdio_himr; |
967 | |
968 | /* clear HISR */ |
969 | v32 = hal->sdio_hisr & MASK_SDIO_HISR_CLEAR; |
970 | if (v32) |
971 | sdio_local_cmd52_write4byte(adapter, SDIO_REG_HISR, v: v32); |
972 | |
973 | sd_int_dpc(adapter); |
974 | } |
975 | } |
976 | |
977 | /* */ |
978 | /* Description: */ |
979 | /* Query SDIO Local register to query current the number of Free TxPacketBuffer page. */ |
980 | /* */ |
981 | /* Assumption: */ |
982 | /* 1. Running at PASSIVE_LEVEL */ |
983 | /* 2. RT_TX_SPINLOCK is NOT acquired. */ |
984 | /* */ |
985 | /* Created by Roger, 2011.01.28. */ |
986 | /* */ |
987 | u8 HalQueryTxBufferStatus8723BSdio(struct adapter *adapter) |
988 | { |
989 | struct hal_com_data *hal; |
990 | u32 numof_free_page; |
991 | |
992 | hal = GET_HAL_DATA(adapter); |
993 | |
994 | numof_free_page = sdio_local_cmd53_read4byte(adapter, SDIO_REG_FREE_TXPG); |
995 | |
996 | memcpy(hal->SdioTxFIFOFreePage, &numof_free_page, 4); |
997 | |
998 | return true; |
999 | } |
1000 | |
1001 | /* */ |
1002 | /* Description: */ |
1003 | /* Query SDIO Local register to get the current number of TX OQT Free Space. */ |
1004 | /* */ |
1005 | void HalQueryTxOQTBufferStatus8723BSdio(struct adapter *adapter) |
1006 | { |
1007 | struct hal_com_data *haldata = GET_HAL_DATA(adapter); |
1008 | |
1009 | haldata->SdioTxOQTFreeSpace = SdioLocalCmd52Read1Byte(adapter, SDIO_REG_OQT_FREE_PG); |
1010 | } |
1011 | |
1012 | |
1013 | |