blob: ed3df007f2e405bffe65d8e5e2107dc2a4e05055 [file] [log] [blame]
David Collins7370f1a2017-01-18 16:21:53 -08001/*
2 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/arm-smccc.h>
17#include <linux/debugfs.h>
18#include <linux/delay.h>
19#include <linux/of_device.h>
20#include <linux/init.h>
21#include <linux/io.h>
22#include <linux/kernel.h>
23#include <linux/list.h>
24#include <linux/module.h>
25#include <linux/of.h>
26#include <linux/platform_device.h>
27#include <linux/slab.h>
28#include <linux/string.h>
29#include <linux/power/qcom/apm.h>
30#include <soc/qcom/scm.h>
31
32/*
33 * VDD_APCC
34 * =============================================================
35 * | VDD_MX | |
36 * | ==========================|============= |
37 * ___|___ ___|___ ___|___ ___|___ ___|___ ___|___
38 * | | | | | | | | | | | |
39 * | APCC | | MX HS | | MX HS | | APCC | | MX HS | | APCC |
40 * | HS | | | | | | HS | | | | HS |
41 * |_______| |_______| |_______| |_______| |_______| |_______|
42 * |_________| |_________| |__________|
43 * | | |
44 * ______|_____ ______|_____ _______|_____
45 * | | | | | |
46 * | | | | | |
47 * | CPU MEM | | L2 MEM | | L3 MEM |
48 * | Arrays | | Arrays | | Arrays |
49 * | | | | | |
50 * |____________| |____________| |_____________|
51 *
52 */
53
54/* Register value definitions */
55#define APCS_GFMUXA_SEL_VAL 0x13
56#define APCS_GFMUXA_DESEL_VAL 0x03
57#define MSM_APM_MX_MODE_VAL 0x00
58#define MSM_APM_APCC_MODE_VAL 0x10
59#define MSM_APM_MX_DONE_VAL 0x00
60#define MSM_APM_APCC_DONE_VAL 0x03
61#define MSM_APM_OVERRIDE_SEL_VAL 0xb0
62#define MSM_APM_SEC_CLK_SEL_VAL 0x30
63#define SPM_EVENT_SET_VAL 0x01
64#define SPM_EVENT_CLEAR_VAL 0x00
65
66/* Register bit mask definitions */
67#define MSM_APM_CTL_STS_MASK 0x0f
68
69/* Register offset definitions */
70#define APCC_APM_MODE 0x00000098
71#define APCC_APM_CTL_STS 0x000000a8
72#define APCS_SPARE 0x00000068
73#define APCS_VERSION 0x00000fd0
74
75#define HMSS_VERSION_1P2 0x10020000
76
77#define MSM_APM_SWITCH_TIMEOUT_US 10
78#define SPM_WAKEUP_DELAY_US 2
79#define SPM_EVENT_NUM 6
80
81#define MSM_APM_DRIVER_NAME "qcom,msm-apm"
82
83enum {
84 CLOCK_ASSERT_ENABLE,
85 CLOCK_ASSERT_DISABLE,
86 CLOCK_ASSERT_TOGGLE,
87};
88
89enum {
90 MSM8996_ID,
91 MSM8996PRO_ID,
92 MSM8953_ID,
93};
94
95struct msm_apm_ctrl_dev {
96 struct list_head list;
97 struct device *dev;
98 enum msm_apm_supply supply;
99 spinlock_t lock;
100 void __iomem *reg_base;
101 void __iomem *apcs_csr_base;
102 void __iomem **apcs_spm_events_addr;
103 void __iomem *apc0_pll_ctl_addr;
104 void __iomem *apc1_pll_ctl_addr;
105 bool clk_src_override;
106 u32 version;
107 struct dentry *debugfs;
108 u32 msm_id;
109};
110
111#if defined(CONFIG_DEBUG_FS)
112static struct dentry *apm_debugfs_base;
113#endif
114
115static DEFINE_MUTEX(apm_ctrl_list_mutex);
116static LIST_HEAD(apm_ctrl_list);
117
118static unsigned long __invoke_psci_fn_smc(unsigned long a, unsigned long b,
119 unsigned long c, unsigned long d)
120{
121 struct arm_smccc_res res;
122
123 arm_smccc_smc(a, b, c, d, 0, 0, 0, 0, &res);
124
125 return res.a0;
126}
127
128/*
129 * Get the resources associated with the APM controller from device tree
130 * and remap all I/O addresses that are relevant to this HW revision.
131 */
132static int msm_apm_ctrl_devm_ioremap(struct platform_device *pdev,
133 struct msm_apm_ctrl_dev *ctrl)
134{
135 struct device *dev = &pdev->dev;
136 struct resource *res;
137 static const char *res_name[SPM_EVENT_NUM] = {
138 "apc0-l2-spm",
139 "apc1-l2-spm",
140 "apc0-cpu0-spm",
141 "apc0-cpu1-spm",
142 "apc1-cpu0-spm",
143 "apc1-cpu1-spm"
144 };
145 int i, ret = 0;
146
147 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pm-apcc-glb");
148 if (!res) {
149 dev_err(dev, "Missing PM APCC Global register physical address");
150 return -EINVAL;
151 }
152 ctrl->reg_base = devm_ioremap(dev, res->start, resource_size(res));
153 if (!ctrl->reg_base) {
154 dev_err(dev, "Failed to map PM APCC Global registers\n");
155 return -ENOMEM;
156 }
157
158 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apcs-csr");
159 if (!res) {
160 dev_err(dev, "Missing APCS CSR physical base address");
161 return -EINVAL;
162 }
163 ctrl->apcs_csr_base = devm_ioremap(dev, res->start, resource_size(res));
164 if (!ctrl->apcs_csr_base) {
165 dev_err(dev, "Failed to map APCS CSR registers\n");
166 return -ENOMEM;
167 }
168
169 ctrl->clk_src_override = of_property_read_bool(dev->of_node,
170 "qcom,clock-source-override");
171
172 if (ctrl->clk_src_override)
173 dev_info(dev, "overriding clock sources across APM switch\n");
174
175 ctrl->version = readl_relaxed(ctrl->apcs_csr_base + APCS_VERSION);
176
177 if (ctrl->version >= HMSS_VERSION_1P2)
178 return ret;
179
180 ctrl->apcs_spm_events_addr = devm_kzalloc(&pdev->dev,
181 SPM_EVENT_NUM
182 * sizeof(void __iomem *),
183 GFP_KERNEL);
184 if (!ctrl->apcs_spm_events_addr) {
185 dev_err(dev, "Failed to allocate memory for APCS SPM event registers\n");
186 return -ENOMEM;
187 }
188
189 for (i = 0; i < SPM_EVENT_NUM; i++) {
190 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
191 res_name[i]);
192 if (!res) {
193 dev_err(dev, "Missing address for %s\n", res_name[i]);
194 ret = -EINVAL;
195 goto free_events;
196 }
197
198 ctrl->apcs_spm_events_addr[i] = devm_ioremap(dev, res->start,
199 resource_size(res));
200 if (!ctrl->apcs_spm_events_addr[i]) {
201 dev_err(dev, "Failed to map %s\n", res_name[i]);
202 ret = -ENOMEM;
203 goto free_events;
204 }
205
206 dev_dbg(dev, "%s event phys: %pa virt:0x%p\n", res_name[i],
207 &res->start, ctrl->apcs_spm_events_addr[i]);
208 }
209
210 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
211 "apc0-pll-ctl");
212 if (!res) {
213 dev_err(dev, "Missing APC0 PLL CTL physical address\n");
214 ret = -EINVAL;
215 goto free_events;
216 }
217
218 ctrl->apc0_pll_ctl_addr = devm_ioremap(dev,
219 res->start,
220 resource_size(res));
221 if (!ctrl->apc0_pll_ctl_addr) {
222 dev_err(dev, "Failed to map APC0 PLL CTL register\n");
223 ret = -ENOMEM;
224 goto free_events;
225 }
226
227 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
228 "apc1-pll-ctl");
229 if (!res) {
230 dev_err(dev, "Missing APC1 PLL CTL physical address\n");
231 ret = -EINVAL;
232 goto free_events;
233 }
234
235 ctrl->apc1_pll_ctl_addr = devm_ioremap(dev,
236 res->start,
237 resource_size(res));
238 if (!ctrl->apc1_pll_ctl_addr) {
239 dev_err(dev, "Failed to map APC1 PLL CTL register\n");
240 ret = -ENOMEM;
241 goto free_events;
242 }
243
244 return ret;
245
246free_events:
247 devm_kfree(dev, ctrl->apcs_spm_events_addr);
248 return ret;
249}
250
251/* MSM8953 register offset definition */
252#define MSM8953_APM_DLY_CNTR 0x2ac
253
254/* Register field shift definitions */
255#define APM_CTL_SEL_SWITCH_DLY_SHIFT 0
256#define APM_CTL_RESUME_CLK_DLY_SHIFT 8
257#define APM_CTL_HALT_CLK_DLY_SHIFT 16
258#define APM_CTL_POST_HALT_DLY_SHIFT 24
259
260/* Register field mask definitions */
261#define APM_CTL_SEL_SWITCH_DLY_MASK GENMASK(7, 0)
262#define APM_CTL_RESUME_CLK_DLY_MASK GENMASK(15, 8)
263#define APM_CTL_HALT_CLK_DLY_MASK GENMASK(23, 16)
264#define APM_CTL_POST_HALT_DLY_MASK GENMASK(31, 24)
265
266/*
267 * Get the resources associated with the MSM8953 APM controller from
268 * device tree, remap all I/O addresses, and program the initial
269 * register configuration required for the MSM8953 APM controller device.
270 */
271static int msm8953_apm_ctrl_init(struct platform_device *pdev,
272 struct msm_apm_ctrl_dev *ctrl)
273{
274 struct device *dev = &pdev->dev;
275 struct resource *res;
276 u32 delay_counter, val = 0, regval = 0;
277 int rc = 0;
278
279 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pm-apcc-glb");
280 if (!res) {
281 dev_err(dev, "Missing PM APCC Global register physical address\n");
282 return -ENODEV;
283 }
284 ctrl->reg_base = devm_ioremap(dev, res->start, resource_size(res));
285 if (!ctrl->reg_base) {
286 dev_err(dev, "Failed to map PM APCC Global registers\n");
287 return -ENOMEM;
288 }
289
290 /*
291 * Initial APM register configuration required before starting
292 * APM HW controller.
293 */
294 regval = readl_relaxed(ctrl->reg_base + MSM8953_APM_DLY_CNTR);
295 val = regval;
296
297 if (of_find_property(dev->of_node, "qcom,apm-post-halt-delay", NULL)) {
298 rc = of_property_read_u32(dev->of_node,
299 "qcom,apm-post-halt-delay", &delay_counter);
300 if (rc < 0) {
301 dev_err(dev, "apm-post-halt-delay read failed, rc = %d",
302 rc);
303 return rc;
304 }
305
306 val &= ~APM_CTL_POST_HALT_DLY_MASK;
307 val |= (delay_counter << APM_CTL_POST_HALT_DLY_SHIFT)
308 & APM_CTL_POST_HALT_DLY_MASK;
309 }
310
311 if (of_find_property(dev->of_node, "qcom,apm-halt-clk-delay", NULL)) {
312 rc = of_property_read_u32(dev->of_node,
313 "qcom,apm-halt-clk-delay", &delay_counter);
314 if (rc < 0) {
315 dev_err(dev, "apm-halt-clk-delay read failed, rc = %d",
316 rc);
317 return rc;
318 }
319
320 val &= ~APM_CTL_HALT_CLK_DLY_MASK;
321 val |= (delay_counter << APM_CTL_HALT_CLK_DLY_SHIFT)
322 & APM_CTL_HALT_CLK_DLY_MASK;
323 }
324
325 if (of_find_property(dev->of_node, "qcom,apm-resume-clk-delay", NULL)) {
326 rc = of_property_read_u32(dev->of_node,
327 "qcom,apm-resume-clk-delay", &delay_counter);
328 if (rc < 0) {
329 dev_err(dev, "apm-resume-clk-delay read failed, rc = %d",
330 rc);
331 return rc;
332 }
333
334 val &= ~APM_CTL_RESUME_CLK_DLY_MASK;
335 val |= (delay_counter << APM_CTL_RESUME_CLK_DLY_SHIFT)
336 & APM_CTL_RESUME_CLK_DLY_MASK;
337 }
338
339 if (of_find_property(dev->of_node, "qcom,apm-sel-switch-delay", NULL)) {
340 rc = of_property_read_u32(dev->of_node,
341 "qcom,apm-sel-switch-delay", &delay_counter);
342 if (rc < 0) {
343 dev_err(dev, "apm-sel-switch-delay read failed, rc = %d",
344 rc);
345 return rc;
346 }
347
348 val &= ~APM_CTL_SEL_SWITCH_DLY_MASK;
349 val |= (delay_counter << APM_CTL_SEL_SWITCH_DLY_SHIFT)
350 & APM_CTL_SEL_SWITCH_DLY_MASK;
351 }
352
353 if (val != regval) {
354 writel_relaxed(val, ctrl->reg_base + MSM8953_APM_DLY_CNTR);
355 /* make sure write completes before return */
356 mb();
357 }
358
359 return rc;
360}
361
362static int msm_apm_secure_clock_source_override(
363 struct msm_apm_ctrl_dev *ctrl_dev, bool enable)
364{
365 int ret;
366
367 if (ctrl_dev->clk_src_override) {
368 ret = __invoke_psci_fn_smc(0xC4000020, 3, enable ?
369 CLOCK_ASSERT_ENABLE :
370 CLOCK_ASSERT_DISABLE, 0);
371 if (ret)
372 dev_err(ctrl_dev->dev, "PSCI request to switch to %s clock source failed\n",
373 enable ? "GPLL0" : "original");
374 }
375
376 return 0;
377}
378
379static int msm8996_apm_wait_for_switch(struct msm_apm_ctrl_dev *ctrl_dev,
380 u32 done_val)
381{
382 int timeout = MSM_APM_SWITCH_TIMEOUT_US;
383 u32 regval;
384
385 while (timeout > 0) {
386 regval = readl_relaxed(ctrl_dev->reg_base + APCC_APM_CTL_STS);
387 if ((regval & MSM_APM_CTL_STS_MASK) == done_val)
388 break;
389
390 udelay(1);
391 timeout--;
392 }
393
394 if (timeout == 0) {
395 dev_err(ctrl_dev->dev, "%s switch timed out. APCC_APM_CTL_STS=0x%x\n",
396 done_val == MSM_APM_MX_DONE_VAL
397 ? "APCC to MX" : "MX to APCC",
398 regval);
399 return -ETIMEDOUT;
400 }
401
402 return 0;
403}
404
405static int msm8996_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev)
406{
407 unsigned long flags;
408 int i, ret;
409
410 mutex_lock(&scm_lmh_lock);
411 spin_lock_irqsave(&ctrl_dev->lock, flags);
412
413 ret = msm_apm_secure_clock_source_override(ctrl_dev, true);
414 if (ret)
415 goto done;
416
417 /* Perform revision-specific programming steps */
418 if (ctrl_dev->version < HMSS_VERSION_1P2) {
419 /* Clear SPM events */
420 for (i = 0; i < SPM_EVENT_NUM; i++)
421 writel_relaxed(SPM_EVENT_CLEAR_VAL,
422 ctrl_dev->apcs_spm_events_addr[i]);
423
424 udelay(SPM_WAKEUP_DELAY_US);
425
426 /* Switch APC/CBF to GPLL0 clock */
427 writel_relaxed(APCS_GFMUXA_SEL_VAL,
428 ctrl_dev->apcs_csr_base + APCS_SPARE);
429 ndelay(200);
430 writel_relaxed(MSM_APM_OVERRIDE_SEL_VAL,
431 ctrl_dev->apc0_pll_ctl_addr);
432 ndelay(200);
433 writel_relaxed(MSM_APM_OVERRIDE_SEL_VAL,
434 ctrl_dev->apc1_pll_ctl_addr);
435
436 /* Ensure writes complete before proceeding */
437 mb();
438 }
439
440 /* Switch arrays to MX supply and wait for its completion */
441 writel_relaxed(MSM_APM_MX_MODE_VAL, ctrl_dev->reg_base +
442 APCC_APM_MODE);
443
444 /* Ensure write above completes before delaying */
445 mb();
446
447 ret = msm8996_apm_wait_for_switch(ctrl_dev, MSM_APM_MX_DONE_VAL);
448
449 /* Perform revision-specific programming steps */
450 if (ctrl_dev->version < HMSS_VERSION_1P2) {
451 /* Switch APC/CBF clocks to original source */
452 writel_relaxed(APCS_GFMUXA_DESEL_VAL,
453 ctrl_dev->apcs_csr_base + APCS_SPARE);
454 ndelay(200);
455 writel_relaxed(MSM_APM_SEC_CLK_SEL_VAL,
456 ctrl_dev->apc0_pll_ctl_addr);
457 ndelay(200);
458 writel_relaxed(MSM_APM_SEC_CLK_SEL_VAL,
459 ctrl_dev->apc1_pll_ctl_addr);
460
461 /* Complete clock source switch before SPM event sequence */
462 mb();
463
464 /* Set SPM events */
465 for (i = 0; i < SPM_EVENT_NUM; i++)
466 writel_relaxed(SPM_EVENT_SET_VAL,
467 ctrl_dev->apcs_spm_events_addr[i]);
468 }
469
470 /*
471 * Ensure that HMSS v1.0/v1.1 register writes are completed before
472 * bailing out in the case of a switching time out.
473 */
474 if (ret)
475 goto done;
476
477 ret = msm_apm_secure_clock_source_override(ctrl_dev, false);
478 if (ret)
479 goto done;
480
481 ctrl_dev->supply = MSM_APM_SUPPLY_MX;
482 dev_dbg(ctrl_dev->dev, "APM supply switched to MX\n");
483
484done:
485 spin_unlock_irqrestore(&ctrl_dev->lock, flags);
486 mutex_unlock(&scm_lmh_lock);
487
488 return ret;
489}
490
491static int msm8996_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev)
492{
493 unsigned long flags;
494 int i, ret;
495
496 mutex_lock(&scm_lmh_lock);
497 spin_lock_irqsave(&ctrl_dev->lock, flags);
498
499 ret = msm_apm_secure_clock_source_override(ctrl_dev, true);
500 if (ret)
501 goto done;
502
503 /* Perform revision-specific programming steps */
504 if (ctrl_dev->version < HMSS_VERSION_1P2) {
505 /* Clear SPM events */
506 for (i = 0; i < SPM_EVENT_NUM; i++)
507 writel_relaxed(SPM_EVENT_CLEAR_VAL,
508 ctrl_dev->apcs_spm_events_addr[i]);
509
510 udelay(SPM_WAKEUP_DELAY_US);
511
512 /* Switch APC/CBF to GPLL0 clock */
513 writel_relaxed(APCS_GFMUXA_SEL_VAL,
514 ctrl_dev->apcs_csr_base + APCS_SPARE);
515 ndelay(200);
516 writel_relaxed(MSM_APM_OVERRIDE_SEL_VAL,
517 ctrl_dev->apc0_pll_ctl_addr);
518 ndelay(200);
519 writel_relaxed(MSM_APM_OVERRIDE_SEL_VAL,
520 ctrl_dev->apc1_pll_ctl_addr);
521
522 /* Ensure previous writes complete before proceeding */
523 mb();
524 }
525
526 /* Switch arrays to APCC supply and wait for its completion */
527 writel_relaxed(MSM_APM_APCC_MODE_VAL, ctrl_dev->reg_base +
528 APCC_APM_MODE);
529
530 /* Ensure write above completes before delaying */
531 mb();
532
533 ret = msm8996_apm_wait_for_switch(ctrl_dev, MSM_APM_APCC_DONE_VAL);
534
535 /* Perform revision-specific programming steps */
536 if (ctrl_dev->version < HMSS_VERSION_1P2) {
537 /* Set SPM events */
538 for (i = 0; i < SPM_EVENT_NUM; i++)
539 writel_relaxed(SPM_EVENT_SET_VAL,
540 ctrl_dev->apcs_spm_events_addr[i]);
541
542 /* Complete SPM event sequence before clock source switch */
543 mb();
544
545 /* Switch APC/CBF clocks to original source */
546 writel_relaxed(APCS_GFMUXA_DESEL_VAL,
547 ctrl_dev->apcs_csr_base + APCS_SPARE);
548 ndelay(200);
549 writel_relaxed(MSM_APM_SEC_CLK_SEL_VAL,
550 ctrl_dev->apc0_pll_ctl_addr);
551 ndelay(200);
552 writel_relaxed(MSM_APM_SEC_CLK_SEL_VAL,
553 ctrl_dev->apc1_pll_ctl_addr);
554 }
555
556 /*
557 * Ensure that HMSS v1.0/v1.1 register writes are completed before
558 * bailing out in the case of a switching time out.
559 */
560 if (ret)
561 goto done;
562
563 ret = msm_apm_secure_clock_source_override(ctrl_dev, false);
564 if (ret)
565 goto done;
566
567 ctrl_dev->supply = MSM_APM_SUPPLY_APCC;
568 dev_dbg(ctrl_dev->dev, "APM supply switched to APCC\n");
569
570done:
571 spin_unlock_irqrestore(&ctrl_dev->lock, flags);
572 mutex_unlock(&scm_lmh_lock);
573
574 return ret;
575}
576
577static int msm8996pro_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev)
578{
579 unsigned long flags;
580 int ret;
581
582 spin_lock_irqsave(&ctrl_dev->lock, flags);
583
584 /* Switch arrays to MX supply and wait for its completion */
585 writel_relaxed(MSM_APM_MX_MODE_VAL, ctrl_dev->reg_base +
586 APCC_APM_MODE);
587
588 /* Ensure write above completes before delaying */
589 mb();
590
591 ret = msm8996_apm_wait_for_switch(ctrl_dev, MSM_APM_MX_DONE_VAL);
592 if (ret)
593 goto done;
594
595 ctrl_dev->supply = MSM_APM_SUPPLY_MX;
596 dev_dbg(ctrl_dev->dev, "APM supply switched to MX\n");
597
598done:
599 spin_unlock_irqrestore(&ctrl_dev->lock, flags);
600
601 return ret;
602}
603
604static int msm8996pro_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev)
605{
606 unsigned long flags;
607 int ret;
608
609 spin_lock_irqsave(&ctrl_dev->lock, flags);
610
611 /* Switch arrays to APCC supply and wait for its completion */
612 writel_relaxed(MSM_APM_APCC_MODE_VAL, ctrl_dev->reg_base +
613 APCC_APM_MODE);
614
615 /* Ensure write above completes before delaying */
616 mb();
617
618 ret = msm8996_apm_wait_for_switch(ctrl_dev, MSM_APM_APCC_DONE_VAL);
619 if (ret)
620 goto done;
621
622 ctrl_dev->supply = MSM_APM_SUPPLY_APCC;
623 dev_dbg(ctrl_dev->dev, "APM supply switched to APCC\n");
624
625done:
626 spin_unlock_irqrestore(&ctrl_dev->lock, flags);
627
628 return ret;
629}
630
631/* MSM8953 register value definitions */
632#define MSM8953_APM_MX_MODE_VAL 0x00
633#define MSM8953_APM_APCC_MODE_VAL 0x02
634#define MSM8953_APM_MX_DONE_VAL 0x00
635#define MSM8953_APM_APCC_DONE_VAL 0x03
636
637/* MSM8953 register offset definitions */
638#define MSM8953_APCC_APM_MODE 0x000002a8
639#define MSM8953_APCC_APM_CTL_STS 0x000002b0
640
Tirupathi Reddya008e002016-04-15 18:29:52 +0530641/* 8953 constants */
642#define MSM8953_APM_SWITCH_TIMEOUT_US 500
643
644/* Register bit mask definitions */
645#define MSM8953_APM_CTL_STS_MASK 0x1f
646
David Collins7370f1a2017-01-18 16:21:53 -0800647static int msm8953_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev)
648{
Tirupathi Reddya008e002016-04-15 18:29:52 +0530649 int timeout = MSM8953_APM_SWITCH_TIMEOUT_US;
David Collins7370f1a2017-01-18 16:21:53 -0800650 u32 regval;
651 int ret = 0;
652 unsigned long flags;
653
654 spin_lock_irqsave(&ctrl_dev->lock, flags);
655
656 /* Switch arrays to MX supply and wait for its completion */
657 writel_relaxed(MSM8953_APM_MX_MODE_VAL, ctrl_dev->reg_base +
658 MSM8953_APCC_APM_MODE);
659
660 /* Ensure write above completes before delaying */
661 mb();
662
663 while (timeout > 0) {
664 regval = readl_relaxed(ctrl_dev->reg_base +
665 MSM8953_APCC_APM_CTL_STS);
Tirupathi Reddya008e002016-04-15 18:29:52 +0530666 if ((regval & MSM8953_APM_CTL_STS_MASK) ==
David Collins7370f1a2017-01-18 16:21:53 -0800667 MSM8953_APM_MX_DONE_VAL)
668 break;
669
670 udelay(1);
671 timeout--;
672 }
673
674 if (timeout == 0) {
675 ret = -ETIMEDOUT;
676 dev_err(ctrl_dev->dev, "APCC to MX APM switch timed out. APCC_APM_CTL_STS=0x%x\n",
677 regval);
678 } else {
679 ctrl_dev->supply = MSM_APM_SUPPLY_MX;
680 dev_dbg(ctrl_dev->dev, "APM supply switched to MX\n");
681 }
682
683 spin_unlock_irqrestore(&ctrl_dev->lock, flags);
684
685 return ret;
686}
687
688static int msm8953_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev)
689{
Tirupathi Reddya008e002016-04-15 18:29:52 +0530690 int timeout = MSM8953_APM_SWITCH_TIMEOUT_US;
David Collins7370f1a2017-01-18 16:21:53 -0800691 u32 regval;
692 int ret = 0;
693 unsigned long flags;
694
695 spin_lock_irqsave(&ctrl_dev->lock, flags);
696
697 /* Switch arrays to APCC supply and wait for its completion */
698 writel_relaxed(MSM8953_APM_APCC_MODE_VAL, ctrl_dev->reg_base +
699 MSM8953_APCC_APM_MODE);
700
701 /* Ensure write above completes before delaying */
702 mb();
703
704 while (timeout > 0) {
705 regval = readl_relaxed(ctrl_dev->reg_base +
706 MSM8953_APCC_APM_CTL_STS);
Tirupathi Reddya008e002016-04-15 18:29:52 +0530707 if ((regval & MSM8953_APM_CTL_STS_MASK) ==
David Collins7370f1a2017-01-18 16:21:53 -0800708 MSM8953_APM_APCC_DONE_VAL)
709 break;
710
711 udelay(1);
712 timeout--;
713 }
714
715 if (timeout == 0) {
716 ret = -ETIMEDOUT;
717 dev_err(ctrl_dev->dev, "MX to APCC APM switch timed out. APCC_APM_CTL_STS=0x%x\n",
718 regval);
719 } else {
720 ctrl_dev->supply = MSM_APM_SUPPLY_APCC;
721 dev_dbg(ctrl_dev->dev, "APM supply switched to APCC\n");
722 }
723
724 spin_unlock_irqrestore(&ctrl_dev->lock, flags);
725
726 return ret;
727}
728
729static int msm_apm_switch_to_mx(struct msm_apm_ctrl_dev *ctrl_dev)
730{
731 int ret = 0;
732
733 switch (ctrl_dev->msm_id) {
734 case MSM8996_ID:
735 ret = msm8996_apm_switch_to_mx(ctrl_dev);
736 break;
737 case MSM8996PRO_ID:
738 ret = msm8996pro_apm_switch_to_mx(ctrl_dev);
739 break;
740 case MSM8953_ID:
741 ret = msm8953_apm_switch_to_mx(ctrl_dev);
742 break;
743 }
744
745 return ret;
746}
747
748static int msm_apm_switch_to_apcc(struct msm_apm_ctrl_dev *ctrl_dev)
749{
750 int ret = 0;
751
752 switch (ctrl_dev->msm_id) {
753 case MSM8996_ID:
754 ret = msm8996_apm_switch_to_apcc(ctrl_dev);
755 break;
756 case MSM8996PRO_ID:
757 ret = msm8996pro_apm_switch_to_apcc(ctrl_dev);
758 break;
759 case MSM8953_ID:
760 ret = msm8953_apm_switch_to_apcc(ctrl_dev);
761 break;
762 }
763
764 return ret;
765}
766
767/**
768 * msm_apm_get_supply() - Returns the supply that is currently
769 * powering the memory arrays
770 * @ctrl_dev: Pointer to an MSM APM controller device
771 *
772 * Returns the supply currently selected by the APM.
773 */
774int msm_apm_get_supply(struct msm_apm_ctrl_dev *ctrl_dev)
775{
776 return ctrl_dev->supply;
777}
778EXPORT_SYMBOL(msm_apm_get_supply);
779
780/**
781 * msm_apm_set_supply() - Perform the necessary steps to switch the voltage
782 * source of the memory arrays to a given supply
783 * @ctrl_dev: Pointer to an MSM APM controller device
784 * @supply: Power rail to use as supply for the memory
785 * arrays
786 *
787 * Returns 0 on success, -ETIMEDOUT on APM switch timeout, or -EPERM if
788 * the supply is not supported.
789 */
790int msm_apm_set_supply(struct msm_apm_ctrl_dev *ctrl_dev,
791 enum msm_apm_supply supply)
792{
793 int ret;
794
795 switch (supply) {
796 case MSM_APM_SUPPLY_APCC:
797 ret = msm_apm_switch_to_apcc(ctrl_dev);
798 break;
799 case MSM_APM_SUPPLY_MX:
800 ret = msm_apm_switch_to_mx(ctrl_dev);
801 break;
802 default:
803 ret = -EPERM;
804 break;
805 }
806
807 return ret;
808}
809EXPORT_SYMBOL(msm_apm_set_supply);
810
811/**
812 * msm_apm_ctrl_dev_get() - get a handle to the MSM APM controller linked to
813 * the device in device tree
814 * @dev: Pointer to the device
815 *
816 * The device must specify "qcom,apm-ctrl" property in its device tree
817 * node which points to an MSM APM controller device node.
818 *
819 * Returns an MSM APM controller handle if successful or ERR_PTR on any error.
820 * If the APM controller device hasn't probed yet, ERR_PTR(-EPROBE_DEFER) is
821 * returned.
822 */
823struct msm_apm_ctrl_dev *msm_apm_ctrl_dev_get(struct device *dev)
824{
825 struct msm_apm_ctrl_dev *ctrl_dev = NULL;
826 struct msm_apm_ctrl_dev *dev_found = ERR_PTR(-EPROBE_DEFER);
827 struct device_node *ctrl_node;
828
829 if (!dev || !dev->of_node) {
830 pr_err("Invalid device node\n");
831 return ERR_PTR(-EINVAL);
832 }
833
834 ctrl_node = of_parse_phandle(dev->of_node, "qcom,apm-ctrl", 0);
835 if (!ctrl_node) {
836 pr_err("Could not find qcom,apm-ctrl property in %s\n",
837 dev->of_node->full_name);
838 return ERR_PTR(-ENXIO);
839 }
840
841 mutex_lock(&apm_ctrl_list_mutex);
842 list_for_each_entry(ctrl_dev, &apm_ctrl_list, list) {
843 if (ctrl_dev->dev && ctrl_dev->dev->of_node == ctrl_node) {
844 dev_found = ctrl_dev;
845 break;
846 }
847 }
848 mutex_unlock(&apm_ctrl_list_mutex);
849
850 of_node_put(ctrl_node);
851 return dev_found;
852}
853EXPORT_SYMBOL(msm_apm_ctrl_dev_get);
854
855#if defined(CONFIG_DEBUG_FS)
856
857static int apm_supply_dbg_open(struct inode *inode, struct file *filep)
858{
859 filep->private_data = inode->i_private;
860
861 return 0;
862}
863
864static ssize_t apm_supply_dbg_read(struct file *filep, char __user *ubuf,
865 size_t count, loff_t *ppos)
866{
867 struct msm_apm_ctrl_dev *ctrl_dev = filep->private_data;
868 char buf[10];
869 int len;
870
871 if (!ctrl_dev) {
872 pr_err("invalid apm ctrl handle\n");
873 return -ENODEV;
874 }
875
876 if (ctrl_dev->supply == MSM_APM_SUPPLY_APCC)
877 len = snprintf(buf, sizeof(buf), "APCC\n");
878 else if (ctrl_dev->supply == MSM_APM_SUPPLY_MX)
879 len = snprintf(buf, sizeof(buf), "MX\n");
880 else
881 len = snprintf(buf, sizeof(buf), "ERR\n");
882
883 return simple_read_from_buffer(ubuf, count, ppos, buf, len);
884}
885
886static const struct file_operations apm_supply_fops = {
887 .open = apm_supply_dbg_open,
888 .read = apm_supply_dbg_read,
889};
890
891static void apm_debugfs_base_init(void)
892{
893 apm_debugfs_base = debugfs_create_dir("msm-apm", NULL);
894
895 if (IS_ERR_OR_NULL(apm_debugfs_base))
896 pr_err("msm-apm debugfs base directory creation failed\n");
897}
898
899static void apm_debugfs_init(struct msm_apm_ctrl_dev *ctrl_dev)
900{
901 struct dentry *temp;
902
903 if (IS_ERR_OR_NULL(apm_debugfs_base)) {
904 pr_err("Base directory missing, cannot create apm debugfs nodes\n");
905 return;
906 }
907
908 ctrl_dev->debugfs = debugfs_create_dir(dev_name(ctrl_dev->dev),
909 apm_debugfs_base);
910 if (IS_ERR_OR_NULL(ctrl_dev->debugfs)) {
911 pr_err("%s debugfs directory creation failed\n",
912 dev_name(ctrl_dev->dev));
913 return;
914 }
915
916 temp = debugfs_create_file("supply", 0444, ctrl_dev->debugfs,
917 ctrl_dev, &apm_supply_fops);
918 if (IS_ERR_OR_NULL(temp)) {
919 pr_err("supply mode creation failed\n");
920 return;
921 }
922}
923
924static void apm_debugfs_deinit(struct msm_apm_ctrl_dev *ctrl_dev)
925{
926 if (!IS_ERR_OR_NULL(ctrl_dev->debugfs))
927 debugfs_remove_recursive(ctrl_dev->debugfs);
928}
929
930static void apm_debugfs_base_remove(void)
931{
932 debugfs_remove_recursive(apm_debugfs_base);
933}
934#else
935
936static void apm_debugfs_base_init(void)
937{}
938
939static void apm_debugfs_init(struct msm_apm_ctrl_dev *ctrl_dev)
940{}
941
942static void apm_debugfs_deinit(struct msm_apm_ctrl_dev *ctrl_dev)
943{}
944
945static void apm_debugfs_base_remove(void)
946{}
947
948#endif
949
950static const struct of_device_id msm_apm_match_table[] = {
951 {
952 .compatible = "qcom,msm-apm",
953 .data = (void *)(uintptr_t)MSM8996_ID,
954 },
955 {
956 .compatible = "qcom,msm8996pro-apm",
957 .data = (void *)(uintptr_t)MSM8996PRO_ID,
958 },
959 {
960 .compatible = "qcom,msm8953-apm",
961 .data = (void *)(uintptr_t)MSM8953_ID,
962 },
963 {}
964};
965
966static int msm_apm_probe(struct platform_device *pdev)
967{
968 struct device *dev = &pdev->dev;
969 struct msm_apm_ctrl_dev *ctrl;
970 const struct of_device_id *match;
971 int ret = 0;
972
973 dev_dbg(dev, "probing MSM Array Power Mux driver\n");
974
975 if (!dev->of_node) {
976 dev_err(dev, "Device tree node is missing\n");
977 return -ENODEV;
978 }
979
980 match = of_match_device(msm_apm_match_table, dev);
981 if (!match)
982 return -ENODEV;
983
984 ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
985 if (!ctrl)
986 return -ENOMEM;
987
988 INIT_LIST_HEAD(&ctrl->list);
989 spin_lock_init(&ctrl->lock);
990 ctrl->dev = dev;
991 ctrl->msm_id = (uintptr_t)match->data;
992 platform_set_drvdata(pdev, ctrl);
993
994 switch (ctrl->msm_id) {
995 case MSM8996_ID:
996 case MSM8996PRO_ID:
997 ret = msm_apm_ctrl_devm_ioremap(pdev, ctrl);
998 if (ret) {
999 dev_err(dev, "Failed to add APM controller device\n");
1000 return ret;
1001 }
1002 break;
1003 case MSM8953_ID:
1004 ret = msm8953_apm_ctrl_init(pdev, ctrl);
1005 if (ret) {
1006 dev_err(dev, "Failed to initialize APM controller device: ret=%d\n",
1007 ret);
1008 return ret;
1009 }
1010 break;
1011 default:
1012 dev_err(dev, "unable to add APM controller device for msm_id:%d\n",
1013 ctrl->msm_id);
1014 return -ENODEV;
1015 }
1016
1017 apm_debugfs_init(ctrl);
1018 mutex_lock(&apm_ctrl_list_mutex);
1019 list_add_tail(&ctrl->list, &apm_ctrl_list);
1020 mutex_unlock(&apm_ctrl_list_mutex);
1021
1022 dev_dbg(dev, "MSM Array Power Mux driver probe successful");
1023
1024 return ret;
1025}
1026
1027static int msm_apm_remove(struct platform_device *pdev)
1028{
1029 struct msm_apm_ctrl_dev *ctrl_dev;
1030
1031 ctrl_dev = platform_get_drvdata(pdev);
1032 if (ctrl_dev) {
1033 mutex_lock(&apm_ctrl_list_mutex);
1034 list_del(&ctrl_dev->list);
1035 mutex_unlock(&apm_ctrl_list_mutex);
1036 apm_debugfs_deinit(ctrl_dev);
1037 }
1038
1039 return 0;
1040}
1041
1042static struct platform_driver msm_apm_driver = {
1043 .driver = {
1044 .name = MSM_APM_DRIVER_NAME,
1045 .of_match_table = msm_apm_match_table,
1046 .owner = THIS_MODULE,
1047 },
1048 .probe = msm_apm_probe,
1049 .remove = msm_apm_remove,
1050};
1051
1052static int __init msm_apm_init(void)
1053{
1054 apm_debugfs_base_init();
1055 return platform_driver_register(&msm_apm_driver);
1056}
1057
1058static void __exit msm_apm_exit(void)
1059{
1060 platform_driver_unregister(&msm_apm_driver);
1061 apm_debugfs_base_remove();
1062}
1063
1064arch_initcall(msm_apm_init);
1065module_exit(msm_apm_exit);
1066
1067MODULE_DESCRIPTION("MSM Array Power Mux driver");
1068MODULE_LICENSE("GPL v2");