xref: /linux/drivers/net/wireless/silabs/wfx/hwio.c (revision 8e07e0e3964ca4e23ce7b68e2096fe660a888942)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Low-level I/O functions.
4  *
5  * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
6  * Copyright (c) 2010, ST-Ericsson
7  */
8 #include <linux/kernel.h>
9 #include <linux/delay.h>
10 #include <linux/slab.h>
11 #include <linux/align.h>
12 
13 #include "hwio.h"
14 #include "wfx.h"
15 #include "bus.h"
16 #include "traces.h"
17 
18 #define WFX_HIF_BUFFER_SIZE 0x2000
19 
20 static int wfx_read32(struct wfx_dev *wdev, int reg, u32 *val)
21 {
22 	int ret;
23 	__le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
24 
25 	*val = ~0; /* Never return undefined value */
26 	if (!tmp)
27 		return -ENOMEM;
28 	ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, tmp, sizeof(u32));
29 	if (ret >= 0)
30 		*val = le32_to_cpu(*tmp);
31 	kfree(tmp);
32 	if (ret)
33 		dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret);
34 	return ret;
35 }
36 
37 static int wfx_write32(struct wfx_dev *wdev, int reg, u32 val)
38 {
39 	int ret;
40 	__le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
41 
42 	if (!tmp)
43 		return -ENOMEM;
44 	*tmp = cpu_to_le32(val);
45 	ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, tmp, sizeof(u32));
46 	kfree(tmp);
47 	if (ret)
48 		dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret);
49 	return ret;
50 }
51 
52 static int wfx_read32_locked(struct wfx_dev *wdev, int reg, u32 *val)
53 {
54 	int ret;
55 
56 	wdev->hwbus_ops->lock(wdev->hwbus_priv);
57 	ret = wfx_read32(wdev, reg, val);
58 	_trace_io_read32(reg, *val);
59 	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
60 	return ret;
61 }
62 
63 static int wfx_write32_locked(struct wfx_dev *wdev, int reg, u32 val)
64 {
65 	int ret;
66 
67 	wdev->hwbus_ops->lock(wdev->hwbus_priv);
68 	ret = wfx_write32(wdev, reg, val);
69 	_trace_io_write32(reg, val);
70 	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
71 	return ret;
72 }
73 
74 static int wfx_write32_bits_locked(struct wfx_dev *wdev, int reg, u32 mask, u32 val)
75 {
76 	int ret;
77 	u32 val_r, val_w;
78 
79 	WARN_ON(~mask & val);
80 	val &= mask;
81 	wdev->hwbus_ops->lock(wdev->hwbus_priv);
82 	ret = wfx_read32(wdev, reg, &val_r);
83 	_trace_io_read32(reg, val_r);
84 	if (ret < 0)
85 		goto err;
86 	val_w = (val_r & ~mask) | val;
87 	if (val_w != val_r) {
88 		ret = wfx_write32(wdev, reg, val_w);
89 		_trace_io_write32(reg, val_w);
90 	}
91 err:
92 	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
93 	return ret;
94 }
95 
96 static int wfx_indirect_read(struct wfx_dev *wdev, int reg, u32 addr, void *buf, size_t len)
97 {
98 	int ret;
99 	int i;
100 	u32 cfg;
101 	u32 prefetch;
102 
103 	WARN_ON(len >= WFX_HIF_BUFFER_SIZE);
104 	WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
105 
106 	if (reg == WFX_REG_AHB_DPORT)
107 		prefetch = CFG_PREFETCH_AHB;
108 	else if (reg == WFX_REG_SRAM_DPORT)
109 		prefetch = CFG_PREFETCH_SRAM;
110 	else
111 		return -ENODEV;
112 
113 	ret = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr);
114 	if (ret < 0)
115 		goto err;
116 
117 	ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg);
118 	if (ret < 0)
119 		goto err;
120 
121 	ret = wfx_write32(wdev, WFX_REG_CONFIG, cfg | prefetch);
122 	if (ret < 0)
123 		goto err;
124 
125 	for (i = 0; i < 20; i++) {
126 		ret = wfx_read32(wdev, WFX_REG_CONFIG, &cfg);
127 		if (ret < 0)
128 			goto err;
129 		if (!(cfg & prefetch))
130 			break;
131 		usleep_range(200, 250);
132 	}
133 	if (i == 20) {
134 		ret = -ETIMEDOUT;
135 		goto err;
136 	}
137 
138 	ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, reg, buf, len);
139 
140 err:
141 	if (ret < 0)
142 		memset(buf, 0xFF, len); /* Never return undefined value */
143 	return ret;
144 }
145 
146 static int wfx_indirect_write(struct wfx_dev *wdev, int reg, u32 addr,
147 			      const void *buf, size_t len)
148 {
149 	int ret;
150 
151 	WARN_ON(len >= WFX_HIF_BUFFER_SIZE);
152 	WARN_ON(reg != WFX_REG_AHB_DPORT && reg != WFX_REG_SRAM_DPORT);
153 	ret = wfx_write32(wdev, WFX_REG_BASE_ADDR, addr);
154 	if (ret < 0)
155 		return ret;
156 
157 	return wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, reg, buf, len);
158 }
159 
160 static int wfx_indirect_read_locked(struct wfx_dev *wdev, int reg, u32 addr,
161 				    void *buf, size_t len)
162 {
163 	int ret;
164 
165 	wdev->hwbus_ops->lock(wdev->hwbus_priv);
166 	ret = wfx_indirect_read(wdev, reg, addr, buf, len);
167 	_trace_io_ind_read(reg, addr, buf, len);
168 	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
169 	return ret;
170 }
171 
172 static int wfx_indirect_write_locked(struct wfx_dev *wdev, int reg, u32 addr,
173 				     const void *buf, size_t len)
174 {
175 	int ret;
176 
177 	wdev->hwbus_ops->lock(wdev->hwbus_priv);
178 	ret = wfx_indirect_write(wdev, reg, addr, buf, len);
179 	_trace_io_ind_write(reg, addr, buf, len);
180 	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
181 	return ret;
182 }
183 
184 static int wfx_indirect_read32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 *val)
185 {
186 	int ret;
187 	__le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
188 
189 	if (!tmp)
190 		return -ENOMEM;
191 	wdev->hwbus_ops->lock(wdev->hwbus_priv);
192 	ret = wfx_indirect_read(wdev, reg, addr, tmp, sizeof(u32));
193 	*val = le32_to_cpu(*tmp);
194 	_trace_io_ind_read32(reg, addr, *val);
195 	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
196 	kfree(tmp);
197 	return ret;
198 }
199 
200 static int wfx_indirect_write32_locked(struct wfx_dev *wdev, int reg, u32 addr, u32 val)
201 {
202 	int ret;
203 	__le32 *tmp = kmalloc(sizeof(u32), GFP_KERNEL);
204 
205 	if (!tmp)
206 		return -ENOMEM;
207 	*tmp = cpu_to_le32(val);
208 	wdev->hwbus_ops->lock(wdev->hwbus_priv);
209 	ret = wfx_indirect_write(wdev, reg, addr, tmp, sizeof(u32));
210 	_trace_io_ind_write32(reg, addr, val);
211 	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
212 	kfree(tmp);
213 	return ret;
214 }
215 
216 int wfx_data_read(struct wfx_dev *wdev, void *buf, size_t len)
217 {
218 	int ret;
219 
220 	WARN(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer");
221 	wdev->hwbus_ops->lock(wdev->hwbus_priv);
222 	ret = wdev->hwbus_ops->copy_from_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len);
223 	_trace_io_read(WFX_REG_IN_OUT_QUEUE, buf, len);
224 	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
225 	if (ret)
226 		dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret);
227 	return ret;
228 }
229 
230 int wfx_data_write(struct wfx_dev *wdev, const void *buf, size_t len)
231 {
232 	int ret;
233 
234 	WARN(!IS_ALIGNED((uintptr_t)buf, 4), "unaligned buffer");
235 	wdev->hwbus_ops->lock(wdev->hwbus_priv);
236 	ret = wdev->hwbus_ops->copy_to_io(wdev->hwbus_priv, WFX_REG_IN_OUT_QUEUE, buf, len);
237 	_trace_io_write(WFX_REG_IN_OUT_QUEUE, buf, len);
238 	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
239 	if (ret)
240 		dev_err(wdev->dev, "%s: bus communication error: %d\n", __func__, ret);
241 	return ret;
242 }
243 
244 int wfx_sram_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
245 {
246 	return wfx_indirect_read_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
247 }
248 
249 int wfx_ahb_buf_read(struct wfx_dev *wdev, u32 addr, void *buf, size_t len)
250 {
251 	return wfx_indirect_read_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
252 }
253 
254 int wfx_sram_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
255 {
256 	return wfx_indirect_write_locked(wdev, WFX_REG_SRAM_DPORT, addr, buf, len);
257 }
258 
259 int wfx_ahb_buf_write(struct wfx_dev *wdev, u32 addr, const void *buf, size_t len)
260 {
261 	return wfx_indirect_write_locked(wdev, WFX_REG_AHB_DPORT, addr, buf, len);
262 }
263 
264 int wfx_sram_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
265 {
266 	return wfx_indirect_read32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
267 }
268 
269 int wfx_ahb_reg_read(struct wfx_dev *wdev, u32 addr, u32 *val)
270 {
271 	return wfx_indirect_read32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
272 }
273 
274 int wfx_sram_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
275 {
276 	return wfx_indirect_write32_locked(wdev, WFX_REG_SRAM_DPORT, addr, val);
277 }
278 
279 int wfx_ahb_reg_write(struct wfx_dev *wdev, u32 addr, u32 val)
280 {
281 	return wfx_indirect_write32_locked(wdev, WFX_REG_AHB_DPORT, addr, val);
282 }
283 
284 int wfx_config_reg_read(struct wfx_dev *wdev, u32 *val)
285 {
286 	return wfx_read32_locked(wdev, WFX_REG_CONFIG, val);
287 }
288 
289 int wfx_config_reg_write(struct wfx_dev *wdev, u32 val)
290 {
291 	return wfx_write32_locked(wdev, WFX_REG_CONFIG, val);
292 }
293 
294 int wfx_config_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
295 {
296 	return wfx_write32_bits_locked(wdev, WFX_REG_CONFIG, mask, val);
297 }
298 
299 int wfx_control_reg_read(struct wfx_dev *wdev, u32 *val)
300 {
301 	return wfx_read32_locked(wdev, WFX_REG_CONTROL, val);
302 }
303 
304 int wfx_control_reg_write(struct wfx_dev *wdev, u32 val)
305 {
306 	return wfx_write32_locked(wdev, WFX_REG_CONTROL, val);
307 }
308 
309 int wfx_control_reg_write_bits(struct wfx_dev *wdev, u32 mask, u32 val)
310 {
311 	return wfx_write32_bits_locked(wdev, WFX_REG_CONTROL, mask, val);
312 }
313 
314 int wfx_igpr_reg_read(struct wfx_dev *wdev, int index, u32 *val)
315 {
316 	int ret;
317 
318 	*val = ~0; /* Never return undefined value */
319 	ret = wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, IGPR_RW | index << 24);
320 	if (ret)
321 		return ret;
322 	ret = wfx_read32_locked(wdev, WFX_REG_SET_GEN_R_W, val);
323 	if (ret)
324 		return ret;
325 	*val &= IGPR_VALUE;
326 	return ret;
327 }
328 
329 int wfx_igpr_reg_write(struct wfx_dev *wdev, int index, u32 val)
330 {
331 	return wfx_write32_locked(wdev, WFX_REG_SET_GEN_R_W, index << 24 | val);
332 }
333