📄 denali_spd_ddr2.c
字号:
/* * cpu/ppc4xx/denali_spd_ddr2.c * This SPD SDRAM detection code supports AMCC PPC44x CPUs with a Denali-core * DDR2 controller, specifically the 440EPx/GRx. * * (C) Copyright 2007-2008 * Larry Johnson, lrj@acm.org. * * Based primarily on cpu/ppc4xx/4xx_spd_ddr2.c, which is... * * (C) Copyright 2007 * Stefan Roese, DENX Software Engineering, sr@denx.de. * * COPYRIGHT AMCC CORPORATION 2004 * * 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 * *//* define DEBUG for debugging output (obviously ;-)) */#if 0#define DEBUG#endif#include <common.h>#include <command.h>#include <ppc4xx.h>#include <i2c.h>#include <asm/io.h>#include <asm/processor.h>#include <asm/mmu.h>#include <asm/cache.h>#if defined(CONFIG_SPD_EEPROM) && \ (defined(CONFIG_440EPX) || defined(CONFIG_440GRX))/*-----------------------------------------------------------------------------+ * Defines *-----------------------------------------------------------------------------*/#ifndef TRUE#define TRUE 1#endif#ifndef FALSE#define FALSE 0#endif#define MAXDIMMS 2#define MAXRANKS 2#define ONE_BILLION 1000000000#define MULDIV64(m1, m2, d) (u32)(((u64)(m1) * (u64)(m2)) / (u64)(d))#define DLL_DQS_DELAY 0x19#define DLL_DQS_BYPASS 0x0B#define DQS_OUT_SHIFT 0x7F/* * This DDR2 setup code can dynamically setup the TLB entries for the DDR2 memory * region. Right now the cache should still be disabled in U-Boot because of the * EMAC driver, that need it's buffer descriptor to be located in non cached * memory. * * If at some time this restriction doesn't apply anymore, just define * CONFIG_4xx_DCACHE in the board config file and this code should setup * everything correctly. */#if defined(CONFIG_4xx_DCACHE)#define MY_TLB_WORD2_I_ENABLE 0 /* enable caching on SDRAM */#else#define MY_TLB_WORD2_I_ENABLE TLB_WORD2_I_ENABLE /* disable caching on SDRAM */#endif/*-----------------------------------------------------------------------------+ * Prototypes *-----------------------------------------------------------------------------*/extern int denali_wait_for_dlllock(void);extern void denali_core_search_data_eye(void);extern void dcbz_area(u32 start_address, u32 num_bytes);/* * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed */void __spd_ddr_init_hang(void){ hang();}void spd_ddr_init_hang(void) __attribute__ ((weak, alias("__spd_ddr_init_hang")));#if defined(DEBUG)static void print_mcsr(void){ printf("MCSR = 0x%08X\n", mfspr(SPRN_MCSR));}static void denali_sdram_register_dump(void){ unsigned int sdram_data; printf("\n Register Dump:\n"); mfsdram(DDR0_00, sdram_data); printf(" DDR0_00 = 0x%08X", sdram_data); mfsdram(DDR0_01, sdram_data); printf(" DDR0_01 = 0x%08X\n", sdram_data); mfsdram(DDR0_02, sdram_data); printf(" DDR0_02 = 0x%08X", sdram_data); mfsdram(DDR0_03, sdram_data); printf(" DDR0_03 = 0x%08X\n", sdram_data); mfsdram(DDR0_04, sdram_data); printf(" DDR0_04 = 0x%08X", sdram_data); mfsdram(DDR0_05, sdram_data); printf(" DDR0_05 = 0x%08X\n", sdram_data); mfsdram(DDR0_06, sdram_data); printf(" DDR0_06 = 0x%08X", sdram_data); mfsdram(DDR0_07, sdram_data); printf(" DDR0_07 = 0x%08X\n", sdram_data); mfsdram(DDR0_08, sdram_data); printf(" DDR0_08 = 0x%08X", sdram_data); mfsdram(DDR0_09, sdram_data); printf(" DDR0_09 = 0x%08X\n", sdram_data); mfsdram(DDR0_10, sdram_data); printf(" DDR0_10 = 0x%08X", sdram_data); mfsdram(DDR0_11, sdram_data); printf(" DDR0_11 = 0x%08X\n", sdram_data); mfsdram(DDR0_12, sdram_data); printf(" DDR0_12 = 0x%08X", sdram_data); mfsdram(DDR0_14, sdram_data); printf(" DDR0_14 = 0x%08X\n", sdram_data); mfsdram(DDR0_17, sdram_data); printf(" DDR0_17 = 0x%08X", sdram_data); mfsdram(DDR0_18, sdram_data); printf(" DDR0_18 = 0x%08X\n", sdram_data); mfsdram(DDR0_19, sdram_data); printf(" DDR0_19 = 0x%08X", sdram_data); mfsdram(DDR0_20, sdram_data); printf(" DDR0_20 = 0x%08X\n", sdram_data); mfsdram(DDR0_21, sdram_data); printf(" DDR0_21 = 0x%08X", sdram_data); mfsdram(DDR0_22, sdram_data); printf(" DDR0_22 = 0x%08X\n", sdram_data); mfsdram(DDR0_23, sdram_data); printf(" DDR0_23 = 0x%08X", sdram_data); mfsdram(DDR0_24, sdram_data); printf(" DDR0_24 = 0x%08X\n", sdram_data); mfsdram(DDR0_25, sdram_data); printf(" DDR0_25 = 0x%08X", sdram_data); mfsdram(DDR0_26, sdram_data); printf(" DDR0_26 = 0x%08X\n", sdram_data); mfsdram(DDR0_27, sdram_data); printf(" DDR0_27 = 0x%08X", sdram_data); mfsdram(DDR0_28, sdram_data); printf(" DDR0_28 = 0x%08X\n", sdram_data); mfsdram(DDR0_31, sdram_data); printf(" DDR0_31 = 0x%08X", sdram_data); mfsdram(DDR0_32, sdram_data); printf(" DDR0_32 = 0x%08X\n", sdram_data); mfsdram(DDR0_33, sdram_data); printf(" DDR0_33 = 0x%08X", sdram_data); mfsdram(DDR0_34, sdram_data); printf(" DDR0_34 = 0x%08X\n", sdram_data); mfsdram(DDR0_35, sdram_data); printf(" DDR0_35 = 0x%08X", sdram_data); mfsdram(DDR0_36, sdram_data); printf(" DDR0_36 = 0x%08X\n", sdram_data); mfsdram(DDR0_37, sdram_data); printf(" DDR0_37 = 0x%08X", sdram_data); mfsdram(DDR0_38, sdram_data); printf(" DDR0_38 = 0x%08X\n", sdram_data); mfsdram(DDR0_39, sdram_data); printf(" DDR0_39 = 0x%08X", sdram_data); mfsdram(DDR0_40, sdram_data); printf(" DDR0_40 = 0x%08X\n", sdram_data); mfsdram(DDR0_41, sdram_data); printf(" DDR0_41 = 0x%08X", sdram_data); mfsdram(DDR0_42, sdram_data); printf(" DDR0_42 = 0x%08X\n", sdram_data); mfsdram(DDR0_43, sdram_data); printf(" DDR0_43 = 0x%08X", sdram_data); mfsdram(DDR0_44, sdram_data); printf(" DDR0_44 = 0x%08X\n", sdram_data);}#elsestatic inline void denali_sdram_register_dump(void){}inline static void print_mcsr(void){}#endif /* defined(DEBUG) */static int is_ecc_enabled(void){ u32 val; mfsdram(DDR0_22, val); return 0x3 == DDR0_22_CTRL_RAW_DECODE(val);}static unsigned char spd_read(u8 chip, unsigned int addr){ u8 data[2]; if (0 != i2c_probe(chip) || 0 != i2c_read(chip, addr, 1, data, 1)) { debug("spd_read(0x%02X, 0x%02X) failed\n", chip, addr); return 0; } debug("spd_read(0x%02X, 0x%02X) returned 0x%02X\n", chip, addr, data[0]); return data[0];}static unsigned long get_tcyc(unsigned char reg){ /* * Byte 9, et al: Cycle time for CAS Latency=X, is split into two * nibbles: the higher order nibble (bits 4-7) designates the cycle time * to a granularity of 1ns; the value presented by the lower order * nibble (bits 0-3) has a granularity of .1ns and is added to the value * designated by the higher nibble. In addition, four lines of the lower * order nibble are assigned to support +.25, +.33, +.66, and +.75. */ unsigned char subfield_b = reg & 0x0F; switch (subfield_b & 0x0F) { case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: case 0x8: case 0x9: return 1000 * (reg >> 4) + 100 * subfield_b; case 0xA: return 1000 * (reg >> 4) + 250; case 0xB: return 1000 * (reg >> 4) + 333; case 0xC: return 1000 * (reg >> 4) + 667; case 0xD: return 1000 * (reg >> 4) + 750; } return 0;}/*------------------------------------------------------------------ * Find the installed DIMMs, make sure that the are DDR2, and fill * in the dimm_ranks array. Then dimm_ranks[dimm_num] > 0 iff the * DIMM and dimm_num is present. * Note: Because there are only two chip-select lines, it is assumed * that a board with a single socket can support two ranks on that * socket, while a board with two sockets can support only one rank * on each socket. *-----------------------------------------------------------------*/static void get_spd_info(unsigned long dimm_ranks[], unsigned long *ranks, unsigned char const iic0_dimm_addr[], unsigned long num_dimm_banks){ unsigned long dimm_num; unsigned long dimm_found = FALSE; unsigned long const max_ranks_per_dimm = (1 == num_dimm_banks) ? 2 : 1; unsigned char num_of_bytes; unsigned char total_size; *ranks = 0; for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { num_of_bytes = 0; total_size = 0; num_of_bytes = spd_read(iic0_dimm_addr[dimm_num], 0); total_size = spd_read(iic0_dimm_addr[dimm_num], 1); if ((num_of_bytes != 0) && (total_size != 0)) { unsigned char const dimm_type = spd_read(iic0_dimm_addr[dimm_num], 2); unsigned long ranks_on_dimm = (spd_read(iic0_dimm_addr[dimm_num], 5) & 0x07) + 1; if (8 != dimm_type) { switch (dimm_type) { case 1: printf("ERROR: Standard Fast Page Mode " "DRAM DIMM"); break; case 2: printf("ERROR: EDO DIMM"); break; case 3: printf("ERROR: Pipelined Nibble DIMM"); break; case 4: printf("ERROR: SDRAM DIMM"); break; case 5: printf("ERROR: Multiplexed ROM DIMM"); break; case 6: printf("ERROR: SGRAM DIMM"); break; case 7: printf("ERROR: DDR1 DIMM"); break; default: printf("ERROR: Unknown DIMM (type %d)", (unsigned int)dimm_type); break; } printf(" detected in slot %lu.\n", dimm_num); printf("Only DDR2 SDRAM DIMMs are supported." "\n"); printf("Replace the module with a DDR2 DIMM." "\n\n"); spd_ddr_init_hang(); } dimm_found = TRUE; debug("DIMM slot %lu: populated with %lu-rank DDR2 DIMM" "\n", dimm_num, ranks_on_dimm); if (ranks_on_dimm > max_ranks_per_dimm) { printf("WARNING: DRAM DIMM in slot %lu has %lu " "ranks.\n", dimm_num, ranks_on_dimm); if (1 == max_ranks_per_dimm) { printf("Only one rank will be used.\n"); } else { printf ("Only two ranks will be used.\n"); } ranks_on_dimm = max_ranks_per_dimm; } dimm_ranks[dimm_num] = ranks_on_dimm; *ranks += ranks_on_dimm; } else { dimm_ranks[dimm_num] = 0; debug("DIMM slot %lu: Not populated\n", dimm_num); } } if (dimm_found == FALSE) { printf("ERROR: No memory installed.\n"); printf("Install at least one DDR2 DIMM.\n\n"); spd_ddr_init_hang(); } debug("Total number of ranks = %d\n", *ranks);}/*------------------------------------------------------------------ * For the memory DIMMs installed, this routine verifies that * frequency previously calculated is supported. *-----------------------------------------------------------------*/static void check_frequency(unsigned long *dimm_ranks, unsigned char const iic0_dimm_addr[], unsigned long num_dimm_banks, unsigned long sdram_freq){ unsigned long dimm_num; unsigned long cycle_time; unsigned long calc_cycle_time; /* * calc_cycle_time is calculated from DDR frequency set by board/chip * and is expressed in picoseconds to match the way DIMM cycle time is * calculated below. */ calc_cycle_time = MULDIV64(ONE_BILLION, 1000, sdram_freq); for (dimm_num = 0; dimm_num < num_dimm_banks; dimm_num++) { if (dimm_ranks[dimm_num]) { cycle_time = get_tcyc(spd_read(iic0_dimm_addr[dimm_num], 9)); debug("cycle_time=%d ps\n", cycle_time); if (cycle_time > (calc_cycle_time + 10)) { /* * the provided sdram cycle_time is too small * for the available DIMM cycle_time. The * additionnal 10ps is here to accept a small * incertainty. */ printf ("ERROR: DRAM DIMM detected with cycle_time %d ps in " "slot %d \n while calculated cycle time is %d ps.\n", (unsigned int)cycle_time, (unsigned int)dimm_num, (unsigned int)calc_cycle_time); printf ("Replace the DIMM, or change DDR frequency via " "strapping bits.\n\n"); spd_ddr_init_hang(); } } }}/*------------------------------------------------------------------ * This routine gets size information for the installed memory * DIMMs. *-----------------------------------------------------------------*/static void get_dimm_size(unsigned long dimm_ranks[], unsigned char const iic0_dimm_addr[],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -