diff --git a/Makefile b/Makefile
index ce50bf4b3b..75b7b87d65 100644
--- a/Makefile
+++ b/Makefile
@@ -50,7 +50,7 @@ STYLESHEET = common/beamerthemeBootlin.sty
# in .pdf in the output directory. This is used to compute the list of
# .pdf files that need to be generated from .dia or .svg files.
PICTURES_WITH_TRANSFORMATION = \
- $(patsubst %.$(2),$(OUTDIR)/%.pdf,$(foreach s,$(1),$(wildcard $(s)/*.$(2))))
+ $(patsubst %.$(2),$(OUTDIR)/%.pdf,$(foreach s,$(1),$(shell find -L $(s) -type f -name '*.$(2)')))
# Function that computes the list of pictures of the extension given
# in $(2) from the directories in $(1). This is used for pictures that
@@ -94,6 +94,7 @@ SLIDES_COMMON_BEFORE = common/slide-header.tex \
common/$(SLIDES_TRAINING)-title.tex
SLIDES_CHAPTERS = $($(call UPPERCASE, $(subst -,_, $(SLIDES_TRAINING)))_SLIDES)
SLIDES_COMMON_AFTER = common/slide-footer.tex
+SLIDES_VARSFILE = common/$(SLIDES_TRAINING)-labs-vars.tex
else
SLIDES_TRAINING = $(firstword $(subst -, , $(SLIDES)))
ifeq ($(SLIDES_TRAINING),sysdev)
@@ -122,6 +123,7 @@ endif
# Compute the set of corresponding .tex files and pictures
SLIDES_TEX = \
+ $(SLIDES_VARSFILE) \
$(SLIDES_COMMON_BEFORE) \
$(foreach s,$(SLIDES_CHAPTERS),$(wildcard slides/$(s)/$(s).tex)) \
$(SLIDES_COMMON_AFTER)
diff --git a/common/embedded-linux-imx93-frdm-labs-vars.tex b/common/embedded-linux-imx93-frdm-labs-vars.tex
new file mode 100644
index 0000000000..7aeaa11912
--- /dev/null
+++ b/common/embedded-linux-imx93-frdm-labs-vars.tex
@@ -0,0 +1,15 @@
+\def\labbooktitle{Embedded Linux System Development}
+\def\labbooksubtitle{imx93 frdm variant}
+\def\labboard{imx93-frdm}
+\def\workingkernel{6.15}
+\def\labboarddescription{imx93 frdm Discovery kit}
+\def\zimageboardaddr{0xc2000000}
+\def\dtbboardaddr{0xc4f00000}
+\def\dtname{imx93-11x11-frdm}
+\def\hosttty{/dev/ttyACM0}
+\def\ttyname{ttyLP0}
+\def\console{\ttyname,115200}
+\def\gpionum{533}
+\def\gpioname{PF11}
+\def\busname{I2C2}
+\def\arch{ARM64}
\ No newline at end of file
diff --git a/common/embedded-linux-imx93-frdm-title.tex b/common/embedded-linux-imx93-frdm-title.tex
new file mode 100644
index 0000000000..a2a7b71b9e
--- /dev/null
+++ b/common/embedded-linux-imx93-frdm-title.tex
@@ -0,0 +1,2 @@
+\def \trainingurl{https://bootlin.com/training/embedded-linux}
+\def \trainingtitle{Embedded Linux system development}
diff --git a/common/imx93-frdm-connect-nunchuk.jpg b/common/imx93-frdm-connect-nunchuk.jpg
new file mode 100644
index 0000000000..8a3cf09b7b
Binary files /dev/null and b/common/imx93-frdm-connect-nunchuk.jpg differ
diff --git a/common/slide-header.tex b/common/slide-header.tex
index 9e5c309813..c574df8afa 100644
--- a/common/slide-header.tex
+++ b/common/slide-header.tex
@@ -9,6 +9,7 @@
\usepackage{tabularx}
\usepackage{stmaryrd}
\usepackage{appendixnumberbeamer}
+\usepackage{etoolbox}
\renewcommand{\thempfootnote}{\arabic{mpfootnote}}
diff --git a/lab-data/embedded-linux-imx93-frdm/appdev/nunchuk-mpd-client.c b/lab-data/embedded-linux-imx93-frdm/appdev/nunchuk-mpd-client.c
new file mode 100644
index 0000000000..4350eb1b64
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/appdev/nunchuk-mpd-client.c
@@ -0,0 +1,170 @@
+/* nunchuk-mpd-client
+ (c) 2022 Bootlin
+
+ License: Public Domain
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int handle_error(struct mpd_connection *c)
+{
+ fprintf(stderr, "%s\n", mpd_connection_get_error_message(c));
+ mpd_connection_free(c);
+ return EXIT_FAILURE;
+}
+
+static void change_volume(struct mpd_connection *c, int delta)
+{
+ int volume;
+ if (!mpd_run_change_volume(c, delta))
+ exit(handle_error(c));
+
+ volume = mpd_run_get_volume(c);
+
+ if (volume == -1)
+ exit(handle_error(c));
+
+ printf("%d\n", volume);
+}
+
+static void print_current_song(struct mpd_connection *c)
+{
+ struct mpd_song *song;
+ song = mpd_run_current_song(c);
+
+ if (song) {
+ printf("%s (%u s)\n", mpd_song_get_uri(song), mpd_song_get_duration(song));
+ mpd_song_free(song);
+ }
+}
+
+static int is_event_device(const struct dirent *dir) {
+ return (strncmp("event", dir->d_name, 5) == 0);
+}
+
+int main(int argc, char ** argv)
+{
+ struct mpd_connection *conn;
+ int i, ndev, ret, fd, quit = 0, num_events = 0;
+ struct input_event event;
+ struct dirent **namelist;
+
+ /* Find Nunchuk input device */
+
+ ndev = scandir("/dev/input", &namelist, is_event_device, alphasort);
+
+ if (ndev <= 0) {
+ fprintf(stderr, "ERROR: no input event device found\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < ndev; i++)
+ {
+ char fname[256];
+ char name[256];
+
+ snprintf(fname, sizeof(fname), "/dev/%s", namelist[i]->d_name);
+ free(namelist[i]);
+
+ fd = open(fname, O_RDONLY);
+
+ if (fd < 0)
+ continue;
+
+ ioctl(fd, EVIOCGNAME(sizeof(name)), name);
+
+ if (strcmp("Wii Nunchuck", name) == 0)
+ break;
+ else
+ close(fd);
+
+ }
+
+ if (i == ndev) {
+ fprintf(stderr, "ERROR: didn't manage to find the Nunchuk device in /dev/input. Is the Nunchuk driver loaded?\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Connection to MPD on localhost, default port */
+
+ conn = mpd_connection_new(0, 0, 30000);
+
+ if (mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS)
+ return handle_error(conn);
+
+ printf("Connection successful\n");
+
+ /* Main loop */
+
+ while (!quit) {
+ ret = read(fd, &event, sizeof(struct input_event));
+ num_events++;
+
+ switch (event.type) {
+ case EV_KEY:
+ switch (event.code) {
+ case BTN_Z:
+ if (event.value == 1) {
+ printf("Play/Pause\n");
+ if (!mpd_run_toggle_pause(conn))
+ return handle_error(conn);
+ }
+ break;
+ case BTN_C:
+ if (event.value == 1) {
+ printf("Quit\n");
+ quit = 1;
+ free(conn);
+ }
+ break;
+ }
+ break;
+ case EV_ABS:
+ switch (event.code) {
+ case ABS_Y:
+ if (event.value > 250) {
+ printf("Volume up: ");
+ change_volume(conn, 5);
+ } else if (event.value < 5) {
+ printf("Volume down: ");
+ change_volume(conn, -5);
+ }
+ break;
+ case ABS_X:
+ if (event.value > 250) {
+ if (!mpd_run_next(conn)) {
+ printf("No next song. Aborting\n");
+ exit(handle_error(conn));
+ } else {
+ printf("Next song: ");
+ print_current_song(conn);
+ }
+ }
+ else if (event.value < 5) {
+ if (!mpd_run_previous(conn)) {
+ printf("No previous song. Aborting\n");
+ exit(handle_error(conn));
+ } else {
+ printf("Previous song: ");
+ print_current_song(conn);
+ }
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ /* Close connection */
+ mpd_connection_free(conn);
+ printf("Connection terminated\n");
+ return 0;
+}
diff --git a/lab-data/embedded-linux-imx93-frdm/bootloader/data/flash.bin b/lab-data/embedded-linux-imx93-frdm/bootloader/data/flash.bin
new file mode 100644
index 0000000000..a8fc4531de
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/bootloader/data/flash.bin differ
diff --git a/lab-data/embedded-linux-imx93-frdm/bootloader/data/patches/0001-arm-dts-imx93-add-device-tree-for-imx93-11x11-frd.patch b/lab-data/embedded-linux-imx93-frdm/bootloader/data/patches/0001-arm-dts-imx93-add-device-tree-for-imx93-11x11-frd.patch
new file mode 100644
index 0000000000..ebd27f12fe
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/bootloader/data/patches/0001-arm-dts-imx93-add-device-tree-for-imx93-11x11-frd.patch
@@ -0,0 +1,679 @@
+From 7ece928955d97b7232ae811dc3ba1c3e50668a47 Mon Sep 17 00:00:00 2001
+From: Antoine Picard
+Date: Wed, 11 Jun 2025 08:31:42 +0200
+Subject: [PATCH u-boot v1 1/2] arm: dts: imx93: add device tree for
+ imx93-11x11-frdm board
+
+Add the following device tree files for the i.MX93 11x11 FRDM board:
+
+ - `imx93-11x11-frdm.dts`: base device tree for the board
+ - `imx93-11x11-frdm-u-boot.dtsi`: U-Boot specific overrides
+ - Update to `arch/arm/dts/Makefile` to build the new DTS
+
+These files provide the initial DT support for U-Boot on the i.MX93 FRDM
+platform.
+
+Signed-off-by: Antoine Picard
+---
+ arch/arm/dts/Makefile | 1 +
+ arch/arm/dts/imx93-11x11-frdm-u-boot.dtsi | 53 ++
+ arch/arm/dts/imx93-11x11-frdm.dts | 574 ++++++++++++++++++++++
+ 3 files changed, 628 insertions(+)
+ create mode 100644 arch/arm/dts/imx93-11x11-frdm-u-boot.dtsi
+ create mode 100644 arch/arm/dts/imx93-11x11-frdm.dts
+
+diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
+index 32b698a7f41..2792a101b51 100644
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -918,6 +918,7 @@ dtb-$(CONFIG_ARCH_IMX8M) += \
+ imx8mq-librem5-r4.dtb
+
+ dtb-$(CONFIG_ARCH_IMX9) += \
++ imx93-11x11-frdm.dtb \
+ imx93-var-som-symphony.dtb \
+ imx93-phyboard-segin.dtb
+
+diff --git a/arch/arm/dts/imx93-11x11-frdm-u-boot.dtsi b/arch/arm/dts/imx93-11x11-frdm-u-boot.dtsi
+new file mode 100644
+index 00000000000..5cecc6e4cf8
+--- /dev/null
++++ b/arch/arm/dts/imx93-11x11-frdm-u-boot.dtsi
+@@ -0,0 +1,53 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright 2024-2025 NXP
++ */
++
++#include "imx93-u-boot.dtsi"
++
++&pinctrl_uart1 {
++ bootph-pre-ram;
++};
++
++&lpuart1 {
++ bootph-pre-ram;
++};
++
++&s4muap {
++ bootph-some-ram;
++ status = "okay";
++};
++
++&clk {
++ bootph-pre-ram;
++};
++
++&osc_32k {
++ bootph-pre-ram;
++};
++
++&osc_24m {
++ bootph-pre-ram;
++};
++
++&clk_ext1 {
++ bootph-pre-ram;
++};
++
++&lpi2c2 {
++ bootph-pre-ram;
++ status = "okay";
++ clock-frequency = <100000>;
++};
++
++&pinctrl_lpi2c2 {
++ bootph-pre-ram;
++};
++
++&{/soc@0/bus@44000000/i2c@44350000/pmic@25} {
++ bootph-pre-ram;
++};
++
++&{/soc@0/bus@44000000/i2c@44350000/pmic@25/regulators} {
++ bootph-pre-ram;
++};
+\ No newline at end of file
+diff --git a/arch/arm/dts/imx93-11x11-frdm.dts b/arch/arm/dts/imx93-11x11-frdm.dts
+new file mode 100644
+index 00000000000..1e96b1f5605
+--- /dev/null
++++ b/arch/arm/dts/imx93-11x11-frdm.dts
+@@ -0,0 +1,574 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Copyright 2024-2025 NXP
++ */
++
++/dts-v1/;
++
++#include
++#include "imx93.dtsi"
++
++/ {
++ model = "NXP i.MX93 11X11 FRDM board";
++ compatible = "fsl,imx93-11x11-frdm", "fsl,imx93";
++
++ aliases {
++ rtc0 = &pcf2131;
++ };
++
++ chosen {
++ bootargs = "console=ttyLP0,115200";
++ stdout-path = &lpuart1;
++ };
++
++ reserved-memory {
++ #address-cells = <2>;
++ #size-cells = <2>;
++ ranges;
++
++ linux,cma {
++ compatible = "shared-dma-pool";
++ reusable;
++ alloc-ranges = <0 0x80000000 0 0x40000000>;
++ size = <0 0x10000000>;
++ linux,cma-default;
++ };
++ };
++
++ reg_can2_stby: regulator-can2-stby {
++ compatible = "regulator-fixed";
++ regulator-name = "can2-stby";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ gpio = <&pcal6524 23 GPIO_ACTIVE_LOW>;
++ enable-active-high;
++ };
++
++ reg_vref_1v8: regulator-adc-vref {
++ compatible = "regulator-fixed";
++ regulator-name = "vref_1v8";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ };
++
++ reg_usdhc2_vmmc: regulator-usdhc2 {
++ compatible = "regulator-fixed";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
++ regulator-name = "VSD_3V3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
++ off-on-delay-us = <12000>;
++ enable-active-high;
++ };
++
++ reg_vdd_12v: regulator-vdd-12v {
++ compatible = "regulator-fixed";
++ regulator-name = "reg_vdd_12v";
++ regulator-min-microvolt = <12000000>;
++ regulator-max-microvolt = <12000000>;
++ gpio = <&pcal6524 14 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led_red {
++ label = "led-red";
++ gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>;
++ default-state = "on";
++ };
++
++ led_green {
++ label = "led-green";
++ gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>;
++ default-state = "on";
++ };
++
++ led_blue {
++ label = "led-blue";
++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
++ default-state = "on";
++ };
++ };
++};
++
++
++&adc1 {
++ vref-supply = <®_vref_1v8>;
++ status = "okay";
++};
++
++&mu1 {
++ status = "okay";
++};
++
++&mu2 {
++ status = "okay";
++};
++
++&eqos {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_eqos>;
++ phy-mode = "rgmii-id";
++ phy-handle = <ðphy1>;
++ status = "okay";
++
++ mdio {
++ compatible = "snps,dwmac-mdio";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <5000000>;
++
++ ethphy1: ethernet-phy@1 {
++ reg = <1>;
++ eee-broken-1000t;
++
++ reset-gpios = <&pcal6524 15 GPIO_ACTIVE_LOW>;
++ reset-assert-us = <15000>;
++ reset-deassert-us = <100000>;
++ };
++ };
++};
++
++&fec {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_fec>;
++ phy-mode = "rgmii-id";
++ phy-handle = <ðphy2>;
++ fsl,magic-packet;
++ status = "okay";
++
++ mdio {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <5000000>;
++
++ ethphy2: ethernet-phy@2 {
++ reg = <2>;
++ eee-broken-1000t;
++ };
++ };
++};
++
++&lpi2c1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <400000>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&pinctrl_lpi2c1>;
++ pinctrl-1 = <&pinctrl_lpi2c1>;
++ status = "okay";
++};
++
++&lpi2c2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <400000>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&pinctrl_lpi2c2>;
++ pinctrl-1 = <&pinctrl_lpi2c2>;
++ status = "okay";
++
++ pmic@25 {
++ compatible = "nxp,pca9451a";
++ reg = <0x25>;
++ interrupt-parent = <&pcal6524>;
++ interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
++
++ regulators {
++ buck1: BUCK1 {
++ regulator-name = "BUCK1";
++ regulator-min-microvolt = <650000>;
++ regulator-max-microvolt = <2237500>;
++ regulator-boot-on;
++ regulator-always-on;
++ regulator-ramp-delay = <3125>;
++ };
++
++ buck2: BUCK2 {
++ regulator-name = "BUCK2";
++ regulator-min-microvolt = <600000>;
++ regulator-max-microvolt = <2187500>;
++ regulator-boot-on;
++ regulator-always-on;
++ regulator-ramp-delay = <3125>;
++ };
++
++ buck4: BUCK4{
++ regulator-name = "BUCK4";
++ regulator-min-microvolt = <600000>;
++ regulator-max-microvolt = <3400000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ buck5: BUCK5{
++ regulator-name = "BUCK5";
++ regulator-min-microvolt = <600000>;
++ regulator-max-microvolt = <3400000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ buck6: BUCK6 {
++ regulator-name = "BUCK6";
++ regulator-min-microvolt = <600000>;
++ regulator-max-microvolt = <3400000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ ldo1: LDO1 {
++ regulator-name = "LDO1";
++ regulator-min-microvolt = <1600000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ ldo4: LDO4 {
++ regulator-name = "LDO4";
++ regulator-min-microvolt = <800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ ldo5: LDO5 {
++ regulator-name = "LDO5";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++ };
++ };
++
++ pcal6524: gpio@22 {
++ compatible = "nxp,pcal6524";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_pcal6524>;
++ reg = <0x22>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ interrupt-parent = <&gpio3>;
++ interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
++ };
++ eeprom: eeprom@50 {
++ compatible = "atmel,24c256";
++ reg = <0x50>;
++ pagesize = <64>;
++ };
++
++};
++
++&lpi2c3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <400000>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&pinctrl_lpi2c3>;
++ pinctrl-1 = <&pinctrl_lpi2c3>;
++ status = "okay";
++
++ pcf2131: rtc@53 {
++ compatible = "nxp,pcf2131";
++ reg = <0x53>;
++ interrupt-parent = <&pcal6524>;
++ interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
++ status = "okay";
++ };
++
++ ptn5110: tcpc@50 {
++ compatible = "nxp,ptn5110", "tcpci";
++ reg = <0x50>;
++ interrupt-parent = <&gpio3>;
++ interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
++ status = "okay";
++
++ port {
++ typec1_dr_sw: endpoint {
++ remote-endpoint = <&usb1_drd_sw>;
++ };
++ };
++
++ typec1_con: connector {
++ compatible = "usb-c-connector";
++ label = "USB-C";
++ power-role = "dual";
++ data-role = "dual";
++ try-power-role = "sink";
++ source-pdos = ;
++ sink-pdos = ;
++ op-sink-microwatt = <15000000>;
++ self-powered;
++ };
++ };
++
++};
++
++&lpuart1 { /* console */
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart1>;
++ status = "okay";
++};
++
++&media_blk_ctrl {
++ status = "okay";
++};
++
++&usbotg1 {
++ dr_mode = "otg";
++ hnp-disable;
++ srp-disable;
++ adp-disable;
++ usb-role-switch;
++ disable-over-current;
++ samsung,picophy-pre-emp-curr-control = <3>;
++ samsung,picophy-dc-vol-level-adjust = <7>;
++ status = "okay";
++
++ port {
++ usb1_drd_sw: endpoint {
++ remote-endpoint = <&typec1_dr_sw>;
++ };
++ };
++};
++
++&usbotg2 {
++ dr_mode = "host";
++ disable-over-current;
++ samsung,picophy-pre-emp-curr-control = <3>;
++ samsung,picophy-dc-vol-level-adjust = <7>;
++ status = "okay";
++};
++
++&usdhc1 {
++ pinctrl-names = "default", "state_100mhz", "state_200mhz";
++ pinctrl-0 = <&pinctrl_usdhc1>;
++ pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
++ pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
++ bus-width = <8>;
++ non-removable;
++ status = "okay";
++};
++
++&usdhc2 {
++ pinctrl-names = "default", "state_100mhz", "state_200mhz";
++ pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
++ pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
++ pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
++ cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
++ vmmc-supply = <®_usdhc2_vmmc>;
++ bus-width = <4>;
++ status = "okay";
++ no-sdio;
++ no-mmc;
++};
++
++&usdhc3 {
++ status = "disabled";
++};
++
++&wdog3 {
++ status = "okay";
++};
++
++&iomuxc {
++ pinctrl_eqos: eqosgrp {
++ fsl,pins = <
++ MX93_PAD_ENET1_MDC__ENET_QOS_MDC 0x57e
++ MX93_PAD_ENET1_MDIO__ENET_QOS_MDIO 0x57e
++ MX93_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0 0x57e
++ MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1 0x57e
++ MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2 0x57e
++ MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3 0x57e
++ MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x5fe
++ MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x57e
++ MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0 0x57e
++ MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1 0x57e
++ MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2 0x57e
++ MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3 0x57e
++ MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x5fe
++ MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x57e
++ >;
++ };
++
++ pinctrl_flexspi: flexspigrp {
++ fsl,pins = <
++ MX93_PAD_SD3_CMD__FLEXSPI1_A_SS0_B 0x3fe
++ MX93_PAD_SD3_CLK__FLEXSPI1_A_SCLK 0x3fe
++ MX93_PAD_SD3_DATA0__FLEXSPI1_A_DATA00 0x3fe
++ MX93_PAD_SD3_DATA1__FLEXSPI1_A_DATA01 0x3fe
++ MX93_PAD_SD3_DATA2__FLEXSPI1_A_DATA02 0x3fe
++ MX93_PAD_SD3_DATA3__FLEXSPI1_A_DATA03 0x3fe
++ >;
++ };
++
++ pinctrl_fec: fecgrp {
++ fsl,pins = <
++ MX93_PAD_ENET2_MDC__ENET1_MDC 0x57e
++ MX93_PAD_ENET2_MDIO__ENET1_MDIO 0x57e
++ MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0 0x57e
++ MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1 0x57e
++ MX93_PAD_ENET2_RD2__ENET1_RGMII_RD2 0x57e
++ MX93_PAD_ENET2_RD3__ENET1_RGMII_RD3 0x57e
++ MX93_PAD_ENET2_RXC__ENET1_RGMII_RXC 0x5fe
++ MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL 0x57e
++ MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0 0x57e
++ MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1 0x57e
++ MX93_PAD_ENET2_TD2__ENET1_RGMII_TD2 0x57e
++ MX93_PAD_ENET2_TD3__ENET1_RGMII_TD3 0x57e
++ MX93_PAD_ENET2_TXC__ENET1_RGMII_TXC 0x5fe
++ MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL 0x57e
++ >;
++ };
++
++ pinctrl_lpi2c1: lpi2c1grp {
++ fsl,pins = <
++ MX93_PAD_I2C1_SCL__LPI2C1_SCL 0x40000b9e
++ MX93_PAD_I2C1_SDA__LPI2C1_SDA 0x40000b9e
++ >;
++ };
++
++ pinctrl_lpi2c2: lpi2c2grp {
++ fsl,pins = <
++ MX93_PAD_I2C2_SCL__LPI2C2_SCL 0x40000b9e
++ MX93_PAD_I2C2_SDA__LPI2C2_SDA 0x40000b9e
++ >;
++ };
++
++ pinctrl_lpi2c3: lpi2c3grp {
++ fsl,pins = <
++ MX93_PAD_GPIO_IO28__LPI2C3_SDA 0x40000b9e
++ MX93_PAD_GPIO_IO29__LPI2C3_SCL 0x40000b9e
++ >;
++ };
++
++ pinctrl_pcal6524: pcal6524grp {
++ fsl,pins = <
++ MX93_PAD_CCM_CLKO2__GPIO3_IO27 0x31e
++ >;
++ };
++
++ pinctrl_uart1: uart1grp {
++ fsl,pins = <
++ MX93_PAD_UART1_RXD__LPUART1_RX 0x31e
++ MX93_PAD_UART1_TXD__LPUART1_TX 0x31e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc1: usdhc1grp {
++ fsl,pins = <
++ MX93_PAD_SD1_CLK__USDHC1_CLK 0x1582
++ MX93_PAD_SD1_CMD__USDHC1_CMD 0x40001382
++ MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x40001382
++ MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x40001382
++ MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x40001382
++ MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x40001382
++ MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x40001382
++ MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x40001382
++ MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x40001382
++ MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x40001382
++ MX93_PAD_SD1_STROBE__USDHC1_STROBE 0x1582
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
++ fsl,pins = <
++ MX93_PAD_SD1_CLK__USDHC1_CLK 0x158e
++ MX93_PAD_SD1_CMD__USDHC1_CMD 0x4000138e
++ MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x4000138e
++ MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x4000138e
++ MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x4000138e
++ MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x4000138e
++ MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x4000138e
++ MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x4000138e
++ MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x4000138e
++ MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x4000138e
++ MX93_PAD_SD1_STROBE__USDHC1_STROBE 0x158e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
++ fsl,pins = <
++ MX93_PAD_SD1_CLK__USDHC1_CLK 0x15fe
++ MX93_PAD_SD1_CMD__USDHC1_CMD 0x400013fe
++ MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x400013fe
++ MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x400013fe
++ MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x400013fe
++ MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x400013fe
++ MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x400013fe
++ MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x400013fe
++ MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x400013fe
++ MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x400013fe
++ MX93_PAD_SD1_STROBE__USDHC1_STROBE 0x15fe
++ >;
++ };
++
++ pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
++ fsl,pins = <
++ MX93_PAD_SD2_RESET_B__GPIO3_IO07 0x31e
++ >;
++ };
++
++ pinctrl_usdhc2_gpio: usdhc2gpiogrp {
++ fsl,pins = <
++ MX93_PAD_SD2_CD_B__GPIO3_IO00 0x31e
++ >;
++ };
++
++ pinctrl_usdhc2_gpio_sleep: usdhc2-gpio-grp {
++ fsl,pins = <
++ MX93_PAD_SD2_CD_B__GPIO3_IO00 0x51e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc2: usdhc2grp {
++ fsl,pins = <
++ MX93_PAD_SD2_CLK__USDHC2_CLK 0x1582
++ MX93_PAD_SD2_CMD__USDHC2_CMD 0x40001382
++ MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x40001382
++ MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x40001382
++ MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x40001382
++ MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x40001382
++ MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
++ fsl,pins = <
++ MX93_PAD_SD2_CLK__USDHC2_CLK 0x158e
++ MX93_PAD_SD2_CMD__USDHC2_CMD 0x4000138e
++ MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x4000138e
++ MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x4000138e
++ MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x4000138e
++ MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x4000138e
++ MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
++ fsl,pins = <
++ MX93_PAD_SD2_CLK__USDHC2_CLK 0x15fe
++ MX93_PAD_SD2_CMD__USDHC2_CMD 0x400013fe
++ MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x400013fe
++ MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x400013fe
++ MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x400013fe
++ MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x400013fe
++ MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
++ >;
++ };
++};
+--
+2.43.0
+
diff --git a/lab-data/embedded-linux-imx93-frdm/bootloader/data/patches/0002-board-freescale-add-initial-support-for-imx93_frd.patch b/lab-data/embedded-linux-imx93-frdm/bootloader/data/patches/0002-board-freescale-add-initial-support-for-imx93_frd.patch
new file mode 100644
index 0000000000..a79ed1cffa
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/bootloader/data/patches/0002-board-freescale-add-initial-support-for-imx93_frd.patch
@@ -0,0 +1,4893 @@
+From 80063e1fb35da3eb6c2442c9140efdbfcec2a2c1 Mon Sep 17 00:00:00 2001
+From: Antoine Picard
+Date: Wed, 11 Jun 2025 08:41:21 +0200
+Subject: [PATCH u-boot v1 2/2] board: freescale: add initial support for
+ imx93_frdm board
+
+Add initial support for the NXP i.MX93 FRDM board, including:
+
+ - Board directory with initialization code
+ - DRAM timing files for LPDDR4X (2GB, ECC variants)
+ - SPL support
+ - Board-specific header and configuration
+ - i.MX9 Kconfig entry for board enablement
+ - defconfig for imx93_11x11_frdm
+
+This enables basic SPL and U-Boot support for the i.MX93 FRDM
+development platform.
+
+Signed-off-by: Antoine Picard
+---
+ arch/arm/mach-imx/imx9/Kconfig | 6 +
+ board/freescale/imx93_frdm/Kconfig | 19 +
+ board/freescale/imx93_frdm/MAINTAINERS | 5 +
+ board/freescale/imx93_frdm/Makefile | 16 +
+ board/freescale/imx93_frdm/imx93_frdm.c | 350 +++
+ .../freescale/imx93_frdm/lpddr4x_2gb_timing.c | 1996 ++++++++++++++++
+ .../imx93_frdm/lpddr4x_ecc_2gb_timing.c | 1997 +++++++++++++++++
+ board/freescale/imx93_frdm/spl.c | 201 ++
+ configs/imx93_11x11_frdm_defconfig | 158 ++
+ include/configs/imx93_frdm.h | 27 +
+ 10 files changed, 4775 insertions(+)
+ create mode 100644 board/freescale/imx93_frdm/Kconfig
+ create mode 100644 board/freescale/imx93_frdm/MAINTAINERS
+ create mode 100644 board/freescale/imx93_frdm/Makefile
+ create mode 100644 board/freescale/imx93_frdm/imx93_frdm.c
+ create mode 100644 board/freescale/imx93_frdm/lpddr4x_2gb_timing.c
+ create mode 100644 board/freescale/imx93_frdm/lpddr4x_ecc_2gb_timing.c
+ create mode 100644 board/freescale/imx93_frdm/spl.c
+ create mode 100644 configs/imx93_11x11_frdm_defconfig
+ create mode 100644 include/configs/imx93_frdm.h
+
+diff --git a/arch/arm/mach-imx/imx9/Kconfig b/arch/arm/mach-imx/imx9/Kconfig
+index 0fd82dc0811..5b6587486ad 100644
+--- a/arch/arm/mach-imx/imx9/Kconfig
++++ b/arch/arm/mach-imx/imx9/Kconfig
+@@ -47,6 +47,11 @@ config TARGET_IMX91_11X11_EVK
+ imply BOOTSTD_FULL
+ imply BOOTSTD_BOOTCOMMAND
+
++config TARGET_IMX93_11X11_FRDM
++ bool "imx93_11x11_frdm"
++ select OF_BOARD_FIXUP
++ select IMX93
++
+ config TARGET_IMX93_9X9_QSB
+ bool "imx93_qsb"
+ select OF_BOARD_FIXUP
+@@ -91,6 +96,7 @@ source "board/freescale/imx93_qsb/Kconfig"
+ source "board/phytec/phycore_imx93/Kconfig"
+ source "board/variscite/imx93_var_som/Kconfig"
+ source "board/freescale/imx95_evk/Kconfig"
++source "board/freescale/imx93_frdm/Kconfig"
+
+ endif
+
+diff --git a/board/freescale/imx93_frdm/Kconfig b/board/freescale/imx93_frdm/Kconfig
+new file mode 100644
+index 00000000000..639cb61047f
+--- /dev/null
++++ b/board/freescale/imx93_frdm/Kconfig
+@@ -0,0 +1,19 @@
++if TARGET_IMX93_11X11_FRDM
++
++config SYS_BOARD
++ default "imx93_frdm"
++
++config SYS_VENDOR
++ default "freescale"
++
++config SYS_CONFIG_NAME
++ default "imx93_frdm"
++
++config IMX93_FRDM_LPDDR4X
++ bool "Using LPDDR4X Timing and PMIC voltage"
++ default y
++ select IMX9_LPDDR4X
++ help
++ Select the LPDDR4X timing and 0.6V VDDQ
++
++endif
+diff --git a/board/freescale/imx93_frdm/MAINTAINERS b/board/freescale/imx93_frdm/MAINTAINERS
+new file mode 100644
+index 00000000000..6d443f15a1c
+--- /dev/null
++++ b/board/freescale/imx93_frdm/MAINTAINERS
+@@ -0,0 +1,5 @@
++i.MX93 FRDM BOARD
++S: Maintained
++F: board/freescale/imx93_frdm/
++F: include/configs/imx93_frdm.h
++F: configs/imx93_11x11_frdm_defconfig
+diff --git a/board/freescale/imx93_frdm/Makefile b/board/freescale/imx93_frdm/Makefile
+new file mode 100644
+index 00000000000..adf4a15336c
+--- /dev/null
++++ b/board/freescale/imx93_frdm/Makefile
+@@ -0,0 +1,16 @@
++#
++# Copyright 2024-2025 NXP
++#
++# SPDX-License-Identifier: GPL-2.0+
++#
++
++obj-y += imx93_frdm.o
++
++ifdef CONFIG_SPL_BUILD
++obj-y += spl.o
++ifdef CONFIG_IMX9_DRAM_INLINE_ECC
++obj-$(CONFIG_IMX93_FRDM_LPDDR4X) += lpddr4x_ecc_2gb_timing.o
++else
++obj-$(CONFIG_IMX93_FRDM_LPDDR4X) += lpddr4x_2gb_timing.o
++endif
++endif
+\ No newline at end of file
+diff --git a/board/freescale/imx93_frdm/imx93_frdm.c b/board/freescale/imx93_frdm/imx93_frdm.c
+new file mode 100644
+index 00000000000..7b0e68a2ef8
+--- /dev/null
++++ b/board/freescale/imx93_frdm/imx93_frdm.c
+@@ -0,0 +1,350 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright 2024-2025 NXP
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++
++DECLARE_GLOBAL_DATA_PTR;
++
++#define UART_PAD_CTRL (PAD_CTL_DSE(6) | PAD_CTL_FSEL2)
++#define WDOG_PAD_CTRL (PAD_CTL_DSE(6) | PAD_CTL_ODE | PAD_CTL_PUE | PAD_CTL_PE)
++
++static const iomux_v3_cfg_t uart_pads[] = {
++ MX93_PAD_UART1_RXD__LPUART1_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
++ MX93_PAD_UART1_TXD__LPUART1_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
++};
++
++#if CONFIG_IS_ENABLED(EFI_HAVE_CAPSULE_SUPPORT)
++#define IMX_BOOT_IMAGE_GUID \
++ EFI_GUID(0xbc550d86, 0xda26, 0x4b70, 0xac, 0x05, \
++ 0x2a, 0x44, 0x8e, 0xda, 0x6f, 0x21)
++
++struct efi_fw_image fw_images[] = {
++ {
++ .image_type_id = IMX_BOOT_IMAGE_GUID,
++ .fw_name = u"IMX93-11X11-FRDM-RAW",
++ .image_index = 1,
++ },
++};
++
++struct efi_capsule_update_info update_info = {
++ .dfu_string = "mmc 0=flash-bin raw 0 0x2000 mmcpart 1",
++ .num_images = ARRAY_SIZE(fw_images),
++ .images = fw_images,
++};
++
++#endif /* EFI_HAVE_CAPSULE_SUPPORT */
++
++int board_early_init_f(void)
++{
++ imx_iomux_v3_setup_multiple_pads(uart_pads, ARRAY_SIZE(uart_pads));
++
++ return 0;
++}
++
++#ifdef CONFIG_USB_TCPC
++struct tcpc_port port1;
++struct tcpc_port portpd;
++
++static int setup_pd_switch(u8 i2c_bus, u8 addr)
++{
++ struct udevice *bus;
++ struct udevice *i2c_dev = NULL;
++ int ret;
++ u8 valb;
++
++ ret = uclass_get_device_by_seq(UCLASS_I2C, i2c_bus, &bus);
++ if (ret) {
++ printf("%s: Can't find bus\n", __func__);
++ return -EINVAL;
++ }
++
++ ret = dm_i2c_probe(bus, addr, 0, &i2c_dev);
++ if (ret) {
++ printf("%s: Can't find device id=0x%x\n",__func__, addr);
++ return -ENODEV;
++ }
++
++ ret = dm_i2c_read(i2c_dev, 0xB, &valb, 1);
++ if (ret) {
++ printf("%s dm_i2c_read failed, err %d\n", __func__, ret);
++ return -EIO;
++ }
++ valb |= 0x4; /* Set DB_EXIT to exit dead battery mode */
++ ret = dm_i2c_write(i2c_dev, 0xB, (const uint8_t *)&valb, 1);
++ if (ret) {
++ printf("%s dm_i2c_write failed, err %d\n", __func__, ret);
++ return -EIO;
++ }
++
++ /* Set OVP threshold to 23V */
++ valb = 0x6;
++ ret = dm_i2c_write(i2c_dev, 0x8, (const uint8_t *)&valb, 1);
++ if (ret) {
++ printf("%s dm_i2c_write failed, err %d\n", __func__, ret);
++ return -EIO;
++ }
++
++ return 0;
++}
++
++int pd_switch_snk_enable(struct tcpc_port *port)
++{
++ if (port == &port1) {
++ debug("Setup pd switch on port 1\n");
++ return setup_pd_switch(2, 0x71);
++ } else {
++ return -EINVAL;
++ }
++}
++
++struct tcpc_port_config portpd_config = {
++ .i2c_bus = 2, /*i2c3*/
++ .addr = 0x52,
++ .port_type = TYPEC_PORT_UFP,
++ .max_snk_mv = 20000,
++ .max_snk_ma = 3000,
++ .max_snk_mw = 15000,
++ .op_snk_mv = 9000,
++};
++
++struct tcpc_port_config port1_config = {
++ .i2c_bus = 2, /*i2c3*/
++ .addr = 0x50,
++ .port_type = TYPEC_PORT_UFP,
++ .max_snk_mv = 5000,
++ .max_snk_ma = 3000,
++ .max_snk_mw = 40000,
++ .op_snk_mv = 9000,
++ .switch_setup_func = &pd_switch_snk_enable,
++ .disable_pd = true,
++};
++
++static int setup_typec(void)
++{
++ int ret;
++
++ debug("tcpc_init port pd\n");
++ ret = tcpc_init(&portpd, portpd_config, NULL);
++ if (ret) {
++ printf("%s: tcpc portpd init failed, err=%d\n",__func__, ret);
++ return ret;
++ }
++
++ debug("tcpc_init port 1\n");
++ ret = tcpc_init(&port1, port1_config, NULL);
++ if (ret) {
++ printf("%s: tcpc port1 init failed, err=%d\n",__func__, ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++int board_usb_init(int index, enum usb_init_type init)
++{
++ int ret = 0;
++ struct tcpc_port *port_ptr;
++
++ debug("%s %d, type %d\n", __func__, index, init);
++
++ if (index == 0) {
++ port_ptr = &port1;
++
++ if (init == USB_INIT_HOST)
++ tcpc_setup_dfp_mode(port_ptr);
++ else
++ tcpc_setup_ufp_mode(port_ptr);
++ }
++
++ return ret;
++}
++
++int board_usb_cleanup(int index, enum usb_init_type init)
++{
++ int ret = 0;
++
++ debug("%s %d, type %d\n", __func__, index, init);
++
++ if (init == USB_INIT_HOST) {
++ if (index == 0)
++ ret = tcpc_disable_src_vbus(&port1);
++ }
++
++ return ret;
++}
++
++int board_ehci_usb_phy_mode(struct udevice *dev)
++{
++ int ret = 0;
++ enum typec_cc_polarity pol;
++ enum typec_cc_state state;
++ struct tcpc_port *port_ptr;
++
++ debug("%s %d\n", __func__, dev_seq(dev));
++
++ if (dev_seq(dev) == 0) {
++ port_ptr = &port1;
++
++ tcpc_setup_ufp_mode(port_ptr);
++
++ ret = tcpc_get_cc_status(port_ptr, &pol, &state);
++
++ tcpc_print_log(port_ptr);
++ if (!ret) {
++ if (state == TYPEC_STATE_SRC_RD_RA || state == TYPEC_STATE_SRC_RD)
++ return USB_INIT_HOST;
++ }
++ }
++
++ return USB_INIT_DEVICE;
++}
++#endif
++
++static int setup_fec(void)
++{
++ return set_clk_enet(ENET_125MHZ);
++}
++
++int board_phy_config(struct phy_device *phydev)
++{
++ if (phydev->drv->config)
++ phydev->drv->config(phydev);
++
++ return 0;
++}
++
++static void board_gpio_init(void)
++{
++ struct gpio_desc desc;
++ int ret;
++
++ /* Enable EXT1_PWREN for PCIE_3.3V */
++ ret = dm_gpio_lookup_name("gpio@22_13", &desc);
++ if (ret)
++ return;
++
++ ret = dm_gpio_request(&desc, "EXT1_PWREN");
++ if (ret)
++ return;
++
++ dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT);
++ dm_gpio_set_value(&desc, 1);
++
++ /* Deassert SD3_nRST */
++ ret = dm_gpio_lookup_name("gpio@22_12", &desc);
++ if (ret)
++ return;
++
++ ret = dm_gpio_request(&desc, "SD3_nRST");
++ if (ret)
++ return;
++
++ dm_gpio_set_dir_flags(&desc, GPIOD_IS_OUT);
++ dm_gpio_set_value(&desc, 1);
++}
++
++static int print_board_version(void)
++{
++ int i, ret;
++ struct udevice *dev;
++ unsigned int rev[2];
++ unsigned int data[2];
++
++ ret = uclass_first_device_check(UCLASS_ADC, &dev);
++
++ if (dev) {
++ ret = adc_channel_single_shot(dev->name, 2, &data[0]);
++ if (ret) {
++ printf("BOARD: unknown\n");
++ return 0;
++ }
++ ret = adc_channel_single_shot(dev->name, 3, &data[1]);
++ if (ret) {
++ printf("BOARD: unknown\n");
++ return 0;
++ }
++
++ for (i = 0; i < 2; i++) {
++ if (data[i] < 500)
++ rev[i] = 0;
++ else if (data[i] < 700)
++ rev[i] = 1;
++ else if (data[i] < 1500)
++ rev[i] = 2;
++ else if (data[i] < 2300)
++ rev[i] = 3;
++ else if (data[i] < 3000)
++ rev[i] = 4;
++ else if (data[i] < 3600)
++ rev[i] = 5;
++ else
++ rev[i] = 6;
++ }
++ printf("BOARD: V%d.%d(ADC2:%d,ADC3:%d)\n", rev[0], rev[1], data[0], data[1]);
++ } else {
++ printf("BOARD: unknown\n");
++ }
++
++ return 0;
++}
++
++int board_init(void)
++{
++#ifdef CONFIG_USB_TCPC
++ setup_typec();
++#endif
++ print_board_version();
++
++ if (IS_ENABLED(CONFIG_FEC_MXC))
++ setup_fec();
++
++ board_gpio_init();
++
++ return 0;
++}
++
++int board_late_init(void)
++{
++#ifdef CONFIG_ENV_IS_IN_MMC
++ board_late_mmc_env_init();
++#endif
++
++ env_set("sec_boot", "no");
++#ifdef CONFIG_AHAB_BOOT
++ env_set("sec_boot", "yes");
++#endif
++
++#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
++ env_set("board_name", "11X11_FRDM");
++ env_set("board_rev", "iMX93");
++#endif
++ return 0;
++}
++
++#ifdef CONFIG_FSL_FASTBOOT
++#ifdef CONFIG_ANDROID_RECOVERY
++int is_recovery_key_pressing(void)
++{
++ return 0;
++}
++#endif /*CONFIG_ANDROID_RECOVERY*/
++#endif /*CONFIG_FSL_FASTBOOT*/
+diff --git a/board/freescale/imx93_frdm/lpddr4x_2gb_timing.c b/board/freescale/imx93_frdm/lpddr4x_2gb_timing.c
+new file mode 100644
+index 00000000000..f9da1c6b5f4
+--- /dev/null
++++ b/board/freescale/imx93_frdm/lpddr4x_2gb_timing.c
+@@ -0,0 +1,1996 @@
++/*
++ * Copyright 2024 NXP
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ *
++ * Code generated with DDR Tool v3.4.0_8.3-4e2b550a.
++ * DDR PHY FW2022.01
++ */
++
++#include
++#include
++
++/* Initialize DDRC registers */
++static struct dram_cfg_param ddr_ddrc_cfg[] = {
++ {0x4e300110, 0x44100001},
++ {0x4e300000, 0x8000ff},
++ {0x4e300008, 0x0},
++ {0x4e300080, 0x80000512},
++ {0x4e300084, 0x0},
++ {0x4e300114, 0x1002},
++ {0x4e300260, 0x80},
++ {0x4e300f04, 0x80},
++ {0x4e300800, 0x43b30002},
++ {0x4e300804, 0x1f1f1f1f},
++ {0x4e301000, 0x0},
++ {0x4e301240, 0x0},
++ {0x4e301244, 0x0},
++ {0x4e301248, 0x0},
++ {0x4e30124c, 0x0},
++ {0x4e301250, 0x0},
++ {0x4e301254, 0x0},
++ {0x4e301258, 0x0},
++ {0x4e30125c, 0x0},
++};
++
++/* dram fsp cfg */
++static struct dram_fsp_cfg ddr_dram_fsp_cfg[] = {
++ {
++ {
++ {0x4e300100, 0x24AB321B},
++ {0x4e300104, 0xF8EE001B},
++ {0x4e300108, 0x2F2EE233},
++ {0x4e30010C, 0x0005E18B},
++ {0x4e300124, 0x1C760000},
++ {0x4e300160, 0x00009102},
++ {0x4e30016C, 0x35F00000},
++ {0x4e300170, 0x8B0B0608},
++ {0x4e300250, 0x00000028},
++ {0x4e300254, 0x015B015B},
++ {0x4e300258, 0x00000008},
++ {0x4e30025C, 0x00000400},
++ {0x4e300300, 0x224F2213},
++ {0x4e300304, 0x015B2213},
++ {0x4e300308, 0x0A3C0E3D},
++ },
++ {
++ {0x01, 0xE4},
++ {0x02, 0x36},
++ {0x03, 0x32},
++ {0x0b, 0x46},
++ {0x0c, 0x11},
++ {0x0e, 0x11},
++ {0x16, 0x04},
++ },
++ 0,
++ },
++ {
++ {
++ {0x4e300100, 0x12552100},
++ {0x4e300104, 0xF877000E},
++ {0x4e300108, 0x1816B4AA},
++ {0x4e30010C, 0x005101E6},
++ {0x4e300124, 0x0E3C0000},
++ {0x4e300160, 0x00009101},
++ {0x4e30016C, 0x30900000},
++ {0x4e300170, 0x8A0A0508},
++ {0x4e300250, 0x00000014},
++ {0x4e300254, 0x00AA00AA},
++ {0x4e300258, 0x00000008},
++ {0x4e30025C, 0x00000400},
++ },
++ {
++ {0x01, 0xB4},
++ {0x02, 0x1B},
++ {0x03, 0x32},
++ {0x0b, 0x46},
++ {0x0c, 0x11},
++ {0x0e, 0x11},
++ {0x16, 0x04},
++ },
++ 0,
++ },
++ {
++ {
++ {0x4e300100, 0x00061000},
++ {0x4e300104, 0xF855000A},
++ {0x4e300108, 0x6E62FA48},
++ {0x4e30010C, 0x0031010D},
++ {0x4e300124, 0x04C50000},
++ {0x4e300160, 0x00009100},
++ {0x4e30016C, 0x30000000},
++ {0x4e300170, 0x89090408},
++ {0x4e300250, 0x00000007},
++ {0x4e300254, 0x00340034},
++ {0x4e300258, 0x00000008},
++ {0x4e30025C, 0x00000400},
++ },
++ {
++ {0x01, 0x94},
++ {0x02, 0x9},
++ {0x03, 0x32},
++ {0x0b, 0x46},
++ {0x0c, 0x11},
++ {0x0e, 0x11},
++ {0x16, 0x04},
++ },
++ 1,
++ },
++};
++
++/* PHY Initialize Configuration */
++static struct dram_cfg_param ddr_ddrphy_cfg[] = {
++ {0x100a0, 0x4},
++ {0x100a1, 0x5},
++ {0x100a2, 0x6},
++ {0x100a3, 0x7},
++ {0x100a4, 0x0},
++ {0x100a5, 0x1},
++ {0x100a6, 0x2},
++ {0x100a7, 0x3},
++ {0x110a0, 0x3},
++ {0x110a1, 0x2},
++ {0x110a2, 0x0},
++ {0x110a3, 0x1},
++ {0x110a4, 0x7},
++ {0x110a5, 0x6},
++ {0x110a6, 0x4},
++ {0x110a7, 0x5},
++ {0x1005f, 0x5ff},
++ {0x1015f, 0x5ff},
++ {0x1105f, 0x5ff},
++ {0x1115f, 0x5ff},
++ {0x11005f, 0x5ff},
++ {0x11015f, 0x5ff},
++ {0x11105f, 0x5ff},
++ {0x11115f, 0x5ff},
++ {0x21005f, 0x5ff},
++ {0x21015f, 0x5ff},
++ {0x21105f, 0x5ff},
++ {0x21115f, 0x5ff},
++ {0x55, 0x1ff},
++ {0x1055, 0x1ff},
++ {0x2055, 0x1ff},
++ {0x200c5, 0x19},
++ {0x1200c5, 0xb},
++ {0x2200c5, 0x7},
++ {0x2002e, 0x2},
++ {0x12002e, 0x2},
++ {0x22002e, 0x2},
++ {0x90204, 0x0},
++ {0x190204, 0x0},
++ {0x290204, 0x0},
++ {0x20024, 0x1e3},
++ {0x2003a, 0x2},
++ {0x2007d, 0x212},
++ {0x2007c, 0x61},
++ {0x120024, 0x1e3},
++ {0x2003a, 0x2},
++ {0x12007d, 0x212},
++ {0x12007c, 0x61},
++ {0x220024, 0x1e3},
++ {0x2003a, 0x2},
++ {0x22007d, 0x212},
++ {0x22007c, 0x61},
++ {0x20056, 0x3},
++ {0x120056, 0x3},
++ {0x220056, 0x3},
++ {0x1004d, 0x600},
++ {0x1014d, 0x600},
++ {0x1104d, 0x600},
++ {0x1114d, 0x600},
++ {0x11004d, 0x600},
++ {0x11014d, 0x600},
++ {0x11104d, 0x600},
++ {0x11114d, 0x600},
++ {0x21004d, 0x600},
++ {0x21014d, 0x600},
++ {0x21104d, 0x600},
++ {0x21114d, 0x600},
++ {0x10049, 0xe00},
++ {0x10149, 0xe00},
++ {0x11049, 0xe00},
++ {0x11149, 0xe00},
++ {0x110049, 0xe00},
++ {0x110149, 0xe00},
++ {0x111049, 0xe00},
++ {0x111149, 0xe00},
++ {0x210049, 0xe00},
++ {0x210149, 0xe00},
++ {0x211049, 0xe00},
++ {0x211149, 0xe00},
++ {0x43, 0x60},
++ {0x1043, 0x60},
++ {0x2043, 0x60},
++ {0x20018, 0x1},
++ {0x20075, 0x4},
++ {0x20050, 0x0},
++ {0x2009b, 0x2},
++ {0x20008, 0x3a5},
++ {0x120008, 0x1d3},
++ {0x220008, 0x9c},
++ {0x20088, 0x9},
++ {0x200b2, 0x10c},
++ {0x10043, 0x5a1},
++ {0x10143, 0x5a1},
++ {0x11043, 0x5a1},
++ {0x11143, 0x5a1},
++ {0x1200b2, 0x10c},
++ {0x110043, 0x5a1},
++ {0x110143, 0x5a1},
++ {0x111043, 0x5a1},
++ {0x111143, 0x5a1},
++ {0x2200b2, 0x10c},
++ {0x210043, 0x5a1},
++ {0x210143, 0x5a1},
++ {0x211043, 0x5a1},
++ {0x211143, 0x5a1},
++ {0x200fa, 0x2},
++ {0x1200fa, 0x2},
++ {0x2200fa, 0x2},
++ {0x20019, 0x1},
++ {0x120019, 0x1},
++ {0x220019, 0x1},
++ {0x200f0, 0x600},
++ {0x200f1, 0x0},
++ {0x200f2, 0x4444},
++ {0x200f3, 0x8888},
++ {0x200f4, 0x5655},
++ {0x200f5, 0x0},
++ {0x200f6, 0x0},
++ {0x200f7, 0xf000},
++ {0x1004a, 0x500},
++ {0x1104a, 0x500},
++ {0x20025, 0x0},
++ {0x2002d, 0x0},
++ {0x12002d, 0x0},
++ {0x22002d, 0x0},
++ {0x2002c, 0x0},
++ {0x20021, 0x0},
++ {0x200c7, 0x21},
++ {0x1200c7, 0x21},
++ {0x200ca, 0x24},
++ {0x1200ca, 0x24},
++};
++
++/* ddr phy trained csr */
++static struct dram_cfg_param ddr_ddrphy_trained_csr[] = {
++ {0x1005f, 0x0},
++ {0x1015f, 0x0},
++ {0x1105f, 0x0},
++ {0x1115f, 0x0},
++ {0x11005f, 0x0},
++ {0x11015f, 0x0},
++ {0x11105f, 0x0},
++ {0x11115f, 0x0},
++ {0x21005f, 0x0},
++ {0x21015f, 0x0},
++ {0x21105f, 0x0},
++ {0x21115f, 0x0},
++ {0x55, 0x0},
++ {0x1055, 0x0},
++ {0x2055, 0x0},
++ {0x200c5, 0x0},
++ {0x1200c5, 0x0},
++ {0x2200c5, 0x0},
++ {0x2002e, 0x0},
++ {0x12002e, 0x0},
++ {0x22002e, 0x0},
++ {0x90204, 0x0},
++ {0x190204, 0x0},
++ {0x290204, 0x0},
++ {0x20024, 0x0},
++ {0x2003a, 0x0},
++ {0x2007d, 0x0},
++ {0x2007c, 0x0},
++ {0x120024, 0x0},
++ {0x12007d, 0x0},
++ {0x12007c, 0x0},
++ {0x220024, 0x0},
++ {0x22007d, 0x0},
++ {0x22007c, 0x0},
++ {0x20056, 0x0},
++ {0x120056, 0x0},
++ {0x220056, 0x0},
++ {0x1004d, 0x0},
++ {0x1014d, 0x0},
++ {0x1104d, 0x0},
++ {0x1114d, 0x0},
++ {0x11004d, 0x0},
++ {0x11014d, 0x0},
++ {0x11104d, 0x0},
++ {0x11114d, 0x0},
++ {0x21004d, 0x0},
++ {0x21014d, 0x0},
++ {0x21104d, 0x0},
++ {0x21114d, 0x0},
++ {0x10049, 0x0},
++ {0x10149, 0x0},
++ {0x11049, 0x0},
++ {0x11149, 0x0},
++ {0x110049, 0x0},
++ {0x110149, 0x0},
++ {0x111049, 0x0},
++ {0x111149, 0x0},
++ {0x210049, 0x0},
++ {0x210149, 0x0},
++ {0x211049, 0x0},
++ {0x211149, 0x0},
++ {0x43, 0x0},
++ {0x1043, 0x0},
++ {0x2043, 0x0},
++ {0x20018, 0x0},
++ {0x20075, 0x0},
++ {0x20050, 0x0},
++ {0x2009b, 0x0},
++ {0x20008, 0x0},
++ {0x120008, 0x0},
++ {0x220008, 0x0},
++ {0x20088, 0x0},
++ {0x200b2, 0x0},
++ {0x10043, 0x0},
++ {0x10143, 0x0},
++ {0x11043, 0x0},
++ {0x11143, 0x0},
++ {0x1200b2, 0x0},
++ {0x110043, 0x0},
++ {0x110143, 0x0},
++ {0x111043, 0x0},
++ {0x111143, 0x0},
++ {0x2200b2, 0x0},
++ {0x210043, 0x0},
++ {0x210143, 0x0},
++ {0x211043, 0x0},
++ {0x211143, 0x0},
++ {0x200fa, 0x0},
++ {0x1200fa, 0x0},
++ {0x2200fa, 0x0},
++ {0x20019, 0x0},
++ {0x120019, 0x0},
++ {0x220019, 0x0},
++ {0x200f0, 0x0},
++ {0x200f1, 0x0},
++ {0x200f2, 0x0},
++ {0x200f3, 0x0},
++ {0x200f4, 0x0},
++ {0x200f5, 0x0},
++ {0x200f6, 0x0},
++ {0x200f7, 0x0},
++ {0x1004a, 0x0},
++ {0x1104a, 0x0},
++ {0x20025, 0x0},
++ {0x2002d, 0x0},
++ {0x12002d, 0x0},
++ {0x22002d, 0x0},
++ {0x2002c, 0x0},
++ {0xd0000, 0x0},
++ {0x90000, 0x0},
++ {0x90001, 0x0},
++ {0x90002, 0x0},
++ {0x90003, 0x0},
++ {0x90004, 0x0},
++ {0x90005, 0x0},
++ {0x90029, 0x0},
++ {0x9002a, 0x0},
++ {0x9002b, 0x0},
++ {0x9002c, 0x0},
++ {0x9002d, 0x0},
++ {0x9002e, 0x0},
++ {0x9002f, 0x0},
++ {0x90030, 0x0},
++ {0x90031, 0x0},
++ {0x90032, 0x0},
++ {0x90033, 0x0},
++ {0x90034, 0x0},
++ {0x90035, 0x0},
++ {0x90036, 0x0},
++ {0x90037, 0x0},
++ {0x90038, 0x0},
++ {0x90039, 0x0},
++ {0x9003a, 0x0},
++ {0x9003b, 0x0},
++ {0x9003c, 0x0},
++ {0x9003d, 0x0},
++ {0x9003e, 0x0},
++ {0x9003f, 0x0},
++ {0x90040, 0x0},
++ {0x90041, 0x0},
++ {0x90042, 0x0},
++ {0x90043, 0x0},
++ {0x90044, 0x0},
++ {0x90045, 0x0},
++ {0x90046, 0x0},
++ {0x90047, 0x0},
++ {0x90048, 0x0},
++ {0x90049, 0x0},
++ {0x9004a, 0x0},
++ {0x9004b, 0x0},
++ {0x9004c, 0x0},
++ {0x9004d, 0x0},
++ {0x9004e, 0x0},
++ {0x9004f, 0x0},
++ {0x90050, 0x0},
++ {0x90051, 0x0},
++ {0x90052, 0x0},
++ {0x90053, 0x0},
++ {0x90054, 0x0},
++ {0x90055, 0x0},
++ {0x90056, 0x0},
++ {0x90057, 0x0},
++ {0x90058, 0x0},
++ {0x90059, 0x0},
++ {0x9005a, 0x0},
++ {0x9005b, 0x0},
++ {0x9005c, 0x0},
++ {0x9005d, 0x0},
++ {0x9005e, 0x0},
++ {0x9005f, 0x0},
++ {0x90060, 0x0},
++ {0x90061, 0x0},
++ {0x90062, 0x0},
++ {0x90063, 0x0},
++ {0x90064, 0x0},
++ {0x90065, 0x0},
++ {0x90066, 0x0},
++ {0x90067, 0x0},
++ {0x90068, 0x0},
++ {0x90069, 0x0},
++ {0x9006a, 0x0},
++ {0x9006b, 0x0},
++ {0x9006c, 0x0},
++ {0x9006d, 0x0},
++ {0x9006e, 0x0},
++ {0x9006f, 0x0},
++ {0x90070, 0x0},
++ {0x90071, 0x0},
++ {0x90072, 0x0},
++ {0x90073, 0x0},
++ {0x90074, 0x0},
++ {0x90075, 0x0},
++ {0x90076, 0x0},
++ {0x90077, 0x0},
++ {0x90078, 0x0},
++ {0x90079, 0x0},
++ {0x9007a, 0x0},
++ {0x9007b, 0x0},
++ {0x9007c, 0x0},
++ {0x9007d, 0x0},
++ {0x9007e, 0x0},
++ {0x9007f, 0x0},
++ {0x90080, 0x0},
++ {0x90081, 0x0},
++ {0x90082, 0x0},
++ {0x90083, 0x0},
++ {0x90084, 0x0},
++ {0x90085, 0x0},
++ {0x90086, 0x0},
++ {0x90087, 0x0},
++ {0x90088, 0x0},
++ {0x90089, 0x0},
++ {0x9008a, 0x0},
++ {0x9008b, 0x0},
++ {0x9008c, 0x0},
++ {0x9008d, 0x0},
++ {0x9008e, 0x0},
++ {0x9008f, 0x0},
++ {0x90090, 0x0},
++ {0x90091, 0x0},
++ {0x90092, 0x0},
++ {0x90093, 0x0},
++ {0x90094, 0x0},
++ {0x90095, 0x0},
++ {0x90096, 0x0},
++ {0x90097, 0x0},
++ {0x90098, 0x0},
++ {0x90099, 0x0},
++ {0x9009a, 0x0},
++ {0x9009b, 0x0},
++ {0x9009c, 0x0},
++ {0x9009d, 0x0},
++ {0x9009e, 0x0},
++ {0x9009f, 0x0},
++ {0x900a0, 0x0},
++ {0x900a1, 0x0},
++ {0x900a2, 0x0},
++ {0x900a3, 0x0},
++ {0x900a4, 0x0},
++ {0x900a5, 0x0},
++ {0x900a6, 0x0},
++ {0x900a7, 0x0},
++ {0x900a8, 0x0},
++ {0x900a9, 0x0},
++ {0x40000, 0x0},
++ {0x40020, 0x0},
++ {0x40040, 0x0},
++ {0x40060, 0x0},
++ {0x40001, 0x0},
++ {0x40021, 0x0},
++ {0x40041, 0x0},
++ {0x40061, 0x0},
++ {0x40002, 0x0},
++ {0x40022, 0x0},
++ {0x40042, 0x0},
++ {0x40062, 0x0},
++ {0x40003, 0x0},
++ {0x40023, 0x0},
++ {0x40043, 0x0},
++ {0x40063, 0x0},
++ {0x40004, 0x0},
++ {0x40024, 0x0},
++ {0x40044, 0x0},
++ {0x40064, 0x0},
++ {0x40005, 0x0},
++ {0x40025, 0x0},
++ {0x40045, 0x0},
++ {0x40065, 0x0},
++ {0x40006, 0x0},
++ {0x40026, 0x0},
++ {0x40046, 0x0},
++ {0x40066, 0x0},
++ {0x40007, 0x0},
++ {0x40027, 0x0},
++ {0x40047, 0x0},
++ {0x40067, 0x0},
++ {0x40008, 0x0},
++ {0x40028, 0x0},
++ {0x40048, 0x0},
++ {0x40068, 0x0},
++ {0x40009, 0x0},
++ {0x40029, 0x0},
++ {0x40049, 0x0},
++ {0x40069, 0x0},
++ {0x4000a, 0x0},
++ {0x4002a, 0x0},
++ {0x4004a, 0x0},
++ {0x4006a, 0x0},
++ {0x4000b, 0x0},
++ {0x4002b, 0x0},
++ {0x4004b, 0x0},
++ {0x4006b, 0x0},
++ {0x4000c, 0x0},
++ {0x4002c, 0x0},
++ {0x4004c, 0x0},
++ {0x4006c, 0x0},
++ {0x4000d, 0x0},
++ {0x4002d, 0x0},
++ {0x4004d, 0x0},
++ {0x4006d, 0x0},
++ {0x4000e, 0x0},
++ {0x4002e, 0x0},
++ {0x4004e, 0x0},
++ {0x4006e, 0x0},
++ {0x4000f, 0x0},
++ {0x4002f, 0x0},
++ {0x4004f, 0x0},
++ {0x4006f, 0x0},
++ {0x40010, 0x0},
++ {0x40030, 0x0},
++ {0x40050, 0x0},
++ {0x40070, 0x0},
++ {0x40011, 0x0},
++ {0x40031, 0x0},
++ {0x40051, 0x0},
++ {0x40071, 0x0},
++ {0x40012, 0x0},
++ {0x40032, 0x0},
++ {0x40052, 0x0},
++ {0x40072, 0x0},
++ {0x40013, 0x0},
++ {0x40033, 0x0},
++ {0x40053, 0x0},
++ {0x40073, 0x0},
++ {0x40014, 0x0},
++ {0x40034, 0x0},
++ {0x40054, 0x0},
++ {0x40074, 0x0},
++ {0x40015, 0x0},
++ {0x40035, 0x0},
++ {0x40055, 0x0},
++ {0x40075, 0x0},
++ {0x40016, 0x0},
++ {0x40036, 0x0},
++ {0x40056, 0x0},
++ {0x40076, 0x0},
++ {0x40017, 0x0},
++ {0x40037, 0x0},
++ {0x40057, 0x0},
++ {0x40077, 0x0},
++ {0x40018, 0x0},
++ {0x40038, 0x0},
++ {0x40058, 0x0},
++ {0x40078, 0x0},
++ {0x40019, 0x0},
++ {0x40039, 0x0},
++ {0x40059, 0x0},
++ {0x40079, 0x0},
++ {0x4001a, 0x0},
++ {0x4003a, 0x0},
++ {0x4005a, 0x0},
++ {0x4007a, 0x0},
++ {0x900aa, 0x0},
++ {0x900ab, 0x0},
++ {0x900ac, 0x0},
++ {0x900ad, 0x0},
++ {0x900ae, 0x0},
++ {0x900af, 0x0},
++ {0x900b0, 0x0},
++ {0x900b1, 0x0},
++ {0x900b2, 0x0},
++ {0x900b3, 0x0},
++ {0x900b4, 0x0},
++ {0x900b5, 0x0},
++ {0x900b6, 0x0},
++ {0x900b7, 0x0},
++ {0x900b8, 0x0},
++ {0x900b9, 0x0},
++ {0x900ba, 0x0},
++ {0x900bb, 0x0},
++ {0x900bc, 0x0},
++ {0x900bd, 0x0},
++ {0x900be, 0x0},
++ {0x900bf, 0x0},
++ {0x900c0, 0x0},
++ {0x900c1, 0x0},
++ {0x900c2, 0x0},
++ {0x900c3, 0x0},
++ {0x900c4, 0x0},
++ {0x900c5, 0x0},
++ {0x900c6, 0x0},
++ {0x900c7, 0x0},
++ {0x900c8, 0x0},
++ {0x900c9, 0x0},
++ {0x900ca, 0x0},
++ {0x900cb, 0x0},
++ {0x900cc, 0x0},
++ {0x900cd, 0x0},
++ {0x900ce, 0x0},
++ {0x900cf, 0x0},
++ {0x900d0, 0x0},
++ {0x900d1, 0x0},
++ {0x900d2, 0x0},
++ {0x900d3, 0x0},
++ {0x900d4, 0x0},
++ {0x900d5, 0x0},
++ {0x900d6, 0x0},
++ {0x900d7, 0x0},
++ {0x900d8, 0x0},
++ {0x900d9, 0x0},
++ {0x900da, 0x0},
++ {0x900db, 0x0},
++ {0x900dc, 0x0},
++ {0x900dd, 0x0},
++ {0x900de, 0x0},
++ {0x900df, 0x0},
++ {0x900e0, 0x0},
++ {0x900e1, 0x0},
++ {0x900e2, 0x0},
++ {0x900e3, 0x0},
++ {0x900e4, 0x0},
++ {0x900e5, 0x0},
++ {0x900e6, 0x0},
++ {0x900e7, 0x0},
++ {0x900e8, 0x0},
++ {0x900e9, 0x0},
++ {0x900ea, 0x0},
++ {0x900eb, 0x0},
++ {0x900ec, 0x0},
++ {0x900ed, 0x0},
++ {0x900ee, 0x0},
++ {0x900ef, 0x0},
++ {0x900f0, 0x0},
++ {0x900f1, 0x0},
++ {0x900f2, 0x0},
++ {0x900f3, 0x0},
++ {0x900f4, 0x0},
++ {0x900f5, 0x0},
++ {0x900f6, 0x0},
++ {0x900f7, 0x0},
++ {0x900f8, 0x0},
++ {0x900f9, 0x0},
++ {0x900fa, 0x0},
++ {0x900fb, 0x0},
++ {0x900fc, 0x0},
++ {0x900fd, 0x0},
++ {0x900fe, 0x0},
++ {0x900ff, 0x0},
++ {0x90100, 0x0},
++ {0x90101, 0x0},
++ {0x90102, 0x0},
++ {0x90103, 0x0},
++ {0x90104, 0x0},
++ {0x90105, 0x0},
++ {0x90106, 0x0},
++ {0x90107, 0x0},
++ {0x90108, 0x0},
++ {0x90109, 0x0},
++ {0x9010a, 0x0},
++ {0x9010b, 0x0},
++ {0x9010c, 0x0},
++ {0x9010d, 0x0},
++ {0x9010e, 0x0},
++ {0x9010f, 0x0},
++ {0x90110, 0x0},
++ {0x90111, 0x0},
++ {0x90112, 0x0},
++ {0x90113, 0x0},
++ {0x90114, 0x0},
++ {0x90115, 0x0},
++ {0x90116, 0x0},
++ {0x90117, 0x0},
++ {0x90118, 0x0},
++ {0x90119, 0x0},
++ {0x9011a, 0x0},
++ {0x9011b, 0x0},
++ {0x9011c, 0x0},
++ {0x9011d, 0x0},
++ {0x9011e, 0x0},
++ {0x9011f, 0x0},
++ {0x90120, 0x0},
++ {0x90121, 0x0},
++ {0x90122, 0x0},
++ {0x90123, 0x0},
++ {0x90124, 0x0},
++ {0x90125, 0x0},
++ {0x90126, 0x0},
++ {0x90127, 0x0},
++ {0x90128, 0x0},
++ {0x90129, 0x0},
++ {0x9012a, 0x0},
++ {0x9012b, 0x0},
++ {0x9012c, 0x0},
++ {0x9012d, 0x0},
++ {0x9012e, 0x0},
++ {0x9012f, 0x0},
++ {0x90130, 0x0},
++ {0x90131, 0x0},
++ {0x90132, 0x0},
++ {0x90133, 0x0},
++ {0x90134, 0x0},
++ {0x90135, 0x0},
++ {0x90136, 0x0},
++ {0x90137, 0x0},
++ {0x90138, 0x0},
++ {0x90139, 0x0},
++ {0x9013a, 0x0},
++ {0x9013b, 0x0},
++ {0x9013c, 0x0},
++ {0x9013d, 0x0},
++ {0x9013e, 0x0},
++ {0x9013f, 0x0},
++ {0x90140, 0x0},
++ {0x90141, 0x0},
++ {0x90142, 0x0},
++ {0x90143, 0x0},
++ {0x90144, 0x0},
++ {0x90145, 0x0},
++ {0x90146, 0x0},
++ {0x90147, 0x0},
++ {0x90148, 0x0},
++ {0x90149, 0x0},
++ {0x9014a, 0x0},
++ {0x9014b, 0x0},
++ {0x9014c, 0x0},
++ {0x9014d, 0x0},
++ {0x9014e, 0x0},
++ {0x9014f, 0x0},
++ {0x90150, 0x0},
++ {0x90151, 0x0},
++ {0x90152, 0x0},
++ {0x90153, 0x0},
++ {0x90154, 0x0},
++ {0x90155, 0x0},
++ {0x90156, 0x0},
++ {0x90157, 0x0},
++ {0x90158, 0x0},
++ {0x90159, 0x0},
++ {0x9015a, 0x0},
++ {0x9015b, 0x0},
++ {0x9015c, 0x0},
++ {0x9015d, 0x0},
++ {0x9015e, 0x0},
++ {0x9015f, 0x0},
++ {0x90160, 0x0},
++ {0x90161, 0x0},
++ {0x90162, 0x0},
++ {0x90163, 0x0},
++ {0x90164, 0x0},
++ {0x90165, 0x0},
++ {0x90166, 0x0},
++ {0x90167, 0x0},
++ {0x90168, 0x0},
++ {0x90169, 0x0},
++ {0x9016a, 0x0},
++ {0x9016b, 0x0},
++ {0x9016c, 0x0},
++ {0x9016d, 0x0},
++ {0x9016e, 0x0},
++ {0x9016f, 0x0},
++ {0x90170, 0x0},
++ {0x90171, 0x0},
++ {0x90172, 0x0},
++ {0x90173, 0x0},
++ {0x90174, 0x0},
++ {0x90175, 0x0},
++ {0x90176, 0x0},
++ {0x90177, 0x0},
++ {0x90178, 0x0},
++ {0x90179, 0x0},
++ {0x9017a, 0x0},
++ {0x9017b, 0x0},
++ {0x9017c, 0x0},
++ {0x9017d, 0x0},
++ {0x9017e, 0x0},
++ {0x9017f, 0x0},
++ {0x90180, 0x0},
++ {0x90181, 0x0},
++ {0x90182, 0x0},
++ {0x90183, 0x0},
++ {0x90184, 0x0},
++ {0x90006, 0x0},
++ {0x90007, 0x0},
++ {0x90008, 0x0},
++ {0x90009, 0x0},
++ {0x9000a, 0x0},
++ {0x9000b, 0x0},
++ {0xd00e7, 0x0},
++ {0x90017, 0x0},
++ {0x9001f, 0x0},
++ {0x90026, 0x0},
++ {0x400d0, 0x0},
++ {0x400d1, 0x0},
++ {0x400d2, 0x0},
++ {0x400d3, 0x0},
++ {0x400d4, 0x0},
++ {0x400d5, 0x0},
++ {0x400d6, 0x0},
++ {0x400d7, 0x0},
++ {0x200be, 0x0},
++ {0x2000b, 0x0},
++ {0x2000c, 0x0},
++ {0x2000d, 0x0},
++ {0x2000e, 0x0},
++ {0x12000b, 0x0},
++ {0x12000c, 0x0},
++ {0x12000d, 0x0},
++ {0x12000e, 0x0},
++ {0x22000b, 0x0},
++ {0x22000c, 0x0},
++ {0x22000d, 0x0},
++ {0x22000e, 0x0},
++ {0x9000c, 0x0},
++ {0x9000d, 0x0},
++ {0x9000e, 0x0},
++ {0x9000f, 0x0},
++ {0x90010, 0x0},
++ {0x90011, 0x0},
++ {0x90012, 0x0},
++ {0x90013, 0x0},
++ {0x20010, 0x0},
++ {0x20011, 0x0},
++ {0x120010, 0x0},
++ {0x120011, 0x0},
++ {0x40080, 0x0},
++ {0x40081, 0x0},
++ {0x40082, 0x0},
++ {0x40083, 0x0},
++ {0x40084, 0x0},
++ {0x40085, 0x0},
++ {0x140080, 0x0},
++ {0x140081, 0x0},
++ {0x140082, 0x0},
++ {0x140083, 0x0},
++ {0x140084, 0x0},
++ {0x140085, 0x0},
++ {0x240080, 0x0},
++ {0x240081, 0x0},
++ {0x240082, 0x0},
++ {0x240083, 0x0},
++ {0x240084, 0x0},
++ {0x240085, 0x0},
++ {0x400fd, 0x0},
++ {0x400f1, 0x0},
++ {0x10011, 0x0},
++ {0x10012, 0x0},
++ {0x10013, 0x0},
++ {0x10018, 0x0},
++ {0x10002, 0x0},
++ {0x100b2, 0x0},
++ {0x101b4, 0x0},
++ {0x102b4, 0x0},
++ {0x103b4, 0x0},
++ {0x104b4, 0x0},
++ {0x105b4, 0x0},
++ {0x106b4, 0x0},
++ {0x107b4, 0x0},
++ {0x108b4, 0x0},
++ {0x11011, 0x0},
++ {0x11012, 0x0},
++ {0x11013, 0x0},
++ {0x11018, 0x0},
++ {0x11002, 0x0},
++ {0x110b2, 0x0},
++ {0x111b4, 0x0},
++ {0x112b4, 0x0},
++ {0x113b4, 0x0},
++ {0x114b4, 0x0},
++ {0x115b4, 0x0},
++ {0x116b4, 0x0},
++ {0x117b4, 0x0},
++ {0x118b4, 0x0},
++ {0x20089, 0x0},
++ {0xc0080, 0x0},
++ {0x200cb, 0x0},
++ {0x10068, 0x0},
++ {0x10069, 0x0},
++ {0x10168, 0x0},
++ {0x10169, 0x0},
++ {0x10268, 0x0},
++ {0x10269, 0x0},
++ {0x10368, 0x0},
++ {0x10369, 0x0},
++ {0x10468, 0x0},
++ {0x10469, 0x0},
++ {0x10568, 0x0},
++ {0x10569, 0x0},
++ {0x10668, 0x0},
++ {0x10669, 0x0},
++ {0x10768, 0x0},
++ {0x10769, 0x0},
++ {0x10868, 0x0},
++ {0x10869, 0x0},
++ {0x100aa, 0x0},
++ {0x10062, 0x0},
++ {0x10001, 0x0},
++ {0x100a0, 0x0},
++ {0x100a1, 0x0},
++ {0x100a2, 0x0},
++ {0x100a3, 0x0},
++ {0x100a4, 0x0},
++ {0x100a5, 0x0},
++ {0x100a6, 0x0},
++ {0x100a7, 0x0},
++ {0x11068, 0x0},
++ {0x11069, 0x0},
++ {0x11168, 0x0},
++ {0x11169, 0x0},
++ {0x11268, 0x0},
++ {0x11269, 0x0},
++ {0x11368, 0x0},
++ {0x11369, 0x0},
++ {0x11468, 0x0},
++ {0x11469, 0x0},
++ {0x11568, 0x0},
++ {0x11569, 0x0},
++ {0x11668, 0x0},
++ {0x11669, 0x0},
++ {0x11768, 0x0},
++ {0x11769, 0x0},
++ {0x11868, 0x0},
++ {0x11869, 0x0},
++ {0x110aa, 0x0},
++ {0x11062, 0x0},
++ {0x11001, 0x0},
++ {0x110a0, 0x0},
++ {0x110a1, 0x0},
++ {0x110a2, 0x0},
++ {0x110a3, 0x0},
++ {0x110a4, 0x0},
++ {0x110a5, 0x0},
++ {0x110a6, 0x0},
++ {0x110a7, 0x0},
++ {0x80, 0x0},
++ {0x1080, 0x0},
++ {0x2080, 0x0},
++ {0x10020, 0x0},
++ {0x10080, 0x0},
++ {0x10081, 0x0},
++ {0x100d0, 0x0},
++ {0x100d1, 0x0},
++ {0x1008c, 0x0},
++ {0x1008d, 0x0},
++ {0x10180, 0x0},
++ {0x10181, 0x0},
++ {0x101d0, 0x0},
++ {0x101d1, 0x0},
++ {0x1018c, 0x0},
++ {0x1018d, 0x0},
++ {0x100c0, 0x0},
++ {0x100c1, 0x0},
++ {0x101c0, 0x0},
++ {0x101c1, 0x0},
++ {0x102c0, 0x0},
++ {0x102c1, 0x0},
++ {0x103c0, 0x0},
++ {0x103c1, 0x0},
++ {0x104c0, 0x0},
++ {0x104c1, 0x0},
++ {0x105c0, 0x0},
++ {0x105c1, 0x0},
++ {0x106c0, 0x0},
++ {0x106c1, 0x0},
++ {0x107c0, 0x0},
++ {0x107c1, 0x0},
++ {0x108c0, 0x0},
++ {0x108c1, 0x0},
++ {0x100ae, 0x0},
++ {0x100af, 0x0},
++ {0x11020, 0x0},
++ {0x11080, 0x0},
++ {0x11081, 0x0},
++ {0x110d0, 0x0},
++ {0x110d1, 0x0},
++ {0x1108c, 0x0},
++ {0x1108d, 0x0},
++ {0x11180, 0x0},
++ {0x11181, 0x0},
++ {0x111d0, 0x0},
++ {0x111d1, 0x0},
++ {0x1118c, 0x0},
++ {0x1118d, 0x0},
++ {0x110c0, 0x0},
++ {0x110c1, 0x0},
++ {0x111c0, 0x0},
++ {0x111c1, 0x0},
++ {0x112c0, 0x0},
++ {0x112c1, 0x0},
++ {0x113c0, 0x0},
++ {0x113c1, 0x0},
++ {0x114c0, 0x0},
++ {0x114c1, 0x0},
++ {0x115c0, 0x0},
++ {0x115c1, 0x0},
++ {0x116c0, 0x0},
++ {0x116c1, 0x0},
++ {0x117c0, 0x0},
++ {0x117c1, 0x0},
++ {0x118c0, 0x0},
++ {0x118c1, 0x0},
++ {0x110ae, 0x0},
++ {0x110af, 0x0},
++ {0x90201, 0x0},
++ {0x90202, 0x0},
++ {0x90203, 0x0},
++ {0x90205, 0x0},
++ {0x90206, 0x0},
++ {0x90207, 0x0},
++ {0x90208, 0x0},
++ {0x20020, 0x0},
++ {0x100080, 0x0},
++ {0x101080, 0x0},
++ {0x102080, 0x0},
++ {0x110020, 0x0},
++ {0x110080, 0x0},
++ {0x110081, 0x0},
++ {0x1100d0, 0x0},
++ {0x1100d1, 0x0},
++ {0x11008c, 0x0},
++ {0x11008d, 0x0},
++ {0x110180, 0x0},
++ {0x110181, 0x0},
++ {0x1101d0, 0x0},
++ {0x1101d1, 0x0},
++ {0x11018c, 0x0},
++ {0x11018d, 0x0},
++ {0x1100c0, 0x0},
++ {0x1100c1, 0x0},
++ {0x1101c0, 0x0},
++ {0x1101c1, 0x0},
++ {0x1102c0, 0x0},
++ {0x1102c1, 0x0},
++ {0x1103c0, 0x0},
++ {0x1103c1, 0x0},
++ {0x1104c0, 0x0},
++ {0x1104c1, 0x0},
++ {0x1105c0, 0x0},
++ {0x1105c1, 0x0},
++ {0x1106c0, 0x0},
++ {0x1106c1, 0x0},
++ {0x1107c0, 0x0},
++ {0x1107c1, 0x0},
++ {0x1108c0, 0x0},
++ {0x1108c1, 0x0},
++ {0x1100ae, 0x0},
++ {0x1100af, 0x0},
++ {0x111020, 0x0},
++ {0x111080, 0x0},
++ {0x111081, 0x0},
++ {0x1110d0, 0x0},
++ {0x1110d1, 0x0},
++ {0x11108c, 0x0},
++ {0x11108d, 0x0},
++ {0x111180, 0x0},
++ {0x111181, 0x0},
++ {0x1111d0, 0x0},
++ {0x1111d1, 0x0},
++ {0x11118c, 0x0},
++ {0x11118d, 0x0},
++ {0x1110c0, 0x0},
++ {0x1110c1, 0x0},
++ {0x1111c0, 0x0},
++ {0x1111c1, 0x0},
++ {0x1112c0, 0x0},
++ {0x1112c1, 0x0},
++ {0x1113c0, 0x0},
++ {0x1113c1, 0x0},
++ {0x1114c0, 0x0},
++ {0x1114c1, 0x0},
++ {0x1115c0, 0x0},
++ {0x1115c1, 0x0},
++ {0x1116c0, 0x0},
++ {0x1116c1, 0x0},
++ {0x1117c0, 0x0},
++ {0x1117c1, 0x0},
++ {0x1118c0, 0x0},
++ {0x1118c1, 0x0},
++ {0x1110ae, 0x0},
++ {0x1110af, 0x0},
++ {0x190201, 0x0},
++ {0x190202, 0x0},
++ {0x190203, 0x0},
++ {0x190205, 0x0},
++ {0x190206, 0x0},
++ {0x190207, 0x0},
++ {0x190208, 0x0},
++ {0x120020, 0x0},
++ {0x200080, 0x0},
++ {0x201080, 0x0},
++ {0x202080, 0x0},
++ {0x210020, 0x0},
++ {0x210080, 0x0},
++ {0x210081, 0x0},
++ {0x2100d0, 0x0},
++ {0x2100d1, 0x0},
++ {0x21008c, 0x0},
++ {0x21008d, 0x0},
++ {0x210180, 0x0},
++ {0x210181, 0x0},
++ {0x2101d0, 0x0},
++ {0x2101d1, 0x0},
++ {0x21018c, 0x0},
++ {0x21018d, 0x0},
++ {0x2100c0, 0x0},
++ {0x2100c1, 0x0},
++ {0x2101c0, 0x0},
++ {0x2101c1, 0x0},
++ {0x2102c0, 0x0},
++ {0x2102c1, 0x0},
++ {0x2103c0, 0x0},
++ {0x2103c1, 0x0},
++ {0x2104c0, 0x0},
++ {0x2104c1, 0x0},
++ {0x2105c0, 0x0},
++ {0x2105c1, 0x0},
++ {0x2106c0, 0x0},
++ {0x2106c1, 0x0},
++ {0x2107c0, 0x0},
++ {0x2107c1, 0x0},
++ {0x2108c0, 0x0},
++ {0x2108c1, 0x0},
++ {0x2100ae, 0x0},
++ {0x2100af, 0x0},
++ {0x211020, 0x0},
++ {0x211080, 0x0},
++ {0x211081, 0x0},
++ {0x2110d0, 0x0},
++ {0x2110d1, 0x0},
++ {0x21108c, 0x0},
++ {0x21108d, 0x0},
++ {0x211180, 0x0},
++ {0x211181, 0x0},
++ {0x2111d0, 0x0},
++ {0x2111d1, 0x0},
++ {0x21118c, 0x0},
++ {0x21118d, 0x0},
++ {0x2110c0, 0x0},
++ {0x2110c1, 0x0},
++ {0x2111c0, 0x0},
++ {0x2111c1, 0x0},
++ {0x2112c0, 0x0},
++ {0x2112c1, 0x0},
++ {0x2113c0, 0x0},
++ {0x2113c1, 0x0},
++ {0x2114c0, 0x0},
++ {0x2114c1, 0x0},
++ {0x2115c0, 0x0},
++ {0x2115c1, 0x0},
++ {0x2116c0, 0x0},
++ {0x2116c1, 0x0},
++ {0x2117c0, 0x0},
++ {0x2117c1, 0x0},
++ {0x2118c0, 0x0},
++ {0x2118c1, 0x0},
++ {0x2110ae, 0x0},
++ {0x2110af, 0x0},
++ {0x290201, 0x0},
++ {0x290202, 0x0},
++ {0x290203, 0x0},
++ {0x290205, 0x0},
++ {0x290206, 0x0},
++ {0x290207, 0x0},
++ {0x290208, 0x0},
++ {0x220020, 0x0},
++ {0x20077, 0x0},
++ {0x20072, 0x0},
++ {0x20073, 0x0},
++ {0x400c0, 0x0},
++ {0x10040, 0x0},
++ {0x10140, 0x0},
++ {0x10240, 0x0},
++ {0x10340, 0x0},
++ {0x10440, 0x0},
++ {0x10540, 0x0},
++ {0x10640, 0x0},
++ {0x10740, 0x0},
++ {0x10840, 0x0},
++ {0x11040, 0x0},
++ {0x11140, 0x0},
++ {0x11240, 0x0},
++ {0x11340, 0x0},
++ {0x11440, 0x0},
++ {0x11540, 0x0},
++ {0x11640, 0x0},
++ {0x11740, 0x0},
++ {0x11840, 0x0},
++};
++
++/* P0 message block parameter for training firmware */
++static struct dram_cfg_param ddr_fsp0_cfg[] = {
++ {0xd0000, 0x0},
++ {0x54003, 0xe94},
++ {0x54004, 0x4},
++ {0x54006, 0x15},
++ {0x54008, 0x131f},
++ {0x54009, 0xc8},
++ {0x5400b, 0x4},
++ {0x5400d, 0x100},
++ {0x5400f, 0x100},
++ {0x54012, 0x110},
++ {0x54019, 0x36e4},
++ {0x5401a, 0x32},
++ {0x5401b, 0x1146},
++ {0x5401c, 0x1108},
++ {0x5401e, 0x4},
++ {0x5401f, 0x36e4},
++ {0x54020, 0x32},
++ {0x54021, 0x1146},
++ {0x54022, 0x1108},
++ {0x54024, 0x4},
++ {0x54032, 0xe400},
++ {0x54033, 0x3236},
++ {0x54034, 0x4600},
++ {0x54035, 0x811},
++ {0x54036, 0x11},
++ {0x54037, 0x400},
++ {0x54038, 0xe400},
++ {0x54039, 0x3236},
++ {0x5403a, 0x4600},
++ {0x5403b, 0x811},
++ {0x5403c, 0x11},
++ {0x5403d, 0x400},
++ {0xd0000, 0x1}
++};
++
++/* P1 message block parameter for training firmware */
++static struct dram_cfg_param ddr_fsp1_cfg[] = {
++ {0xd0000, 0x0},
++ {0x54002, 0x1},
++ {0x54003, 0x74a},
++ {0x54004, 0x4},
++ {0x54006, 0x15},
++ {0x54008, 0x121f},
++ {0x54009, 0xc8},
++ {0x5400b, 0x4},
++ {0x5400d, 0x100},
++ {0x5400f, 0x100},
++ {0x54012, 0x110},
++ {0x54019, 0x1bb4},
++ {0x5401a, 0x32},
++ {0x5401b, 0x1146},
++ {0x5401c, 0x1108},
++ {0x5401e, 0x4},
++ {0x5401f, 0x1bb4},
++ {0x54020, 0x32},
++ {0x54021, 0x1146},
++ {0x54022, 0x1108},
++ {0x54024, 0x4},
++ {0x54032, 0xb400},
++ {0x54033, 0x321b},
++ {0x54034, 0x4600},
++ {0x54035, 0x811},
++ {0x54036, 0x11},
++ {0x54037, 0x400},
++ {0x54038, 0xb400},
++ {0x54039, 0x321b},
++ {0x5403a, 0x4600},
++ {0x5403b, 0x811},
++ {0x5403c, 0x11},
++ {0x5403d, 0x400},
++ {0xd0000, 0x1}
++};
++
++/* P2 message block parameter for training firmware */
++static struct dram_cfg_param ddr_fsp2_cfg[] = {
++ {0xd0000, 0x0},
++ {0x54002, 0x102},
++ {0x54003, 0x270},
++ {0x54004, 0x4},
++ {0x54006, 0x15},
++ {0x54008, 0x121f},
++ {0x54009, 0xc8},
++ {0x5400b, 0x4},
++ {0x5400d, 0x100},
++ {0x5400f, 0x100},
++ {0x54012, 0x110},
++ {0x54019, 0x994},
++ {0x5401a, 0x32},
++ {0x5401b, 0x1146},
++ {0x5401c, 0x1100},
++ {0x5401e, 0x4},
++ {0x5401f, 0x994},
++ {0x54020, 0x32},
++ {0x54021, 0x1146},
++ {0x54022, 0x1100},
++ {0x54024, 0x4},
++ {0x54032, 0x9400},
++ {0x54033, 0x3209},
++ {0x54034, 0x4600},
++ {0x54035, 0x11},
++ {0x54036, 0x11},
++ {0x54037, 0x400},
++ {0x54038, 0x9400},
++ {0x54039, 0x3209},
++ {0x5403a, 0x4600},
++ {0x5403b, 0x11},
++ {0x5403c, 0x11},
++ {0x5403d, 0x400},
++ {0xd0000, 0x1}
++};
++
++/* P0 2D message block parameter for training firmware */
++static struct dram_cfg_param ddr_fsp0_2d_cfg[] = {
++ {0xd0000, 0x0},
++ {0x54003, 0xe94},
++ {0x54004, 0x4},
++ {0x54006, 0x15},
++ {0x54008, 0x61},
++ {0x54009, 0xc8},
++ {0x5400b, 0x4},
++ {0x5400d, 0x100},
++ {0x5400f, 0x100},
++ {0x54010, 0x2080},
++ {0x54012, 0x110},
++ {0x54019, 0x36e4},
++ {0x5401a, 0x32},
++ {0x5401b, 0x1146},
++ {0x5401c, 0x1108},
++ {0x5401e, 0x4},
++ {0x5401f, 0x36e4},
++ {0x54020, 0x32},
++ {0x54021, 0x1146},
++ {0x54022, 0x1108},
++ {0x54024, 0x4},
++ {0x54032, 0xe400},
++ {0x54033, 0x3236},
++ {0x54034, 0x4600},
++ {0x54035, 0x811},
++ {0x54036, 0x11},
++ {0x54037, 0x400},
++ {0x54038, 0xe400},
++ {0x54039, 0x3236},
++ {0x5403a, 0x4600},
++ {0x5403b, 0x811},
++ {0x5403c, 0x11},
++ {0x5403d, 0x400},
++ {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, 0xb},
++ {0x90039, 0x7c0},
++ {0x9003a, 0x139},
++ {0x9003b, 0x44},
++ {0x9003c, 0x633},
++ {0x9003d, 0x159},
++ {0x9003e, 0x14f},
++ {0x9003f, 0x630},
++ {0x90040, 0x159},
++ {0x90041, 0x47},
++ {0x90042, 0x633},
++ {0x90043, 0x149},
++ {0x90044, 0x4f},
++ {0x90045, 0x633},
++ {0x90046, 0x179},
++ {0x90047, 0x8},
++ {0x90048, 0xe0},
++ {0x90049, 0x109},
++ {0x9004a, 0x0},
++ {0x9004b, 0x7c8},
++ {0x9004c, 0x109},
++ {0x9004d, 0x0},
++ {0x9004e, 0x1},
++ {0x9004f, 0x8},
++ {0x90050, 0x30},
++ {0x90051, 0x65a},
++ {0x90052, 0x9},
++ {0x90053, 0x0},
++ {0x90054, 0x45a},
++ {0x90055, 0x9},
++ {0x90056, 0x0},
++ {0x90057, 0x448},
++ {0x90058, 0x109},
++ {0x90059, 0x40},
++ {0x9005a, 0x633},
++ {0x9005b, 0x179},
++ {0x9005c, 0x1},
++ {0x9005d, 0x618},
++ {0x9005e, 0x109},
++ {0x9005f, 0x40c0},
++ {0x90060, 0x633},
++ {0x90061, 0x149},
++ {0x90062, 0x8},
++ {0x90063, 0x4},
++ {0x90064, 0x48},
++ {0x90065, 0x4040},
++ {0x90066, 0x633},
++ {0x90067, 0x149},
++ {0x90068, 0x0},
++ {0x90069, 0x4},
++ {0x9006a, 0x48},
++ {0x9006b, 0x40},
++ {0x9006c, 0x633},
++ {0x9006d, 0x149},
++ {0x9006e, 0x0},
++ {0x9006f, 0x658},
++ {0x90070, 0x109},
++ {0x90071, 0x10},
++ {0x90072, 0x4},
++ {0x90073, 0x18},
++ {0x90074, 0x0},
++ {0x90075, 0x4},
++ {0x90076, 0x78},
++ {0x90077, 0x549},
++ {0x90078, 0x633},
++ {0x90079, 0x159},
++ {0x9007a, 0xd49},
++ {0x9007b, 0x633},
++ {0x9007c, 0x159},
++ {0x9007d, 0x94a},
++ {0x9007e, 0x633},
++ {0x9007f, 0x159},
++ {0x90080, 0x441},
++ {0x90081, 0x633},
++ {0x90082, 0x149},
++ {0x90083, 0x42},
++ {0x90084, 0x633},
++ {0x90085, 0x149},
++ {0x90086, 0x1},
++ {0x90087, 0x633},
++ {0x90088, 0x149},
++ {0x90089, 0x0},
++ {0x9008a, 0xe0},
++ {0x9008b, 0x109},
++ {0x9008c, 0xa},
++ {0x9008d, 0x10},
++ {0x9008e, 0x109},
++ {0x9008f, 0x9},
++ {0x90090, 0x3c0},
++ {0x90091, 0x149},
++ {0x90092, 0x9},
++ {0x90093, 0x3c0},
++ {0x90094, 0x159},
++ {0x90095, 0x18},
++ {0x90096, 0x10},
++ {0x90097, 0x109},
++ {0x90098, 0x0},
++ {0x90099, 0x3c0},
++ {0x9009a, 0x109},
++ {0x9009b, 0x18},
++ {0x9009c, 0x4},
++ {0x9009d, 0x48},
++ {0x9009e, 0x18},
++ {0x9009f, 0x4},
++ {0x900a0, 0x58},
++ {0x900a1, 0xb},
++ {0x900a2, 0x10},
++ {0x900a3, 0x109},
++ {0x900a4, 0x1},
++ {0x900a5, 0x10},
++ {0x900a6, 0x109},
++ {0x900a7, 0x5},
++ {0x900a8, 0x7c0},
++ {0x900a9, 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, 0x625},
++ {0x4002b, 0x15},
++ {0x4004b, 0x0},
++ {0x4006b, 0x0},
++ {0x4000c, 0x4028},
++ {0x4002c, 0x80},
++ {0x4004c, 0x0},
++ {0x4006c, 0x0},
++ {0x4000d, 0xe08},
++ {0x4002d, 0xc1a},
++ {0x4004d, 0x0},
++ {0x4006d, 0x0},
++ {0x4000e, 0x625},
++ {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},
++ {0x900aa, 0x0},
++ {0x900ab, 0x790},
++ {0x900ac, 0x11a},
++ {0x900ad, 0x8},
++ {0x900ae, 0x7aa},
++ {0x900af, 0x2a},
++ {0x900b0, 0x10},
++ {0x900b1, 0x7b2},
++ {0x900b2, 0x2a},
++ {0x900b3, 0x0},
++ {0x900b4, 0x7c8},
++ {0x900b5, 0x109},
++ {0x900b6, 0x10},
++ {0x900b7, 0x10},
++ {0x900b8, 0x109},
++ {0x900b9, 0x10},
++ {0x900ba, 0x2a8},
++ {0x900bb, 0x129},
++ {0x900bc, 0x8},
++ {0x900bd, 0x370},
++ {0x900be, 0x129},
++ {0x900bf, 0xa},
++ {0x900c0, 0x3c8},
++ {0x900c1, 0x1a9},
++ {0x900c2, 0xc},
++ {0x900c3, 0x408},
++ {0x900c4, 0x199},
++ {0x900c5, 0x14},
++ {0x900c6, 0x790},
++ {0x900c7, 0x11a},
++ {0x900c8, 0x8},
++ {0x900c9, 0x4},
++ {0x900ca, 0x18},
++ {0x900cb, 0xe},
++ {0x900cc, 0x408},
++ {0x900cd, 0x199},
++ {0x900ce, 0x8},
++ {0x900cf, 0x8568},
++ {0x900d0, 0x108},
++ {0x900d1, 0x18},
++ {0x900d2, 0x790},
++ {0x900d3, 0x16a},
++ {0x900d4, 0x8},
++ {0x900d5, 0x1d8},
++ {0x900d6, 0x169},
++ {0x900d7, 0x10},
++ {0x900d8, 0x8558},
++ {0x900d9, 0x168},
++ {0x900da, 0x1ff8},
++ {0x900db, 0x85a8},
++ {0x900dc, 0x1e8},
++ {0x900dd, 0x50},
++ {0x900de, 0x798},
++ {0x900df, 0x16a},
++ {0x900e0, 0x60},
++ {0x900e1, 0x7a0},
++ {0x900e2, 0x16a},
++ {0x900e3, 0x8},
++ {0x900e4, 0x8310},
++ {0x900e5, 0x168},
++ {0x900e6, 0x8},
++ {0x900e7, 0xa310},
++ {0x900e8, 0x168},
++ {0x900e9, 0xa},
++ {0x900ea, 0x408},
++ {0x900eb, 0x169},
++ {0x900ec, 0x6e},
++ {0x900ed, 0x0},
++ {0x900ee, 0x68},
++ {0x900ef, 0x0},
++ {0x900f0, 0x408},
++ {0x900f1, 0x169},
++ {0x900f2, 0x0},
++ {0x900f3, 0x8310},
++ {0x900f4, 0x168},
++ {0x900f5, 0x0},
++ {0x900f6, 0xa310},
++ {0x900f7, 0x168},
++ {0x900f8, 0x1ff8},
++ {0x900f9, 0x85a8},
++ {0x900fa, 0x1e8},
++ {0x900fb, 0x68},
++ {0x900fc, 0x798},
++ {0x900fd, 0x16a},
++ {0x900fe, 0x78},
++ {0x900ff, 0x7a0},
++ {0x90100, 0x16a},
++ {0x90101, 0x68},
++ {0x90102, 0x790},
++ {0x90103, 0x16a},
++ {0x90104, 0x8},
++ {0x90105, 0x8b10},
++ {0x90106, 0x168},
++ {0x90107, 0x8},
++ {0x90108, 0xab10},
++ {0x90109, 0x168},
++ {0x9010a, 0xa},
++ {0x9010b, 0x408},
++ {0x9010c, 0x169},
++ {0x9010d, 0x58},
++ {0x9010e, 0x0},
++ {0x9010f, 0x68},
++ {0x90110, 0x0},
++ {0x90111, 0x408},
++ {0x90112, 0x169},
++ {0x90113, 0x0},
++ {0x90114, 0x8b10},
++ {0x90115, 0x168},
++ {0x90116, 0x1},
++ {0x90117, 0xab10},
++ {0x90118, 0x168},
++ {0x90119, 0x0},
++ {0x9011a, 0x1d8},
++ {0x9011b, 0x169},
++ {0x9011c, 0x80},
++ {0x9011d, 0x790},
++ {0x9011e, 0x16a},
++ {0x9011f, 0x18},
++ {0x90120, 0x7aa},
++ {0x90121, 0x6a},
++ {0x90122, 0xa},
++ {0x90123, 0x0},
++ {0x90124, 0x1e9},
++ {0x90125, 0x8},
++ {0x90126, 0x8080},
++ {0x90127, 0x108},
++ {0x90128, 0xf},
++ {0x90129, 0x408},
++ {0x9012a, 0x169},
++ {0x9012b, 0xc},
++ {0x9012c, 0x0},
++ {0x9012d, 0x68},
++ {0x9012e, 0x9},
++ {0x9012f, 0x0},
++ {0x90130, 0x1a9},
++ {0x90131, 0x0},
++ {0x90132, 0x408},
++ {0x90133, 0x169},
++ {0x90134, 0x0},
++ {0x90135, 0x8080},
++ {0x90136, 0x108},
++ {0x90137, 0x8},
++ {0x90138, 0x7aa},
++ {0x90139, 0x6a},
++ {0x9013a, 0x0},
++ {0x9013b, 0x8568},
++ {0x9013c, 0x108},
++ {0x9013d, 0xb7},
++ {0x9013e, 0x790},
++ {0x9013f, 0x16a},
++ {0x90140, 0x1f},
++ {0x90141, 0x0},
++ {0x90142, 0x68},
++ {0x90143, 0x8},
++ {0x90144, 0x8558},
++ {0x90145, 0x168},
++ {0x90146, 0xf},
++ {0x90147, 0x408},
++ {0x90148, 0x169},
++ {0x90149, 0xd},
++ {0x9014a, 0x0},
++ {0x9014b, 0x68},
++ {0x9014c, 0x0},
++ {0x9014d, 0x408},
++ {0x9014e, 0x169},
++ {0x9014f, 0x0},
++ {0x90150, 0x8558},
++ {0x90151, 0x168},
++ {0x90152, 0x8},
++ {0x90153, 0x3c8},
++ {0x90154, 0x1a9},
++ {0x90155, 0x3},
++ {0x90156, 0x370},
++ {0x90157, 0x129},
++ {0x90158, 0x20},
++ {0x90159, 0x2aa},
++ {0x9015a, 0x9},
++ {0x9015b, 0x8},
++ {0x9015c, 0xe8},
++ {0x9015d, 0x109},
++ {0x9015e, 0x0},
++ {0x9015f, 0x8140},
++ {0x90160, 0x10c},
++ {0x90161, 0x10},
++ {0x90162, 0x8138},
++ {0x90163, 0x104},
++ {0x90164, 0x8},
++ {0x90165, 0x448},
++ {0x90166, 0x109},
++ {0x90167, 0xf},
++ {0x90168, 0x7c0},
++ {0x90169, 0x109},
++ {0x9016a, 0x0},
++ {0x9016b, 0xe8},
++ {0x9016c, 0x109},
++ {0x9016d, 0x47},
++ {0x9016e, 0x630},
++ {0x9016f, 0x109},
++ {0x90170, 0x8},
++ {0x90171, 0x618},
++ {0x90172, 0x109},
++ {0x90173, 0x8},
++ {0x90174, 0xe0},
++ {0x90175, 0x109},
++ {0x90176, 0x0},
++ {0x90177, 0x7c8},
++ {0x90178, 0x109},
++ {0x90179, 0x8},
++ {0x9017a, 0x8140},
++ {0x9017b, 0x10c},
++ {0x9017c, 0x0},
++ {0x9017d, 0x478},
++ {0x9017e, 0x109},
++ {0x9017f, 0x0},
++ {0x90180, 0x1},
++ {0x90181, 0x8},
++ {0x90182, 0x8},
++ {0x90183, 0x4},
++ {0x90184, 0x0},
++ {0x90006, 0x8},
++ {0x90007, 0x7c8},
++ {0x90008, 0x109},
++ {0x90009, 0x0},
++ {0x9000a, 0x400},
++ {0x9000b, 0x106},
++ {0xd00e7, 0x400},
++ {0x90017, 0x0},
++ {0x9001f, 0x2b},
++ {0x90026, 0x69},
++ {0x400d0, 0x0},
++ {0x400d1, 0x101},
++ {0x400d2, 0x105},
++ {0x400d3, 0x107},
++ {0x400d4, 0x10f},
++ {0x400d5, 0x202},
++ {0x400d6, 0x20a},
++ {0x400d7, 0x20b},
++ {0x2003a, 0x2},
++ {0x200be, 0x3},
++ {0x2000b, 0x41a},
++ {0x2000c, 0xe9},
++ {0x2000d, 0x91c},
++ {0x2000e, 0x2c},
++ {0x12000b, 0x20d},
++ {0x12000c, 0x74},
++ {0x12000d, 0x48e},
++ {0x12000e, 0x2c},
++ {0x22000b, 0xb0},
++ {0x22000c, 0x27},
++ {0x22000d, 0x186},
++ {0x22000e, 0x10},
++ {0x9000c, 0x0},
++ {0x9000d, 0x173},
++ {0x9000e, 0x60},
++ {0x9000f, 0x6110},
++ {0x90010, 0x2152},
++ {0x90011, 0xdfbd},
++ {0x90012, 0x2060},
++ {0x90013, 0x6152},
++ {0x20010, 0x5a},
++ {0x20011, 0x3},
++ {0x120010, 0x5a},
++ {0x120011, 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},
++ {0x400f1, 0xe},
++ {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},
++ {0x20089, 0x1},
++ {0x20088, 0x19},
++ {0xc0080, 0x0},
++ {0xd0000, 0x1},
++};
++
++static struct dram_fsp_msg ddr_dram_fsp_msg[] = {
++ {
++ /* P0 3733mts 1D */
++ .drate = 3733,
++ .fw_type = FW_1D_IMAGE,
++ .fsp_cfg = ddr_fsp0_cfg,
++ .fsp_cfg_num = ARRAY_SIZE(ddr_fsp0_cfg),
++ },
++ {
++ /* P1 1866mts 1D */
++ .drate = 1866,
++ .fw_type = FW_1D_IMAGE,
++ .fsp_cfg = ddr_fsp1_cfg,
++ .fsp_cfg_num = ARRAY_SIZE(ddr_fsp1_cfg),
++ },
++ {
++ /* P2 625mts 1D */
++ .drate = 625,
++ .fw_type = FW_1D_IMAGE,
++ .fsp_cfg = ddr_fsp2_cfg,
++ .fsp_cfg_num = ARRAY_SIZE(ddr_fsp2_cfg),
++ },
++ {
++ /* P0 3733mts 2D */
++ .drate = 3733,
++ .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 dram_timing_2GB = {
++ .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_trained_csr = ddr_ddrphy_trained_csr,
++ .ddrphy_trained_csr_num = ARRAY_SIZE(ddr_ddrphy_trained_csr),
++ .ddrphy_pie = ddr_phy_pie,
++ .ddrphy_pie_num = ARRAY_SIZE(ddr_phy_pie),
++ .fsp_table = { 3733, 1866, 625, },
++ .fsp_cfg = ddr_dram_fsp_cfg,
++ .fsp_cfg_num = ARRAY_SIZE(ddr_dram_fsp_cfg),
++};
+diff --git a/board/freescale/imx93_frdm/lpddr4x_ecc_2gb_timing.c b/board/freescale/imx93_frdm/lpddr4x_ecc_2gb_timing.c
+new file mode 100644
+index 00000000000..c04e34449d8
+--- /dev/null
++++ b/board/freescale/imx93_frdm/lpddr4x_ecc_2gb_timing.c
+@@ -0,0 +1,1997 @@
++/*
++ * Copyright 2024 NXP
++ *
++ * SPDX-License-Identifier: BSD-3-Clause
++ *
++ * Code generated with DDR Tool v3.4.0_8.3-4e2b550a.
++ * DDR PHY FW2022.01
++ */
++
++#include
++#include
++
++/* Initialize DDRC registers */
++static struct dram_cfg_param ddr_ddrc_cfg[] = {
++ {0x4e300110, 0x44100001},
++ {0x4e300000, 0x8000ef},
++ {0x4e300008, 0x0},
++ {0x4e300080, 0x80000512},
++ {0x4e300084, 0x0},
++ {0x4e300114, 0x1012},
++ {0x4e300260, 0x80},
++ {0x4e300f04, 0x80},
++ {0x4e300800, 0x43b30d00},
++ {0x4e300804, 0x1f1f1f1f},
++ {0x4e301000, 0xc0000000},
++ {0x4e301240, 0x0},
++ {0x4e301244, 0x0},
++ {0x4e301248, 0x0},
++ {0x4e30124c, 0x0},
++ {0x4e301250, 0x0},
++ {0x4e301254, 0x0},
++ {0x4e301258, 0x0},
++ {0x4e30125c, 0x0},
++};
++
++/* dram fsp cfg */
++static struct dram_fsp_cfg ddr_dram_fsp_cfg[] = {
++ {
++ {
++ {0x4e300100, 0x24AB321B},
++ {0x4e300104, 0xF8EE001B},
++ {0x4e300108, 0x2F2EE233},
++ {0x4e30010C, 0x0005E18B},
++ {0x4e300124, 0x1C760000},
++ {0x4e300160, 0x00009102},
++ {0x4e30016C, 0x35F00000},
++ {0x4e300170, 0x8B0B0608},
++ {0x4e300250, 0x00000028},
++ {0x4e300254, 0x015B015B},
++ {0x4e300258, 0x00000008},
++ {0x4e30025C, 0x00000400},
++ {0x4e300300, 0x224F2213},
++ {0x4e300304, 0x015B2213},
++ {0x4e300308, 0x0A3C0E3D},
++ },
++ {
++ {0x01, 0xE4},
++ {0x02, 0x36},
++ {0x03, 0x32},
++ {0x0b, 0x46},
++ {0x0c, 0x11},
++ {0x0e, 0x11},
++ {0x16, 0x04},
++ },
++ 0,
++ },
++ {
++ {
++ {0x4e300100, 0x12552100},
++ {0x4e300104, 0xF877000E},
++ {0x4e300108, 0x1816B4AA},
++ {0x4e30010C, 0x005101E6},
++ {0x4e300124, 0x0E3C0000},
++ {0x4e300160, 0x00009101},
++ {0x4e30016C, 0x30900000},
++ {0x4e300170, 0x8A0A0508},
++ {0x4e300250, 0x00000014},
++ {0x4e300254, 0x00AA00AA},
++ {0x4e300258, 0x00000008},
++ {0x4e30025C, 0x00000400},
++ },
++ {
++ {0x01, 0xB4},
++ {0x02, 0x1B},
++ {0x03, 0x32},
++ {0x0b, 0x46},
++ {0x0c, 0x11},
++ {0x0e, 0x11},
++ {0x16, 0x04},
++ },
++ 0,
++ },
++ {
++ {
++ {0x4e300100, 0x00061000},
++ {0x4e300104, 0xF855000A},
++ {0x4e300108, 0x6E62FA48},
++ {0x4e30010C, 0x0031010D},
++ {0x4e300124, 0x04C50000},
++ {0x4e300160, 0x00009100},
++ {0x4e30016C, 0x30000000},
++ {0x4e300170, 0x89090408},
++ {0x4e300250, 0x00000007},
++ {0x4e300254, 0x00340034},
++ {0x4e300258, 0x00000008},
++ {0x4e30025C, 0x00000400},
++ },
++ {
++ {0x01, 0x94},
++ {0x02, 0x9},
++ {0x03, 0x32},
++ {0x0b, 0x46},
++ {0x0c, 0x11},
++ {0x0e, 0x11},
++ {0x16, 0x04},
++ },
++ 1,
++ },
++
++};
++
++/* PHY Initialize Configuration */
++static struct dram_cfg_param ddr_ddrphy_cfg[] = {
++ {0x100a0, 0x4},
++ {0x100a1, 0x5},
++ {0x100a2, 0x6},
++ {0x100a3, 0x7},
++ {0x100a4, 0x0},
++ {0x100a5, 0x1},
++ {0x100a6, 0x2},
++ {0x100a7, 0x3},
++ {0x110a0, 0x3},
++ {0x110a1, 0x2},
++ {0x110a2, 0x0},
++ {0x110a3, 0x1},
++ {0x110a4, 0x7},
++ {0x110a5, 0x6},
++ {0x110a6, 0x4},
++ {0x110a7, 0x5},
++ {0x1005f, 0x5ff},
++ {0x1015f, 0x5ff},
++ {0x1105f, 0x5ff},
++ {0x1115f, 0x5ff},
++ {0x11005f, 0x5ff},
++ {0x11015f, 0x5ff},
++ {0x11105f, 0x5ff},
++ {0x11115f, 0x5ff},
++ {0x21005f, 0x5ff},
++ {0x21015f, 0x5ff},
++ {0x21105f, 0x5ff},
++ {0x21115f, 0x5ff},
++ {0x55, 0x1ff},
++ {0x1055, 0x1ff},
++ {0x2055, 0x1ff},
++ {0x200c5, 0x19},
++ {0x1200c5, 0xb},
++ {0x2200c5, 0x7},
++ {0x2002e, 0x2},
++ {0x12002e, 0x2},
++ {0x22002e, 0x2},
++ {0x90204, 0x0},
++ {0x190204, 0x0},
++ {0x290204, 0x0},
++ {0x20024, 0x1e3},
++ {0x2003a, 0x2},
++ {0x2007d, 0x212},
++ {0x2007c, 0x61},
++ {0x120024, 0x1e3},
++ {0x2003a, 0x2},
++ {0x12007d, 0x212},
++ {0x12007c, 0x61},
++ {0x220024, 0x1e3},
++ {0x2003a, 0x2},
++ {0x22007d, 0x212},
++ {0x22007c, 0x61},
++ {0x20056, 0x3},
++ {0x120056, 0x3},
++ {0x220056, 0x3},
++ {0x1004d, 0x600},
++ {0x1014d, 0x600},
++ {0x1104d, 0x600},
++ {0x1114d, 0x600},
++ {0x11004d, 0x600},
++ {0x11014d, 0x600},
++ {0x11104d, 0x600},
++ {0x11114d, 0x600},
++ {0x21004d, 0x600},
++ {0x21014d, 0x600},
++ {0x21104d, 0x600},
++ {0x21114d, 0x600},
++ {0x10049, 0xe00},
++ {0x10149, 0xe00},
++ {0x11049, 0xe00},
++ {0x11149, 0xe00},
++ {0x110049, 0xe00},
++ {0x110149, 0xe00},
++ {0x111049, 0xe00},
++ {0x111149, 0xe00},
++ {0x210049, 0xe00},
++ {0x210149, 0xe00},
++ {0x211049, 0xe00},
++ {0x211149, 0xe00},
++ {0x43, 0x60},
++ {0x1043, 0x60},
++ {0x2043, 0x60},
++ {0x20018, 0x1},
++ {0x20075, 0x4},
++ {0x20050, 0x0},
++ {0x2009b, 0x2},
++ {0x20008, 0x3a5},
++ {0x120008, 0x1d3},
++ {0x220008, 0x9c},
++ {0x20088, 0x9},
++ {0x200b2, 0x10c},
++ {0x10043, 0x5a1},
++ {0x10143, 0x5a1},
++ {0x11043, 0x5a1},
++ {0x11143, 0x5a1},
++ {0x1200b2, 0x10c},
++ {0x110043, 0x5a1},
++ {0x110143, 0x5a1},
++ {0x111043, 0x5a1},
++ {0x111143, 0x5a1},
++ {0x2200b2, 0x10c},
++ {0x210043, 0x5a1},
++ {0x210143, 0x5a1},
++ {0x211043, 0x5a1},
++ {0x211143, 0x5a1},
++ {0x200fa, 0x2},
++ {0x1200fa, 0x2},
++ {0x2200fa, 0x2},
++ {0x20019, 0x1},
++ {0x120019, 0x1},
++ {0x220019, 0x1},
++ {0x200f0, 0x600},
++ {0x200f1, 0x0},
++ {0x200f2, 0x4444},
++ {0x200f3, 0x8888},
++ {0x200f4, 0x5655},
++ {0x200f5, 0x0},
++ {0x200f6, 0x0},
++ {0x200f7, 0xf000},
++ {0x1004a, 0x500},
++ {0x1104a, 0x500},
++ {0x20025, 0x0},
++ {0x2002d, 0x0},
++ {0x12002d, 0x0},
++ {0x22002d, 0x0},
++ {0x2002c, 0x0},
++ {0x20021, 0x0},
++ {0x200c7, 0x21},
++ {0x1200c7, 0x21},
++ {0x200ca, 0x24},
++ {0x1200ca, 0x24},
++};
++
++/* PHY trained csr */
++static struct dram_cfg_param ddr_ddrphy_trained_csr[] = {
++ {0x1005f, 0x0},
++ {0x1015f, 0x0},
++ {0x1105f, 0x0},
++ {0x1115f, 0x0},
++ {0x11005f, 0x0},
++ {0x11015f, 0x0},
++ {0x11105f, 0x0},
++ {0x11115f, 0x0},
++ {0x21005f, 0x0},
++ {0x21015f, 0x0},
++ {0x21105f, 0x0},
++ {0x21115f, 0x0},
++ {0x55, 0x0},
++ {0x1055, 0x0},
++ {0x2055, 0x0},
++ {0x200c5, 0x0},
++ {0x1200c5, 0x0},
++ {0x2200c5, 0x0},
++ {0x2002e, 0x0},
++ {0x12002e, 0x0},
++ {0x22002e, 0x0},
++ {0x90204, 0x0},
++ {0x190204, 0x0},
++ {0x290204, 0x0},
++ {0x20024, 0x0},
++ {0x2003a, 0x0},
++ {0x2007d, 0x0},
++ {0x2007c, 0x0},
++ {0x120024, 0x0},
++ {0x12007d, 0x0},
++ {0x12007c, 0x0},
++ {0x220024, 0x0},
++ {0x22007d, 0x0},
++ {0x22007c, 0x0},
++ {0x20056, 0x0},
++ {0x120056, 0x0},
++ {0x220056, 0x0},
++ {0x1004d, 0x0},
++ {0x1014d, 0x0},
++ {0x1104d, 0x0},
++ {0x1114d, 0x0},
++ {0x11004d, 0x0},
++ {0x11014d, 0x0},
++ {0x11104d, 0x0},
++ {0x11114d, 0x0},
++ {0x21004d, 0x0},
++ {0x21014d, 0x0},
++ {0x21104d, 0x0},
++ {0x21114d, 0x0},
++ {0x10049, 0x0},
++ {0x10149, 0x0},
++ {0x11049, 0x0},
++ {0x11149, 0x0},
++ {0x110049, 0x0},
++ {0x110149, 0x0},
++ {0x111049, 0x0},
++ {0x111149, 0x0},
++ {0x210049, 0x0},
++ {0x210149, 0x0},
++ {0x211049, 0x0},
++ {0x211149, 0x0},
++ {0x43, 0x0},
++ {0x1043, 0x0},
++ {0x2043, 0x0},
++ {0x20018, 0x0},
++ {0x20075, 0x0},
++ {0x20050, 0x0},
++ {0x2009b, 0x0},
++ {0x20008, 0x0},
++ {0x120008, 0x0},
++ {0x220008, 0x0},
++ {0x20088, 0x0},
++ {0x200b2, 0x0},
++ {0x10043, 0x0},
++ {0x10143, 0x0},
++ {0x11043, 0x0},
++ {0x11143, 0x0},
++ {0x1200b2, 0x0},
++ {0x110043, 0x0},
++ {0x110143, 0x0},
++ {0x111043, 0x0},
++ {0x111143, 0x0},
++ {0x2200b2, 0x0},
++ {0x210043, 0x0},
++ {0x210143, 0x0},
++ {0x211043, 0x0},
++ {0x211143, 0x0},
++ {0x200fa, 0x0},
++ {0x1200fa, 0x0},
++ {0x2200fa, 0x0},
++ {0x20019, 0x0},
++ {0x120019, 0x0},
++ {0x220019, 0x0},
++ {0x200f0, 0x0},
++ {0x200f1, 0x0},
++ {0x200f2, 0x0},
++ {0x200f3, 0x0},
++ {0x200f4, 0x0},
++ {0x200f5, 0x0},
++ {0x200f6, 0x0},
++ {0x200f7, 0x0},
++ {0x1004a, 0x0},
++ {0x1104a, 0x0},
++ {0x20025, 0x0},
++ {0x2002d, 0x0},
++ {0x12002d, 0x0},
++ {0x22002d, 0x0},
++ {0x2002c, 0x0},
++ {0xd0000, 0x0},
++ {0x90000, 0x0},
++ {0x90001, 0x0},
++ {0x90002, 0x0},
++ {0x90003, 0x0},
++ {0x90004, 0x0},
++ {0x90005, 0x0},
++ {0x90029, 0x0},
++ {0x9002a, 0x0},
++ {0x9002b, 0x0},
++ {0x9002c, 0x0},
++ {0x9002d, 0x0},
++ {0x9002e, 0x0},
++ {0x9002f, 0x0},
++ {0x90030, 0x0},
++ {0x90031, 0x0},
++ {0x90032, 0x0},
++ {0x90033, 0x0},
++ {0x90034, 0x0},
++ {0x90035, 0x0},
++ {0x90036, 0x0},
++ {0x90037, 0x0},
++ {0x90038, 0x0},
++ {0x90039, 0x0},
++ {0x9003a, 0x0},
++ {0x9003b, 0x0},
++ {0x9003c, 0x0},
++ {0x9003d, 0x0},
++ {0x9003e, 0x0},
++ {0x9003f, 0x0},
++ {0x90040, 0x0},
++ {0x90041, 0x0},
++ {0x90042, 0x0},
++ {0x90043, 0x0},
++ {0x90044, 0x0},
++ {0x90045, 0x0},
++ {0x90046, 0x0},
++ {0x90047, 0x0},
++ {0x90048, 0x0},
++ {0x90049, 0x0},
++ {0x9004a, 0x0},
++ {0x9004b, 0x0},
++ {0x9004c, 0x0},
++ {0x9004d, 0x0},
++ {0x9004e, 0x0},
++ {0x9004f, 0x0},
++ {0x90050, 0x0},
++ {0x90051, 0x0},
++ {0x90052, 0x0},
++ {0x90053, 0x0},
++ {0x90054, 0x0},
++ {0x90055, 0x0},
++ {0x90056, 0x0},
++ {0x90057, 0x0},
++ {0x90058, 0x0},
++ {0x90059, 0x0},
++ {0x9005a, 0x0},
++ {0x9005b, 0x0},
++ {0x9005c, 0x0},
++ {0x9005d, 0x0},
++ {0x9005e, 0x0},
++ {0x9005f, 0x0},
++ {0x90060, 0x0},
++ {0x90061, 0x0},
++ {0x90062, 0x0},
++ {0x90063, 0x0},
++ {0x90064, 0x0},
++ {0x90065, 0x0},
++ {0x90066, 0x0},
++ {0x90067, 0x0},
++ {0x90068, 0x0},
++ {0x90069, 0x0},
++ {0x9006a, 0x0},
++ {0x9006b, 0x0},
++ {0x9006c, 0x0},
++ {0x9006d, 0x0},
++ {0x9006e, 0x0},
++ {0x9006f, 0x0},
++ {0x90070, 0x0},
++ {0x90071, 0x0},
++ {0x90072, 0x0},
++ {0x90073, 0x0},
++ {0x90074, 0x0},
++ {0x90075, 0x0},
++ {0x90076, 0x0},
++ {0x90077, 0x0},
++ {0x90078, 0x0},
++ {0x90079, 0x0},
++ {0x9007a, 0x0},
++ {0x9007b, 0x0},
++ {0x9007c, 0x0},
++ {0x9007d, 0x0},
++ {0x9007e, 0x0},
++ {0x9007f, 0x0},
++ {0x90080, 0x0},
++ {0x90081, 0x0},
++ {0x90082, 0x0},
++ {0x90083, 0x0},
++ {0x90084, 0x0},
++ {0x90085, 0x0},
++ {0x90086, 0x0},
++ {0x90087, 0x0},
++ {0x90088, 0x0},
++ {0x90089, 0x0},
++ {0x9008a, 0x0},
++ {0x9008b, 0x0},
++ {0x9008c, 0x0},
++ {0x9008d, 0x0},
++ {0x9008e, 0x0},
++ {0x9008f, 0x0},
++ {0x90090, 0x0},
++ {0x90091, 0x0},
++ {0x90092, 0x0},
++ {0x90093, 0x0},
++ {0x90094, 0x0},
++ {0x90095, 0x0},
++ {0x90096, 0x0},
++ {0x90097, 0x0},
++ {0x90098, 0x0},
++ {0x90099, 0x0},
++ {0x9009a, 0x0},
++ {0x9009b, 0x0},
++ {0x9009c, 0x0},
++ {0x9009d, 0x0},
++ {0x9009e, 0x0},
++ {0x9009f, 0x0},
++ {0x900a0, 0x0},
++ {0x900a1, 0x0},
++ {0x900a2, 0x0},
++ {0x900a3, 0x0},
++ {0x900a4, 0x0},
++ {0x900a5, 0x0},
++ {0x900a6, 0x0},
++ {0x900a7, 0x0},
++ {0x900a8, 0x0},
++ {0x900a9, 0x0},
++ {0x40000, 0x0},
++ {0x40020, 0x0},
++ {0x40040, 0x0},
++ {0x40060, 0x0},
++ {0x40001, 0x0},
++ {0x40021, 0x0},
++ {0x40041, 0x0},
++ {0x40061, 0x0},
++ {0x40002, 0x0},
++ {0x40022, 0x0},
++ {0x40042, 0x0},
++ {0x40062, 0x0},
++ {0x40003, 0x0},
++ {0x40023, 0x0},
++ {0x40043, 0x0},
++ {0x40063, 0x0},
++ {0x40004, 0x0},
++ {0x40024, 0x0},
++ {0x40044, 0x0},
++ {0x40064, 0x0},
++ {0x40005, 0x0},
++ {0x40025, 0x0},
++ {0x40045, 0x0},
++ {0x40065, 0x0},
++ {0x40006, 0x0},
++ {0x40026, 0x0},
++ {0x40046, 0x0},
++ {0x40066, 0x0},
++ {0x40007, 0x0},
++ {0x40027, 0x0},
++ {0x40047, 0x0},
++ {0x40067, 0x0},
++ {0x40008, 0x0},
++ {0x40028, 0x0},
++ {0x40048, 0x0},
++ {0x40068, 0x0},
++ {0x40009, 0x0},
++ {0x40029, 0x0},
++ {0x40049, 0x0},
++ {0x40069, 0x0},
++ {0x4000a, 0x0},
++ {0x4002a, 0x0},
++ {0x4004a, 0x0},
++ {0x4006a, 0x0},
++ {0x4000b, 0x0},
++ {0x4002b, 0x0},
++ {0x4004b, 0x0},
++ {0x4006b, 0x0},
++ {0x4000c, 0x0},
++ {0x4002c, 0x0},
++ {0x4004c, 0x0},
++ {0x4006c, 0x0},
++ {0x4000d, 0x0},
++ {0x4002d, 0x0},
++ {0x4004d, 0x0},
++ {0x4006d, 0x0},
++ {0x4000e, 0x0},
++ {0x4002e, 0x0},
++ {0x4004e, 0x0},
++ {0x4006e, 0x0},
++ {0x4000f, 0x0},
++ {0x4002f, 0x0},
++ {0x4004f, 0x0},
++ {0x4006f, 0x0},
++ {0x40010, 0x0},
++ {0x40030, 0x0},
++ {0x40050, 0x0},
++ {0x40070, 0x0},
++ {0x40011, 0x0},
++ {0x40031, 0x0},
++ {0x40051, 0x0},
++ {0x40071, 0x0},
++ {0x40012, 0x0},
++ {0x40032, 0x0},
++ {0x40052, 0x0},
++ {0x40072, 0x0},
++ {0x40013, 0x0},
++ {0x40033, 0x0},
++ {0x40053, 0x0},
++ {0x40073, 0x0},
++ {0x40014, 0x0},
++ {0x40034, 0x0},
++ {0x40054, 0x0},
++ {0x40074, 0x0},
++ {0x40015, 0x0},
++ {0x40035, 0x0},
++ {0x40055, 0x0},
++ {0x40075, 0x0},
++ {0x40016, 0x0},
++ {0x40036, 0x0},
++ {0x40056, 0x0},
++ {0x40076, 0x0},
++ {0x40017, 0x0},
++ {0x40037, 0x0},
++ {0x40057, 0x0},
++ {0x40077, 0x0},
++ {0x40018, 0x0},
++ {0x40038, 0x0},
++ {0x40058, 0x0},
++ {0x40078, 0x0},
++ {0x40019, 0x0},
++ {0x40039, 0x0},
++ {0x40059, 0x0},
++ {0x40079, 0x0},
++ {0x4001a, 0x0},
++ {0x4003a, 0x0},
++ {0x4005a, 0x0},
++ {0x4007a, 0x0},
++ {0x900aa, 0x0},
++ {0x900ab, 0x0},
++ {0x900ac, 0x0},
++ {0x900ad, 0x0},
++ {0x900ae, 0x0},
++ {0x900af, 0x0},
++ {0x900b0, 0x0},
++ {0x900b1, 0x0},
++ {0x900b2, 0x0},
++ {0x900b3, 0x0},
++ {0x900b4, 0x0},
++ {0x900b5, 0x0},
++ {0x900b6, 0x0},
++ {0x900b7, 0x0},
++ {0x900b8, 0x0},
++ {0x900b9, 0x0},
++ {0x900ba, 0x0},
++ {0x900bb, 0x0},
++ {0x900bc, 0x0},
++ {0x900bd, 0x0},
++ {0x900be, 0x0},
++ {0x900bf, 0x0},
++ {0x900c0, 0x0},
++ {0x900c1, 0x0},
++ {0x900c2, 0x0},
++ {0x900c3, 0x0},
++ {0x900c4, 0x0},
++ {0x900c5, 0x0},
++ {0x900c6, 0x0},
++ {0x900c7, 0x0},
++ {0x900c8, 0x0},
++ {0x900c9, 0x0},
++ {0x900ca, 0x0},
++ {0x900cb, 0x0},
++ {0x900cc, 0x0},
++ {0x900cd, 0x0},
++ {0x900ce, 0x0},
++ {0x900cf, 0x0},
++ {0x900d0, 0x0},
++ {0x900d1, 0x0},
++ {0x900d2, 0x0},
++ {0x900d3, 0x0},
++ {0x900d4, 0x0},
++ {0x900d5, 0x0},
++ {0x900d6, 0x0},
++ {0x900d7, 0x0},
++ {0x900d8, 0x0},
++ {0x900d9, 0x0},
++ {0x900da, 0x0},
++ {0x900db, 0x0},
++ {0x900dc, 0x0},
++ {0x900dd, 0x0},
++ {0x900de, 0x0},
++ {0x900df, 0x0},
++ {0x900e0, 0x0},
++ {0x900e1, 0x0},
++ {0x900e2, 0x0},
++ {0x900e3, 0x0},
++ {0x900e4, 0x0},
++ {0x900e5, 0x0},
++ {0x900e6, 0x0},
++ {0x900e7, 0x0},
++ {0x900e8, 0x0},
++ {0x900e9, 0x0},
++ {0x900ea, 0x0},
++ {0x900eb, 0x0},
++ {0x900ec, 0x0},
++ {0x900ed, 0x0},
++ {0x900ee, 0x0},
++ {0x900ef, 0x0},
++ {0x900f0, 0x0},
++ {0x900f1, 0x0},
++ {0x900f2, 0x0},
++ {0x900f3, 0x0},
++ {0x900f4, 0x0},
++ {0x900f5, 0x0},
++ {0x900f6, 0x0},
++ {0x900f7, 0x0},
++ {0x900f8, 0x0},
++ {0x900f9, 0x0},
++ {0x900fa, 0x0},
++ {0x900fb, 0x0},
++ {0x900fc, 0x0},
++ {0x900fd, 0x0},
++ {0x900fe, 0x0},
++ {0x900ff, 0x0},
++ {0x90100, 0x0},
++ {0x90101, 0x0},
++ {0x90102, 0x0},
++ {0x90103, 0x0},
++ {0x90104, 0x0},
++ {0x90105, 0x0},
++ {0x90106, 0x0},
++ {0x90107, 0x0},
++ {0x90108, 0x0},
++ {0x90109, 0x0},
++ {0x9010a, 0x0},
++ {0x9010b, 0x0},
++ {0x9010c, 0x0},
++ {0x9010d, 0x0},
++ {0x9010e, 0x0},
++ {0x9010f, 0x0},
++ {0x90110, 0x0},
++ {0x90111, 0x0},
++ {0x90112, 0x0},
++ {0x90113, 0x0},
++ {0x90114, 0x0},
++ {0x90115, 0x0},
++ {0x90116, 0x0},
++ {0x90117, 0x0},
++ {0x90118, 0x0},
++ {0x90119, 0x0},
++ {0x9011a, 0x0},
++ {0x9011b, 0x0},
++ {0x9011c, 0x0},
++ {0x9011d, 0x0},
++ {0x9011e, 0x0},
++ {0x9011f, 0x0},
++ {0x90120, 0x0},
++ {0x90121, 0x0},
++ {0x90122, 0x0},
++ {0x90123, 0x0},
++ {0x90124, 0x0},
++ {0x90125, 0x0},
++ {0x90126, 0x0},
++ {0x90127, 0x0},
++ {0x90128, 0x0},
++ {0x90129, 0x0},
++ {0x9012a, 0x0},
++ {0x9012b, 0x0},
++ {0x9012c, 0x0},
++ {0x9012d, 0x0},
++ {0x9012e, 0x0},
++ {0x9012f, 0x0},
++ {0x90130, 0x0},
++ {0x90131, 0x0},
++ {0x90132, 0x0},
++ {0x90133, 0x0},
++ {0x90134, 0x0},
++ {0x90135, 0x0},
++ {0x90136, 0x0},
++ {0x90137, 0x0},
++ {0x90138, 0x0},
++ {0x90139, 0x0},
++ {0x9013a, 0x0},
++ {0x9013b, 0x0},
++ {0x9013c, 0x0},
++ {0x9013d, 0x0},
++ {0x9013e, 0x0},
++ {0x9013f, 0x0},
++ {0x90140, 0x0},
++ {0x90141, 0x0},
++ {0x90142, 0x0},
++ {0x90143, 0x0},
++ {0x90144, 0x0},
++ {0x90145, 0x0},
++ {0x90146, 0x0},
++ {0x90147, 0x0},
++ {0x90148, 0x0},
++ {0x90149, 0x0},
++ {0x9014a, 0x0},
++ {0x9014b, 0x0},
++ {0x9014c, 0x0},
++ {0x9014d, 0x0},
++ {0x9014e, 0x0},
++ {0x9014f, 0x0},
++ {0x90150, 0x0},
++ {0x90151, 0x0},
++ {0x90152, 0x0},
++ {0x90153, 0x0},
++ {0x90154, 0x0},
++ {0x90155, 0x0},
++ {0x90156, 0x0},
++ {0x90157, 0x0},
++ {0x90158, 0x0},
++ {0x90159, 0x0},
++ {0x9015a, 0x0},
++ {0x9015b, 0x0},
++ {0x9015c, 0x0},
++ {0x9015d, 0x0},
++ {0x9015e, 0x0},
++ {0x9015f, 0x0},
++ {0x90160, 0x0},
++ {0x90161, 0x0},
++ {0x90162, 0x0},
++ {0x90163, 0x0},
++ {0x90164, 0x0},
++ {0x90165, 0x0},
++ {0x90166, 0x0},
++ {0x90167, 0x0},
++ {0x90168, 0x0},
++ {0x90169, 0x0},
++ {0x9016a, 0x0},
++ {0x9016b, 0x0},
++ {0x9016c, 0x0},
++ {0x9016d, 0x0},
++ {0x9016e, 0x0},
++ {0x9016f, 0x0},
++ {0x90170, 0x0},
++ {0x90171, 0x0},
++ {0x90172, 0x0},
++ {0x90173, 0x0},
++ {0x90174, 0x0},
++ {0x90175, 0x0},
++ {0x90176, 0x0},
++ {0x90177, 0x0},
++ {0x90178, 0x0},
++ {0x90179, 0x0},
++ {0x9017a, 0x0},
++ {0x9017b, 0x0},
++ {0x9017c, 0x0},
++ {0x9017d, 0x0},
++ {0x9017e, 0x0},
++ {0x9017f, 0x0},
++ {0x90180, 0x0},
++ {0x90181, 0x0},
++ {0x90182, 0x0},
++ {0x90183, 0x0},
++ {0x90184, 0x0},
++ {0x90006, 0x0},
++ {0x90007, 0x0},
++ {0x90008, 0x0},
++ {0x90009, 0x0},
++ {0x9000a, 0x0},
++ {0x9000b, 0x0},
++ {0xd00e7, 0x0},
++ {0x90017, 0x0},
++ {0x9001f, 0x0},
++ {0x90026, 0x0},
++ {0x400d0, 0x0},
++ {0x400d1, 0x0},
++ {0x400d2, 0x0},
++ {0x400d3, 0x0},
++ {0x400d4, 0x0},
++ {0x400d5, 0x0},
++ {0x400d6, 0x0},
++ {0x400d7, 0x0},
++ {0x200be, 0x0},
++ {0x2000b, 0x0},
++ {0x2000c, 0x0},
++ {0x2000d, 0x0},
++ {0x2000e, 0x0},
++ {0x12000b, 0x0},
++ {0x12000c, 0x0},
++ {0x12000d, 0x0},
++ {0x12000e, 0x0},
++ {0x22000b, 0x0},
++ {0x22000c, 0x0},
++ {0x22000d, 0x0},
++ {0x22000e, 0x0},
++ {0x9000c, 0x0},
++ {0x9000d, 0x0},
++ {0x9000e, 0x0},
++ {0x9000f, 0x0},
++ {0x90010, 0x0},
++ {0x90011, 0x0},
++ {0x90012, 0x0},
++ {0x90013, 0x0},
++ {0x20010, 0x0},
++ {0x20011, 0x0},
++ {0x120010, 0x0},
++ {0x120011, 0x0},
++ {0x40080, 0x0},
++ {0x40081, 0x0},
++ {0x40082, 0x0},
++ {0x40083, 0x0},
++ {0x40084, 0x0},
++ {0x40085, 0x0},
++ {0x140080, 0x0},
++ {0x140081, 0x0},
++ {0x140082, 0x0},
++ {0x140083, 0x0},
++ {0x140084, 0x0},
++ {0x140085, 0x0},
++ {0x240080, 0x0},
++ {0x240081, 0x0},
++ {0x240082, 0x0},
++ {0x240083, 0x0},
++ {0x240084, 0x0},
++ {0x240085, 0x0},
++ {0x400fd, 0x0},
++ {0x400f1, 0x0},
++ {0x10011, 0x0},
++ {0x10012, 0x0},
++ {0x10013, 0x0},
++ {0x10018, 0x0},
++ {0x10002, 0x0},
++ {0x100b2, 0x0},
++ {0x101b4, 0x0},
++ {0x102b4, 0x0},
++ {0x103b4, 0x0},
++ {0x104b4, 0x0},
++ {0x105b4, 0x0},
++ {0x106b4, 0x0},
++ {0x107b4, 0x0},
++ {0x108b4, 0x0},
++ {0x11011, 0x0},
++ {0x11012, 0x0},
++ {0x11013, 0x0},
++ {0x11018, 0x0},
++ {0x11002, 0x0},
++ {0x110b2, 0x0},
++ {0x111b4, 0x0},
++ {0x112b4, 0x0},
++ {0x113b4, 0x0},
++ {0x114b4, 0x0},
++ {0x115b4, 0x0},
++ {0x116b4, 0x0},
++ {0x117b4, 0x0},
++ {0x118b4, 0x0},
++ {0x20089, 0x0},
++ {0xc0080, 0x0},
++ {0x200cb, 0x0},
++ {0x10068, 0x0},
++ {0x10069, 0x0},
++ {0x10168, 0x0},
++ {0x10169, 0x0},
++ {0x10268, 0x0},
++ {0x10269, 0x0},
++ {0x10368, 0x0},
++ {0x10369, 0x0},
++ {0x10468, 0x0},
++ {0x10469, 0x0},
++ {0x10568, 0x0},
++ {0x10569, 0x0},
++ {0x10668, 0x0},
++ {0x10669, 0x0},
++ {0x10768, 0x0},
++ {0x10769, 0x0},
++ {0x10868, 0x0},
++ {0x10869, 0x0},
++ {0x100aa, 0x0},
++ {0x10062, 0x0},
++ {0x10001, 0x0},
++ {0x100a0, 0x0},
++ {0x100a1, 0x0},
++ {0x100a2, 0x0},
++ {0x100a3, 0x0},
++ {0x100a4, 0x0},
++ {0x100a5, 0x0},
++ {0x100a6, 0x0},
++ {0x100a7, 0x0},
++ {0x11068, 0x0},
++ {0x11069, 0x0},
++ {0x11168, 0x0},
++ {0x11169, 0x0},
++ {0x11268, 0x0},
++ {0x11269, 0x0},
++ {0x11368, 0x0},
++ {0x11369, 0x0},
++ {0x11468, 0x0},
++ {0x11469, 0x0},
++ {0x11568, 0x0},
++ {0x11569, 0x0},
++ {0x11668, 0x0},
++ {0x11669, 0x0},
++ {0x11768, 0x0},
++ {0x11769, 0x0},
++ {0x11868, 0x0},
++ {0x11869, 0x0},
++ {0x110aa, 0x0},
++ {0x11062, 0x0},
++ {0x11001, 0x0},
++ {0x110a0, 0x0},
++ {0x110a1, 0x0},
++ {0x110a2, 0x0},
++ {0x110a3, 0x0},
++ {0x110a4, 0x0},
++ {0x110a5, 0x0},
++ {0x110a6, 0x0},
++ {0x110a7, 0x0},
++ {0x80, 0x0},
++ {0x1080, 0x0},
++ {0x2080, 0x0},
++ {0x10020, 0x0},
++ {0x10080, 0x0},
++ {0x10081, 0x0},
++ {0x100d0, 0x0},
++ {0x100d1, 0x0},
++ {0x1008c, 0x0},
++ {0x1008d, 0x0},
++ {0x10180, 0x0},
++ {0x10181, 0x0},
++ {0x101d0, 0x0},
++ {0x101d1, 0x0},
++ {0x1018c, 0x0},
++ {0x1018d, 0x0},
++ {0x100c0, 0x0},
++ {0x100c1, 0x0},
++ {0x101c0, 0x0},
++ {0x101c1, 0x0},
++ {0x102c0, 0x0},
++ {0x102c1, 0x0},
++ {0x103c0, 0x0},
++ {0x103c1, 0x0},
++ {0x104c0, 0x0},
++ {0x104c1, 0x0},
++ {0x105c0, 0x0},
++ {0x105c1, 0x0},
++ {0x106c0, 0x0},
++ {0x106c1, 0x0},
++ {0x107c0, 0x0},
++ {0x107c1, 0x0},
++ {0x108c0, 0x0},
++ {0x108c1, 0x0},
++ {0x100ae, 0x0},
++ {0x100af, 0x0},
++ {0x11020, 0x0},
++ {0x11080, 0x0},
++ {0x11081, 0x0},
++ {0x110d0, 0x0},
++ {0x110d1, 0x0},
++ {0x1108c, 0x0},
++ {0x1108d, 0x0},
++ {0x11180, 0x0},
++ {0x11181, 0x0},
++ {0x111d0, 0x0},
++ {0x111d1, 0x0},
++ {0x1118c, 0x0},
++ {0x1118d, 0x0},
++ {0x110c0, 0x0},
++ {0x110c1, 0x0},
++ {0x111c0, 0x0},
++ {0x111c1, 0x0},
++ {0x112c0, 0x0},
++ {0x112c1, 0x0},
++ {0x113c0, 0x0},
++ {0x113c1, 0x0},
++ {0x114c0, 0x0},
++ {0x114c1, 0x0},
++ {0x115c0, 0x0},
++ {0x115c1, 0x0},
++ {0x116c0, 0x0},
++ {0x116c1, 0x0},
++ {0x117c0, 0x0},
++ {0x117c1, 0x0},
++ {0x118c0, 0x0},
++ {0x118c1, 0x0},
++ {0x110ae, 0x0},
++ {0x110af, 0x0},
++ {0x90201, 0x0},
++ {0x90202, 0x0},
++ {0x90203, 0x0},
++ {0x90205, 0x0},
++ {0x90206, 0x0},
++ {0x90207, 0x0},
++ {0x90208, 0x0},
++ {0x20020, 0x0},
++ {0x100080, 0x0},
++ {0x101080, 0x0},
++ {0x102080, 0x0},
++ {0x110020, 0x0},
++ {0x110080, 0x0},
++ {0x110081, 0x0},
++ {0x1100d0, 0x0},
++ {0x1100d1, 0x0},
++ {0x11008c, 0x0},
++ {0x11008d, 0x0},
++ {0x110180, 0x0},
++ {0x110181, 0x0},
++ {0x1101d0, 0x0},
++ {0x1101d1, 0x0},
++ {0x11018c, 0x0},
++ {0x11018d, 0x0},
++ {0x1100c0, 0x0},
++ {0x1100c1, 0x0},
++ {0x1101c0, 0x0},
++ {0x1101c1, 0x0},
++ {0x1102c0, 0x0},
++ {0x1102c1, 0x0},
++ {0x1103c0, 0x0},
++ {0x1103c1, 0x0},
++ {0x1104c0, 0x0},
++ {0x1104c1, 0x0},
++ {0x1105c0, 0x0},
++ {0x1105c1, 0x0},
++ {0x1106c0, 0x0},
++ {0x1106c1, 0x0},
++ {0x1107c0, 0x0},
++ {0x1107c1, 0x0},
++ {0x1108c0, 0x0},
++ {0x1108c1, 0x0},
++ {0x1100ae, 0x0},
++ {0x1100af, 0x0},
++ {0x111020, 0x0},
++ {0x111080, 0x0},
++ {0x111081, 0x0},
++ {0x1110d0, 0x0},
++ {0x1110d1, 0x0},
++ {0x11108c, 0x0},
++ {0x11108d, 0x0},
++ {0x111180, 0x0},
++ {0x111181, 0x0},
++ {0x1111d0, 0x0},
++ {0x1111d1, 0x0},
++ {0x11118c, 0x0},
++ {0x11118d, 0x0},
++ {0x1110c0, 0x0},
++ {0x1110c1, 0x0},
++ {0x1111c0, 0x0},
++ {0x1111c1, 0x0},
++ {0x1112c0, 0x0},
++ {0x1112c1, 0x0},
++ {0x1113c0, 0x0},
++ {0x1113c1, 0x0},
++ {0x1114c0, 0x0},
++ {0x1114c1, 0x0},
++ {0x1115c0, 0x0},
++ {0x1115c1, 0x0},
++ {0x1116c0, 0x0},
++ {0x1116c1, 0x0},
++ {0x1117c0, 0x0},
++ {0x1117c1, 0x0},
++ {0x1118c0, 0x0},
++ {0x1118c1, 0x0},
++ {0x1110ae, 0x0},
++ {0x1110af, 0x0},
++ {0x190201, 0x0},
++ {0x190202, 0x0},
++ {0x190203, 0x0},
++ {0x190205, 0x0},
++ {0x190206, 0x0},
++ {0x190207, 0x0},
++ {0x190208, 0x0},
++ {0x120020, 0x0},
++ {0x200080, 0x0},
++ {0x201080, 0x0},
++ {0x202080, 0x0},
++ {0x210020, 0x0},
++ {0x210080, 0x0},
++ {0x210081, 0x0},
++ {0x2100d0, 0x0},
++ {0x2100d1, 0x0},
++ {0x21008c, 0x0},
++ {0x21008d, 0x0},
++ {0x210180, 0x0},
++ {0x210181, 0x0},
++ {0x2101d0, 0x0},
++ {0x2101d1, 0x0},
++ {0x21018c, 0x0},
++ {0x21018d, 0x0},
++ {0x2100c0, 0x0},
++ {0x2100c1, 0x0},
++ {0x2101c0, 0x0},
++ {0x2101c1, 0x0},
++ {0x2102c0, 0x0},
++ {0x2102c1, 0x0},
++ {0x2103c0, 0x0},
++ {0x2103c1, 0x0},
++ {0x2104c0, 0x0},
++ {0x2104c1, 0x0},
++ {0x2105c0, 0x0},
++ {0x2105c1, 0x0},
++ {0x2106c0, 0x0},
++ {0x2106c1, 0x0},
++ {0x2107c0, 0x0},
++ {0x2107c1, 0x0},
++ {0x2108c0, 0x0},
++ {0x2108c1, 0x0},
++ {0x2100ae, 0x0},
++ {0x2100af, 0x0},
++ {0x211020, 0x0},
++ {0x211080, 0x0},
++ {0x211081, 0x0},
++ {0x2110d0, 0x0},
++ {0x2110d1, 0x0},
++ {0x21108c, 0x0},
++ {0x21108d, 0x0},
++ {0x211180, 0x0},
++ {0x211181, 0x0},
++ {0x2111d0, 0x0},
++ {0x2111d1, 0x0},
++ {0x21118c, 0x0},
++ {0x21118d, 0x0},
++ {0x2110c0, 0x0},
++ {0x2110c1, 0x0},
++ {0x2111c0, 0x0},
++ {0x2111c1, 0x0},
++ {0x2112c0, 0x0},
++ {0x2112c1, 0x0},
++ {0x2113c0, 0x0},
++ {0x2113c1, 0x0},
++ {0x2114c0, 0x0},
++ {0x2114c1, 0x0},
++ {0x2115c0, 0x0},
++ {0x2115c1, 0x0},
++ {0x2116c0, 0x0},
++ {0x2116c1, 0x0},
++ {0x2117c0, 0x0},
++ {0x2117c1, 0x0},
++ {0x2118c0, 0x0},
++ {0x2118c1, 0x0},
++ {0x2110ae, 0x0},
++ {0x2110af, 0x0},
++ {0x290201, 0x0},
++ {0x290202, 0x0},
++ {0x290203, 0x0},
++ {0x290205, 0x0},
++ {0x290206, 0x0},
++ {0x290207, 0x0},
++ {0x290208, 0x0},
++ {0x220020, 0x0},
++ {0x20077, 0x0},
++ {0x20072, 0x0},
++ {0x20073, 0x0},
++ {0x400c0, 0x0},
++ {0x10040, 0x0},
++ {0x10140, 0x0},
++ {0x10240, 0x0},
++ {0x10340, 0x0},
++ {0x10440, 0x0},
++ {0x10540, 0x0},
++ {0x10640, 0x0},
++ {0x10740, 0x0},
++ {0x10840, 0x0},
++ {0x11040, 0x0},
++ {0x11140, 0x0},
++ {0x11240, 0x0},
++ {0x11340, 0x0},
++ {0x11440, 0x0},
++ {0x11540, 0x0},
++ {0x11640, 0x0},
++ {0x11740, 0x0},
++ {0x11840, 0x0},
++};
++
++/* P0 message block parameter for training firmware */
++static struct dram_cfg_param ddr_fsp0_cfg[] = {
++ {0xd0000, 0x0},
++ {0x54003, 0xe94},
++ {0x54004, 0x4},
++ {0x54006, 0x15},
++ {0x54008, 0x131f},
++ {0x54009, 0xc8},
++ {0x5400b, 0x4},
++ {0x5400d, 0x100},
++ {0x5400f, 0x100},
++ {0x54012, 0x110},
++ {0x54019, 0x36e4},
++ {0x5401a, 0x32},
++ {0x5401b, 0x1146},
++ {0x5401c, 0x1108},
++ {0x5401e, 0x4},
++ {0x5401f, 0x36e4},
++ {0x54020, 0x32},
++ {0x54021, 0x1146},
++ {0x54022, 0x1108},
++ {0x54024, 0x4},
++ {0x54032, 0xe400},
++ {0x54033, 0x3236},
++ {0x54034, 0x4600},
++ {0x54035, 0x811},
++ {0x54036, 0x11},
++ {0x54037, 0x400},
++ {0x54038, 0xe400},
++ {0x54039, 0x3236},
++ {0x5403a, 0x4600},
++ {0x5403b, 0x811},
++ {0x5403c, 0x11},
++ {0x5403d, 0x400},
++ {0xd0000, 0x1}
++};
++
++/* P1 message block parameter for training firmware */
++static struct dram_cfg_param ddr_fsp1_cfg[] = {
++ {0xd0000, 0x0},
++ {0x54002, 0x1},
++ {0x54003, 0x74a},
++ {0x54004, 0x4},
++ {0x54006, 0x15},
++ {0x54008, 0x121f},
++ {0x54009, 0xc8},
++ {0x5400b, 0x4},
++ {0x5400d, 0x100},
++ {0x5400f, 0x100},
++ {0x54012, 0x110},
++ {0x54019, 0x1bb4},
++ {0x5401a, 0x32},
++ {0x5401b, 0x1146},
++ {0x5401c, 0x1108},
++ {0x5401e, 0x4},
++ {0x5401f, 0x1bb4},
++ {0x54020, 0x32},
++ {0x54021, 0x1146},
++ {0x54022, 0x1108},
++ {0x54024, 0x4},
++ {0x54032, 0xb400},
++ {0x54033, 0x321b},
++ {0x54034, 0x4600},
++ {0x54035, 0x811},
++ {0x54036, 0x11},
++ {0x54037, 0x400},
++ {0x54038, 0xb400},
++ {0x54039, 0x321b},
++ {0x5403a, 0x4600},
++ {0x5403b, 0x811},
++ {0x5403c, 0x11},
++ {0x5403d, 0x400},
++ {0xd0000, 0x1}
++};
++
++/* P2 message block parameter for training firmware */
++static struct dram_cfg_param ddr_fsp2_cfg[] = {
++ {0xd0000, 0x0},
++ {0x54002, 0x102},
++ {0x54003, 0x270},
++ {0x54004, 0x4},
++ {0x54006, 0x15},
++ {0x54008, 0x121f},
++ {0x54009, 0xc8},
++ {0x5400b, 0x4},
++ {0x5400d, 0x100},
++ {0x5400f, 0x100},
++ {0x54012, 0x110},
++ {0x54019, 0x994},
++ {0x5401a, 0x32},
++ {0x5401b, 0x1146},
++ {0x5401c, 0x1100},
++ {0x5401e, 0x4},
++ {0x5401f, 0x994},
++ {0x54020, 0x32},
++ {0x54021, 0x1146},
++ {0x54022, 0x1100},
++ {0x54024, 0x4},
++ {0x54032, 0x9400},
++ {0x54033, 0x3209},
++ {0x54034, 0x4600},
++ {0x54035, 0x11},
++ {0x54036, 0x11},
++ {0x54037, 0x400},
++ {0x54038, 0x9400},
++ {0x54039, 0x3209},
++ {0x5403a, 0x4600},
++ {0x5403b, 0x11},
++ {0x5403c, 0x11},
++ {0x5403d, 0x400},
++ {0xd0000, 0x1}
++};
++
++/* P0 2D message block parameter for training firmware */
++static struct dram_cfg_param ddr_fsp0_2d_cfg[] = {
++ {0xd0000, 0x0},
++ {0x54003, 0xe94},
++ {0x54004, 0x4},
++ {0x54006, 0x15},
++ {0x54008, 0x61},
++ {0x54009, 0xc8},
++ {0x5400b, 0x4},
++ {0x5400d, 0x100},
++ {0x5400f, 0x100},
++ {0x54010, 0x2080},
++ {0x54012, 0x110},
++ {0x54019, 0x36e4},
++ {0x5401a, 0x32},
++ {0x5401b, 0x1146},
++ {0x5401c, 0x1108},
++ {0x5401e, 0x4},
++ {0x5401f, 0x36e4},
++ {0x54020, 0x32},
++ {0x54021, 0x1146},
++ {0x54022, 0x1108},
++ {0x54024, 0x4},
++ {0x54032, 0xe400},
++ {0x54033, 0x3236},
++ {0x54034, 0x4600},
++ {0x54035, 0x811},
++ {0x54036, 0x11},
++ {0x54037, 0x400},
++ {0x54038, 0xe400},
++ {0x54039, 0x3236},
++ {0x5403a, 0x4600},
++ {0x5403b, 0x811},
++ {0x5403c, 0x11},
++ {0x5403d, 0x400},
++ {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, 0xb},
++ {0x90039, 0x7c0},
++ {0x9003a, 0x139},
++ {0x9003b, 0x44},
++ {0x9003c, 0x633},
++ {0x9003d, 0x159},
++ {0x9003e, 0x14f},
++ {0x9003f, 0x630},
++ {0x90040, 0x159},
++ {0x90041, 0x47},
++ {0x90042, 0x633},
++ {0x90043, 0x149},
++ {0x90044, 0x4f},
++ {0x90045, 0x633},
++ {0x90046, 0x179},
++ {0x90047, 0x8},
++ {0x90048, 0xe0},
++ {0x90049, 0x109},
++ {0x9004a, 0x0},
++ {0x9004b, 0x7c8},
++ {0x9004c, 0x109},
++ {0x9004d, 0x0},
++ {0x9004e, 0x1},
++ {0x9004f, 0x8},
++ {0x90050, 0x30},
++ {0x90051, 0x65a},
++ {0x90052, 0x9},
++ {0x90053, 0x0},
++ {0x90054, 0x45a},
++ {0x90055, 0x9},
++ {0x90056, 0x0},
++ {0x90057, 0x448},
++ {0x90058, 0x109},
++ {0x90059, 0x40},
++ {0x9005a, 0x633},
++ {0x9005b, 0x179},
++ {0x9005c, 0x1},
++ {0x9005d, 0x618},
++ {0x9005e, 0x109},
++ {0x9005f, 0x40c0},
++ {0x90060, 0x633},
++ {0x90061, 0x149},
++ {0x90062, 0x8},
++ {0x90063, 0x4},
++ {0x90064, 0x48},
++ {0x90065, 0x4040},
++ {0x90066, 0x633},
++ {0x90067, 0x149},
++ {0x90068, 0x0},
++ {0x90069, 0x4},
++ {0x9006a, 0x48},
++ {0x9006b, 0x40},
++ {0x9006c, 0x633},
++ {0x9006d, 0x149},
++ {0x9006e, 0x0},
++ {0x9006f, 0x658},
++ {0x90070, 0x109},
++ {0x90071, 0x10},
++ {0x90072, 0x4},
++ {0x90073, 0x18},
++ {0x90074, 0x0},
++ {0x90075, 0x4},
++ {0x90076, 0x78},
++ {0x90077, 0x549},
++ {0x90078, 0x633},
++ {0x90079, 0x159},
++ {0x9007a, 0xd49},
++ {0x9007b, 0x633},
++ {0x9007c, 0x159},
++ {0x9007d, 0x94a},
++ {0x9007e, 0x633},
++ {0x9007f, 0x159},
++ {0x90080, 0x441},
++ {0x90081, 0x633},
++ {0x90082, 0x149},
++ {0x90083, 0x42},
++ {0x90084, 0x633},
++ {0x90085, 0x149},
++ {0x90086, 0x1},
++ {0x90087, 0x633},
++ {0x90088, 0x149},
++ {0x90089, 0x0},
++ {0x9008a, 0xe0},
++ {0x9008b, 0x109},
++ {0x9008c, 0xa},
++ {0x9008d, 0x10},
++ {0x9008e, 0x109},
++ {0x9008f, 0x9},
++ {0x90090, 0x3c0},
++ {0x90091, 0x149},
++ {0x90092, 0x9},
++ {0x90093, 0x3c0},
++ {0x90094, 0x159},
++ {0x90095, 0x18},
++ {0x90096, 0x10},
++ {0x90097, 0x109},
++ {0x90098, 0x0},
++ {0x90099, 0x3c0},
++ {0x9009a, 0x109},
++ {0x9009b, 0x18},
++ {0x9009c, 0x4},
++ {0x9009d, 0x48},
++ {0x9009e, 0x18},
++ {0x9009f, 0x4},
++ {0x900a0, 0x58},
++ {0x900a1, 0xb},
++ {0x900a2, 0x10},
++ {0x900a3, 0x109},
++ {0x900a4, 0x1},
++ {0x900a5, 0x10},
++ {0x900a6, 0x109},
++ {0x900a7, 0x5},
++ {0x900a8, 0x7c0},
++ {0x900a9, 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, 0x625},
++ {0x4002b, 0x15},
++ {0x4004b, 0x0},
++ {0x4006b, 0x0},
++ {0x4000c, 0x4028},
++ {0x4002c, 0x80},
++ {0x4004c, 0x0},
++ {0x4006c, 0x0},
++ {0x4000d, 0xe08},
++ {0x4002d, 0xc1a},
++ {0x4004d, 0x0},
++ {0x4006d, 0x0},
++ {0x4000e, 0x625},
++ {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},
++ {0x900aa, 0x0},
++ {0x900ab, 0x790},
++ {0x900ac, 0x11a},
++ {0x900ad, 0x8},
++ {0x900ae, 0x7aa},
++ {0x900af, 0x2a},
++ {0x900b0, 0x10},
++ {0x900b1, 0x7b2},
++ {0x900b2, 0x2a},
++ {0x900b3, 0x0},
++ {0x900b4, 0x7c8},
++ {0x900b5, 0x109},
++ {0x900b6, 0x10},
++ {0x900b7, 0x10},
++ {0x900b8, 0x109},
++ {0x900b9, 0x10},
++ {0x900ba, 0x2a8},
++ {0x900bb, 0x129},
++ {0x900bc, 0x8},
++ {0x900bd, 0x370},
++ {0x900be, 0x129},
++ {0x900bf, 0xa},
++ {0x900c0, 0x3c8},
++ {0x900c1, 0x1a9},
++ {0x900c2, 0xc},
++ {0x900c3, 0x408},
++ {0x900c4, 0x199},
++ {0x900c5, 0x14},
++ {0x900c6, 0x790},
++ {0x900c7, 0x11a},
++ {0x900c8, 0x8},
++ {0x900c9, 0x4},
++ {0x900ca, 0x18},
++ {0x900cb, 0xe},
++ {0x900cc, 0x408},
++ {0x900cd, 0x199},
++ {0x900ce, 0x8},
++ {0x900cf, 0x8568},
++ {0x900d0, 0x108},
++ {0x900d1, 0x18},
++ {0x900d2, 0x790},
++ {0x900d3, 0x16a},
++ {0x900d4, 0x8},
++ {0x900d5, 0x1d8},
++ {0x900d6, 0x169},
++ {0x900d7, 0x10},
++ {0x900d8, 0x8558},
++ {0x900d9, 0x168},
++ {0x900da, 0x1ff8},
++ {0x900db, 0x85a8},
++ {0x900dc, 0x1e8},
++ {0x900dd, 0x50},
++ {0x900de, 0x798},
++ {0x900df, 0x16a},
++ {0x900e0, 0x60},
++ {0x900e1, 0x7a0},
++ {0x900e2, 0x16a},
++ {0x900e3, 0x8},
++ {0x900e4, 0x8310},
++ {0x900e5, 0x168},
++ {0x900e6, 0x8},
++ {0x900e7, 0xa310},
++ {0x900e8, 0x168},
++ {0x900e9, 0xa},
++ {0x900ea, 0x408},
++ {0x900eb, 0x169},
++ {0x900ec, 0x6e},
++ {0x900ed, 0x0},
++ {0x900ee, 0x68},
++ {0x900ef, 0x0},
++ {0x900f0, 0x408},
++ {0x900f1, 0x169},
++ {0x900f2, 0x0},
++ {0x900f3, 0x8310},
++ {0x900f4, 0x168},
++ {0x900f5, 0x0},
++ {0x900f6, 0xa310},
++ {0x900f7, 0x168},
++ {0x900f8, 0x1ff8},
++ {0x900f9, 0x85a8},
++ {0x900fa, 0x1e8},
++ {0x900fb, 0x68},
++ {0x900fc, 0x798},
++ {0x900fd, 0x16a},
++ {0x900fe, 0x78},
++ {0x900ff, 0x7a0},
++ {0x90100, 0x16a},
++ {0x90101, 0x68},
++ {0x90102, 0x790},
++ {0x90103, 0x16a},
++ {0x90104, 0x8},
++ {0x90105, 0x8b10},
++ {0x90106, 0x168},
++ {0x90107, 0x8},
++ {0x90108, 0xab10},
++ {0x90109, 0x168},
++ {0x9010a, 0xa},
++ {0x9010b, 0x408},
++ {0x9010c, 0x169},
++ {0x9010d, 0x58},
++ {0x9010e, 0x0},
++ {0x9010f, 0x68},
++ {0x90110, 0x0},
++ {0x90111, 0x408},
++ {0x90112, 0x169},
++ {0x90113, 0x0},
++ {0x90114, 0x8b10},
++ {0x90115, 0x168},
++ {0x90116, 0x1},
++ {0x90117, 0xab10},
++ {0x90118, 0x168},
++ {0x90119, 0x0},
++ {0x9011a, 0x1d8},
++ {0x9011b, 0x169},
++ {0x9011c, 0x80},
++ {0x9011d, 0x790},
++ {0x9011e, 0x16a},
++ {0x9011f, 0x18},
++ {0x90120, 0x7aa},
++ {0x90121, 0x6a},
++ {0x90122, 0xa},
++ {0x90123, 0x0},
++ {0x90124, 0x1e9},
++ {0x90125, 0x8},
++ {0x90126, 0x8080},
++ {0x90127, 0x108},
++ {0x90128, 0xf},
++ {0x90129, 0x408},
++ {0x9012a, 0x169},
++ {0x9012b, 0xc},
++ {0x9012c, 0x0},
++ {0x9012d, 0x68},
++ {0x9012e, 0x9},
++ {0x9012f, 0x0},
++ {0x90130, 0x1a9},
++ {0x90131, 0x0},
++ {0x90132, 0x408},
++ {0x90133, 0x169},
++ {0x90134, 0x0},
++ {0x90135, 0x8080},
++ {0x90136, 0x108},
++ {0x90137, 0x8},
++ {0x90138, 0x7aa},
++ {0x90139, 0x6a},
++ {0x9013a, 0x0},
++ {0x9013b, 0x8568},
++ {0x9013c, 0x108},
++ {0x9013d, 0xb7},
++ {0x9013e, 0x790},
++ {0x9013f, 0x16a},
++ {0x90140, 0x1f},
++ {0x90141, 0x0},
++ {0x90142, 0x68},
++ {0x90143, 0x8},
++ {0x90144, 0x8558},
++ {0x90145, 0x168},
++ {0x90146, 0xf},
++ {0x90147, 0x408},
++ {0x90148, 0x169},
++ {0x90149, 0xd},
++ {0x9014a, 0x0},
++ {0x9014b, 0x68},
++ {0x9014c, 0x0},
++ {0x9014d, 0x408},
++ {0x9014e, 0x169},
++ {0x9014f, 0x0},
++ {0x90150, 0x8558},
++ {0x90151, 0x168},
++ {0x90152, 0x8},
++ {0x90153, 0x3c8},
++ {0x90154, 0x1a9},
++ {0x90155, 0x3},
++ {0x90156, 0x370},
++ {0x90157, 0x129},
++ {0x90158, 0x20},
++ {0x90159, 0x2aa},
++ {0x9015a, 0x9},
++ {0x9015b, 0x8},
++ {0x9015c, 0xe8},
++ {0x9015d, 0x109},
++ {0x9015e, 0x0},
++ {0x9015f, 0x8140},
++ {0x90160, 0x10c},
++ {0x90161, 0x10},
++ {0x90162, 0x8138},
++ {0x90163, 0x104},
++ {0x90164, 0x8},
++ {0x90165, 0x448},
++ {0x90166, 0x109},
++ {0x90167, 0xf},
++ {0x90168, 0x7c0},
++ {0x90169, 0x109},
++ {0x9016a, 0x0},
++ {0x9016b, 0xe8},
++ {0x9016c, 0x109},
++ {0x9016d, 0x47},
++ {0x9016e, 0x630},
++ {0x9016f, 0x109},
++ {0x90170, 0x8},
++ {0x90171, 0x618},
++ {0x90172, 0x109},
++ {0x90173, 0x8},
++ {0x90174, 0xe0},
++ {0x90175, 0x109},
++ {0x90176, 0x0},
++ {0x90177, 0x7c8},
++ {0x90178, 0x109},
++ {0x90179, 0x8},
++ {0x9017a, 0x8140},
++ {0x9017b, 0x10c},
++ {0x9017c, 0x0},
++ {0x9017d, 0x478},
++ {0x9017e, 0x109},
++ {0x9017f, 0x0},
++ {0x90180, 0x1},
++ {0x90181, 0x8},
++ {0x90182, 0x8},
++ {0x90183, 0x4},
++ {0x90184, 0x0},
++ {0x90006, 0x8},
++ {0x90007, 0x7c8},
++ {0x90008, 0x109},
++ {0x90009, 0x0},
++ {0x9000a, 0x400},
++ {0x9000b, 0x106},
++ {0xd00e7, 0x400},
++ {0x90017, 0x0},
++ {0x9001f, 0x2b},
++ {0x90026, 0x69},
++ {0x400d0, 0x0},
++ {0x400d1, 0x101},
++ {0x400d2, 0x105},
++ {0x400d3, 0x107},
++ {0x400d4, 0x10f},
++ {0x400d5, 0x202},
++ {0x400d6, 0x20a},
++ {0x400d7, 0x20b},
++ {0x2003a, 0x2},
++ {0x200be, 0x3},
++ {0x2000b, 0x41a},
++ {0x2000c, 0xe9},
++ {0x2000d, 0x91c},
++ {0x2000e, 0x2c},
++ {0x12000b, 0x20d},
++ {0x12000c, 0x74},
++ {0x12000d, 0x48e},
++ {0x12000e, 0x2c},
++ {0x22000b, 0xb0},
++ {0x22000c, 0x27},
++ {0x22000d, 0x186},
++ {0x22000e, 0x10},
++ {0x9000c, 0x0},
++ {0x9000d, 0x173},
++ {0x9000e, 0x60},
++ {0x9000f, 0x6110},
++ {0x90010, 0x2152},
++ {0x90011, 0xdfbd},
++ {0x90012, 0x2060},
++ {0x90013, 0x6152},
++ {0x20010, 0x5a},
++ {0x20011, 0x3},
++ {0x120010, 0x5a},
++ {0x120011, 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},
++ {0x400f1, 0xe},
++ {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},
++ {0x20089, 0x1},
++ {0x20088, 0x19},
++ {0xc0080, 0x0},
++ {0xd0000, 0x1},
++};
++
++static struct dram_fsp_msg ddr_dram_fsp_msg[] = {
++ {
++ /* P0 3733mts 1D */
++ .drate = 3733,
++ .fw_type = FW_1D_IMAGE,
++ .fsp_cfg = ddr_fsp0_cfg,
++ .fsp_cfg_num = ARRAY_SIZE(ddr_fsp0_cfg),
++ },
++ {
++ /* P1 1866mts 1D */
++ .drate = 1866,
++ .fw_type = FW_1D_IMAGE,
++ .fsp_cfg = ddr_fsp1_cfg,
++ .fsp_cfg_num = ARRAY_SIZE(ddr_fsp1_cfg),
++ },
++ {
++ /* P2 625mts 1D */
++ .drate = 625,
++ .fw_type = FW_1D_IMAGE,
++ .fsp_cfg = ddr_fsp2_cfg,
++ .fsp_cfg_num = ARRAY_SIZE(ddr_fsp2_cfg),
++ },
++ {
++ /* P0 3733mts 2D */
++ .drate = 3733,
++ .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 dram_timing_2GB = {
++ .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_trained_csr = ddr_ddrphy_trained_csr,
++ .ddrphy_trained_csr_num = ARRAY_SIZE(ddr_ddrphy_trained_csr),
++ .ddrphy_pie = ddr_phy_pie,
++ .ddrphy_pie_num = ARRAY_SIZE(ddr_phy_pie),
++ .fsp_table = { 3733, 1866, 625, },
++ .fsp_cfg = ddr_dram_fsp_cfg,
++ .fsp_cfg_num = ARRAY_SIZE(ddr_dram_fsp_cfg),
++};
+diff --git a/board/freescale/imx93_frdm/spl.c b/board/freescale/imx93_frdm/spl.c
+new file mode 100644
+index 00000000000..5defdb05a5b
+--- /dev/null
++++ b/board/freescale/imx93_frdm/spl.c
+@@ -0,0 +1,201 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright 2024-2025 NXP
++ */
++
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++#include
++
++extern struct dram_timing_info dram_timing_2GB;
++
++DECLARE_GLOBAL_DATA_PTR;
++
++#define SRC_DDRC_SW_CTRL (0x44461020)
++#define SRC_DDRPHY_SINGLE_RESET_SW_CTRL (0x44461424)
++
++int spl_board_boot_device(enum boot_device boot_dev_spl)
++{
++#ifdef CONFIG_SPL_BOOTROM_SUPPORT
++ return BOOT_DEVICE_BOOTROM;
++#else
++ switch (boot_dev_spl) {
++ case SD1_BOOT:
++ case MMC1_BOOT:
++ return BOOT_DEVICE_MMC1;
++ case SD2_BOOT:
++ case MMC2_BOOT:
++ return BOOT_DEVICE_MMC2;
++ default:
++ return BOOT_DEVICE_NONE;
++ }
++#endif
++}
++
++void spl_board_init(void)
++{
++ int ret;
++
++ ret = ele_start_rng();
++ if (ret)
++ printf("Fail to start RNG: %d\n", ret);
++
++ puts("Normal Boot\n");
++}
++
++void spl_dram_init(void)
++{
++ int ret;
++ struct dram_timing_info *ptiming = &dram_timing_2GB;
++
++ printf("DDR: %uMTS\n", ptiming->fsp_msg[0].drate);
++ ret = ddr_init(ptiming);
++ if (ret == 0)
++ printf("found DRAM %s matched\n", "2GB DRAM");
++ else
++ printf("DRAM init failed\n");
++}
++
++#if CONFIG_IS_ENABLED(DM_PMIC_PCA9450)
++int power_init_board(void)
++{
++ struct udevice *dev;
++ int ret;
++ unsigned int val = 0, buck_val;
++
++ ret = pmic_get("pmic@25", &dev);
++ if (ret != 0) {
++ puts("ERROR: Get PMIC PCA9451A failed!\n");
++ return ret;
++ }
++ puts("PMIC: PCA9451A\n");
++ /* BUCKxOUT_DVS0/1 control BUCK123 output */
++ pmic_reg_write(dev, PCA9450_BUCK123_DVS, 0x29);
++
++ /* enable DVS control through PMIC_STBY_REQ */
++ pmic_reg_write(dev, PCA9450_BUCK1CTRL, 0x59);
++
++ ret = pmic_reg_read(dev, PCA9450_PWR_CTRL);
++ if (ret < 0)
++ return ret;
++
++ val = ret;
++
++ if (is_voltage_mode(VOLT_LOW_DRIVE)) {
++ buck_val = 0x0c; /* 0.8v for Low drive mode */
++ printf("PMIC: Low Drive Voltage Mode\n");
++ } else if (is_voltage_mode(VOLT_NOMINAL_DRIVE)) {
++ buck_val = 0x10; /* 0.85v for Nominal drive mode */
++ printf("PMIC: Nominal Voltage Mode\n");
++ } else {
++ buck_val = 0x14; /* 0.9v for Over drive mode */
++ printf("PMIC: Over Drive Voltage Mode\n");
++ }
++
++ if (val & PCA9450_REG_PWRCTRL_TOFF_DEB) {
++ pmic_reg_write(dev, PCA9450_BUCK1OUT_DVS0, buck_val);
++ pmic_reg_write(dev, PCA9450_BUCK3OUT_DVS0, buck_val);
++ } else {
++ pmic_reg_write(dev, PCA9450_BUCK1OUT_DVS0, buck_val + 0x4);
++ pmic_reg_write(dev, PCA9450_BUCK3OUT_DVS0, buck_val + 0x4);
++ }
++
++ if (IS_ENABLED(CONFIG_IMX93_EVK_LPDDR4)) {
++ /* Set VDDQ to 1.1V from buck2 */
++ pmic_reg_write(dev, PCA9450_BUCK2OUT_DVS0, 0x28);
++ }
++
++ /* set standby voltage to 0.65v */
++ if (val & PCA9450_REG_PWRCTRL_TOFF_DEB)
++ pmic_reg_write(dev, PCA9450_BUCK1OUT_DVS1, 0x0);
++ else
++ pmic_reg_write(dev, PCA9450_BUCK1OUT_DVS1, 0x4);
++
++ /* I2C_LT_EN*/
++ pmic_reg_write(dev, 0xa, 0x3);
++ return 0;
++}
++#endif
++
++void board_init_f(ulong dummy)
++{
++ int ret;
++
++ /* Clear the BSS. */
++ memset(__bss_start, 0, __bss_end - __bss_start);
++
++ timer_init();
++
++ arch_cpu_init();
++
++ board_early_init_f();
++
++ spl_early_init();
++
++ preloader_console_init();
++
++ ret = imx9_probe_mu();
++ if (ret) {
++ printf("Fail to init ELE API\n");
++ } else {
++ printf("SOC: 0x%x\n", gd->arch.soc_rev);
++ printf("LC: 0x%x\n", gd->arch.lifecycle);
++ }
++
++ clock_init_late();
++
++ power_init_board();
++
++ if (!is_voltage_mode(VOLT_LOW_DRIVE))
++ set_arm_core_max_clk();
++
++ /* Init power of mix */
++ soc_power_init();
++
++ /* Setup TRDC for DDR access */
++ trdc_init();
++
++ /* DDR initialization */
++ spl_dram_init();
++
++ /* Put M33 into CPUWAIT for following kick */
++ ret = m33_prepare();
++ if (!ret)
++ printf("M33 prepare ok\n");
++
++ board_init_r(NULL, 0);
++}
++
++#ifdef CONFIG_ANDROID_SUPPORT
++int board_get_emmc_id(void)
++{
++ return 0;
++}
++#endif
+diff --git a/configs/imx93_11x11_frdm_defconfig b/configs/imx93_11x11_frdm_defconfig
+new file mode 100644
+index 00000000000..22128b628d5
+--- /dev/null
++++ b/configs/imx93_11x11_frdm_defconfig
+@@ -0,0 +1,158 @@
++CONFIG_ARM=y
++CONFIG_ARCH_IMX9=y
++CONFIG_TEXT_BASE=0x80200000
++CONFIG_SYS_MALLOC_LEN=0x2000000
++CONFIG_SYS_MALLOC_F_LEN=0x18000
++CONFIG_SPL_LIBCOMMON_SUPPORT=y
++CONFIG_SPL_LIBGENERIC_SUPPORT=y
++CONFIG_NR_DRAM_BANKS=2
++CONFIG_SF_DEFAULT_SPEED=40000000
++CONFIG_ENV_SIZE=0x4000
++CONFIG_ENV_OFFSET=0x700000
++CONFIG_IMX_CONFIG="arch/arm/mach-imx/imx9/imximage.cfg"
++CONFIG_DM_GPIO=y
++CONFIG_DEFAULT_DEVICE_TREE="imx93-11x11-frdm"
++CONFIG_TARGET_IMX93_11X11_FRDM=y
++CONFIG_OF_LIBFDT_OVERLAY=y
++CONFIG_SYS_MONITOR_LEN=524288
++CONFIG_SPL_SERIAL=y
++CONFIG_SPL_DRIVERS_MISC=y
++CONFIG_SPL_STACK=0x20519dd0
++CONFIG_SPL_TEXT_BASE=0x2049A000
++CONFIG_SPL_HAS_BSS_LINKER_SECTION=y
++CONFIG_SPL_BSS_START_ADDR=0x2051a000
++CONFIG_SPL_BSS_MAX_SIZE=0x2000
++CONFIG_SYS_LOAD_ADDR=0x80400000
++CONFIG_SPL=y
++CONFIG_CMD_DEKBLOB=y
++CONFIG_SPL_IMX_ROMAPI_LOADADDR=0x88000000
++CONFIG_EFI_VAR_BUF_SIZE=139264
++CONFIG_ANDROID_BOOT_IMAGE=y
++CONFIG_FIT=y
++CONFIG_FIT_SIGNATURE=y
++CONFIG_LEGACY_IMAGE_FORMAT=y
++CONFIG_DISTRO_DEFAULTS=y
++CONFIG_OF_SYSTEM_SETUP=y
++CONFIG_BOOTCOMMAND=""
++CONFIG_DEFAULT_FDT_FILE="imx93-11x11-frdm.dtb"
++CONFIG_SYS_CBSIZE=2048
++CONFIG_SYS_PBSIZE=2074
++CONFIG_CONSOLE_MUX=y
++CONFIG_SYS_DEVICE_NULLDEV=y
++CONFIG_ARCH_MISC_INIT=y
++CONFIG_BOARD_EARLY_INIT_F=y
++CONFIG_BOARD_LATE_INIT=y
++CONFIG_SPL_MAX_SIZE=0x26000
++CONFIG_SPL_BOARD_INIT=y
++CONFIG_SPL_BOOTROM_SUPPORT=y
++CONFIG_SPL_LOAD_IMX_CONTAINER=y
++CONFIG_IMX_CONTAINER_CFG="arch/arm/mach-imx/imx9/container.cfg"
++# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set
++CONFIG_SPL_HAVE_INIT_STACK=y
++CONFIG_SPL_SYS_MALLOC=y
++CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y
++CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x83200000
++CONFIG_SPL_SYS_MALLOC_SIZE=0x80000
++CONFIG_SPL_SYS_MMCSD_RAW_MODE=y
++CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR=0x1040
++CONFIG_SPL_I2C=y
++CONFIG_SPL_POWER=y
++CONFIG_SPL_WATCHDOG=y
++CONFIG_CMD_ERASEENV=y
++CONFIG_CMD_NVEDIT_EFI=y
++CONFIG_CRC32_VERIFY=y
++CONFIG_CMD_CLK=y
++CONFIG_CMD_DFU=y
++CONFIG_CMD_FUSE=y
++CONFIG_CMD_GPIO=y
++CONFIG_CMD_GPT=y
++CONFIG_CMD_I2C=y
++CONFIG_CMD_MMC=y
++CONFIG_CMD_POWEROFF=y
++CONFIG_CMD_USB=y
++CONFIG_CMD_USB_MASS_STORAGE=y
++CONFIG_CMD_SNTP=y
++CONFIG_CMD_CACHE=y
++CONFIG_CMD_EFIDEBUG=y
++CONFIG_CMD_RTC=y
++CONFIG_CMD_REGULATOR=y
++CONFIG_CMD_HASH=y
++CONFIG_CMD_EXT4_WRITE=y
++CONFIG_OF_CONTROL=y
++CONFIG_SPL_OF_CONTROL=y
++CONFIG_ENV_OVERWRITE=y
++CONFIG_ENV_IS_IN_MMC=y
++CONFIG_SYS_RELOC_GD_ENV_ADDR=y
++CONFIG_SYS_MMC_ENV_DEV=1
++CONFIG_USE_ETHPRIME=y
++CONFIG_ETHPRIME="eth1"
++CONFIG_NET_RANDOM_ETHADDR=y
++CONFIG_SPL_DM=y
++CONFIG_REGMAP=y
++CONFIG_SYSCON=y
++CONFIG_ADC=y
++CONFIG_ADC_IMX93=y
++CONFIG_SPL_CLK_IMX93=y
++CONFIG_CLK_IMX93=y
++CONFIG_IMX_RGPIO2P=y
++CONFIG_DM_PCA953X=y
++CONFIG_ADP5585_GPIO=y
++CONFIG_DM_I2C=y
++CONFIG_SYS_I2C_IMX_LPI2C=y
++CONFIG_SUPPORT_EMMC_RPMB=y
++CONFIG_SUPPORT_EMMC_BOOT=y
++CONFIG_MMC_IO_VOLTAGE=y
++CONFIG_MMC_UHS_SUPPORT=y
++CONFIG_MMC_HS400_ES_SUPPORT=y
++CONFIG_MMC_HS400_SUPPORT=y
++CONFIG_FSL_USDHC=y
++CONFIG_MTD=y
++CONFIG_DM_SPI_FLASH=y
++CONFIG_SPI_FLASH_STMICRO=y
++CONFIG_PHY_MOTORCOMM=y
++CONFIG_PHY_REALTEK=y
++CONFIG_DM_ETH_PHY=y
++CONFIG_PHY_GIGE=y
++CONFIG_DWC_ETH_QOS=y
++CONFIG_DWC_ETH_QOS_IMX=y
++CONFIG_FEC_MXC=y
++CONFIG_MII=y
++CONFIG_MIPI_DPHY_HELPERS=y
++CONFIG_PINCTRL=y
++CONFIG_SPL_PINCTRL=y
++CONFIG_PINCTRL_IMX93=y
++CONFIG_POWER_DOMAIN=y
++CONFIG_DM_PMIC=y
++CONFIG_DM_PMIC_PCA9450=y
++CONFIG_SPL_DM_PMIC_PCA9450=y
++CONFIG_DM_REGULATOR=y
++CONFIG_DM_REGULATOR_PCA9450=y
++CONFIG_DM_REGULATOR_FIXED=y
++CONFIG_DM_REGULATOR_GPIO=y
++CONFIG_DM_RTC=y
++CONFIG_RTC_EMULATION=y
++CONFIG_DM_SERIAL=y
++CONFIG_FSL_LPUART=y
++CONFIG_SPI=y
++CONFIG_DM_SPI=y
++CONFIG_NXP_FSPI=y
++CONFIG_SYSRESET=y
++CONFIG_SPL_SYSRESET=y
++CONFIG_SYSRESET_CMD_POWEROFF=y
++CONFIG_SYSRESET_PSCI=y
++CONFIG_DM_THERMAL=y
++CONFIG_USB=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_HOST_ETHER=y
++CONFIG_USB_ETHER_ASIX=y
++CONFIG_USB_ETHER_RTL8152=y
++CONFIG_USB_GADGET=y
++CONFIG_USB_GADGET_MANUFACTURER="FSL"
++CONFIG_USB_GADGET_VENDOR_NUM=0x1fc9
++CONFIG_USB_GADGET_PRODUCT_NUM=0x0152
++CONFIG_CI_UDC=y
++CONFIG_USB_GADGET_DOWNLOAD=y
++CONFIG_ULP_WATCHDOG=y
++CONFIG_WDT=y
++CONFIG_SPL_RSA=y
++CONFIG_SHA384=y
+diff --git a/include/configs/imx93_frdm.h b/include/configs/imx93_frdm.h
+new file mode 100644
+index 00000000000..e1132c07c6b
+--- /dev/null
++++ b/include/configs/imx93_frdm.h
+@@ -0,0 +1,27 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright 2024-2025 NXP
++ */
++
++#ifndef __IMX93_FRDM_H
++#define __IMX93_FRDM_H
++
++#include
++#include
++#include
++
++#define CFG_SYS_UBOOT_BASE \
++ (QSPI0_AMBA_BASE + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR * 512)
++
++/* Link Definitions */
++#define CFG_SYS_INIT_RAM_ADDR 0x80000000
++#define CFG_SYS_INIT_RAM_SIZE 0x200000
++
++#define CFG_SYS_SDRAM_BASE 0x80000000
++#define PHYS_SDRAM 0x80000000
++#define PHYS_SDRAM_SIZE 0x80000000 /* 2GB DDR */
++
++/* Using ULP WDOG for reset */
++#define WDOG_BASE_ADDR WDG3_BASE_ADDR
++
++#endif
+\ No newline at end of file
+--
+2.43.0
+
diff --git a/lab-data/embedded-linux-imx93-frdm/buildroot/data/mpd.conf b/lab-data/embedded-linux-imx93-frdm/buildroot/data/mpd.conf
new file mode 100644
index 0000000000..063a083c45
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/buildroot/data/mpd.conf
@@ -0,0 +1,36 @@
+# MPD configuration
+
+# For ALSA output:
+audio_output {
+ type "alsa"
+ name "My ALSA Device"
+ mixer_type "software"
+}
+
+# Directory where the music is stored
+music_directory "/var/lib/mpd/music"
+
+# Directory where user-made playlists are stored (RW)
+playlist_directory "/var/lib/mpd/playlists"
+
+# Database file (RW)
+db_file "/var/lib/mpd/database"
+
+# Log file (RW)
+log_file "/var/log/mpd.log"
+
+# Process ID file (RW)
+pid_file "/var/run/mpd.pid"
+
+# State file (RW)
+state_file "/var/lib/mpd/state"
+
+# User id to run the daemon as
+#user "nobody"
+
+# TCP socket binding
+#bind_to_address "any"
+bind_to_address "localhost"
+
+# Unix socket to listen on
+bind_to_address "/var/lib/mpd/socket"
diff --git a/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/1-sample.ogg b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/1-sample.ogg
new file mode 100644
index 0000000000..bae2c390c0
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/1-sample.ogg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/2-arpent.ogg b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/2-arpent.ogg
new file mode 100644
index 0000000000..9e60cc81a2
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/2-arpent.ogg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/3-chronos.ogg b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/3-chronos.ogg
new file mode 100644
index 0000000000..fb02cff1de
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/3-chronos.ogg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/4-land-of-pirates.ogg b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/4-land-of-pirates.ogg
new file mode 100644
index 0000000000..321022477e
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/4-land-of-pirates.ogg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/5-ukulele-song.ogg b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/5-ukulele-song.ogg
new file mode 100644
index 0000000000..c536c4d41a
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/5-ukulele-song.ogg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/6-le-baguette.ogg b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/6-le-baguette.ogg
new file mode 100644
index 0000000000..64b171397e
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/6-le-baguette.ogg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/7-fireworks.ogg b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/7-fireworks.ogg
new file mode 100644
index 0000000000..9fc7849844
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/7-fireworks.ogg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/README.txt b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/README.txt
new file mode 100644
index 0000000000..0d194b0eba
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/buildroot/data/music/README.txt
@@ -0,0 +1,3 @@
+With the exception of 1-sample.ogg file which is a short sample,
+music files originate from https://freepd.com/
+(Free Public Domain music)
diff --git a/lab-data/embedded-linux-imx93-frdm/hardware/data/nunchuk/Makefile b/lab-data/embedded-linux-imx93-frdm/hardware/data/nunchuk/Makefile
new file mode 100644
index 0000000000..a857397e12
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/hardware/data/nunchuk/Makefile
@@ -0,0 +1 @@
+obj-m := nunchuk.o
diff --git a/lab-data/embedded-linux-imx93-frdm/hardware/data/nunchuk/nunchuk.c b/lab-data/embedded-linux-imx93-frdm/hardware/data/nunchuk/nunchuk.c
new file mode 100644
index 0000000000..e20f2c7c25
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/hardware/data/nunchuk/nunchuk.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Available on SOLUTION_URL */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* Per device structure */
+struct nunchuk_dev {
+ struct i2c_client *i2c_client;
+};
+
+static int nunchuk_read_registers(struct i2c_client *client, u8 *recv)
+{
+ u8 buf[1];
+ int ret;
+
+ /* Ask the device to get ready for a read */
+ usleep_range(10000, 20000);
+
+ buf[0] = 0x00;
+ ret = i2c_master_send(client, buf, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "i2c send failed (%d)\n", ret);
+ return ret;
+ }
+
+ usleep_range(10000, 20000);
+
+ /* Now read registers */
+ ret = i2c_master_recv(client, recv, 6);
+ if (ret < 0) {
+ dev_err(&client->dev, "i2c recv failed (%d)\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void nunchuk_poll(struct input_dev *input)
+{
+ u8 recv[6];
+ int zpressed, cpressed, bx, by;
+
+ /* Retrieve the physical i2c device */
+ struct nunchuk_dev *nunchuk = input_get_drvdata(input);
+ struct i2c_client *client = nunchuk->i2c_client;
+
+ /* Get the state of the device registers */
+ if (nunchuk_read_registers(client, recv) < 0)
+ return;
+
+ zpressed = (recv[5] & BIT(0)) ? 0 : 1;
+ cpressed = (recv[5] & BIT(1)) ? 0 : 1;
+ bx = recv[0];
+ by = recv[1];
+
+ /* Send events to the INPUT subsystem */
+ input_report_key(input, BTN_Z, zpressed);
+ input_report_key(input, BTN_C, cpressed);
+
+ input_report_abs(input, ABS_X, bx);
+ input_report_abs(input, ABS_Y, by);
+
+ input_sync(input);
+}
+
+static int nunchuk_probe(struct i2c_client *client)
+{
+ struct nunchuk_dev *nunchuk;
+ struct input_dev *input;
+ u8 buf[2];
+ int ret;
+
+ /* Allocate per device structure */
+ nunchuk = devm_kzalloc(&client->dev, sizeof(*nunchuk), GFP_KERNEL);
+ if (!nunchuk)
+ /* No message necessary here, already issued by allocation functions */
+ return -ENOMEM;
+
+ /* Initialize device */
+ buf[0] = 0xf0;
+ buf[1] = 0x55;
+
+ ret = i2c_master_send(client, buf, 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "i2c send failed (%d)\n", ret);
+ return ret;
+ }
+
+ udelay(1000);
+
+ buf[0] = 0xfb;
+ buf[1] = 0x00;
+
+ ret = i2c_master_send(client, buf, 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "i2c send failed (%d)\n", ret);
+ return ret;
+ }
+
+ /* Allocate input device */
+ input = devm_input_allocate_device(&client->dev);
+ if (!input)
+ return -ENOMEM;
+
+ /*
+ * Implement pointers from logical to physical. Here, no need for
+ * physical to logical pointers as unregistering and freeing the
+ * polled_input device will be automatic.
+ */
+ nunchuk->i2c_client = client;
+ input_set_drvdata(input, nunchuk);
+
+ /* Configure input device */
+ input->name = "Wii Nunchuk";
+ input->id.bustype = BUS_I2C;
+
+ set_bit(EV_KEY, input->evbit);
+ set_bit(BTN_C, input->keybit);
+ set_bit(BTN_Z, input->keybit);
+
+ set_bit(EV_ABS, input->evbit);
+ set_bit(ABS_X, input->absbit);
+ set_bit(ABS_Y, input->absbit);
+ input_set_abs_params(input, ABS_X, 30, 220, 4, 8);
+ input_set_abs_params(input, ABS_Y, 40, 200, 4, 8);
+
+ /* Classic buttons */
+ set_bit(BTN_TL, input->keybit);
+ set_bit(BTN_SELECT, input->keybit);
+ set_bit(BTN_MODE, input->keybit);
+ set_bit(BTN_START, input->keybit);
+ set_bit(BTN_TR, input->keybit);
+ set_bit(BTN_TL2, input->keybit);
+ set_bit(BTN_B, input->keybit);
+ set_bit(BTN_Y, input->keybit);
+ set_bit(BTN_A, input->keybit);
+ set_bit(BTN_X, input->keybit);
+ set_bit(BTN_TR2, input->keybit);
+
+ /* Register and configure polling function */
+ ret = input_setup_polling(input, nunchuk_poll);
+ if (ret) {
+ dev_err(&client->dev, "Failed to set polling function (%d)\n",
+ ret);
+ return ret;
+ }
+
+ input_set_poll_interval(input, 50);
+
+ /* Register the input device when everything is ready */
+ ret = input_register_device(input);
+ if (ret) {
+ dev_err(&client->dev, "Cannot register input device (%d)\n",
+ ret);
+ return ret;
+ }
+
+
+ pr_info("Nunchuk device probed successfully\n");
+ return 0;
+}
+
+#if KERNEL_VERSION(5, 16, 0) <= LINUX_VERSION_CODE
+static void nunchuk_remove(struct i2c_client *client)
+#else
+static int nunchuk_remove(struct i2c_client *client)
+#endif
+{
+ /*
+ * Nothing to do here, as the polled_input device is automatically
+ * unregistered and freed thanks to the use of
+ * devm_input_allocate_device.
+ */
+
+ pr_info("Nunchuk device removed successfully\n");
+ #if KERNEL_VERSION(5, 16, 0) > LINUX_VERSION_CODE
+ return 0;
+ #endif
+}
+
+/* Specification of supported Device Tree devices */
+static const struct of_device_id nunchuk_dt_match[] = {
+ { .compatible = "nintendo,nunchuk" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, nunchuk_dt_match);
+
+/* Driver declaration */
+static struct i2c_driver nunchuk_driver = {
+ .driver = {
+ .name = "nunchuk",
+ .of_match_table = nunchuk_dt_match,
+ },
+ .probe = nunchuk_probe,
+ .remove = nunchuk_remove,
+};
+module_i2c_driver(nunchuk_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/lab-data/embedded-linux-imx93-frdm/kernel/data/0001-linux-imx93-frdm.patch b/lab-data/embedded-linux-imx93-frdm/kernel/data/0001-linux-imx93-frdm.patch
new file mode 100644
index 0000000000..50f19d20b9
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/kernel/data/0001-linux-imx93-frdm.patch
@@ -0,0 +1,594 @@
+From 476863b5d172b9466e4158be055d6e352df170ae Mon Sep 17 00:00:00 2001
+From: Antoine Picard
+Date: Thu, 24 Jul 2025 16:06:23 +0200
+Subject: [PATCH] linux-imx93-frdm
+
+Signed-off-by: Antoine Picard
+---
+ .../boot/dts/freescale/imx93-11x11-frdm.dts | 574 ++++++++++++++++++
+ 1 file changed, 574 insertions(+)
+ create mode 100644 arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
+
+diff --git a/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts b/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
+new file mode 100644
+index 000000000000..5236ce3b3f89
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts
+@@ -0,0 +1,574 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Copyright 2024-2025 NXP
++ */
++
++/dts-v1/;
++
++#include
++#include "imx93.dtsi"
++
++/ {
++ model = "NXP i.MX93 11X11 FRDM board";
++ compatible = "fsl,imx93-11x11-frdm", "fsl,imx93";
++
++ aliases {
++ rtc0 = &pcf2131;
++ };
++
++ chosen {
++ bootargs = "console=ttyLP0,115200";
++ stdout-path = &lpuart1;
++ };
++
++ reserved-memory {
++ #address-cells = <2>;
++ #size-cells = <2>;
++ ranges;
++
++ linux,cma {
++ compatible = "shared-dma-pool";
++ reusable;
++ alloc-ranges = <0 0x80000000 0 0x40000000>;
++ size = <0 0x10000000>;
++ linux,cma-default;
++ };
++ };
++
++ reg_can2_stby: regulator-can2-stby {
++ compatible = "regulator-fixed";
++ regulator-name = "can2-stby";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ gpio = <&pcal6524 23 GPIO_ACTIVE_LOW>;
++ enable-active-high;
++ };
++
++ reg_vref_1v8: regulator-adc-vref {
++ compatible = "regulator-fixed";
++ regulator-name = "vref_1v8";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <1800000>;
++ };
++
++ reg_usdhc2_vmmc: regulator-usdhc2 {
++ compatible = "regulator-fixed";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
++ regulator-name = "VSD_3V3";
++ regulator-min-microvolt = <3300000>;
++ regulator-max-microvolt = <3300000>;
++ gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
++ off-on-delay-us = <12000>;
++ enable-active-high;
++ };
++
++ reg_vdd_12v: regulator-vdd-12v {
++ compatible = "regulator-fixed";
++ regulator-name = "reg_vdd_12v";
++ regulator-min-microvolt = <12000000>;
++ regulator-max-microvolt = <12000000>;
++ gpio = <&pcal6524 14 GPIO_ACTIVE_HIGH>;
++ enable-active-high;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ led_red {
++ label = "led-red";
++ gpios = <&gpio2 13 GPIO_ACTIVE_HIGH>;
++ default-state = "on";
++ };
++
++ led_green {
++ label = "led-green";
++ gpios = <&gpio2 4 GPIO_ACTIVE_HIGH>;
++ default-state = "on";
++ };
++
++ led_blue {
++ label = "led-blue";
++ gpios = <&gpio2 12 GPIO_ACTIVE_HIGH>;
++ default-state = "on";
++ };
++ };
++};
++
++
++&adc1 {
++ vref-supply = <®_vref_1v8>;
++ status = "okay";
++};
++
++&mu1 {
++ status = "okay";
++};
++
++&mu2 {
++ status = "okay";
++};
++
++&eqos {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_eqos>;
++ phy-mode = "rgmii-id";
++ phy-handle = <ðphy1>;
++ status = "okay";
++
++ mdio {
++ compatible = "snps,dwmac-mdio";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <5000000>;
++
++ ethphy1: ethernet-phy@1 {
++ reg = <1>;
++ eee-broken-1000t;
++
++ reset-gpios = <&pcal6524 15 GPIO_ACTIVE_LOW>;
++ reset-assert-us = <15000>;
++ reset-deassert-us = <100000>;
++ };
++ };
++};
++
++&fec {
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_fec>;
++ phy-mode = "rgmii-id";
++ phy-handle = <ðphy2>;
++ fsl,magic-packet;
++ status = "okay";
++
++ mdio {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <5000000>;
++
++ ethphy2: ethernet-phy@2 {
++ reg = <2>;
++ eee-broken-1000t;
++ };
++ };
++};
++
++&lpi2c1 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <400000>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&pinctrl_lpi2c1>;
++ pinctrl-1 = <&pinctrl_lpi2c1>;
++ status = "okay";
++};
++
++&lpi2c2 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <400000>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&pinctrl_lpi2c2>;
++ pinctrl-1 = <&pinctrl_lpi2c2>;
++ status = "okay";
++
++ pmic@25 {
++ compatible = "nxp,pca9451a";
++ reg = <0x25>;
++ interrupt-parent = <&pcal6524>;
++ interrupts = <11 IRQ_TYPE_EDGE_FALLING>;
++
++ regulators {
++ buck1: BUCK1 {
++ regulator-name = "BUCK1";
++ regulator-min-microvolt = <650000>;
++ regulator-max-microvolt = <2237500>;
++ regulator-boot-on;
++ regulator-always-on;
++ regulator-ramp-delay = <3125>;
++ };
++
++ buck2: BUCK2 {
++ regulator-name = "BUCK2";
++ regulator-min-microvolt = <600000>;
++ regulator-max-microvolt = <2187500>;
++ regulator-boot-on;
++ regulator-always-on;
++ regulator-ramp-delay = <3125>;
++ };
++
++ buck4: BUCK4{
++ regulator-name = "BUCK4";
++ regulator-min-microvolt = <600000>;
++ regulator-max-microvolt = <3400000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ buck5: BUCK5{
++ regulator-name = "BUCK5";
++ regulator-min-microvolt = <600000>;
++ regulator-max-microvolt = <3400000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ buck6: BUCK6 {
++ regulator-name = "BUCK6";
++ regulator-min-microvolt = <600000>;
++ regulator-max-microvolt = <3400000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ ldo1: LDO1 {
++ regulator-name = "LDO1";
++ regulator-min-microvolt = <1600000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ ldo4: LDO4 {
++ regulator-name = "LDO4";
++ regulator-min-microvolt = <800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++
++ ldo5: LDO5 {
++ regulator-name = "LDO5";
++ regulator-min-microvolt = <1800000>;
++ regulator-max-microvolt = <3300000>;
++ regulator-boot-on;
++ regulator-always-on;
++ };
++ };
++ };
++
++ pcal6524: gpio@22 {
++ compatible = "nxp,pcal6524";
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_pcal6524>;
++ reg = <0x22>;
++ gpio-controller;
++ #gpio-cells = <2>;
++ interrupt-controller;
++ #interrupt-cells = <2>;
++ interrupt-parent = <&gpio3>;
++ interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
++ };
++ eeprom: eeprom@50 {
++ compatible = "atmel,24c256";
++ reg = <0x50>;
++ pagesize = <64>;
++ };
++
++};
++
++&lpi2c3 {
++ #address-cells = <1>;
++ #size-cells = <0>;
++ clock-frequency = <400000>;
++ pinctrl-names = "default", "sleep";
++ pinctrl-0 = <&pinctrl_lpi2c3>;
++ pinctrl-1 = <&pinctrl_lpi2c3>;
++ status = "okay";
++
++ pcf2131: rtc@53 {
++ compatible = "nxp,pcf2131";
++ reg = <0x53>;
++ interrupt-parent = <&pcal6524>;
++ interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
++ status = "okay";
++ };
++
++ ptn5110: tcpc@50 {
++ compatible = "nxp,ptn5110", "tcpci";
++ reg = <0x50>;
++ interrupt-parent = <&gpio3>;
++ interrupts = <27 IRQ_TYPE_EDGE_FALLING>;
++ status = "okay";
++
++ port {
++ typec1_dr_sw: endpoint {
++ remote-endpoint = <&usb1_drd_sw>;
++ };
++ };
++
++ typec1_con: connector {
++ compatible = "usb-c-connector";
++ label = "USB-C";
++ power-role = "dual";
++ data-role = "dual";
++ try-power-role = "sink";
++ source-pdos = ;
++ sink-pdos = ;
++ op-sink-microwatt = <15000000>;
++ self-powered;
++ };
++ };
++
++};
++
++&lpuart1 { /* console */
++ pinctrl-names = "default";
++ pinctrl-0 = <&pinctrl_uart1>;
++ status = "okay";
++};
++
++&media_blk_ctrl {
++ status = "okay";
++};
++
++&usbotg1 {
++ dr_mode = "otg";
++ hnp-disable;
++ srp-disable;
++ adp-disable;
++ usb-role-switch;
++ disable-over-current;
++ samsung,picophy-pre-emp-curr-control = <3>;
++ samsung,picophy-dc-vol-level-adjust = <7>;
++ status = "okay";
++
++ port {
++ usb1_drd_sw: endpoint {
++ remote-endpoint = <&typec1_dr_sw>;
++ };
++ };
++};
++
++&usbotg2 {
++ dr_mode = "host";
++ disable-over-current;
++ samsung,picophy-pre-emp-curr-control = <3>;
++ samsung,picophy-dc-vol-level-adjust = <7>;
++ status = "okay";
++};
++
++&usdhc1 {
++ pinctrl-names = "default", "state_100mhz", "state_200mhz";
++ pinctrl-0 = <&pinctrl_usdhc1>;
++ pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
++ pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
++ bus-width = <8>;
++ non-removable;
++ status = "okay";
++};
++
++&usdhc2 {
++ pinctrl-names = "default", "state_100mhz", "state_200mhz";
++ pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
++ pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
++ pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
++ cd-gpios = <&gpio3 00 GPIO_ACTIVE_LOW>;
++ vmmc-supply = <®_usdhc2_vmmc>;
++ bus-width = <4>;
++ status = "okay";
++ no-sdio;
++ no-mmc;
++};
++
++&usdhc3 {
++ status = "disabled";
++};
++
++&wdog3 {
++ status = "okay";
++};
++
++&iomuxc {
++ pinctrl_eqos: eqosgrp {
++ fsl,pins = <
++ MX93_PAD_ENET1_MDC__ENET_QOS_MDC 0x57e
++ MX93_PAD_ENET1_MDIO__ENET_QOS_MDIO 0x57e
++ MX93_PAD_ENET1_RD0__ENET_QOS_RGMII_RD0 0x57e
++ MX93_PAD_ENET1_RD1__ENET_QOS_RGMII_RD1 0x57e
++ MX93_PAD_ENET1_RD2__ENET_QOS_RGMII_RD2 0x57e
++ MX93_PAD_ENET1_RD3__ENET_QOS_RGMII_RD3 0x57e
++ MX93_PAD_ENET1_RXC__CCM_ENET_QOS_CLOCK_GENERATE_RX_CLK 0x5fe
++ MX93_PAD_ENET1_RX_CTL__ENET_QOS_RGMII_RX_CTL 0x57e
++ MX93_PAD_ENET1_TD0__ENET_QOS_RGMII_TD0 0x57e
++ MX93_PAD_ENET1_TD1__ENET_QOS_RGMII_TD1 0x57e
++ MX93_PAD_ENET1_TD2__ENET_QOS_RGMII_TD2 0x57e
++ MX93_PAD_ENET1_TD3__ENET_QOS_RGMII_TD3 0x57e
++ MX93_PAD_ENET1_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK 0x5fe
++ MX93_PAD_ENET1_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x57e
++ >;
++ };
++
++ pinctrl_flexspi: flexspigrp {
++ fsl,pins = <
++ MX93_PAD_SD3_CMD__FLEXSPI1_A_SS0_B 0x3fe
++ MX93_PAD_SD3_CLK__FLEXSPI1_A_SCLK 0x3fe
++ MX93_PAD_SD3_DATA0__FLEXSPI1_A_DATA00 0x3fe
++ MX93_PAD_SD3_DATA1__FLEXSPI1_A_DATA01 0x3fe
++ MX93_PAD_SD3_DATA2__FLEXSPI1_A_DATA02 0x3fe
++ MX93_PAD_SD3_DATA3__FLEXSPI1_A_DATA03 0x3fe
++ >;
++ };
++
++ pinctrl_fec: fecgrp {
++ fsl,pins = <
++ MX93_PAD_ENET2_MDC__ENET1_MDC 0x57e
++ MX93_PAD_ENET2_MDIO__ENET1_MDIO 0x57e
++ MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0 0x57e
++ MX93_PAD_ENET2_RD1__ENET1_RGMII_RD1 0x57e
++ MX93_PAD_ENET2_RD2__ENET1_RGMII_RD2 0x57e
++ MX93_PAD_ENET2_RD3__ENET1_RGMII_RD3 0x57e
++ MX93_PAD_ENET2_RXC__ENET1_RGMII_RXC 0x5fe
++ MX93_PAD_ENET2_RX_CTL__ENET1_RGMII_RX_CTL 0x57e
++ MX93_PAD_ENET2_TD0__ENET1_RGMII_TD0 0x57e
++ MX93_PAD_ENET2_TD1__ENET1_RGMII_TD1 0x57e
++ MX93_PAD_ENET2_TD2__ENET1_RGMII_TD2 0x57e
++ MX93_PAD_ENET2_TD3__ENET1_RGMII_TD3 0x57e
++ MX93_PAD_ENET2_TXC__ENET1_RGMII_TXC 0x5fe
++ MX93_PAD_ENET2_TX_CTL__ENET1_RGMII_TX_CTL 0x57e
++ >;
++ };
++
++ pinctrl_lpi2c1: lpi2c1grp {
++ fsl,pins = <
++ MX93_PAD_I2C1_SCL__LPI2C1_SCL 0x40000b9e
++ MX93_PAD_I2C1_SDA__LPI2C1_SDA 0x40000b9e
++ >;
++ };
++
++ pinctrl_lpi2c2: lpi2c2grp {
++ fsl,pins = <
++ MX93_PAD_I2C2_SCL__LPI2C2_SCL 0x40000b9e
++ MX93_PAD_I2C2_SDA__LPI2C2_SDA 0x40000b9e
++ >;
++ };
++
++ pinctrl_lpi2c3: lpi2c3grp {
++ fsl,pins = <
++ MX93_PAD_GPIO_IO28__LPI2C3_SDA 0x40000b9e
++ MX93_PAD_GPIO_IO29__LPI2C3_SCL 0x40000b9e
++ >;
++ };
++
++ pinctrl_pcal6524: pcal6524grp {
++ fsl,pins = <
++ MX93_PAD_CCM_CLKO2__GPIO3_IO27 0x31e
++ >;
++ };
++
++ pinctrl_uart1: uart1grp {
++ fsl,pins = <
++ MX93_PAD_UART1_RXD__LPUART1_RX 0x31e
++ MX93_PAD_UART1_TXD__LPUART1_TX 0x31e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc1: usdhc1grp {
++ fsl,pins = <
++ MX93_PAD_SD1_CLK__USDHC1_CLK 0x1582
++ MX93_PAD_SD1_CMD__USDHC1_CMD 0x40001382
++ MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x40001382
++ MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x40001382
++ MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x40001382
++ MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x40001382
++ MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x40001382
++ MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x40001382
++ MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x40001382
++ MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x40001382
++ MX93_PAD_SD1_STROBE__USDHC1_STROBE 0x1582
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc1_100mhz: usdhc1-100mhzgrp {
++ fsl,pins = <
++ MX93_PAD_SD1_CLK__USDHC1_CLK 0x158e
++ MX93_PAD_SD1_CMD__USDHC1_CMD 0x4000138e
++ MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x4000138e
++ MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x4000138e
++ MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x4000138e
++ MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x4000138e
++ MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x4000138e
++ MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x4000138e
++ MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x4000138e
++ MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x4000138e
++ MX93_PAD_SD1_STROBE__USDHC1_STROBE 0x158e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc1_200mhz: usdhc1-200mhzgrp {
++ fsl,pins = <
++ MX93_PAD_SD1_CLK__USDHC1_CLK 0x15fe
++ MX93_PAD_SD1_CMD__USDHC1_CMD 0x400013fe
++ MX93_PAD_SD1_DATA0__USDHC1_DATA0 0x400013fe
++ MX93_PAD_SD1_DATA1__USDHC1_DATA1 0x400013fe
++ MX93_PAD_SD1_DATA2__USDHC1_DATA2 0x400013fe
++ MX93_PAD_SD1_DATA3__USDHC1_DATA3 0x400013fe
++ MX93_PAD_SD1_DATA4__USDHC1_DATA4 0x400013fe
++ MX93_PAD_SD1_DATA5__USDHC1_DATA5 0x400013fe
++ MX93_PAD_SD1_DATA6__USDHC1_DATA6 0x400013fe
++ MX93_PAD_SD1_DATA7__USDHC1_DATA7 0x400013fe
++ MX93_PAD_SD1_STROBE__USDHC1_STROBE 0x15fe
++ >;
++ };
++
++ pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
++ fsl,pins = <
++ MX93_PAD_SD2_RESET_B__GPIO3_IO07 0x31e
++ >;
++ };
++
++ pinctrl_usdhc2_gpio: usdhc2gpiogrp {
++ fsl,pins = <
++ MX93_PAD_SD2_CD_B__GPIO3_IO00 0x31e
++ >;
++ };
++
++ pinctrl_usdhc2_gpio_sleep: usdhc2-gpio-grp {
++ fsl,pins = <
++ MX93_PAD_SD2_CD_B__GPIO3_IO00 0x51e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc2: usdhc2grp {
++ fsl,pins = <
++ MX93_PAD_SD2_CLK__USDHC2_CLK 0x1582
++ MX93_PAD_SD2_CMD__USDHC2_CMD 0x40001382
++ MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x40001382
++ MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x40001382
++ MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x40001382
++ MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x40001382
++ MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
++ fsl,pins = <
++ MX93_PAD_SD2_CLK__USDHC2_CLK 0x158e
++ MX93_PAD_SD2_CMD__USDHC2_CMD 0x4000138e
++ MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x4000138e
++ MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x4000138e
++ MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x4000138e
++ MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x4000138e
++ MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
++ >;
++ };
++
++ /* need to config the SION for data and cmd pad, refer to ERR052021 */
++ pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
++ fsl,pins = <
++ MX93_PAD_SD2_CLK__USDHC2_CLK 0x15fe
++ MX93_PAD_SD2_CMD__USDHC2_CMD 0x400013fe
++ MX93_PAD_SD2_DATA0__USDHC2_DATA0 0x400013fe
++ MX93_PAD_SD2_DATA1__USDHC2_DATA1 0x400013fe
++ MX93_PAD_SD2_DATA2__USDHC2_DATA2 0x400013fe
++ MX93_PAD_SD2_DATA3__USDHC2_DATA3 0x400013fe
++ MX93_PAD_SD2_VSELECT__USDHC2_VSELECT 0x51e
++ >;
++ };
++};
+--
+2.43.0
+
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/0001-menuconfig-GCC-failing-saying-ncurses-is-not-found.patch b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/0001-menuconfig-GCC-failing-saying-ncurses-is-not-found.patch
new file mode 100644
index 0000000000..aaf4753387
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/0001-menuconfig-GCC-failing-saying-ncurses-is-not-found.patch
@@ -0,0 +1,34 @@
+From 5b15eb054e3eb03c3e9214650490868d13966c90 Mon Sep 17 00:00:00 2001
+From: Nop
+Date: Sun, 21 Jul 2024 14:10:52 +0200
+Subject: [PATCH] menuconfig: GCC failing saying ncurses is not found
+
+Newer GCC increased diagnostics levels resulting in considering the test
+code to be invalid. The resulting message was misleading, saying that
+ncurses is not found, while it is actually found because GCC output is
+redirected to /dev/null.
+
+Signed-off-by: ctxnop
+---
+ scripts/kconfig/lxdialog/check-lxdialog.sh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh
+index 5075ebf2d..c644d1d48 100755
+--- a/scripts/kconfig/lxdialog/check-lxdialog.sh
++++ b/scripts/kconfig/lxdialog/check-lxdialog.sh
+@@ -45,9 +45,9 @@ trap "rm -f $tmp" 0 1 2 3 15
+
+ # Check if we can link to ncurses
+ check() {
+- $cc -x c - -o $tmp 2>/dev/null <<'EOF'
++ $cc -x c - -o $tmp <<'EOF'
+ #include CURSES_LOC
+-main() {}
++int main() { return 0; }
+ EOF
+ if [ $? != 0 ]; then
+ echo " *** Unable to find the ncurses libraries or the" 1>&2
+--
+2.47.0
+
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/busybox-1.37.config b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/busybox-1.37.config
new file mode 100644
index 0000000000..eb3cfc76a0
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/busybox-1.37.config
@@ -0,0 +1,1215 @@
+#
+# Automatically generated make config: don't edit
+# Busybox version: 1.37.0
+# Fri Jun 27 16:20:16 2025
+#
+CONFIG_HAVE_DOT_CONFIG=y
+
+#
+# Settings
+#
+# CONFIG_DESKTOP is not set
+# CONFIG_EXTRA_COMPAT is not set
+# CONFIG_FEDORA_COMPAT is not set
+# CONFIG_INCLUDE_SUSv2 is not set
+CONFIG_LONG_OPTS=y
+CONFIG_SHOW_USAGE=y
+CONFIG_FEATURE_VERBOSE_USAGE=y
+# CONFIG_FEATURE_COMPRESS_USAGE is not set
+CONFIG_LFS=y
+CONFIG_TIME64=y
+# CONFIG_PAM is not set
+# CONFIG_FEATURE_DEVPTS is not set
+# CONFIG_FEATURE_UTMP is not set
+# CONFIG_FEATURE_WTMP is not set
+# CONFIG_FEATURE_PIDFILE is not set
+CONFIG_PID_FILE_PATH=""
+CONFIG_BUSYBOX=y
+CONFIG_FEATURE_SHOW_SCRIPT=y
+# CONFIG_FEATURE_INSTALLER is not set
+# CONFIG_INSTALL_NO_USR is not set
+# CONFIG_FEATURE_SUID is not set
+# CONFIG_FEATURE_SUID_CONFIG is not set
+# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set
+# CONFIG_FEATURE_PREFER_APPLETS is not set
+CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe"
+# CONFIG_SELINUX is not set
+# CONFIG_FEATURE_CLEAN_UP is not set
+CONFIG_FEATURE_SYSLOG_INFO=y
+CONFIG_FEATURE_SYSLOG=y
+
+#
+# Build Options
+#
+CONFIG_STATIC=y
+# CONFIG_PIE is not set
+# CONFIG_NOMMU is not set
+# CONFIG_BUILD_LIBBUSYBOX is not set
+# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set
+# CONFIG_FEATURE_INDIVIDUAL is not set
+# CONFIG_FEATURE_SHARED_BUSYBOX is not set
+CONFIG_CROSS_COMPILER_PREFIX="arm-linux-"
+CONFIG_SYSROOT=""
+CONFIG_EXTRA_CFLAGS=""
+CONFIG_EXTRA_LDFLAGS=""
+CONFIG_EXTRA_LDLIBS=""
+# CONFIG_USE_PORTABLE_CODE is not set
+# CONFIG_STACK_OPTIMIZATION_386 is not set
+CONFIG_STATIC_LIBGCC=y
+
+#
+# Installation Options ("make install" behavior)
+#
+CONFIG_INSTALL_APPLET_SYMLINKS=y
+# CONFIG_INSTALL_APPLET_HARDLINKS is not set
+# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set
+# CONFIG_INSTALL_APPLET_DONT is not set
+# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set
+# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set
+# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set
+CONFIG_PREFIX="../nfsroot"
+
+#
+# Debugging Options
+#
+# CONFIG_DEBUG is not set
+# CONFIG_DEBUG_PESSIMIZE is not set
+# CONFIG_DEBUG_SANITIZE is not set
+# CONFIG_UNIT_TEST is not set
+# CONFIG_WERROR is not set
+# CONFIG_WARN_SIMPLE_MSG is not set
+CONFIG_NO_DEBUG_LIB=y
+# CONFIG_DMALLOC is not set
+# CONFIG_EFENCE is not set
+
+#
+# Library Tuning
+#
+# CONFIG_FEATURE_USE_BSS_TAIL is not set
+CONFIG_FLOAT_DURATION=y
+CONFIG_FEATURE_RTMINMAX=y
+CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS=y
+CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
+# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
+# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
+CONFIG_PASSWORD_MINLEN=6
+CONFIG_MD5_SMALL=1
+CONFIG_SHA1_SMALL=3
+# CONFIG_SHA1_HWACCEL is not set
+# CONFIG_SHA256_HWACCEL is not set
+CONFIG_SHA3_SMALL=1
+CONFIG_FEATURE_NON_POSIX_CP=y
+# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set
+CONFIG_FEATURE_USE_SENDFILE=y
+CONFIG_FEATURE_COPYBUF_KB=4
+# CONFIG_MONOTONIC_SYSCALL is not set
+CONFIG_IOCTL_HEX2STR_ERROR=y
+CONFIG_FEATURE_EDITING=y
+CONFIG_FEATURE_EDITING_MAX_LEN=1024
+# CONFIG_FEATURE_EDITING_VI is not set
+CONFIG_FEATURE_EDITING_HISTORY=15
+# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set
+# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set
+# CONFIG_FEATURE_REVERSE_SEARCH is not set
+CONFIG_FEATURE_TAB_COMPLETION=y
+# CONFIG_FEATURE_USERNAME_COMPLETION is not set
+# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set
+CONFIG_FEATURE_EDITING_WINCH=y
+# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set
+# CONFIG_LOCALE_SUPPORT is not set
+CONFIG_UNICODE_SUPPORT=y
+# CONFIG_UNICODE_USING_LOCALE is not set
+# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set
+CONFIG_SUBST_WCHAR=63
+CONFIG_LAST_SUPPORTED_WCHAR=767
+# CONFIG_UNICODE_COMBINING_WCHARS is not set
+# CONFIG_UNICODE_WIDE_WCHARS is not set
+# CONFIG_UNICODE_BIDI_SUPPORT is not set
+# CONFIG_UNICODE_NEUTRAL_TABLE is not set
+# CONFIG_UNICODE_PRESERVE_BROKEN is not set
+# CONFIG_LOOP_CONFIGURE is not set
+# CONFIG_NO_LOOP_CONFIGURE is not set
+CONFIG_TRY_LOOP_CONFIGURE=y
+
+#
+# Applets
+#
+
+#
+# Archival Utilities
+#
+# CONFIG_FEATURE_SEAMLESS_XZ is not set
+# CONFIG_FEATURE_SEAMLESS_LZMA is not set
+# CONFIG_FEATURE_SEAMLESS_BZ2 is not set
+# CONFIG_FEATURE_SEAMLESS_GZ is not set
+# CONFIG_FEATURE_SEAMLESS_Z is not set
+# CONFIG_AR is not set
+# CONFIG_FEATURE_AR_LONG_FILENAMES is not set
+# CONFIG_FEATURE_AR_CREATE is not set
+# CONFIG_UNCOMPRESS is not set
+# CONFIG_GUNZIP is not set
+# CONFIG_ZCAT is not set
+# CONFIG_FEATURE_GUNZIP_LONG_OPTIONS is not set
+# CONFIG_BUNZIP2 is not set
+# CONFIG_BZCAT is not set
+# CONFIG_UNLZMA is not set
+# CONFIG_LZCAT is not set
+# CONFIG_LZMA is not set
+# CONFIG_UNXZ is not set
+# CONFIG_XZCAT is not set
+# CONFIG_XZ is not set
+# CONFIG_BZIP2 is not set
+CONFIG_BZIP2_SMALL=0
+# CONFIG_FEATURE_BZIP2_DECOMPRESS is not set
+# CONFIG_CPIO is not set
+# CONFIG_FEATURE_CPIO_O is not set
+# CONFIG_FEATURE_CPIO_P is not set
+# CONFIG_FEATURE_CPIO_IGNORE_DEVNO is not set
+# CONFIG_FEATURE_CPIO_RENUMBER_INODES is not set
+# CONFIG_DPKG is not set
+# CONFIG_DPKG_DEB is not set
+# CONFIG_GZIP is not set
+# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set
+CONFIG_GZIP_FAST=0
+# CONFIG_FEATURE_GZIP_LEVELS is not set
+# CONFIG_FEATURE_GZIP_DECOMPRESS is not set
+# CONFIG_LZOP is not set
+# CONFIG_UNLZOP is not set
+# CONFIG_LZOPCAT is not set
+# CONFIG_LZOP_COMPR_HIGH is not set
+# CONFIG_RPM is not set
+# CONFIG_RPM2CPIO is not set
+# CONFIG_TAR is not set
+# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set
+# CONFIG_FEATURE_TAR_CREATE is not set
+# CONFIG_FEATURE_TAR_AUTODETECT is not set
+# CONFIG_FEATURE_TAR_FROM is not set
+# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set
+# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set
+# CONFIG_FEATURE_TAR_GNU_EXTENSIONS is not set
+# CONFIG_FEATURE_TAR_TO_COMMAND is not set
+# CONFIG_FEATURE_TAR_UNAME_GNAME is not set
+# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set
+# CONFIG_FEATURE_TAR_SELINUX is not set
+# CONFIG_UNZIP is not set
+# CONFIG_FEATURE_UNZIP_CDF is not set
+# CONFIG_FEATURE_UNZIP_BZIP2 is not set
+# CONFIG_FEATURE_UNZIP_LZMA is not set
+# CONFIG_FEATURE_UNZIP_XZ is not set
+# CONFIG_FEATURE_LZMA_FAST is not set
+
+#
+# Coreutils
+#
+CONFIG_FEATURE_VERBOSE=y
+
+#
+# Common options for date and touch
+#
+# CONFIG_FEATURE_TIMEZONE is not set
+
+#
+# Common options for cp and mv
+#
+# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set
+
+#
+# Common options for df, du, ls
+#
+CONFIG_FEATURE_HUMAN_READABLE=y
+# CONFIG_BASENAME is not set
+CONFIG_CAT=y
+# CONFIG_FEATURE_CATN is not set
+CONFIG_FEATURE_CATV=y
+# CONFIG_CHGRP is not set
+CONFIG_CHMOD=y
+# CONFIG_CHOWN is not set
+# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set
+# CONFIG_CHROOT is not set
+# CONFIG_CKSUM is not set
+# CONFIG_CRC32 is not set
+# CONFIG_COMM is not set
+CONFIG_CP=y
+# CONFIG_FEATURE_CP_LONG_OPTIONS is not set
+# CONFIG_FEATURE_CP_REFLINK is not set
+# CONFIG_CUT is not set
+# CONFIG_FEATURE_CUT_REGEX is not set
+# CONFIG_DATE is not set
+# CONFIG_FEATURE_DATE_ISOFMT is not set
+# CONFIG_FEATURE_DATE_NANO is not set
+# CONFIG_FEATURE_DATE_COMPAT is not set
+# CONFIG_DD is not set
+# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set
+# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set
+# CONFIG_FEATURE_DD_IBS_OBS is not set
+# CONFIG_FEATURE_DD_STATUS is not set
+CONFIG_DF=y
+CONFIG_FEATURE_DF_FANCY=y
+# CONFIG_FEATURE_SKIP_ROOTFS is not set
+# CONFIG_DIRNAME is not set
+# CONFIG_DOS2UNIX is not set
+# CONFIG_UNIX2DOS is not set
+# CONFIG_DU is not set
+# CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K is not set
+CONFIG_ECHO=y
+# CONFIG_FEATURE_FANCY_ECHO is not set
+# CONFIG_ENV is not set
+# CONFIG_EXPAND is not set
+# CONFIG_UNEXPAND is not set
+# CONFIG_EXPR is not set
+# CONFIG_EXPR_MATH_SUPPORT_64 is not set
+# CONFIG_FACTOR is not set
+# CONFIG_FALSE is not set
+# CONFIG_FOLD is not set
+# CONFIG_HEAD is not set
+# CONFIG_FEATURE_FANCY_HEAD is not set
+# CONFIG_HOSTID is not set
+# CONFIG_ID is not set
+# CONFIG_GROUPS is not set
+# CONFIG_INSTALL is not set
+# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set
+# CONFIG_LINK is not set
+CONFIG_LN=y
+# CONFIG_LOGNAME is not set
+CONFIG_LS=y
+# CONFIG_FEATURE_LS_FILETYPES is not set
+# CONFIG_FEATURE_LS_FOLLOWLINKS is not set
+# CONFIG_FEATURE_LS_RECURSIVE is not set
+CONFIG_FEATURE_LS_WIDTH=y
+CONFIG_FEATURE_LS_SORTFILES=y
+CONFIG_FEATURE_LS_TIMESTAMPS=y
+# CONFIG_FEATURE_LS_USERNAME is not set
+# CONFIG_FEATURE_LS_COLOR is not set
+# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set
+# CONFIG_MD5SUM is not set
+# CONFIG_SHA1SUM is not set
+# CONFIG_SHA256SUM is not set
+# CONFIG_SHA512SUM is not set
+# CONFIG_SHA3SUM is not set
+# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set
+CONFIG_MKDIR=y
+# CONFIG_MKFIFO is not set
+CONFIG_MKNOD=y
+# CONFIG_MKTEMP is not set
+CONFIG_MV=y
+# CONFIG_NICE is not set
+# CONFIG_NL is not set
+# CONFIG_NOHUP is not set
+# CONFIG_NPROC is not set
+CONFIG_OD=y
+# CONFIG_PASTE is not set
+# CONFIG_PRINTENV is not set
+# CONFIG_PRINTF is not set
+CONFIG_PWD=y
+# CONFIG_READLINK is not set
+# CONFIG_FEATURE_READLINK_FOLLOW is not set
+# CONFIG_REALPATH is not set
+CONFIG_RM=y
+CONFIG_RMDIR=y
+# CONFIG_SEQ is not set
+# CONFIG_SHRED is not set
+# CONFIG_SHUF is not set
+CONFIG_SLEEP=y
+# CONFIG_FEATURE_FANCY_SLEEP is not set
+# CONFIG_SORT is not set
+# CONFIG_FEATURE_SORT_BIG is not set
+# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set
+# CONFIG_SPLIT is not set
+# CONFIG_FEATURE_SPLIT_FANCY is not set
+# CONFIG_STAT is not set
+# CONFIG_FEATURE_STAT_FORMAT is not set
+# CONFIG_FEATURE_STAT_FILESYSTEM is not set
+# CONFIG_STTY is not set
+# CONFIG_SUM is not set
+CONFIG_SYNC=y
+# CONFIG_FEATURE_SYNC_FANCY is not set
+# CONFIG_FSYNC is not set
+# CONFIG_TAC is not set
+# CONFIG_TAIL is not set
+# CONFIG_FEATURE_FANCY_TAIL is not set
+# CONFIG_TEE is not set
+# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set
+# CONFIG_TEST is not set
+# CONFIG_TEST1 is not set
+# CONFIG_TEST2 is not set
+# CONFIG_FEATURE_TEST_64 is not set
+# CONFIG_TIMEOUT is not set
+CONFIG_TOUCH=y
+# CONFIG_FEATURE_TOUCH_SUSV3 is not set
+# CONFIG_TR is not set
+# CONFIG_FEATURE_TR_CLASSES is not set
+# CONFIG_FEATURE_TR_EQUIV is not set
+# CONFIG_TRUE is not set
+# CONFIG_TRUNCATE is not set
+CONFIG_TSORT=y
+# CONFIG_TTY is not set
+CONFIG_UNAME=y
+CONFIG_UNAME_OSNAME="GNU/Linux"
+# CONFIG_BB_ARCH is not set
+# CONFIG_UNIQ is not set
+# CONFIG_UNLINK is not set
+# CONFIG_USLEEP is not set
+# CONFIG_UUDECODE is not set
+# CONFIG_BASE32 is not set
+# CONFIG_BASE64 is not set
+# CONFIG_UUENCODE is not set
+# CONFIG_WC is not set
+# CONFIG_FEATURE_WC_LARGE is not set
+# CONFIG_WHO is not set
+# CONFIG_W is not set
+# CONFIG_USERS is not set
+# CONFIG_WHOAMI is not set
+# CONFIG_YES is not set
+
+#
+# Console Utilities
+#
+# CONFIG_CHVT is not set
+# CONFIG_CLEAR is not set
+# CONFIG_DEALLOCVT is not set
+# CONFIG_DUMPKMAP is not set
+# CONFIG_FGCONSOLE is not set
+# CONFIG_KBD_MODE is not set
+# CONFIG_LOADFONT is not set
+# CONFIG_SETFONT is not set
+# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set
+CONFIG_DEFAULT_SETFONT_DIR=""
+# CONFIG_FEATURE_LOADFONT_PSF2 is not set
+# CONFIG_FEATURE_LOADFONT_RAW is not set
+# CONFIG_LOADKMAP is not set
+# CONFIG_OPENVT is not set
+# CONFIG_RESET is not set
+# CONFIG_RESIZE is not set
+# CONFIG_FEATURE_RESIZE_PRINT is not set
+# CONFIG_SETCONSOLE is not set
+# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set
+# CONFIG_SETKEYCODES is not set
+# CONFIG_SETLOGCONS is not set
+# CONFIG_SHOWKEY is not set
+
+#
+# Debian Utilities
+#
+# CONFIG_PIPE_PROGRESS is not set
+# CONFIG_RUN_PARTS is not set
+# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set
+# CONFIG_FEATURE_RUN_PARTS_FANCY is not set
+# CONFIG_START_STOP_DAEMON is not set
+# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set
+# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set
+CONFIG_WHICH=y
+
+#
+# klibc-utils
+#
+# CONFIG_MINIPS is not set
+# CONFIG_NUKE is not set
+# CONFIG_RESUME is not set
+# CONFIG_RUN_INIT is not set
+
+#
+# Editors
+#
+# CONFIG_AWK is not set
+# CONFIG_FEATURE_AWK_LIBM is not set
+# CONFIG_FEATURE_AWK_GNU_EXTENSIONS is not set
+# CONFIG_CMP is not set
+# CONFIG_DIFF is not set
+# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set
+# CONFIG_FEATURE_DIFF_DIR is not set
+# CONFIG_ED is not set
+# CONFIG_PATCH is not set
+# CONFIG_SED is not set
+CONFIG_VI=y
+CONFIG_FEATURE_VI_MAX_LEN=4096
+# CONFIG_FEATURE_VI_8BIT is not set
+CONFIG_FEATURE_VI_COLON=y
+CONFIG_FEATURE_VI_COLON_EXPAND=y
+CONFIG_FEATURE_VI_YANKMARK=y
+CONFIG_FEATURE_VI_SEARCH=y
+# CONFIG_FEATURE_VI_REGEX_SEARCH is not set
+CONFIG_FEATURE_VI_USE_SIGNALS=y
+CONFIG_FEATURE_VI_DOT_CMD=y
+# CONFIG_FEATURE_VI_READONLY is not set
+# CONFIG_FEATURE_VI_SETOPTS is not set
+# CONFIG_FEATURE_VI_SET is not set
+CONFIG_FEATURE_VI_WIN_RESIZE=y
+CONFIG_FEATURE_VI_ASK_TERMINAL=y
+CONFIG_FEATURE_VI_UNDO=y
+CONFIG_FEATURE_VI_UNDO_QUEUE=y
+CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256
+CONFIG_FEATURE_VI_VERBOSE_STATUS=y
+# CONFIG_FEATURE_ALLOW_EXEC is not set
+
+#
+# Finding Utilities
+#
+CONFIG_FIND=y
+CONFIG_FEATURE_FIND_PRINT0=y
+CONFIG_FEATURE_FIND_MTIME=y
+# CONFIG_FEATURE_FIND_ATIME is not set
+# CONFIG_FEATURE_FIND_CTIME is not set
+CONFIG_FEATURE_FIND_MMIN=y
+# CONFIG_FEATURE_FIND_AMIN is not set
+# CONFIG_FEATURE_FIND_CMIN is not set
+CONFIG_FEATURE_FIND_PERM=y
+CONFIG_FEATURE_FIND_TYPE=y
+CONFIG_FEATURE_FIND_EXECUTABLE=y
+CONFIG_FEATURE_FIND_XDEV=y
+CONFIG_FEATURE_FIND_MAXDEPTH=y
+CONFIG_FEATURE_FIND_NEWER=y
+CONFIG_FEATURE_FIND_INUM=y
+# CONFIG_FEATURE_FIND_SAMEFILE is not set
+CONFIG_FEATURE_FIND_EXEC=y
+CONFIG_FEATURE_FIND_EXEC_PLUS=y
+CONFIG_FEATURE_FIND_EXEC_OK=y
+CONFIG_FEATURE_FIND_USER=y
+CONFIG_FEATURE_FIND_GROUP=y
+CONFIG_FEATURE_FIND_NOT=y
+CONFIG_FEATURE_FIND_DEPTH=y
+CONFIG_FEATURE_FIND_PAREN=y
+CONFIG_FEATURE_FIND_SIZE=y
+CONFIG_FEATURE_FIND_PRUNE=y
+CONFIG_FEATURE_FIND_QUIT=y
+CONFIG_FEATURE_FIND_DELETE=y
+CONFIG_FEATURE_FIND_EMPTY=y
+CONFIG_FEATURE_FIND_PATH=y
+CONFIG_FEATURE_FIND_REGEX=y
+# CONFIG_FEATURE_FIND_CONTEXT is not set
+CONFIG_FEATURE_FIND_LINKS=y
+CONFIG_GREP=y
+# CONFIG_EGREP is not set
+# CONFIG_FGREP is not set
+# CONFIG_FEATURE_GREP_CONTEXT is not set
+# CONFIG_XARGS is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL is not set
+# CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE is not set
+
+#
+# Init Utilities
+#
+# CONFIG_BOOTCHARTD is not set
+# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set
+# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set
+CONFIG_HALT=y
+CONFIG_POWEROFF=y
+CONFIG_REBOOT=y
+CONFIG_FEATURE_WAIT_FOR_INIT=y
+# CONFIG_FEATURE_CALL_TELINIT is not set
+CONFIG_TELINIT_PATH=""
+CONFIG_INIT=y
+# CONFIG_LINUXRC is not set
+CONFIG_FEATURE_USE_INITTAB=y
+CONFIG_FEATURE_KILL_REMOVED=y
+CONFIG_FEATURE_KILL_DELAY=0
+# CONFIG_FEATURE_INIT_SCTTY is not set
+# CONFIG_FEATURE_INIT_SYSLOG is not set
+CONFIG_FEATURE_INIT_QUIET=y
+# CONFIG_FEATURE_INIT_COREDUMPS is not set
+CONFIG_INIT_TERMINAL_TYPE="linux"
+# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set
+
+#
+# Login/Password Management Utilities
+#
+# CONFIG_FEATURE_SHADOWPASSWDS is not set
+# CONFIG_USE_BB_PWD_GRP is not set
+# CONFIG_USE_BB_SHADOW is not set
+CONFIG_USE_BB_CRYPT=y
+CONFIG_USE_BB_CRYPT_SHA=y
+# CONFIG_ADD_SHELL is not set
+# CONFIG_REMOVE_SHELL is not set
+# CONFIG_ADDGROUP is not set
+# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set
+# CONFIG_ADDUSER is not set
+# CONFIG_FEATURE_CHECK_NAMES is not set
+CONFIG_LAST_ID=0
+CONFIG_FIRST_SYSTEM_ID=0
+CONFIG_LAST_SYSTEM_ID=0
+# CONFIG_CHPASSWD is not set
+CONFIG_FEATURE_DEFAULT_PASSWD_ALGO=""
+# CONFIG_CRYPTPW is not set
+# CONFIG_MKPASSWD is not set
+# CONFIG_DELUSER is not set
+# CONFIG_DELGROUP is not set
+# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set
+CONFIG_GETTY=y
+# CONFIG_LOGIN is not set
+# CONFIG_LOGIN_SESSION_AS_CHILD is not set
+# CONFIG_LOGIN_SCRIPTS is not set
+# CONFIG_FEATURE_NOLOGIN is not set
+# CONFIG_FEATURE_SECURETTY is not set
+# CONFIG_PASSWD is not set
+# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set
+# CONFIG_SU is not set
+# CONFIG_FEATURE_SU_SYSLOG is not set
+# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set
+# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set
+# CONFIG_SULOGIN is not set
+# CONFIG_VLOCK is not set
+
+#
+# Linux Ext2 FS Progs
+#
+# CONFIG_CHATTR is not set
+# CONFIG_FSCK is not set
+# CONFIG_LSATTR is not set
+# CONFIG_TUNE2FS is not set
+
+#
+# Linux Module Utilities
+#
+# CONFIG_MODPROBE_SMALL is not set
+# CONFIG_DEPMOD is not set
+CONFIG_INSMOD=y
+CONFIG_LSMOD=y
+CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT=y
+CONFIG_MODINFO=y
+CONFIG_MODPROBE=y
+# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set
+CONFIG_RMMOD=y
+
+#
+# Options common to multiple modutils
+#
+# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set
+# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set
+# CONFIG_FEATURE_2_4_MODULES is not set
+# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set
+# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set
+# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set
+# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set
+# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set
+# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set
+CONFIG_FEATURE_MODUTILS_ALIAS=y
+CONFIG_FEATURE_MODUTILS_SYMBOLS=y
+CONFIG_DEFAULT_MODULES_DIR="/lib/modules"
+CONFIG_DEFAULT_DEPMOD_FILE="modules.dep"
+
+#
+# Linux System Utilities
+#
+# CONFIG_ACPID is not set
+# CONFIG_FEATURE_ACPID_COMPAT is not set
+# CONFIG_BLKDISCARD is not set
+# CONFIG_BLKID is not set
+# CONFIG_FEATURE_BLKID_TYPE is not set
+# CONFIG_BLOCKDEV is not set
+# CONFIG_CAL is not set
+# CONFIG_CHRT is not set
+CONFIG_DMESG=y
+CONFIG_FEATURE_DMESG_PRETTY=y
+# CONFIG_EJECT is not set
+# CONFIG_FEATURE_EJECT_SCSI is not set
+# CONFIG_FALLOCATE is not set
+# CONFIG_FATATTR is not set
+# CONFIG_FBSET is not set
+# CONFIG_FEATURE_FBSET_FANCY is not set
+# CONFIG_FEATURE_FBSET_READMODE is not set
+# CONFIG_FDFORMAT is not set
+# CONFIG_FDISK is not set
+# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set
+# CONFIG_FEATURE_FDISK_WRITABLE is not set
+# CONFIG_FEATURE_AIX_LABEL is not set
+# CONFIG_FEATURE_SGI_LABEL is not set
+# CONFIG_FEATURE_SUN_LABEL is not set
+# CONFIG_FEATURE_OSF_LABEL is not set
+# CONFIG_FEATURE_GPT_LABEL is not set
+# CONFIG_FEATURE_FDISK_ADVANCED is not set
+# CONFIG_FINDFS is not set
+# CONFIG_FLOCK is not set
+# CONFIG_FDFLUSH is not set
+# CONFIG_FREERAMDISK is not set
+# CONFIG_FSCK_MINIX is not set
+# CONFIG_FSFREEZE is not set
+# CONFIG_FSTRIM is not set
+# CONFIG_GETOPT is not set
+# CONFIG_FEATURE_GETOPT_LONG is not set
+# CONFIG_HEXDUMP is not set
+# CONFIG_HD is not set
+# CONFIG_XXD is not set
+# CONFIG_HWCLOCK is not set
+# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set
+# CONFIG_IONICE is not set
+# CONFIG_IPCRM is not set
+# CONFIG_IPCS is not set
+# CONFIG_LAST is not set
+# CONFIG_FEATURE_LAST_FANCY is not set
+# CONFIG_LOSETUP is not set
+# CONFIG_LSPCI is not set
+CONFIG_LSUSB=y
+# CONFIG_MDEV is not set
+# CONFIG_FEATURE_MDEV_CONF is not set
+# CONFIG_FEATURE_MDEV_RENAME is not set
+# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set
+# CONFIG_FEATURE_MDEV_EXEC is not set
+# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set
+# CONFIG_FEATURE_MDEV_DAEMON is not set
+# CONFIG_MESG is not set
+# CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP is not set
+# CONFIG_MKE2FS is not set
+# CONFIG_MKFS_EXT2 is not set
+# CONFIG_MKFS_MINIX is not set
+# CONFIG_FEATURE_MINIX2 is not set
+# CONFIG_MKFS_REISER is not set
+# CONFIG_MKDOSFS is not set
+# CONFIG_MKFS_VFAT is not set
+# CONFIG_MKSWAP is not set
+# CONFIG_FEATURE_MKSWAP_UUID is not set
+CONFIG_MORE=y
+CONFIG_MOUNT=y
+# CONFIG_FEATURE_MOUNT_FAKE is not set
+# CONFIG_FEATURE_MOUNT_VERBOSE is not set
+# CONFIG_FEATURE_MOUNT_HELPERS is not set
+# CONFIG_FEATURE_MOUNT_LABEL is not set
+# CONFIG_FEATURE_MOUNT_NFS is not set
+# CONFIG_FEATURE_MOUNT_CIFS is not set
+CONFIG_FEATURE_MOUNT_FLAGS=y
+CONFIG_FEATURE_MOUNT_FSTAB=y
+# CONFIG_FEATURE_MOUNT_OTHERTAB is not set
+# CONFIG_MOUNTPOINT is not set
+# CONFIG_NOLOGIN is not set
+# CONFIG_NOLOGIN_DEPENDENCIES is not set
+# CONFIG_NSENTER is not set
+# CONFIG_PIVOT_ROOT is not set
+# CONFIG_RDATE is not set
+# CONFIG_RDEV is not set
+# CONFIG_READPROFILE is not set
+# CONFIG_RENICE is not set
+# CONFIG_REV is not set
+# CONFIG_RTCWAKE is not set
+# CONFIG_SCRIPT is not set
+# CONFIG_SCRIPTREPLAY is not set
+# CONFIG_SETARCH is not set
+# CONFIG_LINUX32 is not set
+# CONFIG_LINUX64 is not set
+# CONFIG_SETPRIV is not set
+# CONFIG_FEATURE_SETPRIV_DUMP is not set
+# CONFIG_FEATURE_SETPRIV_CAPABILITIES is not set
+# CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES is not set
+# CONFIG_SETSID is not set
+# CONFIG_SWAPON is not set
+# CONFIG_FEATURE_SWAPON_DISCARD is not set
+# CONFIG_FEATURE_SWAPON_PRI is not set
+CONFIG_SWAPOFF=y
+# CONFIG_FEATURE_SWAPONOFF_LABEL is not set
+# CONFIG_SWITCH_ROOT is not set
+# CONFIG_TASKSET is not set
+# CONFIG_FEATURE_TASKSET_FANCY is not set
+# CONFIG_FEATURE_TASKSET_CPULIST is not set
+# CONFIG_UEVENT is not set
+CONFIG_UMOUNT=y
+CONFIG_FEATURE_UMOUNT_ALL=y
+# CONFIG_UNSHARE is not set
+# CONFIG_WALL is not set
+
+#
+# Common options for mount/umount
+#
+# CONFIG_FEATURE_MOUNT_LOOP is not set
+# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set
+# CONFIG_FEATURE_MTAB_SUPPORT is not set
+# CONFIG_VOLUMEID is not set
+# CONFIG_FEATURE_VOLUMEID_BCACHE is not set
+# CONFIG_FEATURE_VOLUMEID_BTRFS is not set
+# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set
+# CONFIG_FEATURE_VOLUMEID_EROFS is not set
+# CONFIG_FEATURE_VOLUMEID_EXFAT is not set
+# CONFIG_FEATURE_VOLUMEID_EXT is not set
+# CONFIG_FEATURE_VOLUMEID_F2FS is not set
+# CONFIG_FEATURE_VOLUMEID_FAT is not set
+# CONFIG_FEATURE_VOLUMEID_HFS is not set
+# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set
+# CONFIG_FEATURE_VOLUMEID_JFS is not set
+# CONFIG_FEATURE_VOLUMEID_LFS is not set
+# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set
+# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set
+# CONFIG_FEATURE_VOLUMEID_LUKS is not set
+# CONFIG_FEATURE_VOLUMEID_MINIX is not set
+# CONFIG_FEATURE_VOLUMEID_NILFS is not set
+# CONFIG_FEATURE_VOLUMEID_NTFS is not set
+# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set
+# CONFIG_FEATURE_VOLUMEID_REISERFS is not set
+# CONFIG_FEATURE_VOLUMEID_ROMFS is not set
+# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set
+# CONFIG_FEATURE_VOLUMEID_SYSV is not set
+# CONFIG_FEATURE_VOLUMEID_UBIFS is not set
+# CONFIG_FEATURE_VOLUMEID_UDF is not set
+# CONFIG_FEATURE_VOLUMEID_XFS is not set
+
+#
+# Miscellaneous Utilities
+#
+# CONFIG_ADJTIMEX is not set
+# CONFIG_ASCII is not set
+# CONFIG_BBCONFIG is not set
+# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set
+# CONFIG_BC is not set
+# CONFIG_DC is not set
+# CONFIG_FEATURE_DC_BIG is not set
+# CONFIG_FEATURE_DC_LIBM is not set
+# CONFIG_FEATURE_BC_INTERACTIVE is not set
+# CONFIG_FEATURE_BC_LONG_OPTIONS is not set
+# CONFIG_BEEP is not set
+CONFIG_FEATURE_BEEP_FREQ=0
+CONFIG_FEATURE_BEEP_LENGTH_MS=0
+# CONFIG_CHAT is not set
+# CONFIG_FEATURE_CHAT_NOFAIL is not set
+# CONFIG_FEATURE_CHAT_TTY_HIFI is not set
+# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set
+# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set
+# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set
+# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set
+# CONFIG_FEATURE_CHAT_CLR_ABORT is not set
+# CONFIG_CONSPY is not set
+# CONFIG_CROND is not set
+# CONFIG_FEATURE_CROND_D is not set
+# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set
+# CONFIG_FEATURE_CROND_SPECIAL_TIMES is not set
+CONFIG_FEATURE_CROND_DIR=""
+# CONFIG_CRONTAB is not set
+# CONFIG_DEVFSD is not set
+# CONFIG_DEVFSD_MODLOAD is not set
+# CONFIG_DEVFSD_FG_NP is not set
+# CONFIG_DEVFSD_VERBOSE is not set
+# CONFIG_FEATURE_DEVFS is not set
+# CONFIG_DEVMEM is not set
+# CONFIG_FBSPLASH is not set
+# CONFIG_FLASH_ERASEALL is not set
+# CONFIG_FLASH_LOCK is not set
+# CONFIG_FLASH_UNLOCK is not set
+# CONFIG_FLASHCP is not set
+CONFIG_GETFATTR=y
+# CONFIG_HDPARM is not set
+# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set
+# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set
+# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set
+# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set
+# CONFIG_HEXEDIT is not set
+# CONFIG_I2CGET is not set
+# CONFIG_I2CSET is not set
+# CONFIG_I2CDUMP is not set
+CONFIG_I2CDETECT=y
+# CONFIG_I2CTRANSFER is not set
+# CONFIG_INOTIFYD is not set
+# CONFIG_LESS is not set
+CONFIG_FEATURE_LESS_MAXLINES=0
+# CONFIG_FEATURE_LESS_BRACKETS is not set
+# CONFIG_FEATURE_LESS_FLAGS is not set
+# CONFIG_FEATURE_LESS_TRUNCATE is not set
+# CONFIG_FEATURE_LESS_MARKS is not set
+# CONFIG_FEATURE_LESS_REGEXP is not set
+# CONFIG_FEATURE_LESS_WINCH is not set
+# CONFIG_FEATURE_LESS_ASK_TERMINAL is not set
+# CONFIG_FEATURE_LESS_DASHCMD is not set
+# CONFIG_FEATURE_LESS_LINENUMS is not set
+# CONFIG_FEATURE_LESS_RAW is not set
+# CONFIG_FEATURE_LESS_ENV is not set
+# CONFIG_LSSCSI is not set
+# CONFIG_MAKEDEVS is not set
+# CONFIG_FEATURE_MAKEDEVS_LEAF is not set
+# CONFIG_FEATURE_MAKEDEVS_TABLE is not set
+# CONFIG_MAN is not set
+# CONFIG_MICROCOM is not set
+# CONFIG_MIM is not set
+# CONFIG_MT is not set
+# CONFIG_NANDWRITE is not set
+# CONFIG_NANDDUMP is not set
+# CONFIG_PARTPROBE is not set
+# CONFIG_RAIDAUTORUN is not set
+# CONFIG_READAHEAD is not set
+# CONFIG_RFKILL is not set
+# CONFIG_RUNLEVEL is not set
+# CONFIG_RX is not set
+CONFIG_SEEDRNG=y
+# CONFIG_SETFATTR is not set
+# CONFIG_SETSERIAL is not set
+# CONFIG_STRINGS is not set
+# CONFIG_TIME is not set
+CONFIG_TREE=y
+# CONFIG_TS is not set
+# CONFIG_TTYSIZE is not set
+# CONFIG_UBIATTACH is not set
+# CONFIG_UBIDETACH is not set
+# CONFIG_UBIMKVOL is not set
+# CONFIG_UBIRMVOL is not set
+# CONFIG_UBIRSVOL is not set
+# CONFIG_UBIUPDATEVOL is not set
+# CONFIG_UBIRENAME is not set
+# CONFIG_VOLNAME is not set
+# CONFIG_WATCHDOG is not set
+# CONFIG_FEATURE_WATCHDOG_OPEN_TWICE is not set
+
+#
+# Networking Utilities
+#
+# CONFIG_FEATURE_IPV6 is not set
+# CONFIG_FEATURE_UNIX_LOCAL is not set
+# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set
+# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set
+# CONFIG_FEATURE_ETC_NETWORKS is not set
+# CONFIG_FEATURE_ETC_SERVICES is not set
+# CONFIG_FEATURE_HWIB is not set
+# CONFIG_FEATURE_TLS_SHA1 is not set
+# CONFIG_ARP is not set
+# CONFIG_ARPING is not set
+# CONFIG_BRCTL is not set
+# CONFIG_FEATURE_BRCTL_FANCY is not set
+# CONFIG_FEATURE_BRCTL_SHOW is not set
+# CONFIG_DNSD is not set
+# CONFIG_ETHER_WAKE is not set
+# CONFIG_FTPD is not set
+# CONFIG_FEATURE_FTPD_WRITE is not set
+# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set
+# CONFIG_FEATURE_FTPD_AUTHENTICATION is not set
+# CONFIG_FTPGET is not set
+# CONFIG_FTPPUT is not set
+# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set
+# CONFIG_HOSTNAME is not set
+# CONFIG_DNSDOMAINNAME is not set
+CONFIG_HTTPD=y
+CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80
+# CONFIG_FEATURE_HTTPD_RANGES is not set
+# CONFIG_FEATURE_HTTPD_SETUID is not set
+# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set
+# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set
+CONFIG_FEATURE_HTTPD_CGI=y
+# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set
+# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set
+# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set
+# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set
+# CONFIG_FEATURE_HTTPD_PROXY is not set
+# CONFIG_FEATURE_HTTPD_GZIP is not set
+# CONFIG_FEATURE_HTTPD_ETAG is not set
+# CONFIG_FEATURE_HTTPD_LAST_MODIFIED is not set
+# CONFIG_FEATURE_HTTPD_DATE is not set
+# CONFIG_FEATURE_HTTPD_ACL_IP is not set
+CONFIG_IFCONFIG=y
+CONFIG_FEATURE_IFCONFIG_STATUS=y
+# CONFIG_FEATURE_IFCONFIG_SLIP is not set
+# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set
+# CONFIG_FEATURE_IFCONFIG_HW is not set
+CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y
+# CONFIG_IFENSLAVE is not set
+# CONFIG_IFPLUGD is not set
+# CONFIG_IFUP is not set
+# CONFIG_IFDOWN is not set
+CONFIG_IFUPDOWN_IFSTATE_PATH=""
+# CONFIG_FEATURE_IFUPDOWN_IP is not set
+# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set
+# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set
+# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set
+# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set
+# CONFIG_INETD is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set
+# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set
+# CONFIG_FEATURE_INETD_RPC is not set
+# CONFIG_IP is not set
+# CONFIG_IPADDR is not set
+# CONFIG_IPLINK is not set
+# CONFIG_IPROUTE is not set
+# CONFIG_IPTUNNEL is not set
+# CONFIG_IPRULE is not set
+# CONFIG_IPNEIGH is not set
+# CONFIG_FEATURE_IP_ADDRESS is not set
+# CONFIG_FEATURE_IP_LINK is not set
+CONFIG_FEATURE_IP_LINK_CAN=y
+# CONFIG_FEATURE_IP_ROUTE is not set
+CONFIG_FEATURE_IP_ROUTE_DIR=""
+# CONFIG_FEATURE_IP_TUNNEL is not set
+# CONFIG_FEATURE_IP_RULE is not set
+# CONFIG_FEATURE_IP_NEIGH is not set
+# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set
+# CONFIG_IPCALC is not set
+# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set
+# CONFIG_FEATURE_IPCALC_FANCY is not set
+# CONFIG_FAKEIDENTD is not set
+# CONFIG_NAMEIF is not set
+# CONFIG_FEATURE_NAMEIF_EXTENDED is not set
+# CONFIG_NBDCLIENT is not set
+# CONFIG_NC is not set
+# CONFIG_NETCAT is not set
+# CONFIG_NC_SERVER is not set
+# CONFIG_NC_EXTRA is not set
+# CONFIG_NC_110_COMPAT is not set
+# CONFIG_NETSTAT is not set
+# CONFIG_FEATURE_NETSTAT_WIDE is not set
+# CONFIG_FEATURE_NETSTAT_PRG is not set
+# CONFIG_NSLOOKUP is not set
+# CONFIG_FEATURE_NSLOOKUP_BIG is not set
+# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set
+# CONFIG_NTPD is not set
+# CONFIG_FEATURE_NTPD_SERVER is not set
+# CONFIG_FEATURE_NTPD_CONF is not set
+# CONFIG_FEATURE_NTP_AUTH is not set
+CONFIG_PING=y
+# CONFIG_PING6 is not set
+CONFIG_FEATURE_FANCY_PING=y
+# CONFIG_PSCAN is not set
+# CONFIG_ROUTE is not set
+# CONFIG_SLATTACH is not set
+# CONFIG_SSL_CLIENT is not set
+# CONFIG_TC is not set
+# CONFIG_FEATURE_TC_INGRESS is not set
+# CONFIG_TCPSVD is not set
+# CONFIG_UDPSVD is not set
+# CONFIG_TELNET is not set
+# CONFIG_FEATURE_TELNET_TTYPE is not set
+# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set
+# CONFIG_FEATURE_TELNET_WIDTH is not set
+# CONFIG_TELNETD is not set
+# CONFIG_FEATURE_TELNETD_STANDALONE is not set
+CONFIG_FEATURE_TELNETD_PORT_DEFAULT=0
+# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set
+# CONFIG_TFTP is not set
+# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set
+# CONFIG_FEATURE_TFTP_HPA_COMPAT is not set
+# CONFIG_TFTPD is not set
+# CONFIG_FEATURE_TFTP_GET is not set
+# CONFIG_FEATURE_TFTP_PUT is not set
+# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set
+# CONFIG_TFTP_DEBUG is not set
+# CONFIG_TLS is not set
+# CONFIG_TRACEROUTE is not set
+# CONFIG_TRACEROUTE6 is not set
+# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set
+# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set
+# CONFIG_TUNCTL is not set
+# CONFIG_FEATURE_TUNCTL_UG is not set
+# CONFIG_VCONFIG is not set
+# CONFIG_WGET is not set
+# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set
+# CONFIG_FEATURE_WGET_STATUSBAR is not set
+# CONFIG_FEATURE_WGET_FTP is not set
+# CONFIG_FEATURE_WGET_AUTHENTICATION is not set
+# CONFIG_FEATURE_WGET_TIMEOUT is not set
+# CONFIG_FEATURE_WGET_HTTPS is not set
+# CONFIG_FEATURE_WGET_OPENSSL is not set
+# CONFIG_WHOIS is not set
+# CONFIG_ZCIP is not set
+# CONFIG_UDHCPD is not set
+# CONFIG_FEATURE_UDHCPD_BOOTP is not set
+# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set
+# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set
+CONFIG_DHCPD_LEASES_FILE=""
+# CONFIG_DUMPLEASES is not set
+# CONFIG_DHCPRELAY is not set
+# CONFIG_UDHCPC is not set
+# CONFIG_FEATURE_UDHCPC_ARPING is not set
+# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set
+CONFIG_UDHCPC_DEFAULT_SCRIPT=""
+CONFIG_UDHCPC6_DEFAULT_SCRIPT=""
+# CONFIG_UDHCPC6 is not set
+# CONFIG_FEATURE_UDHCPC6_RFC3646 is not set
+# CONFIG_FEATURE_UDHCPC6_RFC4704 is not set
+# CONFIG_FEATURE_UDHCPC6_RFC4833 is not set
+# CONFIG_FEATURE_UDHCPC6_RFC5970 is not set
+CONFIG_UDHCPC_DEFAULT_INTERFACE=""
+# CONFIG_FEATURE_UDHCP_PORT is not set
+CONFIG_UDHCP_DEBUG=0
+CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0
+# CONFIG_FEATURE_UDHCP_RFC3397 is not set
+# CONFIG_FEATURE_UDHCP_8021Q is not set
+CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS=""
+
+#
+# Print Utilities
+#
+# CONFIG_LPD is not set
+# CONFIG_LPR is not set
+# CONFIG_LPQ is not set
+
+#
+# Mail Utilities
+#
+CONFIG_FEATURE_MIME_CHARSET=""
+# CONFIG_MAKEMIME is not set
+# CONFIG_POPMAILDIR is not set
+# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set
+# CONFIG_REFORMIME is not set
+# CONFIG_FEATURE_REFORMIME_COMPAT is not set
+# CONFIG_SENDMAIL is not set
+
+#
+# Process Utilities
+#
+# CONFIG_FEATURE_FAST_TOP is not set
+CONFIG_FEATURE_SHOW_THREADS=y
+# CONFIG_FREE is not set
+# CONFIG_FUSER is not set
+# CONFIG_IOSTAT is not set
+CONFIG_KILL=y
+# CONFIG_KILLALL is not set
+# CONFIG_KILLALL5 is not set
+# CONFIG_LSOF is not set
+# CONFIG_MPSTAT is not set
+# CONFIG_NMETER is not set
+# CONFIG_PGREP is not set
+# CONFIG_PKILL is not set
+# CONFIG_PIDOF is not set
+# CONFIG_FEATURE_PIDOF_SINGLE is not set
+# CONFIG_FEATURE_PIDOF_OMIT is not set
+# CONFIG_PMAP is not set
+# CONFIG_POWERTOP is not set
+# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set
+CONFIG_PS=y
+# CONFIG_FEATURE_PS_WIDE is not set
+CONFIG_FEATURE_PS_LONG=y
+# CONFIG_FEATURE_PS_TIME is not set
+# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set
+# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set
+# CONFIG_PSTREE is not set
+# CONFIG_PWDX is not set
+# CONFIG_SMEMCAP is not set
+# CONFIG_BB_SYSCTL is not set
+CONFIG_TOP=y
+# CONFIG_FEATURE_TOP_INTERACTIVE is not set
+CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y
+CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y
+CONFIG_FEATURE_TOP_SMP_CPU=y
+CONFIG_FEATURE_TOP_DECIMALS=y
+CONFIG_FEATURE_TOP_SMP_PROCESS=y
+CONFIG_FEATURE_TOPMEM=y
+CONFIG_UPTIME=y
+# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set
+# CONFIG_WATCH is not set
+
+#
+# Runit Utilities
+#
+# CONFIG_CHPST is not set
+# CONFIG_SETUIDGID is not set
+# CONFIG_ENVUIDGID is not set
+# CONFIG_ENVDIR is not set
+# CONFIG_SOFTLIMIT is not set
+# CONFIG_RUNSV is not set
+# CONFIG_RUNSVDIR is not set
+# CONFIG_FEATURE_RUNSVDIR_LOG is not set
+# CONFIG_SV is not set
+CONFIG_SV_DEFAULT_SERVICE_DIR=""
+# CONFIG_SVC is not set
+# CONFIG_SVOK is not set
+# CONFIG_SVLOGD is not set
+# CONFIG_CHCON is not set
+# CONFIG_GETENFORCE is not set
+# CONFIG_GETSEBOOL is not set
+# CONFIG_LOAD_POLICY is not set
+# CONFIG_MATCHPATHCON is not set
+# CONFIG_RUNCON is not set
+# CONFIG_SELINUXENABLED is not set
+# CONFIG_SESTATUS is not set
+# CONFIG_SETENFORCE is not set
+# CONFIG_SETFILES is not set
+# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set
+# CONFIG_RESTORECON is not set
+# CONFIG_SETSEBOOL is not set
+
+#
+# Shells
+#
+CONFIG_SH_IS_ASH=y
+# CONFIG_SH_IS_HUSH is not set
+# CONFIG_SH_IS_NONE is not set
+# CONFIG_BASH_IS_ASH is not set
+# CONFIG_BASH_IS_HUSH is not set
+CONFIG_BASH_IS_NONE=y
+CONFIG_SHELL_ASH=y
+CONFIG_ASH=y
+CONFIG_ASH_OPTIMIZE_FOR_SIZE=y
+CONFIG_ASH_INTERNAL_GLOB=y
+CONFIG_ASH_BASH_COMPAT=y
+# CONFIG_ASH_BASH_SOURCE_CURDIR is not set
+# CONFIG_ASH_BASH_NOT_FOUND_HOOK is not set
+CONFIG_ASH_JOB_CONTROL=y
+# CONFIG_ASH_ALIAS is not set
+# CONFIG_ASH_RANDOM_SUPPORT is not set
+# CONFIG_ASH_EXPAND_PRMT is not set
+# CONFIG_ASH_IDLE_TIMEOUT is not set
+# CONFIG_ASH_MAIL is not set
+CONFIG_ASH_ECHO=y
+# CONFIG_ASH_PRINTF is not set
+CONFIG_ASH_TEST=y
+CONFIG_ASH_HELP=y
+# CONFIG_ASH_GETOPTS is not set
+# CONFIG_ASH_CMDCMD is not set
+# CONFIG_CTTYHACK is not set
+# CONFIG_HUSH is not set
+# CONFIG_SHELL_HUSH is not set
+# CONFIG_HUSH_BASH_COMPAT is not set
+# CONFIG_HUSH_BRACE_EXPANSION is not set
+# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set
+# CONFIG_HUSH_LINENO_VAR is not set
+# CONFIG_HUSH_INTERACTIVE is not set
+# CONFIG_HUSH_SAVEHISTORY is not set
+# CONFIG_HUSH_JOB is not set
+# CONFIG_HUSH_TICK is not set
+# CONFIG_HUSH_IF is not set
+# CONFIG_HUSH_LOOPS is not set
+# CONFIG_HUSH_CASE is not set
+# CONFIG_HUSH_FUNCTIONS is not set
+# CONFIG_HUSH_LOCAL is not set
+# CONFIG_HUSH_RANDOM_SUPPORT is not set
+# CONFIG_HUSH_MODE_X is not set
+# CONFIG_HUSH_ECHO is not set
+# CONFIG_HUSH_PRINTF is not set
+# CONFIG_HUSH_TEST is not set
+# CONFIG_HUSH_HELP is not set
+# CONFIG_HUSH_EXPORT is not set
+# CONFIG_HUSH_EXPORT_N is not set
+# CONFIG_HUSH_READONLY is not set
+# CONFIG_HUSH_KILL is not set
+# CONFIG_HUSH_WAIT is not set
+# CONFIG_HUSH_COMMAND is not set
+# CONFIG_HUSH_TRAP is not set
+# CONFIG_HUSH_TYPE is not set
+# CONFIG_HUSH_TIMES is not set
+# CONFIG_HUSH_READ is not set
+# CONFIG_HUSH_SET is not set
+# CONFIG_HUSH_UNSET is not set
+# CONFIG_HUSH_ULIMIT is not set
+# CONFIG_HUSH_UMASK is not set
+# CONFIG_HUSH_GETOPTS is not set
+# CONFIG_HUSH_MEMLEAK is not set
+
+#
+# Options common to all shells
+#
+# CONFIG_FEATURE_SH_MATH is not set
+# CONFIG_FEATURE_SH_MATH_64 is not set
+# CONFIG_FEATURE_SH_MATH_BASE is not set
+# CONFIG_FEATURE_SH_EXTRA_QUIET is not set
+# CONFIG_FEATURE_SH_STANDALONE is not set
+# CONFIG_FEATURE_SH_NOFORK is not set
+# CONFIG_FEATURE_SH_READ_FRAC is not set
+CONFIG_FEATURE_SH_HISTFILESIZE=y
+CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y
+
+#
+# System Logging Utilities
+#
+# CONFIG_KLOGD is not set
+# CONFIG_FEATURE_KLOGD_KLOGCTL is not set
+# CONFIG_LOGGER is not set
+# CONFIG_LOGREAD is not set
+# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set
+# CONFIG_SYSLOGD is not set
+# CONFIG_FEATURE_ROTATE_LOGFILE is not set
+# CONFIG_FEATURE_REMOTE_LOG is not set
+# CONFIG_FEATURE_SYSLOGD_DUP is not set
+# CONFIG_FEATURE_SYSLOGD_CFG is not set
+# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set
+CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0
+# CONFIG_FEATURE_IPC_SYSLOG is not set
+CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0
+# CONFIG_FEATURE_KMSG_SYSLOG is not set
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/hello.c b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/hello.c
new file mode 100644
index 0000000000..22e78e7fe7
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/hello.c
@@ -0,0 +1,8 @@
+#include
+#include
+
+int main (void)
+{
+ printf( "Hello world!\n" );
+ return EXIT_SUCCESS;
+}
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/cpuinfo b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/cpuinfo
new file mode 100755
index 0000000000..895422b465
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/cpuinfo
@@ -0,0 +1,10 @@
+#!/bin/sh
+echo "Content-type: text/html"
+echo
+echo ""
+echo "CPU information
"
+echo "Your embedded device uses the below processor:"
+echo " "`cat /proc/cpuinfo | grep "model name" | while read cpu; do echo "$cpu "; done`
+echo "
"
+echo "
"
+echo ""
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/list b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/list
new file mode 100755
index 0000000000..0a1dd24c08
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/list
@@ -0,0 +1,22 @@
+#!/bin/sh
+echo "Content-type: text/html"
+echo
+
+UPLOAD_DIR="/www/upload/files"
+URL_PATH="/upload/files"
+
+echo ""
+echo "
"
+echo "File collection
"
+echo "
"
+
+cd $UPLOAD_DIR
+for f in *
+do
+echo "
"
+done
+
+echo ""
+
+echo "
"
+echo ""
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/reboot b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/reboot
new file mode 100755
index 0000000000..b98e29ee4d
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/reboot
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Reboots the system
+echo "Content-type: text/html"
+echo
+echo ""
+echo "Rebooting the system
"
+echo ""
+echo "System reboot initiated"
+echo ""
+echo ""
+reboot
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/upload b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/upload
new file mode 100755
index 0000000000..34584dedaa
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/upload differ
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/upload.c b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/upload.c
new file mode 100644
index 0000000000..65d3f5603b
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/upload.c
@@ -0,0 +1,963 @@
+/*
+
+ upload.exe -- Upload a file to a server using forms.
+
+
+ DESCRIPTION
+
+ This is a CGI program to upload one or more files to a WWW
+ server, using standard HTML forms instead of FTP. It works with
+ Netscape 3.0 and 4.0, and Internet Explorer 4.0.
+
+ See the manpage for more information.
+
+ AUTHOR
+
+ Jeroen C. Kessels
+ Internet Engineer
+ mailto:jeroen@kessels.com http://www.kessels.com/
+ Tel: +31(0)654 744 702
+
+
+ COPYRIGHT
+
+ Jeroen C. Kessels
+ 9 december 2000
+
+
+ VERSION 2.6
+
+*/
+
+
+
+
+#include
+#include
+#include
+#include
+#ifdef unix
+#include
+#else
+#include
+#ifdef _MSC_VER
+#include
+#else
+#include
+#endif
+#endif
+#include
+
+
+
+
+#ifdef unix
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#endif
+
+
+
+#define COPYRIGHT "Upload v2.6
© 2000 Jeroen C. Kessels\n
"
+#define NO 0
+#define YES 1
+#define MUST 2
+
+
+
+/* Define DIRSEP, the character that will be used to separate directories. */
+#ifdef unix
+#define DIRSEP "/\\"
+#else
+#define DIRSEP "\\/"
+#endif
+
+
+
+
+/* Configuration parameters from the configuration file. */
+char Root[BUFSIZ];
+char FileMask[BUFSIZ];
+int IgnoreSubdirs;
+int OverWrite;
+char LogFile[BUFSIZ];
+char OkPage[BUFSIZ];
+char OkUrl[BUFSIZ];
+char BadPage[BUFSIZ];
+char BadUrl[BUFSIZ];
+
+char UpFileName[BUFSIZ];
+int Debug;
+
+long FileCount;
+long ByteCount;
+char LastFileName[BUFSIZ];
+
+
+
+
+/* Translate character to lowercase. */
+char clower(char c) {
+ if ((c >= 'A') && (c <= 'Z')) return((c - 'A') + 'a');
+ return(c);
+ }
+
+
+
+
+/* Compare a string with a mask, case-insensitive. If it matches then return
+ YES, otherwise NO. The mask may contain wildcard characters '?' (any
+ character) '*' (any characters). */
+int MatchMask(char *String, char *Mask) {
+ char *m;
+ char *s;
+
+ if (String == NULL) return NO; /* Just to speed up things. */
+ if (Mask == NULL) return NO;
+ if (strcmp(Mask,"*") == 0) return YES;
+
+ m = Mask;
+ s = String;
+
+ while ((*m != '\0') && (*s != '\0')) {
+ if ((clower(*m) != clower(*s)) && (*m != '?')) {
+ if (*m != '*') return NO;
+ m++;
+ if (*m == '\0') return YES;
+ while (*s != '\0') {
+ if (MatchMask(s,m) == YES) return YES;
+ s++;
+ }
+ return NO;
+ }
+ m++;
+ s++;
+ }
+
+ while (*m == '*') m++;
+ if ((*s == '\0') && (*m == '\0')) return YES;
+ return NO;
+ }
+
+
+
+
+
+/* Translate the URL separator '/' into the directory separator ('/' for
+ UNIX, '\\' for DOS), making a proper pathname. */
+void Url2Dir(char *Dir, char *Url) {
+ char *p1;
+ char *p2;
+
+ p1 = Url;
+ p2 = Dir;
+ while (*p1 != '\0') {
+ if (*p1 == '/') {
+ *p2++ = *DIRSEP;
+ p1++;
+ } else {
+ *p2++ = *p1++;
+ }
+ }
+ *p2 = '\0';
+ }
+
+
+
+
+/* Return the last position in a string of any character from
+ collection. The haystack string is scanned from end to begin until a
+ character is found from the needle string. The pointer to the found
+ character is returned, or NULL if not found. This subroutine is
+ designed to find a directory separator in a path, where the directory
+ separator can be '\\' (DOS) or '/' (UNIX). */
+char *strrchrs(char *haystack,char *needle) {
+ char *h_here;
+ char *n_here;
+ long h_length;
+
+ if ((haystack == NULL) || (needle == NULL)) return(NULL);
+
+ for (h_length = 0, h_here = haystack; *h_here != '\0'; h_here++, h_length++);
+ while (h_length > 0) {
+ h_here--;
+ h_length--;
+ n_here = needle;
+ while (*n_here != '\0') {
+ if (*n_here == *h_here) return(h_here);
+ n_here++;
+ }
+ }
+
+ return(NULL);
+ }
+
+
+
+
+
+/* Create all directories in the path. The permissions of the directory at
+ From are used for the new directory, leave NULL for default permissions.
+ If IsAdir=NO then the path points to a filename, otherwise it is a
+ directoryname. */
+void CreatePath(char *To, char *From, int IsAdir) {
+#ifdef unix
+ struct stat statbuf;
+#endif
+ char s1[BUFSIZ];
+ char s2[BUFSIZ];
+ char *p1;
+
+ if (To == NULL) return;
+
+ /* If the Path contains subdirectories, then strip the last directory and
+ iterate. */
+ strcpy(s1,To);
+ if (From != NULL) {
+ strcpy(s2,From);
+ } else {
+ *s2 ='\0';
+ }
+ p1 = strrchrs(s1,DIRSEP);
+ if (p1 != NULL) {
+ *p1 = '\0';
+ p1 = strrchrs(s2,DIRSEP);
+ if (p1 == NULL) p1 = s2;
+ *p1 = '\0';
+ CreatePath(s1,s2,YES);
+ }
+
+ /* Create the directory. */
+ if (IsAdir == YES) {
+#ifdef unix
+ if ((From != NULL) && (*From != '\0') && (stat(From,&statbuf) == 0)) {
+ mkdir(To,statbuf.st_mode & 0777);
+ } else {
+ mkdir(To,0755);
+ }
+#else
+ if ((strlen(To) > 2) || (To[1] != ':')) mkdir(To);
+#endif
+ }
+ }
+
+
+
+
+
+/* Show the BadPage, with macro MESSAGE. */
+void ShowBadPage(char *Message) {
+ FILE *Fin;
+ char Line[BUFSIZ];
+ char s1[BUFSIZ];
+ char *p1;
+
+ if (*BadUrl != '\0') {
+ fprintf(stdout,"Location: %s\n\n",BadUrl);
+ return;
+ }
+
+ if (Debug == 0) fprintf(stdout,"Content-type: text/html\n\n");
+
+ Fin = fopen(BadPage,"r");
+ if (Fin == NULL) {
+ fprintf(stdout,"\n\n",Message);
+ if (*BadPage != '\0') {
+ fprintf(stdout,"Error: could not open the BadPage: %s\n",BadPage);
+ fprintf(stdout,"The original error message was:
\n");
+ }
+ fprintf(stdout,"%s\n",Message);
+ fprintf(stdout,"\n\n",Message);
+ exit(0);
+ }
+
+ while (fgets(Line,BUFSIZ,Fin) != NULL) {
+ p1 = Line;
+ while (*p1 != '\0') {
+ if (strnicmp(p1,"",15) == 0) {
+ *p1 = '\0';
+ sprintf(s1,"%s%s%s",Line,Message,p1 + 16);
+ strcpy(Line,s1);
+ }
+ p1++;
+ }
+ fprintf(stdout,"%s",Line);
+ }
+
+ exit(0);
+ }
+
+
+
+
+/* Write a line to the logging file. */
+void WriteLogLine(char *Line) {
+ FILE *Fout;
+ char s1[BUFSIZ];
+ time_t Now;
+
+ if (*LogFile == '\0') return;
+
+ Fout = fopen(LogFile,"a");
+ if (Fout == NULL) {
+ sprintf(s1,"I could not open the logfile: %s",LogFile);
+ ShowBadPage(s1);
+ }
+ Now = time(NULL);
+ strcpy(s1,ctime(&Now));
+ s1[24] = '\0';
+ fprintf(Fout,"%s %s\n",s1,Line);
+ fclose(Fout);
+ }
+
+
+
+
+/* Show the OkPage, with statistics about the file. */
+void ShowOkPage(void) {
+ FILE *Fin;
+ char Line[BUFSIZ];
+ char s1[BUFSIZ];
+ char *p1;
+
+ if (*OkUrl != '\0') {
+ fprintf(stdout,"Location: %s\n\n",OkUrl);
+ return;
+ }
+
+ Fin = fopen(OkPage,"r");
+ if (Fin == NULL) {
+ sprintf(s1,"I could not open the OkPage: %s",OkPage);
+ ShowBadPage(s1);
+ }
+ if (Debug == 0) fprintf(stdout,"Content-type: text/html\n\n");
+ while (fgets(Line,BUFSIZ,Fin) != NULL) {
+ p1 = Line;
+ while (*p1 != '\0') {
+ if (strnicmp(p1,"",18) == 0) {
+ *p1 = '\0';
+ sprintf(s1,"%s%lu%s",Line,FileCount,p1 + 18);
+ strcpy(Line,s1);
+ }
+ if (strnicmp(p1,"",18) == 0) {
+ *p1 = '\0';
+ sprintf(s1,"%s%lu%s",Line,ByteCount,p1 + 18);
+ strcpy(Line,s1);
+ }
+ if (strnicmp(p1,"",21) == 0) {
+ *p1 = '\0';
+ sprintf(s1,"%s%s%s",Line,LastFileName,p1 + 21);
+ strcpy(Line,s1);
+ }
+ p1++;
+ }
+ fprintf(stdout,"%s",Line);
+ }
+
+ exit(0);
+ }
+
+
+
+
+/* Load the proper segment from the configuration file. */
+void LoadConfig(char *ProgramPath, char *ConfigID) {
+ FILE *Fin;
+ char Path[BUFSIZ];
+ char Line[BUFSIZ];
+ char Name[BUFSIZ];
+ char Value[BUFSIZ];
+ int Accept;
+ int NewDebug;
+ char *p1;
+ char *p2;
+
+ strcpy(Path,ProgramPath);
+ p1 = strrchrs(Path,"./\\");
+ if (p1 != NULL) {
+ strcpy(p1,".cfg");
+ } else {
+ strcat(Path,".cfg");
+ }
+ Fin = fopen(Path,"rt");
+ if (Fin == NULL) {
+ p1 = getenv("PATH");
+ while ((p1 != NULL) && (*p1 != '\0')) {
+ p2 = Value;
+ while ((*p1 != '\0') && (*p1 != ';')) *p2++ = *p1++;
+ *p2 = '\0';
+ if (*p1 == ';') p1++;
+ sprintf(Name,"%s%cupload.cfg",Value,*DIRSEP);
+ Fin = fopen(Name,"rt");
+ if (Fin != NULL) break;
+ }
+ }
+ if (Fin == NULL) ShowBadPage("I could not open the configuration file.");
+
+ if (Debug > 0) fprintf(stdout,"\n");
+ Accept = NO;
+ NewDebug = Debug;
+ while (fgets(Line,BUFSIZ,Fin) != NULL) {
+ *Name = *Value = '\0';
+ if (sscanf(Line,"%[^ \t=]%*[ \t=]%[^\n\r]",Name,Value) != 2) {
+ sscanf(Line,"%*[ \t]%[^ \t=]%*[ \t=]%[^\n\r]",Name,Value);
+ }
+ if (stricmp(Name,"Config") == 0) {
+ if (Accept == YES) {
+ if (Debug > 0) fprintf(stdout,"\n\n\n");
+ if ((Debug == 0) && (NewDebug > 0)) {
+ fprintf(stdout,"Content-type: text/html\n\n");
+ fprintf(stdout,"\n
\n");
+ fprintf(stdout,"\n");
+ fprintf(stdout,"\n\n");
+ fprintf(stdout,"%s\n",COPYRIGHT);
+ }
+ Debug = NewDebug;
+ return;
+ }
+ if ((ConfigID == NULL) || (*ConfigID == '\0')) {
+ Accept = YES;
+ } else {
+ if (stricmp(ConfigID,Value) == 0) Accept = YES;
+ }
+ if (Debug > 0) {
+ if (Accept == YES) {
+ fprintf(stdout,"Loading configuration
\"%s\"\n",Value);
+ fprintf(stdout,"\n");
+ }
+ }
+ continue;
+ }
+ if (Accept != NO) {
+ if (Debug > 0) {
+ fprintf(stdout,"| %s | %s |
\n",Name,Value);
+ }
+ if (stricmp(Name,"Debug") == 0) NewDebug = atoi(Value);
+ if (stricmp(Name,"Root") == 0) {
+ Url2Dir(Root,Value);
+ p1 = strchr(Root,'\0');
+ if (p1 != Root) p1--;
+ if ((p1 != Root) && (strchr(DIRSEP,*p1) == NULL)) {
+ p1++;
+ *p1++ = *DIRSEP;
+ *p1 = '\0';
+ }
+ }
+ if (stricmp(Name,"FileMask") == 0) strcpy(FileMask,Value);
+ if (stricmp(Name,"LogFile") == 0) Url2Dir(LogFile,Value);
+ if (stricmp(Name,"OkPage") == 0) Url2Dir(OkPage,Value);
+ if (stricmp(Name,"OkUrl") == 0) strcpy(OkUrl,Value);
+ if (stricmp(Name,"BadPage") == 0) Url2Dir(BadPage,Value);
+ if (stricmp(Name,"BadUrl") == 0) strcpy(BadUrl,Value);
+ if (stricmp(Name,"OverWrite") == 0) {
+ if (stricmp(Value,"no") == 0) OverWrite = NO;
+ if (stricmp(Value,"yes") == 0) OverWrite = YES;
+ if (stricmp(Value,"must") == 0) OverWrite = MUST;
+ }
+ if (stricmp(Name,"IgnoreSubdirs") == 0) {
+ if (stricmp(Value,"no") == 0) IgnoreSubdirs = NO;
+ if (stricmp(Value,"yes") == 0) IgnoreSubdirs = YES;
+ }
+ }
+ }
+ if (Debug > 0) {
+ if (Accept == YES) {
+ fprintf(stdout,"
\n\n\n");
+ } else {
+ fprintf(stdout,
+ "\nConfiguration \"%s\" not found, using defaults instead.
\n",
+ ConfigID);
+ }
+ }
+ if ((Debug == 0) && (NewDebug > 0)) {
+ fprintf(stdout,"Content-type: text/html\n\n");
+ fprintf(stdout,"\n
\n");
+ fprintf(stdout,"\n");
+ fprintf(stdout,"\n\n");
+ fprintf(stdout,"%s\n",COPYRIGHT);
+ }
+ Debug = NewDebug;
+ }
+
+
+
+
+
+/* Skip a line in the input stream. */
+void SkipLine(char **Input, /* Pointer into the incoming stream. */
+ long *InputLength) { /* Bytes left in the incoming stream. */
+
+ while ((**Input != '\0') && (**Input != '\r') && (**Input != '\n')) {
+ *Input = *Input + 1;
+ *InputLength = *InputLength - 1;
+ }
+ if (**Input == '\r') {
+ *Input = *Input + 1;
+ *InputLength = *InputLength - 1;
+ }
+ if (**Input == '\n') {
+ *Input = *Input + 1;
+ *InputLength = *InputLength - 1;
+ }
+ }
+
+
+
+
+
+/* Accept a single segment from the incoming mime stream. Each field in the
+ form will generate a mime segment. Return a pointer to the beginning of
+ the Boundary, or NULL if the stream is exhausted. */
+void AcceptSegment(char **Input, /* Pointer into the incoming stream. */
+ long *InputLength, /* Bytes left in the incoming stream. */
+ char *Boundary, /* Character string that delimits segments. */
+ char *ProgramPath) {
+ char FieldName[BUFSIZ]; /* Name of the variable from the form. */
+ char FileName[BUFSIZ]; /* The filename, as selected by the user. */
+ char *ContentStart; /* Pointer to the file content. */
+ char *ContentEnd;
+ char ContentAsString[BUFSIZ];
+ long ContentLength; /* Bytecount of the content. */
+ char Key1[BUFSIZ];
+ char Key2[BUFSIZ];
+ char Path[BUFSIZ];
+ FILE *Fout;
+ long Result;
+ char s1[BUFSIZ];
+ char *p1;
+ int i;
+
+ /* The input stream should begin with a Boundary line. Error-exit if not
+ found. */
+ if (strncmp(*Input,Boundary,strlen(Boundary)) != 0) {
+ sprintf(s1,"Missing boundary in input.");
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ }
+
+ /* Skip the Boundary line. */
+ *Input = *Input + strlen(Boundary);
+ *InputLength = *InputLength - strlen(Boundary);
+ SkipLine(Input,InputLength);
+
+ /* Return NULL if the stream is exhausted (no more segments). */
+ if ((**Input == '\0') || (strncmp(*Input,"--",2) == 0)) {
+ *InputLength = 0;
+ return;
+ }
+
+ /* The first line of a segment must be a "Content-Disposition" line. It
+ contains the fieldname, and optionally the original filename. Error-exit
+ if the line is not recognised. */
+ if (sscanf(*Input,"%[^:]: %[^;]; name=\"%[^\"]\"; filename=\"%[^\"]\"",
+ Key1,Key2,FieldName,FileName) != 4) {
+ *FileName = '\0';
+ if (sscanf(*Input,"%[^:]: %[^;]; name=\"%[^\"]\"",Key1,Key2,
+ FieldName) != 3) {
+ *FieldName = '\0';
+ if (sscanf(*Input,"%[^:]: %[^;]; filename=\"%[^\"]\"",Key1,Key2,
+ FileName) != 3) {
+ sscanf(*Input,"%[^\r\n]",Key1);
+ sprintf(s1,"Disposition line not recognised: %s",Key1);
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ }
+ }
+ }
+ if (stricmp(Key1,"content-disposition") != 0) {
+ sprintf(s1,"\"Content-Disposition\" expected, but I got \"%s\" instead.",
+ Key1);
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ }
+ if (stricmp(Key2,"form-data") != 0) {
+ sprintf(s1,"\"form-data\" expected, but I got \"%s\" instead.",Key2);
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ }
+
+ /* Skip the Disposition line and one or more mime lines, until an empty
+ line is found. */
+ SkipLine(Input,InputLength);
+ while ((**Input != '\r') && (**Input != '\n')) SkipLine(Input,InputLength);
+ SkipLine(Input,InputLength);
+
+ /* The following data in the stream is binary. The Boundary string is the
+ end of the data. There may be a CRLF just before the Boundary, which
+ must be stripped. */
+ ContentStart = *Input;
+ ContentLength = 0;
+ while ((*InputLength > 0) && (memcmp(*Input,Boundary,strlen(Boundary)) != 0)) {
+ *Input = *Input + 1;
+ *InputLength = *InputLength - 1;
+ ContentLength = ContentLength + 1;
+ }
+ ContentEnd = *Input - 1;
+ if ((ContentLength > 0) && (*ContentEnd == '\n')) {
+ ContentEnd--;
+ ContentLength = ContentLength - 1;
+ }
+ if ((ContentLength > 0) && (*ContentEnd == '\r')) {
+ ContentEnd--;
+ ContentLength = ContentLength - 1;
+ }
+ i = BUFSIZ - 1;
+ if (ContentLength < i) i = ContentLength;
+ strncpy(ContentAsString,ContentStart,i);
+ ContentAsString[i] = '\0';
+
+ if (ContentEnd) {}; /* Keep lint happy... */
+
+ /* Show debugging information. */
+ if (Debug > 0) {
+ fprintf(stdout,"\n");
+ fprintf(stdout," | ");
+ if (*FieldName != '\0') fprintf(stdout,"%s",FieldName);
+ fprintf(stdout," | \n");
+ fprintf(stdout," ");
+ if (*FileName != '\0') {
+ fprintf(stdout,"%s",FileName);
+ } else {
+ fprintf(stdout,"%s",ContentAsString);
+ }
+ fprintf(stdout," | \n");
+ fprintf(stdout," %ld | \n",ContentLength);
+ fprintf(stdout,"
\n");
+ }
+
+ /* If this field is the "Config" field, then load the configuration and
+ leave. */
+ if ((stricmp(FieldName,"Config") == 0) &&
+ (*FileName == '\0') &&
+ (*ContentStart != '\0')) {
+ if (Debug > 0) fprintf(stdout,"| ");
+ LoadConfig(ProgramPath,ContentAsString);
+ if (Debug > 0) fprintf(stdout," |
\n");
+ return;
+ }
+
+ /* If this field is the "FileName" field, then store it and leave. */
+ if ((stricmp(FieldName,"FileName") == 0) &&
+ (*FileName == '\0') &&
+ (*ContentStart != '\0')) {
+ strcpy(UpFileName,ContentAsString);
+ if (Debug > 0) {
+ fprintf(stdout,"| New filename stored. |
\n");
+ }
+ return;
+ }
+
+ /* If this field is the "OkPage" field, then store it and leave. */
+ if ((stricmp(FieldName,"OkPage") == 0) &&
+ (*FileName == '\0') &&
+ (*ContentStart != '\0')) {
+ Url2Dir(OkPage,ContentAsString);
+ if (Debug > 0) {
+ fprintf(stdout,"| New OkPage stored. |
\n");
+ }
+ return;
+ }
+
+ /* If this field is the "OkUrl" field, then store it and leave. */
+ if ((stricmp(FieldName,"OkUrl") == 0) &&
+ (*FileName == '\0') &&
+ (*ContentStart != '\0')) {
+ strcpy(OkUrl,ContentAsString);
+ if (Debug > 0) {
+ fprintf(stdout,"| New OkUrl stored. |
\n");
+ }
+ return;
+ }
+
+ /* If this field is the "BadPage" field, then store it and leave. */
+ if ((stricmp(FieldName,"BadPage") == 0) &&
+ (*FileName == '\0') &&
+ (*ContentStart != '\0')) {
+ Url2Dir(BadPage,ContentAsString);
+ if (Debug > 0) {
+ fprintf(stdout,"| New BadPage stored. |
\n");
+ }
+ return;
+ }
+
+ /* If this field is the "BadUrl" field, then store it and leave. */
+ if ((stricmp(FieldName,"BadUrl") == 0) &&
+ (*FileName == '\0') &&
+ (*ContentStart != '\0')) {
+ strcpy(BadUrl,ContentAsString);
+ if (Debug > 0) {
+ fprintf(stdout,"| New BadUrl stored. |
\n");
+ }
+ return;
+ }
+
+ /* Do nothing if this is not a file, but some other kind of field. */
+ if ((FileName == NULL) || (*FileName == '\0')) {
+ if (Debug > 0) {
+ fprintf(stdout,"| FieldName not recognised. |
\n");
+ }
+ return;
+ }
+
+ /* Determine the filename to store the file. If the UpFileName field was
+ defined then use it, otherwise use the name of the incoming file. The
+ ROOT is always prepended. */
+ if (*UpFileName == '\0') strcpy(UpFileName,FileName);
+ if (IgnoreSubdirs == YES) {
+ p1 = strrchrs(UpFileName,DIRSEP);
+ if (p1 != NULL) {
+ p1++;
+ strcpy(UpFileName,p1);
+ }
+ }
+ sprintf(Path,"%s%s",Root,UpFileName);
+
+ /* Test if the filename matches the mask. */
+ if (MatchMask(Path,FileMask) == NO) {
+ sprintf(s1,
+ "The file is rejected because it does not match the mask.
Filename: %s
Mask: %s",
+ Path,FileMask);
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ }
+
+ /* Test if the file already exists. */
+ if (OverWrite != YES) {
+ Fout = fopen(Path,"r");
+ if ((OverWrite == NO) && (Fout != NULL)) {
+ fclose(Fout);
+ sprintf(s1,
+ "The file could not be uploaded because it already exists.
Filename: %s",
+ Path);
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ }
+ if ((OverWrite == MUST) && (Fout == NULL)) {
+ sprintf(s1,
+ "The file could not be uploaded because it does not exist already.
Filename: %s",
+ Path);
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ }
+ if (Fout != NULL) fclose(Fout);
+ }
+
+ /* If needed then create directories for the file. */
+ CreatePath(Path,NULL,NO);
+
+ /* Open the file for writing. */
+#ifndef unix
+ Fout = fopen(Path,"w");
+#else
+ Fout = fopen(Path,"wb");
+#endif
+ if (Fout == NULL) {
+ sprintf(s1,
+ "The file could not be uploaded because write permission is denied.
Filename: %s",
+ Path);
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ }
+#ifndef unix
+ setmode(fileno(Fout),O_BINARY);
+#endif
+
+ /* Write the file to disk. */
+ Result = fwrite(ContentStart,1,ContentLength,Fout);
+ fclose(Fout);
+
+ /* If the wrong number of bytes were written to disk, then show an error
+ message. */
+ if (Result != ContentLength) {
+ sprintf(s1,
+ "The wrong number of bytes were written.
Written: %ld
Bytes in input: %ld",
+ Result,ContentLength);
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ }
+
+ /* Show debugging information. */
+ if (Debug > 0) {
+ fprintf(stdout,"\n");
+ fprintf(stdout," | File written: %s | \n",Path);
+ fprintf(stdout,"
\n");
+ }
+
+ FileCount = FileCount + 1;
+ ByteCount = ByteCount + ContentLength;
+ strcpy(LastFileName,UpFileName);
+
+ sprintf(s1,"File uploaded succesfully: %s (%lu bytes)",
+ UpFileName,ContentLength);
+ WriteLogLine(s1);
+
+ /* Clear the filename. */
+ *UpFileName = '\0';
+
+ return;
+ }
+
+
+
+
+
+int main(int argc, char *argv[], char *environment[]) {
+ char *Method; /* Pointer to REQUEST_METHOD environment variable. */
+ char *ContentLength; /* Pointer to CONTENT_LENGTH environment variable. */
+ char *ContentType; /* Pointer to CONTENT_TYPE environment variable. */
+ long InCount; /* The supposed number of incoming bytes. */
+ long RealCount; /* Actual number of incoming bytes. */
+ char *Content; /* Copy in memory of the Content. */
+ char *Here; /* Position into the Content. */
+ char Boundary[BUFSIZ]; /* The boundary string between segments. */
+
+ char Char;
+ long MoreCount;
+ char *p1;
+ char s1[BUFSIZ];
+
+ if (argc > 1) {
+ fprintf(stdout,"Error: %s is a cgi program, and should not be ",argv[0]);
+ fprintf(stdout,"started from the command line.\n");
+ exit(1);
+ }
+
+ *Root = '\0'; /* Setup defaults. */
+ strcpy(FileMask,"*");
+ IgnoreSubdirs = YES;
+ OverWrite = YES;
+ *LogFile = '\0';
+ *OkPage = '\0';
+ *OkUrl = '\0';
+ *BadPage = '\0';
+ *BadUrl = '\0';
+ Debug = 0;
+ *UpFileName = '\0';
+ FileCount = 0;
+ ByteCount = 0;
+ *LastFileName = '\0';
+
+ if (environment) {}; /* Keep lint() happy. */
+
+ if (Debug > 0) {
+ fprintf(stdout,"Content-type: text/html\n\n");
+ fprintf(stdout,"\n\n");
+ fprintf(stdout,"\n");
+ fprintf(stdout,"\n\n");
+ fprintf(stdout,"%s\n",COPYRIGHT);
+ }
+
+ LoadConfig(argv[0],""); /* Load default configuration. */
+
+ /* Test if the program was started by a METHOD=POST form. */
+ Method = getenv("REQUEST_METHOD");
+ if ((Method == NULL) || (*Method == '\0') || (stricmp(Method,"post") != 0)) {
+ ShowBadPage("Sorry, this program only supports METHOD=POST.");
+ }
+ if (Debug > 0) fprintf(stdout,"Loading input
\n",Method);
+ if (Debug > 0) fprintf(stdout,"Method = %s
\n",Method);
+
+ /* Test if the program was started with ENCTYPE="multipart/form-data". */
+ ContentType = getenv("CONTENT_TYPE");
+ if ((ContentType == NULL) ||
+ (strnicmp(ContentType,"multipart/form-data; boundary=",30) != 0)) {
+ ShowBadPage("Sorry, this program only supports ENCTYPE=\"multipart/form-data\".");
+ }
+ if (Debug > 0) fprintf(stdout,"Enctype = %s
\n",ContentType);
+
+ /* Determine the Boundary, the string that separates the segments in the
+ stream. The boundary is available from the CONTENT_TYPE environment
+ variable. */
+ Here = strchr(ContentType,'=') + 1;
+ sprintf(Boundary,"--%s",Here);
+ if (Debug > 0) fprintf(stdout,"Boundary = %s
\n",Boundary);
+
+ /* Get the total number of bytes in the input stream from the
+ CONTENT_LENGTH environment variable. */
+ ContentLength = getenv("CONTENT_LENGTH");
+ if (ContentLength == NULL) {
+ WriteLogLine("Error: no CONTENT_LENGTH found.");
+ ShowBadPage("Error: no CONTENT_LENGTH found.");
+ }
+ InCount = atol(ContentLength);
+ if (InCount == 0) {
+ WriteLogLine("Error: CONTENT_LENGTH is zero.");
+ ShowBadPage("Error: CONTENT_LENGTH is zero.");
+ }
+ if (Debug > 0) fprintf(stdout,"Content_Length = %d
\n",InCount);
+
+ /* Allocate sufficient memory for the incoming data. */
+ Content = (char *)malloc(InCount + 1);
+ if (Content == NULL) {
+ WriteLogLine("Error: malloc() returned NULL.");
+ ShowBadPage("Error: malloc() returned NULL.");
+ }
+
+ /* Load the data from standard input into memory. */
+#ifndef unix
+ setmode(fileno(stdin),O_BINARY); /* Make sure the input is binary... */
+#endif
+ p1 = Content;
+ RealCount = 0;
+ /* For some reason fread() of Borland C 4.52 barfs if the bytecount is
+ bigger than 2.5Mb, so I have to do it like this. */
+ while (fread(p1++,1,1,stdin) == 1) {
+ RealCount++;
+ if (RealCount >= InCount) break;
+ }
+ *p1 = '\0';
+ /* Ignore any extra caracters. We have to read them, or the server
+ will give an error message. */
+ if (RealCount < InCount) {
+ MoreCount = InCount - RealCount;
+ while ((MoreCount > 0) && (fread(&Char,1,1,stdin) == 1)) MoreCount--;
+ }
+ if (RealCount != InCount) {
+ free(Content);
+ sprintf(s1,
+ "Error: The number of bytes received (%ld) is not what the CONTENT_LENGTH environment variable says it sould be (%ld).",
+ RealCount + MoreCount, InCount);
+ WriteLogLine(s1);
+ ShowBadPage(s1);
+ return(0);
+ }
+ if (Debug > 0) fprintf(stdout,"Input succesfully loaded into memory.
\n");
+
+ /* Handle all segments in the incoming data, that has been stored in
+ memory. */
+ Here = Content;
+ if (Debug > 0) {
+ fprintf(stdout,"\n
\nParsing input
\n");
+ fprintf(stdout,"\n");
+ fprintf(stdout,"\n");
+ fprintf(stdout," | Fieldname | \n");
+ fprintf(stdout," Contents | \n");
+ fprintf(stdout," Size | \n");
+ fprintf(stdout,"
\n");
+ }
+ while (RealCount > 0) AcceptSegment(&Here,&RealCount,Boundary,argv[0]);
+ if (Debug > 0) fprintf(stdout,"
\n\n");
+
+ /* Cleanup. */
+ free(Content);
+
+ if (*LastFileName == '\0') ShowBadPage("You have not specified a file, so nothing was uploaded.");
+
+ /* Display the OkPage. */
+ if (Debug > 0) {
+ fprintf(stdout,"Finished
\n");
+ }
+ ShowOkPage();
+ return(0);
+ }
+
+
+/*
+Ideeen:
+
+- Multiple filemasks.
+- Maximum directory size.
+- Maximum and Minimum file size.
+- Result-macros as parameters to OkUrl.
+
+*/
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/upload.cfg b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/upload.cfg
new file mode 100644
index 0000000000..74683981a3
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/upload.cfg
@@ -0,0 +1,9 @@
+Config = Default
+ Root = /www/upload/files
+ FileMask = *
+ IgnoreSubdirs = YES
+ Overwrite = YES
+ LogFile = /www/upload/files/upload.log
+ OkPage = /www/upload/OkPage.html
+ BadPage = /www/upload/BadPage.html
+ Debug = 0
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/uptime b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/uptime
new file mode 100755
index 0000000000..3ff6b372b8
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/cgi-bin/uptime
@@ -0,0 +1,12 @@
+#!/bin/sh
+echo "Content-type: text/html"
+echo
+echo ""
+echo ""
+echo ""
+echo "Uptime information
"
+echo "Your embedded device has been running for:"
+echo `uptime`
+echo "
"
+echo "
"
+echo ""
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/gohome.png b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/gohome.png
new file mode 100644
index 0000000000..ae0520383f
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/gohome.png differ
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/index.html b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/index.html
new file mode 100644
index 0000000000..ae0c4ffe42
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/index.html
@@ -0,0 +1,24 @@
+
+
+ACME ultra-tiny image server
+
+
+ACME ultra-tiny image server
+Congratulations for your new device!
+Device information
+
+Upload image files
+
+
+
+List file collection
+
+
Reboot your system
+
+
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/kshutdown.png b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/kshutdown.png
new file mode 100644
index 0000000000..a71ed470c3
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/kshutdown.png differ
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/BadPage.html b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/BadPage.html
new file mode 100644
index 0000000000..51c483bf98
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/BadPage.html
@@ -0,0 +1,10 @@
+
+
+Upload failure!
+
+
+
+
+
+
+
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/OkPage.html b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/OkPage.html
new file mode 100644
index 0000000000..9e1348fa28
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/OkPage.html
@@ -0,0 +1,12 @@
+
+
+Successful upload!
+
+File uploaded:
+Bytes uploaded:
+
+
+
+
+
+
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/adult-small.png b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/adult-small.png
new file mode 100644
index 0000000000..d6ea415bd5
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/adult-small.png differ
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/brick.png b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/brick.png
new file mode 100644
index 0000000000..d5b771ef0f
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/brick.png differ
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/linux-blackfin.jpg b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/linux-blackfin.jpg
new file mode 100644
index 0000000000..a1d314d191
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/linux-blackfin.jpg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/linux-kernel-dev-book.jpg b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/linux-kernel-dev-book.jpg
new file mode 100644
index 0000000000..628f6df850
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/linux-kernel-dev-book.jpg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/lkn-small.jpg b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/lkn-small.jpg
new file mode 100644
index 0000000000..82c0559db6
Binary files /dev/null and b/lab-data/embedded-linux-imx93-frdm/tinysystem/data/www/upload/files/lkn-small.jpg differ
diff --git a/lab-data/embedded-linux-imx93-frdm/toolchain/hello.c b/lab-data/embedded-linux-imx93-frdm/toolchain/hello.c
new file mode 100644
index 0000000000..22e78e7fe7
--- /dev/null
+++ b/lab-data/embedded-linux-imx93-frdm/toolchain/hello.c
@@ -0,0 +1,8 @@
+#include
+#include
+
+int main (void)
+{
+ printf( "Hello world!\n" );
+ return EXIT_SUCCESS;
+}
diff --git a/labs/sysdev-accessing-hardware-imx93-frdm/imx93-frdm-connect-gpio.jpg b/labs/sysdev-accessing-hardware-imx93-frdm/imx93-frdm-connect-gpio.jpg
new file mode 100644
index 0000000000..5139cc6ad7
Binary files /dev/null and b/labs/sysdev-accessing-hardware-imx93-frdm/imx93-frdm-connect-gpio.jpg differ
diff --git a/labs/sysdev-accessing-hardware-imx93-frdm/sysdev-accessing-hardware-imx93-frdm.tex b/labs/sysdev-accessing-hardware-imx93-frdm/sysdev-accessing-hardware-imx93-frdm.tex
new file mode 100644
index 0000000000..aefbb8581d
--- /dev/null
+++ b/labs/sysdev-accessing-hardware-imx93-frdm/sysdev-accessing-hardware-imx93-frdm.tex
@@ -0,0 +1,701 @@
+\subchapter{Accessing Hardware Devices}
+{Objective: learn how to access hardware devices and declare new ones.}
+
+\section{Goals}
+
+Now that we have access to a command line shell thanks to a working root
+filesystem, we can now explore existing devices and make new ones
+available. In particular, we will make changes to the Device Tree
+and compile an out-of-tree Linux kernel module.
+
+\section{Setup}
+
+Go to the \code{$HOME/__SESSION_NAME__-labs/hardware} directory,
+which provides useful files for this lab.
+
+However, we will go on booting the system through NFS, using the
+root filesystem built by the previous lab.
+
+\section{Exploring /dev}
+
+Start by exploring \code{/dev} on your target system. Here are a few
+noteworthy device files that you will see:
+
+\begin{itemize}
+ \item {\em Terminal devices}: devices starting with \code{tty}.
+ Terminals are user interfaces taking text as
+ input and producing text as output, and are typically used by
+ interactive shells. In particular, you will find
+ \code{console} which matches the device specified through
+ \code{console=} in the kernel command line. You will also find
+ the {\tt \ttyname} device file.
+ \item {\em Pseudo-terminal devices}: devices starting with \code{pty},
+ used when you connect through SSH for example. Those are virtual
+ devices, but there are so many in \code{/dev} that we wanted
+ to give a description here.
+ \item {MMC device(s) and partitions}: devices starting with
+ \code{mmcblk}. You should here recognize the MMC device(s)
+ on your system and the associated partitions.
+ \item If you have a real board (not QEMU) and a USB stick, you could
+ plug it in and if your kernel was built with USB host and mass
+ storage support, you should see a new \code{sda} device appear,
+ together with the \code{sda} devices for its partitions.
+\end{itemize}
+
+Don't hesitate to explore \code{/dev} on your workstation too
+and ask any questions to your instructor.
+
+\section{Exploring /sys}
+
+The next thing you can explore is the {\em Sysfs} filesystem.
+
+A good place to start is \code{/sys/class}, which exposes devices
+classified by the kernel frameworks which manage them.
+
+For example, go to \code{/sys/class/net}, and you will see all the
+networking interfaces on your system, whether they are internal,
+external or virtual ones.
+
+Find which subdirectory corresponds to the network connection
+to your host system, and then check device properties such as:
+\begin{itemize}
+ \item \code{speed}: will show you whether this is a gigabit
+ or hundred megabit interface.
+ \item \code{address}: will show the device MAC address. No
+ need to get it from a complex command!
+ \item \code{statistics/rx_bytes} will show you how many bytes
+ were received on this interface.
+\end{itemize}
+
+Don't hesitate to look for further interesting properties by yourself!
+
+Next, you can now explore all the buses (virtual or physical) available
+on your system, by checking the contents of \code{/sys/bus}.
+
+In particular, go to \code{/sys/bus/mmc/devices} to see all the
+MMC devices on your system. Go inside the directory for the first device
+and check several files (for example):
+
+\begin{itemize}
+\item \code{serial}: the serial number for your device.
+\item \code{preferred_erase_size}: the preferred erase block for your
+ device. It's recommended that partitions start at multiples of this
+ size.
+\item \code{name}: the product name for your device. You could display
+ it in a user interface or log file, for example.
+\item \code{date}: apparently the manufacturing date for the device.
+\end{itemize}
+
+Don't hesitate to spend more time exploring \code{/sys} on your system
+and asking questions to your instructor.
+
+\section{Driving GPIOs}
+
+At this stage, we can only explore GPIOs through the legacy interface
+in \code{/sys/class/gpio}, because the {\em libgpiod} interface
+commands are provided through a dedicated project which we have to
+build separately, and {\em Busybox} does not provide a
+re-implementation for the {\em libgpiod} tools. In a later lab, we
+will build {\em libgpiod} tools which use the modern
+\code{/dev/gpiochipX} interface.
+
+The first thing to do is to enable this legacy interface by enabling
+\kconfig{CONFIG_GPIO_SYSFS} in the kernel configuration.
+To do so, in recent Linux kernel versions the \kconfig{CONFIG_EXPERT}
+needs to be enable to have access to some legacy options and in our
+case to \kconfig{CONFIG_GPIO_SYSFS}.
+
+Also make sure {\em Debugfs} is enabled (\kconfig{CONFIG_DEBUG_FS} and
+\kconfig{CONFIG_DEBUG_FS_ALLOW_ALL}).
+
+After rebooting the new kernel, the first thing to do is to mount
+the {\em Debugfs} filesystem:
+
+\begin{bashinput}
+# mount -t debugfs debugfs /sys/kernel/debug/
+\end{bashinput}
+
+Then, you can check information about available GPIOs banks and which
+GPIOs are already in use:
+
+\begin{bashinput}
+# cat /sys/kernel/debug/gpio
+\end{bashinput}
+
+We are going to use one of the EXPI connector of the board,
+
+Take one of the F-F breadboard wires provided by your instructor and:
+\begin{itemize}
+ \item Connect one end to the \code{Pin 40} of the \code{EXPI} connector
+ \item Connect the other end to the \code{GND} pin of the \code{EXPI} connector
+\end{itemize}
+
+\includegraphics[width=0.3\textwidth]{labs/sysdev-accessing-hardware-imx93-frdm/imx93-frdm-connect-gpio.jpg}
+
+If you look at the board documentation, you will see that pin 40 is connected to GPIO\_IO21, which belongs to GPIO controller 2. However, GPIO controller 1 is not used, so this GPIO will be referenced under the label gpiochip0 in Linux. Furthermore, we are using GPIO 21 from gpiochip0, which corresponds to gpio-533.
+
+We now have everything we need to drive this GPIO using the legacy
+interface. First, let's enable it:
+
+\begin{bashinput}
+# cd /sys/class/gpio
+# echo %\gpionum% > export
+\end{bashinput}
+
+If indeed the pin is still available, this should create a new
+{\tt gpio\gpionum} file in \code{/sys/class/gpio}.
+
+We can now configure this pin as input:
+
+\begin{bashinput}
+# echo in > gpio%\gpionum%/direction
+\end{bashinput}
+
+And check its value:
+
+\begin{bashinput}
+# cat gpio%\gpionum%/value
+0
+\end{bashinput}
+
+The value should be \code{0} as the pin is connected to a ground level.
+
+Now, let's connect our GPIO pin to the \code{+3.3V} pin.
+
+Let's check the value again:
+
+\begin{bashinput}
+# cat gpio%\gpionum%/value
+1
+\end{bashinput}
+
+The value is \code{1} because our pin is connected to a 3.3V level now.
+
+You could use this GPIO to add a button switch to your board, for
+example.
+
+Note that you could also configure the pin as output and set its value
+through the \code{value} file. This way, you could add an external LED
+to your board, for example.
+
+Before moving on to the next section, you can also check
+\code{/sys/kernel/debug/gpio} again, and see that {\tt gpio-\gpionum} is now
+in use, through the sysfs interface, and is configured as an input pin.
+
+When you're done, you can see your GPIO free:
+
+\begin{bashinput}
+# echo %\gpionum% > unexport
+\end{bashinput}
+
+\section{Driving LEDs}
+
+First, make sure your kernel is compiled with
+\kconfigval{CONFIG_LEDS_CLASS}{y}, \kconfigval{CONFIG_LEDS_GPIO}{y}
+and \kconfigval{CONFIG_LEDS_TRIGGER_TIMER}{y}.
+
+Then, go to \code{/sys/class/leds} to see all the LEDs that you are allowed
+to control.
+
+Let's control the LED which is called
+\code{:heartbeat}.
+
+Go into the directory for this LED, and check its trigger (what
+routine is used to drive its value):
+
+\begin{bashinput}
+# cat trigger
+\end{bashinput}
+
+As you can see, there are many triggers to choose from, the current
+being \code{heartbeat}.
+
+You can disable all triggers by:
+
+\begin{bashinput}
+# echo none > trigger
+\end{bashinput}
+
+And then directly control the LED:
+
+\begin{bashinput}
+# echo 1 > brightness
+# echo 0 > brightness
+\end{bashinput}
+
+You could also use the \code{timer} trigger to light the LED
+with specified time on and time off:
+
+\begin{bashinput}
+# echo timer > trigger
+# echo 10 > delay_on
+# echo 200 > delay_off
+\end{bashinput}
+
+\section{Managing the I2C buses and devices}
+
+\subsection{Enabling an I2C bus}
+
+The next thing we want to do is connect an Nunchuk joystick
+to an I2C bus on our board. The I2C bus is very frequently used
+to connect all sorts of external devices. That's why we're covering
+it here.
+
+First, let’s see which I2C buses are already enabled:
+\begin{bashinput}
+# i2cdetect -l
+# i2cdetect -l
+i2c-1 i2c 44350000.i2c I2C adapter
+i2c-2 i2c 42530000.i2c I2C adapter
+i2c-0 i2c 44340000.i2c I2C adapter
+\end{bashinput}
+
+If we look at the SoC datasheet, we can see that \code{0x4434} is associated with the I2C1 controller, \code{0x4435} is associated with the I2C2 controller, and finally, \code{0x4253} is associated with the I2C3 controller.
+
+So, we are lucky that the first 3 Linux I2C names corresponds to the first 3
+datasheet names.
+
+In this lab we will be using the I2C1 bus to connect the Nunchuk
+because it is located on the 10-pin 2x5 2.54 mm connector and is easily
+accessible.
+
+However because this I2C controller is already enabled, we will
+first play with I2C4 (WKUP\_I2C0 in datasheet) and demonstrate
+how to enable it, even if we won't use I2C4 in the rest of the labs.
+
+\subsection{Customizing the Device Tree}
+
+Fortunately, I2C4 (LPI2C4 in datasheet of the soc) is already defined
+in one of the DTS includes used by the Device Tree for our board.
+In our case, that's in \kfile{arch/arm64/boot/dts/freescale/imx93.dtsi}.
+Look by yourself in this file, and you will find its definition, but with
+\code{status = "disabled";}. This means that this I2C controller is not
+enabled yet, and it's up to boards using it to do so.
+
+We could modify the \kfile{arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts} file
+for our board, but that's not a very good idea as this file is
+maintained by the kernel developers. The changes that you make could
+collide with future changes made by the maintainers for this file.
+
+A more futureproof idea is to create a new Device Tree file which
+includes the standard one, and adds custom definitions. So, create a
+new \code{arch/arm64/boot/dts/freescale/imx93-11x11-frdm-custom.dts} file containing:
+
+\begin{verbatim}
+/dts-v1/;
+#include "imx93-11x11-frdm.dts"
+
+&lpi2c4 {
+ status = "okay";
+};
+\end{verbatim}
+
+As you can see, it's also possible to include \code{dts} files, and not
+only \code{dtsi} ones.
+
+Why the \code{/delete-property/} statement? That's because we want to see what happens when a
+device doesn't have associated pin definitions yet.
+
+Modify the \kfile{arch/arm64/boot/dts/freescale/Makefile} file to add your custom
+Device Tree, and then have it compiled (\code{make dtbs}).
+
+Reboot your board with the update.
+
+Back to the running system, we can now see that there is one more
+I2C bus:
+
+\begin{bashinput}
+# i2cdetect -l
+i2c-3 i2c 42540000.i2c I2C adapter
+i2c-1 i2c 44350000.i2c I2C adapter
+i2c-2 i2c 42530000.i2c I2C adapter
+i2c-0 i2c 44340000.i2c I2C adapter
+\end{bashinput}
+
+Run the below command to confirm that the new bus has the same address
+as in the datasheet (\code{0x4254}):
+
+\bashcmd{ls -l /sys/bus/i2c/devices/i2c-3}
+
+Now, let's use \code{i2cdetect}'s capability to probe a bus for devices.
+Let's start by the bus associated to \code{i2c-1}:
+
+\begin{verbatim}
+# i2cdetect -r 1
+i2cdetect: WARNING! This program can confuse your I2C bus
+Continue? [y/N] y
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f
+00: -- -- -- -- -- -- -- -- -- -- -- -- --
+10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+20: -- -- UU -- -- UU -- -- -- -- -- -- -- -- -- --
+30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+70: -- -- -- -- -- -- -- --
+\end{verbatim}
+
+We can see three devices on this internal bus:
+\begin{itemize}
+\item Two at address \code{0x22} and \code{0x25}, indicated by \code{UU},
+ which means that there is a kernel driver actively
+ driving this device.
+\item One other devices at addresses \code{0x50}.
+ We just know that they are currently not bound to a kernel driver.
+\end{itemize}
+
+Now we have demonstrated how to enable an I2C bus, it's time to
+use the I2C1 bus, which will be connected to our Nunchuk device.
+
+\subsection{Adding and enabling an I2C device}
+
+Let's connect the Nunchuk provided by your instructor
+to the \busname\ bus on the board, using breadboard wires:
+
+\includegraphics[width=0.3\textwidth]{common/nunchuk-pinout.pdf}
+\includegraphics[width=0.7\textwidth]{common/imx93-frdm-connect-nunchuk.jpg}
+
+\begin{itemize}
+\item Connect the Nunchuk PWR pin to \code{+3.3V} pin of 10-pin 2x5 2.54 mm connector
+\item Connect the Nunchuk GND pin to \code{GND} pin of 10-pin 2x5 2.54 mm connector
+\item Connect the Nunchuk SCL pin to \code{SCL} pin of 10-pin 2x5 2.54 mm connector
+\item Connect the Nunchuk SDA pin to \code{SDA} pin of 10-pin 2x5 2.54 mm connector
+\end{itemize}
+
+If you didn't do any mistake, your new device should be detected at
+address \code{0x52}:
+
+\begin{verbatim}
+# i2cdetect -r 0
+i2cdetect: WARNING! This program can confuse your I2C bus
+Continue? [y/N] y
+ 0 1 2 3 4 5 6 7 8 9 a b c d e f
+00: -- -- -- -- -- -- -- -- -- -- -- -- --
+10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+40: -- -- -- -- -- -- -- -- -- -- -- -- 4c -- -- --
+50: -- -- 52 -- -- -- -- -- -- -- -- -- -- -- -- --
+60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
+70: -- -- -- -- -- -- -- --
+\end{verbatim}
+
+We will later compile an out-of-tree kernel module to support this device.
+
+\section{Plugging a USB audio headset}
+
+In the next labs, we are going to play audio using a USB audio headset.
+Let's see whether our kernel supports such hardware by plugging the
+headset provided by your instructor.
+
+Before plugging the device, look at the output of \code{lsusb}:
+
+\begin{bashinput}
+# lsusb
+Bus 001 Device 001: ID 1d6b:0002
+\end{bashinput}
+
+{\bf Known issue:} if you don't get any output from \code{lsusb},
+you may need to remove the power supply and power on the board
+again.
+
+Now, when you plug the USB headset, a number of messages should appear
+on the console, and running \code{lsusb} again should show an
+additional device:
+
+\begin{bashinput}
+# lsusb
+Bus 001 Device 001: ID 1d6b:0002
+Bus 001 Device 002: ID 1b3f:2008
+\end{bashinput}
+
+The device of vendor ID \code{1b3f} and product ID \code{2008} has
+appeared. Of course, this depends on the actual USB audio device
+that you used.
+
+The device also appears in \code{/sys/bus/usb/devices/}, in a
+directory whose name depends on the topology of the USB bus. When the
+device is plugged in the kernel messages show:
+
+\begin{bashinput}
+usb 1-1: new full-speed USB device number 2 using xhci-hcd
+\end{bashinput}
+
+So if we go in \code{/sys/bus/usb/devices/1-1}, we get the {\em
+sysfs} representation of this USB device:
+
+\begin{bashinput}
+# cd /sys/bus/usb/devices/1-1
+# cat idVendor
+1b3f
+# cat idProduct
+2008
+# cat manufacturer
+GeneralPlus
+# cat product
+USB Audio Device
+\end{bashinput}
+
+However, while the USB device is detected, we currently do not have
+any driver for this device, so no actual sound card is detected.
+
+\section{Enabling, installing and using in-tree kernel modules}
+
+Go back to the kernel source directory.
+
+The Linux kernel has a generic driver supporting all USB audio devices
+supporting the standard USB audio class. This driver can be enabled
+using the \kconfig{CONFIG_SND_USB_AUDIO} configuration option. Look
+for this parameter in the kernel configuration, and configure it
+as a module.
+
+So, instead of compiling the corresponding driver as a built-in as
+we did before, that's a good opportunity to practice with kernel modules.
+
+So, compile your modules:
+\begin{bashinput}
+make modules
+\end{bashinput}
+
+Then, following details given in the lectures, install the modules in our NFS
+root filesystem (\code{$HOME/__SESSION_NAME__-labs/tinysystem/nfsroot}).
+
+Also make sure to update the kernel image (\code{make Image.gz}), and reboot the
+board. Indeed, due to the changes we have made to the kernel source code,
+the kernel version is now \code{6.14.-dirty}, the {\em dirty}
+keyword indicating that the Git working tree has uncommitted changes.
+The modules are therefore installed in \code{/lib/modules/6.14.-dirty/},
+and the version of the running Linux kernel must match this.
+
+After rebooting, try to load the module that we need:
+
+\begin{bashinput}
+modprobe snd-usb-audio
+\end{bashinput}
+
+By running \code{lsmod}, see all the module dependencies that
+were loaded too.
+
+You can also see that a new USB device driver in
+\code{/sys/bus/usb/drivers/snd-usb-audio}. This directory shows which
+USB devices are bound to this driver.
+
+You can check that \code{/proc/asound} now exists (thanks to loading
+modules for ALSA, the Linux sound subsystem), and that one sound
+card is available:
+
+\begin{bashinput}
+# cat /proc/asound/cards
+ 0 [Device ]: USB-Audio - USB Audio Device
+ GeneralPlus USB Audio Device at usb-xhci-hcd.3.auto-1, full speed
+\end{bashinput}
+
+Check also the \code{/dev/snd} directory, which should now contain
+some character device files. These will be used by the user-space
+libraries and applications to access the audio devices.
+
+Modify your startup scripts so that the \code{snd-usb-audio} module
+is always loaded at startup.
+
+We cannot test the sound card yet, as we will need to build some
+software first. Be patient, this is coming soon.
+
+\section{Compiling and installing an out-of-tree kernel module}
+
+The next device we want to support is the I2C Nunchuk. There is a driver
+in the kernel to support it when connected to a Wiimote controller, but
+there is no such driver to support it as an I2C device.
+
+Fortunately, one is provided in
+\code{$HOME/__SESSION_NAME__-labs/hardware/data/nunchuk/nunchuk.c}. You can check
+\href{https://bootlin.com/training/kernel/}{Bootlin's Linux kernel and
+driver development course} to learn how to implement all sorts of device
+drivers for Linux.
+
+Go to this directory, and compile the out-of-tree module as follows:
+
+\begin{bashinput}
+make -C $HOME/__SESSION_NAME__-labs/kernel/linux M=$PWD
+\end{bashinput}
+
+Here are a few explanations:
+\begin{itemize}
+\item The \code{-C} option lets \code{make} know which Makefile to
+ use, here the toplevel Makefile in the kernel sources.
+\item \code{M=$PWD} tells the kernel Makefile to build external
+ module(s) from the file(s) in the current directory.
+\end{itemize}
+
+Now, you can install the compiled module in the NFS root filesystem
+by passing the \code{modules_install} target and specifying the
+target directory through the \code{INSTALL_MOD_PATH} variable:
+
+\begin{bashinput}
+make -C $HOME/__SESSION_NAME__-labs/kernel/linux \
+ M=$PWD \
+ INSTALL_MOD_PATH=$HOME/__SESSION_NAME__-labs/tinysystem/nfsroot \
+ modules_install
+\end{bashinput}
+
+You can see that this installs out-of-tree kernel modules under
+\code{lib/modules//updates/}.
+
+Back on the target, you can now check that your custom module can
+be loaded:
+
+\begin{bashinput}
+# modprobe nunchuk
+[ 4317.737978] nunchuk: loading out-of-tree module taints kernel.
+\end{bashinput}
+
+See \kdochtml{kbuild/modules} in kernel documentation
+for details about building out-of-tree kernel modules.
+
+However, run \code{i2cdetect -r 1} again. You will see that the
+Nunchuk is still detected, but still not driven by the kernel.
+Otherwise, it would be signaled by the \code{UU} character. You
+may also look at the \code{nunchuk.c} file and notice a
+\code{Nunchuk device probed successfully} message that you didn't
+see when loading the module.
+
+That's because the Linux kernel doesn't know about the Nunchuk
+device yet, even though the driver for this kind of devices is
+already loaded. Our device also has to be described in the Device Tree.
+
+You can confirm this by having a look at the contents of the
+\code{/sys/bus/i2c} directory. It contains two subdirectories:
+\code{devices} and \code{drivers}.
+
+In \code{drivers}, there should be a \code{nunchuk} subdirectory,
+but no symbolic link to a device yet. In \code{devices} you should
+see some devices, but not the Nunchuk one yet.
+
+\section{Declaring an I2C device}
+
+To allow the kernel to manage our Nunchuk device, let's declare the
+device in the custom Device Tree for our board. The declaration of the \busname\
+bus will then look as follows:
+
+\begin{verbatim}
+&lpi2c1 {
+ status = "okay";
+ clock-frequency = <100000>;
+
+ nunchuk: joystick@52 {
+ compatible = "nintendo,nunchuk";
+ reg = <0x52>;
+ };
+};
+\end{verbatim}
+
+Here are a few notes:
+\begin{itemize}
+\item The \code{clock-frequency} property is used to configure the bus
+ to operate at 100 KHz. This is supposed to be required for the
+ Nunchuk.
+\item The Nunchuk device is added through a child node in the I2C
+ controller node.
+\item For the kernel to {\em probe} and drive our device, it's required
+ that the \code{compatible} string matches one of the
+ \code{compatible} strings supported by the driver.
+\item The \code{reg} property is the address of the device on the
+ I2C bus. If it doesn't match, the driver will probe the device
+ but won't be able to communicate with it.
+\end{itemize}
+
+Recompile your Device Tree and reboot your kernel with the new binary.
+
+You can now load your module again, and this time, you should see that
+the Nunchuk driver probed the Nunchuk device:
+
+\begin{bashinput}
+# modprobe nunchuk
+[ 7.638431] nunchuk: loading out-of-tree module taints kernel.
+[ 7.669813] input: Wii Nunchuk as /devices/platform/bus@f0000/20030000.i2c/i2c-3/3-0052/input/input2
+[ 7.679188] Nunchuk device probed successfully
+\end{bashinput}
+
+List the contents of \code{/sys/bus/i2c/drivers/nunchuk} once again. You
+should now see a symbolic link corresponding to our new device.
+
+Also list \code{/sys/bus/i2c/devices/} again. You should now see the
+Nunchuk device, which can be recognized through its \code{0052} address.
+Follow the link and you should see a symbolic link back to the Nunchuk
+driver!
+
+We are not ready to use this input device yet, but at least we can test
+that we get bytes when buttons or the joypad are used. In the below
+command, use the same number as in the message you got in the console
+(\code{event2} for \code{input2} for example):
+
+\begin{bashinput}
+# cat /dev/input/event2 | od -x
+\end{bashinput}
+
+{\bf Caution}: using \code{od} directly on input event files should
+work but is currently broken with the Musl library. We are investigating
+this issue.
+
+We will use the Nunchuk to control audio playback in an upcoming lab.
+
+\section{Setting the board's model name}
+
+Modify the custom Device Tree file one last time to override the model
+name for your system. Set the \code{model} property to
+\code{BeaglePlay media player}. Don't hesitate to ask your
+instructor if you're not sure how.
+
+Recompile the device tree, and reboot the board with it. You should see
+the new model name in two different places:
+
+\begin{itemize}
+\item In the first kernel messages on the serial console.
+\item In \code{/sys/firmware/devicetree/base/model}. This can be
+ handy for a distribution to identify the device it's running on.
+ By the way, you can explore \code{/sys/firmware/devicetree} and
+ find that every subdirectory corresponds to a DT node, and every
+ file corresponds to a DT property.
+\end{itemize}
+
+\section{Committing kernel tree changes}
+
+Now that our changes to the kernel sources are over,
+create a branch for your changes and create a patch for them.
+{\bf Please don't skip this step} as we need it for the next labs.
+
+First, if not done yet, you should set your identity
+and e-mail address in git:
+
+\begin{bashinput}
+git config --global user.email "linus@bootlin.com"
+git config --global user.name "Linus Torvalds"
+\end{bashinput}
+
+This is necessary to create a commit with the \code{git commit -s}
+command, as required by the Linux kernel contribution guidelines.
+
+Let's create the branch and the patch now:
+
+\begin{bashinput}
+git checkout -b bootlin-labs
+git add arch/arm64/boot/dts/ti/k3-am625-beagleplay-custom.dts
+git commit -as -m "Custom DTS for Bootlin lab"
+\end{bashinput}
+
+We can now create the patch:\\
+\texttt{git format-patch stable/linux-\workingkernel.y}
+
+This should generate a \code{0001-Custom-DTS-for-Bootlin-lab.patch}
+file.
+
+Creating the branch will impact the versions of the kernel and the modules.
+Compile your kernel and install your modules again (not necessary for the
+Nunchuk one for the moment) and see the version changes through the
+new base directory for modules.
+
+To save space for the next lab, remove the old directory under
+\code{lib/modules} containing the "dirty" modules.
+
+Don't forget to update the kernel your board boots.
+
+That's all for now!
diff --git a/labs/sysdev-block-filesystems-imx93-frdm/sysdev-block-filesystems-imx93-frdm.tex b/labs/sysdev-block-filesystems-imx93-frdm/sysdev-block-filesystems-imx93-frdm.tex
new file mode 100644
index 0000000000..f7180abd89
--- /dev/null
+++ b/labs/sysdev-block-filesystems-imx93-frdm/sysdev-block-filesystems-imx93-frdm.tex
@@ -0,0 +1,169 @@
+\subchapter{Filesystems - Block file systems}{Objective: configure and
+ boot an embedded Linux system relying on block storage}
+
+After this lab, you will be able to:
+\begin{itemize}
+\item Produce file system images.
+\item Configure the kernel to use these file systems
+\item Use the tmpfs file system to store temporary files
+\item Load the kernel and DTB from a EXT4 partition
+\end{itemize}
+
+\section{Goals}
+
+After doing the {\em A tiny embedded system} lab, we are going to copy
+the filesystem contents to the SD card. The storage will be
+split into several partitions, and your board will boot
+on an root filesystem on this SD card, without using NFS anymore.
+
+\section{Setup}
+
+Throughout this lab, we will continue to use the root filesystem we
+have created in the \code{$HOME/__SESSION_NAME__-labs/tinysystem/nfsroot}
+directory, which we will progressively adapt to use block filesystems.
+
+\section{Filesystem support in the kernel}
+
+Recompile your kernel with support for SquashFS and ext4\footnote{Basic
+configuration options for these filesystems will be sufficient. No need
+for things like extended attributes.}.
+
+Update your kernel image in the boot partition.
+
+Boot your board with this new kernel and on the NFS filesystem you
+used in this previous lab.
+
+Now, check the contents of \code{/proc/filesystems}. You should see
+ that ext4 and SquashFS are now supported.
+
+\section{Add partitions to the SD card}
+
+Plug the SD card in your workstation.
+
+Using \code{fdisk /dev/mmcblk0}, add two partitions, starting from the beginning
+of the remaining space, with the following properties:
+
+\begin{itemize}
+\item A third primary partition, 100 MB big, for the root filesystem
+\item A fourth primary partition, that fills the rest of the SD card, that will be
+ used for the data filesystem
+\end{itemize}
+
+Save and exit when you are done.
+
+\section{Data partition on the SD card}
+
+Using the \code{mkfs.ext4} create a journaled file system on the
+third partition of the SD card:
+
+\bashcmd{$ sudo mkfs.ext4 -L data -E nodiscard /dev/mmcblk0p3}
+
+\begin{itemize}
+\item \code{-L} assigns a volume name to the partition
+\item \code{-E nodiscard} disables bad block discarding. While this
+ should be a useful option for cards with bad blocks, skipping
+ this step saves long minutes in SD cards.
+\end{itemize}
+
+Now, mount this new partition and move the contents of the
+\code{/www/upload/files} directory (in your target root filesystem) into
+it. The goal is to use the data partition of the SD card as the storage
+for the uploaded images.
+
+Insert the SD card in your board and boot. You should see the
+partitions in \code{/proc/partitions}.
+
+Mount this data partition on \code{/www/upload/files}.
+
+Once this works, modify the startup scripts in your root filesystem
+to do it automatically at boot time.
+
+Reboot your target system and with the \code{mount} command, check that
+\code{/www/upload/files} is now a mount point for the last SD card
+partition. Also make sure that you can still upload new images, and
+that these images are listed in the web interface.
+
+\section{Adding a tmpfs partition for log files}
+
+For the moment, the upload script was storing its log file in
+\code{/www/upload/files/upload.log}. To avoid seeing this log file in
+the directory containing uploaded files, let's store it in
+\code{/var/log} instead.
+
+Add the \code{/var/log/} directory to your root filesystem and modify
+the startup scripts to mount a \code{tmpfs} filesystem on this
+directory. You can test your \code{tmpfs} mount command line on the
+system before adding it to the startup script, in order to be sure
+that it works properly.
+
+Modify the \code{www/cgi-bin/upload.cfg} configuration file to store
+the log file in \code{/var/log/upload.log}. You will lose your log
+file each time you reboot your system, but that's OK in our
+system. That's what \code{tmpfs} is for: temporary data that you don't need
+to keep across system reboots.
+
+Reboot your system and check that it works as expected.
+
+\section{Making a SquashFS image}
+
+We are going to store the root filesystem in a SquashFS filesystem in
+the second partition of the SD card.
+
+In order to create SquashFS images on your host, you need to install
+the \code{squashfs-tools} package. Now create a SquashFS image of your
+NFS root directory.
+
+Finally, using the \code{dd} command, copy the file system image to
+the second partition of the SD card.
+
+\section{Booting on the SquashFS partition}
+
+In the U-boot shell, configure the kernel command line to use the
+second partition of the SD card as the root file system. Also add the
+\code{rootwait} boot argument, to wait for the SD card to be properly
+initialized before trying to mount the root filesystem. Since the SD
+cards are detected asynchronously by the kernel, the kernel might try
+to mount the root filesystem too early without \code{rootwait}.
+
+Check that your system still works.
+
+\section{Loading the kernel and DTB from the SD card}
+
+In order to let the kernel boot on the board autonomously, we can
+copy the kernel image and DTB in the boot partition we created
+previously.
+
+Insert the SD card in your PC, it will get auto-mounted. Copy the
+kernel and device tree to the \code{env} partition.
+
+Insert the SD card back in the board and reset it. You should now be
+able to load the DTB and kernel image from the SD card and boot with:
+
+\begin{ubootinput}
+=> load mmc 1:2 %\zimageboardaddr% Image.gz
+=> load mmc 1:2 %\dtbboardaddr% %\dtname%-custom.dtb
+=> booti %\zimageboardaddr% - %\dtbboardaddr%
+\end{ubootinput}
+
+You are now ready to modify \code{bootcmd} to boot the board
+from SD card. But first, save the settings for booting from
+\code{tftp}:
+
+\begin{ubootinput}
+=> setenv bootcmdtftp %\$%{bootcmd}
+\end{ubootinput}
+
+This will be useful to switch back to \code{tftp} booting mode
+later in the labs.
+
+Finally, using \code{editenv bootcmd}, adjust \code{bootcmd} so that
+the board starts using the kernel from the SD card.
+
+Now, reset the board to check that it boots in the same way from the
+SD card.
+
+Now, the whole system (bootloader, kernel and filesystems) is
+stored on the SD card. That's very useful for product demos, for
+example. You can switch demos by switching SD cards, and the
+system depends on nothing else. In particular, no networking is
+necessary.
diff --git a/labs/sysdev-block-filesystems-stm32/sysdev-block-filesystems-stm32.tex b/labs/sysdev-block-filesystems-stm32/sysdev-block-filesystems-stm32.tex
index 6e0c6ba388..b7be6660c8 100644
--- a/labs/sysdev-block-filesystems-stm32/sysdev-block-filesystems-stm32.tex
+++ b/labs/sysdev-block-filesystems-stm32/sysdev-block-filesystems-stm32.tex
@@ -77,9 +77,9 @@ \section{Data partition on the SD card}
Using the \code{mkfs.ext4} create a journaled file system on the
sixth partition of the SD card:
\ifdefstring{\labboard}{stm32mp1}{
-\bashcmd{$ sudo mkfs.ext4 -L data -E nodiscard /dev/mmcblk0p6}}
+\bashcmd{$ sudo mkfs.ext4 -L data -E nodiscard /dev/mmcblk0p6}}{}
\ifdefstring{\labboard}{stm32mp2}{
-\bashcmd{$ sudo mkfs.ext4 -L data -E nodiscard /dev/mmcblk0p5}}
+\bashcmd{$ sudo mkfs.ext4 -L data -E nodiscard /dev/mmcblk0p5}}{}
\begin{itemize}
\item \code{-L} assigns a volume name to the partition
diff --git a/labs/sysdev-buildroot/sysdev-buildroot.tex b/labs/sysdev-buildroot/sysdev-buildroot.tex
index 9b79cc444a..3ef8c011eb 100644
--- a/labs/sysdev-buildroot/sysdev-buildroot.tex
+++ b/labs/sysdev-buildroot/sysdev-buildroot.tex
@@ -112,9 +112,11 @@ \section{Configure Buildroot}
}{
\item \code{Target Architecture}: \code{ARM (little endian)}
}
-
+
\if\defstring{\labboard}{stm32mp1}
\item \code{Target Architecture Variant}: \code{cortex-A7}
+
+(Change buildroot lab to support imx93-frdm)
\item \code{Target ABI}: \code{EABIhf}
\item \code{Floating point strategy}: \code{VFPv4}
\fi
@@ -124,6 +126,11 @@ \section{Configure Buildroot}
\item \code{Floating point strategy}: \code{FP-ARMv8}
\fi
+ \if\defstring{\labboard}{imx93-frdm}
+ \item \code{Target Architecture Variant}: \code{cortex-A35}
+ \item \code{Floating point strategy}: \code{FP-ARMv8}
+ \fi
+
\if\defstring{\labboard}{qemu}
\item \code{Target Architecture Variant}: \code{cortex-A9}
\item \code{Enable NEON SIMD extension support}: Enabled
@@ -155,7 +162,7 @@ \section{Configure Buildroot}
}
(replace \code{} by your actual user name)
\item \code{External toolchain gcc version}: \code{14.x}
- \item \code{External toolchain kernel headers series}: {\tt \workingkernel}
+ \item \code{External toolchain kernel headers series}: Set it to a version older than the one selected during the build of the toolchain, which itself was older than {\tt \workingkernel}.
\item \code{External toolchain C library}: \code{musl (experimental)}
\item We must tell Buildroot about our toolchain configuration, so
select \code{Toolchain has SSP support?} and
@@ -181,8 +188,9 @@ \section{Configure Buildroot}
\ifdefstring{\labboard}{stm32mp1}{\code{st/stm32mp157a-dk1-custom}}{}
\ifdefstring{\labboard}{stm32mp2}{\code{st/stm32mp257f-dk-custom}}{}
\ifdefstring{\labboard}{beaglebone}{\code{ti/omap/am335x-boneblack-custom}}{}
- \ifdefstring{\labboard}{beagleplay}{\code{ti/k3-am625-beagleplay-custom}}{}
- \ifdefstring{\labboard}{beagleplay}{\item Set \code{Kernel Binary format} to \code{Image.gz}}{}
+ \ifdefstring{\labboard}{beagleplay}{\code{ti/k3-am625-beagleplay-custom}}
+ \ifdefstring{\labboard}{imx93-frdm}{imx93-11x11-frdm-custom}{}
+ \ifdefstring{\arch}{ARM64}{\item Set \code{Kernel Binary format} to \code{Image.gz}}{}
\end{itemize}
\item \code{Target packages}
\begin{itemize}
diff --git a/labs/sysdev-kernel-cross-compiling/sysdev-kernel-cross-compiling.tex b/labs/sysdev-kernel-cross-compiling/sysdev-kernel-cross-compiling.tex
index bf297a2e07..7c88df49e2 100644
--- a/labs/sysdev-kernel-cross-compiling/sysdev-kernel-cross-compiling.tex
+++ b/labs/sysdev-kernel-cross-compiling/sysdev-kernel-cross-compiling.tex
@@ -51,6 +51,14 @@ \section{Choose a particular stable version of Linux}
Check the version again using the \code{make kernelversion} command
to make sure you now have a \workingkernel.x version.
+\if\defstring{\labboard}{imx93-frdm}
+{Before continuing, we still need to apply a patch in kernel/data to add the device tree for the imx93-frdm in `arch/arm64/boot/dts/freescale` because the board is not yet supported in the kernel.
+\begin{bashinput}
+git apply ../data/linux-imx93-frdm.patch
+\end{bashinput}
+After applying the patch edit the Makefile to build imx93-11x11-frdm.dts
+}
+
\section{Cross-compiling environment setup}
To cross-compile Linux, you need to have a cross-compiling
@@ -58,7 +66,7 @@ \section{Cross-compiling environment setup}
previously produced, so we just need to make it available in the PATH:
\begin{bashinput}
-$ export PATH=$HOME/x-tools/%\ifdefstring{\labboard}{beagleplay}{aarch64-training-linux-musl}{arm-training-linux-musleabihf}%/bin:$PATH
+$ export PATH=$HOME/x-tools/%\ifdefstring{\arch}{ARM64}{aarch64-training-linux-musl}{arm-training-linux-musleabihf}%/bin:$PATH
\end{bashinput}
Also, don't forget to either:
@@ -69,7 +77,7 @@ \section{Cross-compiling environment setup}
\item {\bf Or} specify them on the command line at every invocation of
\code{make}, i.e.: \code{make ARCH=... CROSS_COMPILE=... }
\end{itemize}
-\ifdefstring{\labboard}{beagleplay}{
+\ifdefstring{\arch}{ARM64}{
\textbf{Important:} The majority of tools use \code{aarch64} to define 64 bits
ARM processors. However in specific cases, the tools may use \code{arm64} to
define such architecture. In the case of the kernel Makefile we will use the
@@ -89,7 +97,7 @@ \section{Linux kernel configuration}
\ifdefstring{\labboard}{beaglebone}
{In our case look for a configuration for boards in the OMAP2 and
later family which the AM335x found in the BeagleBone belongs to.}{}
-\ifdefstring{\labboard}{beagleplay}
+\ifdefstring{\arch}{ARM64}
{If you search for a configuration file that corresponds to the \code{arm64}
architecture that the kernel will use, you might see that only one
\code{defconfig} file is available. We will therefore load this basic
@@ -140,6 +148,11 @@ \section{Linux kernel configuration}
\item Disable \kconfig{CONFIG_DRM}, which will skip support for many display
controller and GPU drivers.
}{}
+
+\ifdefstring{\labboard}{imx93-frdm}{
+ \item In the \code{System Type} menu, remove support for all the SoCs except
+ the \code{NXP SoC support} ones and in particular \code{NXP i.MX SoC family}.
+ \item To use ethetnet port enable as built in \code{CONFIG_STMMAC_ETH}, \code{CONFIG_STMMAC_PLATFORM},\code{CONFIG_NVMEM_IMX_OCOTP_ELE}, and \code{CONFIG_DWMAC_IMX8}}{}
\end{itemize}
\ifdefstring{\labboard}{stm32mp1}{
@@ -148,7 +161,7 @@ \section{Linux kernel configuration}
enables plenty of features and drivers that will not be useful on our
particular board.}{}
-\ifdefstring{\labboard}{beagleplay}{
+\ifdefstring{\arch}{ARM64}{
Please note that this will definitely not build the smallest and most
optimized kernel for the BeaglePlay: the ARM64 \code{defconfig}
enables plenty of features and drivers that will not be useful on our
@@ -189,13 +202,13 @@ \section{Load and boot the kernel using U-Boot}
\begin{itemize}
-\item On your workstation, copy the {\tt \ifdefstring{\labboard}{beagleplay}{Image.gz}{zImage}} and DTB
+\item On your workstation, copy the {\tt \ifdefstring{\arch}{ARM64}{Image.gz}{zImage}} and DTB
(\texttt{\dtname}\texttt{.dtb}) to the directory exposed by the TFTP server.
-\item On the target (in the U-Boot prompt), load {\tt \ifdefstring{\labboard}{beagleplay}{Image.gz}{zImage}} from
+\item On the target (in the U-Boot prompt), load {\tt \ifdefstring{\arch}{ARM64}{Image.gz}{zImage}} from
TFTP into RAM:
\begin{ubootinput}
-=> tftp %\zimageboardaddr% %\ifdefstring{\labboard}{beagleplay}{Image.gz}{zImage}%
+=> tftp %\zimageboardaddr% %\ifdefstring{\arch}{ARM64}{Image.gz}{zImage}%
\end{ubootinput}
\item Now, also load the DTB file into RAM:
@@ -205,12 +218,12 @@ \section{Load and boot the kernel using U-Boot}
\item Boot the kernel with its device tree:
\begin{ubootinput}
-=> %\ifdefstring{\labboard}{beagleplay}{booti}{bootz} \zimageboardaddr% - %\dtbboardaddr%
+=> %\ifdefstring{\arch}{ARM64}{booti}{bootz} \zimageboardaddr% - %\dtbboardaddr%
\end{ubootinput}
\end{itemize}
-\if\defstring{\labboard}{beagleplay}
+\if\defstring{\arch}{ARM64}
This last command should show you an error message of this type:
\bashcmd{kernel_comp_addr_r or kernel_comp_size is not provided!}
diff --git a/labs/sysdev-system-integration/sysdev-system-integration.tex b/labs/sysdev-system-integration/sysdev-system-integration.tex
index addaf77e4a..c54d7e8487 100644
--- a/labs/sysdev-system-integration/sysdev-system-integration.tex
+++ b/labs/sysdev-system-integration/sysdev-system-integration.tex
@@ -80,8 +80,9 @@ \section{Buildroot configuration}
\ifdefstring{\labboard}{stm32mp1}{\code{st/stm32mp157a-dk1-custom}}{}
\ifdefstring{\labboard}{stm32mp2}{\code{st/stm32mp257f-dk-custom}}{}
\ifdefstring{\labboard}{beaglebone}{\code{ti/omap/am335x-boneblack-custom}}{}
- \ifdefstring{\labboard}{beagleplay}{\code{ti/k3-am625-beagleplay-custom}}{}
- \ifdefstring{\labboard}{beagleplay}{\item Set \code{Kernel Binary format} to \code{Image.gz}}{}
+ \ifdefstring{\labboard}{beagleplay}{\code{ti/k3-am625-beagleplay-custom}}
+ \ifdefstring{\labboard}{imx93-frdm}{imx93-11x11-frdm-custom}{}
+ \ifdefstring{\arch}{ARM64}{\item Set \code{Kernel Binary format} to \code{Image.gz}}{}
\end{itemize}
\item \code{Target packages}
\begin{itemize}
@@ -250,7 +251,7 @@ \section{Understanding automatic module loading with Udev}
address.
\begin{bashinput}
-# cd %\ifdefstring{\labboard}{beagleplay}{3}{1}%-0052
+# cd X-0052
# ls -la
# cat modalias
of:NjoystickT(null)Cnintendo,nunchuk
diff --git a/labs/sysdev-thirdparty-imx93-frdm/dependencies.dia b/labs/sysdev-thirdparty-imx93-frdm/dependencies.dia
new file mode 100644
index 0000000000..3530028822
--- /dev/null
+++ b/labs/sysdev-thirdparty-imx93-frdm/dependencies.dia
@@ -0,0 +1,483 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ #Letter#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #libgpiod#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #alsa-lib#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #alsa-utils#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #ipcalc#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/labs/sysdev-thirdparty-imx93-frdm/sysdev-thirdparty-imx93-frdm.tex b/labs/sysdev-thirdparty-imx93-frdm/sysdev-thirdparty-imx93-frdm.tex
new file mode 100644
index 0000000000..3f947a23ad
--- /dev/null
+++ b/labs/sysdev-thirdparty-imx93-frdm/sysdev-thirdparty-imx93-frdm.tex
@@ -0,0 +1,843 @@
+\subchapter{Third party libraries and applications}{Objective: Learn
+ how to leverage existing libraries and applications: how to
+ configure, compile and install them}
+
+To illustrate how to use existing libraries and applications, we will
+extend the small root filesystem built in the {\em A tiny embedded
+system} lab to add the {\em ALSA} libraries and tools to run
+basic sound support tests, and the {\em libgpiod} library and
+executables to manage GPIOs. {\em ALSA} stands for {\em Advanced Linux
+Sound Architecture}, and is the Linux audio subsystem.
+
+We'll see that manually re-using existing libraries is quite tedious,
+so that more automated procedures are necessary to make it
+easier. However, learning how to perform these operations manually
+will significantly help you when you face issues with more
+automated tools.
+
+\section{Figuring out library dependencies}
+
+We're going to integrate the {\em alsa-utils}, {\em libgpiod}
+and {\em ipcalc} executables. In our case, the dependency chain
+for {\em alsa-utils} is quite simple, it only depends on the
+{\em alsa-lib} library. {\em libgpiod} and {\em ipcalc} are standalone
+and don't have any dependency.
+
+\includegraphics[width=\textwidth]{labs/sysdev-thirdparty-imx93-frdm/dependencies.pdf}
+
+Of course, all these libraries rely on the C library, which is not
+mentioned here, because it is already part of the root filesystem
+built in the {\em A tiny embedded system} lab. You might wonder how to
+figure out this dependency tree by yourself. Basically, there are
+several ways, that can be combined:
+
+\begin{itemize}
+\item Read the library documentation, which often mentions the
+ dependencies;
+\item Read the help message of the \code{configure script} (by running
+ \code{./configure --help}).
+\item By running the \code{configure} script, compiling and looking
+ at the errors.
+\end{itemize}
+
+To configure, compile and install all the components of our system,
+we're going to start from the bottom of the tree with {\em alsa-lib},
+then continue with {\em alsa-utils}. Then, we will also build
+{\em libgpiod} and {\em ipcalc}.
+
+\section{Preparation}
+
+For our cross-compilation work, we will need two separate spaces:
+\begin{itemize}
+\item A \emph{staging} space in which we will directly install all the
+ packages: non-stripped versions of the libraries, headers,
+ documentation and other files needed for the compilation. This
+ \emph{staging} space can be quite big, but will not be used on our
+ target, only for compiling libraries or applications;
+\item A \emph{target} space, in which we will only copy the required
+ files from the \emph{staging} space: binaries and libraries, after
+ stripping, configuration files needed at runtime, etc. This target
+ space will take a lot less space than the \emph{staging} space, and
+ it will contain only the files that are really needed to make the
+ system work on the target.
+\end{itemize}
+
+To sum up, the {\em staging} space will contain everything that's
+needed for compilation, while the {\em target} space will contain only
+what's needed for execution.
+
+Create the \code{$HOME/__SESSION_NAME__-labs/thirdparty} directory,
+and inside, create two directories: \code{staging} and \code{target}.
+
+For the target, we need a basic system with BusyBox and
+initialization scripts. We will re-use the system built in the {\em A
+ tiny embedded system} lab, so copy this system in the target
+directory:
+
+\bashcmd{$ cp -a $HOME/__SESSION_NAME__-labs/tinysystem/nfsroot/* target/}
+
+Note that for this lab, a lot of typing will be required. To save time
+typing, we advise you to copy and paste commands from the electronic
+version of these instructions.
+
+\section{Testing}
+
+Make sure the \code{target/} directory is exported by your NFS server
+to your board by modifying \code{/etc/exports} and restarting your NFS
+server.
+
+Make your board boot from this new directory through NFS.
+
+\section{alsa-lib}
+
+{\em alsa-lib} is a library supposed to handle the interaction with
+the ALSA subsystem. It is available at \url{https://alsa-project.org}.
+Download version 1.2.13, and extract it
+in \code{$HOME/__SESSION_NAME__-labs/thirdparty/}.
+
+{\bf Tip}: if the website for any of the source packages that we
+need to download in the next sections is down, a great mirror
+that you can use is \url{http://sources.buildroot.net/}.
+
+Back to {\em alsa-lib} sources, look at the \code{configure} script
+and see that it has been generated by \code{autoconf} (the header
+contains a sentence like {\em Generated by GNU Autoconf 2.69}). Most of
+the time, \code{autoconf} comes with \code{automake}, that generates
+Makefiles from \code{Makefile.am} files. So {\em alsa-lib} uses a rather
+common build system. Let's try to configure and build it:
+
+\begin{bashinput}
+$ ./configure
+$ make
+\end{bashinput}
+
+If you look at the generated binaries, you'll see that they are
+x86 ones because we compiled the sources with gcc, the default compiler.
+This is obviously not what we want, so let's clean-up the generated objects
+and tell the \code{configure} script to use the ARM cross-compiler:
+
+\begin{bashinput}
+$ make clean
+$ CC=aarch64-linux-gcc ./configure
+\end{bashinput}
+
+Of course, the \code{aarch64-linux-gcc} cross-compiler must be in your
+\code{PATH} prior to running the configure script. The \code{CC} environment
+variable is the classical name for specifying the compiler to
+use.
+
+Quickly, you should get an error saying:
+
+%\footnotesize
+\begin{terminaloutput}
+checking whether we are cross compiling... configure: error: in `/home/tux/__SESSION_NAME__-labs/thirdparty/alsa-lib-1.2.13':
+configure: error: cannot run C compiled programs.
+If you meant to cross compile, use `--host'.
+See `config.log' for more details
+\end{terminaloutput}
+\normalsize
+
+If you look at the \code{config.log} file, you can see that the
+\code{configure} script compiles a binary with the cross-compiler
+and then tries to run it on the development workstation. This is a
+rather usual thing to do for a \code{configure} script, and that's
+why it tests so early that it's actually doable, and bails out if not.
+
+Obviously, it cannot work in our case, and the scripts exits. The job
+of the \code{configure} script is to test the configuration of the system. To
+do so, it tries to compile and run a few sample applications to test
+if this library is available, if this compiler option is supported,
+etc. But in our case, running the test examples is definitely not
+possible.
+
+We need to tell the \code{configure} script that we are cross-compiling, and
+this can be done using the \code{--build} and \code{--host} options,
+as described in the help of the \code{configure} script:
+
+\begin{verbatim}
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+\end{verbatim}
+
+The \code{--build} option allows to specify on which system the
+package is built, while the \code{--host} option allows to specify on
+which system the package will run. By default, the value of the
+\code{--build} option is guessed and the value of \code{--host} is the
+same as the value of the \code{--build} option. The value is guessed
+using the \code{./config.guess} script, which on your system should
+return \code{x86_64-pc-linux-gnu}. See
+\url{https://www.gnu.org/software/autoconf/manual/html_node/Specifying-Names.html}
+for more details on these options.
+
+So, let's override the value of the \code{--host} option:
+
+\bashcmd{$ ./configure --host=aarch64-linux}
+
+Note that \code{CC} is not required anymore. It is implied
+by \code{--host}.
+
+The \code{configure} script should end properly now, and create a
+Makefile.
+
+However, there is one subtle issue to handle.
+We need to tell {\em alsa-lib} to disable a feature called {\em alsa topology}.
+{\em alsa-lib} will build fine but we will encounter some
+problems afterwards, during {\em alsa-utils} building.
+So you should configure {\em alsa-lib} as follows:
+
+\bashcmd{$ ./configure --host=aarch64-linux --disable-topology}
+
+Run the \code{make} command, which should run just fine.
+
+Look at the result of compiling in \code{src/.libs}: a set of object files
+and a set of \code{libasound.so*} files.
+
+The \code{libasound.so*} files are a dynamic version of the
+library. The shared library itself is \code{libasound.so.2.0.0}, it has
+been generated by the following command line:
+
+\begin{bashinput}
+$ aarch64-linux-gcc -shared conf.o confmisc.o input.o output.o async.o error.o dlmisc.o socket.o shmarea.o userfile.o names.o -lm -ldl -lpthread -lrt -Wl,-soname -Wl,libasound.so.2 -o libasound.so.2.0.0
+\end{bashinput}
+
+And creates the symbolic links \code{libasound.so} and
+\code{libasound.so.2}.
+
+\begin{bashinput}
+$ ln -s libasound.so.2.0.0 libasound.so.2
+$ ln -s libasound.so.2.0.0 libasound.so
+\end{bashinput}
+
+These symlinks are needed for two different reasons:
+
+\begin{itemize}
+\item \code{libasound.so} is used at compile time when you want to
+ compile an application that is dynamically linked against the
+ library. To do so, you pass the \code{-lLIBNAME} option to the
+ compiler, which will look for a file named
+ \code{lib.so}. In our case, the compilation option is
+ \code{-lasound} and the name of the library file is
+ \code{libasound.so}. So, the \code{libasound.so} symlink is needed
+ at compile time;
+\item \code{libasound.so.2} is needed because it is the {\em SONAME}
+ of the library. {\em SONAME} stands for {\em Shared Object Name}. It
+ is the name of the library as it will be stored in applications
+ linked against this library. It means that at runtime, the dynamic
+ loader will look for exactly this name when looking for the shared
+ library. So this symbolic link is needed at runtime.
+\end{itemize}
+
+To know what's the {\em SONAME} of a library, you can use:
+\bashcmd{$ aarch64-linux-readelf -d libasound.so.2.0.0}
+
+and look at the \code{(SONAME)} line. You'll also see that this
+library needs the C library, because of the \code{(NEEDED)} line on
+\code{libc.so.0}.
+
+The mechanism of \code{SONAME} allows to change the library without
+recompiling the applications linked with this library. Let's say that
+a security problem is found in the {\em alsa-lib} release that provides
+{\em libasound 2.0.0}, and fixed in the next {\em alsa-lib} release, which will
+now provide {\em libasound 2.0.1}.
+
+You can just recompile the library, install it on your target system,
+change the \code{libasound.so.2} link so that it points to
+\code{libasound.so.2.0.1} and restart your applications. And it will
+work, because your applications don't look specifically for
+\code{libasound.so.2.0.0} but for the {\em SONAME}
+\code{libasound.so.2}.
+
+However, it also means that as a library developer, if you break the
+ABI of the library, you must change the {\em SONAME}: change from
+\code{libasound.so.2} to \code{libasound.so.3}.
+
+Finally, the last step is to tell the \code{configure} script where the
+library is going to be installed. Most \code{configure} scripts consider that
+the installation prefix is \code{/usr/local/} (so that the library is
+installed in \code{/usr/local/lib}, the headers in
+\code{/usr/local/include}, etc.). But in our system, we simply want
+the libraries to be installed in the \code{/usr} prefix, so let's tell
+the \code{configure} script about this:
+
+\begin{bashinput}
+$ ./configure --host=aarch64-linux --disable-topology --prefix=/usr
+$ make
+\end{bashinput}
+
+For this library, this option may not change anything to the resulting
+binaries, but for safety, it is always recommended to make sure that
+the prefix matches where your library will be running on the target
+system.
+
+Do not confuse the {\em prefix} (where the application or library will
+be running on the target system) from the location where the
+application or library will be installed on your host while building
+the root filesystem.
+
+For example, {\em libasound} will be installed in
+\code{$HOME/__SESSION_NAME__-labs/thirdparty/target/usr/lib/} because this is
+the directory where we are building the root filesystem, but once our
+target system will be running, it will see {\em libasound} in
+\code{/usr/lib}.
+
+The prefix corresponds to the path in the target system and {\bf
+ never} on the host. So, one should {\bf never} pass a prefix like
+\code{$HOME/__SESSION_NAME__-labs/thirdparty/target/usr}, otherwise at
+runtime, the application or library may look for files inside this
+directory on the target system, which obviously doesn't exist! By
+default, most build systems will install the application or library in
+the given prefix (\code{/usr} or \code{/usr/local}), but with most
+build systems (including {\em autotools}), the installation prefix can
+be overridden, and be different from the configuration prefix.
+
+We now only have the installation process left to do.
+
+First, let's make the installation in the {\em staging} space:
+\bashcmd{$ make DESTDIR=$HOME/__SESSION_NAME__-labs/thirdparty/staging install}
+
+Now look at what has been installed by {\em alsa-lib}:
+\begin{itemize}
+\item Some configuration files in \code{/usr/share/alsa}
+\item The headers in \code{/usr/include}
+\item The shared library and its libtool (\code{.la}) file in \code{/usr/lib}
+\item A pkgconfig file in \code{/usr/lib/pkgconfig}. We'll come back
+ to these later
+\end{itemize}
+
+Finally, let's install the library in the {\em target} space:
+
+\begin{enumerate}
+\item Create the \code{target/usr/lib} directory, it will contain the
+ stripped version of the library
+\item Copy the dynamic version of the library. Only
+ \code{libasound.so.2} and \code{libasound.so.2.0.0} are needed,
+ since \code{libasound.so.2} is the {\em SONAME} of the library and
+ \code{libasound.so.2.0.0} is the real binary:
+ \begin{itemize}
+ \item \bashcmd{$ cp -a staging/usr/lib/libasound.so.2* target/usr/lib}
+ \end{itemize}
+\item Measure the size of the \code{target/usr/lib/libasound.so.2.0.0}
+ library before stripping.
+\item Strip the library:
+ \begin{itemize}
+ \item \bashcmd{$ aarch64-linux-strip target/usr/lib/libasound.so.2.0.0}
+ \end{itemize}
+\item Measure the size of the \code{target/usr/lib/libasound.so.2.0.0}
+ library library again after stripping. How many unnecessary bytes
+ were saved?
+\end{enumerate}
+
+Then, we need to install the {\em alsa-lib} configuration files:
+
+\begin{bashinput}
+$ mkdir -p target/usr/share
+$ cp -a staging/usr/share/alsa target/usr/share
+\end{bashinput}
+
+Now, we need to adjust one small detail in one of the configuration
+files. Indeed, \code{/usr/share/alsa/alsa.conf} assumes a UNIX group
+called \code{audio} exists, which is not the case on our very small
+system. So edit this file, and replace \code{defaults.pcm.ipc_gid
+audio} by \code{defaults.pcm.ipc_gid 0} instead.
+
+And we're done with {\em alsa-lib}!
+
+\section{Alsa-utils}
+
+
+Download {\em alsa-utils} from the ALSA offical webpage. We tested the lab
+with version 1.2.13. The \code{gettext} package is needed during the build
+so we have to install it.
+
+\bashcmd{sudo apt install gettext}
+
+Once uncompressed, we quickly discover that the {\em alsa-utils} build
+system is based on the {\em autotools}, so we will work once again
+with a regular \code{configure} script.
+
+As we've seen previously, we will have to provide the prefix and host
+options:
+
+\bashcmd{$ ./configure --host=aarch64-linux --prefix=/usr}
+
+Now, we should quiclky get an error in the execution of the
+\code{configure} script:
+
+\begin{verbatim}
+checking for libasound headers version >= 1.2.5 (1.2.5)... not present.
+configure: error: Sufficiently new version of libasound not found.
+\end{verbatim}
+
+Again, we can check in \code{config.log} what the \code{configure}
+script is trying to do:
+
+%\footnotesize
+\begin{terminaloutput}
+configure:15855: checking for libasound headers version >= 1.2.5 (1.2.5)
+configure:15902: aarch64-linux-gcc -c -g -O2 conftest.c >&5
+conftest.c:24:10: fatal error: alsa/asoundlib.h: No such file or directory
+\end{terminaloutput}
+\normalsize
+
+Of course, since {\em alsa-utils} uses {\em alsa-lib}, it includes
+its header file! So we need to tell the C compiler where the headers
+can be found: there are not in the default directory
+\code{/usr/include/}, but in the \code{/usr/include} directory of our
+{\em staging} space. The help text of the \code{configure} script says:
+
+\begin{verbatim}
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if
+ you have headers in a nonstandard directory
+\end{verbatim}
+
+Let's use it:
+
+\begin{bashinput}
+$ CPPFLAGS=-I$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/include \%\linebreak
+./configure --host=aarch64-linux --prefix=/usr
+\end{bashinput}
+
+Now, it should stop a bit later, this time with the error:
+\begin{verbatim}
+checking for snd_ctl_open in -lasound... no
+configure: error: No linkable libasound was found.
+\end{verbatim}
+
+The \code{configure} script tries to compile an application against {\em
+ libasound} (as can be seen from the \code{-lasound} option): {\em
+ alsa-utils} uses {\em alsa-lib}, so the \code{configure} script
+wants to make sure this library is already installed. Unfortunately,
+the \code{ld} linker doesn't find it. So, let's tell the
+linker where to look for libraries using the \code{-L} option followed
+by the directory where our libraries are (in
+\code{staging/usr/lib}). This \code{-L} option can be passed to the
+linker by using the \code{LDFLAGS} at configure time, as told by the
+help text of the \code{configure} script:
+
+\begin{verbatim}
+ LDFLAGS linker flags, e.g. -L if you have libraries in a
+ nonstandard directory
+\end{verbatim}
+
+Let's use this \code{LDFLAGS} variable:
+
+\begin{bashinput}
+$ LDFLAGS=-L$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/lib \
+ CPPFLAGS=-I$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/include \
+ ./configure --host=aarch64-linux --prefix=/usr
+\end{bashinput}
+
+Once again, it should fail a bit further down the tests, this time
+complaining about a missing {\em curses helper header}. {\em curses}
+or {\em ncurses} is a graphical framework to design UIs in the
+terminal. This is only used by {\em alsamixer}, one of the tools
+provided by {\em alsa-utils}, that we are not going to use.
+Hence, we can just disable the build of {\em alsamixer}.
+
+Of course, if we wanted it, we would have had to build {\em ncurses} first,
+just like we built {\em alsa-lib}.
+
+\begin{bashinput}
+$ LDFLAGS=-L$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/lib \
+ CPPFLAGS=-I$HOME/__SESSION_NAME__-labs/thirdparty/staging/usr/include \
+ ./configure --host=aarch64-linux --prefix=/usr \
+ --disable-alsamixer
+\end{bashinput}
+
+Then, run the compilation with \code{make}. It should complete
+successfully.
+
+Let's now begin the installation process. Before really installing in
+the staging directory, let's install in a dummy directory, to see
+what's going to be installed (this dummy directory will not be used
+afterwards, it is only to verify what will be installed before
+polluting the staging space):
+
+\bashcmd{$ make DESTDIR=/tmp/alsa-utils/ install}
+
+The \code{DESTDIR} variable can be used with all Makefiles based on
+\code{automake}. It allows to override the installation directory:
+instead of being installed in the configuration prefix directory, the
+files will be installed in \code{DESTDIR/configuration-prefix}.
+
+Now, let's see what has been installed in \code{/tmp/alsa-utils/} (run
+\code{tree /tmp/alsa-utils}):
+
+\begin{verbatim}
+/tmp/alsa-utils/
+|-- lib
+| `-- udev
+| `-- rules.d
+| `-- 90-alsa-restore.rules
+|-- usr
+| |-- bin
+| | |-- aconnect
+| | |-- alsabat
+| | |-- alsaloop
+| | |-- alsaucm
+| | |-- amidi
+| | |-- amixer
+| | |-- aplay
+| | |-- aplaymidi
+| | |-- arecord -> aplay
+| | |-- arecordmidi
+| | |-- aseqdump
+| | |-- aseqnet
+| | |-- axfer
+| | |-- iecset
+| | |-- nhlt-dmic-info
+| | `-- speaker-test
+| |-- sbin
+| | |-- alsabat-test.sh
+| | |-- alsaconf
+| | |-- alsactl
+| | `-- alsa-info.sh
+| `-- share
+| |-- alsa
+| | `-- init
+| | |-- 00main
+| | |-- ca0106
+| | |-- default
+| | |-- hda
+| | |-- help
+| | |-- info
+| | `-- test
+| |-- locale
+| | |-- de
+| | | `-- LC_MESSAGES
+| | | `-- alsa-utils.mo
+| | |-- eu
+| | | `-- LC_MESSAGES
+| | | `-- alsa-utils.mo
+| | |-- fr
+| | | `-- LC_MESSAGES
+| | | `-- alsa-utils.mo
+| | |-- ja
+| | | `-- LC_MESSAGES
+| | | |-- alsaconf.mo
+| | | `-- alsa-utils.mo
+| | |-- ka
+| | | `-- LC_MESSAGES
+| | | |-- alsaconf.mo
+| | | `-- alsa-utils.mo
+| | |-- ko
+| | | `-- LC_MESSAGES
+| | | `-- alsa-utils.mo
+| | |-- ru
+| | | `-- LC_MESSAGES
+| | | `-- alsaconf.mo
+| | `-- sk
+| | `-- LC_MESSAGES
+| | `-- alsa-utils.mo
+| |-- man
+| | |-- fr
+| | | `-- man8
+| | | `-- alsaconf.8
+| | |-- man1
+| | | |-- aconnect.1
+| | | |-- alsabat.1
+| | | |-- alsactl.1
+| | | |-- alsa-info.sh.1
+| | | |-- alsaloop.1
+| | | |-- amidi.1
+| | | |-- amixer.1
+| | | |-- aplay.1
+| | | |-- aplaymidi.1
+| | | |-- arecord.1 -> aplay.1
+| | | |-- arecordmidi.1
+| | | |-- aseqdump.1
+| | | |-- aseqnet.1
+| | | |-- axfer.1
+| | | |-- axfer-list.1
+| | | |-- axfer-transfer.1
+| | | |-- iecset.1
+| | | |-- nhlt-dmic-info.1
+| | | `-- speaker-test.1
+| | |-- man7
+| | `-- man8
+| | `-- alsaconf.8
+| `-- sounds
+| `-- alsa
+| |-- Front_Center.wav
+| |-- Front_Left.wav
+| |-- Front_Right.wav
+| |-- Noise.wav
+| |-- Rear_Center.wav
+| |-- Rear_Left.wav
+| |-- Rear_Right.wav
+| |-- Side_Left.wav
+| `-- Side_Right.wav
+`-- var
+ `-- lib
+ `-- alsa
+
+37 directories, 68 files
+\end{verbatim}
+
+So, we have:
+\begin{itemize}
+\item The {\em udev} rules in \code{lib/udev}
+\item The {\em alsa-utils} binaries in \code{/usr/bin} and \code{/usr/sbin}
+\item Some sound samples in \code{/usr/share/sounds}
+\item The various translations in \code{/usr/share/locale}
+\item The manual pages in \code{/usr/share/man/}, explaining how to
+ use the various tools
+\item Some configuration samples in \code{/usr/share/alsa}.
+\end{itemize}
+
+Now, let's make the installation in the {\em staging} space:
+
+\bashcmd{$ make DESTDIR=$HOME/__SESSION_NAME__-labs/thirdparty/staging/ install}
+
+Then, let's manually install only the necessary files in the {\em target}
+space. We are only interested in \code{speaker-test}:
+
+\begin{bashinput}
+$ cd ..
+$ cp -a staging/usr/bin/speaker-test target/usr/bin/
+$ aarch64-linux-strip target/usr/bin/speaker-test
+\end{bashinput}
+
+And we're finally done with {\em alsa-utils}!
+
+Now test that all is working fine by running the \code{speaker-test} util on
+your board, with the headset provided by your instructor plugged
+in. You may need to add the missing libraries from the toolchain
+install directory.
+
+Now you can use:
+
+\begin{itemize}
+
+\item \code{speaker-test} with no arguments to generate {\em pink noise}
+
+\item \code{speaker-test -t sine} to generate a {\em sine wave},
+optionally with \code{-f } for a specific frequency
+
+\end{itemize}
+
+There you are: you built and ran your first program depending
+on a library different from the C library.
+
+\section{libgpiod}
+
+\subsection{Compiling libgpiod}
+
+We are now going to use {\em libgpiod} (instead of the
+deprecated interface in \code{/sys/class/gpio}, whose executables
+(\code{gpiodetect}, \code{gpioset}, \code{gpioget}...) will
+allow us to drive and manage GPIOs from shell scripts.
+
+Here, we will be using the 2.2 version of {\em libgpiod}.
+
+\begin{bashinput}
+git clone https://git.kernel.org/pub/scm/libs/libgpiod/libgpiod.git
+cd libgpiod
+git checkout v2.2
+\end{bashinput}
+
+As we are not starting from a release, we will need to install
+further development tools to generate some files like the
+\code{configure} script:
+
+\bashcmd{sudo apt install autoconf-archive pkg-config}
+
+Now let's generate the files which are present in a release:
+
+\bashcmd{./autogen.sh}
+
+Run \code{./configure --help} script, and see that this script provides
+a \code{--enable-tools} option which allows to build the userspace
+executables that we want.
+
+As this project doesn't have any external library dependency, let's
+configure {\em libgpiod} in a similar way as {\em alsa-utils}:
+
+\begin{bashinput}
+$ ./configure --host=aarch64-linux --prefix=/usr --enable-tools
+\end{bashinput}
+
+Now, compile the software:
+
+\bashcmd{$ make}
+
+Installation to the {\em staging} space can be done using the
+classical \code{DESTDIR} mechanism:
+
+\begin{bashinput}
+$ make DESTDIR=$HOME/__SESSION_NAME__-labs/thirdparty/staging/ install
+\end{bashinput}
+
+And finally, only manually install and strip the files
+needed at runtime in the {\em target} space:
+
+\begin{bashinput}
+$ cd ..
+$ cp -a staging/usr/lib/libgpiod.so.3* target/usr/lib/
+$ aarch64-linux-strip target/usr/lib/libgpiod*
+$ cp -a staging/usr/bin/gpio* target/usr/bin/
+$ aarch64-linux-strip target/usr/bin/gpio*
+\end{bashinput}
+
+\subsection{Testing libgpiod}
+
+First, connect \code{GPIO PE1} (pin D2 of connector CN14) connected
+to ground (pin 7 of connector CN16), as in the
+{\em Accessing Hardware Devices} lab.
+
+Now, let's run the \code{gpiodetect} command on the target, and check that
+you can list the various GPIO banks on your system.
+
+\begin{bashinput}
+# gpiodetect
+gpiochip0 [43810000.gpio] (32 lines)
+gpiochip1 [43820000.gpio] (32 lines)
+gpiochip2 [43830000.gpio] (32 lines)
+gpiochip3 [47400000.gpio] (32 lines)
+gpiochip4 [1-0022] (24 lines)
+\end{bashinput}
+
+We can then get details on gpiochip0 by running
+\code{gpioinfo -c gpiochip0} or on all GPIOs by simply running
+\code{gpioinfo}.
+
+You can now read the state of your GPIO\_21:
+
+\begin{bashinput}
+# gpioget -c gpiochip0 21
+"1"=inactive
+\end{bashinput}
+
+Now, connect your wire to 3V3 . You should now
+read:
+
+\begin{bashinput}
+# gpioget -c gpiochip0 21
+"1"=active
+\end{bashinput}
+
+You see that you didn't have to configure the GPIO as input. {\em
+libgpiod} did that for you.
+
+If you have an LED and a small breadboard (or M-F breadboard wires),
+you could also try to drive the GPIO in output mode. Connect the short
+pin of the LED to GND, and the long one to the GPIO. Then then following
+command should light up the diode:
+
+\begin{bashinput}
+# gpioset -c gpiochip0 -t0 11=1
+\end{bashinput}
+
+The \code{-t0} option makes \code{gpioset} terminate by itself
+immediately instead of waiting for the user to interrupt it.
+
+Here's how to turn the LED off:
+
+\begin{bashinput}
+# gpioset -c gpiochip0 -t0 11=0
+\end{bashinput}
+
+\code{gpioset} offers many more options. Run \code{gpioset -h} to
+check by yourself.
+
+\section{ipcalc}
+
+After practicing with autotools based packages, let's build {\em ipcalc}, which
+is using {\em Meson} as build system. We won't really need this utility
+in our system, but at least it has no dependencies and therefore
+offers an easy way to build our first {\em Meson} based package.
+
+So, first install the \code{meson} package:
+
+\bashcmd{$ sudo apt install meson}
+
+In the main lab directory, then let's check out the sources through
+\code{git}:
+
+\begin{bashinput}
+$ git clone https://gitlab.com/ipcalc/ipcalc.git
+$ cd ipcalc/
+$ git checkout 1.0.3
+\end{bashinput}
+
+To cross-compile with {\em Meson}, we need to create a {\em cross file}.
+Let's create the \code{../cross-file.txt} file with the below contents:
+
+\begin{verbatim}
+[binaries]
+c = 'aarch64-linux-gcc'
+
+[host_machine]
+system = 'linux'
+cpu_family = 'arm64'
+cpu = 'cortex-a8'
+endian = 'little'
+\end{verbatim}
+
+We also need to create a special directory for building:
+
+\begin{bashinput}
+$ mkdir cross-build
+$ cd cross-build
+\end{bashinput}
+
+We can now have \code{meson} create the Ninja build files for us:
+
+\begin{bashinput}
+$ meson --cross-file ../../cross-file.txt --prefix /usr ..
+\end{bashinput}
+
+We are now ready to build {\em ipcalc}:
+
+\begin{bashinput}
+$ ninja
+\end{bashinput}
+
+And now install \code{ipcalc} to the build space:
+
+\begin{bashinput}
+$ DESTDIR=$HOME/__SESSION_NAME__-labs/thirdparty/staging ninja install
+\end{bashinput}
+
+Check that the \code{staging/usr/bin/ipcalc} file is indeed an ARM
+executable.
+
+The last thing to do is to copy it to the target space and strip it:
+
+\begin{bashinput}
+$ cd ../..
+$ cp staging/usr/bin/ipcalc target/usr/bin/
+$ aarch64-linux-strip target/usr/bin/ipcalc
+\end{bashinput}
+
+Note that we could have asked \code{ninja install} to strip the
+executable for us when installing it into the staging directory.
+To do, this, we would have added a \code{strip} entry in the cross file,
+and passed \code{--strip} to {\em Meson}. However, it's better to keep
+files unstripped in the staging space, in case we need to debug them.
+
+You can now test that \code{ipcalc} works on the target:
+
+\begin{bashinput}
+# ipcalc 192.168.0.100
+Address: 192.168.0.100
+Address space: Private Use
+\end{bashinput}
+
+\section{Final touch}
+
+To finish this lab completely, and to be consistent with what we've done before,
+let's strip the C library and its loader too.
+
+First, check the initial size of the binaries:
+\bashcmd{$ ls -l target/lib}
+
+Then strip the binaries in \code{/lib}:
+\begin{bashinput}
+$ chmod +w target/lib/*.so.*
+$ aarch64-linux-strip target/lib/*.so.*
+\end{bashinput}
+
+And check the final size:
+\bashcmd{$ ls -l target/lib/}
diff --git a/labs/sysdev-tinysystem/sysdev-tinysystem.tex b/labs/sysdev-tinysystem/sysdev-tinysystem.tex
index 80e081573f..0f01e12eb6 100644
--- a/labs/sysdev-tinysystem/sysdev-tinysystem.tex
+++ b/labs/sysdev-tinysystem/sysdev-tinysystem.tex
@@ -90,7 +90,7 @@ \section{Booting the system}
nfsroot=192.168.0.1:/home//__SESSION_NAME__-labs/tinysystem/nfsroot,nfsvers=3,tcp rw
\end{ubootinput}
\else
-\if\defstring{\labboard}{beagleplay}
+\if\defstring{\arch}{ARM64}
\begin{ubootinput}
=> setenv bootargs ${bootargs} root=/dev/nfs ip=192.168.0.100:::::eth0
nfsroot=192.168.0.1:/home//__SESSION_NAME__-labs/tinysystem/nfsroot,nfsvers=3,tcp rw
diff --git a/labs/sysdev-u-boot-imx93-frdm/indent.log b/labs/sysdev-u-boot-imx93-frdm/indent.log
new file mode 100644
index 0000000000..7b9b6e8573
--- /dev/null
+++ b/labs/sysdev-u-boot-imx93-frdm/indent.log
@@ -0,0 +1,22 @@
+INFO: latexindent version 3.23.6, 2024-01-17, a script to indent .tex files
+ latexindent lives here: /usr/share/texlive/texmf-dist/scripts/latexindent/
+ Fri Jun 13 09:46:15 2025
+ Filename: /home/antoine/training-materials/labs/sysdev-u-boot-imx93-frdm/sysdev-u-boot-imx93-frdm.tex
+INFO: Processing switches:
+INFO: Directory for backup files and indent.log:
+ /home/antoine/training-materials/labs/sysdev-u-boot-imx93-frdm
+INFO: YAML settings read: defaultSettings.yaml
+ Reading defaultSettings.yaml from /usr/share/texlive/texmf-dist/scripts/latexindent/defaultSettings.yaml
+INFO: YAML reading settings
+ Home directory is /home/antoine
+ latexindent.pl didn't find indentconfig.yaml or .indentconfig.yaml
+ see all possible locations: https://latexindentpl.readthedocs.io/en/latest/sec-appendices.html#indentconfig-options)
+INFO: Phase 1: searching for objects
+INFO: Phase 2: finding surrounding indentation
+INFO: Phase 3: indenting objects
+INFO: Phase 4: final indentation check
+INFO: Output routine:
+ Not outputting to file; see -w and -o switches for more options.
+ --------------
+INFO: Please direct all communication/issues to:
+ https://github.com/cmhughes/latexindent.pl
diff --git a/labs/sysdev-u-boot-imx93-frdm/sysdev-u-boot-imx93-frdm.tex b/labs/sysdev-u-boot-imx93-frdm/sysdev-u-boot-imx93-frdm.tex
new file mode 100644
index 0000000000..5b41aeaa57
--- /dev/null
+++ b/labs/sysdev-u-boot-imx93-frdm/sysdev-u-boot-imx93-frdm.tex
@@ -0,0 +1,525 @@
+\subchapter{Bootloader - TF-A and U-Boot}{Objectives: Set up serial
+ communication, compile and install the U-Boot bootloader, use basic
+ U-Boot commands, set up TFTP communication with the development
+ workstation.}
+
+As the bootloader is the first piece of software executed by a
+hardware platform, the installation procedure of the bootloader is
+very specific to the hardware platform. There are usually two cases:
+
+\begin{itemize}
+
+\item The processor offers nothing to ease the installation of the
+ bootloader, in which case the JTAG has to be used to initialize
+ flash storage and write the bootloader code to flash. Detailed
+ knowledge of the hardware is of course required to perform these
+ operations.
+
+\item The processor offers a monitor, implemented in ROM, and through
+ which access to the memories is made easier.
+
+\end{itemize}
+
+The i.MX93 processor falls into the second category. At startup, the ROM code
+initializes minimal hardware (clocks, RAM, etc.) and selects the boot source
+based on BOOT MODE pins and fuse values. It then looks for a valid boot
+container, typically stored on an SD card, eMMC, NOR flash, or received
+USB.
+
+The boot image container must include at least one valid OEM container
+(mandatory) and may include an optional NXP container. These containers hold
+firmware images for the Cortex-A55 and Cortex-M33 cores. The images are
+authenticated by the EdgeLock Secure Enclave. If authentication fails or no
+valid image is found, the processor enters a fallback mode using the Serial
+Download Protocol (SDP), allowing bootloader installation via USB with tools
+like uuu.
+
+This mechanism allows an i.MX93-based board such as the FRDM-i.MX93 to boot
+even without any pre-installed software, making initial setup easier.
+
+\section{Setup}
+
+Go to the \code{$HOME/__SESSION_NAME__-labs/bootloader} directory.
+
+\section{Setting up serial communication with the board}
+
+Plug the USB-C to USB-C cable into the Discovery board. The board has two USB-C ports: connect the power supply to the one labeled POWER, and use the one labeled DEBUG for data. The DEBUG port provides several debugging interfaces, including a serial console. Once connected to your computer, a new serial port should appear, {\tt \hosttty}.
+
+You can also see this device appear by looking at the output of
+\code{sudo dmesg}.
+
+To communicate with the board through the serial port, install a
+serial communication program, such as \code{picocom}:
+
+\bashcmd{$ sudo apt install picocom}
+
+If you run {\tt ls -l \hosttty}, you can also see that only
+\code{root} and users belonging to the \code{dialout} group have
+read and write access to the serial console. Therefore, you need
+to add your user to the \code{dialout} group:
+
+\bashcmd{$ sudo adduser $USER dialout}
+
+{\bf Important}: for the group change to be effective, you have to
+reboot your computer (at least on Ubuntu 24.04) and log in again.
+A workaround is to run \code{newgrp dialout}, but it is not global.
+You have to run it in each terminal.
+
+Run {\tt picocom -b 115200 \hosttty}, to start serial
+communication on {\tt \hosttty}, with a baudrate of 115200.
+If you wish to exit \code{picocom}, press \code{[Ctrl][a]} followed by
+\code{[Ctrl][x]}.
+
+Don't be surprised if you don't get anything on the serial console yet,
+even if you reset the board. That's because the SoC has nothing to boot
+on yet. We will prepare a micro SD card to boot on in the next paragraphs.
+
+\section{TF-A and U-Boot relationship}
+
+The boot process on the i.MX93 platform consists of two main stages. Upon
+power-up, the SoC’s internal ROM code executes and selects a boot image
+container set from the configured boot device (e.g., SD card or QSPI flash). It
+authenticates the container headers, then loads and verifies the contained
+images with the help of the EdgeLock Secure Enclave.
+
+The ROM code loads the first-stage bootloader (FSBL) embedded in ROM, which
+handles early hardware initialization, such as DRAM setup. Once complete,
+control is passed to the second-stage bootloader (SSBL), which continues the
+boot process and eventually launches the operating system.
+
+In our setup, the FSBL is provided by the ROM (no external BL2 is needed), and
+the SSBL is U-Boot. Both are packaged into a boot container using NXP’s boot
+image format. The container may also include components like the secure monitor
+(BL31), but in this setup, no trusted execution environment (OP-TEE) is used.
+These images are bundled into a Firmware Image Package (FIP) during the build
+process.
+
+\section{TF-A setup}
+
+Get the mainline TF-A sources:
+
+\begin{bashinput}
+$ cd ..
+$ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+$ cd trusted-firmware-a/
+$ git checkout v2.12.0
+\end{bashinput}
+
+Two configuration parameters have to be passed to the Makefile:
+\begin{itemize}
+\item Specify the cross-compiler prefix (the part before gcc in the
+ cross-compiler executable name), either using the environment
+ variable:\inlinebash{$ export CROSS_COMPILE=aarch64-linux-}, or just by
+ adding it to the \code{make} command line.
+
+\item And we have to specify the platform \code{PLAT=imx93}
+\end{itemize}
+
+We can now generate the \code{bl31} needed to build the container with u-boot.
+\begin{bashinput}
+$ make PLAT=imx93
+\end{bashinput}
+
+At the end of the build, the important output files generated are
+located in \code{build/imx93/release/}. We will find \code{bl31.bin} the EL3 runtime firmware.
+
+\section{U-Boot setup}
+
+Download U-Boot:
+
+\begin{bashinput}
+$ git clone https://github.com/u-boot/u-boot.git
+$ cd u-boot
+$ git checkout v2025.04
+\end{bashinput}
+
+Before continuing, we need to apply the patches located in bootloader/data/patches/u-boot/. These patches are necessary because the imx93-frdm board is not yet supported upstream.
+
+Get an understanding of U-Boot's configuration and compilation steps
+by reading the \code{README} file, and specifically the {\em Building
+the Software} section.
+
+Basically, you need to:
+
+\begin{enumerate}
+
+\item Retrieve the previously compiled bl31.bin file and place it in the U-Boot directory.
+\bashcmd{$ cp ../trusted-firmware-a/build/imx93/release/bl31.bin ./}
+
+\item Retrieve the NXP firmware required for DDR memory support
+\begin{bashinput}
+$ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.25-27879f8.bin
+$ chmod +x firmware-imx-8.25-27879f8.bin
+$ ./firmware-imx-8.25-27879f8.bin
+\end{bashinput}
+Once the conditions are accepted, copy the following files located in
+\code{firmware-imx-8.25-27879f8/firmware/ddr/synopsys/} to the root of the U-Boot source tree:
+
+lpddr4\_dmem\_1d\_v202201.bin \\
+lpddr4\_dmem\_2d\_v202201.bin \\
+lpddr4\_imem\_1d\_v202201.bin \\
+lpddr4\_imem\_2d\_v202201.bin
+
+\item Specify the cross-compiler prefix
+(the part before \code{gcc} in the cross-compiler executable name) and the
+architecture:
+\bashcmd{$ export CROSS_COMPILE=aarch64-linux-}
+
+\item Run \inlinebash{$ make _defconfig}, where the list of available
+ configurations can be found in the \code{configs/} directory. We will use the standard one (\code{imx93_11x11_frdm}).
+
+\item Now that you have a valid initial configuration, you can now
+ run \inlinebash{$ make menuconfig} to further edit your bootloader features.
+
+ \begin{itemize}
+
+ \item In the \code{Environment} submenu, we will configure U-Boot so
+ that it stores its environment inside a file called \code{uboot.env}
+ in an ext4 filesystem:
+ \begin{itemize}
+ \item Disable \code{Environment is not stored}. We want changes to variables to
+ be persistent across reboots
+ \item Enable \code{Environment is in a EXT4 filesystem}. Disable all other
+ options for environment storage (e.g.SPI, UBI)
+ \item The value for \code{Name of the block device for the environment} should be \code{mmc}
+ \item The value for \code{Device and partition for where to store
+ the environment in EXT4} should be \code{1:1} which indicates
+ we want to store the environment in the 1th partition of the
+ second MMC device (sd card).
+ \item The value for \code{Name of the EXT4 file to use for the
+ environment} should be \code{/uboot.env}, which indicates the
+ filename inside which the U-Boot environment will be stored
+ \item The value for \code{mmc device number} should be \code{-1}, to use our sdcard
+ \end{itemize}
+ \end{itemize}
+
+Install the following packages which should be needed to compile U-Boot for
+your board:
+
+\begin{bashinput}
+$ sudo apt install libssl-dev device-tree-compiler swig \
+ python3-dev python3-setuptools uuid-dev libgnutls28-dev
+\end{bashinput}
+
+\item Finally, run \bashcmd{make DEVICE_TREE=imx93-11x11-frdm}
+ which will build U-Boot
+ \footnote{You can speed up the
+ compiling by using the \code{-jX} option with \code{make}, where X
+ is the number of parallel jobs used for compiling. Twice the
+ number of CPU cores is a good value.}.
+ The \code{DEVICE_TREE} variable specifies the specific
+ Device Tree that describes our hardware board. If you wish to
+run just make, specify our board’s device tree name on Device Tree Control → Default Device Tree
+for DT Control option.
+
+This will generate a flash.bin file, which is our OEM container.
+
+{\bf Note}: u-boot build may fail on your machine if you have a recent
+version of python. Such issue is
+\href{https://source.denx.de/u-boot/u-boot/-/commit/a63456b9191fae2fe49f4b121e025792022e3950}{already
+fixed upstream}, but not in the version targeted for the training. To get the
+relevant fix,
+you can cherry-pick the fix onto your local branch:
+
+\code{git cherry-pick a63456b9191fae2fe49f4b121e025792022e3950}
+\end{enumerate}
+
+\section{Flashing the bootloaders}
+
+The ROM code on the i.MX93 platform is the first piece of software executed by
+the Cortex-A55 core in secure mode. It selects the boot source based on the
+configuration fuses and boot pins, and locates a valid boot container from the
+selected device (e.g., SD card or QSPI flash). The ROM verifies the container
+headers and authenticates the contained images with the help of the EdgeLock
+Secure Enclave.
+
+Once a valid image is found—typically the BL31 firmware—it is loaded into SRAM
+and executed. BL31 then initializes essential hardware components such as the
+clock tree and DDR controller. It subsequently loads and transfers control to
+the Second Stage Bootloader (SSBL), which is U-Boot in our case. U-Boot
+continues system initialization and is responsible for loading and booting the
+Linux kernel.
+
+So, as far as bootloaders are concerned, the SD card partitioning will
+look like:
+
+\begin{verbatim}
+Number Start End Size File system Name Flags
+ 1 2.00MiB 10.0MiB 8.00MiB ext4 bootfs
+
+\end{verbatim}
+We intentionally leave the initial space on the device unallocated, so we can
+later burn our flash.bin there. Then, we create a partition to store U-Boot
+environment variables.
+
+On your workstation, plug in the SD card your instructor gave you. Type
+the \code{sudo dmesg} command to see which device is used by your
+workstation. In case the device is \code{/dev/mmcblk0}, you will see
+something like
+
+\begin{verbatim}
+[46939.425299] mmc0: new high speed SDHC card at address 0007
+[46939.427947] mmcblk0: mmc0:0007 SD16G 14.5 GiB
+\end{verbatim}
+
+The device file name may be different (such as \code{/dev/sdb}
+if the card reader is connected to a USB bus (either internally
+or using a USB card reader).
+
+In the following instructions, we will assume that your SD card is
+seen as \code{/dev/mmcblk0} by your PC workstation.
+
+Type the \code{mount} command to check your currently mounted
+partitions. If SD partitions are mounted, unmount them:
+
+\bashcmd{$ sudo umount /dev/mmcblk0p*}
+
+We will erase the existing partition table and partition contents
+by simply zero-ing the first 128 MiB of the SD card:
+
+\bashcmd{$ sudo dd if=/dev/zero of=/dev/mmcblk0 bs=1M count=128}
+
+Now, let's use the \code{parted} command to create the partitions that
+we are going to use:
+
+\bashcmd{$ sudo parted /dev/mmcblk0}
+
+The ROM monitor handles {\em GPT} partition tables, let's create one:
+
+\begin{verbatim}
+(parted) mklabel gpt
+\end{verbatim}
+
+Then, the 4 partitions are created with:
+\begin{verbatim}
+(parted) unit mib
+(parted) mkpart bootfs ext4 2 10
+\end{verbatim}
+
+You can verify everything looks right with:
+
+\begin{verbatim}
+(parted) print
+Model: SD SA08G (sd/mmc)
+Disk /dev/mmcblk0: 15278080s
+Sector size (logical/physical): 512B/512B
+Partition Table:
+Disk Flags:
+
+Number Start End Size File system Name Flags
+ 1 2.00MiB 10.0MiB 8.00MiB ext4 bootfs
+
+\end{verbatim}
+
+Once done, quit:
+\begin{verbatim}
+(parted) quit
+\end{verbatim}
+
+{\em Note: \code{parted} is definitely not very user friendly compared
+to other tools to manipulate partitions (such as \code{cfdisk}), but
+that's the only tool which supports assigning names to GPT partitions.
+In your projects, you could use \code{gparted}, which is a more
+friendly graphical front-end on top of \code{parted}.}
+
+Now, format the boot partition as an ext4 filesystem. This is where
+U-Boot saves its environment:
+\bashcmd{$ sudo mkfs.ext4 -L boot -O ^metadata_csum /dev/mmcblk0p1}
+
+The \code{-O ^metadata_csum} option allows to create the filesystem
+without enabling metadata checksums, which U-Boot doesn't seem to
+support yet.
+
+Now burn the flash.bin container to the SD card.
+\begin{bashinput}
+$ sudo dd if=./flash.bin of=/dev/mmcblk0 bs=1k seek=32 conv=fsync
+\end{bashinput}
+
+\section{Testing the bootloaders}
+
+Insert the SD card in the board slot. You can now power-up the board
+by connecting the USB-C cable to the board, \code{POWER} and
+to your PC at the other end. Check that it boots your new bootloaders.
+You can verify this by checking the build dates:
+
+\begin{verbatim}
+U-Boot SPL 2025.07-rc2-00029-g354a2daf873f (Jun 13 2025 - 10:20:47 +0200)
+SOC: 0xa1009300
+LC: 0x40010
+PMIC: PCA9451A
+PMIC: Over Drive Voltage Mode
+DDR: 3733MTS
+DDR: 3733MTS
+found DRAM 2GB DRAM matched
+M33 prepare ok
+Normal Boot
+Trying to boot from BOOTROM
+Boot Stage: Primary boot
+image offset 0x8000, pagesize 0x200, ivt offset 0x0
+Load image from 0x3a000 by ROM_API
+NOTICE: TRDC init done
+NOTICE: BL31: v2.12.0(release):v2.13-rc1-2-gb68861c72
+NOTICE: BL31: Built : 10:37:35, May 20 2025
+
+
+U-Boot 2025.07-rc2-00029-g354a2daf873f (Jun 13 2025 - 10:20:47 +0200)
+
+Reset Status: POR
+
+CPU: NXP i.MX93(52) Rev1.1 A55 at 1700 MHz
+CPU: Industrial temperature grade (-40C to 105C) at 49C
+Model: NXP i.MX93 11X11 FRDM board
+DRAM: 2 GiB
+BOARD: V1.0(ADC2:690,ADC3:319)
+Core: 217 devices, 28 uclasses, devicetree: separate
+WDT: Started wdog@42490000 with servicing every 1000ms (40s timeout)
+MMC: FSL_SDHC: 0, FSL_SDHC: 1
+Loading Environment from EXT4... ** File not found /uboot.env **
+
+** Unable to read "/uboot.env" from mmc1:1 **
+In: serial
+Out: serial
+Err: serial
+
+BuildInfo:
+ - ELE firmware not included
+
+Net:
+Warning: ethernet@42890000 (eth1) using random MAC address - 7e:ec:88:77:c0:54
+
+Warning: ethernet@428a0000 (eth0) using random MAC address - 3a:eb:d6:c9:94:b6
+eth0: ethernet@428a0000, eth1: ethernet@42890000 [PRIME]
+=>
+\end{verbatim}
+
+In U-Boot, type the \code{help} command, and explore the few commands
+available.
+
+\subsection{Adding a new command to the U-Boot shell}
+
+Check whether the \code{config} command is available. This command
+allows to dump the configuration settings U-Boot was compiled from.
+
+If it's not, go back to U-Boot's configuration and enable it.
+
+Re-run the build of TF-A, copy bl31.bin, then rebuild U-Boot. Re-flash the SD
+card with the new flash.bin and verify that the command is now available and
+as expected.
+
+\subsection{Playing with the U-Boot environment}
+
+Display the U-Boot environment using \code{printenv}.
+
+Set a new U-Boot variable \code{foo} to a value of your choice, using
+\code{setenv}, and verify it has been set. Reset the board, and check
+if \code{foo} is still defined: it should not.
+
+Now repeat this process, but before resetting the board, use
+\code{saveenv}. After the reset, check the \code{foo} variable is
+still defined.
+
+Now reset the environment to its default settings using \code{env
+ default -a}, and save these changes using \code{saveenv}.
+
+\section{Setting up networking}
+
+The next step is to configure U-boot and your workstation to let your
+board download files, such as the kernel image and Device Tree Binary
+(DTB), using the TFTP protocol through a network connection.
+
+With a network cable, connect the Ethernet port of
+your board to the one of your computer. If your computer already has a
+wired connection to the network, your instructor will provide you with
+a USB Ethernet adapter. A new network interface should appear on your
+Linux system.
+
+\subsection{Network configuration on the target}
+
+Let's configure networking in U-Boot:
+
+\begin{itemize}
+ \item \code{ipaddr}: IP address of the board
+ \item \code{serverip}: IP address of the PC host
+\end{itemize}
+
+\begin{ubootinput}
+=> setenv ipaddr 192.168.0.100
+=> setenv serverip 192.168.0.1
+\end{ubootinput}
+
+Of course, make sure that this address belongs to a separate network
+segment from the one of the main company network.
+
+To make these settings permanent, save the environment:
+
+\begin{ubootinput}
+=> saveenv
+\end{ubootinput}
+
+\subsection{Network configuration on the PC host}
+
+To configure your network interface on the workstation side, we need
+to know the name of the network interface connected to your board.
+
+Find the name of this interface by typing:
+\bashcmd{=> ip a}
+
+The network interface name is likely to be
+\code{enxxx}\footnote{Following the {\em Predictable Network Interface
+Names} convention:
+\url{https://www.freedesktop.org/wiki/Software/systemd/PredictableNetworkInterfaceNames/}}.
+If you have a pluggable Ethernet device, it's easy to identify as it's
+the one that shows up after pluging in the device.
+
+Then, instead of configuring the host IP address from NetworkManager's
+graphical interface, let's do it through its command line interface,
+which is so much easier to use:
+
+\bashcmd{$ nmcli con add type ethernet ifname en... ip4 192.168.0.1/24}
+
+\section{Setting up the TFTP server}
+
+Let's install a TFTP server on your development workstation:
+
+\begin{verbatim}
+sudo apt install tftpd-hpa
+\end{verbatim}
+
+You can then test the TFTP connection. First, put a small text file in
+the directory exported through TFTP on your development
+workstation. Then, from U-Boot, do:
+
+\begin{ubootinput}
+=> tftp %\zimageboardaddr% textfile.txt
+\end{ubootinput}
+
+The \code{tftp} command should have downloaded the
+\code{textfile.txt} file from your development workstation into
+the board's memory at location {\tt \zimageboardaddr}\footnote{
+This location is part of the board DRAM. If you want
+to check where this value comes from, you can check the SoC
+datasheet at
+\url{https://www.st.com/resource/en/reference_manual/dm00327659.pdf}.
+It's a big document (more than 4,000 pages). In this document, look
+for \code{Memory organization} and you will find the SoC memory map.
+You will see that the address range for the memory controller
+({\em DDRC})
+starts at the address we are looking for.
+You can also try with other values in the RAM address range.}.
+
+You can verify that the download was successful by dumping the
+contents of the memory:
+
+\begin{ubootinput}
+=> md %\zimageboardaddr%
+\end{ubootinput}
+
+We will see in the next labs how to use U-Boot to download, flash and
+boot a kernel.
+
+\section{Rescue binaries}
+
+If you have trouble generating binaries that work properly, or later
+make a mistake that causes you to lose your bootloader binaries, you
+will find working versions under \code{data/} in the current lab
+directory.
diff --git a/mk/embedded-linux-bbb.mk b/mk/embedded-linux-bbb.mk
index 1f2d67539b..1c1da76e5f 100644
--- a/mk/embedded-linux-bbb.mk
+++ b/mk/embedded-linux-bbb.mk
@@ -7,6 +7,7 @@ EMBEDDED_LINUX_BBB_SLIDES = \
discovery-board-also-supported \
beagleplay-board-also-supported \
stm32mp2-board-also-supported \
+ imx93-frdm-board-also-supported \
course-information \
sysdev-intro \
sysdev-dev-environment \
diff --git a/mk/embedded-linux-beagleplay.mk b/mk/embedded-linux-beagleplay.mk
index 754742f49f..9512b1a93e 100644
--- a/mk/embedded-linux-beagleplay.mk
+++ b/mk/embedded-linux-beagleplay.mk
@@ -7,6 +7,7 @@ EMBEDDED_LINUX_BEAGLEPLAY_SLIDES = \
discovery-board-also-supported \
beagleboneblack-board-also-supported \
stm32mp2-board-also-supported \
+ imx93-frdm-board-also-supported \
course-information \
sysdev-intro \
sysdev-dev-environment \
diff --git a/mk/embedded-linux-imx93-frdm.mk b/mk/embedded-linux-imx93-frdm.mk
new file mode 100644
index 0000000000..1cc07f3046
--- /dev/null
+++ b/mk/embedded-linux-imx93-frdm.mk
@@ -0,0 +1,65 @@
+EMBEDDED_LINUX_IMX93_FRDM_SLIDES = \
+ first-slides \
+ about-us \
+ course-information-title \
+ discovery-board-imx93-frdm \
+ sysdev-shopping-list-imx93-frdm \
+ discovery-board-also-supported \
+ beagleboneblack-board-also-supported \
+ beagleplay-board-also-supported \
+ stm32mp2-board-also-supported \
+ course-information \
+ sysdev-intro \
+ sysdev-dev-environment \
+ setup-lab \
+ sysdev-toolchains-title \
+ sysdev-toolchains-definition \
+ sysdev-toolchains-options \
+ sysdev-toolchains-obtaining \
+ sysdev-toolchains-lab \
+ sysdev-bootloaders-title \
+ sysdev-bootloaders-sequence \
+ sysdev-bootloaders-u-boot \
+ sysdev-bootloaders-tf-a \
+ sysdev-bootloaders-lab \
+ sysdev-linux-intro-title \
+ sysdev-linux-intro-features \
+ sysdev-linux-intro-versioning \
+ sysdev-linux-intro-sources \
+ sysdev-fetching-linux-kernel-sources-lab \
+ sysdev-kernel-building \
+ sysdev-customizing-dt \
+ sysdev-kernel-booting \
+ sysdev-linux-intro-lab-cross-compilation \
+ sysdev-root-filesystem-title \
+ sysdev-root-filesystem-principles \
+ initramfs \
+ sysdev-root-filesystem-contents \
+ sysdev-root-filesystem-virtual-fs \
+ sysdev-root-filesystem-minimal \
+ boot-sequence-initramfs \
+ sysdev-busybox \
+ sysdev-hw-devices \
+ sysdev-block-filesystems \
+ sysdev-flash-filesystems \
+ sysdev-cross-compiling-user-space \
+ sysdev-build-systems \
+ sysdev-licensing \
+ sysdev-software-stacks \
+ sysdev-application-development \
+ sysdev-references \
+ last-slides \
+ sysdev-extra-slides
+
+EMBEDDED_LINUX_IMX93_FRDM_LABS = setup \
+ sysdev-toolchain \
+ sysdev-u-boot-imx93-frdm \
+ sysdev-kernel-fetch-sources \
+ sysdev-kernel-cross-compiling \
+ sysdev-tinysystem \
+ sysdev-accessing-hardware-imx93-frdm \
+ sysdev-block-filesystems-imx93-frdm \
+ sysdev-thirdparty-imx93-frdm \
+ sysdev-buildroot \
+ sysdev-system-integration \
+ sysdev-application-development-and-debugging
\ No newline at end of file
diff --git a/mk/embedded-linux-qemu.mk b/mk/embedded-linux-qemu.mk
index 4e98c7a4b6..9bba746e5f 100644
--- a/mk/embedded-linux-qemu.mk
+++ b/mk/embedded-linux-qemu.mk
@@ -7,6 +7,7 @@ EMBEDDED_LINUX_QEMU_SLIDES = \
beagleboneblack-board-also-supported \
beagleplay-board-also-supported \
stm32mp2-board-also-supported \
+ imx93-frdm-board-also-supported \
course-information \
sysdev-intro \
sysdev-dev-environment \
diff --git a/mk/embedded-linux-stm32mp2.mk b/mk/embedded-linux-stm32mp2.mk
index 7756b34b6c..c7c843a0e8 100644
--- a/mk/embedded-linux-stm32mp2.mk
+++ b/mk/embedded-linux-stm32mp2.mk
@@ -7,6 +7,7 @@ EMBEDDED_LINUX_STM32MP2_SLIDES = \
discovery-board-also-supported \
beagleboneblack-board-also-supported \
beagleplay-board-also-supported \
+ imx93-frdm-board-also-supported \
course-information \
sysdev-intro \
sysdev-dev-environment \
diff --git a/mk/embedded-linux.mk b/mk/embedded-linux.mk
index 9b9b4a4ec1..a08ce95533 100644
--- a/mk/embedded-linux.mk
+++ b/mk/embedded-linux.mk
@@ -7,6 +7,7 @@ EMBEDDED_LINUX_SLIDES = \
beagleboneblack-board-also-supported \
beagleplay-board-also-supported \
stm32mp2-board-also-supported \
+ imx93-frdm-board-also-supported \
course-information \
sysdev-intro \
sysdev-dev-environment \
diff --git a/slides/discovery-board-imx93-frdm/discovery-board-imx93-frdm.tex b/slides/discovery-board-imx93-frdm/discovery-board-imx93-frdm.tex
new file mode 100644
index 0000000000..7350fd1b36
--- /dev/null
+++ b/slides/discovery-board-imx93-frdm/discovery-board-imx93-frdm.tex
@@ -0,0 +1,28 @@
+\begin{frame}
+\frametitle{Supported hardware}
+ NXP i.MX93 11x11 FRDM development board
+ \footnotesize
+ \begin{columns}
+ \column{0.6\textwidth}
+ \begin{itemize}
+ \item i.MX93 SoC (Dual Cortex-A55 + Cortex-M33)
+ \item 2 GB LPDDR4X, 32 GB eMMC
+ \item Dual Gigabit Ethernet
+ \item USB 2.0 Type-C + USB Type-A
+ \item CAN interface
+ \item MicroSD slot, EEPROM
+ \item Wi-Fi 6 + Bluetooth 5.4 + 802.15.4 (MAYA-W276)
+ \item HDMI output (via LVDS), MIPI DSI and CSI
+ \item Audio jack (MQS), buttons and LEDs
+ \item SWD and UART debug
+ \end{itemize}
+ \column{0.4\textwidth}
+ \begin{center}
+ \includegraphics[width=\textwidth]{slides/discovery-board-imx93-frdm/imx93-frdm.png}\\
+ IMX93 FRDM Board
+ \end{center}
+ \end{columns}
+ \vspace{0.5em}
+ Documentation and resources: \\
+ \href{https://www.nxp.com/design/design-center/development-boards-and-designs/frdm-i-mx-93-development-board:FRDM-IMX93}{nxp.com/imx93-frdm}
+\end{frame}
diff --git a/slides/discovery-board-imx93-frdm/imx93-frdm.png b/slides/discovery-board-imx93-frdm/imx93-frdm.png
new file mode 100644
index 0000000000..2d5011e6d1
Binary files /dev/null and b/slides/discovery-board-imx93-frdm/imx93-frdm.png differ
diff --git a/slides/imx93-frdm-board-also-supported/imx93-frdm-board-also-supported.tex b/slides/imx93-frdm-board-also-supported/imx93-frdm-board-also-supported.tex
new file mode 100644
index 0000000000..ea88df00e7
--- /dev/null
+++ b/slides/imx93-frdm-board-also-supported/imx93-frdm-board-also-supported.tex
@@ -0,0 +1,14 @@
+\begin{frame}
+\frametitle{Labs proposed on another platform}
+ \begin{columns}
+ \column{0.7\textwidth}
+ You can also run the labs of this course on the IMX93-FRDM board.\\
+ \vspace{1em}
+ Lab instructions are available at\\
+ {\small \url{https://bootlin.com/doc/training/__SESSION_NAME__-imx93-frdm}}
+ \column{0.3\textwidth}
+ \begin{center}
+ \includegraphics[width=\textwidth]{../slides/imx93-frdm-board-also-supported/imx93-frdm.png}
+ \end{center}
+ \end{columns}
+\end{frame}
\ No newline at end of file
diff --git a/slides/imx93-frdm-board-also-supported/imx93-frdm.png b/slides/imx93-frdm-board-also-supported/imx93-frdm.png
new file mode 100644
index 0000000000..2d5011e6d1
Binary files /dev/null and b/slides/imx93-frdm-board-also-supported/imx93-frdm.png differ
diff --git a/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx6.dia b/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx6.dia
new file mode 100644
index 0000000000..104eda4218
--- /dev/null
+++ b/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx6.dia
@@ -0,0 +1,888 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ #A4#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+#include <dt-bindings/clock/imx6ul-clock.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "imx6ul-pinfunc.h"#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+#include "imx6ul.dtsi"
+#include "imx6ull-pinfunc.h"
+#include "imx6ull-pinfunc-snvs.h"#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+#include <dt-bindings/gpio/gpio.h>#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+#include <dt-bindings/gpio/gpio.h>#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+#include "imx6ull.dtsi"
+#include "imx6ull-seeed-npi.dtsi"
+#include "imx6ull-seeed-npi-dev-board.dtsi"#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+#include "imx6ull.dtsi"
+#include "imx6ull-seeed-npi.dtsi"
+#include "imx6ull-seeed-npi-dev-board.dtsi"#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imx6ul.dtsi#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imx6ull.dtsi#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imx6ull-seeed-npi.dtsi#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imx6ull-seeed-npi-dev-board.dtsi#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imx6ull-seeed-npi-dev-board-emmc.dts#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imx6ull-seeed-npi-dev-board-nand.dts#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx93-frdm.dia b/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx93-frdm.dia
new file mode 100644
index 0000000000..bcf2726009
--- /dev/null
+++ b/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx93-frdm.dia
@@ -0,0 +1,533 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ #A4#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+
+#include <dt-bindings/usb/pd.h>
+#include "imx93.dtsi"#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+
+#include <dt-bindings/usb/pd.h>
+#include "imx93.dtsi"#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imx93.dtsi#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #SOC#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #BOARD#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imx93-11x11-evk.dts#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #imx93-11x11-frdm.dts#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx93-frdm.pdf b/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx93-frdm.pdf
new file mode 100644
index 0000000000..f53a6a28b9
Binary files /dev/null and b/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx93-frdm.pdf differ
diff --git a/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance.dia b/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance.dia
new file mode 100644
index 0000000000..a829f6cb82
--- /dev/null
+++ b/slides/sysdev-hw-devices/imx93-frdm/dt-inheritance.dia
@@ -0,0 +1,369 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ #A4#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+ / {
+ soc@0 {
+ lpi2c1: i2c@44340000 {
+ compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
+ reg = <0x44340000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_LPI2C1_GATE>;
+ clock-names = "per", "ipg";
+ status = "disabled";
+ };
+ };
+ };#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+ / {
+ soc@0 {
+ lpi2c1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-frequency = <400000>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&pinctrl_lpi2c1>;
+ pinctrl-1 = <&pinctrl_lpi2c1>;
+ status = "okay";
+ };
+ };
+ };#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #
+ / {
+ soc@0 {
+ lpi2c1: i2c@44340000 {
+ compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
+ reg = <0x44340000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clk IMX93_CLK_LPI2C1_GATE>;
+ clock-names = "per", "ipg";
+ clock-frequency = <400000>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&pinctrl_lpi2c1>;
+ pinctrl-1 = <&pinctrl_lpi2c1>;
+ status = "okay";
+ };
+ };
+ }; #
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/slides/sysdev-hw-devices/imx93-frdm/imx93-tab-gpio21.png b/slides/sysdev-hw-devices/imx93-frdm/imx93-tab-gpio21.png
new file mode 100644
index 0000000000..dbb09ae3b5
Binary files /dev/null and b/slides/sysdev-hw-devices/imx93-frdm/imx93-tab-gpio21.png differ
diff --git a/slides/sysdev-hw-devices/imx93-frdm/led-on.jpg b/slides/sysdev-hw-devices/imx93-frdm/led-on.jpg
new file mode 100644
index 0000000000..a478d02795
Binary files /dev/null and b/slides/sysdev-hw-devices/imx93-frdm/led-on.jpg differ
diff --git a/slides/sysdev-hw-devices/imx93-frdm/simple-hardware-imx93-frdm.dia b/slides/sysdev-hw-devices/imx93-frdm/simple-hardware-imx93-frdm.dia
new file mode 100644
index 0000000000..2eee31f87e
--- /dev/null
+++ b/slides/sysdev-hw-devices/imx93-frdm/simple-hardware-imx93-frdm.dia
@@ -0,0 +1,946 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ #Letter#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #System-on-chip#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #CPU cores#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #I2C controller#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Ethernet MAC#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #GIC
+IRQ controller#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #MMC
+controller#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #EEPROM#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ##
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #eMMC 5.1#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Cortex A55#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Cortex A55#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #Ethernet
+PHY#
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/slides/sysdev-hw-devices/imx93-frdm/sysdev-hw-devices-imx93-frdm.tex b/slides/sysdev-hw-devices/imx93-frdm/sysdev-hw-devices-imx93-frdm.tex
new file mode 100644
index 0000000000..2ac9db9332
--- /dev/null
+++ b/slides/sysdev-hw-devices/imx93-frdm/sysdev-hw-devices-imx93-frdm.tex
@@ -0,0 +1,1072 @@
+\begin{frame}[fragile]{DT overall structure: simplified example}
+ \begin{columns}
+ \column{0.6\textwidth}
+ \begin{onlyenv}<1>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ model = "NXP i.MX93 11X11 FRDM board";
+ compatible = "fsl,imx93-11x11-frdm", "fsl,imx93";
+
+ cpus { ... };
+ reserved-memory { ... };
+ chosen { ... };
+ gic: interrupt-controller@48000000 { ... };
+ soc {
+ lpi2c1: i2c@44340000 { ... };
+ eqos: ethernet@428a0000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<2>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ A55_0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a55";
+ reg = <0x0>;
+ enable-method = "psci";
+ #cooling-cells = <2>;
+ };
+
+ A55_1: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a55";
+ reg = <0x100>;
+ enable-method = "psci";
+ #cooling-cells = <2>;
+ };
+ };
+
+ reserved-memory { ... };
+ chosen { ... };
+ intc: interrupt-controller@a0021000 { ... };
+ soc {
+ i2c1: i2c@40012000 { ... };
+ ethernet0: ethernet@5800a000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<3>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ cpus { ... };
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ linux,cma {
+ compatible = "shared-dma-pool";
+ reusable;
+ alloc-ranges = <0 0x80000000 0 0x40000000>;
+ size = <0 0x10000000>;
+ linux,cma-default;
+ };
+ };
+ chosen {
+ bootargs = "console=ttyLP0,115200";
+ stdout-path = &lpuart1;
+ };
+ gic: interrupt-controller@48000000 { ... };
+ soc {
+ lpi2c1: i2c@44340000 { ... };
+ eqos: ethernet@428a0000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<4>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ cpus { ... };
+ reserved-memory { ... };
+ chosen { ... };
+
+ gic: interrupt-controller@48000000 {
+ compatible = "arm,gic-v3";
+ reg = <0 0x48000000 0 0x10000>,
+ <0 0x48040000 0 0xc0000>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ interrupts = ;
+ interrupt-parent = <&gic>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x0 0x80000000>,
+ <0x28000000 0x0 0x28000000 0x10000000>;
+
+ lpi2c1: i2c@44340000 { ... };
+ eqos: ethernet@428a0000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<5>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ cpus { ... };
+ reserved-memory { ... };
+ chosen { ... };
+ gic: interrupt-controller@48000000 { ... };
+ soc {
+ compatible = "simple-bus";
+ ...
+ lpi2c1: i2c@44340000 {
+ compatible = "fsl,imx93-lpi2c", "fsl,imx7ulp-lpi2c";
+ reg = <0x44340000 0x10000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = ;
+ clocks = <&clk IMX93_CLK_LPI2C1_GATE>,
+ <&clk IMX93_CLK_BUS_AON>;
+ clock-names = "per", "ipg";
+ status = "disabled";
+ };
+ eqos: ethernet@428a0000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<6>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ soc {
+ compatible = "simple-bus";
+ ...
+ lpi2c1: i2c@44340000 { ... };
+ eqos: ethernet@428a0000 {
+ compatible = "nxp,imx93-dwmac-eqos", "snps,dwmac-5.10a";
+ reg = <0x428a0000 0x10000>;
+ interrupts = ,
+ ;
+ status = "okay";
+
+ mdio {
+ compatible = "snps,dwmac-mdio";
+ ...
+ ethphy1: ethernet-phy@1 {
+ reg = <1>;
+ eee-broken-1000t;
+ reset-gpios = <&pcal6524 15 GPIO_ACTIVE_LOW>;
+ reset-assert-us = <15000>;
+ reset-deassert-us = <100000>;
+ };
+ };
+ };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \column{0.4\textwidth}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/imx93-frdm/simple-hardware-imx93-frdm.pdf}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Device Tree inheritance}
+ \begin{itemize}
+ \item Device Tree files are not monolithic, they can be split in
+ several files, including each other.
+ \item \code{.dtsi} files are included files, while \code{.dts} files
+ are {\em final} Device Trees
+ \begin{itemize}
+ \item Only \code{.dts} files are accepted as input to \code{dtc}
+ \end{itemize}
+ \item Typically, \code{.dtsi} will contain
+ \begin{itemize}
+ \item definitions of SoC-level information
+ \item definitions common to several boards
+ \end{itemize}
+ \item The \code{.dts} file contains the board-level information
+ \item The inclusion works by {\bf overlaying} the tree of the
+ including file over the tree of the included file,
+ according to the order of the \code{#include} directives.
+ \item Allows an including file to {\bf override} values specified by
+ an included file
+ \item Uses the C pre-processor \code{#include} directive
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{Device Tree inheritance example}
+ \begin{center}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/imx93-frdm/dt-inheritance.pdf}
+ \end{center}
+\end{frame}
+
+\begin{frame}[fragile]{Inheritance and labels}
+
+ \begin{columns}[t]
+ \column{0.5\textwidth}
+ Doing:
+ \begin{block}{soc.dtsi}
+ {\tiny
+\begin{minted}{perl}
+/ {
+ soc {
+ lpuart1: serial@44380000 {
+ compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+ reg = <0x44380000 0x1000>;
+ interrupts = ;
+ clocks = <&clk IMX93_CLK_LPUART1_GATE>, ... ;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };};};
+\end{minted}
+ }
+ \end{block}
+
+ \begin{block}{board.dts}
+ {\tiny
+\begin{minted}{perl}
+#include "soc.dtsi"
+
+/ {
+ soc {
+ serial@44380000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+ };};};
+
+\end{minted}
+ }
+ \end{block}
+
+ \column{0.5\textwidth}
+ \begin{onlyenv}<2>
+ Is exactly equivalent to:
+
+ \begin{block}{soc.dtsi}
+ {\tiny
+\begin{minted}{perl}
+/ {
+ soc {
+ lpuart1: serial@44380000 {
+ compatible = "fsl,imx93-lpuart", "fsl,imx7ulp-lpuart";
+ reg = <0x44380000 0x1000>;
+ interrupts = ;
+ clocks = <&clk IMX93_CLK_LPUART1_GATE>, ... ;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };};};
+\end{minted}
+ }
+ \end{block}
+
+ \begin{block}{board.dts}
+ {\tiny
+\begin{minted}{perl}
+#include "soc.dtsi"
+
+&lpuart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+\end{minted}
+ }
+ \end{block}
+
+ $\rightarrow$ this solution is now often preferred
+ \end{onlyenv}
+ \end{columns}
+
+\end{frame}
+
+\begin{frame}{DT inheritance in imx93-frdm support}
+ \begin{center}
+ \includegraphics[height=0.8\textheight]{slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx93-frdm.pdf}
+ \end{center}
+\end{frame}
+
+\begin{frame}{DT inheritance in imx6ull-seed-npi-dev-board support}
+ \begin{center}
+ \includegraphics[height=0.8\textheight]{slides/sysdev-hw-devices/imx93-frdm/dt-inheritance-imx6.pdf}
+ \end{center}
+\end{frame}
+
+\begin{frame}{Device Tree design principles}
+ \begin{itemize}
+ \item {\bf Describe hardware} (how the hardware is), not
+ configuration (how I choose to use the hardware)
+ \item {\bf OS-agnostic}
+ \begin{itemize}
+ \item For a given piece of HW, Device Tree should be the same for
+ U-Boot, FreeBSD or Linux
+ \item There should be no need to change the Device Tree when updating the OS
+ \end{itemize}
+ \item Describe {\bf integration of hardware components}, not the internals
+ of hardware components
+ \begin{itemize}
+ \item The details of how a specific device/IP block is working is
+ handled by code in device drivers
+ \item The Device Tree describes how the device/IP block is
+ connected/integrated with the rest of the system: IRQ lines, DMA
+ channels, clocks, reset lines, etc.
+ \end{itemize}
+ \item Like all beautiful design principles, these principles are
+ sometimes violated.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{Device Tree specifications}
+ \begin{columns}
+ \column{0.7\textwidth}
+ \begin{itemize}
+ \item How to write the correct nodes/properties to describe a
+ given hardware platform~?
+ \item {\bf Device Tree Specifications} $\rightarrow$ base Device
+ Tree syntax + number of standard properties.
+ \begin{itemize}
+ \item \url{https://www.devicetree.org/specifications/}
+ \item Not sufficient to describe the wide variety of hardware.
+ \end{itemize}
+ \item {\bf Device Tree Bindings} $\rightarrow$ documents that each
+ specify how a piece of HW should be described
+ \begin{itemize}
+ \item \kdir{Documentation/devicetree/bindings} in Linux kernel sources
+ \item Reviewed by DT bindings maintainer team
+ \item Legacy: human readable documents
+ \item New norm: YAML-written specifications
+ \end{itemize}
+ \end{itemize}
+ \column{0.3\textwidth}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/dt-spec.png}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Device Tree binding: old style}
+ \begin{center}
+ \kfile{Documentation/devicetree/bindings/mtd/spear_smi.txt}\\
+ This IP is {\em not} used on IMX93.
+ \end{center}
+ \begin{columns}[t]
+ \column{0.5\textwidth}
+ \begin{block}{}
+ {\fontsize{5}{6}\selectfont
+\begin{verbatim}
+* SPEAr SMI
+
+Required properties:
+- compatible : "st,spear600-smi"
+- reg : Address range of the mtd chip
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+ representing partitions.
+- interrupts: Should contain the STMMAC interrupts
+- clock-rate : Functional clock rate of SMI in Hz
+
+Optional properties:
+- st,smi-fast-mode : Flash supports read in fast mode
+
+\end{verbatim}
+ }
+ \end{block}
+ \column{0.5\textwidth}
+ \begin{block}{}
+ {\fontsize{4}{5}\selectfont
+\begin{verbatim}
+Example:
+
+ smi: flash@fc000000 {
+ compatible = "st,spear600-smi";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xfc000000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <12>;
+ clock-rate = <50000000>; /* 50MHz */
+
+ flash@f8000000 {
+ st,smi-fast-mode;
+ ...
+ };
+ };
+\end{verbatim}
+ }
+ \end{block}
+ \end{columns}
+
+\end{frame}
+
+\begin{frame}[fragile]{Device Tree binding: YAML style}
+ \kfile{Documentation/devicetree/bindings/i2c/i2c-imx-lpi2c.yaml}
+ \begin{columns}[t]
+ \column{0.5\textwidth}
+ \begin{block}{}
+ {\fontsize{5}{5}\selectfont
+\begin{minted}{yaml}
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/i2c-imx-lpi2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Freescale Low Power Inter IC (LPI2C) for i.MX
+
+maintainers:
+ - Shawn Guo
+ - Sascha Hauer
+ - Fabio Estevam
+
+allOf:
+ - $ref: /schemas/i2c/i2c-controller.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - fsl,imx7ulp-lpi2c
+ - items:
+ - enum:
+ - fsl,imx8qxp-lpi2c
+ - fsl,imx8dxl-lpi2c
+ - fsl,imx8qm-lpi2c
+ - fsl,imx8ulp-lpi2c
+ - fsl,imx93-lpi2c
+ - fsl,imx95-lpi2c
+ - const: fsl,imx7ulp-lpi2c
+
+ reg:
+ maxItems: 1
+
+\end{minted}
+ }
+ \end{block}
+ \column{0.5\textwidth}
+ \begin{block}{}
+ {\fontsize{5}{5}\selectfont
+\begin{minted}{yaml}
+ assigned-clock-parents: true
+ assigned-clock-rates: true
+ assigned-clocks: true
+ clock-frequency: true
+
+ clock-names:
+ items:
+ - const: per
+ - const: ipg
+
+ clocks:
+ maxItems: 2
+
+ dmas:
+ items:
+ - description: DMA controller phandle and request line for TX
+ - description: DMA controller phandle and request line for RX
+
+ dma-names:
+ items:
+ - const: tx
+ - const: rx
+
+ power-domains:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+
+unevaluatedProperties: false
+\end{minted}
+ }
+ \end{block}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Device Tree binding: YAML style example}
+ \begin{block}{}
+ {\fontsize{5}{7}\selectfont
+\begin{minted}{yaml}
+examples:
+ - |
+ #include
+ #include
+
+ i2c@40a50000 {
+ compatible = "fsl,imx7ulp-lpi2c";
+ reg = <0x40A50000 0x10000>;
+ interrupt-parent = <&intc>;
+ interrupts = ;
+ clocks = <&clks IMX7ULP_CLK_LPI2C7>,
+ <&clks IMX7ULP_CLK_NIC1_BUS_DIV>;
+ };
+
+\end{minted}
+ }
+ \end{block}
+\end{frame}
+
+\begin{frame}{Validating Device Tree in Linux}
+ \begin{itemize}
+ \item \code{dtc} only does syntactic validation
+ \item YAML bindings allow to do semantic validation
+ \item Linux kernel \code{make} rules:
+ \begin{itemize}
+ \item \code{make dt_binding_check}\\
+ verify that YAML bindings are valid
+ \item \code{make dtbs_check}\\
+ validate DTs currently enabled against YAML bindings
+ \item \code{make DT_SCHEMA_FILES=Documentation/devicetree/bindings/trivial-devices.yaml dtbs_check}\\
+ validate DTs against a specific YAML binding
+ \end{itemize}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{The {\tt compatible} property}
+ \begin{itemize}
+ \item Is a list of strings
+ \begin{itemize}
+ \item From the most specific to the least specific
+ \end{itemize}
+ \item Describes the specific {\bf binding} to which the node complies.
+ \item It uniquely identifies the {\bf programming model} of the
+ device.
+ \item Practically speaking, it is used by the operating system to
+ find the {\bf appropriate driver} for this device.
+ \item When describing real hardware, the typical form is
+ \code{vendor,model}
+ \item Examples:
+ \begin{itemize}
+ \item \code{compatible = "arm,armv7-timer";}
+ \item \code{compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";}
+ \item \code{compatible = "regulator-fixed";}
+ \item \code{compatible = "gpio-keys";}
+ \end{itemize}
+ \item Special value: \code{simple-bus} $\rightarrow$ bus where all
+ sub-nodes are memory-mapped devices
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{{\tt compatible} property and Linux kernel drivers}
+ \begin{columns}
+ \column{0.6\textwidth}
+ \begin{itemize}
+ \item Linux identifies as {\bf platform devices}:
+ \begin{itemize}
+ \item Top-level DT nodes with a \code{compatible} string
+ \item Sub-nodes of \code{simple-bus}
+ \begin{itemize}
+ \item Instantiated automatically at boot time
+ \end{itemize}
+ \end{itemize}
+ \item Sub-nodes of I2C controllers $\rightarrow$ {\em I2C devices}
+ \item Sub-nodes of SPI controllers $\rightarrow$ {\em SPI devices}
+ \item Each Linux driver has a table of compatible strings it supports
+ \begin{itemize}
+ \item \kstruct{of_device_id}\code{[]}
+ \end{itemize}
+ \item When a DT node compatible string matches a given driver, the
+ device is {\em bound} to that driver.
+ \end{itemize}
+ \column{0.4\textwidth}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/dt-to-devices.pdf}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Matching with drivers in Linux: platform driver}
+ \begin{block}{\kfile{drivers/tty/serial/fsl_lpuart.c}}
+ {\tiny
+\begin{minted}{c}
+static const struct of_device_id lpuart_dt_ids[] = {
+ { .compatible = "fsl,vf610-lpuart", .data = &vf_data, },
+ { .compatible = "fsl,ls1021a-lpuart", .data = &ls1021a_data, },
+ { .compatible = "fsl,ls1028a-lpuart", .data = &ls1028a_data, },
+ { .compatible = "fsl,imx7ulp-lpuart", .data = &imx7ulp_data, },
+ { .compatible = "fsl,imx8ulp-lpuart", .data = &imx8ulp_data, },
+ { .compatible = "fsl,imx8qxp-lpuart", .data = &imx8qxp_data, },
+ { .compatible = "fsl,imxrt1050-lpuart", .data = &imxrt1050_data},
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
+
+...
+
+static struct platform_driver lpuart_driver = {
+ .probe = lpuart_probe,
+ .remove_new = lpuart_remove,
+ .driver = {
+ .name = "fsl-lpuart",
+ .of_match_table = lpuart_dt_ids,
+ .pm = pm_ptr(&lpuart_pm_ops),
+ },
+};
+\end{minted}
+ }
+ \end{block}
+\end{frame}
+
+\begin{frame}[fragile]{Matching with drivers in Linux: I2C driver}
+ \begin{block}{\kfile{sound/soc/codecs/cs42l51.c}}
+ {\tiny
+\begin{minted}{c}
+const struct of_device_id cs42l51_of_match[] = {
+ { .compatible = "cirrus,cs42l51", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cs42l51_of_match);
+\end{minted}
+ }
+ \end{block}
+ \begin{block}{\kfile{sound/soc/codecs/cs42l51-i2c.c}}
+ {\tiny
+\begin{minted}{c}
+static struct i2c_driver cs42l51_i2c_driver = {
+ .driver = {
+ .name = "cs42l51",
+ .of_match_table = cs42l51_of_match,
+ .pm = &cs42l51_pm_ops,
+ },
+ .probe = cs42l51_i2c_probe,
+ .remove = cs42l51_i2c_remove,
+ .id_table = cs42l51_i2c_id,
+};
+\end{minted}
+ }
+ \end{block}
+\end{frame}
+
+\begin{frame}[fragile]{{\tt reg} property}
+ \begin{itemize}
+ \item Most important property after \code{compatible}
+ \item {\bf Memory-mapped} devices: base physical address and size of
+ the memory-mapped registers. Can have several entries for multiple
+ register areas.
+\begin{onlyenv}<1>
+\begin{block}{}
+\begin{verbatim}
+sai4: sai@50027000 {
+ reg = <0x50027000 0x4>, <0x500273f0 0x10>;
+};
+\end{verbatim}
+\end{block}
+\end{onlyenv}
+\pause
+ \item {\bf I2C} devices: address of the device on the I2C bus.
+\begin{onlyenv}<2>
+\begin{block}{}
+\begin{verbatim}
+&i2c1 {
+ hdmi-transmitter@39 {
+ reg = <0x39>;
+ };
+ cs42l51: cs42l51@4a {
+ reg = <0x4a>;
+ };
+};
+\end{verbatim}
+\end{block}
+\end{onlyenv}
+\pause
+ \item {\bf SPI} devices: chip select number
+\begin{onlyenv}<3>
+\begin{block}{}
+\begin{verbatim}
+&qspi {
+ flash0: mx66l51235l@0 {
+ reg = <0>;
+ };
+ flash1: mx66l51235l@1 {
+ reg = <1>;
+ };
+};
+\end{verbatim}
+\end{block}
+\end{onlyenv}
+\pause
+\item The unit address must be the address of the first \code{reg}
+ entry.
+\begin{onlyenv}<4>
+\begin{block}{}
+\begin{verbatim}
+sai4: sai@50027000 {
+ reg = <0x50027000 0x4>, <0x500273f0 0x10>;
+};
+\end{verbatim}
+\end{block}
+\end{onlyenv}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{Status property}
+ \begin{itemize}
+ \item The \code{status} property indicates if the device is really in
+ use or not
+ \begin{itemize}
+ \item \code{okay} or \code{ok} $\rightarrow$ the device is really
+ in use
+ \item any other value, by convention \code{disabled} $\rightarrow$
+ the device is not in use
+ \end{itemize}
+ \item In Linux, controls if a device is instantiated
+ \item In \code{.dtsi} files describing SoCs: all devices that
+ interface to the outside world have \code{status = "disabled";}
+ \item Enabled on a per-device basis in the board \code{.dts}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{Resources: interrupts, clocks, DMA, reset lines, ...}
+ \begin{columns}
+ \column{0.5\textwidth}
+ \begin{itemize}
+ \item Common pattern for resources shared by multiple hardware
+ blocks
+ \begin{itemize}
+ \item Interrupt lines
+ \item Clock controllers
+ \item DMA controllers
+ \item Reset controllers
+ \item ...
+ \end{itemize}
+ \item A Device Tree node describing the {\em controller} as a device
+ \item References from other nodes that use resources provided by
+ this {\em controller}
+ \end{itemize}
+ \column{0.5\textwidth}
+\begin{block}{}
+{\fontsize{4}{5}\selectfont
+\begin{minted}{perl}
+gic: interrupt-controller@48000000 {
+ compatible = "arm,gic-v3";
+ reg = <0 0x48000000 0 0x10000>,
+ <0 0x48040000 0 0xc0000>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ interrupts = ;
+ interrupt-parent = <&gic>;
+};
+
+clk: clock-controller@44450000 {
+ compatible = "fsl,imx93-ccm";
+ reg = <0x44450000 0x10000>;
+ #clock-cells = <1>;
+ clocks = <&osc_32k>, <&osc_24m>, <&clk_ext1>;
+ clock-names = "osc_32k", "osc_24m", "clk_ext1";
+};
+
+edma1: dma-controller@44000000 {
+ compatible = "fsl,imx93-edma3";
+ reg = <0x44000000 0x200000>;
+ #dma-cells = <3>;
+ dma-channels = <31>;
+ interrupts = , ;
+ clocks = <&clk IMX93_CLK_EDMA1_GATE>;
+ clock-names = "dma";
+};
+
+lpuart1: serial@44380000 {
+ compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
+ reg = <0x44380000 0x1000>;
+ interrupts = ;
+ clocks = <&clk IMX93_CLK_LPUART1_GATE>;
+ clock-names = "ipg";
+ dmas = <&edma1 17 0 FSL_EDMA_RX>, <&edma1 16 0 0>;
+ dma-names = "rx", "tx";
+};
+\end{minted}
+}
+\end{block}
+\end{columns}
+\end{frame}
+
+\begin{frame}{Pin-muxing description}
+ \begin{columns}
+ \column{0.5\textwidth}
+ \begin{itemize}
+ \item Most modern SoCs, including the IMX93, have more features
+ than they have pins to expose those features to the outside world.
+ \item Pins are muxed: a given pin can be used for one function
+ {\bf or} another
+ \item A specific IP block in the SoC controls the muxing of pins:
+ the {\bf pinmux controller}
+ \item The Device Tree describes which pin configurations are
+ possible, and which configurations are used by the different
+ devices.
+ \end{itemize}
+ \column{0.5\textwidth}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/pin-muxing-principle.pdf}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Pin-muxing controllers on IMX93}
+ \begin{block}{\kfileversion{arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts}{6.1}}
+{\tiny
+\begin{minted}{perl}
+iomuxc: pinctrl@443c0000 {
+ compatible = "fsl,imx93-iomuxc";
+ reg = <0x443c0000 0x10000>;
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX93_PAD_UART1_RXD__LPUART1_RX 0x31e
+ MX93_PAD_UART1_TXD__LPUART1_TX 0x31e
+ >;
+ };
+ pinctrl_lpi2c1: lpi2c1grp {
+ fsl,pins = <
+ MX93_PAD_I2C1_SCL__LPI2C1_SCL 0x40000b9e
+ MX93_PAD_I2C1_SDA__LPI2C1_SDA 0x40000b9e
+ >;
+ };
+};
+
+lpuart1: serial@44380000 {
+ compatible = "fsl,imx93-lpuart", "fsl,imx8ulp-lpuart", "fsl,imx7ulp-lpuart";
+ reg = <0x44380000 0x1000>;
+ interrupts = ;
+ clocks = <&clk IMX93_CLK_LPUART1_GATE>;
+ clock-names = "ipg";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+\end{minted}
+}
+ \end{block}
+\end{frame}
+
+\begin{frame}[fragile]{Pin-muxing configuration}
+\begin{onlyenv}<1>
+ \begin{block}{\kfile{arch/arm64/boot/dts/freescale/imx93-11x11-frdm.dts}}
+{\tiny
+\begin{minted}{perl}
+&iomuxc {
+ pinctrl_lpi2c1: lpi2c1grp {
+ fsl,pins = <
+ MX93_PAD_I2C1_SCL__LPI2C1_SCL 0x40000b9e
+ MX93_PAD_I2C1_SDA__LPI2C1_SDA 0x40000b9e
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX93_PAD_UART1_RXD__LPUART1_RX 0x31e
+ MX93_PAD_UART1_TXD__LPUART1_TX 0x31e
+ >;
+ };
+
+ pinctrl_fec: fecgrp {
+ fsl,pins = <
+ MX93_PAD_ENET2_MDC__ENET1_MDC 0x57e
+ MX93_PAD_ENET2_MDIO__ENET1_MDIO 0x57e
+ MX93_PAD_ENET2_RD0__ENET1_RGMII_RD0 0x57e
+ ...
+ >;
+ };
+};
+\end{minted}
+}
+\end{block}
+\end{onlyenv}
+\end{frame}
+
+\begin{frame}[fragile]{Pin-muxing consumer}
+ \begin{block}{}
+{\tiny
+\begin{minted}{perl}
+&i2c1 {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c1_pins_a>;
+ pinctrl-1 = <&i2c1_sleep_pins_a>;
+ ...
+};
+\end{minted}
+}
+\end{block}
+\begin{itemize}
+\item Typically board-specific, in \code{.dts}
+\item \code{pinctrl-0}, \code{pinctrl-1}, \code{pinctrl-X} provides
+ the pin mux configurations for the different {\bf states}
+\item \code{pinctrl-names} gives a name to each state, mandatory even
+ if only one state
+\item States are mutually exclusive
+\item The driver is responsible for switching between states
+\item \code{default} state is automatically set up when the device is
+ {\em probed}
+\end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{Example: LED and I2C device}
+ \begin{itemize}
+ \item Let's see how to describe an LED and an I2C device connected
+ to the DK1 platform.
+ \item Create \code{arch/arm64/boot/dts/freescale/imx93-11x11-frdm-custom.dts}
+ which includes \code{imx93-11x11-frdm.dts}
+ \begin{block}{}
+{\tiny
+\begin{verbatim}
+#include "imx93-11x11-frdm.dts"
+\end{verbatim}
+}
+ \end{block}
+ \item Make sure \code{imx93-11x11-frdm.dts} gets compiled to a
+ DTB by changing \kfile{arch/arm64/boot/dts/freescale/Makefile}
+ \begin{block}{}
+ {\tiny
+\begin{verbatim}
+dtb-$(CONFIG_ARCH_MXC) += imx93-11x11-frdm-custom.dtb
+\end{verbatim}
+ }
+ \end{block}
+ \item \code{make dtbs}
+ \begin{block}{}
+ {\tiny
+\begin{verbatim}
+ DTC arch/arm64/boot/dts/freescale/imx93-11x11-frdm-custom.dtb
+\end{verbatim}
+ }
+ \end{block}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{Example: describe an LED}
+ \begin{columns}
+ \column{0.5\textwidth}
+ \begin{block}{imx93-11x11-frdm-custom.dts}
+ {\tiny
+\begin{minted}{perl}
+#include "imx93-11x11-frdm.dts"
+
+/ {
+ leds {
+ compatible = "gpio-leds";
+ webinar {
+ label = "webinar";
+ gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+\end{minted}
+ }
+ \end{block}
+ \begin{block}{shell}
+{\tiny
+\begin{verbatim}
+# echo 255 > /sys/class/leds/webinar/brightness
+\end{verbatim}
+}
+\end{block}
+ \column{0.5\textwidth}
+ \begin{center}
+ \includegraphics[height=0.3\textheight]{slides/sysdev-hw-devices/imx93-frdm/imx93-tab-gpio21.png}\\
+ \vspace{0.5cm}
+ \includegraphics[height=0.3\textheight]{slides/sysdev-hw-devices/imx93-frdm/led-on.jpg}
+ \end{center}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Example: connect I2C temperature, humidity and pressure sensor}
+ \begin{columns}
+ \column{0.5\textwidth}
+ \begin{block}{imx93-11x11-frdm-custom.dts}
+ {\tiny
+\begin{minted}{perl}
+
+&lpi2c4 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-frequency = <400000>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&pinctrl_lpi2c4>;
+ pinctrl-1 = <&pinctrl_lpi2c4>;
+ status = "okay";
+
+ pressure@76 {
+ compatible = "bosch,bme280";
+ reg = <0x76>;
+ };
+};
+
+\end{minted}
+}
+ \end{block}
+
+\begin{block}{shell}
+{\tiny
+\begin{verbatim}
+# cat /sys/bus/iio/devices/iio\:device2/in_humidityrelative_input
+49147
+# cat /sys/bus/iio/devices/iio\:device2/in_pressure_input
+101.567167968
+# cat /sys/bus/iio/devices/iio\:device2/in_temp_input
+24380
+\end{verbatim}
+}
+\end{block}
+ \column{0.5\textwidth}
+ \begin{center}
+ \includegraphics[width=0.4\textwidth]{slides/sysdev-hw-devices/bme.jpg}
+ \end{center}
+\end{columns}
+\end{frame}
+
+\begin{frame}{Further details about the Device Tree}
+\small
+Check out our {\em Device Tree 101 webinar}, by Thomas Petazzoni (2021)
+\begin{itemize}
+ \item Slides: \url{https://bootlin.com/blog/device-tree-101-webinar-slides-and-videos/}\\
+ \item Video: \url{https://youtu.be/a9CZ1Uk3OYQ}
+\end{itemize}
+\vspace{0.5cm}
+\includegraphics[height=0.5\textheight]{common/device-tree-video.jpg}
+\end{frame}
+
+\subsection{Discoverable hardware: USB and PCI}
+
+\begin{frame}{Discoverable hardware}
+ \begin{itemize}
+ \item Some busses have built-in hardware discoverability mechanisms
+ \item Most common busses: USB and PCI
+ \item Hardware devices can be enumerated, and their characteristics
+ retrieved with just a driver or the bus controller
+ \item Useful Linux commands
+ \begin{itemize}
+ \item \code{lsusb}, lists all USB devices detected
+ \item \code{lspci}, lists all PCI devices detected
+ \item A detected device does not mean it has a kernel driver
+ associated to it!
+ \end{itemize}
+ \item Association with kernel drivers done based on product
+ ID/vendor ID, or some other characteristics of the device: device
+ class, device sub-class, etc.
+ \end{itemize}
+\end{frame}
+
+\setuplabframe
+{Accessing hardware devices}
+{
+ Time to start the practical lab!
+ \begin{itemize}
+ \item Exploring the contents of \code{/dev} and \code{/sys} and the
+ devices available on the embedded hardware platform.
+ \item Using GPIOs and LEDs.
+ \item Modifying the Device Tree to control pin multiplexing and
+ declare an I2C-connected joystick.
+ \item Adding support for a USB audio card using Linux kernel modules
+ \item Adding support for the I2C-connected joystick through
+ an out-of-tree module.
+ \end{itemize}
+}
diff --git a/slides/sysdev-hw-devices/cn13-pinout.png b/slides/sysdev-hw-devices/stm32mp1/cn13-pinout.png
similarity index 100%
rename from slides/sysdev-hw-devices/cn13-pinout.png
rename to slides/sysdev-hw-devices/stm32mp1/cn13-pinout.png
diff --git a/slides/sysdev-hw-devices/cn14-pinout.png b/slides/sysdev-hw-devices/stm32mp1/cn14-pinout.png
similarity index 100%
rename from slides/sysdev-hw-devices/cn14-pinout.png
rename to slides/sysdev-hw-devices/stm32mp1/cn14-pinout.png
diff --git a/slides/sysdev-hw-devices/dt-inheritance-stm32.dia b/slides/sysdev-hw-devices/stm32mp1/dt-inheritance-stm32.dia
similarity index 100%
rename from slides/sysdev-hw-devices/dt-inheritance-stm32.dia
rename to slides/sysdev-hw-devices/stm32mp1/dt-inheritance-stm32.dia
diff --git a/slides/sysdev-hw-devices/dt-inheritance.dia b/slides/sysdev-hw-devices/stm32mp1/dt-inheritance.dia
similarity index 100%
rename from slides/sysdev-hw-devices/dt-inheritance.dia
rename to slides/sysdev-hw-devices/stm32mp1/dt-inheritance.dia
diff --git a/slides/sysdev-hw-devices/led-on.jpg b/slides/sysdev-hw-devices/stm32mp1/led-on.jpg
similarity index 100%
rename from slides/sysdev-hw-devices/led-on.jpg
rename to slides/sysdev-hw-devices/stm32mp1/led-on.jpg
diff --git a/slides/sysdev-hw-devices/stm32mp157-i2c-pin-mux.png b/slides/sysdev-hw-devices/stm32mp1/stm32mp157-i2c-pin-mux.png
similarity index 100%
rename from slides/sysdev-hw-devices/stm32mp157-i2c-pin-mux.png
rename to slides/sysdev-hw-devices/stm32mp1/stm32mp157-i2c-pin-mux.png
diff --git a/slides/sysdev-hw-devices/stm32mp1/sysdev-hw-devices-stm32mp1.tex b/slides/sysdev-hw-devices/stm32mp1/sysdev-hw-devices-stm32mp1.tex
new file mode 100644
index 0000000000..f16a2eb916
--- /dev/null
+++ b/slides/sysdev-hw-devices/stm32mp1/sysdev-hw-devices-stm32mp1.tex
@@ -0,0 +1,1041 @@
+\begin{frame}[fragile]{DT overall structure: simplified example}
+ \begin{columns}
+ \column{0.6\textwidth}
+ \begin{onlyenv}<1>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";
+ compatible = "st,stm32mp157c-dk2", "st,stm32mp157";
+
+ cpus { ... };
+ memory@0 { ... };
+ chosen { ... };
+ intc: interrupt-controller@a0021000 { ... };
+ soc {
+ i2c1: i2c@40012000 { ... };
+ ethernet0: ethernet@5800a000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<2>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a7";
+ clock-frequency = <650000000>;
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a7";
+ clock-frequency = <650000000>;
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ memory@0 { ... };
+ chosen { ... };
+ intc: interrupt-controller@a0021000 { ... };
+ soc {
+ i2c1: i2c@40012000 { ... };
+ ethernet0: ethernet@5800a000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<3>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ cpus { ... };
+ memory@0 {
+ device_type = "memory";
+ reg = <0x0 0x20000000>;
+ };
+
+ chosen {
+ bootargs = "";
+ stdout-path = "serial0:115200n8";
+ };
+ intc: interrupt-controller@a0021000 { ... };
+ soc {
+ i2c1: i2c@40012000 { ... };
+ ethernet0: ethernet@5800a000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<4>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ cpus { ... };
+ memory@0 { ... };
+ chosen { ... };
+
+ intc: interrupt-controller@a0021000 {
+ compatible = "arm,cortex-a7-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0xa0021000 0x1000>,
+ <0xa0022000 0x2000>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&intc>;
+
+ i2c1: i2c@40012000 { ... };
+ ethernet0: ethernet@5800a000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<5>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ cpus { ... };
+ memory@0 { ... };
+ chosen { ... };
+ intc: interrupt-controller@a0021000 { ... };
+ soc {
+ i2c1: i2c@40012000 {
+ compatible = "st,stm32mp15-i2c";
+ reg = <0x40012000 0x400>;
+ interrupts = ,
+ ;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ cs42l51: cs42l51@4a {
+ compatible = "cirrus,cs42l51";
+ reg = <0x4a>;
+ reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>;
+ status = "okay";
+ };
+ };
+ ethernet0: ethernet@5800a000 { ... };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \begin{onlyenv}<6>
+ \begin{block}{}
+\begin{minted}[fontsize=\tiny]{perl}
+/ {
+ cpus { ... };
+ memory@0 { ... };
+ chosen { ... };
+ intc: interrupt-controller@a0021000 { ... };
+ soc {
+ compatible = "simple-bus";
+ ...
+ interrupt-parent = <&intc>;
+ i2c1: i2c@40012000 { ... };
+
+ ethernet0: ethernet@5800a000 {
+ compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";
+ reg = <0x5800a000 0x2000>;
+ interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+ status = "okay";
+
+ mdio0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dwmac-mdio";
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+ };
+ };
+};
+\end{minted}
+ \end{block}
+ \end{onlyenv}
+ \column{0.4\textwidth}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/simple-hardware.pdf}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Device Tree inheritance}
+ \begin{itemize}
+ \item Device Tree files are not monolithic, they can be split in
+ several files, including each other.
+ \item \code{.dtsi} files are included files, while \code{.dts} files
+ are {\em final} Device Trees
+ \begin{itemize}
+ \item Only \code{.dts} files are accepted as input to \code{dtc}
+ \end{itemize}
+ \item Typically, \code{.dtsi} will contain
+ \begin{itemize}
+ \item definitions of SoC-level information
+ \item definitions common to several boards
+ \end{itemize}
+ \item The \code{.dts} file contains the board-level information
+ \item The inclusion works by {\bf overlaying} the tree of the
+ including file over the tree of the included file,
+ according to the order of the \code{#include} directives.
+ \item Allows an including file to {\bf override} values specified by
+ an included file
+ \item Uses the C pre-processor \code{#include} directive
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{Device Tree inheritance example}
+ \begin{center}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/stm32mp1/dt-inheritance.pdf}
+ \end{center}
+\end{frame}
+
+\begin{frame}[fragile]{Inheritance and labels}
+
+ \begin{columns}[t]
+ \column{0.5\textwidth}
+ Doing:
+ \begin{block}{soc.dtsi}
+ {\tiny
+\begin{minted}{perl}
+/ {
+ soc {
+ usart1: serial@5c000000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x5c000000 0x400>;
+ status = "disabled";
+ };
+ };
+};
+\end{minted}
+ }
+ \end{block}
+
+ \begin{block}{board.dts}
+ {\tiny
+\begin{minted}{perl}
+#include "soc.dtsi"
+
+/ {
+ soc {
+ serial@5c000000 {
+ status = "okay";
+ };
+ };
+};
+\end{minted}
+ }
+ \end{block}
+
+ \column{0.5\textwidth}
+ \begin{onlyenv}<2>
+ Is exactly equivalent to:
+
+ \begin{block}{soc.dtsi}
+ {\tiny
+\begin{minted}{perl}
+/ {
+ soc {
+ usart1: serial@5c000000 {
+ compatible = "st,stm32h7-uart";
+ reg = <0x5c000000 0x400>;
+ status = "disabled";
+ };
+ };
+};
+\end{minted}
+ }
+ \end{block}
+
+ \begin{block}{board.dts}
+ {\tiny
+\begin{minted}{perl}
+#include "soc.dtsi"
+
+&usart1 {
+ status = "okay";
+};
+\end{minted}
+ }
+ \end{block}
+
+ $\rightarrow$ this solution is now often preferred
+ \end{onlyenv}
+ \end{columns}
+
+\end{frame}
+
+\begin{frame}{DT inheritance in STM32MP1 support}
+ \begin{center}
+ \includegraphics[height=0.8\textheight]{slides/sysdev-hw-devices/stm32mp1/dt-inheritance-stm32.pdf}
+ \end{center}
+\end{frame}
+
+\begin{frame}{Device Tree design principles}
+ \begin{itemize}
+ \item {\bf Describe hardware} (how the hardware is), not
+ configuration (how I choose to use the hardware)
+ \item {\bf OS-agnostic}
+ \begin{itemize}
+ \item For a given piece of HW, Device Tree should be the same for
+ U-Boot, FreeBSD or Linux
+ \item There should be no need to change the Device Tree when updating the OS
+ \end{itemize}
+ \item Describe {\bf integration of hardware components}, not the internals
+ of hardware components
+ \begin{itemize}
+ \item The details of how a specific device/IP block is working is
+ handled by code in device drivers
+ \item The Device Tree describes how the device/IP block is
+ connected/integrated with the rest of the system: IRQ lines, DMA
+ channels, clocks, reset lines, etc.
+ \end{itemize}
+ \item Like all beautiful design principles, these principles are
+ sometimes violated.
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{Device Tree specifications}
+ \begin{columns}
+ \column{0.7\textwidth}
+ \begin{itemize}
+ \item How to write the correct nodes/properties to describe a
+ given hardware platform~?
+ \item {\bf Device Tree Specifications} $\rightarrow$ base Device
+ Tree syntax + number of standard properties.
+ \begin{itemize}
+ \item \url{https://www.devicetree.org/specifications/}
+ \item Not sufficient to describe the wide variety of hardware.
+ \end{itemize}
+ \item {\bf Device Tree Bindings} $\rightarrow$ documents that each
+ specify how a piece of HW should be described
+ \begin{itemize}
+ \item \kdir{Documentation/devicetree/bindings} in Linux kernel sources
+ \item Reviewed by DT bindings maintainer team
+ \item Legacy: human readable documents
+ \item New norm: YAML-written specifications
+ \end{itemize}
+ \end{itemize}
+ \column{0.3\textwidth}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/dt-spec.png}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Device Tree binding: old style}
+ \begin{center}
+ \kfile{Documentation/devicetree/bindings/mtd/spear_smi.txt}\\
+ This IP is {\em not} used on STM32MP1.
+ \end{center}
+ \begin{columns}[t]
+ \column{0.5\textwidth}
+ \begin{block}{}
+ {\fontsize{5}{6}\selectfont
+\begin{verbatim}
+* SPEAr SMI
+
+Required properties:
+- compatible : "st,spear600-smi"
+- reg : Address range of the mtd chip
+- #address-cells, #size-cells : Must be present if the device has sub-nodes
+ representing partitions.
+- interrupts: Should contain the STMMAC interrupts
+- clock-rate : Functional clock rate of SMI in Hz
+
+Optional properties:
+- st,smi-fast-mode : Flash supports read in fast mode
+
+\end{verbatim}
+ }
+ \end{block}
+ \column{0.5\textwidth}
+ \begin{block}{}
+ {\fontsize{4}{5}\selectfont
+\begin{verbatim}
+Example:
+
+ smi: flash@fc000000 {
+ compatible = "st,spear600-smi";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ reg = <0xfc000000 0x1000>;
+ interrupt-parent = <&vic1>;
+ interrupts = <12>;
+ clock-rate = <50000000>; /* 50MHz */
+
+ flash@f8000000 {
+ st,smi-fast-mode;
+ ...
+ };
+ };
+\end{verbatim}
+ }
+ \end{block}
+ \end{columns}
+
+\end{frame}
+
+\begin{frame}[fragile]{Device Tree binding: YAML style}
+ \kfile{Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml}
+ \begin{columns}[t]
+ \column{0.5\textwidth}
+ \begin{block}{}
+ {\fontsize{5}{6}\selectfont
+\begin{minted}{yaml}
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/i2c/st,stm32-i2c.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: I2C controller embedded in STMicroelectronics STM32 I2C platform
+
+maintainers:
+ - Pierre-Yves MORDRET
+
+properties:
+ compatible:
+ enum:
+ - st,stm32f4-i2c
+ - st,stm32f7-i2c
+ - st,stm32mp15-i2c
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ items:
+ - description: interrupt ID for I2C event
+ - description: interrupt ID for I2C error
+
+ resets:
+ maxItems: 1
+
+\end{minted}
+ }
+ \end{block}
+ \column{0.5\textwidth}
+ \begin{block}{}
+ {\fontsize{5}{6}\selectfont
+\begin{minted}{yaml}
+ clocks:
+ maxItems: 1
+
+ dmas:
+ items:
+ - description: RX DMA Channel phandle
+ - description: TX DMA Channel phandle
+
+ ...
+
+ clock-frequency:
+ description: Desired I2C bus clock frequency in Hz. If not specified,
+ the default 100 kHz frequency will be used.
+ For STM32F7, STM32H7 and STM32MP1 SoCs, if timing
+ parameters match, the bus clock frequency can be from
+ 1Hz to 1MHz.
+ default: 100000
+ minimum: 1
+ maximum: 1000000
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - resets
+ - clocks
+\end{minted}
+ }
+ \end{block}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Device Tree binding: YAML style example}
+ \begin{block}{}
+ {\fontsize{5}{6}\selectfont
+\begin{minted}{yaml}
+examples:
+ - |
+ //Example 3 (with st,stm32mp15-i2c compatible on stm32mp)
+ #include
+ #include
+ #include
+ i2c@40013000 {
+ compatible = "st,stm32mp15-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x40013000 0x400>;
+ interrupts = ,
+ ;
+ clocks = <&rcc I2C2_K>;
+ resets = <&rcc I2C2_R>;
+ i2c-scl-rising-time-ns = <185>;
+ i2c-scl-falling-time-ns = <20>;
+ st,syscfg-fmp = <&syscfg 0x4 0x2>;
+ };
+\end{minted}
+ }
+ \end{block}
+\end{frame}
+
+\begin{frame}{Validating Device Tree in Linux}
+ \begin{itemize}
+ \item \code{dtc} only does syntactic validation
+ \item YAML bindings allow to do semantic validation
+ \item Linux kernel \code{make} rules:
+ \begin{itemize}
+ \item \code{make dt_binding_check}\\
+ verify that YAML bindings are valid
+ \item \code{make dtbs_check}\\
+ validate DTs currently enabled against YAML bindings
+ \item \code{make DT_SCHEMA_FILES=Documentation/devicetree/bindings/trivial-devices.yaml dtbs_check}\\
+ validate DTs against a specific YAML binding
+ \end{itemize}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{The {\tt compatible} property}
+ \begin{itemize}
+ \item Is a list of strings
+ \begin{itemize}
+ \item From the most specific to the least specific
+ \end{itemize}
+ \item Describes the specific {\bf binding} to which the node complies.
+ \item It uniquely identifies the {\bf programming model} of the
+ device.
+ \item Practically speaking, it is used by the operating system to
+ find the {\bf appropriate driver} for this device.
+ \item When describing real hardware, the typical form is
+ \code{vendor,model}
+ \item Examples:
+ \begin{itemize}
+ \item \code{compatible = "arm,armv7-timer";}
+ \item \code{compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";}
+ \item \code{compatible = "regulator-fixed";}
+ \item \code{compatible = "gpio-keys";}
+ \end{itemize}
+ \item Special value: \code{simple-bus} $\rightarrow$ bus where all
+ sub-nodes are memory-mapped devices
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{{\tt compatible} property and Linux kernel drivers}
+ \begin{columns}
+ \column{0.6\textwidth}
+ \begin{itemize}
+ \item Linux identifies as {\bf platform devices}:
+ \begin{itemize}
+ \item Top-level DT nodes with a \code{compatible} string
+ \item Sub-nodes of \code{simple-bus}
+ \begin{itemize}
+ \item Instantiated automatically at boot time
+ \end{itemize}
+ \end{itemize}
+ \item Sub-nodes of I2C controllers $\rightarrow$ {\em I2C devices}
+ \item Sub-nodes of SPI controllers $\rightarrow$ {\em SPI devices}
+ \item Each Linux driver has a table of compatible strings it supports
+ \begin{itemize}
+ \item \kstruct{of_device_id}\code{[]}
+ \end{itemize}
+ \item When a DT node compatible string matches a given driver, the
+ device is {\em bound} to that driver.
+ \end{itemize}
+ \column{0.4\textwidth}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/dt-to-devices.pdf}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Matching with drivers in Linux: platform driver}
+ \begin{block}{\kfile{drivers/tty/serial/stm32-usart.c}}
+ {\tiny
+\begin{minted}{c}
+static const struct of_device_id stm32_match[] = {
+ { .compatible = "st,stm32-uart", .data = &stm32f4_info},
+ { .compatible = "st,stm32f7-uart", .data = &stm32f7_info},
+ { .compatible = "st,stm32h7-uart", .data = &stm32h7_info},
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm32_match);
+
+...
+
+static struct platform_driver stm32_serial_driver = {
+ .probe = stm32_serial_probe,
+ .remove = stm32_serial_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = &stm32_serial_pm_ops,
+ .of_match_table = of_match_ptr(stm32_match),
+ },
+};
+\end{minted}
+ }
+ \end{block}
+\end{frame}
+
+\begin{frame}[fragile]{Matching with drivers in Linux: I2C driver}
+ \begin{block}{\kfile{sound/soc/codecs/cs42l51.c}}
+ {\tiny
+\begin{minted}{c}
+const struct of_device_id cs42l51_of_match[] = {
+ { .compatible = "cirrus,cs42l51", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cs42l51_of_match);
+\end{minted}
+ }
+ \end{block}
+ \begin{block}{\kfile{sound/soc/codecs/cs42l51-i2c.c}}
+ {\tiny
+\begin{minted}{c}
+static struct i2c_driver cs42l51_i2c_driver = {
+ .driver = {
+ .name = "cs42l51",
+ .of_match_table = cs42l51_of_match,
+ .pm = &cs42l51_pm_ops,
+ },
+ .probe = cs42l51_i2c_probe,
+ .remove = cs42l51_i2c_remove,
+ .id_table = cs42l51_i2c_id,
+};
+\end{minted}
+ }
+ \end{block}
+\end{frame}
+
+\begin{frame}[fragile]{{\tt reg} property}
+ \begin{itemize}
+ \item Most important property after \code{compatible}
+ \item {\bf Memory-mapped} devices: base physical address and size of
+ the memory-mapped registers. Can have several entries for multiple
+ register areas.
+\begin{onlyenv}<1>
+\begin{block}{}
+\begin{verbatim}
+sai4: sai@50027000 {
+ reg = <0x50027000 0x4>, <0x500273f0 0x10>;
+};
+\end{verbatim}
+\end{block}
+\end{onlyenv}
+\pause
+ \item {\bf I2C} devices: address of the device on the I2C bus.
+\begin{onlyenv}<2>
+\begin{block}{}
+\begin{verbatim}
+&i2c1 {
+ hdmi-transmitter@39 {
+ reg = <0x39>;
+ };
+ cs42l51: cs42l51@4a {
+ reg = <0x4a>;
+ };
+};
+\end{verbatim}
+\end{block}
+\end{onlyenv}
+\pause
+ \item {\bf SPI} devices: chip select number
+\begin{onlyenv}<3>
+\begin{block}{}
+\begin{verbatim}
+&qspi {
+ flash0: mx66l51235l@0 {
+ reg = <0>;
+ };
+ flash1: mx66l51235l@1 {
+ reg = <1>;
+ };
+};
+\end{verbatim}
+\end{block}
+\end{onlyenv}
+\pause
+\item The unit address must be the address of the first \code{reg}
+ entry.
+\begin{onlyenv}<4>
+\begin{block}{}
+\begin{verbatim}
+sai4: sai@50027000 {
+ reg = <0x50027000 0x4>, <0x500273f0 0x10>;
+};
+\end{verbatim}
+\end{block}
+\end{onlyenv}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}{Status property}
+ \begin{itemize}
+ \item The \code{status} property indicates if the device is really in
+ use or not
+ \begin{itemize}
+ \item \code{okay} or \code{ok} $\rightarrow$ the device is really
+ in use
+ \item any other value, by convention \code{disabled} $\rightarrow$
+ the device is not in use
+ \end{itemize}
+ \item In Linux, controls if a device is instantiated
+ \item In \code{.dtsi} files describing SoCs: all devices that
+ interface to the outside world have \code{status = "disabled";}
+ \item Enabled on a per-device basis in the board \code{.dts}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{Resources: interrupts, clocks, DMA, reset lines, ...}
+ \begin{columns}
+ \column{0.5\textwidth}
+ \begin{itemize}
+ \item Common pattern for resources shared by multiple hardware
+ blocks
+ \begin{itemize}
+ \item Interrupt lines
+ \item Clock controllers
+ \item DMA controllers
+ \item Reset controllers
+ \item ...
+ \end{itemize}
+ \item A Device Tree node describing the {\em controller} as a device
+ \item References from other nodes that use resources provided by
+ this {\em controller}
+ \end{itemize}
+ \column{0.5\textwidth}
+\begin{block}{}
+{\tiny
+\begin{minted}{perl}
+intc: interrupt-controller@a0021000 {
+ compatible = "arm,cortex-a7-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0xa0021000 0x1000>, <0xa0022000 0x2000>;
+};
+
+rcc: rcc@50000000 {
+ compatible = "st,stm32mp1-rcc", "syscon";
+ reg = <0x50000000 0x1000>;
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+};
+
+dmamux1: dma-router@48002000 {
+ compatible = "st,stm32h7-dmamux";
+ reg = <0x48002000 0x1c>;
+ #dma-cells = <3>;
+ clocks = <&rcc DMAMUX>;
+ resets = <&rcc DMAMUX_R>;
+};
+
+spi3: spi@4000c000 {
+ interrupts = ;
+ clocks = <&rcc SPI3_K>;
+ resets = <&rcc SPI3_R>;
+ dmas = <&dmamux1 61 0x400 0x05>, <&dmamux1 62 0x400 0x05>;
+};
+\end{minted}
+}
+\end{block}
+\end{columns}
+\end{frame}
+
+\begin{frame}{Pin-muxing description}
+ \begin{columns}
+ \column{0.5\textwidth}
+ \begin{itemize}
+ \item Most modern SoCs, including the STM32MP1, have more features
+ than they have pins to expose those features to the outside world.
+ \item Pins are muxed: a given pin can be used for one function
+ {\bf or} another
+ \item A specific IP block in the SoC controls the muxing of pins:
+ the {\bf pinmux controller}
+ \item The Device Tree describes which pin configurations are
+ possible, and which configurations are used by the different
+ devices.
+ \end{itemize}
+ \column{0.5\textwidth}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/pin-muxing-principle.pdf}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Pin-muxing controllers on STM32MP1}
+ \begin{block}{\kfileversion{arch/arm/boot/dts/stm32mp151.dtsi}{6.1}}
+{\tiny
+\begin{minted}{perl}
+pinctrl: pin-controller@50002000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stm32mp157-pinctrl";
+ ...
+ gpioa: gpio@50002000 { ... };
+ gpiob: gpio@50003000 { ... };
+ gpioc: gpio@50004000 { ... };
+ gpiod: gpio@50005000 { ... };
+ gpioe: gpio@50006000 { ... };
+ gpiof: gpio@50007000 { ... };
+ ...
+};
+
+pinctrl_z: pin-controller-z@54004000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "st,stm32mp157-z-pinctrl";
+ ranges = <0 0x54004000 0x400>;
+ ...
+ gpioz: gpio@54004000 { .... };
+ ...
+};
+\end{minted}
+}
+ \end{block}
+\end{frame}
+
+\begin{frame}[fragile]{Pin-muxing configuration}
+\begin{onlyenv}<1>
+ \begin{block}{\kfile{arch/arm/boot/dts/stm32mp15-pinctrl.dtsi}}
+{\tiny
+\begin{minted}{perl}
+&pinctrl {
+ ...
+ i2c1_pins_a: i2c1-0 {
+ pins {
+ pinmux = , /* I2C1_SCL */
+ ; /* I2C1_SDA */
+ bias-disable;
+ drive-open-drain;
+ slew-rate = <0>;
+ };
+ };
+ ...
+ m_can1_pins_a: m-can1-0 {
+ pins1 {
+ pinmux = ; /* CAN1_TX */
+ slew-rate = <1>;
+ drive-push-pull;
+ bias-disable;
+ };
+ pins2 {
+ pinmux = ; /* CAN1_RX */
+ bias-disable;
+ };
+ };
+ ...
+};
+\end{minted}
+}
+ \end{block}
+\end{onlyenv}
+\begin{onlyenv}<2>
+ \begin{center}
+ \includegraphics[height=0.78\textheight]{slides/sysdev-hw-devices/stm32mp1/stm32mp157-i2c-pin-mux.png}
+ \end{center}
+ \tiny
+ Source: \href{https://www.st.com/resource/en/datasheet/stm32mp157c.pdf}{STM32MP157C
+ datasheet}. Note that \code{I2C1_SDA} is also available on pin \code{PF15} (not shown here).
+\end{onlyenv}
+\end{frame}
+
+\begin{frame}[fragile]{Pin-muxing consumer}
+ \begin{block}{}
+{\tiny
+\begin{minted}{perl}
+&i2c1 {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c1_pins_a>;
+ pinctrl-1 = <&i2c1_sleep_pins_a>;
+ ...
+};
+\end{minted}
+}
+\end{block}
+\begin{itemize}
+\item Typically board-specific, in \code{.dts}
+\item \code{pinctrl-0}, \code{pinctrl-1}, \code{pinctrl-X} provides
+ the pin mux configurations for the different {\bf states}
+\item \code{pinctrl-names} gives a name to each state, mandatory even
+ if only one state
+\item States are mutually exclusive
+\item The driver is responsible for switching between states
+\item \code{default} state is automatically set up when the device is
+ {\em probed}
+\end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{Example: LED and I2C device}
+ \begin{itemize}
+ \item Let's see how to describe an LED and an I2C device connected
+ to the DK1 platform.
+ \item Create \code{arch/arm/boot/dts/stm32mp157a-dk1-custom.dts}
+ which includes \code{stm32mp157a-dk1.dts}
+ \begin{block}{}
+{\tiny
+\begin{verbatim}
+#include "stm32mp157a-dk1.dts"
+\end{verbatim}
+}
+ \end{block}
+ \item Make sure \code{stm32mp157a-dk1-custom.dts} gets compiled to a
+ DTB by changing \kfile{arch/arm/boot/dts/Makefile}
+ \begin{block}{}
+ {\tiny
+\begin{verbatim}
+dtb-$(CONFIG_ARCH_STM32) += \
+ ...
+ stm32mp157a-dk1.dtb \
+ stm32mp157a-dk1-custom.dtb \
+\end{verbatim}
+ }
+ \end{block}
+ \item \code{make dtbs}
+ \begin{block}{}
+ {\tiny
+\begin{verbatim}
+ DTC arch/arm/boot/dts/stm32mp157a-dk1-custom.dtb
+\end{verbatim}
+ }
+ \end{block}
+ \end{itemize}
+\end{frame}
+
+\begin{frame}[fragile]{Example: describe an LED}
+ \begin{columns}
+ \column{0.5\textwidth}
+ \begin{block}{stm32mp157a-dk1-custom.dts}
+ {\tiny
+\begin{minted}{perl}
+#include "stm32mp157a-dk1.dts"
+
+/ {
+ leds {
+ compatible = "gpio-leds";
+ webinar {
+ label = "webinar";
+ gpios = <&gpioe 1 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+\end{minted}
+ }
+ \end{block}
+ \begin{block}{shell}
+{\tiny
+\begin{verbatim}
+# echo 255 > /sys/class/leds/webinar/brightness
+\end{verbatim}
+}
+\end{block}
+ \column{0.5\textwidth}
+ \begin{center}
+ \includegraphics[height=0.3\textheight]{slides/sysdev-hw-devices/stm32mp1/cn14-pinout.png}\\
+ \vspace{0.5cm}
+ \includegraphics[height=0.3\textheight]{slides/sysdev-hw-devices/stm32mp1/led-on.jpg}
+ \end{center}
+ \end{columns}
+\end{frame}
+
+\begin{frame}[fragile]{Example: connect I2C temperature, humidity and pressure sensor}
+ \begin{columns}
+ \column{0.5\textwidth}
+ \begin{block}{stm32mp157a-dk1-custom.dts}
+ {\tiny
+\begin{minted}{perl}
+&i2c5 {
+ status = "okay";
+ clock-frequency = <100000>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&i2c5_pins_a>;
+ pinctrl-1 = <&i2c5_pins_sleep_a>;
+
+ pressure@76 {
+ compatible = "bosch,bme280";
+ reg = <0x76>;
+ };
+};
+\end{minted}
+}
+ \end{block}
+
+\begin{block}{shell}
+{\tiny
+\begin{verbatim}
+# cat /sys/bus/iio/devices/iio\:device2/in_humidityrelative_input
+49147
+# cat /sys/bus/iio/devices/iio\:device2/in_pressure_input
+101.567167968
+# cat /sys/bus/iio/devices/iio\:device2/in_temp_input
+24380
+\end{verbatim}
+}
+\end{block}
+ \column{0.5\textwidth}
+ \begin{center}
+ \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/stm32mp1/cn13-pinout.png}\\
+ \includegraphics[width=0.4\textwidth]{slides/sysdev-hw-devices/bme.jpg}
+ \end{center}
+\end{columns}
+\vspace{0.5cm}
+Details at
+\url{https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-connecting-an-i2c-sensor/}
+\end{frame}
+
+\begin{frame}{Further details about the Device Tree}
+\small
+Check out our {\em Device Tree 101 webinar}, by Thomas Petazzoni (2021)
+\begin{itemize}
+ \item Slides: \url{https://bootlin.com/blog/device-tree-101-webinar-slides-and-videos/}\\
+ \item Video: \url{https://youtu.be/a9CZ1Uk3OYQ}
+\end{itemize}
+\vspace{0.5cm}
+\includegraphics[height=0.5\textheight]{common/device-tree-video.jpg}
+\end{frame}
+
+\subsection{Discoverable hardware: USB and PCI}
+
+\begin{frame}{Discoverable hardware}
+ \begin{itemize}
+ \item Some busses have built-in hardware discoverability mechanisms
+ \item Most common busses: USB and PCI
+ \item Hardware devices can be enumerated, and their characteristics
+ retrieved with just a driver or the bus controller
+ \item Useful Linux commands
+ \begin{itemize}
+ \item \code{lsusb}, lists all USB devices detected
+ \item \code{lspci}, lists all PCI devices detected
+ \item A detected device does not mean it has a kernel driver
+ associated to it!
+ \end{itemize}
+ \item Association with kernel drivers done based on product
+ ID/vendor ID, or some other characteristics of the device: device
+ class, device sub-class, etc.
+ \end{itemize}
+\end{frame}
+
+\setuplabframe
+{Accessing hardware devices}
+{
+ Time to start the practical lab!
+ \begin{itemize}
+ \item Exploring the contents of \code{/dev} and \code{/sys} and the
+ devices available on the embedded hardware platform.
+ \item Using GPIOs and LEDs.
+ \item Modifying the Device Tree to control pin multiplexing and
+ declare an I2C-connected joystick.
+ \item Adding support for a USB audio card using Linux kernel modules
+ \item Adding support for the I2C-connected joystick through
+ an out-of-tree module.
+ \end{itemize}
+}
diff --git a/slides/sysdev-hw-devices/sysdev-hw-devices.tex b/slides/sysdev-hw-devices/sysdev-hw-devices.tex
index 67197d246f..ccdad1a347 100644
--- a/slides/sysdev-hw-devices/sysdev-hw-devices.tex
+++ b/slides/sysdev-hw-devices/sysdev-hw-devices.tex
@@ -926,1044 +926,9 @@ \subsection{Describing non-discoverable hardware: Device Tree}
\end{columns}
\end{frame}
-\begin{frame}[fragile]{DT overall structure: simplified example}
- \begin{columns}
- \column{0.6\textwidth}
- \begin{onlyenv}<1>
- \begin{block}{}
-\begin{minted}[fontsize=\tiny]{perl}
-/ {
- #address-cells = <1>;
- #size-cells = <1>;
- model = "STMicroelectronics STM32MP157C-DK2 Discovery Board";
- compatible = "st,stm32mp157c-dk2", "st,stm32mp157";
-
- cpus { ... };
- memory@0 { ... };
- chosen { ... };
- intc: interrupt-controller@a0021000 { ... };
- soc {
- i2c1: i2c@40012000 { ... };
- ethernet0: ethernet@5800a000 { ... };
- };
-};
-\end{minted}
- \end{block}
- \end{onlyenv}
- \begin{onlyenv}<2>
- \begin{block}{}
-\begin{minted}[fontsize=\tiny]{perl}
-/ {
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
- cpu0: cpu@0 {
- compatible = "arm,cortex-a7";
- clock-frequency = <650000000>;
- device_type = "cpu";
- reg = <0>;
- };
-
- cpu1: cpu@1 {
- compatible = "arm,cortex-a7";
- clock-frequency = <650000000>;
- device_type = "cpu";
- reg = <1>;
- };
- };
-
- memory@0 { ... };
- chosen { ... };
- intc: interrupt-controller@a0021000 { ... };
- soc {
- i2c1: i2c@40012000 { ... };
- ethernet0: ethernet@5800a000 { ... };
- };
-};
-\end{minted}
- \end{block}
- \end{onlyenv}
- \begin{onlyenv}<3>
- \begin{block}{}
-\begin{minted}[fontsize=\tiny]{perl}
-/ {
- cpus { ... };
- memory@0 {
- device_type = "memory";
- reg = <0x0 0x20000000>;
- };
-
- chosen {
- bootargs = "";
- stdout-path = "serial0:115200n8";
- };
- intc: interrupt-controller@a0021000 { ... };
- soc {
- i2c1: i2c@40012000 { ... };
- ethernet0: ethernet@5800a000 { ... };
- };
-};
-\end{minted}
- \end{block}
- \end{onlyenv}
- \begin{onlyenv}<4>
- \begin{block}{}
-\begin{minted}[fontsize=\tiny]{perl}
-/ {
- cpus { ... };
- memory@0 { ... };
- chosen { ... };
-
- intc: interrupt-controller@a0021000 {
- compatible = "arm,cortex-a7-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0xa0021000 0x1000>,
- <0xa0022000 0x2000>;
- };
-
- soc {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- interrupt-parent = <&intc>;
-
- i2c1: i2c@40012000 { ... };
- ethernet0: ethernet@5800a000 { ... };
- };
-};
-\end{minted}
- \end{block}
- \end{onlyenv}
- \begin{onlyenv}<5>
- \begin{block}{}
-\begin{minted}[fontsize=\tiny]{perl}
-/ {
- cpus { ... };
- memory@0 { ... };
- chosen { ... };
- intc: interrupt-controller@a0021000 { ... };
- soc {
- i2c1: i2c@40012000 {
- compatible = "st,stm32mp15-i2c";
- reg = <0x40012000 0x400>;
- interrupts = ,
- ;
- #address-cells = <1>;
- #size-cells = <0>;
- status = "okay";
-
- cs42l51: cs42l51@4a {
- compatible = "cirrus,cs42l51";
- reg = <0x4a>;
- reset-gpios = <&gpiog 9 GPIO_ACTIVE_LOW>;
- status = "okay";
- };
- };
- ethernet0: ethernet@5800a000 { ... };
- };
-};
-\end{minted}
- \end{block}
- \end{onlyenv}
- \begin{onlyenv}<6>
- \begin{block}{}
-\begin{minted}[fontsize=\tiny]{perl}
-/ {
- cpus { ... };
- memory@0 { ... };
- chosen { ... };
- intc: interrupt-controller@a0021000 { ... };
- soc {
- compatible = "simple-bus";
- ...
- interrupt-parent = <&intc>;
- i2c1: i2c@40012000 { ... };
-
- ethernet0: ethernet@5800a000 {
- compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";
- reg = <0x5800a000 0x2000>;
- interrupts-extended = <&intc GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
- status = "okay";
-
- mdio0 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "snps,dwmac-mdio";
- phy0: ethernet-phy@0 {
- reg = <0>;
- };
- };
- };
- };
-};
-\end{minted}
- \end{block}
- \end{onlyenv}
- \column{0.4\textwidth}
- \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/simple-hardware.pdf}
- \end{columns}
-\end{frame}
-
-\begin{frame}[fragile]{Device Tree inheritance}
- \begin{itemize}
- \item Device Tree files are not monolithic, they can be split in
- several files, including each other.
- \item \code{.dtsi} files are included files, while \code{.dts} files
- are {\em final} Device Trees
- \begin{itemize}
- \item Only \code{.dts} files are accepted as input to \code{dtc}
- \end{itemize}
- \item Typically, \code{.dtsi} will contain
- \begin{itemize}
- \item definitions of SoC-level information
- \item definitions common to several boards
- \end{itemize}
- \item The \code{.dts} file contains the board-level information
- \item The inclusion works by {\bf overlaying} the tree of the
- including file over the tree of the included file,
- according to the order of the \code{#include} directives.
- \item Allows an including file to {\bf override} values specified by
- an included file
- \item Uses the C pre-processor \code{#include} directive
- \end{itemize}
-\end{frame}
-
-\begin{frame}{Device Tree inheritance example}
- \begin{center}
- \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/dt-inheritance.pdf}
- \end{center}
-\end{frame}
-
-\begin{frame}[fragile]{Inheritance and labels}
-
- \begin{columns}[t]
- \column{0.5\textwidth}
- Doing:
- \begin{block}{soc.dtsi}
- {\tiny
-\begin{minted}{perl}
-/ {
- soc {
- usart1: serial@5c000000 {
- compatible = "st,stm32h7-uart";
- reg = <0x5c000000 0x400>;
- status = "disabled";
- };
- };
-};
-\end{minted}
- }
- \end{block}
-
- \begin{block}{board.dts}
- {\tiny
-\begin{minted}{perl}
-#include "soc.dtsi"
-
-/ {
- soc {
- serial@5c000000 {
- status = "okay";
- };
- };
-};
-\end{minted}
- }
- \end{block}
-
- \column{0.5\textwidth}
- \begin{onlyenv}<2>
- Is exactly equivalent to:
-
- \begin{block}{soc.dtsi}
- {\tiny
-\begin{minted}{perl}
-/ {
- soc {
- usart1: serial@5c000000 {
- compatible = "st,stm32h7-uart";
- reg = <0x5c000000 0x400>;
- status = "disabled";
- };
- };
-};
-\end{minted}
- }
- \end{block}
-
- \begin{block}{board.dts}
- {\tiny
-\begin{minted}{perl}
-#include "soc.dtsi"
-
-&usart1 {
- status = "okay";
-};
-\end{minted}
- }
- \end{block}
-
- $\rightarrow$ this solution is now often preferred
- \end{onlyenv}
- \end{columns}
-
-\end{frame}
-
-\begin{frame}{DT inheritance in STM32MP1 support}
- \begin{center}
- \includegraphics[height=0.8\textheight]{slides/sysdev-hw-devices/dt-inheritance-stm32.pdf}
- \end{center}
-\end{frame}
-
-\begin{frame}{Device Tree design principles}
- \begin{itemize}
- \item {\bf Describe hardware} (how the hardware is), not
- configuration (how I choose to use the hardware)
- \item {\bf OS-agnostic}
- \begin{itemize}
- \item For a given piece of HW, Device Tree should be the same for
- U-Boot, FreeBSD or Linux
- \item There should be no need to change the Device Tree when updating the OS
- \end{itemize}
- \item Describe {\bf integration of hardware components}, not the internals
- of hardware components
- \begin{itemize}
- \item The details of how a specific device/IP block is working is
- handled by code in device drivers
- \item The Device Tree describes how the device/IP block is
- connected/integrated with the rest of the system: IRQ lines, DMA
- channels, clocks, reset lines, etc.
- \end{itemize}
- \item Like all beautiful design principles, these principles are
- sometimes violated.
- \end{itemize}
-\end{frame}
-
-\begin{frame}{Device Tree specifications}
- \begin{columns}
- \column{0.7\textwidth}
- \begin{itemize}
- \item How to write the correct nodes/properties to describe a
- given hardware platform~?
- \item {\bf Device Tree Specifications} $\rightarrow$ base Device
- Tree syntax + number of standard properties.
- \begin{itemize}
- \item \url{https://www.devicetree.org/specifications/}
- \item Not sufficient to describe the wide variety of hardware.
- \end{itemize}
- \item {\bf Device Tree Bindings} $\rightarrow$ documents that each
- specify how a piece of HW should be described
- \begin{itemize}
- \item \kdir{Documentation/devicetree/bindings} in Linux kernel sources
- \item Reviewed by DT bindings maintainer team
- \item Legacy: human readable documents
- \item New norm: YAML-written specifications
- \end{itemize}
- \end{itemize}
- \column{0.3\textwidth}
- \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/dt-spec.png}
- \end{columns}
-\end{frame}
-
-\begin{frame}[fragile]{Device Tree binding: old style}
- \begin{center}
- \kfile{Documentation/devicetree/bindings/mtd/spear_smi.txt}\\
- This IP is {\em not} used on STM32MP1.
- \end{center}
- \begin{columns}[t]
- \column{0.5\textwidth}
- \begin{block}{}
- {\fontsize{5}{6}\selectfont
-\begin{verbatim}
-* SPEAr SMI
-
-Required properties:
-- compatible : "st,spear600-smi"
-- reg : Address range of the mtd chip
-- #address-cells, #size-cells : Must be present if the device has sub-nodes
- representing partitions.
-- interrupts: Should contain the STMMAC interrupts
-- clock-rate : Functional clock rate of SMI in Hz
-
-Optional properties:
-- st,smi-fast-mode : Flash supports read in fast mode
-
-\end{verbatim}
- }
- \end{block}
- \column{0.5\textwidth}
- \begin{block}{}
- {\fontsize{4}{5}\selectfont
-\begin{verbatim}
-Example:
-
- smi: flash@fc000000 {
- compatible = "st,spear600-smi";
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0xfc000000 0x1000>;
- interrupt-parent = <&vic1>;
- interrupts = <12>;
- clock-rate = <50000000>; /* 50MHz */
-
- flash@f8000000 {
- st,smi-fast-mode;
- ...
- };
- };
-\end{verbatim}
- }
- \end{block}
- \end{columns}
-
-\end{frame}
-
-\begin{frame}[fragile]{Device Tree binding: YAML style}
- \kfile{Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml}
- \begin{columns}[t]
- \column{0.5\textwidth}
- \begin{block}{}
- {\fontsize{5}{6}\selectfont
-\begin{minted}{yaml}
-# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
-%YAML 1.2
----
-$id: http://devicetree.org/schemas/i2c/st,stm32-i2c.yaml#
-$schema: http://devicetree.org/meta-schemas/core.yaml#
-
-title: I2C controller embedded in STMicroelectronics STM32 I2C platform
-
-maintainers:
- - Pierre-Yves MORDRET
-
-properties:
- compatible:
- enum:
- - st,stm32f4-i2c
- - st,stm32f7-i2c
- - st,stm32mp15-i2c
-
- reg:
- maxItems: 1
-
- interrupts:
- items:
- - description: interrupt ID for I2C event
- - description: interrupt ID for I2C error
-
- resets:
- maxItems: 1
-
-\end{minted}
- }
- \end{block}
- \column{0.5\textwidth}
- \begin{block}{}
- {\fontsize{5}{6}\selectfont
-\begin{minted}{yaml}
- clocks:
- maxItems: 1
-
- dmas:
- items:
- - description: RX DMA Channel phandle
- - description: TX DMA Channel phandle
-
- ...
-
- clock-frequency:
- description: Desired I2C bus clock frequency in Hz. If not specified,
- the default 100 kHz frequency will be used.
- For STM32F7, STM32H7 and STM32MP1 SoCs, if timing
- parameters match, the bus clock frequency can be from
- 1Hz to 1MHz.
- default: 100000
- minimum: 1
- maximum: 1000000
-
-required:
- - compatible
- - reg
- - interrupts
- - resets
- - clocks
-\end{minted}
- }
- \end{block}
- \end{columns}
-\end{frame}
-
-\begin{frame}[fragile]{Device Tree binding: YAML style example}
- \begin{block}{}
- {\fontsize{5}{6}\selectfont
-\begin{minted}{yaml}
-examples:
- - |
- //Example 3 (with st,stm32mp15-i2c compatible on stm32mp)
- #include
- #include
- #include
- i2c@40013000 {
- compatible = "st,stm32mp15-i2c";
- #address-cells = <1>;
- #size-cells = <0>;
- reg = <0x40013000 0x400>;
- interrupts = ,
- ;
- clocks = <&rcc I2C2_K>;
- resets = <&rcc I2C2_R>;
- i2c-scl-rising-time-ns = <185>;
- i2c-scl-falling-time-ns = <20>;
- st,syscfg-fmp = <&syscfg 0x4 0x2>;
- };
-\end{minted}
- }
- \end{block}
-\end{frame}
-
-\begin{frame}{Validating Device Tree in Linux}
- \begin{itemize}
- \item \code{dtc} only does syntactic validation
- \item YAML bindings allow to do semantic validation
- \item Linux kernel \code{make} rules:
- \begin{itemize}
- \item \code{make dt_binding_check}\\
- verify that YAML bindings are valid
- \item \code{make dtbs_check}\\
- validate DTs currently enabled against YAML bindings
- \item \code{make DT_SCHEMA_FILES=Documentation/devicetree/bindings/trivial-devices.yaml dtbs_check}\\
- validate DTs against a specific YAML binding
- \end{itemize}
- \end{itemize}
-\end{frame}
-
-\begin{frame}{The {\tt compatible} property}
- \begin{itemize}
- \item Is a list of strings
- \begin{itemize}
- \item From the most specific to the least specific
- \end{itemize}
- \item Describes the specific {\bf binding} to which the node complies.
- \item It uniquely identifies the {\bf programming model} of the
- device.
- \item Practically speaking, it is used by the operating system to
- find the {\bf appropriate driver} for this device.
- \item When describing real hardware, the typical form is
- \code{vendor,model}
- \item Examples:
- \begin{itemize}
- \item \code{compatible = "arm,armv7-timer";}
- \item \code{compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a";}
- \item \code{compatible = "regulator-fixed";}
- \item \code{compatible = "gpio-keys";}
- \end{itemize}
- \item Special value: \code{simple-bus} $\rightarrow$ bus where all
- sub-nodes are memory-mapped devices
- \end{itemize}
-\end{frame}
-
-\begin{frame}{{\tt compatible} property and Linux kernel drivers}
- \begin{columns}
- \column{0.6\textwidth}
- \begin{itemize}
- \item Linux identifies as {\bf platform devices}:
- \begin{itemize}
- \item Top-level DT nodes with a \code{compatible} string
- \item Sub-nodes of \code{simple-bus}
- \begin{itemize}
- \item Instantiated automatically at boot time
- \end{itemize}
- \end{itemize}
- \item Sub-nodes of I2C controllers $\rightarrow$ {\em I2C devices}
- \item Sub-nodes of SPI controllers $\rightarrow$ {\em SPI devices}
- \item Each Linux driver has a table of compatible strings it supports
- \begin{itemize}
- \item \kstruct{of_device_id}\code{[]}
- \end{itemize}
- \item When a DT node compatible string matches a given driver, the
- device is {\em bound} to that driver.
- \end{itemize}
- \column{0.4\textwidth}
- \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/dt-to-devices.pdf}
- \end{columns}
-\end{frame}
-
-\begin{frame}[fragile]{Matching with drivers in Linux: platform driver}
- \begin{block}{\kfile{drivers/tty/serial/stm32-usart.c}}
- {\tiny
-\begin{minted}{c}
-static const struct of_device_id stm32_match[] = {
- { .compatible = "st,stm32-uart", .data = &stm32f4_info},
- { .compatible = "st,stm32f7-uart", .data = &stm32f7_info},
- { .compatible = "st,stm32h7-uart", .data = &stm32h7_info},
- {},
-};
-MODULE_DEVICE_TABLE(of, stm32_match);
-
-...
-
-static struct platform_driver stm32_serial_driver = {
- .probe = stm32_serial_probe,
- .remove = stm32_serial_remove,
- .driver = {
- .name = DRIVER_NAME,
- .pm = &stm32_serial_pm_ops,
- .of_match_table = of_match_ptr(stm32_match),
- },
-};
-\end{minted}
- }
- \end{block}
-\end{frame}
-
-\begin{frame}[fragile]{Matching with drivers in Linux: I2C driver}
- \begin{block}{\kfile{sound/soc/codecs/cs42l51.c}}
- {\tiny
-\begin{minted}{c}
-const struct of_device_id cs42l51_of_match[] = {
- { .compatible = "cirrus,cs42l51", },
- { }
-};
-MODULE_DEVICE_TABLE(of, cs42l51_of_match);
-\end{minted}
- }
- \end{block}
- \begin{block}{\kfile{sound/soc/codecs/cs42l51-i2c.c}}
- {\tiny
-\begin{minted}{c}
-static struct i2c_driver cs42l51_i2c_driver = {
- .driver = {
- .name = "cs42l51",
- .of_match_table = cs42l51_of_match,
- .pm = &cs42l51_pm_ops,
- },
- .probe = cs42l51_i2c_probe,
- .remove = cs42l51_i2c_remove,
- .id_table = cs42l51_i2c_id,
-};
-\end{minted}
- }
- \end{block}
-\end{frame}
-
-\begin{frame}[fragile]{{\tt reg} property}
- \begin{itemize}
- \item Most important property after \code{compatible}
- \item {\bf Memory-mapped} devices: base physical address and size of
- the memory-mapped registers. Can have several entries for multiple
- register areas.
-\begin{onlyenv}<1>
-\begin{block}{}
-\begin{verbatim}
-sai4: sai@50027000 {
- reg = <0x50027000 0x4>, <0x500273f0 0x10>;
-};
-\end{verbatim}
-\end{block}
-\end{onlyenv}
-\pause
- \item {\bf I2C} devices: address of the device on the I2C bus.
-\begin{onlyenv}<2>
-\begin{block}{}
-\begin{verbatim}
-&i2c1 {
- hdmi-transmitter@39 {
- reg = <0x39>;
- };
- cs42l51: cs42l51@4a {
- reg = <0x4a>;
- };
-};
-\end{verbatim}
-\end{block}
-\end{onlyenv}
-\pause
- \item {\bf SPI} devices: chip select number
-\begin{onlyenv}<3>
-\begin{block}{}
-\begin{verbatim}
-&qspi {
- flash0: mx66l51235l@0 {
- reg = <0>;
- };
- flash1: mx66l51235l@1 {
- reg = <1>;
- };
-};
-\end{verbatim}
-\end{block}
-\end{onlyenv}
-\pause
-\item The unit address must be the address of the first \code{reg}
- entry.
-\begin{onlyenv}<4>
-\begin{block}{}
-\begin{verbatim}
-sai4: sai@50027000 {
- reg = <0x50027000 0x4>, <0x500273f0 0x10>;
-};
-\end{verbatim}
-\end{block}
-\end{onlyenv}
- \end{itemize}
-\end{frame}
-
-\begin{frame}{Status property}
- \begin{itemize}
- \item The \code{status} property indicates if the device is really in
- use or not
- \begin{itemize}
- \item \code{okay} or \code{ok} $\rightarrow$ the device is really
- in use
- \item any other value, by convention \code{disabled} $\rightarrow$
- the device is not in use
- \end{itemize}
- \item In Linux, controls if a device is instantiated
- \item In \code{.dtsi} files describing SoCs: all devices that
- interface to the outside world have \code{status = "disabled";}
- \item Enabled on a per-device basis in the board \code{.dts}
- \end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]{Resources: interrupts, clocks, DMA, reset lines, ...}
- \begin{columns}
- \column{0.5\textwidth}
- \begin{itemize}
- \item Common pattern for resources shared by multiple hardware
- blocks
- \begin{itemize}
- \item Interrupt lines
- \item Clock controllers
- \item DMA controllers
- \item Reset controllers
- \item ...
- \end{itemize}
- \item A Device Tree node describing the {\em controller} as a device
- \item References from other nodes that use resources provided by
- this {\em controller}
- \end{itemize}
- \column{0.5\textwidth}
-\begin{block}{}
-{\tiny
-\begin{minted}{perl}
-intc: interrupt-controller@a0021000 {
- compatible = "arm,cortex-a7-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0xa0021000 0x1000>, <0xa0022000 0x2000>;
-};
-
-rcc: rcc@50000000 {
- compatible = "st,stm32mp1-rcc", "syscon";
- reg = <0x50000000 0x1000>;
- #clock-cells = <1>;
- #reset-cells = <1>;
-};
-
-dmamux1: dma-router@48002000 {
- compatible = "st,stm32h7-dmamux";
- reg = <0x48002000 0x1c>;
- #dma-cells = <3>;
- clocks = <&rcc DMAMUX>;
- resets = <&rcc DMAMUX_R>;
-};
-
-spi3: spi@4000c000 {
- interrupts = ;
- clocks = <&rcc SPI3_K>;
- resets = <&rcc SPI3_R>;
- dmas = <&dmamux1 61 0x400 0x05>, <&dmamux1 62 0x400 0x05>;
-};
-\end{minted}
-}
-\end{block}
-\end{columns}
-\end{frame}
-
-\begin{frame}{Pin-muxing description}
- \begin{columns}
- \column{0.5\textwidth}
- \begin{itemize}
- \item Most modern SoCs, including the STM32MP1, have more features
- than they have pins to expose those features to the outside world.
- \item Pins are muxed: a given pin can be used for one function
- {\bf or} another
- \item A specific IP block in the SoC controls the muxing of pins:
- the {\bf pinmux controller}
- \item The Device Tree describes which pin configurations are
- possible, and which configurations are used by the different
- devices.
- \end{itemize}
- \column{0.5\textwidth}
- \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/pin-muxing-principle.pdf}
- \end{columns}
-\end{frame}
-
-\begin{frame}[fragile]{Pin-muxing controllers on STM32MP1}
- \begin{block}{\kfileversion{arch/arm/boot/dts/stm32mp151.dtsi}{6.1}}
-{\tiny
-\begin{minted}{perl}
-pinctrl: pin-controller@50002000 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "st,stm32mp157-pinctrl";
- ...
- gpioa: gpio@50002000 { ... };
- gpiob: gpio@50003000 { ... };
- gpioc: gpio@50004000 { ... };
- gpiod: gpio@50005000 { ... };
- gpioe: gpio@50006000 { ... };
- gpiof: gpio@50007000 { ... };
- ...
-};
-
-pinctrl_z: pin-controller-z@54004000 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "st,stm32mp157-z-pinctrl";
- ranges = <0 0x54004000 0x400>;
- ...
- gpioz: gpio@54004000 { .... };
- ...
-};
-\end{minted}
-}
- \end{block}
-\end{frame}
-
-\begin{frame}[fragile]{Pin-muxing configuration}
-\begin{onlyenv}<1>
- \begin{block}{\kfile{arch/arm/boot/dts/stm32mp15-pinctrl.dtsi}}
-{\tiny
-\begin{minted}{perl}
-&pinctrl {
- ...
- i2c1_pins_a: i2c1-0 {
- pins {
- pinmux = , /* I2C1_SCL */
- ; /* I2C1_SDA */
- bias-disable;
- drive-open-drain;
- slew-rate = <0>;
- };
- };
- ...
- m_can1_pins_a: m-can1-0 {
- pins1 {
- pinmux = ; /* CAN1_TX */
- slew-rate = <1>;
- drive-push-pull;
- bias-disable;
- };
- pins2 {
- pinmux = ; /* CAN1_RX */
- bias-disable;
- };
- };
- ...
-};
-\end{minted}
-}
- \end{block}
-\end{onlyenv}
-\begin{onlyenv}<2>
- \begin{center}
- \includegraphics[height=0.78\textheight]{slides/sysdev-hw-devices/stm32mp157-i2c-pin-mux.png}
- \end{center}
- \tiny
- Source: \href{https://www.st.com/resource/en/datasheet/stm32mp157c.pdf}{STM32MP157C
- datasheet}. Note that \code{I2C1_SDA} is also available on pin \code{PF15} (not shown here).
-\end{onlyenv}
-\end{frame}
-
-\begin{frame}[fragile]{Pin-muxing consumer}
- \begin{block}{}
-{\tiny
-\begin{minted}{perl}
-&i2c1 {
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&i2c1_pins_a>;
- pinctrl-1 = <&i2c1_sleep_pins_a>;
- ...
-};
-\end{minted}
-}
-\end{block}
-\begin{itemize}
-\item Typically board-specific, in \code{.dts}
-\item \code{pinctrl-0}, \code{pinctrl-1}, \code{pinctrl-X} provides
- the pin mux configurations for the different {\bf states}
-\item \code{pinctrl-names} gives a name to each state, mandatory even
- if only one state
-\item States are mutually exclusive
-\item The driver is responsible for switching between states
-\item \code{default} state is automatically set up when the device is
- {\em probed}
-\end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]{Example: LED and I2C device}
- \begin{itemize}
- \item Let's see how to describe an LED and an I2C device connected
- to the DK1 platform.
- \item Create \code{arch/arm/boot/dts/stm32mp157a-dk1-custom.dts}
- which includes \code{stm32mp157a-dk1.dts}
- \begin{block}{}
-{\tiny
-\begin{verbatim}
-#include "stm32mp157a-dk1.dts"
-\end{verbatim}
-}
- \end{block}
- \item Make sure \code{stm32mp157a-dk1-custom.dts} gets compiled to a
- DTB by changing \kfile{arch/arm/boot/dts/Makefile}
- \begin{block}{}
- {\tiny
-\begin{verbatim}
-dtb-$(CONFIG_ARCH_STM32) += \
- ...
- stm32mp157a-dk1.dtb \
- stm32mp157a-dk1-custom.dtb \
-\end{verbatim}
- }
- \end{block}
- \item \code{make dtbs}
- \begin{block}{}
- {\tiny
-\begin{verbatim}
- DTC arch/arm/boot/dts/stm32mp157a-dk1-custom.dtb
-\end{verbatim}
- }
- \end{block}
- \end{itemize}
-\end{frame}
-
-\begin{frame}[fragile]{Example: describe an LED}
- \begin{columns}
- \column{0.5\textwidth}
- \begin{block}{stm32mp157a-dk1-custom.dts}
- {\tiny
-\begin{minted}{perl}
-#include "stm32mp157a-dk1.dts"
-
-/ {
- leds {
- compatible = "gpio-leds";
- webinar {
- label = "webinar";
- gpios = <&gpioe 1 GPIO_ACTIVE_HIGH>;
- };
- };
-};
-\end{minted}
- }
- \end{block}
- \begin{block}{shell}
-{\tiny
-\begin{verbatim}
-# echo 255 > /sys/class/leds/webinar/brightness
-\end{verbatim}
-}
-\end{block}
- \column{0.5\textwidth}
- \begin{center}
- \includegraphics[height=0.3\textheight]{slides/sysdev-hw-devices/cn14-pinout.png}\\
- \vspace{0.5cm}
- \includegraphics[height=0.3\textheight]{slides/sysdev-hw-devices/led-on.jpg}
- \end{center}
- \end{columns}
-\end{frame}
-
-\begin{frame}[fragile]{Example: connect I2C temperature, humidity and pressure sensor}
- \begin{columns}
- \column{0.5\textwidth}
- \begin{block}{stm32mp157a-dk1-custom.dts}
- {\tiny
-\begin{minted}{perl}
-&i2c5 {
- status = "okay";
- clock-frequency = <100000>;
- pinctrl-names = "default", "sleep";
- pinctrl-0 = <&i2c5_pins_a>;
- pinctrl-1 = <&i2c5_pins_sleep_a>;
-
- pressure@76 {
- compatible = "bosch,bme280";
- reg = <0x76>;
- };
-};
-\end{minted}
-}
- \end{block}
-
-\begin{block}{shell}
-{\tiny
-\begin{verbatim}
-# cat /sys/bus/iio/devices/iio\:device2/in_humidityrelative_input
-49147
-# cat /sys/bus/iio/devices/iio\:device2/in_pressure_input
-101.567167968
-# cat /sys/bus/iio/devices/iio\:device2/in_temp_input
-24380
-\end{verbatim}
-}
-\end{block}
- \column{0.5\textwidth}
- \begin{center}
- \includegraphics[width=\textwidth]{slides/sysdev-hw-devices/cn13-pinout.png}\\
- \includegraphics[width=0.4\textwidth]{slides/sysdev-hw-devices/bme.jpg}
- \end{center}
-\end{columns}
-\vspace{0.5cm}
-Details at
-\url{https://bootlin.com/blog/building-a-linux-system-for-the-stm32mp1-connecting-an-i2c-sensor/}
-\end{frame}
-
-\begin{frame}{Further details about the Device Tree}
-\small
-Check out our {\em Device Tree 101 webinar}, by Thomas Petazzoni (2021)
-\begin{itemize}
- \item Slides: \url{https://bootlin.com/blog/device-tree-101-webinar-slides-and-videos/}\\
- \item Video: \url{https://youtu.be/a9CZ1Uk3OYQ}
-\end{itemize}
-\vspace{0.5cm}
-\includegraphics[height=0.5\textheight]{common/device-tree-video.jpg}
-\end{frame}
-
-\subsection{Discoverable hardware: USB and PCI}
-
-\begin{frame}{Discoverable hardware}
- \begin{itemize}
- \item Some busses have built-in hardware discoverability mechanisms
- \item Most common busses: USB and PCI
- \item Hardware devices can be enumerated, and their characteristics
- retrieved with just a driver or the bus controller
- \item Useful Linux commands
- \begin{itemize}
- \item \code{lsusb}, lists all USB devices detected
- \item \code{lspci}, lists all PCI devices detected
- \item A detected device does not mean it has a kernel driver
- associated to it!
- \end{itemize}
- \item Association with kernel drivers done based on product
- ID/vendor ID, or some other characteristics of the device: device
- class, device sub-class, etc.
- \end{itemize}
-\end{frame}
-
-\setuplabframe
-{Accessing hardware devices}
-{
- Time to start the practical lab!
- \begin{itemize}
- \item Exploring the contents of \code{/dev} and \code{/sys} and the
- devices available on the embedded hardware platform.
- \item Using GPIOs and LEDs.
- \item Modifying the Device Tree to control pin multiplexing and
- declare an I2C-connected joystick.
- \item Adding support for a USB audio card using Linux kernel modules
- \item Adding support for the I2C-connected joystick through
- an out-of-tree module.
- \end{itemize}
-}
+\ifdefstring{\labboard}{stm32mp1}{
+ \input{slides/sysdev-hw-devices/stm32mp1/sysdev-hw-devices-stm32mp1.tex}
+}{}
+\ifdefstring{\labboard}{imx93-frdm}{
+ \input{slides/sysdev-hw-devices/imx93-frdm/sysdev-hw-devices-imx93-frdm.tex}
+}{\input{slides/sysdev-hw-devices/stm32mp1/sysdev-hw-devices-stm32mp1.tex}}
diff --git a/slides/sysdev-shopping-list-imx93-frdm/sysdev-shopping-list-imx93-frdm.tex b/slides/sysdev-shopping-list-imx93-frdm/sysdev-shopping-list-imx93-frdm.tex
new file mode 100644
index 0000000000..005eab2614
--- /dev/null
+++ b/slides/sysdev-shopping-list-imx93-frdm/sysdev-shopping-list-imx93-frdm.tex
@@ -0,0 +1,27 @@
+\begin{frame}
+\frametitle{Shopping list: hardware for this course}
+ \begin{columns}
+ \column{0.75\textwidth}
+ \footnotesize
+ \begin{itemize}
+ \item NXP i.MX93 11x11 FRDM development board -
+ Available from Mouser (76 EUR + VAT)
+ \item 2 USB-C cable for the power supply and the serial console
+ \item RJ45 cable for networking
+ \item Nintendo Nunchuk with UEXT connector
+ \footnote{\tiny \url{https://www.olimex.com/Products/Modules/Sensors/MOD-WII/MOD-Wii-UEXT-NUNCHUCK/}}
+ \item Breadboard jumper wires - Male ends (to connect the Nunchuk)
+ \footnote{\tiny \url{https://www.olimex.com/Products/Breadboarding/JUMPER-WIRES/JW-110x10/}}
+
+ \item A standard USB audio headset.
+ \item A micro SD card with at least 1 GB of capacity
+ \end{itemize}
+ \column{0.25\textwidth}
+ \includegraphics[height=0.25\textheight]{common/nunchuk.jpg} \\
+ \includegraphics[height=0.15\textheight]{common/jumper-wires.jpg} \\
+ %% Source: https://commons.wikimedia.org/wiki/Category:USB_Audio#/media/File:Andrea_Electronics_PureAudio_Speech_Development_Kit_(26603532598).png
+ \includegraphics[height=0.15\textheight]{common/usb-audio.png} \\
+ %% Source: https://commons.wikimedia.org/wiki/File:SD_card_icon.svg
+ \includegraphics[height=0.15\textheight]{common/sd-card.pdf}
+ \end{columns}
+\end{frame}