parent
ed4cba79d6
commit
96cd66426a
@ -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 |
@ -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; |
||||
} |
Loading…
Reference in new issue