blob: 3b5e0f6ac5acfdae44ce9417c36df87bf118f501 [file] [log] [blame]
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08001/*
Houston Hoffmanf2ff37a2015-11-03 11:33:36 -08002 * Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: if_snoc.c
30 *
31 * c file for snoc specif implementations.
32 */
33
34#include "hif.h"
35#include "hif_main.h"
36#include "hif_debug.h"
37#include "hif_io32.h"
38#include "ce_main.h"
39#include "ce_tasklet.h"
Houston Hoffman8f239f62016-03-14 21:12:05 -070040#include "snoc_api.h"
Houston Hoffmancb9bc632016-08-08 21:46:55 -070041#include <soc/qcom/icnss.h>
Yuanyuan Liufd594c22016-04-25 13:59:19 -070042#include "pld_common.h"
Houston Hoffmancb9bc632016-08-08 21:46:55 -070043#include "qdf_util.h"
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080044
45/**
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080046 * hif_disable_isr(): disable isr
47 *
48 * This function disables isr and kills tasklets
49 *
Komal Seelam644263d2016-02-22 20:45:49 +053050 * @hif_ctx: struct hif_softc
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080051 *
52 * Return: void
53 */
Houston Hoffman8f239f62016-03-14 21:12:05 -070054void hif_snoc_disable_isr(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080055{
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080056 hif_nointrs(scn);
Komal Seelam02cf2f82016-02-22 20:44:25 +053057 ce_tasklet_kill(scn);
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +053058 hif_grp_tasklet_kill(scn);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +053059 qdf_atomic_set(&scn->active_tasklet_cnt, 0);
Venkateswara Swamy Bandaru31108f32016-08-08 18:04:29 +053060 qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -080061}
62
63/**
Govind Singh2443fb32016-01-13 17:44:48 +053064 * hif_dump_registers(): dump bus debug registers
Komal Seelam5584a7c2016-02-24 19:22:48 +053065 * @scn: struct hif_opaque_softc
Govind Singh2443fb32016-01-13 17:44:48 +053066 *
67 * This function dumps hif bus debug registers
Komal Seelam5584a7c2016-02-24 19:22:48 +053068 *
Govind Singh2443fb32016-01-13 17:44:48 +053069 * Return: 0 for success or error code
70 */
Houston Hoffman3c017e72016-03-14 21:12:11 -070071int hif_snoc_dump_registers(struct hif_softc *hif_ctx)
Govind Singh2443fb32016-01-13 17:44:48 +053072{
73 int status;
Houston Hoffman108da402016-03-14 21:11:24 -070074 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
Govind Singh2443fb32016-01-13 17:44:48 +053075
76 status = hif_dump_ce_registers(scn);
77 if (status)
78 HIF_ERROR("%s: Dump CE Registers Failed", __func__);
79
Govind Singh2443fb32016-01-13 17:44:48 +053080 return 0;
81}
82
Nirav Shahb70bd732016-05-25 14:31:51 +053083void hif_snoc_display_stats(struct hif_softc *hif_ctx)
84{
85 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
86
87 if (hif_state == NULL) {
88 HIF_ERROR("%s, hif_ctx null", __func__);
89 return;
90 }
91 hif_display_ce_stats(hif_state);
92}
93
94void hif_snoc_clear_stats(struct hif_softc *hif_ctx)
95{
96 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
97
98 if (hif_state == NULL) {
99 HIF_ERROR("%s, hif_ctx null", __func__);
100 return;
101 }
102 hif_clear_ce_stats(hif_state);
103}
104
Govind Singh2443fb32016-01-13 17:44:48 +0530105/**
Houston Hoffman4ca03b62016-03-14 21:11:51 -0700106 * hif_snoc_close(): hif_bus_close
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800107 *
108 * Return: n/a
109 */
Houston Hoffman32bc8eb2016-03-14 21:11:34 -0700110void hif_snoc_close(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800111{
Houston Hoffman108da402016-03-14 21:11:24 -0700112 hif_ce_close(scn);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800113}
114
115/**
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800116 * hif_bus_open(): hif_bus_open
Houston Hoffman32bc8eb2016-03-14 21:11:34 -0700117 * @hif_ctx: hif context
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800118 * @bus_type: bus type
119 *
120 * Return: n/a
121 */
Houston Hoffman32bc8eb2016-03-14 21:11:34 -0700122QDF_STATUS hif_snoc_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800123{
Houston Hoffman32bc8eb2016-03-14 21:11:34 -0700124 return hif_ce_open(hif_ctx);
Houston Hoffman108da402016-03-14 21:11:24 -0700125}
126
127/**
128 * hif_snoc_get_soc_info() - populates scn with hw info
129 *
130 * fills in the virtual and physical base address as well as
131 * soc version info.
132 *
133 * return 0 or QDF_STATUS_E_FAILURE
134 */
135static QDF_STATUS hif_snoc_get_soc_info(struct hif_softc *scn)
136{
137 int ret;
Yuanyuan Liufd594c22016-04-25 13:59:19 -0700138 struct pld_soc_info soc_info;
Houston Hoffman108da402016-03-14 21:11:24 -0700139
Houston Hoffman32bc8eb2016-03-14 21:11:34 -0700140 qdf_mem_zero(&soc_info, sizeof(soc_info));
Houston Hoffman108da402016-03-14 21:11:24 -0700141
Yuanyuan Liufd594c22016-04-25 13:59:19 -0700142 ret = pld_get_soc_info(scn->qdf_dev->dev, &soc_info);
Houston Hoffman108da402016-03-14 21:11:24 -0700143 if (ret < 0) {
Yuanyuan Liufd594c22016-04-25 13:59:19 -0700144 HIF_ERROR("%s: pld_get_soc_info error = %d", __func__, ret);
Houston Hoffman108da402016-03-14 21:11:24 -0700145 return QDF_STATUS_E_FAILURE;
146 }
147
148 scn->mem = soc_info.v_addr;
149 scn->mem_pa = soc_info.p_addr;
Houston Hoffmancd0884a2016-08-24 15:30:09 -0700150
151 scn->target_info.soc_version = soc_info.soc_id;
152 scn->target_info.target_version = soc_info.soc_id;
153 scn->target_info.target_revision = 0;
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530154 return QDF_STATUS_SUCCESS;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800155}
156
157/**
Houston Hoffman108da402016-03-14 21:11:24 -0700158 * hif_bus_configure() - configure the snoc bus
159 * @scn: pointer to the hif context.
160 *
161 * return: 0 for success. nonzero for failure.
162 */
Houston Hoffman8f239f62016-03-14 21:12:05 -0700163int hif_snoc_bus_configure(struct hif_softc *scn)
Houston Hoffman108da402016-03-14 21:11:24 -0700164{
165 int ret;
166
167 ret = hif_snoc_get_soc_info(scn);
168 if (ret)
169 return ret;
170
171 hif_ce_prepare_config(scn);
172
173 ret = hif_wlan_enable(scn);
174 if (ret) {
175 HIF_ERROR("%s: hif_wlan_enable error = %d",
176 __func__, ret);
177 return ret;
178 }
179
180 ret = hif_config_ce(scn);
181 if (ret)
182 hif_wlan_disable(scn);
183 return ret;
184}
185
186/**
Houston Hoffman795299c2016-03-04 16:55:10 -0800187 * hif_snoc_get_target_type(): Get the target type
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800188 *
189 * This function is used to query the target type.
190 *
Komal Seelam644263d2016-02-22 20:45:49 +0530191 * @ol_sc: hif_softc struct pointer
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800192 * @dev: device pointer
193 * @bdev: bus dev pointer
194 * @bid: bus id pointer
195 * @hif_type: HIF type such as HIF_TYPE_QCA6180
196 * @target_type: target type such as TARGET_TYPE_QCA6180
197 *
198 * Return: 0 for success
199 */
Houston Hoffman795299c2016-03-04 16:55:10 -0800200static inline int hif_snoc_get_target_type(struct hif_softc *ol_sc,
201 struct device *dev, void *bdev, const hif_bus_id *bid,
202 uint32_t *hif_type, uint32_t *target_type)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800203{
Yuanyuan Liufd594c22016-04-25 13:59:19 -0700204 /* TODO: need to use HW version. Hard code for now */
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800205#ifdef QCA_WIFI_3_0_ADRASTEA
206 *hif_type = HIF_TYPE_ADRASTEA;
207 *target_type = TARGET_TYPE_ADRASTEA;
208#else
209 *hif_type = 0;
210 *target_type = 0;
211#endif
212 return 0;
213}
214
215/**
216 * hif_enable_bus(): hif_enable_bus
217 * @dev: dev
218 * @bdev: bus dev
219 * @bid: bus id
220 * @type: bus type
221 *
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530222 * Return: QDF_STATUS
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800223 */
Houston Hoffman8f239f62016-03-14 21:12:05 -0700224QDF_STATUS hif_snoc_enable_bus(struct hif_softc *ol_sc,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800225 struct device *dev, void *bdev,
226 const hif_bus_id *bid,
227 enum hif_enable_type type)
228{
229 int ret;
230 int hif_type;
231 int target_type;
Houston Hoffman834b9272016-09-27 23:42:48 -0700232
233 if (!ol_sc) {
234 HIF_ERROR("%s: hif_ctx is NULL", __func__);
235 return QDF_STATUS_E_NOMEM;
236 }
237
Houston Hoffman6296c3e2016-07-12 18:43:32 -0700238#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
Houston Hoffman047571e2016-06-02 09:04:21 -0700239 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(37));
Houston Hoffman6296c3e2016-07-12 18:43:32 -0700240#else
241 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(37));
242#endif
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800243 if (ret) {
244 HIF_ERROR("%s: failed to set dma mask error = %d",
245 __func__, ret);
246 return ret;
247 }
248
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700249 ret = qdf_device_init_wakeup(ol_sc->qdf_dev, true);
250 if (ret == -EEXIST)
251 HIF_WARN("%s: device_init_wakeup already done",
252 __func__);
253 else if (ret) {
254 HIF_ERROR("%s: device_init_wakeup: err= %d",
255 __func__, ret);
256 return ret;
257 }
258
Houston Hoffman795299c2016-03-04 16:55:10 -0800259 ret = hif_snoc_get_target_type(ol_sc, dev, bdev, bid,
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800260 &hif_type, &target_type);
261 if (ret < 0) {
262 HIF_ERROR("%s: invalid device id/revision_id", __func__);
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530263 return QDF_STATUS_E_FAILURE;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800264 }
265
Houston Hoffman004ec912016-06-06 11:41:55 -0700266 ol_sc->target_info.target_type = target_type;
267
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800268 hif_register_tbl_attach(ol_sc, hif_type);
Govind Singh051a8c42016-05-10 12:23:41 +0530269 hif_target_register_tbl_attach(ol_sc, target_type);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800270
Houston Hoffmanc1064a82016-07-25 13:22:25 -0700271 /* the bus should remain on durring suspend for snoc */
272 hif_vote_link_up(GET_HIF_OPAQUE_HDL(ol_sc));
273
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800274 HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x",
275 __func__, hif_type, target_type);
276
Chouhan, Anuragfc06aa92016-03-03 19:05:05 +0530277 return QDF_STATUS_SUCCESS;
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800278}
279
280/**
281 * hif_disable_bus(): hif_disable_bus
282 *
283 * This function disables the bus
284 *
285 * @bdev: bus dev
286 *
287 * Return: none
288 */
Houston Hoffman8f239f62016-03-14 21:12:05 -0700289void hif_snoc_disable_bus(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800290{
Houston Hoffmanc1064a82016-07-25 13:22:25 -0700291 int ret;
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700292
Houston Hoffmanc1064a82016-07-25 13:22:25 -0700293 hif_vote_link_down(GET_HIF_OPAQUE_HDL(scn));
294
295 ret = qdf_device_init_wakeup(scn->qdf_dev, false);
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700296 if (ret)
297 HIF_ERROR("%s: device_init_wakeup: err %d", __func__, ret);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800298}
299
300/**
301 * hif_nointrs(): disable IRQ
302 *
303 * This function stops interrupt(s)
304 *
Komal Seelam644263d2016-02-22 20:45:49 +0530305 * @scn: struct hif_softc
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800306 *
307 * Return: none
308 */
Houston Hoffman8f239f62016-03-14 21:12:05 -0700309void hif_snoc_nointrs(struct hif_softc *scn)
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800310{
Komal Seelam02cf2f82016-02-22 20:44:25 +0530311 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn);
Kiran Venkatappaa17e5e52016-12-20 11:32:06 +0530312
313 ce_unregister_irq(hif_state, CE_ALL_BITMAP);
Prakash Dhavalid5c9f1c2015-11-08 19:04:44 -0800314}
Houston Hoffman8f239f62016-03-14 21:12:05 -0700315
316/**
317 * ce_irq_enable() - enable copy engine IRQ
318 * @scn: struct hif_softc
319 * @ce_id: ce_id
320 *
321 * Return: N/A
322 */
323void hif_snoc_irq_enable(struct hif_softc *scn,
324 int ce_id)
325{
Houston Hoffman8f239f62016-03-14 21:12:05 -0700326 ce_enable_irq_in_individual_register(scn, ce_id);
Houston Hoffman8f239f62016-03-14 21:12:05 -0700327}
328
329/**
330 * ce_irq_disable() - disable copy engine IRQ
331 * @scn: struct hif_softc
332 * @ce_id: ce_id
333 *
334 * Return: N/A
335 */
336void hif_snoc_irq_disable(struct hif_softc *scn, int ce_id)
337{
Houston Hoffman8f239f62016-03-14 21:12:05 -0700338 ce_disable_irq_in_individual_register(scn, ce_id);
339}
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700340
341/*
342 * hif_snoc_setup_wakeup_sources() - enable/disable irq wake on correct irqs
343 * @hif_softc: hif context
344 *
345 * Firmware will send a wakeup request to the HTC_CTRL_RSVD_SVC when waking up
346 * the host driver. Ensure that the copy complete interrupt from this copy
347 * engine can wake up the apps processor.
348 *
349 * Return: 0 for success
350 */
Jeff Johnson6950fdb2016-10-07 13:00:59 -0700351static
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700352QDF_STATUS hif_snoc_setup_wakeup_sources(struct hif_softc *scn, bool enable)
353{
354 struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(scn);
355 uint8_t ul_pipe, dl_pipe;
356 int ul_is_polled, dl_is_polled;
357 int irq_to_wake_on;
358
359 QDF_STATUS status;
360 int ret;
361
362 status = hif_map_service_to_pipe(hif_hdl, HTC_CTRL_RSVD_SVC,
363 &ul_pipe, &dl_pipe,
364 &ul_is_polled, &dl_is_polled);
365 if (status) {
366 HIF_ERROR("%s: pipe_mapping failure", __func__);
367 return status;
368 }
369
370 irq_to_wake_on = icnss_get_irq(dl_pipe);
371 if (irq_to_wake_on < 0) {
372 HIF_ERROR("%s: failed to map ce to irq", __func__);
373 return QDF_STATUS_E_RESOURCES;
374 }
375
376 if (enable)
377 ret = enable_irq_wake(irq_to_wake_on);
378 else
379 ret = disable_irq_wake(irq_to_wake_on);
380
381 if (ret) {
382 HIF_ERROR("%s: Fail to setup wake IRQ!", __func__);
383 return QDF_STATUS_E_RESOURCES;
384 }
385
Rajeev Kumar8f312f22016-08-24 16:24:51 -0700386 HIF_INFO("%s: expecting wake from ce %d, irq %d enable %d",
387 __func__, dl_pipe, irq_to_wake_on, enable);
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700388 return QDF_STATUS_SUCCESS;
389}
390
Houston Hoffman8a3a9a42016-08-08 21:08:20 -0700391/**
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700392 * hif_snoc_bus_suspend() - prepare to suspend the bus
393 * @scn: hif context
394 *
395 * Setup wakeup interrupt configuration.
Houston Hoffman8a3a9a42016-08-08 21:08:20 -0700396 * Disable CE interrupts (wakeup interrupt will still wake apps)
397 * Drain tasklets. - make sure that we don't suspend while processing
398 * the wakeup message.
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700399 *
400 * Return: 0 on success.
401 */
402int hif_snoc_bus_suspend(struct hif_softc *scn)
403{
404 if (hif_snoc_setup_wakeup_sources(scn, true) != QDF_STATUS_SUCCESS)
Houston Hoffman7fdff0c2016-08-29 12:31:58 -0700405 return -EFAULT;
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700406 return 0;
407}
408
409/**
410 * hif_snoc_bus_resume() - snoc bus resume function
411 * @scn: hif context
412 *
413 * Clear wakeup interrupt configuration.
Houston Hoffman8a3a9a42016-08-08 21:08:20 -0700414 * Reenable ce interrupts
Houston Hoffmancb9bc632016-08-08 21:46:55 -0700415 *
416 * Return: 0 on success
417 */
418int hif_snoc_bus_resume(struct hif_softc *scn)
419{
420 if (hif_snoc_setup_wakeup_sources(scn, false) != QDF_STATUS_SUCCESS)
421 QDF_BUG(0);
422
423 return 0;
424}
Houston Hoffman7fdff0c2016-08-29 12:31:58 -0700425
426/**
427 * hif_snoc_bus_suspend_noirq() - ensure there are no pending transactions
428 * @scn: hif context
429 *
430 * Ensure that if we recieved the wakeup message before the irq
431 * was disabled that the message is pocessed before suspending.
432 *
433 * Return: -EBUSY if we fail to flush the tasklets.
434 */
435int hif_snoc_bus_suspend_noirq(struct hif_softc *scn)
436{
437 if (hif_drain_tasklets(scn) != 0)
438 return -EBUSY;
439 return 0;
440}
441