sc520: Move RAM sizing code from asm to C

This commit is contained in:
Graeme Russ 2011-02-12 15:11:54 +11:00
parent ed4cba79d6
commit 96cd66426a
10 changed files with 611 additions and 767 deletions

View file

@ -33,10 +33,10 @@ LIB := $(obj)lib$(SOC).o
COBJS-$(CONFIG_SYS_SC520) += sc520.o
COBJS-$(CONFIG_PCI) += sc520_pci.o
COBJS-$(CONFIG_SYS_SC520) += sc520_sdram.o
COBJS-$(CONFIG_SYS_SC520_SSI) += sc520_ssi.o
COBJS-$(CONFIG_SYS_SC520_TIMER) += sc520_timer.o
SOBJS-$(CONFIG_SYS_SC520) += sc520_asm.o
SOBJS-$(CONFIG_SYS_SC520) += sc520_car.o
SRCS := $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)

View file

@ -31,13 +31,6 @@
DECLARE_GLOBAL_DATA_PTR;
/*
* utility functions for boards based on the AMD sc520
*
* void init_sc520(void)
* unsigned long init_sc520_dram(void)
*/
sc520_mmcr_t *sc520_mmcr = (sc520_mmcr_t *)SC520_MMCR_BASE;
int cpu_init_f(void)
@ -65,109 +58,6 @@ int cpu_init_f(void)
return x86_cpu_init_f();
}
unsigned long init_sc520_dram(void)
{
bd_t *bd = gd->bd;
u32 dram_present=0;
u32 dram_ctrl;
#ifdef CONFIG_SYS_SDRAM_DRCTMCTL
/* these memory control registers are set up in the assember part,
* in sc520_asm.S, during 'mem_init'. If we muck with them here,
* after we are running a stack in RAM, we have troubles. Besides,
* these refresh and delay values are better ? simply specified
* outright in the include/configs/{cfg} file since the HW designer
* simply dictates it.
*/
#else
u8 tmp;
u8 val;
int cas_precharge_delay = CONFIG_SYS_SDRAM_PRECHARGE_DELAY;
int refresh_rate = CONFIG_SYS_SDRAM_REFRESH_RATE;
int ras_cas_delay = CONFIG_SYS_SDRAM_RAS_CAS_DELAY;
/* set SDRAM speed here */
refresh_rate /= 78;
if (refresh_rate <= 1) {
val = 0; /* 7.8us */
} else if (refresh_rate == 2) {
val = 1; /* 15.6us */
} else if (refresh_rate == 3 || refresh_rate == 4) {
val = 2; /* 31.2us */
} else {
val = 3; /* 62.4us */
}
tmp = (readb(&sc520_mmcr->drcctl) & 0xcf) | (val<<4);
writeb(tmp, &sc520_mmcr->drcctl);
val = readb(&sc520_mmcr->drctmctl) & 0xf0;
if (cas_precharge_delay==3) {
val |= 0x04; /* 3T */
} else if (cas_precharge_delay==4) {
val |= 0x08; /* 4T */
} else if (cas_precharge_delay>4) {
val |= 0x0c;
}
if (ras_cas_delay > 3) {
val |= 2;
} else {
val |= 1;
}
writeb(val, &c520_mmcr->drctmctl);
#endif
/*
* We read-back the configuration of the dram
* controller that the assembly code wrote
*/
dram_ctrl = readl(&sc520_mmcr->drcbendadr);
bd->bi_dram[0].start = 0;
if (dram_ctrl & 0x80) {
/* bank 0 enabled */
dram_present = bd->bi_dram[1].start = (dram_ctrl & 0x7f) << 22;
bd->bi_dram[0].size = bd->bi_dram[1].start;
} else {
bd->bi_dram[0].size = 0;
bd->bi_dram[1].start = bd->bi_dram[0].start;
}
if (dram_ctrl & 0x8000) {
/* bank 1 enabled */
dram_present = bd->bi_dram[2].start = (dram_ctrl & 0x7f00) << 14;
bd->bi_dram[1].size = bd->bi_dram[2].start - bd->bi_dram[1].start;
} else {
bd->bi_dram[1].size = 0;
bd->bi_dram[2].start = bd->bi_dram[1].start;
}
if (dram_ctrl & 0x800000) {
/* bank 2 enabled */
dram_present = bd->bi_dram[3].start = (dram_ctrl & 0x7f0000) << 6;
bd->bi_dram[2].size = bd->bi_dram[3].start - bd->bi_dram[2].start;
} else {
bd->bi_dram[2].size = 0;
bd->bi_dram[3].start = bd->bi_dram[2].start;
}
if (dram_ctrl & 0x80000000) {
/* bank 3 enabled */
dram_present = (dram_ctrl & 0x7f000000) >> 2;
bd->bi_dram[3].size = dram_present - bd->bi_dram[3].start;
} else {
bd->bi_dram[3].size = 0;
}
gd->ram_size = dram_present;
return dram_present;
}
#ifdef CONFIG_SYS_SC520_RESET
void reset_cpu(ulong addr)
{

View file

@ -1,608 +0,0 @@
/*
* (C) Copyright 2002
* Daniel Engström, Omicron Ceti AB <daniel@omicron.se>.
*
* 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 file is largely based on code obtned from AMD. AMD's original
* copyright is included below
*/
/* TITLE SIZER - Aspen DRAM Sizing Routine.
* =============================================================================
*
* Copyright 1999 Advanced Micro Devices, Inc.
* You may redistribute this program and/or modify this program 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 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.
*
* THE MATERIALS ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTY
* OF ANY KIND INCLUDING WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT OF
* THIRD-PARTY INTELLECTUAL PROPERTY, OR FITNESS FOR ANY PARTICULAR PURPOSE.
* IN NO EVENT SHALL AMD OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER
* (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS
* INTERRUPTION, LOSS OF INFORMATION) ARISING OUT OF THE USE OF OR INABILITY
* TO USE THE MATERIALS, EVEN IF AMD HAS BEEN ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGES. BECAUSE SOME JURSIDICTIONS PROHIBIT THE EXCLUSION OR
* LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE ABOVE
* LIMITATION MAY NOT APPLY TO YOU.
*
* AMD does not assume any responsibility for any errors that may appear in
* the Materials nor any responsibility to support or update the Materials.
* AMD retains the right to make changes to its test specifications at any
* time, without notice.
* ==============================================================================
*/
/*
******************************************************************************
*
* FILE : sizer.asm - SDRAM DIMM Sizing Algorithm
*
*
*
* FUNCTIONS : sizemem() - jumped to, not called. To be executed after
* reset to determine the size of the SDRAM DIMMs. Initializes
* the memory subsystem.
*
*
* AUTHOR : Buddy Fey - Original.
*
*
* DESCRIPTION : Performs sizing on SDRAM DIMMs on ASPEN processor.
* NOTE: This is a small memory model version
*
*
* INPUTS : BP contains return address offset
* CACHE is assumed to be disabled.
* The FS segment limit has already been set to big real mode
* (full 32-bit addressing capability)
*
*
* OUTPUTS : None
*
*
* REG USE : ax,bx,cx,dx,di,si,bp, fs
*
*
* REVISION : See PVCS info below
*
*
* TEST PLAN CROSS REFERENCE:
*
*
* $Workfile: $
* $Revision: 1.2 $
* $Date: 1999/09/22 12:49:33 $
* $Author: chipf $
* $Log: sizer.asm $
* Revision 1.2 1999/09/22 12:49:33 chipf
* Add legal header
*
*******************************************************************************
*/
/*******************************************************************************
* FUNCTIONAL DESCRIPTION:
* This routine is called to autodetect the geometry of the DRAM.
*
* This routine is called to determine the number of column bits for the DRAM
* devices in this external bank. This routine assumes that the external bank
* has been configured for an 11-bit column and for 4 internal banks. This gives
* us the maximum address reach in memory. By writing a test value to the max
* address and locating where it aliases to, we can determine the number of valid
* column bits.
*
* This routine is called to determine the number of internal banks each DRAM
* device has. The external bank (under test) is configured for maximum reach
* with 11-bit columns and 4 internal banks. This routine will write to a max
* address (BA1 and BA0 = 1) and then read from an address with BA1=0 to see if
* that column is a "don't care". If BA1 does not affect write/read of data,
* then this device has only 2 internal banks.
*
* This routine is called to determine the ending address for this external
* bank of SDRAM. We write to a max address with a data value and then disable
* row address bits looking for "don't care" locations. Each "don't care" bit
* represents a dividing of the maximum density (128M) by 2. By dividing the
* maximum of 32 4M chunks in an external bank down by all the "don't care" bits
* determined during sizing, we set the proper density.
*
* WARNINGS.
* bp must be preserved because it is used for return linkage.
*
* EXIT
* nothing returned - but the memory subsystem is enabled
*******************************************************************************
*/
#include <config.h>
#include <asm/ic/sc520.h>
.section .text
.equ CACHELINESZ, 0x00000010 /* size of our cache line (read buffer) */
.equ COL11_ADR, 0x0e001e00 /* 11 col addrs */
.equ COL10_ADR, 0x0e000e00 /* 10 col addrs */
.equ COL09_ADR, 0x0e000600 /* 9 col addrs */
.equ COL08_ADR, 0x0e000200 /* 8 col addrs */
.equ ROW14_ADR, 0x0f000000 /* 14 row addrs */
.equ ROW13_ADR, 0x07000000 /* 13 row addrs */
.equ ROW12_ADR, 0x03000000 /* 12 row addrs */
.equ ROW11_ADR, 0x01000000 /* 11 row addrs/also bank switch */
.equ ROW10_ADR, 0x00000000 /* 10 row addrs/also bank switch */
.equ COL11_DATA, 0x0b0b0b0b /* 11 col addrs */
.equ COL10_DATA, 0x0a0a0a0a /* 10 col data */
.equ COL09_DATA, 0x09090909 /* 9 col data */
.equ COL08_DATA, 0x08080808 /* 8 col data */
.equ ROW14_DATA, 0x3f3f3f3f /* 14 row data (MASK) */
.equ ROW13_DATA, 0x1f1f1f1f /* 13 row data (MASK) */
.equ ROW12_DATA, 0x0f0f0f0f /* 12 row data (MASK) */
.equ ROW11_DATA, 0x07070707 /* 11 row data/also bank switch (MASK) */
.equ ROW10_DATA, 0xaaaaaaaa /* 10 row data/also bank switch (MASK) */
.globl mem_init
mem_init:
/* Preserve Boot Flags */
movl %ebx, %ebp
/* initialize dram controller registers */
xorw %ax, %ax
movl $SC520_DBCTL, %edi
movb %al, (%edi) /* disable write buffer */
movl $SC520_ECCCTL, %edi
movb %al, (%edi) /* disable ECC */
movl $SC520_DRCTMCTL, %edi
movb $0x1e, %al /* Set SDRAM timing for slowest */
movb %al, (%edi)
/* setup loop to do 4 external banks starting with bank 3 */
movl $0xff000000, %eax /* enable last bank and setup */
movl $SC520_DRCBENDADR, %edi /* ending address register */
movl %eax, (%edi)
movl $SC520_DRCCFG, %edi /* setup */
movw $0xbbbb, %ax /* dram config register for */
movw %ax, (%edi)
/* issue a NOP to all DRAMs */
movl $SC520_DRCCTL, %edi /* setup DRAM control register with */
movb $0x01, %al /* Disable refresh,disable write buffer */
movb %al, (%edi)
movl $CACHELINESZ, %esi /* just a dummy address to write for */
movw %ax, (%esi)
/* delay for 100 usec? */
movw $100, %cx
sizdelay:
loop sizdelay
/* issue all banks precharge */
movb $0x02, %al
movb %al, (%edi)
movw %ax, (%esi)
/* issue 2 auto refreshes to all banks */
movb $0x04, %al /* Auto refresh cmd */
movb %al, (%edi)
movw $0x02, %cx
refresh1:
movw %ax, (%esi)
loop refresh1
/* issue LOAD MODE REGISTER command */
movb $0x03, %al /* Load mode register cmd */
movb %al, (%edi)
movw %ax, (%esi)
/* issue 8 more auto refreshes to all banks */
movb $0x04, %al /* Auto refresh cmd */
movb %al, (%edi)
movw $0x0008, %cx
refresh2:
movw %ax, (%esi)
loop refresh2
/* set control register to NORMAL mode */
movb $0x00, %al /* Normal mode value */
movb %al, (%edi)
/*
* size dram starting with external bank 3
* moving to external bank 0
*/
movl $0x3, %ecx /* start with external bank 3 */
nextbank:
/* write col 11 wrap adr */
movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */
movl $COL11_DATA, %eax /* pattern for max supported columns(11) */
movl %eax, (%esi) /* write max col pattern at max col adr */
movl (%esi), %ebx /* optional read */
cmpl %ebx, %eax /* to verify write */
jnz bad_ram /* this ram is bad */
/* write col 10 wrap adr */
movl $COL10_ADR, %esi /* set address to 10 col wrap address */
movl $COL10_DATA, %eax /* pattern for 10 col wrap */
movl %eax, (%esi) /* write 10 col pattern @ 10 col wrap adr */
movl (%esi), %ebx /* optional read */
cmpl %ebx, %eax /* to verify write */
jnz bad_ram /* this ram is bad */
/* write col 9 wrap adr */
movl $COL09_ADR, %esi /* set address to 9 col wrap address */
movl $COL09_DATA, %eax /* pattern for 9 col wrap */
movl %eax, (%esi) /* write 9 col pattern @ 9 col wrap adr */
movl (%esi), %ebx /* optional read */
cmpl %ebx, %eax /* to verify write */
jnz bad_ram /* this ram is bad */
/* write col 8 wrap adr */
movl $COL08_ADR, %esi /* set address to min(8) col wrap address */
movl $COL08_DATA, %eax /* pattern for min (8) col wrap */
movl %eax, (%esi) /* write min col pattern @ min col adr */
movl (%esi), %ebx /* optional read */
cmpl %ebx, %eax /* to verify write */
jnz bad_ram /* this ram is bad */
/* write row 14 wrap adr */
movl $ROW14_ADR, %esi /* set address to max row (14) wrap addr */
movl $ROW14_DATA, %eax /* pattern for max supported rows(14) */
movl %eax, (%esi) /* write max row pattern at max row adr */
movl (%esi), %ebx /* optional read */
cmpl %ebx, %eax /* to verify write */
jnz bad_ram /* this ram is bad */
/* write row 13 wrap adr */
movl $ROW13_ADR, %esi /* set address to 13 row wrap address */
movl $ROW13_DATA, %eax /* pattern for 13 row wrap */
movl %eax, (%esi) /* write 13 row pattern @ 13 row wrap adr */
movl (%esi), %ebx /* optional read */
cmpl %ebx, %eax /* to verify write */
jnz bad_ram /* this ram is bad */
/* write row 12 wrap adr */
movl $ROW12_ADR, %esi /* set address to 12 row wrap address */
movl $ROW12_DATA, %eax /* pattern for 12 row wrap */
movl %eax, (%esi) /* write 12 row pattern @ 12 row wrap adr */
movl (%esi), %ebx /* optional read */
cmpl %ebx, %eax /* to verify write */
jnz bad_ram /* this ram is bad */
/* write row 11 wrap adr */
movl $ROW11_ADR, %edi /* set address to 11 row wrap address */
movl $ROW11_DATA, %eax /* pattern for 11 row wrap */
movl %eax, (%edi) /* write 11 row pattern @ 11 row wrap adr */
movl (%edi), %ebx /* optional read */
cmpl %ebx, %eax /* to verify write */
jnz bad_ram /* this ram is bad */
/*
* write row 10 wrap adr --- this write is really to determine
* number of banks
*/
movl $ROW10_ADR, %edi /* set address to 10 row wrap address */
movl $ROW10_DATA, %eax /* pattern for 10 row wrap (AA) */
movl %eax, (%edi) /* write 10 row pattern @ 10 row wrap adr */
movl (%edi), %ebx /* optional read */
cmpl %ebx, %eax /* to verify write */
jnz bad_ram /* this ram is bad */
/*
* read data @ row 12 wrap adr to determine * banks,
* and read data @ row 14 wrap adr to determine * rows.
* if data @ row 12 wrap adr is not AA, 11 or 12 we have bad RAM.
* if data @ row 12 wrap == AA, we only have 2 banks, NOT 4
* if data @ row 12 wrap == 11 or 12, we have 4 banks,
*/
xorw %di, %di /* value for 2 banks in DI */
movl (%esi), %ebx /* read from 12 row wrap to check banks */
/* (esi is setup from the write to row 12 wrap) */
cmpl %ebx, %eax /* check for AA pattern (eax holds the aa pattern) */
jz only2 /* if pattern == AA, we only have 2 banks */
/* 4 banks */
movw $0x008, %di /* value for 4 banks in DI (BNK_CNT bit) */
cmpl $ROW11_DATA, %ebx /* only other legitimate values are 11 */
jz only2
cmpl $ROW12_DATA, %ebx /* and 12 */
jnz bad_ram /* its bad if not 11 or 12! */
/* fall through */
only2:
/*
* validate row mask
*/
movl $ROW14_ADR, %esi /* set address back to max row wrap addr */
movl (%esi), %eax /* read actual number of rows @ row14 adr */
cmpl $ROW11_DATA, %eax /* row must be greater than 11 pattern */
jb bad_ram
cmpl $ROW14_DATA, %eax /* and row must be less than 14 pattern */
ja bad_ram
cmpb %ah, %al /* verify all 4 bytes of dword same */
jnz bad_ram
movl %eax, %ebx
shrl $16, %ebx
cmpw %bx, %ax
jnz bad_ram
/*
* read col 11 wrap adr for real column data value
*/
movl $COL11_ADR, %esi /* set address to max col (11) wrap addr */
movl (%esi), %eax /* read real col number at max col adr */
/*
* validate column data
*/
cmpl $COL08_DATA, %eax /* col must be greater than 8 pattern */
jb bad_ram
cmpl $COL11_DATA, %eax /* and row must be less than 11 pattern */
ja bad_ram
subl $COL08_DATA, %eax /* normalize column data to zero */
jc bad_ram
cmpb %ah, %al /* verify all 4 bytes of dword equal */
jnz bad_ram
movl %eax, %edx
shrl $16, %edx
cmpw %dx, %ax
jnz bad_ram
/*
* merge bank and col data together
*/
addw %di, %dx /* merge of bank and col info in dl */
/*
* fix ending addr mask based upon col info
*/
movb $0x03, %al
subb %dh, %al /* dh contains the overflow from the bank/col merge */
movb %bl, %dh /* bl contains the row mask (aa, 07, 0f, 1f or 3f) */
xchgw %cx, %ax /* cx = ax = 3 or 2 depending on 2 or 4 bank device */
shrb %cl, %dh
incb %dh /* ending addr is 1 greater than real end */
xchgw %cx, %ax /* cx is bank number again */
bad_reint:
/*
* issue all banks precharge
*/
movl $SC520_DRCCTL, %esi /* setup DRAM control register with */
movb $0x02, %al /* All banks precharge */
movb %al, (%esi)
movl $CACHELINESZ, %esi /* address to init read buffer */
movw %ax, (%esi)
/*
* update ENDING ADDRESS REGISTER
*/
movl $SC520_DRCBENDADR, %edi /* DRAM ending address register */
movl %ecx, %ebx
addl %ebx, %edi
movb %dh, (%edi)
/*
* update CONFIG REGISTER
*/
xorb %dh, %dh
movw $0x000f, %bx
movw %cx, %ax
shlw $2, %ax
xchgw %cx, %ax
shlw %cl, %dx
shlw %cl, %bx
notw %bx
xchgw %cx, %ax
movl $SC520_DRCCFG, %edi
movw (%edi), %ax
andw %bx, %ax
orw %dx, %ax
movw %ax, (%edi)
jcxz cleanup
decw %cx
movl %ecx, %ebx
movl $SC520_DRCBENDADR, %edi /* DRAM ending address register */
movb $0xff, %al
addl %ebx, %edi
movb %al, (%edi)
/*
* set control register to NORMAL mode
*/
movl $SC520_DRCCTL, %esi /* setup DRAM control register with */
movb $0x00, %al /* Normal mode value */
movb %al, (%esi)
movl $CACHELINESZ, %esi /* address to init read buffer */
movw %ax, (%esi)
jmp nextbank
cleanup:
movl $SC520_DRCBENDADR, %edi /* DRAM ending address register */
movw $0x04, %cx
xorw %ax, %ax
cleanuplp:
movb (%edi), %al
orb %al, %al
jz emptybank
addb %ah, %al
jns nottoomuch
movb $0x7f, %al
nottoomuch:
movb %al, %ah
orb $0x80, %al
movb %al, (%edi)
emptybank:
incl %edi
loop cleanuplp
#if defined CONFIG_SYS_SDRAM_DRCTMCTL
/* just have your hardware desinger _GIVE_ you what you need here! */
movl $SC520_DRCTMCTL, %edi
movb $CONFIG_SYS_SDRAM_DRCTMCTL, %al
movb %al, (%edi)
#else
#if defined(CONFIG_SYS_SDRAM_CAS_LATENCY_2T) || defined(CONFIG_SYS_SDRAM_CAS_LATENCY_3T)
/*
* Set the CAS latency now since it is hard to do
* when we run from the RAM
*/
movl $SC520_DRCTMCTL, %edi /* DRAM timing register */
movb (%edi), %al
#ifdef CONFIG_SYS_SDRAM_CAS_LATENCY_2T
andb $0xef, %al
#endif
#ifdef CONFIG_SYS_SDRAM_CAS_LATENCY_3T
orb $0x10, %al
#endif
movb %al, (%edi)
#endif
#endif
movl $SC520_DRCCTL, %edi /* DRAM Control register */
movb $0x03, %al /* Load mode register cmd */
movb %al, (%edi)
movw %ax, (%esi)
movl $SC520_DRCCTL, %edi /* DRAM Control register */
movb $0x18, %al /* Enable refresh and NORMAL mode */
movb %al, (%edi)
jmp dram_done
bad_ram:
xorl %edx, %edx
xorl %edi, %edi
jmp bad_reint
dram_done:
/* Restore Boot Flags */
movl %ebx, %ebp
ret
#if CONFIG_SYS_SDRAM_ECC_ENABLE
.globl init_ecc
init_ecc:
/* A nominal memory test: just a byte at each address line */
movl %eax, %ecx
shrl $0x1, %ecx
movl $0x1, %edi
memtest0:
movb $0xa5, (%edi)
cmpb $0xa5, (%edi)
jne out
shrl $0x1, %ecx
andl %ecx, %ecx
jz set_ecc
shll $0x1, %edi
jmp memtest0
set_ecc:
/* clear all ram with a memset */
movl %eax, %ecx
xorl %esi, %esi
xorl %edi, %edi
xorl %eax, %eax
shrl $0x2, %ecx
cld
rep stosl
/* enable read, write buffers */
movb $0x11, %al
movl $SC520_DBCTL, %edi
movb %al, (%edi)
/* enable NMI mapping for ECC */
movl $SC520_ECCINT, %edi
movb $0x10, %al
movb %al, (%edi)
/* Turn on ECC */
movl $SC520_ECCCTL, %edi
movb $0x05, %al
movb %al,(%edi)
out:
ret
#endif
/*
* Read and decode the sc520 DRCBENDADR MMCR and return the number of
* available ram bytes in %eax
*/
.globl get_mem_size
get_mem_size:
movl $SC520_DRCBENDADR, %edi /* DRAM ending address register */
bank0: movl (%edi), %eax
movl %eax, %ecx
andl $0x00000080, %ecx
jz bank1
andl $0x0000007f, %eax
shll $22, %eax
movl %eax, %edx
bank1: movl (%edi), %eax
movl %eax, %ecx
andl $0x00008000, %ecx
jz bank2
andl $0x00007f00, %eax
shll $14, %eax
movl %eax, %edx
bank2: movl (%edi), %eax
movl %eax, %ecx
andl $0x00800000, %ecx
jz bank3
andl $0x007f0000, %eax
shll $6, %eax
movl %eax, %edx
bank3: movl (%edi), %eax
movl %eax, %ecx
andl $0x80000000, %ecx
jz done
andl $0x7f000000, %eax
shrl $2, %eax
movl %eax, %edx
done:
movl %edx, %eax
ret

View file

@ -0,0 +1,532 @@
/*
* (C) Copyright 2010
* Graeme Russ <graeme.russ@gmail.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/processor-flags.h>
#include <asm/ic/sc520.h>
DECLARE_GLOBAL_DATA_PTR;
struct sc520_sdram_info {
u8 banks;
u8 columns;
u8 rows;
u8 size;
};
static void sc520_sizemem(void);
static void sc520_set_dram_timing(void);
static void sc520_set_dram_refresh_rate(void);
static void sc520_enable_dram_refresh(void);
static void sc520_enable_sdram(void);
#if CONFIG_SYS_SDRAM_ECC_ENABLE
static void sc520_enable_ecc(void)
#endif
int dram_init_f(void)
{
sc520_sizemem();
sc520_set_dram_timing();
sc520_set_dram_refresh_rate();
sc520_enable_dram_refresh();
sc520_enable_sdram();
#if CONFIG_SYS_SDRAM_ECC_ENABLE
sc520_enable_ecc();
#endif
return 0;
}
static inline void sc520_dummy_write(void)
{
writew(0x0000, CACHELINESZ);
}
static inline void sc520_issue_sdram_op_mode_select(u8 command)
{
writeb(command, &sc520_mmcr->drcctl);
sc520_dummy_write();
}
static inline int check_long(u32 test_long)
{
u8 i;
u8 tmp_byte = (u8)(test_long & 0x000000ff);
for (i = 1; i < 4; i++) {
if ((u8)((test_long >> (i * 8)) & 0x000000ff) != tmp_byte)
return -1;
}
return 0;
}
static inline int write_and_test(u32 data, u32 address)
{
writel(data, address);
if (readl(address) == data)
return 0; /* Good */
else
return -1; /* Bad */
}
static void sc520_enable_sdram(void)
{
u32 par_config;
/* Enable Writes, Caching and Code Execution to SDRAM */
par_config = readl(&sc520_mmcr->par[3]);
par_config &= ~(SC520_PAR_EXEC_DIS |
SC520_PAR_CACHE_DIS |
SC520_PAR_WRITE_DIS);
writel(par_config, &sc520_mmcr->par[3]);
par_config = readl(&sc520_mmcr->par[4]);
par_config &= ~(SC520_PAR_EXEC_DIS |
SC520_PAR_CACHE_DIS |
SC520_PAR_WRITE_DIS);
writel(par_config, &sc520_mmcr->par[4]);
}
static void sc520_set_dram_timing(void)
{
u8 drctmctl = 0x00;
#if defined CONFIG_SYS_SDRAM_DRCTMCTL
/* just have your hardware designer _GIVE_ you what you need here! */
drctmctl = CONFIG_SYS_SDRAM_DRCTMCTL;
#else
switch (CONFIG_SYS_SDRAM_RAS_CAS_DELAY) {
case 2:
break;
case 3:
drctmctl |= 0x01;
break;
case 4:
default:
drctmctl |= 0x02;
break;
}
switch (CONFIG_SYS_SDRAM_PRECHARGE_DELAY) {
case 2:
break;
case 3:
drctmctl |= 0x04;
break;
case 4:
default:
drctmctl |= 0x08;
break;
case 6:
drctmctl |= 0x0c;
break;
}
switch (CONFIG_SYS_SDRAM_CAS_LATENCY) {
case 2:
break;
case 3:
default:
drctmctl |= 0x10;
break;
}
#endif
writeb(drctmctl, &sc520_mmcr->drctmctl);
/* Issue load mode register command */
sc520_issue_sdram_op_mode_select(0x03);
}
static void sc520_set_dram_refresh_rate(void)
{
u8 drctl;
drctl = readb(&sc520_mmcr->drcctl);
drctl &= 0xcf;
switch (CONFIG_SYS_SDRAM_REFRESH_RATE) {
case 78:
break;
case 156:
default:
drctl |= 0x10;
break;
case 312:
drctl |= 0x20;
break;
case 624:
drctl |= 0x30;
break;
}
writeb(drctl, &sc520_mmcr->drcctl);
}
static void sc520_enable_dram_refresh(void)
{
u8 drctl;
drctl = readb(&sc520_mmcr->drcctl);
drctl &= 0x30; /* keep refresh rate */
drctl |= 0x08; /* enable refresh, normal mode */
writeb(drctl, &sc520_mmcr->drcctl);
}
static void sc520_get_bank_info(int bank, struct sc520_sdram_info *bank_info)
{
u32 col_data;
u32 row_data;
u32 drcbendadr;
u16 drccfg;
u8 banks = 0x00;
u8 columns = 0x00;
u8 rows = 0x00;
bank_info->banks = 0x00;
bank_info->columns = 0x00;
bank_info->rows = 0x00;
bank_info->size = 0x00;
if ((bank < 0) || (bank > 3)) {
printf("Bad Bank ID\n");
return;
}
/* Save configuration */
drcbendadr = readl(&sc520_mmcr->drcbendadr);
drccfg = readw(&sc520_mmcr->drccfg);
/* Setup SDRAM Bank to largest possible size */
writew(0x000b << (bank * 4), &sc520_mmcr->drccfg);
/* Set ending address for this bank */
writel(0x000000ff << (bank * 8), &sc520_mmcr->drcbendadr);
/* write col 11 wrap adr */
if (write_and_test(COL11_DATA, COL11_ADR) != 0)
goto restore_and_exit;
/* write col 10 wrap adr */
if (write_and_test(COL10_DATA, COL10_ADR) != 0)
goto restore_and_exit;
/* write col 9 wrap adr */
if (write_and_test(COL09_DATA, COL09_ADR) != 0)
goto restore_and_exit;
/* write col 8 wrap adr */
if (write_and_test(COL08_DATA, COL08_ADR) != 0)
goto restore_and_exit;
col_data = readl(COL11_ADR);
/* All four bytes in the read long must be the same */
if (check_long(col_data) < 0)
goto restore_and_exit;
if ((col_data >= COL08_DATA) && (col_data <= COL11_DATA))
columns = (u8)(col_data & 0x000000ff);
else
goto restore_and_exit;
/* write row 14 wrap adr */
if (write_and_test(ROW14_DATA, ROW14_ADR) != 0)
goto restore_and_exit;
/* write row 13 wrap adr */
if (write_and_test(ROW13_DATA, ROW13_ADR) != 0)
goto restore_and_exit;
/* write row 12 wrap adr */
if (write_and_test(ROW12_DATA, ROW12_ADR) != 0)
goto restore_and_exit;
/* write row 11 wrap adr */
if (write_and_test(ROW11_DATA, ROW11_ADR) != 0)
goto restore_and_exit;
if (write_and_test(ROW10_DATA, ROW10_ADR) != 0)
goto restore_and_exit;
/*
* read data @ row 12 wrap adr to determine number of banks,
* and read data @ row 14 wrap adr to determine number of rows.
* if data @ row 12 wrap adr is not AA, 11 or 12 we have bad RAM.
* if data @ row 12 wrap == AA, we only have 2 banks, NOT 4
* if data @ row 12 wrap == 11 or 12, we have 4 banks,
*/
row_data = readl(ROW12_ADR);
/* All four bytes in the read long must be the same */
if (check_long(row_data) != 0)
goto restore_and_exit;
switch (row_data) {
case ROW10_DATA:
banks = 2;
break;
case ROW11_DATA:
case ROW12_DATA:
banks = 4;
break;
default:
goto restore_and_exit;
}
row_data = readl(ROW14_ADR);
/* All four bytes in the read long must be the same */
if (check_long(row_data) != 0)
goto restore_and_exit;
switch (row_data) {
case ROW11_DATA:
case ROW12_DATA:
case ROW13_DATA:
case ROW14_DATA:
rows = (u8)(row_data & 0x000000ff);
break;
default:
goto restore_and_exit;
}
bank_info->banks = banks;
bank_info->columns = columns;
bank_info->rows = rows;
if ((bank_info->banks != 0) &&
(bank_info->columns != 0) &&
(bank_info->rows != 0)) {
bank_info->size = bank_info->rows;
bank_info->size >>= (11 - bank_info->columns);
bank_info->size++;
}
restore_and_exit:
/* Restore configuration */
writel(drcbendadr, &sc520_mmcr->drcbendadr);
writew(drccfg, &sc520_mmcr->drccfg);
}
static void sc520_setup_sizemem(void)
{
u8 i;
/* Disable write buffer */
writeb(0x00, &sc520_mmcr->dbctl);
/* Disable ECC */
writeb(0x00, &sc520_mmcr->eccctl);
/* Set slowest SDRAM timing */
writeb(0x1e, &sc520_mmcr->drctmctl);
/* Issue a NOP to all SDRAM banks */
sc520_issue_sdram_op_mode_select(0x01);
/* Delay for 100 microseconds */
udelay(100);
/* Issue 'All Banks Precharge' command */
sc520_issue_sdram_op_mode_select(0x02);
/* Issue 2 'Auto Refresh Enable' command */
sc520_issue_sdram_op_mode_select(0x04);
sc520_dummy_write();
/* Issue 'Load Mode Register' command */
sc520_issue_sdram_op_mode_select(0x03);
/* Issue 8 more 'Auto Refresh Enable' commands */
sc520_issue_sdram_op_mode_select(0x04);
for (i = 0; i < 7; i++)
sc520_dummy_write();
/* Set control register to 'Normal Mode' */
writeb(0x00, &sc520_mmcr->drcctl);
}
static void sc520_sizemem(void)
{
struct sc520_sdram_info sdram_info[4];
u8 bank_config = 0x00;
u8 end_addr = 0x00;
u16 drccfg = 0x0000;
u32 drcbendadr = 0x00000000;
u8 i;
/* Use PARs to disable caching of maximum allowable 256MB SDRAM */
writel(SC520_SDRAM1_PAR | SC520_PAR_CACHE_DIS, &sc520_mmcr->par[3]);
writel(SC520_SDRAM2_PAR | SC520_PAR_CACHE_DIS, &sc520_mmcr->par[4]);
sc520_setup_sizemem();
gd->ram_size = 0;
/* Size each SDRAM bank */
for (i = 0; i <= 3; i++) {
sc520_get_bank_info(i, &sdram_info[i]);
if (sdram_info[i].banks != 0) {
/* Update Configuration register */
bank_config = sdram_info[i].columns - 8;
if (sdram_info[i].banks == 4)
bank_config |= 0x08;
drccfg |= bank_config << (i * 4);
/* Update End Address register */
end_addr += sdram_info[i].size;
drcbendadr |= (end_addr | 0x80) << (i * 8);
gd->ram_size += sdram_info[i].size << 22;
}
/* Issue 'All Banks Precharge' command */
sc520_issue_sdram_op_mode_select(0x02);
/* Set control register to 'Normal Mode' */
writeb(0x00, &sc520_mmcr->drcctl);
}
writel(drcbendadr, &sc520_mmcr->drcbendadr);
writew(drccfg, &sc520_mmcr->drccfg);
/* Clear PARs preventing caching of SDRAM */
writel(0x00000000, &sc520_mmcr->par[3]);
writel(0x00000000, &sc520_mmcr->par[4]);
}
#if CONFIG_SYS_SDRAM_ECC_ENABLE
static void sc520_enable_ecc(void)
/* A nominal memory test: just a byte at each address line */
movl %eax, %ecx
shrl $0x1, %ecx
movl $0x1, %edi
memtest0:
movb $0xa5, (%edi)
cmpb $0xa5, (%edi)
jne out
shrl $0x1, %ecx
andl %ecx, %ecx
jz set_ecc
shll $0x1, %edi
jmp memtest0
set_ecc:
/* clear all ram with a memset */
movl %eax, %ecx
xorl %esi, %esi
xorl %edi, %edi
xorl %eax, %eax
shrl $0x2, %ecx
cld
rep stosl
/* enable read, write buffers */
movb $0x11, %al
movl $DBCTL, %edi
movb %al, (%edi)
/* enable NMI mapping for ECC */
movl $ECCINT, %edi
movb $0x10, %al
movb %al, (%edi)
/* Turn on ECC */
movl $ECCCTL, %edi
movb $0x05, %al
movb %al,(%edi)
out:
jmp init_ecc_ret
}
#endif
int dram_init(void)
{
ulong dram_ctrl;
ulong dram_present = 0x00000000;
/*
* We read-back the configuration of the dram
* controller that the assembly code wrote
*/
dram_ctrl = readl(&sc520_mmcr->drcbendadr);
gd->bd->bi_dram[0].start = 0;
if (dram_ctrl & 0x80) {
/* bank 0 enabled */
gd->bd->bi_dram[1].start = (dram_ctrl & 0x7f) << 22;
dram_present = gd->bd->bi_dram[1].start;
gd->bd->bi_dram[0].size = gd->bd->bi_dram[1].start;
} else {
gd->bd->bi_dram[0].size = 0;
gd->bd->bi_dram[1].start = gd->bd->bi_dram[0].start;
}
if (dram_ctrl & 0x8000) {
/* bank 1 enabled */
gd->bd->bi_dram[2].start = (dram_ctrl & 0x7f00) << 14;
dram_present = gd->bd->bi_dram[2].start;
gd->bd->bi_dram[1].size = gd->bd->bi_dram[2].start -
gd->bd->bi_dram[1].start;
} else {
gd->bd->bi_dram[1].size = 0;
gd->bd->bi_dram[2].start = gd->bd->bi_dram[1].start;
}
if (dram_ctrl & 0x800000) {
/* bank 2 enabled */
gd->bd->bi_dram[3].start = (dram_ctrl & 0x7f0000) << 6;
dram_present = gd->bd->bi_dram[3].start;
gd->bd->bi_dram[2].size = gd->bd->bi_dram[3].start -
gd->bd->bi_dram[2].start;
} else {
gd->bd->bi_dram[2].size = 0;
gd->bd->bi_dram[3].start = gd->bd->bi_dram[2].start;
}
if (dram_ctrl & 0x80000000) {
/* bank 3 enabled */
dram_present = (dram_ctrl & 0x7f000000) >> 2;
gd->bd->bi_dram[3].size = dram_present -
gd->bd->bi_dram[3].start;
} else {
gd->bd->bi_dram[3].size = 0;
}
gd->ram_size = dram_present;
return 0;
}

View file

@ -82,29 +82,22 @@ car_init_ret:
* starting at CONFIG_SYS_CAR_ADDR to be used as a temporary stack
*/
movl $CONFIG_SYS_INIT_SP_ADDR, %esp
movl $CONFIG_SYS_INIT_GD_ADDR, %ebp
/* Skip memory initialization if not starting from cold-reset */
movl %ebx, %ecx
andl $GD_FLG_COLD_BOOT, %ecx
jz skip_mem_init
/* Set Boot Flags in Global Data */
movl %ebx, (GD_FLAGS * 4)(%ebp)
/* Determine our load offset (and put in Global Data) */
call 1f
1: popl %ecx
subl $1b, %ecx
movl %ecx, (GD_LOAD_OFF * 4)(%ebp)
/* size memory */
call mem_init
call dram_init_f
skip_mem_init:
/* fetch memory size (into %eax) */
call get_mem_size
movl %eax, %esp
#if CONFIG_SYS_SDRAM_ECC_ENABLE
/* Skip ECC initialization if not starting from cold-reset */
movl %ebx, %ecx
andl $GD_FLG_COLD_BOOT, %ecx
jz skip_ecc_init
call init_ecc
skip_init_ecc:
#endif
/* Setup stack in SDRAM */
movl (GD_RAM_SIZE * 4)(%ebp), %esp
/* Test the stack */
pushl $0
@ -118,21 +111,8 @@ skip_init_ecc:
wbinvd
/* Determine our load offset */
call 1f
1: popl %ecx
subl $1b, %ecx
/* Set the upper memory limit parameter */
subl $CONFIG_SYS_STACK_SIZE, %eax
/* Pointer to temporary global data */
movl $CONFIG_SYS_INIT_GD_ADDR, %edx
/* %edx points to the global data structure */
movl %esp, (GD_RAM_SIZE * 4)(%edx)
movl %ebx, (GD_FLAGS * 4)(%edx)
movl %ecx, (GD_LOAD_OFF * 4)(%edx)
/* Set parameter to board_init_f() to boot flags */
movl (GD_FLAGS * 4)(%ebp), %eax
call board_init_f /* Enter, U-boot! */

View file

@ -285,6 +285,36 @@ extern sc520_mmcr_t *sc520_mmcr;
#define SC520_PAR14 (SC520_PAR0 + (0x04 * 14))
#define SC520_PAR15 (SC520_PAR0 + (0x04 * 15))
/*
* PARs for maximum allowable 256MB of SDRAM @ 0x00000000
* Two PARs are required due to maximum PAR size of 128MB
* These are used in the SDRAM sizing code to disable caching
*
* 111 0 0 0 1 11111111111 00000000000000 }- 0xe3ffc000
* 111 0 0 0 1 11111111111 00100000000000 }- 0xe3ffc800
* \ / | | | | \----+----/ \-----+------/
* | | | | | | +---------- Start at 0x00000000
* | | | | | | 0x08000000
* | | | | | +----------------------- 128MB Region Size
* | | | | | ((2047 + 1) * 64kB)
* | | | | +------------------------------ 64kB Page Size
* | | | +-------------------------------- Writes Enabled
* | | +---------------------------------- Caching Enabled
* | +------------------------------------ Execution Enabled
* +--------------------------------------- SDRAM
*/
#define SC520_SDRAM1_PAR 0xe3ffc000
#define SC520_SDRAM2_PAR 0xe3ffc800
#define SC520_PAR_WRITE_DIS 0x04000000
#define SC520_PAR_CACHE_DIS 0x08000000
#define SC520_PAR_EXEC_DIS 0x10000000
/*
* Programmable Address Regions to cover 256MB SDRAM (Maximum supported)
* required for DRAM sizing code
*/
/* MMCR Register bits (not all of them :) ) */
/* SSI Stuff */
@ -315,6 +345,33 @@ extern sc520_mmcr_t *sc520_mmcr;
#define UART2_DIS 0x02 /* UART2 Disable */
#define UART1_DIS 0x01 /* UART1 Disable */
/*
* Defines used for SDRAM Sizing (number of columns and rows)
* Refer to section 10.6.4 - SDRAM Sizing Algorithm in the
* Elan SC520 Microcontroller User's Manual (Order #22004B)
*/
#define CACHELINESZ 0x00000010
#define COL11_ADR 0x0e001e00
#define COL10_ADR 0x0e000e00
#define COL09_ADR 0x0e000600
#define COL08_ADR 0x0e000200
#define COL11_DATA 0x0b0b0b0b
#define COL10_DATA 0x0a0a0a0a
#define COL09_DATA 0x09090909
#define COL08_DATA 0x08080808
#define ROW14_ADR 0x0f000000
#define ROW13_ADR 0x07000000
#define ROW12_ADR 0x03000000
#define ROW11_ADR 0x01000000
#define ROW10_ADR 0x00000000
#define ROW14_DATA 0x3f3f3f3f
#define ROW13_DATA 0x1f1f1f1f
#define ROW12_DATA 0x0f0f0f0f
#define ROW11_DATA 0x07070707
#define ROW10_DATA 0xaaaaaaaa
/* 0x28000000 - 0x3fffffff is used by the flash banks */
/* 0x40000000 - 0xffffffff is not adressable by the SC520 */

View file

@ -176,7 +176,7 @@ gd_t *gd;
/*
* Load U-Boot into RAM, initialize BSS, perform relocation adjustments
*/
void board_init_f(ulong mem_top)
void board_init_f(ulong boot_flags)
{
void *text_start = &__text_start;
void *data_end = &__data_end;
@ -194,8 +194,12 @@ void board_init_f(ulong mem_top)
Elf32_Rel *re_src;
Elf32_Rel *re_end;
gd->flags = boot_flags;
/* Calculate destination RAM Address and relocation offset */
dest_addr = (void *)mem_top - (bss_end - text_start);
dest_addr = (void *)gd->ram_size;
dest_addr -= CONFIG_SYS_STACK_SIZE;
dest_addr -= (bss_end - text_start);
rel_offset = text_start - dest_addr;
/* Perform low-level initialization only when cold booted */

View file

@ -160,12 +160,6 @@ int board_early_init_r(void)
return 0;
}
int dram_init(void)
{
init_sc520_dram();
return 0;
}
void show_boot_progress(int val)
{
uchar led_mask;

View file

@ -57,11 +57,6 @@ board_init16:
movl $CONFIG_SYS_SC520_LLIO_PAR, %eax
movl %eax, (%di)
/* Disable SDRAM write buffer */
movw $(SC520_DBCTL - SC520_MMCR_BASE), %di
xorw %ax, %ax
movb %al, (%di)
/* Disabe MMCR alias */
movw $0xfffc, %dx
movl $0x000000cb, %eax

View file

@ -136,11 +136,11 @@
* SDRAM Configuration
*/
#define CONFIG_SYS_SDRAM_DRCTMCTL 0x18
#define CONFIG_SYS_SDRAM_REFRESH_RATE 156
#define CONFIG_NR_DRAM_BANKS 4
/* CONFIG_SYS_SDRAM_DRCTMCTL Overrides the following*/
#undef CONFIG_SYS_SDRAM_PRECHARGE_DELAY
#undef CONFIG_SYS_SDRAM_REFRESH_RATE
#undef CONFIG_SYS_SDRAM_RAS_CAS_DELAY
#undef CONFIG_SYS_SDRAM_CAS_LATENCY_2T
#undef CONFIG_SYS_SDRAM_CAS_LATENCY_3T