From 97d5514a02efd2f464b5377460182e46a60b184e Mon Sep 17 00:00:00 2001 From: Michael Grzeschik Date: Mon, 8 Jun 2015 11:16:18 +0200 Subject: ARM: i.MX6: add Technexion Wandboard support This adds support support for the i.MX6 Technexion Wandboard. The board comes in different SoC variants and different amounts of RAM. The baord type is autodetected based on the SoC type, so all boards can be supported by the same binary image. Signed-off-by: Michael Grzeschik Signed-off-by: Sascha Hauer --- arch/arm/boards/Makefile | 1 + arch/arm/boards/technexion-wandboard/Makefile | 3 + arch/arm/boards/technexion-wandboard/board.c | 78 +++++ .../boards/technexion-wandboard/env/boot/mmc2.1 | 3 + .../technexion-wandboard/env/init/bootsource | 7 + .../flash-header-technexion-wandboard.imxcfg | 3 + arch/arm/boards/technexion-wandboard/lowlevel.c | 356 +++++++++++++++++++++ 7 files changed, 451 insertions(+) create mode 100644 arch/arm/boards/technexion-wandboard/Makefile create mode 100644 arch/arm/boards/technexion-wandboard/board.c create mode 100644 arch/arm/boards/technexion-wandboard/env/boot/mmc2.1 create mode 100644 arch/arm/boards/technexion-wandboard/env/init/bootsource create mode 100644 arch/arm/boards/technexion-wandboard/flash-header-technexion-wandboard.imxcfg create mode 100644 arch/arm/boards/technexion-wandboard/lowlevel.c (limited to 'arch/arm/boards') diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile index 013229db71..2229817dba 100644 --- a/arch/arm/boards/Makefile +++ b/arch/arm/boards/Makefile @@ -109,6 +109,7 @@ obj-$(CONFIG_MACH_SOCFPGA_EBV_SOCRATES) += ebv-socrates/ obj-$(CONFIG_MACH_SOCFPGA_TERASIC_SOCKIT) += terasic-sockit/ obj-$(CONFIG_MACH_SOLIDRUN_CUBOX) += solidrun-cubox/ obj-$(CONFIG_MACH_SOLIDRUN_MICROSOM) += solidrun-microsom/ +obj-$(CONFIG_MACH_TECHNEXION_WANDBOARD) += technexion-wandboard/ obj-$(CONFIG_MACH_TNY_A9260) += tny-a926x/ obj-$(CONFIG_MACH_TNY_A9263) += tny-a926x/ obj-$(CONFIG_MACH_TNY_A9G20) += tny-a926x/ diff --git a/arch/arm/boards/technexion-wandboard/Makefile b/arch/arm/boards/technexion-wandboard/Makefile new file mode 100644 index 0000000000..8fc428c80a --- /dev/null +++ b/arch/arm/boards/technexion-wandboard/Makefile @@ -0,0 +1,3 @@ +obj-y += board.o flash-header-technexion-wandboard.dcd.o +extra-y += flash-header-technexion-wandboard.dcd.S flash-header-technexion-wandboard.dcd +lwl-y += lowlevel.o diff --git a/arch/arm/boards/technexion-wandboard/board.c b/arch/arm/boards/technexion-wandboard/board.c new file mode 100644 index 0000000000..e7b51cc728 --- /dev/null +++ b/arch/arm/boards/technexion-wandboard/board.c @@ -0,0 +1,78 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PHY_ID_AR8031 0x004dd074 +#define AR_PHY_ID_MASK 0xffffffff + +static int ar8031_phy_fixup(struct phy_device *dev) +{ + u16 val; + + /* Ar803x phy SmartEEE feature cause link status generates glitch, + * which cause ethernet link down/up issue, so disable SmartEEE + */ + phy_write(dev, 0xd, 0x3); + phy_write(dev, 0xe, 0x805d); + phy_write(dev, 0xd, 0x4003); + + val = phy_read(dev, 0xe); + phy_write(dev, 0xe, val & ~(1 << 8)); + + /* To enable AR8031 ouput a 125MHz clk from CLK_25M */ + phy_write(dev, 0xd, 0x7); + phy_write(dev, 0xe, 0x8016); + phy_write(dev, 0xd, 0x4007); + + val = phy_read(dev, 0xe); + val &= 0xffe3; + val |= 0x18; + phy_write(dev, 0xe, val); + + /* introduce tx clock delay */ + phy_write(dev, 0x1d, 0x5); + val = phy_read(dev, 0x1e); + val |= 0x0100; + phy_write(dev, 0x1e, val); + + return 0; +} + +static int wandboard_device_init(void) +{ + if (!of_machine_is_compatible("wand,imx6dl-wandboard")) + return 0; + + phy_register_fixup_for_uid(PHY_ID_AR8031, AR_PHY_ID_MASK, ar8031_phy_fixup); + + barebox_set_hostname("wandboard"); + + imx6_bbu_internal_mmc_register_handler("mmc", "/dev/mmc2.barebox", + BBU_HANDLER_FLAG_DEFAULT); + + return 0; +} +device_initcall(wandboard_device_init); diff --git a/arch/arm/boards/technexion-wandboard/env/boot/mmc2.1 b/arch/arm/boards/technexion-wandboard/env/boot/mmc2.1 new file mode 100644 index 0000000000..d11eff7c32 --- /dev/null +++ b/arch/arm/boards/technexion-wandboard/env/boot/mmc2.1 @@ -0,0 +1,3 @@ +#!/bin/sh + +mount /dev/mmc2.1 && boot /mnt/mmc2.1 diff --git a/arch/arm/boards/technexion-wandboard/env/init/bootsource b/arch/arm/boards/technexion-wandboard/env/init/bootsource new file mode 100644 index 0000000000..732ce5b35d --- /dev/null +++ b/arch/arm/boards/technexion-wandboard/env/init/bootsource @@ -0,0 +1,7 @@ +#!/bin/sh + +if [ -n "$nv.boot.default" ]; then + exit +fi + +global.boot.default="mmc2.1 net" diff --git a/arch/arm/boards/technexion-wandboard/flash-header-technexion-wandboard.imxcfg b/arch/arm/boards/technexion-wandboard/flash-header-technexion-wandboard.imxcfg new file mode 100644 index 0000000000..33621117d4 --- /dev/null +++ b/arch/arm/boards/technexion-wandboard/flash-header-technexion-wandboard.imxcfg @@ -0,0 +1,3 @@ +loadaddr 0x00907000 +soc imx6 +dcdofs 0x400 diff --git a/arch/arm/boards/technexion-wandboard/lowlevel.c b/arch/arm/boards/technexion-wandboard/lowlevel.c new file mode 100644 index 0000000000..d3eb9a03e9 --- /dev/null +++ b/arch/arm/boards/technexion-wandboard/lowlevel.c @@ -0,0 +1,356 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __udelay(int us) +{ + volatile int i; + + for (i = 0; i < us * 4; i++); +} + +/* + * Driving strength: + * 0x30 == 40 Ohm + * 0x28 == 48 Ohm + */ + +#define IMX6DQ_DRIVE_STRENGTH 0x30 +#define IMX6SDL_DRIVE_STRENGTH 0x28 + +/* configure MX6Q/DUAL mmdc DDR io registers */ +static struct mx6dq_iomux_ddr_regs mx6dq_ddr_ioregs = { + .dram_sdclk_0 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdclk_1 = IMX6DQ_DRIVE_STRENGTH, + .dram_cas = IMX6DQ_DRIVE_STRENGTH, + .dram_ras = IMX6DQ_DRIVE_STRENGTH, + .dram_reset = IMX6DQ_DRIVE_STRENGTH, + .dram_sdcke0 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdcke1 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdba2 = 0x00000000, + .dram_sdodt0 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdodt1 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdqs0 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdqs1 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdqs2 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdqs3 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdqs4 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdqs5 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdqs6 = IMX6DQ_DRIVE_STRENGTH, + .dram_sdqs7 = IMX6DQ_DRIVE_STRENGTH, + .dram_dqm0 = IMX6DQ_DRIVE_STRENGTH, + .dram_dqm1 = IMX6DQ_DRIVE_STRENGTH, + .dram_dqm2 = IMX6DQ_DRIVE_STRENGTH, + .dram_dqm3 = IMX6DQ_DRIVE_STRENGTH, + .dram_dqm4 = IMX6DQ_DRIVE_STRENGTH, + .dram_dqm5 = IMX6DQ_DRIVE_STRENGTH, + .dram_dqm6 = IMX6DQ_DRIVE_STRENGTH, + .dram_dqm7 = IMX6DQ_DRIVE_STRENGTH, +}; + +/* configure MX6Q/DUAL mmdc GRP io registers */ +static struct mx6dq_iomux_grp_regs mx6dq_grp_ioregs = { + .grp_ddr_type = 0x000c0000, + .grp_ddrmode_ctl = 0x00020000, + .grp_ddrpke = 0x00000000, + .grp_addds = IMX6DQ_DRIVE_STRENGTH, + .grp_ctlds = IMX6DQ_DRIVE_STRENGTH, + .grp_ddrmode = 0x00020000, + .grp_b0ds = IMX6DQ_DRIVE_STRENGTH, + .grp_b1ds = IMX6DQ_DRIVE_STRENGTH, + .grp_b2ds = IMX6DQ_DRIVE_STRENGTH, + .grp_b3ds = IMX6DQ_DRIVE_STRENGTH, + .grp_b4ds = IMX6DQ_DRIVE_STRENGTH, + .grp_b5ds = IMX6DQ_DRIVE_STRENGTH, + .grp_b6ds = IMX6DQ_DRIVE_STRENGTH, + .grp_b7ds = IMX6DQ_DRIVE_STRENGTH, +}; + +/* configure MX6SOLO/DUALLITE mmdc DDR io registers */ +struct mx6sdl_iomux_ddr_regs mx6sdl_ddr_ioregs = { + .dram_sdclk_0 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdclk_1 = IMX6SDL_DRIVE_STRENGTH, + .dram_cas = IMX6SDL_DRIVE_STRENGTH, + .dram_ras = IMX6SDL_DRIVE_STRENGTH, + .dram_reset = IMX6SDL_DRIVE_STRENGTH, + .dram_sdcke0 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdcke1 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdba2 = 0x00000000, + .dram_sdodt0 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdodt1 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdqs0 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdqs1 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdqs2 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdqs3 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdqs4 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdqs5 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdqs6 = IMX6SDL_DRIVE_STRENGTH, + .dram_sdqs7 = IMX6SDL_DRIVE_STRENGTH, + .dram_dqm0 = IMX6SDL_DRIVE_STRENGTH, + .dram_dqm1 = IMX6SDL_DRIVE_STRENGTH, + .dram_dqm2 = IMX6SDL_DRIVE_STRENGTH, + .dram_dqm3 = IMX6SDL_DRIVE_STRENGTH, + .dram_dqm4 = IMX6SDL_DRIVE_STRENGTH, + .dram_dqm5 = IMX6SDL_DRIVE_STRENGTH, + .dram_dqm6 = IMX6SDL_DRIVE_STRENGTH, + .dram_dqm7 = IMX6SDL_DRIVE_STRENGTH, +}; + +/* configure MX6SOLO/DUALLITE mmdc GRP io registers */ +struct mx6sdl_iomux_grp_regs mx6sdl_grp_ioregs = { + .grp_ddr_type = 0x000c0000, + .grp_ddrmode_ctl = 0x00020000, + .grp_ddrpke = 0x00000000, + .grp_addds = IMX6SDL_DRIVE_STRENGTH, + .grp_ctlds = IMX6SDL_DRIVE_STRENGTH, + .grp_ddrmode = 0x00020000, + .grp_b0ds = IMX6SDL_DRIVE_STRENGTH, + .grp_b1ds = IMX6SDL_DRIVE_STRENGTH, + .grp_b2ds = IMX6SDL_DRIVE_STRENGTH, + .grp_b3ds = IMX6SDL_DRIVE_STRENGTH, + .grp_b4ds = IMX6SDL_DRIVE_STRENGTH, + .grp_b5ds = IMX6SDL_DRIVE_STRENGTH, + .grp_b6ds = IMX6SDL_DRIVE_STRENGTH, + .grp_b7ds = IMX6SDL_DRIVE_STRENGTH, +}; + +/* H5T04G63AFR-PB */ +static struct mx6_ddr3_cfg h5t04g63afr = { + .mem_speed = 1600, + .density = 4, + .width = 16, + .banks = 8, + .rowaddr = 15, + .coladdr = 10, + .pagesz = 2, + .trcd = 1375, + .trcmin = 4875, + .trasmin = 3500, +}; + +/* H5TQ2G63DFR-H9 */ +static struct mx6_ddr3_cfg h5tq2g63dfr = { + .mem_speed = 1333, + .density = 2, + .width = 16, + .banks = 8, + .rowaddr = 14, + .coladdr = 10, + .pagesz = 2, + .trcd = 1350, + .trcmin = 4950, + .trasmin = 3600, +}; + +static struct mx6_mmdc_calibration mx6q_2g_mmdc_calib = { + .p0_mpwldectrl0 = 0x001f001f, + .p0_mpwldectrl1 = 0x001f001f, + .p1_mpwldectrl0 = 0x001f001f, + .p1_mpwldectrl1 = 0x001f001f, + .p0_mpdgctrl0 = 0x4301030d, + .p0_mpdgctrl1 = 0x03020277, + .p1_mpdgctrl0 = 0x4300030a, + .p1_mpdgctrl1 = 0x02780248, + .p0_mprddlctl = 0x4536393b, + .p1_mprddlctl = 0x36353441, + .p0_mpwrdlctl = 0x41414743, + .p1_mpwrdlctl = 0x462f453f, +}; + +/* DDR 64bit 2GB */ +static struct mx6_ddr_sysinfo mem_q = { + .dsize = 2, + .cs1_mirror = 0, + .cs_density = 16, + .ncs = 1, + .bi_on = 1, + .rtt_nom = 1, + .rtt_wr = 0, + .ralat = 5, + .walat = 0, + .mif3_mode = 3, + .rst_to_cke = 0x23, + .sde_to_rst = 0x10, +}; + +static struct mx6_mmdc_calibration mx6dl_1g_mmdc_calib = { + .p0_mpwldectrl0 = 0x001f001f, + .p0_mpwldectrl1 = 0x001f001f, + .p1_mpwldectrl0 = 0x001f001f, + .p1_mpwldectrl1 = 0x001f001f, + .p0_mpdgctrl0 = 0x420e020e, + .p0_mpdgctrl1 = 0x02000200, + .p1_mpdgctrl0 = 0x42020202, + .p1_mpdgctrl1 = 0x01720172, + .p0_mprddlctl = 0x494c4f4c, + .p1_mprddlctl = 0x4a4c4c49, + .p0_mpwrdlctl = 0x3f3f3133, + .p1_mpwrdlctl = 0x39373f2e, +}; + +static struct mx6_mmdc_calibration mx6s_512m_mmdc_calib = { + .p0_mpwldectrl0 = 0x0040003c, + .p0_mpwldectrl1 = 0x0032003e, + .p0_mpdgctrl0 = 0x42350231, + .p0_mpdgctrl1 = 0x021a0218, + .p0_mprddlctl = 0x4b4b4e49, + .p0_mpwrdlctl = 0x3f3f3035, +}; + +/* DDR 64bit 1GB */ +static struct mx6_ddr_sysinfo mem_dl = { + .dsize = 2, + .cs1_mirror = 0, + .cs_density = 8, + .ncs = 1, + .bi_on = 1, + .rtt_nom = 1, + .rtt_wr = 0, + .ralat = 5, + .walat = 0, + .mif3_mode = 3, + .rst_to_cke = 0x23, + .sde_to_rst = 0x10, +}; + +/* DDR 32bit 512MB */ +static struct mx6_ddr_sysinfo mem_s = { + .dsize = 1, + .cs1_mirror = 0, + .cs_density = 4, + .ncs = 1, + .bi_on = 1, + .rtt_nom = 1, + .rtt_wr = 0, + .ralat = 5, + .walat = 0, + .mif3_mode = 3, + .rst_to_cke = 0x23, + .sde_to_rst = 0x10, +}; + +static unsigned long wandboard_dram_init(void) +{ + int cpu_type = __imx6_cpu_type(); + unsigned long memsize; + + switch (cpu_type) { + case IMX6_CPUTYPE_IMX6S: + mx6sdl_dram_iocfg(32, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); + mx6_dram_cfg(&mem_s, &mx6s_512m_mmdc_calib, &h5tq2g63dfr); + memsize = SZ_512M; + break; + case IMX6_CPUTYPE_IMX6DL: + mx6sdl_dram_iocfg(64, &mx6sdl_ddr_ioregs, &mx6sdl_grp_ioregs); + mx6_dram_cfg(&mem_dl, &mx6dl_1g_mmdc_calib, &h5tq2g63dfr); + memsize = SZ_1G; + break; + case IMX6_CPUTYPE_IMX6Q: + mx6dq_dram_iocfg(64, &mx6dq_ddr_ioregs, &mx6dq_grp_ioregs); + mx6_dram_cfg(&mem_q, &mx6q_2g_mmdc_calib, &h5t04g63afr); + memsize = SZ_2G; + break; + default: + return 0; + } + + __udelay(100); + + mmdc_do_write_level_calibration(); + mmdc_do_dqs_calibration(); +#ifdef DEBUG + mmdc_print_calibration_results(); +#endif + return memsize; +} + +static void setup_uart(void) +{ + void __iomem *iomuxbase = (void *)MX6_IOMUXC_BASE_ADDR; + + /* mux the uart */ + writel(0x00000003, iomuxbase + 0x4c); + writel(0x00000000, iomuxbase + 0x8fc); + + imx6_ungate_all_peripherals(); + imx6_uart_setup((void *)MX6_UART1_BASE_ADDR); + pbl_set_putc(imx_uart_putc, (void *)MX6_UART1_BASE_ADDR); + + pr_debug("\n"); +} + +static void wandboard_init(void) +{ + unsigned long sdram_size; + + setup_uart(); + + if (get_pc() > 0x10000000) + return; + + sdram_size = wandboard_dram_init(); + + pr_debug("SDRAM init finished. SDRAM size 0x%08lx\n", sdram_size); + + imx6_esdhc_start_image(2); + pr_info("Loading image from SPI flash\n"); + imx6_spi_start_image(0); +} + +extern char __dtb_z_imx6dl_wandboard_start[]; +extern char __dtb_z_imx6q_wandboard_start[]; + +static noinline void wandboard_start(void) +{ + int cpu_type = __imx6_cpu_type(); + void *dtb; + + wandboard_init(); + + switch (cpu_type) { + case IMX6_CPUTYPE_IMX6S: + case IMX6_CPUTYPE_IMX6DL: + dtb = __dtb_z_imx6dl_wandboard_start; + break; + case IMX6_CPUTYPE_IMX6Q: + dtb = __dtb_z_imx6q_wandboard_start; + break; + default: + hang(); + } + + imx6q_barebox_entry(dtb); +} + +ENTRY_FUNCTION(start_imx6_wandboard, r0, r1, r2) +{ + imx6_cpu_lowlevel_init(); + + arm_setup_stack(0x0091ffb0); + + relocate_to_current_adr(); + setup_c(); + barrier(); + + wandboard_start(); +} -- cgit v1.2.3