diff --git a/loader/clock.c b/loader/clock.c index 2b6af86..f0f7276 100644 --- a/loader/clock.c +++ b/loader/clock.c @@ -22,6 +22,97 @@ #include "util.h" #include "types.h" +enum { + OSC_FREQ_13 = 0, + OSC_FREQ_16P8 = 1, + OSC_FREQ_19P2 = 4, + OSC_FREQ_38P4 = 5, + OSC_FREQ_12 = 8, + OSC_FREQ_48 = 9, + OSC_FREQ_26 = 12 +}; +/* This table defines the frequency dividers for every PLL to turn the external + * OSC clock into the frequencies defined by TEGRA_PLL*_KHZ in soc/clock.h. + * All PLLs have three dividers (n, m and p), with the governing formula for + * the output frequency being CF = (IN / m), VCO = CF * n and OUT = VCO / (2^p). + * All divisor configurations must meet the PLL's constraints for VCO and CF: + * PLLX: 12 MHz < CF < 50 MHz, 700 MHz < VCO < 3000 MHz + * PLLC: 12 MHz < CF < 50 MHz, 600 MHz < VCO < 1400 MHz + * PLLM: 12 MHz < CF < 50 MHz, 400 MHz < VCO < 1066 MHz + * PLLP: 1 MHz < CF < 6 MHz, 200 MHz < VCO < 700 MHz + * PLLD: 1 MHz < CF < 6 MHz, 500 MHz < VCO < 1000 MHz + * PLLU: 1 MHz < CF < 6 MHz, 480 MHz < VCO < 960 MHz + * PLLDP: 12 MHz < CF < 38 MHz, 600 MHz < VCO < 1200 MHz + * (values taken from Linux' drivers/clk/tegra/clk-tegra124.c). */ +struct { + int khz; + struct pllcx_dividers pllx; /* target: CONFIG_PLLX_KHZ */ + struct pllcx_dividers pllc; /* target: 600 MHz */ + /* PLLM is set up dynamically by clock_sdram(). */ + /* PLLP is hardwired to 408 MHz in HW (unless we set BASE_OVRD). */ + struct pllu_dividers pllu; /* target; 960 MHz */ + struct pllcx_dividers plldp; /* target; 270 MHz */ + /* PLLDP treats p differently (OUT = VCO / (p + 1) for p < 6). */ +} static const osc_table[16] = { + [OSC_FREQ_12] = { + .khz = 12000, + .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, + .pllc = {.n = 50, .m = 1, .p = 0}, + .pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2}, + .plldp = {.n = 90, .m = 1, .p = 3}, + }, + [OSC_FREQ_13] = { + .khz = 13000, + .pllx = {.n = TEGRA_PLLX_KHZ / 13000, .m = 1, .p = 0}, + .pllc = {.n = 46, .m = 1, .p = 0}, /* 598.0 MHz */ + .pllu = {.n = 960, .m = 13, .p = 0, .cpcon = 12, .lfcon = 2}, + .plldp = {.n = 83, .m = 1, .p = 3}, /* 269.8 MHz */ + }, + [OSC_FREQ_16P8] = { + .khz = 16800, + .pllx = {.n = TEGRA_PLLX_KHZ / 16800, .m = 1, .p = 0}, + .pllc = {.n = 71, .m = 1, .p = 1}, /* 596.4 MHz */ + .pllu = {.n = 400, .m = 7, .p = 0, .cpcon = 5, .lfcon = 2}, + .plldp = {.n = 64, .m = 1, .p = 3}, /* 268.8 MHz */ + }, + [OSC_FREQ_19P2] = { + .khz = 19200, + .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, + .pllc = {.n = 62, .m = 1, .p = 1}, /* 595.2 MHz */ + .pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2}, + .plldp = {.n = 56, .m = 1, .p = 3}, /* 268.8 MHz */ + }, + [OSC_FREQ_26] = { + .khz = 26000, + .pllx = {.n = TEGRA_PLLX_KHZ / 26000, .m = 1, .p = 0}, + .pllc = {.n = 23, .m = 1, .p = 0}, /* 598.0 MHz */ + .pllu = {.n = 960, .m = 26, .p = 0, .cpcon = 12, .lfcon = 2}, + .plldp = {.n = 83, .m = 2, .p = 3}, /* 269.8 MHz */ + }, + /* These oscillators get predivided as PLL inputs... n/m/p divisors for + * 38.4 should always match 19.2, and 48 should always match 12. */ + [OSC_FREQ_38P4] = { + .khz = 38400, + .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, + .pllc = {.n = 62, .m = 1, .p = 1}, /* 595.2 MHz */ + .pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2}, + .plldp = {.n = 56, .m = 1, .p = 3}, /* 268.8 MHz */ + }, + [OSC_FREQ_48] = { + .khz = 48000, + .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, + .pllc = {.n = 50, .m = 1, .p = 0}, + .pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2}, + .plldp = {.n = 90, .m = 1, .p = 3}, + }, +}; +enum { + SCLK_SYS_STATE_STDBY, + SCLK_SYS_STATE_IDLE, + SCLK_SYS_STATE_RUN, + SCLK_SYS_STATE_IRQ = 4U, + SCLK_SYS_STATE_FIQ = 8U, +}; void clock_enable(const clk_rst_t *clk) { // Put clock into reset. @@ -47,26 +138,179 @@ void clock_disable(const clk_rst_t *clk) CLOCK(clk->enable) &= ~BIT(clk->index); } -//For NS Switch -/* - * CLK_OSC - 38.4 MHz crystal. - * CLK_M - 19.2 MHz (osc/2). - * CLK_S - 32.768 KHz (from PMIC). - * SCLK - 204MHz init (-> 408MHz -> OC). - * HCLK - 204MHz init (-> 408MHz -> OC). - * PCLK - 68MHz init (-> 136MHz -> OC/4). - */ -//For P1761(Ardbeg,Fuze F1) -/* - * CLK_OSC - 12 MHz crystal. - * CLK_M - 12 MHz (osc/2). - * CLK_S - 32.768 KHz (from PMIC). - * SCLK - 127.5MHz init (-> 408MHz -> OC). - * HCLK - 127.5MHz init (-> 408MHz -> OC). - * PCLK - 31.875?MHz init (-> 136MHz -> OC/4). - */ -void config_oscillators() -{ +static void init_pll(u32 pll_base_offset, u32 pll_misc_offset, const union pll_fields pll, u32 lock) +{ + //TODO: rename + u32 dividers = pll.div.n << PLL_BASE_DIVN_SHIFT | + pll.div.m << PLL_BASE_DIVM_SHIFT | + pll.div.p << PLL_BASE_DIVP_SHIFT; + u32 misc_con = pll.div.cpcon << PLL_MISC_CPCON_SHIFT | + pll.div.lfcon << PLL_MISC_LFCON_SHIFT; + /* Write dividers but BYPASS the PLL while we're messing with it. */ + CLOCK(pll_base_offset)=dividers | (1<>CLK_OSC_FREQ_SHIFT; + + + /* Set PLLC dynramp_step A to 0x2b and B to 0xb (from U-Boot -- why? */ + CLOCK(CLK_RST_CONTROLLER_PLLC_MISC2)=(0x2b << 17 | 0xb << 9); + + + // static const osc_table[16] = { + // [OSC_FREQ_12] = { + // .khz = 12000, + // .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, + // .pllc = {.n = 50, .m = 1, .p = 0}, + // .pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2}, + // .plldp = {.n = 90, .m = 1, .p = 3}, + // }, + /* Max out the AVP clock before everything else (need PLLC for that). */ + init_pll(CLK_RST_CONTROLLER_PLLC_BASE,CLK_RST_CONTROLLER_PLLC_MISC,osc_table[clk_osc_bit].pllc,(1 << CLK_RST_CONTROLLER_PLLC_MISC_PLLC_LOCK_ENABLE_SHIFT)); + printf_("[x] PLLC setup\n"); + + /* Typical ratios are 1:2:2 or 1:2:3 sclk:hclk:pclk (See: APB DMA + * features section in the TRM). */ + CLOCK(CLK_RST_CONTROLLER_CLK_SYSTEM_RATE)= + TEGRA_HCLK_RATIO << CLK_RST_CONTROLLER_CLK_SYSTEM_RATE_AHB_RATE_SHIFT | + TEGRA_PCLK_RATIO << CLK_RST_CONTROLLER_CLK_SYSTEM_RATE_APB_RATE_SHIFT; + + CLOCK(CLK_RST_CONTROLLER_PLLC_OUT)=CLK_DIVIDER(TEGRA_PLLC_KHZ, TEGRA_SCLK_KHZ) + << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RATIO_SHIFT | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_CLKEN_SHIFT) | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RSTN_SHIFT); + + /* sclk = 300 MHz */ + CLOCK(CLK_RST_CONTROLLER_SCLK_BURST_POLICY)= + CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SYS_STATE_RUN << CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SYS_STATE_SHIFT | + CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE_PLLC_OUT1 <> PMC_XOFS_SHIFT; + + /*Change the oscillator drive strength (from U-Boot -- why?) */ + u32 osc_ctrl = CLOCK(CLK_RST_CONTROLLER_OSC_CTRL); + osc_ctrl &= ~CLK_OSC_XOFS_MASK; + osc_ctrl |= (xofs << CLK_OSC_XOFS_SHIFT); + osc_ctrl |= CLK_OSC_XOE; + CLOCK(CLK_RST_CONTROLLER_OSC_CTRL)=osc_ctrl; + + /* Disable IDDQ for PLLX before we set it up (from U-Boot -- why?) */ + CLOCK(CLK_RST_CONTROLLER_PLLX_MISC_3) &= ~PLLX_MISC3_IDDQ; // Disable IDDQ. + + /* Set up PLLP_OUT(1|2|3|4) divisor to generate (9.6|48|102|204)MHz */ + + //pll2 ovr shift should be 18? + + CLOCK(CLK_RST_CONTROLLER_PLLP_OUTA)=((CLK_DIVIDER(TEGRA_PLLP_KHZ, 9600) << (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RATIO_SHIFT) | + (1 << CLK_RST_CONTROLLER_PLLP_OUTA_PLLP_OUT1_OVRRIDE_SHIFT) | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_CLKEN_SHIFT) | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RSTN_SHIFT)) << PLL_OUT1_SHIFT | + (CLK_DIVIDER(TEGRA_PLLP_KHZ, 48000) << (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RATIO_SHIFT) | + (1 << CLK_RST_CONTROLLER_PLLP_OUTA_PLLP_OUT1_OVRRIDE_SHIFT) | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_CLKEN_SHIFT) | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RSTN_SHIFT)) << PLL_OUT2_SHIFT); + + CLOCK(CLK_RST_CONTROLLER_PLLP_OUTB)= ((CLK_DIVIDER(TEGRA_PLLP_KHZ, 102000) << (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RATIO_SHIFT) | + (1 << CLK_RST_CONTROLLER_PLLP_OUTA_PLLP_OUT1_OVRRIDE_SHIFT) | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_CLKEN_SHIFT) | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RSTN_SHIFT)) << PLL_OUT3_SHIFT | + (CLK_DIVIDER(TEGRA_PLLP_KHZ, 204000) << (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RATIO_SHIFT) | + (1 << CLK_RST_CONTROLLER_PLLP_OUTA_PLLP_OUT1_OVRRIDE_SHIFT) | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_CLKEN_SHIFT) | (1 << CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RSTN_SHIFT)) << PLL_OUT4_SHIFT); + + init_pll(CLK_RST_CONTROLLER_PLLX_BASE,CLK_RST_CONTROLLER_PLLX_MISC,osc_table[clk_osc_bit].pllx,(1 << CLK_RST_CONTROLLER_PLLX_MISC_PLLX_LOCK_ENABLE_SHIFT)); + + init_pll(CLK_RST_CONTROLLER_PLLU_BASE,CLK_RST_CONTROLLER_PLLU_MISC,osc_table[clk_osc_bit].pllu,(1 << CLK_RST_CONTROLLER_PLLU_MISC_PLLU_LOCK_ENABLE_SHIFT)); + + + //TODO usb device init later + + + /* Graphics just has to be different. There's a few more bits we + * need to set in here, but it makes sense just to restrict all the + * special bits to this one function. Imported form graphics_pll(void) + */ + + /* the vendor code sets the dither bit (28) + * an undocumented bit (24) + * and clamp while we mess with it (22) + * Dither is pretty important to display port + * so we really do need to handle these bits. + * I'm not willing to not clamp it, even if + * it might "mostly work" with it not set, + * I don't want to find out in a few months + * that it is needed. + */ + u32 scfg = (1<<28) | (1<<24) | (1<<22); + CLOCK(CLK_RST_CONTROLLER_PLLDP_SS_CFG)=scfg; + + init_pll(CLK_RST_CONTROLLER_PLLDP_BASE, CLK_RST_CONTROLLER_PLLDP_MISC, + osc_table[clk_osc_bit].plldp, (1 << CLK_RST_CONTROLLER_PLLDP_MISC_0_PLLDP_LOCK_ENABLE_SHIFT)); + /* leave dither and undoc bits set, release clamp */ + scfg = (1<<28) | (1<<24); + CLOCK(CLK_RST_CONTROLLER_PLLDP_SS_CFG)=scfg; + + /* disp1 will be set when panel information (pixel clock) is + * retrieved (clock_display). + */ + printf_("[X] PLLP,PLLX,PLLU,PLLDP setup\n"); +} +static const clk_rst_t _clock_uart[] = { + { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTA, CLK_L_UARTA, 0, 2 }, + { CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_CONTROLLER_CLK_SOURCE_UARTB, CLK_L_UARTB, 0, 2 }, + { CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_CONTROLLER_CLK_SOURCE_UARTC, CLK_H_UARTC, 0, 2 }, + { CLK_RST_CONTROLLER_RST_DEVICES_U, CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_CONTROLLER_CLK_SOURCE_UARTD, CLK_U_UARTD, 0, 2 }, +}; +void clock_enable_uart(u32 idx) +{ + clock_enable(&_clock_uart[idx]); +} +#define UART_SRC_CLK_DIV_EN BIT(24) + +int clock_uart_use_src_div(u32 idx, u32 baud) +{ + u32 clk_src_div = CLOCK(_clock_uart[idx].source) & 0xE0000000; + + if (baud == 3000000) + CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | 15; + else if (baud == 1000000) + CLOCK(_clock_uart[idx].source) = clk_src_div | UART_SRC_CLK_DIV_EN | 49; + else + { + CLOCK(_clock_uart[idx].source) = clk_src_div | 2; + + return 1; + } + + return 0; +} diff --git a/loader/clock.h b/loader/clock.h index eac32a0..35e216b 100644 --- a/loader/clock.h +++ b/loader/clock.h @@ -26,12 +26,192 @@ typedef struct _clk_rst_t u8 clk_src; u8 clk_div; } clk_rst_t; +/* soc-specific */ +#define TEGRA_CLK_M_KHZ 12000 +#define TEGRA_PLLX_KHZ 2000000 +#define TEGRA_PLLP_KHZ (408000) +#define TEGRA_PLLC_KHZ (600000) +#define TEGRA_PLLD_KHZ (925000) +#define TEGRA_PLLU_KHZ (960000) + +#define TEGRA_SCLK_KHZ (300000) +#define TEGRA_HCLK_RATIO 1 +#define TEGRA_HCLK_KHZ (TEGRA_SCLK_KHZ / (1 + TEGRA_HCLK_RATIO)) +#define TEGRA_PCLK_RATIO 0 +#define TEGRA_PCLK_KHZ (TEGRA_HCLK_KHZ / (1 + TEGRA_PCLK_RATIO)) + +#define CLK_RST_CONTROLLER_OSC_CTRL 0x50 +#define CLK_OSC_DRIVE_STRENGTH 7 + +//PLLC +#define CLK_RST_CONTROLLER_PLLC_BASE 0x80 +#define CLK_RST_CONTROLLER_PLLC_MISC 0x8c +#define CLK_RST_CONTROLLER_PLLC_MISC_PLLC_LOCK_ENABLE_SHIFT 24 +#define CLK_RST_CONTROLLER_PLLC_MISC2 0x88 +#define CLK_RST_CONTROLLER_PLLC_BASE_PLLC_BYPASS_SHIFT 31 +#define CLK_RST_CONTROLLER_PLLC_OUT 0x84 + +#define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE 0x30 +#define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE_AHB_RATE_SHIFT 4 +#define CLK_RST_CONTROLLER_CLK_SYSTEM_RATE_APB_RATE_SHIFT 0 + +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY 0x28 + +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SYS_STATE_SHIFT 28 +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SYS_STATE_IDLE 1 +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SYS_STATE_RUN 2 +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE_PLLC_OUT1 1 +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE_PLLP_OUT4 2 +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE_PLLP_OUT3 3 +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE_PLLP_OUT2 4 +#define CLK_RST_CONTROLLER_SCLK_BURST_POLICY_SWAKEUP_RUN_SOURCE_SHIFT 4 +//PLLP +#define CLK_RST_CONTROLLER_PLLP_OUTA 0xA4 +#define CLK_RST_CONTROLLER_PLLP_OUTB 0xA8 +#define CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RATIO_SHIFT 8 +#define CLK_RST_CONTROLLER_PLLP_OUTA_PLLP_OUT1_OVRRIDE_SHIFT 2 +#define CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_CLKEN_SHIFT 1 +#define CLK_RST_CONTROLLER_PLLM_OUT_PLLM_OUT1_RSTN_SHIFT 0 + +//PLLX +#define PLLX_MISC3_IDDQ (1U << 3) +#define CLK_RST_CONTROLLER_PLLX_BASE 0xe0 +#define CLK_RST_CONTROLLER_PLLX_MISC 0xe4 +#define CLK_RST_CONTROLLER_PLLX_MISC_3 0x518 +#define CLK_RST_CONTROLLER_PLLX_MISC_PLLX_LOCK_ENABLE_SHIFT 18 + +//PLLU +#define CLK_RST_CONTROLLER_PLLU_BASE 0xc0 +#define CLK_RST_CONTROLLER_PLLU_MISC 0xcc +#define CLK_RST_CONTROLLER_PLLU_MISC_PLLU_LOCK_ENABLE_SHIFT 22 + +//PLLDP (Graphis PLL) +#define CLK_RST_CONTROLLER_PLLDP_SS_CFG 0x598 +#define CLK_RST_CONTROLLER_PLLDP_BASE 0x590 +#define CLK_RST_CONTROLLER_PLLDP_MISC 0x594 +#define CLK_RST_CONTROLLER_PLLDP_MISC_0_PLLDP_LOCK_ENABLE_SHIFT 30 + +#define PLL_OUT1_SHIFT 0 +#define PLL_OUT2_SHIFT 16 +#define PLL_OUT3_SHIFT 0 +#define PLL_OUT4_SHIFT 16 + +#define PLL_BASE_DIVN_SHIFT 8 +#define PLL_BASE_DIVM_SHIFT 0 +#define PLL_BASE_DIVP_SHIFT 20 +#define PLL_MISC_CPCON_SHIFT 8 +#define PLL_MISC_LFCON_SHIFT 4 + +#define CLK_RST_CONTROLLER_PLLC_BASE_PLLC_ENABLE_SHIFT 30 +#define CLK_RST_CONTROLLER_PLLC_BASE_PLLC_LOCK_SHIFT 27 + + +#define PLLCX_BASE_LOCK BIT(27) + +#define DIV_ROUND_UP(x, y) ({ \ + __typeof__(x) _div_local_x = (x); \ + __typeof__(y) _div_local_y = (y); \ + (_div_local_x + _div_local_y - 1) / _div_local_y; \ +}) +#define CLK_DIVIDER(REF, FREQ) (DIV_ROUND_UP(((REF) * 2), (FREQ)) - 2) + +//MC +#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC 0x19c +#define CLK_RST_CONTROLLER_CLK_ENB_H_SET 0x328 +#define CLK_RST_CONTROLLER_CLK_ENB_X_SET 0x284 +#define CLK_RST_CONTROLLER_RST_DEV_H_SET 0x308 +#define CLK_RST_CONTROLLER_LVL2_CLK_GATE_OVRD 0x3a4 + +//Reset +#define CLK_RST_CONTROLLER_RST_DEVICES_L 0x4 +#define CLK_RST_CONTROLLER_RST_DEVICES_H 0x8 +#define CLK_RST_CONTROLLER_RST_DEVICES_U 0xC + +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_L 0x10 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_H 0x14 +#define CLK_RST_CONTROLLER_CLK_OUT_ENB_U 0x18 + +//UART +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTA 0x178 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTB 0x17C +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC 0x1A0 +#define CLK_RST_CONTROLLER_CLK_SOURCE_UARTD 0x1C0 +enum CLK_L_DEV +{ + CLK_L_UARTA = 6, + CLK_L_UARTB = 7, +}; +enum CLK_H_DEV +{ + CLK_H_UARTC = 23, +}; +enum CLK_U_DEV +{ + CLK_U_UARTD = 1, +}; +enum { + CLK_OSC_XOE = 0x1 << 0, + CLK_OSC_XOFS_SHIFT = 4, + CLK_OSC_XOFS_MASK = 0x3f << CLK_OSC_XOFS_SHIFT, + CLK_OSC_FREQ_SHIFT = 28, + CLK_OSC_FREQ_MASK = 0xf << CLK_OSC_FREQ_SHIFT +}; + + + +struct pll_dividers { + u32 n : 10; + u32 m : 8; + u32 p : 4; + u32 cpcon : 4; + u32 lfcon : 4; + u32 : 2; +}; + +/* Some PLLs have more restrictive divider bit lengths or are missing some + * fields. Make sure to use the right struct in the osc_table definition to get + * compile-time checking, but keep the bits aligned with struct pll_dividers so + * they can be used interchangeably at run time. Add new formats as required. */ +struct pllcx_dividers { + u32 n : 8; + u32 : 2; + u32 m : 8; + u32 p : 4; + u32 : 10; +}; +struct pllpad_dividers { + u32 n : 10; + u32 m : 5; + u32 : 3; + u32 p : 3; + u32 : 1; + u32 cpcon : 4; + u32 : 6; +}; +struct pllu_dividers { + u32 n : 10; + u32 m : 5; + u32 : 3; + u32 p : 1; + u32 : 3; + u32 cpcon : 4; + u32 lfcon : 4; + u32 : 2; +}; + +union __attribute__((transparent_union)) pll_fields { + u32 raw; + struct pll_dividers div; + struct pllcx_dividers cx; + struct pllpad_dividers pad; + struct pllu_dividers u; +}; -#define CLK_RST_CONTROLLER_CLK_SOURCE_EMC_0 0x19c void clock_enable(const clk_rst_t *clk); void clock_disable(const clk_rst_t *clk); void clock_enable_cl_dvfs(); void clock_enable_i2c(u32 idx); - -void config_oscillators(); \ No newline at end of file +void clock_enable_uart(u32 idx); +void config_oscillators(); +int clock_uart_use_src_div(u32 idx, u32 baud); \ No newline at end of file diff --git a/loader/pmc.h b/loader/pmc.h index 9f3efe4..8493f3c 100644 --- a/loader/pmc.h +++ b/loader/pmc.h @@ -15,3 +15,8 @@ * along with this program. If not, see . */ #include "types.h" +#define APBDEV_PMC_OSC_EDPD_OVER 0x1A4 +enum { + PMC_XOFS_SHIFT = 1, + PMC_XOFS_MASK = 0x3f << PMC_XOFS_SHIFT +}; \ No newline at end of file diff --git a/loader/util.c b/loader/util.c index 8524e51..1405fc6 100644 --- a/loader/util.c +++ b/loader/util.c @@ -24,4 +24,4 @@ void sleep(u32 ticks) u32 start = TIMER0(TIMERUS_CNTR_1US); while (TIMER0(TIMERUS_CNTR_1US) - start <= ticks) ; -} \ No newline at end of file +} diff --git a/loader/util.h b/loader/util.h index 4f8edcd..d0d6930 100644 --- a/loader/util.h +++ b/loader/util.h @@ -15,4 +15,4 @@ * along with this program. If not, see . */ #include "types.h" -void sleep(u32 ticks); \ No newline at end of file +void sleep(u32 ticks);