2019-06-01 11:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-07-31 00:50:59 +04:00
/*
* Marvell PXA family clocks
*
* Copyright ( C ) 2014 Robert Jarzmik
*
* Common clock code for PXA clocks ( " CKEN " type clocks + DT )
*/
# include <linux/clk.h>
# include <linux/clk-provider.h>
# include <linux/clkdev.h>
2019-04-19 01:20:22 +03:00
# include <linux/io.h>
2014-07-31 00:50:59 +04:00
# include <linux/of.h>
# include <dt-bindings/clock/pxa-clock.h>
# include "clk-pxa.h"
2016-11-03 00:33:06 +03:00
# define KHz 1000
# define MHz (1000 * 1000)
# define MDREFR_K0DB4 (1 << 29) /* SDCLK0 Divide by 4 Control/Status */
# define MDREFR_K2FREE (1 << 25) /* SDRAM Free-Running Control */
# define MDREFR_K1FREE (1 << 24) /* SDRAM Free-Running Control */
# define MDREFR_K0FREE (1 << 23) /* SDRAM Free-Running Control */
# define MDREFR_SLFRSH (1 << 22) /* SDRAM Self-Refresh Control/Status */
# define MDREFR_APD (1 << 20) /* SDRAM/SSRAM Auto-Power-Down Enable */
# define MDREFR_K2DB2 (1 << 19) /* SDCLK2 Divide by 2 Control/Status */
# define MDREFR_K2RUN (1 << 18) /* SDCLK2 Run Control/Status */
# define MDREFR_K1DB2 (1 << 17) /* SDCLK1 Divide by 2 Control/Status */
# define MDREFR_K1RUN (1 << 16) /* SDCLK1 Run Control/Status */
# define MDREFR_E1PIN (1 << 15) /* SDCKE1 Level Control/Status */
# define MDREFR_K0DB2 (1 << 14) /* SDCLK0 Divide by 2 Control/Status */
# define MDREFR_K0RUN (1 << 13) /* SDCLK0 Run Control/Status */
# define MDREFR_E0PIN (1 << 12) /* SDCKE0 Level Control/Status */
# define MDREFR_DB2_MASK (MDREFR_K2DB2 | MDREFR_K1DB2)
# define MDREFR_DRI_MASK 0xFFF
2016-11-09 01:47:56 +03:00
static DEFINE_SPINLOCK ( pxa_clk_lock ) ;
2014-07-31 00:50:59 +04:00
static struct clk * pxa_clocks [ CLK_MAX ] ;
static struct clk_onecell_data onecell_data = {
. clks = pxa_clocks ,
. clk_num = CLK_MAX ,
} ;
2014-10-07 03:07:58 +04:00
struct pxa_clk {
struct clk_hw hw ;
struct clk_fixed_factor lp ;
struct clk_fixed_factor hp ;
struct clk_gate gate ;
bool ( * is_in_low_power ) ( void ) ;
} ;
# define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk, hw)
2014-07-31 00:50:59 +04:00
static unsigned long cken_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
2014-10-07 03:07:58 +04:00
struct pxa_clk * pclk = to_pxa_clk ( hw ) ;
2014-07-31 00:50:59 +04:00
struct clk_fixed_factor * fix ;
if ( ! pclk - > is_in_low_power | | pclk - > is_in_low_power ( ) )
fix = & pclk - > lp ;
else
fix = & pclk - > hp ;
2015-02-12 16:58:30 +03:00
__clk_hw_set_clk ( & fix - > hw , hw ) ;
2014-07-31 00:50:59 +04:00
return clk_fixed_factor_ops . recalc_rate ( & fix - > hw , parent_rate ) ;
}
2018-10-27 08:47:39 +03:00
static const struct clk_ops cken_rate_ops = {
2014-07-31 00:50:59 +04:00
. recalc_rate = cken_recalc_rate ,
} ;
static u8 cken_get_parent ( struct clk_hw * hw )
{
2014-10-07 03:07:58 +04:00
struct pxa_clk * pclk = to_pxa_clk ( hw ) ;
2014-07-31 00:50:59 +04:00
if ( ! pclk - > is_in_low_power )
return 0 ;
return pclk - > is_in_low_power ( ) ? 0 : 1 ;
}
2018-10-27 08:47:39 +03:00
static const struct clk_ops cken_mux_ops = {
2014-07-31 00:50:59 +04:00
. get_parent = cken_get_parent ,
. set_parent = dummy_clk_set_parent ,
} ;
void __init clkdev_pxa_register ( int ckid , const char * con_id ,
const char * dev_id , struct clk * clk )
{
if ( ! IS_ERR ( clk ) & & ( ckid ! = CLK_NONE ) )
pxa_clocks [ ckid ] = clk ;
if ( ! IS_ERR ( clk ) )
clk_register_clkdev ( clk , con_id , dev_id ) ;
}
2014-10-07 03:07:58 +04:00
int __init clk_pxa_cken_init ( const struct desc_clk_cken * clks , int nb_clks )
2014-07-31 00:50:59 +04:00
{
int i ;
2014-10-07 03:07:58 +04:00
struct pxa_clk * pxa_clk ;
2014-07-31 00:50:59 +04:00
struct clk * clk ;
for ( i = 0 ; i < nb_clks ; i + + ) {
2014-10-07 03:07:58 +04:00
pxa_clk = kzalloc ( sizeof ( * pxa_clk ) , GFP_KERNEL ) ;
pxa_clk - > is_in_low_power = clks [ i ] . is_in_low_power ;
pxa_clk - > lp = clks [ i ] . lp ;
pxa_clk - > hp = clks [ i ] . hp ;
pxa_clk - > gate = clks [ i ] . gate ;
2016-11-09 01:47:56 +03:00
pxa_clk - > gate . lock = & pxa_clk_lock ;
2014-10-07 03:07:58 +04:00
clk = clk_register_composite ( NULL , clks [ i ] . name ,
clks [ i ] . parent_names , 2 ,
& pxa_clk - > hw , & cken_mux_ops ,
& pxa_clk - > hw , & cken_rate_ops ,
& pxa_clk - > gate . hw , & clk_gate_ops ,
clks [ i ] . flags ) ;
clkdev_pxa_register ( clks [ i ] . ckid , clks [ i ] . con_id ,
clks [ i ] . dev_id , clk ) ;
2014-07-31 00:50:59 +04:00
}
return 0 ;
}
2014-10-07 03:07:59 +04:00
void __init clk_pxa_dt_common_init ( struct device_node * np )
2014-07-31 00:50:59 +04:00
{
of_clk_add_provider ( np , of_clk_src_onecell_get , & onecell_data ) ;
}
2016-11-03 00:33:06 +03:00
void pxa2xx_core_turbo_switch ( bool on )
{
unsigned long flags ;
unsigned int unused , clkcfg ;
local_irq_save ( flags ) ;
asm ( " mrc p14, 0, %0, c6, c0, 0 " : " =r " ( clkcfg ) ) ;
clkcfg & = ~ CLKCFG_TURBO & ~ CLKCFG_HALFTURBO ;
if ( on )
clkcfg | = CLKCFG_TURBO ;
clkcfg | = CLKCFG_FCS ;
asm volatile (
" b 2f \n "
" .align 5 \n "
" 1: mcr p14, 0, %1, c6, c0, 0 \n "
" b 3f \n "
" 2: b 1b \n "
" 3: nop \n "
2017-09-15 22:53:47 +03:00
: " =&r " ( unused ) : " r " ( clkcfg ) ) ;
2016-11-03 00:33:06 +03:00
local_irq_restore ( flags ) ;
}
void pxa2xx_cpll_change ( struct pxa2xx_freq * freq ,
2016-11-09 01:47:56 +03:00
u32 ( * mdrefr_dri ) ( unsigned int ) , void __iomem * mdrefr ,
void __iomem * cccr )
2016-11-03 00:33:06 +03:00
{
unsigned int clkcfg = freq - > clkcfg ;
unsigned int unused , preset_mdrefr , postset_mdrefr ;
unsigned long flags ;
local_irq_save ( flags ) ;
/* Calculate the next MDREFR. If we're slowing down the SDRAM clock
* we need to preset the smaller DRI before the change . If we ' re
* speeding up we need to set the larger DRI value after the change .
*/
preset_mdrefr = postset_mdrefr = readl ( mdrefr ) ;
if ( ( preset_mdrefr & MDREFR_DRI_MASK ) > mdrefr_dri ( freq - > membus_khz ) ) {
preset_mdrefr = ( preset_mdrefr & ~ MDREFR_DRI_MASK ) ;
preset_mdrefr | = mdrefr_dri ( freq - > membus_khz ) ;
}
postset_mdrefr =
( postset_mdrefr & ~ MDREFR_DRI_MASK ) |
mdrefr_dri ( freq - > membus_khz ) ;
/* If we're dividing the memory clock by two for the SDRAM clock, this
* must be set prior to the change . Clearing the divide must be done
* after the change .
*/
if ( freq - > div2 ) {
preset_mdrefr | = MDREFR_DB2_MASK ;
postset_mdrefr | = MDREFR_DB2_MASK ;
} else {
postset_mdrefr & = ~ MDREFR_DB2_MASK ;
}
/* Set new the CCCR and prepare CLKCFG */
writel ( freq - > cccr , cccr ) ;
asm volatile (
" ldr r4, [%1] \n "
" b 2f \n "
" .align 5 \n "
" 1: str %3, [%1] /* preset the MDREFR */ \n "
" mcr p14, 0, %2, c6, c0, 0 /* set CLKCFG[FCS] */ \n "
" str %4, [%1] /* postset the MDREFR */ \n "
" b 3f \n "
" 2: b 1b \n "
" 3: nop \n "
: " =&r " ( unused )
: " r " ( mdrefr ) , " r " ( clkcfg ) , " r " ( preset_mdrefr ) ,
" r " ( postset_mdrefr )
: " r4 " , " r5 " ) ;
local_irq_restore ( flags ) ;
}
int pxa2xx_determine_rate ( struct clk_rate_request * req ,
struct pxa2xx_freq * freqs , int nb_freqs )
{
2016-11-08 17:49:31 +03:00
int i , closest_below = - 1 , closest_above = - 1 ;
2016-11-03 00:33:06 +03:00
unsigned long rate ;
for ( i = 0 ; i < nb_freqs ; i + + ) {
rate = freqs [ i ] . cpll ;
if ( rate = = req - > rate )
break ;
if ( rate < req - > min_rate )
continue ;
if ( rate > req - > max_rate )
continue ;
if ( rate < = req - > rate )
closest_below = i ;
if ( ( rate > = req - > rate ) & & ( closest_above = = - 1 ) )
closest_above = i ;
}
req - > best_parent_hw = NULL ;
2016-11-08 17:49:31 +03:00
if ( i < nb_freqs ) {
rate = req - > rate ;
} else if ( closest_below > = 0 ) {
2016-11-03 00:33:06 +03:00
rate = freqs [ closest_below ] . cpll ;
2016-11-08 17:49:31 +03:00
} else if ( closest_above > = 0 ) {
2016-11-03 00:33:06 +03:00
rate = freqs [ closest_above ] . cpll ;
2016-11-08 17:49:31 +03:00
} else {
pr_debug ( " %s(rate=%lu) no match \n " , __func__ , req - > rate ) ;
return - EINVAL ;
}
2016-11-03 00:33:06 +03:00
2016-11-08 17:49:31 +03:00
pr_debug ( " %s(rate=%lu) rate=%lu \n " , __func__ , req - > rate , rate ) ;
req - > rate = rate ;
2016-11-03 00:33:06 +03:00
2016-11-08 17:49:31 +03:00
return 0 ;
2016-11-03 00:33:06 +03:00
}