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