From ea26f2ac4c4a88f6b634e26886207fc07618ebe9 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:06 -0700 Subject: configs: imx8m*_venice: enable several commands useful for scripting enable cat, xxd, and the ability for setexpr to return values in variables which are all useful for scripting. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- configs/imx8mm_venice_defconfig | 3 +++ configs/imx8mn_venice_defconfig | 3 +++ configs/imx8mp_venice_defconfig | 3 +++ 3 files changed, 9 insertions(+) diff --git a/configs/imx8mm_venice_defconfig b/configs/imx8mm_venice_defconfig index 051cd7efa81..25fc1aa0ce6 100644 --- a/configs/imx8mm_venice_defconfig +++ b/configs/imx8mm_venice_defconfig @@ -66,6 +66,9 @@ CONFIG_CMD_MMC=y CONFIG_CMD_PCI=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_CAT=y +CONFIG_CMD_SETEXPR_FMT=y +CONFIG_CMD_XXD=y CONFIG_CMD_DHCP6=y CONFIG_CMD_TFTPPUT=y CONFIG_SYS_DISABLE_AUTOLOAD=y diff --git a/configs/imx8mn_venice_defconfig b/configs/imx8mn_venice_defconfig index fd8701e11a4..7a22535e5c9 100644 --- a/configs/imx8mn_venice_defconfig +++ b/configs/imx8mn_venice_defconfig @@ -66,6 +66,9 @@ CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_USB=y CONFIG_CMD_USB_MASS_STORAGE=y +CONFIG_CMD_CAT=y +CONFIG_CMD_SETEXPR_FMT=y +CONFIG_CMD_XXD=y CONFIG_CMD_DHCP6=y CONFIG_CMD_TFTPPUT=y CONFIG_SYS_DISABLE_AUTOLOAD=y diff --git a/configs/imx8mp_venice_defconfig b/configs/imx8mp_venice_defconfig index b91e69a25e2..8aa9232cc8d 100644 --- a/configs/imx8mp_venice_defconfig +++ b/configs/imx8mp_venice_defconfig @@ -68,6 +68,9 @@ CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_PCI=y CONFIG_CMD_USB=y +CONFIG_CMD_CAT=y +CONFIG_CMD_SETEXPR_FMT=y +CONFIG_CMD_XXD=y CONFIG_CMD_DHCP6=y CONFIG_CMD_TFTPPUT=y CONFIG_SYS_DISABLE_AUTOLOAD=y -- cgit v1.3.1 From 2f1c3e1f9efb77a0a48c201e0e6004998dda85b7 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:07 -0700 Subject: configs: imx8m*_venice: enable GPT support Enable support for working with General Partition Tables via the 'gpt' command. Also enable support for generating random UUID's for GPT. See: doc/README.gpt for examples Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- configs/imx8mm_venice_defconfig | 2 ++ configs/imx8mn_venice_defconfig | 2 ++ configs/imx8mp_venice_defconfig | 2 ++ 3 files changed, 6 insertions(+) diff --git a/configs/imx8mm_venice_defconfig b/configs/imx8mm_venice_defconfig index 25fc1aa0ce6..0f263a3ecb8 100644 --- a/configs/imx8mm_venice_defconfig +++ b/configs/imx8mm_venice_defconfig @@ -61,6 +61,8 @@ CONFIG_CMD_MEMTEST=y CONFIG_CMD_CLK=y CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_GPT=y +CONFIG_CMD_GPT_RENAME=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_PCI=y diff --git a/configs/imx8mn_venice_defconfig b/configs/imx8mn_venice_defconfig index 7a22535e5c9..4fc8e146b06 100644 --- a/configs/imx8mn_venice_defconfig +++ b/configs/imx8mn_venice_defconfig @@ -62,6 +62,8 @@ CONFIG_CMD_MEMTEST=y CONFIG_CMD_CLK=y CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_GPT=y +CONFIG_CMD_GPT_RENAME=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_USB=y diff --git a/configs/imx8mp_venice_defconfig b/configs/imx8mp_venice_defconfig index 8aa9232cc8d..8f591f4c7dc 100644 --- a/configs/imx8mp_venice_defconfig +++ b/configs/imx8mp_venice_defconfig @@ -64,6 +64,8 @@ CONFIG_CMD_MEMTEST=y CONFIG_CMD_CLK=y CONFIG_CMD_FUSE=y CONFIG_CMD_GPIO=y +CONFIG_CMD_GPT=y +CONFIG_CMD_GPT_RENAME=y CONFIG_CMD_I2C=y CONFIG_CMD_MMC=y CONFIG_CMD_PCI=y -- cgit v1.3.1 From 66e8b17eeef52ec78286386a871675d8bfb898dd Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:08 -0700 Subject: board: venice: move soc-specific dram config into soc-specific files Move the determination of the dram timings into the soc-specific files. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- board/gateworks/venice/lpddr4_timing.h | 14 +---- board/gateworks/venice/lpddr4_timing_imx8mm.c | 57 +++++++++++++----- board/gateworks/venice/lpddr4_timing_imx8mn.c | 31 +++++++++- board/gateworks/venice/lpddr4_timing_imx8mp.c | 23 ++++++- board/gateworks/venice/spl.c | 86 ++++++--------------------- 5 files changed, 108 insertions(+), 103 deletions(-) diff --git a/board/gateworks/venice/lpddr4_timing.h b/board/gateworks/venice/lpddr4_timing.h index d19902f10ec..21997f6fb2a 100644 --- a/board/gateworks/venice/lpddr4_timing.h +++ b/board/gateworks/venice/lpddr4_timing.h @@ -6,18 +6,6 @@ #ifndef __LPDDR4_TIMING_H__ #define __LPDDR4_TIMING_H__ -#ifdef CONFIG_IMX8MM -extern struct dram_timing_info dram_timing_512mb; -extern struct dram_timing_info dram_timing_1gb; -extern struct dram_timing_info dram_timing_2gb; -extern struct dram_timing_info dram_timing_4gb; -#elif CONFIG_IMX8MN -extern struct dram_timing_info dram_timing_1gb_single_die; -extern struct dram_timing_info dram_timing_2gb_single_die; -extern struct dram_timing_info dram_timing_2gb_dual_die; -#elif CONFIG_IMX8MP -extern struct dram_timing_info dram_timing_1gb_single_die; -extern struct dram_timing_info dram_timing_4gb_dual_die; -#endif +extern struct dram_timing_info *spl_dram_init(const char *model, int sizemb); #endif /* __LPDDR4_TIMING_H__ */ diff --git a/board/gateworks/venice/lpddr4_timing_imx8mm.c b/board/gateworks/venice/lpddr4_timing_imx8mm.c index 3f2c090a94f..39e4e46490f 100644 --- a/board/gateworks/venice/lpddr4_timing_imx8mm.c +++ b/board/gateworks/venice/lpddr4_timing_imx8mm.c @@ -1830,7 +1830,7 @@ static struct dram_fsp_msg ddr_dram_fsp_msg_512mb[] = { }; /* ddr timing config params */ -struct dram_timing_info dram_timing_512mb = { +static struct dram_timing_info dram_timing_512mb = { .ddrc_cfg = ddr_ddrc_cfg_512mb, .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_512mb), .ddrphy_cfg = ddr_ddrphy_cfg_512mb, @@ -2489,7 +2489,7 @@ static struct dram_fsp_msg lpddr4_dram_fsp_msg_1gb[] = { }; /* lpddr4 timing config params */ -struct dram_timing_info dram_timing_1gb = { +static struct dram_timing_info dram_timing_1gb = { .ddrc_cfg = lpddr4_ddrc_cfg_1gb, .ddrc_cfg_num = ARRAY_SIZE(lpddr4_ddrc_cfg_1gb), .ddrphy_cfg = lpddr4_ddrphy_cfg_1gb, @@ -3005,7 +3005,7 @@ static struct dram_fsp_msg lpddr4_dram_fsp_msg_4gb[] = { }; /* lpddr4 timing config params */ -struct dram_timing_info dram_timing_4gb = { +static struct dram_timing_info dram_timing_4gb = { .ddrc_cfg = lpddr4_ddrc_cfg_4gb, .ddrc_cfg_num = ARRAY_SIZE(lpddr4_ddrc_cfg_4gb), .ddrphy_cfg = lpddr4_ddrphy_cfg_4gb, @@ -3140,12 +3140,12 @@ static struct dram_cfg_param lpddr4_ddrphy_cfg_2gb[] = { { 0x100a7, 0x7 }, { 0x110a0, 0x0 }, { 0x110a1, 0x1 }, - { 0x110a2, 0x2 }, - { 0x110a3, 0x3 }, - { 0x110a4, 0x4 }, - { 0x110a5, 0x5 }, - { 0x110a6, 0x6 }, - { 0x110a7, 0x7 }, + { 0x110a2, 0x3 }, + { 0x110a3, 0x4 }, + { 0x110a4, 0x5 }, + { 0x110a5, 0x2 }, + { 0x110a6, 0x7 }, + { 0x110a7, 0x6 }, { 0x120a0, 0x0 }, { 0x120a1, 0x1 }, { 0x120a2, 0x3 }, @@ -3156,12 +3156,12 @@ static struct dram_cfg_param lpddr4_ddrphy_cfg_2gb[] = { { 0x120a7, 0x6 }, { 0x130a0, 0x0 }, { 0x130a1, 0x1 }, - { 0x130a2, 0x5 }, - { 0x130a3, 0x2 }, - { 0x130a4, 0x3 }, - { 0x130a5, 0x4 }, - { 0x130a6, 0x7 }, - { 0x130a7, 0x6 }, + { 0x130a2, 0x2 }, + { 0x130a3, 0x3 }, + { 0x130a4, 0x4 }, + { 0x130a5, 0x5 }, + { 0x130a6, 0x6 }, + { 0x130a7, 0x7 }, { 0x1005f, 0x1ff }, { 0x1015f, 0x1ff }, { 0x1105f, 0x1ff }, @@ -3521,7 +3521,7 @@ static struct dram_fsp_msg lpddr4_dram_fsp_msg_2gb[] = { }; /* lpddr4 timing config params */ -struct dram_timing_info dram_timing_2gb = { +static struct dram_timing_info dram_timing_2gb = { .ddrc_cfg = lpddr4_ddrc_cfg_2gb, .ddrc_cfg_num = ARRAY_SIZE(lpddr4_ddrc_cfg_2gb), .ddrphy_cfg = lpddr4_ddrphy_cfg_2gb, @@ -3534,3 +3534,28 @@ struct dram_timing_info dram_timing_2gb = { .ddrphy_pie_num = ARRAY_SIZE(lpddr4_phy_pie), .fsp_table = { 3000, 400, 100, }, }; + +struct dram_timing_info *spl_dram_init(const char *model, int sizemb) +{ + struct dram_timing_info *dram_timing; + + switch (sizemb) { + case 512: + dram_timing = &dram_timing_512mb; + break; + case 1024: + dram_timing = &dram_timing_1gb; + break; + case 2048: + dram_timing = &dram_timing_2gb; + break; + case 4096: + dram_timing = &dram_timing_4gb; + break; + default: + printf("unsupported"); + dram_timing = &dram_timing_1gb; + } + + return dram_timing; +} diff --git a/board/gateworks/venice/lpddr4_timing_imx8mn.c b/board/gateworks/venice/lpddr4_timing_imx8mn.c index 9ba2d2571ce..e7d04822c9c 100644 --- a/board/gateworks/venice/lpddr4_timing_imx8mn.c +++ b/board/gateworks/venice/lpddr4_timing_imx8mn.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ #include +#include #include /* @@ -1425,7 +1426,7 @@ static struct dram_fsp_msg ddr_dram_fsp_msg_1gb_single_die[] = { }; /* ddr timing config params */ -struct dram_timing_info dram_timing_1gb_single_die = { +static struct dram_timing_info dram_timing_1gb_single_die = { .ddrc_cfg = ddr_ddrc_cfg_1gb_single_die, .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_1gb_single_die), .ddrphy_cfg = ddr_ddrphy_cfg_1gb_single_die, @@ -1890,7 +1891,7 @@ static struct dram_fsp_msg ddr_dram_fsp_msg_2gb_single_die[] = { }; /* ddr timing config params */ -struct dram_timing_info dram_timing_2gb_single_die = { +static struct dram_timing_info dram_timing_2gb_single_die = { .ddrc_cfg = ddr_ddrc_cfg_2gb_single_die, .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_2gb_single_die), .ddrphy_cfg = ddr_ddrphy_cfg_2gb_single_die, @@ -2354,7 +2355,7 @@ static struct dram_fsp_msg ddr_dram_fsp_msg_2gb_dual_die[] = { }; /* ddr timing config params */ -struct dram_timing_info dram_timing_2gb_dual_die = { +static struct dram_timing_info dram_timing_2gb_dual_die = { .ddrc_cfg = ddr_ddrc_cfg_2gb_dual_die, .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_2gb_dual_die), .ddrphy_cfg = ddr_ddrphy_cfg_2gb_dual_die, @@ -2367,3 +2368,27 @@ struct dram_timing_info dram_timing_2gb_dual_die = { .ddrphy_pie_num = ARRAY_SIZE(ddr_phy_pie), .fsp_table = { 3200, 400, 100, }, }; + +struct dram_timing_info *spl_dram_init(const char *model, int sizemb) +{ + struct dram_timing_info *dram_timing; + + switch (sizemb) { + case 1024: + dram_timing = &dram_timing_1gb_single_die; + break; + case 2048: + if (!strcmp(model, "GW7902-SP466-A") || + !strcmp(model, "GW7902-SP466-B")) { + dram_timing = &dram_timing_2gb_dual_die; + } else { + dram_timing = &dram_timing_2gb_single_die; + } + break; + default: + printf("unsupported"); + dram_timing = &dram_timing_2gb_dual_die; + } + + return dram_timing; +} diff --git a/board/gateworks/venice/lpddr4_timing_imx8mp.c b/board/gateworks/venice/lpddr4_timing_imx8mp.c index 56c6e2b5cff..36c4cb147e8 100644 --- a/board/gateworks/venice/lpddr4_timing_imx8mp.c +++ b/board/gateworks/venice/lpddr4_timing_imx8mp.c @@ -1832,7 +1832,7 @@ struct dram_fsp_msg ddr_dram_fsp_msg_1gb_single_die[] = { }; /* ddr timing config params */ -struct dram_timing_info dram_timing_1gb_single_die = { +static struct dram_timing_info dram_timing_1gb_single_die = { .ddrc_cfg = ddr_ddrc_cfg_1gb_single_die, .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_1gb_single_die), .ddrphy_cfg = ddr_ddrphy_cfg_1gb_single_die, @@ -2364,7 +2364,7 @@ static struct dram_fsp_msg ddr_dram_fsp_msg_4gb_dual_die[] = { }; /* ddr timing config params */ -struct dram_timing_info dram_timing_4gb_dual_die = { +static struct dram_timing_info dram_timing_4gb_dual_die = { .ddrc_cfg = ddr_ddrc_cfg_4gb_dual_die, .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_4gb_dual_die), .ddrphy_cfg = ddr_ddrphy_cfg_4gb_dual_die, @@ -2377,3 +2377,22 @@ struct dram_timing_info dram_timing_4gb_dual_die = { .ddrphy_pie_num = ARRAY_SIZE(ddr_phy_pie), .fsp_table = { 4000, 400, 100, }, }; + +struct dram_timing_info *spl_dram_init(const char *model, int sizemb) +{ + struct dram_timing_info *dram_timing; + + switch (sizemb) { + case 1024: + dram_timing = &dram_timing_1gb_single_die; + break; + case 4096: + dram_timing = &dram_timing_4gb_dual_die; + break; + default: + printf("unsupported"); + dram_timing = &dram_timing_4gb_dual_die; + } + + return dram_timing; +} diff --git a/board/gateworks/venice/spl.c b/board/gateworks/venice/spl.c index bcdc1a2a468..275f9d3453e 100644 --- a/board/gateworks/venice/spl.c +++ b/board/gateworks/venice/spl.c @@ -32,69 +32,6 @@ #define PCIE_RSTN IMX_GPIO_NR(4, 6) -static void spl_dram_init(int size) -{ - struct dram_timing_info *dram_timing; - - switch (size) { -#ifdef CONFIG_IMX8MM - case 512: - dram_timing = &dram_timing_512mb; - break; - case 1024: - dram_timing = &dram_timing_1gb; - break; - case 2048: - dram_timing = &dram_timing_2gb; - break; - case 4096: - dram_timing = &dram_timing_4gb; - break; - default: - printf("Unknown DDR configuration: %d MiB\n", size); - dram_timing = &dram_timing_1gb; - size = 1024; -#elif CONFIG_IMX8MN - case 1024: - dram_timing = &dram_timing_1gb_single_die; - break; - case 2048: - if (!strcmp(eeprom_get_model(), "GW7902-SP466-A") || - !strcmp(eeprom_get_model(), "GW7902-SP466-B")) { - dram_timing = &dram_timing_2gb_dual_die; - } else { - dram_timing = &dram_timing_2gb_single_die; - } - break; - default: - printf("Unknown DDR configuration: %d MiB\n", size); - dram_timing = &dram_timing_2gb_dual_die; - size = 2048; -#elif CONFIG_IMX8MP - case 1024: - dram_timing = &dram_timing_1gb_single_die; - break; - case 4096: - dram_timing = &dram_timing_4gb_dual_die; - break; - default: - printf("Unknown DDR configuration: %d GiB\n", size); - dram_timing = &dram_timing_4gb_dual_die; - size = 4096; -#endif - } - - printf("DRAM : LPDDR4 "); - if (size > 512) - printf("%d GiB", size / 1024); - else - printf("%d MiB", size); - printf(" %dMT/s %dMHz\n", - dram_timing->fsp_msg[0].drate, - dram_timing->fsp_msg[0].drate / 2); - ddr_init(dram_timing); -} - /* * Model specific PMIC adjustments necessary prior to DRAM init * @@ -118,9 +55,8 @@ static int dm_i2c_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) return dm_i2c_write(dev, reg, &val, 1); } -static int power_init_board(struct udevice *gsc) +static int power_init_board(const char *model, struct udevice *gsc) { - const char *model = eeprom_get_model(); struct udevice *bus; struct udevice *dev; int ret; @@ -251,9 +187,11 @@ static int power_init_board(struct udevice *gsc) void board_init_f(ulong dummy) { + struct dram_timing_info *dram_timing; struct udevice *bus, *dev; + const char *model; + int dram_szmb; int i, ret; - int dram_sz; arch_cpu_init(); @@ -311,13 +249,23 @@ void board_init_f(ulong dummy) break; mdelay(1); } - dram_sz = venice_eeprom_init(0); + dram_szmb = venice_eeprom_init(0); + model = eeprom_get_model(); /* PMIC */ - power_init_board(dev); + power_init_board(model, dev); /* DDR initialization */ - spl_dram_init(dram_sz); + printf("DRAM : LPDDR4 "); + if (dram_szmb > 512) + printf("%d GiB", dram_szmb / 1024); + else + printf("%d MiB", dram_szmb); + dram_timing = spl_dram_init(model, dram_szmb); + printf(" %dMT/s %dMHz\n", + dram_timing->fsp_msg[0].drate, + dram_timing->fsp_msg[0].drate / 2); + ddr_init(dram_timing); board_init_r(NULL, 0); } -- cgit v1.3.1 From 1bf9f1e5501819dd39abcbfc87c823d4639c128e Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:09 -0700 Subject: board: venice: fix dram bus config for GW7902/GW7903/GW7904 The GW7902/GW7903/GW7904 have an alternate databus layout affecting a few of the DDRC and DDR PHY registers. The 512MB configuration used this alternate bus layout. Change the 512MB config to the standard bus configuration and add a generic function to patch the DDRC/PHY configs for the alternate bus layout. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- board/gateworks/venice/lpddr4_timing_imx8mm.c | 46 ++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/board/gateworks/venice/lpddr4_timing_imx8mm.c b/board/gateworks/venice/lpddr4_timing_imx8mm.c index 39e4e46490f..956071c5125 100644 --- a/board/gateworks/venice/lpddr4_timing_imx8mm.c +++ b/board/gateworks/venice/lpddr4_timing_imx8mm.c @@ -6,6 +6,7 @@ */ #include +#include #include #include @@ -1333,7 +1334,7 @@ static struct dram_cfg_param ddr_ddrc_cfg_512mb[] = { { 0x3d400304, 0x1 }, { 0x3d400030, 0x1 }, { 0x3d400000, 0xa1080020 }, - { 0x3d400020, 0x203 }, + { 0x3d400020, 0x223 }, { 0x3d400024, 0x3a980 }, { 0x3d400064, 0x5b0062 }, { 0x3d4000d0, 0xc00305ba }, @@ -1385,7 +1386,7 @@ static struct dram_cfg_param ddr_ddrc_cfg_512mb[] = { { 0x3d400498, 0x620096 }, { 0x3d40049c, 0x1100e07 }, { 0x3d4004a0, 0xc8012c }, - { 0x3d402020, 0x1 }, + { 0x3d402020, 0x21 }, { 0x3d402024, 0x7d00 }, { 0x3d402050, 0x20d040 }, { 0x3d402064, 0xc000d }, @@ -1410,7 +1411,7 @@ static struct dram_cfg_param ddr_ddrc_cfg_512mb[] = { { 0x3d402194, 0x80303 }, { 0x3d4021b4, 0x100 }, { 0x3d4020f4, 0xc99 }, - { 0x3d403020, 0x1 }, + { 0x3d403020, 0x21 }, { 0x3d403024, 0x1f40 }, { 0x3d403050, 0x20d040 }, { 0x3d403064, 0x30004 }, @@ -1459,9 +1460,9 @@ static struct dram_cfg_param ddr_ddrphy_cfg_512mb[] = { { 0x120a0, 0x0 }, { 0x120a1, 0x1 }, { 0x120a2, 0x3 }, - { 0x120a3, 0x4 }, + { 0x120a3, 0x2 }, { 0x120a4, 0x5 }, - { 0x120a5, 0x2 }, + { 0x120a5, 0x4 }, { 0x120a6, 0x7 }, { 0x120a7, 0x6 }, { 0x130a0, 0x0 }, @@ -3535,6 +3536,28 @@ static struct dram_timing_info dram_timing_2gb = { .fsp_table = { 3000, 400, 100, }, }; +static void apply_cfg_patch(struct dram_cfg_param *cfg, int cfg_sz, + struct dram_cfg_param *patch, int patch_sz) +{ + int i, j; + + for (i = 0; i < cfg_sz; i++) + for (j = 0; j < patch_sz; j++) + if (cfg[i].reg == patch[j].reg) + cfg[i].val = patch[j].val; +} + +static struct dram_cfg_param ddr_ddrc_cfg_alt_patch[] = { + { 0x3d400020, 0x203}, + { 0x3d402020, 0x1}, + { 0x3d403020, 0x1} +}; + +static struct dram_cfg_param ddr_ddrphy_cfg_alt_patch[] = { + { 0x120a3, 0x4 }, + { 0x120a5, 0x2 }, +}; + struct dram_timing_info *spl_dram_init(const char *model, int sizemb) { struct dram_timing_info *dram_timing; @@ -3557,5 +3580,18 @@ struct dram_timing_info *spl_dram_init(const char *model, int sizemb) dram_timing = &dram_timing_1gb; } + /* apply ddrc/phy register changes for alternate dram bus layout */ + if (!strncmp(model, "GW7902", 6) || + !strncmp(model, "GW7903", 6) || + !strncmp(model, "GW7904", 6)) { + apply_cfg_patch(dram_timing->ddrc_cfg, dram_timing->ddrc_cfg_num, + ddr_ddrc_cfg_alt_patch, + ARRAY_SIZE(ddr_ddrc_cfg_alt_patch)); + + apply_cfg_patch(dram_timing->ddrphy_cfg, dram_timing->ddrphy_cfg_num, + ddr_ddrphy_cfg_alt_patch, + ARRAY_SIZE(ddr_ddrphy_cfg_alt_patch)); + } + return dram_timing; } -- cgit v1.3.1 From c83ab8264087282bbd339cc6c55f2033a6667ff9 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:10 -0700 Subject: board: venice: fix dram size for GW7901-SP486 The GW7901-SP486 with the exception of the -C revision has 2GB DRAM loaded but incorrectly specifies 1GB in the EEPROM. Adjust the DRAM size to account for this. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- board/gateworks/venice/eeprom.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/board/gateworks/venice/eeprom.c b/board/gateworks/venice/eeprom.c index afaabf34879..abe25256e66 100644 --- a/board/gateworks/venice/eeprom.c +++ b/board/gateworks/venice/eeprom.c @@ -350,6 +350,11 @@ int venice_eeprom_init(int quiet) if (!quiet) eeprom_info(false); + if (!strncmp(venice_model, "GW7901-SP486", 12) && + strcmp(venice_model, "GW7901-SP486-C")) { + return 2048; + } + return (16 << som_info.sdram_size); } -- cgit v1.3.1 From ea04f7261ef84eb1b5cecb60e5e45c75c760626c Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:11 -0700 Subject: board: venice: use baseboard model for family The venice family of baseboards which is normally GW7xxx is being expanded to GW8xxx so we need to use the baseboard number instead of the som. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- board/gateworks/venice/eeprom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/board/gateworks/venice/eeprom.c b/board/gateworks/venice/eeprom.c index abe25256e66..351d18886f1 100644 --- a/board/gateworks/venice/eeprom.c +++ b/board/gateworks/venice/eeprom.c @@ -322,7 +322,7 @@ int venice_eeprom_init(int quiet) /* create model strings */ if (base_info.model[0]) { sprintf(venice_model, "GW%c%c%c%c-%c%c-", - som_info.model[2], /* family */ + base_info.model[2], /* family */ base_info.model[3], /* baseboard */ base_info.model[4], base_info.model[5], /* subload of baseboard */ som_info.model[4], som_info.model[5]); /* last 2digits of SOM */ -- cgit v1.3.1 From b1ead5a2240002f880e6560bc7715eb6b250dd6d Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:12 -0700 Subject: board: venice: use SOM model for PMIC adjustment on SOM Use the SOM model to adjust PMIC settings on SOM's. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- board/gateworks/venice/eeprom.c | 7 +++++++ board/gateworks/venice/eeprom.h | 1 + board/gateworks/venice/spl.c | 6 ++---- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/board/gateworks/venice/eeprom.c b/board/gateworks/venice/eeprom.c index 351d18886f1..41f620c90e7 100644 --- a/board/gateworks/venice/eeprom.c +++ b/board/gateworks/venice/eeprom.c @@ -19,6 +19,7 @@ struct venice_board_info som_info; struct venice_board_info base_info; char venice_model[32]; +char venice_som_model[32]; char venice_baseboard_model[32]; u32 venice_serial; @@ -315,6 +316,7 @@ int venice_eeprom_init(int quiet) memset(&som_info, 0, sizeof(som_info)); return 0; } + strlcpy(venice_som_model, som_info.model, sizeof(venice_som_model)); /* read optional baseboard EEPROM */ eeprom_read(BASEBOARD_EEPROM_BUSNO, BASEBOARD_EEPROM_ADDR, 2, &base_info); @@ -368,6 +370,11 @@ const char *eeprom_get_model(void) return venice_model; } +const char *eeprom_get_som_model(void) +{ + return venice_som_model; +} + const char *eeprom_get_baseboard_model(void) { return venice_baseboard_model; diff --git a/board/gateworks/venice/eeprom.h b/board/gateworks/venice/eeprom.h index bb7a5fa9ad1..30cd347d945 100644 --- a/board/gateworks/venice/eeprom.h +++ b/board/gateworks/venice/eeprom.h @@ -26,6 +26,7 @@ struct venice_board_info { int venice_eeprom_init(int quiet); const char *eeprom_get_model(void); +const char *eeprom_get_som_model(void); const char *eeprom_get_baseboard_model(void); const char *eeprom_get_dtb_name(int level, char *buf, int len); int eeprom_getmac(int index, uint8_t *enetaddr); diff --git a/board/gateworks/venice/spl.c b/board/gateworks/venice/spl.c index 275f9d3453e..f14ab1497d7 100644 --- a/board/gateworks/venice/spl.c +++ b/board/gateworks/venice/spl.c @@ -57,6 +57,7 @@ static int dm_i2c_clrsetbits(struct udevice *dev, uint reg, uint clr, uint set) static int power_init_board(const char *model, struct udevice *gsc) { + const char *som = eeprom_get_som_model(); struct udevice *bus; struct udevice *dev; int ret; @@ -77,10 +78,7 @@ static int power_init_board(const char *model, struct udevice *gsc) } } - if ((!strncmp(model, "GW71", 4)) || - (!strncmp(model, "GW72", 4)) || - (!strncmp(model, "GW73", 4)) || - (!strncmp(model, "GW75", 4))) { + if (!strncmp(som, "GW70", 4)) { ret = uclass_get_device_by_seq(UCLASS_I2C, 0, &bus); if (ret) { printf("PMIC : failed I2C1 probe: %d\n", ret); -- cgit v1.3.1 From 5e726768905bd00082b711e05e3021ebe36c1767 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:13 -0700 Subject: board: venice: flip logic for GSC supervisor enable Flip the logic used to determine if a board has the proper hardware to support enabling the GSC voltage supervisor so that we do not need to keep adding new models to the list. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- board/gateworks/venice/spl.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/board/gateworks/venice/spl.c b/board/gateworks/venice/spl.c index f14ab1497d7..e813f3e763e 100644 --- a/board/gateworks/venice/spl.c +++ b/board/gateworks/venice/spl.c @@ -62,14 +62,16 @@ static int power_init_board(const char *model, struct udevice *gsc) struct udevice *dev; int ret; - /* Enable GSC voltage supervisor for new board models */ - if ((!strncmp(model, "GW7100", 6) && model[10] > 'D') || - (!strncmp(model, "GW7101", 6) && model[10] > 'D') || - (!strncmp(model, "GW7200", 6) && model[10] > 'E') || - (!strncmp(model, "GW7201", 6) && model[10] > 'E') || - (!strncmp(model, "GW7300", 6) && model[10] > 'E') || - (!strncmp(model, "GW7301", 6) && model[10] > 'E') || - (!strncmp(model, "GW740", 5) && model[7] > 'B')) { + /* Enable GSC voltage supervisor only for newew board models */ + if ((!strncmp(model, "GW7100", 6) && model[10] < 'E') || + (!strncmp(model, "GW7101", 6) && model[10] < 'E') || + (!strncmp(model, "GW7200", 6) && model[10] < 'F') || + (!strncmp(model, "GW7201", 6) && model[10] < 'F') || + (!strncmp(model, "GW7300", 6) && model[10] < 'F') || + (!strncmp(model, "GW7301", 6) && model[10] < 'F') || + (!strncmp(model, "GW740", 5) && model[7] < 'C')) { + printf("GSC : voltage supervisor disabled\n"); + } else { u8 ver; if (!dm_i2c_read(gsc, 14, &ver, 1) && ver > 62) { -- cgit v1.3.1 From 9eebca1025037e8a58cf442646042f41f0893151 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:14 -0700 Subject: board: venice: add imx8mp-gw82xx support The Gateworks GW82XX-2X is an ARM based single board computer (SBC) comprised of the i.MX8M Plus based gw702x SoM and the gw82xx baseboard featuring: - i.MX8M Plus SoC - LPDDR4 DRAM - eMMC FLASH - Gateworks System Controller (GSC) - microSD (1.8V/3.3V Capable) - panel status bi-color LED - pushbutton switch - fan controller with tachometer - USB Type-C connector - PCIe switch - 2x GbE RJ45 connectors - multi-protocol RS232/RS485/RS422 Serial ports - 2x Flexible Socket Adapters with SDIO/UART/USB/PCIe (for M.2 and miniPCIe expansion) - 2x isolated CAN - GPS - accelerometer - magnetometer - off-board connectors for: SPI, GPIO, I2C, ADC - Wide range DC power input - support for 802.3at PoE (via adapter) Add support for it by providing its device-tree. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- arch/arm/dts/imx8mp-venice-gw82xx-2x-u-boot.dtsi | 49 ++++++++++++++++++++++++ configs/imx8mp_venice_defconfig | 2 +- 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 arch/arm/dts/imx8mp-venice-gw82xx-2x-u-boot.dtsi diff --git a/arch/arm/dts/imx8mp-venice-gw82xx-2x-u-boot.dtsi b/arch/arm/dts/imx8mp-venice-gw82xx-2x-u-boot.dtsi new file mode 100644 index 00000000000..2d58b3b8ab7 --- /dev/null +++ b/arch/arm/dts/imx8mp-venice-gw82xx-2x-u-boot.dtsi @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2025 Gateworks Corporation + */ +#include "imx8mp-venice-gw702x-u-boot.dtsi" + +&gpio4 { + dio_1 { + gpio-hog; + input; + gpios = <8 GPIO_ACTIVE_HIGH>; + line-name = "dio1"; + }; + + dio_0 { + gpio-hog; + input; + gpios = <11 GPIO_ACTIVE_HIGH>; + line-name = "dio0#"; + }; + + usb1mux { + gpio-hog; + output-high; + gpios = <17 GPIO_ACTIVE_HIGH>; + line-name = "usb1_mux"; + }; + + rs485_en { + gpio-hog; + output-low; + gpios = <22 GPIO_ACTIVE_HIGH>; + line-name = "rs485_en"; + }; + + rs485_term { + gpio-hog; + output-low; + gpios = <23 GPIO_ACTIVE_HIGH>; + line-name = "rs485_term"; + }; + + rs485_half { + gpio-hog; + output-low; + gpios = <27 GPIO_ACTIVE_HIGH>; + line-name = "rs485_hd"; + }; +}; diff --git a/configs/imx8mp_venice_defconfig b/configs/imx8mp_venice_defconfig index 8f591f4c7dc..10eac0a0c78 100644 --- a/configs/imx8mp_venice_defconfig +++ b/configs/imx8mp_venice_defconfig @@ -88,7 +88,7 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_EFI_PARTITION is not set CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y -CONFIG_OF_LIST="freescale/imx8mp-venice-gw71xx-2x freescale/imx8mp-venice-gw72xx-2x freescale/imx8mp-venice-gw73xx-2x freescale/imx8mp-venice-gw74xx freescale/imx8mp-venice-gw75xx-2x" +CONFIG_OF_LIST="freescale/imx8mp-venice-gw71xx-2x freescale/imx8mp-venice-gw72xx-2x freescale/imx8mp-venice-gw73xx-2x freescale/imx8mp-venice-gw74xx freescale/imx8mp-venice-gw75xx-2x freescale/imx8mp-venice-gw82xx-2x" CONFIG_ENV_IS_IN_MMC=y CONFIG_SYS_REDUNDAND_ENVIRONMENT=y CONFIG_SYS_MMC_ENV_DEV=2 -- cgit v1.3.1 From da9e2218afc2fd8ac9e4cd4e4dd02a9a2e83e6db Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:15 -0700 Subject: board: venice: add FSA support The Gateworks Flexible Socket Adapters adapt common busses such as SDIO/UART/USB/PCI to various connectors such as M.2 B-Key, M.2 E-Key, M.2 M-Key, and MiniPCIe. Each FSA has an EEPROM onboard describing its details as well as an optional port-expander for configurable GPIO's. Add support for identifying the FSA's and configuring their details such as user description and GPIO's: - enable pca953x, pca954x and eeprom support for communicating with the I2C eeprom and gpio port expander on the FSA - add FSA detection support - add FSA gpio configuration support Each FSA is identified in the device-tree by an alias to it's I2C bus where an eeprom@54 node must exist as well as an gpio@20 node for an io-expander. These nodes must be enabled so that they can be probed to determine if they are actually present in the system. If not present or not enabled the gpio expander can not be used. This also requires livetree as the gpio expander node if not present must be disabled. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- board/gateworks/fsa.c | 736 ++++++++++++++++++++++++++++++++++++++++ board/gateworks/fsa.h | 51 +++ board/gateworks/venice/Makefile | 1 + board/gateworks/venice/eeprom.c | 3 + board/gateworks/venice/venice.c | 7 + configs/imx8mm_venice_defconfig | 5 + configs/imx8mn_venice_defconfig | 5 + configs/imx8mp_venice_defconfig | 5 + 8 files changed, 813 insertions(+) create mode 100644 board/gateworks/fsa.c create mode 100644 board/gateworks/fsa.h diff --git a/board/gateworks/fsa.c b/board/gateworks/fsa.c new file mode 100644 index 00000000000..1af8021057c --- /dev/null +++ b/board/gateworks/fsa.c @@ -0,0 +1,736 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2025 Gateworks Corporation + */ + +#include +#include +#include +#include +#include +#include +#include // device_remove/device_unbind +#include +#include +#include + +#include "fsa.h" + +static int fsa; +static struct udevice *fsa_gpiodevs[FSA_MAX] = { NULL }; + +/* find the ofnode of the FSA i2c bus */ +static ofnode fsa_get_ofnode(int fsa) +{ + char str[32]; + + /* by alias */ + snprintf(str, sizeof(str), "fsa%d", fsa); + return ofnode_get_aliases_node(str); +} + +static int fsa_get_dtnode(void *fdt, int fsa) +{ + char str[32]; + + /* by alias */ + snprintf(str, sizeof(str), "fsa%d", fsa); + return fdt_path_offset(fdt, fdt_get_alias(fdt, str)); +} + +static const char * const fsa_gpio_config_names[] = { "NC", "", "input", "output-low", + "output-high" }; + +static const char *fsa_gpio_config_name(struct fsa_gpio_desc *desc) +{ + if (desc->config < ARRAY_SIZE(fsa_gpio_config_names)) + return fsa_gpio_config_names[desc->config]; + return NULL; +}; + +static char *fsa_get_gpio_desc(struct fsa_gpio_desc *desc, char *str, int sz) +{ + str[0] = 0; + if (desc->source == 0xff) { + snprintf(str, sz, "fsa_gpio%d : %s %s", + desc->offset + 1, + desc->name, + fsa_gpio_config_name(desc)); + } else if (desc->config) { + snprintf(str, sz, "gpio@%02x_%02d: %s %s", + desc->source, + desc->offset, + desc->name, + fsa_gpio_config_name(desc)); + } + return str; +} + +static void fsa_show_gpio_descs(const char *prefix, int fsa, struct fsa_board_info *board_info, + struct fsa_user_info *user_info) +{ + char str[128]; + int i; + + /* display slot specific gpios */ + for (i = 0; i < board_info->sockgpios; i++) { + fsa_get_gpio_desc(&user_info->gpios[i], str, sizeof(str)); + printf("%s%-2d: %s\n", prefix, i, str); + } + /* display io-expander specific gpios */ + if (fsa_gpiodevs[fsa]) { + for (i = board_info->sockgpios; + i < (board_info->sockgpios + board_info->ioexpgpios); + i++) { + fsa_get_gpio_desc(&user_info->gpios[i], str, sizeof(str)); + printf("%s%-2d: %s\n", prefix, i, str); + } + } +} + +/* detect gpio expander by address and deal with enabling/disabling/adding gpio expander to dt */ +static int fsa_get_gpiodev(int fsa, int addr, struct udevice **devp) +{ + struct udevice *bus, *dev; + char gpio_name[32]; + int ret; + + ret = device_get_global_by_ofnode(fsa_get_ofnode(fsa), &bus); + if (ret) + return ret; + + sprintf(gpio_name, "gpio@%02x", addr); + + /* probe device on i2c bus */ + ret = dm_i2c_probe(bus, addr, 0, &dev); + switch (ret) { + case -EREMOTEIO: /* chip is not present on i2c bus */ + /* if device is in dt remove/unbind/disable it */ + ret = device_find_child_by_name(bus, gpio_name, &dev); + if (ret) + return ret; + ret = ofnode_set_enabled(dev_ofnode(dev), false); + if (ret) + return ret; + ret = device_unbind(dev); + if (ret) + return ret; + ret = device_remove(dev, DM_REMOVE_NORMAL); + if (ret) + return ret; + return ret; + case -ENOSYS: /* chip found but driver invalid */ + /* if device is in not in dt add/bind it */ + return ret; + case 0: /* chip responded and driver bound */ + break; + } + + if (devp) + *devp = dev; + return 0; +} + +/* add gpio's to gpio device: GPIO device must be probed before you can manipulate it */ +static int fsa_config_gpios(int fsa, struct fsa_user_info *info, int gpios, struct udevice *dev) +{ + struct fsa_gpio_desc *desc; + struct gpio_desc gdesc; + struct udevice *gdev; + int i, ret, flags; + char name[32]; + + /* configure GPIO's */ + for (i = 0; i < gpios; i++) { + desc = &info->gpios[i]; + if (desc->config < FSA_GPIO_INPUT) + continue; + memset(&gdesc, 0, sizeof(gdesc)); + + if (desc->source == 0xff) { + /* Board specific IMX8M GPIO's: find dev of controller by line-name */ + sprintf(name, "fsa%d_gpio%d", fsa, desc->offset + 1); + uclass_foreach_dev_probe(UCLASS_GPIO, gdev) { + ret = dev_read_stringlist_search(gdev, "gpio-line-names", name); + if (ret >= 0) { + gdesc.dev = gdev; + gdesc.offset = ret; + break; + } + } + } else { + /* port expander GPIOs */ + gdesc.dev = dev; + gdesc.offset = desc->offset; + } + + if (!gdesc.dev) + continue; + + sprintf(name, "fsa%d_%s", fsa, desc->name); + switch (desc->config) { + case FSA_GPIO_INPUT: + flags = GPIOD_IS_IN; + break; + case FSA_GPIO_OUTPUT_LOW: + flags = GPIOD_IS_OUT; + break; + case FSA_GPIO_OUTPUT_HIGH: + flags = GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE; + break; + } + if (!dm_gpio_request(&gdesc, name)) + dm_gpio_clrset_flags(&gdesc, GPIOD_MASK_DIR, flags); + } + + return 0; +} + +static int fsa_read_board_config(int fsa, struct fsa_board_info *info) +{ + struct udevice *dev; + int chksum; + int i, ret; + ofnode node; + + /* find eeprom dev */ + node = ofnode_find_subnode(fsa_get_ofnode(fsa), "eeprom@54"); + if (!ofnode_valid(node)) + return -EINVAL; + ret = device_get_global_by_ofnode(node, &dev); + if (ret) + return ret; + + /* read eeprom */ + ret = dm_i2c_read(dev, 0, (uint8_t *)info, sizeof(*info)); + if (ret) { + dev_err(dev, "read failed: %d\n", ret); + return ret; + } + + /* validate checksum */ + for (chksum = 0, i = 0; i < (int)sizeof(*info) - 2; i++) + chksum += ((unsigned char *)info)[i]; + if ((info->chksum[0] != ((chksum >> 8) & 0xff)) || + (info->chksum[1] != (chksum & 0xff))) { + dev_err(dev, "FSA%d EEPROM: Invalid User Config Checksum\n", fsa); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, info, sizeof(*info)); + memset(info, 0, sizeof(*info)); + return -EINVAL; + } + + return 0; +} + +static int fsa_read_user_config(int fsa, struct fsa_user_info *info) +{ + struct udevice *dev; + int chksum; + int i, ret; + ofnode node; + + /* find eeprom dev */ + node = ofnode_find_subnode(fsa_get_ofnode(fsa), "eeprom@55"); + if (!ofnode_valid(node)) + return -EINVAL; + ret = device_get_global_by_ofnode(node, &dev); + if (ret) + return ret; + + /* read eeprom */ + ret = dm_i2c_read(dev, 0, (uint8_t *)info, sizeof(*info)); + if (ret) { + dev_err(dev, "read failed: %d\n", ret); + return ret; + } + + /* validate checksum */ + for (chksum = 0, i = 0; i < (int)sizeof(*info) - 2; i++) + chksum += ((unsigned char *)info)[i]; + if ((info->chksum[0] != ((chksum >> 8) & 0xff)) || + (info->chksum[1] != (chksum & 0xff))) { + dev_err(dev, "FSA%d EEPROM: Invalid User Config Checksum\n", fsa); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, info, sizeof(*info)); + memset(info, 0, sizeof(*info)); + return -EINVAL; + } + + return 0; +} + +static int fsa_write_user_config(int fsa, struct fsa_user_info *info) +{ + struct udevice *bus, *dev; + int i, n, chunk, slave, base, ret; + ofnode node; + int chksum; + + /* create checksum */ + for (chksum = 0, i = 0; i < (int)sizeof(*info) - 2; i++) + chksum += ((unsigned char *)info)[i]; + info->chksum[0] = chksum >> 8; + info->chksum[1] = chksum & 0xff; + + /* find eeprom dev */ + node = ofnode_find_subnode(fsa_get_ofnode(fsa), "eeprom@55"); + ret = device_get_global_by_ofnode(node, &dev); + if (ret) + return ret; + bus = dev->parent; + base = dev_read_addr(dev); + + /* write in 16byte chunks (multi-byte writes fail larger than that) */ + chunk = 16; + slave = -1; + for (i = 0; i < sizeof(*info); i += chunk) { + /* select device based on offset */ + if ((base + (i / 256)) != slave) { + slave = base + (i / 256); + ret = i2c_get_chip(bus, slave, 1, &dev); + if (ret) { + dev_err(bus, "failed to get eeprom@0x%02x: %d\n", slave, ret); + return ret; + } + } + /* select byte count */ + n = sizeof(*info) - i; + if (n > chunk) + n = chunk; + ret = dm_i2c_write(dev, i % 256, (uint8_t *)info + i, n); + if (ret) { + dev_err(dev, "write failed: %d\n", ret); + return ret; + } + mdelay(11); + } + + return ret; +} + +static int fsa_detect(int fsa, struct fsa_board_info *board_info, struct fsa_user_info *user_info, + bool gpio) +{ + int ret; + + ret = fsa_read_board_config(fsa, board_info); + if (ret) + return ret; + if (user_info) { + ret = fsa_read_user_config(fsa, user_info); + if (ret) + return ret; + /* detect port expander */ + if (gpio && !fsa_get_gpiodev(fsa, 0x20, &fsa_gpiodevs[fsa])) + fsa_config_gpios(fsa, user_info, + board_info->sockgpios + board_info->ioexpgpios, + fsa_gpiodevs[fsa]); + } + + return ret; +} + +static int ft_fixup_stringlist_elem(void *fdt, int offset, const char *prop, int elem, + const char *val) +{ + const char *list, *end; + char *new, *buf; + int length; + int sz = 0; + int i = 0; + int ret; + + if (offset < 0 || elem < 0 || !val) { + printf("%s -EINVAL\n", __func__); + return -EINVAL; + } + + list = fdt_getprop(fdt, offset, prop, &length); + + /* no property or invalid params */ + if (!list || length < 0) { + printf("%s failed - no property\n", __func__); + return -EINVAL; + } + + /* create new buffer with enough space */ + buf = calloc(1, length + strlen(val)); + new = buf; + + /* iterate over current stringlist and build new list into buf */ + end = list + length; + while (list < end) { + length = strnlen(list, end - list) + 1; + sz += length; + /* insert new value into buf */ + if (elem == i) { + strcpy(new, val); + new += strlen(val) + 1; + } else { + strcpy(new, list); + new += length; + } + list += length; + i++; + } + length = new - buf; + ret = fdt_setprop(fdt, offset, prop, buf, length); + free(buf); + if (ret) + printf("%s failed %d\n", __func__, ret); + + return ret; +} + +static int ft_fixup_fsa_gpio_name(void *fdt, int offset, int fsa, int gpio, const char *name) +{ + const char *prop = "gpio-line-names"; + char str[32]; + + sprintf(str, "fsa%d_%s", fsa, name); + + if (!fdt_getprop(fdt, offset, prop, NULL)) { + char buf[16] = { 0 }; + + fdt_setprop(fdt, offset, prop, &buf, sizeof(buf)); + } + + return ft_fixup_stringlist_elem(fdt, offset, prop, gpio, str); +} + +static void fsa_show_details(int fsa, struct fsa_board_info *board, struct fsa_user_info *user) +{ + printf("FSA%d: %s\n", fsa, board->model); + printf("description: %s\n", user->desc); + printf("overlay: %s\n", user->overlay); + fsa_show_gpio_descs("\t", fsa, board, user); +} + +int fsa_init(void) +{ + struct fsa_board_info board_info; + struct fsa_user_info user_info; + int fsa, ret; + + for (fsa = 1; fsa < FSA_MAX; fsa++) { + ret = fsa_detect(fsa, &board_info, &user_info, true); + if (!ret) + printf("FSA%d: %s %s\n", fsa, board_info.model, user_info.desc); + } + + return 0; +} + +int fsa_show(void) +{ + struct fsa_board_info board_info; + int fsa, ret; + + for (fsa = 1; fsa < FSA_MAX; fsa++) { + ret = fsa_detect(fsa, &board_info, NULL, false); + if (!ret) { + printf("FSA%d : %s %d %02x-%02x-%02x%02x\n", fsa, + board_info.model, board_info.serial, + board_info.mfgdate[0], board_info.mfgdate[1], + board_info.mfgdate[2], board_info.mfgdate[3]); + } + } + return 0; +} + +/* fixup gpio line names for fsa gpios */ +int fsa_ft_fixup(void *fdt) +{ + struct fsa_board_info board_info; + struct fsa_user_info user_info; + int fsa, i, ret; + char path[128]; + char str[32]; + ofnode node; + int off; + + /* iterate over FSA's and rename gpio's */ + for (fsa = 1; fsa < FSA_MAX; fsa++) { + /* disable FSA ioexp node if disabled in controlling dt */ + off = fdt_subnode_offset(fdt, fsa_get_dtnode(fdt, fsa), "gpio@20"); + if (off >= 0) { + if (!fdt_get_path(fdt, off, path, sizeof(path))) { + node = ofnode_path(path); + if (ofnode_valid(node) && !ofnode_is_enabled(node)) + fdt_setprop_string(fdt, off, "status", "disabled"); + } + } + + /* detect FSA eeprom */ + if (fsa_detect(fsa, &board_info, &user_info, false)) + continue; + + /* configure GPIO's */ + for (i = 0; i < board_info.sockgpios + board_info.ioexpgpios; i++) { + if (user_info.gpios[i].config < FSA_GPIO_INPUT) + continue; + + if (user_info.gpios[i].source == 0xff) { + /* Board specific IMX8M GPIO's */ + for (off = fdt_node_offset_by_prop_value(fdt, 0, + "gpio-controller", NULL, + 0); + off >= 0; + off = fdt_node_offset_by_prop_value(fdt, off, + "gpio-controller", NULL, + 0) + ) { + sprintf(str, "fsa%d_gpio%d", fsa, + user_info.gpios[i].offset + 1); + ret = fdt_stringlist_search(fdt, off, "gpio-line-names", + str); + if (ret >= 0) { + ft_fixup_fsa_gpio_name(fdt, off, fsa, ret, + user_info.gpios[i].name); + break; + } + } + } else { + /* port expander GPIOs */ + off = fdt_subnode_offset(fdt, fsa_get_dtnode(fdt, fsa), "gpio@20"); + ft_fixup_fsa_gpio_name(fdt, off, fsa, user_info.gpios[i].offset, + user_info.gpios[i].name); + } + } + } + + return 0; +} + +static int do_fsa_dev(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + struct fsa_board_info board_info; + struct fsa_user_info user_info; + int i; + + if (argc < 2) { + /* list FSAs */ + printf("detecting FSA Adapters:\n"); + for (i = 1; i < FSA_MAX; i++) { + if (!fsa_read_board_config(i, &board_info) && + !fsa_read_user_config(i, &user_info)) + printf("FSA%d : %s %s\n", i, board_info.model, user_info.desc); + } + } else { + /* select FSA */ + fsa = simple_strtoul(argv[1], NULL, 10); + } + + if (fsa) { + /* read FSA */ + if (!fsa_read_board_config(fsa, &board_info) && + !fsa_read_user_config(fsa, &user_info)) { + printf("selected:\n"); + fsa_show_details(fsa, &board_info, &user_info); + } else { + printf("FSA%d not detected\n", fsa); + fsa = 0; + } + } else { + printf("no FSA currently selected\n"); + } + + return 0; +} + +static int do_fsa_desc(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + struct fsa_board_info board_info; + struct fsa_user_info user_info; + + /* strip off leading cmd arg */ + argc--; + argv++; + + if (!fsa) { + printf("No FSA selected\n"); + return CMD_RET_USAGE; + } + + if (fsa_read_board_config(fsa, &board_info) || fsa_read_user_config(fsa, &user_info)) { + printf("can't detect FSA%d\n", fsa); + return CMD_RET_USAGE; + } + + /* set */ + if (argc) { + strlcpy(user_info.desc, argv[0], sizeof(user_info.desc)); + if (fsa_write_user_config(fsa, &user_info)) + return CMD_RET_FAILURE; + } + + /* show */ + fsa_show_details(fsa, &board_info, &user_info); + + return CMD_RET_SUCCESS; +} + +static int do_fsa_overlay(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + struct fsa_board_info board_info; + struct fsa_user_info user_info; + + /* strip off leading cmd arg */ + argc--; + argv++; + + if (!fsa) { + printf("No FSA selected\n"); + return CMD_RET_USAGE; + } + + if (fsa_read_board_config(fsa, &board_info) || fsa_read_user_config(fsa, &user_info)) { + printf("can't detect FSA%d\n", fsa); + return CMD_RET_USAGE; + } + + /* set */ + if (argc) { + strlcpy(user_info.overlay, argv[0], sizeof(user_info.overlay)); + if (fsa_write_user_config(fsa, &user_info)) + return CMD_RET_FAILURE; + } + + /* show */ + fsa_show_details(fsa, &board_info, &user_info); + + return CMD_RET_SUCCESS; +} + +static int do_fsa_gpio(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + struct fsa_board_info board_info; + struct fsa_user_info user_info; + struct fsa_gpio_desc desc; + char str[64]; + int i, j; + + /* strip off leading cmd arg */ + argc--; + argv++; + + if (!fsa) { + printf("No FSA selected\n"); + return CMD_RET_USAGE; + } + + if (fsa_read_board_config(fsa, &board_info) || fsa_read_user_config(fsa, &user_info)) { + printf("can't detect FSA%d\n", fsa); + return CMD_RET_USAGE; + } + + if (!argc) { + /* show all gpios */ + fsa_show_gpio_descs("\t", fsa, &board_info, &user_info); + return CMD_RET_SUCCESS; + } + + if (!isdigit(argv[0][0])) { + printf("invalid gpio offset: %s\n", argv[0]); + return CMD_RET_USAGE; + } + + memset(&desc, 0, sizeof(desc)); + i = simple_strtoul(argv[0], NULL, 10); + + if (i >= 0 && i < board_info.sockgpios) { + desc.offset = i; + desc.source = 0xff; + } else if (i >= board_info.sockgpios && + i < (board_info.sockgpios + board_info.ioexpgpios) && + fsa_gpiodevs[fsa]) { + desc.offset = i - board_info.sockgpios; + desc.source = 0x20; + } else { + printf("invalid index %d", i); + return CMD_RET_FAILURE; + } + + if (argc > 1) { + if (user_info.gpios[i].config == FSA_GPIO_NC) { + printf("can not alter NC gpio\n"); + return CMD_RET_FAILURE; + } + strlcpy(desc.name, argv[1], sizeof(desc.name)); + if (!*desc.name) { + printf("FSA%d %s erasing gpio %d\n", fsa, board_info.model, i); + memset(&user_info.gpios[i], 0, sizeof(desc)); + if (fsa_write_user_config(fsa, &user_info)) + return CMD_RET_FAILURE; + return CMD_RET_SUCCESS; + } + } + if (argc > 2) { + if (user_info.gpios[i].config == FSA_GPIO_NC) { + printf("can not alter NC gpio\n"); + return CMD_RET_FAILURE; + } + for (j = 1; j < ARRAY_SIZE(fsa_gpio_config_names); j++) { + if (!strcasecmp(argv[2], fsa_gpio_config_names[j])) { + desc.config = j; + break; + } + }; + if (j >= ARRAY_SIZE(fsa_gpio_config_names)) { + printf("invalid config type '%s\n", argv[2]); + return CMD_RET_FAILURE; + } + } + + /* show a specific gpio */ + if (argc == 1) { + printf("FSA%d %s showing gpio %d\n", fsa, board_info.model, i); + printf("%s\n", fsa_get_gpio_desc(&user_info.gpios[i], str, sizeof(str))); + return CMD_RET_SUCCESS; + } + + /* set a specific gpio */ + else if (argc == 3) { + printf("FSA%d %s updating gpio %d\n", fsa, board_info.model, i); + memcpy(&user_info.gpios[i], &desc, sizeof(desc)); + if (fsa_write_user_config(fsa, &user_info)) + return CMD_RET_FAILURE; + return CMD_RET_SUCCESS; + } + + return CMD_RET_USAGE; +} + +static struct cmd_tbl cmd_fsa_sub[] = { + U_BOOT_CMD_MKENT(dev, 1, 1, do_fsa_dev, "", ""), + U_BOOT_CMD_MKENT(gpio, 4, 1, do_fsa_gpio, "", ""), + U_BOOT_CMD_MKENT(description, 1, 1, do_fsa_desc, "", ""), + U_BOOT_CMD_MKENT(overlay, 1, 1, do_fsa_overlay, "", ""), +}; + +static int do_fsa(struct cmd_tbl *cmdtp, int flag, int argc, char * const argv[]) +{ + struct cmd_tbl *c; + + /* strip off leading fsa arg */ + argc--; + argv++; + + c = find_cmd_tbl(argv[0], cmd_fsa_sub, ARRAY_SIZE(cmd_fsa_sub)); + if (c) + return c->cmd(cmdtp, flag, argc, argv); + return CMD_RET_USAGE; +} + +U_BOOT_LONGHELP(fsa, + "dev [dev] - show or set current FSA adapter\n" + "fsa gpio - show current gpio descriptors\n" + "fsa gpio []|[ ] - show a specific gpio descriptor\n" + "fsa gpio [ [source]] - set a gpio descriptor\n" + "fsa description [description] - show or set the FSA user description string\n" + "fsa overlay [overlay] - show or set the FSA overlay string\n" +); + +U_BOOT_CMD(fsa, 6, 1, do_fsa, + "Flexible Socket Adapter", + fsa_help_text +); diff --git a/board/gateworks/fsa.h b/board/gateworks/fsa.h new file mode 100644 index 00000000000..ddb64499d78 --- /dev/null +++ b/board/gateworks/fsa.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright 2025 Gateworks Corporation + */ + +#ifndef _FSA_H_ +#define _FSA_H_ + +#define FSA_MAX 5 + +enum fsa_gpio_cfg { + FSA_GPIO_NC, + FSA_GPIO_UNCONFIGURED, + FSA_GPIO_INPUT, + FSA_GPIO_OUTPUT_LOW, + FSA_GPIO_OUTPUT_HIGH, +}; + +struct fsa_gpio_desc { + u8 offset; + u8 config; + u8 source; + char name[13]; +}; + +struct fsa_board_info { + char model[16]; /* 0x00: model string */ + u8 mac[6]; /* 0x10: MAC base */ + u8 macno; /* 0x16: number of mac addrs */ + u8 resv1; /* 0x17: reserved */ + u32 serial; /* 0x18: Serial Number */ + u8 mfgdate[4]; /* 0x1c: MFG date */ + u8 sockgpios; /* 0x20: number of socket gpio descriptors */ + u8 ioexpgpios; /* 0x21: number of io expander gpio descriptors */ + u8 resv2[220]; /* 0x22: reserved */ + u8 chksum[2]; /* 0xfe: */ +}; + +struct fsa_user_info { + char desc[32]; /* 0x000: user description */ + char overlay[16]; /* 0x020: dt-overlay suffice */ + struct fsa_gpio_desc gpios[20]; /* 0x030: gpio descriptors */ + u8 reserved[398]; /* 0x170: reserved */ + u8 chksum[2]; /* 0x2fe: */ +}; + +int fsa_init(void); +int fsa_show(void); +int fsa_ft_fixup(void *fdt); + +#endif // _FSA_H_ diff --git a/board/gateworks/venice/Makefile b/board/gateworks/venice/Makefile index ab69e07ba7b..1aaf0295d5c 100644 --- a/board/gateworks/venice/Makefile +++ b/board/gateworks/venice/Makefile @@ -5,6 +5,7 @@ # obj-y += venice.o eeprom.o +obj-y += ../fsa.o ifdef CONFIG_XPL_BUILD obj-y += spl.o diff --git a/board/gateworks/venice/eeprom.c b/board/gateworks/venice/eeprom.c index 41f620c90e7..49b1ad34b14 100644 --- a/board/gateworks/venice/eeprom.c +++ b/board/gateworks/venice/eeprom.c @@ -9,6 +9,7 @@ #include #include "eeprom.h" +#include "../fsa.h" /* I2C */ #define SOM_EEPROM_BUSNO 0 @@ -300,6 +301,8 @@ static int eeprom_info(bool verbose) base_info.mfgdate[0], base_info.mfgdate[1], base_info.mfgdate[2], base_info.mfgdate[3]); } + if (verbose) + fsa_show(); return 0; } diff --git a/board/gateworks/venice/venice.c b/board/gateworks/venice/venice.c index f9bcdd8496e..6a24f618ae2 100644 --- a/board/gateworks/venice/venice.c +++ b/board/gateworks/venice/venice.c @@ -15,6 +15,7 @@ #include #include "eeprom.h" +#include "../fsa.h" int board_phys_sdram_size(phys_size_t *size) { @@ -76,6 +77,9 @@ int board_init(void) { venice_eeprom_init(1); + /* detect and configure FSA adapters */ + fsa_init(); + return 0; } @@ -222,6 +226,9 @@ int ft_board_setup(void *fdt, struct bd_info *bd) /* set board model dt prop */ fdt_setprop_string(fdt, 0, "board", eeprom_get_model()); + /* fixups for FSA adapters */ + fsa_ft_fixup(fdt); + if (!strncmp(base_model, "GW73", 4)) { pcbrev = get_pcb_rev(base_model); path = fdt_get_alias(fdt, "ethernet1"); diff --git a/configs/imx8mm_venice_defconfig b/configs/imx8mm_venice_defconfig index 0f263a3ecb8..cc7dfcb1400 100644 --- a/configs/imx8mm_venice_defconfig +++ b/configs/imx8mm_venice_defconfig @@ -86,6 +86,7 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_EFI_PARTITION is not set CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_LIVE=y CONFIG_OF_LIST="freescale/imx8mm-venice-gw71xx-0x freescale/imx8mm-venice-gw72xx-0x freescale/imx8mm-venice-gw73xx-0x freescale/imx8mm-venice-gw7901 freescale/imx8mm-venice-gw7902 freescale/imx8mm-venice-gw7903 freescale/imx8mm-venice-gw7904 freescale/imx8mm-venice-gw75xx-0x" CONFIG_ENV_IS_IN_MMC=y CONFIG_SYS_REDUNDAND_ENVIRONMENT=y @@ -106,10 +107,14 @@ CONFIG_CLK_IMX8MM=y CONFIG_GPIO_HOG=y CONFIG_DM_GPIO_LOOKUP_LABEL=y CONFIG_MXC_GPIO=y +CONFIG_DM_PCA953X=y CONFIG_DM_I2C=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA954x=y CONFIG_LED=y CONFIG_LED_BLINK=y CONFIG_LED_GPIO=y +CONFIG_I2C_EEPROM=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_SPL_MMC_IO_VOLTAGE=y diff --git a/configs/imx8mn_venice_defconfig b/configs/imx8mn_venice_defconfig index 4fc8e146b06..a7a838b61bb 100644 --- a/configs/imx8mn_venice_defconfig +++ b/configs/imx8mn_venice_defconfig @@ -86,6 +86,7 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_EFI_PARTITION is not set CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_LIVE=y CONFIG_ENV_IS_IN_MMC=y CONFIG_SYS_REDUNDAND_ENVIRONMENT=y CONFIG_SYS_MMC_ENV_DEV=2 @@ -103,10 +104,14 @@ CONFIG_CLK_IMX8MN=y CONFIG_GPIO_HOG=y CONFIG_DM_GPIO_LOOKUP_LABEL=y CONFIG_MXC_GPIO=y +CONFIG_DM_PCA953X=y CONFIG_DM_I2C=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA954x=y CONFIG_LED=y CONFIG_LED_BLINK=y CONFIG_LED_GPIO=y +CONFIG_I2C_EEPROM=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_SPL_MMC_IO_VOLTAGE=y diff --git a/configs/imx8mp_venice_defconfig b/configs/imx8mp_venice_defconfig index 10eac0a0c78..2e4cacf166d 100644 --- a/configs/imx8mp_venice_defconfig +++ b/configs/imx8mp_venice_defconfig @@ -88,6 +88,7 @@ CONFIG_CMD_EXT4_WRITE=y # CONFIG_SPL_EFI_PARTITION is not set CONFIG_OF_CONTROL=y CONFIG_SPL_OF_CONTROL=y +CONFIG_OF_LIVE=y CONFIG_OF_LIST="freescale/imx8mp-venice-gw71xx-2x freescale/imx8mp-venice-gw72xx-2x freescale/imx8mp-venice-gw73xx-2x freescale/imx8mp-venice-gw74xx freescale/imx8mp-venice-gw75xx-2x freescale/imx8mp-venice-gw82xx-2x" CONFIG_ENV_IS_IN_MMC=y CONFIG_SYS_REDUNDAND_ENVIRONMENT=y @@ -104,10 +105,14 @@ CONFIG_CLK_IMX8MP=y CONFIG_GPIO_HOG=y CONFIG_DM_GPIO_LOOKUP_LABEL=y CONFIG_MXC_GPIO=y +CONFIG_DM_PCA953X=y CONFIG_DM_I2C=y +CONFIG_I2C_MUX=y +CONFIG_I2C_MUX_PCA954x=y CONFIG_LED=y CONFIG_LED_BLINK=y CONFIG_LED_GPIO=y +CONFIG_I2C_EEPROM=y CONFIG_SUPPORT_EMMC_BOOT=y CONFIG_MMC_IO_VOLTAGE=y CONFIG_MMC_UHS_SUPPORT=y -- cgit v1.3.1 From 41bc2d5334fbd23fcba6853d90c6f45b1400dd87 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:16 -0700 Subject: board: venice: update model representation for venice-flex Update the model string representation for the Venice-Flex product family (GW8xxx). Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- board/gateworks/venice/eeprom.c | 104 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 102 insertions(+), 2 deletions(-) diff --git a/board/gateworks/venice/eeprom.c b/board/gateworks/venice/eeprom.c index 49b1ad34b14..702ab392a04 100644 --- a/board/gateworks/venice/eeprom.c +++ b/board/gateworks/venice/eeprom.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "eeprom.h" @@ -19,7 +20,7 @@ struct venice_board_info som_info; struct venice_board_info base_info; -char venice_model[32]; +char venice_model[64]; char venice_som_model[32]; char venice_baseboard_model[32]; u32 venice_serial; @@ -109,7 +110,7 @@ static int eeprom_read(int busno, int slave, int alen, struct venice_board_info /* validate checksum */ for (chksum = 0, i = 0; i < (int)sizeof(*info) - 2; i++) chksum += buf[i]; - if ((info->chksum[0] != chksum >> 8) || + if ((info->chksum[0] != ((chksum >> 8) & 0xff)) || (info->chksum[1] != (chksum & 0xff))) { printf("EEPROM: I2C%d@0x%02x: Invalid Checksum\n", busno, slave); print_hex_dump_bytes("", DUMP_PREFIX_NONE, buf, sizeof(*info)); @@ -128,6 +129,54 @@ static int eeprom_read(int busno, int slave, int alen, struct venice_board_info return 0; } +static int fsa_eeprom_read(const char *base, int fsa, struct fsa_board_info *info) +{ + int i; + int chksum; + unsigned char *buf = (unsigned char *)info; + struct udevice *dev, *bus; + int ret; + u8 reg; + + /* probe mux */ + ret = uclass_get_device_by_seq(UCLASS_I2C, 2, &bus); + if (!ret) + ret = dm_i2c_probe(bus, 0x70, 0, &dev); + if (ret) + return ret; + /* steer mux */ + if (!strncmp(base, "GW82", 4)) { + if (fsa < 3) + reg = (fsa == 1) ? BIT(1) : BIT(0); + else + return -EINVAL; + } + dm_i2c_write(dev, 0x00, ®, 1); + + /* get eeprom */ + ret = dm_i2c_probe(bus, 0x54, 0, &dev); + if (ret) + return ret; + + /* read eeprom config section */ + ret = dm_i2c_read(dev, 0x00, buf, sizeof(*info)); + if (ret) + return ret; + + /* validate checksum */ + for (chksum = 0, i = 0; i < (int)sizeof(*info) - 2; i++) + chksum += buf[i]; + if ((info->chksum[0] != ((chksum >> 8) & 0xff)) || + (info->chksum[1] != (chksum & 0xff))) { + printf("FSA%d EEPROM (board): %s: Invalid Checksum\n", fsa, dev->name); + print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, buf, sizeof(*info)); + memset(info, 0, sizeof(*info)); + return -EINVAL; + } + + return 0; +} + /* determine BOM revision from model */ int get_bom_rev(const char *str) { @@ -352,6 +401,57 @@ int venice_eeprom_init(int quiet) } venice_serial = som_info.serial; + /* GW8xxx product family naming scheme */ + if (venice_model[2] == '8') { + struct fsa_board_info fsa_info; + int i = 0; + int fsa; + + /* baseboard */ + if (base_info.model[0]) { + rev_pcb = get_pcb_rev(base_info.model); + rev_bom = get_bom_rev(base_info.model); + venice_model[i++] = 'G'; + venice_model[i++] = 'W'; + venice_model[i++] = base_info.model[2]; /* baseboard */ + venice_model[i++] = base_info.model[3]; + venice_model[i++] = base_info.model[4]; /* subload */ + venice_model[i++] = base_info.model[5]; + venice_model[i++] = rev_pcb; + if (rev_bom) + venice_model[i++] = rev_bom; + venice_model[i++] = '-'; + venice_model[i++] = 'S'; + } else { + venice_model[i++] = 'G'; + venice_model[i++] = 'W'; + } + + /* som */ + rev_pcb = get_pcb_rev(som_info.model); + rev_bom = get_bom_rev(som_info.model); + venice_model[i++] = som_info.model[4]; + venice_model[i++] = som_info.model[5]; + venice_model[i++] = rev_pcb; + if (rev_bom) + venice_model[i++] = rev_bom; + + /* fsa */ + for (fsa = 1; fsa < FSA_MAX; fsa++) { + if (!fsa_eeprom_read(venice_model, fsa, &fsa_info)) { + venice_model[i++] = '-'; + venice_model[i++] = 'F'; + venice_model[i++] = '0' + fsa; + venice_model[i++] = fsa_info.model[5]; + venice_model[i++] = fsa_info.model[6]; + venice_model[i++] = fsa_info.model[8]; + if (fsa_info.model[9]) + venice_model[i++] = fsa_info.model[9]; + } + } + venice_model[i++] = 0; + } + if (!quiet) eeprom_info(false); -- cgit v1.3.1 From 314469b6bad1892b04c4cbc10e91f9cec30bdec5 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:17 -0700 Subject: board: venice: append configuration string to model Append the optional board configuration string to the model info. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- board/gateworks/venice/eeprom.c | 9 +++++++++ board/gateworks/venice/eeprom.h | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/board/gateworks/venice/eeprom.c b/board/gateworks/venice/eeprom.c index 702ab392a04..d9a87193434 100644 --- a/board/gateworks/venice/eeprom.c +++ b/board/gateworks/venice/eeprom.c @@ -449,6 +449,15 @@ int venice_eeprom_init(int quiet) venice_model[i++] = fsa_info.model[9]; } } + + /* append extra model info */ + if (som_info.config[0] >= 32 && som_info.config[0] < 0x7f) { + venice_model[i++] = '-'; + strlcpy(venice_model + i, som_info.config, (sizeof(venice_model) - i) - 1); + i += strlen(som_info.config); + if (i >= sizeof(venice_model)) + i = sizeof(venice_model) - 1; + } venice_model[i++] = 0; } diff --git a/board/gateworks/venice/eeprom.h b/board/gateworks/venice/eeprom.h index 30cd347d945..a0f449299aa 100644 --- a/board/gateworks/venice/eeprom.h +++ b/board/gateworks/venice/eeprom.h @@ -20,7 +20,7 @@ struct venice_board_info { u8 sdram_width; /* 0x2D: (8 << n) bit */ u8 res3[2]; /* 0x2E */ char model[16]; /* 0x30: model string */ - u8 res4[14]; /* 0x40 */ + u8 config[14]; /* 0x40: model config */ u8 chksum[2]; /* 0x4E */ }; -- cgit v1.3.1 From 37195f84133da33388fe65cb2b141c1c84635b52 Mon Sep 17 00:00:00 2001 From: Tim Harvey Date: Fri, 23 May 2025 10:20:18 -0700 Subject: imx8mp-venice-gw74xx: add w_disable2 gpio configuration The GW74xx D revision has added a M2SKT_WDIS2# GPIO which routes to the W_DISABLE2# pin of the M.2 socket. Add the iomux and a line name for this and rename the existing m2_wdis# signal to m2_wdis1#. Signed-off-by: Tim Harvey Reviewed-by: Peng Fan --- arch/arm/dts/imx8mp-venice-gw74xx-u-boot.dtsi | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/arm/dts/imx8mp-venice-gw74xx-u-boot.dtsi b/arch/arm/dts/imx8mp-venice-gw74xx-u-boot.dtsi index a90794d8108..95f5f15e742 100644 --- a/arch/arm/dts/imx8mp-venice-gw74xx-u-boot.dtsi +++ b/arch/arm/dts/imx8mp-venice-gw74xx-u-boot.dtsi @@ -98,6 +98,13 @@ gpios = <6 GPIO_ACTIVE_HIGH>; line-name = "m2_rst"; }; + + m2_wdis2 { + gpio-hog; + output-high; + gpios = <14 GPIO_ACTIVE_HIGH>; + line-name = "m2_wdis2#"; + }; }; &gpio4 { @@ -110,11 +117,11 @@ line-name = "m2_off#"; }; - m2_wdis { + m2_wdis1 { gpio-hog; output-high; gpios = <18 GPIO_ACTIVE_HIGH>; - line-name = "m2_wdis#"; + line-name = "m2_wdis1#"; }; rs485_en { -- cgit v1.3.1 From 0f53197c3d6ccced1d73103de5ee222500353394 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Fri, 30 May 2025 17:16:43 +0200 Subject: clk: imx: add i.MX6UL clk driver Add i.MX6UL clk driver for i.MX6UL CLK driver model usage Reviewed-by: Peng Fan Reviewed-by: Christoph Niedermaier Tested-by: Christoph Niedermaier Signed-off-by: Michael Trimarchi --- drivers/clk/imx/Kconfig | 8 ++ drivers/clk/imx/Makefile | 1 + drivers/clk/imx/clk-imx6ul.c | 289 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+) create mode 100644 drivers/clk/imx/clk-imx6ul.c diff --git a/drivers/clk/imx/Kconfig b/drivers/clk/imx/Kconfig index d17a54fb9b3..74d5fe73f94 100644 --- a/drivers/clk/imx/Kconfig +++ b/drivers/clk/imx/Kconfig @@ -14,6 +14,14 @@ config CLK_IMX6Q help This enables DM/DTS support for clock driver in i.MX6Q platforms. +config CLK_IMX6UL + bool "Clock support for i.MX6UL" + depends on ARCH_MX6 + select CLK + select CLK_CCF + help + This enables DM/DTS support for clock driver in i.MX6UL platforms. + config CLK_IMX8 bool "Clock support for i.MX8" depends on ARCH_IMX8 diff --git a/drivers/clk/imx/Makefile b/drivers/clk/imx/Makefile index a89ee7acb12..b10221a195c 100644 --- a/drivers/clk/imx/Makefile +++ b/drivers/clk/imx/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_$(PHASE_)CLK_CCF) += clk-gate2.o clk-pllv3.o clk-pfd.o obj-$(CONFIG_$(PHASE_)CLK_IMX6Q) += clk-imx6q.o +obj-$(CONFIG_$(PHASE_)CLK_IMX6UL) += clk-imx6ul.o obj-$(CONFIG_CLK_IMX8) += clk-imx8.o ifdef CONFIG_CLK_IMX8 diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c new file mode 100644 index 00000000000..32fb949ffbc --- /dev/null +++ b/drivers/clk/imx/clk-imx6ul.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Amarula Solutions Software Engineering + * Michael Trimarchi, Amarula Solutions Software Engineering, michael@amarulasolutions.com + */ + +#include +#include +#include +#include +#include +#include + +#include "clk.h" + +static int imx6ul_clk_request(struct clk *clk) +{ + debug("%s: request clk id %ld\n", __func__, clk->id); + + if (clk->id < IMX6UL_CLK_DUMMY || clk->id >= IMX6UL_CLK_END) { + printf("%s: Invalid clk ID #%lu\n", __func__, clk->id); + return -EINVAL; + } + + return 0; +} + +static struct clk_ops imx6ul_clk_ops = { + .request = imx6ul_clk_request, + .set_rate = ccf_clk_set_rate, + .get_rate = ccf_clk_get_rate, + .enable = ccf_clk_enable, + .disable = ccf_clk_disable, +}; + +static const char *const pll_bypass_src_sels[] = { "osc", "dummy", }; +static const char *const pll3_bypass_sels[] = { "pll3", "pll3_bypass_src", }; +static const char *const bch_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *const gpmi_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; + +static const char *const enfc_sels[] = { "pll2_pfd0_352m", "pll2_bus", "pll3_usb_otg", "pll2_pfd2_396m", + "pll3_pfd3_454m", "dummy", "dummy", "dummy", }; +static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", }; +static const char *const periph_sels[] = { "periph_pre", "periph_clk2", }; +static const char *const periph2_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", + "pll4_audio_div", }; +static const char *const periph_clk2_sels[] = { "pll3_usb_otg", "osc", "pll2_bypass_src", }; +static const char *const periph2_clk2_sels[] = { "pll3_usb_otg", "osc", }; +static const char *const perclk_sels[] = { "ipg", "osc", }; + +static const char *const periph_pre_sels[] = { "pll2_bus", "pll2_pfd2_396m", "pll2_pfd0_352m", + "pll2_198m", }; +static const char *const uart_sels[] = { "pll3_80m", "osc", }; +static const char *const ecspi_sels[] = { "pll3_60m", "osc", }; + +static int imx6ul_clk_probe(struct udevice *dev) +{ + struct clk osc_clk; + void *base; + int ret; + + /* Anatop clocks */ + base = (void *)ANATOP_BASE_ADDR; + + clk_dm(IMX6UL_CLK_DUMMY, clk_register_fixed_rate(NULL, "dummy", 0)); + + ret = clk_get_by_name(dev, "osc", &osc_clk); + if (ret) + return ret; + + clk_dm(IMX6UL_CLK_OSC, dev_get_clk_ptr(osc_clk.dev)); + + clk_dm(IMX6UL_CLK_PLL2, + imx_clk_pllv3(dev, IMX_PLLV3_GENERIC, "pll2_bus", "osc", + base + 0x30, 0x1)); + clk_dm(IMX6UL_CLK_PLL3, + imx_clk_pllv3(dev, IMX_PLLV3_USB, "pll3", "osc", + base + 0x10, 0x3)); + clk_dm(IMX6UL_PLL3_BYPASS_SRC, + imx_clk_mux(dev, "pll3_bypass_src", base + 0x10, 14, 1, + pll_bypass_src_sels, + ARRAY_SIZE(pll_bypass_src_sels))); + clk_dm(IMX6UL_PLL3_BYPASS, + imx_clk_mux_flags(dev, "pll3_bypass", base + 0x10, 16, 1, + pll3_bypass_sels, ARRAY_SIZE(pll3_bypass_sels), + CLK_SET_RATE_PARENT)); + clk_dm(IMX6UL_CLK_PLL3_USB_OTG, + imx_clk_gate(dev, "pll3_usb_otg", "pll3_bypass", base + 0x10, + 13)); + clk_dm(IMX6UL_CLK_PLL3_80M, + imx_clk_fixed_factor(dev, "pll3_80m", "pll3_usb_otg", 1, 6)); + clk_dm(IMX6UL_CLK_PLL3_60M, + imx_clk_fixed_factor(dev, "pll3_60m", "pll3_usb_otg", 1, 8)); + clk_dm(IMX6UL_CLK_PLL2_PFD0, + imx_clk_pfd("pll2_pfd0_352m", "pll2_bus", base + 0x100, 0)); + clk_dm(IMX6UL_CLK_PLL2_PFD1, + imx_clk_pfd("pll2_pfd1_594m", "pll2_bus", base + 0x100, 1)); + clk_dm(IMX6UL_CLK_PLL2_PFD2, + imx_clk_pfd("pll2_pfd2_396m", "pll2_bus", base + 0x100, 2)); + clk_dm(IMX6UL_CLK_PLL2_PFD3, + imx_clk_pfd("pll2_pfd3_396m", "pll2_bus", base + 0x100, 3)); + clk_dm(IMX6UL_CLK_PLL6, + imx_clk_pllv3(dev, IMX_PLLV3_ENET, "pll6", "osc", base + 0xe0, + 0x3)); + clk_dm(IMX6UL_CLK_PLL6_ENET, + imx_clk_gate(dev, "pll6_enet", "pll6", base + 0xe0, 13)); + + /* CCM clocks */ + base = dev_read_addr_ptr(dev); + if (!base) + return -EINVAL; + + clk_dm(IMX6UL_CLK_GPMI_SEL, + imx_clk_mux(dev, "gpmi_sel", base + 0x1c, 19, 1, gpmi_sels, + ARRAY_SIZE(gpmi_sels))); + clk_dm(IMX6UL_CLK_BCH_SEL, + imx_clk_mux(dev, "bch_sel", base + 0x1c, 18, 1, bch_sels, + ARRAY_SIZE(bch_sels))); + clk_dm(IMX6UL_CLK_USDHC1_SEL, + imx_clk_mux(dev, "usdhc1_sel", base + 0x1c, 16, 1, usdhc_sels, + ARRAY_SIZE(usdhc_sels))); + clk_dm(IMX6UL_CLK_USDHC2_SEL, + imx_clk_mux(dev, "usdhc2_sel", base + 0x1c, 17, 1, usdhc_sels, + ARRAY_SIZE(usdhc_sels))); + clk_dm(IMX6UL_CLK_ECSPI_SEL, + imx_clk_mux(dev, "ecspi_sel", base + 0x38, 18, 1, ecspi_sels, + ARRAY_SIZE(ecspi_sels))); + clk_dm(IMX6UL_CLK_UART_SEL, + imx_clk_mux(dev, "uart_sel", base + 0x24, 6, 1, uart_sels, + ARRAY_SIZE(uart_sels))); + clk_dm(IMX6UL_CLK_ENFC_SEL, + imx_clk_mux(dev, "enfc_sel", base + 0x2c, 15, 3, enfc_sels, + ARRAY_SIZE(enfc_sels))); + clk_dm(IMX6UL_CLK_PERCLK_SEL, + imx_clk_mux(dev, "perclk_sel", base + 0x1c, 6, 1, perclk_sels, + ARRAY_SIZE(perclk_sels))); + clk_dm(IMX6UL_CLK_PERIPH_PRE, + imx_clk_mux(dev, "periph_pre", base + 0x18, 18, 2, + periph_pre_sels, ARRAY_SIZE(periph_pre_sels))); + clk_dm(IMX6UL_CLK_PERIPH2_PRE, + imx_clk_mux(dev, "periph2_pre", base + 0x18, 21, 2, + periph2_pre_sels, ARRAY_SIZE(periph2_pre_sels))); + clk_dm(IMX6UL_CLK_PERIPH_CLK2_SEL, + imx_clk_mux(dev, "periph_clk2_sel", base + 0x18, 12, 2, + periph_clk2_sels, ARRAY_SIZE(periph_clk2_sels))); + clk_dm(IMX6UL_CLK_PERIPH2_CLK2_SEL, + imx_clk_mux(dev, "periph2_clk2_sel", base + 0x18, 20, 1, + periph2_clk2_sels, ARRAY_SIZE(periph2_clk2_sels))); + clk_dm(IMX6UL_CLK_PERIPH, + imx_clk_busy_mux(dev, "periph", base + 0x14, 25, 1, base + 0x48, + 5, periph_sels, ARRAY_SIZE(periph_sels))); + clk_dm(IMX6UL_CLK_AHB, + imx_clk_busy_divider(dev, "ahb", "periph", base + 0x14, 10, 3, + base + 0x48, 1)); + clk_dm(IMX6UL_CLK_PERIPH_CLK2, + imx_clk_divider(dev, "periph_clk2", "periph_clk2_sel", + base + 0x14, 27, 3)); + clk_dm(IMX6UL_CLK_PERIPH2_CLK2, + imx_clk_divider(dev, "periph2_clk2", "periph2_clk2_sel", + base + 0x14, 0, 3)); + clk_dm(IMX6UL_CLK_IPG, + imx_clk_divider(dev, "ipg", "ahb", base + 0x14, 8, 2)); + clk_dm(IMX6UL_CLK_ENFC_PRED, + imx_clk_divider(dev, "enfc_pred", "enfc_sel", base + 0x2c, 18, + 3)); + clk_dm(IMX6UL_CLK_ENFC_PODF, + imx_clk_divider(dev, "enfc_podf", "enfc_pred", base + 0x2c, 21, + 6)); + clk_dm(IMX6UL_CLK_GPMI_PODF, + imx_clk_divider(dev, "gpmi_podf", "gpmi_sel", base + 0x24, 22, + 3)); + clk_dm(IMX6UL_CLK_BCH_PODF, + imx_clk_divider(dev, "bch_podf", "bch_sel", base + 0x24, 19, 3)); + clk_dm(IMX6UL_CLK_PERCLK, + imx_clk_divider(dev, "perclk", "perclk_sel", base + 0x1c, 0, 6)); + clk_dm(IMX6UL_CLK_UART_PODF, + imx_clk_divider(dev, "uart_podf", "uart_sel", base + 0x24, 0, + 6)); + clk_dm(IMX6UL_CLK_USDHC1_PODF, + imx_clk_divider(dev, "usdhc1_podf", "usdhc1_sel", base + 0x24, + 11, 3)); + clk_dm(IMX6UL_CLK_USDHC2_PODF, + imx_clk_divider(dev, "usdhc2_podf", "usdhc2_sel", base + 0x24, + 16, 3)); + clk_dm(IMX6UL_CLK_ECSPI_PODF, + imx_clk_divider(dev, "ecspi_podf", "ecspi_sel", base + 0x38, 19, + 6)); + + clk_dm(IMX6UL_CLK_APBHDMA, + imx_clk_gate2(dev, "apbh_dma", "bch_podf", base + 0x68, 4)); + clk_dm(IMX6UL_CLK_ECSPI1, + imx_clk_gate2(dev, "ecspi1", "ecspi_podf", base + 0x6c, 0)); + clk_dm(IMX6UL_CLK_ECSPI2, + imx_clk_gate2(dev, "ecspi2", "ecspi_podf", base + 0x6c, 2)); + clk_dm(IMX6UL_CLK_ECSPI3, + imx_clk_gate2(dev, "ecspi3", "ecspi_podf", base + 0x6c, 4)); + clk_dm(IMX6UL_CLK_ECSPI4, + imx_clk_gate2(dev, "ecspi4", "ecspi_podf", base + 0x6c, 6)); + + clk_dm(IMX6UL_CLK_USBOH3, + imx_clk_gate2(dev, "usboh3", "ipg", base + 0x80, 0)); + clk_dm(IMX6UL_CLK_USDHC1, + imx_clk_gate2(dev, "usdhc1", "usdhc1_podf", base + 0x80, 2)); + clk_dm(IMX6UL_CLK_USDHC2, + imx_clk_gate2(dev, "usdhc2", "usdhc2_podf", base + 0x80, 4)); + + clk_dm(IMX6UL_CLK_UART1_IPG, + imx_clk_gate2(dev, "uart1_ipg", "ipg", base + 0x7c, 24)); + clk_dm(IMX6UL_CLK_UART1_SERIAL, + imx_clk_gate2(dev, "uart1_serial", "uart_podf", base + 0x7c, 24)); + clk_dm(IMX6UL_CLK_UART2_IPG, + imx_clk_gate2(dev, "uart2_ipg", "ipg", base + 0x68, 28)); + clk_dm(IMX6UL_CLK_UART2_SERIAL, + imx_clk_gate2(dev, "uart2_serial", "uart_podf", base + 0x68, 28)); + clk_dm(IMX6UL_CLK_UART3_IPG, + imx_clk_gate2(dev, "uart3_ipg", "ipg", base + 0x6c, 10)); + clk_dm(IMX6UL_CLK_UART3_SERIAL, + imx_clk_gate2(dev, "uart3_serial", "uart_podf", base + 0x6c, 10)); + clk_dm(IMX6UL_CLK_UART4_IPG, + imx_clk_gate2(dev, "uart4_ipg", "ipg", base + 0x6c, 24)); + clk_dm(IMX6UL_CLK_UART4_SERIAL, + imx_clk_gate2(dev, "uart4_serial", "uart_podf", base + 0x6c, 24)); + clk_dm(IMX6UL_CLK_UART5_IPG, + imx_clk_gate2(dev, "uart5_ipg", "ipg", base + 0x74, 2)); + clk_dm(IMX6UL_CLK_UART5_SERIAL, + imx_clk_gate2(dev, "uart5_serial", "uart_podf", base + 0x74, 2)); + clk_dm(IMX6UL_CLK_UART6_IPG, + imx_clk_gate2(dev, "uart6_ipg", "ipg", base + 0x74, 6)); + clk_dm(IMX6UL_CLK_UART6_SERIAL, + imx_clk_gate2(dev, "uart6_serial", "uart_podf", base + 0x74, 6)); + clk_dm(IMX6UL_CLK_UART7_IPG, + imx_clk_gate2(dev, "uart7_ipg", "ipg", base + 0x7c, 26)); + clk_dm(IMX6UL_CLK_UART7_SERIAL, + imx_clk_gate2(dev, "uart7_serial", "uart_podf", base + 0x7c, 26)); + clk_dm(IMX6UL_CLK_UART8_IPG, + imx_clk_gate2(dev, "uart8_ipg", "ipg", base + 0x80, 14)); + clk_dm(IMX6UL_CLK_UART8_SERIAL, + imx_clk_gate2(dev, "uart8_serial", "uart_podf", base + 0x80, 14)); + +#if CONFIG_IS_ENABLED(NAND_MXS) + clk_dm(IMX6UL_CLK_PER_BCH, + imx_clk_gate2(dev, "per_bch", "bch_podf", base + 0x78, 12)); + clk_dm(IMX6UL_CLK_GPMI_BCH_APB, + imx_clk_gate2(dev, "gpmi_bch_apb", "bch_podf", base + 0x78, 24)); + clk_dm(IMX6UL_CLK_GPMI_BCH, + imx_clk_gate2(dev, "gpmi_bch", "gpmi_podf", base + 0x78, 26)); + clk_dm(IMX6UL_CLK_GPMI_IO, + imx_clk_gate2(dev, "gpmi_io", "enfc_podf", base + 0x78, 28)); + clk_dm(IMX6UL_CLK_GPMI_APB, + imx_clk_gate2(dev, "gpmi_apb", "bch_podf", base + 0x78, 30)); +#endif + + clk_dm(IMX6UL_CLK_I2C1, + imx_clk_gate2(dev, "i2c1", "perclk", base + 0x70, 6)); + clk_dm(IMX6UL_CLK_I2C2, + imx_clk_gate2(dev, "i2c2", "perclk", base + 0x70, 8)); + clk_dm(IMX6UL_CLK_I2C3, + imx_clk_gate2(dev, "i2c3", "perclk", base + 0x70, 10)); + clk_dm(IMX6UL_CLK_PWM1, + imx_clk_gate2(dev, "pwm1", "perclk", base + 0x78, 16)); + + clk_dm(IMX6UL_CLK_ENET, + imx_clk_gate2(dev, "enet", "ipg", base + 0x6c, 10)); + clk_dm(IMX6UL_CLK_ENET_REF, + imx_clk_fixed_factor(dev, "enet_ref", "pll6_enet", 1, 1)); + + struct clk *clk, *clk1; + + clk_get_by_id(IMX6UL_CLK_ENFC_SEL, &clk); + clk_get_by_id(IMX6UL_CLK_PLL2_PFD2, &clk1); + + clk_set_parent(clk, clk1); + + return 0; +} + +static const struct udevice_id imx6ul_clk_ids[] = { + { .compatible = "fsl,imx6ul-ccm" }, + { }, +}; + +U_BOOT_DRIVER(imx6ul_clk) = { + .name = "clk_imx6ul", + .id = UCLASS_CLK, + .of_match = imx6ul_clk_ids, + .ops = &imx6ul_clk_ops, + .probe = imx6ul_clk_probe, + .flags = DM_FLAG_PRE_RELOC, +}; -- cgit v1.3.1 From 1c513b9edf64d82aaeb1308d2e0ea14e5a2e13f1 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Fri, 30 May 2025 17:16:44 +0200 Subject: mtd: mxs_nand_dt: Move from clk_get/clk_enable to clk_bulk api Make simple the clock registration and enable and allow later to add support for other platforms Signed-off-by: Michael Trimarchi --- drivers/mtd/nand/raw/mxs_nand_dt.c | 48 ++++---------------------------------- 1 file changed, 5 insertions(+), 43 deletions(-) diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c index 11dbcbbf442..b62474bc5ab 100644 --- a/drivers/mtd/nand/raw/mxs_nand_dt.c +++ b/drivers/mtd/nand/raw/mxs_nand_dt.c @@ -100,9 +100,7 @@ static int mxs_nand_dt_probe(struct udevice *dev) if (IS_ENABLED(CONFIG_CLK) && (IS_ENABLED(CONFIG_IMX8) || IS_ENABLED(CONFIG_IMX8M))) { - /* Assigned clock already set clock */ - struct clk gpmi_clk; - + struct clk_bulk clk_bulk; info->gpmi_clk = devm_clk_get(dev, "gpmi_io"); if (IS_ERR(info->gpmi_clk)) { @@ -111,47 +109,11 @@ static int mxs_nand_dt_probe(struct udevice *dev) return ret; } - ret = clk_enable(info->gpmi_clk); - if (ret < 0) { - debug("Can't enable gpmi io clk: %d\n", ret); - return ret; - } - - if (IS_ENABLED(CONFIG_IMX8)) { - ret = clk_get_by_name(dev, "gpmi_apb", &gpmi_clk); - if (ret < 0) { - debug("Can't get gpmi_apb clk: %d\n", ret); - return ret; - } - - ret = clk_enable(&gpmi_clk); - if (ret < 0) { - debug("Can't enable gpmi_apb clk: %d\n", ret); - return ret; - } - - ret = clk_get_by_name(dev, "gpmi_bch", &gpmi_clk); - if (ret < 0) { - debug("Can't get gpmi_bch clk: %d\n", ret); - return ret; - } - - ret = clk_enable(&gpmi_clk); - if (ret < 0) { - debug("Can't enable gpmi_bch clk: %d\n", ret); - return ret; - } - } - - ret = clk_get_by_name(dev, "gpmi_bch_apb", &gpmi_clk); - if (ret < 0) { - debug("Can't get gpmi_bch_apb clk: %d\n", ret); - return ret; - } - - ret = clk_enable(&gpmi_clk); + ret = clk_get_bulk(dev, &clk_bulk); + if (!ret) + ret = clk_enable_bulk(&clk_bulk); if (ret < 0) { - debug("Can't enable gpmi_bch_apb clk: %d\n", ret); + debug("Can't enable gpmi clks: %d\n", ret); return ret; } } -- cgit v1.3.1 From 404a4c84d8800ce3e39cdaff1c6bc97ad3d6c459 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Fri, 30 May 2025 17:16:45 +0200 Subject: mtd: nand: Add support for EDO mode 1-5 to IMX6ULL platform The clock driver allows to boost the NAND performance controller. Make changes to let it use the new clock driver => time nand read ${loadaddr} kernel NAND read: device 0 offset 0x500000, size 0x800000 8388608 bytes read: OK time: 0.488 seconds Signed-off-by: Michael Trimarchi --- drivers/mtd/nand/raw/mxs_nand.c | 10 ++++++++++ drivers/mtd/nand/raw/mxs_nand_dt.c | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/mxs_nand.c b/drivers/mtd/nand/raw/mxs_nand.c index 80d9307cdd1..ba67466069b 100644 --- a/drivers/mtd/nand/raw/mxs_nand.c +++ b/drivers/mtd/nand/raw/mxs_nand.c @@ -1507,8 +1507,18 @@ static void mxs_compute_timings(struct nand_chip *chip, writel(GPMI_CTRL1_CLEAR_MASK, &nand_info->gpmi_regs->hw_gpmi_ctrl1_clr); writel(ctrl1n, &nand_info->gpmi_regs->hw_gpmi_ctrl1_set); + /* Clock dividers do NOT guarantee a clean clock signal on its output + * during the change of the divide factor on i.MX6Q/UL/SX. On i.MX7/8, + * all clock dividers provide these guarantee. + */ + if (IS_ENABLED(CONFIG_MX6ULL)) + clk_disable(nand_info->gpmi_clk); + clk_set_rate(nand_info->gpmi_clk, clk_rate); + if (IS_ENABLED(CONFIG_MX6ULL)) + clk_enable(nand_info->gpmi_clk); + /* Wait 64 clock cycles before using the GPMI after enabling the DLL */ dll_wait_time_us = USEC_PER_SEC / clk_rate * 64; if (!dll_wait_time_us) diff --git a/drivers/mtd/nand/raw/mxs_nand_dt.c b/drivers/mtd/nand/raw/mxs_nand_dt.c index b62474bc5ab..90eefa2558d 100644 --- a/drivers/mtd/nand/raw/mxs_nand_dt.c +++ b/drivers/mtd/nand/raw/mxs_nand_dt.c @@ -99,7 +99,7 @@ static int mxs_nand_dt_probe(struct udevice *dev) info->use_minimum_ecc = dev_read_bool(dev, "fsl,use-minimum-ecc"); if (IS_ENABLED(CONFIG_CLK) && - (IS_ENABLED(CONFIG_IMX8) || IS_ENABLED(CONFIG_IMX8M))) { + (IS_ENABLED(CONFIG_IMX8) || IS_ENABLED(CONFIG_IMX8M) || IS_ENABLED(CONFIG_MX6ULL))) { struct clk_bulk clk_bulk; info->gpmi_clk = devm_clk_get(dev, "gpmi_io"); -- cgit v1.3.1 From 8642939ee049b737c179afd530da3dc1f9525964 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Fri, 30 May 2025 17:16:46 +0200 Subject: configs/imx6ulz_smm_m2_defconfig: Enable clock framework Enable the clock framework on the m2 platform. This helps to increase the NAND controller performance. Signed-off-by: Michael Trimarchi --- configs/imx6ulz_smm_m2_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/imx6ulz_smm_m2_defconfig b/configs/imx6ulz_smm_m2_defconfig index 436bfb78cc2..6e425d6e52d 100644 --- a/configs/imx6ulz_smm_m2_defconfig +++ b/configs/imx6ulz_smm_m2_defconfig @@ -43,6 +43,8 @@ CONFIG_ENV_IS_IN_NAND=y CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_NO_NET=y CONFIG_BOUNCE_BUFFER=y +CONFIG_CLK_COMPOSITE_CCF=y +CONFIG_CLK_IMX6UL=y CONFIG_USB_FUNCTION_FASTBOOT=y CONFIG_FASTBOOT_BUF_ADDR=0x82000000 CONFIG_FASTBOOT_FLASH=y -- cgit v1.3.1 From c7b82b4aabc6ef9af953b779490eb2385d299f51 Mon Sep 17 00:00:00 2001 From: Michael Trimarchi Date: Sat, 31 May 2025 16:54:33 +0200 Subject: bsh: imx6ulz_smm_m2: Add imx6ulz BSH SMM M2B board Introduce the BSH SystemMaster (SMM) M2B board. Notably, the M2B is designed to leverage the existing device tree of its predecessor, the M2. The primary distinction arises from memory incompatibilities with the M2. To address this, we've implemented a configuration system that allows for selective inclusion of the desired memory components. Signed-off-by: Michael Trimarchi --- board/bsh/imx6ulz_smm_m2/Kconfig | 21 ++++ board/bsh/imx6ulz_smm_m2/MAINTAINERS | 1 + board/bsh/imx6ulz_smm_m2/Makefile | 4 +- board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m.c | 1 + board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m_m2b.c | 152 +++++++++++++++++++++++ board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m.c | 1 + board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m_m2b.c | 137 ++++++++++++++++++++ board/bsh/imx6ulz_smm_m2/ddr3l_timing_512m.c | 1 + board/bsh/imx6ulz_smm_m2/spl.c | 37 +++--- board/bsh/imx6ulz_smm_m2/spl_mtypes.h | 1 + configs/imx6ulz_smm_m2b_defconfig | 78 ++++++++++++ 11 files changed, 416 insertions(+), 18 deletions(-) create mode 100644 board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m_m2b.c create mode 100644 board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m_m2b.c create mode 100644 configs/imx6ulz_smm_m2b_defconfig diff --git a/board/bsh/imx6ulz_smm_m2/Kconfig b/board/bsh/imx6ulz_smm_m2/Kconfig index e38df7ce5cb..20971aa4fe1 100644 --- a/board/bsh/imx6ulz_smm_m2/Kconfig +++ b/board/bsh/imx6ulz_smm_m2/Kconfig @@ -9,4 +9,25 @@ config SYS_VENDOR config SYS_CONFIG_NAME default "imx6ulz_smm_m2" +choice + prompt "Memory Type (M2/M2B) board" + default BSH_M2_MEMORY + help + Memory type setup. + Please choose correct memory model here. + +config BSH_M2_MEMORY + bool "Enable for bsh m2 variant" + help + If this option is enabled, U-Boot will be configured to support + imx6ulz bsh m2 revision memories. + +config BSH_M2B_MEMORY + bool "Enable for bsh m2b variant" + help + If this option is enabled, U-Boot will be configured to support + imx6ulz bsh m2b revision memories. + +endchoice + endif diff --git a/board/bsh/imx6ulz_smm_m2/MAINTAINERS b/board/bsh/imx6ulz_smm_m2/MAINTAINERS index 77a033c6cbb..a75cddd72f8 100644 --- a/board/bsh/imx6ulz_smm_m2/MAINTAINERS +++ b/board/bsh/imx6ulz_smm_m2/MAINTAINERS @@ -4,3 +4,4 @@ S: Maintained F: board/bsh/imx6ulz_smm_m2/ F: include/configs/imx6ulz_smm_m2.h F: configs/imx6ulz_smm_m2_defconfig +F: configs/imx6ulz_smm_m2b_defconfig diff --git a/board/bsh/imx6ulz_smm_m2/Makefile b/board/bsh/imx6ulz_smm_m2/Makefile index 4f4d67f659d..233bbff4c16 100644 --- a/board/bsh/imx6ulz_smm_m2/Makefile +++ b/board/bsh/imx6ulz_smm_m2/Makefile @@ -2,4 +2,6 @@ # (C) Copyright 2021 Amarula Solutions B.V. obj-y := imx6ulz_smm_m2.o -obj-$(CONFIG_XPL_BUILD) += spl.o ddr3l_timing_512m.o ddr3l_timing_256m.o ddr3l_timing_128m.o +obj-$(CONFIG_XPL_BUILD) += spl.o +obj-$(CONFIG_BSH_M2_MEMORY) += ddr3l_timing_512m.o ddr3l_timing_256m.o ddr3l_timing_128m.o +obj-$(CONFIG_BSH_M2B_MEMORY) += ddr3l_timing_256m_m2b.o ddr3l_timing_128m_m2b.o diff --git a/board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m.c b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m.c index 66c3483adbf..f11654a8ceb 100644 --- a/board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m.c +++ b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m.c @@ -166,4 +166,5 @@ static const struct dram_cfg_param ddr_ddrc_cfg_128mb[] = { struct dram_timing_info bsh_dram_timing_128mb = { .ddrc_cfg = ddr_ddrc_cfg_128mb, .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_128mb), + .dram_size = SZ_128M, }; diff --git a/board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m_m2b.c b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m_m2b.c new file mode 100644 index 00000000000..f989e24f567 --- /dev/null +++ b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_128m_m2b.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include "spl_mtypes.h" + +static const struct dram_cfg_param ddr_ddrc_cfg_128mb[] = { + /* IOMUX */ + + /* DDR IO Type: */ + {0x020e04b4, 0x000C0000}, /* IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE */ + {0x020e04ac, 0x00000000}, /* IOMUXC_SW_PAD_CTL_GRP_DDRPKE */ + + /* Clock: */ + {0x020e027c, 0x00000028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK_0 */ + + /* Address: */ + {0x020e0250, 0x00000028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS */ + {0x020e024c, 0x00000028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS */ + {0x020e0490, 0x00000028}, /* IOMUXC_SW_PAD_CTL_GRP_ADDDS */ + + /* Control: */ + {0x020e0288, 0x000C0028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_RESET */ + {0x020e0270, 0x00000000}, /* + * IOMUXC_SW_PAD_CTL_PAD_DRAM_SDBA2 - DSE can be configured + * using Group Control Register IOMUXC_SW_PAD_CTL_GRP_CTLDS + */ + + {0x020e0260, 0x00000028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT0 */ + {0x020e0264, 0x00000028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_SDODT1 */ + {0x020e04a0, 0x00000028}, /* IOMUXC_SW_PAD_CTL_GRP_CTLDS */ + + /* Data Strobes: */ + {0x020e0494, 0x00020000}, /* IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL */ + {0x020e0280, 0x00000028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0 */ + {0x020e0284, 0x00000028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1 */ + + /* Data: */ + {0x020e04b0, 0x00020000}, /* IOMUXC_SW_PAD_CTL_GRP_DDRMODE */ + {0x020e0498, 0x00000028}, /* IOMUXC_SW_PAD_CTL_GRP_B0DS */ + {0x020e04a4, 0x00000028}, /* IOMUXC_SW_PAD_CTL_GRP_B1DS */ + + {0x020e0244, 0x00000028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0 */ + {0x020e0248, 0x00000028}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1 */ + + /* + * ============================================================================= + * DDR Controller Registers + * ============================================================================= + * Manufacturer:WINBOND + * Device Part Number:W631GU6RB-11 + * Clock Freq.: 400MHz + * Density per CS in Gb: 1 + * Chip Selects used:1 + * Total DRAM density (Gb)1 + * Number of Banks:8 + * Row address: 13 + * Column address: 10 + * Data bus width16 + * ============================================================================= + */ + {0x021b001c, 0x00008000}, /* + * MMDC0_MDSCR, set the Configuration request bit + * during MMDC set up + */ + + /* + * ============================================================================= + * Calibration setup. + * ============================================================================= + */ + {0x021b0800, 0xA1390003}, /* + * DDR_PHY_P0_MPZQHWCTRL, enable both one-time & periodic + * HW ZQ calibration. + */ + + /* + * For target board, may need to run write leveling calibration to fine tune + * these settings. + */ + {0x021b080c, 0x00060002}, + + /* Read DQS Gating calibration */ + {0x021b083c, 0x414c0150}, /* MPDGCTRL0 PHY0 */ + + /* Read calibration */ + {0x021b0848, 0x4040363e}, /* MPRDDLCTL PHY0 */ + + /* Write calibration */ + {0x021b0850, 0x40402a28}, /* MPWRDLCTL PHY0 */ + + /* + * Read data bit delay: 3 is the recommended default value, although out of reset + * value is 0. + */ + {0x021b081c, 0x33333333}, /* MMDC_MPRDDQBY0DL */ + {0x021b0820, 0x33333333}, /* MMDC_MPRDDQBY1DL */ + + /* Write data bit delay: */ + {0x021b082c, 0xf3333333}, /* MMDC_MPWRDQBY0DL */ + {0x021b0830, 0xf3333333}, /* MMDC_MPWRDQBY1DL */ + + /* DQS&CLK Duty Cycle */ + {0x021b08c0, 0x00944009}, /* [MMDC_MPDCCR] MMDC Duty Cycle Control Register */ + + /* Complete calibration by forced measurement: */ + {0x021b08b8, 0x00000800}, /* DDR_PHY_P0_MPMUR0, frc_msr */ + + /* MMDC init: */ + {0x021b0004, 0x0002002D}, /* MMDC0_MDPDC */ + {0x021b0008, 0x1B333030}, /* MMDC0_MDOTC */ + {0x021b000c, 0x2B2F52F3}, /* MMDC0_MDCFG0 */ + {0x021b0010, 0xB66D0A63}, /* MMDC0_MDCFG1 */ + {0x021b0014, 0x01FF00DB}, /* MMDC0_MDCFG2 */ + {0x021b0018, 0x00201740}, /* MMDC0_MDMISC */ + {0x021b002C, 0x000026D2}, /* MMDC0_MDRWD */ + {0x021b0030, 0x002F1023}, /* MMDC0_MDOR */ + {0x021b0040, 0x00000043}, /* CS0_END */ + {0x021b0000, 0x82180000}, /* MMDC0_MDCTL */ + + /* Mode register writes for CS0 */ + {0x021B001C, 0x02808032}, /* MMDC0_MDSCR, MR2 write, CS0 */ + {0x021B001C, 0x00008033}, /* MMDC0_MDSCR, MR3 write, CS0 */ + {0x021B001C, 0x00048031}, /* MMDC0_MDSCR, MR1 write, CS0 */ + {0x021B001C, 0x15208030}, /* MMDC0_MDSCR, MR0 write, CS0 */ + {0x021B001C, 0x04008040}, /* + * MMDC0_MDSCR, ZQ calibration + * command sent to device on CS0 + */ + + /* final DDR setup, before operation start: */ + {0x021b0020, 0x00000800}, /* MMDC0_MDREF */ + + {0x021b0818, 0x00000227}, /* DDR_PHY_P0_MPODTCTRL */ + + {0x021b0004, 0x0002556D}, /* MMDC0_MDPDC now SDCTL power down enabled */ + + {0x021b0404, 0x00011006}, /* + * MMDC0_MAPSR ADOPT power down enabled, + * MMDC will enter automatically to self-refresh + * while the number of idle cycle reached. + */ + + {0x021b001c, 0x00000000}, /* + * MMDC0_MDSCR, clear this register (especially the + * configuration bit as initialization is complete) + */ +}; + +struct dram_timing_info bsh_dram_timing_128mb = { + .ddrc_cfg = ddr_ddrc_cfg_128mb, + .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_128mb), + .dram_size = SZ_128M, +}; diff --git a/board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m.c b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m.c index 0fe5b90a673..5dfc9f5c70d 100644 --- a/board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m.c +++ b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m.c @@ -165,4 +165,5 @@ static const struct dram_cfg_param ddr_ddrc_cfg_256mb[] = { struct dram_timing_info bsh_dram_timing_256mb = { .ddrc_cfg = ddr_ddrc_cfg_256mb, .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_256mb), + .dram_size = SZ_256M, }; diff --git a/board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m_m2b.c b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m_m2b.c new file mode 100644 index 00000000000..c44f632b928 --- /dev/null +++ b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_256m_m2b.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include "spl_mtypes.h" + +static const struct dram_cfg_param ddr_ddrc_cfg_256mb[] = { + /* IOMUX */ + + /* DDR IO Type: */ + {0x020e04b4, 0x000C0000}, /* IOMUXC_SW_PAD_CTL_GRP_DDR_TYPE */ + {0x020e04ac, 0x00000000}, /* IOMUXC_SW_PAD_CTL_GRP_DDRPKE */ + + /* Clock: */ + {0x020e027c, 0x00000030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_SDCLK0_P */ + + /* Address: */ + {0x020e0250, 0x00000030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_CAS */ + {0x020e024c, 0x00000030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_RAS */ + {0x020e0490, 0x00000030}, /* IOMUXC_SW_PAD_CTL_GRP_ADDDS */ + + /* Control: */ + {0x020e0288, 0x000C0030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_RESET */ + {0x020e0270, 0x00000000}, /* + * IOMUXC_SW_PAD_CTL_PAD_DRAM_SDBA2 - DSE can be + * configured using Group Control Register: + * IOMUXC_SW_PAD_CTL_GRP_CTLDS + */ + + {0x020e0260, 0x00000030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_ODT0 */ + {0x020e0264, 0x00000030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_ODT1 */ + {0x020e04a0, 0x00000028}, /* IOMUXC_SW_PAD_CTL_GRP_CTLDS */ + + /* Data Strobes: */ + {0x020e0494, 0x00020000}, /* IOMUXC_SW_PAD_CTL_GRP_DDRMODE_CTL */ + {0x020e0280, 0x00000030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS0_P */ + {0x020e0284, 0x00000030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_SDQS1_P */ + + /* Data: */ + {0x020e04b0, 0x00020000}, /* IOMUXC_SW_PAD_CTL_GRP_DDRMODE */ + {0x020e0498, 0x00000030}, /* IOMUXC_SW_PAD_CTL_GRP_B0DS */ + {0x020e04a4, 0x00000030}, /* IOMUXC_SW_PAD_CTL_GRP_B1DS */ + + {0x020e0244, 0x00000030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM0 */ + {0x020e0248, 0x00000030}, /* IOMUXC_SW_PAD_CTL_PAD_DRAM_DQM1 */ + + /* + * ============================================================================= + * DDR Controller Registers + * ============================================================================= + * Manufacturer:WINBOND + * Device Part Number:W632GU6RB-11 + * Clock Freq.: 400MHz + * Density per CS in Gb: 2 + * Chip Selects used:1 + * Total DRAM density (Gb)2 + * Number of Banks:8 + * Row address: 14 + * Column address: 10 + * Data bus width16 + * ============================================================================= + */ + {0x021b001c, 0x00008000}, /* + * MMDC0_MDSCR, set the Configuration request bit + * during MMDC set up + */ + + /* + * ============================================================================= + * Calibration setup. + * ============================================================================= + */ + {0x021b0800, 0xA1390003}, /* + * DDR_PHY_P0_MPZQHWCTRL, enable both one-time & periodic + * HW ZQ calibration. + */ + + /* + * For target board, may need to run write leveling calibration to fine tune + * these settings. + */ + {0x021b080c, 0x00070005}, + + /* Read DQS Gating calibration */ + {0x021b083c, 0x414c0150}, /* MPDGCTRL0 PHY0 */ + + /* Read calibration */ + {0x021b0848, 0x4040383e}, /* MMDC_MPRDDLCTL */ + + /* Write calibration */ + {0x021b0850, 0x40402e2a}, /* MMDC_MPWRDLCTL */ + + {0x021B081C, 0x33333333}, /* MMDC_MPRDDQBY0DL */ + {0x021B0820, 0x33333333}, /* MMDC_MPRDDQBY1DL */ + + {0x021B082C, 0xf3333333}, /* MMDC_MPWRDQBY0DL */ + {0x021B0830, 0xf3333333}, /* MMDC_MPWRDQBY1DL */ + + {0x021B08C0, 0x00944009}, /* MMDC_MPDCCR */ + + /* Complete calibration by forced measurement: */ + {0x021B08B8, 0x00000800}, /* DDR_PHY_P0_MPMUR0, frc_msr */ + + /* MMDC init: */ + {0x021b0004, 0x00020024}, /* MMDC0_MDPDC */ + {0x021b0008, 0x1B333030}, /* MMDC0_MDOTC */ + {0x021b000c, 0x3F4352D3}, /* MMDC0_MDCFG0 */ + {0x021b0010, 0xB66D0A63}, /* MMDC0_MDCFG1 */ + {0x021b0014, 0x01FF00DB}, /* MMDC0_MDCFG2 */ + {0x021b0018, 0x00201740}, /* MMDC0_MDMISC */ + {0x021b002C, 0x000026D2}, /* MMDC0_MDRWD */ + {0x021b0030, 0x00431023}, /* MMDC0_MDOR */ + {0x021b0040, 0x00000047}, /* CS0_END */ + {0x021b0000, 0x83180000}, /* MMDC0_MDCTL */ + + /* Mode register writes for CS0 */ + {0x021B001C, 0x02808032}, /* MMDC0_MDSCR, MR2 write, CS0 */ + {0x021B001C, 0x00008033}, /* MMDC0_MDSCR, MR3 write, CS0 */ + {0x021B001C, 0x00048031}, /* MMDC0_MDSCR, MR1 write, CS0 */ + {0x021B001C, 0x15208030}, /* MMDC0_MDSCR, MR0 write, CS0 */ + {0x021B001C, 0x04008040}, /* MMDC0_MDSCR, ZQ calibration */ + + /* final DDR setup, before operation start: */ + {0x021b0020, 0x00000800}, /* MMDC0_MDREF */ + + {0x021b0818, 0x00000227}, /* DDR_PHY_P0_MPODTCTRL */ + {0x021b0004, 0x00025564}, /* MMDC0_MDPDC now SDCTL power down enabled */ + {0x021b0404, 0x00011006}, /* MMDC0_MAPSR ADOPT power down enabled */ + {0x021b001c, 0x00000000}, /* + * MMDC0_MDSCR, clear this register (especially + * the configuration bit as initialization is complete) + */ +}; + +struct dram_timing_info bsh_dram_timing_256mb = { + .ddrc_cfg = ddr_ddrc_cfg_256mb, + .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_256mb), + .dram_size = SZ_256M, +}; diff --git a/board/bsh/imx6ulz_smm_m2/ddr3l_timing_512m.c b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_512m.c index f5989382f5a..4c2ffcd429d 100644 --- a/board/bsh/imx6ulz_smm_m2/ddr3l_timing_512m.c +++ b/board/bsh/imx6ulz_smm_m2/ddr3l_timing_512m.c @@ -165,4 +165,5 @@ static const struct dram_cfg_param ddr_ddrc_cfg_512mb[] = { struct dram_timing_info bsh_dram_timing_512mb = { .ddrc_cfg = ddr_ddrc_cfg_512mb, .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg_512mb), + .dram_size = SZ_512M, }; diff --git a/board/bsh/imx6ulz_smm_m2/spl.c b/board/bsh/imx6ulz_smm_m2/spl.c index c330e4d6d39..7aea73f0f5d 100644 --- a/board/bsh/imx6ulz_smm_m2/spl.c +++ b/board/bsh/imx6ulz_smm_m2/spl.c @@ -52,28 +52,31 @@ static void ddr_cfg_write(const struct dram_timing_info *dram_timing_info) } } +static const struct dram_timing_info *board_dram_timing[] = { +#if defined(CONFIG_M2_MEMORY) + &bsh_dram_timing_512mb, +#endif + &bsh_dram_timing_256mb, + &bsh_dram_timing_128mb, +}; + static void spl_dram_init(void) { /* Configure memory to maximum supported size for detection */ - ddr_cfg_write(&bsh_dram_timing_512mb); + ddr_cfg_write(board_dram_timing[0]); /* Detect memory physically present */ - gd->ram_size = get_ram_size((void *)CFG_SYS_SDRAM_BASE, SZ_512M); - - /* Reconfigure memory for actual detected size */ - switch (gd->ram_size) { - case SZ_512M: - /* Already configured, nothing to do */ - break; - case SZ_256M: - udelay(1); - ddr_cfg_write(&bsh_dram_timing_256mb); - break; - case SZ_128M: - default: - udelay(1); - ddr_cfg_write(&bsh_dram_timing_128mb); - break; + gd->ram_size = get_ram_size((void *)CFG_SYS_SDRAM_BASE, board_dram_timing[0]->dram_size); + + if (board_dram_timing[0]->dram_size == gd->ram_size) + return; + + for (size_t index = 1; index < ARRAY_SIZE(board_dram_timing); index++) { + if (board_dram_timing[index]->dram_size == gd->ram_size) { + udelay(1); + ddr_cfg_write(board_dram_timing[index]); + break; + } } } diff --git a/board/bsh/imx6ulz_smm_m2/spl_mtypes.h b/board/bsh/imx6ulz_smm_m2/spl_mtypes.h index 8da59881c83..06d6f2d76d8 100644 --- a/board/bsh/imx6ulz_smm_m2/spl_mtypes.h +++ b/board/bsh/imx6ulz_smm_m2/spl_mtypes.h @@ -18,6 +18,7 @@ struct dram_cfg_param { struct dram_timing_info { const struct dram_cfg_param *ddrc_cfg; unsigned int ddrc_cfg_num; + size_t dram_size; }; extern struct dram_timing_info bsh_dram_timing_128mb; diff --git a/configs/imx6ulz_smm_m2b_defconfig b/configs/imx6ulz_smm_m2b_defconfig new file mode 100644 index 00000000000..c9e66adde98 --- /dev/null +++ b/configs/imx6ulz_smm_m2b_defconfig @@ -0,0 +1,78 @@ +CONFIG_ARM=y +CONFIG_ARCH_MX6=y +CONFIG_TEXT_BASE=0x87800000 +CONFIG_SYS_MALLOC_LEN=0x1000000 +CONFIG_SYS_MALLOC_F_LEN=0x18000 +CONFIG_SPL_GPIO=y +CONFIG_SPL_LIBCOMMON_SUPPORT=y +CONFIG_SPL_LIBGENERIC_SUPPORT=y +CONFIG_NR_DRAM_BANKS=1 +CONFIG_ENV_SIZE=0x20000 +CONFIG_ENV_OFFSET=0x400000 +CONFIG_MX6ULL=y +CONFIG_TARGET_MX6ULZ_SMM_M2=y +CONFIG_BSH_M2B_MEMORY=y +CONFIG_DEFAULT_DEVICE_TREE="nxp/imx/imx6ulz-bsh-smm-m2" +CONFIG_SPL_SERIAL=y +CONFIG_SPL_BSS_START_ADDR=0x84100000 +CONFIG_SPL=y +CONFIG_FIT=y +CONFIG_FIT_SIGNATURE=y +CONFIG_FIT_VERBOSE=y +CONFIG_LEGACY_IMAGE_FORMAT=y +CONFIG_DISTRO_DEFAULTS=y +CONFIG_BOOTDELAY=3 +CONFIG_BOARD_LATE_INIT=y +CONFIG_SPL_SYS_MALLOC=y +CONFIG_SPL_DMA=y +CONFIG_SPL_MTD=y +CONFIG_SPL_NAND_SUPPORT=y +CONFIG_SPL_WATCHDOG=y +CONFIG_CMD_GPIO=y +CONFIG_CMD_I2C=y +CONFIG_CMD_USB=y +CONFIG_CMD_USB_SDP=y +CONFIG_CMD_CACHE=y +CONFIG_CMD_MTDPARTS=y +CONFIG_MTDIDS_DEFAULT="nand0=gpmi-nand" +CONFIG_MTDPARTS_DEFAULT="mtdparts=gpmi-nand:4m(nandboot),1m(env),8m(kernel),1m(nanddtb),-(rootfs)" +CONFIG_CMD_UBI=y +# CONFIG_ISO_PARTITION is not set +CONFIG_OF_CONTROL=y +CONFIG_ENV_OVERWRITE=y +CONFIG_ENV_IS_IN_NAND=y +CONFIG_SYS_RELOC_GD_ENV_ADDR=y +CONFIG_NO_NET=y +CONFIG_BOUNCE_BUFFER=y +CONFIG_USB_FUNCTION_FASTBOOT=y +CONFIG_FASTBOOT_BUF_ADDR=0x82000000 +CONFIG_FASTBOOT_FLASH=y +CONFIG_FASTBOOT_UUU_SUPPORT=y +CONFIG_SYS_I2C_MXC=y +# CONFIG_MMC is not set +CONFIG_MTD=y +CONFIG_MTD_RAW_NAND=y +CONFIG_SYS_NAND_USE_FLASH_BBT=y +CONFIG_NAND_MXS=y +CONFIG_NAND_MXS_DT=y +CONFIG_SYS_NAND_ONFI_DETECTION=y +CONFIG_SYS_NAND_U_BOOT_LOCATIONS=y +CONFIG_SYS_NAND_U_BOOT_OFFS=0x111400 +CONFIG_SYS_NAND_U_BOOT_OFFS_REDUND=0x291400 +CONFIG_PINCTRL=y +CONFIG_PINCTRL_IMX6=y +CONFIG_DM_PMIC=y +CONFIG_DM_REGULATOR=y +CONFIG_DM_REGULATOR_FIXED=y +CONFIG_MXC_UART=y +CONFIG_IMX_THERMAL=y +CONFIG_USB=y +CONFIG_SPL_USB_HOST=y +CONFIG_USB_GADGET=y +CONFIG_SPL_USB_GADGET=y +CONFIG_USB_GADGET_MANUFACTURER="BSH" +CONFIG_USB_GADGET_VENDOR_NUM=0x0525 +CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5 +CONFIG_CI_UDC=y +CONFIG_SDP_LOADADDR=0x877fffc0 +CONFIG_SPL_USB_SDP_SUPPORT=y -- cgit v1.3.1