1 /******************************************************************************
2 *
3 * Copyright(c) 2019 Realtek Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 *****************************************************************************/
15 #define _RTW_SDIO_C_
16
17 #include <drv_types.h> /* struct dvobj_priv and etc. */
18 #include <drv_types_sdio.h> /* RTW_SDIO_ADDR_CMD52_GEN */
19
20 /*
21 * Description:
22 * Use SDIO cmd52 or cmd53 to read/write data
23 *
24 * Parameters:
25 * d pointer of device object(struct dvobj_priv)
26 * addr SDIO address, 17 bits
27 * buf buffer for I/O
28 * len length
29 * write 0:read, 1:write
30 * cmd52 0:cmd52, 1:cmd53
31 *
32 * Return:
33 * _SUCCESS I/O ok.
34 * _FAIL I/O fail.
35 */
sdio_io(struct dvobj_priv * d,u32 addr,void * buf,size_t len,u8 write,u8 cmd52)36 static u8 sdio_io(struct dvobj_priv *d, u32 addr, void *buf, size_t len, u8 write, u8 cmd52)
37 {
38 #ifdef DBG_SDIO
39 #if (DBG_SDIO >= 3)
40 struct sdio_data *sdio = dvobj_to_sdio(d);
41 #endif /* DBG_SDIO >= 3 */
42 #endif /* DBG_SDIO */
43 u32 addr_drv; /* address with driver defined bit */
44 int err;
45 u8 retry = 0;
46 u8 stop_retry = _FALSE; /* flag for stopping retry or not */
47
48 if (dev_is_surprise_removed(d)) {
49 RTW_ERR("%s: bSurpriseRemoved, skip %s 0x%05x, %zu bytes\n",
50 __FUNCTION__, write?"write":"read", addr, len);
51 return _FAIL;
52 }
53
54 addr_drv = addr;
55 if (cmd52)
56 addr_drv = RTW_SDIO_ADDR_CMD52_GEN(addr_drv);
57
58 do {
59 if (write)
60 err = d->intf_ops->write(d, addr_drv, buf, len, 0);
61 else
62 err = d->intf_ops->read(d, addr_drv, buf, len, 0);
63 if (!err) {
64 if (retry) {
65 RTW_INFO("%s: Retry %s OK! addr=0x%05x %zu bytes, retry=%u,%u\n",
66 __FUNCTION__, write?"write":"read",
67 addr, len, retry, ATOMIC_READ(&d->continual_io_error));
68 RTW_INFO_DUMP("Data: ", buf, len);
69 }
70 rtw_reset_continual_io_error(d);
71 break;
72 }
73 RTW_ERR("%s: %s FAIL! error(%d) addr=0x%05x %zu bytes, retry=%u,%u\n",
74 __FUNCTION__, write?"write":"read", err, addr, len,
75 retry, ATOMIC_READ(&d->continual_io_error));
76
77 #ifdef DBG_SDIO
78 #if (DBG_SDIO >= 3)
79 if (sdio->dbg_enable) {
80 if (sdio->err_test && sdio->err_test_triggered)
81 sdio->err_test = 0;
82
83 if (sdio->err_stop) {
84 RTW_ERR("%s: I/O error! Set surprise remove flag ON!\n",
85 __FUNCTION__);
86 dev_set_surprise_removed(d);
87 return _FAIL;
88 }
89 }
90 #endif /* DBG_SDIO >= 3 */
91 #endif /* DBG_SDIO */
92
93 retry++;
94 stop_retry = rtw_inc_and_chk_continual_io_error(d);
95 if ((err == -1) || (stop_retry == _TRUE) || (retry > SD_IO_TRY_CNT)) {
96 /* critical error, unrecoverable */
97 RTW_ERR("%s: Fatal error! Set surprise remove flag ON! (retry=%u,%u)\n",
98 __FUNCTION__, retry, ATOMIC_READ(&d->continual_io_error));
99 dev_set_surprise_removed(d);
100 return _FAIL;
101 }
102
103 /* WLAN IOREG or SDIO Local */
104 if ((addr & 0x10000) || !(addr & 0xE000)) {
105 RTW_WARN("%s: Retry %s addr=0x%05x %zu bytes, retry=%u,%u\n",
106 __FUNCTION__, write?"write":"read", addr, len,
107 retry, ATOMIC_READ(&d->continual_io_error));
108 continue;
109 }
110 return _FAIL;
111 } while (1);
112
113 return _SUCCESS;
114 }
115
rtw_sdio_read_cmd52(struct dvobj_priv * d,u32 addr,void * buf,size_t len)116 u8 rtw_sdio_read_cmd52(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
117 {
118 return sdio_io(d, addr, buf, len, 0, 1);
119 }
120
rtw_sdio_read_cmd53(struct dvobj_priv * d,u32 addr,void * buf,size_t len)121 u8 rtw_sdio_read_cmd53(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
122 {
123 return sdio_io(d, addr, buf, len, 0, 0);
124 }
125
rtw_sdio_write_cmd52(struct dvobj_priv * d,u32 addr,void * buf,size_t len)126 u8 rtw_sdio_write_cmd52(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
127 {
128 return sdio_io(d, addr, buf, len, 1, 1);
129 }
130
rtw_sdio_write_cmd53(struct dvobj_priv * d,u32 addr,void * buf,size_t len)131 u8 rtw_sdio_write_cmd53(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
132 {
133 return sdio_io(d, addr, buf, len, 1, 0);
134 }
135
rtw_sdio_f0_read(struct dvobj_priv * d,u32 addr,void * buf,size_t len)136 u8 rtw_sdio_f0_read(struct dvobj_priv *d, u32 addr, void *buf, size_t len)
137 {
138 int err;
139 u8 ret;
140
141
142 ret = _SUCCESS;
143 addr = RTW_SDIO_ADDR_F0_GEN(addr);
144
145 err = d->intf_ops->read(d, addr, buf, len, 0);
146 if (err)
147 ret = _FAIL;
148
149 return ret;
150 }
151
152 /**
153 * rtw_sdio_cmd53_align_size() - Align size to one CMD53 could complete
154 * @d struct dvobj_priv*
155 * @len length to align
156 *
157 * Adjust len to align block size, and the new size could be transfered by one
158 * CMD53.
159 * If len < block size, it would keep original value, otherwise the value
160 * would be rounded up by block size.
161 *
162 * Return adjusted length.
163 */
rtw_sdio_cmd53_align_size(struct dvobj_priv * d,size_t len)164 size_t rtw_sdio_cmd53_align_size(struct dvobj_priv *d, size_t len)
165 {
166 u32 blk_sz;
167
168
169 blk_sz = rtw_sdio_get_block_size(d);
170 if (len <= blk_sz)
171 return len;
172
173 return _RND(len, blk_sz);
174 }
175