diff options
author | Eric Nelson <eric@nelint.com> | 2017-12-11 13:52:11 -0200 |
---|---|---|
committer | Stefano Babic <sbabic@denx.de> | 2018-01-03 13:58:51 +0100 |
commit | baefb63a13d106458577704ca4586b3f414c9520 (patch) | |
tree | c2dc6a64124d1e7ff4e0d8ac90da7542e9f65e63 /board | |
parent | 1314bd1192b4c67d28bdae7eee639588e88090cd (diff) |
mx6: Add board mx6memcal for use in validating DDR
This is a virtual "board" that uses configuration files and
Kconfig to define the memory layout used by a real board during
the board bring-up process.
It generates an SPL image that can be loaded using imx_usb or
SB_LOADER.exe.
When run, it will generate a set of calibration constants for
use in either or both a DCD configuration file for boards that
use u-boot.imx or struct mx6_mmdc_calibration for boards that
boot via SPL.
In essence, it is a configurable, open-source variant of the
Freescale ddr-stress tool.
https://community.nxp.com/docs/DOC-105652
File mx6memcal_defconfig configures the board for use with
mx6sabresd or mx6qsabreauto.
Signed-off-by: Eric Nelson <eric@nelint.com>
Signed-off-by: Fabio Estevam <fabio.estevam@nxp.com>
Diffstat (limited to 'board')
-rw-r--r-- | board/freescale/mx6memcal/Kconfig | 235 | ||||
-rw-r--r-- | board/freescale/mx6memcal/MAINTAINERS | 7 | ||||
-rw-r--r-- | board/freescale/mx6memcal/Makefile | 13 | ||||
-rw-r--r-- | board/freescale/mx6memcal/README | 49 | ||||
-rw-r--r-- | board/freescale/mx6memcal/mx6memcal.c | 32 | ||||
-rw-r--r-- | board/freescale/mx6memcal/spl.c | 456 |
6 files changed, 792 insertions, 0 deletions
diff --git a/board/freescale/mx6memcal/Kconfig b/board/freescale/mx6memcal/Kconfig new file mode 100644 index 0000000000..443804dc11 --- /dev/null +++ b/board/freescale/mx6memcal/Kconfig @@ -0,0 +1,235 @@ +if TARGET_MX6MEMCAL + +config SYS_BOARD + default "mx6memcal" + +config SYS_VENDOR + default "freescale" + +config SYS_CONFIG_NAME + default "mx6memcal" + +menu "mx6memcal specifics" +choice + prompt "Serial console" + help + Either UART1 or UART2 will be used as the console for + displaying the calibration values or errors. + +config SERIAL_CONSOLE_UART1 + bool "UART1" + help + Select this if your board uses UART1 for its' console. + +config SERIAL_CONSOLE_UART2 + bool "UART2" + help + Select this if your board uses UART2 for its' console. + +endchoice + +choice + prompt "UART pads" + help + Select the RX and TX pads used for your serial console. + The choices below reflect the most commonly used options + for your UART. + + config UART2_EIM_D26_27 + bool "UART2 on EIM_D26/27 (SabreLite, Nitrogen6x)" + depends on SERIAL_CONSOLE_UART2 + help + Choose this configuration if you're using pads + EIM_D26 and D27 for a console on UART2. + This is typical for designs that are based on the + NXP SABRELite. + + config UART1_CSI0_DAT10_11 + bool "UART1 on CSI0_DAT10/11 (Wand)" + depends on SERIAL_CONSOLE_UART1 + help + Choose this configuration if you're using pads + CSI0_DAT10 and DAT11 for a console on UART1 as + is done on the i.MX6 Wand board. + + config UART1_SD3_DAT6_7 + bool "UART1 on SD3_DAT6/7 (SabreSD, SabreAuto)" + depends on SERIAL_CONSOLE_UART1 + help + Choose this configuration if you're using pads + SD3_DAT6 and DAT7 for a console on UART1 as is + done on the NXP SABRESD or SABREAUTO designs. + + config UART1_UART1 + bool "UART1 on UART1 (i.MX6SL EVK, WaRP)" + depends on SERIAL_CONSOLE_UART1 + help + Choose this configuration if you're using pads + UART1_TXD/RXD for a console on UART1 as is done + on most i.MX6SL designs. + +endchoice + +config IMXIMAGE_OUTPUT + bool "Include output for imximage .cfg files" + default y + help + Say "Y" if you want output formatted for use in non-SPL + (DCD-style) configuration files. + +config DDRWIDTH + int "DDR bus width" + default 64 + help + Select either 32 or 64 to reflect the DDR bus width. + +config DDRCS + int "DDR chip selects" + default 2 + range 1 2 + help + Select the number of chip selects used in your board design + +choice + prompt "Memory type" + help + Select the type of DDR (DDR3 or LPDDR2) used on your design + +config DDR3 + bool "DDR3" + help + Select this if your board design uses DDR3. + +config LPDDR2 + bool "LPDDR2" + help + Select this if your board design uses LPDDR2. + +endchoice + +choice + prompt "Memory device" + +config MT41K512M16TNA + bool "Micron MT41K512M16TNA 512Mx16 (1GiB/chip)" + depends on DDR3 + +config MT41K128M16JT + bool "Micron MT41K128M16JT 128Mx16 (256 MiB/chip)" + depends on DDR3 + +config H5TQ4G63AFR + bool "Hynix H5TQ4G63AFR 256Mx16 (512 MiB/chip)" + depends on DDR3 + +config H5TQ2G63DFR + bool "Hynix H5TQ2G63DFR 128Mx16 (256 MiB/chip)" + depends on DDR3 + +config MT42L256M32D2LG + bool "Micron MT42L256M32D2LG LPDDR2 256Mx32 (1GiB/chip)" + depends on LPDDR2 + +config MT29PZZZ4D4BKESK + bool "Micron MT29PZZZ4D4BKESK multi-chip 512MiB LPDDR2/4GiB eMMC" + depends on LPDDR2 + +endchoice + +config DDR_ODT + int "DDR On-die-termination" + default 2 + range 0 7 + help + Enter the on-die termination value as an index defined for + IOMUX settings for PAD_DRAM_SDCLK0_P and others. + 0 == Disabled + 1 == 120 Ohm + 2 == 60 Ohm + 3 == 40 Ohm + 4 == 30 Ohm + 5 == 24 Ohm + 6 == 20 Ohm + 7 == 17 Ohm + Value will be applied to all clock and data lines + + +config DRAM_DRIVE_STRENGTH + int "DRAM Drive strength" + default 6 + range 0 7 + help + Enter drive strength as an index defined for IOMUX settings + for GRP_B1DS and others. + 0 == Hi Z + 6 == 40 Ohm (default) + 7 == 34 Ohm + Value will be applied to all clock and data lines + +config RTT_NOM + int "RTT_NOM" + default 1 + range 1 2 + help + Enter the RTT_NOM selector + 1 == RZQ/4 (60ohm) + 2 == RZQ/2 (120ohm) + +config RTT_WR + int "RTT_WR" + default 1 + range 0 2 + help + Enter the RTT_WR selector for MR2 + 0 == Dynamic ODT disabled + 1 == RZQ/4 (60ohm) + 2 == RZQ/2 (120ohm) + +config RALAT + int "Read additional latency" + default 5 + range 0 7 + help + Enter a latency in number of cycles. This will be added to + CAS and internal delays for which the MMDC will retrieve the + read data from the internal FIFO. + This is used to compensate for board/chip delays. + +config WALAT + int "Write additional latency" + default 0 + range 0 7 + help + Enter a latency in number of cycles. This will be added to + CAS and internal delays for which the MMDC will retrieve the + read data from the internal FIFO + This is used to compensate for board/chip delays. + +config REFSEL + int "Refresh period" + range 0 3 + default 1 + help + Select the DDR refresh period. + See the description of bitfield REF_SEL in the reference manual + for details. + 0 == disabled + 1 == 32 kHz + 2 == 64 kHz + 3 == fast counter + +config REFR + int "Number of refreshes" + range 0 7 + default 7 + help + This selects the number of refreshes (-1) during each period. + i.e.: + 0 == 1 refresh (tRFC) + 7 == 8 refreshes (tRFC*8) + See the description of MDREF[REFR] in the reference manual for + details. + +endmenu +endif + diff --git a/board/freescale/mx6memcal/MAINTAINERS b/board/freescale/mx6memcal/MAINTAINERS new file mode 100644 index 0000000000..5da38f7109 --- /dev/null +++ b/board/freescale/mx6memcal/MAINTAINERS @@ -0,0 +1,7 @@ +MX6MEMCAL BOARD +M: Eric Nelson <eric@nelint.com> +S: Maintained +F: board/freescale/mx6memcal/ +F: include/configs/mx6memcal.h +F: configs/mx6memcal_defconfig + diff --git a/board/freescale/mx6memcal/Makefile b/board/freescale/mx6memcal/Makefile new file mode 100644 index 0000000000..2d7a6fa5d9 --- /dev/null +++ b/board/freescale/mx6memcal/Makefile @@ -0,0 +1,13 @@ +# +# Copyright (C) 2007, Guennadi Liakhovetski <lg@denx.de> +# +# (C) Copyright 2011 Freescale Semiconductor, Inc. +# +# SPDX-License-Identifier: GPL-2.0+ +# + +ifdef CONFIG_SPL_BUILD +obj-y := spl.o +else +obj-y := mx6memcal.o +endif diff --git a/board/freescale/mx6memcal/README b/board/freescale/mx6memcal/README new file mode 100644 index 0000000000..9fe2fe2d04 --- /dev/null +++ b/board/freescale/mx6memcal/README @@ -0,0 +1,49 @@ +mx6memcal - a tool for calibrating DDR on i.MX6 boards. + +The mx6memcal board isn't a real board, but a tool for use in bring-up of +new i.MX6 board designs. + +It provides a similar function to the tool from NXP([1]) with a number +of advantages: + +1. It's open-source, so it's easier to change if needed. + Typical reasons for needing to change include the use of alternate + UARTs and PMIC initialization. +2. It produces an image that's directly loadable with imx_usb [2] or + SB_LOADER.exe [3]. + The NXP tool requires either a cumbersome JTAG connection that + makes running the DDR very slow or a working U-Boot image that + suffers from a chicken-and-egg problem (i.e. where do you get the + DDR parameters for U-Boot?). +3. It doesn't prompt for parameters, so it's much faster to gather + data from multiple boards. +4. Parameters to the calibration process can be chosen through + 'make menuconfig'. + +When booted, the mx6memcal board will run the DDR calibration +routines and display the result in a form suitable for cut and +paste into struct mx6_mmdc_calibration. It can also optionally +produce output in a form usable in a DCD-style .cfg file. + +Selections in Kconfig allow most system design settings to be chosen: + +1. The UART number and pad configuration for the UART. Options + include support for the most frequent reference designs on + i.MX6DQ/SDL (SABRE Lite and SABRESD designs). +2. The memory bus width (64 and 32-bit) +3. The number of chip-selects in use +4. The type of DDR (DDR3 or LPDDR2). Note that LPDDR2 support + is incomplete as of this writing. +5. The type of DDR chips in use. This selection allows re-use of common + parts and four DDR3 and two LPDDR2 parts are currently defined +6. The On-die termination value for the DRAM lines +7. The DRAM drive strength +8. The RTT_NOM and RTT_WR termination settings +9. RALAT/WALAT latency values + +References: +[1] - NXP DDR Stress Test Tool - https://community.nxp.com/docs/DOC-105652 +[2] - Boundary Devices imx_usb_loader + https://github.com/boundarydevices/imx_usb_loader +[3] - Use of SB_Loader.exe + https://boundarydevices.com/windows-users-and-unbricking diff --git a/board/freescale/mx6memcal/mx6memcal.c b/board/freescale/mx6memcal/mx6memcal.c new file mode 100644 index 0000000000..afea0fbd9d --- /dev/null +++ b/board/freescale/mx6memcal/mx6memcal.c @@ -0,0 +1,32 @@ +/* + * mx6memcal board support - provides a minimal, UART-only + * U-Boot that's capable of running a memory test. + * + * Copyright (C) 2016 Nelson Integration, LLC + * Author: Eric Nelson <eric@nelint.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/arch/sys_proto.h> + +DECLARE_GLOBAL_DATA_PTR; + +int board_init(void) +{ + return 0; +} + +int checkboard(void) +{ + puts("Board: mx6memcal\n"); + return 0; +} + +int dram_init(void) +{ + gd->ram_size = imx_ddr_size(); + return 0; +} + diff --git a/board/freescale/mx6memcal/spl.c b/board/freescale/mx6memcal/spl.c new file mode 100644 index 0000000000..8ee89ff116 --- /dev/null +++ b/board/freescale/mx6memcal/spl.c @@ -0,0 +1,456 @@ +/* + * Copyright (C) 2016 Nelson Integration, LLC + * Author: Eric Nelson <eric@nelint.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/iomux.h> +#include <asm/arch/clock.h> +#include <asm/arch/crm_regs.h> +#include <asm/arch/mx6-ddr.h> +#include <asm/arch/mx6-pins.h> +#include <asm/arch/sys_proto.h> +#include <spl.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define UART_PAD_CTRL (PAD_CTL_PUS_100K_UP | \ + PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm | \ + PAD_CTL_SRE_FAST | PAD_CTL_HYS) + +static iomux_v3_cfg_t const uart_pads[] = { +#ifdef CONFIG_UART2_EIM_D26_27 + IOMUX_PADS(PAD_EIM_D26__UART2_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), + IOMUX_PADS(PAD_EIM_D27__UART2_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), +#elif defined(CONFIG_UART1_CSI0_DAT10_11) + IOMUX_PADS(PAD_CSI0_DAT10__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), + IOMUX_PADS(PAD_CSI0_DAT11__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), +#elif defined(CONFIG_UART1_SD3_DAT6_7) + IOMUX_PADS(PAD_SD3_DAT6__UART1_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), + IOMUX_PADS(PAD_SD3_DAT7__UART1_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)), +#elif defined(CONFIG_UART1_UART1) + MX6_PAD_UART1_TXD__UART1_TXD | MUX_PAD_CTRL(UART_PAD_CTRL), + MX6_PAD_UART1_RXD__UART1_RXD | MUX_PAD_CTRL(UART_PAD_CTRL), +#else +#error select UART console pads +#endif +}; + +#ifdef CONFIG_DDR3 +#define GRP_DDRTYPE 0x000C0000 +#else +#define GRP_DDRTYPE 0x00080000 +#endif + +/* all existing designs have this disabled */ +#define DDR_PKE 0 + +/* use Kconfig for ODT and DRIVE_STRENGTH */ +#define DDR_ODT \ + (CONFIG_DDR_ODT << 8) +#define DRAM_DRIVE_STRENGTH \ + (CONFIG_DRAM_DRIVE_STRENGTH << 3) + +/* configure MX6Q/DUAL mmdc DDR io registers */ +static struct mx6dq_iomux_ddr_regs const mx6dq_ddr_ioregs = { + /* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */ + .dram_sdclk_0 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_sdclk_1 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_cas = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_ras = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_reset = DDR_ODT + DRAM_DRIVE_STRENGTH, + /* SDCKE[0:1]: 100k pull-up */ + .dram_sdcke0 = 0x00003000, + .dram_sdcke1 = 0x00003000, + /* SDBA2: pull-up disabled */ + .dram_sdba2 = 0x00000000, + /* SDODT[0:1]: 100k pull-up, 40 ohm */ + .dram_sdodt0 = 0x00003000 + DRAM_DRIVE_STRENGTH, + .dram_sdodt1 = 0x00003000 + DRAM_DRIVE_STRENGTH, + /* SDQS[0:7]: Differential input, 40 ohm */ + .dram_sdqs0 = DRAM_DRIVE_STRENGTH, + .dram_sdqs1 = DRAM_DRIVE_STRENGTH, + .dram_sdqs2 = DRAM_DRIVE_STRENGTH, + .dram_sdqs3 = DRAM_DRIVE_STRENGTH, + .dram_sdqs4 = DRAM_DRIVE_STRENGTH, + .dram_sdqs5 = DRAM_DRIVE_STRENGTH, + .dram_sdqs6 = DRAM_DRIVE_STRENGTH, + .dram_sdqs7 = DRAM_DRIVE_STRENGTH, + + /* DQM[0:7]: Differential input, 40 ohm */ + .dram_dqm0 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm1 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm2 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm3 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm4 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm5 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm6 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm7 = DDR_ODT + DRAM_DRIVE_STRENGTH, +}; + +/* configure MX6Q/DUAL mmdc GRP io registers */ +static struct mx6dq_iomux_grp_regs const mx6dq_grp_ioregs = { + /* DDR3 */ + .grp_ddr_type = GRP_DDRTYPE, + .grp_ddrmode_ctl = DDR_ODT, + /* disable DDR pullups */ + .grp_ddrpke = DDR_PKE, + /* ADDR[00:16], SDBA[0:1]: 40 ohm */ + .grp_addds = DRAM_DRIVE_STRENGTH, + /* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */ + .grp_ctlds = DRAM_DRIVE_STRENGTH, + /* DATA[00:63]: Differential input, 40 ohm */ + .grp_ddrmode = DDR_ODT, + .grp_b0ds = DRAM_DRIVE_STRENGTH, + .grp_b1ds = DRAM_DRIVE_STRENGTH, + .grp_b2ds = DRAM_DRIVE_STRENGTH, + .grp_b3ds = DRAM_DRIVE_STRENGTH, + .grp_b4ds = DRAM_DRIVE_STRENGTH, + .grp_b5ds = DRAM_DRIVE_STRENGTH, + .grp_b6ds = DRAM_DRIVE_STRENGTH, + .grp_b7ds = DRAM_DRIVE_STRENGTH, +}; + +static struct mx6sdl_iomux_ddr_regs const mx6sdl_ddr_ioregs = { + /* SDCLK[0:1], CAS, RAS, Reset: Differential input, 40ohm */ + .dram_sdclk_0 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_sdclk_1 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_cas = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_ras = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_reset = DDR_ODT + DRAM_DRIVE_STRENGTH, + /* SDCKE[0:1]: 100k pull-up */ + .dram_sdcke0 = 0x00003000, + .dram_sdcke1 = 0x00003000, + /* SDBA2: pull-up disabled */ + .dram_sdba2 = 0x00000000, + /* SDODT[0:1]: 100k pull-up, 40 ohm */ + .dram_sdodt0 = 0x00003000 + DRAM_DRIVE_STRENGTH, + .dram_sdodt1 = 0x00003000 + DRAM_DRIVE_STRENGTH, + /* SDQS[0:7]: Differential input, 40 ohm */ + .dram_sdqs0 = DRAM_DRIVE_STRENGTH, + .dram_sdqs1 = DRAM_DRIVE_STRENGTH, + .dram_sdqs2 = DRAM_DRIVE_STRENGTH, + .dram_sdqs3 = DRAM_DRIVE_STRENGTH, + .dram_sdqs4 = DRAM_DRIVE_STRENGTH, + .dram_sdqs5 = DRAM_DRIVE_STRENGTH, + .dram_sdqs6 = DRAM_DRIVE_STRENGTH, + .dram_sdqs7 = DRAM_DRIVE_STRENGTH, + + /* DQM[0:7]: Differential input, 40 ohm */ + .dram_dqm0 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm1 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm2 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm3 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm4 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm5 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm6 = DDR_ODT + DRAM_DRIVE_STRENGTH, + .dram_dqm7 = DDR_ODT + DRAM_DRIVE_STRENGTH, +}; + +/* configure MX6SOLO/DUALLITE mmdc GRP io registers */ +static struct mx6sdl_iomux_grp_regs const mx6sdl_grp_ioregs = { + /* DDR3 */ + .grp_ddr_type = GRP_DDRTYPE, + /* SDQS[0:7]: Differential input, 40 ohm */ + .grp_ddrmode_ctl = DDR_ODT, + /* disable DDR pullups */ + .grp_ddrpke = DDR_PKE, + /* ADDR[00:16], SDBA[0:1]: 40 ohm */ + .grp_addds = DRAM_DRIVE_STRENGTH, + /* CS0/CS1/SDBA2/CKE0/CKE1/SDWE: 40 ohm */ + .grp_ctlds = DRAM_DRIVE_STRENGTH, + /* DATA[00:63]: Differential input, 40 ohm */ + .grp_ddrmode = DDR_ODT, + .grp_b0ds = DRAM_DRIVE_STRENGTH, + .grp_b1ds = DRAM_DRIVE_STRENGTH, + .grp_b2ds = DRAM_DRIVE_STRENGTH, + .grp_b3ds = DRAM_DRIVE_STRENGTH, + .grp_b4ds = DRAM_DRIVE_STRENGTH, + .grp_b5ds = DRAM_DRIVE_STRENGTH, + .grp_b6ds = DRAM_DRIVE_STRENGTH, + .grp_b7ds = DRAM_DRIVE_STRENGTH, +}; + +const struct mx6sl_iomux_ddr_regs mx6sl_ddr_ioregs = { + .dram_sdqs0 = DRAM_DRIVE_STRENGTH, + .dram_sdqs1 = DRAM_DRIVE_STRENGTH, + .dram_sdqs2 = DRAM_DRIVE_STRENGTH, + .dram_sdqs3 = DRAM_DRIVE_STRENGTH, + .dram_dqm0 = DRAM_DRIVE_STRENGTH, + .dram_dqm1 = DRAM_DRIVE_STRENGTH, + .dram_dqm2 = DRAM_DRIVE_STRENGTH, + .dram_dqm3 = DRAM_DRIVE_STRENGTH, + .dram_cas = DRAM_DRIVE_STRENGTH, + .dram_ras = DRAM_DRIVE_STRENGTH, + .dram_sdclk_0 = DRAM_DRIVE_STRENGTH, + .dram_reset = DRAM_DRIVE_STRENGTH, + .dram_sdba2 = 0x00020000, + .dram_odt0 = 0x00030000 + DRAM_DRIVE_STRENGTH, + .dram_odt1 = 0x00030000 + DRAM_DRIVE_STRENGTH, +}; + +const struct mx6sl_iomux_grp_regs mx6sl_grp_ioregs = { + .grp_b0ds = DRAM_DRIVE_STRENGTH, + .grp_b1ds = DRAM_DRIVE_STRENGTH, + .grp_b2ds = DRAM_DRIVE_STRENGTH, + .grp_b3ds = DRAM_DRIVE_STRENGTH, + .grp_addds = DRAM_DRIVE_STRENGTH, + .grp_ctlds = DRAM_DRIVE_STRENGTH, + .grp_ddrmode_ctl = DDR_ODT, + .grp_ddrpke = DDR_PKE, + .grp_ddrmode = DDR_ODT, + .grp_ddr_type = GRP_DDRTYPE, +}; + +static struct mx6_ddr_sysinfo const sysinfo = { + /* width of data bus:0=16,1=32,2=64 */ +#if CONFIG_DDRWIDTH == 32 + .dsize = 1, +#elif CONFIG_DDRWIDTH == 64 + .dsize = 2, +#else +#error missing CONFIG_DDRWIDTH +#endif + /* config for full 4GB range so that get_mem_size() works */ + .cs_density = 32, /* 32Gb per CS */ + + /* # of chip selects */ + .ncs = CONFIG_DDRCS, + .cs1_mirror = 0, + .bi_on = 1, /* Bank interleaving enabled */ + .rtt_nom = CONFIG_RTT_NOM, + .rtt_wr = CONFIG_RTT_WR, + .ralat = CONFIG_RALAT, /* Read additional latency */ + .walat = CONFIG_WALAT, /* Write additional latency */ + .mif3_mode = 3, /* Command prediction working mode */ +#ifdef CONFIG_DDR3 + .rst_to_cke = 0x23, /* 33 cycles, 500us (JEDEC default) */ + .sde_to_rst = 0x10, /* JEDEC value for LPDDR2 - 200us */ + .pd_fast_exit = 0, /* immaterial for calibration */ + .ddr_type = DDR_TYPE_DDR3, +#else + .rst_to_cke = 0x10, /* JEDEC value for LPDDR2: 200us */ + .sde_to_rst = 0, /* LPDDR2 does not need this field */ + .pd_fast_exit = 0, /* immaterial for calibration */ + .ddr_type = DDR_TYPE_LPDDR2, +#endif + .refsel = CONFIG_REFSEL, + .refr = CONFIG_REFR, +}; + +#ifdef CONFIG_MT41K512M16TNA +/* Micron MT41K512M16TNA-125 */ +static struct mx6_ddr3_cfg const ddrtype = { + .mem_speed = 1600, + .density = 8, + .width = 16, + .banks = 8, + .rowaddr = 15, + .coladdr = 10, + .pagesz = 1, + .trcd = 1375, + .trcmin = 5062, + .trasmin = 3750, +}; +#elif defined(CONFIG_MT41K128M16JT) +/* Micron MT41K128M16JT-125 */ +static struct mx6_ddr3_cfg const ddrtype = { + .mem_speed = 1600, + .density = 2, + .width = 16, + .banks = 8, + .rowaddr = 14, + .coladdr = 10, + .pagesz = 2, + .trcd = 1375, + .trcmin = 4875, + .trasmin = 3500, +}; +#elif defined(CONFIG_H5TQ4G63AFR) +/* Hynix H5TQ4G63AFR */ +static struct mx6_ddr3_cfg const ddrtype = { + .mem_speed = 1600, + .density = 4, + .width = 16, + .banks = 8, + .rowaddr = 15, + .coladdr = 10, + .pagesz = 2, + .trcd = 1375, + .trcmin = 4875, + .trasmin = 3500, +}; +#elif defined CONFIG_H5TQ2G63DFR +/* Hynix H5TQ2G63DFR */ +static struct mx6_ddr3_cfg const ddrtype = { + .mem_speed = 1333, + .density = 2, + .width = 16, + .banks = 8, + .rowaddr = 14, + .coladdr = 10, + .pagesz = 2, + .trcd = 1350, + .trcmin = 4950, + .trasmin = 3600, +}; +#elif defined(CONFIG_MT42L256M32D2LG) +/* Micron MT42L256M32D2LG */ +static struct mx6_lpddr2_cfg ddrtype = { + .mem_speed = 800, + .density = 4, + .width = 32, + .banks = 8, + .rowaddr = 14, + .coladdr = 10, + .trcd_lp = 2000, + .trppb_lp = 2000, + .trpab_lp = 2250, + .trasmin = 4200, +}; +#elif defined(CONFIG_MT29PZZZ4D4BKESK) +/* Micron MT29PZZZ4D4BKESK */ +static struct mx6_lpddr2_cfg ddrtype = { + .mem_speed = 800, + .density = 4, + .width = 32, + .banks = 8, + .rowaddr = 14, + .coladdr = 10, + .trcd_lp = 2000, + .trppb_lp = 2000, + .trpab_lp = 2250, + .trasmin = 4200, +}; +#else +#error please select DDR type using menuconfig +#endif + +static void ccgr_init(void) +{ + struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + + /* FIXME: these should probably be checked, especially + * for i.MX6SL, UL, ULL + */ + writel(0x00C03F3F, &ccm->CCGR0); + writel(0x0030FC03, &ccm->CCGR1); + writel(0x0FFFC000, &ccm->CCGR2); + writel(0x3FF00000, &ccm->CCGR3); + writel(0x00FFF300, &ccm->CCGR4); + writel(0x0F0000C3, &ccm->CCGR5); + writel(0x000003FF, &ccm->CCGR6); +} + +static void display_calibration(struct mx6_mmdc_calibration *calib) +{ + printf(".p0_mpdgctrl0\t= 0x%08X\n", calib->p0_mpdgctrl0); + printf(".p0_mpdgctrl1\t= 0x%08X\n", calib->p0_mpdgctrl1); + printf(".p0_mprddlctl\t= 0x%08X\n", calib->p0_mprddlctl); + printf(".p0_mpwrdlctl\t= 0x%08X\n", calib->p0_mpwrdlctl); + printf(".p0_mpwldectrl0\t= 0x%08X\n", calib->p0_mpwldectrl0); + printf(".p0_mpwldectrl1\t= 0x%08X\n", calib->p0_mpwldectrl1); + if (sysinfo.dsize == 2) { + printf(".p1_mpdgctrl0\t= 0x%08X\n", calib->p1_mpdgctrl0); + printf(".p1_mpdgctrl1\t= 0x%08X\n", calib->p1_mpdgctrl1); + printf(".p1_mprddlctl\t= 0x%08X\n", calib->p1_mprddlctl); + printf(".p1_mpwrdlctl\t= 0x%08X\n", calib->p1_mpwrdlctl); + printf(".p1_mpwldectrl0\t= 0x%08X\n", calib->p1_mpwldectrl0); + printf(".p1_mpwldectrl1\t= 0x%08X\n", calib->p1_mpwldectrl1); + } +#ifdef CONFIG_IMXIMAGE_OUTPUT + printf("DATA 4 MX6_MMDC_P0_MPDGCTRL0\t= 0x%08X\n", calib->p0_mpdgctrl0); + printf("DATA 4 MX6_MMDC_P0_MPDGCTRL1\t= 0x%08X\n", calib->p0_mpdgctrl1); + printf("DATA 4 MX6_MMDC_P0_MPRDDLCTL\t= 0x%08X\n", calib->p0_mprddlctl); + printf("DATA 4 MX6_MMDC_P0_MPWRDLCTL\t= 0x%08X\n", calib->p0_mpwrdlctl); + printf("DATA 4 MX6_MMDC_P0_MPWLDECTRL0\t= 0x%08X\n", + calib->p0_mpwldectrl0); + printf("DATA 4 MX6_MMDC_P0_MPWLDECTRL1\t= 0x%08X\n", + calib->p0_mpwldectrl1); + if (sysinfo.dsize == 2) { + printf("DATA 4 MX6_MMDC_P1_MPDGCTRL0\t= 0x%08X\n", + calib->p1_mpdgctrl0); + printf("DATA 4 MX6_MMDC_P1_MPDGCTRL1\t= 0x%08X\n", + calib->p1_mpdgctrl1); + printf("DATA 4 MX6_MMDC_P1_MPRDDLCTL\t= 0x%08X\n", + calib->p1_mprddlctl); + printf("DATA 4 MX6_MMDC_P1_MPWRDLCTL\t= 0x%08X\n", + calib->p1_mpwrdlctl); + printf("DATA 4 MX6_MMDC_P1_MPWLDECTRL0\t= 0x%08X\n", + calib->p1_mpwldectrl0); + printf("DATA 4 MX6_MMDC_P1_MPWLDECTRL1\t= 0x%08X\n", + calib->p1_mpwldectrl1); + } +#endif +} + +/* + * called from C runtime startup code (arch/arm/lib/crt0.S:_main) + * - we have a stack and a place to store GD, both in SRAM + * - no variable global data is available + */ +void board_init_f(ulong dummy) +{ + int errs; + struct mx6_mmdc_calibration calibration = {0}; + + memset((void *)gd, 0, sizeof(struct global_data)); + + /* write leveling calibration defaults */ + calibration.p0_mpwrdlctl = 0x40404040; + calibration.p1_mpwrdlctl = 0x40404040; + + /* setup AIPS and disable watchdog */ + arch_cpu_init(); + + ccgr_init(); + + SETUP_IOMUX_PADS(uart_pads); + + /* setup GP timer */ + timer_init(); + + /* UART clocks enabled and gd valid - init serial console */ + preloader_console_init(); + + if (sysinfo.dsize != 1) { + if (is_cpu_type(MXC_CPU_MX6SX) || + is_cpu_type(MXC_CPU_MX6UL) || + is_cpu_type(MXC_CPU_MX6SL)) { + printf("cpu type 0x%x doesn't support 64-bit bus\n", + get_cpu_type()); + reset_cpu(0); + } + } +#ifdef CONFIG_MX6SL + mx6sl_dram_iocfg(CONFIG_DDRWIDTH, &mx6sl_ddr_ioregs, + &mx6sl_grp_ioregs); +#else + if (is_cpu_type(MXC_CPU_MX6Q)) { + mx6dq_dram_iocfg(CONFIG_DDRWIDTH, &mx6dq_ddr_ioregs, + &mx6dq_grp_ioregs); + } else { + mx6sdl_dram_iocfg(CONFIG_DDRWIDTH, &mx6sdl_ddr_ioregs, + &mx6sdl_grp_ioregs); + } +#endif + mx6_dram_cfg(&sysinfo, &calibration, &ddrtype); + + errs = mmdc_do_write_level_calibration(&sysinfo); + if (errs) { + printf("error %d from write level calibration\n", errs); + } else { + errs = mmdc_do_dqs_calibration(&sysinfo); + if (errs) { + printf("error %d from write level calibration\n", errs); + } else { + printf("completed successfully\n"); + mmdc_read_calibration(&sysinfo, &calibration); + display_calibration(&calibration); + } + } + reset_cpu(0); +} |