From mboxrd@z Thu Jan 1 00:00:00 1970 Return-path: Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1k7Z2f-0004t7-NY for barebox@lists.infradead.org; Mon, 17 Aug 2020 06:54:51 +0000 Date: Mon, 17 Aug 2020 08:54:47 +0200 From: Oleksij Rempel Message-ID: <20200817065447.bge4k7m7xsu4c45e@pengutronix.de> References: <20200813125514.13574-1-o.rempel@pengutronix.de> <20200813125514.13574-5-o.rempel@pengutronix.de> <20200813160726.40c40aad@erd988> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20200813160726.40c40aad@erd988> List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "barebox" Errors-To: barebox-bounces+u.kleine-koenig=pengutronix.de@lists.infradead.org Subject: Re: [PATCH v3 4/6] ARM: protonic-imx6: port Protonic specific board code To: David Jander Cc: barebox@lists.infradead.org On Thu, Aug 13, 2020 at 04:07:26PM +0200, David Jander wrote: > On Thu, 13 Aug 2020 14:55:12 +0200 > Oleksij Rempel wrote: > > > Signed-off-by: Oleksij Rempel > > --- > > arch/arm/boards/protonic-imx6/Makefile | 1 + > > arch/arm/boards/protonic-imx6/board.c | 1002 ++++++++++++++++++++++++ > > 2 files changed, 1003 insertions(+) > > create mode 100644 arch/arm/boards/protonic-imx6/board.c > > > > diff --git a/arch/arm/boards/protonic-imx6/Makefile b/arch/arm/boards/protonic-imx6/Makefile > > index b08c4a93ca..01c7a259e9 100644 > > --- a/arch/arm/boards/protonic-imx6/Makefile > > +++ b/arch/arm/boards/protonic-imx6/Makefile > > @@ -1 +1,2 @@ > > +obj-y += board.o > > lwl-y += lowlevel.o > > diff --git a/arch/arm/boards/protonic-imx6/board.c b/arch/arm/boards/protonic-imx6/board.c > > new file mode 100644 > > index 0000000000..f3bd0dd86a > > --- /dev/null > > +++ b/arch/arm/boards/protonic-imx6/board.c > > @@ -0,0 +1,1002 @@ > > +// SPDX-License-Identifier: GPL-2.0-only > > +// SPDX-FileCopyrightText: 2012 Steffen Trumtrar, Pengutronix > > +// SPDX-FileCopyrightText: 2014 Protonic Holland > > +// SPDX-FileCopyrightText: 2020 Oleksij Rempel, Pengutronix > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > + > > +#define GPIO_HW_REV_ID {\ > > + {IMX_GPIO_NR(2, 8), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id0"}, \ > > + {IMX_GPIO_NR(2, 9), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id1"}, \ > > + {IMX_GPIO_NR(2, 10), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id2"} \ > > +} > > + > > +#define GPIO_HW_TYPE_ID {\ > > + {IMX_GPIO_NR(2, 11), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id0"}, \ > > + {IMX_GPIO_NR(2, 12), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id1"}, \ > > + {IMX_GPIO_NR(2, 13), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id2"}, \ > > + {IMX_GPIO_NR(2, 14), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id3"}, \ > > + {IMX_GPIO_NR(2, 15), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "hw_id4"} \ > > +} > > + > > +enum { > > + HW_TYPE_PRTI6Q = 0, > > + HW_TYPE_PRTWD2 = 1, > > + HW_TYPE_ALTI6S = 2, > > + HW_TYPE_VICUT1 = 4, > > + HW_TYPE_ALTI6P = 6, > > + HW_TYPE_PRTMVT = 8, > > + HW_TYPE_PRTI6G = 10, > > + HW_TYPE_PRTRVT = 12, > > + HW_TYPE_VICUT2 = 16, > > + HW_TYPE_PLYM2M = 20, > > + HW_TYPE_PRTVT7 = 22, > > + HW_TYPE_LANMCU = 23, > > + HW_TYPE_PLYBAS = 24, > > + HW_TYPE_VICTGO = 28, > > +}; > > + > > +enum prt_imx6_kvg_pw_mode { > > + PW_MODE_KVG_WITH_YACO = 0, > > + PW_MODE_KVG_NEW = 1, > > + PW_MODE_KUBOTA = 2, > > +}; > > + > > +/* board specific flags */ > > +#define PRT_IMX6_BOOTCHOOSER BIT(3) > > +#define PRT_IMX6_USB_LONG_DELAY BIT(2) > > +#define PRT_IMX6_BOOTSRC_EMMC BIT(1) > > +#define PRT_IMX6_BOOTSRC_SPI_NOR BIT(0) > > + > > +static struct prt_imx6_priv *prt_priv; > > +struct prt_machine_data { > > + unsigned int hw_id; > > + unsigned int hw_rev; > > + unsigned int i2c_addr; > > + unsigned int i2c_adapter; > > + unsigned int flags; > > + int (*init)(struct prt_imx6_priv *priv); > > +}; > > + > > +struct prt_imx6_priv { > > + struct device_d *dev; > > + const struct prt_machine_data *dcfg; > > + unsigned int hw_id; > > + unsigned int hw_rev; > > + const char *name; > > + struct poller_async poller; > > + unsigned int usb_delay; > > +}; > > + > > +struct prti6q_rfid_contents { > > + u8 mac[6]; > > + char serial[10]; > > + u8 cs; > > +} __attribute__ ((packed)); > > + > > +#define GPIO_DIP1_FB IMX_GPIO_NR(4, 18) > > +#define GPIO_FORCE_ON1 IMX_GPIO_NR(2, 30) > > +#define GPIO_ON1_CTRL IMX_GPIO_NR(4, 21) > > +#define GPIO_ON2_CTRL IMX_GPIO_NR(4, 22) > > + > > +static const struct gpio prt_imx6_kvg_gpios[] = { > > + { > > + .gpio = GPIO_DIP1_FB, > > + .flags = GPIOF_IN, > > + .label = "DIP1_FB", > > + }, > > + { > > + .gpio = GPIO_FORCE_ON1, > > + .flags = GPIOF_OUT_INIT_HIGH, > > + .label = "FORCE_ON1", > > + }, > > + { > > + .gpio = GPIO_ON1_CTRL, > > + .flags = GPIOF_IN, > > + .label = "ON1_CTRL", > > + }, > > + { > > + .gpio = GPIO_ON2_CTRL, > > + .flags = GPIOF_IN, > > + .label = "ON2_CTRL", > > + }, > > +}; > > + > > +static int prt_imx6_read_rfid(struct prt_imx6_priv *priv, void *buf, > > + size_t size) > > +{ > > + const struct prt_machine_data *dcfg = priv->dcfg; > > + struct device_d *dev = priv->dev; > > + struct i2c_client cl; > > + int ret; > > + > > + cl.addr = dcfg->i2c_addr; > > + cl.adapter = i2c_get_adapter(dcfg->i2c_adapter); > > + if (!cl.adapter) { > > + dev_err(dev, "i2c bus not found\n"); > > + return -ENODEV; > > + } > > + > > + /* 0x6000 user storage in the RFID tag */ > > + ret = i2c_read_reg(&cl, 0x6000 | I2C_ADDR_16_BIT, buf, size); > > + if (ret < 0) { > > + dev_err(dev, "Filed to read the RFID: %i\n", ret); > > + return ret; > > + } > > + > > + return 0; > > +} > > + > > +static u8 prt_imx6_calc_rfid_crc(void *buf, size_t size) > > +{ > > This is really a simple checksum, not a form of CRC code, so maybe > prt_imx6_calc_rfid_cs is a better name for the function. done > > + unsigned int cs = 0; > > + u8 *dat = buf; > > + int t; > > + > > + for (t = 0; t < size - 1; t++) { > > + cs += dat[t]; > > + } > > + > > + cs ^= 0xff; > > + > > + return cs & 0xff; > > + > > +} > > + > > +static int prt_imx6_set_mac(struct prt_imx6_priv *priv, > > + struct prti6q_rfid_contents *rfid) > > +{ > > + struct device_d *dev = priv->dev; > > + struct device_node *node; > > + > > + node = of_find_node_by_alias(of_get_root_node(), "ethernet0"); > > + if (!node) { > > + dev_err(dev, "Cannot find FEC!\n"); > > + return -ENODEV; > > + } > > + > > + if (!is_valid_ether_addr(&rfid->mac[0])) { > > + dev_err(dev, "bad MAC addr\n"); > > + return -EILSEQ; > > + } > > + > > + of_eth_register_ethaddr(node, &rfid->mac[0]); > > + > > + return 0; > > +} > > + > > +static int prt_of_fixup_serial(struct device_node *dstroot, void *arg) > > +{ > > + struct device_node *srcroot = arg; > > + const char *ser; > > + int len; > > + > > + ser = of_get_property(srcroot, "serial-number", &len); > > + return of_set_property(dstroot, "serial-number", ser, len, 1); > > +} > > + > > +static void prt_oftree_fixup_serial(const char *serial) > > +{ > > + struct device_node *root = of_get_root_node(); > > + > > + of_set_property(root, "serial-number", serial, strlen(serial) + 1, 1); > > + of_register_fixup(prt_of_fixup_serial, root); > > +} > > + > > +static int prt_imx6_set_serial(struct prt_imx6_priv *priv, > > + struct prti6q_rfid_contents *rfid) > > +{ > > + rfid->serial[9] = 0; /* Failsafe */ > > + dev_info(priv->dev, "Serial number: %s\n", rfid->serial); > > + prt_oftree_fixup_serial(rfid->serial); > > + > > + return 0; > > +} > > + > > +static int prt_imx6_read_i2c_mac_serial(struct prt_imx6_priv *priv) > > +{ > > + struct device_d *dev = priv->dev; > > + struct prti6q_rfid_contents rfid; > > + int ret; > > + > > + ret = prt_imx6_read_rfid(priv, &rfid, sizeof(rfid)); > > + if (ret) > > + return ret; > > + > > + if (rfid.cs != prt_imx6_calc_rfid_crc(&rfid, sizeof(rfid))) { > > + dev_err(dev, "RFID: bad checksum!\n"); > > + return -EBADMSG; > > + } > > + > > + ret = prt_imx6_set_mac(priv, &rfid); > > + if (ret) > > + return ret; > > + > > + ret = prt_imx6_set_serial(priv, &rfid); > > + if (ret) > > + return ret; > > + > > + return 0; > > +} > > + > > +#define OTG_PORTSC1 (MX6_OTG_BASE_ADDR+0x184) > > + > > +static void prt_imx6_check_usb_boot(void *data) > > +{ > > + struct prt_imx6_priv *priv = data; > > + struct device_d *dev = priv->dev; > > + char *second_word, *bootsrc; > > + unsigned int v; > > + ssize_t size; > > + char buf[16]; > > + int fd, ret; > > + > > + v = *((unsigned int *)OTG_PORTSC1); > > + if ((v & 0x0c00) == 0) /* LS == SE0 ==> nothing connected */ > > + return; > > + > > + usb_rescan(); > > + > > + ret = mkdir("/usb", 0); > > + if (ret) { > > + dev_err(dev, "Cannot mkdir /usb\n"); > > + goto exit_usb_boot; > > + } > > + > > + ret = mount("/dev/disk0.0", NULL, "usb", NULL); > > + if (ret) { > > + dev_warn(dev, "Filed to mount USB Disk partition with error (%i), trying bare device\n", ret); > > + > > + ret = mount("/dev/disk0", NULL, "usb", NULL); > > + if (ret) { > > + dev_err(dev, "USB mount failed!\n"); > > + goto exit_usb_boot; > > + } > > + } > > + > > + fd = open("/usb/boot_target", O_RDONLY); > > + if (fd < 0) { > > + dev_err(dev, "Can't open /usb/boot_target file\n"); > > + ret = fd; > > + goto exit_usb_boot; > > + } > > + > > + size = read(fd, buf, sizeof(buf)); > > + close(fd); > > + if (size < 0) { > > + ret = size; > > + goto exit_usb_boot; > > + } > > + > > + /* length of "vicut1 usb", the shortest possible target */ > > + if (size < sizeof("vicut1 usb")) { > > + dev_err(dev, "Invalid boot target file!\n"); > > + ret = -EINVAL; > > + goto exit_usb_boot; > > + } > > + > > + if (strncmp(buf, priv->name, 6) && strncmp(buf, "prti6qp ", 8)) { > > + dev_err(dev, "Boot target for a different board! (%s %s)\n", > > + buf, priv->name); > > + ret = -EINVAL; > > + goto exit_usb_boot; > > + } > > + > > + second_word = strchr(buf, 32); > > + second_word++; > > + > > + if (strncmp(second_word, "usb", 3) == 0) { > > + bootsrc = "disk0.0"; > > Does this work if the USB stick does not have a partition table? good point! fixed. > > + } else if (strncmp(second_word, "recovery", 8) == 0) { > > + bootsrc = "recovery"; > > + } else { > > + dev_err(dev, "Unknown boot target!\n"); > > + ret = -ENODEV; > > + goto exit_usb_boot; > > + } > > + > > + ret = setenv("global.boot.default", bootsrc); > > + if (ret) > > + goto exit_usb_boot; > > + > > + return; > > + > > +exit_usb_boot: > > + dev_err(dev, "Failed to run usb boot: %i\n", ret); > > + > > + return; > > +} > > + > > +static int prt_imx6_env_init(struct prt_imx6_priv *priv) > > +{ > > + const struct prt_machine_data *dcfg = priv->dcfg; > > + struct device_d *dev = priv->dev; > > + char *delay, *bootsrc; > > + int ret; > > + > > + ret = setenv("global.linux.bootargs.base", "consoleblank=0 vt.color=0x00"); > > + if (ret) > > + goto exit_env_init; > > + > > + if (dcfg->flags & PRT_IMX6_USB_LONG_DELAY) > > + priv->usb_delay = 4; > > + else > > + priv->usb_delay = 1; > > + > > + /* the usb_delay value is used for poller_call_async() */ > > + delay = basprintf("%d", priv->usb_delay); > > + ret = setenv("global.autoboot_timeout", delay); > > + if (ret) > > + goto exit_env_init; > > + > > + if (dcfg->flags & PRT_IMX6_BOOTCHOOSER) > > + bootsrc = "bootchooser"; > > + else > > + bootsrc = "mmc2"; > > + > > + ret = setenv("global.boot.default", bootsrc); > > + if (ret) > > + goto exit_env_init; > > + > > + dev_info(dev, "Board specific env init is done\n"); > > + return 0; > > + > > +exit_env_init: > > + dev_err(dev, "Failed to set env: %i\n", ret); > > + > > + return ret; > > +} > > + > > +static int prt_imx6_bbu(struct prt_imx6_priv *priv) > > +{ > > + const struct prt_machine_data *dcfg = priv->dcfg; > > + u32 emmc_flags = 0; > > + int ret; > > + > > + if (dcfg->flags & PRT_IMX6_BOOTSRC_SPI_NOR) { > > + ret = imx6_bbu_internal_spi_i2c_register_handler("SPI", "/dev/m25p0.barebox", > > + BBU_HANDLER_FLAG_DEFAULT); > > + if (ret) > > + goto exit_bbu; > > + } else { > > + emmc_flags = BBU_HANDLER_FLAG_DEFAULT; > > + } > > + > > + ret = imx6_bbu_internal_mmcboot_register_handler("eMMC", "/dev/mmc2", > > + emmc_flags); > > + if (ret) > > + goto exit_bbu; > > + > > + ret = imx6_bbu_internal_mmc_register_handler("SD", "/dev/mmc0", 0); > > + if (ret) > > + goto exit_bbu; > > + > > + return 0; > > +exit_bbu: > > + dev_err(priv->dev, "Failed to register bbu: %i\n", ret); > > + return ret; > > +} > > + > > +static int prt_imx6_devices_init(void) > > +{ > > + struct prt_imx6_priv *priv = prt_priv; > > + int ret; > > + > > + if (!priv) > > + return 0; > > + > > + if (priv->dcfg->init) { > > + ret = priv->dcfg->init(priv); > > + if (ret) > > + return ret; > > + } > > + > > + ret = prt_imx6_bbu(priv); > > + if (ret) > > + return ret; > > + > > + ret = prt_imx6_read_i2c_mac_serial(priv); > > + if (ret) > > + return ret; > > Why are we bailing out here if the I2C contents are not (yet) correct? fixed. in this case it would make sense to ignore error for most of prt_imx6_devices_init() callees. > > + > > + ret = prt_imx6_env_init(priv); > > + if (ret) > > + return ret; > > + > > + ret = poller_async_register(&priv->poller, "usb-boot"); > > + if (ret) { > > + dev_err(priv->dev, "can't setup poller\n"); > > + return ret; > > + } > > + > > + poller_call_async(&priv->poller, priv->usb_delay * SECOND, > > + &prt_imx6_check_usb_boot, priv); > > + > > + return 0; > > +} > > +late_initcall(prt_imx6_devices_init); > > + > > +static int prt_imx6_init_kvg_set_ctrl(struct prt_imx6_priv *priv, bool val) > > +{ > > + int ret; > > + > > + ret = gpio_direction_output(GPIO_ON1_CTRL, val); > > + if (ret) > > + return ret; > > + > > + ret = gpio_direction_output(GPIO_ON2_CTRL, val); > > + if (ret) > > + return ret; > > + > > + return 0; > > +} > > + > > +static int prt_imx6_yaco_set_kvg_power_mode(struct prt_imx6_priv *priv, > > + char *serial) > > +{ > > + static const char command[] = "{\"command\":\"mode\",\"value\":\"kvg\",\"on2\":true}"; > > + struct device_d *dev = priv->dev; > > + struct console_device *yccon; > > + int ret; > > + > > + yccon = of_console_get_by_alias(serial); > > + if (!yccon) { > > + dev_dbg(dev, "Cant find the %s node, try later\n", serial); > > + return -EPROBE_DEFER; > > + } > > + > > + ret = console_set_baudrate(yccon, 115200); > > + if (ret) > > + goto exit_yaco_set_kvg_power_mode; > > + > > + yccon->puts(yccon, command, sizeof(command)); > > + > > + dev_info(dev, "Send YaCO power init sequence to the %s\n", serial); > > I think the word "the" here is not necessary. removed. > > + return 0; > > + > > +exit_yaco_set_kvg_power_mode: > > + dev_err(dev, "Failed to set YaCO pw mode: %i", ret); > > + > > + return ret; > > +} > > + > > +static int prt_imx6_init_kvg_power(struct prt_imx6_priv *priv, > > + enum prt_imx6_kvg_pw_mode pw_mode) > > +{ > > + const char *mode; > > + int ret; > > + > > + ret = gpio_request_array(prt_imx6_kvg_gpios, > > + ARRAY_SIZE(prt_imx6_kvg_gpios)); > > + if (ret) > > + goto exit_init_kvg_vicut; > > + > > + mdelay(1); > > + > > + if (!gpio_get_value(GPIO_DIP1_FB)) > > + pw_mode = PW_MODE_KUBOTA; > > + > > + switch (pw_mode) { > > + case PW_MODE_KVG_WITH_YACO: > > + mode = "KVG (with YaCO)"; > > + > > + /* GPIO_ON1_CTRL and GPIO_ON2_CTRL are N.C. on the SoC for > > + * older revisions */ > > + > > + /* Inform YaCO of power mode */ > > + ret = prt_imx6_yaco_set_kvg_power_mode(priv, "serial0"); > > + break; > > + case PW_MODE_KVG_NEW: > > + mode = "KVG (new)"; > > + > > + ret = prt_imx6_init_kvg_set_ctrl(priv, true); > > + if (ret) > > + goto exit_init_kvg_vicut; > > + break; > > + case PW_MODE_KUBOTA: > > + mode = "Kubota"; > > + ret = prt_imx6_init_kvg_set_ctrl(priv, false); > > + if (ret) > > + goto exit_init_kvg_vicut; > > + break; > > + default: > > + ret = -ENODEV; > > + goto exit_init_kvg_vicut; > > + } > > + > > + dev_info(priv->dev, "Power mode: %s\n", mode); > > + > > + return 0; > > + > > +exit_init_kvg_vicut: > > + dev_err(priv->dev, "KvG power init failed: %i\n", ret); > > + > > + return ret; > > +} > > + > > +static int prt_imx6_init_victgo(struct prt_imx6_priv *priv) > > +{ > > + int ret = 0; > > + > > + /* Bit 1 of HW-REV is pulled low by 2k2, but must be high on some > > + * revisions > > + */ > > + if (priv->hw_rev & 2) { > > + ret = gpio_direction_output(IMX_GPIO_NR(2, 9), 1); > > + if (ret) { > > + dev_err(priv->dev, "Failed to set gpio up\n"); > > + return ret; > > + } > > + } > > + > > + return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_NEW); > > +} > > + > > +static int prt_imx6_init_kvg_new(struct prt_imx6_priv *priv) > > +{ > > + return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_NEW); > > +} > > + > > +static int prt_imx6_init_kvg_yaco(struct prt_imx6_priv *priv) > > +{ > > + return prt_imx6_init_kvg_power(priv, PW_MODE_KVG_WITH_YACO); > > +} > > + > > +static int prt_imx6_rfid_fixup(struct prt_imx6_priv *priv, > > + struct device_node *root) > > +{ > > + const struct prt_machine_data *dcfg = priv->dcfg; > > + struct device_node *node, *i2c_node; > > + char *eeprom_node_name, *alias; > > + int na, ns, len = 0; > > + int ret; > > + u8 *tmp; > > + > > + alias = basprintf("i2c%d", dcfg->i2c_adapter); > > + if (!alias) { > > + ret = -ENOMEM; > > + goto exit_error; > > + } > > + > > + i2c_node = of_find_node_by_alias(root, alias); > > + if (!i2c_node) { > > + dev_err(priv->dev, "Unsupported i2c adapter\n"); > > + ret = -ENODEV; > > + goto free_alias; > > + } > > + > > + eeprom_node_name = basprintf("/eeprom@%x", dcfg->i2c_addr); > > + if (!eeprom_node_name) { > > + ret = -ENOMEM; > > + goto free_alias; > > + } > > + > > + node = of_create_node(i2c_node, eeprom_node_name); > > + if (!node) { > > + dev_err(priv->dev, "Failed to create node %s\n", > > + eeprom_node_name); > > + ret = -ENOMEM; > > + goto free_eeprom; > > + } > > + > > + ret = of_property_write_string(node, "compatible", "atmel,24c256"); > > + if (ret) > > + goto free_eeprom; > > + > > + na = of_n_addr_cells(node); > > + ns = of_n_size_cells(node); > > + tmp = xzalloc((na + ns) * 4); > > + > > + of_write_number(tmp + len, dcfg->i2c_addr, na); > > + len += na * 4; > > + of_write_number(tmp + len, 0, ns); > > + len += ns * 4; > > + > > + ret = of_set_property(node, "reg", tmp, len, 1); > > + kfree(tmp); > > + if (ret) > > + goto free_eeprom; > > + > > + return 0; > > +free_eeprom: > > + kfree(eeprom_node_name); > > +free_alias: > > + kfree(alias); > > +exit_error: > > + dev_err(priv->dev, "Failed to apply fixup: %i\n", ret); > > + return ret; > > +} > > + > > +static int prt_imx6_of_fixup(struct device_node *root, void *data) > > +{ > > + struct prt_imx6_priv *priv = data; > > + int ret; > > + > > + if (!root) { > > + dev_err(priv->dev, "Unable to find the root node\n"); > > + return -ENODEV; > > + } > > + > > + ret = prt_imx6_rfid_fixup(priv, root); > > + if (ret) > > + goto exit_of_fixups; > > + > > + return 0; > > +exit_of_fixups: > > + dev_err(priv->dev, "Failed to apply OF fixups: %i\n", ret); > > + return ret; > > +} > > + > > +static int prt_imx6_get_id(struct prt_imx6_priv *priv) > > +{ > > + struct gpio gpios_type[] = GPIO_HW_TYPE_ID; > > + struct gpio gpios_rev[] = GPIO_HW_REV_ID; > > + int ret; > > + > > + ret = gpio_array_to_id(gpios_type, ARRAY_SIZE(gpios_type), &priv->hw_id); > > + if (ret) > > + goto exit_get_id; > > + > > + ret = gpio_array_to_id(gpios_rev, ARRAY_SIZE(gpios_rev), &priv->hw_rev); > > + if (ret) > > + goto exit_get_id; > > + > > + return 0; > > +exit_get_id: > > + dev_err(priv->dev, "Failed to read gpio ID: %i\n", ret); > > + return ret; > > +} > > + > > +static int prt_imx6_get_dcfg(struct prt_imx6_priv *priv) > > +{ > > + const struct prt_machine_data *dcfg, *found = NULL; > > + int ret; > > + > > + dcfg = of_device_get_match_data(priv->dev); > > + if (!dcfg) { > > + ret = -EINVAL; > > + goto exit_get_dcfg; > > + } > > + > > + for (; dcfg->hw_id != UINT_MAX; dcfg++) { > > + if (dcfg->hw_id != priv->hw_id) > > + continue; > > + if (dcfg->hw_rev > priv->hw_rev) > > + break; > > + found = dcfg; > > + } > > + > > + if (!found) { > > + ret = -ENODEV; > > + goto exit_get_dcfg; > > + } > > + > > + priv->dcfg = found; > > + > > + return 0; > > +exit_get_dcfg: > > + dev_err(priv->dev, "Failed to get dcfg: %i\n", ret); > > + return ret; > > +} > > + > > +static int prt_imx6_probe(struct device_d *dev) > > +{ > > + struct prt_imx6_priv *priv; > > + const char *name, *ptr; > > + struct param_d *p; > > + int ret; > > + > > + priv = kzalloc(sizeof(*priv), GFP_KERNEL); > > + if (!priv) > > + return -ENOMEM; > > + > > + priv->dev = dev; > > + name = of_device_get_match_compatible(priv->dev); > > + ptr = strchr(name, ','); > > + priv->name = ptr ? ptr + 1 : name; > > + > > + pr_info("Detected machine type: %s\n", priv->name); > > + > > + ret = prt_imx6_get_id(priv); > > + if (ret) > > + goto free_priv; > > + > > + pr_info(" HW type: %d\n", priv->hw_id); > > + pr_info(" HW revision: %d\n", priv->hw_rev); > > + > > + ret = prt_imx6_get_dcfg(priv); > > + if (ret) > > + goto free_priv; > > + > > + p = dev_add_param_uint32_ro(dev, "boardrev", &priv->hw_rev, "%u"); > > + if (IS_ERR(p)) { > > + ret = PTR_ERR(p); > > + goto free_priv; > > + } > > + > > + p = dev_add_param_uint32_ro(dev, "boardid", &priv->hw_id, "%u"); > > + if (IS_ERR(p)) { > > + ret = PTR_ERR(p); > > + goto free_priv; > > + } > > + > > + ret = prt_imx6_of_fixup(of_get_root_node(), priv); > > + if (ret) > > + goto free_priv; > > + > > + ret = of_register_fixup(prt_imx6_of_fixup, priv); > > + if (ret) { > > + dev_err(dev, "Failed to register fixup\n"); > > + goto free_priv; > > + } > > + > > + prt_priv = priv; > > + > > + return 0; > > +free_priv: > > + kfree(priv); > > + return ret; > > +} > > + > > +static const struct prt_machine_data prt_imx6_cfg_alti6p[] = { > > + { > > + .hw_id = HW_TYPE_ALTI6P, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_EMMC, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_victgo[] = { > > + { > > + .hw_id = HW_TYPE_VICTGO, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .init = prt_imx6_init_victgo, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_vicut1[] = { > > + { > > + .hw_id = HW_TYPE_VICUT1, > > + .hw_rev = 0, > > + .i2c_addr = 0x50, > > + .i2c_adapter = 1, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = HW_TYPE_VICUT1, > > + .hw_rev = 1, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .init = prt_imx6_init_kvg_yaco, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = HW_TYPE_VICUT2, > > + .hw_rev = 1, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .init = prt_imx6_init_kvg_new, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_vicut1q[] = { > > + { > > + .hw_id = HW_TYPE_VICUT1, > > + .hw_rev = 0, > > + .i2c_addr = 0x50, > > + .i2c_adapter = 1, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = HW_TYPE_VICUT1, > > + .hw_rev = 1, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .init = prt_imx6_init_kvg_yaco, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = HW_TYPE_VICUT2, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .init = prt_imx6_init_kvg_yaco, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = HW_TYPE_VICUT2, > > + .hw_rev = 1, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .init = prt_imx6_init_kvg_new, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_vicutp[] = { > > + { > > + .hw_id = HW_TYPE_VICUT2, > > + .hw_rev = 1, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .init = prt_imx6_init_kvg_new, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_lanmcu[] = { > > + { > > + .hw_id = HW_TYPE_LANMCU, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_EMMC | PRT_IMX6_BOOTCHOOSER, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_plybas[] = { > > + { > > + .hw_id = HW_TYPE_PLYBAS, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR | PRT_IMX6_USB_LONG_DELAY, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_plym2m[] = { > > + { > > + .hw_id = HW_TYPE_PLYM2M, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR | PRT_IMX6_USB_LONG_DELAY, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_prti6g[] = { > > + { > > + .hw_id = HW_TYPE_PRTI6G, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_EMMC, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_prti6q[] = { > > + { > > + .hw_id = HW_TYPE_PRTI6Q, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 2, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = HW_TYPE_PRTI6Q, > > + .hw_rev = 1, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_prtmvt[] = { > > + { > > + .hw_id = HW_TYPE_PRTMVT, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_prtrvt[] = { > > + { > > + .hw_id = HW_TYPE_PRTRVT, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_SPI_NOR, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_prtvt7[] = { > > + { > > + .hw_id = HW_TYPE_PRTVT7, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_EMMC | PRT_IMX6_BOOTCHOOSER, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_prtwd2[] = { > > + { > > + .hw_id = HW_TYPE_PRTWD2, > > + .hw_rev = 0, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_EMMC, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct prt_machine_data prt_imx6_cfg_prtwd3[] = { > > + { > > + .hw_id = HW_TYPE_PRTWD2, > > + .hw_rev = 2, > > + .i2c_addr = 0x51, > > + .i2c_adapter = 0, > > + .flags = PRT_IMX6_BOOTSRC_EMMC, > > + }, { > > + .hw_id = UINT_MAX > > + }, > > +}; > > + > > +static const struct of_device_id prt_imx6_of_match[] = { > > + { .compatible = "alt,alti6p", .data = &prt_imx6_cfg_alti6p }, > > + { .compatible = "kvg,victgo", .data = &prt_imx6_cfg_victgo }, > > + { .compatible = "kvg,vicut1", .data = &prt_imx6_cfg_vicut1 }, > > + { .compatible = "kvg,vicut1q", .data = &prt_imx6_cfg_vicut1q }, > > + { .compatible = "kvg,vicutp", .data = &prt_imx6_cfg_vicutp }, > > + { .compatible = "lan,lanmcu", .data = &prt_imx6_cfg_lanmcu }, > > + { .compatible = "ply,plybas", .data = &prt_imx6_cfg_plybas }, > > + { .compatible = "ply,plym2m", .data = &prt_imx6_cfg_plym2m }, > > + { .compatible = "prt,prti6g", .data = &prt_imx6_cfg_prti6g }, > > + { .compatible = "prt,prti6q", .data = &prt_imx6_cfg_prti6q }, > > + { .compatible = "prt,prtmvt", .data = &prt_imx6_cfg_prtmvt }, > > + { .compatible = "prt,prtrvt", .data = &prt_imx6_cfg_prtrvt }, > > + { .compatible = "prt,prtvt7", .data = &prt_imx6_cfg_prtvt7 }, > > + { .compatible = "prt,prtwd2", .data = &prt_imx6_cfg_prtwd2 }, > > + { .compatible = "prt,prtwd3", .data = &prt_imx6_cfg_prtwd3 }, > > + { /* sentinel */ }, > > +}; > > + > > +static struct driver_d prt_imx6_board_driver = { > > + .name = "board-protonic-imx6", > > + .probe = prt_imx6_probe, > > + .of_compatible = DRV_OF_COMPAT(prt_imx6_of_match), > > +}; > > +postcore_platform_driver(prt_imx6_board_driver); Best regards, Oleksij -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox