📄 4xx_ibm_ddr2_autocalib.c
字号:
int bxcr_num; int rffd_average; int pass; u32 passed = 0; int in_window; struct autocal_regs curr_win_min; struct autocal_regs curr_win_max; struct autocal_regs best_win_min; struct autocal_regs best_win_max; struct autocal_regs loop_win_min; struct autocal_regs loop_win_max;#ifdef DEBUG ulong temp;#endif ulong rdcc; char slash[] = "\\|/-\\|/-"; int loopi = 0; /* start */ in_window = 0; memset(&curr_win_min, 0, sizeof(curr_win_min)); memset(&curr_win_max, 0, sizeof(curr_win_max)); memset(&best_win_min, 0, sizeof(best_win_min)); memset(&best_win_max, 0, sizeof(best_win_max)); memset(&loop_win_min, 0, sizeof(loop_win_min)); memset(&loop_win_max, 0, sizeof(loop_win_max)); rdcc = 0; /* * Program RDCC register * Read sample cycle auto-update enable */ mtsdram(SDRAM_RDCC, SDRAM_RDCC_RDSS_T1 | SDRAM_RDCC_RSAE_ENABLE);#ifdef DEBUG mfsdram(SDRAM_RDCC, temp); debug("<%s>SDRAM_RDCC=0x%x\n", __func__, temp); mfsdram(SDRAM_RTSR, temp); debug("<%s>SDRAM_RTSR=0x%x\n", __func__, temp); mfsdram(SDRAM_FCSR, temp); debug("<%s>SDRAM_FCSR=0x%x\n", __func__, temp);#endif /* * Program RQDC register * Internal DQS delay mechanism enable */ mtsdram(SDRAM_RQDC, SDRAM_RQDC_RQDE_ENABLE | SDRAM_RQDC_RQFD_ENCODE(0x00));#ifdef DEBUG mfsdram(SDRAM_RQDC, temp); debug("<%s>SDRAM_RQDC=0x%x\n", __func__, temp);#endif /* * Program RFDC register * Set Feedback Fractional Oversample * Auto-detect read sample cycle enable */ mtsdram(SDRAM_RFDC, SDRAM_RFDC_ARSE_ENABLE | SDRAM_RFDC_RFOS_ENCODE(0) | SDRAM_RFDC_RFFD_ENCODE(0));#ifdef DEBUG mfsdram(SDRAM_RFDC, temp); debug("<%s>SDRAM_RFDC=0x%x\n", __func__, temp);#endif putc(' '); for (rqfd = 0; rqfd <= SDRAM_RQDC_RQFD_MAX; rqfd++) { mfsdram(SDRAM_RQDC, rqdc_reg); rqdc_reg &= ~(SDRAM_RQDC_RQFD_MASK); mtsdram(SDRAM_RQDC, rqdc_reg | SDRAM_RQDC_RQFD_ENCODE(rqfd)); putc('\b'); putc(slash[loopi++ % 8]); curr_win_min.rffd = 0; curr_win_max.rffd = 0; in_window = 0; for (rffd = 0, pass = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) { mfsdram(SDRAM_RFDC, rfdc_reg); rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK); mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd)); for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) { mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf); /* Banks enabled */ if (bxcf & SDRAM_BXCF_M_BE_MASK) { /* Bank is enabled */ membase = get_membase(bxcr_num); pass = short_mem_test(membase); } /* if bank enabled */ } /* for bxcr_num */ /* If this value passed update RFFD windows */ if (pass && !in_window) { /* at the start of window */ in_window = 1; curr_win_min.rffd = curr_win_max.rffd = rffd; curr_win_min.rqfd = curr_win_max.rqfd = rqfd; mfsdram(SDRAM_RDCC, rdcc); /*record this value*/ } else if (!pass && in_window) { /* at end of window */ in_window = 0; } else if (pass && in_window) { /* within the window */ curr_win_max.rffd = rffd; curr_win_max.rqfd = rqfd; } /* else if (!pass && !in_window) skip - no pass, not currently in a window */ if (in_window) { if ((curr_win_max.rffd - curr_win_min.rffd) > (best_win_max.rffd - best_win_min.rffd)) { best_win_min.rffd = curr_win_min.rffd; best_win_max.rffd = curr_win_max.rffd; best_win_min.rqfd = curr_win_min.rqfd; best_win_max.rqfd = curr_win_max.rqfd; cal->rdcc = rdcc; } passed = 1; } } /* RFDC.RFFD */ /* * save-off the best window results of the RFDC.RFFD * for this RQDC.RQFD setting */ /* * if (just ended RFDC.RFDC loop pass window) > * (prior RFDC.RFFD loop pass window) */ if ((best_win_max.rffd - best_win_min.rffd) > (loop_win_max.rffd - loop_win_min.rffd)) { loop_win_min.rffd = best_win_min.rffd; loop_win_max.rffd = best_win_max.rffd; loop_win_min.rqfd = rqfd; loop_win_max.rqfd = rqfd; debug("RQFD.min 0x%08x, RQFD.max 0x%08x, " "RFFD.min 0x%08x, RFFD.max 0x%08x\n", loop_win_min.rqfd, loop_win_max.rqfd, loop_win_min.rffd, loop_win_max.rffd); } } /* RQDC.RQFD */ putc('\b'); debug("\n"); if ((loop_win_min.rffd == 0) && (loop_win_max.rffd == 0) && (best_win_min.rffd == 0) && (best_win_max.rffd == 0) && (best_win_min.rqfd == 0) && (best_win_max.rqfd == 0)) { passed = 0; } /* * Need to program RQDC before RFDC. */ debug("<%s> RQFD Min: 0x%x\n", __func__, loop_win_min.rqfd); debug("<%s> RQFD Max: 0x%x\n", __func__, loop_win_max.rqfd); rqfd_average = loop_win_max.rqfd; if (rqfd_average < 0) rqfd_average = 0; if (rqfd_average > SDRAM_RQDC_RQFD_MAX) rqfd_average = SDRAM_RQDC_RQFD_MAX; debug("<%s> RFFD average: 0x%08x\n", __func__, rqfd_average); mtsdram(SDRAM_RQDC, (rqdc_reg & ~SDRAM_RQDC_RQFD_MASK) | SDRAM_RQDC_RQFD_ENCODE(rqfd_average)); debug("<%s> RFFD Min: 0x%08x\n", __func__, loop_win_min.rffd); debug("<%s> RFFD Max: 0x%08x\n", __func__, loop_win_max.rffd); rffd_average = ((loop_win_min.rffd + loop_win_max.rffd) / 2); if (rffd_average < 0) rffd_average = 0; if (rffd_average > SDRAM_RFDC_RFFD_MAX) rffd_average = SDRAM_RFDC_RFFD_MAX; debug("<%s> RFFD average: 0x%08x\n", __func__, rffd_average); mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average)); /* if something passed, then return the size of the largest window */ if (passed != 0) { passed = loop_win_max.rffd - loop_win_min.rffd; cal->rqfd = rqfd_average; cal->rffd = rffd_average; cal->rffd_min = loop_win_min.rffd; cal->rffd_max = loop_win_max.rffd; } return (u32)passed;}#else /* !defined(CONFIG_PPC4xx_DDR_METHOD_A) *//*-----------------------------------------------------------------------------+| program_DQS_calibration_methodB.+-----------------------------------------------------------------------------*/static u32 program_DQS_calibration_methodB(struct ddrautocal *ddrcal){ u32 pass_result = 0;#ifdef DEBUG ulong temp;#endif /* * Program RDCC register * Read sample cycle auto-update enable */ mtsdram(SDRAM_RDCC, SDRAM_RDCC_RDSS_T2 | SDRAM_RDCC_RSAE_ENABLE);#ifdef DEBUG mfsdram(SDRAM_RDCC, temp); debug("<%s>SDRAM_RDCC=0x%08x\n", __func__, temp);#endif /* * Program RQDC register * Internal DQS delay mechanism enable */ mtsdram(SDRAM_RQDC,#if defined(CONFIG_DDR_RQDC_START_VAL) SDRAM_RQDC_RQDE_ENABLE | SDRAM_RQDC_RQFD_ENCODE(CONFIG_DDR_RQDC_START_VAL));#else SDRAM_RQDC_RQDE_ENABLE | SDRAM_RQDC_RQFD_ENCODE(0x38));#endif#ifdef DEBUG mfsdram(SDRAM_RQDC, temp); debug("<%s>SDRAM_RQDC=0x%08x\n", __func__, temp);#endif /* * Program RFDC register * Set Feedback Fractional Oversample * Auto-detect read sample cycle enable */ mtsdram(SDRAM_RFDC, SDRAM_RFDC_ARSE_ENABLE | SDRAM_RFDC_RFOS_ENCODE(0) | SDRAM_RFDC_RFFD_ENCODE(0));#ifdef DEBUG mfsdram(SDRAM_RFDC, temp); debug("<%s>SDRAM_RFDC=0x%08x\n", __func__, temp);#endif pass_result = DQS_calibration_methodB(ddrcal); return pass_result;}/* * DQS_calibration_methodB() * * Autocalibration Method B * * ARRAY [Entire DQS Range] DQS_Valid_Window ; initialized to all zeros * ARRAY [Entire Feedback Range] FDBK_Valid_Window; initialized to all zeros * MEMWRITE(addr, expected_data); * Initialialize the DQS delay to 80 degrees (MCIF0_RRQDC[RQFD]=0x38). * * for (j = 0; j < Entire Feedback Range; j++) { * MEMREAD(addr, actual_data); * if (actual_data == expected_data) { * FDBK_Valid_Window[j] = 1; * } * } * * Set MCIF0_RFDC[RFFD] to the middle of the FDBK_Valid_Window. * * for (i = 0; i < Entire DQS Range; i++) { * MEMREAD(addr, actual_data); * if (actual_data == expected_data) { * DQS_Valid_Window[i] = 1; * } * } * * Set MCIF0_RRQDC[RQFD] to the middle of the DQS_Valid_Window. *//*-----------------------------------------------------------------------------+| DQS_calibration_methodB.+-----------------------------------------------------------------------------*/static u32 DQS_calibration_methodB(struct ddrautocal *cal){ ulong rfdc_reg; ulong rffd; ulong rqdc_reg; ulong rqfd; ulong rdcc; u32 *membase; ulong bxcf; int rqfd_average; int bxcr_num; int rffd_average; int pass; uint passed = 0; int in_window; u32 curr_win_min, curr_win_max; u32 best_win_min, best_win_max; u32 size = 0; /*------------------------------------------------------------------ | Test to determine the best read clock delay tuning bits. | | Before the DDR controller can be used, the read clock delay needs to | be set. This is SDRAM_RQDC[RQFD] and SDRAM_RFDC[RFFD]. | This value cannot be hardcoded into the program because it changes | depending on the board's setup and environment. | To do this, all delay values are tested to see if they | work or not. By doing this, you get groups of fails with groups of | passing values. The idea is to find the start and end of a passing | window and take the center of it to use as the read clock delay. | | A failure has to be seen first so that when we hit a pass, we know | that it is truely the start of the window. If we get passing values | to start off with, we don't know if we are at the start of the window | | The code assumes that a failure will always be found. | If a failure is not found, there is no easy way to get the middle | of the passing window. I guess we can pretty much pick any value | but some values will be better than others. Since the lowest speed | we can clock the DDR interface at is 200 MHz (2x 100 MHz PLB speed), | from experimentation it is safe to say you will always have a failure +-----------------------------------------------------------------*/ debug("\n\n"); in_window = 0; rdcc = 0; curr_win_min = curr_win_max = 0; best_win_min = best_win_max = 0; for (rffd = 0; rffd <= SDRAM_RFDC_RFFD_MAX; rffd++) { mfsdram(SDRAM_RFDC, rfdc_reg); rfdc_reg &= ~(SDRAM_RFDC_RFFD_MASK); mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd)); pass = 1; for (bxcr_num = 0; bxcr_num < MAXBXCF; bxcr_num++) { mfsdram(SDRAM_MB0CF + (bxcr_num<<2), bxcf); /* Banks enabled */ if (bxcf & SDRAM_BXCF_M_BE_MASK) { /* Bank is enabled */ membase = get_membase(bxcr_num); pass &= short_mem_test(membase); } /* if bank enabled */ } /* for bxcf_num */ /* If this value passed */ if (pass && !in_window) { /* start of passing window */ in_window = 1; curr_win_min = curr_win_max = rffd; mfsdram(SDRAM_RDCC, rdcc); /* record this value */ } else if (!pass && in_window) { /* end passing window */ in_window = 0; } else if (pass && in_window) { /* within the passing window */ curr_win_max = rffd; } if (in_window) { if ((curr_win_max - curr_win_min) > (best_win_max - best_win_min)) { best_win_min = curr_win_min; best_win_max = curr_win_max; cal->rdcc = rdcc; } passed = 1; } } /* for rffd */ if ((best_win_min == 0) && (best_win_max == 0)) passed = 0; else size = best_win_max - best_win_min; debug("RFFD Min: 0x%x\n", best_win_min); debug("RFFD Max: 0x%x\n", best_win_max); rffd_average = ((best_win_min + best_win_max) / 2); cal->rffd_min = best_win_min; cal->rffd_max = best_win_max; if (rffd_average < 0) rffd_average = 0; if (rffd_average > SDRAM_RFDC_RFFD_MAX) rffd_average = SDRAM_RFDC_RFFD_MAX; mtsdram(SDRAM_RFDC, rfdc_reg | SDRAM_RFDC_RFFD_ENCODE(rffd_average)); rffd = rffd_average; in_window = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -