blob: f64e9de563182d0354b190362bf5d111ba695cd2 [file] [log] [blame]
Lior David639ebed2017-02-28 14:23:55 +02001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/of.h>
16#include <linux/of_gpio.h>
17#include <linux/msm_pcie.h>
18#include <asm/dma-iommu.h>
19#include <linux/msm-bus.h>
20#include <linux/iommu.h>
21#include <linux/version.h>
22#include <linux/delay.h>
23#include <soc/qcom/subsystem_restart.h>
24#include <soc/qcom/subsystem_notif.h>
25#include <soc/qcom/ramdump.h>
26#include <soc/qcom/memory_dump.h>
27#include <linux/regulator/consumer.h>
28#include <linux/clk.h>
Lior Daviddb711962017-02-15 21:04:55 +020029#include <linux/interrupt.h>
30#include <linux/cpumask.h>
31#include <linux/cpufreq.h>
32#include <linux/sched/core_ctl.h>
Lior David639ebed2017-02-28 14:23:55 +020033#include "wil_platform.h"
34#include "msm_11ad.h"
35
36#define WIGIG_VENDOR (0x1ae9)
37#define WIGIG_DEVICE (0x0310)
38
Maya Erez34c251e2017-03-27 09:31:39 +030039#define SMMU_BASE 0x20000000 /* Device address range base */
Lior David639ebed2017-02-28 14:23:55 +020040#define SMMU_SIZE ((SZ_1G * 4ULL) - SMMU_BASE)
41
42#define WIGIG_ENABLE_DELAY 50
Lior David639ebed2017-02-28 14:23:55 +020043
44#define WIGIG_SUBSYS_NAME "WIGIG"
45#define WIGIG_RAMDUMP_SIZE 0x200000 /* maximum ramdump size */
46#define WIGIG_DUMP_FORMAT_VER 0x1
47#define WIGIG_DUMP_MAGIC_VER_V1 0x57474947
48#define VDD_MIN_UV 1028000
49#define VDD_MAX_UV 1028000
50#define VDD_MAX_UA 575000
51#define VDDIO_MIN_UV 1950000
52#define VDDIO_MAX_UV 2040000
53#define VDDIO_MAX_UA 70300
54
Maya Erez17ef6c32017-03-27 08:37:07 +030055#define PCIE20_CAP_LINKCTRLSTATUS 0x80
56
Maya Erez3ef3e362017-03-27 08:47:02 +030057#define WIGIG_MIN_CPU_BOOST_KBPS 150000
58
Lior David639ebed2017-02-28 14:23:55 +020059struct device;
60
61static const char * const gpio_en_name = "qcom,wigig-en";
62static const char * const sleep_clk_en_name = "qcom,sleep-clk-en";
63
64struct msm11ad_vreg {
65 const char *name;
66 struct regulator *reg;
67 int max_uA;
68 int min_uV;
69 int max_uV;
70 bool enabled;
71};
72
73struct msm11ad_clk {
74 const char *name;
75 struct clk *clk;
76 bool enabled;
77};
78
79struct msm11ad_ctx {
80 struct list_head list;
81 struct device *dev; /* for platform device */
82 int gpio_en; /* card enable */
83 int sleep_clk_en; /* sleep clock enable for low PM management */
84
85 /* pci device */
86 u32 rc_index; /* PCIE root complex index */
87 struct pci_dev *pcidev;
88 struct pci_saved_state *pristine_state;
Maya Erez3ef3e362017-03-27 08:47:02 +030089 bool l1_enabled_in_enum;
Lior David639ebed2017-02-28 14:23:55 +020090
91 /* SMMU */
92 bool use_smmu; /* have SMMU enabled? */
Maya Erez34c251e2017-03-27 09:31:39 +030093 int smmu_s1_en;
Lior David639ebed2017-02-28 14:23:55 +020094 int smmu_fast_map;
Maya Erez34c251e2017-03-27 09:31:39 +030095 int smmu_coherent;
Lior David639ebed2017-02-28 14:23:55 +020096 struct dma_iommu_mapping *mapping;
Maya Erez34c251e2017-03-27 09:31:39 +030097 u32 smmu_base;
98 u32 smmu_size;
Lior David639ebed2017-02-28 14:23:55 +020099
100 /* bus frequency scaling */
101 struct msm_bus_scale_pdata *bus_scale;
102 u32 msm_bus_handle;
103
104 /* subsystem restart */
105 struct wil_platform_rops rops;
106 void *wil_handle;
107 struct subsys_desc subsysdesc;
108 struct subsys_device *subsys;
109 void *subsys_handle;
110 bool recovery_in_progress;
111
112 /* ramdump */
113 void *ramdump_addr;
114 struct msm_dump_data dump_data;
115 struct ramdump_device *ramdump_dev;
116
117 /* external vregs and clocks */
118 struct msm11ad_vreg vdd;
119 struct msm11ad_vreg vddio;
120 struct msm11ad_clk rf_clk3;
121 struct msm11ad_clk rf_clk3_pin;
Lior Daviddb711962017-02-15 21:04:55 +0200122
123 /* cpu boost support */
124 bool use_cpu_boost;
125 bool is_cpu_boosted;
126 struct cpumask boost_cpu;
Maya Erez692e94c2017-05-14 16:40:19 +0300127
128 bool keep_radio_on_during_sleep;
Maya Erez308f9fe2017-11-08 21:35:31 +0200129 int features;
Lior David639ebed2017-02-28 14:23:55 +0200130};
131
132static LIST_HEAD(dev_list);
133
134static struct msm11ad_ctx *pcidev2ctx(struct pci_dev *pcidev)
135{
136 struct msm11ad_ctx *ctx;
137
138 list_for_each_entry(ctx, &dev_list, list) {
139 if (ctx->pcidev == pcidev)
140 return ctx;
141 }
142 return NULL;
143}
144
145static int msm_11ad_init_vreg(struct device *dev,
146 struct msm11ad_vreg *vreg, const char *name)
147{
148 int rc = 0;
149
150 if (!vreg)
151 return 0;
152
153 vreg->name = kstrdup(name, GFP_KERNEL);
154 if (!vreg->name)
155 return -ENOMEM;
156
157 vreg->reg = devm_regulator_get(dev, name);
158 if (IS_ERR_OR_NULL(vreg->reg)) {
159 rc = PTR_ERR(vreg->reg);
160 dev_err(dev, "%s: failed to get %s, rc=%d\n",
161 __func__, name, rc);
162 kfree(vreg->name);
163 vreg->reg = NULL;
164 goto out;
165 }
166
167 dev_info(dev, "%s: %s initialized successfully\n", __func__, name);
168
169out:
170 return rc;
171}
172
173static int msm_11ad_release_vreg(struct device *dev, struct msm11ad_vreg *vreg)
174{
175 if (!vreg || !vreg->reg)
176 return 0;
177
178 dev_info(dev, "%s: %s released\n", __func__, vreg->name);
179
180 devm_regulator_put(vreg->reg);
181 vreg->reg = NULL;
182 kfree(vreg->name);
183
184 return 0;
185}
186
187static int msm_11ad_init_clk(struct device *dev, struct msm11ad_clk *clk,
188 const char *name)
189{
190 int rc = 0;
191
192 clk->name = kstrdup(name, GFP_KERNEL);
193 if (!clk->name)
194 return -ENOMEM;
195
196 clk->clk = devm_clk_get(dev, name);
197 if (IS_ERR(clk->clk)) {
198 rc = PTR_ERR(clk->clk);
199 if (rc == -ENOENT)
200 rc = -EPROBE_DEFER;
201 dev_err(dev, "%s: failed to get %s rc %d",
202 __func__, name, rc);
203 kfree(clk->name);
204 clk->clk = NULL;
205 goto out;
206 }
207
208 dev_info(dev, "%s: %s initialized successfully\n", __func__, name);
209
210out:
211 return rc;
212}
213
214static int msm_11ad_release_clk(struct device *dev, struct msm11ad_clk *clk)
215{
216 if (!clk || !clk->clk)
217 return 0;
218
219 dev_info(dev, "%s: %s released\n", __func__, clk->name);
220
221 devm_clk_put(dev, clk->clk);
222 clk->clk = NULL;
223
224 kfree(clk->name);
225
226 return 0;
227}
228
229static int msm_11ad_init_vregs(struct msm11ad_ctx *ctx)
230{
231 int rc;
232 struct device *dev = ctx->dev;
233
234 if (!of_property_read_bool(dev->of_node, "qcom,use-ext-supply"))
235 return 0;
236
237 rc = msm_11ad_init_vreg(dev, &ctx->vdd, "vdd");
238 if (rc)
239 goto out;
240
241 ctx->vdd.max_uV = VDD_MAX_UV;
242 ctx->vdd.min_uV = VDD_MIN_UV;
243 ctx->vdd.max_uA = VDD_MAX_UA;
244
245 rc = msm_11ad_init_vreg(dev, &ctx->vddio, "vddio");
246 if (rc)
247 goto vddio_fail;
248
249 ctx->vddio.max_uV = VDDIO_MAX_UV;
250 ctx->vddio.min_uV = VDDIO_MIN_UV;
251 ctx->vddio.max_uA = VDDIO_MAX_UA;
252
253 return rc;
254
255vddio_fail:
256 msm_11ad_release_vreg(dev, &ctx->vdd);
257out:
258 return rc;
259}
260
261static void msm_11ad_release_vregs(struct msm11ad_ctx *ctx)
262{
263 msm_11ad_release_vreg(ctx->dev, &ctx->vdd);
264 msm_11ad_release_vreg(ctx->dev, &ctx->vddio);
265}
266
267static int msm_11ad_cfg_vreg(struct device *dev,
268 struct msm11ad_vreg *vreg, bool on)
269{
270 int rc = 0;
271 int min_uV;
272 int uA_load;
273
274 if (!vreg || !vreg->reg)
275 goto out;
276
277 if (regulator_count_voltages(vreg->reg) > 0) {
278 min_uV = on ? vreg->min_uV : 0;
279 rc = regulator_set_voltage(vreg->reg, min_uV, vreg->max_uV);
280 if (rc) {
281 dev_err(dev, "%s: %s set voltage failed, err=%d\n",
282 __func__, vreg->name, rc);
283 goto out;
284 }
285 uA_load = on ? vreg->max_uA : 0;
286 rc = regulator_set_load(vreg->reg, uA_load);
287 if (rc >= 0) {
288 /*
289 * regulator_set_load() returns new regulator
290 * mode upon success.
291 */
292 dev_dbg(dev,
293 "%s: %s regulator_set_load rc(%d)\n",
294 __func__, vreg->name, rc);
295 rc = 0;
296 } else {
297 dev_err(dev,
298 "%s: %s set load(uA_load=%d) failed, rc=%d\n",
299 __func__, vreg->name, uA_load, rc);
300 goto out;
301 }
302 }
303
304out:
305 return rc;
306}
307
308static int msm_11ad_enable_vreg(struct msm11ad_ctx *ctx,
309 struct msm11ad_vreg *vreg)
310{
311 struct device *dev = ctx->dev;
312 int rc = 0;
313
314 if (!vreg || !vreg->reg || vreg->enabled)
315 goto out;
316
317 rc = msm_11ad_cfg_vreg(dev, vreg, true);
318 if (rc)
319 goto out;
320
321 rc = regulator_enable(vreg->reg);
322 if (rc) {
323 dev_err(dev, "%s: %s enable failed, rc=%d\n",
324 __func__, vreg->name, rc);
325 goto enable_fail;
326 }
327
328 vreg->enabled = true;
329
330 dev_info(dev, "%s: %s enabled\n", __func__, vreg->name);
331
332 return rc;
333
334enable_fail:
335 msm_11ad_cfg_vreg(dev, vreg, false);
336out:
337 return rc;
338}
339
340static int msm_11ad_disable_vreg(struct msm11ad_ctx *ctx,
341 struct msm11ad_vreg *vreg)
342{
343 struct device *dev = ctx->dev;
344 int rc = 0;
345
346 if (!vreg || !vreg->reg || !vreg->enabled)
347 goto out;
348
349 rc = regulator_disable(vreg->reg);
350 if (rc) {
351 dev_err(dev, "%s: %s disable failed, rc=%d\n",
352 __func__, vreg->name, rc);
353 goto out;
354 }
355
356 /* ignore errors on applying disable config */
357 msm_11ad_cfg_vreg(dev, vreg, false);
358 vreg->enabled = false;
359
360 dev_info(dev, "%s: %s disabled\n", __func__, vreg->name);
361
362out:
363 return rc;
364}
365
366static int msm_11ad_enable_vregs(struct msm11ad_ctx *ctx)
367{
368 int rc = 0;
369
370 rc = msm_11ad_enable_vreg(ctx, &ctx->vdd);
371 if (rc)
372 goto out;
373
374 rc = msm_11ad_enable_vreg(ctx, &ctx->vddio);
375 if (rc)
376 goto vddio_fail;
377
378 return rc;
379
380vddio_fail:
381 msm_11ad_disable_vreg(ctx, &ctx->vdd);
382out:
383 return rc;
384}
385
386static int msm_11ad_disable_vregs(struct msm11ad_ctx *ctx)
387{
388 if (!ctx->vdd.reg && !ctx->vddio.reg)
389 goto out;
390
391 /* ignore errors on disable vreg */
392 msm_11ad_disable_vreg(ctx, &ctx->vdd);
393 msm_11ad_disable_vreg(ctx, &ctx->vddio);
394
395out:
396 return 0;
397}
398
399static int msm_11ad_enable_clk(struct msm11ad_ctx *ctx,
400 struct msm11ad_clk *clk)
401{
402 struct device *dev = ctx->dev;
403 int rc = 0;
404
405 if (!clk || !clk->clk || clk->enabled)
406 goto out;
407
408 rc = clk_prepare_enable(clk->clk);
409 if (rc) {
410 dev_err(dev, "%s: failed to enable %s, rc(%d)\n",
411 __func__, clk->name, rc);
412 goto out;
413 }
414 clk->enabled = true;
415
416 dev_dbg(dev, "%s: %s enabled\n", __func__, clk->name);
417
418out:
419 return rc;
420}
421
422static void msm_11ad_disable_clk(struct msm11ad_ctx *ctx,
423 struct msm11ad_clk *clk)
424{
425 struct device *dev = ctx->dev;
426
427 if (!clk || !clk->clk || !clk->enabled)
428 goto out;
429
430 clk_disable_unprepare(clk->clk);
431 clk->enabled = false;
432
433 dev_dbg(dev, "%s: %s disabled\n", __func__, clk->name);
434
435out:
436 return;
437}
438
439static int msm_11ad_enable_clocks(struct msm11ad_ctx *ctx)
440{
441 int rc;
442
443 rc = msm_11ad_enable_clk(ctx, &ctx->rf_clk3);
444 if (rc)
445 return rc;
446
447 rc = msm_11ad_enable_clk(ctx, &ctx->rf_clk3_pin);
448 if (rc)
449 msm_11ad_disable_clk(ctx, &ctx->rf_clk3);
450
451 return rc;
452}
453
454static int msm_11ad_init_clocks(struct msm11ad_ctx *ctx)
455{
456 int rc;
457 struct device *dev = ctx->dev;
458
459 if (!of_property_read_bool(dev->of_node, "qcom,use-ext-clocks"))
460 return 0;
461
462 rc = msm_11ad_init_clk(dev, &ctx->rf_clk3, "rf_clk3_clk");
463 if (rc)
464 return rc;
465
466 rc = msm_11ad_init_clk(dev, &ctx->rf_clk3_pin, "rf_clk3_pin_clk");
467 if (rc)
468 msm_11ad_release_clk(ctx->dev, &ctx->rf_clk3);
469
470 return rc;
471}
472
473static void msm_11ad_release_clocks(struct msm11ad_ctx *ctx)
474{
475 msm_11ad_release_clk(ctx->dev, &ctx->rf_clk3_pin);
476 msm_11ad_release_clk(ctx->dev, &ctx->rf_clk3);
477}
478
479static void msm_11ad_disable_clocks(struct msm11ad_ctx *ctx)
480{
481 msm_11ad_disable_clk(ctx, &ctx->rf_clk3_pin);
482 msm_11ad_disable_clk(ctx, &ctx->rf_clk3);
483}
484
Maya Erez3ef3e362017-03-27 08:47:02 +0300485int msm_11ad_ctrl_aspm_l1(struct msm11ad_ctx *ctx, bool enable)
486{
487 int rc;
488 u32 val;
489 struct pci_dev *pdev = ctx->pcidev;
490 bool l1_enabled;
491
492 /* Read current state */
493 rc = pci_read_config_dword(pdev,
494 PCIE20_CAP_LINKCTRLSTATUS, &val);
495 if (rc) {
496 dev_err(ctx->dev,
497 "reading PCIE20_CAP_LINKCTRLSTATUS failed:%d\n", rc);
498 return rc;
499 }
500 dev_dbg(ctx->dev, "PCIE20_CAP_LINKCTRLSTATUS read returns 0x%x\n", val);
501
502 l1_enabled = val & PCI_EXP_LNKCTL_ASPM_L1;
503 if (l1_enabled == enable) {
504 dev_dbg(ctx->dev, "ASPM_L1 is already %s\n",
505 l1_enabled ? "enabled" : "disabled");
506 return 0;
507 }
508
509 if (enable)
510 val |= PCI_EXP_LNKCTL_ASPM_L1; /* enable bit 1 */
511 else
512 val &= ~PCI_EXP_LNKCTL_ASPM_L1; /* disable bit 1 */
513
514 dev_dbg(ctx->dev, "writing PCIE20_CAP_LINKCTRLSTATUS (val 0x%x)\n",
515 val);
516 rc = pci_write_config_dword(pdev,
517 PCIE20_CAP_LINKCTRLSTATUS, val);
518 if (rc)
519 dev_err(ctx->dev,
520 "writing PCIE20_CAP_LINKCTRLSTATUS (val 0x%x) failed:%d\n",
521 val, rc);
522
523 return rc;
524}
525
Maya Erez692e94c2017-05-14 16:40:19 +0300526static int msm_11ad_turn_device_power_off(struct msm11ad_ctx *ctx)
Lior David639ebed2017-02-28 14:23:55 +0200527{
Lior David639ebed2017-02-28 14:23:55 +0200528 if (ctx->gpio_en >= 0)
529 gpio_direction_output(ctx->gpio_en, 0);
530
531 if (ctx->sleep_clk_en >= 0)
532 gpio_direction_output(ctx->sleep_clk_en, 0);
533
534 msm_11ad_disable_clocks(ctx);
535
536 msm_11ad_disable_vregs(ctx);
537
Maya Erez692e94c2017-05-14 16:40:19 +0300538 return 0;
Lior David639ebed2017-02-28 14:23:55 +0200539}
540
Maya Erez692e94c2017-05-14 16:40:19 +0300541static int msm_11ad_turn_device_power_on(struct msm11ad_ctx *ctx)
Lior David639ebed2017-02-28 14:23:55 +0200542{
543 int rc;
Lior David639ebed2017-02-28 14:23:55 +0200544
545 rc = msm_11ad_enable_vregs(ctx);
546 if (rc) {
547 dev_err(ctx->dev, "msm_11ad_enable_vregs failed :%d\n",
548 rc);
549 return rc;
550 }
551
552 rc = msm_11ad_enable_clocks(ctx);
553 if (rc) {
554 dev_err(ctx->dev, "msm_11ad_enable_clocks failed :%d\n", rc);
555 goto err_disable_vregs;
556 }
557
558 if (ctx->sleep_clk_en >= 0)
559 gpio_direction_output(ctx->sleep_clk_en, 1);
560
Lior David639ebed2017-02-28 14:23:55 +0200561 if (ctx->gpio_en >= 0) {
562 gpio_direction_output(ctx->gpio_en, 1);
563 msleep(WIGIG_ENABLE_DELAY);
564 }
565
Maya Erez692e94c2017-05-14 16:40:19 +0300566 return 0;
567
568err_disable_vregs:
569 msm_11ad_disable_vregs(ctx);
570 return rc;
571}
572
573static int msm_11ad_suspend_power_off(void *handle)
574{
575 int rc;
576 struct msm11ad_ctx *ctx = handle;
577 struct pci_dev *pcidev;
578
579 pr_debug("%s\n", __func__);
580
581 if (!ctx) {
582 pr_err("%s: No context\n", __func__);
583 return -ENODEV;
584 }
585
586 pcidev = ctx->pcidev;
587
588 msm_pcie_shadow_control(ctx->pcidev, 0);
589
590 rc = pci_save_state(pcidev);
591 if (rc) {
592 dev_err(ctx->dev, "pci_save_state failed :%d\n", rc);
593 goto out;
594 }
595 ctx->pristine_state = pci_store_saved_state(pcidev);
596
597 rc = msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number,
598 pcidev, NULL, 0);
599 if (rc) {
600 dev_err(ctx->dev, "msm_pcie_pm_control(SUSPEND) failed :%d\n",
601 rc);
602 goto out;
603 }
604
605 rc = msm_11ad_turn_device_power_off(ctx);
606
607out:
608 return rc;
609}
610
611static int ops_suspend(void *handle, bool keep_device_power)
612{
613 struct msm11ad_ctx *ctx = handle;
614 struct pci_dev *pcidev;
615 int rc;
616
617 pr_debug("11ad suspend: %s\n", __func__);
618 if (!ctx) {
619 pr_err("11ad suspend: No context\n");
620 return -ENODEV;
621 }
622
623 if (!keep_device_power)
624 return msm_11ad_suspend_power_off(handle);
625
626 pcidev = ctx->pcidev;
627
628 msm_pcie_shadow_control(pcidev, 0);
629
630 dev_dbg(ctx->dev, "disable device and save config\n");
631 pci_disable_device(pcidev);
632 pci_save_state(pcidev);
633 ctx->pristine_state = pci_store_saved_state(pcidev);
634 dev_dbg(ctx->dev, "moving to D3\n");
635 pci_set_power_state(pcidev, PCI_D3hot);
636
637 rc = msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number,
638 pcidev, NULL, 0);
639 if (rc)
640 dev_err(ctx->dev, "msm_pcie_pm_control(SUSPEND) failed :%d\n",
641 rc);
642
643 return rc;
644}
645
646static int msm_11ad_resume_power_on(void *handle)
647{
648 int rc;
649 struct msm11ad_ctx *ctx = handle;
650 struct pci_dev *pcidev;
651
652 pr_debug("%s\n", __func__);
653
654 if (!ctx) {
655 pr_err("%s: No context\n", __func__);
656 return -ENODEV;
657 }
658 pcidev = ctx->pcidev;
659
660 rc = msm_11ad_turn_device_power_on(ctx);
661 if (rc)
662 return rc;
663
Lior David639ebed2017-02-28 14:23:55 +0200664 rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number,
Maya Erez692e94c2017-05-14 16:40:19 +0300665 pcidev, NULL, 0);
Lior David639ebed2017-02-28 14:23:55 +0200666 if (rc) {
667 dev_err(ctx->dev, "msm_pcie_pm_control(RESUME) failed :%d\n",
668 rc);
669 goto err_disable_power;
670 }
Maya Erez692e94c2017-05-14 16:40:19 +0300671
672 pci_set_power_state(pcidev, PCI_D0);
673
674 if (ctx->pristine_state)
675 pci_load_saved_state(ctx->pcidev, ctx->pristine_state);
676 pci_restore_state(ctx->pcidev);
677
678 msm_pcie_shadow_control(ctx->pcidev, 1);
Lior David639ebed2017-02-28 14:23:55 +0200679
Maya Erez3ef3e362017-03-27 08:47:02 +0300680 /* Disable L1, in case it is enabled */
681 if (ctx->l1_enabled_in_enum) {
682 rc = msm_11ad_ctrl_aspm_l1(ctx, false);
683 if (rc) {
684 dev_err(ctx->dev,
685 "failed to disable L1, rc %d\n", rc);
686 goto err_suspend_rc;
687 }
Maya Erez17ef6c32017-03-27 08:37:07 +0300688 }
689
Lior David639ebed2017-02-28 14:23:55 +0200690 return 0;
691
692err_suspend_rc:
693 msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number,
Maya Erez692e94c2017-05-14 16:40:19 +0300694 pcidev, NULL, 0);
Lior David639ebed2017-02-28 14:23:55 +0200695err_disable_power:
Maya Erez692e94c2017-05-14 16:40:19 +0300696 msm_11ad_turn_device_power_off(ctx);
697 return rc;
698}
Lior David639ebed2017-02-28 14:23:55 +0200699
Maya Erez692e94c2017-05-14 16:40:19 +0300700static int ops_resume(void *handle, bool device_powered_on)
701{
702 struct msm11ad_ctx *ctx = handle;
703 struct pci_dev *pcidev;
704 int rc;
Lior David639ebed2017-02-28 14:23:55 +0200705
Maya Erez692e94c2017-05-14 16:40:19 +0300706 pr_debug("11ad resume: %s\n", __func__);
707 if (!ctx) {
708 pr_err("11ad resume: No context\n");
709 return -ENODEV;
710 }
Lior David639ebed2017-02-28 14:23:55 +0200711
Maya Erez692e94c2017-05-14 16:40:19 +0300712 pcidev = ctx->pcidev;
713
714 if (!device_powered_on)
715 return msm_11ad_resume_power_on(handle);
716
717 rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number,
718 pcidev, NULL, 0);
719 if (rc) {
720 dev_err(ctx->dev, "msm_pcie_pm_control(RESUME) failed :%d\n",
721 rc);
722 return rc;
723 }
724 pci_set_power_state(pcidev, PCI_D0);
725
726 dev_dbg(ctx->dev, "restore state and enable device\n");
727 pci_load_saved_state(pcidev, ctx->pristine_state);
728 pci_restore_state(pcidev);
729
730 rc = pci_enable_device(pcidev);
731 if (rc) {
732 dev_err(ctx->dev, "pci_enable_device failed (%d)\n", rc);
733 goto out;
734 }
735
736 msm_pcie_shadow_control(pcidev, 1);
737
738 dev_dbg(ctx->dev, "pci set master\n");
739 pci_set_master(pcidev);
740
741out:
Lior David639ebed2017-02-28 14:23:55 +0200742 return rc;
743}
744
745static int msm_11ad_smmu_init(struct msm11ad_ctx *ctx)
746{
747 int atomic_ctx = 1;
748 int rc;
Maya Erez34c251e2017-03-27 09:31:39 +0300749 int force_pt_coherent = 1;
750 int smmu_bypass = !ctx->smmu_s1_en;
Lior David639ebed2017-02-28 14:23:55 +0200751
752 if (!ctx->use_smmu)
753 return 0;
754
Maya Erez34c251e2017-03-27 09:31:39 +0300755 dev_info(ctx->dev, "Initialize SMMU, bypass=%d, fastmap=%d, coherent=%d\n",
756 smmu_bypass, ctx->smmu_fast_map, ctx->smmu_coherent);
Lior David639ebed2017-02-28 14:23:55 +0200757
758 ctx->mapping = arm_iommu_create_mapping(&platform_bus_type,
Maya Erez34c251e2017-03-27 09:31:39 +0300759 ctx->smmu_base, ctx->smmu_size);
Lior David639ebed2017-02-28 14:23:55 +0200760 if (IS_ERR_OR_NULL(ctx->mapping)) {
761 rc = PTR_ERR(ctx->mapping) ?: -ENODEV;
762 dev_err(ctx->dev, "Failed to create IOMMU mapping (%d)\n", rc);
763 return rc;
764 }
765
766 rc = iommu_domain_set_attr(ctx->mapping->domain,
767 DOMAIN_ATTR_ATOMIC,
768 &atomic_ctx);
769 if (rc) {
770 dev_err(ctx->dev, "Set atomic attribute to SMMU failed (%d)\n",
771 rc);
772 goto release_mapping;
773 }
774
Maya Erez34c251e2017-03-27 09:31:39 +0300775 if (smmu_bypass) {
Lior David639ebed2017-02-28 14:23:55 +0200776 rc = iommu_domain_set_attr(ctx->mapping->domain,
777 DOMAIN_ATTR_S1_BYPASS,
Maya Erez34c251e2017-03-27 09:31:39 +0300778 &smmu_bypass);
Lior David639ebed2017-02-28 14:23:55 +0200779 if (rc) {
780 dev_err(ctx->dev, "Set bypass attribute to SMMU failed (%d)\n",
781 rc);
782 goto release_mapping;
783 }
Maya Erez34c251e2017-03-27 09:31:39 +0300784 } else {
785 /* Set dma-coherent and page table coherency */
786 if (ctx->smmu_coherent) {
787 arch_setup_dma_ops(&ctx->pcidev->dev, 0, 0, NULL, true);
788 rc = iommu_domain_set_attr(ctx->mapping->domain,
789 DOMAIN_ATTR_PAGE_TABLE_FORCE_COHERENT,
790 &force_pt_coherent);
791 if (rc) {
792 dev_err(ctx->dev,
793 "Set SMMU PAGE_TABLE_FORCE_COHERENT attr failed (%d)\n",
794 rc);
795 goto release_mapping;
796 }
797 }
798
799 if (ctx->smmu_fast_map) {
800 rc = iommu_domain_set_attr(ctx->mapping->domain,
801 DOMAIN_ATTR_FAST,
802 &ctx->smmu_fast_map);
803 if (rc) {
804 dev_err(ctx->dev, "Set fast attribute to SMMU failed (%d)\n",
805 rc);
806 goto release_mapping;
807 }
Lior David639ebed2017-02-28 14:23:55 +0200808 }
809 }
810
811 rc = arm_iommu_attach_device(&ctx->pcidev->dev, ctx->mapping);
812 if (rc) {
813 dev_err(ctx->dev, "arm_iommu_attach_device failed (%d)\n", rc);
814 goto release_mapping;
815 }
816 dev_info(ctx->dev, "attached to IOMMU\n");
817
818 return 0;
819release_mapping:
820 arm_iommu_release_mapping(ctx->mapping);
821 ctx->mapping = NULL;
822 return rc;
823}
824
825static int msm_11ad_ssr_shutdown(const struct subsys_desc *subsys,
826 bool force_stop)
827{
828 pr_info("%s(%p,%d)\n", __func__, subsys, force_stop);
829 /* nothing is done in shutdown. We do full recovery in powerup */
830 return 0;
831}
832
833static int msm_11ad_ssr_powerup(const struct subsys_desc *subsys)
834{
835 int rc = 0;
836 struct platform_device *pdev;
837 struct msm11ad_ctx *ctx;
838
839 pr_info("%s(%p)\n", __func__, subsys);
840
841 pdev = to_platform_device(subsys->dev);
842 ctx = platform_get_drvdata(pdev);
843
844 if (!ctx)
845 return -ENODEV;
846
847 if (ctx->recovery_in_progress) {
848 if (ctx->rops.fw_recovery && ctx->wil_handle) {
849 dev_info(ctx->dev, "requesting FW recovery\n");
850 rc = ctx->rops.fw_recovery(ctx->wil_handle);
851 }
852 ctx->recovery_in_progress = false;
853 }
854
855 return rc;
856}
857
Lior David88865332017-03-30 17:22:57 +0300858static int msm_11ad_ssr_copy_ramdump(struct msm11ad_ctx *ctx)
859{
860 if (ctx->rops.ramdump && ctx->wil_handle) {
861 int rc = ctx->rops.ramdump(ctx->wil_handle, ctx->ramdump_addr,
862 WIGIG_RAMDUMP_SIZE);
863 if (rc) {
864 dev_err(ctx->dev, "ramdump failed : %d\n", rc);
865 return -EINVAL;
866 }
867 }
868
869 ctx->dump_data.version = WIGIG_DUMP_FORMAT_VER;
870 strlcpy(ctx->dump_data.name, WIGIG_SUBSYS_NAME,
871 sizeof(ctx->dump_data.name));
872
873 ctx->dump_data.magic = WIGIG_DUMP_MAGIC_VER_V1;
874 return 0;
875}
876
Lior David639ebed2017-02-28 14:23:55 +0200877static int msm_11ad_ssr_ramdump(int enable, const struct subsys_desc *subsys)
878{
879 int rc;
880 struct ramdump_segment segment;
881 struct platform_device *pdev;
882 struct msm11ad_ctx *ctx;
883
884 pdev = to_platform_device(subsys->dev);
885 ctx = platform_get_drvdata(pdev);
886
887 if (!ctx)
888 return -ENODEV;
889
890 if (!enable)
891 return 0;
892
Lior David88865332017-03-30 17:22:57 +0300893 if (!ctx->recovery_in_progress) {
894 rc = msm_11ad_ssr_copy_ramdump(ctx);
895 if (rc)
896 return rc;
Lior David639ebed2017-02-28 14:23:55 +0200897 }
898
899 memset(&segment, 0, sizeof(segment));
900 segment.v_address = ctx->ramdump_addr;
901 segment.size = WIGIG_RAMDUMP_SIZE;
902
903 return do_ramdump(ctx->ramdump_dev, &segment, 1);
904}
905
906static void msm_11ad_ssr_crash_shutdown(const struct subsys_desc *subsys)
907{
Lior David639ebed2017-02-28 14:23:55 +0200908 struct platform_device *pdev;
909 struct msm11ad_ctx *ctx;
910
911 pdev = to_platform_device(subsys->dev);
912 ctx = platform_get_drvdata(pdev);
913
914 if (!ctx) {
915 pr_err("%s: no context\n", __func__);
916 return;
917 }
918
Lior David88865332017-03-30 17:22:57 +0300919 if (!ctx->recovery_in_progress)
920 (void)msm_11ad_ssr_copy_ramdump(ctx);
Lior David639ebed2017-02-28 14:23:55 +0200921}
922
923static void msm_11ad_ssr_deinit(struct msm11ad_ctx *ctx)
924{
925 if (ctx->ramdump_dev) {
926 destroy_ramdump_device(ctx->ramdump_dev);
927 ctx->ramdump_dev = NULL;
928 }
929
930 kfree(ctx->ramdump_addr);
931 ctx->ramdump_addr = NULL;
932
933 if (ctx->subsys_handle) {
934 subsystem_put(ctx->subsys_handle);
935 ctx->subsys_handle = NULL;
936 }
937
938 if (ctx->subsys) {
939 subsys_unregister(ctx->subsys);
940 ctx->subsys = NULL;
941 }
942}
943
944static int msm_11ad_ssr_init(struct msm11ad_ctx *ctx)
945{
946 int rc;
947 struct msm_dump_entry dump_entry;
948
949 ctx->subsysdesc.name = "WIGIG";
950 ctx->subsysdesc.owner = THIS_MODULE;
951 ctx->subsysdesc.shutdown = msm_11ad_ssr_shutdown;
952 ctx->subsysdesc.powerup = msm_11ad_ssr_powerup;
953 ctx->subsysdesc.ramdump = msm_11ad_ssr_ramdump;
954 ctx->subsysdesc.crash_shutdown = msm_11ad_ssr_crash_shutdown;
955 ctx->subsysdesc.dev = ctx->dev;
956 ctx->subsys = subsys_register(&ctx->subsysdesc);
957 if (IS_ERR(ctx->subsys)) {
958 rc = PTR_ERR(ctx->subsys);
959 dev_err(ctx->dev, "subsys_register failed :%d\n", rc);
960 goto out_rc;
961 }
962
963 /* register ramdump area */
964 ctx->ramdump_addr = kmalloc(WIGIG_RAMDUMP_SIZE, GFP_KERNEL);
965 if (!ctx->ramdump_addr) {
966 rc = -ENOMEM;
967 goto out_rc;
968 }
969
970 ctx->dump_data.addr = virt_to_phys(ctx->ramdump_addr);
971 ctx->dump_data.len = WIGIG_RAMDUMP_SIZE;
972 dump_entry.id = MSM_DUMP_DATA_WIGIG;
973 dump_entry.addr = virt_to_phys(&ctx->dump_data);
974
975 rc = msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
976 if (rc) {
977 dev_err(ctx->dev, "Dump table setup failed: %d\n", rc);
978 goto out_rc;
979 }
980
981 ctx->ramdump_dev = create_ramdump_device(ctx->subsysdesc.name,
982 ctx->subsysdesc.dev);
983 if (!ctx->ramdump_dev) {
984 dev_err(ctx->dev, "Create ramdump device failed: %d\n", rc);
985 rc = -ENOMEM;
986 goto out_rc;
987 }
988
989 return 0;
990
991out_rc:
992 msm_11ad_ssr_deinit(ctx);
993 return rc;
994}
995
Lior Daviddb711962017-02-15 21:04:55 +0200996static void msm_11ad_init_cpu_boost(struct msm11ad_ctx *ctx)
997{
998 unsigned int minfreq = 0, maxfreq = 0, freq;
Hamad Kadmany6e03e622017-05-09 13:35:31 +0300999 int i, boost_cpu = 0;
Lior Daviddb711962017-02-15 21:04:55 +02001000
1001 for_each_possible_cpu(i) {
1002 freq = cpufreq_quick_get_max(i);
1003 if (freq > maxfreq) {
1004 maxfreq = freq;
1005 boost_cpu = i;
1006 }
1007 if (!minfreq || freq < minfreq)
1008 minfreq = freq;
1009 }
1010
1011 if (minfreq != maxfreq) {
1012 /*
1013 * use first big core for boost, to be compatible with WLAN
1014 * which assigns big cores from the last index
1015 */
1016 ctx->use_cpu_boost = true;
1017 cpumask_clear(&ctx->boost_cpu);
1018 cpumask_set_cpu(boost_cpu, &ctx->boost_cpu);
1019 dev_info(ctx->dev, "CPU boost: will use core %d\n", boost_cpu);
1020 } else {
1021 ctx->use_cpu_boost = false;
1022 dev_info(ctx->dev, "CPU boost disabled, uniform topology\n");
1023 }
1024}
1025
Lior David639ebed2017-02-28 14:23:55 +02001026static int msm_11ad_probe(struct platform_device *pdev)
1027{
1028 struct msm11ad_ctx *ctx;
1029 struct device *dev = &pdev->dev;
1030 struct device_node *of_node = dev->of_node;
1031 struct device_node *rc_node;
1032 struct pci_dev *pcidev = NULL;
Maya Erez34c251e2017-03-27 09:31:39 +03001033 u32 smmu_mapping[2];
Lior David639ebed2017-02-28 14:23:55 +02001034 int rc;
Maya Erez17ef6c32017-03-27 08:37:07 +03001035 u32 val;
Lior David639ebed2017-02-28 14:23:55 +02001036
1037 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
1038 if (!ctx)
1039 return -ENOMEM;
1040
1041 ctx->dev = dev;
1042
1043 /*== parse ==*/
1044
1045 /* Information pieces:
1046 * - of_node stands for "wil6210":
1047 * wil6210: qcom,wil6210 {
1048 * compatible = "qcom,wil6210";
1049 * qcom,pcie-parent = <&pcie1>;
1050 * qcom,wigig-en = <&tlmm 94 0>; (ctx->gpio_en)
1051 * qcom,sleep-clk-en = <&pm8994_gpios 18 0>; (ctx->sleep_clk_en)
1052 * qcom,msm-bus,name = "wil6210";
1053 * qcom,msm-bus,num-cases = <2>;
1054 * qcom,msm-bus,num-paths = <1>;
1055 * qcom,msm-bus,vectors-KBps =
1056 * <100 512 0 0>,
1057 * <100 512 600000 800000>;
1058 * qcom,smmu-support;
1059 *};
1060 * rc_node stands for "qcom,pcie", selected entries:
1061 * cell-index = <1>; (ctx->rc_index)
1062 * iommus = <&anoc0_smmu>;
1063 * qcom,smmu-exist;
1064 */
1065
1066 /* wigig-en is optional property */
1067 ctx->gpio_en = of_get_named_gpio(of_node, gpio_en_name, 0);
1068 if (ctx->gpio_en < 0)
1069 dev_warn(ctx->dev, "GPIO <%s> not found, enable GPIO not used\n",
1070 gpio_en_name);
1071 ctx->sleep_clk_en = of_get_named_gpio(of_node, sleep_clk_en_name, 0);
1072 if (ctx->sleep_clk_en < 0)
1073 dev_warn(ctx->dev, "GPIO <%s> not found, sleep clock not used\n",
1074 sleep_clk_en_name);
1075 rc_node = of_parse_phandle(of_node, "qcom,pcie-parent", 0);
1076 if (!rc_node) {
1077 dev_err(ctx->dev, "Parent PCIE device not found\n");
1078 return -EINVAL;
1079 }
1080 rc = of_property_read_u32(rc_node, "cell-index", &ctx->rc_index);
1081 if (rc < 0) {
1082 dev_err(ctx->dev, "Parent PCIE device index not found\n");
1083 return -EINVAL;
1084 }
1085 ctx->use_smmu = of_property_read_bool(of_node, "qcom,smmu-support");
Maya Erez692e94c2017-05-14 16:40:19 +03001086 ctx->keep_radio_on_during_sleep = of_property_read_bool(of_node,
Hamad Kadmany290544c2017-05-22 13:33:32 +03001087 "qcom,keep-radio-on-during-sleep");
Lior David639ebed2017-02-28 14:23:55 +02001088 ctx->bus_scale = msm_bus_cl_get_pdata(pdev);
Alexei Avshalom Lazar4b3303f2017-11-23 10:59:04 +02001089 if (!ctx->bus_scale) {
1090 dev_err(ctx->dev, "Unable to read bus-scaling from DT\n");
1091 return -EINVAL;
1092 }
Lior David639ebed2017-02-28 14:23:55 +02001093
Maya Erez34c251e2017-03-27 09:31:39 +03001094 ctx->smmu_s1_en = of_property_read_bool(of_node, "qcom,smmu-s1-en");
1095 if (ctx->smmu_s1_en) {
1096 ctx->smmu_fast_map = of_property_read_bool(
1097 of_node, "qcom,smmu-fast-map");
1098 ctx->smmu_coherent = of_property_read_bool(
1099 of_node, "qcom,smmu-coherent");
1100 }
1101 rc = of_property_read_u32_array(dev->of_node, "qcom,smmu-mapping",
1102 smmu_mapping, 2);
1103 if (rc) {
1104 dev_err(ctx->dev,
1105 "Failed to read base/size smmu addresses %d, fallback to default\n",
1106 rc);
1107 ctx->smmu_base = SMMU_BASE;
1108 ctx->smmu_size = SMMU_SIZE;
1109 } else {
1110 ctx->smmu_base = smmu_mapping[0];
1111 ctx->smmu_size = smmu_mapping[1];
1112 }
1113 dev_dbg(ctx->dev, "smmu_base=0x%x smmu_sise=0x%x\n",
1114 ctx->smmu_base, ctx->smmu_size);
Lior David639ebed2017-02-28 14:23:55 +02001115
1116 /*== execute ==*/
1117 /* turn device on */
1118 rc = msm_11ad_init_vregs(ctx);
1119 if (rc) {
1120 dev_err(ctx->dev, "msm_11ad_init_vregs failed: %d\n", rc);
Alexei Avshalom Lazar4b3303f2017-11-23 10:59:04 +02001121 goto out_bus_scale;
Lior David639ebed2017-02-28 14:23:55 +02001122 }
1123 rc = msm_11ad_enable_vregs(ctx);
1124 if (rc) {
1125 dev_err(ctx->dev, "msm_11ad_enable_vregs failed: %d\n", rc);
1126 goto out_vreg_clk;
1127 }
1128
1129 rc = msm_11ad_init_clocks(ctx);
1130 if (rc) {
1131 dev_err(ctx->dev, "msm_11ad_init_clocks failed: %d\n", rc);
1132 goto out_vreg_clk;
1133 }
1134
1135 rc = msm_11ad_enable_clocks(ctx);
1136 if (rc) {
1137 dev_err(ctx->dev, "msm_11ad_enable_clocks failed: %d\n", rc);
1138 goto out_vreg_clk;
1139 }
1140
1141 if (ctx->gpio_en >= 0) {
1142 rc = gpio_request(ctx->gpio_en, gpio_en_name);
1143 if (rc < 0) {
1144 dev_err(ctx->dev, "failed to request GPIO %d <%s>\n",
1145 ctx->gpio_en, gpio_en_name);
1146 goto out_req;
1147 }
1148 rc = gpio_direction_output(ctx->gpio_en, 1);
1149 if (rc < 0) {
1150 dev_err(ctx->dev, "failed to set GPIO %d <%s>\n",
1151 ctx->gpio_en, gpio_en_name);
1152 goto out_set;
1153 }
1154 msleep(WIGIG_ENABLE_DELAY);
1155 }
1156
1157 /* enumerate it on PCIE */
1158 rc = msm_pcie_enumerate(ctx->rc_index);
1159 if (rc < 0) {
1160 dev_err(ctx->dev, "Parent PCIE enumeration failed\n");
1161 goto out_rc;
1162 }
1163 /* search for PCIE device in our domain */
1164 do {
1165 pcidev = pci_get_device(WIGIG_VENDOR, WIGIG_DEVICE, pcidev);
1166 if (!pcidev)
1167 break;
1168
1169 if (pci_domain_nr(pcidev->bus) == ctx->rc_index)
1170 break;
1171 } while (true);
1172 if (!pcidev) {
1173 rc = -ENODEV;
1174 dev_err(ctx->dev, "Wigig device %4x:%4x not found\n",
1175 WIGIG_VENDOR, WIGIG_DEVICE);
1176 goto out_rc;
1177 }
1178 ctx->pcidev = pcidev;
Maya Erez17ef6c32017-03-27 08:37:07 +03001179
Alexei Avshalom Lazar4b3303f2017-11-23 10:59:04 +02001180 rc = msm_pcie_pm_control(MSM_PCIE_RESUME, pcidev->bus->number,
1181 pcidev, NULL, 0);
1182 if (rc) {
1183 dev_err(ctx->dev, "msm_pcie_pm_control(RESUME) failed:%d\n",
1184 rc);
1185 goto out_rc;
1186 }
1187
1188 pci_set_power_state(pcidev, PCI_D0);
1189
1190 pci_restore_state(ctx->pcidev);
1191
Maya Erez3ef3e362017-03-27 08:47:02 +03001192 /* Read current state */
1193 rc = pci_read_config_dword(pcidev,
Maya Erez17ef6c32017-03-27 08:37:07 +03001194 PCIE20_CAP_LINKCTRLSTATUS, &val);
1195 if (rc) {
1196 dev_err(ctx->dev,
1197 "reading PCIE20_CAP_LINKCTRLSTATUS failed:%d\n",
1198 rc);
Alexei Avshalom Lazar4b3303f2017-11-23 10:59:04 +02001199 goto out_suspend;
Maya Erez17ef6c32017-03-27 08:37:07 +03001200 }
Maya Erez3ef3e362017-03-27 08:47:02 +03001201
1202 ctx->l1_enabled_in_enum = val & PCI_EXP_LNKCTL_ASPM_L1;
1203 dev_dbg(ctx->dev, "L1 is %s in enumeration\n",
1204 ctx->l1_enabled_in_enum ? "enabled" : "disabled");
1205
1206 /* Disable L1, in case it is enabled */
1207 if (ctx->l1_enabled_in_enum) {
1208 rc = msm_11ad_ctrl_aspm_l1(ctx, false);
1209 if (rc) {
1210 dev_err(ctx->dev,
1211 "failed to disable L1, rc %d\n", rc);
Alexei Avshalom Lazar4b3303f2017-11-23 10:59:04 +02001212 goto out_suspend;
Maya Erez3ef3e362017-03-27 08:47:02 +03001213 }
Maya Erez17ef6c32017-03-27 08:37:07 +03001214 }
1215
Lior David639ebed2017-02-28 14:23:55 +02001216 if (ctx->sleep_clk_en >= 0) {
1217 rc = gpio_request(ctx->sleep_clk_en, "msm_11ad");
1218 if (rc < 0) {
1219 dev_err(ctx->dev,
1220 "failed to request GPIO %d <%s>, sleep clock disabled\n",
1221 ctx->sleep_clk_en, sleep_clk_en_name);
1222 ctx->sleep_clk_en = -EINVAL;
1223 } else {
1224 gpio_direction_output(ctx->sleep_clk_en, 0);
1225 }
1226 }
1227
1228 /* register for subsystem restart */
1229 rc = msm_11ad_ssr_init(ctx);
1230 if (rc) {
1231 dev_err(ctx->dev, "msm_11ad_ssr_init failed: %d\n", rc);
Alexei Avshalom Lazar4b3303f2017-11-23 10:59:04 +02001232 goto out_suspend;
Lior David639ebed2017-02-28 14:23:55 +02001233 }
1234
Lior Daviddb711962017-02-15 21:04:55 +02001235 msm_11ad_init_cpu_boost(ctx);
1236
Lior David639ebed2017-02-28 14:23:55 +02001237 /* report */
1238 dev_info(ctx->dev, "msm_11ad discovered. %p {\n"
1239 " gpio_en = %d\n"
1240 " sleep_clk_en = %d\n"
1241 " rc_index = %d\n"
1242 " use_smmu = %d\n"
1243 " pcidev = %p\n"
1244 "}\n", ctx, ctx->gpio_en, ctx->sleep_clk_en, ctx->rc_index,
1245 ctx->use_smmu, ctx->pcidev);
1246
1247 platform_set_drvdata(pdev, ctx);
1248 device_disable_async_suspend(&pcidev->dev);
1249
1250 list_add_tail(&ctx->list, &dev_list);
Maya Erez692e94c2017-05-14 16:40:19 +03001251 msm_11ad_suspend_power_off(ctx);
Lior David639ebed2017-02-28 14:23:55 +02001252
1253 return 0;
Alexei Avshalom Lazar4b3303f2017-11-23 10:59:04 +02001254out_suspend:
1255 msm_pcie_pm_control(MSM_PCIE_SUSPEND, pcidev->bus->number,
1256 pcidev, NULL, 0);
Lior David639ebed2017-02-28 14:23:55 +02001257out_rc:
1258 if (ctx->gpio_en >= 0)
1259 gpio_direction_output(ctx->gpio_en, 0);
1260out_set:
1261 if (ctx->gpio_en >= 0)
1262 gpio_free(ctx->gpio_en);
1263out_req:
1264 ctx->gpio_en = -EINVAL;
1265out_vreg_clk:
1266 msm_11ad_disable_clocks(ctx);
1267 msm_11ad_release_clocks(ctx);
1268 msm_11ad_disable_vregs(ctx);
1269 msm_11ad_release_vregs(ctx);
Alexei Avshalom Lazar4b3303f2017-11-23 10:59:04 +02001270out_bus_scale:
1271 msm_bus_cl_clear_pdata(ctx->bus_scale);
Lior David639ebed2017-02-28 14:23:55 +02001272
1273 return rc;
1274}
1275
1276static int msm_11ad_remove(struct platform_device *pdev)
1277{
1278 struct msm11ad_ctx *ctx = platform_get_drvdata(pdev);
1279
1280 msm_11ad_ssr_deinit(ctx);
1281 list_del(&ctx->list);
1282 dev_info(ctx->dev, "%s: pdev %p pcidev %p\n", __func__, pdev,
1283 ctx->pcidev);
1284 kfree(ctx->pristine_state);
1285
Lior David639ebed2017-02-28 14:23:55 +02001286 pci_dev_put(ctx->pcidev);
1287 if (ctx->gpio_en >= 0) {
1288 gpio_direction_output(ctx->gpio_en, 0);
1289 gpio_free(ctx->gpio_en);
1290 }
1291 if (ctx->sleep_clk_en >= 0)
1292 gpio_free(ctx->sleep_clk_en);
1293
1294 msm_11ad_disable_clocks(ctx);
1295 msm_11ad_release_clocks(ctx);
1296 msm_11ad_disable_vregs(ctx);
1297 msm_11ad_release_vregs(ctx);
1298
1299 return 0;
1300}
1301
1302static const struct of_device_id msm_11ad_of_match[] = {
1303 { .compatible = "qcom,wil6210", },
1304 {},
1305};
1306
1307static struct platform_driver msm_11ad_driver = {
1308 .driver = {
1309 .name = "msm_11ad",
1310 .of_match_table = msm_11ad_of_match,
1311 },
1312 .probe = msm_11ad_probe,
1313 .remove = msm_11ad_remove,
1314};
1315module_platform_driver(msm_11ad_driver);
1316
Lior Daviddb711962017-02-15 21:04:55 +02001317static void msm_11ad_set_boost_affinity(struct msm11ad_ctx *ctx)
1318{
1319 /*
1320 * There is a very small window where user space can change the
1321 * affinity after we changed it here and before setting the
1322 * NO_BALANCING flag. Retry this several times as a workaround.
1323 */
1324 int retries = 5, rc;
1325 struct irq_desc *desc;
1326
1327 while (retries > 0) {
1328 irq_modify_status(ctx->pcidev->irq, IRQ_NO_BALANCING, 0);
1329 rc = irq_set_affinity_hint(ctx->pcidev->irq, &ctx->boost_cpu);
1330 if (rc)
1331 dev_warn(ctx->dev,
1332 "Failed set affinity, rc=%d\n", rc);
1333 irq_modify_status(ctx->pcidev->irq, 0, IRQ_NO_BALANCING);
1334 desc = irq_to_desc(ctx->pcidev->irq);
1335 if (cpumask_equal(desc->irq_common_data.affinity,
1336 &ctx->boost_cpu))
1337 break;
1338 retries--;
1339 }
1340
1341 if (!retries)
1342 dev_warn(ctx->dev, "failed to set CPU boost affinity\n");
1343}
1344
Dedy Lanskyf91b9152017-05-16 15:18:02 +03001345static void msm_11ad_clear_boost_affinity(struct msm11ad_ctx *ctx)
1346{
1347 int rc;
1348
1349 irq_modify_status(ctx->pcidev->irq, IRQ_NO_BALANCING, 0);
1350 rc = irq_set_affinity_hint(ctx->pcidev->irq, NULL);
1351 if (rc)
1352 dev_warn(ctx->dev,
1353 "Failed clear affinity, rc=%d\n", rc);
1354}
1355
Lior David639ebed2017-02-28 14:23:55 +02001356/* hooks for the wil6210 driver */
1357static int ops_bus_request(void *handle, u32 kbps /* KBytes/Sec */)
1358{
1359 struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
1360 int rc, i;
1361 int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
1362 struct msm_bus_paths *usecase;
1363 u32 usecase_kbps;
1364 u32 min_kbps = ~0;
1365
1366 /* find the lowest usecase that is bigger than requested kbps */
1367 for (i = 0; i < ctx->bus_scale->num_usecases; i++) {
1368 usecase = &ctx->bus_scale->usecase[i];
1369 /*
1370 * assume we have single path (vectors[0]). If we ever
1371 * have multiple paths, need to define the behavior
1372 */
1373 usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
1374 if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
1375 min_kbps = usecase_kbps;
1376 vote = i;
1377 }
1378 }
1379
1380 rc = msm_bus_scale_client_update_request(ctx->msm_bus_handle, vote);
1381 if (rc)
1382 dev_err(ctx->dev,
1383 "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
1384 kbps, vote, rc);
1385
Lior Daviddb711962017-02-15 21:04:55 +02001386 if (ctx->use_cpu_boost) {
1387 bool was_boosted = ctx->is_cpu_boosted;
1388 bool needs_boost = (kbps >= WIGIG_MIN_CPU_BOOST_KBPS);
1389
1390 if (was_boosted != needs_boost) {
1391 if (needs_boost) {
1392 rc = core_ctl_set_boost(true);
1393 if (rc) {
1394 dev_err(ctx->dev,
1395 "Failed enable boost rc=%d\n",
1396 rc);
1397 goto out;
1398 }
1399 msm_11ad_set_boost_affinity(ctx);
1400 dev_dbg(ctx->dev, "CPU boost enabled\n");
1401 } else {
1402 rc = core_ctl_set_boost(false);
1403 if (rc)
1404 dev_err(ctx->dev,
1405 "Failed disable boost rc=%d\n",
1406 rc);
Dedy Lanskyf91b9152017-05-16 15:18:02 +03001407 msm_11ad_clear_boost_affinity(ctx);
Lior Daviddb711962017-02-15 21:04:55 +02001408 dev_dbg(ctx->dev, "CPU boost disabled\n");
1409 }
1410 ctx->is_cpu_boosted = needs_boost;
1411 }
1412 }
1413out:
Lior David639ebed2017-02-28 14:23:55 +02001414 return rc;
1415}
1416
1417static void ops_uninit(void *handle)
1418{
1419 struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
1420
1421 if (ctx->msm_bus_handle) {
1422 msm_bus_scale_unregister_client(ctx->msm_bus_handle);
1423 ctx->msm_bus_handle = 0;
1424 }
1425
1426 if (ctx->use_smmu) {
1427 arm_iommu_detach_device(&ctx->pcidev->dev);
1428 arm_iommu_release_mapping(ctx->mapping);
1429 ctx->mapping = NULL;
1430 }
1431
1432 memset(&ctx->rops, 0, sizeof(ctx->rops));
1433 ctx->wil_handle = NULL;
1434
Maya Erez692e94c2017-05-14 16:40:19 +03001435 msm_11ad_suspend_power_off(ctx);
Lior David639ebed2017-02-28 14:23:55 +02001436}
1437
1438static int msm_11ad_notify_crash(struct msm11ad_ctx *ctx)
1439{
1440 int rc;
1441
1442 if (ctx->subsys) {
1443 dev_info(ctx->dev, "SSR requested\n");
Lior David88865332017-03-30 17:22:57 +03001444 (void)msm_11ad_ssr_copy_ramdump(ctx);
Lior David639ebed2017-02-28 14:23:55 +02001445 ctx->recovery_in_progress = true;
Alexei Avshalom Lazar5f439732017-11-15 10:55:49 +02001446 subsys_set_crash_status(ctx->subsys, CRASH_STATUS_ERR_FATAL);
Lior David639ebed2017-02-28 14:23:55 +02001447 rc = subsystem_restart_dev(ctx->subsys);
1448 if (rc) {
1449 dev_err(ctx->dev,
1450 "subsystem_restart_dev fail: %d\n", rc);
1451 ctx->recovery_in_progress = false;
1452 }
1453 }
1454
1455 return 0;
1456}
1457
1458static int ops_notify(void *handle, enum wil_platform_event evt)
1459{
1460 struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
1461 int rc = 0;
1462
1463 switch (evt) {
1464 case WIL_PLATFORM_EVT_FW_CRASH:
1465 rc = msm_11ad_notify_crash(ctx);
1466 break;
1467 case WIL_PLATFORM_EVT_PRE_RESET:
1468 /*
Maya Erez308f9fe2017-11-08 21:35:31 +02001469 * Enable rf_clk3 clock before resetting the device to ensure
1470 * stable ref clock during the device reset
Lior David639ebed2017-02-28 14:23:55 +02001471 */
Maya Erez308f9fe2017-11-08 21:35:31 +02001472 if (ctx->features &
1473 BIT(WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL)) {
1474 rc = msm_11ad_enable_clk(ctx, &ctx->rf_clk3);
1475 if (rc) {
1476 dev_err(ctx->dev,
1477 "failed to enable clk, rc %d\n", rc);
1478 break;
1479 }
1480 }
1481
Maya Erez3ef3e362017-03-27 08:47:02 +03001482 /* Re-enable L1 in case it was enabled in enumeration */
1483 if (ctx->l1_enabled_in_enum) {
1484 rc = msm_11ad_ctrl_aspm_l1(ctx, true);
1485 if (rc)
1486 dev_err(ctx->dev,
1487 "failed to enable L1, rc %d\n", rc);
1488 }
Lior David639ebed2017-02-28 14:23:55 +02001489 break;
1490 case WIL_PLATFORM_EVT_FW_RDY:
1491 /*
Maya Erez308f9fe2017-11-08 21:35:31 +02001492 * Disable rf_clk3 clock after the device is up to allow
Lior David639ebed2017-02-28 14:23:55 +02001493 * the device to control it via its GPIO for power saving
1494 */
Maya Erez308f9fe2017-11-08 21:35:31 +02001495 if (ctx->features &
1496 BIT(WIL_PLATFORM_FEATURE_FW_EXT_CLK_CONTROL))
1497 msm_11ad_disable_clk(ctx, &ctx->rf_clk3);
Lior David639ebed2017-02-28 14:23:55 +02001498 break;
1499 default:
1500 pr_debug("%s: Unhandled event %d\n", __func__, evt);
1501 break;
1502 }
1503
1504 return rc;
1505}
1506
Maya Ereza3a52882017-10-22 11:12:59 +03001507static int ops_get_capa(void *handle)
Maya Erez692e94c2017-05-14 16:40:19 +03001508{
1509 struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
Maya Ereza3a52882017-10-22 11:12:59 +03001510 int capa;
Maya Erez692e94c2017-05-14 16:40:19 +03001511
1512 pr_debug("%s: keep radio on during sleep is %s\n", __func__,
1513 ctx->keep_radio_on_during_sleep ? "allowed" : "not allowed");
1514
Maya Ereza3a52882017-10-22 11:12:59 +03001515 capa = (ctx->keep_radio_on_during_sleep ?
1516 BIT(WIL_PLATFORM_CAPA_RADIO_ON_IN_SUSPEND) : 0) |
1517 BIT(WIL_PLATFORM_CAPA_T_PWR_ON_0) |
1518 BIT(WIL_PLATFORM_CAPA_EXT_CLK);
1519
1520 return capa;
Maya Erez692e94c2017-05-14 16:40:19 +03001521}
1522
Maya Erez308f9fe2017-11-08 21:35:31 +02001523static void ops_set_features(void *handle, int features)
1524{
1525 struct msm11ad_ctx *ctx = (struct msm11ad_ctx *)handle;
1526
1527 pr_debug("%s: features 0x%x\n", __func__, features);
1528 ctx->features = features;
1529}
1530
Lior David639ebed2017-02-28 14:23:55 +02001531void *msm_11ad_dev_init(struct device *dev, struct wil_platform_ops *ops,
1532 const struct wil_platform_rops *rops, void *wil_handle)
1533{
1534 struct pci_dev *pcidev = to_pci_dev(dev);
1535 struct msm11ad_ctx *ctx = pcidev2ctx(pcidev);
1536
1537 if (!ctx) {
1538 pr_err("Context not found for pcidev %p\n", pcidev);
1539 return NULL;
1540 }
1541
1542 /* bus scale */
1543 ctx->msm_bus_handle =
1544 msm_bus_scale_register_client(ctx->bus_scale);
1545 if (!ctx->msm_bus_handle) {
1546 dev_err(ctx->dev, "Failed msm_bus registration\n");
1547 return NULL;
1548 }
1549 dev_info(ctx->dev, "msm_bus handle 0x%x\n", ctx->msm_bus_handle);
1550 /* smmu */
1551 if (msm_11ad_smmu_init(ctx)) {
1552 msm_bus_scale_unregister_client(ctx->msm_bus_handle);
1553 ctx->msm_bus_handle = 0;
1554 return NULL;
1555 }
1556
1557 /* subsystem restart */
1558 if (rops) {
1559 ctx->rops = *rops;
1560 ctx->wil_handle = wil_handle;
1561 }
1562
1563 /* fill ops */
1564 memset(ops, 0, sizeof(*ops));
1565 ops->bus_request = ops_bus_request;
1566 ops->suspend = ops_suspend;
1567 ops->resume = ops_resume;
1568 ops->uninit = ops_uninit;
1569 ops->notify = ops_notify;
Maya Ereza3a52882017-10-22 11:12:59 +03001570 ops->get_capa = ops_get_capa;
Maya Erez308f9fe2017-11-08 21:35:31 +02001571 ops->set_features = ops_set_features;
Lior David639ebed2017-02-28 14:23:55 +02001572
1573 return ctx;
1574}
1575EXPORT_SYMBOL(msm_11ad_dev_init);
1576
1577int msm_11ad_modinit(void)
1578{
1579 struct msm11ad_ctx *ctx = list_first_entry_or_null(&dev_list,
1580 struct msm11ad_ctx,
1581 list);
1582
1583 if (!ctx) {
1584 pr_err("Context not found\n");
1585 return -EINVAL;
1586 }
1587
Lior David639ebed2017-02-28 14:23:55 +02001588 ctx->subsys_handle = subsystem_get(ctx->subsysdesc.name);
1589
Maya Erez692e94c2017-05-14 16:40:19 +03001590 return msm_11ad_resume_power_on(ctx);
Lior David639ebed2017-02-28 14:23:55 +02001591}
1592EXPORT_SYMBOL(msm_11ad_modinit);
1593
1594void msm_11ad_modexit(void)
1595{
1596 struct msm11ad_ctx *ctx = list_first_entry_or_null(&dev_list,
1597 struct msm11ad_ctx,
1598 list);
1599
1600 if (!ctx) {
1601 pr_err("Context not found\n");
1602 return;
1603 }
1604
1605 if (ctx->subsys_handle) {
1606 subsystem_put(ctx->subsys_handle);
1607 ctx->subsys_handle = NULL;
1608 }
1609}
1610EXPORT_SYMBOL(msm_11ad_modexit);
1611
1612MODULE_LICENSE("GPL v2");
1613MODULE_DESCRIPTION("Platform driver for Qualcomm Technologies, Inc. 11ad card");
1614