xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/hif_io32.h (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2015-2021 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #ifndef __HIF_IO32_H__
20 #define __HIF_IO32_H__
21 
22 #include <linux/io.h>
23 #include "hif.h"
24 #include "hif_main.h"
25 #include "pld_common.h"
26 /* Device memory is 32MB but bar size is only 1MB.
27  * Register remapping logic is used to access 32MB device memory.
28  * 0-512KB : Fixed address, 512KB-1MB : remapped address.
29  * Use PCIE_REMAP_1M_BAR_CTRL register to set window
30  * for pcie based wifi chipsets.
31  */
32 #define MAX_UNWINDOWED_ADDRESS 0x80000
33 #if defined(QCA_WIFI_QCA6390) || defined(QCA_WIFI_QCA6490) || \
34 	defined(QCA_WIFI_QCN9000) || defined(QCA_WIFI_QCA6750) || \
35 	defined(QCA_WIFI_QCN9224) || defined(QCA_WIFI_WCN7850)
36 #define WINDOW_ENABLE_BIT 0x40000000
37 #else
38 #define WINDOW_ENABLE_BIT 0x80000000
39 #endif
40 #define WINDOW_REG_ADDRESS 0x310C
41 #define WINDOW_SHIFT 19
42 #define WINDOW_VALUE_MASK 0x3F
43 #define WINDOW_START MAX_UNWINDOWED_ADDRESS
44 #define WINDOW_RANGE_MASK 0x7FFFF
45 
46 #if defined(HIF_REG_WINDOW_SUPPORT) && defined(HIF_PCI)
47 
48 static inline
49 void hif_write32_mb_reg_window(void *sc,
50 			       void __iomem *addr, uint32_t value);
51 static inline
52 uint32_t hif_read32_mb_reg_window(void *sc,
53 				  void __iomem *addr);
54 #define hif_read32_mb(scn, addr) \
55 	hif_read32_mb_reg_window((void *)scn, \
56 				 (void __iomem *)addr)
57 #define hif_write32_mb(scn, addr, value) \
58 	hif_write32_mb_reg_window((void *)scn, \
59 				  (void __iomem *)addr, value)
60 
61 #else
62 #define hif_read32_mb(scn, addr)         ioread32((void __iomem *)addr)
63 #define hif_write32_mb(scn, addr, value) \
64 	iowrite32((u32)(value), (void __iomem *)(addr))
65 #endif
66 
67 #define Q_TARGET_ACCESS_BEGIN(scn) \
68 	hif_target_sleep_state_adjust(scn, false, true)
69 #define Q_TARGET_ACCESS_END(scn) \
70 	hif_target_sleep_state_adjust(scn, true, false)
71 #define TARGET_REGISTER_ACCESS_ALLOWED(scn)\
72 		hif_is_target_register_access_allowed(scn)
73 
74 /*
75  * A_TARGET_ACCESS_LIKELY will not wait for the target to wake up before
76  * continuing execution.  Because A_TARGET_ACCESS_LIKELY does not guarantee
77  * that the target is awake before continuing, Q_TARGET_ACCESS macros must
78  * protect the actual target access.  Since Q_TARGET_ACCESS protect the actual
79  * target access, A_TARGET_ACCESS_LIKELY hints are optional.
80  *
81  * To ignore "LIKELY" hints, set CONFIG_TARGET_ACCESS_LIKELY to 0
82  * (slightly worse performance, less power)
83  *
84  * To use "LIKELY" hints, set CONFIG_TARGET_ACCESS_LIKELY to 1
85  * (slightly better performance, more power)
86  *
87  * note: if a bus doesn't use hif_target_sleep_state_adjust, this will have
88  * no impact.
89  */
90 #define CONFIG_TARGET_ACCESS_LIKELY 0
91 #if CONFIG_TARGET_ACCESS_LIKELY
92 #define A_TARGET_ACCESS_LIKELY(scn) \
93 	hif_target_sleep_state_adjust(scn, false, false)
94 #define A_TARGET_ACCESS_UNLIKELY(scn) \
95 	hif_target_sleep_state_adjust(scn, true, false)
96 #else                           /* CONFIG_ATH_PCIE_ACCESS_LIKELY */
97 #define A_TARGET_ACCESS_LIKELY(scn) \
98 	do { \
99 		unsigned long unused = (unsigned long)(scn); \
100 		unused = unused; \
101 	} while (0)
102 
103 #define A_TARGET_ACCESS_UNLIKELY(scn) \
104 	do { \
105 		unsigned long unused = (unsigned long)(scn); \
106 		unused = unused; \
107 	} while (0)
108 #endif /* CONFIG_ATH_PCIE_ACCESS_LIKELY */
109 
110 
111 #ifdef HIF_PCI
112 #include "hif_io32_pci.h"
113 #endif
114 #ifdef HIF_SNOC
115 #include "hif_io32_snoc.h"
116 #endif
117 #ifdef HIF_IPCI
118 #include "hif_io32_ipci.h"
119 #endif
120 
121 #ifdef HIF_IPCI
122 /**
123  * hif_target_access_allowed(): Check if target access is allowed
124  *
125  * @scn: HIF handler
126  *
127  * Return: True if access is allowed else False
128  */
129 static inline
130 bool hif_target_access_allowed(struct hif_softc *scn)
131 {
132 	return !(scn->recovery);
133 }
134 
135 #define TARGET_ACCESS_ALLOWED(scn) \
136 	hif_target_access_allowed(scn)
137 #else
138 #define TARGET_ACCESS_ALLOWED(scn) (1)
139 #endif
140 
141 #if defined(HIF_REG_WINDOW_SUPPORT) && defined(HIF_PCI)
142 
143 #include "qdf_lock.h"
144 #include "qdf_util.h"
145 
146 /**
147  * hif_reg_write_result_check() - check register writing result
148  * @sc: hif pcie context
149  * @offset: register offset to read
150  * @exp_val: the expected value of register
151  *
152  * Return: none
153  */
154 static inline void hif_reg_write_result_check(struct hif_pci_softc *sc,
155 					      uint32_t offset,
156 					      uint32_t exp_val)
157 {
158 	uint32_t value;
159 
160 	value = qdf_ioread32(sc->mem + offset);
161 	if (exp_val != value) {
162 		hif_err("Reg write failed. write val 0x%x read val 0x%x offset 0x%x",
163 			exp_val,
164 			value,
165 			offset);
166 	}
167 }
168 
169 #ifdef PCIE_REG_WINDOW_LOCAL_NO_CACHE
170 /**
171  * hif_select_window_confirm(): Update the register window
172  * @sc: HIF pci handle
173  * @offset: reg offset to read from or write to
174  *
175  * Calculate the window using the offset provided and update
176  * the window reg value accordingly for windowed read/write reg
177  * access.
178  * Read back to make sure the window is written to the register.
179  * Return: None
180  */
181 static inline
182 void hif_select_window_confirm(struct hif_pci_softc *sc, uint32_t offset)
183 {
184 	uint32_t window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK;
185 
186 	qdf_iowrite32(sc->mem + WINDOW_REG_ADDRESS,
187 		      WINDOW_ENABLE_BIT | window);
188 	sc->register_window = window;
189 	hif_reg_write_result_check(sc, WINDOW_REG_ADDRESS,
190 				   WINDOW_ENABLE_BIT | window);
191 }
192 #else /* PCIE_REG_WINDOW_LOCAL_NO_CACHE */
193 
194 static inline
195 void hif_select_window_confirm(struct hif_pci_softc *sc, uint32_t offset)
196 {
197 	uint32_t window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK;
198 
199 	if (window != sc->register_window) {
200 		qdf_iowrite32(sc->mem + WINDOW_REG_ADDRESS,
201 			      WINDOW_ENABLE_BIT | window);
202 		sc->register_window = window;
203 		hif_reg_write_result_check(sc, WINDOW_REG_ADDRESS,
204 					   WINDOW_ENABLE_BIT | window);
205 	}
206 }
207 #endif /* PCIE_REG_WINDOW_LOCAL_NO_CACHE */
208 
209 #if !defined(QCA_WIFI_QCA6390) && !defined(QCA_WIFI_QCA6490)
210 /**
211  * hif_lock_reg_access() - Lock window register access spinlock
212  * @sc: HIF handle
213  * @flags: variable pointer to save CPU states
214  *
215  * Lock register window spinlock
216  *
217  * Return: void
218  */
219 static inline void hif_lock_reg_access(struct hif_pci_softc *sc,
220 				       unsigned long *flags)
221 {
222 	qdf_spin_lock_irqsave(&sc->register_access_lock);
223 }
224 
225 /**
226  * hif_unlock_reg_access() - Unlock window register access spinlock
227  * @sc: HIF handle
228  * @flags: variable pointer to save CPU states
229  *
230  * Unlock register window spinlock
231  *
232  * Return: void
233  */
234 static inline void hif_unlock_reg_access(struct hif_pci_softc *sc,
235 					 unsigned long *flags)
236 {
237 	qdf_spin_unlock_irqrestore(&sc->register_access_lock);
238 }
239 #else
240 static inline void hif_lock_reg_access(struct hif_pci_softc *sc,
241 				       unsigned long *flags)
242 {
243 	pld_lock_reg_window(sc->dev, flags);
244 }
245 
246 static inline void hif_unlock_reg_access(struct hif_pci_softc *sc,
247 					 unsigned long *flags)
248 {
249 	pld_unlock_reg_window(sc->dev, flags);
250 }
251 #endif
252 
253 /**
254  * note1: WINDOW_RANGE_MASK = (1 << WINDOW_SHIFT) -1
255  * note2: 1 << WINDOW_SHIFT = MAX_UNWINDOWED_ADDRESS
256  * note3: WINDOW_VALUE_MASK = big enough that trying to write past that window
257  *				would be a bug
258  */
259 static inline void hif_write32_mb_reg_window(void *scn,
260 					     void __iomem *addr, uint32_t value)
261 {
262 	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
263 	uint32_t offset = addr - sc->mem;
264 	unsigned long flags;
265 
266 	if (!sc->use_register_windowing ||
267 	    offset < MAX_UNWINDOWED_ADDRESS) {
268 		qdf_iowrite32(addr, value);
269 	} else {
270 		hif_lock_reg_access(sc, &flags);
271 		hif_select_window_confirm(sc, offset);
272 		qdf_iowrite32(sc->mem + WINDOW_START +
273 			  (offset & WINDOW_RANGE_MASK), value);
274 		hif_unlock_reg_access(sc, &flags);
275 	}
276 }
277 
278 static inline uint32_t hif_read32_mb_reg_window(void *scn, void __iomem *addr)
279 {
280 	struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn);
281 	uint32_t ret;
282 	uint32_t offset = addr - sc->mem;
283 	unsigned long flags;
284 
285 	if (!sc->use_register_windowing ||
286 	    offset < MAX_UNWINDOWED_ADDRESS) {
287 		return qdf_ioread32(addr);
288 	}
289 	hif_lock_reg_access(sc, &flags);
290 	hif_select_window_confirm(sc, offset);
291 	ret = qdf_ioread32(sc->mem + WINDOW_START +
292 		       (offset & WINDOW_RANGE_MASK));
293 	hif_unlock_reg_access(sc, &flags);
294 
295 	return ret;
296 }
297 #endif
298 
299 #ifdef CONFIG_IO_MEM_ACCESS_DEBUG
300 uint32_t hif_target_read_checked(struct hif_softc *scn,
301 					uint32_t offset);
302 void hif_target_write_checked(struct hif_softc *scn, uint32_t offset,
303 				     uint32_t value);
304 
305 #define A_TARGET_READ(scn, offset) \
306 	hif_target_read_checked(scn, (offset))
307 #define A_TARGET_WRITE(scn, offset, value) \
308 	hif_target_write_checked(scn, (offset), (value))
309 #else                           /* CONFIG_ATH_PCIE_ACCESS_DEBUG */
310 #define A_TARGET_READ(scn, offset) \
311 	hif_read32_mb(scn, scn->mem + (offset))
312 #define A_TARGET_WRITE(scn, offset, value) \
313 	hif_write32_mb(scn, (scn->mem) + (offset), value)
314 #endif
315 
316 void hif_irq_enable(struct hif_softc *scn, int irq_id);
317 void hif_irq_disable(struct hif_softc *scn, int irq_id);
318 
319 #endif /* __HIF_IO32_H__ */
320