summaryrefslogtreecommitdiff
path: root/arch/mips/cpu
diff options
context:
space:
mode:
authorXiangfu Liu <xiangfu@openmobilefree.net>2011-10-12 12:24:06 +0800
committerShinya Kuribayashi <skuribay@pobox.com>2011-10-10 22:06:12 +0900
commit80421fcc3ed1843f62a4a463548a4f33cdde362f (patch)
tree0e17b489ca37e73be16fbc1f85fd8b8c63cb773b /arch/mips/cpu
parent0841ca90f22d73b0ea4642ef1ce33d879bb2f3ff (diff)
downloadu-boot-imx-80421fcc3ed1843f62a4a463548a4f33cdde362f.zip
u-boot-imx-80421fcc3ed1843f62a4a463548a4f33cdde362f.tar.gz
u-boot-imx-80421fcc3ed1843f62a4a463548a4f33cdde362f.tar.bz2
MIPS: Ingenic XBurst Jz4740 processor support
Jz4740 is a multimedia application processor targeting for mobile devices like e-Dictionary, eBook, portable media player (PMP) and GPS navigator. Jz4740 is powered by Ingenic 360 MHz XBurst CPU core (JzRISC), in which RISC/SIMD/DSP hybrid instruction set architecture provides high integration, high performance and low power consumption. JzRISC incorporated in Jz4740 is the advanced and power-efficient 32-bit RISC core, compatible with MIPS32, with 16K I-Cache and 16K D-Cache, and can operate at speeds up to 400 MHz. On-chip modules such as LCD controller, embedded audio codec, multi- channel SAR-ADC, AC97/I2S controller and camera I/F offer a rich suite of peripherals for multimedia application. NAND controller (SLC/MLC), USB (host 1.1 and device 2.0), UART, I2C, SPI, etc. are also available. For more info about Ingenic XBurst Jz4740: http://en.ingenic.cn/eng/ http://www.linux-mips.org/wiki/Ingenic This patch introduces XBurst CPU support in U-Boot. It's compatible with MIPS32, but requires a bit different cache maintenance, timer routines, and boot mechanism using USB boot tool, so XBurst support can go into a separate new home, cpu/xburst/. Signed-off-by: Xiangfu Liu <xiangfu@openmobilefree.net> Acked-by: Daniel <zpxu@ingenic.cn> Signed-off-by: Shinya Kuribayashi <skuribay@pobox.com>
Diffstat (limited to 'arch/mips/cpu')
-rw-r--r--arch/mips/cpu/xburst/Makefile49
-rw-r--r--arch/mips/cpu/xburst/config.mk24
-rw-r--r--arch/mips/cpu/xburst/cpu.c152
-rw-r--r--arch/mips/cpu/xburst/jz4740.c248
-rw-r--r--arch/mips/cpu/xburst/jz_serial.c114
-rw-r--r--arch/mips/cpu/xburst/start.S171
-rw-r--r--arch/mips/cpu/xburst/timer.c162
7 files changed, 920 insertions, 0 deletions
diff --git a/arch/mips/cpu/xburst/Makefile b/arch/mips/cpu/xburst/Makefile
new file mode 100644
index 0000000..b1f2ae4
--- /dev/null
+++ b/arch/mips/cpu/xburst/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2011 Xiangfu Liu <xiangfu@openmobilefree.net>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+START = start.o
+SOBJS-y =
+COBJS-y = cpu.o timer.o jz_serial.o
+
+COBJS-$(CONFIG_JZ4740) += jz4740.o
+
+SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/mips/cpu/xburst/config.mk b/arch/mips/cpu/xburst/config.mk
new file mode 100644
index 0000000..bce0c1b
--- /dev/null
+++ b/arch/mips/cpu/xburst/config.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (C) 2011 Xiangfu Liu <xiangfu@openmobilefree.net>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_CPPFLAGS += -march=mips32 -EL
+PLATFORM_LDFLAGS += -EL
diff --git a/arch/mips/cpu/xburst/cpu.c b/arch/mips/cpu/xburst/cpu.c
new file mode 100644
index 0000000..e976341
--- /dev/null
+++ b/arch/mips/cpu/xburst/cpu.c
@@ -0,0 +1,152 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+ * (C) Copyright 2011
+ * Xiangfu Liu <xiangfu@openmobilefree.net>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <netdev.h>
+#include <asm/mipsregs.h>
+#include <asm/cacheops.h>
+#include <asm/reboot.h>
+#include <asm/io.h>
+#include <asm/jz4740.h>
+
+#define cache_op(op, addr) \
+ __asm__ __volatile__( \
+ ".set push\n" \
+ ".set noreorder\n" \
+ ".set mips3\n" \
+ "cache %0, %1\n" \
+ ".set pop\n" \
+ : \
+ : "i" (op), "R" (*(unsigned char *)(addr)))
+
+void __attribute__((weak)) _machine_restart(void)
+{
+ struct jz4740_wdt *wdt = (struct jz4740_wdt *)JZ4740_WDT_BASE;
+ struct jz4740_tcu *tcu = (struct jz4740_tcu *)JZ4740_TCU_BASE;
+ u16 tmp;
+
+ /* wdt_select_extalclk() */
+ tmp = readw(&wdt->tcsr);
+ tmp &= ~(WDT_TCSR_EXT_EN | WDT_TCSR_RTC_EN | WDT_TCSR_PCK_EN);
+ tmp |= WDT_TCSR_EXT_EN;
+ writew(tmp, &wdt->tcsr);
+
+ /* wdt_select_clk_div64() */
+ tmp = readw(&wdt->tcsr);
+ tmp &= ~WDT_TCSR_PRESCALE_MASK;
+ tmp |= WDT_TCSR_PRESCALE64,
+ writew(tmp, &wdt->tcsr);
+
+ writew(100, &wdt->tdr); /* wdt_set_data(100) */
+ writew(0, &wdt->tcnt); /* wdt_set_count(0); */
+ writew(TCU_TSSR_WDTSC, &tcu->tscr); /* tcu_start_wdt_clock */
+ writeb(readb(&wdt->tcer) | WDT_TCER_TCEN, &wdt->tcer); /* wdt start */
+
+ while (1)
+ ;
+}
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ _machine_restart();
+
+ fprintf(stderr, "*** reset failed ***\n");
+ return 0;
+}
+
+void flush_cache(ulong start_addr, ulong size)
+{
+ unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
+ unsigned long addr = start_addr & ~(lsize - 1);
+ unsigned long aend = (start_addr + size - 1) & ~(lsize - 1);
+
+ for (; addr <= aend; addr += lsize) {
+ cache_op(Hit_Writeback_Inv_D, addr);
+ cache_op(Hit_Invalidate_I, addr);
+ }
+}
+
+void flush_dcache_range(ulong start_addr, ulong stop)
+{
+ unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
+ unsigned long addr = start_addr & ~(lsize - 1);
+ unsigned long aend = (stop - 1) & ~(lsize - 1);
+
+ for (; addr <= aend; addr += lsize)
+ cache_op(Hit_Writeback_Inv_D, addr);
+}
+
+void invalidate_dcache_range(ulong start_addr, ulong stop)
+{
+ unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
+ unsigned long addr = start_addr & ~(lsize - 1);
+ unsigned long aend = (stop - 1) & ~(lsize - 1);
+
+ for (; addr <= aend; addr += lsize)
+ cache_op(Hit_Invalidate_D, addr);
+}
+
+void flush_icache_all(void)
+{
+ u32 addr, t = 0;
+
+ __asm__ __volatile__("mtc0 $0, $28"); /* Clear Taglo */
+ __asm__ __volatile__("mtc0 $0, $29"); /* Clear TagHi */
+
+ for (addr = CKSEG0; addr < CKSEG0 + CONFIG_SYS_ICACHE_SIZE;
+ addr += CONFIG_SYS_CACHELINE_SIZE) {
+ cache_op(Index_Store_Tag_I, addr);
+ }
+
+ /* invalidate btb */
+ __asm__ __volatile__(
+ ".set mips32\n\t"
+ "mfc0 %0, $16, 7\n\t"
+ "nop\n\t"
+ "ori %0,2\n\t"
+ "mtc0 %0, $16, 7\n\t"
+ ".set mips2\n\t"
+ :
+ : "r" (t));
+}
+
+void flush_dcache_all(void)
+{
+ u32 addr;
+
+ for (addr = CKSEG0; addr < CKSEG0 + CONFIG_SYS_DCACHE_SIZE;
+ addr += CONFIG_SYS_CACHELINE_SIZE) {
+ cache_op(Index_Writeback_Inv_D, addr);
+ }
+
+ __asm__ __volatile__("sync");
+}
+
+void flush_cache_all(void)
+{
+ flush_dcache_all();
+ flush_icache_all();
+}
diff --git a/arch/mips/cpu/xburst/jz4740.c b/arch/mips/cpu/xburst/jz4740.c
new file mode 100644
index 0000000..c0b9817
--- /dev/null
+++ b/arch/mips/cpu/xburst/jz4740.c
@@ -0,0 +1,248 @@
+/*
+ * Jz4740 common routines
+ * Copyright (c) 2006 Ingenic Semiconductor, <jlwei@ingenic.cn>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/jz4740.h>
+
+void enable_interrupts(void)
+{
+}
+
+int disable_interrupts(void)
+{
+ return 0;
+}
+
+/*
+ * PLL output clock = EXTAL * NF / (NR * NO)
+ * NF = FD + 2, NR = RD + 2
+ * NO = 1 (if OD = 0), NO = 2 (if OD = 1 or 2), NO = 4 (if OD = 3)
+ */
+void pll_init(void)
+{
+ struct jz4740_cpm *cpm = (struct jz4740_cpm *)JZ4740_CPM_BASE;
+
+ register unsigned int cfcr, plcr1;
+ int n2FR[33] = {
+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+ 9
+ };
+ int div[5] = {1, 3, 3, 3, 3}; /* divisors of I:S:P:L:M */
+ int nf, pllout2;
+
+ cfcr = CPM_CPCCR_CLKOEN |
+ CPM_CPCCR_PCS |
+ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
+ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
+ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
+ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT) |
+ (n2FR[div[4]] << CPM_CPCCR_LDIV_BIT);
+
+ pllout2 = (cfcr & CPM_CPCCR_PCS) ?
+ CONFIG_SYS_CPU_SPEED : (CONFIG_SYS_CPU_SPEED / 2);
+
+ /* Init USB Host clock, pllout2 must be n*48MHz */
+ writel(pllout2 / 48000000 - 1, &cpm->uhccdr);
+
+ nf = CONFIG_SYS_CPU_SPEED * 2 / CONFIG_SYS_EXTAL;
+ plcr1 = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */
+ (0 << CPM_CPPCR_PLLN_BIT) | /* RD=0, NR=2 */
+ (0 << CPM_CPPCR_PLLOD_BIT) | /* OD=0, NO=1 */
+ (0x20 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */
+ CPM_CPPCR_PLLEN; /* enable PLL */
+
+ /* init PLL */
+ writel(cfcr, &cpm->cpccr);
+ writel(plcr1, &cpm->cppcr);
+}
+
+void sdram_init(void)
+{
+ struct jz4740_emc *emc = (struct jz4740_emc *)JZ4740_EMC_BASE;
+
+ register unsigned int dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns;
+
+ unsigned int cas_latency_sdmr[2] = {
+ EMC_SDMR_CAS_2,
+ EMC_SDMR_CAS_3,
+ };
+
+ unsigned int cas_latency_dmcr[2] = {
+ 1 << EMC_DMCR_TCL_BIT, /* CAS latency is 2 */
+ 2 << EMC_DMCR_TCL_BIT /* CAS latency is 3 */
+ };
+
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ cpu_clk = CONFIG_SYS_CPU_SPEED;
+ mem_clk = cpu_clk * div[__cpm_get_cdiv()] / div[__cpm_get_mdiv()];
+
+ writel(0, &emc->bcr); /* Disable bus release */
+ writew(0, &emc->rtcsr); /* Disable clock for counting */
+
+ /* Fault DMCR value for mode register setting*/
+#define SDRAM_ROW0 11
+#define SDRAM_COL0 8
+#define SDRAM_BANK40 0
+
+ dmcr0 = ((SDRAM_ROW0 - 11) << EMC_DMCR_RA_BIT) |
+ ((SDRAM_COL0 - 8) << EMC_DMCR_CA_BIT) |
+ (SDRAM_BANK40 << EMC_DMCR_BA_BIT) |
+ (SDRAM_BW16 << EMC_DMCR_BW_BIT) |
+ EMC_DMCR_EPIN |
+ cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)];
+
+ /* Basic DMCR value */
+ dmcr = ((SDRAM_ROW - 11) << EMC_DMCR_RA_BIT) |
+ ((SDRAM_COL - 8) << EMC_DMCR_CA_BIT) |
+ (SDRAM_BANK4 << EMC_DMCR_BA_BIT) |
+ (SDRAM_BW16 << EMC_DMCR_BW_BIT) |
+ EMC_DMCR_EPIN |
+ cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)];
+
+ /* SDRAM timimg */
+ ns = 1000000000 / mem_clk;
+ tmp = SDRAM_TRAS / ns;
+ if (tmp < 4)
+ tmp = 4;
+ if (tmp > 11)
+ tmp = 11;
+ dmcr |= (tmp - 4) << EMC_DMCR_TRAS_BIT;
+ tmp = SDRAM_RCD / ns;
+
+ if (tmp > 3)
+ tmp = 3;
+ dmcr |= tmp << EMC_DMCR_RCD_BIT;
+ tmp = SDRAM_TPC / ns;
+
+ if (tmp > 7)
+ tmp = 7;
+ dmcr |= tmp << EMC_DMCR_TPC_BIT;
+ tmp = SDRAM_TRWL / ns;
+
+ if (tmp > 3)
+ tmp = 3;
+ dmcr |= tmp << EMC_DMCR_TRWL_BIT;
+ tmp = (SDRAM_TRAS + SDRAM_TPC) / ns;
+
+ if (tmp > 14)
+ tmp = 14;
+ dmcr |= ((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT;
+
+ /* SDRAM mode value */
+ sdmode = EMC_SDMR_BT_SEQ |
+ EMC_SDMR_OM_NORMAL |
+ EMC_SDMR_BL_4 |
+ cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)];
+
+ /* Stage 1. Precharge all banks by writing SDMR with DMCR.MRSET=0 */
+ writel(dmcr, &emc->dmcr);
+ writeb(0, JZ4740_EMC_SDMR0 | sdmode);
+
+ /* Wait for precharge, > 200us */
+ tmp = (cpu_clk / 1000000) * 1000;
+ while (tmp--)
+ ;
+
+ /* Stage 2. Enable auto-refresh */
+ writel(dmcr | EMC_DMCR_RFSH, &emc->dmcr);
+
+ tmp = SDRAM_TREF / ns;
+ tmp = tmp / 64 + 1;
+ if (tmp > 0xff)
+ tmp = 0xff;
+ writew(tmp, &emc->rtcor);
+ writew(0, &emc->rtcnt);
+ /* Divisor is 64, CKO/64 */
+ writew(EMC_RTCSR_CKS_64, &emc->rtcsr);
+
+ /* Wait for number of auto-refresh cycles */
+ tmp = (cpu_clk / 1000000) * 1000;
+ while (tmp--)
+ ;
+
+ /* Stage 3. Mode Register Set */
+ writel(dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET, &emc->dmcr);
+ writeb(0, JZ4740_EMC_SDMR0 | sdmode);
+
+ /* Set back to basic DMCR value */
+ writel(dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET, &emc->dmcr);
+
+ /* everything is ok now */
+}
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void calc_clocks(void)
+{
+ unsigned int pllout;
+ unsigned int div[10] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ pllout = __cpm_get_pllout();
+
+ gd->cpu_clk = pllout / div[__cpm_get_cdiv()];
+ gd->sys_clk = pllout / div[__cpm_get_hdiv()];
+ gd->per_clk = pllout / div[__cpm_get_pdiv()];
+ gd->mem_clk = pllout / div[__cpm_get_mdiv()];
+ gd->dev_clk = CONFIG_SYS_EXTAL;
+}
+
+void rtc_init(void)
+{
+ struct jz4740_rtc *rtc = (struct jz4740_rtc *)JZ4740_RTC_BASE;
+
+ while (!(readl(&rtc->rcr) & RTC_RCR_WRDY))
+ ;
+ writel(readl(&rtc->rcr) | RTC_RCR_AE, &rtc->rcr); /* enable alarm */
+
+ while (!(readl(&rtc->rcr) & RTC_RCR_WRDY))
+ ;
+ writel(0x00007fff, &rtc->rgr); /* type value */
+
+ while (!(readl(&rtc->rcr) & RTC_RCR_WRDY))
+ ;
+ writel(0x0000ffe0, &rtc->hwfcr); /* Power on delay 2s */
+
+ while (!(readl(&rtc->rcr) & RTC_RCR_WRDY))
+ ;
+ writel(0x00000fe0, &rtc->hrcr); /* reset delay 125ms */
+}
+
+/* U-Boot common routines */
+phys_size_t initdram(int board_type)
+{
+ struct jz4740_emc *emc = (struct jz4740_emc *)JZ4740_EMC_BASE;
+ u32 dmcr;
+ u32 rows, cols, dw, banks;
+ ulong size;
+
+ dmcr = readl(&emc->dmcr);
+ rows = 11 + ((dmcr & EMC_DMCR_RA_MASK) >> EMC_DMCR_RA_BIT);
+ cols = 8 + ((dmcr & EMC_DMCR_CA_MASK) >> EMC_DMCR_CA_BIT);
+ dw = (dmcr & EMC_DMCR_BW) ? 2 : 4;
+ banks = (dmcr & EMC_DMCR_BA) ? 4 : 2;
+
+ size = (1 << (rows + cols)) * dw * banks;
+
+ return size;
+}
diff --git a/arch/mips/cpu/xburst/jz_serial.c b/arch/mips/cpu/xburst/jz_serial.c
new file mode 100644
index 0000000..e6c48e0
--- /dev/null
+++ b/arch/mips/cpu/xburst/jz_serial.c
@@ -0,0 +1,114 @@
+/*
+ * Jz4740 UART support
+ * Copyright (c) 2011
+ * Qi Hardware, Xiangfu Liu <xiangfu@sharism.cc>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/jz4740.h>
+
+/*
+ * serial_init - initialize a channel
+ *
+ * This routine initializes the number of data bits, parity
+ * and set the selected baud rate. Interrupts are disabled.
+ * Set the modem control signals if the option is selected.
+ *
+ * RETURNS: N/A
+ */
+struct jz4740_uart *uart = (struct jz4740_uart *)CONFIG_SYS_UART_BASE;
+
+int serial_init(void)
+{
+ /* Disable port interrupts while changing hardware */
+ writeb(0, &uart->dlhr_ier);
+
+ /* Disable UART unit function */
+ writeb(~UART_FCR_UUE, &uart->iir_fcr);
+
+ /* Set both receiver and transmitter in UART mode (not SIR) */
+ writeb(~(SIRCR_RSIRE | SIRCR_TSIRE), &uart->isr);
+
+ /*
+ * Set databits, stopbits and parity.
+ * (8-bit data, 1 stopbit, no parity)
+ */
+ writeb(UART_LCR_WLEN_8 | UART_LCR_STOP_1, &uart->lcr);
+
+ /* Set baud rate */
+ serial_setbrg();
+
+ /* Enable UART unit, enable and clear FIFO */
+ writeb(UART_FCR_UUE | UART_FCR_FE | UART_FCR_TFLS | UART_FCR_RFLS,
+ &uart->iir_fcr);
+
+ return 0;
+}
+
+void serial_setbrg(void)
+{
+ u32 baud_div, tmp;
+
+ baud_div = CONFIG_SYS_EXTAL / 16 / CONFIG_BAUDRATE;
+
+ tmp = readb(&uart->lcr);
+ tmp |= UART_LCR_DLAB;
+ writeb(tmp, &uart->lcr);
+
+ writeb((baud_div >> 8) & 0xff, &uart->dlhr_ier);
+ writeb(baud_div & 0xff, &uart->rbr_thr_dllr);
+
+ tmp &= ~UART_LCR_DLAB;
+ writeb(tmp, &uart->lcr);
+}
+
+int serial_tstc(void)
+{
+ if (readb(&uart->lsr) & UART_LSR_DR)
+ return 1;
+
+ return 0;
+}
+
+void serial_putc(const char c)
+{
+ if (c == '\n')
+ serial_putc('\r');
+
+ /* Wait for fifo to shift out some bytes */
+ while (!((readb(&uart->lsr) & (UART_LSR_TDRQ | UART_LSR_TEMT)) == 0x60))
+ ;
+
+ writeb((u8)c, &uart->rbr_thr_dllr);
+}
+
+int serial_getc(void)
+{
+ while (!serial_tstc())
+ ;
+
+ return readb(&uart->rbr_thr_dllr);
+}
+
+void serial_puts(const char *s)
+{
+ while (*s)
+ serial_putc(*s++);
+}
diff --git a/arch/mips/cpu/xburst/start.S b/arch/mips/cpu/xburst/start.S
new file mode 100644
index 0000000..d846104
--- /dev/null
+++ b/arch/mips/cpu/xburst/start.S
@@ -0,0 +1,171 @@
+/*
+ * Startup Code for MIPS32 XBURST CPU-core
+ *
+ * Copyright (c) 2010 Xiangfu Liu <xiangfu@sharism.cc>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <version.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/cacheops.h>
+
+ .set noreorder
+
+ .globl _start
+ .text
+_start:
+ /* Initialize $gp */
+ bal 1f
+ nop
+ .word _gp
+1:
+ lw gp, 0(ra)
+
+ /* Set up temporary stack */
+ li sp, CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_INIT_SP_OFFSET
+
+ la t9, board_init_f
+ jr t9
+ nop
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * a0 = addr_sp
+ * a1 = gd
+ * a2 = destination address
+ */
+ .globl relocate_code
+ .ent relocate_code
+relocate_code:
+ move sp, a0 # set new stack pointer
+
+ li t0, CONFIG_SYS_MONITOR_BASE
+ la t3, in_ram
+ lw t2, -12(t3) # t2 <-- uboot_end_data
+ move t1, a2
+
+ /*
+ * Fix $gp:
+ *
+ * New $gp = (Old $gp - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ */
+ move t6, gp
+ sub gp, CONFIG_SYS_MONITOR_BASE
+ add gp, a2 # gp now adjusted
+ sub t6, gp, t6 # t6 <-- relocation offset
+
+ /*
+ * t0 = source address
+ * t1 = target address
+ * t2 = source end address
+ */
+1:
+ lw t3, 0(t0)
+ sw t3, 0(t1)
+ addu t0, 4
+ ble t0, t2, 1b
+ addu t1, 4
+
+ /* If caches were enabled, we would have to flush them here. */
+
+ /* flush d-cache */
+ li t0, KSEG0
+ addi t1, t0, CONFIG_SYS_DCACHE_SIZE
+2:
+ cache Index_Writeback_Inv_D, 0(t0)
+ bne t0, t1, 2b
+ addi t0, CONFIG_SYS_CACHELINE_SIZE
+
+ sync
+
+ /* flush i-cache */
+ li t0, KSEG0
+ addi t1, t0, CONFIG_SYS_ICACHE_SIZE
+3:
+ cache Index_Invalidate_I, 0(t0)
+ bne t0, t1, 3b
+ addi t0, CONFIG_SYS_CACHELINE_SIZE
+
+ /* Invalidate BTB */
+ mfc0 t0, CP0_CONFIG, 7
+ nop
+ ori t0, 2
+ mtc0 t0, CP0_CONFIG, 7
+ nop
+
+ /* Jump to where we've relocated ourselves */
+ addi t0, a2, in_ram - _start
+ jr t0
+ nop
+
+ .word _gp
+ .word _GLOBAL_OFFSET_TABLE_
+ .word uboot_end_data
+ .word uboot_end
+ .word num_got_entries
+
+in_ram:
+ /*
+ * Now we want to update GOT.
+ *
+ * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
+ * generated by GNU ld. Skip these reserved entries from relocation.
+ */
+ lw t3, -4(t0) # t3 <-- num_got_entries
+ lw t4, -16(t0) # t4 <-- _GLOBAL_OFFSET_TABLE_
+ lw t5, -20(t0) # t5 <-- _gp
+ sub t4, t5 # compute offset
+ add t4, t4, gp # t4 now holds relocated _G_O_T_
+ addi t4, t4, 8 # skipping first two entries
+ li t2, 2
+1:
+ lw t1, 0(t4)
+ beqz t1, 2f
+ add t1, t6
+ sw t1, 0(t4)
+2:
+ addi t2, 1
+ blt t2, t3, 1b
+ addi t4, 4
+
+ /* Clear BSS */
+ lw t1, -12(t0) # t1 <-- uboot_end_data
+ lw t2, -8(t0) # t2 <-- uboot_end
+ add t1, t6 # adjust pointers
+ add t2, t6
+
+ sub t1, 4
+1: addi t1, 4
+ bltl t1, t2, 1b
+ sw zero, 0(t1)
+
+ move a0, a1 # a0 <-- gd
+ la t9, board_init_r
+ jr t9
+ move a1, a2
+
+ .end relocate_code
diff --git a/arch/mips/cpu/xburst/timer.c b/arch/mips/cpu/xburst/timer.c
new file mode 100644
index 0000000..de6f5da
--- /dev/null
+++ b/arch/mips/cpu/xburst/timer.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2006
+ * Ingenic Semiconductor, <jlwei@ingenic.cn>
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+
+#include <asm/jz4740.h>
+
+#define TIMER_CHAN 0
+#define TIMER_FDATA 0xffff /* Timer full data value */
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct jz4740_tcu *tcu = (struct jz4740_tcu *)JZ4740_TCU_BASE;
+
+void reset_timer_masked(void)
+{
+ /* reset time */
+ gd->lastinc = readw(&tcu->tcnt0);
+ gd->tbl = 0;
+}
+
+ulong get_timer_masked(void)
+{
+ ulong now = readw(&tcu->tcnt0);
+
+ if (gd->lastinc <= now)
+ gd->tbl += now - gd->lastinc; /* normal mode */
+ else {
+ /* we have an overflow ... */
+ gd->tbl += TIMER_FDATA + now - gd->lastinc;
+ }
+
+ gd->lastinc = now;
+
+ return gd->tbl;
+}
+
+void udelay_masked(unsigned long usec)
+{
+ ulong tmo;
+ ulong endtime;
+ signed long diff;
+
+ /* normalize */
+ if (usec >= 1000) {
+ tmo = usec / 1000;
+ tmo *= CONFIG_SYS_HZ;
+ tmo /= 1000;
+ } else {
+ if (usec > 1) {
+ tmo = usec * CONFIG_SYS_HZ;
+ tmo /= 1000*1000;
+ } else
+ tmo = 1;
+ }
+
+ endtime = get_timer_masked() + tmo;
+
+ do {
+ ulong now = get_timer_masked();
+ diff = endtime - now;
+ } while (diff >= 0);
+}
+
+int timer_init(void)
+{
+ writew(TCU_TCSR_PRESCALE256 | TCU_TCSR_EXT_EN, &tcu->tcsr0);
+
+ writew(0, &tcu->tcnt0);
+ writew(0, &tcu->tdhr0);
+ writew(TIMER_FDATA, &tcu->tdfr0);
+
+ /* mask irqs */
+ writel((1 << TIMER_CHAN) | (1 << (TIMER_CHAN + 16)), &tcu->tmsr);
+ writel(1 << TIMER_CHAN, &tcu->tscr); /* enable timer clock */
+ writeb(1 << TIMER_CHAN, &tcu->tesr); /* start counting up */
+
+ gd->lastinc = 0;
+ gd->tbl = 0;
+
+ return 0;
+}
+
+void reset_timer(void)
+{
+ reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+ return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+ gd->tbl = t;
+}
+
+void __udelay(unsigned long usec)
+{
+ ulong tmo, tmp;
+
+ /* normalize */
+ if (usec >= 1000) {
+ tmo = usec / 1000;
+ tmo *= CONFIG_SYS_HZ;
+ tmo /= 1000;
+ } else {
+ if (usec >= 1) {
+ tmo = usec * CONFIG_SYS_HZ;
+ tmo /= 1000 * 1000;
+ } else
+ tmo = 1;
+ }
+
+ /* check for rollover during this delay */
+ tmp = get_timer(0);
+ if ((tmp + tmo) < tmp)
+ reset_timer_masked(); /* timer would roll over */
+ else
+ tmo += tmp;
+
+ while (get_timer_masked() < tmo)
+ ;
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On MIPS it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+ return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On MIPS it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+ return CONFIG_SYS_HZ;
+}