1 /* 2 * Copyright 2014-2015, Freescale Semiconductor, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 * 6 * Derived from arch/power/cpu/mpc85xx/speed.c 7 */ 8 9 #include <common.h> 10 #include <linux/compiler.h> 11 #include <fsl_ifc.h> 12 #include <asm/processor.h> 13 #include <asm/io.h> 14 #include <asm/arch-fsl-layerscape/immap_lsch3.h> 15 #include <asm/arch/clock.h> 16 #include <asm/arch/soc.h> 17 #include "cpu.h" 18 19 DECLARE_GLOBAL_DATA_PTR; 20 21 #ifndef CONFIG_SYS_FSL_NUM_CC_PLLS 22 #define CONFIG_SYS_FSL_NUM_CC_PLLS 6 23 #endif 24 25 26 void get_sys_info(struct sys_info *sys_info) 27 { 28 struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR); 29 #ifdef CONFIG_FSL_IFC 30 struct fsl_ifc ifc_regs = {(void *)CONFIG_SYS_IFC_ADDR, (void *)NULL}; 31 u32 ccr; 32 #endif 33 struct ccsr_clk_cluster_group __iomem *clk_grp[2] = { 34 (void *)(CONFIG_SYS_FSL_CH3_CLK_GRPA_ADDR), 35 (void *)(CONFIG_SYS_FSL_CH3_CLK_GRPB_ADDR) 36 }; 37 struct ccsr_clk_ctrl __iomem *clk_ctrl = 38 (void *)(CONFIG_SYS_FSL_CH3_CLK_CTRL_ADDR); 39 unsigned int cpu; 40 const u8 core_cplx_pll[16] = { 41 [0] = 0, /* CC1 PPL / 1 */ 42 [1] = 0, /* CC1 PPL / 2 */ 43 [2] = 0, /* CC1 PPL / 4 */ 44 [4] = 1, /* CC2 PPL / 1 */ 45 [5] = 1, /* CC2 PPL / 2 */ 46 [6] = 1, /* CC2 PPL / 4 */ 47 [8] = 2, /* CC3 PPL / 1 */ 48 [9] = 2, /* CC3 PPL / 2 */ 49 [10] = 2, /* CC3 PPL / 4 */ 50 [12] = 3, /* CC4 PPL / 1 */ 51 [13] = 3, /* CC4 PPL / 2 */ 52 [14] = 3, /* CC4 PPL / 4 */ 53 }; 54 55 const u8 core_cplx_pll_div[16] = { 56 [0] = 1, /* CC1 PPL / 1 */ 57 [1] = 2, /* CC1 PPL / 2 */ 58 [2] = 4, /* CC1 PPL / 4 */ 59 [4] = 1, /* CC2 PPL / 1 */ 60 [5] = 2, /* CC2 PPL / 2 */ 61 [6] = 4, /* CC2 PPL / 4 */ 62 [8] = 1, /* CC3 PPL / 1 */ 63 [9] = 2, /* CC3 PPL / 2 */ 64 [10] = 4, /* CC3 PPL / 4 */ 65 [12] = 1, /* CC4 PPL / 1 */ 66 [13] = 2, /* CC4 PPL / 2 */ 67 [14] = 4, /* CC4 PPL / 4 */ 68 }; 69 70 uint i, cluster; 71 uint freq_c_pll[CONFIG_SYS_FSL_NUM_CC_PLLS]; 72 uint ratio[CONFIG_SYS_FSL_NUM_CC_PLLS]; 73 unsigned long sysclk = CONFIG_SYS_CLK_FREQ; 74 int cc_group[12] = CONFIG_SYS_FSL_CLUSTER_CLOCKS; 75 u32 c_pll_sel, cplx_pll; 76 void *offset; 77 78 sys_info->freq_systembus = sysclk; 79 #ifdef CONFIG_DDR_CLK_FREQ 80 sys_info->freq_ddrbus = CONFIG_DDR_CLK_FREQ; 81 #ifdef CONFIG_SYS_FSL_HAS_DP_DDR 82 sys_info->freq_ddrbus2 = CONFIG_DDR_CLK_FREQ; 83 #endif 84 #else 85 sys_info->freq_ddrbus = sysclk; 86 #ifdef CONFIG_SYS_FSL_HAS_DP_DDR 87 sys_info->freq_ddrbus2 = sysclk; 88 #endif 89 #endif 90 91 /* The freq_systembus is used to record frequency of platform PLL */ 92 sys_info->freq_systembus *= (gur_in32(&gur->rcwsr[0]) >> 93 FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_SHIFT) & 94 FSL_CHASSIS3_RCWSR0_SYS_PLL_RAT_MASK; 95 sys_info->freq_ddrbus *= (gur_in32(&gur->rcwsr[0]) >> 96 FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_SHIFT) & 97 FSL_CHASSIS3_RCWSR0_MEM_PLL_RAT_MASK; 98 #ifdef CONFIG_SYS_FSL_HAS_DP_DDR 99 if (soc_has_dp_ddr()) { 100 sys_info->freq_ddrbus2 *= (gur_in32(&gur->rcwsr[0]) >> 101 FSL_CHASSIS3_RCWSR0_MEM2_PLL_RAT_SHIFT) & 102 FSL_CHASSIS3_RCWSR0_MEM2_PLL_RAT_MASK; 103 } else { 104 sys_info->freq_ddrbus2 = 0; 105 } 106 #endif 107 108 for (i = 0; i < CONFIG_SYS_FSL_NUM_CC_PLLS; i++) { 109 /* 110 * fixme: prefer to combine the following into one line, but 111 * cannot pass compiling without warning about in_le32. 112 */ 113 offset = (void *)((size_t)clk_grp[i/3] + 114 offsetof(struct ccsr_clk_cluster_group, 115 pllngsr[i%3].gsr)); 116 ratio[i] = (in_le32(offset) >> 1) & 0x3f; 117 freq_c_pll[i] = sysclk * ratio[i]; 118 } 119 120 for_each_cpu(i, cpu, cpu_numcores(), cpu_mask()) { 121 cluster = fsl_qoriq_core_to_cluster(cpu); 122 c_pll_sel = (in_le32(&clk_ctrl->clkcncsr[cluster].csr) >> 27) 123 & 0xf; 124 cplx_pll = core_cplx_pll[c_pll_sel]; 125 cplx_pll += cc_group[cluster] - 1; 126 sys_info->freq_processor[cpu] = 127 freq_c_pll[cplx_pll] / core_cplx_pll_div[c_pll_sel]; 128 } 129 130 #if defined(CONFIG_FSL_IFC) 131 ccr = ifc_in32(&ifc_regs.gregs->ifc_ccr); 132 ccr = ((ccr & IFC_CCR_CLK_DIV_MASK) >> IFC_CCR_CLK_DIV_SHIFT) + 1; 133 134 sys_info->freq_localbus = sys_info->freq_systembus / ccr; 135 #endif 136 } 137 138 139 int get_clocks(void) 140 { 141 struct sys_info sys_info; 142 get_sys_info(&sys_info); 143 gd->cpu_clk = sys_info.freq_processor[0]; 144 gd->bus_clk = sys_info.freq_systembus / CONFIG_SYS_FSL_PCLK_DIV; 145 gd->mem_clk = sys_info.freq_ddrbus; 146 #ifdef CONFIG_SYS_FSL_HAS_DP_DDR 147 gd->arch.mem2_clk = sys_info.freq_ddrbus2; 148 #endif 149 #if defined(CONFIG_FSL_ESDHC) 150 gd->arch.sdhc_clk = gd->bus_clk / CONFIG_SYS_FSL_SDHC_CLK_DIV; 151 #endif /* defined(CONFIG_FSL_ESDHC) */ 152 153 if (gd->cpu_clk != 0) 154 return 0; 155 else 156 return 1; 157 } 158 159 /******************************************** 160 * get_bus_freq 161 * return platform clock in Hz 162 *********************************************/ 163 ulong get_bus_freq(ulong dummy) 164 { 165 if (!gd->bus_clk) 166 get_clocks(); 167 168 return gd->bus_clk; 169 } 170 171 /******************************************** 172 * get_ddr_freq 173 * return ddr bus freq in Hz 174 *********************************************/ 175 ulong get_ddr_freq(ulong ctrl_num) 176 { 177 if (!gd->mem_clk) 178 get_clocks(); 179 180 /* 181 * DDR controller 0 & 1 are on memory complex 0 182 * DDR controller 2 is on memory complext 1 183 */ 184 #ifdef CONFIG_SYS_FSL_HAS_DP_DDR 185 if (ctrl_num >= 2) 186 return gd->arch.mem2_clk; 187 #endif 188 189 return gd->mem_clk; 190 } 191 192 int get_i2c_freq(ulong dummy) 193 { 194 return get_bus_freq(0) / CONFIG_SYS_FSL_I2C_CLK_DIV; 195 } 196 197 int get_dspi_freq(ulong dummy) 198 { 199 return get_bus_freq(0) / CONFIG_SYS_FSL_DSPI_CLK_DIV; 200 } 201 202 int get_serial_clock(void) 203 { 204 return get_bus_freq(0) / CONFIG_SYS_FSL_DUART_CLK_DIV; 205 } 206 207 unsigned int mxc_get_clock(enum mxc_clock clk) 208 { 209 switch (clk) { 210 case MXC_I2C_CLK: 211 return get_i2c_freq(0); 212 case MXC_DSPI_CLK: 213 return get_dspi_freq(0); 214 default: 215 printf("Unsupported clock\n"); 216 } 217 return 0; 218 } 219