forked from luck/tmp_suning_uos_patched
Add the power-domain base-driver which currently contains
support for the rk3288 powerdomain layout but can be easily extended for the socs (including arm64) later on. A big thanks to Ceasar Wang for pulling through on this during 18 revisions. Also included is a fix to the pm-clock handling in the generic powerdomains to adapt it to the per-user clock handling we now do, Acked by Rafael Wysocki. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABCAAGBQJWFNeQAAoJEPOmecmc0R2BgHQH/RR/YS0IUPaeYhLr3FMVc47o GrObw1uaNaykGSV8XYIxoxQaP+MwoW7Mw6ipfw+FLmqVGRjz8ljTIcnFrgz7hly1 CHmG6yCMjAeLh2ZMu3ge/VSQ7BdB7U690Coj5JnnfpO+Rufvu8Pp9sV+q4AH0qH2 bEfsoBoHQldTXCA5vlvH9C0CAqLDOBXWimgLRVi5TGCJjEsQINoeqJOWTl+hHnsi arJs1sKBi71jFygsYXSZKIUnoZ1JUZofattPH8YgLeXNGUncEUYJsTTWYxm78ORt 3/iP0/mnqXnoFEqrY9Whi3IVpW60gnKUdUuAD4KK9vx1feT0bwLtVf/0lpCNXf8= =txXq -----END PGP SIGNATURE----- Merge tag 'v4.4-rockchip-drivers1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip into next/drivers Merge "Rockchip power-domain drivers for 4.4" from Heiko Stuebner: Add the power-domain base-driver which currently contains support for the rk3288 powerdomain layout but can be easily extended for the socs (including arm64) later on. A big thanks to Ceasar Wang for pulling through on this during 18 revisions. Also included is a fix to the pm-clock handling in the generic powerdomains to adapt it to the per-user clock handling we now do, Acked by Rafael Wysocki. * tag 'v4.4-rockchip-drivers1' of git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip: soc: rockchip: power-domain: Add power domain driver dt-bindings: add document of Rockchip power domains PM / clk: Do not __clk_get passed in clock-references dt-bindings: add power-domain header for RK3288 SoCs
This commit is contained in:
commit
273395f0c2
|
@ -0,0 +1,46 @@
|
|||
* Rockchip Power Domains
|
||||
|
||||
Rockchip processors include support for multiple power domains which can be
|
||||
powered up/down by software based on different application scenes to save power.
|
||||
|
||||
Required properties for power domain controller:
|
||||
- compatible: Should be one of the following.
|
||||
"rockchip,rk3288-power-controller" - for RK3288 SoCs.
|
||||
- #power-domain-cells: Number of cells in a power-domain specifier.
|
||||
Should be 1 for multiple PM domains.
|
||||
- #address-cells: Should be 1.
|
||||
- #size-cells: Should be 0.
|
||||
|
||||
Required properties for power domain sub nodes:
|
||||
- reg: index of the power domain, should use macros in:
|
||||
"include/dt-bindings/power-domain/rk3288.h" - for RK3288 type power domain.
|
||||
- clocks (optional): phandles to clocks which need to be enabled while power domain
|
||||
switches state.
|
||||
|
||||
Example:
|
||||
|
||||
power: power-controller {
|
||||
compatible = "rockchip,rk3288-power-controller";
|
||||
#power-domain-cells = <1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
pd_gpu {
|
||||
reg = <RK3288_PD_GPU>;
|
||||
clocks = <&cru ACLK_GPU>;
|
||||
};
|
||||
};
|
||||
|
||||
Node of a device using power domains must have a power-domains property,
|
||||
containing a phandle to the power device node and an index specifying which
|
||||
power domain to use.
|
||||
The index should use macros in:
|
||||
"include/dt-bindings/power-domain/rk3288.h" - for rk3288 type power domain.
|
||||
|
||||
Example of the node using power domain:
|
||||
|
||||
node {
|
||||
/* ... */
|
||||
power-domains = <&power RK3288_PD_GPU>;
|
||||
/* ... */
|
||||
};
|
|
@ -93,7 +93,7 @@ static int __pm_clk_add(struct device *dev, const char *con_id,
|
|||
return -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
if (IS_ERR(clk) || !__clk_get(clk)) {
|
||||
if (IS_ERR(clk)) {
|
||||
kfree(ce);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -127,7 +127,9 @@ int pm_clk_add(struct device *dev, const char *con_id)
|
|||
* @clk: Clock pointer
|
||||
*
|
||||
* Add the clock to the list of clocks used for the power management of @dev.
|
||||
* It will increment refcount on clock pointer, use clk_put() on it when done.
|
||||
* The power-management code will take control of the clock reference, so
|
||||
* callers should not call clk_put() on @clk after this function sucessfully
|
||||
* returned.
|
||||
*/
|
||||
int pm_clk_add_clk(struct device *dev, struct clk *clk)
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@ menu "SOC (System On Chip) specific Drivers"
|
|||
|
||||
source "drivers/soc/mediatek/Kconfig"
|
||||
source "drivers/soc/qcom/Kconfig"
|
||||
source "drivers/soc/rockchip/Kconfig"
|
||||
source "drivers/soc/sunxi/Kconfig"
|
||||
source "drivers/soc/ti/Kconfig"
|
||||
source "drivers/soc/versatile/Kconfig"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
obj-$(CONFIG_MACH_DOVE) += dove/
|
||||
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
|
||||
obj-$(CONFIG_ARCH_QCOM) += qcom/
|
||||
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
|
||||
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
|
||||
obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
||||
obj-$(CONFIG_SOC_TI) += ti/
|
||||
|
|
14
drivers/soc/rockchip/Kconfig
Normal file
14
drivers/soc/rockchip/Kconfig
Normal file
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Rockchip Soc drivers
|
||||
#
|
||||
config ROCKCHIP_PM_DOMAINS
|
||||
bool "Rockchip generic power domain"
|
||||
depends on PM
|
||||
select PM_GENERIC_DOMAINS
|
||||
help
|
||||
Say y here to enable power domain support.
|
||||
In order to meet high performance and low power requirements, a power
|
||||
management unit is designed or saving power when RK3288 in low power
|
||||
mode. The RK3288 PMU is dedicated for managing the power of the whole chip.
|
||||
|
||||
If unsure, say N.
|
4
drivers/soc/rockchip/Makefile
Normal file
4
drivers/soc/rockchip/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
#
|
||||
# Rockchip Soc drivers
|
||||
#
|
||||
obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
|
490
drivers/soc/rockchip/pm_domains.c
Normal file
490
drivers/soc/rockchip/pm_domains.c
Normal file
|
@ -0,0 +1,490 @@
|
|||
/*
|
||||
* Rockchip Generic power domain support.
|
||||
*
|
||||
* Copyright (c) 2015 ROCKCHIP, Co. Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/pm_clock.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <dt-bindings/power/rk3288-power.h>
|
||||
|
||||
struct rockchip_domain_info {
|
||||
int pwr_mask;
|
||||
int status_mask;
|
||||
int req_mask;
|
||||
int idle_mask;
|
||||
int ack_mask;
|
||||
};
|
||||
|
||||
struct rockchip_pmu_info {
|
||||
u32 pwr_offset;
|
||||
u32 status_offset;
|
||||
u32 req_offset;
|
||||
u32 idle_offset;
|
||||
u32 ack_offset;
|
||||
|
||||
u32 core_pwrcnt_offset;
|
||||
u32 gpu_pwrcnt_offset;
|
||||
|
||||
unsigned int core_power_transition_time;
|
||||
unsigned int gpu_power_transition_time;
|
||||
|
||||
int num_domains;
|
||||
const struct rockchip_domain_info *domain_info;
|
||||
};
|
||||
|
||||
struct rockchip_pm_domain {
|
||||
struct generic_pm_domain genpd;
|
||||
const struct rockchip_domain_info *info;
|
||||
struct rockchip_pmu *pmu;
|
||||
int num_clks;
|
||||
struct clk *clks[];
|
||||
};
|
||||
|
||||
struct rockchip_pmu {
|
||||
struct device *dev;
|
||||
struct regmap *regmap;
|
||||
const struct rockchip_pmu_info *info;
|
||||
struct mutex mutex; /* mutex lock for pmu */
|
||||
struct genpd_onecell_data genpd_data;
|
||||
struct generic_pm_domain *domains[];
|
||||
};
|
||||
|
||||
#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
|
||||
|
||||
#define DOMAIN(pwr, status, req, idle, ack) \
|
||||
{ \
|
||||
.pwr_mask = BIT(pwr), \
|
||||
.status_mask = BIT(status), \
|
||||
.req_mask = BIT(req), \
|
||||
.idle_mask = BIT(idle), \
|
||||
.ack_mask = BIT(ack), \
|
||||
}
|
||||
|
||||
#define DOMAIN_RK3288(pwr, status, req) \
|
||||
DOMAIN(pwr, status, req, req, (req) + 16)
|
||||
|
||||
static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd)
|
||||
{
|
||||
struct rockchip_pmu *pmu = pd->pmu;
|
||||
const struct rockchip_domain_info *pd_info = pd->info;
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(pmu->regmap, pmu->info->idle_offset, &val);
|
||||
return (val & pd_info->idle_mask) == pd_info->idle_mask;
|
||||
}
|
||||
|
||||
static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd,
|
||||
bool idle)
|
||||
{
|
||||
const struct rockchip_domain_info *pd_info = pd->info;
|
||||
struct rockchip_pmu *pmu = pd->pmu;
|
||||
unsigned int val;
|
||||
|
||||
regmap_update_bits(pmu->regmap, pmu->info->req_offset,
|
||||
pd_info->req_mask, idle ? -1U : 0);
|
||||
|
||||
dsb(sy);
|
||||
|
||||
do {
|
||||
regmap_read(pmu->regmap, pmu->info->ack_offset, &val);
|
||||
} while ((val & pd_info->ack_mask) != (idle ? pd_info->ack_mask : 0));
|
||||
|
||||
while (rockchip_pmu_domain_is_idle(pd) != idle)
|
||||
cpu_relax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd)
|
||||
{
|
||||
struct rockchip_pmu *pmu = pd->pmu;
|
||||
unsigned int val;
|
||||
|
||||
regmap_read(pmu->regmap, pmu->info->status_offset, &val);
|
||||
|
||||
/* 1'b0: power on, 1'b1: power off */
|
||||
return !(val & pd->info->status_mask);
|
||||
}
|
||||
|
||||
static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd,
|
||||
bool on)
|
||||
{
|
||||
struct rockchip_pmu *pmu = pd->pmu;
|
||||
|
||||
regmap_update_bits(pmu->regmap, pmu->info->pwr_offset,
|
||||
pd->info->pwr_mask, on ? 0 : -1U);
|
||||
|
||||
dsb(sy);
|
||||
|
||||
while (rockchip_pmu_domain_is_on(pd) != on)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&pd->pmu->mutex);
|
||||
|
||||
if (rockchip_pmu_domain_is_on(pd) != power_on) {
|
||||
for (i = 0; i < pd->num_clks; i++)
|
||||
clk_enable(pd->clks[i]);
|
||||
|
||||
if (!power_on) {
|
||||
/* FIXME: add code to save AXI_QOS */
|
||||
|
||||
/* if powering down, idle request to NIU first */
|
||||
rockchip_pmu_set_idle_request(pd, true);
|
||||
}
|
||||
|
||||
rockchip_do_pmu_set_power_domain(pd, power_on);
|
||||
|
||||
if (power_on) {
|
||||
/* if powering up, leave idle mode */
|
||||
rockchip_pmu_set_idle_request(pd, false);
|
||||
|
||||
/* FIXME: add code to restore AXI_QOS */
|
||||
}
|
||||
|
||||
for (i = pd->num_clks - 1; i >= 0; i--)
|
||||
clk_disable(pd->clks[i]);
|
||||
}
|
||||
|
||||
mutex_unlock(&pd->pmu->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_pd_power_on(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
|
||||
|
||||
return rockchip_pd_power(pd, true);
|
||||
}
|
||||
|
||||
static int rockchip_pd_power_off(struct generic_pm_domain *domain)
|
||||
{
|
||||
struct rockchip_pm_domain *pd = to_rockchip_pd(domain);
|
||||
|
||||
return rockchip_pd_power(pd, false);
|
||||
}
|
||||
|
||||
static int rockchip_pd_attach_dev(struct generic_pm_domain *genpd,
|
||||
struct device *dev)
|
||||
{
|
||||
struct clk *clk;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
dev_dbg(dev, "attaching to power domain '%s'\n", genpd->name);
|
||||
|
||||
error = pm_clk_create(dev);
|
||||
if (error) {
|
||||
dev_err(dev, "pm_clk_create failed %d\n", error);
|
||||
return error;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while ((clk = of_clk_get(dev->of_node, i++)) && !IS_ERR(clk)) {
|
||||
dev_dbg(dev, "adding clock '%pC' to list of PM clocks\n", clk);
|
||||
error = pm_clk_add_clk(dev, clk);
|
||||
if (error) {
|
||||
dev_err(dev, "pm_clk_add_clk failed %d\n", error);
|
||||
clk_put(clk);
|
||||
pm_clk_destroy(dev);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
|
||||
struct device *dev)
|
||||
{
|
||||
dev_dbg(dev, "detaching from power domain '%s'\n", genpd->name);
|
||||
|
||||
pm_clk_destroy(dev);
|
||||
}
|
||||
|
||||
static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
||||
struct device_node *node)
|
||||
{
|
||||
const struct rockchip_domain_info *pd_info;
|
||||
struct rockchip_pm_domain *pd;
|
||||
struct clk *clk;
|
||||
int clk_cnt;
|
||||
int i;
|
||||
u32 id;
|
||||
int error;
|
||||
|
||||
error = of_property_read_u32(node, "reg", &id);
|
||||
if (error) {
|
||||
dev_err(pmu->dev,
|
||||
"%s: failed to retrieve domain id (reg): %d\n",
|
||||
node->name, error);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (id >= pmu->info->num_domains) {
|
||||
dev_err(pmu->dev, "%s: invalid domain id %d\n",
|
||||
node->name, id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pd_info = &pmu->info->domain_info[id];
|
||||
if (!pd_info) {
|
||||
dev_err(pmu->dev, "%s: undefined domain id %d\n",
|
||||
node->name, id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
clk_cnt = of_count_phandle_with_args(node, "clocks", "#clock-cells");
|
||||
pd = devm_kzalloc(pmu->dev,
|
||||
sizeof(*pd) + clk_cnt * sizeof(pd->clks[0]),
|
||||
GFP_KERNEL);
|
||||
if (!pd)
|
||||
return -ENOMEM;
|
||||
|
||||
pd->info = pd_info;
|
||||
pd->pmu = pmu;
|
||||
|
||||
for (i = 0; i < clk_cnt; i++) {
|
||||
clk = of_clk_get(node, i);
|
||||
if (IS_ERR(clk)) {
|
||||
error = PTR_ERR(clk);
|
||||
dev_err(pmu->dev,
|
||||
"%s: failed to get clk %pC (index %d): %d\n",
|
||||
node->name, clk, i, error);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
error = clk_prepare(clk);
|
||||
if (error) {
|
||||
dev_err(pmu->dev,
|
||||
"%s: failed to prepare clk %pC (index %d): %d\n",
|
||||
node->name, clk, i, error);
|
||||
clk_put(clk);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
pd->clks[pd->num_clks++] = clk;
|
||||
|
||||
dev_dbg(pmu->dev, "added clock '%pC' to domain '%s'\n",
|
||||
clk, node->name);
|
||||
}
|
||||
|
||||
error = rockchip_pd_power(pd, true);
|
||||
if (error) {
|
||||
dev_err(pmu->dev,
|
||||
"failed to power on domain '%s': %d\n",
|
||||
node->name, error);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
pd->genpd.name = node->name;
|
||||
pd->genpd.power_off = rockchip_pd_power_off;
|
||||
pd->genpd.power_on = rockchip_pd_power_on;
|
||||
pd->genpd.attach_dev = rockchip_pd_attach_dev;
|
||||
pd->genpd.detach_dev = rockchip_pd_detach_dev;
|
||||
pd->genpd.flags = GENPD_FLAG_PM_CLK;
|
||||
pm_genpd_init(&pd->genpd, NULL, false);
|
||||
|
||||
pmu->genpd_data.domains[id] = &pd->genpd;
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
while (--i >= 0) {
|
||||
clk_unprepare(pd->clks[i]);
|
||||
clk_put(pd->clks[i]);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pd->num_clks; i++) {
|
||||
clk_unprepare(pd->clks[i]);
|
||||
clk_put(pd->clks[i]);
|
||||
}
|
||||
|
||||
/* protect the zeroing of pm->num_clks */
|
||||
mutex_lock(&pd->pmu->mutex);
|
||||
pd->num_clks = 0;
|
||||
mutex_unlock(&pd->pmu->mutex);
|
||||
|
||||
/* devm will free our memory */
|
||||
}
|
||||
|
||||
static void rockchip_pm_domain_cleanup(struct rockchip_pmu *pmu)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
struct rockchip_pm_domain *pd;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pmu->genpd_data.num_domains; i++) {
|
||||
genpd = pmu->genpd_data.domains[i];
|
||||
if (genpd) {
|
||||
pd = to_rockchip_pd(genpd);
|
||||
rockchip_pm_remove_one_domain(pd);
|
||||
}
|
||||
}
|
||||
|
||||
/* devm will free our memory */
|
||||
}
|
||||
|
||||
static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu,
|
||||
u32 domain_reg_offset,
|
||||
unsigned int count)
|
||||
{
|
||||
/* First configure domain power down transition count ... */
|
||||
regmap_write(pmu->regmap, domain_reg_offset, count);
|
||||
/* ... and then power up count. */
|
||||
regmap_write(pmu->regmap, domain_reg_offset + 4, count);
|
||||
}
|
||||
|
||||
static int rockchip_pm_domain_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct device_node *node;
|
||||
struct device *parent;
|
||||
struct rockchip_pmu *pmu;
|
||||
const struct of_device_id *match;
|
||||
const struct rockchip_pmu_info *pmu_info;
|
||||
int error;
|
||||
|
||||
if (!np) {
|
||||
dev_err(dev, "device tree node not found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
match = of_match_device(dev->driver->of_match_table, dev);
|
||||
if (!match || !match->data) {
|
||||
dev_err(dev, "missing pmu data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pmu_info = match->data;
|
||||
|
||||
pmu = devm_kzalloc(dev,
|
||||
sizeof(*pmu) +
|
||||
pmu_info->num_domains * sizeof(pmu->domains[0]),
|
||||
GFP_KERNEL);
|
||||
if (!pmu)
|
||||
return -ENOMEM;
|
||||
|
||||
pmu->dev = &pdev->dev;
|
||||
mutex_init(&pmu->mutex);
|
||||
|
||||
pmu->info = pmu_info;
|
||||
|
||||
pmu->genpd_data.domains = pmu->domains;
|
||||
pmu->genpd_data.num_domains = pmu_info->num_domains;
|
||||
|
||||
parent = dev->parent;
|
||||
if (!parent) {
|
||||
dev_err(dev, "no parent for syscon devices\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
pmu->regmap = syscon_node_to_regmap(parent->of_node);
|
||||
|
||||
/*
|
||||
* Configure power up and down transition delays for CORE
|
||||
* and GPU domains.
|
||||
*/
|
||||
rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset,
|
||||
pmu_info->core_power_transition_time);
|
||||
rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset,
|
||||
pmu_info->gpu_power_transition_time);
|
||||
|
||||
error = -ENODEV;
|
||||
|
||||
for_each_available_child_of_node(np, node) {
|
||||
error = rockchip_pm_add_one_domain(pmu, node);
|
||||
if (error) {
|
||||
dev_err(dev, "failed to handle node %s: %d\n",
|
||||
node->name, error);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
if (error) {
|
||||
dev_dbg(dev, "no power domains defined\n");
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
of_genpd_add_provider_onecell(np, &pmu->genpd_data);
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
rockchip_pm_domain_cleanup(pmu);
|
||||
return error;
|
||||
}
|
||||
|
||||
static const struct rockchip_domain_info rk3288_pm_domains[] = {
|
||||
[RK3288_PD_VIO] = DOMAIN_RK3288(7, 7, 4),
|
||||
[RK3288_PD_HEVC] = DOMAIN_RK3288(14, 10, 9),
|
||||
[RK3288_PD_VIDEO] = DOMAIN_RK3288(8, 8, 3),
|
||||
[RK3288_PD_GPU] = DOMAIN_RK3288(9, 9, 2),
|
||||
};
|
||||
|
||||
static const struct rockchip_pmu_info rk3288_pmu = {
|
||||
.pwr_offset = 0x08,
|
||||
.status_offset = 0x0c,
|
||||
.req_offset = 0x10,
|
||||
.idle_offset = 0x14,
|
||||
.ack_offset = 0x14,
|
||||
|
||||
.core_pwrcnt_offset = 0x34,
|
||||
.gpu_pwrcnt_offset = 0x3c,
|
||||
|
||||
.core_power_transition_time = 24, /* 1us */
|
||||
.gpu_power_transition_time = 24, /* 1us */
|
||||
|
||||
.num_domains = ARRAY_SIZE(rk3288_pm_domains),
|
||||
.domain_info = rk3288_pm_domains,
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_pm_domain_dt_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3288-power-controller",
|
||||
.data = (void *)&rk3288_pmu,
|
||||
},
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
|
||||
static struct platform_driver rockchip_pm_domain_driver = {
|
||||
.probe = rockchip_pm_domain_probe,
|
||||
.driver = {
|
||||
.name = "rockchip-pm-domain",
|
||||
.of_match_table = rockchip_pm_domain_dt_match,
|
||||
/*
|
||||
* We can't forcibly eject devices form power domain,
|
||||
* so we can't really remove power domains once they
|
||||
* were added.
|
||||
*/
|
||||
.suppress_bind_attrs = true,
|
||||
},
|
||||
};
|
||||
|
||||
static int __init rockchip_pm_domain_drv_register(void)
|
||||
{
|
||||
return platform_driver_register(&rockchip_pm_domain_driver);
|
||||
}
|
||||
postcore_initcall(rockchip_pm_domain_drv_register);
|
31
include/dt-bindings/power/rk3288-power.h
Normal file
31
include/dt-bindings/power/rk3288-power.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef __DT_BINDINGS_POWER_RK3288_POWER_H__
|
||||
#define __DT_BINDINGS_POWER_RK3288_POWER_H__
|
||||
|
||||
/**
|
||||
* RK3288 Power Domain and Voltage Domain Summary.
|
||||
*/
|
||||
|
||||
/* VD_CORE */
|
||||
#define RK3288_PD_A17_0 0
|
||||
#define RK3288_PD_A17_1 1
|
||||
#define RK3288_PD_A17_2 2
|
||||
#define RK3288_PD_A17_3 3
|
||||
#define RK3288_PD_SCU 4
|
||||
#define RK3288_PD_DEBUG 5
|
||||
#define RK3288_PD_MEM 6
|
||||
|
||||
/* VD_LOGIC */
|
||||
#define RK3288_PD_BUS 7
|
||||
#define RK3288_PD_PERI 8
|
||||
#define RK3288_PD_VIO 9
|
||||
#define RK3288_PD_ALIVE 10
|
||||
#define RK3288_PD_HEVC 11
|
||||
#define RK3288_PD_VIDEO 12
|
||||
|
||||
/* VD_GPU */
|
||||
#define RK3288_PD_GPU 13
|
||||
|
||||
/* VD_PMU */
|
||||
#define RK3288_PD_PMU 14
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user