2019-05-28 10:10:04 -07:00
// SPDX-License-Identifier: GPL-2.0-only
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
/*
* Copyright ( c ) 2012 , NVIDIA CORPORATION . All rights reserved .
*/
# include <linux/kernel.h>
# include <linux/io.h>
# include <linux/delay.h>
# include <linux/err.h>
# include <linux/slab.h>
# include <linux/clk-provider.h>
# include "clk.h"
# define SUPER_STATE_IDLE 0
# define SUPER_STATE_RUN 1
# define SUPER_STATE_IRQ 2
# define SUPER_STATE_FIQ 3
# define SUPER_STATE_SHIFT 28
# define SUPER_STATE_MASK ((BIT(SUPER_STATE_IDLE) | BIT(SUPER_STATE_RUN) | \
BIT ( SUPER_STATE_IRQ ) | BIT ( SUPER_STATE_FIQ ) ) \
< < SUPER_STATE_SHIFT )
# define SUPER_LP_DIV2_BYPASS (1 << 16)
# define super_state(s) (BIT(s) << SUPER_STATE_SHIFT)
# define super_state_to_src_shift(m, s) ((m->width * s))
# define super_state_to_src_mask(m) (((1 << m->width) - 1))
2019-08-16 12:41:54 -07:00
# define CCLK_SRC_PLLP_OUT0 4
# define CCLK_SRC_PLLP_OUT4 5
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
static u8 clk_super_get_parent ( struct clk_hw * hw )
{
struct tegra_clk_super_mux * mux = to_clk_super_mux ( hw ) ;
u32 val , state ;
u8 source , shift ;
val = readl_relaxed ( mux - > reg ) ;
state = val & SUPER_STATE_MASK ;
BUG_ON ( ( state ! = super_state ( SUPER_STATE_RUN ) ) & &
( state ! = super_state ( SUPER_STATE_IDLE ) ) ) ;
shift = ( state = = super_state ( SUPER_STATE_IDLE ) ) ?
super_state_to_src_shift ( mux , SUPER_STATE_IDLE ) :
super_state_to_src_shift ( mux , SUPER_STATE_RUN ) ;
source = ( val > > shift ) & super_state_to_src_mask ( mux ) ;
/*
* If LP_DIV2_BYPASS is not set and PLLX is current parent then
* PLLX / 2 is the input source to CCLKLP .
*/
if ( ( mux - > flags & TEGRA_DIVIDER_2 ) & & ! ( val & SUPER_LP_DIV2_BYPASS ) & &
( source = = mux - > pllx_index ) )
source = mux - > div2_index ;
return source ;
}
static int clk_super_set_parent ( struct clk_hw * hw , u8 index )
{
struct tegra_clk_super_mux * mux = to_clk_super_mux ( hw ) ;
u32 val , state ;
2013-02-07 18:24:14 +02:00
int err = 0 ;
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
u8 parent_index , shift ;
2013-02-07 18:24:14 +02:00
unsigned long flags = 0 ;
if ( mux - > lock )
spin_lock_irqsave ( mux - > lock , flags ) ;
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
val = readl_relaxed ( mux - > reg ) ;
state = val & SUPER_STATE_MASK ;
BUG_ON ( ( state ! = super_state ( SUPER_STATE_RUN ) ) & &
( state ! = super_state ( SUPER_STATE_IDLE ) ) ) ;
shift = ( state = = super_state ( SUPER_STATE_IDLE ) ) ?
super_state_to_src_shift ( mux , SUPER_STATE_IDLE ) :
super_state_to_src_shift ( mux , SUPER_STATE_RUN ) ;
/*
* For LP mode super - clock switch between PLLX direct
* and divided - by - 2 outputs is allowed only when other
* than PLLX clock source is current parent .
*/
if ( ( mux - > flags & TEGRA_DIVIDER_2 ) & & ( ( index = = mux - > div2_index ) | |
( index = = mux - > pllx_index ) ) ) {
parent_index = clk_super_get_parent ( hw ) ;
if ( ( parent_index = = mux - > div2_index ) | |
2013-02-07 18:24:14 +02:00
( parent_index = = mux - > pllx_index ) ) {
err = - EINVAL ;
goto out ;
}
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
val ^ = SUPER_LP_DIV2_BYPASS ;
writel_relaxed ( val , mux - > reg ) ;
udelay ( 2 ) ;
if ( index = = mux - > div2_index )
index = mux - > pllx_index ;
}
2019-08-16 12:41:54 -07:00
/* enable PLLP branches to CPU before selecting PLLP source */
if ( ( mux - > flags & TEGRA210_CPU_CLK ) & &
( index = = CCLK_SRC_PLLP_OUT0 | | index = = CCLK_SRC_PLLP_OUT4 ) )
tegra_clk_set_pllp_out_cpu ( true ) ;
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
val & = ~ ( ( super_state_to_src_mask ( mux ) ) < < shift ) ;
val | = ( index & ( super_state_to_src_mask ( mux ) ) ) < < shift ;
writel_relaxed ( val , mux - > reg ) ;
udelay ( 2 ) ;
2013-02-07 18:24:14 +02:00
2019-08-16 12:41:54 -07:00
/* disable PLLP branches to CPU if not used */
if ( ( mux - > flags & TEGRA210_CPU_CLK ) & &
index ! = CCLK_SRC_PLLP_OUT0 & & index ! = CCLK_SRC_PLLP_OUT4 )
tegra_clk_set_pllp_out_cpu ( false ) ;
2013-02-07 18:24:14 +02:00
out :
if ( mux - > lock )
spin_unlock_irqrestore ( mux - > lock , flags ) ;
return err ;
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
}
2019-08-16 12:41:55 -07:00
static void clk_super_mux_restore_context ( struct clk_hw * hw )
{
int parent_id ;
parent_id = clk_hw_get_parent_index ( hw ) ;
if ( WARN_ON ( parent_id < 0 ) )
return ;
clk_super_set_parent ( hw , parent_id ) ;
}
2019-03-19 23:35:04 +08:00
static const struct clk_ops tegra_clk_super_mux_ops = {
2017-02-28 16:37:21 +02:00
. get_parent = clk_super_get_parent ,
. set_parent = clk_super_set_parent ,
2019-08-16 12:41:55 -07:00
. restore_context = clk_super_mux_restore_context ,
2017-02-28 16:37:21 +02:00
} ;
static long clk_super_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * parent_rate )
{
struct tegra_clk_super_mux * super = to_clk_super_mux ( hw ) ;
struct clk_hw * div_hw = & super - > frac_div . hw ;
__clk_hw_set_clk ( div_hw , hw ) ;
return super - > div_ops - > round_rate ( div_hw , rate , parent_rate ) ;
}
static unsigned long clk_super_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct tegra_clk_super_mux * super = to_clk_super_mux ( hw ) ;
struct clk_hw * div_hw = & super - > frac_div . hw ;
__clk_hw_set_clk ( div_hw , hw ) ;
return super - > div_ops - > recalc_rate ( div_hw , parent_rate ) ;
}
static int clk_super_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct tegra_clk_super_mux * super = to_clk_super_mux ( hw ) ;
struct clk_hw * div_hw = & super - > frac_div . hw ;
__clk_hw_set_clk ( div_hw , hw ) ;
return super - > div_ops - > set_rate ( div_hw , rate , parent_rate ) ;
}
2019-08-16 12:41:55 -07:00
static void clk_super_restore_context ( struct clk_hw * hw )
{
struct tegra_clk_super_mux * super = to_clk_super_mux ( hw ) ;
struct clk_hw * div_hw = & super - > frac_div . hw ;
int parent_id ;
parent_id = clk_hw_get_parent_index ( hw ) ;
if ( WARN_ON ( parent_id < 0 ) )
return ;
super - > div_ops - > restore_context ( div_hw ) ;
clk_super_set_parent ( hw , parent_id ) ;
}
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
const struct clk_ops tegra_clk_super_ops = {
. get_parent = clk_super_get_parent ,
. set_parent = clk_super_set_parent ,
2017-02-28 16:37:21 +02:00
. set_rate = clk_super_set_rate ,
. round_rate = clk_super_round_rate ,
. recalc_rate = clk_super_recalc_rate ,
2019-08-16 12:41:55 -07:00
. restore_context = clk_super_restore_context ,
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
} ;
struct clk * tegra_clk_register_super_mux ( const char * name ,
const char * * parent_names , u8 num_parents ,
unsigned long flags , void __iomem * reg , u8 clk_super_flags ,
u8 width , u8 pllx_index , u8 div2_index , spinlock_t * lock )
{
struct tegra_clk_super_mux * super ;
struct clk * clk ;
struct clk_init_data init ;
super = kzalloc ( sizeof ( * super ) , GFP_KERNEL ) ;
2017-02-28 16:37:21 +02:00
if ( ! super )
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
return ERR_PTR ( - ENOMEM ) ;
init . name = name ;
2017-02-28 16:37:21 +02:00
init . ops = & tegra_clk_super_mux_ops ;
clk: tegra: add Tegra specific clocks
Add Tegra specific clocks, pll, pll_out, peripheral, frac_divider, super.
Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com>
[swarren: alloc sizeof(*foo) not sizeof(struct foo), add comments re:
storing pointers to stack variables, make a timeout loop more idiomatic,
use _clk_pll_disable() not clk_disable_pll() from _program_pll() to
avoid redundant lock operations, unified tegra_clk_periph() and
tegra_clk_periph_nodiv(), unified tegra_clk_pll{,e}, rename all clock
registration functions so they don't have the same name as the clock
structs, return -EINVAL from clk_plle_enable when matching table rate
not found, pass ops to _tegra_clk_register_pll rather than a bool.]
Acked-by: Mike Turquette <mturquette@linaro.org>
Signed-off-by: Stephen Warren <swarren@nvidia.com>
2013-01-11 13:16:20 +05:30
init . flags = flags ;
init . parent_names = parent_names ;
init . num_parents = num_parents ;
super - > reg = reg ;
super - > pllx_index = pllx_index ;
super - > div2_index = div2_index ;
super - > lock = lock ;
super - > width = width ;
super - > flags = clk_super_flags ;
/* Data in .init is copied by clk_register(), so stack variable OK */
super - > hw . init = & init ;
clk = clk_register ( NULL , & super - > hw ) ;
if ( IS_ERR ( clk ) )
kfree ( super ) ;
return clk ;
}
2017-02-28 16:37:21 +02:00
struct clk * tegra_clk_register_super_clk ( const char * name ,
const char * const * parent_names , u8 num_parents ,
unsigned long flags , void __iomem * reg , u8 clk_super_flags ,
spinlock_t * lock )
{
struct tegra_clk_super_mux * super ;
struct clk * clk ;
struct clk_init_data init ;
super = kzalloc ( sizeof ( * super ) , GFP_KERNEL ) ;
if ( ! super )
return ERR_PTR ( - ENOMEM ) ;
init . name = name ;
init . ops = & tegra_clk_super_ops ;
init . flags = flags ;
init . parent_names = parent_names ;
init . num_parents = num_parents ;
super - > reg = reg ;
super - > lock = lock ;
super - > width = 4 ;
super - > flags = clk_super_flags ;
super - > frac_div . reg = reg + 4 ;
super - > frac_div . shift = 16 ;
super - > frac_div . width = 8 ;
super - > frac_div . frac_width = 1 ;
super - > frac_div . lock = lock ;
super - > div_ops = & tegra_clk_frac_div_ops ;
/* Data in .init is copied by clk_register(), so stack variable OK */
super - > hw . init = & init ;
clk = clk_register ( NULL , & super - > hw ) ;
if ( IS_ERR ( clk ) )
kfree ( super ) ;
return clk ;
}