variables:
- windows_vm: vs2015-win2012r2
+ windows_vm: vs2017-win2016
ubuntu_vm: ubuntu-18.04
ci_runner_image: trini/u-boot-gitlab-ci-runner:bionic-20200112-17Jan2020
# Add '-u 0' options for Azure pipelines, otherwise we get "permission
S: Maintained
F: cmd/ab_select.c
F: common/android_ab.c
-F: doc/android/ab.txt
+F: doc/android/ab.rst
F: include/android_ab.h
F: test/py/tests/test_android/test_ab.py
S: Maintained
F: cmd/avb.c
F: common/avb_verify.c
-F: doc/android/avb2.txt
+F: doc/android/avb2.rst
F: include/avb_verify.h
F: lib/libavb/
F: test/py/tests/test_android/test_avb.py
&wkup_i2c0 {
u-boot,dm-spl;
};
+
+&main_i2c0 {
+ u-boot,dm-spl;
+};
+
+&main_i2c0_pins_default {
+ u-boot,dm-spl;
+};
+
+&exp2 {
+ u-boot,dm-spl;
+};
J721E_IOPAD(0x214, PIN_OUTPUT, 4) /* (V4) MCAN1_TX.USB1_DRVVBUS */
>;
};
+
+ main_i2c0_pins_default: main-i2c0-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x220, PIN_INPUT_PULLUP, 0) /* (AC5) I2C0_SCL */
+ J721E_IOPAD(0x224, PIN_INPUT_PULLUP, 0) /* (AA5) I2C0_SDA */
+ >;
+ };
};
&wkup_pmx0 {
pinctrl-0 = <&wkup_i2c0_pins_default>;
clock-frequency = <400000>;
};
+
+&main_i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c0_pins_default>;
+ clock-frequency = <400000>;
+
+ exp1: gpio@20 {
+ compatible = "ti,tca6416";
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ exp2: gpio@22 {
+ compatible = "ti,tca6424";
+ reg = <0x22>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+};
clock-names = "fclk";
};
+ main_gpio0: gpio@600000 {
+ compatible = "ti,j721e-gpio", "ti,keystone-gpio";
+ reg = <0x0 0x00600000 0x0 0x100>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <105 0 IRQ_TYPE_EDGE_RISING>,
+ <105 1 IRQ_TYPE_EDGE_RISING>,
+ <105 2 IRQ_TYPE_EDGE_RISING>,
+ <105 3 IRQ_TYPE_EDGE_RISING>,
+ <105 4 IRQ_TYPE_EDGE_RISING>,
+ <105 5 IRQ_TYPE_EDGE_RISING>,
+ <105 6 IRQ_TYPE_EDGE_RISING>,
+ <105 7 IRQ_TYPE_EDGE_RISING>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ ti,ngpio = <128>;
+ ti,davinci-gpio-unbanked = <0>;
+ power-domains = <&k3_pds 105 TI_SCI_PD_EXCLUSIVE>;
+ clocks = <&k3_clks 105 0>;
+ clock-names = "gpio";
+ };
+
main_sdhci0: sdhci@4f80000 {
compatible = "ti,j721e-sdhci-8bit";
reg = <0x0 0x4f80000 0x0 0x1000>, <0x0 0x4f88000 0x0 0x400>;
dma-coherent;
};
};
+
+ main_i2c0: i2c@2000000 {
+ compatible = "ti,j721e-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2000000 0x0 0x100>;
+ interrupts = <GIC_SPI 200 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 187 0>;
+ power-domains = <&k3_pds 187 TI_SCI_PD_EXCLUSIVE>;
+ };
+
+ main_i2c1: i2c@2010000 {
+ compatible = "ti,j721e-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2010000 0x0 0x100>;
+ interrupts = <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 188 0>;
+ power-domains = <&k3_pds 188 TI_SCI_PD_EXCLUSIVE>;
+ };
+
+ main_i2c2: i2c@2020000 {
+ compatible = "ti,j721e-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2020000 0x0 0x100>;
+ interrupts = <GIC_SPI 202 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 189 0>;
+ power-domains = <&k3_pds 189 TI_SCI_PD_EXCLUSIVE>;
+ };
+
+ main_i2c3: i2c@2030000 {
+ compatible = "ti,j721e-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2030000 0x0 0x100>;
+ interrupts = <GIC_SPI 203 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 190 0>;
+ power-domains = <&k3_pds 190 TI_SCI_PD_EXCLUSIVE>;
+ };
+
+ main_i2c4: i2c@2040000 {
+ compatible = "ti,j721e-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2040000 0x0 0x100>;
+ interrupts = <GIC_SPI 204 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 191 0>;
+ power-domains = <&k3_pds 191 TI_SCI_PD_EXCLUSIVE>;
+ };
+
+ main_i2c5: i2c@2050000 {
+ compatible = "ti,j721e-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2050000 0x0 0x100>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 192 0>;
+ power-domains = <&k3_pds 192 TI_SCI_PD_EXCLUSIVE>;
+ };
+
+ main_i2c6: i2c@2060000 {
+ compatible = "ti,j721e-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x2060000 0x0 0x100>;
+ interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 193 0>;
+ power-domains = <&k3_pds 193 TI_SCI_PD_EXCLUSIVE>;
+ };
};
assigned-clock-rates = <250000000>;
};
};
+
+ mcu_i2c0: i2c@40b00000 {
+ compatible = "ti,j721e-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x40b00000 0x0 0x100>;
+ interrupts = <GIC_SPI 852 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 194 0>;
+ power-domains = <&k3_pds 194 TI_SCI_PD_EXCLUSIVE>;
+ };
+
+ mcu_i2c1: i2c@40b10000 {
+ compatible = "ti,j721e-i2c", "ti,omap4-i2c";
+ reg = <0x0 0x40b10000 0x0 0x100>;
+ interrupts = <GIC_SPI 853 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clock-names = "fck";
+ clocks = <&k3_clks 195 0>;
+ power-domains = <&k3_pds 195 TI_SCI_PD_EXCLUSIVE>;
+ };
};
clock-frequency = <200000000>;
u-boot,dm-spl;
};
+
+ clk_19_2mhz: dummy_clock {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <19200000>;
+ u-boot,dm-spl;
+ };
};
&cbass_mcu_wakeup {
J721E_IOPAD(0x25c, PIN_INPUT, 0) /* (R28) MMC1_SDWP */
>;
};
+
+ main_i2c0_pins_default: main-i2c0-pins-default {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x220, PIN_INPUT_PULLUP, 0) /* (AC5) I2C0_SCL */
+ J721E_IOPAD(0x224, PIN_INPUT_PULLUP, 0) /* (AA5) I2C0_SDA */
+ >;
+ };
};
&wkup_uart0 {
u-boot,dm-spl;
};
+&usbss0 {
+ /delete-property/ power-domains;
+ /delete-property/ assigned-clocks;
+ /delete-property/ assigned-clock-parents;
+ clocks = <&clk_19_2mhz>;
+ clock-names = "usb2_refclk";
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_usbss0_pins_default>;
+ ti,vbus-divider;
+};
+
+&main_i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c0_pins_default>;
+ clock-frequency = <400000>;
+
+ exp1: gpio@20 {
+ compatible = "ti,tca6416";
+ reg = <0x20>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ exp2: gpio@22 {
+ compatible = "ti,tca6424";
+ reg = <0x22>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+};
+
#include "k3-j721e-common-proc-board-u-boot.dtsi"
serial9 = &main_uart7;
serial10 = &main_uart8;
serial11 = &main_uart9;
+ i2c0 = &wkup_i2c0;
+ i2c1 = &mcu_i2c0;
+ i2c2 = &mcu_i2c1;
+ i2c3 = &main_i2c0;
+ i2c4 = &main_i2c1;
+ i2c5 = &main_i2c2;
+ i2c6 = &main_i2c3;
+ i2c7 = &main_i2c4;
+ i2c8 = &main_i2c5;
+ i2c9 = &main_i2c6;
};
chosen { };
.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
PTE_BLOCK_INNER_SHARE
}, {
- .virt = 0xfe000000UL,
- .phys = 0xfe000000UL,
- .size = 0x01800000UL,
+ .virt = 0xfc000000UL,
+ .phys = 0xfc000000UL,
+ .size = 0x03800000UL,
.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
PTE_BLOCK_NON_SHARE |
PTE_BLOCK_PXN | PTE_BLOCK_UXN
/* With BootMode B = 1 */
#define BOOT_DEVICE_MMC2 0x10
#define BOOT_DEVICE_MMC1 0x11
-#define BOOT_DEVICE_USB 0x12
+#define BOOT_DEVICE_DFU 0x12
#define BOOT_DEVICE_UFS 0x13
#define BOOT_DEVIE_GPMC 0x14
#define BOOT_DEVICE_PCIE 0x15
#include <malloc.h>
#include <remoteproc.h>
#include <linux/soc/ti/ti_sci_protocol.h>
+#include <g_dnl.h>
+#include <usb.h>
+#include <dfu.h>
+
#include <asm/arch/sys_proto.h>
#include "common.h"
ret);
}
+#if CONFIG_IS_ENABLED(DFU)
+static int k3_sysfw_dfu_download(void *addr)
+{
+ char dfu_str[50];
+ int ret;
+
+ sprintf(dfu_str, "sysfw.itb ram 0x%p 0x%x", addr,
+ CONFIG_K3_SYSFW_IMAGE_SIZE_MAX);
+ ret = dfu_config_entities(dfu_str, "ram", "0");
+ if (ret) {
+ dfu_free_entities();
+ goto exit;
+ }
+
+ run_usb_dnl_gadget(0, "usb_dnl_dfu");
+exit:
+ dfu_free_entities();
+ return ret;
+}
+#endif
+
void k3_sysfw_loader(void (*config_pm_done_callback)(void))
{
struct spl_image_info spl_image = { 0 };
#endif
ret = spl_ymodem_load_image(&spl_image, &bootdev);
break;
+#endif
+#if CONFIG_IS_ENABLED(DFU)
+ case BOOT_DEVICE_DFU:
+ ret = k3_sysfw_dfu_download(sysfw_load_address);
+ break;
#endif
default:
panic("Loading SYSFW image from device %u not supported!\n",
hex
default 0x10000
+config HAVE_ITSS
+ bool "Enable ITSS"
+ help
+ Select this to include the driver for the Interrupt Timer
+ Subsystem (ITSS) which is found on several Intel devices.
+
menu "System tables"
depends on !EFI && !SYS_COREBOOT
imply HAVE_X86_FIT
imply INTEL_GPIO
imply SMP
+ imply HAVE_ITSS
if INTEL_APOLLOLAKE
endif
obj-y += hostbridge.o
-obj-y += itss.o
obj-y += lpc.o
obj-y += p2sb.o
obj-y += pch.o
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Something to do with Interrupts, but I don't know what ITSS stands for
- *
- * Copyright (C) 2017 Intel Corporation.
- * Copyright (C) 2017 Siemens AG
- * Copyright 2019 Google LLC
- *
- * Taken from coreboot itss.c
- */
-
-#include <common.h>
-#include <dm.h>
-#include <dt-structs.h>
-#include <irq.h>
-#include <p2sb.h>
-#include <spl.h>
-#include <asm/arch/itss.h>
-
-struct apl_itss_platdata {
-#if CONFIG_IS_ENABLED(OF_PLATDATA)
- /* Put this first since driver model will copy the data here */
- struct dtd_intel_apl_itss dtplat;
-#endif
-};
-
-/* struct pmc_route - Routing for PMC to GPIO */
-struct pmc_route {
- u32 pmc;
- u32 gpio;
-};
-
-struct apl_itss_priv {
- struct pmc_route *route;
- uint route_count;
- u32 irq_snapshot[NUM_IPC_REGS];
-};
-
-static int apl_set_polarity(struct udevice *dev, uint irq, bool active_low)
-{
- u32 mask;
- uint reg;
-
- if (irq > ITSS_MAX_IRQ)
- return -EINVAL;
-
- reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * (irq / IRQS_PER_IPC);
- mask = 1 << (irq % IRQS_PER_IPC);
-
- pcr_clrsetbits32(dev, reg, mask, active_low ? mask : 0);
-
- return 0;
-}
-
-#ifndef CONFIG_TPL_BUILD
-static int apl_snapshot_polarities(struct udevice *dev)
-{
- struct apl_itss_priv *priv = dev_get_priv(dev);
- const int start = GPIO_IRQ_START;
- const int end = GPIO_IRQ_END;
- int reg_start;
- int reg_end;
- int i;
-
- reg_start = start / IRQS_PER_IPC;
- reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
-
- for (i = reg_start; i < reg_end; i++) {
- uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
-
- priv->irq_snapshot[i] = pcr_read32(dev, reg);
- }
-
- return 0;
-}
-
-static void show_polarities(struct udevice *dev, const char *msg)
-{
- int i;
-
- log_info("ITSS IRQ Polarities %s:\n", msg);
- for (i = 0; i < NUM_IPC_REGS; i++) {
- uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
-
- log_info("IPC%d: 0x%08x\n", i, pcr_read32(dev, reg));
- }
-}
-
-static int apl_restore_polarities(struct udevice *dev)
-{
- struct apl_itss_priv *priv = dev_get_priv(dev);
- const int start = GPIO_IRQ_START;
- const int end = GPIO_IRQ_END;
- int reg_start;
- int reg_end;
- int i;
-
- show_polarities(dev, "Before");
-
- reg_start = start / IRQS_PER_IPC;
- reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
-
- for (i = reg_start; i < reg_end; i++) {
- u32 mask;
- u16 reg;
- int irq_start;
- int irq_end;
-
- irq_start = i * IRQS_PER_IPC;
- irq_end = min(irq_start + IRQS_PER_IPC - 1, ITSS_MAX_IRQ);
-
- if (start > irq_end)
- continue;
- if (end < irq_start)
- break;
-
- /* Track bits within the bounds of of the register */
- irq_start = max(start, irq_start) % IRQS_PER_IPC;
- irq_end = min(end, irq_end) % IRQS_PER_IPC;
-
- /* Create bitmask of the inclusive range of start and end */
- mask = (((1U << irq_end) - 1) | (1U << irq_end));
- mask &= ~((1U << irq_start) - 1);
-
- reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
- pcr_clrsetbits32(dev, reg, mask, mask & priv->irq_snapshot[i]);
- }
-
- show_polarities(dev, "After");
-
- return 0;
-}
-#endif
-
-static int apl_route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
-{
- struct apl_itss_priv *priv = dev_get_priv(dev);
- struct pmc_route *route;
- int i;
-
- for (i = 0, route = priv->route; i < priv->route_count; i++, route++) {
- if (pmc_gpe_num == route->pmc)
- return route->gpio;
- }
-
- return -ENOENT;
-}
-
-static int apl_itss_ofdata_to_platdata(struct udevice *dev)
-{
- struct apl_itss_priv *priv = dev_get_priv(dev);
- int ret;
-
-#if CONFIG_IS_ENABLED(OF_PLATDATA)
- struct apl_itss_platdata *plat = dev_get_platdata(dev);
- struct dtd_intel_apl_itss *dtplat = &plat->dtplat;
-
- /*
- * It would be nice to do this in the bind() method, but with
- * of-platdata binding happens in the order that DM finds things in the
- * linker list (i.e. alphabetical order by driver name). So the GPIO
- * device may well be bound before its parent (p2sb), and this call
- * will fail if p2sb is not bound yet.
- *
- * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc
- */
- ret = p2sb_set_port_id(dev, dtplat->intel_p2sb_port_id);
- if (ret)
- return log_msg_ret("Could not set port id", ret);
- priv->route = (struct pmc_route *)dtplat->intel_pmc_routes;
- priv->route_count = ARRAY_SIZE(dtplat->intel_pmc_routes) /
- sizeof(struct pmc_route);
-#else
- int size;
-
- size = dev_read_size(dev, "intel,pmc-routes");
- if (size < 0)
- return size;
- priv->route = malloc(size);
- if (!priv->route)
- return -ENOMEM;
- ret = dev_read_u32_array(dev, "intel,pmc-routes", (u32 *)priv->route,
- size / sizeof(fdt32_t));
- if (ret)
- return log_msg_ret("Cannot read pmc-routes", ret);
- priv->route_count = size / sizeof(struct pmc_route);
-#endif
-
- return 0;
-}
-
-static const struct irq_ops apl_itss_ops = {
- .route_pmc_gpio_gpe = apl_route_pmc_gpio_gpe,
- .set_polarity = apl_set_polarity,
-#ifndef CONFIG_TPL_BUILD
- .snapshot_polarities = apl_snapshot_polarities,
- .restore_polarities = apl_restore_polarities,
-#endif
-};
-
-static const struct udevice_id apl_itss_ids[] = {
- { .compatible = "intel,apl-itss"},
- { }
-};
-
-U_BOOT_DRIVER(apl_itss_drv) = {
- .name = "intel_apl_itss",
- .id = UCLASS_IRQ,
- .of_match = apl_itss_ids,
- .ops = &apl_itss_ops,
- .ofdata_to_platdata = apl_itss_ofdata_to_platdata,
- .platdata_auto_alloc_size = sizeof(struct apl_itss_platdata),
- .priv_auto_alloc_size = sizeof(struct apl_itss_priv),
-};
/* DS: data, read/write, 4 GB, base 0 */
gdt_addr[X86_GDT_ENTRY_32BIT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff);
- /* FS: data, read/write, 4 GB, base (Global Data Pointer) */
+ /*
+ * FS: data, read/write, sizeof (Global Data Pointer),
+ * base (Global Data Pointer)
+ */
new_gd->arch.gd_addr = new_gd;
- gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0xc093,
- (ulong)&new_gd->arch.gd_addr, 0xfffff);
+ gdt_addr[X86_GDT_ENTRY_32BIT_FS] = GDT_ENTRY(0x8093,
+ (ulong)&new_gd->arch.gd_addr,
+ sizeof(new_gd->arch.gd_addr) - 1);
/* 16-bit CS: code, read/execute, 64 kB, base 0 */
gdt_addr[X86_GDT_ENTRY_16BIT_CS] = GDT_ENTRY(0x009b, 0, 0x0ffff);
endif
endif
obj-y += pch.o
+obj-$(CONFIG_HAVE_ITSS) += itss.o
ifdef CONFIG_SPL
ifndef CONFIG_SPL_BUILD
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Interrupt Timer Subsystem
+ *
+ * Copyright (C) 2017 Intel Corporation.
+ * Copyright (C) 2017 Siemens AG
+ * Copyright 2019 Google LLC
+ *
+ * Taken from coreboot itss.c
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+#include <irq.h>
+#include <p2sb.h>
+#include <spl.h>
+#include <asm/itss.h>
+
+struct itss_platdata {
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ /* Put this first since driver model will copy the data here */
+ struct dtd_intel_itss dtplat;
+#endif
+};
+
+/* struct pmc_route - Routing for PMC to GPIO */
+struct pmc_route {
+ u32 pmc;
+ u32 gpio;
+};
+
+struct itss_priv {
+ struct pmc_route *route;
+ uint route_count;
+ u32 irq_snapshot[NUM_IPC_REGS];
+};
+
+static int set_polarity(struct udevice *dev, uint irq, bool active_low)
+{
+ u32 mask;
+ uint reg;
+
+ if (irq > ITSS_MAX_IRQ)
+ return -EINVAL;
+
+ reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * (irq / IRQS_PER_IPC);
+ mask = 1 << (irq % IRQS_PER_IPC);
+
+ pcr_clrsetbits32(dev, reg, mask, active_low ? mask : 0);
+
+ return 0;
+}
+
+#ifndef CONFIG_TPL_BUILD
+static int snapshot_polarities(struct udevice *dev)
+{
+ struct itss_priv *priv = dev_get_priv(dev);
+ const int start = GPIO_IRQ_START;
+ const int end = GPIO_IRQ_END;
+ int reg_start;
+ int reg_end;
+ int i;
+
+ reg_start = start / IRQS_PER_IPC;
+ reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
+
+ for (i = reg_start; i < reg_end; i++) {
+ uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
+
+ priv->irq_snapshot[i] = pcr_read32(dev, reg);
+ }
+
+ return 0;
+}
+
+static void show_polarities(struct udevice *dev, const char *msg)
+{
+ int i;
+
+ log_info("ITSS IRQ Polarities %s:\n", msg);
+ for (i = 0; i < NUM_IPC_REGS; i++) {
+ uint reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
+
+ log_info("IPC%d: 0x%08x\n", i, pcr_read32(dev, reg));
+ }
+}
+
+static int restore_polarities(struct udevice *dev)
+{
+ struct itss_priv *priv = dev_get_priv(dev);
+ const int start = GPIO_IRQ_START;
+ const int end = GPIO_IRQ_END;
+ int reg_start;
+ int reg_end;
+ int i;
+
+ show_polarities(dev, "Before");
+
+ reg_start = start / IRQS_PER_IPC;
+ reg_end = (end + IRQS_PER_IPC - 1) / IRQS_PER_IPC;
+
+ for (i = reg_start; i < reg_end; i++) {
+ u32 mask;
+ u16 reg;
+ int irq_start;
+ int irq_end;
+
+ irq_start = i * IRQS_PER_IPC;
+ irq_end = min(irq_start + IRQS_PER_IPC - 1, ITSS_MAX_IRQ);
+
+ if (start > irq_end)
+ continue;
+ if (end < irq_start)
+ break;
+
+ /* Track bits within the bounds of of the register */
+ irq_start = max(start, irq_start) % IRQS_PER_IPC;
+ irq_end = min(end, irq_end) % IRQS_PER_IPC;
+
+ /* Create bitmask of the inclusive range of start and end */
+ mask = (((1U << irq_end) - 1) | (1U << irq_end));
+ mask &= ~((1U << irq_start) - 1);
+
+ reg = PCR_ITSS_IPC0_CONF + sizeof(u32) * i;
+ pcr_clrsetbits32(dev, reg, mask, mask & priv->irq_snapshot[i]);
+ }
+
+ show_polarities(dev, "After");
+
+ return 0;
+}
+#endif
+
+static int route_pmc_gpio_gpe(struct udevice *dev, uint pmc_gpe_num)
+{
+ struct itss_priv *priv = dev_get_priv(dev);
+ struct pmc_route *route;
+ int i;
+
+ for (i = 0, route = priv->route; i < priv->route_count; i++, route++) {
+ if (pmc_gpe_num == route->pmc)
+ return route->gpio;
+ }
+
+ return -ENOENT;
+}
+
+static int itss_ofdata_to_platdata(struct udevice *dev)
+{
+ struct itss_priv *priv = dev_get_priv(dev);
+ int ret;
+
+#if CONFIG_IS_ENABLED(OF_PLATDATA)
+ struct itss_platdata *plat = dev_get_platdata(dev);
+ struct dtd_intel_itss *dtplat = &plat->dtplat;
+
+ /*
+ * It would be nice to do this in the bind() method, but with
+ * of-platdata binding happens in the order that DM finds things in the
+ * linker list (i.e. alphabetical order by driver name). So the GPIO
+ * device may well be bound before its parent (p2sb), and this call
+ * will fail if p2sb is not bound yet.
+ *
+ * TODO(sjg@chromium.org): Add a parent pointer to child devices in dtoc
+ */
+ ret = p2sb_set_port_id(dev, dtplat->intel_p2sb_port_id);
+ if (ret)
+ return log_msg_ret("Could not set port id", ret);
+ priv->route = (struct pmc_route *)dtplat->intel_pmc_routes;
+ priv->route_count = ARRAY_SIZE(dtplat->intel_pmc_routes) /
+ sizeof(struct pmc_route);
+#else
+ int size;
+
+ size = dev_read_size(dev, "intel,pmc-routes");
+ if (size < 0)
+ return size;
+ priv->route = malloc(size);
+ if (!priv->route)
+ return -ENOMEM;
+ ret = dev_read_u32_array(dev, "intel,pmc-routes", (u32 *)priv->route,
+ size / sizeof(fdt32_t));
+ if (ret)
+ return log_msg_ret("Cannot read pmc-routes", ret);
+ priv->route_count = size / sizeof(struct pmc_route);
+#endif
+
+ return 0;
+}
+
+static const struct irq_ops itss_ops = {
+ .route_pmc_gpio_gpe = route_pmc_gpio_gpe,
+ .set_polarity = set_polarity,
+#ifndef CONFIG_TPL_BUILD
+ .snapshot_polarities = snapshot_polarities,
+ .restore_polarities = restore_polarities,
+#endif
+};
+
+static const struct udevice_id itss_ids[] = {
+ { .compatible = "intel,itss"},
+ { }
+};
+
+U_BOOT_DRIVER(itss_drv) = {
+ .name = "intel_itss",
+ .id = UCLASS_IRQ,
+ .of_match = itss_ids,
+ .ops = &itss_ops,
+ .ofdata_to_platdata = itss_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct itss_platdata),
+ .priv_auto_alloc_size = sizeof(struct itss_priv),
+};
data->stride,
data->clk);
- /*
- * The data->type provides port io or mmio access type info,
- * but the access type will be controlled by
- * CONFIG_SYS_NS16550_PORT_MAPPED or CONFIG_SYS_NS16550_MEM32.
- *
- * TBD: ns16550 access type configuration in runtime.
- * ex) plat->access_type = data->type
- */
plat->base = data->base;
/* ns16550 uses reg_shift, then covert stride to shift */
plat->reg_shift = data->stride >> 1;
+ plat->reg_width = data->stride;
plat->clock = data->clk;
+ plat->fcr = UART_FCR_DEFVAL;
+ plat->flags = 0;
+ if (data->type == 1)
+ plat->flags |= NS16550_FLAG_IO;
return 0;
}
movl %cr0, %eax
orl $(X86_CR0_NW | X86_CR0_CD), %eax
movl %eax, %cr0
- wbinvd
+ invd
/*
* Zero the BIST (Built-In Self Test) value since we don't have it.
movl %cr0, %eax
orl $(X86_CR0_NW | X86_CR0_CD), %eax
movl %eax, %cr0
- wbinvd
+ invd
/* load the temporary Global Descriptor Table */
data32 cs lidt idt_ptr
itss {
u-boot,dm-pre-reloc;
- compatible = "intel,apl-itss";
+ compatible = "intel,itss";
intel,p2sb-port-id = <PID_ITSS>;
intel,pmc-routes = <
PMC_GPE_SW_31_0 GPIO_GPE_SW_31_0
/dts-v1/;
/include/ "skeleton.dtsi"
-/include/ "serial.dtsi"
/include/ "keyboard.dtsi"
/include/ "pcspkr.dtsi"
/include/ "reset.dtsi"
u-boot,dm-pre-reloc;
};
+ serial: serial {
+ u-boot,dm-pre-reloc;
+ compatible = "coreboot-serial";
+ };
+
coreboot-fb {
compatible = "coreboot-fb";
};
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Copyright (C) 2017 Intel Corporation.
- * Copyright 2019 Google LLC
- *
- * Modified from coreboot itss.h
- */
-
-#ifndef _ASM_ARCH_ITSS_H
-#define _ASM_ARCH_ITSS_H
-
-#define GPIO_IRQ_START 50
-#define GPIO_IRQ_END ITSS_MAX_IRQ
-
-#define ITSS_MAX_IRQ 119
-#define IRQS_PER_IPC 32
-#define NUM_IPC_REGS ((ITSS_MAX_IRQ + IRQS_PER_IPC - 1) / IRQS_PER_IPC)
-
-/* Max PXRC registers in ITSS */
-#define MAX_PXRC_CONFIG (PCR_ITSS_PIRQH_ROUT - PCR_ITSS_PIRQA_ROUT + 1)
-
-/* PIRQA Routing Control Register */
-#define PCR_ITSS_PIRQA_ROUT 0x3100
-/* PIRQB Routing Control Register */
-#define PCR_ITSS_PIRQB_ROUT 0x3101
-/* PIRQC Routing Control Register */
-#define PCR_ITSS_PIRQC_ROUT 0x3102
-/* PIRQD Routing Control Register */
-#define PCR_ITSS_PIRQD_ROUT 0x3103
-/* PIRQE Routing Control Register */
-#define PCR_ITSS_PIRQE_ROUT 0x3104
-/* PIRQF Routing Control Register */
-#define PCR_ITSS_PIRQF_ROUT 0x3105
-/* PIRQG Routing Control Register */
-#define PCR_ITSS_PIRQG_ROUT 0x3106
-/* PIRQH Routing Control Register */
-#define PCR_ITSS_PIRQH_ROUT 0x3107
-/* ITSS Interrupt polarity control */
-#define PCR_ITSS_IPC0_CONF 0x3200
-/* ITSS Power reduction control */
-#define PCR_ITSS_ITSSPRC 0x3300
-
-#endif /* _ASM_ARCH_ITSS_H */
u32 type;
u32 baseaddr;
u32 baud;
+ u32 regwidth;
+
+ /*
+ * Crystal or input frequency to the chip containing the UART.
+ * Provide the board specific details to allow the payload to
+ * initialize the chip containing the UART and make independent
+ * decisions as to which dividers to select and their values
+ * to eventually arrive at the desired console baud-rate.
+ */
+ u32 input_hertz;
+
+ /*
+ * UART PCI address: bus, device, function
+ * 1 << 31 - Valid bit, PCI UART in use
+ * Bus << 20
+ * Device << 15
+ * Function << 12
+ */
+ u32 uart_pci_addr;
};
#define CB_TAG_CONSOLE 0x0010
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Interrupt Timer Subsystem
+ *
+ * Copyright (C) 2017 Intel Corporation.
+ * Copyright 2019 Google LLC
+ *
+ * Modified from coreboot itss.h
+ */
+
+#ifndef _ASM_ARCH_ITSS_H
+#define _ASM_ARCH_ITSS_H
+
+#define GPIO_IRQ_START 50
+#define GPIO_IRQ_END ITSS_MAX_IRQ
+
+#define ITSS_MAX_IRQ 119
+#define IRQS_PER_IPC 32
+#define NUM_IPC_REGS ((ITSS_MAX_IRQ + IRQS_PER_IPC - 1) / IRQS_PER_IPC)
+
+/* Max PXRC registers in ITSS */
+#define MAX_PXRC_CONFIG (PCR_ITSS_PIRQH_ROUT - PCR_ITSS_PIRQA_ROUT + 1)
+
+/* PIRQA Routing Control Register */
+#define PCR_ITSS_PIRQA_ROUT 0x3100
+/* PIRQB Routing Control Register */
+#define PCR_ITSS_PIRQB_ROUT 0x3101
+/* PIRQC Routing Control Register */
+#define PCR_ITSS_PIRQC_ROUT 0x3102
+/* PIRQD Routing Control Register */
+#define PCR_ITSS_PIRQD_ROUT 0x3103
+/* PIRQE Routing Control Register */
+#define PCR_ITSS_PIRQE_ROUT 0x3104
+/* PIRQF Routing Control Register */
+#define PCR_ITSS_PIRQF_ROUT 0x3105
+/* PIRQG Routing Control Register */
+#define PCR_ITSS_PIRQG_ROUT 0x3106
+/* PIRQH Routing Control Register */
+#define PCR_ITSS_PIRQH_ROUT 0x3107
+/* ITSS Interrupt polarity control */
+#define PCR_ITSS_IPC0_CONF 0x3200
+/* ITSS Power reduction control */
+#define PCR_ITSS_ITSSPRC 0x3300
+
+#endif /* _ASM_ARCH_ITSS_H */
files should be merged in one dtb further, which needs to be passed to
the kernel, as part of a boot process.
+config CMD_ABOOTIMG
+ bool "abootimg"
+ depends on ANDROID_BOOT_IMAGE
+ help
+ Android Boot Image manipulation commands. Allows one to extract
+ images contained in boot.img, like kernel, ramdisk, dtb, etc, and
+ obtain corresponding meta-information from boot.img.
+
+ See doc/android/boot-image.rst for details.
+
config CMD_ELF
bool "bootelf, bootvx"
default y
Android devices. Fastboot requires either the network stack
enabled or support for acting as a USB device.
- See doc/android/fastboot.txt for more information.
+ See doc/android/fastboot.rst for more information.
config CMD_FLASH
bool "flinfo, erase, protect"
obj-$(CONFIG_CMD_DIAG) += diag.o
endif
obj-$(CONFIG_CMD_ADTIMG) += adtimg.o
+obj-$(CONFIG_CMD_ABOOTIMG) += abootimg.o
obj-$(CONFIG_CMD_ECHO) += echo.o
obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o
obj-$(CONFIG_CMD_EEPROM) += eeprom.o
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2020
+ * Sam Protsenko <joe.skb7@gmail.com>
+ */
+
+#include <android_image.h>
+#include <common.h>
+#include <mapmem.h>
+
+#define abootimg_addr() \
+ (_abootimg_addr == -1 ? image_load_addr : _abootimg_addr)
+
+/* Please use abootimg_addr() macro to obtain the boot image address */
+static ulong _abootimg_addr = -1;
+
+static int abootimg_get_ver(int argc, char * const argv[])
+{
+ const struct andr_img_hdr *hdr;
+ int res = CMD_RET_SUCCESS;
+
+ if (argc > 1)
+ return CMD_RET_USAGE;
+
+ hdr = map_sysmem(abootimg_addr(), sizeof(*hdr));
+ if (android_image_check_header(hdr)) {
+ printf("Error: Boot Image header is incorrect\n");
+ res = CMD_RET_FAILURE;
+ goto exit;
+ }
+
+ if (argc == 0)
+ printf("%u\n", hdr->header_version);
+ else
+ env_set_ulong(argv[0], hdr->header_version);
+
+exit:
+ unmap_sysmem(hdr);
+ return res;
+}
+
+static int abootimg_get_recovery_dtbo(int argc, char * const argv[])
+{
+ ulong addr;
+ u32 size;
+
+ if (argc > 2)
+ return CMD_RET_USAGE;
+
+ if (!android_image_get_dtbo(abootimg_addr(), &addr, &size))
+ return CMD_RET_FAILURE;
+
+ if (argc == 0) {
+ printf("%lx\n", addr);
+ } else {
+ env_set_hex(argv[0], addr);
+ if (argc == 2)
+ env_set_hex(argv[1], size);
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int abootimg_get_dtb_load_addr(int argc, char * const argv[])
+{
+ const struct andr_img_hdr *hdr;
+ int res = CMD_RET_SUCCESS;
+
+ if (argc > 1)
+ return CMD_RET_USAGE;
+
+ hdr = map_sysmem(abootimg_addr(), sizeof(*hdr));
+ if (android_image_check_header(hdr)) {
+ printf("Error: Boot Image header is incorrect\n");
+ res = CMD_RET_FAILURE;
+ goto exit;
+ }
+
+ if (hdr->header_version < 2) {
+ printf("Error: header_version must be >= 2 for this\n");
+ res = CMD_RET_FAILURE;
+ goto exit;
+ }
+
+ if (argc == 0)
+ printf("%lx\n", (ulong)hdr->dtb_addr);
+ else
+ env_set_hex(argv[0], (ulong)hdr->dtb_addr);
+
+exit:
+ unmap_sysmem(hdr);
+ return res;
+}
+
+static int abootimg_get_dtb_by_index(int argc, char * const argv[])
+{
+ const char *index_str;
+ u32 num;
+ char *endp;
+ ulong addr;
+ u32 size;
+
+ if (argc < 1 || argc > 3)
+ return CMD_RET_USAGE;
+
+ index_str = argv[0] + strlen("--index=");
+ if (index_str[0] == '\0') {
+ printf("Error: Wrong index num\n");
+ return CMD_RET_FAILURE;
+ }
+
+ num = simple_strtoul(index_str, &endp, 0);
+ if (*endp != '\0') {
+ printf("Error: Wrong index num\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (!android_image_get_dtb_by_index(abootimg_addr(), num,
+ &addr, &size)) {
+ return CMD_RET_FAILURE;
+ }
+
+ if (argc == 1) {
+ printf("%lx\n", addr);
+ } else {
+ if (env_set_hex(argv[1], addr)) {
+ printf("Error: Can't set [addr_var]\n");
+ return CMD_RET_FAILURE;
+ }
+
+ if (argc == 3) {
+ if (env_set_hex(argv[2], size)) {
+ printf("Error: Can't set [size_var]\n");
+ return CMD_RET_FAILURE;
+ }
+ }
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static int abootimg_get_dtb(int argc, char * const argv[])
+{
+ if (argc < 1)
+ return CMD_RET_USAGE;
+
+ if (strstr(argv[0], "--index="))
+ return abootimg_get_dtb_by_index(argc, argv);
+
+ return CMD_RET_USAGE;
+}
+
+static int do_abootimg_addr(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ char *endp;
+ ulong img_addr;
+
+ if (argc != 2)
+ return CMD_RET_USAGE;
+
+ img_addr = simple_strtoul(argv[1], &endp, 16);
+ if (*endp != '\0') {
+ printf("Error: Wrong image address\n");
+ return CMD_RET_FAILURE;
+ }
+
+ _abootimg_addr = img_addr;
+ return CMD_RET_SUCCESS;
+}
+
+static int do_abootimg_get(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ const char *param;
+
+ if (argc < 2)
+ return CMD_RET_USAGE;
+
+ param = argv[1];
+ argc -= 2;
+ argv += 2;
+ if (!strcmp(param, "ver"))
+ return abootimg_get_ver(argc, argv);
+ else if (!strcmp(param, "recovery_dtbo"))
+ return abootimg_get_recovery_dtbo(argc, argv);
+ else if (!strcmp(param, "dtb_load_addr"))
+ return abootimg_get_dtb_load_addr(argc, argv);
+ else if (!strcmp(param, "dtb"))
+ return abootimg_get_dtb(argc, argv);
+
+ return CMD_RET_USAGE;
+}
+
+static int do_abootimg_dump(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ if (argc != 2)
+ return CMD_RET_USAGE;
+
+ if (!strcmp(argv[1], "dtb")) {
+ if (android_image_print_dtb_contents(abootimg_addr()))
+ return CMD_RET_FAILURE;
+ } else {
+ return CMD_RET_USAGE;
+ }
+
+ return CMD_RET_SUCCESS;
+}
+
+static cmd_tbl_t cmd_abootimg_sub[] = {
+ U_BOOT_CMD_MKENT(addr, 2, 1, do_abootimg_addr, "", ""),
+ U_BOOT_CMD_MKENT(dump, 2, 1, do_abootimg_dump, "", ""),
+ U_BOOT_CMD_MKENT(get, 5, 1, do_abootimg_get, "", ""),
+};
+
+static int do_abootimg(cmd_tbl_t *cmdtp, int flag, int argc,
+ char * const argv[])
+{
+ cmd_tbl_t *cp;
+
+ cp = find_cmd_tbl(argv[1], cmd_abootimg_sub,
+ ARRAY_SIZE(cmd_abootimg_sub));
+
+ /* Strip off leading 'abootimg' command argument */
+ argc--;
+ argv++;
+
+ if (!cp || argc > cp->maxargs)
+ return CMD_RET_USAGE;
+ if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp))
+ return CMD_RET_SUCCESS;
+
+ return cp->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+ abootimg, CONFIG_SYS_MAXARGS, 0, do_abootimg,
+ "manipulate Android Boot Image",
+ "addr <addr>\n"
+ " - set the address in RAM where boot image is located\n"
+ " ($loadaddr is used by default)\n"
+ "abootimg dump dtb\n"
+ " - print info for all DT blobs in DTB area\n"
+ "abootimg get ver [varname]\n"
+ " - get header version\n"
+ "abootimg get recovery_dtbo [addr_var [size_var]]\n"
+ " - get address and size (hex) of recovery DTBO area in the image\n"
+ " [addr_var]: variable name to contain DTBO area address\n"
+ " [size_var]: variable name to contain DTBO area size\n"
+ "abootimg get dtb_load_addr [varname]\n"
+ " - get load address (hex) of DTB, from image header\n"
+ "abootimg get dtb --index=<num> [addr_var [size_var]]\n"
+ " - get address and size (hex) of DT blob in the image by index\n"
+ " <num>: index number of desired DT blob in DTB area\n"
+ " [addr_var]: variable name to contain DT blob address\n"
+ " [size_var]: variable name to contain DT blob size"
+);
obj-y += image.o
obj-$(CONFIG_ANDROID_AB) += android_ab.o
-obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
+obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o image-android-dt.o
obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += image-fdt.o
obj-$(CONFIG_$(SPL_TPL_)FIT) += image-fit.o
obj-$(CONFIG_$(SPL_)MULTI_DTB_FIT) += boot_fit.o common_fit.o
#include <common.h>
#include <env.h>
#include <image.h>
+#include <image-android-dt.h>
#include <android_image.h>
#include <malloc.h>
#include <errno.h>
#include <asm/unaligned.h>
+#include <mapmem.h>
#define ANDROID_IMAGE_DEFAULT_KERNEL_ADDR 0x10008000
return 0;
}
+/**
+ * android_image_get_dtbo() - Get address and size of recovery DTBO image.
+ * @hdr_addr: Boot image header address
+ * @addr: If not NULL, will contain address of recovery DTBO image
+ * @size: If not NULL, will contain size of recovery DTBO image
+ *
+ * Get the address and size of DTBO image in "Recovery DTBO" area of Android
+ * Boot Image in RAM. The format of this image is Android DTBO (see
+ * corresponding "DTB/DTBO Partitions" AOSP documentation for details). Once
+ * the address is obtained from this function, one can use 'adtimg' U-Boot
+ * command or android_dt_*() functions to extract desired DTBO blob.
+ *
+ * This DTBO (included in boot image) is only needed for non-A/B devices, and it
+ * only can be found in recovery image. On A/B devices we can always rely on
+ * "dtbo" partition. See "Including DTBO in Recovery for Non-A/B Devices" in
+ * AOSP documentation for details.
+ *
+ * Return: true on success or false on error.
+ */
+bool android_image_get_dtbo(ulong hdr_addr, ulong *addr, u32 *size)
+{
+ const struct andr_img_hdr *hdr;
+ ulong dtbo_img_addr;
+ bool ret = true;
+
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ if (android_image_check_header(hdr)) {
+ printf("Error: Boot Image header is incorrect\n");
+ ret = false;
+ goto exit;
+ }
+
+ if (hdr->header_version < 1) {
+ printf("Error: header_version must be >= 1 to get dtbo\n");
+ ret = false;
+ goto exit;
+ }
+
+ if (hdr->recovery_dtbo_size == 0) {
+ printf("Error: recovery_dtbo_size is 0\n");
+ ret = false;
+ goto exit;
+ }
+
+ /* Calculate the address of DTB area in boot image */
+ dtbo_img_addr = hdr_addr;
+ dtbo_img_addr += hdr->page_size;
+ dtbo_img_addr += ALIGN(hdr->kernel_size, hdr->page_size);
+ dtbo_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
+ dtbo_img_addr += ALIGN(hdr->second_size, hdr->page_size);
+
+ if (addr)
+ *addr = dtbo_img_addr;
+ if (size)
+ *size = hdr->recovery_dtbo_size;
+
+exit:
+ unmap_sysmem(hdr);
+ return ret;
+}
+
+/**
+ * android_image_get_dtb_img_addr() - Get the address of DTB area in boot image.
+ * @hdr_addr: Boot image header address
+ * @addr: Will contain the address of DTB area in boot image
+ *
+ * Return: true on success or false on fail.
+ */
+static bool android_image_get_dtb_img_addr(ulong hdr_addr, ulong *addr)
+{
+ const struct andr_img_hdr *hdr;
+ ulong dtb_img_addr;
+ bool ret = true;
+
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ if (android_image_check_header(hdr)) {
+ printf("Error: Boot Image header is incorrect\n");
+ ret = false;
+ goto exit;
+ }
+
+ if (hdr->header_version < 2) {
+ printf("Error: header_version must be >= 2 to get dtb\n");
+ ret = false;
+ goto exit;
+ }
+
+ if (hdr->dtb_size == 0) {
+ printf("Error: dtb_size is 0\n");
+ ret = false;
+ goto exit;
+ }
+
+ /* Calculate the address of DTB area in boot image */
+ dtb_img_addr = hdr_addr;
+ dtb_img_addr += hdr->page_size;
+ dtb_img_addr += ALIGN(hdr->kernel_size, hdr->page_size);
+ dtb_img_addr += ALIGN(hdr->ramdisk_size, hdr->page_size);
+ dtb_img_addr += ALIGN(hdr->second_size, hdr->page_size);
+ dtb_img_addr += ALIGN(hdr->recovery_dtbo_size, hdr->page_size);
+
+ *addr = dtb_img_addr;
+
+exit:
+ unmap_sysmem(hdr);
+ return ret;
+}
+
+/**
+ * android_image_get_dtb_by_index() - Get address and size of blob in DTB area.
+ * @hdr_addr: Boot image header address
+ * @index: Index of desired DTB in DTB area (starting from 0)
+ * @addr: If not NULL, will contain address to specified DTB
+ * @size: If not NULL, will contain size of specified DTB
+ *
+ * Get the address and size of DTB blob by its index in DTB area of Android
+ * Boot Image in RAM.
+ *
+ * Return: true on success or false on error.
+ */
+bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr,
+ u32 *size)
+{
+ const struct andr_img_hdr *hdr;
+ bool res;
+ ulong dtb_img_addr; /* address of DTB part in boot image */
+ u32 dtb_img_size; /* size of DTB payload in boot image */
+ ulong dtb_addr; /* address of DTB blob with specified index */
+ u32 i; /* index iterator */
+
+ res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr);
+ if (!res)
+ return false;
+
+ /* Check if DTB area of boot image is in DTBO format */
+ if (android_dt_check_header(dtb_img_addr)) {
+ return android_dt_get_fdt_by_index(dtb_img_addr, index, addr,
+ size);
+ }
+
+ /* Find out the address of DTB with specified index in concat blobs */
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ dtb_img_size = hdr->dtb_size;
+ unmap_sysmem(hdr);
+ i = 0;
+ dtb_addr = dtb_img_addr;
+ while (dtb_addr < dtb_img_addr + dtb_img_size) {
+ const struct fdt_header *fdt;
+ u32 dtb_size;
+
+ fdt = map_sysmem(dtb_addr, sizeof(*fdt));
+ if (fdt_check_header(fdt) != 0) {
+ unmap_sysmem(fdt);
+ printf("Error: Invalid FDT header for index %u\n", i);
+ return false;
+ }
+
+ dtb_size = fdt_totalsize(fdt);
+ unmap_sysmem(fdt);
+
+ if (i == index) {
+ if (size)
+ *size = dtb_size;
+ if (addr)
+ *addr = dtb_addr;
+ return true;
+ }
+
+ dtb_addr += dtb_size;
+ ++i;
+ }
+
+ printf("Error: Index is out of bounds (%u/%u)\n", index, i);
+ return false;
+}
+
#if !defined(CONFIG_SPL_BUILD)
/**
* android_print_contents - prints out the contents of the Android format image
printf("%sdtb addr: %llx\n", p, hdr->dtb_addr);
}
}
+
+/**
+ * android_image_print_dtb_info - Print info for one DTB blob in DTB area.
+ * @fdt: DTB header
+ * @index: Number of DTB blob in DTB area.
+ *
+ * Return: true on success or false on error.
+ */
+static bool android_image_print_dtb_info(const struct fdt_header *fdt,
+ u32 index)
+{
+ int root_node_off;
+ u32 fdt_size;
+ const char *model;
+ const char *compatible;
+
+ root_node_off = fdt_path_offset(fdt, "/");
+ if (root_node_off < 0) {
+ printf("Error: Root node not found\n");
+ return false;
+ }
+
+ fdt_size = fdt_totalsize(fdt);
+ compatible = fdt_getprop(fdt, root_node_off, "compatible",
+ NULL);
+ model = fdt_getprop(fdt, root_node_off, "model", NULL);
+
+ printf(" - DTB #%u:\n", index);
+ printf(" (DTB)size = %d\n", fdt_size);
+ printf(" (DTB)model = %s\n", model ? model : "(unknown)");
+ printf(" (DTB)compatible = %s\n",
+ compatible ? compatible : "(unknown)");
+
+ return true;
+}
+
+/**
+ * android_image_print_dtb_contents() - Print info for DTB blobs in DTB area.
+ * @hdr_addr: Boot image header address
+ *
+ * DTB payload in Android Boot Image v2+ can be in one of following formats:
+ * 1. Concatenated DTB blobs
+ * 2. Android DTBO format (see CONFIG_CMD_ADTIMG for details)
+ *
+ * This function does next:
+ * 1. Prints out the format used in DTB area
+ * 2. Iterates over all DTB blobs in DTB area and prints out the info for
+ * each blob.
+ *
+ * Return: true on success or false on error.
+ */
+bool android_image_print_dtb_contents(ulong hdr_addr)
+{
+ const struct andr_img_hdr *hdr;
+ bool res;
+ ulong dtb_img_addr; /* address of DTB part in boot image */
+ u32 dtb_img_size; /* size of DTB payload in boot image */
+ ulong dtb_addr; /* address of DTB blob with specified index */
+ u32 i; /* index iterator */
+
+ res = android_image_get_dtb_img_addr(hdr_addr, &dtb_img_addr);
+ if (!res)
+ return false;
+
+ /* Check if DTB area of boot image is in DTBO format */
+ if (android_dt_check_header(dtb_img_addr)) {
+ printf("## DTB area contents (DTBO format):\n");
+ android_dt_print_contents(dtb_img_addr);
+ return true;
+ }
+
+ printf("## DTB area contents (concat format):\n");
+
+ /* Iterate over concatenated DTB blobs */
+ hdr = map_sysmem(hdr_addr, sizeof(*hdr));
+ dtb_img_size = hdr->dtb_size;
+ unmap_sysmem(hdr);
+ i = 0;
+ dtb_addr = dtb_img_addr;
+ while (dtb_addr < dtb_img_addr + dtb_img_size) {
+ const struct fdt_header *fdt;
+ u32 dtb_size;
+
+ fdt = map_sysmem(dtb_addr, sizeof(*fdt));
+ if (fdt_check_header(fdt) != 0) {
+ unmap_sysmem(fdt);
+ printf("Error: Invalid FDT header for index %u\n", i);
+ return false;
+ }
+
+ res = android_image_print_dtb_info(fdt, i);
+ if (!res) {
+ unmap_sysmem(fdt);
+ return false;
+ }
+
+ dtb_size = fdt_totalsize(fdt);
+ unmap_sysmem(fdt);
+ dtb_addr += dtb_size;
+ ++i;
+ }
+
+ return true;
+}
#endif
# CONFIG_MISC_INIT_R is not set
CONFIG_VERSION_VARIABLE=y
CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_AVB_VERIFY=y
+CONFIG_ANDROID_AB=y
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SPL_DMA=y
CONFIG_SYS_SPI_U_BOOT_OFFS=0x40000
CONFIG_SPL_YMODEM_SUPPORT=y
CONFIG_CMD_ADTIMG=y
+CONFIG_CMD_ABOOTIMG=y
CONFIG_CMD_SPL=y
CONFIG_CMD_BCB=y
# CONFIG_CMD_FLASH is not set
# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_AB_SELECT=y
# CONFIG_CMD_PMIC is not set
+CONFIG_CMD_AVB=y
CONFIG_OF_CONTROL=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_DEFAULT_DEVICE_TREE="am572x-idk"
CONFIG_USB_GADGET_MANUFACTURER="Texas Instruments"
CONFIG_USB_GADGET_VENDOR_NUM=0x0451
CONFIG_USB_GADGET_PRODUCT_NUM=0xd022
+CONFIG_LIBAVB=y
# CONFIG_MISC_INIT_R is not set
CONFIG_VERSION_VARIABLE=y
CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_AVB_VERIFY=y
+CONFIG_ANDROID_AB=y
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SPL_DMA=y
CONFIG_SPL_SPI_LOAD=y
CONFIG_SYS_SPI_U_BOOT_OFFS=0x40000
CONFIG_CMD_ADTIMG=y
+CONFIG_CMD_ABOOTIMG=y
CONFIG_CMD_BCB=y
# CONFIG_CMD_FLASH is not set
# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_AB_SELECT=y
# CONFIG_CMD_PMIC is not set
+CONFIG_CMD_AVB=y
CONFIG_OF_CONTROL=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_DEFAULT_DEVICE_TREE="am57xx-beagle-x15"
CONFIG_USB_GADGET_MANUFACTURER="Texas Instruments"
CONFIG_USB_GADGET_VENDOR_NUM=0x0451
CONFIG_USB_GADGET_PRODUCT_NUM=0xd022
+CONFIG_LIBAVB=y
# CONFIG_MISC_INIT_R is not set
CONFIG_VERSION_VARIABLE=y
CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_AVB_VERIFY=y
+CONFIG_ANDROID_AB=y
CONFIG_SPL_SYS_MALLOC_SIMPLE=y
CONFIG_SPL_SEPARATE_BSS=y
CONFIG_SPL_DMA=y
CONFIG_SPL_DFU=y
CONFIG_SPL_YMODEM_SUPPORT=y
CONFIG_CMD_ADTIMG=y
+CONFIG_CMD_ABOOTIMG=y
CONFIG_CMD_BCB=y
# CONFIG_CMD_FLASH is not set
# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_AB_SELECT=y
# CONFIG_CMD_PMIC is not set
+CONFIG_CMD_AVB=y
CONFIG_OF_CONTROL=y
CONFIG_SPL_OF_CONTROL=y
CONFIG_DEFAULT_DEVICE_TREE="am57xx-beagle-x15"
CONFIG_USB_GADGET_MANUFACTURER="Texas Instruments"
CONFIG_USB_GADGET_VENDOR_NUM=0x0451
CONFIG_USB_GADGET_PRODUCT_NUM=0xd022
+CONFIG_LIBAVB=y
CONFIG_VENDOR_INTEL=y
CONFIG_TARGET_EDISON=y
CONFIG_SMP=y
+CONFIG_GENERATE_ACPI_TABLE=y
CONFIG_BOARD_EARLY_INIT_R=y
CONFIG_LAST_STAGE_INIT=y
CONFIG_HUSH_PARSER=y
-# CONFIG_CMDLINE_EDITING is not set
CONFIG_CMD_CPU=y
CONFIG_CMD_ASKENV=y
CONFIG_CMD_GREPENV=y
CONFIG_ARM=y
CONFIG_ARCH_K3=y
+CONFIG_SPL_GPIO_SUPPORT=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
CONFIG_SYS_MALLOC_F_LEN=0x8000
CONFIG_SPL_DM_RESET=y
CONFIG_SPL_POWER_SUPPORT=y
CONFIG_SPL_POWER_DOMAIN=y
+CONFIG_SPL_RAM_SUPPORT=y
+CONFIG_SPL_RAM_DEVICE=y
CONFIG_SPL_SPI_LOAD=y
CONFIG_SYS_SPI_U_BOOT_OFFS=0x280000
+CONFIG_SPL_USB_GADGET=y
+CONFIG_SPL_DFU=y
CONFIG_SPL_YMODEM_SUPPORT=y
CONFIG_CMD_ASKENV=y
CONFIG_CMD_DFU=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPT=y
+CONFIG_CMD_GPIO=y
CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y
CONFIG_CMD_MTD=y
CONFIG_SPL_MULTI_DTB_FIT_NO_COMPRESSION=y
CONFIG_ENV_IS_IN_MMC=y
CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
-CONFIG_ENV_OFFSET_REDUND=0x700000
+CONFIG_ENV_OFFSET_REDUND=0x6A0000
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_NET_RANDOM_ETHADDR=y
CONFIG_DM=y
CONFIG_FASTBOOT_FLASH_MMC_DEV=0
CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
CONFIG_TI_SCI_PROTOCOL=y
+CONFIG_DM_GPIO=y
+CONFIG_DA8XX_GPIO=y
+CONFIG_DM_PCA953X=y
CONFIG_DM_I2C=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_DM_MAILBOX=y
CONFIG_POWER_DOMAIN=y
CONFIG_TI_SCI_POWER_DOMAIN=y
CONFIG_RAM=y
+CONFIG_SPL_RAM=y
CONFIG_REMOTEPROC_TI_K3_DSP=y
CONFIG_REMOTEPROC_TI_K3_R5F=y
CONFIG_DM_RESET=y
CONFIG_USB_CDNS3=y
CONFIG_USB_CDNS3_GADGET=y
CONFIG_USB_CDNS3_HOST=y
+CONFIG_SPL_USB_CDNS3_GADGET=y
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_MANUFACTURER="Texas Instruments"
CONFIG_USB_GADGET_VENDOR_NUM=0x0451
CONFIG_SPL_GPIO_SUPPORT=y
CONFIG_SPL_LIBCOMMON_SUPPORT=y
CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x55000
+CONFIG_SYS_MALLOC_F_LEN=0x70000
CONFIG_SOC_K3_J721E=y
CONFIG_TARGET_J721E_R5_EVM=y
CONFIG_ENV_SIZE=0x20000
CONFIG_SPL_REMOTEPROC=y
CONFIG_SPL_SPI_LOAD=y
CONFIG_SYS_SPI_U_BOOT_OFFS=0x80000
+CONFIG_SPL_USB_GADGET=y
+CONFIG_SPL_DFU=y
CONFIG_SPL_YMODEM_SUPPORT=y
CONFIG_HUSH_PARSER=y
+CONFIG_CMD_DFU=y
# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPT=y
CONFIG_CMD_MMC=y
CONFIG_CLK_TI_SCI=y
CONFIG_TI_SCI_PROTOCOL=y
CONFIG_DA8XX_GPIO=y
+CONFIG_DM_PCA953X=y
CONFIG_DM_I2C=y
CONFIG_I2C_SET_DEFAULT_BUS_NUM=y
CONFIG_SYS_I2C_OMAP24XX=y
CONFIG_TIMER=y
CONFIG_SPL_TIMER=y
CONFIG_OMAP_TIMER=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_DM_USB_GADGET=y
+CONFIG_SPL_DM_USB_GADGET=y
+CONFIG_USB_CDNS3=y
+CONFIG_USB_CDNS3_GADGET=y
+CONFIG_SPL_USB_CDNS3_GADGET=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="Texas Instruments"
+CONFIG_USB_GADGET_VENDOR_NUM=0x0451
+CONFIG_USB_GADGET_PRODUCT_NUM=0x6163
+CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_FS_EXT4=y
CONFIG_FS_FAT_MAX_CLUSTSIZE=16384
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_SYS_PROMPT="U-Boot> "
+CONFIG_CMD_DFU=y
+# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPIO=y
CONFIG_CMD_MMC=y
CONFIG_CMD_FS_UUID=y
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_DFU_MMC=y
CONFIG_DM_KEYBOARD=y
CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_BCM2835=y
+CONFIG_DM_ETH=y
+CONFIG_BCMGENET=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_GENERIC is not set
# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_DM_USB_GADGET=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="FSL"
+CONFIG_USB_GADGET_VENDOR_NUM=0x0525
+CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5
+CONFIG_USB_GADGET_DWC2_OTG=y
+CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_DM_VIDEO=y
CONFIG_VIDEO_BPP32=y
CONFIG_SYS_WHITE_ON_BLACK=y
# CONFIG_DISPLAY_CPUINFO is not set
# CONFIG_DISPLAY_BOARDINFO is not set
CONFIG_SYS_PROMPT="U-Boot> "
+CONFIG_CMD_DFU=y
+# CONFIG_CMD_FLASH is not set
CONFIG_CMD_GPIO=y
CONFIG_CMD_MMC=y
CONFIG_CMD_FS_UUID=y
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
CONFIG_SYS_RELOC_GD_ENV_ADDR=y
CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
+CONFIG_DFU_MMC=y
CONFIG_DM_KEYBOARD=y
CONFIG_DM_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_BCM2835=y
+CONFIG_DM_ETH=y
+CONFIG_BCMGENET=y
CONFIG_PINCTRL=y
# CONFIG_PINCTRL_GENERIC is not set
# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_DM_USB_GADGET=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="FSL"
+CONFIG_USB_GADGET_VENDOR_NUM=0x0525
+CONFIG_USB_GADGET_PRODUCT_NUM=0xa4a5
+CONFIG_USB_GADGET_DWC2_OTG=y
+CONFIG_USB_GADGET_DOWNLOAD=y
CONFIG_DM_VIDEO=y
CONFIG_VIDEO_BPP32=y
CONFIG_SYS_WHITE_ON_BLACK=y
CONFIG_USB_HOST_ETHER=y
CONFIG_USB_ETHER_LAN78XX=y
CONFIG_USB_ETHER_SMSC95XX=y
+CONFIG_BCMGENET=y
CONFIG_DM_VIDEO=y
CONFIG_VIDEO_BPP32=y
CONFIG_SYS_WHITE_ON_BLACK=y
CONFIG_CMD_CPU=y
CONFIG_CMD_LICENSE=y
CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_ABOOTIMG=y
# CONFIG_CMD_ELF is not set
CONFIG_CMD_ASKENV=y
CONFIG_CMD_GREPENV=y
--- /dev/null
+.. SPDX-License-Identifier: GPL-2.0+
+
+Android A/B updates
+===================
+
+Overview
+--------
+
+A/B system updates ensures modern approach for system update. This feature
+allows one to use two sets (or more) of partitions referred to as slots
+(normally slot A and slot B). The system runs from the current slot while the
+partitions in the unused slot can be updated [1]_.
+
+A/B enablement
+--------------
+
+The A/B updates support can be activated by specifying next options in
+your board configuration file::
+
+ CONFIG_ANDROID_AB=y
+ CONFIG_CMD_AB_SELECT=y
+
+The disk space on target device must be partitioned in a way so that each
+partition which needs to be updated has two or more instances. The name of
+each instance must be formed by adding suffixes: ``_a``, ``_b``, ``_c``, etc.
+For example: ``boot_a``, ``boot_b``, ``system_a``, ``system_b``, ``vendor_a``,
+``vendor_b``.
+
+As a result you can use ``ab_select`` command to ensure A/B boot process in your
+boot script. This command analyzes and processes A/B metadata stored on a
+special partition (e.g. ``misc``) and determines which slot should be used for
+booting up.
+
+Command usage
+-------------
+
+.. code-block:: none
+
+ ab_select <slot_var_name> <interface> <dev[:part_number|#part_name]>
+
+for example::
+
+ => ab_select slot_name mmc 1:4
+
+or::
+
+ => ab_select slot_name mmc 1#misc
+
+Result::
+
+ => printenv slot_name
+ slot_name=a
+
+Based on this slot information, the current boot partition should be defined,
+and next kernel command line parameters should be generated:
+
+* ``androidboot.slot_suffix=``
+* ``root=``
+
+For example::
+
+ androidboot.slot_suffix=_a root=/dev/mmcblk1p12
+
+A/B metadata is organized according to AOSP reference [2]_. On the first system
+start with A/B enabled, when ``misc`` partition doesn't contain required data,
+the default A/B metadata will be created and written to ``misc`` partition.
+
+References
+----------
+
+.. [1] https://source.android.com/devices/tech/ota/ab
+.. [2] https://android.googlesource.com/platform/bootable/recovery/+/refs/tags/android-10.0.0_r25/bootloader_message/include/bootloader_message/bootloader_message.h
+++ /dev/null
-Android A/B updates
-===================
-
-Overview
---------
-
-A/B system updates ensures modern approach for system update. This feature
-allows one to use two sets (or more) of partitions referred to as slots
-(normally slot A and slot B). The system runs from the current slot while the
-partitions in the unused slot can be updated [1].
-
-A/B enablement
---------------
-
-The A/B updates support can be activated by specifying next options in
-your board configuration file:
-
- CONFIG_ANDROID_AB=y
- CONFIG_CMD_AB_SELECT=y
-
-The disk space on target device must be partitioned in a way so that each
-partition which needs to be updated has two or more instances. The name of
-each instance must be formed by adding suffixes: _a, _b, _c, etc.
-For example: boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
-
-As a result you can use 'ab_select' command to ensure A/B boot process in your
-boot script. This command analyzes and processes A/B metadata stored on a
-special partition (e.g. "misc") and determines which slot should be used for
-booting up.
-
-Command usage
--------------
-
- ab_select <slot_var_name> <interface> <dev[:part_number|#part_name]>
-
-for example:
-
- => ab_select slot_name mmc 1:4
-
-or
-
- => ab_select slot_name mmc 1#misc
-
-Result:
-
- => printenv slot_name
- slot_name=a
-
-Based on this slot information, the current boot partition should be defined,
-and next kernel command line parameters should be generated:
-
- - androidboot.slot_suffix=
- - root=
-
-For example:
-
- androidboot.slot_suffix=_a root=/dev/mmcblk1p12
-
-A/B metadata is organized according to AOSP reference [2]. On the first system
-start with A/B enabled, when 'misc' partition doesn't contain required data,
-the default A/B metadata will be created and written to 'misc' partition.
-
-References
-----------
-
-[1] https://source.android.com/devices/tech/ota/ab
-[2] bootable/recovery/bootloader_message/include/bootloader_message/bootloader_message.h
--- /dev/null
+.. SPDX-License-Identifier: GPL-2.0+
+
+Android Verified Boot 2.0
+=========================
+
+This file contains information about the current support of Android Verified
+Boot 2.0 in U-Boot.
+
+Overview
+--------
+
+Verified Boot establishes a chain of trust from the bootloader to system images:
+
+* Provides integrity checking for:
+
+ * Android Boot image: Linux kernel + ramdisk. RAW hashing of the whole
+ partition is done and the hash is compared with the one stored in
+ the VBMeta image
+ * ``system``/``vendor`` partitions: verifying root hash of dm-verity hashtrees
+
+* Provides capabilities for rollback protection
+
+Integrity of the bootloader (U-Boot BLOB and environment) is out of scope.
+
+For additional details check [1]_.
+
+AVB using OP-TEE (optional)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If AVB is configured to use OP-TEE (see `Enable on your board`_) rollback
+indexes and device lock state are stored in RPMB. The RPMB partition is managed
+by OP-TEE (see [2]_ for details) which is a secure OS leveraging ARM
+TrustZone.
+
+AVB 2.0 U-Boot shell commands
+-----------------------------
+
+Provides CLI interface to invoke AVB 2.0 verification + misc. commands for
+different testing purposes::
+
+ avb init <dev> - initialize avb 2.0 for <dev>
+ avb verify - run verification process using hash data from vbmeta structure
+ avb read_rb <num> - read rollback index at location <num>
+ avb write_rb <num> <rb> - write rollback index <rb> to <num>
+ avb is_unlocked - returns unlock status of the device
+ avb get_uuid <partname> - read and print uuid of partition <partname>
+ avb read_part <partname> <offset> <num> <addr> - read <num> bytes from
+ partition <partname> to buffer <addr>
+ avb write_part <partname> <offset> <num> <addr> - write <num> bytes to
+ <partname> by <offset> using data from <addr>
+
+Partitions tampering (example)
+------------------------------
+
+Boot or system/vendor (dm-verity metadata section) is tampered::
+
+ => avb init 1
+ => avb verify
+ avb_slot_verify.c:175: ERROR: boot: Hash of data does not match digest in
+ descriptor.
+ Slot verification result: ERROR_IO
+
+Vbmeta partition is tampered::
+
+ => avb init 1
+ => avb verify
+ avb_vbmeta_image.c:206: ERROR: Hash does not match!
+ avb_slot_verify.c:388: ERROR: vbmeta: Error verifying vbmeta image:
+ HASH_MISMATCH
+ Slot verification result: ERROR_IO
+
+Enable on your board
+--------------------
+
+The following options must be enabled::
+
+ CONFIG_LIBAVB=y
+ CONFIG_AVB_VERIFY=y
+ CONFIG_CMD_AVB=y
+
+In addtion optionally if storing rollback indexes in RPMB with help of
+OP-TEE::
+
+ CONFIG_TEE=y
+ CONFIG_OPTEE=y
+ CONFIG_OPTEE_TA_AVB=y
+ CONFIG_SUPPORT_EMMC_RPMB=y
+
+Then add ``avb verify`` invocation to your android boot sequence of commands,
+e.g.::
+
+ => avb_verify=avb init $mmcdev; avb verify;
+ => if run avb_verify; then \
+ echo AVB verification OK. Continue boot; \
+ set bootargs $bootargs $avb_bootargs; \
+ else \
+ echo AVB verification failed; \
+ exit; \
+ fi; \
+
+ => emmc_android_boot= \
+ echo Trying to boot Android from eMMC ...; \
+ ... \
+ run avb_verify; \
+ mmc read ${fdtaddr} ${fdt_start} ${fdt_size}; \
+ mmc read ${loadaddr} ${boot_start} ${boot_size}; \
+ bootm $loadaddr $loadaddr $fdtaddr; \
+
+If partitions you want to verify are slotted (have A/B suffixes), then current
+slot suffix should be passed to ``avb verify`` sub-command, e.g.::
+
+ => avb verify _a
+
+To switch on automatic generation of vbmeta partition in AOSP build, add these
+lines to device configuration mk file::
+
+ BOARD_AVB_ENABLE := true
+ BOARD_AVB_ALGORITHM := SHA512_RSA4096
+ BOARD_BOOTIMAGE_PARTITION_SIZE := <boot partition size>
+
+After flashing U-Boot don't forget to update environment and write new
+partition table::
+
+ => env default -f -a
+ => setenv partitions $partitions_android
+ => env save
+ => gpt write mmc 1 $partitions_android
+
+References
+----------
+
+.. [1] https://android.googlesource.com/platform/external/avb/+/master/README.md
+.. [2] https://www.op-tee.org/
+++ /dev/null
-Android Verified Boot 2.0
-
-This file contains information about the current support of Android Verified
-Boot 2.0 in U-boot
-
-1. OVERVIEW
----------------------------------
-Verified Boot establishes a chain of trust from the bootloader to system images
-* Provides integrity checking for:
- - Android Boot image: Linux kernel + ramdisk. RAW hashing of the whole
- partition is done and the hash is compared with the one stored in
- the VBMeta image
- - system/vendor partitions: verifying root hash of dm-verity hashtrees.
-* Provides capabilities for rollback protection.
-
-Integrity of the bootloader (U-boot BLOB and environment) is out of scope.
-
-For additional details check:
-https://android.googlesource.com/platform/external/avb/+/master/README.md
-
-1.1. AVB using OP-TEE (optional)
----------------------------------
-If AVB is configured to use OP-TEE (see 4. below) rollback indexes and
-device lock state are stored in RPMB. The RPMB partition is managed by
-OP-TEE (https://www.op-tee.org/) which is a secure OS leveraging ARM
-TrustZone.
-
-
-2. AVB 2.0 U-BOOT SHELL COMMANDS
------------------------------------
-Provides CLI interface to invoke AVB 2.0 verification + misc. commands for
-different testing purposes:
-
-avb init <dev> - initialize avb 2.0 for <dev>
-avb verify - run verification process using hash data from vbmeta structure
-avb read_rb <num> - read rollback index at location <num>
-avb write_rb <num> <rb> - write rollback index <rb> to <num>
-avb is_unlocked - returns unlock status of the device
-avb get_uuid <partname> - read and print uuid of partition <partname>
-avb read_part <partname> <offset> <num> <addr> - read <num> bytes from
-partition <partname> to buffer <addr>
-avb write_part <partname> <offset> <num> <addr> - write <num> bytes to
-<partname> by <offset> using data from <addr>
-
-
-3. PARTITIONS TAMPERING (EXAMPLE)
------------------------------------
-Boot or system/vendor (dm-verity metadata section) is tampered:
-=> avb init 1
-=> avb verify
-avb_slot_verify.c:175: ERROR: boot: Hash of data does not match digest in
-descriptor.
-Slot verification result: ERROR_IO
-
-Vbmeta partition is tampered:
-=> avb init 1
-=> avb verify
-avb_vbmeta_image.c:206: ERROR: Hash does not match!
-avb_slot_verify.c:388: ERROR: vbmeta: Error verifying vbmeta image:
-HASH_MISMATCH
-Slot verification result: ERROR_IO
-
-
-4. ENABLE ON YOUR BOARD
------------------------------------
-The following options must be enabled:
-CONFIG_LIBAVB=y
-CONFIG_AVB_VERIFY=y
-CONFIG_CMD_AVB=y
-
-In addtion optionally if storing rollback indexes in RPMB with help of
-OP-TEE:
-CONFIG_TEE=y
-CONFIG_OPTEE=y
-CONFIG_OPTEE_TA_AVB=y
-CONFIG_SUPPORT_EMMC_RPMB=y
-
-Then add `avb verify` invocation to your android boot sequence of commands,
-e.g.:
-
-=> avb_verify=avb init $mmcdev; avb verify;
-=> if run avb_verify; then \
- echo AVB verification OK. Continue boot; \
- set bootargs $bootargs $avb_bootargs; \
- else \
- echo AVB verification failed; \
- exit; \
- fi; \
-
-=> emmc_android_boot= \
- echo Trying to boot Android from eMMC ...; \
- ... \
- run avb_verify; \
- mmc read ${fdtaddr} ${fdt_start} ${fdt_size}; \
- mmc read ${loadaddr} ${boot_start} ${boot_size}; \
- bootm $loadaddr $loadaddr $fdtaddr; \
-
-If partitions you want to verify are slotted (have A/B suffixes), then current
-slot suffix should be passed to 'avb verify' sub-command, e.g.:
-
-=> avb verify _a
-
-To switch on automatic generation of vbmeta partition in AOSP build, add these
-lines to device configuration mk file:
-
-BOARD_AVB_ENABLE := true
-BOARD_AVB_ALGORITHM := SHA512_RSA4096
-BOARD_BOOTIMAGE_PARTITION_SIZE := <boot partition size>
-
-After flashing U-boot don't forget to update environment and write new
-partition table:
-=> env default -f -a
-=> setenv partitions $partitions_android
-=> env save
-=> gpt write mmc 1 $partitions_android
--- /dev/null
+.. SPDX-License-Identifier: GPL-2.0+
+
+Android Bootloader Control Block (BCB)
+======================================
+
+The purpose behind this file is to:
+
+* give an overview of BCB w/o duplicating public documentation
+* describe the main BCB use-cases which concern U-Boot
+* reflect current support status in U-Boot
+* mention any relevant U-Boot build-time tunables
+* precisely exemplify one or more use-cases
+
+Additions and fixes are welcome!
+
+Overview
+--------
+
+Bootloader Control Block (BCB) is a well established term/acronym in
+the Android namespace which refers to a location in a dedicated raw
+(i.e. FS-unaware) flash (e.g. eMMC) partition, usually called ``misc``,
+which is used as media for exchanging messages between Android userspace
+(particularly recovery [1]_) and an Android-capable bootloader.
+
+On higher level, BCB provides a way to implement a subset of Android
+Bootloader Requirements [2]_, amongst which are:
+
+* Android-specific bootloader flow [3]_
+* Get the "reboot reason" (and act accordingly) [4]_
+* Get/pass a list of commands from/to recovery [1]_
+* TODO
+
+
+'bcb'. Shell command overview
+-----------------------------
+
+The ``bcb`` command provides a CLI to facilitate the development of the
+requirements enumerated above. Below is the command's help message::
+
+ => bcb
+ bcb - Load/set/clear/test/dump/store Android BCB fields
+
+ Usage:
+ bcb load <dev> <part> - load BCB from mmc <dev>:<part>
+ bcb set <field> <val> - set BCB <field> to <val>
+ bcb clear [<field>] - clear BCB <field> or all fields
+ bcb test <field> <op> <val> - test BCB <field> against <val>
+ bcb dump <field> - dump BCB <field>
+ bcb store - store BCB back to mmc
+
+ Legend:
+ <dev> - MMC device index containing the BCB partition
+ <part> - MMC partition index or name containing the BCB
+ <field> - one of {command,status,recovery,stage,reserved}
+ <op> - the binary operator used in 'bcb test':
+ '=' returns true if <val> matches the string stored in <field>
+ '~' returns true if <val> matches a subset of <field>'s string
+ <val> - string/text provided as input to bcb {set,test}
+ NOTE: any ':' character in <val> will be replaced by line feed
+ during 'bcb set' and used as separator by upper layers
+
+
+'bcb'. Example of getting reboot reason
+---------------------------------------
+
+.. code-block:: bash
+
+ if bcb load 1 misc; then
+ # valid BCB found
+ if bcb test command = bootonce-bootloader; then
+ bcb clear command; bcb store;
+ # do the equivalent of AOSP ${fastbootcmd}
+ # i.e. call fastboot
+ else if bcb test command = boot-recovery; then
+ bcb clear command; bcb store;
+ # do the equivalent of AOSP ${recoverycmd}
+ # i.e. do anything required for booting into recovery
+ else
+ # boot Android OS normally
+ fi
+ else
+ # corrupted/non-existent BCB
+ # report error or boot non-Android OS (platform-specific)
+ fi
+
+
+Enable on your board
+--------------------
+
+The following Kconfig options must be enabled::
+
+ CONFIG_PARTITIONS=y
+ CONFIG_MMC=y
+ CONFIG_BCB=y
+
+.. [1] https://android.googlesource.com/platform/bootable/recovery
+.. [2] https://source.android.com/devices/bootloader
+.. [3] https://patchwork.ozlabs.org/patch/746835/
+ ("[U-Boot,5/6] Initial support for the Android Bootloader flow")
+.. [4] https://source.android.com/devices/bootloader/boot-reason
+++ /dev/null
-Android Bootloader Control Block (BCB)
-
-The purpose behind this file is to:
- - give an overview of BCB w/o duplicating public documentation
- - describe the main BCB use-cases which concern U-Boot
- - reflect current support status in U-Boot
- - mention any relevant U-Boot build-time tunables
- - precisely exemplify one or more use-cases
-
-Additions and fixes are welcome!
-
-
-1. OVERVIEW
----------------------------------
-Bootloader Control Block (BCB) is a well established term/acronym in
-the Android namespace which refers to a location in a dedicated raw
-(i.e. FS-unaware) flash (e.g. eMMC) partition, usually called "misc",
-which is used as media for exchanging messages between Android userspace
-(particularly recovery [1]) and an Android-capable bootloader.
-
-On higher level, BCB provides a way to implement a subset of Android
-Bootloader Requirements [2], amongst which are:
- - Android-specific bootloader flow [3]
- - Get the "reboot reason" (and act accordingly) [4]
- - Get/pass a list of commands from/to recovery [1]
- - TODO
-
-
-2. 'BCB'. SHELL COMMAND OVERVIEW
------------------------------------
-The 'bcb' command provides a CLI to facilitate the development of the
-requirements enumerated above. Below is the command's help message:
-
-=> bcb
-bcb - Load/set/clear/test/dump/store Android BCB fields
-
-Usage:
-bcb load <dev> <part> - load BCB from mmc <dev>:<part>
-bcb set <field> <val> - set BCB <field> to <val>
-bcb clear [<field>] - clear BCB <field> or all fields
-bcb test <field> <op> <val> - test BCB <field> against <val>
-bcb dump <field> - dump BCB <field>
-bcb store - store BCB back to mmc
-
-Legend:
-<dev> - MMC device index containing the BCB partition
-<part> - MMC partition index or name containing the BCB
-<field> - one of {command,status,recovery,stage,reserved}
-<op> - the binary operator used in 'bcb test':
- '=' returns true if <val> matches the string stored in <field>
- '~' returns true if <val> matches a subset of <field>'s string
-<val> - string/text provided as input to bcb {set,test}
- NOTE: any ':' character in <val> will be replaced by line feed
- during 'bcb set' and used as separator by upper layers
-
-
-3. 'BCB'. EXAMPLE OF GETTING REBOOT REASON
------------------------------------
-if bcb load 1 misc; then
- # valid BCB found
- if bcb test command = bootonce-bootloader; then
- bcb clear command; bcb store;
- # do the equivalent of AOSP ${fastbootcmd}
- # i.e. call fastboot
- else if bcb test command = boot-recovery; then
- bcb clear command; bcb store;
- # do the equivalent of AOSP ${recoverycmd}
- # i.e. do anything required for booting into recovery
- else
- # boot Android OS normally
- fi
-else
- # corrupted/non-existent BCB
- # report error or boot non-Android OS (platform-specific)
-fi
-
-
-4. ENABLE ON YOUR BOARD
------------------------------------
-The following Kconfig options must be enabled:
-CONFIG_PARTITIONS=y
-CONFIG_MMC=y
-CONFIG_BCB=y
-
-[1] https://android.googlesource.com/platform/bootable/recovery
-[2] https://source.android.com/devices/bootloader
-[3] https://patchwork.ozlabs.org/patch/746835/
- ("[U-Boot,5/6] Initial support for the Android Bootloader flow")
-[4] https://source.android.com/devices/bootloader/boot-reason
--- /dev/null
+.. SPDX-License-Identifier: GPL-2.0+
+.. sectionauthor:: Sam Protsenko <joe.skb7@gmail.com>
+
+Android Boot Image
+==================
+
+Overview
+--------
+
+Android Boot Image is used to boot Android OS. It usually contains kernel image
+(like ``zImage`` file) and ramdisk. Sometimes it can contain additional
+binaries. This image is built as a part of AOSP (called ``boot.img``), and being
+flashed into ``boot`` partition on eMMC. Bootloader then reads that image from
+``boot`` partition to RAM and boots the kernel from it. Kernel than starts
+``init`` process from the ramdisk. It should be mentioned that recovery image
+(``recovery.img``) also has Android Boot Image format.
+
+Android Boot Image format is described at [1]_. At the moment it can have one of
+next image headers:
+
+* v0: it's called *legacy* boot image header; used in devices launched before
+ Android 9; contains kernel image, ramdisk and second stage bootloader
+ (usually unused)
+* v1: used in devices launched with Android 9; adds ``recovery_dtbo`` field,
+ which should be used for non-A/B devices in ``recovery.img`` (see [2]_ for
+ details)
+* v2: used in devices launched with Android 10; adds ``dtb`` field, which
+ references payload containing DTB blobs (either concatenated one after the
+ other, or in Android DTBO image format)
+
+v2, v1 and v0 formats are backward compatible.
+
+Android Boot Image format is represented by :c:type:`struct andr_img_hdr` in
+U-Boot, and can be seen in ``include/android_image.h``. U-Boot supports booting
+Android Boot Image and also has associated command
+
+Booting
+-------
+
+U-Boot is able to boot the Android OS from Android Boot Image using ``bootm``
+command. In order to use Android Boot Image format support, next option should
+be enabled::
+
+ CONFIG_ANDROID_BOOT_IMAGE=y
+
+Then one can use next ``bootm`` command call to run Android:
+
+.. code-block:: bash
+
+ => bootm $loadaddr $loadaddr $fdtaddr
+
+where ``$loadaddr`` - address in RAM where boot image was loaded; ``$fdtaddr`` -
+address in RAM where DTB blob was loaded.
+
+And parameters are, correspondingly:
+
+ 1. Where kernel image is located in RAM
+ 2. Where ramdisk is located in RAM (can be ``"-"`` if not applicable)
+ 3. Where DTB blob is located in RAM
+
+``bootm`` command will figure out that image located in ``$loadaddr`` has
+Android Boot Image format, will parse that and boot the kernel from it,
+providing DTB blob to kernel (from 3rd parameter), passing info about ramdisk to
+kernel via DTB.
+
+DTB and DTBO blobs
+------------------
+
+``bootm`` command can't just use DTB blob from Android Boot Image (``dtb``
+field), because:
+
+* there is no DTB area in Android Boot Image before v2
+* there may be several DTB blobs in DTB area (e.g. for different SoCs)
+* some DTBO blobs may have to be merged in DTB blobs before booting
+ (e.g. for different boards)
+
+So user has to prepare DTB blob manually and provide it in a 3rd parameter
+of ``bootm`` command. Next commands can be used to do so:
+
+1. ``abootimg``: manipulates Anroid Boot Image, allows one to extract
+ meta-information and payloads from it
+2. ``adtimg``: manipulates Android DTB/DTBO image [3]_, allows one to extract
+ DTB/DTBO blobs from it
+
+In order to use those, please enable next config options::
+
+ CONFIG_CMD_ABOOTIMG=y
+ CONFIG_CMD_ADTIMG=y
+
+For example, let's assume we have next Android partitions on eMMC:
+
+* ``boot``: contains Android Boot Image v2 (including DTB blobs)
+* ``dtbo``: contains DTBO blobs
+
+Then next command sequence can be used to boot Android:
+
+.. code-block:: bash
+
+ => mmc dev 1
+
+ # Read boot image to RAM (into $loadaddr)
+ => part start mmc 1 boot boot_start
+ => part size mmc 1 boot boot_size
+ => mmc read $loadaddr $boot_start $boot_size
+
+ # Read DTBO image to RAM (into $dtboaddr)
+ => part start mmc 1 dtbo dtbo_start
+ => part size mmc 1 dtbo dtbo_size
+ => mmc read $dtboaddr $dtbo_start $dtbo_size
+
+ # Copy required DTB blob (into $fdtaddr)
+ => abootimg get dtb --index=0 dtb0_start dtb0_size
+ => cp.b $dtb0_start $fdtaddr $dtb0_size
+
+ # Merge required DTBO blobs into DTB blob
+ => fdt addr $fdtaddr 0x100000
+ => adtimg addr $dtboaddr
+ => adtimg get dt --index=0 $dtbo0_addr
+ => fdt apply $dtbo0_addr
+
+ # Boot Android
+ => bootm $loadaddr $loadaddr $fdtaddr
+
+This sequence should be used for Android 10 boot. Of course, the whole Android
+boot procedure includes much more actions, like:
+
+* obtaining reboot reason from BCB (see [4]_)
+* implementing recovery boot
+* implementing fastboot boot
+* implementing A/B slotting (see [5]_)
+* implementing AVB2.0 (see [6]_)
+
+But Android Boot Image booting is the most crucial part in Android boot scheme.
+
+All Android bootloader requirements documentation is available at [7]_. Some
+overview on the whole Android 10 boot process can be found at [8]_.
+
+C API for working with Android Boot Image format
+------------------------------------------------
+
+.. kernel-doc:: common/image-android.c
+ :internal:
+
+References
+----------
+
+.. [1] https://source.android.com/devices/bootloader/boot-image-header
+.. [2] https://source.android.com/devices/bootloader/recovery-image
+.. [3] https://source.android.com/devices/architecture/dto/partitions
+.. [4] :doc:`bcb`
+.. [5] :doc:`ab`
+.. [6] :doc:`avb2`
+.. [7] https://source.android.com/devices/bootloader
+.. [8] https://connect.linaro.org/resources/san19/san19-217/
--- /dev/null
+.. SPDX-License-Identifier: GPL-2.0+
+
+FastBoot Version 0.4
+====================
+
+The fastboot protocol is a mechanism for communicating with bootloaders
+over USB. It is designed to be very straightforward to implement, to
+allow it to be used across a wide range of devices and from hosts running
+Linux, Windows, or OSX.
+
+Basic Requirements
+------------------
+
+* Two bulk endpoints (in, out) are required
+* Max packet size must be 64 bytes for full-speed and 512 bytes for
+ high-speed USB
+* The protocol is entirely host-driven and synchronous (unlike the
+ multi-channel, bi-directional, asynchronous ADB protocol)
+
+
+Transport and Framing
+---------------------
+
+1. Host sends a command, which is an ascii string in a single
+ packet no greater than 64 bytes.
+
+2. Client response with a single packet no greater than 64 bytes.
+ The first four bytes of the response are "OKAY", "FAIL", "DATA",
+ or "INFO". Additional bytes may contain an (ascii) informative
+ message.
+
+ a. INFO -> the remaining 60 bytes are an informative message
+ (providing progress or diagnostic messages). They should
+ be displayed and then step #2 repeats
+
+ b. FAIL -> the requested command failed. The remaining 60 bytes
+ of the response (if present) provide a textual failure message
+ to present to the user. Stop.
+
+ c. OKAY -> the requested command completed successfully. Go to #5
+
+ d. DATA -> the requested command is ready for the data phase.
+ A DATA response packet will be 12 bytes long, in the form of
+ DATA00000000 where the 8 digit hexidecimal number represents
+ the total data size to transfer.
+
+3. Data phase. Depending on the command, the host or client will
+ send the indicated amount of data. Short packets are always
+ acceptable and zero-length packets are ignored. This phase continues
+ until the client has sent or received the number of bytes indicated
+ in the "DATA" response above.
+
+4. Client responds with a single packet no greater than 64 bytes.
+ The first four bytes of the response are "OKAY", "FAIL", or "INFO".
+ Similar to #2:
+
+ a. INFO -> display the remaining 60 bytes and return to #4
+
+ b. FAIL -> display the remaining 60 bytes (if present) as a failure
+ reason and consider the command failed. Stop.
+
+ c. OKAY -> success. Go to #5
+
+5. Success. Stop.
+
+
+Example Session
+---------------
+
+.. code-block:: none
+
+ Host: "getvar:version" request version variable
+
+ Client: "OKAY0.4" return version "0.4"
+
+ Host: "getvar:nonexistant" request some undefined variable
+
+ Client: "OKAY" return value ""
+
+ Host: "download:00001234" request to send 0x1234 bytes of data
+
+ Client: "DATA00001234" ready to accept data
+
+ Host: < 0x1234 bytes > send data
+
+ Client: "OKAY" success
+
+ Host: "flash:bootloader" request to flash the data to the bootloader
+
+ Client: "INFOerasing flash" indicate status / progress
+ "INFOwriting flash"
+ "OKAY" indicate success
+
+ Host: "powerdown" send a command
+
+ Client: "FAILunknown command" indicate failure
+
+
+Command Reference
+-----------------
+
+* Command parameters are indicated by printf-style escape sequences.
+
+* Commands are ascii strings and sent without the quotes (which are
+ for illustration only here) and without a trailing 0 byte.
+
+* Commands that begin with a lowercase letter are reserved for this
+ specification. OEM-specific commands should not begin with a
+ lowercase letter, to prevent incompatibilities with future specs.
+
+.. code-block:: none
+
+ "getvar:%s" Read a config/version variable from the bootloader.
+ The variable contents will be returned after the
+ OKAY response.
+
+ "download:%08x" Write data to memory which will be later used
+ by "boot", "ramdisk", "flash", etc. The client
+ will reply with "DATA%08x" if it has enough
+ space in RAM or "FAIL" if not. The size of
+ the download is remembered.
+
+ "verify:%08x" Send a digital signature to verify the downloaded
+ data. Required if the bootloader is "secure"
+ otherwise "flash" and "boot" will be ignored.
+
+ "flash:%s" Write the previously downloaded image to the
+ named partition (if possible).
+
+ "erase:%s" Erase the indicated partition (clear to 0xFFs)
+
+ "boot" The previously downloaded data is a boot.img
+ and should be booted according to the normal
+ procedure for a boot.img
+
+ "continue" Continue booting as normal (if possible)
+
+ "reboot" Reboot the device.
+
+ "reboot-bootloader" Reboot back into the bootloader.
+ Useful for upgrade processes that require upgrading
+ the bootloader and then upgrading other partitions
+ using the new bootloader.
+
+ "powerdown" Power off the device.
+
+Client Variables
+----------------
+
+The ``getvar:%s`` command is used to read client variables which
+represent various information about the device and the software
+on it.
+
+The various currently defined names are::
+
+ version Version of FastBoot protocol supported.
+ It should be "0.3" for this document.
+
+ version-bootloader Version string for the Bootloader.
+
+ version-baseband Version string of the Baseband Software
+
+ product Name of the product
+
+ serialno Product serial number
+
+ secure If the value is "yes", this is a secure
+ bootloader requiring a signature before
+ it will install or boot images.
+
+Names starting with a lowercase character are reserved by this
+specification. OEM-specific names should not start with lowercase
+characters.
+++ /dev/null
-FastBoot Version 0.4
-----------------------
-
-The fastboot protocol is a mechanism for communicating with bootloaders
-over USB. It is designed to be very straightforward to implement, to
-allow it to be used across a wide range of devices and from hosts running
-Linux, Windows, or OSX.
-
-
-Basic Requirements
-------------------
-
-* Two bulk endpoints (in, out) are required
-* Max packet size must be 64 bytes for full-speed and 512 bytes for
- high-speed USB
-* The protocol is entirely host-driven and synchronous (unlike the
- multi-channel, bi-directional, asynchronous ADB protocol)
-
-
-Transport and Framing
----------------------
-
-1. Host sends a command, which is an ascii string in a single
- packet no greater than 64 bytes.
-
-2. Client response with a single packet no greater than 64 bytes.
- The first four bytes of the response are "OKAY", "FAIL", "DATA",
- or "INFO". Additional bytes may contain an (ascii) informative
- message.
-
- a. INFO -> the remaining 60 bytes are an informative message
- (providing progress or diagnostic messages). They should
- be displayed and then step #2 repeats
-
- b. FAIL -> the requested command failed. The remaining 60 bytes
- of the response (if present) provide a textual failure message
- to present to the user. Stop.
-
- c. OKAY -> the requested command completed successfully. Go to #5
-
- d. DATA -> the requested command is ready for the data phase.
- A DATA response packet will be 12 bytes long, in the form of
- DATA00000000 where the 8 digit hexidecimal number represents
- the total data size to transfer.
-
-3. Data phase. Depending on the command, the host or client will
- send the indicated amount of data. Short packets are always
- acceptable and zero-length packets are ignored. This phase continues
- until the client has sent or received the number of bytes indicated
- in the "DATA" response above.
-
-4. Client responds with a single packet no greater than 64 bytes.
- The first four bytes of the response are "OKAY", "FAIL", or "INFO".
- Similar to #2:
-
- a. INFO -> display the remaining 60 bytes and return to #4
-
- b. FAIL -> display the remaining 60 bytes (if present) as a failure
- reason and consider the command failed. Stop.
-
- c. OKAY -> success. Go to #5
-
-5. Success. Stop.
-
-
-Example Session
----------------
-
-Host: "getvar:version" request version variable
-
-Client: "OKAY0.4" return version "0.4"
-
-Host: "getvar:nonexistant" request some undefined variable
-
-Client: "OKAY" return value ""
-
-Host: "download:00001234" request to send 0x1234 bytes of data
-
-Client: "DATA00001234" ready to accept data
-
-Host: < 0x1234 bytes > send data
-
-Client: "OKAY" success
-
-Host: "flash:bootloader" request to flash the data to the bootloader
-
-Client: "INFOerasing flash" indicate status / progress
- "INFOwriting flash"
- "OKAY" indicate success
-
-Host: "powerdown" send a command
-
-Client: "FAILunknown command" indicate failure
-
-
-Command Reference
------------------
-
-* Command parameters are indicated by printf-style escape sequences.
-
-* Commands are ascii strings and sent without the quotes (which are
- for illustration only here) and without a trailing 0 byte.
-
-* Commands that begin with a lowercase letter are reserved for this
- specification. OEM-specific commands should not begin with a
- lowercase letter, to prevent incompatibilities with future specs.
-
- "getvar:%s" Read a config/version variable from the bootloader.
- The variable contents will be returned after the
- OKAY response.
-
- "download:%08x" Write data to memory which will be later used
- by "boot", "ramdisk", "flash", etc. The client
- will reply with "DATA%08x" if it has enough
- space in RAM or "FAIL" if not. The size of
- the download is remembered.
-
- "verify:%08x" Send a digital signature to verify the downloaded
- data. Required if the bootloader is "secure"
- otherwise "flash" and "boot" will be ignored.
-
- "flash:%s" Write the previously downloaded image to the
- named partition (if possible).
-
- "erase:%s" Erase the indicated partition (clear to 0xFFs)
-
- "boot" The previously downloaded data is a boot.img
- and should be booted according to the normal
- procedure for a boot.img
-
- "continue" Continue booting as normal (if possible)
-
- "reboot" Reboot the device.
-
- "reboot-bootloader" Reboot back into the bootloader.
- Useful for upgrade processes that require upgrading
- the bootloader and then upgrading other partitions
- using the new bootloader.
-
- "powerdown" Power off the device.
-
-
-
-Client Variables
-----------------
-
-The "getvar:%s" command is used to read client variables which
-represent various information about the device and the software
-on it.
-
-The various currently defined names are:
-
- version Version of FastBoot protocol supported.
- It should be "0.3" for this document.
-
- version-bootloader Version string for the Bootloader.
-
- version-baseband Version string of the Baseband Software
-
- product Name of the product
-
- serialno Product serial number
-
- secure If the value is "yes", this is a secure
- bootloader requiring a signature before
- it will install or boot images.
-
-Names starting with a lowercase character are reserved by this
-specification. OEM-specific names should not start with lowercase
-characters.
--- /dev/null
+.. SPDX-License-Identifier: GPL-2.0+
+
+Android Fastboot
+================
+
+Overview
+--------
+
+The protocol that is used over USB and UDP is described in [1]_.
+
+The current implementation supports the following standard commands:
+
+- ``boot``
+- ``continue``
+- ``download``
+- ``erase`` (if enabled)
+- ``flash`` (if enabled)
+- ``getvar``
+- ``reboot``
+- ``reboot-bootloader``
+- ``set_active`` (only a stub implementation which always succeeds)
+
+The following OEM commands are supported (if enabled):
+
+- ``oem format`` - this executes ``gpt write mmc %x $partitions``
+
+Support for both eMMC and NAND devices is included.
+
+Client installation
+-------------------
+
+The counterpart to this is the fastboot client which can be found in
+Android's ``platform/system/core`` repository in the fastboot
+folder. It runs on Windows, Linux and OSX. The fastboot client is
+part of the Android SDK Platform-Tools and can be downloaded from [2]_.
+
+Board specific
+--------------
+
+USB configuration
+^^^^^^^^^^^^^^^^^
+
+The fastboot gadget relies on the USB download gadget, so the following
+options must be configured:
+
+::
+
+ CONFIG_USB_GADGET_DOWNLOAD
+ CONFIG_USB_GADGET_VENDOR_NUM
+ CONFIG_USB_GADGET_PRODUCT_NUM
+ CONFIG_USB_GADGET_MANUFACTURER
+
+NOTE: The ``CONFIG_USB_GADGET_VENDOR_NUM`` must be one of the numbers
+supported by the fastboot client. The list of vendor IDs supported can
+be found in the fastboot client source code.
+
+General configuration
+^^^^^^^^^^^^^^^^^^^^^
+
+The fastboot protocol requires a large memory buffer for
+downloads. This buffer should be as large as possible for a
+platform. The location of the buffer and size are set with
+``CONFIG_FASTBOOT_BUF_ADDR`` and ``CONFIG_FASTBOOT_BUF_SIZE``. These
+may be overridden on the fastboot command line using ``-l`` and
+``-s``.
+
+Fastboot environment variables
+------------------------------
+
+Partition aliases
+^^^^^^^^^^^^^^^^^
+
+Fastboot partition aliases can also be defined for devices where GPT
+limitations prevent user-friendly partition names such as ``boot``, ``system``
+and ``cache``. Or, where the actual partition name doesn't match a standard
+partition name used commonly with fastboot.
+
+The current implementation checks aliases when accessing partitions by
+name (flash_write and erase functions). To define a partition alias
+add an environment variable similar to::
+
+ fastboot_partition_alias_<alias partition name>=<actual partition name>
+
+for example::
+
+ fastboot_partition_alias_boot=LNX
+
+Variable overrides
+^^^^^^^^^^^^^^^^^^
+
+Variables retrived through ``getvar`` can be overridden by defining
+environment variables of the form ``fastboot.<variable>``. These are
+looked up first so can be used to override values which would
+otherwise be returned. Using this mechanism you can also return types
+for NAND filesystems, as the fully parameterised variable is looked
+up, e.g.::
+
+ fastboot.partition-type:boot=jffs2
+
+Boot command
+^^^^^^^^^^^^
+
+When executing the fastboot ``boot`` command, if ``fastboot_bootcmd`` is set
+then that will be executed in place of ``bootm <CONFIG_FASTBOOT_BUF_ADDR>``.
+
+Partition Names
+---------------
+
+The Fastboot implementation in U-Boot allows to write images into disk
+partitions. Target partitions are referred on the host computer by
+their names.
+
+For GPT/EFI the respective partition name is used.
+
+For MBR the partitions are referred by generic names according to the
+following schema::
+
+ <device type><device index letter><partition index>
+
+Example: ``hda3``, ``sdb1``, ``usbda1``.
+
+The device type is as follows:
+
+ * IDE, ATAPI and SATA disks: ``hd``
+ * SCSI disks: ``sd``
+ * USB media: ``usbd``
+ * MMC and SD cards: ``mmcsd``
+ * Disk on chip: ``docd``
+ * other: ``xx``
+
+The device index starts from ``a`` and refers to the interface (e.g. USB
+controller, SD/MMC controller) or disk index. The partition index starts
+from ``1`` and describes the partition number on the particular device.
+
+Writing Partition Table
+-----------------------
+
+Fastboot also allows to write the partition table to the media. This can be
+done by writing the respective partition table image to a special target
+"gpt" or "mbr". These names can be customized by defining the following
+configuration options:
+
+::
+
+ CONFIG_FASTBOOT_GPT_NAME
+ CONFIG_FASTBOOT_MBR_NAME
+
+In Action
+---------
+
+Enter into fastboot by executing the fastboot command in U-Boot for either USB::
+
+ => fastboot usb 0
+
+or UDP::
+
+ => fastboot udp
+ link up on port 0, speed 100, full duplex
+ Using ethernet@4a100000 device
+ Listening for fastboot command on 192.168.0.102
+
+On the client side you can fetch the bootloader version for instance::
+
+ $ fastboot getvar version-bootloader
+ version-bootloader: U-Boot 2019.07-rc4-00240-g00c9f2a2ec
+ Finished. Total time: 0.005s
+
+or initiate a reboot::
+
+ $ fastboot reboot
+
+and once the client comes back, the board should reset.
+
+You can also specify a kernel image to boot. You have to either specify
+the an image in Android format *or* pass a binary kernel and let the
+fastboot client wrap the Android suite around it. On OMAP for instance you
+take zImage kernel and pass it to the fastboot client::
+
+ $ fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0 mem=128M" boot zImage
+ creating boot image...
+ creating boot image - 1847296 bytes
+ downloading 'boot.img'...
+ OKAY [ 2.766s]
+ booting...
+ OKAY [ -0.000s]
+ finished. total time: 2.766s
+
+and on the U-Boot side you should see::
+
+ Starting download of 1847296 bytes
+ ........................................................
+ downloading of 1847296 bytes finished
+ Booting kernel..
+ ## Booting Android Image at 0x81000000 ...
+ Kernel load addr 0x80008000 size 1801 KiB
+ Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0 mem=128M
+ Loading Kernel Image ... OK
+ OK
+
+ Starting kernel ...
+
+References
+----------
+
+.. [1] :doc:`fastboot-protocol`
+.. [2] https://developer.android.com/studio/releases/platform-tools
+++ /dev/null
-================
-Android Fastboot
-================
-
-Overview
-========
-
-The protocol that is used over USB and UDP is described in
-``doc/android/fastboot-protocol.txt``.
-
-The current implementation supports the following standard commands:
-
-- ``boot``
-- ``continue``
-- ``download``
-- ``erase`` (if enabled)
-- ``flash`` (if enabled)
-- ``getvar``
-- ``reboot``
-- ``reboot-bootloader``
-- ``set_active`` (only a stub implementation which always succeeds)
-
-The following OEM commands are supported (if enabled):
-
-- oem format - this executes ``gpt write mmc %x $partitions``
-
-Support for both eMMC and NAND devices is included.
-
-Client installation
-===================
-
-The counterpart to this is the fastboot client which can be found in
-Android's ``platform/system/core`` repository in the fastboot
-folder. It runs on Windows, Linux and OSX. The fastboot client is
-part of the Android SDK Platform-Tools and can be downloaded from:
-
-https://developer.android.com/studio/releases/platform-tools
-
-Board specific
-==============
-
-USB configuration
------------------
-
-The fastboot gadget relies on the USB download gadget, so the following
-options must be configured:
-
-::
-
- CONFIG_USB_GADGET_DOWNLOAD
- CONFIG_USB_GADGET_VENDOR_NUM
- CONFIG_USB_GADGET_PRODUCT_NUM
- CONFIG_USB_GADGET_MANUFACTURER
-
-NOTE: The ``CONFIG_USB_GADGET_VENDOR_NUM`` must be one of the numbers
-supported by the fastboot client. The list of vendor IDs supported can
-be found in the fastboot client source code.
-
-General configuration
----------------------
-
-The fastboot protocol requires a large memory buffer for
-downloads. This buffer should be as large as possible for a
-platform. The location of the buffer and size are set with
-``CONFIG_FASTBOOT_BUF_ADDR`` and ``CONFIG_FASTBOOT_BUF_SIZE``. These
-may be overridden on the fastboot command line using ``-l`` and
-``-s``.
-
-Fastboot environment variables
-==============================
-
-Partition aliases
------------------
-
-Fastboot partition aliases can also be defined for devices where GPT
-limitations prevent user-friendly partition names such as "boot", "system"
-and "cache". Or, where the actual partition name doesn't match a standard
-partition name used commonly with fastboot.
-
-The current implementation checks aliases when accessing partitions by
-name (flash_write and erase functions). To define a partition alias
-add an environment variable similar to:
-
-``fastboot_partition_alias_<alias partition name>=<actual partition name>``
-
-for example:
-
-``fastboot_partition_alias_boot=LNX``
-
-Variable overrides
-------------------
-
-Variables retrived through ``getvar`` can be overridden by defining
-environment variables of the form ``fastboot.<variable>``. These are
-looked up first so can be used to override values which would
-otherwise be returned. Using this mechanism you can also return types
-for NAND filesystems, as the fully parameterised variable is looked
-up, e.g.
-
-``fastboot.partition-type:boot=jffs2``
-
-Boot command
-------------
-
-When executing the fastboot ``boot`` command, if ``fastboot_bootcmd`` is set then
-that will be executed in place of ``bootm <CONFIG_FASTBOOT_BUF_ADDR>``.
-
-Partition Names
-===============
-
-The Fastboot implementation in U-Boot allows to write images into disk
-partitions. Target partitions are referred on the host computer by
-their names.
-
-For GPT/EFI the respective partition name is used.
-
-For MBR the partitions are referred by generic names according to the
-following schema:
-
- <device type><device index letter><partition index>
-
-Example: ``hda3``, ``sdb1``, ``usbda1``
-
-The device type is as follows:
-
- * IDE, ATAPI and SATA disks: ``hd``
- * SCSI disks: ``sd``
- * USB media: ``usbd``
- * MMC and SD cards: ``mmcsd``
- * Disk on chip: ``docd``
- * other: ``xx``
-
-The device index starts from ``a`` and refers to the interface (e.g. USB
-controller, SD/MMC controller) or disk index. The partition index starts
-from ``1`` and describes the partition number on the particular device.
-
-Writing Partition Table
-=======================
-
-Fastboot also allows to write the partition table to the media. This can be
-done by writing the respective partition table image to a special target
-"gpt" or "mbr". These names can be customized by defining the following
-configuration options:
-
-::
-
- CONFIG_FASTBOOT_GPT_NAME
- CONFIG_FASTBOOT_MBR_NAME
-
-In Action
-=========
-
-Enter into fastboot by executing the fastboot command in U-Boot for either USB:
-
-::
-
- => fastboot usb 0
-
-or UDP:
-
-::
-
- => fastboot udp
- link up on port 0, speed 100, full duplex
- Using ethernet@4a100000 device
- Listening for fastboot command on 192.168.0.102
-
-On the client side you can fetch the bootloader version for instance:
-
-::
-
- $ fastboot getvar version-bootloader
- version-bootloader: U-Boot 2019.07-rc4-00240-g00c9f2a2ec
- Finished. Total time: 0.005s
-
-or initiate a reboot:
-
-::
-
- $ fastboot reboot
-
-and once the client comes back, the board should reset.
-
-You can also specify a kernel image to boot. You have to either specify
-the an image in Android format *or* pass a binary kernel and let the
-fastboot client wrap the Android suite around it. On OMAP for instance you
-take zImage kernel and pass it to the fastboot client:
-
-::
-
- $ fastboot -b 0x80000000 -c "console=ttyO2 earlyprintk root=/dev/ram0 mem=128M" boot zImage
- creating boot image...
- creating boot image - 1847296 bytes
- downloading 'boot.img'...
- OKAY [ 2.766s]
- booting...
- OKAY [ -0.000s]
- finished. total time: 2.766s
-
-and on the U-Boot side you should see:
-
-::
-
- Starting download of 1847296 bytes
- ........................................................
- downloading of 1847296 bytes finished
- Booting kernel..
- ## Booting Android Image at 0x81000000 ...
- Kernel load addr 0x80008000 size 1801 KiB
- Kernel command line: console=ttyO2 earlyprintk root=/dev/ram0 mem=128M
- Loading Kernel Image ... OK
- OK
-
- Starting kernel ...
--- /dev/null
+.. SPDX-License-Identifier: GPL-2.0+
+
+Android-specific doc
+====================
+
+.. toctree::
+ :maxdepth: 2
+
+ ab
+ avb2
+ bcb
+ boot-image
+ fastboot-protocol
+ fastboot
Boot flow - U-Boot post-relocation
----------------------------------
+----------------------------------
U-Boot starts up normally, running near the top of RAM. After driver model is
running, arch_fsp_init_r() is called which loads and runs the FSP-S binary.
-----------
Bootstage is used through all phases of U-Boot to keep accurate timimgs for
-boot. Use 'bootstage report' in U-Boot to see the report, e.g.:
-
-Timer summary in microseconds (16 records):
- Mark Elapsed Stage
- 0 0 reset
- 155,325 155,325 TPL
- 204,014 48,689 end TPL
- 204,385 371 SPL
- 738,633 534,248 end SPL
- 739,161 528 board_init_f
- 842,764 103,603 board_init_r
- 1,166,233 323,469 main_loop
- 1,166,283 50 id=175
-
-Accumulated time:
- 62 fast_spi
- 202 dm_r
- 7,779 dm_spl
- 15,555 dm_f
- 208,357 fsp-m
- 239,847 fsp-s
- 292,143 mmap_spi
-
-CPU performance is about 3500 DMIPS:
-
-=> dhry
-1000000 iterations in 161 ms: 6211180/s, 3535 DMIPS
+boot. Use 'bootstage report' in U-Boot to see the report, e.g.::
+
+ Timer summary in microseconds (16 records):
+ Mark Elapsed Stage
+ 0 0 reset
+ 155,325 155,325 TPL
+ 204,014 48,689 end TPL
+ 204,385 371 SPL
+ 738,633 534,248 end SPL
+ 739,161 528 board_init_f
+ 842,764 103,603 board_init_r
+ 1,166,233 323,469 main_loop
+ 1,166,283 50 id=175
+
+ Accumulated time:
+ 62 fast_spi
+ 202 dm_r
+ 7,779 dm_spl
+ 15,555 dm_f
+ 208,357 fsp-m
+ 239,847 fsp-s
+ 292,143 mmap_spi
+
+CPU performance is about 3500 DMIPS::
+
+ => dhry
+ 1000000 iterations in 161 ms: 6211180/s, 3535 DMIPS
Partial memory map
------------------
-ffffffff Top of ROM (and last byte of 32-bit address space)
-ffff8000 TPL loaded here (from IFWI)
-ff000000 Bottom of ROM
-fefc000 Top of CAR region
-fef96000 Stack for FSP-M
-fef40000 59000 FSP-M
-fef11000 SPL loaded here
-fef10000 CONFIG_BLOBLIST_ADDR
-fef10000 Stack top in TPL, SPL and U-Boot before relocation
-fef00000 1000 CONFIG_BOOTSTAGE_STASH_ADDR
-fef00000 Base of CAR region
-
- f0000 CONFIG_ROM_TABLE_ADDR
- 120000 BSS (defined in u-boot-spl.lds)
- 200000 FSP-S (which is run after U-Boot is relocated)
- 1110000 CONFIG_SYS_TEXT_BASE
+::
+
+ ffffffff Top of ROM (and last byte of 32-bit address space)
+ ffff8000 TPL loaded here (from IFWI)
+ ff000000 Bottom of ROM
+ fefc000 Top of CAR region
+ fef96000 Stack for FSP-M
+ fef40000 59000 FSP-M
+ fef11000 SPL loaded here
+ fef10000 CONFIG_BLOBLIST_ADDR
+ fef10000 Stack top in TPL, SPL and U-Boot before relocation
+ fef00000 1000 CONFIG_BOOTSTAGE_STASH_ADDR
+ fef00000 Base of CAR region
+
+ f0000 CONFIG_ROM_TABLE_ADDR
+ 120000 BSS (defined in u-boot-spl.lds)
+ 200000 FSP-S (which is run after U-Boot is relocated)
+ 1110000 CONFIG_SYS_TEXT_BASE
Supported peripherals
Build Instruction for Slim Bootloader for LeafHill (APL) target
---------------------------------------------------------------
-LeafHill is using PCI UART2 device as a serial port.
-For MEM32 serial port, CONFIG_SYS_NS16550_MEM32 needs to be enabled in U-Boot.
+Prepare U-Boot and Slim Bootloader as described at the beginning of this page.
+Also, the PayloadId needs to be set for APL board.
-1. Enable CONFIG_SYS_NS16550_MEM32 in U-Boot::
-
- $ vi include/configs/slimbootloader.h
- +#define CONFIG_SYS_NS16550_MEM32
- #ifdef CONFIG_SYS_NS16550_MEM3
-
-2. Build U-Boot::
-
- $ make disclean
- $ make slimbootloader_defconfig
- $ make all
-
-3. Copy u-boot-dtb.bin to Slim Bootloader.
- Slim Bootloader looks for a payload from the specific location.
- Copy the build u-boot-dtb.bin to the expected location::
-
- $ mkdir -p <Slim Bootloader Dir>/PayloadPkg/PayloadBins/
- $ cp <U-Boot Dir>/u-boot-dtb.bin <Slim Bootloader Dir>/PayloadPkg/PayloadBins/u-boot-dtb.bin
-
-4. Update PayloadId. Let's use 'U-BT' as an example::
+1. Update PayloadId. Let's use 'U-BT' as an example::
$ vi Platform/ApollolakeBoardPkg/CfgData/CfgData_Int_LeafHill.dlt
-GEN_CFG_DATA.PayloadId | 'AUTO
+GEN_CFG_DATA.PayloadId | 'U-BT'
-5. Update payload text base.
+2. Update payload text base.
* PAYLOAD_EXE_BASE must be the same as U-Boot CONFIG_SYS_TEXT_BASE
in board/intel/slimbootloader/Kconfig.
+ self.PAYLOAD_LOAD_HIGH = 0
+ self.PAYLOAD_EXE_BASE = 0x00100000
-6. Build APL target. Make sure u-boot-dtb.bin and U-BT PayloadId
+3. Build APL target. Make sure u-boot-dtb.bin and U-BT PayloadId
in build command. The output is Outputs/apl/Stitch_Components.zip::
$ python BuildLoader.py build apl -p "OsLoader.efi:LLDR:Lz4;u-boot-dtb.bin:U-BT:Lzma"
-7. Stitch IFWI.
+4. Stitch IFWI.
Refer to Apollolake_ page in Slim Bootloader document site::
$ python Platform/ApollolakeBoardPkg/Script/StitchLoader.py -i <Existing IFWI> -s Outputs/apl/Stitch_Components.zip -o <Output IFWI>
-8. Flash IFWI.
+5. Flash IFWI.
Use DediProg to flash IFWI. You should reach at U-Boot serial console.
2. Build U-Boot::
- $ make disclean
+ $ make distclean
$ make slimbootloader_defconfig
$ make all
$ strip u-boot (removing symbol for reduced size)
board/index
+Android-specific doc
+--------------------
+
+These books provide information about booting the Android OS from U-Boot,
+manipulating Android images from U-Boot shell and discusses other
+Android-specific features available in U-Boot.
+
+.. toctree::
+ :maxdepth: 2
+
+ android/index
+
Indices and tables
==================
static unsigned char *dfu_file_buf;
static u64 dfu_file_buf_len;
-static long dfu_file_buf_filled;
+static u64 dfu_file_buf_offset;
static int mmc_block_op(enum dfu_op op, struct dfu_entity *dfu,
u64 offset, void *buf, long *len)
return 0;
}
-static int mmc_file_buffer(struct dfu_entity *dfu, void *buf, long *len)
-{
- if (dfu_file_buf_len + *len > CONFIG_SYS_DFU_MAX_FILE_SIZE) {
- dfu_file_buf_len = 0;
- return -EINVAL;
- }
-
- /* Add to the current buffer. */
- memcpy(dfu_file_buf + dfu_file_buf_len, buf, *len);
- dfu_file_buf_len += *len;
-
- return 0;
-}
-
static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu,
- void *buf, u64 *len)
+ u64 offset, void *buf, u64 *len)
{
char dev_part_str[8];
int ret;
switch (op) {
case DFU_OP_READ:
- ret = fs_read(dfu->name, (size_t)buf, 0, 0, &size);
+ ret = fs_read(dfu->name, (size_t)buf, offset, *len, &size);
if (ret) {
puts("dfu: fs_read error!\n");
return ret;
*len = size;
break;
case DFU_OP_WRITE:
- ret = fs_write(dfu->name, (size_t)buf, 0, *len, &size);
+ ret = fs_write(dfu->name, (size_t)buf, offset, *len, &size);
if (ret) {
puts("dfu: fs_write error!\n");
return ret;
return ret;
}
+static int mmc_file_buf_write(struct dfu_entity *dfu, u64 offset, void *buf, long *len)
+{
+ int ret = 0;
+
+ if (offset == 0) {
+ dfu_file_buf_len = 0;
+ dfu_file_buf_offset = 0;
+ }
+
+ /* Add to the current buffer. */
+ if (dfu_file_buf_len + *len > CONFIG_SYS_DFU_MAX_FILE_SIZE)
+ *len = CONFIG_SYS_DFU_MAX_FILE_SIZE - dfu_file_buf_len;
+ memcpy(dfu_file_buf + dfu_file_buf_len, buf, *len);
+ dfu_file_buf_len += *len;
+
+ if (dfu_file_buf_len == CONFIG_SYS_DFU_MAX_FILE_SIZE) {
+ ret = mmc_file_op(DFU_OP_WRITE, dfu, dfu_file_buf_offset,
+ dfu_file_buf, &dfu_file_buf_len);
+ dfu_file_buf_offset += dfu_file_buf_len;
+ dfu_file_buf_len = 0;
+ }
+
+ return ret;
+}
+
+static int mmc_file_buf_write_finish(struct dfu_entity *dfu)
+{
+ int ret = mmc_file_op(DFU_OP_WRITE, dfu, dfu_file_buf_offset,
+ dfu_file_buf, &dfu_file_buf_len);
+
+ /* Now that we're done */
+ dfu_file_buf_len = 0;
+ dfu_file_buf_offset = 0;
+
+ return ret;
+}
+
int dfu_write_medium_mmc(struct dfu_entity *dfu,
u64 offset, void *buf, long *len)
{
break;
case DFU_FS_FAT:
case DFU_FS_EXT4:
- ret = mmc_file_buffer(dfu, buf, len);
+ ret = mmc_file_buf_write(dfu, offset, buf, len);
break;
default:
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
if (dfu->layout != DFU_RAW_ADDR) {
/* Do stuff here. */
- ret = mmc_file_op(DFU_OP_WRITE, dfu, dfu_file_buf,
- &dfu_file_buf_len);
-
- /* Now that we're done */
- dfu_file_buf_len = 0;
+ ret = mmc_file_buf_write_finish(dfu);
}
return ret;
return 0;
case DFU_FS_FAT:
case DFU_FS_EXT4:
- dfu_file_buf_filled = -1;
- ret = mmc_file_op(DFU_OP_SIZE, dfu, NULL, size);
+ ret = mmc_file_op(DFU_OP_SIZE, dfu, 0, NULL, size);
if (ret < 0)
return ret;
- if (*size > CONFIG_SYS_DFU_MAX_FILE_SIZE)
- return -1;
return 0;
default:
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
}
}
-static int mmc_file_unbuffer(struct dfu_entity *dfu, u64 offset, void *buf,
+
+static int mmc_file_buf_read(struct dfu_entity *dfu, u64 offset, void *buf,
long *len)
{
int ret;
- u64 file_len;
- if (dfu_file_buf_filled == -1) {
- ret = mmc_file_op(DFU_OP_READ, dfu, dfu_file_buf, &file_len);
+ if (offset == 0 || offset >= dfu_file_buf_offset + dfu_file_buf_len ||
+ offset + *len < dfu_file_buf_offset) {
+ u64 file_len = CONFIG_SYS_DFU_MAX_FILE_SIZE;
+
+ ret = mmc_file_op(DFU_OP_READ, dfu, offset, dfu_file_buf,
+ &file_len);
if (ret < 0)
return ret;
- dfu_file_buf_filled = file_len;
+ dfu_file_buf_len = file_len;
+ dfu_file_buf_offset = offset;
}
- if (offset + *len > dfu_file_buf_filled)
+ if (offset + *len > dfu_file_buf_offset + dfu_file_buf_len)
return -EINVAL;
/* Add to the current buffer. */
- memcpy(buf, dfu_file_buf + offset, *len);
+ memcpy(buf, dfu_file_buf + offset - dfu_file_buf_offset, *len);
return 0;
}
break;
case DFU_FS_FAT:
case DFU_FS_EXT4:
- ret = mmc_file_unbuffer(dfu, offset, buf, len);
+ ret = mmc_file_buf_read(dfu, offset, buf, len);
break;
default:
printf("%s: Layout (%s) not (yet) supported!\n", __func__,
static struct davinci_gpio *davinci_get_gpio_bank(struct udevice *dev, unsigned int offset)
{
struct davinci_gpio_bank *bank = dev_get_priv(dev);
- unsigned int addr;
+ unsigned long addr;
/*
* The device tree is not broken into banks but the infrastructure is
static const struct udevice_id davinci_gpio_ids[] = {
{ .compatible = "ti,dm6441-gpio" },
{ .compatible = "ti,k2g-gpio" },
+ { .compatible = "ti,keystone-gpio" },
{ }
};
struct udevice *pinctrl = dev_get_parent(dev);
uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset);
- pcr_clrsetbits32(dev, config_offset,
+ pcr_clrsetbits32(pinctrl, config_offset,
PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
- PAD_CFG0_TX_DISABLE,
+ PAD_CFG0_TX_DISABLE | PAD_CFG0_TX_STATE,
PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE |
(value ? PAD_CFG0_TX_STATE : 0));
if (!mode) {
rx_tx = reg & (PAD_CFG0_TX_DISABLE | PAD_CFG0_RX_DISABLE);
if (rx_tx == PAD_CFG0_TX_DISABLE)
- return mode & PAD_CFG0_RX_STATE_BIT ? 1 : 0;
+ return reg & PAD_CFG0_RX_STATE ? 1 : 0;
else if (rx_tx == PAD_CFG0_RX_DISABLE)
- return mode & PAD_CFG0_TX_STATE_BIT ? 1 : 0;
+ return reg & PAD_CFG0_TX_STATE ? 1 : 0;
}
return 0;
struct udevice *pinctrl = dev_get_parent(dev);
uint config_offset = intel_pinctrl_get_config_reg_addr(pinctrl, offset);
- pcr_clrsetbits32(dev, config_offset, PAD_CFG0_TX_STATE,
+ pcr_clrsetbits32(pinctrl, config_offset, PAD_CFG0_TX_STATE,
value ? PAD_CFG0_TX_STATE : 0);
return 0;
*
* TODO:
* 1. Support PCA957X_TYPE
- * 2. Support 24 gpio pins
- * 3. Support Polarity Inversion
+ * 2. Support Polarity Inversion
*/
#include <common.h>
ret = dm_i2c_read(dev, reg, val, 1);
} else if (info->gpio_count <= 16) {
ret = dm_i2c_read(dev, reg << 1, val, info->bank_count);
+ } else if (info->gpio_count <= 24) {
+ /* Auto increment */
+ ret = dm_i2c_read(dev, (reg << 2) | 0x80, val,
+ info->bank_count);
} else if (info->gpio_count == 40) {
/* Auto increment */
ret = dm_i2c_read(dev, (reg << 3) | 0x80, val,
ret = dm_i2c_write(dev, reg, val, 1);
} else if (info->gpio_count <= 16) {
ret = dm_i2c_write(dev, reg << 1, val, info->bank_count);
+ } else if (info->gpio_count <= 24) {
+ /* Auto increment */
+ ret = dm_i2c_write(dev, (reg << 2) | 0x80, val,
+ info->bank_count);
} else if (info->gpio_count == 40) {
/* Auto increment */
ret = dm_i2c_write(dev, (reg << 3) | 0x80, val, info->bank_count);
help
This driver supports the BCM6368 Ethernet MAC.
+config BCMGENET
+ bool "BCMGENET V5 support"
+ depends on DM_ETH
+ select PHYLIB
+ help
+ This driver supports the BCMGENET Ethernet MAC.
+
config DWC_ETH_QOS
bool "Synopsys DWC Ethernet QOS device support"
depends on DM_ETH
obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
obj-$(CONFIG_BCM6368_ETH) += bcm6368-eth.o
+obj-$(CONFIG_BCMGENET) += bcmgenet.o
obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Amit Singh Tomar <amittomer25@gmail.com>
+ *
+ * Driver for Broadcom GENETv5 Ethernet controller (as found on the RPi4)
+ * This driver is based on the Linux driver:
+ * drivers/net/ethernet/broadcom/genet/bcmgenet.c
+ * which is: Copyright (c) 2014-2017 Broadcom
+ *
+ * The hardware supports multiple queues (16 priority queues and one
+ * default queue), both for RX and TX. There are 256 DMA descriptors (both
+ * for TX and RX), and they live in MMIO registers. The hardware allows
+ * assigning descriptor ranges to queues, but we choose the most simple setup:
+ * All 256 descriptors are assigned to the default queue (#16).
+ * Also the Linux driver supports multiple generations of the MAC, whereas
+ * we only support v5, as used in the Raspberry Pi 4.
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <cpu_func.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <linux/err.h>
+#include <malloc.h>
+#include <miiphy.h>
+#include <net.h>
+#include <dm/of_access.h>
+#include <dm/ofnode.h>
+#include <linux/iopoll.h>
+#include <linux/sizes.h>
+#include <asm/dma-mapping.h>
+#include <wait_bit.h>
+
+/* Register definitions derived from Linux source */
+#define SYS_REV_CTRL 0x00
+
+#define SYS_PORT_CTRL 0x04
+#define PORT_MODE_EXT_GPHY 3
+
+#define GENET_SYS_OFF 0x0000
+#define SYS_RBUF_FLUSH_CTRL (GENET_SYS_OFF + 0x08)
+#define SYS_TBUF_FLUSH_CTRL (GENET_SYS_OFF + 0x0c)
+
+#define GENET_EXT_OFF 0x0080
+#define EXT_RGMII_OOB_CTRL (GENET_EXT_OFF + 0x0c)
+#define RGMII_LINK BIT(4)
+#define OOB_DISABLE BIT(5)
+#define RGMII_MODE_EN BIT(6)
+#define ID_MODE_DIS BIT(16)
+
+#define GENET_RBUF_OFF 0x0300
+#define RBUF_TBUF_SIZE_CTRL (GENET_RBUF_OFF + 0xb4)
+#define RBUF_CTRL (GENET_RBUF_OFF + 0x00)
+#define RBUF_ALIGN_2B BIT(1)
+
+#define GENET_UMAC_OFF 0x0800
+#define UMAC_MIB_CTRL (GENET_UMAC_OFF + 0x580)
+#define UMAC_MAX_FRAME_LEN (GENET_UMAC_OFF + 0x014)
+#define UMAC_MAC0 (GENET_UMAC_OFF + 0x00c)
+#define UMAC_MAC1 (GENET_UMAC_OFF + 0x010)
+#define UMAC_CMD (GENET_UMAC_OFF + 0x008)
+#define MDIO_CMD (GENET_UMAC_OFF + 0x614)
+#define UMAC_TX_FLUSH (GENET_UMAC_OFF + 0x334)
+#define MDIO_START_BUSY BIT(29)
+#define MDIO_READ_FAIL BIT(28)
+#define MDIO_RD (2 << 26)
+#define MDIO_WR BIT(26)
+#define MDIO_PMD_SHIFT 21
+#define MDIO_PMD_MASK 0x1f
+#define MDIO_REG_SHIFT 16
+#define MDIO_REG_MASK 0x1f
+
+#define CMD_TX_EN BIT(0)
+#define CMD_RX_EN BIT(1)
+#define UMAC_SPEED_10 0
+#define UMAC_SPEED_100 1
+#define UMAC_SPEED_1000 2
+#define UMAC_SPEED_2500 3
+#define CMD_SPEED_SHIFT 2
+#define CMD_SPEED_MASK 3
+#define CMD_SW_RESET BIT(13)
+#define CMD_LCL_LOOP_EN BIT(15)
+#define CMD_TX_EN BIT(0)
+#define CMD_RX_EN BIT(1)
+
+#define MIB_RESET_RX BIT(0)
+#define MIB_RESET_RUNT BIT(1)
+#define MIB_RESET_TX BIT(2)
+
+/* total number of Buffer Descriptors, same for Rx/Tx */
+#define TOTAL_DESCS 256
+#define RX_DESCS TOTAL_DESCS
+#define TX_DESCS TOTAL_DESCS
+
+#define DEFAULT_Q 0x10
+
+/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528.
+ * 1536 is multiple of 256 bytes
+ */
+#define ENET_BRCM_TAG_LEN 6
+#define ENET_PAD 8
+#define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + \
+ VLAN_HLEN + ENET_BRCM_TAG_LEN + \
+ ETH_FCS_LEN + ENET_PAD)
+
+/* Tx/Rx Dma Descriptor common bits */
+#define DMA_EN BIT(0)
+#define DMA_RING_BUF_EN_SHIFT 0x01
+#define DMA_RING_BUF_EN_MASK 0xffff
+#define DMA_BUFLENGTH_MASK 0x0fff
+#define DMA_BUFLENGTH_SHIFT 16
+#define DMA_RING_SIZE_SHIFT 16
+#define DMA_OWN 0x8000
+#define DMA_EOP 0x4000
+#define DMA_SOP 0x2000
+#define DMA_WRAP 0x1000
+#define DMA_MAX_BURST_LENGTH 0x8
+/* Tx specific DMA descriptor bits */
+#define DMA_TX_UNDERRUN 0x0200
+#define DMA_TX_APPEND_CRC 0x0040
+#define DMA_TX_OW_CRC 0x0020
+#define DMA_TX_DO_CSUM 0x0010
+#define DMA_TX_QTAG_SHIFT 7
+
+/* DMA rings size */
+#define DMA_RING_SIZE 0x40
+#define DMA_RINGS_SIZE (DMA_RING_SIZE * (DEFAULT_Q + 1))
+
+/* DMA descriptor */
+#define DMA_DESC_LENGTH_STATUS 0x00
+#define DMA_DESC_ADDRESS_LO 0x04
+#define DMA_DESC_ADDRESS_HI 0x08
+#define DMA_DESC_SIZE 12
+
+#define GENET_RX_OFF 0x2000
+#define GENET_RDMA_REG_OFF \
+ (GENET_RX_OFF + TOTAL_DESCS * DMA_DESC_SIZE)
+#define GENET_TX_OFF 0x4000
+#define GENET_TDMA_REG_OFF \
+ (GENET_TX_OFF + TOTAL_DESCS * DMA_DESC_SIZE)
+
+#define DMA_FC_THRESH_HI (RX_DESCS >> 4)
+#define DMA_FC_THRESH_LO 5
+#define DMA_FC_THRESH_VALUE ((DMA_FC_THRESH_LO << 16) | \
+ DMA_FC_THRESH_HI)
+
+#define DMA_XOFF_THRESHOLD_SHIFT 16
+
+#define TDMA_RING_REG_BASE \
+ (GENET_TDMA_REG_OFF + DEFAULT_Q * DMA_RING_SIZE)
+#define TDMA_READ_PTR (TDMA_RING_REG_BASE + 0x00)
+#define TDMA_CONS_INDEX (TDMA_RING_REG_BASE + 0x08)
+#define TDMA_PROD_INDEX (TDMA_RING_REG_BASE + 0x0c)
+#define DMA_RING_BUF_SIZE 0x10
+#define DMA_START_ADDR 0x14
+#define DMA_END_ADDR 0x1c
+#define DMA_MBUF_DONE_THRESH 0x24
+#define TDMA_FLOW_PERIOD (TDMA_RING_REG_BASE + 0x28)
+#define TDMA_WRITE_PTR (TDMA_RING_REG_BASE + 0x2c)
+
+#define RDMA_RING_REG_BASE \
+ (GENET_RDMA_REG_OFF + DEFAULT_Q * DMA_RING_SIZE)
+#define RDMA_WRITE_PTR (RDMA_RING_REG_BASE + 0x00)
+#define RDMA_PROD_INDEX (RDMA_RING_REG_BASE + 0x08)
+#define RDMA_CONS_INDEX (RDMA_RING_REG_BASE + 0x0c)
+#define RDMA_XON_XOFF_THRESH (RDMA_RING_REG_BASE + 0x28)
+#define RDMA_READ_PTR (RDMA_RING_REG_BASE + 0x2c)
+
+#define TDMA_REG_BASE (GENET_TDMA_REG_OFF + DMA_RINGS_SIZE)
+#define RDMA_REG_BASE (GENET_RDMA_REG_OFF + DMA_RINGS_SIZE)
+#define DMA_RING_CFG 0x00
+#define DMA_CTRL 0x04
+#define DMA_SCB_BURST_SIZE 0x0c
+
+#define RX_BUF_LENGTH 2048
+#define RX_TOTAL_BUFSIZE (RX_BUF_LENGTH * RX_DESCS)
+#define RX_BUF_OFFSET 2
+
+struct bcmgenet_eth_priv {
+ char rxbuffer[RX_TOTAL_BUFSIZE] __aligned(ARCH_DMA_MINALIGN);
+ void *mac_reg;
+ void *tx_desc_base;
+ void *rx_desc_base;
+ int tx_index;
+ int rx_index;
+ int c_index;
+ int phyaddr;
+ u32 interface;
+ u32 speed;
+ struct phy_device *phydev;
+ struct mii_dev *bus;
+};
+
+static void bcmgenet_umac_reset(struct bcmgenet_eth_priv *priv)
+{
+ u32 reg;
+
+ reg = readl(priv->mac_reg + SYS_RBUF_FLUSH_CTRL);
+ reg |= BIT(1);
+ writel(reg, (priv->mac_reg + SYS_RBUF_FLUSH_CTRL));
+ udelay(10);
+
+ reg &= ~BIT(1);
+ writel(reg, (priv->mac_reg + SYS_RBUF_FLUSH_CTRL));
+ udelay(10);
+
+ writel(0, (priv->mac_reg + SYS_RBUF_FLUSH_CTRL));
+ udelay(10);
+
+ writel(0, priv->mac_reg + UMAC_CMD);
+
+ writel(CMD_SW_RESET | CMD_LCL_LOOP_EN, priv->mac_reg + UMAC_CMD);
+ udelay(2);
+ writel(0, priv->mac_reg + UMAC_CMD);
+
+ /* clear tx/rx counter */
+ writel(MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT,
+ priv->mac_reg + UMAC_MIB_CTRL);
+ writel(0, priv->mac_reg + UMAC_MIB_CTRL);
+
+ writel(ENET_MAX_MTU_SIZE, priv->mac_reg + UMAC_MAX_FRAME_LEN);
+
+ /* init rx registers, enable ip header optimization */
+ reg = readl(priv->mac_reg + RBUF_CTRL);
+ reg |= RBUF_ALIGN_2B;
+ writel(reg, (priv->mac_reg + RBUF_CTRL));
+
+ writel(1, (priv->mac_reg + RBUF_TBUF_SIZE_CTRL));
+}
+
+static int bcmgenet_gmac_write_hwaddr(struct udevice *dev)
+{
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ uchar *addr = pdata->enetaddr;
+ u32 reg;
+
+ reg = addr[0] << 24 | addr[1] << 16 | addr[2] << 8 | addr[3];
+ writel_relaxed(reg, priv->mac_reg + UMAC_MAC0);
+
+ reg = addr[4] << 8 | addr[5];
+ writel_relaxed(reg, priv->mac_reg + UMAC_MAC1);
+
+ return 0;
+}
+
+static void bcmgenet_disable_dma(struct bcmgenet_eth_priv *priv)
+{
+ clrbits_32(priv->mac_reg + TDMA_REG_BASE + DMA_CTRL, DMA_EN);
+ clrbits_32(priv->mac_reg + RDMA_REG_BASE + DMA_CTRL, DMA_EN);
+
+ writel(1, priv->mac_reg + UMAC_TX_FLUSH);
+ udelay(10);
+ writel(0, priv->mac_reg + UMAC_TX_FLUSH);
+}
+
+static void bcmgenet_enable_dma(struct bcmgenet_eth_priv *priv)
+{
+ u32 dma_ctrl = (1 << (DEFAULT_Q + DMA_RING_BUF_EN_SHIFT)) | DMA_EN;
+
+ writel(dma_ctrl, priv->mac_reg + TDMA_REG_BASE + DMA_CTRL);
+
+ setbits_32(priv->mac_reg + RDMA_REG_BASE + DMA_CTRL, dma_ctrl);
+}
+
+static int bcmgenet_gmac_eth_send(struct udevice *dev, void *packet, int length)
+{
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+ void *desc_base = priv->tx_desc_base + priv->tx_index * DMA_DESC_SIZE;
+ u32 len_stat = length << DMA_BUFLENGTH_SHIFT;
+ ulong packet_aligned = rounddown((ulong)packet, ARCH_DMA_MINALIGN);
+ u32 prod_index, cons;
+ u32 tries = 100;
+
+ prod_index = readl(priv->mac_reg + TDMA_PROD_INDEX);
+
+ /* There is actually no reason for the rounding here, but the ARMv7
+ * implementation of flush_dcache_range() checks for aligned
+ * boundaries of the flushed range.
+ * Adjust them here to pass that check and avoid misleading messages.
+ */
+ flush_dcache_range(packet_aligned,
+ packet_aligned + roundup(length, ARCH_DMA_MINALIGN));
+
+ len_stat |= 0x3F << DMA_TX_QTAG_SHIFT;
+ len_stat |= DMA_TX_APPEND_CRC | DMA_SOP | DMA_EOP;
+
+ /* Set-up packet for transmission */
+ writel(lower_32_bits((ulong)packet), (desc_base + DMA_DESC_ADDRESS_LO));
+ writel(upper_32_bits((ulong)packet), (desc_base + DMA_DESC_ADDRESS_HI));
+ writel(len_stat, (desc_base + DMA_DESC_LENGTH_STATUS));
+
+ /* Increment index and start transmission */
+ if (++priv->tx_index >= TX_DESCS)
+ priv->tx_index = 0;
+
+ prod_index++;
+
+ /* Start Transmisson */
+ writel(prod_index, priv->mac_reg + TDMA_PROD_INDEX);
+
+ do {
+ cons = readl(priv->mac_reg + TDMA_CONS_INDEX);
+ } while ((cons & 0xffff) < prod_index && --tries);
+ if (!tries)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+/* Check whether all cache lines affected by an invalidate are within
+ * the buffer, to make sure we don't accidentally lose unrelated dirty
+ * data stored nearby.
+ * Alignment of the buffer start address will be checked in the implementation
+ * of invalidate_dcache_range().
+ */
+static void invalidate_dcache_check(unsigned long addr, size_t size,
+ size_t buffer_size)
+{
+ size_t inval_size = roundup(size, ARCH_DMA_MINALIGN);
+
+ if (unlikely(inval_size > buffer_size))
+ printf("WARNING: Cache invalidate area exceeds buffer size\n");
+
+ invalidate_dcache_range(addr, addr + inval_size);
+}
+
+static int bcmgenet_gmac_eth_recv(struct udevice *dev,
+ int flags, uchar **packetp)
+{
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+ void *desc_base = priv->rx_desc_base + priv->rx_index * DMA_DESC_SIZE;
+ u32 prod_index = readl(priv->mac_reg + RDMA_PROD_INDEX);
+ u32 length, addr;
+
+ if (prod_index == priv->c_index)
+ return -EAGAIN;
+
+ length = readl(desc_base + DMA_DESC_LENGTH_STATUS);
+ length = (length >> DMA_BUFLENGTH_SHIFT) & DMA_BUFLENGTH_MASK;
+ addr = readl(desc_base + DMA_DESC_ADDRESS_LO);
+
+ invalidate_dcache_check(addr, length, RX_BUF_LENGTH);
+
+ /* To cater for the IP header alignment the hardware does.
+ * This would actually not be needed if we don't program
+ * RBUF_ALIGN_2B
+ */
+ *packetp = (uchar *)(ulong)addr + RX_BUF_OFFSET;
+
+ return length - RX_BUF_OFFSET;
+}
+
+static int bcmgenet_gmac_free_pkt(struct udevice *dev, uchar *packet,
+ int length)
+{
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+
+ /* Tell the MAC we have consumed that last receive buffer. */
+ priv->c_index = (priv->c_index + 1) & 0xFFFF;
+ writel(priv->c_index, priv->mac_reg + RDMA_CONS_INDEX);
+
+ /* Forward our descriptor pointer, wrapping around if needed. */
+ if (++priv->rx_index >= RX_DESCS)
+ priv->rx_index = 0;
+
+ return 0;
+}
+
+static void rx_descs_init(struct bcmgenet_eth_priv *priv)
+{
+ char *rxbuffs = &priv->rxbuffer[0];
+ u32 len_stat, i;
+ void *desc_base = priv->rx_desc_base;
+
+ priv->c_index = 0;
+
+ len_stat = (RX_BUF_LENGTH << DMA_BUFLENGTH_SHIFT) | DMA_OWN;
+
+ for (i = 0; i < RX_DESCS; i++) {
+ writel(lower_32_bits((uintptr_t)&rxbuffs[i * RX_BUF_LENGTH]),
+ desc_base + i * DMA_DESC_SIZE + DMA_DESC_ADDRESS_LO);
+ writel(upper_32_bits((uintptr_t)&rxbuffs[i * RX_BUF_LENGTH]),
+ desc_base + i * DMA_DESC_SIZE + DMA_DESC_ADDRESS_HI);
+ writel(len_stat,
+ desc_base + i * DMA_DESC_SIZE + DMA_DESC_LENGTH_STATUS);
+ }
+}
+
+static void rx_ring_init(struct bcmgenet_eth_priv *priv)
+{
+ writel(DMA_MAX_BURST_LENGTH,
+ priv->mac_reg + RDMA_REG_BASE + DMA_SCB_BURST_SIZE);
+
+ writel(0x0, priv->mac_reg + RDMA_RING_REG_BASE + DMA_START_ADDR);
+ writel(0x0, priv->mac_reg + RDMA_READ_PTR);
+ writel(0x0, priv->mac_reg + RDMA_WRITE_PTR);
+ writel(RX_DESCS * DMA_DESC_SIZE / 4 - 1,
+ priv->mac_reg + RDMA_RING_REG_BASE + DMA_END_ADDR);
+
+ writel(0x0, priv->mac_reg + RDMA_PROD_INDEX);
+ writel(0x0, priv->mac_reg + RDMA_CONS_INDEX);
+ writel((RX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH,
+ priv->mac_reg + RDMA_RING_REG_BASE + DMA_RING_BUF_SIZE);
+ writel(DMA_FC_THRESH_VALUE, priv->mac_reg + RDMA_XON_XOFF_THRESH);
+ writel(1 << DEFAULT_Q, priv->mac_reg + RDMA_REG_BASE + DMA_RING_CFG);
+}
+
+static void tx_ring_init(struct bcmgenet_eth_priv *priv)
+{
+ writel(DMA_MAX_BURST_LENGTH,
+ priv->mac_reg + TDMA_REG_BASE + DMA_SCB_BURST_SIZE);
+
+ writel(0x0, priv->mac_reg + TDMA_RING_REG_BASE + DMA_START_ADDR);
+ writel(0x0, priv->mac_reg + TDMA_READ_PTR);
+ writel(0x0, priv->mac_reg + TDMA_WRITE_PTR);
+ writel(TX_DESCS * DMA_DESC_SIZE / 4 - 1,
+ priv->mac_reg + TDMA_RING_REG_BASE + DMA_END_ADDR);
+ writel(0x0, priv->mac_reg + TDMA_PROD_INDEX);
+ writel(0x0, priv->mac_reg + TDMA_CONS_INDEX);
+ writel(0x1, priv->mac_reg + TDMA_RING_REG_BASE + DMA_MBUF_DONE_THRESH);
+ writel(0x0, priv->mac_reg + TDMA_FLOW_PERIOD);
+ writel((TX_DESCS << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH,
+ priv->mac_reg + TDMA_RING_REG_BASE + DMA_RING_BUF_SIZE);
+
+ writel(1 << DEFAULT_Q, priv->mac_reg + TDMA_REG_BASE + DMA_RING_CFG);
+}
+
+static int bcmgenet_adjust_link(struct bcmgenet_eth_priv *priv)
+{
+ struct phy_device *phy_dev = priv->phydev;
+ u32 speed;
+
+ switch (phy_dev->speed) {
+ case SPEED_1000:
+ speed = UMAC_SPEED_1000;
+ break;
+ case SPEED_100:
+ speed = UMAC_SPEED_100;
+ break;
+ case SPEED_10:
+ speed = UMAC_SPEED_10;
+ break;
+ default:
+ printf("bcmgenet: Unsupported PHY speed: %d\n", phy_dev->speed);
+ return -EINVAL;
+ }
+
+ clrsetbits_32(priv->mac_reg + EXT_RGMII_OOB_CTRL, OOB_DISABLE,
+ RGMII_LINK | RGMII_MODE_EN | ID_MODE_DIS);
+
+ writel(speed << CMD_SPEED_SHIFT, (priv->mac_reg + UMAC_CMD));
+
+ return 0;
+}
+
+static int bcmgenet_gmac_eth_start(struct udevice *dev)
+{
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+ int ret;
+
+ priv->tx_desc_base = priv->mac_reg + GENET_TX_OFF;
+ priv->rx_desc_base = priv->mac_reg + GENET_RX_OFF;
+ priv->tx_index = 0x0;
+ priv->rx_index = 0x0;
+
+ bcmgenet_umac_reset(priv);
+
+ bcmgenet_gmac_write_hwaddr(dev);
+
+ /* Disable RX/TX DMA and flush TX queues */
+ bcmgenet_disable_dma(priv);
+
+ rx_ring_init(priv);
+ rx_descs_init(priv);
+
+ tx_ring_init(priv);
+
+ /* Enable RX/TX DMA */
+ bcmgenet_enable_dma(priv);
+
+ /* read PHY properties over the wire from generic PHY set-up */
+ ret = phy_startup(priv->phydev);
+ if (ret) {
+ printf("bcmgenet: PHY startup failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Update MAC registers based on PHY property */
+ ret = bcmgenet_adjust_link(priv);
+ if (ret) {
+ printf("bcmgenet: adjust PHY link failed: %d\n", ret);
+ return ret;
+ }
+
+ /* Enable Rx/Tx */
+ setbits_32(priv->mac_reg + UMAC_CMD, CMD_TX_EN | CMD_RX_EN);
+
+ return 0;
+}
+
+static int bcmgenet_phy_init(struct bcmgenet_eth_priv *priv, void *dev)
+{
+ struct phy_device *phydev;
+ int ret;
+
+ phydev = phy_connect(priv->bus, priv->phyaddr, dev, priv->interface);
+ if (!phydev)
+ return -ENODEV;
+
+ phydev->supported &= PHY_GBIT_FEATURES;
+ if (priv->speed) {
+ ret = phy_set_supported(priv->phydev, priv->speed);
+ if (ret)
+ return ret;
+ }
+ phydev->advertising = phydev->supported;
+
+ phy_connect_dev(phydev, dev);
+
+ priv->phydev = phydev;
+ phy_config(priv->phydev);
+
+ return 0;
+}
+
+static void bcmgenet_mdio_start(struct bcmgenet_eth_priv *priv)
+{
+ setbits_32(priv->mac_reg + MDIO_CMD, MDIO_START_BUSY);
+}
+
+static int bcmgenet_mdio_write(struct mii_dev *bus, int addr, int devad,
+ int reg, u16 value)
+{
+ struct udevice *dev = bus->priv;
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+ u32 val;
+
+ /* Prepare the read operation */
+ val = MDIO_WR | (addr << MDIO_PMD_SHIFT) |
+ (reg << MDIO_REG_SHIFT) | (0xffff & value);
+ writel_relaxed(val, priv->mac_reg + MDIO_CMD);
+
+ /* Start MDIO transaction */
+ bcmgenet_mdio_start(priv);
+
+ return wait_for_bit_32(priv->mac_reg + MDIO_CMD,
+ MDIO_START_BUSY, false, 20, true);
+}
+
+static int bcmgenet_mdio_read(struct mii_dev *bus, int addr, int devad, int reg)
+{
+ struct udevice *dev = bus->priv;
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+ u32 val;
+ int ret;
+
+ /* Prepare the read operation */
+ val = MDIO_RD | (addr << MDIO_PMD_SHIFT) | (reg << MDIO_REG_SHIFT);
+ writel_relaxed(val, priv->mac_reg + MDIO_CMD);
+
+ /* Start MDIO transaction */
+ bcmgenet_mdio_start(priv);
+
+ ret = wait_for_bit_32(priv->mac_reg + MDIO_CMD,
+ MDIO_START_BUSY, false, 20, true);
+ if (ret)
+ return ret;
+
+ val = readl_relaxed(priv->mac_reg + MDIO_CMD);
+
+ return val & 0xffff;
+}
+
+static int bcmgenet_mdio_init(const char *name, struct udevice *priv)
+{
+ struct mii_dev *bus = mdio_alloc();
+
+ if (!bus) {
+ debug("Failed to allocate MDIO bus\n");
+ return -ENOMEM;
+ }
+
+ bus->read = bcmgenet_mdio_read;
+ bus->write = bcmgenet_mdio_write;
+ snprintf(bus->name, sizeof(bus->name), name);
+ bus->priv = (void *)priv;
+
+ return mdio_register(bus);
+}
+
+/* We only support RGMII (as used on the RPi4). */
+static int bcmgenet_interface_set(struct bcmgenet_eth_priv *priv)
+{
+ phy_interface_t phy_mode = priv->interface;
+
+ switch (phy_mode) {
+ case PHY_INTERFACE_MODE_RGMII:
+ case PHY_INTERFACE_MODE_RGMII_RXID:
+ writel(PORT_MODE_EXT_GPHY, priv->mac_reg + SYS_PORT_CTRL);
+ break;
+ default:
+ printf("unknown phy mode: %d\n", priv->interface);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bcmgenet_eth_probe(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+ ofnode mdio_node;
+ const char *name;
+ u32 reg;
+ int ret;
+ u8 major;
+
+ priv->mac_reg = map_physmem(pdata->iobase, SZ_64K, MAP_NOCACHE);
+ priv->interface = pdata->phy_interface;
+ priv->speed = pdata->max_speed;
+
+ /* Read GENET HW version */
+ reg = readl_relaxed(priv->mac_reg + SYS_REV_CTRL);
+ major = (reg >> 24) & 0x0f;
+ if (major != 6) {
+ if (major == 5)
+ major = 4;
+ else if (major == 0)
+ major = 1;
+
+ printf("Unsupported GENETv%d.%d\n", major, (reg >> 16) & 0x0f);
+ return -ENODEV;
+ }
+
+ ret = bcmgenet_interface_set(priv);
+ if (ret)
+ return ret;
+
+ writel(0, priv->mac_reg + SYS_RBUF_FLUSH_CTRL);
+ udelay(10);
+ /* disable MAC while updating its registers */
+ writel(0, priv->mac_reg + UMAC_CMD);
+ /* issue soft reset with (rg)mii loopback to ensure a stable rxclk */
+ writel(CMD_SW_RESET | CMD_LCL_LOOP_EN, priv->mac_reg + UMAC_CMD);
+
+ mdio_node = dev_read_first_subnode(dev);
+ name = ofnode_get_name(mdio_node);
+
+ ret = bcmgenet_mdio_init(name, dev);
+ if (ret)
+ return ret;
+
+ priv->bus = miiphy_get_dev_by_name(name);
+
+ return bcmgenet_phy_init(priv, dev);
+}
+
+static void bcmgenet_gmac_eth_stop(struct udevice *dev)
+{
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+
+ clrbits_32(priv->mac_reg + UMAC_CMD, CMD_TX_EN | CMD_RX_EN);
+
+ bcmgenet_disable_dma(priv);
+}
+
+static const struct eth_ops bcmgenet_gmac_eth_ops = {
+ .start = bcmgenet_gmac_eth_start,
+ .write_hwaddr = bcmgenet_gmac_write_hwaddr,
+ .send = bcmgenet_gmac_eth_send,
+ .recv = bcmgenet_gmac_eth_recv,
+ .free_pkt = bcmgenet_gmac_free_pkt,
+ .stop = bcmgenet_gmac_eth_stop,
+};
+
+static int bcmgenet_eth_ofdata_to_platdata(struct udevice *dev)
+{
+ struct eth_pdata *pdata = dev_get_platdata(dev);
+ struct bcmgenet_eth_priv *priv = dev_get_priv(dev);
+ struct ofnode_phandle_args phy_node;
+ const char *phy_mode;
+ int ret;
+
+ pdata->iobase = dev_read_addr(dev);
+
+ /* Get phy mode from DT */
+ pdata->phy_interface = -1;
+ phy_mode = dev_read_string(dev, "phy-mode");
+ if (phy_mode)
+ pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+ if (pdata->phy_interface == -1) {
+ debug("%s: Invalid PHY interface '%s'\n", __func__, phy_mode);
+ return -EINVAL;
+ }
+
+ ret = dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
+ &phy_node);
+ if (!ret) {
+ ofnode_read_s32(phy_node.node, "reg", &priv->phyaddr);
+ ofnode_read_s32(phy_node.node, "max-speed", &pdata->max_speed);
+ }
+
+ return 0;
+}
+
+/* The BCM2711 implementation has a limited burst length compared to a generic
+ * GENETv5 version, but we go with that shorter value (8) in both cases, for
+ * the sake of simplicity.
+ */
+static const struct udevice_id bcmgenet_eth_ids[] = {
+ {.compatible = "brcm,genet-v5"},
+ {.compatible = "brcm,bcm2711-genet-v5"},
+ {}
+};
+
+U_BOOT_DRIVER(eth_bcmgenet) = {
+ .name = "eth_bcmgenet",
+ .id = UCLASS_ETH,
+ .of_match = bcmgenet_eth_ids,
+ .ofdata_to_platdata = bcmgenet_eth_ofdata_to_platdata,
+ .probe = bcmgenet_eth_probe,
+ .ops = &bcmgenet_gmac_eth_ops,
+ .priv_auto_alloc_size = sizeof(struct bcmgenet_eth_priv),
+ .platdata_auto_alloc_size = sizeof(struct eth_pdata),
+ .flags = DM_FLAG_ALLOC_PRIV_DMA,
+};
#include <asm/intel_pinctrl.h>
#include <asm/intel_pinctrl_defs.h>
#include <asm/arch/gpio.h>
-#include <asm/arch/itss.h>
+#include <asm/itss.h>
#include <dm/device-internal.h>
#include <dt-bindings/gpio/gpio.h>
help
Select this to enable UART on BCM6345 SoCs.
+config COREBOOT_SERIAL
+ bool "Coreboot UART support"
+ depends on DM_SERIAL
+ default y if SYS_COREBOOT
+ select SYS_NS16550
+ help
+ Select this to enable a ns16550-style UART where the platform data
+ comes from the coreboot 'sysinfo' tables. This allows U-Boot to have
+ a serial console on any platform without needing to change the
+ device tree, etc.
+
config FSL_LINFLEXUART
bool "Freescale Linflex UART support"
depends on DM_SERIAL
be used. It can be a constant or a function to get clock, eg,
get_serial_clock().
+config NS16550_DYNAMIC
+ bool "Allow NS16550 to be configured at runtime"
+ default y if SYS_COREBOOT || SYS_SLIMBOOTLOADER
+ help
+ Enable this option to allow device-tree control of the driver.
+
+ Normally this driver is controlled by the following options:
+
+ CONFIG_SYS_NS16550_PORT_MAPPED - indicates that port I/O is used for
+ access. If not enabled, then the UART is memory-mapped.
+ CONFIG_SYS_NS16550_MEM32 - if memory-mapped, indicates that 32-bit
+ access should be used (instead of 8-bit)
+ CONFIG_SYS_NS16550_REG_SIZE - indicates register width and also
+ endianness. If positive, big-endian access is used. If negative,
+ little-endian is used.
+
+ It is not a good practice for a driver to be statically configured,
+ since it prevents the same driver being used for different types of
+ UARTs in a system. This option avoids this problem at the cost of a
+ slightly increased code size.
+
config INTEL_MID_SERIAL
bool "Intel MID platform UART support"
depends on DM_SERIAL && OF_CONTROL
obj-$(CONFIG_ARM_DCC) += arm_dcc.o
obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
obj-$(CONFIG_BCM6345_SERIAL) += serial_bcm6345.o
+obj-$(CONFIG_COREBOOT_SERIAL) += serial_coreboot.o
obj-$(CONFIG_EFI_APP) += serial_efi.o
obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o
obj-$(CONFIG_MCFUART) += mcfuart.o
#define CONFIG_SYS_NS16550_CLK 0
#endif
+/*
+ * Use this #ifdef for now since many platforms don't define in(), out(),
+ * out_le32(), etc. but we don't have #defines to indicate this.
+ *
+ * TODO(sjg@chromium.org): Add CONFIG options to indicate what I/O is available
+ * on a platform
+ */
+#ifdef CONFIG_NS16550_DYNAMIC
+static void serial_out_dynamic(struct ns16550_platdata *plat, u8 *addr,
+ int value)
+{
+ if (plat->flags & NS16550_FLAG_IO) {
+ outb(value, addr);
+ } else if (plat->reg_width == 4) {
+ if (plat->flags & NS16550_FLAG_ENDIAN) {
+ if (plat->flags & NS16550_FLAG_BE)
+ out_be32(addr, value);
+ else
+ out_le32(addr, value);
+ } else {
+ writel(value, addr);
+ }
+ } else if (plat->flags & NS16550_FLAG_BE) {
+ writeb(value, addr + (1 << plat->reg_shift) - 1);
+ } else {
+ writeb(value, addr);
+ }
+}
+
+static int serial_in_dynamic(struct ns16550_platdata *plat, u8 *addr)
+{
+ if (plat->flags & NS16550_FLAG_IO) {
+ return inb(addr);
+ } else if (plat->reg_width == 4) {
+ if (plat->flags & NS16550_FLAG_ENDIAN) {
+ if (plat->flags & NS16550_FLAG_BE)
+ return in_be32(addr);
+ else
+ return in_le32(addr);
+ } else {
+ return readl(addr);
+ }
+ } else if (plat->flags & NS16550_FLAG_BE) {
+ return readb(addr + (1 << plat->reg_shift) - 1);
+ } else {
+ return readb(addr);
+ }
+}
+#else
+static inline void serial_out_dynamic(struct ns16550_platdata *plat, u8 *addr,
+ int value)
+{
+}
+
+static inline int serial_in_dynamic(struct ns16550_platdata *plat, u8 *addr)
+{
+ return 0;
+}
+
+#endif /* CONFIG_NS16550_DYNAMIC */
+
static void ns16550_writeb(NS16550_t port, int offset, int value)
{
struct ns16550_platdata *plat = port->plat;
unsigned char *addr;
offset *= 1 << plat->reg_shift;
- addr = (unsigned char *)plat->base + offset;
+ addr = (unsigned char *)plat->base + offset + plat->reg_offset;
- /*
- * As far as we know it doesn't make sense to support selection of
- * these options at run-time, so use the existing CONFIG options.
- */
- serial_out_shift(addr + plat->reg_offset, plat->reg_shift, value);
+ if (IS_ENABLED(CONFIG_NS16550_DYNAMIC))
+ serial_out_dynamic(plat, addr, value);
+ else
+ serial_out_shift(addr, plat->reg_shift, value);
}
static int ns16550_readb(NS16550_t port, int offset)
unsigned char *addr;
offset *= 1 << plat->reg_shift;
- addr = (unsigned char *)plat->base + offset;
+ addr = (unsigned char *)plat->base + offset + plat->reg_offset;
- return serial_in_shift(addr + plat->reg_offset, plat->reg_shift);
+ if (IS_ENABLED(CONFIG_NS16550_DYNAMIC))
+ return serial_in_dynamic(plat, addr);
+ else
+ return serial_in_shift(addr, plat->reg_shift);
}
static u32 ns16550_getfcr(NS16550_t port)
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * UART support for U-Boot when launched from Coreboot
+ *
+ * Copyright 2019 Google LLC
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ns16550.h>
+#include <serial.h>
+#include <asm/arch/sysinfo.h>
+
+static int coreboot_ofdata_to_platdata(struct udevice *dev)
+{
+ struct ns16550_platdata *plat = dev_get_platdata(dev);
+ struct cb_serial *cb_info = lib_sysinfo.serial;
+
+ plat->base = cb_info->baseaddr;
+ plat->reg_shift = cb_info->regwidth == 4 ? 2 : 0;
+ plat->reg_width = cb_info->regwidth;
+ plat->clock = cb_info->input_hertz;
+ plat->fcr = UART_FCR_DEFVAL;
+ plat->flags = 0;
+ if (cb_info->type == CB_SERIAL_TYPE_IO_MAPPED)
+ plat->flags |= NS16550_FLAG_IO;
+
+ return 0;
+}
+
+static const struct udevice_id coreboot_serial_ids[] = {
+ { .compatible = "coreboot-serial" },
+ { },
+};
+
+U_BOOT_DRIVER(coreboot_uart) = {
+ .name = "coreboot_uart",
+ .id = UCLASS_SERIAL,
+ .of_match = coreboot_serial_ids,
+ .priv_auto_alloc_size = sizeof(struct NS16550),
+ .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
+ .ofdata_to_platdata = coreboot_ofdata_to_platdata,
+ .probe = ns16550_serial_probe,
+ .ops = &ns16550_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
return 0; /* ignore */
case SPINOR_OP_BE_4K:
cycle = HSFSTS_CYCLE_4K_ERASE;
- while (len) {
- uint xfer_len = 0x1000;
-
- ret = exec_sync_hwseq_xfer(regs, cycle, offset, 0);
- if (ret)
- return ret;
- offset += xfer_len;
- len -= xfer_len;
- }
- return 0;
+ ret = exec_sync_hwseq_xfer(regs, cycle, offset, 0);
+ return ret;
default:
debug("Unknown cycle %x\n", op->cmd.opcode);
return -EINVAL;
#include <linux/usb/otg.h>
#include <linux/usb/gadget.h>
+#include <phys2bus.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
#include <asm/io.h>
static const struct udevice_id dwc2_udc_otg_ids[] = {
{ .compatible = "snps,dwc2" },
+ { .compatible = "brcm,bcm2835-usb" },
{ .compatible = "st,stm32mp1-hsotg",
.data = (ulong)dwc2_set_stm32mp1_hsotg_params },
{},
{
u32 ep_ctrl;
- writel(usb_ctrl_dma_addr, ®->in_endp[EP0_CON].diepdma);
+ writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), ®->in_endp[EP0_CON].diepdma);
writel(DIEPT_SIZ_PKT_CNT(1), ®->in_endp[EP0_CON].dieptsiz);
ep_ctrl = readl(®->in_endp[EP0_CON].diepctl);
writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest),
®->out_endp[EP0_CON].doeptsiz);
- writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma);
+ writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), ®->out_endp[EP0_CON].doepdma);
ep_ctrl = readl(®->out_endp[EP0_CON].doepctl);
writel(ep_ctrl|DEPCTL_EPENA, ®->out_endp[EP0_CON].doepctl);
writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest),
®->out_endp[EP0_CON].doeptsiz);
- writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma);
+ writel(phys_to_bus((unsigned long)usb_ctrl_dma_addr), ®->out_endp[EP0_CON].doepdma);
ep_ctrl = readl(®->out_endp[EP0_CON].doepctl);
writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK,
(unsigned long) ep->dma_buf +
ROUND(ep->len, CONFIG_SYS_CACHELINE_SIZE));
- writel((unsigned long) ep->dma_buf, ®->out_endp[ep_num].doepdma);
+ writel(phys_to_bus((unsigned long)ep->dma_buf), ®->out_endp[ep_num].doepdma);
writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length),
®->out_endp[ep_num].doeptsiz);
writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->out_endp[ep_num].doepctl);
while (readl(®->grstctl) & TX_FIFO_FLUSH)
;
- writel((unsigned long) ep->dma_buf, ®->in_endp[ep_num].diepdma);
+ writel(phys_to_bus((unsigned long)ep->dma_buf), ®->in_endp[ep_num].diepdma);
writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length),
®->in_endp[ep_num].dieptsiz);
(unsigned long) usb_ctrl +
ROUND(sizeof(g_status), CONFIG_SYS_CACHELINE_SIZE));
- writel(usb_ctrl_dma_addr, ®->in_endp[EP0_CON].diepdma);
+ writel(phys_to_bus(usb_ctrl_dma_addr), ®->in_endp[EP0_CON].diepdma);
writel(DIEPT_SIZ_PKT_CNT(1) | DIEPT_SIZ_XFER_SIZE(2),
®->in_endp[EP0_CON].dieptsiz);
{
struct omap3_wdt_priv *priv = dev_get_priv(dev);
-/*
- * Somebody just triggered watchdog reset and write to WTGR register
- * is in progress. It is resetting right now, no need to trigger it
- * again
- */
+ /*
+ * Somebody just triggered watchdog reset and write to WTGR register
+ * is in progress. It is resetting right now, no need to trigger it
+ * again
+ */
if ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR)
return 0;
priv->wdt_trgr_pattern = ~(priv->wdt_trgr_pattern);
writel(priv->wdt_trgr_pattern, &priv->regs->wdtwtgr);
-/*
- * Don't wait for posted write to complete, i.e. don't check
- * WDT_WWPS_PEND_WTGR bit in WWPS register. There is no writes to
- * WTGR register outside of this func, and if entering it
- * we see WDT_WWPS_PEND_WTGR bit set, it means watchdog reset
- * was just triggered. This prevents us from wasting time in busy
- * polling of WDT_WWPS_PEND_WTGR bit.
- */
+ /*
+ * Don't wait for posted write to complete, i.e. don't check
+ * WDT_WWPS_PEND_WTGR bit in WWPS register. There is no writes to
+ * WTGR register outside of this func, and if entering it
+ * we see WDT_WWPS_PEND_WTGR bit set, it means watchdog reset
+ * was just triggered. This prevents us from wasting time in busy
+ * polling of WDT_WWPS_PEND_WTGR bit.
+ */
return 0;
}
{
struct omap3_wdt_priv *priv = dev_get_priv(dev);
-/* disable watchdog */
+ /* disable watchdog */
writel(0xAAAA, &priv->regs->wdtwspr);
while (readl(&priv->regs->wdtwwps) != 0x0)
;
static int omap3_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
{
struct omap3_wdt_priv *priv = dev_get_priv(dev);
- u32 pre_margin = GET_WLDR_VAL(timeout_ms);
-/*
- * Make sure the watchdog is disabled. This is unfortunately required
- * because writing to various registers with the watchdog running has no
- * effect.
- */
+ u32 pre_margin = GET_WLDR_VAL(timeout_ms / 1000);
+ /*
+ * Make sure the watchdog is disabled. This is unfortunately required
+ * because writing to various registers with the watchdog running has
+ * no effect.
+ */
omap3_wdt_stop(dev);
-/* initialize prescaler */
+ /* initialize prescaler */
while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WCLR)
;
writel(WDT_WCLR_PRE | (PTV << WDT_WCLR_PTV_OFF), &priv->regs->wdtwclr);
while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WCLR)
;
-/* just count up at 32 KHz */
+ /* just count up at 32 KHz */
while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WLDR)
;
writel(pre_margin, &priv->regs->wdtwldr);
while (readl(&priv->regs->wdtwwps) & WDT_WWPS_PEND_WLDR)
;
-/* Sequence to enable the watchdog */
+ /* Sequence to enable the watchdog */
writel(0xBBBB, &priv->regs->wdtwspr);
while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WSPR)
;
while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WSPR)
;
+ /* Trigger the watchdog to actually reload the counter. */
+ while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR)
+ ;
+
+ priv->wdt_trgr_pattern = ~(priv->wdt_trgr_pattern);
+ writel(priv->wdt_trgr_pattern, &priv->regs->wdtwtgr);
+
+ while ((readl(&priv->regs->wdtwwps)) & WDT_WWPS_PEND_WTGR)
+ ;
+
return 0;
}
#ifdef CONFIG_TARGET_J721E_A72_EVM
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SPL_TEXT_BASE + \
CONFIG_SYS_K3_NON_SECURE_MSRAM_SIZE)
+/* Image load address in RAM for DFU boot*/
+#define CONFIG_SPL_LOAD_FIT_ADDRESS 0x81000000
#else
/*
* Maximum size in memory allocated to the SPL BSS. Keep it as tight as
/* Configure R5 SPL post-relocation malloc pool in DDR */
#define CONFIG_SYS_SPL_MALLOC_START 0x84000000
#define CONFIG_SYS_SPL_MALLOC_SIZE SZ_16M
+/* Image load address in RAM for DFU boot*/
+#define CONFIG_SPL_LOAD_FIT_ADDRESS 0x80080000
#endif
#ifdef CONFIG_SYS_K3_SPL_ATF
#define CONFIG_TFTP_TSIZE
#endif
+/* DFU over USB/UDC */
+#ifdef CONFIG_CMD_DFU
+#define CONFIG_SYS_DFU_DATA_BUF_SIZE SZ_1M
+#define CONFIG_SYS_DFU_MAX_FILE_SIZE SZ_2M
+
+#ifdef CONFIG_ARM64
+#define KERNEL_FILENAME "Image"
+#else
+#define KERNEL_FILENAME "zImage"
+#endif
+
+#define ENV_DFU_SETTINGS \
+ "dfu_alt_info=u-boot.bin fat 0 1;uboot.env fat 0 1;" \
+ "config.txt fat 0 1;" \
+ KERNEL_FILENAME " fat 0 1\0"
+#else
+#define ENV_DFU_SETTINGS ""
+#endif
+
/* Console configuration */
#define CONFIG_SYS_CBSIZE 1024
#define CONFIG_EXTRA_ENV_SETTINGS \
"dhcpuboot=usb start; dhcp u-boot.uimg; bootm\0" \
ENV_DEVICE_SETTINGS \
+ ENV_DFU_SETTINGS \
ENV_MEM_LAYOUT_SETTINGS \
BOOTENV
#include <configs/x86-common.h>
-/*
- * By default, CONFIG_SYS_NS16550_PORT_MAPPED is enabled for port io serial.
- * To use mmio base serial, enable CONFIG_SYS_NS16550_MEM32 and disable
- * CONFIG_SYS_NS16550_PORT_MAPPED until ns16550 driver supports serial port
- * configuration in run-time.
- *
- * #define CONFIG_SYS_NS16550_MEM32
- * #undef CONFIG_SYS_NS16550_PORT_MAPPED
- */
-#ifdef CONFIG_SYS_NS16550_MEM32
-#undef CONFIG_SYS_NS16550_PORT_MAPPED
-#endif
-
#define CONFIG_STD_DEVICES_SETTINGS \
"stdin=serial,i8042-kbd,usbkbd\0" \
"stdout=serial\0" \
* seen large trees). We say all of this must be within the first 256MB
* as that will normally be within the kernel lowmem and thus visible via
* bootm_size and we only run on platforms with 256MB or more of memory.
+ *
+ * As a temporary storage for DTBO blobs (which should be applied into DTB
+ * blob), we use the location 15.5 MB above the ramdisk. If someone wants to
+ * use ramdisk bigger than 15.5 MB, then DTBO can be loaded and applied to DTB
+ * blob before loading the ramdisk, as DTBO location is only used as a temporary
+ * storage, and can be re-used after 'fdt apply' command is done.
*/
#define DEFAULT_LINUX_BOOT_ENV \
"loadaddr=0x82000000\0" \
"kernel_addr_r=0x82000000\0" \
"fdtaddr=0x88000000\0" \
+ "dtboaddr=0x89000000\0" \
"fdt_addr_r=0x88000000\0" \
"rdaddr=0x88080000\0" \
"ramdisk_addr_r=0x88080000\0" \
#define CONSOLEDEV "ttyS2"
#endif
-#define VBMETA_PART_SIZE (64 * 1024)
-
-#if defined(CONFIG_LIBAVB)
-#define VBMETA_PART \
- "name=vbmeta,size=" __stringify(VBMETA_PART_SIZE) \
- ",uuid=${uuid_gpt_vbmeta};"
-#else
-#define VBMETA_PART ""
-#endif
-
-#if defined(CONFIG_CMD_AB_SELECT)
-#define COMMON_PARTS \
- "name=boot_a,size=20M,uuid=${uuid_gpt_boot_a};" \
- "name=boot_b,size=20M,uuid=${uuid_gpt_boot_b};" \
- "name=system_a,size=1024M,uuid=${uuid_gpt_system_a};" \
- "name=system_b,size=1024M,uuid=${uuid_gpt_system_b};"
-#else
-#define COMMON_PARTS \
- "name=boot,size=20M,uuid=${uuid_gpt_boot};" \
- "name=system,size=1024M,uuid=${uuid_gpt_system};"
-#endif
-
#ifndef PARTS_DEFAULT
-/* Define the default GPT table for eMMC */
+/*
+ * Default GPT tables for eMMC (Linux and Android). Notes:
+ * 1. Keep partitions aligned to erase group size (512 KiB) when possible
+ * 2. Keep partitions in sync with DFU_ALT_INFO_EMMC (see dfu.h)
+ * 3. Keep 'bootloader' partition (U-Boot proper) start address in sync with
+ * CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR (see common/spl/Kconfig)
+ */
#define PARTS_DEFAULT \
/* Linux partitions */ \
"uuid_disk=${uuid_gpt_disk};" \
"name=bootloader,size=2048K,uuid=${uuid_gpt_bootloader};" \
"name=uboot-env,start=2432K,size=256K,uuid=${uuid_gpt_reserved};" \
"name=misc,size=128K,uuid=${uuid_gpt_misc};" \
- "name=recovery,size=40M,uuid=${uuid_gpt_recovery};" \
- COMMON_PARTS \
- "name=vendor,size=256M,uuid=${uuid_gpt_vendor};" \
- VBMETA_PART \
+ "name=boot_a,size=20M,uuid=${uuid_gpt_boot_a};" \
+ "name=boot_b,size=20M,uuid=${uuid_gpt_boot_b};" \
+ "name=dtbo_a,size=8M,uuid=${uuid_gpt_dtbo_a};" \
+ "name=dtbo_b,size=8M,uuid=${uuid_gpt_dtbo_b};" \
+ "name=vbmeta_a,size=64K,uuid=${uuid_gpt_vbmeta_a};" \
+ "name=vbmeta_b,size=64K,uuid=${uuid_gpt_vbmeta_b};" \
+ "name=recovery,size=64M,uuid=${uuid_gpt_recovery};" \
+ "name=super,size=2560M,uuid=${uuid_gpt_super};" \
+ "name=metadata,size=16M,uuid=${uuid_gpt_metadata};" \
"name=userdata,size=-,uuid=${uuid_gpt_userdata}"
#endif /* PARTS_DEFAULT */
"else " \
"echo AVB verification failed.;" \
"exit; fi;"
-#define AVB_VERIFY_CMD "avb_verify=avb init 1; avb verify;\0"
+#define AVB_VERIFY_CMD "avb_verify=avb init 1; avb verify $slot_suffix;\0"
#else
#define AVB_VERIFY_CHECK ""
#define AVB_VERIFY_CMD ""
#define CONTROL_PARTITION "misc"
#if defined(CONFIG_CMD_AB_SELECT)
-#define AB_SELECT \
+#define AB_SELECT_SLOT \
"if part number mmc 1 " CONTROL_PARTITION " control_part_number; " \
"then " \
"echo " CONTROL_PARTITION \
"echo " CONTROL_PARTITION " partition not found;" \
"exit;" \
"fi;" \
- "setenv slot_suffix _${slot_name};" \
- "if part number mmc ${mmcdev} system${slot_suffix} " \
- "system_part_number; then " \
- "setenv bootargs_ab " \
- "ro root=/dev/mmcblk${mmcdev}p${system_part_number} " \
- "rootwait init=/init skip_initramfs " \
- "androidboot.slot_suffix=${slot_suffix};" \
- "echo A/B cmdline addition: ${bootargs_ab};" \
- "setenv bootargs ${bootargs} ${bootargs_ab};" \
- "else " \
- "echo system${slot_suffix} partition not found;" \
- "fi;"
+ "setenv slot_suffix _${slot_name};"
+#define AB_SELECT_ARGS \
+ "setenv bootargs_ab androidboot.slot_suffix=${slot_suffix}; " \
+ "echo A/B cmdline addition: ${bootargs_ab};" \
+ "setenv bootargs ${bootargs} ${bootargs_ab};"
#else
-#define AB_SELECT ""
+#define AB_SELECT_SLOT ""
+#define AB_SELECT_ARGS ""
#endif
+/*
+ * Prepares complete device tree blob for current board (for Android boot).
+ *
+ * Boot image or recovery image should be loaded into $loadaddr prior to running
+ * these commands. The logic of these commnads is next:
+ *
+ * 1. Read correct DTB for current SoC/board from boot image in $loadaddr
+ * to $fdtaddr
+ * 2. Merge all needed DTBO for current board from 'dtbo' partition into read
+ * DTB
+ * 3. User should provide $fdtaddr as 3rd argument to 'bootm'
+ */
+#define PREPARE_FDT \
+ "echo Preparing FDT...; " \
+ "if test $board_name = am57xx_evm_reva3; then " \
+ "echo \" Reading DTBO partition...\"; " \
+ "part start mmc ${mmcdev} dtbo${slot_suffix} p_dtbo_start; " \
+ "part size mmc ${mmcdev} dtbo${slot_suffix} p_dtbo_size; " \
+ "mmc read ${dtboaddr} ${p_dtbo_start} ${p_dtbo_size}; " \
+ "echo \" Reading DTB for AM57x EVM RevA3...\"; " \
+ "abootimg get dtb --index=0 dtb_start dtb_size; " \
+ "cp.b $dtb_start $fdtaddr $dtb_size; " \
+ "fdt addr $fdtaddr; " \
+ "echo \" Applying DTBOs for AM57x EVM RevA3...\"; " \
+ "adtimg addr $dtboaddr; " \
+ "adtimg get dt --index=0 dtbo0_addr; " \
+ "fdt apply $dtbo0_addr; " \
+ "adtimg get dt --index=1 dtbo1_addr; " \
+ "fdt apply $dtbo1_addr; " \
+ "elif test $board_name = beagle_x15_revc; then " \
+ "echo \" Reading DTB for Beagle X15 RevC...\"; " \
+ "abootimg get dtb --index=0 dtb_start dtb_size; " \
+ "cp.b $dtb_start $fdtaddr $dtb_size; " \
+ "fdt addr $fdtaddr; " \
+ "else " \
+ "echo Error: Android boot is not supported for $board_name; " \
+ "exit; " \
+ "fi; " \
+
#define FASTBOOT_CMD \
"echo Booting into fastboot ...; " \
"fastboot " __stringify(CONFIG_FASTBOOT_USB_DEV) "; "
"setenv mmcroot /dev/mmcblk0p2 rw; " \
"run mmcboot;\0" \
"emmc_android_boot=" \
+ "setenv mmcdev 1; " \
+ "mmc dev $mmcdev; " \
+ "mmc rescan; " \
+ AB_SELECT_SLOT \
"if bcb load " __stringify(CONFIG_FASTBOOT_FLASH_MMC_DEV) " " \
CONTROL_PARTITION "; then " \
+ "setenv ardaddr -; " \
"if bcb test command = bootonce-bootloader; then " \
- "echo BCB: Bootloader boot...; " \
+ "echo Android: Bootloader boot...; " \
"bcb clear command; bcb store; " \
FASTBOOT_CMD \
+ "exit; " \
"elif bcb test command = boot-recovery; then " \
- "echo BCB: Recovery boot...; " \
- "echo Warning: recovery is not implemented; " \
- "echo Performing normal boot for now...; " \
- "bcb clear command; bcb store; " \
- "run emmc_android_normal_boot; " \
+ "echo Android: Recovery boot...; " \
+ "setenv ardaddr $loadaddr;" \
+ "setenv apart recovery; " \
"else " \
- "echo BCB: Normal boot requested...; " \
- "run emmc_android_normal_boot; " \
+ "echo Android: Normal boot...; " \
+ "setenv ardaddr $loadaddr; " \
+ "setenv apart boot${slot_suffix}; " \
"fi; " \
"else " \
"echo Warning: BCB is corrupted or does not exist; " \
- "echo Performing normal boot...; " \
- "run emmc_android_normal_boot; " \
- "fi;\0" \
- "emmc_android_normal_boot=" \
- "echo Trying to boot Android from eMMC ...; " \
- "run update_to_fit; " \
+ "echo Android: Normal boot...; " \
+ "fi; " \
"setenv eval_bootargs setenv bootargs $bootargs; " \
"run eval_bootargs; " \
- "setenv mmcdev 1; " \
"setenv machid fe6; " \
- "mmc dev $mmcdev; " \
- "mmc rescan; " \
AVB_VERIFY_CHECK \
- AB_SELECT \
- "if part start mmc ${mmcdev} boot${slot_suffix} boot_start; " \
- "then " \
- "part size mmc ${mmcdev} boot${slot_suffix} " \
- "boot_size; " \
- "mmc read ${loadaddr} ${boot_start} ${boot_size}; " \
- "bootm ${loadaddr}#${fdtfile}; " \
+ AB_SELECT_ARGS \
+ "if part start mmc $mmcdev $apart boot_start; then " \
+ "part size mmc $mmcdev $apart boot_size; " \
+ "mmc read $loadaddr $boot_start $boot_size; " \
+ PREPARE_FDT \
+ "bootm $loadaddr $ardaddr $fdtaddr; " \
"else " \
- "echo boot${slot_suffix} partition not found; " \
+ "echo $apart partition not found; " \
+ "exit; " \
"fi;\0"
#ifdef CONFIG_OMAP54XX
ulong *rd_data, ulong *rd_len);
int android_image_get_second(const struct andr_img_hdr *hdr,
ulong *second_data, ulong *second_len);
+bool android_image_get_dtbo(ulong hdr_addr, ulong *addr, u32 *size);
+bool android_image_get_dtb_by_index(ulong hdr_addr, u32 index, ulong *addr,
+ u32 *size);
ulong android_image_get_end(const struct andr_img_hdr *hdr);
ulong android_image_get_kload(const struct andr_img_hdr *hdr);
ulong android_image_get_kcomp(const struct andr_img_hdr *hdr);
void android_print_contents(const struct andr_img_hdr *hdr);
+#if !defined(CONFIG_SPL_BUILD)
+bool android_image_print_dtb_contents(ulong hdr_addr);
+#endif
#endif /* CONFIG_ANDROID_BOOT_IMAGE */
#define CONFIG_SYS_NS16550_REG_SIZE (-1)
#endif
+#ifdef CONFIG_NS16550_DYNAMIC
+#define UART_REG(x) unsigned char x
+#else
#if !defined(CONFIG_SYS_NS16550_REG_SIZE) || (CONFIG_SYS_NS16550_REG_SIZE == 0)
#error "Please define NS16550 registers size."
#elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_DM_SERIAL)
unsigned char x; \
unsigned char postpad_##x[-CONFIG_SYS_NS16550_REG_SIZE - 1];
#endif
+#endif /* CONFIG_NS16550_DYNAMIC */
+
+enum ns16550_flags {
+ NS16550_FLAG_IO = 1 << 0, /* Use I/O access (else mem-mapped) */
+ NS16550_FLAG_ENDIAN = 1 << 1, /* Use out_le/be_32() */
+ NS16550_FLAG_BE = 1 << 2, /* Big-endian access (else little) */
+};
/**
* struct ns16550_platdata - information about a NS16550 port
*
* @base: Base register address
- * @reg_width: IO accesses size of registers (in bytes)
+ * @reg_width: IO accesses size of registers (in bytes, 1 or 4)
* @reg_shift: Shift size of registers (0=byte, 1=16bit, 2=32bit...)
+ * @reg_offset: Offset to start of registers (normally 0)
* @clock: UART base clock speed in Hz
+ * @fcr: Offset of FCR register (normally UART_FCR_DEFVAL)
+ * @flags: A few flags (enum ns16550_flags)
* @bdf: PCI slot/function (pci_dev_t)
*/
struct ns16550_platdata {
int reg_offset;
int clock;
u32 fcr;
+ int flags;
#if defined(CONFIG_PCI) && defined(CONFIG_SPL)
int bdf;
#endif
--- /dev/null
+# SPDX-License-Identifier: GPL-2.0+
+# Copyright (c) 2020
+# Author: Sam Protsenko <joe.skb7@gmail.com>
+
+# Test U-Boot's "abootimg" commands.
+
+import os
+import pytest
+import u_boot_utils
+
+"""
+These tests rely on disk image (boot.img), which is automatically created by
+the test from the stored hex dump. This is done to avoid the dependency on the
+most recent mkbootimg tool from AOSP/master. Here is the list of commands which
+was used to generate the boot.img and obtain compressed hex dump from it:
+
+ $ echo '/dts-v1/; / { model = "x1"; compatible = "y1,z1"; };' > test1.dts
+ $ echo '/dts-v1/; / { model = "x2"; compatible = "y2,z2"; };' > test2.dts
+ $ dtc test1.dts > dt1.dtb
+ $ dtc test2.dts > dt2.dtb
+ $ cat dt1.dtb dt2.dtb > dtb.img
+ $ echo 'kernel payload' > kernel
+ $ echo 'ramdisk payload' > ramdisk.img
+ $ mkbootimg --kernel ./kernel --ramdisk ./ramdisk.img \
+ --cmdline "cmdline test" --dtb ./dtb.img \
+ --os_version R --os_patch_level 2019-06-05 \
+ --header_version 2 --output boot.img
+ $ gzip -9 boot.img
+ $ xxd -p boot.img.gz > boot.img.gz.hex
+
+Now one can obtain original boot.img from this hex dump like this:
+
+ $ xxd -r -p boot.img.gz.hex boot.img.gz
+ $ gunzip -9 boot.img.gz
+"""
+
+# boot.img.gz hex dump
+img_hex = """1f8b08084844af5d0203626f6f742e696d670073f47309f2f77451e46700
+820606010106301084501f04181819041838181898803c3346060c909c9b
+92939997aa50925a5cc2300a461c3078b2e1793c4b876fd92db97939fb6c
+b7762ffff07d345446c1281805e8a0868d81e117a45e111c0d8dc101b253
+8bf25273140a122b73f21353b8460364148c8251300a46c1281801a02831
+3725b3387bb401300a46c1281805a360148c207081f7df5b20550bc41640
+9c03c41a0c90f17fe85400986d82452b6c3680198a192a0ce17c3610ae34
+d4a9820881a70f3873f35352731892f3730b124b32937252a96bb9119ae5
+463a5546f82c1f05a360148c8251300a462e000085bf67f200200000"""
+# Expected response for "abootimg dtb_dump" command
+dtb_dump_resp="""## DTB area contents (concat format):
+ - DTB #0:
+ (DTB)size = 125
+ (DTB)model = x1
+ (DTB)compatible = y1,z1
+ - DTB #1:
+ (DTB)size = 125
+ (DTB)model = x2
+ (DTB)compatible = y2,z2"""
+# Address in RAM where to load the boot image ('abootimg' looks in $loadaddr)
+loadaddr = 0x1000
+# Expected DTB #1 offset from the boot image start address
+dtb1_offset = 0x187d
+# DTB #1 start address in RAM
+dtb1_addr = loadaddr + dtb1_offset
+
+class AbootimgTestDiskImage(object):
+ """Disk image used by abootimg tests."""
+
+ def __init__(self, u_boot_console):
+ """Initialize a new AbootimgDiskImage object.
+
+ Args:
+ u_boot_console: A U-Boot console.
+
+ Returns:
+ Nothing.
+ """
+
+ gz_hex = u_boot_console.config.persistent_data_dir + '/boot.img.gz.hex'
+ gz = u_boot_console.config.persistent_data_dir + '/boot.img.gz'
+
+ filename = 'boot.img'
+ persistent = u_boot_console.config.persistent_data_dir + '/' + filename
+ self.path = u_boot_console.config.result_dir + '/' + filename
+
+ with u_boot_utils.persistent_file_helper(u_boot_console.log, persistent):
+ if os.path.exists(persistent):
+ u_boot_console.log.action('Disk image file ' + persistent +
+ ' already exists')
+ else:
+ u_boot_console.log.action('Generating ' + persistent)
+
+ f = open(gz_hex, "w")
+ f.write(img_hex)
+ f.close()
+
+ cmd = ('xxd', '-r', '-p', gz_hex, gz)
+ u_boot_utils.run_and_log(u_boot_console, cmd)
+
+ cmd = ('gunzip', '-9', gz)
+ u_boot_utils.run_and_log(u_boot_console, cmd)
+
+ cmd = ('cp', persistent, self.path)
+ u_boot_utils.run_and_log(u_boot_console, cmd)
+
+gtdi = None
+@pytest.fixture(scope='function')
+def abootimg_disk_image(u_boot_console):
+ """pytest fixture to provide a AbootimgTestDiskImage object to tests.
+ This is function-scoped because it uses u_boot_console, which is also
+ function-scoped. However, we don't need to actually do any function-scope
+ work, so this simply returns the same object over and over each time."""
+
+ global gtdi
+ if not gtdi:
+ gtdi = AbootimgTestDiskImage(u_boot_console)
+ return gtdi
+
+@pytest.mark.boardspec('sandbox')
+@pytest.mark.buildconfigspec('android_boot_image')
+@pytest.mark.buildconfigspec('cmd_abootimg')
+@pytest.mark.buildconfigspec('cmd_fdt')
+@pytest.mark.requiredtool('xxd')
+@pytest.mark.requiredtool('gunzip')
+def test_abootimg(abootimg_disk_image, u_boot_console):
+ """Test the 'abootimg' command."""
+
+ u_boot_console.log.action('Loading disk image to RAM...')
+ u_boot_console.run_command('setenv loadaddr 0x%x' % (loadaddr))
+ u_boot_console.run_command('host load hostfs - 0x%x %s' % (loadaddr,
+ abootimg_disk_image.path))
+
+ u_boot_console.log.action('Testing \'abootimg get ver\'...')
+ response = u_boot_console.run_command('abootimg get ver')
+ assert response == "2"
+ u_boot_console.run_command('abootimg get ver v')
+ response = u_boot_console.run_command('env print v')
+ assert response == 'v=2'
+
+ u_boot_console.log.action('Testing \'abootimg get recovery_dtbo\'...')
+ response = u_boot_console.run_command('abootimg get recovery_dtbo a')
+ assert response == 'Error: recovery_dtbo_size is 0'
+
+ u_boot_console.log.action('Testing \'abootimg dump dtb\'...')
+ response = u_boot_console.run_command('abootimg dump dtb').replace('\r', '')
+ assert response == dtb_dump_resp
+
+ u_boot_console.log.action('Testing \'abootimg get dtb_load_addr\'...')
+ u_boot_console.run_command('abootimg get dtb_load_addr a')
+ response = u_boot_console.run_command('env print a')
+ assert response == 'a=11f00000'
+
+ u_boot_console.log.action('Testing \'abootimg get dtb --index\'...')
+ u_boot_console.run_command('abootimg get dtb --index=1 dtb1_start')
+ response = u_boot_console.run_command('env print dtb1_start')
+ correct_str = "dtb1_start=%x" % (dtb1_addr)
+ assert response == correct_str
+ u_boot_console.run_command('fdt addr $dtb1_start')
+ u_boot_console.run_command('fdt get value v / model')
+ response = u_boot_console.run_command('env print v')
+ assert response == 'v=x2'
This tests Android Verified Boot 2.0 support in U-boot:
For additional details about how to build proper vbmeta partition
-check doc/android/avb2.txt
+check doc/android/avb2.rst
For configuration verification:
- Corrupt boot partition and check for failure