#include "FreeRTOS.h" #include "chip.h" #include "board.h" #define PLL_BYPASS (1 << 30) #define PLL_FOUTVCOPD (1 << 29) #define PLL_FOUTPOSTDIVPD (1 << 28) #define PLL_DSMPD (1 << 27) #define PLL_PD (1 << 26) #define PLL_POSTDIV2_OFFSET (23) #define PLL_POSTDIV2_MASK (0x7) #define PLL_POSTDIV1_OFFSET (20) #define PLL_POSTDIV1_MASK (0x7) #define PLL_FBDIV_OFFSET (8) #define PLL_FBDIV_MASK (0xfff) #define PLL_REFDIV_OFFSET (0) #define PLL_REFDIV_MASK (0x3f) typedef struct { uint32_t clkid; uint32_t clktype; uint32_t source; int clksource[MAX_CLK_SOURCE_NUM]; int source_index; int div; uint32_t enable_reg[MAX_CLK_ENABLE_BITS]; int enable_offset[MAX_CLK_ENABLE_BITS]; int enable_bits; union { uint32_t fixed_freq; struct { int div; int mult; } fixed_fator_property; struct { uint32_t cfgreg; uint32_t sup_sprd; } pll_property; struct { uint32_t cfgreg; uint32_t analogreg; } dds_property; struct { uint32_t cfgreg; int index_offset; int index_value; uint32_t index_mask; int div_offset; int div_value; uint32_t div_mask; int div_mode; uint32_t inv_reg; int inv_offset; uint32_t inv_mask; int inv_value; } sys_property; } u; } xClockProperty; xClockProperty xClocks[] = { {.clkid = CLK_XTAL32K, .clktype = FIXED_CLOCK, .u.fixed_freq = 32768}, {.clkid = CLK_XTAL24M, .clktype = FIXED_CLOCK, .u.fixed_freq = 24000000}, {.clkid = CLK_CPUPLL, .clktype = PLL_CLOCK, .clksource = {CLK_XTAL24M}, .u.pll_property.cfgreg = REGS_SYSCTL_BASE + SYS_CPUPLL_CFG, .u.pll_property.sup_sprd = 0}, {.clkid = CLK_SYSPLL, .clktype = PLL_CLOCK, .clksource = {CLK_XTAL24M}, .u.pll_property.cfgreg = REGS_SYSCTL_BASE + SYS_SYSPLL_CFG, .u.pll_property.sup_sprd = 1}, {.clkid = CLK_VPUPLL, .clktype = PLL_CLOCK, .clksource = {CLK_XTAL24M}, .u.pll_property.cfgreg = REGS_SYSCTL_BASE + SYS_VPUPLL_CFG, .u.pll_property.sup_sprd = 1}, {.clkid = CLK_DDRPLL, .clktype = PLL_CLOCK, .clksource = {CLK_XTAL24M}, .u.pll_property.cfgreg = REGS_SYSCTL_BASE + SYS_DDRPLL_CFG, .u.pll_property.sup_sprd = 0}, {.clkid = CLK_MFCPLL, .clktype = PLL_CLOCK, .clksource = {CLK_XTAL24M}, .u.pll_property.cfgreg = REGS_SYSCTL_BASE + SYS_MFCPLL_CFG, .u.pll_property.sup_sprd = 0}, {.clkid = CLK_AHBPLL, .clktype = PLL_CLOCK, .clksource = {CLK_XTAL24M}, .u.pll_property.cfgreg = REGS_SYSCTL_BASE + SYS_AHBPLL_CFG, .u.pll_property.sup_sprd = 1}, {.clkid = CLK_GPUPLL, .clktype = PLL_CLOCK, .clksource = {CLK_XTAL24M}, .u.pll_property.cfgreg = REGS_SYSCTL_BASE + SYS_GPUPLL_CFG, .u.pll_property.sup_sprd = 0}, {.clkid = CLK_DDR, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_DDRPLL}, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_BUS_CLK_CFG, .u.sys_property.index_offset = 1, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = -1 }, {.clkid = CLK_CPU, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_CPUPLL}, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_BUS_CLK_CFG, .u.sys_property.index_offset = 0, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = -1 }, {.clkid = CLK_AXI, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_SYSPLL}, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_BUS_CLK_CFG, .u.sys_property.index_offset = 2, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = -1 }, {.clkid = CLK_AHB, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_BUS_CLK_CFG, .u.sys_property.index_offset = 3, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = -1 }, {.clkid = CLK_APB, .clktype = SYS_CLOCK, .clksource = {CLK_AHB}, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_BUS_CLK_CFG, .u.sys_property.div_offset = 4, .u.sys_property.div_mask = 3, .u.sys_property.div_value = -1, .u.sys_property.div_mode = DIVMODE_EXPONENT}, {.clkid = CLK_LCD, .clktype = SYS_CLOCK, .clksource = {CLK_SYSPLL, CLK_VPUPLL, CLK_XTAL24M}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {17, 0, 18, 17, 16}, .enable_bits = 5, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_VOU_CLK_CFG, .u.sys_property.index_offset = 0, .u.sys_property.index_mask = 0x3, .u.sys_property.index_value = 1, .u.sys_property.div_offset = 3, .u.sys_property.div_mask = 0x1f, .u.sys_property.div_value = 5, .u.sys_property.div_mode = DIVMODE_PLUSONE, #ifdef LCD_CLK_INVERSE .u.sys_property.inv_reg = REGS_SYSCTL_BASE + SYS_VOU_CLK_CFG, .u.sys_property.inv_offset = 8, .u.sys_property.inv_mask = 0x1, .u.sys_property.inv_value = 1, #endif }, {.clkid = CLK_QOI, .clktype = SYS_CLOCK, .clksource = {CLK_SYSPLL, CLK_MFCPLL, CLK_XTAL24M}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN1}, .enable_offset = {20, 5, 5}, .enable_bits = 3, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_BUS_CLK1_CFG, .u.sys_property.index_offset = 16, .u.sys_property.index_mask = 0x3, .u.sys_property.index_value = 1, .u.sys_property.div_offset = 19, .u.sys_property.div_mask = 0x1f, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE, }, {.clkid = CLK_GPU, .clktype = SYS_CLOCK, .clksource = {CLK_SYSPLL, CLK_GPUPLL, CLK_XTAL24M}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {19, 3, 24}, .enable_bits = 3, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_TIMER1_CLK_CFG, .u.sys_property.index_offset = 0, .u.sys_property.index_mask = 0x3, .u.sys_property.index_value = 1, .u.sys_property.div_offset = 3, .u.sys_property.div_mask = 0x1f, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE, }, {.clkid = CLK_SDMMC0, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN, REGS_SYSCTL_BASE + SYS_SDMMC_CLK_CFG}, .enable_offset = {15, 15, 6}, .enable_bits = 3, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_SDMMC_CLK_CFG, .u.sys_property.index_offset = 7, .u.sys_property.index_mask = 1, .u.sys_property.index_value = 1, .u.sys_property.div_offset = 0, .u.sys_property.div_mask = 0x1f, .u.sys_property.div_value = 5, .u.sys_property.div_mode = DIVMODE_PLUSONE, }, {.clkid = CLK_SDMMC1, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN, REGS_SYSCTL_BASE + SYS_SDMMC1_CLK_CFG}, .enable_offset = {16, 31, 6}, .enable_bits = 3, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_SDMMC1_CLK_CFG, .u.sys_property.index_offset = 7, .u.sys_property.index_mask = 1, .u.sys_property.index_value = 1, .u.sys_property.div_offset = 0, .u.sys_property.div_mask = 0x1f, .u.sys_property.div_value = 5, .u.sys_property.div_mode = DIVMODE_PLUSONE, }, {.clkid = CLK_TIMER, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {7, 9}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_TIMER_CLK_CFG, .u.sys_property.index_offset = 4, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0, .u.sys_property.div_offset = 0, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, {.clkid = CLK_TIMER1, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {26}, .enable_bits = 1, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_TIMER1_CLK_CFG, .u.sys_property.index_offset = 20, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0, .u.sys_property.div_offset = 16, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, {.clkid = CLK_TIMER2_3, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_PER_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {27, 28}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_TIMER1_CLK_CFG, .u.sys_property.index_offset = 28, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0, .u.sys_property.div_offset = 24, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, {.clkid = CLK_MFC, .clktype = SYS_CLOCK, .clksource = {CLK_SYSPLL, CLK_MFCPLL, CLK_XTAL24M}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN, REGS_SYSCTL_BASE + SYS_DDR_CTL1_CFG}, .enable_offset = {21, 4, 23, 17}, .enable_bits = 4, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_TIMER_CLK_CFG, .u.sys_property.index_offset = 8, .u.sys_property.index_mask = 0x3, .u.sys_property.index_value = 1, .u.sys_property.div_offset = 11, .u.sys_property.div_mask = 0x1f, .u.sys_property.div_value = 2, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, {.clkid = CLK_UART0, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {11, 4}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_PERCTL_CFG, .u.sys_property.index_offset = 0, .u.sys_property.index_mask = 1, .u.sys_property.index_value = 0, .u.sys_property.div_offset = 1, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, {.clkid = CLK_UART1, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {12, 5}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_PERCTL_CFG, .u.sys_property.index_offset = 16, .u.sys_property.index_mask = 1, .u.sys_property.index_value = 0, .u.sys_property.div_offset = 17, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, {.clkid = CLK_UART2, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {13, 6}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_PERCTL_CFG, .u.sys_property.index_offset = 8, .u.sys_property.index_mask = 1, .u.sys_property.index_value = 0, .u.sys_property.div_offset = 9, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, {.clkid = CLK_UART3, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {14, 7}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_PERCTL_CFG, .u.sys_property.index_offset = 24, .u.sys_property.index_mask = 1, .u.sys_property.index_value = 0, .u.sys_property.div_offset = 25, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, #ifdef DW_SPI0_SUPPORT {.clkid = CLK_SPI0, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_CPUPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {26, 0}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_SSP_CLK_CFG, .u.sys_property.index_offset = 4, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 1, .u.sys_property.div_offset = 0, .u.sys_property.div_mask = 0xf, .u.sys_property.div_mode = DIVMODE_PLUSONE, #ifndef SPI0_QSPI_MODE .u.sys_property.div_value = 5,}, #else .u.sys_property.div_value = 4,}, #endif #endif #ifdef EC_SPI1_SUPPORT {.clkid = CLK_SPI1, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_CPUPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {2, 1}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_SSP_CLK_CFG, .u.sys_property.index_offset = 20, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0, .u.sys_property.div_offset = 16, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, #endif #ifdef DW_SPI2_SUPPORT {.clkid = CLK_SPI2, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_CPUPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {27, 29}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_SSP_CLK_CFG, .u.sys_property.index_offset = 28, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0, .u.sys_property.div_offset = 24, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, #endif //PWM时钟配置和MCU_PWM是复用的,默认是24Mhz,如果要修改的话需要在MCU工程修改 {.clkid = CLK_PWM, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M, CLK_SYSPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {15, 10}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_PER_CLK_CFG, .u.sys_property.index_offset = 8, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = -1, .u.sys_property.div_offset = 4, .u.sys_property.div_mask = 0xf, .u.sys_property.div_value = 1, .u.sys_property.div_mode = DIVMODE_PLUSONE,}, #ifdef ADC0_SUPPORT {.clkid = CLK_ADC, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {5, 13}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_TIMER_CLK_CFG, .u.sys_property.div_offset = 16, .u.sys_property.div_mask = 0x7fff, .u.sys_property.div_value = 2400, .u.sys_property.div_mode = DIVMODE_PONEDOUBLE,}, #endif #ifdef ADC1_SUPPORT {.clkid = CLK_ADC1, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN1}, .enable_offset = {25, 14}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_ADC_CLK1_CFG, .u.sys_property.div_offset = 0, .u.sys_property.div_mask = 0x7fff, .u.sys_property.div_value = 2400, .u.sys_property.div_mode = DIVMODE_PONEDOUBLE,}, #endif #ifdef ADC2_SUPPORT {.clkid = CLK_ADC2, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL24M}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN1}, .enable_offset = {26, 15}, .enable_bits = 2, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_ADC_CLK1_CFG, .u.sys_property.div_offset = 16, .u.sys_property.div_mask = 0x7fff, .u.sys_property.div_value = 2400, .u.sys_property.div_mode = DIVMODE_PONEDOUBLE,}, #endif {.clkid = CLK_I2S, .clktype = SYS_CLOCK, .clksource = {CLK_SYSPLL, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN, REGS_SYSCTL_BASE + SYS_PER_CLK_EN}, .enable_offset = {0, 12, 11}, .enable_bits = 3, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_PER_CLK_CFG, .u.sys_property.index_offset = 16, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0, .u.sys_property.div_value = 1,}, {.clkid = CLK_I2S1, .clktype = SYS_CLOCK, .clksource = {CLK_SYSPLL, CLK_AHBPLL}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN1, REGS_SYSCTL_BASE + SYS_PER_CLK_EN1}, .enable_offset = {1, 1, 0}, .enable_bits = 3, .u.sys_property.cfgreg = REGS_SYSCTL_BASE + SYS_BUS_CLK1_CFG, .u.sys_property.index_offset = 4, .u.sys_property.index_mask = 0x1, .u.sys_property.index_value = 0, .u.sys_property.div_value = 1,}, {.clkid = CLK_RTC, .clktype = SYS_CLOCK, .clksource = {CLK_XTAL32K}, .enable_reg = {REGS_SYSCTL_BASE + SYS_BUS_CLK_EN1}, .enable_offset = {8}, .enable_bits = 1,}, {.clkid = CLK_ETH, .clktype = SYS_CLOCK, .clksource = {CLK_AHB},}, }; #define CLOCK_NUM (sizeof(xClocks) / sizeof(xClocks[0])) static xClockProperty *clk_get(uint32_t clkid) { int i; for (i = 0; i < CLOCK_NUM; i++) { if (xClocks[i].clkid == clkid) { return &xClocks[i]; } } return NULL; } static uint32_t clk_fixed_get_rate(xClockProperty *clk) { return clk->u.fixed_freq; } static uint32_t clk_fixed_factor_get_rate(xClockProperty *clk) { xClockProperty *parentclk = clk_get(clk->clksource[0]); configASSERT(parentclk); return clk_fixed_get_rate(parentclk) * clk->u.fixed_fator_property.mult / clk->u.fixed_fator_property.div; } static uint32_t clk_pll_get_rate(xClockProperty *clk) { uint32_t reg, parent_rate; uint32_t posdiv2, posdiv1, fbdiv, refdiv; uint32_t pllclk; configASSERT(clk); parent_rate = ulClkGetRate(clk->clksource[clk->source_index]); reg = readl(clk->u.pll_property.cfgreg); if (reg & PLL_BYPASS) { pllclk = parent_rate; } else { posdiv2 = (reg >> PLL_POSTDIV2_OFFSET) & PLL_POSTDIV2_MASK; posdiv1 = (reg >> PLL_POSTDIV1_OFFSET) & PLL_POSTDIV1_MASK; fbdiv = (reg >> PLL_FBDIV_OFFSET) & PLL_FBDIV_MASK; refdiv = (reg >> PLL_REFDIV_OFFSET) & PLL_REFDIV_MASK; pllclk = (uint64_t)parent_rate * fbdiv / posdiv2 / posdiv1 / refdiv; } return pllclk; } static uint32_t clk_sys_get_rate(xClockProperty *clk) { uint32_t parent_rate; configASSERT(clk); configASSERT(clk->div); parent_rate = ulClkGetRate(clk->clksource[clk->source_index]); return parent_rate / clk->div; } static void clk_pll_init(xClockProperty *clk) { configASSERT(clk); clk->source_index = 0; } static int clk_get_div(int div, int divmode) { switch(divmode) { case DIVMODE_NOZERO: div = div ? div : 1; break; case DIVMODE_PLUSONE: div = div + 1; break; case DIVMODE_DOUBLE: div *= 2; break; case DIVMODE_EXPONENT: div = 1 << div; break; case DIVMODE_PONEDOUBLE: div = (div + 1) * 2; break; } return div; } static __INLINE int clk_set_div(int div, int divmode) { switch(divmode) { case DIVMODE_PLUSONE: div = div - 1; break; case DIVMODE_DOUBLE: div /= 2; break; case DIVMODE_EXPONENT: div = fls(div) - 1; break; case DIVMODE_PONEDOUBLE: div = div / 2 - 1; break; } return div; } static void clk_sys_set_rate(xClockProperty *clk, uint32_t freq) { int div; uint32_t reg; uint32_t parent_rate; configASSERT(clk); parent_rate = ulClkGetRate(clk->clksource[clk->source_index]); div = DIV_ROUND_UP(parent_rate, freq); clk->div = div; div = clk_set_div(div, clk->u.sys_property.div_mode); reg = readl(clk->u.sys_property.cfgreg); reg &= ~(clk->u.sys_property.div_mask << clk->u.sys_property.div_offset); reg |= (div & clk->u.sys_property.div_mask) << clk->u.sys_property.div_offset; writel(reg, clk->u.sys_property.cfgreg); } static void clk_sys_init(xClockProperty *clk) { uint32_t reg; uint32_t val; configASSERT(clk); if (clk->u.sys_property.index_value >= 0 && clk->u.sys_property.index_mask) { clk->source_index = clk->u.sys_property.index_value; val = clk->u.sys_property.index_value == 3 ? 4 : clk->u.sys_property.index_value; reg = readl(clk->u.sys_property.cfgreg); reg &= ~(clk->u.sys_property.index_mask << clk->u.sys_property.index_offset); reg |= (val & clk->u.sys_property.index_mask) << clk->u.sys_property.index_offset; writel(reg, clk->u.sys_property.cfgreg); } else if (clk->u.sys_property.index_mask) { reg = readl(clk->u.sys_property.cfgreg); val = (reg >> clk->u.sys_property.index_offset) & clk->u.sys_property.index_mask; clk->source_index = val == 4 ? 3 : val; } if (clk->u.sys_property.div_value >= 0 && clk->u.sys_property.div_mask) { val = clk_set_div(clk->u.sys_property.div_value, clk->u.sys_property.div_mode); clk->div = clk_get_div(val, clk->u.sys_property.div_mode); reg = readl(clk->u.sys_property.cfgreg); reg &= ~(clk->u.sys_property.div_mask << clk->u.sys_property.div_offset); reg |= (val & clk->u.sys_property.div_mask) << clk->u.sys_property.div_offset; writel(reg, clk->u.sys_property.cfgreg); } else if (clk->u.sys_property.div_mask) { reg = readl(clk->u.sys_property.cfgreg); val = (reg >> clk->u.sys_property.div_offset) & clk->u.sys_property.div_mask; clk->div = clk_get_div(val, clk->u.sys_property.div_mode); } else if (clk->u.sys_property.div_value > 0) { clk->div = clk->u.sys_property.div_value; } else { clk->div = 1; } if (clk->u.sys_property.inv_reg) { reg = readl(clk->u.sys_property.inv_reg); reg &= ~(clk->u.sys_property.inv_mask << clk->u.sys_property.inv_offset); reg |= (clk->u.sys_property.inv_value & clk->u.sys_property.inv_mask) << clk->u.sys_property.inv_offset; writel(reg, clk->u.sys_property.inv_reg); } } static void clk_sys_enable(xClockProperty *clk) { int i; configASSERT(clk); for (i = 0; i < clk->enable_bits; i++) writel(readl(clk->enable_reg[i]) | (1 << clk->enable_offset[i]), clk->enable_reg[i]); } static void clk_sys_disable(xClockProperty *clk) { int i; configASSERT(clk); for (i = 0; i < clk->enable_bits; i++) writel(readl(clk->enable_reg[i]) & ~(1 << clk->enable_offset[i]), clk->enable_reg[i]); } void vClkInit(void) { int i; xClockProperty *clk; for (i = 0; i < CLOCK_NUM; i++) { clk = &xClocks[i]; if (clk->clktype == PLL_CLOCK) { clk_pll_init(clk); } else if (clk->clktype == SYS_CLOCK) { clk_sys_init(clk); } } } uint32_t ulClkGetRate(uint32_t clkid) { xClockProperty *clk = clk_get(clkid); if (clk == NULL) return 0; switch (clk->clktype) { case FIXED_CLOCK: return clk_fixed_get_rate(clk); case FIXED_FACTOR_CLOCK: return clk_fixed_factor_get_rate(clk); case PLL_CLOCK: return clk_pll_get_rate(clk); case SYS_CLOCK: return clk_sys_get_rate(clk); } return 0; } void vClkSetRate(uint32_t clkid, uint32_t freq) { xClockProperty *clk = clk_get(clkid); if (clk == NULL) return; if (clk->clktype == SYS_CLOCK) clk_sys_set_rate(clk, freq); } void vClkEnable(uint32_t clkid) { xClockProperty *clk = clk_get(clkid); if (clk == NULL) return; if (clk->clktype == SYS_CLOCK) clk_sys_enable(clk); } void vClkDisable(uint32_t clkid) { xClockProperty *clk = clk_get(clkid); if (clk == NULL) return; if (clk->clktype == SYS_CLOCK) clk_sys_disable(clk); }