Add mpc7448hpc2 (mpc7448 + tsi108) board associated code support.
authorroy zang <tie-fei.zang@freescale.com>
Thu, 2 Nov 2006 10:52:21 +0000 (18:52 +0800)
committerZang Tiefei <roy@bus.ap.freescale.net>
Thu, 2 Nov 2006 10:52:21 +0000 (18:52 +0800)
The mpc7448hpc2 board support low level assemble language init code.

Signed-off-by: Alexandre Bounine <alexandreb@tundra.com>
Signed-off-by: Roy Zang <tie-fei.zang@freescale.com>
board/mpc7448hpc2/asm_init.S [new file with mode: 0644]

diff --git a/board/mpc7448hpc2/asm_init.S b/board/mpc7448hpc2/asm_init.S
new file mode 100644 (file)
index 0000000..8c15a3d
--- /dev/null
@@ -0,0 +1,955 @@
+/*****************************************************************************
+ * (C) Copyright 2004-05;  Tundra Semiconductor Corp.
+ * 
+ * Added automatic detect of SDC settings
+ * Copyright (c) 2005 Freescale Semiconductor, Inc.
+ * Maintainer tie-fei.zang@freescale.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
+ ****************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * FILENAME: asm_init.s
+ *
+ * Originator: Alex Bounine
+ *
+ * DESCRIPTION:
+ * Initialization code for the Tundra Tsi108 bridge chip
+ *
+ *---------------------------------------------------------------------------*/
+
+#include <config.h>
+#include <version.h>
+
+#include <ppc_asm.tmpl>
+#include <ppc_defs.h>
+#include <asm/processor.h>
+
+#include <tsi108.h>
+
+/*===========================================================================
+ * Build Configuration Options
+ */
+
+/* #define DISABLE_PBM       disables usage of PB Master */
+/* #define SDC_HARDCODED_INIT  config SDRAM controller with hardcoded values */
+/* #define SDC_AUTOPRECH_EN    enable SDRAM auto precharge */
+
+/* ===========================================================================
+ * Hardcoded SDC settings
+ */
+
+#ifdef SDC_HARDCODED_INIT
+
+/* Micron MT9HTF6472AY-40EA1 : Unbuffered, 512MB, 400, CL3, Single Rank */
+
+#define VAL_SD_REFRESH  (0x61A)
+#define VAL_SD_TIMING   (0x0308336b)
+#define VAL_SD_D0_CTRL  (0x07100021) /* auto-precharge disabled */
+#define VAL_SD_D0_BAR   (0x0FE00000) /* 512MB @ 0x00000000 */
+#define VAL_SD_D1_CTRL  (0x07100021) /* auto-precharge disabled */
+#define VAL_SD_D1_BAR   (0x0FE00200) /* 512MB @ 0x20000000 */
+
+#endif /* SDC_HARDCODED_INIT */
+
+/*---------------------------------------------------------------------------
+ CPU Configuration:
+
+ CPU Address and Data Parity enables.
+
+#define CPU_AP
+#define CPU_DP
+
+===========================================================================
+ Macros
+
+ !!! Attention !!! Macros LOAD_PTR, LOAD_U32 and LOAD_MEM defined below are
+ expected to work correctly for the CSR space within 32KB range.
+
+ LOAD_PTR and LOAD_U32 - load specified register with a 32 bit constant.
+ These macros are absolutely identical except their names. This difference
+ is provided intentionally for better readable code.
+ -------------------------------------------------------------------------*/
+
+#define LOAD_PTR(reg,const32) \
+      addis reg,r0,const32@h; ori reg,reg,const32@l
+
+#define LOAD_U32(reg,const32) \
+      addis reg,r0,const32@h; ori reg,reg,const32@l
+
+/* LOADMEM initializes a register with the contents of a specified 32-bit memory
+ location, usually a CSR value.*/
+
+#define LOAD_MEM(reg,addr32) \
+      addis reg,r0,addr32@ha; lwz reg,addr32@l(reg)
+
+#ifndef SDC_HARDCODED_INIT
+sdc_clk_sync:
+       /* MHz: 0,0,183,100,133,167,200,233 */
+       .long   0,0,  6, 10,  8,  6,  5,  4  /* nSec */
+#endif
+
+/*===========================================================================
+ board_asm_init() - early initialization function. Coded to be portable to
+                    dual-CPU configuration.
+ Checks CPU number and performs board HW initialization if called for CPU0.
+
+ Registers used: r3,r4,r5,r6,r19,r29
+===========================================================================
+
+---------------------------------------------------------------------------
+ NOTE: For dual-CPU configuration only CPU0 is allowed to configure Tsi108
+       and the rest of the board. Current implementation demonstrates two
+       possible ways to identify CPU number:
+        - for MPC74xx platform: uses MSSCR0[ID] bit as defined in UM.
+        - for PPC750FX/GX boards: uses WHO_AM_I bit reported by Tsi108.
+---------------------------------------------------------------------------*/
+
+    .globl board_asm_init
+board_asm_init:
+
+    mflr    r19          /* Save LR to be able return later. */
+
+    bl icache_enable     /* Enable icache to reduce reads from flash. */
+
+    /* Initialize pointer to Tsi108 register space
+    -------------------------------------------------------------------------*/
+
+    LOAD_PTR(r29,CFG_TSI108_CSR_RST_BASE)/* r29 - pointer to tsi108 CSR space */
+    ori r4,r29,TSI108_PB_REG_OFFSET
+
+    /*-------------------------------------------------------------------------
+     Check Processor Version Number */
+
+    mfspr   r3, PVR
+    rlwinm  r3,r3,16,16,23  /* get ((Processor Version Number) & 0xFF00) */
+
+    cmpli   0,0,r3,0x8000   /* MPC74xx */
+    bne     cont_brd_init
+
+    /* ------------------------------------------
+     For MPC744x/5x enable extended BATs[4-7]
+     Sri: Set HIGH_BAT_EN and XBSEN, and SPD =1
+          to disable prefetch 
+     */
+
+    mfspr   r5, HID0
+    oris    r5, r5, 0x0080  /* Set HID0[HIGH_BAT_EN] bit #8 */
+    ori     r5, r5, 0x0380    /* Set SPD,XBSEN,SGE bits #22,23,24 */
+    mtspr   HID0, r5
+    isync
+    sync
+
+    /* Adding code to disable external interventions in MPX bus mode */
+    mfspr   r3, 1014
+    oris    r3, r3, 0x0100 /* Set the EIDIS bit in MSSCR0:  bit 7 */
+    mtspr   1014, r3
+    isync
+    sync
+
+    /* Sri: code to enable FP unit */
+    mfmsr   r3
+    ori     r3, r3, 0x2000
+    mtmsr   r3
+    isync
+    sync
+
+#if(1) /* def CONFIG_DUAL_CPU
+    -------------------------------------------------------------------------
+     For MPC74xx processor, use MSSCR0[ID] bit to identify CPU number.
+     */
+
+    mfspr   r3,1014         /* read MSSCR0 */
+    rlwinm. r3,r3,27,31,31  /* get processor ID number */
+    mtspr   SPRN_PIR,r3     /* Save CPU ID */
+    sync
+    bne init_done
+    b do_tsi108_init
+
+cont_brd_init:
+
+    /* An alternative method of checking the processor number (in addition
+       to configuration using MSSCR0[ID] bit on MPC74xx). 
+       Good for IBM PPC750FX/GX.
+     */
+
+    lwz r3,PB_BUS_MS_SELECT(r4) /* read PB_ID register */
+    rlwinm. r3,r3,24,31,31      /* get processor ID number */
+
+    bne init_done
+
+#else
+
+cont_brd_init:
+
+#endif /* CONFIG_DUAL_CPU */
+
+    /* Initialize Tsi108 chip
+    ---------------------------------------------------------------------------
+     */
+
+do_tsi108_init:
+
+    /*--------------------------------------------------------------------------
+     Adjust HLP/Flash parameters. By default after reset the HLP port is set
+     to support slow devices. Better performance can be achived when an optimal
+     parameters are used for specific EPROM device.
+     NOTE: This should be performed ASAP for the emulation platform because
+     it has 5MHz HLP clocking.
+     */
+
+#ifdef CONFIG_TSI108EMU
+    ori r4,r29,TSI108_HLP_REG_OFFSET
+    LOAD_U32(r5,0x434422c0)
+    stw r5,0x08(r4)            /* set HLP B0_CTRL0 */
+    sync
+    LOAD_U32(r5,0xd0012000)
+    stw r5,0x0c(r4)            /* set HLP B0_CTRL1 */
+    sync
+#endif
+
+    /* -------------------------------------------------------------------------
+     * Initialize PB interface.
+     */
+
+    ori r4,r29,TSI108_PB_REG_OFFSET
+
+#if (CFG_TSI108_CSR_BASE != CFG_TSI108_CSR_RST_BASE)
+    /* Relocate (if required) Tsi108 registers. Set new value for PB_REG_BAR:
+     * Note we are in the 32-bit address mode.
+     */
+    LOAD_U32(r5,(CFG_TSI108_CSR_BASE | 0x01)) /* value for PB_REG_BAR: BA + EN*/
+    stw r5,PB_REG_BAR(r4)
+    andis. r29,r5,0xFFFF
+    sync
+
+    ori r4,r29,TSI108_PB_REG_OFFSET
+#endif
+
+    /* Set PB Slave configuration register */
+
+/*    LOAD_U32(r5,0x000024C7)  value for PB_SCR: TEA enabled,AACK delay = 7 */
+    LOAD_U32(r5,0x00002481) /* value for PB_SCR: TEA enabled,AACK delay = 1 */
+    lwz r3, PB_RSR(r4)      /* get PB bus mode */
+    xori r3,r3,0x0001       /* mask PB_BMODE: r3 -> (0 = 60X, 1 = MPX) */
+    rlwimi  r5,r3,14,17,17  /* for MPX: set DTI_MODE bit */
+    stw r5,PB_SCR(r4)
+    sync
+
+    /* Configure PB Arbiter */
+
+    lwz r5,PB_ARB_CTRL(r4)      /* Read PB Arbiter Control Register */
+    li r3, 0x00F0               /* ARB_PIPELINE_DEP mask */
+#ifdef DISABLE_PBM
+    ori r3,r3,0x1000            /* add PBM_EN to clear (enabled by default) */
+#endif
+    andc r5,r5,r3               /* Clear the masked bit fields */
+/*    ori r5,r5,0x0040             Set pipeline depth 4
+    ori r5,r5,0x0080             Set pipeline depth 8
+    ori r5,r5,0x0020            !!!avb Testing: set pipeline depth 2 */
+    ori r5,r5,0x0001
+    stw r5,PB_ARB_CTRL(r4)
+
+#if (0) /* currently using the default settings for PBM after reset */
+    LOAD_U32(r5,0x) /* value for PB_MCR */
+    stw r5,PB_MCR(r4)
+    sync
+
+    LOAD_U32(r5,0x) /* value for PB_MCMD */
+    stw r5,PB_MCMD(r4)
+    sync
+#endif
+
+/* Disable or enable PVT based on processor bus frequency
+   1. Read CG_PWRUP_STATUS register field bits 18,17,16
+   2. See if the value is < or > 133mhz (18:16 = 100)
+   3. If > enable PVT 
+   */
+
+    LOAD_U32(r3,0xC0002234)
+    lwz  r3,0(r3)
+    rlwinm  r3,r3,16,29,31
+
+    cmpi 0,0,r3,0x0004
+    bgt sdc_init
+
+#ifndef CONFIG_TSI108EMU
+   /* FIXME:    Disable PB calibration control for any real Tsi108 board */
+    li  r5,0x0101 /* disable calibration control */
+    stw r5,PB_PVT_CTRL2(r4)
+    sync
+#endif
+
+/*---------------------------------------------------------------------------
+ Initialize SDRAM controller.
+----------------------------------------------------------------------------*/
+
+sdc_init:
+
+#ifndef SDC_HARDCODED_INIT
+    /* get SDC clock prior doing sdram controller autoconfig */
+    ori r4,r29,TSI108_CLK_REG_OFFSET   /* r4 - ptr to CG registers */
+    lwz r3, CG_PWRUP_STATUS(r4)                /* get CG configuration */
+    rlwinm r3,r3,12,29,31                      /* r3 - SD clk */
+    lis r5,sdc_clk_sync@h
+    ori r5,r5,sdc_clk_sync@l
+       /* Sri:  At this point check if r3 = 001. If yes,
+        * the memory frequency should be same as the 
+        * MPX bus frequency
+        */
+    cmpi 0,0,r3,0x0001
+    bne get_nsec
+    lwz r6, CG_PWRUP_STATUS(r4)
+    rlwinm r6,r6,16,29,31
+    mr r3,r6
+
+get_nsec:
+    rlwinm r3,r3,2,0,31
+    lwzx r9,r5,r3      /* get SD clk rate in nSec */
+       /* ATTN: r9 will be used by SPD routine */
+#endif /* !SDC_HARDCODED_INIT */
+
+    ori r4,r29,TSI108_SD_REG_OFFSET /* r4 - ptr to SDRAM registers */
+
+    /* Initialize SDRAM controller. SDRAM Size = 512MB, One DIMM. */
+
+    LOAD_U32(r5,0x00)
+    stw r5,SD_INT_ENABLE(r4)    /* Ensure that interrupts are disabled */
+#ifdef ENABLE_SDRAM_ECC
+    li r5, 0x01
+#endif /* ENABLE_SDRAM_ECC */
+    stw r5,SD_ECC_CTRL(r4)      /* Enable/Disable ECC */
+    sync
+
+#ifdef SDC_HARDCODED_INIT /* config sdram controller with hardcoded values */
+
+    /* First read the CG_PWRUP_STATUS register to get the
+       memory speed from bits 22,21,20 */
+
+    LOAD_U32(r3,0xC0002234)
+    lwz  r3,0(r3)
+    rlwinm  r3,r3,12,29,31
+
+    /* Now first check for 166, then 200, or default */
+
+    cmpi 0,0,r3,0x0005
+    bne check_for_200mhz
+
+    /* set values for 166 Mhz memory speed */
+
+    /* Set refresh rate and timing parameters */
+    LOAD_U32(r5,0x00000515)
+    stw r5,SD_REFRESH(r4)
+    LOAD_U32(r5,0x03073368)
+    stw r5,SD_TIMING(r4)
+    sync
+
+    /* Initialize DIMM0 control and BAR registers */
+    LOAD_U32(r5,VAL_SD_D0_CTRL)   /* auto-precharge disabled */
+#ifdef SDC_AUTOPRECH_EN
+    oris r5,r5,0x0001   /* set auto precharge EN bit */
+#endif
+    stw r5,SD_D0_CTRL(r4)
+    LOAD_U32(r5,VAL_SD_D0_BAR)
+    stw r5,SD_D0_BAR(r4)
+    sync
+
+    /* Initialize DIMM1 control and BAR registers
+     *  (same as dimm 0, next 512MB, disabled)
+     */
+    LOAD_U32(r5,VAL_SD_D1_CTRL)  /* auto-precharge disabled */
+#ifdef SDC_AUTOPRECH_EN
+    oris r5,r5,0x0001   /* set auto precharge EN bit */
+#endif
+    stw r5,SD_D1_CTRL(r4)
+    LOAD_U32(r5,VAL_SD_D1_BAR)
+    stw r5,SD_D1_BAR(r4)
+    sync
+
+    b sdc_init_done
+
+check_for_200mhz:
+
+    cmpi 0,0,r3,0x0006
+    bne set_default_values
+
+    /* set values for 200Mhz memory speed */
+
+    /* Set refresh rate and timing parameters */
+    LOAD_U32(r5,0x0000061a)
+    stw r5,SD_REFRESH(r4)
+    LOAD_U32(r5,0x03083348)
+    stw r5,SD_TIMING(r4)
+    sync
+
+    /* Initialize DIMM0 control and BAR registers */
+    LOAD_U32(r5,VAL_SD_D0_CTRL)   /* auto-precharge disabled */
+#ifdef SDC_AUTOPRECH_EN
+    oris r5,r5,0x0001   /* set auto precharge EN bit */
+#endif
+    stw r5,SD_D0_CTRL(r4)
+    LOAD_U32(r5,VAL_SD_D0_BAR)
+    stw r5,SD_D0_BAR(r4)
+    sync
+
+    /* Initialize DIMM1 control and BAR registers
+     *  (same as dimm 0, next 512MB, disabled)
+     */
+    LOAD_U32(r5,VAL_SD_D1_CTRL)  /* auto-precharge disabled */
+#ifdef SDC_AUTOPRECH_EN
+    oris r5,r5,0x0001   /* set auto precharge EN bit */
+#endif
+    stw r5,SD_D1_CTRL(r4)
+    LOAD_U32(r5,VAL_SD_D1_BAR)
+    stw r5,SD_D1_BAR(r4)
+    sync
+
+    b sdc_init_done
+
+set_default_values:
+
+    /* Set refresh rate and timing parameters */
+    LOAD_U32(r5,VAL_SD_REFRESH)
+    stw r5,SD_REFRESH(r4)
+    LOAD_U32(r5,VAL_SD_TIMING)
+    stw r5,SD_TIMING(r4)
+    sync
+
+    /* Initialize DIMM0 control and BAR registers */
+    LOAD_U32(r5,VAL_SD_D0_CTRL)   /* auto-precharge disabled */
+#ifdef SDC_AUTOPRECH_EN
+    oris r5,r5,0x0001   /* set auto precharge EN bit */
+#endif
+    stw r5,SD_D0_CTRL(r4)
+    LOAD_U32(r5,VAL_SD_D0_BAR)
+    stw r5,SD_D0_BAR(r4)
+    sync
+
+    /* Initialize DIMM1 control and BAR registers
+     *  (same as dimm 0, next 512MB, disabled)
+     */
+    LOAD_U32(r5,VAL_SD_D1_CTRL)  /* auto-precharge disabled */
+#ifdef SDC_AUTOPRECH_EN
+    oris r5,r5,0x0001   /* set auto precharge EN bit */
+#endif
+    stw r5,SD_D1_CTRL(r4)
+    LOAD_U32(r5,VAL_SD_D1_BAR)
+    stw r5,SD_D1_BAR(r4)
+    sync
+
+#else /* !SDC_HARDCODED_INIT */
+        
+    bl tsi108_sdram_spd        /* automatically detect SDC settings */
+     
+#endif /* SDC_HARDCODED_INIT */
+
+sdc_init_done:
+
+#ifdef DISABLE_PBM
+    LOAD_U32(r5,0x00000030)     /* PB_EN + OCN_EN */
+#else
+    LOAD_U32(r5,0x00000230)     /* PB_EN + OCN_EN + PB/OCN=80/20 */
+#endif /* DISABLE_PBM */
+
+#ifdef CONFIG_TSI108EMU
+    oris r5,r5,0x0010   /* set EMULATION_MODE bit */
+#endif
+
+    stw r5,SD_CTRL(r4)
+    eieio
+    sync
+
+    /* Enable SDRAM access */
+
+    oris r5,r5,0x8000   /* start SDC: set SD_CTRL[ENABLE] bit */
+    stw r5,SD_CTRL(r4)
+    sync
+
+wait_init_complete:
+    lwz r5,SD_STATUS(r4)
+    andi.   r5,r5,0x0001
+    beq wait_init_complete  /* wait until SDRAM initialization is complete */
+
+/*---------------------------------------------------------------------------
+ Map SDRAM into the processor bus address space
+---------------------------------------------------------------------------*/
+
+    ori r4,r29,TSI108_PB_REG_OFFSET
+
+    /* Setup BARs associated with direct path PB<->SDRAM */
+
+    /* PB_SDRAM_BAR1:
+       provides a direct path to the main system memory (cacheable SDRAM) */
+
+    LOAD_U32(r5, 0x00000011)  /* BA=0,Size=512MB, ENable, No Addr.Translation */
+    stw r5,PB_SDRAM_BAR1(r4)
+    sync
+
+    /* Make sure that PB_SDRAM_BAR1 decoder is set
+       (to allow following immediate read from SDRAM) */
+    lwz r5,PB_SDRAM_BAR1(r4)
+    sync
+
+    /* PB_SDRAM_BAR2:
+       provides non-cacheable alias (via the direct path) to main system memory.
+       Size = 512MB, ENable, Addr.Translation - ON,
+       BA = 0x0_40000000, TA = 0x0_00000000 */
+
+    LOAD_U32(r5, 0x40010011)
+    stw r5,PB_SDRAM_BAR2(r4)
+    sync
+
+    /* Make sure that PB_SDRAM_BAR2 decoder is set
+      (to allow following immediate read from SDRAM) */
+    lwz r5,PB_SDRAM_BAR2(r4)
+    sync
+
+
+init_done:
+
+    /* All done. Restore LR and return. */
+    mtlr    r19
+    blr
+
+#if (0)
+/*===========================================================================
+ init_cpu1
+
+ This routine enables CPU1 on the dual-processor system.
+===========================================================================*/
+
+    .global enable_cpu1
+enable_cpu1:
+
+    lis r3,Tsi108_Base@ha       /* Get Grendel CSR Base Addr */
+    addi    r3,r3,Tsi108_Base@l
+    lwz r3,0(r3)                /* R3 = CSR Base Addr */
+    ori r4,r3,TSI108_PB_REG_OFFSET
+    lwz r3,PB_ARB_CTRL(r4)      /* Read PB Arbiter Control Register */
+    ori r3,r3,0x0200            /* Set M1_EN bit */
+    stw r3,PB_ARB_CTRL(r4)
+
+    blr
+#endif
+
+/*===========================================================================
+ enable_EI
+
+ Enable CPU core external interrupt
+===========================================================================*/
+
+    .global enable_EI
+enable_EI:
+    mfmsr    r3
+    ori      r3,r3,0x8000   /* set EE bit */
+    mtmsr    r3
+    blr
+
+/*===========================================================================
+ disable_EI
+
+ Disable CPU core external interrupt
+===========================================================================*/
+
+    .global disable_EI
+disable_EI:
+    mfmsr   r3
+    li  r4,-32768   /* aka "li  r4,0x8000" */
+    andc r3,r3,r4   /* clear EE bit */
+    mtmsr   r3
+    blr
+
+#ifdef ENABLE_SDRAM_ECC
+/*===========================================================================
+ enable_ECC
+
+ enables SDRAM ECC
+===========================================================================*/
+
+    .global enable_ECC
+enable_ECC:
+    ori r4,r29,TSI108_SD_REG_OFFSET
+    lwz r3,SD_ECC_CTRL(r4)      /* Read SDRAM ECC Control Register */
+    ori r3,r3,0x0001            /* Set ECC_EN bit */
+    stw r3,SD_ECC_CTRL(r4)
+    blr
+
+/*===========================================================================
+ clear_ECC_err
+
+ Clears all pending SDRAM ECC errors
+ (normally after SDRAM scrubbing/initialization)
+===========================================================================*/
+
+    .global clear_ECC_err
+clear_ECC_err:
+    ori r4,r29,TSI108_SD_REG_OFFSET
+/*    lwz r3,SD_INT_STATUS(r4)       Read SDRAM ECC Control Register */
+    ori r3,r0,0x0030                /* ECC_UE_INT + ECC_CE_INT bits */
+    stw r3,SD_INT_STATUS(r4)
+    blr
+
+#endif /* ENABLE_SDRAM_ECC */
+
+#ifndef SDC_HARDCODED_INIT
+
+/********************************************************************
+ * SDRAM SPD Support
+ */
+
+#define        SD_I2C_CTRL1    (0x400)
+#define        SD_I2C_CTRL2    (0x404)
+#define SD_I2C_RD_DATA (0x408)
+#define SD_I2C_WR_DATA         (0x40C)
+
+/*
+ * SDRAM SPD Support Macros
+ */
+
+#define SPD_DIMM0      (0x00000100)
+#define SPD_DIMM1      (0x00000200) /* SPD_DIMM1 was 0x00000000 */
+
+#define SPD_RDIMM                      (0x01)
+#define SPD_UDIMM                      (0x02)
+
+#define SPD_CAS_3                      0x8
+#define SPD_CAS_4                      0x10
+#define SPD_CAS_5                      0x20
+
+#define ERR_NO_DIMM_FOUND              (0xdb0)
+#define ERR_TRAS_FAIL                  (0xdb1)
+#define ERR_TRCD_FAIL                  (0xdb2)
+#define ERR_TRP_FAIL                   (0xdb3)
+#define ERR_TWR_FAIL                   (0xdb4)
+#define ERR_UNKNOWN_PART               (0xdb5)
+#define ERR_NRANK_INVALID              (0xdb6)
+#define ERR_DIMM_SIZE                  (0xdb7)
+#define ERR_ADDR_MODE                  (0xdb8)
+#define ERR_RFRSH_RATE                 (0xdb9)
+#define ERR_DIMM_TYPE                  (0xdba)
+#define ERR_CL_VALUE                   (0xdbb)
+#define ERR_TRFC_FAIL                  (0xdbc)
+
+/* READ_SPD requirements:
+ * byte - byte address in SPD device (0 - 255)
+ * r3 = will return data read from I2C Byte location
+ * r4 - unchanged (SDC base addr)
+ * r5 - clobbered in routine (I2C status)
+ * r10 - number of DDR slot where first SPD device is detected
+ */
+
+#define READ_SPD(byte_num)     \
+       addis r3, 0, byte_num@l;\
+       or      r3, r3, r10;\
+       ori r3, r3, 0x0A;\
+       stw r3, SD_I2C_CTRL1(r4);\
+       li r3, I2C_CNTRL2_START;\
+       stw r3, SD_I2C_CTRL2(r4);\
+       eieio;\
+       sync;\
+       li r3, 0x100;\
+1:                             ;\
+       addic. r3, r3, -1;\
+       bne 1b;\
+2:               ;\
+       lwz r5, SD_I2C_CTRL2(r4);\
+       rlwinm. r3,r5,0,23,23;\
+       bne 2b;\
+       rlwinm. r3,r5,0,3,3;\
+       lwz r3, SD_I2C_RD_DATA(r4)
+
+#define SPD_MIN_RFRSH  (0x80)
+#define SPD_MAX_RFRSH  (0x85)
+
+refresh_rates: /* in nSec */
+       .long   15625   /* Normal (0x80) */
+       .long   3900    /* Reduced 0.25x (0x81) */
+       .long   7800    /* Reduced 0.5x (0x82) */
+       .long   31300   /* Extended 2x (0x83) */
+       .long   62500   /* Extended 4x (0x84) */
+       .long   125000  /* Extended 8x (0x85) */
+
+/*===========================================================================
+ * tsi108_sdram_spd
+ *
+ * Inittializes SDRAM Controller using DDR2 DIMM Serial Presence Detect data
+ * Uses registers: r4 - SDC base address (not changed)
+ *                                r9 - SDC clocking period in nSec
+ * Changes registers: r3,r5,r6,r7,r8,r10,r11
+ *==========================================================================*/
+
+tsi108_sdram_spd:
+
+       li r10,SPD_DIMM0
+       xor     r11,r11,r11             /* DIMM Base Address: starts from 0 */
+
+do_first_dimm:
+
+       /**************************************
+        * Program Refresh Rate Register
+        */
+
+       READ_SPD(12)    /* get Refresh Rate */
+       beq check_next_slot
+       li r5, ERR_RFRSH_RATE
+       cmpi 0,0,r3,SPD_MIN_RFRSH
+       ble spd_fail
+       cmpi 0,0,r3,SPD_MAX_RFRSH
+       bgt spd_fail
+       addi r3,r3,-SPD_MIN_RFRSH
+       rlwinm r3,r3,2,0,31
+       lis r5,refresh_rates@h
+       ori r5,r5,refresh_rates@l
+       lwzx r5,r5,r3   /* get refresh rate in nSec */
+       divwu r5,r5,r9  /* calculate # of SDC clocks */
+       stw r5,SD_REFRESH(r4)   /* Set refresh rate */
+       sync
+
+       /**************************************
+        * Program SD Timing Register
+        */
+
+       li r7, 0                /* clear r7 prior parameter collection */
+
+       READ_SPD(20)    /* get DIMM type: Registered or Unbuffered */
+       beq     spd_read_fail
+       li r5, ERR_DIMM_TYPE
+       cmpi 0,0,r3,SPD_UDIMM
+       beq do_cl
+       cmpi 0,0,r3,SPD_RDIMM
+       bne spd_fail
+       oris r7,r7,0x1000       /* set SD_TIMING[DIMM_TYPE] bit */
+
+do_cl:
+       READ_SPD(18)    /* Get CAS Latency */
+       beq     spd_read_fail
+       li r5,ERR_CL_VALUE
+       andi. r6,r3,SPD_CAS_3
+       beq cl_4
+       li r6,3
+       b set_cl
+cl_4:
+       andi. r6,r3,SPD_CAS_4
+       beq cl_5
+       li r6,4
+       b set_cl
+cl_5:
+       andi. r6,r3,SPD_CAS_5
+       beq spd_fail
+       li r6,5
+set_cl:
+       rlwimi r7,r6,24,5,7
+
+       READ_SPD(30)    /* Get tRAS */
+       beq     spd_read_fail
+       divwu r6,r3,r9
+       mullw r8,r6,r9
+       subf. r8,r8,r3
+       beq     set_tras
+       addi r6,r6,1
+set_tras:
+       li r5,ERR_TRAS_FAIL
+       cmpi 0,0,r6,0x0F        /* max supported value */
+       bgt spd_fail
+       rlwimi r7,r6,16,12,15
+
+       READ_SPD(29)    /* Get tRCD */
+       beq     spd_read_fail
+       rlwinm r3,r3,30,2,31/* right shift tRCD by 2 bits as per DDR2 spec */
+       divwu r6,r3,r9
+       mullw r8,r6,r9
+       subf. r8,r8,r3
+       beq     set_trcd
+       addi r6,r6,1
+set_trcd:
+       li r5,ERR_TRCD_FAIL
+       cmpi 0,0,r6,0x07        /* max supported value */
+       bgt spd_fail
+       rlwimi r7,r6,12,17,19
+
+       READ_SPD(27)    /* Get tRP value */
+       beq     spd_read_fail
+       rlwinm r3,r3,30,2,31    /* right shift tRP by 2 bits as per DDR2 spec */
+       divwu r6,r3,r9
+       mullw r8,r6,r9
+       subf. r8,r8,r3
+       beq     set_trp
+       addi r6,r6,1
+set_trp:
+       li r5,ERR_TRP_FAIL
+       cmpi 0,0,r6,0x07        /* max supported value */
+       bgt spd_fail
+       rlwimi r7,r6,8,21,23
+
+       READ_SPD(36)    /* Get tWR value */
+       beq     spd_read_fail
+       rlwinm r3,r3,30,2,31    /* right shift tWR by 2 bits as per DDR2 spec */
+       divwu r6,r3,r9
+       mullw r8,r6,r9
+       subf. r8,r8,r3
+       beq     set_twr
+       addi r6,r6,1
+set_twr:
+       addi r6,r6,-1           /* Tsi108 SDC always gives one extra clock */
+       li r5,ERR_TWR_FAIL
+       cmpi 0,0,r6,0x07        /* max supported value */
+       bgt spd_fail
+       rlwimi r7,r6,5,24,26
+
+       READ_SPD(42)    /* Get tRFC */
+       beq     spd_read_fail
+       li r5, ERR_TRFC_FAIL
+       /* Tsi108 spec: tRFC=(tRFC + 1)/2 */
+       addi r3,r3,1
+       rlwinm. r3,r3,31,1,31 /* divide by 2 */
+       beq spd_fail
+       divwu r6,r3,r9
+       mullw r8,r6,r9
+       subf. r8,r8,r3
+       beq     set_trfc
+       addi r6,r6,1
+set_trfc:
+       cmpi 0,0,r6,0x1F        /* max supported value */
+       bgt spd_fail
+       rlwimi r7,r6,0,27,31
+
+       stw     r7,SD_TIMING(r4)
+       sync
+
+       /*=====================================================================
+        * The following two registers are set on per-DIMM basis.
+        * The SD_REFRESH and SD_TIMING settings are common for both DIMMS
+        *=====================================================================
+        */
+
+do_each_dimm:
+
+       /*****************************************
+        * Program SDRAM DIMM Control Register
+        */
+
+       li r7, 0                /* clear r7 prior parameter collection */
+
+       READ_SPD(13)            /* Get Primary SDRAM Width */
+       beq     spd_read_fail
+       cmpi 0,0,r3,4   /* Check for 4-bit SDRAM */
+       beq do_nbank
+       oris r7,r7,0x0010       /* Set MEM_WIDTH bit */
+
+do_nbank:
+       READ_SPD(17)            /* Get Number of banks on SDRAM device */
+       beq     spd_read_fail
+       /* Grendel only distinguish betw. 4 or 8-bank memory parts */
+       li r5,ERR_UNKNOWN_PART  /* non-supported memory part */
+       cmpi 0,0,r3,4
+       beq do_nrank
+       cmpi 0,0,r3,8
+       bne spd_fail
+       ori r7,r7,0x1000
+
+do_nrank:
+       READ_SPD(5)     /* Get # of Ranks */
+       beq     spd_read_fail
+       li r5,ERR_NRANK_INVALID
+       andi. r6,r3,0x7 /* Use bits [2..0] only */
+       beq do_addr_mode
+       cmpi 0,0,r6,1
+       bgt spd_fail
+       rlwimi r7,r6,8,23,23
+
+do_addr_mode:
+       READ_SPD(4)     /* Get # of Column Addresses */
+       beq     spd_read_fail
+       li r5, ERR_ADDR_MODE
+       andi. r3,r3,0x0f        /* cut off reserved bits */
+       cmpi 0,0,r3,8
+       ble spd_fail
+       cmpi 0,0,r3,15
+       bgt spd_fail
+       addi r6,r3,-8   /* calculate ADDR_MODE parameter */
+       rlwimi r7,r6,4,24,27    /* set ADDR_MODE field */
+
+set_dimm_ctrl:
+#ifdef SDC_AUTOPRECH_EN
+    oris r7,r7,0x0001   /* set auto precharge EN bit */
+#endif
+       ori r7,r7,1     /* set ENABLE bit */
+       cmpi 0,0,r10,SPD_DIMM0
+       bne 1f
+       stw r7,SD_D0_CTRL(r4)
+       sync
+       b set_dimm_bar
+1:
+       stw r7,SD_D1_CTRL(r4)
+       sync
+
+
+       /********************************************
+        * Program SDRAM DIMMx Base Address Register
+        */
+
+set_dimm_bar:
+       READ_SPD(5)             /* get # of Ranks */
+       beq     spd_read_fail
+       andi.r7,r3,0x7
+       addi r7,r7,1
+       READ_SPD(31)    /* Read DIMM rank density */
+       beq     spd_read_fail
+       rlwinm r5,r3,27,29,31
+       rlwinm r6,r3,3,24,28
+       or r5,r6,r5             /* r5 = Normalized Rank Density byte */
+       lis r8, 0x0080          /* 128MB >> 4 */
+       mullw r8,r8,r5          /* r8 = (rank_size >> 4) */
+       mullw r8,r8,r7          /* r8 = (DIMM_size >> 4) */
+       neg r7,r8
+       rlwinm r7,r7,28,4,31
+       or r7,r7,r11            /* set ADDR field */
+       rlwinm r8,r8,12,20,31
+       add r11,r11,r8          /* set Base Addr for next DIMM */
+
+       cmpi 0,0,r10,SPD_DIMM0
+       bne set_dimm1_size
+       stw r7,SD_D0_BAR(r4)
+       sync
+       li r10,SPD_DIMM1
+       READ_SPD(0)
+       bne do_each_dimm
+       b spd_done
+
+set_dimm1_size:
+       stw r7,SD_D1_BAR(r4)
+       sync
+spd_done:
+       blr
+
+check_next_slot:
+       cmpi 0,0,r10,SPD_DIMM1
+       beq spd_read_fail
+       li r10,SPD_DIMM1
+       b do_first_dimm
+spd_read_fail:
+       ori     r3,r0,0xdead
+       b err_hung
+spd_fail:
+       li      r3,0x0bad
+       sync
+err_hung:   /* hang here for debugging */
+    nop
+    nop
+    b err_hung
+
+#endif /* !SDC_HARDCODED_INIT */
+