diff options
author | Xiangfu Liu <xiangfu@openmobilefree.net> | 2011-10-12 12:24:06 +0800 |
---|---|---|
committer | Shinya Kuribayashi <skuribay@pobox.com> | 2011-10-10 22:06:12 +0900 |
commit | 80421fcc3ed1843f62a4a463548a4f33cdde362f (patch) | |
tree | 0e17b489ca37e73be16fbc1f85fd8b8c63cb773b /arch/mips/cpu/xburst | |
parent | 0841ca90f22d73b0ea4642ef1ce33d879bb2f3ff (diff) | |
download | u-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/xburst')
-rw-r--r-- | arch/mips/cpu/xburst/Makefile | 49 | ||||
-rw-r--r-- | arch/mips/cpu/xburst/config.mk | 24 | ||||
-rw-r--r-- | arch/mips/cpu/xburst/cpu.c | 152 | ||||
-rw-r--r-- | arch/mips/cpu/xburst/jz4740.c | 248 | ||||
-rw-r--r-- | arch/mips/cpu/xburst/jz_serial.c | 114 | ||||
-rw-r--r-- | arch/mips/cpu/xburst/start.S | 171 | ||||
-rw-r--r-- | arch/mips/cpu/xburst/timer.c | 162 |
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; +} |