Commit 626f048b authored by Mateusz Kulikowski's avatar Mateusz Kulikowski Committed by Tom Rini

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: default avatarMateusz Kulikowski <mateusz.kulikowski@gmail.com>
Tested-by: default avatarSimon Glass <sjg@chromium.org>
parent 08592136
......@@ -107,6 +107,8 @@ dtb-$(CONFIG_FSL_LSCH2) += fsl-ls1043a-qds-duart.dtb \
fsl-ls1043a-qds-lpuart.dtb \
fsl-ls1043a-rdb.dtb
dtb-$(CONFIG_ARCH_SNAPDRAGON) += dragonboard410c.dtb
dtb-$(CONFIG_MACH_SUN4I) += \
sun4i-a10-a1000.dtb \
sun4i-a10-ba10-tvbox.dtb \
......
/*
* U-Boot addition to handle Dragonboard 410c pins
*
* (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
&pm8916_gpios {
usb_hub_reset_pm {
gpios = <&pm8916_gpios 2 0>;
};
usb_sw_sel_pm {
gpios = <&pm8916_gpios 3 0>;
};
};
&pm8916_pon {
key_vol_down {
gpios = <&pm8916_pon 1 0>;
};
key_power {
gpios = <&pm8916_pon 0 0>;
};
};
/*
* Qualcomm APQ8016 based Dragonboard 410C board device tree source
*
* (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
/dts-v1/;
#include "skeleton64.dtsi"
/ {
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>;
memory {
device_type = "memory";
reg = <0 0x80000000 0 0x3da00000>;
};
chosen {
stdout-path = "/soc/serial@78b0000";
};
soc {
#address-cells = <0x1>;
#size-cells = <0x1>;
ranges = <0x0 0x0 0x0 0xffffffff>;
compatible = "simple-bus";
clkc: qcom,gcc@1800000 {
compatible = "qcom,gcc-apq8016";
reg = <0x1800000 0x80000>;
#address-cells = <0x1>;
#size-cells = <0x0>;
};
serial@78b0000 {
compatible = "qcom,msm-uartdm-v1.4";
reg = <0x78b0000 0x200>;
u-boot,dm-pre-reloc;
clock = <&clkc 4>;
};
restart@4ab000 {
compatible = "qcom,pshold";
reg = <0x4ab000 0x4>;
};
soc_gpios: pinctrl@1000000 {
compatible = "qcom,apq8016-pinctrl";
reg = <0x1000000 0x300000>;
gpio-controller;
gpio-count = <122>;
gpio-bank-name="soc";
#gpio-cells = <1>;
};
ehci@78d9000 {
compatible = "qcom,ehci-host";
reg = <0x78d9000 0x400>;
};
sdhci@07824000 {
compatible = "qcom,sdhci-msm-v4";
reg = <0x7824900 0x11c 0x7824000 0x800>;
bus-width = <0x8>;
index = <0x0>;
non-removable;
clock = <&clkc 0>;
clock-frequency = <100000000>;
};
sdhci@07864000 {
compatible = "qcom,sdhci-msm-v4";
reg = <0x7864900 0x11c 0x7864000 0x800>;
index = <0x1>;
bus-width = <0x4>;
clock = <&clkc 1>;
clock-frequency = <200000000>;
};
spmi@200f000 {
compatible = "qcom,spmi-pmic-arb";
reg = <0x200f800 0x200 0x2400000 0x400000 0x2c00000 0x400000>;
#address-cells = <0x1>;
#size-cells = <0x1>;
pmic0: pm8916@0 {
compatible = "qcom,spmi-pmic";
reg = <0x0 0x1>;
#address-cells = <0x1>;
#size-cells = <0x1>;
pm8916_pon: pm8916_pon@800 {
compatible = "qcom,pm8916-pwrkey";
reg = <0x800 0x96>;
#gpio-cells = <2>;
gpio-controller;
};
pm8916_gpios: pm8916_gpios@c000 {
compatible = "qcom,pm8916-gpio";
reg = <0xc000 0x400>;
gpio-controller;
gpio-count = <4>;
#gpio-cells = <2>;
gpio-bank-name="pmic";
};
};
pmic1: pm8916@1 {
compatible = "qcom,spmi-pmic";
reg = <0x1 0x1>;
};
};
};
leds {
compatible = "gpio-leds";
user1 {
label = "green:user1";
gpios = <&soc_gpios 21 0>;
};
user2 {
label = "green:user2";
gpios = <&soc_gpios 120 0>;
};
user3 {
label = "green:user3";
gpios = <&pm8916_gpios 0 0>;
};
user4 {
label = "green:user4";
gpios = <&pm8916_gpios 1 0>;
};
};
};
#include "dragonboard410c-uboot.dtsi"
......@@ -3,4 +3,24 @@ if ARCH_SNAPDRAGON
config SYS_SOC
default "snapdragon"
choice
prompt "Snapdragon board select"
config TARGET_DRAGONBOARD410C
bool "96Boards Dragonboard 410C"
help
Support for 96Boards Dragonboard 410C. This board complies with
96Board Open Platform Specifications. Features:
- Qualcomm Snapdragon 410C SoC - APQ8016 (4xCortex A53, Adreno 306)
- 1GiB RAM
- 8GiB eMMC, uSD slot
- WiFi, Bluetooth and GPS module
- 2x Host, 1x Device USB port
- HDMI
- 20-pin low speed and 40-pin high speed expanders, 4 LED, 3 buttons
endchoice
source "board/qualcomm/dragonboard410c/Kconfig"
endif
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
DRAGONBOARD410C BOARD
M: Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
S: Maintained
F: board/qualcomm/dragonboard410c/
F: include/configs/dragonboard410c.h
F: configs/dragonboard410c_defconfig
#
# (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
#
# SPDX-License-Identifier: GPL-2.0+
#
obj-y := dragonboard410c.o
extra-y += head.o
/*
* 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;
}
/*
* 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 */
#
# (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.
/*
* 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*) }
}
CONFIG_ARM=y
CONFIG_ARCH_SNAPDRAGON=y
CONFIG_DEFAULT_DEVICE_TREE="dragonboard410c"
CONFIG_SYS_PROMPT="dragonboard410c => "
# CONFIG_CMD_IMI is not set
# CONFIG_CMD_IMLS is not set
CONFIG_CMD_USB=y
CONFIG_CLK=y
CONFIG_MSM_GPIO=y
CONFIG_PM8916_GPIO=y
CONFIG_LED=y
CONFIG_LED_GPIO=y
CONFIG_RESET=y
CONFIG_DM_MMC=y
CONFIG_MSM_SDHCI=y
CONFIG_DM_PMIC=y
CONFIG_PMIC_PM8916=y
CONFIG_MSM_SERIAL=y
CONFIG_SPMI_MSM=y
CONFIG_USB=y
CONFIG_DM_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_MSM=y
CONFIG_USB_ULPI_VIEWPORT=y
CONFIG_USB_ULPI=y
CONFIG_USB_STORAGE=y
/*
* Board configuration file for Dragonboard 410C
*
* (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#ifndef __CONFIGS_DRAGONBOARD410C_H
#define __CONFIGS_DRAGONBOARD410C_H
#include <linux/sizes.h>
#include <asm/arch/sysmap-apq8016.h>
#define CONFIG_IDENT_STRING "\nQualcomm-DragonBoard 410C"
#define CONFIG_MISC_INIT_R /* To stop autoboot */
/* Physical Memory Map */
#define CONFIG_NR_DRAM_BANKS 1
#define PHYS_SDRAM_1 0x80000000
/* 1008 MB (the last ~30Mb are secured for TrustZone by ATF*/
#define PHYS_SDRAM_1_SIZE 0x3da00000
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
#define CONFIG_SYS_TEXT_BASE 0x80080000
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x80000)
#define CONFIG_SYS_BOOTM_LEN 0x1000000 /* 16MB max kernel size */
/* UART */
#define CONFIG_BAUDRATE 115200
/* Generic Timer Definitions */
#define COUNTER_FREQUENCY 19000000
/* This are needed to have proper mmc support */
#define CONFIG_MMC
#define CONFIG_GENERIC_MMC
#define CONFIG_SDHCI
#define CONFIG_SYS_LDSCRIPT "board/qualcomm/dragonboard410c/u-boot.lds"
/* Fixup - in init code we switch from device to host mode,
* it has to be done after each HCD reset */
#define CONFIG_EHCI_HCD_INIT_AFTER_RESET
#define CONFIG_USB_HOST_ETHER /* Enable USB Networking */
/* Support all possible USB ethernet dongles */
#define CONFIG_USB_ETHER_DM9601
#define CONFIG_USB_ETHER_ASIX
#define CONFIG_USB_ETHER_ASIX88179
#define CONFIG_USB_ETHER_MCS7830
#define CONFIG_USB_ETHER_SMSC95XX
/* Libraries */
#define CONFIG_MD5
/* Extra Commands */
#define CONFIG_CMD_CACHE
#define CONFIG_CMD_ENV
#define CONFIG_CMD_GPIO
#define CONFIG_CMD_GPT
#define CONFIG_CMD_MD5SUM
#define CONFIG_CMD_MEMINFO
#define CONFIG_CMD_MMC
/* Enable that for switching of boot partitions */
/* Disabled by default as some sub-commands can brick eMMC */
/*#define CONFIG_SUPPORT_EMMC_BOOT */
#define CONFIG_CMD_PART
#define CONFIG_CMD_REGINFO /* Register dump */
#define CONFIG_CMD_TFTP
#define CONFIG_CMD_TIMER
#define CONFIG_CMD_UNZIP
/* Partition table support */
#define HAVE_BLOCK_DEVICE /* Needed for partition commands */
#define CONFIG_PARTITION_UUIDS
#include <config_distro_defaults.h>
/* BOOTP options */
#define CONFIG_BOOTP_BOOTFILESIZE
/* Environment - Boot*/
#define CONFIG_BOOTARGS "console=ttyMSM0,115200n8"
#define BOOT_TARGET_DEVICES(func) \
func(USB, usb, 0) \
func(MMC, mmc, 0) \
func(MMC, mmc, 1) \
func(DHCP, dhcp, na)
#include <config_distro_bootcmd.h>
/* Does what recovery does */
#define REFLASH(file, part) \
"part start mmc 0 "#part" start && "\
"part size mmc 0 "#part" size && "\
"tftp $loadaddr "#file" && " \
"mmc write $loadaddr $start $size && "
#define CONFIG_ENV_REFLASH \
"mmc dev 0 && "\
"usb start && "\
"dhcp && "\
"tftp $loadaddr dragonboard/rescue/gpt_both0.bin && "\
"mmc write $loadaddr 0 43 && " \
"mmc rescan && "\
REFLASH(dragonboard/rescue/NON-HLOS.bin, 1)\
REFLASH(dragonboard/rescue/sbl1.mbn, 2)\
REFLASH(dragonboard/rescue/rpm.mbn, 3)\
REFLASH(dragonboard/rescue/tz.mbn, 4)\
REFLASH(dragonboard/rescue/hyp.mbn, 5)\
REFLASH(dragonboard/rescue/sec.dat, 6)\
REFLASH(dragonboard/rescue/emmc_appsboot.mbn, 7)\
REFLASH(dragonboard/u-boot.img, 8)\
"usb stop &&"\
"echo Reflash completed"
/* Environment */
#define CONFIG_EXTRA_ENV_SETTINGS \
"reflash="CONFIG_ENV_REFLASH"\0"\
"loadaddr=0x81000000\0" \
"fdt_high=0xffffffffffffffff\0" \
"initrd_high=0xffffffffffffffff\0" \
"linux_image=Image\0" \
"linux_addr=0x81000000\0"\
"fdt_image=apq8016-sbc.dtb\0" \
"fdt_addr=0x83000000\0"\
"ramdisk_addr=0x84000000\0"\
BOOTENV
#define CONFIG_ENV_IS_NOWHERE
#define CONFIG_ENV_SIZE 0x1000
#define CONFIG_ENV_VARS_UBOOT_CONFIG
#define CONFIG_SYS_NO_FLASH
/* Size of malloc() pool */
#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + SZ_8M)
/* Monitor Command Prompt */
#define CONFIG_SYS_CBSIZE 512 /* Console I/O Buffer Size */
#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + \
sizeof(CONFIG_SYS_PROMPT) + 16)