📄 4xx_ibm_ddr2_autocalib.c
字号:
/* * cpu/ppc4xx/4xx_ibm_ddr2_autocalib.c * This SPD SDRAM detection code supports AMCC PPC44x cpu's with a * DDR2 controller (non Denali Core). Those currently are: * * 405: 405EX * 440/460: 440SP/440SPe/460EX/460GT/460SX * * (C) Copyright 2008 Applied Micro Circuits Corporation * Adam Graham <agraham@amcc.com> * * (C) Copyright 2007-2008 * 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 ;-)) */#undef DEBUG#include <common.h>#include <ppc4xx.h>#include <asm/io.h>#include <asm/processor.h>#if defined(CONFIG_PPC4xx_DDR_AUTOCALIBRATION)/* * Only compile the DDR auto-calibration code for NOR boot and * not for NAND boot (NAND SPL and NAND U-Boot - NUB) */#if !defined(CONFIG_NAND_U_BOOT) && !defined(CONFIG_NAND_SPL)#define MAXBXCF 4#define SDRAM_RXBAS_SHIFT_1M 20#if defined(CFG_DECREMENT_PATTERNS)#define NUMMEMTESTS 24#else#define NUMMEMTESTS 8#endif /* CFG_DECREMENT_PATTERNS */#define NUMLOOPS 1 /* configure as you deem approporiate */#define NUMMEMWORDS 16/* Private Structure Definitions */struct autocal_regs { u32 rffd; u32 rqfd;};struct ddrautocal { u32 rffd; u32 rffd_min; u32 rffd_max; u32 rffd_size; u32 rqfd; u32 rqfd_size; u32 rdcc; u32 flags;};struct sdram_timing { u32 wrdtr; u32 clktr;};struct sdram_timing_clks { u32 wrdtr; u32 clktr; u32 rdcc; u32 flags;};struct autocal_clks { struct sdram_timing_clks clocks; struct ddrautocal autocal;};/*--------------------------------------------------------------------------+ * Prototypes *--------------------------------------------------------------------------*/#if defined(CONFIG_PPC4xx_DDR_METHOD_A)static u32 DQS_calibration_methodA(struct ddrautocal *);static u32 program_DQS_calibration_methodA(struct ddrautocal *);#elsestatic u32 DQS_calibration_methodB(struct ddrautocal *);static u32 program_DQS_calibration_methodB(struct ddrautocal *);#endifstatic int short_mem_test(u32 *);/* * To provide an interface for board specific config values in this common * DDR setup code, we implement he "weak" default functions here. They return * the default value back to the caller. * * Please see include/configs/yucca.h for an example fora board specific * implementation. */#if !defined(CONFIG_SPD_EEPROM)u32 __ddr_wrdtr(u32 default_val){ return default_val;}u32 ddr_wrdtr(u32) __attribute__((weak, alias("__ddr_wrdtr")));u32 __ddr_clktr(u32 default_val){ return default_val;}u32 ddr_clktr(u32) __attribute__((weak, alias("__ddr_clktr")));/* * Board-specific Platform code can reimplement spd_ddr_init_hang () if needed */void __spd_ddr_init_hang(void){ hang();}voidspd_ddr_init_hang(void) __attribute__((weak, alias("__spd_ddr_init_hang")));#endif /* defined(CONFIG_SPD_EEPROM) */ulong __ddr_scan_option(ulong default_val){ return default_val;}ulong ddr_scan_option(ulong) __attribute__((weak, alias("__ddr_scan_option")));static u32 *get_membase(int bxcr_num){ ulong bxcf; u32 *membase;#if defined(SDRAM_R0BAS) /* BAS from Memory Queue rank reg. */ membase = (u32 *)(SDRAM_RXBAS_SDBA_DECODE(mfdcr_any(SDRAM_R0BAS+bxcr_num))); bxcf = 0; /* just to satisfy the compiler */#else /* BAS from SDRAM_MBxCF mem rank reg. */ mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf); membase = (u32 *)((bxcf & 0xfff80000) << 3);#endif return membase;}static inline void ecc_clear_status_reg(void){ mtsdram(SDRAM_ECCCR, 0xffffffff);#if defined(SDRAM_R0BAS) mtdcr(SDRAM_ERRSTATLL, 0xffffffff);#endif}/* * Reset and relock memory DLL after SDRAM_CLKTR change */static inline void relock_memory_DLL(void){ u32 reg; mtsdram(SDRAM_MCOPT2, SDRAM_MCOPT2_IPTR_EXECUTE); do { mfsdram(SDRAM_MCSTAT, reg); } while (!(reg & SDRAM_MCSTAT_MIC_COMP)); mfsdram(SDRAM_MCOPT2, reg); mtsdram(SDRAM_MCOPT2, reg | SDRAM_MCOPT2_DCEN_ENABLE);}static int ecc_check_status_reg(void){ u32 ecc_status; /* * Compare suceeded, now check * if got ecc error. If got an * ecc error, then don't count * this as a passing value */ mfsdram(SDRAM_ECCCR, ecc_status); if (ecc_status != 0x00000000) { /* clear on error */ ecc_clear_status_reg(); /* ecc check failure */ return 0; } ecc_clear_status_reg(); sync(); return 1;}/* return 1 if passes, 0 if fail */static int short_mem_test(u32 *base_address){ int i, j, l; u32 ecc_mode = 0; ulong test[NUMMEMTESTS][NUMMEMWORDS] = { /* 0 */ {0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF}, /* 1 */ {0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000}, /* 2 */ {0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555}, /* 3 */ {0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA, 0x55555555, 0x55555555, 0xAAAAAAAA, 0xAAAAAAAA}, /* 4 */ {0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A}, /* 5 */ {0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5, 0x5A5A5A5A, 0x5A5A5A5A, 0xA5A5A5A5, 0xA5A5A5A5}, /* 6 */ {0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA}, /* 7 */ {0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55, 0x55AA55AA, 0x55AA55AA, 0xAA55AA55, 0xAA55AA55},#if defined(CFG_DECREMENT_PATTERNS) /* 8 */ {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff}, /* 9 */ {0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe, 0xfffefffe}, /* 10 */{0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd, 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd, 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd, 0xfffdfffd, 0xfffdfffd, 0xfffdffff, 0xfffdfffd}, /* 11 */{0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc, 0xfffcfffc}, /* 12 */{0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb, 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb, 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb, 0xfffbfffb, 0xfffffffb, 0xfffffffb, 0xfffffffb}, /* 13 */{0xfffafffa, 0xfffafffa, 0xfffffffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa, 0xfffafffa}, /* 14 */{0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9, 0xfff9fff9}, /* 15 */{0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8, 0xfff8fff8}, /* 16 */{0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7, 0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7, 0xfff7fff7, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7, 0xfff7ffff, 0xfff7ffff, 0xfff7fff7, 0xfff7fff7}, /* 17 */{0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7, 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7, 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7, 0xfff6fff5, 0xfff6ffff, 0xfff6fff6, 0xfff6fff7}, /* 18 */{0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5, 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5, 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5, 0xfff5fff4, 0xfff5ffff, 0xfff5fff5, 0xfff5fff5}, /* 19 */{0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4, 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4, 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4, 0xfff4fff3, 0xfff4ffff, 0xfff4fff4, 0xfff4fff4}, /* 20 */{0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3, 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3, 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3, 0xfff3fff2, 0xfff3ffff, 0xfff3fff3, 0xfff3fff3}, /* 21 */{0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2, 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2, 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2, 0xfff2ffff, 0xfff2ffff, 0xfff2fff2, 0xfff2fff2}, /* 22 */{0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1, 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1, 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1, 0xfff1ffff, 0xfff1ffff, 0xfff1fff1, 0xfff1fff1}, /* 23 */{0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fff0, 0xfff0fffe, 0xfff0fff0, 0xfff0fff0},#endif /* CFG_DECREMENT_PATTERNS */ }; mfsdram(SDRAM_MCOPT1, ecc_mode); if ((ecc_mode & SDRAM_MCOPT1_MCHK_CHK_REP) == SDRAM_MCOPT1_MCHK_CHK_REP) { ecc_clear_status_reg(); sync(); ecc_mode = 1; } else { ecc_mode = 0; } /* * Run the short memory test. */ for (i = 0; i < NUMMEMTESTS; i++) { for (j = 0; j < NUMMEMWORDS; j++) { base_address[j] = test[i][j]; ppcDcbf((ulong)&(base_address[j])); } sync(); for (l = 0; l < NUMLOOPS; l++) { for (j = 0; j < NUMMEMWORDS; j++) { if (base_address[j] != test[i][j]) { ppcDcbf((u32)&(base_address[j])); return 0; } else { if (ecc_mode) { if (!ecc_check_status_reg()) return 0; } } ppcDcbf((u32)&(base_address[j])); } /* for (j = 0; j < NUMMEMWORDS; j++) */ sync(); } /* for (l=0; l<NUMLOOPS; l++) */ } return 1;}#if defined(CONFIG_PPC4xx_DDR_METHOD_A)/*-----------------------------------------------------------------------------+| program_DQS_calibration_methodA.+-----------------------------------------------------------------------------*/static u32 program_DQS_calibration_methodA(struct ddrautocal *ddrcal){ u32 pass_result = 0;#ifdef DEBUG ulong temp; mfsdram(SDRAM_RDCC, temp); debug("<%s>SDRAM_RDCC=0x%08x\n", __func__, temp);#endif pass_result = DQS_calibration_methodA(ddrcal); return pass_result;}/* * DQS_calibration_methodA() * * Autocalibration Method A * * ARRAY [Entire DQS Range] DQS_Valid_Window ; initialized to all zeros * ARRAY [Entire FDBK Range] FDBK_Valid_Window; initialized to all zeros * MEMWRITE(addr, expected_data); * for (i = 0; i < Entire DQS Range; i++) { RQDC.RQFD * for (j = 0; j < Entire FDBK Range; j++) { RFDC.RFFD * MEMREAD(addr, actual_data); * if (actual_data == expected_data) { * DQS_Valid_Window[i] = 1; RQDC.RQFD * FDBK_Valid_Window[i][j] = 1; RFDC.RFFD * } * } * } */static u32 DQS_calibration_methodA(struct ddrautocal *cal){ ulong rfdc_reg; ulong rffd; ulong rqdc_reg; ulong rqfd; u32 *membase; ulong bxcf; int rqfd_average;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -