summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/boards/protonic-imx6/Makefile1
-rw-r--r--arch/arm/boards/protonic-imx6/board.c1034
-rw-r--r--arch/arm/dts/imx6dl-lanmcu.dts50
-rw-r--r--arch/arm/dts/imx6dl-plym2m.dts51
-rw-r--r--arch/arm/dts/imx6dl-prtrvt.dts1
-rw-r--r--arch/arm/dts/imx6q-prti6q.dts24
-rw-r--r--arch/arm/dts/imx6qdl-prti6q-nor.dtsi10
-rw-r--r--arch/arm/dts/imx6qdl-prti6q.dtsi31
-rw-r--r--arch/arm/dts/imx6qdl-vicut1.dtsi26
-rw-r--r--common/console_common.c18
-rw-r--r--drivers/gpio/gpiolib.c31
-rw-r--r--drivers/of/base.c17
-rw-r--r--drivers/of/device.c12
-rw-r--r--include/console.h1
-rw-r--r--include/gpio.h5
-rw-r--r--include/of_device.h6
16 files changed, 1282 insertions, 36 deletions
diff --git a/arch/arm/boards/protonic-imx6/Makefile b/arch/arm/boards/protonic-imx6/Makefile
index b08c4a9..01c7a25 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 0000000..daae9a5
--- /dev/null
+++ b/arch/arm/boards/protonic-imx6/board.c
@@ -0,0 +1,1034 @@
+// 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 <bbu.h>
+#include <common.h>
+#include <environment.h>
+#include <fcntl.h>
+#include <gpio.h>
+#include <i2c/i2c.h>
+#include <mach/bbu.h>
+#include <mach/imx6.h>
+#include <net.h>
+#include <of_device.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <usb/usb.h>
+
+#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, "Failed to read the RFID: %i\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static u8 prt_imx6_calc_rfid_cs(void *buf, size_t size)
+{
+ 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])) {
+ unsigned char ethaddr_str[sizeof("xx:xx:xx:xx:xx:xx")];
+
+ ethaddr_to_string(&rfid->mac[0], ethaddr_str);
+ dev_err(dev, "bad MAC addr: %s\n", ethaddr_str);
+
+ 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_cs(&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;
+}
+
+static int prt_imx6_usb_mount(struct prt_imx6_priv *priv, char **usbdisk)
+{
+ struct device_d *dev = priv->dev;
+ const char *path;
+ struct stat s;
+ int ret;
+
+ ret = mkdir("/usb", 0);
+ if (ret) {
+ dev_err(dev, "Cannot mkdir /usb\n");
+ return ret;
+ }
+
+ path = "/dev/disk0.0";
+ ret = stat(path, &s);
+ if (!ret) {
+ ret = mount(path, NULL, "usb", NULL);
+ if (ret)
+ goto exit_usb_mount;
+
+ *usbdisk = strdup("disk0.0");
+ return 0;
+ }
+
+ path = "/dev/disk0";
+ ret = stat(path, &s);
+ if (!ret) {
+ ret = mount(path, NULL, "usb", NULL);
+ if (ret)
+ goto exit_usb_mount;
+
+ *usbdisk = strdup("disk0");
+ return 0;
+ }
+
+exit_usb_mount:
+ dev_err(dev, "Failed to mount %s with error (%i)\n", path, ret);
+ return ret;
+}
+
+#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, *usbdisk;
+ char buf[sizeof("vicut1q recovery")] = {};
+ unsigned int v;
+ ssize_t size;
+ int fd, ret;
+
+ v = readl(OTG_PORTSC1);
+ if ((v & 0x0c00) == 0) /* LS == SE0 ==> nothing connected */
+ return;
+
+ usb_rescan();
+
+ ret = prt_imx6_usb_mount(priv, &usbdisk);
+ if (ret)
+ return;
+
+ fd = open("/usb/boot_target", O_RDONLY);
+ if (fd < 0) {
+ dev_warn(dev, "Can't open /usb/boot_target file, continue with normal boot\n");
+ ret = fd;
+ goto exit_usb_boot;
+ }
+
+ size = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (size < 0) {
+ ret = size;
+ goto exit_usb_boot;
+ }
+
+ /* Length of "vicut1 usb", the shortest possible target. */
+ if (size < strlen("vicut1 usb")) {
+ dev_err(dev, "Invalid boot target file!\n");
+ ret = -EINVAL;
+ goto exit_usb_boot;
+ }
+
+ second_word = strchr(buf, ' ');
+ if (!second_word) {
+ dev_err(dev, "Cant find boot target in the boot target file!\n");
+ ret = -ENODEV;
+ goto exit_usb_boot;
+ }
+
+ *second_word = 0;
+
+ if (strcmp(buf, priv->name)) {
+ dev_err(dev, "Boot target for a different board! (got: %s expected: %s)\n",
+ buf, priv->name);
+ ret = -EINVAL;
+ goto exit_usb_boot;
+ }
+
+ second_word++;
+ if (strncmp(second_word, "usb", 3) == 0) {
+ bootsrc = usbdisk;
+ } else if (strncmp(second_word, "recovery", 8) == 0) {
+ bootsrc = "recovery";
+ } else {
+ dev_err(dev, "Unknown boot target!\n");
+ ret = -ENODEV;
+ goto exit_usb_boot;
+ }
+
+ dev_info(dev, "detected valid usb boot target file, overwriting boot to: %s\n", bootsrc);
+ ret = setenv("global.boot.default", bootsrc);
+ if (ret)
+ goto exit_usb_boot;
+
+ free(usbdisk);
+ return;
+
+exit_usb_boot:
+ dev_err(dev, "Failed to run usb boot: %s\n", strerror(-ret));
+ free(usbdisk);
+
+ 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)
+ priv->dcfg->init(priv);
+
+ prt_imx6_bbu(priv);
+
+ prt_imx6_read_i2c_mac_serial(priv);
+
+ prt_imx6_env_init(priv);
+
+ 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,
+ const 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 %s\n", serial);
+ 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");
+ dump_stack();
+ 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 = xzalloc(sizeof(*priv));
+ 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);
diff --git a/arch/arm/dts/imx6dl-lanmcu.dts b/arch/arm/dts/imx6dl-lanmcu.dts
index 9f69d67..d50e6af 100644
--- a/arch/arm/dts/imx6dl-lanmcu.dts
+++ b/arch/arm/dts/imx6dl-lanmcu.dts
@@ -13,6 +13,11 @@
chosen {
stdout-path = &uart4;
+
+ environment-emmc {
+ compatible = "barebox,environment";
+ device-path = &usdhc3, "partname:barebox-environment";
+ };
};
memory {
@@ -92,6 +97,12 @@
linux,default-trigger = "heartbeat";
};
};
+
+ clk50m_phy: phy_clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
};
&iomuxc {
@@ -190,7 +201,7 @@
fsl,pins = <
MX6QDL_PAD_EIM_D26__UART2_RX_DATA 0x1b0b1
MX6QDL_PAD_EIM_D27__UART2_TX_DATA 0x1b0b1
- MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x130b1
+ MX6QDL_PAD_EIM_D28__UART2_CTS_B 0x130b1
>;
};
@@ -198,7 +209,7 @@
fsl,pins = <
MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
MX6QDL_PAD_EIM_D25__UART3_RX_DATA 0x1b0b1
- MX6QDL_PAD_EIM_D30__GPIO3_IO30 0x130b1
+ MX6QDL_PAD_EIM_D30__UART3_CTS_B 0x130b1
>;
};
@@ -297,18 +308,32 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
phy-mode = "rmii";
- phy-reset-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>;
clocks = <&clks IMX6QDL_CLK_ENET>,
- <&clks IMX6QDL_CLK_ENET>;
- clock-names = "ipg", "ahb";
+ <&clks IMX6QDL_CLK_ENET>,
+ <&clk50m_phy>;
+ clock-names = "ipg", "ahb", "ptp";
status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* Microchip KSZ8081RNA PHY */
+ rgmii_phy: ethernet-phy@0 {
+ reg = <0>;
+ interrupts-extended = <&gpio5 23 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>;
+ reset-assert-us = <10000>;
+ reset-deassert-us = <300>;
+ };
+ };
};
&uart2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart2>;
linux,rs485-enabled-at-boot-time;
- rts-gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>;
+ uart-has-rtscts;
status = "okay";
};
@@ -316,7 +341,7 @@
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_uart3>;
linux,rs485-enabled-at-boot-time;
- rts-gpios = <&gpio3 30 GPIO_ACTIVE_HIGH>;
+ uart-has-rtscts;
status = "okay";
};
@@ -414,9 +439,14 @@
#size-cells = <1>;
#address-cells = <1>;
- bootstate_backend: bootstate_backend@f0000 {
- reg = <0xf0000 0x10000>;
- label = "bootstate";
+ partition@100000 {
+ label = "barebox-environment";
+ reg = <0x100000 0x100000>;
+ };
+
+ partition@200000 {
+ label = "state";
+ reg = <0x200000 0x100000>;
};
};
};
diff --git a/arch/arm/dts/imx6dl-plym2m.dts b/arch/arm/dts/imx6dl-plym2m.dts
index b66321f..e944a14 100644
--- a/arch/arm/dts/imx6dl-plym2m.dts
+++ b/arch/arm/dts/imx6dl-plym2m.dts
@@ -6,6 +6,7 @@
/dts-v1/;
#include <arm/imx6dl.dtsi>
#include "imx6qdl-prti6q.dtsi"
+#include "imx6qdl-prti6q-nor.dtsi"
/ {
model = "Plymovent M2M board";
@@ -26,18 +27,52 @@
linux,default-trigger = "heartbeat";
};
};
+
+ clk50m_phy: phy_clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
};
+&ecspi1 {
+ cs-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ status = "okay";
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+};
&fec {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet>;
phy-mode = "rmii";
- phy-reset-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>;
clocks = <&clks IMX6QDL_CLK_ENET>,
- <&clks IMX6QDL_CLK_ENET>;
- clock-names = "ipg", "ahb";
+ <&clks IMX6QDL_CLK_ENET>,
+ <&clk50m_phy>;
+ clock-names = "ipg", "ahb", "ptp";
status = "okay";
+
+ mdio {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* Microchip KSZ8081RNA PHY */
+ rgmii_phy: ethernet-phy@0 {
+ reg = <0>;
+ interrupts-extended = <&gpio5 23 IRQ_TYPE_LEVEL_LOW>;
+ reset-gpios = <&gpio5 22 GPIO_ACTIVE_LOW>;
+ reset-assert-us = <10000>;
+ reset-deassert-us = <300>;
+ };
+ };
};
&iomuxc {
@@ -58,6 +93,16 @@
>;
};
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1
+ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1
+ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1
+ /* CS */
+ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1
+ >;
+ };
+
pinctrl_usbotg: usbotggrp {
fsl,pins = <
MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x1b0b0
diff --git a/arch/arm/dts/imx6dl-prtrvt.dts b/arch/arm/dts/imx6dl-prtrvt.dts
index 802bd50..c403ba3 100644
--- a/arch/arm/dts/imx6dl-prtrvt.dts
+++ b/arch/arm/dts/imx6dl-prtrvt.dts
@@ -6,6 +6,7 @@
/dts-v1/;
#include <arm/imx6dl.dtsi>
#include "imx6qdl-prti6q.dtsi"
+#include "imx6qdl-prti6q-nor.dtsi"
#include <dt-bindings/leds/common.h>
/ {
diff --git a/arch/arm/dts/imx6q-prti6q.dts b/arch/arm/dts/imx6q-prti6q.dts
index 89a23ef..acdb7b2 100644
--- a/arch/arm/dts/imx6q-prti6q.dts
+++ b/arch/arm/dts/imx6q-prti6q.dts
@@ -6,6 +6,7 @@
/dts-v1/;
#include <arm/imx6q.dtsi>
#include "imx6qdl-prti6q.dtsi"
+#include "imx6qdl-prti6q-nor.dtsi"
#include <dt-bindings/leds/common.h>
#include <dt-bindings/sound/fsl-imx-audmux.h>
@@ -13,13 +14,6 @@
model = "Protonic PRTI6Q board";
compatible = "prt,prti6q", "fsl,imx6q";
- chosen {
- environment {
- compatible = "barebox,environment";
- device-path = &ecspi1, "partname:env";
- };
- };
-
memory@10000000 {
device_type = "memory";
reg = <0x10000000 0xf0000000>;
@@ -161,24 +155,8 @@
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <20000000>;
-
#address-cells = <1>;
#size-cells = <1>;
-
- partition@0 {
- label = "boot";
- reg = <0x0 0x100000>;
- };
-
- partition@100000 {
- label = "env";
- reg = <0x100000 0x10000>;
- };
-
- partition@110000 {
- label = "spare";
- reg = <0x110000 0x2f0000>;
- };
};
};
diff --git a/arch/arm/dts/imx6qdl-prti6q-nor.dtsi b/arch/arm/dts/imx6qdl-prti6q-nor.dtsi
new file mode 100644
index 0000000..ad718ce
--- /dev/null
+++ b/arch/arm/dts/imx6qdl-prti6q-nor.dtsi
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+&ecspi1 {
+ flash@0 {
+ partition@0 {
+ label = "barebox";
+ reg = <0x0 0x100000>;
+ };
+ };
+};
diff --git a/arch/arm/dts/imx6qdl-prti6q.dtsi b/arch/arm/dts/imx6qdl-prti6q.dtsi
index ed526d1..f2b3655 100644
--- a/arch/arm/dts/imx6qdl-prti6q.dtsi
+++ b/arch/arm/dts/imx6qdl-prti6q.dtsi
@@ -9,6 +9,22 @@
/ {
chosen {
stdout-path = &uart4;
+
+ environment-emmc {
+ compatible = "barebox,environment";
+ device-path = &usdhc3, "partname:barebox-environment";
+ };
+ };
+
+ reserved-memory {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ /* Address will be determined by the bootloader */
+ ramoops {
+ compatible = "ramoops";
+ };
};
reg_1v8: regulator-1v8 {
@@ -105,7 +121,22 @@
pinctrl-0 = <&pinctrl_usdhc3>;
bus-width = <8>;
non-removable;
+ no-sdio;
+ no-sd;
status = "okay";
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@100000 {
+ label = "barebox-environment";
+ reg = <0x100000 0x100000>;
+ };
+
+ partition@200000 {
+ label = "state";
+ reg = <0x200000 0x100000>;
+ };
};
&iomuxc {
diff --git a/arch/arm/dts/imx6qdl-vicut1.dtsi b/arch/arm/dts/imx6qdl-vicut1.dtsi
index dc18614..dbfcf25 100644
--- a/arch/arm/dts/imx6qdl-vicut1.dtsi
+++ b/arch/arm/dts/imx6qdl-vicut1.dtsi
@@ -4,6 +4,7 @@
*/
#include "imx6qdl-prti6q.dtsi"
+#include "imx6qdl-prti6q-nor.dtsi"
#include <dt-bindings/input/input.h>
/ {
@@ -74,6 +75,21 @@
};
};
+&ecspi1 {
+ cs-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ecspi1>;
+ status = "okay";
+
+ flash@0 {
+ compatible = "jedec,spi-nor";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+};
+
&iomuxc {
pinctrl_hog: hoggrp {
fsl,pins = <
@@ -151,6 +167,16 @@
>;
};
+ pinctrl_ecspi1: ecspi1grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__ECSPI1_MISO 0x100b1
+ MX6QDL_PAD_EIM_D18__ECSPI1_MOSI 0x100b1
+ MX6QDL_PAD_EIM_D16__ECSPI1_SCLK 0x100b1
+ /* CS */
+ MX6QDL_PAD_EIM_D19__GPIO3_IO19 0x000b1
+ >;
+ };
+
pinctrl_usbotg: usbotggrp {
fsl,pins = <
MX6QDL_PAD_EIM_D21__USB_OTG_OC 0x1b0b0
diff --git a/common/console_common.c b/common/console_common.c
index a174c2d..8cd57e6 100644
--- a/common/console_common.c
+++ b/common/console_common.c
@@ -23,6 +23,7 @@
#include <environment.h>
#include <globalvar.h>
#include <magicvar.h>
+#include <of.h>
#include <password.h>
#include <clock.h>
#include <malloc.h>
@@ -323,6 +324,23 @@ struct console_device *console_get_first_active(void)
}
EXPORT_SYMBOL(console_get_first_active);
+struct console_device *of_console_get_by_alias(const char *alias)
+{
+ struct device_node *node;
+ struct device_d *dev;
+
+ node = of_find_node_by_alias(NULL, alias);
+ if (!node)
+ return NULL;
+
+ dev = of_find_device_by_node(node);
+ if (!dev)
+ return NULL;
+
+ return console_get_by_dev(dev);
+}
+EXPORT_SYMBOL(of_console_get_by_alias);
+
#endif /* !CONFIG_CONSOLE_NONE */
int dprintf(int file, const char *fmt, ...)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 27674af..6088cad 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -381,6 +381,37 @@ void gpio_free_array(const struct gpio *array, size_t num)
}
EXPORT_SYMBOL_GPL(gpio_free_array);
+int gpio_array_to_id(const struct gpio *array, size_t num, u32 *val)
+{
+ u32 id = 0;
+ int ret, i;
+
+ if (num > 32)
+ return -EOVERFLOW;
+
+ ret = gpio_request_array(array, num);
+ if (ret)
+ return ret;
+
+ /* Wait until logic level will be stable */
+ udelay(5);
+ for (i = 0; i < num; i++) {
+ ret = gpio_is_active(array[i].gpio);
+ if (ret < 0)
+ goto free_array;
+ if (ret)
+ id |= 1UL << i;
+ }
+
+ *val = id;
+ ret = 0;
+
+free_array:
+ gpio_free_array(array, num);
+ return ret;
+}
+EXPORT_SYMBOL(gpio_array_to_id);
+
static int gpiochip_find_base(int start, int ngpio)
{
int i;
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 4c633bc..0a2632f 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -2130,6 +2130,21 @@ static void of_probe_memory(void)
}
}
+static void of_platform_device_create_root(struct device_node *np)
+{
+ struct device_d *dev;
+ int ret;
+
+ dev = xzalloc(sizeof(*dev));
+ dev->id = DEVICE_ID_SINGLE;
+ dev->device_node = np;
+ dev_set_name(dev, "machine");
+
+ ret = platform_device_register(dev);
+ if (ret)
+ free(dev);
+}
+
int of_probe(void)
{
struct device_node *firmware;
@@ -2149,6 +2164,8 @@ int of_probe(void)
if (firmware)
of_platform_populate(firmware, NULL, NULL);
+ of_platform_device_create_root(root_node);
+
of_clk_init(root_node, NULL);
of_platform_populate(root_node, of_default_bus_match_table, NULL);
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 67a67bd..b3f522e 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -31,3 +31,15 @@ const void *of_device_get_match_data(const struct device_d *dev)
return match->data;
}
EXPORT_SYMBOL(of_device_get_match_data);
+
+const char *of_device_get_match_compatible(const struct device_d *dev)
+{
+ const struct of_device_id *match;
+
+ match = of_match_device(dev->driver->of_compatible, dev);
+ if (!match)
+ return NULL;
+
+ return match->compatible;
+}
+EXPORT_SYMBOL(of_device_get_match_compatible);
diff --git a/include/console.h b/include/console.h
index 5b5c037..a71d0da 100644
--- a/include/console.h
+++ b/include/console.h
@@ -87,6 +87,7 @@ int console_unregister(struct console_device *cdev);
struct console_device *console_get_by_dev(struct device_d *dev);
struct console_device *console_get_by_name(const char *name);
+struct console_device *of_console_get_by_alias(const char *alias);
extern struct list_head console_list;
#define for_each_console(console) list_for_each_entry(console, &console_list, list)
diff --git a/include/gpio.h b/include/gpio.h
index 98c5b93..81beb47 100644
--- a/include/gpio.h
+++ b/include/gpio.h
@@ -145,6 +145,10 @@ static inline void gpio_free_array(const struct gpio *array, size_t num)
/* GPIO can never have been requested */
WARN_ON(1);
}
+static inline int gpio_array_to_id(const struct gpio *array, size_t num, u32 *val)
+{
+ return -EINVAL;
+}
#else
int gpio_request(unsigned gpio, const char *label);
int gpio_find_by_name(const char *name);
@@ -153,6 +157,7 @@ void gpio_free(unsigned gpio);
int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
int gpio_request_array(const struct gpio *array, size_t num);
void gpio_free_array(const struct gpio *array, size_t num);
+int gpio_array_to_id(const struct gpio *array, size_t num, u32 *val);
#endif
struct gpio_chip;
diff --git a/include/of_device.h b/include/of_device.h
index 244f5fc..cef6d5b 100644
--- a/include/of_device.h
+++ b/include/of_device.h
@@ -22,6 +22,7 @@ static inline int of_driver_match_device(struct device_d *dev,
}
extern const void *of_device_get_match_data(const struct device_d *dev);
+extern const char *of_device_get_match_compatible(const struct device_d *dev);
#else /* CONFIG_OFTREE */
@@ -36,6 +37,11 @@ static inline const void *of_device_get_match_data(const struct device_d *dev)
return NULL;
}
+static inline const char *of_device_get_match_compatible(const struct device_d *dev)
+{
+ return NULL;
+}
+
static inline const struct of_device_id *__of_match_device(
const struct of_device_id *matches, const struct device_d *dev)
{