1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2011 Semihalf. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * From: FreeBSD: src/sys/arm/mv/kirkwood/sheevaplug.c,v 1.2 2010/06/13 13:28:53 29 */ 30 31 #include <sys/cdefs.h> 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bus.h> 35 36 #include <machine/armreg.h> 37 #include <machine/bus.h> 38 #include <machine/cpu.h> 39 40 #include <arm/mv/mvwin.h> 41 #include <arm/mv/mvreg.h> 42 #include <arm/mv/mvvar.h> 43 44 #include <dev/ofw/openfirm.h> 45 46 #include <machine/fdt.h> 47 48 #define CPU_FREQ_FIELD(sar) (((0x01 & (sar >> 52)) << 3) | \ 49 (0x07 & (sar >> 21))) 50 #define FAB_FREQ_FIELD(sar) (((0x01 & (sar >> 51)) << 4) | \ 51 (0x0F & (sar >> 24))) 52 53 static uint32_t count_l2clk(void); 54 void armadaxp_l2_init(void); 55 void armadaxp_init_coher_fabric(void); 56 int platform_get_ncpus(void); 57 static uint64_t get_sar_value_armadaxp(void); 58 59 #define ARMADAXP_L2_BASE (MV_BASE + 0x8000) 60 #define ARMADAXP_L2_CTRL 0x100 61 #define L2_ENABLE (1 << 0) 62 #define ARMADAXP_L2_AUX_CTRL 0x104 63 #define L2_WBWT_MODE_MASK (3 << 0) 64 #define L2_WBWT_MODE_PAGE 0 65 #define L2_WBWT_MODE_WB 1 66 #define L2_WBWT_MODE_WT 2 67 #define L2_REP_STRAT_MASK (3 << 27) 68 #define L2_REP_STRAT_LSFR (1 << 27) 69 #define L2_REP_STRAT_SEMIPLRU (3 << 27) 70 71 #define ARMADAXP_L2_CNTR_CTRL 0x200 72 #define ARMADAXP_L2_CNTR_CONF(x) (0x204 + (x) * 0xc) 73 #define ARMADAXP_L2_CNTR2_VAL_LOW (0x208 + (x) * 0xc) 74 #define ARMADAXP_L2_CNTR2_VAL_HI (0x20c + (x) * 0xc) 75 76 #define ARMADAXP_L2_INT_CAUSE 0x220 77 78 #define ARMADAXP_L2_SYNC_BARRIER 0x700 79 #define ARMADAXP_L2_INV_WAY 0x778 80 #define ARMADAXP_L2_CLEAN_WAY 0x7BC 81 #define ARMADAXP_L2_FLUSH_PHYS 0x7F0 82 #define ARMADAXP_L2_FLUSH_WAY 0x7FC 83 84 #define MV_COHERENCY_FABRIC_BASE (MV_MBUS_BRIDGE_BASE + 0x200) 85 #define COHER_FABRIC_CTRL 0x00 86 #define COHER_FABRIC_CONF 0x04 87 #define COHER_FABRIC_CFU 0x28 88 #define COHER_FABRIC_CIB_CTRL 0x80 89 90 struct vco_freq_ratio { 91 uint8_t vco_cpu; /* VCO to CLK0(CPU) clock ratio */ 92 uint8_t vco_l2c; /* VCO to NB(L2 cache) clock ratio */ 93 uint8_t vco_hcl; /* VCO to HCLK(DDR controller) clock ratio */ 94 uint8_t vco_ddr; /* VCO to DR(DDR memory) clock ratio */ 95 }; 96 97 static struct vco_freq_ratio freq_conf_table[] = { 98 /*00*/ { 1, 1, 4, 2 }, 99 /*01*/ { 1, 2, 2, 2 }, 100 /*02*/ { 2, 2, 6, 3 }, 101 /*03*/ { 2, 2, 3, 3 }, 102 /*04*/ { 1, 2, 3, 3 }, 103 /*05*/ { 1, 2, 4, 2 }, 104 /*06*/ { 1, 1, 2, 2 }, 105 /*07*/ { 2, 3, 6, 6 }, 106 /*08*/ { 2, 3, 5, 5 }, 107 /*09*/ { 1, 2, 6, 3 }, 108 /*10*/ { 2, 4, 10, 5 }, 109 /*11*/ { 1, 3, 6, 6 }, 110 /*12*/ { 1, 2, 5, 5 }, 111 /*13*/ { 1, 3, 6, 3 }, 112 /*14*/ { 1, 2, 5, 5 }, 113 /*15*/ { 2, 2, 5, 5 }, 114 /*16*/ { 1, 1, 3, 3 }, 115 /*17*/ { 2, 5, 10, 10 }, 116 /*18*/ { 1, 3, 8, 4 }, 117 /*19*/ { 1, 1, 2, 1 }, 118 /*20*/ { 2, 3, 6, 3 }, 119 /*21*/ { 1, 2, 8, 4 }, 120 /*22*/ { 2, 5, 10, 5 } 121 }; 122 123 static uint16_t cpu_clock_table[] = { 124 1000, 1066, 1200, 1333, 1500, 1666, 1800, 2000, 600, 667, 800, 1600, 125 2133, 2200, 2400 }; 126 127 static uint64_t 128 get_sar_value_armadaxp(void) 129 { 130 uint32_t sar_low, sar_high; 131 132 sar_high = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 133 SAMPLE_AT_RESET_HI); 134 sar_low = bus_space_read_4(fdtbus_bs_tag, MV_MISC_BASE, 135 SAMPLE_AT_RESET_LO); 136 return (((uint64_t)sar_high << 32) | sar_low); 137 } 138 139 uint32_t 140 get_tclk_armadaxp(void) 141 { 142 uint32_t cputype; 143 144 cputype = cp15_midr_get(); 145 cputype &= CPU_ID_CPU_MASK; 146 147 if (cputype == CPU_ID_MV88SV584X_V7) 148 return (TCLK_250MHZ); 149 else 150 return (TCLK_200MHZ); 151 } 152 153 uint32_t 154 get_cpu_freq_armadaxp(void) 155 { 156 157 return (0); 158 } 159 160 static uint32_t 161 count_l2clk(void) 162 { 163 uint64_t sar_reg; 164 uint32_t freq_vco, freq_l2clk; 165 uint8_t sar_cpu_freq, sar_fab_freq, array_size; 166 167 /* Get value of the SAR register and process it */ 168 sar_reg = get_sar_value_armadaxp(); 169 sar_cpu_freq = CPU_FREQ_FIELD(sar_reg); 170 sar_fab_freq = FAB_FREQ_FIELD(sar_reg); 171 172 /* Check if CPU frequency field has correct value */ 173 array_size = nitems(cpu_clock_table); 174 if (sar_cpu_freq >= array_size) 175 panic("Reserved value in cpu frequency configuration field: " 176 "%d", sar_cpu_freq); 177 178 /* Check if fabric frequency field has correct value */ 179 array_size = nitems(freq_conf_table); 180 if (sar_fab_freq >= array_size) 181 panic("Reserved value in fabric frequency configuration field: " 182 "%d", sar_fab_freq); 183 184 /* Get CPU clock frequency */ 185 freq_vco = cpu_clock_table[sar_cpu_freq] * 186 freq_conf_table[sar_fab_freq].vco_cpu; 187 188 /* Get L2CLK clock frequency */ 189 freq_l2clk = freq_vco / freq_conf_table[sar_fab_freq].vco_l2c; 190 191 /* Round L2CLK value to integer MHz */ 192 if (((freq_vco % freq_conf_table[sar_fab_freq].vco_l2c) * 10 / 193 freq_conf_table[sar_fab_freq].vco_l2c) >= 5) 194 freq_l2clk++; 195 196 return (freq_l2clk * 1000000); 197 } 198 199 uint32_t 200 get_l2clk(void) 201 { 202 static uint32_t l2clk_freq = 0; 203 204 /* If get_l2clk is called first time get L2CLK value from register */ 205 if (l2clk_freq == 0) 206 l2clk_freq = count_l2clk(); 207 208 return (l2clk_freq); 209 } 210 211 static uint32_t 212 read_coher_fabric(uint32_t reg) 213 { 214 215 return (bus_space_read_4(fdtbus_bs_tag, MV_COHERENCY_FABRIC_BASE, reg)); 216 } 217 218 static void 219 write_coher_fabric(uint32_t reg, uint32_t val) 220 { 221 222 bus_space_write_4(fdtbus_bs_tag, MV_COHERENCY_FABRIC_BASE, reg, val); 223 } 224 225 int 226 platform_get_ncpus(void) 227 { 228 #if !defined(SMP) 229 return (1); 230 #else 231 return ((read_coher_fabric(COHER_FABRIC_CONF) & 0xf) + 1); 232 #endif 233 } 234 235 void 236 armadaxp_init_coher_fabric(void) 237 { 238 uint32_t val, cpus, mask; 239 240 cpus = platform_get_ncpus(); 241 mask = (1 << cpus) - 1; 242 val = read_coher_fabric(COHER_FABRIC_CTRL); 243 val |= (mask << 24); 244 write_coher_fabric(COHER_FABRIC_CTRL, val); 245 246 val = read_coher_fabric(COHER_FABRIC_CONF); 247 val |= (mask << 24); 248 val |= (1 << 15); 249 write_coher_fabric(COHER_FABRIC_CONF, val); 250 } 251 252 #define ALL_WAYS 0xffffffff 253 254 /* L2 cache configuration registers */ 255 static uint32_t 256 read_l2_cache(uint32_t reg) 257 { 258 259 return (bus_space_read_4(fdtbus_bs_tag, ARMADAXP_L2_BASE, reg)); 260 } 261 262 static void 263 write_l2_cache(uint32_t reg, uint32_t val) 264 { 265 266 bus_space_write_4(fdtbus_bs_tag, ARMADAXP_L2_BASE, reg, val); 267 } 268 269 static void 270 armadaxp_l2_idcache_inv_all(void) 271 { 272 write_l2_cache(ARMADAXP_L2_INV_WAY, ALL_WAYS); 273 } 274 275 void 276 armadaxp_l2_init(void) 277 { 278 u_int32_t reg; 279 280 /* Set L2 policy */ 281 reg = read_l2_cache(ARMADAXP_L2_AUX_CTRL); 282 reg &= ~(L2_WBWT_MODE_MASK); 283 reg &= ~(L2_REP_STRAT_MASK); 284 reg |= L2_REP_STRAT_SEMIPLRU; 285 reg |= L2_WBWT_MODE_WT; 286 write_l2_cache(ARMADAXP_L2_AUX_CTRL, reg); 287 288 /* Invalidate l2 cache */ 289 armadaxp_l2_idcache_inv_all(); 290 291 /* Clear pending L2 interrupts */ 292 write_l2_cache(ARMADAXP_L2_INT_CAUSE, 0x1ff); 293 294 /* Enable l2 cache */ 295 reg = read_l2_cache(ARMADAXP_L2_CTRL); 296 write_l2_cache(ARMADAXP_L2_CTRL, reg | L2_ENABLE); 297 298 /* 299 * For debug purposes 300 * Configure and enable counter 301 */ 302 write_l2_cache(ARMADAXP_L2_CNTR_CONF(0), 0xf0000 | (4 << 2)); 303 write_l2_cache(ARMADAXP_L2_CNTR_CONF(1), 0xf0000 | (2 << 2)); 304 write_l2_cache(ARMADAXP_L2_CNTR_CTRL, 0x303); 305 306 /* 307 * Enable Cache maintenance operation propagation in coherency fabric 308 * Change point of coherency and point of unification to DRAM. 309 */ 310 reg = read_coher_fabric(COHER_FABRIC_CFU); 311 reg |= (1 << 17) | (1 << 18); 312 write_coher_fabric(COHER_FABRIC_CFU, reg); 313 314 /* Coherent IO Bridge initialization */ 315 reg = read_coher_fabric(COHER_FABRIC_CIB_CTRL); 316 reg &= ~(7 << 16); 317 reg |= (7 << 16); 318 write_coher_fabric(COHER_FABRIC_CIB_CTRL, reg); 319 } 320