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
20static 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
37static 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
52static 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
63static 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
74static 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	}
91err:
92	wdev->hwbus_ops->unlock(wdev->hwbus_priv);
93	return ret;
94}
95
96static 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
140err:
141	if (ret < 0)
142		memset(buf, 0xFF, len); /* Never return undefined value */
143	return ret;
144}
145
146static 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
160static 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
172static 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
184static 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
200static 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
216int 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
230int 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
244int 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
249int 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
254int 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
259int 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
264int 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
269int 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
274int 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
279int 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
284int wfx_config_reg_read(struct wfx_dev *wdev, u32 *val)
285{
286	return wfx_read32_locked(wdev, WFX_REG_CONFIG, val);
287}
288
289int wfx_config_reg_write(struct wfx_dev *wdev, u32 val)
290{
291	return wfx_write32_locked(wdev, WFX_REG_CONFIG, val);
292}
293
294int 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
299int wfx_control_reg_read(struct wfx_dev *wdev, u32 *val)
300{
301	return wfx_read32_locked(wdev, WFX_REG_CONTROL, val);
302}
303
304int wfx_control_reg_write(struct wfx_dev *wdev, u32 val)
305{
306	return wfx_write32_locked(wdev, WFX_REG_CONTROL, val);
307}
308
309int 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
314int 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
329int 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