[U-Boot] [PATCH V3 12/18] arm: mx6: add support for Compulab cm-fx6 CoM

Nikita Kiryanov
2014-08-19T15:17:52Z

Hi Igor,

On 13/08/14 15:55, Igor Grinberg wrote:
>> +#ifdef CONFIG_FSL_ESDHC
>> +int board_mmc_init(bd_t *bis)
>> +{
>> + int i;
>> +
>> + cm_fx6_set_usdhc_iomux();
>> + for (i = 0; i < CONFIG_SYS_FSL_USDHC_NUM; i++) {
>> + usdhc_cfg[i].sdhc_clk = mxc_get_clock(usdhc_clk[i]);
>> + usdhc_cfg[i].max_bus_width = 4;
>> + fsl_esdhc_initialize(bis, &usdhc_cfg[i]);
>> + enable_usdhc_clk(1, i);
>
> Why does the board code needs to handle the mmc clocks?
> Can't this be handled in the common code?

It (probably) can, but it currently isn't. If we were to change this
I would prefer it to be done outside of this patch series.

>
>> + }
>> +
>> + return 0;
>> +}
>> +#endif
>> +
>> +int board_init(void)
>> +{
>> + gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
>> + return 0;
>> +}
>> +
>> +int checkboard(void)
>> +{
>> + puts("Board: CM-FX6\n");
>> + return 0;
>> +}
>> +
>> +static ulong bank1_size;
>> +static ulong bank2_size;
>> +
>> +void dram_init_banksize(void)
>> +{
>> + gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
>> + gd->bd->bi_dram[0].size = bank1_size;
>> + gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
>> + gd->bd->bi_dram[1].size = bank2_size;
>> +}
>> +
>> +int dram_init(void)
>> +{
>> + gd->ram_size = imx_ddr_size();
>> + switch (gd->ram_size) {
>> + case 0x10000000: /* DDR_16BIT_256MB */
>> + bank1_size = 0x10000000;
>> + bank2_size = 0;
>> + break;
>> + case 0x20000000: /* DDR_32BIT_512MB */
>> + bank1_size = 0x20000000;
>> + bank2_size = 0;
>> + break;
>> + case 0x40000000:
>> + if (is_cpu_type(MXC_CPU_MX6SOLO)) { /* DDR_32BIT_1GB */
>> + bank1_size = 0x20000000;
>> + bank2_size = 0x20000000;
>> + } else { /* DDR_64BIT_1GB */
>> + bank1_size = 0x40000000;
>> + bank2_size = 0;
>
> You don't need to init bank2_size to zero in all above cases.

Actually, I'm going to refactor and eliminate these variables, because
I see that bss is not yet ready at this stage in the boot.

>
>> + }
>> + break;
>> + case 0x80000000: /* DDR_64BIT_2GB */
>> + bank1_size = 0x40000000;
>> + bank2_size = 0x40000000;
>> + break;
>> + case 0xF0000000: /* DDR_64BIT_4GB */
>> + bank1_size = 0x70000000;
>> + bank2_size = 0x7FF00000;
>> + gd->ram_size -= 0x100000;
>> + break;
>> + default:
>> + printf("ERROR: Unsupported DRAM size 0x%lx\n", gd->ram_size);
>> + return -1;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +u32 get_board_rev(void)
>> +{
>> + return 100;
>
> Hmmm... cl_eeprom_get_board_rev()?

There's no I2C support in this patch.
I'll remove this function and reintroduce it later per your suggestion
in a different patch.

>> +static __maybe_unused enum mxc_clock usdhc_clk[3] = {
>> + MXC_ESDHC_CLK,
>> + MXC_ESDHC2_CLK,
>> + MXC_ESDHC3_CLK,
>> +};
>
> Why do you need the above structures defined here in .h file?
> Can they live in .c file that is using them?
> I think cm_fx6.c is the appropriate place for these.

I'll move them to cm_fx6.c. The code reuse was minimal anyway..

>> +static void spl_mx6s_dram_setup_iomux(void)
>> +{
>> + struct mx6sdl_iomux_ddr_regs ddr_iomux;
>> + struct mx6sdl_iomux_grp_regs grp_iomux;
>> +
>> + ddr_iomux.dram_sdqs0 = 0x00000038;
>> + ddr_iomux.dram_sdqs1 = 0x00000038;
>> + ddr_iomux.dram_sdqs2 = 0x00000038;
>> + ddr_iomux.dram_sdqs3 = 0x00000038;
>> + ddr_iomux.dram_sdqs4 = 0x00000038;
>> + ddr_iomux.dram_sdqs5 = 0x00000038;
>> + ddr_iomux.dram_sdqs6 = 0x00000038;
>> + ddr_iomux.dram_sdqs7 = 0x00000038;
>> + ddr_iomux.dram_dqm0 = 0x00000038;
>> + ddr_iomux.dram_dqm1 = 0x00000038;
>> + ddr_iomux.dram_dqm2 = 0x00000038;
>> + ddr_iomux.dram_dqm3 = 0x00000038;
>> + ddr_iomux.dram_dqm4 = 0x00000038;
>> + ddr_iomux.dram_dqm5 = 0x00000038;
>> + ddr_iomux.dram_dqm6 = 0x00000038;
>> + ddr_iomux.dram_dqm7 = 0x00000038;
>> + ddr_iomux.dram_cas = 0x00000038;
>> + ddr_iomux.dram_ras = 0x00000038;
>> + ddr_iomux.dram_sdclk_0 = 0x00000038;
>> + ddr_iomux.dram_sdclk_1 = 0x00000038;
>> + ddr_iomux.dram_sdcke0 = 0x00003000;
>> + ddr_iomux.dram_sdcke1 = 0x00003000;
>> + /*
>> + * Below DRAM_RESET[DDR_SEL] = 0 which is incorrect according to
>> + * Freescale QRM, but this is exactly the value used by the automatic
>> + * calibration script and it works also in all our tests, so we leave
>> + * it as is at this point.
>> + */
>> + ddr_iomux.dram_reset = 0x00000038;
>> + ddr_iomux.dram_sdba2 = 0x00000000;
>> + ddr_iomux.dram_sdodt0 = 0x00000038;
>> + ddr_iomux.dram_sdodt1 = 0x00000038;
>> + grp_iomux.grp_b0ds = 0x00000038;
>> + grp_iomux.grp_b1ds = 0x00000038;
>> + grp_iomux.grp_b2ds = 0x00000038;
>> + grp_iomux.grp_b3ds = 0x00000038;
>> + grp_iomux.grp_b4ds = 0x00000038;
>> + grp_iomux.grp_b5ds = 0x00000038;
>> + grp_iomux.grp_b6ds = 0x00000038;
>> + grp_iomux.grp_b7ds = 0x00000038;
>> + grp_iomux.grp_addds = 0x00000038;
>> + grp_iomux.grp_ddrmode_ctl = 0x00020000;
>> + grp_iomux.grp_ddrpke = 0x00000000;
>> + grp_iomux.grp_ddrmode = 0x00020000;
>> + grp_iomux.grp_ctlds = 0x00000038;
>> + grp_iomux.grp_ddr_type = 0x000C0000;
>
> Hmmm... Can we do the above initializations statically?

Yes.

> I mean, define the structures outside of the function and initialize
> them statically, and then only pass the structures to the below
> function. Moreover, this way, you will not need this function at all,
> but call the below from cm_fx6_spl_dram_init().

Will do (here and below)..

>
>> + mx6sdl_dram_iocfg(64, &ddr_iomux, &grp_iomux);
>> +}
>> +
>> +static void spl_mx6q_dram_setup_iomux(void)
>> +{
>> + struct mx6dq_iomux_ddr_regs ddr_iomux;
>> + struct mx6dq_iomux_grp_regs grp_iomux;
>> +

[..]

>> + mx6dq_dram_iocfg(64, &ddr_iomux, &grp_iomux);
>> +}
>> +
>> +static void spl_mx6s_dram_init(enum ddr_config dram_config, int reset)
>
> I think we have bool type in U-Boot, right?
> If so, it would be more descriptive to have bool reset.

OK

>
>> +{
>> + struct mx6_mmdc_calibration calib;
>> + struct mx6_ddr_sysinfo sysinfo;
>> + struct mx6_ddr3_cfg ddr3_cfg;
>> +
>> + if (reset)
>> + ((struct mmdc_p_regs *)MX6_MMDC_P0_MDCTL)->mdmisc = 2;
>> +
>> + calib.p0_mpwldectrl0 = 0x005B0061;
>> + calib.p0_mpwldectrl1 = 0x004F0055;

[..]

>> +
>> +static int cm_fx6_spl_dram_init(void)
>> +{
>> + u32 cpurev, imxtype;
>> + unsigned long bank1_size, bank2_size;
>> +
>> + cpurev = get_cpu_rev();
>> + imxtype = (cpurev & 0xFF000) >> 12;
>
> I would expect here at least cpu_type() usage instead of open coding.
> Or may be to spare the above construct, it is worth introducing
> a kind of get_cpu_type()? like:
>
> #define get_cpu_type() (cpu_type(get_cpu_rev()))
>
> in arch/arm/include/asm/arch-mx6/sys_proto.h
> And then you can use get_imx_cpu_type() inside the switch below.
> What do you think?

Good idea. Will add it.

>
>> +
>> + switch (imxtype) {
>> + case MXC_CPU_MX6SOLO:
>> + spl_mx6s_dram_setup_iomux();
>> +
>> + spl_mx6s_dram_init(DDR_32BIT_1GB, 0);
>> + bank1_size = get_ram_size((long int *)PHYS_SDRAM_1, 0x80000000);
>> + if (bank1_size == 0x40000000)
>> + return 0;
>> +
>> + if (bank1_size == 0x20000000) {
>> + spl_mx6s_dram_init(DDR_32BIT_512MB, 1);
>> + return 0;
>> + }
>> +
>> + spl_mx6s_dram_init(DDR_16BIT_256MB, 1);
>> + bank1_size = get_ram_size((long int *)PHYS_SDRAM_1, 0x80000000);
>> + if (bank1_size == 0x10000000)
>> + return 0;
>> +
>> + break;
>> + case MXC_CPU_MX6D:
>> + case MXC_CPU_MX6Q:
>> + spl_mx6q_dram_setup_iomux();
>> +
>> + spl_mx6q_dram_init(DDR_64BIT_4GB, 0);
>> + bank1_size = get_ram_size((long int *)PHYS_SDRAM_1, 0x80000000);
>> + if (bank1_size == 0x80000000)
>> + return 0;
>> +
>> + if (bank1_size == 0x40000000) {
>> + bank2_size = get_ram_size((long int *)PHYS_SDRAM_2,
>> + 0x80000000);
>> + if (bank2_size == 0x40000000) {
>> + /* Don't do a full reset here */
>> + spl_mx6q_dram_init(DDR_64BIT_2GB, 0);
>> + } else {
>> + spl_mx6q_dram_init(DDR_64BIT_1GB, 1);
>> + }
>> +
>> + return 0;
>> + }
>> +
>> + spl_mx6q_dram_init(DDR_32BIT_512MB, 1);
>> + bank1_size = get_ram_size((long int *)PHYS_SDRAM_1, 0x80000000);
>> + if (bank1_size == 0x20000000)
>> + return 0;
>> +
>> + spl_mx6q_dram_init(DDR_16BIT_256MB, 1);
>> + bank1_size = get_ram_size((long int *)PHYS_SDRAM_1, 0x80000000);
>> + if (bank1_size == 0x10000000)
>> + return 0;
>> +
>> + break;
>> + }
>> +
>> + return -1;
>> +}
>> +
>> +static iomux_v3_cfg_t const uart4_pads[] = {
>> + IOMUX_PADS(PAD_KEY_COL0__UART4_TX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
>> + IOMUX_PADS(PAD_KEY_ROW0__UART4_RX_DATA | MUX_PAD_CTRL(UART_PAD_CTRL)),
>> +};
>> +
>> +static void cm_fx6_setup_uart(void)
>> +{
>> + SETUP_IOMUX_PADS(uart4_pads);
>> + enable_uart_clk(1);
>> +}
>> +
>> +#ifdef CONFIG_SPL_SPI_SUPPORT
>> +static void cm_fx6_setup_ecspi(void)
>> +{
>> + enable_cspi_clock(1, 0);
>> + cm_fx6_set_ecspi_iomux();
>
> It does not really meter, but it will lok better if the sequence
> will be the same as for uart: mux and then clock...

Can do..

>
>> +}
>> +#else
>> +static void cm_fx6_setup_ecspi(void) { }
>> +#endif
>> +
>> +void board_init_f(ulong dummy)
>> +{
>> + gd = &gdata;
>> + enable_usdhc_clk(1, 2);
>
> can this be done inside board_mmc_init() or even in a common location
> like fsl_esdhc_initialize()?
>
>> + arch_cpu_init();
>> + timer_init();
>> + cm_fx6_setup_ecspi();
>> + cm_fx6_setup_uart();
>> + get_clocks();
>> + preloader_console_init();
>> + gpio_direction_output(CM_FX6_GREEN_LED, 1);
>> + if (cm_fx6_spl_dram_init()) {
>> + puts("!!!ERROR!!! DRAM detection failed!!!\n");
>> + hang();
>
> Hmmm... why hang? may be reset the cpu/board and try again?

I prefer the hang because it seems safer to me; better to not
boot than boot with bad RAM.

>
>> + }
>> +
>> + memset(__bss_start, 0, __bss_end - __bss_start);
>> + board_init_r(NULL, 0);
>> +}
>> +
>> +void spl_board_init(void)
>> +{
>> + uint soc_sbmr = readl(SRC_BASE_ADDR + 0x4);
>> + uint bt_mem_ctl = (soc_sbmr & 0x000000FF) >> 4;
>> + uint bt_mem_type = (soc_sbmr & 0x00000008) >> 3;
>> +
>> + if (bt_mem_ctl == 0x3 && !bt_mem_type)
>> + puts("Booting from SPI flash\n");
>> + else if (bt_mem_ctl == 0x4 || bt_mem_ctl == 0x5)
>> + puts("Booting from MMC\n");
>> + else
>> + puts("Unknown boot device\n");
>
> Can we call spl_boot_device() here instead?

Sure

>
>> +}
>> +
>> +#ifdef CONFIG_SPL_MMC_SUPPORT
>> +int board_mmc_init(bd_t *bis)
>> +{
>> + cm_fx6_set_usdhc_iomux();
>> +
>> + usdhc_cfg[2].sdhc_clk = mxc_get_clock(usdhc_clk[2]);
>> + usdhc_cfg[2].max_bus_width = 4;
>
> You use only one member of that array...
> It is not likely to change.
> Can we just define one instance on the stack and
> hardcode its initialization?
> This will eliminate the need for sharing the same definition
> of that array between SPL and U-Boot and thus make things simpler.

Agreed.

>> diff --git a/include/configs/cm_fx6.h b/include/configs/cm_fx6.h
>> new file mode 100644
>> index 0000000..b877b65
>> --- /dev/null
>> +++ b/include/configs/cm_fx6.h
>> @@ -0,0 +1,211 @@
>> +/*
>> + * Config file for Compulab CM-FX6 board
>> + *
>> + * Copyright (C) 2014, Compulab Ltd - http://compulab.co.il/
>> + *
>> + * Author: Nikita Kiryanov <nikita@compulab.co.il>
>> + *
>> + * SPDX-License-Identifier: GPL-2.0+
>> + */
>> +
>> +#ifndef __CONFIG_CM_FX6_H
>> +#define __CONFIG_CM_FX6_H
>> +
>> +#include <asm/arch/imx-regs.h>
>> +#include <config_distro_defaults.h>
>> +
>> +#define CONFIG_SYS_L2CACHE_OFF
>
> Hmmm... Is there a problem using cache on i.MX6 currently?
>

This define can be removed.

>
>> +#define CONFIG_EXTRA_ENV_SETTINGS \
>> + "kernel=uImage-cm-fx6\0" \
>> + "autoload=no\0" \
>> + "loadaddr=0x10800000\0" \
>> + "fdtaddr=0x11000000\0" \
>> + "console=ttymxc3,115200\0" \
>> + "ethprime=FEC0\0" \
>> + "bootscr=boot.scr\0" \
>> + "bootm_low=18000000\0" \
>> + "video_hdmi=mxcfb0:dev=hdmi,1920x1080M-32 at 50,if=RGB32\0" \
>> + "video_dvi=mxcfb0:dev=dvi,1280x800M-32 at 50,if=RGB32\0" \
>> + "fdtfile=cm-fx6.dtb\0" \
>> + "doboot=bootm ${loadaddr}\0" \
>> + "loadfdt=false\0" \
>> + "setboottypez=setenv kernel zImage-cm-fx6;" \
>> + "setenv doboot bootz ${loadaddr} - ${fdtaddr};" \
>> + "setenv loadfdt true;\0" \
>> + "setboottypem=setenv kernel uImage-cm-fx6;" \
>> + "setenv doboot bootm ${loadaddr};" \
>> + "setenv loadfdt false;\0"\
>> + "run_eboot=echo Starting EBOOT ...; "\
>> + "mmc dev ${mmcdev} && " \
>> + "mmc rescan && mmc read 10042000 a 400 && go 10042000\0" \
>> + "mmcdev=2\0" \
>> + "mmcroot=/dev/mmcblk0p2 rw rootwait\0" \
>> + "loadmmcbootscript=fatload mmc ${mmcdev} ${loadaddr} ${bootscr}\0" \
>
> Can we switch to use load instead of fatload?
>

Yes