In title, you can convert sdram->SDRAM

On Tue 2015-06-02 22:52:49, dingu...@opensource.altera.com wrote:
> From: Dinh Nguyen <dingu...@opensource.altera.com>
> 
> This patch adds the DDR calibration portion of the Altera SDRAM driver.
> 
> Signed-off-by: Dinh Nguyen <dingu...@opensource.altera.com>

> +/*
> + * In order to reduce ROM size, most of the selectable calibration steps are
> + * decided at compile time based on the user's calibration mode selection,
> + * as captured by the STATIC_CALIB_STEPS selection below.
> + *
> + * However, to support simulation-time selection of fast simulation mode, 
> where
> + * we skip everything except the bare minimum, we need a few of the steps to
> + * be dynamic.  In those cases, we either use the DYNAMIC_CALIB_STEPS for the
> + * check, which is based on the rtl-supplied value, or we dynamically compute
> + * the value to use based on the dynamically-chosen calibration mode

"." at the end of sentence.

> +
> +#define DLEVEL 0
> +#define STATIC_IN_RTL_SIM 0
> +#define STATIC_SKIP_DELAY_LOOPS 0
> +
> +#define STATIC_CALIB_STEPS (STATIC_IN_RTL_SIM | CALIB_SKIP_FULL_TEST | \
> +     STATIC_SKIP_DELAY_LOOPS)

Would it make sense to drop simulation-time support for initial merge?

> +/* calibration steps requested by the rtl */
> +uint16_t dyn_calib_steps;

rtl?

> +/*
> + * To make CALIB_SKIP_DELAY_LOOPS a dynamic conditional option
> + * instead of static, we use boolean logic to select between
> + * non-skip and skip values
> + *
> + * The mask is set to include all bits when not-skipping, but is
> + * zero when skipping
> + */

"." at the end of sentence. Twice here :-).

> +
> +uint16_t skip_delay_mask;    /* mask off bits when skipping/not-skipping */
> +
> +#define SKIP_DELAY_LOOP_VALUE_OR_ZERO(non_skip_value) \
> +     ((non_skip_value) & skip_delay_mask)
> +
> +struct gbl_type *gbl;
> +struct param_type *param;
> +uint32_t curr_shadow_reg;
> +
> +static uint32_t rw_mgr_mem_calibrate_write_test(uint32_t rank_bgn,
> +     uint32_t write_group, uint32_t use_dm,
> +     uint32_t all_correct, uint32_t *bit_chk, uint32_t all_ranks);
> +
> +static u32 sdr_get_addr(u32 *base)
> +{
> +     u32 addr = (u32)base & MGR_SELECT_MASK;

You sometimes use uint32_t, and sometimes u32, as seen here. Would it
be more readable to just use u32 everywhere?

And this function would be really helped by taking "u32 base", not
"u32 *", as youd reduce number of typecasts below...


> +     switch (addr) {
> +     case BASE_PHY_MGR:
> +             addr = (((u32)base >> 8) & (1 << 6)) | ((u32)base & 0x3f) |
> +                     SDR_PHYGRP_PHYMGRGRP_ADDRESS;
> +             break;
> +     case BASE_RW_MGR:
> +             addr = ((u32)base & 0x1fff) | SDR_PHYGRP_RWMGRGRP_ADDRESS;
> +             break;
> +     case BASE_DATA_MGR:
> +             addr = ((u32)base & 0x7ff) | SDR_PHYGRP_DATAMGRGRP_ADDRESS;
> +             break;
> +     case BASE_SCC_MGR:
> +             addr = ((u32)base & 0xfff) | SDR_PHYGRP_SCCGRP_ADDRESS;
> +             break;
> +     case BASE_REG_FILE:
> +             addr = ((u32)base & 0x7ff) | SDR_PHYGRP_REGFILEGRP_ADDRESS;
> +             break;
> +     case BASE_MMR:
> +             addr = ((u32)base & 0xfff) | SDR_CTRLGRP_ADDRESS;
> +             break;

Or at least introduce temporary variable...

> +static void initialize(void)
> +{
> +     u32 addr = sdr_get_addr(&phy_mgr_cfg->mux_sel);
> +
> +     debug("%s:%d\n", __func__, __LINE__);

Is this debugging neccessary? It will change when you for example
change comment in here...

> +     /* USER calibration has control over path to memory */
> +     /*
> +      * In Hard PHY this is a 2-bit control:
> +      * 0: AFI Mux Select
> +      * 1: DDIO Mux Select
> +      */
> +     writel(0x3, SOCFPGA_SDR_ADDRESS + addr);
> +
> +     /* USER memory clock is not stable we begin initialization  */

"  */" -> " */"

> +     for (i = 0; i < 16; i++) {
> +             debug_cond(DLEVEL == 1, "%s:%d: Clearing SCC RFILE index %u",
> +                        __func__, __LINE__, i);

Ok, custom debugging system. Neccessary?

> +static void scc_mgr_set_dqs_en_delay(uint32_t read_group, uint32_t delay)
> +{
> +     uint32_t addr = sdr_get_addr((u32 *)SCC_MGR_DQS_EN_DELAY);

Now uint32_t vs. u32 on single line...

> +     for (r = 0; r < RW_MGR_MEM_NUMBER_OF_RANKS;
> +             r += NUM_RANKS_PER_SHADOW_REG) {
> +             scc_mgr_set_dqs_en_delay(read_group, delay);
> +
> +             addr = sdr_get_addr(&sdr_scc_mgr->dqs_ena);
> +             writel(read_group, SOCFPGA_SDR_ADDRESS + addr);
> +             /*
> +              * In shadow register mode, the T11 settings are stored in
> +              * registers in the core, which are updated by the DQS_ENA
> +              * signals. Not issuing the SCC_MGR_UPD command allows us to
> +              * save lots of rank switching overhead, by calling
> +              * select_shadow_regs_for_update with update_scan_chains
> +              * set to 0.
> +              */
> +             addr = sdr_get_addr(&sdr_scc_mgr->update);
> +             writel(0, SOCFPGA_SDR_ADDRESS + addr);
> +     }
> +     /*
> +      * In shadow register mode, the T11 settings are stored in
> +      * registers in the core, which are updated by the DQS_ENA
> +      * signals. Not issuing the SCC_MGR_UPD command allows us to
> +      * save lots of rank switching overhead, by calling
> +      * select_shadow_regs_for_update with update_scan_chains
> +      * set to 0.
> +      */
> +     addr = sdr_get_addr(&sdr_scc_mgr->update);
> +     writel(0, SOCFPGA_SDR_ADDRESS + addr);


Umm. Two completely same comments, two same pieces of code. Make it
function?

Does it make sense to run this twice in fact?


> +static void scc_set_bypass_mode(uint32_t write_group, uint32_t mode)
> +{
> +     uint32_t addr;
> +     /* mode = 0 : Do NOT bypass - Half Rate Mode */
> +     /* mode = 1 : Bypass - Full Rate Mode */

Then perhaps the parameter should be named "do_bypass" or "full_rate"?

> +             if ((RW_MGR_MEM_ADDRESS_MIRRORING >> r) & 0x1) {
> +                     set_jump_as_return();
> +                     addr = sdr_get_addr((u32 *)RW_MGR_RUN_SINGLE_GROUP);
> +                     writel(RW_MGR_MRS2_MIRR, SOCFPGA_SDR_ADDRESS + addr);
> +                     delay_for_n_mem_clocks(4);
> +                     set_jump_as_return();
> +                     writel(RW_MGR_MRS3_MIRR, SOCFPGA_SDR_ADDRESS + addr);
> +                     delay_for_n_mem_clocks(4);

What is this, some kind of bytecode interpretter? Or does it create a
bytecode for someone?

> +static int find_working_phase(uint32_t *grp, uint32_t *bit_chk,
> +                           uint32_t dtaps_per_ptap, uint32_t *work_bgn,
> +                           uint32_t *v, uint32_t *d, uint32_t *p,
> +                           uint32_t *i, uint32_t *max_working_cnt)
> +{

Undocumented, single-letter parameters do not really make reading the
code easy...

Should we have structure for work_bgn, v, d, p, i ... instead of
separate parameters?


> +     uint32_t found_begin = 0;
> +     uint32_t tmp_delay = 0;
> +     uint32_t test_status;
> +
> +     for (*d = 0; *d <= dtaps_per_ptap; (*d)++, tmp_delay +=
> +             IO_DELAY_PER_DQS_EN_DCHAIN_TAP) {
> +             *work_bgn = tmp_delay;
> +             scc_mgr_set_dqs_en_delay_all_ranks(*grp, *d);
> +
> +             for (*i = 0; *i < VFIFO_SIZE; (*i)++) {
> +                     for (*p = 0; *p <= IO_DQS_EN_PHASE_MAX; (*p)++, 
> *work_bgn +=
> +                             IO_DELAY_PER_OPA_TAP) {

Does this look like c-code to you?

> +     } else {
> +             /* ******************************************************* */
> +             /* * step 3-5b:  Find the right edge of the window using
> +             delay taps   * */
> +             debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase:vfifo=%u \
> +                        ptap=%u dtap=%u bgn=%u\n", __func__, __LINE__,
> +                        v, p, d, work_bgn);
> +
> +             work_end = work_bgn;
> +
> +             /* * The actual increment of dtaps is done outside of the
> +             if/else loop to share code */
> +
> +             /* Only here to counterbalance a subtract later on which is
> +             not needed if this branch of the algorithm is taken */
> +             max_working_cnt++;

Comment style in this block is even stranger than in other pieces of
this patch.

> +             } else {
> +                     for (i = 0; i < RW_MGR_MEM_DQ_PER_READ_DQS; i++) {
> +                             if (bit_chk & 1) {
> +                                     /* Remember a passing test as
> +                                     the right_edge */
> +                                     right_edge[i] = d;
> +                             } else {
> +                                     if (d != 0) {
> +                                             /* If a right edge has not been
> +                                             seen yet, then a future passing
> +                                             test will mark this edge as the
> +                                             left edge */
> +                                             if (right_edge[i] ==
> +                                             IO_IO_IN_DELAY_MAX + 1) {
> +                                                     left_edge[i] = -(d + 1);
> +                                             }
> +                                     } else {
> +                                             /* d = 0 failed, but it passed
> +                                             when testing the left edge,
> +                                             so it must be marginal,
> +                                             set it to -1 */
> +                                             if (right_edge[i] ==
> +                                                     IO_IO_IN_DELAY_MAX + 1 
> &&
> +                                                     left_edge[i] !=
> +                                                     IO_IO_IN_DELAY_MAX
> +                                                     + 1) {
> +                                                     right_edge[i] = -1;
> +                                             }

When this happens to your code, you know it is time to split your
function into sub-functions.

> +             if 
> (rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase_sweep_dq_in_delay
> +                 (write_group, read_group, test_bgn)) {
> +                             /*
> +                              * USER Read per-bit deskew can be done on a
> +                              * per shadow register basis.
> +                              */
> +                             for (rank_bgn = 0, sr = 0;
> +                                     rank_bgn < RW_MGR_MEM_NUMBER_OF_RANKS;
> +                                     rank_bgn += NUM_RANKS_PER_SHADOW_REG,
> +                                     ++sr) {
> +                                     /*
> +                                      * Determine if this set of ranks
> +                                      * should be skipped entirely.
> +                                      */
> +                                     if (!param->skip_shadow_regs[sr]) {
> +                                             /*
> +                                              * If doing read after write
> +                                              * calibration, do not update
> +                                              * FOM, now - do it then.
> +                                              */
> +                                     if (!rw_mgr_mem_calibrate_vfifo_center
> +                                             (rank_bgn, write_group,
> +                                             read_group, test_bgn, 1, 0)) {
> +                                                     grp_calibrated = 0;
> +                                                     failed_substage =
> +                                             CAL_SUBSTAGE_VFIFO_CENTER;
> +                                             }
> +                                     }

Here too. Notice that indentation is actually wrong/confusing here,
the ifs are nested.


> +/* VFIFO Calibration -- Read Deskew Calibration after write deskew */
> +static uint32_t rw_mgr_mem_calibrate_vfifo_end(uint32_t read_group,
> +                                            uint32_t test_bgn)
> +{
> +     uint32_t rank_bgn, sr;
> +     uint32_t grp_calibrated;
> +     uint32_t write_group;
> +
> +     debug("%s:%d %u %u", __func__, __LINE__, read_group, test_bgn);
> +
> +     /* update info for sims */
> +
> +     reg_file_set_stage(CAL_STAGE_VFIFO_AFTER_WRITES);
> +     reg_file_set_sub_stage(CAL_SUBSTAGE_VFIFO_CENTER);
> +
> +     write_group = read_group;
> +
> +     /* update info for sims */
> +     reg_file_set_group(read_group);
> +
> +     grp_calibrated = 1;
> +     /* Read per-bit deskew can be done on a per shadow register basis */
> +     for (rank_bgn = 0, sr = 0; rank_bgn < RW_MGR_MEM_NUMBER_OF_RANKS;
> +             rank_bgn += NUM_RANKS_PER_SHADOW_REG, ++sr) {
> +             /* Determine if this set of ranks should be skipped entirely */
> +             if (!param->skip_shadow_regs[sr]) {

if (param...)
   continue;

Then you get one less level of identation.

> +             /* This is the last calibration round, update FOM here */
> +                     if (!rw_mgr_mem_calibrate_vfifo_center(rank_bgn,
> +                                                             write_group,
> +                                                             read_group,
> +                                                             test_bgn, 0,
> +                                                             1)) {
> +                             grp_calibrated = 0;
> +                     }

..and you'll be able to do something with this.

> +             writel(gbl->curr_read_lat, SOCFPGA_SDR_ADDRESS + addr);
> +             debug_cond(DLEVEL == 2, "%s:%d lfifo: read_lat=%u",
> +                        __func__, __LINE__, gbl->curr_read_lat);
> +
> +             if (!rw_mgr_mem_calibrate_read_test_all_ranks(0,
> +                                                           NUM_READ_TESTS,
> +                                                           PASS_ALL_BITS,
> +                                                           &bit_chk, 1)) {
> +                     break;
> +             }

If you can't fix it any other way,

             if (!rw_mgr_mem_calibrate_read_test_all_ranks(0,
                   NUM_READ_TESTS, PASS_ALL_BITS, &bit_chk, 1)) {

is preferable. And you don't need {}'s around break;

> +             if (stop == 1) {
> +                     if (d == 0) {
> +                             for (i = 0; i < RW_MGR_MEM_DQ_PER_WRITE_DQS;
> +                                     i++) {
> +                                     /* d = 0 failed, but it passed when
> +                                     testing the left edge, so it must be
> +                                     marginal, set it to -1 */
> +                                     if (right_edge[i] ==
> +                                             IO_IO_OUT1_DELAY_MAX + 1 &&
> +                                             left_edge[i] !=
> +                                             IO_IO_OUT1_DELAY_MAX + 1) {
> +                                             right_edge[i] = -1;
> +                                     }
> +                             }
> +                     }
> +                     break;
> +             } else {
> +                     for (i = 0; i < RW_MGR_MEM_DQ_PER_WRITE_DQS; i++) {
> +                             if (bit_chk & 1) {
> +                                     /*
> +                                      * Remember a passing test as
> +                                      * the right_edge.
> +                                      */
> +                                     right_edge[i] = d;
> +                             } else {
> +                                     if (d != 0) {
> +                                             /*
> +                                              * If a right edge has not
> +                                              * been seen yet, then a future
> +                                              * passing test will mark this
> +                                              * edge as the left edge.
> +                                              */
> +                                             if (right_edge[i] ==
> +                                                 IO_IO_OUT1_DELAY_MAX + 1)
> +                                                     left_edge[i] = -(d + 1);
> +                                     } else {
> +                                             /*
> +                                              * d = 0 failed, but it passed
> +                                              * when testing the left edge,
> +                                              * so it must be marginal, set
> +                                              * it to -1.
> +                                              */
> +                                             if (right_edge[i] ==
> +                                                 IO_IO_OUT1_DELAY_MAX + 1 &&
> +                                                 left_edge[i] !=
> +                                                 IO_IO_OUT1_DELAY_MAX + 1)
> +                                                     right_edge[i] = -1;
> +                                             /*
> +                                              * If a right edge has not been
> +                                              * seen yet, then a future
> +                                              * passing test will mark this
> +                                              * edge as the left edge.
> +                                              */
> +                                             else if (right_edge[i] ==
> +                                                     IO_IO_OUT1_DELAY_MAX +
> +                                                     1)
> +                                                     left_edge[i] = -(d + 1);
> +                                     }
> +                             }

Something needs to be done here, too...

> +                             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;
> +                                                             }
> +                                                     }
> +                                             }
> +                                     }
> +                             }

And here. Note how indentation is so deep ifs are actually indented
the other way around here.

I guess it would be better to ignore 80-columns rule than _this_. But
splitting it into smaller functions is of course preffered.

Thanks,
                                                                        Pavel

-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) 
http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to