[U-Boot] [PATCH V3 28/32] mx6q_4x_mt41j128.cfg: add mx6 solo/duallite support

Eric Nelson eric.nelson at boundarydevices.com
Mon Oct 8 20:46:09 CEST 2012


Hi Troy,

This seems to be the patch where the rubber meets the road in
much of this series.

On 10/03/2012 06:47 PM, Troy Kisky wrote:
> Signed-off-by: Troy Kisky<troy.kisky at boundarydevices.com>
> ---
>   board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg |  120 +++++++++++++++++++-------
>   1 file changed, 87 insertions(+), 33 deletions(-)
>
> diff --git a/board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg b/board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg
> index 9e20db0..f45f93e 100644
> --- a/board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg
> +++ b/board/freescale/imx/ddr/mx6q_4x_mt41j128.cfg
> @@ -49,6 +49,15 @@ BOOT_FROM      sd
>    *      Address   absolute address of the register
>    *      value     value to be stored in the register
>    */
> +/*
> + * DDR3 settings
> + * MX6Q    ddr is limited to 1066 Mhz, currently 1056 MHz(528 MHz clock),
> + *	   memory bus width: 64 bits, x16/x32/x64
> + * MX6DL   ddr is limited to 800 MHz(400 MHz clock)
> + *	   memory bus width: 64 bits, x16/x32/x64
> + * MX6SOLO ddr is limited to 800 MHz(400 MHz clock)
> + *	   memory bus width: 32 bits, x16/x32
> + */

This comment seems to be critical to understanding some of
what's below, since now three **different** memory configurations
are represented in this file.

At a minimum, the file name should be changed to get rid of
'6q' and '4x' since those don't necessarily apply.

>   WRITE_ENTRY1(IOM_DRAM_SDQS0, 0x00000030)
>   WRITE_ENTRY1(IOM_DRAM_SDQS1, 0x00000030)
>   WRITE_ENTRY1(IOM_DRAM_SDQS2, 0x00000030)
> @@ -90,6 +99,7 @@ WRITE_ENTRY1(IOM_GRP_B6DS, 0x00000030)
>   WRITE_ENTRY1(IOM_GRP_B7DS, 0x00000030)
>
>   WRITE_ENTRY1(IOM_GRP_ADDDS, 0x00000030)
> +
>   /* (differential input) */
>   WRITE_ENTRY1(IOM_DDRMODE_CTL, 0x00020000)
>   /* disable ddr pullups */
> @@ -119,48 +129,92 @@ WRITE_ENTRY1(MMDC_P0_MDMISC, 0x00081740)
>    * MDSCR, con_req
>    */
>   WRITE_ENTRY1(MMDC_P0_MDSCR, 0x00008000)
> +
>   /*
> - * MDCFG0, tRFC=0x56 clocks, tXS=0x5b clocks
> - * tXP=4 clocks, tXPDLL=13 clocks
> - * tFAW=24 clocks, cas=8 cycles
> + * MDCFG0,
> + * MX6Q:
> + *	tRFC=0x56 clocks, tXS=0x5b clocks, tXP=4 clocks, tXPDLL=13 clocks
> + *	tFAW=24 clocks, cas=8 cycles
> + * MX6DL/SOLO:
> + *	tRFC=0x6a clocks, tXS=0x6e clocks, tXP=3 clocks, tXPDLL=10 clocks
> + *	 tFAW=19 clocks, cas=6 cycles
>    */
> -WRITE_ENTRY1(MMDC_P0_MDCFG0, 0x555A7975)
> +WRITE_ENTRY2(MMDC_P0_MDCFG0, 0x555A7975, 0x696D5323)
> +

Here's where I start to get lost in the macro-fu.

The WRITE_ENTRY1 macros make some sense to me in that they
always write a single value to an offset whose address
changes based on the processor type.

In order to understand WRITE_ENTRY2, you really have to
know that the dual, solo, and sololite share many
characteristics.

It's kinda hard to infer that knowledge from the code
and I wonder if this structure will hold up under future
revisions.

>   /*
> - * MDCFG1, tRDC=8, tRP=8, tRC=27,tRAS=20,tRPA=tRP+1,tWR=8
> - * tMRD=4, tCWL=6
> + * MDCFG1,
> + * MX6Q:
> + *	tRDC=8, tRP=8, tRC=27, tRAS=20, tRPA=tRP+1, tWR=8, tMRD=4, tCWL=6
> + * MX6DL/SOLO:
> + *	tRDC=6, tRP=6, tRC=20, tRAS=15, tRPA=tRP+1, tWR=7, tMRD=4, tCWL=5
>    */
> -WRITE_ENTRY1(MMDC_P0_MDCFG1, 0xFF538E64)
> +WRITE_ENTRY2(MMDC_P0_MDCFG1, 0xFF538E64, 0xB66E8C63)
> +
>   /*
>    * MDCFG2,tDLLK=512,tRTP=4,tWTR=4,tRRD=4
>    */
>   WRITE_ENTRY1(MMDC_P0_MDCFG2, 0x01FF00DB)
>   WRITE_ENTRY1(MMDC_P0_MDRWD, 0x000026D2)
> -
>   WRITE_ENTRY1(MMDC_P0_MDOR, 0x005B0E21)
> -WRITE_ENTRY1(MMDC_P0_MDOTC, 0x09444040)
> -WRITE_ENTRY1(MMDC_P0_MDPDC, 0x00025576)
>
>   /*
> - * Mx6Q - 64 bit wide ddr
> + * MMDC_MDOTC,
> + * MX6Q:
> + *	tAOFPD=2 cycles, tAONPD=2, tANPD=5, tAXPD=5, tODTLon=5, tODT_idle_off=5
> + * MX6DL/SOLO:
> + *	tAOFPD=1 cycles, tAONPD=1, tANPD=4, tAXPD=4, tODTLon=4, tODT_idle_off=4
> + */
> +WRITE_ENTRY2(MMDC_P0_MDOTC, 0x09444040, 0x00333030)
> +
> +/*
> + * MDPDC - [17:16](2) =>  CKE pulse width = 3 cycles.
> + * [15:12](5) =>  PWDT_1 = 256 cycles
> + * [11:8](5) =>PWDR_0 = 256 cycles
> + * MX6Q:       [2:0](6) =>  CKSRE = 6 cycles, [5:3](6) =>  CKSRX = 6 cycles
> + * MX6DL/SOLO: [2:0](5) =>  CKSRE = 5 cycles, [5:3](5) =>  CKSRX = 5 cycles
> + */
> +WRITE_ENTRY2(MMDC_P0_MDPDC, 0x00025576, 0x0002556D)
> +
> +/*
> + * MX6Q/DL - 64 bit wide ddr
>    * last address is  (1<<28 (base) + 1<<30  - 1)  / (1<<25) =
>    * 	1<<3 + 1<<5 - 1 = 8 + 0x20 -1 = 0x27
>    */
> +/*
> + * MX6SOLO - 32 bit wide ddr
> + * last address is  (1<<28 (base) + 1<<29  - 1)  / (1<<25) =
> + *	1<<3 + 1<<4 - 1 = 8 + 0x10 -1 = 0x17
> + */
>   /* MDASP, CS0_END */
> -WRITE_ENTRY1(MMDC_P0_MDASP, 0x00000027)
> +WRITE_ENTRY3(MMDC_P0_MDASP, 0x00000027, 0x00000027, 0x00000017)

Is it unreasonable to think there's a use case for 32-bit wide
memory on a dual or quad?

What happens when we populate 256Mx16 DDR chips?

Sabre Auto is already doing this.

>   /*
> - * MDCTL, CS0 enable, CS1 disabled, row=14, col=10, burst=8, width=64/32bit
> - * mx6q   : row+col+bank+width=14+10+3+3=30 = 1G
> + * MDCTL, CS0 enable, CS1 disabled, row=14, col=10, burst=8
> + * MX6Q/DL: width=64bit row+col+bank+width=14+10+3+3=30 = 1G
> + * MX6SOLO: width=32bit row+col+bank+width=14+10+3+2=29 = 512M
>    */
> -WRITE_ENTRY1(MMDC_P0_MDCTL, 0x831A0000)
> +WRITE_ENTRY3(MMDC_P0_MDCTL, 0x831A0000, 0x831A0000, 0x83190000)
>
> -/* MDSCR, con_req, LOAD MR2, CS0, A3,A10 set (CAS Write=6), RZQ/2 */
> -WRITE_ENTRY1(MMDC_P0_MDSCR, 0x04088032)
> +/*
> + * LOAD MR2: MDSCR, con_req,  CS0, A10 set - RZQ/2
> + * MX6Q:    A3 set(CAS Write=6)
> + * MX6DL/SOLO: (CAS Write=5)
> + */
> +WRITE_ENTRY2(MMDC_P0_MDSCR, 0x04088032, 0x04008032)
>   /* LOAD MR3, CS0 */
>   WRITE_ENTRY1(MMDC_P0_MDSCR, 0x00008033)
> -/* LOAD MR1, CS0, A1,A6 set Rtt=RZQ/2, ODI=RZQ/7 */
> -WRITE_ENTRY1(MMDC_P0_MDSCR, 0x00428031)
> -/* LOAD MR0, CS0, A6,A8,A11 set CAS=8, WR=8, DLL reset */
> -WRITE_ENTRY1(MMDC_P0_MDSCR, 0x09408030)
> +
> +/*
> + * LOAD MR1, CS0
> + * MX6Q: A6 set: Rtt=RZQ/2, A1 set: ODI=RZQ/7
> + * MX6DL/SOLO: A2 set: Rtt=RZQ/4, ODI=RZQ/6
> + */
> +WRITE_ENTRY2(MMDC_P0_MDSCR, 0x00428031, 0x00048031)
> +
> +/* LOAD MR0, CS0 A8 set: DLL Reset
> + * MX6Q: A6 set: CAS=8 A11 set: WR=8
> + * MX6DL/SOLO: A4 set: CAS=5, A9,A10 set: WR=7
> + */
> +WRITE_ENTRY2(MMDC_P0_MDSCR, 0x09408030, 0x07208030)
>
>   /* ZQ calibrate, CS0 */
>   WRITE_ENTRY1(MMDC_P0_MDSCR, 0x04008040)
> @@ -173,18 +227,18 @@ WRITE_ENTRY1(MMDC_P0_MPODTCTRL, 0x00022227)
>   WRITE_ENTRY1(MMDC_P1_MPODTCTRL, 0x00022227)
>
>   /* MPDGCTRL0/1 DQS GATE*/
> -WRITE_ENTRY1(MMDC_P0_MPDGCTRL0, 0x434B0350)
> -WRITE_ENTRY1(MMDC_P0_MPDGCTRL1, 0x034C0359)
> -WRITE_ENTRY1(MMDC_P1_MPDGCTRL0, 0x434B0350)
> -WRITE_ENTRY1(MMDC_P1_MPDGCTRL1, 0x03650348)
> -WRITE_ENTRY1(MMDC_P0_MPRDDLCTL, 0x4436383B)
> -WRITE_ENTRY1(MMDC_P1_MPRDDLCTL, 0x39393341)
> -WRITE_ENTRY1(MMDC_P0_MPWRDLCTL, 0x35373933)
> -WRITE_ENTRY1(MMDC_P1_MPWRDLCTL, 0x48254A36)
> -WRITE_ENTRY1(MMDC_P0_MPWLDECTRL0, 0x001F001F)
> -WRITE_ENTRY1(MMDC_P0_MPWLDECTRL1, 0x001F001F)
> -WRITE_ENTRY1(MMDC_P1_MPWLDECTRL0, 0x00440044)
> -WRITE_ENTRY1(MMDC_P1_MPWLDECTRL1, 0x00440044)
> +WRITE_ENTRY2(MMDC_P0_MPDGCTRL0, 0x434B0350, 0x42350231)
> +WRITE_ENTRY2(MMDC_P0_MPDGCTRL1, 0x034C0359, 0x021A0218)
> +WRITE_ENTRY2(MMDC_P1_MPDGCTRL0, 0x434B0350, 0x42350231)
> +WRITE_ENTRY2(MMDC_P1_MPDGCTRL1, 0x03650348, 0x021A0218)
> +WRITE_ENTRY2(MMDC_P0_MPRDDLCTL, 0x4436383B, 0x4B4B4E49)
> +WRITE_ENTRY2(MMDC_P1_MPRDDLCTL, 0x39393341, 0x4B4B4E49)
> +WRITE_ENTRY2(MMDC_P0_MPWRDLCTL, 0x35373933, 0x3F3F3035)
> +WRITE_ENTRY2(MMDC_P1_MPWRDLCTL, 0x48254A36, 0x3F3F3035)
> +WRITE_ENTRY2(MMDC_P0_MPWLDECTRL0, 0x001F001F, 0x0040003C)
> +WRITE_ENTRY2(MMDC_P0_MPWLDECTRL1, 0x001F001F, 0x0032003E)
> +WRITE_ENTRY2(MMDC_P1_MPWLDECTRL0, 0x00440044, 0x0040003C)
> +WRITE_ENTRY2(MMDC_P1_MPWLDECTRL1, 0x00440044, 0x0032003E)
>
>   /* MPMUR0 - Complete calibration by forced measurement */
>   WRITE_ENTRY1(MMDC_P0_MPMUR0, 0x00000800)

It appears that only the memory configuration registers use
WRITE_ENTRY2 or WRITE_ENTRY3 macros, and if so, I'd much
rather see three separate files expressing the values, i.e.:

     mx6q_4x_mt41j128.cfg
     mx6dl_4x_mt41j128.cfg
     mx6s_2x_mt41j128.cfg

I'm not certain the processor part of the name is the
right designator though. If I understand correctly,
the differences in values between 6q and 6dl are mostly
based on the memory speed.

Is that right?

It also seems valid that a board would want to use an
i.mx6quad with a lower memory bus speed.

If the address differences are taken care of by the
preprocessor, it seems that a set like this would
be more appropriate (and processor independent):

     mx6_4x_mt41j128_1066.cfg
     mx6_4x_mt41j128_800.cfg
     mx6_2x_mt41j128_800.cfg

By splitting up the files, we can still check for
differences between them using 'diff', and it will
be easier to extend the set.

Note that meaningful diffs will require the use of
symbolic names rather than varying addresses for
registers.

It's also conceivable that calibration on a given
layout will require per-board tweaks, but that's
not clear at the moment.

You've clearly been through this in more detail than
I have. Please let me know your thoughts.

Regards,


Eric


More information about the U-Boot mailing list