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 #define WINDOW_REG_ADDRESS 0x310C 42 #define WINDOW_SHIFT 19 43 #define WINDOW_VALUE_MASK 0x3F 44 #define WINDOW_START MAX_UNWINDOWED_ADDRESS 45 #define WINDOW_RANGE_MASK 0x7FFFF 46 47 #if defined(HIF_REG_WINDOW_SUPPORT) && defined(HIF_PCI) 48 49 static inline 50 void hif_write32_mb_reg_window(void *sc, 51 void __iomem *addr, uint32_t value); 52 static inline 53 uint32_t hif_read32_mb_reg_window(void *sc, 54 void __iomem *addr); 55 #define hif_read32_mb(scn, addr) \ 56 hif_read32_mb_reg_window((void *)scn, \ 57 (void __iomem *)addr) 58 #define hif_write32_mb(scn, addr, value) \ 59 hif_write32_mb_reg_window((void *)scn, \ 60 (void __iomem *)addr, value) 61 62 #else 63 #define hif_read32_mb(scn, addr) ioread32((void __iomem *)addr) 64 #define hif_write32_mb(scn, addr, value) \ 65 iowrite32((u32)(value), (void __iomem *)(addr)) 66 #endif 67 68 #define Q_TARGET_ACCESS_BEGIN(scn) \ 69 hif_target_sleep_state_adjust(scn, false, true) 70 #define Q_TARGET_ACCESS_END(scn) \ 71 hif_target_sleep_state_adjust(scn, true, false) 72 #define TARGET_REGISTER_ACCESS_ALLOWED(scn)\ 73 hif_is_target_register_access_allowed(scn) 74 75 /* 76 * A_TARGET_ACCESS_LIKELY will not wait for the target to wake up before 77 * continuing execution. Because A_TARGET_ACCESS_LIKELY does not guarantee 78 * that the target is awake before continuing, Q_TARGET_ACCESS macros must 79 * protect the actual target access. Since Q_TARGET_ACCESS protect the actual 80 * target access, A_TARGET_ACCESS_LIKELY hints are optional. 81 * 82 * To ignore "LIKELY" hints, set CONFIG_TARGET_ACCESS_LIKELY to 0 83 * (slightly worse performance, less power) 84 * 85 * To use "LIKELY" hints, set CONFIG_TARGET_ACCESS_LIKELY to 1 86 * (slightly better performance, more power) 87 * 88 * note: if a bus doesn't use hif_target_sleep_state_adjust, this will have 89 * no impact. 90 */ 91 #define CONFIG_TARGET_ACCESS_LIKELY 0 92 #if CONFIG_TARGET_ACCESS_LIKELY 93 #define A_TARGET_ACCESS_LIKELY(scn) \ 94 hif_target_sleep_state_adjust(scn, false, false) 95 #define A_TARGET_ACCESS_UNLIKELY(scn) \ 96 hif_target_sleep_state_adjust(scn, true, false) 97 #else /* CONFIG_ATH_PCIE_ACCESS_LIKELY */ 98 #define A_TARGET_ACCESS_LIKELY(scn) \ 99 do { \ 100 unsigned long unused = (unsigned long)(scn); \ 101 unused = unused; \ 102 } while (0) 103 104 #define A_TARGET_ACCESS_UNLIKELY(scn) \ 105 do { \ 106 unsigned long unused = (unsigned long)(scn); \ 107 unused = unused; \ 108 } while (0) 109 #endif /* CONFIG_ATH_PCIE_ACCESS_LIKELY */ 110 111 112 #ifdef HIF_PCI 113 #include "hif_io32_pci.h" 114 #endif 115 #ifdef HIF_SNOC 116 #include "hif_io32_snoc.h" 117 #endif 118 #ifdef HIF_IPCI 119 #include "hif_io32_ipci.h" 120 #endif 121 122 #ifdef HIF_IPCI 123 /** 124 * hif_target_access_allowed(): Check if target access is allowed 125 * 126 * @scn: HIF handler 127 * 128 * Return: True if access is allowed else False 129 */ 130 static inline 131 bool hif_target_access_allowed(struct hif_softc *scn) 132 { 133 return !(scn->recovery); 134 } 135 136 #define TARGET_ACCESS_ALLOWED(scn) \ 137 hif_target_access_allowed(scn) 138 #else 139 #define TARGET_ACCESS_ALLOWED(scn) (1) 140 #endif 141 142 #if defined(HIF_REG_WINDOW_SUPPORT) && defined(HIF_PCI) 143 144 #include "qdf_lock.h" 145 #include "qdf_util.h" 146 147 /** 148 * hif_reg_write_result_check() - check register writing result 149 * @sc: hif pcie context 150 * @offset: register offset to read 151 * @exp_val: the expected value of register 152 * 153 * Return: none 154 */ 155 static inline void hif_reg_write_result_check(struct hif_pci_softc *sc, 156 uint32_t offset, 157 uint32_t exp_val) 158 { 159 uint32_t value; 160 161 value = qdf_ioread32(sc->mem + offset); 162 if (exp_val != value) { 163 hif_err("Reg write failed. write val 0x%x read val 0x%x offset 0x%x", 164 exp_val, 165 value, 166 offset); 167 } 168 } 169 170 #ifdef PCIE_REG_WINDOW_LOCAL_NO_CACHE 171 /** 172 * hif_select_window_confirm(): Update the register window 173 * @sc: HIF pci handle 174 * @offset: reg offset to read from or write to 175 * 176 * Calculate the window using the offset provided and update 177 * the window reg value accordingly for windowed read/write reg 178 * access. 179 * Read back to make sure the window is written to the register. 180 * Return: None 181 */ 182 static inline 183 void hif_select_window_confirm(struct hif_pci_softc *sc, uint32_t offset) 184 { 185 uint32_t window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK; 186 187 qdf_iowrite32(sc->mem + WINDOW_REG_ADDRESS, 188 WINDOW_ENABLE_BIT | window); 189 sc->register_window = window; 190 hif_reg_write_result_check(sc, WINDOW_REG_ADDRESS, 191 WINDOW_ENABLE_BIT | window); 192 } 193 #else /* PCIE_REG_WINDOW_LOCAL_NO_CACHE */ 194 195 static inline 196 void hif_select_window_confirm(struct hif_pci_softc *sc, uint32_t offset) 197 { 198 uint32_t window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK; 199 200 if (window != sc->register_window) { 201 qdf_iowrite32(sc->mem + WINDOW_REG_ADDRESS, 202 WINDOW_ENABLE_BIT | window); 203 sc->register_window = window; 204 hif_reg_write_result_check(sc, WINDOW_REG_ADDRESS, 205 WINDOW_ENABLE_BIT | window); 206 } 207 } 208 #endif /* PCIE_REG_WINDOW_LOCAL_NO_CACHE */ 209 210 #ifdef WINDOW_REG_PLD_LOCK_ENABLE 211 /** 212 * hif_lock_reg_access() - Lock window register access spinlock 213 * @sc: HIF handle 214 * @flags: variable pointer to save CPU states 215 * 216 * Lock register window spinlock 217 * 218 * Return: void 219 */ 220 static inline void hif_lock_reg_access(struct hif_pci_softc *sc, 221 unsigned long *flags) 222 { 223 pld_lock_reg_window(sc->dev, flags); 224 } 225 226 /** 227 * hif_unlock_reg_access() - Unlock window register access spinlock 228 * @sc: HIF handle 229 * @flags: variable pointer to save CPU states 230 * 231 * Unlock register window spinlock 232 * 233 * Return: void 234 */ 235 static inline void hif_unlock_reg_access(struct hif_pci_softc *sc, 236 unsigned long *flags) 237 { 238 pld_unlock_reg_window(sc->dev, flags); 239 } 240 #else 241 static inline void hif_lock_reg_access(struct hif_pci_softc *sc, 242 unsigned long *flags) 243 { 244 qdf_spin_lock_irqsave(&sc->register_access_lock); 245 } 246 247 static inline void hif_unlock_reg_access(struct hif_pci_softc *sc, 248 unsigned long *flags) 249 { 250 qdf_spin_unlock_irqrestore(&sc->register_access_lock); 251 } 252 #endif 253 254 /* 255 * note1: WINDOW_RANGE_MASK = (1 << WINDOW_SHIFT) -1 256 * note2: 1 << WINDOW_SHIFT = MAX_UNWINDOWED_ADDRESS 257 * note3: WINDOW_VALUE_MASK = big enough that trying to write past that window 258 * would be a bug 259 */ 260 static inline void hif_write32_mb_reg_window(void *scn, 261 void __iomem *addr, uint32_t value) 262 { 263 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); 264 uint32_t offset = addr - sc->mem; 265 unsigned long flags; 266 267 if (!sc->use_register_windowing || 268 offset < MAX_UNWINDOWED_ADDRESS) { 269 qdf_iowrite32(addr, value); 270 } else { 271 hif_lock_reg_access(sc, &flags); 272 hif_select_window_confirm(sc, offset); 273 qdf_iowrite32(sc->mem + WINDOW_START + 274 (offset & WINDOW_RANGE_MASK), value); 275 hif_unlock_reg_access(sc, &flags); 276 } 277 } 278 279 static inline uint32_t hif_read32_mb_reg_window(void *scn, void __iomem *addr) 280 { 281 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); 282 uint32_t ret; 283 uint32_t offset = addr - sc->mem; 284 unsigned long flags; 285 286 if (!sc->use_register_windowing || 287 offset < MAX_UNWINDOWED_ADDRESS) { 288 return qdf_ioread32(addr); 289 } 290 hif_lock_reg_access(sc, &flags); 291 hif_select_window_confirm(sc, offset); 292 ret = qdf_ioread32(sc->mem + WINDOW_START + 293 (offset & WINDOW_RANGE_MASK)); 294 hif_unlock_reg_access(sc, &flags); 295 296 return ret; 297 } 298 #endif 299 300 #ifdef CONFIG_IO_MEM_ACCESS_DEBUG 301 uint32_t hif_target_read_checked(struct hif_softc *scn, 302 uint32_t offset); 303 void hif_target_write_checked(struct hif_softc *scn, uint32_t offset, 304 uint32_t value); 305 306 #define A_TARGET_READ(scn, offset) \ 307 hif_target_read_checked(scn, (offset)) 308 #define A_TARGET_WRITE(scn, offset, value) \ 309 hif_target_write_checked(scn, (offset), (value)) 310 #else /* CONFIG_ATH_PCIE_ACCESS_DEBUG */ 311 #define A_TARGET_READ(scn, offset) \ 312 hif_read32_mb(scn, scn->mem + (offset)) 313 #define A_TARGET_WRITE(scn, offset, value) \ 314 hif_write32_mb(scn, (scn->mem) + (offset), value) 315 #endif 316 317 void hif_irq_enable(struct hif_softc *scn, int irq_id); 318 void hif_irq_disable(struct hif_softc *scn, int irq_id); 319 320 #endif /* __HIF_IO32_H__ */ 321