Commit 3f4e557d authored by Stephen Boyd's avatar Stephen Boyd

Merge tag 'for-5.14-clk' of...

Merge tag 'for-5.14-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into clk-nvidia

Pull Tegra clk driver updates from Thierry Reding:

This contains a few fixes across the board and adds stubs to allow
certain drivers to be compile-tested. One other notable change added
here is that clock enabling no longer deasserts the reset. Drivers are
now supposed to do that explicitly because doing it implicitly can get
in the way of certain power-up sequences.

* tag 'for-5.14-clk' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  clk: tegra: tegra124-emc: Fix clock imbalance in emc_set_timing()
  clk: tegra: Add stubs needed for compile-testing
  clk: tegra: Don't deassert reset on enabling clocks
  clk: tegra: Mark external clocks as not having reset control
  clk: tegra: cclk: Handle thermal DIV2 CPU frequency throttling
  clk: tegra: Don't allow zero clock rate for PLLs
  clk: tegra: Halve SCLK rate on Tegra20
  clk: tegra: Ensure that PLLU configuration is applied properly
  clk: tegra: Fix refcounting of gate clocks
  clk: tegra30: Use 300MHz for video decoder by default
parents 6efb943b f13570e7
......@@ -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;
......
......@@ -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,
};
......
......@@ -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)
......
......@@ -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),
......
......@@ -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)
{
struct tegra_clk_super_mux *super = to_clk_super_mux(hw);
u32 val = readl_relaxed(super->reg);
unsigned int div2;
/* 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;
return parent_rate >> div2;
return tegra_clk_super_ops.recalc_rate(hw, parent_rate);
return tegra_clk_super_ops.recalc_rate(hw, parent_rate) >> div2;
}
static int cclk_super_determine_rate(struct clk_hw *hw,
......
......@@ -249,8 +249,10 @@ static int emc_set_timing(struct tegra_clk_emc *tegra,
div = timing->parent_rate / (timing->rate / 2) - 2;
err = tegra->prepare_timing_change(emc, timing->rate);
if (err)
if (err) {
clk_disable_unprepare(timing->parent);
return err;
}
spin_lock_irqsave(tegra->lock, flags);
......
......@@ -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 },
......
......@@ -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 },
......
......@@ -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)
......
......@@ -743,11 +743,6 @@ static int tegra_powergate_enable_clocks(struct tegra_powergate *pg)
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)
{
......
......@@ -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_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment