mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
power: optimize the power consumption of vad wakeup [1/1]
PD#SWPL-3826 Problem: optimize the power consumption of tl1 with vad wakeup Solution: optimize the power consumption when enter freeze mode switch the clk81 to 24M cpu and dsu clk switch to gp1 pll,frequency is 600M closed the fixed pll closed the vddio_3.3V Verify: TL1 revB Change-Id: I39170bb8efb91b126b6a15faad3cefee19b13089 Signed-off-by: zhiqiang liang <zhiqiang.liang@amlogic.com> Signed-off-by: Jian Hu <jian.hu@amlogic.com> Signed-off-by: Hong Guo <hong.guo@amlogic.com>
This commit is contained in:
@@ -15153,3 +15153,8 @@ M: shunzhou jiang <shunzhou.jiang@amlogic.com>
|
||||
F: drivers/amlogic/firmware/bl40_module.c
|
||||
F: drivers/amlogic/firmware/Makefile
|
||||
F: drivers/amlogic/firmware/Kconfig
|
||||
|
||||
AMLOGIC VAD WAKEUP POWER
|
||||
M: Zhiqiang Liang <zhiqiang.liang@amlogic.com>
|
||||
F: drivers/amlogic/pm/vad_power.c
|
||||
F: drivers/amlogic/pm/vad_power.h
|
||||
|
||||
@@ -281,6 +281,16 @@
|
||||
device_name = "aml_pm";
|
||||
debug_reg = <0xff8000a8>;
|
||||
exit_reg = <0xff80023c>;
|
||||
dmc_asr = <0xff638634>;
|
||||
cpu_reg = <0xff63c19c>;
|
||||
clocks = <&clkc CLKID_SWITCH_CLK81>,
|
||||
<&clkc CLKID_CLK81>,
|
||||
<&clkc CLKID_FIXED_PLL>,
|
||||
<&xtal>;
|
||||
clock-names = "switch_clk81",
|
||||
"clk81",
|
||||
"fixed_pll",
|
||||
"xtal";
|
||||
};
|
||||
|
||||
cpuinfo {
|
||||
|
||||
@@ -1229,6 +1229,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
aml_pm {
|
||||
vad_wakeup_disable = <0x0>;
|
||||
vddio3v3_en = <&gpio_ao GPIOAO_2 0>;
|
||||
};
|
||||
|
||||
sd_emmc_b: sdio@ffe05000 {
|
||||
status = "okay";
|
||||
compatible = "amlogic, meson-mmc-tl1";
|
||||
|
||||
@@ -1330,6 +1330,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
aml_pm {
|
||||
vad_wakeup_disable = <0x0>;
|
||||
vddio3v3_en = <&gpio_ao GPIOAO_2 0>;
|
||||
};
|
||||
|
||||
/* sd_emmc_b: sd@ffe05000 {
|
||||
* status = "okay";
|
||||
* compatible = "amlogic, meson-mmc-tl1";
|
||||
|
||||
@@ -1323,6 +1323,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
aml_pm {
|
||||
vad_wakeup_disable = <0x0>;
|
||||
vddio3v3_en = <&gpio_ao GPIOAO_2 0>;
|
||||
};
|
||||
|
||||
/* sd_emmc_b: sd@ffe05000 {
|
||||
* status = "okay";
|
||||
* compatible = "amlogic, meson-mmc-tl1";
|
||||
|
||||
@@ -281,6 +281,16 @@
|
||||
device_name = "aml_pm";
|
||||
debug_reg = <0xff8000a8>;
|
||||
exit_reg = <0xff80023c>;
|
||||
dmc_asr = <0xff638634>;
|
||||
cpu_reg = <0xff63c19c>;
|
||||
clocks = <&clkc CLKID_SWITCH_CLK81>,
|
||||
<&clkc CLKID_CLK81>,
|
||||
<&clkc CLKID_FIXED_PLL>,
|
||||
<&xtal>;
|
||||
clock-names = "switch_clk81",
|
||||
"clk81",
|
||||
"fixed_pll",
|
||||
"xtal";
|
||||
};
|
||||
|
||||
cpuinfo {
|
||||
|
||||
@@ -1227,6 +1227,11 @@
|
||||
};
|
||||
};
|
||||
|
||||
aml_pm {
|
||||
vad_wakeup_disable = <0x0>;
|
||||
vddio3v3_en = <&gpio_ao GPIOAO_2 0>;
|
||||
};
|
||||
|
||||
sd_emmc_b: sdio@ffe05000 {
|
||||
status = "okay";
|
||||
compatible = "amlogic, meson-mmc-tl1";
|
||||
|
||||
@@ -1326,6 +1326,12 @@
|
||||
*/
|
||||
};
|
||||
};
|
||||
|
||||
aml_pm {
|
||||
vad_wakeup_disable = <0x0>;
|
||||
vddio3v3_en = <&gpio_ao GPIOAO_2 0>;
|
||||
};
|
||||
|
||||
/* sd_emmc_b: sd@ffe05000 {
|
||||
* status = "okay";
|
||||
* compatible = "amlogic, meson-mmc-tl1";
|
||||
|
||||
@@ -1318,6 +1318,12 @@
|
||||
*/
|
||||
};
|
||||
};
|
||||
|
||||
aml_pm {
|
||||
vad_wakeup_disable = <0x0>;
|
||||
vddio3v3_en = <&gpio_ao GPIOAO_2 0>;
|
||||
};
|
||||
|
||||
/* sd_emmc_b: sd@ffe05000 {
|
||||
* status = "okay";
|
||||
* compatible = "amlogic, meson-mmc-tl1";
|
||||
|
||||
@@ -1188,6 +1188,11 @@ static void __init tl1_clkc_init(struct device_node *np)
|
||||
goto iounmap;
|
||||
}
|
||||
|
||||
/* fixed pll init */
|
||||
ret = clk_prepare_enable(tl1_fixed_pll.hw.clk);
|
||||
if (ret)
|
||||
pr_err("%s, failed to init fixed pll\n", __func__);
|
||||
|
||||
ret = of_clk_add_provider(np, of_clk_src_onecell_get,
|
||||
&clk_data);
|
||||
if (ret < 0) {
|
||||
|
||||
@@ -499,6 +499,9 @@ static void meson_tl1_pll_disable(struct clk_hw *hw)
|
||||
if (pll->lock)
|
||||
spin_lock_irqsave(pll->lock, flags);
|
||||
|
||||
if (!strcmp(clk_hw_get_name(hw), "fixed_pll"))
|
||||
pr_warn("Pay Attention, fixed pll will be disabled\n");
|
||||
|
||||
writel(readl(pll->base + p->reg_off) | (MESON_PLL_RESET),
|
||||
pll->base + p->reg_off);
|
||||
writel(readl(pll->base + p->reg_off) & (~MESON_PLL_ENABLE),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
obj-$(CONFIG_AMLOGIC_LEGACY_EARLY_SUSPEND) += lgcy_early_suspend.o
|
||||
obj-$(CONFIG_AMLOGIC_GX_SUSPEND) += gx_pm.o
|
||||
obj-$(CONFIG_AMLOGIC_GX_SUSPEND) += vad_power.o
|
||||
obj-$(CONFIG_AMLOGIC_M8B_SUSPEND) += m8b_pm.o
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <linux/kobject.h>
|
||||
#include <../kernel/power/power.h>
|
||||
#include <linux/amlogic/scpi_protocol.h>
|
||||
#include "vad_power.h"
|
||||
|
||||
typedef unsigned long (psci_fn)(unsigned long, unsigned long,
|
||||
unsigned long, unsigned long);
|
||||
@@ -218,6 +219,8 @@ static int __init meson_pm_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device_node *cpu_node;
|
||||
struct device_node *state_node;
|
||||
struct pm_data *p_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
int count = 0, ret;
|
||||
u32 ver = psci_get_version();
|
||||
u32 paddr = 0;
|
||||
@@ -246,6 +249,14 @@ static int __init meson_pm_probe(struct platform_device *pdev)
|
||||
suspend_set_ops(&meson_gx_ops);
|
||||
}
|
||||
|
||||
p_data = devm_kzalloc(&pdev->dev, sizeof(struct pm_data), GFP_KERNEL);
|
||||
if (!p_data)
|
||||
return -ENOMEM;
|
||||
p_data->dev = dev;
|
||||
dev_set_drvdata(dev, p_data);
|
||||
|
||||
vad_wakeup_power_init(pdev, p_data);
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"debug_reg", &paddr);
|
||||
if (!ret) {
|
||||
@@ -280,6 +291,23 @@ uniomap:
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
int pm_suspend_noirq(struct device *dev)
|
||||
{
|
||||
vad_wakeup_power_suspend(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pm_resume_noirq(struct device *dev)
|
||||
{
|
||||
vad_wakeup_power_resume(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops meson_pm_noirq_ops = {
|
||||
.suspend_noirq = pm_suspend_noirq,
|
||||
.resume_noirq = pm_resume_noirq,
|
||||
};
|
||||
|
||||
static int meson_pm_remove(struct platform_device *pdev)
|
||||
{
|
||||
return 0;
|
||||
@@ -296,6 +324,7 @@ static struct platform_driver meson_pm_driver = {
|
||||
.name = "pm-meson",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = amlogic_pm_dt_match,
|
||||
.pm = &meson_pm_noirq_ops,
|
||||
},
|
||||
.probe = meson_pm_probe,
|
||||
.remove = meson_pm_remove,
|
||||
|
||||
217
drivers/amlogic/pm/vad_power.c
Normal file
217
drivers/amlogic/pm/vad_power.c
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* drivers/amlogic/pm/vad_power.c
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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/pm.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/amlogic/pm.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include "../../gpio/gpiolib.h"
|
||||
#include "vad_power.h"
|
||||
|
||||
#define IO3V3_EN "vddio3v3_en"
|
||||
|
||||
static int fixed_pll_cnt;
|
||||
|
||||
int vad_wakeup_power_init(struct platform_device *pdev, struct pm_data *p_data)
|
||||
{
|
||||
int ret;
|
||||
const char *value;
|
||||
struct gpio_desc *desc;
|
||||
u32 paddr = 0;
|
||||
|
||||
ret = of_property_read_string(pdev->dev.of_node, "vddio3v3_en", &value);
|
||||
if (ret) {
|
||||
pr_info("no vddio3v3_en pin");
|
||||
p_data->vddio3v3_en = 0;
|
||||
} else {
|
||||
desc = of_get_named_gpiod_flags(pdev->dev.of_node,
|
||||
"vddio3v3_en", 0, NULL);
|
||||
p_data->vddio3v3_en = desc_to_gpio(desc);
|
||||
}
|
||||
if (p_data->vddio3v3_en > 0)
|
||||
gpio_request(p_data->vddio3v3_en, IO3V3_EN);
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"vad_wakeup_disable", &paddr);
|
||||
if (!ret) {
|
||||
p_data->vad_wakeup_disable = paddr;
|
||||
pr_info("vad_wakeup_disable: 0x%x\n", paddr);
|
||||
} else {
|
||||
p_data->vad_wakeup_disable = 1;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"dmc_asr", &paddr);
|
||||
if (!ret) {
|
||||
pr_info("dmc_asr: 0x%x\n", paddr);
|
||||
p_data->dmc_asr = ioremap(paddr, 0x4);
|
||||
} else {
|
||||
p_data->dmc_asr = 0;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(pdev->dev.of_node,
|
||||
"cpu_reg", &paddr);
|
||||
if (!ret) {
|
||||
pr_info("cpu_reg: 0x%x\n", paddr);
|
||||
p_data->cpu_reg = ioremap(paddr, 0x4);
|
||||
} else {
|
||||
p_data->cpu_reg = 0;
|
||||
}
|
||||
|
||||
p_data->switch_clk81 = devm_clk_get(&pdev->dev, "switch_clk81");
|
||||
if (IS_ERR(p_data->switch_clk81)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Can't get switch_clk81\n");
|
||||
return PTR_ERR(p_data->switch_clk81);
|
||||
}
|
||||
p_data->clk81 = devm_clk_get(&pdev->dev, "clk81");
|
||||
if (IS_ERR(p_data->clk81)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Can't get clk81\n");
|
||||
return PTR_ERR(p_data->clk81);
|
||||
}
|
||||
p_data->xtal = devm_clk_get(&pdev->dev, "xtal");
|
||||
if (IS_ERR(p_data->xtal)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Can't get xtal\n");
|
||||
return PTR_ERR(p_data->xtal);
|
||||
}
|
||||
p_data->fixed_pll = devm_clk_get(&pdev->dev, "fixed_pll");
|
||||
if (IS_ERR(p_data->fixed_pll)) {
|
||||
dev_err(&pdev->dev,
|
||||
"Can't get fixed_pll\n");
|
||||
return PTR_ERR(p_data->fixed_pll);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cpu_clk_switch_to_gp1(unsigned int flag, void __iomem *paddr)
|
||||
{
|
||||
u32 control;
|
||||
u32 dyn_pre_mux = 0;
|
||||
u32 dyn_post_mux = 1;
|
||||
u32 dyn_div = 1;
|
||||
|
||||
control = readl(paddr);
|
||||
/*check cpu busy or not*/
|
||||
do {
|
||||
control = readl(paddr);
|
||||
} while (control & (1 << 28));
|
||||
|
||||
if (!flag) {
|
||||
dyn_pre_mux = 3;
|
||||
dyn_post_mux = 1;
|
||||
dyn_div = 1;
|
||||
/*cpu clk sel channel a*/
|
||||
if (control & (1 << 10)) {
|
||||
control = (control & ~((1 << 10) | (0x3f << 4)
|
||||
| (1 << 2) | (0x3 << 0)))
|
||||
| ((0 << 10)
|
||||
| (dyn_div << 4)
|
||||
| (dyn_post_mux << 2)
|
||||
| (dyn_pre_mux << 0));
|
||||
} else {
|
||||
/*cpu clk sel channel b*/
|
||||
control = (control & ~((1 << 10) | (0x3f << 20)
|
||||
| (1 << 18) | (0x3 << 16)))
|
||||
| ((1 << 10)
|
||||
| (dyn_div << 20)
|
||||
| (dyn_post_mux << 18)
|
||||
| (dyn_pre_mux << 16));
|
||||
}
|
||||
} else {
|
||||
if (control & (1 << 10))
|
||||
control = control & ~(1 << 10);
|
||||
else
|
||||
control = control | (1 << 10);
|
||||
}
|
||||
writel(control, paddr);
|
||||
}
|
||||
|
||||
int vad_wakeup_power_suspend(struct device *dev)
|
||||
{
|
||||
struct pm_data *p_data = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
if (!is_pm_freeze_mode() || p_data->vad_wakeup_disable)
|
||||
return 0;
|
||||
|
||||
clk_set_parent(p_data->switch_clk81, p_data->xtal);
|
||||
pr_info("switch clk81 to 24M.\n");
|
||||
|
||||
/*cpu clk switch to gp1*/
|
||||
cpu_clk_switch_to_gp1(0, p_data->cpu_reg);
|
||||
pr_info("cpu clk switch to gp1.\n");
|
||||
|
||||
fixed_pll_cnt = __clk_get_enable_count(p_data->fixed_pll);
|
||||
if (fixed_pll_cnt > 1)
|
||||
dev_warn(dev,
|
||||
"Now fixed pll enable count = %d\n",
|
||||
fixed_pll_cnt);
|
||||
|
||||
for (i = 0; i < fixed_pll_cnt; i++)
|
||||
clk_disable_unprepare(p_data->fixed_pll);
|
||||
|
||||
gpio_direction_output(p_data->vddio3v3_en, 0);
|
||||
pr_info("power off vddio_3v3.\n");
|
||||
|
||||
if (p_data->dmc_asr) {
|
||||
writel(0x3fe00, p_data->dmc_asr);
|
||||
pr_info("enable dmc asr\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vad_wakeup_power_resume(struct device *dev)
|
||||
{
|
||||
struct pm_data *p_data = dev_get_drvdata(dev);
|
||||
int i;
|
||||
|
||||
if (!is_pm_freeze_mode() || p_data->vad_wakeup_disable)
|
||||
return 0;
|
||||
|
||||
gpio_direction_output(p_data->vddio3v3_en, 1);
|
||||
pr_info("power on vddio_3v3.\n");
|
||||
|
||||
if (p_data->dmc_asr) {
|
||||
writel(0x0, p_data->dmc_asr);
|
||||
pr_info("disable dmc asr\n");
|
||||
}
|
||||
|
||||
/* enable fixed pll */
|
||||
for (i = 0; i < fixed_pll_cnt; i++) {
|
||||
if (clk_prepare_enable(p_data->fixed_pll))
|
||||
dev_err(dev, "failed to enable fixed pll\n");
|
||||
}
|
||||
|
||||
/*restore cpu clk*/
|
||||
cpu_clk_switch_to_gp1(1, p_data->cpu_reg);
|
||||
pr_info("cpu clk restore.\n");
|
||||
clk_set_parent(p_data->switch_clk81, p_data->clk81);
|
||||
pr_info("switch clk81 to 166M.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
33
drivers/amlogic/pm/vad_power.h
Normal file
33
drivers/amlogic/pm/vad_power.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* drivers/amlogic/pm/vad_power.h
|
||||
*
|
||||
* Copyright (C) 2017 Amlogic, Inc. 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 as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
struct pm_data {
|
||||
struct device *dev;
|
||||
int vddio3v3_en;
|
||||
bool vad_wakeup_disable;
|
||||
void __iomem *dmc_asr;
|
||||
void __iomem *cpu_reg;
|
||||
struct clk *switch_clk81;
|
||||
struct clk *clk81;
|
||||
struct clk *fixed_pll;
|
||||
struct clk *xtal;
|
||||
};
|
||||
|
||||
int vad_wakeup_power_init(struct platform_device *pdev, struct pm_data *p_data);
|
||||
int vad_wakeup_power_suspend(struct device *dev);
|
||||
int vad_wakeup_power_resume(struct device *dev);
|
||||
|
||||
Reference in New Issue
Block a user