tegra124: Revamp clock source/divisor configuration
The clock_ll_set_source_divisor() function has loads of issues, its ugly name only being the least of them. This patch replaces it with a nice little macro that allows you to very easily and cleanly specify the clock source and target frequency you want to use for a specific device, while automatically calculating the correct divisor bits at compile time. There's the small catch that Nvidia hardware designers in their great wisdom decided to just encode the same clock sources with different bits for a few devices. There's no easy way around this, so I suggest building this solution for the common case and writing the bits directly for those few outlier devices (right now we only need one of them). Also moves some clock source configuration code from display.c to clock.c so that we can lose the external dependency on clk_rst.h and hide all the ugly clock internals in one file (which I think is a cleaner architecture). This still won't prevent us from splitting the clock_config() function into individual smaller wrappers at a later point. BUG=None TEST=Booted, runs as good as before, dumped and compared all clock source registers to ensure they stayed the same. Change-Id: I2365c9167977eebe36fb1e8e48c7983cdd655f51 Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/174804
This commit is contained in:
parent
72365c3369
commit
3f31a634f6
4 changed files with 49 additions and 84 deletions
|
|
@ -425,24 +425,10 @@ enum {
|
|||
#define OSC_XOFS_MASK (0x3F << OSC_XOFS_SHIFT)
|
||||
#define OSC_DRIVE_STRENGTH 7
|
||||
|
||||
/*
|
||||
* CLK_RST_CONTROLLER_CLK_SOURCE_x_OUT_0 - the mask here is normally 8 bits
|
||||
* but can be 16. We could use knowledge we have to restrict the mask in
|
||||
* the 8-bit cases (the divider_bits value returned by
|
||||
* get_periph_clock_source()) but it does not seem worth it since the code
|
||||
* already checks the ranges of values it is writing, in clk_get_divider().
|
||||
*/
|
||||
#define CLK_DIVISOR_SHIFT 0
|
||||
#define CLK_DIVISOR_MASK (0xffff << CLK_DIVISOR_SHIFT)
|
||||
#define CLK_DIVISOR_MASK (0xffff)
|
||||
|
||||
#define CLK_SOURCE_SHIFT 30
|
||||
#define CLK_SOURCE_MASK (3U << CLK_SOURCE_SHIFT)
|
||||
|
||||
#define CLK_SOURCE3_SHIFT 29
|
||||
#define CLK_SOURCE3_MASK (7U << CLK_SOURCE3_SHIFT)
|
||||
|
||||
#define CLK_SOURCE4_SHIFT 28
|
||||
#define CLK_SOURCE4_MASK (15U << CLK_SOURCE4_SHIFT)
|
||||
#define CLK_SOURCE_SHIFT 29
|
||||
#define CLK_SOURCE_MASK (0x7 << CLK_SOURCE_SHIFT)
|
||||
|
||||
#define CLK_UART_DIV_OVERRIDE (1 << 24)
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,13 @@
|
|||
#include "flow.h"
|
||||
#include "pmc.h"
|
||||
|
||||
/* Warning: Some devices just use different bits for the same sources for no
|
||||
* apparent reason. *Always* double-check the TRM before trusting this macro. */
|
||||
#define clock_configure_source(device, src, freq) \
|
||||
clrsetbits_le32(&clk_rst->clk_src_##device, \
|
||||
CLK_SOURCE_MASK | CLK_DIVISOR_MASK, \
|
||||
src << CLK_SOURCE_SHIFT | CLK_DIVIDER(TEGRA_##src##_KHZ, freq));
|
||||
|
||||
static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE;
|
||||
static struct flow_ctlr *flow = (void *)TEGRA_FLOW_BASE;
|
||||
static struct tegra_pmc_regs *pmc = (void*)TEGRA_PMC_BASE;
|
||||
|
|
@ -143,23 +150,6 @@ struct {
|
|||
},
|
||||
};
|
||||
|
||||
// TODO(hungte) Some clock source are assigned in 3 or 4 bits
|
||||
// (OUT_CLK_SOURCE*_MASK/SHIFT), not always OUT_CLK_SOURCE_MASK/SHIFT.
|
||||
void clock_ll_set_source_divisor(u32 *reg, u32 source, u32 divisor)
|
||||
{
|
||||
u32 value;
|
||||
|
||||
value = readl(reg);
|
||||
|
||||
value &= ~CLK_SOURCE_MASK;
|
||||
value |= source << CLK_SOURCE_SHIFT;
|
||||
|
||||
value &= ~CLK_DIVISOR_MASK;
|
||||
value |= divisor << CLK_DIVISOR_SHIFT;
|
||||
|
||||
writel(value, reg);
|
||||
}
|
||||
|
||||
/* Get the oscillator frequency, from the corresponding hardware
|
||||
* configuration field. This is actually a per-soc thing. Avoid the
|
||||
* temptation to make it common.
|
||||
|
|
@ -214,8 +204,8 @@ static void init_pll(u32 *base, u32 *misc, const union pll_fields pll)
|
|||
* been determined through trial and error (must lead to div 13 at 24MHz). */
|
||||
void clock_early_uart(void)
|
||||
{
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_uarta, 3,
|
||||
CLK_UART_DIV_OVERRIDE | CLK_DIVIDER(clock_get_osc_khz(), 1800));
|
||||
write32(CLK_M << CLK_SOURCE_SHIFT | CLK_UART_DIV_OVERRIDE |
|
||||
CLK_DIVIDER(TEGRA_CLK_M_KHZ, 1800), &clk_rst->clk_src_uarta);
|
||||
setbits_le32(&clk_rst->clk_out_enb_l, CLK_L_UARTA);
|
||||
udelay(2);
|
||||
clrbits_le32(&clk_rst->rst_dev_l, CLK_L_UARTA);
|
||||
|
|
@ -332,7 +322,7 @@ void clock_config(void)
|
|||
/* TODO: can (should?) we use the _SET and _CLR registers here? */
|
||||
setbits_le32(&clk_rst->clk_out_enb_l,
|
||||
CLK_L_CACHE2 | CLK_L_GPIO | CLK_L_TMR | CLK_L_I2C1 |
|
||||
CLK_L_SDMMC4);
|
||||
CLK_L_SDMMC4 | CLK_L_DISP1 | CLK_L_HOST1X);
|
||||
setbits_le32(&clk_rst->clk_out_enb_h,
|
||||
CLK_H_EMC | CLK_H_I2C2 | CLK_H_I2C5 | CLK_H_SBC1 |
|
||||
CLK_H_PMC | CLK_H_APBDMA | CLK_H_MEM);
|
||||
|
|
@ -341,43 +331,37 @@ void clock_config(void)
|
|||
setbits_le32(&clk_rst->clk_out_enb_v, CLK_V_MSELECT | CLK_V_I2C4);
|
||||
setbits_le32(&clk_rst->clk_out_enb_w, CLK_W_DVFS);
|
||||
|
||||
/*
|
||||
* Set MSELECT clock source as PLLP (00)_REG, and ask for a clock
|
||||
* divider that would set the MSELECT clock at 102MHz for a
|
||||
* PLLP base of 408MHz.
|
||||
*/
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_mselect, 0,
|
||||
CLK_DIVIDER(TEGRA_PLLP_KHZ, 102000));
|
||||
|
||||
/* Give clock time to stabilize */
|
||||
udelay(IO_STABILIZATION_DELAY);
|
||||
|
||||
/* I2C1 gets CLK_M and a divisor of 17 */
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_i2c1, 3, 16);
|
||||
/* I2C2 gets CLK_M and a divisor of 17 */
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_i2c2, 3, 16);
|
||||
/* I2C3 (cam) gets CLK_M and a divisor of 17 */
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_i2c3, 3, 16);
|
||||
/* I2C4 (ddc) gets CLK_M and a divisor of 17 */
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_i2c4, 3, 16);
|
||||
/* I2C5 (PMU) gets CLK_M and a divisor of 17 */
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_i2c5, 3, 16);
|
||||
clock_configure_source(mselect, PLLP, 102000);
|
||||
|
||||
/* UARTA gets PLLP, deactivate CLK_UART_DIV_OVERRIDE */
|
||||
writel(0 << CLK_SOURCE_SHIFT, &clk_rst->clk_src_uarta);
|
||||
/* TODO: is the 1.333MHz correct? This may have always been bogus... */
|
||||
clock_configure_source(i2c1, CLK_M, 1333);
|
||||
clock_configure_source(i2c2, CLK_M, 1333);
|
||||
clock_configure_source(i2c3, CLK_M, 1333);
|
||||
clock_configure_source(i2c4, CLK_M, 1333);
|
||||
clock_configure_source(i2c5, CLK_M, 1333);
|
||||
|
||||
/* Move UARTA to PLLP and remove the CLK_UART_DIV_OVERRIDE */
|
||||
write32(PLLP << CLK_SOURCE_SHIFT, &clk_rst->clk_src_uarta);
|
||||
|
||||
/* MMC3 and MMC4: Set base clock frequency for SD Clock to Tegra MMC's
|
||||
* maximum speed (48MHz) so we can change SDCLK by second stage divisor
|
||||
* in payloads, without touching base clock.
|
||||
*
|
||||
* Note, parent clock source for MMC3/4 is PLLP_OUT0. MMC clock source
|
||||
* should be specified in 3 bits, but since PLLP_OUT0 is #0, it's OK to
|
||||
* simply call clock_ll_set_source_divisor (2 bits).
|
||||
*/
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_sdmmc3, 0,
|
||||
CLK_DIVIDER(TEGRA_PLLP_KHZ, 48000));
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_sdmmc4, 0,
|
||||
CLK_DIVIDER(TEGRA_PLLP_KHZ, 48000));
|
||||
clock_configure_source(sdmmc3, PLLP, 48000);
|
||||
clock_configure_source(sdmmc4, PLLP, 48000);
|
||||
|
||||
/* PLLP and PLLM are switched for HOST1x for no apparent reason. */
|
||||
write32(4 /* PLLP! */ << CLK_SOURCE_SHIFT |
|
||||
/* TODO(rminnich): The divisor isn't accurate enough to get to
|
||||
* 144MHz (it goes to 163 instead). What should we do here? */
|
||||
CLK_DIVIDER(TEGRA_PLLP_KHZ, 144000),
|
||||
&clk_rst->clk_src_host1x);
|
||||
|
||||
/* DISP1 doesn't support a divisor. Use PLLC which runs at 600MHz. */
|
||||
clock_configure_source(disp1, PLLC, 600000);
|
||||
|
||||
/* Give clock time to stabilize. */
|
||||
udelay(IO_STABILIZATION_DELAY);
|
||||
|
|
@ -386,7 +370,7 @@ void clock_config(void)
|
|||
|
||||
clrbits_le32(&clk_rst->rst_dev_l,
|
||||
CLK_L_CACHE2 | CLK_L_GPIO | CLK_L_TMR | CLK_L_I2C1 |
|
||||
CLK_L_SDMMC4);
|
||||
CLK_L_SDMMC4 | CLK_L_DISP1 | CLK_L_HOST1X);
|
||||
clrbits_le32(&clk_rst->rst_dev_h,
|
||||
CLK_H_EMC | CLK_H_I2C2 | CLK_H_I2C5 | CLK_H_SBC1 |
|
||||
CLK_H_PMC | CLK_H_APBDMA | CLK_H_MEM);
|
||||
|
|
|
|||
|
|
@ -32,12 +32,9 @@
|
|||
#include <cbmem.h>
|
||||
#include <soc/clock.h>
|
||||
#include <soc/nvidia/tegra/dc.h>
|
||||
#include "clk_rst.h"
|
||||
#include "chip.h"
|
||||
#include <soc/display.h>
|
||||
|
||||
static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE;
|
||||
|
||||
static const u32 rgb_enb_tab[PIN_REG_COUNT] = {
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
|
|
@ -281,20 +278,6 @@ void display_startup(device_t dev)
|
|||
* The panel_vdd is done in the romstage, so we need only
|
||||
* light things up here once we're sure it's all working.
|
||||
*/
|
||||
setbits_le32(&clk_rst->rst_dev_l, CLK_L_DISP1 | CLK_L_HOST1X);
|
||||
|
||||
clock_ll_set_source_divisor(&clk_rst->clk_src_host1x, 4,
|
||||
CLK_DIVIDER(TEGRA_PLLP_KHZ, 144000));
|
||||
|
||||
/* DISP1 doesn't support a divisor. Use PLLC which runs at 600MHz. */
|
||||
val = readl(&clk_rst->clk_src_disp1);
|
||||
val &= ~CLK_SOURCE3_MASK;
|
||||
val |= (4 << CLK_SOURCE3_SHIFT);
|
||||
writel(val, &clk_rst->clk_src_disp1);
|
||||
|
||||
udelay(2);
|
||||
|
||||
clrbits_le32(&clk_rst->rst_dev_l, CLK_L_DISP1|CLK_L_HOST1X);
|
||||
|
||||
writel(0x00000100, &dc->cmd.gen_incr_syncpt_ctrl);
|
||||
writel(0x0000011a, &dc->cmd.cont_syncpt_vsync);
|
||||
|
|
|
|||
|
|
@ -155,7 +155,20 @@ enum {
|
|||
/* Calculate clock frequency value from reference and clock divider value */
|
||||
#define CLK_FREQUENCY(REF, REG) (((REF) * 2) / (REG + 2))
|
||||
|
||||
enum clock_source { /* Careful: Not true for all sources, always check TRM! */
|
||||
PLLP = 0,
|
||||
PLLC2 = 1,
|
||||
PLLC = 2,
|
||||
PLLD = 2,
|
||||
PLLC3 = 3,
|
||||
PLLA = 3,
|
||||
PLLM = 4,
|
||||
PLLD2 = 5,
|
||||
CLK_M = 6,
|
||||
};
|
||||
|
||||
/* soc-specific */
|
||||
#define TEGRA_CLK_M_KHZ clock_get_osc_khz()
|
||||
#define TEGRA_PLLX_KHZ (1900000)
|
||||
#define TEGRA_PLLP_KHZ (408000)
|
||||
#define TEGRA_PLLC_KHZ (600000)
|
||||
|
|
@ -167,5 +180,4 @@ void clock_early_uart(void);
|
|||
void clock_cpu0_config_and_reset(void * entry);
|
||||
void clock_config(void);
|
||||
void clock_init(void);
|
||||
void clock_ll_set_source_divisor(u32 *reg, u32 source, u32 divisor);
|
||||
#endif /* __SOC_NVIDIA_TEGRA124_CLOCK_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue