summaryrefslogtreecommitdiffstats
path: root/arch/arm/boards/protonic-imx6/board.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/boards/protonic-imx6/board.c')
-rw-r--r--arch/arm/boards/protonic-imx6/board.c251
1 files changed, 176 insertions, 75 deletions
diff --git a/arch/arm/boards/protonic-imx6/board.c b/arch/arm/boards/protonic-imx6/board.c
index cdbb8debe6..9e62dc1544 100644
--- a/arch/arm/boards/protonic-imx6/board.c
+++ b/arch/arm/boards/protonic-imx6/board.c
@@ -4,24 +4,27 @@
// SPDX-FileCopyrightText: 2020 Oleksij Rempel, Pengutronix
#include <bbu.h>
+#include <boot.h>
+#include <bootm.h>
#include <common.h>
#include <deep-probe.h>
#include <environment.h>
#include <fcntl.h>
+#include <globalvar.h>
#include <gpio.h>
#include <i2c/i2c.h>
-#include <mach/bbu.h>
-#include <mach/imx6.h>
+#include <mach/imx/bbu.h>
+#include <mach/imx/imx6.h>
+#include <mach/imx/ocotp-fusemap.h>
#include <mfd/imx6q-iomuxc-gpr.h>
#include <mfd/syscon.h>
#include <net.h>
#include <of_device.h>
-#include <regmap.h>
+#include <linux/regmap.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <usb/usb.h>
-#include <work.h>
+#include <linux/usb/usb.h>
#define GPIO_HW_REV_ID {\
{IMX_GPIO_NR(2, 8), GPIOF_DIR_IN | GPIOF_ACTIVE_LOW, "rev_id0"}, \
@@ -81,15 +84,13 @@ struct prt_machine_data {
};
struct prt_imx6_priv {
- struct device_d *dev;
+ struct device *dev;
const struct prt_machine_data *dcfg;
unsigned int hw_id;
unsigned int hw_rev;
const char *name;
- unsigned int usb_delay;
unsigned int no_usb_check;
- struct work_queue wq;
- struct work_struct work;
+ char *ocotp_serial;
};
struct prti6q_rfid_contents {
@@ -146,7 +147,7 @@ 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 device *dev = priv->dev;
struct i2c_client cl;
int ret;
@@ -186,7 +187,7 @@ static u8 prt_imx6_calc_rfid_cs(void *buf, size_t size)
static int prt_imx6_set_mac(struct prt_imx6_priv *priv,
struct prti6q_rfid_contents *rfid)
{
- struct device_d *dev = priv->dev;
+ struct device *dev = priv->dev;
struct device_node *node;
node = of_find_node_by_alias(of_get_root_node(), "ethernet0");
@@ -199,10 +200,7 @@ static int prt_imx6_set_mac(struct prt_imx6_priv *priv,
return 0;
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);
+ dev_err(dev, "bad MAC addr: %pM\n", &rfid->mac[0]);
return -EILSEQ;
}
@@ -212,19 +210,18 @@ static int prt_imx6_set_mac(struct prt_imx6_priv *priv,
return 0;
}
-static int prt_imx6_set_serial(struct prt_imx6_priv *priv,
- struct prti6q_rfid_contents *rfid)
+static int prt_imx6_set_serial(struct prt_imx6_priv *priv, char *serial)
{
- rfid->serial[9] = 0; /* Failsafe */
- dev_info(priv->dev, "Serial number: %s\n", rfid->serial);
- barebox_set_serial_number(rfid->serial);
+ serial[9] = 0; /* Failsafe */
+ dev_info(priv->dev, "Serial number: %s\n", serial);
+ barebox_set_serial_number(serial);
return 0;
}
static int prt_imx6_read_i2c_mac_serial(struct prt_imx6_priv *priv)
{
- struct device_d *dev = priv->dev;
+ struct device *dev = priv->dev;
struct prti6q_rfid_contents rfid;
int ret;
@@ -241,16 +238,60 @@ static int prt_imx6_read_i2c_mac_serial(struct prt_imx6_priv *priv)
if (ret)
return ret;
- ret = prt_imx6_set_serial(priv, &rfid);
+ ret = prt_imx6_set_serial(priv, rfid.serial);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+#define PRT_IMX6_GP1_FMT_DEC BIT(31)
+
+static int prt_imx6_read_ocotp_serial(struct prt_imx6_priv *priv)
+{
+ int ret;
+ unsigned val;
+
+ ret = imx_ocotp_read_field(OCOTP_GP1, &val);
+ if (ret) {
+ dev_err(priv->dev, "Failed to read ocotp serial (%i)\n", ret);
+ return ret;
+ }
+
+ if (!(val & PRT_IMX6_GP1_FMT_DEC))
+ return -EINVAL;
+ val &= PRT_IMX6_GP1_FMT_DEC - 1;
+
+ priv->ocotp_serial = xasprintf("%u", val);
+
+ return prt_imx6_set_serial(priv, priv->ocotp_serial);
+}
+
+static int prt_imx6_set_ocotp_serial(struct param_d *param, void *driver_priv)
+{
+ struct prt_imx6_priv *priv = driver_priv;
+ int ret;
+ unsigned val;
+
+ ret = kstrtouint(priv->ocotp_serial, 10, &val);
+ if (ret)
+ return ret;
+
+ if (val & PRT_IMX6_GP1_FMT_DEC)
+ return -ERANGE;
+ val |= PRT_IMX6_GP1_FMT_DEC;
+
+ ret = imx_ocotp_write_field(OCOTP_GP1, val);
if (ret)
return ret;
+ barebox_set_serial_number(priv->ocotp_serial);
return 0;
}
-static int prt_imx6_usb_mount(struct prt_imx6_priv *priv, char **usbdisk)
+static int prt_imx6_usb_mount(struct prt_imx6_priv *priv)
{
- struct device_d *dev = priv->dev;
+ struct device *dev = priv->dev;
const char *path;
struct stat s;
int ret;
@@ -267,8 +308,6 @@ static int prt_imx6_usb_mount(struct prt_imx6_priv *priv, char **usbdisk)
ret = mount(path, NULL, "usb", NULL);
if (ret)
goto exit_usb_mount;
-
- *usbdisk = strdup("disk0.0");
return 0;
}
@@ -278,8 +317,6 @@ static int prt_imx6_usb_mount(struct prt_imx6_priv *priv, char **usbdisk)
ret = mount(path, NULL, "usb", NULL);
if (ret)
goto exit_usb_mount;
-
- *usbdisk = strdup("disk0");
return 0;
}
@@ -290,25 +327,21 @@ exit_usb_mount:
#define OTG_PORTSC1 (MX6_OTG_BASE_ADDR+0x184)
-static void prt_imx6_check_usb_boot_do_work(struct work_struct *w)
+static int prt_imx6_usb_boot(struct bootentry *entry, int verbose, int dryrun)
{
- struct prt_imx6_priv *priv = container_of(w, struct prt_imx6_priv, work);
- struct device_d *dev = priv->dev;
- char *second_word, *bootsrc, *usbdisk;
+ struct prt_imx6_priv *priv = prt_priv;
+ struct device *dev = priv->dev;
+ char *second_word;
char buf[sizeof("vicut1q recovery")] = {};
- unsigned int v;
+ struct bootm_data bootm_data = {};
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);
+ ret = prt_imx6_usb_mount(priv);
if (ret)
- return;
+ return ret;
fd = open("/usb/boot_target", O_RDONLY);
if (fd < 0) {
@@ -347,37 +380,91 @@ static void prt_imx6_check_usb_boot_do_work(struct work_struct *w)
goto exit_usb_boot;
}
+ bootm_data_init_defaults(&bootm_data);
+
second_word++;
if (strncmp(second_word, "usb", 3) == 0) {
- bootsrc = "usb";
+ dev_info(dev, "Booting from USB drive\n");
+ bootm_data.os_file = "/usb/linuximage.fit";
} else if (strncmp(second_word, "recovery", 8) == 0) {
- bootsrc = "recovery";
+ dev_info(dev, "Booting internal recovery OS\n");
+ bootm_data.os_file = "/dev/mmc2.5";
} 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);
+ ret = globalvar_add_simple("linux.bootargs.root",
+ "root=/dev/ram rw rootwait ramdisk_size=196608");
+ if (ret)
+ goto exit_usb_boot;
+
+ if (verbose)
+ bootm_data.verbose = verbose;
+ if (dryrun)
+ bootm_data.dryrun = dryrun;
+
+ ret = bootm_boot(&bootm_data);
if (ret)
goto exit_usb_boot;
- free(usbdisk);
- return;
+ return 0;
exit_usb_boot:
dev_err(dev, "Failed to run usb boot: %s\n", strerror(-ret));
- free(usbdisk);
- return;
+ return ret;
+}
+
+static void prt_imx6_bootentry_release(struct bootentry *entry)
+{
+ free(entry);
+}
+
+static int prt_imx6_bootentry_create(struct bootentries *bootentries, const char *name)
+{
+ struct bootentry *entry;
+
+ entry = xzalloc(sizeof(*entry));
+ if (!entry)
+ return -ENOMEM;
+
+ entry->me.type = MENU_ENTRY_NORMAL;
+ entry->release = prt_imx6_bootentry_release;
+ entry->boot = prt_imx6_usb_boot;
+ entry->title = xstrdup(name);
+ entry->description = xstrdup("Boot FIT image of a USB drive");
+ bootentries_add_entry(bootentries, entry);
+
+ return 0;
+}
+
+static int prt_imx6_bootentry_provider(struct bootentries *bootentries,
+ const char *name)
+{
+ int found = 0;
+ unsigned int v;
+
+ if (strncmp(name, "prt-usb", 7))
+ return found;
+
+ v = readl(OTG_PORTSC1);
+ if ((v & 0x0c00) == 0) /* No usb device detected */
+ return found;
+
+ if (!prt_imx6_bootentry_create(bootentries, name))
+ found = 1;
+
+ return found;
}
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;
+ struct device *dev = priv->dev;
+ char *delay, *bootsrc, *boot_targets;
+ unsigned int autoboot_timeout;
int ret;
ret = setenv("global.linux.bootargs.base", "consoleblank=0 vt.color=0x00");
@@ -388,13 +475,14 @@ static int prt_imx6_env_init(struct prt_imx6_priv *priv)
set_autoboot_state(AUTOBOOT_BOOT);
} else {
if (dcfg->flags & PRT_IMX6_USB_LONG_DELAY)
- priv->usb_delay = 4;
+ autoboot_timeout = 4;
else
- priv->usb_delay = 1;
+ autoboot_timeout = 1;
/* the usb_delay value is used for poller_call_async() */
- delay = basprintf("%d", priv->usb_delay);
+ delay = basprintf("%d", autoboot_timeout);
ret = setenv("global.autoboot_timeout", delay);
+ free(delay);
if (ret)
goto exit_env_init;
}
@@ -404,7 +492,13 @@ static int prt_imx6_env_init(struct prt_imx6_priv *priv)
else
bootsrc = "mmc2";
- ret = setenv("global.boot.default", bootsrc);
+ if (!priv->no_usb_check)
+ boot_targets = xasprintf("prt-usb %s", bootsrc);
+ else
+ boot_targets = xstrdup(bootsrc);
+
+ ret = setenv("global.boot.default", boot_targets);
+ free(boot_targets);
if (ret)
goto exit_env_init;
@@ -433,7 +527,7 @@ static int prt_imx6_bbu(struct prt_imx6_priv *priv)
emmc_flags = BBU_HANDLER_FLAG_DEFAULT;
}
- devicefile = basprintf("mmc%d", dcfg->emmc_usdhc);
+ devicefile = basprintf("/dev/mmc%d", dcfg->emmc_usdhc);
if (!devicefile) {
ret = -ENOMEM;
goto exit_bbu;
@@ -443,7 +537,7 @@ static int prt_imx6_bbu(struct prt_imx6_priv *priv)
if (ret)
goto exit_bbu;
- devicefile = basprintf("mmc%d", dcfg->sd_usdhc);
+ devicefile = basprintf("/dev/mmc%d", dcfg->sd_usdhc);
if (!devicefile) {
ret = -ENOMEM;
goto exit_bbu;
@@ -462,6 +556,8 @@ exit_bbu:
static int prt_imx6_devices_init(void)
{
struct prt_imx6_priv *priv = prt_priv;
+ struct device *ocotp_dev;
+ struct param_d *p;
if (!priv)
return 0;
@@ -471,17 +567,26 @@ static int prt_imx6_devices_init(void)
prt_imx6_bbu(priv);
- prt_imx6_read_i2c_mac_serial(priv);
-
- prt_imx6_env_init(priv);
+ /*
+ * Read serial number from fuses. On success we'll assume the imx_ocotp
+ * driver takes care of providing the mac address if needed. On
+ * failure we'll fallback to reading and setting serial and mac from an
+ * attached RFID eeprom.
+ */
+ if (prt_imx6_read_ocotp_serial(priv) != 0)
+ prt_imx6_read_i2c_mac_serial(priv);
- if (!priv->no_usb_check) {
- priv->wq.fn = prt_imx6_check_usb_boot_do_work;
+ bootentry_register_provider(prt_imx6_bootentry_provider);
- wq_register(&priv->wq);
+ prt_imx6_env_init(priv);
- wq_queue_delayed_work(&priv->wq, &priv->work,
- priv->usb_delay * SECOND);
+ ocotp_dev = get_device_by_name("ocotp0");
+ if (ocotp_dev) {
+ p = dev_add_param_string(ocotp_dev, "serial_number",
+ prt_imx6_set_ocotp_serial, NULL,
+ &priv->ocotp_serial, priv);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
}
return 0;
@@ -507,7 +612,7 @@ 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 device *dev = priv->dev;
struct console_device *yccon;
int ret;
@@ -680,24 +785,22 @@ static int prt_imx6_rfid_fixup(struct prt_imx6_priv *priv,
}
i2c_node = of_find_node_by_alias(root, alias);
+ kfree(alias);
if (!i2c_node) {
dev_err(priv->dev, "Unsupported i2c adapter\n");
- ret = -ENODEV;
- goto free_alias;
+ return -ENODEV;
}
eeprom_node_name = basprintf("/eeprom@%x", dcfg->i2c_addr);
if (!eeprom_node_name) {
- ret = -ENOMEM;
- goto free_alias;
+ return -ENOMEM;
}
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;
+ return -ENOMEM;
}
ret = of_property_write_string(node, "compatible", "atmel,24c256");
@@ -721,8 +824,6 @@ static int prt_imx6_rfid_fixup(struct prt_imx6_priv *priv,
return 0;
free_eeprom:
kfree(eeprom_node_name);
-free_alias:
- kfree(alias);
exit_error:
dev_err(priv->dev, "Failed to apply fixup: %pe\n", ERR_PTR(ret));
return ret;
@@ -810,7 +911,7 @@ exit_get_dcfg:
return ret;
}
-static int prt_imx6_probe(struct device_d *dev)
+static int prt_imx6_probe(struct device *dev)
{
struct prt_imx6_priv *priv;
struct param_d *p;
@@ -1158,7 +1259,7 @@ static const struct of_device_id prt_imx6_of_match[] = {
{ .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 = "vdl,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 },
@@ -1173,7 +1274,7 @@ static const struct of_device_id prt_imx6_of_match[] = {
};
BAREBOX_DEEP_PROBE_ENABLE(prt_imx6_of_match);
-static struct driver_d prt_imx6_board_driver = {
+static struct driver prt_imx6_board_driver = {
.name = "board-protonic-imx6",
.probe = prt_imx6_probe,
.of_compatible = DRV_OF_COMPAT(prt_imx6_of_match),