📄 spd_sdram.c
字号:
/* * Copyright 2004 Freescale Semiconductor. * (C) Copyright 2003 Motorola Inc. * Xianghua Xiao (X.Xiao@motorola.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/processor.h>#include <i2c.h>#include <spd.h>#include <asm/mmu.h>#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRCONTROLLER)extern void dma_init(void);extern uint dma_check(void);extern int dma_xfer(void *dest, uint count, void *src);#endif#ifdef CONFIG_SPD_EEPROM#ifndef CFG_READ_SPD#define CFG_READ_SPD i2c_read#endif/* * Only one of the following three should be 1; others should be 0 * By default the cache line interleaving is selected if * the CONFIG_DDR_INTERLEAVE flag is defined */#define CFG_PAGE_INTERLEAVING 0#define CFG_BANK_INTERLEAVING 0#define CFG_SUPER_BANK_INTERLEAVING 0/* * Convert picoseconds into clock cycles (rounding up if needed). */intpicos_to_clk(int picos){ int clks; clks = picos / (2000000000 / (get_bus_freq(0) / 1000)); if (picos % (2000000000 / (get_bus_freq(0) / 1000)) != 0) { clks++; } return clks;}/* * Calculate the Density of each Physical Rank. * Returned size is in bytes. * * Study these table from Byte 31 of JEDEC SPD Spec. * * DDR I DDR II * Bit Size Size * --- ----- ------ * 7 high 512MB 512MB * 6 256MB 256MB * 5 128MB 128MB * 4 64MB 16GB * 3 32MB 8GB * 2 16MB 4GB * 1 2GB 2GB * 0 low 1GB 1GB * * Reorder Table to be linear by stripping the bottom * 2 or 5 bits off and shifting them up to the top. */unsigned intcompute_banksize(unsigned int mem_type, unsigned char row_dens){ unsigned int bsize; if (mem_type == SPD_MEMTYPE_DDR) { /* Bottom 2 bits up to the top. */ bsize = ((row_dens >> 2) | ((row_dens & 3) << 6)) << 24; debug("DDR: DDR I rank density = 0x%08x\n", bsize); } else { /* Bottom 5 bits up to the top. */ bsize = ((row_dens >> 5) | ((row_dens & 31) << 3)) << 27; debug("DDR: DDR II rank density = 0x%08x\n", bsize); } return bsize;}/* * Convert a two-nibble BCD value into a cycle time. * While the spec calls for nano-seconds, picos are returned. * * This implements the tables for bytes 9, 23 and 25 for both * DDR I and II. No allowance for distinguishing the invalid * fields absent for DDR I yet present in DDR II is made. * (That is, cycle times of .25, .33, .66 and .75 ns are * allowed for both DDR II and I.) */unsigned intconvert_bcd_tenths_to_cycle_time_ps(unsigned int spd_val){ /* * Table look up the lower nibble, allow DDR I & II. */ unsigned int tenths_ps[16] = { 0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 250, 330, 660, 750, 0, /* undefined */ 0 /* undefined */ }; unsigned int whole_ns = (spd_val & 0xF0) >> 4; unsigned int tenth_ns = spd_val & 0x0F; unsigned int ps = whole_ns * 1000 + tenths_ps[tenth_ns]; return ps;}/* * Determine Refresh Rate. Ignore self refresh bit on DDR I. * Table from SPD Spec, Byte 12, converted to picoseconds and * filled in with "default" normal values. */unsigned int determine_refresh_rate(unsigned int spd_refresh){ unsigned int refresh_time_ns[8] = { 15625000, /* 0 Normal 1.00x */ 3900000, /* 1 Reduced .25x */ 7800000, /* 2 Extended .50x */ 31300000, /* 3 Extended 2.00x */ 62500000, /* 4 Extended 4.00x */ 125000000, /* 5 Extended 8.00x */ 15625000, /* 6 Normal 1.00x filler */ 15625000, /* 7 Normal 1.00x filler */ }; return picos_to_clk(refresh_time_ns[spd_refresh & 0x7]);}long intspd_init(unsigned char i2c_address, unsigned int ddr_num, unsigned int dimm_num, unsigned int start_addr){ volatile immap_t *immap = (immap_t *)CFG_IMMR; volatile ccsr_ddr_t *ddr; volatile ccsr_gur_t *gur = &immap->im_gur; spd_eeprom_t spd; unsigned int n_ranks; unsigned int rank_density; unsigned int odt_rd_cfg, odt_wr_cfg; unsigned int odt_cfg, mode_odt_enable; unsigned int refresh_clk;#ifdef MPC86xx_DDR_SDRAM_CLK_CNTL unsigned char clk_adjust;#endif unsigned int dqs_cfg; unsigned char twr_clk, twtr_clk, twr_auto_clk; unsigned int tCKmin_ps, tCKmax_ps; unsigned int max_data_rate; unsigned int busfreq; unsigned int memsize; unsigned char caslat, caslat_ctrl; unsigned int trfc, trfc_clk, trfc_low, trfc_high; unsigned int trcd_clk; unsigned int trtp_clk; unsigned char cke_min_clk; unsigned char add_lat; unsigned char wr_lat; unsigned char wr_data_delay; unsigned char four_act; unsigned char cpo; unsigned char burst_len; unsigned int mode_caslat; unsigned char d_init; unsigned int tCycle_ps, modfreq; if (ddr_num == 1) ddr = &immap->im_ddr1; else ddr = &immap->im_ddr2; /* * Read SPD information. */ debug("Performing SPD read at I2C address 0x%02lx\n",i2c_address); memset((void *)&spd, 0, sizeof(spd)); CFG_READ_SPD(i2c_address, 0, 1, (uchar *) &spd, sizeof(spd)); /* * Check for supported memory module types. */ if (spd.mem_type != SPD_MEMTYPE_DDR && spd.mem_type != SPD_MEMTYPE_DDR2) { debug("Warning: Unable to locate DDR I or DDR II module for DIMM %d of DDR controller %d.\n" " Fundamental memory type is 0x%0x\n", dimm_num, ddr_num, spd.mem_type); return 0; } debug("\nFound memory of type 0x%02lx ", spd.mem_type); if (spd.mem_type == SPD_MEMTYPE_DDR) debug("DDR I\n"); else debug("DDR II\n"); /* * These test gloss over DDR I and II differences in interpretation * of bytes 3 and 4, but irrelevantly. Multiple asymmetric banks * are not supported on DDR I; and not encoded on DDR II. * * Also note that the 8548 controller can support: * 12 <= nrow <= 16 * and * 8 <= ncol <= 11 (still, for DDR) * 6 <= ncol <= 9 (for FCRAM) */ if (spd.nrow_addr < 12 || spd.nrow_addr > 14) { printf("DDR: Unsupported number of Row Addr lines: %d.\n", spd.nrow_addr); return 0; } if (spd.ncol_addr < 8 || spd.ncol_addr > 11) { printf("DDR: Unsupported number of Column Addr lines: %d.\n", spd.ncol_addr); return 0; } /* * Determine the number of physical banks controlled by * different Chip Select signals. This is not quite the * same as the number of DIMM modules on the board. Feh. */ if (spd.mem_type == SPD_MEMTYPE_DDR) { n_ranks = spd.nrows; } else { n_ranks = (spd.nrows & 0x7) + 1; } debug("DDR: number of ranks = %d\n", n_ranks); if (n_ranks > 2) { printf("DDR: Only 2 chip selects are supported: %d\n", n_ranks); return 0; } /* * Adjust DDR II IO voltage biasing. It just makes it work. */ if (spd.mem_type == SPD_MEMTYPE_DDR2) { gur->ddrioovcr = (0 | 0x80000000 /* Enable */ | 0x10000000 /* VSEL to 1.8V */ ); } /* * Determine the size of each Rank in bytes. */ rank_density = compute_banksize(spd.mem_type, spd.row_dens); debug("Start address for this controller is 0x%08lx\n", start_addr); /* * ODT configuration recommendation from DDR Controller Chapter. */ odt_rd_cfg = 0; /* Never assert ODT */ odt_wr_cfg = 0; /* Never assert ODT */ if (spd.mem_type == SPD_MEMTYPE_DDR2) { odt_wr_cfg = 1; /* Assert ODT on writes to CS0 */ }#ifdef CONFIG_DDR_INTERLEAVE if (dimm_num != 1) { printf("For interleaving memory on HPCN, need to use DIMM 1 for DDR Controller %d !\n", ddr_num); return 0; } else { /* * Since interleaved memory only uses CS0, the * memory sticks have to be identical in size and quantity * of ranks. That essentially gives double the size on * one rank, i.e on CS0 for both controllers put together. * Confirm this??? */ rank_density *= 2; /* * Eg: Bounds: 0x0000_0000 to 0x0f000_0000 first 256 Meg */ start_addr = 0; ddr->cs0_bnds = (start_addr >> 8) | (((start_addr + rank_density - 1) >> 24)); /* * Default interleaving mode to cache-line interleaving. */ ddr->cs0_config = ( 1 << 31#if (CFG_PAGE_INTERLEAVING == 1) | (PAGE_INTERLEAVING)#elif (CFG_BANK_INTERLEAVING == 1) | (BANK_INTERLEAVING)#elif (CFG_SUPER_BANK_INTERLEAVING == 1) | (SUPER_BANK_INTERLEAVING)#else | (CACHE_LINE_INTERLEAVING)#endif | (odt_rd_cfg << 20) | (odt_wr_cfg << 16) | (spd.nrow_addr - 12) << 8 | (spd.ncol_addr - 8) ); debug("DDR: cs0_bnds = 0x%08x\n", ddr->cs0_bnds); debug("DDR: cs0_config = 0x%08x\n", ddr->cs0_config); /* * Adjustment for dual rank memory to get correct memory * size (return value of this function). */ if (n_ranks == 2) { n_ranks = 1; rank_density /= 2; } else { rank_density /= 2; } }#else /* CONFIG_DDR_INTERLEAVE */ if (dimm_num == 1) { /* * Eg: Bounds: 0x0000_0000 to 0x0f000_0000 first 256 Meg */ ddr->cs0_bnds = (start_addr >> 8) | (((start_addr + rank_density - 1) >> 24)); ddr->cs0_config = ( 1 << 31 | (odt_rd_cfg << 20) | (odt_wr_cfg << 16) | (spd.nrow_addr - 12) << 8 | (spd.ncol_addr - 8) ); debug("DDR: cs0_bnds = 0x%08x\n", ddr->cs0_bnds); debug("DDR: cs0_config = 0x%08x\n", ddr->cs0_config); if (n_ranks == 2) { /* * Eg: Bounds: 0x1000_0000 to 0x1f00_0000, * second 256 Meg */ ddr->cs1_bnds = (((start_addr + rank_density) >> 8) | (( start_addr + 2*rank_density - 1) >> 24)); ddr->cs1_config = ( 1<<31 | (odt_rd_cfg << 20) | (odt_wr_cfg << 16) | (spd.nrow_addr - 12) << 8 | (spd.ncol_addr - 8) ); debug("DDR: cs1_bnds = 0x%08x\n", ddr->cs1_bnds); debug("DDR: cs1_config = 0x%08x\n", ddr->cs1_config); } } else { /* * This is the 2nd DIMM slot for this controller */ /* * Eg: Bounds: 0x0000_0000 to 0x0f000_0000 first 256 Meg */ ddr->cs2_bnds = (start_addr >> 8) | (((start_addr + rank_density - 1) >> 24)); ddr->cs2_config = ( 1 << 31 | (odt_rd_cfg << 20) | (odt_wr_cfg << 16) | (spd.nrow_addr - 12) << 8 | (spd.ncol_addr - 8) ); debug("DDR: cs2_bnds = 0x%08x\n", ddr->cs2_bnds); debug("DDR: cs2_config = 0x%08x\n", ddr->cs2_config); if (n_ranks == 2) { /* * Eg: Bounds: 0x1000_0000 to 0x1f00_0000, * second 256 Meg */ ddr->cs3_bnds = (((start_addr + rank_density) >> 8) | (( start_addr + 2*rank_density - 1) >> 24)); ddr->cs3_config = ( 1<<31 | (odt_rd_cfg << 20) | (odt_wr_cfg << 16) | (spd.nrow_addr - 12) << 8 | (spd.ncol_addr - 8) ); debug("DDR: cs3_bnds = 0x%08x\n", ddr->cs3_bnds); debug("DDR: cs3_config = 0x%08x\n", ddr->cs3_config); } }#endif /* CONFIG_DDR_INTERLEAVE */ /* * Find the largest CAS by locating the highest 1 bit * in the spd.cas_lat field. Translate it to a DDR * controller field value:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -