summaryrefslogtreecommitdiff
path: root/release/src/shared/min_osl.c
diff options
context:
space:
mode:
authorAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 12:04:58 +0100
committerAndreas Baumann <mail@andreasbaumann.cc>2015-01-03 12:04:58 +0100
commit008d0be72b2f160382c6e880765e96b64a050c65 (patch)
tree36f48a98a3815a408e2ce1693dd182af90f80305 /release/src/shared/min_osl.c
parent611becfb8726c60cb060368541ad98191d4532f5 (diff)
downloadtomato-008d0be72b2f160382c6e880765e96b64a050c65.tar.gz
tomato-008d0be72b2f160382c6e880765e96b64a050c65.tar.bz2
imported original firmware WRT54GL_v4.30.11_11_US
Diffstat (limited to 'release/src/shared/min_osl.c')
-rw-r--r--release/src/shared/min_osl.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/release/src/shared/min_osl.c b/release/src/shared/min_osl.c
new file mode 100644
index 00000000..d50a7fbc
--- /dev/null
+++ b/release/src/shared/min_osl.c
@@ -0,0 +1,320 @@
+/*
+ * Initialization and support routines for self-booting
+ * compressed image.
+ *
+ * Copyright 2005, Broadcom Corporation
+ * All Rights Reserved.
+ *
+ * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
+ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
+ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
+ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
+ *
+ * $Id: min_osl.c,v 1.1.1.3 2005/03/07 07:31:12 kanki Exp $
+ */
+
+#include <osl.h>
+#include <sbutils.h>
+#include <bcmutils.h>
+#include <hndmips.h>
+
+/* Cache support */
+
+/* Cache and line sizes */
+static uint icache_size, ic_lsize, dcache_size, dc_lsize;
+
+static void
+_change_cachability(uint32 cm)
+{
+ uint32 prid, c0reg;
+
+ c0reg = MFC0(C0_CONFIG, 0);
+ c0reg &= ~CONF_CM_CMASK;
+ c0reg |= (cm & CONF_CM_CMASK);
+ MTC0(C0_CONFIG, 0, c0reg);
+ prid = MFC0(C0_PRID, 0);
+ if ((prid & (PRID_COMP_MASK | PRID_IMP_MASK)) ==
+ (PRID_COMP_BROADCOM | PRID_IMP_BCM3302)) {
+ c0reg = MFC0(C0_BROADCOM, 0);
+ /* Enable icache */
+ c0reg |= (1 << 31);
+ /* Enable dcache */
+ c0reg |= (1 << 30);
+ MTC0(C0_BROADCOM, 0 , c0reg);
+ }
+}
+static void (*change_cachability)(uint32);
+
+void
+caches_on(void)
+{
+ uint32 config1;
+ uint start, end, size, lsize;
+
+ /* Save cache config */
+ config1 = MFC0(C0_CONFIG, 1);
+
+ icache_probe(config1, &size, &lsize);
+ icache_size = size;
+ ic_lsize = lsize;
+
+ dcache_probe(config1, &size, &lsize);
+ dcache_size = size;
+ dc_lsize = lsize;
+
+ if ((MFC0(C0_CONFIG, 0) & CONF_CM_CMASK) != CONF_CM_UNCACHED) {
+ blast_dcache();
+ blast_icache();
+ return;
+ }
+
+ /* init icache */
+ start = KSEG0;
+ end = (start + icache_size);
+ MTC0(C0_TAGLO, 0, 0);
+ MTC0(C0_TAGHI, 0, 0);
+ while (start < end) {
+ cache_unroll(start, Index_Store_Tag_I);
+ start += ic_lsize;
+ }
+
+ /* init dcache */
+ start = KSEG0;
+ end = (start + dcache_size);
+ MTC0(C0_TAGLO, 0, 0);
+ MTC0(C0_TAGHI, 0, 0);
+ while (start < end) {
+ cache_unroll(start, Index_Store_Tag_D);
+ start += dc_lsize;
+ }
+
+ /* Must be in KSEG1 to change cachability */
+ change_cachability = (void (*)(uint32)) KSEG1ADDR(_change_cachability);
+ change_cachability(CONF_CM_CACHABLE_NONCOHERENT);
+}
+
+
+#define BCM4710_DUMMY_RREG() (((sbconfig_t *)(KSEG1ADDR(0x18000000 + SBCONFIGOFF)))->sbimstate)
+
+void
+blast_dcache(void)
+{
+ uint32 start, end;
+
+ start = KSEG0;
+ end = start + dcache_size;
+
+ while(start < end) {
+ BCM4710_DUMMY_RREG();
+ cache_unroll(start, Index_Writeback_Inv_D);
+ start += dc_lsize;
+ }
+}
+
+void
+blast_icache(void)
+{
+ uint32 start, end;
+
+ start = KSEG0;
+ end = start + icache_size;
+
+ while(start < end) {
+ cache_unroll(start, Index_Invalidate_I);
+ start += ic_lsize;
+ }
+}
+
+/* uart output */
+
+struct serial_struct {
+ unsigned char *iomem_base;
+ unsigned short iomem_reg_shift;
+ int irq;
+ int baud_base;
+};
+
+static struct serial_struct hndrte_uart;
+
+#define LOG_BUF_LEN (1024)
+#define LOG_BUF_MASK (LOG_BUF_LEN-1)
+static char log_buf[LOG_BUF_LEN];
+static unsigned long log_start;
+
+
+static inline int
+serial_in(struct serial_struct *info, int offset)
+{
+ return ((int)R_REG((uint8 *)(info->iomem_base + (offset << info->iomem_reg_shift))));
+}
+
+static inline void
+serial_out(struct serial_struct *info, int offset, int value)
+{
+ W_REG((uint8 *)(info->iomem_base + (offset << info->iomem_reg_shift)), value);
+ *((volatile unsigned int *) KSEG1ADDR(0x18000000));
+}
+
+void
+putc(int c)
+{
+ /* CR before LF */
+ if (c == '\n')
+ putc('\r');
+
+ /* Store in log buffer */
+ *((char *) KSEG1ADDR(&log_buf[log_start])) = (char) c;
+ log_start = (log_start + 1) & LOG_BUF_MASK;
+
+ /* No UART */
+ if (!hndrte_uart.iomem_base)
+ return;
+
+ while (!(serial_in(&hndrte_uart, UART_LSR) & UART_LSR_THRE));
+ serial_out(&hndrte_uart, UART_TX, c);
+}
+
+/* assert & debugging */
+
+
+/* general purpose memory allocation */
+
+extern char text_start[], text_end[];
+extern char data_start[], data_end[];
+extern char bss_start[], bss_end[];
+
+static ulong free_mem_ptr = 0;
+static ulong free_mem_ptr_end = 0;
+
+void *
+malloc(uint size)
+{
+ void *p;
+
+ /* Sanity check */
+ if (size < 0)
+ printf("Malloc error");
+ if (free_mem_ptr == 0)
+ printf("Memory error");
+
+ /* Align */
+ free_mem_ptr = (free_mem_ptr + 3) & ~3;
+
+ p = (void *) free_mem_ptr;
+ free_mem_ptr += size;
+
+ if (free_mem_ptr >= free_mem_ptr_end)
+ printf("Out of memory");
+
+ return p;
+}
+
+int
+free(void *where)
+{
+ return 0;
+}
+
+/* microsecond delay */
+
+/* Default to 125 MHz */
+static unsigned long cpu_clock = 125000000;
+
+static inline void
+__delay(uint loops)
+{
+ __asm__ __volatile__ (
+ ".set\tnoreorder\n"
+ "1:\tbnez\t%0,1b\n\t"
+ "subu\t%0,1\n\t"
+ ".set\treorder"
+ :"=r" (loops)
+ :"0" (loops));
+}
+
+void
+udelay(uint us)
+{
+ uint loops;
+
+ loops = cpu_clock / 5;
+
+ __delay(loops);
+}
+
+extern char *
+getvar(char *vars, char *name)
+{
+ return NULL;
+}
+
+extern int
+getintvar(char *vars, char *name)
+{
+ return 0;
+}
+
+/* No trap handling in self-decompressing boots */
+extern void trap_init(void);
+
+void
+trap_init(void)
+{
+}
+
+
+static void
+serial_add(void *regs, uint irq, uint baud_base, uint reg_shift)
+{
+ int quot;
+
+ if (hndrte_uart.iomem_base)
+ return;
+
+ hndrte_uart.iomem_base = regs;
+ hndrte_uart.irq = irq;
+ hndrte_uart.baud_base = baud_base / 16;
+ hndrte_uart.iomem_reg_shift = reg_shift;
+
+ /* Set baud and 8N1 */
+ quot = (hndrte_uart.baud_base + 57600) / 115200;
+ serial_out(&hndrte_uart, UART_LCR, UART_LCR_DLAB);
+ serial_out(&hndrte_uart, UART_DLL, quot & 0xff);
+ serial_out(&hndrte_uart, UART_DLM, quot >> 8);
+ serial_out(&hndrte_uart, UART_LCR, UART_LCR_WLEN8);
+
+ /* According to the Synopsys website: "the serial clock
+ * modules must have time to see new register values
+ * and reset their respective state machines. This
+ * total time is guaranteed to be no more than
+ * (2 * baud divisor * 16) clock cycles of the slower
+ * of the two system clocks. No data should be transmitted
+ * or received before this maximum time expires."
+ */
+ udelay(1000);
+}
+
+
+void *
+osl_init()
+{
+ uint32 c0reg;
+ void *sbh;
+
+ /* Disable interrupts */
+ c0reg = MFC0(C0_STATUS, 0);
+ c0reg &= ~ST0_IE;
+ MTC0(C0_STATUS, 0 , c0reg);
+
+ /* Scan backplane */
+ sbh = sb_kattach();
+
+ sb_mips_init(sbh);
+ sb_serial_init(sbh, serial_add);
+
+ /* Init malloc */
+ free_mem_ptr = (ulong) bss_end;
+ free_mem_ptr_end = ((ulong)&c0reg) - 8192; /* Enough stack? */
+
+ return (sbh);
+}