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