Commit c5b736d0 authored by Kevin Hilman's avatar Kevin Hilman

davinci: major rework of clock, PLL, PSC infrastructure

This is a significant rework of the low-level clock, PLL and Power
Sleep Controller (PSC) implementation for the DaVinci family.  The
primary goal is to have better modeling if the hardware clocks and
features with the aim of DVFS functionality.

Highlights:
- model PLLs and all PLL-derived clocks
- model parent/child relationships of PLLs and clocks
- convert to new clkdev layer
- view clock frequency and refcount via /proc/davinci_clocks

Special thanks to significant contributions and testing by David
Brownell.

Cc: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
parent e653034e
...@@ -586,6 +586,7 @@ config ARCH_DAVINCI ...@@ -586,6 +586,7 @@ config ARCH_DAVINCI
select HAVE_CLK select HAVE_CLK
select ZONE_DMA select ZONE_DMA
select HAVE_IDE select HAVE_IDE
select COMMON_CLKDEV
help help
Support for TI's DaVinci platform. Support for TI's DaVinci platform.
......
...@@ -18,6 +18,18 @@ config MACH_DAVINCI_EVM ...@@ -18,6 +18,18 @@ config MACH_DAVINCI_EVM
Configure this option to specify the whether the board used Configure this option to specify the whether the board used
for development is a DaVinci EVM for development is a DaVinci EVM
config DAVINCI_RESET_CLOCKS
bool "Reset unused clocks during boot"
depends on ARCH_DAVINCI
help
Say Y if you want to reset unused clocks during boot.
This option saves power, but assumes all drivers are
using the clock framework. Broken drivers that do not
yet use clock framework may not work with this option.
If you are booting from another operating system, you
probably do not want this option enabled until your
device drivers work properly.
endmenu endmenu
endif endif
...@@ -406,8 +406,6 @@ davinci_evm_map_io(void) ...@@ -406,8 +406,6 @@ davinci_evm_map_io(void)
static __init void davinci_evm_init(void) static __init void davinci_evm_init(void)
{ {
davinci_psc_init();
#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \ #if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE) defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
#if defined(CONFIG_MTD_PHYSMAP) || \ #if defined(CONFIG_MTD_PHYSMAP) || \
......
This diff is collapsed.
/* /*
* TI DaVinci clock definitions * TI DaVinci clock definitions
* *
* Copyright (C) 2006 Texas Instruments. * Copyright (C) 2006-2007 Texas Instruments.
* Copyright (C) 2008-2009 Deep Root Systems, LLC
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
...@@ -11,23 +12,85 @@ ...@@ -11,23 +12,85 @@
#ifndef __ARCH_ARM_DAVINCI_CLOCK_H #ifndef __ARCH_ARM_DAVINCI_CLOCK_H
#define __ARCH_ARM_DAVINCI_CLOCK_H #define __ARCH_ARM_DAVINCI_CLOCK_H
#include <linux/list.h>
#include <asm/clkdev.h>
#define DAVINCI_PLL1_BASE 0x01c40800
#define DAVINCI_PLL2_BASE 0x01c40c00
#define MAX_PLL 2
/* PLL/Reset register offsets */
#define PLLCTL 0x100
#define PLLCTL_PLLEN BIT(0)
#define PLLCTL_CLKMODE BIT(8)
#define PLLM 0x110
#define PLLM_PLLM_MASK 0xff
#define PREDIV 0x114
#define PLLDIV1 0x118
#define PLLDIV2 0x11c
#define PLLDIV3 0x120
#define POSTDIV 0x128
#define BPDIV 0x12c
#define PLLCMD 0x138
#define PLLSTAT 0x13c
#define PLLALNCTL 0x140
#define PLLDCHANGE 0x144
#define PLLCKEN 0x148
#define PLLCKSTAT 0x14c
#define PLLSYSTAT 0x150
#define PLLDIV4 0x160
#define PLLDIV5 0x164
#define PLLDIV6 0x168
#define PLLDIV7 0x16c
#define PLLDIV8 0x170
#define PLLDIV9 0x174
#define PLLDIV_EN BIT(15)
#define PLLDIV_RATIO_MASK 0x1f
struct pll_data {
u32 phys_base;
void __iomem *base;
u32 num;
u32 flags;
u32 input_rate;
};
#define PLL_HAS_PREDIV 0x01
#define PLL_HAS_POSTDIV 0x02
struct clk { struct clk {
struct list_head node; struct list_head node;
struct module *owner; struct module *owner;
const char *name; const char *name;
unsigned int *rate; unsigned long rate;
int id; u8 usecount;
__s8 usecount; u8 flags;
__u8 flags; u8 lpsc;
__u8 lpsc; struct clk *parent;
struct pll_data *pll_data;
u32 div_reg;
}; };
/* Clock flags */ /* Clock flags */
#define RATE_CKCTL 1 #define ALWAYS_ENABLED BIT(1)
#define RATE_FIXED 2 #define CLK_PSC BIT(2)
#define RATE_PROPAGATES 4 #define PSC_DSP BIT(3) /* PSC uses DSP domain, not ARM */
#define VIRTUAL_CLOCK 8 #define CLK_PLL BIT(4) /* PLL-derived clock */
#define ALWAYS_ENABLED 16 #define PRE_PLL BIT(5) /* source is before PLL mult/div */
#define ENABLE_REG_32BIT 32
struct davinci_clk {
struct clk_lookup lk;
};
#define CLK(dev, con, ck) \
{ \
.lk = { \
.dev_id = dev, \
.con_id = con, \
.clk = ck, \
}, \
}
int davinci_clk_init(struct davinci_clk *clocks);
#endif #endif
#ifndef __MACH_CLKDEV_H
#define __MACH_CLKDEV_H
static inline int __clk_get(struct clk *clk)
{
return 1;
}
static inline void __clk_put(struct clk *clk)
{
}
#endif
...@@ -17,6 +17,5 @@ struct clk; ...@@ -17,6 +17,5 @@ struct clk;
extern int clk_register(struct clk *clk); extern int clk_register(struct clk *clk);
extern void clk_unregister(struct clk *clk); extern void clk_unregister(struct clk *clk);
extern int davinci_clk_init(void);
#endif #endif
...@@ -38,8 +38,6 @@ ...@@ -38,8 +38,6 @@
#define DAVINCI_LPSC_TPTC1 4 #define DAVINCI_LPSC_TPTC1 4
#define DAVINCI_LPSC_EMAC 5 #define DAVINCI_LPSC_EMAC 5
#define DAVINCI_LPSC_EMAC_WRAPPER 6 #define DAVINCI_LPSC_EMAC_WRAPPER 6
#define DAVINCI_LPSC_MDIO 7
#define DAVINCI_LPSC_IEEE1394 8
#define DAVINCI_LPSC_USB 9 #define DAVINCI_LPSC_USB 9
#define DAVINCI_LPSC_ATA 10 #define DAVINCI_LPSC_ATA 10
#define DAVINCI_LPSC_VLYNQ 11 #define DAVINCI_LPSC_VLYNQ 11
...@@ -47,7 +45,6 @@ ...@@ -47,7 +45,6 @@
#define DAVINCI_LPSC_DDR_EMIF 13 #define DAVINCI_LPSC_DDR_EMIF 13
#define DAVINCI_LPSC_AEMIF 14 #define DAVINCI_LPSC_AEMIF 14
#define DAVINCI_LPSC_MMC_SD 15 #define DAVINCI_LPSC_MMC_SD 15
#define DAVINCI_LPSC_MEMSTICK 16
#define DAVINCI_LPSC_McBSP 17 #define DAVINCI_LPSC_McBSP 17
#define DAVINCI_LPSC_I2C 18 #define DAVINCI_LPSC_I2C 18
#define DAVINCI_LPSC_UART0 19 #define DAVINCI_LPSC_UART0 19
...@@ -73,4 +70,54 @@ ...@@ -73,4 +70,54 @@
#define DAVINCI_LPSC_GEM 39 #define DAVINCI_LPSC_GEM 39
#define DAVINCI_LPSC_IMCOP 40 #define DAVINCI_LPSC_IMCOP 40
#define DM355_LPSC_TIMER3 5
#define DM355_LPSC_SPI1 6
#define DM355_LPSC_MMC_SD1 7
#define DM355_LPSC_McBSP1 8
#define DM355_LPSC_PWM3 10
#define DM355_LPSC_SPI2 11
#define DM355_LPSC_RTO 12
#define DM355_LPSC_VPSS_DAC 41
/*
* LPSC Assignments
*/
#define DM646X_LPSC_ARM 0
#define DM646X_LPSC_C64X_CPU 1
#define DM646X_LPSC_HDVICP0 2
#define DM646X_LPSC_HDVICP1 3
#define DM646X_LPSC_TPCC 4
#define DM646X_LPSC_TPTC0 5
#define DM646X_LPSC_TPTC1 6
#define DM646X_LPSC_TPTC2 7
#define DM646X_LPSC_TPTC3 8
#define DM646X_LPSC_PCI 13
#define DM646X_LPSC_EMAC 14
#define DM646X_LPSC_VDCE 15
#define DM646X_LPSC_VPSSMSTR 16
#define DM646X_LPSC_VPSSSLV 17
#define DM646X_LPSC_TSIF0 18
#define DM646X_LPSC_TSIF1 19
#define DM646X_LPSC_DDR_EMIF 20
#define DM646X_LPSC_AEMIF 21
#define DM646X_LPSC_McASP0 22
#define DM646X_LPSC_McASP1 23
#define DM646X_LPSC_CRGEN0 24
#define DM646X_LPSC_CRGEN1 25
#define DM646X_LPSC_UART0 26
#define DM646X_LPSC_UART1 27
#define DM646X_LPSC_UART2 28
#define DM646X_LPSC_PWM0 29
#define DM646X_LPSC_PWM1 30
#define DM646X_LPSC_I2C 31
#define DM646X_LPSC_SPI 32
#define DM646X_LPSC_GPIO 33
#define DM646X_LPSC_TIMER0 34
#define DM646X_LPSC_TIMER1 35
#define DM646X_LPSC_ARM_INTC 45
extern int davinci_psc_is_clk_active(unsigned int id);
extern void davinci_psc_config(unsigned int domain, unsigned int id,
char enable);
#endif /* __ASM_ARCH_PSC_H */ #endif /* __ASM_ARCH_PSC_H */
...@@ -53,5 +53,4 @@ void __init davinci_map_common_io(void) ...@@ -53,5 +53,4 @@ void __init davinci_map_common_io(void)
void __init davinci_init_common_hw(void) void __init davinci_init_common_hw(void)
{ {
davinci_clk_init();
} }
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <mach/cputype.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/psc.h> #include <mach/psc.h>
#include <mach/mux.h> #include <mach/mux.h>
...@@ -36,76 +37,57 @@ ...@@ -36,76 +37,57 @@
#define MDSTAT 0x800 #define MDSTAT 0x800
#define MDCTL 0xA00 #define MDCTL 0xA00
/* System control register offsets */
#define VDD3P3V_PWDN 0x48
static void davinci_psc_mux(unsigned int id) /* Return nonzero iff the domain's clock is active */
int __init davinci_psc_is_clk_active(unsigned int id)
{ {
switch (id) { void __iomem *psc_base = IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE);
case DAVINCI_LPSC_ATA: u32 mdstat = __raw_readl(psc_base + MDSTAT + 4 * id);
davinci_mux_peripheral(DAVINCI_MUX_HDIREN, 1);
davinci_mux_peripheral(DAVINCI_MUX_ATAEN, 1); /* if clocked, state can be "Enable" or "SyncReset" */
break; return mdstat & BIT(12);
case DAVINCI_LPSC_MMC_SD:
/* VDD power manupulations are done in U-Boot for CPMAC
* so applies to MMC as well
*/
/*Set up the pull regiter for MMC */
davinci_writel(0, DAVINCI_SYSTEM_MODULE_BASE + VDD3P3V_PWDN);
davinci_mux_peripheral(DAVINCI_MUX_MSTK, 0);
break;
case DAVINCI_LPSC_I2C:
davinci_mux_peripheral(DAVINCI_MUX_I2C, 1);
break;
case DAVINCI_LPSC_McBSP:
davinci_mux_peripheral(DAVINCI_MUX_ASP, 1);
break;
default:
break;
}
} }
/* Enable or disable a PSC domain */ /* Enable or disable a PSC domain */
void davinci_psc_config(unsigned int domain, unsigned int id, char enable) void davinci_psc_config(unsigned int domain, unsigned int id, char enable)
{ {
u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl, mdstat_mask; u32 epcpr, ptcmd, ptstat, pdstat, pdctl1, mdstat, mdctl, mdstat_mask;
void __iomem *psc_base = IO_ADDRESS(DAVINCI_PWR_SLEEP_CNTRL_BASE);
mdctl = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id); mdctl = __raw_readl(psc_base + MDCTL + 4 * id);
if (enable) if (enable)
mdctl |= 0x00000003; /* Enable Module */ mdctl |= 0x00000003; /* Enable Module */
else else
mdctl &= 0xFFFFFFF2; /* Disable Module */ mdctl &= 0xFFFFFFE2; /* Disable Module */
davinci_writel(mdctl, DAVINCI_PWR_SLEEP_CNTRL_BASE + MDCTL + 4 * id); __raw_writel(mdctl, psc_base + MDCTL + 4 * id);
pdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDSTAT); pdstat = __raw_readl(psc_base + PDSTAT);
if ((pdstat & 0x00000001) == 0) { if ((pdstat & 0x00000001) == 0) {
pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); pdctl1 = __raw_readl(psc_base + PDCTL1);
pdctl1 |= 0x1; pdctl1 |= 0x1;
davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); __raw_writel(pdctl1, psc_base + PDCTL1);
ptcmd = 1 << domain; ptcmd = 1 << domain;
davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD); __raw_writel(ptcmd, psc_base + PTCMD);
do { do {
epcpr = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + epcpr = __raw_readl(psc_base + EPCPR);
EPCPR);
} while ((((epcpr >> domain) & 1) == 0)); } while ((((epcpr >> domain) & 1) == 0));
pdctl1 = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); pdctl1 = __raw_readl(psc_base + PDCTL1);
pdctl1 |= 0x100; pdctl1 |= 0x100;
davinci_writel(pdctl1, DAVINCI_PWR_SLEEP_CNTRL_BASE + PDCTL1); __raw_writel(pdctl1, psc_base + PDCTL1);
do { do {
ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + ptstat = __raw_readl(psc_base +
PTSTAT); PTSTAT);
} while (!(((ptstat >> domain) & 1) == 0)); } while (!(((ptstat >> domain) & 1) == 0));
} else { } else {
ptcmd = 1 << domain; ptcmd = 1 << domain;
davinci_writel(ptcmd, DAVINCI_PWR_SLEEP_CNTRL_BASE + PTCMD); __raw_writel(ptcmd, psc_base + PTCMD);
do { do {
ptstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + ptstat = __raw_readl(psc_base + PTSTAT);
PTSTAT);
} while (!(((ptstat >> domain) & 1) == 0)); } while (!(((ptstat >> domain) & 1) == 0));
} }
...@@ -115,23 +97,6 @@ void davinci_psc_config(unsigned int domain, unsigned int id, char enable) ...@@ -115,23 +97,6 @@ void davinci_psc_config(unsigned int domain, unsigned int id, char enable)
mdstat_mask = 0x2; mdstat_mask = 0x2;
do { do {
mdstat = davinci_readl(DAVINCI_PWR_SLEEP_CNTRL_BASE + mdstat = __raw_readl(psc_base + MDSTAT + 4 * id);
MDSTAT + 4 * id);
} while (!((mdstat & 0x0000001F) == mdstat_mask)); } while (!((mdstat & 0x0000001F) == mdstat_mask));
if (enable)
davinci_psc_mux(id);
}
void __init davinci_psc_init(void)
{
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_VPSSMSTR, 1);
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_VPSSSLV, 1);
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPCC, 1);
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPTC0, 1);
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TPTC1, 1);
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_GPIO, 1);
/* Turn on WatchDog timer LPSC. Needed for RESET to work */
davinci_psc_config(DAVINCI_GPSC_ARMDOMAIN, DAVINCI_LPSC_TIMER2, 1);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment