summaryrefslogtreecommitdiffstats
path: root/src/target/firmware/board
diff options
context:
space:
mode:
authorWolfram Sang <wolfram@the-dreams.de>2011-05-04 22:58:17 +0200
committerHarald Welte <laforge@gnumonks.org>2011-05-05 09:52:47 +0200
commita5611f9555fb288149c01371411a1405aa61056e (patch)
treefe968b3ccb2703c11e2785ccb1f23f2b42b3b281 /src/target/firmware/board
parent07589649b1ae07a45afc370e222374281735aa72 (diff)
target/boards: add infrastructure for loaders for Mediatek platforms
We are just interested in the loaders here, no other applications needed. Split it from the compal-based phones. Add mt62xx as first user. Based on a patch by steve-m, but cleaned up and seperated from compal/calypso. Signed-off-by: Steve Markgraf <steve@steve-m.de> Signed-off-by: Wolfram Sang <wolfram@the-dreams.de>
Diffstat (limited to 'src/target/firmware/board')
-rw-r--r--src/target/firmware/board/mediatek/macros.S76
-rw-r--r--src/target/firmware/board/mediatek/ram.lds112
-rw-r--r--src/target/firmware/board/mediatek/start.ram.S26
-rw-r--r--src/target/firmware/board/mediatek/uart.c426
-rw-r--r--src/target/firmware/board/mt62xx/init.c139
5 files changed, 779 insertions, 0 deletions
diff --git a/src/target/firmware/board/mediatek/macros.S b/src/target/firmware/board/mediatek/macros.S
new file mode 100644
index 00000000..14ee6e6a
--- /dev/null
+++ b/src/target/firmware/board/mediatek/macros.S
@@ -0,0 +1,76 @@
+
+.macro clear_bss
+ mov r0, #0
+ ldr r1, =__bss_start
+ ldr r2, =__bss_end
+loop_bss:
+ cmp r1, r2
+ strlo r0, [r1], #4
+ blo loop_bss
+.endm
+
+.macro copy_data
+ ldr r0, =__data_start
+ ldr r1, =_data_start
+ ldr r2, =__data_end
+ cmp r0, r2
+ beq done_data
+loop_data:
+ ldrb r4, [r0], #1
+ strb r4, [r1], #1
+ cmp r0, r2
+ bne loop_data
+done_data:
+.endm
+
+.macro copy_ramtext
+ ldr r0, =__ramtext_start
+ ldr r1, =_ramtext_start
+ ldr r2, =__ramtext_end
+ cmp r0, r2
+ beq done_ramtext
+loop_ramtext:
+ ldrb r4, [r0], #1
+ strb r4, [r1], #1
+ cmp r0, r2
+ bne loop_ramtext
+done_ramtext:
+.endm
+
+ .EQU ARM_MODE_FIQ, 0x11
+ .EQU ARM_MODE_IRQ, 0x12
+ .EQU ARM_MODE_SVC, 0x13
+
+ .EQU I_BIT, 0x80
+ .EQU F_BIT, 0x40
+
+#define TOP_OF_RAM 0x4000a000
+#define FIQ_STACK_SIZE 1024
+#define IRQ_STACK_SIZE 1024
+
+.macro init_stacks
+ /* initialize stacks, starting at TOP_OF_RAM */
+ ldr r0, =TOP_OF_RAM
+
+ /* initialize FIQ stack */
+ msr CPSR_c, #ARM_MODE_FIQ | I_BIT | F_BIT
+ mov r13, r0
+ sub r0, r0, #FIQ_STACK_SIZE
+
+ /* initialize IRQ stack */
+ msr CPSR_c, #ARM_MODE_IRQ | I_BIT | F_BIT
+ mov r13, r0
+ sub r0, r0, #IRQ_STACK_SIZE
+
+ /* initialize supervisor stack */
+ msr CPSR_c, #ARM_MODE_SVC | I_BIT | F_BIT
+ mov r13, r0
+.endm
+
+.macro call_ctors
+ /* call constructor functions */
+ ldr r0, =_ctor_start
+ ldr r1, =_ctor_end
+ bl do_global_ctors
+.endm
+
diff --git a/src/target/firmware/board/mediatek/ram.lds b/src/target/firmware/board/mediatek/ram.lds
new file mode 100644
index 00000000..465c0ba9
--- /dev/null
+++ b/src/target/firmware/board/mediatek/ram.lds
@@ -0,0 +1,112 @@
+/*
+ * Linker script for running from internal SRAM on MTK phones
+ *
+ * This script is tailored specifically to the requirements imposed
+ * on us by the Mediatek bootloader.
+ *
+ */
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_start)
+MEMORY
+{
+ /* mtk-loaded binary: our text, initialized data */
+ LRAM (rw) : ORIGIN = 0x40000000, LENGTH = 0x00005000
+ /* mtk-loaded binary: our unitialized data, stacks, heap */
+ IRAM (rw) : ORIGIN = 0x40005000, LENGTH = 0x00005000
+}
+SECTIONS
+{
+ . = 0x40000000;
+
+ /* romloader data section, contains passthru interrupt vectors */
+ .mtk.loader (NOLOAD) : { . = 0x1400; } > LRAM
+
+ /* initialization code */
+ . = ALIGN(4);
+ .text.start : {
+ PROVIDE(_start = .);
+ KEEP(*(.text.start))
+ *(.text.start)
+ } > LRAM
+
+ /* code */
+ . = ALIGN(4);
+ .text (LOADADDR(.text.start) + SIZEOF(.text.start)) :
+ AT (LOADADDR(.text.start) + SIZEOF(.text.start)) {
+ /* regular code */
+ *(.text*)
+ /* always-in-ram code */
+ *(.ramtext*)
+ /* gcc voodoo */
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+ . = ALIGN(4);
+ } > LRAM
+ PROVIDE(_text_start = LOADADDR(.text));
+ PROVIDE(_text_end = LOADADDR(.text) + SIZEOF(.text));
+
+ /* constructor pointers */
+ .ctors : {
+ /* ctor count */
+ LONG(SIZEOF(.ctors) / 4 - 2)
+ /* ctor pointers */
+ KEEP(*(SORT(.ctors)))
+ /* end of list */
+ LONG(0)
+ } > LRAM
+ PROVIDE(_ctor_start = LOADADDR(.ctors));
+ PROVIDE(_ctor_end = LOADADDR(.ctors) + SIZEOF(.ctors));
+
+ /* destructor pointers */
+ .dtors : {
+ /* dtor count */
+ LONG(SIZEOF(.dtors) / 4 - 2)
+ /* dtor pointers */
+ KEEP(*(SORT(.dtors)))
+ /* end of list */
+ LONG(0)
+ } > LRAM
+ PROVIDE(_dtor_start = LOADADDR(.dtors));
+ PROVIDE(_dtor_end = LOADADDR(.dtors) + SIZEOF(.dtors));
+
+ /* read-only data */
+ . = ALIGN(4);
+ .rodata : {
+ *(.rodata*)
+ } > LRAM
+ PROVIDE(_rodata_start = LOADADDR(.rodata));
+ PROVIDE(_rodata_end = LOADADDR(.rodata) + SIZEOF(.rodata));
+
+ /* initialized data */
+ . = ALIGN(4);
+ .data : {
+ *(.data)
+ } > LRAM
+ PROVIDE(_data_start = LOADADDR(.data));
+ PROVIDE(_data_end = LOADADDR(.data) + SIZEOF(.data));
+
+ /* pic offset tables */
+ . = ALIGN(4);
+ .got : {
+ *(.got)
+ *(.got.plt) *(.igot.plt) *(.got) *(.igot)
+ } > LRAM
+ PROVIDE(_got_start = LOADADDR(.got));
+ PROVIDE(_got_end = LOADADDR(.got) + SIZEOF(.got));
+
+ /* uninitialized data */
+ .bss (NOLOAD) : {
+ . = ALIGN(4);
+ __bss_start = .;
+ *(.bss)
+ } > IRAM
+ . = ALIGN(4);
+ __bss_end = .;
+ PROVIDE(_bss_start = __bss_start);
+ PROVIDE(_bss_end = __bss_end);
+
+ /* end of image */
+ . = ALIGN(4);
+ _end = .;
+ PROVIDE(end = .);
+}
diff --git a/src/target/firmware/board/mediatek/start.ram.S b/src/target/firmware/board/mediatek/start.ram.S
new file mode 100644
index 00000000..c8f242c0
--- /dev/null
+++ b/src/target/firmware/board/mediatek/start.ram.S
@@ -0,0 +1,26 @@
+
+.section .text.start
+
+#include "macros.S"
+
+.globl _start
+_start:
+ /* clear bss section */
+ clear_bss
+
+ /* initialize all stacks */
+ init_stacks
+
+ /* call constructors */
+ call_ctors
+
+ /* jump to main */
+ ldr pc, _jump_main
+
+ /* endless loop at end of program */
+_loop:
+ b _loop
+ b _start
+
+_jump_main:
+ .word main
diff --git a/src/target/firmware/board/mediatek/uart.c b/src/target/firmware/board/mediatek/uart.c
new file mode 100644
index 00000000..ff82245e
--- /dev/null
+++ b/src/target/firmware/board/mediatek/uart.c
@@ -0,0 +1,426 @@
+/* MediaTek MT62xx internal UART Driver
+ *
+ * based on the Calypso driver, so there might be some cruft from it left...
+ *
+ * (C) 2010 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2010 by Ingo Albrecht <prom@berlin.ccc.de>
+ * (C) 2010 by Steve Markgraf <steve@steve-m.de>
+ * (C) 2011 by Wolfram Sang <wolfram@the-dreams.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <debug.h>
+#include <memory.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <defines.h>
+#include <uart.h>
+#include <console.h>
+
+#include <comm/sercomm.h>
+
+#include <calypso/irq.h>
+
+/* MT622x */
+#if 0
+#define BASE_ADDR_UART1 0x80130000
+#define BASE_ADDR_UART2 0x80180000
+#define BASE_ADDR_UART3 0x801b0000
+#endif
+
+/* MT 6235 */
+#define BASE_ADDR_UART1 0x81030000
+
+//TODO make UART2 and 3 work
+#define UART_REG(n,m) (BASE_ADDR_UART1 + (m))
+
+#define LCR7BIT 0x80
+#define LCRBFBIT 0x40
+#define MCR6BIT 0x20
+#define REG_OFFS(m) ((m) & ~(LCR7BIT|LCRBFBIT|MCR6BIT))
+/* read access LCR[7] = 0 */
+enum uart_reg {
+ RBR = 0x00,
+ IER = 0x04,
+ IIR = 0x08,
+ LCR = 0x0c,
+ MCR = 0x10,
+ LSR = 0x14,
+ MSR = 0x18,
+ SCR = 0x1c,
+ AUTOBAUD_EN = 0x20,
+ HIGHSPEED = 0x24,
+ SAMPLE_COUNT = 0x28,
+ SAMPLE_POINT = 0x2c,
+ AUTOBAUD_REG = 0x30,
+ RATE_FIX_REG = 0x34, /* undocumented */
+ AUTOBAUDSAMPLE = 0x38,
+ GUARD = 0x3c,
+ ESCAPE_DAT = 0x40,
+ ESCAPE_EN = 0x44,
+ SLEEP_EN = 0x48,
+ VFIFO_EN = 0x4c,
+/* read access LCR[7] = 1 */
+ DLL = RBR,
+ DLH = IER,
+/* read/write access LCR[7:0] = 0xbf */
+ EFR = IIR | LCRBFBIT,
+ XON1 = MCR | LCRBFBIT,
+ XON2 = LSR | LCRBFBIT,
+ XOFF1 = MSR | LCRBFBIT,
+ XOFF2 = SCR | LCRBFBIT,
+};
+
+enum fcr_bits {
+ FIFO_EN = (1 << 0),
+ RX_FIFO_CLEAR = (1 << 1),
+ TX_FIFO_CLEAR = (1 << 2),
+ DMA_MODE = (1 << 3),
+};
+#define TX_FIFO_TRIG_SHIFT 4
+#define RX_FIFO_TRIG_SHIFT 6
+
+enum iir_bits {
+ IIR_INT_PENDING = 0x01,
+ IIR_INT_TYPE = 0x3E,
+ IIR_INT_TYPE_RX_STATUS_ERROR = 0x06,
+ IIR_INT_TYPE_RX_TIMEOUT = 0x0C,
+ IIR_INT_TYPE_RBR = 0x04,
+ IIR_INT_TYPE_THR = 0x02,
+ IIR_INT_TYPE_MSR = 0x00,
+ IIR_INT_TYPE_XOFF = 0x10,
+ IIR_INT_TYPE_FLOW = 0x20,
+ IIR_FCR0_MIRROR = 0xC0,
+};
+
+
+/* enable or disable the divisor latch for access to DLL, DLH */
+static void uart_set_lcr7bit(int uart, int on)
+{
+ uint8_t reg;
+
+ reg = readb(UART_REG(uart, LCR));
+ if (on)
+ reg |= (1 << 7);
+ else
+ reg &= ~(1 << 7);
+ writeb(reg, UART_REG(uart, LCR));
+}
+
+static uint8_t old_lcr;
+static void uart_set_lcr_bf(int uart, int on)
+{
+ if (on) {
+ old_lcr = readb(UART_REG(uart, LCR));
+ writeb(0xBF, UART_REG(uart, LCR));
+ } else {
+ writeb(old_lcr, UART_REG(uart, LCR));
+ }
+}
+
+/* Enable or disable the TCR_TLR latch bit in MCR[6] */
+static void uart_set_mcr6bit(int uart, int on)
+{
+ uint8_t mcr;
+ /* we assume EFR[4] is always set to 1 */
+ mcr = readb(UART_REG(uart, MCR));
+ if (on)
+ mcr |= (1 << 6);
+ else
+ mcr &= ~(1 << 6);
+ writeb(mcr, UART_REG(uart, MCR));
+}
+
+static void uart_reg_write(int uart, enum uart_reg reg, uint8_t val)
+{
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 1);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 1);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 1);
+
+ writeb(val, UART_REG(uart, REG_OFFS(reg)));
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 0);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 0);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 0);
+}
+
+/* read from a UART register, applying any required latch bits */
+static uint8_t uart_reg_read(int uart, enum uart_reg reg)
+{
+ uint8_t ret;
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 1);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 1);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 1);
+
+ ret = readb(UART_REG(uart, REG_OFFS(reg)));
+
+ if (reg & LCRBFBIT)
+ uart_set_lcr_bf(uart, 0);
+ else if (reg & LCR7BIT)
+ uart_set_lcr7bit(uart, 0);
+ else if (reg & MCR6BIT)
+ uart_set_mcr6bit(uart, 0);
+
+ return ret;
+}
+
+static void uart_irq_handler_cons(__unused int irqnr)
+{
+ const uint8_t uart = CONS_UART_NR;
+ uint8_t iir;
+
+ //uart_putchar_nb(uart, 'U');
+
+ iir = uart_reg_read(uart, IIR);
+ if (iir & IIR_INT_PENDING)
+ return;
+
+ switch (iir & IIR_INT_TYPE) {
+ case IIR_INT_TYPE_RBR:
+ break;
+ case IIR_INT_TYPE_THR:
+ if (cons_rb_flush() == 1) {
+ /* everything was flushed, disable RBR IRQ */
+ uint8_t ier = uart_reg_read(uart, IER);
+ ier &= ~(1 << 1);
+ uart_reg_write(uart, IER, ier);
+ }
+ break;
+ case IIR_INT_TYPE_MSR:
+ break;
+ case IIR_INT_TYPE_RX_STATUS_ERROR:
+ break;
+ case IIR_INT_TYPE_RX_TIMEOUT:
+ break;
+ case IIR_INT_TYPE_XOFF:
+ break;
+ }
+}
+
+static void uart_irq_handler_sercomm(__unused int irqnr)
+{
+ const uint8_t uart = SERCOMM_UART_NR;
+ uint8_t iir, ch;
+
+ //uart_putchar_nb(uart, 'U');
+
+ iir = uart_reg_read(uart, IIR);
+ if (iir & IIR_INT_PENDING)
+ return;
+
+ switch (iir & IIR_INT_TYPE) {
+ case IIR_INT_TYPE_RX_TIMEOUT:
+ case IIR_INT_TYPE_RBR:
+ /* as long as we have rx data available */
+ while (uart_getchar_nb(uart, &ch)) {
+ if (sercomm_drv_rx_char(ch) < 0) {
+ /* sercomm cannot receive more data right now */
+ uart_irq_enable(uart, UART_IRQ_RX_CHAR, 0);
+ }
+ }
+ break;
+ case IIR_INT_TYPE_THR:
+ /* as long as we have space in the FIFO */
+ while (!uart_tx_busy(uart)) {
+ /* get a byte from sercomm */
+ if (!sercomm_drv_pull(&ch)) {
+ /* no more bytes in sercomm, stop TX interrupts */
+ uart_irq_enable(uart, UART_IRQ_TX_EMPTY, 0);
+ break;
+ }
+ /* write the byte into the TX FIFO */
+ uart_putchar_nb(uart, ch);
+ }
+ break;
+ case IIR_INT_TYPE_MSR:
+ printf("UART IRQ MSR\n");
+ break;
+ case IIR_INT_TYPE_RX_STATUS_ERROR:
+ printf("UART IRQ RX_SE\n");
+ break;
+ case IIR_INT_TYPE_XOFF:
+ printf("UART IRQXOFF\n");
+ break;
+ }
+}
+
+void uart_init(uint8_t uart, __unused uint8_t interrupts)
+{
+ /* no interrupts, only polling so far */
+
+ uart_reg_write(uart, IER, 0x00);
+ if (uart == CONS_UART_NR) {
+ cons_init();
+ } else {
+ sercomm_init();
+ uart_irq_enable(uart, UART_IRQ_RX_CHAR, 1);
+ }
+
+ uart_reg_write(uart, AUTOBAUD_EN, 0x00); /* disable AUTOBAUD */
+ uart_reg_write(uart, EFR, 0x10); /* Enhanced Features Register */
+
+ /* no XON/XOFF flow control, ENHANCED_EN, no auto-RTS/CTS */
+ uart_reg_write(uart, EFR, (1 << 4));
+ /* enable Tx/Rx FIFO, Tx trigger at 56 spaces, Rx trigger at 60 chars */
+ //FIXME check those FIFO settings
+ uart_reg_write(uart, IIR, FIFO_EN | RX_FIFO_CLEAR | TX_FIFO_CLEAR |
+ (3 << TX_FIFO_TRIG_SHIFT) | (1 << RX_FIFO_TRIG_SHIFT));
+
+ /* RBR interrupt only when TX FIFO and TX shift register are empty */
+ uart_reg_write(uart, SCR, (1 << 0));// | (1 << 3));
+
+ /* 8 bit, 1 stop bit, no parity, no break */
+ uart_reg_write(uart, LCR, 0x03);
+
+ uart_set_lcr7bit(uart, 0);
+}
+
+void uart_poll(uint8_t uart) {
+ if(uart == CONS_UART_NR) {
+ uart_irq_handler_cons(0);
+ } else {
+ uart_irq_handler_sercomm(0);
+ }
+}
+
+void uart_irq_enable(uint8_t uart, enum uart_irq irq, int on)
+{
+ uint8_t ier = uart_reg_read(uart, IER);
+ uint8_t mask = 0;
+
+ switch (irq) {
+ case UART_IRQ_TX_EMPTY:
+ mask = (1 << 1);
+ break;
+ case UART_IRQ_RX_CHAR:
+ mask = (1 << 0);
+ break;
+ }
+
+ if (on)
+ ier |= mask;
+ else
+ ier &= ~mask;
+
+ uart_reg_write(uart, IER, ier);
+}
+
+
+void uart_putchar_wait(uint8_t uart, int c)
+{
+ /* wait while TX FIFO indicates full */
+ while (~readb(UART_REG(uart, LSR)) & 0x20) { }
+
+ /* put character in TX FIFO */
+ writeb(c, UART_REG(uart, RBR));
+}
+
+int uart_putchar_nb(uint8_t uart, int c)
+{
+ /* if TX FIFO indicates full, abort */
+ if (~readb(UART_REG(uart, LSR)) & 0x20)
+ return 0;
+
+ writeb(c, UART_REG(uart, RBR));
+ return 1;
+}
+
+int uart_getchar_nb(uint8_t uart, uint8_t *ch)
+{
+ uint8_t lsr;
+
+ lsr = readb(UART_REG(uart, LSR));
+
+ /* something strange happened */
+ if (lsr & 0x02)
+ printf("LSR RX_OE\n");
+ if (lsr & 0x04)
+ printf("LSR RX_PE\n");
+ if (lsr & 0x08)
+ printf("LSR RX_FE\n");
+ if (lsr & 0x10)
+ printf("LSR RX_BI\n");
+ if (lsr & 0x80)
+ printf("LSR RX_FIFO_STS\n");
+
+ /* is the Rx FIFO empty? */
+ if (!(lsr & 0x01))
+ return 0;
+
+ *ch = readb(UART_REG(uart, RBR));
+ //printf("getchar_nb(%u) = %02x\n", uart, *ch);
+ return 1;
+}
+
+int uart_tx_busy(uint8_t uart)
+{
+ /* Check THRE bit (LSR[5]) to see if FIFO is full */
+ if (~readb(UART_REG(uart, LSR)) & 0x20)
+ return 1;
+ return 0;
+}
+
+#if 0
+/* 26MHz clock input (used when no PLL initialized directly after poweron) */
+static const uint16_t divider[] = {
+ [UART_38400] = 42,
+ [UART_57600] = 28,
+ [UART_115200] = 14,
+ [UART_230400] = 7,
+ [UART_460800] = 14, /* would need UART_REG(HIGHSPEED) = 1 or 2 */
+ [UART_921600] = 7, /* would need UART_REG(HIGHSPEED) = 2 */
+};
+#endif
+
+/* 52MHz clock input (after PLL init) */
+static const uint16_t divider[] = {
+ [UART_38400] = 85,
+ [UART_57600] = 56,
+ [UART_115200] = 28,
+ [UART_230400] = 14,
+ [UART_460800] = 7,
+ [UART_921600] = 7, /* would need UART_REG(HIGHSPEED) = 1 */
+};
+
+int uart_baudrate(uint8_t uart, enum uart_baudrate bdrt)
+{
+ uint16_t div;
+
+ if (bdrt > ARRAY_SIZE(divider))
+ return -1;
+
+ div = divider[bdrt];
+ uart_set_lcr7bit(uart, 1);
+ writeb(div & 0xff, UART_REG(uart, DLL));
+ writeb(div >> 8, UART_REG(uart, DLH));
+ uart_set_lcr7bit(uart, 0);
+
+ return 0;
+}
diff --git a/src/target/firmware/board/mt62xx/init.c b/src/target/firmware/board/mt62xx/init.c
new file mode 100644
index 00000000..3f683757
--- /dev/null
+++ b/src/target/firmware/board/mt62xx/init.c
@@ -0,0 +1,139 @@
+/* Initialization for the MT62xx Basebands */
+
+/* (C) 2010 by Steve Markgraf <steve@steve-m.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+
+#include <debug.h>
+#include <ctors.h>
+#include <memory.h>
+#include <board.h>
+#include <keypad.h>
+#include <uart.h>
+#include <console.h>
+#include <delay.h>
+
+#include <flash/cfi_flash.h>
+
+#include <comm/sercomm.h>
+#include <comm/timer.h>
+
+#include <mtk/emi.h>
+#include <mtk/mt6235.h>
+#include <mtk/system.h>
+
+void pll_init(void)
+{
+ /* Power on PLL */
+ writew(0, MTK_PLL_PDN_CON);
+ writew(PLL_CLKSQ_DIV2_DSP | PLL_CLKSQ_DIV2_MCU, MTK_PLL_CLK_CON);
+
+ writew(PLL_RST, MTK_PLL_PLL);
+ writew(0, MTK_PLL_PLL);
+ delay_ms(1);
+
+ /* Turn on PLL for MCU, DSP and USB */
+ writew(PLL_MPLLSEL_PLL | PLL_DPLLSEL | PLL_UPLLSEL, MTK_PLL_PLL);
+
+ /*
+ * Setup MCU clock register:
+ * ARMCLK = 208MHz, AHBx4CLK = 52MHz, AHBx8CLK = 104MHz
+ * we have to write to the read-only part (EMICLK) as well, otherwise
+ * the EMI won't work! (datasheet lies)
+ */
+ writew(7 << MCUCLK_CON_AHBX8CLK_SHIFT |
+ 3 << MCUCLK_CON_AHBX4CLK_SHIFT |
+ 15 << MCUCLK_CON_ARMCLK_SHIFT |
+ 7 << MCUCLK_CON_EMICLK_SHIFT,
+ MTK_CONFG_MCUCLK_CON);
+}
+
+void memory_init(void)
+{
+ int i;
+
+ /* Initialization for Hynix RAM */
+
+ /* Configure DRAM controller */
+ writel(0x0001000e, MTK_EMI_GEND);
+ writel(0x00088a0a, MTK_EMI_GENA);
+ writel(0x00000280, MTK_EMI_GENB);
+ writel(0x52945294, MTK_EMI_GENC);
+ writel(0x1c016605, MTK_EMI_CONL);
+ writel(0x00002828, MTK_EMI_CONM);
+ writel(0x02334000, MTK_EMI_CONI);
+ writel(0x16c12212, MTK_EMI_CONJ);
+ writel(0x032d0000, MTK_EMI_CONK);
+
+ for (i = 0; i < 5; ++i) {
+ /* Setup five single bits, one by one for DRAM init */
+ writel((1 << (24 + i)) | (0x400013), MTK_EMI_CONN);
+ delay_ms(1);
+ writel(0x400013, MTK_EMI_CONN);
+ delay_ms(1);
+ }
+
+#if 0
+ /* Initialization for Toshiba RAM */
+
+ /* Configure DRAM controller */
+ writel(0x0001000E, MTK_EMI_GEND);
+ writel(0x00088E3A, MTK_EMI_GENA);
+ writel(0x000000C0, MTK_EMI_GENB);
+ writel(0x18C618C6, MTK_EMI_GENC);
+ writel(0x18007505, MTK_EMI_CONL);
+ writel(0x00002828, MTK_EMI_CONM);
+ writel(0x00332000, MTK_EMI_CONI);
+ writel(0x3CD24431, MTK_EMI_CONJ);
+ writel(0x02000000, MTK_EMI_CONK);
+
+ for (i = 0; i < 5; ++i) {
+ /* Setup five single bits, one by one for DRAM init */
+ writel((1 << (24 + i)) | (0x500013), MTK_EMI_CONN);
+ delay_ms(1);
+ writel(0x500013, MTK_EMI_CONN);
+ delay_ms(1);
+ }
+
+#endif
+}
+
+void board_init(void)
+{
+ /* powerup the baseband */
+ writew(POWERKEY1_MAGIC, MTK_RTC_POWERKEY1);
+ writew(POWERKEY2_MAGIC, MTK_RTC_POWERKEY2);
+ writew(BBPU_MAGIC | RTC_BBPU_WRITE_EN |
+ RTC_BBPU_BBPU | RTC_BBPU_AUTO,
+ MTK_RTC_BBPU);
+ writew(1, MTK_RTC_WRTGR);
+
+ /* disable watchdog timer */
+ writew(WDT_MODE_KEY, MTK_RGU_WDT_MODE);
+
+ pll_init();
+ memory_init();
+
+ /* Initialize UART without interrupts */
+ uart_init(SERCOMM_UART_NR, 0);
+ uart_baudrate(SERCOMM_UART_NR, UART_115200);
+}