2 * Initialization and support routines for self-booting compressed
5 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
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.
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.
19 * $Id: min_osl.c 367718 2012-11-09 03:57:10Z $
32 /* Global ASSERT type */
33 uint32 g_assert_type
= 0;
38 /* Cache and line sizes */
39 uint __icache_size
, __ic_lsize
, __dcache_size
, __dc_lsize
;
42 _change_cachability(uint32 cm
)
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);
52 c0reg
= MFC0(C0_BROADCOM
, 0);
53 /* Enable icache & dcache */
54 c0reg
|= BRCM_IC_ENABLE
| BRCM_DC_ENABLE
;
55 MTC0(C0_BROADCOM
, 0, c0reg
);
58 static void (*change_cachability
)(uint32
);
63 uint32 config
, config1
, r2
, tmp
;
64 uint start
, end
, size
, lsize
;
66 config
= MFC0(C0_CONFIG
, 0);
67 r2
= config
& CONF_AR
;
68 config1
= MFC0(C0_CONFIG
, 1);
70 icache_probe(config1
, &size
, &lsize
);
74 dcache_probe(config1
, &size
, &lsize
);
78 /* If caches are not in the default state then
79 * presume that caches are already init'd
81 if ((config
& CONF_CM_CMASK
) != CONF_CM_UNCACHED
) {
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
) {
90 start
= KSEG0ADDR(caches_on
) & 0xff800000;
91 end
= (start
+ __icache_size
);
95 cache_op(start
, Index_Store_Tag_I
);
100 start
= KSEG0ADDR(caches_on
) & 0xff800000;
101 end
= (start
+ __dcache_size
);
103 /* mips32r2 has the data tags in select 2 */
104 MTC0(C0_TAGLO
, 2, 0);
105 MTC0(C0_TAGHI
, 2, 0);
107 MTC0(C0_TAGLO
, 0, 0);
108 MTC0(C0_TAGHI
, 0, 0);
110 while (start
< end
) {
111 cache_op(start
, Index_Store_Tag_D
);
116 /* Must be in KSEG1 to change cachability */
117 change_cachability
= (void (*)(uint32
))KSEG1ADDR(_change_cachability
);
118 change_cachability(CONF_CM_CACHABLE_NONCOHERENT
);
127 start
= KSEG0ADDR(blast_dcache
) & 0xff800000;
128 end
= start
+ __dcache_size
;
130 while (start
< end
) {
131 cache_op(start
, Index_Writeback_Inv_D
);
141 start
= KSEG0ADDR(blast_icache
) & 0xff800000;
142 end
= start
+ __icache_size
;
144 while (start
< end
) {
145 cache_op(start
, Index_Invalidate_I
);
150 #elif defined(__ARM_ARCH_7A__)
152 static uint8 loader_pagetable_array
[128*1024+16384];
154 typedef volatile struct scu_reg_struct_t
{
169 typedef volatile struct l2cc_reg_struct_t
{
173 uint32 control
; /* 0x100 */
175 uint32 tag_ram_control
;
176 uint32 data_ram_control
;
178 uint32 ev_counter_ctrl
; /* 0x200 */
179 uint32 ev_counter1_cfg
;
180 uint32 ev_counter0_cfg
;
184 uint32 int_mask_status
;
185 uint32 int_raw_status
;
188 uint32 rsvd4
[64]; /* 0x300 */
189 uint32 rsvd5
[64]; /* 0x400 */
190 uint32 rsvd6
[64]; /* 0x500 */
191 uint32 rsvd7
[64]; /* 0x600 */
192 uint32 rsvd8
[12]; /* 0x700 - 0x72F */
193 uint32 cache_sync
; /* 0x730 */
195 uint32 inv_pa
; /* 0x770 */
197 uint32 inv_way
; /* 0x77C */
199 uint32 clean_pa
; /* 0x7B0 */
201 uint32 clean_index
; /* 0x7B8 */
204 uint32 clean_inv_pa
; /* 0x7F0 */
206 uint32 clean_inv_index
;
207 uint32 clean_inv_way
;
208 uint32 rsvd15
[64]; /* 0x800 - 0x8FF */
209 uint32 d_lockdown0
; /* 0x900 */
225 uint32 rsvd16
[4]; /* 0x940 */
226 uint32 lock_line_en
; /* 0x950 */
229 uint32 rsvd18
[64]; /* 0xA00 */
230 uint32 rsvd19
[64]; /* 0xB00 */
231 uint32 addr_filtering_start
; /* 0xC00 */
232 uint32 addr_filtering_end
;
234 uint32 rsvd21
[64]; /* 0xD00 */
235 uint32 rsvd22
[64]; /* 0xE00 */
236 uint32 rsvd23
[16]; /* 0xF00 - 0xF3F */
237 uint32 debug_ctrl
; /* 0xF40 */
239 uint32 prefetch_ctrl
; /* 0xF60 */
241 uint32 power_ctrl
; /* 0xF80 */
244 /* ARM9 Private memory region */
245 #define IPROC_PERIPH_BASE (0x19020000) /* (IHOST_A9MP_scu_CONTROL) */
246 #define IPROC_PERIPH_SCU_REG_BASE (IPROC_PERIPH_BASE)
247 #define IPROC_L2CC_REG_BASE (IPROC_PERIPH_BASE + 0x2000) /* L2 Cache controller */
249 /* Structures and bit definitions */
250 /* SCU Control register */
251 #define IPROC_SCU_CTRL_SCU_EN (0x00000001)
252 #define IPROC_SCU_CTRL_ADRFLT_EN (0x00000002)
253 #define IPROC_SCU_CTRL_PARITY_EN (0x00000004)
254 #define IPROC_SCU_CTRL_SPEC_LNFL_EN (0x00000008)
255 #define IPROC_SCU_CTRL_FRC2P0_EN (0x00000010)
256 #define IPROC_SCU_CTRL_SCU_STNDBY_EN (0x00000020)
257 #define IPROC_SCU_CTRL_IC_STNDBY_EN (0x00000040)
260 * CR1 bits (CP#15 CR1)
262 #define CR_M (1 << 0) /* MMU enable */
263 #define CR_A (1 << 1) /* Alignment abort enable */
264 #define CR_C (1 << 2) /* Dcache enable */
265 #define CR_W (1 << 3) /* Write buffer enable */
266 #define CR_P (1 << 4) /* 32-bit exception handler */
267 #define CR_D (1 << 5) /* 32-bit data address range */
268 #define CR_L (1 << 6) /* Implementation defined */
269 #define CR_B (1 << 7) /* Big endian */
270 #define CR_S (1 << 8) /* System MMU protection */
271 #define CR_R (1 << 9) /* ROM MMU protection */
272 #define CR_F (1 << 10) /* Implementation defined */
273 #define CR_Z (1 << 11) /* Implementation defined */
274 #define CR_I (1 << 12) /* Icache enable */
275 #define CR_V (1 << 13) /* Vectors relocated to 0xffff0000 */
276 #define CR_RR (1 << 14) /* Round Robin cache replacement */
277 #define CR_L4 (1 << 15) /* LDR pc can set T bit */
278 #define CR_DT (1 << 16)
279 #define CR_IT (1 << 18)
280 #define CR_ST (1 << 19)
281 #define CR_FI (1 << 21) /* Fast interrupt (lower latency mode) */
282 #define CR_U (1 << 22) /* Unaligned access operation */
283 #define CR_XP (1 << 23) /* Extended page tables */
284 #define CR_VE (1 << 24) /* Vectored interrupts */
285 #define CR_EE (1 << 25) /* Exception (Big) Endian */
286 #define CR_TRE (1 << 28) /* TEX remap enable */
287 #define CR_AFE (1 << 29) /* Access flag enable */
288 #define CR_TE (1 << 30) /* Thumb exception enable */
290 #define isb() __asm__ __volatile__ ("" : : : "memory")
291 #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t")
293 extern void cpu_flush_cache_all(void);
294 extern void cpu_inv_cache_all(void);
296 void flush_cache(unsigned long dummy1
, unsigned long dummy2
)
298 cpu_flush_cache_all();
302 static void l2cc_init(void)
305 l2cc_reg_struct
*l2cc
= (l2cc_reg_struct
*)IPROC_L2CC_REG_BASE
;
307 regval
= l2cc
->aux_control
;
308 regval
&= ~(0x000F0000); /* Clear the Way-size and associativity (8 way) */
309 regval
|= 0x0A130000; /* Non-secure interrupt access, Way-size 16KB,
310 16 way and event monitoring
312 l2cc
->aux_control
= regval
;
313 l2cc
->tag_ram_control
= 0; /* Tag ram latency */
314 l2cc
->data_ram_control
= 0; /* Data ram latency */
317 static void l2cc_invalidate(void)
319 l2cc_reg_struct
*l2cc
= (l2cc_reg_struct
*)IPROC_L2CC_REG_BASE
;
321 /* Invalidate the entire L2 cache */
322 l2cc
->inv_way
= 0x0000FFFF;
325 int l2cc_enable(void)
328 l2cc_reg_struct
*l2cc
= (l2cc_reg_struct
*)IPROC_L2CC_REG_BASE
;
334 while (l2cc
->inv_way
&& i
)
342 /* Clear any pending interrupts from this controller */
343 l2cc
->int_clear
= 0x1FF;
346 l2cc
->control
= 0x01;
348 /* mem barrier to sync up things */
350 asm("mcr p15, 0, %0, c7, c10, 4": :"r"(i
));
355 static void cp_delay(void)
359 /* copro seems to need some delay between reading and writing */
360 for (i
= 0; i
< 1000; i
++)
362 asm volatile("" : : : "memory");
369 uint32 val
, *ptb
, ptbaddr
;
374 asm("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val
) : : "cc");
377 asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" : : "r" (val
) : "cc");
380 /* prepare page table for MMU */
381 ptbaddr
= (uint32
)loader_pagetable_array
;
382 /* Round down to next 64 kB limit */
384 ptbaddr
&= ~(0x10000 - 1);
385 ptb
= (uint32
*)ptbaddr
;
387 /* Set up an identity-mapping for all 4GB, rw for everyone */
388 for (i
= 0; i
< 128; i
++) {
389 /* DRAM area: TEX = 0x4, Ap = 3, Domain = 0, C =1, B = 0 */
390 ptb
[i
] = i
<< 20 | 0x4c0e;
393 for (i
= 128; i
< 480; i
++) {
394 /* TEX = 0x2(device memory), Ap = 3, Domain = 0, C =0, B = 0 */
395 ptb
[i
] = i
<< 20 | 0x0c02;
398 for (i
= 480; i
< 512; i
++) {
399 /* SPI region: TEX = 0x4, Ap = 3, Domain = 0, C =1, B = 0 */
400 ptb
[i
] = i
<< 20 | 0x4c0a;
403 for (i
= 512; i
< 4096; i
++) {
404 /* TEX = 0x2(device memory), Ap = 3, Domain = 0, C =0, B = 0 */
405 ptb
[i
] = i
<< 20 | 0x2c02;
408 /* Apply page table address to CP15 */
409 asm volatile("mcr p15, 0, %0, c2, c0, 0" : : "r" (ptb
) : "memory");
410 /* Set the access control to all-supervisor */
411 asm volatile("mcr p15, 0, %0, c3, c0, 0" : : "r" (~0));
413 /* Enable I$ and MMU */
414 asm("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val
) : : "cc");
416 val
|= (CR_C
| CR_M
);
417 asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" : : "r" (val
) : "cc");
427 asm("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val
) : : "cc");
430 if ((val
& CR_C
) != CR_C
)
431 return; /* D$ not enabled */
438 val
&= ~(CR_C
| CR_M
);
440 asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" : : "r" (val
) : "cc");
442 #endif /* !CFG_UNCACHED */
451 asm("mrc p15, 0, %0, c1, c0, 0 @ get CR" : "=r" (val
) : : "cc");
454 if ((val
& CR_I
) != CR_I
)
455 return; /* I$ not enabled */
458 asm volatile("mcr p15, 0, %0, c1, c0, 0 @ set CR" : : "r" (val
) : "cc");
461 /* invalidate I-cache */
462 asm("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
470 struct serial_struct
{
471 unsigned char *reg_base
;
472 unsigned short reg_shift
;
477 static struct serial_struct min_uart
;
480 #define LOG_BUF_LEN (16 * 1024)
482 #define LOG_BUF_LEN (1024)
484 #define LOG_BUF_MASK (LOG_BUF_LEN-1)
485 static unsigned long log_idx
;
486 static char log_buf
[LOG_BUF_LEN
];
490 serial_in(struct serial_struct
*info
, int offset
)
492 return ((int)R_REG(NULL
, (uint8
*)(info
->reg_base
+ (offset
<< info
->reg_shift
))));
496 serial_out(struct serial_struct
*info
, int offset
, int value
)
498 W_REG(NULL
, (uint8
*)(info
->reg_base
+ (offset
<< info
->reg_shift
)), value
);
510 /* Store in log buffer */
511 idx
= *((uint32
*)OSL_UNCACHED((uintptr
)&log_idx
));
512 *((char *)OSL_UNCACHED(&log_buf
[idx
])) = (char)c
;
513 *((uint32
*)OSL_UNCACHED((uintptr
)&log_idx
)) = (idx
+ 1) & LOG_BUF_MASK
;
516 if (!min_uart
.reg_base
)
519 while (!(serial_in(&min_uart
, UART_LSR
) & UART_LSR_THRE
));
520 serial_out(&min_uart
, UART_TX
, c
);
523 /* assert & debugging */
526 /* general purpose memory allocation */
528 extern char text_start
[], text_end
[];
529 extern char data_start
[], data_end
[];
530 extern char bss_start
[], bss_end
[];
532 static ulong free_mem_ptr
= 0;
533 static ulong free_mem_ptr_end
= 0;
535 #define MIN_ALIGN 4 /* Alignment at 4 bytes */
536 #define MAX_ALIGN 4096 /* Max alignment at 4k */
541 return malloc_align(size
, MIN_ALIGN
);
545 malloc_align(uint size
, uint align_bits
)
552 printf("Malloc error\n");
553 if (free_mem_ptr
== 0)
554 printf("Memory error\n");
557 align_mask
= 1 << align_bits
;
558 if (align_mask
< MIN_ALIGN
)
559 align_mask
= MIN_ALIGN
;
560 if (align_mask
> MAX_ALIGN
)
561 align_mask
= MAX_ALIGN
;
563 free_mem_ptr
= (free_mem_ptr
+ align_mask
) & ~align_mask
;
565 p
= (void *) free_mem_ptr
;
566 free_mem_ptr
+= size
;
568 if (free_mem_ptr
>= free_mem_ptr_end
)
569 printf("Out of memory\n");
580 /* get processor cycle count */
583 #define get_cycle_count get_c0_count
584 #elif defined(__arm__) || defined(__thumb__) || defined(__thumb2__)
585 #define get_cycle_count get_arm_cyclecount
586 #ifdef __ARM_ARCH_7A__
587 extern long _getticks(void);
588 #define get_arm_cyclecount (uint32)_getticks
595 return get_cycle_count();
598 /* microsecond delay */
600 /* Default to 125 MHz */
601 static uint32 cpu_clock
= 125000000;
602 static uint32 c0counts_per_us
= 125000000 / 2000000;
603 static uint32 c0counts_per_ms
= 125000000 / 2000;
610 curr
= get_cycle_count();
611 lim
= curr
+ (us
* c0counts_per_us
);
614 while (get_cycle_count() > curr
)
617 while (get_cycle_count() < lim
)
623 /* No trap handling in self-decompressing boots */
624 extern void trap_init(void);
631 #endif /* !MIN_DO_TRAP */
634 serial_add(void *regs
, uint irq
, uint baud_base
, uint reg_shift
)
638 if (min_uart
.reg_base
)
641 min_uart
.reg_base
= regs
;
643 min_uart
.baud_base
= baud_base
/ 16;
644 min_uart
.reg_shift
= reg_shift
;
646 /* Set baud and 8N1 */
647 #if defined(CFG_SIM) && defined(__ARM_ARCH_7A__)
648 quot
= (min_uart
.baud_base
+ 300) / 600;
650 quot
= (min_uart
.baud_base
+ 57600) / 115200;
652 serial_out(&min_uart
, UART_LCR
, UART_LCR_DLAB
);
653 serial_out(&min_uart
, UART_DLL
, quot
& 0xff);
654 serial_out(&min_uart
, UART_DLM
, quot
>> 8);
655 serial_out(&min_uart
, UART_LCR
, UART_LCR_WLEN8
);
657 /* According to the Synopsys website: "the serial clock
658 * modules must have time to see new register values
659 * and reset their respective state machines. This
660 * total time is guaranteed to be no more than
661 * (2 * baud divisor * 16) clock cycles of the slower
662 * of the two system clocks. No data should be transmitted
663 * or received before this maximum time expires."
672 uint32 c0counts_per_cycle
;
676 sih
= si_kattach(SI_OSH
);
682 si_mips_init(sih
, 0);
683 c0counts_per_cycle
= 2;
684 #elif defined(__arm__) || defined(__thumb__) || defined(__thumb2__)
686 c0counts_per_cycle
= 1;
691 cpu_clock
= si_cpu_clock(sih
);
692 c0counts_per_us
= cpu_clock
/ (1000000 * c0counts_per_cycle
);
693 c0counts_per_ms
= si_cpu_clock(sih
) / (1000 * c0counts_per_cycle
);
695 /* Don't really need to talk to the uart in simulation */
696 if ((sih
->chippkg
!= HDLSIM_PKG_ID
) && (sih
->chippkg
!= HWSIM_PKG_ID
))
697 si_serial_init(sih
, serial_add
);
700 #if defined(CFG_SHMOO)
704 free_mem_ptr
= _memsize
>> 1;
705 free_mem_ptr_end
= _memsize
- (_memsize
>> 2);
709 free_mem_ptr
= (ulong
) bss_end
;
710 free_mem_ptr_end
= ((ulong
)&sih
) - 8192; /* Enough stack? */
711 #endif /* CFG_SHMOO */
712 return ((void *)sih
);
715 /* translate bcmerros */
717 osl_error(int bcmerror
)