From c17b07d4dc35fc9f8b424229ef4d1a3390f1dbe8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 1 Aug 2014 09:12:53 +0200 Subject: sunxi-common.h: Remove CONFIG_SYS_BOOT_GET_CMDLINE sunxi does not need this and it should never have been enabled for it in the first place. Signed-off-by: Hans de Goede Acked-by: Ian Campbell --- include/configs/sunxi-common.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 6a3044f9ce3..e3dc9c45da8 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -126,8 +126,6 @@ #define CONFIG_EXTRA_ENV_SETTINGS \ "bootm_size=0x10000000\0" -#define CONFIG_SYS_BOOT_GET_CMDLINE - #include #define CONFIG_FAT_WRITE /* enable write access */ -- cgit v1.2.3 From ad0fd965f7ac938923391667d2db5caa88d7bc6d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 1 Aug 2014 09:16:47 +0200 Subject: sunxi-common.h: Remove dead #ifdef CONFIG_CMD_NET code block We undef CONFIG_CMD_NET at line 167, and there is nothing re-defining it between line 167 and the #ifdef CONFIG_CMD_NET, so remove this effectively dead block. Signed-off-by: Hans de Goede Acked-by: Ian Campbell --- include/configs/sunxi-common.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index e3dc9c45da8..9d4801a67b4 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -205,14 +205,6 @@ #define CONFIG_PHYLIB #endif -#ifdef CONFIG_CMD_NET -#define CONFIG_CMD_NFS -#define CONFIG_CMD_DNS -#define CONFIG_NETCONSOLE -#define CONFIG_BOOTP_DNS2 -#define CONFIG_BOOTP_SEND_HOSTNAME -#endif - #ifdef CONFIG_USB_EHCI #define CONFIG_CMD_USB #define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1 -- cgit v1.2.3 From 85a4455c517b15e7f08700d3e1f2523ac64aae35 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 1 Aug 2014 09:18:20 +0200 Subject: sunxi-common.h: Don't undefine CONFIG_CMD_NFS I see no reason to override the choice to include this from config_cmd_defauls.h . Signed-off-by: Hans de Goede Acked-by: Ian Campbell --- include/configs/sunxi-common.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 9d4801a67b4..cbe8b403f25 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -168,7 +168,6 @@ #undef CONFIG_CMD_FPGA #undef CONFIG_CMD_NET -#undef CONFIG_CMD_NFS /* I2C */ #define CONFIG_SPL_I2C_SUPPORT -- cgit v1.2.3 From b9fb3b94cbb76884df4e8425abc2a95bb7aa6a56 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 1 Aug 2014 09:19:55 +0200 Subject: sunxi-common.h: Don't undef CONFIG_CMD_NET only to redefine it again later config_distro_defaults.h which is include later will redefine CONFIG_CMD_NET, drop the useless / meaningless undef of it. While at also move the undef of CONFIG_CMD_FPGA up to directly under the include of config_cmd_defaults.h, to make it clear that it overwrites the setting done from config_cmd_defaults.h . Signed-off-by: Hans de Goede Acked-by: Ian Campbell --- include/configs/sunxi-common.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index cbe8b403f25..4c712f35eae 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -127,6 +127,7 @@ "bootm_size=0x10000000\0" #include +#undef CONFIG_CMD_FPGA #define CONFIG_FAT_WRITE /* enable write access */ @@ -166,9 +167,6 @@ #define CONFIG_SYS_SPL_MALLOC_START 0x4ff00000 #define CONFIG_SYS_SPL_MALLOC_SIZE 0x00080000 /* 512 KiB */ -#undef CONFIG_CMD_FPGA -#undef CONFIG_CMD_NET - /* I2C */ #define CONFIG_SPL_I2C_SUPPORT #define CONFIG_SYS_I2C -- cgit v1.2.3 From 6ae66f2e892b61eda9199f5a3869b5c5c3f5544a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 1 Aug 2014 09:28:24 +0200 Subject: sunxi: Kconfig: move common settings into a shared code block SYS_CPU, SYS_BOARD and SYS_SOC are identical for all sunxi boards, move them to a shared code block. Signed-off-by: Hans de Goede Acked-by: Ian Campbell --- board/sunxi/Kconfig | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index b06b5e0548e..24cca4747b4 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -1,17 +1,5 @@ if TARGET_SUN4I -config SYS_CPU - string - default "armv7" - -config SYS_BOARD - string - default "sunxi" - -config SYS_SOC - string - default "sunxi" - config SYS_CONFIG_NAME string default "sun4i" @@ -20,25 +8,21 @@ endif if TARGET_SUN5I -config SYS_CPU +config SYS_CONFIG_NAME string - default "armv7" + default "sun5i" -config SYS_BOARD - string - default "sunxi" +endif -config SYS_SOC - string - default "sunxi" +if TARGET_SUN7I config SYS_CONFIG_NAME string - default "sun5i" + default "sun7i" endif -if TARGET_SUN7I +if TARGET_SUN4I || TARGET_SUN5I || TARGET_SUN7I config SYS_CPU string @@ -52,8 +36,4 @@ config SYS_SOC string default "sunxi" -config SYS_CONFIG_NAME - string - default "sun7i" - endif -- cgit v1.2.3 From 8cc96848f0a467922820895b6b2363b0c64163b5 Mon Sep 17 00:00:00 2001 From: Dennis Gilmore Date: Wed, 30 Jul 2014 16:37:14 -0600 Subject: config: introduce a generic $bootcmd This generic $bootcmd, and associated support macros, automatically searches a defined set of storage devices (or network protocols) for an extlinux configuration file or U-Boot boot script in various standardized locations. Distros that install such a boot config file/script in those standard locations will get easy-to-set-up booting on HW that enables this generic $bootcmd. Boards can define the set of devices from which boot is attempted, and the order in which they are attempted. Users may later customize this set/order by edting $boot_targets. Users may interrupt the boot process and boot from a specific device simply by executing e.g.: $ run bootcmd_mmc1 or: $ run bootcmd_pxe This patch was originally written by Dennis Gilmore based on Tegra and rpi_b boot scripts. I have made the following modifications since then: * Boards must define the BOOT_TARGET_DEVICES macro in order to specify the set of devices (and order) from which to attempt boot. If needed, we can define a default directly in config_distro_bootcmd.h. * Removed $env_import and related variables; nothing used them, and I think it's better for boards to pre-load an environment customization file using CONFIG_PREBOOT if they need. * Renamed a bunch of variables to suit my whims:-) Signed-off-by: Dennis Gilmore Signed-off-by: Stephen Warren Reviewed-by: Marek Vasut Acked-by: Simon Glass --- include/config_distro_bootcmd.h | 197 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 include/config_distro_bootcmd.h diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h new file mode 100644 index 00000000000..90d990157f6 --- /dev/null +++ b/include/config_distro_bootcmd.h @@ -0,0 +1,197 @@ +/* + * (C) Copyright 2014 + * NVIDIA Corporation + * + * Copyright 2014 Red Hat, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef _CONFIG_CMD_DISTRO_BOOTCMD_H +#define _CONFIG_CMD_DISTRO_BOOTCMD_H + +#define BOOTENV_SHARED_BLKDEV_BODY(devtypel) \ + "if " #devtypel " dev ${devnum}; then " \ + "setenv devtype " #devtypel "; " \ + "run scan_dev_for_boot; " \ + "fi\0" + +#define BOOTENV_SHARED_BLKDEV(devtypel) \ + #devtypel "_boot=" \ + BOOTENV_SHARED_BLKDEV_BODY(devtypel) + +#define BOOTENV_DEV_BLKDEV(devtypeu, devtypel, instance) \ + "bootcmd_" #devtypel #instance "=" \ + "setenv devnum " #instance "; " \ + "run " #devtypel "_boot\0" + +#define BOOTENV_DEV_NAME_BLKDEV(devtypeu, devtypel, instance) \ + #devtypel #instance " " + +#ifdef CONFIG_CMD_MMC +#define BOOTENV_SHARED_MMC BOOTENV_SHARED_BLKDEV(mmc) +#define BOOTENV_DEV_MMC BOOTENV_DEV_BLKDEV +#define BOOTENV_DEV_NAME_MMC BOOTENV_DEV_NAME_BLKDEV +#else +#define BOOTENV_SHARED_MMC +#define BOOTENV_DEV_MMC \ + BOOT_TARGET_DEVICES_references_MMC_without_CONFIG_CMD_MMC +#define BOOTENV_DEV_NAME_MMC \ + BOOT_TARGET_DEVICES_references_MMC_without_CONFIG_CMD_MMC +#endif + +#ifdef CONFIG_CMD_SATA +#define BOOTENV_SHARED_SATA BOOTENV_SHARED_BLKDEV(sata) +#define BOOTENV_DEV_SATA BOOTENV_DEV_BLKDEV +#define BOOTENV_DEV_NAME_SATA BOOTENV_DEV_NAME_BLKDEV +#else +#define BOOTENV_SHARED_SATA +#define BOOTENV_DEV_SATA \ + BOOT_TARGET_DEVICES_references_SATA_without_CONFIG_CMD_SATA +#define BOOTENV_DEV_NAME_SATA \ + BOOT_TARGET_DEVICES_references_SATA_without_CONFIG_CMD_SATA +#endif + +#ifdef CONFIG_CMD_SCSI +#define BOOTENV_SHARED_SCSI BOOTENV_SHARED_BLKDEV(scsi) +#define BOOTENV_DEV_SCSI BOOTENV_DEV_BLKDEV +#define BOOTENV_DEV_NAME_SCSI BOOTENV_DEV_NAME_BLKDEV +#else +#define BOOTENV_SHARED_SCSI +#define BOOTENV_DEV_SCSI \ + BOOT_TARGET_DEVICES_references_SCSI_without_CONFIG_CMD_SCSI +#define BOOTENV_DEV_NAME_SCSI \ + BOOT_TARGET_DEVICES_references_SCSI_without_CONFIG_CMD_SCSI +#endif + +#ifdef CONFIG_CMD_IDE +#define BOOTENV_SHARED_IDE BOOTENV_SHARED_BLKDEV(ide) +#define BOOTENV_DEV_IDE BOOTENV_DEV_BLKDEV +#define BOOTENV_DEV_NAME_IDE BOOTENV_DEV_NAME_BLKDEV +#else +#define BOOTENV_SHARED_IDE +#define BOOTENV_DEV_IDE \ + BOOT_TARGET_DEVICES_references_IDE_without_CONFIG_CMD_IDE +#define BOOTENV_DEV_NAME_IDE \ + BOOT_TARGET_DEVICES_references_IDE_without_CONFIG_CMD_IDE +#endif + +#ifdef CONFIG_CMD_USB +#define BOOTENV_RUN_USB_INIT "run usb_init; " +#define BOOTENV_SET_USB_NEED_INIT "setenv usb_need_init; " +#define BOOTENV_SHARED_USB \ + "usb_init=" \ + "if ${usb_need_init}; then " \ + "setenv usb_need_init false; " \ + "usb start 0; " \ + "fi\0" \ + \ + "usb_boot=" \ + BOOTENV_RUN_USB_INIT \ + BOOTENV_SHARED_BLKDEV_BODY(usb) +#define BOOTENV_DEV_USB BOOTENV_DEV_BLKDEV +#define BOOTENV_DEV_NAME_USB BOOTENV_DEV_NAME_BLKDEV +#else +#define BOOTENV_RUN_USB_INIT +#define BOOTENV_SET_USB_NEED_INIT +#define BOOTENV_SHARED_USB +#define BOOTENV_DEV_USB \ + BOOT_TARGET_DEVICES_references_USB_without_CONFIG_CMD_USB +#define BOOTENV_DEV_NAME_USB \ + BOOT_TARGET_DEVICES_references_USB_without_CONFIG_CMD_USB +#endif + +#if defined(CONFIG_CMD_DHCP) +#define BOOTENV_DEV_DHCP(devtypeu, devtypel, instance) \ + "bootcmd_dhcp=" \ + BOOTENV_RUN_USB_INIT \ + "if dhcp ${scriptaddr} boot.scr.uimg; then " \ + "source ${scriptaddr}; " \ + "fi\0" +#define BOOTENV_DEV_NAME_DHCP(devtypeu, devtypel, instance) \ + "dhcp " +#else +#define BOOTENV_DEV_DHCP \ + BOOT_TARGET_DEVICES_references_DHCP_without_CONFIG_CMD_DHCP +#define BOOTENV_DEV_NAME_DHCP \ + BOOT_TARGET_DEVICES_references_DHCP_without_CONFIG_CMD_DHCP +#endif + +#if defined(CONFIG_CMD_DHCP) && defined(CONFIG_CMD_PXE) +#define BOOTENV_DEV_PXE(devtypeu, devtypel, instance) \ + "bootcmd_pxe=" \ + BOOTENV_RUN_USB_INIT \ + "dhcp; " \ + "if pxe get; then " \ + "pxe boot; " \ + "fi\0" +#define BOOTENV_DEV_NAME_PXE(devtypeu, devtypel, instance) \ + "pxe " +#else +#define BOOTENV_DEV_PXE \ + BOOT_TARGET_DEVICES_references_PXE_without_CONFIG_CMD_DHCP_or_PXE +#define BOOTENV_DEV_NAME_PXE \ + BOOT_TARGET_DEVICES_references_PXE_without_CONFIG_CMD_DHCP_or_PXE +#endif + +#define BOOTENV_DEV_NAME(devtypeu, devtypel, instance) \ + BOOTENV_DEV_NAME_##devtypeu(devtypeu, devtypel, instance) +#define BOOTENV_BOOT_TARGETS \ + "boot_targets=" BOOT_TARGET_DEVICES(BOOTENV_DEV_NAME) "\0" + +#define BOOTENV_DEV(devtypeu, devtypel, instance) \ + BOOTENV_DEV_##devtypeu(devtypeu, devtypel, instance) +#define BOOTENV \ + BOOTENV_SHARED_MMC \ + BOOTENV_SHARED_USB \ + BOOTENV_SHARED_SATA \ + BOOTENV_SHARED_SCSI \ + BOOTENV_SHARED_IDE \ + "boot_prefixes=/ /boot/\0" \ + "boot_scripts=boot.scr.uimg boot.scr\0" \ + BOOTENV_BOOT_TARGETS \ + "bootpart=1\0" \ + \ + "boot_extlinux=" \ + "sysboot ${devtype} ${devnum}:${bootpart} any " \ + "${scriptaddr} ${prefix}extlinux/extlinux.conf\0" \ + \ + "scan_dev_for_extlinux=" \ + "if test -e ${devtype} ${devnum}:${bootpart} " \ + "${prefix}extlinux/extlinux.conf; then " \ + "echo Found ${prefix}extlinux/extlinux.conf; " \ + "run boot_extlinux; " \ + "echo SCRIPT FAILED: continuing...; " \ + "fi\0" \ + \ + "boot_a_script=" \ + "load ${devtype} ${devnum}:${bootpart} " \ + "${scriptaddr} ${prefix}${script}; " \ + "source ${scriptaddr}\0" \ + \ + "scan_dev_for_scripts=" \ + "for script in ${boot_scripts}; do " \ + "if test -e ${devtype} ${devnum}:${bootpart} " \ + "${prefix}${script}; then " \ + "echo Found U-Boot script " \ + "${prefix}${script}; " \ + "run boot_a_script; " \ + "echo SCRIPT FAILED: continuing...; " \ + "fi; " \ + "done\0" \ + \ + "scan_dev_for_boot=" \ + "echo Scanning ${devtype} ${devnum}...; " \ + "for prefix in ${boot_prefixes}; do " \ + "run scan_dev_for_extlinux; " \ + "run scan_dev_for_scripts; " \ + "done\0" \ + \ + BOOT_TARGET_DEVICES(BOOTENV_DEV) \ + \ + "bootcmd=" BOOTENV_SET_USB_NEED_INIT \ + "for target in ${boot_targets}; do " \ + "run bootcmd_${target}; " \ + "done\0" + +#endif /* _CONFIG_CMD_DISTRO_BOOTCMD_H */ -- cgit v1.2.3 From 2ec3a612f440364fa0ed250f22e7d3c3a8d72b92 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 31 Jul 2014 23:04:45 +0200 Subject: sunxi-common.h: Use new generic $bootcmd Use the new standard bootcmd from . Signed-off-by: Hans de Goede Acked-by: Stephen Warren --- include/configs/sunxi-common.h | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 4c712f35eae..9bfc4eede31 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -123,9 +123,6 @@ #define CONFIG_ENV_OFFSET (544 << 10) /* (8 + 24 + 512) KiB */ #define CONFIG_ENV_SIZE (128 << 10) /* 128 KiB */ -#define CONFIG_EXTRA_ENV_SETTINGS \ - "bootm_size=0x10000000\0" - #include #undef CONFIG_CMD_FPGA @@ -219,6 +216,28 @@ #ifndef CONFIG_SPL_BUILD #include + +#ifdef CONFIG_AHCI +#define BOOT_TARGET_DEVICES_SCSI(func) func(SCSI, scsi, 0) +#else +#define BOOT_TARGET_DEVICES_SCSI(func) +#endif + +#define BOOT_TARGET_DEVICES(func) \ + func(MMC, mmc, 0) \ + BOOT_TARGET_DEVICES_SCSI(func) \ + func(USB, usb, 0) \ + func(PXE, pxe, na) \ + func(DHCP, dhcp, na) + +#include + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "bootm_size=0x10000000\0" \ + BOOTENV + +#else /* ifndef CONFIG_SPL_BUILD */ +#define CONFIG_EXTRA_ENV_SETTINGS #endif #endif /* _SUNXI_COMMON_CONFIG_H */ -- cgit v1.2.3 From 846e325448ed591c4a5e8db55e2817b0ca013b0b Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 1 Aug 2014 09:37:58 +0200 Subject: sunxi: Add environment settings to make extlinux.conf booting work Automatic booting using an extlinux.conf file requires various environment variables to be set. Also modify CONFIG_SYS_LOAD_ADDR and CONFIG_STANDALONE_LOAD_ADDR to match the value chosen for kernel_addr_r, see the added comment for why the new value is chosen. Signed-off-by: Hans de Goede Acked-by: Stephen Warren --- board/sunxi/Kconfig | 3 +++ configs/A10-OLinuXino-Lime_defconfig | 1 + configs/A10s-OLinuXino-M_defconfig | 1 + configs/A13-OLinuXinoM_defconfig | 1 + configs/A13-OLinuXino_defconfig | 1 + configs/A20-OLinuXino_MICRO_defconfig | 1 + configs/Auxtek-T004_defconfig | 1 + configs/Bananapi_defconfig | 1 + configs/Cubieboard2_FEL_defconfig | 1 + configs/Cubieboard2_defconfig | 1 + configs/Cubieboard_defconfig | 1 + configs/Cubietruck_FEL_defconfig | 1 + configs/Cubietruck_defconfig | 1 + configs/Linksprite_pcDuino3_defconfig | 1 + configs/Mele_A1000G_defconfig | 1 + configs/Mele_A1000_defconfig | 1 + configs/Mini-X-1Gb_defconfig | 1 + configs/Mini-X_defconfig | 1 + configs/ba10_tv_box_defconfig | 1 + configs/i12-tvbox_defconfig | 1 + configs/qt840a_defconfig | 1 + configs/r7-tv-dongle_defconfig | 1 + include/configs/sunxi-common.h | 18 +++++++++++++++--- 23 files changed, 39 insertions(+), 3 deletions(-) diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig index 24cca4747b4..c61c650735b 100644 --- a/board/sunxi/Kconfig +++ b/board/sunxi/Kconfig @@ -36,4 +36,7 @@ config SYS_SOC string default "sunxi" +config FTDFILE + string "Default ftdfile env setting for this board" + endif diff --git a/configs/A10-OLinuXino-Lime_defconfig b/configs/A10-OLinuXino-Lime_defconfig index a4149537fc8..b93ae7d52fb 100644 --- a/configs/A10-OLinuXino-Lime_defconfig +++ b/configs/A10-OLinuXino-Lime_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="A10_OLINUXINO_L,SPL,AXP209_POWER,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPC(3),USB_EHCI" +CONFIG_FTDFILE="sun4i-a10-olinuxino-lime.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN4I=y diff --git a/configs/A10s-OLinuXino-M_defconfig b/configs/A10s-OLinuXino-M_defconfig index 1560ab18ec0..f2069704179 100644 --- a/configs/A10s-OLinuXino-M_defconfig +++ b/configs/A10s-OLinuXino-M_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="A10S_OLINUXINO_M,SPL,AXP152_POWER,SUNXI_EMAC,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPB(10)" +CONFIG_FTDFILE="sun5i-a10s-olinuxino-micro.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN5I=y diff --git a/configs/A13-OLinuXinoM_defconfig b/configs/A13-OLinuXinoM_defconfig index fb510d5cca1..8529dbe1416 100644 --- a/configs/A13-OLinuXinoM_defconfig +++ b/configs/A13-OLinuXinoM_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="A13_OLINUXINOM,SPL,CONS_INDEX=2,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(11)" +CONFIG_FTDFILE="sun5i-a13-olinuxino-micro.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN5I=y diff --git a/configs/A13-OLinuXino_defconfig b/configs/A13-OLinuXino_defconfig index ba21136dc90..c3a12cc17df 100644 --- a/configs/A13-OLinuXino_defconfig +++ b/configs/A13-OLinuXino_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="A13_OLINUXINO,SPL,CONS_INDEX=2,AXP209_POWER,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(11)" +CONFIG_FTDFILE="sun5i-a13-olinuxino.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN5I=y diff --git a/configs/A20-OLinuXino_MICRO_defconfig b/configs/A20-OLinuXino_MICRO_defconfig index 52a857a7704..c91319d551d 100644 --- a/configs/A20-OLinuXino_MICRO_defconfig +++ b/configs/A20-OLinuXino_MICRO_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="A20_OLINUXINO_M,SPL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI" +CONFIG_FTDFILE="sun7i-a20-olinuxino-micro.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN7I=y diff --git a/configs/Auxtek-T004_defconfig b/configs/Auxtek-T004_defconfig index 643e628f551..193019c926a 100644 --- a/configs/Auxtek-T004_defconfig +++ b/configs/Auxtek-T004_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="AUXTEK_T004,SPL,AXP152_POWER,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(13)" +CONFIG_FTDFILE="sun5i-a10s-auxtek-t004.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN5I=y diff --git a/configs/Bananapi_defconfig b/configs/Bananapi_defconfig index be3d815568b..dc68469e08d 100644 --- a/configs/Bananapi_defconfig +++ b/configs/Bananapi_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="BANANAPI,SPL,AXP209_POWER,SUNXI_GMAC,RGMII,MACPWR=SUNXI_GPH(23),AHCI,USB_EHCI" +CONFIG_FTDFILE="sun7i-a20-bananapi.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN7I=y diff --git a/configs/Cubieboard2_FEL_defconfig b/configs/Cubieboard2_FEL_defconfig index 63636b029ae..ae5e25a561a 100644 --- a/configs/Cubieboard2_FEL_defconfig +++ b/configs/Cubieboard2_FEL_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL_FEL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI" +CONFIG_FTDFILE="sun7i-a20-cubieboard2.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN7I=y diff --git a/configs/Cubieboard2_defconfig b/configs/Cubieboard2_defconfig index fa34c5178af..df87edc911f 100644 --- a/configs/Cubieboard2_defconfig +++ b/configs/Cubieboard2_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD2,SPL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI" +CONFIG_FTDFILE="sun7i-a20-cubieboard2.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN7I=y diff --git a/configs/Cubieboard_defconfig b/configs/Cubieboard_defconfig index 774029c8b03..57bf045050a 100644 --- a/configs/Cubieboard_defconfig +++ b/configs/Cubieboard_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="CUBIEBOARD,SPL,AXP209_POWER,SUNXI_EMAC,AHCI,SATAPWR=SUNXI_GPB(8),USB_EHCI" +CONFIG_FTDFILE="sun4i-a10-cubieboard.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN4I=y diff --git a/configs/Cubietruck_FEL_defconfig b/configs/Cubietruck_FEL_defconfig index 7ebf6353ee0..790125a344e 100644 --- a/configs/Cubietruck_FEL_defconfig +++ b/configs/Cubietruck_FEL_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL_FEL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12),USB_EHCI" +CONFIG_FTDFILE="sun7i-a20-cubietruck.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN7I=y diff --git a/configs/Cubietruck_defconfig b/configs/Cubietruck_defconfig index fbc912745ff..4ad82e3cee2 100644 --- a/configs/Cubietruck_defconfig +++ b/configs/Cubietruck_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="CUBIETRUCK,SPL,AXP209_POWER,SUNXI_GMAC,RGMII,AHCI,SATAPWR=SUNXI_GPH(12),USB_EHCI" +CONFIG_FTDFILE="sun7i-a20-cubietruck.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN7I=y diff --git a/configs/Linksprite_pcDuino3_defconfig b/configs/Linksprite_pcDuino3_defconfig index 10ebcefdfdf..22d0446387f 100644 --- a/configs/Linksprite_pcDuino3_defconfig +++ b/configs/Linksprite_pcDuino3_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="PCDUINO3,SPL,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPH(2),USB_EHCI" +CONFIG_FTDFILE="sun7i-a20-pcduino3.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN7I=y diff --git a/configs/Mele_A1000G_defconfig b/configs/Mele_A1000G_defconfig index 20792798b85..fa47faea4ae 100644 --- a/configs/Mele_A1000G_defconfig +++ b/configs/Mele_A1000G_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="MELE_A1000G,SPL,AXP209_POWER,SUNXI_EMAC,MACPWR=SUNXI_GPH(15),AHCI,USB_EHCI" +CONFIG_FTDFILE="sun4i-a10-a1000.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN4I=y diff --git a/configs/Mele_A1000_defconfig b/configs/Mele_A1000_defconfig index 13528abeb3f..d7c156d30d9 100644 --- a/configs/Mele_A1000_defconfig +++ b/configs/Mele_A1000_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="MELE_A1000,SPL,AXP209_POWER,SUNXI_EMAC,MACPWR=SUNXI_GPH(15),AHCI,USB_EHCI" +CONFIG_FTDFILE="sun4i-a10-a1000.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN4I=y diff --git a/configs/Mini-X-1Gb_defconfig b/configs/Mini-X-1Gb_defconfig index 61fa1de1554..af0b8003bae 100644 --- a/configs/Mini-X-1Gb_defconfig +++ b/configs/Mini-X-1Gb_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="MINI_X_1GB,SPL,AXP209_POWER,USB_EHCI" +CONFIG_FTDFILE="sun4i-a10-mini-xplus.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN4I=y diff --git a/configs/Mini-X_defconfig b/configs/Mini-X_defconfig index ceb02c5cd06..ea0c786c654 100644 --- a/configs/Mini-X_defconfig +++ b/configs/Mini-X_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="MINI_X,SPL,AXP209_POWER,USB_EHCI" +CONFIG_FTDFILE="sun4i-a10-mini-xplus.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN4I=y diff --git a/configs/ba10_tv_box_defconfig b/configs/ba10_tv_box_defconfig index 02a2538d799..c9961bda7fc 100644 --- a/configs/ba10_tv_box_defconfig +++ b/configs/ba10_tv_box_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="BA10_TV_BOX,SPL,AXP209_POWER,SUNXI_EMAC,USB_EHCI,SUNXI_USB_VBUS1_GPIO=SUNXI_GPH(12)" +CONFIG_FTDFILE="sun4i-a10-ba10-tvbox.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN4I=y diff --git a/configs/i12-tvbox_defconfig b/configs/i12-tvbox_defconfig index ff86841f9da..b2673127d0e 100644 --- a/configs/i12-tvbox_defconfig +++ b/configs/i12-tvbox_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="I12_TVBOX,SPL,AXP209_POWER,SUNXI_GMAC,MACPWR=SUNXI_GPH(21),USB_EHCI" +CONFIG_FTDFILE="sun7i-a20-i12-tvbox.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN7I=y diff --git a/configs/qt840a_defconfig b/configs/qt840a_defconfig index acb100c7189..73602124f88 100644 --- a/configs/qt840a_defconfig +++ b/configs/qt840a_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="QT840A,SPL,AXP209_POWER,SUNXI_GMAC,MACPWR=SUNXI_GPH(21),USB_EHCI" +CONFIG_FTDFILE="sun7i-a20-i12-tvbox.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN7I=y diff --git a/configs/r7-tv-dongle_defconfig b/configs/r7-tv-dongle_defconfig index f0f97b05619..35b66f0ff61 100644 --- a/configs/r7-tv-dongle_defconfig +++ b/configs/r7-tv-dongle_defconfig @@ -1,4 +1,5 @@ CONFIG_SPL=y CONFIG_SYS_EXTRA_OPTIONS="R7DONGLE,SPL,AXP152_POWER,USB_EHCI,SUNXI_USB_VBUS0_GPIO=SUNXI_GPG(13)" +CONFIG_FTDFILE="sun5i-a10s-r7-tv-dongle.dtb" +S:CONFIG_ARM=y +S:CONFIG_TARGET_SUN5I=y diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h index 9bfc4eede31..e7689213834 100644 --- a/include/configs/sunxi-common.h +++ b/include/configs/sunxi-common.h @@ -100,10 +100,10 @@ /* Boot Argument Buffer Size */ #define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE -#define CONFIG_SYS_LOAD_ADDR 0x48000000 /* default load address */ +#define CONFIG_SYS_LOAD_ADDR 0x42000000 /* default load address */ /* standalone support */ -#define CONFIG_STANDALONE_LOAD_ADDR 0x48000000 +#define CONFIG_STANDALONE_LOAD_ADDR 0x42000000 #define CONFIG_SYS_HZ 1000 @@ -217,6 +217,16 @@ #ifndef CONFIG_SPL_BUILD #include +/* 256M RAM (minimum), 32M uncompressed kernel, 16M compressed kernel, 1M fdt, + * 1M script, 1M pxe and the ramdisk at the end */ +#define MEM_LAYOUT_ENV_SETTINGS \ + "bootm_size=0x10000000\0" \ + "kernel_addr_r=0x42000000\0" \ + "fdt_addr_r=0x43000000\0" \ + "scriptaddr=0x43100000\0" \ + "pxefile_addr_r=0x43200000\0" \ + "ramdisk_addr_r=0x43300000\0" + #ifdef CONFIG_AHCI #define BOOT_TARGET_DEVICES_SCSI(func) func(SCSI, scsi, 0) #else @@ -233,7 +243,9 @@ #include #define CONFIG_EXTRA_ENV_SETTINGS \ - "bootm_size=0x10000000\0" \ + MEM_LAYOUT_ENV_SETTINGS \ + "fdtfile=" CONFIG_FTDFILE "\0" \ + "console=ttyS0,115200\0" \ BOOTENV #else /* ifndef CONFIG_SPL_BUILD */ -- cgit v1.2.3 From 34759d74a386ec82af946c2858935af9327a9f8a Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:39 +0300 Subject: sunxi: dram: Remove useless 'dramc_scan_dll_para()' function The attempt to do DRAM parameters calibration in 'dramc_scan_dll_para()' function by trying different DLL adjustments and using the hardware DQS gate training result as a feedback is a great source of inspiration, but it just can't work properly the way it is implemented now. The fatal problem of this implementation is that the DQS gating window can be successfully found for almost every DLL delay adjustment setup that gets tried. Thus making it unable to see any real difference between 'good' and 'bad' settings. Also this code was supposed to be only activated by setting the highest bit in the 'dram_tpr3' variable of the 'dram_para' struct (per-board dram configuration). But none of the linux-sunxi devices has ever used it for real. Basically, this code is just a dead weight. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 125 +--------------------------------------- 1 file changed, 1 insertion(+), 124 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 0f1ceecc1d4..236eed77111 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -321,117 +321,6 @@ static int dramc_scan_readpipe(void) return 0; } -static int dramc_scan_dll_para(void) -{ - struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; - const u32 dqs_dly[7] = {0x3, 0x2, 0x1, 0x0, 0xe, 0xd, 0xc}; - const u32 clk_dly[15] = {0x07, 0x06, 0x05, 0x04, 0x03, - 0x02, 0x01, 0x00, 0x08, 0x10, - 0x18, 0x20, 0x28, 0x30, 0x38}; - u32 clk_dqs_count[15]; - u32 dqs_i, clk_i, cr_i; - u32 max_val, min_val; - u32 dqs_index, clk_index; - - /* Find DQS_DLY Pass Count for every CLK_DLY */ - for (clk_i = 0; clk_i < 15; clk_i++) { - clk_dqs_count[clk_i] = 0; - clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, - (clk_dly[clk_i] & 0x3f) << 6); - for (dqs_i = 0; dqs_i < 7; dqs_i++) { - for (cr_i = 1; cr_i < 5; cr_i++) { - clrsetbits_le32(&dram->dllcr[cr_i], - 0x4f << 14, - (dqs_dly[dqs_i] & 0x4f) << 14); - } - udelay(2); - if (dramc_scan_readpipe() == 0) - clk_dqs_count[clk_i]++; - } - } - /* Test DQS_DLY Pass Count for every CLK_DLY from up to down */ - for (dqs_i = 15; dqs_i > 0; dqs_i--) { - max_val = 15; - min_val = 15; - for (clk_i = 0; clk_i < 15; clk_i++) { - if (clk_dqs_count[clk_i] == dqs_i) { - max_val = clk_i; - if (min_val == 15) - min_val = clk_i; - } - } - if (max_val < 15) - break; - } - - /* Check if Find a CLK_DLY failed */ - if (!dqs_i) - goto fail; - - /* Find the middle index of CLK_DLY */ - clk_index = (max_val + min_val) >> 1; - if ((max_val == (15 - 1)) && (min_val > 0)) - /* if CLK_DLY[MCTL_CLK_DLY_COUNT] is very good, then the middle - * value can be more close to the max_val - */ - clk_index = (15 + clk_index) >> 1; - else if ((max_val < (15 - 1)) && (min_val == 0)) - /* if CLK_DLY[0] is very good, then the middle value can be more - * close to the min_val - */ - clk_index >>= 1; - if (clk_dqs_count[clk_index] < dqs_i) - clk_index = min_val; - - /* Find the middle index of DQS_DLY for the CLK_DLY got above, and Scan - * read pipe again - */ - clrsetbits_le32(&dram->dllcr[0], 0x3f << 6, - (clk_dly[clk_index] & 0x3f) << 6); - max_val = 7; - min_val = 7; - for (dqs_i = 0; dqs_i < 7; dqs_i++) { - clk_dqs_count[dqs_i] = 0; - for (cr_i = 1; cr_i < 5; cr_i++) { - clrsetbits_le32(&dram->dllcr[cr_i], - 0x4f << 14, - (dqs_dly[dqs_i] & 0x4f) << 14); - } - udelay(2); - if (dramc_scan_readpipe() == 0) { - clk_dqs_count[dqs_i] = 1; - max_val = dqs_i; - if (min_val == 7) - min_val = dqs_i; - } - } - - if (max_val < 7) { - dqs_index = (max_val + min_val) >> 1; - if ((max_val == (7-1)) && (min_val > 0)) - dqs_index = (7 + dqs_index) >> 1; - else if ((max_val < (7-1)) && (min_val == 0)) - dqs_index >>= 1; - if (!clk_dqs_count[dqs_index]) - dqs_index = min_val; - for (cr_i = 1; cr_i < 5; cr_i++) { - clrsetbits_le32(&dram->dllcr[cr_i], - 0x4f << 14, - (dqs_dly[dqs_index] & 0x4f) << 14); - } - udelay(2); - return dramc_scan_readpipe(); - } - -fail: - clrbits_le32(&dram->dllcr[0], 0x3f << 6); - for (cr_i = 1; cr_i < 5; cr_i++) - clrbits_le32(&dram->dllcr[cr_i], 0x4f << 14); - udelay(2); - - return dramc_scan_readpipe(); -} - static void dramc_clock_output_en(u32 on) { #if defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I) @@ -665,19 +554,7 @@ unsigned long dramc_init(struct dram_para *para) /* scan read pipe value */ mctl_itm_enable(); - if (para->tpr3 & (0x1 << 31)) { - ret_val = dramc_scan_dll_para(); - if (ret_val == 0) - para->tpr3 = - (((readl(&dram->dllcr[0]) >> 6) & 0x3f) << 16) | - (((readl(&dram->dllcr[1]) >> 14) & 0xf) << 0) | - (((readl(&dram->dllcr[2]) >> 14) & 0xf) << 4) | - (((readl(&dram->dllcr[3]) >> 14) & 0xf) << 8) | - (((readl(&dram->dllcr[4]) >> 14) & 0xf) << 12 - ); - } else { - ret_val = dramc_scan_readpipe(); - } + ret_val = dramc_scan_readpipe(); if (ret_val < 0) return 0; -- cgit v1.2.3 From f2577967738f923571b7156ad46ef91d9fa8d9f8 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:40 +0300 Subject: sunxi: dram: Remove broken super-standby remnants If the dram->ppwrsctl (SDR_DPCR) register has the lowest bit set to 1, this means that DRAM is currently in self-refresh mode and retaining the old data. Since we have no idea what to do in this situation yet, just set this register to 0 and initialize DRAM in the same way as on any normal reboot (discarding whatever was stored there). This part of code was apparently used by the Allwinner boot0 bootloader to handle resume from the so-called super-standby mode. But this particular code got somehow mangled on the way from the boot0 bootloader to the u-boot-sunxi bootloader and has no chance of doing anything even remotely sane. For example: 1. in the original boot0 code we had "mctl_write_w(SDR_DPCR, 0x16510000)" (write to the register) and in the u-boot it now looks like "setbits_le32(&dram->ppwrsctl, 0x16510000)" (set bits in the register) 2. in the original boot0 code it was issuing three commands "0x12, 0x17, 0x13" (Self-Refresh entry, Self-Refresh exit, Refresh), but in the u-boot they have become "0x12, 0x12, 0x13" (Self-Refresh entry, Self-Refresh entry, Refresh) Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 66 +++++++++++++---------------------------- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 236eed77111..dc79d1c8ba3 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -359,6 +359,24 @@ static void dramc_set_autorefresh_cycle(u32 clk, u32 type, u32 density) writel(DRAM_DRR_TREFI(tREFI) | DRAM_DRR_TRFC(tRFC), &dram->drr); } +/* + * If the dram->ppwrsctl (SDR_DPCR) register has the lowest bit set to 1, this + * means that DRAM is currently in self-refresh mode and retaining the old + * data. Since we have no idea what to do in this situation yet, just set this + * register to 0 and initialize DRAM in the same way as on any normal reboot + * (discarding whatever was stored there). + * + * Note: on sun7i hardware, the highest 16 bits need to be set to 0x1651 magic + * value for this write operation to have any effect. On sun5i hadware this + * magic value is not necessary. And on sun4i hardware the writes to this + * register seem to have no effect at all. + */ +static void mctl_disable_power_save(void) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + writel(0x16510000, &dram->ppwrsctl); +} + unsigned long dramc_init(struct dram_para *para) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; @@ -373,10 +391,8 @@ unsigned long dramc_init(struct dram_para *para) /* setup DRAM relative clock */ mctl_setup_dram_clock(para->clock); -#ifdef CONFIG_SUN5I /* Disable any pad power save control */ - writel(0, &dram->ppwrsctl); -#endif + mctl_disable_power_save(); /* reset external DRAM */ #ifndef CONFIG_SUN7I @@ -444,10 +460,7 @@ unsigned long dramc_init(struct dram_para *para) #endif #ifdef CONFIG_SUN7I - if ((readl(&dram->ppwrsctl) & 0x1) != 0x1) - mctl_ddr3_reset(); - else - setbits_le32(&dram->mcr, DRAM_MCR_RESET); + mctl_ddr3_reset(); #else /* dram clock on */ dramc_clock_output_en(1); @@ -513,45 +526,6 @@ unsigned long dramc_init(struct dram_para *para) setbits_le32(&dram->ccr, DRAM_CCR_INIT); await_completion(&dram->ccr, DRAM_CCR_INIT); -#ifdef CONFIG_SUN7I - /* setup zq calibration manual */ - reg_val = readl(&dram->ppwrsctl); - if ((reg_val & 0x1) == 1) { - /* super_standby_flag = 1 */ - - reg_val = readl(0x01c20c00 + 0x120); /* rtc */ - reg_val &= 0x000fffff; - reg_val |= 0x17b00000; - writel(reg_val, &dram->zqcr0); - - /* exit self-refresh state */ - clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x12 << 27); - /* check whether command has been executed */ - await_completion(&dram->dcr, 0x1 << 31); - - udelay(2); - - /* dram pad hold off */ - setbits_le32(&dram->ppwrsctl, 0x16510000); - - await_completion(&dram->ppwrsctl, 0x1); - - /* exit self-refresh state */ - clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x12 << 27); - - /* check whether command has been executed */ - await_completion(&dram->dcr, 0x1 << 31); - - udelay(2); - - /* issue a refresh command */ - clrsetbits_le32(&dram->dcr, 0x1f << 27, 0x13 << 27); - await_completion(&dram->dcr, 0x1 << 31); - - udelay(2); - } -#endif - /* scan read pipe value */ mctl_itm_enable(); ret_val = dramc_scan_readpipe(); -- cgit v1.2.3 From e626d2d446996b4b1cd16bf65b42c080985d8a84 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:41 +0300 Subject: sunxi: dram: Respect the DDR3 reset timing requirements The RESET pin needs to be kept low for at least 200 us according to the DDR3 spec. So just do it the right way. This issue did not cause any visible major problems earlier, because the DRAM RESET pin is usually already low after the board reset. And the time gap before reaching the sunxi u-boot DRAM initialization code appeared to be sufficient. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index dc79d1c8ba3..a632926fa73 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -48,6 +48,11 @@ static void await_completion(u32 *reg, u32 mask) } } +/* + * This performs the external DRAM reset by driving the RESET pin low and + * then high again. According to the DDR3 spec, the RESET pin needs to be + * kept low for at least 200 us. + */ static void mctl_ddr3_reset(void) { struct sunxi_dram_reg *dram = @@ -64,13 +69,13 @@ static void mctl_ddr3_reset(void) if ((reg_val & CPU_CFG_CHIP_VER_MASK) != CPU_CFG_CHIP_VER(CPU_CFG_CHIP_REV_A)) { setbits_le32(&dram->mcr, DRAM_MCR_RESET); - udelay(2); + udelay(200); clrbits_le32(&dram->mcr, DRAM_MCR_RESET); } else #endif { clrbits_le32(&dram->mcr, DRAM_MCR_RESET); - udelay(2); + udelay(200); setbits_le32(&dram->mcr, DRAM_MCR_RESET); } } -- cgit v1.2.3 From f8e88b68371755129c129772148307a967874838 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:42 +0300 Subject: sunxi: dram: Fix CKE delay handling for sun4i/sun5i Before driving the CKE pin (Clock Enable) high, the DDR3 spec requires to wait for additional 500 us after the RESET pin is de-asserted. The DRAM controller takes care of this delay by itself, using a configurable counter in the SDR_IDCR register. This works in the same way on sun4i/sun5i/sun7i hardware (even the default register value 0x00c80064 is identical). Except that the counter is ticking a bit slower on sun7i (3 DRAM clock cycles instead of 2), resulting in longer actual delays for the same settings. This patch configures the SDR_IDCR register for all sun4i/sun5i/sun7i SoC variants and not just for sun7i alone. Also an explicit udelay(500) is added immediately after DDR3 reset for extra safety. This is a duplicated functionality. But since we don't have perfect documentation, it may be reasonable to play safe. Half a millisecond boot time increase is not that significant. Boot time can be always optimized later. Preferebly by the people, who have the hardware equipment to check the actual signals on the RESET and CKE lines and verify all the timings. The old code did not configure the SDR_IDCR register for sun4i/sun5i, but performed the DDR3 reset very early for sun4i/sun5i. This resulted in a larger time gap between the DDR3 reset and the DDR3 initialization steps and reduced the chances of CKE delay timing violation to cause real troubles. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 57 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index a632926fa73..6849952adb6 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -78,6 +78,19 @@ static void mctl_ddr3_reset(void) udelay(200); setbits_le32(&dram->mcr, DRAM_MCR_RESET); } + /* After the RESET pin is de-asserted, the DDR3 spec requires to wait + * for additional 500 us before driving the CKE pin (Clock Enable) + * high. The duration of this delay can be configured in the SDR_IDCR + * (Initialization Delay Configuration Register) and applied + * automatically by the DRAM controller during the DDR3 initialization + * step. But SDR_IDCR has limited range on sun4i/sun5i hardware and + * can't provide sufficient delay at DRAM clock frequencies higher than + * 524 MHz (while Allwinner A13 supports DRAM clock frequency up to + * 533 MHz according to the datasheet). Additionally, there is no + * official documentation for the SDR_IDCR register anywhere, and + * there is always a chance that we are interpreting it wrong. + * Better be safe than sorry, so add an explicit delay here. */ + udelay(500); } static void mctl_set_drive(void) @@ -382,6 +395,40 @@ static void mctl_disable_power_save(void) writel(0x16510000, &dram->ppwrsctl); } +/* + * After the DRAM is powered up or reset, the DDR3 spec requires to wait at + * least 500 us before driving the CKE pin (Clock Enable) high. The dram->idct + * (SDR_IDCR) register appears to configure this delay, which gets applied + * right at the time when the DRAM initialization is activated in the + * 'mctl_ddr3_initialize' function. + */ +static void mctl_set_cke_delay(void) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + + /* The CKE delay is represented in DRAM clock cycles, multiplied by N + * (where N=2 for sun4i/sun5i and N=3 for sun7i). Here it is set to + * the maximum possible value 0x1ffff, just like in the Allwinner's + * boot0 bootloader. The resulting delay value is somewhere between + * ~0.4 ms (sun5i with 648 MHz DRAM clock speed) and ~1.1 ms (sun7i + * with 360 MHz DRAM clock speed). */ + setbits_le32(&dram->idcr, 0x1ffff); +} + +/* + * This triggers the DRAM initialization. It performs sending the mode registers + * to the DRAM among other things. Very likely the ZQCL command is also getting + * executed (to do the initial impedance calibration on the DRAM side of the + * wire). The memory controller and the PHY must be already configured before + * calling this function. + */ +static void mctl_ddr3_initialize(void) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + setbits_le32(&dram->ccr, DRAM_CCR_INIT); + await_completion(&dram->ccr, DRAM_CCR_INIT); +} + unsigned long dramc_init(struct dram_para *para) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; @@ -459,10 +506,7 @@ unsigned long dramc_init(struct dram_para *para) writel(reg_val, &dram->zqcr0); #endif -#ifdef CONFIG_SUN7I - /* Set CKE Delay to about 1ms */ - setbits_le32(&dram->idcr, 0x1ffff); -#endif + mctl_set_cke_delay(); #ifdef CONFIG_SUN7I mctl_ddr3_reset(); @@ -527,9 +571,8 @@ unsigned long dramc_init(struct dram_para *para) if (para->tpr4 & 0x1) setbits_le32(&dram->ccr, DRAM_CCR_COMMAND_RATE_1T); #endif - /* reset external DRAM */ - setbits_le32(&dram->ccr, DRAM_CCR_INIT); - await_completion(&dram->ccr, DRAM_CCR_INIT); + /* initialize external DRAM */ + mctl_ddr3_initialize(); /* scan read pipe value */ mctl_itm_enable(); -- cgit v1.2.3 From 7e40e1926a237ad215901cd780f309e995105515 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:43 +0300 Subject: sunxi: dram: Remove broken impedance and ODT configuration code We can safely remove it, because none of the currently supported boards uses these features. The existing implementation had multiple problems: - unnecessary code duplication between sun4i/sun5i/sun7i - ZQ calibration was never initiated explicitly, and could be only triggered by setting the highest bit in the 'zq' parameter in the 'dram_para' struct (this was never actually done for any of the known Allwinner devices). - even if the ZQ calibration could be started, no attempts were made to wait for its completion, or checking whether the default automatically initiated ZQ calibration is still in progress - ODT was only ever enabled on sun4i, but not on sun5i/sun7i Additionally, SDR_IOCR was set to 0x00cc0000 only on sun4i. There are some hints in the Rockchip Linux kernel sources, indicating that these bits are related to the automatic I/O power down feature, which is poorly understood on sunxi hardware at the moment. Avoiding to set these bits on sun4i too does not seem to have any measurable/visible impact. The impedance and ODT configuration code will be re-introdeced in one of the next comits. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 6849952adb6..33e8bd69642 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -492,20 +492,9 @@ unsigned long dramc_init(struct dram_para *para) writel(reg_val, &dram->dcr); #ifdef CONFIG_SUN7I - setbits_le32(&dram->zqcr1, (0x1 << 24) | (0x1 << 1)); - if (para->tpr4 & 0x2) - clrsetbits_le32(&dram->zqcr1, (0x1 << 24), (0x1 << 1)); dramc_clock_output_en(1); #endif -#if (defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I)) - /* set odt impendance divide ratio */ - reg_val = ((para->zq) >> 8) & 0xfffff; - reg_val |= ((para->zq) & 0xff) << 20; - reg_val |= (para->zq) & 0xf0000000; - writel(reg_val, &dram->zqcr0); -#endif - mctl_set_cke_delay(); #ifdef CONFIG_SUN7I @@ -521,22 +510,6 @@ unsigned long dramc_init(struct dram_para *para) mctl_enable_dllx(para->tpr3); -#ifdef CONFIG_SUN4I - /* set odt impedance divide ratio */ - reg_val = ((para->zq) >> 8) & 0xfffff; - reg_val |= ((para->zq) & 0xff) << 20; - reg_val |= (para->zq) & 0xf0000000; - writel(reg_val, &dram->zqcr0); -#endif - -#ifdef CONFIG_SUN4I - /* set I/O configure register */ - reg_val = 0x00cc0000; - reg_val |= (para->odt_en) & 0x3; - reg_val |= ((para->odt_en) & 0x3) << 30; - writel(reg_val, &dram->iocr); -#endif - /* set refresh period */ dramc_set_autorefresh_cycle(para->clock, para->type - 2, density); -- cgit v1.2.3 From cfc89b003bb2600eb330939da0f53b9caf3e17fa Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:44 +0300 Subject: sunxi: dram: Do DDR3 reset in the same way on sun4i/sun5i/sun7i The older differences were likely justified by the need to mitigate the CKE delay timing violations on sun4i/sun5i. The CKE problem is already resolved, so now we can use the sun7i variant of this code everywhere. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 33e8bd69642..9042e9a2943 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -446,10 +446,6 @@ unsigned long dramc_init(struct dram_para *para) /* Disable any pad power save control */ mctl_disable_power_save(); - /* reset external DRAM */ -#ifndef CONFIG_SUN7I - mctl_ddr3_reset(); -#endif mctl_set_drive(); /* dram clock off */ @@ -491,18 +487,11 @@ unsigned long dramc_init(struct dram_para *para) reg_val |= DRAM_DCR_MODE(DRAM_DCR_MODE_INTERLEAVE); writel(reg_val, &dram->dcr); -#ifdef CONFIG_SUN7I dramc_clock_output_en(1); -#endif mctl_set_cke_delay(); -#ifdef CONFIG_SUN7I mctl_ddr3_reset(); -#else - /* dram clock on */ - dramc_clock_output_en(1); -#endif udelay(1); -- cgit v1.2.3 From 94cd3019881523b7776138f93f9e6b9849adc4d4 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:45 +0300 Subject: sunxi: dram: Add 'await_bits_clear'/'await_bits_set' helper functions The old 'await_completion' function is not sufficient, because in some cases we want to wait for bits to be cleared, and in the other cases we want to wait for bits to be set. So split the 'await_completion' into two new 'await_bits_clear' and 'await_bits_set' functions. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 9042e9a2943..4a72480425d 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -36,18 +36,34 @@ #define CPU_CFG_CHIP_REV_B 0x3 /* - * Wait up to 1s for mask to be clear in given reg. + * Wait up to 1s for value to be set in given part of reg. */ -static void await_completion(u32 *reg, u32 mask) +static void await_completion(u32 *reg, u32 mask, u32 val) { unsigned long tmo = timer_get_us() + 1000000; - while (readl(reg) & mask) { + while ((readl(reg) & mask) != val) { if (timer_get_us() > tmo) panic("Timeout initialising DRAM\n"); } } +/* + * Wait up to 1s for mask to be clear in given reg. + */ +static inline void await_bits_clear(u32 *reg, u32 mask) +{ + await_completion(reg, mask, 0); +} + +/* + * Wait up to 1s for mask to be set in given reg. + */ +static inline void await_bits_set(u32 *reg, u32 mask) +{ + await_completion(reg, mask, mask); +} + /* * This performs the external DRAM reset by driving the RESET pin low and * then high again. According to the DDR3 spec, the RESET pin needs to be @@ -329,7 +345,7 @@ static int dramc_scan_readpipe(void) setbits_le32(&dram->ccr, DRAM_CCR_DATA_TRAINING); /* check whether data training process has completed */ - await_completion(&dram->ccr, DRAM_CCR_DATA_TRAINING); + await_bits_clear(&dram->ccr, DRAM_CCR_DATA_TRAINING); /* check data training result */ reg_val = readl(&dram->csr); @@ -426,7 +442,7 @@ static void mctl_ddr3_initialize(void) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; setbits_le32(&dram->ccr, DRAM_CCR_INIT); - await_completion(&dram->ccr, DRAM_CCR_INIT); + await_bits_clear(&dram->ccr, DRAM_CCR_INIT); } unsigned long dramc_init(struct dram_para *para) @@ -495,7 +511,7 @@ unsigned long dramc_init(struct dram_para *para) udelay(1); - await_completion(&dram->ccr, DRAM_CCR_INIT); + await_bits_clear(&dram->ccr, DRAM_CCR_INIT); mctl_enable_dllx(para->tpr3); -- cgit v1.2.3 From 5c18384dea60a9acbbc6f2f95a5e291089db7e94 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:46 +0300 Subject: sunxi: dram: Re-introduce the impedance calibration ond ODT The DRAM controller allows to configure impedance either by using the calibration against an external high precision 240 ohm resistor, or by skipping the calibration and loading pre-defined data. The DRAM controller register guide is available here: http://linux-sunxi.org/A10_DRAM_Controller_Register_Guide#SDR_ZQCR0 The new code supports both of the impedance configuration modes: - If the higher bits of the 'zq' parameter in the 'dram_para' struct are zero, then the lowest 8 bits are used as the ZPROG value, where two divisors encoded in lower and higher 4 bits. One divisor is used for calibrating the termination impedance, and another is used for the output impedance. - If bits 27:8 in the 'zq' parameters are non-zero, then they are used as the pre-defined ZDATA value instead of performing the ZQ calibration. Two lowest bits in the 'odt_en' parameter enable ODT for the DQ and DQS lines individually. Enabling ODT for both DQ and DQS means that the 'odt_en' parameter needs to be set to 3. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 56 ++++++++++++++++++++++++++++++++++ arch/arm/include/asm/arch-sunxi/dram.h | 4 +++ 2 files changed, 60 insertions(+) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 4a72480425d..f87cbebae23 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -445,6 +445,60 @@ static void mctl_ddr3_initialize(void) await_bits_clear(&dram->ccr, DRAM_CCR_INIT); } +/* + * Perform impedance calibration on the DRAM controller side of the wire. + */ +static void mctl_set_impedance(u32 zq, u32 odt_en) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + u32 reg_val; + u32 zprog = zq & 0xFF, zdata = (zq >> 8) & 0xFFFFF; + +#ifndef CONFIG_SUN7I + /* Appears that some kind of automatically initiated default + * ZQ calibration is already in progress at this point on sun4i/sun5i + * hardware, but not on sun7i. So it is reasonable to wait for its + * completion before doing anything else. */ + await_bits_set(&dram->zqsr, DRAM_ZQSR_ZDONE); +#endif + + /* ZQ calibration is not really useful unless ODT is enabled */ + if (!odt_en) + return; + +#ifdef CONFIG_SUN7I + /* Enabling ODT in SDR_IOCR on sun7i hardware results in a deadlock + * unless bit 24 is set in SDR_ZQCR1. Not much is known about the + * SDR_ZQCR1 register, but there are hints indicating that it might + * be related to periodic impedance re-calibration. This particular + * magic value is borrowed from the Allwinner boot0 bootloader, and + * using it helps to avoid troubles */ + writel((1 << 24) | (1 << 1), &dram->zqcr1); +#endif + + /* Needed at least for sun5i, because it does not self clear there */ + clrbits_le32(&dram->zqcr0, DRAM_ZQCR0_ZCAL); + + if (zdata) { + /* Set the user supplied impedance data */ + reg_val = DRAM_ZQCR0_ZDEN | zdata; + writel(reg_val, &dram->zqcr0); + /* no need to wait, this takes effect immediately */ + } else { + /* Do the calibration using the external resistor */ + reg_val = DRAM_ZQCR0_ZCAL | DRAM_ZQCR0_IMP_DIV(zprog); + writel(reg_val, &dram->zqcr0); + /* Wait for the new impedance configuration to settle */ + await_bits_set(&dram->zqsr, DRAM_ZQSR_ZDONE); + } + + /* Needed at least for sun5i, because it does not self clear there */ + clrbits_le32(&dram->zqcr0, DRAM_ZQCR0_ZCAL); + + /* Set I/O configure register */ + writel(DRAM_IOCR_ODT_EN(odt_en), &dram->iocr); +} + unsigned long dramc_init(struct dram_para *para) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; @@ -505,6 +559,8 @@ unsigned long dramc_init(struct dram_para *para) dramc_clock_output_en(1); + mctl_set_impedance(para->zq, para->odt_en); + mctl_set_cke_delay(); mctl_ddr3_reset(); diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 67fbfad07ea..4433eeb29e9 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -159,6 +159,10 @@ struct dram_para { #define DRAM_ZQCR0_IMP_DIV(n) (((n) & 0xff) << 20) #define DRAM_ZQCR0_IMP_DIV_MASK DRAM_ZQCR0_IMP_DIV(0xff) +#define DRAM_ZQCR0_ZCAL (1 << 31) /* Starts ZQ calibration when set to 1 */ +#define DRAM_ZQCR0_ZDEN (1 << 28) /* Uses ZDATA instead of doing calibration */ + +#define DRAM_ZQSR_ZDONE (1 << 31) /* ZQ calibration completion flag */ #define DRAM_IOCR_ODT_EN(n) ((((n) & 0x3) << 30) | ((n) & 0x3) << 0) #define DRAM_IOCR_ODT_EN_MASK DRAM_IOCR_ODT_EN(0x3) -- cgit v1.2.3 From 1a9717cbb3753ea93d156621b3082434b8417c9f Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:47 +0300 Subject: sunxi: dram: Configurable MBUS clock speed (use PLL5 or PLL6) The sun5i hardware (Allwinner A13) introduced configurable MBUS clock speed. Allwinner A13 uses only 16-bit data bus width to connect the external DRAM, which is halved compared to the 32-bit data bus of sun4i (Allwinner A10), so it does not make much sense to clock a wider internal bus at a very high speed. The Allwinner A13 manual specifies 300 MHz MBUS clock speed limit and 533 MHz DRAM clock speed limit. Newer sun7i hardware (Allwinner A20) has a full width 32-bit external memory interface again, but still keeps the MBUS clock speed configurable. Clocking MBUS too low inhibits memory performance and one has to find the optimal MBUS/DRAM clock speed ratio, which may depend on many factors: http://linux-sunxi.org/A10_DRAM_Controller_Performance This patch introduces a new 'mbus_clock' parameter for the 'dram_para' struct and uses it as a desired MBUS clock speed target. If 'mbus_clock' is not set, 300 MHz is used by default to match the older hardcoded settings. PLL5P and PLL6 are both evaluated as possible clock sources. Preferring the one, which can provide higher clock frequency that is lower or equal to the 'mbus_clock' target. In the case of a tie, PLL5P has higher priority. Attempting to set the MBUS clock speed has no effect on sun4i, but does no harm either. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 52 +++++++++++++++++++++++++--------- arch/arm/include/asm/arch-sunxi/dram.h | 1 + 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index f87cbebae23..2403659b473 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -235,11 +235,20 @@ static void mctl_configure_hostport(void) writel(hpcr_value[i], &dram->hpcr[i]); } -static void mctl_setup_dram_clock(u32 clk) +static void mctl_setup_dram_clock(u32 clk, u32 mbus_clk) { u32 reg_val; struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + /* PLL5P and PLL6 are the potential clock sources for MBUS */ + u32 pll6x_div, pll5p_div; + u32 pll6x_clk = clock_get_pll6() / 1000000; + u32 pll5p_clk = clk / 24 * 24; + u32 pll5p_rate, pll6x_rate; +#ifdef CONFIG_SUN7I + pll6x_clk *= 2; /* sun7i uses PLL6*2, sun5i uses just PLL6 */ +#endif + /* setup DRAM PLL */ reg_val = readl(&ccm->pll5_cfg); reg_val &= ~CCM_PLL5_CTRL_M_MASK; /* set M to 0 (x1) */ @@ -248,30 +257,35 @@ static void mctl_setup_dram_clock(u32 clk) reg_val &= ~CCM_PLL5_CTRL_P_MASK; /* set P to 0 (x1) */ if (clk >= 540 && clk < 552) { /* dram = 540MHz, pll5p = 540MHz */ + pll5p_clk = 540; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(15)); reg_val |= CCM_PLL5_CTRL_P(1); } else if (clk >= 512 && clk < 528) { /* dram = 512MHz, pll5p = 384MHz */ + pll5p_clk = 384; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(4)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(16)); reg_val |= CCM_PLL5_CTRL_P(2); } else if (clk >= 496 && clk < 504) { /* dram = 496MHz, pll5p = 372MHz */ + pll5p_clk = 372; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(31)); reg_val |= CCM_PLL5_CTRL_P(2); } else if (clk >= 468 && clk < 480) { /* dram = 468MHz, pll5p = 468MHz */ + pll5p_clk = 468; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(13)); reg_val |= CCM_PLL5_CTRL_P(1); } else if (clk >= 396 && clk < 408) { /* dram = 396MHz, pll5p = 396MHz */ + pll5p_clk = 396; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(11)); @@ -298,20 +312,30 @@ static void mctl_setup_dram_clock(u32 clk) clrbits_le32(&ccm->ahb_gate0, CCM_AHB_GATE_GPS); #endif -#if defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I) /* setup MBUS clock */ - reg_val = CCM_MBUS_CTRL_GATE | -#ifdef CONFIG_SUN7I - CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL6) | - CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(2)) | - CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(2)); -#else /* defined(CONFIG_SUN5I) */ - CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL5) | - CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(1)) | - CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(2)); -#endif + if (!mbus_clk) + mbus_clk = 300; + pll6x_div = DIV_ROUND_UP(pll6x_clk, mbus_clk); + pll5p_div = DIV_ROUND_UP(pll5p_clk, mbus_clk); + pll6x_rate = pll6x_clk / pll6x_div; + pll5p_rate = pll5p_clk / pll5p_div; + + if (pll6x_div <= 16 && pll6x_rate > pll5p_rate) { + /* use PLL6 as the MBUS clock source */ + reg_val = CCM_MBUS_CTRL_GATE | + CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL6) | + CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(1)) | + CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(pll6x_div)); + } else if (pll5p_div <= 16) { + /* use PLL5P as the MBUS clock source */ + reg_val = CCM_MBUS_CTRL_GATE | + CCM_MBUS_CTRL_CLK_SRC(CCM_MBUS_CTRL_CLK_SRC_PLL5) | + CCM_MBUS_CTRL_N(CCM_MBUS_CTRL_N_X(1)) | + CCM_MBUS_CTRL_M(CCM_MBUS_CTRL_M_X(pll5p_div)); + } else { + panic("Bad mbus_clk\n"); + } writel(reg_val, &ccm->mbus_clk_cfg); -#endif /* * open DRAMC AHB & DLL register clock @@ -511,7 +535,7 @@ unsigned long dramc_init(struct dram_para *para) return 0; /* setup DRAM relative clock */ - mctl_setup_dram_clock(para->clock); + mctl_setup_dram_clock(para->clock, para->mbus_clock); /* Disable any pad power save control */ mctl_disable_power_save(); diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 4433eeb29e9..3c2925625d1 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -69,6 +69,7 @@ struct sunxi_dram_reg { struct dram_para { u32 clock; + u32 mbus_clock; u32 type; u32 rank_num; u32 density; -- cgit v1.2.3 From 013f2d746955147439215a4939655c9ed6bdd866 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:48 +0300 Subject: sunxi: dram: Use divisor P=1 for PLL5 This configures the PLL5P clock frequency to something in the ballpark of 1GHz and allows more choices for MBUS and G2D clock frequency selection (using their own divisors). In particular, it enables the use of 2/3 clock speed ratio between MBUS and DRAM. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 2403659b473..6f98c6a3bb5 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -243,7 +243,7 @@ static void mctl_setup_dram_clock(u32 clk, u32 mbus_clk) /* PLL5P and PLL6 are the potential clock sources for MBUS */ u32 pll6x_div, pll5p_div; u32 pll6x_clk = clock_get_pll6() / 1000000; - u32 pll5p_clk = clk / 24 * 24; + u32 pll5p_clk = clk / 24 * 48; u32 pll5p_rate, pll6x_rate; #ifdef CONFIG_SUN7I pll6x_clk *= 2; /* sun7i uses PLL6*2, sun5i uses just PLL6 */ @@ -256,46 +256,40 @@ static void mctl_setup_dram_clock(u32 clk, u32 mbus_clk) reg_val &= ~CCM_PLL5_CTRL_N_MASK; /* set N to 0 (x0) */ reg_val &= ~CCM_PLL5_CTRL_P_MASK; /* set P to 0 (x1) */ if (clk >= 540 && clk < 552) { - /* dram = 540MHz, pll5p = 540MHz */ - pll5p_clk = 540; + /* dram = 540MHz, pll5p = 1080MHz */ + pll5p_clk = 1080; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(15)); - reg_val |= CCM_PLL5_CTRL_P(1); } else if (clk >= 512 && clk < 528) { - /* dram = 512MHz, pll5p = 384MHz */ - pll5p_clk = 384; + /* dram = 512MHz, pll5p = 1536MHz */ + pll5p_clk = 1536; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(4)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(16)); - reg_val |= CCM_PLL5_CTRL_P(2); } else if (clk >= 496 && clk < 504) { - /* dram = 496MHz, pll5p = 372MHz */ - pll5p_clk = 372; + /* dram = 496MHz, pll5p = 1488MHz */ + pll5p_clk = 1488; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(3)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(31)); - reg_val |= CCM_PLL5_CTRL_P(2); } else if (clk >= 468 && clk < 480) { - /* dram = 468MHz, pll5p = 468MHz */ - pll5p_clk = 468; + /* dram = 468MHz, pll5p = 936MHz */ + pll5p_clk = 936; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(13)); - reg_val |= CCM_PLL5_CTRL_P(1); } else if (clk >= 396 && clk < 408) { - /* dram = 396MHz, pll5p = 396MHz */ - pll5p_clk = 396; + /* dram = 396MHz, pll5p = 792MHz */ + pll5p_clk = 792; reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(3)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(11)); - reg_val |= CCM_PLL5_CTRL_P(1); } else { /* any other frequency that is a multiple of 24 */ reg_val |= CCM_PLL5_CTRL_M(CCM_PLL5_CTRL_M_X(2)); reg_val |= CCM_PLL5_CTRL_K(CCM_PLL5_CTRL_K_X(2)); reg_val |= CCM_PLL5_CTRL_N(CCM_PLL5_CTRL_N_X(clk / 24)); - reg_val |= CCM_PLL5_CTRL_P(CCM_PLL5_CTRL_P_X(2)); } reg_val &= ~CCM_PLL5_CTRL_VCO_GAIN; /* PLL VCO Gain off */ reg_val |= CCM_PLL5_CTRL_EN; /* PLL On */ -- cgit v1.2.3 From b8f7cb6ae31d3c2de7349e58889ed3c5a1a77c42 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:49 +0300 Subject: sunxi: dram: Improve DQS gate data training error handling The stale error status should be cleared for all sun4i/sun5i/sun7i hardware and not just for sun7i. Also there are two types of DQS gate training errors ("found no result" and "found more than one possible result"). Both are handled now. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 2 -- arch/arm/include/asm/arch-sunxi/dram.h | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 6f98c6a3bb5..47017d2df18 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -357,9 +357,7 @@ static int dramc_scan_readpipe(void) u32 reg_val; /* data training trigger */ -#ifdef CONFIG_SUN7I clrbits_le32(&dram->csr, DRAM_CSR_FAILED); -#endif setbits_le32(&dram->ccr, DRAM_CCR_DATA_TRAINING); /* check whether data training process has completed */ diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 3c2925625d1..11e35077f43 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -133,7 +133,9 @@ struct dram_para { #define DRAM_DCR_MODE_SEQ 0x0 #define DRAM_DCR_MODE_INTERLEAVE 0x1 -#define DRAM_CSR_FAILED (0x1 << 20) +#define DRAM_CSR_DTERR (0x1 << 20) +#define DRAM_CSR_DTIERR (0x1 << 21) +#define DRAM_CSR_FAILED (DRAM_CSR_DTERR | DRAM_CSR_DTIERR) #define DRAM_DRR_TRFC(n) ((n) & 0xff) #define DRAM_DRR_TREFI(n) (((n) & 0xffff) << 8) -- cgit v1.2.3 From e044daa33e28947c34b855643e5d16a030da8fe8 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:50 +0300 Subject: sunxi: dram: Add a helper function 'mctl_get_number_of_lanes' It is going to be useful in more than one place. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 27 ++++++++++++++++----------- arch/arm/include/asm/arch-sunxi/dram.h | 3 --- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 47017d2df18..30483913b35 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -152,23 +152,28 @@ static void mctl_enable_dll0(u32 phase) udelay(22); } +/* Get the number of DDR byte lanes */ +static u32 mctl_get_number_of_lanes(void) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + if ((readl(&dram->dcr) & DRAM_DCR_BUS_WIDTH_MASK) == + DRAM_DCR_BUS_WIDTH(DRAM_DCR_BUS_WIDTH_32BIT)) + return 4; + else + return 2; +} + /* * Note: This differs from pm/standby in that it checks the bus width */ static void mctl_enable_dllx(u32 phase) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; - u32 i, n, bus_width; - - bus_width = readl(&dram->dcr); + u32 i, number_of_lanes; - if ((bus_width & DRAM_DCR_BUS_WIDTH_MASK) == - DRAM_DCR_BUS_WIDTH(DRAM_DCR_BUS_WIDTH_32BIT)) - n = DRAM_DCR_NR_DLLCR_32BIT; - else - n = DRAM_DCR_NR_DLLCR_16BIT; + number_of_lanes = mctl_get_number_of_lanes(); - for (i = 1; i < n; i++) { + for (i = 1; i <= number_of_lanes; i++) { clrsetbits_le32(&dram->dllcr[i], 0xf << 14, (phase & 0xf) << 14); clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET, @@ -177,12 +182,12 @@ static void mctl_enable_dllx(u32 phase) } udelay(2); - for (i = 1; i < n; i++) + for (i = 1; i <= number_of_lanes; i++) clrbits_le32(&dram->dllcr[i], DRAM_DLLCR_NRESET | DRAM_DLLCR_DISABLE); udelay(22); - for (i = 1; i < n; i++) + for (i = 1; i <= number_of_lanes; i++) clrsetbits_le32(&dram->dllcr[i], DRAM_DLLCR_DISABLE, DRAM_DLLCR_NRESET); udelay(22); diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 11e35077f43..71301dbf33f 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -122,9 +122,6 @@ struct dram_para { #define DRAM_DCR_BUS_WIDTH_32BIT 0x3 #define DRAM_DCR_BUS_WIDTH_16BIT 0x1 #define DRAM_DCR_BUS_WIDTH_8BIT 0x0 -#define DRAM_DCR_NR_DLLCR_32BIT 5 -#define DRAM_DCR_NR_DLLCR_16BIT 3 -#define DRAM_DCR_NR_DLLCR_8BIT 2 #define DRAM_DCR_RANK_SEL(n) (((n) & 0x3) << 10) #define DRAM_DCR_RANK_SEL_MASK DRAM_DCR_CMD_RANK(0x3) #define DRAM_DCR_CMD_RANK_ALL (0x1 << 12) -- cgit v1.2.3 From d755a5fb20a7e3192d301d6d6a44814b10fb4f46 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:51 +0300 Subject: sunxi: dram: Configurable DQS gating window mode and delay The hardware DQS gate training is a bit unreliable and does not always find the best delay settings. So we introduce a 32-bit 'dqs_gating_delay' variable, where each byte encodes the DQS gating delay for each byte lane. The delay granularity is 1/4 cycle. Also we allow to enable the active DQS gating window mode, which works better than the passive mode in practice. The DDR3 spec says that there is a 0.9 cycles preamble and 0.3 cycle postamble. The DQS window has to be opened during preamble and closed during postamble. In the passive window mode, the gating window is opened and closed by just using the gating delay settings. And because of the 1/4 cycle delay granularity, accurately hitting the 0.3 cycle long postamble is a bit tough. In the active window mode, the gating window is auto-closing with the help of monitoring the DQS line, which relaxes the gating delay accuracy requirements. But the hardware DQS gate training is still performed in the passive window mode. It is a more strict test, which is reducing the results variance compared to the training with active window mode. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 55 +++++++++++++++++++++++++++++++++- arch/arm/include/asm/arch-sunxi/dram.h | 2 ++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 30483913b35..be6750d880c 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -136,6 +136,14 @@ static void mctl_itm_enable(void) clrbits_le32(&dram->ccr, DRAM_CCR_ITM_OFF); } +static void mctl_itm_reset(void) +{ + mctl_itm_disable(); + udelay(1); /* ITM reset needs a bit of delay */ + mctl_itm_enable(); + udelay(1); +} + static void mctl_enable_dll0(u32 phase) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; @@ -356,6 +364,37 @@ static void mctl_setup_dram_clock(u32 clk, u32 mbus_clk) udelay(22); } +/* + * The data from rslrX and rdgrX registers (X=rank) is stored + * in a single 32-bit value using the following format: + * bits [31:26] - DQS gating system latency for byte lane 3 + * bits [25:24] - DQS gating phase select for byte lane 3 + * bits [23:18] - DQS gating system latency for byte lane 2 + * bits [17:16] - DQS gating phase select for byte lane 2 + * bits [15:10] - DQS gating system latency for byte lane 1 + * bits [ 9:8 ] - DQS gating phase select for byte lane 1 + * bits [ 7:2 ] - DQS gating system latency for byte lane 0 + * bits [ 1:0 ] - DQS gating phase select for byte lane 0 + */ +static void mctl_set_dqs_gating_delay(int rank, u32 dqs_gating_delay) +{ + struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; + u32 lane, number_of_lanes = mctl_get_number_of_lanes(); + /* rank0 gating system latency (3 bits per lane: cycles) */ + u32 slr = readl(rank == 0 ? &dram->rslr0 : &dram->rslr1); + /* rank0 gating phase select (2 bits per lane: 90, 180, 270, 360) */ + u32 dgr = readl(rank == 0 ? &dram->rdgr0 : &dram->rdgr1); + for (lane = 0; lane < number_of_lanes; lane++) { + u32 tmp = dqs_gating_delay >> (lane * 8); + slr &= ~(7 << (lane * 3)); + slr |= ((tmp >> 2) & 7) << (lane * 3); + dgr &= ~(3 << (lane * 2)); + dgr |= (tmp & 3) << (lane * 2); + } + writel(slr, rank == 0 ? &dram->rslr0 : &dram->rslr1); + writel(dgr, rank == 0 ? &dram->rdgr0 : &dram->rdgr1); +} + static int dramc_scan_readpipe(void) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; @@ -618,7 +657,7 @@ unsigned long dramc_init(struct dram_para *para) writel(para->emr2, &dram->emr2); writel(para->emr3, &dram->emr3); - /* set DQS window mode */ + /* disable drift compensation and set passive DQS window mode */ clrsetbits_le32(&dram->ccr, DRAM_CCR_DQS_DRIFT_COMP, DRAM_CCR_DQS_GATE); #ifdef CONFIG_SUN7I @@ -631,11 +670,25 @@ unsigned long dramc_init(struct dram_para *para) /* scan read pipe value */ mctl_itm_enable(); + + /* Hardware DQS gate training */ ret_val = dramc_scan_readpipe(); if (ret_val < 0) return 0; + /* allow to override the DQS training results with a custom delay */ + if (para->dqs_gating_delay) + mctl_set_dqs_gating_delay(0, para->dqs_gating_delay); + + /* set the DQS gating window type */ + if (para->active_windowing) + clrbits_le32(&dram->ccr, DRAM_CCR_DQS_GATE); + else + setbits_le32(&dram->ccr, DRAM_CCR_DQS_GATE); + + mctl_itm_reset(); + /* configure all host port */ mctl_configure_hostport(); diff --git a/arch/arm/include/asm/arch-sunxi/dram.h b/arch/arm/include/asm/arch-sunxi/dram.h index 71301dbf33f..1945f75441f 100644 --- a/arch/arm/include/asm/arch-sunxi/dram.h +++ b/arch/arm/include/asm/arch-sunxi/dram.h @@ -88,6 +88,8 @@ struct dram_para { u32 emr1; u32 emr2; u32 emr3; + u32 dqs_gating_delay; + u32 active_windowing; }; #define DRAM_CCR_COMMAND_RATE_1T (0x1 << 5) -- cgit v1.2.3 From b5c71f5f9c1634d72f40b2c17aeff53ef8fdf8e0 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:52 +0300 Subject: sunxi: dram: Drop DDR2 support and assume only single rank DDR3 memory All the known Allwinner A10/A13/A20 devices are using just single rank DDR3 memory. So don't pretend that we support DDR2 or more than one rank, because nobody could ever test these configurations for real and they are likely broken. Support for these features can be added back in the case if such hardware actually exists. As part of this code cleanup, also replace division by 1024 with division by 1000 for the refresh timing calculations. This allows to use the original non-skewed tRFC timing table from the DRR3 spec and make code less confusing. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index be6750d880c..0bbb10d5e3d 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -434,20 +434,18 @@ static void dramc_clock_output_en(u32 on) #endif } -static const u16 tRFC_table[2][6] = { - /* 256Mb 512Mb 1Gb 2Gb 4Gb 8Gb */ - /* DDR2 75ns 105ns 127.5ns 195ns 327.5ns invalid */ - { 77, 108, 131, 200, 336, 336 }, - /* DDR3 invalid 90ns 110ns 160ns 300ns 350ns */ - { 93, 93, 113, 164, 308, 359 } +/* tRFC in nanoseconds for different densities (from the DDR3 spec) */ +static const u16 tRFC_DDR3_table[6] = { + /* 256Mb 512Mb 1Gb 2Gb 4Gb 8Gb */ + 90, 90, 110, 160, 300, 350 }; -static void dramc_set_autorefresh_cycle(u32 clk, u32 type, u32 density) +static void dramc_set_autorefresh_cycle(u32 clk, u32 density) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; u32 tRFC, tREFI; - tRFC = (tRFC_table[type][density] * clk + 1023) >> 10; + tRFC = (tRFC_DDR3_table[density] * clk + 999) / 1000; tREFI = (7987 * clk) >> 10; /* <= 7.8us */ writel(DRAM_DRR_TREFI(tREFI) | DRAM_DRR_TRFC(tRFC), &dram->drr); @@ -570,6 +568,13 @@ unsigned long dramc_init(struct dram_para *para) if (!para) return 0; + /* + * only single rank DDR3 is supported by this code even though the + * hardware can theoretically support DDR2 and up to two ranks + */ + if (para->type != DRAM_MEMORY_TYPE_DDR3 || para->rank_num != 1) + return 0; + /* setup DRAM relative clock */ mctl_setup_dram_clock(para->clock, para->mbus_clock); @@ -590,9 +595,7 @@ unsigned long dramc_init(struct dram_para *para) mctl_enable_dll0(para->tpr3); /* configure external DRAM */ - reg_val = 0x0; - if (para->type == DRAM_MEMORY_TYPE_DDR3) - reg_val |= DRAM_DCR_TYPE_DDR3; + reg_val = DRAM_DCR_TYPE_DDR3; reg_val |= DRAM_DCR_IO_WIDTH(para->io_width >> 3); if (para->density == 256) @@ -632,25 +635,19 @@ unsigned long dramc_init(struct dram_para *para) mctl_enable_dllx(para->tpr3); /* set refresh period */ - dramc_set_autorefresh_cycle(para->clock, para->type - 2, density); + dramc_set_autorefresh_cycle(para->clock, density); /* set timing parameters */ writel(para->tpr0, &dram->tpr0); writel(para->tpr1, &dram->tpr1); writel(para->tpr2, &dram->tpr2); - if (para->type == DRAM_MEMORY_TYPE_DDR3) { - reg_val = DRAM_MR_BURST_LENGTH(0x0); + reg_val = DRAM_MR_BURST_LENGTH(0x0); #if (defined(CONFIG_SUN5I) || defined(CONFIG_SUN7I)) - reg_val |= DRAM_MR_POWER_DOWN; + reg_val |= DRAM_MR_POWER_DOWN; #endif - reg_val |= DRAM_MR_CAS_LAT(para->cas - 4); - reg_val |= DRAM_MR_WRITE_RECOVERY(0x5); - } else if (para->type == DRAM_MEMORY_TYPE_DDR2) { - reg_val = DRAM_MR_BURST_LENGTH(0x2); - reg_val |= DRAM_MR_CAS_LAT(para->cas); - reg_val |= DRAM_MR_WRITE_RECOVERY(0x5); - } + reg_val |= DRAM_MR_CAS_LAT(para->cas - 4); + reg_val |= DRAM_MR_WRITE_RECOVERY(0x5); writel(reg_val, &dram->mr); writel(para->emr1, &dram->emr); -- cgit v1.2.3 From 935758b1d5e58ebd24d8570487455ba286ba4656 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:53 +0300 Subject: sunxi: dram: Derive write recovery delay from DRAM clock speed The write recovery time is 15ns for all JEDEC DDR3 speed bins. And instead of hardcoding it to 10 cycles, it is possible to set tighter timings based on accurate calculations. For example, DRAM clock frequencies up to 533MHz need only 8 cycles for write recovery. Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 0bbb10d5e3d..2ad685b2f8f 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -451,6 +451,21 @@ static void dramc_set_autorefresh_cycle(u32 clk, u32 density) writel(DRAM_DRR_TREFI(tREFI) | DRAM_DRR_TRFC(tRFC), &dram->drr); } +/* Calculate the value for A11, A10, A9 bits in MR0 (write recovery) */ +static u32 ddr3_write_recovery(u32 clk) +{ + u32 twr_ns = 15; /* DDR3 spec says that it is 15ns for all speed bins */ + u32 twr_ck = (twr_ns * clk + 999) / 1000; + if (twr_ck < 5) + return 1; + else if (twr_ck <= 8) + return twr_ck - 4; + else if (twr_ck <= 10) + return 5; + else + return 6; +} + /* * If the dram->ppwrsctl (SDR_DPCR) register has the lowest bit set to 1, this * means that DRAM is currently in self-refresh mode and retaining the old @@ -647,7 +662,7 @@ unsigned long dramc_init(struct dram_para *para) reg_val |= DRAM_MR_POWER_DOWN; #endif reg_val |= DRAM_MR_CAS_LAT(para->cas - 4); - reg_val |= DRAM_MR_WRITE_RECOVERY(0x5); + reg_val |= DRAM_MR_WRITE_RECOVERY(ddr3_write_recovery(para->clock)); writel(reg_val, &dram->mr); writel(para->emr1, &dram->emr); -- cgit v1.2.3 From bf4ca384ad991c09cad7dd7838c1da6756c101b9 Mon Sep 17 00:00:00 2001 From: Siarhei Siamashka Date: Sun, 3 Aug 2014 05:32:54 +0300 Subject: sunxi: dram: Autodetect DDR3 bus width and density In the case if the 'dram_para' struct does not specify the exact bus width or chip density, just use a trial and error method to find a usable configuration. Because all the major bugs in the DRAM initialization sequence are now hopefully fixed, it should be safe to re-initialize the DRAM controller multiple times until we get it configured right. The original Allwinner's boot0 bootloader also used a similar autodetection trick. The DDR3 spec contains the package pinout and addressing table for different possible chip densities. It appears to be impossible to distinguish between a single chip with 16 I/O data lines and a pair of chips with 8 I/O data lines in the case if they provide the same storage capacity. Because a single 16-bit chip has a higher density than a pair of equivalent 8-bit chips, it has stricter refresh timings. So in the case of doubt, we assume that 16-bit chips are used. Additionally, only Allwinner A20 has all A0-A15 address lines and can support densities up to 8192. The older Allwinner A10 and Allwinner A13 can only support densities up to 4096. We deliberately leave out DDR2, dual-rank configurations and the special case of a 8-bit chip with density 8192. None of these configurations seem to have been ever used in real devices. And no new devices are likely to use these exotic configurations (because only up to 2GB of RAM can be populated in any case). This DRAM autodetection feature potentially allows to have a single low performance fail-safe DDR3 initialiazation for a universal single bootloader binary, which can be compatible with all Allwinner A10/A13/A20 based devices (if the ifdefs are replaced with a runtime SoC type detection). Signed-off-by: Siarhei Siamashka Acked-by: Ian Campbell Signed-off-by: Hans de Goede --- arch/arm/cpu/armv7/sunxi/dram.c | 52 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/arch/arm/cpu/armv7/sunxi/dram.c b/arch/arm/cpu/armv7/sunxi/dram.c index 2ad685b2f8f..584f7420d7d 100644 --- a/arch/arm/cpu/armv7/sunxi/dram.c +++ b/arch/arm/cpu/armv7/sunxi/dram.c @@ -572,17 +572,13 @@ static void mctl_set_impedance(u32 zq, u32 odt_en) writel(DRAM_IOCR_ODT_EN(odt_en), &dram->iocr); } -unsigned long dramc_init(struct dram_para *para) +static unsigned long dramc_init_helper(struct dram_para *para) { struct sunxi_dram_reg *dram = (struct sunxi_dram_reg *)SUNXI_DRAMC_BASE; u32 reg_val; u32 density; int ret_val; - /* check input dram parameter structure */ - if (!para) - return 0; - /* * only single rank DDR3 is supported by this code even though the * hardware can theoretically support DDR2 and up to two ranks @@ -706,3 +702,49 @@ unsigned long dramc_init(struct dram_para *para) return get_ram_size((long *)PHYS_SDRAM_0, PHYS_SDRAM_0_SIZE); } + +unsigned long dramc_init(struct dram_para *para) +{ + unsigned long dram_size, actual_density; + + /* If the dram configuration is not provided, use a default */ + if (!para) + return 0; + + /* if everything is known, then autodetection is not necessary */ + if (para->io_width && para->bus_width && para->density) + return dramc_init_helper(para); + + /* try to autodetect the DRAM bus width and density */ + para->io_width = 16; + para->bus_width = 32; +#if defined(CONFIG_SUN4I) || defined(CONFIG_SUN5I) + /* only A0-A14 address lines on A10/A13, limiting max density to 4096 */ + para->density = 4096; +#else + /* all A0-A15 address lines on A20, which allow density 8192 */ + para->density = 8192; +#endif + + dram_size = dramc_init_helper(para); + if (!dram_size) { + /* if 32-bit bus width failed, try 16-bit bus width instead */ + para->bus_width = 16; + dram_size = dramc_init_helper(para); + if (!dram_size) { + /* if 16-bit bus width also failed, then bail out */ + return dram_size; + } + } + + /* check if we need to adjust the density */ + actual_density = (dram_size >> 17) * para->io_width / para->bus_width; + + if (actual_density != para->density) { + /* update the density and re-initialize DRAM again */ + para->density = actual_density; + dram_size = dramc_init_helper(para); + } + + return dram_size; +} -- cgit v1.2.3