board: Add Qualcomm Dragonboard 410C support
This commit add support for 96Boards Dragonboard410C.
It is board based on APQ8016 Qualcomm SoC, complying with
96boards specification.
Features (present out of the box):
- 4x Cortex A53 (ARMv8)
- 2x USB Host port
- 1x USB Device port
- 4x LEDs
- 1x HDMI connector
- 1x uSD connector
- 3x buttons (Power, Vol+, Vol-/Reset)
- WIFI, Bluetooth with integrated antenna
- 8GiB eMMC
U-Boot boots chained with fastboot in 64-bit mode.
For detailed build instructions see readme.txt in board directory.
Signed-off-by: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
Tested-by: Simon Glass <sjg@chromium.org>
diff --git a/board/qualcomm/dragonboard410c/Kconfig b/board/qualcomm/dragonboard410c/Kconfig
new file mode 100644
index 0000000..03bd7ae
--- /dev/null
+++ b/board/qualcomm/dragonboard410c/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_DRAGONBOARD410C
+
+config SYS_BOARD
+ default "dragonboard410c"
+
+config SYS_VENDOR
+ default "qualcomm"
+
+config SYS_SOC
+ default "apq8016"
+
+config SYS_CONFIG_NAME
+ default "dragonboard410c"
+
+endif
diff --git a/board/qualcomm/dragonboard410c/MAINTAINERS b/board/qualcomm/dragonboard410c/MAINTAINERS
new file mode 100644
index 0000000..65cb47c
--- /dev/null
+++ b/board/qualcomm/dragonboard410c/MAINTAINERS
@@ -0,0 +1,6 @@
+DRAGONBOARD410C BOARD
+M: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+S: Maintained
+F: board/qualcomm/dragonboard410c/
+F: include/configs/dragonboard410c.h
+F: configs/dragonboard410c_defconfig
diff --git a/board/qualcomm/dragonboard410c/Makefile b/board/qualcomm/dragonboard410c/Makefile
new file mode 100644
index 0000000..cd67808
--- /dev/null
+++ b/board/qualcomm/dragonboard410c/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-y := dragonboard410c.o
+extra-y += head.o
diff --git a/board/qualcomm/dragonboard410c/dragonboard410c.c b/board/qualcomm/dragonboard410c/dragonboard410c.c
new file mode 100644
index 0000000..1fa5664
--- /dev/null
+++ b/board/qualcomm/dragonboard410c/dragonboard410c.c
@@ -0,0 +1,131 @@
+/*
+ * Board init file for Dragonboard 410C
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <usb.h>
+#include <asm/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int dram_init(void)
+{
+ gd->ram_size = PHYS_SDRAM_1_SIZE;
+ return 0;
+}
+
+void dram_init_banksize(void)
+{
+ gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
+ gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
+}
+
+
+int board_prepare_usb(enum usb_init_type type)
+{
+ static struct udevice *pmic_gpio;
+ static struct gpio_desc hub_reset, usb_sel;
+ int ret = 0, node;
+
+ if (!pmic_gpio) {
+ ret = uclass_get_device_by_name(UCLASS_GPIO,
+ "pm8916_gpios@c000",
+ &pmic_gpio);
+ if (ret < 0) {
+ printf("Failed to find pm8916_gpios@c000 node.\n");
+ return ret;
+ }
+ }
+
+ /* Try to request gpios needed to start usb host on dragonboard */
+ if (!dm_gpio_is_valid(&hub_reset)) {
+ node = fdt_subnode_offset(gd->fdt_blob, pmic_gpio->of_offset,
+ "usb_hub_reset_pm");
+ if (node < 0) {
+ printf("Failed to find usb_hub_reset_pm dt node.\n");
+ return node;
+ }
+ ret = gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0,
+ &hub_reset, 0);
+ if (ret < 0) {
+ printf("Failed to request usb_hub_reset_pm gpio.\n");
+ return ret;
+ }
+ }
+
+ if (!dm_gpio_is_valid(&usb_sel)) {
+ node = fdt_subnode_offset(gd->fdt_blob, pmic_gpio->of_offset,
+ "usb_sw_sel_pm");
+ if (node < 0) {
+ printf("Failed to find usb_sw_sel_pm dt node.\n");
+ return 0;
+ }
+ ret = gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0,
+ &usb_sel, 0);
+ if (ret < 0) {
+ printf("Failed to request usb_sw_sel_pm gpio.\n");
+ return ret;
+ }
+ }
+
+ if (type == USB_INIT_HOST) {
+ /* Start USB Hub */
+ dm_gpio_set_dir_flags(&hub_reset,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ mdelay(100);
+ /* Switch usb to host connectors */
+ dm_gpio_set_dir_flags(&usb_sel,
+ GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+ mdelay(100);
+ } else { /* Device */
+ /* Disable hub */
+ dm_gpio_set_dir_flags(&hub_reset, GPIOD_IS_OUT);
+ /* Switch back to device connector */
+ dm_gpio_set_dir_flags(&usb_sel, GPIOD_IS_OUT);
+ }
+
+ return 0;
+}
+
+int board_init(void)
+{
+ return 0;
+}
+
+/* Check for vol- button - if pressed - stop autoboot */
+int misc_init_r(void)
+{
+ struct udevice *pon;
+ struct gpio_desc resin;
+ int node, ret;
+
+ ret = uclass_get_device_by_name(UCLASS_GPIO, "pm8916_pon@800", &pon);
+ if (ret < 0) {
+ printf("Failed to find PMIC pon node. Check device tree\n");
+ return 0;
+ }
+
+ node = fdt_subnode_offset(gd->fdt_blob, pon->of_offset, "key_vol_down");
+ if (node < 0) {
+ printf("Failed to find key_vol_down node. Check device tree\n");
+ return 0;
+ }
+
+ if (gpio_request_by_name_nodev(gd->fdt_blob, node, "gpios", 0, &resin,
+ 0)) {
+ printf("Failed to request key_vol_down button.\n");
+ return 0;
+ }
+
+ if (dm_gpio_get_value(&resin)) {
+ setenv("bootdelay", "-1");
+ printf("Power button pressed - dropping to console.\n");
+ }
+
+ return 0;
+}
diff --git a/board/qualcomm/dragonboard410c/head.S b/board/qualcomm/dragonboard410c/head.S
new file mode 100644
index 0000000..ba29b12
--- /dev/null
+++ b/board/qualcomm/dragonboard410c/head.S
@@ -0,0 +1,34 @@
+/*
+ * ARM64 header for proper chain-loading with Little Kernel.
+ *
+ * Little Kernel shipped with Dragonboard410C boots standard Linux images for
+ * ARM64. This file adds header that is required to boot U-Boot properly.
+ *
+ * For details see:
+ * https://www.kernel.org/doc/Documentation/arm64/booting.txt
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+
+.global _arm64_header
+_arm64_header:
+ b _start
+ .word 0
+ /* Image load offset from start of RAM, little-endian */
+ .quad CONFIG_SYS_TEXT_BASE-PHYS_SDRAM_1
+ /* Effective size of kernel image, little-endian */
+ .quad 0 /* 0x60000 - ignored */
+ /* Informative flags, little-endian */
+ .quad 0
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .quad 0 /* reserved */
+ .byte 0x41 /* Magic number, "ARM\x64" */
+ .byte 0x52
+ .byte 0x4d
+ .byte 0x64
+ .word 0 /* reserved */
diff --git a/board/qualcomm/dragonboard410c/readme.txt b/board/qualcomm/dragonboard410c/readme.txt
new file mode 100644
index 0000000..7fc7c7a
--- /dev/null
+++ b/board/qualcomm/dragonboard410c/readme.txt
@@ -0,0 +1,71 @@
+#
+# (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+Build & Run instructions:
+
+1) Install mkbootimg and dtbTool from
+ git://codeaurora.org/quic/kernel/skales (15ece94f09 worked for me)
+2) Setup CROSS_COMPILE to aarch64 compiler
+3) make dragonboard410c_config
+4) make
+5) generate fake, empty ramdisk (can have 0 bytes)
+$ touch rd
+
+6) Generate qualcomm device tree table with dtbTool [1]
+$ dtbTool -o dt.img arch/arm/dts
+
+7) Generate Android boot image with mkbootimg [2]:
+$ mkbootimg --kernel=u-boot-dtb.bin --output=u-boot.img --dt=dt.img \
+ --pagesize 2048 --base 0x80000000 --ramdisk=rd --cmdline=""
+
+8) Enter fastboot (reboot board with vol- button pressed)
+
+9) Boot it:
+$ fastboot boot u-boot.img
+or flash as kernel:
+$ fastboot flash boot u-boot.img
+$ fastboot reboot
+
+
+What is working:
+- UART
+- GPIO (SoC)
+- SD
+- eMMC
+- Reset
+- USB in EHCI mode (usb starts does switch device->host, usb stop does the opposite)
+- PMIC GPIOS (but not in generic subsystem)
+- PMIC "special" buttons (power, vol-)
+
+What is not working / known bugs:
+- SDHCI is slow (~2.5MiB/s for SD and eMMC)
+
+[1] To boot any kernel image, Little Kernel requires valid device tree for the
+platform it runs on. dtbTool creates device tree table that Little Kernel scans.
+Later on proper device tree is passed to next boot stage.
+Full device tree is not required to boot u-boot. Enough would be:
+/dts-v1/;
+
+/ {
+ model = "Qualcomm Technologies, Inc. Dragonboard 410c";
+ compatible = "qcom,dragonboard", "qcom,apq8016-sbc";
+ qcom,msm-id = <0xce 0x0 0xf8 0x0 0xf9 0x0 0xfa 0x0 0xf7 0x0>;
+ qcom,board-id = <0x10018 0x0>;
+ #address-cells = <0x2>;
+ #size-cells = <0x2>;
+ chosen { };
+ aliases { };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x80000000 0 0x3da00000>;
+ };
+};
+
+but for simplicity (and because size of image is not that critical) we use
+existing Qualcomm device trees.
+
+[2] Note that ramdisk is required, even if it is unused.
diff --git a/board/qualcomm/dragonboard410c/u-boot.lds b/board/qualcomm/dragonboard410c/u-boot.lds
new file mode 100644
index 0000000..6e1c5a8
--- /dev/null
+++ b/board/qualcomm/dragonboard410c/u-boot.lds
@@ -0,0 +1,90 @@
+/*
+ * Override linker script for fastboot-readable images
+ *
+ * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * Based on arch/arm/cpu/armv8/u-boot.lds (Just add header)
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+ENTRY(_arm64_header)
+SECTIONS
+{
+ . = 0x00000000;
+
+ . = ALIGN(8);
+ .text :
+ {
+ *(.__image_copy_start)
+ board/qualcomm/dragonboard410c/head.o (.text*)
+ CPUDIR/start.o (.text*)
+ *(.text*)
+ }
+
+ . = ALIGN(8);
+ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+
+ . = ALIGN(8);
+ .data : {
+ *(.data*)
+ }
+
+ . = ALIGN(8);
+
+ . = .;
+
+ . = ALIGN(8);
+ .u_boot_list : {
+ KEEP(*(SORT(.u_boot_list*)));
+ }
+
+ . = ALIGN(8);
+
+ .image_copy_end :
+ {
+ *(.__image_copy_end)
+ }
+
+ . = ALIGN(8);
+
+ .rel_dyn_start :
+ {
+ *(.__rel_dyn_start)
+ }
+
+ .rela.dyn : {
+ *(.rela*)
+ }
+
+ .rel_dyn_end :
+ {
+ *(.__rel_dyn_end)
+ }
+
+ _end = .;
+
+ . = ALIGN(8);
+
+ .bss_start : {
+ KEEP(*(.__bss_start));
+ }
+
+ .bss : {
+ *(.bss*)
+ . = ALIGN(8);
+ }
+
+ .bss_end : {
+ KEEP(*(.__bss_end));
+ }
+
+ /DISCARD/ : { *(.dynsym) }
+ /DISCARD/ : { *(.dynstr*) }
+ /DISCARD/ : { *(.dynamic*) }
+ /DISCARD/ : { *(.plt*) }
+ /DISCARD/ : { *(.interp*) }
+ /DISCARD/ : { *(.gnu*) }
+}