Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff07d5bd authored by Lina Iyer's avatar Lina Iyer
Browse files

drivers: qcom: system_pm: add system PM driver for QTI SoC



Handle QTI specific functionality when entering system low power modes
for the SoC. When the application processor subsystem, decides it has
nothing else to do, it could enter an idle state initiated either by
cpuidle or suspend framework. In both these cases, Linux is ready to
vote for the SoC to enter deeper low power modes that could turn off or
lower requirements on resources that are no longer needed by the
subsystem. This facilitates power saving by the SoC by reducing
bandwidth requirements on DDR, turning off backbone power rails, XO
buffers etc.

The driver exports API that are called by the cpuidle drivers that when
it has been decided that the system can safely enter deep idle states
for enough duration that it makes powering down SoC components
worthwhile.

This is a snapshot as of commit b4a69c05b01172d4be245db80f4b9.

Change-Id: I3b8ba0077b4d9abaa00ab8843104fa02b816afdd
Signed-off-by: default avatarLina Iyer <ilina@codeaurora.org>
parent baf71316
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
SYSTEM PM

System PM device is a virtual device that handles all CPU subsystem low power
mode activties. When entering core shutdown, resource state that were requested
from the processor may be relinquished and set to idle and restored when the
cores are brought out of sleep.

PROPERTIES

- compatible:
	Usage: required
	Value type: <string>
	Definition: must be "qcom,system-pm".

-mboxes:
	Usage: optional
	Value type: <phandle>
	Definition: phandle the TCS mailbox controller for the CPU subsystem.
	This property is generally set only for SoCs that use RPMH communication
	through a mailbox controller.

EXAMPLE

	system_pm {
		compatible = "qcom,system-pm";
		mboxes = <&apps_rsc 0>;
	};

+4 −0
Original line number Diff line number Diff line
@@ -309,6 +309,10 @@ config QTI_RPMH_API
	bool "QTI RPMH (h/w accelerators) Communication API"
	select MAILBOX
	select QTI_RPMH_MBOX
	select QTI_SYSTEM_PM
	help
	  This option enables RPMH hardware communication for making shared
	  resource requests on Qualcomm Technologies Inc SoCs.

config QTI_SYSTEM_PM
	bool
+1 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ obj-$(CONFIG_MSM_PIL) += peripheral-loader.o
obj-$(CONFIG_QCOM_BUS_SCALING) += msm_bus/
obj-$(CONFIG_QCOM_COMMAND_DB) += cmd-db.o
obj-$(CONFIG_QTI_RPMH_API) += rpmh.o
obj-$(CONFIG_QTI_SYSTEM_PM) += system_pm.o

ifdef CONFIG_MSM_SUBSYSTEM_RESTART
       obj-y += subsystem_notif.o
+110 −0
Original line number Diff line number Diff line
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

#include <linux/kernel.h>
#include <linux/platform_device.h>

#include <soc/qcom/rpmh.h>
#include <soc/qcom/system_pm.h>

#define ARCH_TIMER_HZ		(19200000UL)
#define PDC_TIME_VALID_SHIFT	31
#define PDC_TIME_UPPER_MASK	0xFFFFFF

static struct rpmh_client *rpmh_client;

static int setup_wakeup(uint64_t sleep_val)
{
	struct tcs_cmd cmd[2] = { { 0 } };

	cmd[0].data = (sleep_val >> 32) & PDC_TIME_UPPER_MASK;
	cmd[0].data |= 1 << PDC_TIME_VALID_SHIFT;
	cmd[1].data = sleep_val & 0xFFFFFFFF;

	return rpmh_write_control(rpmh_client, cmd, ARRAY_SIZE(cmd));
}

/**
 * system_sleep_allowed() - Returns if its okay to enter system low power modes
 */
bool system_sleep_allowed(void)
{
	return (rpmh_ctrlr_idle(rpmh_client) == 0);
}
EXPORT_SYMBOL(system_sleep_allowed);

/**
 * system_sleep_enter() - Activties done when entering system low power modes
 *
 * @sleep_val: The sleep duration in us.
 *
 * Returns 0 for success or error values from writing the timer value in the
 * hardware block.
 */
int system_sleep_enter(uint64_t sleep_val)
{
	int ret;

	if (IS_ERR_OR_NULL(rpmh_client))
		return -EFAULT;

	ret = rpmh_flush(rpmh_client);
	if (ret)
		return ret;

	/*
	 * Set up the wake up value offset from the current time.
	 * Convert us to ns to allow div by 19.2 Mhz tick timer.
	 */
	if (sleep_val) {
		sleep_val *= NSEC_PER_USEC;
		do_div(sleep_val, NSEC_PER_SEC/ARCH_TIMER_HZ);
		sleep_val += arch_counter_get_cntvct();
	} else {
		sleep_val = ~0ULL;
	}

	return setup_wakeup(sleep_val);
}
EXPORT_SYMBOL(system_sleep_enter);

/**
 * system_sleep_exit() - Activities done when exiting system low power modes
 */
void system_sleep_exit(void)
{
}
EXPORT_SYMBOL(system_sleep_exit);

static int sys_pm_probe(struct platform_device *pdev)
{
	rpmh_client = rpmh_get_byindex(pdev, 0);
	if (IS_ERR_OR_NULL(rpmh_client))
		return PTR_ERR(rpmh_client);

	return 0;
}

static const struct of_device_id sys_pm_drv_match[] = {
	{ .compatible = "qcom,system-pm", },
	{ }
};

static struct platform_driver sys_pm_driver = {
	.probe = sys_pm_probe,
	.driver = {
		.name = KBUILD_MODNAME,
		.of_match_table = sys_pm_drv_match,
	},
};
builtin_platform_driver(sys_pm_driver);
+34 −0
Original line number Diff line number Diff line
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */
#ifndef __SOC_QCOM_SYS_PM_H__
#define __SOC_QCOM_SYS_PM_H__

#ifdef CONFIG_QTI_SYSTEM_PM
int system_sleep_enter(uint64_t sleep_val);

void system_sleep_exit(void);

bool system_sleep_allowed(void);
#else
static inline int system_sleep_enter(uint64_t sleep_val)
{ return -ENODEV; }

static inline void system_sleep_exit(void)
{ }

static inline bool system_sleep_allowed(void)
{ return false; }

#endif /* CONFIG_QTI_SYSTEM_PM */

#endif /* __SOC_QCOM_SYS_PM_H__ */