diff options
Diffstat (limited to 'src/soc/nvidia/tegra124/include/soc/clock.h')
-rw-r--r-- | src/soc/nvidia/tegra124/include/soc/clock.h | 64 |
1 files changed, 60 insertions, 4 deletions
diff --git a/src/soc/nvidia/tegra124/include/soc/clock.h b/src/soc/nvidia/tegra124/include/soc/clock.h index 056a38b2e0..675fbfb4f2 100644 --- a/src/soc/nvidia/tegra124/include/soc/clock.h +++ b/src/soc/nvidia/tegra124/include/soc/clock.h @@ -149,13 +149,69 @@ enum { #define CLOCK_PLL_STABLE_DELAY_US 300 #define IO_STABILIZATION_DELAY (2) -/* Calculate clock fractional divider value from ref and target frequencies */ +/* Calculate clock fractional divider value from ref and target frequencies. + * This is for a U7.1 format. This is not well written up in the book and + * there have been some questions about this macro, so here we go. + * U7.1 format is defined as (ddddddd+1) + (h*.5) + * The lowest order bit is actually a fractional bit. + * Hence, the divider can be thought of as 9 bits. + * So: + * divider = ((ref/freq) << 1 - 1) (upper 7 bits) | + * (ref/freq & 1) (low order half-bit) + * however we can't do fractional arithmetic ... these are integers! + * So we normalize by shifting the result left 1 bit, and extracting + * ddddddd and h directly to the returned u8. + * divider = 2*(ref/freq); + * We want to + * preserve 7 bits of divisor and one bit of fraction, in 8 bits, as well as + * subtract one from ddddddd. Since we computed ref*2, the dddddd is now nicely + * situated in the upper 7 bits, and the h is sitting there in the low order + * bit. To subtract 1 from ddddddd, just subtract 2 from the 8-bit number + * and voila, upper 7 bits are (ref/freq-1), and lowest bit is h. Since you + * will assign this to a u8, it gets nicely truncated for you. + */ #define CLK_DIVIDER(REF, FREQ) ((((REF) * 2) / FREQ) - 2) -/* Calculate clock frequency value from reference and clock divider value */ +/* Calculate clock frequency value from reference and clock divider value + * The discussion in the book is pretty lacking. + * The idea is that we need to divide a ref clock by a divisor + * in U7.1 format, where 7 upper bits are the integer + * and lowest order bit is a fraction. + * from the book, U7.1 is (ddddddd+1) + (h*.5) + * To normalize to an actual number, we might do this: + * ((d>>7+1)&0x7f) + (d&1 >> 1) + * but as you might guess, the low order bit would be lost. + * Since we can't express the fractional bit, we need to multiply it all by 2. + * ((d + 2)&0xfe) + (d & 1) + * Since we're just adding +2, the lowest order bit is preserved. Hence + * (d+2) is the same as ((d + 2)&0xfe) + (d & 1) + * + * Since you multiply denominator * 2 (by NOT shifting it), + * you multiply numerator * 2 to cancel it out. + */ #define CLK_FREQUENCY(REF, REG) (((REF) * 2) / (REG + 2)) +/* 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)); + +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) @@ -165,7 +221,7 @@ enum { int clock_get_osc_khz(void); void clock_early_uart(void); void clock_cpu0_config_and_reset(void * entry); -void clock_config(void); +void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w); void clock_init(void); -void clock_ll_set_source_divisor(u32 *reg, u32 source, u32 divisor); +void clock_init_arm_generic_timer(void); #endif /* __SOC_NVIDIA_TEGRA124_CLOCK_H__ */ |