Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2013-2016 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 | /** |
| 20 | * DOC: if_ahb.c |
| 21 | * |
| 22 | * c file for ahb specific implementations. |
| 23 | */ |
| 24 | |
| 25 | #include "hif.h" |
| 26 | #include "hif_main.h" |
| 27 | #include "hif_debug.h" |
| 28 | #include "hif_io32.h" |
| 29 | #include "ce_main.h" |
| 30 | #include "ce_tasklet.h" |
| 31 | #include "if_ahb.h" |
| 32 | #include "if_pci.h" |
| 33 | #include "ahb_api.h" |
Aravind Narasimhan | a1c7d6d | 2016-06-01 10:21:32 +0530 | [diff] [blame] | 34 | #include "pci_api.h" |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 35 | #include "hif_napi.h" |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 36 | |
| 37 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) |
| 38 | #define IRQF_DISABLED 0x00000020 |
| 39 | #endif |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 40 | |
| 41 | #define HIF_IC_CE0_IRQ_OFFSET 4 |
| 42 | #define HIF_IC_MAX_IRQ 54 |
| 43 | |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 44 | static uint8_t ic_irqnum[HIF_IC_MAX_IRQ]; |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 45 | /* integrated chip irq names */ |
| 46 | const char *ic_irqname[HIF_IC_MAX_IRQ] = { |
Pamidipati, Vijay | 30dc8f2 | 2016-10-26 21:54:23 +0530 | [diff] [blame] | 47 | "misc-pulse1", |
| 48 | "misc-latch", |
| 49 | "sw-exception", |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 50 | "watchdog", |
| 51 | "ce0", |
| 52 | "ce1", |
| 53 | "ce2", |
| 54 | "ce3", |
| 55 | "ce4", |
| 56 | "ce5", |
| 57 | "ce6", |
| 58 | "ce7", |
| 59 | "ce8", |
| 60 | "ce9", |
| 61 | "ce10", |
| 62 | "ce11", |
| 63 | "ce12", |
| 64 | "ce13", |
Pamidipati, Vijay | 30dc8f2 | 2016-10-26 21:54:23 +0530 | [diff] [blame] | 65 | "host2wbm-desc-feed", |
| 66 | "host2reo-re-injection", |
| 67 | "host2reo-command", |
| 68 | "host2rxdma-monitor-ring3", |
| 69 | "host2rxdma-monitor-ring2", |
| 70 | "host2rxdma-monitor-ring1", |
| 71 | "reo2ost-exception", |
| 72 | "wbm2host-rx-release", |
| 73 | "reo2host-status", |
| 74 | "reo2host-destination-ring4", |
| 75 | "reo2host-destination-ring3", |
| 76 | "reo2host-destination-ring2", |
| 77 | "reo2host-destination-ring1", |
| 78 | "rxdma2host-monitor-destination-mac3", |
| 79 | "rxdma2host-monitor-destination-mac2", |
| 80 | "rxdma2host-monitor-destination-mac1", |
| 81 | "ppdu-end-interrupts-mac3", |
| 82 | "ppdu-end-interrupts-mac2", |
| 83 | "ppdu-end-interrupts-mac1", |
| 84 | "rxdma2host-monitor-status-ring-mac3", |
| 85 | "rxdma2host-monitor-status-ring-mac2", |
| 86 | "rxdma2host-monitor-status-ring-mac1", |
| 87 | "host2rxdma-host-buf-ring-mac3", |
| 88 | "host2rxdma-host-buf-ring-mac2", |
| 89 | "host2rxdma-host-buf-ring-mac1", |
| 90 | "rxdma2host-destination-ring-mac3", |
| 91 | "rxdma2host-destination-ring-mac2", |
| 92 | "rxdma2host-destination-ring-mac1", |
| 93 | "host2tcl-input-ring4", |
| 94 | "host2tcl-input-ring3", |
| 95 | "host2tcl-input-ring2", |
| 96 | "host2tcl-input-ring1", |
| 97 | "wbm2host-tx-completions-ring3", |
| 98 | "wbm2host-tx-completions-ring2", |
| 99 | "wbm2host-tx-completions-ring1", |
| 100 | "tcl2host-status-ring", |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 101 | }; |
| 102 | |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 103 | /** |
| 104 | * hif_disable_isr() - disable isr |
| 105 | * |
| 106 | * This function disables isr and kills tasklets |
| 107 | * |
| 108 | * @hif_ctx: struct hif_softc |
| 109 | * |
| 110 | * Return: void |
| 111 | */ |
| 112 | void hif_ahb_disable_isr(struct hif_softc *scn) |
| 113 | { |
| 114 | struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); |
| 115 | |
| 116 | hif_nointrs(scn); |
| 117 | ce_tasklet_kill(scn); |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 118 | hif_grp_tasklet_kill(scn); |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 119 | tasklet_kill(&sc->intr_tq); |
| 120 | qdf_atomic_set(&scn->active_tasklet_cnt, 0); |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 121 | qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0); |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 122 | } |
| 123 | |
| 124 | /** |
| 125 | * hif_dump_registers() - dump bus debug registers |
| 126 | * @scn: struct hif_opaque_softc |
| 127 | * |
| 128 | * This function dumps hif bus debug registers |
| 129 | * |
| 130 | * Return: 0 for success or error code |
| 131 | */ |
| 132 | int hif_ahb_dump_registers(struct hif_softc *hif_ctx) |
| 133 | { |
| 134 | int status; |
| 135 | struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); |
| 136 | |
| 137 | status = hif_dump_ce_registers(scn); |
| 138 | if (status) |
| 139 | HIF_ERROR("%s: Dump CE Registers Failed status %d", __func__, |
| 140 | status); |
| 141 | |
| 142 | return 0; |
| 143 | } |
| 144 | |
| 145 | /** |
| 146 | * hif_ahb_close() - hif_bus_close |
| 147 | * @scn: pointer to the hif context. |
| 148 | * |
| 149 | * This is a callback function for hif_bus_close. |
| 150 | * |
| 151 | * |
| 152 | * Return: n/a |
| 153 | */ |
| 154 | void hif_ahb_close(struct hif_softc *scn) |
| 155 | { |
| 156 | hif_ce_close(scn); |
| 157 | } |
| 158 | |
| 159 | /** |
| 160 | * hif_bus_open() - hif_ahb open |
| 161 | * @hif_ctx: hif context |
| 162 | * @bus_type: bus type |
| 163 | * |
| 164 | * This is a callback function for hif_bus_open. |
| 165 | * |
| 166 | * Return: n/a |
| 167 | */ |
| 168 | QDF_STATUS hif_ahb_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type) |
| 169 | { |
| 170 | |
| 171 | struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); |
| 172 | |
| 173 | qdf_spinlock_create(&sc->irq_lock); |
| 174 | return hif_ce_open(hif_ctx); |
| 175 | } |
| 176 | |
| 177 | /** |
| 178 | * hif_bus_configure() - Configure the bus |
| 179 | * @scn: pointer to the hif context. |
| 180 | * |
| 181 | * This function configure the ahb bus |
| 182 | * |
| 183 | * return: 0 for success. nonzero for failure. |
| 184 | */ |
| 185 | int hif_ahb_bus_configure(struct hif_softc *scn) |
| 186 | { |
| 187 | return hif_pci_bus_configure(scn); |
| 188 | } |
| 189 | |
| 190 | /** |
| 191 | * hif_configure_msi_ahb - Configure MSI interrupts |
| 192 | * @sc : pointer to the hif context |
| 193 | * |
| 194 | * return: 0 for success. nonzero for failure. |
| 195 | */ |
| 196 | |
| 197 | int hif_configure_msi_ahb(struct hif_pci_softc *sc) |
| 198 | { |
| 199 | return 0; |
| 200 | } |
| 201 | |
| 202 | /** |
| 203 | * hif_ahb_configure_legacy_irq() - Configure Legacy IRQ |
| 204 | * @sc: pointer to the hif context. |
| 205 | * |
| 206 | * This function registers the irq handler and enables legacy interrupts |
| 207 | * |
| 208 | * return: 0 for success. nonzero for failure. |
| 209 | */ |
| 210 | int hif_ahb_configure_legacy_irq(struct hif_pci_softc *sc) |
| 211 | { |
| 212 | int ret = 0; |
| 213 | struct hif_softc *scn = HIF_GET_SOFTC(sc); |
| 214 | struct platform_device *pdev = (struct platform_device *)sc->pdev; |
| 215 | int irq = 0; |
| 216 | |
| 217 | /* do not support MSI or MSI IRQ failed */ |
| 218 | tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc); |
| 219 | irq = platform_get_irq_byname(pdev, "legacy"); |
| 220 | if (irq < 0) { |
| 221 | dev_err(&pdev->dev, "Unable to get irq\n"); |
| 222 | ret = -1; |
| 223 | goto end; |
| 224 | } |
| 225 | ret = request_irq(irq, hif_pci_interrupt_handler, |
| 226 | IRQF_DISABLED, "wlan_ahb", sc); |
| 227 | if (ret) { |
| 228 | dev_err(&pdev->dev, "ath_request_irq failed\n"); |
| 229 | ret = -1; |
| 230 | goto end; |
| 231 | } |
| 232 | sc->irq = irq; |
| 233 | |
| 234 | /* Use Legacy PCI Interrupts */ |
| 235 | hif_write32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS | |
| 236 | PCIE_INTR_ENABLE_ADDRESS), |
| 237 | PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); |
| 238 | /* read once to flush */ |
| 239 | hif_read32_mb(sc->mem+(SOC_CORE_BASE_ADDRESS | |
| 240 | PCIE_INTR_ENABLE_ADDRESS) |
| 241 | ); |
| 242 | |
| 243 | end: |
| 244 | return ret; |
| 245 | } |
| 246 | |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 247 | int hif_ahb_configure_irq(struct hif_pci_softc *sc) |
| 248 | { |
| 249 | int ret = 0; |
| 250 | struct hif_softc *scn = HIF_GET_SOFTC(sc); |
| 251 | struct platform_device *pdev = (struct platform_device *)sc->pdev; |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 252 | struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); |
| 253 | struct hif_ext_group_entry *hif_ext_group; |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 254 | int irq = 0; |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 255 | int i, j; |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 256 | |
| 257 | /* configure per CE interrupts */ |
| 258 | for (i = 0; i < scn->ce_count; i++) { |
| 259 | irq = platform_get_irq_byname(pdev, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i]); |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 260 | ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i] = irq; |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 261 | ret = request_irq(irq , |
| 262 | hif_ahb_interrupt_handler, |
| 263 | IRQF_TRIGGER_RISING, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i], |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 264 | &hif_state->tasklets[i]); |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 265 | if (ret) { |
| 266 | dev_err(&pdev->dev, "ath_request_irq failed\n"); |
| 267 | ret = -1; |
| 268 | goto end; |
| 269 | } |
| 270 | hif_ahb_irq_enable(scn, i); |
| 271 | } |
| 272 | |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 273 | /* configure external interrupts */ |
| 274 | for (i = 0; i < hif_state->hif_num_extgroup; i++) { |
| 275 | |
| 276 | hif_ext_group = &hif_state->hif_ext_group[i]; |
| 277 | if (hif_ext_group->configured) { |
| 278 | |
| 279 | tasklet_init(&hif_ext_group->intr_tq, |
| 280 | hif_ext_grp_tasklet, |
| 281 | (unsigned long)hif_ext_group); |
| 282 | hif_ext_group->inited = true; |
| 283 | |
| 284 | for (j = 0; j < hif_ext_group->numirq; j++) { |
| 285 | irq = platform_get_irq_byname(pdev, |
| 286 | ic_irqname[hif_ext_group->irq[j]]); |
| 287 | |
| 288 | ic_irqnum[hif_ext_group->irq[j]] = irq; |
| 289 | ret = request_irq(irq, |
| 290 | hif_ext_group_ahb_interrupt_handler, |
| 291 | IRQF_TRIGGER_RISING, "wlan_ahb", |
| 292 | hif_ext_group); |
| 293 | if (ret) { |
| 294 | dev_err(&pdev->dev, |
| 295 | "ath_request_irq failed\n"); |
| 296 | ret = -1; |
| 297 | goto end; |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | } |
| 302 | |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 303 | end: |
| 304 | return ret; |
| 305 | } |
| 306 | |
| 307 | irqreturn_t hif_ahb_interrupt_handler(int irq, void *context) |
| 308 | { |
| 309 | struct ce_tasklet_entry *tasklet_entry = context; |
| 310 | return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry); |
| 311 | } |
| 312 | |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 313 | irqreturn_t hif_ext_group_ahb_interrupt_handler(int irq, void *context) |
| 314 | { |
| 315 | struct hif_ext_group_entry *hif_ext_group = context; |
| 316 | struct HIF_CE_state *hif_state = hif_ext_group->hif_state; |
| 317 | struct hif_softc *scn = HIF_GET_SOFTC(hif_state); |
| 318 | struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn); |
| 319 | uint32_t grp_id = hif_ext_group->grp_id; |
| 320 | |
| 321 | hif_grp_irq_disable(scn, grp_id); |
| 322 | |
| 323 | qdf_atomic_inc(&scn->active_grp_tasklet_cnt); |
| 324 | |
| 325 | if (hif_ext_napi_enabled(hif_hdl, grp_id)) { |
| 326 | hif_napi_schedule_grp(hif_hdl, grp_id); |
| 327 | } else { |
| 328 | tasklet_schedule(&hif_ext_group->intr_tq); |
| 329 | } |
| 330 | |
| 331 | return IRQ_HANDLED; |
| 332 | } |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 333 | |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 334 | /** |
| 335 | * hif_target_sync() : ensure the target is ready |
| 336 | * @scn: hif control structure |
| 337 | * |
| 338 | * Informs fw that we plan to use legacy interupts so that |
| 339 | * it can begin booting. Ensures that the fw finishes booting |
| 340 | * before continuing. Should be called before trying to write |
| 341 | * to the targets other registers for the first time. |
| 342 | * |
| 343 | * Return: none |
| 344 | */ |
| 345 | int hif_target_sync_ahb(struct hif_softc *scn) |
| 346 | { |
| 347 | hif_write32_mb(scn->mem + FW_INDICATOR_ADDRESS, FW_IND_HOST_READY); |
| 348 | if (HAS_FW_INDICATOR) { |
| 349 | int wait_limit = 500; |
| 350 | int fw_ind = 0; |
| 351 | |
| 352 | while (1) { |
| 353 | fw_ind = hif_read32_mb(scn->mem + |
| 354 | FW_INDICATOR_ADDRESS); |
| 355 | if (fw_ind & FW_IND_INITIALIZED) |
| 356 | break; |
| 357 | if (wait_limit-- < 0) |
| 358 | break; |
| 359 | hif_write32_mb(scn->mem+(SOC_CORE_BASE_ADDRESS | |
| 360 | PCIE_INTR_ENABLE_ADDRESS), |
| 361 | PCIE_INTR_FIRMWARE_MASK); |
| 362 | qdf_mdelay(10); |
| 363 | } |
| 364 | if (wait_limit < 0) { |
| 365 | HIF_TRACE("%s: FW signal timed out", __func__); |
| 366 | return -EIO; |
| 367 | } else { |
| 368 | HIF_TRACE("%s: Got FW signal, retries = %x", __func__, |
| 369 | 500-wait_limit); |
| 370 | } |
| 371 | } |
| 372 | |
| 373 | return 0; |
| 374 | } |
| 375 | |
| 376 | /** |
| 377 | * hif_disable_bus() - Disable the bus |
| 378 | * @scn : pointer to the hif context |
| 379 | * |
| 380 | * This function disables the bus and helds the target in reset state |
| 381 | * |
| 382 | * Return: none |
| 383 | */ |
| 384 | void hif_ahb_disable_bus(struct hif_softc *scn) |
| 385 | { |
| 386 | struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); |
| 387 | void __iomem *mem; |
| 388 | struct platform_device *pdev = (struct platform_device *)sc->pdev; |
Venkateswara Swamy Bandaru | 3ca38e2 | 2016-08-05 14:51:19 +0530 | [diff] [blame] | 389 | struct resource *memres = NULL; |
| 390 | int mem_pa_size = 0; |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 391 | |
| 392 | /*Disable WIFI clock input*/ |
Venkateswara Swamy Bandaru | 3ca38e2 | 2016-08-05 14:51:19 +0530 | [diff] [blame] | 393 | if (sc->mem) { |
| 394 | memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 395 | if (!memres) { |
| 396 | HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", |
| 397 | __func__); |
| 398 | return; |
| 399 | } |
| 400 | mem_pa_size = memres->end - memres->start + 1; |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 401 | |
Venkateswara Swamy Bandaru | 3ca38e2 | 2016-08-05 14:51:19 +0530 | [diff] [blame] | 402 | hif_ahb_clk_enable_disable(&pdev->dev, 0); |
| 403 | |
| 404 | hif_ahb_device_reset(scn); |
| 405 | mem = (void __iomem *)sc->mem; |
| 406 | if (mem) { |
| 407 | devm_iounmap(&pdev->dev, mem); |
| 408 | devm_release_mem_region(&pdev->dev, scn->mem_pa, |
| 409 | mem_pa_size); |
| 410 | sc->mem = NULL; |
| 411 | } |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 412 | } |
| 413 | scn->mem = NULL; |
| 414 | } |
| 415 | |
| 416 | /** |
| 417 | * hif_enable_bus() - Enable the bus |
| 418 | * @dev: dev |
| 419 | * @bdev: bus dev |
| 420 | * @bid: bus id |
| 421 | * @type: bus type |
| 422 | * |
| 423 | * This function enables the radio bus by enabling necessary |
| 424 | * clocks and waits for the target to get ready to proceed futher |
| 425 | * |
| 426 | * Return: QDF_STATUS |
| 427 | */ |
| 428 | QDF_STATUS hif_ahb_enable_bus(struct hif_softc *ol_sc, |
| 429 | struct device *dev, void *bdev, |
| 430 | const hif_bus_id *bid, |
| 431 | enum hif_enable_type type) |
| 432 | { |
| 433 | int ret = 0; |
| 434 | int hif_type; |
| 435 | int target_type; |
| 436 | const struct platform_device_id *id = (struct platform_device_id *)bid; |
| 437 | struct platform_device *pdev = bdev; |
| 438 | struct hif_target_info *tgt_info = NULL; |
| 439 | struct resource *memres = NULL; |
| 440 | void __iomem *mem = NULL; |
| 441 | uint32_t revision_id = 0; |
| 442 | struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(ol_sc); |
| 443 | |
| 444 | sc->pdev = (struct pci_dev *)pdev; |
| 445 | sc->dev = &pdev->dev; |
| 446 | sc->devid = id->driver_data; |
| 447 | |
| 448 | ret = hif_get_device_type(id->driver_data, revision_id, |
| 449 | &hif_type, &target_type); |
| 450 | if (ret < 0) { |
| 451 | HIF_ERROR("%s: invalid device ret %d id %d revision_id %d", |
| 452 | __func__, ret, (int)id->driver_data, revision_id); |
| 453 | return QDF_STATUS_E_FAILURE; |
| 454 | } |
| 455 | |
| 456 | memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 457 | if (!memres) { |
| 458 | HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", __func__); |
| 459 | return -EIO; |
| 460 | } |
| 461 | |
| 462 | ret = dma_set_mask(dev, DMA_BIT_MASK(32)); |
| 463 | if (ret) { |
| 464 | HIF_INFO("ath: 32-bit DMA not available\n"); |
| 465 | goto err_cleanup1; |
| 466 | } |
| 467 | |
Houston Hoffman | 6296c3e | 2016-07-12 18:43:32 -0700 | [diff] [blame] | 468 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 469 | ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); |
Houston Hoffman | 6296c3e | 2016-07-12 18:43:32 -0700 | [diff] [blame] | 470 | #else |
| 471 | ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); |
| 472 | #endif |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 473 | if (ret) { |
| 474 | HIF_ERROR("%s: failed to set dma mask error = %d", |
| 475 | __func__, ret); |
| 476 | return ret; |
| 477 | } |
| 478 | |
| 479 | /* Arrange for access to Target SoC registers. */ |
Houston Hoffman | 6296c3e | 2016-07-12 18:43:32 -0700 | [diff] [blame] | 480 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 481 | mem = devm_ioremap_resource(&pdev->dev, memres); |
Houston Hoffman | 6296c3e | 2016-07-12 18:43:32 -0700 | [diff] [blame] | 482 | #else |
| 483 | mem = devm_request_and_ioremap(&pdev->dev, memres); |
| 484 | #endif |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 485 | if (IS_ERR(mem)) { |
| 486 | HIF_INFO("ath: ioremap error\n"); |
| 487 | ret = PTR_ERR(mem); |
| 488 | goto err_cleanup1; |
| 489 | } |
| 490 | |
| 491 | sc->mem = mem; |
| 492 | ol_sc->mem = mem; |
| 493 | ol_sc->mem_pa = memres->start; |
Venkateswara Swamy Bandaru | 3ca38e2 | 2016-08-05 14:51:19 +0530 | [diff] [blame] | 494 | |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 495 | tgt_info = hif_get_target_info_handle((struct hif_opaque_softc *)ol_sc); |
| 496 | |
| 497 | tgt_info->target_type = target_type; |
| 498 | hif_register_tbl_attach(ol_sc, hif_type); |
Govind Singh | 051a8c4 | 2016-05-10 12:23:41 +0530 | [diff] [blame] | 499 | hif_target_register_tbl_attach(ol_sc, target_type); |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 500 | |
Pratik Gandhi | 815c6d8 | 2016-10-19 12:06:32 +0530 | [diff] [blame] | 501 | /* QCA_WIFI_QCA8074_VP:Should not be executed on 8074 VP platform */ |
| 502 | if (tgt_info->target_type != TARGET_TYPE_QCA8074) { |
| 503 | if (hif_ahb_enable_radio(sc, pdev, id) != 0) { |
| 504 | HIF_INFO("error in enabling soc\n"); |
| 505 | return -EIO; |
| 506 | } |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 507 | |
Pratik Gandhi | 815c6d8 | 2016-10-19 12:06:32 +0530 | [diff] [blame] | 508 | if (hif_target_sync_ahb(ol_sc) < 0) { |
| 509 | ret = -EIO; |
| 510 | goto err_target_sync; |
| 511 | } |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 512 | } |
| 513 | HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x", |
| 514 | __func__, hif_type, target_type); |
| 515 | |
| 516 | return QDF_STATUS_SUCCESS; |
| 517 | err_target_sync: |
Pratik Gandhi | 815c6d8 | 2016-10-19 12:06:32 +0530 | [diff] [blame] | 518 | /* QCA_WIFI_QCA8074_VP:Should not be executed on 8074 VP platform */ |
| 519 | if (tgt_info->target_type != TARGET_TYPE_QCA8074) { |
| 520 | HIF_INFO("Error: Disabling target\n"); |
| 521 | hif_ahb_disable_bus(ol_sc); |
| 522 | } |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 523 | err_cleanup1: |
| 524 | return ret; |
| 525 | } |
| 526 | |
| 527 | |
| 528 | /** |
| 529 | * hif_reset_soc() - reset soc |
| 530 | * |
| 531 | * @hif_ctx: HIF context |
| 532 | * |
| 533 | * This function resets soc and helds the |
| 534 | * target in reset state |
| 535 | * |
| 536 | * Return: void |
| 537 | */ |
| 538 | /* Function to reset SoC */ |
Venkateswara Swamy Bandaru | 3ca38e2 | 2016-08-05 14:51:19 +0530 | [diff] [blame] | 539 | void hif_ahb_reset_soc(struct hif_softc *hif_ctx) |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 540 | { |
Venkateswara Swamy Bandaru | 3ca38e2 | 2016-08-05 14:51:19 +0530 | [diff] [blame] | 541 | hif_ahb_device_reset(hif_ctx); |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 542 | } |
| 543 | |
| 544 | |
| 545 | /** |
| 546 | * hif_nointrs() - disable IRQ |
| 547 | * |
| 548 | * @scn: struct hif_softc |
| 549 | * |
| 550 | * This function stops interrupt(s) |
| 551 | * |
| 552 | * Return: none |
| 553 | */ |
| 554 | void hif_ahb_nointrs(struct hif_softc *scn) |
| 555 | { |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 556 | int i; |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 557 | struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 558 | struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); |
| 559 | |
Kiran Venkatappa | a17e5e5 | 2016-12-20 11:32:06 +0530 | [diff] [blame^] | 560 | ce_unregister_irq(hif_state, CE_ALL_BITMAP); |
| 561 | |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 562 | if (scn->request_irq_done == false) |
| 563 | return; |
| 564 | |
| 565 | if (sc->num_msi_intrs > 0) { |
| 566 | /* MSI interrupt(s) */ |
| 567 | for (i = 0; i < sc->num_msi_intrs; i++) { |
| 568 | free_irq(sc->irq + i, sc); |
| 569 | } |
| 570 | sc->num_msi_intrs = 0; |
| 571 | } else { |
| 572 | if (!scn->per_ce_irq) { |
| 573 | free_irq(sc->irq, sc); |
| 574 | } else { |
| 575 | for (i = 0; i < scn->ce_count; i++) { |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 576 | free_irq(ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i], |
| 577 | sc); |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 578 | } |
| 579 | } |
| 580 | } |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 581 | scn->request_irq_done = false; |
Kiran Venkatappa | a17e5e5 | 2016-12-20 11:32:06 +0530 | [diff] [blame^] | 582 | |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 583 | } |
| 584 | |
| 585 | /** |
| 586 | * ce_irq_enable() - enable copy engine IRQ |
| 587 | * @scn: struct hif_softc |
| 588 | * @ce_id: ce_id |
| 589 | * |
| 590 | * This function enables the interrupt for the radio. |
| 591 | * |
| 592 | * Return: N/A |
| 593 | */ |
| 594 | void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id) |
| 595 | { |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 596 | uint32_t regval; |
| 597 | uint32_t reg_offset = 0; |
| 598 | struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); |
| 599 | struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id]; |
| 600 | |
| 601 | if (scn->per_ce_irq) { |
| 602 | if (target_ce_conf->pipedir & PIPEDIR_OUT) { |
| 603 | reg_offset = HOST_IE_ADDRESS; |
| 604 | qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); |
| 605 | regval = hif_read32_mb(scn->mem + reg_offset); |
| 606 | regval |= (1 << ce_id); |
| 607 | hif_write32_mb(scn->mem + reg_offset, regval); |
| 608 | qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); |
| 609 | } |
| 610 | if (target_ce_conf->pipedir & PIPEDIR_IN) { |
| 611 | reg_offset = HOST_IE_ADDRESS_2; |
| 612 | qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); |
| 613 | regval = hif_read32_mb(scn->mem + reg_offset); |
| 614 | regval |= (1 << ce_id); |
| 615 | hif_write32_mb(scn->mem + reg_offset, regval); |
| 616 | qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); |
| 617 | } |
| 618 | } else { |
| 619 | hif_pci_irq_enable(scn, ce_id); |
| 620 | } |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 621 | } |
| 622 | |
| 623 | /** |
| 624 | * ce_irq_disable() - disable copy engine IRQ |
| 625 | * @scn: struct hif_softc |
| 626 | * @ce_id: ce_id |
| 627 | * |
| 628 | * Return: N/A |
| 629 | */ |
| 630 | void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id) |
| 631 | { |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 632 | uint32_t regval; |
| 633 | uint32_t reg_offset = 0; |
| 634 | struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); |
| 635 | struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id]; |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 636 | |
Venkateswara Swamy Bandaru | 9fd9af0 | 2016-09-20 20:27:31 +0530 | [diff] [blame] | 637 | if (scn->per_ce_irq) { |
| 638 | if (target_ce_conf->pipedir & PIPEDIR_OUT) { |
| 639 | reg_offset = HOST_IE_ADDRESS; |
| 640 | qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); |
| 641 | regval = hif_read32_mb(scn->mem + reg_offset); |
| 642 | regval &= ~(1 << ce_id); |
| 643 | hif_write32_mb(scn->mem + reg_offset, regval); |
| 644 | qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); |
| 645 | } |
| 646 | if (target_ce_conf->pipedir & PIPEDIR_IN) { |
| 647 | reg_offset = HOST_IE_ADDRESS_2; |
| 648 | qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); |
| 649 | regval = hif_read32_mb(scn->mem + reg_offset); |
| 650 | regval &= ~(1 << ce_id); |
| 651 | hif_write32_mb(scn->mem + reg_offset, regval); |
| 652 | qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); |
| 653 | } |
| 654 | } |
Houston Hoffman | 3db96a4 | 2016-05-05 19:54:39 -0700 | [diff] [blame] | 655 | } |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 656 | |
| 657 | void hif_ahb_grp_irq_disable(struct hif_softc *scn, uint32_t grp_id) |
| 658 | { |
| 659 | struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); |
| 660 | struct hif_ext_group_entry *hif_ext_group; |
| 661 | uint32_t i; |
| 662 | |
| 663 | hif_ext_group = &hif_state->hif_ext_group[grp_id]; |
| 664 | |
| 665 | for (i = 0; i < hif_ext_group->numirq; i++) { |
Pamidipati, Vijay | 30dc8f2 | 2016-10-26 21:54:23 +0530 | [diff] [blame] | 666 | disable_irq_nosync(ic_irqnum[hif_ext_group->irq[i]]); |
Venkateswara Swamy Bandaru | 31108f3 | 2016-08-08 18:04:29 +0530 | [diff] [blame] | 667 | } |
| 668 | } |
| 669 | |
| 670 | void hif_ahb_grp_irq_enable(struct hif_softc *scn, uint32_t grp_id) |
| 671 | { |
| 672 | struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); |
| 673 | struct hif_ext_group_entry *hif_ext_group; |
| 674 | uint32_t i; |
| 675 | |
| 676 | hif_ext_group = &hif_state->hif_ext_group[grp_id]; |
| 677 | |
| 678 | for (i = 0; i < hif_ext_group->numirq; i++) { |
| 679 | enable_irq(ic_irqnum[hif_ext_group->irq[i]]); |
| 680 | } |
| 681 | } |