blob: 9ef685b924ad7ad4188d3cd75a1502120eb4fa52 [file] [log] [blame]
Maulik Shah24c5f032018-02-01 14:39:50 +05301/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
Lina Iyer15d6df32016-08-18 12:10:27 -06002 *
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
14#include <linux/kernel.h>
15#include <linux/platform_device.h>
Archana Sathyakumardf8e8c32017-10-31 13:45:13 -060016#include <asm/arch_timer.h>
Lina Iyera2243002017-12-21 01:30:38 +000017#include <clocksource/arm_arch_timer.h>
Maulik Shah24c5f032018-02-01 14:39:50 +053018#include "rpmh_master_stat.h"
Raju P.L.S.S.S.N99d241e2017-12-07 00:09:01 +053019#include <soc/qcom/lpm_levels.h>
20#include <soc/qcom/rpmh.h>
Lina Iyera2243002017-12-21 01:30:38 +000021
Lina Iyer15d6df32016-08-18 12:10:27 -060022#define PDC_TIME_VALID_SHIFT 31
23#define PDC_TIME_UPPER_MASK 0xFFFFFF
24
Mahesh Sivasubramanian247fccb2018-03-20 08:43:19 -060025#ifdef CONFIG_ARM_GIC_V3
26#include <linux/irqchip/arm-gic-v3.h>
27#else
28static inline void gic_v3_dist_restore(void) {}
29static inline void gic_v3_dist_save(void) {}
30#endif
31
Lina Iyer15d6df32016-08-18 12:10:27 -060032static struct rpmh_client *rpmh_client;
33
Lina Iyera2243002017-12-21 01:30:38 +000034static int setup_wakeup(uint32_t lo, uint32_t hi)
Lina Iyer15d6df32016-08-18 12:10:27 -060035{
Lina Iyerd1a6e682017-06-20 10:05:09 -060036 struct tcs_cmd cmd[2] = { { 0 } };
Lina Iyer15d6df32016-08-18 12:10:27 -060037
Lina Iyera2243002017-12-21 01:30:38 +000038 cmd[0].data = hi & PDC_TIME_UPPER_MASK;
Lina Iyerd93fbce2017-03-01 09:07:20 -070039 cmd[0].data |= 1 << PDC_TIME_VALID_SHIFT;
Lina Iyera2243002017-12-21 01:30:38 +000040 cmd[1].data = lo;
Lina Iyer15d6df32016-08-18 12:10:27 -060041
42 return rpmh_write_control(rpmh_client, cmd, ARRAY_SIZE(cmd));
43}
44
Raju P.L.S.S.S.N99d241e2017-12-07 00:09:01 +053045static int system_sleep_update_wakeup(bool from_idle)
Lina Iyera2243002017-12-21 01:30:38 +000046{
47 uint32_t lo = ~0U, hi = ~0U;
48
49 /* Read the hardware to get the most accurate value */
50 arch_timer_mem_get_cval(&lo, &hi);
51
52 return setup_wakeup(lo, hi);
53}
Lina Iyera2243002017-12-21 01:30:38 +000054
Lina Iyer15d6df32016-08-18 12:10:27 -060055/**
Lina Iyer4524c0e2017-08-15 11:32:31 -060056 * system_sleep_allowed() - Returns if its okay to enter system low power modes
57 */
Raju P.L.S.S.S.N99d241e2017-12-07 00:09:01 +053058static bool system_sleep_allowed(void)
Lina Iyer4524c0e2017-08-15 11:32:31 -060059{
60 return (rpmh_ctrlr_idle(rpmh_client) == 0);
61}
Lina Iyer4524c0e2017-08-15 11:32:31 -060062
63/**
Lina Iyer15d6df32016-08-18 12:10:27 -060064 * system_sleep_enter() - Activties done when entering system low power modes
65 *
Lina Iyera2243002017-12-21 01:30:38 +000066 * Returns 0 for success or error values from writing the sleep/wake values to
67 * the hardware block.
Lina Iyer15d6df32016-08-18 12:10:27 -060068 */
Raju P.L.S.S.S.N99d241e2017-12-07 00:09:01 +053069static int system_sleep_enter(struct cpumask *mask)
Lina Iyer15d6df32016-08-18 12:10:27 -060070{
Mahesh Sivasubramanian247fccb2018-03-20 08:43:19 -060071 gic_v3_dist_save();
Lina Iyera2243002017-12-21 01:30:38 +000072 return rpmh_flush(rpmh_client);
Lina Iyer15d6df32016-08-18 12:10:27 -060073}
Lina Iyer15d6df32016-08-18 12:10:27 -060074
75/**
76 * system_sleep_exit() - Activities done when exiting system low power modes
77 */
Raju P.L.S.S.S.N99d241e2017-12-07 00:09:01 +053078static void system_sleep_exit(void)
Lina Iyer15d6df32016-08-18 12:10:27 -060079{
Maulik Shah24c5f032018-02-01 14:39:50 +053080 msm_rpmh_master_stats_update();
Mahesh Sivasubramanian247fccb2018-03-20 08:43:19 -060081 gic_v3_dist_restore();
Lina Iyer15d6df32016-08-18 12:10:27 -060082}
Raju P.L.S.S.S.N99d241e2017-12-07 00:09:01 +053083
84static struct system_pm_ops pm_ops = {
85 .enter = system_sleep_enter,
86 .exit = system_sleep_exit,
87 .update_wakeup = system_sleep_update_wakeup,
88 .sleep_allowed = system_sleep_allowed,
89};
Lina Iyer15d6df32016-08-18 12:10:27 -060090
91static int sys_pm_probe(struct platform_device *pdev)
92{
93 rpmh_client = rpmh_get_byindex(pdev, 0);
94 if (IS_ERR_OR_NULL(rpmh_client))
95 return PTR_ERR(rpmh_client);
96
Raju P.L.S.S.S.N99d241e2017-12-07 00:09:01 +053097 return register_system_pm_ops(&pm_ops);
Lina Iyer15d6df32016-08-18 12:10:27 -060098}
99
100static const struct of_device_id sys_pm_drv_match[] = {
101 { .compatible = "qcom,system-pm", },
102 { }
103};
104
105static struct platform_driver sys_pm_driver = {
106 .probe = sys_pm_probe,
107 .driver = {
108 .name = KBUILD_MODNAME,
Maulik Shah59b58152018-07-11 11:18:16 +0530109 .suppress_bind_attrs = true,
Lina Iyer15d6df32016-08-18 12:10:27 -0600110 .of_match_table = sys_pm_drv_match,
111 },
112};
113builtin_platform_driver(sys_pm_driver);