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