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>master
parent
0841ca90f2
commit
80421fcc3e
@ -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 |
||||
|
||||
#########################################################################
|
@ -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
|
@ -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(); |
||||
} |
@ -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; |
||||
} |
@ -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++); |
||||
} |
@ -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
|
@ -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; |
||||
} |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue