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