Merge branch 'for-5.14/clk' into for-5.14/memory

This commit is contained in:
Thierry Reding 2021-06-01 13:38:23 +02:00
commit dd44ca5164
10 changed files with 168 additions and 80 deletions

View File

@ -48,36 +48,45 @@ static int clk_periph_is_enabled(struct clk_hw *hw)
return state;
}
static int clk_periph_enable(struct clk_hw *hw)
static void clk_periph_enable_locked(struct clk_hw *hw)
{
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
unsigned long flags = 0;
spin_lock_irqsave(&periph_ref_lock, flags);
gate->enable_refcnt[gate->clk_num]++;
if (gate->enable_refcnt[gate->clk_num] > 1) {
spin_unlock_irqrestore(&periph_ref_lock, flags);
return 0;
}
write_enb_set(periph_clk_to_bit(gate), gate);
udelay(2);
if (!(gate->flags & TEGRA_PERIPH_NO_RESET) &&
!(gate->flags & TEGRA_PERIPH_MANUAL_RESET)) {
if (read_rst(gate) & periph_clk_to_bit(gate)) {
udelay(5); /* reset propogation delay */
write_rst_clr(periph_clk_to_bit(gate), gate);
}
}
if (gate->flags & TEGRA_PERIPH_WAR_1005168) {
writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
writel_relaxed(BIT(22), gate->clk_base + LVL2_CLK_GATE_OVRE);
udelay(1);
writel_relaxed(0, gate->clk_base + LVL2_CLK_GATE_OVRE);
}
}
static void clk_periph_disable_locked(struct clk_hw *hw)
{
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
/*
* If peripheral is in the APB bus then read the APB bus to
* flush the write operation in apb bus. This will avoid the
* peripheral access after disabling clock
*/
if (gate->flags & TEGRA_PERIPH_ON_APB)
tegra_read_chipid();
write_enb_clr(periph_clk_to_bit(gate), gate);
}
static int clk_periph_enable(struct clk_hw *hw)
{
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
unsigned long flags = 0;
spin_lock_irqsave(&periph_ref_lock, flags);
if (!gate->enable_refcnt[gate->clk_num]++)
clk_periph_enable_locked(hw);
spin_unlock_irqrestore(&periph_ref_lock, flags);
@ -91,21 +100,28 @@ static void clk_periph_disable(struct clk_hw *hw)
spin_lock_irqsave(&periph_ref_lock, flags);
gate->enable_refcnt[gate->clk_num]--;
if (gate->enable_refcnt[gate->clk_num] > 0) {
spin_unlock_irqrestore(&periph_ref_lock, flags);
return;
}
WARN_ON(!gate->enable_refcnt[gate->clk_num]);
if (--gate->enable_refcnt[gate->clk_num] == 0)
clk_periph_disable_locked(hw);
spin_unlock_irqrestore(&periph_ref_lock, flags);
}
static void clk_periph_disable_unused(struct clk_hw *hw)
{
struct tegra_clk_periph_gate *gate = to_clk_periph_gate(hw);
unsigned long flags = 0;
spin_lock_irqsave(&periph_ref_lock, flags);
/*
* If peripheral is in the APB bus then read the APB bus to
* flush the write operation in apb bus. This will avoid the
* peripheral access after disabling clock
* Some clocks are duplicated and some of them are marked as critical,
* like fuse and fuse_burn for example, thus the enable_refcnt will
* be non-zero here if the "unused" duplicate is disabled by CCF.
*/
if (gate->flags & TEGRA_PERIPH_ON_APB)
tegra_read_chipid();
write_enb_clr(periph_clk_to_bit(gate), gate);
if (!gate->enable_refcnt[gate->clk_num])
clk_periph_disable_locked(hw);
spin_unlock_irqrestore(&periph_ref_lock, flags);
}
@ -114,6 +130,7 @@ const struct clk_ops tegra_clk_periph_gate_ops = {
.is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable,
.disable = clk_periph_disable,
.disable_unused = clk_periph_disable_unused,
};
struct clk *tegra_clk_register_periph_gate(const char *name,
@ -148,9 +165,6 @@ struct clk *tegra_clk_register_periph_gate(const char *name,
gate->enable_refcnt = enable_refcnt;
gate->regs = pregs;
if (read_enb(gate) & periph_clk_to_bit(gate))
enable_refcnt[clk_num]++;
/* Data in .init is copied by clk_register(), so stack variable OK */
gate->hw.init = &init;

View File

@ -100,6 +100,15 @@ static void clk_periph_disable(struct clk_hw *hw)
gate_ops->disable(gate_hw);
}
static void clk_periph_disable_unused(struct clk_hw *hw)
{
struct tegra_clk_periph *periph = to_clk_periph(hw);
const struct clk_ops *gate_ops = periph->gate_ops;
struct clk_hw *gate_hw = &periph->gate.hw;
gate_ops->disable_unused(gate_hw);
}
static void clk_periph_restore_context(struct clk_hw *hw)
{
struct tegra_clk_periph *periph = to_clk_periph(hw);
@ -126,6 +135,7 @@ const struct clk_ops tegra_clk_periph_ops = {
.is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable,
.disable = clk_periph_disable,
.disable_unused = clk_periph_disable_unused,
.restore_context = clk_periph_restore_context,
};
@ -135,6 +145,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
.is_enabled = clk_periph_is_enabled,
.enable = clk_periph_enable,
.disable = clk_periph_disable,
.disable_unused = clk_periph_disable_unused,
.restore_context = clk_periph_restore_context,
};

View File

@ -558,6 +558,9 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
u32 p_div = 0;
int ret;
if (!rate)
return -EINVAL;
switch (parent_rate) {
case 12000000:
case 26000000:
@ -1131,7 +1134,8 @@ static int clk_pllu_enable(struct clk_hw *hw)
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
_clk_pll_enable(hw);
if (!clk_pll_is_enabled(hw))
_clk_pll_enable(hw);
ret = clk_pll_wait_for_lock(pll);
if (ret < 0)
@ -1748,15 +1752,13 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw)
return -EINVAL;
}
if (clk_pll_is_enabled(hw))
return 0;
input_rate = clk_hw_get_rate(__clk_get_hw(osc));
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
_clk_pll_enable(hw);
if (!clk_pll_is_enabled(hw))
_clk_pll_enable(hw);
ret = clk_pll_wait_for_lock(pll);
if (ret < 0)

View File

@ -712,9 +712,9 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX8("ndflash", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash_8),
MUX8("ndspeed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed_8),
MUX8("hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, 0, tegra_clk_hdmi),
MUX8("extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, 0, tegra_clk_extern1),
MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, 0, tegra_clk_extern2),
MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, 0, tegra_clk_extern3),
MUX8("extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, TEGRA_PERIPH_NO_RESET, tegra_clk_extern1),
MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, TEGRA_PERIPH_NO_RESET, tegra_clk_extern2),
MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, TEGRA_PERIPH_NO_RESET, tegra_clk_extern3),
MUX8("soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm),
MUX8("soc_therm", mux_clkm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm_8),
MUX8("vi_sensor", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 164, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_8),

View File

@ -25,6 +25,8 @@
#define SUPER_CDIV_ENB BIT(31)
#define TSENSOR_SLOWDOWN BIT(23)
static struct tegra_clk_super_mux *cclk_super;
static bool cclk_on_pllx;
@ -47,10 +49,20 @@ static int cclk_super_set_rate(struct clk_hw *hw, unsigned long rate,
static unsigned long cclk_super_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
if (cclk_super_get_parent(hw) == PLLX_INDEX)
return parent_rate;
struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
u32 val = readl_relaxed(super->reg);
unsigned int div2;
return tegra_clk_super_ops.recalc_rate(hw, parent_rate);
/* check whether thermal throttling is active */
if (val & TSENSOR_SLOWDOWN)
div2 = 1;
else
div2 = 0;
if (cclk_super_get_parent(hw) == PLLX_INDEX)
return parent_rate >> div2;
return tegra_clk_super_ops.recalc_rate(hw, parent_rate) >> div2;
}
static int cclk_super_determine_rate(struct clk_hw *hw,

View File

@ -1021,9 +1021,9 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 },
{ TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 },
{ TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 0 },
{ TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 240000000, 0 },
{ TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 240000000, 0 },
{ TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 240000000, 0 },
{ TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 0 },
{ TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 120000000, 0 },
{ TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 120000000, 0 },
{ TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 0 },
{ TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1 },
{ TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1 },

View File

@ -930,7 +930,7 @@ static void __init tegra30_super_clk_init(void)
/* CCLKG */
clk = tegra_clk_register_super_cclk("cclk_g", cclk_g_parents,
ARRAY_SIZE(cclk_g_parents),
CLK_SET_RATE_PARENT,
CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
clk_base + CCLKG_BURST_POLICY,
0, NULL);
clks[TEGRA30_CLK_CCLK_G] = clk;
@ -1006,7 +1006,7 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {
TEGRA_INIT_DATA_MUX("dam0", mux_pllacp_clkm, CLK_SOURCE_DAM0, 108, 0, TEGRA30_CLK_DAM0),
TEGRA_INIT_DATA_MUX("dam1", mux_pllacp_clkm, CLK_SOURCE_DAM1, 109, 0, TEGRA30_CLK_DAM1),
TEGRA_INIT_DATA_MUX("dam2", mux_pllacp_clkm, CLK_SOURCE_DAM2, 110, 0, TEGRA30_CLK_DAM2),
TEGRA_INIT_DATA_INT("3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, TEGRA_PERIPH_MANUAL_RESET, TEGRA30_CLK_GR3D2),
TEGRA_INIT_DATA_INT("3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, 0, TEGRA30_CLK_GR3D2),
TEGRA_INIT_DATA_INT("se", mux_pllpcm_clkm, CLK_SOURCE_SE, 127, 0, TEGRA30_CLK_SE),
TEGRA_INIT_DATA_MUX8("hdmi", mux_pllpmdacd2_clkm, CLK_SOURCE_HDMI, 51, 0, TEGRA30_CLK_HDMI),
TEGRA_INIT_DATA("pwm", NULL, NULL, pwm_parents, CLK_SOURCE_PWM, 28, 2, 0, 0, 8, 1, 0, 17, TEGRA_PERIPH_ON_APB, TEGRA30_CLK_PWM),
@ -1245,7 +1245,7 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{ TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0 },
{ TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0 },
{ TEGRA30_CLK_PLL_U, TEGRA30_CLK_CLK_MAX, 480000000, 0 },
{ TEGRA30_CLK_VDE, TEGRA30_CLK_PLL_C, 600000000, 0 },
{ TEGRA30_CLK_VDE, TEGRA30_CLK_PLL_C, 300000000, 0 },
{ TEGRA30_CLK_SPDIF_IN_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
{ TEGRA30_CLK_I2S0_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },
{ TEGRA30_CLK_I2S1_SYNC, TEGRA30_CLK_CLK_MAX, 24000000, 0 },

View File

@ -553,9 +553,6 @@ struct tegra_clk_periph_regs {
* Flags:
* TEGRA_PERIPH_NO_RESET - This flag indicates that reset is not allowed
* for this module.
* TEGRA_PERIPH_MANUAL_RESET - This flag indicates not to reset module
* after clock enable and driver for the module is responsible for
* doing reset.
* TEGRA_PERIPH_ON_APB - If peripheral is in the APB bus then read the
* bus to flush the write operation in apb bus. This flag indicates
* that this peripheral is in apb bus.
@ -577,7 +574,6 @@ struct tegra_clk_periph_gate {
#define TEGRA_CLK_PERIPH_GATE_MAGIC 0x17760309
#define TEGRA_PERIPH_NO_RESET BIT(0)
#define TEGRA_PERIPH_MANUAL_RESET BIT(1)
#define TEGRA_PERIPH_ON_APB BIT(2)
#define TEGRA_PERIPH_WAR_1005168 BIT(3)
#define TEGRA_PERIPH_NO_DIV BIT(4)

View File

@ -743,11 +743,6 @@ out:
return err;
}
int __weak tegra210_clk_handle_mbist_war(unsigned int id)
{
return 0;
}
static int tegra_powergate_power_up(struct tegra_powergate *pg,
bool disable_clocks)
{

View File

@ -123,20 +123,6 @@ static inline void tegra_cpu_clock_resume(void)
}
#endif
extern int tegra210_plle_hw_sequence_start(void);
extern bool tegra210_plle_hw_sequence_is_enabled(void);
extern void tegra210_xusb_pll_hw_control_enable(void);
extern void tegra210_xusb_pll_hw_sequence_start(void);
extern void tegra210_sata_pll_hw_control_enable(void);
extern void tegra210_sata_pll_hw_sequence_start(void);
extern void tegra210_set_sata_pll_seq_sw(bool state);
extern void tegra210_put_utmipll_in_iddq(void);
extern void tegra210_put_utmipll_out_iddq(void);
extern int tegra210_clk_handle_mbist_war(unsigned int id);
extern void tegra210_clk_emc_dll_enable(bool flag);
extern void tegra210_clk_emc_dll_update_setting(u32 emc_dll_src_value);
extern void tegra210_clk_emc_update_setting(u32 emc_src_value);
struct clk;
struct tegra_emc;
@ -144,17 +130,10 @@ typedef long (tegra20_clk_emc_round_cb)(unsigned long rate,
unsigned long min_rate,
unsigned long max_rate,
void *arg);
void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
void *cb_arg);
int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same);
typedef int (tegra124_emc_prepare_timing_change_cb)(struct tegra_emc *emc,
unsigned long rate);
typedef void (tegra124_emc_complete_timing_change_cb)(struct tegra_emc *emc,
unsigned long rate);
void tegra124_clk_set_emc_callbacks(tegra124_emc_prepare_timing_change_cb *prep_cb,
tegra124_emc_complete_timing_change_cb *complete_cb);
struct tegra210_clk_emc_config {
unsigned long rate;
@ -176,8 +155,87 @@ struct tegra210_clk_emc_provider {
const struct tegra210_clk_emc_config *config);
};
#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
void tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
void *cb_arg);
int tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same);
#else
static inline void
tegra20_clk_set_emc_round_callback(tegra20_clk_emc_round_cb *round_cb,
void *cb_arg)
{
}
static inline int
tegra20_clk_prepare_emc_mc_same_freq(struct clk *emc_clk, bool same)
{
return 0;
}
#endif
#ifdef CONFIG_TEGRA124_CLK_EMC
void tegra124_clk_set_emc_callbacks(tegra124_emc_prepare_timing_change_cb *prep_cb,
tegra124_emc_complete_timing_change_cb *complete_cb);
#else
static inline void
tegra124_clk_set_emc_callbacks(tegra124_emc_prepare_timing_change_cb *prep_cb,
tegra124_emc_complete_timing_change_cb *complete_cb)
{
}
#endif
#ifdef CONFIG_ARCH_TEGRA_210_SOC
int tegra210_plle_hw_sequence_start(void);
bool tegra210_plle_hw_sequence_is_enabled(void);
void tegra210_xusb_pll_hw_control_enable(void);
void tegra210_xusb_pll_hw_sequence_start(void);
void tegra210_sata_pll_hw_control_enable(void);
void tegra210_sata_pll_hw_sequence_start(void);
void tegra210_set_sata_pll_seq_sw(bool state);
void tegra210_put_utmipll_in_iddq(void);
void tegra210_put_utmipll_out_iddq(void);
int tegra210_clk_handle_mbist_war(unsigned int id);
void tegra210_clk_emc_dll_enable(bool flag);
void tegra210_clk_emc_dll_update_setting(u32 emc_dll_src_value);
void tegra210_clk_emc_update_setting(u32 emc_src_value);
int tegra210_clk_emc_attach(struct clk *clk,
struct tegra210_clk_emc_provider *provider);
void tegra210_clk_emc_detach(struct clk *clk);
#else
static inline int tegra210_plle_hw_sequence_start(void)
{
return 0;
}
static inline bool tegra210_plle_hw_sequence_is_enabled(void)
{
return false;
}
static inline int tegra210_clk_handle_mbist_war(unsigned int id)
{
return 0;
}
static inline int
tegra210_clk_emc_attach(struct clk *clk,
struct tegra210_clk_emc_provider *provider)
{
return 0;
}
static inline void tegra210_xusb_pll_hw_control_enable(void) {}
static inline void tegra210_xusb_pll_hw_sequence_start(void) {}
static inline void tegra210_sata_pll_hw_control_enable(void) {}
static inline void tegra210_sata_pll_hw_sequence_start(void) {}
static inline void tegra210_set_sata_pll_seq_sw(bool state) {}
static inline void tegra210_put_utmipll_in_iddq(void) {}
static inline void tegra210_put_utmipll_out_iddq(void) {}
static inline void tegra210_clk_emc_dll_enable(bool flag) {}
static inline void tegra210_clk_emc_dll_update_setting(u32 emc_dll_src_value) {}
static inline void tegra210_clk_emc_update_setting(u32 emc_src_value) {}
static inline void tegra210_clk_emc_detach(struct clk *clk) {}
#endif
#endif /* __LINUX_CLK_TEGRA_H_ */