Newer
Older
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
bgn_curr = d;
/*
* If current window is bigger than best seen. Set best
* seen to be current window.
*/
if ((end_curr-bgn_curr+1) > win_best) {
win_best = end_curr-bgn_curr+1;
bgn_best = bgn_curr;
end_best = end_curr;
}
} else {
/* We just saw a failing test. Reset temp edge */
bgn_curr = IO_IO_OUT1_DELAY_MAX + 1;
end_curr = IO_IO_OUT1_DELAY_MAX + 1;
/* Early exit optimization: if ther remaining delay
chain space is less than already seen largest window
we can exit */
if ((win_best-1) >
(IO_IO_OUT1_DELAY_MAX - new_dqs - d)) {
break;
}
}
}
/* assign left and right edge for cal and reporting; */
left_edge[0] = -1*bgn_best;
right_edge[0] = end_best;
debug_cond(DLEVEL == 2, "%s:%d dm_calib: left=%d right=%d\n", __func__,
__LINE__, left_edge[0], right_edge[0]);
/* Move DQS (back to orig) */
scc_mgr_apply_group_dqs_io_and_oct_out1(write_group, new_dqs);
/* Move DM */
/* Find middle of window for the DM bit */
mid = (left_edge[0] - right_edge[0]) / 2;
/* only move right, since we are not moving DQS/DQ */
if (mid < 0)
mid = 0;
/* dm_marign should fail if we never find a window */
if (win_best == 0)
dm_margin = -1;
else
dm_margin = left_edge[0] - mid;
scc_mgr_apply_group_dm_out1_delay(mid);
writel(0, &sdr_scc_mgr->update);
debug_cond(DLEVEL == 2, "%s:%d dm_calib: left=%d right=%d mid=%d \
dm_margin=%d\n", __func__, __LINE__, left_edge[0],
right_edge[0], mid, dm_margin);
/* Export values */
gbl->fom_out += dq_margin + dqs_margin;
debug_cond(DLEVEL == 2, "%s:%d write_center: dq_margin=%d \
dqs_margin=%d dm_margin=%d\n", __func__, __LINE__,
dq_margin, dqs_margin, dm_margin);
/*
* Do not remove this line as it makes sure all of our
* decisions have been applied.
*/
writel(0, &sdr_scc_mgr->update);
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
return (dq_margin >= 0) && (dqs_margin >= 0) && (dm_margin >= 0);
}
/* calibrate the write operations */
static uint32_t rw_mgr_mem_calibrate_writes(uint32_t rank_bgn, uint32_t g,
uint32_t test_bgn)
{
/* update info for sims */
debug("%s:%d %u %u\n", __func__, __LINE__, g, test_bgn);
reg_file_set_stage(CAL_STAGE_WRITES);
reg_file_set_sub_stage(CAL_SUBSTAGE_WRITES_CENTER);
reg_file_set_group(g);
if (!rw_mgr_mem_calibrate_writes_center(rank_bgn, g, test_bgn)) {
set_failing_group_stage(g, CAL_STAGE_WRITES,
CAL_SUBSTAGE_WRITES_CENTER);
return 0;
}
return 1;
}
/* precharge all banks and activate row 0 in bank "000..." and bank "111..." */
static void mem_precharge_and_activate(void)
{
uint32_t r;
for (r = 0; r < RW_MGR_MEM_NUMBER_OF_RANKS; r++) {
if (param->skip_ranks[r]) {
/* request to skip the rank */
continue;
}
/* set rank */
set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_OFF);
/* precharge all banks ... */
writel(RW_MGR_PRECHARGE_ALL, SDR_PHYGRP_RWMGRGRP_ADDRESS |
RW_MGR_RUN_SINGLE_GROUP_OFFSET);
writel(0x0F, &sdr_rw_load_mgr_regs->load_cntr0);
writel(RW_MGR_ACTIVATE_0_AND_1_WAIT1,
&sdr_rw_load_jump_mgr_regs->load_jump_add0);
writel(0x0F, &sdr_rw_load_mgr_regs->load_cntr1);
writel(RW_MGR_ACTIVATE_0_AND_1_WAIT2,
&sdr_rw_load_jump_mgr_regs->load_jump_add1);
/* activate rows */
writel(RW_MGR_ACTIVATE_0_AND_1, SDR_PHYGRP_RWMGRGRP_ADDRESS |
RW_MGR_RUN_SINGLE_GROUP_OFFSET);
}
}
/* Configure various memory related parameters. */
static void mem_config(void)
{
uint32_t rlat, wlat;
uint32_t rw_wl_nop_cycles;
uint32_t max_latency;
debug("%s:%d\n", __func__, __LINE__);
/* read in write and read latency */
wlat = readl(&data_mgr->t_wl_add);
wlat += readl(&data_mgr->mem_t_add);
/* WL for hard phy does not include additive latency */
/*
* add addtional write latency to offset the address/command extra
* clock cycle. We change the AC mux setting causing AC to be delayed
* by one mem clock cycle. Only do this for DDR3
*/
wlat = wlat + 1;
rlat = readl(&data_mgr->t_rl_add);
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
rw_wl_nop_cycles = wlat - 2;
gbl->rw_wl_nop_cycles = rw_wl_nop_cycles;
/*
* For AV/CV, lfifo is hardened and always runs at full rate so
* max latency in AFI clocks, used here, is correspondingly smaller.
*/
max_latency = (1<<MAX_LATENCY_COUNT_WIDTH)/1 - 1;
/* configure for a burst length of 8 */
/* write latency */
/* Adjust Write Latency for Hard PHY */
wlat = wlat + 1;
/* set a pretty high read latency initially */
gbl->curr_read_lat = rlat + 16;
if (gbl->curr_read_lat > max_latency)
gbl->curr_read_lat = max_latency;
writel(gbl->curr_read_lat, &phy_mgr_cfg->phy_rlat);
/* advertise write latency */
gbl->curr_write_lat = wlat;
writel(wlat - 2, &phy_mgr_cfg->afi_wlat);
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
/* initialize bit slips */
mem_precharge_and_activate();
}
/* Set VFIFO and LFIFO to instant-on settings in skip calibration mode */
static void mem_skip_calibrate(void)
{
uint32_t vfifo_offset;
uint32_t i, j, r;
debug("%s:%d\n", __func__, __LINE__);
/* Need to update every shadow register set used by the interface */
for (r = 0; r < RW_MGR_MEM_NUMBER_OF_RANKS;
r += NUM_RANKS_PER_SHADOW_REG) {
/*
* Set output phase alignment settings appropriate for
* skip calibration.
*/
for (i = 0; i < RW_MGR_MEM_IF_READ_DQS_WIDTH; i++) {
scc_mgr_set_dqs_en_phase(i, 0);
#if IO_DLL_CHAIN_LENGTH == 6
scc_mgr_set_dqdqs_output_phase(i, 6);
#else
scc_mgr_set_dqdqs_output_phase(i, 7);
#endif
/*
* Case:33398
*
* Write data arrives to the I/O two cycles before write
* latency is reached (720 deg).
* -> due to bit-slip in a/c bus
* -> to allow board skew where dqs is longer than ck
* -> how often can this happen!?
* -> can claim back some ptaps for high freq
* support if we can relax this, but i digress...
*
* The write_clk leads mem_ck by 90 deg
* The minimum ptap of the OPA is 180 deg
* Each ptap has (360 / IO_DLL_CHAIN_LENGH) deg of delay
* The write_clk is always delayed by 2 ptaps
*
* Hence, to make DQS aligned to CK, we need to delay
* DQS by:
* (720 - 90 - 180 - 2 * (360 / IO_DLL_CHAIN_LENGTH))
*
* Dividing the above by (360 / IO_DLL_CHAIN_LENGTH)
* gives us the number of ptaps, which simplies to:
*
* (1.25 * IO_DLL_CHAIN_LENGTH - 2)
*/
scc_mgr_set_dqdqs_output_phase(i, (1.25 *
IO_DLL_CHAIN_LENGTH - 2));
}
writel(0xff, &sdr_scc_mgr->dqs_ena);
writel(0xff, &sdr_scc_mgr->dqs_io_ena);
for (i = 0; i < RW_MGR_MEM_IF_WRITE_DQS_WIDTH; i++) {
writel(i, SDR_PHYGRP_SCCGRP_ADDRESS |
SCC_MGR_GROUP_COUNTER_OFFSET);
writel(0xff, &sdr_scc_mgr->dq_ena);
writel(0xff, &sdr_scc_mgr->dm_ena);
writel(0, &sdr_scc_mgr->update);
}
/* Compensate for simulation model behaviour */
for (i = 0; i < RW_MGR_MEM_IF_READ_DQS_WIDTH; i++) {
scc_mgr_set_dqs_bus_in_delay(i, 10);
scc_mgr_load_dqs(i);
}
writel(0, &sdr_scc_mgr->update);
/*
* ArriaV has hard FIFOs that can only be initialized by incrementing
* in sequencer.
*/
vfifo_offset = CALIB_VFIFO_OFFSET;
for (j = 0; j < vfifo_offset; j++) {
writel(0xff, &phy_mgr_cmd->inc_vfifo_hard_phy);
writel(0, &phy_mgr_cmd->fifo_reset);
/*
* For ACV with hard lfifo, we get the skip-cal setting from
* generation-time constant.
*/
gbl->curr_read_lat = CALIB_LFIFO_OFFSET;
writel(gbl->curr_read_lat, &phy_mgr_cfg->phy_rlat);
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
}
/* Memory calibration entry point */
static uint32_t mem_calibrate(void)
{
uint32_t i;
uint32_t rank_bgn, sr;
uint32_t write_group, write_test_bgn;
uint32_t read_group, read_test_bgn;
uint32_t run_groups, current_run;
uint32_t failing_groups = 0;
uint32_t group_failed = 0;
uint32_t sr_failed = 0;
debug("%s:%d\n", __func__, __LINE__);
/* Initialize the data settings */
gbl->error_substage = CAL_SUBSTAGE_NIL;
gbl->error_stage = CAL_STAGE_NIL;
gbl->error_group = 0xff;
gbl->fom_in = 0;
gbl->fom_out = 0;
mem_config();
for (i = 0; i < RW_MGR_MEM_IF_READ_DQS_WIDTH; i++) {
writel(i, SDR_PHYGRP_SCCGRP_ADDRESS |
SCC_MGR_GROUP_COUNTER_OFFSET);
/* Only needed once to set all groups, pins, DQ, DQS, DM. */
if (i == 0)
scc_mgr_set_hhp_extras();
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
}
if ((dyn_calib_steps & CALIB_SKIP_ALL) == CALIB_SKIP_ALL) {
/*
* Set VFIFO and LFIFO to instant-on settings in skip
* calibration mode.
*/
mem_skip_calibrate();
} else {
for (i = 0; i < NUM_CALIB_REPEAT; i++) {
/*
* Zero all delay chain/phase settings for all
* groups and all shadow register sets.
*/
scc_mgr_zero_all();
run_groups = ~param->skip_groups;
for (write_group = 0, write_test_bgn = 0; write_group
< RW_MGR_MEM_IF_WRITE_DQS_WIDTH; write_group++,
write_test_bgn += RW_MGR_MEM_DQ_PER_WRITE_DQS) {
/* Initialized the group failure */
group_failed = 0;
current_run = run_groups & ((1 <<
RW_MGR_NUM_DQS_PER_WRITE_GROUP) - 1);
run_groups = run_groups >>
RW_MGR_NUM_DQS_PER_WRITE_GROUP;
if (current_run == 0)
continue;
writel(write_group, SDR_PHYGRP_SCCGRP_ADDRESS |
SCC_MGR_GROUP_COUNTER_OFFSET);
scc_mgr_zero_group(write_group, 0);
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
for (read_group = write_group *
RW_MGR_MEM_IF_READ_DQS_WIDTH /
RW_MGR_MEM_IF_WRITE_DQS_WIDTH,
read_test_bgn = 0;
read_group < (write_group + 1) *
RW_MGR_MEM_IF_READ_DQS_WIDTH /
RW_MGR_MEM_IF_WRITE_DQS_WIDTH &&
group_failed == 0;
read_group++, read_test_bgn +=
RW_MGR_MEM_DQ_PER_READ_DQS) {
/* Calibrate the VFIFO */
if (!((STATIC_CALIB_STEPS) &
CALIB_SKIP_VFIFO)) {
if (!rw_mgr_mem_calibrate_vfifo
(read_group,
read_test_bgn)) {
group_failed = 1;
if (!(gbl->
phy_debug_mode_flags &
PHY_DEBUG_SWEEP_ALL_GROUPS)) {
return 0;
}
}
}
}
/* Calibrate the output side */
if (group_failed == 0) {
for (rank_bgn = 0, sr = 0; rank_bgn
< RW_MGR_MEM_NUMBER_OF_RANKS;
rank_bgn +=
NUM_RANKS_PER_SHADOW_REG,
++sr) {
sr_failed = 0;
if (!((STATIC_CALIB_STEPS) &
CALIB_SKIP_WRITES)) {
if ((STATIC_CALIB_STEPS)
& CALIB_SKIP_DELAY_SWEEPS) {
/* not needed in quick mode! */
} else {
/*
* Determine if this set of
* ranks should be skipped
* entirely.
*/
if (!param->skip_shadow_regs[sr]) {
if (!rw_mgr_mem_calibrate_writes
(rank_bgn, write_group,
write_test_bgn)) {
sr_failed = 1;
if (!(gbl->
phy_debug_mode_flags &
PHY_DEBUG_SWEEP_ALL_GROUPS)) {
return 0;
}
}
}
}
}
if (sr_failed != 0)
group_failed = 1;
}
}
if (group_failed == 0) {
for (read_group = write_group *
RW_MGR_MEM_IF_READ_DQS_WIDTH /
RW_MGR_MEM_IF_WRITE_DQS_WIDTH,
read_test_bgn = 0;
read_group < (write_group + 1)
* RW_MGR_MEM_IF_READ_DQS_WIDTH
/ RW_MGR_MEM_IF_WRITE_DQS_WIDTH &&
group_failed == 0;
read_group++, read_test_bgn +=
RW_MGR_MEM_DQ_PER_READ_DQS) {
if (!((STATIC_CALIB_STEPS) &
CALIB_SKIP_WRITES)) {
if (!rw_mgr_mem_calibrate_vfifo_end
(read_group, read_test_bgn)) {
group_failed = 1;
if (!(gbl->phy_debug_mode_flags
& PHY_DEBUG_SWEEP_ALL_GROUPS)) {
return 0;
}
}
}
}
}
if (group_failed != 0)
failing_groups++;
}
/*
* USER If there are any failing groups then report
* the failure.
*/
if (failing_groups != 0)
return 0;
/* Calibrate the LFIFO */
if (!((STATIC_CALIB_STEPS) & CALIB_SKIP_LFIFO)) {
/*
* If we're skipping groups as part of debug,
* don't calibrate LFIFO.
*/
if (param->skip_groups == 0) {
if (!rw_mgr_mem_calibrate_lfifo())
return 0;
}
}
}
}
/*
* Do not remove this line as it makes sure all of our decisions
* have been applied.
*/
writel(0, &sdr_scc_mgr->update);
return 1;
}
/**
* run_mem_calibrate() - Perform memory calibration
*
* This function triggers the entire memory calibration procedure.
*/
static int run_mem_calibrate(void)
debug("%s:%d\n", __func__, __LINE__);
/* Reset pass/fail status shown on afi_cal_success/fail */
writel(PHY_MGR_CAL_RESET, &phy_mgr_cfg->cal_status);
/* Stop tracking manager. */
clrbits_le32(&sdr_ctrl->ctrl_cfg, 1 << 22);
phy_mgr_initialize();
rw_mgr_mem_initialize();
/* Perform the actual memory calibration. */
pass = mem_calibrate();
mem_precharge_and_activate();
writel(0, &phy_mgr_cmd->fifo_reset);
/* Handoff. */
rw_mgr_mem_handoff();
* In Hard PHY this is a 2-bit control:
* 0: AFI Mux Select
* 1: DDIO Mux Select
writel(0x2, &phy_mgr_cfg->mux_sel);
/* Start tracking manager. */
setbits_le32(&sdr_ctrl->ctrl_cfg, 1 << 22);
return pass;
}
/**
* debug_mem_calibrate() - Report result of memory calibration
* @pass: Value indicating whether calibration passed or failed
*
* This function reports the results of the memory calibration
* and writes debug information into the register file.
*/
static void debug_mem_calibrate(int pass)
{
uint32_t debug_info;
if (pass) {
printf("%s: CALIBRATION PASSED\n", __FILE__);
gbl->fom_in /= 2;
gbl->fom_out /= 2;
if (gbl->fom_in > 0xff)
gbl->fom_in = 0xff;
if (gbl->fom_out > 0xff)
gbl->fom_out = 0xff;
/* Update the FOM in the register file */
debug_info = gbl->fom_in;
debug_info |= gbl->fom_out << 8;
writel(debug_info, &sdr_reg_file->fom);
writel(debug_info, &phy_mgr_cfg->cal_debug_info);
writel(PHY_MGR_CAL_SUCCESS, &phy_mgr_cfg->cal_status);
} else {
printf("%s: CALIBRATION FAILED\n", __FILE__);
debug_info = gbl->error_stage;
debug_info |= gbl->error_substage << 8;
debug_info |= gbl->error_group << 16;
writel(debug_info, &sdr_reg_file->failing_stage);
writel(debug_info, &phy_mgr_cfg->cal_debug_info);
writel(PHY_MGR_CAL_FAIL, &phy_mgr_cfg->cal_status);
/* Update the failing group/stage in the register file */
debug_info = gbl->error_stage;
debug_info |= gbl->error_substage << 8;
debug_info |= gbl->error_group << 16;
writel(debug_info, &sdr_reg_file->failing_stage);
printf("%s: Calibration complete\n", __FILE__);
/**
* hc_initialize_rom_data() - Initialize ROM data
*
* Initialize ROM data.
*/
static void hc_initialize_rom_data(void)
{
addr = SDR_PHYGRP_RWMGRGRP_ADDRESS | RW_MGR_INST_ROM_WRITE_OFFSET;
for (i = 0; i < ARRAY_SIZE(inst_rom_init); i++)
writel(inst_rom_init[i], addr + (i << 2));
addr = SDR_PHYGRP_RWMGRGRP_ADDRESS | RW_MGR_AC_ROM_WRITE_OFFSET;
for (i = 0; i < ARRAY_SIZE(ac_rom_init); i++)
writel(ac_rom_init[i], addr + (i << 2));
/**
* initialize_reg_file() - Initialize SDR register file
*
* Initialize SDR register file.
*/
static void initialize_reg_file(void)
{
/* Initialize the register file with the correct data */
writel(REG_FILE_INIT_SEQ_SIGNATURE, &sdr_reg_file->signature);
writel(0, &sdr_reg_file->debug_data_addr);
writel(0, &sdr_reg_file->cur_stage);
writel(0, &sdr_reg_file->fom);
writel(0, &sdr_reg_file->failing_stage);
writel(0, &sdr_reg_file->debug1);
writel(0, &sdr_reg_file->debug2);
/**
* initialize_hps_phy() - Initialize HPS PHY
*
* Initialize HPS PHY.
*/
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
static void initialize_hps_phy(void)
{
uint32_t reg;
/*
* Tracking also gets configured here because it's in the
* same register.
*/
uint32_t trk_sample_count = 7500;
uint32_t trk_long_idle_sample_count = (10 << 16) | 100;
/*
* Format is number of outer loops in the 16 MSB, sample
* count in 16 LSB.
*/
reg = 0;
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_ACDELAYEN_SET(2);
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_DQDELAYEN_SET(1);
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_DQSDELAYEN_SET(1);
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_DQSLOGICDELAYEN_SET(1);
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_RESETDELAYEN_SET(0);
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_LPDDRDIS_SET(1);
/*
* This field selects the intrinsic latency to RDATA_EN/FULL path.
* 00-bypass, 01- add 5 cycles, 10- add 10 cycles, 11- add 15 cycles.
*/
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_ADDLATSEL_SET(0);
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_SAMPLECOUNT_19_0_SET(
trk_sample_count);
writel(reg, &sdr_ctrl->phy_ctrl0);
reg = 0;
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_1_SAMPLECOUNT_31_20_SET(
trk_sample_count >>
SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_SAMPLECOUNT_19_0_WIDTH);
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_1_LONGIDLESAMPLECOUNT_19_0_SET(
trk_long_idle_sample_count);
writel(reg, &sdr_ctrl->phy_ctrl1);
reg = 0;
reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_2_LONGIDLESAMPLECOUNT_31_20_SET(
trk_long_idle_sample_count >>
SDR_CTRLGRP_PHYCTRL_PHYCTRL_1_LONGIDLESAMPLECOUNT_19_0_WIDTH);
writel(reg, &sdr_ctrl->phy_ctrl2);
/**
* initialize_tracking() - Initialize tracking
*
* Initialize the register file with usable initial data.
*/
static void initialize_tracking(void)
{
/*
* Initialize the register file with the correct data.
* Compute usable version of value in case we skip full
* computation later.
*/
writel(DIV_ROUND_UP(IO_DELAY_PER_OPA_TAP, IO_DELAY_PER_DCHAIN_TAP) - 1,
&sdr_reg_file->dtaps_per_ptap);
/* trk_sample_count */
writel(7500, &sdr_reg_file->trk_sample_count);
/* longidle outer loop [15:0] */
writel((10 << 16) | (100 << 0), &sdr_reg_file->trk_longidle);
* longidle sample count [31:24]
* trfc, worst case of 933Mhz 4Gb [23:16]
* trcd, worst case [15:8]
* vfifo wait [7:0]
writel((243 << 24) | (14 << 16) | (10 << 8) | (4 << 0),
&sdr_reg_file->delays);
/* mux delay */
writel((RW_MGR_IDLE << 24) | (RW_MGR_ACTIVATE_1 << 16) |
(RW_MGR_SGLE_READ << 8) | (RW_MGR_PRECHARGE_ALL << 0),
&sdr_reg_file->trk_rw_mgr_addr);
writel(RW_MGR_MEM_IF_READ_DQS_WIDTH,
&sdr_reg_file->trk_read_dqs_width);
/* trefi [7:0] */
writel((RW_MGR_REFRESH_ALL << 24) | (1000 << 0),
&sdr_reg_file->trk_rfsh);
}
int sdram_calibration_full(void)
{
struct param_type my_param;
struct gbl_type my_gbl;
uint32_t pass;
memset(&my_param, 0, sizeof(my_param));
memset(&my_gbl, 0, sizeof(my_gbl));
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
param = &my_param;
gbl = &my_gbl;
/* Set the calibration enabled by default */
gbl->phy_debug_mode_flags |= PHY_DEBUG_ENABLE_CAL_RPT;
/*
* Only sweep all groups (regardless of fail state) by default
* Set enabled read test by default.
*/
#if DISABLE_GUARANTEED_READ
gbl->phy_debug_mode_flags |= PHY_DEBUG_DISABLE_GUARANTEED_READ;
#endif
/* Initialize the register file */
initialize_reg_file();
/* Initialize any PHY CSR */
initialize_hps_phy();
scc_mgr_initialize();
initialize_tracking();
printf("%s: Preparing to start memory calibration\n", __FILE__);
debug("%s:%d\n", __func__, __LINE__);
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
debug_cond(DLEVEL == 1,
"DDR3 FULL_RATE ranks=%u cs/dimm=%u dq/dqs=%u,%u vg/dqs=%u,%u ",
RW_MGR_MEM_NUMBER_OF_RANKS, RW_MGR_MEM_NUMBER_OF_CS_PER_DIMM,
RW_MGR_MEM_DQ_PER_READ_DQS, RW_MGR_MEM_DQ_PER_WRITE_DQS,
RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS,
RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS);
debug_cond(DLEVEL == 1,
"dqs=%u,%u dq=%u dm=%u ptap_delay=%u dtap_delay=%u ",
RW_MGR_MEM_IF_READ_DQS_WIDTH, RW_MGR_MEM_IF_WRITE_DQS_WIDTH,
RW_MGR_MEM_DATA_WIDTH, RW_MGR_MEM_DATA_MASK_WIDTH,
IO_DELAY_PER_OPA_TAP, IO_DELAY_PER_DCHAIN_TAP);
debug_cond(DLEVEL == 1, "dtap_dqsen_delay=%u, dll=%u",
IO_DELAY_PER_DQS_EN_DCHAIN_TAP, IO_DLL_CHAIN_LENGTH);
debug_cond(DLEVEL == 1, "max values: en_p=%u dqdqs_p=%u en_d=%u dqs_in_d=%u ",
IO_DQS_EN_PHASE_MAX, IO_DQDQS_OUT_PHASE_MAX,
IO_DQS_EN_DELAY_MAX, IO_DQS_IN_DELAY_MAX);
debug_cond(DLEVEL == 1, "io_in_d=%u io_out1_d=%u io_out2_d=%u ",
IO_IO_IN_DELAY_MAX, IO_IO_OUT1_DELAY_MAX,
IO_IO_OUT2_DELAY_MAX);
debug_cond(DLEVEL == 1, "dqs_in_reserve=%u dqs_out_reserve=%u\n",
IO_DQS_IN_RESERVE, IO_DQS_OUT_RESERVE);
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
hc_initialize_rom_data();
/* update info for sims */
reg_file_set_stage(CAL_STAGE_NIL);
reg_file_set_group(0);
/*
* Load global needed for those actions that require
* some dynamic calibration support.
*/
dyn_calib_steps = STATIC_CALIB_STEPS;
/*
* Load global to allow dynamic selection of delay loop settings
* based on calibration mode.
*/
if (!(dyn_calib_steps & CALIB_SKIP_DELAY_LOOPS))
skip_delay_mask = 0xff;
else
skip_delay_mask = 0x0;
pass = run_mem_calibrate();