Enabling spread spectrum on iMX6 to pass EMI testing

Hi community!

I would like to enable the spread spectrum feature on the Apalis iMX6Q module in order to pass the EMI testing.
I am using U-Boot 2015.04 and Kernel 3.14.52.
In iMX6 the PLL2 is the one that supports spread spectrum feature, so I need to modify the bootloader to configure the PLL2 before the DDR is initialized since DDR will use PPL2 as its clock source.

On my U-Boot I see that DCD configuration is done in files ddr-setup.cfg and 1066mhz_4x256x16.cfg (2GB), these files are called from apalis_imx6q.cfg.
How can I enable the spread spectrum before the DCD configuration? I’m really not sure…

By searching a bit on the web, NXP states that the PLUGIN feature should be enabled using CONFIG_USE_PLUGIN. That way the DDR configuration is done in assembly code and not using DCD tables from ddr-setup.cfg and 1066mhz_4x256x16.cfg.
But I don’t find any PLUGIN feature available in the bootloader code for Toradex boards.

So I use the demo code of NXP (https://community.nxp.com/t5/i-MX-Processors-Knowledge-Base/enable-the-spread-spectrum/ta-p/1122405) and manually added:

  • The file plugin.S which contains my DDR configuration in assembly converted from ddr-setup.cfg and
    1066mhz_4x256x16.cfg, it contains the PLL2 configuration, enables spread spectrum, configures clock gates and qos settings.
    The assembly code of ddr-setup.cfg is defined in macro ddr_setting and the assembly code of 1066mhz_4x256x16.cfg is defined in macro ddr_mb_2048. See at the end of the post for the code of both macros.

I modified:

  • apalis_imx6q.cfg to enable the PLUGIN to call “plugin_start” in file mx6_plugin.S. And commentted the call of ddr-setup.cfg, 1066mhz_4x256mx16.cfg and clocks.cfg which are now done in assembly from plugin.S.
    The line below was added
    PLUGIN board/toradex/apalis_imx6/plugin.bin 0x00907000

  • mx6_plugin.S so the plugin configures the PPL2 (imx6_plugin_add) before the DDR configuration (imx6_ddr_setting)

Now when I tried my new bootloader, it does not work at all! The bootloader does not even boot (I can’t see anything on the debug log using UART)

Can anyone explain how to properly use the PLUGIN configuration? I don’t even know if the code under plugin_start in mx6_plugin.S is triggered. Also if I can have an explanation on how the PLUGIN works in general? How the plugin takes over from ROM and how to return to ROM from Plugin?

Thanks in advance for your answers,
Best Regards,
Ingrid

1 Like

Find below the converted DCD tables to assembly code defined in board/toradex/apalis_imx6/plugin.S

/* Converting ddr-setup.cfg into asm */
.macro ddr_setting
ldr r0, =IOMUXC_BASE_ADDR

ldr r1, =0x00000030
str r1, [r0, #0x5a8] /* MX6_IOM_DRAM_SDQS0 */
str r1, [r0, #0x5b0] /* MX6_IOM_DRAM_SDQS1 */
str r1, [r0, #0x524] /* MX6_IOM_DRAM_SDQS2 */
str r1, [r0, #0x51c] /* MX6_IOM_DRAM_SDQS3 */
str r1, [r0, #0x518] /* MX6_IOM_DRAM_SDQS4 */
str r1, [r0, #0x50c] /* MX6_IOM_DRAM_SDQS5 */
str r1, [r0, #0x5b8] /* MX6_IOM_DRAM_SDQS6 */
str r1, [r0, #0x5c0] /* MX6_IOM_DRAM_SDQS7 */

str r1, [r0, #0x784] /* MX6_IOM_GRP_B0DS */
str r1, [r0, #0x788] /* MX6_IOM_GRP_B1DS */
str r1, [r0, #0x794] /* MX6_IOM_GRP_B2DS */
str r1, [r0, #0x79c] /* MX6_IOM_GRP_B3DS */
str r1, [r0, #0x7a0] /* MX6_IOM_GRP_B4DS */
str r1, [r0, #0x7a4] /* MX6_IOM_GRP_B5DS */
str r1, [r0, #0x7a8] /* MX6_IOM_GRP_B6DS */
str r1, [r0, #0x748] /* MX6_IOM_GRP_B7DS */

str r1, [r0, #0x74c] /* MX6_IOM_GRP_ADDDS */

/* 40 Ohm drive strength for cs0/1,sdba2,cke0/1,sdwe */
str r1, [r0, #0x78c] /* MX6_IOM_GRP_CTLDS */

ldr r1, =0x00020030
str r1, [r0, #0x5ac] /* MX6_IOM_DRAM_DQM0 */
str r1, [r0, #0x5b4] /* MX6_IOM_DRAM_DQM1 */
str r1, [r0, #0x528] /* MX6_IOM_DRAM_DQM2 */
str r1, [r0, #0x520] /* MX6_IOM_DRAM_DQM3 */
str r1, [r0, #0x514] /* MX6_IOM_DRAM_DQM4 */
str r1, [r0, #0x510] /* MX6_IOM_DRAM_DQM5 */
str r1, [r0, #0x5bc] /* MX6_IOM_DRAM_DQM6 */
str r1, [r0, #0x5c4] /* MX6_IOM_DRAM_DQM7 */

str r1, [r0, #0x56c] /* MX6_IOM_DRAM_CAS */
str r1, [r0, #0x578] /* MX6_IOM_DRAM_RAS */
str r1, [r0, #0x588] /* MX6_IOM_DRAM_SDCLK_0 */
str r1, [r0, #0x594] /* MX6_IOM_DRAM_SDCLK_1 */

str r1, [r0, #0x57c] /* MX6_IOM_DRAM_RESET */

ldr r1, =0x00000030
str r1, [r0, #0x590] /* MX6_IOM_DRAM_SDCKE0 */
str r1, [r0, #0x598] /* MX6_IOM_DRAM_SDCKE1 */

ldr r1, =0x00003030
str r1, [r0, #0x59c] /* MX6_IOM_DRAM_SDODT0 */
str r1, [r0, #0x5a0] /* MX6_IOM_DRAM_SDODT1 */

ldr r1, =0x00020000
/* (differential input) */
str r1, [r0, #0x750] /* MX6_IOM_DDRMODE_CTL */
/* (differential input) */
str r1, [r0, #0x774] /* MX6_IOM_GRP_DDRMODE */
/* disable ddr pullups */
ldr r1, =0x00000000
str r1, [r0, #0x758] /* MX6_IOM_GRP_DDRPKE */
str r1, [r0, #0x58c] /* MX6_IOM_DRAM_SDBA2 */
/* 40 Ohm drive strength for cs0/1,sdba2,cke0/1,sdwe */
ldr r1, =0x000c0000
str r1, [r0, #0x798] /* MX6_IOM_GRP_DDR_TYPE */

ldr r0, =MMDC_P0_BASE_ADDR
ldr r1, =MMDC_P1_BASE_ADDR
/* Read data DQ Byte0-3 delay */
ldr r2, =0x33333333
str r2, [r0, #0x81c] /* MX6_MMDC_P0_MPRDDQBY0DL */
str r2, [r0, #0x820] /* MX6_MMDC_P0_MPRDDQBY1DL */
str r2, [r0, #0x824] /* MX6_MMDC_P0_MPRDDQBY2DL */
str r2, [r0, #0x828] /* MX6_MMDC_P0_MPRDDQBY3DL */
str r2, [r1, #0x81c] /* MX6_MMDC_P1_MPRDDQBY0DL */
str r2, [r1, #0x820] /* MX6_MMDC_P1_MPRDDQBY1DL */
str r2, [r1, #0x824] /* MX6_MMDC_P1_MPRDDQBY2DL */
str r2, [r1, #0x828] /* MX6_MMDC_P1_MPRDDQBY3DL */

/*
* MDMISC	mirroring	interleaved (row/bank/col)
*/
ldr r2, =0x00081740
str r2, [r0, #0x018] /* MX6_MMDC_P0_MDMISC */

/*
* MDSCR	con_req
*/
ldr r2, =0x00008000
str r2, [r0, #0x01c] /* MX6_MMDC_P0_MDSCR */

.endm

/* Converting 1066mhz_4x256mx16.cfg into asm /
.macro ddr_mb_2048
ldr r0, =MMDC_P0_BASE_ADDR
ldr r1, =MMDC_P1_BASE_ADDR
ldr r2, =0x00020036
str r2, [r0, #0x004] /
MX6_MMDC_P0_MDPDC /
ldr r2, =0x898E78f5
str r2, [r0, #0x00c] /
MX6_MMDC_P0_MDCFG0 /
ldr r2, =0xff328f64
str r2, [r0, #0x010] /
MX6_MMDC_P0_MDCFG1 /
ldr r2, =0x01FF00DB
str r2, [r0, #0x014] /
MX6_MMDC_P0_MDCFG2 /
ldr r2, =0x000026d2
str r2, [r0, #0x02c] /
MX6_MMDC_P0_MDRWD /
ldr r2, =0x008E1023
str r2, [r0, #0x030] /
MX6_MMDC_P0_MDOR /
ldr r2, =0x09444040
str r2, [r0, #0x008] /
MX6_MMDC_P0_MDOTC /
ldr r2, =0x00025576
str r2, [r0, #0x004] /
MX6_MMDC_P0_MDPDC /
ldr r2, =0x00000047
str r2, [r0, #0x040] /
MX6_MMDC_P0_MDASP /
ldr r2, =0x841A0000
str r2, [r0, #0x000] /
MX6_MMDC_P0_MDCTL /
ldr r2, =0x02888032
str r2, [r0, #0x01c] /
MX6_MMDC_P0_MDSCR /
ldr r2, =0x00008033
str r2, [r0, #0x01c] /
MX6_MMDC_P0_MDSCR /
ldr r2, =0x00048031
str r2, [r0, #0x01c] /
MX6_MMDC_P0_MDSCR /
ldr r2, =0x19408030
str r2, [r0, #0x01c] /
MX6_MMDC_P0_MDSCR /
ldr r2, =0x04008040
str r2, [r0, #0x01c] /
MX6_MMDC_P0_MDSCR /
ldr r2, =0xA1390003
str r2, [r0, #0x800] /
MX6_MMDC_P0_MPZQHWCTRL /
ldr r2, =0xA1390003
str r2, [r1, #0x800] /
MX6_MMDC_P1_MPZQHWCTRL /
ldr r2, =0x00007800
str r2, [r0, #0x020] /
MX6_MMDC_P0_MDREF /
ldr r2, =0x00022227
str r2, [r0, #0x818] /
MX6_MMDC_P0_MPODTCTRL /
ldr r2, =0x00022227
str r2, [r1, #0x818] /
MX6_MMDC_P1_MPODTCTRL */

ldr r2, =0x03300338
str r2, [r0, #0x83c] /* MX6_MMDC_P0_MPDGCTRL0 */
ldr r2, =0x03240324
str r2, [r0, #0x840] /* MX6_MMDC_P0_MPDGCTRL1 */
ldr r2, =0x03440350
str r2, [r1, #0x83c] /* MX6_MMDC_P1_MPDGCTRL0 */
ldr r2, =0x032C0308
str r2, [r1, #0x840] /* MX6_MMDC_P1_MPDGCTRL1 */

ldr r2, =0x40363C3E
str r2, [r0, #0x848] /* MX6_MMDC_P0_MPRDDLCTL */
ldr r2, =0x3C3E3C46
str r2, [r1, #0x848] /* MX6_MMDC_P1_MPRDDLCTL */

ldr r2, =0x403E463E
str r2, [r0, #0x850] /* MX6_MMDC_P0_MPWRDLCTL */
ldr r2, =0x4A384C46
str r2, [r1, #0x850] /* MX6_MMDC_P1_MPWRDLCTL */

ldr r2, =0x0009000E
str r2, [r0, #0x80c] /* MX6_MMDC_P0_MPWLDECTRL0 */
ldr r2, =0x0018000B
str r2, [r0, #0x810] /* MX6_MMDC_P0_MPWLDECTRL1 */
ldr r2, =0x00060015
str r2, [r1, #0x80c] /* MX6_MMDC_P1_MPWLDECTRL0 */
ldr r2, =0x0006000E
str r2, [r1, #0x810] /* MX6_MMDC_P1_MPWLDECTRL1 */

ldr r2, =0x00000800
str r2, [r0, #0x8b8] /* MX6_MMDC_P0_MPMUR0 */
ldr r2, =0x00000800
str r2, [r1, #0x8b8] /* MX6_MMDC_P1_MPMUR0 */
ldr r2, =0x00000000
str r2, [r0, #0x01c] /* MX6_MMDC_P0_MDSCR */
ldr r2, =0x00011006
str r2, [r0, #0x404] /* MX6_MMDC_P0_MAPSR */

.endm

Hello Ingrid,

I have to check with the software team if someone can support there. I know that this can be done.

Best Regards,

Matthias Gohlke

Hi Matthias,

OK thank you for your answer.

Best Regards,
Ingrid

Hi Matthias,
when I read threads about the spread spectrum in the community, I wonder if it would make sense to enable it by default. As far as I know, it is a often useful. Do you know if having it enabled by default in the base images would have disadvantages, besides reducing EM peak emissions?
Thanks for your thoughts and best regards,
ldvp

Hello ldvp,

We are looking into this. it is on our to do list to make a how to manual.

Best Regards,

Matthias Gohlke

1 Like