1 /******************************************************************************
2 *
3 * Copyright(c) 2015 - 2016 Realtek Corporation. All rights reserved.
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 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 *
19 ******************************************************************************/
20 #define _RTL8822BE_IO_C_
21
22 #include <drv_types.h> /* PADAPTER and etc. */
23
24 #ifdef RTK_129X_PLATFORM
25 #include <soc/realtek/rtd129x_lockapi.h>
26
27 #define IO_2K_MASK 0xFFFFF800
28 #define IO_4K_MASK 0xFFFFF000
29 #define MAX_RETRY 5
30
pci_io_read_129x(struct dvobj_priv * pdvobjpriv,u32 addr,u8 size)31 static u32 pci_io_read_129x(struct dvobj_priv *pdvobjpriv, u32 addr, u8 size)
32 {
33 unsigned long mask_addr = pdvobjpriv->mask_addr;
34 unsigned long tran_addr = pdvobjpriv->tran_addr;
35 u8 busnumber = pdvobjpriv->pcipriv.busnumber;
36 u32 rval = 0;
37 u32 mask;
38 u32 translate_val = 0;
39 u32 tmp_addr = addr & 0xFFF;
40 _irqL irqL;
41 u32 pci_error_status = 0;
42 int retry_cnt = 0;
43 unsigned long flags;
44
45 _enter_critical(&pdvobjpriv->io_reg_lock, &irqL);
46
47 /* PCIE1.1 0x9804FCEC, PCIE2.0 0x9803CCEC & 0x9803CC68
48 * can't be used because of 1295 hardware issue.
49 */
50 if ((tmp_addr == 0xCEC) || ((busnumber == 0x01) &&
51 (tmp_addr == 0xC68))) {
52 mask = IO_2K_MASK;
53 writel(0xFFFFF800, (u8 *)mask_addr);
54 translate_val = readl((u8 *)tran_addr);
55 writel(translate_val|(addr&mask), (u8 *)tran_addr);
56 } else if (addr >= 0x1000) {
57 mask = IO_4K_MASK;
58 translate_val = readl((u8 *)tran_addr);
59 writel(translate_val|(addr&mask), (u8 *)tran_addr);
60 } else
61 mask = 0x0;
62
63 pci_read_129x_retry:
64
65 /* All RBUS1 driver need to have a workaround for emmc hardware error */
66 /* Need to protect 0xXXXX_X8XX~ 0xXXXX_X9XX */
67 if ((tmp_addr>0x7FF) && (tmp_addr<0xA00))
68 rtk_lockapi_lock(flags, __func__);
69
70 switch (size) {
71 case 1:
72 rval = readb((u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
73 break;
74 case 2:
75 rval = readw((u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
76 break;
77 case 4:
78 rval = readl((u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
79 break;
80 default:
81 RTW_WARN("RTD129X: %s: wrong size %d\n", __func__, size);
82 break;
83 }
84
85 if ((tmp_addr>0x7FF) && (tmp_addr<0xA00))
86 rtk_lockapi_unlock(flags, __func__);
87
88 //DLLP error patch
89 pci_error_status = readl( (u8 *)(pdvobjpriv->ctrl_start + 0x7C));
90 if(pci_error_status & 0x1F) {
91 writel(pci_error_status, (u8 *)(pdvobjpriv->ctrl_start + 0x7C));
92 RTW_WARN("RTD129X: %s: DLLP(#%d) 0x%x reg=0x%x val=0x%x\n", __func__, retry_cnt, pci_error_status, addr, rval);
93
94 if(retry_cnt < MAX_RETRY) {
95 retry_cnt++;
96 goto pci_read_129x_retry;
97 }
98 }
99
100 /* PCIE1.1 0x9804FCEC, PCIE2.0 0x9803CCEC & 0x9803CC68
101 * can't be used because of 1295 hardware issue.
102 */
103 if ((tmp_addr == 0xCEC) || ((busnumber == 0x01) &&
104 (tmp_addr == 0xC68))) {
105 writel(translate_val, (u8 *)tran_addr);
106 writel(0xFFFFF000, (u8 *)mask_addr);
107 } else if (addr >= 0x1000) {
108 writel(translate_val, (u8 *)tran_addr);
109 }
110
111 _exit_critical(&pdvobjpriv->io_reg_lock, &irqL);
112
113 return rval;
114 }
115
pci_io_write_129x(struct dvobj_priv * pdvobjpriv,u32 addr,u8 size,u32 wval)116 static void pci_io_write_129x(struct dvobj_priv *pdvobjpriv,
117 u32 addr, u8 size, u32 wval)
118 {
119 unsigned long mask_addr = pdvobjpriv->mask_addr;
120 unsigned long tran_addr = pdvobjpriv->tran_addr;
121 u8 busnumber = pdvobjpriv->pcipriv.busnumber;
122 u32 mask;
123 u32 translate_val = 0;
124 u32 tmp_addr = addr & 0xFFF;
125 _irqL irqL;
126 unsigned long flags;
127
128 _enter_critical(&pdvobjpriv->io_reg_lock, &irqL);
129
130 /* PCIE1.1 0x9804FCEC, PCIE2.0 0x9803CCEC & 0x9803CC68
131 * can't be used because of 1295 hardware issue.
132 */
133 if ((tmp_addr == 0xCEC) || ((busnumber == 0x01) &&
134 (tmp_addr == 0xC68))) {
135 mask = IO_2K_MASK;
136 writel(0xFFFFF800, (u8 *)mask_addr);
137 translate_val = readl((u8 *)tran_addr);
138 writel(translate_val|(addr&mask), (u8 *)tran_addr);
139 } else if (addr >= 0x1000) {
140 mask = IO_4K_MASK;
141 translate_val = readl((u8 *)tran_addr);
142 writel(translate_val|(addr&mask), (u8 *)tran_addr);
143 } else
144 mask = 0x0;
145
146 /* All RBUS1 driver need to have a workaround for emmc hardware error */
147 /* Need to protect 0xXXXX_X8XX~ 0xXXXX_X9XX */
148 if ((tmp_addr>0x7FF) && (tmp_addr<0xA00))
149 rtk_lockapi_lock(flags, __func__);
150
151 switch (size) {
152 case 1:
153 writeb((u8)wval,
154 (u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
155 break;
156 case 2:
157 writew((u16)wval,
158 (u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
159 break;
160 case 4:
161 writel((u32)wval,
162 (u8 *)pdvobjpriv->pci_mem_start + (addr&~mask));
163 break;
164 default:
165 RTW_WARN("RTD129X: %s: wrong size %d\n", __func__, size);
166 break;
167 }
168
169 if ((tmp_addr>0x7FF) && (tmp_addr<0xA00))
170 rtk_lockapi_unlock(flags, __func__);
171
172 /* PCIE1.1 0x9804FCEC, PCIE2.0 0x9803CCEC & 0x9803CC68
173 * can't be used because of 1295 hardware issue.
174 */
175 if ((tmp_addr == 0xCEC) || ((busnumber == 0x01) &&
176 (tmp_addr == 0xC68))) {
177 writel(translate_val, (u8 *)tran_addr);
178 writel(0xFFFFF000, (u8 *)mask_addr);
179 } else if (addr >= 0x1000) {
180 writel(translate_val, (u8 *)tran_addr);
181 }
182
183 _exit_critical(&pdvobjpriv->io_reg_lock, &irqL);
184 }
185
pci_read8_129x(struct intf_hdl * phdl,u32 addr)186 static u8 pci_read8_129x(struct intf_hdl *phdl, u32 addr)
187 {
188 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
189
190 return (u8)pci_io_read_129x(pdvobjpriv, addr, 1);
191 }
192
pci_read16_129x(struct intf_hdl * phdl,u32 addr)193 static u16 pci_read16_129x(struct intf_hdl *phdl, u32 addr)
194 {
195 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
196
197 return (u16)pci_io_read_129x(pdvobjpriv, addr, 2);
198 }
199
pci_read32_129x(struct intf_hdl * phdl,u32 addr)200 static u32 pci_read32_129x(struct intf_hdl *phdl, u32 addr)
201 {
202 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
203
204 return (u32)pci_io_read_129x(pdvobjpriv, addr, 4);
205 }
206
207 /*
208 * 2009.12.23. by tynli. Suggested by SD1 victorh.
209 * For ASPM hang on AMD and Nvidia.
210 * 20100212 Tynli: Do read IO operation after write for
211 * all PCI bridge suggested by SD1. Origianally this is only for INTEL.
212 */
pci_write8_129x(struct intf_hdl * phdl,u32 addr,u8 val)213 static int pci_write8_129x(struct intf_hdl *phdl, u32 addr, u8 val)
214 {
215 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
216
217 pci_io_write_129x(pdvobjpriv, addr, 1, val);
218 return 1;
219 }
220
pci_write16_129x(struct intf_hdl * phdl,u32 addr,u16 val)221 static int pci_write16_129x(struct intf_hdl *phdl, u32 addr, u16 val)
222 {
223 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
224
225 pci_io_write_129x(pdvobjpriv, addr, 2, val);
226 return 2;
227 }
228
pci_write32_129x(struct intf_hdl * phdl,u32 addr,u32 val)229 static int pci_write32_129x(struct intf_hdl *phdl, u32 addr, u32 val)
230 {
231 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
232
233 pci_io_write_129x(pdvobjpriv, addr, 4, val);
234 return 4;
235 }
236
237 #else /* original*/
238
pci_read8(struct intf_hdl * phdl,u32 addr)239 static u8 pci_read8(struct intf_hdl *phdl, u32 addr)
240 {
241 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
242
243 return 0xff & readb((u8 *)pdvobjpriv->pci_mem_start + addr);
244 }
245
pci_read16(struct intf_hdl * phdl,u32 addr)246 static u16 pci_read16(struct intf_hdl *phdl, u32 addr)
247 {
248 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
249
250 return readw((u8 *)pdvobjpriv->pci_mem_start + addr);
251 }
252
pci_read32(struct intf_hdl * phdl,u32 addr)253 static u32 pci_read32(struct intf_hdl *phdl, u32 addr)
254 {
255 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
256
257 return readl((u8 *)pdvobjpriv->pci_mem_start + addr);
258 }
259
260 /*
261 * 2009.12.23. by tynli. Suggested by SD1 victorh.
262 * For ASPM hang on AMD and Nvidia.
263 * 20100212 Tynli: Do read IO operation after write for
264 * all PCI bridge suggested by SD1. Origianally this is only for INTEL.
265 */
pci_write8(struct intf_hdl * phdl,u32 addr,u8 val)266 static int pci_write8(struct intf_hdl *phdl, u32 addr, u8 val)
267 {
268 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
269
270 writeb(val, (u8 *)pdvobjpriv->pci_mem_start + addr);
271 return 1;
272 }
273
pci_write16(struct intf_hdl * phdl,u32 addr,u16 val)274 static int pci_write16(struct intf_hdl *phdl, u32 addr, u16 val)
275 {
276 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
277
278 writew(val, (u8 *)pdvobjpriv->pci_mem_start + addr);
279 return 2;
280 }
281
pci_write32(struct intf_hdl * phdl,u32 addr,u32 val)282 static int pci_write32(struct intf_hdl *phdl, u32 addr, u32 val)
283 {
284 struct dvobj_priv *pdvobjpriv = (struct dvobj_priv *)phdl->pintf_dev;
285
286 writel(val, (u8 *)pdvobjpriv->pci_mem_start + addr);
287 return 4;
288 }
289 #endif /* RTK_129X_PLATFORM */
290
pci_read_mem(struct intf_hdl * phdl,u32 addr,u32 cnt,u8 * rmem)291 static void pci_read_mem(struct intf_hdl *phdl, u32 addr, u32 cnt, u8 *rmem)
292 {
293 RTW_INFO("%s(%d)fake function\n", __func__, __LINE__);
294 }
295
pci_write_mem(struct intf_hdl * phdl,u32 addr,u32 cnt,u8 * wmem)296 static void pci_write_mem(struct intf_hdl *phdl, u32 addr, u32 cnt, u8 *wmem)
297 {
298 RTW_INFO("%s(%d)fake function\n", __func__, __LINE__);
299 }
300
pci_read_port(struct intf_hdl * phdl,u32 addr,u32 cnt,u8 * rmem)301 static u32 pci_read_port(struct intf_hdl *phdl, u32 addr, u32 cnt, u8 *rmem)
302 {
303 return 0;
304 }
305
pci_write_port(struct intf_hdl * phdl,u32 addr,u32 cnt,u8 * wmem)306 static u32 pci_write_port(struct intf_hdl *phdl, u32 addr, u32 cnt, u8 *wmem)
307 {
308 _adapter *padapter = (_adapter *)phdl->padapter;
309
310 padapter->pnetdev->trans_start = jiffies;
311
312 return 0;
313 }
314
rtl8822be_set_intf_ops(struct _io_ops * pops)315 void rtl8822be_set_intf_ops(struct _io_ops *pops)
316 {
317 _func_enter_;
318
319 _rtw_memset((u8 *)pops, 0, sizeof(struct _io_ops));
320
321 #ifdef RTK_129X_PLATFORM
322 pops->_read8 = &pci_read8_129x;
323 pops->_read16 = &pci_read16_129x;
324 pops->_read32 = &pci_read32_129x;
325 #else
326 pops->_read8 = &pci_read8;
327 pops->_read16 = &pci_read16;
328 pops->_read32 = &pci_read32;
329 #endif /* RTK_129X_PLATFORM */
330
331 pops->_read_mem = &pci_read_mem;
332 pops->_read_port = &pci_read_port;
333
334 #ifdef RTK_129X_PLATFORM
335 pops->_write8 = &pci_write8_129x;
336 pops->_write16 = &pci_write16_129x;
337 pops->_write32 = &pci_write32_129x;
338 #else
339 pops->_write8 = &pci_write8;
340 pops->_write16 = &pci_write16;
341 pops->_write32 = &pci_write32;
342 #endif /* RTK_129X_PLATFORM */
343
344 pops->_write_mem = &pci_write_mem;
345 pops->_write_port = &pci_write_port;
346
347 _func_exit_;
348
349 }
350