2008-03-18 11:22:06 +03:00
/*
* linux / arch / arm / mach - omap2 / clock . c
*
2008-03-18 12:56:39 +03:00
* Copyright ( C ) 2005 - 2008 Texas Instruments , Inc .
2010-02-23 08:09:24 +03:00
* Copyright ( C ) 2004 - 2010 Nokia Corporation
2008-03-18 11:22:06 +03:00
*
2008-03-18 12:56:39 +03:00
* Contacts :
* Richard Woodruff < r - woodruff2 @ ti . com >
2008-03-18 11:22:06 +03:00
* Paul Walmsley
*
* 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 .
*/
# undef DEBUG
# include <linux/kernel.h>
2012-09-27 20:33:33 +04:00
# include <linux/export.h>
2008-03-18 11:22:06 +03:00
# include <linux/list.h>
# include <linux/errno.h>
2010-02-23 08:09:36 +03:00
# include <linux/err.h>
# include <linux/delay.h>
2015-06-23 03:05:21 +03:00
# include <linux/clk.h>
2012-11-11 03:58:41 +04:00
# include <linux/clk-provider.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2008-09-06 15:13:59 +04:00
# include <linux/bitops.h>
2014-10-22 16:15:36 +04:00
# include <linux/of_address.h>
2011-03-03 13:25:43 +03:00
# include <asm/cpu.h>
2012-08-31 21:59:07 +04:00
# include <trace/events/power.h>
# include "soc.h"
# include "clockdomain.h"
2008-03-18 11:22:06 +03:00
# include "clock.h"
2012-10-30 06:56:29 +04:00
# include "cm.h"
2012-10-21 11:01:11 +04:00
# include "cm2xxx.h"
# include "cm3xxx.h"
2008-03-18 11:22:06 +03:00
# include "cm-regbits-24xx.h"
# include "cm-regbits-34xx.h"
2012-10-30 06:56:29 +04:00
# include "common.h"
2011-12-13 22:46:43 +04:00
u16 cpu_mask ;
2008-03-18 11:22:06 +03:00
2014-07-02 12:47:40 +04:00
/* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */
# define OMAP3430_DPLL_FINT_BAND1_MIN 750000
# define OMAP3430_DPLL_FINT_BAND1_MAX 2100000
# define OMAP3430_DPLL_FINT_BAND2_MIN 7500000
# define OMAP3430_DPLL_FINT_BAND2_MAX 21000000
/*
* DPLL valid Fint frequency range for OMAP36xx and OMAP4xxx .
* From device data manual section 4.3 " DPLL and DLL Specifications " .
*/
# define OMAP3PLUS_DPLL_FINT_MIN 32000
# define OMAP3PLUS_DPLL_FINT_MAX 52000000
2014-10-22 16:15:36 +04:00
static struct ti_clk_ll_ops omap_clk_ll_ops = {
2015-03-03 12:14:31 +03:00
. clkdm_clk_enable = clkdm_clk_enable ,
. clkdm_clk_disable = clkdm_clk_disable ,
2015-03-03 14:47:08 +03:00
. cm_wait_module_ready = omap_cm_wait_module_ready ,
. cm_split_idlest_reg = cm_split_idlest_reg ,
2014-10-22 16:15:36 +04:00
} ;
2015-04-27 21:55:42 +03:00
/**
* omap2_clk_setup_ll_ops - setup clock driver low - level ops
*
* Sets up clock driver low - level platform ops . These are needed
* for register accesses and various other misc platform operations .
* Returns 0 on success , - EBUSY if low level ops have been registered
* already .
*/
int __init omap2_clk_setup_ll_ops ( void )
{
return ti_clk_setup_ll_ops ( & omap_clk_ll_ops ) ;
}
OMAP2+ clock: revise omap2_clk_{disable,enable}()
Simplify the code in the omap2_clk_disable() and omap2_clk_enable()
functions, reducing levels of indentation. This makes the code easier
to read. Add some additional debugging pr_debug()s here also to help
others understand what is going on.
Revise the omap2_clk_disable() logic so that it now attempts to
disable the clock's clockdomain before recursing up the clock tree.
Simultaneously, ensure that omap2_clk_enable() is called on parent
clocks first, before enabling the clockdomain. This ensures that a
parent clock's clockdomain is enabled before the child clock's
clockdomain. These sequences should be the inverse of each other.
Revise the omap2_clk_enable() logic so that it now cleans up after
itself upon encountering an error. Previously, an error enabling a
parent clock could have resulted in inconsistent usecounts on the
enclosing clockdomain.
Remove the trivial _omap2_clk_disable() and _omap2_clk_enable() static
functions, and replace it with the clkops calls that they were
executing.
For all this to work, the clockdomain omap2_clkdm_clk_enable() and
omap2_clkdm_clk_disable() code must not return an error on clockdomains
without CLKSTCTRL registers; so modify those functions to simply return 0
in that case.
While here, add some basic kerneldoc documentation on both functions,
and get rid of some old non-CodingStyle-compliant comments that have
existed since the dawn of time (at least, the OMAP clock framework's
time).
Signed-off-by: Paul Walmsley <paul@pwsan.com>
Cc: Richard Woodruff <r-woodruff2@ti.com>
Cc: Rajendra Nayak <rnayak@ti.com>
2010-02-23 08:09:38 +03:00
/*
* OMAP2 + specific clock functions
*/
2008-03-18 11:22:06 +03:00
2010-01-27 06:13:04 +03:00
/* Private functions */
/* Public functions */
2008-08-19 12:08:45 +04:00
/**
* omap2_init_clk_clkdm - look up a clockdomain name , store pointer in clk
* @ clk : OMAP clock struct ptr to use
*
* Convert a clockdomain name stored in a struct clk ' clk ' into a
* clockdomain pointer , and save it into the struct clk . Intended to be
* called during clk_register ( ) . No return value .
*/
2012-11-11 03:58:41 +04:00
void omap2_init_clk_clkdm ( struct clk_hw * hw )
{
struct clk_hw_omap * clk = to_clk_hw_omap ( hw ) ;
2008-08-19 12:08:45 +04:00
struct clockdomain * clkdm ;
2012-09-22 12:24:17 +04:00
const char * clk_name ;
2008-08-19 12:08:45 +04:00
if ( ! clk - > clkdm_name )
return ;
2012-11-11 03:58:41 +04:00
clk_name = __clk_get_name ( hw - > clk ) ;
2012-09-22 12:24:17 +04:00
2008-08-19 12:08:45 +04:00
clkdm = clkdm_lookup ( clk - > clkdm_name ) ;
if ( clkdm ) {
pr_debug ( " clock: associated clk %s to clkdm %s \n " ,
2012-09-22 12:24:17 +04:00
clk_name , clk - > clkdm_name ) ;
2008-08-19 12:08:45 +04:00
clk - > clkdm = clkdm ;
} else {
2012-07-26 10:54:26 +04:00
pr_debug ( " clock: could not associate clk %s to clkdm %s \n " ,
2012-09-22 12:24:17 +04:00
clk_name , clk - > clkdm_name ) ;
2008-08-19 12:08:45 +04:00
}
}
2012-11-11 03:58:41 +04:00
static int __initdata mpurate ;
/*
* By default we use the rate set by the bootloader .
* You can override this with mpurate = cmdline option .
*/
static int __init omap_clk_setup ( char * str )
{
get_option ( & str , & mpurate ) ;
if ( ! mpurate )
return 1 ;
if ( mpurate < 1000 )
mpurate * = 1000000 ;
return 1 ;
}
__setup ( " mpurate= " , omap_clk_setup ) ;
2010-02-23 08:09:36 +03:00
/**
* omap2_clk_print_new_rates - print summary of current clock tree rates
* @ hfclkin_ck_name : clk name for the off - chip HF oscillator
* @ core_ck_name : clk name for the on - chip CORE_CLK
* @ mpu_ck_name : clk name for the ARM MPU clock
*
* Prints a short message to the console with the HFCLKIN oscillator
* rate , the rate of the CORE clock , and the rate of the ARM MPU clock .
* Called by the boot - time MPU rate switching code . XXX This is intended
* to be handled by the OPP layer code in the near future and should be
* removed from the clock code . No return value .
*/
void __init omap2_clk_print_new_rates ( const char * hfclkin_ck_name ,
const char * core_ck_name ,
const char * mpu_ck_name )
{
struct clk * hfclkin_ck , * core_ck , * mpu_ck ;
unsigned long hfclkin_rate ;
mpu_ck = clk_get ( NULL , mpu_ck_name ) ;
if ( WARN ( IS_ERR ( mpu_ck ) , " clock: failed to get %s. \n " , mpu_ck_name ) )
return ;
core_ck = clk_get ( NULL , core_ck_name ) ;
if ( WARN ( IS_ERR ( core_ck ) , " clock: failed to get %s. \n " , core_ck_name ) )
return ;
hfclkin_ck = clk_get ( NULL , hfclkin_ck_name ) ;
if ( WARN ( IS_ERR ( hfclkin_ck ) , " Failed to get %s. \n " , hfclkin_ck_name ) )
return ;
hfclkin_rate = clk_get_rate ( hfclkin_ck ) ;
2012-07-26 10:54:26 +04:00
pr_info ( " Switched to new clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz \n " ,
( hfclkin_rate / 1000000 ) , ( ( hfclkin_rate / 100000 ) % 10 ) ,
2010-02-23 08:09:36 +03:00
( clk_get_rate ( core_ck ) / 1000000 ) ,
( clk_get_rate ( mpu_ck ) / 1000000 ) ) ;
}
2014-07-02 12:47:39 +04:00
/**
* ti_clk_init_features - init clock features struct for the SoC
*
* Initializes the clock features struct based on the SoC type .
*/
void __init ti_clk_init_features ( void )
{
2015-02-27 18:54:14 +03:00
struct ti_clk_features features = { 0 } ;
2014-07-02 12:47:40 +04:00
/* Fint setup for DPLLs */
if ( cpu_is_omap3430 ( ) ) {
2015-02-27 18:54:14 +03:00
features . fint_min = OMAP3430_DPLL_FINT_BAND1_MIN ;
features . fint_max = OMAP3430_DPLL_FINT_BAND2_MAX ;
features . fint_band1_max = OMAP3430_DPLL_FINT_BAND1_MAX ;
features . fint_band2_min = OMAP3430_DPLL_FINT_BAND2_MIN ;
2014-07-02 12:47:40 +04:00
} else {
2015-02-27 18:54:14 +03:00
features . fint_min = OMAP3PLUS_DPLL_FINT_MIN ;
features . fint_max = OMAP3PLUS_DPLL_FINT_MAX ;
2014-07-02 12:47:40 +04:00
}
2014-07-02 12:47:42 +04:00
/* Bypass value setup for DPLLs */
if ( cpu_is_omap24xx ( ) ) {
2015-02-27 18:54:14 +03:00
features . dpll_bypass_vals | =
2014-07-02 12:47:42 +04:00
( 1 < < OMAP2XXX_EN_DPLL_LPBYPASS ) |
( 1 < < OMAP2XXX_EN_DPLL_FRBYPASS ) ;
} else if ( cpu_is_omap34xx ( ) ) {
2015-02-27 18:54:14 +03:00
features . dpll_bypass_vals | =
2014-07-02 12:47:42 +04:00
( 1 < < OMAP3XXX_EN_DPLL_LPBYPASS ) |
( 1 < < OMAP3XXX_EN_DPLL_FRBYPASS ) ;
} else if ( soc_is_am33xx ( ) | | cpu_is_omap44xx ( ) | | soc_is_am43xx ( ) | |
soc_is_omap54xx ( ) | | soc_is_dra7xx ( ) ) {
2015-02-27 18:54:14 +03:00
features . dpll_bypass_vals | =
2014-07-02 12:47:42 +04:00
( 1 < < OMAP4XXX_EN_DPLL_LPBYPASS ) |
( 1 < < OMAP4XXX_EN_DPLL_FRBYPASS ) |
( 1 < < OMAP4XXX_EN_DPLL_MNBYPASS ) ;
}
2014-07-02 12:47:43 +04:00
/* Jitter correction only available on OMAP343X */
if ( cpu_is_omap343x ( ) )
2015-02-27 18:54:14 +03:00
features . flags | = TI_CLK_DPLL_HAS_FREQSEL ;
2014-07-02 12:47:44 +04:00
/* Idlest value for interface clocks.
* 24 xx uses 0 to indicate not ready , and 1 to indicate ready .
* 34 xx reverses this , just to keep us on our toes
* AM35xx uses both , depending on the module .
*/
if ( cpu_is_omap24xx ( ) )
2015-02-27 18:54:14 +03:00
features . cm_idlest_val = OMAP24XX_CM_IDLEST_VAL ;
2014-07-02 12:47:44 +04:00
else if ( cpu_is_omap34xx ( ) )
2015-02-27 18:54:14 +03:00
features . cm_idlest_val = OMAP34XX_CM_IDLEST_VAL ;
2014-10-03 17:57:10 +04:00
/* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */
if ( omap_rev ( ) = = OMAP3430_REV_ES1_0 )
2015-02-27 18:54:14 +03:00
features . flags | = TI_CLK_DPLL4_DENY_REPROGRAM ;
ti_clk_setup_features ( & features ) ;
2014-07-02 12:47:39 +04:00
}