2005-11-10 17:26:48 +03:00
/*
* linux / arch / arm / mach - omap1 / clock . c
*
* Copyright ( C ) 2004 - 2005 Nokia corporation
* Written by Tuukka Tikkanen < tuukka . tikkanen @ elektrobit . com >
*
* Modified to use omap shared clock framework by
* Tony Lindgren < tony @ atomide . com >
*
* 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/module.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/errno.h>
# include <linux/err.h>
2006-01-07 19:15:52 +03:00
# include <linux/clk.h>
2005-11-10 17:26:48 +03:00
# include <asm/io.h>
# include <asm/arch/usb.h>
# include <asm/arch/clock.h>
# include <asm/arch/sram.h>
# include "clock.h"
__u32 arm_idlect1_mask ;
/*-------------------------------------------------------------------------
* Omap1 specific clock functions
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
static void omap1_watchdog_recalc ( struct clk * clk )
{
clk - > rate = clk - > parent - > rate / 14 ;
}
static void omap1_uart_recalc ( struct clk * clk )
{
unsigned int val = omap_readl ( clk - > enable_reg ) ;
if ( val & clk - > enable_bit )
clk - > rate = 48000000 ;
else
clk - > rate = 12000000 ;
}
static int omap1_clk_enable_dsp_domain ( struct clk * clk )
{
int retval ;
2006-01-18 02:30:42 +03:00
retval = omap1_clk_enable ( & api_ck . clk ) ;
2005-11-10 17:26:48 +03:00
if ( ! retval ) {
2006-01-18 02:30:42 +03:00
retval = omap1_clk_enable_generic ( clk ) ;
omap1_clk_disable ( & api_ck . clk ) ;
2005-11-10 17:26:48 +03:00
}
return retval ;
}
static void omap1_clk_disable_dsp_domain ( struct clk * clk )
{
2006-01-18 02:30:42 +03:00
if ( omap1_clk_enable ( & api_ck . clk ) = = 0 ) {
omap1_clk_disable_generic ( clk ) ;
omap1_clk_disable ( & api_ck . clk ) ;
2005-11-10 17:26:48 +03:00
}
}
static int omap1_clk_enable_uart_functional ( struct clk * clk )
{
int ret ;
struct uart_clk * uclk ;
2006-01-18 02:30:42 +03:00
ret = omap1_clk_enable_generic ( clk ) ;
2005-11-10 17:26:48 +03:00
if ( ret = = 0 ) {
/* Set smart idle acknowledgement mode */
uclk = ( struct uart_clk * ) clk ;
omap_writeb ( ( omap_readb ( uclk - > sysc_addr ) & ~ 0x10 ) | 8 ,
uclk - > sysc_addr ) ;
}
return ret ;
}
static void omap1_clk_disable_uart_functional ( struct clk * clk )
{
struct uart_clk * uclk ;
/* Set force idle acknowledgement mode */
uclk = ( struct uart_clk * ) clk ;
omap_writeb ( ( omap_readb ( uclk - > sysc_addr ) & ~ 0x18 ) , uclk - > sysc_addr ) ;
2006-01-18 02:30:42 +03:00
omap1_clk_disable_generic ( clk ) ;
2005-11-10 17:26:48 +03:00
}
static void omap1_clk_allow_idle ( struct clk * clk )
{
struct arm_idlect1_clk * iclk = ( struct arm_idlect1_clk * ) clk ;
if ( ! ( clk - > flags & CLOCK_IDLE_CONTROL ) )
return ;
if ( iclk - > no_idle_count > 0 & & ! ( - - iclk - > no_idle_count ) )
arm_idlect1_mask | = 1 < < iclk - > idlect_shift ;
}
static void omap1_clk_deny_idle ( struct clk * clk )
{
struct arm_idlect1_clk * iclk = ( struct arm_idlect1_clk * ) clk ;
if ( ! ( clk - > flags & CLOCK_IDLE_CONTROL ) )
return ;
if ( iclk - > no_idle_count + + = = 0 )
arm_idlect1_mask & = ~ ( 1 < < iclk - > idlect_shift ) ;
}
static __u16 verify_ckctl_value ( __u16 newval )
{
/* This function checks for following limitations set
* by the hardware ( all conditions must be true ) :
* DSPMMU_CK = = DSP_CK or DSPMMU_CK = = DSP_CK / 2
* ARM_CK > = TC_CK
* DSP_CK > = TC_CK
* DSPMMU_CK > = TC_CK
*
* In addition following rules are enforced :
* LCD_CK < = TC_CK
* ARMPER_CK < = TC_CK
*
* However , maximum frequencies are not checked for !
*/
__u8 per_exp ;
__u8 lcd_exp ;
__u8 arm_exp ;
__u8 dsp_exp ;
__u8 tc_exp ;
__u8 dspmmu_exp ;
per_exp = ( newval > > CKCTL_PERDIV_OFFSET ) & 3 ;
lcd_exp = ( newval > > CKCTL_LCDDIV_OFFSET ) & 3 ;
arm_exp = ( newval > > CKCTL_ARMDIV_OFFSET ) & 3 ;
dsp_exp = ( newval > > CKCTL_DSPDIV_OFFSET ) & 3 ;
tc_exp = ( newval > > CKCTL_TCDIV_OFFSET ) & 3 ;
dspmmu_exp = ( newval > > CKCTL_DSPMMUDIV_OFFSET ) & 3 ;
if ( dspmmu_exp < dsp_exp )
dspmmu_exp = dsp_exp ;
if ( dspmmu_exp > dsp_exp + 1 )
dspmmu_exp = dsp_exp + 1 ;
if ( tc_exp < arm_exp )
tc_exp = arm_exp ;
if ( tc_exp < dspmmu_exp )
tc_exp = dspmmu_exp ;
if ( tc_exp > lcd_exp )
lcd_exp = tc_exp ;
if ( tc_exp > per_exp )
per_exp = tc_exp ;
newval & = 0xf000 ;
newval | = per_exp < < CKCTL_PERDIV_OFFSET ;
newval | = lcd_exp < < CKCTL_LCDDIV_OFFSET ;
newval | = arm_exp < < CKCTL_ARMDIV_OFFSET ;
newval | = dsp_exp < < CKCTL_DSPDIV_OFFSET ;
newval | = tc_exp < < CKCTL_TCDIV_OFFSET ;
newval | = dspmmu_exp < < CKCTL_DSPMMUDIV_OFFSET ;
return newval ;
}
static int calc_dsor_exp ( struct clk * clk , unsigned long rate )
{
/* Note: If target frequency is too low, this function will return 4,
* which is invalid value . Caller must check for this value and act
* accordingly .
*
* Note : This function does not check for following limitations set
* by the hardware ( all conditions must be true ) :
* DSPMMU_CK = = DSP_CK or DSPMMU_CK = = DSP_CK / 2
* ARM_CK > = TC_CK
* DSP_CK > = TC_CK
* DSPMMU_CK > = TC_CK
*/
unsigned long realrate ;
struct clk * parent ;
unsigned dsor_exp ;
if ( unlikely ( ! ( clk - > flags & RATE_CKCTL ) ) )
return - EINVAL ;
parent = clk - > parent ;
if ( unlikely ( parent = = 0 ) )
return - EIO ;
realrate = parent - > rate ;
for ( dsor_exp = 0 ; dsor_exp < 4 ; dsor_exp + + ) {
if ( realrate < = rate )
break ;
realrate / = 2 ;
}
return dsor_exp ;
}
static void omap1_ckctl_recalc ( struct clk * clk )
{
int dsor ;
/* Calculate divisor encoded as 2-bit exponent */
dsor = 1 < < ( 3 & ( omap_readw ( ARM_CKCTL ) > > clk - > rate_offset ) ) ;
if ( unlikely ( clk - > rate = = clk - > parent - > rate / dsor ) )
return ; /* No change, quick exit */
clk - > rate = clk - > parent - > rate / dsor ;
if ( unlikely ( clk - > flags & RATE_PROPAGATES ) )
propagate_rate ( clk ) ;
}
static void omap1_ckctl_recalc_dsp_domain ( struct clk * clk )
{
int dsor ;
/* Calculate divisor encoded as 2-bit exponent
*
* The clock control bits are in DSP domain ,
* so api_ck is needed for access .
* Note that DSP_CKCTL virt addr = phys addr , so
* we must use __raw_readw ( ) instead of omap_readw ( ) .
*/
2006-01-18 02:30:42 +03:00
omap1_clk_enable ( & api_ck . clk ) ;
2005-11-10 17:26:48 +03:00
dsor = 1 < < ( 3 & ( __raw_readw ( DSP_CKCTL ) > > clk - > rate_offset ) ) ;
2006-01-18 02:30:42 +03:00
omap1_clk_disable ( & api_ck . clk ) ;
2005-11-10 17:26:48 +03:00
if ( unlikely ( clk - > rate = = clk - > parent - > rate / dsor ) )
return ; /* No change, quick exit */
clk - > rate = clk - > parent - > rate / dsor ;
if ( unlikely ( clk - > flags & RATE_PROPAGATES ) )
propagate_rate ( clk ) ;
}
/* MPU virtual clock functions */
static int omap1_select_table_rate ( struct clk * clk , unsigned long rate )
{
/* Find the highest supported frequency <= rate and switch to it */
struct mpu_rate * ptr ;
if ( clk ! = & virtual_ck_mpu )
return - EINVAL ;
for ( ptr = rate_table ; ptr - > rate ; ptr + + ) {
if ( ptr - > xtal ! = ck_ref . rate )
continue ;
/* DPLL1 cannot be reprogrammed without risking system crash */
if ( likely ( ck_dpll1 . rate ! = 0 ) & & ptr - > pll_rate ! = ck_dpll1 . rate )
continue ;
/* Can check only after xtal frequency check */
if ( ptr - > rate < = rate )
break ;
}
if ( ! ptr - > rate )
return - EINVAL ;
/*
* In most cases we should not need to reprogram DPLL .
* Reprogramming the DPLL is tricky , it must be done from SRAM .
*/
omap_sram_reprogram_clock ( ptr - > dpllctl_val , ptr - > ckctl_val ) ;
ck_dpll1 . rate = ptr - > pll_rate ;
propagate_rate ( & ck_dpll1 ) ;
return 0 ;
}
static int omap1_clk_set_rate_dsp_domain ( struct clk * clk , unsigned long rate )
{
int ret = - EINVAL ;
int dsor_exp ;
__u16 regval ;
if ( clk - > flags & RATE_CKCTL ) {
dsor_exp = calc_dsor_exp ( clk , rate ) ;
if ( dsor_exp > 3 )
dsor_exp = - EINVAL ;
if ( dsor_exp < 0 )
return dsor_exp ;
regval = __raw_readw ( DSP_CKCTL ) ;
regval & = ~ ( 3 < < clk - > rate_offset ) ;
regval | = dsor_exp < < clk - > rate_offset ;
__raw_writew ( regval , DSP_CKCTL ) ;
clk - > rate = clk - > parent - > rate / ( 1 < < dsor_exp ) ;
ret = 0 ;
}
if ( unlikely ( ret = = 0 & & ( clk - > flags & RATE_PROPAGATES ) ) )
propagate_rate ( clk ) ;
return ret ;
}
static long omap1_round_to_table_rate ( struct clk * clk , unsigned long rate )
{
/* Find the highest supported frequency <= rate */
struct mpu_rate * ptr ;
long highest_rate ;
if ( clk ! = & virtual_ck_mpu )
return - EINVAL ;
highest_rate = - EINVAL ;
for ( ptr = rate_table ; ptr - > rate ; ptr + + ) {
if ( ptr - > xtal ! = ck_ref . rate )
continue ;
highest_rate = ptr - > rate ;
/* Can check only after xtal frequency check */
if ( ptr - > rate < = rate )
break ;
}
return highest_rate ;
}
static unsigned calc_ext_dsor ( unsigned long rate )
{
unsigned dsor ;
/* MCLK and BCLK divisor selection is not linear:
* freq = 96 MHz / dsor
*
* RATIO_SEL range : dsor < - > RATIO_SEL
* 0. .6 : ( RATIO_SEL + 2 ) < - > ( dsor - 2 )
* 6. .48 : ( 8 + ( RATIO_SEL - 6 ) * 2 ) < - > ( ( dsor - 8 ) / 2 + 6 )
* Minimum dsor is 2 and maximum is 96. Odd divisors starting from 9
* can not be used .
*/
for ( dsor = 2 ; dsor < 96 ; + + dsor ) {
if ( ( dsor & 1 ) & & dsor > 8 )
2006-04-02 20:46:20 +04:00
continue ;
2005-11-10 17:26:48 +03:00
if ( rate > = 96000000 / dsor )
break ;
}
return dsor ;
}
/* Only needed on 1510 */
static int omap1_set_uart_rate ( struct clk * clk , unsigned long rate )
{
unsigned int val ;
val = omap_readl ( clk - > enable_reg ) ;
if ( rate = = 12000000 )
val & = ~ ( 1 < < clk - > enable_bit ) ;
else if ( rate = = 48000000 )
val | = ( 1 < < clk - > enable_bit ) ;
else
return - EINVAL ;
omap_writel ( val , clk - > enable_reg ) ;
clk - > rate = rate ;
return 0 ;
}
/* External clock (MCLK & BCLK) functions */
static int omap1_set_ext_clk_rate ( struct clk * clk , unsigned long rate )
{
unsigned dsor ;
__u16 ratio_bits ;
dsor = calc_ext_dsor ( rate ) ;
clk - > rate = 96000000 / dsor ;
if ( dsor > 8 )
ratio_bits = ( ( dsor - 8 ) / 2 + 6 ) < < 2 ;
else
ratio_bits = ( dsor - 2 ) < < 2 ;
ratio_bits | = omap_readw ( clk - > enable_reg ) & ~ 0xfd ;
omap_writew ( ratio_bits , clk - > enable_reg ) ;
return 0 ;
}
static long omap1_round_ext_clk_rate ( struct clk * clk , unsigned long rate )
{
return 96000000 / calc_ext_dsor ( rate ) ;
}
static void omap1_init_ext_clk ( struct clk * clk )
{
unsigned dsor ;
__u16 ratio_bits ;
/* Determine current rate and ensure clock is based on 96MHz APLL */
ratio_bits = omap_readw ( clk - > enable_reg ) & ~ 1 ;
omap_writew ( ratio_bits , clk - > enable_reg ) ;
ratio_bits = ( ratio_bits & 0xfc ) > > 2 ;
if ( ratio_bits > 6 )
dsor = ( ratio_bits - 6 ) * 2 + 8 ;
else
dsor = ratio_bits + 2 ;
clk - > rate = 96000000 / dsor ;
}
2006-01-18 02:30:42 +03:00
static int omap1_clk_enable ( struct clk * clk )
2005-11-10 17:26:48 +03:00
{
int ret = 0 ;
if ( clk - > usecount + + = = 0 ) {
if ( likely ( clk - > parent ) ) {
2006-01-18 02:30:42 +03:00
ret = omap1_clk_enable ( clk - > parent ) ;
2005-11-10 17:26:48 +03:00
if ( unlikely ( ret ! = 0 ) ) {
clk - > usecount - - ;
return ret ;
}
if ( clk - > flags & CLOCK_NO_IDLE_PARENT )
if ( ! cpu_is_omap24xx ( ) )
omap1_clk_deny_idle ( clk - > parent ) ;
}
ret = clk - > enable ( clk ) ;
if ( unlikely ( ret ! = 0 ) & & clk - > parent ) {
2006-01-18 02:30:42 +03:00
omap1_clk_disable ( clk - > parent ) ;
2005-11-10 17:26:48 +03:00
clk - > usecount - - ;
}
}
return ret ;
}
2006-01-18 02:30:42 +03:00
static void omap1_clk_disable ( struct clk * clk )
2005-11-10 17:26:48 +03:00
{
if ( clk - > usecount > 0 & & ! ( - - clk - > usecount ) ) {
clk - > disable ( clk ) ;
if ( likely ( clk - > parent ) ) {
2006-01-18 02:30:42 +03:00
omap1_clk_disable ( clk - > parent ) ;
2005-11-10 17:26:48 +03:00
if ( clk - > flags & CLOCK_NO_IDLE_PARENT )
if ( ! cpu_is_omap24xx ( ) )
omap1_clk_allow_idle ( clk - > parent ) ;
}
}
}
2006-01-18 02:30:42 +03:00
static int omap1_clk_enable_generic ( struct clk * clk )
2005-11-10 17:26:48 +03:00
{
__u16 regval16 ;
__u32 regval32 ;
if ( clk - > flags & ALWAYS_ENABLED )
return 0 ;
if ( unlikely ( clk - > enable_reg = = 0 ) ) {
printk ( KERN_ERR " clock.c: Enable for %s without enable code \n " ,
clk - > name ) ;
return 0 ;
}
if ( clk - > flags & ENABLE_REG_32BIT ) {
if ( clk - > flags & VIRTUAL_IO_ADDRESS ) {
regval32 = __raw_readl ( clk - > enable_reg ) ;
regval32 | = ( 1 < < clk - > enable_bit ) ;
__raw_writel ( regval32 , clk - > enable_reg ) ;
} else {
regval32 = omap_readl ( clk - > enable_reg ) ;
regval32 | = ( 1 < < clk - > enable_bit ) ;
omap_writel ( regval32 , clk - > enable_reg ) ;
}
} else {
if ( clk - > flags & VIRTUAL_IO_ADDRESS ) {
regval16 = __raw_readw ( clk - > enable_reg ) ;
regval16 | = ( 1 < < clk - > enable_bit ) ;
__raw_writew ( regval16 , clk - > enable_reg ) ;
} else {
regval16 = omap_readw ( clk - > enable_reg ) ;
regval16 | = ( 1 < < clk - > enable_bit ) ;
omap_writew ( regval16 , clk - > enable_reg ) ;
}
}
return 0 ;
}
2006-01-18 02:30:42 +03:00
static void omap1_clk_disable_generic ( struct clk * clk )
2005-11-10 17:26:48 +03:00
{
__u16 regval16 ;
__u32 regval32 ;
if ( clk - > enable_reg = = 0 )
return ;
if ( clk - > flags & ENABLE_REG_32BIT ) {
if ( clk - > flags & VIRTUAL_IO_ADDRESS ) {
regval32 = __raw_readl ( clk - > enable_reg ) ;
regval32 & = ~ ( 1 < < clk - > enable_bit ) ;
__raw_writel ( regval32 , clk - > enable_reg ) ;
} else {
regval32 = omap_readl ( clk - > enable_reg ) ;
regval32 & = ~ ( 1 < < clk - > enable_bit ) ;
omap_writel ( regval32 , clk - > enable_reg ) ;
}
} else {
if ( clk - > flags & VIRTUAL_IO_ADDRESS ) {
regval16 = __raw_readw ( clk - > enable_reg ) ;
regval16 & = ~ ( 1 < < clk - > enable_bit ) ;
__raw_writew ( regval16 , clk - > enable_reg ) ;
} else {
regval16 = omap_readw ( clk - > enable_reg ) ;
regval16 & = ~ ( 1 < < clk - > enable_bit ) ;
omap_writew ( regval16 , clk - > enable_reg ) ;
}
}
}
static long omap1_clk_round_rate ( struct clk * clk , unsigned long rate )
{
int dsor_exp ;
if ( clk - > flags & RATE_FIXED )
return clk - > rate ;
if ( clk - > flags & RATE_CKCTL ) {
dsor_exp = calc_dsor_exp ( clk , rate ) ;
if ( dsor_exp < 0 )
return dsor_exp ;
if ( dsor_exp > 3 )
dsor_exp = 3 ;
return clk - > parent - > rate / ( 1 < < dsor_exp ) ;
}
if ( clk - > round_rate ! = 0 )
return clk - > round_rate ( clk , rate ) ;
return clk - > rate ;
}
static int omap1_clk_set_rate ( struct clk * clk , unsigned long rate )
{
int ret = - EINVAL ;
int dsor_exp ;
__u16 regval ;
if ( clk - > set_rate )
ret = clk - > set_rate ( clk , rate ) ;
else if ( clk - > flags & RATE_CKCTL ) {
dsor_exp = calc_dsor_exp ( clk , rate ) ;
if ( dsor_exp > 3 )
dsor_exp = - EINVAL ;
if ( dsor_exp < 0 )
return dsor_exp ;
regval = omap_readw ( ARM_CKCTL ) ;
regval & = ~ ( 3 < < clk - > rate_offset ) ;
regval | = dsor_exp < < clk - > rate_offset ;
regval = verify_ckctl_value ( regval ) ;
omap_writew ( regval , ARM_CKCTL ) ;
clk - > rate = clk - > parent - > rate / ( 1 < < dsor_exp ) ;
ret = 0 ;
}
if ( unlikely ( ret = = 0 & & ( clk - > flags & RATE_PROPAGATES ) ) )
propagate_rate ( clk ) ;
return ret ;
}
/*-------------------------------------------------------------------------
* Omap1 clock reset and init functions
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
# ifdef CONFIG_OMAP_RESET_CLOCKS
/*
* Resets some clocks that may be left on from bootloader ,
* but leaves serial clocks on . See also omap_late_clk_reset ( ) .
*/
static inline void omap1_early_clk_reset ( void )
{
//omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
}
static int __init omap1_late_clk_reset ( void )
{
/* Turn off all unused clocks */
struct clk * p ;
__u32 regval32 ;
/* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
regval32 = omap_readw ( SOFT_REQ_REG ) & ( 1 < < 4 ) ;
omap_writew ( regval32 , SOFT_REQ_REG ) ;
omap_writew ( 0 , SOFT_REQ_REG2 ) ;
list_for_each_entry ( p , & clocks , node ) {
if ( p - > usecount > 0 | | ( p - > flags & ALWAYS_ENABLED ) | |
p - > enable_reg = = 0 )
continue ;
/* Clocks in the DSP domain need api_ck. Just assume bootloader
* has not enabled any DSP clocks */
if ( ( u32 ) p - > enable_reg = = DSP_IDLECT2 ) {
printk ( KERN_INFO " Skipping reset check for DSP domain "
" clock \" %s \" \n " , p - > name ) ;
continue ;
}
/* Is the clock already disabled? */
if ( p - > flags & ENABLE_REG_32BIT ) {
if ( p - > flags & VIRTUAL_IO_ADDRESS )
regval32 = __raw_readl ( p - > enable_reg ) ;
else
regval32 = omap_readl ( p - > enable_reg ) ;
} else {
if ( p - > flags & VIRTUAL_IO_ADDRESS )
regval32 = __raw_readw ( p - > enable_reg ) ;
else
regval32 = omap_readw ( p - > enable_reg ) ;
}
if ( ( regval32 & ( 1 < < p - > enable_bit ) ) = = 0 )
continue ;
/* FIXME: This clock seems to be necessary but no-one
* has asked for its activation . */
if ( p = = & tc2_ck // FIX: pm.c (SRAM), CCP, Camera
| | p = = & ck_dpll1out . clk // FIX: SoSSI, SSR
| | p = = & arm_gpio_ck // FIX: GPIO code for 1510
) {
printk ( KERN_INFO " FIXME: Clock \" %s \" seems unused \n " ,
p - > name ) ;
continue ;
}
printk ( KERN_INFO " Disabling unused clock \" %s \" ... " , p - > name ) ;
p - > disable ( p ) ;
printk ( " done \n " ) ;
}
return 0 ;
}
late_initcall ( omap1_late_clk_reset ) ;
# else
# define omap1_early_clk_reset() {}
# endif
static struct clk_functions omap1_clk_functions = {
2006-01-18 02:30:42 +03:00
. clk_enable = omap1_clk_enable ,
. clk_disable = omap1_clk_disable ,
2005-11-10 17:26:48 +03:00
. clk_round_rate = omap1_clk_round_rate ,
. clk_set_rate = omap1_clk_set_rate ,
} ;
int __init omap1_clk_init ( void )
{
struct clk * * clkp ;
const struct omap_clock_config * info ;
int crystal_type = 0 ; /* Default 12 MHz */
omap1_early_clk_reset ( ) ;
clk_init ( & omap1_clk_functions ) ;
/* By default all idlect1 clocks are allowed to idle */
arm_idlect1_mask = ~ 0 ;
for ( clkp = onchip_clks ; clkp < onchip_clks + ARRAY_SIZE ( onchip_clks ) ; clkp + + ) {
if ( ( ( * clkp ) - > flags & CLOCK_IN_OMAP1510 ) & & cpu_is_omap1510 ( ) ) {
clk_register ( * clkp ) ;
continue ;
}
if ( ( ( * clkp ) - > flags & CLOCK_IN_OMAP16XX ) & & cpu_is_omap16xx ( ) ) {
clk_register ( * clkp ) ;
continue ;
}
if ( ( ( * clkp ) - > flags & CLOCK_IN_OMAP730 ) & & cpu_is_omap730 ( ) ) {
clk_register ( * clkp ) ;
continue ;
}
2006-04-02 20:46:20 +04:00
if ( ( ( * clkp ) - > flags & CLOCK_IN_OMAP310 ) & & cpu_is_omap310 ( ) ) {
clk_register ( * clkp ) ;
continue ;
}
2005-11-10 17:26:48 +03:00
}
info = omap_get_config ( OMAP_TAG_CLOCK , struct omap_clock_config ) ;
if ( info ! = NULL ) {
if ( ! cpu_is_omap1510 ( ) )
crystal_type = info - > system_clock_type ;
}
# if defined(CONFIG_ARCH_OMAP730)
ck_ref . rate = 13000000 ;
# elif defined(CONFIG_ARCH_OMAP16XX)
if ( crystal_type = = 2 )
ck_ref . rate = 19200000 ;
# endif
printk ( " Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x \n " ,
omap_readw ( ARM_SYSST ) , omap_readw ( DPLL_CTL ) ,
omap_readw ( ARM_CKCTL ) ) ;
/* We want to be in syncronous scalable mode */
omap_writew ( 0x1000 , ARM_SYSST ) ;
# ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER
/* Use values set by bootloader. Determine PLL rate and recalculate
* dependent clocks as if kernel had changed PLL or divisors .
*/
{
unsigned pll_ctl_val = omap_readw ( DPLL_CTL ) ;
ck_dpll1 . rate = ck_ref . rate ; /* Base xtal rate */
if ( pll_ctl_val & 0x10 ) {
/* PLL enabled, apply multiplier and divisor */
if ( pll_ctl_val & 0xf80 )
ck_dpll1 . rate * = ( pll_ctl_val & 0xf80 ) > > 7 ;
ck_dpll1 . rate / = ( ( pll_ctl_val & 0x60 ) > > 5 ) + 1 ;
} else {
/* PLL disabled, apply bypass divisor */
switch ( pll_ctl_val & 0xc ) {
case 0 :
break ;
case 0x4 :
ck_dpll1 . rate / = 2 ;
break ;
default :
ck_dpll1 . rate / = 4 ;
break ;
}
}
}
propagate_rate ( & ck_dpll1 ) ;
# else
/* Find the highest supported frequency and enable it */
if ( omap1_select_table_rate ( & virtual_ck_mpu , ~ 0 ) ) {
printk ( KERN_ERR " System frequencies not set. Check your config. \n " ) ;
/* Guess sane values (60MHz) */
omap_writew ( 0x2290 , DPLL_CTL ) ;
omap_writew ( 0x1005 , ARM_CKCTL ) ;
ck_dpll1 . rate = 60000000 ;
propagate_rate ( & ck_dpll1 ) ;
}
# endif
/* Cache rates for clocks connected to ck_ref (not dpll1) */
propagate_rate ( & ck_ref ) ;
printk ( KERN_INFO " Clocking rate (xtal/DPLL1/MPU): "
" %ld.%01ld/%ld.%01ld/%ld.%01ld MHz \n " ,
ck_ref . rate / 1000000 , ( ck_ref . rate / 100000 ) % 10 ,
ck_dpll1 . rate / 1000000 , ( ck_dpll1 . rate / 100000 ) % 10 ,
arm_ck . rate / 1000000 , ( arm_ck . rate / 100000 ) % 10 ) ;
# ifdef CONFIG_MACH_OMAP_PERSEUS2
/* Select slicer output as OMAP input clock */
omap_writew ( omap_readw ( OMAP730_PCC_UPLD_CTRL ) & ~ 0x1 , OMAP730_PCC_UPLD_CTRL ) ;
# endif
/* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
omap_writew ( omap_readw ( ARM_CKCTL ) & 0x0fff , ARM_CKCTL ) ;
/* Put DSP/MPUI into reset until needed */
omap_writew ( 0 , ARM_RSTCT1 ) ;
omap_writew ( 1 , ARM_RSTCT2 ) ;
omap_writew ( 0x400 , ARM_IDLECT1 ) ;
/*
* According to OMAP5910 Erratum SYS_DMA_1 , bit DMACK_REQ ( bit 8 )
* of the ARM_IDLECT2 register must be set to zero . The power - on
* default value of this bit is one .
*/
omap_writew ( 0x0000 , ARM_IDLECT2 ) ; /* Turn LCD clock off also */
/*
* Only enable those clocks we will need , let the drivers
* enable other clocks as necessary
*/
2006-01-18 02:30:42 +03:00
clk_enable ( & armper_ck . clk ) ;
clk_enable ( & armxor_ck . clk ) ;
clk_enable ( & armtim_ck . clk ) ; /* This should be done by timer code */
2005-11-10 17:26:48 +03:00
2006-04-02 20:46:20 +04:00
if ( cpu_is_omap15xx ( ) )
2005-11-10 17:26:48 +03:00
clk_enable ( & arm_gpio_ck ) ;
return 0 ;
}