power: add the power domain control API [1/1]

PD#SWPL-17563

Problem:
add power domain control API for TM2 and SM1

Solution:
add power domain control API for TM2 and SM1

Verify:
T962E2

Change-Id: I2587b2b554281ee7c81d77e8978a2640e5f73be5
Signed-off-by: zhiqiang liang <zhiqiang.liang@amlogic.com>
Signed-off-by: chunlong.cao <chunlong.cao@amlogic.com>
This commit is contained in:
zhiqiang liang
2019-11-28 15:30:30 +08:00
committed by Chris
parent bee0d8b36b
commit 7b1af7284f
10 changed files with 722 additions and 16 deletions

View File

@@ -0,0 +1,32 @@
Amlogic power domain controller
==============================
The Amlogic Meson SoCs embeds an internal Power domain controller.
Power Domain
----------------
There are many power domains controlled by this power controller.
The bindings must respect the power domain bindings as described in the file
power_domain.txt
Device Tree Bindings:
---------------------
Required properties:
- compatible:
Example:
-------
pwrdm: power-domains {
compatible = "amlogic,tm2-power-domain";
status = "okay";
};
pwrdm: power-domains {
compatible = "amlogic,sm1-power-domain";
status = "okay";
};

View File

@@ -15231,3 +15231,19 @@ F: arch/arm64/boot/dts/amlogic/tm2_t962x3_ab301_drm.dts
F: arch/arm64/boot/dts/amlogic/tm2_t962e2_ab311_drm.dts
F: arch/arm64/boot/dts/amlogic/mesontm2_drm.dtsi
F: arch/arm/boot/dts/amlogic/mesontm2_drm.dtsi
AMLOGIC TM2 C4A SBR DTS
M: Bing Jiang <Bing.Jiang@amlogic.com>
F: arch/arm/boot/dts/amlogic/partition_sbr_gva.dtsi
F: arch/arm/boot/dts/amlogic/tm2_t962e2_ab311_gva_sbr.dts
F: arch/arm64/boot/dts/amlogic/partition_sbr_gva.dtsi
F: arch/arm64/boot/dts/amlogic/tm2_t962e2_ab311_gva_sbr.dts
AMLOGIC V4L HEADFILE
M: Nanxin Qin <Nanxin.Qin@amlogic.com>
F: include/linux/amlogic/media/video_sink/v4lvideo_ext.h
AMLOGIC POWER DOMAIN DRIVER
M: Zhiqiang Liang <zhiqiang.liang@amlogic.com>
F: drivers/amlogic/power/power_domain.c

View File

@@ -495,10 +495,15 @@
reg = <0xff809000 0x48>;
};
power_ctrl: power_ctrl@ff8000e8 {
compatible = "amlogic, sm1-powerctrl";
reg = <0xff8000e8 0x10>,
<0xff63c100 0x10>;
pwrdm: power-domains {
compatible = "amlogic,sm1-power-domain";
reg = <0xff62fc00 0xf0>,
<0xff8000e8 0x10>,
<0xff63c100 0x40>,
<0xffd01080 0x20>;
vpu_mempd_reg3 = <0xc>;
vpu_mempd_reg4 = <0x10>;
status = "okay";
};
bl40: bl40 {

View File

@@ -628,10 +628,15 @@
quality = /bits/ 16 <1000>;
};
power_ctrl: power_ctrl@ff8000e8 {
compatible = "amlogic, sm1-powerctrl";
reg = <0xff8000e8 0x10>,
<0xff63c100 0x10>;
pwrdm: power-domains {
compatible = "amlogic,tm2-power-domain";
reg = <0xff62fc00 0xd0>,
<0xff8000e8 0x10>,
<0xff63c100 0x40>,
<0xffd01080 0x20>;
vpu_mempd_reg3 = <0x38>;
vpu_mempd_reg4 = <0x30>;
status = "okay";
};
soc {

View File

@@ -495,10 +495,15 @@
reg = <0x0 0xff809000 0x0 0x48>;
};
power_ctrl: power_ctrl@ff8000e8 {
compatible = "amlogic, sm1-powerctrl";
reg = <0x0 0xff8000e8 0x0 0x10>,
<0x0 0xff63c100 0x0 0x10>;
pwrdm: power-domains {
compatible = "amlogic,sm1-power-domain";
reg = <0x0 0xff62fc00 0x0 0xf0>,
<0x0 0xff8000e8 0x0 0x10>,
<0x0 0xff63c100 0x0 0x40>,
<0x0 0xffd01080 0x0 0x20>;
vpu_mempd_reg3 = <0xc>;
vpu_mempd_reg4 = <0x10>;
status = "okay";
};
bl40: bl40 {

View File

@@ -627,10 +627,15 @@
quality = /bits/ 16 <1000>;
};
power_ctrl: power_ctrl@ff8000e8 {
compatible = "amlogic, sm1-powerctrl";
reg = <0x0 0xff8000e8 0x0 0x10>,
<0x0 0xff63c100 0x0 0x10>;
pwrdm: power-domains {
compatible = "amlogic,tm2-power-domain";
reg = <0x0 0xff62fc00 0x0 0xd0>,
<0x0 0xff8000e8 0x0 0x10>,
<0x0 0xff63c100 0x0 0x40>,
<0x0 0xffd01080 0x0 0x20>;
vpu_mempd_reg3 = <0x38>;
vpu_mempd_reg4 = <0x30>;
status = "okay";
};
soc {

View File

@@ -4,3 +4,4 @@ obj-$(CONFIG_AMLOGIC_PMU_OF) += aml_pmu_of_common.o
obj-$(CONFIG_AMLOGIC_M8B_DVFS) += aml_dvfs/
obj-$(CONFIG_AMLOGIC_POWER) += power_ctrl.o
obj-$(CONFIG_AMLOGIC_POWER) += power_domain.o

View File

@@ -0,0 +1,596 @@
/*
* drivers/amlogic/power/power_domain.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/io.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/of_device.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/amlogic/power_domain.h>
#include <dt-bindings/power/amlogic,pd.h>
//dos reg
#define DOS_SW_RESET0 0x0
#define DOS_SW_RESET1 0x1c
#define DOS_SW_RESET3 0xd0
#define DOS_SW_RESET4 0xdc
#define DOS_MEM_PD_VDEC 0xc0
#define DOS_MEM_PD_HCODEC 0xc8
#define DOS_MEM_PD_HEVC 0xcc
#define DOS_MEM_PD_WAVE420L 0xe4
//ao reg
#define AO_RTI_GEN_PWR_SLEEP0 0x0
#define AO_RTI_GEN_PWR_ISO0 0x4
//mempd reg
#define HHI_MEM_PD_REG0 0x0
#define HHI_VPU_MEM_PD_REG0 0x4
#define HHI_VPU_MEM_PD_REG1 0x8
#define HHI_DEMOD_MEM_PD_REG 0xc
#define HHI_DSP_MEM_PD_REG0 0x10
#define HHI_NANOQ_MEM_PD_REG0 0x18
#define HHI_NANOQ_MEM_PD_REG1 0x1c
#define HHI_VPU_MEM_PD_REG2 0x34
//reset reg
#define RESET0_LEVEL 0x0
#define RESET1_LEVEL 0x4
#define RESET2_LEVEL 0x8
#define RESET3_LEVEL 0xc
#define RESET4_LEVEL 0x10
#define RESET5_LEVEL 0x14
#define RESET6_LEVEL 0x18
#define RESET7_LEVEL 0x1c
static u32 vpu_mem_pd_reg3;
static u32 vpu_mem_pd_reg4;
struct power_domains {
void __iomem *dos_addr;
void __iomem *ao_addr;
void __iomem *mempd_addr;
void __iomem *reset_addr;
/**used for power reg concurrent access protect **/
spinlock_t power_lock;
/**used for mempd reg concurrent access protect **/
spinlock_t mem_pd_lock;
/**used for reset reg concurrent access protect **/
spinlock_t reset_lock;
/**used for iso reg concurrent access protect **/
spinlock_t iso_lock;
};
static struct power_domains *s_pd;
static void power_switch(int pwr_domain, bool pwr_switch)
{
unsigned int value;
unsigned long flags;
spin_lock_irqsave(&s_pd->power_lock, flags);
value = readl(s_pd->ao_addr + AO_RTI_GEN_PWR_SLEEP0);
if (pwr_switch == PWR_ON)
value &= ~(1 << pwr_domain);
else
value |= (1 << pwr_domain);
writel(value, (s_pd->ao_addr + AO_RTI_GEN_PWR_SLEEP0));
spin_unlock_irqrestore(&s_pd->power_lock, flags);
}
static void mem_pd_switch(int pwr_domain, bool pwr_switch)
{
unsigned int value;
unsigned long flags;
spin_lock_irqsave(&s_pd->mem_pd_lock, flags);
if (pwr_switch == PWR_ON) {
switch (pwr_domain) {
case PM_DOS_HCODEC:
writel(0x0, (s_pd->dos_addr + DOS_MEM_PD_HCODEC));
break;
case PM_DOS_VDEC:
writel(0x0, (s_pd->dos_addr + DOS_MEM_PD_VDEC));
break;
case PM_DOS_HEVC:
writel(0x0, (s_pd->dos_addr + DOS_MEM_PD_HEVC));
break;
case PM_WAVE420L:
writel(0x0, (s_pd->dos_addr + DOS_MEM_PD_WAVE420L));
break;
case PM_CSI:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value &= ~(0x3 << 6);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_VPU:
writel(0x0, (s_pd->mempd_addr + HHI_VPU_MEM_PD_REG0));
writel(0x0, (s_pd->mempd_addr + HHI_VPU_MEM_PD_REG1));
writel(0x0, (s_pd->mempd_addr + HHI_VPU_MEM_PD_REG2));
writel(0x0, (s_pd->mempd_addr + vpu_mem_pd_reg3));
writel(0x0, (s_pd->mempd_addr + vpu_mem_pd_reg4));
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value &= ~(0xff << 8);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_NN:
writel(0x0, (s_pd->mempd_addr + HHI_NANOQ_MEM_PD_REG0));
writel(0x0, (s_pd->mempd_addr + HHI_NANOQ_MEM_PD_REG1));
break;
case PM_USB:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value &= ~(0x3 << 30);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_PCIE0:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value &= ~(0xf << 26);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_GE2D:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value &= ~(0xff << 18);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_PCIE1:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value &= ~(0xf << 4);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_DSPA:
value = readl(s_pd->mempd_addr + HHI_DSP_MEM_PD_REG0);
value &= ~(0xffff);
writel(value, (s_pd->mempd_addr + HHI_DSP_MEM_PD_REG0));
break;
case PM_DSPB:
value = readl(s_pd->mempd_addr + HHI_DSP_MEM_PD_REG0);
value &= ~(0xffff << 16);
writel(value, (s_pd->mempd_addr + HHI_DSP_MEM_PD_REG0));
break;
case PM_DEMOD:
value = readl(s_pd->mempd_addr + HHI_DEMOD_MEM_PD_REG);
value &= ~0x2fff;
writel(value, (s_pd->mempd_addr +
HHI_DEMOD_MEM_PD_REG));
break;
}
} else {
switch (pwr_domain) {
case PM_DOS_HCODEC:
writel(0xffffffff, (s_pd->dos_addr +
DOS_MEM_PD_HCODEC));
break;
case PM_DOS_VDEC:
writel(0xffffffff, (s_pd->dos_addr + DOS_MEM_PD_VDEC));
break;
case PM_DOS_HEVC:
writel(0xffffffff, (s_pd->dos_addr + DOS_MEM_PD_HEVC));
break;
case PM_WAVE420L:
writel(0xffffffff, (s_pd->dos_addr +
DOS_MEM_PD_WAVE420L));
break;
case PM_CSI:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value |= (0x3 << 6);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_VPU:
writel(0xffffffff, (s_pd->mempd_addr +
HHI_VPU_MEM_PD_REG0));
writel(0xffffffff, (s_pd->mempd_addr +
HHI_VPU_MEM_PD_REG1));
writel(0xffffffff, (s_pd->mempd_addr +
HHI_VPU_MEM_PD_REG2));
writel(0xffffffff, (s_pd->mempd_addr +
vpu_mem_pd_reg3));
writel(0xffffffff, (s_pd->mempd_addr +
vpu_mem_pd_reg4));
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value |= (0xff << 8);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_NN:
writel(0xffffffff, (s_pd->mempd_addr +
HHI_NANOQ_MEM_PD_REG0));
writel(0xffffffff, (s_pd->mempd_addr +
HHI_NANOQ_MEM_PD_REG1));
break;
case PM_USB:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value |= (0x3 << 30);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_PCIE0:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value |= (0xf << 26);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_GE2D:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value |= (0xff << 18);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_PCIE1:
value = readl(s_pd->mempd_addr + HHI_MEM_PD_REG0);
value |= (0xf << 4);
writel(value, (s_pd->mempd_addr + HHI_MEM_PD_REG0));
break;
case PM_DSPA:
value = readl(s_pd->mempd_addr + HHI_DSP_MEM_PD_REG0);
value |= (0xffff);
writel(value, (s_pd->mempd_addr + HHI_DSP_MEM_PD_REG0));
break;
case PM_DSPB:
value = readl(s_pd->mempd_addr + HHI_DSP_MEM_PD_REG0);
value |= (0xffff << 16);
writel(value, (s_pd->mempd_addr + HHI_DSP_MEM_PD_REG0));
break;
case PM_DEMOD:
value = readl(s_pd->mempd_addr + HHI_DEMOD_MEM_PD_REG);
value |= 0x2fff;
writel(value, (s_pd->mempd_addr +
HHI_DEMOD_MEM_PD_REG));
break;
}
}
spin_unlock_irqrestore(&s_pd->mem_pd_lock, flags);
}
static void reset_switch(int pwr_domain, bool pwr_switch)
{
unsigned int value;
unsigned int tmp;
unsigned long flags;
spin_lock_irqsave(&s_pd->reset_lock, flags);
if (pwr_switch == PWR_ON) {
switch (pwr_domain) {
case PM_DOS_HCODEC:
value = readl(s_pd->dos_addr + DOS_SW_RESET1);
value &= ~(0xffff << 2);
writel(value, (s_pd->dos_addr + DOS_SW_RESET1));
break;
case PM_DOS_VDEC:
value = readl(s_pd->dos_addr + DOS_SW_RESET0);
value &= ~(0x1fff << 2);
writel(value, (s_pd->dos_addr + DOS_SW_RESET0));
break;
case PM_DOS_HEVC:
value = readl(s_pd->dos_addr + DOS_SW_RESET3);
value &= ~(0x3ffff << 2 | 1 << 24);
writel(value, (s_pd->dos_addr + DOS_SW_RESET3));
break;
case PM_WAVE420L:
value = readl(s_pd->dos_addr + DOS_SW_RESET4);
value &= ~(0xf << 8);
writel(value, (s_pd->dos_addr + DOS_SW_RESET4));
break;
case PM_VPU:
tmp = 0x1 << 5 | 0x1 << 10 | 0x1 << 19 | 0x1 << 13;
value = readl(s_pd->reset_addr + RESET0_LEVEL);
value |= tmp;
writel(value, (s_pd->reset_addr + RESET0_LEVEL));
tmp = 0x1 << 5 | 0x1 << 4;
value = readl(s_pd->reset_addr + RESET1_LEVEL);
value |= tmp;
writel(value, (s_pd->reset_addr + RESET1_LEVEL));
tmp = 0x1 << 15;
value = readl(s_pd->reset_addr + RESET2_LEVEL);
value |= tmp;
writel(value, (s_pd->reset_addr + RESET2_LEVEL));
tmp = 0x1 << 6 | 0x1 << 7 | 0x1 << 13 |
0x1 << 5 | 0x1 << 9 | 0x1 << 4 | 0x1 << 12;
value = readl(s_pd->reset_addr + RESET4_LEVEL);
value |= tmp;
writel(value, (s_pd->reset_addr + RESET4_LEVEL));
tmp = 0x1 << 7;
value = readl(s_pd->reset_addr + RESET7_LEVEL);
value |= tmp;
writel(value, (s_pd->reset_addr + RESET7_LEVEL));
break;
case PM_NN:
value = readl(s_pd->reset_addr + RESET2_LEVEL);
value |= (0x1 << 12);
writel(value, (s_pd->reset_addr + RESET2_LEVEL));
break;
case PM_USB:
value = readl(s_pd->reset_addr + RESET1_LEVEL);
value |= (0x1 << 2);
writel(value, (s_pd->reset_addr + RESET1_LEVEL));
break;
case PM_PCIE0:
value = readl(s_pd->reset_addr + RESET0_LEVEL);
value |= ((0x1 << 12) | (0x3 << 14));
writel(value, (s_pd->reset_addr + RESET0_LEVEL));
break;
case PM_GE2D:
value = readl(s_pd->reset_addr + RESET2_LEVEL);
value |= (0x1 << 6);
writel(value, (s_pd->reset_addr + RESET2_LEVEL));
break;
case PM_PCIE1:
value = readl(s_pd->reset_addr + RESET0_LEVEL);
value |= (0x7 << 28);
writel(value, (s_pd->reset_addr + RESET0_LEVEL));
break;
case PM_DSPA:
value = readl(s_pd->reset_addr + RESET4_LEVEL);
value |= 0x1;
writel(value, (s_pd->reset_addr + RESET4_LEVEL));
value = readl(s_pd->reset_addr + RESET1_LEVEL);
value |= (0x1 << 20);
writel(value, (s_pd->reset_addr + RESET1_LEVEL));
break;
case PM_DSPB:
value = readl(s_pd->reset_addr + RESET4_LEVEL);
value |= (0x1 << 1);
writel(value, (s_pd->reset_addr + RESET4_LEVEL));
value = readl(s_pd->reset_addr + RESET1_LEVEL);
value |= (0x1 << 21);
writel(value, (s_pd->reset_addr + RESET1_LEVEL));
break;
case PM_DEMOD:
value = readl(s_pd->reset_addr + RESET0_LEVEL);
value |= (0x1 << 8);
writel(value, (s_pd->reset_addr + RESET0_LEVEL));
break;
}
} else {
switch (pwr_domain) {
case PM_DOS_HCODEC:
value = readl(s_pd->dos_addr + DOS_SW_RESET1);
value |= (0xffff << 2);
writel(value, (s_pd->dos_addr + DOS_SW_RESET1));
break;
case PM_DOS_VDEC:
value = readl(s_pd->dos_addr + DOS_SW_RESET0);
value |= (0x1fff << 2);
writel(value, (s_pd->dos_addr + DOS_SW_RESET0));
break;
case PM_DOS_HEVC:
value = readl(s_pd->dos_addr + DOS_SW_RESET3);
value |= (0x3ffff << 2 | 1 << 24);
writel(value, (s_pd->dos_addr + DOS_SW_RESET3));
break;
case PM_WAVE420L:
value = readl(s_pd->dos_addr + DOS_SW_RESET4);
value |= (0xf << 8);
writel(value, (s_pd->dos_addr + DOS_SW_RESET4));
break;
case PM_VPU:
tmp = 0x1 << 5 | 0x1 << 10 | 0x1 << 19 | 0x1 << 13;
value = readl(s_pd->reset_addr + RESET0_LEVEL);
value &= ~tmp;
writel(value, (s_pd->reset_addr + RESET0_LEVEL));
tmp = 0x1 << 5 | 0x1 << 4;
value = readl(s_pd->reset_addr + RESET1_LEVEL);
value &= ~tmp;
writel(value, (s_pd->reset_addr + RESET1_LEVEL));
tmp = 0x1 << 15;
value = readl(s_pd->reset_addr + RESET2_LEVEL);
value &= ~tmp;
writel(value, (s_pd->reset_addr + RESET2_LEVEL));
tmp = 0x1 << 6 | 0x1 << 7 | 0x1 << 13 |
0x1 << 5 | 0x1 << 9 | 0x1 << 4 | 0x1 << 12;
value = readl(s_pd->reset_addr + RESET4_LEVEL);
value &= ~tmp;
writel(value, (s_pd->reset_addr + RESET4_LEVEL));
tmp = 0x1 << 7;
value = readl(s_pd->reset_addr + RESET7_LEVEL);
value &= ~tmp;
writel(value, (s_pd->reset_addr + RESET7_LEVEL));
break;
case PM_NN:
value = readl(s_pd->reset_addr + RESET2_LEVEL);
value &= ~(0x1 << 12);
writel(value, (s_pd->reset_addr + RESET2_LEVEL));
break;
case PM_USB:
value = readl(s_pd->reset_addr + RESET1_LEVEL);
value &= ~(0x1 << 2);
writel(value, (s_pd->reset_addr + RESET1_LEVEL));
break;
case PM_PCIE0:
value = readl(s_pd->reset_addr + RESET0_LEVEL);
value &= ~((0x1 << 12) | (0x3 << 14));
writel(value, (s_pd->reset_addr + RESET0_LEVEL));
break;
case PM_GE2D:
value = readl(s_pd->reset_addr + RESET2_LEVEL);
value &= ~(0x1 << 6);
writel(value, (s_pd->reset_addr + RESET2_LEVEL));
break;
case PM_PCIE1:
value = readl(s_pd->reset_addr + RESET0_LEVEL);
value &= ~(0x7 << 28);
writel(value, (s_pd->reset_addr + RESET0_LEVEL));
break;
case PM_DSPA:
value = readl(s_pd->reset_addr + RESET4_LEVEL);
value &= ~0x1;
writel(value, (s_pd->reset_addr + RESET4_LEVEL));
value = readl(s_pd->reset_addr + RESET1_LEVEL);
value &= ~(0x1 << 20);
writel(value, (s_pd->reset_addr + RESET1_LEVEL));
break;
case PM_DSPB:
value = readl(s_pd->reset_addr + RESET4_LEVEL);
value &= ~(0x1 << 1);
writel(value, (s_pd->reset_addr + RESET4_LEVEL));
value = readl(s_pd->reset_addr + RESET1_LEVEL);
value &= ~(0x1 << 21);
writel(value, (s_pd->reset_addr + RESET1_LEVEL));
break;
case PM_DEMOD:
value = readl(s_pd->reset_addr + RESET0_LEVEL);
value &= ~(0x1 << 8);
writel(value, (s_pd->reset_addr + RESET0_LEVEL));
break;
}
}
spin_unlock_irqrestore(&s_pd->reset_lock, flags);
}
static void iso_switch(int pwr_domain, bool pwr_switch)
{
unsigned int value;
unsigned long flags;
spin_lock_irqsave(&s_pd->iso_lock, flags);
value = readl(s_pd->ao_addr + AO_RTI_GEN_PWR_ISO0);
if (pwr_switch == PWR_ON)
value &= ~(1 << pwr_domain);
else
value |= (1 << pwr_domain);
writel(value, (s_pd->ao_addr + AO_RTI_GEN_PWR_ISO0));
spin_unlock_irqrestore(&s_pd->iso_lock, flags);
}
void power_domain_switch(int pwr_domain, bool pwr_switch)
{
if (pwr_switch == PWR_ON) {
/* Powerup Power Domain */
power_switch(pwr_domain, PWR_ON);
usleep_range(40, 50);
/* Powerup memories */
mem_pd_switch(pwr_domain, PWR_ON);
usleep_range(100, 150);
reset_switch(pwr_domain, PWR_OFF);
/* remove isolations */
iso_switch(pwr_domain, PWR_ON);
/* deassert reset */
reset_switch(pwr_domain, PWR_ON);
} else {
/* reset */
reset_switch(pwr_domain, PWR_OFF);
/* add isolation to domain */
iso_switch(pwr_domain, PWR_OFF);
/* Power down memories */
mem_pd_switch(pwr_domain, PWR_OFF);
usleep_range(40, 50);
/* Power off domain */
power_switch(pwr_domain, PWR_OFF);
}
}
EXPORT_SYMBOL(power_domain_switch);
static int pd_probe(struct platform_device *pdev)
{
struct resource *res;
struct power_domains *power_domains;
int ret;
u32 offset;
power_domains = devm_kzalloc(&pdev->dev, sizeof(*power_domains),
GFP_KERNEL);
if (!power_domains)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "Fail to get dos addr res\n");
return -ENXIO;
}
power_domains->dos_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(power_domains->dos_addr))
return PTR_ERR(power_domains->dos_addr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
dev_err(&pdev->dev, "Fail to get ao addr res\n");
return -ENXIO;
}
power_domains->ao_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(power_domains->ao_addr))
return PTR_ERR(power_domains->ao_addr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
if (!res) {
dev_err(&pdev->dev, "Fail to get mempd addr res\n");
return -ENXIO;
}
power_domains->mempd_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(power_domains->mempd_addr))
return PTR_ERR(power_domains->mempd_addr);
res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
if (!res) {
dev_err(&pdev->dev, "Fail to get reset addr res\n");
return -ENXIO;
}
power_domains->reset_addr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(power_domains->reset_addr))
return PTR_ERR(power_domains->reset_addr);
ret = of_property_read_u32(pdev->dev.of_node,
"vpu_mempd_reg3", &offset);
if (!ret) {
pr_info("vpu_mempd_reg3: 0x%x\n", offset);
vpu_mem_pd_reg3 = offset;
}
ret = of_property_read_u32(pdev->dev.of_node,
"vpu_mempd_reg4", &offset);
if (!ret) {
pr_info("vpu_mempd_reg4: 0x%x\n", offset);
vpu_mem_pd_reg4 = offset;
}
spin_lock_init(&power_domains->power_lock);
spin_lock_init(&power_domains->mem_pd_lock);
spin_lock_init(&power_domains->reset_lock);
spin_lock_init(&power_domains->iso_lock);
s_pd = power_domains;
return 0;
}
static const struct of_device_id pd_match_table[] = {
{ .compatible = "amlogic,tm2-power-domain", },
{ .compatible = "amlogic,sm1-power-domain", },
{}
};
static struct platform_driver pd_driver = {
.driver = {
.name = "amlogic,power-domain",
.of_match_table = pd_match_table,
},
.probe = pd_probe,
};
static int __init pd_init(void)
{
return platform_driver_register(&pd_driver);
}
arch_initcall(pd_init);

View File

@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#define PM_DOS_HCODEC 0
#define PM_DOS_VDEC 1
#define PM_DOS_HEVC 2
#define PM_WAVE420L 3
#define PM_CSI 6
#define PM_VPU 8
#define PM_NN 16
#define PM_USB 17
#define PM_PCIE0 18
#define PM_GE2D 19
#define PM_PCIE1 20
#define PM_DSPA 21
#define PM_DSPB 22
#define PM_DEMOD 23

View File

@@ -0,0 +1,22 @@
/*
* include/linux/amlogic/power_domain.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.
*
*/
#define PWR_ON 0
#define PWR_OFF 1
void power_domain_switch(int pwr_domain, bool pwr_switch);