diff options
Diffstat (limited to 'arch/arm/cpu/arm926ejs')
150 files changed, 27161 insertions, 0 deletions
diff --git a/arch/arm/cpu/arm926ejs/Makefile b/arch/arm/cpu/arm926ejs/Makefile new file mode 100644 index 0000000..5923e65 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/Makefile @@ -0,0 +1,53 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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 +COBJS = cpu.o cache.o + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_NO_CPU_SUPPORT_CODE +START := +endif +endif + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +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/arm/cpu/arm926ejs/armada100/Makefile b/arch/arm/cpu/arm926ejs/armada100/Makefile new file mode 100644 index 0000000..d30d608 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/armada100/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2010 +# Marvell Semiconductor <www.marvell.com> +# Written-by: Prafulla Wadaskar <prafulla@marvell.com> +# +# 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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS-y = cpu.o timer.o dram.o + +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/armada100/cpu.c b/arch/arm/cpu/arm926ejs/armada100/cpu.c new file mode 100644 index 0000000..14121a0 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/armada100/cpu.c @@ -0,0 +1,108 @@ +/* + * (C) Copyright 2010 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * Contributor: Mahavir Jain <mjain@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/armada100.h> + +#define UARTCLK14745KHZ (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1)) +#define SET_MRVL_ID (1<<8) +#define L2C_RAM_SEL (1<<4) + +int arch_cpu_init(void) +{ + u32 val; + struct armd1cpu_registers *cpuregs = + (struct armd1cpu_registers *) ARMD1_CPU_BASE; + + struct armd1apb1_registers *apb1clkres = + (struct armd1apb1_registers *) ARMD1_APBC1_BASE; + + struct armd1mpmu_registers *mpmu = + (struct armd1mpmu_registers *) ARMD1_MPMU_BASE; + + /* set SEL_MRVL_ID bit in ARMADA100_CPU_CONF register */ + val = readl(&cpuregs->cpu_conf); + val = val | SET_MRVL_ID; + writel(val, &cpuregs->cpu_conf); + + /* Enable Clocks for all hardware units */ + writel(0xFFFFFFFF, &mpmu->acgr); + + /* Turn on AIB and AIB-APB Functional clock */ + writel(APBC_APBCLK | APBC_FNCLK, &apb1clkres->aib); + + /* ensure L2 cache is not mapped as SRAM */ + val = readl(&cpuregs->cpu_conf); + val = val & ~(L2C_RAM_SEL); + writel(val, &cpuregs->cpu_conf); + + /* Enable GPIO clock */ + writel(APBC_APBCLK, &apb1clkres->gpio); + +#ifdef CONFIG_I2C_MV + /* Enable general I2C clock */ + writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi0); + writel(APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi0); + + /* Enable power I2C clock */ + writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi1); + writel(APBC_FNCLK | APBC_APBCLK, &apb1clkres->twsi1); +#endif + + /* + * Enable Functional and APB clock at 14.7456MHz + * for configured UART console + */ +#if (CONFIG_SYS_NS16550_COM1 == ARMD1_UART3_BASE) + writel(UARTCLK14745KHZ, &apb1clkres->uart3); +#elif (CONFIG_SYS_NS16550_COM1 == ARMD1_UART2_BASE) + writel(UARTCLK14745KHZ, &apb1clkres->uart2); +#else + writel(UARTCLK14745KHZ, &apb1clkres->uart1); +#endif + icache_enable(); + + return 0; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + u32 id; + struct armd1cpu_registers *cpuregs = + (struct armd1cpu_registers *) ARMD1_CPU_BASE; + + id = readl(&cpuregs->chip_id); + printf("SoC: Armada 88AP%X-%X\n", (id & 0xFFF), (id >> 0x10)); + return 0; +} +#endif + +#ifdef CONFIG_I2C_MV +void i2c_clk_enable(void) +{ +} +#endif diff --git a/arch/arm/cpu/arm926ejs/armada100/dram.c b/arch/arm/cpu/arm926ejs/armada100/dram.c new file mode 100644 index 0000000..8609004 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/armada100/dram.c @@ -0,0 +1,132 @@ +/* + * (C) Copyright 2010 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com>, + * Contributor: Mahavir Jain <mjain@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/armada100.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * ARMADA100 DRAM controller supports upto 8 banks + * for chip select 0 and 1 + */ + +/* + * DDR Memory Control Registers + * Refer Datasheet Appendix A.17 + */ +struct armd1ddr_map_registers { + u32 cs; /* Memory Address Map Register -CS */ + u32 pad[3]; +}; + +struct armd1ddr_registers { + u8 pad[0x100 - 0x000]; + struct armd1ddr_map_registers mmap[2]; +}; + +/* + * armd1_sdram_base - reads SDRAM Base Address Register + */ +u32 armd1_sdram_base(int chip_sel) +{ + struct armd1ddr_registers *ddr_regs = + (struct armd1ddr_registers *)ARMD1_DRAM_BASE; + u32 result = 0; + u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs); + + if (!CS_valid) + return 0; + + result = readl(&ddr_regs->mmap[chip_sel].cs) & 0xFF800000; + return result; +} + +/* + * armd1_sdram_size - reads SDRAM size + */ +u32 armd1_sdram_size(int chip_sel) +{ + struct armd1ddr_registers *ddr_regs = + (struct armd1ddr_registers *)ARMD1_DRAM_BASE; + u32 result = 0; + u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs); + + if (!CS_valid) + return 0; + + result = readl(&ddr_regs->mmap[chip_sel].cs); + result = (result >> 16) & 0xF; + if (result < 0x7) { + printf("Unknown DRAM Size\n"); + return -1; + } else { + return ((0x8 << (result - 0x7)) * 1024 * 1024); + } +} + +#ifndef CONFIG_SYS_BOARD_DRAM_INIT +int dram_init(void) +{ + int i; + + gd->ram_size = 0; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + gd->bd->bi_dram[i].start = armd1_sdram_base(i); + gd->bd->bi_dram[i].size = armd1_sdram_size(i); + /* + * It is assumed that all memory banks are consecutive + * and without gaps. + * If the gap is found, ram_size will be reported for + * consecutive memory only + */ + if (gd->bd->bi_dram[i].start != gd->ram_size) + break; + + gd->ram_size += gd->bd->bi_dram[i].size; + + } + + for (; i < CONFIG_NR_DRAM_BANKS; i++) { + /* If above loop terminated prematurely, we need to set + * remaining banks' start address & size as 0. Otherwise other + * u-boot functions and Linux kernel gets wrong values which + * could result in crash */ + gd->bd->bi_dram[i].start = 0; + gd->bd->bi_dram[i].size = 0; + } + return 0; +} + +/* + * If this function is not defined here, + * board.c alters dram bank zero configuration defined above. + */ +void dram_init_banksize(void) +{ + dram_init(); +} +#endif /* CONFIG_SYS_BOARD_DRAM_INIT */ diff --git a/arch/arm/cpu/arm926ejs/armada100/timer.c b/arch/arm/cpu/arm926ejs/armada100/timer.c new file mode 100644 index 0000000..948607f --- /dev/null +++ b/arch/arm/cpu/arm926ejs/armada100/timer.c @@ -0,0 +1,210 @@ +/* + * (C) Copyright 2010 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * Contributor: Mahavir Jain <mjain@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/armada100.h> + +/* + * Timer registers + * Refer Section A.6 in Datasheet + */ +struct armd1tmr_registers { + u32 clk_ctrl; /* Timer clk control reg */ + u32 match[9]; /* Timer match registers */ + u32 count[3]; /* Timer count registers */ + u32 status[3]; + u32 ie[3]; + u32 preload[3]; /* Timer preload value */ + u32 preload_ctrl[3]; + u32 wdt_match_en; + u32 wdt_match_r; + u32 wdt_val; + u32 wdt_sts; + u32 icr[3]; + u32 wdt_icr; + u32 cer; /* Timer count enable reg */ + u32 cmr; + u32 ilr[3]; + u32 wcr; + u32 wfar; + u32 wsar; + u32 cvwr; +}; + +#define TIMER 0 /* Use TIMER 0 */ +/* Each timer has 3 match registers */ +#define MATCH_CMP(x) ((3 * TIMER) + x) +#define TIMER_LOAD_VAL 0xffffffff +#define COUNT_RD_REQ 0x1 + +DECLARE_GLOBAL_DATA_PTR; +/* Using gd->arch.tbu from timestamp and gd->arch.tbl for lastdec */ + +/* For preventing risk of instability in reading counter value, + * first set read request to register cvwr and then read same + * register after it captures counter value. + */ +ulong read_timer(void) +{ + struct armd1tmr_registers *armd1timers = + (struct armd1tmr_registers *) ARMD1_TIMER_BASE; + volatile int loop=100; + + writel(COUNT_RD_REQ, &armd1timers->cvwr); + while (loop--); + return(readl(&armd1timers->cvwr)); +} + +ulong get_timer_masked(void) +{ + ulong now = read_timer(); + + if (now >= gd->arch.tbl) { + /* normal mode */ + gd->arch.tbu += now - gd->arch.tbl; + } else { + /* we have an overflow ... */ + gd->arch.tbu += now + TIMER_LOAD_VAL - gd->arch.tbl; + } + gd->arch.tbl = now; + + return gd->arch.tbu; +} + +ulong get_timer(ulong base) +{ + return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) - + base); +} + +void __udelay(unsigned long usec) +{ + ulong delayticks; + ulong endtime; + + delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000)); + endtime = get_timer_masked() + delayticks; + + while (get_timer_masked() < endtime); +} + +/* + * init the Timer + */ +int timer_init(void) +{ + struct armd1apb1_registers *apb1clkres = + (struct armd1apb1_registers *) ARMD1_APBC1_BASE; + struct armd1tmr_registers *armd1timers = + (struct armd1tmr_registers *) ARMD1_TIMER_BASE; + + /* Enable Timer clock at 3.25 MHZ */ + writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers); + + /* load value into timer */ + writel(0x0, &armd1timers->clk_ctrl); + /* Use Timer 0 Match Resiger 0 */ + writel(TIMER_LOAD_VAL, &armd1timers->match[MATCH_CMP(0)]); + /* Preload value is 0 */ + writel(0x0, &armd1timers->preload[TIMER]); + /* Enable match comparator 0 for Timer 0 */ + writel(0x1, &armd1timers->preload_ctrl[TIMER]); + + /* Enable timer 0 */ + writel(0x1, &armd1timers->cer); + /* init the gd->arch.tbu and gd->arch.tbl value */ + gd->arch.tbl = read_timer(); + gd->arch.tbu = 0; + + return 0; +} + +#define MPMU_APRR_WDTR (1<<4) +#define TMR_WFAR 0xbaba /* WDT Register First key */ +#define TMP_WSAR 0xeb10 /* WDT Register Second key */ + +/* + * This function uses internal Watchdog Timer + * based reset mechanism. + * Steps to write watchdog registers (protected access) + * 1. Write key value to TMR_WFAR reg. + * 2. Write key value to TMP_WSAR reg. + * 3. Perform write operation. + */ +void reset_cpu (unsigned long ignored) +{ + struct armd1mpmu_registers *mpmu = + (struct armd1mpmu_registers *) ARMD1_MPMU_BASE; + struct armd1tmr_registers *armd1timers = + (struct armd1tmr_registers *) ARMD1_TIMER_BASE; + u32 val; + + /* negate hardware reset to the WDT after system reset */ + val = readl(&mpmu->aprr); + val = val | MPMU_APRR_WDTR; + writel(val, &mpmu->aprr); + + /* reset/enable WDT clock */ + writel(APBC_APBCLK | APBC_FNCLK | APBC_RST, &mpmu->wdtpcr); + readl(&mpmu->wdtpcr); + writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr); + readl(&mpmu->wdtpcr); + + /* clear previous WDT status */ + writel(TMR_WFAR, &armd1timers->wfar); + writel(TMP_WSAR, &armd1timers->wsar); + writel(0, &armd1timers->wdt_sts); + + /* set match counter */ + writel(TMR_WFAR, &armd1timers->wfar); + writel(TMP_WSAR, &armd1timers->wsar); + writel(0xf, &armd1timers->wdt_match_r); + + /* enable WDT reset */ + writel(TMR_WFAR, &armd1timers->wfar); + writel(TMP_WSAR, &armd1timers->wsar); + writel(0x3, &armd1timers->wdt_match_en); + + while(1); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM 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 ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return (ulong)CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/aspeed/COMMINF.H b/arch/arm/cpu/arm926ejs/aspeed/COMMINF.H new file mode 100644 index 0000000..44b7540 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/COMMINF.H @@ -0,0 +1,641 @@ +/* + * 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 + */ +#ifndef COMMINF_H +#define COMMINF_H + +#include "SWFUNC.H" + +#if defined(LinuxAP) +#endif +#ifdef SLT_UBOOT +#endif +#ifdef SLT_DOS + #include <stdio.h> + #include <time.h> + #include <dos.h> // For delay() +#endif + +#include "TYPEDEF.H" +#include "LIB.H" + +//--------------------------------------------------------- +// Print Message +//--------------------------------------------------------- +// for function +#define FP_LOG 0 +#define FP_IO 1 +#define STD_OUT 2 + +#ifdef SLT_UBOOT + #define PRINT printf + #define OUT_OBJ + #define FILE_VAR + + #define GET_OBJ( i ) \ + do { \ + if ( i != STD_OUT ) \ + return; \ + } while ( 0 ); + +#else + #define PRINT fprintf + #define OUT_OBJ fp, + #define FILE_VAR FILE *fp; + + #define GET_OBJ( i ) \ + switch( i ) { \ + case FP_LOG: \ + fp = fp_log; \ + break; \ + case FP_IO: \ + fp = fp_io; \ + break; \ + case STD_OUT: \ + fp = stdout; \ + break; \ + default : break; \ + } +#endif + +//--------------------------------------------------------- +// Function +//--------------------------------------------------------- +#ifdef SLT_UBOOT + #define DELAY( x ) udelay( x * 1000 ) // For Uboot, the unit of udelay() is us. + #define GET_CAHR getc +#endif +#ifdef SLT_DOS + #define DELAY( x ) delay( x ) // For DOS, the unit of delay() is ms. + #define GET_CAHR getchar +#endif + +//--------------------------------------------------------- +// Default argument +//--------------------------------------------------------- +#define DEF_USER_DEF_PACKET_VAL 0x66666666 //0xff00ff00, 0xf0f0f0f0, 0xcccccccc, 0x55aa55aa, 0x5a5a5a5a, 0x66666666 +#define DEF_IOTIMINGBUND 5 //0/1/3/5/7 +#define DEF_PHY_ADR 0 +#define DEF_TESTMODE 0 //[0]0: no burst mode, 1: 0xff, 2: 0x55, 3: random, 4: ARP, 5: ARP, 6: IO timing, 7: IO timing+IO Strength +#define DEF_LOOP_MAX 1 +#define DEF_MAC_LOOP_BACK 0 //GCtrl bit6 +#define DEF_SKIP_CHECK_PHY 0 //GCtrl bit4 +#define DEF_INIT_PHY 1 //GCtrl bit3 + +#define SET_1GBPS 0 // 1G bps +#define SET_100MBPS 1 // 100M bps +#define SET_10MBPS 2 // 10M bps +#define SET_1G_100M_10MBPS 3 // 1G and 100M and 10M bps +#define DEF_SPEED SET_1G_100M_10MBPS +#define DEF_ARPNUMCNT 0 + +//--------------------------------------------------------- +// MAC information +//--------------------------------------------------------- +#if ( AST1010_IOMAP == 1 ) + // AST1010 only has a MAC + #define MAC_BASE1 AST_MAC1_BASE + #define MAC_BASE2 AST_MAC1_BASE + #define MAC_BASE3 AST_MAC1_BASE + #define MAC_BASE4 AST_MAC1_BASE +#endif + +#if ( AST1010_IOMAP == 2 ) + // AST1010 only has a MAC + #define MAC_BASE1 0x0830000 + #define MAC_BASE2 0x0830000 + #define MAC_BASE3 0x0830000 + #define MAC_BASE4 0x0830000 +#endif + +#ifndef AST1010_IOMAP + #define MAC_BASE1 0x1e660000 + #define MAC_BASE2 0x1e680000 + #define MAC_BASE3 0x1e670000 + #define MAC_BASE4 0x1e690000 +#endif + +#define MDC_Thres 0x3f +#define MAC_PHYWr 0x08000000 +#define MAC_PHYRd 0x04000000 + +#define MAC_PHYWr_New 0x00009400 +#define MAC_PHYRd_New 0x00009800 +#define MAC_PHYBusy_New 0x00008000 + +//#define MAC_30h 0x00001010 +//#define MAC_34h 0x00000000 +//#define MAC_38h 0x00d22f00 //default 0x22f00 +//#define MAC_38h 0x00022f00 //default 0x22f00 + +#define MAC_40h 0x40000000 + +#ifdef Enable_BufMerge + #define MAC_48h 0x007702F1 //default 0xf1 +#else + #ifdef AST1010_IOMAP + #define MAC_48h 0x000002F1 //default 0xf1 + #else + #define MAC_48h 0x000001F1 //default 0xf1 + #endif +#endif + +//--------------------------------------------------------- +// Data information +//--------------------------------------------------------- +#ifdef SelectSimpleBoundary + #define ZeroCopy_OFFSET 0 +#else + #define ZeroCopy_OFFSET ( (BurstEnable) ? 0 : 2 ) +#endif + +// --------------------------------- DRAM_MapAdr = TDES_BASE1 +// | TX descriptor ring #1 | +// ------------------------- DRAM_MapAdr + 0x040000 = RDES_BASE1 +// | RX descriptor ring #1 | +// ------------------------- DRAM_MapAdr + 0x080000 = TDES_BASE2 +// | TX descriptor ring #2 | +// ------------------------- DRAM_MapAdr + 0x0C0000 = RDES_BASE2 +// | RX descriptor ring #2 | +// --------------------------------- DRAM_MapAdr + 0x100000 = DMA_BASE ------------------------- +// | #1 | \ | #1 Tx | +// DMA buffer | | DMA_BufSize | LOOP = 0 | +// ( Tx/Rx ) ------------------------- / -------------------------------------------------- +// | #2 | | #2 Rx | #2 Tx | +// | | | LOOP = 0 | LOOP = 1 | +// ------------------------- -------------------------------------------------- +// | #3 | | #3 Rx | +// | | | LOOP = 1 | +// ------------------------- ------------------------- +// | #4 | .......... +// | | +// ------------------------- +// | #5 | +// | | +// ------------------------- +// | #6 | +// | | +// ------------------------- +// . +// . +// ------------------------- +// | #n, n = DMA_BufNum | +// | | +// --------------------------------- + +#if ( AST1010_IOMAP == 1 ) + #define DRAM_MapAdr ( CONFIG_DRAM_SWAP_BASE + 0x00200000 ) // We use 0xA00000 to 0xEFFFFF + #define CPU_BUS_ADDR_SDRAM_OFFSET 0x01000000 // In ReMapping function, MAC engine need Bus address + // But Coldfire need CPU address, so need to do offset +#endif + +#if ( AST1010_IOMAP == 2 ) + #define DRAM_MapAdr 0x0A00000 // We use 0xA00000 to 0xEFFFFF + #define CPU_BUS_ADDR_SDRAM_OFFSET 0 +#endif + +#ifndef AST1010_IOMAP + #ifdef AST3200_IOMAP + #define DRAM_MapAdr 0x80000000 + #else + #define DRAM_MapAdr 0x44000000 + #endif + + #define CPU_BUS_ADDR_SDRAM_OFFSET 0 +#endif + + #define TDES_BASE1 ( 0x00000000 + DRAM_MapAdr ) + #define RDES_BASE1 ( 0x00040000 + DRAM_MapAdr ) + #define TDES_BASE2 ( 0x00080000 + DRAM_MapAdr ) + #define RDES_BASE2 ( 0x000C0000 + DRAM_MapAdr ) + + #define TDES_IniVal ( 0xb0000000 + FRAME_LEN_Cur ) + #define RDES_IniVal ( 0x00000fff ) + #define EOR_IniVal ( 0x40008000 ) + #define HWOwnTx(dat) ( (dat) & 0x80000000 ) + #define HWOwnRx(dat) ( !((dat) & 0x80000000) ) + #define HWEOR(dat) ( dat & 0x40000000 ) + +//--------------------------------------------------------- +// Error Flag Bits +//--------------------------------------------------------- +#define Err_MACMode ( 1 << 0 ) // MAC interface mode mismatch +#define Err_PHY_Type ( 1 << 1 ) // Unidentifiable PHY +#define Err_MALLOC_FrmSize ( 1 << 2 ) // Malloc fail at frame size buffer +#define Err_MALLOC_LastWP ( 1 << 3 ) // Malloc fail at last WP buffer +#define Err_Check_Buf_Data ( 1 << 4 ) // Received data mismatch +#define Err_Check_Des ( 1 << 5 ) // Descriptor error +#define Err_NCSI_LinkFail ( 1 << 6 ) // NCSI packet retry number over flows +#define Err_NCSI_Check_TxOwnTimeOut ( 1 << 7 ) // Time out of checking Tx owner bit in NCSI packet +#define Err_NCSI_Check_RxOwnTimeOut ( 1 << 8 ) // Time out of checking Rx owner bit in NCSI packet +#define Err_NCSI_Check_ARPOwnTimeOut ( 1 << 9 ) // Time out of checking ARP owner bit in NCSI packet +#define Err_NCSI_No_PHY ( 1 << 10 ) // Can not find NCSI PHY +#define Err_NCSI_Channel_Num ( 1 << 11 ) // NCSI Channel Number Mismatch +#define Err_NCSI_Package_Num ( 1 << 12 ) // NCSI Package Number Mismatch +#define Err_PHY_TimeOut ( 1 << 13 ) // Time out of read/write/reset PHY register +#define Err_RXBUF_UNAVA ( 1 << 14 ) // MAC00h[2]:Receiving buffer unavailable +#define Err_RPKT_LOST ( 1 << 15 ) // MAC00h[3]:Received packet lost due to RX FIFO full +#define Err_NPTXBUF_UNAVA ( 1 << 16 ) // MAC00h[6]:Normal priority transmit buffer unavailable +#define Err_TPKT_LOST ( 1 << 17 ) // MAC00h[7]:Packets transmitted to Ethernet lost +#define Err_DMABufNum ( 1 << 18 ) // DMA Buffer is not enough +#define Err_IOMargin ( 1 << 19 ) // IO timing margin is not enough +#define Err_IOMarginOUF ( 1 << 20 ) // IO timing testing out of boundary +#define Err_MHCLK_Ratio ( 1 << 21 ) // Error setting of MAC AHB bus clock (SCU08[18:16]) + +#define Check_Des_TxOwnTimeOut ( 1 << 0 ) // Time out of checking Tx owner bit +#define Check_Des_RxOwnTimeOut ( 1 << 1 ) // Time out of checking Rx owner bit +#define Check_Des_RxErr ( 1 << 2 ) // Input signal RxErr +#define Check_Des_OddNibble ( 1 << 3 ) // Nibble bit happen +#define Check_Des_CRC ( 1 << 4 ) // CRC error of frame +#define Check_Des_RxFIFOFull ( 1 << 5 ) // Rx FIFO full +#define Check_Des_FrameLen ( 1 << 6 ) // Frame length mismatch + +#define NCSI_LinkFail_Get_Version_ID ( 1 << 0 ) // Time out when Get Version ID +#define NCSI_LinkFail_Get_Capabilities ( 1 << 1 ) // Time out when Get Capabilities +#define NCSI_LinkFail_Select_Active_Package ( 1 << 2 ) // Time out when Select Active Package +#define NCSI_LinkFail_Enable_Set_MAC_Address ( 1 << 3 ) // Time out when Enable Set MAC Address +#define NCSI_LinkFail_Enable_Broadcast_Filter ( 1 << 4 ) // Time out when Enable Broadcast Filter +#define NCSI_LinkFail_Enable_Network_TX ( 1 << 5 ) // Time out when Enable Network TX +#define NCSI_LinkFail_Enable_Channel ( 1 << 6 ) // Time out when Enable Channel +#define NCSI_LinkFail_Disable_Network_TX ( 1 << 7 ) // Time out when Disable Network TX +#define NCSI_LinkFail_Disable_Channel ( 1 << 8 ) // Time out when Disable Channel + +//--------------------------------------------------------- +// SCU information +//--------------------------------------------------------- +#if ( AST1010_IOMAP == 1 ) + #define SCU_BASE AST_SCU_BASE +#endif +#if ( AST1010_IOMAP == 2 ) + #define SCU_BASE 0x0841000 +#endif + +#ifndef AST1010_IOMAP + #define SCU_BASE 0x1e6e2000 +#endif + +#define SCU_48h_AST1010 0x00000200 +#define SCU_48h_AST2300 0x00222255 + +//#ifdef SLT_DOS +// #define SCU_80h 0x00000000 +// #define SCU_88h 0x00000000 +// #define SCU_90h 0x00000000 +// #define SCU_74h 0x00000000 +//#else +// #define SCU_80h 0x0000000f //AST2300[3:0]MAC1~4 PHYLINK +// #define SCU_88h 0xc0000000 //AST2300[31]MAC1 MDIO, [30]MAC1 MDC +// #define SCU_90h 0x00000004 //AST2300[2 ]MAC2 MDC/MDIO +// #define SCU_74h 0x06300000 //AST3000[20]MAC2 MDC/MDIO, [21]MAC2 MII, [25]MAC1 PHYLINK, [26]MAC2 PHYLINK +//#endif + +//--------------------------------------------------------- +// DMA Buffer information +//--------------------------------------------------------- +#ifdef FPGA + #define DRAM_KByteSize ( 56 * 1024 ) +#else + #ifdef AST1010_IOMAP + #define DRAM_KByteSize ( 3 * 1024 ) // DATA buffer only use 0xB00000 to 0xE00000 + #else + #define DRAM_KByteSize ( 18 * 1024 ) + #endif +#endif + +#define DMA_BASE ( 0x00100000 + DRAM_MapAdr ) + +#ifdef Enable_Jumbo + #define DMA_PakSize ( 10 * 1024 ) +#else + #define DMA_PakSize ( 2 * 1024 ) // The size of one LAN packet +#endif + +#ifdef SelectSimpleBoundary + #define DMA_BufSize ( ( ( ( ( DES_NUMBER + 15 ) * DMA_PakSize ) >> 2 ) << 2 ) ) //vary by DES_NUMBER +#else + #define DMA_BufSize (4 + ( ( ( ( DES_NUMBER + 15 ) * DMA_PakSize ) >> 2 ) << 2 ) ) //vary by DES_NUMBER +#endif + +#define DMA_BufNum ( ( DRAM_KByteSize * 1024 ) / ( DMA_BufSize ) ) //vary by DES_NUMBER +#define GET_DMA_BASE_SETUP ( DMA_BASE ) +#define GET_DMA_BASE(x) ( DMA_BASE + ( ( ( ( x ) % DMA_BufNum ) + 1 ) * DMA_BufSize ) )//vary by DES_NUMBER + +#define SEED_START 8 +#define DATA_SEED(seed) ( ( seed ) | (( seed + 1 ) << 16 ) ) +#define DATA_IncVal 0x00020001 +//#define DATA_IncVal 0x01000001 //fail +//#define DATA_IncVal 0x10000001 //fail +//#define DATA_IncVal 0x10000000 //fail +//#define DATA_IncVal 0x80000000 //fail +//#define DATA_IncVal 0x00000001 //ok +//#define DATA_IncVal 0x01000100 //ok +//#define DATA_IncVal 0x01010000 //ok +//#define DATA_IncVal 0x01010101 //ok +//#define DATA_IncVal 0x00000101 //ok +//#define DATA_IncVal 0x00001111 //fail +//#define DATA_IncVal 0x00000011 //fail +//#define DATA_IncVal 0x10100101 //fail +//#define DATA_IncVal 0xfeff0201 +//#define DATA_IncVal 0x00010001 +#define PktByteSize ( ( ( ( ZeroCopy_OFFSET + FRAME_LEN_Cur - 1 ) >> 2 ) + 1) << 2 ) + +//--------------------------------------------------------- +// Delay (ms) +//--------------------------------------------------------- +//#define Delay_DesGap 1000 //off +//#define Delay_DesGap 700 //off + +//#define Delay_ChkRxOwn 10 +//#define Delay_ChkTxOwn 10 +#define Delay_CntMax 100000000 +//#define Delay_CntMax 1000 +//#define Delay_CntMax 8465 +//#define Delay_CntMaxIncVal 50000 +#define Delay_CntMaxIncVal 47500 + +#define Delay_PHYRst 100 +#define Delay_PHYRd 5 + +#define Delay_SCU 11 +#define Delay_MACRst 1 +#define Delay_MACDump 100 + +//#define Delay_DES 1 + +//--------------------------------------------------------- +// Time Out +//--------------------------------------------------------- +#define TIME_OUT_Des 10000 +#define TIME_OUT_PHY_RW 10000 +#define TIME_OUT_PHY_Rst 10000 + +//#define TIME_OUT_NCSI 300000 +#define TIME_OUT_NCSI 30000 + + + +//--------------------------------------------------------- +// Chip memory MAP +//--------------------------------------------------------- +#define LITTLE_ENDIAN_ADDRESS 0 +#define BIG_ENDIAN_ADDRESS 1 + +typedef struct { + ULONG StartAddr; + ULONG EndAddr; +} LittleEndian_Area; + +#if ( AST1010_IOMAP == 1 ) + static const LittleEndian_Area LittleEndianArea[] = { + { AST_IO_BASE, (AST_IO_BASE + 0x000FFFFF) }, + { 0xFFFFFFFF, 0xFFFFFFFF } // End + }; +#else + static const LittleEndian_Area LittleEndianArea[] = { + { 0xFFFFFFFF, 0xFFFFFFFF } // End + }; +#endif + +// ======================================================== +// For ncsi.c + +#define DEF_PACKAGE2NUM 1 // Default value +#define DEF_CHANNEL2NUM 2 // Default value + +typedef struct { + unsigned char Package_ID; + unsigned char Channel_ID; + unsigned long Capabilities_Flags; + unsigned long Broadcast_Packet_Filter_Capabilities; + unsigned long Multicast_Packet_Filter_Capabilities; + unsigned long Buffering_Capabilities; + unsigned long AEN_Control_Support; + unsigned long PCI_DID_VID; + unsigned long ManufacturerID; +} NCSI_Capability; + +#undef GLOBAL +#ifdef NCSI_C +#define GLOBAL +#else +#define GLOBAL extern +#endif + +GLOBAL NCSI_Capability NCSI_Cap_SLT; +GLOBAL BYTE number_chl; + +GLOBAL char phy_ncsi (void); + +// ======================================================== +// For mactest + +#undef GLOBAL +#ifdef MACTEST_C +#define GLOBAL +#else +#define GLOBAL extern +#endif + +GLOBAL ULONG NCSI_DiSChannel; + +// +#ifdef SLT_UBOOT +#else +// SLT_DOS +GLOBAL FILE *fp_log; +GLOBAL FILE *fp_io; +#endif + +GLOBAL CHAR dlymap[16][16]; +GLOBAL CHAR PrintNCSIEn; +GLOBAL ULONG ARPNumCnt; +GLOBAL CHAR FileNameMain[256]; +GLOBAL CHAR FileName[256]; +GLOBAL CHAR ASTChipName[256]; +GLOBAL CHAR LOOP_Str[256]; +GLOBAL BYTE IOTimingBund; +GLOBAL BYTE ChannelTolNum; +GLOBAL BYTE PackageTolNum; +GLOBAL ULONG IOdly_out_reg; +GLOBAL BYTE IOdly_out_reg_idx; +GLOBAL ULONG Dat_ULONG; +GLOBAL ULONG IOdly_incval; +GLOBAL ULONG IOdly_in_reg; +GLOBAL BYTE IOdly_in_reg_idx; +GLOBAL ULONG *wp_lst; +GLOBAL ULONG *FRAME_LEN; +GLOBAL ULONG DES_NUMBER; +GLOBAL ULONG DES_NUMBER_Org; +GLOBAL int LOOP_MAX; +GLOBAL ULONG LOOP_CheckNum; +GLOBAL int Loop; +GLOBAL ULONG CheckBuf_MBSize; +GLOBAL ULONG Err_Flag; +GLOBAL ULONG SCU_f0h_old; +#ifdef AST1010_IOMAP + GLOBAL ULONG SCU_11Ch_old; +#endif +GLOBAL ULONG SCU_04h; +GLOBAL ULONG SCU_90h_old; +GLOBAL ULONG SCU_7ch_old; +GLOBAL ULONG MAC_50h; +GLOBAL ULONG SCU_ach_old; +GLOBAL ULONG SCU_70h_old; +GLOBAL ULONG MAC_50h_Speed; +GLOBAL ULONG SCU_48h_old; +GLOBAL ULONG SCU_48h_mix; +GLOBAL ULONG MAC_08h_old; +GLOBAL ULONG MAC_0ch_old; +GLOBAL ULONG MAC_40h_old; +GLOBAL ULONG SCU_08h_old; +GLOBAL ULONG MAC_PHYBASE; +GLOBAL ULONG LOOP_MAX_arg; +GLOBAL BYTE GRun_Mode; +GLOBAL ULONG GSpeed_idx; +GLOBAL CHAR GSpeed_sel[3]; +GLOBAL CHAR PHY_ADR; +GLOBAL CHAR PHY_ADR_arg; +GLOBAL CHAR PHYName[256]; +GLOBAL ULONG PHY_ID3; +GLOBAL ULONG PHY_ID2; +GLOBAL BYTE number_pak; +GLOBAL BYTE TestMode; +GLOBAL ULONG IOStr_i; +GLOBAL BYTE IOTimingBund_arg; +GLOBAL BYTE GSpeed; +GLOBAL BYTE GCtrl; +GLOBAL ULONG UserDVal; +GLOBAL ULONG H_MAC_BASE; +GLOBAL ULONG H_TDES_BASE; +GLOBAL ULONG H_RDES_BASE; +GLOBAL CHAR Loop_rl[3]; +GLOBAL CHAR IOTiming; +GLOBAL CHAR LOOP_INFINI; +GLOBAL CHAR SelectMAC; +GLOBAL CHAR Enable_SkipChkPHY; +GLOBAL CHAR Enable_MAC34; +GLOBAL CHAR IOStrength; +GLOBAL CHAR DataDelay; +GLOBAL CHAR SA[6]; +GLOBAL CHAR RxDataEnable; +GLOBAL CHAR IEEETesting; +GLOBAL CHAR BurstEnable; +GLOBAL CHAR MAC_Mode; +GLOBAL CHAR Enable_MACLoopback; +GLOBAL CHAR Enable_InitPHY; +GLOBAL CHAR MAC1_1GEn; +GLOBAL CHAR MAC2_RMII; +GLOBAL CHAR Enable_RMII; +GLOBAL CHAR MAC2_1GEn; +GLOBAL CHAR TxDataEnable; +GLOBAL CHAR AST2300_NewMDIO; +GLOBAL CHAR ASTChipType; +GLOBAL CHAR Err_Flag_PrintEn; +GLOBAL CHAR AST2400; +GLOBAL CHAR AST2300; +GLOBAL CHAR AST1100;//Different in phy & dram initiation & dram size & RMII +GLOBAL CHAR AST3200; +GLOBAL CHAR AST1010; +GLOBAL SCHAR IOdly_i_min; +GLOBAL SCHAR IOdly_j_min; +GLOBAL SCHAR IOdly_i_max; +GLOBAL SCHAR IOdly_j_max; +GLOBAL BYTE IOdly_i; +GLOBAL BYTE IOdly_j; +GLOBAL BYTE IOdly_in; +GLOBAL BYTE IOdly_out; +GLOBAL SCHAR IOdly_in_str; +GLOBAL BYTE IOdly_in_end; +GLOBAL BYTE IOdly_out_end; +GLOBAL BYTE IOdly_out_shf; +GLOBAL BYTE IOdly_in_shf; +GLOBAL SCHAR IOdly_out_str; +GLOBAL BYTE valary[16]; + +#define MODE_DEDICATED 0x01 +#define MODE_NSCI 0x02 +GLOBAL CHAR ModeSwitch; + +#ifdef SLT_UBOOT +#else + GLOBAL time_t timestart; +#endif + +#ifdef SPI_BUS + GLOBAL ULONG mmiobase; +#else + // ( USE_P2A | USE_LPC ) + GLOBAL UCHAR *mmiobase; + GLOBAL ULONG ulPCIBaseAddress; + GLOBAL ULONG ulMMIOBaseAddress; +#endif + + +// ======================================================== +// For mac.c +#undef GLOBAL +#ifdef MAC_C +#define GLOBAL +#else +#define GLOBAL extern +#endif + +GLOBAL ULONG ARP_data[16]; +GLOBAL ULONG NCSI_LinkFail_Val; +static const char version_name[] = VER_NAME; + +GLOBAL void Debug_delay (void); +GLOBAL void read_scu (void); +GLOBAL void Setting_scu (void); +GLOBAL void PrintMode (void); +GLOBAL void PrintPakNUm (void); +GLOBAL void PrintChlNUm (void); +GLOBAL void PrintTest (void); +GLOBAL void PrintIOTimingBund (void); +GLOBAL void PrintSpeed (void); +GLOBAL void PrintCtrl (void); +GLOBAL void PrintLoop (void); +GLOBAL void PrintPHYAdr (void); +GLOBAL void Finish_Close (void); +GLOBAL void Calculate_LOOP_CheckNum (void); +GLOBAL char Finish_Check (int value); +GLOBAL void init_scu1 (void); +GLOBAL void init_scu_macrst (void); +GLOBAL void setup_arp (void); +GLOBAL void TestingSetup (void); +GLOBAL void init_scu2 (void); +GLOBAL void init_scu3 (void); +GLOBAL void init_mac (ULONG base, ULONG tdexbase, ULONG rdexbase); +GLOBAL char TestingLoop (ULONG loop_checknum); +GLOBAL void PrintIO_Line_LOG (void); +GLOBAL void init_phy (int loop_phy); +GLOBAL void recov_phy (int loop_phy); +GLOBAL int FindErr (int value); +GLOBAL int FindErr_Des (int value); +GLOBAL void PrintIO_Header (BYTE option); +GLOBAL void Print_Header (BYTE option); +GLOBAL void PrintIO_LineS (BYTE option); +GLOBAL void PrintIO_Line (BYTE option); +GLOBAL void FPri_ErrFlag (BYTE option); + +#ifdef SUPPORT_PHY_LAN9303 +// ======================================================== +// For LAN9303.c +#undef GLOBAL +#ifdef LAN9303_C +#define GLOBAL +#else +#define GLOBAL extern +#endif + +GLOBAL void LAN9303(int num, int phy_adr, int speed, int int_loopback); +#endif // SUPPORT_PHY_LAN9303 +#endif // End COMMINF_H + diff --git a/arch/arm/cpu/arm926ejs/aspeed/DEF_SPI.H b/arch/arm/cpu/arm926ejs/aspeed/DEF_SPI.H new file mode 100644 index 0000000..02353e7 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/DEF_SPI.H @@ -0,0 +1,35 @@ +/*
+ * 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
+ */
+#ifndef DEF_SPI_H
+#define DEF_SPI_H
+
+#include "TYPEDEF.H"
+#include "SWFUNC.H"
+
+typedef struct _DEVICE_PCI_INFO
+{
+ USHORT usVendorID;
+ USHORT usDeviceID;
+ ULONG ulPCIConfigurationBaseAddress;
+ ULONG ulPhysicalBaseAddress;
+ ULONG ulMMIOBaseAddress;
+ USHORT usRelocateIO;
+} DEVICE_PCI_INFO;
+
+//VIDEO Engine Info
+typedef struct _VIDEO_ENGINE_INFO {
+ USHORT iEngVersion;
+ DEVICE_PCI_INFO VGAPCIInfo;
+} VIDEO_ENGINE_INFO;
+
+BOOLEAN GetDevicePCIInfo (VIDEO_ENGINE_INFO *VideoEngineInfo);
+
+#endif // DEF_SPI_H
diff --git a/arch/arm/cpu/arm926ejs/aspeed/DRAM_SPI.c b/arch/arm/cpu/arm926ejs/aspeed/DRAM_SPI.c new file mode 100644 index 0000000..fe2b5cf --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/DRAM_SPI.c @@ -0,0 +1,78 @@ +/*
+ * 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
+ */
+#define DRAM_SPI_C
+static const char ThisFile[] = "DRAM_SPI.c";
+
+#include "SWFUNC.H"
+
+#ifdef SPI_BUS
+#include <stdio.h>
+#include "DEF_SPI.H"
+#include "LIB_SPI.H"
+
+VOID Set_MMIO_Base(ULONG PCI_BASE, ULONG addr)
+{
+ static ULONG MMIO_BASE = -1;
+
+ if(MMIO_BASE != (addr & 0xffff0000)){
+ if(MMIO_BASE == -1){
+ *(ULONG *)(PCI_BASE + 0xF000) = 1;
+ }
+ *(ULONG *)(PCI_BASE + 0xF004) = addr;
+ MMIO_BASE = addr & 0xffff0000;
+ }
+}
+
+VOID MOutbm(ULONG PCI_BASE, ULONG Offset, BYTE Data)
+{
+ Set_MMIO_Base(PCI_BASE, Offset);
+ *(BYTE *)(PCI_BASE + 0x10000 + (Offset & 0xffff)) = Data;
+}
+
+VOID MOutwm(ULONG PCI_BASE, ULONG Offset, USHORT Data)
+{
+ Set_MMIO_Base(PCI_BASE, Offset);
+ *(USHORT *)(PCI_BASE + 0x10000 + (Offset & 0xffff)) = Data;
+}
+
+VOID MOutdwm(ULONG PCI_BASE, ULONG Offset, ULONG Data)
+{
+ Set_MMIO_Base(PCI_BASE, Offset);
+ *(ULONG *)(PCI_BASE + 0x10000 + (Offset & 0xffff)) = Data;
+}
+
+BYTE MInbm(ULONG PCI_BASE, ULONG Offset)
+{
+ BYTE jData;
+
+ Set_MMIO_Base(PCI_BASE, Offset);
+ jData = *(BYTE *)(PCI_BASE + 0x10000 + (Offset & 0xffff));
+ return(jData);
+}
+
+USHORT MInwm(ULONG PCI_BASE, ULONG Offset)
+{
+ USHORT usData;
+
+ Set_MMIO_Base(PCI_BASE, Offset);
+ usData = *(USHORT *)(PCI_BASE + 0x10000 + (Offset & 0xffff));
+ return(usData);
+}
+
+ULONG MIndwm(ULONG PCI_BASE, ULONG Offset)
+{
+ ULONG ulData;
+
+ Set_MMIO_Base(PCI_BASE, Offset);
+ ulData = *(ULONG *)(PCI_BASE + 0x10000 + (Offset & 0xffff));
+ return(ulData);
+}
+#endif // End SPI_BUS
diff --git a/arch/arm/cpu/arm926ejs/aspeed/IO.H b/arch/arm/cpu/arm926ejs/aspeed/IO.H new file mode 100644 index 0000000..5fe03f0 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/IO.H @@ -0,0 +1,36 @@ +/*
+ * 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
+ */
+#ifndef IO_H
+#define IO_H
+
+#include "SWFUNC.H"
+
+//
+// Macro
+//
+#if defined(LinuxAP)
+ #define delay(val) usleep(val*1000)
+ #define ob(p,d) outb(d,p)
+ #define ib(p) inb(p)
+#else
+ #define ob(p,d) outp(p,d)
+ #define ib(p) inp(p)
+#endif
+
+#ifdef USE_LPC
+void open_aspeed_sio_password(void);
+void enable_aspeed_LDU(BYTE jldu_number);
+int findlpcport(BYTE jldu_number);
+#endif
+
+void WriteSOC_DD(ULONG addr, ULONG data);
+ULONG ReadSOC_DD(ULONG addr);
+#endif
diff --git a/arch/arm/cpu/arm926ejs/aspeed/IO.c b/arch/arm/cpu/arm926ejs/aspeed/IO.c new file mode 100644 index 0000000..b06fdba --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/IO.c @@ -0,0 +1,355 @@ +/*
+ * 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
+ */
+#define IO_C
+static const char ThisFile[] = "IO.c";
+
+#include "SWFUNC.H"
+
+#if defined(LinuxAP)
+ #include <stdio.h>
+ #include <string.h>
+ #include <stdlib.h>
+ #include <stdarg.h>
+ #include <unistd.h>
+ #include <string.h>
+ #include <fcntl.h>
+ #include <pthread.h>
+ #include <sys/mman.h>
+ #include <sys/io.h>
+#endif
+#ifdef SLT_UBOOT
+ #include <common.h>
+ #include <command.h>
+ #include <post.h>
+ #include <malloc.h>
+ #include <net.h>
+ #include "COMMINF.H"
+#endif
+#ifdef SLT_DOS
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <time.h>
+ #include <conio.h>
+ #include <dos.h>
+ #include <mem.h>
+ #include "TYPEDEF.H"
+ #include "LIB.H"
+ #include "COMMINF.H"
+#endif
+
+#include "TYPEDEF.H"
+#include "IO.H"
+#include "LIB_SPI.H"
+
+#ifdef SPI_BUS
+#endif
+#ifdef USE_LPC
+ USHORT usLPCPort;
+#endif
+#ifdef USE_P2A
+#endif
+
+#ifdef USE_LPC
+//------------------------------------------------------------
+// LPC access
+//------------------------------------------------------------
+void open_aspeed_sio_password(void)
+{
+ ob (usLPCPort, 0xaa);
+
+ ob (usLPCPort, 0xa5);
+ ob (usLPCPort, 0xa5);
+}
+
+//------------------------------------------------------------
+void close_aspeed_sio_password(void)
+{
+ ob (usLPCPort, 0xaa);
+}
+
+//------------------------------------------------------------
+void enable_aspeed_LDU(BYTE jldu_number)
+{
+ ob (usLPCPort, 0x07);
+ ob ((usLPCPort + 1), jldu_number);
+ ob (usLPCPort, 0x30);
+ ob ((usLPCPort + 1), 0x01);
+}
+
+//------------------------------------------------------------
+void disable_aspeed_LDU(BYTE jldu_number)
+{
+ ob (usLPCPort, 0x07);
+ ob ((usLPCPort + 1), jldu_number);
+ ob (usLPCPort, 0x30);
+ ob ((usLPCPort + 1), 0x00);
+}
+
+//------------------------------------------------------------
+/*
+ulAddress = AHB address
+jmode = 0: byte mode
+ 1: word mode
+ 2: dword mode
+*/
+static ULONG lpc_read (ULONG ulAddress, BYTE jmode)
+{
+ ULONG uldata = 0;
+ ULONG ultemp = 0;
+ BYTE jtemp;
+
+ //Write Address
+ ob ( usLPCPort, 0xf0);
+ ob ( (usLPCPort + 1 ), ((ulAddress & 0xff000000) >> 24));
+ ob ( usLPCPort, 0xf1);
+ ob ( (usLPCPort + 1) , ((ulAddress & 0x00ff0000) >> 16));
+ ob ( usLPCPort, 0xf2);
+ ob ( (usLPCPort + 1), ((ulAddress & 0x0000ff00) >> 8));
+ ob ( usLPCPort, 0xf3);
+ ob ( (usLPCPort + 1), ulAddress & 0xff);
+
+ //Write Mode
+ ob (usLPCPort, 0xf8);
+ jtemp = ib ((usLPCPort + 1));
+ ob ((usLPCPort + 1), ((jtemp & 0xfc) | jmode));
+
+ //Fire
+ ob (usLPCPort, 0xfe);
+ jtemp = ib ((usLPCPort + 1));
+
+ //Get Data
+ switch ( jmode )
+ {
+ case 0:
+ ob (usLPCPort, 0xf7);
+ ultemp = ib ((usLPCPort + 1));
+ uldata |= (ultemp);
+ break;
+
+ case 1:
+ ob (usLPCPort, 0xf6);
+ ultemp = ib ((usLPCPort + 1));
+ uldata |= (ultemp << 8);
+ ob (usLPCPort, 0xf7);
+ ultemp = ib ((usLPCPort + 1));
+ uldata |= (ultemp << 0);
+ break;
+
+ case 2:
+ ob (usLPCPort, 0xf4);
+ ultemp = ib ((usLPCPort + 1));
+ uldata |= (ultemp << 24);
+ ob (usLPCPort, 0xf5);
+ ultemp = ib ((usLPCPort + 1));
+ uldata |= (ultemp << 16);
+ ob (usLPCPort, 0xf6);
+ ultemp = ib ((usLPCPort + 1));
+ uldata |= (ultemp << 8);
+ ob (usLPCPort, 0xf7);
+ ultemp = ib ((usLPCPort + 1));
+ uldata |= ultemp;
+ break;
+ } // End switch ( jmode )
+
+ return uldata;
+} // End static ULONG lpc_read (ULONG ulAddress, BYTE jmode)
+
+//------------------------------------------------------------
+static void lpc_write (ULONG ulAddress, ULONG uldata, BYTE jmode)
+{
+ BYTE jtemp;
+
+ //Write Address
+ ob ( usLPCPort, 0xf0);
+ ob ((usLPCPort + 1), ((ulAddress & 0xff000000) >> 24));
+ ob ( usLPCPort, 0xf1);
+ ob ((usLPCPort + 1), ((ulAddress & 0x00ff0000) >> 16));
+ ob ( usLPCPort, 0xf2);
+ ob ((usLPCPort + 1), ((ulAddress & 0x0000ff00) >> 8));
+ ob ( usLPCPort, 0xf3);
+ ob ((usLPCPort + 1), ulAddress & 0xff);
+
+ //Write Data
+ switch ( jmode )
+ {
+ case 0:
+ ob ( usLPCPort, 0xf7);
+ ob ((usLPCPort + 1), (uldata & 0xff));
+ break;
+ case 1:
+ ob ( usLPCPort, 0xf6);
+ ob ((usLPCPort + 1), ((uldata & 0xff00) >> 8));
+ ob ( usLPCPort, 0xf7);
+ ob ((usLPCPort + 1), (uldata & 0x00ff));
+ break;
+ case 2:
+ ob ( usLPCPort, 0xf4);
+ ob ((usLPCPort + 1), ((uldata & 0xff000000) >> 24));
+ ob ( usLPCPort, 0xf5);
+ ob ((usLPCPort + 1), ((uldata & 0x00ff0000) >> 16));
+ ob ( usLPCPort, 0xf6);
+ ob ((usLPCPort + 1), ((uldata & 0x0000ff00) >> 8));
+ ob ( usLPCPort, 0xf7);
+ ob ((usLPCPort + 1), uldata & 0xff);
+ break;
+ } // End switch ( jmode )
+
+ //Write Mode
+ ob (usLPCPort, 0xf8);
+ jtemp = ib ((usLPCPort + 1));
+ ob ((usLPCPort + 1), ((jtemp & 0xfc) | jmode));
+
+ //Fire
+ ob (usLPCPort, 0xfe);
+ ob ((usLPCPort + 1), 0xcf);
+
+} // End static void lpc_write (ULONG ulAddress, ULONG uldata, BYTE jmode)
+
+//------------------------------------------------------------
+static USHORT usLPCPortList[] = {0x2e, 0x4e, 0xff};
+int findlpcport(BYTE jldu_number)
+{
+ USHORT *jLPCPortPtr;
+ ULONG ulData;
+
+ jLPCPortPtr = usLPCPortList;
+ while (*(USHORT *)(jLPCPortPtr) != 0xff )
+ {
+ usLPCPort = *(USHORT *)(jLPCPortPtr++);
+
+ open_aspeed_sio_password();
+ enable_aspeed_LDU(0x0d);
+
+ ulData = lpc_read(0x1e6e207c, 2);
+
+ if ( (ulData != 0x00000000) &&
+ (ulData != 0xFFFFFFFF) )
+ {
+ printf("Find LPC IO port at 0x%2x \n", usLPCPort);
+ return 1;
+ }
+
+ disable_aspeed_LDU(0x0d);
+ close_aspeed_sio_password();
+ }
+
+ //printf("[Error] Fail to find proper LPC IO Port \n");
+ return 0;
+}
+#endif // End ifdef USE_LPC
+
+#ifdef USE_P2A
+//------------------------------------------------------------
+// A2P Access
+//------------------------------------------------------------
+void mm_write (ULONG addr, ULONG data, BYTE jmode)
+{
+ *(ULONG *) (mmiobase + 0xF004) = (ULONG) ((addr) & 0xFFFF0000);
+ *(ULONG *) (mmiobase + 0xF000) = (ULONG) 0x00000001;
+
+ switch ( jmode )
+ {
+ case 0:
+ *(BYTE *) (mmiobase + 0x10000 + ((addr) & 0x0000FFFF)) = (BYTE) data;
+ break;
+ case 1:
+ *(USHORT *) (mmiobase + 0x10000 + ((addr) & 0x0000FFFF)) = (USHORT) data;
+ break;
+ case 2:
+ default:
+ *(ULONG *) (mmiobase + 0x10000 + ((addr) & 0x0000FFFF)) = data;
+ break;
+ } //switch
+}
+
+//------------------------------------------------------------
+ULONG mm_read (ULONG addr, BYTE jmode)
+{
+ *(ULONG *) (mmiobase + 0xF004) = (ULONG) ((addr) & 0xFFFF0000);
+ *(ULONG *) (mmiobase + 0xF000) = (ULONG) 0x00000001;
+ switch (jmode)
+ {
+ case 0:
+ return ( *(BYTE *) (mmiobase + 0x10000 + ((addr) & 0x0000FFFF)) );
+ break;
+ case 1:
+ return ( *(USHORT *) (mmiobase + 0x10000 + ((addr) & 0x0000FFFF)) );
+ break;
+ default:
+ case 2:
+ return ( *(ULONG *) (mmiobase + 0x10000 + ((addr) & 0x0000FFFF)) );
+ break;
+ } //switch
+
+ return 0;
+}
+#endif // End ifdef USE_P2A
+
+//------------------------------------------------------------
+// General Access API
+//------------------------------------------------------------
+#ifdef SLT_UBOOT
+BYTE Check_BEorLN ( ULONG chkaddr )
+{
+ BYTE ret = BIG_ENDIAN_ADDRESS;
+ BYTE i = 0;
+
+ do {
+ if ( LittleEndianArea[i].StartAddr == LittleEndianArea[i].EndAddr )
+ break;
+
+ if ( ( LittleEndianArea[i].StartAddr <= chkaddr ) &&
+ ( LittleEndianArea[i].EndAddr >= chkaddr ) ) {
+ ret = LITTLE_ENDIAN_ADDRESS;
+ break;
+ }
+ i++;
+ } while ( 1 );
+
+ return ret;
+}
+#endif
+
+void WriteSOC_DD(ULONG addr, ULONG data)
+{
+#ifdef SLT_UBOOT
+ if ( Check_BEorLN( addr ) == BIG_ENDIAN_ADDRESS )
+ *(volatile unsigned long *)(addr) = cpu_to_le32(data);
+ else
+ *(volatile unsigned long *)(addr) = data;
+#else
+ #ifdef USE_LPC
+ lpc_write(addr, data, 2);
+ #endif
+ #ifdef USE_P2A
+ mm_write(addr, data, 2);
+ #endif
+#endif
+}
+
+//------------------------------------------------------------
+ULONG ReadSOC_DD(ULONG addr)
+{
+#ifdef SLT_UBOOT
+ if ( Check_BEorLN( addr ) == BIG_ENDIAN_ADDRESS )
+ return le32_to_cpu(*(volatile unsigned long *) (addr));
+ else
+ return (*(volatile unsigned long *) (addr));
+#else
+ #ifdef USE_LPC
+ return (lpc_read(addr, 2));
+ #endif
+ #ifdef USE_P2A
+ return (mm_read(addr, 2));
+ #endif
+#endif
+ return 0;
+}
diff --git a/arch/arm/cpu/arm926ejs/aspeed/LAN9303.c b/arch/arm/cpu/arm926ejs/aspeed/LAN9303.c new file mode 100644 index 0000000..fdabd45 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/LAN9303.c @@ -0,0 +1,525 @@ +/*
+ * 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
+ */
+#define LAN9303_C
+static const char ThisFile[] = "LAN9303.c";
+
+#include "SWFUNC.H" +#ifdef SLT_UBOOT
+ #include "COMMINF.H" + #include "MAC.H" + #include "IO.H"
+#endif
+
+#ifdef SLT_DOS
+ #include "COMMINF.H"
+ #include <stdlib.h> + #include "IO.H" +#endif
+
+#ifdef SUPPORT_PHY_LAN9303 +//#define LAN9303M
+#define I2C_Debug 0
+#define Print_DWRW 0
+#define Print_PHYRW 0
+#define I2C_TIMEOUT 10000000
+
+ULONG devbase;
+ULONG busnum;
+ULONG byte;
+ULONG data_rd;
+
+//------------------------------------------------------------
+// Basic
+//------------------------------------------------------------
+void actime(ULONG ac1, ULONG ac2, ULONG *fact, ULONG *ckh, ULONG *ckl)
+{
+ static int divcnt;
+
+ ac1 = ac1 * 50 + 1;
+ ac2 = ac2 * 50 + 1;
+
+ divcnt = 0;
+ while (ac1 > 8 || ac2 > 8) {
+ divcnt++;
+ ac1 >>= 1;
+ ac2 >>= 1;
+ }
+
+ if (ac1 < 2 ) ac1 = 2;
+ if (ac2 < 2 ) ac2 = 2;
+ if (ac1 > ac2) ac2 = 1;
+ else ac1 += 1;
+
+#ifdef PRINT_MSG
+ printf("Divcnt = %d, ckdiv = %d, ckh = %d, ckl = %d\n",(1<<divcnt)*(ac1+ac2),divcnt,ac1-1,ac2-1);
+ printf("CKH = %d us, CKL = %d us\n",(1<<divcnt)*ac1/50,(1<<divcnt)*ac2/50);
+#endif
+
+ *fact = divcnt;
+ *ckh = ac1 - 1;
+ *ckl = ac2 - 1;
+}
+
+//------------------------------------------------------------
+ULONG PollStatus()
+{
+ static ULONG status;
+ static ULONG cnt = 0;
+
+ do {
+ status = ReadSOC_DD( devbase + 0x14 ) & 0xff;
+
+ if ( ++cnt > I2C_TIMEOUT ) {
+ printf("\nWait1 Timeout at bus %d!\n", busnum);
+ printf("Status 14 = %08x\n", ReadSOC_DD(devbase + 0x14));
+ exit(0);
+ }
+ } while (status != 0);
+
+ cnt = 0;
+ do {
+ status = ReadSOC_DD( devbase + 0x10 );
+ if ( ++cnt > I2C_TIMEOUT ) {
+ printf("\nWait2 Timeout at bus %d!\n", busnum);
+ printf("Status 14 = %08x\n", ReadSOC_DD(devbase + 0x14));
+ exit(0);
+ }
+ } while (status == 0);
+
+ WriteSOC_DD( devbase + 0x10, status );
+
+ return(status);
+}
+
+
+//------------------------------------------------------------
+ULONG writeb(ULONG start, ULONG data, ULONG stop)
+{
+ WriteSOC_DD( devbase + 0x20, data);
+ WriteSOC_DD( devbase + 0x14, 0x02 | start | (stop << 5) );
+ return(PollStatus());
+}
+
+//------------------------------------------------------------
+ULONG readb(ULONG last, ULONG stop)
+{
+ static ULONG data;
+
+ WriteSOC_DD( devbase + 0x14, 0x08 | (last << 4) | (stop << 5) );
+ data = PollStatus();
+
+ if (data & 0x4) {
+ data = ReadSOC_DD( devbase + 0x20 );
+ return(data >> 8);
+ }
+ else {
+ return(-1);
+ }
+}
+
+//------------------------------------------------------------
+void Initial(ULONG base, ULONG ckh, ULONG ckl)
+{
+ static ULONG ackh;
+ static ULONG ackl;
+ static ULONG divx;
+
+ actime(ckh, ckl, &divx, &ackh, &ackl);
+ WriteSOC_DD(base + 0x00, 0x1);
+ if (ReadSOC_DD(base + 0x00) != 0x1) {
+ printf("Controller initial fail : %x\n",base);
+ exit(0);
+ }
+ WriteSOC_DD(base + 0x04, 0x77700360 | (ackh << 16) | (ackl << 12) | divx);
+ WriteSOC_DD(base + 0x08, 0x0);
+ WriteSOC_DD(base + 0x0c, 0x0);
+ WriteSOC_DD(base + 0x10, 0xffffffff);
+ WriteSOC_DD(base + 0x14, 0x00);
+ WriteSOC_DD(base + 0x1C, 0xff0000);
+ WriteSOC_DD(base + 0x20, 0x00);
+}
+
+//------------------------------------------------------------
+void print_status(ULONG status)
+{
+ if ( status & 0x02 ) printf( "Device NAK\n" );
+ if ( status & 0x08 ) printf( "Arbitration Loss\n" );
+ if ( status & 0x10 ) printf( "STOP\n" );
+ if ( status & 0x20 ) printf( "Abnormal STOP\n" );
+ if ( status & 0x40 ) printf( "SCL Low timeout\n" );
+}
+
+//------------------------------------------------------------
+void readme()
+{
+ printf("\nVersion:%s\n", version_name);
+#ifdef LAN9303M
+ printf("LAN9303M [bus] [vir_PHY_adr] [speed] [func]\n");
+#else
+ printf("LAN9303 [bus] [vir_PHY_adr] [speed] [func]\n" );
+#endif
+ printf("[bus] | 1~14: I2C bus number\n" );
+ printf("[vir_PHY_adr] | 0~1: virtual PHY address\n" );
+ printf("[speed] | 1: 100M\n" );
+ printf(" | 2: 10 M\n" );
+ printf("[func] | 0: external loopback\n" );
+ printf(" | 1: internal loopback\n" );
+}
+
+//------------------------------------------------------------
+void quit()
+{
+ WriteSOC_DD( devbase + 0x14, 0x20 );
+ PollStatus();
+ readme();
+}
+
+//------------------------------------------------------------
+// Double-Word Read/Write
+//------------------------------------------------------------
+ULONG I2C_DWRead(ULONG adr)
+{
+ static ULONG status;
+ int i;
+
+ Initial(devbase, 10, 10);
+
+ if ( Print_DWRW )
+ printf("RAdr %02x: ", adr);
+
+ status = writeb( 1, LAN9303_I2C_ADR, 0 ); + if ( I2C_Debug )
+ printf("R1W[%02x]%02x ", status, LAN9303_I2C_ADR); +
+ if ( status != 0x1 ) {
+ print_status(status);
+ quit();
+ exit(0);
+ }
+
+ status = writeb(0, adr, 0);
+ if ( I2C_Debug )
+ printf("R2W[%02x]%02x ", status, adr);
+ if ( !(status & 0x1) ) {
+ print_status(status);
+ quit();
+ exit(0);
+ }
+
+ status = writeb(1, LAN9303_I2C_ADR | 0x1, 0); + if ( I2C_Debug )
+ printf("R3W[%02x]%02x ", status, LAN9303_I2C_ADR | 0x1); + if ( status != 0x1 ) {
+ print_status(status);
+ quit();
+ exit(0);
+ }
+
+ if ( I2C_Debug )
+ printf("R4");
+
+ data_rd = 0;
+ for (i = 24; i >= 0; i-=8) {
+ if (i == 0) byte = readb(1, 1);
+ else byte = readb(0, 0);
+
+ if ( I2C_Debug )
+ printf("%02x ", byte);
+ data_rd = data_rd | (byte << i);
+ }
+
+ if ( Print_DWRW )
+ printf("%08x\n", data_rd);
+
+ return (data_rd);
+} // End ULONG I2C_DWRead(ULONG adr)
+
+//------------------------------------------------------------
+void I2C_DWWrite(ULONG adr, ULONG dwdata)
+{
+ static ULONG status;
+ int i;
+ ULONG endx;
+
+ Initial(devbase, 10, 10);
+ if (Print_DWRW)
+ printf("WAdr %02x: ", adr);
+
+ status = writeb(1, LAN9303_I2C_ADR, 0); + if ( I2C_Debug )
+ printf("W1[%02x]%02x ", status, LAN9303_I2C_ADR); + if ( status != 0x1 ) {
+ print_status(status);
+ quit();
+ exit(0);
+ }
+ status = writeb(0, adr, 0);
+ if ( I2C_Debug )
+ printf("W2[%02x]%02x ", status, adr);
+ if ( !(status & 0x1) ) {
+ print_status(status);
+ quit();
+ exit(0);
+ }
+
+ if (I2C_Debug)
+ printf("W3");
+ endx = 0;
+ for (i = 24; i >= 0; i-=8) {
+ if (i == 0)
+ endx = 1;
+ byte = (dwdata >> i) & 0xff;
+ status = writeb(0, byte, endx);
+
+ if (I2C_Debug)
+ printf("[%02x]%02x ", status, byte);
+ if (!(status & 0x1)) {
+ print_status(status);
+ quit();
+ exit(0);
+ }
+ }
+
+ if (Print_DWRW) printf("%08x\n", dwdata);
+} // End void I2C_DWWrite(ULONG adr, ULONG dwdata)
+
+//------------------------------------------------------------
+// PHY Read/Write
+//------------------------------------------------------------
+ULONG LAN9303_PHY_Read(ULONG phy_adr, ULONG reg_adr)
+{
+ static ULONG data_rd;
+
+ I2C_DWWrite(0x2a, ((phy_adr & 0x1f) << 11) | ((reg_adr & 0x1f) << 6));//[0A8h]PMI_ACCESS
+ do {
+ data_rd = I2C_DWRead (0x2a);
+ } while(data_rd & 0x00000001);//[0A8h]PMI_ACCESS
+
+ data_rd = I2C_DWRead (0x29);//[0A4h]PMI_DATA
+ if (Print_PHYRW)
+ printf("PHY:%2d, Reg:%2d, Data:%08x\n", phy_adr, reg_adr, data_rd);
+
+ return(data_rd);
+}
+
+//------------------------------------------------------------
+void LAN9303_PHY_Write(ULONG phy_adr, ULONG reg_adr, ULONG data_wr)
+{
+ static ULONG data_rd;
+
+ I2C_DWWrite(0x29, data_wr);//[0A4h]PMI_DATA
+
+ I2C_DWWrite(0x2a, ((phy_adr & 0x1f) << 11) | ((reg_adr & 0x1f) << 6) | 0x2);//[0A8h]PMI_ACCESS
+ do {
+ data_rd = I2C_DWRead (0x2a);
+ } while(data_rd & 0x00000001);//[0A8h]PMI_ACCESS
+}
+
+//------------------------------------------------------------
+ULONG LAN9303_PHY_Read_WD(ULONG data_ctl)
+{
+ static ULONG data_rd;
+
+ I2C_DWWrite(0x2a, data_ctl);//[0A8h]PMI_ACCESS
+ do {
+ data_rd = I2C_DWRead (0x2a);
+ } while(data_rd & 0x00000001);//[0A8h]PMI_ACCESS
+
+ data_rd = I2C_DWRead (0x29);//[0A4h]PMI_DATA
+ if (Print_PHYRW)
+ printf("WD Data:%08x\n", data_ctl);
+
+ return(data_rd);
+}
+
+//------------------------------------------------------------
+void LAN9303_PHY_Write_WD(ULONG data_ctl, ULONG data_wr)
+{
+ static ULONG data_rd;
+
+ I2C_DWWrite( 0x29, data_wr ); //[0A4h]PMI_DATA
+ I2C_DWWrite( 0x2a, data_ctl ); //[0A8h]PMI_ACCESS
+ do {
+ data_rd = I2C_DWRead (0x2a);
+ } while(data_rd & 0x00000001); //[0A8h]PMI_ACCESS
+}
+
+//------------------------------------------------------------
+// Virtual PHY Read/Write
+//------------------------------------------------------------
+ULONG LAN9303_VirPHY_Read(ULONG reg_adr)
+{
+ static ULONG data_rd;
+
+ data_rd = I2C_DWRead (0x70+reg_adr);//[1C0h]
+ if ( Print_PHYRW )
+ printf("VirPHY Reg:%2d, Data:%08x\n", reg_adr, data_rd);
+
+ return(data_rd);
+}
+
+//------------------------------------------------------------
+void LAN9303_VirPHY_Write(ULONG reg_adr, ULONG data_wr)
+{
+ I2C_DWWrite(0x70+reg_adr, data_wr);//[1C0h]
+}
+
+//------------------------------------------------------------
+void LAN9303_VirPHY_RW(ULONG reg_adr, ULONG data_clr, ULONG data_set)
+{
+ I2C_DWWrite(0x70+reg_adr, (LAN9303_VirPHY_Read(reg_adr) & (~data_clr)) | data_set);//[1C0h]
+}
+
+//------------------------------------------------------------
+// PHY Read/Write
+//------------------------------------------------------------
+ULONG LAN9303_Read(ULONG adr)
+{
+ static ULONG data_rd;
+
+ I2C_DWWrite(0x6c, 0xc00f0000 | adr & 0xffff);//[1B0h]SWITCH_CSR_CMD
+ do {
+ data_rd = I2C_DWRead (0x6c);
+ } while(data_rd & 0x80000000);//[1B0h]SWITCH_CSR_CMD
+
+ return(I2C_DWRead (0x6b));//[1ACh]SWITCH_CSR_DATA
+}
+
+//------------------------------------------------------------
+void LAN9303_Write(ULONG adr, ULONG data)
+{
+ static ULONG data_rd;
+
+ I2C_DWWrite(0x6b, data);//[1ACh]SWITCH_CSR_DATA
+ I2C_DWWrite(0x6c, 0x800f0000 | adr & 0xffff);//[1B0h]SWITCH_CSR_CMD
+
+ do {
+ data_rd = I2C_DWRead (0x6c);
+ } while(data_rd & 0x80000000);//[1B0h]SWITCH_CSR_CMD
+}
+
+//------------------------------------------------------------
+void LAN9303(int num, int phy_adr, int speed, int int_loopback)
+{
+ static ULONG data_rd;
+
+ //------------------------------------------------------------
+ // I2C Initial
+ //------------------------------------------------------------
+ busnum = num;
+ if (busnum <= 7) devbase = 0x1E78A000 + ( busnum * 0x40);
+ else devbase = 0x1E78A300 + ((busnum-8) * 0x40);
+ Initial(devbase, 10, 10);
+
+ //------------------------------------------------------------
+ // LAN9303 Register Setting
+ //------------------------------------------------------------
+ printf("----> Start\n");
+ if (int_loopback == 0) {
+ //Force Speed & external loopback
+ if (speed == 1) { //100M
+ LAN9303_VirPHY_RW( 0, 0xffff, 0x2300 ); //adr clr set //VPHY_BASIC_CTRL
+ LAN9303_VirPHY_RW( 11, 0xffff, 0x2300 ); //adr clr set //P1_MII_BASIC_CONTROL
+ LAN9303_PHY_Write( phy_adr + 1, 0, 0x2300 );
+ LAN9303_PHY_Write( phy_adr + 2, 0, 0x2300 );
+ }
+ else {
+ LAN9303_VirPHY_RW( 0, 0xffff, 0x0100 ); //adr clr set //VPHY_BASIC_CTRL
+ LAN9303_VirPHY_RW( 11, 0xffff, 0x0100 ); //adr clr set //P1_MII_BASIC_CONTROL
+ LAN9303_PHY_Write( phy_adr + 1, 0, 0x0100);
+ LAN9303_PHY_Write( phy_adr + 2, 0, 0x0100);
+ }
+
+ LAN9303_Write( 0x180c, 0x00000001 ); // SWE_VLAN_WR_DATA
+ LAN9303_Write( 0x180b, 0x00000010 ); // SWE_VLAN_CMD
+ do {data_rd = LAN9303_Read (0x1810);} while(data_rd & 0x1);
+
+ LAN9303_Write( 0x180c, 0x00000002 ); // SWE_VLAN_WR_DATA
+ LAN9303_Write( 0x180b, 0x00000011 ); // SWE_VLAN_CMD
+ do {data_rd = LAN9303_Read (0x1810);} while(data_rd & 0x1);
+
+ LAN9303_Write( 0x180c, 0x00000003 ); // SWE_VLAN_WR_DATA
+ LAN9303_Write( 0x180b, 0x00000012 ); // SWE_VLAN_CMD
+ do {data_rd = LAN9303_Read (0x1810);} while(data_rd & 0x1);
+
+#ifdef LAN9303M
+ LAN9303_Write( 0x180c, 0x00022001 ); // SWE_VLAN_WR_DATA
+ LAN9303_Write( 0x180b, 0x00000000 ); // SWE_VLAN_CMD
+ do {data_rd = LAN9303_Read (0x1810);} while(data_rd & 0x1);
+
+ LAN9303_Write( 0x180c, 0x00024002 ); // SWE_VLAN_WR_DATA
+ LAN9303_Write( 0x180b, 0x00000001 ); // SWE_VLAN_CMD
+ do {data_rd = LAN9303_Read (0x1810);} while(data_rd & 0x1);
+
+ LAN9303_Write( 0x180c, 0x0002a003 ); // SWE_VLAN_WR_DATA
+ LAN9303_Write( 0x180b, 0x00000002 ); // SWE_VLAN_CMD
+ do {data_rd = LAN9303_Read (0x1810);} while(data_rd & 0x1);
+#else
+ LAN9303_Write( 0x180c, 0x0002a001 ); // SWE_VLAN_WR_DATA
+ LAN9303_Write( 0x180b, 0x00000000 ); // SWE_VLAN_CMD
+ do {data_rd = LAN9303_Read (0x1810);} while(data_rd & 0x1);
+
+ LAN9303_Write( 0x180c, 0x0000a002 ); // SWE_VLAN_WR_DATA
+ LAN9303_Write( 0x180b, 0x00000001 ); // SWE_VLAN_CMD
+ do {data_rd = LAN9303_Read (0x1810);} while(data_rd & 0x1);
+
+ LAN9303_Write( 0x180c, 0x00022003 ); // SWE_VLAN_WR_DATA
+ LAN9303_Write( 0x180b, 0x00000002 ); // SWE_VLAN_CMD
+ do {data_rd = LAN9303_Read (0x1810);} while(data_rd & 0x1);
+#endif
+ LAN9303_Write( 0x1840, 0x00000007);
+ }
+ else if ( int_loopback == 1 ) {
+ //Force Speed & internal loopback
+ if ( speed == 1 ) {
+ //100M
+ LAN9303_VirPHY_RW( 0, 0xffff, 0x6300 ); // adr clr set //VPHY_BASIC_CTRL
+ LAN9303_VirPHY_RW( 11, 0xffff, 0x6300 ); // adr clr set //P1_MII_BASIC_CONTROL
+ LAN9303_PHY_Write( phy_adr + 1, 0, 0x6300 );
+ LAN9303_PHY_Write( phy_adr + 2, 0, 0x6300 );
+ }
+ else {
+ LAN9303_VirPHY_RW( 0, 0xffff, 0x4100 ); // adr clr set //VPHY_BASIC_CTRL
+ LAN9303_VirPHY_RW( 11, 0xffff, 0x4100 ); // adr clr set //P1_MII_BASIC_CONTROL
+ LAN9303_PHY_Write( phy_adr + 1, 0, 0x4100 );
+ LAN9303_PHY_Write( phy_adr + 2, 0, 0x4100 );
+ }
+ }
+ else {
+ //Force Speed
+ if (speed == 1) {
+ //100M
+ LAN9303_VirPHY_RW( 0, 0xffff, 0x2300 ); // adr clr set //VPHY_BASIC_CTRL
+ LAN9303_VirPHY_RW( 11, 0xffff, 0x2300 ); // adr clr set //P1_MII_BASIC_CONTROL
+ LAN9303_PHY_Write( phy_adr + 1, 0, 0x2300 );
+ LAN9303_PHY_Write( phy_adr + 2, 0, 0x2300 );
+ }
+ else {
+ LAN9303_VirPHY_RW( 0, 0xffff, 0x0100 ); // adr clr set //VPHY_BASIC_CTRL
+ LAN9303_VirPHY_RW( 11, 0xffff, 0x0100 ); // adr clr set //P1_MII_BASIC_CONTROL
+ LAN9303_PHY_Write( phy_adr + 1, 0, 0x0100 );
+ LAN9303_PHY_Write( phy_adr + 2, 0, 0x0100 );
+ }
+#ifdef LAN9303M
+#else
+ if (int_loopback == 3) {
+ //[LAN9303]IEEE measurement
+ data_rd = LAN9303_PHY_Read(phy_adr+1, 27);//PHY_SPECIAL_CONTROL_STAT_IND_x
+ LAN9303_PHY_Write(phy_adr+1, 27, (data_rd & 0x9fff) | 0x8000);//PHY_SPECIAL_CONTROL_STAT_IND_x
+
+ data_rd = LAN9303_PHY_Read(phy_adr+2, 27);//PHY_SPECIAL_CONTROL_STAT_IND_x
+ LAN9303_PHY_Write(phy_adr+2, 27, (data_rd & 0x9fff) | 0x8000);//PHY_SPECIAL_CONTROL_STAT_IND_x
+ }
+#endif
+ } // End if (int_loopback == 0)
+} // End void LAN9303(int num, int phy_adr, int speed, int int_loopback)
+#endif // SUPPORT_PHY_LAN9303 +
diff --git a/arch/arm/cpu/arm926ejs/aspeed/LIB.H b/arch/arm/cpu/arm926ejs/aspeed/LIB.H new file mode 100644 index 0000000..a7c61dd --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/LIB.H @@ -0,0 +1,37 @@ +/*
+ * 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
+ */
+#ifndef LIB_H
+#define LIB_H
+
+#include "TYPEDEF.H"
+
+//
+// Macro
+//
+#define INTFUNC int386
+
+#define OUTDWPORT outpd
+#define INDWPORT inpd
+#define OUTPUT outp
+#define INPUT inp
+
+//
+// PCI
+//
+ULONG ReadPCIReg (ULONG ulPCIConfigAddress, BYTE jOffest, ULONG ulMask);
+ULONG FindPCIDevice (USHORT usVendorID, USHORT usDeviceID, USHORT usBusType);
+VOID WritePCIReg (ULONG ulPCIConfigAddress, BYTE jOffest, ULONG ulMask, ULONG ulData);
+
+//
+// Map Resource
+//
+ULONG MapPhysicalToLinear (ULONG ulBaseAddress, ULONG ulSize);
+#endif
diff --git a/arch/arm/cpu/arm926ejs/aspeed/LIB.c b/arch/arm/cpu/arm926ejs/aspeed/LIB.c new file mode 100644 index 0000000..f2a0c54 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/LIB.c @@ -0,0 +1,184 @@ +/*
+ * 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
+ */
+#define LIB_C
+static const char ThisFile[] = "LIB.c";
+
+#include "SWFUNC.H"
+
+#ifdef SLT_UBOOT
+ #include <common.h>
+ #include <command.h>
+#endif
+#ifdef SLT_DOS
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <conio.h>
+#include <dos.h>
+#include <mem.h>
+#endif
+
+#include "LIB.H"
+#include "TYPEDEF.H"
+
+#ifdef USE_P2A
+//------------------------------------------------------------
+// PCI
+//------------------------------------------------------------
+ULONG ReadPCIReg (ULONG ulPCIConfigAddress, BYTE jOffest, ULONG ulMask)
+{
+#ifndef Windows
+ OUTDWPORT(0xcf8, ulPCIConfigAddress + jOffest);
+
+ return (((ULONG)INDWPORT(0xcfc)) & ulMask);
+#else
+ WRITE_PORT_ULONG((PULONG)0xcf8, ulPCIConfigAddress + jOffest);
+
+ return (READ_PORT_ULONG((PULONG)0xcfc) & ulMask);
+#endif
+}
+
+//------------------------------------------------------------
+VOID WritePCIReg (ULONG ulPCIConfigAddress, BYTE jOffest, ULONG ulMask, ULONG ulData)
+{
+#ifndef Windows
+ OUTDWPORT(0xcf8, ulPCIConfigAddress + jOffest);
+ OUTDWPORT(0xcfc, (INDWPORT(0xcfc) & ulMask | ulData));
+#else
+ WRITE_PORT_ULONG((PULONG)0xcf8, ulPCIConfigAddress + jOffest);
+ WRITE_PORT_ULONG((PULONG)0xcfc, (READ_PORT_ULONG((PULONG)0xcfc) & ulMask | ulData));
+#endif
+}
+
+//------------------------------------------------------------
+ULONG FindPCIDevice (USHORT usVendorID, USHORT usDeviceID, USHORT usBusType)
+{
+//Return: ulPCIConfigAddress
+//usBusType: ACTIVE/PCI/AGP/PCI-E
+
+ ULONG Base[256];
+ ULONG ebx;
+ USHORT i;
+ USHORT j;
+
+ for (i = 0; i < 256; i++) {
+ Base[i] = 0x80000000 + 0x10000 * i;
+ }
+
+ if (usBusType == PCI)
+ {
+ ebx = 0x80000000;
+ }
+ else if (usBusType == PCIE)
+ {
+ ebx = 0x80020000;
+ }
+ else // AGP and ACTIVE
+ {
+ ebx = 0x80010000;
+ }
+
+ if ( usBusType != ACTIVE ) //AGP, PCI, PCIE
+ {
+ for (i = 0; i < 32; i++)
+ {
+ ebx = ebx + (0x800);
+ if (((USHORT)ReadPCIReg(ebx, 0, 0xffff) == usVendorID) && ((USHORT)(ReadPCIReg(ebx, 0, 0xffff0000) >> 16) == usDeviceID))
+ {
+ return ebx;
+ }
+ }
+ return 0;
+ }
+ else //ACTIVE
+ {
+ for (j = 0; j < 256; j++)
+ {
+ ebx = Base[j];
+ for (i = 0; i < 32; i++)
+ {
+ ebx = ebx + (0x800);
+ if (((USHORT)ReadPCIReg(ebx, 0, 0xffff) == usVendorID) && ((USHORT)(ReadPCIReg(ebx, 0, 0xffff0000) >> 16) == usDeviceID))
+ {
+ return ebx;
+ }
+ }
+ }
+ return 0;
+ }
+} // End ULONG FindPCIDevice (USHORT usVendorID, USHORT usDeviceID, USHORT usBusType)
+#endif
+//------------------------------------------------------------
+// Allocate Resource
+//------------------------------------------------------------
+#ifdef SLT_DOS
+ULONG InitDOS32()
+{
+ union REGS regs ;
+
+ regs.w.ax = 0xee00;
+ INTFUNC(0x31, ®s, ®s) ;
+
+ if(regs.w.ax >= 0x301) // DOS32 version >= 3.01 ?
+ return 1;
+ else
+ return 0;
+}
+
+//------------------------------------------------------------
+USHORT CheckDOS()
+{
+ union REGS regs;
+
+ regs.w.ax = 0xeeff;
+ int386(0x31, ®s, ®s);
+ if (regs.x.eax == 0x504d4457)
+ {
+ return 0;
+ } else {
+ printf("PMODEW Init. fail\n");
+ return 1;
+ }
+}
+
+//------------------------------------------------------------
+ULONG MapPhysicalToLinear (ULONG ulBaseAddress, ULONG ulSize)
+{
+ union REGS regs;
+
+ regs.w.ax = 0x0800; // map physcial memory
+ regs.w.bx = ulBaseAddress >> 16; // bx:cx = physical address
+ regs.w.cx = ulBaseAddress;
+ regs.w.si = ulSize >> 16; // si:di = mapped memory block size
+ regs.w.di = ulSize;
+ INTFUNC(0x31, ®s, ®s); // int386(0x31, ®s, ®s);
+ if (regs.w.cflag == 0)
+ return (ULONG) (regs.w.bx << 16 + regs.w.cx); // Linear Addr = bx:cx
+ else
+ return 0;
+}
+
+//------------------------------------------------------------
+USHORT FreePhysicalMapping(ULONG udwLinAddress)
+{
+ union REGS regs;
+
+ regs.w.ax = 0x0801;
+ regs.w.bx = udwLinAddress >> 16;
+ regs.w.cx = udwLinAddress & 0xFFFF;
+ int386(0x31, ®s, ®s);
+
+ if (regs.x.cflag)
+ return ((USHORT) 0);
+ else return ((USHORT) 1);
+}
+#endif
+
diff --git a/arch/arm/cpu/arm926ejs/aspeed/LIB_SPI.H b/arch/arm/cpu/arm926ejs/aspeed/LIB_SPI.H new file mode 100644 index 0000000..78c8f1e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/LIB_SPI.H @@ -0,0 +1,23 @@ +/*
+ * 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
+ */
+#ifndef LIB_SPI_H
+#define LIB_SPI_H
+
+#ifdef SPI_BUS
+ // MMIO Functions
+ VOID MOutwm (ULONG, ULONG, USHORT);
+ VOID MOutdwm (ULONG, ULONG, ULONG);
+ ULONG MIndwm (ULONG, ULONG);
+
+ void spim_init(int cs);
+#endif
+
+#endif // LIB_SPI_H
diff --git a/arch/arm/cpu/arm926ejs/aspeed/MAC.H b/arch/arm/cpu/arm926ejs/aspeed/MAC.H new file mode 100644 index 0000000..6732117 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/MAC.H @@ -0,0 +1,157 @@ +/*
+ * 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
+ */
+#ifndef MAC_H
+#define MAC_H
+
+#ifdef SPI_BUS
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <time.h>
+ #define SPI_CS 1
+#endif
+// ( USE_P2A | USE_LPC )
+
+#if defined(LinuxAP)
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <stdarg.h>
+ #include <unistd.h>
+ #include <string.h>
+ #include <fcntl.h>
+ #include <pthread.h>
+ #include <sys/mman.h>
+ #include <sys/io.h>
+#endif
+#ifdef SLT_UBOOT
+ #include <common.h>
+ #include <command.h>
+#endif
+#ifdef SLT_DOS
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <time.h>
+ #include <conio.h>
+ #include <dos.h>
+ #include <mem.h>
+#endif
+
+#include "NCSI.H"
+#include "IO.H"
+
+// --------------------------------------------------------------
+// Define
+// --------------------------------------------------------------
+
+//#define Force_Enable_MAC34 //[ON][SLT:off] (Force enable mac34)
+//#define Force_Enable_NewMDIO //[off][SLT:off] (Force enable new MDC/MDIO)
+//#define Enable_Fast_SCU //[off]
+//#define Enable_Old_Style //[off]
+#define ENABLE_DASA //[ON]
+//#define Enable_AST2300_Int125MHz //[off]
+//#define ENABLE_ARP_2_WOL //[off]
+//#define Enable_MAC_SWRst //[off]
+
+#define Enable_Runt
+//#define Enable_Jumbo
+//#define Enable_BufMerge
+//#define Disable_VGA
+
+//#define SelectSimpleBoundary //[off] Using in debug
+//#define SelectSimpleData //[off] Using in debug
+//#define SelectSimpleLength 1512 //[off] 60(0x3c) ~ 1514(0x5ea); 1512(0x5e8)
+//#define SelectDesNumber 8 //[off] 1 ~
+//#define SelectSimpleDA //[off] Using in debug
+//#define SelectSimpleDes //[off]
+//#define SelectLengthInc //[off] Using in debug
+
+#define SimpleData_Fix //[ON] Using in debug
+#define SimpleData_FixNum 12
+#define SimpleData_FixVal00 0x00000000 //[0]no SelectSimpleDA: (60: 0412 8908)(1512: e20d e9da)
+#define SimpleData_FixVal01 0xffffffff //[0]no SelectSimpleDA: (60: f48c f14d)(1512: af05 260c)
+#define SimpleData_FixVal02 0x55555555 //[0]no SelectSimpleDA: (60: 5467 5ecb)(1512: d90a 5368)
+#define SimpleData_FixVal03 0xaaaaaaaa //[0]no SelectSimpleDA: (60: a4f9 268e)(1512: 9402 9cbe)
+#define SimpleData_FixVal04 0x5a5a5a5a //[1]no SelectSimpleDA: (60: 7f01 e22d)(1512: 4fd3 8012)
+#define SimpleData_FixVal05 0xc3c3c3c3 //[1]no SelectSimpleDA: (60: 5916 02d5)(1512: 99f1 6127)
+#define SimpleData_FixVal06 0x96969696 //[1]no SelectSimpleDA: (60: 0963 d516)(1512: a2f6 db95)
+#define SimpleData_FixVal07 0xf0f0f0f0 //[1]no SelectSimpleDA: (60: dfea 4dab)(1512: 39dc f576)
+#define SimpleData_FixVal08 0x5555aaaa //[2]no SelectSimpleDA: (60: b61b 5777)(1512: 4652 ddb0)
+#define SimpleData_FixVal09 0xffff0000 //[2]no SelectSimpleDA: (60: 16f0 f8f1)(1512: 305d a8d4)
+#define SimpleData_FixVal10 0x5a5aa5a5 //[2]no SelectSimpleDA: (60: 9d7d eb91)(1512: d08b 0eca)
+#define SimpleData_FixVal11 0xc3c33c3c //[2]no SelectSimpleDA: (60: bb6a 0b69)(1512: 06a9 efff)
+
+#define SelectSimpleDA_Dat0 0x67052301
+#define SelectSimpleDA_Dat1 0xe0cda089
+#define SelectSimpleDA_Dat2 0x98badcfe
+
+#define SelectWOLDA_DatH 0x206a
+#define SelectWOLDA_DatL 0x8a374d9b
+
+#define MOVE_DATA_MB_SEC 800 // MByte per second to move data
+
+//---------------------------------------------------------
+// Frame size
+//---------------------------------------------------------
+#define ENABLE_RAND_SIZE 0
+#define Rand_Sed 0xffccd
+#define FRAME_Rand_Simple 0
+#define MIN_FRAME_RAND_SIZE 60
+#define MAX_FRAME_RAND_SIZE 1514
+
+#define FRAME_SELH_PERD 7
+#ifdef Enable_Jumbo
+// #define FRAME_LENH 9212 //max:9212
+// #define FRAME_LENL 9211 //max:9212
+ #define FRAME_LENH 9212 //max:9212
+ #define FRAME_LENL 9212 //max:9212
+// #define FRAME_LENH 8120
+// #define FRAME_LENL 8119
+// #define FRAME_LENH 7000
+// #define FRAME_LENL 6999
+// #define FRAME_LENH 4095
+// #define FRAME_LENL 4094
+// #define FRAME_LENH 2040
+// #define FRAME_LENL 2039
+#else
+ #ifdef SelectSimpleLength
+// #define FRAME_LENH ( SelectSimpleLength + 1 )
+// #define FRAME_LENL ( SelectSimpleLength )
+ #define FRAME_LENH SelectSimpleLength
+ #define FRAME_LENL SelectSimpleLength
+ #else
+// #define FRAME_LENH 1514 //max:1514
+// #define FRAME_LENL 1513 //max:1514
+ #define FRAME_LENH 1514 //max:1514
+ #define FRAME_LENL 1514 //max:1514
+ #endif
+#endif
+
+const ULONG ARP_org_data[16] = {
+ 0xffffffff,
+ 0x0000ffff, // SA:00 00
+ 0x12345678, // SA:12 34 56 78
+ 0x01000608, // ARP(0x0806)
+ 0x04060008,
+ 0x00000100, // sender MAC Address: 00 00
+ 0x12345678, // sender MAC Address: 12 34 56 78
+ 0xeb00a8c0, // sender IP Address: 192.168.0.235
+ 0x00000000, // target MAC Address: 00 00 00 00
+ 0xa8c00000, // target MAC Address: 00 00, sender IP Address:192.168
+ 0x00000100, // sender IP Address: 0.1
+// 0x0000de00, // sender IP Address: 0.222
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0xc68e2bd5
+};
+
+#endif // MAC_H
diff --git a/arch/arm/cpu/arm926ejs/aspeed/MAC.c b/arch/arm/cpu/arm926ejs/aspeed/MAC.c new file mode 100644 index 0000000..b4182f5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/MAC.c @@ -0,0 +1,2083 @@ +/*
+ * 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
+ */
+#define MAC_C
+static const char ThisFile[] = "MAC.c";
+
+#include "SWFUNC.H"
+
+#ifdef SLT_UBOOT
+ #include <common.h>
+ #include <command.h>
+ #include "COMMINF.H"
+ #include "STDUBOOT.H"
+#endif
+#ifdef SLT_DOS
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <conio.h>
+ #include <string.h>
+ #include "COMMINF.H"
+#endif
+
+#include "MAC.H"
+
+double Avg_frame_len;
+ULONG Check_Des_Val;
+ULONG wp_fir;
+ULONG wp;
+ULONG FRAME_LEN_Cur;
+ULONG gdata;
+ULONG CheckDesFail_DesNum;
+ULONG VGAMode;
+ULONG SCU_1ch_old;
+ULONG SCU_0ch_old;
+ULONG SCU_48h_default;
+ULONG SCU_2ch_old;
+ULONG SCU_80h_old;
+ULONG SCU_74h_old;
+ULONG SCU_a4h_old;
+ULONG SCU_88h_old;
+ULONG WDT_0ch_old;
+ULONG SCU_04h_mix;
+ULONG SCU_04h_old;
+ULONG WDT_2ch_old;
+char SCU_oldvld = 0;
+
+#ifdef SLT_UBOOT
+#else
+ static double timeused;
+#endif
+// -------------------------------------------------------------
+
+void Debug_delay (void) {
+ #ifdef DbgPrn_Enable_Debug_delay
+ GET_CAHR();
+ #endif
+}
+
+
+
+
+void dump_mac_ROreg (void) {
+ DELAY(Delay_MACDump);
+ printf("\n");
+ printf("[MAC-H] ROReg A0h~ACh: %08lx %08lx %08lx %08lx\n", ReadSOC_DD(H_MAC_BASE+0xA0), ReadSOC_DD(H_MAC_BASE+0xA4), ReadSOC_DD(H_MAC_BASE+0xA8), ReadSOC_DD(H_MAC_BASE+0xAC));
+ printf("[MAC-H] ROReg B0h~BCh: %08lx %08lx %08lx %08lx\n", ReadSOC_DD(H_MAC_BASE+0xB0), ReadSOC_DD(H_MAC_BASE+0xB4), ReadSOC_DD(H_MAC_BASE+0xB8), ReadSOC_DD(H_MAC_BASE+0xBC));
+ printf("[MAC-H] ROReg C0h~C8h: %08lx %08lx %08lx \n", ReadSOC_DD(H_MAC_BASE+0xC0), ReadSOC_DD(H_MAC_BASE+0xC4), ReadSOC_DD(H_MAC_BASE+0xC8));
+}
+
+//------------------------------------------------------------
+// SCU
+//------------------------------------------------------------
+void recov_scu (void) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("recov_scu\n");
+ Debug_delay();
+ #endif
+
+ //MAC
+ WriteSOC_DD( H_MAC_BASE + 0x08, MAC_08h_old );
+ WriteSOC_DD( H_MAC_BASE + 0x0c, MAC_0ch_old );
+ WriteSOC_DD( H_MAC_BASE + 0x40, MAC_40h_old );
+
+ //SCU
+ WriteSOC_DD( SCU_BASE + 0x04, SCU_04h_old );
+ WriteSOC_DD( SCU_BASE + 0x08, SCU_08h_old );
+ WriteSOC_DD( SCU_BASE + 0x0c, SCU_0ch_old );
+ WriteSOC_DD( SCU_BASE + 0x1c, SCU_1ch_old );
+ WriteSOC_DD( SCU_BASE + 0x2c, SCU_2ch_old );
+ WriteSOC_DD( SCU_BASE + 0x48, SCU_48h_old );
+// WriteSOC_DD( SCU_BASE + 0x70, SCU_70h_old );
+ WriteSOC_DD( SCU_BASE + 0x74, SCU_74h_old );
+ WriteSOC_DD( SCU_BASE + 0x7c, SCU_7ch_old );
+ WriteSOC_DD( SCU_BASE + 0x80, SCU_80h_old );
+ WriteSOC_DD( SCU_BASE + 0x88, SCU_88h_old );
+ WriteSOC_DD( SCU_BASE + 0x90, SCU_90h_old );
+ WriteSOC_DD( SCU_BASE + 0xa4, SCU_a4h_old );
+ WriteSOC_DD( SCU_BASE + 0xac, SCU_ach_old );
+ #ifdef AST1010_IOMAP
+ WriteSOC_DD( SCU_BASE + 0x11C, SCU_11Ch_old );
+ #endif
+
+ //WDT
+ #ifdef AST1010_IOMAP
+ #else
+ // WriteSOC_DD(0x1e78500c, WDT_0ch_old);
+ // WriteSOC_DD(0x1e78502c, WDT_2ch_old);
+ #endif
+
+ if ( ASTChipType == 3 ) {
+ if ( SCU_f0h_old & 0x01 ) WriteSOC_DD( SCU_BASE + 0xf0, 0xAEED0001 ); //Enable MAC34
+ if ( SCU_f0h_old & 0x02 ) WriteSOC_DD( SCU_BASE + 0xf0, 0x2000DEEA ); //Enable Decode
+ if ( SCU_f0h_old & 0x04 ) WriteSOC_DD( SCU_BASE + 0xf0, 0xA0E0E0D3 ); //Enable I2S
+ if ( SCU_f0h_old & 0x08 ) WriteSOC_DD( SCU_BASE + 0xf0, 0x4D0E0E0A ); //Enable PCI Host
+ if ( SCU_f0h_old & 0x10 ) WriteSOC_DD( SCU_BASE + 0xf0, 0x10ADDEED ); //Enable IR
+ if ( SCU_f0h_old & 0x20 ) WriteSOC_DD( SCU_BASE + 0xf0, 0x66559959 ); //Enabel Buffer Merge
+ if ( SCU_f0h_old & 0x40 ) WriteSOC_DD( SCU_BASE + 0xf0, 0x68961A33 ); //Enable PS2 IO
+ if ( SCU_f0h_old & 0x80 ) WriteSOC_DD( SCU_BASE + 0xf0, 0x68971A33 ); //Enable PS2 IO
+ }
+} // End void recov_scu (void)
+
+void read_scu (void) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("read_scu\n");
+ Debug_delay();
+ #endif
+
+ if (!SCU_oldvld) {
+ //SCU
+ SCU_04h_old = ReadSOC_DD( SCU_BASE + 0x04 );
+ SCU_08h_old = ReadSOC_DD( SCU_BASE + 0x08 );
+ SCU_0ch_old = ReadSOC_DD( SCU_BASE + 0x0c );
+ SCU_1ch_old = ReadSOC_DD( SCU_BASE + 0x1c );
+ SCU_2ch_old = ReadSOC_DD( SCU_BASE + 0x2c );
+ SCU_48h_old = ReadSOC_DD( SCU_BASE + 0x48 );
+ SCU_70h_old = ReadSOC_DD( SCU_BASE + 0x70 );
+ SCU_74h_old = ReadSOC_DD( SCU_BASE + 0x74 );
+ SCU_7ch_old = ReadSOC_DD( SCU_BASE + 0x7c );
+ SCU_80h_old = ReadSOC_DD( SCU_BASE + 0x80 );
+ SCU_88h_old = ReadSOC_DD( SCU_BASE + 0x88 );
+ SCU_90h_old = ReadSOC_DD( SCU_BASE + 0x90 );
+ SCU_a4h_old = ReadSOC_DD( SCU_BASE + 0xa4 );
+ SCU_ach_old = ReadSOC_DD( SCU_BASE + 0xac );
+ SCU_f0h_old = ReadSOC_DD( SCU_BASE + 0xf0 );
+ #ifdef AST1010_IOMAP
+ SCU_11Ch_old = ReadSOC_DD( SCU_BASE + 0x11C );
+ #endif
+
+ //WDT
+ #ifdef AST1010_IOMAP
+ #else
+ WDT_0ch_old = ReadSOC_DD( 0x1e78500c );
+ WDT_2ch_old = ReadSOC_DD( 0x1e78502c );
+ #endif
+
+ SCU_oldvld = 1;
+ } // End if (!SCU_oldvld)
+} // End read_scu()
+
+void Setting_scu (void)
+{
+ //SCU
+ if (AST1010) {
+ do {
+ WriteSOC_DD( SCU_BASE + 0x00 , 0x1688a8a8);
+ #ifndef SLT_UBOOT
+ WriteSOC_DD( SCU_BASE + 0x70 , SCU_70h_old & 0xfffffffe); // Disable CPU
+ #endif
+ } while ( ReadSOC_DD( SCU_BASE + 0x00 ) != 0x1 );
+
+ #if( AST1010_IOMAP == 1)
+ WriteSOC_DD( SCU_BASE + 0x11C, 0x00000000); // Disable Cache functionn
+ #endif
+ }
+ else {
+ do {
+ WriteSOC_DD( SCU_BASE + 0x00, 0x1688a8a8);
+ #ifndef SLT_UBOOT
+ WriteSOC_DD( SCU_BASE + 0x70, SCU_70h_old | 0x3 ); // Disable CPU
+ #endif
+ } while ( ReadSOC_DD( SCU_BASE + 0x00 ) != 0x1 );
+ } // End if (AST1010)
+
+ //WDT
+ #ifdef AST1010_IOMAP
+ #else
+ WriteSOC_DD( 0x1e78500c, WDT_0ch_old & 0xfffffffc );
+ WriteSOC_DD( 0x1e78502c, WDT_2ch_old & 0xfffffffc );
+ #endif
+}
+
+//------------------------------------------------------------
+void init_scu1 (void) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("init_scu1\n");
+ Debug_delay();
+ #endif
+
+ if (AST3200) {
+ WriteSOC_DD( SCU_BASE + 0x0c, (SCU_0ch_old & 0xffefffff) );//Clock Stop Control
+ }
+ else if (AST1010) {
+ WriteSOC_DD( SCU_BASE + 0x0c, ( SCU_0ch_old & 0xffffffbf ) );//Clock Stop Control
+ WriteSOC_DD( SCU_BASE + 0x88, ((SCU_88h_old & 0x003fffff ) | 0xffc00000) );//Multi-function Pin Control
+ }
+ else if (AST2300) {
+#ifdef Enable_BufMerge
+ WriteSOC_DD( SCU_BASE + 0xf0, 0x66559959 );//MAC buffer merge
+#endif
+
+#ifdef Enable_AST2300_Int125MHz
+ SCU_48h_mix = (SCU_48h_old & 0xf0000000) | 0x80000000;
+// WriteSOC_DD( SCU_BASE + 0xf0, 0xa0e0e0d3 );//Enable I2S
+// WriteSOC_DD( SCU_BASE + 0x04, SCU_04h_old & 0xfffdffff );//Rst(Enable I2S)
+//
+//// WriteSOC_DD( 0x1e6e5020, ReadSOC_DD(0x1e6e5020) | 0x00010000 );//P_I2SPLLAdjEnable
+// WriteSOC_DD( 0x1e6e5020, ReadSOC_DD(0x1e6e5020) | 0x00000000 );//P_I2SPLLAdjEnable
+// WriteSOC_DD( 0x1e6e5024, 0x00000175 );//P_I2SPLLAdjCnt
+
+// WriteSOC_DD( SCU_BASE + 0x1c, 0x0000a51a );//124800000(24MHz)
+// WriteSOC_DD( SCU_BASE + 0x1c, 0x0000a92f );//125333333(24MHz)
+// WriteSOC_DD( SCU_BASE + 0x1c, 0x0000587d );//125000000(24MHz)
+ WriteSOC_DD( SCU_BASE + 0x1c, 0x00006c7d );//125000000(24MHz)
+ WriteSOC_DD( SCU_BASE + 0x2c, 0x00300000 | (SCU_2ch_old & 0xffcfffef) );//D-PLL assigned to VGA, D2-PLL assigned to I2S.
+ WriteSOC_DD( SCU_BASE + 0x48, 0x80000000 | SCU_48h_old );//125MHz come from I2SPLL
+#else
+ SCU_48h_mix = (SCU_48h_old & 0xf0000000);
+#endif
+ switch (SelectMAC) {
+ case 0 :
+ WriteSOC_DD( SCU_BASE + 0x88, (SCU_88h_old & 0x3fffffff) | 0xc0000000 );//[31]MAC1 MDIO, [30]MAC1 MDC
+ break;
+ case 1 :
+ WriteSOC_DD( SCU_BASE + 0x90, (SCU_90h_old & 0xfffffffb) | 0x00000004 );//[2 ]MAC2 MDC/MDIO
+ break;
+ case 2 :
+ case 3 :
+ default : break;
+ }
+
+ WriteSOC_DD(SCU_BASE+0x0c, (SCU_0ch_old & 0xff0fffff) );//Clock Stop Control
+// WriteSOC_DD(SCU_BASE+0x80, (SCU_80h_old & 0xfffffff0) | 0x0000000f);//MAC1LINK/MAC2LINK
+ }
+ else {
+ switch (SelectMAC) {
+ case 0 :
+// WriteSOC_DD(SCU_BASE+0x74, (SCU_74h_old & 0xfdffffff) | 0x02000000);//[25]MAC1 PHYLINK
+ break;
+ case 1 :
+ if (MAC2_RMII) {
+// WriteSOC_DD(SCU_BASE+0x74, (SCU_74h_old & 0xfbefffff) | 0x04100000);//[26]MAC2 PHYLINK, [21]MAC2 MII, [20]MAC2 MDC/MDIO
+ WriteSOC_DD(SCU_BASE+0x74, (SCU_74h_old & 0xffefffff) | 0x00100000);//[26]MAC2 PHYLINK, [21]MAC2 MII, [20]MAC2 MDC/MDIO
+ } else {
+// WriteSOC_DD(SCU_BASE+0x74, (SCU_74h_old & 0xfbcfffff) | 0x04300000);//[26]MAC2 PHYLINK, [21]MAC2 MII, [20]MAC2 MDC/MDIO
+ WriteSOC_DD(SCU_BASE+0x74, (SCU_74h_old & 0xffcfffff) | 0x00300000);//[26]MAC2 PHYLINK, [21]MAC2 MII, [20]MAC2 MDC/MDIO
+ }
+ break;
+ default : break;
+ } // End switch (SelectMAC)
+ } // End if (AST3200)
+} // End void init_scu1 (void)
+
+//------------------------------------------------------------
+void init_scu_macrst (void) {
+
+#ifdef Enable_AST2300_Int125MHz
+ if (ASTChipType == 3) {
+ SCU_04h_mix = SCU_04h_old & 0xfffdffff;
+ } else {
+ SCU_04h_mix = SCU_04h_old;
+ }
+#else
+ SCU_04h_mix = SCU_04h_old;
+#endif
+
+ WriteSOC_DD ( SCU_BASE + 0x04, (SCU_04h_mix & ~SCU_04h) | SCU_04h);//Rst
+ DELAY(Delay_SCU);
+ WriteSOC_DD ( SCU_BASE + 0x04, (SCU_04h_mix & ~SCU_04h) );//Enable Engine
+// DELAY(Delay_SCU);
+} // End void init_scu_macrst (void)
+
+//------------------------------------------------------------
+void init_scu2 (void) {
+
+#ifdef SCU_74h
+ #ifdef DbgPrn_FuncHeader
+ printf ("init_scu2\n");
+ Debug_delay();
+ #endif
+
+ WriteSOC_DD( SCU_BASE + 0x74, SCU_74h_old | SCU_74h );//PinMux
+ delay(Delay_SCU);
+#endif
+
+} // End void init_scu2 (void)
+
+//------------------------------------------------------------
+void init_scu3 (void) {
+
+#ifdef SCU_74h
+ #ifdef DbgPrn_FuncHeader
+ printf ("init_scu3\n");
+ Debug_delay();
+ #endif
+
+ WriteSOC_DD( SCU_BASE + 0x74, SCU_74h_old | (SCU_74h & 0xffefffff) );//PinMux
+ delay(Delay_SCU);
+#endif
+
+} // End void init_scu3 (void)
+
+//------------------------------------------------------------
+// MAC
+//------------------------------------------------------------
+void init_mac (ULONG base, ULONG tdexbase, ULONG rdexbase) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("init_mac\n");
+ Debug_delay();
+ #endif
+
+#ifdef Enable_MAC_SWRst
+ WriteSOC_DD( base + 0x50, 0x80000000 | MAC_50h | MAC_50h_Speed);
+// WriteSOC_DD( base + 0x50, 0x80000000);
+
+ while (0x80000000 & ReadSOC_DD(base+0x50)) {
+//printf(".");
+ DELAY(Delay_MACRst);
+ }
+ DELAY(Delay_MACRst);
+#endif
+
+ WriteSOC_DD( base + 0x20, (tdexbase + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730
+ WriteSOC_DD( base + 0x24, (rdexbase + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730
+
+#ifdef MAC_30h
+ WriteSOC_DD( base + 0x30, MAC_30h);//Int Thr/Cnt
+#endif
+
+#ifdef MAC_34h
+ WriteSOC_DD( base + 0x34, MAC_34h);//Poll Cnt
+#endif
+
+#ifdef MAC_38h
+ WriteSOC_DD( base + 0x38, MAC_38h);
+#endif
+
+#ifdef MAC_40h
+ if (Enable_MACLoopback) {
+ if (AST2300_NewMDIO) WriteSOC_DD( base + 0x40, MAC_40h | 0x80000000);
+ else WriteSOC_DD( base + 0x40, MAC_40h);
+ }
+#endif
+
+#ifdef MAC_48h
+ WriteSOC_DD( base + 0x48, MAC_48h);
+#endif
+
+ if ( ModeSwitch == MODE_NSCI )
+ WriteSOC_DD( base + 0x4c, NCSI_RxDMA_PakSize);
+ else
+ WriteSOC_DD( base + 0x4c, DMA_PakSize);
+
+ WriteSOC_DD( base + 0x50, MAC_50h | MAC_50h_Speed | 0xf);
+ DELAY(Delay_MACRst);
+} // End void init_mac (ULONG base, ULONG tdexbase, ULONG rdexbase)
+
+//------------------------------------------------------------
+// Basic
+//------------------------------------------------------------
+void FPri_RegValue (BYTE option) {
+
+#ifdef SLT_UBOOT
+#else
+ time_t timecur;
+#endif
+
+ FILE_VAR
+
+ GET_OBJ( option )
+
+ PRINT(OUT_OBJ "[SCU] 04:%08lx 08:%08lx 0c:%08lx 48:%08lx\n", SCU_04h_old, SCU_08h_old, SCU_0ch_old, SCU_48h_old);
+ PRINT(OUT_OBJ "[SCU] 70:%08lx 74:%08lx 7c:%08lx\n", SCU_70h_old, SCU_74h_old, SCU_7ch_old);
+ PRINT(OUT_OBJ "[SCU] 80:%08lx 88:%08lx 90:%08lx f0:%08lx\n", SCU_80h_old, SCU_88h_old, SCU_90h_old, SCU_f0h_old);
+ PRINT(OUT_OBJ "[SCU] a4:%08lx ac:%08lx\n", SCU_a4h_old, SCU_ach_old);
+ PRINT(OUT_OBJ "[WDT] 0c:%08lx 2c:%08lx\n", WDT_0ch_old, WDT_2ch_old);
+ PRINT(OUT_OBJ "[MAC] 08:%08lx 0c:%08lx\n", MAC_08h_old, MAC_0ch_old);
+ PRINT(OUT_OBJ "[MAC] A0|%08lx %08lx %08lx %08lx\n", ReadSOC_DD( MAC_PHYBASE + 0xa0), ReadSOC_DD( MAC_PHYBASE + 0xa4 ), ReadSOC_DD( MAC_PHYBASE + 0xa8 ), ReadSOC_DD(MAC_PHYBASE + 0xac ) );
+ PRINT(OUT_OBJ "[MAC] B0|%08lx %08lx %08lx %08lx\n", ReadSOC_DD( MAC_PHYBASE + 0xb0), ReadSOC_DD( MAC_PHYBASE + 0xb4 ), ReadSOC_DD( MAC_PHYBASE + 0xb8 ), ReadSOC_DD(MAC_PHYBASE + 0xbc ) );
+ PRINT(OUT_OBJ "[MAC] C0|%08lx %08lx %08lx\n", ReadSOC_DD( MAC_PHYBASE + 0xc0), ReadSOC_DD( MAC_PHYBASE + 0xc4 ), ReadSOC_DD( MAC_PHYBASE + 0xc8 ));
+
+#ifdef SLT_UBOOT
+#else
+ fprintf(fp, "Time: %s", ctime(×tart));
+ time(&timecur);
+ fprintf(fp, "----> %s", ctime(&timecur));
+#endif
+} // End void FPri_RegValue (BYTE *fp)
+
+//------------------------------------------------------------
+void FPri_End (BYTE option) {
+
+ FILE_VAR
+
+ GET_OBJ( option )
+
+ if ( !RxDataEnable ) {
+ }
+ else if ( Err_Flag ) {
+ PRINT(OUT_OBJ " \n----> fail !!!\n");
+ } else {
+ PRINT(OUT_OBJ " \n----> All Pass !!!\n");
+ }
+
+ if ( ModeSwitch == MODE_DEDICATED ) {
+ if (PHY_ADR_arg != PHY_ADR)
+ PRINT(OUT_OBJ "\n[Warning] PHY Address change from %d to %d !!!\n", PHY_ADR_arg, PHY_ADR);
+ }
+
+ if ( AST1010 ) {
+ Dat_ULONG = (SCU_ach_old >> 12) & 0xf;
+ if (Dat_ULONG) {
+ PRINT(OUT_OBJ "\n[Warning] SCUAC[15:12] == 0x%02lx is not the suggestion value 0.\n", Dat_ULONG);
+ PRINT(OUT_OBJ " This change at this platform must been proven again by the ASPEED.\n");
+ }
+
+ SCU_48h_default = SCU_48h_AST1010 & 0x01000f00;
+ if ((SCU_48h_old != SCU_48h_default)) {
+ PRINT(OUT_OBJ "\n[Warning] SCU48 == 0x%08lx is not the suggestion value 0x%08lx.\n", SCU_48h_old, SCU_48h_default);
+ PRINT(OUT_OBJ " This change at this platform must been proven again by the ASPEED.\n");
+ }
+ }
+ else if ( AST2300 ) {
+ if ( AST2400 ) {
+ Dat_ULONG = (SCU_90h_old >> 8) & 0xf;
+ if (Dat_ULONG) {
+ PRINT(OUT_OBJ "\n[Warning] SCU90[11: 8] == 0x%02lx is not the suggestion value 0.\n", Dat_ULONG);
+ PRINT(OUT_OBJ " This change at this platform must been proven again by the ASPEED.\n");
+ }
+ }
+ else {
+ Dat_ULONG = (SCU_90h_old >> 8) & 0xff;
+ if (Dat_ULONG) {
+ PRINT(OUT_OBJ "\n[Warning] SCU90[15: 8] == 0x%02lx is not the suggestion value 0.\n", Dat_ULONG);
+ PRINT(OUT_OBJ " This change at this platform must been proven again by the ASPEED.\n");
+ }
+ }
+
+ if (Enable_MAC34) SCU_48h_default = SCU_48h_AST2300;
+ else SCU_48h_default = SCU_48h_AST2300 & 0x0300ffff;
+
+ if ((SCU_48h_old != SCU_48h_default)) {
+ PRINT(OUT_OBJ "\n[Warning] SCU48 == 0x%08lx is not the suggestion value 0x%08lx.\n", SCU_48h_old, SCU_48h_default);
+ PRINT(OUT_OBJ " This change at this platform must been proven again by the ASPEED.\n");
+ }
+ } // End if ( AST1010 )
+
+ if ( ModeSwitch == MODE_NSCI ) {
+ PRINT(OUT_OBJ "\n[Arg] %d %d %d %d %d %ld (%s)\n", GRun_Mode, PackageTolNum, ChannelTolNum, TestMode, IOTimingBund, (ARPNumCnt| (ULONG)PrintNCSIEn), ASTChipName);
+
+ switch (NCSI_Cap_SLT.PCI_DID_VID) {
+ case PCI_DID_VID_Intel_82574L : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82574L \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82575_10d6 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82575 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82575_10a7 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82575 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82575_10a9 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82575 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82576_10c9 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82576 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82576_10e6 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82576 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82576_10e7 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82576 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82576_10e8 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82576 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82576_1518 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82576 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82576_1526 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82576 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82576_150a : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82576 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82576_150d : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82576 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82599_10fb : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82599 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_82599_1557 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel 82599 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_I350_1521 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel I350 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_I350_1523 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel I350 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_I210 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel I210 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Intel_X540 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel X540 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Broadcom_BCM5718 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Broadcom BCM5718 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Broadcom_BCM5720 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Broadcom BCM5720 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Broadcom_BCM5725 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Broadcom BCM5725 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+// case PCI_DID_VID_Broadcom_BCM57810 : PRINT( OUT_OBJ "[NC]%08x %08x: Broadcom BCM57810 \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case PCI_DID_VID_Mellanox_ConnectX_3 : PRINT( OUT_OBJ "[NC]%08lx %08lx: Mellanox ConnectX-3\n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ default :
+ switch (NCSI_Cap_SLT.ManufacturerID) {
+ case ManufacturerID_Intel : PRINT( OUT_OBJ "[NC]%08lx %08lx: Intel \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case ManufacturerID_Broadcom : PRINT( OUT_OBJ "[NC]%08lx %08lx: Broadcom\n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ case ManufacturerID_Mellanox : PRINT( OUT_OBJ "[NC]%08lx %08lx: Mellanox\n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID ); break;
+ default : PRINT(OUT_OBJ "[NC]%08lx %08lx \n", NCSI_Cap_SLT.ManufacturerID, NCSI_Cap_SLT.PCI_DID_VID); break;
+ } // End switch (NCSI_Cap_SLT.ManufacturerID)
+ } // End switch (NCSI_Cap_SLT.PCI_DID_VID)
+ }
+ else {
+ if (LOOP_INFINI) PRINT(OUT_OBJ "\n[Arg] %d %d %d # %d %d %d %lx (%s)[%d %d %d]\n" , GRun_Mode, GSpeed, GCtrl, TestMode, PHY_ADR_arg, IOTimingBund, UserDVal, ASTChipName, Loop_rl[0], Loop_rl[1], Loop_rl[2]);
+ else PRINT(OUT_OBJ "\n[Arg] %d %d %d %ld %d %d %d %lx (%s)[%d %d %d]\n", GRun_Mode, GSpeed, GCtrl, LOOP_MAX_arg, TestMode, PHY_ADR_arg, IOTimingBund, UserDVal, ASTChipName, Loop_rl[0], Loop_rl[1], Loop_rl[2]);
+
+ PRINT(OUT_OBJ "[PHY] Adr:%d ID2:%04lx ID3:%04lx (%s)\n", PHY_ADR, PHY_ID2, PHY_ID3, PHYName);
+ } // End if ( ModeSwitch == MODE_NSCI )
+
+#ifdef SUPPORT_PHY_LAN9303
+ PRINT(OUT_OBJ "[Ver II] %s (for LAN9303 with I2C%d)\n", version_name, LAN9303_I2C_BUSNUM);
+#else
+ PRINT(OUT_OBJ "[Ver II] %s\n", version_name);
+#endif
+} // End void FPri_End (BYTE option)
+
+//------------------------------------------------------------
+void FPri_ErrFlag (BYTE option) {
+
+ FILE_VAR
+
+ GET_OBJ( option )
+
+ if (Err_Flag && Err_Flag_PrintEn) {
+ PRINT(OUT_OBJ "\n\n");
+//fprintf(fp, "Err_Flag: %x\n\n", Err_Flag);
+
+ if ( Err_Flag & Err_PHY_Type ) PRINT( OUT_OBJ "[Err] Unidentifiable PHY \n" );
+ if ( Err_Flag & Err_MALLOC_FrmSize ) PRINT( OUT_OBJ "[Err] Malloc fail at frame size buffer \n" );
+ if ( Err_Flag & Err_MALLOC_LastWP ) PRINT( OUT_OBJ "[Err] Malloc fail at last WP buffer \n" );
+ if ( Err_Flag & Err_Check_Buf_Data ) PRINT( OUT_OBJ "[Err] Received data mismatch \n" );
+ if ( Err_Flag & Err_NCSI_Check_TxOwnTimeOut ) PRINT( OUT_OBJ "[Err] Time out of checking Tx owner bit in NCSI packet \n" );
+ if ( Err_Flag & Err_NCSI_Check_RxOwnTimeOut ) PRINT( OUT_OBJ "[Err] Time out of checking Rx owner bit in NCSI packet \n" );
+ if ( Err_Flag & Err_NCSI_Check_ARPOwnTimeOut) PRINT( OUT_OBJ "[Err] Time out of checking ARP owner bit in NCSI packet \n" );
+ if ( Err_Flag & Err_NCSI_No_PHY ) PRINT( OUT_OBJ "[Err] Can not find NCSI PHY \n" );
+ if ( Err_Flag & Err_NCSI_Channel_Num ) PRINT( OUT_OBJ "[Err] NCSI Channel Number Mismatch \n" );
+ if ( Err_Flag & Err_NCSI_Package_Num ) PRINT( OUT_OBJ "[Err] NCSI Package Number Mismatch \n" );
+ if ( Err_Flag & Err_PHY_TimeOut ) PRINT( OUT_OBJ "[Err] Time out of read/write/reset PHY register \n" );
+ if ( Err_Flag & Err_RXBUF_UNAVA ) PRINT( OUT_OBJ "[Err] MAC00h[2]:Receiving buffer unavailable \n" );
+ if ( Err_Flag & Err_RPKT_LOST ) PRINT( OUT_OBJ "[Err] MAC00h[3]:Received packet lost due to RX FIFO full \n" );
+ if ( Err_Flag & Err_NPTXBUF_UNAVA ) PRINT( OUT_OBJ "[Err] MAC00h[6]:Normal priority transmit buffer unavailable \n" );
+ if ( Err_Flag & Err_TPKT_LOST ) PRINT( OUT_OBJ "[Err] MAC00h[7]:Packets transmitted to Ethernet lost \n" );
+ if ( Err_Flag & Err_DMABufNum ) PRINT( OUT_OBJ "[Err] DMA Buffer is not enough \n" );
+ if ( Err_Flag & Err_IOMargin ) PRINT( OUT_OBJ "[Err] IO timing margin is not enough \n" );
+
+ if ( Err_Flag & Err_MHCLK_Ratio ) {
+ if ( AST1010 ) {
+ PRINT(OUT_OBJ "[Err] Error setting of MAC AHB bus clock (SCU08[13:12]) \n");
+ Dat_ULONG = (SCU_08h_old >> 12) & 0x3;
+ PRINT(OUT_OBJ " SCU08[13:12] == 0x%01lx is not the suggestion value 0.\n", Dat_ULONG);
+ }
+ else {
+ PRINT(OUT_OBJ "[Err] Error setting of MAC AHB bus clock (SCU08[18:16]) \n");
+ Dat_ULONG = (SCU_08h_old >> 16) & 0x7;
+
+ if (MAC1_1GEn | MAC2_1GEn) {
+ PRINT(OUT_OBJ " SCU08[18:16] == 0x%01lx is not the suggestion value 2.\n", Dat_ULONG);
+ }
+ else {
+ PRINT(OUT_OBJ " SCU08[18:16] == 0x%01lx is not the suggestion value 4.\n", Dat_ULONG);
+ }
+ } // end if ( AST1010 )
+ } // End if ( Err_Flag & Err_MHCLK_Ratio )
+
+ if (Err_Flag & Err_IOMarginOUF ) {
+ PRINT(OUT_OBJ "[Err] IO timing testing range out of boundary\n");
+ if (Enable_RMII) {
+#ifdef Enable_Old_Style
+ PRINT(OUT_OBJ " (%d,%d): 1x%d [%d]x[%d:%d]\n", IOdly_out_reg_idx, IOdly_in_reg_idx, IOTimingBund, IOdly_out_reg_idx, IOdly_in_reg_idx - (IOTimingBund>>1), IOdly_in_reg_idx + (IOTimingBund>>1));
+#else
+ PRINT(OUT_OBJ " (%d,%d): %dx1 [%d:%d]x[%d]\n", IOdly_in_reg_idx, IOdly_out_reg_idx, IOTimingBund, IOdly_in_reg_idx - (IOTimingBund>>1), IOdly_in_reg_idx + (IOTimingBund>>1), IOdly_out_reg_idx);
+#endif
+ } else {
+#ifdef Enable_Old_Style
+ PRINT(OUT_OBJ " (%d,%d): %dx%d [%d:%d]x[%d:%d]\n", IOdly_out_reg_idx, IOdly_in_reg_idx, IOTimingBund, IOTimingBund, IOdly_out_reg_idx - (IOTimingBund>>1), IOdly_out_reg_idx + (IOTimingBund>>1), IOdly_in_reg_idx - (IOTimingBund>>1), IOdly_in_reg_idx + (IOTimingBund>>1));
+#else
+ PRINT(OUT_OBJ " (%d,%d): %dx%d [%d:%d]x[%d:%d]\n", IOdly_in_reg_idx, IOdly_out_reg_idx, IOTimingBund, IOTimingBund, IOdly_in_reg_idx - (IOTimingBund>>1), IOdly_in_reg_idx + (IOTimingBund>>1), IOdly_out_reg_idx - (IOTimingBund>>1), IOdly_out_reg_idx + (IOTimingBund>>1));
+#endif
+ }
+ } // End if (Err_Flag & Err_IOMarginOUF )
+
+ if (Err_Flag & Err_Check_Des ) {
+ PRINT(OUT_OBJ "[Err] Descriptor error\n");
+ if ( Check_Des_Val & Check_Des_TxOwnTimeOut ) PRINT( OUT_OBJ "[Des] Time out of checking Tx owner bit\n" );
+ if ( Check_Des_Val & Check_Des_RxOwnTimeOut ) PRINT( OUT_OBJ "[Des] Time out of checking Rx owner bit\n" );
+ if ( Check_Des_Val & Check_Des_RxErr ) PRINT( OUT_OBJ "[Des] Input signal RxErr \n" );
+ if ( Check_Des_Val & Check_Des_OddNibble ) PRINT( OUT_OBJ "[Des] Nibble bit happen \n" );
+ if ( Check_Des_Val & Check_Des_CRC ) PRINT( OUT_OBJ "[Des] CRC error of frame \n" );
+ if ( Check_Des_Val & Check_Des_RxFIFOFull ) PRINT( OUT_OBJ "[Des] Rx FIFO full \n" );
+ if ( Check_Des_Val & Check_Des_FrameLen ) PRINT( OUT_OBJ "[Des] Frame length mismatch \n" );
+ } // End if (Err_Flag & Err_Check_Des )
+
+ if (Err_Flag & Err_MACMode ) {
+ PRINT(OUT_OBJ "[Err] MAC interface mode mismatch\n");
+ if ( AST1010 ) {
+ }
+ else if (AST2300) {
+ switch (MAC_Mode) {
+ case 0 : PRINT( OUT_OBJ " SCU70h[7:6] == 0: [MAC#1] RMII [MAC#2] RMII \n" ); break;
+ case 1 : PRINT( OUT_OBJ " SCU70h[7:6] == 1: [MAC#1] RGMII [MAC#2] RMII \n" ); break;
+ case 2 : PRINT( OUT_OBJ " SCU70h[7:6] == 2: [MAC#1] RMII [MAC#2] RGMII\n" ); break;
+ case 3 : PRINT( OUT_OBJ " SCU70h[7:6] == 3: [MAC#1] RGMII [MAC#2] RGMII\n" ); break;
+ }
+ }
+ else {
+ switch (MAC_Mode) {
+ case 0 : PRINT( OUT_OBJ " SCU70h[8:6] == 000: [MAC#1] GMII \n" ); break;
+ case 1 : PRINT( OUT_OBJ " SCU70h[8:6] == 001: [MAC#1] MII [MAC#2] MII \n" ); break;
+ case 2 : PRINT( OUT_OBJ " SCU70h[8:6] == 010: [MAC#1] RMII [MAC#2] MII \n" ); break;
+ case 3 : PRINT( OUT_OBJ " SCU70h[8:6] == 011: [MAC#1] MII \n" ); break;
+ case 4 : PRINT( OUT_OBJ " SCU70h[8:6] == 100: [MAC#1] RMII \n" ); break;
+ case 5 : PRINT( OUT_OBJ " SCU70h[8:6] == 101: Reserved \n" ); break;
+ case 6 : PRINT( OUT_OBJ " SCU70h[8:6] == 110: [MAC#1] RMII [MAC#2] RMII\n" ); break;
+ case 7 : PRINT( OUT_OBJ " SCU70h[8:6] == 111: Disable MAC \n" ); break;
+ }
+ } // End if ( AST1010 )
+ } // End if (Err_Flag & Err_MACMode )
+
+ if ( ModeSwitch == MODE_NSCI ) {
+ if (Err_Flag & Err_NCSI_LinkFail ) {
+ PRINT(OUT_OBJ "[Err] NCSI packet retry number over flows when find channel\n");
+
+ if (NCSI_LinkFail_Val & NCSI_LinkFail_Get_Version_ID ) PRINT(OUT_OBJ "[NCSI] Time out when Get Version ID \n");
+ if (NCSI_LinkFail_Val & NCSI_LinkFail_Get_Capabilities ) PRINT(OUT_OBJ "[NCSI] Time out when Get Capabilities \n");
+ if (NCSI_LinkFail_Val & NCSI_LinkFail_Select_Active_Package ) PRINT(OUT_OBJ "[NCSI] Time out when Select Active Package \n");
+ if (NCSI_LinkFail_Val & NCSI_LinkFail_Enable_Set_MAC_Address ) PRINT(OUT_OBJ "[NCSI] Time out when Enable Set MAC Address \n");
+ if (NCSI_LinkFail_Val & NCSI_LinkFail_Enable_Broadcast_Filter) PRINT(OUT_OBJ "[NCSI] Time out when Enable Broadcast Filter\n");
+ if (NCSI_LinkFail_Val & NCSI_LinkFail_Enable_Network_TX ) PRINT(OUT_OBJ "[NCSI] Time out when Enable Network TX \n");
+ if (NCSI_LinkFail_Val & NCSI_LinkFail_Enable_Channel ) PRINT(OUT_OBJ "[NCSI] Time out when Enable Channel \n");
+ if (NCSI_LinkFail_Val & NCSI_LinkFail_Disable_Network_TX ) PRINT(OUT_OBJ "[NCSI] Time out when Disable Network TX \n");
+ if (NCSI_LinkFail_Val & NCSI_LinkFail_Disable_Channel ) PRINT(OUT_OBJ "[NCSI] Time out when Disable Channel \n");
+ }
+
+ if (Err_Flag & Err_NCSI_Channel_Num ) PRINT(OUT_OBJ "[NCSI] Channel number expected: %d, real: %d\n", ChannelTolNum, number_chl);
+ if (Err_Flag & Err_NCSI_Package_Num ) PRINT(OUT_OBJ "[NCSI] Peckage number expected: %d, real: %d\n", PackageTolNum, number_pak);
+ } // End if ( ModeSwitch == MODE_NSCI )
+ } // End if (Err_Flag && Err_Flag_PrintEn)
+} // End void FPri_ErrFlag (BYTE option)
+
+//------------------------------------------------------------
+void Finish_Close (void) {
+
+ if (SCU_oldvld)
+ recov_scu();
+
+#ifdef SLT_DOS
+ if (fp_io && IOTiming)
+ fclose(fp_io);
+
+ if (fp_log)
+ fclose(fp_log);
+#endif
+} // End void Finish_Close (void)
+
+//------------------------------------------------------------
+char Finish_Check (int value) {
+ ULONG temp;
+ CHAR i = 0;
+
+#ifdef Disable_VGA
+ if (VGAModeVld) {
+ outp(0x3d4, 0x17);
+ outp(0x3d5, VGAMode);
+ }
+#endif
+ #ifdef DbgPrn_FuncHeader
+ printf ("Finish_Check\n");
+ Debug_delay();
+ #endif
+
+ if ( FRAME_LEN )
+ free(FRAME_LEN);
+
+ if ( wp_lst )
+ free(wp_lst );
+
+ Err_Flag = Err_Flag | value;
+
+ if ( DbgPrn_ErrFlg )
+ printf ("\nErr_Flag: [%08lx]\n", Err_Flag);
+
+ if ( !BurstEnable )
+ FPri_ErrFlag( FP_LOG );
+
+ if ( IOTiming )
+ FPri_ErrFlag( FP_IO );
+
+ FPri_ErrFlag( STD_OUT );
+
+ if ( !BurstEnable )
+ FPri_End( FP_LOG );
+
+ if ( IOTiming )
+ FPri_End( FP_IO );
+
+ FPri_End( STD_OUT );
+
+
+ if ( !BurstEnable ) FPri_RegValue( FP_LOG );
+ if ( IOTiming ) FPri_RegValue( FP_IO );
+
+ Finish_Close();
+
+ // 20140325
+ temp = ReadSOC_DD( 0x1e6e2040 );
+ if ( ModeSwitch == MODE_NSCI )
+ {
+ if ( SelectMAC == 0 )
+ i = 17;
+ else
+ i = 16;
+ }
+ else
+ {
+ if ( SelectMAC == 0 )
+ i = 19;
+ else
+ i = 18;
+ }
+ WriteSOC_DD( 0x1e6e2040, (temp | (1 << i)) );
+
+
+ if ( Err_Flag )
+ {
+ // Fail
+ return( 1 );
+ }
+ else
+ {
+ // Pass
+ return( 0 );
+ }
+} // End char Finish_Check (int value)
+
+//------------------------------------------------------------
+int FindErr (int value) {
+ Err_Flag = Err_Flag | value;
+
+ if ( DbgPrn_ErrFlg )
+ printf ("\nErr_Flag: [%08lx]\n", Err_Flag);
+
+ return(1);
+}
+
+//------------------------------------------------------------
+int FindErr_Des (int value) {
+ Check_Des_Val = Check_Des_Val | value;
+ Err_Flag = Err_Flag | Err_Check_Des;
+ if ( DbgPrn_ErrFlg )
+ printf ("\nErr_Flag: [%08lx] Check_Des_Val: [%08lx]\n", Err_Flag, Check_Des_Val);
+
+ return(1);
+}
+
+//------------------------------------------------------------
+// Get and Check status of Interrupt
+//------------------------------------------------------------
+int check_int ( char *type ) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("check_int : %d\n", Loop);
+ Debug_delay();
+ #endif
+
+ Dat_ULONG = ReadSOC_DD( H_MAC_BASE + 0x00 );//Interrupt Status
+#ifdef SLT_DOS
+#ifdef CheckRxbufUNAVA
+ if ( Dat_ULONG & 0x00000004 ) {
+ fprintf(fp_log, "[%sIntStatus] Receiving buffer unavailable : %08lx [loop:%d]\n", type, Dat_ULONG, Loop);
+ FindErr( Err_RXBUF_UNAVA );
+ }
+#endif
+
+#ifdef CheckRPktLost
+ if ( Dat_ULONG & 0x00000008 ) {
+ fprintf(fp_log, "[%sIntStatus] Received packet lost due to RX FIFO full : %08lx [loop:%d]\n", type, Dat_ULONG, Loop);
+ FindErr( Err_RPKT_LOST );
+ }
+#endif
+
+#ifdef CheckNPTxbufUNAVA
+ if ( Dat_ULONG & 0x00000040 ) {
+ fprintf(fp_log, "[%sIntStatus] Normal priority transmit buffer unavailable: %08lx [loop:%d]\n", type, Dat_ULONG, Loop);
+ FindErr( Err_NPTXBUF_UNAVA );
+ }
+#endif
+
+#ifdef CheckTPktLost
+ if ( Dat_ULONG & 0x00000080 ) {
+ fprintf(fp_log, "[%sIntStatus] Packets transmitted to Ethernet lost : %08lx [loop:%d]\n", type, Dat_ULONG, Loop);
+ FindErr( Err_TPKT_LOST );
+ }
+#endif
+#endif
+ if (Err_Flag)
+ return(1);
+ else
+ return(0);
+} // End int check_int (char *type)
+
+
+//------------------------------------------------------------
+// Buffer
+//------------------------------------------------------------
+void setup_framesize (void) {
+ int i;
+
+ #ifdef DbgPrn_FuncHeader
+ printf ("setup_framesize\n");
+ Debug_delay();
+ #endif
+
+ //------------------------------------------------------------
+ // Fill Frame Size out descriptor area
+ //------------------------------------------------------------
+ #ifdef SLT_UBOOT
+ if (0)
+ #else
+ if ( ENABLE_RAND_SIZE )
+ #endif
+ {
+ for (i = 0; i < DES_NUMBER; i++) {
+ if ( FRAME_Rand_Simple ) {
+ switch(rand() % 5) {
+ case 0 : FRAME_LEN[i] = 0x4e ; break;
+ case 1 : FRAME_LEN[i] = 0x4ba; break;
+ default: FRAME_LEN[i] = 0x5ea; break;
+ }
+ }
+ else {
+ FRAME_LEN_Cur = rand() % (MAX_FRAME_RAND_SIZE + 1);
+
+ if (FRAME_LEN_Cur < MIN_FRAME_RAND_SIZE)
+ FRAME_LEN_Cur = MIN_FRAME_RAND_SIZE;
+
+ FRAME_LEN[i] = FRAME_LEN_Cur;
+ }
+#ifdef SLT_DOS
+ if (DbgPrn_FRAME_LEN)
+ fprintf(fp_log, "[setup_framesize] FRAME_LEN_Cur:%08lx[Des:%d][loop:%d]\n", FRAME_LEN[i], i, Loop);
+#endif
+ }
+ }
+ else {
+ for (i = 0; i < DES_NUMBER; i++) {
+ #ifdef SelectSimpleLength
+ if (i % FRAME_SELH_PERD)
+ FRAME_LEN[i] = FRAME_LENH;
+ else
+ FRAME_LEN[i] = FRAME_LENL;
+ #else
+ if ( BurstEnable ) {
+ if (IEEETesting) {
+ FRAME_LEN[i] = 1514;
+ }
+ else {
+ #ifdef ENABLE_ARP_2_WOL
+ FRAME_LEN[i] = 164;
+ #else
+ FRAME_LEN[i] = 60;
+ #endif
+ }
+ }
+ else {
+ #ifdef SelectLengthInc
+// FRAME_LEN[i] = (i%1455)+60;
+ FRAME_LEN[i] = 1514-( i % 1455 );
+ #else
+ if (i % FRAME_SELH_PERD)
+ FRAME_LEN[i] = FRAME_LENH;
+ else
+ FRAME_LEN[i] = FRAME_LENL;
+ #endif
+ } // End if (BurstEnable)
+ #endif
+/*
+ switch(i % 20) {
+ case 0 : FRAME_LEN[i] = FRAME_LENH; break;
+ case 1 : FRAME_LEN[i] = FRAME_LENH; break;
+ case 2 : FRAME_LEN[i] = FRAME_LENH; break;
+ default: FRAME_LEN[i] = FRAME_LENL; break;
+ }
+*/
+#ifdef SLT_DOS
+ if (DbgPrn_FRAME_LEN)
+ fprintf(fp_log, "[setup_framesize] FRAME_LEN_Cur:%08lx[Des:%d][loop:%d]\n", FRAME_LEN[i], i, Loop);
+#endif
+ } // End for (i = 0; i < DES_NUMBER; i++)
+ } // End if ( ENABLE_RAND_SIZE )
+
+ // Calculate average of frame size
+ Avg_frame_len = 0;
+
+ for ( i = 0; i < DES_NUMBER; i++ ) {
+ Avg_frame_len += FRAME_LEN[i];
+ }
+
+ Avg_frame_len = Avg_frame_len / (double)DES_NUMBER;
+
+ //------------------------------------------------------------
+ // Write Plane
+ //------------------------------------------------------------
+ switch( ZeroCopy_OFFSET & 0x3 ) {
+ case 0: wp_fir = 0xffffffff; break;
+ case 1: wp_fir = 0xffffff00; break;
+ case 2: wp_fir = 0xffff0000; break;
+ case 3: wp_fir = 0xff000000; break;
+ }
+
+ for ( i = 0; i < DES_NUMBER; i++ ) {
+ switch( ( ZeroCopy_OFFSET + FRAME_LEN[i] - 1 ) & 0x3 ) {
+ case 0: wp_lst[i] = 0x000000ff; break;
+ case 1: wp_lst[i] = 0x0000ffff; break;
+ case 2: wp_lst[i] = 0x00ffffff; break;
+ case 3: wp_lst[i] = 0xffffffff; break;
+ }
+ } // End for ( i = 0; i < DES_NUMBER; i++ )
+} // End void setup_framesize (void)
+
+//------------------------------------------------------------
+void setup_arp (void) {
+ int i;
+ for (i = 0; i < 16; i++ )
+ ARP_data[i] = ARP_org_data[i];
+
+ ARP_data[1] = 0x0000ffff | ( SA[0] << 16 )
+ | ( SA[1] << 24 );
+
+ ARP_data[2] = ( SA[2] )
+ | ( SA[3] << 8 )
+ | ( SA[4] << 16 )
+ | ( SA[5] << 24 );
+
+ ARP_data[5] = 0x00000100 | ( SA[0] << 16 )
+ | ( SA[1] << 24 );
+
+ ARP_data[6] = ( SA[2] )
+ | ( SA[3] << 8 )
+ | ( SA[4] << 16 )
+ | ( SA[5] << 24 );
+} // End void setup_arp (void)
+
+//------------------------------------------------------------
+void setup_buf (void) {
+ int i;
+ int j;
+ ULONG adr;
+ ULONG adr_srt;
+ ULONG adr_end;
+ ULONG len;
+ #ifdef SelectSimpleDA
+ int cnt;
+ ULONG Current_framelen;
+ #endif
+
+ #ifdef ENABLE_ARP_2_WOL
+ int DA[3];
+
+ DA[0] = ( ( SelectWOLDA_DatH >> 8 ) & 0x00ff ) |
+ ( ( SelectWOLDA_DatH << 8 ) & 0xff00 );
+
+ DA[1] = ( ( SelectWOLDA_DatL >> 24 ) & 0x00ff ) |
+ ( ( SelectWOLDA_DatL >> 8 ) & 0xff00 );
+
+ DA[2] = ( ( SelectWOLDA_DatL >> 8 ) & 0x00ff ) |
+ ( ( SelectWOLDA_DatL << 8 ) & 0xff00 );
+ #endif
+
+ #ifdef DbgPrn_FuncHeader
+ printf ("setup_buf : %d\n", Loop);
+ Debug_delay();
+ #endif
+
+ // It need be multiple of 4
+ adr_srt = GET_DMA_BASE_SETUP & 0xfffffffc;
+
+ for (j = 0; j < DES_NUMBER; j++) {
+ if ( DbgPrn_BufAdr )
+ printf("[loop:%4d][des:%4d][setup_buf ] %08lx\n", Loop, j, adr_srt);
+
+ if ( BurstEnable ) {
+ if ( IEEETesting ) {
+ #ifdef ENABLE_DASA
+ WriteSOC_DD( adr_srt , 0xffffffff );
+ WriteSOC_DD( adr_srt + 4, ARP_data[1] );
+ WriteSOC_DD( adr_srt + 8, ARP_data[2] );
+
+ for (adr = (adr_srt + 12); adr < (adr_srt + DMA_PakSize); adr += 4 )
+ #else
+ for (adr = adr_srt; adr < (adr_srt + DMA_PakSize); adr += 4 )
+ #endif
+ {
+ switch( TestMode ) {
+ case 1: gdata = 0xffffffff; break;
+ case 2: gdata = 0x55555555; break;
+ case 3: gdata = rand() | (rand() << 16); break;
+ case 5: gdata = UserDVal; break;
+ }
+ WriteSOC_DD(adr, gdata);
+ } // End for()
+ }
+ else {
+ for (i = 0; i < 16; i++) {
+ WriteSOC_DD( adr_srt + ( i << 2 ), ARP_data[i] );
+ }
+
+ #ifdef ENABLE_ARP_2_WOL
+ for (i = 16; i < 40; i += 3) {
+ WriteSOC_DD( adr_srt + ( i << 2 ), ( DA[1] << 16 ) | DA[0] );
+ WriteSOC_DD( adr_srt + ( i << 2 ) + 4, ( DA[0] << 16 ) | DA[2] );
+ WriteSOC_DD( adr_srt + ( i << 2 ) + 8, ( DA[2] << 16 ) | DA[1] );
+ }
+ #endif
+ } // End if ( IEEETesting )
+ }
+ else {
+ // --------------------------------------------
+ #ifdef SelectSimpleData
+ #ifdef SimpleData_Fix
+ switch( j % SimpleData_FixNum ) {
+ case 0 : gdata = SimpleData_FixVal00; break;
+ case 1 : gdata = SimpleData_FixVal01; break;
+ case 2 : gdata = SimpleData_FixVal02; break;
+ case 3 : gdata = SimpleData_FixVal03; break;
+ case 4 : gdata = SimpleData_FixVal04; break;
+ case 5 : gdata = SimpleData_FixVal05; break;
+ case 6 : gdata = SimpleData_FixVal06; break;
+ case 7 : gdata = SimpleData_FixVal07; break;
+ case 8 : gdata = SimpleData_FixVal08; break;
+ case 9 : gdata = SimpleData_FixVal09; break;
+ case 10 : gdata = SimpleData_FixVal10; break;
+ default : gdata = SimpleData_FixVal11; break;
+ }
+ #else
+ gdata = 0x11111111 * ((j + SEED_START) % 256);
+ #endif
+
+ adr_end = adr_srt + DMA_PakSize;
+ for ( adr = adr_srt; adr < adr_end; adr += 4 ) {
+ WriteSOC_DD( adr, gdata );
+ }
+ // --------------------------------------------
+ #elif SelectSimpleDA
+
+ gdata = DATA_SEED(j + SEED_START);
+ Current_framelen = FRAME_LEN[j];
+
+ if ( DbgPrn_FRAME_LEN )
+ fprintf(fp_log, "[setup_buf ] Current_framelen:%08lx[Des:%d][loop:%d]\n", Current_framelen, j, Loop);
+
+ cnt = 0;
+ len = ( ( ( Current_framelen - 14 ) & 0xff ) << 8) |
+ ( ( Current_framelen - 14 ) >> 8 );
+
+ adr_end = adr_srt + DMA_PakSize;
+ for ( adr = adr_srt; adr < adr_end; adr += 4 ) {
+ cnt++;
+ if (cnt == 1 ) WriteSOC_DD( adr, SelectSimpleDA_Dat0 );
+ else if (cnt == 2 ) WriteSOC_DD( adr, SelectSimpleDA_Dat1 );
+ else if (cnt == 3 ) WriteSOC_DD( adr, SelectSimpleDA_Dat2 );
+ else if (cnt == 4 ) WriteSOC_DD( adr, len | (len << 16) );
+ else
+ WriteSOC_DD( adr, gdata );
+
+ gdata += DATA_IncVal;
+ }
+ // --------------------------------------------
+ #else
+
+ gdata = DATA_SEED(j + SEED_START);
+ adr_end = adr_srt + DMA_PakSize;
+ for ( adr = adr_srt; adr < adr_end; adr += 4 ) {
+ WriteSOC_DD( adr, gdata );
+
+ gdata += DATA_IncVal;
+ }
+
+ #endif
+
+ } // End if ( BurstEnable )
+
+ adr_srt += DMA_PakSize;
+ } // End for (j = 0; j < DES_NUMBER; j++)
+} // End void setup_buf (void)
+
+//------------------------------------------------------------
+// Check data of one packet
+//------------------------------------------------------------
+char check_Data (ULONG desadr, LONG number) {
+ int index;
+ int cnt;
+ ULONG rdata;
+ ULONG wp_lst_cur;
+ ULONG adr_las;
+ ULONG adr;
+ ULONG adr_srt;
+ ULONG adr_end;
+ ULONG len;
+ #ifdef SelectSimpleDA
+ ULONG gdata_bak;
+ #endif
+
+ #ifdef DbgPrn_FuncHeader
+ printf ("check_Data : %d\n", Loop);
+ Debug_delay();
+ #endif
+ //printf("[Des:%d][loop:%d]Desadr:%08x\n", number, Loop, desadr);
+
+ wp_lst_cur = wp_lst[number];
+ FRAME_LEN_Cur = FRAME_LEN[number];
+#ifdef SLT_DOS
+ if ( DbgPrn_FRAME_LEN )
+ fprintf(fp_log, "[check_Data ] FRAME_LEN_Cur:%08lx[Des:%d][loop:%d]\n", FRAME_LEN_Cur, number, Loop);
+#endif
+ adr_srt = ReadSOC_DD(desadr) & 0xfffffffc;
+ adr_end = adr_srt + PktByteSize;
+
+ #ifdef SelectSimpleData
+ #ifdef SimpleData_Fix
+ switch( number % SimpleData_FixNum ) {
+ case 0 : gdata = SimpleData_FixVal00; break;
+ case 1 : gdata = SimpleData_FixVal01; break;
+ case 2 : gdata = SimpleData_FixVal02; break;
+ case 3 : gdata = SimpleData_FixVal03; break;
+ case 4 : gdata = SimpleData_FixVal04; break;
+ case 5 : gdata = SimpleData_FixVal05; break;
+ case 6 : gdata = SimpleData_FixVal06; break;
+ case 7 : gdata = SimpleData_FixVal07; break;
+ case 8 : gdata = SimpleData_FixVal08; break;
+ case 9 : gdata = SimpleData_FixVal09; break;
+ case 10 : gdata = SimpleData_FixVal10; break;
+ default : gdata = SimpleData_FixVal11; break;
+ }
+ #else
+ gdata = 0x11111111 * ((number + SEED_START) % 256);
+ #endif
+ #else
+ gdata = DATA_SEED(number + SEED_START);
+ #endif
+
+ wp = wp_fir;
+ adr_las = adr_end - 4;
+
+ cnt = 0;
+ len = (((FRAME_LEN_Cur-14) & 0xff) << 8) | ((FRAME_LEN_Cur-14) >> 8);
+#ifdef SLT_DOS
+ if (DbgPrn_Bufdat)
+ fprintf(fp_log, " Inf:%08lx ~ %08lx(%08lx) %08lx [Des:%d][loop:%d]\n", adr_srt, adr_end, adr_las, gdata, number, Loop);
+#endif
+ for (adr = adr_srt; adr < adr_end; adr+=4) {
+
+ #ifdef SelectSimpleDA
+ cnt++;
+ if ( cnt == 1 ) { gdata_bak = gdata; gdata = SelectSimpleDA_Dat0; }
+ else if ( cnt == 2 ) { gdata_bak = gdata; gdata = SelectSimpleDA_Dat1; }
+ else if ( cnt == 3 ) { gdata_bak = gdata; gdata = SelectSimpleDA_Dat2; }
+ else if ( cnt == 4 ) { gdata_bak = gdata; gdata = len | (len << 16); }
+ #endif
+ rdata = ReadSOC_DD(adr);
+ if (adr == adr_las)
+ wp = wp & wp_lst_cur;
+
+ if ( (rdata & wp) != (gdata & wp) ) {
+#ifdef SLT_DOS
+ fprintf(fp_log, "\nError: Adr:%08lx[%3d] (%08lx) (%08lx:%08lx) [Des:%d][loop:%d]\n", adr, (adr - adr_srt) / 4, rdata, gdata, wp, number, Loop);
+#endif
+ for (index = 0; index < 6; index++) {
+ rdata = ReadSOC_DD(adr);
+#ifdef SLT_DOS
+ fprintf(fp_log, "Rep : Adr:%08lx (%08lx) (%08lx:%08lx) [Des:%d][loop:%d]\n", adr, rdata, gdata, wp, number, Loop);
+#endif
+ }
+
+ if ( DbgPrn_DumpMACCnt )
+ dump_mac_ROreg();
+
+ return( FindErr( Err_Check_Buf_Data ) );
+ } // End if ( (rdata & wp) != (gdata & wp) )
+#ifdef SLT_DOS
+ if ( DbgPrn_BufdatDetail )
+ fprintf(fp_log, " Adr:%08lx[%3d] (%08lx) (%08lx:%08lx) [Des:%d][loop:%d]\n", adr, (adr - adr_srt) / 4, rdata, gdata, wp, number, Loop);
+#endif
+ #ifdef SelectSimpleDA
+ if ( cnt <= 4 )
+ gdata = gdata_bak;
+ #endif
+
+ #ifdef SelectSimpleData
+ #else
+ gdata += DATA_IncVal;
+ #endif
+
+ wp = 0xffffffff;
+ }
+ return(0);
+} // End char check_Data (ULONG desadr, LONG number)
+
+//------------------------------------------------------------
+char check_buf (int loopcnt) {
+ int count;
+ ULONG desadr;
+
+ #ifdef DbgPrn_FuncHeader
+ printf ("check_buf : %d\n", Loop);
+ Debug_delay();
+ #endif
+
+ for ( count = DES_NUMBER - 1; count >= 0; count-- ) {
+ desadr = H_RDES_BASE + ( 16 * count ) + 12;
+ //printf("%d:%08x\n", count, desadr);
+ if (check_Data(desadr, count)) {
+ check_int ("");
+
+ return(1);
+ }
+ }
+ if ( check_int ("") )
+ return(1);
+
+ return(0);
+} // End char check_buf (int loopcnt)
+
+//------------------------------------------------------------
+// Descriptor
+//------------------------------------------------------------
+void setup_txdes (ULONG desadr, ULONG bufbase) {
+ ULONG bufadr;
+ ULONG desval;
+ int count;
+
+ #ifdef DbgPrn_FuncHeader
+ printf ("setup_txdes: %d\n", Loop);
+ Debug_delay();
+ #endif
+
+ bufadr = bufbase + ZeroCopy_OFFSET;
+
+ if (TxDataEnable) {
+ for (count = 0; count < DES_NUMBER; count++) {
+ FRAME_LEN_Cur = FRAME_LEN[count];
+ desval = TDES_IniVal;
+ #ifdef SLT_DOS
+ if (DbgPrn_FRAME_LEN)
+ fprintf(fp_log, "[setup_txdes ] FRAME_LEN_Cur:%08lx[Des:%d][loop:%d]\n", FRAME_LEN_Cur, count, Loop);
+ #endif
+ if (DbgPrn_BufAdr)
+ printf("[loop:%4d][des:%4d][setup_txdes] %08lx\n", Loop, count, bufadr);
+
+ WriteSOC_DD( desadr + 0x04, 0 );
+ WriteSOC_DD( desadr + 0x08, 0 );
+ WriteSOC_DD( desadr + 0x0C, (bufadr + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730
+ if ( count == ( DES_NUMBER - 1 ) )
+ WriteSOC_DD( desadr , desval | EOR_IniVal);
+ else
+ WriteSOC_DD( desadr , desval );
+
+ bufadr += DMA_PakSize;
+ desadr += 16;
+ }
+ }
+ else {
+ WriteSOC_DD( desadr , 0);
+ }
+} // End void setup_txdes (ULONG desadr, ULONG bufbase)
+
+//------------------------------------------------------------
+void setup_rxdes (ULONG desadr, ULONG bufbase) {
+ ULONG bufadr;
+ ULONG desval;
+ int count;
+
+ #ifdef DbgPrn_FuncHeader
+ printf ("setup_rxdes: %d\n", Loop);
+ Debug_delay();
+ #endif
+
+ bufadr = bufbase+ZeroCopy_OFFSET;
+ desval = RDES_IniVal;
+
+ if ( RxDataEnable ) {
+ for (count = 0; count < DES_NUMBER; count++) {
+ if (DbgPrn_BufAdr)
+ printf("[loop:%4d][des:%4d][setup_rxdes] %08lx\n", Loop, count, bufadr);
+ WriteSOC_DD( desadr + 0x04, 0 );
+ WriteSOC_DD( desadr + 0x08, 0 );
+ WriteSOC_DD( desadr + 0x0C, ( bufadr + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730
+ if ( count == ( DES_NUMBER - 1 ) )
+ WriteSOC_DD( desadr , desval | EOR_IniVal );
+ else
+ WriteSOC_DD( desadr , desval );
+
+ desadr += 16;
+ bufadr += DMA_PakSize;
+ }
+ }
+ else {
+ WriteSOC_DD( desadr , 0x80000000 );
+ } // End if ( RxDataEnable )
+} // End void setup_rxdes (ULONG desadr, ULONG bufbase)
+
+//------------------------------------------------------------
+// First setting TX and RX information
+//------------------------------------------------------------
+void setup_des (ULONG bufnum) {
+
+ if ( DbgPrn_BufAdr ) {
+ printf ("setup_rxdes: %ld\n", bufnum);
+ Debug_delay();
+ }
+
+ setup_txdes( H_TDES_BASE, GET_DMA_BASE_SETUP );
+ setup_rxdes( H_RDES_BASE, GET_DMA_BASE(0) );
+
+} // End void setup_des (ULONG bufnum)
+
+//------------------------------------------------------------
+// Move buffer point of TX and RX descriptor to next DMA buffer
+//------------------------------------------------------------
+void setup_des_loop (ULONG bufnum) {
+ int count;
+ ULONG H_rx_desadr;
+ ULONG H_tx_desadr;
+ ULONG H_tx_bufadr;
+ ULONG H_rx_bufadr;
+
+ if ( DbgPrn_BufAdr ) {
+ printf ("setup_rxdes_loop: %ld\n", bufnum);
+ Debug_delay();
+ }
+
+ if (RxDataEnable) {
+ H_rx_bufadr = GET_DMA_BASE( bufnum + 1 ) + ZeroCopy_OFFSET;
+ H_rx_desadr = H_RDES_BASE;
+//printf (" =====>setup_rxdes_loop: %ld [%lX]\n", bufnum, H_rx_bufadr);
+ for (count = 0; count < DES_NUMBER; count++) {
+ WriteSOC_DD(H_rx_desadr + 0x0C, (H_rx_bufadr + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730
+
+ if (count == (DES_NUMBER - 1)) {
+ WriteSOC_DD( H_rx_desadr, RDES_IniVal | EOR_IniVal );
+ }
+ else {
+ WriteSOC_DD( H_rx_desadr, RDES_IniVal );
+ }
+ H_rx_bufadr += DMA_PakSize;
+ H_rx_desadr += 16;
+ }
+ }
+
+ if (TxDataEnable) {
+ if (RxDataEnable) {
+ H_tx_bufadr = GET_DMA_BASE( bufnum ) + ZeroCopy_OFFSET;
+ }
+ else {
+ H_tx_bufadr = GET_DMA_BASE( 0 ) + ZeroCopy_OFFSET;
+ }
+ H_tx_desadr = H_TDES_BASE;
+//printf (" =====>setup_Txdes_loop: %ld [%lX]\n", bufnum, H_tx_bufadr);
+ for (count = 0; count < DES_NUMBER; count++) {
+ FRAME_LEN_Cur = FRAME_LEN[count];
+ WriteSOC_DD( H_tx_desadr + 0x0C, ( H_tx_bufadr + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730
+ if (count == (DES_NUMBER - 1)) {
+ WriteSOC_DD( H_tx_desadr, TDES_IniVal | EOR_IniVal );
+ }
+ else {
+ WriteSOC_DD( H_tx_desadr, TDES_IniVal );
+ }
+ H_tx_bufadr += DMA_PakSize;
+ H_tx_desadr += 16;
+ }
+ }
+
+ WriteSOC_DD( H_MAC_BASE + 0x18, 0x00000000 ); // Tx Poll
+ WriteSOC_DD( H_MAC_BASE + 0x1c, 0x00000000 ); // Rx Poll
+} // End void setup_des_loop (ULONG bufnum)
+
+//------------------------------------------------------------
+char check_des_header_Tx (char *type, ULONG adr, LONG desnum) {
+ int timeout = 0;
+ ULONG dat;
+
+ dat = ReadSOC_DD(adr);
+
+ while ( HWOwnTx(dat) ) {
+ // we will run again, if transfer has not been completed.
+ if ( RxDataEnable && (++timeout > TIME_OUT_Des) ) {
+ #ifdef SLT_DOS
+ fprintf(fp_log, "[%sTxDesOwn] Address %08lx = %08lx [Des:%d][loop:%d]\n", type, adr, dat, desnum, Loop);
+ #endif
+ return(FindErr_Des(Check_Des_TxOwnTimeOut));
+ }
+ WriteSOC_DD(H_MAC_BASE + 0x18, 0x00000000);//Tx Poll
+ WriteSOC_DD(H_MAC_BASE + 0x1c, 0x00000000);//Rx Poll
+
+ #ifdef Delay_ChkTxOwn
+ delay(Delay_ChkTxOwn);
+ #endif
+ dat = ReadSOC_DD(adr);
+ }
+
+ return(0);
+} // End char check_des_header_Tx (char *type, ULONG adr, LONG desnum)
+
+//------------------------------------------------------------
+char check_des_header_Rx (char *type, ULONG adr, LONG desnum) {
+ #ifdef CheckRxOwn
+ int timeout = 0;
+ ULONG dat;
+
+ dat = ReadSOC_DD(adr);
+
+ while ( HWOwnRx( dat ) ) {
+ // we will run again, if transfer has not been completed.
+ if (TxDataEnable && (++timeout > TIME_OUT_Des)) {
+ #ifdef SLT_DOS
+ fprintf(fp_log, "[%sRxDesOwn] Address %08lx = %08lx [Des:%d][loop:%d]\n", type, adr, dat, desnum, Loop);
+ #endif
+ return(FindErr_Des(Check_Des_RxOwnTimeOut));
+ }
+
+ WriteSOC_DD(H_MAC_BASE + 0x18, 0x00000000);//Tx Poll
+ WriteSOC_DD(H_MAC_BASE + 0x1c, 0x00000000);//Rx Poll
+
+ #ifdef Delay_ChkRxOwn
+ delay(Delay_ChkRxOwn);
+ #endif
+ dat = ReadSOC_DD(adr);
+ };
+
+ Dat_ULONG = ReadSOC_DD( adr + 12 );
+
+ #ifdef CheckRxLen
+ #ifdef SLT_DOS
+ if ( DbgPrn_FRAME_LEN )
+ fprintf(fp_log, "[%sRxDes ] FRAME_LEN_Cur:%08lx[Des:%d][loop:%d]\n", type, (FRAME_LEN_Cur + 4), desnum, Loop);
+ #endif
+
+ if ((dat & 0x3fff) != (FRAME_LEN_Cur + 4)) {
+ #ifdef SLT_DOS
+ fprintf(fp_log, "[%sRxDes] Error Frame Length %08lx:%08lx %08lx(%4d/%4d) [Des:%d][loop:%d]\n", type, adr, dat, Dat_ULONG, (dat & 0x3fff), (FRAME_LEN_Cur + 4), desnum, Loop);
+ #endif
+ FindErr_Des(Check_Des_FrameLen);
+ }
+ #endif // End CheckRxLen
+
+ #ifdef CheckRxErr
+ if (dat & 0x00040000) {
+ #ifdef SLT_DOS
+ fprintf(fp_log, "[%sRxDes] Error RxErr %08lx:%08lx %08lx [Des:%d][loop:%d]\n", type, adr, dat, Dat_ULONG, desnum, Loop);
+ #endif
+ FindErr_Des(Check_Des_RxErr);
+ }
+ #endif // End CheckRxErr
+
+ #ifdef CheckOddNibble
+ if (dat & 0x00400000) {
+ #ifdef SLT_DOS
+ fprintf(fp_log, "[%sRxDes] Odd Nibble %08lx:%08lx %08lx [Des:%d][loop:%d]\n", type, adr, dat, Dat_ULONG, desnum, Loop);
+ #endif
+ FindErr_Des(Check_Des_OddNibble);
+ }
+ #endif // End CheckOddNibble
+
+ #ifdef CheckCRC
+ if (dat & 0x00080000) {
+ #ifdef SLT_DOS
+ fprintf(fp_log, "[%sRxDes] Error CRC %08lx:%08lx %08lx [Des:%d][loop:%d]\n", type, adr, dat, Dat_ULONG, desnum, Loop);
+ #endif
+ FindErr_Des(Check_Des_CRC);
+ }
+ #endif // End CheckCRC
+
+ #ifdef CheckRxFIFOFull
+ if (dat & 0x00800000) {
+ #ifdef SLT_DOS
+ fprintf(fp_log, "[%sRxDes] Error Rx FIFO Full %08lx:%08lx %08lx [Des:%d][loop:%d]\n", type, adr, dat, Dat_ULONG, desnum, Loop);
+ #endif
+ FindErr_Des(Check_Des_RxFIFOFull);
+ }
+ #endif // End CheckRxFIFOFull
+
+ // if (check_int ("")) {return(1);}
+ #endif // End CheckRxOwn
+
+ if (Err_Flag)
+ return(1);
+ else
+ return(0);
+} // End char check_des_header_Rx (char *type, ULONG adr, LONG desnum)
+
+//------------------------------------------------------------
+char check_des (ULONG bufnum, int checkpoint) {
+ int desnum;
+ ULONG H_rx_desadr;
+ ULONG H_tx_desadr;
+ ULONG H_tx_bufadr;
+ ULONG H_rx_bufadr;
+
+ #ifdef Delay_DesGap
+ ULONG dly_cnt = 0;
+ ULONG dly_max = Delay_CntMaxIncVal;
+ #endif
+
+ #ifdef DbgPrn_FuncHeader
+ printf ("check_des : %d(%d)\n", Loop, checkpoint);
+ Debug_delay();
+ #endif
+
+ // Fire the engine to send and recvice
+ WriteSOC_DD( H_MAC_BASE + 0x18, 0x00000000 );//Tx Poll
+ WriteSOC_DD( H_MAC_BASE + 0x1c, 0x00000000 );//Rx Poll
+
+ #ifdef SelectSimpleDes
+ #else
+ if ( IEEETesting == 1 ) {
+ // IEEE test mode, there is the same data in every lan packet
+ H_tx_bufadr = GET_DMA_BASE_SETUP;
+ H_rx_bufadr = GET_DMA_BASE(0);
+ }
+ else {
+ H_rx_bufadr = GET_DMA_BASE( bufnum + 1 ) + ZeroCopy_OFFSET;
+
+ if (RxDataEnable) {
+ H_tx_bufadr = GET_DMA_BASE(bufnum ) + ZeroCopy_OFFSET;
+ }
+ else {
+ H_tx_bufadr = GET_DMA_BASE( 0 ) + ZeroCopy_OFFSET;
+ }
+ }
+ #endif
+
+ H_rx_desadr = H_RDES_BASE;
+ H_tx_desadr = H_TDES_BASE;
+
+ #ifdef Delay_DES
+ delay(Delay_DES);
+ #endif
+
+ for (desnum = 0; desnum < DES_NUMBER; desnum++) {
+ if ( DbgPrn_BufAdr )
+ printf( "[loop:%4d][des:%4d][check_des ] %08lx %08lx [%08lx] [%08lx]\n", Loop, desnum, ( H_tx_desadr ), ( H_rx_desadr ), ReadSOC_DD( H_tx_desadr + 12 ), ReadSOC_DD( H_rx_desadr + 12 ) );
+
+ //[Delay]--------------------
+ #ifdef Delay_DesGap
+ if ( dly_cnt++ > 3 ) {
+ switch ( rand() % 12 ) {
+ case 1 : dly_max = 00000; break;
+ case 3 : dly_max = 20000; break;
+ case 5 : dly_max = 40000; break;
+ case 7 : dly_max = 60000; break;
+ defaule: dly_max = 70000; break;
+ }
+
+ dly_max += ( rand() % 4 ) * 14321;
+
+ while (dly_cnt < dly_max) {
+ dly_cnt++;
+ }
+
+ dly_cnt = 0;
+ }
+ else {
+// timeout = 0;
+// while (timeout < 50000) {timeout++;};
+ }
+ #endif // End Delay_DesGap
+
+ //[Check Owner Bit]--------------------
+ FRAME_LEN_Cur = FRAME_LEN[desnum];
+#ifdef SLT_DOS
+ if ( DbgPrn_FRAME_LEN )
+ fprintf(fp_log, "[check_des ] FRAME_LEN_Cur:%08lx[Des:%d][loop:%d]%d\n", FRAME_LEN_Cur, desnum, Loop, checkpoint);
+#endif
+// if (BurstEnable) {
+// if (check_des_header_Tx("", H_tx_desadr, desnum)) {CheckDesFail_DesNum = desnum; return(1);}
+// } else {
+// if (check_des_header_Rx("", H_rx_desadr, desnum)) {CheckDesFail_DesNum = desnum; return(1);}
+// if (check_des_header_Tx("", H_tx_desadr, desnum)) {CheckDesFail_DesNum = desnum; return(1);}
+// }
+
+ // Check the description of Tx and Rx
+ if ( RxDataEnable && check_des_header_Rx("", H_rx_desadr, desnum) ) {
+ CheckDesFail_DesNum = desnum;
+
+ return(1);
+ }
+ if ( TxDataEnable && check_des_header_Tx("", H_tx_desadr, desnum) ) {
+ CheckDesFail_DesNum = desnum;
+
+ return(1);
+ }
+// else {
+// printf(" %d \r", desnum);
+// }
+
+ #ifdef SelectSimpleDes
+ #else
+ if ( !checkpoint ) {
+ // Setting buffer address to description of Tx and Rx on next stage
+
+// if (!BurstEnable) {
+// WriteSOC_DD( H_rx_desadr + 0x0C, (H_rx_bufadr + CPU_BUS_ADDR_SDRAM_OFFSET) );
+// WriteSOC_DD( H_tx_desadr + 0x0C, (H_tx_bufadr + CPU_BUS_ADDR_SDRAM_OFFSET) );
+// }
+//
+// if ( desnum == (DES_NUMBER - 1) ) {
+// WriteSOC_DD( H_rx_desadr, RDES_IniVal | EOR_IniVal );
+// WriteSOC_DD( H_tx_desadr, TDES_IniVal | EOR_IniVal );
+// }
+// else {
+// WriteSOC_DD( H_rx_desadr, RDES_IniVal );
+// WriteSOC_DD( H_tx_desadr, TDES_IniVal );
+// }
+// WriteSOC_DD( H_MAC_BASE+0x18, 0x00000000 ); //Tx Poll
+// WriteSOC_DD( H_MAC_BASE+0x1c, 0x00000000 ); //Rx Poll
+
+ if ( RxDataEnable ) {
+ WriteSOC_DD( H_rx_desadr + 0x0C, (H_rx_bufadr + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730
+
+ if ( desnum == (DES_NUMBER - 1) ) {
+ WriteSOC_DD( H_rx_desadr, RDES_IniVal | EOR_IniVal );
+ } else {
+ WriteSOC_DD( H_rx_desadr, RDES_IniVal );
+ }
+ }
+ if ( TxDataEnable ) {
+ WriteSOC_DD( H_tx_desadr + 0x0C, (H_tx_bufadr + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730
+ if ( desnum == (DES_NUMBER - 1) ) {
+ WriteSOC_DD( H_tx_desadr, TDES_IniVal | EOR_IniVal );
+ }
+ else {
+ WriteSOC_DD( H_tx_desadr, TDES_IniVal );
+ }
+ }
+ WriteSOC_DD( H_MAC_BASE + 0x18, 0x00000000 ); //Tx Poll
+ WriteSOC_DD( H_MAC_BASE + 0x1c, 0x00000000 ); //Rx Poll
+ }
+ H_rx_bufadr += DMA_PakSize;
+ H_tx_bufadr += DMA_PakSize;
+ #endif // End SelectSimpleDes
+
+ H_rx_desadr += 16;
+ H_tx_desadr += 16;
+ } // End for (desnum = 0; desnum < DES_NUMBER; desnum++)
+
+ return(0);
+} // End char check_des (ULONG bufnum, int checkpoint)
+//#endif
+
+//------------------------------------------------------------
+// Print
+//------------------------------------------------------------
+void PrintMode (void) {
+ if (Enable_MAC34) printf ("run_mode[dec] | 0->MAC1 1->MAC2 2->MAC3 3->MAC4\n");
+ else printf ("run_mode[dec] | 0->MAC1 1->MAC2\n");
+}
+
+//------------------------------------------------------------
+void PrintSpeed (void) {
+ printf ("speed[dec] | 0->1G 1->100M 2->10M 3->all speed (default:%3d)\n", DEF_SPEED);
+}
+
+//------------------------------------------------------------
+void PrintCtrl (void) {
+ printf ("ctrl[dec] | bit0~2: Reserved\n");
+ printf ("(default:%3d) | bit3 : 1->Enable PHY init 0->Disable PHY init\n", GCtrl);
+ printf (" | bit4 : 1->Enable PHY int-loop 0->Disable PHY int-loop\n");
+ printf (" | bit5 : 1->Ignore PHY ID 0->Check PHY ID\n");
+ if (AST2400) {
+ printf (" | bit6 : 1->Enable MAC int-loop 0->Disable MAC int-loop\n");
+ }
+}
+
+//------------------------------------------------------------
+void PrintLoop (void) {
+ printf ("loop_max[dec] | 1G : 20 will run 1 sec (default:%3d)\n", DEF_LOOP_MAX * 20);
+ printf (" | 100M: 2 will run 1 sec (default:%3d)\n", DEF_LOOP_MAX * 2);
+ printf (" | 10M : 1 will run 1 sec (default:%3d)\n", DEF_LOOP_MAX);
+}
+
+//------------------------------------------------------------
+void PrintTest (void) {
+ if ( ModeSwitch == MODE_NSCI ) {
+ printf ("test_mode[dec] | 0: NCSI configuration with Disable_Channel request\n");
+ printf ("(default:%3d) | 1: NCSI configuration without Disable_Channel request\n", DEF_TESTMODE);
+ }
+ else {
+ printf ("test_mode[dec] | 0: Tx/Rx frame checking\n");
+ printf ("(default:%3d) | 1: Tx output 0xff frame\n", DEF_TESTMODE);
+ printf (" | 2: Tx output 0x55 frame\n");
+ printf (" | 3: Tx output random frame\n");
+ printf (" | 4: Tx output ARP frame\n");
+ printf (" | 5: Tx output user defined value frame (default:0x%8x)\n", DEF_USER_DEF_PACKET_VAL);
+ } // End if ( ModeSwitch == MODE_NSCI )
+
+ if (AST2300) {
+ printf (" | 6: IO timing testing\n");
+ printf (" | 7: IO timing/strength testing\n");
+ }
+}
+
+//------------------------------------------------------------
+void PrintPHYAdr (void) {
+ printf ("phy_adr[dec] | 0~31: PHY Address (default:%d)\n", DEF_PHY_ADR);
+}
+
+//------------------------------------------------------------
+void PrintIOTimingBund (void) {
+ printf ("IO margin[dec] | 0/1/3/5 (default:%d)\n", DEF_IOTIMINGBUND);
+}
+
+//------------------------------------------------------------
+void PrintPakNUm (void) {
+ printf ("package_num[dec] | 1~ 8: Total Number of NCSI Package (default:%d)\n", DEF_PACKAGE2NUM);
+}
+
+//------------------------------------------------------------
+void PrintChlNUm (void) {
+ printf ("channel_num[dec] | 1~32: Total Number of NCSI Channel (default:%d)\n", DEF_CHANNEL2NUM);
+}
+
+//------------------------------------------------------------
+
+void Print_Header (BYTE option) {
+
+ FILE_VAR
+
+ GET_OBJ( option )
+
+ if (GSpeed_sel[0]) PRINT(OUT_OBJ " 1G ");
+ else if (GSpeed_sel[1]) PRINT(OUT_OBJ " 100M ");
+ else PRINT(OUT_OBJ " 10M ");
+
+ switch (TestMode) {
+ case 0 : PRINT(OUT_OBJ "Tx/Rx frame checking \n" ); break;
+ case 1 : PRINT(OUT_OBJ "Tx output 0xff frame \n" ); break;
+ case 2 : PRINT(OUT_OBJ "Tx output 0x55 frame \n" ); break;
+ case 3 : PRINT(OUT_OBJ "Tx output random frame \n" ); break;
+ case 4 : PRINT(OUT_OBJ "Tx output ARP frame \n" ); break;
+ case 5 : PRINT(OUT_OBJ "Tx output 0x%08lx frame \n", UserDVal); break;
+ case 6 : PRINT(OUT_OBJ "IO delay testing \n" ); break;
+ case 7 : PRINT(OUT_OBJ "IO delay testing(Strength) \n" ); break;
+ case 8 : PRINT(OUT_OBJ "Tx frame \n" ); break;
+ case 9 : PRINT(OUT_OBJ "Rx frame checking \n" ); break;
+ }
+}
+
+//------------------------------------------------------------
+void PrintIO_Header (BYTE option) {
+
+ FILE_VAR
+
+ GET_OBJ( option )
+
+ if ( IOStrength ) {
+ if (GSpeed_sel[0]) PRINT(OUT_OBJ "[Strength %ld][1G ]========================================\n", IOStr_i);
+ else if (GSpeed_sel[1]) PRINT(OUT_OBJ "[Strength %ld][100M]========================================\n", IOStr_i);
+ else PRINT(OUT_OBJ "[Strength %ld][10M ]========================================\n", IOStr_i);
+ } else {
+ if (GSpeed_sel[0]) PRINT(OUT_OBJ "[1G ]========================================\n");
+ else if (GSpeed_sel[1]) PRINT(OUT_OBJ "[100M]========================================\n");
+ else PRINT(OUT_OBJ "[10M ]========================================\n");
+ }
+
+#ifdef Enable_Old_Style
+ if (Enable_RMII) PRINT(OUT_OBJ "Tx:SCU48[ %2d]= ", IOdly_out_shf);
+ else PRINT(OUT_OBJ "Tx:SCU48[%2d:%2d]= ", IOdly_out_shf+3, IOdly_out_shf);
+
+ for (IOdly_j = IOdly_out_str; IOdly_j <= IOdly_out_end; IOdly_j+=IOdly_incval) {
+ IOdly_out = valary[IOdly_j];
+ PRINT(OUT_OBJ "%2x", IOdly_out);
+ }
+
+ PRINT(OUT_OBJ "\n ");
+ for (IOdly_j = IOdly_out_str; IOdly_j <= IOdly_out_end; IOdly_j+=IOdly_incval) {
+ if (IOdly_out_reg_idx == IOdly_j) PRINT(OUT_OBJ " |");
+ else PRINT(OUT_OBJ " ");
+ }
+#else
+ PRINT(OUT_OBJ "Rx:SCU48[%2d:%2d]= ", IOdly_in_shf+3, IOdly_in_shf);
+
+ for (IOdly_i = IOdly_in_str; IOdly_i <= IOdly_in_end; IOdly_i+=IOdly_incval) {
+ IOdly_in = valary[IOdly_i];
+ PRINT(OUT_OBJ "%2x", IOdly_in);
+ }
+
+ PRINT(OUT_OBJ "\n ");
+ for (IOdly_i = IOdly_in_str; IOdly_i <= IOdly_in_end; IOdly_i+=IOdly_incval) {
+ if (IOdly_in_reg_idx == IOdly_i) PRINT(OUT_OBJ " |");
+ else PRINT(OUT_OBJ " ");
+ }
+#endif
+
+ PRINT(OUT_OBJ "\n");
+} // End void PrintIO_Header (BYTE option)
+
+//------------------------------------------------------------
+void PrintIO_LineS (BYTE option) {
+
+ FILE_VAR
+
+ GET_OBJ( option )
+
+
+#ifdef Enable_Old_Style
+ if (IOdly_in_reg == IOdly_in) {
+ PRINT(OUT_OBJ "Rx:SCU48[%2d:%2d]=%01x:-", IOdly_in_shf+3, IOdly_in_shf, IOdly_in);
+ }
+ else {
+ PRINT(OUT_OBJ "Rx:SCU48[%2d:%2d]=%01x: ", IOdly_in_shf+3, IOdly_in_shf, IOdly_in);
+ }
+#else
+ if (Enable_RMII) {
+ if (IOdly_out_reg == IOdly_out) {
+ PRINT(OUT_OBJ "Tx:SCU48[ %2d]=%01x:-", IOdly_out_shf, IOdly_out);
+ }
+ else {
+ PRINT(OUT_OBJ "Tx:SCU48[ %2d]=%01x: ", IOdly_out_shf, IOdly_out);
+ }
+ } else {
+ if (IOdly_out_reg == IOdly_out) {
+ PRINT(OUT_OBJ "Tx:SCU48[%2d:%2d]=%01x:-", IOdly_out_shf+3, IOdly_out_shf, IOdly_out);
+ }
+ else {
+ PRINT(OUT_OBJ "Tx:SCU48[%2d:%2d]=%01x: ", IOdly_out_shf+3, IOdly_out_shf, IOdly_out);
+ }
+ }
+#endif
+} // void PrintIO_LineS (BYTE option)
+
+//------------------------------------------------------------
+void PrintIO_Line (BYTE option) {
+
+ FILE_VAR
+
+ GET_OBJ( option )
+
+ if ( ( IOdly_in_reg == IOdly_in ) && ( IOdly_out_reg == IOdly_out ) ) {
+ if (dlymap[IOdly_i][IOdly_j]) PRINT(OUT_OBJ " X");
+ else PRINT(OUT_OBJ " O");
+ }
+ else {
+ if (dlymap[IOdly_i][IOdly_j]) PRINT(OUT_OBJ " x");
+ else PRINT(OUT_OBJ " o");
+ }
+} // End void PrintIO_Line (BYTE option)
+
+//------------------------------------------------------------
+void PrintIO_Line_LOG (void) {
+#ifndef SLT_UBOOT
+#ifdef Enable_Old_Style
+ if (Enable_RMII) fprintf(fp_log, "\nTx:SCU48[ %2d]=%2x, ", IOdly_out_shf, IOdly_out);
+ else fprintf(fp_log, "\nTx:SCU48[%2d:%2d]=%2x, ", IOdly_out_shf+3, IOdly_out_shf, IOdly_out);
+
+ fprintf(fp_log, "Rx:SCU48[%2d:%2d]=%01x: ", IOdly_in_shf+3, IOdly_in_shf, IOdly_in);
+
+ if (dlymap[IOdly_i][IOdly_j]) fprintf(fp_log, " X\n");
+ else fprintf(fp_log, " O\n");
+#else
+ fprintf(fp_log, "\nRx:SCU48[%2d:%2d]=%2x, ", IOdly_in_shf+3, IOdly_in_shf, IOdly_in);
+
+ if (Enable_RMII) fprintf(fp_log, "Tx:SCU48[ %2d]=%01x: ", IOdly_out_shf, IOdly_out);
+ else fprintf(fp_log, "Tx:SCU48[%2d:%2d]=%01x: ", IOdly_out_shf+3, IOdly_out_shf, IOdly_out);
+
+ if (dlymap[IOdly_i][IOdly_j]) fprintf(fp_log, " X\n");
+ else fprintf(fp_log, " O\n");
+#endif
+#endif
+}
+
+//------------------------------------------------------------
+// main
+//------------------------------------------------------------
+void Calculate_LOOP_CheckNum (void) {
+
+#define ONE_MBYTE 1048576
+
+ #ifdef CheckDataEveryTime
+ LOOP_CheckNum = 1;
+ #else
+ if (IOTiming || IOTimingBund || (GSpeed == SET_1G_100M_10MBPS)) {
+ LOOP_CheckNum = LOOP_MAX;
+ }
+ else {
+ switch ( GSpeed ) {
+ case SET_1GBPS : CheckBuf_MBSize = MOVE_DATA_MB_SEC ; break; // 1G
+ case SET_100MBPS : CheckBuf_MBSize = (MOVE_DATA_MB_SEC >> 3); break; // 100M ~ 1G / 8
+ case SET_10MBPS : CheckBuf_MBSize = (MOVE_DATA_MB_SEC >> 6); break; // 10M ~ 1G / 64
+ }
+ LOOP_CheckNum = ( CheckBuf_MBSize / ( ((DES_NUMBER * DMA_PakSize) / ONE_MBYTE ) + 1) );
+ }
+ #endif
+}
+
+//------------------------------------------------------------
+void TestingSetup (void) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("TestingSetup\n");
+ Debug_delay();
+ #endif
+
+ #ifdef SLT_UBOOT
+ #else
+ #ifdef Rand_Sed
+ srand((unsigned) Rand_Sed);
+ #else
+ srand((unsigned) timestart);
+ #endif
+ #endif
+
+ //[Disable VGA]--------------------
+ #ifdef Disable_VGA
+ if ( LOOP_INFINI & ~(BurstEnable || IOTiming) ) {
+ VGAModeVld = 1;
+ outp(0x3d4, 0x17);
+ VGAMode = inp(0x3d5);
+ outp(0x3d4, 0x17);
+ outp(0x3d5, 0);
+ }
+ #endif
+
+ //[Setup]--------------------
+ setup_framesize();
+ setup_buf();
+}
+
+//------------------------------------------------------------
+// Return 1 ==> fail
+// Return 0 ==> PASS
+//------------------------------------------------------------
+char TestingLoop (ULONG loop_checknum) {
+ char checkprd;
+ char looplast;
+ char checken;
+
+ #ifdef SLT_UBOOT
+ #else
+ clock_t timeold;
+ #endif
+
+ #ifdef DbgPrn_FuncHeader
+ printf ("TestingLoop: %d\n", Loop);
+ Debug_delay();
+ #endif
+
+ if ( DbgPrn_DumpMACCnt )
+ dump_mac_ROreg();
+
+ //[Setup]--------------------
+ Loop = 0;
+ checkprd = 0;
+ checken = 0;
+ looplast = 0;
+
+ setup_des( 0 );
+
+ #ifdef SLT_UBOOT
+ #else
+ timeold = clock();
+ #endif
+
+ while ( (Loop < LOOP_MAX) || LOOP_INFINI ) {
+ looplast = !LOOP_INFINI && (Loop == LOOP_MAX - 1);
+
+ #ifdef CheckRxBuf
+ if (!BurstEnable) {
+ checkprd = ((Loop % loop_checknum) == (loop_checknum - 1));
+ }
+ checken = looplast | checkprd;
+ #endif
+
+ if ( DataDelay & ( Loop == 0 ) ) {
+ printf ("Press any key to start...\n");
+ GET_CAHR();
+ }
+
+#ifdef DbgPrn_FuncHeader
+ if ( DbgPrn_BufAdr ) {
+ printf ("for start ======> %d/%d(%d) looplast:%d checkprd:%d checken:%d\n", Loop, LOOP_MAX, LOOP_INFINI, looplast, checkprd, checken);
+ Debug_delay();
+ }
+#endif
+
+ //[Check DES]--------------------
+ if ( check_des(Loop, checken) ) {
+ //descriptor error
+ #ifdef CheckRxBuf
+ DES_NUMBER = CheckDesFail_DesNum + 1;
+ if ( checkprd ) {
+ check_buf(loop_checknum);
+ }
+ else {
+ check_buf((LOOP_MAX % loop_checknum));
+ }
+ DES_NUMBER = DES_NUMBER_Org;
+ #endif
+
+ if (DbgPrn_DumpMACCnt)
+ dump_mac_ROreg();
+
+ return(1);
+ }
+
+ //[Check Buf]--------------------
+ if ( RxDataEnable && checken ) {
+ #ifdef SLT_UBOOT
+ #else
+ timeused = (clock() - timeold) / (double) CLK_TCK;
+ #endif
+
+ if ( checkprd ) {
+ #ifdef SLT_DOS
+ #else
+ #ifdef SLT_UBOOT
+ #else
+ printf("[run loop:%3d] BandWidth: %7.2f Mbps, %6.2f sec\n", loop_checknum, ((double)loop_checknum * (double)DES_NUMBER * Avg_frame_len * 8.0) / ((double)timeused * 1000000.0), timeused);
+ fprintf(fp_log, "[run loop:%3d] BandWidth: %7.2f Mbps, %6.2f sec\n", loop_checknum, ((double)loop_checknum * (double)DES_NUMBER * Avg_frame_len * 8.0) / ((double)timeused * 1000000.0), timeused);
+ #endif
+ #endif
+
+ #ifdef CheckRxBuf
+ if ( check_buf( loop_checknum ) )
+ return(1);
+ #endif
+ }
+ else {
+ #ifdef SLT_DOS
+ #else
+ #ifdef SLT_UBOOT
+ #else
+ printf("[run loop:%3d] BandWidth: %7.2f Mbps, %6.2f sec\n", (LOOP_MAX % loop_checknum), ((double)(LOOP_MAX % loop_checknum) * (double)DES_NUMBER * Avg_frame_len * 8.0) / ((double)timeused * 1000000.0), timeused);
+ fprintf(fp_log, "[run loop:%3d] BandWidth: %7.2f Mbps, %6.2f sec\n", (LOOP_MAX % loop_checknum), ((double)(LOOP_MAX % loop_checknum) * (double)DES_NUMBER * Avg_frame_len * 8.0) / ((double)timeused * 1000000.0), timeused);
+ #endif
+ #endif
+
+ #ifdef CheckRxBuf
+ if ( check_buf( ( LOOP_MAX % loop_checknum ) ) )
+ return(1);
+ #endif
+ } // End if ( checkprd )
+
+ #ifdef SelectSimpleDes
+ #else
+ if ( !looplast )
+ setup_des_loop( Loop );
+ #endif
+
+ #ifdef SLT_DOS
+ #else
+ #ifdef SLT_UBOOT
+ #else
+ timeold = clock();
+ #endif
+ #endif
+
+ } // End if ( RxDataEnable && checken )
+
+ #ifdef SelectSimpleDes
+ if ( !looplast )
+ setup_des_loop( Loop );
+ #endif
+
+ if ( LOOP_INFINI ) {
+ printf("===============> Loop: %d \r", Loop);
+ }
+ else if (TestMode == 0) {
+ if (!(DbgPrn_BufAdr || IOTimingBund))
+ printf(" %d \r", Loop);
+// switch (Loop % 4) {
+// case 0x00: printf("| %d \r", Loop); break;
+// case 0x01: printf("/ %d \r", Loop); break;
+// case 0x02: printf("- %d \r", Loop); break;
+// default : printf("\ %d \r", Loop); break;
+// }
+ }
+
+ if ( DbgPrn_BufAdr ) {
+ printf ("for end ======> %d/%d(%d)\n", Loop, LOOP_MAX, LOOP_INFINI);
+ Debug_delay();
+ }
+
+ Loop++;
+ } // End while ((Loop < LOOP_MAX) || LOOP_INFINI)
+
+ Loop_rl[GSpeed_idx] = Loop;
+
+ return(0);
+} // End char TestingLoop (ULONG loop_checknum)
diff --git a/arch/arm/cpu/arm926ejs/aspeed/Makefile b/arch/arm/cpu/arm926ejs/aspeed/Makefile new file mode 100644 index 0000000..4c4e239 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/Makefile @@ -0,0 +1,53 @@ +# 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$(SOC).o + +COBJS = timer.o +COBJS += reset.o +COBJS += mactest.o +COBJS += DRAM_SPI.o +COBJS += IO.o +COBJS += LIB.o +COBJS += MAC.o +COBJS += NCSI.o +COBJS += PCI_SPI.o +COBJS += PHY.o +COBJS += SPIM.o +COBJS += STDUBOOT.o +COBJS += PLLTESTU.o +COBJS += TRAPTEST.o +COBJS += STRESS.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/aspeed/NCSI.H b/arch/arm/cpu/arm926ejs/aspeed/NCSI.H new file mode 100644 index 0000000..a0e448b --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/NCSI.H @@ -0,0 +1,189 @@ +/* + * 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 + */ +#ifndef NCSI_H +#define NCSI_H + +#include "TYPEDEF.H" + +//--------------------------------------------------------- +// Define +//--------------------------------------------------------- +#define MAX_PACKAGE_NUM 8 // 1 ~ 8 +#define MAX_CHANNEL_NUM 4 // 1 ~ 32 +//#define Enable_NCSI_LOOP_INFINI //[off] + +//--------------------------------------------------------- +// Function +//--------------------------------------------------------- +#define SENT_RETRY_COUNT 1 +#define NCSI_RxDESNum 50 + +//#define NCSI_Skip_Phase1_DeSelectPackage +//#define NCSI_Skip_DeSelectPackage +//#define NCSI_Skip_DiSChannel +//#define NCSI_EnableDelay_DeSelectPackage +//#define NCSI_EnableDelay_GetLinkStatus +//#define NCSI_EnableDelay_EachPackage +//#define Print_Version_ID +//#define Print_PackageName + +//--------------------------------------------------------- +// PCI DID/VID & Manufacturer ID +//--------------------------------------------------------- +#define ManufacturerID_Intel 0x00000157 //343 +#define ManufacturerID_Broadcom 0x0000113d //4413 +#define ManufacturerID_Mellanox 0x000002c9 //713 + +//PCI VID: [163c]intel +//PCI VID: [8086]Intel Corporation +//PCI VID: [8087]Intel +//PCI VID: [14e4]Broadcom Corporation +//PCI VID: [15b3]Mellanox +#define PCI_DID_VID_Intel_82574L 0x10d38086 // IntelR 82574L Gigabit Ethernet Controller +#define PCI_DID_VID_Intel_82575_10d6 0x10d68086 // 82566 DM-2-gigabyte +#define PCI_DID_VID_Intel_82575_10a7 0x10a78086 // 82575EB Gigabit Network Connection +#define PCI_DID_VID_Intel_82575_10a9 0x10a98086 // 82575EB Gigabit Network Connection +#define PCI_DID_VID_Intel_82576_10c9 0x10c98086 //*82576 Gigabit ET Dual Port Server Adapter +#define PCI_DID_VID_Intel_82576_10e6 0x10e68086 // 82576 Gigabit Network Connection +#define PCI_DID_VID_Intel_82576_10e7 0x10e78086 // 82576 Gigabit Network Connection +#define PCI_DID_VID_Intel_82576_10e8 0x10e88086 // E64750-xxx Intel Gigabit ET Quad Port Server Adapter +#define PCI_DID_VID_Intel_82576_1518 0x15188086 // 82576NS SerDes Gigabit Network Connectio +#define PCI_DID_VID_Intel_82576_1526 0x15268086 // Intel Gigabit ET2 Quad Port Server Adapter +#define PCI_DID_VID_Intel_82576_150a 0x150a8086 // 82576NS Gigabit Ethernet Controller +#define PCI_DID_VID_Intel_82576_150d 0x150d8086 // 82576 Gigabit Backplane Connection +#define PCI_DID_VID_Intel_82599_10fb 0x10fb8086 // 10 Gb Ethernet controller +#define PCI_DID_VID_Intel_82599_1557 0x15578086 // +#define PCI_DID_VID_Intel_I350_1521 0x15218086 // +#define PCI_DID_VID_Intel_I350_1523 0x15238086 // +#define PCI_DID_VID_Intel_I210 0x15338086 // +#define PCI_DID_VID_Intel_X540 0x15288086 // +#define PCI_DID_VID_Broadcom_BCM5718 0x165614e4 // +#define PCI_DID_VID_Broadcom_BCM5720 0x165f14e4 // +#define PCI_DID_VID_Broadcom_BCM5725 0x164314e4 // +#define PCI_DID_VID_Mellanox_ConnectX_3 0x100315b3 //* + +//--------------------------------------------------------- +// Delay (ms) +//--------------------------------------------------------- +#define Delay_EachPackage 1000 +#define Delay_DeSelectPackage 50 +#define Delay_GetLinkStatus 50 + +//--------------------------------------------------------- +// NCSI Parameter +//--------------------------------------------------------- +//Command and Response Type +#define CLEAR_INITIAL_STATE 0x00 //M +#define SELECT_PACKAGE 0x01 //M +#define DESELECT_PACKAGE 0x02 //M +#define ENABLE_CHANNEL 0x03 //M +#define DISABLE_CHANNEL 0x04 //M +#define RESET_CHANNEL 0x05 //M +#define ENABLE_CHANNEL_NETWORK_TX 0x06 //M +#define DISABLE_CHANNEL_NETWORK_TX 0x07 //M +#define AEN_ENABLE 0x08 +#define SET_LINK 0x09 //M +#define GET_LINK_STATUS 0x0A //M +#define SET_VLAN_FILTER 0x0B //M +#define ENABLE_VLAN 0x0C //M +#define DISABLE_VLAN 0x0D //M +#define SET_MAC_ADDRESS 0x0E //M +#define ENABLE_BROADCAST_FILTERING 0x10 //M +#define DISABLE_BROADCAST_FILTERING 0x11 //M +#define ENABLE_GLOBAL_MULTICAST_FILTERING 0x12 +#define DISABLE_GLOBAL_MULTICAST_FILTERING 0x13 +#define SET_NCSI_FLOW_CONTROL 0x14 +#define GET_VERSION_ID 0x15 //M +#define GET_CAPABILITIES 0x16 //M +#define GET_PARAMETERS 0x17 //M +#define GET_CONTROLLER_PACKET_STATISTICS 0x18 +#define GET_NCSI_STATISTICS 0x19 +#define GET_NCSI_PASS_THROUGH_STATISTICS 0x1A + +//Standard Response Code +#define COMMAND_COMPLETED 0x00 +#define COMMAND_FAILED 0x01 +#define COMMAND_UNAVAILABLE 0x02 +#define COMMAND_UNSUPPORTED 0x03 + +//Standard Reason Code +#define NO_ERROR 0x0000 +#define INTERFACE_INITIALIZATION_REQUIRED 0x0001 +#define PARAMETER_IS_INVALID 0x0002 +#define CHANNEL_NOT_READY 0x0003 +#define PACKAGE_NOT_READY 0x0004 +#define INVALID_PAYLOAD_LENGTH 0x0005 +#define UNKNOWN_COMMAND_TYPE 0x7FFF + +//SET_MAC_ADDRESS +#define UNICAST ( 0x00 << 5 ) +#define MULTICAST ( 0x01 << 5 ) +#define DISABLE_MAC_ADDRESS_FILTER 0x00 +#define ENABLE_MAC_ADDRESS_FILTER 0x01 + +//GET_LINK_STATUS +#define LINK_DOWN 0 +#define LINK_UP 1 + +#define NCSI_RxDMA_PakSize 2048 +#define NCSI_RxDMA_BASE (DMA_BASE+0x00100000) + +//--------------------------------------------------------- +// Variable +//--------------------------------------------------------- +//NC-SI Command Packet +typedef struct { +//Ethernet Header + unsigned char DA[6]; // Destination Address + unsigned char SA[6]; // Source Address + unsigned short EtherType; // DMTF NC-SI, it should be 0x88F8 +//NC-SI Control Packet + unsigned char MC_ID; // Management Controller should set this field to 0x00 + unsigned char Header_Revision; // For NC-SI 1.0 spec, this field has to set 0x01 + unsigned char Reserved_1; // Reserved has to set to 0x00 + unsigned char IID; // Instance ID + unsigned char Command; + unsigned char Channel_ID; + unsigned short Payload_Length; // Payload Length = 12 bits, 4 bits are reserved + unsigned long Reserved_2; + unsigned long Reserved_3; + + unsigned short Reserved_4; + unsigned short Reserved_5; + unsigned short Response_Code; + unsigned short Reason_Code; + unsigned char Payload_Data[64]; +} NCSI_Command_Packet; + +//NC-SI Response Packet +typedef struct { + unsigned char DA[6]; + unsigned char SA[6]; + unsigned short EtherType; //DMTF NC-SI +//NC-SI Control Packet + unsigned char MC_ID; //Management Controller should set this field to 0x00 + unsigned char Header_Revision; //For NC-SI 1.0 spec, this field has to set 0x01 + unsigned char Reserved_1; //Reserved has to set to 0x00 + unsigned char IID; //Instance ID + unsigned char Command; + unsigned char Channel_ID; + unsigned short Payload_Length; //Payload Length = 12 bits, 4 bits are reserved + unsigned short Reserved_2; + unsigned short Reserved_3; + unsigned short Reserved_4; + unsigned short Reserved_5; + + unsigned short Response_Code; + unsigned short Reason_Code; + unsigned char Payload_Data[64]; +} NCSI_Response_Packet; + +#endif // NCSI_H diff --git a/arch/arm/cpu/arm926ejs/aspeed/NCSI.c b/arch/arm/cpu/arm926ejs/aspeed/NCSI.c new file mode 100644 index 0000000..7e86fb6 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/NCSI.c @@ -0,0 +1,934 @@ +/* + * 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 + */ +#define NCSI_C +static const char ThisFile[] = "NCSI.c"; + +#include "SWFUNC.H" + +#ifdef SLT_UBOOT + #include <common.h> + #include <command.h> + #include "COMMINF.H" + #include "NCSI.H" + #include "IO.H" +#endif +#ifdef SLT_DOS + #include <stdio.h> + #include <stdlib.h> + #include <conio.h> + #include <string.h> + #include "COMMINF.H" + #include "NCSI.H" + #include "IO.H" +#endif + +NCSI_Command_Packet NCSI_Request_SLT; +NCSI_Response_Packet NCSI_Respond_SLT; +int InstanceID; +int NCSI_RxTimeOutScale; +ULONG NCSI_RxDesBase; +ULONG NCSI_TxDWBUF[512]; +ULONG NCSI_RxDWBUF[512]; +char NCSI_CommandStr[512]; +unsigned char *NCSI_TxByteBUF; +unsigned char *NCSI_RxByteBUF; +unsigned char NCSI_Payload_Data[16]; +unsigned long Payload_Checksum_NCSI = 0x00000000; +ULONG select_flag[MAX_PACKAGE_NUM]; + +ULONG DWSwap_SLT (ULONG in) { + return( ((in & 0xff000000) >> 24) + | ((in & 0x00ff0000) >> 8) + | ((in & 0x0000ff00) << 8) + | ((in & 0x000000ff) << 24) + ); +} +USHORT WDSwap_SLT (USHORT in) { + return( ((in & 0xff00) >> 8) + | ((in & 0x00ff) << 8) + ); +} + +//------------------------------------------------------------ +int FindErr_NCSI (int value) { + NCSI_LinkFail_Val = NCSI_LinkFail_Val | value; + Err_Flag = Err_Flag | Err_NCSI_LinkFail; + if ( DbgPrn_ErrFlg ) + printf ("\nErr_Flag: [%08lx] NCSI_LinkFail_Val: [%08lx]\n", Err_Flag, NCSI_LinkFail_Val); + + return(1); +} + +//------------------------------------------------------------ +// PHY IC(NC-SI) +//------------------------------------------------------------ +void ncsi_respdump ( NCSI_Response_Packet *in ) { + printf ("DA : %02x %02x %02x %02x %02x %02x\n", in->DA[5], in->DA[4], in->DA[3], in->DA[2], in->DA[1], in->DA[0]); + printf ("SA : %02x %02x %02x %02x %02x %02x\n", in->SA[5], in->SA[4], in->SA[3], in->SA[2], in->SA[1], in->SA[0]); + printf ("EtherType : %04x\n", in->EtherType );//DMTF NC-SI + printf ("MC_ID : %02x\n", in->MC_ID );//Management Controller should set this field to 0x00 + printf ("Header_Revision: %02x\n", in->Header_Revision );//For NC-SI 1.0 spec, this field has to set 0x01 +// printf ("Reserved_1 : %02x\n", in->Reserved_1 ); //Reserved has to set to 0x00 + printf ("IID : %02x\n", in->IID );//Instance ID + printf ("Command : %02x\n", in->Command ); + printf ("Channel_ID : %02x\n", in->Channel_ID ); + printf ("Payload_Length : %04x\n", in->Payload_Length );//Payload Length = 12 bits, 4 bits are reserved +// printf ("Reserved_2 : %04x\n", in->Reserved_2 ); +// printf ("Reserved_3 : %04x\n", in->Reserved_3 ); +// printf ("Reserved_4 : %04x\n", in->Reserved_4 ); +// printf ("Reserved_5 : %04x\n", in->Reserved_5 ); + printf ("Response_Code : %04x\n", in->Response_Code ); + printf ("Reason_Code : %04x\n", in->Reason_Code ); + printf ("Payload_Data : %02x%02x%02x%02x\n", in->Payload_Data[ 3], in->Payload_Data[ 2], in->Payload_Data[ 1], in->Payload_Data[ 0]); +// printf ("Payload_Data : %02x%02x%02x%02x\n", in->Payload_Data[ 7], in->Payload_Data[ 6], in->Payload_Data[ 5], in->Payload_Data[ 4]); +// printf ("Payload_Data : %02x%02x%02x%02x\n", in->Payload_Data[11], in->Payload_Data[10], in->Payload_Data[ 9], in->Payload_Data[ 8]); +// printf ("Payload_Data : %02x%02x%02x%02x\n", in->Payload_Data[15], in->Payload_Data[14], in->Payload_Data[13], in->Payload_Data[12]); +// printf ("Payload_Data : %02x%02x%02x%02x\n", in->Payload_Data[19], in->Payload_Data[18], in->Payload_Data[17], in->Payload_Data[16]); +// printf ("Payload_Data : %02x%02x%02x%02x\n", in->Payload_Data[23], in->Payload_Data[22], in->Payload_Data[21], in->Payload_Data[20]); +} + +//------------------------------------------------------------ +void NCSI_Struct_Initialize_SLT (void) { + int i; + + ULONG NCSI_RxDatBase; + + InstanceID = 0; + NCSI_RxTimeOutScale = 1; + + for (i = 0; i < 6; i++) { + NCSI_Request_SLT.DA[i] = 0xFF; + } + + for (i = 0; i < 6; i++) { +// NCSI_Request.SA[i] = i<<2; + NCSI_Request_SLT.SA[i] = SA[i]; + } + + NCSI_Request_SLT.EtherType = WDSwap_SLT(0x88F8); // EtherType = 0x88F8 (DMTF NC-SI) page 50, table 8, NC-SI spec. version 1.0.0 + NCSI_Request_SLT.MC_ID = 0; + NCSI_Request_SLT.Header_Revision = 0x01; + NCSI_Request_SLT.Reserved_1 = 0; + NCSI_Request_SLT.Reserved_2 = 0; + NCSI_Request_SLT.Reserved_3 = 0; + + NCSI_TxByteBUF = (unsigned char *) &NCSI_TxDWBUF[0]; + NCSI_RxByteBUF = (unsigned char *) &NCSI_RxDWBUF[0]; + + NCSI_RxDesBase = H_RDES_BASE; + NCSI_RxDatBase = NCSI_RxDMA_BASE; + + for (i = 0; i < NCSI_RxDESNum - 1; i++) { + WriteSOC_DD( ( NCSI_RxDesBase + 0 ), 0x00000000 ); + WriteSOC_DD( ( NCSI_RxDesBase + 4 ), 0x00000000 ); + WriteSOC_DD( ( NCSI_RxDesBase + 8 ), 0x00000000 ); + WriteSOC_DD( ( NCSI_RxDesBase + 0x0C ), (NCSI_RxDatBase + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730 + NCSI_RxDesBase += 16; + NCSI_RxDatBase += NCSI_RxDMA_PakSize; + } + WriteSOC_DD( ( NCSI_RxDesBase + 0 ), EOR_IniVal ); + WriteSOC_DD( ( NCSI_RxDesBase + 4 ), 0x00000000 ); + WriteSOC_DD( ( NCSI_RxDesBase + 8 ), 0x00000000 ); + WriteSOC_DD( ( NCSI_RxDesBase + 0x0C ), (NCSI_RxDatBase + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730 + + NCSI_RxDesBase = H_RDES_BASE; +} + +//------------------------------------------------------------ +void Calculate_Checksum_NCSI (unsigned char *buffer_base, int Length) { + ULONG CheckSum = 0; + ULONG Data; + ULONG Data1; + int i; + + // Calculate checksum is from byte 14 of ethernet Haeder and Control packet header + // Page 50, NC-SI spec. ver. 1.0.0 form DMTF + for (i = 14; i < Length; i += 2 ) { + Data = buffer_base[i]; + Data1 = buffer_base[i + 1]; + CheckSum += ((Data << 8) + Data1); + } + Payload_Checksum_NCSI = DWSwap_SLT(~(CheckSum) + 1); //2's complement +} + +//------------------------------------------------------------ +// return 0: it is PASS +// return 1: it is FAIL +//------------------------------------------------------------ +char NCSI_Rx_SLT (unsigned char command) { + +#define NCSI_RX_RETRY_TIME 2 + int timeout = 0; + int bytesize; + int dwsize; + int i; + int retry = 0; + char ret = 1; + + ULONG NCSI_RxDatBase; + ULONG NCSI_RxDesDat; + ULONG NCSI_RxData; + + + do { + WriteSOC_DD( ( H_MAC_BASE + 0x1C ), 0x00000000 );//Rx Poll + + do { + NCSI_RxDesDat = ReadSOC_DD(NCSI_RxDesBase); + if ( ++timeout > TIME_OUT_NCSI * NCSI_RxTimeOutScale ) { + #ifdef SLT_DOS + fprintf(fp_log, "[Cmd:%02X][NCSI-RxDesOwn] %08lX \n", command, NCSI_RxDesDat ); + #endif + return( FindErr(Err_NCSI_Check_RxOwnTimeOut) ); + } + } while( HWOwnRx(NCSI_RxDesDat) ); + + #ifdef CheckRxErr + if (NCSI_RxDesDat & 0x00040000) { + #ifdef SLT_DOS + fprintf(fp_log, "[RxDes] Error RxErr %08lx\n", NCSI_RxDesDat); + #endif + FindErr_Des(Check_Des_RxErr); + } + #endif + + #ifdef CheckOddNibble + if (NCSI_RxDesDat & 0x00400000) { + #ifdef SLT_DOS + fprintf(fp_log, "[RxDes] Odd Nibble %08lx\n", NCSI_RxDesDat); + #endif + FindErr_Des(Check_Des_OddNibble); + } + #endif + + #ifdef CheckCRC + if (NCSI_RxDesDat & 0x00080000) { + #ifdef SLT_DOS + fprintf(fp_log, "[RxDes] Error CRC %08lx\n", NCSI_RxDesDat); + #endif + FindErr_Des(Check_Des_CRC); + } + #endif + + #ifdef CheckRxFIFOFull + if (NCSI_RxDesDat & 0x00800000) { + #ifdef SLT_DOS + fprintf(fp_log, "[RxDes] Error Rx FIFO Full %08lx\n", NCSI_RxDesDat); + #endif + FindErr_Des(Check_Des_RxFIFOFull); + } + #endif + + // Get point of RX DMA buffer + NCSI_RxDatBase = ReadSOC_DD( NCSI_RxDesBase + 0x0C ); + NCSI_RxData = ReadSOC_DD( NCSI_RxDatBase + 0x0C ); + + if ( HWEOR( NCSI_RxDesDat ) ) { + // it is last the descriptor in the receive Ring + WriteSOC_DD( NCSI_RxDesBase , EOR_IniVal ); + NCSI_RxDesBase = H_RDES_BASE; + } + else { + WriteSOC_DD( NCSI_RxDesBase , 0x00000000 ); + NCSI_RxDesBase += 16; + } + + // Get RX valid data in offset 00h of RXDS#0 + bytesize = (NCSI_RxDesDat & 0x3fff); + + // Fill up to multiple of 4 + if ( ( bytesize % 4 ) != 0 ) + dwsize = ( bytesize >> 2 ) + 1; + else + dwsize = bytesize >> 2; + + #ifdef SLT_DOS + if ( PrintNCSIEn ) + fprintf(fp_log ,"[Rx] %d bytes(%xh)\n", bytesize, bytesize); + #endif + + for (i = 0; i < dwsize; i++) { + NCSI_RxDWBUF[i] = ReadSOC_DD(NCSI_RxDatBase + ( i << 2 )); + if ( PrintNCSIEn ) { + if ( i == ( dwsize - 1 ) ) { + switch (bytesize % 4) { + case 0 : NCSI_RxDWBUF[i] = NCSI_RxDWBUF[i] & 0xffffffff; break; + case 3 : NCSI_RxDWBUF[i] = NCSI_RxDWBUF[i] & 0xffffff ; break; + case 2 : NCSI_RxDWBUF[i] = NCSI_RxDWBUF[i] & 0xffff ; break; + case 1 : NCSI_RxDWBUF[i] = NCSI_RxDWBUF[i] & 0xff ; break; + } + #ifdef SLT_DOS + switch (bytesize % 4) { + case 0 : fprintf(fp_log ,"[Rx%02d]%08lx %08lx\n", i, NCSI_RxDWBUF[i], DWSwap_SLT(NCSI_RxDWBUF[i]) ); break; + case 3 : fprintf(fp_log ,"[Rx%02d]--%06lx %06lx--\n", i, NCSI_RxDWBUF[i], DWSwap_SLT(NCSI_RxDWBUF[i]) >> 8 ); break; + case 2 : fprintf(fp_log ,"[Rx%02d]----%04lx %04lx----\n", i, NCSI_RxDWBUF[i], DWSwap_SLT(NCSI_RxDWBUF[i]) >> 16 ); break; + case 1 : fprintf(fp_log ,"[Rx%02d]------%02lx %02lx------\n", i, NCSI_RxDWBUF[i], DWSwap_SLT(NCSI_RxDWBUF[i]) >> 24 ); break; + default : fprintf(fp_log ,"[Rx%02d]error", i); break; + } + #endif + } + else { + #ifdef SLT_DOS + fprintf(fp_log ,"[Rx%02d]%08lx %08lx\n", i, NCSI_RxDWBUF[i], DWSwap_SLT(NCSI_RxDWBUF[i])); + #endif + } + } + } // End for (i = 0; i < dwsize; i++) + + // EtherType field of the response packet should be 0x88F8 + if ((NCSI_RxData & 0xffff) == 0xf888) { + memcpy (&NCSI_Respond_SLT, NCSI_RxByteBUF, bytesize); + + #ifdef SLT_DOS + if ( PrintNCSIEn ) + fprintf(fp_log ,"[Rx IID:%2d]\n", NCSI_Respond_SLT.IID); + #endif + + NCSI_Respond_SLT.EtherType = WDSwap_SLT( NCSI_Respond_SLT.EtherType ); + NCSI_Respond_SLT.Payload_Length = WDSwap_SLT( NCSI_Respond_SLT.Payload_Length ); + NCSI_Respond_SLT.Response_Code = WDSwap_SLT( NCSI_Respond_SLT.Response_Code ); + NCSI_Respond_SLT.Reason_Code = WDSwap_SLT( NCSI_Respond_SLT.Reason_Code ); + + ret = 0; + break; + } + else { + #ifdef SLT_DOS + if ( PrintNCSIEn ) + fprintf(fp_log, "[Skip] Not NCSI Response: %08lx\n", NCSI_RxData); + #endif + + retry++; + } + } while ( retry < NCSI_RX_RETRY_TIME ); + + return( ret ); +} // End char NCSI_Rx_SLT (void) + +//------------------------------------------------------------ +char NCSI_Tx (void) { + int bytesize; + int dwsize; + int i; + int timeout = 0; + ULONG NCSI_TxDesDat; + + // Header of NC-SI command format is 34 bytes. page 58, NC-SI spec. ver 1.0.0 from DMTF + // The minimum size of a NC-SI package is 64 bytes. + bytesize = 34 + WDSwap_SLT(NCSI_Request_SLT.Payload_Length); + if ( bytesize < 64 ) { + memset (NCSI_TxByteBUF + bytesize, 0, 60 - bytesize); + bytesize = 64; + } + + // Fill up to multiple of 4 +// dwsize = (bytesize + 3) >> 2; + if ( ( bytesize % 4 ) != 0 ) + dwsize = ( bytesize >> 2 ) + 1; + else + dwsize = bytesize >> 2; + + #ifdef SLT_DOS + if ( PrintNCSIEn ) + fprintf(fp_log ,"[Tx IID:%2d] %d bytes(%xh)\n", NCSI_Request_SLT.IID, bytesize, bytesize); + #endif + + // Copy data to DMA buffer + for (i = 0; i < dwsize; i++) { + WriteSOC_DD( DMA_BASE + (i << 2), NCSI_TxDWBUF[i] ); + if ( PrintNCSIEn ) { + if (i == (dwsize - 1)) { + switch (bytesize % 4) { + case 0 : NCSI_TxDWBUF[i] = NCSI_TxDWBUF[i] & 0xffffffff; break; + case 3 : NCSI_TxDWBUF[i] = NCSI_TxDWBUF[i] & 0x00ffffff; break; + case 2 : NCSI_TxDWBUF[i] = NCSI_TxDWBUF[i] & 0x0000ffff; break; + case 1 : NCSI_TxDWBUF[i] = NCSI_TxDWBUF[i] & 0x000000ff; break; + } + #ifdef SLT_DOS + switch (bytesize % 4) { + case 0 : fprintf(fp_log ,"[Tx%02d]%08x %08x\n", i, NCSI_TxDWBUF[i], DWSwap_SLT( NCSI_TxDWBUF[i]) ); break; + case 3 : fprintf(fp_log ,"[Tx%02d]--%06x %06x--\n", i, NCSI_TxDWBUF[i], DWSwap_SLT( NCSI_TxDWBUF[i]) >> 8 ); break; + case 2 : fprintf(fp_log ,"[Tx%02d]----%04x %04x----\n", i, NCSI_TxDWBUF[i], DWSwap_SLT( NCSI_TxDWBUF[i]) >> 16 ); break; + case 1 : fprintf(fp_log ,"[Tx%02d]------%02x %02x------\n", i, NCSI_TxDWBUF[i], DWSwap_SLT( NCSI_TxDWBUF[i]) >> 24 ); break; + default : fprintf(fp_log ,"[Tx%02d]error", i); break; + } + #endif + } + else { + #ifdef SLT_DOS + fprintf( fp_log , "[Tx%02d]%08x %08x\n", i, NCSI_TxDWBUF[i], DWSwap_SLT(NCSI_TxDWBUF[i]) ); + #endif + } + } + } // End for (i = 0; i < dwsize; i++) + + // Setting one TX descriptor + WriteSOC_DD( H_TDES_BASE + 0x04, 0 ); + WriteSOC_DD( H_TDES_BASE + 0x08, 0 ); + WriteSOC_DD( H_TDES_BASE + 0x0C, (DMA_BASE + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730 + WriteSOC_DD( H_TDES_BASE , 0xf0008000 + bytesize ); + // Fire + WriteSOC_DD( H_MAC_BASE + 0x18, 0x00000000 );//Tx Poll + + do { + NCSI_TxDesDat = ReadSOC_DD(H_TDES_BASE); + if ( ++timeout > TIME_OUT_NCSI ) { + #ifdef SLT_DOS + fprintf(fp_log, "[NCSI-TxDesOwn] %08lx\n", NCSI_TxDesDat); + #endif + + return(FindErr(Err_NCSI_Check_TxOwnTimeOut)); + } + } while ( HWOwnTx(NCSI_TxDesDat) ); + + return(0); +} // End char NCSI_Tx (void) + +//------------------------------------------------------------ +char NCSI_ARP (void) { + int i; + int timeout = 0; + ULONG NCSI_TxDesDat; + + if ( ARPNumCnt ) { + #ifdef SLT_DOS + if ( PrintNCSIEn ) + fprintf(fp_log ,"[ARP] 60 bytes x%d\n", ARPNumCnt); + #endif + + for (i = 0; i < 15; i++) { + #ifdef SLT_DOS + if ( PrintNCSIEn ) + fprintf(fp_log ,"[Tx%02d] %08x %08x\n", i, ARP_data[i], DWSwap_SLT(ARP_data[i])); + #endif + WriteSOC_DD( DMA_BASE + ( i << 2 ), ARP_data[i] ); + } + WriteSOC_DD( H_TDES_BASE + 0x04, 0 ); + WriteSOC_DD( H_TDES_BASE + 0x08, 0 ); + WriteSOC_DD( H_TDES_BASE + 0x0C, (DMA_BASE + CPU_BUS_ADDR_SDRAM_OFFSET) ); // 20130730 + WriteSOC_DD( H_TDES_BASE , 0xf0008000 + 60 ); + + for (i = 0; i < ARPNumCnt; i++) { + WriteSOC_DD( H_TDES_BASE , 0xf0008000 + 60); + + WriteSOC_DD( H_MAC_BASE + 0x18, 0x00000000 );//Tx Poll + + timeout = 0; + do { + NCSI_TxDesDat = ReadSOC_DD(H_TDES_BASE); + + if (++timeout > TIME_OUT_NCSI) { + #ifdef SLT_DOS + fprintf(fp_log, "[ARP-TxDesOwn] %08lx\n", NCSI_TxDesDat); + #endif + + return(FindErr(Err_NCSI_Check_ARPOwnTimeOut)); + } + } while (HWOwnTx(NCSI_TxDesDat)); + } + } + return(0); +} // End char NCSI_ARP (void) + +//------------------------------------------------------------ +void WrRequest (unsigned char command, unsigned char id, unsigned short length) { + + NCSI_Request_SLT.IID = InstanceID; + NCSI_Request_SLT.Command = command; + NCSI_Request_SLT.Channel_ID = id; + NCSI_Request_SLT.Payload_Length = WDSwap_SLT(length); + + memcpy ( NCSI_TxByteBUF , &NCSI_Request_SLT , 30 ); + memcpy ((NCSI_TxByteBUF + 30 ), &NCSI_Payload_Data , length); + Calculate_Checksum_NCSI(NCSI_TxByteBUF, 30 + length); + memcpy ((NCSI_TxByteBUF + 30 + length), &Payload_Checksum_NCSI, 4 ); +} + +//------------------------------------------------------------ +void NCSI_PrintCommandStr (unsigned char command, unsigned iid) { + switch (command & 0x80) { + case 0x80 : sprintf(NCSI_CommandStr, "IID:%3d [%02x][Respond]", iid, command); break; + default : sprintf(NCSI_CommandStr, "IID:%3d [%02x][Request]", iid, command); break; + } + switch (command & 0x7f) { + case 0x00 : sprintf(NCSI_CommandStr, "%s[CLEAR_INITIAL_STATE ]", NCSI_CommandStr); break; + case 0x01 : sprintf(NCSI_CommandStr, "%s[SELECT_PACKAGE ]", NCSI_CommandStr); break; + case 0x02 : sprintf(NCSI_CommandStr, "%s[DESELECT_PACKAGE ]", NCSI_CommandStr); break; + case 0x03 : sprintf(NCSI_CommandStr, "%s[ENABLE_CHANNEL ]", NCSI_CommandStr); break; + case 0x04 : sprintf(NCSI_CommandStr, "%s[DISABLE_CHANNEL ]", NCSI_CommandStr); break; + case 0x05 : sprintf(NCSI_CommandStr, "%s[RESET_CHANNEL ]", NCSI_CommandStr); break; + case 0x06 : sprintf(NCSI_CommandStr, "%s[ENABLE_CHANNEL_NETWORK_TX ]", NCSI_CommandStr); break; + case 0x07 : sprintf(NCSI_CommandStr, "%s[DISABLE_CHANNEL_NETWORK_TX ]", NCSI_CommandStr); break; + case 0x08 : sprintf(NCSI_CommandStr, "%s[AEN_ENABLE ]", NCSI_CommandStr); break; + case 0x09 : sprintf(NCSI_CommandStr, "%s[SET_LINK ]", NCSI_CommandStr); break; + case 0x0A : sprintf(NCSI_CommandStr, "%s[GET_LINK_STATUS ]", NCSI_CommandStr); break; + case 0x0B : sprintf(NCSI_CommandStr, "%s[SET_VLAN_FILTER ]", NCSI_CommandStr); break; + case 0x0C : sprintf(NCSI_CommandStr, "%s[ENABLE_VLAN ]", NCSI_CommandStr); break; + case 0x0D : sprintf(NCSI_CommandStr, "%s[DISABLE_VLAN ]", NCSI_CommandStr); break; + case 0x0E : sprintf(NCSI_CommandStr, "%s[SET_MAC_ADDRESS ]", NCSI_CommandStr); break; + case 0x10 : sprintf(NCSI_CommandStr, "%s[ENABLE_BROADCAST_FILTERING ]", NCSI_CommandStr); break; + case 0x11 : sprintf(NCSI_CommandStr, "%s[DISABLE_BROADCAST_FILTERING ]", NCSI_CommandStr); break; + case 0x12 : sprintf(NCSI_CommandStr, "%s[ENABLE_GLOBAL_MULTICAST_FILTERING ]", NCSI_CommandStr); break; + case 0x13 : sprintf(NCSI_CommandStr, "%s[DISABLE_GLOBAL_MULTICAST_FILTERING ]", NCSI_CommandStr); break; + case 0x14 : sprintf(NCSI_CommandStr, "%s[SET_NCSI_FLOW_CONTROL ]", NCSI_CommandStr); break; + case 0x15 : sprintf(NCSI_CommandStr, "%s[GET_VERSION_ID ]", NCSI_CommandStr); break; + case 0x16 : sprintf(NCSI_CommandStr, "%s[GET_CAPABILITIES ]", NCSI_CommandStr); break; + case 0x17 : sprintf(NCSI_CommandStr, "%s[GET_PARAMETERS ]", NCSI_CommandStr); break; + case 0x18 : sprintf(NCSI_CommandStr, "%s[GET_CONTROLLER_PACKET_STATISTICS ]", NCSI_CommandStr); break; + case 0x19 : sprintf(NCSI_CommandStr, "%s[GET_NCSI_STATISTICS ]", NCSI_CommandStr); break; + case 0x1A : sprintf(NCSI_CommandStr, "%s[GET_NCSI_PASS_THROUGH_STATISTICS ]", NCSI_CommandStr); break; + case 0x50 : sprintf(NCSI_CommandStr, "%s[OEM_COMMAND ]", NCSI_CommandStr); break; + default : sprintf(NCSI_CommandStr, "%s Not Support Command", NCSI_CommandStr); break ; + } +} // End void NCSI_PrintCommandStr (unsigned char command, unsigned iid) + +//------------------------------------------------------------ +void NCSI_PrintCommandType (unsigned char command, unsigned iid) { + NCSI_PrintCommandStr(command, iid); + printf ("%s\n", NCSI_CommandStr); +} + +//------------------------------------------------------------ +void NCSI_PrintCommandType2File (unsigned char command, unsigned iid) { + NCSI_PrintCommandStr(command, iid); + #ifdef SLT_DOS + fprintf(fp_log, "%s\n", NCSI_CommandStr); + #endif +} + +//------------------------------------------------------------ +char NCSI_SentWaitPacket (unsigned char command, unsigned char id, unsigned short length) { + int Retry = 0; + char ret; + + do { + InstanceID++; + WrRequest(command, id, length); + + ret = NCSI_Tx();
if ( ret != 0 ) + { + // printf("======> NCSI_Tx return code = %X\n", ret ); + return(1); + }
+#ifdef Print_PackageName + NCSI_PrintCommandType(command, InstanceID); +#endif + +#ifdef NCSI_EnableDelay_EachPackage + delay(Delay_EachPackage); +#endif + if ( NCSI_Rx_SLT( command ) ) + return(2); + + #ifdef SLT_DOS + if ( PrintNCSIEn ) + fprintf(fp_log, "[Request] ETyp:%04x MC_ID:%02x HeadVer:%02x IID:%02x Comm:%02x ChlID:%02x PayLen:%04x\n", WDSwap_SLT(NCSI_Request_SLT.EtherType), + NCSI_Request_SLT.MC_ID, + NCSI_Request_SLT.Header_Revision, + NCSI_Request_SLT.IID, + NCSI_Request_SLT.Command, + NCSI_Request_SLT.Channel_ID, + WDSwap_SLT(NCSI_Request_SLT.Payload_Length) ); + if ( PrintNCSIEn ) + fprintf(fp_log, "[Respond] ETyp:%04x MC_ID:%02x HeadVer:%02x IID:%02x Comm:%02x ChlID:%02x PayLen:%04x ResCd:%02x ReaCd:%02x\n", + NCSI_Respond_SLT.EtherType, + NCSI_Respond_SLT.MC_ID, + NCSI_Respond_SLT.Header_Revision, + NCSI_Respond_SLT.IID, + NCSI_Respond_SLT.Command, + NCSI_Respond_SLT.Channel_ID, + NCSI_Respond_SLT.Payload_Length, + NCSI_Respond_SLT.Response_Code, + NCSI_Respond_SLT.Reason_Code); + #endif + + if ( (NCSI_Respond_SLT.IID != InstanceID) || + (NCSI_Respond_SLT.Command != (command | 0x80)) || + (NCSI_Respond_SLT.Response_Code != COMMAND_COMPLETED) ) { + #ifdef SLT_DOS + if ( PrintNCSIEn ) + fprintf(fp_log, "Retry: Command = %x, Response_Code = %x\n", NCSI_Request_SLT.Command, NCSI_Respond_SLT.Response_Code); + + #endif + Retry++; + } + else { + if ( PrintNCSIEn ) + NCSI_PrintCommandType2File(command, InstanceID); + + return(0); + } + } while (Retry <= SENT_RETRY_COUNT); + + return( 3 ); +} // End char NCSI_SentWaitPacket (unsigned char command, unsigned char id, unsigned short length) + +//------------------------------------------------------------ +char Clear_Initial_State_SLT (int Channel_ID) {//Command:0x00 + return(NCSI_SentWaitPacket(CLEAR_INITIAL_STATE, (NCSI_Cap_SLT.Package_ID << 5) + Channel_ID, 0));//Internal Channel ID = 0 +} + +//------------------------------------------------------------ +char Select_Package_SLT (int Package_ID) {//Command:0x01 + memset ((void *)NCSI_Payload_Data, 0, 4); + NCSI_Payload_Data[3] = 1; //Arbitration Disable + + return(NCSI_SentWaitPacket(SELECT_PACKAGE, (Package_ID << 5) + 0x1F, 4));//Internal Channel ID = 0x1F, 0x1F means all channel +} + +//------------------------------------------------------------ +void Select_Active_Package_SLT (void) {//Command:0x01 + memset ((void *)NCSI_Payload_Data, 0, 4); + NCSI_Payload_Data[3] = 1; //Arbitration Disable + + if (NCSI_SentWaitPacket(SELECT_PACKAGE, (NCSI_Cap_SLT.Package_ID << 5) + 0x1F, 4)) {//Internal Channel ID = 0x1F + FindErr_NCSI(NCSI_LinkFail_Select_Active_Package); + } +} + +//------------------------------------------------------------ +void DeSelect_Package_SLT (int Package_ID) {//Command:0x02 + NCSI_SentWaitPacket(DESELECT_PACKAGE, (Package_ID << 5) + 0x1F, 0);//Internal Channel ID = 0x1F, 0x1F means all channel + +#ifdef NCSI_EnableDelay_DeSelectPackage + delay(Delay_DeSelectPackage); +#endif +} + +//------------------------------------------------------------ +void Enable_Channel_SLT (void) {//Command:0x03 + if ( NCSI_SentWaitPacket(ENABLE_CHANNEL, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 0) ) { + FindErr_NCSI(NCSI_LinkFail_Enable_Channel); + } +} + +//------------------------------------------------------------ +void Disable_Channel_SLT (void) {//Command:0x04 + memset ((void *)NCSI_Payload_Data, 0, 4); + NCSI_Payload_Data[3] = 0x1; //ALD + + if (NCSI_SentWaitPacket(DISABLE_CHANNEL, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 4)) { + FindErr_NCSI(NCSI_LinkFail_Disable_Channel); + } +} +void Enable_Network_TX_SLT (void) {//Command:0x06 + if ( NCSI_SentWaitPacket(ENABLE_CHANNEL_NETWORK_TX, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 0) ) { + FindErr_NCSI(NCSI_LinkFail_Enable_Network_TX); + } +} + +//------------------------------------------------------------ +void Disable_Network_TX_SLT (void) {//Command:0x07 + if ( NCSI_SentWaitPacket(DISABLE_CHANNEL_NETWORK_TX, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 0) ) { + FindErr_NCSI(NCSI_LinkFail_Disable_Network_TX); + } +} + +//------------------------------------------------------------ +void Set_Link_SLT (void) {//Command:0x09 + memset ((void *)NCSI_Payload_Data, 0, 8); + NCSI_Payload_Data[2] = 0x02; //full duplex +// NCSI_Payload_Data[3] = 0x04; //100M, auto-disable + NCSI_Payload_Data[3] = 0x05; //100M, auto-enable + + NCSI_SentWaitPacket(SET_LINK, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 8); +} + +//------------------------------------------------------------ +char Get_Link_Status_SLT (void) {//Command:0x0a + + if (NCSI_SentWaitPacket(GET_LINK_STATUS, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 0)) { + return(0); + } + else { + if (NCSI_Respond_SLT.Payload_Data[3] & 0x20) { + if (NCSI_Respond_SLT.Payload_Data[3] & 0x40) { + if (NCSI_Respond_SLT.Payload_Data[3] & 0x01) + return(1); //Link Up or Not + else + return(0); + } else + return(0); //Auto Negotiate did not finish + } else { + if (NCSI_Respond_SLT.Payload_Data[3] & 0x01) + return(1); //Link Up or Not + else + return(0); + } + } +} // End char Get_Link_Status_SLT (void) + +//------------------------------------------------------------ +void Enable_Set_MAC_Address_SLT (void) {//Command:0x0e + int i; + + for ( i = 0; i < 6; i++ ) { + NCSI_Payload_Data[i] = NCSI_Request_SLT.SA[i]; + } + NCSI_Payload_Data[6] = 1; //MAC Address Num = 1 --> address filter 1, fixed in sample code + NCSI_Payload_Data[7] = UNICAST + 0 + ENABLE_MAC_ADDRESS_FILTER; //AT + Reserved + E + + if ( NCSI_SentWaitPacket(SET_MAC_ADDRESS, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 8) ) { + FindErr_NCSI(NCSI_LinkFail_Enable_Set_MAC_Address); + } +} + +//------------------------------------------------------------ +void Enable_Broadcast_Filter_SLT (void) {//Command:0x10 + memset ((void *)NCSI_Payload_Data, 0, 4); + NCSI_Payload_Data[3] = 0xF; //ARP, DHCP, NetBIOS + + if (NCSI_SentWaitPacket(ENABLE_BROADCAST_FILTERING, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 4) ) { + FindErr_NCSI(NCSI_LinkFail_Enable_Broadcast_Filter); + } +} + +//------------------------------------------------------------ +void Get_Version_ID_SLT (void) {//Command:0x15 + + if (NCSI_SentWaitPacket(GET_VERSION_ID, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 0) ) { + FindErr_NCSI(NCSI_LinkFail_Get_Version_ID); + } + else { +#ifdef Print_Version_ID + printf ("NCSI Version : %02x %02x %02x %02x\n", NCSI_Respond_SLT.Payload_Data[ 0], NCSI_Respond_SLT.Payload_Data[ 1], NCSI_Respond_SLT.Payload_Data[ 2], NCSI_Respond_SLT.Payload_Data[ 3]); + printf ("NCSI Version : %02x %02x %02x %02x\n", NCSI_Respond_SLT.Payload_Data[ 4], NCSI_Respond_SLT.Payload_Data[ 5], NCSI_Respond_SLT.Payload_Data[ 6], NCSI_Respond_SLT.Payload_Data[ 7]); + printf ("Firmware Name String: %02x %02x %02x %02x\n", NCSI_Respond_SLT.Payload_Data[ 8], NCSI_Respond_SLT.Payload_Data[ 9], NCSI_Respond_SLT.Payload_Data[10], NCSI_Respond_SLT.Payload_Data[11]); + printf ("Firmware Name String: %02x %02x %02x %02x\n", NCSI_Respond_SLT.Payload_Data[12], NCSI_Respond_SLT.Payload_Data[13], NCSI_Respond_SLT.Payload_Data[14], NCSI_Respond_SLT.Payload_Data[15]); + printf ("Firmware Name String: %02x %02x %02x %02x\n", NCSI_Respond_SLT.Payload_Data[16], NCSI_Respond_SLT.Payload_Data[17], NCSI_Respond_SLT.Payload_Data[18], NCSI_Respond_SLT.Payload_Data[19]); + printf ("Firmware Version : %02x %02x %02x %02x\n", NCSI_Respond_SLT.Payload_Data[20], NCSI_Respond_SLT.Payload_Data[21], NCSI_Respond_SLT.Payload_Data[22], NCSI_Respond_SLT.Payload_Data[23]); + printf ("PCI DID/VID : %02x %02x/%02x %02x\n", NCSI_Respond_SLT.Payload_Data[24], NCSI_Respond_SLT.Payload_Data[25], NCSI_Respond_SLT.Payload_Data[26], NCSI_Respond_SLT.Payload_Data[27]); + printf ("PCI SSID/SVID : %02x %02x/%02x %02x\n", NCSI_Respond_SLT.Payload_Data[28], NCSI_Respond_SLT.Payload_Data[29], NCSI_Respond_SLT.Payload_Data[30], NCSI_Respond_SLT.Payload_Data[31]); + printf ("Manufacturer ID : %02x %02x %02x %02x\n", NCSI_Respond_SLT.Payload_Data[32], NCSI_Respond_SLT.Payload_Data[33], NCSI_Respond_SLT.Payload_Data[34], NCSI_Respond_SLT.Payload_Data[35]); + printf ("Checksum : %02x %02x %02x %02x\n", NCSI_Respond_SLT.Payload_Data[36], NCSI_Respond_SLT.Payload_Data[37], NCSI_Respond_SLT.Payload_Data[38], NCSI_Respond_SLT.Payload_Data[39]); +#endif + NCSI_Cap_SLT.PCI_DID_VID = (NCSI_Respond_SLT.Payload_Data[24]<<24) + | (NCSI_Respond_SLT.Payload_Data[25]<<16) + | (NCSI_Respond_SLT.Payload_Data[26]<< 8) + | (NCSI_Respond_SLT.Payload_Data[27] ); + NCSI_Cap_SLT.ManufacturerID = (NCSI_Respond_SLT.Payload_Data[32]<<24) + | (NCSI_Respond_SLT.Payload_Data[33]<<16) + | (NCSI_Respond_SLT.Payload_Data[34]<< 8) + | (NCSI_Respond_SLT.Payload_Data[35] ); + } +} // End void Get_Version_ID_SLT (void) + +//------------------------------------------------------------ +void Get_Capabilities_SLT (void) {//Command:0x16 + + if (NCSI_SentWaitPacket(GET_CAPABILITIES, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 0)) { + FindErr_NCSI(NCSI_LinkFail_Get_Capabilities); + } + else { + NCSI_Cap_SLT.Capabilities_Flags = NCSI_Respond_SLT.Payload_Data[0]; + NCSI_Cap_SLT.Broadcast_Packet_Filter_Capabilities = NCSI_Respond_SLT.Payload_Data[1]; + NCSI_Cap_SLT.Multicast_Packet_Filter_Capabilities = NCSI_Respond_SLT.Payload_Data[2]; + NCSI_Cap_SLT.Buffering_Capabilities = NCSI_Respond_SLT.Payload_Data[3]; + NCSI_Cap_SLT.AEN_Control_Support = NCSI_Respond_SLT.Payload_Data[4]; + } +} + +//------------------------------------------------------------ +void Get_Controller_Packet_Statistics (void) {//Command:0x18 + + NCSI_SentWaitPacket(GET_CONTROLLER_PACKET_STATISTICS, (NCSI_Cap_SLT.Package_ID << 5) + NCSI_Cap_SLT.Channel_ID, 0); +} + +//------------------------------------------------------------ +char phy_ncsi (void) { + ULONG Channel_Found = 0; + ULONG Package_Found = 0; + ULONG Re_Send; + ULONG Err_Flag_bak; + ULONG pkg_idx; + ULONG chl_idx; + ULONG Link_Status; + ULONG NCSI_LinkFail_Val_bak; + + number_chl = 0; + number_pak = 0; + + NCSI_LinkFail_Val = 0; +
#ifdef SLT_DOS + fprintf(fp_log, "\n\n======> Start:\n" ); + #endif
+ NCSI_Struct_Initialize_SLT(); + + #ifdef NCSI_Skip_Phase1_DeSelectPackage + #else + + //NCSI Start + //Disable Channel then DeSelect Package + for (pkg_idx = 0; pkg_idx < MAX_PACKAGE_NUM; pkg_idx++) { + // Ignore error flag in the NCSI command + Err_Flag_bak = Err_Flag; + NCSI_LinkFail_Val_bak = NCSI_LinkFail_Val; + select_flag[pkg_idx] = Select_Package_SLT (pkg_idx); // Command:0x01 + Err_Flag = Err_Flag_bak; + NCSI_LinkFail_Val = NCSI_LinkFail_Val_bak; + + if ( select_flag[pkg_idx] == 0 ) { + NCSI_Cap_SLT.Package_ID = pkg_idx; + + for ( chl_idx = 0; chl_idx < MAX_CHANNEL_NUM; chl_idx++ ) { + NCSI_Cap_SLT.Channel_ID = chl_idx; + // Ignore error flag in the NCSI command + Err_Flag_bak = Err_Flag; + NCSI_LinkFail_Val_bak = NCSI_LinkFail_Val; + Disable_Channel_SLT(); // Command: 0x04 + Err_Flag = Err_Flag_bak; + NCSI_LinkFail_Val = NCSI_LinkFail_Val_bak; + } + #ifdef NCSI_Skip_DeSelectPackage + #else + DeSelect_Package_SLT (pkg_idx); // Command:0x02 + #endif + } // End if ( select_flag[pkg_idx] == 0 ) + } // End for (pkg_idx = 0; pkg_idx < MAX_PACKAGE_NUM; pkg_idx++) + #endif + + //Select Package + for (pkg_idx = 0; pkg_idx < MAX_PACKAGE_NUM; pkg_idx++) { + #ifdef NCSI_Skip_Phase1_DeSelectPackage + // Ignore error flag in the NCSI command + Err_Flag_bak = Err_Flag; + NCSI_LinkFail_Val_bak = NCSI_LinkFail_Val; + select_flag[pkg_idx] = Select_Package_SLT (pkg_idx);//Command:0x01 + Err_Flag = Err_Flag_bak; + NCSI_LinkFail_Val = NCSI_LinkFail_Val_bak; + #endif + + if (select_flag[pkg_idx] == 0) { + //NCSI_RxTimeOutScale = 1000; + NCSI_RxTimeOutScale = 10; + number_pak++; + Package_Found = 1; + NCSI_Cap_SLT.Package_ID = pkg_idx; + + if ( !(IOTiming||IOTimingBund) ) + printf ("====Find Package ID: %d\n", NCSI_Cap_SLT.Package_ID); + #ifdef SLT_DOS + fprintf(fp_log, "====Find Package ID: %d\n", NCSI_Cap_SLT.Package_ID); + #endif + + #ifdef NCSI_Skip_Phase1_DeSelectPackage + #else + Select_Package_SLT (pkg_idx);//Command:0x01 + #endif + + // Scan all channel in the package + for ( chl_idx = 0; chl_idx < MAX_CHANNEL_NUM; chl_idx++ ) { + // backup error flag + Err_Flag_bak = Err_Flag; + NCSI_LinkFail_Val_bak = NCSI_LinkFail_Val; + if (Clear_Initial_State_SLT(chl_idx) == 0) { //Command:0x00 + number_chl++; + Channel_Found = 1; + NCSI_Cap_SLT.Channel_ID = chl_idx; + + if ( !(IOTiming || IOTimingBund) ) + printf ("--------Find Channel ID: %d\n", NCSI_Cap_SLT.Channel_ID); + + #ifdef SLT_DOS + fprintf(fp_log, "--------Find Channel ID: %d\n", NCSI_Cap_SLT.Channel_ID); + #endif + // Get Version and Capabilities + Get_Version_ID_SLT(); //Command:0x15 + Get_Capabilities_SLT(); //Command:0x16 + Select_Active_Package_SLT(); //Command:0x01 + Enable_Set_MAC_Address_SLT(); //Command:0x0e + Enable_Broadcast_Filter_SLT(); //Command:0x10 + + // Enable TX + Enable_Network_TX_SLT(); //Command:0x06 + + // Enable Channel + Enable_Channel_SLT(); //Command:0x03 + + // Get Link Status + Re_Send = 0; + do { + #ifdef NCSI_EnableDelay_GetLinkStatus + if ( Re_Send >= 2 ) + delay(Delay_GetLinkStatus); + #endif + + Link_Status = Get_Link_Status_SLT();//Command:0x0a + + if ( Link_Status == LINK_UP ) { + if (!(IOTiming||IOTimingBund)) + printf (" This Channel is LINK_UP\n"); + + #ifdef SLT_DOS + fprintf(fp_log, " This Channel is LINK_UP\n"); + #endif + + NCSI_ARP (); + + break; + } + else if ( Link_Status == LINK_DOWN ) { + if ( Re_Send >= 2 ) { + if ( !(IOTiming || IOTimingBund) ) + printf (" This Channel is LINK_DOWN\n"); + + #ifdef SLT_DOS + fprintf(fp_log, " This Channel is LINK_DOWN\n"); + #endif + + break; + } + } // End if ( Link_Status == LINK_UP ) + } while ( Re_Send++ <= 2 ); + + #ifdef NCSI_Skip_DiSChannel + #else + if ( NCSI_DiSChannel ) { + // Disable TX + Disable_Network_TX_SLT(); //Command:0x07 + // Disable Channel + Disable_Channel_SLT(); //Command:0x04 + } + #endif + } + else { + Err_Flag = Err_Flag_bak; + NCSI_LinkFail_Val = NCSI_LinkFail_Val_bak; + } + } // End for ( chl_idx = 0; chl_idx < MAX_CHANNEL_NUM; chl_idx++ ) + + #ifdef NCSI_Skip_DeSelectPackage + #else + DeSelect_Package_SLT (pkg_idx);//Command:0x02 + #endif + NCSI_RxTimeOutScale = 1; + } + else { + if (!(IOTiming||IOTimingBund)) { + printf ("====Absence of Package ID: %ld\n", pkg_idx); + #ifdef SLT_DOS + fprintf(fp_log, "====Absence of Package ID: %ld\n", pkg_idx); + #endif + } + } // End if (select_flag[pkg_idx] == 0) + } // End for (pkg_idx = 0; pkg_idx < MAX_PACKAGE_NUM; pkg_idx++) + + if ( !Package_Found ) FindErr( Err_NCSI_No_PHY ); + if ( ChannelTolNum != number_chl ) FindErr( Err_NCSI_Channel_Num ); + if ( PackageTolNum != number_pak ) FindErr( Err_NCSI_Package_Num ); +// if ( !Channel_Found) FindErr(); + + if ( Err_Flag ) + return(1); + else + return(0); +} + diff --git a/arch/arm/cpu/arm926ejs/aspeed/PCI_SPI.c b/arch/arm/cpu/arm926ejs/aspeed/PCI_SPI.c new file mode 100644 index 0000000..77aac47 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/PCI_SPI.c @@ -0,0 +1,83 @@ +/*
+ * 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
+ */
+#define PCI_SPI_C
+static const char ThisFile[] = "PCI_SPI.c";
+
+#include "SWFUNC.H"
+
+#ifdef SLT_UBOOT
+ #include <common.h>
+ #include <command.h>
+#endif
+#ifdef SLT_DOS
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <conio.h>
+ #include <string.h>
+ #include <dos.h>
+#endif
+
+#include "DEF_SPI.H"
+#include "LIB.H"
+#include "TYPEDEF.H"
+
+#ifdef SPI_BUS
+ULONG GetPCIInfo (DEVICE_PCI_INFO *VGAPCIInfo)
+{
+ ULONG ulPCIBaseAddress, MMIOBaseAddress, LinearAddressBase, busnum, data;
+
+ ulPCIBaseAddress = FindPCIDevice (0x1A03, 0x2000, ACTIVE);
+ busnum = 0;
+ while (ulPCIBaseAddress == 0 && busnum < 256) {
+ ulPCIBaseAddress = FindPCIDevice (0x1A03, 0x2000, busnum);
+ if (ulPCIBaseAddress == 0) {
+ ulPCIBaseAddress = FindPCIDevice (0x1688, 0x2000, busnum);
+ }
+ if (ulPCIBaseAddress == 0) {
+ ulPCIBaseAddress = FindPCIDevice (0x1A03, 0x1160, busnum);
+ }
+ if (ulPCIBaseAddress == 0) {
+ ulPCIBaseAddress = FindPCIDevice (0x1A03, 0x1180, busnum);
+ }
+ busnum++;
+ }
+ printf ("ulPCIBaseAddress = %lx\n", ulPCIBaseAddress);
+ if (ulPCIBaseAddress != 0) {
+ VGAPCIInfo->ulPCIConfigurationBaseAddress = ulPCIBaseAddress;
+ VGAPCIInfo->usVendorID = ReadPCIReg(ulPCIBaseAddress, 0, 0xFFFF);
+ VGAPCIInfo->usDeviceID = ReadPCIReg(ulPCIBaseAddress, 0, 0xFFFF0000) >> 16;
+ LinearAddressBase = ReadPCIReg (ulPCIBaseAddress, 0x10, 0xFFFFFFF0);
+ VGAPCIInfo->ulPhysicalBaseAddress = MapPhysicalToLinear (LinearAddressBase, 64 * 1024 * 1024 + 0x200000);
+ MMIOBaseAddress = ReadPCIReg (ulPCIBaseAddress, 0x14, 0xFFFF0000);
+ VGAPCIInfo->ulMMIOBaseAddress = MapPhysicalToLinear (MMIOBaseAddress, 64 * 1024 * 1024);
+ VGAPCIInfo->usRelocateIO = ReadPCIReg (ulPCIBaseAddress, 0x18, 0x0000FF80);
+ OUTDWPORT(0xcf8, ulPCIBaseAddress + 0x4);
+ data = INDWPORT(0xcfc);
+ OUTDWPORT(0xcfc, data | 0x3);
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+} // End ULONG GetPCIInfo (DEVICE_PCI_INFO *VGAPCIInfo)
+
+BOOLEAN GetDevicePCIInfo (VIDEO_ENGINE_INFO *VideoEngineInfo)
+{
+ if (GetPCIInfo (&VideoEngineInfo->VGAPCIInfo) == TRUE) {
+ return TRUE;
+ }
+ else {
+ printf("Can not find PCI device!\n");
+ exit(0);
+ return FALSE;
+ }
+} // End
+#endif // End ifdef SPI_BUS
diff --git a/arch/arm/cpu/arm926ejs/aspeed/PHY.H b/arch/arm/cpu/arm926ejs/aspeed/PHY.H new file mode 100644 index 0000000..81d9470 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/PHY.H @@ -0,0 +1,56 @@ +/*
+ * 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
+ */
+#ifndef PHY_H
+#define PHY_H
+
+//
+// Define
+//
+#define Enable_SearchPHYID //[ON] (Search vlid PHY ID)
+#define Enable_CheckZeroPHYID //[ON] (Check PHY ID with value 0)
+
+#ifdef Enable_CheckZeroPHYID
+ #define PHY_IS_VALID( dat ) ( ( (dat & 0xffff) != 0xffff ) && ( ( dat & 0xffff ) != 0x0 ) )
+#else
+ #define PHY_IS_VALID( dat ) ( ( dat & 0xffff) != 0xffff )
+#endif
+
+// Define PHY basic register
+#define PHY_REG_BMCR 0x00 // Basic Mode Control Register
+#define PHY_REG_BMSR 0x01 // Basic Mode Status Register
+#define PHY_REG_ID_1 0x02
+#define PHY_REG_ID_2 0x03
+#define PHY_ANER 0x06 // Auto-negotiation Expansion Register
+#define PHY_GBCR 0x09 // 1000Base-T Control Register
+#define PHY_SR 0x11 // PHY Specific Status Register
+#define PHY_INER 0x12 // Interrupt Enable Register
+
+#define TIME_OUT_PHY_RW 10000
+#define TIME_OUT_PHY_Rst 10000
+
+#define PHYID3_Mask 0xfc00 //0xffc0
+
+/* --- Note for SettingPHY chip ---
+void phy_xxxx (int loop_phy) {
+
+ if ( BurstEnable ) {
+ // IEEE test
+ }
+ else if (loop_phy) {
+ // Internal loop back
+ }
+ else {
+ // external loop back
+ }
+}
+----------------------------------- */
+
+#endif // PHY_H
diff --git a/arch/arm/cpu/arm926ejs/aspeed/PHY.c b/arch/arm/cpu/arm926ejs/aspeed/PHY.c new file mode 100644 index 0000000..db73a70 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/PHY.c @@ -0,0 +1,1541 @@ +/*
+ * 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
+ */
+#define PHY_C
+static const char ThisFile[] = "PHY.c";
+
+#include "SWFUNC.H"
+
+#ifdef SLT_UBOOT
+ #include <common.h>
+ #include <command.h>
+ #include "COMMINF.H"
+ #include "STDUBOOT.H"
+#endif
+#ifdef SLT_DOS
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <conio.h>
+ #include <string.h>
+ #include "COMMINF.H"
+#endif
+
+#include "PHY.H"
+#include "TYPEDEF.H"
+#include "IO.H"
+
+ULONG PHY_09h;
+ULONG PHY_18h;
+ULONG PHY_1fh;
+ULONG PHY_06hA[7];
+ULONG PHY_11h;
+ULONG PHY_12h;
+ULONG PHY_15h;
+ULONG PHY_06h;
+char PHYID[256];
+ULONG PHY_00h;
+
+//------------------------------------------------------------
+// PHY R/W basic
+//------------------------------------------------------------
+void phy_write (int adr, ULONG data) {
+ int timeout = 0;
+
+ if (AST2300_NewMDIO) {
+ WriteSOC_DD( MAC_PHYBASE + 0x60, ( data << 16 ) | MAC_PHYWr_New | (PHY_ADR<<5) | (adr & 0x1f));
+
+ while ( ReadSOC_DD( MAC_PHYBASE + 0x60 ) & MAC_PHYBusy_New ) {
+ if ( ++timeout > TIME_OUT_PHY_RW ) {
+ if (!BurstEnable)
+#ifdef SLT_DOS
+ fprintf(fp_log, "[PHY-Write] Time out: %08lx\n", ReadSOC_DD( MAC_PHYBASE + 0x60 ) );
+#endif
+ FindErr( Err_PHY_TimeOut );
+ break;
+ }
+ }
+ }
+ else {
+ WriteSOC_DD( MAC_PHYBASE + 0x64, data );
+
+ WriteSOC_DD( MAC_PHYBASE + 0x60, MDC_Thres | MAC_PHYWr | (PHY_ADR<<16) | ((adr & 0x1f) << 21));
+
+ while ( ReadSOC_DD( MAC_PHYBASE + 0x60 ) & MAC_PHYWr ) {
+ if ( ++timeout > TIME_OUT_PHY_RW ) {
+#ifdef SLT_DOS
+ if (!BurstEnable)
+ fprintf(fp_log, "[PHY-Write] Time out: %08lx\n", ReadSOC_DD( MAC_PHYBASE + 0x60 ) );
+#endif
+ FindErr( Err_PHY_TimeOut );
+ break;
+ }
+ }
+ } // End if (AST2300_NewMDIO)
+
+ if ( DbgPrn_PHYRW )
+ printf ("[Wr ]%02d: %04lx\n", adr, data);
+} // End void phy_write (int adr, ULONG data)
+
+//------------------------------------------------------------
+ULONG phy_read (int adr) {
+ int timeout = 0;
+
+ if ( AST2300_NewMDIO ) {
+ WriteSOC_DD( MAC_PHYBASE + 0x60, MAC_PHYRd_New | (PHY_ADR << 5) | ( adr & 0x1f ) );
+
+ while ( ReadSOC_DD( MAC_PHYBASE + 0x60 ) & MAC_PHYBusy_New ) {
+ if ( ++timeout > TIME_OUT_PHY_RW ) {
+ if ( !BurstEnable )
+#ifdef SLT_DOS
+ fprintf(fp_log, "[PHY-Read] Time out: %08lx\n", ReadSOC_DD( MAC_PHYBASE + 0x60 ));
+#endif
+ FindErr( Err_PHY_TimeOut );
+ break;
+ }
+ }
+
+ DELAY(Delay_PHYRd);
+ Dat_ULONG = ReadSOC_DD( MAC_PHYBASE + 0x64 ) & 0xffff;
+ }
+ else {
+ WriteSOC_DD( MAC_PHYBASE + 0x60, MDC_Thres | MAC_PHYRd | (PHY_ADR << 16) | ((adr & 0x1f) << 21) );
+
+ while ( ReadSOC_DD( MAC_PHYBASE + 0x60 ) & MAC_PHYRd ) {
+ if ( ++timeout > TIME_OUT_PHY_RW ) {
+#ifdef SLT_DOS
+ if ( !BurstEnable )
+ fprintf( fp_log, "[PHY-Read] Time out: %08lx\n", ReadSOC_DD( MAC_PHYBASE + 0x60 ) );
+#endif
+ FindErr( Err_PHY_TimeOut );
+ break;
+ }
+ }
+
+ DELAY( Delay_PHYRd );
+ Dat_ULONG = ReadSOC_DD( MAC_PHYBASE + 0x64 ) >> 16;
+ }
+
+ if ( DbgPrn_PHYRW )
+ printf ("[Rd ]%02d: %04lx\n", adr, Dat_ULONG );
+
+ return( Dat_ULONG );
+} // End ULONG phy_read (int adr)
+
+//------------------------------------------------------------
+void phy_Read_Write (int adr, ULONG clr_mask, ULONG set_mask) {
+ if ( DbgPrn_PHYRW )
+ printf ("[RW ]%02d: clr:%04lx: set:%04lx\n", adr, clr_mask, set_mask);
+ phy_write(adr, ((phy_read(adr) & (~clr_mask)) | set_mask));
+}
+
+//------------------------------------------------------------
+void phy_out ( int adr ) {
+ printf ("%02d: %04lx\n", adr, phy_read(adr));
+}
+
+//------------------------------------------------------------
+//void phy_outchg ( int adr ) {
+// ULONG PHY_valold = 0;
+// ULONG PHY_val;
+//
+// while (1) {
+// PHY_val = phy_read(adr);
+// if (PHY_valold != PHY_val) {
+// printf ("%02d: %04lx\n", adr, PHY_val);
+// PHY_valold = PHY_val;
+// }
+// }
+//}
+
+//------------------------------------------------------------
+void phy_dump (char *name) {
+ int index;
+
+ printf ("[%s][%d]----------------\n", name, PHY_ADR);
+ for (index = 0; index < 32; index++) {
+ printf ("%02d: %04lx ", index, phy_read(index));
+
+ if ((index % 8) == 7)
+ printf ("\n");
+ }
+}
+
+//------------------------------------------------------------
+void phy_id (BYTE option) {
+
+ ULONG reg_adr;
+ CHAR PHY_ADR_org;
+ FILE_VAR
+
+ GET_OBJ( option )
+
+ PHY_ADR_org = PHY_ADR;
+ for (PHY_ADR = 0; PHY_ADR < 32; PHY_ADR++) {
+
+ PRINT(OUT_OBJ "[%02d] ", PHY_ADR);
+
+ for (reg_adr = 2; reg_adr <= 3; reg_adr++)
+ PRINT(OUT_OBJ "%ld:%04lx ", reg_adr, phy_read(reg_adr));
+
+ if ((PHY_ADR % 4) == 3)
+ PRINT(OUT_OBJ "\n");
+ }
+ PHY_ADR = PHY_ADR_org;
+}
+
+
+//------------------------------------------------------------
+void phy_delay (int dt) {
+ DELAY( dt );
+}
+
+//------------------------------------------------------------
+// PHY IC
+//------------------------------------------------------------
+void phy_basic_setting (int loop_phy) {
+ phy_Read_Write(0, 0x7140, PHY_00h); //clr set
+ if ( DbgPrn_PHYRW )
+ printf ("[Set]00: %04lx\n", phy_read( PHY_REG_BMCR ));
+}
+
+//------------------------------------------------------------
+void phy_Wait_Reset_Done (void) {
+ int timeout = 0;
+
+ while ( phy_read( PHY_REG_BMCR ) & 0x8000 ) {
+ if (DbgPrn_PHYRW)
+ printf ("00: %04lx\n", phy_read( PHY_REG_BMCR ));
+
+ if (++timeout > TIME_OUT_PHY_Rst) {
+#ifdef SLT_DOS
+ if (!BurstEnable) fprintf(fp_log, "[PHY-Reset] Time out: %08lx\n", ReadSOC_DD(MAC_PHYBASE+0x60));
+#endif
+ FindErr(Err_PHY_TimeOut);
+ break;
+ }
+ }//wait Rst Done
+
+ if (DbgPrn_PHYRW) printf ("[Clr]00: %04lx\n", phy_read( PHY_REG_BMCR ));
+ DELAY(Delay_PHYRst);
+}
+
+//------------------------------------------------------------
+void phy_Reset (int loop_phy) {
+ phy_basic_setting(loop_phy);
+
+ phy_Read_Write(0, 0x0000, 0x8000 | PHY_00h);//clr set//Rst PHY
+ phy_Wait_Reset_Done();
+
+ phy_basic_setting(loop_phy);
+ DELAY(Delay_PHYRst);
+}
+
+//------------------------------------------------------------
+void recov_phy_marvell (int loop_phy) {//88E1111
+ if ( BurstEnable ) {
+ }
+ else if ( loop_phy ) {
+ }
+ else {
+ if (GSpeed_sel[0]) {
+ phy_write(9, PHY_09h);
+
+ phy_Reset(loop_phy);
+
+ phy_write(29, 0x0007);
+ phy_Read_Write(30, 0x0008, 0x0000);//clr set
+ phy_write(29, 0x0010);
+ phy_Read_Write(30, 0x0002, 0x0000);//clr set
+ phy_write(29, 0x0012);
+ phy_Read_Write(30, 0x0001, 0x0000);//clr set
+
+ phy_write(18, PHY_12h);
+ }
+ }
+}
+
+//------------------------------------------------------------
+void phy_marvell (int loop_phy) {//88E1111
+ int Retry;
+
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Marvell] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ if ( BurstEnable ) {
+ phy_Reset(loop_phy);
+ }
+ else if ( loop_phy ) {
+ phy_Reset(loop_phy);
+ }
+ else {
+ if ( GSpeed_sel[0] ) {
+ PHY_09h = phy_read( PHY_GBCR );
+ PHY_12h = phy_read( PHY_INER );
+ phy_write ( 18, 0x0000 );
+ phy_Read_Write( 9, 0x0000, 0x1800 );//clr set
+ }
+
+ phy_Reset(loop_phy);
+
+ if (GSpeed_sel[0]) {
+ phy_write ( 29, 0x0007 );
+ phy_Read_Write( 30, 0x0000, 0x0008 );//clr set
+ phy_write ( 29, 0x0010 );
+ phy_Read_Write( 30, 0x0000, 0x0002 );//clr set
+ phy_write ( 29, 0x0012 );
+ phy_Read_Write( 30, 0x0000, 0x0001 );//clr set
+ }
+ }
+
+ Retry = 0;
+ do {
+ PHY_11h = phy_read( PHY_SR );
+ } while ( !( ( PHY_11h & 0x0400 ) | loop_phy | ( Retry++ > 20 ) ) );
+}
+
+//------------------------------------------------------------
+void recov_phy_marvell0 (int loop_phy) {//88E1310
+ if (BurstEnable) {
+ } else if (loop_phy) {
+ } else {
+ if (GSpeed_sel[0]) {
+ phy_write(22, 0x0006);
+ phy_Read_Write(16, 0x0020, 0x0000);//clr set
+ phy_write(22, 0x0000);
+ }
+ }
+}
+
+//------------------------------------------------------------
+void phy_marvell0 (int loop_phy) {//88E1310
+ int Retry;
+
+ if (DbgPrn_PHYName)
+ printf ("--->(%04lx %04lx)[Marvell] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ phy_write( 22, 0x0002 );
+
+ PHY_15h = phy_read(21);
+ if (PHY_15h & 0x0030) {
+ printf ("\n\n[Warning] Page2, Register 21, bit 4~5 must be 0 [Reg15_2:%04lx]\n\n", PHY_15h);
+#ifdef SLT_DOS
+ if ( IOTiming )
+ fprintf (fp_io, "\n\n[Warning] Page2, Register 21, bit 4~5 must be 0 [Reg15_2:%04lx]\n\n", PHY_15h);
+ if ( !BurstEnable)
+ fprintf (fp_log, "\n\n[Warning] Page2, Register 21, bit 4~5 must be 0 [Reg15_2:%04lx]\n\n", PHY_15h);
+#endif
+// phy_Read_Write(21, 0x0030, 0x0000);//clr set//[5]Rx Dly, [4]Tx Dly
+ phy_write(21, PHY_15h & 0xffcf); // Set [5]Rx Dly, [4]Tx Dly to 0
+ }
+ phy_write(22, 0x0000);
+
+ if ( BurstEnable ) {
+ phy_Reset(loop_phy);
+ }
+ else if ( loop_phy ) {
+ phy_write( 22, 0x0002 );
+
+ if ( GSpeed_sel[0] ) {
+ phy_Read_Write( 21, 0x6040, 0x0040 );//clr set
+ }
+ else if ( GSpeed_sel[1] ) {
+ phy_Read_Write( 21, 0x6040, 0x2000 );//clr set
+ }
+ else {
+ phy_Read_Write( 21, 0x6040, 0x0000 );//clr set
+ }
+ phy_write( 22, 0x0000 );
+ phy_Reset( loop_phy );
+ }
+ else {
+ if ( GSpeed_sel[0] ) {
+ phy_write( 22, 0x0006 );
+ phy_Read_Write( 16, 0x0000, 0x0020 );//clr set
+ phy_write( 22, 0x0000 );
+ }
+
+ phy_Reset(loop_phy);
+ }
+
+ Retry = 0;
+ do {
+ PHY_11h = phy_read( PHY_SR );
+ } while (!((PHY_11h & 0x0400) | loop_phy | (Retry++ > 20)));
+}
+
+//------------------------------------------------------------
+void recov_phy_marvell1 (int loop_phy) {//88E6176
+ CHAR PHY_ADR_org;
+
+ PHY_ADR_org = PHY_ADR;
+ for ( PHY_ADR = 16; PHY_ADR <= 22; PHY_ADR++ ) {
+ if ( BurstEnable ) {
+ }
+ else {
+ phy_write(6, PHY_06hA[PHY_ADR-16]);//06h[5]P5 loopback, 06h[6]P6 loopback
+ }
+ }
+ for ( PHY_ADR = 21; PHY_ADR <= 22; PHY_ADR++ ) {
+ phy_write(1, 0x3); //01h[1:0]00 = 10 Mbps, 01 = 100 Mbps, 10 = 1000 Mbps, 11 = Speed is not forced.
+ }
+ PHY_ADR = PHY_ADR_org;
+}
+
+//------------------------------------------------------------
+void phy_marvell1 (int loop_phy) {//88E6176
+// ULONG PHY_01h;
+ CHAR PHY_ADR_org;
+
+ if (DbgPrn_PHYName)
+ printf ("--->(%04lx %04lx)[Marvell] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ //The 88E6176 is switch with 7 Port(P0~P6) and the PHYAdr will be fixed at 0x10~0x16, and only P5/P6 can be connected to the MAC.
+ //Therefor, the 88E6176 only can run the internal loopback.
+ PHY_ADR_org = PHY_ADR;
+ for ( PHY_ADR = 16; PHY_ADR <= 20; PHY_ADR++ ) {
+ if ( BurstEnable ) {
+ }
+ else {
+ PHY_06hA[PHY_ADR-16] = phy_read( PHY_ANER );
+ phy_write(6, 0x00);//06h[5]P5 loopback, 06h[6]P6 loopback
+ }
+ }
+
+ for ( PHY_ADR = 21; PHY_ADR <= 22; PHY_ADR++ ) {
+// PHY_01h = phy_read( PHY_REG_BMSR );
+// if (GSpeed_sel[0]) phy_write(1, (PHY_01h & 0xfffc) | 0x2);//[1:0]00 = 10 Mbps, 01 = 100 Mbps, 10 = 1000 Mbps, 11 = Speed is not forced.
+// else if (GSpeed_sel[1]) phy_write(1, (PHY_01h & 0xfffc) | 0x1);//[1:0]00 = 10 Mbps, 01 = 100 Mbps, 10 = 1000 Mbps, 11 = Speed is not forced.
+// else phy_write(1, (PHY_01h & 0xfffc) );//[1:0]00 = 10 Mbps, 01 = 100 Mbps, 10 = 1000 Mbps, 11 = Speed is not forced.
+ if (GSpeed_sel[0]) phy_write(1, 0x2);//01h[1:0]00 = 10 Mbps, 01 = 100 Mbps, 10 = 1000 Mbps, 11 = Speed is not forced.
+ else if (GSpeed_sel[1]) phy_write(1, 0x1);//01h[1:0]00 = 10 Mbps, 01 = 100 Mbps, 10 = 1000 Mbps, 11 = Speed is not forced.
+ else phy_write(1, 0x0);//01h[1:0]00 = 10 Mbps, 01 = 100 Mbps, 10 = 1000 Mbps, 11 = Speed is not forced.
+
+ if (BurstEnable) {
+ }
+ else {
+ PHY_06hA[PHY_ADR-16] = phy_read( PHY_ANER );
+ if (PHY_ADR == 21) phy_write(6, 0x20);//06h[5]P5 loopback, 06h[6]P6 loopback
+ else phy_write(6, 0x40);//06h[5]P5 loopback, 06h[6]P6 loopback
+ }
+ }
+ PHY_ADR = PHY_ADR_org;
+}
+
+//------------------------------------------------------------
+void recov_phy_marvell2 (int loop_phy) {//88E1512
+ if (BurstEnable) {
+ }
+ else if (loop_phy) {
+ }
+ else {
+ if (GSpeed_sel[0]) {
+ phy_write(22, 0x0006);
+ phy_Read_Write(18, 0x0008, 0x0000);//clr set
+ phy_write(22, 0x0000);
+ }
+ }
+}
+
+//------------------------------------------------------------
+void phy_marvell2 (int loop_phy) {//88E1512
+ int Retry = 0;
+ ULONG temp_reg;
+
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Marvell] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ phy_write(22, 0x0002);
+ PHY_15h = phy_read(21);
+
+ if ( PHY_15h & 0x0030 ) {
+ printf ("\n\n[Warning] Page2, Register 21, bit 4~5 must be 0 [Reg15h_2:%04lx]\n\n", PHY_15h);
+#ifdef SLT_DOS
+ if (IOTiming ) fprintf (fp_io, "\n\n[Warning] Page2, Register 21, bit 4~5 must be 0 [Reg15h_2:%04lx]\n\n", PHY_15h);
+ if (!BurstEnable) fprintf (fp_log, "\n\n[Warning] Page2, Register 21, bit 4~5 must be 0 [Reg15h_2:%04lx]\n\n", PHY_15h);
+#endif
+ // phy_Read_Write(21, 0x0030, 0x0000);//clr set//[5]Rx Dly, [4]Tx Dly
+// phy_write(21, PHY_15h & 0xffcf);
+ }
+ phy_write(22, 0x0000);
+
+ if ( BurstEnable ) {
+ phy_Reset(loop_phy);
+ }
+ else if (loop_phy) {
+ // Internal loopback funciton only support in copper mode
+ // switch page 18
+ phy_write(22, 0x0012);
+ // Change mode to Copper mode
+ phy_write(20, 0x8210);
+ // do software reset
+ do {
+ temp_reg = phy_read( 20 );
+ } while ( ( (temp_reg & 0x8000) == 0x8000 ) & (Retry++ < 20) );
+
+ // switch page 2
+ phy_write(22, 0x0002);
+ if (GSpeed_sel[0]) {
+ phy_Read_Write(21, 0x2040, 0x0040);//clr set
+ }
+ else if (GSpeed_sel[1]) {
+ phy_Read_Write(21, 0x2040, 0x2000);//clr set
+ }
+ else {
+ phy_Read_Write(21, 0x2040, 0x0000);//clr set
+ }
+ phy_write(22, 0x0000);
+
+ phy_Reset(loop_phy);
+ }
+ else {
+ if (GSpeed_sel[0]) {
+ phy_write(22, 0x0006);
+ phy_Read_Write(18, 0x0000, 0x0008);//clr set
+ phy_write(22, 0x0000);
+ }
+
+ phy_Reset(loop_phy);
+ }
+
+ Retry = 0;
+ do {
+ PHY_11h = phy_read( PHY_SR );
+ } while (!((PHY_11h & 0x0400) | loop_phy | (Retry++ > 20)));
+}
+
+//------------------------------------------------------------
+void phy_broadcom (int loop_phy) {//BCM5221
+ if (DbgPrn_PHYName)
+ printf ("--->(%04lx %04lx)[Broadcom] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ phy_Reset(loop_phy);
+
+ if (IEEETesting) {
+ if (IOTimingBund_arg == 0) {
+ phy_write(25, 0x1f01);//Force MDI //Measuring from channel A
+ }
+ else {
+ phy_Read_Write(24, 0x0000, 0x4000);//clr set//Force Link
+// phy_write( 0, PHY_00h);
+// phy_write(30, 0x1000);
+ }
+ }
+}
+
+//------------------------------------------------------------
+void recov_phy_broadcom0 (int loop_phy) {//BCM54612
+
+ // Need to do it for AST2400
+ phy_write(0x1C, 0x8C00); // Disable GTXCLK Clock Delay Enable
+ phy_write(0x18, 0xF0E7); // Disable RGMII RXD to RXC Skew
+
+ if (BurstEnable) {
+ }
+ else if (loop_phy) {
+ phy_write( 0, PHY_00h);
+ }
+ else {
+ phy_write(0x00, PHY_00h);
+ phy_write(0x09, PHY_09h);
+ phy_write(0x18, PHY_18h);
+ }
+}
+
+//------------------------------------------------------------
+void phy_broadcom0 (int loop_phy) {//BCM54612
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Broadcom] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ // Need to do it for AST2400
+ phy_write(0x1C, 0x8C00); // Disable GTXCLK Clock Delay Enable
+ phy_write(0x18, 0xF0E7); // Disable RGMII RXD to RXC Skew
+
+ // Backup org value
+ // read reg 18H, Page 103, BCM54612EB1KMLG_Spec.pdf
+ phy_write(0x18, 0x7007);
+ PHY_18h = phy_read(0x18);
+
+ PHY_00h = phy_read( PHY_REG_BMCR );
+ PHY_09h = phy_read( PHY_GBCR );
+
+ if ( BurstEnable ) {
+ phy_basic_setting(loop_phy);
+ }
+ else if (loop_phy) {
+ phy_basic_setting(loop_phy);
+
+ // Enable Internal Loopback mode
+ // Page 58, BCM54612EB1KMLG_Spec.pdf
+ phy_write(0x0, 0x5140);
+ DELAY(Delay_PHYRst);
+ /* Only 1G Test is PASS, 100M and 10M is false @20130619 */
+
+// Waiting for BCM FAE's response
+// if (GSpeed_sel[0]) {
+// // Speed 1G
+// // Enable Internal Loopback mode
+// // Page 58, BCM54612EB1KMLG_Spec.pdf
+// phy_write(0x0, 0x5140);
+// }
+// else if (GSpeed_sel[1]) {
+// // Speed 100M
+// // Enable Internal Loopback mode
+// // Page 58, BCM54612EB1KMLG_Spec.pdf
+// phy_write(0x0, 0x7100);
+// phy_write(0x1E, 0x1000);
+// }
+// else if (GSpeed_sel[2]) {
+// // Speed 10M
+// // Enable Internal Loopback mode
+// // Page 58, BCM54612EB1KMLG_Spec.pdf
+// phy_write(0x0, 0x5100);
+// phy_write(0x1E, 0x1000);
+// }
+//
+// DELAY(Delay_PHYRst);
+ }
+ else {
+
+ if (GSpeed_sel[0]) {
+ // Page 60, BCM54612EB1KMLG_Spec.pdf
+ // need to insert loopback plug
+ phy_write( 9, 0x1800);
+ phy_write( 0, 0x0140);
+ phy_write( 0x18, 0x8400); // Enable Transmit test mode
+ } else if (GSpeed_sel[1]) {
+ // Page 60, BCM54612EB1KMLG_Spec.pdf
+ // need to insert loopback plug
+ phy_write( 0, 0x2100);
+ phy_write( 0x18, 0x8400); // Enable Transmit test mode
+ } else {
+ // Page 60, BCM54612EB1KMLG_Spec.pdf
+ // need to insert loopback plug
+ phy_write( 0, 0x0100);
+ phy_write( 0x18, 0x8400); // Enable Transmit test mode
+ }
+ }
+}
+
+//------------------------------------------------------------
+void phy_realtek (int loop_phy) {//RTL8201N
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Realtek] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ phy_Reset(loop_phy);
+}
+
+//------------------------------------------------------------
+//internal loop 100M: Don't support
+//internal loop 10M : no loopback stub
+void phy_realtek0 (int loop_phy) {//RTL8201E
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Realtek] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ phy_Reset(loop_phy);
+
+// phy_Read_Write(25, 0x2800, 0x0000);//clr set
+// printf("Enable phy output RMII clock\n");
+ if (IEEETesting) {
+ phy_write(31, 0x0001);
+ if (IOTimingBund_arg == 0) {
+ phy_write(25, 0x1f01);//Force MDI //Measuring from channel A
+ }
+ else {
+ phy_write(25, 0x1f00);//Force MDIX //Measuring from channel B
+ }
+ phy_write(31, 0x0000);
+ }
+}
+
+//------------------------------------------------------------
+void recov_phy_realtek1 (int loop_phy) {//RTL8211D
+ if ( BurstEnable ) {
+ if ( IEEETesting ) {
+ if ( GSpeed_sel[0] ) {
+ if (IOTimingBund_arg == 0) {
+ //Test Mode 1
+ phy_write( 31, 0x0002 );
+ phy_write( 2, 0xc203 );
+ phy_write( 31, 0x0000 );
+ phy_write( 9, 0x0000 );
+ }
+ else {
+ //Test Mode 4
+ phy_write( 31, 0x0000 );
+ phy_write( 9, 0x0000 );
+ }
+
+ phy_write( 31, 0x0000 );
+ }
+ else if ( GSpeed_sel[1] ) {
+ phy_write( 23, 0x2100 );
+ phy_write( 16, 0x016e );
+ }
+ else {
+// phy_write( 31, 0x0006 );
+// phy_write( 0, 0x5a00 );
+// phy_write( 31, 0x0000 );
+ }
+ } // End if ( IEEETesting )
+ }
+ else if (loop_phy) {
+ if ( GSpeed_sel[0] ) {
+ phy_write( 31, 0x0000 ); // new in Rev. 1.6
+ phy_write( 0, 0x1140 ); // new in Rev. 1.6
+ phy_write( 20, 0x8040 ); // new in Rev. 1.6
+ }
+ }
+ else {
+ if ( GSpeed_sel[0] ) {
+ phy_write( 31, 0x0001 );
+ phy_write( 3, 0xdf41 );
+ phy_write( 2, 0xdf20 );
+ phy_write( 1, 0x0140 );
+ phy_write( 0, 0x00bb );
+ phy_write( 4, 0xb800 );
+ phy_write( 4, 0xb000 );
+
+ phy_write( 31, 0x0000 );
+// phy_write( 26, 0x0020 ); // Rev. 1.2
+ phy_write( 26, 0x0040 ); // new in Rev. 1.6
+ phy_write( 0, 0x1140 );
+// phy_write( 21, 0x0006 ); // Rev. 1.2
+ phy_write( 21, 0x1006 ); // new in Rev. 1.6
+ phy_write( 23, 0x2100 );
+// } else if ( GSpeed_sel[1] ) {//option
+// phy_write( 31, 0x0000 );
+// phy_write( 9, 0x0200 );
+// phy_write( 0, 0x1200 );
+// } else if ( GSpeed_sel[2] ) {//option
+// phy_write( 31, 0x0000 );
+// phy_write( 9, 0x0200 );
+// phy_write( 4, 0x05e1 );
+// phy_write( 0, 0x1200 );
+ }
+ } // End if ( BurstEnable )
+} // End void recov_phy_realtek1 (int loop_phy)
+
+//------------------------------------------------------------
+//internal loop 1G : no loopback stub
+//internal loop 100M: no loopback stub
+//internal loop 10M : no loopback stub
+void phy_realtek1 (int loop_phy) {//RTL8211D
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Realtek] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ if ( BurstEnable ) {
+ if ( IEEETesting ) {
+ if ( GSpeed_sel[0] ) {
+ if (IOTimingBund_arg == 0) {
+ //Test Mode 1
+ phy_write( 31, 0x0002 );
+ phy_write( 2, 0xc22b );
+ phy_write( 31, 0x0000 );
+ phy_write( 9, 0x2000 );
+ }
+ else {
+ //Test Mode 4
+ phy_write( 31, 0x0000 );
+ phy_write( 9, 0x8000 );
+ }
+ phy_write( 31, 0x0000 );
+ }
+ else if ( GSpeed_sel[1] ) {
+ if ( IOTimingBund_arg == 0 ) {
+ //From Channel A
+ phy_write( 23, 0xa102 );
+ phy_write( 16, 0x01ae );//MDI
+ }
+ else {
+ //From Channel B
+ phy_Read_Write( 17, 0x0008, 0x0000 ); // clr set
+ phy_write( 23, 0xa102 ); // MDI
+ phy_write( 16, 0x010e );
+ }
+ } else {
+// if ( IOTimingBund_arg == 0 ) {//Pseudo-random pattern
+// phy_write( 31, 0x0006 );
+// phy_write( 0, 0x5a21 );
+// phy_write( 31, 0x0000 );
+// }
+// else if ( IOTimingBund_arg == 1 ) {//¡§FF¡¨ pattern
+// phy_write( 31, 0x0006 );
+// phy_write( 2, 0x05ee );
+// phy_write( 0, 0xff21 );
+// phy_write( 31, 0x0000 );
+// } else {//¡§00¡¨ pattern
+// phy_write( 31, 0x0006 );
+// phy_write( 2, 0x05ee );
+// phy_write( 0, 0x0021 );
+// phy_write( 31, 0x0000 );
+// }
+ }
+ }
+ else {
+ phy_Reset(loop_phy);
+ }
+ }
+ else if ( loop_phy ) {
+ phy_Reset(loop_phy);
+
+ if ( GSpeed_sel[0] ) {
+ phy_write(20, 0x0042);//new in Rev. 1.6
+ }
+ }
+ else {
+ if ( GSpeed_sel[0] ) {
+ phy_write( 31, 0x0001 );
+ phy_write( 3, 0xff41 );
+ phy_write( 2, 0xd720 );
+ phy_write( 1, 0x0140 );
+ phy_write( 0, 0x00bb );
+ phy_write( 4, 0xb800 );
+ phy_write( 4, 0xb000 );
+
+ phy_write( 31, 0x0007 );
+ phy_write( 30, 0x0040 );
+ phy_write( 24, 0x0008 );
+
+ phy_write( 31, 0x0000 );
+ phy_write( 9, 0x0300 );
+ phy_write( 26, 0x0020 );
+ phy_write( 0, 0x0140 );
+ phy_write( 23, 0xa101 );
+ phy_write( 21, 0x0200 );
+ phy_write( 23, 0xa121 );
+ phy_write( 23, 0xa161 );
+ phy_write( 0, 0x8000 );
+ phy_Wait_Reset_Done();
+ phy_delay(200); // new in Rev. 1.6
+// }
+// else if ( GSpeed_sel[1] ) {//option
+// phy_write( 31, 0x0000 );
+// phy_write( 9, 0x0000 );
+// phy_write( 4, 0x0061 );
+// phy_write( 0, 0x1200 );
+// phy_delay(5000);
+// }
+// else if (GSpeed_sel[2]) {//option
+// phy_write( 31, 0x0000 );
+// phy_write( 9, 0x0000 );
+// phy_write( 4, 0x05e1 );
+// phy_write( 0, 0x1200 );
+// phy_delay(5000);
+ }
+ else {
+ phy_Reset(loop_phy);
+ }
+ }
+} // End void phy_realtek1 (int loop_phy)
+
+//------------------------------------------------------------
+void recov_phy_realtek2 (int loop_phy) {//RTL8211E
+ if ( BurstEnable ) {
+ if ( IEEETesting ) {
+ phy_write( 31, 0x0005 );
+ phy_write( 5, 0x8b86 );
+ phy_write( 6, 0xe201 );
+ phy_write( 31, 0x0007 );
+ phy_write( 30, 0x0020 );
+ phy_write( 21, 0x1108 );
+ phy_write( 31, 0x0000 );
+
+ if ( GSpeed_sel[0] ) {
+ phy_write( 31, 0x0000 );
+ phy_write( 9, 0x0000 );
+ }
+ else if ( GSpeed_sel[1] ) {
+ phy_write( 31, 0x0007 );
+ phy_write( 30, 0x002f );
+ phy_write( 23, 0xd88f );
+ phy_write( 30, 0x002d );
+ phy_write( 24, 0xf050 );
+ phy_write( 31, 0x0000 );
+ phy_write( 16, 0x006e );
+ }
+ else {
+ }
+ }
+ else {
+ }
+ }
+ else if (loop_phy) {
+ }
+ else {
+ if (GSpeed_sel[0]) {
+ //Rev 1.5 //not stable
+// phy_write( 31, 0x0000 );
+// phy_write( 0, 0x8000 );
+// phy_Wait_Reset_Done();
+// phy_delay(30);
+// phy_write( 23, 0x2160 );
+// phy_write( 31, 0x0007 );
+// phy_write( 30, 0x0040 );
+// phy_write( 24, 0x0004 );
+// phy_write( 24, 0x1a24 );
+// phy_write( 25, 0xfd00 );
+// phy_write( 24, 0x0000 );
+// phy_write( 31, 0x0000 );
+// phy_write( 0, 0x1140 );
+// phy_write( 26, 0x0040 );
+// phy_write( 31, 0x0007 );
+// phy_write( 30, 0x002f );
+// phy_write( 23, 0xd88f );
+// phy_write( 30, 0x0023 );
+// phy_write( 22, 0x0300 );
+// phy_write( 31, 0x0000 );
+// phy_write( 21, 0x1006 );
+// phy_write( 23, 0x2100 );
+/**/
+ //Rev 1.6
+ phy_write( 31, 0x0000 );
+ phy_write( 0, 0x8000 );
+ phy_Wait_Reset_Done();
+ phy_delay(30);
+ phy_write( 31, 0x0007 );
+ phy_write( 30, 0x0042 );
+ phy_write( 21, 0x0500 );
+ phy_write( 31, 0x0000 );
+ phy_write( 0, 0x1140 );
+ phy_write( 26, 0x0040 );
+ phy_write( 31, 0x0007 );
+ phy_write( 30, 0x002f );
+ phy_write( 23, 0xd88f );
+ phy_write( 30, 0x0023 );
+ phy_write( 22, 0x0300 );
+ phy_write( 31, 0x0000 );
+ phy_write( 21, 0x1006 );
+ phy_write( 23, 0x2100 );
+/**/
+// } else if (GSpeed_sel[1]) {//option
+// phy_write( 31, 0x0000 );
+// phy_write( 9, 0x0200 );
+// phy_write( 0, 0x1200 );
+// } else if (GSpeed_sel[2]) {//option
+// phy_write( 31, 0x0000 );
+// phy_write( 9, 0x0200 );
+// phy_write( 4, 0x05e1 );
+// phy_write( 0, 0x1200 );
+ }
+ }
+} // End void recov_phy_realtek2 (int loop_phy)
+
+//------------------------------------------------------------
+//internal loop 1G : no loopback stub
+//internal loop 100M: no loopback stub
+//internal loop 10M : no loopback stub
+void phy_realtek2 (int loop_phy) {//RTL8211E
+
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Realtek] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ phy_Read_Write( 0, 0x0000, 0x8000 | PHY_00h ); // clr set // Rst PHY
+ phy_Wait_Reset_Done();
+ phy_delay(30);
+
+ if ( BurstEnable ) {
+ if ( IEEETesting ) {
+ phy_write( 31, 0x0005 );
+ phy_write( 5, 0x8b86 );
+ phy_write( 6, 0xe200 );
+ phy_write( 31, 0x0007 );
+ phy_write( 30, 0x0020 );
+ phy_write( 21, 0x0108 );
+ phy_write( 31, 0x0000 );
+
+ if ( GSpeed_sel[0] ) {
+ phy_write( 31, 0x0000 );
+
+ if ( IOTimingBund_arg == 0 ) {
+ phy_write( 9, 0x2000);//Test Mode 1
+ }
+ else {
+ phy_write( 9, 0x8000);//Test Mode 4
+ }
+ }
+ else if ( GSpeed_sel[1] ) {
+ phy_write( 31, 0x0007 );
+ phy_write( 30, 0x002f );
+ phy_write( 23, 0xd818 );
+ phy_write( 30, 0x002d );
+ phy_write( 24, 0xf060 );
+ phy_write( 31, 0x0000 );
+
+ if ( IOTimingBund_arg == 0 ) {
+ phy_write(16, 0x00ae);//From Channel A
+ }
+ else {
+ phy_write(16, 0x008e);//From Channel B
+ }
+ }
+ else {
+ }
+ }
+ else {
+ phy_basic_setting(loop_phy);
+ phy_delay(30);
+ }
+ }
+ else if (loop_phy) {
+ phy_basic_setting(loop_phy);
+
+ phy_Read_Write(0, 0x0000, 0x8000 | PHY_00h);//clr set//Rst PHY
+ phy_Wait_Reset_Done();
+ phy_delay(30);
+
+ phy_basic_setting(loop_phy);
+ phy_delay(30);
+ }
+ else {
+ if ( GSpeed_sel[0] ) {
+ //Rev 1.5 //not stable
+// phy_write( 23, 0x2160 );
+// phy_write( 31, 0x0007 );
+// phy_write( 30, 0x0040 );
+// phy_write( 24, 0x0004 );
+// phy_write( 24, 0x1a24 );
+// phy_write( 25, 0x7d00 );
+// phy_write( 31, 0x0000 );
+// phy_write( 23, 0x2100 );
+// phy_write( 31, 0x0007 );
+// phy_write( 30, 0x0040 );
+// phy_write( 24, 0x0000 );
+// phy_write( 30, 0x0023 );
+// phy_write( 22, 0x0006 );
+// phy_write( 31, 0x0000 );
+// phy_write( 0, 0x0140 );
+// phy_write( 26, 0x0060 );
+// phy_write( 31, 0x0007 );
+// phy_write( 30, 0x002f );
+// phy_write( 23, 0xd820 );
+// phy_write( 31, 0x0000 );
+// phy_write( 21, 0x0206 );
+// phy_write( 23, 0x2120 );
+// phy_write( 23, 0x2160 );
+/**/
+ //Rev 1.6
+ phy_write( 31, 0x0007 );
+ phy_write( 30, 0x0042 );
+ phy_write( 21, 0x2500 );
+ phy_write( 30, 0x0023 );
+ phy_write( 22, 0x0006 );
+ phy_write( 31, 0x0000 );
+ phy_write( 0, 0x0140 );
+ phy_write( 26, 0x0060 );
+ phy_write( 31, 0x0007 );
+ phy_write( 30, 0x002f );
+ phy_write( 23, 0xd820 );
+ phy_write( 31, 0x0000 );
+ phy_write( 21, 0x0206 );
+ phy_write( 23, 0x2120 );
+ phy_write( 23, 0x2160 );
+ phy_delay(300);
+/**/
+// }
+// else if ( GSpeed_sel[1] ) {//option
+// phy_write( 31, 0x0000 );
+// phy_write( 9, 0x0000 );
+// phy_write( 4, 0x0061 );
+// phy_write( 0, 0x1200 );
+// phy_delay(5000);
+// }
+// else if ( GSpeed_sel[2] ) {//option
+// phy_write( 31, 0x0000 );
+// phy_write( 9, 0x0000 );
+// phy_write( 4, 0x05e1 );
+// phy_write( 0, 0x1200 );
+// phy_delay(5000);
+ }
+ else {
+ phy_basic_setting(loop_phy);
+ phy_delay(150);
+ }
+ }
+} // End void phy_realtek2 (int loop_phy)
+
+//------------------------------------------------------------
+void recov_phy_realtek3 (int loop_phy) {//RTL8211C
+ if ( BurstEnable ) {
+ if ( IEEETesting ) {
+ if ( GSpeed_sel[0] ) {
+ phy_write( 9, 0x0000 );
+ }
+ else if ( GSpeed_sel[1] ) {
+ phy_write( 17, PHY_11h );
+ phy_write( 14, 0x0000 );
+ phy_write( 16, 0x00a0 );
+ }
+ else {
+// phy_write( 31, 0x0006 );
+// phy_write( 0, 0x5a00 );
+// phy_write( 31, 0x0000 );
+ }
+ }
+ else {
+ }
+ }
+ else if (loop_phy) {
+ if ( GSpeed_sel[0] ) {
+ phy_write( 11, 0x0000 );
+ }
+ phy_write( 12, 0x1006 );
+ }
+ else {
+ if ( GSpeed_sel[0] ) {
+ phy_write( 31, 0x0001 );
+ phy_write( 4, 0xb000 );
+ phy_write( 3, 0xff41 );
+ phy_write( 2, 0xdf20 );
+ phy_write( 1, 0x0140 );
+ phy_write( 0, 0x00bb );
+ phy_write( 4, 0xb800 );
+ phy_write( 4, 0xb000 );
+
+ phy_write( 31, 0x0000 );
+ phy_write( 25, 0x8c00 );
+ phy_write( 26, 0x0040 );
+ phy_write( 0, 0x1140 );
+ phy_write( 14, 0x0000 );
+ phy_write( 12, 0x1006 );
+ phy_write( 23, 0x2109 );
+ }
+ }
+}
+
+//------------------------------------------------------------
+void phy_realtek3 (int loop_phy) {//RTL8211C
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Realtek] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ if ( BurstEnable ) {
+ if ( IEEETesting ) {
+ if ( GSpeed_sel[0] ) {
+ if ( IOTimingBund_arg == 0 ) { //Test Mode 1
+ phy_write( 9, 0x2000);
+ }
+ else if (IOTimingBund_arg == 1) {//Test Mode 2
+ phy_write( 9, 0x4000);
+ }
+ else if (IOTimingBund_arg == 2) {//Test Mode 3
+ phy_write( 9, 0x6000);
+ }
+ else { //Test Mode 4
+ phy_write( 9, 0x8000);
+ }
+ }
+ else if ( GSpeed_sel[1] ) {
+ PHY_11h = phy_read( PHY_SR );
+ phy_write( 17, PHY_11h & 0xfff7 );
+ phy_write( 14, 0x0660 );
+
+ if ( IOTimingBund_arg == 0 ) {
+ phy_write( 16, 0x00a0 );//MDI //From Channel A
+ }
+ else {
+ phy_write( 16, 0x0080 );//MDIX //From Channel B
+ }
+ }
+ else {
+// if (IOTimingBund_arg == 0) {//Pseudo-random pattern
+// phy_write( 31, 0x0006 );
+// phy_write( 0, 0x5a21 );
+// phy_write( 31, 0x0000 );
+// }
+// else if (IOTimingBund_arg == 1) {//¡§FF¡¨ pattern
+// phy_write( 31, 0x0006 );
+// phy_write( 2, 0x05ee );
+// phy_write( 0, 0xff21 );
+// phy_write( 31, 0x0000 );
+// }
+// else {//¡§00¡¨ pattern
+// phy_write( 31, 0x0006 );
+// phy_write( 2, 0x05ee );
+// phy_write( 0, 0x0021 );
+// phy_write( 31, 0x0000 );
+// }
+ }
+ }
+ else {
+ phy_Reset(loop_phy);
+ }
+ }
+ else if (loop_phy) {
+ phy_write( 0, 0x9200);
+ phy_Wait_Reset_Done();
+ phy_delay(30);
+
+ phy_write( 17, 0x401c );
+ phy_write( 12, 0x0006 );
+
+ if ( GSpeed_sel[0] ) {
+ phy_write(11, 0x0002);
+ }
+ else {
+ phy_basic_setting(loop_phy);
+ }
+ }
+ else {
+ if (GSpeed_sel[0]) {
+ phy_write( 31, 0x0001 );
+ phy_write( 4, 0xb000 );
+ phy_write( 3, 0xff41 );
+ phy_write( 2, 0xd720 );
+ phy_write( 1, 0x0140 );
+ phy_write( 0, 0x00bb );
+ phy_write( 4, 0xb800 );
+ phy_write( 4, 0xb000 );
+
+ phy_write( 31, 0x0000 );
+ phy_write( 25, 0x8400 );
+ phy_write( 26, 0x0020 );
+ phy_write( 0, 0x0140 );
+ phy_write( 14, 0x0210 );
+ phy_write( 12, 0x0200 );
+ phy_write( 23, 0x2109 );
+ phy_write( 23, 0x2139 );
+ }
+ else {
+ phy_Reset(loop_phy);
+ }
+ }
+} // End void phy_realtek3 (int loop_phy)
+
+//------------------------------------------------------------
+void phy_realtek4 (int loop_phy) {//RTL8201F
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Realtek] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ if ( BurstEnable ) {
+ if ( IEEETesting ) {
+ phy_write( 31, 0x0004 );
+ phy_write( 16, 0x4077 );
+ phy_write( 21, 0xc5a0 );
+ phy_write( 31, 0x0000 );
+
+ if ( GSpeed_sel[1] ) {
+ phy_write( 0, 0x8000 ); // Reset PHY
+ phy_write( 24, 0x0310 ); // Disable ALDPS
+
+ if ( IOTimingBund_arg == 0 ) {
+ phy_write( 28, 0x40c2 ); //Force MDI //From Channel A (RJ45 pair 1, 2)
+ }
+ else {
+ phy_write( 28, 0x40c0 ); //Force MDIX//From Channel B (RJ45 pair 3, 6)
+ }
+ phy_write( 0, 0x2100); //Force 100M/Full Duplex)
+ }
+ } else {
+ phy_Reset(loop_phy);
+ }
+ }
+ else {
+ phy_Reset(loop_phy);
+ }
+}
+
+//------------------------------------------------------------
+void phy_smsc (int loop_phy) {//LAN8700
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[SMSC] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ phy_Reset(loop_phy);
+}
+
+//------------------------------------------------------------
+void phy_micrel (int loop_phy) {//KSZ8041
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[Micrel] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ phy_Reset(loop_phy);
+
+// phy_write(24, 0x0600);
+}
+
+//------------------------------------------------------------
+void phy_micrel0 (int loop_phy) {//KSZ8031/KSZ8051
+ if ( DbgPrn_PHYName ) printf ("--->(%04lx %04lx)[Micrel] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ //For KSZ8051RNL only
+ //Reg1Fh[7] = 0(default): 25MHz Mode, XI, XO(pin 9, 8) is 25MHz(crystal/oscilator).
+ //Reg1Fh[7] = 1 : 50MHz Mode, XI(pin 9) is 50MHz(oscilator).
+ PHY_1fh = phy_read(31);
+ if (PHY_1fh & 0x0080) sprintf(PHYName, "%s-50MHz Mode", PHYName);
+ else sprintf(PHYName, "%s-25MHz Mode", PHYName);
+
+ if (IEEETesting) {
+ phy_Read_Write( 0, 0x0000, 0x8000 | PHY_00h );//clr set//Rst PHY
+ phy_Wait_Reset_Done();
+
+ phy_Read_Write( 31, 0x0000, 0x2000 );//clr set//1Fh[13] = 1: Disable auto MDI/MDI-X
+ phy_basic_setting(loop_phy);
+ phy_Read_Write( 31, 0x0000, 0x0800 );//clr set//1Fh[11] = 1: Force link pass
+
+// phy_delay(2500);//2.5 sec
+ }
+ else {
+ phy_Reset(loop_phy);
+
+ //Reg16h[6] = 1 : RMII B-to-B override
+ //Reg16h[1] = 1(default): RMII override
+ phy_Read_Write( 22, 0x0000, 0x0042 );//clr set
+ }
+
+ if ( PHY_1fh & 0x0080 )
+ phy_Read_Write( 31, 0x0000, 0x0080 );//clr set//Reset PHY will clear Reg1Fh[7]
+}
+
+//------------------------------------------------------------
+void recov_phy_vitesse (int loop_phy) {//VSC8601
+ if ( BurstEnable ) {
+// if (IEEETesting) {
+// } else {
+// }
+ }
+ else if ( loop_phy ) {
+ }
+ else {
+ if ( GSpeed_sel[0] ) {
+ phy_write( 24, PHY_18h );
+ phy_write( 18, PHY_12h );
+ }
+ }
+}
+
+//------------------------------------------------------------
+void phy_vitesse (int loop_phy) {//VSC8601
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)[VITESSE] %s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ if ( BurstEnable ) {
+ if ( IEEETesting ) {
+ phy_Reset(loop_phy);
+ }
+ else {
+ phy_Reset(loop_phy);
+ }
+ }
+ else if ( loop_phy ) {
+ phy_Reset(loop_phy);
+ }
+ else {
+ if ( GSpeed_sel[0] ) {
+ PHY_18h = phy_read( 24 );
+ PHY_12h = phy_read( PHY_INER );
+
+ phy_Reset(loop_phy);
+
+ phy_write( 24, PHY_18h | 0x0001 );
+ phy_write( 18, PHY_12h | 0x0020 );
+ }
+ else {
+ phy_Reset(loop_phy);
+ }
+ }
+}
+
+//------------------------------------------------------------
+void phy_default (int loop_phy) {
+ if ( DbgPrn_PHYName )
+ printf ("--->(%04lx %04lx)%s\n", PHY_ID2, PHY_ID3, PHYName);
+
+ phy_Reset(loop_phy);
+}
+
+//------------------------------------------------------------
+// PHY Init
+//------------------------------------------------------------
+BOOLEAN find_phyadr (void) {
+ ULONG PHY_val;
+ BOOLEAN ret = FALSE;
+
+ #ifdef DbgPrn_FuncHeader
+ printf ("find_phyadr\n");
+ Debug_delay();
+ #endif
+
+ do {
+ // Check current PHY address by user setting
+ PHY_val = phy_read( PHY_REG_ID_1 );
+ if ( PHY_IS_VALID(PHY_val) ) {
+ ret = TRUE;
+ break;
+ }
+
+ if ( Enable_SkipChkPHY ) {
+ PHY_val = phy_read( PHY_REG_BMCR );
+
+ if ((PHY_val & 0x8000) & Enable_InitPHY) {
+ // PHY is reseting and need to inital PHY
+ #ifndef Enable_SearchPHYID
+ break;
+ #endif
+ }
+ else {
+ ret = TRUE;
+ break;
+ }
+ }
+
+ #ifdef Enable_SearchPHYID
+ // Scan PHY address from 0 to 31
+ printf("Search PHY address\n");
+ for ( PHY_ADR = 0; PHY_ADR < 32; PHY_ADR++ ) {
+ PHY_val = phy_read( PHY_REG_ID_1 );
+ if ( PHY_IS_VALID(PHY_val) ) {
+ ret = TRUE;
+ break;
+ }
+ }
+ // Don't find PHY address
+ PHY_ADR = PHY_ADR_arg;
+ #endif
+ } while ( 0 );
+
+ if ( ret == TRUE ) {
+ if ( PHY_ADR_arg != PHY_ADR ) {
+
+ if ( !BurstEnable )
+ phy_id( FP_LOG );
+
+ phy_id( STD_OUT );
+ }
+ }
+ else {
+
+ if ( !BurstEnable )
+ phy_id( FP_LOG );
+
+ phy_id( STD_OUT );
+ FindErr( Err_PHY_Type );
+ }
+
+ return ret;
+} // End BOOLEAN find_phyadr (void)
+
+//------------------------------------------------------------
+char phy_chk (ULONG id2, ULONG id3, ULONG id3_mask) {
+ if ((PHY_ID2 == id2) && ((PHY_ID3 & id3_mask) == (id3 & id3_mask)))
+ return(1);
+ else
+ return(0);
+}
+
+//------------------------------------------------------------
+void phy_set00h (int loop_phy) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("phy_set00h\n");
+ Debug_delay();
+ #endif
+
+ if (BurstEnable) {
+ if (IEEETesting) {
+ if (GSpeed_sel[0]) PHY_00h = 0x0140;
+ else if (GSpeed_sel[1]) PHY_00h = 0x2100;
+ else PHY_00h = 0x0100;
+ }
+ else {
+ if (GSpeed_sel[0]) PHY_00h = 0x1140;
+ else if (GSpeed_sel[1]) PHY_00h = 0x3100;
+ else PHY_00h = 0x1100;
+ }
+ }
+ else if (loop_phy) {
+ if (GSpeed_sel[0]) PHY_00h = 0x4140;
+ else if (GSpeed_sel[1]) PHY_00h = 0x6100;
+ else PHY_00h = 0x4100;
+ }
+ else {
+ if (GSpeed_sel[0]) PHY_00h = 0x0140;
+ else if (GSpeed_sel[1]) PHY_00h = 0x2100;
+ else PHY_00h = 0x0100;
+ }
+}
+
+//------------------------------------------------------------
+void phy_sel (int loop_phy) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("phy_sel\n");
+ Debug_delay();
+ #endif
+
+ PHY_ID2 = phy_read( PHY_REG_ID_1 );
+ PHY_ID3 = phy_read( PHY_REG_ID_2 );
+ phy_set00h(loop_phy);
+
+ if ((PHY_ID2 == 0xffff) && (PHY_ID3 == 0xffff) && !Enable_SkipChkPHY) {
+ sprintf(PHYName, "--");
+ FindErr(Err_PHY_Type);
+ }
+#ifdef Enable_CheckZeroPHYID
+ else if ((PHY_ID2 == 0x0000) && (PHY_ID3 == 0x0000) && !Enable_SkipChkPHY) {
+ sprintf(PHYName, "--"); FindErr(Err_PHY_Type);
+ }
+#endif
+
+ if (phy_chk(0x0362, 0x5e6a, 0xfff0 )) {sprintf(PHYName, "BCM54612" ); if (Enable_InitPHY) phy_broadcom0(loop_phy);}//BCM54612 1G/100/10M RGMII
+ else if (phy_chk(0x0362, 0x5d10, 0xfff0 )) {sprintf(PHYName, "BCM54616S" ); if (Enable_InitPHY) phy_broadcom0(loop_phy);}//BCM54616A 1G/100/10M RGMII
+ else if (phy_chk(0x0040, 0x61e0, PHYID3_Mask)) {sprintf(PHYName, "BCM5221" ); if (Enable_InitPHY) phy_broadcom (loop_phy);}//BCM5221 100/10M MII, RMII
+ else if (phy_chk(0x0141, 0x0dd0, 0xfff0 )) {sprintf(PHYName, "88E1512" ); if (Enable_InitPHY) phy_marvell2 (loop_phy);}//88E1512 1G/100/10M RGMII
+ else if (phy_chk(0xff00, 0x1761, 0xffff )) {sprintf(PHYName, "88E6176(IntLoop)"); if (Enable_InitPHY) phy_marvell1 (loop_phy);}//88E6176 1G/100/10M 2 RGMII Switch
+ else if (phy_chk(0x0141, 0x0e90, 0xfff0 )) {sprintf(PHYName, "88E1310" ); if (Enable_InitPHY) phy_marvell0 (loop_phy);}//88E1310 1G/100/10M RGMII
+ else if (phy_chk(0x0141, 0x0cc0, PHYID3_Mask)) {sprintf(PHYName, "88E1111" ); if (Enable_InitPHY) phy_marvell (loop_phy);}//88E1111 1G/100/10M GMII, MII, RGMII
+ else if (phy_chk(0x001c, 0xc816, 0xffff )) {sprintf(PHYName, "RTL8201F" ); if (Enable_InitPHY) phy_realtek4 (loop_phy);}//RTL8201F 100/10M MII, RMII
+ else if (phy_chk(0x001c, 0xc815, 0xfff0 )) {sprintf(PHYName, "RTL8201E" ); if (Enable_InitPHY) phy_realtek0 (loop_phy);}//RTL8201E 100/10M MII, RMII(RTL8201E(L)-VC only)
+ else if (phy_chk(0x001c, 0xc912, 0xffff )) {sprintf(PHYName, "RTL8211C" ); if (Enable_InitPHY) phy_realtek3 (loop_phy);}//RTL8211C 1G/100/10M RGMII
+ else if (phy_chk(0x001c, 0xc914, 0xffff )) {sprintf(PHYName, "RTL8211D" ); if (Enable_InitPHY) phy_realtek1 (loop_phy);}//RTL8211D 1G/100/10M GMII(RTL8211DN/RTL8211DG only), MII(RTL8211DN/RTL8211DG only), RGMII
+ else if (phy_chk(0x001c, 0xc915, 0xffff )) {sprintf(PHYName, "RTL8211E" ); if (Enable_InitPHY) phy_realtek2 (loop_phy);}//RTL8211E 1G/100/10M GMII(RTL8211EG only), RGMII
+ else if (phy_chk(0x0000, 0x8201, PHYID3_Mask)) {sprintf(PHYName, "RTL8201N" ); if (Enable_InitPHY) phy_realtek (loop_phy);}//RTL8201N 100/10M MII, RMII
+ else if (phy_chk(0x0007, 0xc0c4, PHYID3_Mask)) {sprintf(PHYName, "LAN8700" ); if (Enable_InitPHY) phy_smsc (loop_phy);}//LAN8700 100/10M MII, RMII
+ else if (phy_chk(0x0022, 0x1555, 0xfff0 )) {sprintf(PHYName, "KSZ8031/KSZ8051" ); if (Enable_InitPHY) phy_micrel0 (loop_phy);}//KSZ8051/KSZ8031 100/10M RMII
+ else if (phy_chk(0x0022, 0x1560, 0xfff0 )) {sprintf(PHYName, "KSZ8081" ); if (Enable_InitPHY) phy_micrel0 (loop_phy);}//KSZ8081 100/10M RMII
+ else if (phy_chk(0x0022, 0x1512, 0xfff0 )) {sprintf(PHYName, "KSZ8041" ); if (Enable_InitPHY) phy_micrel (loop_phy);}//KSZ8041 100/10M RMII
+ else if (phy_chk(0x0007, 0x0421, 0xfff0 )) {sprintf(PHYName, "VSC8601" ); if (Enable_InitPHY) phy_vitesse (loop_phy);}//VSC8601 1G/100/10M RGMII
+ else {sprintf(PHYName, "default" ); if (Enable_InitPHY) phy_default (loop_phy);}//
+}
+
+//------------------------------------------------------------
+void recov_phy (int loop_phy) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("recov_phy\n");
+ Debug_delay();
+ #endif
+
+ if (phy_chk(0x0362, 0x5e6a, 0xfff0 )) recov_phy_broadcom0(loop_phy);//BCM54612 1G/100/10M RGMII
+ else if (phy_chk(0x0362, 0x5d10, 0xfff0 )) recov_phy_broadcom0(loop_phy);//BCM54616A 1G/100/10M RGMII
+ else if (phy_chk(0x0141, 0x0dd0, 0xfff0 )) recov_phy_marvell2 (loop_phy);//88E1512 1G/100/10M RGMII
+ else if (phy_chk(0xff00, 0x1761, 0xffff )) recov_phy_marvell1 (loop_phy);//88E6176 1G/100/10M 2 RGMII Switch
+ else if (phy_chk(0x0141, 0x0e90, 0xfff0 )) recov_phy_marvell0 (loop_phy);//88E1310 1G/100/10M RGMII
+ else if (phy_chk(0x0141, 0x0cc0, PHYID3_Mask)) recov_phy_marvell (loop_phy);//88E1111 1G/100/10M GMII, MII, RGMII
+ else if (phy_chk(0x001c, 0xc914, 0xffff )) recov_phy_realtek1 (loop_phy);//RTL8211D 1G/100/10M GMII(RTL8211DN/RTL8211DG only), MII(RTL8211DN/RTL8211DG only), RGMII
+ else if (phy_chk(0x001c, 0xc915, 0xffff )) recov_phy_realtek2 (loop_phy);//RTL8211E 1G/100/10M GMII(RTL8211EG only), RGMII
+ else if (phy_chk(0x001c, 0xc912, 0xffff )) recov_phy_realtek3 (loop_phy);//RTL8211C 1G/100/10M RGMII
+ else if (phy_chk(0x0007, 0x0421, 0xfff0 )) recov_phy_vitesse (loop_phy);//VSC8601 1G/100/10M RGMII
+}
+
+//------------------------------------------------------------
+void init_phy (int loop_phy) {
+ #ifdef DbgPrn_FuncHeader
+ printf ("init_phy\n");
+ Debug_delay();
+ #endif
+
+ sprintf( PHYID, "PHY%d", SelectMAC + 1 );
+
+ if ( DbgPrn_PHYInit )
+ phy_dump( PHYID );
+
+ if ( find_phyadr() == TRUE )
+ phy_sel( loop_phy );
+
+ if ( DbgPrn_PHYInit )
+ phy_dump( PHYID );
+}
+
+
diff --git a/arch/arm/cpu/arm926ejs/aspeed/PLLTESTU.H b/arch/arm/cpu/arm926ejs/aspeed/PLLTESTU.H new file mode 100644 index 0000000..6fa96e6 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/PLLTESTU.H @@ -0,0 +1,50 @@ +/* + * 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 + */ +#ifndef PLLTESTU_H +#define PLLTESTU_H + +//PLL Mode Definition +#define NAND_PLLMODE 0x00 +#define DELAY_PLLMODE 0x04 +#define PCI_PLLMODE 0x08 +#define DPLL_PLLMODE 0x2c +#define MPLL_PLLMODE 0x10 +#define HPLL_PLLMODE 0x14 +#define LPC_PLLMODE 0x18 +#define VIDEOA_PLLMODE 0x1c +#define D2PLL_PLLMODE 0x0c +#define VIDEOB_PLLMODE 0x3c + +#define PCI_PLLMODE_AST1160 0x10 +#define MPLL_PLLMODE_AST1160 0x14 +#define HPLL_PLLMODE_AST1160 0x14 +#define DPLL_PLLMODE_AST1160 0x1c + +#define PCI_PLLMODE_AST2300 0x2c +#define MPLL_PLLMODE_AST2300 0x10 +#define HPLL_PLLMODE_AST2300 0x30 +#define DPLL_PLLMODE_AST2300 0x08 +#define DEL0_PLLMODE_AST2300 0x00 + +#define ERR_FATAL 0x00000001 + +typedef struct _VGAINFO { + USHORT usDeviceID; + UCHAR jRevision; + + ULONG ulMCLK; + ULONG ulDRAMBusWidth; + + ULONG ulCPUCLK; + ULONG ulAHBCLK; +} _VGAInfo; + +#endif // End PLLTESTU_H diff --git a/arch/arm/cpu/arm926ejs/aspeed/PLLTESTU.c b/arch/arm/cpu/arm926ejs/aspeed/PLLTESTU.c new file mode 100644 index 0000000..2414d57 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/PLLTESTU.c @@ -0,0 +1,409 @@ +/* + * 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 + */ +#define PLLTEST_C +static const char ThisFile[] = "PLLTEST.c"; + +#include "SWFUNC.H" + +#include "COMMINF.H" +#include "STDUBOOT.H" +#include "TYPEDEF.H" +#include "IO.H" +#include "PLLTESTU.H" + +/* + * static + */ +static UCHAR jVersion[] = "v.0.57.00"; + +void print_usage( void ) +{ + printf(" PLLTest [pll mode] [err rate]\n"); + printf(" [pll mode] h-pll: ARM CPU Clock PLL\n"); + printf(" m-pll: Memory Clock PLL\n"); + printf(" [err rate] Error Rate: unit %\n"); + printf(" default is 1%\n"); +} + +BOOL CompareToRing(_VGAInfo *VGAInfo, ULONG ulPLLMode, ULONG ulDCLK, ULONG ulErrRate) +{ + ULONG ulCounter, ulLowLimit, ulHighLimit; + ULONG ulData, ulValue, ulDiv; + ULONG ulSCUBase; + double del0; + ULONG uldel0; + + if ((VGAInfo->usDeviceID == 0x1160) || (VGAInfo->usDeviceID == 0x1180)) + ulSCUBase = 0x80fc8200; + else + ulSCUBase = 0x1e6e2000; + + //Fixed AST2300 H-PLL can't Get Correct Value in VGA only mode, ycchen@081711 + if ( (VGAInfo->jRevision >= 0x20) && (ulPLLMode == HPLL_PLLMODE_AST2300) ) + { + WriteSOC_DD(ulSCUBase, 0x1688a8a8); + ulData = ReadSOC_DD(ulSCUBase + 0x08); + WriteSOC_DD(ulSCUBase + 0x08, ulData & 0xFFFFFF00); + } + + ulCounter = (ulDCLK/1000) * 512 / 24000 - 1; + ulLowLimit = ulCounter * (100 - ulErrRate) / 100; + ulHighLimit = ulCounter * (100 + ulErrRate) / 100; + + DELAY(10); + WriteSOC_DD(ulSCUBase, 0x1688a8a8); + WriteSOC_DD(ulSCUBase + 0x28, (ulHighLimit << 16) | ulLowLimit); + WriteSOC_DD(ulSCUBase + 0x10, ulPLLMode); + WriteSOC_DD(ulSCUBase + 0x10, ulPLLMode | 0x03); + DELAY(1); + do { + ulData = ReadSOC_DD(ulSCUBase + 0x10); + } while (!(ulData & 0x40)); + ulValue = ReadSOC_DD(ulSCUBase + 0x14); + + //Patch for AST1160/1180 DCLK calculate + if ( ((VGAInfo->usDeviceID == 0x1160) || (VGAInfo->usDeviceID == 0x1180)) && (ulPLLMode == DPLL_PLLMODE_AST1160) ) + { + ulData = ReadSOC_DD(0x80fc906c); + ulDiv = ulData & 0x000c0000; + ulDiv >>= 18; + ulDiv++; + ulValue /= ulDiv; + } + + if ( (VGAInfo->jRevision >= 0x20) && (ulPLLMode == DEL0_PLLMODE_AST2300) ) + { + del0 = (double)(24.0 * (ulValue + 1) / 512.0); + del0 = 1000/del0/16/8; + uldel0 = (ULONG) (del0 * 1000000); + if (uldel0 < ulDCLK) + { + printf( "[PASS][DEL0] Actual DEL0:%f ns, Max. DEL0:%f ns \n", del0, (double)ulDCLK/1000000); + ulData |= 0x80; + } + else + { + printf( "[ERROR][DEL0] Actual DEL0:%f ns, Max. DEL0:%f ns \n", del0, (double)ulDCLK/1000000); + ulData == 0x00; + } + } + else + { + printf( "[INFO] PLL Predict Count = %x, Actual Count = %x \n", ulCounter, ulValue); + } + + WriteSOC_DD(ulSCUBase + 0x10, 0x2C); //disable ring + + if (ulData & 0x80) + return (TRUE); + else + return(FALSE); +} /* CompareToRing */ + +VOID GetDRAMInfo(_VGAInfo *VGAInfo) +{ + ULONG ulData, ulData2; + ULONG ulRefPLL, ulDeNumerator, ulNumerator, ulDivider, ulOD; + + if (VGAInfo->jRevision >= 0x10) + { + WriteSOC_DD(0x1e6e2000, 0x1688A8A8); + + //Get DRAM Bus Width + ulData = ReadSOC_DD(0x1e6e0004); + if (ulData & 0x40) + VGAInfo->ulDRAMBusWidth = 16; + else + VGAInfo->ulDRAMBusWidth = 32; + + ulRefPLL = 24000; + if (VGAInfo->jRevision >= 0x30) //AST2400 + { + ulData = ReadSOC_DD(0x1e6e2070); + if (ulData & 0x00800000) //D[23] = 1 + ulRefPLL = 25000; + } + + ulData = ReadSOC_DD(0x1e6e2020); + ulDeNumerator = ulData & 0x0F; + ulNumerator = (ulData & 0x07E0) >> 5; + ulOD = (ulData & 0x10) ? 1:2; + + ulData = (ulData & 0x7000) >> 12; + switch (ulData) + { + case 0x07: + ulDivider = 16; + break; + case 0x06: + ulDivider = 8; + break; + case 0x05: + ulDivider = 4; + break; + case 0x04: + ulDivider = 2; + break; + default: + ulDivider = 0x01; + } + + VGAInfo->ulMCLK = ulRefPLL * ulOD * (ulNumerator + 2) / ((ulDeNumerator + 1) * ulDivider * 1000); + } +} // GetDRAMInfo + +VOID GetCLKInfo( _VGAInfo *VGAInfo) +{ + ULONG ulData, ulCPUTrap, ulAHBTrap; + ULONG ulRefPLL, ulDeNumerator, ulNumerator, ulDivider, ulOD; + + if (VGAInfo->jRevision >= 0x30) + { + WriteSOC_DD(0x1e6e2000, 0x1688a8a8); + ulData = ReadSOC_DD(0x1e6e2024); + if (ulData & 0x40000) //from H-PLL + { + ulRefPLL = 24000; + ulData = ReadSOC_DD(0x1e6e2070); + if (ulData & 0x00800000) //D[23] = 1 + ulRefPLL = 25000; + + ulData = ReadSOC_DD(0x1e6e2024); + + ulDeNumerator = ulData & 0x0F; + ulNumerator = (ulData & 0x07E0) >> 5; + ulOD = (ulData & 0x10) ? 1:2; + + VGAInfo->ulCPUCLK = ulRefPLL * ulOD * (ulNumerator + 2) / ((ulDeNumerator + 1) * 1000); + + } + else //from trapping + { + ulRefPLL = 24; + ulData = ReadSOC_DD(0x1e6e2070); + if (ulData & 0x00800000) //D[23] = 1 + ulRefPLL = 25; + + ulCPUTrap = ulData & 0x0300; + ulCPUTrap >>= 8; + + switch (ulCPUTrap) + { + case 0x00: + VGAInfo->ulCPUCLK = ulRefPLL * 16; + break; + case 0x01: + VGAInfo->ulCPUCLK = ulRefPLL * 15; + break; + case 0x02: + VGAInfo->ulCPUCLK = ulRefPLL * 14; + break; + case 0x03: + VGAInfo->ulCPUCLK = ulRefPLL * 17; + break; + } + + } + + ulData = ReadSOC_DD(0x1e6e2070); + ulAHBTrap = ulData & 0x0c00; + ulAHBTrap >>= 10; + switch (ulAHBTrap) + { + case 0x00: + VGAInfo->ulAHBCLK = VGAInfo->ulCPUCLK; + break; + case 0x01: + VGAInfo->ulAHBCLK = VGAInfo->ulCPUCLK / 2; + break; + case 0x02: + VGAInfo->ulAHBCLK = VGAInfo->ulCPUCLK / 4; + break; + case 0x03: + VGAInfo->ulAHBCLK = VGAInfo->ulCPUCLK / 3; + break; + } + + } //AST2400 + else if (VGAInfo->jRevision >= 0x20) + { + WriteSOC_DD(0x1e6e2000, 0x1688a8a8); + ulData = ReadSOC_DD(0x1e6e2024); + if (ulData & 0x40000) //from H-PLL + { + ulRefPLL = 24000; + + ulData = ReadSOC_DD(0x1e6e2024); + + ulDeNumerator = ulData & 0x0F; + ulNumerator = (ulData & 0x07E0) >> 5; + ulOD = (ulData & 0x10) ? 1:2; + + VGAInfo->ulCPUCLK = ulRefPLL * ulOD * (ulNumerator + 2) / ((ulDeNumerator + 1) * 1000); + + } + else //from trapping + { + ulData = ReadSOC_DD(0x1e6e2070); + ulCPUTrap = ulData & 0x0300; + ulCPUTrap >>= 8; + + switch (ulCPUTrap) + { + case 0x00: + VGAInfo->ulCPUCLK = 384; + break; + case 0x01: + VGAInfo->ulCPUCLK = 360; + break; + case 0x02: + VGAInfo->ulCPUCLK = 336; + break; + case 0x03: + VGAInfo->ulCPUCLK = 408; + break; + } + + } + + ulData = ReadSOC_DD(0x1e6e2070); + ulAHBTrap = ulData & 0x0c00; + ulAHBTrap >>= 10; + switch (ulAHBTrap) + { + case 0x00: + VGAInfo->ulAHBCLK = VGAInfo->ulCPUCLK; + break; + case 0x01: + VGAInfo->ulAHBCLK = VGAInfo->ulCPUCLK / 2; + break; + case 0x02: + VGAInfo->ulAHBCLK = VGAInfo->ulCPUCLK / 4; + break; + case 0x03: + VGAInfo->ulAHBCLK = VGAInfo->ulCPUCLK / 3; + break; + } + + } //AST2300 +} // GetCLKInfo + +int pll_function(int argc, char *argv[]) +{ + _VGAInfo *pVGAInfo; + ULONG ulErrRate = 1; + ULONG PLLMode; + ULONG RefClk; + CHAR *stop_at; + CHAR i; + + printf("**************************************************** \n"); + printf("*** ASPEED Graphics PLL Test %s Log *** \n", jVersion); + printf("*** for u-boot *** \n"); + printf("**************************************************** \n"); + printf("\n"); + + // Check chip type + switch ( ReadSOC_DD( 0x1e6e2000 + 0x7c ) ) { + case 0x02010303 : + case 0x02000303 : + printf("The chip is AST2400\n" ); + pVGAInfo->usDeviceID = 0x2400; + pVGAInfo->jRevision = 0x30; + break; + + case 0x02010103 : + case 0x02000003 : + printf("The chip is AST1400\n" ); + pVGAInfo->usDeviceID = 0x1400; + pVGAInfo->jRevision = 0x30; + break; + + case 0x01010303 : + case 0x01000003 : + printf("The chip is AST2300\n" ); + pVGAInfo->usDeviceID = 0x2300; + pVGAInfo->jRevision = 0x20; + break; + + case 0x01010203 : + printf("The chip is AST1050\n" ); + pVGAInfo->usDeviceID = 0x1050; + pVGAInfo->jRevision = 0x20; + break; + + default : + printf ("Error Silicon Revision ID(SCU7C) %08lx!!!\n", ReadSOC_DD( 0x1e6e2000 + 0x7c ) ); + return(1); + } + + + GetDRAMInfo( pVGAInfo ); + GetCLKInfo( pVGAInfo ); + + if ( ( argc <= 1 ) || ( argc >= 4 ) ){ + print_usage(); + return (ERR_FATAL); + } + else { + for ( i = 1; i < argc; i++ ) { + switch ( i ) { + case 1: + if (!strcmp(argv[i], "m-pll")) + { + if (pVGAInfo->jRevision >= 0x20) + PLLMode = MPLL_PLLMODE_AST2300; + else + PLLMode = MPLL_PLLMODE; + + RefClk = pVGAInfo->ulMCLK * 1000000; + if (pVGAInfo->jRevision >= 0x20) //dual-edge + RefClk /= 2; + } + else if (!strcmp(argv[i], "h-pll")) + { + if (pVGAInfo->jRevision >= 0x20) + PLLMode = HPLL_PLLMODE_AST2300; + else + PLLMode = HPLL_PLLMODE; + + //AST2300 only has HCLK ring test mode, ycchen@040512 + RefClk = pVGAInfo->ulCPUCLK * 1000000; //Other : H-PLL + if (pVGAInfo->jRevision >= 0x20) //AST2300: HCLK + RefClk = pVGAInfo->ulAHBCLK * 1000000; + } + else { + print_usage(); + return (ERR_FATAL); + } + break; + case 2: + ulErrRate = (ULONG) strtoul(argv[i], &stop_at, 10); + + break; + default: + break; + } // End switch() + } // End for + } + + /* Compare ring */ + if (CompareToRing(pVGAInfo, PLLMode, RefClk, ulErrRate ) == TRUE) + { + printf("[PASS] %s PLL Check Pass!! \n", argv[1]); + return 0; + } + else + { + printf("[ERROR] %s PLL Check Failed!! \n", argv[1]); + return (ERR_FATAL); + } +} diff --git a/arch/arm/cpu/arm926ejs/aspeed/SPIM.c b/arch/arm/cpu/arm926ejs/aspeed/SPIM.c new file mode 100644 index 0000000..e1bdd07 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/SPIM.c @@ -0,0 +1,63 @@ +/*
+ * 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
+ */
+#define SPIM_C
+static const char ThisFile[] = "SPIM.c";
+
+#include "SWFUNC.H"
+
+#ifdef SPI_BUS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <conio.h>
+#include <string.h>
+#include "TYPEDEF.H"
+#include "LIB_SPI.H"
+
+#define SPIM_CMD_WHA 0x01
+#define SPIM_CMD_RD 0x0B
+#define SPIM_CMD_DRD 0xBB
+#define SPIM_CMD_WR 0x02
+#define SPIM_CMD_DWR 0xD2
+#define SPIM_CMD_STA 0x05
+#define SPIM_CMD_ENBYTE 0x06
+#define SPIM_CMD_DISBYTE 0x04
+
+ULONG spim_cs;
+ULONG spim_base;
+ULONG spim_hadr;
+
+void spim_end()
+{
+ ULONG data;
+
+ data = MIndwm((ULONG)mmiobase, 0x1E620010 + (spim_cs << 2));
+ MOutdwm( (ULONG)mmiobase, 0x1E620010 + (spim_cs << 2), data | 0x4);
+ MOutdwm( (ULONG)mmiobase, 0x1E620010 + (spim_cs << 2), data);
+}
+
+//------------------------------------------------------------
+void spim_init(int cs)
+{
+ ULONG data;
+
+ spim_cs = cs;
+ MOutdwm( (ULONG)mmiobase, 0x1E620000, (0x2 << (cs << 1)) | (0x10000 << cs));
+ MOutdwm( (ULONG)mmiobase, 0x1E620010 + (cs << 2), 0x00000007);
+ MOutdwm( (ULONG)mmiobase, 0x1E620010 + (cs << 2), 0x00002003);
+ MOutdwm( (ULONG)mmiobase, 0x1E620004, 0x100 << cs);
+ data = MIndwm((ULONG)mmiobase, 0x1E620030 + (cs << 2));
+ spim_base = 0x20000000 | ((data & 0x007f0000) << 7);
+ MOutwm ( (ULONG)mmiobase, spim_base, SPIM_CMD_WHA);
+ spim_end();
+ spim_hadr = 0;
+}
+#endif // End SPI_BUS
diff --git a/arch/arm/cpu/arm926ejs/aspeed/STDUBOOT.H b/arch/arm/cpu/arm926ejs/aspeed/STDUBOOT.H new file mode 100644 index 0000000..4e0adf6 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/STDUBOOT.H @@ -0,0 +1,17 @@ +/* + * 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 + */ +#ifndef STDUBOOT_H +#define STDUBOOT_H + +unsigned long int strtoul(char *string, char **endPtr, int base); +int atoi( char s[] ); + +#endif // End STDUBOOT_H diff --git a/arch/arm/cpu/arm926ejs/aspeed/STDUBOOT.c b/arch/arm/cpu/arm926ejs/aspeed/STDUBOOT.c new file mode 100644 index 0000000..4b1f439 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/STDUBOOT.c @@ -0,0 +1,224 @@ +/* + * 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 + */ +#define STDUBOOT_C +static const char ThisFile[] = "STDUBOOT.c"; + +#include "SWFUNC.H" + +#ifdef SLT_UBOOT + +int isspace ( char c ) +{ + if ( ( c == ' ' ) || ( c == 9 ) || ( c == 13 ) ) + return 1; + + return 0; +} + +/* + * strtoul.c -- + * + * Source code for the "strtoul" library procedure. + * + * Copyright 1988 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + */ + +//#include <ctype.h> + +/* + * The table below is used to convert from ASCII digits to a + * numerical equivalent. It maps from '0' through 'z' to integers + * (100 for non-digit characters). + */ + +static char cvtIn[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ + 100, 100, 100, 100, 100, 100, 100, /* punctuation */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, + 100, 100, 100, 100, 100, 100, /* punctuation */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35}; + +/* + *---------------------------------------------------------------------- + * + * strtoul -- + * + * Convert an ASCII string into an integer. + * + * Results: + * The return value is the integer equivalent of string. If endPtr + * is non-NULL, then *endPtr is filled in with the character + * after the last one that was part of the integer. If string + * doesn't contain a valid integer value, then zero is returned + * and *endPtr is set to string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned long int +strtoul(char *string, char **endPtr, int base) + /* string; String of ASCII digits, possibly + * preceded by white space. For bases + * greater than 10, either lower- or + * upper-case digits may be used. + */ + /* **endPtr; Where to store address of terminating + * character, or NULL. */ + /* base; Base for conversion. Must be less + * than 37. If 0, then the base is chosen + * from the leading characters of string: + * "0x" means hex, "0" means octal, anything + * else means decimal. + */ +{ + register char *p; + register unsigned long int result = 0; + register unsigned digit; + int anyDigits = 0; + + /* + * Skip any leading blanks. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + + /* + * If no base was provided, pick one from the leading characters + * of the string. + */ + + if (base == 0) + { + if (*p == '0') { + p += 1; + if (*p == 'x') { + p += 1; + base = 16; + } else { + + /* + * Must set anyDigits here, otherwise "0" produces a + * "no digits" error. + */ + + anyDigits = 1; + base = 8; + } + } + else base = 10; + } else if (base == 16) { + + /* + * Skip a leading "0x" from hex numbers. + */ + + if ((p[0] == '0') && (p[1] == 'x')) { + p += 2; + } + } + + /* + * Sorry this code is so messy, but speed seems important. Do + * different things for base 8, 10, 16, and other. + */ + + if (base == 8) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > 7) { + break; + } + result = (result << 3) + digit; + anyDigits = 1; + } + } else if (base == 10) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > 9) { + break; + } + result = (10*result) + digit; + anyDigits = 1; + } + } else if (base == 16) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > ('z' - '0')) { + break; + } + digit = cvtIn[digit]; + if (digit > 15) { + break; + } + result = (result << 4) + digit; + anyDigits = 1; + } + } else { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > ('z' - '0')) { + break; + } + digit = cvtIn[digit]; + if (digit >= base) { + break; + } + result = result*base + digit; + anyDigits = 1; + } + } + + /* + * See if there were any digits at all. + */ + + if (!anyDigits) { + p = string; + } + + if (endPtr != 0) { + *endPtr = p; + } + + return result; +} + +// ----------------------------------------------------------------------------- +int atoi( char s[] ) +{ + + int i; + int ans = 0; + + for( i = 0; s[i] >= '0' && s[i] <= '9'; ++i ) + ans = ( 10 * ans ) + ( s[i] - '0' ); + + return ans; +} + +#endif // End SLT_UBOOT diff --git a/arch/arm/cpu/arm926ejs/aspeed/STRESS.c b/arch/arm/cpu/arm926ejs/aspeed/STRESS.c new file mode 100644 index 0000000..e86685e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/STRESS.c @@ -0,0 +1,144 @@ +/*
+ * 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
+ */
+#define STRESS_C
+static const char ThisFile[] = "STRESS.c";
+
+#include "SWFUNC.H"
+#include "COMMINF.H"
+#include "IO.H"
+
+#define TIMEOUT_DRAM 5000000
+
+/* ------------------------------------------------------------------------- */
+int MMCTestBurst(unsigned int datagen)
+{
+ unsigned int data;
+ unsigned int timeout = 0;
+
+ WriteSOC_DD( 0x1E6E0070, 0x00000000 );
+ WriteSOC_DD( 0x1E6E0070, (0x000000C1 | (datagen << 3)) );
+
+ do {
+ data = ReadSOC_DD( 0x1E6E0070 ) & 0x3000;
+
+ if( data & 0x2000 )
+ return(0);
+
+ if( ++timeout > TIMEOUT_DRAM ) {
+ printf("Timeout!!\n");
+ WriteSOC_DD( 0x1E6E0070, 0x00000000 );
+
+ return(0);
+ }
+ } while( !data );
+ WriteSOC_DD( 0x1E6E0070, 0x00000000 );
+
+ return(1);
+}
+
+/* ------------------------------------------------------------------------- */
+int MMCTestSingle(unsigned int datagen)
+{
+ unsigned int data;
+ unsigned int timeout = 0;
+
+ WriteSOC_DD( 0x1E6E0070, 0x00000000 );
+ WriteSOC_DD( 0x1E6E0070, (0x00000085 | (datagen << 3)) );
+
+ do {
+ data = ReadSOC_DD( 0x1E6E0070 ) & 0x3000;
+
+ if( data & 0x2000 )
+ return(0);
+
+ if( ++timeout > TIMEOUT_DRAM ){
+ printf("Timeout!!\n");
+ WriteSOC_DD( 0x1E6E0070, 0x00000000 );
+
+ return(0);
+ }
+ } while ( !data );
+ WriteSOC_DD( 0x1E6E0070, 0x00000000 );
+
+ return(1);
+}
+
+/* ------------------------------------------------------------------------- */
+int MMCTest()
+{
+ unsigned int pattern;
+
+ pattern = ReadSOC_DD( 0x1E6E2078 );
+ printf("Pattern = %08X : ",pattern);
+
+ WriteSOC_DD(0x1E6E0074, (DRAM_MapAdr | 0x7fffff) );
+ WriteSOC_DD(0x1E6E007C, pattern );
+
+ if(!MMCTestBurst(0)) return(0);
+ if(!MMCTestBurst(1)) return(0);
+ if(!MMCTestBurst(2)) return(0);
+ if(!MMCTestBurst(3)) return(0);
+ if(!MMCTestBurst(4)) return(0);
+ if(!MMCTestBurst(5)) return(0);
+ if(!MMCTestBurst(6)) return(0);
+ if(!MMCTestBurst(7)) return(0);
+ if(!MMCTestSingle(0)) return(0);
+ if(!MMCTestSingle(1)) return(0);
+ if(!MMCTestSingle(2)) return(0);
+ if(!MMCTestSingle(3)) return(0);
+ if(!MMCTestSingle(4)) return(0);
+ if(!MMCTestSingle(5)) return(0);
+ if(!MMCTestSingle(6)) return(0);
+ if(!MMCTestSingle(7)) return(0);
+
+ return(1);
+}
+
+/* ------------------------------------------------------------------------- */
+int dram_stress_function(int argc, char *argv[])
+{
+ unsigned int Pass;
+ unsigned int PassCnt = 0;
+ unsigned int Testcounter = 0;
+ int ret = 1;
+ char *stop_at;
+
+ printf("**************************************************** \n");
+ printf("*** ASPEED Stress DRAM *** \n");
+ printf("*** 20131107 for u-boot *** \n");
+ printf("**************************************************** \n");
+ printf("\n");
+
+ if ( argc != 2 ){
+ ret = 0;
+ return ( ret );
+ }
+ else {
+ Testcounter = (unsigned int) strtoul(argv[1], &stop_at, 10);
+ }
+
+ WriteSOC_DD(0x1E6E0000, 0xFC600309);
+
+ while( ( Testcounter > PassCnt ) || ( Testcounter == 0 ) ){
+ if( !MMCTest() ) {
+ printf("FAIL...%d/%d\n", PassCnt, Testcounter);
+ ret = 0;
+
+ break;
+ }
+ else {
+ PassCnt++;
+ printf("Pass %d/%d\n", PassCnt, Testcounter);
+ }
+ } // End while()
+
+ return( ret );
+}
diff --git a/arch/arm/cpu/arm926ejs/aspeed/SWFUNC.H b/arch/arm/cpu/arm926ejs/aspeed/SWFUNC.H new file mode 100644 index 0000000..4671612 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/SWFUNC.H @@ -0,0 +1,137 @@ +/* + * 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 + */ +#ifndef SWFUNC_H +#define SWFUNC_H + + +//--------------------------------------------------------- +// Program information +//--------------------------------------------------------- +#define VER_NAME "Ver 0.34 version @2014/03/25 0932" + +/* == Step 1: ====== Support OS system =================== */ +// LinuxAP +// #define Windows +#define SLT_UBOOT +//#define SLT_DOS + +/* == Step 2:======== Support interface ================== */ +/* Choose One */ +//#define SPI_BUS +//#define USE_LPC +//#define USE_P2A // PCI or PCIe bus to AHB bus + +/* == Step 3:========== Support Chip ================== */ +//#define AST1010_CHIP +//#define AST3200_IOMAP +//#define FPGA + +#ifdef AST1010_CHIP + #ifdef SLT_UBOOT + #define AST1010_IOMAP 1 + #endif + #ifdef SLT_DOS + #define AST1010_IOMAP 2 + + // AST1010 only has LPC interface + #undef USE_P2A + #undef SPI_BUS + #define USE_LPC + #endif +#endif + +/* == Step 4:========== Select PHY ================== */ +//#define SUPPORT_PHY_LAN9303 // Initial PHY via I2C bus +#define LAN9303_I2C_BUSNUM 6 // 1-based +#define LAN9303_I2C_ADR 0x14 + +/* ====================== Program ======================== */ +// The "PHY_NCSI" option is only for DOS compiler +#if defined (PHY_NCSI) + #ifdef SLT_UBOOT + #error Wrong setting...... + #endif +#endif + +#if defined (PHY_NCSI) + #ifdef SUPPORT_PHY_LAN9303 + #error Wrong setting (Can NOT support LAN9303)...... + #endif +#endif + +/* ================= Check setting ===================== */ +#ifdef SLT_UBOOT + #ifdef SLT_DOS + #error Can NOT support two OS + #endif +#endif +#ifdef SLT_DOS + #ifdef SLT_UBOOT + #error Can NOT support two OS + #endif +#endif + +#ifdef USE_P2A + #ifdef SLT_UBOOT + #error Can NOT be set PCI bus in Uboot + #endif +#endif +#ifdef USE_LPC + #ifdef SLT_UBOOT + #error Can NOT be set LPC bus in Uboot + #endif +#endif +#ifdef SPI_BUS + #ifdef SLT_UBOOT + #error Can NOT be set SPI bus in Uboot + #endif +#endif + +/* ======================== Program flow control ======================== */ +#define RUN_STEP 5 +// 0: read_scu +// 1: parameter setup +// 2: init_scu1, +// 3: init_scu_macrst +// 4: Data Initial +// 5: ALL + +/* ====================== Switch print debug message ====================== */ +#define DbgPrn_Enable_Debug_delay 0 +//#define DbgPrn_FuncHeader 0 //1 +#define DbgPrn_ErrFlg 0 +#define DbgPrn_BufAdr 0 //1 +#define DbgPrn_Bufdat 0 +#define DbgPrn_BufdatDetail 0 +#define DbgPrn_PHYRW 0 +#define DbgPrn_PHYInit 0 +#define DbgPrn_PHYName 0 +#define DbgPrn_DumpMACCnt 0 +#define DbgPrn_Info 0 //1 +#define DbgPrn_FRAME_LEN 0 + + +/* ============ Enable or Disable Check item of the descriptor ============ */ +#define CheckRxOwn +#define CheckRxErr +//#define CheckOddNibble +#define CheckCRC +#define CheckRxFIFOFull +#define CheckRxLen +//#define CheckDataEveryTime + +//#define CheckRxbufUNAVA +#define CheckRPktLost +//#define CheckNPTxbufUNAVA +#define CheckTPktLost +#define CheckRxBuf + +#endif // SWFUNC_H diff --git a/arch/arm/cpu/arm926ejs/aspeed/TRAPTEST.c b/arch/arm/cpu/arm926ejs/aspeed/TRAPTEST.c new file mode 100644 index 0000000..24ec0c5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/TRAPTEST.c @@ -0,0 +1,151 @@ +/* + * 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 + */ +#define PLLTEST_C +static const char ThisFile[] = "PLLTEST.c"; + +#include "SWFUNC.H" + +#include "COMMINF.H" +#include "TYPEDEF.H" +#include "IO.H" + +#define ASTCHIP_2400 0 +#define ASTCHIP_2300 1 +#define ASTCHIP_1400 2 +#define ASTCHIP_1300 3 +#define ASTCHIP_1050 4 + +const UCHAR jVersion[] = "v.0.60.06"; + +typedef struct _TRAPINFO { + USHORT CPU_clk; + UCHAR CPU_AHB_ratio; +} _TrapInfo; + +const _TrapInfo AST_default_trap_setting[] = { + // CPU_clk, CPU_AHB_ratio + { 384, 2 }, // AST2400 or AST1250 ( ASTCHIP_2400 ) + { 384, 2 }, // AST2300 ( ASTCHIP_2300 ) + { 384, 0xFF }, // AST1400 ( ASTCHIP_1400 ) + { 384, 0xFF }, // AST1300 ( ASTCHIP_1300 ) + { 384, 2 } // AST1050 ( ASTCHIP_1050 ) +}; + +int trap_function(int argc, char *argv[]) +{ + UCHAR chiptype; + ULONG ulData, ulTemp; + UCHAR status = TRUE; + USHORT val_trap; + + printf("**************************************************** \n"); + printf("*** ASPEED Trap Test %s Log *** \n", jVersion); + printf("*** for u-boot *** \n"); + printf("**************************************************** \n"); + printf("\n"); + + // Check chip type + switch ( ReadSOC_DD( 0x1e6e2000 + 0x7c ) ) { + case 0x02010303 : + case 0x02000303 : + printf("The chip is AST2400 or AST1250\n" ); + chiptype = ASTCHIP_2400; + break; + + case 0x02010103 : + case 0x02000003 : + printf("The chip is AST1400\n" ); + chiptype = ASTCHIP_1400; + break; + + case 0x01010303 : + case 0x01000003 : + printf("The chip is AST2300\n" ); + chiptype = ASTCHIP_2300; + break; + + case 0x01010203 : + printf("The chip is AST1050\n" ); + chiptype = ASTCHIP_1050; + break; + + case 0x01010003 : + printf("The chip is AST1300\n" ); + chiptype = ASTCHIP_1300; + break; + + default : + printf ("Error Silicon Revision ID(SCU7C) %08lx!!!\n", ReadSOC_DD( 0x1e6e2000 + 0x7c ) ); + return(1); + } + + WriteSOC_DD(0x1e6e2000, 0x1688A8A8); + ulData = ReadSOC_DD(0x1e6e2070); + + // Check CPU clock + ulTemp = ulData; + ulTemp &= 0x0300; + ulTemp >>= 8; + + switch (ulTemp) + { + case 0x00: + val_trap = 384; + break; + case 0x01: + val_trap = 360; + break; + case 0x02: + val_trap = 336; + break; + case 0x03: + val_trap = 408; + break; + } + + if (AST_default_trap_setting[chiptype].CPU_clk != val_trap) + { + printf("[ERROR] CPU CLK: Correct is %d; Real is %d \n", AST_default_trap_setting[chiptype].CPU_clk, val_trap); + status = FALSE; + } + + // Check cpu_ahb_ratio + ulTemp = ulData; + ulTemp &= 0x0c00; + ulTemp >>= 10; + + switch (ulTemp) + { + case 0x00: + val_trap = 1; + break; + case 0x01: + val_trap = 2; + break; + case 0x02: + val_trap = 4; + break; + case 0x03: + val_trap = 3; + break; + } + + if (AST_default_trap_setting[chiptype].CPU_AHB_ratio != val_trap) + { + printf("[ERROR] CPU:AHB: Correct is %x:1; Real is %x:1 \n", AST_default_trap_setting[chiptype].CPU_AHB_ratio, val_trap); + status = FALSE; + } + + if ( status == TRUE ) + printf("[PASS] hardware trap for CPU clock and CPU\\AHB ratio.\n"); + + return status; +} diff --git a/arch/arm/cpu/arm926ejs/aspeed/TYPEDEF.H b/arch/arm/cpu/arm926ejs/aspeed/TYPEDEF.H new file mode 100644 index 0000000..3053ad7 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/TYPEDEF.H @@ -0,0 +1,74 @@ +/*
+ * 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
+ */
+#ifndef TYPEDEF_H
+#define TYPEDEF_H
+
+#include "SWFUNC.H"
+
+//
+// Define
+//
+#define PCI 1
+#define PCIE 2
+#define AGP 3
+#define ACTIVE 4
+
+#if defined(LinuxAP)
+ #ifndef FLONG
+ #define FLONG unsigned long
+ #endif
+ #ifndef ULONG
+ #define ULONG unsigned long
+ #endif
+ #ifndef LONG
+ #define LONG long
+ #endif
+ #ifndef USHORT
+ #define USHORT unsigned short
+ #endif
+ #ifndef SHORT
+ #define SHORT short
+ #endif
+ #ifndef UCHAR
+ #define UCHAR unsigned char
+ #endif
+ #ifndef CHAR
+ #define CHAR char
+ #endif
+ #ifndef BYTE
+ #define BYTE unsigned char
+ #endif
+ #ifndef VOID
+ #define VOID void
+ #endif
+ #ifndef SCHAR
+ #define SCHAR signed char
+ #endif
+#else
+/* DOS Program */
+ #define VOID void
+ #define FLONG unsigned long
+ #define ULONG unsigned long
+ #define USHORT unsigned short
+ #define UCHAR unsigned char
+ #define LONG long
+ #define SHORT short
+ #define CHAR char
+ #define BYTE UCHAR
+ #define BOOL SHORT
+ #define BOOLEAN unsigned short
+ #define PULONG ULONG *
+ #define SCHAR signed char
+#endif
+ #define TRUE 1
+ #define FALSE 0
+
+#endif // TYPEDEF_H
diff --git a/arch/arm/cpu/arm926ejs/aspeed/mactest.c b/arch/arm/cpu/arm926ejs/aspeed/mactest.c new file mode 100644 index 0000000..62a696d --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/mactest.c @@ -0,0 +1,1214 @@ +/* + * 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 + */ +#define MACTEST_C +static const char ThisFile[] = "MACTEST.c"; + +#include "SWFUNC.H" + +#ifdef SLT_UBOOT + #include <common.h> + #include <command.h> + #include <post.h> + #include <malloc.h> + #include <net.h> + #include "COMMINF.H" + #include "STDUBOOT.H" + #include "IO.H" +#else + #include <stdlib.h> + #include <string.h> + #include "LIB.H" + #include "COMMINF.H" + #include "IO.H" +#endif + +const BYTE Val_Array[16] = {0,1, 2,3, 4,5, 6,7, 8,9, 10,11, 12,13, 14,15}; // AST2300-A1 +const BYTE Val_Array_A0[16] = {8,1, 10,3, 12,5, 14,7, 0,9, 2,11, 4,13, 6,15}; // AST2300-A0 + +#ifdef SLT_UBOOT +int main_function(int argc, char *argv[]) +#endif +#ifdef SLT_DOS +int main(int argc, char *argv[]) +#endif +{ + CHAR MAC2_Valid; + CHAR MAC_1GEn; + CHAR MAC1_RMII; + CHAR Enable_IntLoopPHY; + CHAR Disable_RecovPHY; + CHAR Force1G; + CHAR Force10M; + CHAR Force100M; + CHAR *stop_at; + ULONG IOStr_val; + ULONG IOStr_max; + ULONG IOStr_shf; + ULONG IOdly_val; + ULONG Err_Flag_allapeed; + int DES_LowNumber; + int index; + int i; + int j; + #ifdef Enable_NCSI_LOOP_INFINI + BYTE GSpeed_org[3]; + #endif + +#ifdef SPI_BUS + VIDEO_ENGINE_INFO VideoEngineInfo; +#else + // ( USE_P2A | USE_LPC ) + UCHAR *ulMMIOLinearBaseAddress; +#endif + + #ifdef SLT_UBOOT + #else + time(×tart); + #endif + + // For DOS system + #if defined(PHY_NCSI) + // For DOS compiler OPEN WATCOM + ModeSwitch = MODE_NSCI; + #else + #ifdef SLT_DOS + ModeSwitch = MODE_DEDICATED; + #endif + #endif + +//------------------------------------------------------------ +// Argument Initial +//------------------------------------------------------------ + Err_Flag_allapeed = 0; + Err_Flag = 0; + Err_Flag_PrintEn = 1; + Loop_rl[0] = 0; + Loop_rl[1] = 0; + Loop_rl[2] = 0; + +//------------------------------------------------------------ +// Bus Initial +//------------------------------------------------------------ +#if defined(LinuxAP) +#else + //DOS system + #ifdef SPI_BUS + #endif + #ifdef USE_LPC + + if ( findlpcport( 0x0d ) == 0) { + printf("Failed to find proper LPC port \n"); + + return(1); + } + open_aspeed_sio_password(); + enable_aspeed_LDU( 0x0d ); + #endif + #ifdef USE_P2A + // PCI bus + #ifdef DOS_PMODEW + if (CheckDOS()) return 1; + #endif + + #ifdef DbgPrn_FuncHeader + printf ("Initial-MMIO\n"); + Debug_delay(); + #endif + ulPCIBaseAddress = FindPCIDevice (0x1A03, 0x2000, ACTIVE); + if ( ulPCIBaseAddress == 0 ) + ulPCIBaseAddress = FindPCIDevice (0x1688, 0x2000, ACTIVE); + if ( ulPCIBaseAddress == 0 ) + ulPCIBaseAddress = FindPCIDevice (0x1A03, 0x0200, ACTIVE); + if ( ulPCIBaseAddress == 0 ) + ulPCIBaseAddress = FindPCIDevice (0x1A03, 0x3000, ACTIVE); + if ( ulPCIBaseAddress == 0 ) + ulPCIBaseAddress = FindPCIDevice (0x1A03, 0x2010, ACTIVE); + if ( ulPCIBaseAddress == 0 ) { + printf ("Can't find device\n"); + + return(1); + } + + WritePCIReg (ulPCIBaseAddress, 0x04, 0xFFFFFFFc, 0x3); + ulMMIOBaseAddress = ReadPCIReg (ulPCIBaseAddress, 0x14, 0xFFFF0000); + ulMMIOLinearBaseAddress = (UCHAR *)MapPhysicalToLinear (ulMMIOBaseAddress, 64 * 1024 * 1024); + #endif // #ifdef USE_P2A +#endif // End defined(LinuxAP) + +#ifdef SPI_BUS + GetDevicePCIInfo (&VideoEngineInfo); + mmiobase = VideoEngineInfo.VGAPCIInfo.ulMMIOBaseAddress; + spim_init(SPI_CS); +#else + // ( USE_P2A | USE_LPC ) + mmiobase = ulMMIOLinearBaseAddress; +#endif + +//------------------------------------------------------------ +// Check Chip Feature +//------------------------------------------------------------ + read_scu(); + + if (RUN_STEP >= 1) { + switch (SCU_7ch_old) { +// case 0x02000003 : sprintf(ASTChipName, "[ ]AST3200-FPGA" ); ASTChipType = 6; AST1100 = 0; break; + + case 0x03020003 : sprintf(ASTChipName, "[ ]AST1010-A2" ); ASTChipType = 5; AST1100 = 0; break; + case 0x03010003 : sprintf(ASTChipName, "[ ]AST1010-A1" ); ASTChipType = 5; AST1100 = 0; break; + case 0x03000003 : sprintf(ASTChipName, "[*]AST1010-A0" ); ASTChipType = 5; AST1100 = 0; break; + + case 0x02010303 : sprintf(ASTChipName, "[*]AST2400-A1" ); ASTChipType = 4; AST1100 = 0; break;//AST2400-A1 + case 0x02000303 : sprintf(ASTChipName, "[ ]AST2400-A0" ); ASTChipType = 4; AST1100 = 0; break;//AST2400-A0 + case 0x02010103 : sprintf(ASTChipName, "[*]AST1400-A1" ); ASTChipType = 4; AST1100 = 0; break;//AST1400-A1 + case 0x02000003 : sprintf(ASTChipName, "[ ]AST1400-A0" ); ASTChipType = 4; AST1100 = 0; break;//AST1400-A0 + + case 0x01010303 : sprintf(ASTChipName, "[*]AST2300-A1" ); ASTChipType = 3; AST1100 = 0; break;//AST2300-A1 + case 0x01010203 : sprintf(ASTChipName, "[*]AST1050-A1" ); ASTChipType = 3; AST1100 = 0; break;//AST1050-A1 + case 0x01010003 : sprintf(ASTChipName, "[*]AST1300-A1" ); ASTChipType = 3; AST1100 = 0; break;//AST1300-A1 + case 0x01000003 : sprintf(ASTChipName, "[ ]AST2300-A0" ); ASTChipType = 3; AST1100 = 0; break;//AST2300-A0 +// case 0x01860003 : sprintf(ASTChipName, "[ ]AST2300-FPGA" ); ASTChipType = 3; AST1100 = 0; break; + + case 0x00000102 : sprintf(ASTChipName, "[*]AST2200-A1" ); ASTChipType = 2; AST1100 = 0; break;//AST2200-A1/A0 + + case 0x00000302 : sprintf(ASTChipName, "[*]AST2100-A3" ); ASTChipType = 1; AST1100 = 0; break;//AST2100-A3/A2 + case 0x00000301 : sprintf(ASTChipName, "[ ]AST2100-A1" ); ASTChipType = 1; AST1100 = 0; break;//AST2100-A1 + case 0x00000300 : sprintf(ASTChipName, "[ ]AST2100-A0" ); ASTChipType = 1; AST1100 = 0; break;//AST2100-A0 + case 0x00000202 : sprintf(ASTChipName, "[*]AST2050/AST1100-A3, AST2150-A1"); ASTChipType = 1; AST1100 = 1; break;//AST2050/AST1100-A3/A2 AST2150-A1/A0 + case 0x00000201 : sprintf(ASTChipName, "[ ]AST2050/AST1100-A1" ); ASTChipType = 1; AST1100 = 1; break;//AST2050/AST1100-A1 + case 0x00000200 : sprintf(ASTChipName, "[ ]AST2050/AST1100-A0" ); ASTChipType = 1; AST1100 = 1; break;//AST2050/AST1100-A0 + + default : + printf ("Error Silicon Revision ID(SCU7C) %08lx!!!\n", SCU_7ch_old); + return(1); + } // End switch (SCU_7ch_old) + + switch (ASTChipType) { + case 6 : AST2300 = 1; AST2400 = 1; AST1010 = 0; AST3200 = 1; break; + case 5 : AST2300 = 1; AST2400 = 1; AST1010 = 1; AST3200 = 0; break; + case 4 : AST2300 = 1; AST2400 = 1; AST1010 = 0; AST3200 = 0; break; + case 3 : AST2300 = 1; AST2400 = 0; AST1010 = 0; AST3200 = 0; break; + default : AST2300 = 0; AST2400 = 0; AST1010 = 0; AST3200 = 0; break; + } // End switch (ASTChipType) + + if (ASTChipType == 3) { +#ifdef Force_Enable_MAC34 + WriteSOC_DD( SCU_BASE + 0xf0, 0xAEED0001 ); //enable mac34 + Enable_MAC34 = 1; +#else + if (SCU_f0h_old & 0x00000001) + Enable_MAC34 = 1; + else + Enable_MAC34 = 0; +#endif + } + else { + Enable_MAC34 = 0; + } // End if (ASTChipType == 3) + + Setting_scu(); + +//------------------------------------------------------------ +// Argument Input +//------------------------------------------------------------ + // Load default value + UserDVal = DEF_USER_DEF_PACKET_VAL; + IOTimingBund_arg = DEF_IOTIMINGBUND; + PHY_ADR_arg = DEF_PHY_ADR; + TestMode = DEF_TESTMODE; + LOOP_INFINI = 0; + LOOP_MAX_arg = 0; + GCtrl = ( DEF_MAC_LOOP_BACK << 6 ) | ( DEF_SKIP_CHECK_PHY << 5 ) | ( DEF_INIT_PHY << 3 ); + GSpeed = DEF_SPEED; + + // Get setting information by user + GRun_Mode = (BYTE)atoi(argv[1]); + + if ( ModeSwitch == MODE_NSCI ) { + ARPNumCnt = DEF_ARPNUMCNT; + ChannelTolNum = DEF_CHANNEL2NUM; + PackageTolNum = DEF_PACKAGE2NUM; + GSpeed = SET_100MBPS; // In NCSI mode, we set to 100M bps + } + + // Setting user's configuration + if (argc > 1) { + if ( ModeSwitch == MODE_NSCI ) + switch (argc) { + case 7: ARPNumCnt = (ULONG)atoi(argv[6]); + case 6: IOTimingBund_arg = (BYTE)atoi(argv[5]); + case 5: TestMode = (BYTE)atoi(argv[4]); + case 4: ChannelTolNum = (BYTE)atoi(argv[3]); + case 3: PackageTolNum = (BYTE)atoi(argv[2]); + default: break; + } + else + switch (argc) { + case 9: UserDVal = strtoul (argv[8], &stop_at, 16); + case 8: IOTimingBund_arg = (BYTE)atoi(argv[7]); + case 7: PHY_ADR_arg = (BYTE)atoi(argv[6]); + case 6: TestMode = (BYTE)atoi(argv[5]); + case 5: strcpy(LOOP_Str, argv[4]); + if (!strcmp(LOOP_Str, "#")) LOOP_INFINI = 1; + else LOOP_MAX_arg = (ULONG)atoi(LOOP_Str); + case 4: GCtrl = (BYTE)atoi(argv[3]); + case 3: GSpeed = (BYTE)atoi(argv[2]); + default: break; + } + + IOTimingBund = IOTimingBund_arg; + PHY_ADR = PHY_ADR_arg; + } + else { + // Wrong parameter + if ( ModeSwitch == MODE_NSCI ) { + if (AST2300) + printf ("\nNCSITEST.exe run_mode <package_num> <channel_num> <test_mode> <IO margin>\n\n"); + else + printf ("\nNCSITEST.exe run_mode <package_num> <channel_num> <test_mode>\n\n"); + PrintMode (); + PrintPakNUm(); + PrintChlNUm(); + PrintTest (); + if (AST2300) + PrintIOTimingBund (); + } + else { + if (AST2300) + printf ("\nMACTEST.exe run_mode <speed> <ctrl> <loop_max> <test_mode> <phy_adr> <IO margin>\n\n"); + else + printf ("\nMACTEST.exe run_mode <speed> <ctrl> <loop_max> <test_mode> <phy_adr>\n\n"); + PrintMode (); + PrintSpeed (); + PrintCtrl (); + PrintLoop (); + PrintTest (); + PrintPHYAdr (); + if (AST2300) + PrintIOTimingBund (); + } + Finish_Close(); + + return(1); + } // End if (argc > 1) + +//------------------------------------------------------------ +// Check Argument +//------------------------------------------------------------ + switch ( GRun_Mode ) { + case 0: printf ("\n[MAC1]\n"); SelectMAC = 0; H_MAC_BASE = MAC_BASE1; break; + case 1: printf ("\n[MAC2]\n"); SelectMAC = 1; H_MAC_BASE = MAC_BASE2; break; + case 2: if (Enable_MAC34) {printf ("\n[MAC3]\n"); SelectMAC = 2; H_MAC_BASE = MAC_BASE3; break;} + else + goto Error_MAC_Mode; + case 3: if (Enable_MAC34) {printf ("\n[MAC4]\n"); SelectMAC = 3; H_MAC_BASE = MAC_BASE4; break;} + else + goto Error_MAC_Mode; + default: +Error_MAC_Mode: + printf ("Error run_mode!!!\n"); + PrintMode (); + + return(1); + } // End switch ( GRun_Mode ) + + H_TDES_BASE = TDES_BASE1; + H_RDES_BASE = RDES_BASE1; + MAC_PHYBASE = H_MAC_BASE; + + Force1G = 0; + Force10M = 0; + Force100M = 0; + GSpeed_sel[0] = 0;//1G + GSpeed_sel[1] = 0;//100M + GSpeed_sel[2] = 0;//10M + + switch ( GSpeed ) { + case SET_1GBPS : Force1G = 1; GSpeed_sel[0] = 1; break; + case SET_100MBPS : Force100M = 1; GSpeed_sel[1] = 1; break; + case SET_10MBPS : Force10M = 1; GSpeed_sel[2] = 1; break; + case SET_1G_100M_10MBPS : break; + default: printf ("Error speed!!!\n"); + PrintSpeed (); + return(1); + } // End switch ( GSpeed ) + + if ( ModeSwitch == MODE_NSCI ) { + Enable_MACLoopback = 0; // For mactest function + Enable_SkipChkPHY = 0; // For mactest function + Enable_IntLoopPHY = 0; // For mactest function + Enable_InitPHY = 0; // For mactest function + Disable_RecovPHY = 0; // For mactest function + BurstEnable = 0; // For mactest function + + PrintNCSIEn = (ARPNumCnt & 0x1); + ARPNumCnt = ARPNumCnt & 0xfffffffe; + + // Check parameter + if ((PackageTolNum < 1) || (PackageTolNum > 8)) { + PrintPakNUm(); + return(1); + } +// if ((ChannelTolNum < 0) || (ChannelTolNum > 32)) { + if (ChannelTolNum > 32) { + PrintChlNUm(); + return(1); + } + + switch (TestMode) { + case 0 : NCSI_DiSChannel = 1; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 1; break; + case 1 : NCSI_DiSChannel = 0; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 1; break; + case 6 : if (AST2300) {NCSI_DiSChannel = 1; IOTiming = 1; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 1; break;} + else + goto Error_Test_Mode_NCSI; + case 7 : if (AST2300) {NCSI_DiSChannel = 1; IOTiming = 1; IOStrength = 1; TxDataEnable = 1; RxDataEnable = 1; break;} + else + goto Error_Test_Mode_NCSI; + default: + // Wrong parameter +Error_Test_Mode_NCSI: + printf ("Error test_mode!!!\n"); + PrintTest (); + return(1); + } // End switch (TestMode) + } + else { + if ( GCtrl & 0xffffff83 ) { + printf ("Error ctrl!!!\n"); + PrintCtrl (); + return(1); + } + else { + Enable_MACLoopback = ( GCtrl >> 6 ) & 0x1; // ?? + Enable_SkipChkPHY = ( GCtrl >> 5 ) & 0x1; // ?? + Enable_IntLoopPHY = ( GCtrl >> 4 ) & 0x1; + Enable_InitPHY = ( GCtrl >> 3 ) & 0x1; + Disable_RecovPHY = ( GCtrl >> 2 ) & 0x1; // ?? + + if (!AST2400 && Enable_MACLoopback) { + printf ("Error ctrl!!!\n"); + PrintCtrl (); + return(1); + } + } // End if ( GCtrl & 0xffffff83 ) + + if (!LOOP_MAX_arg) { + switch (GSpeed) { + case SET_1GBPS : LOOP_MAX_arg = DEF_LOOP_MAX * 200; break; // 20140325 + case SET_100MBPS : LOOP_MAX_arg = DEF_LOOP_MAX * 20 ; break; // 20140325 + case SET_10MBPS : LOOP_MAX_arg = DEF_LOOP_MAX * 10 ; break; // 20140325 + case SET_1G_100M_10MBPS: LOOP_MAX_arg = DEF_LOOP_MAX * 10 ; break; // 20140325 + } + } // End if (!LOOP_MAX_arg) + + LOOP_MAX = LOOP_MAX_arg * 10; // 20140325 + Calculate_LOOP_CheckNum(); + + switch (TestMode) { + case 0 : BurstEnable = 0; IEEETesting = 0; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 1; DataDelay = 0; break; + case 1 : BurstEnable = 1; IEEETesting = 1; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 0; DataDelay = 0; break; + case 2 : BurstEnable = 1; IEEETesting = 1; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 0; DataDelay = 0; break; + case 3 : BurstEnable = 1; IEEETesting = 1; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 0; DataDelay = 0; break; + case 4 : BurstEnable = 1; IEEETesting = 0; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 0; DataDelay = 0; break; // ?? + case 5 : BurstEnable = 1; IEEETesting = 1; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 0; DataDelay = 0; break; // ?? + case 6 : if (AST2300) {BurstEnable = 0; IEEETesting = 0; IOTiming = 1; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 1; DataDelay = 0; break;} + else + goto Error_Test_Mode; + case 7 : if (AST2300) {BurstEnable = 0; IEEETesting = 0; IOTiming = 1; IOStrength = 1; TxDataEnable = 1; RxDataEnable = 1; DataDelay = 0; break;} + else + goto Error_Test_Mode; + case 8 : BurstEnable = 0; IEEETesting = 0; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 0; DataDelay = 0; break; // ?? + case 9 : BurstEnable = 0; IEEETesting = 0; IOTiming = 0; IOStrength = 0; TxDataEnable = 0; RxDataEnable = 1; DataDelay = 0; break; // ?? + case 10 : BurstEnable = 0; IEEETesting = 0; IOTiming = 0; IOStrength = 0; TxDataEnable = 1; RxDataEnable = 1; DataDelay = 1; break; // ?? + default: +Error_Test_Mode: + printf ("Error test_mode!!!\n"); + PrintTest (); + return(1); + } // End switch (TestMode) + + if ( PHY_ADR > 31 ) { + printf ("Error phy_adr!!!\n"); + PrintPHYAdr (); + return(1); + } // End if (PHY_ADR > 31) + } // End if ( ModeSwitch == MODE_NSCI ) + + if ( BurstEnable ) { + IOTimingBund = 0; + } + else { + if ( ~DataDelay && AST2300 ) { + if ( !( ( (7 >= IOTimingBund) && (IOTimingBund & 0x1) ) || + ( IOTimingBund == 0 ) ) ) { + printf ("Error IO margin!!!\n"); + PrintIOTimingBund (); + return(1); + } + } + else { + IOTimingBund = 0; + } // End if ( ~DataDelay && AST2300 ) + + // Define Output file name + if ( ModeSwitch == MODE_NSCI ) + sprintf(FileNameMain, "%d", SelectMAC+1); + else { + if (Enable_IntLoopPHY) + sprintf(FileNameMain, "%dI", SelectMAC+1); + else + sprintf(FileNameMain, "%dE", SelectMAC+1); + } + + #ifndef SLT_UBOOT + if ( IOTiming ) { + if ( IOStrength ) + sprintf(FileName, "MIOD%sS.log", FileNameMain); + else + sprintf(FileName, "MIOD%s.log", FileNameMain); + + fp_log = fopen(FileName,"w"); + + if ( IOStrength ) + sprintf(FileName, "MIO%sS.log", FileNameMain); + else + sprintf(FileName, "MIO%s.log", FileNameMain); + + fp_io = fopen(FileName,"w"); + } + else { + sprintf(FileName, "MAC%s.log", FileNameMain); + + fp_log = fopen(FileName,"w"); + } + #endif + } // End if (BurstEnable) + +//------------------------------------------------------------ +// Check Definition +//------------------------------------------------------------ + for (i = 0; i < 16; i++) + valary[i] = Val_Array[i]; + + if ( AST3200 ) { + MAC_Mode = (SCU_70h_old >> 6) & 0x1; + MAC1_1GEn = (MAC_Mode & 0x1) ? 1 : 0;//1:RGMII, 0:RMII + MAC2_1GEn = 0; + + MAC1_RMII = !MAC1_1GEn; + MAC2_RMII = 0; + MAC2_Valid = 0; + } + else if ( AST1010 ) { + MAC_Mode = 0; + MAC1_1GEn = 0; + MAC2_1GEn = 0; + + MAC1_RMII = 1; + MAC2_RMII = 0; + MAC2_Valid = 0; + } + else if ( AST2300 ) { + if (SCU_7ch_old == 0x01000003) { + //AST2300-A0 + for (i = 0; i < 16; i++) { + valary[i] = Val_Array_A0[i]; + } + } + + MAC_Mode = (SCU_70h_old >> 6) & 0x3; + MAC1_1GEn = (MAC_Mode & 0x1) ? 1 : 0;//1:RGMII, 0:RMII + MAC2_1GEn = (MAC_Mode & 0x2) ? 1 : 0;//1:RGMII, 0:RMII + + MAC1_RMII = !MAC1_1GEn; + MAC2_RMII = !MAC2_1GEn; + MAC2_Valid = 1; + } + else { + MAC_Mode = (SCU_70h_old >> 6) & 0x7; + MAC1_1GEn = (MAC_Mode == 0x0) ? 1 : 0; + MAC2_1GEn = 0; + + switch ( MAC_Mode ) { + case 0 : MAC1_RMII = 0; MAC2_RMII = 0; MAC2_Valid = 0; break; //000: Select GMII(MAC#1) only + case 1 : MAC1_RMII = 0; MAC2_RMII = 0; MAC2_Valid = 1; break; //001: Select MII (MAC#1) and MII(MAC#2) + case 2 : MAC1_RMII = 1; MAC2_RMII = 0; MAC2_Valid = 1; break; //010: Select RMII(MAC#1) and MII(MAC#2) + case 3 : MAC1_RMII = 0; MAC2_RMII = 0; MAC2_Valid = 0; break; //011: Select MII (MAC#1) only + case 4 : MAC1_RMII = 1; MAC2_RMII = 0; MAC2_Valid = 0; break; //100: Select RMII(MAC#1) only +// case 5 : MAC1_RMII = 0; MAC2_RMII = 0; MAC2_Valid = 0; break; //101: Reserved + case 6 : MAC1_RMII = 1; MAC2_RMII = 1; MAC2_Valid = 1; break; //110: Select RMII(MAC#1) and RMII(MAC#2) +// case 7 : MAC1_RMII = 0; MAC2_RMII = 0; MAC2_Valid = 0; break; //111: Disable dual MAC + default: return(Finish_Check(Err_MACMode)); + } + } // End if ( AST3200 ) + + if ( SelectMAC == 0 ) { + Enable_RMII = MAC1_RMII; + MAC_1GEn = MAC1_1GEn; + + if ( Force1G & !MAC1_1GEn ) { + printf ("\nMAC1 don't support 1Gbps !!!\n"); + return( Finish_Check(Err_MACMode) ); + } + } else if (SelectMAC == 1) { + Enable_RMII = MAC2_RMII; + MAC_1GEn = MAC2_1GEn; + + if ( Force1G & !MAC2_1GEn ) { + printf ("\nMAC2 don't support 1Gbps !!!\n"); + return(Finish_Check(Err_MACMode)); + } + if ( !MAC2_Valid ) { + printf ("\nMAC2 not valid !!!\n"); + return(Finish_Check(Err_MACMode)); + } + } + else { + Enable_RMII = 1; + MAC_1GEn = 0; + + if (Force1G) { + printf ("\nMAC3/MAC4 don't support 1Gbps !!!\n"); + return(Finish_Check(Err_MACMode)); + } + } // End if ( SelectMAC == 0 ) + + if ( ModeSwitch == MODE_NSCI ) { + if (!Enable_RMII) { + printf ("\nNCSI must be RMII interface !!!\n"); + return(Finish_Check(Err_MACMode)); + } + } + + if ( GSpeed == SET_1G_100M_10MBPS ) { + GSpeed_sel[0] = MAC_1GEn; + GSpeed_sel[1] = 1; + GSpeed_sel[2] = 1; + } + + if ( AST1010 ) { + // Check bit 13:12 + Dat_ULONG = SCU_08h_old & 0x00003000; + if (Dat_ULONG != 0x00000000) + return(Finish_Check(Err_MHCLK_Ratio)); + } + else if ( AST2300 ) { + Dat_ULONG = (SCU_08h_old >> 16) & 0x7; + if (MAC1_1GEn | MAC2_1GEn) { + if ( (Dat_ULONG == 0) || (Dat_ULONG > 2) ) + return(Finish_Check(Err_MHCLK_Ratio)); + } + else { + if (Dat_ULONG != 4) + return(Finish_Check(Err_MHCLK_Ratio)); + } + } // End if (AST1010) + + //MAC + MAC_08h_old = ReadSOC_DD( H_MAC_BASE + 0x08 ); + MAC_0ch_old = ReadSOC_DD( H_MAC_BASE + 0x0c ); + MAC_40h_old = ReadSOC_DD( H_MAC_BASE + 0x40 ); + + if ( ((MAC_08h_old == 0x0000) && (MAC_0ch_old == 0x00000000)) + || ((MAC_08h_old == 0xffff) && (MAC_0ch_old == 0xffffffff)) +// || (MAC_0ch_old & 0x1) +// || (MAC_0ch_old & 0x2) + ) + { + // Load default for MAC address + SA[0] = 0x00; + SA[1] = 0x57; + SA[2] = 0x89; + SA[3] = 0x56; + SA[4] = 0x88; + SA[5] = 0x38; + } + else { + SA[0] = (MAC_08h_old >> 8) & 0xff; + SA[1] = (MAC_08h_old ) & 0xff; + SA[2] = (MAC_0ch_old >> 24) & 0xff; + SA[3] = (MAC_0ch_old >> 16) & 0xff; + SA[4] = (MAC_0ch_old >> 8) & 0xff; + SA[5] = (MAC_0ch_old ) & 0xff; + } + // printf ("%08x %08x: %02x %02x %02x %02x %02x %02x\n", MAC_08h_old, MAC_0ch_old, SA[0], SA[1], SA[2], SA[3], SA[4], SA[5]); + + if ( AST2300 ) { +#ifdef Force_Enable_NewMDIO + AST2300_NewMDIO = 1; + WriteSOC_DD(H_MAC_BASE+0x40, MAC_40h_old | 0x80000000) +#else + AST2300_NewMDIO = (MAC_40h_old & 0x80000000) ? 1 : 0; +#endif + } + else { + AST2300_NewMDIO = 0; + } // End if (AST2300) + +//------------------------------------------------------------ +// Parameter Initial +//------------------------------------------------------------ + if ( AST3200 ) { + SCU_04h = 0x0c000800; //Reset Engine + } + else if (AST1010) { + SCU_04h = 0x00000010; //Reset Engine + } + else if (AST2300) { + SCU_04h = 0x0c001800; //Reset Engine + } + else { + SCU_04h = 0x00001800; //Reset Engine + } // End if ( AST3200 ) + + if ( ModeSwitch == MODE_NSCI ) + // Set to 100Mbps and Enable RX broabcast packets and CRC_APD and Full duplex + MAC_50h = 0x000a0500; + else { + // RX_ALLADR and CRC_APD and Full duplex + MAC_50h = 0x00004500; + + #ifdef Enable_Runt + MAC_50h = MAC_50h | 0x00001000; + #endif + + #ifdef Enable_Jumbo + MAC_50h = MAC_50h | 0x00002000; + #endif + } // End if ( ModeSwitch == MODE_NSCI ) + +//------------------------------------------------------------ +// Descriptor Number +//------------------------------------------------------------ + if ( ModeSwitch == MODE_DEDICATED ) { + + #ifdef Enable_Jumbo + DES_LowNumber = 1; + #else + DES_LowNumber = IOTiming; + #endif + if ( Enable_SkipChkPHY && ( TestMode == 0 ) ) { + DES_NUMBER = 114;//for SMSC's LAN9303 issue + } + else { + if ( AST1010 | AST3200 ) { + DES_NUMBER = (IOTimingBund) ? 100 : 256; + } + else { + switch ( GSpeed ) { + case SET_1GBPS : DES_NUMBER = (IOTimingBund) ? 10 : (DES_LowNumber) ? 50 : 400; break; // 20140325 + case SET_100MBPS : DES_NUMBER = (IOTimingBund) ? 10 : (DES_LowNumber) ? 50 : 400; break; // 20140325 + case SET_10MBPS : DES_NUMBER = (IOTimingBund) ? 10 : (DES_LowNumber) ? 10 : 80; break; // 20140325 + case SET_1G_100M_10MBPS : DES_NUMBER = (IOTimingBund) ? 10 : (DES_LowNumber) ? 10 : 80; break; // 20140325 + } + } // End if ( Enable_SkipChkPHY && ( TestMode == 0 ) ) + } + + #ifdef SelectDesNumber + DES_NUMBER = SelectDesNumber; + #endif + + #ifdef USE_LPC + DES_NUMBER /= 8; + #endif + + #ifdef ENABLE_ARP_2_WOL + if ( TestMode == 4 ) { + DES_NUMBER = 1; + } + #endif + + DES_NUMBER_Org = DES_NUMBER; + + if ( DbgPrn_Info ) { + printf ("CheckBuf_MBSize : %ld\n", CheckBuf_MBSize); + printf ("LOOP_CheckNum : %ld\n", LOOP_CheckNum); + printf ("DES_NUMBER : %ld\n", DES_NUMBER); + printf ("DMA_BufSize : %ld bytes\n", DMA_BufSize); + printf ("DMA_BufNum : %d\n", DMA_BufNum); + printf ("\n"); + } +// if (3 > DMA_BufNum) +// return( Finish_Check(Err_DMABufNum) ); + + if (2 > DMA_BufNum) + return( Finish_Check(Err_DMABufNum) ); + } // End if ( ModeSwitch == MODE_DEDICATED ) + } // End if (RUN_STEP >= 1) + +//------------------------------------------------------------ +// SCU Initial +//------------------------------------------------------------ + if ( RUN_STEP >= 2 ) { + init_scu1(); + } + + if ( RUN_STEP >= 3 ) { + init_scu_macrst(); + } + +//------------------------------------------------------------ +// Data Initial +//------------------------------------------------------------ + if (RUN_STEP >= 4) { + setup_arp(); + if ( ModeSwitch == MODE_DEDICATED ) { + + FRAME_LEN = (ULONG *)malloc(DES_NUMBER * sizeof( ULONG )); + wp_lst = (ULONG *)malloc(DES_NUMBER * sizeof( ULONG )); + + if ( !FRAME_LEN ) + return( Finish_Check( Err_MALLOC_FrmSize ) ); + + if ( !wp_lst ) + return( Finish_Check( Err_MALLOC_LastWP )); + + // Setup data and length + TestingSetup(); + } // End if ( ModeSwitch == MODE_DEDICATED ) + + // Get bit (shift) of IO driving strength register + if ( IOStrength ) { + if (AST1010) { + IOStr_max = 1;//0~1 + } + else if (AST2400) { + IOStr_max = 1;//0~1 + switch (SelectMAC) { + case 0 : IOStr_shf = 9; break; + case 1 : IOStr_shf = 11; break; + } + } + else { + IOStr_max = 3;//0~3 + switch (SelectMAC) { + case 0 : IOStr_shf = 8; break; + case 1 : IOStr_shf = 10; break; + case 2 : IOStr_shf = 12; break; + case 3 : IOStr_shf = 14; break; + } + } + } + else { + IOStr_max = 0; + IOStr_shf = 0; + } // End if (IOStrength) + + // Get current clock delay value of TX(out) and RX(in) in the SCU48 register + // and setting test range + if ( Enable_RMII ) { + switch (GRun_Mode) { + case 0 : IOdly_out_shf = 24; IOdly_in_shf = 8; break; + case 1 : IOdly_out_shf = 25; IOdly_in_shf = 12; break; + case 2 : IOdly_out_shf = 26; IOdly_in_shf = 16; break; + case 3 : IOdly_out_shf = 27; IOdly_in_shf = 20; break; + } + IOdly_in_reg = (SCU_48h_old >> IOdly_in_shf ) & 0xf; + IOdly_out_reg = (SCU_48h_old >> IOdly_out_shf) & 0x1; + } + else { + switch (GRun_Mode) { + case 0 : IOdly_out_shf = 0; IOdly_in_shf = 8; break; + case 1 : IOdly_out_shf = 4; IOdly_in_shf = 12; break; + } + IOdly_in_reg = (SCU_48h_old >> IOdly_in_shf ) & 0xf; + IOdly_out_reg = (SCU_48h_old >> IOdly_out_shf) & 0xf; + } // End if ( Enable_RMII ) + + // Find the coordinate in X-Y axis + for ( index = 0; index <= 15; index++ ) + if ( IOdly_in_reg == valary[index] ) { + IOdly_in_reg_idx = index; + break; + } + for ( index = 0; index <= 15; index++ ) + if ( IOdly_out_reg == valary[index] ) { + IOdly_out_reg_idx = index; + break; + } + + // Get the range for testmargin block + if ( IOTiming ) { + if ( Enable_RMII ) { + IOdly_incval = 1; + IOdly_in_str = 0; + IOdly_in_end = 15; + IOdly_out_str = 0; + IOdly_out_end = 1; + } + else { + IOdly_incval = 1; + IOdly_in_str = 0; + IOdly_in_end = 15; + IOdly_out_str = 0; + IOdly_out_end = 15; + } + } + else if ( IOTimingBund ) { + if ( Enable_RMII ) { + IOdly_incval = 1; + IOdly_in_str = IOdly_in_reg_idx - ( IOTimingBund >> 1 ); + IOdly_in_end = IOdly_in_reg_idx + ( IOTimingBund >> 1 ); + IOdly_out_str = IOdly_out_reg_idx; + IOdly_out_end = IOdly_out_reg_idx; + } + else { + IOdly_incval = 1; + IOdly_in_str = IOdly_in_reg_idx - ( IOTimingBund >> 1 ); + IOdly_in_end = IOdly_in_reg_idx + ( IOTimingBund >> 1 ); + IOdly_out_str = IOdly_out_reg_idx - ( IOTimingBund >> 1 ); + IOdly_out_end = IOdly_out_reg_idx + ( IOTimingBund >> 1 ); + } + if ((IOdly_in_str < 0) || (IOdly_in_end > 15)) + return( Finish_Check( Err_IOMarginOUF ) ); + + if ((IOdly_out_str < 0) || (IOdly_out_end > 15)) + return( Finish_Check( Err_IOMarginOUF ) ); + +// if (IOdly_in_str < 0) IOdly_in_str = 0; +// if (IOdly_in_end > 15) IOdly_in_end = 15; +// if (IOdly_out_str < 0) IOdly_out_str = 0; +// if (IOdly_out_end > 15) IOdly_out_end = 15; + } + else { + IOdly_incval = 1; + IOdly_in_str = 0; + IOdly_in_end = 0; + IOdly_out_str = 0; + IOdly_out_end = 0; + } // End if (IOTiming) + } // End if (RUN_STEP >= 4) + +//------------------------------------------------------------ +// main +//------------------------------------------------------------ + if (RUN_STEP >= 5) { + #ifdef DbgPrn_FuncHeader + printf ("GSpeed_sel: %d %d %d\n", GSpeed_sel[0], GSpeed_sel[1], GSpeed_sel[2]); + Debug_delay(); + #endif + + if ( ModeSwitch == MODE_NSCI ) { + #ifdef Enable_NCSI_LOOP_INFINI + for ( GSpeed_idx = 0; GSpeed_idx < 3; GSpeed_idx++ ) { + GSpeed_org[GSpeed_idx] = GSpeed_sel[GSpeed_idx]; + } +NCSI_LOOP_INFINI:; + for ( GSpeed_idx = 0; GSpeed_idx < 3; GSpeed_idx++ ) { + GSpeed_sel[GSpeed_idx] = GSpeed_org[GSpeed_idx]; + } + #endif + } // End if ( ModeSwitch == MODE_NSCI ) + + for (GSpeed_idx = 0; GSpeed_idx < 3; GSpeed_idx++) { + Err_Flag_PrintEn = 1; + if ( GSpeed_sel[GSpeed_idx] ) { + // Setting the LAN speed + if ( ModeSwitch == MODE_DEDICATED ) { + + + // Test three speed of LAN, we will modify loop number + if (GSpeed == SET_1G_100M_10MBPS) { + if (GSpeed_sel[0]) LOOP_MAX = LOOP_MAX_arg; + else if (GSpeed_sel[1]) LOOP_MAX = LOOP_MAX_arg / 10; + else LOOP_MAX = LOOP_MAX_arg / 100; + + if ( !LOOP_MAX ) + LOOP_MAX = 1; + + Calculate_LOOP_CheckNum(); + } + + // Setting speed of LAN + if (GSpeed_sel[0]) MAC_50h_Speed = 0x00000200; + else if (GSpeed_sel[1]) MAC_50h_Speed = 0x00080000; + else MAC_50h_Speed = 0x00000000; + + //------------------------------------------------------------ + // PHY Initial + //------------------------------------------------------------ + if ( AST1100 ) + init_scu2(); + + if ( Enable_InitPHY ) { +#ifdef SUPPORT_PHY_LAN9303 + LAN9303(LAN9303_I2C_BUSNUM, PHY_ADR_arg, GSpeed_idx, Enable_IntLoopPHY | (BurstEnable<<1) | IEEETesting); +#else + init_phy( Enable_IntLoopPHY ); +#endif + DELAY( Delay_PHYRst * 10 ); + } // End if (Enable_InitPHY) + + if ( AST1100 ) + init_scu3(); + + if ( Err_Flag ) + return( Finish_Check( 0 ) ); + } // End if ( ModeSwitch == MODE_DEDICATED ) + + //------------------------------------------------------------ + // Start + //------------------------------------------------------------ + + // The loop is for different IO strength + for ( IOStr_i = 0; IOStr_i <= IOStr_max; IOStr_i++ ) { + + // Print Header of report to monitor and log file + if ( IOTiming || IOTimingBund ) { + if ( IOStrength ) { + if ( AST1010 ) { + IOStr_val = (SCU_ach_old & 0xfff0ffff) | ((IOStr_i) ? 0xf0000 : 0x0); + } + else { + IOStr_val = (SCU_90h_old & 0xffff00ff) | (IOStr_i << IOStr_shf); + } + //printf("\nIOStrength_val= %08x, ", IOStr_val); + //printf("SCU90h: %08x ->", ReadSOC_DD(SCU_BASE+0x90)); + WriteSOC_DD( SCU_BASE + 0x90, IOStr_val ); + //printf(" %08x\n", ReadSOC_DD(SCU_BASE+0x90)); + + #ifndef SLT_UBOOT + if (GSpeed_sel[0]) fprintf(fp_log, "[Strength %d][1G ]========================================\n", IOStr_i); + else if (GSpeed_sel[1]) fprintf(fp_log, "[Strength %d][100M]========================================\n", IOStr_i); + else fprintf(fp_log, "[Strength %d][10M ]========================================\n", IOStr_i); + #endif + } + else { + #ifndef SLT_UBOOT + if (GSpeed_sel[0]) fprintf(fp_log, "[1G ]========================================\n"); + else if (GSpeed_sel[1]) fprintf(fp_log, "[100M]========================================\n"); + else fprintf(fp_log, "[10M ]========================================\n"); + #endif + } + + if ( IOTimingBund ) + PrintIO_Header(FP_LOG); + if ( IOTiming ) + PrintIO_Header(FP_IO); + + PrintIO_Header(STD_OUT); + + } + else { + if ( ModeSwitch == MODE_DEDICATED ) { + + if (!BurstEnable) + Print_Header(FP_LOG); + + Print_Header(STD_OUT); + } + } // End if (IOTiming || IOTimingBund) + +#ifdef Enable_Old_Style + for (IOdly_i = IOdly_in_str; IOdly_i <= IOdly_in_end; IOdly_i+=IOdly_incval) { + IOdly_in = valary[IOdly_i]; +#else + for (IOdly_j = IOdly_out_str; IOdly_j <= IOdly_out_end; IOdly_j+=IOdly_incval) { + IOdly_out = valary[IOdly_j]; +#endif + + if (IOTiming || IOTimingBund) { +#ifdef Enable_Fast_SCU + #ifdef Enable_Old_Style + WriteSOC_DD(SCU_BASE + 0x48, SCU_48h_mix | (IOdly_in << IOdly_in_shf)); + #else + WriteSOC_DD(SCU_BASE + 0x48, SCU_48h_mix | (IOdly_out << IOdly_out_shf)); + #endif +#endif + + if ( IOTimingBund ) + PrintIO_LineS(FP_LOG); + if ( IOTiming ) + PrintIO_LineS(FP_IO); + + PrintIO_LineS(STD_OUT); + } // End if (IOTiming || IOTimingBund) + + //------------------------------------------------------------ + // SCU Initial + //------------------------------------------------------------ +#ifdef Enable_Fast_SCU + init_scu_macrst(); +#endif +#ifdef Enable_Old_Style + for (IOdly_j = IOdly_out_str; IOdly_j <= IOdly_out_end; IOdly_j+=IOdly_incval) { + IOdly_out = valary[IOdly_j]; +#else + for (IOdly_i = IOdly_in_str; IOdly_i <= IOdly_in_end; IOdly_i+=IOdly_incval) { + IOdly_in = valary[IOdly_i]; +#endif + if ( IOTiming || IOTimingBund ) { + IOdly_val = (IOdly_in << IOdly_in_shf) | (IOdly_out << IOdly_out_shf); + +//printf("\nIOdly_val= %08x, ", IOdly_val); +//printf("SCU48h: %08x ->", ReadSOC_DD( SCU_BASE + 0x48 ) ); + WriteSOC_DD( SCU_BASE + 0x48, SCU_48h_mix | IOdly_val ); +//printf(" %08x\n", ReadSOC_DD(SCU_BASE+0x48)); + } // End if (IOTiming || IOTimingBund) + + //------------------------------------------------------------ + // SCU Initial + //------------------------------------------------------------ +#ifdef Enable_Fast_SCU +#else + init_scu_macrst(); +#endif + + //------------------------------------------------------------ + // MAC Initial + //------------------------------------------------------------ + init_mac(H_MAC_BASE, H_TDES_BASE, H_RDES_BASE); + if ( Err_Flag ) + return( Finish_Check(0) ); + + // Testing + if ( ModeSwitch == MODE_NSCI ) + dlymap[IOdly_i][IOdly_j] = phy_ncsi(); + else + dlymap[IOdly_i][IOdly_j] = TestingLoop(LOOP_CheckNum); + + + // Display to Log file and monitor + if ( IOTiming || IOTimingBund ) { + + if ( IOTimingBund ) + PrintIO_Line(FP_LOG); + + if ( IOTiming ) + PrintIO_Line(FP_IO); + + PrintIO_Line(STD_OUT); + + // Find the range of current setting + if ( ( IOdly_in_reg == IOdly_in ) && ( IOdly_out_reg == IOdly_out ) ) { + IOdly_i_min = IOdly_i - ( IOTimingBund >> 1 ); + IOdly_i_max = IOdly_i + ( IOTimingBund >> 1 ); + + if ( Enable_RMII ) { + IOdly_j_min = IOdly_j; + IOdly_j_max = IOdly_j; + } + else { + IOdly_j_min = IOdly_j - (IOTimingBund >> 1 ); + IOdly_j_max = IOdly_j + (IOTimingBund >> 1 ); + } + } + + PrintIO_Line_LOG(); + FPri_ErrFlag(FP_LOG); + +// Err_Flag_allapeed = Err_Flag_allapeed | Err_Flag; + Err_Flag = 0; + } + }// End for (IOdly_j = IOdly_out_str; IOdly_j <= IOdly_out_end; IOdly_j+=IOdly_incval) +#ifndef SLT_UBOOT + if ( IOTiming || IOTimingBund ) { + if ( IOTimingBund ) + fprintf(fp_log, "\n"); + if (IOTiming ) + fprintf(fp_io, "\n"); + } +#endif + printf("\n"); + } // End for (IOdly_j = IOdly_out_str; IOdly_j <= IOdly_out_end; IOdly_j+=IOdly_incval) + + //------------------------------------------------------------ + // End + //------------------------------------------------------------ + + if ( IOTiming || IOTimingBund ) { + if ( ( IOdly_i_min < 0 ) || ( IOdly_i_max > 15 ) ) + FindErr(Err_IOMarginOUF); + if ( ( IOdly_j_min < 0 ) || ( IOdly_j_max > 15 ) ) + FindErr(Err_IOMarginOUF); + + if ( IOdly_i_min < 0 ) IOdly_i_min = 0; + if ( IOdly_i_max > 15 ) IOdly_i_max = 15; + if ( IOdly_j_min < 0 ) IOdly_j_min = 0; + if ( IOdly_j_max > 15 ) IOdly_j_max = 15; + +#ifdef Enable_Old_Style + for (IOdly_i = IOdly_i_min; IOdly_i <= IOdly_i_max; IOdly_i++) + for (IOdly_j = IOdly_j_min; IOdly_j <= IOdly_j_max; IOdly_j++) +#else + for (IOdly_j = IOdly_j_min; IOdly_j <= IOdly_j_max; IOdly_j++) + for (IOdly_i = IOdly_i_min; IOdly_i <= IOdly_i_max; IOdly_i++) +#endif + { + if ( dlymap[IOdly_i][IOdly_j] ) { +#ifdef SLT_DOS + if ( IOTiming ) { +#ifdef Enable_Old_Style + for (i = IOdly_i_min; i <= IOdly_i_max; i++) +#else + for (j = IOdly_j_min; j <= IOdly_j_max; j++) +#endif + { +#ifdef Enable_Old_Style + for (j = IOdly_j_min; j <= IOdly_j_max; j++) +#else + for (i = IOdly_i_min; i <= IOdly_i_max; i++) +#endif + { + if (dlymap[i][j]) fprintf(fp_io, "x "); + else fprintf(fp_io, "o "); + } + fprintf(fp_io, "\n"); + } + } // End if ( IOTiming ) +#endif // End SLT_DOS + FindErr(Err_IOMargin); + goto Find_Err_IOMargin; + } // End if ( dlymap[IOdly_i][IOdly_j] ) + } + } // End if ( IOTiming || IOTimingBund ) + +Find_Err_IOMargin:; + if ( !BurstEnable ) + FPri_ErrFlag(FP_LOG); + if ( IOTiming ) + FPri_ErrFlag(FP_IO); + + FPri_ErrFlag(STD_OUT); + + Err_Flag_allapeed = Err_Flag_allapeed | Err_Flag; + Err_Flag = 0; + } // End for (IOStr_i = 0; IOStr_i <= IOStr_max; IOStr_i++) + + if ( ModeSwitch == MODE_DEDICATED ) { + if ( Enable_InitPHY & !Disable_RecovPHY ) + recov_phy(Enable_IntLoopPHY); + } + + GSpeed_sel[GSpeed_idx] = 0; + } // End if (GSpeed_sel[GSpeed_idx]) + + Err_Flag_PrintEn = 0; + } // End for (GSpeed_idx = 0; GSpeed_idx < 3; GSpeed_idx++) + + Err_Flag = Err_Flag_allapeed; + + if ( ModeSwitch == MODE_NSCI ) { + #ifdef Enable_NCSI_LOOP_INFINI + if (Err_Flag == 0) { + if (fp_log) { + fclose(fp_log); + fp_log = fopen(FileName,"w"); + } + goto NCSI_LOOP_INFINI; + } + #endif + } + + } // End if (RUN_STEP >= 5) + + return(Finish_Check(0)); + +} diff --git a/arch/arm/cpu/arm926ejs/aspeed/reset.c b/arch/arm/cpu/arm926ejs/aspeed/reset.c new file mode 100644 index 0000000..ce8dba1 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/reset.c @@ -0,0 +1,24 @@ +/* + * 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 <asm/io.h> + +#define AST_WDT_BASE 0x1e785000 +void reset_cpu(ulong addr) +{ + __raw_writel(0x10 , AST_WDT_BASE+0x04); + __raw_writel(0x4755, AST_WDT_BASE+0x08); + __raw_writel(0x23, AST_WDT_BASE+0x0c); /* reset the full chip */ + + while (1) + /*nothing*/; +} diff --git a/arch/arm/cpu/arm926ejs/aspeed/timer.c b/arch/arm/cpu/arm926ejs/aspeed/timer.c new file mode 100644 index 0000000..add4c0e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/aspeed/timer.c @@ -0,0 +1,135 @@ +/* + * 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> + +#if CONFIG_ASPEED_TIMER_CLK < CONFIG_SYS_HZ +#error "CONFIG_ASPEED_TIMER_CLK must be as large as CONFIG_SYS_HZ" +#endif + +#define TIMER_LOAD_VAL 0xffffffff +#define CLK_PER_HZ (CONFIG_ASPEED_TIMER_CLK / CONFIG_SYS_HZ) + +/* macro to read the 32 bit timer */ +#define READ_CLK (*(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0)) +#define READ_TIMER (READ_CLK / CLK_PER_HZ) + +static ulong timestamp; +static ulong lastdec; + +int timer_init (void) +{ + *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 4) = TIMER_LOAD_VAL; + *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 0x30) = 0x3; /* enable timer1 */ + + /* init the timestamp and lastdec value */ + reset_timer_masked(); + + return 0; +} + +/* + * timer without interrupts + */ + +void reset_timer (void) +{ + reset_timer_masked (); +} + +ulong get_timer (ulong base) +{ + return get_timer_masked () - base; +} + +void set_timer (ulong t) +{ + timestamp = t; +} + +/* delay x useconds AND perserve advance timstamp value */ +void __udelay (unsigned long usec) +{ + ulong last = READ_CLK; + ulong clks; + ulong elapsed = 0; + + /* translate usec to clocks */ + clks = (usec / 1000) * CLK_PER_HZ; + clks += (usec % 1000) * CLK_PER_HZ / 1000; + + while (clks > elapsed) { + ulong now = READ_CLK; + if (now <= last) { + elapsed += last - now; + } else { + elapsed += TIMER_LOAD_VAL - (now - last); + } + last = now; + } +} + +void reset_timer_masked (void) +{ + /* reset time */ + lastdec = READ_TIMER; /* capure current decrementer value time */ + timestamp = 0; /* start "advancing" time stamp from 0 */ +} + +ulong get_timer_masked (void) +{ + ulong now = READ_TIMER; /* current tick value */ + + if (lastdec >= now) { /* normal mode (non roll) */ + /* normal mode */ + timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */ + } else { /* we have overflow of the count down timer */ + /* nts = ts + ld + (TLV - now) + * ts=old stamp, ld=time that passed before passing through -1 + * (TLV-now) amount of time after passing though -1 + * nts = new "advancing time stamp"...it could also roll and cause problems. + */ + timestamp += lastdec + (TIMER_LOAD_VAL / CLK_PER_HZ) - now; + } + lastdec = now; + + return timestamp; +} + +/* waits specified delay value and resets timestamp */ +void udelay_masked (unsigned long usec) +{ + __udelay(usec); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM 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 ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/at91/Makefile b/arch/arm/cpu/arm926ejs/at91/Makefile new file mode 100644 index 0000000..c4408f6 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/Makefile @@ -0,0 +1,66 @@ +# +# (C) Copyright 2000-2008 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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$(SOC).o + +COBJS-$(CONFIG_AT91CAP9) += at91cap9_devices.o +COBJS-$(CONFIG_AT91SAM9260) += at91sam9260_devices.o +COBJS-$(CONFIG_AT91SAM9G20) += at91sam9260_devices.o +COBJS-$(CONFIG_AT91SAM9XE) += at91sam9260_devices.o +COBJS-$(CONFIG_AT91SAM9261) += at91sam9261_devices.o +COBJS-$(CONFIG_AT91SAM9G10) += at91sam9261_devices.o +COBJS-$(CONFIG_AT91SAM9263) += at91sam9263_devices.o +COBJS-$(CONFIG_AT91SAM9RL) += at91sam9rl_devices.o +COBJS-$(CONFIG_AT91SAM9M10G45) += at91sam9m10g45_devices.o +COBJS-$(CONFIG_AT91SAM9G45) += at91sam9m10g45_devices.o +COBJS-$(CONFIG_AT91SAM9N12) += at91sam9n12_devices.o +COBJS-$(CONFIG_AT91SAM9X5) += at91sam9x5_devices.o +COBJS-$(CONFIG_AT91_EFLASH) += eflash.o +COBJS-$(CONFIG_AT91_LED) += led.o +COBJS-y += clock.o +COBJS-y += cpu.o +COBJS-y += reset.o +COBJS-y += timer.o + +ifndef CONFIG_SKIP_LOWLEVEL_INIT +SOBJS-y := lowlevel_init.o +endif + +SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/at91/at91cap9_devices.c b/arch/arm/cpu/arm926ejs/at91/at91cap9_devices.c new file mode 100644 index 0000000..db2ecb8 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/at91cap9_devices.c @@ -0,0 +1,205 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * (C) Copyright 2009 + * Daniel Gorsulowski <daniel.gorsulowski@esd.eu> + * esd electronic system design gmbh <www.esd.eu> + * + * 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 <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> +#include <asm/arch/io.h> + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTA, 22, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTA, 23, 0); /* RXD0 */ + writel(1 << AT91CAP9_ID_US0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTD, 0, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTD, 1, 0); /* RXD1 */ + writel(1 << AT91CAP9_ID_US1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTD, 2, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTD, 3, 0); /* RXD2 */ + writel(1 << AT91CAP9_ID_US2, &pmc->pcer); +} + +void at91_serial3_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTC, 30, 0); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTC, 31, 1); /* DTXD */ + writel(1 << AT91_ID_SYS, &pmc->pcer); +} + +void at91_serial_hw_init(void) +{ +#ifdef CONFIG_USART0 + at91_serial0_hw_init(); +#endif + +#ifdef CONFIG_USART1 + at91_serial1_hw_init(); +#endif + +#ifdef CONFIG_USART2 + at91_serial2_hw_init(); +#endif + +#ifdef CONFIG_USART3 /* DBGU */ + at91_serial3_hw_init(); +#endif +} + +#ifdef CONFIG_HAS_DATAFLASH +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_b_periph(AT91_PIO_PORTA, 0, 0); /* SPI0_MISO */ + at91_set_b_periph(AT91_PIO_PORTA, 1, 0); /* SPI0_MOSI */ + at91_set_b_periph(AT91_PIO_PORTA, 2, 0); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << AT91CAP9_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_b_periph(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTD, 0, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTD, 1, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTD, 0, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTD, 1, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTB, 12, 0); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 13, 0); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 14, 0); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << AT91CAP9_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 15, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_a_periph(AT91_PIO_PORTB, 16, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTB, 18, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 15, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTB, 16, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTB, 18, 1); + } + +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + at91_set_a_periph(AT91_PIO_PORTB, 21, 0); /* ETXCK_EREFCK */ + at91_set_a_periph(AT91_PIO_PORTB, 22, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTB, 25, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTB, 26, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTB, 27, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTB, 28, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTB, 23, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTB, 24, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTB, 30, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTB, 29, 0); /* EMDC */ + +#ifndef CONFIG_RMII + at91_set_b_periph(AT91_PIO_PORTC, 25, 0); /* ECRS */ + at91_set_b_periph(AT91_PIO_PORTC, 26, 0); /* ECOL */ + at91_set_b_periph(AT91_PIO_PORTC, 22, 0); /* ERX2 */ + at91_set_b_periph(AT91_PIO_PORTC, 23, 0); /* ERX3 */ + at91_set_b_periph(AT91_PIO_PORTC, 27, 0); /* ERXCK */ + at91_set_b_periph(AT91_PIO_PORTC, 20, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTC, 21, 0); /* ETX3 */ + at91_set_b_periph(AT91_PIO_PORTC, 24, 0); /* ETXER */ +#endif +} +#endif + +#ifdef CONFIG_AT91_CAN +void at91_can_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) AT91_PMC_BASE; + + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* CAN_TX */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 1); /* CAN_RX */ + + /* Enable clock */ + writel(1 << AT91CAP9_ID_CAN, &pmc->pcer); +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c new file mode 100644 index 0000000..5e995e1 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/at91sam9260_devices.c @@ -0,0 +1,225 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * 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 <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 4, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTB, 5, PUP); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 6, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTB, 7, PUP); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 8, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTB, 9, PUP); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 14, PUP); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTB, 15, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 0, PUP); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 1, PUP); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 2, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTC, 11, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTC, 16, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTC, 17, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTC, 11, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTC, 16, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTC, 17, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 0, PUP); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 1, PUP); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 2, PUP); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 3, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTC, 5, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTC, 4, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTC, 3, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 3, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTC, 5, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTC, 4, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTC, 3, 1); + } +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + /* Enable EMAC clock */ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + writel(1 << ATMEL_ID_EMAC0, &pmc->pcer); + + at91_set_a_periph(AT91_PIO_PORTA, 19, 0); /* ETXCK_EREFCK */ + at91_set_a_periph(AT91_PIO_PORTA, 17, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTA, 14, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTA, 15, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTA, 18, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTA, 16, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTA, 21, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTA, 20, 0); /* EMDC */ + +#ifndef CONFIG_RMII + at91_set_b_periph(AT91_PIO_PORTA, 28, 0); /* ECRS */ + at91_set_b_periph(AT91_PIO_PORTA, 29, 0); /* ECOL */ + at91_set_b_periph(AT91_PIO_PORTA, 25, 0); /* ERX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 26, 0); /* ERX3 */ + at91_set_b_periph(AT91_PIO_PORTA, 27, 0); /* ERXCK */ +#if defined(CONFIG_AT91SAM9260EK) || defined(CONFIG_AFEB9260) + /* + * use PA10, PA11 for ETX2, ETX3. + * PA23 and PA24 are for TWI EEPROM + */ + at91_set_b_periph(AT91_PIO_PORTA, 10, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 11, 0); /* ETX3 */ +#else + at91_set_b_periph(AT91_PIO_PORTA, 23, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 24, 0); /* ETX3 */ +#if defined(CONFIG_AT91SAM9G20) + /* 9G20 BOOT ROM initializes those pins to multi-drive, undo that */ + at91_set_pio_multi_drive(AT91_PIO_PORTA, 23, 0); + at91_set_pio_multi_drive(AT91_PIO_PORTA, 24, 0); +#endif +#endif + at91_set_b_periph(AT91_PIO_PORTA, 22, 0); /* ETXER */ +#endif +} +#endif + +#if defined(CONFIG_GENERIC_ATMEL_MCI) +void at91_mci_hw_init(void) +{ + /* Enable mci clock */ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + writel(1 << ATMEL_ID_MCI, &pmc->pcer); + + at91_set_a_periph(AT91_PIO_PORTA, 8, 1); /* MCCK */ +#if defined(CONFIG_ATMEL_MCI_PORTB) + at91_set_b_periph(AT91_PIO_PORTA, 1, 1); /* MCCDB */ + at91_set_b_periph(AT91_PIO_PORTA, 0, 1); /* MCDB0 */ + at91_set_b_periph(AT91_PIO_PORTA, 5, 1); /* MCDB1 */ + at91_set_b_periph(AT91_PIO_PORTA, 4, 1); /* MCDB2 */ + at91_set_b_periph(AT91_PIO_PORTA, 3, 1); /* MCDB3 */ +#else + at91_set_a_periph(AT91_PIO_PORTA, 7, 1); /* MCCDA */ + at91_set_a_periph(AT91_PIO_PORTA, 6, 1); /* MCDA0 */ + at91_set_a_periph(AT91_PIO_PORTA, 9, 1); /* MCDA1 */ + at91_set_a_periph(AT91_PIO_PORTA, 10, 1); /* MCDA2 */ + at91_set_a_periph(AT91_PIO_PORTA, 11, 1); /* MCDA3 */ +#endif +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9261_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9261_devices.c new file mode 100644 index 0000000..ae8cd56 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/at91sam9261_devices.c @@ -0,0 +1,156 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * 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 <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 8, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTC, 9, 0); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 12, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTC, 13, 0); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 14, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTC, 15, 0); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 9, 0); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTA, 10, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 0, PUP); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 1, PUP); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 2, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_a_periph(AT91_PIO_PORTA, 4, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTA, 6, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTA, 4, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTA, 6, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 30, PUP); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 31, PUP); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 29, PUP); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 28, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTA, 24, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTA, 25, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTA, 26, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 28, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTA, 24, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTA, 25, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTA, 26, 1); + } +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9263_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9263_devices.c new file mode 100644 index 0000000..7191db2 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/at91sam9263_devices.c @@ -0,0 +1,209 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * (C) Copyright 2009-2011 + * Daniel Gorsulowski <daniel.gorsulowski@esd.eu> + * esd electronic system design gmbh <www.esd.eu> + * + * 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 <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 26, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTA, 27, PUP); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTD, 0, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTD, 1, PUP); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTD, 2, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTD, 3, PUP); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 30, PUP); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTC, 31, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_b_periph(AT91_PIO_PORTA, 0, PUP); /* SPI0_MISO */ + at91_set_b_periph(AT91_PIO_PORTA, 1, PUP); /* SPI0_MOSI */ + at91_set_b_periph(AT91_PIO_PORTA, 2, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_b_periph(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTA, 4, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTB, 11, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 5, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTA, 3, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTA, 4, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTB, 11, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 12, PUP); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 13, PUP); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 14, PUP); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 15, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_a_periph(AT91_PIO_PORTB, 16, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTB, 18, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 15, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTB, 16, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTB, 18, 1); + } +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + at91_set_a_periph(AT91_PIO_PORTE, 21, 0); /* ETXCK_EREFCK */ + at91_set_b_periph(AT91_PIO_PORTC, 25, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTE, 25, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTE, 26, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTE, 27, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTE, 28, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTE, 23, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTE, 24, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTE, 30, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTE, 29, 0); /* EMDC */ + +#ifndef CONFIG_RMII + at91_set_a_periph(AT91_PIO_PORTE, 22, 0); /* ECRS */ + at91_set_b_periph(AT91_PIO_PORTC, 26, 0); /* ECOL */ + at91_set_b_periph(AT91_PIO_PORTC, 22, 0); /* ERX2 */ + at91_set_b_periph(AT91_PIO_PORTC, 23, 0); /* ERX3 */ + at91_set_b_periph(AT91_PIO_PORTC, 27, 0); /* ERXCK */ + at91_set_b_periph(AT91_PIO_PORTC, 20, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTC, 21, 0); /* ETX3 */ + at91_set_b_periph(AT91_PIO_PORTC, 24, 0); /* ETXER */ +#endif +} +#endif + +#ifdef CONFIG_USB_OHCI_NEW +void at91_uhp_hw_init(void) +{ + /* Enable VBus on UHP ports */ + at91_set_pio_output(AT91_PIO_PORTA, 21, 0); + at91_set_pio_output(AT91_PIO_PORTA, 24, 0); +} +#endif + +#ifdef CONFIG_AT91_CAN +void at91_can_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* CAN_TX */ + at91_set_a_periph(AT91_PIO_PORTA, 14, 1); /* CAN_RX */ + + /* Enable clock */ + writel(1 << ATMEL_ID_CAN, &pmc->pcer); +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c new file mode 100644 index 0000000..f31c364 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/at91sam9m10g45_devices.c @@ -0,0 +1,183 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * 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 <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> +#include <asm/io.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 19, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTB, 18, PUP); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 4, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTB, 5, PUP); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTD, 6, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTD, 7, PUP); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 12, 0); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTB, 13, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 0, PUP); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 1, PUP); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 2, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 3, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTB, 18, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_b_periph(AT91_PIO_PORTB, 19, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTD, 27, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 3, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTB, 18, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTB, 19, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTD, 27, 1); + } +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTB, 14, PUP); /* SPI1_MISO */ + at91_set_a_periph(AT91_PIO_PORTB, 15, PUP); /* SPI1_MOSI */ + at91_set_a_periph(AT91_PIO_PORTB, 16, PUP); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTD, 28, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTD, 18, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_a_periph(AT91_PIO_PORTD, 19, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTB, 17, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTD, 28, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTD, 18, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTD, 19, 1); + } + +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + at91_set_a_periph(AT91_PIO_PORTA, 17, 0); /* ETXCK_EREFCK */ + at91_set_a_periph(AT91_PIO_PORTA, 15, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTA, 16, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTA, 14, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTA, 10, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTA, 11, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTA, 19, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTA, 18, 0); /* EMDC */ +#ifndef CONFIG_RMII + at91_set_b_periph(AT91_PIO_PORTA, 29, 0); /* ECRS */ + at91_set_b_periph(AT91_PIO_PORTA, 30, 0); /* ECOL */ + at91_set_b_periph(AT91_PIO_PORTA, 8, 0); /* ERX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 9, 0); /* ERX3 */ + at91_set_b_periph(AT91_PIO_PORTA, 28, 0); /* ERXCK */ + at91_set_b_periph(AT91_PIO_PORTA, 6, 0); /* ETX2 */ + at91_set_b_periph(AT91_PIO_PORTA, 7, 0); /* ETX3 */ + at91_set_b_periph(AT91_PIO_PORTA, 27, 0); /* ETXER */ +#endif +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9n12_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9n12_devices.c new file mode 100644 index 0000000..6eaeac0 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/at91sam9n12_devices.c @@ -0,0 +1,177 @@ +/* + * (C) Copyright 2013 Atmel Corporation + * Josh Wu <josh.wu@atmel.com> + * + * 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 <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/at91_pio.h> + +unsigned int has_lcdc() +{ + return 1; +} + +void at91_serial0_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 0, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTA, 1, 0); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 5, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTA, 6, 0); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 7, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTA, 8, 0); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_serial3_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_b_periph(AT91_PIO_PORTC, 22, 1); /* TXD3 */ + at91_set_b_periph(AT91_PIO_PORTC, 23, 0); /* RXD3 */ + writel(1 << ATMEL_ID_USART3, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 10, 1); /* DTXD */ + at91_set_a_periph(AT91_PIO_PORTA, 9, 0); /* DRXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#ifdef CONFIG_ATMEL_SPI +void at91_spi0_hw_init(unsigned long cs_mask) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 11, 0); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) + at91_set_pio_output(AT91_PIO_PORTA, 14, 1); + if (cs_mask & (1 << 1)) + at91_set_pio_output(AT91_PIO_PORTA, 7, 1); + if (cs_mask & (1 << 2)) + at91_set_pio_output(AT91_PIO_PORTA, 1, 1); + if (cs_mask & (1 << 3)) + at91_set_pio_output(AT91_PIO_PORTB, 3, 1); +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_b_periph(AT91_PIO_PORTA, 21, 0); /* SPI1_MISO */ + at91_set_b_periph(AT91_PIO_PORTA, 22, 0); /* SPI1_MOSI */ + at91_set_b_periph(AT91_PIO_PORTA, 23, 0); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) + at91_set_pio_output(AT91_PIO_PORTA, 8, 1); + if (cs_mask & (1 << 1)) + at91_set_pio_output(AT91_PIO_PORTA, 0, 1); + if (cs_mask & (1 << 2)) + at91_set_pio_output(AT91_PIO_PORTA, 31, 1); + if (cs_mask & (1 << 3)) + at91_set_pio_output(AT91_PIO_PORTA, 30, 1); +} +#endif + +void at91_mci_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 17, 0); /* MCCK */ + at91_set_a_periph(AT91_PIO_PORTA, 16, 0); /* MCCDA */ + at91_set_a_periph(AT91_PIO_PORTA, 15, 0); /* MCDA0 */ + at91_set_a_periph(AT91_PIO_PORTA, 18, 0); /* MCDA1 */ + at91_set_a_periph(AT91_PIO_PORTA, 19, 0); /* MCDA2 */ + at91_set_a_periph(AT91_PIO_PORTA, 20, 0); /* MCDA3 */ + + writel(1 << ATMEL_ID_HSMCI0, &pmc->pcer); +} + +#ifdef CONFIG_LCD +void at91_lcd_hw_init(void) +{ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTC, 24, 0); /* LCDDPWR */ + at91_set_a_periph(AT91_PIO_PORTC, 26, 0); /* LCDVSYNC */ + at91_set_a_periph(AT91_PIO_PORTC, 27, 0); /* LCDHSYNC */ + at91_set_a_periph(AT91_PIO_PORTC, 28, 0); /* LCDDOTCK */ + at91_set_a_periph(AT91_PIO_PORTC, 29, 0); /* LCDDEN */ + at91_set_a_periph(AT91_PIO_PORTC, 30, 0); /* LCDDOTCK */ + + at91_set_a_periph(AT91_PIO_PORTC, 0, 0); /* LCDD0 */ + at91_set_a_periph(AT91_PIO_PORTC, 1, 0); /* LCDD1 */ + at91_set_a_periph(AT91_PIO_PORTC, 2, 0); /* LCDD2 */ + at91_set_a_periph(AT91_PIO_PORTC, 3, 0); /* LCDD3 */ + at91_set_a_periph(AT91_PIO_PORTC, 4, 0); /* LCDD4 */ + at91_set_a_periph(AT91_PIO_PORTC, 5, 0); /* LCDD5 */ + at91_set_a_periph(AT91_PIO_PORTC, 6, 0); /* LCDD6 */ + at91_set_a_periph(AT91_PIO_PORTC, 7, 0); /* LCDD7 */ + at91_set_a_periph(AT91_PIO_PORTC, 8, 0); /* LCDD8 */ + at91_set_a_periph(AT91_PIO_PORTC, 9, 0); /* LCDD9 */ + at91_set_a_periph(AT91_PIO_PORTC, 10, 0); /* LCDD10 */ + at91_set_a_periph(AT91_PIO_PORTC, 11, 0); /* LCDD11 */ + at91_set_a_periph(AT91_PIO_PORTC, 12, 0); /* LCDD12 */ + at91_set_a_periph(AT91_PIO_PORTC, 13, 0); /* LCDD13 */ + at91_set_a_periph(AT91_PIO_PORTC, 14, 0); /* LCDD14 */ + at91_set_a_periph(AT91_PIO_PORTC, 15, 0); /* LCDD15 */ + at91_set_a_periph(AT91_PIO_PORTC, 16, 0); /* LCDD16 */ + at91_set_a_periph(AT91_PIO_PORTC, 17, 0); /* LCDD17 */ + at91_set_a_periph(AT91_PIO_PORTC, 18, 0); /* LCDD18 */ + at91_set_a_periph(AT91_PIO_PORTC, 19, 0); /* LCDD19 */ + at91_set_a_periph(AT91_PIO_PORTC, 20, 0); /* LCDD20 */ + at91_set_a_periph(AT91_PIO_PORTC, 21, 0); /* LCDD21 */ + at91_set_a_periph(AT91_PIO_PORTC, 22, 0); /* LCDD22 */ + at91_set_a_periph(AT91_PIO_PORTC, 23, 0); /* LCDD23 */ + + writel(1 << ATMEL_ID_LCDC, &pmc->pcer); +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9rl_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9rl_devices.c new file mode 100644 index 0000000..ca44cf5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/at91sam9rl_devices.c @@ -0,0 +1,119 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * 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 <asm/io.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> + +/* + * if CONFIG_AT91_GPIO_PULLUP ist set, keep pullups on on all + * peripheral pins. Good to have if hardware is soldered optionally + * or in case of SPI no slave is selected. Avoid lines to float + * needlessly. Use a short local PUP define. + * + * Due to errata "TXD floats when CTS is inactive" pullups are always + * on for TXD pins. + */ +#ifdef CONFIG_AT91_GPIO_PULLUP +# define PUP CONFIG_AT91_GPIO_PULLUP +#else +# define PUP 0 +#endif + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 6, 1); /* TXD0 */ + at91_set_a_periph(AT91_PIO_PORTA, 7, PUP); /* RXD0 */ + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 11, 1); /* TXD1 */ + at91_set_a_periph(AT91_PIO_PORTA, 12, PUP); /* RXD1 */ + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 13, 1); /* TXD2 */ + at91_set_a_periph(AT91_PIO_PORTA, 14, PUP); /* RXD2 */ + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 21, PUP); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTA, 22, 1); /* DTXD */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +#if defined(CONFIG_HAS_DATAFLASH) || defined(CONFIG_ATMEL_SPI) +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 25, PUP); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 26, PUP); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 27, PUP); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI, &pmc->pcer); + + if (cs_mask & (1 << 0)) { + at91_set_a_periph(AT91_PIO_PORTA, 28, 1); + } + if (cs_mask & (1 << 1)) { + at91_set_b_periph(AT91_PIO_PORTB, 7, 1); + } + if (cs_mask & (1 << 2)) { + at91_set_a_periph(AT91_PIO_PORTD, 8, 1); + } + if (cs_mask & (1 << 3)) { + at91_set_b_periph(AT91_PIO_PORTD, 9, 1); + } + if (cs_mask & (1 << 4)) { + at91_set_pio_output(AT91_PIO_PORTA, 28, 1); + } + if (cs_mask & (1 << 5)) { + at91_set_pio_output(AT91_PIO_PORTB, 7, 1); + } + if (cs_mask & (1 << 6)) { + at91_set_pio_output(AT91_PIO_PORTD, 8, 1); + } + if (cs_mask & (1 << 7)) { + at91_set_pio_output(AT91_PIO_PORTD, 9, 1); + } +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/at91sam9x5_devices.c b/arch/arm/cpu/arm926ejs/at91/at91sam9x5_devices.c new file mode 100644 index 0000000..9218546 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/at91sam9x5_devices.c @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2012 Atmel Corporation + * + * 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 <asm/arch/at91_common.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/gpio.h> +#include <asm/io.h> + +unsigned int get_chip_id(void) +{ + /* The 0x40 is the offset of cidr in DBGU */ + return readl(ATMEL_BASE_DBGU + 0x40) & ~ARCH_ID_VERSION_MASK; +} + +unsigned int get_extension_chip_id(void) +{ + /* The 0x44 is the offset of exid in DBGU */ + return readl(ATMEL_BASE_DBGU + 0x44); +} + +unsigned int has_emac1() +{ + return cpu_is_at91sam9x25(); +} + +unsigned int has_emac0() +{ + return !(cpu_is_at91sam9g15()); +} + +unsigned int has_lcdc() +{ + return cpu_is_at91sam9g15() || cpu_is_at91sam9g35() + || cpu_is_at91sam9x35(); +} + +char *get_cpu_name() +{ + unsigned int extension_id = get_extension_chip_id(); + + if (cpu_is_at91sam9x5()) { + switch (extension_id) { + case ARCH_EXID_AT91SAM9G15: + return "AT91SAM9G15"; + case ARCH_EXID_AT91SAM9G25: + return "AT91SAM9G25"; + case ARCH_EXID_AT91SAM9G35: + return "AT91SAM9G35"; + case ARCH_EXID_AT91SAM9X25: + return "AT91SAM9X25"; + case ARCH_EXID_AT91SAM9X35: + return "AT91SAM9X35"; + default: + return "Unknown CPU type"; + } + } else { + return "Unknown CPU type"; + } +} + +void at91_seriald_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 9, 0); /* DRXD */ + at91_set_a_periph(AT91_PIO_PORTA, 10, 1); /* DTXD */ + + writel(1 << ATMEL_ID_SYS, &pmc->pcer); +} + +void at91_serial0_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 0, 1); /* TXD */ + at91_set_a_periph(AT91_PIO_PORTA, 1, 0); /* RXD */ + + writel(1 << ATMEL_ID_USART0, &pmc->pcer); +} + +void at91_serial1_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 5, 1); /* TXD */ + at91_set_a_periph(AT91_PIO_PORTA, 6, 0); /* RXD */ + + writel(1 << ATMEL_ID_USART1, &pmc->pcer); +} + +void at91_serial2_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 7, 1); /* TXD */ + at91_set_a_periph(AT91_PIO_PORTA, 8, 0); /* RXD */ + + writel(1 << ATMEL_ID_USART2, &pmc->pcer); +} + +void at91_mci_hw_init(void) +{ + /* Initialize the MCI0 */ + at91_set_a_periph(AT91_PIO_PORTA, 17, 1); /* MCCK */ + at91_set_a_periph(AT91_PIO_PORTA, 16, 1); /* MCCDA */ + at91_set_a_periph(AT91_PIO_PORTA, 15, 1); /* MCDA0 */ + at91_set_a_periph(AT91_PIO_PORTA, 18, 1); /* MCDA1 */ + at91_set_a_periph(AT91_PIO_PORTA, 19, 1); /* MCDA2 */ + at91_set_a_periph(AT91_PIO_PORTA, 20, 1); /* MCDA3 */ + + /* Enable clock for MCI0 */ + struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC; + writel(1 << ATMEL_ID_HSMCI0, &pmc->pcer); +} + +#ifdef CONFIG_ATMEL_SPI +void at91_spi0_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_a_periph(AT91_PIO_PORTA, 11, 0); /* SPI0_MISO */ + at91_set_a_periph(AT91_PIO_PORTA, 12, 0); /* SPI0_MOSI */ + at91_set_a_periph(AT91_PIO_PORTA, 13, 0); /* SPI0_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI0, &pmc->pcer); + + if (cs_mask & (1 << 0)) + at91_set_a_periph(AT91_PIO_PORTA, 14, 0); + if (cs_mask & (1 << 1)) + at91_set_b_periph(AT91_PIO_PORTA, 7, 0); + if (cs_mask & (1 << 2)) + at91_set_b_periph(AT91_PIO_PORTA, 1, 0); + if (cs_mask & (1 << 3)) + at91_set_b_periph(AT91_PIO_PORTB, 3, 0); + if (cs_mask & (1 << 4)) + at91_set_pio_output(AT91_PIO_PORTA, 14, 0); + if (cs_mask & (1 << 5)) + at91_set_pio_output(AT91_PIO_PORTA, 7, 0); + if (cs_mask & (1 << 6)) + at91_set_pio_output(AT91_PIO_PORTA, 1, 0); + if (cs_mask & (1 << 7)) + at91_set_pio_output(AT91_PIO_PORTB, 3, 0); +} + +void at91_spi1_hw_init(unsigned long cs_mask) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + at91_set_b_periph(AT91_PIO_PORTA, 21, 0); /* SPI1_MISO */ + at91_set_b_periph(AT91_PIO_PORTA, 22, 0); /* SPI1_MOSI */ + at91_set_b_periph(AT91_PIO_PORTA, 23, 0); /* SPI1_SPCK */ + + /* Enable clock */ + writel(1 << ATMEL_ID_SPI1, &pmc->pcer); + + if (cs_mask & (1 << 0)) + at91_set_b_periph(AT91_PIO_PORTA, 8, 0); + if (cs_mask & (1 << 1)) + at91_set_b_periph(AT91_PIO_PORTA, 0, 0); + if (cs_mask & (1 << 2)) + at91_set_b_periph(AT91_PIO_PORTA, 31, 0); + if (cs_mask & (1 << 3)) + at91_set_b_periph(AT91_PIO_PORTA, 30, 0); + if (cs_mask & (1 << 4)) + at91_set_pio_output(AT91_PIO_PORTA, 8, 0); + if (cs_mask & (1 << 5)) + at91_set_pio_output(AT91_PIO_PORTA, 0, 0); + if (cs_mask & (1 << 6)) + at91_set_pio_output(AT91_PIO_PORTA, 31, 0); + if (cs_mask & (1 << 7)) + at91_set_pio_output(AT91_PIO_PORTA, 30, 0); +} +#endif + +#if defined(CONFIG_USB_OHCI_NEW) || defined(CONFIG_USB_EHCI) +void at91_uhp_hw_init(void) +{ + /* Enable VBus on UHP ports */ + at91_set_pio_output(AT91_PIO_PORTD, 18, 0); /* port A */ + at91_set_pio_output(AT91_PIO_PORTD, 19, 0); /* port B */ +#if defined(CONFIG_USB_OHCI_NEW) + /* port C is OHCI only */ + at91_set_pio_output(AT91_PIO_PORTD, 20, 0); /* port C */ +#endif +} +#endif + +#ifdef CONFIG_MACB +void at91_macb_hw_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + + if (has_emac0()) { + /* Enable EMAC0 clock */ + writel(1 << ATMEL_ID_EMAC0, &pmc->pcer); + /* EMAC0 pins setup */ + at91_set_a_periph(AT91_PIO_PORTB, 4, 0); /* ETXCK */ + at91_set_a_periph(AT91_PIO_PORTB, 3, 0); /* ERXDV */ + at91_set_a_periph(AT91_PIO_PORTB, 0, 0); /* ERX0 */ + at91_set_a_periph(AT91_PIO_PORTB, 1, 0); /* ERX1 */ + at91_set_a_periph(AT91_PIO_PORTB, 2, 0); /* ERXER */ + at91_set_a_periph(AT91_PIO_PORTB, 7, 0); /* ETXEN */ + at91_set_a_periph(AT91_PIO_PORTB, 9, 0); /* ETX0 */ + at91_set_a_periph(AT91_PIO_PORTB, 10, 0); /* ETX1 */ + at91_set_a_periph(AT91_PIO_PORTB, 5, 0); /* EMDIO */ + at91_set_a_periph(AT91_PIO_PORTB, 6, 0); /* EMDC */ + } + + if (has_emac1()) { + /* Enable EMAC1 clock */ + writel(1 << ATMEL_ID_EMAC1, &pmc->pcer); + /* EMAC1 pins setup */ + at91_set_b_periph(AT91_PIO_PORTC, 29, 0); /* ETXCK */ + at91_set_b_periph(AT91_PIO_PORTC, 28, 0); /* ECRSDV */ + at91_set_b_periph(AT91_PIO_PORTC, 20, 0); /* ERXO */ + at91_set_b_periph(AT91_PIO_PORTC, 21, 0); /* ERX1 */ + at91_set_b_periph(AT91_PIO_PORTC, 16, 0); /* ERXER */ + at91_set_b_periph(AT91_PIO_PORTC, 27, 0); /* ETXEN */ + at91_set_b_periph(AT91_PIO_PORTC, 18, 0); /* ETX0 */ + at91_set_b_periph(AT91_PIO_PORTC, 19, 0); /* ETX1 */ + at91_set_b_periph(AT91_PIO_PORTC, 31, 0); /* EMDIO */ + at91_set_b_periph(AT91_PIO_PORTC, 30, 0); /* EMDC */ + } + +#ifndef CONFIG_RMII + /* Only emac0 support MII */ + if (has_emac0()) { + at91_set_a_periph(AT91_PIO_PORTB, 16, 0); /* ECRS */ + at91_set_a_periph(AT91_PIO_PORTB, 17, 0); /* ECOL */ + at91_set_a_periph(AT91_PIO_PORTB, 13, 0); /* ERX2 */ + at91_set_a_periph(AT91_PIO_PORTB, 14, 0); /* ERX3 */ + at91_set_a_periph(AT91_PIO_PORTB, 15, 0); /* ERXCK */ + at91_set_a_periph(AT91_PIO_PORTB, 11, 0); /* ETX2 */ + at91_set_a_periph(AT91_PIO_PORTB, 12, 0); /* ETX3 */ + at91_set_a_periph(AT91_PIO_PORTB, 8, 0); /* ETXER */ + } +#endif +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/clock.c b/arch/arm/cpu/arm926ejs/at91/clock.c new file mode 100644 index 0000000..5b4923f --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/clock.c @@ -0,0 +1,192 @@ +/* + * [origin: Linux kernel linux/arch/arm/mach-at91/clock.c] + * + * Copyright (C) 2005 David Brownell + * Copyright (C) 2005 Ivan Kokshaysky + * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * + * 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. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/clk.h> + +#if !defined(CONFIG_AT91FAMILY) +# error You need to define CONFIG_AT91FAMILY in your board config! +#endif + +DECLARE_GLOBAL_DATA_PTR; + +static unsigned long at91_css_to_rate(unsigned long css) +{ + switch (css) { + case AT91_PMC_MCKR_CSS_SLOW: + return CONFIG_SYS_AT91_SLOW_CLOCK; + case AT91_PMC_MCKR_CSS_MAIN: + return gd->arch.main_clk_rate_hz; + case AT91_PMC_MCKR_CSS_PLLA: + return gd->arch.plla_rate_hz; + case AT91_PMC_MCKR_CSS_PLLB: + return gd->arch.pllb_rate_hz; + } + + return 0; +} + +#ifdef CONFIG_USB_ATMEL +static unsigned at91_pll_calc(unsigned main_freq, unsigned out_freq) +{ + unsigned i, div = 0, mul = 0, diff = 1 << 30; + unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00; + + /* PLL output max 240 MHz (or 180 MHz per errata) */ + if (out_freq > 240000000) + goto fail; + + for (i = 1; i < 256; i++) { + int diff1; + unsigned input, mul1; + + /* + * PLL input between 1MHz and 32MHz per spec, but lower + * frequences seem necessary in some cases so allow 100K. + * Warning: some newer products need 2MHz min. + */ + input = main_freq / i; +#if defined(CONFIG_AT91SAM9G20) + if (input < 2000000) + continue; +#endif + if (input < 100000) + continue; + if (input > 32000000) + continue; + + mul1 = out_freq / input; +#if defined(CONFIG_AT91SAM9G20) + if (mul > 63) + continue; +#endif + if (mul1 > 2048) + continue; + if (mul1 < 2) + goto fail; + + diff1 = out_freq - input * mul1; + if (diff1 < 0) + diff1 = -diff1; + if (diff > diff1) { + diff = diff1; + div = i; + mul = mul1; + if (diff == 0) + break; + } + } + if (i == 256 && diff > (out_freq >> 5)) + goto fail; + return ret | ((mul - 1) << 16) | div; +fail: + return 0; +} +#endif + +static u32 at91_pll_rate(u32 freq, u32 reg) +{ + unsigned mul, div; + + div = reg & 0xff; + mul = (reg >> 16) & 0x7ff; + if (div && mul) { + freq /= div; + freq *= mul + 1; + } else + freq = 0; + + return freq; +} + +int at91_clock_init(unsigned long main_clock) +{ + unsigned freq, mckr; + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; +#ifndef CONFIG_SYS_AT91_MAIN_CLOCK + unsigned tmp; + /* + * When the bootloader initialized the main oscillator correctly, + * there's no problem using the cycle counter. But if it didn't, + * or when using oscillator bypass mode, we must be told the speed + * of the main clock. + */ + if (!main_clock) { + do { + tmp = readl(&pmc->mcfr); + } while (!(tmp & AT91_PMC_MCFR_MAINRDY)); + tmp &= AT91_PMC_MCFR_MAINF_MASK; + main_clock = tmp * (CONFIG_SYS_AT91_SLOW_CLOCK / 16); + } +#endif + gd->arch.main_clk_rate_hz = main_clock; + + /* report if PLLA is more than mildly overclocked */ + gd->arch.plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar)); + +#ifdef CONFIG_USB_ATMEL + /* + * USB clock init: choose 48 MHz PLLB value, + * disable 48MHz clock during usb peripheral suspend. + * + * REVISIT: assumes MCK doesn't derive from PLLB! + */ + gd->arch.at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | + AT91_PMC_PLLBR_USBDIV_2; + gd->arch.pllb_rate_hz = at91_pll_rate(main_clock, + gd->arch.at91_pllb_usb_init); +#endif + + /* + * MCK and CPU derive from one of those primary clocks. + * For now, assume this parentage won't change. + */ + mckr = readl(&pmc->mckr); +#if defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) \ + || defined(CONFIG_AT91SAM9N12) || defined(CONFIG_AT91SAM9X5) + /* plla divisor by 2 */ + gd->arch.plla_rate_hz /= (1 << ((mckr & 1 << 12) >> 12)); +#endif + gd->arch.mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK); + freq = gd->arch.mck_rate_hz; + + freq /= (1 << ((mckr & AT91_PMC_MCKR_PRES_MASK) >> 2)); /* prescale */ +#if defined(CONFIG_AT91SAM9G20) + /* mdiv ; (x >> 7) = ((x >> 8) * 2) */ + gd->arch.mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) ? + freq / ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 7) : freq; + if (mckr & AT91_PMC_MCKR_MDIV_MASK) + freq /= 2; /* processor clock division */ +#elif defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) \ + || defined(CONFIG_AT91SAM9N12) || defined(CONFIG_AT91SAM9X5) + /* mdiv <==> divisor + * 0 <==> 1 + * 1 <==> 2 + * 2 <==> 4 + * 3 <==> 3 + */ + gd->arch.mck_rate_hz = (mckr & AT91_PMC_MCKR_MDIV_MASK) == + (AT91_PMC_MCKR_MDIV_2 | AT91_PMC_MCKR_MDIV_4) + ? freq / 3 + : freq / (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8)); +#else + gd->arch.mck_rate_hz = freq / + (1 << ((mckr & AT91_PMC_MCKR_MDIV_MASK) >> 8)); +#endif + gd->arch.cpu_clk_rate_hz = freq; + + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/at91/config.mk b/arch/arm/cpu/arm926ejs/at91/config.mk new file mode 100644 index 0000000..370630d --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/config.mk @@ -0,0 +1,2 @@ +PF_CPPFLAGS_TUNE := $(call cc-option,-mtune=arm926ejs,) +PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_TUNE) diff --git a/arch/arm/cpu/arm926ejs/at91/cpu.c b/arch/arm/cpu/arm926ejs/at91/cpu.c new file mode 100644 index 0000000..5cf4fad --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/cpu.c @@ -0,0 +1,73 @@ +/* + * (C) Copyright 2010 + * Reinhard Meyer, reinhard.meyer@emk-elektronik.de + * (C) Copyright 2009 + * Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * + * 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 <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/at91_pit.h> +#include <asm/arch/at91_gpbr.h> +#include <asm/arch/clk.h> + +#ifndef CONFIG_SYS_AT91_MAIN_CLOCK +#define CONFIG_SYS_AT91_MAIN_CLOCK 0 +#endif + +int arch_cpu_init(void) +{ + return at91_clock_init(CONFIG_SYS_AT91_MAIN_CLOCK); +} + +void arch_preboot_os(void) +{ + ulong cpiv; + at91_pit_t *pit = (at91_pit_t *) ATMEL_BASE_PIT; + + cpiv = AT91_PIT_MR_PIV_MASK(readl(&pit->piir)); + + /* + * Disable PITC + * Add 0x1000 to current counter to stop it faster + * without waiting for wrapping back to 0 + */ + writel(cpiv + 0x1000, &pit->mr); +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + char buf[32]; + + printf("CPU: %s\n", ATMEL_CPU_NAME); + printf("Crystal frequency: %8s MHz\n", + strmhz(buf, get_main_clk_rate())); + printf("CPU clock : %8s MHz\n", + strmhz(buf, get_cpu_clk_rate())); + printf("Master clock : %8s MHz\n", + strmhz(buf, get_mck_clk_rate())); + + return 0; +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/eflash.c b/arch/arm/cpu/arm926ejs/at91/eflash.c new file mode 100644 index 0000000..b0c1e1e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/eflash.c @@ -0,0 +1,270 @@ +/* + * (C) Copyright 2010 + * Reinhard Meyer, EMK Elektronik, reinhard.meyer@emk-elektronik.de + * + * 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 + */ + +/* + * this driver supports the enhanced embedded flash in the Atmel + * AT91SAM9XE devices with the following geometry: + * + * AT91SAM9XE128: 1 plane of 8 regions of 32 pages (total 256 pages) + * AT91SAM9XE256: 1 plane of 16 regions of 32 pages (total 512 pages) + * AT91SAM9XE512: 1 plane of 32 regions of 32 pages (total 1024 pages) + * (the exact geometry is read from the flash at runtime, so any + * future devices should already be covered) + * + * Regions can be write/erase protected. + * Whole (!) pages can be individually written with erase on the fly. + * Writing partial pages will corrupt the rest of the page. + * + * The flash is presented to u-boot with each region being a sector, + * having the following effects: + * Each sector can be hardware protected (protect on/off). + * Each page in a sector can be rewritten anytime. + * Since pages are erased when written, the "erase" does nothing. + * The first "CONFIG_EFLASH_PROTSECTORS" cannot be unprotected + * by u-Boot commands. + * + * Note: Redundant environment will not work in this flash since + * it does use partial page writes. Make sure the environent spans + * whole pages! + */ + +/* + * optional TODOs (nice to have features): + * + * make the driver coexist with other NOR flash drivers + * (use an index into flash_info[], requires work + * in those other drivers, too) + * Make the erase command fill the sectors with 0xff + * (if the flashes grow larger in the future and + * someone puts a jffs2 into them) + * do a read-modify-write for partially programmed pages + */ +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_common.h> +#include <asm/arch/at91_eefc.h> +#include <asm/arch/at91_dbu.h> + +/* checks to detect configuration errors */ +#if CONFIG_SYS_MAX_FLASH_BANKS!=1 +#error eflash: this driver can only handle 1 bank +#endif + +/* global structure */ +flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS]; +static u32 pagesize; + +unsigned long flash_init (void) +{ + at91_eefc_t *eefc = (at91_eefc_t *) ATMEL_BASE_EEFC; + at91_dbu_t *dbu = (at91_dbu_t *) ATMEL_BASE_DBGU; + u32 id, size, nplanes, planesize, nlocks; + u32 addr, i, tmp=0; + + debug("eflash: init\n"); + + flash_info[0].flash_id = FLASH_UNKNOWN; + + /* check if its an AT91ARM9XE SoC */ + if ((readl(&dbu->cidr) & AT91_DBU_CID_ARCH_MASK) != AT91_DBU_CID_ARCH_9XExx) { + puts("eflash: not an AT91SAM9XE\n"); + return 0; + } + + /* now query the eflash for its structure */ + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GETD, &eefc->fcr); + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + id = readl(&eefc->frr); /* word 0 */ + size = readl(&eefc->frr); /* word 1 */ + pagesize = readl(&eefc->frr); /* word 2 */ + nplanes = readl(&eefc->frr); /* word 3 */ + planesize = readl(&eefc->frr); /* word 4 */ + debug("id=%08x size=%u pagesize=%u planes=%u planesize=%u\n", + id, size, pagesize, nplanes, planesize); + for (i=1; i<nplanes; i++) { + tmp = readl(&eefc->frr); /* words 5..4+nplanes-1 */ + }; + nlocks = readl(&eefc->frr); /* word 4+nplanes */ + debug("nlocks=%u\n", nlocks); + /* since we are going to use the lock regions as sectors, check count */ + if (nlocks > CONFIG_SYS_MAX_FLASH_SECT) { + printf("eflash: number of lock regions(%u) "\ + "> CONFIG_SYS_MAX_FLASH_SECT. reducing...\n", + nlocks); + nlocks = CONFIG_SYS_MAX_FLASH_SECT; + } + flash_info[0].size = size; + flash_info[0].sector_count = nlocks; + flash_info[0].flash_id = id; + + addr = ATMEL_BASE_FLASH; + for (i=0; i<nlocks; i++) { + tmp = readl(&eefc->frr); /* words 4+nplanes+1.. */ + flash_info[0].start[i] = addr; + flash_info[0].protect[i] = 0; + addr += tmp; + }; + + /* now read the protection information for all regions */ + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GLB, &eefc->fcr); + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + for (i=0; i<flash_info[0].sector_count; i++) { + if (i%32 == 0) + tmp = readl(&eefc->frr); + flash_info[0].protect[i] = (tmp >> (i%32)) & 1; +#if defined(CONFIG_EFLASH_PROTSECTORS) + if (i < CONFIG_EFLASH_PROTSECTORS) + flash_info[0].protect[i] = 1; +#endif + } + + return size; +} + +void flash_print_info (flash_info_t *info) +{ + int i; + + puts("AT91SAM9XE embedded flash\n Size: "); + print_size(info->size, " in "); + printf("%d Sectors\n", info->sector_count); + + printf(" Sector Start Addresses:"); + for (i=0; i<info->sector_count; ++i) { + if ((i % 5) == 0) + printf("\n "); + printf(" %08lX%s", + info->start[i], + info->protect[i] ? " (RO)" : " " + ); + } + printf ("\n"); + return; +} + +int flash_real_protect (flash_info_t *info, long sector, int prot) +{ + at91_eefc_t *eefc = (at91_eefc_t *) ATMEL_BASE_EEFC; + u32 pagenum = (info->start[sector]-ATMEL_BASE_FLASH)/pagesize; + u32 i, tmp=0; + + debug("protect sector=%ld prot=%d\n", sector, prot); + +#if defined(CONFIG_EFLASH_PROTSECTORS) + if (sector < CONFIG_EFLASH_PROTSECTORS) { + if (!prot) { + printf("eflash: sector %lu cannot be unprotected\n", + sector); + } + return 1; /* return anyway, caller does not care for result */ + } +#endif + if (prot) { + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_SLB | + (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr); + } else { + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_CLB | + (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr); + } + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + /* now re-read the protection information for all regions */ + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_GLB, &eefc->fcr); + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + for (i=0; i<info->sector_count; i++) { + if (i%32 == 0) + tmp = readl(&eefc->frr); + info->protect[i] = (tmp >> (i%32)) & 1; + } + return 0; +} + +static u32 erase_write_page (u32 pagenum) +{ + at91_eefc_t *eefc = (at91_eefc_t *) ATMEL_BASE_EEFC; + + debug("erase+write page=%u\n", pagenum); + + /* give erase and write page command */ + writel(AT91_EEFC_FCR_KEY | AT91_EEFC_FCR_FCMD_EWP | + (pagenum << AT91_EEFC_FCR_FARG_SHIFT), &eefc->fcr); + while ((readl(&eefc->fsr) & AT91_EEFC_FSR_FRDY) == 0) + ; + /* return status */ + return readl(&eefc->fsr) + & (AT91_EEFC_FSR_FCMDE | AT91_EEFC_FSR_FLOCKE); +} + +int flash_erase (flash_info_t *info, int s_first, int s_last) +{ + debug("erase first=%d last=%d\n", s_first, s_last); + puts("this flash does not need and support erasing!\n"); + return 0; +} + +/* + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + */ + +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ + u32 pagenum; + u32 *src32, *dst32; + u32 i; + + debug("write src=%08lx addr=%08lx cnt=%lx\n", + (ulong)src, addr, cnt); + + /* REQUIRE addr to be on a page start, abort if not */ + if (addr % pagesize) { + printf ("eflash: start %08lx is not on page start\n"\ + " write aborted\n", addr); + return 1; + } + + /* now start copying data */ + pagenum = (addr-ATMEL_BASE_FLASH)/pagesize; + src32 = (u32 *) src; + dst32 = (u32 *) addr; + while (cnt > 0) { + i = pagesize / 4; + /* fill page buffer */ + while (i--) + *dst32++ = *src32++; + /* write page */ + if (erase_write_page(pagenum)) + return 1; + pagenum++; + if (cnt > pagesize) + cnt -= pagesize; + else + cnt = 0; + } + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/at91/led.c b/arch/arm/cpu/arm926ejs/at91/led.c new file mode 100644 index 0000000..a1bb28d --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/led.c @@ -0,0 +1,65 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * 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 <asm/io.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/at91_pio.h> +#include <asm/arch/gpio.h> + +#ifdef CONFIG_RED_LED +void red_led_on(void) +{ + at91_set_gpio_value(CONFIG_RED_LED, 1); +} + +void red_led_off(void) +{ + at91_set_gpio_value(CONFIG_RED_LED, 0); +} +#endif + +#ifdef CONFIG_GREEN_LED +void green_led_on(void) +{ + at91_set_gpio_value(CONFIG_GREEN_LED, 0); +} + +void green_led_off(void) +{ + at91_set_gpio_value(CONFIG_GREEN_LED, 1); +} +#endif + +#ifdef CONFIG_YELLOW_LED +void yellow_led_on(void) +{ + at91_set_gpio_value(CONFIG_YELLOW_LED, 0); +} + +void yellow_led_off(void) +{ + at91_set_gpio_value(CONFIG_YELLOW_LED, 1); +} +#endif diff --git a/arch/arm/cpu/arm926ejs/at91/lowlevel_init.S b/arch/arm/cpu/arm926ejs/at91/lowlevel_init.S new file mode 100644 index 0000000..d102195 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/lowlevel_init.S @@ -0,0 +1,274 @@ +/* + * Memory Setup stuff - taken from blob memsetup.S + * + * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and + * Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) + * + * Copyright (C) 2008 Ronetix Ilko Iliev (www.ronetix.at) + * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com> + * + * 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 <asm/arch/hardware.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/at91_wdt.h> +#include <asm/arch/at91_pio.h> +#include <asm/arch/at91_matrix.h> +#include <asm/arch/at91sam9_sdramc.h> +#include <asm/arch/at91sam9_smc.h> +#include <asm/arch/at91_rstc.h> +#ifdef CONFIG_ATMEL_LEGACY +#include <asm/arch/at91sam9_matrix.h> +#endif +#ifndef CONFIG_SYS_MATRIX_EBICSA_VAL +#define CONFIG_SYS_MATRIX_EBICSA_VAL CONFIG_SYS_MATRIX_EBI0CSA_VAL +#endif + +_TEXT_BASE: + .word CONFIG_SYS_TEXT_BASE + +.globl lowlevel_init +.type lowlevel_init,function +lowlevel_init: + + mov r5, pc /* r5 = POS1 + 4 current */ +POS1: + ldr r0, =POS1 /* r0 = POS1 compile */ + ldr r2, _TEXT_BASE + sub r0, r0, r2 /* r0 = POS1-_TEXT_BASE (POS1 relative) */ + sub r5, r5, r0 /* r0 = CONFIG_SYS_TEXT_BASE-1 */ + sub r5, r5, #4 /* r1 = text base - current */ + + /* memory control configuration 1 */ + ldr r0, =SMRDATA + ldr r2, =SMRDATA1 + ldr r1, _TEXT_BASE + sub r0, r0, r1 + sub r2, r2, r1 + add r0, r0, r5 + add r2, r2, r5 +0: + /* the address */ + ldr r1, [r0], #4 + /* the value */ + ldr r3, [r0], #4 + str r3, [r1] + cmp r2, r0 + bne 0b + +/* ---------------------------------------------------------------------------- + * PMC Init Step 1. + * ---------------------------------------------------------------------------- + * - Check if the PLL is already initialized + * ---------------------------------------------------------------------------- + */ + ldr r1, =(AT91_ASM_PMC_MCKR) + ldr r0, [r1] + and r0, r0, #3 + cmp r0, #0 + bne PLL_setup_end + +/* --------------------------------------------------------------------------- + * - Enable the Main Oscillator + * --------------------------------------------------------------------------- + */ + ldr r1, =(AT91_ASM_PMC_MOR) + ldr r2, =(AT91_ASM_PMC_SR) + /* Main oscillator Enable register PMC_MOR: */ + ldr r0, =CONFIG_SYS_MOR_VAL + str r0, [r1] + + /* Reading the PMC Status to detect when the Main Oscillator is enabled */ + mov r4, #AT91_PMC_IXR_MOSCS +MOSCS_Loop: + ldr r3, [r2] + and r3, r4, r3 + cmp r3, #AT91_PMC_IXR_MOSCS + bne MOSCS_Loop + +/* ---------------------------------------------------------------------------- + * PMC Init Step 2. + * ---------------------------------------------------------------------------- + * Setup PLLA + * ---------------------------------------------------------------------------- + */ + ldr r1, =(AT91_ASM_PMC_PLLAR) + ldr r0, =CONFIG_SYS_PLLAR_VAL + str r0, [r1] + + /* Reading the PMC Status register to detect when the PLLA is locked */ + mov r4, #AT91_PMC_IXR_LOCKA +MOSCS_Loop1: + ldr r3, [r2] + and r3, r4, r3 + cmp r3, #AT91_PMC_IXR_LOCKA + bne MOSCS_Loop1 + +/* ---------------------------------------------------------------------------- + * PMC Init Step 3. + * ---------------------------------------------------------------------------- + * - Switch on the Main Oscillator + * ---------------------------------------------------------------------------- + */ + ldr r1, =(AT91_ASM_PMC_MCKR) + + /* -Master Clock Controller register PMC_MCKR */ + ldr r0, =CONFIG_SYS_MCKR1_VAL + str r0, [r1] + + /* Reading the PMC Status to detect when the Master clock is ready */ + mov r4, #AT91_PMC_IXR_MCKRDY +MCKRDY_Loop: + ldr r3, [r2] + and r3, r4, r3 + cmp r3, #AT91_PMC_IXR_MCKRDY + bne MCKRDY_Loop + + ldr r0, =CONFIG_SYS_MCKR2_VAL + str r0, [r1] + + /* Reading the PMC Status to detect when the Master clock is ready */ + mov r4, #AT91_PMC_IXR_MCKRDY +MCKRDY_Loop1: + ldr r3, [r2] + and r3, r4, r3 + cmp r3, #AT91_PMC_IXR_MCKRDY + bne MCKRDY_Loop1 +PLL_setup_end: + +/* ---------------------------------------------------------------------------- + * - memory control configuration 2 + * ---------------------------------------------------------------------------- + */ + ldr r0, =(AT91_ASM_SDRAMC_TR) + ldr r1, [r0] + cmp r1, #0 + bne SDRAM_setup_end + + ldr r0, =SMRDATA1 + ldr r2, =SMRDATA2 + ldr r1, _TEXT_BASE + sub r0, r0, r1 + sub r2, r2, r1 + add r0, r0, r5 + add r2, r2, r5 +2: + /* the address */ + ldr r1, [r0], #4 + /* the value */ + ldr r3, [r0], #4 + str r3, [r1] + cmp r2, r0 + bne 2b + +SDRAM_setup_end: + /* everything is fine now */ + mov pc, lr + + .ltorg + +SMRDATA: + .word AT91_ASM_WDT_MR + .word CONFIG_SYS_WDTC_WDMR_VAL + /* configure PIOx as EBI0 D[16-31] */ +#if defined(CONFIG_AT91SAM9263) + .word AT91_ASM_PIOD_PDR + .word CONFIG_SYS_PIOD_PDR_VAL1 + .word AT91_ASM_PIOD_PUDR + .word CONFIG_SYS_PIOD_PPUDR_VAL + .word AT91_ASM_PIOD_ASR + .word CONFIG_SYS_PIOD_PPUDR_VAL +#elif defined(CONFIG_AT91SAM9260) || defined(CONFIG_AT91SAM9261) \ + || defined(CONFIG_AT91SAM9G20) + .word AT91_ASM_PIOC_PDR + .word CONFIG_SYS_PIOC_PDR_VAL1 + .word AT91_ASM_PIOC_PUDR + .word CONFIG_SYS_PIOC_PPUDR_VAL +#endif + .word AT91_ASM_MATRIX_CSA0 + .word CONFIG_SYS_MATRIX_EBICSA_VAL + + /* flash */ + .word AT91_ASM_SMC_MODE0 + .word CONFIG_SYS_SMC0_MODE0_VAL + + .word AT91_ASM_SMC_CYCLE0 + .word CONFIG_SYS_SMC0_CYCLE0_VAL + + .word AT91_ASM_SMC_PULSE0 + .word CONFIG_SYS_SMC0_PULSE0_VAL + + .word AT91_ASM_SMC_SETUP0 + .word CONFIG_SYS_SMC0_SETUP0_VAL + +SMRDATA1: + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL1 + .word AT91_ASM_SDRAMC_TR + .word CONFIG_SYS_SDRC_TR_VAL1 + .word AT91_ASM_SDRAMC_CR + .word CONFIG_SYS_SDRC_CR_VAL + .word AT91_ASM_SDRAMC_MDR + .word CONFIG_SYS_SDRC_MDR_VAL + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL2 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL1 + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL3 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL2 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL3 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL4 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL5 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL6 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL7 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL8 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL9 + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL4 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL10 + .word AT91_ASM_SDRAMC_MR + .word CONFIG_SYS_SDRC_MR_VAL5 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL11 + .word AT91_ASM_SDRAMC_TR + .word CONFIG_SYS_SDRC_TR_VAL2 + .word CONFIG_SYS_SDRAM_BASE + .word CONFIG_SYS_SDRAM_VAL12 + /* User reset enable*/ + .word AT91_ASM_RSTC_MR + .word CONFIG_SYS_RSTC_RMR_VAL +#ifdef CONFIG_SYS_MATRIX_MCFG_REMAP + /* MATRIX_MCFG - REMAP all masters */ + .word AT91_ASM_MATRIX_MCFG + .word 0x1FF +#endif +SMRDATA2: + .word 0 diff --git a/arch/arm/cpu/arm926ejs/at91/reset.c b/arch/arm/cpu/arm926ejs/at91/reset.c new file mode 100644 index 0000000..f6a7cb7 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/reset.c @@ -0,0 +1,45 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * 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 <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_rstc.h> + +/* Reset the cpu by telling the reset controller to do so */ +void reset_cpu(ulong ignored) +{ + at91_rstc_t *rstc = (at91_rstc_t *) ATMEL_BASE_RSTC; + + writel(AT91_RSTC_KEY + | AT91_RSTC_CR_PROCRST /* Processor Reset */ + | AT91_RSTC_CR_PERRST /* Peripheral Reset */ +#ifdef CONFIG_AT91RESET_EXTRST + | AT91_RSTC_CR_EXTRST /* External Reset (assert nRST pin) */ +#endif + , &rstc->cr); + /* never reached */ + while (1) + ; +} diff --git a/arch/arm/cpu/arm926ejs/at91/timer.c b/arch/arm/cpu/arm926ejs/at91/timer.c new file mode 100644 index 0000000..4443fef --- /dev/null +++ b/arch/arm/cpu/arm926ejs/at91/timer.c @@ -0,0 +1,136 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * 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 <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/at91_pit.h> +#include <asm/arch/at91_pmc.h> +#include <asm/arch/clk.h> +#include <div64.h> + +#if !defined(CONFIG_AT91FAMILY) +# error You need to define CONFIG_AT91FAMILY in your board config! +#endif + +DECLARE_GLOBAL_DATA_PTR; + +/* + * We're using the AT91CAP9/SAM9 PITC in 32 bit mode, by + * setting the 20 bit counter period to its maximum (0xfffff). + * (See the relevant data sheets to understand that this really works) + * + * We do also mimic the typical powerpc way of incrementing + * two 32 bit registers called tbl and tbu. + * + * Those registers increment at 1/16 the main clock rate. + */ + +#define TIMER_LOAD_VAL 0xfffff + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + tick *= CONFIG_SYS_HZ; + do_div(tick, gd->arch.timer_rate_hz); + + return tick; +} + +static inline unsigned long long usec_to_tick(unsigned long long usec) +{ + usec *= gd->arch.timer_rate_hz; + do_div(usec, 1000000); + + return usec; +} + +/* + * Use the PITC in full 32 bit incrementing mode + */ +int timer_init(void) +{ + at91_pmc_t *pmc = (at91_pmc_t *) ATMEL_BASE_PMC; + at91_pit_t *pit = (at91_pit_t *) ATMEL_BASE_PIT; + + /* Enable PITC Clock */ + writel(1 << ATMEL_ID_SYS, &pmc->pcer); + + /* Enable PITC */ + writel(TIMER_LOAD_VAL | AT91_PIT_MR_EN , &pit->mr); + + gd->arch.timer_rate_hz = gd->arch.mck_rate_hz / 16; + gd->arch.tbu = gd->arch.tbl = 0; + + return 0; +} + +/* + * Get the current 64 bit timer tick count + */ +unsigned long long get_ticks(void) +{ + at91_pit_t *pit = (at91_pit_t *) ATMEL_BASE_PIT; + + ulong now = readl(&pit->piir); + + /* increment tbu if tbl has rolled over */ + if (now < gd->arch.tbl) + gd->arch.tbu++; + gd->arch.tbl = now; + return (((unsigned long long)gd->arch.tbu) << 32) | gd->arch.tbl; +} + +void __udelay(unsigned long usec) +{ + unsigned long long start; + ulong tmo; + + start = get_ticks(); /* get current timestamp */ + tmo = usec_to_tick(usec); /* convert usecs to ticks */ + while ((get_ticks() - start) < tmo) + ; /* loop till time has passed */ +} + +/* + * get_timer(base) can be used to check for timeouts or + * to measure elasped time relative to an event: + * + * ulong start_time = get_timer(0) sets start_time to the current + * time value. + * get_timer(start_time) returns the time elapsed since then. + * + * The time is used in CONFIG_SYS_HZ units! + */ +ulong get_timer(ulong base) +{ + return tick_to_time(get_ticks()) - base; +} + +/* + * Return the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return gd->arch.timer_rate_hz; +} diff --git a/arch/arm/cpu/arm926ejs/cache.c b/arch/arm/cpu/arm926ejs/cache.c new file mode 100644 index 0000000..2740ad7 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/cache.c @@ -0,0 +1,120 @@ +/* + * (C) Copyright 2011 + * Ilya Yanok, EmCraft Systems + * + * 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. + */ +#include <linux/types.h> +#include <common.h> + +#ifndef CONFIG_SYS_DCACHE_OFF + +#ifndef CONFIG_SYS_CACHELINE_SIZE +#define CONFIG_SYS_CACHELINE_SIZE 32 +#endif + +void invalidate_dcache_all(void) +{ + asm volatile("mcr p15, 0, %0, c7, c6, 0\n" : : "r"(0)); +} + +void flush_dcache_all(void) +{ + asm volatile( + "0:" + "mrc p15, 0, r15, c7, c14, 3\n" + "bne 0b\n" + "mcr p15, 0, %0, c7, c10, 4\n" + : : "r"(0) : "memory" + ); +} + +static int check_cache_range(unsigned long start, unsigned long stop) +{ + int ok = 1; + + if (start & (CONFIG_SYS_CACHELINE_SIZE - 1)) + ok = 0; + + if (stop & (CONFIG_SYS_CACHELINE_SIZE - 1)) + ok = 0; + + if (!ok) + debug("CACHE: Misaligned operation at range [%08lx, %08lx]\n", + start, stop); + + return ok; +} + +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ + if (!check_cache_range(start, stop)) + return; + + while (start < stop) { + asm volatile("mcr p15, 0, %0, c7, c6, 1\n" : : "r"(start)); + start += CONFIG_SYS_CACHELINE_SIZE; + } +} + +void flush_dcache_range(unsigned long start, unsigned long stop) +{ + if (!check_cache_range(start, stop)) + return; + + while (start < stop) { + asm volatile("mcr p15, 0, %0, c7, c14, 1\n" : : "r"(start)); + start += CONFIG_SYS_CACHELINE_SIZE; + } + + asm volatile("mcr p15, 0, %0, c7, c10, 4\n" : : "r"(0)); +} + +void flush_cache(unsigned long start, unsigned long size) +{ + flush_dcache_range(start, start + size); +} +#else /* #ifndef CONFIG_SYS_DCACHE_OFF */ +void invalidate_dcache_all(void) +{ +} + +void flush_dcache_all(void) +{ +} + +void invalidate_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void flush_dcache_range(unsigned long start, unsigned long stop) +{ +} + +void flush_cache(unsigned long start, unsigned long size) +{ +} +#endif /* #ifndef CONFIG_SYS_DCACHE_OFF */ + +/* + * Stub implementations for l2 cache operations + */ +void __l2_cache_disable(void) {} + +void l2_cache_disable(void) + __attribute__((weak, alias("__l2_cache_disable"))); diff --git a/arch/arm/cpu/arm926ejs/config.mk b/arch/arm/cpu/arm926ejs/config.mk new file mode 100644 index 0000000..f0e31d1 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/config.mk @@ -0,0 +1,43 @@ +# +# (C) Copyright 2002 +# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> +# +# 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_RELFLAGS += -fno-common -ffixed-r8 -msoft-float + +PLATFORM_CPPFLAGS += -march=armv5te +# ========================================================================= +# +# Supply options according to compiler version +# +# ========================================================================= +PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) +PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT) + +ifneq ($(CONFIG_IMX_CONFIG),) +ifdef CONFIG_SPL +ifdef CONFIG_SPL_BUILD +ALL-y += $(OBJTREE)/SPL +endif +else +ALL-y += $(obj)u-boot.imx +endif +endif diff --git a/arch/arm/cpu/arm926ejs/cpu.c b/arch/arm/cpu/arm926ejs/cpu.c new file mode 100644 index 0000000..626384c --- /dev/null +++ b/arch/arm/cpu/arm926ejs/cpu.c @@ -0,0 +1,67 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * 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 + */ + +/* + * CPU specific code + */ + +#include <common.h> +#include <command.h> +#include <asm/system.h> + +static void cache_flush(void); + +int cleanup_before_linux (void) +{ + /* + * this function is called just before we call linux + * it prepares the processor for linux + * + * we turn off caches etc ... + */ + + disable_interrupts (); + + + /* turn off I/D-cache */ + icache_disable(); + dcache_disable(); + l2_cache_disable(); + + /* flush I/D-cache */ + cache_flush(); + + return 0; +} + +/* flush I/D-cache */ +static void cache_flush (void) +{ + unsigned long i = 0; + + asm ("mcr p15, 0, %0, c7, c7, 0": :"r" (i)); +} diff --git a/arch/arm/cpu/arm926ejs/davinci/Makefile b/arch/arm/cpu/arm926ejs/davinci/Makefile new file mode 100644 index 0000000..bba4671 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/Makefile @@ -0,0 +1,66 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.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$(SOC).o + +COBJS-y += cpu.o misc.o timer.o psc.o pinmux.o reset.o +COBJS-$(CONFIG_DA850_LOWLEVEL) += da850_lowlevel.o +COBJS-$(CONFIG_SOC_DM355) += dm355.o +COBJS-$(CONFIG_SOC_DM365) += dm365.o +COBJS-$(CONFIG_SOC_DM644X) += dm644x.o +COBJS-$(CONFIG_SOC_DM646X) += dm646x.o +COBJS-$(CONFIG_SOC_DA830) += da830_pinmux.o +COBJS-$(CONFIG_SOC_DA850) += da850_pinmux.o +COBJS-$(CONFIG_DRIVER_TI_EMAC) += lxt972.o dp83848.o et1011c.o ksz8873.o + +ifdef CONFIG_SPL_BUILD +COBJS-$(CONFIG_SPL_FRAMEWORK) += spl.o +COBJS-$(CONFIG_SOC_DM365) += dm365_lowlevel.o +COBJS-$(CONFIG_SOC_DA8XX) += da850_lowlevel.o +endif + +ifndef CONFIG_SKIP_LOWLEVEL_INIT +SOBJS += lowlevel_init.o +endif + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/davinci/config.mk b/arch/arm/cpu/arm926ejs/davinci/config.mk new file mode 100644 index 0000000..7452315 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/config.mk @@ -0,0 +1,16 @@ +# +# Copyright (C) 2012, Texas Instruments, Incorporated - http://www.ti.com/ +# +# 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 "as is" WITHOUT ANY WARRANTY of any +# kind, whether express or implied; without even the implied warranty +# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +ifndef CONFIG_SPL_BUILD +ALL-$(CONFIG_SPL_FRAMEWORK) += $(obj)u-boot.ais +endif diff --git a/arch/arm/cpu/arm926ejs/davinci/cpu.c b/arch/arm/cpu/arm926ejs/davinci/cpu.c new file mode 100644 index 0000000..b31add8 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/cpu.c @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2004 Texas Instruments. + * Copyright (C) 2009 David Brownell + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <netdev.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* offsets from PLL controller base */ +#define PLLC_PLLCTL 0x100 +#define PLLC_PLLM 0x110 +#define PLLC_PREDIV 0x114 +#define PLLC_PLLDIV1 0x118 +#define PLLC_PLLDIV2 0x11c +#define PLLC_PLLDIV3 0x120 +#define PLLC_POSTDIV 0x128 +#define PLLC_BPDIV 0x12c +#define PLLC_PLLDIV4 0x160 +#define PLLC_PLLDIV5 0x164 +#define PLLC_PLLDIV6 0x168 +#define PLLC_PLLDIV7 0x16c +#define PLLC_PLLDIV8 0x170 +#define PLLC_PLLDIV9 0x174 + +#define BIT(x) (1 << (x)) + +/* SOC-specific pll info */ +#ifdef CONFIG_SOC_DM355 +#define ARM_PLLDIV PLLC_PLLDIV1 +#define DDR_PLLDIV PLLC_PLLDIV1 +#endif + +#ifdef CONFIG_SOC_DM644X +#define ARM_PLLDIV PLLC_PLLDIV2 +#define DSP_PLLDIV PLLC_PLLDIV1 +#define DDR_PLLDIV PLLC_PLLDIV2 +#endif + +#ifdef CONFIG_SOC_DM646X +#define DSP_PLLDIV PLLC_PLLDIV1 +#define ARM_PLLDIV PLLC_PLLDIV2 +#define DDR_PLLDIV PLLC_PLLDIV1 +#endif + +#ifdef CONFIG_SOC_DA8XX +unsigned int sysdiv[9] = { + PLLC_PLLDIV1, PLLC_PLLDIV2, PLLC_PLLDIV3, PLLC_PLLDIV4, PLLC_PLLDIV5, + PLLC_PLLDIV6, PLLC_PLLDIV7, PLLC_PLLDIV8, PLLC_PLLDIV9 +}; + +int clk_get(enum davinci_clk_ids id) +{ + int pre_div; + int pllm; + int post_div; + int pll_out; + unsigned int pll_base; + + pll_out = CONFIG_SYS_OSCIN_FREQ; + + if (id == DAVINCI_AUXCLK_CLKID) + goto out; + + if ((id >> 16) == 1) + pll_base = (unsigned int)davinci_pllc1_regs; + else + pll_base = (unsigned int)davinci_pllc0_regs; + + id &= 0xFFFF; + + /* + * Lets keep this simple. Combining operations can result in + * unexpected approximations + */ + pre_div = (readl(pll_base + PLLC_PREDIV) & + DAVINCI_PLLC_DIV_MASK) + 1; + pllm = readl(pll_base + PLLC_PLLM) + 1; + + pll_out /= pre_div; + pll_out *= pllm; + + if (id == DAVINCI_PLLM_CLKID) + goto out; + + post_div = (readl(pll_base + PLLC_POSTDIV) & + DAVINCI_PLLC_DIV_MASK) + 1; + + pll_out /= post_div; + + if (id == DAVINCI_PLLC_CLKID) + goto out; + + pll_out /= (readl(pll_base + sysdiv[id - 1]) & + DAVINCI_PLLC_DIV_MASK) + 1; + +out: + return pll_out; +} + +int set_cpu_clk_info(void) +{ + gd->bd->bi_arm_freq = clk_get(DAVINCI_ARM_CLKID) / 1000000; + /* DDR PHY uses an x2 input clock */ + gd->bd->bi_ddr_freq = cpu_is_da830() ? 0 : + (clk_get(DAVINCI_DDR_CLKID) / 1000000); + gd->bd->bi_dsp_freq = 0; + return 0; +} + +#else /* CONFIG_SOC_DA8XX */ + +static unsigned pll_div(volatile void *pllbase, unsigned offset) +{ + u32 div; + + div = REG(pllbase + offset); + return (div & BIT(15)) ? (1 + (div & 0x1f)) : 1; +} + +static inline unsigned pll_prediv(volatile void *pllbase) +{ +#ifdef CONFIG_SOC_DM355 + /* this register read seems to fail on pll0 */ + if (pllbase == (volatile void *)DAVINCI_PLL_CNTRL0_BASE) + return 8; + else + return pll_div(pllbase, PLLC_PREDIV); +#elif defined(CONFIG_SOC_DM365) + return pll_div(pllbase, PLLC_PREDIV); +#endif + return 1; +} + +static inline unsigned pll_postdiv(volatile void *pllbase) +{ +#if defined(CONFIG_SOC_DM355) || defined(CONFIG_SOC_DM365) + return pll_div(pllbase, PLLC_POSTDIV); +#elif defined(CONFIG_SOC_DM6446) + if (pllbase == (volatile void *)DAVINCI_PLL_CNTRL0_BASE) + return pll_div(pllbase, PLLC_POSTDIV); +#endif + return 1; +} + +static unsigned pll_sysclk_mhz(unsigned pll_addr, unsigned div) +{ + volatile void *pllbase = (volatile void *) pll_addr; +#ifdef CONFIG_SOC_DM646X + unsigned base = CONFIG_REFCLK_FREQ / 1000; +#else + unsigned base = CONFIG_SYS_HZ_CLOCK / 1000; +#endif + + /* the PLL might be bypassed */ + if (readl(pllbase + PLLC_PLLCTL) & BIT(0)) { + base /= pll_prediv(pllbase); +#if defined(CONFIG_SOC_DM365) + base *= 2 * (readl(pllbase + PLLC_PLLM) & 0x0ff); +#else + base *= 1 + (REG(pllbase + PLLC_PLLM) & 0x0ff); +#endif + base /= pll_postdiv(pllbase); + } + return DIV_ROUND_UP(base, 1000 * pll_div(pllbase, div)); +} + +#ifdef DAVINCI_DM6467EVM +unsigned int davinci_arm_clk_get() +{ + return pll_sysclk_mhz(DAVINCI_PLL_CNTRL0_BASE, ARM_PLLDIV) * 1000000; +} +#endif + +#if defined(CONFIG_SOC_DM365) +unsigned int davinci_clk_get(unsigned int div) +{ + return pll_sysclk_mhz(DAVINCI_PLL_CNTRL0_BASE, div) * 1000000; +} +#endif + +int set_cpu_clk_info(void) +{ + unsigned int pllbase = DAVINCI_PLL_CNTRL0_BASE; +#if defined(CONFIG_SOC_DM365) + pllbase = DAVINCI_PLL_CNTRL1_BASE; +#endif + gd->bd->bi_arm_freq = pll_sysclk_mhz(pllbase, ARM_PLLDIV); + +#ifdef DSP_PLLDIV + gd->bd->bi_dsp_freq = + pll_sysclk_mhz(DAVINCI_PLL_CNTRL0_BASE, DSP_PLLDIV); +#else + gd->bd->bi_dsp_freq = 0; +#endif + + pllbase = DAVINCI_PLL_CNTRL1_BASE; +#if defined(CONFIG_SOC_DM365) + pllbase = DAVINCI_PLL_CNTRL0_BASE; +#endif + gd->bd->bi_ddr_freq = pll_sysclk_mhz(pllbase, DDR_PLLDIV) / 2; + + return 0; +} + +#endif /* !CONFIG_SOC_DA8XX */ + +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ +#if defined(CONFIG_DRIVER_TI_EMAC) + davinci_emac_initialize(); +#endif + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/davinci/da830_pinmux.c b/arch/arm/cpu/arm926ejs/davinci/da830_pinmux.c new file mode 100644 index 0000000..d0c964a --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/da830_pinmux.c @@ -0,0 +1,151 @@ +/* + * Pinmux configurations for the DA830 SoCs + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/ + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <asm/arch/davinci_misc.h> +#include <asm/arch/hardware.h> +#include <asm/arch/pinmux_defs.h> + +/* SPI0 pin muxer settings */ +const struct pinmux_config spi0_pins_base[] = { + { pinmux(7), 1, 3 }, /* SPI0_SOMI */ + { pinmux(7), 1, 4 }, /* SPI0_SIMO */ + { pinmux(7), 1, 6 } /* SPI0_CLK */ +}; + +const struct pinmux_config spi0_pins_scs0[] = { + { pinmux(7), 1, 7 } /* SPI0_SCS[0] */ +}; + +const struct pinmux_config spi0_pins_ena[] = { + { pinmux(7), 1, 5 } /* SPI0_ENA */ +}; + +/* NAND pin muxer settings */ +const struct pinmux_config emifa_pins_cs0[] = { + { pinmux(18), 1, 2 } /* EMA_CS[0] */ +}; + +const struct pinmux_config emifa_pins_cs2[] = { + { pinmux(18), 1, 3 } /* EMA_CS[2] */ +}; + +const struct pinmux_config emifa_pins_cs3[] = { + { pinmux(18), 1, 4 } /* EMA_CS[3] */ +}; + +#ifdef CONFIG_USE_NAND +const struct pinmux_config emifa_pins[] = { + { pinmux(13), 1, 6 }, /* EMA_D[0] */ + { pinmux(13), 1, 7 }, /* EMA_D[1] */ + { pinmux(14), 1, 0 }, /* EMA_D[2] */ + { pinmux(14), 1, 1 }, /* EMA_D[3] */ + { pinmux(14), 1, 2 }, /* EMA_D[4] */ + { pinmux(14), 1, 3 }, /* EMA_D[5] */ + { pinmux(14), 1, 4 }, /* EMA_D[6] */ + { pinmux(14), 1, 5 }, /* EMA_D[7] */ + { pinmux(14), 1, 6 }, /* EMA_D[8] */ + { pinmux(14), 1, 7 }, /* EMA_D[9] */ + { pinmux(15), 1, 0 }, /* EMA_D[10] */ + { pinmux(15), 1, 1 }, /* EMA_D[11] */ + { pinmux(15), 1, 2 }, /* EMA_D[12] */ + { pinmux(15), 1, 3 }, /* EMA_D[13] */ + { pinmux(15), 1, 4 }, /* EMA_D[14] */ + { pinmux(15), 1, 5 }, /* EMA_D[15] */ + { pinmux(15), 1, 6 }, /* EMA_A[0] */ + { pinmux(15), 1, 7 }, /* EMA_A[1] */ + { pinmux(16), 1, 0 }, /* EMA_A[2] */ + { pinmux(16), 1, 1 }, /* EMA_A[3] */ + { pinmux(16), 1, 2 }, /* EMA_A[4] */ + { pinmux(16), 1, 3 }, /* EMA_A[5] */ + { pinmux(16), 1, 4 }, /* EMA_A[6] */ + { pinmux(16), 1, 5 }, /* EMA_A[7] */ + { pinmux(16), 1, 6 }, /* EMA_A[8] */ + { pinmux(16), 1, 7 }, /* EMA_A[9] */ + { pinmux(17), 1, 0 }, /* EMA_A[10] */ + { pinmux(17), 1, 1 }, /* EMA_A[11] */ + { pinmux(17), 1, 2 }, /* EMA_A[12] */ + { pinmux(17), 1, 3 }, /* EMA_BA[1] */ + { pinmux(17), 1, 4 }, /* EMA_BA[0] */ + { pinmux(17), 1, 5 }, /* EMA_CLK */ + { pinmux(17), 1, 6 }, /* EMA_SDCKE */ + { pinmux(17), 1, 7 }, /* EMA_CAS */ + { pinmux(18), 1, 0 }, /* EMA_CAS */ + { pinmux(18), 1, 1 }, /* EMA_WE */ + { pinmux(18), 1, 5 }, /* EMA_OE */ + { pinmux(18), 1, 6 }, /* EMA_WE_DQM[1] */ + { pinmux(18), 1, 7 }, /* EMA_WE_DQM[0] */ + { pinmux(10), 1, 0 } /* Tristate */ +}; +#endif + +/* EMAC PHY interface pins */ +const struct pinmux_config emac_pins_rmii[] = { + { pinmux(10), 2, 1 }, /* RMII_TXD[0] */ + { pinmux(10), 2, 2 }, /* RMII_TXD[1] */ + { pinmux(10), 2, 3 }, /* RMII_TXEN */ + { pinmux(10), 2, 4 }, /* RMII_CRS_DV */ + { pinmux(10), 2, 5 }, /* RMII_RXD[0] */ + { pinmux(10), 2, 6 }, /* RMII_RXD[1] */ + { pinmux(10), 2, 7 } /* RMII_RXER */ +}; + +const struct pinmux_config emac_pins_mdio[] = { + { pinmux(11), 2, 0 }, /* MDIO_CLK */ + { pinmux(11), 2, 1 } /* MDIO_D */ +}; + +const struct pinmux_config emac_pins_rmii_clk_source[] = { + { pinmux(9), 0, 5 } /* ref.clk from external source */ +}; + +/* UART2 pin muxer settings */ +const struct pinmux_config uart2_pins_txrx[] = { + { pinmux(8), 2, 7 }, /* UART2_RXD */ + { pinmux(9), 2, 0 } /* UART2_TXD */ +}; + +/* I2C0 pin muxer settings */ +const struct pinmux_config i2c0_pins[] = { + { pinmux(8), 2, 3 }, /* I2C0_SDA */ + { pinmux(8), 2, 4 } /* I2C0_SCL */ +}; + +/* USB0_DRVVBUS pin muxer settings */ +const struct pinmux_config usb_pins[] = { + { pinmux(9), 1, 1 } /* USB0_DRVVBUS */ +}; + +#ifdef CONFIG_DAVINCI_MMC +/* MMC0 pin muxer settings */ +const struct pinmux_config mmc0_pins_8bit[] = { + { pinmux(15), 2, 7 }, /* MMCSD0_CLK */ + { pinmux(16), 2, 0 }, /* MMCSD0_CMD */ + { pinmux(13), 2, 6 }, /* MMCSD0_DAT_0 */ + { pinmux(13), 2, 7 }, /* MMCSD0_DAT_1 */ + { pinmux(14), 2, 0 }, /* MMCSD0_DAT_2 */ + { pinmux(14), 2, 1 }, /* MMCSD0_DAT_3 */ + { pinmux(14), 2, 2 }, /* MMCSD0_DAT_4 */ + { pinmux(14), 2, 3 }, /* MMCSD0_DAT_5 */ + { pinmux(14), 2, 4 }, /* MMCSD0_DAT_6 */ + { pinmux(14), 2, 5 } /* MMCSD0_DAT_7 */ + /* DA830 supports 8-bit mode */ +}; +#endif diff --git a/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c b/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c new file mode 100644 index 0000000..127beb8 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/da850_lowlevel.c @@ -0,0 +1,324 @@ +/* + * SoC-specific lowlevel code for DA850 + * + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <common.h> +#include <nand.h> +#include <ns16550.h> +#include <post.h> +#include <asm/arch/da850_lowlevel.h> +#include <asm/arch/hardware.h> +#include <asm/arch/davinci_misc.h> +#include <asm/arch/ddr2_defs.h> +#include <asm/arch/emif_defs.h> +#include <asm/arch/pll_defs.h> + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_LPSC_UART0); + + /* Bringup UART0 out of reset */ + REG(UART0_PWREMU_MGMT) = 0x00006001; +} + +#if defined(CONFIG_SYS_DA850_PLL_INIT) +void da850_waitloop(unsigned long loopcnt) +{ + unsigned long i; + + for (i = 0; i < loopcnt; i++) + asm(" NOP"); +} + +int da850_pll_init(struct davinci_pllc_regs *reg, unsigned long pllmult) +{ + if (reg == davinci_pllc0_regs) + /* Unlock PLL registers. */ + clrbits_le32(&davinci_syscfg_regs->cfgchip0, PLL_MASTER_LOCK); + + /* + * Set PLLENSRC '0',bit 5, PLL Enable(PLLEN) selection is controlled + * through MMR + */ + clrbits_le32(®->pllctl, PLLCTL_PLLENSRC); + /* PLLCTL.EXTCLKSRC bit 9 should be left at 0 for Freon */ + clrbits_le32(®->pllctl, PLLCTL_EXTCLKSRC); + + /* Set PLLEN=0 => PLL BYPASS MODE */ + clrbits_le32(®->pllctl, PLLCTL_PLLEN); + + da850_waitloop(150); + + if (reg == davinci_pllc0_regs) { + /* + * Select the Clock Mode bit 8 as External Clock or On Chip + * Oscilator + */ + dv_maskbits(®->pllctl, ~PLLCTL_RES_9); + setbits_le32(®->pllctl, + (CONFIG_SYS_DV_CLKMODE << PLLCTL_CLOCK_MODE_SHIFT)); + } + + /* Clear PLLRST bit to reset the PLL */ + clrbits_le32(®->pllctl, PLLCTL_PLLRST); + + /* Disable the PLL output */ + setbits_le32(®->pllctl, PLLCTL_PLLDIS); + + /* PLL initialization sequence */ + /* + * Power up the PLL- PWRDN bit set to 0 to bring the PLL out of + * power down bit + */ + clrbits_le32(®->pllctl, PLLCTL_PLLPWRDN); + + /* Enable the PLL from Disable Mode PLLDIS bit to 0 */ + clrbits_le32(®->pllctl, PLLCTL_PLLDIS); + +#if defined(CONFIG_SYS_DA850_PLL0_PREDIV) + /* program the prediv */ + if (reg == davinci_pllc0_regs && CONFIG_SYS_DA850_PLL0_PREDIV) + writel((PLL_DIVEN | CONFIG_SYS_DA850_PLL0_PREDIV), + ®->prediv); +#endif + + /* Program the required multiplier value in PLLM */ + writel(pllmult, ®->pllm); + + /* program the postdiv */ + if (reg == davinci_pllc0_regs) + writel((PLL_POSTDEN | CONFIG_SYS_DA850_PLL0_POSTDIV), + ®->postdiv); + else + writel((PLL_POSTDEN | CONFIG_SYS_DA850_PLL1_POSTDIV), + ®->postdiv); + + /* + * Check for the GOSTAT bit in PLLSTAT to clear to 0 to indicate that + * no GO operation is currently in progress + */ + while ((readl(®->pllstat) & PLLCMD_GOSTAT) == PLLCMD_GOSTAT) + ; + + if (reg == davinci_pllc0_regs) { + writel(CONFIG_SYS_DA850_PLL0_PLLDIV1, ®->plldiv1); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV2, ®->plldiv2); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV3, ®->plldiv3); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV4, ®->plldiv4); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV5, ®->plldiv5); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV6, ®->plldiv6); + writel(CONFIG_SYS_DA850_PLL0_PLLDIV7, ®->plldiv7); + } else { + writel(CONFIG_SYS_DA850_PLL1_PLLDIV1, ®->plldiv1); + writel(CONFIG_SYS_DA850_PLL1_PLLDIV2, ®->plldiv2); + writel(CONFIG_SYS_DA850_PLL1_PLLDIV3, ®->plldiv3); + } + + /* + * Set the GOSET bit in PLLCMD to 1 to initiate a new divider + * transition. + */ + setbits_le32(®->pllcmd, PLLCMD_GOSTAT); + + /* + * Wait for the GOSTAT bit in PLLSTAT to clear to 0 + * (completion of phase alignment). + */ + while ((readl(®->pllstat) & PLLCMD_GOSTAT) == PLLCMD_GOSTAT) + ; + + /* Wait for PLL to reset properly. See PLL spec for PLL reset time */ + da850_waitloop(200); + + /* Set the PLLRST bit in PLLCTL to 1 to bring the PLL out of reset */ + setbits_le32(®->pllctl, PLLCTL_PLLRST); + + /* Wait for PLL to lock. See PLL spec for PLL lock time */ + da850_waitloop(2400); + + /* + * Set the PLLEN bit in PLLCTL to 1 to remove the PLL from bypass + * mode + */ + setbits_le32(®->pllctl, PLLCTL_PLLEN); + + + /* + * clear EMIFA and EMIFB clock source settings, let them + * run off SYSCLK + */ + if (reg == davinci_pllc0_regs) + dv_maskbits(&davinci_syscfg_regs->cfgchip3, + ~(PLL_SCSCFG3_DIV45PENA | PLL_SCSCFG3_EMA_CLKSRC)); + + return 0; +} +#endif /* CONFIG_SYS_DA850_PLL_INIT */ + +#if defined(CONFIG_SYS_DA850_DDR_INIT) +int da850_ddr_setup(void) +{ + unsigned long tmp; + + /* Enable the Clock to DDR2/mDDR */ + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + + tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); + if ((tmp & VTP_POWERDWN) == VTP_POWERDWN) { + /* Begin VTP Calibration */ + clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_POWERDWN); + clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_LOCK); + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); + clrbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_CLKRZ); + + /* Polling READY bit to see when VTP calibration is done */ + tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); + while ((tmp & VTP_READY) != VTP_READY) + tmp = readl(&davinci_syscfg1_regs->vtpio_ctl); + + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_LOCK); + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_POWERDWN); + } + setbits_le32(&davinci_syscfg1_regs->vtpio_ctl, VTP_IOPWRDWN); + writel(CONFIG_SYS_DA850_DDR2_DDRPHYCR, &dv_ddr2_regs_ctrl->ddrphycr); + + if (CONFIG_SYS_DA850_DDR2_SDBCR & (1 << DV_DDR_SDCR_DDR2EN_SHIFT)) { + /* DDR2 */ + clrbits_le32(&davinci_syscfg1_regs->ddr_slew, + (1 << DDR_SLEW_DDR_PDENA_BIT) | + (1 << DDR_SLEW_CMOSEN_BIT)); + } else { + /* MOBILE DDR */ + setbits_le32(&davinci_syscfg1_regs->ddr_slew, + (1 << DDR_SLEW_DDR_PDENA_BIT) | + (1 << DDR_SLEW_CMOSEN_BIT)); + } + + /* + * SDRAM Configuration Register (SDCR): + * First set the BOOTUNLOCK bit to make configuration bits + * writeable. + */ + setbits_le32(&dv_ddr2_regs_ctrl->sdbcr, DV_DDR_BOOTUNLOCK); + + /* + * Write the new value of these bits and clear BOOTUNLOCK. + * At the same time, set the TIMUNLOCK bit to allow changing + * the timing registers + */ + tmp = CONFIG_SYS_DA850_DDR2_SDBCR; + tmp &= ~DV_DDR_BOOTUNLOCK; + tmp |= DV_DDR_TIMUNLOCK; + writel(tmp, &dv_ddr2_regs_ctrl->sdbcr); + + /* write memory configuration and timing */ + if (!(CONFIG_SYS_DA850_DDR2_SDBCR & (1 << DV_DDR_SDCR_DDR2EN_SHIFT))) { + /* MOBILE DDR only*/ + writel(CONFIG_SYS_DA850_DDR2_SDBCR2, + &dv_ddr2_regs_ctrl->sdbcr2); + } + writel(CONFIG_SYS_DA850_DDR2_SDTIMR, &dv_ddr2_regs_ctrl->sdtimr); + writel(CONFIG_SYS_DA850_DDR2_SDTIMR2, &dv_ddr2_regs_ctrl->sdtimr2); + + /* clear the TIMUNLOCK bit and write the value of the CL field */ + tmp &= ~DV_DDR_TIMUNLOCK; + writel(tmp, &dv_ddr2_regs_ctrl->sdbcr); + + /* + * LPMODEN and MCLKSTOPEN must be set! + * Without this bits set, PSC don;t switch states !! + */ + writel(CONFIG_SYS_DA850_DDR2_SDRCR | + (1 << DV_DDR_SRCR_LPMODEN_SHIFT) | + (1 << DV_DDR_SRCR_MCLKSTOPEN_SHIFT), + &dv_ddr2_regs_ctrl->sdrcr); + + /* SyncReset the Clock to EMIF3A SDRAM */ + lpsc_syncreset(DAVINCI_LPSC_DDR_EMIF); + /* Enable the Clock to EMIF3A SDRAM */ + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + + /* disable self refresh */ + clrbits_le32(&dv_ddr2_regs_ctrl->sdrcr, + DV_DDR_SDRCR_LPMODEN | DV_DDR_SDRCR_MCLKSTOPEN); + writel(CONFIG_SYS_DA850_DDR2_PBBPR, &dv_ddr2_regs_ctrl->pbbpr); + + return 0; +} +#endif /* CONFIG_SYS_DA850_DDR_INIT */ + +__attribute__((weak)) +void board_gpio_init(void) +{ + return; +} + +int arch_cpu_init(void) +{ + /* Unlock kick registers */ + writel(DV_SYSCFG_KICK0_UNLOCK, &davinci_syscfg_regs->kick0); + writel(DV_SYSCFG_KICK1_UNLOCK, &davinci_syscfg_regs->kick1); + + dv_maskbits(&davinci_syscfg_regs->suspsrc, + CONFIG_SYS_DA850_SYSCFG_SUSPSRC); + + /* configure pinmux settings */ + if (davinci_configure_pin_mux_items(pinmuxes, pinmuxes_size)) + return 1; + +#if defined(CONFIG_SYS_DA850_PLL_INIT) + /* PLL setup */ + da850_pll_init(davinci_pllc0_regs, CONFIG_SYS_DA850_PLL0_PLLM); + da850_pll_init(davinci_pllc1_regs, CONFIG_SYS_DA850_PLL1_PLLM); +#endif + /* setup CSn config */ +#if defined(CONFIG_SYS_DA850_CS2CFG) + writel(CONFIG_SYS_DA850_CS2CFG, &davinci_emif_regs->ab1cr); +#endif +#if defined(CONFIG_SYS_DA850_CS3CFG) + writel(CONFIG_SYS_DA850_CS3CFG, &davinci_emif_regs->ab2cr); +#endif + + da8xx_configure_lpsc_items(lpsc, lpsc_size); + + /* GPIO setup */ + board_gpio_init(); + + + NS16550_init((NS16550_t)(CONFIG_SYS_NS16550_COM1), + CONFIG_SYS_NS16550_CLK / 16 / CONFIG_BAUDRATE); + + /* + * Fix Power and Emulation Management Register + * see sprufw3a.pdf page 37 Table 24 + */ + writel((DAVINCI_UART_PWREMU_MGMT_FREE | DAVINCI_UART_PWREMU_MGMT_URRST | + DAVINCI_UART_PWREMU_MGMT_UTRST), + &davinci_uart2_ctrl_regs->pwremu_mgmt); + +#if defined(CONFIG_SYS_DA850_DDR_INIT) + da850_ddr_setup(); +#endif + + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/davinci/da850_pinmux.c b/arch/arm/cpu/arm926ejs/davinci/da850_pinmux.c new file mode 100644 index 0000000..133265e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/da850_pinmux.c @@ -0,0 +1,187 @@ +/* + * Pinmux configurations for the DA850 SoCs + * + * Copyright (C) 2011 OMICRON electronics GmbH + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <asm/arch/davinci_misc.h> +#include <asm/arch/hardware.h> +#include <asm/arch/pinmux_defs.h> + +/* SPI pin muxer settings */ +const struct pinmux_config spi1_pins_base[] = { + { pinmux(5), 1, 2 }, /* SPI1_CLK */ + { pinmux(5), 1, 4 }, /* SPI1_SOMI */ + { pinmux(5), 1, 5 }, /* SPI1_SIMO */ +}; + +const struct pinmux_config spi1_pins_scs0[] = { + { pinmux(5), 1, 1 }, /* SPI1_SCS[0] */ +}; + +/* UART pin muxer settings */ +const struct pinmux_config uart0_pins_txrx[] = { + { pinmux(3), 2, 4 }, /* UART0_RXD */ + { pinmux(3), 2, 5 }, /* UART0_TXD */ +}; + +const struct pinmux_config uart1_pins_txrx[] = { + { pinmux(4), 2, 6 }, /* UART1_RXD */ + { pinmux(4), 2, 7 }, /* UART1_TXD */ +}; + +const struct pinmux_config uart2_pins_txrx[] = { + { pinmux(4), 2, 4 }, /* UART2_RXD */ + { pinmux(4), 2, 5 }, /* UART2_TXD */ +}; + +const struct pinmux_config uart2_pins_rtscts[] = { + { pinmux(0), 4, 6 }, /* UART2_RTS */ + { pinmux(0), 4, 7 }, /* UART2_CTS */ +}; + +/* EMAC pin muxer settings*/ +const struct pinmux_config emac_pins_rmii[] = { + { pinmux(14), 8, 2 }, /* RMII_TXD[1] */ + { pinmux(14), 8, 3 }, /* RMII_TXD[0] */ + { pinmux(14), 8, 4 }, /* RMII_TXEN */ + { pinmux(14), 8, 5 }, /* RMII_RXD[1] */ + { pinmux(14), 8, 6 }, /* RMII_RXD[0] */ + { pinmux(14), 8, 7 }, /* RMII_RXER */ + { pinmux(15), 8, 1 }, /* RMII_CRS_DV */ +}; + +const struct pinmux_config emac_pins_mii[] = { + { pinmux(2), 8, 1 }, /* MII_TXEN */ + { pinmux(2), 8, 2 }, /* MII_TXCLK */ + { pinmux(2), 8, 3 }, /* MII_COL */ + { pinmux(2), 8, 4 }, /* MII_TXD[3] */ + { pinmux(2), 8, 5 }, /* MII_TXD[2] */ + { pinmux(2), 8, 6 }, /* MII_TXD[1] */ + { pinmux(2), 8, 7 }, /* MII_TXD[0] */ + { pinmux(3), 8, 0 }, /* MII_RXCLK */ + { pinmux(3), 8, 1 }, /* MII_RXDV */ + { pinmux(3), 8, 2 }, /* MII_RXER */ + { pinmux(3), 8, 3 }, /* MII_CRS */ + { pinmux(3), 8, 4 }, /* MII_RXD[3] */ + { pinmux(3), 8, 5 }, /* MII_RXD[2] */ + { pinmux(3), 8, 6 }, /* MII_RXD[1] */ + { pinmux(3), 8, 7 }, /* MII_RXD[0] */ +}; + +const struct pinmux_config emac_pins_mdio[] = { + { pinmux(4), 8, 0 }, /* MDIO_CLK */ + { pinmux(4), 8, 1 }, /* MDIO_D */ +}; + +/* I2C pin muxer settings */ +const struct pinmux_config i2c0_pins[] = { + { pinmux(4), 2, 2 }, /* I2C0_SCL */ + { pinmux(4), 2, 3 }, /* I2C0_SDA */ +}; + +const struct pinmux_config i2c1_pins[] = { + { pinmux(4), 4, 4 }, /* I2C1_SCL */ + { pinmux(4), 4, 5 }, /* I2C1_SDA */ +}; + +/* EMIFA pin muxer settings */ +const struct pinmux_config emifa_pins_cs2[] = { + { pinmux(7), 1, 0 }, /* EMA_CS2 */ +}; + +const struct pinmux_config emifa_pins_cs3[] = { + { pinmux(7), 1, 1 }, /* EMA_CS[3] */ +}; + +const struct pinmux_config emifa_pins_cs4[] = { + { pinmux(7), 1, 2 }, /* EMA_CS[4] */ +}; + +const struct pinmux_config emifa_pins_nand[] = { + { pinmux(7), 1, 4 }, /* EMA_WE */ + { pinmux(7), 1, 5 }, /* EMA_OE */ + { pinmux(9), 1, 0 }, /* EMA_D[7] */ + { pinmux(9), 1, 1 }, /* EMA_D[6] */ + { pinmux(9), 1, 2 }, /* EMA_D[5] */ + { pinmux(9), 1, 3 }, /* EMA_D[4] */ + { pinmux(9), 1, 4 }, /* EMA_D[3] */ + { pinmux(9), 1, 5 }, /* EMA_D[2] */ + { pinmux(9), 1, 6 }, /* EMA_D[1] */ + { pinmux(9), 1, 7 }, /* EMA_D[0] */ + { pinmux(12), 1, 5 }, /* EMA_A[2] */ + { pinmux(12), 1, 6 }, /* EMA_A[1] */ +}; + +/* NOR pin muxer settings */ +const struct pinmux_config emifa_pins_nor[] = { + { pinmux(5), 1, 6 }, /* EMA_BA[1] */ + { pinmux(6), 1, 6 }, /* EMA_WAIT[1] */ + { pinmux(7), 1, 4 }, /* EMA_WE */ + { pinmux(7), 1, 5 }, /* EMA_OE */ + { pinmux(8), 1, 0 }, /* EMA_D[15] */ + { pinmux(8), 1, 1 }, /* EMA_D[14] */ + { pinmux(8), 1, 2 }, /* EMA_D[13] */ + { pinmux(8), 1, 3 }, /* EMA_D[12] */ + { pinmux(8), 1, 4 }, /* EMA_D[11] */ + { pinmux(8), 1, 5 }, /* EMA_D[10] */ + { pinmux(8), 1, 6 }, /* EMA_D[9] */ + { pinmux(8), 1, 7 }, /* EMA_D[8] */ + { pinmux(9), 1, 0 }, /* EMA_D[7] */ + { pinmux(9), 1, 1 }, /* EMA_D[6] */ + { pinmux(9), 1, 2 }, /* EMA_D[5] */ + { pinmux(9), 1, 3 }, /* EMA_D[4] */ + { pinmux(9), 1, 4 }, /* EMA_D[3] */ + { pinmux(9), 1, 5 }, /* EMA_D[2] */ + { pinmux(9), 1, 6 }, /* EMA_D[1] */ + { pinmux(9), 1, 7 }, /* EMA_D[0] */ + { pinmux(10), 1, 1 }, /* EMA_A[22] */ + { pinmux(10), 1, 2 }, /* EMA_A[21] */ + { pinmux(10), 1, 3 }, /* EMA_A[20] */ + { pinmux(10), 1, 4 }, /* EMA_A[19] */ + { pinmux(10), 1, 5 }, /* EMA_A[18] */ + { pinmux(10), 1, 6 }, /* EMA_A[17] */ + { pinmux(10), 1, 7 }, /* EMA_A[16] */ + { pinmux(11), 1, 0 }, /* EMA_A[15] */ + { pinmux(11), 1, 1 }, /* EMA_A[14] */ + { pinmux(11), 1, 2 }, /* EMA_A[13] */ + { pinmux(11), 1, 3 }, /* EMA_A[12] */ + { pinmux(11), 1, 4 }, /* EMA_A[11] */ + { pinmux(11), 1, 5 }, /* EMA_A[10] */ + { pinmux(11), 1, 6 }, /* EMA_A[9] */ + { pinmux(11), 1, 7 }, /* EMA_A[8] */ + { pinmux(12), 1, 0 }, /* EMA_A[7] */ + { pinmux(12), 1, 1 }, /* EMA_A[6] */ + { pinmux(12), 1, 2 }, /* EMA_A[5] */ + { pinmux(12), 1, 3 }, /* EMA_A[4] */ + { pinmux(12), 1, 4 }, /* EMA_A[3] */ + { pinmux(12), 1, 5 }, /* EMA_A[2] */ + { pinmux(12), 1, 6 }, /* EMA_A[1] */ + { pinmux(12), 1, 7 }, /* EMA_A[0] */ +}; + +/* MMC0 pin muxer settings */ +const struct pinmux_config mmc0_pins[] = { + { pinmux(10), 2, 0 }, /* MMCSD0_CLK */ + { pinmux(10), 2, 1 }, /* MMCSD0_CMD */ + { pinmux(10), 2, 2 }, /* MMCSD0_DAT_0 */ + { pinmux(10), 2, 3 }, /* MMCSD0_DAT_1 */ + { pinmux(10), 2, 4 }, /* MMCSD0_DAT_2 */ + { pinmux(10), 2, 5 }, /* MMCSD0_DAT_3 */ + /* DA850 supports only 4-bit mode, remaining pins are not configured */ +}; diff --git a/arch/arm/cpu/arm926ejs/davinci/dm355.c b/arch/arm/cpu/arm926ejs/davinci/dm355.c new file mode 100644 index 0000000..bc45b67 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/dm355.c @@ -0,0 +1,45 @@ +/* + * SoC-specific code for tms320dm355 and similar chips + * + * Copyright (C) 2009 David Brownell + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <asm/arch/hardware.h> + + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_LPSC_UART0); + + /* Bringup UART0 out of reset */ + REG(UART0_PWREMU_MGMT) = 0x00006001; +} + + +#ifdef CONFIG_DRIVER_DAVINCI_I2C +void davinci_enable_i2c(void) +{ + lpsc_on(DAVINCI_LPSC_I2C); + + /* Enable I2C pin Mux */ + REG(PINMUX3) |= (1 << 20) | (1 << 19); +} +#endif diff --git a/arch/arm/cpu/arm926ejs/davinci/dm365.c b/arch/arm/cpu/arm926ejs/davinci/dm365.c new file mode 100644 index 0000000..56c1bc0 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/dm365.c @@ -0,0 +1,35 @@ +/* + * SoC-specific code for tms320dm365 and similar chips + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <asm/arch/hardware.h> + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_LPSC_UART0); +} + +#ifdef CONFIG_DRIVER_DAVINCI_I2C +void davinci_enable_i2c(void) +{ + lpsc_on(DAVINCI_LPSC_I2C); +} +#endif diff --git a/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c b/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c new file mode 100644 index 0000000..c9936fd --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/dm365_lowlevel.c @@ -0,0 +1,474 @@ +/* + * SoC-specific lowlevel code for tms320dm365 and similar chips + * Actually used for booting from NAND with nand_spl. + * + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#include <common.h> +#include <nand.h> +#include <ns16550.h> +#include <post.h> +#include <asm/arch/dm365_lowlevel.h> +#include <asm/arch/hardware.h> + +void dm365_waitloop(unsigned long loopcnt) +{ + unsigned long i; + + for (i = 0; i < loopcnt; i++) + asm(" NOP"); +} + +int dm365_pll1_init(unsigned long pllmult, unsigned long prediv) +{ + unsigned int clksrc = 0x0; + + /* Power up the PLL */ + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLPWRDN); + + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_RES_9); + setbits_le32(&dv_pll0_regs->pllctl, + clksrc << PLLCTL_CLOCK_MODE_SHIFT); + + /* + * Set PLLENSRC '0', PLL Enable(PLLEN) selection is controlled + * through MMR + */ + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLENSRC); + + /* Set PLLEN=0 => PLL BYPASS MODE */ + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLEN); + + dm365_waitloop(150); + + /* PLLRST=1(reset assert) */ + setbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLRST); + + dm365_waitloop(300); + + /*Bring PLL out of Reset*/ + clrbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLRST); + + /* Program the Multiper and Pre-Divider for PLL1 */ + writel(pllmult, &dv_pll0_regs->pllm); + writel(prediv, &dv_pll0_regs->prediv); + + /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 1 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TENABLEDIV | PLLSECCTL_TENABLE | + PLLSECCTL_TINITZ, &dv_pll0_regs->secctl); + /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 0 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TENABLEDIV | PLLSECCTL_TENABLE, + &dv_pll0_regs->secctl); + /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 0 */ + writel(PLLSECCTL_STOPMODE, &dv_pll0_regs->secctl); + /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 1 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TINITZ, &dv_pll0_regs->secctl); + + /* Program the PostDiv for PLL1 */ + writel(PLL_POSTDEN, &dv_pll0_regs->postdiv); + + /* Post divider setting for PLL1 */ + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV1, &dv_pll0_regs->plldiv1); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV2, &dv_pll0_regs->plldiv2); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV3, &dv_pll0_regs->plldiv3); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV4, &dv_pll0_regs->plldiv4); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV5, &dv_pll0_regs->plldiv5); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV6, &dv_pll0_regs->plldiv6); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV7, &dv_pll0_regs->plldiv7); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV8, &dv_pll0_regs->plldiv8); + writel(CONFIG_SYS_DM36x_PLL1_PLLDIV9, &dv_pll0_regs->plldiv9); + + dm365_waitloop(300); + + /* Set the GOSET bit */ + writel(PLLCMD_GOSET, &dv_pll0_regs->pllcmd); /* Go */ + + dm365_waitloop(300); + + /* Wait for PLL to LOCK */ + while (!((readl(&dv_sys_module_regs->pll0_config) & PLL0_LOCK) + == PLL0_LOCK)) + ; + + /* Enable the PLL Bit of PLLCTL*/ + setbits_le32(&dv_pll0_regs->pllctl, PLLCTL_PLLEN); + + return 0; +} + +int dm365_pll2_init(unsigned long pllm, unsigned long prediv) +{ + unsigned int clksrc = 0x0; + + /* Power up the PLL*/ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLPWRDN); + + /* + * Select the Clock Mode as Onchip Oscilator or External Clock on + * MXI pin + * VDB has input on MXI pin + */ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_RES_9); + setbits_le32(&dv_pll1_regs->pllctl, + clksrc << PLLCTL_CLOCK_MODE_SHIFT); + + /* + * Set PLLENSRC '0', PLL Enable(PLLEN) selection is controlled + * through MMR + */ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLENSRC); + + /* Set PLLEN=0 => PLL BYPASS MODE */ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLEN); + + dm365_waitloop(50); + + /* PLLRST=1(reset assert) */ + setbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLRST); + + dm365_waitloop(300); + + /* Bring PLL out of Reset */ + clrbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLRST); + + /* Program the Multiper and Pre-Divider for PLL2 */ + writel(pllm, &dv_pll1_regs->pllm); + writel(prediv, &dv_pll1_regs->prediv); + + writel(PLL_POSTDEN, &dv_pll1_regs->postdiv); + + /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 1 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TENABLEDIV | PLLSECCTL_TENABLE | + PLLSECCTL_TINITZ, &dv_pll1_regs->secctl); + /* Assert TENABLE = 1, TENABLEDIV = 1, TINITZ = 0 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TENABLEDIV | PLLSECCTL_TENABLE, + &dv_pll1_regs->secctl); + /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 0 */ + writel(PLLSECCTL_STOPMODE, &dv_pll1_regs->secctl); + /* Assert TENABLE = 0, TENABLEDIV = 0, TINITZ = 1 */ + writel(PLLSECCTL_STOPMODE | PLLSECCTL_TINITZ, &dv_pll1_regs->secctl); + + /* Post divider setting for PLL2 */ + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV1, &dv_pll1_regs->plldiv1); + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV2, &dv_pll1_regs->plldiv2); + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV3, &dv_pll1_regs->plldiv3); + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV4, &dv_pll1_regs->plldiv4); + writel(CONFIG_SYS_DM36x_PLL2_PLLDIV5, &dv_pll1_regs->plldiv5); + + /* GoCmd for PostDivider to take effect */ + writel(PLLCMD_GOSET, &dv_pll1_regs->pllcmd); + + dm365_waitloop(150); + + /* Wait for PLL to LOCK */ + while (!((readl(&dv_sys_module_regs->pll1_config) & PLL1_LOCK) + == PLL1_LOCK)) + ; + + dm365_waitloop(4100); + + /* Enable the PLL2 */ + setbits_le32(&dv_pll1_regs->pllctl, PLLCTL_PLLEN); + + /* do this after PLL's have been set up */ + writel(CONFIG_SYS_DM36x_PERI_CLK_CTRL, + &dv_sys_module_regs->peri_clkctl); + + return 0; +} + +int dm365_ddr_setup(void) +{ + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + clrbits_le32(&dv_sys_module_regs->vtpiocr, + VPTIO_IOPWRDN | VPTIO_CLRZ | VPTIO_LOCK | VPTIO_PWRDN); + + /* Set bit CLRZ (bit 13) */ + setbits_le32(&dv_sys_module_regs->vtpiocr, VPTIO_CLRZ); + + /* Check VTP READY Status */ + while (!(readl(&dv_sys_module_regs->vtpiocr) & VPTIO_RDY)) + ; + + /* Set bit VTP_IOPWRDWN bit 14 for DDR input buffers) */ + setbits_le32(&dv_sys_module_regs->vtpiocr, VPTIO_IOPWRDN); + + /* Set bit LOCK(bit7) */ + setbits_le32(&dv_sys_module_regs->vtpiocr, VPTIO_LOCK); + + /* + * Powerdown VTP as it is locked (bit 6) + * Set bit VTP_IOPWRDWN bit 14 for DDR input buffers) + */ + setbits_le32(&dv_sys_module_regs->vtpiocr, + VPTIO_IOPWRDN | VPTIO_PWRDN); + + /* Wait for calibration to complete */ + dm365_waitloop(150); + + /* Set the DDR2 to synreset, then enable it again */ + lpsc_syncreset(DAVINCI_LPSC_DDR_EMIF); + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + + writel(CONFIG_SYS_DM36x_DDR2_DDRPHYCR, &dv_ddr2_regs_ctrl->ddrphycr); + + /* Program SDRAM Bank Config Register */ + writel((CONFIG_SYS_DM36x_DDR2_SDBCR | DV_DDR_BOOTUNLOCK), + &dv_ddr2_regs_ctrl->sdbcr); + writel((CONFIG_SYS_DM36x_DDR2_SDBCR | DV_DDR_TIMUNLOCK), + &dv_ddr2_regs_ctrl->sdbcr); + + /* Program SDRAM Timing Control Register1 */ + writel(CONFIG_SYS_DM36x_DDR2_SDTIMR, &dv_ddr2_regs_ctrl->sdtimr); + /* Program SDRAM Timing Control Register2 */ + writel(CONFIG_SYS_DM36x_DDR2_SDTIMR2, &dv_ddr2_regs_ctrl->sdtimr2); + + writel(CONFIG_SYS_DM36x_DDR2_PBBPR, &dv_ddr2_regs_ctrl->pbbpr); + + writel(CONFIG_SYS_DM36x_DDR2_SDBCR, &dv_ddr2_regs_ctrl->sdbcr); + + /* Program SDRAM Refresh Control Register */ + writel(CONFIG_SYS_DM36x_DDR2_SDRCR, &dv_ddr2_regs_ctrl->sdrcr); + + lpsc_syncreset(DAVINCI_LPSC_DDR_EMIF); + lpsc_on(DAVINCI_LPSC_DDR_EMIF); + + return 0; +} + +static void dm365_vpss_sync_reset(void) +{ + unsigned int PdNum = 0; + + /* VPSS_CLKMD 1:1 */ + setbits_le32(&dv_sys_module_regs->vpss_clkctl, + VPSS_CLK_CTL_VPSS_CLKMD); + + /* LPSC SyncReset DDR Clock Enable */ + writel(((readl(&dv_psc_regs->mdctl[DAVINCI_LPSC_VPSSMASTER]) & + ~PSC_MD_STATE_MSK) | PSC_SYNCRESET), + &dv_psc_regs->mdctl[DAVINCI_LPSC_VPSSMASTER]); + + writel((1 << PdNum), &dv_psc_regs->ptcmd); + + while (!(((readl(&dv_psc_regs->ptstat) >> PdNum) & PSC_GOSTAT) == 0)) + ; + while (!((readl(&dv_psc_regs->mdstat[DAVINCI_LPSC_VPSSMASTER]) & + PSC_MD_STATE_MSK) == PSC_SYNCRESET)) + ; +} + +static void dm365_por_reset(void) +{ + struct davinci_timer *wdog = + (struct davinci_timer *)DAVINCI_WDOG_BASE; + + if (readl(&dv_pll0_regs->rstype) & + (PLL_RSTYPE_POR | PLL_RSTYPE_XWRST)) { + dm365_vpss_sync_reset(); + + writel(DV_TMPBUF_VAL, TMPBUF); + setbits_le32(TMPSTATUS, FLAG_PORRST); + writel(DV_WDT_ENABLE_SYS_RESET, &wdog->na1); + writel(DV_WDT_TRIGGER_SYS_RESET, &wdog->na2); + + while (1); + } +} + +static void dm365_wdt_reset(void) +{ + struct davinci_timer *wdog = + (struct davinci_timer *)DAVINCI_WDOG_BASE; + + if (readl(TMPBUF) != DV_TMPBUF_VAL) { + writel(DV_TMPBUF_VAL, TMPBUF); + setbits_le32(TMPSTATUS, FLAG_PORRST); + setbits_le32(TMPSTATUS, FLAG_FLGOFF); + + dm365_waitloop(100); + + dm365_vpss_sync_reset(); + + writel(DV_WDT_ENABLE_SYS_RESET, &wdog->na1); + writel(DV_WDT_TRIGGER_SYS_RESET, &wdog->na2); + + while (1); + } +} + +static void dm365_wdt_flag_on(void) +{ + /* VPSS_CLKMD 1:2 */ + clrbits_le32(&dv_sys_module_regs->vpss_clkctl, + VPSS_CLK_CTL_VPSS_CLKMD); + writel(0, TMPBUF); + setbits_le32(TMPSTATUS, FLAG_FLGON); +} + +void dm365_psc_init(void) +{ + unsigned char i = 0; + unsigned char lpsc_start; + unsigned char lpsc_end, lpscgroup, lpscmin, lpscmax; + unsigned int PdNum = 0; + + lpscmin = 0; + lpscmax = 2; + + for (lpscgroup = lpscmin; lpscgroup <= lpscmax; lpscgroup++) { + if (lpscgroup == 0) { + /* Enabling LPSC 3 to 28 SCR first */ + lpsc_start = DAVINCI_LPSC_VPSSMSTR; + lpsc_end = DAVINCI_LPSC_TIMER1; + } else if (lpscgroup == 1) { /* Skip locked LPSCs [29-37] */ + lpsc_start = DAVINCI_LPSC_CFG5; + lpsc_end = DAVINCI_LPSC_VPSSMASTER; + } else { + lpsc_start = DAVINCI_LPSC_MJCP; + lpsc_end = DAVINCI_LPSC_HDVICP; + } + + /* NEXT=0x3, Enable LPSC's */ + for (i = lpsc_start; i <= lpsc_end; i++) + setbits_le32(&dv_psc_regs->mdctl[i], PSC_ENABLE); + + /* + * Program goctl to start transition sequence for LPSCs + * CSL_PSC_0_REGS->PTCMD = (1<<PdNum); Kick off Power + * Domain 0 Modules + */ + writel((1 << PdNum), &dv_psc_regs->ptcmd); + + /* + * Wait for GOSTAT = NO TRANSITION from PSC for Powerdomain 0 + */ + while (!(((readl(&dv_psc_regs->ptstat) >> PdNum) & PSC_GOSTAT) + == 0)) + ; + + /* Wait for MODSTAT = ENABLE from LPSC's */ + for (i = lpsc_start; i <= lpsc_end; i++) + while (!((readl(&dv_psc_regs->mdstat[i]) & + PSC_MD_STATE_MSK) == PSC_ENABLE)) + ; + } +} + +static void dm365_emif_init(void) +{ + writel(CONFIG_SYS_DM36x_AWCCR, &davinci_emif_regs->awccr); + writel(CONFIG_SYS_DM36x_AB1CR, &davinci_emif_regs->ab1cr); + + setbits_le32(&davinci_emif_regs->nandfcr, DAVINCI_NANDFCR_CS2NAND); + + writel(CONFIG_SYS_DM36x_AB2CR, &davinci_emif_regs->ab2cr); + + return; +} + +void dm365_pinmux_ctl(unsigned long offset, unsigned long mask, + unsigned long value) +{ + clrbits_le32(&dv_sys_module_regs->pinmux[offset], mask); + setbits_le32(&dv_sys_module_regs->pinmux[offset], (mask & value)); +} + +__attribute__((weak)) +void board_gpio_init(void) +{ + return; +} + +#if defined(CONFIG_POST) +int post_log(char *format, ...) +{ + return 0; +} +#endif + +void dm36x_lowlevel_init(ulong bootflag) +{ + struct davinci_uart_ctrl_regs *davinci_uart_ctrl_regs = + (struct davinci_uart_ctrl_regs *)(CONFIG_SYS_NS16550_COM1 + + DAVINCI_UART_CTRL_BASE); + + /* Mask all interrupts */ + writel(DV_AINTC_INTCTL_IDMODE, &dv_aintc_regs->intctl); + writel(0x0, &dv_aintc_regs->eabase); + writel(0x0, &dv_aintc_regs->eint0); + writel(0x0, &dv_aintc_regs->eint1); + + /* Clear all interrupts */ + writel(0xffffffff, &dv_aintc_regs->fiq0); + writel(0xffffffff, &dv_aintc_regs->fiq1); + writel(0xffffffff, &dv_aintc_regs->irq0); + writel(0xffffffff, &dv_aintc_regs->irq1); + + dm365_por_reset(); + dm365_wdt_reset(); + + /* System PSC setup - enable all */ + dm365_psc_init(); + + /* Setup Pinmux */ + dm365_pinmux_ctl(0, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX0); + dm365_pinmux_ctl(1, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX1); + dm365_pinmux_ctl(2, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX2); + dm365_pinmux_ctl(3, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX3); + dm365_pinmux_ctl(4, 0xFFFFFFFF, CONFIG_SYS_DM36x_PINMUX4); + + /* PLL setup */ + dm365_pll1_init(CONFIG_SYS_DM36x_PLL1_PLLM, + CONFIG_SYS_DM36x_PLL1_PREDIV); + dm365_pll2_init(CONFIG_SYS_DM36x_PLL2_PLLM, + CONFIG_SYS_DM36x_PLL2_PREDIV); + + /* GPIO setup */ + board_gpio_init(); + + NS16550_init((NS16550_t)(CONFIG_SYS_NS16550_COM1), + CONFIG_SYS_NS16550_CLK / 16 / CONFIG_BAUDRATE); + + /* + * Fix Power and Emulation Management Register + * see sprufh2.pdf page 38 Table 22 + */ + writel((DAVINCI_UART_PWREMU_MGMT_FREE | DAVINCI_UART_PWREMU_MGMT_URRST | + DAVINCI_UART_PWREMU_MGMT_UTRST), + &davinci_uart_ctrl_regs->pwremu_mgmt); + + puts("ddr init\n"); + dm365_ddr_setup(); + + puts("emif init\n"); + dm365_emif_init(); + + dm365_wdt_flag_on(); + +#if defined(CONFIG_POST) + /* + * Do memory tests, calls arch_memory_failure_handle() + * if error detected. + */ + memory_post_test(0); +#endif +} diff --git a/arch/arm/cpu/arm926ejs/davinci/dm644x.c b/arch/arm/cpu/arm926ejs/davinci/dm644x.c new file mode 100644 index 0000000..bb105b5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/dm644x.c @@ -0,0 +1,96 @@ +/* + * SoC-specific code for tms320dm644x chips + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2008 Lyrtech <www.lyrtech.com> + * Copyright (C) 2004 Texas Instruments. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <asm/arch/hardware.h> + + +#define PINMUX0_EMACEN (1 << 31) +#define PINMUX0_AECS5 (1 << 11) +#define PINMUX0_AECS4 (1 << 10) + +#define PINMUX1_I2C (1 << 7) +#define PINMUX1_UART1 (1 << 1) +#define PINMUX1_UART0 (1 << 0) + + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_LPSC_UART0); + + /* Bringup UART0 out of reset */ + REG(UART0_PWREMU_MGMT) = 0x00006001; + + /* Enable UART0 MUX lines */ + REG(PINMUX1) |= PINMUX1_UART0; +} + +#ifdef CONFIG_DRIVER_TI_EMAC +void davinci_enable_emac(void) +{ + lpsc_on(DAVINCI_LPSC_EMAC); + lpsc_on(DAVINCI_LPSC_EMAC_WRAPPER); + lpsc_on(DAVINCI_LPSC_MDIO); + + /* Enable GIO3.3V cells used for EMAC */ + REG(VDD3P3V_PWDN) = 0; + + /* Enable EMAC. */ + REG(PINMUX0) |= PINMUX0_EMACEN; +} +#endif + +#ifdef CONFIG_DRIVER_DAVINCI_I2C +void davinci_enable_i2c(void) +{ + lpsc_on(DAVINCI_LPSC_I2C); + + /* Enable I2C pin Mux */ + REG(PINMUX1) |= PINMUX1_I2C; +} +#endif + +void davinci_errata_workarounds(void) +{ + /* + * Workaround for TMS320DM6446 errata 1.3.22: + * PSC: PTSTAT Register Does Not Clear After Warm/Maximum Reset + * Revision(s) Affected: 1.3 and earlier + */ + REG(PSC_SILVER_BULLET) = 0; + + /* + * Set the PR_OLD_COUNT bits in the Bus Burst Priority Register (PBBPR) + * as suggested in TMS320DM6446 errata 2.1.2: + * + * On DM6446 Silicon Revision 2.1 and earlier, under certain conditions + * low priority modules can occupy the bus and prevent high priority + * modules like the VPSS from getting the required DDR2 throughput. + * A hex value of 0x20 should provide a good ARM (cache enabled) + * performance and still allow good utilization by the VPSS or other + * modules. + */ + REG(VBPR) = 0x20; +} diff --git a/arch/arm/cpu/arm926ejs/davinci/dm646x.c b/arch/arm/cpu/arm926ejs/davinci/dm646x.c new file mode 100644 index 0000000..329825f --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/dm646x.c @@ -0,0 +1,41 @@ +/* + * SoC-specific code for TMS320DM646x chips + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <asm/arch/hardware.h> + +void davinci_enable_uart0(void) +{ + lpsc_on(DAVINCI_DM646X_LPSC_UART0); +} + +#ifdef CONFIG_DRIVER_TI_EMAC +void davinci_enable_emac(void) +{ + lpsc_on(DAVINCI_DM646X_LPSC_EMAC); +} +#endif + +#ifdef CONFIG_DRIVER_DAVINCI_I2C +void davinci_enable_i2c(void) +{ + lpsc_on(DAVINCI_DM646X_LPSC_I2C); +} +#endif diff --git a/arch/arm/cpu/arm926ejs/davinci/dp83848.c b/arch/arm/cpu/arm926ejs/davinci/dp83848.c new file mode 100644 index 0000000..d435e4b --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/dp83848.c @@ -0,0 +1,144 @@ +/* + * National Semiconductor DP83848 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.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 <net.h> +#include <dp83848.h> +#include <asm/arch/emac_defs.h> +#include "../../../../../drivers/net/davinci_emac.h" + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +int dp83848_is_phy_connected(int phy_addr) +{ + u_int16_t id1, id2; + + if (!davinci_eth_phy_read(phy_addr, DP83848_PHYID1_REG, &id1)) + return(0); + if (!davinci_eth_phy_read(phy_addr, DP83848_PHYID2_REG, &id2)) + return(0); + + if ((id1 == DP83848_PHYID1_OUI) && (id2 == DP83848_PHYID2_OUI)) + return(1); + + return(0); +} + +int dp83848_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR; + + if (!davinci_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp)) + return(0); + + if (!(tmp & DP83848_LINK_STATUS)) /* link up? */ + return(0); + + if (!davinci_eth_phy_read(phy_addr, DP83848_PHY_STAT_REG, &tmp)) + return(0); + + /* Speed doesn't matter, there is no setting for it in EMAC... */ + if (tmp & DP83848_DUPLEX) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); +} + + +int dp83848_init_phy(int phy_addr) +{ + int ret = 1; + + if (!dp83848_get_link_speed(phy_addr)) { + /* Try another time */ + udelay(100000); + ret = dp83848_get_link_speed(phy_addr); + } + + /* Disable PHY Interrupts */ + davinci_eth_phy_write(phy_addr, DP83848_PHY_INTR_CTRL_REG, 0); + + return(ret); +} + + +int dp83848_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + + if (!davinci_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp &= ~DP83848_AUTONEG; /* remove autonegotiation enable */ + tmp |= DP83848_ISOLATE; /* Electrically isolate PHY */ + davinci_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /* Set the Auto_negotiation Advertisement Register + * MII advertising for Next page, 100BaseTxFD and HD, + * 10BaseTFD and HD, IEEE 802.3 + */ + tmp = DP83848_NP | DP83848_TX_FDX | DP83848_TX_HDX | + DP83848_10_FDX | DP83848_10_HDX | DP83848_AN_IEEE_802_3; + davinci_eth_phy_write(phy_addr, DP83848_ANA_REG, tmp); + + + /* Read Control Register */ + if (!davinci_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp)) + return(0); + + tmp |= DP83848_SPEED_SELECT | DP83848_AUTONEG | DP83848_DUPLEX_MODE; + davinci_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /* Restart Auto_negotiation */ + tmp |= DP83848_RESTART_AUTONEG; + davinci_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /*check AutoNegotiate complete */ + udelay(10000); + if (!davinci_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp)) + return(0); + + if (!(tmp & DP83848_AUTONEG_COMP)) + return(0); + + return (dp83848_get_link_speed(phy_addr)); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/arch/arm/cpu/arm926ejs/davinci/et1011c.c b/arch/arm/cpu/arm926ejs/davinci/et1011c.c new file mode 100644 index 0000000..68650e5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/et1011c.c @@ -0,0 +1,54 @@ +/* + * LSI ET1011C PHY Driver for TI DaVinci(TMS320DM6467) board. + * + * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/ + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <net.h> +#include <miiphy.h> +#include <asm/arch/emac_defs.h> +#include "../../../../../drivers/net/davinci_emac.h" + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +/* LSI PHYSICAL LAYER TRANSCEIVER ET1011C */ + +#define MII_PHY_CONFIG_REG 22 + +/* PHY Config bits */ +#define PHY_SYS_CLK_EN (1 << 4) + +int et1011c_get_link_speed(int phy_addr) +{ + u_int16_t data; + + if (davinci_eth_phy_read(phy_addr, MII_STATUS_REG, &data) && (data & 0x04)) { + davinci_eth_phy_read(phy_addr, MII_PHY_CONFIG_REG, &data); + /* Enable 125MHz clock sourced from PHY */ + davinci_eth_phy_write(phy_addr, MII_PHY_CONFIG_REG, + data | PHY_SYS_CLK_EN); + return (1); + } + return (0); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/arch/arm/cpu/arm926ejs/davinci/ksz8873.c b/arch/arm/cpu/arm926ejs/davinci/ksz8873.c new file mode 100644 index 0000000..3546e7f --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/ksz8873.c @@ -0,0 +1,69 @@ +/* + * Micrel KSZ8873 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2011 Heiko Schocher <hsdenx.de> + * + * based on: + * National Semiconductor DP83848 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.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 <miiphy.h> +#include <net.h> +#include <asm/arch/emac_defs.h> +#include <asm/io.h> +#include "../../../../../drivers/net/davinci_emac.h" + +int ksz8873_is_phy_connected(int phy_addr) +{ + u_int16_t dummy; + + return davinci_eth_phy_read(phy_addr, MII_PHYSID1, &dummy); +} + +int ksz8873_get_link_speed(int phy_addr) +{ + emac_regs *emac = (emac_regs *)EMAC_BASE_ADDR; + + /* we always have a link to the switch, 100 FD */ + writel((EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE), + &emac->MACCONTROL); + return 1; +} + + +int ksz8873_init_phy(int phy_addr) +{ + return 1; +} + + +int ksz8873_auto_negotiate(int phy_addr) +{ + return dp83848_get_link_speed(phy_addr); +} diff --git a/arch/arm/cpu/arm926ejs/davinci/lowlevel_init.S b/arch/arm/cpu/arm926ejs/davinci/lowlevel_init.S new file mode 100644 index 0000000..0e45426 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/lowlevel_init.S @@ -0,0 +1,712 @@ +/* + * Low-level board setup code for TI DaVinci SoC based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Partially based on TI sources, original copyrights follow: + */ + +/* + * Board specific setup info + * + * (C) Copyright 2003 + * Texas Instruments, <www.ti.com> + * Kshitij Gupta <Kshitij@ti.com> + * + * Modified for OMAP 1610 H2 board by Nishant Kamat, Jan 2004 + * + * Modified for OMAP 5912 OSK board by Rishi Bhattacharya, Apr 2004 + * See file CREDITS for list of people who contributed to this + * project. + * + * Modified for DV-EVM board by Rishi Bhattacharya, Apr 2005 + * See file CREDITS for list of people who contributed to this + * project. + * + * Modified for DV-EVM board by Swaminathan S, Nov 2005 + * 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> + +#define MDSTAT_STATE 0x3f + +.globl lowlevel_init +lowlevel_init: +#ifdef CONFIG_SOC_DM644X + + /*-------------------------------------------------------* + * Mask all IRQs by setting all bits in the EINT default * + *-------------------------------------------------------*/ + mov r1, $0 + ldr r0, =EINT_ENABLE0 + str r1, [r0] + ldr r0, =EINT_ENABLE1 + str r1, [r0] + + /*------------------------------------------------------* + * Put the GEM in reset * + *------------------------------------------------------*/ + + /* Put the GEM in reset */ + ldr r8, PSC_GEM_FLAG_CLEAR + ldr r6, MDCTL_GEM + ldr r7, [r6] + and r7, r7, r8 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x02 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStopGem: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x02 + bne checkStatClkStopGem + + /* Check for GEM Reset Completion */ +checkGemStatClkStop: + ldr r6, MDSTAT_GEM + ldr r7, [r6] + ands r7, r7, $0x100 + bne checkGemStatClkStop + + /* Do this for enabling a WDT initiated reset this is a workaround + for a chip bug. Not required under normal situations */ + ldr r6, P1394 + mov r10, $0 + str r10, [r6] + + /*------------------------------------------------------* + * Enable L1 & L2 Memories in Fast mode * + *------------------------------------------------------*/ + ldr r6, DFT_ENABLE + mov r10, $0x01 + str r10, [r6] + + ldr r6, MMARG_BRF0 + ldr r10, MMARG_BRF0_VAL + str r10, [r6] + + ldr r6, DFT_ENABLE + mov r10, $0 + str r10, [r6] + + /*------------------------------------------------------* + * DDR2 PLL Initialization * + *------------------------------------------------------*/ + + /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */ + mov r10, $0 + ldr r6, PLL2_CTL + ldr r7, PLL_CLKSRC_MASK + ldr r8, [r6] + and r8, r8, r7 + mov r9, r10, lsl $8 + orr r8, r8, r9 + str r8, [r6] + + /* Select the PLLEN source */ + ldr r7, PLL_ENSRC_MASK + and r8, r8, r7 + str r8, [r6] + + /* Bypass the PLL */ + ldr r7, PLL_BYPASS_MASK + and r8, r8, r7 + str r8, [r6] + + /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */ + mov r10, $0x20 +WaitPPL2Loop: + subs r10, r10, $1 + bne WaitPPL2Loop + + /* Reset the PLL */ + ldr r7, PLL_RESET_MASK + and r8, r8, r7 + str r8, [r6] + + /* Power up the PLL */ + ldr r7, PLL_PWRUP_MASK + and r8, r8, r7 + str r8, [r6] + + /* Enable the PLL from Disable Mode */ + ldr r7, PLL_DISABLE_ENABLE_MASK + and r8, r8, r7 + str r8, [r6] + + /* Program the PLL Multiplier */ + ldr r6, PLL2_PLLM + mov r2, $0x17 /* 162 MHz */ + str r2, [r6] + + /* Program the PLL2 Divisor Value */ + ldr r6, PLL2_DIV2 + mov r3, $0x01 + str r3, [r6] + + /* Program the PLL2 Divisor Value */ + ldr r6, PLL2_DIV1 + mov r4, $0x0b /* 54 MHz */ + str r4, [r6] + + /* PLL2 DIV2 MMR */ + ldr r8, PLL2_DIV_MASK + ldr r6, PLL2_DIV2 + ldr r9, [r6] + and r8, r8, r9 + mov r9, $0x01 + mov r9, r9, lsl $15 + orr r8, r8, r9 + str r8, [r6] + + /* Program the GOSET bit to take new divider values */ + ldr r6, PLL2_PLLCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Wait for Done */ + ldr r6, PLL2_PLLSTAT +doneLoop_0: + ldr r7, [r6] + ands r7, r7, $0x01 + bne doneLoop_0 + + /* PLL2 DIV1 MMR */ + ldr r8, PLL2_DIV_MASK + ldr r6, PLL2_DIV1 + ldr r9, [r6] + and r8, r8, r9 + mov r9, $0x01 + mov r9, r9, lsl $15 + orr r8, r8, r9 + str r8, [r6] + + /* Program the GOSET bit to take new divider values */ + ldr r6, PLL2_PLLCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Wait for Done */ + ldr r6, PLL2_PLLSTAT +doneLoop: + ldr r7, [r6] + ands r7, r7, $0x01 + bne doneLoop + + /* Wait for PLL to Reset Properly */ + mov r10, $0x218 +ResetPPL2Loop: + subs r10, r10, $1 + bne ResetPPL2Loop + + /* Bring PLL out of Reset */ + ldr r6, PLL2_CTL + ldr r8, [r6] + orr r8, r8, $0x08 + str r8, [r6] + + /* Wait for PLL to Lock */ + ldr r10, PLL_LOCK_COUNT +PLL2Lock: + subs r10, r10, $1 + bne PLL2Lock + + /* Enable the PLL */ + ldr r6, PLL2_CTL + ldr r8, [r6] + orr r8, r8, $0x01 + str r8, [r6] + + /*------------------------------------------------------* + * Issue Soft Reset to DDR Module * + *------------------------------------------------------*/ + + /* Shut down the DDR2 LPSC Module */ + ldr r8, PSC_FLAG_CLEAR + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + and r7, r7, r8 + orr r7, r7, $0x03 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStop: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkStop + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkStop: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $MDSTAT_STATE + cmp r7, $0x03 + bne checkDDRStatClkStop + + /*------------------------------------------------------* + * Program DDR2 MMRs for 162MHz Setting * + *------------------------------------------------------*/ + + /* Program PHY Control Register */ + ldr r6, DDRCTL + ldr r7, DDRCTL_VAL + str r7, [r6] + + /* Program SDRAM Bank Config Register */ + ldr r6, SDCFG + ldr r7, SDCFG_VAL + str r7, [r6] + + /* Program SDRAM TIM-0 Config Register */ + ldr r6, SDTIM0 + ldr r7, SDTIM0_VAL_162MHz + str r7, [r6] + + /* Program SDRAM TIM-1 Config Register */ + ldr r6, SDTIM1 + ldr r7, SDTIM1_VAL_162MHz + str r7, [r6] + + /* Program the SDRAM Bank Config Control Register */ + ldr r10, MASK_VAL + ldr r8, SDCFG + ldr r9, SDCFG_VAL + and r9, r9, r10 + str r9, [r8] + + /* Program SDRAM SDREF Config Register */ + ldr r6, SDREF + ldr r7, SDREF_VAL + str r7, [r6] + + /*------------------------------------------------------* + * Issue Soft Reset to DDR Module * + *------------------------------------------------------*/ + + /* Issue a Dummy DDR2 read/write */ + ldr r8, DDR2_START_ADDR + ldr r7, DUMMY_VAL + str r7, [r8] + ldr r7, [r8] + + /* Shut down the DDR2 LPSC Module */ + ldr r8, PSC_FLAG_CLEAR + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + and r7, r7, r8 + orr r7, r7, $0x01 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStop2: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkStop2 + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkStop2: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $MDSTAT_STATE + cmp r7, $0x01 + bne checkDDRStatClkStop2 + + /*------------------------------------------------------* + * Turn DDR2 Controller Clocks On * + *------------------------------------------------------*/ + + /* Enable the DDR2 LPSC Module */ + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + orr r7, r7, $0x03 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkEn2: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkEn2 + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkEn2: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $MDSTAT_STATE + cmp r7, $0x03 + bne checkDDRStatClkEn2 + + /* DDR Writes and Reads */ + ldr r6, CFGTEST + mov r3, $0x01 + str r3, [r6] + + /*------------------------------------------------------* + * System PLL Initialization * + *------------------------------------------------------*/ + + /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */ + mov r2, $0 + ldr r6, PLL1_CTL + ldr r7, PLL_CLKSRC_MASK + ldr r8, [r6] + and r8, r8, r7 + mov r9, r2, lsl $8 + orr r8, r8, r9 + str r8, [r6] + + /* Select the PLLEN source */ + ldr r7, PLL_ENSRC_MASK + and r8, r8, r7 + str r8, [r6] + + /* Bypass the PLL */ + ldr r7, PLL_BYPASS_MASK + and r8, r8, r7 + str r8, [r6] + + /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */ + mov r10, $0x20 + +WaitLoop: + subs r10, r10, $1 + bne WaitLoop + + /* Reset the PLL */ + ldr r7, PLL_RESET_MASK + and r8, r8, r7 + str r8, [r6] + + /* Disable the PLL */ + orr r8, r8, $0x10 + str r8, [r6] + + /* Power up the PLL */ + ldr r7, PLL_PWRUP_MASK + and r8, r8, r7 + str r8, [r6] + + /* Enable the PLL from Disable Mode */ + ldr r7, PLL_DISABLE_ENABLE_MASK + and r8, r8, r7 + str r8, [r6] + + /* Program the PLL Multiplier */ + ldr r6, PLL1_PLLM + mov r3, $0x15 /* For 594MHz */ + str r3, [r6] + + /* Wait for PLL to Reset Properly */ + mov r10, $0xff + +ResetLoop: + subs r10, r10, $1 + bne ResetLoop + + /* Bring PLL out of Reset */ + ldr r6, PLL1_CTL + orr r8, r8, $0x08 + str r8, [r6] + + /* Wait for PLL to Lock */ + ldr r10, PLL_LOCK_COUNT + +PLL1Lock: + subs r10, r10, $1 + bne PLL1Lock + + /* Enable the PLL */ + orr r8, r8, $0x01 + str r8, [r6] + + nop + nop + nop + nop + + /*------------------------------------------------------* + * AEMIF configuration for NOR Flash (double check) * + *------------------------------------------------------*/ + ldr r0, _PINMUX0 + ldr r1, _DEV_SETTING + str r1, [r0] + + ldr r0, WAITCFG + ldr r1, WAITCFG_VAL + ldr r2, [r0] + orr r2, r2, r1 + str r2, [r0] + + ldr r0, ACFG3 + ldr r1, ACFG3_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + ldr r0, ACFG4 + ldr r1, ACFG4_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + ldr r0, ACFG5 + ldr r1, ACFG5_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + /*--------------------------------------* + * VTP manual Calibration * + *--------------------------------------*/ + ldr r0, VTPIOCR + ldr r1, VTP_MMR0 + str r1, [r0] + + ldr r0, VTPIOCR + ldr r1, VTP_MMR1 + str r1, [r0] + + /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */ + ldr r10, VTP_LOCK_COUNT +VTPLock: + subs r10, r10, $1 + bne VTPLock + + ldr r6, DFT_ENABLE + mov r10, $0x01 + str r10, [r6] + + ldr r6, DDRVTPR + ldr r7, [r6] + mov r8, r7, LSL #32-10 + mov r8, r8, LSR #32-10 /* grab low 10 bits */ + ldr r7, VTP_RECAL + orr r8, r7, r8 + ldr r7, VTP_EN + orr r8, r7, r8 + str r8, [r0] + + + /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */ + ldr r10, VTP_LOCK_COUNT +VTP1Lock: + subs r10, r10, $1 + bne VTP1Lock + + ldr r1, [r0] + ldr r2, VTP_MASK + and r2, r1, r2 + str r2, [r0] + + ldr r6, DFT_ENABLE + mov r10, $0 + str r10, [r6] + + /* + * Call board-specific lowlevel init. + * That MUST be present and THAT returns + * back to arch calling code with "mov pc, lr." + */ + b dv_board_init + +.ltorg + +_PINMUX0: + .word 0x01c40000 /* Device Configuration Registers */ +_PINMUX1: + .word 0x01c40004 /* Device Configuration Registers */ + +_DEV_SETTING: + .word 0x00000c1f + +WAITCFG: + .word 0x01e00004 +WAITCFG_VAL: + .word 0 +ACFG3: + .word 0x01e00014 +ACFG3_VAL: + .word 0x3ffffffd +ACFG4: + .word 0x01e00018 +ACFG4_VAL: + .word 0x3ffffffd +ACFG5: + .word 0x01e0001c +ACFG5_VAL: + .word 0x3ffffffd + +MDCTL_DDR2: + .word 0x01c41a34 +MDSTAT_DDR2: + .word 0x01c41834 + +PTCMD: + .word 0x01c41120 +PTSTAT: + .word 0x01c41128 + +EINT_ENABLE0: + .word 0x01c48018 +EINT_ENABLE1: + .word 0x01c4801c + +PSC_FLAG_CLEAR: + .word 0xffffffe0 +PSC_GEM_FLAG_CLEAR: + .word 0xfffffeff + +/* DDR2 MMR & CONFIGURATION VALUES, 162 MHZ clock */ +DDRCTL: + .word 0x200000e4 +DDRCTL_VAL: + .word 0x50006405 +SDREF: + .word 0x2000000c +SDREF_VAL: + .word 0x000005c3 +SDCFG: + .word 0x20000008 +SDCFG_VAL: +#ifdef DDR_4BANKS + .word 0x00178622 +#elif defined DDR_8BANKS + .word 0x00178632 +#else +#error "Unknown DDR configuration!!!" +#endif +SDTIM0: + .word 0x20000010 +SDTIM0_VAL_162MHz: + .word 0x28923211 +SDTIM1: + .word 0x20000014 +SDTIM1_VAL_162MHz: + .word 0x0016c722 +VTPIOCR: + .word 0x200000f0 /* VTP IO Control register */ +DDRVTPR: + .word 0x01c42030 /* DDR VPTR MMR */ +VTP_MMR0: + .word 0x201f +VTP_MMR1: + .word 0xa01f +DFT_ENABLE: + .word 0x01c4004c +VTP_LOCK_COUNT: + .word 0x5b0 +VTP_MASK: + .word 0xffffdfff +VTP_RECAL: + .word 0x08000 +VTP_EN: + .word 0x02000 +CFGTEST: + .word 0x80010000 +MASK_VAL: + .word 0x00000fff + +/* GEM Power Up & LPSC Control Register */ +MDCTL_GEM: + .word 0x01c41a9c +MDSTAT_GEM: + .word 0x01c4189c + +/* For WDT reset chip bug */ +P1394: + .word 0x01c41a20 + +PLL_CLKSRC_MASK: + .word 0xfffffeff /* Mask the Clock Mode bit */ +PLL_ENSRC_MASK: + .word 0xffffffdf /* Select the PLLEN source */ +PLL_BYPASS_MASK: + .word 0xfffffffe /* Put the PLL in BYPASS */ +PLL_RESET_MASK: + .word 0xfffffff7 /* Put the PLL in Reset Mode */ +PLL_PWRUP_MASK: + .word 0xfffffffd /* PLL Power up Mask Bit */ +PLL_DISABLE_ENABLE_MASK: + .word 0xffffffef /* Enable the PLL from Disable */ +PLL_LOCK_COUNT: + .word 0x2000 + +/* PLL1-SYSTEM PLL MMRs */ +PLL1_CTL: + .word 0x01c40900 +PLL1_PLLM: + .word 0x01c40910 + +/* PLL2-SYSTEM PLL MMRs */ +PLL2_CTL: + .word 0x01c40d00 +PLL2_PLLM: + .word 0x01c40d10 +PLL2_DIV1: + .word 0x01c40d18 +PLL2_DIV2: + .word 0x01c40d1c +PLL2_PLLCMD: + .word 0x01c40d38 +PLL2_PLLSTAT: + .word 0x01c40d3c +PLL2_DIV_MASK: + .word 0xffff7fff + +MMARG_BRF0: + .word 0x01c42010 /* BRF margin mode 0 (R/W)*/ +MMARG_BRF0_VAL: + .word 0x00444400 + +DDR2_START_ADDR: + .word 0x80000000 +DUMMY_VAL: + .word 0xa55aa55a +#else /* CONFIG_SOC_DM644X */ + mov pc, lr +#endif diff --git a/arch/arm/cpu/arm926ejs/davinci/lxt972.c b/arch/arm/cpu/arm926ejs/davinci/lxt972.c new file mode 100644 index 0000000..cce1fe4 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/lxt972.c @@ -0,0 +1,129 @@ +/* + * Intel LXT971/LXT972 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.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 <net.h> +#include <miiphy.h> +#include <lxt971a.h> +#include <asm/arch/emac_defs.h> +#include "../../../../../drivers/net/davinci_emac.h" + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +int lxt972_is_phy_connected(int phy_addr) +{ + u_int16_t id1, id2; + + if (!davinci_eth_phy_read(phy_addr, MII_PHYSID1, &id1)) + return(0); + if (!davinci_eth_phy_read(phy_addr, MII_PHYSID2, &id2)) + return(0); + + if ((id1 == (0x0013)) && ((id2 & 0xfff0) == 0x78e0)) + return(1); + + return(0); +} + +int lxt972_get_link_speed(int phy_addr) +{ + u_int16_t stat1, tmp; + volatile emac_regs *emac = (emac_regs *)EMAC_BASE_ADDR; + + if (!davinci_eth_phy_read(phy_addr, PHY_LXT971_STAT2, &stat1)) + return(0); + + if (!(stat1 & PHY_LXT971_STAT2_LINK)) /* link up? */ + return(0); + + if (!davinci_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp)) + return(0); + + tmp |= PHY_LXT971_DIG_CFG_MII_DRIVE; + + davinci_eth_phy_write(phy_addr, PHY_LXT971_DIG_CFG, tmp); + /* Read back */ + if (!davinci_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp)) + return(0); + + /* Speed doesn't matter, there is no setting for it in EMAC... */ + if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | + EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); +} + + +int lxt972_init_phy(int phy_addr) +{ + int ret = 1; + + if (!lxt972_get_link_speed(phy_addr)) { + /* Try another time */ + ret = lxt972_get_link_speed(phy_addr); + } + + /* Disable PHY Interrupts */ + davinci_eth_phy_write(phy_addr, PHY_LXT971_INT_ENABLE, 0); + + return(ret); +} + + +int lxt972_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + if (!davinci_eth_phy_read(phy_addr, MII_BMCR, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp |= BMCR_ANRESTART; + davinci_eth_phy_write(phy_addr, MII_BMCR, tmp); + + /*check AutoNegotiate complete */ + udelay (10000); + if (!davinci_eth_phy_read(phy_addr, MII_BMSR, &tmp)) + return(0); + + if (!(tmp & BMSR_ANEGCOMPLETE)) + return(0); + + return (lxt972_get_link_speed(phy_addr)); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/arch/arm/cpu/arm926ejs/davinci/misc.c b/arch/arm/cpu/arm926ejs/davinci/misc.c new file mode 100644 index 0000000..162c1e0 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/misc.c @@ -0,0 +1,153 @@ +/* + * Miscelaneous DaVinci functions. + * + * Copyright (C) 2009 Nick Thompson, GE Fanuc Ltd, <nick.thompson@gefanuc.com> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2008 Lyrtech <www.lyrtech.com> + * Copyright (C) 2004 Texas Instruments. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <i2c.h> +#include <net.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> +#include <asm/arch/davinci_misc.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_SPL_BUILD +int dram_init(void) +{ + /* dram_init must store complete ramsize in gd->ram_size */ + gd->ram_size = get_ram_size( + (void *)CONFIG_SYS_SDRAM_BASE, + CONFIG_MAX_RAM_BANK_SIZE); + return 0; +} + +void dram_init_banksize(void) +{ + gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE; + gd->bd->bi_dram[0].size = gd->ram_size; +} +#endif + +#ifdef CONFIG_DRIVER_TI_EMAC +/* + * Read ethernet MAC address from EEPROM for DVEVM compatible boards. + * Returns 1 if found, 0 otherwise. + */ +int dvevm_read_mac_address(uint8_t *buf) +{ +#ifdef CONFIG_SYS_I2C_EEPROM_ADDR + /* Read MAC address. */ + if (i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, 0x7F00, + CONFIG_SYS_I2C_EEPROM_ADDR_LEN, (uint8_t *) &buf[0], 6)) + goto i2cerr; + + /* Check that MAC address is valid. */ + if (!is_valid_ether_addr(buf)) + goto err; + + return 1; /* Found */ + +i2cerr: + printf("Read from EEPROM @ 0x%02x failed\n", + CONFIG_SYS_I2C_EEPROM_ADDR); +err: +#endif /* CONFIG_SYS_I2C_EEPROM_ADDR */ + + return 0; +} + +/* + * Set the mii mode as MII or RMII + */ +#if defined(CONFIG_SOC_DA8XX) +void davinci_emac_mii_mode_sel(int mode_sel) +{ + int val; + + val = readl(&davinci_syscfg_regs->cfgchip3); + if (mode_sel == 0) + val &= ~(1 << 8); + else + val |= (1 << 8); + writel(val, &davinci_syscfg_regs->cfgchip3); +} +#endif +/* + * If there is no MAC address in the environment, then it will be initialized + * (silently) from the value in the EEPROM. + */ +void davinci_sync_env_enetaddr(uint8_t *rom_enetaddr) +{ + uint8_t env_enetaddr[6]; + int ret; + + ret = eth_getenv_enetaddr_by_index("eth", 0, env_enetaddr); + if (!ret) { + /* + * There is no MAC address in the environment, so we + * initialize it from the value in the EEPROM. + */ + debug("### Setting environment from EEPROM MAC address = " + "\"%pM\"\n", + env_enetaddr); + ret = !eth_setenv_enetaddr("ethaddr", rom_enetaddr); + } + if (!ret) + printf("Failed to set mac address from EEPROM: %d\n", ret); +} +#endif /* CONFIG_DRIVER_TI_EMAC */ + +#if defined(CONFIG_SOC_DA8XX) +#ifndef CONFIG_USE_IRQ +void irq_init(void) +{ + /* + * Mask all IRQs by clearing the global enable and setting + * the enable clear for all the 90 interrupts. + */ + writel(0, &davinci_aintc_regs->ger); + + writel(0, &davinci_aintc_regs->hier); + + writel(0xffffffff, &davinci_aintc_regs->ecr1); + writel(0xffffffff, &davinci_aintc_regs->ecr2); + writel(0xffffffff, &davinci_aintc_regs->ecr3); +} +#endif + +/* + * Enable PSC for various peripherals. + */ +int da8xx_configure_lpsc_items(const struct lpsc_resource *item, + const int n_items) +{ + int i; + + for (i = 0; i < n_items; i++) + lpsc_on(item[i].lpsc_no); + + return 0; +} +#endif diff --git a/arch/arm/cpu/arm926ejs/davinci/pinmux.c b/arch/arm/cpu/arm926ejs/davinci/pinmux.c new file mode 100644 index 0000000..ce58f71 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/pinmux.c @@ -0,0 +1,105 @@ +/* + * DaVinci pinmux functions. + * + * Copyright (C) 2009 Nick Thompson, GE Fanuc Ltd, <nick.thompson@gefanuc.com> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2008 Lyrtech <www.lyrtech.com> + * Copyright (C) 2004 Texas Instruments. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> +#include <asm/arch/davinci_misc.h> + +/* + * Change the setting of a pin multiplexer field. + * + * Takes an array of pinmux settings similar to: + * + * struct pinmux_config uart_pins[] = { + * { &davinci_syscfg_regs->pinmux[8], 2, 7 }, + * { &davinci_syscfg_regs->pinmux[9], 2, 0 } + * }; + * + * Stepping through the array, each pinmux[n] register has the given value + * set in the pin mux field specified. + * + * The number of pins in the array must be passed (ARRAY_SIZE can provide + * this value conveniently). + * + * Returns 0 if all field numbers and values are in the correct range, + * else returns -1. + */ +int davinci_configure_pin_mux(const struct pinmux_config *pins, + const int n_pins) +{ + int i; + + /* check for invalid pinmux values */ + for (i = 0; i < n_pins; i++) { + if (pins[i].field >= PIN_MUX_NUM_FIELDS || + (pins[i].value & ~PIN_MUX_FIELD_MASK) != 0) + return -1; + } + + /* configure the pinmuxes */ + for (i = 0; i < n_pins; i++) { + const int offset = pins[i].field * PIN_MUX_FIELD_SIZE; + const unsigned int value = pins[i].value << offset; + const unsigned int mask = PIN_MUX_FIELD_MASK << offset; + const dv_reg *mux = pins[i].mux; + + writel(value | (readl(mux) & (~mask)), mux); + } + + return 0; +} + +/* + * Configure multiple pinmux resources. + * + * Takes an pinmux_resource array of pinmux_config and pin counts: + * + * const struct pinmux_resource pinmuxes[] = { + * PINMUX_ITEM(uart_pins), + * PINMUX_ITEM(i2c_pins), + * }; + * + * The number of items in the array must be passed (ARRAY_SIZE can provide + * this value conveniently). + * + * Each item entry is configured in the defined order. If configuration + * of any item fails, -1 is returned and none of the following items are + * configured. On success, 0 is returned. + */ +int davinci_configure_pin_mux_items(const struct pinmux_resource *item, + const int n_items) +{ + int i; + + for (i = 0; i < n_items; i++) { + if (davinci_configure_pin_mux(item[i].pins, + item[i].n_pins) != 0) + return -1; + } + + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/davinci/psc.c b/arch/arm/cpu/arm926ejs/davinci/psc.c new file mode 100644 index 0000000..2ffb42a --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/psc.c @@ -0,0 +1,175 @@ +/* + * Power and Sleep Controller (PSC) functions. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * Copyright (C) 2008 Lyrtech <www.lyrtech.com> + * Copyright (C) 2004 Texas Instruments. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <common.h> +#include <asm/arch/hardware.h> +#include <asm/io.h> + +/* + * The PSC manages three inputs to a "module" which may be a peripheral or + * CPU. Those inputs are the module's: clock; reset signal; and sometimes + * its power domain. For our purposes, we only care whether clock and power + * are active, and the module is out of reset. + * + * DaVinci chips may include two separate power domains: "Always On" and "DSP". + * Chips without a DSP generally have only one domain. + * + * The "Always On" power domain is always on when the chip is on, and is + * powered by the VDD pins (on DM644X). The majority of DaVinci modules + * lie within the "Always On" power domain. + * + * A separate domain called the "DSP" domain houses the C64x+ and other video + * hardware such as VICP. In some chips, the "DSP" domain is not always on. + * The "DSP" power domain is powered by the CVDDDSP pins (on DM644X). + */ + +/* Works on Always On power domain only (no PD argument) */ +static void lpsc_transition(unsigned int id, unsigned int state) +{ + dv_reg_p mdstat, mdctl, ptstat, ptcmd; +#ifdef CONFIG_SOC_DA8XX + struct davinci_psc_regs *psc_regs; +#endif + +#ifndef CONFIG_SOC_DA8XX + if (id >= DAVINCI_LPSC_GEM) + return; /* Don't work on DSP Power Domain */ + + mdstat = REG_P(PSC_MDSTAT_BASE + (id * 4)); + mdctl = REG_P(PSC_MDCTL_BASE + (id * 4)); + ptstat = REG_P(PSC_PTSTAT); + ptcmd = REG_P(PSC_PTCMD); +#else + if (id < DAVINCI_LPSC_PSC1_BASE) { + if (id >= PSC_PSC0_MODULE_ID_CNT) + return; + psc_regs = davinci_psc0_regs; + mdstat = &psc_regs->psc0.mdstat[id]; + mdctl = &psc_regs->psc0.mdctl[id]; + } else { + id -= DAVINCI_LPSC_PSC1_BASE; + if (id >= PSC_PSC1_MODULE_ID_CNT) + return; + psc_regs = davinci_psc1_regs; + mdstat = &psc_regs->psc1.mdstat[id]; + mdctl = &psc_regs->psc1.mdctl[id]; + } + ptstat = &psc_regs->ptstat; + ptcmd = &psc_regs->ptcmd; +#endif + + while (readl(ptstat) & 0x01) + continue; + + if ((readl(mdstat) & PSC_MDSTAT_STATE) == state) + return; /* Already in that state */ + + writel((readl(mdctl) & ~PSC_MDCTL_NEXT) | state, mdctl); + + switch (id) { +#ifdef CONFIG_SOC_DM644X + /* Special treatment for some modules as for sprue14 p.7.4.2 */ + case DAVINCI_LPSC_VPSSSLV: + case DAVINCI_LPSC_EMAC: + case DAVINCI_LPSC_EMAC_WRAPPER: + case DAVINCI_LPSC_MDIO: + case DAVINCI_LPSC_USB: + case DAVINCI_LPSC_ATA: + case DAVINCI_LPSC_VLYNQ: + case DAVINCI_LPSC_UHPI: + case DAVINCI_LPSC_DDR_EMIF: + case DAVINCI_LPSC_AEMIF: + case DAVINCI_LPSC_MMC_SD: + case DAVINCI_LPSC_MEMSTICK: + case DAVINCI_LPSC_McBSP: + case DAVINCI_LPSC_GPIO: + writel(readl(mdctl) | 0x200, mdctl); + break; +#endif + } + + writel(0x01, ptcmd); + + while (readl(ptstat) & 0x01) + continue; + while ((readl(mdstat) & PSC_MDSTAT_STATE) != state) + continue; +} + +void lpsc_on(unsigned int id) +{ + lpsc_transition(id, 0x03); +} + +void lpsc_syncreset(unsigned int id) +{ + lpsc_transition(id, 0x01); +} + +void lpsc_disable(unsigned int id) +{ + lpsc_transition(id, 0x0); +} + +/* Not all DaVinci chips have a DSP power domain. */ +#ifdef CONFIG_SOC_DM644X + +/* If DSPLINK is used, we don't want U-Boot to power on the DSP. */ +#if !defined(CONFIG_SYS_USE_DSPLINK) +void dsp_on(void) +{ + int i; + + if (REG(PSC_PDSTAT1) & 0x1f) + return; /* Already on */ + + REG(PSC_GBLCTL) |= 0x01; + REG(PSC_PDCTL1) |= 0x01; + REG(PSC_PDCTL1) &= ~0x100; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_GEM * 4)) &= 0xfffffeff; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) |= 0x03; + REG(PSC_MDCTL_BASE + (DAVINCI_LPSC_IMCOP * 4)) &= 0xfffffeff; + REG(PSC_PTCMD) = 0x02; + + for (i = 0; i < 100; i++) { + if (REG(PSC_EPCPR) & 0x02) + break; + } + + REG(PSC_CHP_SHRTSW) = 0x01; + REG(PSC_PDCTL1) |= 0x100; + REG(PSC_EPCCR) = 0x02; + + for (i = 0; i < 100; i++) { + if (!(REG(PSC_PTSTAT) & 0x02)) + break; + } + + REG(PSC_GBLCTL) &= ~0x1f; +} +#endif /* CONFIG_SYS_USE_DSPLINK */ + +#endif /* have a DSP */ diff --git a/arch/arm/cpu/arm926ejs/davinci/reset.c b/arch/arm/cpu/arm926ejs/davinci/reset.c new file mode 100644 index 0000000..80f1ce9 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/reset.c @@ -0,0 +1,33 @@ +/* + * Processor reset using WDT. + * + * Copyright (C) 2012 Dmitry Bondar <bond@inmys.ru> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. +*/ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/timer_defs.h> +#include <asm/arch/hardware.h> + +void reset_cpu(unsigned long a) +{ + struct davinci_timer *const wdttimer = + (struct davinci_timer *)DAVINCI_WDOG_BASE; + writel(0x08, &wdttimer->tgcr); + writel(readl(&wdttimer->tgcr) | 0x03, &wdttimer->tgcr); + writel(0, &wdttimer->tim12); + writel(0, &wdttimer->tim34); + writel(0, &wdttimer->prd12); + writel(0, &wdttimer->prd34); + writel(readl(&wdttimer->tcr) | 0x40, &wdttimer->tcr); + writel(readl(&wdttimer->wdtcr) | 0x4000, &wdttimer->wdtcr); + writel(0xa5c64000, &wdttimer->wdtcr); + writel(0xda7e4000, &wdttimer->wdtcr); + writel(0x4000, &wdttimer->wdtcr); + while (1) + /*nothing*/; +} diff --git a/arch/arm/cpu/arm926ejs/davinci/spl.c b/arch/arm/cpu/arm926ejs/davinci/spl.c new file mode 100644 index 0000000..ca8a412 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/spl.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * 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 <config.h> +#include <spl.h> +#include <asm/u-boot.h> +#include <asm/utils.h> +#include <nand.h> +#include <asm/arch/dm365_lowlevel.h> +#include <ns16550.h> +#include <malloc.h> +#include <spi_flash.h> +#include <mmc.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifndef CONFIG_SPL_LIBCOMMON_SUPPORT +void puts(const char *str) +{ + while (*str) + putc(*str++); +} + +void putc(char c) +{ + if (c == '\n') + NS16550_putc((NS16550_t)(CONFIG_SYS_NS16550_COM1), '\r'); + + NS16550_putc((NS16550_t)(CONFIG_SYS_NS16550_COM1), c); +} +#endif /* CONFIG_SPL_LIBCOMMON_SUPPORT */ + +void board_init_f(ulong dummy) +{ + /* First, setup our stack pointer. */ + asm volatile("mov sp, %0\n" : : "r"(CONFIG_SPL_STACK)); + + /* Second, perform our low-level init. */ +#ifdef CONFIG_SOC_DM365 + dm36x_lowlevel_init(0); +#endif +#ifdef CONFIG_SOC_DA8XX + arch_cpu_init(); +#endif + + /* Third, we clear the BSS. */ + memset(__bss_start, 0, __bss_end - __bss_start); + + /* Finally, setup gd and move to the next step. */ + gd = &gdata; + board_init_r(NULL, 0); +} + +void spl_board_init(void) +{ + preloader_console_init(); +} + +u32 spl_boot_mode(void) +{ + return MMCSD_MODE_RAW; +} + +u32 spl_boot_device(void) +{ +#ifdef CONFIG_SPL_NAND_SIMPLE + return BOOT_DEVICE_NAND; +#elif defined(CONFIG_SPL_SPI_LOAD) + return BOOT_DEVICE_SPI; +#elif defined(CONFIG_SPL_MMC_LOAD) + return BOOT_DEVICE_MMC1; +#else + puts("Unknown boot device\n"); + hang(); +#endif +} diff --git a/arch/arm/cpu/arm926ejs/davinci/timer.c b/arch/arm/cpu/arm926ejs/davinci/timer.c new file mode 100644 index 0000000..4142932 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/davinci/timer.c @@ -0,0 +1,144 @@ +/* + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.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 <asm/io.h> +#include <asm/arch/timer_defs.h> +#include <div64.h> + +DECLARE_GLOBAL_DATA_PTR; + +static struct davinci_timer * const timer = + (struct davinci_timer *)CONFIG_SYS_TIMERBASE; + +#define TIMER_LOAD_VAL 0xffffffff + +#define TIM_CLK_DIV 16 + +int timer_init(void) +{ + /* We are using timer34 in unchained 32-bit mode, full speed */ + writel(0x0, &timer->tcr); + writel(0x0, &timer->tgcr); + writel(0x06 | ((TIM_CLK_DIV - 1) << 8), &timer->tgcr); + writel(0x0, &timer->tim34); + writel(TIMER_LOAD_VAL, &timer->prd34); + writel(2 << 22, &timer->tcr); + gd->arch.timer_rate_hz = CONFIG_SYS_HZ_CLOCK / TIM_CLK_DIV; + gd->arch.timer_reset_value = 0; + + return(0); +} + +/* + * Get the current 64 bit timer tick count + */ +unsigned long long get_ticks(void) +{ + unsigned long now = readl(&timer->tim34); + + /* increment tbu if tbl has rolled over */ + if (now < gd->arch.tbl) + gd->arch.tbu++; + gd->arch.tbl = now; + + return (((unsigned long long)gd->arch.tbu) << 32) | gd->arch.tbl; +} + +ulong get_timer(ulong base) +{ + unsigned long long timer_diff; + + timer_diff = get_ticks() - gd->arch.timer_reset_value; + + return lldiv(timer_diff, + (gd->arch.timer_rate_hz / CONFIG_SYS_HZ)) - base; +} + +void __udelay(unsigned long usec) +{ + unsigned long long endtime; + + endtime = lldiv((unsigned long long)usec * gd->arch.timer_rate_hz, + 1000000UL); + endtime += get_ticks(); + + while (get_ticks() < endtime) + ; +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return gd->arch.timer_rate_hz; +} + +#ifdef CONFIG_HW_WATCHDOG +static struct davinci_timer * const wdttimer = + (struct davinci_timer *)CONFIG_SYS_WDTTIMERBASE; + +/* + * See prufw2.pdf for using Timer as a WDT + */ +void davinci_hw_watchdog_enable(void) +{ + writel(0x0, &wdttimer->tcr); + writel(0x0, &wdttimer->tgcr); + /* TIMMODE = 2h */ + writel(0x08 | 0x03 | ((TIM_CLK_DIV - 1) << 8), &wdttimer->tgcr); + writel(CONFIG_SYS_WDT_PERIOD_LOW, &wdttimer->prd12); + writel(CONFIG_SYS_WDT_PERIOD_HIGH, &wdttimer->prd34); + writel(2 << 22, &wdttimer->tcr); + writel(0x0, &wdttimer->tim12); + writel(0x0, &wdttimer->tim34); + /* set WDEN bit, WDKEY 0xa5c6 */ + writel(0xa5c64000, &wdttimer->wdtcr); + /* clear counter register */ + writel(0xda7e4000, &wdttimer->wdtcr); +} + +void davinci_hw_watchdog_reset(void) +{ + writel(0xa5c64000, &wdttimer->wdtcr); + writel(0xda7e4000, &wdttimer->wdtcr); +} +#endif diff --git a/arch/arm/cpu/arm926ejs/kirkwood/Makefile b/arch/arm/cpu/arm926ejs/kirkwood/Makefile new file mode 100644 index 0000000..777006c --- /dev/null +++ b/arch/arm/cpu/arm926ejs/kirkwood/Makefile @@ -0,0 +1,50 @@ +# +# (C) Copyright 2009 +# Marvell Semiconductor <www.marvell.com> +# Written-by: Prafulla Wadaskar <prafulla@marvell.com> +# +# 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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS-y = cpu.o +COBJS-y += dram.o +COBJS-y += mpp.o +COBJS-y += timer.o +COBJS-y += cache.o + +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/kirkwood/cache.c b/arch/arm/cpu/arm926ejs/kirkwood/cache.c new file mode 100644 index 0000000..645d962 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/kirkwood/cache.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012 Michael Walle + * Michael Walle <michael@walle.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. + */ +#include <common.h> +#include <asm/arch/cpu.h> + +#define FEROCEON_EXTRA_FEATURE_L2C_EN (1<<22) + +void l2_cache_disable() +{ + u32 ctrl; + + ctrl = readfr_extra_feature_reg(); + ctrl &= ~FEROCEON_EXTRA_FEATURE_L2C_EN; + writefr_extra_feature_reg(ctrl); +} diff --git a/arch/arm/cpu/arm926ejs/kirkwood/cpu.c b/arch/arm/cpu/arm926ejs/kirkwood/cpu.c new file mode 100644 index 0000000..fba5e01 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/kirkwood/cpu.c @@ -0,0 +1,396 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <netdev.h> +#include <asm/cache.h> +#include <u-boot/md5.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/kirkwood.h> +#include <hush.h> + +#define BUFLEN 16 + +void reset_cpu(unsigned long ignored) +{ + struct kwcpu_registers *cpureg = + (struct kwcpu_registers *)KW_CPU_REG_BASE; + + writel(readl(&cpureg->rstoutn_mask) | (1 << 2), + &cpureg->rstoutn_mask); + writel(readl(&cpureg->sys_soft_rst) | 1, + &cpureg->sys_soft_rst); + while (1) ; +} + +/* + * Generates Ramdom hex number reading some time varient system registers + * and using md5 algorithm + */ +unsigned char get_random_hex(void) +{ + int i; + u32 inbuf[BUFLEN]; + u8 outbuf[BUFLEN]; + + /* + * in case of 88F6281/88F6282/88F6192 A0, + * Bit7 need to reset to generate random values in KW_REG_UNDOC_0x1470 + * Soc reg offsets KW_REG_UNDOC_0x1470 and KW_REG_UNDOC_0x1478 are + * reserved regs and does not have names at this moment + * (no errata available) + */ + writel(readl(KW_REG_UNDOC_0x1478) & ~(1 << 7), KW_REG_UNDOC_0x1478); + for (i = 0; i < BUFLEN; i++) { + inbuf[i] = readl(KW_REG_UNDOC_0x1470); + } + md5((u8 *) inbuf, (BUFLEN * sizeof(u32)), outbuf); + return outbuf[outbuf[7] % 0x0f]; +} + +/* + * Window Size + * Used with the Base register to set the address window size and location. + * Must be programmed from LSB to MSB as sequence of ones followed by + * sequence of zeros. The number of ones specifies the size of the window in + * 64 KByte granularity (e.g., a value of 0x00FF specifies 256 = 16 MByte). + * NOTE: A value of 0x0 specifies 64-KByte size. + */ +unsigned int kw_winctrl_calcsize(unsigned int sizeval) +{ + int i; + unsigned int j = 0; + u32 val = sizeval >> 1; + + for (i = 0; val >= 0x10000; i++) { + j |= (1 << i); + val = val >> 1; + } + return (0x0000ffff & j); +} + +/* + * kw_config_adr_windows - Configure address Windows + * + * There are 8 address windows supported by Kirkwood Soc to addess different + * devices. Each window can be configured for size, BAR and remap addr + * Below configuration is standard for most of the cases + * + * If remap function not used, remap_lo must be set as base + * + * Reference Documentation: + * Mbus-L to Mbus Bridge Registers Configuration. + * (Sec 25.1 and 25.3 of Datasheet) + */ +int kw_config_adr_windows(void) +{ + struct kwwin_registers *winregs = + (struct kwwin_registers *)KW_CPU_WIN_BASE; + + /* Window 0: PCIE MEM address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 256, KWCPU_TARGET_PCIE, + KWCPU_ATTR_PCIE_MEM, KWCPU_WIN_ENABLE), &winregs[0].ctrl); + + writel(KW_DEFADR_PCI_MEM, &winregs[0].base); + writel(KW_DEFADR_PCI_MEM, &winregs[0].remap_lo); + writel(0x0, &winregs[0].remap_hi); + + /* Window 1: PCIE IO address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 64, KWCPU_TARGET_PCIE, + KWCPU_ATTR_PCIE_IO, KWCPU_WIN_ENABLE), &winregs[1].ctrl); + writel(KW_DEFADR_PCI_IO, &winregs[1].base); + writel(KW_DEFADR_PCI_IO_REMAP, &winregs[1].remap_lo); + writel(0x0, &winregs[1].remap_hi); + + /* Window 2: NAND Flash address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_NANDFLASH, KWCPU_WIN_ENABLE), &winregs[2].ctrl); + writel(KW_DEFADR_NANDF, &winregs[2].base); + writel(KW_DEFADR_NANDF, &winregs[2].remap_lo); + writel(0x0, &winregs[2].remap_hi); + + /* Window 3: SPI Flash address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_SPIFLASH, KWCPU_WIN_ENABLE), &winregs[3].ctrl); + writel(KW_DEFADR_SPIF, &winregs[3].base); + writel(KW_DEFADR_SPIF, &winregs[3].remap_lo); + writel(0x0, &winregs[3].remap_hi); + + /* Window 4: BOOT Memory address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 1024 * 128, KWCPU_TARGET_MEMORY, + KWCPU_ATTR_BOOTROM, KWCPU_WIN_ENABLE), &winregs[4].ctrl); + writel(KW_DEFADR_BOOTROM, &winregs[4].base); + + /* Window 5: Security SRAM address space */ + writel(KWCPU_WIN_CTRL_DATA(1024 * 64, KWCPU_TARGET_SASRAM, + KWCPU_ATTR_SASRAM, KWCPU_WIN_ENABLE), &winregs[5].ctrl); + writel(KW_DEFADR_SASRAM, &winregs[5].base); + + /* Window 6-7: Disabled */ + writel(KWCPU_WIN_DISABLE, &winregs[6].ctrl); + writel(KWCPU_WIN_DISABLE, &winregs[7].ctrl); + + return 0; +} + +/* + * kw_config_gpio - GPIO configuration + */ +void kw_config_gpio(u32 gpp0_oe_val, u32 gpp1_oe_val, u32 gpp0_oe, u32 gpp1_oe) +{ + struct kwgpio_registers *gpio0reg = + (struct kwgpio_registers *)KW_GPIO0_BASE; + struct kwgpio_registers *gpio1reg = + (struct kwgpio_registers *)KW_GPIO1_BASE; + + /* Init GPIOS to default values as per board requirement */ + writel(gpp0_oe_val, &gpio0reg->dout); + writel(gpp1_oe_val, &gpio1reg->dout); + writel(gpp0_oe, &gpio0reg->oe); + writel(gpp1_oe, &gpio1reg->oe); +} + +/* + * kw_config_mpp - Multi-Purpose Pins Functionality configuration + * + * Each MPP can be configured to different functionality through + * MPP control register, ref (sec 6.1 of kirkwood h/w specification) + * + * There are maximum 64 Multi-Pourpose Pins on Kirkwood + * Each MPP functionality can be configuration by a 4bit value + * of MPP control reg, the value and associated functionality depends + * upon used SoC varient + */ +int kw_config_mpp(u32 mpp0_7, u32 mpp8_15, u32 mpp16_23, u32 mpp24_31, + u32 mpp32_39, u32 mpp40_47, u32 mpp48_55) +{ + u32 *mppreg = (u32 *) KW_MPP_BASE; + + /* program mpp registers */ + writel(mpp0_7, &mppreg[0]); + writel(mpp8_15, &mppreg[1]); + writel(mpp16_23, &mppreg[2]); + writel(mpp24_31, &mppreg[3]); + writel(mpp32_39, &mppreg[4]); + writel(mpp40_47, &mppreg[5]); + writel(mpp48_55, &mppreg[6]); + return 0; +} + +/* + * SYSRSTn Duration Counter Support + * + * Kirkwood SoC implements a hardware-based SYSRSTn duration counter. + * When SYSRSTn is asserted low, a SYSRSTn duration counter is running. + * The SYSRSTn duration counter is useful for implementing a manufacturer + * or factory reset. Upon a long reset assertion that is greater than a + * pre-configured environment variable value for sysrstdelay, + * The counter value is stored in the SYSRSTn Length Counter Register + * The counter is based on the 25-MHz reference clock (40ns) + * It is a 29-bit counter, yielding a maximum counting duration of + * 2^29/25 MHz (21.4 seconds). When the counter reach its maximum value, + * it remains at this value until counter reset is triggered by setting + * bit 31 of KW_REG_SYSRST_CNT + */ +static void kw_sysrst_action(void) +{ + int ret; + char *s = getenv("sysrstcmd"); + + if (!s) { + debug("Error.. %s failed, check sysrstcmd\n", + __FUNCTION__); + return; + } + + debug("Starting %s process...\n", __FUNCTION__); + ret = run_command(s, 0); + if (ret < 0) + debug("Error.. %s failed\n", __FUNCTION__); + else + debug("%s process finished\n", __FUNCTION__); +} + +static void kw_sysrst_check(void) +{ + u32 sysrst_cnt, sysrst_dly; + char *s; + + /* + * no action if sysrstdelay environment variable is not defined + */ + s = getenv("sysrstdelay"); + if (s == NULL) + return; + + /* read sysrstdelay value */ + sysrst_dly = (u32) simple_strtoul(s, NULL, 10); + + /* read SysRst Length counter register (bits 28:0) */ + sysrst_cnt = (0x1fffffff & readl(KW_REG_SYSRST_CNT)); + debug("H/w Rst hold time: %d.%d secs\n", + sysrst_cnt / SYSRST_CNT_1SEC_VAL, + sysrst_cnt % SYSRST_CNT_1SEC_VAL); + + /* clear the counter for next valid read*/ + writel(1 << 31, KW_REG_SYSRST_CNT); + + /* + * sysrst_action: + * if H/w Reset key is pressed and hold for time + * more than sysrst_dly in seconds + */ + if (sysrst_cnt >= SYSRST_CNT_1SEC_VAL * sysrst_dly) + kw_sysrst_action(); +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + char *rev; + u16 devid = (readl(KW_REG_PCIE_DEVID) >> 16) & 0xffff; + u8 revid = readl(KW_REG_PCIE_REVID) & 0xff; + + if ((readl(KW_REG_DEVICE_ID) & 0x03) > 2) { + printf("Error.. %s:Unsupported Kirkwood SoC 88F%04x\n", __FUNCTION__, devid); + return -1; + } + + switch (revid) { + case 0: + rev = "Z0"; + break; + case 2: + rev = "A0"; + break; + case 3: + rev = "A1"; + break; + default: + rev = "??"; + break; + } + + printf("SoC: Kirkwood 88F%04x_%s\n", devid, rev); + return 0; +} +#endif /* CONFIG_DISPLAY_CPUINFO */ + +#ifdef CONFIG_ARCH_CPU_INIT +int arch_cpu_init(void) +{ + u32 reg; + struct kwcpu_registers *cpureg = + (struct kwcpu_registers *)KW_CPU_REG_BASE; + + /* Linux expects` the internal registers to be at 0xf1000000 */ + writel(KW_REGS_PHY_BASE, KW_OFFSET_REG); + + /* Enable and invalidate L2 cache in write through mode */ + writel(readl(&cpureg->l2_cfg) | 0x18, &cpureg->l2_cfg); + invalidate_l2_cache(); + + kw_config_adr_windows(); + +#ifdef CONFIG_KIRKWOOD_RGMII_PAD_1V8 + /* + * Configures the I/O voltage of the pads connected to Egigabit + * Ethernet interface to 1.8V + * By defult it is set to 3.3V + */ + reg = readl(KW_REG_MPP_OUT_DRV_REG); + reg |= (1 << 7); + writel(reg, KW_REG_MPP_OUT_DRV_REG); +#endif +#ifdef CONFIG_KIRKWOOD_EGIGA_INIT + /* + * Set egiga port0/1 in normal functional mode + * This is required becasue on kirkwood by default ports are in reset mode + * OS egiga driver may not have provision to set them in normal mode + * and if u-boot is build without network support, network may fail at OS level + */ + reg = readl(KWGBE_PORT_SERIAL_CONTROL1_REG(0)); + reg &= ~(1 << 4); /* Clear PortReset Bit */ + writel(reg, (KWGBE_PORT_SERIAL_CONTROL1_REG(0))); + reg = readl(KWGBE_PORT_SERIAL_CONTROL1_REG(1)); + reg &= ~(1 << 4); /* Clear PortReset Bit */ + writel(reg, (KWGBE_PORT_SERIAL_CONTROL1_REG(1))); +#endif +#ifdef CONFIG_KIRKWOOD_PCIE_INIT + /* + * Enable PCI Express Port0 + */ + reg = readl(&cpureg->ctrl_stat); + reg |= (1 << 0); /* Set PEX0En Bit */ + writel(reg, &cpureg->ctrl_stat); +#endif + return 0; +} +#endif /* CONFIG_ARCH_CPU_INIT */ + +/* + * SOC specific misc init + */ +#if defined(CONFIG_ARCH_MISC_INIT) +int arch_misc_init(void) +{ + volatile u32 temp; + + /*CPU streaming & write allocate */ + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 28); /* disable wr alloc */ + writefr_extra_feature_reg(temp); + + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 29); /* streaming disabled */ + writefr_extra_feature_reg(temp); + + /* L2Cache settings */ + temp = readfr_extra_feature_reg(); + /* Disable L2C pre fetch - Set bit 24 */ + temp |= (1 << 24); + /* enable L2C - Set bit 22 */ + temp |= (1 << 22); + writefr_extra_feature_reg(temp); + + icache_enable(); + /* Change reset vector to address 0x0 */ + temp = get_cr(); + set_cr(temp & ~CR_V); + + /* checks and execute resset to factory event */ + kw_sysrst_check(); + + return 0; +} +#endif /* CONFIG_ARCH_MISC_INIT */ + +#ifdef CONFIG_MVGBE +int cpu_eth_init(bd_t *bis) +{ + mvgbe_initialize(bis); + return 0; +} +#endif diff --git a/arch/arm/cpu/arm926ejs/kirkwood/dram.c b/arch/arm/cpu/arm926ejs/kirkwood/dram.c new file mode 100644 index 0000000..807894f --- /dev/null +++ b/arch/arm/cpu/arm926ejs/kirkwood/dram.c @@ -0,0 +1,153 @@ +/* + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <config.h> +#include <common.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/kirkwood.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct kw_sdram_bank { + u32 win_bar; + u32 win_sz; +}; + +struct kw_sdram_addr_dec { + struct kw_sdram_bank sdram_bank[4]; +}; + +#define KW_REG_CPUCS_WIN_ENABLE (1 << 0) +#define KW_REG_CPUCS_WIN_WR_PROTECT (1 << 1) +#define KW_REG_CPUCS_WIN_WIN0_CS(x) (((x) & 0x3) << 2) +#define KW_REG_CPUCS_WIN_SIZE(x) (((x) & 0xff) << 24) + +/* + * kw_sdram_bar - reads SDRAM Base Address Register + */ +u32 kw_sdram_bar(enum memory_bank bank) +{ + struct kw_sdram_addr_dec *base = + (struct kw_sdram_addr_dec *)KW_REGISTER(0x1500); + u32 result = 0; + u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz); + + if ((!enable) || (bank > BANK3)) + return 0; + + result = readl(&base->sdram_bank[bank].win_bar); + return result; +} + +/* + * kw_sdram_bs_set - writes SDRAM Bank size + */ +static void kw_sdram_bs_set(enum memory_bank bank, u32 size) +{ + struct kw_sdram_addr_dec *base = + (struct kw_sdram_addr_dec *)KW_REGISTER(0x1500); + /* Read current register value */ + u32 reg = readl(&base->sdram_bank[bank].win_sz); + + /* Clear window size */ + reg &= ~KW_REG_CPUCS_WIN_SIZE(0xFF); + + /* Set new window size */ + reg |= KW_REG_CPUCS_WIN_SIZE((size - 1) >> 24); + + writel(reg, &base->sdram_bank[bank].win_sz); +} + +/* + * kw_sdram_bs - reads SDRAM Bank size + */ +u32 kw_sdram_bs(enum memory_bank bank) +{ + struct kw_sdram_addr_dec *base = + (struct kw_sdram_addr_dec *)KW_REGISTER(0x1500); + u32 result = 0; + u32 enable = 0x01 & readl(&base->sdram_bank[bank].win_sz); + + if ((!enable) || (bank > BANK3)) + return 0; + result = 0xff000000 & readl(&base->sdram_bank[bank].win_sz); + result += 0x01000000; + return result; +} + +void kw_sdram_size_adjust(enum memory_bank bank) +{ + u32 size; + + /* probe currently equipped RAM size */ + size = get_ram_size((void *)kw_sdram_bar(bank), kw_sdram_bs(bank)); + + /* adjust SDRAM window size accordingly */ + kw_sdram_bs_set(bank, size); +} + +#ifndef CONFIG_SYS_BOARD_DRAM_INIT +int dram_init(void) +{ + int i; + + gd->ram_size = 0; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + gd->bd->bi_dram[i].start = kw_sdram_bar(i); + gd->bd->bi_dram[i].size = kw_sdram_bs(i); + /* + * It is assumed that all memory banks are consecutive + * and without gaps. + * If the gap is found, ram_size will be reported for + * consecutive memory only + */ + if (gd->bd->bi_dram[i].start != gd->ram_size) + break; + + gd->ram_size += gd->bd->bi_dram[i].size; + + } + + for (; i < CONFIG_NR_DRAM_BANKS; i++) { + /* If above loop terminated prematurely, we need to set + * remaining banks' start address & size as 0. Otherwise other + * u-boot functions and Linux kernel gets wrong values which + * could result in crash */ + gd->bd->bi_dram[i].start = 0; + gd->bd->bi_dram[i].size = 0; + } + + return 0; +} + +/* + * If this function is not defined here, + * board.c alters dram bank zero configuration defined above. + */ +void dram_init_banksize(void) +{ + dram_init(); +} +#endif /* CONFIG_SYS_BOARD_DRAM_INIT */ diff --git a/arch/arm/cpu/arm926ejs/kirkwood/mpp.c b/arch/arm/cpu/arm926ejs/kirkwood/mpp.c new file mode 100644 index 0000000..0ba6f09 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/kirkwood/mpp.c @@ -0,0 +1,90 @@ +/* + * arch/arm/mach-kirkwood/mpp.c + * + * MPP functions for Marvell Kirkwood SoCs + * Referenced from Linux kernel source + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/cpu.h> +#include <asm/arch/kirkwood.h> +#include <asm/arch/mpp.h> + +static u32 kirkwood_variant(void) +{ + switch (readl(KW_REG_DEVICE_ID) & 0x03) { + case 1: + return MPP_F6192_MASK; + case 2: + return MPP_F6281_MASK; + default: + debug("MPP setup: unknown kirkwood variant\n"); + return 0; + } +} + +#define MPP_CTRL(i) (KW_MPP_BASE + (i* 4)) +#define MPP_NR_REGS (1 + MPP_MAX/8) + +void kirkwood_mpp_conf(const u32 *mpp_list, u32 *mpp_save) +{ + u32 mpp_ctrl[MPP_NR_REGS]; + unsigned int variant_mask; + int i; + + variant_mask = kirkwood_variant(); + if (!variant_mask) + return; + + debug( "initial MPP regs:"); + for (i = 0; i < MPP_NR_REGS; i++) { + mpp_ctrl[i] = readl(MPP_CTRL(i)); + debug(" %08x", mpp_ctrl[i]); + } + debug("\n"); + + + while (*mpp_list) { + unsigned int num = MPP_NUM(*mpp_list); + unsigned int sel = MPP_SEL(*mpp_list); + unsigned int sel_save; + int shift; + + if (num > MPP_MAX) { + debug("kirkwood_mpp_conf: invalid MPP " + "number (%u)\n", num); + continue; + } + if (!(*mpp_list & variant_mask)) { + debug("kirkwood_mpp_conf: requested MPP%u config " + "unavailable on this hardware\n", num); + continue; + } + + shift = (num & 7) << 2; + + if (mpp_save) { + sel_save = (mpp_ctrl[num / 8] >> shift) & 0xf; + *mpp_save = num | (sel_save << 8) | variant_mask; + mpp_save++; + } + + mpp_ctrl[num / 8] &= ~(0xf << shift); + mpp_ctrl[num / 8] |= sel << shift; + + mpp_list++; + } + + debug(" final MPP regs:"); + for (i = 0; i < MPP_NR_REGS; i++) { + writel(mpp_ctrl[i], MPP_CTRL(i)); + debug(" %08x", mpp_ctrl[i]); + } + debug("\n"); + +} diff --git a/arch/arm/cpu/arm926ejs/kirkwood/timer.c b/arch/arm/cpu/arm926ejs/kirkwood/timer.c new file mode 100644 index 0000000..85e81e3 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/kirkwood/timer.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) Marvell International Ltd. and its affiliates + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/kirkwood.h> + +#define UBOOT_CNTR 0 /* counter to use for uboot timer */ + +/* Timer reload and current value registers */ +struct kwtmr_val { + u32 reload; /* Timer reload reg */ + u32 val; /* Timer value reg */ +}; + +/* Timer registers */ +struct kwtmr_registers { + u32 ctrl; /* Timer control reg */ + u32 pad[3]; + struct kwtmr_val tmr[2]; + u32 wdt_reload; + u32 wdt_val; +}; + +struct kwtmr_registers *kwtmr_regs = (struct kwtmr_registers *)KW_TIMER_BASE; + +/* + * ARM Timers Registers Map + */ +#define CNTMR_CTRL_REG &kwtmr_regs->ctrl +#define CNTMR_RELOAD_REG(tmrnum) &kwtmr_regs->tmr[tmrnum].reload +#define CNTMR_VAL_REG(tmrnum) &kwtmr_regs->tmr[tmrnum].val + +/* + * ARM Timers Control Register + * CPU_TIMERS_CTRL_REG (CTCR) + */ +#define CTCR_ARM_TIMER_EN_OFFS(cntr) (cntr * 2) +#define CTCR_ARM_TIMER_EN_MASK(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS) +#define CTCR_ARM_TIMER_EN(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS(cntr)) +#define CTCR_ARM_TIMER_DIS(cntr) (0 << CTCR_ARM_TIMER_EN_OFFS(cntr)) + +#define CTCR_ARM_TIMER_AUTO_OFFS(cntr) ((cntr * 2) + 1) +#define CTCR_ARM_TIMER_AUTO_MASK(cntr) (1 << 1) +#define CTCR_ARM_TIMER_AUTO_EN(cntr) (1 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) +#define CTCR_ARM_TIMER_AUTO_DIS(cntr) (0 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) + +/* + * ARM Timer\Watchdog Reload Register + * CNTMR_RELOAD_REG (TRR) + */ +#define TRG_ARM_TIMER_REL_OFFS 0 +#define TRG_ARM_TIMER_REL_MASK 0xffffffff + +/* + * ARM Timer\Watchdog Register + * CNTMR_VAL_REG (TVRG) + */ +#define TVR_ARM_TIMER_OFFS 0 +#define TVR_ARM_TIMER_MASK 0xffffffff +#define TVR_ARM_TIMER_MAX 0xffffffff +#define TIMER_LOAD_VAL 0xffffffff + +#define READ_TIMER (readl(CNTMR_VAL_REG(UBOOT_CNTR)) / \ + (CONFIG_SYS_TCLK / 1000)) + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +ulong get_timer_masked(void) +{ + ulong now = READ_TIMER; + + if (lastdec >= now) { + /* normal mode */ + timestamp += lastdec - now; + } else { + /* we have an overflow ... */ + timestamp += lastdec + + (TIMER_LOAD_VAL / (CONFIG_SYS_TCLK / 1000)) - now; + } + lastdec = now; + + return timestamp; +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +void __udelay(unsigned long usec) +{ + uint current; + ulong delayticks; + + current = readl(CNTMR_VAL_REG(UBOOT_CNTR)); + delayticks = (usec * (CONFIG_SYS_TCLK / 1000000)); + + if (current < delayticks) { + delayticks -= current; + while (readl(CNTMR_VAL_REG(UBOOT_CNTR)) < current) ; + while ((TIMER_LOAD_VAL - delayticks) < + readl(CNTMR_VAL_REG(UBOOT_CNTR))) ; + } else { + while (readl(CNTMR_VAL_REG(UBOOT_CNTR)) > + (current - delayticks)) ; + } +} + +/* + * init the counter + */ +int timer_init(void) +{ + unsigned int cntmrctrl; + + /* load value into timer */ + writel(TIMER_LOAD_VAL, CNTMR_RELOAD_REG(UBOOT_CNTR)); + writel(TIMER_LOAD_VAL, CNTMR_VAL_REG(UBOOT_CNTR)); + + /* enable timer in auto reload mode */ + cntmrctrl = readl(CNTMR_CTRL_REG); + cntmrctrl |= CTCR_ARM_TIMER_EN(UBOOT_CNTR); + cntmrctrl |= CTCR_ARM_TIMER_AUTO_EN(UBOOT_CNTR); + writel(cntmrctrl, CNTMR_CTRL_REG); + + /* init the timestamp and lastdec value */ + lastdec = READ_TIMER; + timestamp = 0; + + return 0; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM 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 ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return (ulong)CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/Makefile b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile new file mode 100644 index 0000000..ae1f0a5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/Makefile @@ -0,0 +1,45 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS = cpu.o clk.o devices.o timer.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/clk.c b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c new file mode 100644 index 0000000..6f26d62 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/clk.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com> + * + * 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 <common.h> +#include <div64.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; + +unsigned int get_sys_clk_rate(void) +{ + if (readl(&clk->sysclk_ctrl) & CLK_SYSCLK_PLL397) + return RTC_CLK_FREQUENCY * 397; + else + return OSC_CLK_FREQUENCY; +} + +unsigned int get_hclk_pll_rate(void) +{ + unsigned long long fin, fref, fcco, fout; + u32 val, m_div, n_div, p_div; + + /* + * Valid frequency ranges: + * 1 * 10^6 <= Fin <= 20 * 10^6 + * 1 * 10^6 <= Fref <= 27 * 10^6 + * 156 * 10^6 <= Fcco <= 320 * 10^6 + */ + + fref = fin = get_sys_clk_rate(); + if (fin > 20000000ULL || fin < 1000000ULL) + return 0; + + val = readl(&clk->hclkpll_ctrl); + m_div = ((val & CLK_HCLK_PLL_FEEDBACK_DIV_MASK) >> 1) + 1; + n_div = ((val & CLK_HCLK_PLL_PREDIV_MASK) >> 9) + 1; + if (val & CLK_HCLK_PLL_DIRECT) + p_div = 0; + else + p_div = ((val & CLK_HCLK_PLL_POSTDIV_MASK) >> 11) + 1; + p_div = 1 << p_div; + + if (val & CLK_HCLK_PLL_BYPASS) { + do_div(fin, p_div); + return fin; + } + + do_div(fref, n_div); + if (fref > 27000000ULL || fref < 1000000ULL) + return 0; + + fout = fref * m_div; + if (val & CLK_HCLK_PLL_FEEDBACK) { + fcco = fout; + do_div(fout, p_div); + } else + fcco = fout * p_div; + + if (fcco > 320000000ULL || fcco < 156000000ULL) + return 0; + + return fout; +} + +unsigned int get_hclk_clk_div(void) +{ + u32 val; + + val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_ARM_PLL_DIV_MASK; + + return 1 << val; +} + +unsigned int get_hclk_clk_rate(void) +{ + return get_hclk_pll_rate() / get_hclk_clk_div(); +} + +unsigned int get_periph_clk_div(void) +{ + u32 val; + + val = readl(&clk->hclkdiv_ctrl) & CLK_HCLK_PERIPH_DIV_MASK; + + return (val >> 2) + 1; +} + +unsigned int get_periph_clk_rate(void) +{ + if (!(readl(&clk->pwr_ctrl) & CLK_PWR_NORMAL_RUN)) + return get_sys_clk_rate(); + + return get_hclk_pll_rate() / get_periph_clk_div(); +} + +int get_serial_clock(void) +{ + return get_periph_clk_rate(); +} diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c new file mode 100644 index 0000000..e29e130 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/cpu.c @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com> + * + * 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 <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/wdt.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; +static struct wdt_regs *wdt = (struct wdt_regs *)WDT_BASE; + +void reset_cpu(ulong addr) +{ + /* Enable watchdog clock */ + setbits_le32(&clk->timclk_ctrl, CLK_TIMCLK_WATCHDOG); + + /* Reset pulse length is 13005 peripheral clock frames */ + writel(13000, &wdt->pulse); + + /* Force WDOG_RESET2 and RESOUT_N signal active */ + writel(WDTIM_MCTRL_RESFRC2 | WDTIM_MCTRL_RESFRC1 | WDTIM_MCTRL_M_RES2, + &wdt->mctrl); + + while (1) + /* NOP */; +} + +#if defined(CONFIG_ARCH_CPU_INIT) +int arch_cpu_init(void) +{ + /* + * It might be necessary to flush data cache, if U-boot is loaded + * from kickstart bootloader, e.g. from S1L loader + */ + flush_dcache_all(); + + return 0; +} +#else +#error "You have to select CONFIG_ARCH_CPU_INIT" +#endif + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + printf("CPU: NXP LPC32XX\n"); + printf("CPU clock: %uMHz\n", get_hclk_pll_rate() / 1000000); + printf("AHB bus clock: %uMHz\n", get_hclk_clk_rate() / 1000000); + printf("Peripheral clock: %uMHz\n", get_periph_clk_rate() / 1000000); + + return 0; +} +#endif diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c new file mode 100644 index 0000000..9f305b5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 by Vladimir Zapolskiy <vz@mleia.com> + * + * 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 <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/uart.h> +#include <asm/io.h> + +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; +static struct uart_ctrl_regs *ctrl = (struct uart_ctrl_regs *)UART_CTRL_BASE; + +void lpc32xx_uart_init(unsigned int uart_id) +{ + if (uart_id < 1 || uart_id > 7) + return; + + /* Disable loopback mode, if it is set by S1L bootloader */ + clrbits_le32(&ctrl->loop, + UART_LOOPBACK(CONFIG_SYS_LPC32XX_UART)); + + if (uart_id < 3 || uart_id > 6) + return; + + /* Enable UART system clock */ + setbits_le32(&clk->uartclk_ctrl, CLK_UART(uart_id)); + + /* Set UART into autoclock mode */ + clrsetbits_le32(&ctrl->clkmode, + UART_CLKMODE_MASK(uart_id), + UART_CLKMODE_AUTO(uart_id)); + + /* Bypass pre-divider of UART clock */ + writel(CLK_UART_X_DIV(1) | CLK_UART_Y_DIV(1), + &clk->u3clk + (uart_id - 3)); +} diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/timer.c b/arch/arm/cpu/arm926ejs/lpc32xx/timer.c new file mode 100644 index 0000000..1ce2358 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/lpc32xx/timer.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2011 Vladimir Zapolskiy <vz@mleia.com> + * + * 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 <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/clk.h> +#include <asm/arch/timer.h> +#include <asm/io.h> + +static struct timer_regs *timer0 = (struct timer_regs *)TIMER0_BASE; +static struct timer_regs *timer1 = (struct timer_regs *)TIMER1_BASE; +static struct clk_pm_regs *clk = (struct clk_pm_regs *)CLK_PM_BASE; + +static void lpc32xx_timer_clock(u32 bit, int enable) +{ + if (enable) + setbits_le32(&clk->timclk_ctrl1, bit); + else + clrbits_le32(&clk->timclk_ctrl1, bit); +} + +static void lpc32xx_timer_reset(struct timer_regs *timer, u32 freq) +{ + writel(TIMER_TCR_COUNTER_RESET, &timer->tcr); + writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr); + writel(0, &timer->tc); + writel(0, &timer->pr); + + /* Count mode is every rising PCLK edge */ + writel(TIMER_CTCR_MODE_TIMER, &timer->ctcr); + + /* Set prescale counter value */ + writel((get_periph_clk_rate() / freq) - 1, &timer->pr); +} + +static void lpc32xx_timer_count(struct timer_regs *timer, int enable) +{ + if (enable) + writel(TIMER_TCR_COUNTER_ENABLE, &timer->tcr); + else + writel(TIMER_TCR_COUNTER_DISABLE, &timer->tcr); +} + +int timer_init(void) +{ + lpc32xx_timer_clock(CLK_TIMCLK_TIMER0, 1); + lpc32xx_timer_reset(timer0, CONFIG_SYS_HZ); + lpc32xx_timer_count(timer0, 1); + + return 0; +} + +ulong get_timer(ulong base) +{ + return readl(&timer0->tc) - base; +} + +void __udelay(unsigned long usec) +{ + lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 1); + lpc32xx_timer_reset(timer1, CONFIG_SYS_HZ * 1000); + lpc32xx_timer_count(timer1, 1); + + while (readl(&timer1->tc) < usec) + /* NOP */; + + lpc32xx_timer_count(timer1, 0); + lpc32xx_timer_clock(CLK_TIMCLK_TIMER1, 0); +} + +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/mb86r0x/Makefile b/arch/arm/cpu/arm926ejs/mb86r0x/Makefile new file mode 100644 index 0000000..bab048b --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mb86r0x/Makefile @@ -0,0 +1,47 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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$(SOC).o + +COBJS = clock.o reset.o timer.o +SOBJS = + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/mb86r0x/asm-offsets.c b/arch/arm/cpu/arm926ejs/mb86r0x/asm-offsets.c new file mode 100644 index 0000000..6f9c722 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mb86r0x/asm-offsets.c @@ -0,0 +1,65 @@ +/* + * Adapted from Linux v2.6.36 kernel: arch/powerpc/kernel/asm-offsets.c + * + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + * + * 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. + */ + +#include <common.h> +#include <asm/arch/mb86r0x.h> + +#include <linux/kbuild.h> + +int main(void) +{ + /* ddr2 controller */ + DEFINE(DDR2_DRIC, offsetof(struct mb86r0x_ddr2c, dric)); + DEFINE(DDR2_DRIC1, offsetof(struct mb86r0x_ddr2c, dric1)); + DEFINE(DDR2_DRIC2, offsetof(struct mb86r0x_ddr2c, dric2)); + DEFINE(DDR2_DRCA, offsetof(struct mb86r0x_ddr2c, drca)); + DEFINE(DDR2_DRCM, offsetof(struct mb86r0x_ddr2c, drcm)); + DEFINE(DDR2_DRCST1, offsetof(struct mb86r0x_ddr2c, drcst1)); + DEFINE(DDR2_DRCST2, offsetof(struct mb86r0x_ddr2c, drcst2)); + DEFINE(DDR2_DRCR, offsetof(struct mb86r0x_ddr2c, drcr)); + DEFINE(DDR2_DRCF, offsetof(struct mb86r0x_ddr2c, drcf)); + DEFINE(DDR2_DRASR, offsetof(struct mb86r0x_ddr2c, drasr)); + DEFINE(DDR2_DRIMS, offsetof(struct mb86r0x_ddr2c, drims)); + DEFINE(DDR2_DROS, offsetof(struct mb86r0x_ddr2c, dros)); + DEFINE(DDR2_DRIBSODT1, offsetof(struct mb86r0x_ddr2c, dribsodt1)); + DEFINE(DDR2_DROABA, offsetof(struct mb86r0x_ddr2c, droaba)); + DEFINE(DDR2_DROBS, offsetof(struct mb86r0x_ddr2c, drobs)); + + /* clock reset generator */ + DEFINE(CRG_CRPR, offsetof(struct mb86r0x_crg, crpr)); + DEFINE(CRG_CRHA, offsetof(struct mb86r0x_crg, crha)); + DEFINE(CRG_CRPA, offsetof(struct mb86r0x_crg, crpa)); + DEFINE(CRG_CRPB, offsetof(struct mb86r0x_crg, crpb)); + DEFINE(CRG_CRHB, offsetof(struct mb86r0x_crg, crhb)); + DEFINE(CRG_CRAM, offsetof(struct mb86r0x_crg, cram)); + + /* chip control module */ + DEFINE(CCNT_CDCRC, offsetof(struct mb86r0x_ccnt, cdcrc)); + + /* external bus interface */ + DEFINE(MEMC_MCFMODE0, offsetof(struct mb86r0x_memc, mcfmode[0])); + DEFINE(MEMC_MCFMODE2, offsetof(struct mb86r0x_memc, mcfmode[2])); + DEFINE(MEMC_MCFMODE4, offsetof(struct mb86r0x_memc, mcfmode[4])); + DEFINE(MEMC_MCFTIM0, offsetof(struct mb86r0x_memc, mcftim[0])); + DEFINE(MEMC_MCFTIM2, offsetof(struct mb86r0x_memc, mcftim[2])); + DEFINE(MEMC_MCFTIM4, offsetof(struct mb86r0x_memc, mcftim[4])); + DEFINE(MEMC_MCFAREA0, offsetof(struct mb86r0x_memc, mcfarea[0])); + DEFINE(MEMC_MCFAREA2, offsetof(struct mb86r0x_memc, mcfarea[2])); + DEFINE(MEMC_MCFAREA4, offsetof(struct mb86r0x_memc, mcfarea[4])); + + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/mb86r0x/clock.c b/arch/arm/cpu/arm926ejs/mb86r0x/clock.c new file mode 100644 index 0000000..70c8c8b --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mb86r0x/clock.c @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2010 + * Matthias Weisser <weisserm@arcor.de> + * + * 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 <asm/io.h> +#include <asm/arch/hardware.h> + +/* + * Get the peripheral bus frequency depending on pll pin settings + */ +ulong get_bus_freq(ulong dummy) +{ + struct mb86r0x_crg * crg = (struct mb86r0x_crg *) + MB86R0x_CRG_BASE; + uint32_t pllmode; + + pllmode = readl(&crg->crpr) & MB86R0x_CRG_CRPR_PLLMODE; + + if (pllmode == MB86R0x_CRG_CRPR_PLLMODE_X20) + return 40000000; + + return 41164767; +} diff --git a/arch/arm/cpu/arm926ejs/mb86r0x/reset.c b/arch/arm/cpu/arm926ejs/mb86r0x/reset.c new file mode 100644 index 0000000..e7f0f67 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mb86r0x/reset.c @@ -0,0 +1,40 @@ +/* + * (C) Copyright 2010 + * Matthias Weisser <weisserm@arcor.de> + * + * 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 <asm/io.h> +#include <asm/arch/hardware.h> + +/* + * Reset the cpu by setting software reset request bit + */ +void reset_cpu(ulong ignored) +{ + struct mb86r0x_crg * crg = (struct mb86r0x_crg *) + MB86R0x_CRG_BASE; + + writel(MB86R0x_CRSR_SWRSTREQ, &crg->crsr); + while (1) + /* NOP */; + /* Never reached */ +} diff --git a/arch/arm/cpu/arm926ejs/mb86r0x/timer.c b/arch/arm/cpu/arm926ejs/mb86r0x/timer.c new file mode 100644 index 0000000..c6486c1 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mb86r0x/timer.c @@ -0,0 +1,131 @@ +/* + * (C) Copyright 2007-2008 + * Stelian Pop <stelian@popies.net> + * Lead Tech Design <www.leadtechdesign.com> + * + * (C) Copyright 2010 + * Matthias Weisser, Graf-Syteco <weisserm@arcor.de> + * + * 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 <div64.h> +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> + +#define TIMER_LOAD_VAL 0xffffffff +#define TIMER_FREQ (CONFIG_MB86R0x_IOCLK / 256) + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + tick *= CONFIG_SYS_HZ; + do_div(tick, TIMER_FREQ); + + return tick; +} + +static inline unsigned long long usec_to_tick(unsigned long long usec) +{ + usec *= TIMER_FREQ; + do_div(usec, 1000000); + + return usec; +} + +/* nothing really to do with interrupts, just starts up a counter. */ +int timer_init(void) +{ + struct mb86r0x_timer * timer = (struct mb86r0x_timer *) + MB86R0x_TIMER_BASE; + ulong ctrl = readl(&timer->control); + + writel(TIMER_LOAD_VAL, &timer->load); + + ctrl |= MB86R0x_TIMER_ENABLE | MB86R0x_TIMER_PRS_8S | + MB86R0x_TIMER_SIZE_32; + + writel(ctrl, &timer->control); + + /* capture current value time */ + lastdec = readl(&timer->value); + timestamp = 0; /* start "advancing" time stamp from 0 */ + + return 0; +} + +/* + * timer without interrupts + */ +unsigned long long get_ticks(void) +{ + struct mb86r0x_timer * timer = (struct mb86r0x_timer *) + MB86R0x_TIMER_BASE; + ulong now = readl(&timer->value); + + if (now <= lastdec) { + /* normal mode (non roll) */ + /* move stamp forward with absolut diff ticks */ + timestamp += lastdec - now; + } else { + /* we have rollover of incrementer */ + timestamp += lastdec + TIMER_LOAD_VAL - now; + } + lastdec = now; + return timestamp; +} + +ulong get_timer_masked(void) +{ + return tick_to_time(get_ticks()); +} + +void __udelay(unsigned long usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = usec_to_tick(usec); + tmp = get_ticks(); /* get current timestamp */ + + while ((get_ticks() - tmp) < tmo) /* loop till event */ + /*NOP*/; +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + ulong tbclk; + + tbclk = TIMER_FREQ; + return tbclk; +} diff --git a/arch/arm/cpu/arm926ejs/mx25/Makefile b/arch/arm/cpu/arm926ejs/mx25/Makefile new file mode 100644 index 0000000..3c2a65e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx25/Makefile @@ -0,0 +1,44 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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$(SOC).o + +COBJS = generic.o timer.o reset.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/mx25/asm-offsets.c b/arch/arm/cpu/arm926ejs/mx25/asm-offsets.c new file mode 100644 index 0000000..ba8dfd4 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx25/asm-offsets.c @@ -0,0 +1,60 @@ +/* + * Adapted from Linux v2.6.36 kernel: arch/powerpc/kernel/asm-offsets.c + * + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + * + * 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. + */ + +#include <common.h> +#include <asm/arch/imx-regs.h> + +#include <linux/kbuild.h> + +int main(void) +{ + /* Clock Control Module */ + DEFINE(CCM_CCTL, offsetof(struct ccm_regs, cctl)); + DEFINE(CCM_CGCR0, offsetof(struct ccm_regs, cgr0)); + DEFINE(CCM_CGCR1, offsetof(struct ccm_regs, cgr1)); + DEFINE(CCM_CGCR2, offsetof(struct ccm_regs, cgr2)); + DEFINE(CCM_PCDR2, offsetof(struct ccm_regs, pcdr[2])); + DEFINE(CCM_MCR, offsetof(struct ccm_regs, mcr)); + + /* Enhanced SDRAM Controller */ + DEFINE(ESDRAMC_ESDCTL0, offsetof(struct esdramc_regs, ctl0)); + DEFINE(ESDRAMC_ESDCFG0, offsetof(struct esdramc_regs, cfg0)); + DEFINE(ESDRAMC_ESDMISC, offsetof(struct esdramc_regs, misc)); + + /* Multi-Layer AHB Crossbar Switch */ + DEFINE(MAX_MPR0, offsetof(struct max_regs, mpr0)); + DEFINE(MAX_SGPCR0, offsetof(struct max_regs, sgpcr0)); + DEFINE(MAX_MPR1, offsetof(struct max_regs, mpr1)); + DEFINE(MAX_SGPCR1, offsetof(struct max_regs, sgpcr1)); + DEFINE(MAX_MPR2, offsetof(struct max_regs, mpr2)); + DEFINE(MAX_SGPCR2, offsetof(struct max_regs, sgpcr2)); + DEFINE(MAX_MPR3, offsetof(struct max_regs, mpr3)); + DEFINE(MAX_SGPCR3, offsetof(struct max_regs, sgpcr3)); + DEFINE(MAX_MPR4, offsetof(struct max_regs, mpr4)); + DEFINE(MAX_SGPCR4, offsetof(struct max_regs, sgpcr4)); + DEFINE(MAX_MGPCR0, offsetof(struct max_regs, mgpcr0)); + DEFINE(MAX_MGPCR1, offsetof(struct max_regs, mgpcr1)); + DEFINE(MAX_MGPCR2, offsetof(struct max_regs, mgpcr2)); + DEFINE(MAX_MGPCR3, offsetof(struct max_regs, mgpcr3)); + DEFINE(MAX_MGPCR4, offsetof(struct max_regs, mgpcr4)); + + /* AHB <-> IP-Bus Interface */ + DEFINE(AIPS_MPR_0_7, offsetof(struct aips_regs, mpr_0_7)); + DEFINE(AIPS_MPR_8_15, offsetof(struct aips_regs, mpr_8_15)); + + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/mx25/generic.c b/arch/arm/cpu/arm926ejs/mx25/generic.c new file mode 100644 index 0000000..7cbbe65 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx25/generic.c @@ -0,0 +1,262 @@ +/* + * (C) Copyright 2009 DENX Software Engineering + * Author: John Rigby <jrigby@gmail.com> + * + * Based on mx27/generic.c: + * Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org> + * Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com> + * + * 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 <div64.h> +#include <netdev.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> + +#ifdef CONFIG_FSL_ESDHC +#include <fsl_esdhc.h> + +DECLARE_GLOBAL_DATA_PTR; +#endif + +/* + * get the system pll clock in Hz + * + * mfi + mfn / (mfd +1) + * f = 2 * f_ref * -------------------- + * pd + 1 + */ +static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref) +{ + unsigned int mfi = (pll >> CCM_PLL_MFI_SHIFT) + & CCM_PLL_MFI_MASK; + int mfn = (pll >> CCM_PLL_MFN_SHIFT) + & CCM_PLL_MFN_MASK; + unsigned int mfd = (pll >> CCM_PLL_MFD_SHIFT) + & CCM_PLL_MFD_MASK; + unsigned int pd = (pll >> CCM_PLL_PD_SHIFT) + & CCM_PLL_PD_MASK; + + mfi = mfi <= 5 ? 5 : mfi; + mfn = mfn >= 512 ? mfn - 1024 : mfn; + mfd += 1; + pd += 1; + + return lldiv(2 * (u64) f_ref * (mfi * mfd + mfn), + mfd * pd); +} + +static ulong imx_get_mpllclk(void) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong fref = MXC_HCLK; + + return imx_decode_pll(readl(&ccm->mpctl), fref); +} + +static ulong imx_get_armclk(void) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong cctl = readl(&ccm->cctl); + ulong fref = imx_get_mpllclk(); + ulong div; + + if (cctl & CCM_CCTL_ARM_SRC) + fref = lldiv((u64) fref * 3, 4); + + div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT) + & CCM_CCTL_ARM_DIV_MASK) + 1; + + return fref / div; +} + +static ulong imx_get_ahbclk(void) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong cctl = readl(&ccm->cctl); + ulong fref = imx_get_armclk(); + ulong div; + + div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT) + & CCM_CCTL_AHB_DIV_MASK) + 1; + + return fref / div; +} + +static ulong imx_get_ipgclk(void) +{ + return imx_get_ahbclk() / 2; +} + +static ulong imx_get_perclk(int clk) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong fref = imx_get_ahbclk(); + ulong div; + + div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]); + div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1; + + return fref / div; +} + +unsigned int mxc_get_clock(enum mxc_clock clk) +{ + if (clk >= MXC_CLK_NUM) + return -1; + switch (clk) { + case MXC_ARM_CLK: + return imx_get_armclk(); + case MXC_AHB_CLK: + return imx_get_ahbclk(); + case MXC_IPG_CLK: + case MXC_CSPI_CLK: + case MXC_FEC_CLK: + return imx_get_ipgclk(); + default: + return imx_get_perclk(clk); + } +} + +u32 get_cpu_rev(void) +{ + u32 srev; + u32 system_rev = 0x25000; + + /* read SREV register from IIM module */ + struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; + srev = readl(&iim->iim_srev); + + switch (srev) { + case 0x00: + system_rev |= CHIP_REV_1_0; + break; + case 0x01: + system_rev |= CHIP_REV_1_1; + break; + case 0x02: + system_rev |= CHIP_REV_1_2; + break; + default: + system_rev |= 0x8000; + break; + } + + return system_rev; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +static char *get_reset_cause(void) +{ + /* read RCSR register from CCM module */ + struct ccm_regs *ccm = + (struct ccm_regs *)IMX_CCM_BASE; + + u32 cause = readl(&ccm->rcsr) & 0x0f; + + if (cause == 0) + return "POR"; + else if (cause == 1) + return "RST"; + else if ((cause & 2) == 2) + return "WDOG"; + else if ((cause & 4) == 4) + return "SW RESET"; + else if ((cause & 8) == 8) + return "JTAG"; + else + return "unknown reset"; + +} + +int print_cpuinfo(void) +{ + char buf[32]; + u32 cpurev = get_cpu_rev(); + + printf("CPU: Freescale i.MX25 rev%d.%d%s at %s MHz\n", + (cpurev & 0xF0) >> 4, (cpurev & 0x0F), + ((cpurev & 0x8000) ? " unknown" : ""), + strmhz(buf, imx_get_armclk())); + printf("Reset cause: %s\n\n", get_reset_cause()); + return 0; +} +#endif + +void enable_caches(void) +{ +#ifndef CONFIG_SYS_DCACHE_OFF + /* Enable D-cache. I-cache is already enabled in start.S */ + dcache_enable(); +#endif +} + +#if defined(CONFIG_FEC_MXC) +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + ulong val; + + val = readl(&ccm->cgr0); + val |= (1 << 23); + writel(val, &ccm->cgr0); + return fecmxc_initialize(bis); +} +#endif + +int get_clocks(void) +{ +#ifdef CONFIG_FSL_ESDHC +#if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE + gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK); +#else + gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK); +#endif +#endif + return 0; +} + +#ifdef CONFIG_FSL_ESDHC +/* + * Initializes on-chip MMC controllers. + * to override, implement board_mmc_init() + */ +int cpu_mmc_init(bd_t *bis) +{ + return fsl_esdhc_mmc_init(bis); +} +#endif + +#ifdef CONFIG_FEC_MXC +void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) +{ + int i; + struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; + struct fuse_bank *bank = &iim->bank[0]; + struct fuse_bank0_regs *fuse = + (struct fuse_bank0_regs *)bank->fuse_regs; + + for (i = 0; i < 6; i++) + mac[i] = readl(&fuse->mac_addr[i]) & 0xff; +} +#endif /* CONFIG_FEC_MXC */ diff --git a/arch/arm/cpu/arm926ejs/mx25/reset.c b/arch/arm/cpu/arm926ejs/mx25/reset.c new file mode 100644 index 0000000..e6f1056 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx25/reset.c @@ -0,0 +1,56 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2009 + * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> + * + * 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 <asm/io.h> +#include <asm/arch/imx-regs.h> + +/* + * Reset the cpu by setting up the watchdog timer and let it time out + */ +void reset_cpu(ulong ignored) +{ + struct wdog_regs *regs = (struct wdog_regs *)IMX_WDT_BASE; + /* Disable watchdog and set Time-Out field to 0 */ + writew(0, ®s->wcr); + + /* Write Service Sequence */ + writew(WSR_UNLOCK1, ®s->wsr); + writew(WSR_UNLOCK2, ®s->wsr); + + /* Enable watchdog */ + writew(WCR_WDE, ®s->wcr); + + while (1) ; +} diff --git a/arch/arm/cpu/arm926ejs/mx25/timer.c b/arch/arm/cpu/arm926ejs/mx25/timer.c new file mode 100644 index 0000000..f8bebcc --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx25/timer.c @@ -0,0 +1,182 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2009 + * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> + * + * (C) Copyright 2009 DENX Software Engineering + * Author: John Rigby <jrigby@gmail.com> + * Add support for MX25 + * + * 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 <div64.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp (gd->arch.tbl) +#define lastinc (gd->arch.lastinc) + +/* + * "time" is measured in 1 / CONFIG_SYS_HZ seconds, + * "tick" is internal timer period + */ +#ifdef CONFIG_MX25_TIMER_HIGH_PRECISION +/* ~0.4% error - measured with stop-watch on 100s boot-delay */ +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + tick *= CONFIG_SYS_HZ; + do_div(tick, MXC_CLK32); + return tick; +} + +static inline unsigned long long time_to_tick(unsigned long long time) +{ + time *= MXC_CLK32; + do_div(time, CONFIG_SYS_HZ); + return time; +} + +static inline unsigned long long us_to_tick(unsigned long long us) +{ + us = us * MXC_CLK32 + 999999; + do_div(us, 1000000); + return us; +} +#else +/* ~2% error */ +#define TICK_PER_TIME ((MXC_CLK32 + CONFIG_SYS_HZ / 2) / CONFIG_SYS_HZ) +#define US_PER_TICK (1000000 / MXC_CLK32) + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + do_div(tick, TICK_PER_TIME); + return tick; +} + +static inline unsigned long long time_to_tick(unsigned long long time) +{ + return time * TICK_PER_TIME; +} + +static inline unsigned long long us_to_tick(unsigned long long us) +{ + us += US_PER_TICK - 1; + do_div(us, US_PER_TICK); + return us; +} +#endif + +/* nothing really to do with interrupts, just starts up a counter. */ +/* The 32KHz 32-bit timer overruns in 134217 seconds */ +int timer_init(void) +{ + int i; + struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE; + struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE; + + /* setup GP Timer 1 */ + writel(GPT_CTRL_SWR, &gpt->ctrl); + + writel(readl(&ccm->cgr1) | CCM_CGR1_GPT1, &ccm->cgr1); + + for (i = 0; i < 100; i++) + writel(0, &gpt->ctrl); /* We have no udelay by now */ + writel(0, &gpt->pre); /* prescaler = 1 */ + /* Freerun Mode, 32KHz input */ + writel(readl(&gpt->ctrl) | GPT_CTRL_CLKSOURCE_32 | GPT_CTRL_FRR, + &gpt->ctrl); + writel(readl(&gpt->ctrl) | GPT_CTRL_TEN, &gpt->ctrl); + + return 0; +} + +unsigned long long get_ticks(void) +{ + struct gpt_regs *gpt = (struct gpt_regs *)IMX_GPT1_BASE; + ulong now = readl(&gpt->counter); /* current tick value */ + + if (now >= lastinc) { + /* + * normal mode (non roll) + * move stamp forward with absolut diff ticks + */ + timestamp += (now - lastinc); + } else { + /* we have rollover of incrementer */ + timestamp += (0xFFFFFFFF - lastinc) + now; + } + lastinc = now; + return timestamp; +} + +ulong get_timer_masked(void) +{ + /* + * get_ticks() returns a long long (64 bit), it wraps in + * 2^64 / MXC_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ + * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in + * 5 * 10^6 days - long enough. + */ + return tick_to_time(get_ticks()); +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* delay x useconds AND preserve advance timstamp value */ +void __udelay(unsigned long usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = us_to_tick(usec); + tmp = get_ticks() + tmo; /* get current timestamp */ + + while (get_ticks() < tmp) /* loop till event */ + /*NOP*/; +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + ulong tbclk; + + tbclk = MXC_CLK32; + return tbclk; +} diff --git a/arch/arm/cpu/arm926ejs/mx27/Makefile b/arch/arm/cpu/arm926ejs/mx27/Makefile new file mode 100644 index 0000000..0e112b3 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx27/Makefile @@ -0,0 +1,44 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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$(SOC).o + +COBJS = generic.o reset.o timer.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/mx27/asm-offsets.c b/arch/arm/cpu/arm926ejs/mx27/asm-offsets.c new file mode 100644 index 0000000..f3a8d7b --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx27/asm-offsets.c @@ -0,0 +1,45 @@ +/* + * Adapted from Linux v2.6.36 kernel: arch/powerpc/kernel/asm-offsets.c + * + * This program is used to generate definitions needed by + * assembly language modules. + * + * We use the technique used in the OSF Mach kernel code: + * generate asm statements containing #defines, + * compile this file to assembler, and then extract the + * #defines from the assembly-language output. + * + * 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. + */ + +#include <common.h> +#include <asm/arch/imx-regs.h> + +#include <linux/kbuild.h> + +int main(void) +{ + DEFINE(AIPI1_PSR0, IMX_AIPI1_BASE + offsetof(struct aipi_regs, psr0)); + DEFINE(AIPI1_PSR1, IMX_AIPI1_BASE + offsetof(struct aipi_regs, psr1)); + DEFINE(AIPI2_PSR0, IMX_AIPI2_BASE + offsetof(struct aipi_regs, psr0)); + DEFINE(AIPI2_PSR1, IMX_AIPI2_BASE + offsetof(struct aipi_regs, psr1)); + + DEFINE(CSCR, IMX_PLL_BASE + offsetof(struct pll_regs, cscr)); + DEFINE(MPCTL0, IMX_PLL_BASE + offsetof(struct pll_regs, mpctl0)); + DEFINE(SPCTL0, IMX_PLL_BASE + offsetof(struct pll_regs, spctl0)); + DEFINE(PCDR0, IMX_PLL_BASE + offsetof(struct pll_regs, pcdr0)); + DEFINE(PCDR1, IMX_PLL_BASE + offsetof(struct pll_regs, pcdr1)); + DEFINE(PCCR0, IMX_PLL_BASE + offsetof(struct pll_regs, pccr0)); + DEFINE(PCCR1, IMX_PLL_BASE + offsetof(struct pll_regs, pccr1)); + + DEFINE(ESDCTL0_ROF, offsetof(struct esdramc_regs, esdctl0)); + DEFINE(ESDCFG0_ROF, offsetof(struct esdramc_regs, esdcfg0)); + DEFINE(ESDCTL1_ROF, offsetof(struct esdramc_regs, esdctl1)); + DEFINE(ESDCFG1_ROF, offsetof(struct esdramc_regs, esdcfg1)); + DEFINE(ESDMISC_ROF, offsetof(struct esdramc_regs, esdmisc)); + + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/mx27/generic.c b/arch/arm/cpu/arm926ejs/mx27/generic.c new file mode 100644 index 0000000..a9a13cb --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx27/generic.c @@ -0,0 +1,392 @@ +/* + * Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org> + * Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com> + * + * 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 <div64.h> +#include <netdev.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/clock.h> +#include <asm/arch/gpio.h> +#ifdef CONFIG_MXC_MMC +#include <asm/arch/mxcmmc.h> +#endif + +/* + * get the system pll clock in Hz + * + * mfi + mfn / (mfd +1) + * f = 2 * f_ref * -------------------- + * pd + 1 + */ +static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref) +{ + unsigned int mfi = (pll >> 10) & 0xf; + unsigned int mfn = pll & 0x3ff; + unsigned int mfd = (pll >> 16) & 0x3ff; + unsigned int pd = (pll >> 26) & 0xf; + + mfi = mfi <= 5 ? 5 : mfi; + + return lldiv(2 * (u64)f_ref * (mfi * (mfd + 1) + mfn), + (mfd + 1) * (pd + 1)); +} + +static ulong clk_in_32k(void) +{ + return 1024 * CONFIG_MX27_CLK32; +} + +static ulong clk_in_26m(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + if (readl(&pll->cscr) & CSCR_OSC26M_DIV1P5) { + /* divide by 1.5 */ + return 26000000 * 2 / 3; + } else { + return 26000000; + } +} + +static ulong imx_get_mpllclk(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + ulong cscr = readl(&pll->cscr); + ulong fref; + + if (cscr & CSCR_MCU_SEL) + fref = clk_in_26m(); + else + fref = clk_in_32k(); + + return imx_decode_pll(readl(&pll->mpctl0), fref); +} + +static ulong imx_get_armclk(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + ulong cscr = readl(&pll->cscr); + ulong fref = imx_get_mpllclk(); + ulong div; + + if (!(cscr & CSCR_ARM_SRC_MPLL)) + fref = lldiv((fref * 2), 3); + + div = ((cscr >> 12) & 0x3) + 1; + + return lldiv(fref, div); +} + +static ulong imx_get_ahbclk(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + ulong cscr = readl(&pll->cscr); + ulong fref = imx_get_mpllclk(); + ulong div; + + div = ((cscr >> 8) & 0x3) + 1; + + return lldiv(fref * 2, 3 * div); +} + +static __attribute__((unused)) ulong imx_get_spllclk(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + ulong cscr = readl(&pll->cscr); + ulong fref; + + if (cscr & CSCR_SP_SEL) + fref = clk_in_26m(); + else + fref = clk_in_32k(); + + return imx_decode_pll(readl(&pll->spctl0), fref); +} + +static ulong imx_decode_perclk(ulong div) +{ + return lldiv((imx_get_mpllclk() * 2), (div * 3)); +} + +static ulong imx_get_perclk1(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + return imx_decode_perclk((readl(&pll->pcdr1) & 0x3f) + 1); +} + +static ulong imx_get_perclk2(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + return imx_decode_perclk(((readl(&pll->pcdr1) >> 8) & 0x3f) + 1); +} + +static __attribute__((unused)) ulong imx_get_perclk3(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + return imx_decode_perclk(((readl(&pll->pcdr1) >> 16) & 0x3f) + 1); +} + +static __attribute__((unused)) ulong imx_get_perclk4(void) +{ + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + return imx_decode_perclk(((readl(&pll->pcdr1) >> 24) & 0x3f) + 1); +} + +unsigned int mxc_get_clock(enum mxc_clock clk) +{ + switch (clk) { + case MXC_ARM_CLK: + return imx_get_armclk(); + case MXC_I2C_CLK: + return imx_get_ahbclk()/2; + case MXC_UART_CLK: + return imx_get_perclk1(); + case MXC_FEC_CLK: + return imx_get_ahbclk(); + case MXC_ESDHC_CLK: + return imx_get_perclk2(); + } + return -1; +} + + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo (void) +{ + char buf[32]; + + printf("CPU: Freescale i.MX27 at %s MHz\n\n", + strmhz(buf, imx_get_mpllclk())); + return 0; +} +#endif + +int cpu_eth_init(bd_t *bis) +{ +#if defined(CONFIG_FEC_MXC) + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + /* enable FEC clock */ + writel(readl(&pll->pccr1) | PCCR1_HCLK_FEC, &pll->pccr1); + writel(readl(&pll->pccr0) | PCCR0_FEC_EN, &pll->pccr0); + return fecmxc_initialize(bis); +#else + return 0; +#endif +} + +/* + * Initializes on-chip MMC controllers. + * to override, implement board_mmc_init() + */ +int cpu_mmc_init(bd_t *bis) +{ +#ifdef CONFIG_MXC_MMC + return mxc_mmc_init(bis); +#else + return 0; +#endif +} + +void imx_gpio_mode(int gpio_mode) +{ + struct gpio_port_regs *regs = (struct gpio_port_regs *)IMX_GPIO_BASE; + unsigned int pin = gpio_mode & GPIO_PIN_MASK; + unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT; + unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT; + unsigned int aout = (gpio_mode & GPIO_AOUT_MASK) >> GPIO_AOUT_SHIFT; + unsigned int bout = (gpio_mode & GPIO_BOUT_MASK) >> GPIO_BOUT_SHIFT; + unsigned int tmp; + + /* Pullup enable */ + if (gpio_mode & GPIO_PUEN) { + writel(readl(®s->port[port].puen) | (1 << pin), + ®s->port[port].puen); + } else { + writel(readl(®s->port[port].puen) & ~(1 << pin), + ®s->port[port].puen); + } + + /* Data direction */ + if (gpio_mode & GPIO_OUT) { + writel(readl(®s->port[port].gpio_dir) | 1 << pin, + ®s->port[port].gpio_dir); + } else { + writel(readl(®s->port[port].gpio_dir) & ~(1 << pin), + ®s->port[port].gpio_dir); + } + + /* Primary / alternate function */ + if (gpio_mode & GPIO_AF) { + writel(readl(®s->port[port].gpr) | (1 << pin), + ®s->port[port].gpr); + } else { + writel(readl(®s->port[port].gpr) & ~(1 << pin), + ®s->port[port].gpr); + } + + /* use as gpio? */ + if (!(gpio_mode & (GPIO_PF | GPIO_AF))) { + writel(readl(®s->port[port].gius) | (1 << pin), + ®s->port[port].gius); + } else { + writel(readl(®s->port[port].gius) & ~(1 << pin), + ®s->port[port].gius); + } + + /* Output / input configuration */ + if (pin < 16) { + tmp = readl(®s->port[port].ocr1); + tmp &= ~(3 << (pin * 2)); + tmp |= (ocr << (pin * 2)); + writel(tmp, ®s->port[port].ocr1); + + writel(readl(®s->port[port].iconfa1) & ~(3 << (pin * 2)), + ®s->port[port].iconfa1); + writel(readl(®s->port[port].iconfa1) | aout << (pin * 2), + ®s->port[port].iconfa1); + writel(readl(®s->port[port].iconfb1) & ~(3 << (pin * 2)), + ®s->port[port].iconfb1); + writel(readl(®s->port[port].iconfb1) | bout << (pin * 2), + ®s->port[port].iconfb1); + } else { + pin -= 16; + + tmp = readl(®s->port[port].ocr2); + tmp &= ~(3 << (pin * 2)); + tmp |= (ocr << (pin * 2)); + writel(tmp, ®s->port[port].ocr2); + + writel(readl(®s->port[port].iconfa2) & ~(3 << (pin * 2)), + ®s->port[port].iconfa2); + writel(readl(®s->port[port].iconfa2) | aout << (pin * 2), + ®s->port[port].iconfa2); + writel(readl(®s->port[port].iconfb2) & ~(3 << (pin * 2)), + ®s->port[port].iconfb2); + writel(readl(®s->port[port].iconfb2) | bout << (pin * 2), + ®s->port[port].iconfb2); + } +} + +#ifdef CONFIG_MXC_UART +void mx27_uart1_init_pins(void) +{ + int i; + unsigned int mode[] = { + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + }; + + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + +} +#endif /* CONFIG_MXC_UART */ + +#ifdef CONFIG_FEC_MXC +void mx27_fec_init_pins(void) +{ + int i; + unsigned int mode[] = { + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC | GPIO_PUEN, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_CLR, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + }; + + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); +} + +void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) +{ + int i; + struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE; + struct fuse_bank *bank = &iim->bank[0]; + struct fuse_bank0_regs *fuse = + (struct fuse_bank0_regs *)bank->fuse_regs; + + for (i = 0; i < 6; i++) + mac[6 - 1 - i] = readl(&fuse->mac_addr[i]) & 0xff; +} +#endif /* CONFIG_FEC_MXC */ + +#ifdef CONFIG_MXC_MMC +void mx27_sd1_init_pins(void) +{ + int i; + unsigned int mode[] = { + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + }; + + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + +} + +void mx27_sd2_init_pins(void) +{ + int i; + unsigned int mode[] = { + PB4_PF_SD2_D0, + PB5_PF_SD2_D1, + PB6_PF_SD2_D2, + PB7_PF_SD2_D3, + PB8_PF_SD2_CMD, + PB9_PF_SD2_CLK, + }; + + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + +} +#endif /* CONFIG_MXC_MMC */ + +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ + /* Enable D-cache. I-cache is already enabled in start.S */ + dcache_enable(); +} +#endif /* CONFIG_SYS_DCACHE_OFF */ diff --git a/arch/arm/cpu/arm926ejs/mx27/reset.c b/arch/arm/cpu/arm926ejs/mx27/reset.c new file mode 100644 index 0000000..cc0a33e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx27/reset.c @@ -0,0 +1,57 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2009 + * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> + * + * 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 <asm/io.h> +#include <asm/arch/imx-regs.h> + +/* + * Reset the cpu by setting up the watchdog timer and let it time out + */ +void reset_cpu(ulong ignored) +{ + struct wdog_regs *regs = (struct wdog_regs *)IMX_WDT_BASE; + /* Disable watchdog and set Time-Out field to 0 */ + writel(0x00000000, ®s->wcr); + + /* Write Service Sequence */ + writel(0x00005555, ®s->wsr); + writel(0x0000AAAA, ®s->wsr); + + /* Enable watchdog */ + writel(WCR_WDE, ®s->wcr); + + while (1); + /*NOTREACHED*/ +} diff --git a/arch/arm/cpu/arm926ejs/mx27/timer.c b/arch/arm/cpu/arm926ejs/mx27/timer.c new file mode 100644 index 0000000..07e132a --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mx27/timer.c @@ -0,0 +1,178 @@ +/* + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2009 + * Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com> + * + * 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 <div64.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +/* General purpose timers bitfields */ +#define GPTCR_SWR (1 << 15) /* Software reset */ +#define GPTCR_FRR (1 << 8) /* Freerun / restart */ +#define GPTCR_CLKSOURCE_32 (4 << 1) /* Clock source */ +#define GPTCR_TEN 1 /* Timer enable */ + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp (gd->arch.tbl) +#define lastinc (gd->arch.lastinc) + +/* + * "time" is measured in 1 / CONFIG_SYS_HZ seconds, + * "tick" is internal timer period + */ +#ifdef CONFIG_MX27_TIMER_HIGH_PRECISION +/* ~0.4% error - measured with stop-watch on 100s boot-delay */ +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + tick *= CONFIG_SYS_HZ; + do_div(tick, CONFIG_MX27_CLK32); + return tick; +} + +static inline unsigned long long time_to_tick(unsigned long long time) +{ + time *= CONFIG_MX27_CLK32; + do_div(time, CONFIG_SYS_HZ); + return time; +} + +static inline unsigned long long us_to_tick(unsigned long long us) +{ + us = us * CONFIG_MX27_CLK32 + 999999; + do_div(us, 1000000); + return us; +} +#else +/* ~2% error */ +#define TICK_PER_TIME ((CONFIG_MX27_CLK32 + CONFIG_SYS_HZ / 2) / \ + CONFIG_SYS_HZ) +#define US_PER_TICK (1000000 / CONFIG_MX27_CLK32) + +static inline unsigned long long tick_to_time(unsigned long long tick) +{ + do_div(tick, TICK_PER_TIME); + return tick; +} + +static inline unsigned long long time_to_tick(unsigned long long time) +{ + return time * TICK_PER_TIME; +} + +static inline unsigned long long us_to_tick(unsigned long long us) +{ + us += US_PER_TICK - 1; + do_div(us, US_PER_TICK); + return us; +} +#endif + +/* nothing really to do with interrupts, just starts up a counter. */ +/* The 32768Hz 32-bit timer overruns in 131072 seconds */ +int timer_init(void) +{ + int i; + struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; + struct pll_regs *pll = (struct pll_regs *)IMX_PLL_BASE; + + /* setup GP Timer 1 */ + writel(GPTCR_SWR, ®s->gpt_tctl); + + writel(readl(&pll->pccr0) | PCCR0_GPT1_EN, &pll->pccr0); + writel(readl(&pll->pccr1) | PCCR1_PERCLK1_EN, &pll->pccr1); + + for (i = 0; i < 100; i++) + writel(0, ®s->gpt_tctl); /* We have no udelay by now */ + writel(0, ®s->gpt_tprer); /* 32Khz */ + /* Freerun Mode, PERCLK1 input */ + writel(readl(®s->gpt_tctl) | GPTCR_CLKSOURCE_32 | GPTCR_FRR, + ®s->gpt_tctl); + writel(readl(®s->gpt_tctl) | GPTCR_TEN, ®s->gpt_tctl); + + return 0; +} + +unsigned long long get_ticks(void) +{ + struct gpt_regs *regs = (struct gpt_regs *)IMX_TIM1_BASE; + ulong now = readl(®s->gpt_tcn); /* current tick value */ + + if (now >= lastinc) { + /* + * normal mode (non roll) + * move stamp forward with absolut diff ticks + */ + timestamp += (now - lastinc); + } else { + /* we have rollover of incrementer */ + timestamp += (0xFFFFFFFF - lastinc) + now; + } + lastinc = now; + return timestamp; +} + +ulong get_timer_masked(void) +{ + /* + * get_ticks() returns a long long (64 bit), it wraps in + * 2^64 / CONFIG_MX27_CLK32 = 2^64 / 2^15 = 2^49 ~ 5 * 10^14 (s) ~ + * 5 * 10^9 days... and get_ticks() * CONFIG_SYS_HZ wraps in + * 5 * 10^6 days - long enough. + */ + return tick_to_time(get_ticks()); +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* delay x useconds AND preserve advance timstamp value */ +void __udelay(unsigned long usec) +{ + unsigned long long tmp; + ulong tmo; + + tmo = us_to_tick(usec); + tmp = get_ticks() + tmo; /* get current timestamp */ + + while (get_ticks() < tmp) /* loop till event */ + /*NOP*/; +} + +ulong get_tbclk(void) +{ + return CONFIG_MX27_CLK32; +} diff --git a/arch/arm/cpu/arm926ejs/mxs/Makefile b/arch/arm/cpu/arm926ejs/mxs/Makefile new file mode 100644 index 0000000..038c1c1 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/Makefile @@ -0,0 +1,60 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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$(SOC).o + +COBJS = clock.o mxs.o iomux.o timer.o + +ifdef CONFIG_SPL_BUILD +COBJS += spl_boot.o spl_lradc_init.o spl_mem_init.o spl_power_init.o +endif + +SRCS := $(START:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +# Specify the target for use in elftosb call +ELFTOSB_TARGET-$(CONFIG_MX23) = imx23 +ELFTOSB_TARGET-$(CONFIG_MX28) = imx28 + +$(OBJTREE)/u-boot.bd: $(SRCTREE)/$(CPUDIR)/$(SOC)/u-boot-$(ELFTOSB_TARGET-y).bd + sed "s@OBJTREE@$(OBJTREE)@g" $^ > $@ + +$(OBJTREE)/u-boot.sb: $(OBJTREE)/u-boot.bin $(OBJTREE)/spl/u-boot-spl.bin $(OBJTREE)/u-boot.bd + elftosb -zf $(ELFTOSB_TARGET-y) -c $(OBJTREE)/u-boot.bd -o $(OBJTREE)/u-boot.sb + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c b/arch/arm/cpu/arm926ejs/mxs/clock.c new file mode 100644 index 0000000..f94107f --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/clock.c @@ -0,0 +1,452 @@ +/* + * Freescale i.MX23/i.MX28 clock setup code + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * 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 <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/imx-regs.h> + +/* + * The PLL frequency is 480MHz and XTAL frequency is 24MHz + * iMX23: datasheet section 4.2 + * iMX28: datasheet section 10.2 + */ +#define PLL_FREQ_KHZ 480000 +#define PLL_FREQ_COEF 18 +#define XTAL_FREQ_KHZ 24000 + +#define PLL_FREQ_MHZ (PLL_FREQ_KHZ / 1000) +#define XTAL_FREQ_MHZ (XTAL_FREQ_KHZ / 1000) + +#if defined(CONFIG_MX23) +#define MXC_SSPCLK_MAX MXC_SSPCLK0 +#elif defined(CONFIG_MX28) +#define MXC_SSPCLK_MAX MXC_SSPCLK3 +#endif + +static uint32_t mxs_get_pclk(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + uint32_t clkctrl, clkseq, div; + uint8_t clkfrac, frac; + + clkctrl = readl(&clkctrl_regs->hw_clkctrl_cpu); + + /* No support of fractional divider calculation */ + if (clkctrl & + (CLKCTRL_CPU_DIV_XTAL_FRAC_EN | CLKCTRL_CPU_DIV_CPU_FRAC_EN)) { + return 0; + } + + clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); + + /* XTAL Path */ + if (clkseq & CLKCTRL_CLKSEQ_BYPASS_CPU) { + div = (clkctrl & CLKCTRL_CPU_DIV_XTAL_MASK) >> + CLKCTRL_CPU_DIV_XTAL_OFFSET; + return XTAL_FREQ_MHZ / div; + } + + /* REF Path */ + clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]); + frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; + div = clkctrl & CLKCTRL_CPU_DIV_CPU_MASK; + return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; +} + +static uint32_t mxs_get_hclk(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + uint32_t div; + uint32_t clkctrl; + + clkctrl = readl(&clkctrl_regs->hw_clkctrl_hbus); + + /* No support of fractional divider calculation */ + if (clkctrl & CLKCTRL_HBUS_DIV_FRAC_EN) + return 0; + + div = clkctrl & CLKCTRL_HBUS_DIV_MASK; + return mxs_get_pclk() / div; +} + +static uint32_t mxs_get_emiclk(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + uint32_t clkctrl, clkseq, div; + uint8_t clkfrac, frac; + + clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); + clkctrl = readl(&clkctrl_regs->hw_clkctrl_emi); + + /* XTAL Path */ + if (clkseq & CLKCTRL_CLKSEQ_BYPASS_EMI) { + div = (clkctrl & CLKCTRL_EMI_DIV_XTAL_MASK) >> + CLKCTRL_EMI_DIV_XTAL_OFFSET; + return XTAL_FREQ_MHZ / div; + } + + /* REF Path */ + clkfrac = readb(&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]); + frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; + div = clkctrl & CLKCTRL_EMI_DIV_EMI_MASK; + return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; +} + +static uint32_t mxs_get_gpmiclk(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; +#if defined(CONFIG_MX23) + uint8_t *reg = + &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]; +#elif defined(CONFIG_MX28) + uint8_t *reg = + &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI]; +#endif + uint32_t clkctrl, clkseq, div; + uint8_t clkfrac, frac; + + clkseq = readl(&clkctrl_regs->hw_clkctrl_clkseq); + clkctrl = readl(&clkctrl_regs->hw_clkctrl_gpmi); + + /* XTAL Path */ + if (clkseq & CLKCTRL_CLKSEQ_BYPASS_GPMI) { + div = clkctrl & CLKCTRL_GPMI_DIV_MASK; + return XTAL_FREQ_MHZ / div; + } + + /* REF Path */ + clkfrac = readb(reg); + frac = clkfrac & CLKCTRL_FRAC_FRAC_MASK; + div = clkctrl & CLKCTRL_GPMI_DIV_MASK; + return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div; +} + +/* + * Set IO clock frequency, in kHz + */ +void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint32_t div; + int io_reg; + + if (freq == 0) + return; + + if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1)) + return; + + div = (PLL_FREQ_KHZ * PLL_FREQ_COEF) / freq; + + if (div < 18) + div = 18; + + if (div > 35) + div = 35; + + io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */ + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_set[io_reg]); + writeb(CLKCTRL_FRAC_CLKGATE | (div & CLKCTRL_FRAC_FRAC_MASK), + &clkctrl_regs->hw_clkctrl_frac0[io_reg]); + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_clr[io_reg]); +} + +/* + * Get IO clock, returns IO clock in kHz + */ +static uint32_t mxs_get_ioclk(enum mxs_ioclock io) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint8_t ret; + int io_reg; + + if ((io < MXC_IOCLK0) || (io > MXC_IOCLK1)) + return 0; + + io_reg = CLKCTRL_FRAC0_IO0 - io; /* Register order is reversed */ + + ret = readb(&clkctrl_regs->hw_clkctrl_frac0[io_reg]) & + CLKCTRL_FRAC_FRAC_MASK; + + return (PLL_FREQ_KHZ * PLL_FREQ_COEF) / ret; +} + +/* + * Configure SSP clock frequency, in kHz + */ +void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint32_t clk, clkreg; + + if (ssp > MXC_SSPCLK_MAX) + return; + + clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) + + (ssp * sizeof(struct mxs_register_32)); + + clrbits_le32(clkreg, CLKCTRL_SSP_CLKGATE); + while (readl(clkreg) & CLKCTRL_SSP_CLKGATE) + ; + + if (xtal) + clk = XTAL_FREQ_KHZ; + else + clk = mxs_get_ioclk(ssp >> 1); + + if (freq > clk) + return; + + /* Calculate the divider and cap it if necessary */ + clk /= freq; + if (clk > CLKCTRL_SSP_DIV_MASK) + clk = CLKCTRL_SSP_DIV_MASK; + + clrsetbits_le32(clkreg, CLKCTRL_SSP_DIV_MASK, clk); + while (readl(clkreg) & CLKCTRL_SSP_BUSY) + ; + + if (xtal) + writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp, + &clkctrl_regs->hw_clkctrl_clkseq_set); + else + writel(CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp, + &clkctrl_regs->hw_clkctrl_clkseq_clr); +} + +/* + * Return SSP frequency, in kHz + */ +static uint32_t mxs_get_sspclk(enum mxs_sspclock ssp) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint32_t clkreg; + uint32_t clk, tmp; + + if (ssp > MXC_SSPCLK_MAX) + return 0; + + tmp = readl(&clkctrl_regs->hw_clkctrl_clkseq); + if (tmp & (CLKCTRL_CLKSEQ_BYPASS_SSP0 << ssp)) + return XTAL_FREQ_KHZ; + + clkreg = (uint32_t)(&clkctrl_regs->hw_clkctrl_ssp0) + + (ssp * sizeof(struct mxs_register_32)); + + tmp = readl(clkreg) & CLKCTRL_SSP_DIV_MASK; + + if (tmp == 0) + return 0; + + clk = mxs_get_ioclk(ssp >> 1); + + return clk / tmp; +} + +/* + * Set SSP/MMC bus frequency, in kHz) + */ +void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq) +{ + struct mxs_ssp_regs *ssp_regs; + const enum mxs_sspclock clk = mxs_ssp_clock_by_bus(bus); + const uint32_t sspclk = mxs_get_sspclk(clk); + uint32_t reg; + uint32_t divide, rate, tgtclk; + + ssp_regs = mxs_ssp_regs_by_bus(bus); + + /* + * SSP bit rate = SSPCLK / (CLOCK_DIVIDE * (1 + CLOCK_RATE)), + * CLOCK_DIVIDE has to be an even value from 2 to 254, and + * CLOCK_RATE could be any integer from 0 to 255. + */ + for (divide = 2; divide < 254; divide += 2) { + rate = sspclk / freq / divide; + if (rate <= 256) + break; + } + + tgtclk = sspclk / divide / rate; + while (tgtclk > freq) { + rate++; + tgtclk = sspclk / divide / rate; + } + if (rate > 256) + rate = 256; + + /* Always set timeout the maximum */ + reg = SSP_TIMING_TIMEOUT_MASK | + (divide << SSP_TIMING_CLOCK_DIVIDE_OFFSET) | + ((rate - 1) << SSP_TIMING_CLOCK_RATE_OFFSET); + writel(reg, &ssp_regs->hw_ssp_timing); + + debug("SPI%d: Set freq rate to %d KHz (requested %d KHz)\n", + bus, tgtclk, freq); +} + +void mxs_set_lcdclk(uint32_t freq) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + uint32_t fp, x, k_rest, k_best, x_best, tk; + int32_t k_best_l = 999, k_best_t = 0, x_best_l = 0xff, x_best_t = 0xff; + + if (freq == 0) + return; + +#if defined(CONFIG_MX23) + writel(CLKCTRL_CLKSEQ_BYPASS_PIX, &clkctrl_regs->hw_clkctrl_clkseq_clr); +#elif defined(CONFIG_MX28) + writel(CLKCTRL_CLKSEQ_BYPASS_DIS_LCDIF, &clkctrl_regs->hw_clkctrl_clkseq_clr); +#endif + + /* + * / 18 \ 1 1 + * freq kHz = | 480000000 Hz * -- | * --- * ------ + * \ x / k 1000 + * + * 480000000 Hz 18 + * ------------ * -- + * freq kHz x + * k = ------------------- + * 1000 + */ + + fp = ((PLL_FREQ_KHZ * 1000) / freq) * 18; + + for (x = 18; x <= 35; x++) { + tk = fp / x; + if ((tk / 1000 == 0) || (tk / 1000 > 255)) + continue; + + k_rest = tk % 1000; + + if (k_rest < (k_best_l % 1000)) { + k_best_l = tk; + x_best_l = x; + } + + if (k_rest > (k_best_t % 1000)) { + k_best_t = tk; + x_best_t = x; + } + } + + if (1000 - (k_best_t % 1000) > (k_best_l % 1000)) { + k_best = k_best_l; + x_best = x_best_l; + } else { + k_best = k_best_t; + x_best = x_best_t; + } + + k_best /= 1000; + +#if defined(CONFIG_MX23) + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_PIX]); + writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK), + &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_PIX]); + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_PIX]); + + writel(CLKCTRL_PIX_CLKGATE, + &clkctrl_regs->hw_clkctrl_pix_set); + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_pix, + CLKCTRL_PIX_DIV_MASK | CLKCTRL_PIX_CLKGATE, + k_best << CLKCTRL_PIX_DIV_OFFSET); + + while (readl(&clkctrl_regs->hw_clkctrl_pix) & CLKCTRL_PIX_BUSY) + ; +#elif defined(CONFIG_MX28) + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_PIX]); + writeb(CLKCTRL_FRAC_CLKGATE | (x_best & CLKCTRL_FRAC_FRAC_MASK), + &clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_PIX]); + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_PIX]); + + writel(CLKCTRL_DIS_LCDIF_CLKGATE, + &clkctrl_regs->hw_clkctrl_lcdif_set); + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_lcdif, + CLKCTRL_DIS_LCDIF_DIV_MASK | CLKCTRL_DIS_LCDIF_CLKGATE, + k_best << CLKCTRL_DIS_LCDIF_DIV_OFFSET); + + while (readl(&clkctrl_regs->hw_clkctrl_lcdif) & CLKCTRL_DIS_LCDIF_BUSY) + ; +#endif +} + +uint32_t mxc_get_clock(enum mxc_clock clk) +{ + switch (clk) { + case MXC_ARM_CLK: + return mxs_get_pclk() * 1000000; + case MXC_GPMI_CLK: + return mxs_get_gpmiclk() * 1000000; + case MXC_AHB_CLK: + case MXC_IPG_CLK: + return mxs_get_hclk() * 1000000; + case MXC_EMI_CLK: + return mxs_get_emiclk(); + case MXC_IO0_CLK: + return mxs_get_ioclk(MXC_IOCLK0); + case MXC_IO1_CLK: + return mxs_get_ioclk(MXC_IOCLK1); + case MXC_XTAL_CLK: + return XTAL_FREQ_KHZ * 1000; + case MXC_SSP0_CLK: + return mxs_get_sspclk(MXC_SSPCLK0); +#ifdef CONFIG_MX28 + case MXC_SSP1_CLK: + return mxs_get_sspclk(MXC_SSPCLK1); + case MXC_SSP2_CLK: + return mxs_get_sspclk(MXC_SSPCLK2); + case MXC_SSP3_CLK: + return mxs_get_sspclk(MXC_SSPCLK3); +#endif + } + + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/mxs/iomux.c b/arch/arm/cpu/arm926ejs/mxs/iomux.c new file mode 100644 index 0000000..73f1446 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/iomux.c @@ -0,0 +1,109 @@ +/* + * Copyright 2004-2006,2010 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de> + * Copyright (C) 2009 by Jan Weitzel Phytec Messtechnik GmbH, + * <armlinux@phytec.de> + * + * 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 <common.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/iomux.h> +#include <asm/arch/imx-regs.h> + +#if defined(CONFIG_MX23) +#define DRIVE_OFFSET 0x200 +#define PULL_OFFSET 0x400 +#elif defined(CONFIG_MX28) +#define DRIVE_OFFSET 0x300 +#define PULL_OFFSET 0x600 +#else +#error "Please select CONFIG_MX23 or CONFIG_MX28" +#endif + +/* + * configures a single pad in the iomuxer + */ +int mxs_iomux_setup_pad(iomux_cfg_t pad) +{ + u32 reg, ofs, bp, bm; + void *iomux_base = (void *)MXS_PINCTRL_BASE; + struct mxs_register_32 *mxs_reg; + + /* muxsel */ + ofs = 0x100; + ofs += PAD_BANK(pad) * 0x20 + PAD_PIN(pad) / 16 * 0x10; + bp = PAD_PIN(pad) % 16 * 2; + bm = 0x3 << bp; + reg = readl(iomux_base + ofs); + reg &= ~bm; + reg |= PAD_MUXSEL(pad) << bp; + writel(reg, iomux_base + ofs); + + /* drive */ + ofs = DRIVE_OFFSET; + ofs += PAD_BANK(pad) * 0x40 + PAD_PIN(pad) / 8 * 0x10; + /* mA */ + if (PAD_MA_VALID(pad)) { + bp = PAD_PIN(pad) % 8 * 4; + bm = 0x3 << bp; + reg = readl(iomux_base + ofs); + reg &= ~bm; + reg |= PAD_MA(pad) << bp; + writel(reg, iomux_base + ofs); + } + /* vol */ + if (PAD_VOL_VALID(pad)) { + bp = PAD_PIN(pad) % 8 * 4 + 2; + mxs_reg = (struct mxs_register_32 *)(iomux_base + ofs); + if (PAD_VOL(pad)) + writel(1 << bp, &mxs_reg->reg_set); + else + writel(1 << bp, &mxs_reg->reg_clr); + } + + /* pull */ + if (PAD_PULL_VALID(pad)) { + ofs = PULL_OFFSET; + ofs += PAD_BANK(pad) * 0x10; + bp = PAD_PIN(pad); + mxs_reg = (struct mxs_register_32 *)(iomux_base + ofs); + if (PAD_PULL(pad)) + writel(1 << bp, &mxs_reg->reg_set); + else + writel(1 << bp, &mxs_reg->reg_clr); + } + + return 0; +} + +int mxs_iomux_setup_multiple_pads(const iomux_cfg_t *pad_list, unsigned count) +{ + const iomux_cfg_t *p = pad_list; + int i; + int ret; + + for (i = 0; i < count; i++) { + ret = mxs_iomux_setup_pad(*p); + if (ret) + return ret; + p++; + } + + return 0; +} diff --git a/arch/arm/cpu/arm926ejs/mxs/mxs.c b/arch/arm/cpu/arm926ejs/mxs/mxs.c new file mode 100644 index 0000000..45667bd --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/mxs.c @@ -0,0 +1,315 @@ +/* + * Freescale i.MX23/i.MX28 common code + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * Copyright (C) 2010 Freescale Semiconductor, Inc. + * + * 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 <asm/errno.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/imx-common/dma.h> +#include <asm/arch/gpio.h> +#include <asm/arch/iomux.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> +#include <linux/compiler.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* Lowlevel init isn't used on i.MX28, so just have a dummy here */ +inline void lowlevel_init(void) {} + +void reset_cpu(ulong ignored) __attribute__((noreturn)); + +void reset_cpu(ulong ignored) +{ + struct mxs_rtc_regs *rtc_regs = + (struct mxs_rtc_regs *)MXS_RTC_BASE; + struct mxs_lcdif_regs *lcdif_regs = + (struct mxs_lcdif_regs *)MXS_LCDIF_BASE; + + /* + * Shut down the LCD controller as it interferes with BootROM boot mode + * pads sampling. + */ + writel(LCDIF_CTRL_RUN, &lcdif_regs->hw_lcdif_ctrl_clr); + + /* Wait 1 uS before doing the actual watchdog reset */ + writel(1, &rtc_regs->hw_rtc_watchdog); + writel(RTC_CTRL_WATCHDOGEN, &rtc_regs->hw_rtc_ctrl_set); + + /* Endless loop, reset will exit from here */ + for (;;) + ; +} + +void enable_caches(void) +{ +#ifndef CONFIG_SYS_ICACHE_OFF + icache_enable(); +#endif +#ifndef CONFIG_SYS_DCACHE_OFF + dcache_enable(); +#endif +} + +/* + * This function will craft a jumptable at 0x0 which will redirect interrupt + * vectoring to proper location of U-Boot in RAM. + * + * The structure of the jumptable will be as follows: + * ldr pc, [pc, #0x18] ..... for each vector, thus repeated 8 times + * <destination address> ... for each previous ldr, thus also repeated 8 times + * + * The "ldr pc, [pc, #0x18]" instruction above loads address from memory at + * offset 0x18 from current value of PC register. Note that PC is already + * incremented by 4 when computing the offset, so the effective offset is + * actually 0x20, this the associated <destination address>. Loading the PC + * register with an address performs a jump to that address. + */ +void mx28_fixup_vt(uint32_t start_addr) +{ + /* ldr pc, [pc, #0x18] */ + const uint32_t ldr_pc = 0xe59ff018; + /* Jumptable location is 0x0 */ + uint32_t *vt = (uint32_t *)0x0; + int i; + + for (i = 0; i < 8; i++) { + vt[i] = ldr_pc; + vt[i + 8] = start_addr + (4 * i); + } +} + +#ifdef CONFIG_ARCH_MISC_INIT +int arch_misc_init(void) +{ + mx28_fixup_vt(gd->relocaddr); + return 0; +} +#endif + +int arch_cpu_init(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + extern uint32_t _start; + + mx28_fixup_vt((uint32_t)&_start); + + /* + * Enable NAND clock + */ + /* Clear bypass bit */ + writel(CLKCTRL_CLKSEQ_BYPASS_GPMI, + &clkctrl_regs->hw_clkctrl_clkseq_set); + + /* Set GPMI clock to ref_gpmi / 12 */ + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_gpmi, + CLKCTRL_GPMI_CLKGATE | CLKCTRL_GPMI_DIV_MASK, 1); + + udelay(1000); + + /* + * Configure GPIO unit + */ + mxs_gpio_init(); + +#ifdef CONFIG_APBH_DMA + /* Start APBH DMA */ + mxs_dma_init(); +#endif + + return 0; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +static const char *get_cpu_type(void) +{ + struct mxs_digctl_regs *digctl_regs = + (struct mxs_digctl_regs *)MXS_DIGCTL_BASE; + + switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) { + case HW_DIGCTL_CHIPID_MX23: + return "23"; + case HW_DIGCTL_CHIPID_MX28: + return "28"; + default: + return "??"; + } +} + +static const char *get_cpu_rev(void) +{ + struct mxs_digctl_regs *digctl_regs = + (struct mxs_digctl_regs *)MXS_DIGCTL_BASE; + uint8_t rev = readl(&digctl_regs->hw_digctl_chipid) & 0x000000FF; + + switch (readl(&digctl_regs->hw_digctl_chipid) & HW_DIGCTL_CHIPID_MASK) { + case HW_DIGCTL_CHIPID_MX23: + switch (rev) { + case 0x0: + return "1.0"; + case 0x1: + return "1.1"; + case 0x2: + return "1.2"; + case 0x3: + return "1.3"; + case 0x4: + return "1.4"; + default: + return "??"; + } + case HW_DIGCTL_CHIPID_MX28: + switch (rev) { + case 0x1: + return "1.2"; + default: + return "??"; + } + default: + return "??"; + } +} + +int print_cpuinfo(void) +{ + struct mxs_spl_data *data = (struct mxs_spl_data *) + ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf); + + printf("CPU: Freescale i.MX%s rev%s at %d MHz\n", + get_cpu_type(), + get_cpu_rev(), + mxc_get_clock(MXC_ARM_CLK) / 1000000); + printf("BOOT: %s\n", mxs_boot_modes[data->boot_mode_idx].mode); + return 0; +} +#endif + +int do_mx28_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + printf("CPU: %3d MHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000); + printf("BUS: %3d MHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000000); + printf("EMI: %3d MHz\n", mxc_get_clock(MXC_EMI_CLK)); + printf("GPMI: %3d MHz\n", mxc_get_clock(MXC_GPMI_CLK) / 1000000); + return 0; +} + +/* + * Initializes on-chip ethernet controllers. + */ +#if defined(CONFIG_MX28) && defined(CONFIG_CMD_NET) +int cpu_eth_init(bd_t *bis) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + /* Turn on ENET clocks */ + clrbits_le32(&clkctrl_regs->hw_clkctrl_enet, + CLKCTRL_ENET_SLEEP | CLKCTRL_ENET_DISABLE); + + /* Set up ENET PLL for 50 MHz */ + /* Power on ENET PLL */ + writel(CLKCTRL_PLL2CTRL0_POWER, + &clkctrl_regs->hw_clkctrl_pll2ctrl0_set); + + udelay(10); + + /* Gate on ENET PLL */ + writel(CLKCTRL_PLL2CTRL0_CLKGATE, + &clkctrl_regs->hw_clkctrl_pll2ctrl0_clr); + + /* Enable pad output */ + setbits_le32(&clkctrl_regs->hw_clkctrl_enet, CLKCTRL_ENET_CLK_OUT_EN); + + return 0; +} +#endif + +__weak void mx28_adjust_mac(int dev_id, unsigned char *mac) +{ + mac[0] = 0x00; + mac[1] = 0x04; /* Use FSL vendor MAC address by default */ + + if (dev_id == 1) /* Let MAC1 be MAC0 + 1 by default */ + mac[5] += 1; +} + +#ifdef CONFIG_MX28_FEC_MAC_IN_OCOTP + +#define MXS_OCOTP_MAX_TIMEOUT 1000000 +void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) +{ + struct mxs_ocotp_regs *ocotp_regs = + (struct mxs_ocotp_regs *)MXS_OCOTP_BASE; + uint32_t data; + + memset(mac, 0, 6); + + writel(OCOTP_CTRL_RD_BANK_OPEN, &ocotp_regs->hw_ocotp_ctrl_set); + + if (mxs_wait_mask_clr(&ocotp_regs->hw_ocotp_ctrl_reg, OCOTP_CTRL_BUSY, + MXS_OCOTP_MAX_TIMEOUT)) { + printf("MXS FEC: Can't get MAC from OCOTP\n"); + return; + } + + data = readl(&ocotp_regs->hw_ocotp_cust0); + + mac[2] = (data >> 24) & 0xff; + mac[3] = (data >> 16) & 0xff; + mac[4] = (data >> 8) & 0xff; + mac[5] = data & 0xff; + mx28_adjust_mac(dev_id, mac); +} +#else +void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) +{ + memset(mac, 0, 6); +} +#endif + +int mxs_dram_init(void) +{ + struct mxs_spl_data *data = (struct mxs_spl_data *) + ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf); + + if (data->mem_dram_size == 0) { + printf("MXS:\n" + "Error, the RAM size passed up from SPL is 0!\n"); + hang(); + } + + gd->ram_size = data->mem_dram_size; + return 0; +} + +U_BOOT_CMD( + clocks, CONFIG_SYS_MAXARGS, 1, do_mx28_showclocks, + "display clocks", + "" +); diff --git a/arch/arm/cpu/arm926ejs/mxs/mxs_init.h b/arch/arm/cpu/arm926ejs/mxs/mxs_init.h new file mode 100644 index 0000000..084def5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/mxs_init.h @@ -0,0 +1,45 @@ +/* + * Freescale i.MX28 SPL functions + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * 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 + */ + +#ifndef __M28_INIT_H__ +#define __M28_INIT_H__ + +void early_delay(int delay); + +void mxs_power_init(void); + +#ifdef CONFIG_SPL_MXS_PSWITCH_WAIT +void mxs_power_wait_pswitch(void); +#else +static inline void mxs_power_wait_pswitch(void) { } +#endif + +void mxs_mem_init(void); +uint32_t mxs_mem_get_size(void); + +void mxs_lradc_init(void); +void mxs_lradc_enable_batt_measurement(void); + +#endif /* __M28_INIT_H__ */ diff --git a/arch/arm/cpu/arm926ejs/mxs/spl_boot.c b/arch/arm/cpu/arm926ejs/mxs/spl_boot.c new file mode 100644 index 0000000..ed525e5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/spl_boot.c @@ -0,0 +1,150 @@ +/* + * Freescale i.MX28 Boot setup + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * 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 <config.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> +#include <asm/gpio.h> + +#include "mxs_init.h" + +/* + * This delay function is intended to be used only in early stage of boot, where + * clock are not set up yet. The timer used here is reset on every boot and + * takes a few seconds to roll. The boot doesn't take that long, so to keep the + * code simple, it doesn't take rolling into consideration. + */ +void early_delay(int delay) +{ + struct mxs_digctl_regs *digctl_regs = + (struct mxs_digctl_regs *)MXS_DIGCTL_BASE; + + uint32_t st = readl(&digctl_regs->hw_digctl_microseconds); + st += delay; + while (st > readl(&digctl_regs->hw_digctl_microseconds)) + ; +} + +#define MUX_CONFIG_BOOTMODE_PAD (MXS_PAD_3V3 | MXS_PAD_4MA | MXS_PAD_NOPULL) +static const iomux_cfg_t iomux_boot[] = { +#if defined(CONFIG_MX23) + MX23_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD, + MX23_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD, +#elif defined(CONFIG_MX28) + MX28_PAD_LCD_D00__GPIO_1_0 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D01__GPIO_1_1 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D02__GPIO_1_2 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D03__GPIO_1_3 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D04__GPIO_1_4 | MUX_CONFIG_BOOTMODE_PAD, + MX28_PAD_LCD_D05__GPIO_1_5 | MUX_CONFIG_BOOTMODE_PAD, +#endif +}; + +static uint8_t mxs_get_bootmode_index(void) +{ + uint8_t bootmode = 0; + int i; + uint8_t masked; + + /* Setup IOMUX of bootmode pads to GPIO */ + mxs_iomux_setup_multiple_pads(iomux_boot, ARRAY_SIZE(iomux_boot)); + +#if defined(CONFIG_MX23) + /* Setup bootmode pins as GPIO input */ + gpio_direction_input(MX23_PAD_LCD_D00__GPIO_1_0); + gpio_direction_input(MX23_PAD_LCD_D01__GPIO_1_1); + gpio_direction_input(MX23_PAD_LCD_D02__GPIO_1_2); + gpio_direction_input(MX23_PAD_LCD_D03__GPIO_1_3); + gpio_direction_input(MX23_PAD_LCD_D05__GPIO_1_5); + + /* Read bootmode pads */ + bootmode |= (gpio_get_value(MX23_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0; + bootmode |= (gpio_get_value(MX23_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1; + bootmode |= (gpio_get_value(MX23_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2; + bootmode |= (gpio_get_value(MX23_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3; + bootmode |= (gpio_get_value(MX23_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5; +#elif defined(CONFIG_MX28) + /* Setup bootmode pins as GPIO input */ + gpio_direction_input(MX28_PAD_LCD_D00__GPIO_1_0); + gpio_direction_input(MX28_PAD_LCD_D01__GPIO_1_1); + gpio_direction_input(MX28_PAD_LCD_D02__GPIO_1_2); + gpio_direction_input(MX28_PAD_LCD_D03__GPIO_1_3); + gpio_direction_input(MX28_PAD_LCD_D04__GPIO_1_4); + gpio_direction_input(MX28_PAD_LCD_D05__GPIO_1_5); + + /* Read bootmode pads */ + bootmode |= (gpio_get_value(MX28_PAD_LCD_D00__GPIO_1_0) ? 1 : 0) << 0; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D01__GPIO_1_1) ? 1 : 0) << 1; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D02__GPIO_1_2) ? 1 : 0) << 2; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D03__GPIO_1_3) ? 1 : 0) << 3; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D04__GPIO_1_4) ? 1 : 0) << 4; + bootmode |= (gpio_get_value(MX28_PAD_LCD_D05__GPIO_1_5) ? 1 : 0) << 5; +#endif + + for (i = 0; i < ARRAY_SIZE(mxs_boot_modes); i++) { + masked = bootmode & mxs_boot_modes[i].boot_mask; + if (masked == mxs_boot_modes[i].boot_pads) + break; + } + + return i; +} + +void mxs_common_spl_init(const iomux_cfg_t *iomux_setup, + const unsigned int iomux_size) +{ + struct mxs_spl_data *data = (struct mxs_spl_data *) + ((CONFIG_SYS_TEXT_BASE - sizeof(struct mxs_spl_data)) & ~0xf); + uint8_t bootmode = mxs_get_bootmode_index(); + + mxs_iomux_setup_multiple_pads(iomux_setup, iomux_size); + mxs_power_init(); + + mxs_mem_init(); + data->mem_dram_size = mxs_mem_get_size(); + + data->boot_mode_idx = bootmode; + + mxs_power_wait_pswitch(); +} + +/* Support aparatus */ +inline void board_init_f(unsigned long bootflag) +{ + for (;;) + ; +} + +inline void board_init_r(gd_t *id, ulong dest_addr) +{ + for (;;) + ; +} diff --git a/arch/arm/cpu/arm926ejs/mxs/spl_lradc_init.c b/arch/arm/cpu/arm926ejs/mxs/spl_lradc_init.c new file mode 100644 index 0000000..d90f0a1 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/spl_lradc_init.c @@ -0,0 +1,86 @@ +/* + * Freescale i.MX28 Battery measurement init + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * 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 <config.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +#include "mxs_init.h" + +void mxs_lradc_init(void) +{ + struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)MXS_LRADC_BASE; + + writel(LRADC_CTRL0_SFTRST, ®s->hw_lradc_ctrl0_clr); + writel(LRADC_CTRL0_CLKGATE, ®s->hw_lradc_ctrl0_clr); + writel(LRADC_CTRL0_ONCHIP_GROUNDREF, ®s->hw_lradc_ctrl0_clr); + + clrsetbits_le32(®s->hw_lradc_ctrl3, + LRADC_CTRL3_CYCLE_TIME_MASK, + LRADC_CTRL3_CYCLE_TIME_6MHZ); + + clrsetbits_le32(®s->hw_lradc_ctrl4, + LRADC_CTRL4_LRADC7SELECT_MASK | + LRADC_CTRL4_LRADC6SELECT_MASK, + LRADC_CTRL4_LRADC7SELECT_CHANNEL7 | + LRADC_CTRL4_LRADC6SELECT_CHANNEL10); +} + +void mxs_lradc_enable_batt_measurement(void) +{ + struct mxs_lradc_regs *regs = (struct mxs_lradc_regs *)MXS_LRADC_BASE; + + /* Check if the channel is present at all. */ + if (!(readl(®s->hw_lradc_status) & LRADC_STATUS_CHANNEL7_PRESENT)) + return; + + writel(LRADC_CTRL1_LRADC7_IRQ_EN, ®s->hw_lradc_ctrl1_clr); + writel(LRADC_CTRL1_LRADC7_IRQ, ®s->hw_lradc_ctrl1_clr); + + clrsetbits_le32(®s->hw_lradc_conversion, + LRADC_CONVERSION_SCALE_FACTOR_MASK, + LRADC_CONVERSION_SCALE_FACTOR_LI_ION); + writel(LRADC_CONVERSION_AUTOMATIC, ®s->hw_lradc_conversion_set); + + /* Configure the channel. */ + writel((1 << 7) << LRADC_CTRL2_DIVIDE_BY_TWO_OFFSET, + ®s->hw_lradc_ctrl2_clr); + writel(0xffffffff, ®s->hw_lradc_ch7_clr); + clrbits_le32(®s->hw_lradc_ch7, LRADC_CH_NUM_SAMPLES_MASK); + writel(LRADC_CH_ACCUMULATE, ®s->hw_lradc_ch7_clr); + + /* Schedule the channel. */ + writel(1 << 7, ®s->hw_lradc_ctrl0_set); + + /* Start the channel sampling. */ + writel(((1 << 7) << LRADC_DELAY_TRIGGER_LRADCS_OFFSET) | + ((1 << 3) << LRADC_DELAY_TRIGGER_DELAYS_OFFSET) | + 100, ®s->hw_lradc_delay3); + + writel(0xffffffff, ®s->hw_lradc_ch7_clr); + + writel(LRADC_DELAY_KICK, ®s->hw_lradc_delay3_set); +} diff --git a/arch/arm/cpu/arm926ejs/mxs/spl_mem_init.c b/arch/arm/cpu/arm926ejs/mxs/spl_mem_init.c new file mode 100644 index 0000000..07db279 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/spl_mem_init.c @@ -0,0 +1,347 @@ +/* + * Freescale i.MX28 RAM init + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * 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 <config.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> +#include <linux/compiler.h> + +#include "mxs_init.h" + +static uint32_t dram_vals[] = { +/* + * i.MX28 DDR2 at 200MHz + */ +#if defined(CONFIG_MX28) + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000100, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00010101, 0x01010101, + 0x000f0f01, 0x0f02020a, 0x00000000, 0x00010101, + 0x00000100, 0x00000100, 0x00000000, 0x00000002, + 0x01010000, 0x07080403, 0x06005003, 0x0a0000c8, + 0x02009c40, 0x0002030c, 0x0036a609, 0x031a0612, + 0x02030202, 0x00c8001c, 0x00000000, 0x00000000, + 0x00012100, 0xffff0303, 0x00012100, 0xffff0303, + 0x00012100, 0xffff0303, 0x00012100, 0xffff0303, + 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000612, 0x01000F02, + 0x06120612, 0x00000200, 0x00020007, 0xf4004a27, + 0xf4004a27, 0xf4004a27, 0xf4004a27, 0x07000300, + 0x07000300, 0x07400300, 0x07400300, 0x00000005, + 0x00000000, 0x00000000, 0x01000000, 0x01020408, + 0x08040201, 0x000f1133, 0x00000000, 0x00001f04, + 0x00001f04, 0x00001f04, 0x00001f04, 0x00001f04, + 0x00001f04, 0x00001f04, 0x00001f04, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00010000, 0x00030404, + 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x01010000, + 0x01000000, 0x03030000, 0x00010303, 0x01020202, + 0x00000000, 0x02040303, 0x21002103, 0x00061200, + 0x06120612, 0x04420442, 0x04420442, 0x00040004, + 0x00040004, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0xffffffff + +/* + * i.MX23 DDR at 133MHz + */ +#elif defined(CONFIG_MX23) + 0x01010001, 0x00010100, 0x01000101, 0x00000001, + 0x00000101, 0x00000000, 0x00010000, 0x01000001, + 0x00000000, 0x00000001, 0x07000200, 0x00070202, + 0x02020000, 0x04040a01, 0x00000201, 0x02040000, + 0x02000000, 0x19000f08, 0x0d0d0000, 0x02021313, + 0x02061521, 0x0000000a, 0x00080008, 0x00200020, + 0x00200020, 0x00200020, 0x000003f7, 0x00000000, + 0x00000000, 0x00000020, 0x00000020, 0x00c80000, + 0x000a23cd, 0x000000c8, 0x00006665, 0x00000000, + 0x00000101, 0x00040001, 0x00000000, 0x00000000, + 0x00010000 +#else +#error Unsupported memory initialization +#endif +}; + +__weak void mxs_adjust_memory_params(uint32_t *dram_vals) +{ +} + +#ifdef CONFIG_MX28 +static void initialize_dram_values(void) +{ + int i; + + mxs_adjust_memory_params(dram_vals); + + for (i = 0; i < ARRAY_SIZE(dram_vals); i++) + writel(dram_vals[i], MXS_DRAM_BASE + (4 * i)); +} +#else +static void initialize_dram_values(void) +{ + int i; + + mxs_adjust_memory_params(dram_vals); + + /* + * HW_DRAM_CTL27, HW_DRAM_CTL28 and HW_DRAM_CTL35 are not initialized as + * per FSL bootlets code. + * + * mx23 Reference Manual marks HW_DRAM_CTL27 and HW_DRAM_CTL28 as + * "reserved". + * HW_DRAM_CTL8 is setup as the last element. + * So skip the initialization of these HW_DRAM_CTL registers. + */ + for (i = 0; i < ARRAY_SIZE(dram_vals); i++) { + if (i == 8 || i == 27 || i == 28 || i == 35) + continue; + writel(dram_vals[i], MXS_DRAM_BASE + (4 * i)); + } + + /* + * Enable tRAS lockout in HW_DRAM_CTL08 ; it must be the last + * element to be set + */ + writel((1 << 24), MXS_DRAM_BASE + (4 * 8)); +} +#endif + +static void mxs_mem_init_clock(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; +#if defined(CONFIG_MX23) + /* Fractional divider for ref_emi is 33 ; 480 * 18 / 33 = 266MHz */ + const unsigned char divider = 33; +#elif defined(CONFIG_MX28) + /* Fractional divider for ref_emi is 21 ; 480 * 18 / 21 = 411MHz */ + const unsigned char divider = 21; +#endif + + /* Gate EMI clock */ + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_set[CLKCTRL_FRAC0_EMI]); + + /* Set fractional divider for ref_emi */ + writeb(CLKCTRL_FRAC_CLKGATE | (divider & CLKCTRL_FRAC_FRAC_MASK), + &clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_EMI]); + + /* Ungate EMI clock */ + writeb(CLKCTRL_FRAC_CLKGATE, + &clkctrl_regs->hw_clkctrl_frac0_clr[CLKCTRL_FRAC0_EMI]); + + early_delay(11000); + + /* Set EMI clock divider for EMI clock to 411 / 2 = 205MHz */ + writel((2 << CLKCTRL_EMI_DIV_EMI_OFFSET) | + (1 << CLKCTRL_EMI_DIV_XTAL_OFFSET), + &clkctrl_regs->hw_clkctrl_emi); + + /* Unbypass EMI */ + writel(CLKCTRL_CLKSEQ_BYPASS_EMI, + &clkctrl_regs->hw_clkctrl_clkseq_clr); + + early_delay(10000); +} + +static void mxs_mem_setup_cpu_and_hbus(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + /* Set fractional divider for ref_cpu to 480 * 18 / 19 = 454MHz + * and ungate CPU clock */ + writeb(19 & CLKCTRL_FRAC_FRAC_MASK, + (uint8_t *)&clkctrl_regs->hw_clkctrl_frac0[CLKCTRL_FRAC0_CPU]); + + /* Set CPU bypass */ + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, + &clkctrl_regs->hw_clkctrl_clkseq_set); + + /* HBUS = 151MHz */ + writel(CLKCTRL_HBUS_DIV_MASK, &clkctrl_regs->hw_clkctrl_hbus_set); + writel(((~3) << CLKCTRL_HBUS_DIV_OFFSET) & CLKCTRL_HBUS_DIV_MASK, + &clkctrl_regs->hw_clkctrl_hbus_clr); + + early_delay(10000); + + /* CPU clock divider = 1 */ + clrsetbits_le32(&clkctrl_regs->hw_clkctrl_cpu, + CLKCTRL_CPU_DIV_CPU_MASK, 1); + + /* Disable CPU bypass */ + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, + &clkctrl_regs->hw_clkctrl_clkseq_clr); + + early_delay(15000); +} + +static void mxs_mem_setup_vdda(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + writel((0xc << POWER_VDDACTRL_TRG_OFFSET) | + (0x7 << POWER_VDDACTRL_BO_OFFSET_OFFSET) | + POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW, + &power_regs->hw_power_vddactrl); +} + +uint32_t mxs_mem_get_size(void) +{ + uint32_t sz, da; + uint32_t *vt = (uint32_t *)0x20; + /* The following is "subs pc, r14, #4", used as return from DABT. */ + const uint32_t data_abort_memdetect_handler = 0xe25ef004; + + /* Replace the DABT handler. */ + da = vt[4]; + vt[4] = data_abort_memdetect_handler; + + sz = get_ram_size((long *)PHYS_SDRAM_1, PHYS_SDRAM_1_SIZE); + + /* Restore the old DABT handler. */ + vt[4] = da; + + return sz; +} + +#ifdef CONFIG_MX23 +static void mx23_mem_setup_vddmem(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + clrbits_le32(&power_regs->hw_power_vddmemctrl, + POWER_VDDMEMCTRL_ENABLE_ILIMIT); + +} + +static void mx23_mem_init(void) +{ + /* + * Reset/ungate the EMI block. This is essential, otherwise the system + * suffers from memory instability. This thing is mx23 specific and is + * no longer present on mx28. + */ + mxs_reset_block((struct mxs_register_32 *)MXS_EMI_BASE); + + mx23_mem_setup_vddmem(); + + /* + * Configure the DRAM registers + */ + + /* Clear START and SREFRESH bit from DRAM_CTL8 */ + clrbits_le32(MXS_DRAM_BASE + 0x20, (1 << 16) | (1 << 8)); + + initialize_dram_values(); + + /* Set START bit in DRAM_CTL8 */ + setbits_le32(MXS_DRAM_BASE + 0x20, 1 << 16); + + clrbits_le32(MXS_DRAM_BASE + 0x40, 1 << 17); + early_delay(20000); + + /* Adjust EMI port priority. */ + clrsetbits_le32(0x80020000, 0x1f << 16, 0x2); + early_delay(20000); + + setbits_le32(MXS_DRAM_BASE + 0x40, 1 << 19); + setbits_le32(MXS_DRAM_BASE + 0x40, 1 << 11); +} +#endif + +#ifdef CONFIG_MX28 +static void mx28_mem_init(void) +{ + struct mxs_pinctrl_regs *pinctrl_regs = + (struct mxs_pinctrl_regs *)MXS_PINCTRL_BASE; + + /* Set DDR2 mode */ + writel(PINCTRL_EMI_DS_CTRL_DDR_MODE_DDR2, + &pinctrl_regs->hw_pinctrl_emi_ds_ctrl_set); + + /* + * Configure the DRAM registers + */ + + /* Clear START bit from DRAM_CTL16 */ + clrbits_le32(MXS_DRAM_BASE + 0x40, 1); + + initialize_dram_values(); + + /* Clear SREFRESH bit from DRAM_CTL17 */ + clrbits_le32(MXS_DRAM_BASE + 0x44, 1); + + /* Set START bit in DRAM_CTL16 */ + setbits_le32(MXS_DRAM_BASE + 0x40, 1); + + /* Wait for bit 20 (DRAM init complete) in DRAM_CTL58 */ + while (!(readl(MXS_DRAM_BASE + 0xe8) & (1 << 20))) + ; +} +#endif + +void mxs_mem_init(void) +{ + early_delay(11000); + + mxs_mem_init_clock(); + + mxs_mem_setup_vdda(); + +#if defined(CONFIG_MX23) + mx23_mem_init(); +#elif defined(CONFIG_MX28) + mx28_mem_init(); +#endif + + early_delay(10000); + + mxs_mem_setup_cpu_and_hbus(); +} diff --git a/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c b/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c new file mode 100644 index 0000000..21cac7b --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/spl_power_init.c @@ -0,0 +1,963 @@ +/* + * Freescale i.MX28 Boot PMIC init + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * 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 <config.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> + +#include "mxs_init.h" + +static void mxs_power_clock2xtal(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + /* Set XTAL as CPU reference clock */ + writel(CLKCTRL_CLKSEQ_BYPASS_CPU, + &clkctrl_regs->hw_clkctrl_clkseq_set); +} + +static void mxs_power_clock2pll(void) +{ + struct mxs_clkctrl_regs *clkctrl_regs = + (struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE; + + setbits_le32(&clkctrl_regs->hw_clkctrl_pll0ctrl0, + CLKCTRL_PLL0CTRL0_POWER); + early_delay(100); + setbits_le32(&clkctrl_regs->hw_clkctrl_clkseq, + CLKCTRL_CLKSEQ_BYPASS_CPU); +} + +static void mxs_power_clear_auto_restart(void) +{ + struct mxs_rtc_regs *rtc_regs = + (struct mxs_rtc_regs *)MXS_RTC_BASE; + + writel(RTC_CTRL_SFTRST, &rtc_regs->hw_rtc_ctrl_clr); + while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_SFTRST) + ; + + writel(RTC_CTRL_CLKGATE, &rtc_regs->hw_rtc_ctrl_clr); + while (readl(&rtc_regs->hw_rtc_ctrl) & RTC_CTRL_CLKGATE) + ; + + /* + * Due to the hardware design bug of mx28 EVK-A + * we need to set the AUTO_RESTART bit. + */ + if (readl(&rtc_regs->hw_rtc_persistent0) & RTC_PERSISTENT0_AUTO_RESTART) + return; + + while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK) + ; + + setbits_le32(&rtc_regs->hw_rtc_persistent0, + RTC_PERSISTENT0_AUTO_RESTART); + writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_set); + writel(RTC_CTRL_FORCE_UPDATE, &rtc_regs->hw_rtc_ctrl_clr); + while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_NEW_REGS_MASK) + ; + while (readl(&rtc_regs->hw_rtc_stat) & RTC_STAT_STALE_REGS_MASK) + ; +} + +static void mxs_power_set_linreg(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Set linear regulator 25mV below switching converter */ + clrsetbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_LINREG_OFFSET_MASK, + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW); + + clrsetbits_le32(&power_regs->hw_power_vddactrl, + POWER_VDDACTRL_LINREG_OFFSET_MASK, + POWER_VDDACTRL_LINREG_OFFSET_1STEPS_BELOW); + + clrsetbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_LINREG_OFFSET_MASK, + POWER_VDDIOCTRL_LINREG_OFFSET_1STEPS_BELOW); +} + +static int mxs_get_batt_volt(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t volt = readl(&power_regs->hw_power_battmonitor); + volt &= POWER_BATTMONITOR_BATT_VAL_MASK; + volt >>= POWER_BATTMONITOR_BATT_VAL_OFFSET; + volt *= 8; + return volt; +} + +static int mxs_is_batt_ready(void) +{ + return (mxs_get_batt_volt() >= 3600); +} + +static int mxs_is_batt_good(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t volt = mxs_get_batt_volt(); + + if ((volt >= 2400) && (volt <= 4300)) + return 1; + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + 0x3 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_clr); + + clrsetbits_le32(&power_regs->hw_power_charge, + POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, + POWER_CHARGE_STOP_ILIMIT_10MA | 0x3); + + writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_clr); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_clr); + + early_delay(500000); + + volt = mxs_get_batt_volt(); + + if (volt >= 3500) + return 0; + + if (volt >= 2400) + return 1; + + writel(POWER_CHARGE_STOP_ILIMIT_MASK | POWER_CHARGE_BATTCHRG_I_MASK, + &power_regs->hw_power_charge_clr); + writel(POWER_CHARGE_PWD_BATTCHRG, &power_regs->hw_power_charge_set); + + return 0; +} + +static void mxs_power_setup_5v_detect(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Start 5V detection */ + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_VBUSVALID_TRSH_MASK, + POWER_5VCTRL_VBUSVALID_TRSH_4V4 | + POWER_5VCTRL_PWRUP_VBUS_CMPS); +} + +static void mxs_src_power_init(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Improve efficieny and reduce transient ripple */ + writel(POWER_LOOPCTRL_TOGGLE_DIF | POWER_LOOPCTRL_EN_CM_HYST | + POWER_LOOPCTRL_EN_DF_HYST, &power_regs->hw_power_loopctrl_set); + + clrsetbits_le32(&power_regs->hw_power_dclimits, + POWER_DCLIMITS_POSLIMIT_BUCK_MASK, + 0x30 << POWER_DCLIMITS_POSLIMIT_BUCK_OFFSET); + + setbits_le32(&power_regs->hw_power_battmonitor, + POWER_BATTMONITOR_EN_BATADJ); + + /* Increase the RCSCALE level for quick DCDC response to dynamic load */ + clrsetbits_le32(&power_regs->hw_power_loopctrl, + POWER_LOOPCTRL_EN_RCSCALE_MASK, + POWER_LOOPCTRL_RCSCALE_THRESH | + POWER_LOOPCTRL_EN_RCSCALE_8X); + + clrsetbits_le32(&power_regs->hw_power_minpwr, + POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS); + + /* 5V to battery handoff ... FIXME */ + setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); + early_delay(30); + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); +} + +static void mxs_power_init_4p2_params(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Setup 4P2 parameters */ + clrsetbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_CMPTRIP_MASK | POWER_DCDC4P2_TRG_MASK, + POWER_DCDC4P2_TRG_4V2 | (31 << POWER_DCDC4P2_CMPTRIP_OFFSET)); + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_HEADROOM_ADJ_MASK, + 0x4 << POWER_5VCTRL_HEADROOM_ADJ_OFFSET); + + clrsetbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_DROPOUT_CTRL_MASK, + POWER_DCDC4P2_DROPOUT_CTRL_100MV | + POWER_DCDC4P2_DROPOUT_CTRL_SRC_SEL); + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); +} + +static void mxs_enable_4p2_dcdc_input(int xfer) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp, vbus_thresh, vbus_5vdetect, pwd_bo; + uint32_t prev_5v_brnout, prev_5v_droop; + + prev_5v_brnout = readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_PWDN_5VBRNOUT; + prev_5v_droop = readl(&power_regs->hw_power_ctrl) & + POWER_CTRL_ENIRQ_VDD5V_DROOP; + + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT); + writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF, + &power_regs->hw_power_reset); + + clrbits_le32(&power_regs->hw_power_ctrl, POWER_CTRL_ENIRQ_VDD5V_DROOP); + + if (xfer && (readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_ENABLE_DCDC)) { + return; + } + + /* + * Recording orignal values that will be modified temporarlily + * to handle a chip bug. See chip errata for CQ ENGR00115837 + */ + tmp = readl(&power_regs->hw_power_5vctrl); + vbus_thresh = tmp & POWER_5VCTRL_VBUSVALID_TRSH_MASK; + vbus_5vdetect = tmp & POWER_5VCTRL_VBUSVALID_5VDETECT; + + pwd_bo = readl(&power_regs->hw_power_minpwr) & POWER_MINPWR_PWD_BO; + + /* + * Disable mechanisms that get erroneously tripped by when setting + * the DCDC4P2 EN_DCDC + */ + clrbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_VBUSVALID_5VDETECT | + POWER_5VCTRL_VBUSVALID_TRSH_MASK); + + writel(POWER_MINPWR_PWD_BO, &power_regs->hw_power_minpwr_set); + + if (xfer) { + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_DCDC_XFER); + early_delay(20); + clrbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_DCDC_XFER); + + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_ENABLE_DCDC); + } else { + setbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_ENABLE_DCDC); + } + + early_delay(25); + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_VBUSVALID_TRSH_MASK, vbus_thresh); + + if (vbus_5vdetect) + writel(vbus_5vdetect, &power_regs->hw_power_5vctrl_set); + + if (!pwd_bo) + clrbits_le32(&power_regs->hw_power_minpwr, POWER_MINPWR_PWD_BO); + + while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) + writel(POWER_CTRL_VBUS_VALID_IRQ, + &power_regs->hw_power_ctrl_clr); + + if (prev_5v_brnout) { + writel(POWER_5VCTRL_PWDN_5VBRNOUT, + &power_regs->hw_power_5vctrl_set); + writel(POWER_RESET_UNLOCK_KEY, + &power_regs->hw_power_reset); + } else { + writel(POWER_5VCTRL_PWDN_5VBRNOUT, + &power_regs->hw_power_5vctrl_clr); + writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF, + &power_regs->hw_power_reset); + } + + while (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VDD5V_DROOP_IRQ) + writel(POWER_CTRL_VDD5V_DROOP_IRQ, + &power_regs->hw_power_ctrl_clr); + + if (prev_5v_droop) + clrbits_le32(&power_regs->hw_power_ctrl, + POWER_CTRL_ENIRQ_VDD5V_DROOP); + else + setbits_le32(&power_regs->hw_power_ctrl, + POWER_CTRL_ENIRQ_VDD5V_DROOP); +} + +static void mxs_power_init_4p2_regulator(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp, tmp2; + + setbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_ENABLE_4P2); + + writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_set); + + writel(POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + &power_regs->hw_power_5vctrl_clr); + clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_TRG_MASK); + + /* Power up the 4p2 rail and logic/control */ + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_clr); + + /* + * Start charging up the 4p2 capacitor. We ramp of this charge + * gradually to avoid large inrush current from the 5V cable which can + * cause transients/problems + */ + mxs_enable_4p2_dcdc_input(0); + + if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) { + /* + * If we arrived here, we were unable to recover from mx23 chip + * errata 5837. 4P2 is disabled and sufficient battery power is + * not present. Exiting to not enable DCDC power during 5V + * connected state. + */ + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_ENABLE_DCDC); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_set); + hang(); + } + + /* + * Here we set the 4p2 brownout level to something very close to 4.2V. + * We then check the brownout status. If the brownout status is false, + * the voltage is already close to the target voltage of 4.2V so we + * can go ahead and set the 4P2 current limit to our max target limit. + * If the brownout status is true, we need to ramp us the current limit + * so that we don't cause large inrush current issues. We step up the + * current limit until the brownout status is false or until we've + * reached our maximum defined 4p2 current limit. + */ + clrsetbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_BO_MASK, + 22 << POWER_DCDC4P2_BO_OFFSET); /* 4.15V */ + + if (!(readl(&power_regs->hw_power_sts) & POWER_STS_DCDC_4P2_BO)) { + setbits_le32(&power_regs->hw_power_5vctrl, + 0x3f << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); + } else { + tmp = (readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK) >> + POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET; + while (tmp < 0x3f) { + if (!(readl(&power_regs->hw_power_sts) & + POWER_STS_DCDC_4P2_BO)) { + tmp = readl(&power_regs->hw_power_5vctrl); + tmp |= POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK; + early_delay(100); + writel(tmp, &power_regs->hw_power_5vctrl); + break; + } else { + tmp++; + tmp2 = readl(&power_regs->hw_power_5vctrl); + tmp2 &= ~POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK; + tmp2 |= tmp << + POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET; + writel(tmp2, &power_regs->hw_power_5vctrl); + early_delay(100); + } + } + } + + clrbits_le32(&power_regs->hw_power_dcdc4p2, POWER_DCDC4P2_BO_MASK); + writel(POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr); +} + +static void mxs_power_init_dcdc_4p2_source(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + if (!(readl(&power_regs->hw_power_dcdc4p2) & + POWER_DCDC4P2_ENABLE_DCDC)) { + hang(); + } + + mxs_enable_4p2_dcdc_input(1); + + if (readl(&power_regs->hw_power_ctrl) & POWER_CTRL_VBUS_VALID_IRQ) { + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_ENABLE_DCDC); + writel(POWER_5VCTRL_ENABLE_DCDC, + &power_regs->hw_power_5vctrl_clr); + writel(POWER_5VCTRL_PWD_CHARGE_4P2_MASK, + &power_regs->hw_power_5vctrl_set); + } +} + +static void mxs_power_enable_4p2(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t vdddctrl, vddactrl, vddioctrl; + uint32_t tmp; + + vdddctrl = readl(&power_regs->hw_power_vdddctrl); + vddactrl = readl(&power_regs->hw_power_vddactrl); + vddioctrl = readl(&power_regs->hw_power_vddioctrl); + + setbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG | + POWER_VDDDCTRL_PWDN_BRNOUT); + + setbits_le32(&power_regs->hw_power_vddactrl, + POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG | + POWER_VDDACTRL_PWDN_BRNOUT); + + setbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_DISABLE_FET | POWER_VDDIOCTRL_PWDN_BRNOUT); + + mxs_power_init_4p2_params(); + mxs_power_init_4p2_regulator(); + + /* Shutdown battery (none present) */ + if (!mxs_is_batt_ready()) { + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_BO_MASK); + writel(POWER_CTRL_DCDC4P2_BO_IRQ, + &power_regs->hw_power_ctrl_clr); + writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, + &power_regs->hw_power_ctrl_clr); + } + + mxs_power_init_dcdc_4p2_source(); + + writel(vdddctrl, &power_regs->hw_power_vdddctrl); + early_delay(20); + writel(vddactrl, &power_regs->hw_power_vddactrl); + early_delay(20); + writel(vddioctrl, &power_regs->hw_power_vddioctrl); + + /* + * Check if FET is enabled on either powerout and if so, + * disable load. + */ + tmp = 0; + tmp |= !(readl(&power_regs->hw_power_vdddctrl) & + POWER_VDDDCTRL_DISABLE_FET); + tmp |= !(readl(&power_regs->hw_power_vddactrl) & + POWER_VDDACTRL_DISABLE_FET); + tmp |= !(readl(&power_regs->hw_power_vddioctrl) & + POWER_VDDIOCTRL_DISABLE_FET); + if (tmp) + writel(POWER_CHARGE_ENABLE_LOAD, + &power_regs->hw_power_charge_clr); +} + +static void mxs_boot_valid_5v(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* + * Use VBUSVALID level instead of VDD5V_GT_VDDIO level to trigger a 5V + * disconnect event. FIXME + */ + writel(POWER_5VCTRL_VBUSVALID_5VDETECT, + &power_regs->hw_power_5vctrl_set); + + /* Configure polarity to check for 5V disconnection. */ + writel(POWER_CTRL_POLARITY_VBUSVALID | + POWER_CTRL_POLARITY_VDD5V_GT_VDDIO, + &power_regs->hw_power_ctrl_clr); + + writel(POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_VDD5V_GT_VDDIO_IRQ, + &power_regs->hw_power_ctrl_clr); + + mxs_power_enable_4p2(); +} + +static void mxs_powerdown(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + writel(POWER_RESET_UNLOCK_KEY, &power_regs->hw_power_reset); + writel(POWER_RESET_UNLOCK_KEY | POWER_RESET_PWD_OFF, + &power_regs->hw_power_reset); +} + +static void mxs_batt_boot(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_PWDN_5VBRNOUT); + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_ENABLE_DCDC); + + clrbits_le32(&power_regs->hw_power_dcdc4p2, + POWER_DCDC4P2_ENABLE_DCDC | POWER_DCDC4P2_ENABLE_4P2); + writel(POWER_CHARGE_ENABLE_LOAD, &power_regs->hw_power_charge_clr); + + /* 5V to battery handoff. */ + setbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); + early_delay(30); + clrbits_le32(&power_regs->hw_power_5vctrl, POWER_5VCTRL_DCDC_XFER); + + writel(POWER_CTRL_ENIRQ_DCDC4P2_BO, &power_regs->hw_power_ctrl_clr); + + clrsetbits_le32(&power_regs->hw_power_minpwr, + POWER_MINPWR_HALFFETS, POWER_MINPWR_DOUBLE_FETS); + + mxs_power_set_linreg(); + + clrbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG); + + clrbits_le32(&power_regs->hw_power_vddactrl, + POWER_VDDACTRL_DISABLE_FET | POWER_VDDACTRL_ENABLE_LINREG); + + clrbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_DISABLE_FET); + + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_PWD_CHARGE_4P2_MASK); + + setbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_ENABLE_DCDC); + + clrsetbits_le32(&power_regs->hw_power_5vctrl, + POWER_5VCTRL_CHARGE_4P2_ILIMIT_MASK, + 0x8 << POWER_5VCTRL_CHARGE_4P2_ILIMIT_OFFSET); +} + +static void mxs_handle_5v_conflict(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp; + + setbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_BO_OFFSET_MASK); + + for (;;) { + tmp = readl(&power_regs->hw_power_sts); + + if (tmp & POWER_STS_VDDIO_BO) { + /* + * VDDIO has a brownout, then the VDD5V_GT_VDDIO becomes + * unreliable + */ + mxs_powerdown(); + break; + } + + if (tmp & POWER_STS_VDD5V_GT_VDDIO) { + mxs_boot_valid_5v(); + break; + } else { + mxs_powerdown(); + break; + } + + if (tmp & POWER_STS_PSWITCH_MASK) { + mxs_batt_boot(); + break; + } + } +} + +static void mxs_5v_boot(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* + * NOTE: In original IMX-Bootlets, this also checks for VBUSVALID, + * but their implementation always returns 1 so we omit it here. + */ + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + mxs_boot_valid_5v(); + return; + } + + early_delay(1000); + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + mxs_boot_valid_5v(); + return; + } + + mxs_handle_5v_conflict(); +} + +static void mxs_init_batt_bo(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + /* Brownout at 3V */ + clrsetbits_le32(&power_regs->hw_power_battmonitor, + POWER_BATTMONITOR_BRWNOUT_LVL_MASK, + 15 << POWER_BATTMONITOR_BRWNOUT_LVL_OFFSET); + + writel(POWER_CTRL_BATT_BO_IRQ, &power_regs->hw_power_ctrl_clr); + writel(POWER_CTRL_ENIRQ_BATT_BO, &power_regs->hw_power_ctrl_clr); +} + +static void mxs_switch_vddd_to_dcdc_source(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + clrsetbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_LINREG_OFFSET_MASK, + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW); + + clrbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_DISABLE_FET | POWER_VDDDCTRL_ENABLE_LINREG | + POWER_VDDDCTRL_DISABLE_STEPPING); +} + +static void mxs_power_configure_power_source(void) +{ + int batt_ready, batt_good; + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + struct mxs_lradc_regs *lradc_regs = + (struct mxs_lradc_regs *)MXS_LRADC_BASE; + + mxs_src_power_init(); + + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + batt_ready = mxs_is_batt_ready(); + if (batt_ready) { + /* 5V source detected, good battery detected. */ + mxs_batt_boot(); + } else { + batt_good = mxs_is_batt_good(); + if (!batt_good) { + /* 5V source detected, bad battery detected. */ + writel(LRADC_CONVERSION_AUTOMATIC, + &lradc_regs->hw_lradc_conversion_clr); + clrbits_le32(&power_regs->hw_power_battmonitor, + POWER_BATTMONITOR_BATT_VAL_MASK); + } + mxs_5v_boot(); + } + } else { + /* 5V not detected, booting from battery. */ + mxs_batt_boot(); + } + + mxs_power_clock2pll(); + + mxs_init_batt_bo(); + + mxs_switch_vddd_to_dcdc_source(); + +#ifdef CONFIG_MX23 + /* Fire up the VDDMEM LinReg now that we're all set. */ + writel(POWER_VDDMEMCTRL_ENABLE_LINREG | POWER_VDDMEMCTRL_ENABLE_ILIMIT, + &power_regs->hw_power_vddmemctrl); +#endif +} + +static void mxs_enable_output_rail_protection(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ | + POWER_CTRL_VDDIO_BO_IRQ, &power_regs->hw_power_ctrl_clr); + + setbits_le32(&power_regs->hw_power_vdddctrl, + POWER_VDDDCTRL_PWDN_BRNOUT); + + setbits_le32(&power_regs->hw_power_vddactrl, + POWER_VDDACTRL_PWDN_BRNOUT); + + setbits_le32(&power_regs->hw_power_vddioctrl, + POWER_VDDIOCTRL_PWDN_BRNOUT); +} + +static int mxs_get_vddio_power_source_off(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp; + + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + tmp = readl(&power_regs->hw_power_vddioctrl); + if (tmp & POWER_VDDIOCTRL_DISABLE_FET) { + if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) == + POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) { + return 1; + } + } + + if (!(readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_ENABLE_DCDC)) { + if ((tmp & POWER_VDDIOCTRL_LINREG_OFFSET_MASK) == + POWER_VDDIOCTRL_LINREG_OFFSET_0STEPS) { + return 1; + } + } + } + + return 0; + +} + +static int mxs_get_vddd_power_source_off(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t tmp; + + tmp = readl(&power_regs->hw_power_vdddctrl); + if (tmp & POWER_VDDDCTRL_DISABLE_FET) { + if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) == + POWER_VDDDCTRL_LINREG_OFFSET_0STEPS) { + return 1; + } + } + + if (readl(&power_regs->hw_power_sts) & POWER_STS_VDD5V_GT_VDDIO) { + if (!(readl(&power_regs->hw_power_5vctrl) & + POWER_5VCTRL_ENABLE_DCDC)) { + return 1; + } + } + + if (!(tmp & POWER_VDDDCTRL_ENABLE_LINREG)) { + if ((tmp & POWER_VDDDCTRL_LINREG_OFFSET_MASK) == + POWER_VDDDCTRL_LINREG_OFFSET_1STEPS_BELOW) { + return 1; + } + } + + return 0; +} + +struct mxs_vddx_cfg { + uint32_t *reg; + uint8_t step_mV; + uint16_t lowest_mV; + int (*powered_by_linreg)(void); + uint32_t trg_mask; + uint32_t bo_irq; + uint32_t bo_enirq; + uint32_t bo_offset_mask; + uint32_t bo_offset_offset; +}; + +static const struct mxs_vddx_cfg mxs_vddio_cfg = { + .reg = &(((struct mxs_power_regs *)MXS_POWER_BASE)-> + hw_power_vddioctrl), +#if defined(CONFIG_MX23) + .step_mV = 25, +#else + .step_mV = 50, +#endif + .lowest_mV = 2800, + .powered_by_linreg = mxs_get_vddio_power_source_off, + .trg_mask = POWER_VDDIOCTRL_TRG_MASK, + .bo_irq = POWER_CTRL_VDDIO_BO_IRQ, + .bo_enirq = POWER_CTRL_ENIRQ_VDDIO_BO, + .bo_offset_mask = POWER_VDDIOCTRL_BO_OFFSET_MASK, + .bo_offset_offset = POWER_VDDIOCTRL_BO_OFFSET_OFFSET, +}; + +static const struct mxs_vddx_cfg mxs_vddd_cfg = { + .reg = &(((struct mxs_power_regs *)MXS_POWER_BASE)-> + hw_power_vdddctrl), + .step_mV = 25, + .lowest_mV = 800, + .powered_by_linreg = mxs_get_vddd_power_source_off, + .trg_mask = POWER_VDDDCTRL_TRG_MASK, + .bo_irq = POWER_CTRL_VDDD_BO_IRQ, + .bo_enirq = POWER_CTRL_ENIRQ_VDDD_BO, + .bo_offset_mask = POWER_VDDDCTRL_BO_OFFSET_MASK, + .bo_offset_offset = POWER_VDDDCTRL_BO_OFFSET_OFFSET, +}; + +#ifdef CONFIG_MX23 +static const struct mxs_vddx_cfg mxs_vddmem_cfg = { + .reg = &(((struct mxs_power_regs *)MXS_POWER_BASE)-> + hw_power_vddmemctrl), + .step_mV = 50, + .lowest_mV = 1700, + .powered_by_linreg = NULL, + .trg_mask = POWER_VDDMEMCTRL_TRG_MASK, + .bo_irq = 0, + .bo_enirq = 0, + .bo_offset_mask = 0, + .bo_offset_offset = 0, +}; +#endif + +static void mxs_power_set_vddx(const struct mxs_vddx_cfg *cfg, + uint32_t new_target, uint32_t new_brownout) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + uint32_t cur_target, diff, bo_int = 0; + uint32_t powered_by_linreg = 0; + int adjust_up, tmp; + + new_brownout = DIV_ROUND(new_target - new_brownout, cfg->step_mV); + + cur_target = readl(cfg->reg); + cur_target &= cfg->trg_mask; + cur_target *= cfg->step_mV; + cur_target += cfg->lowest_mV; + + adjust_up = new_target > cur_target; + if (cfg->powered_by_linreg) + powered_by_linreg = cfg->powered_by_linreg(); + + if (adjust_up && cfg->bo_irq) { + if (powered_by_linreg) { + bo_int = readl(cfg->reg); + clrbits_le32(cfg->reg, cfg->bo_enirq); + } + setbits_le32(cfg->reg, cfg->bo_offset_mask); + } + + do { + if (abs(new_target - cur_target) > 100) { + if (adjust_up) + diff = cur_target + 100; + else + diff = cur_target - 100; + } else { + diff = new_target; + } + + diff -= cfg->lowest_mV; + diff /= cfg->step_mV; + + clrsetbits_le32(cfg->reg, cfg->trg_mask, diff); + + if (powered_by_linreg || + (readl(&power_regs->hw_power_sts) & + POWER_STS_VDD5V_GT_VDDIO)) + early_delay(500); + else { + for (;;) { + tmp = readl(&power_regs->hw_power_sts); + if (tmp & POWER_STS_DC_OK) + break; + } + } + + cur_target = readl(cfg->reg); + cur_target &= cfg->trg_mask; + cur_target *= cfg->step_mV; + cur_target += cfg->lowest_mV; + } while (new_target > cur_target); + + if (cfg->bo_irq) { + if (adjust_up && powered_by_linreg) { + writel(cfg->bo_irq, &power_regs->hw_power_ctrl_clr); + if (bo_int & cfg->bo_enirq) + setbits_le32(cfg->reg, cfg->bo_enirq); + } + + clrsetbits_le32(cfg->reg, cfg->bo_offset_mask, + new_brownout << cfg->bo_offset_offset); + } +} + +static void mxs_setup_batt_detect(void) +{ + mxs_lradc_init(); + mxs_lradc_enable_batt_measurement(); + early_delay(10); +} + +static void mxs_ungate_power(void) +{ +#ifdef CONFIG_MX23 + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + writel(POWER_CTRL_CLKGATE, &power_regs->hw_power_ctrl_clr); +#endif +} + +void mxs_power_init(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + mxs_ungate_power(); + + mxs_power_clock2xtal(); + mxs_power_clear_auto_restart(); + mxs_power_set_linreg(); + mxs_power_setup_5v_detect(); + + mxs_setup_batt_detect(); + + mxs_power_configure_power_source(); + mxs_enable_output_rail_protection(); + + mxs_power_set_vddx(&mxs_vddio_cfg, 3300, 3150); + mxs_power_set_vddx(&mxs_vddd_cfg, 1500, 1000); +#ifdef CONFIG_MX23 + mxs_power_set_vddx(&mxs_vddmem_cfg, 2500, 1700); +#endif + writel(POWER_CTRL_VDDD_BO_IRQ | POWER_CTRL_VDDA_BO_IRQ | + POWER_CTRL_VDDIO_BO_IRQ | POWER_CTRL_VDD5V_DROOP_IRQ | + POWER_CTRL_VBUS_VALID_IRQ | POWER_CTRL_BATT_BO_IRQ | + POWER_CTRL_DCDC4P2_BO_IRQ, &power_regs->hw_power_ctrl_clr); + + writel(POWER_5VCTRL_PWDN_5VBRNOUT, &power_regs->hw_power_5vctrl_set); + + early_delay(1000); +} + +#ifdef CONFIG_SPL_MXS_PSWITCH_WAIT +void mxs_power_wait_pswitch(void) +{ + struct mxs_power_regs *power_regs = + (struct mxs_power_regs *)MXS_POWER_BASE; + + while (!(readl(&power_regs->hw_power_sts) & POWER_STS_PSWITCH_MASK)) + ; +} +#endif diff --git a/arch/arm/cpu/arm926ejs/mxs/start.S b/arch/arm/cpu/arm926ejs/mxs/start.S new file mode 100644 index 0000000..bf54423 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/start.S @@ -0,0 +1,209 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Groger <mag@sysgo.de> + * Copyright (c) 2002 Alex Zupke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.net> + * + * Change to support call back into iMX28 bootrom + * Copyright (c) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * 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 <asm-offsets.h> +#include <config.h> +#include <common.h> +#include <version.h> + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + + +.globl _start +_start: + b reset + b undefined_instruction + b software_interrupt + b prefetch_abort + b data_abort + b not_used + b irq + b fiq + +/* + * Vector table, located at address 0x20. + * This table allows the code running AFTER SPL, the U-Boot, to install it's + * interrupt handlers here. The problem is that the U-Boot is loaded into RAM, + * including it's interrupt vectoring table and the table at 0x0 is still the + * SPLs. So if interrupt happens in U-Boot, the SPLs interrupt vectoring table + * is still used. + */ +_vt_reset: + .word _reset +_vt_undefined_instruction: + .word _hang +_vt_software_interrupt: + .word _hang +_vt_prefetch_abort: + .word _hang +_vt_data_abort: + .word _hang +_vt_not_used: + .word _reset +_vt_irq: + .word _hang +_vt_fiq: + .word _hang + +reset: + ldr pc, _vt_reset +undefined_instruction: + ldr pc, _vt_undefined_instruction +software_interrupt: + ldr pc, _vt_software_interrupt +prefetch_abort: + ldr pc, _vt_prefetch_abort +data_abort: + ldr pc, _vt_data_abort +not_used: + ldr pc, _vt_not_used +irq: + ldr pc, _vt_irq +fiq: + ldr pc, _vt_fiq + + .balignl 16,0xdeadbeef + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + ************************************************************************* + */ + +.globl _TEXT_BASE +_TEXT_BASE: +#ifdef CONFIG_SPL_TEXT_BASE + .word CONFIG_SPL_TEXT_BASE +#else + .word CONFIG_SYS_TEXT_BASE +#endif + +/* + * These are defined in the board-specific linker script. + * Subtracting _start from them lets the linker put their + * relative position in the executable instead of leaving + * them null. + */ +.globl _bss_start_ofs +_bss_start_ofs: + .word __bss_start - _start + +.globl _bss_end_ofs +_bss_end_ofs: + .word __bss_end - _start + +.globl _end_ofs +_end_ofs: + .word _end - _start + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word 0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: + .word 0x0badc0de +#endif + +/* IRQ stack memory (calculated at run-time) + 8 bytes */ +.globl IRQ_STACK_START_IN +IRQ_STACK_START_IN: + .word 0x0badc0de + +/* + * the actual reset code + */ + +_reset: + /* + * Store all registers on old stack pointer, this will allow us later to + * return to the BootROM and let the BootROM load U-Boot into RAM. + */ + push {r0-r12,r14} + + /* save control register c1 */ + mrc p15, 0, r0, c1, c0, 0 + push {r0} + + /* + * set the cpu to SVC32 mode and store old CPSR register content + */ + mrs r0,cpsr + push {r0} + bic r0,r0,#0x1f + orr r0,r0,#0xd3 + msr cpsr,r0 + + bl board_init_ll + + /* + * restore bootrom's cpu mode (especially FIQ) + */ + pop {r0} + msr cpsr,r0 + + /* + * restore c1 register + * (especially set exception vector location back to + * bootrom space which is required by bootrom for USB boot) + */ + pop {r0} + mcr p15, 0, r0, c1, c0, 0 + + pop {r0-r12,r14} + bx lr + +_hang: + ldr sp, _TEXT_BASE /* switch to abort stack */ +1: + bl 1b /* hang and never return */ diff --git a/arch/arm/cpu/arm926ejs/mxs/timer.c b/arch/arm/cpu/arm926ejs/mxs/timer.c new file mode 100644 index 0000000..2039106 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/timer.c @@ -0,0 +1,175 @@ +/* + * Freescale i.MX28 timer driver + * + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * Based on code from LTIB: + * (C) Copyright 2009-2010 Freescale Semiconductor, Inc. + * + * 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 <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> + +/* Maximum fixed count */ +#if defined(CONFIG_MX23) +#define TIMER_LOAD_VAL 0xffff +#elif defined(CONFIG_MX28) +#define TIMER_LOAD_VAL 0xffffffff +#endif + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp (gd->arch.tbl) +#define lastdec (gd->arch.lastinc) + +/* + * This driver uses 1kHz clock source. + */ +#define MXS_INCREMENTER_HZ 1000 + +static inline unsigned long tick_to_time(unsigned long tick) +{ + return tick / (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ); +} + +static inline unsigned long time_to_tick(unsigned long time) +{ + return time * (MXS_INCREMENTER_HZ / CONFIG_SYS_HZ); +} + +/* Calculate how many ticks happen in "us" microseconds */ +static inline unsigned long us_to_tick(unsigned long us) +{ + return (us * MXS_INCREMENTER_HZ) / 1000000; +} + +int timer_init(void) +{ + struct mxs_timrot_regs *timrot_regs = + (struct mxs_timrot_regs *)MXS_TIMROT_BASE; + + /* Reset Timers and Rotary Encoder module */ + mxs_reset_block(&timrot_regs->hw_timrot_rotctrl_reg); + + /* Set fixed_count to 0 */ +#if defined(CONFIG_MX23) + writel(0, &timrot_regs->hw_timrot_timcount0); +#elif defined(CONFIG_MX28) + writel(0, &timrot_regs->hw_timrot_fixed_count0); +#endif + + /* Set UPDATE bit and 1Khz frequency */ + writel(TIMROT_TIMCTRLn_UPDATE | TIMROT_TIMCTRLn_RELOAD | + TIMROT_TIMCTRLn_SELECT_1KHZ_XTAL, + &timrot_regs->hw_timrot_timctrl0); + + /* Set fixed_count to maximal value */ +#if defined(CONFIG_MX23) + writel(TIMER_LOAD_VAL - 1, &timrot_regs->hw_timrot_timcount0); +#elif defined(CONFIG_MX28) + writel(TIMER_LOAD_VAL, &timrot_regs->hw_timrot_fixed_count0); +#endif + + return 0; +} + +unsigned long long get_ticks(void) +{ + struct mxs_timrot_regs *timrot_regs = + (struct mxs_timrot_regs *)MXS_TIMROT_BASE; + uint32_t now; + + /* Current tick value */ +#if defined(CONFIG_MX23) + /* Upper bits are the valid ones. */ + now = readl(&timrot_regs->hw_timrot_timcount0) >> + TIMROT_RUNNING_COUNTn_RUNNING_COUNT_OFFSET; +#elif defined(CONFIG_MX28) + now = readl(&timrot_regs->hw_timrot_running_count0); +#endif + + if (lastdec >= now) { + /* + * normal mode (non roll) + * move stamp forward with absolut diff ticks + */ + timestamp += (lastdec - now); + } else { + /* we have rollover of decrementer */ + timestamp += (TIMER_LOAD_VAL - now) + lastdec; + + } + lastdec = now; + + return timestamp; +} + +ulong get_timer_masked(void) +{ + return tick_to_time(get_ticks()); +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +/* We use the HW_DIGCTL_MICROSECONDS register for sub-millisecond timer. */ +#define MXS_HW_DIGCTL_MICROSECONDS 0x8001c0c0 + +void __udelay(unsigned long usec) +{ + uint32_t old, new, incr; + uint32_t counter = 0; + + old = readl(MXS_HW_DIGCTL_MICROSECONDS); + + while (counter < usec) { + new = readl(MXS_HW_DIGCTL_MICROSECONDS); + + /* Check if the timer wrapped. */ + if (new < old) { + incr = 0xffffffff - old; + incr += new; + } else { + incr = new - old; + } + + /* + * Check if we are close to the maximum time and the counter + * would wrap if incremented. If that's the case, break out + * from the loop as the requested delay time passed. + */ + if (counter + incr < counter) + break; + + counter += incr; + old = new; + } +} + +ulong get_tbclk(void) +{ + return MXS_INCREMENTER_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/mxs/u-boot-imx23.bd b/arch/arm/cpu/arm926ejs/mxs/u-boot-imx23.bd new file mode 100644 index 0000000..8b6c30e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/u-boot-imx23.bd @@ -0,0 +1,18 @@ +options { + driveTag = 0x00; + flags = 0x01; +} + +sources { + u_boot_spl="OBJTREE/spl/u-boot-spl.bin"; + u_boot="OBJTREE/u-boot.bin"; +} + +section (0) { + load u_boot_spl > 0x0000; + load ivt (entry = 0x0014) > 0x8000; + call 0x8000; + + load u_boot > 0x40000100; + call 0x40000100; +} diff --git a/arch/arm/cpu/arm926ejs/mxs/u-boot-imx28.bd b/arch/arm/cpu/arm926ejs/mxs/u-boot-imx28.bd new file mode 100644 index 0000000..a5fa648 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/u-boot-imx28.bd @@ -0,0 +1,14 @@ +sources { + u_boot_spl="OBJTREE/spl/u-boot-spl.bin"; + u_boot="OBJTREE/u-boot.bin"; +} + +section (0) { + load u_boot_spl > 0x0000; + load ivt (entry = 0x0014) > 0x8000; + hab call 0x8000; + + load u_boot > 0x40000100; + load ivt (entry = 0x40000100) > 0x8000; + hab call 0x8000; +} diff --git a/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds b/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds new file mode 100644 index 0000000..f4e7525 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/mxs/u-boot-spl.lds @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * January 2004 - Changed to support H4 device + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * 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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + arch/arm/cpu/arm926ejs/mxs/start.o (.text*) + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { + *(.data*) + } + + . = ALIGN(4); + + .rel.dyn : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + } + + .bss : { + . = ALIGN(4); + __bss_start = .; + *(.bss*) + . = ALIGN(4); + __bss_end = .; + } + + _end = .; + + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynsym*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.hash*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } +} diff --git a/arch/arm/cpu/arm926ejs/nomadik/Makefile b/arch/arm/cpu/arm926ejs/nomadik/Makefile new file mode 100644 index 0000000..1c1f58e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/nomadik/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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$(SOC).o + +COBJS = timer.o gpio.o +SOBJS = reset.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) $(addprefix $(obj),$(SOBJS)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/nomadik/gpio.c b/arch/arm/cpu/arm926ejs/nomadik/gpio.c new file mode 100644 index 0000000..62a375b --- /dev/null +++ b/arch/arm/cpu/arm926ejs/nomadik/gpio.c @@ -0,0 +1,99 @@ +/* + * (C) Copyright 2009 Alessandro Rubini + * + * 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 <asm/io.h> +#include <asm/arch/gpio.h> + +static unsigned long gpio_base[4] = { + NOMADIK_GPIO0_BASE, + NOMADIK_GPIO1_BASE, + NOMADIK_GPIO2_BASE, + NOMADIK_GPIO3_BASE +}; + +enum gpio_registers { + GPIO_DAT = 0x00, /* data register */ + GPIO_DATS = 0x04, /* data set */ + GPIO_DATC = 0x08, /* data clear */ + GPIO_PDIS = 0x0c, /* pull disable */ + GPIO_DIR = 0x10, /* direction */ + GPIO_DIRS = 0x14, /* direction set */ + GPIO_DIRC = 0x18, /* direction clear */ + GPIO_AFSLA = 0x20, /* alternate function select A */ + GPIO_AFSLB = 0x24, /* alternate function select B */ +}; + +static inline unsigned long gpio_to_base(int gpio) +{ + return gpio_base[gpio / 32]; +} + +static inline u32 gpio_to_bit(int gpio) +{ + return 1 << (gpio & 0x1f); +} + +void nmk_gpio_af(int gpio, int alternate_function) +{ + unsigned long base = gpio_to_base(gpio); + u32 bit = gpio_to_bit(gpio); + u32 afunc, bfunc; + + /* alternate function is 0..3, with one bit per register */ + afunc = readl(base + GPIO_AFSLA) & ~bit; + bfunc = readl(base + GPIO_AFSLB) & ~bit; + if (alternate_function & 1) afunc |= bit; + if (alternate_function & 2) bfunc |= bit; + writel(afunc, base + GPIO_AFSLA); + writel(bfunc, base + GPIO_AFSLB); +} + +void nmk_gpio_dir(int gpio, int dir) +{ + unsigned long base = gpio_to_base(gpio); + u32 bit = gpio_to_bit(gpio); + + if (dir) + writel(bit, base + GPIO_DIRS); + else + writel(bit, base + GPIO_DIRC); +} + +void nmk_gpio_set(int gpio, int val) +{ + unsigned long base = gpio_to_base(gpio); + u32 bit = gpio_to_bit(gpio); + + if (val) + writel(bit, base + GPIO_DATS); + else + writel(bit, base + GPIO_DATC); +} + +int nmk_gpio_get(int gpio) +{ + unsigned long base = gpio_to_base(gpio); + u32 bit = gpio_to_bit(gpio); + + return readl(base + GPIO_DAT) & bit; +} diff --git a/arch/arm/cpu/arm926ejs/nomadik/reset.S b/arch/arm/cpu/arm926ejs/nomadik/reset.S new file mode 100644 index 0000000..ec95472 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/nomadik/reset.S @@ -0,0 +1,14 @@ +#include <config.h> +/* + * Processor reset for Nomadik + */ + + .align 5 +.globl reset_cpu +reset_cpu: + ldr r0, =NOMADIK_SRC_BASE /* System and Reset Controller */ + ldr r1, =0x1 + str r1, [r0, #0x18] + +_loop_forever: + b _loop_forever diff --git a/arch/arm/cpu/arm926ejs/nomadik/timer.c b/arch/arm/cpu/arm926ejs/nomadik/timer.c new file mode 100644 index 0000000..bc2e4d5 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/nomadik/timer.c @@ -0,0 +1,87 @@ +/* + * (C) Copyright 2009 Alessandro Rubini + * + * 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 <asm/io.h> +#include <asm/arch/mtu.h> + +/* + * The timer is a decrementer, we'll left it free running at 2.4MHz. + * We have 2.4 ticks per microsecond and an overflow in almost 30min + */ +#define TIMER_CLOCK (24 * 100 * 1000) +#define COUNT_TO_USEC(x) ((x) * 5 / 12) /* overflows at 6min */ +#define USEC_TO_COUNT(x) ((x) * 12 / 5) /* overflows at 6min */ +#define TICKS_PER_HZ (TIMER_CLOCK / CONFIG_SYS_HZ) +#define TICKS_TO_HZ(x) ((x) / TICKS_PER_HZ) + +/* macro to read the decrementing 32 bit timer as an increasing count */ +#define READ_TIMER() (0 - readl(CONFIG_SYS_TIMERBASE + MTU_VAL(0))) + +/* Configure a free-running, auto-wrap counter with no prescaler */ +int timer_init(void) +{ + ulong val; + + writel(MTU_CRn_ENA | MTU_CRn_PRESCALE_1 | MTU_CRn_32BITS, + CONFIG_SYS_TIMERBASE + MTU_CR(0)); + + /* Reset the timer */ + writel(0, CONFIG_SYS_TIMERBASE + MTU_LR(0)); + /* + * The load-register isn't really immediate: it changes on clock + * edges, so we must wait for our newly-written value to appear. + * Since we might miss reading 0, wait for any change in value. + */ + val = READ_TIMER(); + while (READ_TIMER() == val) + ; + + return 0; +} + +/* Return how many HZ passed since "base" */ +ulong get_timer(ulong base) +{ + return TICKS_TO_HZ(READ_TIMER()) - base; +} + +/* Delay x useconds */ +void __udelay(unsigned long usec) +{ + ulong ini, end; + + ini = READ_TIMER(); + end = ini + USEC_TO_COUNT(usec); + while ((signed)(end - READ_TIMER()) > 0) + ; +} + +unsigned long long get_ticks(void) +{ + return get_timer(0); +} + +ulong get_tbclk(void) +{ + return CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/omap/Makefile b/arch/arm/cpu/arm926ejs/omap/Makefile new file mode 100644 index 0000000..862ca02 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/omap/Makefile @@ -0,0 +1,47 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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$(SOC).o + +COBJS = timer.o cpuinfo.o +SOBJS = reset.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/omap/cpuinfo.c b/arch/arm/cpu/arm926ejs/omap/cpuinfo.c new file mode 100644 index 0000000..02332ee --- /dev/null +++ b/arch/arm/cpu/arm926ejs/omap/cpuinfo.c @@ -0,0 +1,242 @@ +/* + * OMAP1 CPU identification code + * + * Copyright (C) 2004 Nokia Corporation + * Written by Tony Lindgren <tony@atomide.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <common.h> +#include <command.h> +#include <linux/compiler.h> + +#if defined(CONFIG_DISPLAY_CPUINFO) && defined(CONFIG_OMAP) + +#define omap_readw(x) *(volatile unsigned short *)(x) +#define omap_readl(x) *(volatile unsigned long *)(x) + +#define OMAP_DIE_ID_0 0xfffe1800 +#define OMAP_DIE_ID_1 0xfffe1804 +#define OMAP_PRODUCTION_ID_0 0xfffe2000 +#define OMAP_PRODUCTION_ID_1 0xfffe2004 +#define OMAP32_ID_0 0xfffed400 +#define OMAP32_ID_1 0xfffed404 + +struct omap_id { + u16 jtag_id; /* Used to determine OMAP type */ + u8 die_rev; /* Processor revision */ + u32 omap_id; /* OMAP revision */ + u32 type; /* Cpu id bits [31:08], cpu class bits [07:00] */ +}; + +/* Register values to detect the OMAP version */ +static struct omap_id omap_ids[] = { + { .jtag_id = 0xb574, .die_rev = 0x2, .omap_id = 0x03310315, .type = 0x03100000}, + { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100}, + { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300}, + { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000}, + { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000}, + { .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000}, + { .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00}, + { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00}, + { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, + { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, + { .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000}, + { .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00}, + { .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00}, + { .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300}, + { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300}, + { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300}, + { .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000}, + { .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000}, + { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000}, +}; + +/* + * Get OMAP type from PROD_ID. + * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM. + * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense. + * Undocumented register in TEST BLOCK is used as fallback; This seems to + * work on 1510, 1610 & 1710. The official way hopefully will work in future + * processors. + */ +static u16 omap_get_jtag_id(void) +{ + u32 prod_id, omap_id; + + prod_id = omap_readl(OMAP_PRODUCTION_ID_1); + omap_id = omap_readl(OMAP32_ID_1); + + /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */ + if (((prod_id >> 20) == 0) || (prod_id == omap_id)) + prod_id = 0; + else + prod_id &= 0xffff; + + if (prod_id) + return prod_id; + + /* Use OMAP32_ID_1 as fallback */ + prod_id = ((omap_id >> 12) & 0xffff); + + return prod_id; +} + +/* + * Get OMAP revision from DIE_REV. + * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID. + * Undocumented register in the TEST BLOCK is used as fallback. + * REVISIT: This does not seem to work on 1510 + */ +static u8 omap_get_die_rev(void) +{ + u32 die_rev; + + die_rev = omap_readl(OMAP_DIE_ID_1); + + /* Check for broken OMAP_DIE_ID on early 1710 */ + if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id()) + die_rev = 0; + + die_rev = (die_rev >> 17) & 0xf; + if (die_rev) + return die_rev; + + die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf; + + return die_rev; +} + +static unsigned long dpll1(void) +{ + unsigned short pll_ctl_val = omap_readw(DPLL_CTL_REG); + unsigned long rate; + + rate = CONFIG_SYS_CLK_FREQ; /* Base xtal rate */ + if (pll_ctl_val & 0x10) { + /* PLL enabled, apply multiplier and divisor */ + if (pll_ctl_val & 0xf80) + rate *= (pll_ctl_val & 0xf80) >> 7; + rate /= ((pll_ctl_val & 0x60) >> 5) + 1; + } else { + /* PLL disabled, apply bypass divisor */ + switch (pll_ctl_val & 0xc) { + case 0: + break; + case 0x4: + rate /= 2; + break; + default: + rate /= 4; + break; + } + } + + return rate; +} + +static unsigned long armcore(void) +{ + unsigned short arm_ckctl = omap_readw(ARM_CKCTL); + + return (dpll1() >> ((arm_ckctl & 0x0030) >> 4)); +} + +int print_cpuinfo (void) +{ + int i; + u16 jtag_id; + u8 die_rev; + u32 omap_id; + u8 cpu_type; + __maybe_unused u32 system_serial_high; + __maybe_unused u32 system_serial_low; + u32 system_rev = 0; + + jtag_id = omap_get_jtag_id(); + die_rev = omap_get_die_rev(); + omap_id = omap_readl(OMAP32_ID_0); + +#ifdef DEBUG + printf("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0)); + printf("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n", + omap_readl(OMAP_DIE_ID_1), + (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf); + printf("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0)); + printf("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n", + omap_readl(OMAP_PRODUCTION_ID_1), + omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff); + printf("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0)); + printf("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1)); + printf("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev); +#endif + + system_serial_high = omap_readl(OMAP_DIE_ID_0); + system_serial_low = omap_readl(OMAP_DIE_ID_1); + + /* First check only the major version in a safe way */ + for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { + if (jtag_id == (omap_ids[i].jtag_id)) { + system_rev = omap_ids[i].type; + break; + } + } + + /* Check if we can find the die revision */ + for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { + if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) { + system_rev = omap_ids[i].type; + break; + } + } + + /* Finally check also the omap_id */ + for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { + if (jtag_id == omap_ids[i].jtag_id + && die_rev == omap_ids[i].die_rev + && omap_id == omap_ids[i].omap_id) { + system_rev = omap_ids[i].type; + break; + } + } + + /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */ + cpu_type = system_rev >> 24; + + switch (cpu_type) { + case 0x07: + system_rev |= 0x07; + break; + case 0x03: + case 0x15: + system_rev |= 0x15; + break; + case 0x16: + case 0x17: + system_rev |= 0x16; + break; + case 0x24: + system_rev |= 0x24; + break; + default: + printf("Unknown OMAP cpu type: 0x%02x\n", cpu_type); + } + + printf("CPU: OMAP%04x", system_rev >> 16); + if ((system_rev >> 8) & 0xff) + printf("%x", (system_rev >> 8) & 0xff); +#ifdef DEBUG + printf(" revision %i handled as %02xxx id: %08x%08x", + die_rev, system_rev & 0xff, system_serial_low, system_serial_high); +#endif + printf(" at %ld.%01ld MHz (DPLL1=%ld.%01ld MHz)\n", + armcore() / 1000000, (armcore() / 100000) % 10, + dpll1() / 1000000, (dpll1() / 100000) % 10); + + return 0; +} + +#endif /* #if defined(CONFIG_DISPLAY_CPUINFO) && defined(CONFIG_OMAP) */ diff --git a/arch/arm/cpu/arm926ejs/omap/reset.S b/arch/arm/cpu/arm926ejs/omap/reset.S new file mode 100644 index 0000000..8321072 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/omap/reset.S @@ -0,0 +1,45 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * + * 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 + */ + + .align 5 +.globl reset_cpu +reset_cpu: + ldr r1, rstctl1 /* get clkm1 reset ctl */ + mov r3, #0x0 + strh r3, [r1] /* clear it */ + mov r3, #0x8 + strh r3, [r1] /* force dsp+arm reset */ +_loop_forever: + b _loop_forever + +rstctl1: + .word 0xfffece10 diff --git a/arch/arm/cpu/arm926ejs/omap/timer.c b/arch/arm/cpu/arm926ejs/omap/timer.c new file mode 100644 index 0000000..16530b0 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/omap/timer.c @@ -0,0 +1,168 @@ +/* + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * + * 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 <asm/io.h> + +#define TIMER_CLOCK (CONFIG_SYS_CLK_FREQ / (2 << CONFIG_SYS_PTV)) +#define TIMER_LOAD_VAL 0xffffffff + +/* macro to read the 32 bit timer */ +#define READ_TIMER readl(CONFIG_SYS_TIMERBASE+8) \ + / (TIMER_CLOCK / CONFIG_SYS_HZ) + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +int timer_init (void) +{ + int32_t val; + + /* Start the decrementer ticking down from 0xffffffff */ + *((int32_t *) (CONFIG_SYS_TIMERBASE + LOAD_TIM)) = TIMER_LOAD_VAL; + val = MPUTIM_ST | MPUTIM_AR | MPUTIM_CLOCK_ENABLE | (CONFIG_SYS_PTV << MPUTIM_PTV_BIT); + *((int32_t *) (CONFIG_SYS_TIMERBASE + CNTL_TIMER)) = val; + + /* init the timestamp and lastdec value */ + reset_timer_masked(); + + return 0; +} + +/* + * timer without interrupts + */ +ulong get_timer (ulong base) +{ + return get_timer_masked () - base; +} + +/* delay x useconds AND preserve advance timestamp value */ +void __udelay (unsigned long usec) +{ + ulong tmo, tmp; + + if(usec >= 1000){ /* if "big" number, spread normalization to seconds */ + tmo = usec / 1000; /* start to normalize for usec to ticks per sec */ + tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */ + tmo /= 1000; /* finish normalize. */ + }else{ /* else small number, don't kill it prior to HZ multiply */ + tmo = usec * CONFIG_SYS_HZ; + tmo /= (1000*1000); + } + + tmp = get_timer (0); /* get current timestamp */ + if( (tmo + tmp + 1) < tmp ) /* if setting this fordward will roll time stamp */ + reset_timer_masked (); /* reset "advancing" timestamp to 0, set lastdec value */ + else + tmo += tmp; /* else, set advancing stamp wake up time */ + + while (get_timer_masked () < tmo)/* loop till event */ + /*NOP*/; +} + +void reset_timer_masked (void) +{ + /* reset time */ + lastdec = READ_TIMER; /* capure current decrementer value time */ + timestamp = 0; /* start "advancing" time stamp from 0 */ +} + +ulong get_timer_masked (void) +{ + ulong now = READ_TIMER; /* current tick value */ + + if (lastdec >= now) { /* normal mode (non roll) */ + /* normal mode */ + timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */ + } else { /* we have overflow of the count down timer */ + /* nts = ts + ld + (TLV - now) + * ts=old stamp, ld=time that passed before passing through -1 + * (TLV-now) amount of time after passing though -1 + * nts = new "advancing time stamp"...it could also roll and cause problems. + */ + timestamp += lastdec + (TIMER_LOAD_VAL / (TIMER_CLOCK / + CONFIG_SYS_HZ)) - now; + } + lastdec = now; + + return timestamp; +} + +/* waits specified delay value and resets timestamp */ +void udelay_masked (unsigned long usec) +{ + ulong tmo; + ulong endtime; + signed long diff; + + if (usec >= 1000) { /* if "big" number, spread normalization to seconds */ + tmo = usec / 1000; /* start to normalize for usec to ticks per sec */ + tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */ + tmo /= 1000; /* finish normalize. */ + } else { /* else small number, don't kill it prior to HZ multiply */ + tmo = usec * CONFIG_SYS_HZ; + tmo /= (1000*1000); + } + + endtime = get_timer_masked () + tmo; + + do { + ulong now = get_timer_masked (); + diff = endtime - now; + } while (diff >= 0); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM 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 ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/orion5x/Makefile b/arch/arm/cpu/arm926ejs/orion5x/Makefile new file mode 100644 index 0000000..a4298b4 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/Makefile @@ -0,0 +1,55 @@ +# +# Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> +# +# Based on original Kirkwood support which is +# (C) Copyright 2009 +# Marvell Semiconductor <www.marvell.com> +# Written-by: Prafulla Wadaskar <prafulla@marvell.com> +# +# 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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS-y = cpu.o +COBJS-y += dram.o +COBJS-y += timer.o + +ifndef CONFIG_SKIP_LOWLEVEL_INIT +SOBJS := lowlevel_init.o +endif + +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/orion5x/cpu.c b/arch/arm/cpu/arm926ejs/orion5x/cpu.c new file mode 100644 index 0000000..5a4775a --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/cpu.c @@ -0,0 +1,311 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> + * + * Based on original Kirkwood support which is + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <netdev.h> +#include <asm/cache.h> +#include <asm/io.h> +#include <u-boot/md5.h> +#include <asm/arch/cpu.h> +#include <hush.h> + +#define BUFLEN 16 + +void reset_cpu(unsigned long ignored) +{ + struct orion5x_cpu_registers *cpureg = + (struct orion5x_cpu_registers *)ORION5X_CPU_REG_BASE; + + writel(readl(&cpureg->rstoutn_mask) | (1 << 2), + &cpureg->rstoutn_mask); + writel(readl(&cpureg->sys_soft_rst) | 1, + &cpureg->sys_soft_rst); + while (1) + ; +} + +/* + * Compute Window Size field value from size expressed in bytes + * Used with the Base register to set the address window size and location. + * Must be programmed from LSB to MSB as sequence of ones followed by + * sequence of zeros. The number of ones specifies the size of the window in + * 64 KiB granularity (e.g., a value of 0x00FF specifies 256 = 16 MiB). + * NOTES: + * 1) A sizeval equal to 0x0 specifies 4 GiB. + * 2) A return value of 0x0 specifies 64 KiB. + */ +unsigned int orion5x_winctrl_calcsize(unsigned int sizeval) +{ + /* + * Calculate the number of 64 KiB blocks needed minus one (rounding up). + * For sizeval > 0 this is equivalent to: + * sizeval = (u32) ceil((double) sizeval / 65536.0) - 1 + */ + sizeval = (sizeval - 1) >> 16; + + /* + * Propagate 'one' bits to the right by 'oring' them. + * We need only treat bits 15-0. + */ + sizeval |= sizeval >> 1; /* 'Or' bit 15 onto bit 14 */ + sizeval |= sizeval >> 2; /* 'Or' bits 15-14 onto bits 13-12 */ + sizeval |= sizeval >> 4; /* 'Or' bits 15-12 onto bits 11-8 */ + sizeval |= sizeval >> 8; /* 'Or' bits 15-8 onto bits 7-0*/ + + return sizeval; +} + +/* + * orion5x_config_adr_windows - Configure address Windows + * + * There are 8 address windows supported by Orion5x Soc to addess different + * devices. Each window can be configured for size, BAR and remap addr + * Below configuration is standard for most of the cases + * + * If remap function not used, remap_lo must be set as base + * + * NOTES: + * + * 1) in order to avoid windows with inconsistent control and base values + * (which could prevent access to BOOTCS and hence execution from FLASH) + * always disable window before writing the base value then reenable it + * by writing the control value. + * + * 2) in order to avoid losing access to BOOTCS when disabling window 7, + * first configure window 6 for BOOTCS, then configure window 7 for BOOTCS, + * then configure windows 6 for its own target. + * + * Reference Documentation: + * Mbus-L to Mbus Bridge Registers Configuration. + * (Sec 25.1 and 25.3 of Datasheet) + */ +int orion5x_config_adr_windows(void) +{ + struct orion5x_win_registers *winregs = + (struct orion5x_win_registers *)ORION5X_CPU_WIN_BASE; + +/* Disable window 0, configure it for its intended target, enable it. */ + writel(0, &winregs[0].ctrl); + writel(ORION5X_ADR_PCIE_MEM, &winregs[0].base); + writel(ORION5X_ADR_PCIE_MEM_REMAP_LO, &winregs[0].remap_lo); + writel(ORION5X_ADR_PCIE_MEM_REMAP_HI, &winregs[0].remap_hi); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCIE_MEM, + ORION5X_TARGET_PCIE, ORION5X_ATTR_PCIE_MEM, + ORION5X_WIN_ENABLE), &winregs[0].ctrl); +/* Disable window 1, configure it for its intended target, enable it. */ + writel(0, &winregs[1].ctrl); + writel(ORION5X_ADR_PCIE_IO, &winregs[1].base); + writel(ORION5X_ADR_PCIE_IO_REMAP_LO, &winregs[1].remap_lo); + writel(ORION5X_ADR_PCIE_IO_REMAP_HI, &winregs[1].remap_hi); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCIE_IO, + ORION5X_TARGET_PCIE, ORION5X_ATTR_PCIE_IO, + ORION5X_WIN_ENABLE), &winregs[1].ctrl); +/* Disable window 2, configure it for its intended target, enable it. */ + writel(0, &winregs[2].ctrl); + writel(ORION5X_ADR_PCI_MEM, &winregs[2].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCI_MEM, + ORION5X_TARGET_PCI, ORION5X_ATTR_PCI_MEM, + ORION5X_WIN_ENABLE), &winregs[2].ctrl); +/* Disable window 3, configure it for its intended target, enable it. */ + writel(0, &winregs[3].ctrl); + writel(ORION5X_ADR_PCI_IO, &winregs[3].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_PCI_IO, + ORION5X_TARGET_PCI, ORION5X_ATTR_PCI_IO, + ORION5X_WIN_ENABLE), &winregs[3].ctrl); +/* Disable window 4, configure it for its intended target, enable it. */ + writel(0, &winregs[4].ctrl); + writel(ORION5X_ADR_DEV_CS0, &winregs[4].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_DEV_CS0, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS0, + ORION5X_WIN_ENABLE), &winregs[4].ctrl); +/* Disable window 5, configure it for its intended target, enable it. */ + writel(0, &winregs[5].ctrl); + writel(ORION5X_ADR_DEV_CS1, &winregs[5].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_DEV_CS1, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS1, + ORION5X_WIN_ENABLE), &winregs[5].ctrl); +/* Disable window 6, configure it for FLASH, enable it. */ + writel(0, &winregs[6].ctrl); + writel(ORION5X_ADR_BOOTROM, &winregs[6].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_BOOTROM, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_BOOTROM, + ORION5X_WIN_ENABLE), &winregs[6].ctrl); +/* Disable window 7, configure it for FLASH, enable it. */ + writel(0, &winregs[7].ctrl); + writel(ORION5X_ADR_BOOTROM, &winregs[7].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_BOOTROM, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_BOOTROM, + ORION5X_WIN_ENABLE), &winregs[7].ctrl); +/* Disable window 6, configure it for its intended target, enable it. */ + writel(0, &winregs[6].ctrl); + writel(ORION5X_ADR_DEV_CS2, &winregs[6].base); + writel(ORION5X_CPU_WIN_CTRL_DATA(ORION5X_SZ_DEV_CS2, + ORION5X_TARGET_DEVICE, ORION5X_ATTR_DEV_CS2, + ORION5X_WIN_ENABLE), &winregs[6].ctrl); + + return 0; +} + +/* + * Orion5x identification is done through PCIE space. + */ + +u32 orion5x_device_id(void) +{ + return readl(PCIE_DEV_ID_OFF) >> 16; +} + +u32 orion5x_device_rev(void) +{ + return readl(PCIE_DEV_REV_OFF) & 0xff; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) + +/* Display device and revision IDs. + * This function must cover all known device/revision + * combinations, not only the one for which u-boot is + * compiled; this way, one can identify actual HW in + * case of a mismatch. + */ +int print_cpuinfo(void) +{ + char dev_str[7]; /* room enough for 0x0000 plus null byte */ + char rev_str[5]; /* room enough for 0x00 plus null byte */ + char *dev_name = NULL; + char *rev_name = NULL; + + u32 dev = orion5x_device_id(); + u32 rev = orion5x_device_rev(); + + if (dev == MV88F5181_DEV_ID) { + dev_name = "MV88F5181"; + if (rev == MV88F5181_REV_B1) + rev_name = "B1"; + else if (rev == MV88F5181L_REV_A1) { + dev_name = "MV88F5181L"; + rev_name = "A1"; + } else if (rev == MV88F5181L_REV_A0) { + dev_name = "MV88F5181L"; + rev_name = "A0"; + } + } else if (dev == MV88F5182_DEV_ID) { + dev_name = "MV88F5182"; + if (rev == MV88F5182_REV_A2) + rev_name = "A2"; + } else if (dev == MV88F5281_DEV_ID) { + dev_name = "MV88F5281"; + if (rev == MV88F5281_REV_D2) + rev_name = "D2"; + else if (rev == MV88F5281_REV_D1) + rev_name = "D1"; + else if (rev == MV88F5281_REV_D0) + rev_name = "D0"; + } else if (dev == MV88F6183_DEV_ID) { + dev_name = "MV88F6183"; + if (rev == MV88F6183_REV_B0) + rev_name = "B0"; + } + if (dev_name == NULL) { + sprintf(dev_str, "0x%04x", dev); + dev_name = dev_str; + } + if (rev_name == NULL) { + sprintf(rev_str, "0x%02x", rev); + rev_name = rev_str; + } + + printf("SoC: Orion5x %s-%s\n", dev_name, rev_name); + + return 0; +} +#endif /* CONFIG_DISPLAY_CPUINFO */ + +#ifdef CONFIG_ARCH_CPU_INIT +int arch_cpu_init(void) +{ + /* Enable and invalidate L2 cache in write through mode */ + invalidate_l2_cache(); + + orion5x_config_adr_windows(); + + return 0; +} +#endif /* CONFIG_ARCH_CPU_INIT */ + +/* + * SOC specific misc init + */ +#if defined(CONFIG_ARCH_MISC_INIT) +int arch_misc_init(void) +{ + u32 temp; + + /*CPU streaming & write allocate */ + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 28); /* disable wr alloc */ + writefr_extra_feature_reg(temp); + + temp = readfr_extra_feature_reg(); + temp &= ~(1 << 29); /* streaming disabled */ + writefr_extra_feature_reg(temp); + + /* L2Cache settings */ + temp = readfr_extra_feature_reg(); + /* Disable L2C pre fetch - Set bit 24 */ + temp |= (1 << 24); + /* enable L2C - Set bit 22 */ + temp |= (1 << 22); + writefr_extra_feature_reg(temp); + + icache_enable(); + /* Change reset vector to address 0x0 */ + temp = get_cr(); + set_cr(temp & ~CR_V); + + /* Set CPIOs and MPPs - values provided by board + include file */ + writel(ORION5X_MPP0_7, ORION5X_MPP_BASE+0x00); + writel(ORION5X_MPP8_15, ORION5X_MPP_BASE+0x04); + writel(ORION5X_MPP16_23, ORION5X_MPP_BASE+0x50); + writel(ORION5X_GPIO_OUT_VALUE, ORION5X_GPIO_BASE+0x00); + writel(ORION5X_GPIO_OUT_ENABLE, ORION5X_GPIO_BASE+0x04); + writel(ORION5X_GPIO_IN_POLARITY, ORION5X_GPIO_BASE+0x0c); + + /* initialize timer */ + timer_init_r(); + return 0; +} +#endif /* CONFIG_ARCH_MISC_INIT */ + +#ifdef CONFIG_MVGBE +int cpu_eth_init(bd_t *bis) +{ + mvgbe_initialize(bis); + return 0; +} +#endif diff --git a/arch/arm/cpu/arm926ejs/orion5x/dram.c b/arch/arm/cpu/arm926ejs/orion5x/dram.c new file mode 100644 index 0000000..c0f7ef1 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/dram.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> + * + * Based on original Kirkwood support which is + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <config.h> +#include <asm/arch/cpu.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * orion5x_sdram_bar - reads SDRAM Base Address Register + */ +u32 orion5x_sdram_bar(enum memory_bank bank) +{ + struct orion5x_ddr_addr_decode_registers *winregs = + (struct orion5x_ddr_addr_decode_registers *) + ORION5X_DRAM_BASE; + + u32 result = 0; + u32 enable = 0x01 & winregs[bank].size; + + if ((!enable) || (bank > BANK3)) + return 0; + + result = winregs[bank].base; + return result; +} +int dram_init (void) +{ + /* dram_init must store complete ramsize in gd->ram_size */ + gd->ram_size = get_ram_size( + (long *) orion5x_sdram_bar(0), + CONFIG_MAX_RAM_BANK_SIZE); + return 0; +} + +void dram_init_banksize (void) +{ + int i; + + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + gd->bd->bi_dram[i].start = orion5x_sdram_bar(i); + gd->bd->bi_dram[i].size = get_ram_size( + (long *) (gd->bd->bi_dram[i].start), + CONFIG_MAX_RAM_BANK_SIZE); + } +} diff --git a/arch/arm/cpu/arm926ejs/orion5x/lowlevel_init.S b/arch/arm/cpu/arm926ejs/orion5x/lowlevel_init.S new file mode 100644 index 0000000..a2de3cf --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/lowlevel_init.S @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> + * + * (C) Copyright 2009 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <config.h> +#include "asm/arch/orion5x.h" + +/* + * Configuration values for SDRAM access setup + */ + +#define SDRAM_CONFIG 0x3148400 +#define SDRAM_MODE 0x62 +#define SDRAM_CONTROL 0x4041000 +#define SDRAM_TIME_CTRL_LOW 0x11602220 +#define SDRAM_TIME_CTRL_HI 0x40c +#define SDRAM_OPEN_PAGE_EN 0x0 +/* DDR 1 2x 32M NANYA NT5DS16M16CS-6K ==> 64MB */ +#define SDRAM_BANK0_SIZE 0x3ff0001 +#define SDRAM_ADDR_CTRL 0x10 + +#define SDRAM_OP_NOP 0x05 +#define SDRAM_OP_SETMODE 0x03 + +#define SDRAM_PAD_CTRL_WR_EN 0x80000000 +#define SDRAM_PAD_CTRL_TUNE_EN 0x00010000 +#define SDRAM_PAD_CTRL_DRVN_MASK 0x0000003f +#define SDRAM_PAD_CTRL_DRVP_MASK 0x00000fc0 + +/* + * For Guideline MEM-3 - Drive Strength value + */ + +#define DDR1_PAD_STRENGTH_DEFAULT 0x00001000 +#define SDRAM_PAD_CTRL_DRV_STR_MASK 0x00003000 + +/* + * For Guideline MEM-4 - DQS Reference Delay Tuning + */ + +#define MSAR_ARMDDRCLCK_MASK 0x000000f0 +#define MSAR_ARMDDRCLCK_H_MASK 0x00000100 + +#define MSAR_ARMDDRCLCK_333_167 0x00000000 +#define MSAR_ARMDDRCLCK_500_167 0x00000030 +#define MSAR_ARMDDRCLCK_667_167 0x00000060 +#define MSAR_ARMDDRCLCK_400_200_1 0x000001E0 +#define MSAR_ARMDDRCLCK_400_200 0x00000010 +#define MSAR_ARMDDRCLCK_600_200 0x00000050 +#define MSAR_ARMDDRCLCK_800_200 0x00000070 + +#define FTDLL_DDR1_166MHZ 0x0047F001 + +#define FTDLL_DDR1_200MHZ 0x0044D001 + +/* + * Low-level init happens right after start.S has switched to SVC32, + * flushed and disabled caches and disabled MMU. We're still running + * from the boot chip select, so the first thing we should do is set + * up RAM for us to relocate into. + */ + +.globl lowlevel_init + +lowlevel_init: + + /* Use 'r4 as the base for internal register accesses */ + ldr r4, =ORION5X_REGS_PHY_BASE + + /* move internal registers from the default 0xD0000000 + * to their intended location, defined by SoC */ + ldr r3, =0xD0000000 + add r3, r3, #0x20000 + str r4, [r3, #0x80] + + /* Use R3 as the base for DRAM registers */ + add r3, r4, #0x01000 + + /*DDR SDRAM Initialization Control */ + ldr r6, =0x00000001 + str r6, [r3, #0x480] + + /* Use R3 as the base for PCI registers */ + add r3, r4, #0x31000 + + /* Disable arbiter */ + ldr r6, =0x00000030 + str r6, [r3, #0xd00] + + /* Use R3 as the base for DRAM registers */ + add r3, r4, #0x01000 + + /* set all dram windows to 0 */ + mov r6, #0 + str r6, [r3, #0x504] + str r6, [r3, #0x50C] + str r6, [r3, #0x514] + str r6, [r3, #0x51C] + + /* 1) Configure SDRAM */ + ldr r6, =SDRAM_CONFIG + str r6, [r3, #0x400] + + /* 2) Set SDRAM Control reg */ + ldr r6, =SDRAM_CONTROL + str r6, [r3, #0x404] + + /* 3) Write SDRAM address control register */ + ldr r6, =SDRAM_ADDR_CTRL + str r6, [r3, #0x410] + + /* 4) Write SDRAM bank 0 size register */ + ldr r6, =SDRAM_BANK0_SIZE + str r6, [r3, #0x504] + /* keep other banks disabled */ + + /* 5) Write SDRAM open pages control register */ + ldr r6, =SDRAM_OPEN_PAGE_EN + str r6, [r3, #0x414] + + /* 6) Write SDRAM timing Low register */ + ldr r6, =SDRAM_TIME_CTRL_LOW + str r6, [r3, #0x408] + + /* 7) Write SDRAM timing High register */ + ldr r6, =SDRAM_TIME_CTRL_HI + str r6, [r3, #0x40C] + + /* 8) Write SDRAM mode register */ + /* The CPU must not attempt to change the SDRAM Mode register setting */ + /* prior to DRAM controller completion of the DRAM initialization */ + /* sequence. To guarantee this restriction, it is recommended that */ + /* the CPU sets the SDRAM Operation register to NOP command, performs */ + /* read polling until the register is back in Normal operation value, */ + /* and then sets SDRAM Mode register to its new value. */ + + /* 8.1 write 'nop' to SDRAM operation */ + ldr r6, =SDRAM_OP_NOP + str r6, [r3, #0x418] + + /* 8.2 poll SDRAM operation until back in 'normal' mode. */ +1: + ldr r6, [r3, #0x418] + cmp r6, #0 + bne 1b + + /* 8.3 Now its safe to write new value to SDRAM Mode register */ + ldr r6, =SDRAM_MODE + str r6, [r3, #0x41C] + + /* 8.4 Set new mode */ + ldr r6, =SDRAM_OP_SETMODE + str r6, [r3, #0x418] + + /* 8.5 poll SDRAM operation until back in 'normal' mode. */ +2: + ldr r6, [r3, #0x418] + cmp r6, #0 + bne 2b + + /* DDR SDRAM Address/Control Pads Calibration */ + ldr r6, [r3, #0x4C0] + + /* Set Bit [31] to make the register writable */ + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C0] + + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + bic r6, r6, #SDRAM_PAD_CTRL_TUNE_EN + bic r6, r6, #SDRAM_PAD_CTRL_DRVN_MASK + bic r6, r6, #SDRAM_PAD_CTRL_DRVP_MASK + + /* Get the final N locked value of driving strength [22:17] */ + mov r1, r6 + mov r1, r1, LSL #9 + mov r1, r1, LSR #26 /* r1[5:0]<DrvN> = r3[22:17]<LockN> */ + orr r1, r1, r1, LSL #6 /* r1[11:6]<DrvP> = r1[5:0]<DrvN> */ + + /* Write to both <DrvN> bits [5:0] and <DrvP> bits [11:6] */ + orr r6, r6, r1 + str r6, [r3, #0x4C0] + + /* DDR SDRAM Data Pads Calibration */ + ldr r6, [r3, #0x4C4] + + /* Set Bit [31] to make the register writable */ + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C4] + + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + bic r6, r6, #SDRAM_PAD_CTRL_TUNE_EN + bic r6, r6, #SDRAM_PAD_CTRL_DRVN_MASK + bic r6, r6, #SDRAM_PAD_CTRL_DRVP_MASK + + /* Get the final N locked value of driving strength [22:17] */ + mov r1, r6 + mov r1, r1, LSL #9 + mov r1, r1, LSR #26 + orr r1, r1, r1, LSL #6 /* r1[5:0] = r3[22:17]<LockN> */ + + /* Write to both <DrvN> bits [5:0] and <DrvP> bits [11:6] */ + orr r6, r6, r1 + + str r6, [r3, #0x4C4] + + /* Implement Guideline (GL# MEM-3) Drive Strength Value */ + /* Relevant for: 88F5181-A1/B0/B1 and 88F5281-A0/B0 */ + + ldr r1, =DDR1_PAD_STRENGTH_DEFAULT + + /* Enable writes to DDR SDRAM Addr/Ctrl Pads Calibration register */ + ldr r6, [r3, #0x4C0] + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C0] + + /* Correct strength and disable writes again */ + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + bic r6, r6, #SDRAM_PAD_CTRL_DRV_STR_MASK + orr r6, r6, r1 + str r6, [r3, #0x4C0] + + /* Enable writes to DDR SDRAM Data Pads Calibration register */ + ldr r6, [r3, #0x4C4] + orr r6, r6, #SDRAM_PAD_CTRL_WR_EN + str r6, [r3, #0x4C4] + + /* Correct strength and disable writes again */ + bic r6, r6, #SDRAM_PAD_CTRL_DRV_STR_MASK + bic r6, r6, #SDRAM_PAD_CTRL_WR_EN + orr r6, r6, r1 + str r6, [r3, #0x4C4] + + /* Implement Guideline (GL# MEM-4) DQS Reference Delay Tuning */ + /* Relevant for: 88F5181-A1/B0/B1 and 88F5281-A0/B0 */ + + /* Get the "sample on reset" register for the DDR frequancy */ + ldr r3, =0x10000 + ldr r6, [r3, #0x010] + ldr r1, =MSAR_ARMDDRCLCK_MASK + and r1, r6, r1 + + ldr r6, =FTDLL_DDR1_166MHZ + cmp r1, #MSAR_ARMDDRCLCK_333_167 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_500_167 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_667_167 + beq 3f + + ldr r6, =FTDLL_DDR1_200MHZ + cmp r1, #MSAR_ARMDDRCLCK_400_200_1 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_400_200 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_600_200 + beq 3f + cmp r1, #MSAR_ARMDDRCLCK_800_200 + beq 3f + + ldr r6, =0 + +3: + /* Use R3 as the base for DRAM registers */ + add r3, r4, #0x01000 + + ldr r2, [r3, #0x484] + orr r2, r2, r6 + str r2, [r3, #0x484] + + /* Return to U-boot via saved link register */ + mov pc, lr diff --git a/arch/arm/cpu/arm926ejs/orion5x/timer.c b/arch/arm/cpu/arm926ejs/orion5x/timer.c new file mode 100644 index 0000000..f723351 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/orion5x/timer.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2010 Albert ARIBAUD <albert.u.boot@aribaud.net> + * + * Based on original Kirkwood support which is + * Copyright (C) Marvell International Ltd. and its affiliates + * Written-by: Prafulla Wadaskar <prafulla@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/io.h> + +#define UBOOT_CNTR 0 /* counter to use for uboot timer */ + +/* Timer reload and current value registers */ +struct orion5x_tmr_val { + u32 reload; /* Timer reload reg */ + u32 val; /* Timer value reg */ +}; + +/* Timer registers */ +struct orion5x_tmr_registers { + u32 ctrl; /* Timer control reg */ + u32 pad[3]; + struct orion5x_tmr_val tmr[2]; + u32 wdt_reload; + u32 wdt_val; +}; + +struct orion5x_tmr_registers *orion5x_tmr_regs = + (struct orion5x_tmr_registers *)ORION5X_TIMER_BASE; + +/* + * ARM Timers Registers Map + */ +#define CNTMR_CTRL_REG (&orion5x_tmr_regs->ctrl) +#define CNTMR_RELOAD_REG(tmrnum) (&orion5x_tmr_regs->tmr[tmrnum].reload) +#define CNTMR_VAL_REG(tmrnum) (&orion5x_tmr_regs->tmr[tmrnum].val) + +/* + * ARM Timers Control Register + * CPU_TIMERS_CTRL_REG (CTCR) + */ +#define CTCR_ARM_TIMER_EN_OFFS(cntr) (cntr * 2) +#define CTCR_ARM_TIMER_EN_MASK(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS) +#define CTCR_ARM_TIMER_EN(cntr) (1 << CTCR_ARM_TIMER_EN_OFFS(cntr)) +#define CTCR_ARM_TIMER_DIS(cntr) (0 << CTCR_ARM_TIMER_EN_OFFS(cntr)) + +#define CTCR_ARM_TIMER_AUTO_OFFS(cntr) ((cntr * 2) + 1) +#define CTCR_ARM_TIMER_AUTO_MASK(cntr) (1 << 1) +#define CTCR_ARM_TIMER_AUTO_EN(cntr) (1 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) +#define CTCR_ARM_TIMER_AUTO_DIS(cntr) (0 << CTCR_ARM_TIMER_AUTO_OFFS(cntr)) + +/* + * ARM Timer\Watchdog Reload Register + * CNTMR_RELOAD_REG (TRR) + */ +#define TRG_ARM_TIMER_REL_OFFS 0 +#define TRG_ARM_TIMER_REL_MASK 0xffffffff + +/* + * ARM Timer\Watchdog Register + * CNTMR_VAL_REG (TVRG) + */ +#define TVR_ARM_TIMER_OFFS 0 +#define TVR_ARM_TIMER_MASK 0xffffffff +#define TVR_ARM_TIMER_MAX 0xffffffff +#define TIMER_LOAD_VAL 0xffffffff + +static inline ulong read_timer(void) +{ + return readl(CNTMR_VAL_REG(UBOOT_CNTR)) + / (CONFIG_SYS_TCLK / 1000); +} + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +ulong get_timer_masked(void) +{ + ulong now = read_timer(); + + if (lastdec >= now) { + /* normal mode */ + timestamp += lastdec - now; + } else { + /* we have an overflow ... */ + timestamp += lastdec + + (TIMER_LOAD_VAL / (CONFIG_SYS_TCLK / 1000)) - now; + } + lastdec = now; + + return timestamp; +} + +ulong get_timer(ulong base) +{ + return get_timer_masked() - base; +} + +static inline ulong uboot_cntr_val(void) +{ + return readl(CNTMR_VAL_REG(UBOOT_CNTR)); +} + +void __udelay(unsigned long usec) +{ + uint current; + ulong delayticks; + + current = uboot_cntr_val(); + delayticks = (usec * (CONFIG_SYS_TCLK / 1000000)); + + if (current < delayticks) { + delayticks -= current; + while (uboot_cntr_val() < current) + ; + while ((TIMER_LOAD_VAL - delayticks) < uboot_cntr_val()) + ; + } else { + while (uboot_cntr_val() > (current - delayticks)) + ; + } +} + +/* + * init the counter + */ +int timer_init(void) +{ + unsigned int cntmrctrl; + + /* load value into timer */ + writel(TIMER_LOAD_VAL, CNTMR_RELOAD_REG(UBOOT_CNTR)); + writel(TIMER_LOAD_VAL, CNTMR_VAL_REG(UBOOT_CNTR)); + + /* enable timer in auto reload mode */ + cntmrctrl = readl(CNTMR_CTRL_REG); + cntmrctrl |= CTCR_ARM_TIMER_EN(UBOOT_CNTR); + cntmrctrl |= CTCR_ARM_TIMER_AUTO_EN(UBOOT_CNTR); + writel(cntmrctrl, CNTMR_CTRL_REG); + return 0; +} + +void timer_init_r(void) +{ + /* init the timestamp and lastdec value */ + lastdec = read_timer(); + timestamp = 0; +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM 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 ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return (ulong)CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/pantheon/Makefile b/arch/arm/cpu/arm926ejs/pantheon/Makefile new file mode 100644 index 0000000..8f962b0 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/pantheon/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2011 +# Marvell Semiconductor <www.marvell.com> +# Written-by: Lei Wen <leiwen@marvell.com> +# +# 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., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).o + +COBJS-y = cpu.o timer.o dram.o + +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS-y)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/pantheon/cpu.c b/arch/arm/cpu/arm926ejs/pantheon/cpu.c new file mode 100644 index 0000000..db9b348 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/pantheon/cpu.c @@ -0,0 +1,101 @@ +/* + * (C) Copyright 2011 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Lei Wen <leiwen@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/pantheon.h> + +#define UARTCLK14745KHZ (APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(1)) +#define SET_MRVL_ID (1<<8) +#define L2C_RAM_SEL (1<<4) + +int arch_cpu_init(void) +{ + u32 val; + struct panthcpu_registers *cpuregs = + (struct panthcpu_registers*) PANTHEON_CPU_BASE; + + struct panthapb_registers *apbclkres = + (struct panthapb_registers*) PANTHEON_APBC_BASE; + + struct panthmpmu_registers *mpmu = + (struct panthmpmu_registers*) PANTHEON_MPMU_BASE; + + struct panthapmu_registers *apmu = + (struct panthapmu_registers *) PANTHEON_APMU_BASE; + + /* set SEL_MRVL_ID bit in PANTHEON_CPU_CONF register */ + val = readl(&cpuregs->cpu_conf); + val = val | SET_MRVL_ID; + writel(val, &cpuregs->cpu_conf); + + /* Turn on clock gating (PMUM_CCGR) */ + writel(0xFFFFFFFF, &mpmu->ccgr); + + /* Turn on clock gating (PMUM_ACGR) */ + writel(0xFFFFFFFF, &mpmu->acgr); + + /* Turn on uart2 clock */ + writel(UARTCLK14745KHZ, &apbclkres->uart0); + + /* Enable GPIO clock */ + writel(APBC_APBCLK, &apbclkres->gpio); + +#ifdef CONFIG_I2C_MV + /* Enable I2C clock */ + writel(APBC_RST | APBC_FNCLK | APBC_APBCLK, &apbclkres->twsi); + writel(APBC_FNCLK | APBC_APBCLK, &apbclkres->twsi); +#endif + +#ifdef CONFIG_MV_SDHCI + /* Enable mmc clock */ + writel(APMU_PERI_CLK | APMU_AXI_CLK | APMU_PERI_RST | APMU_AXI_RST, + &apmu->sd1); + writel(APMU_PERI_CLK | APMU_AXI_CLK | APMU_PERI_RST | APMU_AXI_RST, + &apmu->sd3); +#endif + + icache_enable(); + + return 0; +} + +#if defined(CONFIG_DISPLAY_CPUINFO) +int print_cpuinfo(void) +{ + u32 id; + struct panthcpu_registers *cpuregs = + (struct panthcpu_registers*) PANTHEON_CPU_BASE; + + id = readl(&cpuregs->chip_id); + printf("SoC: PANTHEON 88AP%X-%X\n", (id & 0xFFF), (id >> 0x10)); + return 0; +} +#endif + +#ifdef CONFIG_I2C_MV +void i2c_clk_enable(void) +{ +} +#endif diff --git a/arch/arm/cpu/arm926ejs/pantheon/dram.c b/arch/arm/cpu/arm926ejs/pantheon/dram.c new file mode 100644 index 0000000..a3d719e --- /dev/null +++ b/arch/arm/cpu/arm926ejs/pantheon/dram.c @@ -0,0 +1,133 @@ +/* + * (C) Copyright 2011 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Lei Wen <leiwen@marvell.com>, + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/pantheon.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Pantheon DRAM controller supports upto 8 banks + * for chip select 0 and 1 + */ + +/* + * DDR Memory Control Registers + * Refer Datasheet 4.4 + */ +struct panthddr_map_registers { + u32 cs; /* Memory Address Map Register -CS */ + u32 pad[3]; +}; + +struct panthddr_registers { + u8 pad[0x100 - 0x000]; + struct panthddr_map_registers mmap[2]; +}; + +/* + * panth_sdram_base - reads SDRAM Base Address Register + */ +u32 panth_sdram_base(int chip_sel) +{ + struct panthddr_registers *ddr_regs = + (struct panthddr_registers *)PANTHEON_DRAM_BASE; + u32 result = 0; + u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs); + + if (!CS_valid) + return 0; + + result = readl(&ddr_regs->mmap[chip_sel].cs) & 0xFF800000; + return result; +} + +/* + * panth_sdram_size - reads SDRAM size + */ +u32 panth_sdram_size(int chip_sel) +{ + struct panthddr_registers *ddr_regs = + (struct panthddr_registers *)PANTHEON_DRAM_BASE; + u32 result = 0; + u32 CS_valid = 0x01 & readl(&ddr_regs->mmap[chip_sel].cs); + + if (!CS_valid) + return 0; + + result = readl(&ddr_regs->mmap[chip_sel].cs); + result = (result >> 16) & 0xF; + if (result < 0x7) { + printf("Unknown DRAM Size\n"); + return -1; + } else { + return ((0x8 << (result - 0x7)) * 1024 * 1024); + } +} + +#ifndef CONFIG_SYS_BOARD_DRAM_INIT +int dram_init(void) +{ + int i; + + gd->ram_size = 0; + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + gd->bd->bi_dram[i].start = panth_sdram_base(i); + gd->bd->bi_dram[i].size = panth_sdram_size(i); + /* + * It is assumed that all memory banks are consecutive + * and without gaps. + * If the gap is found, ram_size will be reported for + * consecutive memory only + */ + if (gd->bd->bi_dram[i].start != gd->ram_size) + break; + + gd->ram_size += gd->bd->bi_dram[i].size; + + } + + for (; i < CONFIG_NR_DRAM_BANKS; i++) { + /* + * If above loop terminated prematurely, we need to set + * remaining banks' start address & size as 0. Otherwise other + * u-boot functions and Linux kernel gets wrong values which + * could result in crash + */ + gd->bd->bi_dram[i].start = 0; + gd->bd->bi_dram[i].size = 0; + } + return 0; +} + +/* + * If this function is not defined here, + * board.c alters dram bank zero configuration defined above. + */ +void dram_init_banksize(void) +{ + dram_init(); +} +#endif /* CONFIG_SYS_BOARD_DRAM_INIT */ diff --git a/arch/arm/cpu/arm926ejs/pantheon/timer.c b/arch/arm/cpu/arm926ejs/pantheon/timer.c new file mode 100644 index 0000000..2d9ddba --- /dev/null +++ b/arch/arm/cpu/arm926ejs/pantheon/timer.c @@ -0,0 +1,217 @@ +/* + * (C) Copyright 2011 + * Marvell Semiconductor <www.marvell.com> + * Written-by: Lei Wen <leiwen@marvell.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <common.h> +#include <asm/arch/cpu.h> +#include <asm/arch/pantheon.h> + +/* + * Timer registers + * Refer 6.2.9 in Datasheet + */ +struct panthtmr_registers { + u32 clk_ctrl; /* Timer clk control reg */ + u32 match[9]; /* Timer match registers */ + u32 count[3]; /* Timer count registers */ + u32 status[3]; + u32 ie[3]; + u32 preload[3]; /* Timer preload value */ + u32 preload_ctrl[3]; + u32 wdt_match_en; + u32 wdt_match_r; + u32 wdt_val; + u32 wdt_sts; + u32 icr[3]; + u32 wdt_icr; + u32 cer; /* Timer count enable reg */ + u32 cmr; + u32 ilr[3]; + u32 wcr; + u32 wfar; + u32 wsar; + u32 cvwr[3]; +}; + +#define TIMER 0 /* Use TIMER 0 */ +/* Each timer has 3 match registers */ +#define MATCH_CMP(x) ((3 * TIMER) + x) +#define TIMER_LOAD_VAL 0xffffffff +#define COUNT_RD_REQ 0x1 + +DECLARE_GLOBAL_DATA_PTR; +/* Using gd->arch.tbu from timestamp and gd->arch.tbl for lastdec */ + +/* + * For preventing risk of instability in reading counter value, + * first set read request to register cvwr and then read same + * register after it captures counter value. + */ +ulong read_timer(void) +{ + struct panthtmr_registers *panthtimers = + (struct panthtmr_registers *) PANTHEON_TIMER_BASE; + volatile int loop=100; + ulong val; + + writel(COUNT_RD_REQ, &panthtimers->cvwr); + while (loop--) + val = readl(&panthtimers->cvwr); + + /* + * This stop gcc complain and prevent loop mistake init to 0 + */ + val = readl(&panthtimers->cvwr); + + return val; +} + +ulong get_timer_masked(void) +{ + ulong now = read_timer(); + + if (now >= gd->arch.tbl) { + /* normal mode */ + gd->arch.tbu += now - gd->arch.tbl; + } else { + /* we have an overflow ... */ + gd->arch.tbu += now + TIMER_LOAD_VAL - gd->arch.tbl; + } + gd->arch.tbl = now; + + return gd->arch.tbu; +} + +ulong get_timer(ulong base) +{ + return ((get_timer_masked() / (CONFIG_SYS_HZ_CLOCK / 1000)) - + base); +} + +void __udelay(unsigned long usec) +{ + ulong delayticks; + ulong endtime; + + delayticks = (usec * (CONFIG_SYS_HZ_CLOCK / 1000000)); + endtime = get_timer_masked() + delayticks; + + while (get_timer_masked() < endtime) + ; +} + +/* + * init the Timer + */ +int timer_init(void) +{ + struct panthapb_registers *apb1clkres = + (struct panthapb_registers *) PANTHEON_APBC_BASE; + struct panthtmr_registers *panthtimers = + (struct panthtmr_registers *) PANTHEON_TIMER_BASE; + + /* Enable Timer clock at 3.25 MHZ */ + writel(APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(3), &apb1clkres->timers); + + /* load value into timer */ + writel(0x0, &panthtimers->clk_ctrl); + /* Use Timer 0 Match Resiger 0 */ + writel(TIMER_LOAD_VAL, &panthtimers->match[MATCH_CMP(0)]); + /* Preload value is 0 */ + writel(0x0, &panthtimers->preload[TIMER]); + /* Enable match comparator 0 for Timer 0 */ + writel(0x1, &panthtimers->preload_ctrl[TIMER]); + + /* Enable timer 0 */ + writel(0x1, &panthtimers->cer); + /* init the gd->arch.tbu and gd->arch.tbl value */ + gd->arch.tbl = read_timer(); + gd->arch.tbu = 0; + + return 0; +} + +#define MPMU_APRR_WDTR (1<<4) +#define TMR_WFAR 0xbaba /* WDT Register First key */ +#define TMP_WSAR 0xeb10 /* WDT Register Second key */ + +/* + * This function uses internal Watchdog Timer + * based reset mechanism. + * Steps to write watchdog registers (protected access) + * 1. Write key value to TMR_WFAR reg. + * 2. Write key value to TMP_WSAR reg. + * 3. Perform write operation. + */ +void reset_cpu (unsigned long ignored) +{ + struct panthmpmu_registers *mpmu = + (struct panthmpmu_registers *) PANTHEON_MPMU_BASE; + struct panthtmr_registers *panthtimers = + (struct panthtmr_registers *) PANTHEON_WD_TIMER_BASE; + u32 val; + + /* negate hardware reset to the WDT after system reset */ + val = readl(&mpmu->aprr); + val = val | MPMU_APRR_WDTR; + writel(val, &mpmu->aprr); + + /* reset/enable WDT clock */ + writel(APBC_APBCLK, &mpmu->wdtpcr); + + /* clear previous WDT status */ + writel(TMR_WFAR, &panthtimers->wfar); + writel(TMP_WSAR, &panthtimers->wsar); + writel(0, &panthtimers->wdt_sts); + + /* set match counter */ + writel(TMR_WFAR, &panthtimers->wfar); + writel(TMP_WSAR, &panthtimers->wsar); + writel(0xf, &panthtimers->wdt_match_r); + + /* enable WDT reset */ + writel(TMR_WFAR, &panthtimers->wfar); + writel(TMP_WSAR, &panthtimers->wsar); + writel(0x3, &panthtimers->wdt_match_en); + + /*enable functional WDT clock */ + writel(APBC_APBCLK | APBC_FNCLK, &mpmu->wdtpcr); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM 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 ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + return (ulong)CONFIG_SYS_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/spear/Makefile b/arch/arm/cpu/arm926ejs/spear/Makefile new file mode 100644 index 0000000..d06f03d --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/Makefile @@ -0,0 +1,57 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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$(SOC).o + +COBJS-y := cpu.o \ + reset.o \ + timer.o + +ifdef CONFIG_SPL_BUILD +COBJS-y += spl.o spl_boot.o +COBJS-$(CONFIG_SPEAR600) += spear600.o +COBJS-$(CONFIG_DDR_MT47H64M16) += spr600_mt47h64m16_3_333_cl5_psync.o +COBJS-$(CONFIG_DDR_MT47H32M16) += spr600_mt47h32m16_333_cl5_psync.o +COBJS-$(CONFIG_DDR_MT47H32M16) += spr600_mt47h32m16_37e_166_cl4_sync.o +COBJS-$(CONFIG_DDR_MT47H128M8) += spr600_mt47h128m8_3_266_cl5_async.o +endif + +SRCS := $(START:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/spear/cpu.c b/arch/arm/cpu/arm926ejs/spear/cpu.c new file mode 100644 index 0000000..e299de3 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/cpu.c @@ -0,0 +1,87 @@ +/* + * (C) Copyright 2010 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. + * + * 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 <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/spr_misc.h> + +int arch_cpu_init(void) +{ + struct misc_regs *const misc_p = + (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 periph1_clken, periph_clk_cfg; + + periph1_clken = readl(&misc_p->periph1_clken); + +#if defined(CONFIG_SPEAR3XX) + periph1_clken |= MISC_GPT2ENB; +#elif defined(CONFIG_SPEAR600) + periph1_clken |= MISC_GPT3ENB; +#endif + +#if defined(CONFIG_PL011_SERIAL) + periph1_clken |= MISC_UART0ENB; + + periph_clk_cfg = readl(&misc_p->periph_clk_cfg); + periph_clk_cfg &= ~CONFIG_SPEAR_UARTCLKMSK; + periph_clk_cfg |= CONFIG_SPEAR_UART48M; + writel(periph_clk_cfg, &misc_p->periph_clk_cfg); +#endif +#if defined(CONFIG_DESIGNWARE_ETH) + periph1_clken |= MISC_ETHENB; +#endif +#if defined(CONFIG_DW_UDC) + periph1_clken |= MISC_USBDENB; +#endif +#if defined(CONFIG_DW_I2C) + periph1_clken |= MISC_I2CENB; +#endif +#if defined(CONFIG_ST_SMI) + periph1_clken |= MISC_SMIENB; +#endif +#if defined(CONFIG_NAND_FSMC) + periph1_clken |= MISC_FSMCENB; +#endif + + writel(periph1_clken, &misc_p->periph1_clken); + return 0; +} + +#ifdef CONFIG_DISPLAY_CPUINFO +int print_cpuinfo(void) +{ +#ifdef CONFIG_SPEAR300 + printf("CPU: SPEAr300\n"); +#elif defined(CONFIG_SPEAR310) + printf("CPU: SPEAr310\n"); +#elif defined(CONFIG_SPEAR320) + printf("CPU: SPEAr320\n"); +#elif defined(CONFIG_SPEAR600) + printf("CPU: SPEAr600\n"); +#else +#error CPU not supported in spear platform +#endif + return 0; +} +#endif diff --git a/arch/arm/cpu/arm926ejs/spear/reset.c b/arch/arm/cpu/arm926ejs/spear/reset.c new file mode 100644 index 0000000..73ad86d --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/reset.c @@ -0,0 +1,54 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. + * + * 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 <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/spr_syscntl.h> + +void reset_cpu(ulong ignored) +{ + struct syscntl_regs *syscntl_regs_p = + (struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE; + + printf("System is going to reboot ...\n"); + + /* + * This 1 second delay will allow the above message + * to be printed before reset + */ + udelay((1000 * 1000)); + + /* Going into slow mode before resetting SOC */ + writel(0x02, &syscntl_regs_p->scctrl); + + /* + * Writing any value to the system status register will + * reset the SoC + */ + writel(0x00, &syscntl_regs_p->scsysstat); + + /* system will restart */ + while (1) + ; +} diff --git a/arch/arm/cpu/arm926ejs/spear/spear600.c b/arch/arm/cpu/arm926ejs/spear/spear600.c new file mode 100644 index 0000000..9f0c1d1 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/spear600.c @@ -0,0 +1,233 @@ +/* + * (C) Copyright 2000-2009 + * Viresh Kumar, ST Microelectronics, viresh.kumar@st.com + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * 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 <asm/hardware.h> +#include <asm/io.h> +#include <asm/arch/spr_misc.h> +#include <asm/arch/spr_defs.h> + +static void sel_1v8(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 ddr1v8, ddr2v5; + + ddr2v5 = readl(&misc_p->ddr_2v5_compensation); + ddr2v5 &= 0x8080ffc0; + ddr2v5 |= 0x78000003; + writel(ddr2v5, &misc_p->ddr_2v5_compensation); + + ddr1v8 = readl(&misc_p->ddr_1v8_compensation); + ddr1v8 &= 0x8080ffc0; + ddr1v8 |= 0x78000010; + writel(ddr1v8, &misc_p->ddr_1v8_compensation); + + while (!(readl(&misc_p->ddr_1v8_compensation) & DDR_COMP_ACCURATE)) + ; +} + +static void sel_2v5(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 ddr1v8, ddr2v5; + + ddr1v8 = readl(&misc_p->ddr_1v8_compensation); + ddr1v8 &= 0x8080ffc0; + ddr1v8 |= 0x78000003; + writel(ddr1v8, &misc_p->ddr_1v8_compensation); + + ddr2v5 = readl(&misc_p->ddr_2v5_compensation); + ddr2v5 &= 0x8080ffc0; + ddr2v5 |= 0x78000010; + writel(ddr2v5, &misc_p->ddr_2v5_compensation); + + while (!(readl(&misc_p->ddr_2v5_compensation) & DDR_COMP_ACCURATE)) + ; +} + +/* + * plat_ddr_init: + */ +void plat_ddr_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 ddrpad; + u32 core3v3, ddr1v8, ddr2v5; + + /* DDR pad register configurations */ + ddrpad = readl(&misc_p->ddr_pad); + ddrpad &= ~DDR_PAD_CNF_MSK; + +#if (CONFIG_DDR_HCLK) + ddrpad |= 0xEAAB; +#elif (CONFIG_DDR_2HCLK) + ddrpad |= 0xEAAD; +#elif (CONFIG_DDR_PLL2) + ddrpad |= 0xEAAD; +#endif + writel(ddrpad, &misc_p->ddr_pad); + + /* Compensation register configurations */ + core3v3 = readl(&misc_p->core_3v3_compensation); + core3v3 &= 0x8080ffe0; + core3v3 |= 0x78000002; + writel(core3v3, &misc_p->core_3v3_compensation); + + ddr1v8 = readl(&misc_p->ddr_1v8_compensation); + ddr1v8 &= 0x8080ffc0; + ddr1v8 |= 0x78000004; + writel(ddr1v8, &misc_p->ddr_1v8_compensation); + + ddr2v5 = readl(&misc_p->ddr_2v5_compensation); + ddr2v5 &= 0x8080ffc0; + ddr2v5 |= 0x78000004; + writel(ddr2v5, &misc_p->ddr_2v5_compensation); + + if ((readl(&misc_p->ddr_pad) & DDR_PAD_SW_CONF) == DDR_PAD_SW_CONF) { + /* Software memory configuration */ + if (readl(&misc_p->ddr_pad) & DDR_PAD_SSTL_SEL) + sel_1v8(); + else + sel_2v5(); + } else { + /* Hardware memory configuration */ + if (readl(&misc_p->ddr_pad) & DDR_PAD_DRAM_TYPE) + sel_1v8(); + else + sel_2v5(); + } +} + +/* + * soc_init: + */ +void soc_init(void) +{ + /* Nothing to be done for SPEAr600 */ +} + +/* + * xxx_boot_selected: + * + * return true if the particular booting option is selected + * return false otherwise + */ +static u32 read_bootstrap(void) +{ + return (readl(CONFIG_SPEAR_BOOTSTRAPCFG) >> CONFIG_SPEAR_BOOTSTRAPSHFT) + & CONFIG_SPEAR_BOOTSTRAPMASK; +} + +int snor_boot_selected(void) +{ + u32 bootstrap = read_bootstrap(); + + if (SNOR_BOOT_SUPPORTED) { + /* Check whether SNOR boot is selected */ + if ((bootstrap & CONFIG_SPEAR_ONLYSNORBOOT) == + CONFIG_SPEAR_ONLYSNORBOOT) + return true; + + if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) == + CONFIG_SPEAR_NORNAND8BOOT) + return true; + + if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) == + CONFIG_SPEAR_NORNAND16BOOT) + return true; + } + + return false; +} + +int nand_boot_selected(void) +{ + u32 bootstrap = read_bootstrap(); + + if (NAND_BOOT_SUPPORTED) { + /* Check whether NAND boot is selected */ + if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) == + CONFIG_SPEAR_NORNAND8BOOT) + return true; + + if ((bootstrap & CONFIG_SPEAR_NORNANDBOOT) == + CONFIG_SPEAR_NORNAND16BOOT) + return true; + } + + return false; +} + +int pnor_boot_selected(void) +{ + /* Parallel NOR boot is not selected in any SPEAr600 revision */ + return false; +} + +int usb_boot_selected(void) +{ + u32 bootstrap = read_bootstrap(); + + if (USB_BOOT_SUPPORTED) { + /* Check whether USB boot is selected */ + if (!(bootstrap & CONFIG_SPEAR_USBBOOT)) + return true; + } + + return false; +} + +int tftp_boot_selected(void) +{ + /* TFTP boot is not selected in any SPEAr600 revision */ + return false; +} + +int uart_boot_selected(void) +{ + /* UART boot is not selected in any SPEAr600 revision */ + return false; +} + +int spi_boot_selected(void) +{ + /* SPI boot is not selected in any SPEAr600 revision */ + return false; +} + +int i2c_boot_selected(void) +{ + /* I2C boot is not selected in any SPEAr600 revision */ + return false; +} + +int mmc_boot_selected(void) +{ + return false; +} + +void plat_late_init(void) +{ + spear_late_init(); +} diff --git a/arch/arm/cpu/arm926ejs/spear/spl.c b/arch/arm/cpu/arm926ejs/spear/spl.c new file mode 100644 index 0000000..0101c5d --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/spl.c @@ -0,0 +1,275 @@ +/* + * Copyright (C) 2011 + * Heiko Schocher, DENX Software Engineering, hs@denx.de. + * + * Copyright (C) 2012 Stefan Roese <sr@denx.de> + * + * 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 <version.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/spr_defs.h> +#include <asm/arch/spr_misc.h> +#include <asm/arch/spr_syscntl.h> + +static void ddr_clock_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 clkenb, ddrpll; + + clkenb = readl(&misc_p->periph1_clken); + clkenb &= ~PERIPH_MPMCMSK; + clkenb |= PERIPH_MPMC_WE; + + /* Intentionally done twice */ + writel(clkenb, &misc_p->periph1_clken); + writel(clkenb, &misc_p->periph1_clken); + + ddrpll = readl(&misc_p->pll_ctr_reg); + ddrpll &= ~MEM_CLK_SEL_MSK; +#if (CONFIG_DDR_HCLK) + ddrpll |= MEM_CLK_HCLK; +#elif (CONFIG_DDR_2HCLK) + ddrpll |= MEM_CLK_2HCLK; +#elif (CONFIG_DDR_PLL2) + ddrpll |= MEM_CLK_PLL2; +#else +#error "please define one of CONFIG_DDR_(HCLK|2HCLK|PLL2)" +#endif + writel(ddrpll, &misc_p->pll_ctr_reg); + + writel(readl(&misc_p->periph1_clken) | PERIPH_MPMC_EN, + &misc_p->periph1_clken); +} + +static void mpmc_init_values(void) +{ + u32 i; + u32 *mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE; + u32 *mpmc_val_p = &mpmc_conf_vals[0]; + + for (i = 0; i < CONFIG_SPEAR_MPMCREGS; i++, mpmc_reg_p++, mpmc_val_p++) + writel(*mpmc_val_p, mpmc_reg_p); + + mpmc_reg_p = (u32 *)CONFIG_SPEAR_MPMCBASE; + + /* + * MPMC controller start + * MPMC waiting for DLLLOCKREG high + */ + writel(0x01000100, &mpmc_reg_p[7]); + + while (!(readl(&mpmc_reg_p[3]) & 0x10000)) + ; +} + +static void mpmc_init(void) +{ + /* Clock related settings for DDR */ + ddr_clock_init(); + + /* + * DDR pad register bits are different for different SoCs + * Compensation values are also handled separately + */ + plat_ddr_init(); + + /* Initialize mpmc register values */ + mpmc_init_values(); +} + +static void pll_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + + /* Initialize PLLs */ + writel(FREQ_332, &misc_p->pll1_frq); + writel(0x1C0A, &misc_p->pll1_cntl); + writel(0x1C0E, &misc_p->pll1_cntl); + writel(0x1C06, &misc_p->pll1_cntl); + writel(0x1C0E, &misc_p->pll1_cntl); + + writel(FREQ_332, &misc_p->pll2_frq); + writel(0x1C0A, &misc_p->pll2_cntl); + writel(0x1C0E, &misc_p->pll2_cntl); + writel(0x1C06, &misc_p->pll2_cntl); + writel(0x1C0E, &misc_p->pll2_cntl); + + /* wait for pll locks */ + while (!(readl(&misc_p->pll1_cntl) & 0x1)) + ; + while (!(readl(&misc_p->pll2_cntl) & 0x1)) + ; +} + +static void mac_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + + writel(readl(&misc_p->periph1_clken) & (~PERIPH_GMAC), + &misc_p->periph1_clken); + + writel(SYNTH23, &misc_p->gmac_synth_clk); + + switch (get_socrev()) { + case SOC_SPEAR600_AA: + case SOC_SPEAR600_AB: + case SOC_SPEAR600_BA: + case SOC_SPEAR600_BB: + case SOC_SPEAR600_BC: + case SOC_SPEAR600_BD: + writel(0x0, &misc_p->gmac_ctr_reg); + break; + + case SOC_SPEAR300: + case SOC_SPEAR310: + case SOC_SPEAR320: + writel(0x4, &misc_p->gmac_ctr_reg); + break; + } + + writel(readl(&misc_p->periph1_clken) | PERIPH_GMAC, + &misc_p->periph1_clken); + + writel(readl(&misc_p->periph1_rst) | PERIPH_GMAC, + &misc_p->periph1_rst); + writel(readl(&misc_p->periph1_rst) & (~PERIPH_GMAC), + &misc_p->periph1_rst); +} + +static void sys_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + struct syscntl_regs *syscntl_p = + (struct syscntl_regs *)CONFIG_SPEAR_SYSCNTLBASE; + + /* Set system state to SLOW */ + writel(SLOW, &syscntl_p->scctrl); + writel(PLL_TIM << 3, &syscntl_p->scpllctrl); + + /* Initialize PLLs */ + pll_init(); + + /* + * Ethernet configuration + * To be done only if the tftp boot is not selected already + * Boot code ensures the correct configuration in tftp booting + */ + if (!tftp_boot_selected()) + mac_init(); + + writel(RTC_DISABLE | PLLTIMEEN, &misc_p->periph_clk_cfg); + writel(0x555, &misc_p->amba_clk_cfg); + + writel(NORMAL, &syscntl_p->scctrl); + + /* Wait for system to switch to normal mode */ + while (((readl(&syscntl_p->scctrl) >> MODE_SHIFT) & MODE_MASK) + != NORMAL) + ; +} + +/* + * get_socrev + * + * Get SoC Revision. + * @return SOC_SPEARXXX + */ +int get_socrev(void) +{ +#if defined(CONFIG_SPEAR600) + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + u32 soc_id = readl(&misc_p->soc_core_id); + u32 pri_socid = (soc_id >> SOC_PRI_SHFT) & 0xFF; + u32 sec_socid = (soc_id >> SOC_SEC_SHFT) & 0xFF; + + if ((pri_socid == 'B') && (sec_socid == 'B')) + return SOC_SPEAR600_BB; + else if ((pri_socid == 'B') && (sec_socid == 'C')) + return SOC_SPEAR600_BC; + else if ((pri_socid == 'B') && (sec_socid == 'D')) + return SOC_SPEAR600_BD; + else if (soc_id == 0) + return SOC_SPEAR600_BA; + else + return SOC_SPEAR_NA; +#elif defined(CONFIG_SPEAR300) + return SOC_SPEAR300; +#elif defined(CONFIG_SPEAR310) + return SOC_SPEAR310; +#elif defined(CONFIG_SPEAR320) + return SOC_SPEAR320; +#endif +} + +void lowlevel_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + const char *u_boot_rev = U_BOOT_VERSION; + + /* Initialize PLLs */ + sys_init(); + + /* Initialize UART */ + serial_init(); + + /* Print U-Boot SPL version string */ + serial_puts("\nU-Boot SPL "); + /* Avoid a second "U-Boot" coming from this string */ + u_boot_rev = &u_boot_rev[7]; + serial_puts(u_boot_rev); + serial_puts(" ("); + serial_puts(U_BOOT_DATE); + serial_puts(" - "); + serial_puts(U_BOOT_TIME); + serial_puts(")\n"); + +#if defined(CONFIG_OS_BOOT) + writel(readl(&misc_p->periph1_clken) | PERIPH_UART1, + &misc_p->periph1_clken); +#endif + + /* Enable IPs (release reset) */ + writel(PERIPH_RST_ALL, &misc_p->periph1_rst); + + /* Initialize MPMC */ + serial_puts("Configure DDR\n"); + mpmc_init(); + + /* SoC specific initialization */ + soc_init(); +} + +void spear_late_init(void) +{ + struct misc_regs *misc_p = (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + + writel(0x80000007, &misc_p->arb_icm_ml1); + writel(0x80000007, &misc_p->arb_icm_ml2); + writel(0x80000007, &misc_p->arb_icm_ml3); + writel(0x80000007, &misc_p->arb_icm_ml4); + writel(0x80000007, &misc_p->arb_icm_ml5); + writel(0x80000007, &misc_p->arb_icm_ml6); + writel(0x80000007, &misc_p->arb_icm_ml7); + writel(0x80000007, &misc_p->arb_icm_ml8); + writel(0x80000007, &misc_p->arb_icm_ml9); +} diff --git a/arch/arm/cpu/arm926ejs/spear/spl_boot.c b/arch/arm/cpu/arm926ejs/spear/spl_boot.c new file mode 100644 index 0000000..3e2953c --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/spl_boot.c @@ -0,0 +1,197 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * Copyright (C) 2012 Stefan Roese <sr@denx.de> + * + * 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 <image.h> +#include <linux/compiler.h> +#include <asm/io.h> +#include <asm/arch/spr_defs.h> +#include <linux/mtd/st_smi.h> + +static const char kernel_name[] = "Linux"; +static const char loader_name[] = "U-Boot"; + +int image_check_header(image_header_t *hdr, const char *name) +{ + if (image_check_magic(hdr) && + (!strncmp(image_get_name(hdr), name, strlen(name))) && + image_check_hcrc(hdr)) { + return 1; + } + return 0; +} + +int image_check_data(image_header_t *hdr) +{ + if (image_check_dcrc(hdr)) + return 1; + + return 0; +} + +/* + * SNOR (Serial NOR flash) related functions + */ +void snor_init(void) +{ + struct smi_regs *const smicntl = + (struct smi_regs * const)CONFIG_SYS_SMI_BASE; + + /* Setting the fast mode values. SMI working at 166/4 = 41.5 MHz */ + writel(HOLD1 | FAST_MODE | BANK_EN | DSEL_TIME | PRESCAL4, + &smicntl->smi_cr1); +} + +static int snor_image_load(u8 *load_addr, void (**image_p)(void), + const char *image_name) +{ + image_header_t *header; + + /* + * Since calculating the crc in the SNOR flash does not + * work, we copy the image to the destination address + * minus the header size. And point the header to this + * new destination. This will not work for address 0 + * of course. + */ + header = (image_header_t *)load_addr; + memcpy((ulong *)(image_get_load(header) - sizeof(image_header_t)), + (const ulong *)load_addr, + image_get_data_size(header) + sizeof(image_header_t)); + header = (image_header_t *)(image_get_load(header) - + sizeof(image_header_t)); + + if (image_check_header(header, image_name)) { + if (image_check_data(header)) { + /* Jump to boot image */ + *image_p = (void *)image_get_load(header); + return 1; + } + } + + return 0; +} + +static void boot_image(void (*image)(void)) +{ + void (*funcp)(void) __noreturn = (void *)image; + + (*funcp)(); +} + +/* + * spl_boot: + * + * All supported booting types of all supported SoCs are listed here. + * Generic readback APIs are provided for each supported booting type + * eg. nand_read_skip_bad + */ +u32 spl_boot(void) +{ + void (*image)(void); + +#ifdef CONFIG_SPEAR_USBTTY + plat_late_init(); + return 1; +#endif + + /* + * All the supported booting devices are listed here. Each of + * the booting type supported by the platform would define the + * macro xxx_BOOT_SUPPORTED to true. + */ + + if (SNOR_BOOT_SUPPORTED && snor_boot_selected()) { + /* SNOR-SMI initialization */ + snor_init(); + + serial_puts("Booting via SNOR\n"); + /* Serial NOR booting */ + if (1 == snor_image_load((u8 *)CONFIG_SYS_UBOOT_BASE, + &image, loader_name)) { + /* Platform related late initialasations */ + plat_late_init(); + + /* Jump to boot image */ + serial_puts("Jumping to U-Boot\n"); + boot_image(image); + return 1; + } + } + + if (NAND_BOOT_SUPPORTED && nand_boot_selected()) { + /* NAND booting */ + /* Not ported from XLoader to SPL yet */ + return 0; + } + + if (PNOR_BOOT_SUPPORTED && pnor_boot_selected()) { + /* PNOR booting */ + /* Not ported from XLoader to SPL yet */ + return 0; + } + + if (MMC_BOOT_SUPPORTED && mmc_boot_selected()) { + /* MMC booting */ + /* Not ported from XLoader to SPL yet */ + return 0; + } + + if (SPI_BOOT_SUPPORTED && spi_boot_selected()) { + /* SPI booting */ + /* Not supported for any platform as of now */ + return 0; + } + + if (I2C_BOOT_SUPPORTED && i2c_boot_selected()) { + /* I2C booting */ + /* Not supported for any platform as of now */ + return 0; + } + + /* + * All booting types without memory are listed as below + * Control has to be returned to BootROM in case of all + * the following booting scenarios + */ + + if (USB_BOOT_SUPPORTED && usb_boot_selected()) { + plat_late_init(); + return 1; + } + + if (TFTP_BOOT_SUPPORTED && tftp_boot_selected()) { + plat_late_init(); + return 1; + } + + if (UART_BOOT_SUPPORTED && uart_boot_selected()) { + plat_late_init(); + return 1; + } + + /* Ideally, the control should not reach here. */ + hang(); +} diff --git a/arch/arm/cpu/arm926ejs/spear/spr600_mt47h128m8_3_266_cl5_async.c b/arch/arm/cpu/arm926ejs/spear/spr600_mt47h128m8_3_266_cl5_async.c new file mode 100644 index 0000000..5edc115 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/spr600_mt47h128m8_3_266_cl5_async.c @@ -0,0 +1,130 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * 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> + +#if (CONFIG_DDR_PLL2) + +const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = { + 0x00000001, + 0x00000000, + 0x01000000, + 0x00000101, + 0x00000001, + 0x01000000, + 0x00010001, + 0x00000100, + 0x00010001, + 0x00000003, + 0x01000201, + 0x06000202, + 0x06060106, + 0x03050502, + 0x03040404, + 0x02020503, + 0x02010106, + 0x03000404, + 0x02030202, + 0x03000204, + 0x0707073f, + 0x07070707, + 0x06060607, + 0x06060606, + 0x05050506, + 0x05050505, + 0x04040405, + 0x04040404, + 0x03030304, + 0x03030303, + 0x02020203, + 0x02020202, + 0x01010102, + 0x01010101, + 0x08080a01, + 0x0000023f, + 0x00040800, + 0x00000000, + 0x00000f02, + 0x00001b1b, + 0x7f000000, + 0x005f0000, + 0x1c040b6a, + 0x00640064, + 0x00640064, + 0x00640064, + 0x00000064, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x000007ff, + 0x00000000, + 0x47ec00c8, + 0x00c8001f, + 0x00000000, + 0x0000cd98, + 0x00000000, + 0x03030100, + 0x03030303, + 0x03030303, + 0x03030303, + 0x00270000, + 0x00250027, + 0x00300000, + 0x008900b7, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; +#endif diff --git a/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_333_cl5_psync.c b/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_333_cl5_psync.c new file mode 100644 index 0000000..616b861 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_333_cl5_psync.c @@ -0,0 +1,135 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * 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> + +#if (CONFIG_DDR_PLL2 || CONFIG_DDR_2HCLK) + +const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = { +#if (CONFIG_DDR_PLL2) + 0x00000001, + 0x00000000, +#elif (CONFIG_DDR_2HCLK) + 0x02020201, + 0x02020202, +#endif + 0x01000000, + 0x00000101, + 0x00000101, + 0x01000000, + 0x00010001, + 0x00000100, + 0x01010001, + 0x00000201, + 0x01000101, + 0x06000002, + 0x06060106, + 0x03050502, + 0x03040404, + 0x02020503, + 0x02010106, + 0x03000405, + 0x03040202, + 0x04000305, + 0x0707073f, + 0x07070707, + 0x06060607, + 0x06060606, + 0x05050506, + 0x05050505, + 0x04040405, + 0x04040404, + 0x03030304, + 0x03030303, + 0x02020203, + 0x02020202, + 0x01010102, + 0x01010101, + 0x0a0a0a01, + 0x0000023f, + 0x00050a00, + 0x11000000, + 0x00001302, + 0x00000A0A, + 0x72000000, + 0x00550000, + 0x2b050e86, + 0x00640064, + 0x00640064, + 0x00640064, + 0x00000064, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00000a24, + 0x43C20000, + 0x5b1c00c8, + 0x00c8002e, + 0x00000000, + 0x0001046b, + 0x00000000, + 0x03030100, + 0x03030303, + 0x03030303, + 0x03030303, + 0x00210000, + 0x00010021, + 0x00200000, + 0x006c0090, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; +#endif diff --git a/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_37e_166_cl4_sync.c b/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_37e_166_cl4_sync.c new file mode 100644 index 0000000..b89f77d --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/spr600_mt47h32m16_37e_166_cl4_sync.c @@ -0,0 +1,130 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * 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> + +#if (CONFIG_DDR_HCLK) + +const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = { + 0x03030301, + 0x03030303, + 0x01000000, + 0x00000101, + 0x00000001, + 0x01000000, + 0x00010001, + 0x00000100, + 0x00010001, + 0x00000003, + 0x01000201, + 0x06000202, + 0x06060106, + 0x03050502, + 0x03040404, + 0x02020503, + 0x02010106, + 0x03000404, + 0x02020202, + 0x03000203, + 0x0707073f, + 0x07070707, + 0x06060607, + 0x06060606, + 0x05050506, + 0x05050505, + 0x04040405, + 0x04040404, + 0x03030304, + 0x03030303, + 0x02020203, + 0x02020202, + 0x01010102, + 0x01010101, + 0x08080a01, + 0x0000023f, + 0x00030600, + 0x00000000, + 0x00000a02, + 0x00001c1c, + 0x7f000000, + 0x005f0000, + 0x12030743, + 0x00640064, + 0x00640064, + 0x00640064, + 0x00000064, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x0000050e, + 0x00000000, + 0x2d8900c8, + 0x00c80014, + 0x00000000, + 0x00008236, + 0x00000000, + 0x03030100, + 0x03030303, + 0x03030303, + 0x03030303, + 0x00400000, + 0x003a0040, + 0x00680000, + 0x00d80120, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; +#endif diff --git a/arch/arm/cpu/arm926ejs/spear/spr600_mt47h64m16_3_333_cl5_psync.c b/arch/arm/cpu/arm926ejs/spear/spr600_mt47h64m16_3_333_cl5_psync.c new file mode 100644 index 0000000..0c39cd1 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/spr600_mt47h64m16_3_333_cl5_psync.c @@ -0,0 +1,144 @@ +/* + * (C) Copyright 2000-2009 + * Vipin Kumar, ST Microelectronics, vipin.kumar@st.com + * + * 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> + +#if (CONFIG_DDR_PLL2 || CONFIG_DDR_2HCLK) + +const u32 mpmc_conf_vals[CONFIG_SPEAR_MPMCREGS] = { +#if (CONFIG_DDR_PLL2) + 0x00000001, + 0x00000000, +#elif (CONFIG_DDR_2HCLK) + 0x02020201, + 0x02020202, +#endif + 0x01000000, + 0x00000101, + 0x00000101, + 0x01000000, + 0x00010001, + 0x00000100, + 0x01010001, + 0x00000201, + 0x01000101, + 0x06000002, + 0x06060106, + 0x03050502, + 0x03040404, + 0x02020503, +#ifdef CONFIG_X600 + 0x02030206, +#else + 0x02010106, +#endif + 0x03000405, + 0x03040202, + 0x04000305, + 0x0707073f, + 0x07070707, + 0x06060607, + 0x06060606, + 0x05050506, + 0x05050505, + 0x04040405, + 0x04040404, + 0x03030304, + 0x03030303, + 0x02020203, + 0x02020202, + 0x01010102, + 0x01010101, + 0x0a0a0a01, + 0x0000023f, + 0x00050a00, + 0x11000000, + 0x00001302, + 0x00000A0A, +#ifdef CONFIG_X600 + 0x7f000000, + 0x005c0000, +#else + 0x72000000, + 0x00550000, +#endif + 0x2b050e86, + 0x00640064, + 0x00640064, + 0x00640064, + 0x00000064, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00200020, + 0x00000a24, + 0x43C20000, + 0x5b1c00c8, + 0x00c8002e, + 0x00000000, + 0x0001046b, + 0x00000000, + 0x03030100, + 0x03030303, + 0x03030303, + 0x03030303, + 0x00210000, + 0x00010021, + 0x00200000, + 0x006c0090, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x003fffff, + 0x003fffff, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000 +}; +#endif diff --git a/arch/arm/cpu/arm926ejs/spear/start.S b/arch/arm/cpu/arm926ejs/spear/start.S new file mode 100644 index 0000000..a103c0f --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/start.S @@ -0,0 +1,122 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * + * 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> + +.globl _start +_start: + b reset + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: +_software_interrupt: +_prefetch_abort: +_data_abort: +_not_used: +_irq: +_fiq: + .word infinite_loop + +infinite_loop: + b infinite_loop + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * Below are the critical initializations already taken place in BootROM. + * So, these are not taken care in Xloader + * 1. Relocation to RAM + * 2. Initializing stacks + * + ************************************************************************* + */ + +/* + * the actual reset code + */ + +reset: +/* + * Xloader has to return back to BootROM in a few cases. + * eg. Ethernet boot, UART boot, USB boot + * Saving registers for returning back + */ + stmdb sp!, {r0-r12,r14} + bl cpu_init_crit +/* + * Clearing bss area is not done in Xloader. + * BSS area lies in the DDR location which is not yet initialized + * bss is assumed to be uninitialized. + */ + bl spl_boot + ldmia sp!, {r0-r12,pc} + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ +cpu_init_crit: + /* + * flush v4 I/D caches + */ + mov r0, #0 + mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */ + mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */ + + /* + * enable instruction cache + */ + mrc p15, 0, r0, c1, c0, 0 + orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */ + mcr p15, 0, r0, c1, c0, 0 + + /* + * Go setup Memory and board specific bits prior to relocation. + */ + stmdb sp!, {lr} + bl lowlevel_init /* go setup pll,mux,memory */ + ldmia sp!, {pc} diff --git a/arch/arm/cpu/arm926ejs/spear/timer.c b/arch/arm/cpu/arm926ejs/spear/timer.c new file mode 100644 index 0000000..de4ba7b --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/timer.c @@ -0,0 +1,139 @@ +/* + * (C) Copyright 2009 + * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. + * + * 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 <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/arch/spr_gpt.h> +#include <asm/arch/spr_misc.h> + +#define GPT_RESOLUTION (CONFIG_SPEAR_HZ_CLOCK / CONFIG_SPEAR_HZ) +#define READ_TIMER() (readl(&gpt_regs_p->count) & GPT_FREE_RUNNING) + +static struct gpt_regs *const gpt_regs_p = + (struct gpt_regs *)CONFIG_SPEAR_TIMERBASE; + +static struct misc_regs *const misc_regs_p = + (struct misc_regs *)CONFIG_SPEAR_MISCBASE; + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +int timer_init(void) +{ + u32 synth; + + /* Prescaler setting */ +#if defined(CONFIG_SPEAR3XX) + writel(MISC_PRSC_CFG, &misc_regs_p->prsc2_clk_cfg); + synth = MISC_GPT4SYNTH; +#elif defined(CONFIG_SPEAR600) + writel(MISC_PRSC_CFG, &misc_regs_p->prsc1_clk_cfg); + synth = MISC_GPT3SYNTH; +#else +# error Incorrect config. Can only be spear{600|300|310|320} +#endif + + writel(readl(&misc_regs_p->periph_clk_cfg) | synth, + &misc_regs_p->periph_clk_cfg); + + /* disable timers */ + writel(GPT_PRESCALER_1 | GPT_MODE_AUTO_RELOAD, &gpt_regs_p->control); + + /* load value for free running */ + writel(GPT_FREE_RUNNING, &gpt_regs_p->compare); + + /* auto reload, start timer */ + writel(readl(&gpt_regs_p->control) | GPT_ENABLE, &gpt_regs_p->control); + + /* Reset the timer */ + lastdec = READ_TIMER(); + timestamp = 0; + + return 0; +} + +/* + * timer without interrupts + */ +ulong get_timer(ulong base) +{ + return (get_timer_masked() / GPT_RESOLUTION) - base; +} + +void __udelay(unsigned long usec) +{ + ulong tmo; + ulong start = get_timer_masked(); + ulong tenudelcnt = CONFIG_SPEAR_HZ_CLOCK / (1000 * 100); + ulong rndoff; + + rndoff = (usec % 10) ? 1 : 0; + + /* tenudelcnt timer tick gives 10 microsecconds delay */ + tmo = ((usec / 10) + rndoff) * tenudelcnt; + + while ((ulong) (get_timer_masked() - start) < tmo) + ; +} + +ulong get_timer_masked(void) +{ + ulong now = READ_TIMER(); + + if (now >= lastdec) { + /* normal mode */ + timestamp += now - lastdec; + } else { + /* we have an overflow ... */ + timestamp += now + GPT_FREE_RUNNING - lastdec; + } + lastdec = now; + + return timestamp; +} + +void udelay_masked(unsigned long usec) +{ + return udelay(usec); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM 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 ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + return CONFIG_SPEAR_HZ; +} diff --git a/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds b/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds new file mode 100644 index 0000000..446d095 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/spear/u-boot-spl.lds @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com> + * on behalf of DENX Software Engineering GmbH + * + * January 2004 - Changed to support H4 device + * Copyright (c) 2004-2008 Texas Instruments + * + * (C) Copyright 2002 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * 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 + */ + +OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = 0x00000000; + + . = ALIGN(4); + .text : + { + arch/arm/cpu/arm926ejs/spear/start.o (.text*) + *(.text*) + } + + . = ALIGN(4); + .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } + + . = ALIGN(4); + .data : { + *(.data*) + } + + . = ALIGN(4); + + .rel.dyn : { + __rel_dyn_start = .; + *(.rel*) + __rel_dyn_end = .; + } + + .bss : { + . = ALIGN(4); + __bss_start = .; + *(.bss*) + . = ALIGN(4); + __bss_end = .; + } + + _end = .; + + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynsym*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.hash*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } +} diff --git a/arch/arm/cpu/arm926ejs/start.S b/arch/arm/cpu/arm926ejs/start.S new file mode 100644 index 0000000..5fc8e04 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/start.S @@ -0,0 +1,415 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * Copyright (c) 2010 Albert Aribaud <albert.u.boot@aribaud.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 <asm-offsets.h> +#include <config.h> +#include <common.h> +#include <version.h> + +/* + ************************************************************************* + * + * Jump vector table as in table 3.1 in [1] + * + ************************************************************************* + */ + + +#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG +.globl _start +_start: +.globl _NOR_BOOT_CFG +_NOR_BOOT_CFG: + .word CONFIG_SYS_DV_NOR_BOOT_CFG + b reset +#else +.globl _start +_start: + b reset +#endif +#ifdef CONFIG_SPL_BUILD +/* No exception handlers in preloader */ + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + ldr pc, _hang + +_hang: + .word do_hang +/* pad to 64 byte boundary */ + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 + .word 0x12345678 +#else + ldr pc, _undefined_instruction + ldr pc, _software_interrupt + ldr pc, _prefetch_abort + ldr pc, _data_abort + ldr pc, _not_used + ldr pc, _irq + ldr pc, _fiq + +_undefined_instruction: + .word undefined_instruction +_software_interrupt: + .word software_interrupt +_prefetch_abort: + .word prefetch_abort +_data_abort: + .word data_abort +_not_used: + .word not_used +_irq: + .word irq +_fiq: + .word fiq + +#endif /* CONFIG_SPL_BUILD */ + .balignl 16,0xdeadbeef + + +/* + ************************************************************************* + * + * Startup Code (reset vector) + * + * do important init only if we don't start from memory! + * setup Memory and board specific bits prior to relocation. + * relocate armboot to ram + * setup stack + * + ************************************************************************* + */ + +.globl _TEXT_BASE +_TEXT_BASE: +#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE) + .word CONFIG_SPL_TEXT_BASE +#else + .word CONFIG_SYS_TEXT_BASE +#endif + +/* + * These are defined in the board-specific linker script. + * Subtracting _start from them lets the linker put their + * relative position in the executable instead of leaving + * them null. + */ +.globl _bss_start_ofs +_bss_start_ofs: + .word __bss_start - _start + +.globl _bss_end_ofs +_bss_end_ofs: + .word __bss_end - _start + +.globl _end_ofs +_end_ofs: + .word _end - _start + +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word 0x0badc0de + +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: + .word 0x0badc0de +#endif + +/* IRQ stack memory (calculated at run-time) + 8 bytes */ +.globl IRQ_STACK_START_IN +IRQ_STACK_START_IN: + .word 0x0badc0de + +/* + * the actual reset code + */ + +reset: + /* + * set the cpu to SVC32 mode + */ + mrs r0,cpsr + bic r0,r0,#0x1f + orr r0,r0,#0xd3 + msr cpsr,r0 + + /* + * we do sys-critical inits only at reboot, + * not when booting from ram! + */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT + bl cpu_init_crit +#endif + + bl _main + +/*------------------------------------------------------------------------------*/ + + .globl c_runtime_cpu_setup +c_runtime_cpu_setup: + + bx lr + +/* + ************************************************************************* + * + * CPU_init_critical registers + * + * setup important registers + * setup memory timing + * + ************************************************************************* + */ +#ifndef CONFIG_SKIP_LOWLEVEL_INIT +cpu_init_crit: + /* + * flush D cache before disabling it + */ + mov r0, #0 +flush_dcache: + mrc p15, 0, r15, c7, c10, 3 + bne flush_dcache + + mcr p15, 0, r0, c8, c7, 0 /* invalidate TLB */ + mcr p15, 0, r0, c7, c5, 0 /* invalidate I Cache */ + + /* + * disable MMU and D cache + * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined + */ + mrc p15, 0, r0, c1, c0, 0 + bic r0, r0, #0x00000300 /* clear bits 9:8 (---- --RS) */ + bic r0, r0, #0x00000087 /* clear bits 7, 2:0 (B--- -CAM) */ +#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH + orr r0, r0, #0x00002000 /* set bit 13 (--V- ----) */ +#else + bic r0, r0, #0x00002000 /* clear bit 13 (--V- ----) */ +#endif + orr r0, r0, #0x00000002 /* set bit 2 (A) Align */ +#ifndef CONFIG_SYS_ICACHE_OFF + orr r0, r0, #0x00001000 /* set bit 12 (I) I-Cache */ +#endif + mcr p15, 0, r0, c1, c0, 0 + + /* + * Go setup Memory and board specific bits prior to relocation. + */ + mov ip, lr /* perserve link reg across call */ + bl lowlevel_init /* go setup pll,mux,memory */ + mov lr, ip /* restore link */ + mov pc, lr /* back to my caller */ +#endif /* CONFIG_SKIP_LOWLEVEL_INIT */ + +#ifndef CONFIG_SPL_BUILD +/* + ************************************************************************* + * + * Interrupt handling + * + ************************************************************************* + */ + +@ +@ IRQ stack frame. +@ +#define S_FRAME_SIZE 72 + +#define S_OLD_R0 68 +#define S_PSR 64 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 + +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 + +#define MODE_SVC 0x13 +#define I_BIT 0x80 + +/* + * use bad_save_user_regs for abort/prefetch/undef/swi ... + * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling + */ + + .macro bad_save_user_regs + @ carve out a frame on current user stack + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Save user registers (now in svc mode) r0-r12 + ldr r2, IRQ_STACK_START_IN + @ get values for "aborted" pc and cpsr (into parm regs) + ldmia r2, {r2 - r3} + add r0, sp, #S_FRAME_SIZE @ grab pointer to old stack + add r5, sp, #S_SP + mov r1, lr + stmia r5, {r0 - r3} @ save sp_SVC, lr_SVC, pc, cpsr + mov r0, sp @ save current stack into r0 (param register) + .endm + + .macro irq_save_user_regs + sub sp, sp, #S_FRAME_SIZE + stmia sp, {r0 - r12} @ Calling r0-r12 + @ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good. + add r8, sp, #S_PC + stmdb r8, {sp, lr}^ @ Calling SP, LR + str lr, [r8, #0] @ Save calling PC + mrs r6, spsr + str r6, [r8, #4] @ Save CPSR + str r0, [r8, #8] @ Save OLD_R0 + mov r0, sp + .endm + + .macro irq_restore_user_regs + ldmia sp, {r0 - lr}^ @ Calling r0 - lr + mov r0, r0 + ldr lr, [sp, #S_PC] @ Get PC + add sp, sp, #S_FRAME_SIZE + subs pc, lr, #4 @ return & move spsr_svc into cpsr + .endm + + .macro get_bad_stack + ldr r13, IRQ_STACK_START_IN @ setup our mode stack + + str lr, [r13] @ save caller lr in position 0 of saved stack + mrs lr, spsr @ get the spsr + str lr, [r13, #4] @ save spsr in position 1 of saved stack + mov r13, #MODE_SVC @ prepare SVC-Mode + @ msr spsr_c, r13 + msr spsr, r13 @ switch modes, make sure moves will execute + mov lr, pc @ capture return pc + movs pc, lr @ jump to next instruction & switch modes. + .endm + + .macro get_irq_stack @ setup IRQ stack + ldr sp, IRQ_STACK_START + .endm + + .macro get_fiq_stack @ setup FIQ stack + ldr sp, FIQ_STACK_START + .endm +#endif /* CONFIG_SPL_BUILD */ + +/* + * exception handlers + */ +#ifdef CONFIG_SPL_BUILD + .align 5 +do_hang: + ldr sp, _TEXT_BASE /* switch to abort stack */ +1: + bl 1b /* hang and never return */ +#else /* !CONFIG_SPL_BUILD */ + .align 5 +undefined_instruction: + get_bad_stack + bad_save_user_regs + bl do_undefined_instruction + + .align 5 +software_interrupt: + get_bad_stack + bad_save_user_regs + bl do_software_interrupt + + .align 5 +prefetch_abort: + get_bad_stack + bad_save_user_regs + bl do_prefetch_abort + + .align 5 +data_abort: + get_bad_stack + bad_save_user_regs + bl do_data_abort + + .align 5 +not_used: + get_bad_stack + bad_save_user_regs + bl do_not_used + +#ifdef CONFIG_USE_IRQ + + .align 5 +irq: + get_irq_stack + irq_save_user_regs + bl do_irq + irq_restore_user_regs + + .align 5 +fiq: + get_fiq_stack + /* someone ought to write a more effiction fiq_save_user_regs */ + irq_save_user_regs + bl do_fiq + irq_restore_user_regs + +#else + + .align 5 +irq: + get_bad_stack + bad_save_user_regs + bl do_irq + + .align 5 +fiq: + get_bad_stack + bad_save_user_regs + bl do_fiq + +#endif +#endif /* CONFIG_SPL_BUILD */ diff --git a/arch/arm/cpu/arm926ejs/versatile/Makefile b/arch/arm/cpu/arm926ejs/versatile/Makefile new file mode 100644 index 0000000..64e6aae --- /dev/null +++ b/arch/arm/cpu/arm926ejs/versatile/Makefile @@ -0,0 +1,47 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# 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$(SOC).o + +COBJS = timer.o +SOBJS = reset.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/arch/arm/cpu/arm926ejs/versatile/reset.S b/arch/arm/cpu/arm926ejs/versatile/reset.S new file mode 100644 index 0000000..8321072 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/versatile/reset.S @@ -0,0 +1,45 @@ +/* + * armboot - Startup Code for ARM926EJS CPU-core + * + * Copyright (c) 2003 Texas Instruments + * + * ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------ + * + * Copyright (c) 2001 Marius Gröger <mag@sysgo.de> + * Copyright (c) 2002 Alex Züpke <azu@sysgo.de> + * Copyright (c) 2002 Gary Jennejohn <garyj@denx.de> + * Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com> + * Copyright (c) 2003 Kshitij <kshitij@ti.com> + * + * 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 + */ + + .align 5 +.globl reset_cpu +reset_cpu: + ldr r1, rstctl1 /* get clkm1 reset ctl */ + mov r3, #0x0 + strh r3, [r1] /* clear it */ + mov r3, #0x8 + strh r3, [r1] /* force dsp+arm reset */ +_loop_forever: + b _loop_forever + +rstctl1: + .word 0xfffece10 diff --git a/arch/arm/cpu/arm926ejs/versatile/timer.c b/arch/arm/cpu/arm926ejs/versatile/timer.c new file mode 100644 index 0000000..b36d6d9 --- /dev/null +++ b/arch/arm/cpu/arm926ejs/versatile/timer.c @@ -0,0 +1,196 @@ +/* + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * + * 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> + +#define TIMER_LOAD_VAL 0xffffffff + +/* macro to read the 32 bit timer */ +#define READ_TIMER (*(volatile ulong *)(CONFIG_SYS_TIMERBASE+4)) + +DECLARE_GLOBAL_DATA_PTR; + +#define timestamp gd->arch.tbl +#define lastdec gd->arch.lastinc + +#define TIMER_ENABLE (1 << 7) +#define TIMER_MODE_MSK (1 << 6) +#define TIMER_MODE_FR (0 << 6) +#define TIMER_MODE_PD (1 << 6) + +#define TIMER_INT_EN (1 << 5) +#define TIMER_PRS_MSK (3 << 2) +#define TIMER_PRS_8S (1 << 3) +#define TIMER_SIZE_MSK (1 << 2) +#define TIMER_ONE_SHT (1 << 0) + +int timer_init (void) +{ + ulong tmr_ctrl_val; + + /* 1st disable the Timer */ + tmr_ctrl_val = *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8); + tmr_ctrl_val &= ~TIMER_ENABLE; + *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = tmr_ctrl_val; + + /* + * The Timer Control Register has one Undefined/Shouldn't Use Bit + * So we should do read/modify/write Operation + */ + + /* + * Timer Mode : Free Running + * Interrupt : Disabled + * Prescale : 8 Stage, Clk/256 + * Tmr Siz : 16 Bit Counter + * Tmr in Wrapping Mode + */ + tmr_ctrl_val = *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8); + tmr_ctrl_val &= ~(TIMER_MODE_MSK | TIMER_INT_EN | TIMER_PRS_MSK | TIMER_SIZE_MSK | TIMER_ONE_SHT ); + tmr_ctrl_val |= (TIMER_ENABLE | TIMER_PRS_8S); + + *(volatile ulong *)(CONFIG_SYS_TIMERBASE + 8) = tmr_ctrl_val; + + /* init the timestamp and lastdec value */ + reset_timer_masked(); + + return 0; +} + +/* + * timer without interrupts + */ +ulong get_timer (ulong base) +{ + return get_timer_masked () - base; +} + +/* delay x useconds AND preserve advance timestamp value */ +void __udelay (unsigned long usec) +{ + ulong tmo, tmp; + + if(usec >= 1000){ /* if "big" number, spread normalization to seconds */ + tmo = usec / 1000; /* start to normalize for usec to ticks per sec */ + tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */ + tmo /= 1000; /* finish normalize. */ + }else{ /* else small number, don't kill it prior to HZ multiply */ + tmo = usec * CONFIG_SYS_HZ; + tmo /= (1000*1000); + } + + tmp = get_timer (0); /* get current timestamp */ + if( (tmo + tmp + 1) < tmp ) /* if setting this fordward will roll time stamp */ + reset_timer_masked (); /* reset "advancing" timestamp to 0, set lastdec value */ + else + tmo += tmp; /* else, set advancing stamp wake up time */ + + while (get_timer_masked () < tmo)/* loop till event */ + /*NOP*/; +} + +void reset_timer_masked (void) +{ + /* reset time */ + lastdec = READ_TIMER; /* capure current decrementer value time */ + timestamp = 0; /* start "advancing" time stamp from 0 */ +} + +ulong get_timer_masked (void) +{ + ulong now = READ_TIMER; /* current tick value */ + + if (lastdec >= now) { /* normal mode (non roll) */ + /* normal mode */ + timestamp += lastdec - now; /* move stamp fordward with absoulte diff ticks */ + } else { /* we have overflow of the count down timer */ + /* nts = ts + ld + (TLV - now) + * ts=old stamp, ld=time that passed before passing through -1 + * (TLV-now) amount of time after passing though -1 + * nts = new "advancing time stamp"...it could also roll and cause problems. + */ + timestamp += lastdec + TIMER_LOAD_VAL - now; + } + lastdec = now; + + return timestamp; +} + +/* waits specified delay value and resets timestamp */ +void udelay_masked (unsigned long usec) +{ + ulong tmo; + ulong endtime; + signed long diff; + + if (usec >= 1000) { /* if "big" number, spread normalization to seconds */ + tmo = usec / 1000; /* start to normalize for usec to ticks per sec */ + tmo *= CONFIG_SYS_HZ; /* find number of "ticks" to wait to achieve target */ + tmo /= 1000; /* finish normalize. */ + } else { /* else small number, don't kill it prior to HZ multiply */ + tmo = usec * CONFIG_SYS_HZ; + tmo /= (1000*1000); + } + + endtime = get_timer_masked () + tmo; + + do { + ulong now = get_timer_masked (); + diff = endtime - now; + } while (diff >= 0); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM 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 ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk (void) +{ + ulong tbclk; + + tbclk = CONFIG_SYS_HZ; + return tbclk; +} |