[PATCH v1 0/3] Implement support of simple PLL

Simple PLL clocks like PLLD2 were omitted since they do not share common 4 register structure with main clocks. Such clocks are contained in simple PLL group. Only clock_start_pll function supported them. This patch expands this support on clock_set_rate and clock_get_rate which should make simple PLL clocks equal to main PLL clocks.
Implementation was tested on T30/T114 using PLLD2 simple PLL (PLLD2 can serve as a video subsystem main clock and this is how it was tested).
Patches pass buildman ./tools/buildman/buildman tegra
Building current source for 33 boards (12 threads, 1 job per thread) 33 0 0 /33 colibri_t30 Completed: 33 total built, 33 newly), duration 0:06:25, rate 0.09
Svyatoslav Ryhel (3): ARM: tegra: clock: support get and set rate for simple PLL ARM: tegra30: clock: implement PLLD2 support ARM: tegra114: clock: implement PLLD2 support
arch/arm/include/asm/arch-tegra/clk_rst.h | 3 +- .../include/asm/arch-tegra114/clock-tables.h | 2 +- .../include/asm/arch-tegra30/clock-tables.h | 2 +- arch/arm/mach-tegra/clock.c | 78 ++++++++++++++----- arch/arm/mach-tegra/tegra114/clock.c | 22 ++++++ arch/arm/mach-tegra/tegra124/clock.c | 12 ++- arch/arm/mach-tegra/tegra20/clock.c | 15 ++++ arch/arm/mach-tegra/tegra210/clock.c | 15 ++++ arch/arm/mach-tegra/tegra30/clock.c | 22 ++++++ 9 files changed, 146 insertions(+), 25 deletions(-)

Simple PLL clocks like PLLD2 were omitted since they do not share common 4 register structure with main clocks. Such clocks are contained in simple PLL group. Only clock_start_pll function supported them. This patch expands this support on clock_set_rate and clock_get_rate which should make simple PLL clocks equal to main PLL clocks.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- arch/arm/mach-tegra/clock.c | 75 +++++++++++++++++++++------- arch/arm/mach-tegra/tegra114/clock.c | 15 ++++++ arch/arm/mach-tegra/tegra124/clock.c | 12 +++-- arch/arm/mach-tegra/tegra20/clock.c | 15 ++++++ arch/arm/mach-tegra/tegra210/clock.c | 15 ++++++ arch/arm/mach-tegra/tegra30/clock.c | 15 ++++++ 6 files changed, 126 insertions(+), 21 deletions(-)
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 966009f375..7f31630a23 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -128,14 +128,14 @@ unsigned long clock_start_pll(enum clock_id clkid, u32 divm, u32 divn, struct clk_pll_simple *simple_pll = NULL; u32 misc_data, data;
- if (clkid < (enum clock_id)TEGRA_CLK_PLLS) { + if (clkid < (enum clock_id)TEGRA_CLK_PLLS) pll = get_pll(clkid); - } else { + else simple_pll = clock_get_simple_pll(clkid); - if (!simple_pll) { - debug("%s: Uknown simple PLL %d\n", __func__, clkid); - return 0; - } + + if (!simple_pll && !pll) { + log_err("Unknown PLL id %d\n", clkid); + return 0; }
/* @@ -542,7 +542,8 @@ unsigned int __weak clk_m_get_rate(unsigned int parent_rate)
unsigned clock_get_rate(enum clock_id clkid) { - struct clk_pll *pll; + struct clk_pll *pll = NULL; + struct clk_pll_simple *simple_pll = NULL; u32 base, divm; u64 parent_rate, rate; struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid]; @@ -554,10 +555,20 @@ unsigned clock_get_rate(enum clock_id clkid) if (clkid == CLOCK_ID_CLK_M) return clk_m_get_rate(parent_rate);
- pll = get_pll(clkid); - if (!pll) + if (clkid < (enum clock_id)TEGRA_CLK_PLLS) + pll = get_pll(clkid); + else + simple_pll = clock_get_simple_pll(clkid); + + if (!simple_pll && !pll) { + log_err("Unknown PLL id %d\n", clkid); return 0; - base = readl(&pll->pll_base); + } + + if (pll) + base = readl(&pll->pll_base); + else + base = readl(&simple_pll->pll_base);
rate = parent_rate * ((base >> pllinfo->n_shift) & pllinfo->n_mask); divm = (base >> pllinfo->m_shift) & pllinfo->m_mask; @@ -599,12 +610,24 @@ unsigned clock_get_rate(enum clock_id clkid) int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon) { u32 base_reg, misc_reg; - struct clk_pll *pll; + struct clk_pll *pll = NULL; + struct clk_pll_simple *simple_pll = NULL; struct clk_pll_info *pllinfo = &tegra_pll_info_table[clkid];
- pll = get_pll(clkid); + if (clkid < (enum clock_id)TEGRA_CLK_PLLS) + pll = get_pll(clkid); + else + simple_pll = clock_get_simple_pll(clkid); + + if (!simple_pll && !pll) { + log_err("Unknown PLL id %d\n", clkid); + return 0; + }
- base_reg = readl(&pll->pll_base); + if (pll) + base_reg = readl(&pll->pll_base); + else + base_reg = readl(&simple_pll->pll_base);
/* Set BYPASS, m, n and p to PLL_BASE */ base_reg &= ~(pllinfo->m_mask << pllinfo->m_shift); @@ -631,21 +654,37 @@ int clock_set_rate(enum clock_id clkid, u32 n, u32 m, u32 p, u32 cpcon) }
base_reg |= PLL_BYPASS_MASK; - writel(base_reg, &pll->pll_base); + if (pll) + writel(base_reg, &pll->pll_base); + else + writel(base_reg, &simple_pll->pll_base);
/* Set cpcon (KCP) to PLL_MISC */ - misc_reg = readl(&pll->pll_misc); + if (pll) + misc_reg = readl(&pll->pll_misc); + else + misc_reg = readl(&simple_pll->pll_misc); + misc_reg &= ~(pllinfo->kcp_mask << pllinfo->kcp_shift); misc_reg |= cpcon << pllinfo->kcp_shift; - writel(misc_reg, &pll->pll_misc); + if (pll) + writel(misc_reg, &pll->pll_misc); + else + writel(misc_reg, &simple_pll->pll_misc);
/* Enable PLL */ base_reg |= PLL_ENABLE_MASK; - writel(base_reg, &pll->pll_base); + if (pll) + writel(base_reg, &pll->pll_base); + else + writel(base_reg, &simple_pll->pll_base);
/* Disable BYPASS */ base_reg &= ~PLL_BYPASS_MASK; - writel(base_reg, &pll->pll_base); + if (pll) + writel(base_reg, &pll->pll_base); + else + writel(base_reg, &simple_pll->pll_base);
return 0; } diff --git a/arch/arm/mach-tegra/tegra114/clock.c b/arch/arm/mach-tegra/tegra114/clock.c index 8ad71f590f..9a8c10e3d6 100644 --- a/arch/arm/mach-tegra/tegra114/clock.c +++ b/arch/arm/mach-tegra/tegra114/clock.c @@ -768,6 +768,21 @@ void arch_timer_init(void) debug("%s: TSC CNTCR = 0x%08X\n", __func__, val); }
+struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid) +{ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + + switch (clkid) { + case CLOCK_ID_XCPU: + case CLOCK_ID_EPCI: + case CLOCK_ID_SFROM32KHZ: + return &clkrst->crc_pll_simple[clkid - CLOCK_ID_FIRST_SIMPLE]; + default: + return NULL; + } +} + struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SBC1, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC2, CLOCK_ID_PERIPH }, diff --git a/arch/arm/mach-tegra/tegra124/clock.c b/arch/arm/mach-tegra/tegra124/clock.c index ca9549a318..ed8b6d9638 100644 --- a/arch/arm/mach-tegra/tegra124/clock.c +++ b/arch/arm/mach-tegra/tegra124/clock.c @@ -1189,10 +1189,16 @@ struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid) struct clk_rst_ctlr *clkrst = (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE;
- if (clkid == CLOCK_ID_DP) + switch (clkid) { + case CLOCK_ID_XCPU: + case CLOCK_ID_EPCI: + case CLOCK_ID_SFROM32KHZ: + return &clkrst->crc_pll_simple[clkid - CLOCK_ID_FIRST_SIMPLE]; + case CLOCK_ID_DP: return &clkrst->plldp; - - return NULL; + default: + return NULL; + } }
struct periph_clk_init periph_clk_init_table[] = { diff --git a/arch/arm/mach-tegra/tegra20/clock.c b/arch/arm/mach-tegra/tegra20/clock.c index abd6e3917a..109b73bfbe 100644 --- a/arch/arm/mach-tegra/tegra20/clock.c +++ b/arch/arm/mach-tegra/tegra20/clock.c @@ -792,6 +792,21 @@ int tegra_plle_enable(void) return 0; }
+struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid) +{ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + + switch (clkid) { + case CLOCK_ID_XCPU: + case CLOCK_ID_EPCI: + case CLOCK_ID_SFROM32KHZ: + return &clkrst->crc_pll_simple[clkid - CLOCK_ID_FIRST_SIMPLE]; + default: + return NULL; + } +} + struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SPI1, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC1, CLOCK_ID_PERIPH }, diff --git a/arch/arm/mach-tegra/tegra210/clock.c b/arch/arm/mach-tegra/tegra210/clock.c index 900537afbe..74817e0440 100644 --- a/arch/arm/mach-tegra/tegra210/clock.c +++ b/arch/arm/mach-tegra/tegra210/clock.c @@ -1266,6 +1266,21 @@ int tegra_plle_enable(void) return 0; }
+struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid) +{ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + + switch (clkid) { + case CLOCK_ID_XCPU: + case CLOCK_ID_EPCI: + case CLOCK_ID_SFROM32KHZ: + return &clkrst->crc_pll_simple[clkid - CLOCK_ID_FIRST_SIMPLE]; + default: + return NULL; + } +} + struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SBC1, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC2, CLOCK_ID_PERIPH }, diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c index 698c7ab956..7bbe70921f 100644 --- a/arch/arm/mach-tegra/tegra30/clock.c +++ b/arch/arm/mach-tegra/tegra30/clock.c @@ -871,6 +871,21 @@ int tegra_plle_enable(void) return 0; }
+struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid) +{ + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + + switch (clkid) { + case CLOCK_ID_XCPU: + case CLOCK_ID_EPCI: + case CLOCK_ID_SFROM32KHZ: + return &clkrst->crc_pll_simple[clkid - CLOCK_ID_FIRST_SIMPLE]; + default: + return NULL; + } +} + struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SBC1, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC2, CLOCK_ID_PERIPH },

PLLD2 is a simple clock (controlled by 2 registers) and appears starting from T30. Primary use of PLLD2 is as main HDMI clock parent.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- arch/arm/include/asm/arch-tegra/clk_rst.h | 3 +-- arch/arm/include/asm/arch-tegra30/clock-tables.h | 2 +- arch/arm/mach-tegra/clock.c | 3 +++ arch/arm/mach-tegra/tegra30/clock.c | 7 +++++++ 4 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/arch/arm/include/asm/arch-tegra/clk_rst.h b/arch/arm/include/asm/arch-tegra/clk_rst.h index 2359e142fb..04910d594e 100644 --- a/arch/arm/include/asm/arch-tegra/clk_rst.h +++ b/arch/arm/include/asm/arch-tegra/clk_rst.h @@ -174,8 +174,7 @@ struct clk_rst_ctlr { uint crc_audio_sync_clk_i2s4; /* _AUDIO_SYNC_CLK_I2S4_0, 0x4B0 */ uint crc_audio_sync_clk_spdif; /* _AUDIO_SYNC_CLK_SPDIF_0, 0x4B4 */
- uint crc_plld2_base; /* _PLLD2_BASE_0, 0x4B8 */ - uint crc_plld2_misc; /* _PLLD2_MISC_0, 0x4BC */ + struct clk_pll_simple plld2; /* _PLLD2_BASE_0, 0x4B8 */ uint crc_utmip_pll_cfg3; /* _UTMIP_PLL_CFG3_0, 0x4C0 */ uint crc_pllrefe_base; /* _PLLREFE_BASE_0, 0x4C4 */ uint crc_pllrefe_misc; /* _PLLREFE_MISC_0, 0x4C8 */ diff --git a/arch/arm/include/asm/arch-tegra30/clock-tables.h b/arch/arm/include/asm/arch-tegra30/clock-tables.h index 6c899ff64c..5ebcbc2c9a 100644 --- a/arch/arm/include/asm/arch-tegra30/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra30/clock-tables.h @@ -23,6 +23,7 @@ enum clock_id { CLOCK_ID_XCPU = CLOCK_ID_FIRST_SIMPLE, CLOCK_ID_EPCI, CLOCK_ID_SFROM32KHZ, + CLOCK_ID_DISPLAY2,
/* These are the base clocks (inputs to the Tegra SOC) */ CLOCK_ID_32KHZ, @@ -30,7 +31,6 @@ enum clock_id { CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of PLLs */ - CLOCK_ID_DISPLAY2, /* Tegra3, placeholder */ CLOCK_ID_NONE = -1, };
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 7f31630a23..575da2bdb5 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -768,6 +768,9 @@ void clock_init(void) pll_rate[CLOCK_ID_SFROM32KHZ] = 32768; pll_rate[CLOCK_ID_OSC] = clock_get_rate(CLOCK_ID_OSC); pll_rate[CLOCK_ID_CLK_M] = clock_get_rate(CLOCK_ID_CLK_M); +#ifndef CONFIG_TEGRA20 + pll_rate[CLOCK_ID_DISPLAY2] = clock_get_rate(CLOCK_ID_DISPLAY2); +#endif
debug("Osc = %d\n", pll_rate[CLOCK_ID_OSC]); debug("CLKM = %d\n", pll_rate[CLOCK_ID_CLK_M]); diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c index 7bbe70921f..0af8cde8c6 100644 --- a/arch/arm/mach-tegra/tegra30/clock.c +++ b/arch/arm/mach-tegra/tegra30/clock.c @@ -438,6 +438,8 @@ struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = { .lock_ena = 9, .lock_det = 11, .kcp_shift = 6, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLE */ { .m_shift = 0, .m_mask = 0x0F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07, .lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLS (RESERVED) */ + { .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07, + .lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLD2 */ };
/* @@ -654,6 +656,9 @@ enum clock_id clk_id_to_pll_id(int clk_id) case TEGRA30_CLK_PLL_D: case TEGRA30_CLK_PLL_D_OUT0: return CLOCK_ID_DISPLAY; + case TEGRA30_CLK_PLL_D2: + case TEGRA30_CLK_PLL_D2_OUT0: + return CLOCK_ID_DISPLAY2; case TEGRA30_CLK_PLL_X: return CLOCK_ID_XCPU; case TEGRA30_CLK_PLL_E: @@ -881,6 +886,8 @@ struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid) case CLOCK_ID_EPCI: case CLOCK_ID_SFROM32KHZ: return &clkrst->crc_pll_simple[clkid - CLOCK_ID_FIRST_SIMPLE]; + case CLOCK_ID_DISPLAY2: + return &clkrst->plld2; default: return NULL; }

PLLD2 is a simple clock (controlled by 2 registers) and appears starting from T30. Primary use of PLLD2 is as main HDMI clock parent.
Signed-off-by: Svyatoslav Ryhel clamor95@gmail.com --- arch/arm/include/asm/arch-tegra114/clock-tables.h | 2 +- arch/arm/mach-tegra/tegra114/clock.c | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/arm/include/asm/arch-tegra114/clock-tables.h b/arch/arm/include/asm/arch-tegra114/clock-tables.h index 9b95b339e2..95fadd0c59 100644 --- a/arch/arm/include/asm/arch-tegra114/clock-tables.h +++ b/arch/arm/include/asm/arch-tegra114/clock-tables.h @@ -23,6 +23,7 @@ enum clock_id { CLOCK_ID_XCPU = CLOCK_ID_FIRST_SIMPLE, CLOCK_ID_EPCI, CLOCK_ID_SFROM32KHZ, + CLOCK_ID_DISPLAY2,
/* These are the base clocks (inputs to the Tegra SOC) */ CLOCK_ID_32KHZ, @@ -30,7 +31,6 @@ enum clock_id { CLOCK_ID_CLK_M,
CLOCK_ID_COUNT, /* number of PLLs */ - CLOCK_ID_DISPLAY2, /* placeholder */ CLOCK_ID_NONE = -1, };
diff --git a/arch/arm/mach-tegra/tegra114/clock.c b/arch/arm/mach-tegra/tegra114/clock.c index 9a8c10e3d6..418ad48ddc 100644 --- a/arch/arm/mach-tegra/tegra114/clock.c +++ b/arch/arm/mach-tegra/tegra114/clock.c @@ -457,6 +457,8 @@ struct clk_pll_info tegra_pll_info_table[CLOCK_ID_PLL_COUNT] = { .lock_ena = 9, .lock_det = 11, .kcp_shift = 6, .kcp_mask = 3, .kvco_shift = 0, .kvco_mask = 1 }, /* PLLE */ { .m_shift = 0, .m_mask = 0x0F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07, .lock_ena = 18, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLS (RESERVED) */ + { .m_shift = 0, .m_mask = 0x1F, .n_shift = 8, .n_mask = 0x3FF, .p_shift = 20, .p_mask = 0x07, + .lock_ena = 22, .lock_det = 27, .kcp_shift = 8, .kcp_mask = 0xF, .kvco_shift = 4, .kvco_mask = 0xF }, /* PLLD2 */ };
/* @@ -671,6 +673,9 @@ enum clock_id clk_id_to_pll_id(int clk_id) case TEGRA114_CLK_PLL_D: case TEGRA114_CLK_PLL_D_OUT0: return CLOCK_ID_DISPLAY; + case TEGRA114_CLK_PLL_D2: + case TEGRA114_CLK_PLL_D2_OUT0: + return CLOCK_ID_DISPLAY2; case TEGRA114_CLK_PLL_X: return CLOCK_ID_XCPU; case TEGRA114_CLK_PLL_E_OUT0: @@ -778,6 +783,8 @@ struct clk_pll_simple *clock_get_simple_pll(enum clock_id clkid) case CLOCK_ID_EPCI: case CLOCK_ID_SFROM32KHZ: return &clkrst->crc_pll_simple[clkid - CLOCK_ID_FIRST_SIMPLE]; + case CLOCK_ID_DISPLAY2: + return &clkrst->plld2; default: return NULL; }
participants (1)
-
Svyatoslav Ryhel