* [PATCH 0/5] Hexagon Geosystems GS05 Board Support
@ 2026-02-05 15:45 Marco Felsch
2026-02-05 15:45 ` [PATCH 1/5] ARM: i.MX8MM: add MX8MM_PAD_CTL defines Marco Felsch
` (5 more replies)
0 siblings, 6 replies; 23+ messages in thread
From: Marco Felsch @ 2026-02-05 15:45 UTC (permalink / raw)
To: Sascha Hauer, BAREBOX; +Cc: Marco Felsch, Johannes Schneider
Hi,
this series adds the support for the Hexagon Geosystems GS05 product
[1]. The GS05 is part of a larger product family from SW pov, therefore
most logic is implemented below 'common/boards/hgs'.
The board support was added before the new security-profiles made it
into barebox mainline, therefore security-profiles aren't used yet but
maybe in the future.
Further products will be send mainline as well, once this basic support
got merged.
Patch1-2 were also sent here [2] in parallel.
Regards,
Marco
[1] https://leica-geosystems.com/de-de/products/gnss-systems/smart-antennas/leica-gs05
[2] https://lore.kernel.org/barebox/20260204151645.1426068-1-m.felsch@pengutronix.de/
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
Marco Felsch (5):
ARM: i.MX8MM: add MX8MM_PAD_CTL defines
lib: hexdump: make use of pr_print
mfd: Add Hexagon EFI driver
watchdog: Add Hexagon EFI watchdog driver
ARM: i.MX8MM: add Hexagon Geosystems GS05
arch/arm/boards/Makefile | 1 +
arch/arm/boards/hgs-gs05/Makefile | 6 +
arch/arm/boards/hgs-gs05/board.c | 237 +++++
arch/arm/boards/hgs-gs05/flash-header-gs05.imxcfg | 12 +
arch/arm/boards/hgs-gs05/lowlevel.c | 128 +++
arch/arm/boards/hgs-gs05/lpddr4-timing.c | 1118 +++++++++++++++++++++
arch/arm/dts/Makefile | 1 +
arch/arm/dts/imx8m-hgs-common.dtsi | 80 ++
arch/arm/dts/imx8mm-hgs-gs05.dts | 320 ++++++
arch/arm/mach-imx/Kconfig | 8 +
commands/ethlog.c | 4 +-
common/boards/Kconfig | 12 +
common/boards/Makefile | 1 +
common/boards/hgs/Makefile | 7 +
common/boards/hgs/common.c | 627 ++++++++++++
common/boards/hgs/lib.c | 73 ++
common/boards/hgs/pbl.c | 100 ++
drivers/mfd/Kconfig | 8 +
drivers/mfd/Makefile | 1 +
drivers/mfd/hgs-efi.c | 473 +++++++++
drivers/mtd/ubi/attach.c | 2 +-
drivers/watchdog/Kconfig | 9 +
drivers/watchdog/Makefile | 1 +
drivers/watchdog/hgs_efi_wdt.c | 88 ++
fs/ubifs/debug.c | 4 +-
images/Makefile.imx | 2 +
include/boards/hgs/common.h | 84 ++
include/linux/printk.h | 4 +-
include/mach/imx/iomux-mx8mm.h | 10 +
include/mfd/hgs-efi.h | 46 +
include/printf.h | 2 +-
include/soc/ti/cppi5.h | 2 +-
lib/hexdump.c | 13 +-
33 files changed, 3467 insertions(+), 17 deletions(-)
---
base-commit: 8781fc641fc147df639c9e767a89aa3277d2c9be
change-id: 20260205-vmaster-customers-leicageo-system1600-f62320eed41f
Best regards,
--
Marco Felsch <m.felsch@pengutronix.de>
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH 1/5] ARM: i.MX8MM: add MX8MM_PAD_CTL defines 2026-02-05 15:45 [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch @ 2026-02-05 15:45 ` Marco Felsch 2026-02-06 13:04 ` Ahmad Fatoum 2026-02-05 15:45 ` [PATCH 2/5] lib: hexdump: make use of pr_print Marco Felsch ` (4 subsequent siblings) 5 siblings, 1 reply; 23+ messages in thread From: Marco Felsch @ 2026-02-05 15:45 UTC (permalink / raw) To: Sascha Hauer, BAREBOX; +Cc: Marco Felsch Add defines like already done for i.MX8MP and i.MX8MQ. Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> --- include/mach/imx/iomux-mx8mm.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/include/mach/imx/iomux-mx8mm.h b/include/mach/imx/iomux-mx8mm.h index ee0240f538322021ae37a7d154bfdd26d0628087..693eb67b9602c1c5ca4f8f9b448c2a7886ce1046 100644 --- a/include/mach/imx/iomux-mx8mm.h +++ b/include/mach/imx/iomux-mx8mm.h @@ -691,6 +691,16 @@ enum { IMX8MM_PAD_UART4_TXD_GPIO5_IO29 = IOMUX_PAD(0x04B8, 0x0250, 5, 0x0000, 0, 0), }; +#define MX8MM_PAD_CTL_DSE1 (0 << 1) +#define MX8MM_PAD_CTL_DSE2 (2 << 1) +#define MX8MM_PAD_CTL_DSE4 (1 << 1) +#define MX8MM_PAD_CTL_DSE6 (3 << 1) +#define MX8MM_PAD_CTL_FSEL BIT(4) +#define MX8MM_PAD_CTL_ODE BIT(5) +#define MX8MM_PAD_CTL_PUE BIT(6) +#define MX8MM_PAD_CTL_HYS BIT(7) +#define MX8MM_PAD_CTL_PE BIT(8) + static inline void imx8mm_setup_pad(iomux_v3_cfg_t pad) { void __iomem *iomux = IOMEM(MX8MM_IOMUXC_BASE_ADDR); -- 2.47.3 ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/5] ARM: i.MX8MM: add MX8MM_PAD_CTL defines 2026-02-05 15:45 ` [PATCH 1/5] ARM: i.MX8MM: add MX8MM_PAD_CTL defines Marco Felsch @ 2026-02-06 13:04 ` Ahmad Fatoum 0 siblings, 0 replies; 23+ messages in thread From: Ahmad Fatoum @ 2026-02-06 13:04 UTC (permalink / raw) To: Marco Felsch, Sascha Hauer, BAREBOX On 2/5/26 4:45 PM, Marco Felsch wrote: > Add defines like already done for i.MX8MP and i.MX8MQ. > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > include/mach/imx/iomux-mx8mm.h | 10 ++++++++++ > 1 file changed, 10 insertions(+) > > diff --git a/include/mach/imx/iomux-mx8mm.h b/include/mach/imx/iomux-mx8mm.h > index ee0240f538322021ae37a7d154bfdd26d0628087..693eb67b9602c1c5ca4f8f9b448c2a7886ce1046 100644 > --- a/include/mach/imx/iomux-mx8mm.h > +++ b/include/mach/imx/iomux-mx8mm.h > @@ -691,6 +691,16 @@ enum { > IMX8MM_PAD_UART4_TXD_GPIO5_IO29 = IOMUX_PAD(0x04B8, 0x0250, 5, 0x0000, 0, 0), > }; > > +#define MX8MM_PAD_CTL_DSE1 (0 << 1) > +#define MX8MM_PAD_CTL_DSE2 (2 << 1) > +#define MX8MM_PAD_CTL_DSE4 (1 << 1) > +#define MX8MM_PAD_CTL_DSE6 (3 << 1) > +#define MX8MM_PAD_CTL_FSEL BIT(4) > +#define MX8MM_PAD_CTL_ODE BIT(5) > +#define MX8MM_PAD_CTL_PUE BIT(6) > +#define MX8MM_PAD_CTL_HYS BIT(7) > +#define MX8MM_PAD_CTL_PE BIT(8) > + > static inline void imx8mm_setup_pad(iomux_v3_cfg_t pad) > { > void __iomem *iomux = IOMEM(MX8MM_IOMUXC_BASE_ADDR); > -- 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 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 2/5] lib: hexdump: make use of pr_print 2026-02-05 15:45 [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch 2026-02-05 15:45 ` [PATCH 1/5] ARM: i.MX8MM: add MX8MM_PAD_CTL defines Marco Felsch @ 2026-02-05 15:45 ` Marco Felsch 2026-02-06 13:05 ` Ahmad Fatoum 2026-02-05 15:45 ` [PATCH 3/5] mfd: Add Hexagon EFI driver Marco Felsch ` (3 subsequent siblings) 5 siblings, 1 reply; 23+ messages in thread From: Marco Felsch @ 2026-02-05 15:45 UTC (permalink / raw) To: Sascha Hauer, BAREBOX; +Cc: Marco Felsch The hexdump library was ported from Linux which supports different printk() level. Because the barebox print* facility is different compared to the one from Linux the barebox printk() doesn't support levels. Therefore the level is always set to an empty string. Furthermore all barebox printk() calls aren't recorded by the internal barebox_logbuf because they are mostly used for command prints. Linux on the other hand record each printk() print. Not recording the output can be an issue on systems which don't have a hw-console but a USB-ACM console, because the hexdump call may already occurred before the console was ready. Make use of pr_print() instead to record the output within the barebox_logbuf to be available later on via dmesg. With that the hexdump API changes from a string based loglevel to a integer based loglevel parameter. Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> --- commands/ethlog.c | 4 ++-- drivers/mtd/ubi/attach.c | 2 +- fs/ubifs/debug.c | 4 ++-- include/linux/printk.h | 4 ++-- include/printf.h | 2 +- include/soc/ti/cppi5.h | 2 +- lib/hexdump.c | 13 +++++-------- 7 files changed, 14 insertions(+), 17 deletions(-) diff --git a/commands/ethlog.c b/commands/ethlog.c index 21d88bf1cbfba1b1688fd1101686c0c5c85bb56a..d641fd90ddb82c437348de11f8c3a99b686163ac 100644 --- a/commands/ethlog.c +++ b/commands/ethlog.c @@ -12,7 +12,7 @@ static void ethlog_rx_monitor(struct eth_device *edev, void *packet, int length) { - dev_print_hex_dump(&edev->dev, KERN_DEBUG, "rx data <: ", + dev_print_hex_dump(&edev->dev, MSG_DEBUG, "rx data <: ", DUMP_PREFIX_OFFSET, 16, 1, packet, length, true); printk("\n"); } @@ -20,7 +20,7 @@ static void ethlog_rx_monitor(struct eth_device *edev, void *packet, static void ethlog_tx_monitor(struct eth_device *edev, void *packet, int length) { - dev_print_hex_dump(&edev->dev, KERN_DEBUG, "tx data >: ", + dev_print_hex_dump(&edev->dev, MSG_DEBUG, "tx data >: ", DUMP_PREFIX_OFFSET, 16, 1, packet, length, true); printk("\n"); } diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c index 44fe435e4163f81e4d120d246dab1a028c68ce37..e49ceb8690d8de0a14cb1de88458f3d79827ce56 100644 --- a/drivers/mtd/ubi/attach.c +++ b/drivers/mtd/ubi/attach.c @@ -897,7 +897,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, ubi_dump_vid_hdr(vid_hdr); pr_err("hexdump of PEB %d offset %d, length %d\n", pnum, ubi->leb_start, ubi->leb_size); - ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + ubi_dbg_print_hex_dump(MSG_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, ubi->peb_buf, ubi->leb_size, 1); err = 1; diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index a4cffe84df7118f062d63721982e3e88aaf45d49..2aae47b3b7d8dc36d68b02d125580d22eedf6852 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -224,7 +224,7 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node) /* If the magic is incorrect, just hexdump the first bytes */ if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) { pr_err("Not a node, first %zu bytes:", UBIFS_CH_SZ); - print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 32, 1, + print_hex_dump(MSG_ERR, "", DUMP_PREFIX_OFFSET, 32, 1, (void *)node, UBIFS_CH_SZ, 1); return; } @@ -400,7 +400,7 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node) (int)le16_to_cpu(dn->compr_type)); pr_err("\tdata size %d\n", dlen); pr_err("\tdata:\n"); - print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1, + print_hex_dump(MSG_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1, (void *)&dn->data, dlen, 0); break; } diff --git a/include/linux/printk.h b/include/linux/printk.h index 0d7180f0ebbca1dbe583a1798203e9ac61a64b0a..6c071af5158bcc36ae3582fe20e28a8dae0e6947 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -202,7 +202,7 @@ struct va_format { #if LOGLEVEL >= MSG_DEBUG #define print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ - print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ + print_hex_dump(MSG_DEBUG, prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) #else static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, @@ -221,7 +221,7 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, * @buf: data blob to dump * @len: number of bytes in the @buf * - * Calls print_hex_dump(), with log level of KERN_DEBUG, + * Calls print_hex_dump(), with log level of MSG_DEBUG, * rowsize of 16, groupsize of 1, and ASCII output included. */ #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ diff --git a/include/printf.h b/include/printf.h index 3503b72c9e5eca3e8a81cde4269db62a8080e203..92d6e18728f5baa9ab680962ef26b845c465a0a5 100644 --- a/include/printf.h +++ b/include/printf.h @@ -52,7 +52,7 @@ enum { extern int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, char *linebuf, size_t linebuflen, bool ascii); -extern void dev_print_hex_dump(struct device *dev, const char *level, +extern void dev_print_hex_dump(struct device *dev, int level, const char *prefix_str, int prefix_type, int rowsize, int groupsize, const void *buf, size_t len, bool ascii); diff --git a/include/soc/ti/cppi5.h b/include/soc/ti/cppi5.h index 34e118fff25a4348870f27953bcd32e98dc47860..6331a38a85f0f1528539b779ce1c995ed9186eaa 100644 --- a/include/soc/ti/cppi5.h +++ b/include/soc/ti/cppi5.h @@ -150,7 +150,7 @@ struct cppi5_monolithic_desc_t { static inline void cppi5_desc_dump(void *desc, u32 size) { - print_hex_dump(KERN_ERR, "dump udmap_desc: ", DUMP_PREFIX_NONE, + print_hex_dump(MSG_ERR, "dump udmap_desc: ", DUMP_PREFIX_NONE, 32, 4, desc, size, false); } diff --git a/lib/hexdump.c b/lib/hexdump.c index 940c4eec64e926cbb1ecaa3aa20863c3e672c81e..d98a4e6100d6e8783ad6cbda30845749875484cf 100644 --- a/lib/hexdump.c +++ b/lib/hexdump.c @@ -228,7 +228,7 @@ EXPORT_SYMBOL(hex_dump_to_buffer); /** * print_hex_dump - print a text hex dump to syslog for a binary blob of data - * @level: kernel log level (e.g. KERN_DEBUG) + * @level: barebox log level (e.g. MSG_DEBUG) * @prefix_str: string to prefix each line with; * caller supplies trailing spaces for alignment if desired * @prefix_type: controls whether prefix of an offset, address, or none @@ -257,7 +257,7 @@ EXPORT_SYMBOL(hex_dump_to_buffer); * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode: * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~. */ -void dev_print_hex_dump(struct device *dev, const char *level, +void dev_print_hex_dump(struct device *dev, int level, const char *prefix_str, int prefix_type, int rowsize, int groupsize, const void *buf, size_t len, bool ascii) { @@ -284,16 +284,13 @@ void dev_print_hex_dump(struct device *dev, const char *level, switch (prefix_type) { case DUMP_PREFIX_ADDRESS: - printk("%s%s%s%p: %s\n", level, name, prefix_str, - ptr + i, linebuf); + pr_print(level, "%s%s%p: %s\n", name, prefix_str, ptr + i, linebuf); break; case DUMP_PREFIX_OFFSET: - printk("%s%s%s%.8x: %s\n", level, name, prefix_str, - i, linebuf); + pr_print(level, "%s%s%.8x: %s\n", name, prefix_str, i, linebuf); break; default: - printk("%s%s%s%s\n", level, name, prefix_str, - linebuf); + pr_print(level, "%s%s%s\n", name, prefix_str, linebuf); break; } } -- 2.47.3 ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 2/5] lib: hexdump: make use of pr_print 2026-02-05 15:45 ` [PATCH 2/5] lib: hexdump: make use of pr_print Marco Felsch @ 2026-02-06 13:05 ` Ahmad Fatoum 0 siblings, 0 replies; 23+ messages in thread From: Ahmad Fatoum @ 2026-02-06 13:05 UTC (permalink / raw) To: Marco Felsch, Sascha Hauer, BAREBOX On 2/5/26 4:45 PM, Marco Felsch wrote: > The hexdump library was ported from Linux which supports different > printk() level. Because the barebox print* facility is different > compared to the one from Linux the barebox printk() doesn't support > levels. Therefore the level is always set to an empty string. > > Furthermore all barebox printk() calls aren't recorded by the internal > barebox_logbuf because they are mostly used for command prints. Linux on > the other hand record each printk() print. > > Not recording the output can be an issue on systems which don't have a > hw-console but a USB-ACM console, because the hexdump call may already > occurred before the console was ready. > > Make use of pr_print() instead to record the output within the > barebox_logbuf to be available later on via dmesg. With that the hexdump > API changes from a string based loglevel to a integer based loglevel > parameter. > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > --- > commands/ethlog.c | 4 ++-- > drivers/mtd/ubi/attach.c | 2 +- > fs/ubifs/debug.c | 4 ++-- > include/linux/printk.h | 4 ++-- > include/printf.h | 2 +- > include/soc/ti/cppi5.h | 2 +- > lib/hexdump.c | 13 +++++-------- > 7 files changed, 14 insertions(+), 17 deletions(-) > > diff --git a/commands/ethlog.c b/commands/ethlog.c > index 21d88bf1cbfba1b1688fd1101686c0c5c85bb56a..d641fd90ddb82c437348de11f8c3a99b686163ac 100644 > --- a/commands/ethlog.c > +++ b/commands/ethlog.c > @@ -12,7 +12,7 @@ > static void ethlog_rx_monitor(struct eth_device *edev, void *packet, > int length) > { > - dev_print_hex_dump(&edev->dev, KERN_DEBUG, "rx data <: ", > + dev_print_hex_dump(&edev->dev, MSG_DEBUG, "rx data <: ", > DUMP_PREFIX_OFFSET, 16, 1, packet, length, true); > printk("\n"); > } > @@ -20,7 +20,7 @@ static void ethlog_rx_monitor(struct eth_device *edev, void *packet, > static void ethlog_tx_monitor(struct eth_device *edev, void *packet, > int length) > { > - dev_print_hex_dump(&edev->dev, KERN_DEBUG, "tx data >: ", > + dev_print_hex_dump(&edev->dev, MSG_DEBUG, "tx data >: ", > DUMP_PREFIX_OFFSET, 16, 1, packet, length, true); > printk("\n"); > } > diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c > index 44fe435e4163f81e4d120d246dab1a028c68ce37..e49ceb8690d8de0a14cb1de88458f3d79827ce56 100644 > --- a/drivers/mtd/ubi/attach.c > +++ b/drivers/mtd/ubi/attach.c > @@ -897,7 +897,7 @@ static int check_corruption(struct ubi_device *ubi, struct ubi_vid_hdr *vid_hdr, > ubi_dump_vid_hdr(vid_hdr); > pr_err("hexdump of PEB %d offset %d, length %d\n", > pnum, ubi->leb_start, ubi->leb_size); > - ubi_dbg_print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, > + ubi_dbg_print_hex_dump(MSG_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, > ubi->peb_buf, ubi->leb_size, 1); > err = 1; > > diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c > index a4cffe84df7118f062d63721982e3e88aaf45d49..2aae47b3b7d8dc36d68b02d125580d22eedf6852 100644 > --- a/fs/ubifs/debug.c > +++ b/fs/ubifs/debug.c > @@ -224,7 +224,7 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node) > /* If the magic is incorrect, just hexdump the first bytes */ > if (le32_to_cpu(ch->magic) != UBIFS_NODE_MAGIC) { > pr_err("Not a node, first %zu bytes:", UBIFS_CH_SZ); > - print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 32, 1, > + print_hex_dump(MSG_ERR, "", DUMP_PREFIX_OFFSET, 32, 1, > (void *)node, UBIFS_CH_SZ, 1); > return; > } > @@ -400,7 +400,7 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node) > (int)le16_to_cpu(dn->compr_type)); > pr_err("\tdata size %d\n", dlen); > pr_err("\tdata:\n"); > - print_hex_dump(KERN_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1, > + print_hex_dump(MSG_ERR, "\t", DUMP_PREFIX_OFFSET, 32, 1, > (void *)&dn->data, dlen, 0); > break; > } > diff --git a/include/linux/printk.h b/include/linux/printk.h > index 0d7180f0ebbca1dbe583a1798203e9ac61a64b0a..6c071af5158bcc36ae3582fe20e28a8dae0e6947 100644 > --- a/include/linux/printk.h > +++ b/include/linux/printk.h > @@ -202,7 +202,7 @@ struct va_format { > #if LOGLEVEL >= MSG_DEBUG > #define print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ > groupsize, buf, len, ascii) \ > - print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ > + print_hex_dump(MSG_DEBUG, prefix_str, prefix_type, rowsize, \ > groupsize, buf, len, ascii) > #else > static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, > @@ -221,7 +221,7 @@ static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, > * @buf: data blob to dump > * @len: number of bytes in the @buf > * > - * Calls print_hex_dump(), with log level of KERN_DEBUG, > + * Calls print_hex_dump(), with log level of MSG_DEBUG, > * rowsize of 16, groupsize of 1, and ASCII output included. > */ > #define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ > diff --git a/include/printf.h b/include/printf.h > index 3503b72c9e5eca3e8a81cde4269db62a8080e203..92d6e18728f5baa9ab680962ef26b845c465a0a5 100644 > --- a/include/printf.h > +++ b/include/printf.h > @@ -52,7 +52,7 @@ enum { > extern int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, > int groupsize, char *linebuf, size_t linebuflen, > bool ascii); > -extern void dev_print_hex_dump(struct device *dev, const char *level, > +extern void dev_print_hex_dump(struct device *dev, int level, > const char *prefix_str, int prefix_type, > int rowsize, int groupsize, const void *buf, > size_t len, bool ascii); > diff --git a/include/soc/ti/cppi5.h b/include/soc/ti/cppi5.h > index 34e118fff25a4348870f27953bcd32e98dc47860..6331a38a85f0f1528539b779ce1c995ed9186eaa 100644 > --- a/include/soc/ti/cppi5.h > +++ b/include/soc/ti/cppi5.h > @@ -150,7 +150,7 @@ struct cppi5_monolithic_desc_t { > > static inline void cppi5_desc_dump(void *desc, u32 size) > { > - print_hex_dump(KERN_ERR, "dump udmap_desc: ", DUMP_PREFIX_NONE, > + print_hex_dump(MSG_ERR, "dump udmap_desc: ", DUMP_PREFIX_NONE, > 32, 4, desc, size, false); > } > > diff --git a/lib/hexdump.c b/lib/hexdump.c > index 940c4eec64e926cbb1ecaa3aa20863c3e672c81e..d98a4e6100d6e8783ad6cbda30845749875484cf 100644 > --- a/lib/hexdump.c > +++ b/lib/hexdump.c > @@ -228,7 +228,7 @@ EXPORT_SYMBOL(hex_dump_to_buffer); > > /** > * print_hex_dump - print a text hex dump to syslog for a binary blob of data > - * @level: kernel log level (e.g. KERN_DEBUG) > + * @level: barebox log level (e.g. MSG_DEBUG) > * @prefix_str: string to prefix each line with; > * caller supplies trailing spaces for alignment if desired > * @prefix_type: controls whether prefix of an offset, address, or none > @@ -257,7 +257,7 @@ EXPORT_SYMBOL(hex_dump_to_buffer); > * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode: > * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~. > */ > -void dev_print_hex_dump(struct device *dev, const char *level, > +void dev_print_hex_dump(struct device *dev, int level, > const char *prefix_str, int prefix_type, int rowsize, > int groupsize, const void *buf, size_t len, bool ascii) > { > @@ -284,16 +284,13 @@ void dev_print_hex_dump(struct device *dev, const char *level, > > switch (prefix_type) { > case DUMP_PREFIX_ADDRESS: > - printk("%s%s%s%p: %s\n", level, name, prefix_str, > - ptr + i, linebuf); > + pr_print(level, "%s%s%p: %s\n", name, prefix_str, ptr + i, linebuf); > break; > case DUMP_PREFIX_OFFSET: > - printk("%s%s%s%.8x: %s\n", level, name, prefix_str, > - i, linebuf); > + pr_print(level, "%s%s%.8x: %s\n", name, prefix_str, i, linebuf); > break; > default: > - printk("%s%s%s%s\n", level, name, prefix_str, > - linebuf); > + pr_print(level, "%s%s%s\n", name, prefix_str, linebuf); > break; > } > } > -- 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 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 3/5] mfd: Add Hexagon EFI driver 2026-02-05 15:45 [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch 2026-02-05 15:45 ` [PATCH 1/5] ARM: i.MX8MM: add MX8MM_PAD_CTL defines Marco Felsch 2026-02-05 15:45 ` [PATCH 2/5] lib: hexdump: make use of pr_print Marco Felsch @ 2026-02-05 15:45 ` Marco Felsch 2026-02-06 13:09 ` Ahmad Fatoum 2026-02-09 9:03 ` Sascha Hauer 2026-02-05 15:45 ` [PATCH 4/5] watchdog: Add Hexagon EFI watchdog driver Marco Felsch ` (2 subsequent siblings) 5 siblings, 2 replies; 23+ messages in thread From: Marco Felsch @ 2026-02-05 15:45 UTC (permalink / raw) To: Sascha Hauer, BAREBOX; +Cc: Marco Felsch This adds the EFI core driver to communicate with the system co-processor. Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> --- drivers/mfd/Kconfig | 8 + drivers/mfd/Makefile | 1 + drivers/mfd/hgs-efi.c | 473 ++++++++++++++++++++++++++++++++++++++++++++++++++ include/mfd/hgs-efi.h | 46 +++++ 4 files changed, 528 insertions(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 471f85cd63dad30b39017f694b594b768e463a15..f09e3903bcb50556b1556a84500ae73d91a5a63d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -158,4 +158,12 @@ config MFD_ATMEL_SMC bool select MFD_SYSCON +config MFD_HGS_EFI + tristate "Hexagon Geosystems EFI core driver" + depends on SERIAL_DEV_BUS + select CRC16 + help + Select this to get support for the EFI Co-Processor + device found on several devices in the System1600 platform. + endmenu diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 88480f70640d464e0e12241ec422a63ca860330d..9d27b0bc336a908f1245eb7f1d257a23e271ebd7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o obj-$(CONFIG_MFD_PCA9450) += pca9450.o obj-$(CONFIG_MFD_TPS65219) += tps65219.o +obj-$(CONFIG_MFD_HGS_EFI) += hgs-efi.o diff --git a/drivers/mfd/hgs-efi.c b/drivers/mfd/hgs-efi.c new file mode 100644 index 0000000000000000000000000000000000000000..e548a6b209a6f64cecd8d56edcaa565b0b6d2657 --- /dev/null +++ b/drivers/mfd/hgs-efi.c @@ -0,0 +1,473 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2025 Pengutronix + +/* + * Multifunction core driver for Hexagon Geosystems EFI MCU that is connected + * via dedicated UART port. The communication protocol between both parties is + * called Sensor Protocol (SEP). + * + * Based on drivers/mfd/rave-sp.c + */ + +#include <asm/unaligned.h> +#include <common.h> +#include <init.h> +#include <of_device.h> +#include <mfd/hgs-efi.h> +#include <linux/crc16.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <mfd/hgs-efi.h> + +#define HGS_EFI_SEP_ASCII_SYNCBYTE 'S' +#define HGS_EFI_SEP_ASCII_MSG_TYPE_CMD 'C' +#define HGS_EFI_SEP_ASCII_MSG_TYPE_EVENT 'E' +#define HGS_EFI_SEP_ASCII_MSG_TYPE_REPLY 'R' +#define HGS_EFI_SEP_ASCII_DELIM ',' +#define HGS_EFI_SEP_ASCII_HDR_END ':' + +/* Non addressed ascii header format */ +struct hgs_efi_sep_ascii_hdr { + u8 syncbyte; + u8 msg_type; + u8 msg_id[5]; /* u16 dec number */ + u8 delim; + u8 crc16[4]; /* u16 hex number */ + u8 hdr_end; +} __packed; + +#define HGS_EFI_SEP_RX_BUFFER_SIZE 64 +#define HGS_EFI_SEP_FRAME_PREAMBLE_SZ 2 +#define HGS_EFI_SEP_FRAME_POSTAMBLE_SZ 2 + +enum hgs_efi_sep_deframer_state { + HGS_EFI_SEP_EXPECT_SOF, + HGS_EFI_SEP_EXPECT_DATA, +}; + +/** + * struct hgs_efi_deframer - Device protocol deframer + * + * @state: Current state of the deframer + * @data: Buffer used to collect deframed data + * @length: Number of bytes de-framed so far + */ +struct hgs_efi_deframer { + enum hgs_efi_sep_deframer_state state; + unsigned char data[HGS_EFI_SEP_RX_BUFFER_SIZE]; + size_t length; +}; + +/** + * struct hgs_efi_reply - Reply as per SEP + * + * @length: Expected reply length + * @data: Buffer to store reply payload in + * @msg_id: Expected SEP msg-id + * @received: Successful reply reception + */ +struct hgs_efi_reply { + size_t length; + void *data; + u16 msg_id; + bool received; +}; + +struct hgs_efi_sep_coder { + int (*encode)(struct hgs_efi *efi, struct hgs_sep_cmd *cmd, u8 *buf); + int (*process_frame)(struct hgs_efi *efi, void *buf, size_t size); + unsigned int sep_header_hdrsize; + char sep_sof_char; +}; + +struct hgs_efi { + struct device dev; + struct serdev_device *serdev; + const struct hgs_efi_sep_coder *coder; + struct hgs_efi_deframer deframer; + struct hgs_efi_reply *reply; +}; + +static void hgs_efi_write(struct hgs_efi *efi, const u8 *data, size_t data_size) +{ + print_hex_dump_bytes("hgs-efi tx: ", DUMP_PREFIX_NONE, data, data_size); + + /* timeout is ignored, instead polling_window is used */ + serdev_device_write(efi->serdev, data, data_size, SECOND); +} + +int hgs_efi_exec(struct hgs_efi *efi, struct hgs_sep_cmd *cmd) +{ + struct device *dev = efi->serdev->dev; + struct hgs_efi_reply reply = { + .msg_id = cmd->msg_id, + .data = cmd->reply_data, + .length = cmd->reply_data_size, + .received = false, + }; + unsigned int max_msg_len; + u8 *msg, *p; + int ret; + + switch (cmd->type) { + case HGS_SEP_MSG_TYPE_COMMAND: + case HGS_SEP_MSG_TYPE_EVENT: + break; + case HGS_SEP_MSG_TYPE_REPLY: + dev_warn(dev, "MCU initiated communication is not supported yet!\n"); + return -EINVAL; + default: + dev_warn(dev, "Unknown EFI msg-type %#x\n", cmd->type); + return -EINVAL; + } + + max_msg_len = HGS_EFI_SEP_FRAME_PREAMBLE_SZ + + HGS_EFI_SEP_FRAME_POSTAMBLE_SZ + + efi->coder->sep_header_hdrsize + cmd->payload_size; + msg = p = xzalloc(max_msg_len); + if (!msg) { + dev_err(dev, "No memory\n"); + return -ENOMEM; + } + + /* MCU serial flush preamble */ + *p++ = '\r'; + *p++ = '\n'; + + ret = efi->coder->encode(efi, cmd, p); + if (ret < 0) { + free(msg); + return ret; + } + + p += ret; + + /* SEP postamble */ + *p++ = '\r'; + *p++ = '\n'; + + efi->reply = &reply; + hgs_efi_write(efi, msg, p - msg); + + free(msg); + + if (cmd->type == HGS_SEP_MSG_TYPE_EVENT) { + efi->reply = NULL; + return 0; + } + + /* + * is_timeout will implicitly poll serdev via poller + * infrastructure + */ + ret = wait_on_timeout(SECOND, reply.received); + if (ret) + dev_err(dev, "Command timeout\n"); + + efi->reply = NULL; + + return ret; +} + +#define HGS_SEP_DOUBLE_QUOTE_SUB_VAL 0x1a + +char *hgs_efi_extract_str_response(u8 *buf) +{ + unsigned char *start; + unsigned char *end; + unsigned char *p; + size_t i; + + if (!buf || buf[0] != '"') { + pr_warn("hgs-efi: No start \" char found in string response\n"); + return ERR_PTR(-EINVAL); + } + + start = &buf[1]; + end = strrchr(start, '"'); + if (!end) { + pr_warn("hgs-efi: No end \" char found in string response\n"); + return ERR_PTR(-EINVAL); + } + *end = '\0'; + + /* + * Last step, check for substition val in string reply + * and re-substitute it. + */ + p = start; + for (i = 0; i < strlen(start); i++) + if (*p == HGS_SEP_DOUBLE_QUOTE_SUB_VAL) + *p = '"'; + + return start; +} + +static int hgs_sep_ascii_encode(struct hgs_efi *efi, struct hgs_sep_cmd *cmd, + u8 *buf) +{ + struct device *dev = efi->serdev->dev; + size_t hdr_len; + char msg_type; + char *hdr; + + switch (cmd->type) { + case HGS_SEP_MSG_TYPE_COMMAND: + msg_type = 'C'; + break; + case HGS_SEP_MSG_TYPE_EVENT: + msg_type = 'E'; + break; + default: + /* Should never happen */ + return -EINVAL; + } + + /* + * The ASCII coder doesn't care about the CRC, also the CRC handling + * has a few flaws. Therefore skip it for now. + */ + hdr = xasprintf("S%c%u:", msg_type, cmd->msg_id); + if (!hdr) { + dev_err(dev, "No memory\n"); + return -ENOMEM; + } + + /* Now copy the header and the payload to the buffer */ + hdr_len = strlen(hdr); + memcpy(buf, hdr, hdr_len); + memcpy(buf + hdr_len, cmd->payload, cmd->payload_size); + + free(hdr); + + return hdr_len + cmd->payload_size; +} + +static int +hgs_sep_process_ascii_frame(struct hgs_efi *efi, void *_buf, size_t size) +{ + struct device *dev = efi->serdev->dev; + unsigned char *payload; + unsigned int copy_bytes; + unsigned int msgid; + size_t payload_len; + u8 *buf = _buf; + size_t hdrlen; + char *p; + int ret; + + /* + * Non addressing ASCII format: + * S[MsgType][MsgID](,[CRC]):[Payload] + */ + if (buf[1] != HGS_EFI_SEP_ASCII_MSG_TYPE_REPLY) { + dev_warn(dev, "Invalid msg-type %c(%#x)\n", *buf, *buf); + return -EINVAL; + } + + /* Split header from payload first for the following str-ops on buf */ + payload = strstr(buf, ":"); + if (!payload) { + dev_warn(dev, "Failed to find header delim\n"); + return -EINVAL; + } + + hdrlen = payload - buf; + if (hdrlen > sizeof(struct hgs_efi_sep_ascii_hdr)) { + dev_warn(dev, "Invalid header len detected\n"); + return -EINVAL; + } + + *payload = 0; + payload++; + + /* + * Albeit the CRC is optional and the calc as a few flaws the coder may + * has added it. Skip the CRC check but do the msg-id check. + */ + p = strstr(buf, ","); + if (p) + *p = 0; + + ret = kstrtouint(&buf[2], 10, &msgid); + if (ret) { + dev_warn(dev, "Failed to parse msgid, ret:%d\n", ret); + return -EINVAL; + } + + if (msgid != efi->reply->msg_id) { + dev_warn(dev, "Wrong msg-id received, ignore frame (%u != %u)\n", + msgid, efi->reply->msg_id); + return -EINVAL; + } + + payload_len = size - hdrlen; + copy_bytes = payload_len; + if (payload_len > efi->reply->length) { + dev_warn(dev, "Reply buffer to small, dropping remaining %zu bytes\n", + payload_len - efi->reply->length); + copy_bytes = efi->reply->length; + } + + memcpy(efi->reply->data, payload, copy_bytes); + + return 0; +} + +static const struct hgs_efi_sep_coder hgs_efi_ascii_coder = { + .encode = hgs_sep_ascii_encode, + .process_frame = hgs_sep_process_ascii_frame, + .sep_header_hdrsize = sizeof(struct hgs_efi_sep_ascii_hdr), + .sep_sof_char = HGS_EFI_SEP_ASCII_SYNCBYTE, +}; + +static bool hgs_efi_eof_received(struct hgs_efi_deframer *deframer) +{ + const char eof_seq[] = { '\r', '\n' }; + + if (deframer->length <= 2) + return false; + + if (memcmp(&deframer->data[deframer->length - 2], eof_seq, 2)) + return false; + + return true; +} + +static void hgs_efi_receive_frame(struct hgs_efi *efi, + struct hgs_efi_deframer *deframer) +{ + int ret; + + if (deframer->length < efi->coder->sep_header_hdrsize) { + dev_warn(efi->serdev->dev, "Bad frame: Too short\n"); + return; + } + + print_hex_dump_bytes("hgs-efi rx-frame: ", DUMP_PREFIX_NONE, + deframer->data, deframer->length); + + ret = efi->coder->process_frame(efi, deframer->data, + deframer->length - HGS_EFI_SEP_FRAME_PREAMBLE_SZ); + if (!ret) + efi->reply->received = true; +} + +static int hgs_efi_receive_buf(struct serdev_device *serdev, + const unsigned char *buf, size_t size) +{ + struct device *dev = serdev->dev; + struct hgs_efi *efi = dev->priv; + struct hgs_efi_deframer *deframer = &efi->deframer; + const unsigned char *src = buf; + const unsigned char *end = buf + size; + + print_hex_dump_bytes("hgs-efi rx-bytes: ", DUMP_PREFIX_NONE, buf, size); + + while (src < end) { + const unsigned char byte = *src++; + + switch (deframer->state) { + case HGS_EFI_SEP_EXPECT_SOF: + if (byte == efi->coder->sep_sof_char) + deframer->state = HGS_EFI_SEP_EXPECT_DATA; + deframer->data[deframer->length++] = byte; + break; + case HGS_EFI_SEP_EXPECT_DATA: + if (deframer->length >= sizeof(deframer->data)) { + dev_warn(dev, "Bad frame: Too long\n"); + goto frame_reset; + } + + deframer->data[deframer->length++] = byte; + if (hgs_efi_eof_received(deframer)) { + hgs_efi_receive_frame(efi, deframer); + goto frame_reset; + } + } + } + + /* + * All bytes processed but no EOF detected yet which because the serdev + * poller may called us to early. Keep the deframer state to continue + * the work where we finished. + */ + return size; + +frame_reset: + memset(deframer->data, 0, deframer->length); + deframer->length = 0; + deframer->state = HGS_EFI_SEP_EXPECT_SOF; + + return src - buf; +} + +static int hgs_efi_register_dev(struct hgs_efi *efi) +{ + struct device *dev = &efi->dev; + + dev->parent = efi->serdev->dev; + dev_set_name(dev, "%s", "efi"); + dev->id = DEVICE_ID_SINGLE; + + return register_device(dev); +} + +static int hgs_efi_probe(struct device *dev) +{ + struct serdev_device *serdev = to_serdev_device(dev->parent); + struct hgs_efi *efi; + u32 baud; + int ret; + + if (of_property_read_u32(dev->of_node, "current-speed", &baud)) { + dev_err(dev, + "'current-speed' is not specified in device node\n"); + return -EINVAL; + } + + efi = xzalloc(sizeof(*efi)); + if (!efi) + return -ENOMEM; + + efi->coder = of_device_get_match_data(dev); + if (!efi->coder) { + free(efi); + return -ENODEV; + } + + efi->serdev = serdev; + + dev->priv = efi; + serdev->dev = dev; + serdev->receive_buf = hgs_efi_receive_buf; + serdev->polling_interval = 200 * MSECOND; + serdev->polling_window = 10 * MSECOND; + + ret = serdev_device_open(serdev); + if (ret) + return ret; + + serdev_device_set_baudrate(serdev, baud); + + ret = hgs_efi_register_dev(efi); + if (ret) { + dev_err(dev, "Failed to register EFI device\n"); + return ret; + }; + + return of_platform_populate(dev->of_node, NULL, dev); +} + +static const struct of_device_id __maybe_unused hgs_efi_dt_ids[] = { + { .compatible = "hgs,efi-gs05", .data = &hgs_efi_ascii_coder }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, lgs_efi_dt_ids); + +static struct driver hgs_efi_drv = { + .name = "hgs-efi", + .probe = hgs_efi_probe, + .of_compatible = DRV_OF_COMPAT(hgs_efi_dt_ids), +}; +console_platform_driver(hgs_efi_drv); diff --git a/include/mfd/hgs-efi.h b/include/mfd/hgs-efi.h new file mode 100644 index 0000000000000000000000000000000000000000..8a848a0c7655ce1347f92838c1bdd1865c896475 --- /dev/null +++ b/include/mfd/hgs-efi.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2025 Pengutronix */ + +#ifndef HGS_EFI_H +#define HGS_EFI_H + +#include <errno.h> +#include <linux/types.h> + +enum hgs_sep_msg_type { + HGS_SEP_MSG_TYPE_COMMAND, + HGS_SEP_MSG_TYPE_EVENT, + HGS_SEP_MSG_TYPE_REPLY, +}; + +struct hgs_sep_cmd { + enum hgs_sep_msg_type type; + uint16_t msg_id; + void *payload; + size_t payload_size; + void *reply_data; + size_t reply_data_size; +}; + +struct hgs_efi; + +#if defined(CONFIG_MFD_HGS_EFI) + +int hgs_efi_exec(struct hgs_efi *efi, struct hgs_sep_cmd *cmd); +char *hgs_efi_extract_str_response(u8 *buf); + +#else + +static inline int hgs_efi_exec(struct hgs_efi *efi, struct hgs_sep_cmd *cmd) +{ + return -ENOTSUPP; +} + +static inline char *hgs_efi_extract_str_response(u8 *buf) +{ + return ERR_PTR(-ENOTSUPP); +} + +#endif /* CONFIG_MFD_HGS_EFI */ + +#endif /* HGS_EFI_H */ -- 2.47.3 ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 3/5] mfd: Add Hexagon EFI driver 2026-02-05 15:45 ` [PATCH 3/5] mfd: Add Hexagon EFI driver Marco Felsch @ 2026-02-06 13:09 ` Ahmad Fatoum 2026-02-06 15:52 ` Marco Felsch 2026-02-09 9:03 ` Sascha Hauer 1 sibling, 1 reply; 23+ messages in thread From: Ahmad Fatoum @ 2026-02-06 13:09 UTC (permalink / raw) To: Marco Felsch, Sascha Hauer, BAREBOX Hi, On 2/5/26 4:45 PM, Marco Felsch wrote: > This adds the EFI core driver to communicate with the system > co-processor. > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> Acked-by: Ahmad Fatoum <a.fatoum@pengutronix.de> but see below for some nits should there be a v2. > + max_msg_len = HGS_EFI_SEP_FRAME_PREAMBLE_SZ + > + HGS_EFI_SEP_FRAME_POSTAMBLE_SZ + > + efi->coder->sep_header_hdrsize + cmd->payload_size; > + msg = p = xzalloc(max_msg_len); > + if (!msg) { xzalloc never fails. > + dev_err(dev, "No memory\n"); dev_err allocates memory, so this wouldn't work anyway. > + /* Split header from payload first for the following str-ops on buf */ > + payload = strstr(buf, ":"); Nitpick: strchr() > + if (!payload) { > + dev_warn(dev, "Failed to find header delim\n"); > + return -EINVAL; > + } > + > + hdrlen = payload - buf; > + if (hdrlen > sizeof(struct hgs_efi_sep_ascii_hdr)) { > + dev_warn(dev, "Invalid header len detected\n"); > + return -EINVAL; > + } > + > + *payload = 0; > + payload++; > + > + /* > + * Albeit the CRC is optional and the calc as a few flaws the coder may > + * has added it. Skip the CRC check but do the msg-id check. > + */ > + p = strstr(buf, ","); Nitpick: strchr() Cheers, Ahmad -- 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 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 3/5] mfd: Add Hexagon EFI driver 2026-02-06 13:09 ` Ahmad Fatoum @ 2026-02-06 15:52 ` Marco Felsch 0 siblings, 0 replies; 23+ messages in thread From: Marco Felsch @ 2026-02-06 15:52 UTC (permalink / raw) To: Ahmad Fatoum; +Cc: BAREBOX Hi Ahmad, On 26-02-06, Ahmad Fatoum wrote: > Hi, > > On 2/5/26 4:45 PM, Marco Felsch wrote: > > This adds the EFI core driver to communicate with the system > > co-processor. > > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> > > Acked-by: Ahmad Fatoum <a.fatoum@pengutronix.de> > > but see below for some nits should there be a v2. > > > + max_msg_len = HGS_EFI_SEP_FRAME_PREAMBLE_SZ + > > + HGS_EFI_SEP_FRAME_POSTAMBLE_SZ + > > + efi->coder->sep_header_hdrsize + cmd->payload_size; > > + msg = p = xzalloc(max_msg_len); > > + if (!msg) { > > xzalloc never fails. > > > + dev_err(dev, "No memory\n"); > > dev_err allocates memory, so this wouldn't work anyway. Dropped the check and the print, also for the probe() function. > > + /* Split header from payload first for the following str-ops on buf */ > > + payload = strstr(buf, ":"); > > Nitpick: strchr() > > > + if (!payload) { > > + dev_warn(dev, "Failed to find header delim\n"); > > + return -EINVAL; > > + } > > + > > + hdrlen = payload - buf; > > + if (hdrlen > sizeof(struct hgs_efi_sep_ascii_hdr)) { > > + dev_warn(dev, "Invalid header len detected\n"); > > + return -EINVAL; > > + } > > + > > + *payload = 0; > > + payload++; > > + > > + /* > > + * Albeit the CRC is optional and the calc as a few flaws the coder may > > + * has added it. Skip the CRC check but do the msg-id check. > > + */ > > + p = strstr(buf, ","); > > Nitpick: strchr() I applied all your findings, thanks! Regards, Marco > > > Cheers, > Ahmad > > -- > 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 | > > -- #gernperDu #CallMeByMyFirstName Pengutronix e.K. | | Steuerwalder Str. 21 | https://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 3/5] mfd: Add Hexagon EFI driver 2026-02-05 15:45 ` [PATCH 3/5] mfd: Add Hexagon EFI driver Marco Felsch 2026-02-06 13:09 ` Ahmad Fatoum @ 2026-02-09 9:03 ` Sascha Hauer 2026-02-09 11:13 ` Marco Felsch 1 sibling, 1 reply; 23+ messages in thread From: Sascha Hauer @ 2026-02-09 9:03 UTC (permalink / raw) To: Marco Felsch; +Cc: BAREBOX On Thu, Feb 05, 2026 at 04:45:05PM +0100, Marco Felsch wrote: > This adds the EFI core driver to communicate with the system > co-processor. This EFI doesn't have anything to do with the Extensible Firmware Interface, right? Could you add some note what it means to commit message, Kconfig and to the description in hgs-efi.c to avoid confusion? > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> > --- > drivers/mfd/Kconfig | 8 + > drivers/mfd/Makefile | 1 + > drivers/mfd/hgs-efi.c | 473 ++++++++++++++++++++++++++++++++++++++++++++++++++ > include/mfd/hgs-efi.h | 46 +++++ > 4 files changed, 528 insertions(+) > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig > index 471f85cd63dad30b39017f694b594b768e463a15..f09e3903bcb50556b1556a84500ae73d91a5a63d 100644 > --- a/drivers/mfd/Kconfig > +++ b/drivers/mfd/Kconfig > @@ -158,4 +158,12 @@ config MFD_ATMEL_SMC > bool > select MFD_SYSCON > > +config MFD_HGS_EFI > + tristate "Hexagon Geosystems EFI core driver" > + depends on SERIAL_DEV_BUS > + select CRC16 > + help > + Select this to get support for the EFI Co-Processor > + device found on several devices in the System1600 platform. > + > endmenu > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile > index 88480f70640d464e0e12241ec422a63ca860330d..9d27b0bc336a908f1245eb7f1d257a23e271ebd7 100644 > --- a/drivers/mfd/Makefile > +++ b/drivers/mfd/Makefile > @@ -27,3 +27,4 @@ obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o > obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o > obj-$(CONFIG_MFD_PCA9450) += pca9450.o > obj-$(CONFIG_MFD_TPS65219) += tps65219.o > +obj-$(CONFIG_MFD_HGS_EFI) += hgs-efi.o > diff --git a/drivers/mfd/hgs-efi.c b/drivers/mfd/hgs-efi.c > new file mode 100644 > index 0000000000000000000000000000000000000000..e548a6b209a6f64cecd8d56edcaa565b0b6d2657 > --- /dev/null > +++ b/drivers/mfd/hgs-efi.c > @@ -0,0 +1,473 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +// SPDX-FileCopyrightText: 2025 Pengutronix > + > +/* > + * Multifunction core driver for Hexagon Geosystems EFI MCU that is connected > + * via dedicated UART port. The communication protocol between both parties is > + * called Sensor Protocol (SEP). > + * > + * Based on drivers/mfd/rave-sp.c > + */ > + > +#include <asm/unaligned.h> > +#include <common.h> > +#include <init.h> > +#include <of_device.h> > +#include <mfd/hgs-efi.h> > +#include <linux/crc16.h> > +#include <linux/ctype.h> > +#include <linux/string.h> > +#include <mfd/hgs-efi.h> > + > +#define HGS_EFI_SEP_ASCII_SYNCBYTE 'S' > +#define HGS_EFI_SEP_ASCII_MSG_TYPE_CMD 'C' > +#define HGS_EFI_SEP_ASCII_MSG_TYPE_EVENT 'E' > +#define HGS_EFI_SEP_ASCII_MSG_TYPE_REPLY 'R' > +#define HGS_EFI_SEP_ASCII_DELIM ',' > +#define HGS_EFI_SEP_ASCII_HDR_END ':' > + > +/* Non addressed ascii header format */ > +struct hgs_efi_sep_ascii_hdr { > + u8 syncbyte; > + u8 msg_type; > + u8 msg_id[5]; /* u16 dec number */ > + u8 delim; > + u8 crc16[4]; /* u16 hex number */ > + u8 hdr_end; > +} __packed; > + > +#define HGS_EFI_SEP_RX_BUFFER_SIZE 64 > +#define HGS_EFI_SEP_FRAME_PREAMBLE_SZ 2 > +#define HGS_EFI_SEP_FRAME_POSTAMBLE_SZ 2 > + > +enum hgs_efi_sep_deframer_state { > + HGS_EFI_SEP_EXPECT_SOF, > + HGS_EFI_SEP_EXPECT_DATA, > +}; > + > +/** > + * struct hgs_efi_deframer - Device protocol deframer > + * > + * @state: Current state of the deframer > + * @data: Buffer used to collect deframed data > + * @length: Number of bytes de-framed so far > + */ > +struct hgs_efi_deframer { > + enum hgs_efi_sep_deframer_state state; > + unsigned char data[HGS_EFI_SEP_RX_BUFFER_SIZE]; > + size_t length; > +}; > + > +/** > + * struct hgs_efi_reply - Reply as per SEP > + * > + * @length: Expected reply length > + * @data: Buffer to store reply payload in > + * @msg_id: Expected SEP msg-id > + * @received: Successful reply reception > + */ > +struct hgs_efi_reply { > + size_t length; > + void *data; > + u16 msg_id; > + bool received; > +}; > + > +struct hgs_efi_sep_coder { > + int (*encode)(struct hgs_efi *efi, struct hgs_sep_cmd *cmd, u8 *buf); > + int (*process_frame)(struct hgs_efi *efi, void *buf, size_t size); > + unsigned int sep_header_hdrsize; > + char sep_sof_char; > +}; > + > +struct hgs_efi { > + struct device dev; > + struct serdev_device *serdev; > + const struct hgs_efi_sep_coder *coder; > + struct hgs_efi_deframer deframer; > + struct hgs_efi_reply *reply; > +}; > + > +static void hgs_efi_write(struct hgs_efi *efi, const u8 *data, size_t data_size) > +{ > + print_hex_dump_bytes("hgs-efi tx: ", DUMP_PREFIX_NONE, data, data_size); > + > + /* timeout is ignored, instead polling_window is used */ > + serdev_device_write(efi->serdev, data, data_size, SECOND); > +} > + > +int hgs_efi_exec(struct hgs_efi *efi, struct hgs_sep_cmd *cmd) > +{ > + struct device *dev = efi->serdev->dev; > + struct hgs_efi_reply reply = { > + .msg_id = cmd->msg_id, > + .data = cmd->reply_data, > + .length = cmd->reply_data_size, > + .received = false, > + }; > + unsigned int max_msg_len; > + u8 *msg, *p; > + int ret; > + > + switch (cmd->type) { > + case HGS_SEP_MSG_TYPE_COMMAND: > + case HGS_SEP_MSG_TYPE_EVENT: > + break; > + case HGS_SEP_MSG_TYPE_REPLY: > + dev_warn(dev, "MCU initiated communication is not supported yet!\n"); > + return -EINVAL; > + default: > + dev_warn(dev, "Unknown EFI msg-type %#x\n", cmd->type); > + return -EINVAL; > + } > + > + max_msg_len = HGS_EFI_SEP_FRAME_PREAMBLE_SZ + > + HGS_EFI_SEP_FRAME_POSTAMBLE_SZ + > + efi->coder->sep_header_hdrsize + cmd->payload_size; > + msg = p = xzalloc(max_msg_len); > + if (!msg) { > + dev_err(dev, "No memory\n"); > + return -ENOMEM; > + } > + > + /* MCU serial flush preamble */ > + *p++ = '\r'; > + *p++ = '\n'; > + > + ret = efi->coder->encode(efi, cmd, p); > + if (ret < 0) { > + free(msg); > + return ret; > + } > + > + p += ret; > + > + /* SEP postamble */ > + *p++ = '\r'; > + *p++ = '\n'; > + > + efi->reply = &reply; > + hgs_efi_write(efi, msg, p - msg); > + > + free(msg); > + > + if (cmd->type == HGS_SEP_MSG_TYPE_EVENT) { > + efi->reply = NULL; > + return 0; > + } > + > + /* > + * is_timeout will implicitly poll serdev via poller > + * infrastructure > + */ > + ret = wait_on_timeout(SECOND, reply.received); > + if (ret) > + dev_err(dev, "Command timeout\n"); > + > + efi->reply = NULL; > + > + return ret; > +} > + > +#define HGS_SEP_DOUBLE_QUOTE_SUB_VAL 0x1a > + > +char *hgs_efi_extract_str_response(u8 *buf) > +{ > + unsigned char *start; > + unsigned char *end; > + unsigned char *p; > + size_t i; > + > + if (!buf || buf[0] != '"') { > + pr_warn("hgs-efi: No start \" char found in string response\n"); Add above the includes: #define pr_fmt(fmt) "hgs-efi: " fmt And drp the prefix here. > + return ERR_PTR(-EINVAL); > + } > + > + start = &buf[1]; > + end = strrchr(start, '"'); > + if (!end) { > + pr_warn("hgs-efi: No end \" char found in string response\n"); > + return ERR_PTR(-EINVAL); > + } > + *end = '\0'; > + > + /* > + * Last step, check for substition val in string reply > + * and re-substitute it. > + */ > + p = start; > + for (i = 0; i < strlen(start); i++) > + if (*p == HGS_SEP_DOUBLE_QUOTE_SUB_VAL) > + *p = '"'; > + > + return start; > +} > + > +static int hgs_sep_ascii_encode(struct hgs_efi *efi, struct hgs_sep_cmd *cmd, > + u8 *buf) > +{ > + struct device *dev = efi->serdev->dev; > + size_t hdr_len; > + char msg_type; > + char *hdr; > + > + switch (cmd->type) { > + case HGS_SEP_MSG_TYPE_COMMAND: > + msg_type = 'C'; > + break; > + case HGS_SEP_MSG_TYPE_EVENT: > + msg_type = 'E'; > + break; > + default: > + /* Should never happen */ > + return -EINVAL; > + } > + > + /* > + * The ASCII coder doesn't care about the CRC, also the CRC handling > + * has a few flaws. Therefore skip it for now. > + */ > + hdr = xasprintf("S%c%u:", msg_type, cmd->msg_id); xasprintf also doesn't fail. > + if (!hdr) { > + dev_err(dev, "No memory\n"); > + return -ENOMEM; > + } > + > + /* Now copy the header and the payload to the buffer */ > + hdr_len = strlen(hdr); > + memcpy(buf, hdr, hdr_len); You could simplify the above by doing: hdr_len = sprintf(buf, "S%c%u:", msg_type, cmd->msg_id); > + memcpy(buf + hdr_len, cmd->payload, cmd->payload_size); > + > + free(hdr); > + > + return hdr_len + cmd->payload_size; > +} > + > +static int > +hgs_sep_process_ascii_frame(struct hgs_efi *efi, void *_buf, size_t size) > +{ > + struct device *dev = efi->serdev->dev; > + unsigned char *payload; > + unsigned int copy_bytes; > + unsigned int msgid; > + size_t payload_len; > + u8 *buf = _buf; > + size_t hdrlen; > + char *p; > + int ret; > + > + /* > + * Non addressing ASCII format: > + * S[MsgType][MsgID](,[CRC]):[Payload] > + */ > + if (buf[1] != HGS_EFI_SEP_ASCII_MSG_TYPE_REPLY) { check buf[0] != 0 before looking at buf[1]? > + dev_warn(dev, "Invalid msg-type %c(%#x)\n", *buf, *buf); > + return -EINVAL; > + } > + > + /* Split header from payload first for the following str-ops on buf */ > + payload = strstr(buf, ":"); > + if (!payload) { > + dev_warn(dev, "Failed to find header delim\n"); > + return -EINVAL; > + } > + > + hdrlen = payload - buf; > + if (hdrlen > sizeof(struct hgs_efi_sep_ascii_hdr)) { > + dev_warn(dev, "Invalid header len detected\n"); > + return -EINVAL; > + } > + > + *payload = 0; > + payload++; > + > + /* > + * Albeit the CRC is optional and the calc as a few flaws the coder may s/as/has/ > + * has added it. Skip the CRC check but do the msg-id check. > + */ > + p = strstr(buf, ","); > + if (p) > + *p = 0; > + > + ret = kstrtouint(&buf[2], 10, &msgid); > + if (ret) { > + dev_warn(dev, "Failed to parse msgid, ret:%d\n", ret); > + return -EINVAL; > + } > + > + if (msgid != efi->reply->msg_id) { > + dev_warn(dev, "Wrong msg-id received, ignore frame (%u != %u)\n", > + msgid, efi->reply->msg_id); > + return -EINVAL; > + } > + > + payload_len = size - hdrlen; > + copy_bytes = payload_len; > + if (payload_len > efi->reply->length) { > + dev_warn(dev, "Reply buffer to small, dropping remaining %zu bytes\n", > + payload_len - efi->reply->length); > + copy_bytes = efi->reply->length; > + } > + > + memcpy(efi->reply->data, payload, copy_bytes); > + > + return 0; > +} > + > +static const struct hgs_efi_sep_coder hgs_efi_ascii_coder = { > + .encode = hgs_sep_ascii_encode, > + .process_frame = hgs_sep_process_ascii_frame, > + .sep_header_hdrsize = sizeof(struct hgs_efi_sep_ascii_hdr), > + .sep_sof_char = HGS_EFI_SEP_ASCII_SYNCBYTE, > +}; > + > +static bool hgs_efi_eof_received(struct hgs_efi_deframer *deframer) > +{ > + const char eof_seq[] = { '\r', '\n' }; > + > + if (deframer->length <= 2) > + return false; > + > + if (memcmp(&deframer->data[deframer->length - 2], eof_seq, 2)) > + return false; > + > + return true; > +} > + > +static void hgs_efi_receive_frame(struct hgs_efi *efi, > + struct hgs_efi_deframer *deframer) > +{ > + int ret; > + > + if (deframer->length < efi->coder->sep_header_hdrsize) { > + dev_warn(efi->serdev->dev, "Bad frame: Too short\n"); > + return; > + } > + > + print_hex_dump_bytes("hgs-efi rx-frame: ", DUMP_PREFIX_NONE, > + deframer->data, deframer->length); > + > + ret = efi->coder->process_frame(efi, deframer->data, > + deframer->length - HGS_EFI_SEP_FRAME_PREAMBLE_SZ); > + if (!ret) > + efi->reply->received = true; > +} > + > +static int hgs_efi_receive_buf(struct serdev_device *serdev, > + const unsigned char *buf, size_t size) > +{ > + struct device *dev = serdev->dev; > + struct hgs_efi *efi = dev->priv; > + struct hgs_efi_deframer *deframer = &efi->deframer; > + const unsigned char *src = buf; > + const unsigned char *end = buf + size; > + > + print_hex_dump_bytes("hgs-efi rx-bytes: ", DUMP_PREFIX_NONE, buf, size); > + > + while (src < end) { > + const unsigned char byte = *src++; > + > + switch (deframer->state) { > + case HGS_EFI_SEP_EXPECT_SOF: > + if (byte == efi->coder->sep_sof_char) > + deframer->state = HGS_EFI_SEP_EXPECT_DATA; > + deframer->data[deframer->length++] = byte; > + break; > + case HGS_EFI_SEP_EXPECT_DATA: > + if (deframer->length >= sizeof(deframer->data)) { > + dev_warn(dev, "Bad frame: Too long\n"); > + goto frame_reset; > + } > + > + deframer->data[deframer->length++] = byte; > + if (hgs_efi_eof_received(deframer)) { > + hgs_efi_receive_frame(efi, deframer); > + goto frame_reset; > + } > + } > + } > + > + /* > + * All bytes processed but no EOF detected yet which because the serdev s/which// > + * poller may called us to early. Keep the deframer state to continue > + * the work where we finished. > + */ > + return size; > + > +frame_reset: > + memset(deframer->data, 0, deframer->length); > + deframer->length = 0; > + deframer->state = HGS_EFI_SEP_EXPECT_SOF; > + > + return src - buf; > +} > + > +static int hgs_efi_register_dev(struct hgs_efi *efi) > +{ > + struct device *dev = &efi->dev; > + > + dev->parent = efi->serdev->dev; > + dev_set_name(dev, "%s", "efi"); dev_set_name(dev, "efi"); > + dev->id = DEVICE_ID_SINGLE; > + > + return register_device(dev); > +} > + > +static int hgs_efi_probe(struct device *dev) > +{ > + struct serdev_device *serdev = to_serdev_device(dev->parent); > + struct hgs_efi *efi; > + u32 baud; > + int ret; > + > + if (of_property_read_u32(dev->of_node, "current-speed", &baud)) { > + dev_err(dev, > + "'current-speed' is not specified in device node\n"); > + return -EINVAL; > + } > + > + efi = xzalloc(sizeof(*efi)); > + if (!efi) > + return -ENOMEM; > + > + efi->coder = of_device_get_match_data(dev); > + if (!efi->coder) { > + free(efi); > + return -ENODEV; > + } > + > + efi->serdev = serdev; > + > + dev->priv = efi; > + serdev->dev = dev; > + serdev->receive_buf = hgs_efi_receive_buf; > + serdev->polling_interval = 200 * MSECOND; > + serdev->polling_window = 10 * MSECOND; > + > + ret = serdev_device_open(serdev); This registers a poller, so when one of the calls below fails this might have some bad consequences. Oh, we do not have a serdev_device_close(), I won't look further ;) Sascha > + if (ret) > + return ret; > + > + serdev_device_set_baudrate(serdev, baud); > + > + ret = hgs_efi_register_dev(efi); > + if (ret) { > + dev_err(dev, "Failed to register EFI device\n"); > + return ret; > + }; > + > + return of_platform_populate(dev->of_node, NULL, dev); > +} > + > +static const struct of_device_id __maybe_unused hgs_efi_dt_ids[] = { > + { .compatible = "hgs,efi-gs05", .data = &hgs_efi_ascii_coder }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, lgs_efi_dt_ids); > + > +static struct driver hgs_efi_drv = { > + .name = "hgs-efi", > + .probe = hgs_efi_probe, > + .of_compatible = DRV_OF_COMPAT(hgs_efi_dt_ids), > +}; > +console_platform_driver(hgs_efi_drv); -- 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 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 3/5] mfd: Add Hexagon EFI driver 2026-02-09 9:03 ` Sascha Hauer @ 2026-02-09 11:13 ` Marco Felsch 2026-02-09 13:46 ` Sascha Hauer 0 siblings, 1 reply; 23+ messages in thread From: Marco Felsch @ 2026-02-09 11:13 UTC (permalink / raw) To: Sascha Hauer; +Cc: BAREBOX On 26-02-09, Sascha Hauer wrote: > On Thu, Feb 05, 2026 at 04:45:05PM +0100, Marco Felsch wrote: > > This adds the EFI core driver to communicate with the system > > co-processor. > > This EFI doesn't have anything to do with the Extensible Firmware > Interface, right? Could you add some note what it means to commit > message, Kconfig and to the description in hgs-efi.c to avoid confusion? Sure! > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> > > --- > > drivers/mfd/Kconfig | 8 + > > drivers/mfd/Makefile | 1 + > > drivers/mfd/hgs-efi.c | 473 ++++++++++++++++++++++++++++++++++++++++++++++++++ > > include/mfd/hgs-efi.h | 46 +++++ > > 4 files changed, 528 insertions(+) > > > > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig > > index 471f85cd63dad30b39017f694b594b768e463a15..f09e3903bcb50556b1556a84500ae73d91a5a63d 100644 > > --- a/drivers/mfd/Kconfig > > +++ b/drivers/mfd/Kconfig > > @@ -158,4 +158,12 @@ config MFD_ATMEL_SMC > > bool > > select MFD_SYSCON > > > > +config MFD_HGS_EFI > > + tristate "Hexagon Geosystems EFI core driver" > > + depends on SERIAL_DEV_BUS > > + select CRC16 > > + help > > + Select this to get support for the EFI Co-Processor > > + device found on several devices in the System1600 platform. > > + > > endmenu > > diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile > > index 88480f70640d464e0e12241ec422a63ca860330d..9d27b0bc336a908f1245eb7f1d257a23e271ebd7 100644 > > --- a/drivers/mfd/Makefile > > +++ b/drivers/mfd/Makefile > > @@ -27,3 +27,4 @@ obj-$(CONFIG_MFD_ATMEL_SMC) += atmel-smc.o > > obj-$(CONFIG_MFD_ROHM_BD718XX) += rohm-bd718x7.o > > obj-$(CONFIG_MFD_PCA9450) += pca9450.o > > obj-$(CONFIG_MFD_TPS65219) += tps65219.o > > +obj-$(CONFIG_MFD_HGS_EFI) += hgs-efi.o > > diff --git a/drivers/mfd/hgs-efi.c b/drivers/mfd/hgs-efi.c > > new file mode 100644 > > index 0000000000000000000000000000000000000000..e548a6b209a6f64cecd8d56edcaa565b0b6d2657 > > --- /dev/null > > +++ b/drivers/mfd/hgs-efi.c > > @@ -0,0 +1,473 @@ > > +// SPDX-License-Identifier: GPL-2.0-only > > +// SPDX-FileCopyrightText: 2025 Pengutronix > > + > > +/* > > + * Multifunction core driver for Hexagon Geosystems EFI MCU that is connected > > + * via dedicated UART port. The communication protocol between both parties is > > + * called Sensor Protocol (SEP). > > + * > > + * Based on drivers/mfd/rave-sp.c > > + */ > > + > > +#include <asm/unaligned.h> > > +#include <common.h> > > +#include <init.h> > > +#include <of_device.h> > > +#include <mfd/hgs-efi.h> > > +#include <linux/crc16.h> > > +#include <linux/ctype.h> > > +#include <linux/string.h> > > +#include <mfd/hgs-efi.h> > > + > > +#define HGS_EFI_SEP_ASCII_SYNCBYTE 'S' > > +#define HGS_EFI_SEP_ASCII_MSG_TYPE_CMD 'C' > > +#define HGS_EFI_SEP_ASCII_MSG_TYPE_EVENT 'E' > > +#define HGS_EFI_SEP_ASCII_MSG_TYPE_REPLY 'R' > > +#define HGS_EFI_SEP_ASCII_DELIM ',' > > +#define HGS_EFI_SEP_ASCII_HDR_END ':' > > + > > +/* Non addressed ascii header format */ > > +struct hgs_efi_sep_ascii_hdr { > > + u8 syncbyte; > > + u8 msg_type; > > + u8 msg_id[5]; /* u16 dec number */ > > + u8 delim; > > + u8 crc16[4]; /* u16 hex number */ > > + u8 hdr_end; > > +} __packed; > > + > > +#define HGS_EFI_SEP_RX_BUFFER_SIZE 64 > > +#define HGS_EFI_SEP_FRAME_PREAMBLE_SZ 2 > > +#define HGS_EFI_SEP_FRAME_POSTAMBLE_SZ 2 > > + > > +enum hgs_efi_sep_deframer_state { > > + HGS_EFI_SEP_EXPECT_SOF, > > + HGS_EFI_SEP_EXPECT_DATA, > > +}; > > + > > +/** > > + * struct hgs_efi_deframer - Device protocol deframer > > + * > > + * @state: Current state of the deframer > > + * @data: Buffer used to collect deframed data > > + * @length: Number of bytes de-framed so far > > + */ > > +struct hgs_efi_deframer { > > + enum hgs_efi_sep_deframer_state state; > > + unsigned char data[HGS_EFI_SEP_RX_BUFFER_SIZE]; > > + size_t length; > > +}; > > + > > +/** > > + * struct hgs_efi_reply - Reply as per SEP > > + * > > + * @length: Expected reply length > > + * @data: Buffer to store reply payload in > > + * @msg_id: Expected SEP msg-id > > + * @received: Successful reply reception > > + */ > > +struct hgs_efi_reply { > > + size_t length; > > + void *data; > > + u16 msg_id; > > + bool received; > > +}; > > + > > +struct hgs_efi_sep_coder { > > + int (*encode)(struct hgs_efi *efi, struct hgs_sep_cmd *cmd, u8 *buf); > > + int (*process_frame)(struct hgs_efi *efi, void *buf, size_t size); > > + unsigned int sep_header_hdrsize; > > + char sep_sof_char; > > +}; > > + > > +struct hgs_efi { > > + struct device dev; > > + struct serdev_device *serdev; > > + const struct hgs_efi_sep_coder *coder; > > + struct hgs_efi_deframer deframer; > > + struct hgs_efi_reply *reply; > > +}; > > + > > +static void hgs_efi_write(struct hgs_efi *efi, const u8 *data, size_t data_size) > > +{ > > + print_hex_dump_bytes("hgs-efi tx: ", DUMP_PREFIX_NONE, data, data_size); > > + > > + /* timeout is ignored, instead polling_window is used */ > > + serdev_device_write(efi->serdev, data, data_size, SECOND); > > +} > > + > > +int hgs_efi_exec(struct hgs_efi *efi, struct hgs_sep_cmd *cmd) > > +{ > > + struct device *dev = efi->serdev->dev; > > + struct hgs_efi_reply reply = { > > + .msg_id = cmd->msg_id, > > + .data = cmd->reply_data, > > + .length = cmd->reply_data_size, > > + .received = false, > > + }; > > + unsigned int max_msg_len; > > + u8 *msg, *p; > > + int ret; > > + > > + switch (cmd->type) { > > + case HGS_SEP_MSG_TYPE_COMMAND: > > + case HGS_SEP_MSG_TYPE_EVENT: > > + break; > > + case HGS_SEP_MSG_TYPE_REPLY: > > + dev_warn(dev, "MCU initiated communication is not supported yet!\n"); > > + return -EINVAL; > > + default: > > + dev_warn(dev, "Unknown EFI msg-type %#x\n", cmd->type); > > + return -EINVAL; > > + } > > + > > + max_msg_len = HGS_EFI_SEP_FRAME_PREAMBLE_SZ + > > + HGS_EFI_SEP_FRAME_POSTAMBLE_SZ + > > + efi->coder->sep_header_hdrsize + cmd->payload_size; > > + msg = p = xzalloc(max_msg_len); > > + if (!msg) { > > + dev_err(dev, "No memory\n"); > > + return -ENOMEM; > > + } > > + > > + /* MCU serial flush preamble */ > > + *p++ = '\r'; > > + *p++ = '\n'; > > + > > + ret = efi->coder->encode(efi, cmd, p); > > + if (ret < 0) { > > + free(msg); > > + return ret; > > + } > > + > > + p += ret; > > + > > + /* SEP postamble */ > > + *p++ = '\r'; > > + *p++ = '\n'; > > + > > + efi->reply = &reply; > > + hgs_efi_write(efi, msg, p - msg); > > + > > + free(msg); > > + > > + if (cmd->type == HGS_SEP_MSG_TYPE_EVENT) { > > + efi->reply = NULL; > > + return 0; > > + } > > + > > + /* > > + * is_timeout will implicitly poll serdev via poller > > + * infrastructure > > + */ > > + ret = wait_on_timeout(SECOND, reply.received); > > + if (ret) > > + dev_err(dev, "Command timeout\n"); > > + > > + efi->reply = NULL; > > + > > + return ret; > > +} > > + > > +#define HGS_SEP_DOUBLE_QUOTE_SUB_VAL 0x1a > > + > > +char *hgs_efi_extract_str_response(u8 *buf) > > +{ > > + unsigned char *start; > > + unsigned char *end; > > + unsigned char *p; > > + size_t i; > > + > > + if (!buf || buf[0] != '"') { > > + pr_warn("hgs-efi: No start \" char found in string response\n"); > > Add above the includes: > > #define pr_fmt(fmt) "hgs-efi: " fmt > > And drp the prefix here. Will do. > > + return ERR_PTR(-EINVAL); > > + } > > + > > + start = &buf[1]; > > + end = strrchr(start, '"'); > > + if (!end) { > > + pr_warn("hgs-efi: No end \" char found in string response\n"); > > + return ERR_PTR(-EINVAL); > > + } > > + *end = '\0'; > > + > > + /* > > + * Last step, check for substition val in string reply > > + * and re-substitute it. > > + */ > > + p = start; > > + for (i = 0; i < strlen(start); i++) > > + if (*p == HGS_SEP_DOUBLE_QUOTE_SUB_VAL) > > + *p = '"'; > > + > > + return start; > > +} > > + > > +static int hgs_sep_ascii_encode(struct hgs_efi *efi, struct hgs_sep_cmd *cmd, > > + u8 *buf) > > +{ > > + struct device *dev = efi->serdev->dev; > > + size_t hdr_len; > > + char msg_type; > > + char *hdr; > > + > > + switch (cmd->type) { > > + case HGS_SEP_MSG_TYPE_COMMAND: > > + msg_type = 'C'; > > + break; > > + case HGS_SEP_MSG_TYPE_EVENT: > > + msg_type = 'E'; > > + break; > > + default: > > + /* Should never happen */ > > + return -EINVAL; > > + } > > + > > + /* > > + * The ASCII coder doesn't care about the CRC, also the CRC handling > > + * has a few flaws. Therefore skip it for now. > > + */ > > + hdr = xasprintf("S%c%u:", msg_type, cmd->msg_id); > > xasprintf also doesn't fail. Thanks > > + if (!hdr) { > > + dev_err(dev, "No memory\n"); > > + return -ENOMEM; > > + } > > + > > + /* Now copy the header and the payload to the buffer */ > > + hdr_len = strlen(hdr); > > + memcpy(buf, hdr, hdr_len); > > You could simplify the above by doing: > > hdr_len = sprintf(buf, "S%c%u:", msg_type, cmd->msg_id); Thats a good point, thanks! > > > + memcpy(buf + hdr_len, cmd->payload, cmd->payload_size); > > + > > + free(hdr); > > + > > + return hdr_len + cmd->payload_size; > > +} > > + > > +static int > > +hgs_sep_process_ascii_frame(struct hgs_efi *efi, void *_buf, size_t size) > > +{ > > + struct device *dev = efi->serdev->dev; > > + unsigned char *payload; > > + unsigned int copy_bytes; > > + unsigned int msgid; > > + size_t payload_len; > > + u8 *buf = _buf; > > + size_t hdrlen; > > + char *p; > > + int ret; > > + > > + /* > > + * Non addressing ASCII format: > > + * S[MsgType][MsgID](,[CRC]):[Payload] > > + */ > > + if (buf[1] != HGS_EFI_SEP_ASCII_MSG_TYPE_REPLY) { > > check buf[0] != 0 before looking at buf[1]? I could do this, but this function is only called if buf[0] has the correct value (see: HGS_EFI_SEP_EXPECT_SOF). > > + dev_warn(dev, "Invalid msg-type %c(%#x)\n", *buf, *buf); > > + return -EINVAL; > > + } > > + > > + /* Split header from payload first for the following str-ops on buf */ > > + payload = strstr(buf, ":"); > > + if (!payload) { > > + dev_warn(dev, "Failed to find header delim\n"); > > + return -EINVAL; > > + } > > + > > + hdrlen = payload - buf; > > + if (hdrlen > sizeof(struct hgs_efi_sep_ascii_hdr)) { > > + dev_warn(dev, "Invalid header len detected\n"); > > + return -EINVAL; > > + } > > + > > + *payload = 0; > > + payload++; > > + > > + /* > > + * Albeit the CRC is optional and the calc as a few flaws the coder may > > s/as/has/ thanks. > > > + * has added it. Skip the CRC check but do the msg-id check. > > + */ > > + p = strstr(buf, ","); > > + if (p) > > + *p = 0; > > + > > + ret = kstrtouint(&buf[2], 10, &msgid); > > + if (ret) { > > + dev_warn(dev, "Failed to parse msgid, ret:%d\n", ret); > > + return -EINVAL; > > + } > > + > > + if (msgid != efi->reply->msg_id) { > > + dev_warn(dev, "Wrong msg-id received, ignore frame (%u != %u)\n", > > + msgid, efi->reply->msg_id); > > + return -EINVAL; > > + } > > + > > + payload_len = size - hdrlen; > > + copy_bytes = payload_len; > > + if (payload_len > efi->reply->length) { > > + dev_warn(dev, "Reply buffer to small, dropping remaining %zu bytes\n", > > + payload_len - efi->reply->length); > > + copy_bytes = efi->reply->length; > > + } > > + > > + memcpy(efi->reply->data, payload, copy_bytes); > > + > > + return 0; > > +} > > + > > +static const struct hgs_efi_sep_coder hgs_efi_ascii_coder = { > > + .encode = hgs_sep_ascii_encode, > > + .process_frame = hgs_sep_process_ascii_frame, > > + .sep_header_hdrsize = sizeof(struct hgs_efi_sep_ascii_hdr), > > + .sep_sof_char = HGS_EFI_SEP_ASCII_SYNCBYTE, > > +}; > > + > > +static bool hgs_efi_eof_received(struct hgs_efi_deframer *deframer) > > +{ > > + const char eof_seq[] = { '\r', '\n' }; > > + > > + if (deframer->length <= 2) > > + return false; > > + > > + if (memcmp(&deframer->data[deframer->length - 2], eof_seq, 2)) > > + return false; > > + > > + return true; > > +} > > + > > +static void hgs_efi_receive_frame(struct hgs_efi *efi, > > + struct hgs_efi_deframer *deframer) > > +{ > > + int ret; > > + > > + if (deframer->length < efi->coder->sep_header_hdrsize) { > > + dev_warn(efi->serdev->dev, "Bad frame: Too short\n"); > > + return; > > + } > > + > > + print_hex_dump_bytes("hgs-efi rx-frame: ", DUMP_PREFIX_NONE, > > + deframer->data, deframer->length); > > + > > + ret = efi->coder->process_frame(efi, deframer->data, > > + deframer->length - HGS_EFI_SEP_FRAME_PREAMBLE_SZ); > > + if (!ret) > > + efi->reply->received = true; > > +} > > + > > +static int hgs_efi_receive_buf(struct serdev_device *serdev, > > + const unsigned char *buf, size_t size) > > +{ > > + struct device *dev = serdev->dev; > > + struct hgs_efi *efi = dev->priv; > > + struct hgs_efi_deframer *deframer = &efi->deframer; > > + const unsigned char *src = buf; > > + const unsigned char *end = buf + size; > > + > > + print_hex_dump_bytes("hgs-efi rx-bytes: ", DUMP_PREFIX_NONE, buf, size); > > + > > + while (src < end) { > > + const unsigned char byte = *src++; > > + > > + switch (deframer->state) { > > + case HGS_EFI_SEP_EXPECT_SOF: > > + if (byte == efi->coder->sep_sof_char) > > + deframer->state = HGS_EFI_SEP_EXPECT_DATA; > > + deframer->data[deframer->length++] = byte; > > + break; > > + case HGS_EFI_SEP_EXPECT_DATA: > > + if (deframer->length >= sizeof(deframer->data)) { > > + dev_warn(dev, "Bad frame: Too long\n"); > > + goto frame_reset; > > + } > > + > > + deframer->data[deframer->length++] = byte; > > + if (hgs_efi_eof_received(deframer)) { > > + hgs_efi_receive_frame(efi, deframer); > > + goto frame_reset; > > + } > > + } > > + } > > + > > + /* > > + * All bytes processed but no EOF detected yet which because the serdev > > s/which// > > > + * poller may called us to early. Keep the deframer state to continue > > + * the work where we finished. > > + */ > > + return size; > > + > > +frame_reset: > > + memset(deframer->data, 0, deframer->length); > > + deframer->length = 0; > > + deframer->state = HGS_EFI_SEP_EXPECT_SOF; > > + > > + return src - buf; > > +} > > + > > +static int hgs_efi_register_dev(struct hgs_efi *efi) > > +{ > > + struct device *dev = &efi->dev; > > + > > + dev->parent = efi->serdev->dev; > > + dev_set_name(dev, "%s", "efi"); > > dev_set_name(dev, "efi"); Sure. > > + dev->id = DEVICE_ID_SINGLE; > > + > > + return register_device(dev); > > +} > > + > > +static int hgs_efi_probe(struct device *dev) > > +{ > > + struct serdev_device *serdev = to_serdev_device(dev->parent); > > + struct hgs_efi *efi; > > + u32 baud; > > + int ret; > > + > > + if (of_property_read_u32(dev->of_node, "current-speed", &baud)) { > > + dev_err(dev, > > + "'current-speed' is not specified in device node\n"); > > + return -EINVAL; > > + } > > + > > + efi = xzalloc(sizeof(*efi)); > > + if (!efi) > > + return -ENOMEM; > > + > > + efi->coder = of_device_get_match_data(dev); > > + if (!efi->coder) { > > + free(efi); > > + return -ENODEV; > > + } > > + > > + efi->serdev = serdev; > > + > > + dev->priv = efi; > > + serdev->dev = dev; > > + serdev->receive_buf = hgs_efi_receive_buf; > > + serdev->polling_interval = 200 * MSECOND; > > + serdev->polling_window = 10 * MSECOND; > > + > > + ret = serdev_device_open(serdev); > > This registers a poller, so when one of the calls below fails this might > have some bad consequences. Oh, we do not have a serdev_device_close(), > I won't look further ;) Hm.. something we should fix. Let me check if I can add a serdev_device_close() routine real quick else I would add a comment. Regards, Marco > > Sascha > > > + if (ret) > > + return ret; > > + > > + serdev_device_set_baudrate(serdev, baud); > > + > > + ret = hgs_efi_register_dev(efi); > > + if (ret) { > > + dev_err(dev, "Failed to register EFI device\n"); > > + return ret; > > + }; > > + > > + return of_platform_populate(dev->of_node, NULL, dev); > > +} > > + > > +static const struct of_device_id __maybe_unused hgs_efi_dt_ids[] = { > > + { .compatible = "hgs,efi-gs05", .data = &hgs_efi_ascii_coder }, > > + { /* sentinel */ } > > +}; > > +MODULE_DEVICE_TABLE(of, lgs_efi_dt_ids); > > + > > +static struct driver hgs_efi_drv = { > > + .name = "hgs-efi", > > + .probe = hgs_efi_probe, > > + .of_compatible = DRV_OF_COMPAT(hgs_efi_dt_ids), > > +}; > > +console_platform_driver(hgs_efi_drv); > > -- > 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 | > -- #gernperDu #CallMeByMyFirstName Pengutronix e.K. | | Steuerwalder Str. 21 | https://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 3/5] mfd: Add Hexagon EFI driver 2026-02-09 11:13 ` Marco Felsch @ 2026-02-09 13:46 ` Sascha Hauer 0 siblings, 0 replies; 23+ messages in thread From: Sascha Hauer @ 2026-02-09 13:46 UTC (permalink / raw) To: Marco Felsch; +Cc: BAREBOX On Mon, Feb 09, 2026 at 12:13:05PM +0100, Marco Felsch wrote: > > > +hgs_sep_process_ascii_frame(struct hgs_efi *efi, void *_buf, size_t size) > > > +{ > > > + struct device *dev = efi->serdev->dev; > > > + unsigned char *payload; > > > + unsigned int copy_bytes; > > > + unsigned int msgid; > > > + size_t payload_len; > > > + u8 *buf = _buf; > > > + size_t hdrlen; > > > + char *p; > > > + int ret; > > > + > > > + /* > > > + * Non addressing ASCII format: > > > + * S[MsgType][MsgID](,[CRC]):[Payload] > > > + */ > > > + if (buf[1] != HGS_EFI_SEP_ASCII_MSG_TYPE_REPLY) { > > > > check buf[0] != 0 before looking at buf[1]? > > I could do this, but this function is only called if buf[0] has the > correct value (see: HGS_EFI_SEP_EXPECT_SOF). By adding the check you can prevent other people from spending the few minutes it takes to check that. 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 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 4/5] watchdog: Add Hexagon EFI watchdog driver 2026-02-05 15:45 [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch ` (2 preceding siblings ...) 2026-02-05 15:45 ` [PATCH 3/5] mfd: Add Hexagon EFI driver Marco Felsch @ 2026-02-05 15:45 ` Marco Felsch 2026-02-06 13:13 ` Ahmad Fatoum 2026-02-05 15:45 ` [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 Marco Felsch 2026-02-05 15:50 ` [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch 5 siblings, 1 reply; 23+ messages in thread From: Marco Felsch @ 2026-02-05 15:45 UTC (permalink / raw) To: Sascha Hauer, BAREBOX; +Cc: Marco Felsch The EFI system co-processor implements a watchdog device which must be pinged to inform the MCU that the system is up and running. Normaly the ping is done by Linux but sometimes it can become necessary to do it within barebox too, e.g. to allow barebox debugging and development. Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> --- drivers/watchdog/Kconfig | 9 +++++ drivers/watchdog/Makefile | 1 + drivers/watchdog/hgs_efi_wdt.c | 88 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index bf18782bdb58b20240d7762ce32f98c78c4cd12d..c962e8f22e5a7cb21ee93b3f82189cc8536781b9 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -195,4 +195,13 @@ config K3_RTI_WDT Say Y here if you want to include support for the K3 watchdog timer (RTI module) available in the K3 generation of processors. +config HGS_EFI_WATCHDOG + bool "Hexagon Geosystems EFI watchdog" + depends on MFD_HGS_EFI || COMPILE_TEST + help + Say Y here if you want to include support for the Hexagon Geosystems + EFI watchdog timer. + + If unsure, say N. + endif diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 85d8dbfa3f83d868ad84935ab98c5f7f64922f8e..187ab247ddcf61f9db8137425b3234b60a7062ac 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_STARFIVE_WDT) += starfive_wdt.o obj-$(CONFIG_WDAT_WDT) += wdat_wdt.o obj-$(CONFIG_CADENCE_WATCHDOG) += cadence_wdt.o obj-$(CONFIG_K3_RTI_WDT) += rti_wdt.o +obj-$(CONFIG_HGS_EFI_WATCHDOG) += hgs_efi_wdt.o diff --git a/drivers/watchdog/hgs_efi_wdt.c b/drivers/watchdog/hgs_efi_wdt.c new file mode 100644 index 0000000000000000000000000000000000000000..985d6515c7e6643047ba98cf4c11d2570a030d54 --- /dev/null +++ b/drivers/watchdog/hgs_efi_wdt.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2025 Pengutronix + +#include <common.h> +#include <init.h> +#include <of_device.h> +#include <watchdog.h> + +#include <mfd/hgs-efi.h> + +struct hgs_efi_wdt_data { + unsigned int msg_id; +}; + +struct hgs_efi_wdt { + struct watchdog wdd; + struct hgs_efi *efi; + const struct hgs_efi_wdt_data *data; + bool is_running; +}; + +static struct hgs_efi_wdt *to_hgs_efi_wdt(struct watchdog *wdd) +{ + return container_of(wdd, struct hgs_efi_wdt, wdd); +} + +static int hgs_efi_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout) +{ + struct hgs_efi_wdt *efi_wd = to_hgs_efi_wdt(wdd); + struct device *dev = &wdd->dev; + struct hgs_sep_cmd cmd = { + .type = HGS_SEP_MSG_TYPE_EVENT, + .msg_id = efi_wd->data->msg_id, + }; + int ret; + + /* The watchdog can't be turned of */ + if (efi_wd->is_running && !timeout) + return -ENOSYS; + + /* The EFI watchdog doesn't have a timeout, once pinged */ + if (efi_wd->is_running) + return 0; + + ret = hgs_efi_exec(efi_wd->efi, &cmd); + if (ret) + dev_warn(dev, "Failed to send OsRunning/SystemReady\n"); + + return ret; +} + +static int hgs_efi_wdt_drv_probe(struct device *dev) +{ + struct hgs_efi_wdt *efi_wd; + struct watchdog *wdd; + int ret; + + efi_wd = xzalloc(sizeof(*efi_wd)); + efi_wd->efi = dev_get_priv(dev->parent); + efi_wd->data = of_device_get_match_data(dev); + + wdd = &efi_wd->wdd; + wdd->hwdev = dev; + wdd->set_timeout = hgs_efi_wdt_set_timeout; + + ret = watchdog_register(wdd); + if (ret) + dev_err(dev, "Failed to register watchdog device\n"); + + return ret; +} + +const struct hgs_efi_wdt_data hgs_efi_wdt_gs05 = { + .msg_id = 0, +}; + +static struct of_device_id hgs_efi_wdt_of_match[] = { + { .compatible = "hgs,efi-gs05-wdt", .data = &hgs_efi_wdt_gs05 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, hgs_efi_wdt_of_match); + +static struct driver hgs_efi_wdt_driver = { + .name = "hgs-efi-wdt", + .probe = hgs_efi_wdt_drv_probe, + .of_compatible = hgs_efi_wdt_of_match, +}; +device_platform_driver(hgs_efi_wdt_driver); -- 2.47.3 ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/5] watchdog: Add Hexagon EFI watchdog driver 2026-02-05 15:45 ` [PATCH 4/5] watchdog: Add Hexagon EFI watchdog driver Marco Felsch @ 2026-02-06 13:13 ` Ahmad Fatoum 2026-02-06 16:34 ` Marco Felsch 0 siblings, 1 reply; 23+ messages in thread From: Ahmad Fatoum @ 2026-02-06 13:13 UTC (permalink / raw) To: Marco Felsch, Sascha Hauer, BAREBOX On 2/5/26 4:45 PM, Marco Felsch wrote: > The EFI system co-processor implements a watchdog device which must be > pinged to inform the MCU that the system is up and running. > > Normaly the ping is done by Linux but sometimes it can become necessary > to do it within barebox too, e.g. to allow barebox debugging and > development. > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> > --- > drivers/watchdog/Kconfig | 9 +++++ > drivers/watchdog/Makefile | 1 + > drivers/watchdog/hgs_efi_wdt.c | 88 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 98 insertions(+) > > diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig > index bf18782bdb58b20240d7762ce32f98c78c4cd12d..c962e8f22e5a7cb21ee93b3f82189cc8536781b9 100644 > --- a/drivers/watchdog/Kconfig > +++ b/drivers/watchdog/Kconfig > @@ -195,4 +195,13 @@ config K3_RTI_WDT > Say Y here if you want to include support for the K3 watchdog > timer (RTI module) available in the K3 generation of processors. > > +config HGS_EFI_WATCHDOG > + bool "Hexagon Geosystems EFI watchdog" > + depends on MFD_HGS_EFI || COMPILE_TEST Thanks for making sure it compiles under COMPILE_TEST. :) > +#include <mfd/hgs-efi.h> > + > +struct hgs_efi_wdt_data { > + unsigned int msg_id; > +}; > + > +struct hgs_efi_wdt { > + struct watchdog wdd; > + struct hgs_efi *efi; > + const struct hgs_efi_wdt_data *data; > + bool is_running; This is only ever read, but set no where. > +}; > + > +static struct hgs_efi_wdt *to_hgs_efi_wdt(struct watchdog *wdd) > +{ > + return container_of(wdd, struct hgs_efi_wdt, wdd); > +} > + > +static int hgs_efi_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout) > +{ > + struct hgs_efi_wdt *efi_wd = to_hgs_efi_wdt(wdd); > + struct device *dev = &wdd->dev; > + struct hgs_sep_cmd cmd = { > + .type = HGS_SEP_MSG_TYPE_EVENT, > + .msg_id = efi_wd->data->msg_id, > + }; > + int ret; > + > + /* The watchdog can't be turned of */ > + if (efi_wd->is_running && !timeout) > + return -ENOSYS; > + > + /* The EFI watchdog doesn't have a timeout, once pinged */ > + if (efi_wd->is_running) > + return 0; A watchdog can also implement a ping callback, which may be suitable here. > +static int hgs_efi_wdt_drv_probe(struct device *dev) > +{ > + struct hgs_efi_wdt *efi_wd; > + struct watchdog *wdd; > + int ret; > + > + efi_wd = xzalloc(sizeof(*efi_wd)); > + efi_wd->efi = dev_get_priv(dev->parent); > + efi_wd->data = of_device_get_match_data(dev); > + > + wdd = &efi_wd->wdd; > + wdd->hwdev = dev; > + wdd->set_timeout = hgs_efi_wdt_set_timeout; FYI, if you can query the EFI whether it's enabled, you can set wdd->running to either WDOG_HW_RUNNING or WDOG_HW_NOT_RUNNING > + > + ret = watchdog_register(wdd); > + if (ret) > + dev_err(dev, "Failed to register watchdog device\n"); > + > + return ret; > +} > + > +const struct hgs_efi_wdt_data hgs_efi_wdt_gs05 = { > + .msg_id = 0, > +}; > + > +static struct of_device_id hgs_efi_wdt_of_match[] = { > + { .compatible = "hgs,efi-gs05-wdt", .data = &hgs_efi_wdt_gs05 }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, hgs_efi_wdt_of_match); > + > +static struct driver hgs_efi_wdt_driver = { > + .name = "hgs-efi-wdt", > + .probe = hgs_efi_wdt_drv_probe, > + .of_compatible = hgs_efi_wdt_of_match, > +}; > +device_platform_driver(hgs_efi_wdt_driver); > -- 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 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 4/5] watchdog: Add Hexagon EFI watchdog driver 2026-02-06 13:13 ` Ahmad Fatoum @ 2026-02-06 16:34 ` Marco Felsch 0 siblings, 0 replies; 23+ messages in thread From: Marco Felsch @ 2026-02-06 16:34 UTC (permalink / raw) To: Ahmad Fatoum; +Cc: BAREBOX On 26-02-06, Ahmad Fatoum wrote: > > > On 2/5/26 4:45 PM, Marco Felsch wrote: > > The EFI system co-processor implements a watchdog device which must be > > pinged to inform the MCU that the system is up and running. > > > > Normaly the ping is done by Linux but sometimes it can become necessary > > to do it within barebox too, e.g. to allow barebox debugging and > > development. > > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> > > --- > > drivers/watchdog/Kconfig | 9 +++++ > > drivers/watchdog/Makefile | 1 + > > drivers/watchdog/hgs_efi_wdt.c | 88 ++++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 98 insertions(+) > > > > diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig > > index bf18782bdb58b20240d7762ce32f98c78c4cd12d..c962e8f22e5a7cb21ee93b3f82189cc8536781b9 100644 > > --- a/drivers/watchdog/Kconfig > > +++ b/drivers/watchdog/Kconfig > > @@ -195,4 +195,13 @@ config K3_RTI_WDT > > Say Y here if you want to include support for the K3 watchdog > > timer (RTI module) available in the K3 generation of processors. > > > > +config HGS_EFI_WATCHDOG > > + bool "Hexagon Geosystems EFI watchdog" > > + depends on MFD_HGS_EFI || COMPILE_TEST > > Thanks for making sure it compiles under COMPILE_TEST. :) > > > > +#include <mfd/hgs-efi.h> > > + > > +struct hgs_efi_wdt_data { > > + unsigned int msg_id; > > +}; > > + > > +struct hgs_efi_wdt { > > + struct watchdog wdd; > > + struct hgs_efi *efi; > > + const struct hgs_efi_wdt_data *data; > > + bool is_running; > > This is only ever read, but set no where. You're right, I forgot to set it since pinging the watchdog within barebox is a dev-feature :/ Fixed it with the new version. > > +}; > > + > > +static struct hgs_efi_wdt *to_hgs_efi_wdt(struct watchdog *wdd) > > +{ > > + return container_of(wdd, struct hgs_efi_wdt, wdd); > > +} > > + > > +static int hgs_efi_wdt_set_timeout(struct watchdog *wdd, unsigned int timeout) > > +{ > > + struct hgs_efi_wdt *efi_wd = to_hgs_efi_wdt(wdd); > > + struct device *dev = &wdd->dev; > > + struct hgs_sep_cmd cmd = { > > + .type = HGS_SEP_MSG_TYPE_EVENT, > > + .msg_id = efi_wd->data->msg_id, > > + }; > > + int ret; > > + > > + /* The watchdog can't be turned of */ > > + if (efi_wd->is_running && !timeout) > > + return -ENOSYS; > > + > > + /* The EFI watchdog doesn't have a timeout, once pinged */ > > + if (efi_wd->is_running) > > + return 0; > > A watchdog can also implement a ping callback, which may be suitable here. You're right, I adapted the code. Since the ping() is optional and the set_timeout() isn't I went the way of supplying only the set_timeout(). However, I convered it to ping() and always return -ENOSYS in case of set_timeout(). > > +static int hgs_efi_wdt_drv_probe(struct device *dev) > > +{ > > + struct hgs_efi_wdt *efi_wd; > > + struct watchdog *wdd; > > + int ret; > > + > > + efi_wd = xzalloc(sizeof(*efi_wd)); > > + efi_wd->efi = dev_get_priv(dev->parent); > > + efi_wd->data = of_device_get_match_data(dev); > > + > > + wdd = &efi_wd->wdd; > > + wdd->hwdev = dev; > > + wdd->set_timeout = hgs_efi_wdt_set_timeout; > > FYI, if you can query the EFI whether it's enabled, you can set > wdd->running to either WDOG_HW_RUNNING or WDOG_HW_NOT_RUNNING Right! I added the WDOG_HW_RUNNING, since the watchdog is always running. Thanks for the review! Regards, Marco > > > + > > + ret = watchdog_register(wdd); > > + if (ret) > > + dev_err(dev, "Failed to register watchdog device\n"); > > + > > + return ret; > > +} > > + > > +const struct hgs_efi_wdt_data hgs_efi_wdt_gs05 = { > > + .msg_id = 0, > > +}; > > + > > +static struct of_device_id hgs_efi_wdt_of_match[] = { > > + { .compatible = "hgs,efi-gs05-wdt", .data = &hgs_efi_wdt_gs05 }, > > + { /* sentinel */ } > > +}; > > +MODULE_DEVICE_TABLE(of, hgs_efi_wdt_of_match); > > + > > +static struct driver hgs_efi_wdt_driver = { > > + .name = "hgs-efi-wdt", > > + .probe = hgs_efi_wdt_drv_probe, > > + .of_compatible = hgs_efi_wdt_of_match, > > +}; > > +device_platform_driver(hgs_efi_wdt_driver); > > > > -- > 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 | > > -- #gernperDu #CallMeByMyFirstName Pengutronix e.K. | | Steuerwalder Str. 21 | https://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 2026-02-05 15:45 [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch ` (3 preceding siblings ...) 2026-02-05 15:45 ` [PATCH 4/5] watchdog: Add Hexagon EFI watchdog driver Marco Felsch @ 2026-02-05 15:45 ` Marco Felsch 2026-02-06 13:47 ` Ahmad Fatoum 2026-02-09 10:42 ` Sascha Hauer 2026-02-05 15:50 ` [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch 5 siblings, 2 replies; 23+ messages in thread From: Marco Felsch @ 2026-02-05 15:45 UTC (permalink / raw) To: Sascha Hauer, BAREBOX; +Cc: Marco Felsch, Johannes Schneider This adds support for the Hexagon Geosystems GS05 which is part of the System1600 platform. Co-developed-by: Johannes Schneider <johannes.schneider@leica-geosystems.com> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> --- arch/arm/boards/Makefile | 1 + arch/arm/boards/hgs-gs05/Makefile | 6 + arch/arm/boards/hgs-gs05/board.c | 237 +++++ arch/arm/boards/hgs-gs05/flash-header-gs05.imxcfg | 12 + arch/arm/boards/hgs-gs05/lowlevel.c | 128 +++ arch/arm/boards/hgs-gs05/lpddr4-timing.c | 1118 +++++++++++++++++++++ arch/arm/dts/Makefile | 1 + arch/arm/dts/imx8m-hgs-common.dtsi | 80 ++ arch/arm/dts/imx8mm-hgs-gs05.dts | 320 ++++++ arch/arm/mach-imx/Kconfig | 8 + common/boards/Kconfig | 12 + common/boards/Makefile | 1 + common/boards/hgs/Makefile | 7 + common/boards/hgs/common.c | 627 ++++++++++++ common/boards/hgs/lib.c | 73 ++ common/boards/hgs/pbl.c | 100 ++ images/Makefile.imx | 2 + include/boards/hgs/common.h | 84 ++ 18 files changed, 2817 insertions(+) diff --git a/arch/arm/boards/Makefile b/arch/arm/boards/Makefile index dd2f2c324e25d35978c14acf157a986f507c6548..e3fbf5262f0c08a7623930b9d51b5d2340cdf0a6 100644 --- a/arch/arm/boards/Makefile +++ b/arch/arm/boards/Makefile @@ -53,6 +53,7 @@ obj-$(CONFIG_MACH_GUF_SANTARO) += guf-santaro/ obj-$(CONFIG_MACH_GUF_VINCELL) += guf-vincell/ obj-$(CONFIG_MACH_GW_VENTANA) += gateworks-ventana/ obj-$(CONFIG_MACH_HABA_KNX_LITE) += haba-knx/ +obj-$(CONFIG_MACH_HGS_GS05) += hgs-gs05/ obj-$(CONFIG_MACH_IMX233_OLINUXINO) += imx233-olinuxino/ obj-$(CONFIG_MACH_INNOCOMM_WB15) += innocomm-imx8mm-wb15/ obj-$(CONFIG_MACH_KAMSTRUP_MX7_CONCENTRATOR) += kamstrup-mx7-concentrator/ diff --git a/arch/arm/boards/hgs-gs05/Makefile b/arch/arm/boards/hgs-gs05/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..494a9a87f78ba31147205ca72fe0db3cf04f7cb6 --- /dev/null +++ b/arch/arm/boards/hgs-gs05/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only +# SPDX-FileCopyrightText: 2025 Pengutronix +# SPDX-FileCopyrightText: Leica Geosystems AG + +obj-y += board.o +lwl-y += lowlevel.o lpddr4-timing.o diff --git a/arch/arm/boards/hgs-gs05/board.c b/arch/arm/boards/hgs-gs05/board.c new file mode 100644 index 0000000000000000000000000000000000000000..962bc91d3a3d0b3290e748ccbe30bfca21af9e1c --- /dev/null +++ b/arch/arm/boards/hgs-gs05/board.c @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2025 Pengutronix +// SPDX-FileCopyrightText: Leica Geosystems AG + +#include <boards/hgs/common.h> +#include <bootsource.h> +#include <common.h> +#include <deep-probe.h> +#include <envfs.h> +#include <environment.h> +#include <init.h> +#include <i2c/i2c.h> +#include <linux/phy.h> +#include <mach/imx/bbu.h> +#include <mach/imx/generic.h> +#include <mfd/hgs-efi.h> +#include <of.h> +#include <state.h> + +#define PHY_ID_AR8031 0x004dd074 +#define AR_PHY_ID_MASK 0xffffffff + +#define HGS_GS05_BASE_NAME "Hexagon Geosystems GS05" + +#define HGS_GS05_MACHINE(_revid, _compatible, _model_suffix) \ + HGS_MACHINE(_revid, _compatible, HGS_GS05_BASE_NAME " " _model_suffix) + +struct hgs_machine hgs_gs05_variants[] = { + HGS_GS05_MACHINE(HGS_BOARD_REV_C, "hgs,gs05-rev-c", "Rev-C"), + HGS_GS05_MACHINE(HGS_BOARD_REV_D, "hgs,gs05-rev-d", "Rev-D"), + { /* Sentinel */ } +}; + +#define HGS_GS05_LEGACY_MACHINE(_revchar, _revid, _compatible, _model_suffix) \ +{ \ + .revision = _revchar, \ + .machine = HGS_GS05_MACHINE(_revid, _compatible, _model_suffix) \ +} + +struct hgs_gs05_legacy_machine { + u8 revision; + struct hgs_machine machine; +} hgs_gs05_legacy_variants[] = { + HGS_GS05_LEGACY_MACHINE('C', HGS_BOARD_REV_C, "hgs,gs05-rev-c", "Rev-C"), + HGS_GS05_LEGACY_MACHINE('D', HGS_BOARD_REV_D, "hgs,gs05-rev-d", "Rev-D"), + { /* Sentinel */ } +}; + +static int ar8031_phy_fixup(struct phy_device *phydev) +{ + /* enable rgmii rxc skew and phy mode select to RGMII copper */ + phy_write(phydev, 0x1d, 0x1f); + phy_write(phydev, 0x1e, 0x8); + phy_write(phydev, 0x1d, 0x00); + phy_write(phydev, 0x1e, 0x82ee); + phy_write(phydev, 0x1d, 0x05); + phy_write(phydev, 0x1e, 0x100); + + return 0; +} + +static struct hgs_machine * +hgs_gs05_get_board_from_legacy(const unsigned char *serial) +{ + struct hgs_gs05_legacy_machine *machine = hgs_gs05_legacy_variants; + + for (; machine->revision; machine++) + if (serial[6] == machine->revision) + return &machine->machine; + + return ERR_PTR(-EINVAL); +} + +static struct hgs_machine * +hgs_gs05_select_board(const unsigned char *serial, bool legacy_format) +{ + struct hgs_machine *machine = hgs_gs05_variants; + const struct hgs_board_revision *rev; + + /* TODO: Remove legacy handling if no longer required */ + if (legacy_format) + return hgs_gs05_get_board_from_legacy(serial); + + rev = hgs_get_rev_from_part_trace((struct hgs_part_trace_code *)serial); + if (!rev) + return ERR_PTR(-EINVAL); + + for (; machine->dts_compatible; machine++) + if (rev->id == machine->revision) + return machine; + + return ERR_PTR(-EINVAL); +} + +static u64 +hgs_gs05_set_efi_poll_intervall(struct device *efid, u64 new_polling_interval) +{ + const char *old_interval_str; + char *new_interval; + u64 old_interval; + + old_interval_str = dev_get_param(efid->parent, "polling_interval"); + kstrtoull(old_interval_str, 10, &old_interval); + + pr_debug("Update EFI UART-Rx poll interval: %llu ns -> %llu ns\n", + old_interval, new_polling_interval); + + new_interval = basprintf("%llu", new_polling_interval); + dev_set_param(efid->parent, "polling_interval", new_interval); + free(new_interval); + + return old_interval; +} + +/* '"' + sizeof(struct hgs_part_trace_code) + '"' + string delim '\0' */ +#define HGS_GS05_SERIAL_NUMBER_CHARS \ + (1 + sizeof(struct hgs_part_trace_code) + 1 + 1) + +static struct hgs_machine *hgs_gs05_get_board(struct device_d *dev) +{ + u8 buf[HGS_GS05_SERIAL_NUMBER_CHARS] = { }; + struct device *efi_dev = get_device_by_name("efi"); + struct hgs_efi *efi = dev_get_priv(efi_dev->parent); + struct hgs_sep_cmd cmd = { + .type = HGS_SEP_MSG_TYPE_COMMAND, + .msg_id = 11, + .reply_data = buf, + .reply_data_size = sizeof(buf), + }; + u64 orig_poll_interval; + unsigned char *resp; + bool legacy = false; + unsigned int len; + int ret; + + /* + * The GS05 has a very slow EFI UART baudrate of 19200 bps. So the + * serial-number query takes ~18ms just for the transfer, not taking + * the EFI MCU command processing into account. + * + * This causes an UART Rx FIFO overflow with the standard EFI MCU + * driver settings for polling_window and polling_intervall because the + * EFI response is too long for the 32-Rx byte FIFO and the poll + * reschedule is too late. + * + * Set the polling_interval to 1ms to workaround the slow UART baudrate, + * so the complete poll intervall takes ~11ms. This shall ensure that + * the reschdule happens at least once while retrieving the EFI + * response. + * + * Adapt the polling_interval and not the polling_window to be more + * responsive and avoid unnecessary wait times. + * + * The polling_interval unit is ns. + */ + orig_poll_interval = hgs_gs05_set_efi_poll_intervall(efi_dev, 1 * MSECOND); + ret = hgs_efi_exec(efi, &cmd); + hgs_gs05_set_efi_poll_intervall(efi_dev, orig_poll_interval); + if (ret) { + dev_warn(dev, "Failed to query serial number\n"); + return ERR_PTR(-EINVAL); + } + + resp = hgs_efi_extract_str_response(buf); + if (IS_ERR(resp)) { + dev_warn(dev, "Failed to query EFI response"); + return ERR_CAST(resp); + } + len = strlen(resp); + + switch (len) { + case 0: + dev_warn(dev, "Empty EFI serial number detected\n"); + return ERR_PTR(-EINVAL); + case 17: + dev_warn(dev, "Legacy Revision format detected: please update PP4 and re-program board-id in the new format.\n"); + legacy = true; + fallthrough; + case 29: + barebox_set_serial_number(resp); + return hgs_gs05_select_board(resp, legacy); + default: + dev_warn(dev, "Invalid serial number EFI response length\n"); + return ERR_PTR(-EINVAL); + } +} + +static struct hgs_machine *hgs_gs05_fallback_board(struct device_d *dev) +{ + struct hgs_machine *fallback; + + fallback = hgs_get_last_variant_entry(hgs_gs05_variants); + dev_warn(dev, "Board detection failed, fallback to: %s\n", + fallback->model); + + return fallback; +} + +static int hgs_gs05_probe(struct device_d *dev) +{ + struct hgs_machine *board; + + phy_register_fixup_for_uid(PHY_ID_AR8031, AR_PHY_ID_MASK, + ar8031_phy_fixup); + /* + * Ensure that the MCU driver was already probed before try to access + * the MCU to query the revision. + */ + of_devices_ensure_probed_by_compatible("hgs,efi-gs05"); + + /* Ensure state is probed to be able to query the hostname */ + state_by_alias("state"); + + board = hgs_gs05_get_board(dev); + if (IS_ERR(board)) + board = hgs_gs05_fallback_board(dev); + board->dev = dev; + board->type = HGS_HW_GS05; + board->console_alias = "serial2"; + board->pp4_gpio = IMX_GPIO_NR(1, 10); + board->hostname = xstrdup(getenv("state.product.hostname")); + + return hgs_common_boot(board); +} + +static const struct of_device_id hgs_gs05_of_match[] = { + { .compatible = "hgs,gs05" }, + { /* Sentinel */ } +}; +BAREBOX_DEEP_PROBE_ENABLE(hgs_gs05_of_match); + +static struct driver_d hgs_gs05_board_driver = { + .name = "board-hgs-gs05", + .probe = hgs_gs05_probe, + .of_compatible = hgs_gs05_of_match, +}; +coredevice_platform_driver(hgs_gs05_board_driver); diff --git a/arch/arm/boards/hgs-gs05/flash-header-gs05.imxcfg b/arch/arm/boards/hgs-gs05/flash-header-gs05.imxcfg new file mode 100644 index 0000000000000000000000000000000000000000..008d4171a919381f78d4bb708ea6363e85cdd8d5 --- /dev/null +++ b/arch/arm/boards/hgs-gs05/flash-header-gs05.imxcfg @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +# SPDX-FileCopyrightText: 2025 Pengutronix +# SPDX-FileCopyrightText: Leica Geosystems AG + +soc imx8mm + +loadaddr 0x007e1000 +max_load_size 0x3f000 +ivtofs 0x400 + +#include <mach/imx/flexspi-imx8mm-cfg.h> +#include <mach/imx/habv4-imx8-gencsf.h> diff --git a/arch/arm/boards/hgs-gs05/lowlevel.c b/arch/arm/boards/hgs-gs05/lowlevel.c new file mode 100644 index 0000000000000000000000000000000000000000..fcd7cc77ba187965905fabd987aa88c447650366 --- /dev/null +++ b/arch/arm/boards/hgs-gs05/lowlevel.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2025 Pengutronix +// SPDX-FileCopyrightText: Leica Geosystems AG + +#include <debug_ll.h> + +#include <asm/cache.h> +#include <asm/barebox-arm.h> +#include <asm/mmu.h> +#include <asm/system.h> + +#include <boards/hgs/common.h> + +#include <mach/imx/debug_ll.h> +#include <mach/imx/esdctl.h> +#include <mach/imx/generic.h> +#include <mach/imx/imx-gpio.h> +#include <mach/imx/imx8mm-regs.h> +#include <mach/imx/iomux-mx8mm.h> +#include <mach/imx/imx8m-ccm-regs.h> +#include <mach/imx/xload.h> +#include <soc/imx8m/ddr.h> + +#include <mfd/pca9450.h> + +#include <pbl/i2c.h> +#include <pbl/pmic.h> + +#include <soc/imx8m/ddr.h> + +static struct pmic_config pca9450_cfg[] = { + /* BUCKxOUT_DVS0/1 control BUCK123 output */ + { PCA9450_BUCK123_DVS, 0x29 }, + + /* Buck 1 DVS control through PMIC_STBY_REQ */ + { PCA9450_BUCK1CTRL, 0x59 }, + + /* Set DVS1 to 0.8v for suspend */ + { PCA9450_BUCK1OUT_DVS1, 0x10 }, + + /* increase VDD_DRAM to 0.95v for 3Ghz DDR */ + { PCA9450_BUCK3OUT_DVS0, 0x1c }, + + /* + * VDD_DRAM needs off in suspend, set B3_ENMODE=10 + * (ON by PMIC_ON_REQ = H && PMIC_STBY_REQ = L) + */ + { PCA9450_BUCK3CTRL, 0x4a }, + + /* set VDD_SNVS_0V8 from default 0.85V */ + { PCA9450_LDO2CTRL, 0xc0 }, + + /* set WDOG_B_CFG to cold reset only LDO1/2 left enabled */ + { PCA9450_RESET_CTRL, 0xa1 }, +}; + +static void power_init_board(void) +{ + struct pbl_i2c *i2c; + + imx8mm_setup_pad(IMX8MM_PAD_I2C1_SCL_I2C1_SCL); + imx8mm_setup_pad(IMX8MM_PAD_I2C1_SDA_I2C1_SDA); + + imx8mm_early_clock_init(); + imx8m_ccgr_clock_enable(IMX8M_CCM_CCGR_I2C1); + + i2c = imx8m_i2c_early_init(IOMEM(MX8MM_I2C1_BASE_ADDR)); + + pmic_configure(i2c, 0x25, pca9450_cfg, ARRAY_SIZE(pca9450_cfg)); +} + +extern struct dram_timing_info hgs_gs05_dram_timing; +extern char __dtb_z_imx8mm_hgs_gs05_start[]; + +static void start_atf(void) +{ + /* + * If we are in EL3 we are running for the first time and need to + * initialize the DRAM and run TF-A (BL31). The TF-A will then jump + * to DRAM in EL2. + */ + if (current_el() != 3) + return; + + power_init_board(); + imx8mm_ddr_init(&hgs_gs05_dram_timing, DRAM_TYPE_LPDDR4); + + /* OP-TEE binary will be loaded at the 1G (start of RAM) */ + __imx8mm_load_and_start_image_via_tfa(__dtb_z_imx8mm_hgs_gs05_start, + (void *)(MX8M_DDR_CSD1_BASE_ADDR + OPTEE_SIZE)); +} + +/* + * Power-on execution flow might not be obvious for a very first read, + * so here's, hopefully helpful, summary: + * + * 1. MaskROM uploads PBL into OCRAM and that's where this function is + * executed for the first time. At entry the exception level is EL3. + * + * 2. DDR is initialized and the image is loaded from storage into DRAM. The PBL + * part is copied from OCRAM to the TF-A return address in DRAM. + * + * 3. TF-A is executed and exits into the PBL code in DRAM. TF-A has taken us + * from EL3 to EL2. + * + * 4. Standard barebox boot flow continues + */ +static __noreturn noinline void hgs_gs05_start(void) +{ + hgs_early_hw_init(HGS_HW_GS05); + + start_atf(); + + /* + * Standard entry we hit once we initialized both DDR and ATF + */ + imx8mm_barebox_entry(__dtb_z_imx8mm_hgs_gs05_start); +} + +ENTRY_FUNCTION(start_hgs_gs05, r0, r1, r2) +{ + imx8mm_cpu_lowlevel_init(); + + relocate_to_current_adr(); + setup_c(); + + hgs_gs05_start(); +} diff --git a/arch/arm/boards/hgs-gs05/lpddr4-timing.c b/arch/arm/boards/hgs-gs05/lpddr4-timing.c new file mode 100644 index 0000000000000000000000000000000000000000..9ad33b0639cf0cdf95c7adde881f9e72798d6044 --- /dev/null +++ b/arch/arm/boards/hgs-gs05/lpddr4-timing.c @@ -0,0 +1,1118 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2023 NXP +// SPDX-FileCopyrightText: Leica Geosystems AG +/* + * Code generated with DDR Tool v1.0.0. + */ + +#include <common.h> +#include <soc/imx8m/ddr.h> + +static struct dram_cfg_param ddr_ddrc_cfg[] = { + /** Initialize DDRC registers **/ + {0x3d400304, 0x1}, + {0x3d400030, 0x1}, + {0x3d400000, 0xa1080020}, + {0x3d400020, 0x223}, + {0x3d400024, 0x3a980}, + {0x3d400064, 0x5b0087}, + {0x3d4000d0, 0xc00305ba}, + {0x3d4000d4, 0x940000}, + {0x3d4000dc, 0xd4002d}, + {0x3d4000e0, 0x310000}, + {0x3d4000e8, 0x66004d}, + {0x3d4000ec, 0x16004d}, + {0x3d400100, 0x191e1920}, + {0x3d400104, 0x60630}, + {0x3d40010c, 0xb0b000}, + {0x3d400110, 0xe04080e}, + {0x3d400114, 0x2040c0c}, + {0x3d400118, 0x1010007}, + {0x3d40011c, 0x402}, + {0x3d400130, 0x20600}, + {0x3d400134, 0xc100002}, + {0x3d400138, 0x8d}, + {0x3d400144, 0x96004b}, + {0x3d400180, 0x2ee0017}, + {0x3d400184, 0x2605b8e}, + {0x3d400188, 0x0}, + {0x3d400190, 0x497820a}, + {0x3d400194, 0x80303}, + {0x3d4001b4, 0x170a}, + {0x3d4001a0, 0xe0400018}, + {0x3d4001a4, 0xdf00e4}, + {0x3d4001a8, 0x80000000}, + {0x3d4001b0, 0x11}, + {0x3d4001c0, 0x1}, + {0x3d4001c4, 0x1}, + {0x3d4000f4, 0x699}, + {0x3d400108, 0x70e1617}, + {0x3d400200, 0x1f}, + {0x3d40020c, 0x0}, + {0x3d400210, 0x1f1f}, + {0x3d400204, 0x80808}, + {0x3d400214, 0x7070707}, + {0x3d400218, 0xf070707}, + {0x3d40021c, 0xf0f}, + {0x3d400250, 0x29001701}, + {0x3d400254, 0x2c}, + {0x3d40025c, 0x4000030}, + {0x3d400264, 0x900093e7}, + {0x3d40026c, 0x2005574}, + {0x3d400400, 0x111}, + {0x3d400408, 0x72ff}, + {0x3d400494, 0x2100e07}, + {0x3d400498, 0x620096}, + {0x3d40049c, 0x1100e07}, + {0x3d4004a0, 0xc8012c}, + {0x3d402020, 0x21}, + {0x3d402024, 0x7d00}, + {0x3d402050, 0x20d040}, + {0x3d402064, 0xc0012}, + {0x3d4020dc, 0x840000}, + {0x3d4020e0, 0x310000}, + {0x3d4020e8, 0x66004d}, + {0x3d4020ec, 0x16004d}, + {0x3d402100, 0xa040305}, + {0x3d402104, 0x30407}, + {0x3d402108, 0x203060b}, + {0x3d40210c, 0x505000}, + {0x3d402110, 0x2040202}, + {0x3d402114, 0x2030202}, + {0x3d402118, 0x1010004}, + {0x3d40211c, 0x302}, + {0x3d402130, 0x20300}, + {0x3d402134, 0xa100002}, + {0x3d402138, 0x13}, + {0x3d402144, 0x14000a}, + {0x3d402180, 0x640004}, + {0x3d402190, 0x3818200}, + {0x3d402194, 0x80303}, + {0x3d4021b4, 0x100}, + {0x3d4020f4, 0x599}, + {0x3d403020, 0x21}, + {0x3d403024, 0x1f40}, + {0x3d403050, 0x20d040}, + {0x3d403064, 0x30005}, + {0x3d4030dc, 0x840000}, + {0x3d4030e0, 0x310000}, + {0x3d4030e8, 0x66004d}, + {0x3d4030ec, 0x16004d}, + {0x3d403100, 0xa010102}, + {0x3d403104, 0x30404}, + {0x3d403108, 0x203060b}, + {0x3d40310c, 0x505000}, + {0x3d403110, 0x2040202}, + {0x3d403114, 0x2030202}, + {0x3d403118, 0x1010004}, + {0x3d40311c, 0x302}, + {0x3d403130, 0x20300}, + {0x3d403134, 0xa100002}, + {0x3d403138, 0x5}, + {0x3d403144, 0x50003}, + {0x3d403180, 0x190004}, + {0x3d403190, 0x3818200}, + {0x3d403194, 0x80303}, + {0x3d4031b4, 0x100}, + {0x3d4030f4, 0x599}, + {0x3d400028, 0x0}, + +}; + +/* PHY Initialize Configuration */ +static struct dram_cfg_param ddr_ddrphy_cfg[] = { + {0x100a0, 0x0}, + {0x100a1, 0x1}, + {0x100a2, 0x2}, + {0x100a3, 0x3}, + {0x100a4, 0x4}, + {0x100a5, 0x5}, + {0x100a6, 0x6}, + {0x100a7, 0x7}, + {0x110a0, 0x0}, + {0x110a1, 0x1}, + {0x110a2, 0x3}, + {0x110a3, 0x4}, + {0x110a4, 0x5}, + {0x110a5, 0x2}, + {0x110a6, 0x7}, + {0x110a7, 0x6}, + {0x120a0, 0x0}, + {0x120a1, 0x1}, + {0x120a2, 0x3}, + {0x120a3, 0x2}, + {0x120a4, 0x5}, + {0x120a5, 0x4}, + {0x120a6, 0x7}, + {0x120a7, 0x6}, + {0x130a0, 0x0}, + {0x130a1, 0x1}, + {0x130a2, 0x2}, + {0x130a3, 0x3}, + {0x130a4, 0x4}, + {0x130a5, 0x5}, + {0x130a6, 0x6}, + {0x130a7, 0x7}, + {0x1005f, 0x1ff}, + {0x1015f, 0x1ff}, + {0x1105f, 0x1ff}, + {0x1115f, 0x1ff}, + {0x1205f, 0x1ff}, + {0x1215f, 0x1ff}, + {0x1305f, 0x1ff}, + {0x1315f, 0x1ff}, + {0x11005f, 0x1ff}, + {0x11015f, 0x1ff}, + {0x11105f, 0x1ff}, + {0x11115f, 0x1ff}, + {0x11205f, 0x1ff}, + {0x11215f, 0x1ff}, + {0x11305f, 0x1ff}, + {0x11315f, 0x1ff}, + {0x21005f, 0x1ff}, + {0x21015f, 0x1ff}, + {0x21105f, 0x1ff}, + {0x21115f, 0x1ff}, + {0x21205f, 0x1ff}, + {0x21215f, 0x1ff}, + {0x21305f, 0x1ff}, + {0x21315f, 0x1ff}, + {0x55, 0x1ff}, + {0x1055, 0x1ff}, + {0x2055, 0x1ff}, + {0x3055, 0x1ff}, + {0x4055, 0x1ff}, + {0x5055, 0x1ff}, + {0x6055, 0x1ff}, + {0x7055, 0x1ff}, + {0x8055, 0x1ff}, + {0x9055, 0x1ff}, + {0x200c5, 0x19}, + {0x1200c5, 0x7}, + {0x2200c5, 0x7}, + {0x2002e, 0x2}, + {0x12002e, 0x2}, + {0x22002e, 0x2}, + {0x90204, 0x0}, + {0x190204, 0x0}, + {0x290204, 0x0}, + {0x20024, 0x1ab}, + {0x2003a, 0x0}, + {0x120024, 0x1ab}, + {0x2003a, 0x0}, + {0x220024, 0x1ab}, + {0x2003a, 0x0}, + {0x20056, 0x3}, + {0x120056, 0x3}, + {0x220056, 0x3}, + {0x1004d, 0xe00}, + {0x1014d, 0xe00}, + {0x1104d, 0xe00}, + {0x1114d, 0xe00}, + {0x1204d, 0xe00}, + {0x1214d, 0xe00}, + {0x1304d, 0xe00}, + {0x1314d, 0xe00}, + {0x11004d, 0xe00}, + {0x11014d, 0xe00}, + {0x11104d, 0xe00}, + {0x11114d, 0xe00}, + {0x11204d, 0xe00}, + {0x11214d, 0xe00}, + {0x11304d, 0xe00}, + {0x11314d, 0xe00}, + {0x21004d, 0xe00}, + {0x21014d, 0xe00}, + {0x21104d, 0xe00}, + {0x21114d, 0xe00}, + {0x21204d, 0xe00}, + {0x21214d, 0xe00}, + {0x21304d, 0xe00}, + {0x21314d, 0xe00}, + {0x10049, 0xe38}, + {0x10149, 0xe38}, + {0x11049, 0xe38}, + {0x11149, 0xe38}, + {0x12049, 0xe38}, + {0x12149, 0xe38}, + {0x13049, 0xe38}, + {0x13149, 0xe38}, + {0x110049, 0xe38}, + {0x110149, 0xe38}, + {0x111049, 0xe38}, + {0x111149, 0xe38}, + {0x112049, 0xe38}, + {0x112149, 0xe38}, + {0x113049, 0xe38}, + {0x113149, 0xe38}, + {0x210049, 0xe38}, + {0x210149, 0xe38}, + {0x211049, 0xe38}, + {0x211149, 0xe38}, + {0x212049, 0xe38}, + {0x212149, 0xe38}, + {0x213049, 0xe38}, + {0x213149, 0xe38}, + {0x43, 0x63}, + {0x1043, 0x63}, + {0x2043, 0x63}, + {0x3043, 0x63}, + {0x4043, 0x63}, + {0x5043, 0x63}, + {0x6043, 0x63}, + {0x7043, 0x63}, + {0x8043, 0x63}, + {0x9043, 0x63}, + {0x20018, 0x3}, + {0x20075, 0x4}, + {0x20050, 0x0}, + {0x20008, 0x2ee}, + {0x120008, 0x64}, + {0x220008, 0x19}, + {0x20088, 0x9}, + {0x200b2, 0xdc}, + {0x10043, 0x5a1}, + {0x10143, 0x5a1}, + {0x11043, 0x5a1}, + {0x11143, 0x5a1}, + {0x12043, 0x5a1}, + {0x12143, 0x5a1}, + {0x13043, 0x5a1}, + {0x13143, 0x5a1}, + {0x1200b2, 0xdc}, + {0x110043, 0x5a1}, + {0x110143, 0x5a1}, + {0x111043, 0x5a1}, + {0x111143, 0x5a1}, + {0x112043, 0x5a1}, + {0x112143, 0x5a1}, + {0x113043, 0x5a1}, + {0x113143, 0x5a1}, + {0x2200b2, 0xdc}, + {0x210043, 0x5a1}, + {0x210143, 0x5a1}, + {0x211043, 0x5a1}, + {0x211143, 0x5a1}, + {0x212043, 0x5a1}, + {0x212143, 0x5a1}, + {0x213043, 0x5a1}, + {0x213143, 0x5a1}, + {0x200fa, 0x1}, + {0x1200fa, 0x1}, + {0x2200fa, 0x1}, + {0x20019, 0x1}, + {0x120019, 0x1}, + {0x220019, 0x1}, + {0x200f0, 0x660}, + {0x200f1, 0x0}, + {0x200f2, 0x4444}, + {0x200f3, 0x8888}, + {0x200f4, 0x5665}, + {0x200f5, 0x0}, + {0x200f6, 0x0}, + {0x200f7, 0xf000}, + {0x20025, 0x0}, + {0x2002d, 0x0}, + {0x12002d, 0x0}, + {0x22002d, 0x0}, + {0x200ca, 0x24}, + {0x1200ca, 0x24}, + {0x2200ca, 0x24}, + {0x200c7, 0x21}, + {0x1200c7, 0x21}, + {0x2200c7, 0x21}, + +}; + +/* P0 message block parameter for training firmware */ +static struct dram_cfg_param ddr_fsp0_cfg[] = { + {0xd0000, 0x0}, + {0x54003, 0xbb8}, + {0x54004, 0x2}, + {0x54005, 0x2828}, + {0x54006, 0x11}, + {0x54008, 0x131f}, + {0x54009, 0xc8}, + {0x5400b, 0x2}, + {0x54012, 0x110}, + {0x54019, 0x2dd4}, + {0x5401a, 0x31}, + {0x5401b, 0x4d66}, + {0x5401c, 0x4d00}, + {0x5401e, 0x16}, + {0x5401f, 0x2dd4}, + {0x54020, 0x31}, + {0x54021, 0x4d66}, + {0x54022, 0x4d00}, + {0x54024, 0x16}, + {0x5402b, 0x1000}, + {0x5402c, 0x1}, + {0x54032, 0xd400}, + {0x54033, 0x312d}, + {0x54034, 0x6600}, + {0x54035, 0x4d}, + {0x54036, 0x4d}, + {0x54037, 0x1600}, + {0x54038, 0xd400}, + {0x54039, 0x312d}, + {0x5403a, 0x6600}, + {0x5403b, 0x4d}, + {0x5403c, 0x4d}, + {0x5403d, 0x1600}, + {0xd0000, 0x1} +}; +/* P1 message block parameter for training firmware */ +static struct dram_cfg_param ddr_fsp1_cfg[] = { + {0xd0000, 0x0}, + {0x54002, 0x101}, + {0x54003, 0x190}, + {0x54004, 0x2}, + {0x54005, 0x2828}, + {0x54006, 0x11}, + {0x54008, 0x121f}, + {0x54009, 0xc8}, + {0x5400b, 0x2}, + {0x54012, 0x110}, + {0x54019, 0x84}, + {0x5401a, 0x31}, + {0x5401b, 0x4d66}, + {0x5401c, 0x4d00}, + {0x5401e, 0x16}, + {0x5401f, 0x84}, + {0x54020, 0x31}, + {0x54021, 0x4d66}, + {0x54022, 0x4d00}, + {0x54024, 0x16}, + {0x5402b, 0x1000}, + {0x5402c, 0x1}, + {0x54032, 0x8400}, + {0x54033, 0x3100}, + {0x54034, 0x6600}, + {0x54035, 0x4d}, + {0x54036, 0x4d}, + {0x54037, 0x1600}, + {0x54038, 0x8400}, + {0x54039, 0x3100}, + {0x5403a, 0x6600}, + {0x5403b, 0x4d}, + {0x5403c, 0x4d}, + {0x5403d, 0x1600}, + {0xd0000, 0x1} +}; +/* P2 message block parameter for training firmware */ +static struct dram_cfg_param ddr_fsp2_cfg[] = { + {0xd0000, 0x0}, + {0x54002, 0x102}, + {0x54003, 0x64}, + {0x54004, 0x2}, + {0x54005, 0x2828}, + {0x54006, 0x11}, + {0x54008, 0x121f}, + {0x54009, 0xc8}, + {0x5400b, 0x2}, + {0x54012, 0x110}, + {0x54019, 0x84}, + {0x5401a, 0x31}, + {0x5401b, 0x4d66}, + {0x5401c, 0x4d00}, + {0x5401e, 0x16}, + {0x5401f, 0x84}, + {0x54020, 0x31}, + {0x54021, 0x4d66}, + {0x54022, 0x4d00}, + {0x54024, 0x16}, + {0x5402b, 0x1000}, + {0x5402c, 0x1}, + {0x54032, 0x8400}, + {0x54033, 0x3100}, + {0x54034, 0x6600}, + {0x54035, 0x4d}, + {0x54036, 0x4d}, + {0x54037, 0x1600}, + {0x54038, 0x8400}, + {0x54039, 0x3100}, + {0x5403a, 0x6600}, + {0x5403b, 0x4d}, + {0x5403c, 0x4d}, + {0x5403d, 0x1600}, + {0xd0000, 0x1} +}; + + +/* P0 2D message block parameter for training firmware */ +static struct dram_cfg_param ddr_fsp0_2d_cfg[] = { + {0xd0000, 0x0}, + {0x54003, 0xbb8}, + {0x54004, 0x2}, + {0x54005, 0x2828}, + {0x54006, 0x11}, + {0x54008, 0x61}, + {0x54009, 0xc8}, + {0x5400b, 0x2}, + {0x5400d, 0x100}, + {0x5400f, 0x100}, + {0x54010, 0x1f7f}, + {0x54012, 0x110}, + {0x54019, 0x2dd4}, + {0x5401a, 0x31}, + {0x5401b, 0x4d66}, + {0x5401c, 0x4d00}, + {0x5401e, 0x16}, + {0x5401f, 0x2dd4}, + {0x54020, 0x31}, + {0x54021, 0x4d66}, + {0x54022, 0x4d00}, + {0x54024, 0x16}, + {0x5402b, 0x1000}, + {0x5402c, 0x1}, + {0x54032, 0xd400}, + {0x54033, 0x312d}, + {0x54034, 0x6600}, + {0x54035, 0x4d}, + {0x54036, 0x4d}, + {0x54037, 0x1600}, + {0x54038, 0xd400}, + {0x54039, 0x312d}, + {0x5403a, 0x6600}, + {0x5403b, 0x4d}, + {0x5403c, 0x4d}, + {0x5403d, 0x1600}, + {0xd0000, 0x1} +}; + +/* DRAM PHY init engine image */ +static struct dram_cfg_param ddr_phy_pie[] = { + {0xd0000, 0x0}, + {0x90000, 0x10}, + {0x90001, 0x400}, + {0x90002, 0x10e}, + {0x90003, 0x0}, + {0x90004, 0x0}, + {0x90005, 0x8}, + {0x90029, 0xb}, + {0x9002a, 0x480}, + {0x9002b, 0x109}, + {0x9002c, 0x8}, + {0x9002d, 0x448}, + {0x9002e, 0x139}, + {0x9002f, 0x8}, + {0x90030, 0x478}, + {0x90031, 0x109}, + {0x90032, 0x0}, + {0x90033, 0xe8}, + {0x90034, 0x109}, + {0x90035, 0x2}, + {0x90036, 0x10}, + {0x90037, 0x139}, + {0x90038, 0xf}, + {0x90039, 0x7c0}, + {0x9003a, 0x139}, + {0x9003b, 0x44}, + {0x9003c, 0x630}, + {0x9003d, 0x159}, + {0x9003e, 0x14f}, + {0x9003f, 0x630}, + {0x90040, 0x159}, + {0x90041, 0x47}, + {0x90042, 0x630}, + {0x90043, 0x149}, + {0x90044, 0x4f}, + {0x90045, 0x630}, + {0x90046, 0x179}, + {0x90047, 0x8}, + {0x90048, 0xe0}, + {0x90049, 0x109}, + {0x9004a, 0x0}, + {0x9004b, 0x7c8}, + {0x9004c, 0x109}, + {0x9004d, 0x0}, + {0x9004e, 0x1}, + {0x9004f, 0x8}, + {0x90050, 0x0}, + {0x90051, 0x45a}, + {0x90052, 0x9}, + {0x90053, 0x0}, + {0x90054, 0x448}, + {0x90055, 0x109}, + {0x90056, 0x40}, + {0x90057, 0x630}, + {0x90058, 0x179}, + {0x90059, 0x1}, + {0x9005a, 0x618}, + {0x9005b, 0x109}, + {0x9005c, 0x40c0}, + {0x9005d, 0x630}, + {0x9005e, 0x149}, + {0x9005f, 0x8}, + {0x90060, 0x4}, + {0x90061, 0x48}, + {0x90062, 0x4040}, + {0x90063, 0x630}, + {0x90064, 0x149}, + {0x90065, 0x0}, + {0x90066, 0x4}, + {0x90067, 0x48}, + {0x90068, 0x40}, + {0x90069, 0x630}, + {0x9006a, 0x149}, + {0x9006b, 0x10}, + {0x9006c, 0x4}, + {0x9006d, 0x18}, + {0x9006e, 0x0}, + {0x9006f, 0x4}, + {0x90070, 0x78}, + {0x90071, 0x549}, + {0x90072, 0x630}, + {0x90073, 0x159}, + {0x90074, 0xd49}, + {0x90075, 0x630}, + {0x90076, 0x159}, + {0x90077, 0x94a}, + {0x90078, 0x630}, + {0x90079, 0x159}, + {0x9007a, 0x441}, + {0x9007b, 0x630}, + {0x9007c, 0x149}, + {0x9007d, 0x42}, + {0x9007e, 0x630}, + {0x9007f, 0x149}, + {0x90080, 0x1}, + {0x90081, 0x630}, + {0x90082, 0x149}, + {0x90083, 0x0}, + {0x90084, 0xe0}, + {0x90085, 0x109}, + {0x90086, 0xa}, + {0x90087, 0x10}, + {0x90088, 0x109}, + {0x90089, 0x9}, + {0x9008a, 0x3c0}, + {0x9008b, 0x149}, + {0x9008c, 0x9}, + {0x9008d, 0x3c0}, + {0x9008e, 0x159}, + {0x9008f, 0x18}, + {0x90090, 0x10}, + {0x90091, 0x109}, + {0x90092, 0x0}, + {0x90093, 0x3c0}, + {0x90094, 0x109}, + {0x90095, 0x18}, + {0x90096, 0x4}, + {0x90097, 0x48}, + {0x90098, 0x18}, + {0x90099, 0x4}, + {0x9009a, 0x58}, + {0x9009b, 0xa}, + {0x9009c, 0x10}, + {0x9009d, 0x109}, + {0x9009e, 0x2}, + {0x9009f, 0x10}, + {0x900a0, 0x109}, + {0x900a1, 0x5}, + {0x900a2, 0x7c0}, + {0x900a3, 0x109}, + {0x900a4, 0x10}, + {0x900a5, 0x10}, + {0x900a6, 0x109}, + {0x40000, 0x811}, + {0x40020, 0x880}, + {0x40040, 0x0}, + {0x40060, 0x0}, + {0x40001, 0x4008}, + {0x40021, 0x83}, + {0x40041, 0x4f}, + {0x40061, 0x0}, + {0x40002, 0x4040}, + {0x40022, 0x83}, + {0x40042, 0x51}, + {0x40062, 0x0}, + {0x40003, 0x811}, + {0x40023, 0x880}, + {0x40043, 0x0}, + {0x40063, 0x0}, + {0x40004, 0x720}, + {0x40024, 0xf}, + {0x40044, 0x1740}, + {0x40064, 0x0}, + {0x40005, 0x16}, + {0x40025, 0x83}, + {0x40045, 0x4b}, + {0x40065, 0x0}, + {0x40006, 0x716}, + {0x40026, 0xf}, + {0x40046, 0x2001}, + {0x40066, 0x0}, + {0x40007, 0x716}, + {0x40027, 0xf}, + {0x40047, 0x2800}, + {0x40067, 0x0}, + {0x40008, 0x716}, + {0x40028, 0xf}, + {0x40048, 0xf00}, + {0x40068, 0x0}, + {0x40009, 0x720}, + {0x40029, 0xf}, + {0x40049, 0x1400}, + {0x40069, 0x0}, + {0x4000a, 0xe08}, + {0x4002a, 0xc15}, + {0x4004a, 0x0}, + {0x4006a, 0x0}, + {0x4000b, 0x623}, + {0x4002b, 0x15}, + {0x4004b, 0x0}, + {0x4006b, 0x0}, + {0x4000c, 0x4028}, + {0x4002c, 0x80}, + {0x4004c, 0x0}, + {0x4006c, 0x0}, + {0x4000d, 0xe08}, + {0x4002d, 0xc1a}, + {0x4004d, 0x0}, + {0x4006d, 0x0}, + {0x4000e, 0x623}, + {0x4002e, 0x1a}, + {0x4004e, 0x0}, + {0x4006e, 0x0}, + {0x4000f, 0x4040}, + {0x4002f, 0x80}, + {0x4004f, 0x0}, + {0x4006f, 0x0}, + {0x40010, 0x2604}, + {0x40030, 0x15}, + {0x40050, 0x0}, + {0x40070, 0x0}, + {0x40011, 0x708}, + {0x40031, 0x5}, + {0x40051, 0x0}, + {0x40071, 0x2002}, + {0x40012, 0x8}, + {0x40032, 0x80}, + {0x40052, 0x0}, + {0x40072, 0x0}, + {0x40013, 0x2604}, + {0x40033, 0x1a}, + {0x40053, 0x0}, + {0x40073, 0x0}, + {0x40014, 0x708}, + {0x40034, 0xa}, + {0x40054, 0x0}, + {0x40074, 0x2002}, + {0x40015, 0x4040}, + {0x40035, 0x80}, + {0x40055, 0x0}, + {0x40075, 0x0}, + {0x40016, 0x60a}, + {0x40036, 0x15}, + {0x40056, 0x1200}, + {0x40076, 0x0}, + {0x40017, 0x61a}, + {0x40037, 0x15}, + {0x40057, 0x1300}, + {0x40077, 0x0}, + {0x40018, 0x60a}, + {0x40038, 0x1a}, + {0x40058, 0x1200}, + {0x40078, 0x0}, + {0x40019, 0x642}, + {0x40039, 0x1a}, + {0x40059, 0x1300}, + {0x40079, 0x0}, + {0x4001a, 0x4808}, + {0x4003a, 0x880}, + {0x4005a, 0x0}, + {0x4007a, 0x0}, + {0x900a7, 0x0}, + {0x900a8, 0x790}, + {0x900a9, 0x11a}, + {0x900aa, 0x8}, + {0x900ab, 0x7aa}, + {0x900ac, 0x2a}, + {0x900ad, 0x10}, + {0x900ae, 0x7b2}, + {0x900af, 0x2a}, + {0x900b0, 0x0}, + {0x900b1, 0x7c8}, + {0x900b2, 0x109}, + {0x900b3, 0x10}, + {0x900b4, 0x2a8}, + {0x900b5, 0x129}, + {0x900b6, 0x8}, + {0x900b7, 0x370}, + {0x900b8, 0x129}, + {0x900b9, 0xa}, + {0x900ba, 0x3c8}, + {0x900bb, 0x1a9}, + {0x900bc, 0xc}, + {0x900bd, 0x408}, + {0x900be, 0x199}, + {0x900bf, 0x14}, + {0x900c0, 0x790}, + {0x900c1, 0x11a}, + {0x900c2, 0x8}, + {0x900c3, 0x4}, + {0x900c4, 0x18}, + {0x900c5, 0xe}, + {0x900c6, 0x408}, + {0x900c7, 0x199}, + {0x900c8, 0x8}, + {0x900c9, 0x8568}, + {0x900ca, 0x108}, + {0x900cb, 0x18}, + {0x900cc, 0x790}, + {0x900cd, 0x16a}, + {0x900ce, 0x8}, + {0x900cf, 0x1d8}, + {0x900d0, 0x169}, + {0x900d1, 0x10}, + {0x900d2, 0x8558}, + {0x900d3, 0x168}, + {0x900d4, 0x70}, + {0x900d5, 0x788}, + {0x900d6, 0x16a}, + {0x900d7, 0x1ff8}, + {0x900d8, 0x85a8}, + {0x900d9, 0x1e8}, + {0x900da, 0x50}, + {0x900db, 0x798}, + {0x900dc, 0x16a}, + {0x900dd, 0x60}, + {0x900de, 0x7a0}, + {0x900df, 0x16a}, + {0x900e0, 0x8}, + {0x900e1, 0x8310}, + {0x900e2, 0x168}, + {0x900e3, 0x8}, + {0x900e4, 0xa310}, + {0x900e5, 0x168}, + {0x900e6, 0xa}, + {0x900e7, 0x408}, + {0x900e8, 0x169}, + {0x900e9, 0x6e}, + {0x900ea, 0x0}, + {0x900eb, 0x68}, + {0x900ec, 0x0}, + {0x900ed, 0x408}, + {0x900ee, 0x169}, + {0x900ef, 0x0}, + {0x900f0, 0x8310}, + {0x900f1, 0x168}, + {0x900f2, 0x0}, + {0x900f3, 0xa310}, + {0x900f4, 0x168}, + {0x900f5, 0x1ff8}, + {0x900f6, 0x85a8}, + {0x900f7, 0x1e8}, + {0x900f8, 0x68}, + {0x900f9, 0x798}, + {0x900fa, 0x16a}, + {0x900fb, 0x78}, + {0x900fc, 0x7a0}, + {0x900fd, 0x16a}, + {0x900fe, 0x68}, + {0x900ff, 0x790}, + {0x90100, 0x16a}, + {0x90101, 0x8}, + {0x90102, 0x8b10}, + {0x90103, 0x168}, + {0x90104, 0x8}, + {0x90105, 0xab10}, + {0x90106, 0x168}, + {0x90107, 0xa}, + {0x90108, 0x408}, + {0x90109, 0x169}, + {0x9010a, 0x58}, + {0x9010b, 0x0}, + {0x9010c, 0x68}, + {0x9010d, 0x0}, + {0x9010e, 0x408}, + {0x9010f, 0x169}, + {0x90110, 0x0}, + {0x90111, 0x8b10}, + {0x90112, 0x168}, + {0x90113, 0x0}, + {0x90114, 0xab10}, + {0x90115, 0x168}, + {0x90116, 0x0}, + {0x90117, 0x1d8}, + {0x90118, 0x169}, + {0x90119, 0x80}, + {0x9011a, 0x790}, + {0x9011b, 0x16a}, + {0x9011c, 0x18}, + {0x9011d, 0x7aa}, + {0x9011e, 0x6a}, + {0x9011f, 0xa}, + {0x90120, 0x0}, + {0x90121, 0x1e9}, + {0x90122, 0x8}, + {0x90123, 0x8080}, + {0x90124, 0x108}, + {0x90125, 0xf}, + {0x90126, 0x408}, + {0x90127, 0x169}, + {0x90128, 0xc}, + {0x90129, 0x0}, + {0x9012a, 0x68}, + {0x9012b, 0x9}, + {0x9012c, 0x0}, + {0x9012d, 0x1a9}, + {0x9012e, 0x0}, + {0x9012f, 0x408}, + {0x90130, 0x169}, + {0x90131, 0x0}, + {0x90132, 0x8080}, + {0x90133, 0x108}, + {0x90134, 0x8}, + {0x90135, 0x7aa}, + {0x90136, 0x6a}, + {0x90137, 0x0}, + {0x90138, 0x8568}, + {0x90139, 0x108}, + {0x9013a, 0xb7}, + {0x9013b, 0x790}, + {0x9013c, 0x16a}, + {0x9013d, 0x1f}, + {0x9013e, 0x0}, + {0x9013f, 0x68}, + {0x90140, 0x8}, + {0x90141, 0x8558}, + {0x90142, 0x168}, + {0x90143, 0xf}, + {0x90144, 0x408}, + {0x90145, 0x169}, + {0x90146, 0xc}, + {0x90147, 0x0}, + {0x90148, 0x68}, + {0x90149, 0x0}, + {0x9014a, 0x408}, + {0x9014b, 0x169}, + {0x9014c, 0x0}, + {0x9014d, 0x8558}, + {0x9014e, 0x168}, + {0x9014f, 0x8}, + {0x90150, 0x3c8}, + {0x90151, 0x1a9}, + {0x90152, 0x3}, + {0x90153, 0x370}, + {0x90154, 0x129}, + {0x90155, 0x20}, + {0x90156, 0x2aa}, + {0x90157, 0x9}, + {0x90158, 0x0}, + {0x90159, 0x400}, + {0x9015a, 0x10e}, + {0x9015b, 0x8}, + {0x9015c, 0xe8}, + {0x9015d, 0x109}, + {0x9015e, 0x0}, + {0x9015f, 0x8140}, + {0x90160, 0x10c}, + {0x90161, 0x10}, + {0x90162, 0x8138}, + {0x90163, 0x10c}, + {0x90164, 0x8}, + {0x90165, 0x7c8}, + {0x90166, 0x101}, + {0x90167, 0x8}, + {0x90168, 0x0}, + {0x90169, 0x8}, + {0x9016a, 0x8}, + {0x9016b, 0x448}, + {0x9016c, 0x109}, + {0x9016d, 0xf}, + {0x9016e, 0x7c0}, + {0x9016f, 0x109}, + {0x90170, 0x0}, + {0x90171, 0xe8}, + {0x90172, 0x109}, + {0x90173, 0x47}, + {0x90174, 0x630}, + {0x90175, 0x109}, + {0x90176, 0x8}, + {0x90177, 0x618}, + {0x90178, 0x109}, + {0x90179, 0x8}, + {0x9017a, 0xe0}, + {0x9017b, 0x109}, + {0x9017c, 0x0}, + {0x9017d, 0x7c8}, + {0x9017e, 0x109}, + {0x9017f, 0x8}, + {0x90180, 0x8140}, + {0x90181, 0x10c}, + {0x90182, 0x0}, + {0x90183, 0x1}, + {0x90184, 0x8}, + {0x90185, 0x8}, + {0x90186, 0x4}, + {0x90187, 0x8}, + {0x90188, 0x8}, + {0x90189, 0x7c8}, + {0x9018a, 0x101}, + {0x90006, 0x0}, + {0x90007, 0x0}, + {0x90008, 0x8}, + {0x90009, 0x0}, + {0x9000a, 0x0}, + {0x9000b, 0x0}, + {0xd00e7, 0x400}, + {0x90017, 0x0}, + {0x9001f, 0x2a}, + {0x90026, 0x6a}, + {0x400d0, 0x0}, + {0x400d1, 0x101}, + {0x400d2, 0x105}, + {0x400d3, 0x107}, + {0x400d4, 0x10f}, + {0x400d5, 0x202}, + {0x400d6, 0x20a}, + {0x400d7, 0x20b}, + {0x2003a, 0x2}, + {0x2000b, 0x5d}, + {0x2000c, 0xbb}, + {0x2000d, 0x753}, + {0x2000e, 0x2c}, + {0x12000b, 0xc}, + {0x12000c, 0x19}, + {0x12000d, 0xfa}, + {0x12000e, 0x10}, + {0x22000b, 0x3}, + {0x22000c, 0x6}, + {0x22000d, 0x3e}, + {0x22000e, 0x10}, + {0x9000c, 0x0}, + {0x9000d, 0x173}, + {0x9000e, 0x60}, + {0x9000f, 0x6110}, + {0x90010, 0x2152}, + {0x90011, 0xdfbd}, + {0x90012, 0x60}, + {0x90013, 0x6152}, + {0x20010, 0x5a}, + {0x20011, 0x3}, + {0x40080, 0xe0}, + {0x40081, 0x12}, + {0x40082, 0xe0}, + {0x40083, 0x12}, + {0x40084, 0xe0}, + {0x40085, 0x12}, + {0x140080, 0xe0}, + {0x140081, 0x12}, + {0x140082, 0xe0}, + {0x140083, 0x12}, + {0x140084, 0xe0}, + {0x140085, 0x12}, + {0x240080, 0xe0}, + {0x240081, 0x12}, + {0x240082, 0xe0}, + {0x240083, 0x12}, + {0x240084, 0xe0}, + {0x240085, 0x12}, + {0x400fd, 0xf}, + {0x10011, 0x1}, + {0x10012, 0x1}, + {0x10013, 0x180}, + {0x10018, 0x1}, + {0x10002, 0x6209}, + {0x100b2, 0x1}, + {0x101b4, 0x1}, + {0x102b4, 0x1}, + {0x103b4, 0x1}, + {0x104b4, 0x1}, + {0x105b4, 0x1}, + {0x106b4, 0x1}, + {0x107b4, 0x1}, + {0x108b4, 0x1}, + {0x11011, 0x1}, + {0x11012, 0x1}, + {0x11013, 0x180}, + {0x11018, 0x1}, + {0x11002, 0x6209}, + {0x110b2, 0x1}, + {0x111b4, 0x1}, + {0x112b4, 0x1}, + {0x113b4, 0x1}, + {0x114b4, 0x1}, + {0x115b4, 0x1}, + {0x116b4, 0x1}, + {0x117b4, 0x1}, + {0x118b4, 0x1}, + {0x12011, 0x1}, + {0x12012, 0x1}, + {0x12013, 0x180}, + {0x12018, 0x1}, + {0x12002, 0x6209}, + {0x120b2, 0x1}, + {0x121b4, 0x1}, + {0x122b4, 0x1}, + {0x123b4, 0x1}, + {0x124b4, 0x1}, + {0x125b4, 0x1}, + {0x126b4, 0x1}, + {0x127b4, 0x1}, + {0x128b4, 0x1}, + {0x13011, 0x1}, + {0x13012, 0x1}, + {0x13013, 0x180}, + {0x13018, 0x1}, + {0x13002, 0x6209}, + {0x130b2, 0x1}, + {0x131b4, 0x1}, + {0x132b4, 0x1}, + {0x133b4, 0x1}, + {0x134b4, 0x1}, + {0x135b4, 0x1}, + {0x136b4, 0x1}, + {0x137b4, 0x1}, + {0x138b4, 0x1}, + {0x2003a, 0x2}, + {0xc0080, 0x2}, + {0xd0000, 0x1}, + +}; + +static struct dram_fsp_msg ddr_dram_fsp_msg[] = { + { + /* P0 3000mts 1D */ + .drate = 3000, + .fw_type = FW_1D_IMAGE, + .fsp_cfg = ddr_fsp0_cfg, + .fsp_cfg_num = ARRAY_SIZE(ddr_fsp0_cfg), + }, + { + /* P1 400mts 1D */ + .drate = 400, + .fw_type = FW_1D_IMAGE, + .fsp_cfg = ddr_fsp1_cfg, + .fsp_cfg_num = ARRAY_SIZE(ddr_fsp1_cfg), + }, + { + /* P2 100mts 1D */ + .drate = 100, + .fw_type = FW_1D_IMAGE, + .fsp_cfg = ddr_fsp2_cfg, + .fsp_cfg_num = ARRAY_SIZE(ddr_fsp2_cfg), + }, + { + /* P0 3000mts 2D */ + .drate = 3000, + .fw_type = FW_2D_IMAGE, + .fsp_cfg = ddr_fsp0_2d_cfg, + .fsp_cfg_num = ARRAY_SIZE(ddr_fsp0_2d_cfg), + }, +}; + +/* ddr timing config params */ +struct dram_timing_info hgs_gs05_dram_timing = { + .ddrc_cfg = ddr_ddrc_cfg, + .ddrc_cfg_num = ARRAY_SIZE(ddr_ddrc_cfg), + .ddrphy_cfg = ddr_ddrphy_cfg, + .ddrphy_cfg_num = ARRAY_SIZE(ddr_ddrphy_cfg), + .fsp_msg = ddr_dram_fsp_msg, + .fsp_msg_num = ARRAY_SIZE(ddr_dram_fsp_msg), + .ddrphy_pie = ddr_phy_pie, + .ddrphy_pie_num = ARRAY_SIZE(ddr_phy_pie), + .fsp_table = { 3000, 400, 100, }, +}; diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile index a84e09e388506c1e63d655ce75c251514ea5a489..1da0ac3a8f7999b1a20e592b623da5483ec0bf3f 100644 --- a/arch/arm/dts/Makefile +++ b/arch/arm/dts/Makefile @@ -41,6 +41,7 @@ lwl-$(CONFIG_MACH_GRINN_LITEBOARD) += imx6ul-liteboard.dtb.o lwl-$(CONFIG_MACH_GUF_SANTARO) += imx6q-guf-santaro.dtb.o lwl-$(CONFIG_MACH_GUF_VINCELL) += imx53-guf-vincell.dtb.o imx53-guf-vincell-lt.dtb.o lwl-$(CONFIG_MACH_GW_VENTANA) += imx6q-gw54xx.dtb.o +lwl-$(CONFIG_MACH_HGS_GS05) += imx8mm-hgs-gs05.dtb.o lwl-$(CONFIG_MACH_KAMSTRUP_MX7_CONCENTRATOR) += imx7d-flex-concentrator-mfg.dtb.o lwl-$(CONFIG_MACH_KARO_QSXP_ML81) += imx8mp-karo-qsxp-ml81-qsbase4.dtb.o lwl-$(CONFIG_MACH_KOENIGBAUER_ALPHAJET) += imx8mp-koenigbauer-alphajet.dtb.o diff --git a/arch/arm/dts/imx8m-hgs-common.dtsi b/arch/arm/dts/imx8m-hgs-common.dtsi new file mode 100644 index 0000000000000000000000000000000000000000..2e5276dae749c7a112721c3dc022acaf06d6b6c5 --- /dev/null +++ b/arch/arm/dts/imx8m-hgs-common.dtsi @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: (GPL-2.0 OR MIT) +// SPDX-FileCopyrightText: 2024 Pengutronix + +/ { + aliases { + state = &state; + }; + + chosen { + environment-emmc { + compatible = "barebox,environment"; + device-path = &usdhc3, "partname:barebox-environment"; + status = "disabled"; + }; + }; + + state: state { + compatible = "barebox,state"; + magic = <0xef784236>; + backend-type = "raw"; + backend = <&usdhc3>; + + /* + * barebox-state partition size: 1 MiB + * nr. of redundant copies: 3 + * ==> max. stride size: 1 MiB / 3 = 349525 Byte + * ==> keep it simple and align it to 256K + * + * stride size: 262144 Byte + * raw-header: - 16 Byte + * direct-storage: - 8 Byte + * ------------ + * max state size: 262120 Byte + * =========== + */ + backend-stridesize = <262144>; + + bootstate { + #address-cells = <1>; + #size-cells = <1>; + + systemA { + #address-cells = <1>; + #size-cells = <1>; + + remaining_attempts@0 { + reg = <0x0 0x4>; + type = "uint32"; + default = <3>; + }; + priority@4 { + reg = <0x4 0x4>; + type = "uint32"; + default = <20>; + }; + }; + + systemB { + #address-cells = <1>; + #size-cells = <1>; + + remaining_attempts@8 { + reg = <0x8 0x4>; + type = "uint32"; + default = <3>; + }; + priority@c { + reg = <0xc 0x4>; + type = "uint32"; + default = <10>; + }; + }; + + last_chosen@10 { + reg = <0x10 0x4>; + type = "uint32"; + }; + }; + }; +}; diff --git a/arch/arm/dts/imx8mm-hgs-gs05.dts b/arch/arm/dts/imx8mm-hgs-gs05.dts new file mode 100644 index 0000000000000000000000000000000000000000..c25cb44f17f78b06ef5291df8eba43911f0d3a32 --- /dev/null +++ b/arch/arm/dts/imx8mm-hgs-gs05.dts @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) +// SPDX-FileCopyrightText: 2020 NXP +// SPDX-FileCopyrightText: Leica Geosystems AG + +/dts-v1/; + +#include <arm64/freescale/imx8mm.dtsi> +#include "imx8mm.dtsi" +#include "imx8m-hgs-common.dtsi" + +/ { + /* compatible containing the correct revision and model is patched via board file */ + compatible = "hgs,gs05", "fsl,imx8mm"; + model = "Hexagon Geosystems GS05"; + + aliases { + efiwdt = &efi_wdt; + }; + + /* + * Prohibit OP-TEE from turning of the UART output if enabled via + * CFG_UART_BASE. To do so we need to specify a stdout-path which + * doesn't exist else OP-TEE turns off the UART. + */ + secure-chosen { + stdout-path = "/this-path/does/not/exist"; + }; +}; + +&fec1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_fec1>; + phy-mode = "rgmii-id"; + phy-handle = <ðphy0>; + status = "okay"; + + mdio { + #address-cells = <1>; + #size-cells = <0>; + + ethphy0: ethernet-phy@0 { + compatible = "ethernet-phy-ieee802.3-c22"; + reg = <0>; + + reset-gpios = <&gpio4 10 GPIO_ACTIVE_LOW>; + reset-assert-us = <10000>; + qca,disable-smarteee; + }; + }; +}; + +&flexspi { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flexspi0>; + status = "okay"; +}; + +&gpio1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio1>; +}; + +/* Used in M4 */ +&gpio4 { + status = "disabled"; +}; + +/* Used in M4 */ +&gpio5 { + status = "disabled"; +}; + +&state { + devel { + #address-cells = <1>; + #size-cells = <1>; + + m4@14 { + reg = <0x14 0x4>; + type = "enum32"; + names = "off", "on"; + default = <0>; + }; + }; + + product { + #address-cells = <1>; + #size-cells = <1>; + + hostname@18 { + reg = <0x18 0xf>; + type = "string"; + default = ""; + }; + + usb_model_name@28 { + reg = <0x28 0x1f>; + type = "string"; + default = ""; + }; + usb_serial_number@48 { + reg = <0x48 0xf>; + type = "string"; + default = ""; + }; + usb_pid@58 { + reg = <0x58 0x6>; + type = "string"; + default = ""; + }; + }; +}; + +/* console */ +&uart3 { + pinctrl-names = "default", "uart"; + pinctrl-0 = <&pinctrl_uart3_gpio>; + pinctrl-1 = <&pinctrl_uart3>; + status = "okay"; +}; + +&uart4 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart4>; + status = "okay"; + + /* EFI */ + mcu { + compatible = "hgs,efi-gs05"; + current-speed = <19200>; + #address-cells = <1>; + #size-cells = <0>; + + efi_wdt: watchdog { + compatible = "hgs,efi-gs05-wdt"; + }; + }; +}; + +&usdhc3 { /* eMMC */ + assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>; + assigned-clock-rates = <400000000>; + pinctrl-names = "default", "state_100mhz", "state_200mhz"; + pinctrl-0 = <&pinctrl_usdhc3>; + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; + bus-width = <8>; + non-removable; + status = "okay"; +}; + +&usbotg1 { + dr_mode = "otg"; + disable-over-current; + samsung,picophy-pre-emp-curr-control = <3>; + samsung,picophy-dc-vol-level-adjust = <7>; + ci-disable-lpm; + status = "okay"; +}; + +&usbotg2 { + dr_mode = "host"; + disable-over-current; + status = "okay"; +}; + +&wdog1 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_wdog>; + fsl,ext-reset-output; + status = "okay"; +}; + +&iomuxc { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_gpio>; + + pinctrl_fec1: fec1grp { + fsl,pins = < + MX8MM_IOMUXC_ENET_MDC_ENET1_MDC 0x3 + MX8MM_IOMUXC_ENET_MDIO_ENET1_MDIO 0x3 + MX8MM_IOMUXC_ENET_TD3_ENET1_RGMII_TD3 0x1f + MX8MM_IOMUXC_ENET_TD2_ENET1_RGMII_TD2 0x1f + MX8MM_IOMUXC_ENET_TD1_ENET1_RGMII_TD1 0x1f + MX8MM_IOMUXC_ENET_TD0_ENET1_RGMII_TD0 0x1f + MX8MM_IOMUXC_ENET_RD3_ENET1_RGMII_RD3 0x91 + MX8MM_IOMUXC_ENET_RD2_ENET1_RGMII_RD2 0x91 + MX8MM_IOMUXC_ENET_RD1_ENET1_RGMII_RD1 0x91 + MX8MM_IOMUXC_ENET_RD0_ENET1_RGMII_RD0 0x91 + MX8MM_IOMUXC_ENET_TXC_ENET1_RGMII_TXC 0x1f + MX8MM_IOMUXC_ENET_RXC_ENET1_RGMII_RXC 0x91 + MX8MM_IOMUXC_ENET_RX_CTL_ENET1_RGMII_RX_CTL 0x91 + MX8MM_IOMUXC_ENET_TX_CTL_ENET1_RGMII_TX_CTL 0x1f + MX8MM_IOMUXC_SAI1_TXFS_GPIO4_IO10 0x19 + >; + }; + + pinctrl_gpio1: gpio1grp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x100 + >; + }; + + pinctrl_usdhc3: usdhc3grp { + fsl,pins = < + MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK 0x190 + MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d0 + MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d0 + MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d0 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d0 + MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d0 + MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d0 + MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d0 + MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d0 + MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d0 + MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x190 + >; + }; + + pinctrl_usdhc3_100mhz: usdhc3-100mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK 0x194 + MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d4 + MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d4 + MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d4 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d4 + MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d4 + MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d4 + MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d4 + MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d4 + MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d4 + MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x194 + >; + }; + + pinctrl_usdhc3_200mhz: usdhc3-200mhzgrp { + fsl,pins = < + MX8MM_IOMUXC_NAND_WE_B_USDHC3_CLK 0x196 + MX8MM_IOMUXC_NAND_WP_B_USDHC3_CMD 0x1d6 + MX8MM_IOMUXC_NAND_DATA04_USDHC3_DATA0 0x1d6 + MX8MM_IOMUXC_NAND_DATA05_USDHC3_DATA1 0x1d6 + MX8MM_IOMUXC_NAND_DATA06_USDHC3_DATA2 0x1d6 + MX8MM_IOMUXC_NAND_DATA07_USDHC3_DATA3 0x1d6 + MX8MM_IOMUXC_NAND_RE_B_USDHC3_DATA4 0x1d6 + MX8MM_IOMUXC_NAND_CE2_B_USDHC3_DATA5 0x1d6 + MX8MM_IOMUXC_NAND_CE3_B_USDHC3_DATA6 0x1d6 + MX8MM_IOMUXC_NAND_CLE_USDHC3_DATA7 0x1d6 + MX8MM_IOMUXC_NAND_CE1_B_USDHC3_STROBE 0x196 + >; + }; + + pinctrl_uart3: uart3grp { + fsl,pins = < + MX8MM_IOMUXC_UART3_RXD_UART3_DCE_RX 0x0 + MX8MM_IOMUXC_UART3_TXD_UART3_DCE_TX 0x140 + >; + }; + + pinctrl_uart3_gpio: uart3-gpiogrp { + fsl,pins = < + MX8MM_IOMUXC_UART3_RXD_GPIO5_IO26 0x20 + MX8MM_IOMUXC_UART3_TXD_GPIO5_IO27 0x20 + >; + }; + + pinctrl_uart4: uart4grp { + fsl,pins = < + MX8MM_IOMUXC_UART4_RXD_UART4_DCE_RX 0x140 + MX8MM_IOMUXC_UART4_TXD_UART4_DCE_TX 0x0 + >; + }; + + pinctrl_flexspi0: flexspi0grp { + fsl,pins = < + MX8MM_IOMUXC_NAND_ALE_QSPI_A_SCLK 0x1c2 + MX8MM_IOMUXC_NAND_CE0_B_QSPI_A_SS0_B 0x82 + MX8MM_IOMUXC_NAND_DATA00_QSPI_A_DATA0 0x82 + MX8MM_IOMUXC_NAND_DATA01_QSPI_A_DATA1 0x82 + MX8MM_IOMUXC_NAND_DATA02_QSPI_A_DATA2 0x82 + MX8MM_IOMUXC_NAND_DATA03_QSPI_A_DATA3 0x82 + >; + }; + + pinctrl_wdog: wdoggrp { + fsl,pins = < + MX8MM_IOMUXC_GPIO1_IO02_WDOG1_WDOG_B 0x166 + >; + }; + + pinctrl_gpio: gpiogrp { + fsl,pins = < + /* GS05_LTE_OCx */ + MX8MM_IOMUXC_GPIO1_IO05_GPIO1_IO5 0x00 + /* GS05_PRESSURE_INT */ + MX8MM_IOMUXC_GPIO1_IO06_GPIO1_IO6 0x100 + /* GS05_IMX8_CPU_RDY */ + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x100 + /* GS05_IMX8_I2C_1_RSTx */ + MX8MM_IOMUXC_GPIO1_IO11_GPIO1_IO11 0x140 + /* GS05_IMX8_I2C_1_INTx */ + MX8MM_IOMUXC_GPIO1_IO12_GPIO1_IO12 0x00 + /* GS05_IMX8_USB1_OC_SOURCEx */ + MX8MM_IOMUXC_GPIO1_IO13_GPIO1_IO13 0x00 + /* GS05_IMX8_LTE_V180_ONx */ + MX8MM_IOMUXC_GPIO1_IO14_GPIO1_IO14 0x140 + /* GS05_IMX8_USB1_OC_SINKx */ + MX8MM_IOMUXC_GPIO1_IO15_GPIO1_IO15 0x00 + /* GS05_GNSS_RSTX */ + MX8MM_IOMUXC_SAI5_RXFS_GPIO3_IO19 0x20 + /* GS05_TPM_LP */ + MX8MM_IOMUXC_SAI5_RXC_GPIO3_IO20 0x100 + /* GS05_GNSS_EXTINT */ + MX8MM_IOMUXC_SAI5_RXD0_GPIO3_IO21 0x20 + /* GS05_TPM_IRQ */ + MX8MM_IOMUXC_SAI5_RXD1_GPIO3_IO22 0x140 + /* GS05_UHF_GPIO_0 */ + MX8MM_IOMUXC_SAI5_RXD2_GPIO3_IO23 0x100 + >; + }; +}; diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index d244c5758073c0f2c683e500e0d4ed0a6bff2cb5..92d21676240ea5cf7bdf31c3bca68ef82f3e69cf 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -612,6 +612,14 @@ config MACH_CONGATEC_QMX8P_SOM select IMX8M_DRAM select I2C_IMX_EARLY +config MACH_HGS_GS05 + bool "Hexagon Geosystems GS05 Board" + select ARCH_IMX8MM + select BOARD_HGS + select FIRMWARE_IMX8MM_ATF + select USB_GADGET_DRIVER_ARC_PBL + select HGS_EFI_WATCHDOG + config MACH_KOENIGBAUER_ALPHAJET bool "Koenig+Bauer AlphaJet" select MACH_CONGATEC_QMX8P_SOM diff --git a/common/boards/Kconfig b/common/boards/Kconfig index a9e1b75a76414e352d9af47ecf5901cf2bd05a84..4231867337f23b71b97ffa1a6b532478a7c23b70 100644 --- a/common/boards/Kconfig +++ b/common/boards/Kconfig @@ -1,5 +1,17 @@ # SPDX-License-Identifier: GPL-2.0-only +config BOARD_HGS + bool + select ARCH_IMX_ATF_PASS_BL_PARAMS + select ARM_SMCCC + select FIRMWARE_IMX_LPDDR4_PMU_TRAIN + select I2C_IMX_EARLY + select IMX8M_DRAM + select HABV4 + select MCI_IMX_ESDHC_PBL + select MFD_HGS_EFI + select OPTEE_APPLY_OVERLAY + config BOARD_QEMU bool "Extra support for QEMU-emulated boards" if COMPILE_TEST diff --git a/common/boards/Makefile b/common/boards/Makefile index 86d07e04a2ade09fe7d9ea50a81294628a594d51..25a3aefd568ac111a5c4f3ae3a0d64ed6ecbed67 100644 --- a/common/boards/Makefile +++ b/common/boards/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_BOARD_HGS) += hgs/ obj-$(CONFIG_BOARD_QEMU) += qemu/ obj-$(CONFIG_BOARD_QEMU_VIRT) += qemu-virt/ obj-$(CONFIG_BOARD_PHYTEC_SOM_DETECTION) += phytec/ diff --git a/common/boards/hgs/Makefile b/common/boards/hgs/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..5af27d05591eec5c4078bedd701191040f75bf24 --- /dev/null +++ b/common/boards/hgs/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-only +# SPDX-FileCopyrightText: 2025 Pengutronix +# SPDX-FileCopyrightText: Leica Geosystems AG + +pbl-y += pbl.o +obj-y += common.o +obj-y += lib.o diff --git a/common/boards/hgs/common.c b/common/boards/hgs/common.c new file mode 100644 index 0000000000000000000000000000000000000000..05f4afc5ed392baaa85d8378b006caee02351f8b --- /dev/null +++ b/common/boards/hgs/common.c @@ -0,0 +1,627 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2025 Pengutronix +// SPDX-FileCopyrightText: Leica Geosystems AG + +#include <block.h> +#include <boot.h> +#include <bootm.h> +#include <bootsource.h> +#include <command.h> +#include <common.h> +#include <envfs.h> +#include <environment.h> +#include <fastboot.h> +#include <fcntl.h> +#include <file-list.h> +#include <globalvar.h> +#include <gpio.h> +#include <hab.h> +#include <init.h> +#include <pinctrl.h> +#include <string.h> +#include <system-partitions.h> +#include <watchdog.h> + +#include <linux/string.h> +#include <linux/usb/gadget-multi.h> + +#include <mach/imx/bbu.h> +#include <mach/imx/generic.h> +#include <mach/imx/ocotp.h> +#include <mach/imx/ocotp-fusemap.h> + +#include <boards/hgs/common.h> + +static bool hgs_first_boot; +static bool hgs_enable_usbgadget; +static struct hgs_machine *priv; + +static unsigned int hgs_get_key_idx(void) +{ + return CONFIG_HABV4_SRK_INDEX; +} + +static void hgs_setup_default_machine_options(struct hgs_machine *machine) +{ + if (isempty(machine->mmc_alias)) + machine->mmc_alias = "mmc2"; + + if (!barebox_hostname_is_valid(machine->hostname)) { + const char *fallback_host, *soc_uid; + + switch (machine->type) { + case HGS_HW_GS05: + fallback_host = "GS05"; + break; + default: + fallback_host = "unknown-hgs-host"; + break; + } + + free(machine->hostname); + soc_uid = getenv("soc0.serial_number"); + machine->hostname = xasprintf("%s-%s", fallback_host, soc_uid); + } +} + +static int hgs_mmc_ensure_probed(struct hgs_machine *machine) +{ + struct device_node *np; + + /* + * We can't use bootsource_*() helpers since the correct MMC device + * needs to be available for USB-Serial-Download boots as well e.g. + * during first setup which performs the eMMC setup. + * + * The barebox /dev/mmcX enumeration matches the OF aliases + */ + np = of_find_node_by_alias(NULL, machine->mmc_alias); + if (IS_ERR(np)) { + dev_err(machine->dev, "Failed to find /aliases/%s OF node\n", + machine->mmc_alias); + return PTR_ERR(np); + } + + /* Ensure that the MMC and the below partitions are available */ + machine->mmc_cdev = of_cdev_find(np); + if (IS_ERR(machine->mmc_cdev)) { + dev_err(machine->dev, "Failed to find /dev/%s\n", + machine->mmc_alias); + return PTR_ERR(np); + } + + return 0; +} + +static int hgs_fixup_names(struct hgs_machine *machine) +{ + const struct device *dev = machine->dev; + int err; + + err = of_prepend_machine_compatible(NULL, machine->dts_compatible); + if (err) { + dev_err(dev, "Failed to fixup compatible\n"); + return -EINVAL; + } + + barebox_set_hostname(machine->hostname); + barebox_set_model(machine->model); + + return 0; +} + +static int hgs_setup_emmc(struct hgs_machine *machine) +{ + static const char * const mmc_commands[] = { "enh_area", "write_reliability" }; + int partitioning_completed; + char *cmd, *tmp; + unsigned int i; + + tmp = xasprintf("%s.partitioning_completed", machine->mmc_alias); + getenv_bool(tmp, &partitioning_completed); + free(tmp); + if (partitioning_completed) + return 0; + + for (i = 0; i < ARRAY_SIZE(mmc_commands); i++) { + cmd = xasprintf("mmc %s /dev/%s", mmc_commands[i], machine->mmc_alias); + if (run_command(cmd)) { + dev_err(machine->dev, + "Failed to run command: %s, skip eMMC partition-complete\n", cmd); + free(cmd); + return -EINVAL; + } + free(cmd); + } + + /* Make the final complete not part of the loop */ + cmd = xasprintf("mmc partition_complete /dev/%s", machine->mmc_alias); + run_command(cmd); + free(cmd); + + dev_info(machine->dev, "Initial eMMC setup completed successfully\n"); + return 0; +} + +static int +hgs_fastboot_cmd_flash(struct fastboot *fb, struct file_list_entry *entry, + const char *filename, size_t len) +{ + /* + * Ensure to trigger a data partition wipe if the the eMMC is going to + * be flashed. + */ + if (!strncmp(entry->name, "eMMC", 4)) + globalvar_add_simple("linux.bootargs.hgs_datapart_handling", + "format_data_partition"); + + /* We don't handle the flash, we just want to get notified */ + return FASTBOOT_CMD_FALLTHROUGH; +} + +static void hgs_register_bbu_handlers(struct hgs_machine *machine) +{ + char *dev; + int ret; + + dev = xasprintf("/dev/%s", machine->mmc_alias); + ret = imx8m_bbu_internal_mmcboot_register_handler("eMMC", dev, + BBU_HANDLER_FLAG_DEFAULT); + if (ret) { + dev_warn(machine->dev, "Failed to register bbu-eMMC\n"); + free(dev); + } +} + +static int hgs_console_open_fixup(struct device_node *root, void *context) +{ + struct hgs_machine *machine = context; + struct device_node *console_np; + struct property *property; + + console_np = of_find_node_by_alias(root, machine->console_alias); + if (!console_np) + return -EINVAL; + + property = of_rename_property(console_np, "pinctrl-1", "pinctrl-0"); + if (!property) + return -EINVAL; /* pinctrl-1 not found */ + + return 0; +} + +static int hgs_open_console(struct hgs_machine *machine) +{ + struct console_device *console; + struct pinctrl *pinctrl; + int err; + + err = of_device_ensure_probed_by_alias(machine->console_alias); + if (err) + return err; + + console = of_console_get_by_alias(machine->console_alias); + if (!console) + return -EINVAL; + + pinctrl = pinctrl_get_select(console->dev, "uart"); + if (IS_ERR(pinctrl)) + return PTR_ERR(pinctrl); + + err = console_set_active(console, CONSOLE_STDIOE); + if (err) + return err; + + console_set_stdoutpath(console, CONFIG_BAUDRATE); + + of_register_fixup(hgs_console_open_fixup, machine); + + return 0; +} + +static bool +hgs_data_partition_available(struct hgs_machine *machine) +{ + struct cdev *data_cdev; + + data_cdev = cdev_find_partition(machine->mmc_cdev, "data"); + /* + * MMC needs to be formated if the data partition is not available. + * This is a valid use-case. + */ + if (!data_cdev) { + dev_info(machine->dev, "MMC data partition not found, trigger (re-)format\n"); + return false; + } + + if (!cdev_is_block_partition(data_cdev)) { + dev_warn(machine->dev, "%s is not a block device, trigger (re-)format\n", + cdev_name(data_cdev)); + return false; + } + + return true; +} + +static void hgs_set_common_boot_options(struct hgs_machine *machine) +{ + boot_set_default("bootchooser rescue"); + + /* + * Check if the data partition does exist and if not inform the + * userspace to (re-)format the data partition. + */ + if (!hgs_data_partition_available(machine)) + globalvar_add_simple("linux.bootargs.hgs_datapart_handling", + "format_data_partition"); +} + +static bool hgs_field_return_mode(struct hgs_machine *machine) +{ + const struct device *dev = machine->dev; + unsigned int field_return = 0; + int ret; + + ret = imx_ocotp_read_field(MX8M_OCOTP_FIELD_RETURN, &field_return); + if (ret) { + dev_err(dev, "Failed to query the field-return status\n"); + return false; + } + + return field_return; +} + +static int hgs_development_boot(struct hgs_machine *machine) +{ + const char *run_mode; + + /* Allow barebox rw environment */ + of_device_enable_path("/chosen/environment-emmc"); + + if (hgs_field_return_mode(machine)) + run_mode = "field_return_mode"; + else + run_mode = "developer_mode"; + + /* Inform user-space about the run mode */ + globalvar_add_simple("linux.bootargs.hgs_runmode", run_mode); + + /* + * Init system.partitions for fastboot default, can be overridden in + * dev-mode via nv + */ + globalvar_add_simple("system.partitions", "/dev/mmc2(eMMC)"); + + hgs_enable_usbgadget = true; + + /* Allow shell and mux stdin and stdout correctly */ + return hgs_open_console(machine); +} + +static int hgs_release_boot(struct hgs_machine *machine) +{ + set_fastboot_bbu(0); + usbgadget_autostart(0); + + /* Only signed fit images are allowed */ + bootm_force_signed_images(); + + /* + * Explicit disable the console else the kernel may grap any console + * which is available. This can cause issues like BT issues, because + * the kernel may grap the BT serdev. + */ + globalvar_add_simple("linux.bootargs.console", "console=\"\""); + + return 0; +} + +static int hgs_run_first_boot(struct hgs_machine *machine) +{ + hgs_first_boot = true; + + hgs_open_console(machine); + + hgs_enable_usbgadget = true; + + /* + * Prohibit booting for the first boot and instead wait for explicit + * fastboot reset command. + */ + boot_set_default("does-not-exist"); + set_autoboot_state(AUTOBOOT_ABORT); + + /* + * Now we need to wait for the fastboot to reset the device to finish + * the eMMC setup and to boot from eMMC boot partition next time. + */ + return 0; +} + +static bool hgs_is_first_boot(struct hgs_machine *machine) +{ + /* + * Allow machines which are in early development stage to skip the + * initial setup + */ + if (machine->skip_firstboot_setup) { + dev_warn(machine->dev, "Skipping first boot procedure on development device!\n"); + return false; + } + + /* Device is not locked down -> this is the first boot */ + if (!imx_hab_device_locked_down()) + return true; + + return false; +} + +static int hgs_verify_key_usage(struct hgs_machine *machine) +{ + unsigned int current_key = hgs_get_key_idx(); + unsigned int revoked_keys_map; + int ret = 0; + int key; + + /* Nothing to do for us */ + if (current_key == 0) + goto out; + + if (bootsource_get() == BOOTSOURCE_SERIAL) + goto out; + + ret = imx_ocotp_read_field(MX8M_OCOTP_SRK_REVOKE, &revoked_keys_map); + if (ret) + goto out; + + /* Revoke all key below the current one */ + for (key = current_key - 1; key >= 0; key--) { + /* Key is already revoked -> skip */ + if (revoked_keys_map & BIT(key)) + continue; + dev_info(machine->dev, "Revoking SRK key %i\n", key); + imx_hab_revoke_key(key, true); + } + +out: + imx_ocotp_lock_srk_revoke(); + return ret; +} + +static int hgs_open_device(void) +{ + /* + * Expose barebox fastboot partition and enable fastboot to let the user + * flash an development barebox and to reboot the system via fastboot. + */ + hgs_enable_usbgadget = true; + + /* + * Prohibit booting and instead wait for explicit fastboot reset + * command. This is required to let the i.MX8M hardware re-evaluate the + * FIELD_RETURN fuse again. + */ + boot_set_default("does-not-exist"); + set_autoboot_state(AUTOBOOT_ABORT); + + /* Field return unlocked -> we need to open the device */ + return imx_hab_field_return(true); +} + +static bool hgs_open_device_request(void) +{ + if (IS_ENABLED(CONFIG_HABV4_CSF_UNLOCK_FIELD_RETURN)) { + if (!imx_ocotp_field_return_locked()) + return true; + } + + return false; +} + +int hgs_common_boot(struct hgs_machine *machine) +{ + int ret; + + hgs_setup_default_machine_options(machine); + + ret = hgs_mmc_ensure_probed(machine); + if (ret) + return ret; + + ret = hgs_fixup_names(machine); + if (ret) + return ret; + + hgs_register_bbu_handlers(machine); + + priv = machine; + + if (hgs_is_first_boot(machine)) + return hgs_run_first_boot(machine); + + if (hgs_open_device_request()) + return hgs_open_device(); + + ret = hgs_verify_key_usage(machine); + if (ret) + return ret; + + hgs_set_common_boot_options(machine); + + if (hgs_get_built_type() == HGS_DEV_BUILD) + return hgs_development_boot(machine); + else + return hgs_release_boot(machine); +} + +/* --------------------- Additional initcalls ---------------------- */ +struct hgs_fusemap { + uint32_t field; + unsigned int val; +}; + +#define SIMPLE_FUSE(fuse) \ +{ \ + .field = fuse, \ + .val = 0x1, \ +} + +#define CUSTOM_FUSE(fuse, _val) \ +{ \ + .field = fuse, \ + .val = _val, \ +} + +/* + * We need to run this after the environment_initcall() is done since we need + * access to /env. + */ +static int hgs_run_first_boot_setup(void) +{ + unsigned int flags = IMX_SRK_HASH_WRITE_PERMANENT | + IMX_SRK_HASH_WRITE_LOCK; + const struct hgs_fusemap common_fusemap[] = { + /* Security */ + /* MX8M_OCOTP_SEC_CONFIG[1] is done during imx_hab_lockdown_device() */ + /* MX8M_OCOTP_SRK_HASH[255:0] is done during imx_hab_write_srk_hash_file() */ + SIMPLE_FUSE(MX8M_OCOTP_TZASC_EN), + /* Debug */ + SIMPLE_FUSE(MX8M_OCOTP_KTE), + SIMPLE_FUSE(MX8M_OCOTP_SJC_DISABLE), + CUSTOM_FUSE(MX8M_OCOTP_JTAG_SMODE, 0x3), + SIMPLE_FUSE(MX8M_OCOTP_JTAG_HEO), + /* Boot */ + SIMPLE_FUSE(MX8M_OCOTP_FORCE_COLD_BOOT), + SIMPLE_FUSE(MX8M_OCOTP_RECOVERY_SDMMC_BOOT_DIS), + /* eFuse locks */ + CUSTOM_FUSE(MX8M_OCOTP_USB_ID_LOCK, 0x3), + SIMPLE_FUSE(MX8M_OCOTP_SJC_RESP_LOCK), + /* MX8M_OCOTP_SRK_LOCK is done during imx_hab_write_srk_hash_file() */ + { /* sentinel */ } + }; + const struct hgs_fusemap imx8mp_fusemap[] = { + /* Boot */ + SIMPLE_FUSE(MX8MP_OCOTP_ROM_NO_LOG), + { /* sentinel */ } + }; + const struct hgs_fusemap *iter; + struct device *dev = priv->dev; + struct watchdog *wdg; + int err; + + if (!hgs_first_boot) + return 0; + + /* Before doing anything inform the EFI to not power-cycle us */ + wdg = watchdog_get_by_name("efiwdt"); + if (wdg) { + err = watchdog_ping(wdg); + if (err) + dev_warn(dev, "Failed to ping the EFI watchdog\n"); + } else { + dev_warn(dev, "Failed to find and ping EFI watchdog\n"); + } + + /* eMMC setup must always run first! */ + err = hgs_setup_emmc(priv); + if (err) + return err; + + err = imx_hab_write_srk_hash_file("/env/imx-srk-fuse.bin", flags); + if (err && err != -EEXIST) { + dev_err(dev, "Failed to burn SRK fuses\n"); + return err; + } + dev_info(dev, "SRK fuses burnt successfully\n"); + + err = imx_ocotp_permanent_write(1); + if (err) { + dev_err(dev, "Failed to enable permanent write\n"); + return err; + } + + for (iter = &common_fusemap[0]; iter->field; iter++) + err |= imx_ocotp_write_field(iter->field, iter->val); + + if (cpu_is_mx8mp()) { + for (iter = &imx8mp_fusemap[0]; iter->field; iter++) + err |= imx_ocotp_write_field(iter->field, iter->val); + } + + imx_ocotp_permanent_write(0); + + if (err) { + dev_err(dev, "Failed to burn individual fuses\n"); + return err; + } + dev_info(dev, "Burning of individual fuses succeeded\n"); + + /* + * Lockdown the device at the end since this signals barebox that the + * initial (first-boot) is done. + */ + err = imx_hab_lockdown_device(flags); + if (err) { + dev_err(dev, "Failed to lockdown the device\n"); + return err; + } + dev_info(dev, "Lockdown of the device succeeded\n"); + return 0; +} +postenvironment_initcall(hgs_run_first_boot_setup); + +/* + * Notify the PP4 at the latest point to ensure that barebox was started + * properly. If this function is not reached the PP4 timeout of 10sec is + * triggered which puts us into serial-downloader mode. + */ +static int hgs_notify_pp4(void) +{ + int ret; + + if (!priv) + return 0; + + ret = gpio_request_one(priv->pp4_gpio, GPIOF_OUT_INIT_HIGH, "pp4-cpu-rdy"); + if (ret) + return ret; + + return 0; +} +postenvironment_initcall(hgs_notify_pp4); + +/* + * Custom USB gadget handling since we need to get notified upon the flash of + * the data partition. The setup is done very late like the + * usbgadget_autostart_init() since we need to ensure that the NV is loaded + * properly for development case. + */ +static int hgs_usbgadget_autostart(void) +{ + struct usbgadget_funcs funcs = {}; + struct f_multi_opts *opts; + int ret; + + if (!hgs_enable_usbgadget) + return 0; + + /* + * Some HW is missing a HW serial connecotr. Fastboot is used for file + * download. + */ + funcs.flags |= USBGADGET_EXPORT_BBU | USBGADGET_FASTBOOT | USBGADGET_ACM; + + opts = usbgadget_prepare(&funcs); + if (IS_ERR(opts)) + return PTR_ERR(opts); + + /* Custom hook to get notified once the user want to flash something */ + opts->fastboot_opts.cmd_flash = hgs_fastboot_cmd_flash; + + ret = usbgadget_register(opts); + if (ret) + usb_multi_opts_release(opts); + + return ret; +} +postenvironment_initcall(hgs_usbgadget_autostart); diff --git a/common/boards/hgs/lib.c b/common/boards/hgs/lib.c new file mode 100644 index 0000000000000000000000000000000000000000..b80206352727c14222d296410947f82df8b279f5 --- /dev/null +++ b/common/boards/hgs/lib.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2025 Pengutronix +// SPDX-FileCopyrightText: Leica Geosystems AG + +#define pr_fmt(fmt) "hgs-lib: " fmt + +#include <common.h> +#include <linux/stddef.h> +#include <linux/hex.h> + +#include <boards/hgs/common.h> + +#define HGS_BOARD_REV(_id, _str) { \ + .id = _id, \ + .str = _str, \ +} + +#define HGS_BOARD_REV_SIMPLE(_id) \ + HGS_BOARD_REV(HGS_BOARD_REV##_id, #_id) + +static const struct hgs_board_revision hgs_revision_table[] = { + HGS_BOARD_REV_SIMPLE(_A), + HGS_BOARD_REV_SIMPLE(_B), + HGS_BOARD_REV_SIMPLE(_C), + HGS_BOARD_REV_SIMPLE(_D), + HGS_BOARD_REV_SIMPLE(_E), +}; + +const struct hgs_board_revision * +hgs_get_rev_from_part_trace(const struct hgs_part_trace_code *code) +{ + const struct hgs_board_revision *rev = hgs_revision_table; + + for (; rev->str; rev++) + if (!memcmp(code->material_revision, rev->str, + sizeof(code->material_revision))) + return rev; + + return NULL; +} + +const u32 +hgs_get_artno_from_part_trace(const struct hgs_part_trace_code *code) +{ + __be32 res = 0; + u8 tmp[8]; + int err; + + /* + * Art-no. has 7-digits, add a leading '0' to align it to 8 and make + * use of hex2bin + */ + memset(tmp, '0', sizeof(tmp)); + memcpy(tmp + 1, code->art_number, sizeof(code->art_number)); + err = hex2bin((u8 *)&res, tmp, sizeof(res)); + + return err ? 0 : be32_to_cpu(res); +} + +struct hgs_machine *hgs_get_last_variant_entry(struct hgs_machine *variants) +{ + struct hgs_machine *last_entry = NULL; + + if (!variants->dts_compatible) { + pr_warn("%s: Invalid input\n", __func__); + return ERR_PTR(-EINVAL); + } + + for (; variants->dts_compatible; variants++) + last_entry = variants; + + return last_entry; +} diff --git a/common/boards/hgs/pbl.c b/common/boards/hgs/pbl.c new file mode 100644 index 0000000000000000000000000000000000000000..1d45545a93e9f6407a85b67c0e1aa203073c390e --- /dev/null +++ b/common/boards/hgs/pbl.c @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2025 Pengutronix +// SPDX-FileCopyrightText: Leica Geosystems AG + +#include <debug_ll.h> +#include <pbl.h> + +#include <mach/imx/debug_ll.h> +#include <mach/imx/generic.h> +#include <mach/imx/imx-gpio.h> +#include <mach/imx/imx8m-ccm-regs.h> +#include <mach/imx/iomux-mx8mp.h> +#include <mach/imx/iomux-mx8mm.h> +#include <mach/imx/iomux-v3.h> + +#include <boards/hgs/common.h> + +struct hgs_hw_early_cfg {; + void __iomem *uart_base; + void __iomem *iomux_base; + + unsigned int pp4_gpio_num; + void __iomem *pp4_gpio_base; + + iomux_v3_cfg_t *mux_cfg_rel; + unsigned int mux_cfg_rel_num; + iomux_v3_cfg_t *mux_cfg_dev; + unsigned int mux_cfg_dev_num; +}; + +#define GS05_UART_PAD_CTRL MUX_PAD_CTRL(PAD_CTL_DSE_3P3V_45_OHM) +#define GS05_PP4_PAD_CTRL MUX_PAD_CTRL(MX8MM_PAD_CTL_PE | MX8MM_PAD_CTL_DSE6) + +/* Mux console pads explicit to GPIO */ +static iomux_v3_cfg_t hgs_gs05_iomuxc_release[] = { + IMX8MM_PAD_UART3_TXD_GPIO5_IO27 | GS05_UART_PAD_CTRL, + IMX8MM_PAD_UART3_RXD_GPIO5_IO26 | GS05_UART_PAD_CTRL, + IMX8MM_PAD_GPIO1_IO10_GPIO1_IO10 | GS05_PP4_PAD_CTRL, +}; + +static iomux_v3_cfg_t hgs_gs05_iomuxc_development[] = { + IMX8MM_PAD_UART3_TXD_UART3_TX | GS05_UART_PAD_CTRL, + IMX8MM_PAD_GPIO1_IO10_GPIO1_IO10 | GS05_PP4_PAD_CTRL, +}; + +static struct hgs_hw_early_cfg hgs_hw_early_config[] = { + [HGS_HW_GS05] = { + .uart_base = IOMEM(MX8M_UART3_BASE_ADDR), + .iomux_base = IOMEM(MX8MM_IOMUXC_BASE_ADDR), + .pp4_gpio_num = 10, + .pp4_gpio_base = IOMEM(MX8MM_GPIO1_BASE_ADDR), + .mux_cfg_rel = hgs_gs05_iomuxc_release, + .mux_cfg_rel_num = ARRAY_SIZE(hgs_gs05_iomuxc_release), + .mux_cfg_dev = hgs_gs05_iomuxc_development, + .mux_cfg_dev_num = ARRAY_SIZE(hgs_gs05_iomuxc_development), + }, +}; + +static void hgs_early_setup_iomuxc(struct hgs_hw_early_cfg *cfg) +{ + unsigned int mux_cfg_num, i; + iomux_v3_cfg_t *mux_cfg; + + if (!cfg) + return; + + if (hgs_get_built_type() == HGS_DEV_BUILD) { + mux_cfg_num = cfg->mux_cfg_dev_num; + mux_cfg = cfg->mux_cfg_dev; + } else { + mux_cfg_num = cfg->mux_cfg_rel_num; + mux_cfg = cfg->mux_cfg_rel; + } + + for (i = 0; i < mux_cfg_num; i++) + imx8m_setup_pad(cfg->iomux_base, mux_cfg[i]); +} + +void hgs_early_hw_init(const enum hgs_hw hw) +{ + struct hgs_hw_early_cfg *cfg = &hgs_hw_early_config[hw]; + void __iomem *uart = cfg->uart_base; + + hgs_early_setup_iomuxc(cfg); + + /* Set PP4 CPU_RDY signal to 0 till barebox is fully booted */ + imx8m_gpio_direction_output(cfg->pp4_gpio_base, cfg->pp4_gpio_num, 0); + + /* + * UART enable could be skipped in release use-case but the TF-A + * requires a running UART. Therefore we keep it on but mux the pads to + * GPIO functions. + */ + imx8m_early_setup_uart_clock(); + imx8m_uart_setup(uart); + + pbl_set_putc(imx_uart_putc, uart); + + putc_ll('>'); +} diff --git a/images/Makefile.imx b/images/Makefile.imx index f66c0af6a43283a616933a2b2a137754b8a68240..0cc2cb29f0f7caf37794c243b1c7edbb07a9c7f0 100644 --- a/images/Makefile.imx +++ b/images/Makefile.imx @@ -493,6 +493,8 @@ $(call build_imx8m_habv4img, CONFIG_MACH_PROTONIC_IMX8M, start_prt_prt8mm, proto $(call build_imx8m_habv4img, CONFIG_MACH_INNOCOMM_WB15, start_innocomm_wb15_evk, innocomm-imx8mm-wb15/flash-header-imx8mm-wb15, innocomm-imx8mm-wb15-evk) +$(call build_imx8m_habv4img, CONFIG_MACH_HGS_GS05, start_hgs_gs05, hgs-gs05/flash-header-gs05, hgs-gs05) + # ----------------------- i.MX8mn based boards -------------------------- $(call build_imx8m_habv4img, CONFIG_MACH_NXP_IMX8MN_EVK, start_nxp_imx8mn_evk, nxp-imx8mn-evk/flash-header-imx8mn-evk, nxp-imx8mn-evk) diff --git a/include/boards/hgs/common.h b/include/boards/hgs/common.h new file mode 100644 index 0000000000000000000000000000000000000000..17b69727f5a5785f5104293c247677845ecb8013 --- /dev/null +++ b/include/boards/hgs/common.h @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2025 Pengutronix */ +/* SPDX-FileCopyrightText: Leica Geosystems AG */ + +#ifndef HGS_COMMON_H +#define HGS_COMMON_H + +#include <linux/types.h> + +enum hgs_hw { + HGS_HW_GS05, + NUM_HGS_HW +}; + +enum hgs_built_type { + HGS_DEV_BUILD, + HGS_REL_BUILD +}; + +struct hgs_part_trace_code { + /* Art. Number (e.g. 0983441 – if 6 digit add 0 before) */ + u8 art_number[7]; + /* Material Revision (_A,_B,...,_Z,AA,AB,...,ZZ) */ + u8 material_revision[2]; + /* Vendor id of component manufacturer */ + u8 vendor_id[7]; + /* Production lot date (YYYYMMDD) */ + u8 production_date[8]; + /* Consecutive number (restart 00001 for each production date) */ + u8 consecutive_number[5]; +} __packed; + +enum hgs_board_rev { + HGS_BOARD_REV_A, + HGS_BOARD_REV_B, + HGS_BOARD_REV_C, + HGS_BOARD_REV_D, + HGS_BOARD_REV_E, +}; + +struct hgs_board_revision { + enum hgs_board_rev id; + const char *str; +}; + +#define HGS_MACHINE(_revid, _comp, _model) { \ + .revision = _revid, \ + .dts_compatible = _comp, \ + .model = _model \ +} + +struct hgs_machine { + enum hgs_hw type; + struct device *dev; + enum hgs_board_rev revision; + const char *dts_compatible; + const char *console_alias; + const char *model; + const char *mmc_alias; + struct cdev *mmc_cdev; + char *hostname; + unsigned int pp4_gpio; + + bool skip_firstboot_setup; +}; + +static inline enum hgs_built_type hgs_get_built_type(void) +{ + return CONFIG_HABV4_SRK_INDEX == 0 ? HGS_DEV_BUILD : HGS_REL_BUILD; +} + +enum hgs_tag; + +void hgs_early_hw_init(enum hgs_hw hw); +int hgs_common_boot(struct hgs_machine *machine); + +/* Helper functions */ +const struct hgs_board_revision * +hgs_get_rev_from_part_trace(const struct hgs_part_trace_code *code); +const u32 +hgs_get_artno_from_part_trace(const struct hgs_part_trace_code *code); +struct hgs_machine *hgs_get_last_variant_entry(struct hgs_machine *variants); + +#endif /* HGS_COMMON_H */ -- 2.47.3 ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 2026-02-05 15:45 ` [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 Marco Felsch @ 2026-02-06 13:47 ` Ahmad Fatoum 2026-02-06 14:07 ` SCHNEIDER Johannes 2026-02-06 17:12 ` Marco Felsch 2026-02-09 10:42 ` Sascha Hauer 1 sibling, 2 replies; 23+ messages in thread From: Ahmad Fatoum @ 2026-02-06 13:47 UTC (permalink / raw) To: Marco Felsch, Sascha Hauer, BAREBOX; +Cc: Johannes Schneider Hi, On 2/5/26 4:45 PM, Marco Felsch wrote: > This adds support for the Hexagon Geosystems GS05 which is part of the > System1600 platform. > > Co-developed-by: Johannes Schneider <johannes.schneider@leica-geosystems.com> fyi, correct procedure for Linux would be for co-developed-by to be followed by s-o-b, but I won't insist on it here. > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> > --- > +static int ar8031_phy_fixup(struct phy_device *phydev) > +{ > + /* enable rgmii rxc skew and phy mode select to RGMII copper */ > + phy_write(phydev, 0x1d, 0x1f); > + phy_write(phydev, 0x1e, 0x8); > + phy_write(phydev, 0x1d, 0x00); > + phy_write(phydev, 0x1e, 0x82ee); > + phy_write(phydev, 0x1d, 0x05); > + phy_write(phydev, 0x1e, 0x100); > + > + return 0; barebox supports qca,clk-out-frequency, qca,clk-out-strength and phy-mode properties to apply these fixups to the PHY. This is useful if you have the same PHY elsewhere, e.g. behind a switch as you can identify the specific PHY that should have these settings applied. It also allows a faster boot as you could skip network probe in barebox and do the fixups in Linux if the device tree lists them. Just for your information. As you guard this behind your board compatible, I can live with it. > +} > + > +static struct hgs_machine * > +hgs_gs05_get_board_from_legacy(const unsigned char *serial) > +{ > + struct hgs_gs05_legacy_machine *machine = hgs_gs05_legacy_variants; > + > + for (; machine->revision; machine++) > + if (serial[6] == machine->revision) > + return &machine->machine; > + > + return ERR_PTR(-EINVAL); > +} > + > +static struct hgs_machine * > +hgs_gs05_select_board(const unsigned char *serial, bool legacy_format) > +{ > + struct hgs_machine *machine = hgs_gs05_variants; > + const struct hgs_board_revision *rev; > + > + /* TODO: Remove legacy handling if no longer required */ > + if (legacy_format) > + return hgs_gs05_get_board_from_legacy(serial); > + > + rev = hgs_get_rev_from_part_trace((struct hgs_part_trace_code *)serial); > + if (!rev) > + return ERR_PTR(-EINVAL); > + > + for (; machine->dts_compatible; machine++) > + if (rev->id == machine->revision) > + return machine; > + > + return ERR_PTR(-EINVAL); > +} > + > +static u64 > +hgs_gs05_set_efi_poll_intervall(struct device *efid, u64 new_polling_interval) > +{ > + const char *old_interval_str; > + char *new_interval; > + u64 old_interval; > + > + old_interval_str = dev_get_param(efid->parent, "polling_interval"); > + kstrtoull(old_interval_str, 10, &old_interval); > + > + pr_debug("Update EFI UART-Rx poll interval: %llu ns -> %llu ns\n", > + old_interval, new_polling_interval); > + > + new_interval = basprintf("%llu", new_polling_interval); > + dev_set_param(efid->parent, "polling_interval", new_interval); > + free(new_interval); > + > + return old_interval; > +} > + > +/* '"' + sizeof(struct hgs_part_trace_code) + '"' + string delim '\0' */ > +#define HGS_GS05_SERIAL_NUMBER_CHARS \ > + (1 + sizeof(struct hgs_part_trace_code) + 1 + 1) > + > +static struct hgs_machine *hgs_gs05_get_board(struct device_d *dev) Should there be a v2, you can use the occasion to replace all device_d and driver_d with device and driver respectively. > + chosen { > + environment-emmc { > + compatible = "barebox,environment"; > + device-path = &usdhc3, "partname:barebox-environment"; > + status = "disabled"; > + }; > + }; Does your board happen to have the barebox env GPT partition type UUID? In that case, you could also control this via autoload_external_env() or env.autoprobe instead of having to hardcode anything in DT. > +/ { > + /* compatible containing the correct revision and model is patched via board file */ > + compatible = "hgs,gs05", "fsl,imx8mm"; > + model = "Hexagon Geosystems GS05"; > + > + aliases { > + efiwdt = &efi_wdt; Do you not have a kernel driver for the watchdog? You may want to use watchdog0 and watchdog1 in that case to be able to identify them reliably. > + }; > + > + /* > + * Prohibit OP-TEE from turning of the UART output if enabled via > + * CFG_UART_BASE. To do so we need to specify a stdout-path which > + * doesn't exist else OP-TEE turns off the UART. > + */ > + secure-chosen { > + stdout-path = "/this-path/does/not/exist"; ... :/ > +&usdhc3 { /* eMMC */ > + assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>; > + assigned-clock-rates = <400000000>; > + pinctrl-names = "default", "state_100mhz", "state_200mhz"; > + pinctrl-0 = <&pinctrl_usdhc3>; > + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; > + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; > + bus-width = <8>; > + non-removable; no-sd; no-sdio; to skip their detect? > + pinctrl_gpio1: gpio1grp { > + fsl,pins = < > + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x100 This looks a bit unconventional. Can't the consumer select this group? > +config BOARD_HGS > + bool > + select ARCH_IMX_ATF_PASS_BL_PARAMS > + select ARM_SMCCC > + select FIRMWARE_IMX_LPDDR4_PMU_TRAIN > + select I2C_IMX_EARLY > + select IMX8M_DRAM > + select HABV4 Do you need to select this one? I think it would be better without to allow it to be enabled in the defconfig without flipping HABv4 on for all other boards? > +static int hgs_console_open_fixup(struct device_node *root, void *context) > +{ > + struct hgs_machine *machine = context; > + struct device_node *console_np; > + struct property *property; > + > + console_np = of_find_node_by_alias(root, machine->console_alias); > + if (!console_np) > + return -EINVAL; > + > + property = of_rename_property(console_np, "pinctrl-1", "pinctrl-0"); Does this not yield an invalid DT when passed to the kernel? I think you want to either keep pinctrl-1 as is or shorten pinctrl-names as well. > + pinctrl = pinctrl_get_select(console->dev, "uart"); Nitpick: I think a name like "open" might be clearer? Cheers, Ahmad -- 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 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 2026-02-06 13:47 ` Ahmad Fatoum @ 2026-02-06 14:07 ` SCHNEIDER Johannes 2026-02-06 15:43 ` Marco Felsch 2026-02-06 17:12 ` Marco Felsch 1 sibling, 1 reply; 23+ messages in thread From: SCHNEIDER Johannes @ 2026-02-06 14:07 UTC (permalink / raw) To: Ahmad Fatoum, Marco Felsch, Sascha Hauer; +Cc: BAREBOX Hoi > > Hi, > > On 2/5/26 4:45 PM, Marco Felsch wrote: > > This adds support for the Hexagon Geosystems GS05 which is part of the > > System1600 platform. > > > > Co-developed-by: Johannes Schneider <johannes.schneider@leica-geosystems.com> > > fyi, correct procedure for Linux would be for co-developed-by to be > followed by s-o-b, but I won't insist on it here. > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> > > --- > some/very few of the original patches that went into this upstreamable version came from me - i'll leave it up to marco to either keep the co-devleoped-by, add my signed-of-by and/or have both. > > > > +static int ar8031_phy_fixup(struct phy_device *phydev) > > +{ > > + /* enable rgmii rxc skew and phy mode select to RGMII copper */ > > + phy_write(phydev, 0x1d, 0x1f); > > + phy_write(phydev, 0x1e, 0x8); > > + phy_write(phydev, 0x1d, 0x00); > > + phy_write(phydev, 0x1e, 0x82ee); > > + phy_write(phydev, 0x1d, 0x05); > > + phy_write(phydev, 0x1e, 0x100); > > + > > + return 0; > > barebox supports qca,clk-out-frequency, qca,clk-out-strength and > phy-mode properties to apply these fixups to the PHY. > > This is useful if you have the same PHY elsewhere, e.g. behind a switch > as you can identify the specific PHY that should have these settings > applied. It also allows a faster boot as you could skip network probe in > barebox and do the fixups in Linux if the device tree lists them. > > Just for your information. As you guard this behind your board > compatible, I can live with it. > the GS05 itself actually has no phy - at least the "customer relesae" one. the AR8033 phy is on a 'debug board'; alongside a ft232rq. > > +} > > + > > +static struct hgs_machine * > > +hgs_gs05_get_board_from_legacy(const unsigned char *serial) > > +{ > > + struct hgs_gs05_legacy_machine *machine = hgs_gs05_legacy_variants; > > + > > + for (; machine->revision; machine++) > > + if (serial[6] == machine->revision) > > + return &machine->machine; > > + > > + return ERR_PTR(-EINVAL); > > +} > > + > > +static struct hgs_machine * > > +hgs_gs05_select_board(const unsigned char *serial, bool legacy_format) > > +{ > > + struct hgs_machine *machine = hgs_gs05_variants; > > + const struct hgs_board_revision *rev; > > + > > + /* TODO: Remove legacy handling if no longer required */ > > + if (legacy_format) > > + return hgs_gs05_get_board_from_legacy(serial); > > + > > + rev = hgs_get_rev_from_part_trace((struct hgs_part_trace_code *)serial); > > + if (!rev) > > + return ERR_PTR(-EINVAL); > > + > > + for (; machine->dts_compatible; machine++) > > + if (rev->id == machine->revision) > > + return machine; > > + > > + return ERR_PTR(-EINVAL); > > +} > > + > > +static u64 > > +hgs_gs05_set_efi_poll_intervall(struct device *efid, u64 new_polling_interval) > > +{ > > + const char *old_interval_str; > > + char *new_interval; > > + u64 old_interval; > > + > > + old_interval_str = dev_get_param(efid->parent, "polling_interval"); > > + kstrtoull(old_interval_str, 10, &old_interval); > > + > > + pr_debug("Update EFI UART-Rx poll interval: %llu ns -> %llu ns\n", > > + old_interval, new_polling_interval); > > + > > + new_interval = basprintf("%llu", new_polling_interval); > > + dev_set_param(efid->parent, "polling_interval", new_interval); > > + free(new_interval); > > + > > + return old_interval; > > +} > > + > > +/* '"' + sizeof(struct hgs_part_trace_code) + '"' + string delim '\0' */ > > +#define HGS_GS05_SERIAL_NUMBER_CHARS \ > > + (1 + sizeof(struct hgs_part_trace_code) + 1 + 1) > > + > > +static struct hgs_machine *hgs_gs05_get_board(struct device_d *dev) > > Should there be a v2, you can use the occasion to replace all device_d > and driver_d with device and driver respectively. > > > + chosen { > > + environment-emmc { > > + compatible = "barebox,environment"; > > + device-path = &usdhc3, "partname:barebox-environment"; > > + status = "disabled"; > > + }; > > + }; > > Does your board happen to have the barebox env GPT partition type UUID? > In that case, you could also control this via autoload_external_env() > or env.autoprobe instead of having to hardcode anything in DT. > > > +/ { > > + /* compatible containing the correct revision and model is patched via board file */ > > + compatible = "hgs,gs05", "fsl,imx8mm"; > > + model = "Hexagon Geosystems GS05"; > > + > > + aliases { > > + efiwdt = &efi_wdt; > > Do you not have a kernel driver for the watchdog? You may want to use > watchdog0 and watchdog1 in that case to be able to identify them reliably. > good point - there would be also imx internal watchdog (connected to the pmic) gruß Johannes > > > + }; > > + > > + /* > > + * Prohibit OP-TEE from turning of the UART output if enabled via > > + * CFG_UART_BASE. To do so we need to specify a stdout-path which > > + * doesn't exist else OP-TEE turns off the UART. > > + */ > > + secure-chosen { > > + stdout-path = "/this-path/does/not/exist"; > > ... :/ > > > +&usdhc3 { /* eMMC */ > > + assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>; > > + assigned-clock-rates = <400000000>; > > + pinctrl-names = "default", "state_100mhz", "state_200mhz"; > > + pinctrl-0 = <&pinctrl_usdhc3>; > > + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; > > + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; > > + bus-width = <8>; > > + non-removable; > > no-sd; > no-sdio; > > to skip their detect? > > > + pinctrl_gpio1: gpio1grp { > > + fsl,pins = < > > + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x100 > > This looks a bit unconventional. Can't the consumer select this group? > > > +config BOARD_HGS > > + bool > > + select ARCH_IMX_ATF_PASS_BL_PARAMS > > + select ARM_SMCCC > > + select FIRMWARE_IMX_LPDDR4_PMU_TRAIN > > + select I2C_IMX_EARLY > > + select IMX8M_DRAM > > + select HABV4 > > Do you need to select this one? I think it would be better without to > allow it to be enabled in the defconfig without flipping HABv4 on for > all other boards? > > > +static int hgs_console_open_fixup(struct device_node *root, void *context) > > +{ > > + struct hgs_machine *machine = context; > > + struct device_node *console_np; > > + struct property *property; > > + > > + console_np = of_find_node_by_alias(root, machine->console_alias); > > + if (!console_np) > > + return -EINVAL; > > + > > + property = of_rename_property(console_np, "pinctrl-1", "pinctrl-0"); > > Does this not yield an invalid DT when passed to the kernel? > I think you want to either keep pinctrl-1 as is or shorten pinctrl-names > as well. > > > + pinctrl = pinctrl_get_select(console->dev, "uart"); > > Nitpick: I think a name like "open" might be clearer? > > > Cheers, > Ahmad > > -- > 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 | > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 2026-02-06 14:07 ` SCHNEIDER Johannes @ 2026-02-06 15:43 ` Marco Felsch 0 siblings, 0 replies; 23+ messages in thread From: Marco Felsch @ 2026-02-06 15:43 UTC (permalink / raw) To: SCHNEIDER Johannes; +Cc: BAREBOX, Ahmad Fatoum Hi Johannes, Ahmad, On 26-02-06, SCHNEIDER Johannes wrote: > Hoi > > > > Hi, > > > > On 2/5/26 4:45 PM, Marco Felsch wrote: > > > This adds support for the Hexagon Geosystems GS05 which is part of the > > > System1600 platform. > > > > > > Co-developed-by: Johannes Schneider <johannes.schneider@leica-geosystems.com> > > > > fyi, correct procedure for Linux would be for co-developed-by to be > > followed by s-o-b, but I won't insist on it here. > > > > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> > > > --- > > > > some/very few of the original patches that went into this upstreamable version > came from me - i'll leave it up to marco to either keep the co-devleoped-by, add > my signed-of-by and/or have both. I will add you sob if that is okay for you. > > > +static int ar8031_phy_fixup(struct phy_device *phydev) > > > +{ > > > + /* enable rgmii rxc skew and phy mode select to RGMII copper */ > > > + phy_write(phydev, 0x1d, 0x1f); > > > + phy_write(phydev, 0x1e, 0x8); > > > + phy_write(phydev, 0x1d, 0x00); > > > + phy_write(phydev, 0x1e, 0x82ee); > > > + phy_write(phydev, 0x1d, 0x05); > > > + phy_write(phydev, 0x1e, 0x100); > > > + > > > + return 0; > > > > barebox supports qca,clk-out-frequency, qca,clk-out-strength and > > phy-mode properties to apply these fixups to the PHY. Good to know! > > This is useful if you have the same PHY elsewhere, e.g. behind a switch > > as you can identify the specific PHY that should have these settings > > applied. It also allows a faster boot as you could skip network probe in > > barebox and do the fixups in Linux if the device tree lists them. Good point. > > Just for your information. As you guard this behind your board > > compatible, I can live with it. > > > > the GS05 itself actually has no phy - at least the "customer relesae" one. > the AR8033 phy is on a 'debug board'; alongside a ft232rq. > > > > +} > > > + > > > +static struct hgs_machine * > > > +hgs_gs05_get_board_from_legacy(const unsigned char *serial) > > > +{ > > > + struct hgs_gs05_legacy_machine *machine = hgs_gs05_legacy_variants; > > > + > > > + for (; machine->revision; machine++) > > > + if (serial[6] == machine->revision) > > > + return &machine->machine; > > > + > > > + return ERR_PTR(-EINVAL); > > > +} > > > + > > > +static struct hgs_machine * > > > +hgs_gs05_select_board(const unsigned char *serial, bool legacy_format) > > > +{ > > > + struct hgs_machine *machine = hgs_gs05_variants; > > > + const struct hgs_board_revision *rev; > > > + > > > + /* TODO: Remove legacy handling if no longer required */ > > > + if (legacy_format) > > > + return hgs_gs05_get_board_from_legacy(serial); > > > + > > > + rev = hgs_get_rev_from_part_trace((struct hgs_part_trace_code *)serial); > > > + if (!rev) > > > + return ERR_PTR(-EINVAL); > > > + > > > + for (; machine->dts_compatible; machine++) > > > + if (rev->id == machine->revision) > > > + return machine; > > > + > > > + return ERR_PTR(-EINVAL); > > > +} > > > + > > > +static u64 > > > +hgs_gs05_set_efi_poll_intervall(struct device *efid, u64 new_polling_interval) > > > +{ > > > + const char *old_interval_str; > > > + char *new_interval; > > > + u64 old_interval; > > > + > > > + old_interval_str = dev_get_param(efid->parent, "polling_interval"); > > > + kstrtoull(old_interval_str, 10, &old_interval); > > > + > > > + pr_debug("Update EFI UART-Rx poll interval: %llu ns -> %llu ns\n", > > > + old_interval, new_polling_interval); > > > + > > > + new_interval = basprintf("%llu", new_polling_interval); > > > + dev_set_param(efid->parent, "polling_interval", new_interval); > > > + free(new_interval); > > > + > > > + return old_interval; > > > +} > > > + > > > +/* '"' + sizeof(struct hgs_part_trace_code) + '"' + string delim '\0' */ > > > +#define HGS_GS05_SERIAL_NUMBER_CHARS \ > > > + (1 + sizeof(struct hgs_part_trace_code) + 1 + 1) > > > + > > > +static struct hgs_machine *hgs_gs05_get_board(struct device_d *dev) > > > > Should there be a v2, you can use the occasion to replace all device_d > > and driver_d with device and driver respectively. Sure! > > > + chosen { > > > + environment-emmc { > > > + compatible = "barebox,environment"; > > > + device-path = &usdhc3, "partname:barebox-environment"; > > > + status = "disabled"; > > > + }; > > > + }; > > > > Does your board happen to have the barebox env GPT partition type UUID? > > In that case, you could also control this via autoload_external_env() > > or env.autoprobe instead of having to hardcode anything in DT. Yes, we do use the GPT part-type UUID thanks for pointing this out. > > > +/ { > > > + /* compatible containing the correct revision and model is patched via board file */ > > > + compatible = "hgs,gs05", "fsl,imx8mm"; > > > + model = "Hexagon Geosystems GS05"; > > > + > > > + aliases { > > > + efiwdt = &efi_wdt; > > > > Do you not have a kernel driver for the watchdog? You may want to use > > watchdog0 and watchdog1 in that case to be able to identify them reliably. No we currently don't have a Linux driver for it and maybe never will (currently in discussion). Regards, Marco > > > > good point - there would be also imx internal watchdog (connected to the pmic) > > > gruß > Johannes > > > > > > + }; > > > + > > > + /* > > > + * Prohibit OP-TEE from turning of the UART output if enabled via > > > + * CFG_UART_BASE. To do so we need to specify a stdout-path which > > > + * doesn't exist else OP-TEE turns off the UART. > > > + */ > > > + secure-chosen { > > > + stdout-path = "/this-path/does/not/exist"; > > > > ... :/ > > > > > +&usdhc3 { /* eMMC */ > > > + assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>; > > > + assigned-clock-rates = <400000000>; > > > + pinctrl-names = "default", "state_100mhz", "state_200mhz"; > > > + pinctrl-0 = <&pinctrl_usdhc3>; > > > + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; > > > + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; > > > + bus-width = <8>; > > > + non-removable; > > > > no-sd; > > no-sdio; > > > > to skip their detect? > > > > > + pinctrl_gpio1: gpio1grp { > > > + fsl,pins = < > > > + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x100 > > > > This looks a bit unconventional. Can't the consumer select this group? > > > > > +config BOARD_HGS > > > + bool > > > + select ARCH_IMX_ATF_PASS_BL_PARAMS > > > + select ARM_SMCCC > > > + select FIRMWARE_IMX_LPDDR4_PMU_TRAIN > > > + select I2C_IMX_EARLY > > > + select IMX8M_DRAM > > > + select HABV4 > > > > Do you need to select this one? I think it would be better without to > > allow it to be enabled in the defconfig without flipping HABv4 on for > > all other boards? > > > > > +static int hgs_console_open_fixup(struct device_node *root, void *context) > > > +{ > > > + struct hgs_machine *machine = context; > > > + struct device_node *console_np; > > > + struct property *property; > > > + > > > + console_np = of_find_node_by_alias(root, machine->console_alias); > > > + if (!console_np) > > > + return -EINVAL; > > > + > > > + property = of_rename_property(console_np, "pinctrl-1", "pinctrl-0"); > > > > Does this not yield an invalid DT when passed to the kernel? > > I think you want to either keep pinctrl-1 as is or shorten pinctrl-names > > as well. > > > > > + pinctrl = pinctrl_get_select(console->dev, "uart"); > > > > Nitpick: I think a name like "open" might be clearer? > > > > > > Cheers, > > Ahmad > > > > -- > > 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 | > > > -- #gernperDu #CallMeByMyFirstName Pengutronix e.K. | | Steuerwalder Str. 21 | https://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 2026-02-06 13:47 ` Ahmad Fatoum 2026-02-06 14:07 ` SCHNEIDER Johannes @ 2026-02-06 17:12 ` Marco Felsch 1 sibling, 0 replies; 23+ messages in thread From: Marco Felsch @ 2026-02-06 17:12 UTC (permalink / raw) To: Ahmad Fatoum; +Cc: BAREBOX, Johannes Schneider On 26-02-06, Ahmad Fatoum wrote: > Hi, > > On 2/5/26 4:45 PM, Marco Felsch wrote: ... > > + }; > > + > > + /* > > + * Prohibit OP-TEE from turning of the UART output if enabled via > > + * CFG_UART_BASE. To do so we need to specify a stdout-path which > > + * doesn't exist else OP-TEE turns off the UART. > > + */ > > + secure-chosen { > > + stdout-path = "/this-path/does/not/exist"; > > ... :/ > > > +&usdhc3 { /* eMMC */ > > + assigned-clocks = <&clk IMX8MM_CLK_USDHC3_ROOT>; > > + assigned-clock-rates = <400000000>; > > + pinctrl-names = "default", "state_100mhz", "state_200mhz"; > > + pinctrl-0 = <&pinctrl_usdhc3>; > > + pinctrl-1 = <&pinctrl_usdhc3_100mhz>; > > + pinctrl-2 = <&pinctrl_usdhc3_200mhz>; > > + bus-width = <8>; > > + non-removable; > > no-sd; > no-sdio; > > to skip their detect? Yes, thanks! > > + pinctrl_gpio1: gpio1grp { > > + fsl,pins = < > > + MX8MM_IOMUXC_GPIO1_IO10_GPIO1_IO10 0x100 > > This looks a bit unconventional. Can't the consumer select this group? Good catch, this was required before we had the EFI driver. I will adapt the driver to request the pin accordingly. > > +config BOARD_HGS > > + bool > > + select ARCH_IMX_ATF_PASS_BL_PARAMS > > + select ARM_SMCCC > > + select FIRMWARE_IMX_LPDDR4_PMU_TRAIN > > + select I2C_IMX_EARLY > > + select IMX8M_DRAM > > + select HABV4 > > Do you need to select this one? I think it would be better without to > allow it to be enabled in the defconfig without flipping HABv4 on for > all other boards? Good point albeit this is secure-boot only platform it makes sense to enable it within the defconfig to benefit from the CI. We don't have a good CI setup for secure-boot builds, right? > > +static int hgs_console_open_fixup(struct device_node *root, void *context) > > +{ > > + struct hgs_machine *machine = context; > > + struct device_node *console_np; > > + struct property *property; > > + > > + console_np = of_find_node_by_alias(root, machine->console_alias); > > + if (!console_np) > > + return -EINVAL; > > + > > + property = of_rename_property(console_np, "pinctrl-1", "pinctrl-0"); > > Does this not yield an invalid DT when passed to the kernel? > I think you want to either keep pinctrl-1 as is or shorten pinctrl-names > as well. FYI, what the kernel-DT is doing: | pinctrl-names = "default"; | pinctrl-0 = <&pinctrl_uart3_gpio>; | pinctrl-1 = <&pinctrl_uart3>; The of_rename_property() will delete the pinctrl-0 first and and later on renames pinctrl-1 to pinctrl-0. Therefore we don't have issues with invalid DTs. This is a bit different to the barebox-DT since for the barebox-DT but could be aligned later in either way of course! > > + pinctrl = pinctrl_get_select(console->dev, "uart"); > > Nitpick: I think a name like "open" might be clearer? IMHO pinctrl "uart" is easier to understand given the context that this function is called within hgs_open_console(). What would be a "open" console mean? Regards, Marco > > > Cheers, > Ahmad > > -- > 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 | > > -- #gernperDu #CallMeByMyFirstName Pengutronix e.K. | | Steuerwalder Str. 21 | https://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 2026-02-05 15:45 ` [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 Marco Felsch 2026-02-06 13:47 ` Ahmad Fatoum @ 2026-02-09 10:42 ` Sascha Hauer 2026-02-09 11:39 ` Marco Felsch 1 sibling, 1 reply; 23+ messages in thread From: Sascha Hauer @ 2026-02-09 10:42 UTC (permalink / raw) To: Marco Felsch; +Cc: BAREBOX, Johannes Schneider On Thu, Feb 05, 2026 at 04:45:07PM +0100, Marco Felsch wrote: > +#include <common.h> > +#include <deep-probe.h> > +#include <envfs.h> > +#include <environment.h> > +#include <init.h> > +#include <i2c/i2c.h> > +#include <linux/phy.h> > +#include <mach/imx/bbu.h> > +#include <mach/imx/generic.h> > +#include <mfd/hgs-efi.h> > +#include <of.h> > +#include <state.h> > + > +#define PHY_ID_AR8031 0x004dd074 > +#define AR_PHY_ID_MASK 0xffffffff > + > +#define HGS_GS05_BASE_NAME "Hexagon Geosystems GS05" > + > +#define HGS_GS05_MACHINE(_revid, _compatible, _model_suffix) \ > + HGS_MACHINE(_revid, _compatible, HGS_GS05_BASE_NAME " " _model_suffix) > + > +struct hgs_machine hgs_gs05_variants[] = { static > + HGS_GS05_MACHINE(HGS_BOARD_REV_C, "hgs,gs05-rev-c", "Rev-C"), > + HGS_GS05_MACHINE(HGS_BOARD_REV_D, "hgs,gs05-rev-d", "Rev-D"), > + { /* Sentinel */ } > +}; > + > +#define HGS_GS05_LEGACY_MACHINE(_revchar, _revid, _compatible, _model_suffix) \ > +{ \ > + .revision = _revchar, \ > + .machine = HGS_GS05_MACHINE(_revid, _compatible, _model_suffix) \ > +} > + > +struct hgs_gs05_legacy_machine { static > + u8 revision; > + struct hgs_machine machine; > +} hgs_gs05_legacy_variants[] = { > + HGS_GS05_LEGACY_MACHINE('C', HGS_BOARD_REV_C, "hgs,gs05-rev-c", "Rev-C"), > + HGS_GS05_LEGACY_MACHINE('D', HGS_BOARD_REV_D, "hgs,gs05-rev-d", "Rev-D"), > + { /* Sentinel */ } > +}; > + > +static int ar8031_phy_fixup(struct phy_device *phydev) > +{ > + /* enable rgmii rxc skew and phy mode select to RGMII copper */ > + phy_write(phydev, 0x1d, 0x1f); > + phy_write(phydev, 0x1e, 0x8); > + phy_write(phydev, 0x1d, 0x00); > + phy_write(phydev, 0x1e, 0x82ee); > + phy_write(phydev, 0x1d, 0x05); > + phy_write(phydev, 0x1e, 0x100); > + > + return 0; > +} > + > +static struct hgs_machine * > +hgs_gs05_get_board_from_legacy(const unsigned char *serial) > +{ > + struct hgs_gs05_legacy_machine *machine = hgs_gs05_legacy_variants; > + > + for (; machine->revision; machine++) > + if (serial[6] == machine->revision) > + return &machine->machine; Drop sentinel and use ARRAY_SIZE? > + > + return ERR_PTR(-EINVAL); > +} > + > +static struct hgs_machine * > +hgs_gs05_select_board(const unsigned char *serial, bool legacy_format) > +{ > + struct hgs_machine *machine = hgs_gs05_variants; > + const struct hgs_board_revision *rev; > + > + /* TODO: Remove legacy handling if no longer required */ > + if (legacy_format) > + return hgs_gs05_get_board_from_legacy(serial); > + > + rev = hgs_get_rev_from_part_trace((struct hgs_part_trace_code *)serial); > + if (!rev) > + return ERR_PTR(-EINVAL); > + > + for (; machine->dts_compatible; machine++) > + if (rev->id == machine->revision) > + return machine; same here. [...] > +static int hgs_setup_emmc(struct hgs_machine *machine) > +{ > + static const char * const mmc_commands[] = { "enh_area", "write_reliability" }; > + int partitioning_completed; > + char *cmd, *tmp; > + unsigned int i; > + > + tmp = xasprintf("%s.partitioning_completed", machine->mmc_alias); > + getenv_bool(tmp, &partitioning_completed); > + free(tmp); > + if (partitioning_completed) > + return 0; > + > + for (i = 0; i < ARRAY_SIZE(mmc_commands); i++) { > + cmd = xasprintf("mmc %s /dev/%s", mmc_commands[i], machine->mmc_alias); > + if (run_command(cmd)) { run_command("mmc %s /dev/%s", mmc_commands[i], machine->mmc_alias); Would be nice ;) > + dev_err(machine->dev, > + "Failed to run command: %s, skip eMMC partition-complete\n", cmd); > + free(cmd); > + return -EINVAL; > + } > + free(cmd); > + } > + > + /* Make the final complete not part of the loop */ > + cmd = xasprintf("mmc partition_complete /dev/%s", machine->mmc_alias); > + run_command(cmd); > + free(cmd); > + > + dev_info(machine->dev, "Initial eMMC setup completed successfully\n"); > + return 0; > +} > + [...] > + err = imx_hab_lockdown_device(flags); > + if (err) { > + dev_err(dev, "Failed to lockdown the device\n"); > + return err; > + } > + dev_info(dev, "Lockdown of the device succeeded\n"); > + return 0; > +} > +postenvironment_initcall(hgs_run_first_boot_setup); Needs to be protected from running on other boards. > + > +/* > + * Notify the PP4 at the latest point to ensure that barebox was started > + * properly. If this function is not reached the PP4 timeout of 10sec is > + * triggered which puts us into serial-downloader mode. > + */ > +static int hgs_notify_pp4(void) > +{ > + int ret; > + > + if (!priv) > + return 0; > + > + ret = gpio_request_one(priv->pp4_gpio, GPIOF_OUT_INIT_HIGH, "pp4-cpu-rdy"); > + if (ret) > + return ret; > + > + return 0; > +} > +postenvironment_initcall(hgs_notify_pp4); ditto. > + > +/* > + * Custom USB gadget handling since we need to get notified upon the flash of > + * the data partition. The setup is done very late like the > + * usbgadget_autostart_init() since we need to ensure that the NV is loaded > + * properly for development case. > + */ > +static int hgs_usbgadget_autostart(void) > +{ > + struct usbgadget_funcs funcs = {}; > + struct f_multi_opts *opts; > + int ret; > + > + if (!hgs_enable_usbgadget) > + return 0; > + > + /* > + * Some HW is missing a HW serial connecotr. Fastboot is used for file > + * download. > + */ > + funcs.flags |= USBGADGET_EXPORT_BBU | USBGADGET_FASTBOOT | USBGADGET_ACM; > + > + opts = usbgadget_prepare(&funcs); > + if (IS_ERR(opts)) > + return PTR_ERR(opts); > + > + /* Custom hook to get notified once the user want to flash something */ > + opts->fastboot_opts.cmd_flash = hgs_fastboot_cmd_flash; > + > + ret = usbgadget_register(opts); > + if (ret) > + usb_multi_opts_release(opts); > + > + return ret; > +} > +postenvironment_initcall(hgs_usbgadget_autostart); ditto. > +++ b/common/boards/hgs/lib.c > @@ -0,0 +1,73 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +// SPDX-FileCopyrightText: 2025 Pengutronix > +// SPDX-FileCopyrightText: Leica Geosystems AG > + > +#define pr_fmt(fmt) "hgs-lib: " fmt > + > +#include <common.h> > +#include <linux/stddef.h> > +#include <linux/hex.h> > + > +#include <boards/hgs/common.h> > + > +#define HGS_BOARD_REV(_id, _str) { \ > + .id = _id, \ > + .str = _str, \ > +} > + > +#define HGS_BOARD_REV_SIMPLE(_id) \ > + HGS_BOARD_REV(HGS_BOARD_REV##_id, #_id) > + > +static const struct hgs_board_revision hgs_revision_table[] = { > + HGS_BOARD_REV_SIMPLE(_A), > + HGS_BOARD_REV_SIMPLE(_B), > + HGS_BOARD_REV_SIMPLE(_C), > + HGS_BOARD_REV_SIMPLE(_D), > + HGS_BOARD_REV_SIMPLE(_E), > +}; > + > +const struct hgs_board_revision * > +hgs_get_rev_from_part_trace(const struct hgs_part_trace_code *code) > +{ > + const struct hgs_board_revision *rev = hgs_revision_table; > + > + for (; rev->str; rev++) This iterates past the array. Use ARRAY_SIZE. > + if (!memcmp(code->material_revision, rev->str, > + sizeof(code->material_revision))) > + return rev; > + > + return NULL; > +} > + > +const u32 > +hgs_get_artno_from_part_trace(const struct hgs_part_trace_code *code) > +{ > + __be32 res = 0; > + u8 tmp[8]; > + int err; > + > + /* > + * Art-no. has 7-digits, add a leading '0' to align it to 8 and make > + * use of hex2bin > + */ > + memset(tmp, '0', sizeof(tmp)); tmp[0] = '0' > + memcpy(tmp + 1, code->art_number, sizeof(code->art_number)); > + err = hex2bin((u8 *)&res, tmp, sizeof(res)); > + > + return err ? 0 : be32_to_cpu(res); > +} > + > +struct hgs_machine *hgs_get_last_variant_entry(struct hgs_machine *variants) > +{ > + struct hgs_machine *last_entry = NULL; > + > + if (!variants->dts_compatible) { > + pr_warn("%s: Invalid input\n", __func__); > + return ERR_PTR(-EINVAL); > + } > + > + for (; variants->dts_compatible; variants++) > + last_entry = variants; > + > + return last_entry; > +} 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 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 2026-02-09 10:42 ` Sascha Hauer @ 2026-02-09 11:39 ` Marco Felsch 2026-02-09 13:40 ` Sascha Hauer 0 siblings, 1 reply; 23+ messages in thread From: Marco Felsch @ 2026-02-09 11:39 UTC (permalink / raw) To: Sascha Hauer; +Cc: BAREBOX, Johannes Schneider On 26-02-09, Sascha Hauer wrote: > On Thu, Feb 05, 2026 at 04:45:07PM +0100, Marco Felsch wrote: > > +#include <common.h> > > +#include <deep-probe.h> > > +#include <envfs.h> > > +#include <environment.h> > > +#include <init.h> > > +#include <i2c/i2c.h> > > +#include <linux/phy.h> > > +#include <mach/imx/bbu.h> > > +#include <mach/imx/generic.h> > > +#include <mfd/hgs-efi.h> > > +#include <of.h> > > +#include <state.h> > > + > > +#define PHY_ID_AR8031 0x004dd074 > > +#define AR_PHY_ID_MASK 0xffffffff > > + > > +#define HGS_GS05_BASE_NAME "Hexagon Geosystems GS05" > > + > > +#define HGS_GS05_MACHINE(_revid, _compatible, _model_suffix) \ > > + HGS_MACHINE(_revid, _compatible, HGS_GS05_BASE_NAME " " _model_suffix) > > + > > +struct hgs_machine hgs_gs05_variants[] = { > > static Sure. > > + HGS_GS05_MACHINE(HGS_BOARD_REV_C, "hgs,gs05-rev-c", "Rev-C"), > > + HGS_GS05_MACHINE(HGS_BOARD_REV_D, "hgs,gs05-rev-d", "Rev-D"), > > + { /* Sentinel */ } > > +}; > > + > > +#define HGS_GS05_LEGACY_MACHINE(_revchar, _revid, _compatible, _model_suffix) \ > > +{ \ > > + .revision = _revchar, \ > > + .machine = HGS_GS05_MACHINE(_revid, _compatible, _model_suffix) \ > > +} > > + > > +struct hgs_gs05_legacy_machine { > > static Sure. > > + u8 revision; > > + struct hgs_machine machine; > > +} hgs_gs05_legacy_variants[] = { > > + HGS_GS05_LEGACY_MACHINE('C', HGS_BOARD_REV_C, "hgs,gs05-rev-c", "Rev-C"), > > + HGS_GS05_LEGACY_MACHINE('D', HGS_BOARD_REV_D, "hgs,gs05-rev-d", "Rev-D"), > > + { /* Sentinel */ } > > +}; > > + > > +static int ar8031_phy_fixup(struct phy_device *phydev) > > +{ > > + /* enable rgmii rxc skew and phy mode select to RGMII copper */ > > + phy_write(phydev, 0x1d, 0x1f); > > + phy_write(phydev, 0x1e, 0x8); > > + phy_write(phydev, 0x1d, 0x00); > > + phy_write(phydev, 0x1e, 0x82ee); > > + phy_write(phydev, 0x1d, 0x05); > > + phy_write(phydev, 0x1e, 0x100); > > + > > + return 0; > > +} > > + > > +static struct hgs_machine * > > +hgs_gs05_get_board_from_legacy(const unsigned char *serial) > > +{ > > + struct hgs_gs05_legacy_machine *machine = hgs_gs05_legacy_variants; > > + > > + for (; machine->revision; machine++) > > + if (serial[6] == machine->revision) > > + return &machine->machine; > > Drop sentinel and use ARRAY_SIZE? Is this rather a personal preference or barebox coding style? I would like to keep the sentinel-approach since we use the same approach for other boards too which allowed us simpler code constructions. > > + return ERR_PTR(-EINVAL); > > +} > > + > > +static struct hgs_machine * > > +hgs_gs05_select_board(const unsigned char *serial, bool legacy_format) > > +{ > > + struct hgs_machine *machine = hgs_gs05_variants; > > + const struct hgs_board_revision *rev; > > + > > + /* TODO: Remove legacy handling if no longer required */ > > + if (legacy_format) > > + return hgs_gs05_get_board_from_legacy(serial); > > + > > + rev = hgs_get_rev_from_part_trace((struct hgs_part_trace_code *)serial); > > + if (!rev) > > + return ERR_PTR(-EINVAL); > > + > > + for (; machine->dts_compatible; machine++) > > + if (rev->id == machine->revision) > > + return machine; > > same here. > > [...] > > > +static int hgs_setup_emmc(struct hgs_machine *machine) > > +{ > > + static const char * const mmc_commands[] = { "enh_area", "write_reliability" }; > > + int partitioning_completed; > > + char *cmd, *tmp; > > + unsigned int i; > > + > > + tmp = xasprintf("%s.partitioning_completed", machine->mmc_alias); > > + getenv_bool(tmp, &partitioning_completed); > > + free(tmp); > > + if (partitioning_completed) > > + return 0; > > + > > + for (i = 0; i < ARRAY_SIZE(mmc_commands); i++) { > > + cmd = xasprintf("mmc %s /dev/%s", mmc_commands[i], machine->mmc_alias); > > + if (run_command(cmd)) { > > run_command("mmc %s /dev/%s", mmc_commands[i], machine->mmc_alias); > > Would be nice ;) Yeah, would come in handy here, let me check this. > > + dev_err(machine->dev, > > + "Failed to run command: %s, skip eMMC partition-complete\n", cmd); > > + free(cmd); > > + return -EINVAL; > > + } > > + free(cmd); > > + } > > + > > + /* Make the final complete not part of the loop */ > > + cmd = xasprintf("mmc partition_complete /dev/%s", machine->mmc_alias); > > + run_command(cmd); > > + free(cmd); > > + > > + dev_info(machine->dev, "Initial eMMC setup completed successfully\n"); > > + return 0; > > +} > > + > > [...] > > > + err = imx_hab_lockdown_device(flags); > > + if (err) { > > + dev_err(dev, "Failed to lockdown the device\n"); > > + return err; > > + } > > + dev_info(dev, "Lockdown of the device succeeded\n"); > > + return 0; > > +} > > +postenvironment_initcall(hgs_run_first_boot_setup); > > Needs to be protected from running on other boards. Guarded via the hgs_first_boot variable which is only set by hgs_run_first_boot() which in turn gets only called via hgs_common_boot(). > > > + > > +/* > > + * Notify the PP4 at the latest point to ensure that barebox was started > > + * properly. If this function is not reached the PP4 timeout of 10sec is > > + * triggered which puts us into serial-downloader mode. > > + */ > > +static int hgs_notify_pp4(void) > > +{ > > + int ret; > > + > > + if (!priv) > > + return 0; > > + > > + ret = gpio_request_one(priv->pp4_gpio, GPIOF_OUT_INIT_HIGH, "pp4-cpu-rdy"); > > + if (ret) > > + return ret; > > + > > + return 0; > > +} > > +postenvironment_initcall(hgs_notify_pp4); > > ditto. It's guarded by the 'if (!priv)' but this function may get removed in v2 anyway. > > + > > +/* > > + * Custom USB gadget handling since we need to get notified upon the flash of > > + * the data partition. The setup is done very late like the > > + * usbgadget_autostart_init() since we need to ensure that the NV is loaded > > + * properly for development case. > > + */ > > +static int hgs_usbgadget_autostart(void) > > +{ > > + struct usbgadget_funcs funcs = {}; > > + struct f_multi_opts *opts; > > + int ret; > > + > > + if (!hgs_enable_usbgadget) > > + return 0; > > + > > + /* > > + * Some HW is missing a HW serial connecotr. Fastboot is used for file > > + * download. > > + */ > > + funcs.flags |= USBGADGET_EXPORT_BBU | USBGADGET_FASTBOOT | USBGADGET_ACM; > > + > > + opts = usbgadget_prepare(&funcs); > > + if (IS_ERR(opts)) > > + return PTR_ERR(opts); > > + > > + /* Custom hook to get notified once the user want to flash something */ > > + opts->fastboot_opts.cmd_flash = hgs_fastboot_cmd_flash; > > + > > + ret = usbgadget_register(opts); > > + if (ret) > > + usb_multi_opts_release(opts); > > + > > + return ret; > > +} > > +postenvironment_initcall(hgs_usbgadget_autostart); > > ditto. Guarded via hgs_enable_usbgadget. > > > +++ b/common/boards/hgs/lib.c > > @@ -0,0 +1,73 @@ > > +// SPDX-License-Identifier: GPL-2.0-only > > +// SPDX-FileCopyrightText: 2025 Pengutronix > > +// SPDX-FileCopyrightText: Leica Geosystems AG > > + > > +#define pr_fmt(fmt) "hgs-lib: " fmt > > + > > +#include <common.h> > > +#include <linux/stddef.h> > > +#include <linux/hex.h> > > + > > +#include <boards/hgs/common.h> > > + > > +#define HGS_BOARD_REV(_id, _str) { \ > > + .id = _id, \ > > + .str = _str, \ > > +} > > + > > +#define HGS_BOARD_REV_SIMPLE(_id) \ > > + HGS_BOARD_REV(HGS_BOARD_REV##_id, #_id) > > + > > +static const struct hgs_board_revision hgs_revision_table[] = { > > + HGS_BOARD_REV_SIMPLE(_A), > > + HGS_BOARD_REV_SIMPLE(_B), > > + HGS_BOARD_REV_SIMPLE(_C), > > + HGS_BOARD_REV_SIMPLE(_D), > > + HGS_BOARD_REV_SIMPLE(_E), > > +}; > > + > > +const struct hgs_board_revision * > > +hgs_get_rev_from_part_trace(const struct hgs_part_trace_code *code) > > +{ > > + const struct hgs_board_revision *rev = hgs_revision_table; > > + > > + for (; rev->str; rev++) > > This iterates past the array. Use ARRAY_SIZE. You're right! It was never noticed since we never reached the end :/ I can change it to ARRAY_SIZE() but I would like to keep the sentinel approach and add the missing sentinel if this is fine for you. > > + if (!memcmp(code->material_revision, rev->str, > > + sizeof(code->material_revision))) > > + return rev; > > + > > + return NULL; > > +} > > + > > +const u32 > > +hgs_get_artno_from_part_trace(const struct hgs_part_trace_code *code) > > +{ > > + __be32 res = 0; > > + u8 tmp[8]; > > + int err; > > + > > + /* > > + * Art-no. has 7-digits, add a leading '0' to align it to 8 and make > > + * use of hex2bin > > + */ > > + memset(tmp, '0', sizeof(tmp)); > > tmp[0] = '0' Sure, could also have done the intialization during the definition of tmp. Thanks for the review, Marco > > + memcpy(tmp + 1, code->art_number, sizeof(code->art_number)); > > + err = hex2bin((u8 *)&res, tmp, sizeof(res)); > > + > > + return err ? 0 : be32_to_cpu(res); > > +} > > + > > +struct hgs_machine *hgs_get_last_variant_entry(struct hgs_machine *variants) > > +{ > > + struct hgs_machine *last_entry = NULL; > > + > > + if (!variants->dts_compatible) { > > + pr_warn("%s: Invalid input\n", __func__); > > + return ERR_PTR(-EINVAL); > > + } > > + > > + for (; variants->dts_compatible; variants++) > > + last_entry = variants; > > + > > + return last_entry; > > +} > > 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 | > -- #gernperDu #CallMeByMyFirstName Pengutronix e.K. | | Steuerwalder Str. 21 | https://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 2026-02-09 11:39 ` Marco Felsch @ 2026-02-09 13:40 ` Sascha Hauer 0 siblings, 0 replies; 23+ messages in thread From: Sascha Hauer @ 2026-02-09 13:40 UTC (permalink / raw) To: Marco Felsch; +Cc: BAREBOX, Johannes Schneider On Mon, Feb 09, 2026 at 12:39:01PM +0100, Marco Felsch wrote: > On 26-02-09, Sascha Hauer wrote: > > On Thu, Feb 05, 2026 at 04:45:07PM +0100, Marco Felsch wrote: > > > +#include <common.h> > > > +#include <deep-probe.h> > > > +#include <envfs.h> > > > +#include <environment.h> > > > +#include <init.h> > > > +#include <i2c/i2c.h> > > > +#include <linux/phy.h> > > > +#include <mach/imx/bbu.h> > > > +#include <mach/imx/generic.h> > > > +#include <mfd/hgs-efi.h> > > > +#include <of.h> > > > +#include <state.h> > > > + > > > +#define PHY_ID_AR8031 0x004dd074 > > > +#define AR_PHY_ID_MASK 0xffffffff > > > + > > > +#define HGS_GS05_BASE_NAME "Hexagon Geosystems GS05" > > > + > > > +#define HGS_GS05_MACHINE(_revid, _compatible, _model_suffix) \ > > > + HGS_MACHINE(_revid, _compatible, HGS_GS05_BASE_NAME " " _model_suffix) > > > + > > > +struct hgs_machine hgs_gs05_variants[] = { > > > > static > > Sure. > > > > + HGS_GS05_MACHINE(HGS_BOARD_REV_C, "hgs,gs05-rev-c", "Rev-C"), > > > + HGS_GS05_MACHINE(HGS_BOARD_REV_D, "hgs,gs05-rev-d", "Rev-D"), > > > + { /* Sentinel */ } > > > +}; > > > + > > > +#define HGS_GS05_LEGACY_MACHINE(_revchar, _revid, _compatible, _model_suffix) \ > > > +{ \ > > > + .revision = _revchar, \ > > > + .machine = HGS_GS05_MACHINE(_revid, _compatible, _model_suffix) \ > > > +} > > > + > > > +struct hgs_gs05_legacy_machine { > > > > static > > Sure. > > > > + u8 revision; > > > + struct hgs_machine machine; > > > +} hgs_gs05_legacy_variants[] = { > > > + HGS_GS05_LEGACY_MACHINE('C', HGS_BOARD_REV_C, "hgs,gs05-rev-c", "Rev-C"), > > > + HGS_GS05_LEGACY_MACHINE('D', HGS_BOARD_REV_D, "hgs,gs05-rev-d", "Rev-D"), > > > + { /* Sentinel */ } > > > +}; > > > + > > > +static int ar8031_phy_fixup(struct phy_device *phydev) > > > +{ > > > + /* enable rgmii rxc skew and phy mode select to RGMII copper */ > > > + phy_write(phydev, 0x1d, 0x1f); > > > + phy_write(phydev, 0x1e, 0x8); > > > + phy_write(phydev, 0x1d, 0x00); > > > + phy_write(phydev, 0x1e, 0x82ee); > > > + phy_write(phydev, 0x1d, 0x05); > > > + phy_write(phydev, 0x1e, 0x100); > > > + > > > + return 0; > > > +} > > > + > > > +static struct hgs_machine * > > > +hgs_gs05_get_board_from_legacy(const unsigned char *serial) > > > +{ > > > + struct hgs_gs05_legacy_machine *machine = hgs_gs05_legacy_variants; > > > + > > > + for (; machine->revision; machine++) > > > + if (serial[6] == machine->revision) > > > + return &machine->machine; > > > > Drop sentinel and use ARRAY_SIZE? > > Is this rather a personal preference or barebox coding style? > > I would like to keep the sentinel-approach since we use the same > approach for other boards too which allowed us simpler code > constructions. As you've seen in this patch such a sentinel is easily forgotten. When you use the arrays non locally and have to pass the number of array entries around as an additional argument, then Ok, use the sentinel approach. But since you don't do that, what's the good argument for not using ARRAY_SIZE and save a few bytes of binary space? > > [...] > > > > > + err = imx_hab_lockdown_device(flags); > > > + if (err) { > > > + dev_err(dev, "Failed to lockdown the device\n"); > > > + return err; > > > + } > > > + dev_info(dev, "Lockdown of the device succeeded\n"); > > > + return 0; > > > +} > > > +postenvironment_initcall(hgs_run_first_boot_setup); > > > > Needs to be protected from running on other boards. > > Guarded via the hgs_first_boot variable which is only set by > hgs_run_first_boot() which in turn gets only called via > hgs_common_boot(). Hm, you're right. Nevertheless please do not add multiple initcalls at the same level in the same file. 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 | ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 0/5] Hexagon Geosystems GS05 Board Support 2026-02-05 15:45 [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch ` (4 preceding siblings ...) 2026-02-05 15:45 ` [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 Marco Felsch @ 2026-02-05 15:50 ` Marco Felsch 5 siblings, 0 replies; 23+ messages in thread From: Marco Felsch @ 2026-02-05 15:50 UTC (permalink / raw) To: Sascha Hauer, BAREBOX; +Cc: Johannes Schneider On 26-02-05, Marco Felsch wrote: > Hi, > > this series adds the support for the Hexagon Geosystems GS05 product > [1]. The GS05 is part of a larger product family from SW pov, therefore > most logic is implemented below 'common/boards/hgs'. > > The board support was added before the new security-profiles made it > into barebox mainline, therefore security-profiles aren't used yet but > maybe in the future. > > Further products will be send mainline as well, once this basic support > got merged. > > Patch1-2 were also sent here [2] in parallel. I forgot to mention, that this patchset depends on: https://lore.kernel.org/barebox/20260204-v2025-09-0-topic-optee-of-handling-v2-0-da075e6818e0@pengutronix.de/ > Regards, > Marco > > [1] https://leica-geosystems.com/de-de/products/gnss-systems/smart-antennas/leica-gs05 > [2] https://lore.kernel.org/barebox/20260204151645.1426068-1-m.felsch@pengutronix.de/ > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de> > --- > Marco Felsch (5): > ARM: i.MX8MM: add MX8MM_PAD_CTL defines > lib: hexdump: make use of pr_print > mfd: Add Hexagon EFI driver > watchdog: Add Hexagon EFI watchdog driver > ARM: i.MX8MM: add Hexagon Geosystems GS05 > > arch/arm/boards/Makefile | 1 + > arch/arm/boards/hgs-gs05/Makefile | 6 + > arch/arm/boards/hgs-gs05/board.c | 237 +++++ > arch/arm/boards/hgs-gs05/flash-header-gs05.imxcfg | 12 + > arch/arm/boards/hgs-gs05/lowlevel.c | 128 +++ > arch/arm/boards/hgs-gs05/lpddr4-timing.c | 1118 +++++++++++++++++++++ > arch/arm/dts/Makefile | 1 + > arch/arm/dts/imx8m-hgs-common.dtsi | 80 ++ > arch/arm/dts/imx8mm-hgs-gs05.dts | 320 ++++++ > arch/arm/mach-imx/Kconfig | 8 + > commands/ethlog.c | 4 +- > common/boards/Kconfig | 12 + > common/boards/Makefile | 1 + > common/boards/hgs/Makefile | 7 + > common/boards/hgs/common.c | 627 ++++++++++++ > common/boards/hgs/lib.c | 73 ++ > common/boards/hgs/pbl.c | 100 ++ > drivers/mfd/Kconfig | 8 + > drivers/mfd/Makefile | 1 + > drivers/mfd/hgs-efi.c | 473 +++++++++ > drivers/mtd/ubi/attach.c | 2 +- > drivers/watchdog/Kconfig | 9 + > drivers/watchdog/Makefile | 1 + > drivers/watchdog/hgs_efi_wdt.c | 88 ++ > fs/ubifs/debug.c | 4 +- > images/Makefile.imx | 2 + > include/boards/hgs/common.h | 84 ++ > include/linux/printk.h | 4 +- > include/mach/imx/iomux-mx8mm.h | 10 + > include/mfd/hgs-efi.h | 46 + > include/printf.h | 2 +- > include/soc/ti/cppi5.h | 2 +- > lib/hexdump.c | 13 +- > 33 files changed, 3467 insertions(+), 17 deletions(-) > --- > base-commit: 8781fc641fc147df639c9e767a89aa3277d2c9be > change-id: 20260205-vmaster-customers-leicageo-system1600-f62320eed41f > > Best regards, > -- > Marco Felsch <m.felsch@pengutronix.de> > > -- #gernperDu #CallMeByMyFirstName Pengutronix e.K. | | Steuerwalder Str. 21 | https://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-9 | ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2026-02-09 13:47 UTC | newest] Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-02-05 15:45 [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch 2026-02-05 15:45 ` [PATCH 1/5] ARM: i.MX8MM: add MX8MM_PAD_CTL defines Marco Felsch 2026-02-06 13:04 ` Ahmad Fatoum 2026-02-05 15:45 ` [PATCH 2/5] lib: hexdump: make use of pr_print Marco Felsch 2026-02-06 13:05 ` Ahmad Fatoum 2026-02-05 15:45 ` [PATCH 3/5] mfd: Add Hexagon EFI driver Marco Felsch 2026-02-06 13:09 ` Ahmad Fatoum 2026-02-06 15:52 ` Marco Felsch 2026-02-09 9:03 ` Sascha Hauer 2026-02-09 11:13 ` Marco Felsch 2026-02-09 13:46 ` Sascha Hauer 2026-02-05 15:45 ` [PATCH 4/5] watchdog: Add Hexagon EFI watchdog driver Marco Felsch 2026-02-06 13:13 ` Ahmad Fatoum 2026-02-06 16:34 ` Marco Felsch 2026-02-05 15:45 ` [PATCH 5/5] ARM: i.MX8MM: add Hexagon Geosystems GS05 Marco Felsch 2026-02-06 13:47 ` Ahmad Fatoum 2026-02-06 14:07 ` SCHNEIDER Johannes 2026-02-06 15:43 ` Marco Felsch 2026-02-06 17:12 ` Marco Felsch 2026-02-09 10:42 ` Sascha Hauer 2026-02-09 11:39 ` Marco Felsch 2026-02-09 13:40 ` Sascha Hauer 2026-02-05 15:50 ` [PATCH 0/5] Hexagon Geosystems GS05 Board Support Marco Felsch
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox