[U-Boot] [U-boot][PATCHv2 2/3] driver/ddr/altera/: Add the sdram calibration portion

Marek Vasut marex at denx.de
Sat May 2 02:41:08 CEST 2015


On Wednesday, April 29, 2015 at 04:58:15 PM, dinguyen at opensource.altera.com 
wrote:
> From: Dinh Nguyen <dinguyen at opensource.altera.com>
> 
> This patch adds the DDR calibration portion of the Altera SDRAM driver.
> 
> Signed-off-by: Dinh Nguyen <dinguyen at opensource.altera.com>

[...]

> +/*************************************************************************
> ***** +
> **************************************************************************
> **** + ** NOTE: Special Rules for Globale Variables                        
>        ** + **                                                            
>              ** + ** All global variables that are explicitly initialized
> (including          ** + ** explicitly initialized to zero), are only
> initialized once, during       ** + ** configuration time, and not again
> on reset.  This means that they        ** + ** preserve their current
> contents across resets, which is needed for some  ** + ** special cases
> involving communication with external modules.  In         ** + **
> addition, this avoids paying the price to have the memory initialized,  
> ** + ** even for zeroed data, provided it is explicitly set to zero in the
> code, ** + ** and doesn't rely on implicit initialization.                
>             ** +
> **************************************************************************
> **** +
> **************************************************************************
> ****/ +
> +/*
> + * Temporary workaround to place the initial stack pointer at a safe
> + * offset from end
> + */
> +asm(".global __alt_stack_pointer");
> +asm("__alt_stack_pointer = " __stringify(STACK_POINTER));

This is really scary. The idea here is to have some kind of a storage
which is preserved over warm reboots, right ? Tom, Simon, Albert, don't
we have some kind of a generic abstration for this kind of stuff ?

> +/* Just to make the debugging code more uniform */
> +#ifndef RW_MGR_MEM_NUMBER_OF_CS_PER_DIMM
> +#define RW_MGR_MEM_NUMBER_OF_CS_PER_DIMM 0
> +#endif
> +
> +#define SDR_WRITE	1
> +#define SDR_READ	0
> +
> +#define DELTA_D		1
> +#define MGR_SELECT_MASK		0xf8000
> +
> +/*
> + * 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 + */
> +
> +#define BTFLD_FMT "%u"

Nit: Maybe you should just massage this BTFLD_FMT into the code and drop the 
macro.

> +/* For HPS running on actual hardware */
> +
> +#define DLEVEL 0
> +/*
> + * space around comma is required for varargs macro to remove comma if
> args + * is empty
> + */
> +#define BFM_GBL_SET(field, value)
> +#define BFM_GBL_GET(field)		((long unsigned int)0)
> +#define BFM_STAGE(stage)
> +#define BFM_INC_VFIFO
> +#define COV(label)

Are the macros above needed ?

> +#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)
> +
> +/* calibration steps requested by the rtl */
> +uint16_t dyn_calib_steps;

[...]

> +static inline void scc_mgr_set_dm_in_delay(uint32_t write_group,
> +					   uint32_t dm, uint32_t delay)
> +{
> +	/* Load the setting in the SCC manager */
> +	sdr_ops((u32 *)SCC_MGR_IO_IN_DELAY,
> +		(RW_MGR_MEM_DQ_PER_WRITE_DQS + 1 + dm) << 2, delay, SDR_WRITE);

Won't it be better to convert this entire sdr_ops() to something like ...

addr = get_reg_address(...args...);
writel(...value..., addr);

? I think that'd make this code a bit more readable. What do you think ?

> +}
> +

[...]

> +/* find a good dqs enable to use */
> +static uint32_t rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(uint32_t grp)
> +{
> +	uint32_t i, d, v, p;
> +	uint32_t max_working_cnt;
> +	uint32_t fail_cnt;
> +	uint32_t bit_chk;
> +	uint32_t dtaps_per_ptap;
> +	uint32_t found_begin, found_end;
> +	uint32_t work_bgn, work_mid, work_end, tmp_delay;
> +	uint32_t test_status;
> +	uint32_t found_passing_read, found_failing_read, initial_failing_dtap;
> +
> +	debug("%s:%d %u\n", __func__, __LINE__, grp);
> +	BFM_STAGE("find_dqs_en_phase");
> +
> +	reg_file_set_sub_stage(CAL_SUBSTAGE_VFIFO_CENTER);
> +
> +	scc_mgr_set_dqs_en_delay_all_ranks(grp, 0);
> +	scc_mgr_set_dqs_en_phase_all_ranks(grp, 0);
> +
> +	fail_cnt = 0;
> +
> +	/* ************************************************************** */
> +	/* * Step 0 : Determine number of delay taps for each phase tap * */

You might want to split the steps in this function into separate functions,
since this functions is really extremely long. Would thats work please?

> +	dtaps_per_ptap = 0;
> +	tmp_delay = 0;
> +	while (tmp_delay < IO_DELAY_PER_OPA_TAP) {
> +		dtaps_per_ptap++;
> +		tmp_delay += IO_DELAY_PER_DQS_EN_DCHAIN_TAP;
> +	}
> +	dtaps_per_ptap--;
> +	tmp_delay = 0;

[...]

> diff --git a/drivers/ddr/altera/sequencer.h
> b/drivers/ddr/altera/sequencer.h new file mode 100644
> index 0000000..29f61a8
> --- /dev/null
> +++ b/drivers/ddr/altera/sequencer.h

[...]

> +/* MarkW: how should these base addresses be done for A-V? */
> +#define BASE_PTR_MGR			(0x00040000)
> +#define BASE_SCC_MGR			(0x00058000)
> +#define BASE_REG_FILE			(0x00070000)
> +#define BASE_TIMER			(0x00078000)
> +#define BASE_PHY_MGR			(0x00088000)
> +#define BASE_RW_MGR			(0x00090000)
> +#define BASE_DATA_MGR			(0x00098000)
> +#define BASE_MMR                        (0x000C0000)
> +#define BASE_TRK_MGR			(0x000D0000)

No need for those () around value .

> +#define SCC_MGR_GROUP_COUNTER			(BASE_SCC_MGR + 0x0000)
> +#define SCC_MGR_DQS_IN_DELAY			(BASE_SCC_MGR + 0x0100)
> +#define SCC_MGR_DQS_EN_PHASE			(BASE_SCC_MGR + 0x0200)
> +#define SCC_MGR_DQS_EN_DELAY			(BASE_SCC_MGR + 0x0300)
> +#define SCC_MGR_DQDQS_OUT_PHASE			(BASE_SCC_MGR + 0x0400)
> +#define SCC_MGR_OCT_OUT1_DELAY			(BASE_SCC_MGR + 0x0500)
> +#define SCC_MGR_IO_OUT1_DELAY			(BASE_SCC_MGR + 0x0700)
> +#define SCC_MGR_IO_IN_DELAY			(BASE_SCC_MGR + 0x0900)

Here it _IS_ needed though ;)

[...]

> diff --git a/drivers/ddr/altera/sequencer_auto_ac_init.c
> b/drivers/ddr/altera/sequencer_auto_ac_init.c new file mode 100644
> index 0000000..358a0ca
> --- /dev/null
> +++ b/drivers/ddr/altera/sequencer_auto_ac_init.c
> @@ -0,0 +1,85 @@
> +/*
> + * Copyright Altera Corporation (C) 2012-2015
> + *
> + * SPDX-License-Identifier:    BSD-3-Clause
> + */
> +
> +const unsigned long ac_rom_init_size = 36;

You can use ARRAY_SIZE() on the array below if that's really needed.
No need to explicitly hardcode values :)

> +const unsigned long ac_rom_init[36] = {

The compiler will compute the size of the array automatically.

> +#ifdef CONFIG_SOCFPGA_ARRIA5
> +/* The if..else... is not required if generated by tools */
> +	0x20700000,
> +	0x20780000,
> +	0x10080831,
> +	0x10080930,
> +	0x10090004,
> +	0x100a0008,
> +	0x100b0000,

[...]

> diff --git a/drivers/ddr/altera/sequencer_auto_inst_init.c
> b/drivers/ddr/altera/sequencer_auto_inst_init.c new file mode 100644
> index 0000000..9983c40
> --- /dev/null
> +++ b/drivers/ddr/altera/sequencer_auto_inst_init.c
> @@ -0,0 +1,270 @@
> +/*
> + * Copyright Altera Corporation (C) 2012-2015
> + *
> + * SPDX-License-Identifier:    BSD-3-Clause
> + */
> +
> +#ifdef CONFIG_SOCFPGA_ARRIA5
> +/* The if..else... is not required if generated by tools */
> +const alt_u32 inst_rom_init_size = 126;
> +const alt_u32 inst_rom_init[126] = {

DTTO here.

[...]


More information about the U-Boot mailing list