summaryrefslogtreecommitdiff
path: root/arch/arm/mach-kirkwood/common.c
diff options
context:
space:
mode:
authorRabeeh Khoury <rabeeh@marvell.com>2009-03-22 17:30:32 +0200
committerNicolas Pitre <nico@cam.org>2009-06-08 13:04:58 -0400
commite8b2b7ba1200de8e50788e358e2d945a0c0fcfad (patch)
treedb48240d16d267bca6b740fe401406f9838410e3 /arch/arm/mach-kirkwood/common.c
parentfb7b2d3f0dda3fbd711c191fd3b9496653e81ac7 (diff)
[ARM] Kirkwood: clock gating for unused peripherals
To save power: 1. Enabling clock gating of unused peripherals 2. PLL and PHY of the units are also disabled (when possible. Signed-off-by: Rabeeh Khoury <rabeeh@marvell.com> Signed-off-by: Nicolas Pitre <nico@marvell.com>
Diffstat (limited to 'arch/arm/mach-kirkwood/common.c')
-rw-r--r--arch/arm/mach-kirkwood/common.c59
1 files changed, 59 insertions, 0 deletions
diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
index 6e3eb1a6a660..d127731f47dc 100644
--- a/arch/arm/mach-kirkwood/common.c
+++ b/arch/arm/mach-kirkwood/common.c
@@ -55,6 +55,13 @@ void __init kirkwood_map_io(void)
iotable_init(kirkwood_io_desc, ARRAY_SIZE(kirkwood_io_desc));
}
+/*
+ * Default clock control bits. Any bit _not_ set in this variable
+ * will be cleared from the hardware after platform devices have been
+ * registered. Some reserved bits must be set to 1.
+ */
+unsigned int kirkwood_clk_ctrl = CGC_DUNIT | CGC_RESERVED;
+
/*****************************************************************************
* EHCI
@@ -96,6 +103,7 @@ static struct platform_device kirkwood_ehci = {
void __init kirkwood_ehci_init(void)
{
+ kirkwood_clk_ctrl |= CGC_USB0;
platform_device_register(&kirkwood_ehci);
}
@@ -152,6 +160,7 @@ static struct platform_device kirkwood_ge00 = {
void __init kirkwood_ge00_init(struct mv643xx_eth_platform_data *eth_data)
{
+ kirkwood_clk_ctrl |= CGC_GE0;
eth_data->shared = &kirkwood_ge00_shared;
kirkwood_ge00.dev.platform_data = eth_data;
@@ -213,6 +222,7 @@ static struct platform_device kirkwood_ge01 = {
void __init kirkwood_ge01_init(struct mv643xx_eth_platform_data *eth_data)
{
+ kirkwood_clk_ctrl |= CGC_GE1;
eth_data->shared = &kirkwood_ge01_shared;
kirkwood_ge01.dev.platform_data = eth_data;
@@ -287,6 +297,7 @@ static struct platform_device kirkwood_nand_flash = {
void __init kirkwood_nand_init(struct mtd_partition *parts, int nr_parts,
int chip_delay)
{
+ kirkwood_clk_ctrl |= CGC_RUNIT;
kirkwood_nand_data.parts = parts;
kirkwood_nand_data.nr_parts = nr_parts;
kirkwood_nand_data.chip_delay = chip_delay;
@@ -338,6 +349,9 @@ static struct platform_device kirkwood_sata = {
void __init kirkwood_sata_init(struct mv_sata_platform_data *sata_data)
{
+ kirkwood_clk_ctrl |= CGC_SATA0;
+ if (sata_data->n_ports > 1)
+ kirkwood_clk_ctrl |= CGC_SATA1;
sata_data->dram = &kirkwood_mbus_dram_info;
kirkwood_sata.dev.platform_data = sata_data;
platform_device_register(&kirkwood_sata);
@@ -383,6 +397,7 @@ void __init kirkwood_sdio_init(struct mvsdio_platform_data *mvsdio_data)
else
mvsdio_data->clock = 200000000;
mvsdio_data->dram = &kirkwood_mbus_dram_info;
+ kirkwood_clk_ctrl |= CGC_SDIO;
kirkwood_sdio.dev.platform_data = mvsdio_data;
platform_device_register(&kirkwood_sdio);
}
@@ -414,6 +429,7 @@ static struct platform_device kirkwood_spi = {
void __init kirkwood_spi_init()
{
+ kirkwood_clk_ctrl |= CGC_RUNIT;
platform_device_register(&kirkwood_spi);
}
@@ -634,6 +650,7 @@ static struct platform_device kirkwood_xor01_channel = {
static void __init kirkwood_xor0_init(void)
{
+ kirkwood_clk_ctrl |= CGC_XOR0;
platform_device_register(&kirkwood_xor0_shared);
/*
@@ -732,6 +749,7 @@ static struct platform_device kirkwood_xor11_channel = {
static void __init kirkwood_xor1_init(void)
{
+ kirkwood_clk_ctrl |= CGC_XOR1;
platform_device_register(&kirkwood_xor1_shared);
/*
@@ -844,3 +862,44 @@ void __init kirkwood_init(void)
kirkwood_xor0_init();
kirkwood_xor1_init();
}
+
+static int __init kirkwood_clock_gate(void)
+{
+ unsigned int curr = readl(CLOCK_GATING_CTRL);
+
+ printk(KERN_DEBUG "Gating clock of unused units\n");
+ printk(KERN_DEBUG "before: 0x%08x\n", curr);
+
+ /* Make sure those units are accessible */
+ writel(curr | CGC_SATA0 | CGC_SATA1 | CGC_PEX0, CLOCK_GATING_CTRL);
+
+ /* For SATA: first shutdown the phy */
+ if (!(kirkwood_clk_ctrl & CGC_SATA0)) {
+ /* Disable PLL and IVREF */
+ writel(readl(SATA0_PHY_MODE_2) & ~0xf, SATA0_PHY_MODE_2);
+ /* Disable PHY */
+ writel(readl(SATA0_IF_CTRL) | 0x200, SATA0_IF_CTRL);
+ }
+ if (!(kirkwood_clk_ctrl & CGC_SATA1)) {
+ /* Disable PLL and IVREF */
+ writel(readl(SATA1_PHY_MODE_2) & ~0xf, SATA1_PHY_MODE_2);
+ /* Disable PHY */
+ writel(readl(SATA1_IF_CTRL) | 0x200, SATA1_IF_CTRL);
+ }
+
+ /* For PCIe: first shutdown the phy */
+ if (!(kirkwood_clk_ctrl & CGC_PEX0)) {
+ writel(readl(PCIE_LINK_CTRL) | 0x10, PCIE_LINK_CTRL);
+ while (1)
+ if (readl(PCIE_STATUS) & 0x1)
+ break;
+ writel(readl(PCIE_LINK_CTRL) & ~0x10, PCIE_LINK_CTRL);
+ }
+
+ /* Now gate clock the required units */
+ writel(kirkwood_clk_ctrl, CLOCK_GATING_CTRL);
+ printk(KERN_DEBUG " after: 0x%08x\n", readl(CLOCK_GATING_CTRL));
+
+ return 0;
+}
+late_initcall(kirkwood_clock_gate);