diff options
author | Wolfram Sang <wolfram@the-dreams.de> | 2011-05-04 22:58:17 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2011-05-05 09:52:47 +0200 |
commit | a5611f9555fb288149c01371411a1405aa61056e (patch) | |
tree | fe968b3ccb2703c11e2785ccb1f23f2b42b3b281 /src/target/firmware/board | |
parent | 07589649b1ae07a45afc370e222374281735aa72 (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.S | 76 | ||||
-rw-r--r-- | src/target/firmware/board/mediatek/ram.lds | 112 | ||||
-rw-r--r-- | src/target/firmware/board/mediatek/start.ram.S | 26 | ||||
-rw-r--r-- | src/target/firmware/board/mediatek/uart.c | 426 | ||||
-rw-r--r-- | src/target/firmware/board/mt62xx/init.c | 139 |
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); +} |