* [PATCH v4 0/7] prepare Protonic board code for mainline @ 2020-08-17 8:19 Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 1/7] of: base: register DT root as device Oleksij Rempel ` (6 more replies) 0 siblings, 7 replies; 10+ messages in thread From: Oleksij Rempel @ 2020-08-17 8:19 UTC (permalink / raw) To: barebox, david; +Cc: Oleksij Rempel changes v4: - follow suggestion provided by Ahmad and open-code the root node registration and call it machine.of - board: rename crc and cs - board: ignore most of init related errors. Even if one part will fail, we should be able to get as mach as possible. changes v3: - remove barebox-serial driver and use read the rfid directy from board code (as was done in initial implementation) - use initcall instead of registering driver in the board code - add delayed USB scan - add rampoops node - add partition tables changes v2: - add power init support for KvG boards - spell fixes - do not print error on probe exit - add of_console_get_by_alias() helper - free requested gpio array - exit fec init only in case of PROBE_DEFERED This patch series is a preparation and actual Protonic board code. Following changes was made in the main code: - register DT root node as device to make it possible to loade board code as usual driver - provide helpers to read ethernet mac from nvmem cell register in a devicetree. - provide barebox-serial driver which should be a nvmem cell consumer and serial-number DT property provider. - provide gpio helper to read gpio based board revision. Oleksij Rempel (7): of: base: register DT root as device gpiolib: add gpio_array_to_id helper to get ID out of GPIO array common: console_common: add of_console_get_by_alias() helper of: of_device_get_match_compatible() helper ARM: protonic-imx6: port Protonic specific board code ARM: dts: unify barebox and barebox,env partitions for all Protonic boards ARM: dts: imx6q-prti6q: add pstore/ramoops node arch/arm/boards/protonic-imx6/Makefile | 1 + arch/arm/boards/protonic-imx6/board.c | 996 +++++++++++++++++++++++++ arch/arm/dts/imx6dl-plym2m.dts | 25 + arch/arm/dts/imx6dl-prtrvt.dts | 1 + arch/arm/dts/imx6q-prti6q.dts | 24 +- arch/arm/dts/imx6qdl-prti6q-nor.dtsi | 10 + arch/arm/dts/imx6qdl-prti6q.dtsi | 31 + arch/arm/dts/imx6qdl-vicut1.dtsi | 26 + common/console_common.c | 18 + drivers/gpio/gpiolib.c | 31 + drivers/of/base.c | 17 + drivers/of/device.c | 12 + include/console.h | 1 + include/gpio.h | 5 + include/of_device.h | 6 + 15 files changed, 1181 insertions(+), 23 deletions(-) create mode 100644 arch/arm/boards/protonic-imx6/board.c create mode 100644 arch/arm/dts/imx6qdl-prti6q-nor.dtsi -- 2.28.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 1/7] of: base: register DT root as device 2020-08-17 8:19 [PATCH v4 0/7] prepare Protonic board code for mainline Oleksij Rempel @ 2020-08-17 8:19 ` Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 2/7] gpiolib: add gpio_array_to_id helper to get ID out of GPIO array Oleksij Rempel ` (5 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: Oleksij Rempel @ 2020-08-17 8:19 UTC (permalink / raw) To: barebox, david; +Cc: Oleksij Rempel A usual board file contains at least one of_machine_is_compatible(). Some of the have a rather long list with complicated version logic. To avoid own implementation for driver management, register the root node of device tree as platform device. So, the main platform bus can attach proper board driver. After this patch a typical board.c file can reuse existing driver infrastructure. After this patch, you will be able to see all registered board drivers with drvinfo as fallow: ... board-embest-riot board-protonic-imx6 machine.of ... With devinfo, you'll be able to get some board specific information, if this is implemented: barebox@Protonic PRTI6Q board:/ devinfo machine.of Driver: board-protonic-imx6 Bus: platform Parameters: boardid: 0 (type: uint32) boardrev: 1 (type: uint32) Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- drivers/of/base.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 2fc87528eb..9e49158e61 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -2136,6 +2136,21 @@ static int of_probe_memory(void) } mem_initcall(of_probe_memory); +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.of"); + + ret = platform_device_register(dev); + if (ret) + free(dev); +} + int of_probe(void) { struct device_node *firmware; @@ -2153,6 +2168,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); -- 2.28.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 2/7] gpiolib: add gpio_array_to_id helper to get ID out of GPIO array 2020-08-17 8:19 [PATCH v4 0/7] prepare Protonic board code for mainline Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 1/7] of: base: register DT root as device Oleksij Rempel @ 2020-08-17 8:19 ` Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 3/7] common: console_common: add of_console_get_by_alias() helper Oleksij Rempel ` (4 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: Oleksij Rempel @ 2020-08-17 8:19 UTC (permalink / raw) To: barebox, david; +Cc: Oleksij Rempel Some boards provide a board version and/or ID coded by pull-up/down resistors connected to the gpio pins (or pins which can be multiplexed at some point as gpio). In this case every one implements own gpio id reader function. To avoid it, provide the common helper function to extract a value out of provided gpio array. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- drivers/gpio/gpiolib.c | 31 +++++++++++++++++++++++++++++++ include/gpio.h | 5 +++++ 2 files changed, 36 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 27674af54c..6088cadd8a 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/include/gpio.h b/include/gpio.h index 98c5b93ba2..81beb47309 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; -- 2.28.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 3/7] common: console_common: add of_console_get_by_alias() helper 2020-08-17 8:19 [PATCH v4 0/7] prepare Protonic board code for mainline Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 1/7] of: base: register DT root as device Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 2/7] gpiolib: add gpio_array_to_id helper to get ID out of GPIO array Oleksij Rempel @ 2020-08-17 8:19 ` Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 4/7] of: of_device_get_match_compatible() helper Oleksij Rempel ` (3 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: Oleksij Rempel @ 2020-08-17 8:19 UTC (permalink / raw) To: barebox, david; +Cc: Oleksij Rempel Add helper function to get console device by devicetree alias Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- common/console_common.c | 18 ++++++++++++++++++ include/console.h | 1 + 2 files changed, 19 insertions(+) diff --git a/common/console_common.c b/common/console_common.c index a174c2deed..8cd57e623d 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/include/console.h b/include/console.h index 5b5c037026..a71d0da42e 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) -- 2.28.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 4/7] of: of_device_get_match_compatible() helper 2020-08-17 8:19 [PATCH v4 0/7] prepare Protonic board code for mainline Oleksij Rempel ` (2 preceding siblings ...) 2020-08-17 8:19 ` [PATCH v4 3/7] common: console_common: add of_console_get_by_alias() helper Oleksij Rempel @ 2020-08-17 8:19 ` Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 5/7] ARM: protonic-imx6: port Protonic specific board code Oleksij Rempel ` (2 subsequent siblings) 6 siblings, 0 replies; 10+ messages in thread From: Oleksij Rempel @ 2020-08-17 8:19 UTC (permalink / raw) To: barebox, david; +Cc: Oleksij Rempel Some times we need to know, against which compatible did the driver was registered. So, instead of coding it in the driver, add generic helper for all drivers. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- drivers/of/device.c | 12 ++++++++++++ include/of_device.h | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/of/device.c b/drivers/of/device.c index 67a67bd565..b3f522e1fa 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/of_device.h b/include/of_device.h index 244f5fcbbb..cef6d5b5cc 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) { -- 2.28.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 5/7] ARM: protonic-imx6: port Protonic specific board code 2020-08-17 8:19 [PATCH v4 0/7] prepare Protonic board code for mainline Oleksij Rempel ` (3 preceding siblings ...) 2020-08-17 8:19 ` [PATCH v4 4/7] of: of_device_get_match_compatible() helper Oleksij Rempel @ 2020-08-17 8:19 ` Oleksij Rempel 2020-08-19 6:27 ` Sascha Hauer 2020-08-17 8:19 ` [PATCH v4 6/7] ARM: dts: unify barebox and barebox, env partitions for all Protonic boards Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 7/7] ARM: dts: imx6q-prti6q: add pstore/ramoops node Oleksij Rempel 6 siblings, 1 reply; 10+ messages in thread From: Oleksij Rempel @ 2020-08-17 8:19 UTC (permalink / raw) To: barebox, david; +Cc: Oleksij Rempel Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- arch/arm/boards/protonic-imx6/Makefile | 1 + arch/arm/boards/protonic-imx6/board.c | 996 +++++++++++++++++++++++++ 2 files changed, 997 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..a28b7eb3b6 --- /dev/null +++ b/arch/arm/boards/protonic-imx6/board.c @@ -0,0 +1,996 @@ +// 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 <gpio.h> +#include <mach/bbu.h> +#include <mach/imx6.h> +#include <of_device.h> + +#include <usb/usb.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <net.h> +#include <i2c/i2c.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, "Filed 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])) { + 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_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; +} + +#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; + 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; + } + usbdisk = "disk0"; + } else { + usbdisk = "disk0.0"; + } + + 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 = 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; + } + + 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) + 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, + 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"); + 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); -- 2.28.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 5/7] ARM: protonic-imx6: port Protonic specific board code 2020-08-17 8:19 ` [PATCH v4 5/7] ARM: protonic-imx6: port Protonic specific board code Oleksij Rempel @ 2020-08-19 6:27 ` Sascha Hauer 2020-08-19 8:01 ` David Jander 0 siblings, 1 reply; 10+ messages in thread From: Sascha Hauer @ 2020-08-19 6:27 UTC (permalink / raw) To: Oleksij Rempel; +Cc: barebox, david On Mon, Aug 17, 2020 at 10:19:27AM +0200, Oleksij Rempel wrote: > +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"); Maybe print the failed MAC address? ethaddr_to_string can be of help here. > + 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; > +} > + > +#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; > + unsigned int v; > + ssize_t size; > + char buf[16]; > + int fd, ret; > + > + v = *((unsigned int *)OTG_PORTSC1); readl > + 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); s/Filed/Failed/ A warning is a bit harsh here. When this is a valid usecase then it's a gentle information at best. I would explicitly test for existence of /dev/disk0.0 before trying to mount it, because if it does exist and mounting fails then there's no point in trying to mount the raw device. > + > + ret = mount("/dev/disk0", NULL, "usb", NULL); > + if (ret) { > + dev_err(dev, "USB mount failed!\n"); > + goto exit_usb_boot; > + } > + usbdisk = "disk0"; > + } else { > + usbdisk = "disk0.0"; > + } > + > + fd = open("/usb/boot_target", O_RDONLY); > + if (fd < 0) { > + dev_err(dev, "Can't open /usb/boot_target file\n"); So some arbitrary USB stick is inserted. Is this really an error or just a case of saying "boot_target file not found on USB stick. Continuing normal boot"? > + 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")) { When the file contains "vicut1 usb" then this is without the trailing \0 whereas sizeof("vicut1 usb") gives you the size of the string including the trailing \0, so I believe in this case you error out. > + 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++; You assume that buf contains two words. strchr() returns NULL if it doesn't. I think you should do the split up in words before testing any contents of them. Then you wouldn't need all these questionable strncmp and could use plain strcmp. > + > + 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"); Here it would be nice two know for the user what the second word was. > + 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); You can print a nicer error message with strerror(-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) > + 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, > + char *serial) 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"); > + return -ENODEV; > + } This means someone called of_fix_tree() with a NULL pointer. In this case he deserves the resulting backtrace. No need to check this. > + > + 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; xzalloc()? Sascha -- 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 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 5/7] ARM: protonic-imx6: port Protonic specific board code 2020-08-19 6:27 ` Sascha Hauer @ 2020-08-19 8:01 ` David Jander 0 siblings, 0 replies; 10+ messages in thread From: David Jander @ 2020-08-19 8:01 UTC (permalink / raw) To: Sascha Hauer; +Cc: Oleksij Rempel, barebox On Wed, 19 Aug 2020 08:27:41 +0200 Sascha Hauer <s.hauer@pengutronix.de> wrote: > On Mon, Aug 17, 2020 at 10:19:27AM +0200, Oleksij Rempel wrote: > > +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"); > > Maybe print the failed MAC address? ethaddr_to_string can be of help > here. The important thing is to know the MAC address is correctly stored (CS ok) but invalid. Printing the invalid MAC address itself might be helpful too, but is not really needed here. It can be extracted "by hand" while investigating the issue. Something that normally shouldn't be occurring. OTOH, ethaddr_to_string() is already linked in, so binary size increase is probably negligible for this. I'm fine either way. > > + 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; > > +} > > + > > +#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; > > + unsigned int v; > > + ssize_t size; > > + char buf[16]; > > + int fd, ret; > > + > > + v = *((unsigned int *)OTG_PORTSC1); > > readl > > > + 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); > > s/Filed/Failed/ > > A warning is a bit harsh here. When this is a valid usecase then it's a > gentle information at best. Ack. > I would explicitly test for existence of /dev/disk0.0 before trying to > mount it, because if it does exist and mounting fails then there's no > point in trying to mount the raw device. Ack. > > + > > + ret = mount("/dev/disk0", NULL, "usb", NULL); > > + if (ret) { > > + dev_err(dev, "USB mount failed!\n"); > > + goto exit_usb_boot; > > + } > > + usbdisk = "disk0"; > > + } else { > > + usbdisk = "disk0.0"; > > + } > > + > > + fd = open("/usb/boot_target", O_RDONLY); > > + if (fd < 0) { > > + dev_err(dev, "Can't open /usb/boot_target file\n"); > > So some arbitrary USB stick is inserted. Is this really an error or just > a case of saying "boot_target file not found on USB stick. Continuing > normal boot"? Ack. This probably shouldn't be an error... but maybe a warning is OK. > > + 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")) { > > When the file contains "vicut1 usb" then this is without the trailing \0 > whereas sizeof("vicut1 usb") gives you the size of the string including > the trailing \0, so I believe in this case you error out. Ack. This should be "strlen" or (sizeof("vicut1 usb")-1) with a proper comment. FYI, original code was (v == size read from file): if (v < 10) { /* length of "vicut1 usb", the shortest possible target */ ... > > + 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++; > > > You assume that buf contains two words. strchr() returns NULL if it > doesn't. Ack. A check for NULL is needed here. > I think you should do the split up in words before testing any contents > of them. Then you wouldn't need all these questionable strncmp and could > use plain strcmp. > > > + > > + 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"); > > Here it would be nice two know for the user what the second word was. But that would risk the word to not be printable and mess up the console. Shouldn't be done without further checks IMHO, and that is too costly for the purpose. > > + 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); > > You can print a nicer error message with strerror(-ret). Ack. > > + > > + 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, > > + char *serial) > > 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"); > > + return -ENODEV; > > + } > > This means someone called of_fix_tree() with a NULL pointer. In this > case he deserves the resulting backtrace. No need to check this. Good point. > > + > > + 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; > > xzalloc()? > > Sascha Best regards, -- David Jander Protonic Holland. _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 6/7] ARM: dts: unify barebox and barebox, env partitions for all Protonic boards 2020-08-17 8:19 [PATCH v4 0/7] prepare Protonic board code for mainline Oleksij Rempel ` (4 preceding siblings ...) 2020-08-17 8:19 ` [PATCH v4 5/7] ARM: protonic-imx6: port Protonic specific board code Oleksij Rempel @ 2020-08-17 8:19 ` Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 7/7] ARM: dts: imx6q-prti6q: add pstore/ramoops node Oleksij Rempel 6 siblings, 0 replies; 10+ messages in thread From: Oleksij Rempel @ 2020-08-17 8:19 UTC (permalink / raw) To: barebox, david; +Cc: Oleksij Rempel Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- arch/arm/dts/imx6dl-plym2m.dts | 25 +++++++++++++++++++++++++ arch/arm/dts/imx6dl-prtrvt.dts | 1 + arch/arm/dts/imx6q-prti6q.dts | 24 +----------------------- arch/arm/dts/imx6qdl-prti6q-nor.dtsi | 10 ++++++++++ arch/arm/dts/imx6qdl-prti6q.dtsi | 20 ++++++++++++++++++++ arch/arm/dts/imx6qdl-vicut1.dtsi | 26 ++++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 23 deletions(-) create mode 100644 arch/arm/dts/imx6qdl-prti6q-nor.dtsi diff --git a/arch/arm/dts/imx6dl-plym2m.dts b/arch/arm/dts/imx6dl-plym2m.dts index b66321fb46..335cb6f342 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"; @@ -28,6 +29,20 @@ }; }; +&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"; @@ -58,6 +73,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 802bd50ae6..c403ba3ea7 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 76bb4d53d3..63a02149f1 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 0000000000..ad718ce421 --- /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 ed526d185f..19acca042d 100644 --- a/arch/arm/dts/imx6qdl-prti6q.dtsi +++ b/arch/arm/dts/imx6qdl-prti6q.dtsi @@ -9,6 +9,11 @@ / { chosen { stdout-path = &uart4; + + environment-emmc { + compatible = "barebox,environment"; + device-path = &usdhc3, "partname:barebox-environment"; + }; }; reg_1v8: regulator-1v8 { @@ -105,7 +110,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 dc18614f89..dbfcf2527c 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 -- 2.28.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 7/7] ARM: dts: imx6q-prti6q: add pstore/ramoops node 2020-08-17 8:19 [PATCH v4 0/7] prepare Protonic board code for mainline Oleksij Rempel ` (5 preceding siblings ...) 2020-08-17 8:19 ` [PATCH v4 6/7] ARM: dts: unify barebox and barebox, env partitions for all Protonic boards Oleksij Rempel @ 2020-08-17 8:19 ` Oleksij Rempel 6 siblings, 0 replies; 10+ messages in thread From: Oleksij Rempel @ 2020-08-17 8:19 UTC (permalink / raw) To: barebox, david; +Cc: Oleksij Rempel Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- arch/arm/dts/imx6qdl-prti6q.dtsi | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/dts/imx6qdl-prti6q.dtsi b/arch/arm/dts/imx6qdl-prti6q.dtsi index 19acca042d..f2b36553d4 100644 --- a/arch/arm/dts/imx6qdl-prti6q.dtsi +++ b/arch/arm/dts/imx6qdl-prti6q.dtsi @@ -16,6 +16,17 @@ }; }; + reserved-memory { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + /* Address will be determined by the bootloader */ + ramoops { + compatible = "ramoops"; + }; + }; + reg_1v8: regulator-1v8 { compatible = "regulator-fixed"; regulator-name = "1v8"; -- 2.28.0 _______________________________________________ barebox mailing list barebox@lists.infradead.org http://lists.infradead.org/mailman/listinfo/barebox ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2020-08-19 8:01 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-08-17 8:19 [PATCH v4 0/7] prepare Protonic board code for mainline Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 1/7] of: base: register DT root as device Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 2/7] gpiolib: add gpio_array_to_id helper to get ID out of GPIO array Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 3/7] common: console_common: add of_console_get_by_alias() helper Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 4/7] of: of_device_get_match_compatible() helper Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 5/7] ARM: protonic-imx6: port Protonic specific board code Oleksij Rempel 2020-08-19 6:27 ` Sascha Hauer 2020-08-19 8:01 ` David Jander 2020-08-17 8:19 ` [PATCH v4 6/7] ARM: dts: unify barebox and barebox, env partitions for all Protonic boards Oleksij Rempel 2020-08-17 8:19 ` [PATCH v4 7/7] ARM: dts: imx6q-prti6q: add pstore/ramoops node Oleksij Rempel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox