1/* 2 * Initialization and support routines for self-booting compressed 3 * image. 4 * 5 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved. 6 * 7 * Permission to use, copy, modify, and/or distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 16 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 * 19 * $Id: min_osl.c,v 1.28 2009/07/10 22:43:40 Exp $ 20 */ 21 22#include <typedefs.h> 23#include <bcmdefs.h> 24#include <osl.h> 25#include <bcmdevs.h> 26#include <bcmutils.h> 27#include <siutils.h> 28#include <hndcpu.h> 29#include <sbchipc.h> 30#include <hndchipc.h> 31 32/* Global ASSERT type */ 33uint32 g_assert_type = 0; 34 35#ifdef mips 36/* Cache support */ 37 38/* Cache and line sizes */ 39uint __icache_size, __ic_lsize, __dcache_size, __dc_lsize; 40 41static void 42_change_cachability(uint32 cm) 43{ 44 uint32 prid, c0reg; 45 46 c0reg = MFC0(C0_CONFIG, 0); 47 c0reg &= ~CONF_CM_CMASK; 48 c0reg |= (cm & CONF_CM_CMASK); 49 MTC0(C0_CONFIG, 0, c0reg); 50 prid = MFC0(C0_PRID, 0); 51 if (BCM330X(prid)) { 52 c0reg = MFC0(C0_BROADCOM, 0); 53 /* Enable icache & dcache */ 54 c0reg |= BRCM_IC_ENABLE | BRCM_DC_ENABLE; 55 MTC0(C0_BROADCOM, 0, c0reg); 56 } 57} 58static void (*change_cachability)(uint32); 59 60void 61caches_on(void) 62{ 63 uint32 config, config1, r2, tmp; 64 uint start, end, size, lsize; 65 66 config = MFC0(C0_CONFIG, 0); 67 r2 = config & CONF_AR; 68 config1 = MFC0(C0_CONFIG, 1); 69 70 icache_probe(config1, &size, &lsize); 71 __icache_size = size; 72 __ic_lsize = lsize; 73 74 dcache_probe(config1, &size, &lsize); 75 __dcache_size = size; 76 __dc_lsize = lsize; 77 78 /* If caches are not in the default state then 79 * presume that caches are already init'd 80 */ 81 if ((config & CONF_CM_CMASK) != CONF_CM_UNCACHED) { 82 blast_dcache(); 83 blast_icache(); 84 return; 85 } 86 87 tmp = R_REG(NULL, (uint32 *)(OSL_UNCACHED(SI_ENUM_BASE + CC_CHIPID))); 88 if (((tmp & CID_PKG_MASK) >> CID_PKG_SHIFT) != HDLSIM_PKG_ID) { 89 /* init icache */ 90 start = KSEG0ADDR(caches_on) & 0xff800000; 91 end = (start + __icache_size); 92 MTC0(C0_TAGLO, 0, 0); 93 MTC0(C0_TAGHI, 0, 0); 94 while (start < end) { 95 cache_op(start, Index_Store_Tag_I); 96 start += __ic_lsize; 97 } 98 99 /* init dcache */ 100 start = KSEG0ADDR(caches_on) & 0xff800000; 101 end = (start + __dcache_size); 102 if (r2) { 103 /* mips32r2 has the data tags in select 2 */ 104 MTC0(C0_TAGLO, 2, 0); 105 MTC0(C0_TAGHI, 2, 0); 106 } else { 107 MTC0(C0_TAGLO, 0, 0); 108 MTC0(C0_TAGHI, 0, 0); 109 } 110 while (start < end) { 111 cache_op(start, Index_Store_Tag_D); 112 start += __dc_lsize; 113 } 114 } 115 116 /* Must be in KSEG1 to change cachability */ 117 change_cachability = (void (*)(uint32))KSEG1ADDR(_change_cachability); 118 change_cachability(CONF_CM_CACHABLE_NONCOHERENT); 119} 120 121 122void 123blast_dcache(void) 124{ 125 uint32 start, end; 126 127 start = KSEG0ADDR(blast_dcache) & 0xff800000; 128 end = start + __dcache_size; 129 130 while (start < end) { 131 cache_op(start, Index_Writeback_Inv_D); 132 start += __dc_lsize; 133 } 134} 135 136void 137blast_icache(void) 138{ 139 uint32 start, end; 140 141 start = KSEG0ADDR(blast_icache) & 0xff800000; 142 end = start + __icache_size; 143 144 while (start < end) { 145 cache_op(start, Index_Invalidate_I); 146 start += __ic_lsize; 147 } 148} 149#endif /* mips */ 150 151/* uart output */ 152 153struct serial_struct { 154 unsigned char *reg_base; 155 unsigned short reg_shift; 156 int irq; 157 int baud_base; 158}; 159 160static struct serial_struct min_uart; 161 162#define LOG_BUF_LEN (1024) 163#define LOG_BUF_MASK (LOG_BUF_LEN-1) 164static unsigned long log_idx; 165static char log_buf[LOG_BUF_LEN]; 166 167 168static inline int 169serial_in(struct serial_struct *info, int offset) 170{ 171 return ((int)R_REG(NULL, (uint8 *)(info->reg_base + (offset << info->reg_shift)))); 172} 173 174static inline void 175serial_out(struct serial_struct *info, int offset, int value) 176{ 177 W_REG(NULL, (uint8 *)(info->reg_base + (offset << info->reg_shift)), value); 178} 179 180void 181putc(int c) 182{ 183 uint32 idx; 184 185 /* CR before LF */ 186 if (c == '\n') 187 putc('\r'); 188 189 /* Store in log buffer */ 190 idx = *((uint32 *)OSL_UNCACHED((uintptr)&log_idx)); 191 *((char *)OSL_UNCACHED(&log_buf[idx])) = (char)c; 192 *((uint32 *)OSL_UNCACHED((uintptr)&log_idx)) = (idx + 1) & LOG_BUF_MASK; 193 194 /* No UART */ 195 if (!min_uart.reg_base) 196 return; 197 198 while (!(serial_in(&min_uart, UART_LSR) & UART_LSR_THRE)); 199 serial_out(&min_uart, UART_TX, c); 200} 201 202/* assert & debugging */ 203 204#ifdef BCMDBG_ASSERT 205void 206assfail(char *exp, char *file, int line) 207{ 208 printf("ASSERT %s file %s line %d\n", exp, file, line); 209} 210#endif /* BCMDBG_ASSERT */ 211 212/* general purpose memory allocation */ 213 214extern char text_start[], text_end[]; 215extern char data_start[], data_end[]; 216extern char bss_start[], bss_end[]; 217 218static ulong free_mem_ptr = 0; 219static ulong free_mem_ptr_end = 0; 220 221void * 222malloc(uint size) 223{ 224 void *p; 225 226 /* Sanity check */ 227 if (size < 0) 228 printf("Malloc error\n"); 229 if (free_mem_ptr == 0) 230 printf("Memory error\n"); 231 232 /* Align */ 233 free_mem_ptr = (free_mem_ptr + 3) & ~3; 234 235 p = (void *) free_mem_ptr; 236 free_mem_ptr += size; 237 238 if (free_mem_ptr >= free_mem_ptr_end) 239 printf("Out of memory\n"); 240 241 return p; 242} 243 244int 245free(void *where) 246{ 247 return 0; 248} 249 250/* get processor cycle count */ 251 252#if defined(mips) 253#define get_cycle_count get_c0_count 254#elif defined(__arm__) || defined(__thumb__) || defined(__thumb2__) 255#define get_cycle_count get_arm_cyclecount 256#endif 257 258uint32 259osl_getcycles(void) 260{ 261 return get_cycle_count(); 262} 263 264/* microsecond delay */ 265 266/* Default to 125 MHz */ 267static uint32 cpu_clock = 125000000; 268static uint32 c0counts_per_us = 125000000 / 2000000; 269static uint32 c0counts_per_ms = 125000000 / 2000; 270 271void 272udelay(uint32 us) 273{ 274 uint32 curr, lim; 275 276 curr = get_cycle_count(); 277 lim = curr + (us * c0counts_per_us); 278 279 if (lim < curr) 280 while (get_cycle_count() > curr) 281 ; 282 283 while (get_cycle_count() < lim) 284 ; 285} 286 287#ifndef MIN_DO_TRAP 288 289/* No trap handling in self-decompressing boots */ 290extern void trap_init(void); 291 292void 293trap_init(void) 294{ 295} 296 297#endif /* !MIN_DO_TRAP */ 298 299static void 300serial_add(void *regs, uint irq, uint baud_base, uint reg_shift) 301{ 302 int quot; 303 304 if (min_uart.reg_base) 305 return; 306 307 min_uart.reg_base = regs; 308 min_uart.irq = irq; 309 min_uart.baud_base = baud_base / 16; 310 min_uart.reg_shift = reg_shift; 311 312 /* Set baud and 8N1 */ 313 quot = (min_uart.baud_base + 57600) / 115200; 314 serial_out(&min_uart, UART_LCR, UART_LCR_DLAB); 315 serial_out(&min_uart, UART_DLL, quot & 0xff); 316 serial_out(&min_uart, UART_DLM, quot >> 8); 317 serial_out(&min_uart, UART_LCR, UART_LCR_WLEN8); 318 319 /* According to the Synopsys website: "the serial clock 320 * modules must have time to see new register values 321 * and reset their respective state machines. This 322 * total time is guaranteed to be no more than 323 * (2 * baud divisor * 16) clock cycles of the slower 324 * of the two system clocks. No data should be transmitted 325 * or received before this maximum time expires." 326 */ 327 udelay(1000); 328} 329 330 331void * 332osl_init() 333{ 334 uint32 c0counts_per_cycle; 335 si_t *sih; 336 337 /* Scan backplane */ 338 sih = si_kattach(SI_OSH); 339 340 if (sih == NULL) 341 return NULL; 342 343#if defined(mips) 344 si_mips_init(sih, 0); 345 c0counts_per_cycle = 2; 346#elif defined(__arm__) || defined(__thumb__) || defined(__thumb2__) 347 si_arm_init(sih); 348 c0counts_per_cycle = 1; 349#else 350#error "Unknow CPU" 351#endif 352 cpu_clock = si_cpu_clock(sih); 353 c0counts_per_us = cpu_clock / (1000000 * c0counts_per_cycle); 354 c0counts_per_ms = si_cpu_clock(sih) / (1000 * c0counts_per_cycle); 355 356 /* Don't really need to talk to the uart in simulation */ 357 if ((sih->chippkg != HDLSIM_PKG_ID) && (sih->chippkg != HWSIM_PKG_ID)) 358 si_serial_init(sih, serial_add); 359 360 /* Init malloc */ 361 free_mem_ptr = (ulong) bss_end; 362 free_mem_ptr_end = ((ulong)&sih) - 8192; /* Enough stack? */ 363 364 return ((void *)sih); 365} 366 367/* translate bcmerros */ 368int 369osl_error(int bcmerror) 370{ 371 if (bcmerror) 372 return -1; 373 else 374 return 0; 375} 376