summaryrefslogtreecommitdiff
path: root/board/gateworks
diff options
context:
space:
mode:
Diffstat (limited to 'board/gateworks')
-rw-r--r--board/gateworks/fsa.c736
-rw-r--r--board/gateworks/fsa.h51
-rw-r--r--board/gateworks/gw_ventana/gw_ventana.c1
-rw-r--r--board/gateworks/venice/Makefile1
-rw-r--r--board/gateworks/venice/eeprom.c130
-rw-r--r--board/gateworks/venice/eeprom.h3
-rw-r--r--board/gateworks/venice/lpddr4_timing.h14
-rw-r--r--board/gateworks/venice/lpddr4_timing_imx8mm.c103
-rw-r--r--board/gateworks/venice/lpddr4_timing_imx8mn.c31
-rw-r--r--board/gateworks/venice/lpddr4_timing_imx8mp.c23
-rw-r--r--board/gateworks/venice/spl.c110
-rw-r--r--board/gateworks/venice/venice.c8
12 files changed, 1087 insertions, 124 deletions
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 <command.h>
+#include <hexdump.h>
+#include <i2c.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <dm/device_compat.h>
+#include <dm/device-internal.h> // device_remove/device_unbind
+#include <asm-generic/gpio.h>
+#include <fdt_support.h>
+#include <linux/delay.h>
+
+#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 [<offset>]|[<offset> <source>] - show a specific gpio descriptor\n"
+ "fsa gpio [<offset> <name> <input|output-low|output-high> [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/gw_ventana/gw_ventana.c b/board/gateworks/gw_ventana/gw_ventana.c
index 21a908c20dd..457d8281a66 100644
--- a/board/gateworks/gw_ventana/gw_ventana.c
+++ b/board/gateworks/gw_ventana/gw_ventana.c
@@ -6,6 +6,7 @@
*/
#include <command.h>
+#include <env.h>
#include <fdt_support.h>
#include <gsc.h>
#include <hwconfig.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 afaabf34879..d9a87193434 100644
--- a/board/gateworks/venice/eeprom.c
+++ b/board/gateworks/venice/eeprom.c
@@ -6,9 +6,11 @@
#include <gsc.h>
#include <hexdump.h>
#include <i2c.h>
+#include <dm/device.h>
#include <dm/uclass.h>
#include "eeprom.h"
+#include "../fsa.h"
/* I2C */
#define SOM_EEPROM_BUSNO 0
@@ -18,7 +20,8 @@
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;
@@ -107,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));
@@ -126,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, &reg, 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)
{
@@ -299,6 +350,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;
}
@@ -315,6 +368,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);
@@ -322,7 +376,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 */
@@ -347,9 +401,74 @@ 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];
+ }
+ }
+
+ /* 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;
+ }
+
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);
}
@@ -363,6 +482,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..a0f449299aa 100644
--- a/board/gateworks/venice/eeprom.h
+++ b/board/gateworks/venice/eeprom.h
@@ -20,12 +20,13 @@ 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 */
};
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/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..956071c5125 100644
--- a/board/gateworks/venice/lpddr4_timing_imx8mm.c
+++ b/board/gateworks/venice/lpddr4_timing_imx8mm.c
@@ -6,6 +6,7 @@
*/
#include <linux/kernel.h>
+#include <string.h>
#include <asm/arch/ddr.h>
#include <asm/arch/lpddr4_define.h>
@@ -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 },
@@ -1830,7 +1831,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 +2490,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 +3006,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 +3141,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 +3157,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 +3522,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 +3535,63 @@ struct dram_timing_info dram_timing_2gb = {
.ddrphy_pie_num = ARRAY_SIZE(lpddr4_phy_pie),
.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;
+
+ 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;
+ }
+
+ /* 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;
+}
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 <linux/kernel.h>
+#include <string.h>
#include <asm/arch/ddr.h>
/*
@@ -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..e813f3e763e 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,21 +55,23 @@ 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();
+ const char *som = eeprom_get_som_model();
struct udevice *bus;
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) {
@@ -141,10 +80,7 @@ static int power_init_board(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);
@@ -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);
}
diff --git a/board/gateworks/venice/venice.c b/board/gateworks/venice/venice.c
index 98b33624f04..6a24f618ae2 100644
--- a/board/gateworks/venice/venice.c
+++ b/board/gateworks/venice/venice.c
@@ -3,6 +3,7 @@
* Copyright 2021 Gateworks Corporation
*/
+#include <env.h>
#include <fdt_support.h>
#include <init.h>
#include <led.h>
@@ -14,6 +15,7 @@
#include <asm/mach-imx/boot_mode.h>
#include "eeprom.h"
+#include "../fsa.h"
int board_phys_sdram_size(phys_size_t *size)
{
@@ -75,6 +77,9 @@ int board_init(void)
{
venice_eeprom_init(1);
+ /* detect and configure FSA adapters */
+ fsa_init();
+
return 0;
}
@@ -221,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");