X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=qemu%2Froms%2Fu-boot%2Fboard%2Ffreescale%2Fmpc7448hpc2%2Fasm_init.S;fp=qemu%2Froms%2Fu-boot%2Fboard%2Ffreescale%2Fmpc7448hpc2%2Fasm_init.S;h=70315c31e456cf370b2262c2132a621b5850b8dd;hb=e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb;hp=0000000000000000000000000000000000000000;hpb=9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00;p=kvmfornfv.git diff --git a/qemu/roms/u-boot/board/freescale/mpc7448hpc2/asm_init.S b/qemu/roms/u-boot/board/freescale/mpc7448hpc2/asm_init.S new file mode 100644 index 000000000..70315c31e --- /dev/null +++ b/qemu/roms/u-boot/board/freescale/mpc7448hpc2/asm_init.S @@ -0,0 +1,905 @@ +/* + * (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 + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * FILENAME: asm_init.s + * + * Originator: Alex Bounine + * + * DESCRIPTION: + * Initialization code for the Tundra Tsi108 bridge chip + * + */ + +#include +#include + +#include +#include +#include + +#include + +/* + * 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,CONFIG_SYS_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 + + /* def CONFIG_DUAL_CPU + * For MPC74xx processor, use MSSCR0[ID] bit to identify CPU number. + */ +#if(1) + 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 (CONFIG_SYS_TSI108_CSR_BASE != CONFIG_SYS_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,(CONFIG_SYS_TSI108_CSR_BASE | 0x01)) /* 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,0x00002481) /* 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,0x0001 /* Set pipeline depth */ + 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 + /* wait until SDRAM initialization is complete */ + beq wait_init_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) + */ + + /* BA=0,Size=512MB, ENable, No Addr.Translation */ + LOAD_U32(r5, 0x00000011) + 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. + * Now there is only one processor in the 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 + /* 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 + 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 + /* right shift tRCD by 2 bits as per DDR2 spec */ + rlwinm r3,r3,30,2,31 + 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 */