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 55static uint32_t count_l2clk(void); 56void armadaxp_l2_init(void); 57void armadaxp_init_coher_fabric(void); 58int platform_get_ncpus(void); 59static 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 92struct 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 99static 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 125static uint16_t cpu_clock_table[] = { 126 1000, 1066, 1200, 1333, 1500, 1666, 1800, 2000, 600, 667, 800, 1600, 127 2133, 2200, 2400 }; 128 129static uint64_t 130get_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 141uint32_t 142get_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 155uint32_t 156get_cpu_freq_armadaxp(void) 157{ 158 159 return (0); 160} 161 162static uint32_t 163count_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 201uint32_t 202get_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 213static uint32_t 214read_coher_fabric(uint32_t reg) 215{ 216 217 return (bus_space_read_4(fdtbus_bs_tag, MV_COHERENCY_FABRIC_BASE, reg)); 218} 219 220static void 221write_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 227int 228platform_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 237void 238armadaxp_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 */ 257static uint32_t 258read_l2_cache(uint32_t reg) 259{ 260 261 return (bus_space_read_4(fdtbus_bs_tag, ARMADAXP_L2_BASE, reg)); 262} 263 264static void 265write_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 271static void 272armadaxp_l2_idcache_inv_all(void) 273{ 274 write_l2_cache(ARMADAXP_L2_INV_WAY, ALL_WAYS); 275} 276 277void 278armadaxp_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 323