arm64: add support for Ka-Ro TXSD-410E karo-txsd KARO-TXSD-2017-03-15
authorLothar Waßmann <LW@KARO-electronics.de>
Wed, 15 Mar 2017 08:10:30 +0000 (09:10 +0100)
committerLothar Waßmann <LW@KARO-electronics.de>
Wed, 15 Mar 2017 08:10:30 +0000 (09:10 +0100)
The TXSD-410E is a SoM compatible to the Qualcomm Dragonboard410c but
in a form factor compatible with the TX module family manufactured by
Ka-Ro electronics GmbH.

21 files changed:
arch/arm/dts/Makefile
arch/arm/dts/txsd-410e.dts [new file with mode: 0644]
arch/arm/mach-snapdragon/Kconfig
board/karo/common/Makefile [new file with mode: 0644]
board/karo/common/env.c [new file with mode: 0644]
board/karo/common/fdt.c [new file with mode: 0644]
board/karo/common/karo.h [new file with mode: 0644]
board/karo/common/lcd.c [new file with mode: 0644]
board/karo/common/mmc.c [new file with mode: 0644]
board/karo/common/splashimage.c [new file with mode: 0644]
board/karo/txsd/Kconfig [new file with mode: 0644]
board/karo/txsd/MAINTAINERS [new file with mode: 0644]
board/karo/txsd/Makefile [new file with mode: 0644]
board/karo/txsd/README [new file with mode: 0644]
board/karo/txsd/config.mk [new file with mode: 0644]
board/karo/txsd/head.S [new file with mode: 0644]
board/karo/txsd/txsd.c [new file with mode: 0644]
board/karo/txsd/u-boot.lds [new file with mode: 0644]
configs/txsd-410e_defconfig [new file with mode: 0644]
include/configs/txsd.h [new file with mode: 0644]
scripts/config_whitelist.txt

index 032c5ae..8e6b064 100644 (file)
@@ -152,7 +152,8 @@ dtb-$(CONFIG_FSL_LSCH2) += fsl-ls1043a-qds-duart.dtb \
        fsl-ls1012a-rdb.dtb \
        fsl-ls1012a-frdm.dtb
 
-dtb-$(CONFIG_ARCH_SNAPDRAGON) += dragonboard410c.dtb
+dtb-$(CONFIG_ARCH_SNAPDRAGON) += dragonboard410c.dtb \
+       txsd-410e.dtb
 
 dtb-$(CONFIG_MACH_SUN4I) += \
        sun4i-a10-a1000.dtb \
diff --git a/arch/arm/dts/txsd-410e.dts b/arch/arm/dts/txsd-410e.dts
new file mode 100644 (file)
index 0000000..a373882
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Qualcomm APQ8016 based Ka-Ro TXSD-410E board device tree source
+ *
+ * (C) Copyright 2016 Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/dts-v1/;
+
+#include "skeleton64.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+       model = "Ka-Ro electronics GmbH TXSD-410E";
+       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>;
+
+       aliases {
+               serial0 = &uart1;
+               soc_gpios = &soc_gpios;
+               i2c0 = &i2c_gpio1;
+               i2c1 = &i2c_gpio2;
+               i2c2 = &i2c_gpio3;
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0 0x90000000 0 0x2da00000>;
+       };
+
+       chosen {
+               stdout-path = "serial0";
+       };
+
+       psci {
+               compatible = "arm,psci-1.0";
+               method = "smc";
+       };
+
+       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>;
+               };
+
+               uart1: 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 = <2>;
+               };
+
+               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 = <0x200f000 0x1000
+                              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>;
+
+                               rtc@6000 {
+                                       compatible = "qcom,pm8941-rtc";
+                                       reg = <0x6000 0x4c>, <0x6100 0x49>;
+                                       reg-names = "rtc", "alarm";
+                                       interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
+                               };
+
+                               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>;
+                       };
+               };
+       };
+
+       i2c_gpio1: i2c-gpio@0 {
+               compatible = "i2c-gpio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c0_pinmux>;
+               gpios = <&soc_gpios 18 GPIO_ACTIVE_HIGH>, /* SDA */
+                       <&soc_gpios 19 GPIO_ACTIVE_HIGH>; /* CLK */
+
+               tsc2007@48 {
+                       compatible = "ti,tsc2007";
+                       reg = <0x48>;
+               };
+       };
+
+       i2c_gpio2: i2c-gpio@1 {
+               compatible = "i2c-gpio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c1_pinmux>;
+               gpios = <&soc_gpios 53 GPIO_ACTIVE_HIGH>, /* SDA */
+                       <&soc_gpios 54 GPIO_ACTIVE_HIGH>; /* CLK */
+
+               dsi83@2c {
+                       compatible = "ti,sn65dsi83";
+                       reg = <0x2c>;
+               };
+       };
+
+       i2c_gpio3: i2c-gpio@2 {
+               compatible = "i2c-gpio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&i2c2_pinmux>;
+               gpios = <&soc_gpios 29 GPIO_ACTIVE_HIGH>, /* SDA */
+                       <&soc_gpios 30 GPIO_ACTIVE_HIGH>; /* CLK */
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               user {
+                       label = "user";
+                       gpios = <&soc_gpios 71 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&soc_gpios {
+       i2c0_pinmux: i2c0-pins {
+               pinmux {
+                       function = "gpio";
+                       pins = "gpio18", "gpio19";
+               };
+
+               pinconf {
+                       pins = "gpio18", "gpio19";
+                       drive-strength = <16>;
+                       bias-pull-up;
+               };
+       };
+
+       i2c1_pinmux: i2c1-pins {
+               pinmux {
+                       function = "gpio";
+                       pins = "gpio53", "gpio54";
+               };
+
+               pinconf {
+                       pins = "gpio53", "gpio54";
+                       drive-strength = <16>;
+                       bias-pull-up;
+               };
+       };
+
+       i2c2_pinmux: i2c2-pins {
+               pinmux {
+                       function = "gpio";
+                       pins = "gpio29", "gpio30";
+               };
+
+               pinconf {
+                       pins = "gpio29", "gpio30";
+                       drive-strength = <16>;
+                       bias-pull-up;
+               };
+       };
+
+       led_pinmux: led-pins {
+               pinmux {
+                       function = "gpio";
+                       pins = "gpio71";
+       };
+
+               pinconf {
+                       pins = "gpio71";
+                       drive-strength = <16>;
+       };
+};
+
+       usb_vbus_pinmux: usb-vbus {
+               pinmux {
+                       function = "gpio";
+                       pins = "gpio56";
+       };
+
+               pinconf {
+                       pins = "gpio56";
+                       drive-strength = <16>;
+               };
+       };
+};
index dc7ba21..e2affb4 100644 (file)
@@ -19,8 +19,17 @@ config TARGET_DRAGONBOARD410C
          - HDMI
          - 20-pin low speed and 40-pin high speed expanders, 4 LED, 3 buttons
 
+config TARGET_TXSD_410E
+       bool "Ka-Ro electronics TXSD-410E"
+       help
+         Support for Ka-Ro electronics TXSD-410E module. This board
+         is compatible with the Qualcomm Snapdragon 410C board and
+         has a form factor like the TX-Series modules produced by
+         Ka-Ro electronics GmbH.
+
 endchoice
 
 source "board/qualcomm/dragonboard410c/Kconfig"
+source "board/karo/txsd/Kconfig"
 
 endif
diff --git a/board/karo/common/Makefile b/board/karo/common/Makefile
new file mode 100644 (file)
index 0000000..d8869d2
--- /dev/null
@@ -0,0 +1,14 @@
+#
+# (C) Copyright 2012-2015 Lothar Waßmann <LW@KARO-electronics.de>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+ifeq ($(CONFIG_SPL_BUILD),)
+       obj-$(CONFIG_OF_LIBFDT)         += fdt.o
+       obj-$(CONFIG_SPLASH_SCREEN)     += splashimage.o
+endif
+obj-$(CONFIG_CMD_NAND)                 += nand.o
+obj-$(CONFIG_ENV_IS_IN_MMC)            += mmc.o
+obj-$(CONFIG_LCD)                      += lcd.o
+obj-y                                  += env.o
diff --git a/board/karo/common/env.c b/board/karo/common/env.c
new file mode 100644 (file)
index 0000000..2b347cd
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2014 Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <environment.h>
+
+#include "karo.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_UBOOT_IGNORE_ENV
+void env_cleanup(void)
+{
+       set_default_env(NULL);
+}
+#else
+static const char const *cleanup_vars[] = {
+       "bootargs",
+       "fileaddr",
+       "filesize",
+       "safeboot",
+       "wdreset",
+};
+
+void env_cleanup(void)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(cleanup_vars); i++) {
+               setenv(cleanup_vars[i], NULL);
+       }
+}
+#endif
diff --git a/board/karo/common/fdt.c b/board/karo/common/fdt.c
new file mode 100644 (file)
index 0000000..d8ff1b8
--- /dev/null
@@ -0,0 +1,929 @@
+/*
+ * (C) Copyright 2012-2016 Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+#include <common.h>
+#include <console.h>
+#include <errno.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <nand.h>
+#ifdef CONFIG_VIDEO_IPUV3
+#include <mxcfb.h>
+#endif
+#include <asm/gpio.h>
+#include <linux/list.h>
+#include <linux/fb.h>
+#include <jffs2/load_kernel.h>
+#include <malloc.h>
+
+#include "karo.h"
+
+#ifdef CONFIG_MAX_DTB_SIZE
+#define MAX_DTB_SIZE   CONFIG_MAX_DTB_SIZE
+#else
+#define MAX_DTB_SIZE   SZ_64K
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void karo_set_fdtsize(void *fdt)
+{
+       size_t fdtsize = getenv_hex("fdtsize", 0);
+
+       if (fdtsize == fdt_totalsize(fdt)) {
+               return;
+       }
+       debug("FDT size changed from %zu to %u\n",
+               fdtsize, fdt_totalsize(fdt));
+       setenv_hex("fdtsize", fdt_totalsize(fdt));
+}
+
+static void *karo_fdt_load_dtb(void)
+{
+       int ret;
+       void *fdt;
+
+       if (getenv("fdtaddr") == NULL)
+               setenv_hex("fdtaddr", CONFIG_SYS_FDT_ADDR);
+       fdt = (void *)getenv_ulong("fdtaddr", 16, CONFIG_SYS_FDT_ADDR);
+
+       if (had_ctrlc()) {
+               printf("aborting DTB load\n");
+               return NULL;
+       }
+
+       ret = karo_load_part("dtb", fdt, MAX_DTB_SIZE);
+       if (ret) {
+               printf("Failed to load dtb from flash: %d\n", ret);
+               memset(fdt, 0, MAX_DTB_SIZE);
+               return NULL;
+       }
+
+       if (fdt_check_header(fdt)) {
+               debug("No valid DTB in flash\n");
+               return NULL;
+       }
+       debug("Using DTB from flash\n");
+       karo_set_fdtsize(fdt);
+       return fdt;
+}
+
+static inline void karo_create_default_dtb(void *fdt)
+{
+       int offs;
+
+       fdt_create_empty_tree(fdt, 256);
+       offs = fdt_add_subnode(fdt, 0, "display");
+       offs = fdt_add_subnode(fdt, offs, "display-timings");
+       offs = fdt_add_subnode(fdt, 0, "aliases");
+       fdt_setprop(fdt, offs, "display", "/display", strlen("/display"));
+}
+
+void karo_fdt_move_fdt(void)
+{
+       void *fdt;
+       unsigned long fdt_addr = getenv_hex("fdtaddr", 0);
+
+       if (working_fdt) {
+               debug("DTB already loaded\n");
+               return;
+       }
+
+       setenv("fdtsize", NULL);
+
+       if (!fdt_addr) {
+               fdt_addr = CONFIG_SYS_FDT_ADDR;
+               printf("fdtaddr is not set; using default: %08lx\n",
+                       fdt_addr);
+       }
+
+       fdt = karo_fdt_load_dtb();
+       if (fdt == NULL) {
+               fdt = (void *)gd->fdt_blob;
+               if (fdt == NULL) {
+#ifdef CONFIG_OF_EMBED
+                       printf("Compiled in FDT not found");
+#else
+                       printf("No FDT found");
+#endif
+                       printf("; creating empty DTB\n");
+                       fdt = (void *)fdt_addr;
+                       karo_create_default_dtb(fdt);
+               } else {
+                       printf("No DTB in flash; using default DTB\n");
+               }
+               debug("Checking FDT header @ %p\n", fdt);
+               if (fdt_check_header(fdt)) {
+                       printf("ERROR: No valid DTB found at %p\n", fdt);
+                       return;
+               }
+               debug("Copying FDT from %p..%p to %08lx..%08lx\n",
+                       fdt, fdt + fdt_totalsize(fdt) - 1,
+                       fdt_addr, fdt_addr + fdt_totalsize(fdt) - 1);
+               memmove((void *)fdt_addr, fdt, fdt_totalsize(fdt));
+       }
+       set_working_fdt_addr(fdt_addr);
+       karo_set_fdtsize(fdt);
+}
+
+void karo_fdt_remove_node(void *blob, const char *node)
+{
+       int off = fdt_path_offset(blob, node);
+       int ret;
+
+       debug("Removing node '%s' from DT\n", node);
+
+       if (off < 0) {
+               printf("Could not find node '%s': %s\n", node,
+                       fdt_strerror(off));
+       } else {
+               ret = fdt_del_node(blob, off);
+               if (ret)
+                       printf("Failed to remove node '%s': %s\n",
+                               node, fdt_strerror(ret));
+       }
+       karo_set_fdtsize(blob);
+}
+
+void karo_fdt_enable_node(void *blob, const char *node, int enable)
+{
+       int off = fdt_path_offset(blob, node);
+
+       debug("%sabling node '%s'\n", enable ? "En" : "Dis", node);
+       if (off < 0) {
+               printf("Could not find node '%s': %s\n", node,
+                       fdt_strerror(off));
+               return;
+       }
+       fdt_set_node_status(blob, off,
+                       enable ? FDT_STATUS_OKAY : FDT_STATUS_DISABLED, 0);
+
+       karo_set_fdtsize(blob);
+}
+
+static void fdt_disable_tp_node(void *blob, const char *name)
+{
+       int offs = fdt_node_offset_by_compatible(blob, -1, name);
+
+       while (offs >= 0) {
+               debug("Disabling node '%s'\n", name);
+               fdt_set_node_status(blob, offs, FDT_STATUS_DISABLED, 0);
+               offs = fdt_node_offset_by_compatible(blob, offs, name);
+       }
+}
+
+void karo_fdt_fixup_touchpanel(void *blob, const char *panels[],
+                       size_t num_panels)
+{
+       int i;
+       const char *model = getenv("touchpanel");
+
+       for (i = 0; i < num_panels; i++) {
+               const char *tp = panels[i];
+
+               if (model != NULL) {
+                       if (strcmp(model, tp) == 0)
+                               continue;
+                       while (tp != NULL) {
+                               if (*tp != '\0' && strcmp(model, tp + 1) == 0)
+                                       break;
+                               tp = strpbrk(tp + 1, ",-");
+                       }
+                       if (tp != NULL)
+                               continue;
+               }
+               fdt_disable_tp_node(blob, panels[i]);
+       }
+       karo_set_fdtsize(blob);
+}
+
+static int karo_fdt_disable_node_phandle(void *blob, const char *parent,
+                                       const char *name)
+{
+       const uint32_t *ph;
+       int off;
+
+       off = fdt_path_offset(blob, parent);
+       if (off < 0) {
+               printf("Failed to find node '%s'\n", parent);
+               return off;
+       }
+
+       ph = fdt_getprop(blob, off, name, NULL);
+       if (ph == NULL) {
+               debug("Failed to find '%s' phandle in node '%s'\n", name,
+                       fdt_get_name(blob, off, NULL));
+               return -FDT_ERR_NOTFOUND;
+       }
+
+       off = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*ph));
+       if (off <= 0) {
+               printf("Failed to find '%s' node via phandle %04x\n",
+                       name, fdt32_to_cpu(*ph));
+               return -FDT_ERR_NOTFOUND;
+       }
+       return fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+}
+
+void karo_fdt_fixup_usb_otg(void *blob, const char *node, const char *phy,
+                       const char *phy_supply)
+{
+       const char *otg_mode = getenv("otg_mode");
+       int off;
+       int ret;
+       int disable_otg = 0;
+       int disable_phy_pins = 0;
+
+       debug("OTG mode is '%s'\n", otg_mode ? otg_mode : "<UNSET>");
+
+       off = fdt_path_offset(blob, node);
+       if (off < 0) {
+               debug("Failed to find node %s\n", node);
+               return;
+       }
+
+       if (otg_mode && (strcasecmp(otg_mode, "device") == 0 ||
+                               strcasecmp(otg_mode, "gadget") == 0)) {
+               debug("Setting dr_mode to 'peripheral'\n");
+               ret = fdt_setprop_string(blob, off, "dr_mode", "peripheral");
+               disable_phy_pins = 1;
+       } else if (otg_mode && strcasecmp(otg_mode, "host") == 0) {
+               debug("Setting dr_mode to 'host'\n");
+               ret = fdt_setprop_string(blob, off, "dr_mode", "host");
+       } else if (otg_mode && strcasecmp(otg_mode, "otg") == 0) {
+               debug("Setting dr_mode to 'otg'\n");
+               ret = fdt_setprop_string(blob, off, "dr_mode", "otg");
+       } else {
+               if (otg_mode && strcasecmp(otg_mode, "none") != 0)
+                       printf("Invalid 'otg_mode' setting '%s'; disabling usbotg port\n",
+                               otg_mode);
+               disable_otg = 1;
+               ret = 0;
+       }
+
+       if ((!disable_phy_pins && !disable_otg) || ret)
+               goto out;
+
+       ret = karo_fdt_disable_node_phandle(blob, node, phy_supply);
+       if (ret && ret == -FDT_ERR_NOTFOUND) {
+               const uint32_t *ph;
+
+               ph = fdt_getprop(blob, off, phy, NULL);
+               if (ph == NULL) {
+                       printf("Failed to find '%s' phandle in node '%s'\n",
+                               phy, node);
+                       ret = -FDT_ERR_NOTFOUND;
+                       goto out;
+               }
+               off = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*ph));
+               if (off < 0) {
+                       printf("Failed to find '%s' node via phandle %04x\n",
+                               phy, fdt32_to_cpu(*ph));
+                       ret = off;
+                       goto out;
+               }
+               ph = fdt_getprop(blob, off, phy_supply, NULL);
+               if (ph == NULL) {
+                       debug("Failed to find '%s' phandle in node '%s'\n",
+                               phy_supply, fdt_get_name(blob, off, NULL));
+                       ret = -FDT_ERR_NOTFOUND;
+                       goto disable_otg;
+               }
+               ret = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*ph));
+               if (ret > 0) {
+                       debug("Disabling node %s via phandle %s:%s\n",
+                               fdt_get_name(blob, ret, NULL),
+                               fdt_get_name(blob, off, NULL), phy_supply);
+                       ret = fdt_set_node_status(blob, ret,
+                                               FDT_STATUS_DISABLED, 0);
+               }
+       }
+       if (ret && ret != -FDT_ERR_NOTFOUND)
+               goto out;
+
+disable_otg:
+       if (disable_otg) {
+               debug("Disabling '%s'\n", fdt_get_name(blob, off, NULL));
+               ret = fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+               if (ret > 0)
+                       ret = karo_fdt_disable_node_phandle(blob, node, phy);
+       } else if (disable_phy_pins) {
+               debug("Removing '%s' from node '%s'\n", phy_supply,
+                       fdt_get_name(blob, off, NULL));
+               ret = fdt_delprop(blob, off, phy_supply);
+       }
+
+out:
+       if (ret && ret != -FDT_ERR_NOTFOUND)
+               printf("Failed to update usbotg: %s\n", fdt_strerror(ret));
+       else
+               debug("node '%s' updated\n", node);
+       karo_set_fdtsize(blob);
+}
+
+static inline int karo_fdt_flexcan_enabled(void *blob)
+{
+       static const char *can_ifs[] = {
+               "can0",
+               "can1",
+       };
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(can_ifs); i++) {
+               const char *status;
+               int off = fdt_path_offset(blob, can_ifs[i]);
+
+               if (off < 0) {
+                       debug("node '%s' not found\n", can_ifs[i]);
+                       continue;
+               }
+               status = fdt_getprop(blob, off, "status", NULL);
+               if (status && strcmp(status, "okay") == 0) {
+                       debug("%s is enabled\n", can_ifs[i]);
+                       return 1;
+               }
+       }
+       debug("can driver is disabled\n");
+       return 0;
+}
+
+static inline void karo_fdt_set_lcd_pins(void *blob, const char *name)
+{
+       int off = fdt_path_offset(blob, name);
+       u32 ph;
+       const struct fdt_property *pc;
+       int len;
+
+       if (off < 0)
+               return;
+
+       ph = fdt_create_phandle(blob, off);
+       if (!ph)
+               return;
+
+       off = fdt_path_offset(blob, "display");
+       if (off < 0)
+               return;
+
+       pc = fdt_get_property(blob, off, "pinctrl-0", &len);
+       if (!pc || len < sizeof(ph))
+               return;
+
+       memcpy((void *)pc->data, &ph, sizeof(ph));
+       fdt_setprop_cell(blob, off, "pinctrl-0", ph);
+}
+
+void karo_fdt_fixup_flexcan(void *blob, int xcvr_present)
+{
+       int ret;
+       const char *xcvr_status = "disabled";
+       const char *otg_mode = getenv("otg_mode");
+
+       if (xcvr_present) {
+               if (karo_fdt_flexcan_enabled(blob)) {
+                       if (!is_lvds()) {
+                               debug("Changing LCD to use 23bits only\n");
+                               karo_fdt_set_lcd_pins(blob, "lcdif_23bit_pins_a");
+                               xcvr_status = NULL;
+                       }
+               } else if (!is_lvds()) {
+                       debug("Changing LCD to use 24bits\n");
+                       karo_fdt_set_lcd_pins(blob, "lcdif_24bit_pins_a");
+               }
+       } else {
+               int off = fdt_path_offset(blob, "can0");
+
+               if (off >= 0)
+                       fdt_delprop(blob, off, "xceiver-supply");
+               off = fdt_path_offset(blob, "can1");
+               if (off >= 0)
+                       fdt_delprop(blob, off, "xceiver-supply");
+               if (!is_lvds())
+                       karo_fdt_set_lcd_pins(blob, "lcdif_24bit_pins_a");
+       }
+
+       if (otg_mode && strcasecmp(otg_mode, "host") == 0)
+               karo_fdt_enable_node(blob, "can1", 0);
+
+       if (xcvr_status) {
+               debug("Disabling CAN XCVR\n");
+               ret = fdt_find_and_setprop(blob, "reg_can_xcvr", "status",
+                                       xcvr_status, strlen(xcvr_status) + 1, 1);
+               if (ret)
+                       printf("Failed to disable CAN transceiver switch: %s\n",
+                               fdt_strerror(ret));
+       }
+}
+
+void karo_fdt_del_prop(void *blob, const char *compat, u32 offs,
+                       const char *propname)
+{
+       int offset = -1;
+       const fdt32_t *reg = NULL;
+
+       while (1) {
+               offset = fdt_node_offset_by_compatible(blob, offset, compat);
+               if (offset <= 0)
+                       return;
+
+               reg = fdt_getprop(blob, offset, "reg", NULL);
+               if (reg == NULL)
+                       return;
+
+               if (fdt32_to_cpu(*reg) == offs)
+                       break;
+       }
+       debug("Removing property '%s' from node %s@%x\n",
+               propname, compat, offs);
+       fdt_delprop(blob, offset, propname);
+
+       karo_set_fdtsize(blob);
+}
+
+#ifdef CONFIG_LCD
+static int fdt_init_fb_mode(const void *blob, int off, struct fb_videomode *fb_mode)
+{
+       const uint32_t *prop;
+
+       memset(fb_mode, 0, sizeof(*fb_mode));
+
+       prop = fdt_getprop(blob, off, "clock-frequency", NULL);
+       if (prop)
+               fb_mode->pixclock = KHZ2PICOS(fdt32_to_cpu(*prop) / 1000);
+
+       prop = fdt_getprop(blob, off, "hactive", NULL);
+       if (prop)
+               fb_mode->xres = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "vactive", NULL);
+       if (prop)
+               fb_mode->yres = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "hback-porch", NULL);
+       if (prop)
+               fb_mode->left_margin = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "hsync-len", NULL);
+       if (prop)
+               fb_mode->hsync_len = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "hfront-porch", NULL);
+       if (prop)
+               fb_mode->right_margin = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "vback-porch", NULL);
+       if (prop)
+               fb_mode->upper_margin = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "vsync-len", NULL);
+       if (prop)
+               fb_mode->vsync_len = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "vfront-porch", NULL);
+       if (prop)
+               fb_mode->lower_margin = fdt32_to_cpu(*prop);
+
+       prop = fdt_getprop(blob, off, "hsync-active", NULL);
+       if (prop)
+               fb_mode->sync |= *prop ? FB_SYNC_VERT_HIGH_ACT : 0;
+
+       prop = fdt_getprop(blob, off, "vsync-active", NULL);
+       if (prop)
+               fb_mode->sync |= *prop ? FB_SYNC_VERT_HIGH_ACT : 0;
+
+       prop = fdt_getprop(blob, off, "de-active", NULL);
+       if (prop)
+               fb_mode->sync |= *prop ? 0 : FB_SYNC_OE_LOW_ACT;
+
+       prop = fdt_getprop(blob, off, "pixelclk-active", NULL);
+       if (prop)
+               fb_mode->sync |= *prop ? 0 : FB_SYNC_CLK_LAT_FALL;
+
+       return 0;
+}
+
+static int fdt_update_native_fb_mode(void *blob, int off)
+{
+       int ret;
+       uint32_t ph;
+
+       ret = fdt_increase_size(blob, 64);
+       if (ret) {
+               printf("Warning: Failed to increase FDT size: %s\n",
+                       fdt_strerror(ret));
+       }
+       debug("Creating phandle at offset %d\n", off);
+       ph = fdt_create_phandle(blob, off);
+       if (!ph) {
+               printf("Failed to create phandle for video timing\n");
+               return -ENOMEM;
+       }
+
+       debug("phandle of %s @ %06x=%04x\n", fdt_get_name(blob, off, NULL),
+               off, ph);
+       off = fdt_parent_offset(blob, off);
+       if (off < 0)
+               return off;
+       debug("parent offset=%06x\n", off);
+       ret = fdt_setprop_cell(blob, off, "native-mode", ph);
+       if (ret)
+               printf("Failed to set property 'native-mode': %s\n",
+                       fdt_strerror(ret));
+       karo_set_fdtsize(blob);
+       return ret;
+}
+
+static int karo_fdt_find_video_timings(const void *blob)
+{
+       int off = fdt_path_offset(blob, "display");
+       const char *subnode = "display-timings";
+
+       if (off < 0) {
+               debug("Could not find node 'display' in FDT: %s\n",
+                       fdt_strerror(off));
+               return off;
+       }
+
+       off = fdt_subnode_offset(blob, off, subnode);
+       if (off < 0) {
+               debug("Could not find node '%s' in FDT: %s\n", subnode,
+                       fdt_strerror(off));
+       }
+       return off;
+}
+
+int karo_fdt_get_fb_mode(const void *blob, const char *name,
+                       struct fb_videomode *fb_mode)
+{
+       int off = karo_fdt_find_video_timings(blob);
+
+       if (off < 0)
+               return off;
+       while (off > 0) {
+               const char *n, *endp;
+               int len, d = 1;
+
+               off = fdt_next_node(blob, off, &d);
+               if (off < 0)
+                       return off;
+               if (d < 1)
+                       return -EINVAL;
+               if (d > 2) {
+                       debug("Skipping node @ %04x %s depth %d\n", off,
+                               fdt_get_name(blob, off, NULL), d);
+                       continue;
+               }
+
+               n = fdt_getprop(blob, off, "panel-name", &len);
+               if (!n) {
+                       n = fdt_get_name(blob, off, NULL);
+                       if (strcasecmp(n, name) == 0) {
+                               break;
+                       }
+               } else {
+                       int found = 0;
+
+                       for (endp = n + len; n < endp; n += strlen(n) + 1) {
+                               debug("Checking panel-name '%s'\n", n);
+                               if (strcasecmp(n, name) == 0) {
+                                       debug("Using node %s @ %04x\n",
+                                               fdt_get_name(blob, off, NULL), off);
+                                       found = 1;
+                                       break;
+                               }
+                       }
+                       if (found)
+                               break;
+               }
+       }
+       if (off > 0)
+               return fdt_init_fb_mode(blob, off, fb_mode);
+
+       return -EINVAL;
+}
+
+#define SET_FB_PROP(n, v) ({                                           \
+       int ret;                                                        \
+       ret = fdt_setprop_u32(blob, off, n, v);                         \
+       if (ret) {                                                      \
+               printf("Failed to set property %s: %s\n", name,         \
+                       fdt_strerror(ret));                             \
+       }                                                               \
+       ret;                                                            \
+})
+
+int karo_fdt_create_fb_mode(void *blob, const char *name,
+                       struct fb_videomode *fb_mode)
+{
+       int off = fdt_path_offset(blob, "display");
+       int ret;
+       const char *subnode = "display-timings";
+
+       if (off < 0) {
+               printf("'display' node not found in FDT\n");
+               return off;
+       }
+
+       ret = fdt_increase_size(blob, 512);
+       if (ret) {
+               printf("Failed to increase FDT size: %s\n", fdt_strerror(ret));
+               return ret;
+       }
+
+       ret = fdt_subnode_offset(blob, off, subnode);
+       if (ret < 0) {
+               debug("Could not find node '%s' in FDT: %s\n", subnode,
+                       fdt_strerror(ret));
+               ret = fdt_add_subnode(blob, off, subnode);
+               if (ret < 0) {
+                       printf("Failed to add %s subnode: %s\n", subnode,
+                               fdt_strerror(ret));
+                       return ret;
+               }
+       }
+
+       ret = fdt_add_subnode(blob, ret, name);
+       if (ret < 0) {
+               printf("Failed to add %s subnode: %s\n", name,
+                       fdt_strerror(ret));
+               return ret;
+       }
+       off = ret;
+
+       ret = SET_FB_PROP("clock-frequency",
+                       PICOS2KHZ(fb_mode->pixclock) * 1000);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("hactive", fb_mode->xres);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("vactive", fb_mode->yres);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("hback-porch", fb_mode->left_margin);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("hsync-len", fb_mode->hsync_len);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("hfront-porch", fb_mode->right_margin);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("vback-porch", fb_mode->upper_margin);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("vsync-len", fb_mode->vsync_len);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("vfront-porch", fb_mode->lower_margin);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("hsync-active",
+                       fb_mode->sync & FB_SYNC_VERT_HIGH_ACT ? 1 : 0);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("vsync-active",
+                       fb_mode->sync & FB_SYNC_VERT_HIGH_ACT ? 1 : 0);
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("de-active",
+                       !(fb_mode->sync & FB_SYNC_OE_LOW_ACT));
+       if (ret)
+               goto out;
+       ret = SET_FB_PROP("pixelclk-active",
+                       !(fb_mode->sync & FB_SYNC_CLK_LAT_FALL));
+out:
+       karo_set_fdtsize(blob);
+       return ret;
+}
+
+int karo_fdt_update_fb_mode(void *blob, const char *name)
+{
+       int off = fdt_path_offset(blob, "display");
+       const char *subnode = "display-timings";
+
+       if (off < 0)
+               return off;
+
+       if (name == NULL) {
+               int ret;
+
+               debug("Disabling node '%s' at %03x\n",
+                       fdt_get_name(blob, off, NULL), off);
+               ret = fdt_set_node_status(blob, off, FDT_STATUS_DISABLED, 0);
+               return ret;
+       }
+
+       off = fdt_subnode_offset(blob, off, subnode);
+       if (off < 0) {
+               debug("Could not find node '%s' in FDT: %s\n", subnode,
+                       fdt_strerror(off));
+               return off;
+       }
+       while (off > 0) {
+               const char *n, *endp;
+               int len, d = 1;
+
+               off = fdt_next_node(blob, off, &d);
+               if (off < 0)
+                       return off;
+               if (d < 1)
+                       return -EINVAL;
+               if (d > 2) {
+                       debug("Skipping node @ %04x %s depth %d\n", off,
+                               fdt_get_name(blob, off, NULL), d);
+                       continue;
+               }
+
+               n = fdt_getprop(blob, off, "panel-name", &len);
+               if (!n) {
+                       n = fdt_get_name(blob, off, NULL);
+                       if (strcasecmp(n, name) == 0) {
+                               break;
+                       }
+               } else {
+                       int found = 0;
+
+                       for (endp = n + len; n < endp; n += strlen(n) + 1) {
+                               debug("Checking panel-name '%s'\n", n);
+                               if (strcasecmp(n, name) == 0) {
+                                       debug("Using node %s @ %04x\n",
+                                               fdt_get_name(blob, off, NULL), off);
+                                       found = 1;
+                                       break;
+                               }
+                       }
+                       if (found)
+                               break;
+               }
+       }
+       if (off > 0)
+               return fdt_update_native_fb_mode(blob, off);
+       return off;
+}
+
+#ifdef CONFIG_SYS_LVDS_IF
+#ifdef CONFIG_SOC_MXC
+#define LVDS_DATA_WIDTH_NAME   "fsl,data-width"
+#define LVDS_DATA_MAPPING_NAME "fsl,data-mapping"
+#else
+#define LVDS_DATA_WIDTH_NAME   "lvds-data-width"
+#define LVDS_DATA_MAPPING_NAME "lvds-data-mapping"
+#endif
+
+int karo_fdt_get_lcd_bus_width(const void *blob, int default_width)
+{
+       int off = fdt_path_offset(blob, "display");
+
+       if (off >= 0) {
+               const uint32_t *prop;
+
+               prop = fdt_getprop(blob, off, LVDS_DATA_WIDTH_NAME, NULL);
+               if (prop)
+                       return fdt32_to_cpu(*prop);
+       }
+       return default_width;
+}
+
+int karo_fdt_get_lvds_mapping(const void *blob, int default_mapping)
+{
+       int off = fdt_path_offset(blob, "display");
+
+       if (off >= 0) {
+               const char *prop;
+
+               prop = fdt_getprop(blob, off, LVDS_DATA_MAPPING_NAME, NULL);
+               if (prop)
+                       return strcmp(prop, "jeida") == 0;
+       }
+       return default_mapping;
+}
+
+u8 karo_fdt_get_lvds_channels(const void *blob)
+{
+       static const char *lvds_chans[] = {
+               "lvds0",
+               "lvds1",
+       };
+       u8 lvds_chan_mask = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(lvds_chans); i++) {
+               const char *status;
+               int off = fdt_path_offset(blob, lvds_chans[i]);
+
+               if (off < 0)
+                       continue;
+
+               status = fdt_getprop(blob, off, "status", NULL);
+               if (status && strcmp(status, "okay") == 0) {
+                       debug("%s is enabled\n", lvds_chans[i]);
+                       lvds_chan_mask |= 1 << i;
+               }
+       }
+       return lvds_chan_mask;
+}
+#endif
+
+int karo_fdt_find_backlight_node(const void *blob)
+{
+       int off = fdt_path_offset(blob, "backlight"); /* first try alias */
+#ifdef CONFIG_SYS_LVDS_IF
+       const char *backlight_node = "/backlight0";
+#else
+       const char *backlight_node = "/backlight";
+#endif
+       if (off < 0) {
+               /*
+                * if no 'backlight' alias exists try finding '/backlight0'
+                * or '/backlight' depending on LVDS or not
+                */
+               off = fdt_path_offset(blob, backlight_node);
+               if (off < 0) {
+                       printf("%s node not found in DT\n", backlight_node);
+                       return off;
+               }
+       }
+       return off;
+}
+
+int karo_fdt_get_backlight_gpio(const void *blob, struct gpio_desc *desc)
+{
+       int off = karo_fdt_find_backlight_node(blob);
+       const char *prop_name = "gpios";
+       const struct fdt_property *prop;
+       int ret;
+
+       if (off < 0) {
+               printf("Could not find 'backlight' node in FDT: %s\n",
+                       fdt_strerror(off));
+               return off;
+       }
+
+       prop = fdt_get_property(blob, off, prop_name, NULL);
+       if (!prop) {
+               prop_name = "gpio";
+               prop = fdt_get_property(blob, off, prop_name, NULL);
+               if (!prop) {
+                       debug("'gpios' or 'gpio' property not found in backlight node\n");
+                       return -ENOENT;
+               }
+       }
+       ret = gpio_request_by_name_nodev(blob, off, prop_name, 0, desc, 0);
+       if (ret < 0)
+               printf("Failed to request backlight gpio %s/%s: %d\n",
+                       fdt_get_name(blob, off, NULL), prop_name, ret);
+
+       return ret;
+}
+
+int karo_fdt_get_backlight_polarity(const void *blob)
+{
+       int off = karo_fdt_find_backlight_node(blob);
+       const struct fdt_property *prop;
+       int len;
+       const char *prop_name = "pwms";
+
+       if (off < 0) {
+               printf("Could not find 'backlight' node in FDT: %s\n",
+                       fdt_strerror(off));
+               return off;
+       }
+
+       prop = fdt_get_property(blob, off, prop_name, &len);
+       if (!prop) {
+               prop_name = "gpios";
+               prop = fdt_get_property(blob, off, prop_name, &len);
+               if (!prop) {
+                       prop_name = "gpios";
+                       prop = fdt_get_property(blob, off, prop_name, &len);
+               }
+               if (!prop) {
+                       printf("'pwms' or 'gpios' property not found in backlight node\n");
+                       return 0;
+               }
+       }
+       if (prop)
+               debug("'%s' property has len %d\n", prop_name, len);
+
+       len /= sizeof(u32);
+       if (prop && len > 3) {
+               const u32 *data = (const u32 *)prop->data;
+               return fdt32_to_cpu(data[3]) != 0;
+       }
+       return 0;
+}
+#endif /* CONFIG_LCD */
diff --git a/board/karo/common/karo.h b/board/karo/common/karo.h
new file mode 100644 (file)
index 0000000..2841c8c
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * (C) Copyright 2012 Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+*/
+
+#include <errno.h>
+
+struct fb_videomode;
+struct gpio_desc;
+
+#ifdef CONFIG_SYS_LVDS_IF
+#define is_lvds()                      1
+#else
+#define is_lvds()                      0
+#endif
+
+void env_cleanup(void);
+
+#ifdef CONFIG_OF_LIBFDT
+void karo_fdt_remove_node(void *blob, const char *node);
+void karo_fdt_move_fdt(void);
+void karo_fdt_fixup_touchpanel(void *blob, const char *panels[],
+                       size_t num_panels);
+void karo_fdt_fixup_usb_otg(void *blob, const char *node, const char *phy,
+                       const char *phy_supply);
+void karo_fdt_fixup_flexcan(void *blob, int xcvr_present);
+void karo_fdt_del_prop(void *blob, const char *compat, u32 offs,
+               const char *prop);
+void karo_fdt_enable_node(void *blob, const char *node, int enable);
+int karo_fdt_get_fb_mode(const void *blob, const char *name,
+               struct fb_videomode *fb_mode);
+int karo_fdt_update_fb_mode(void *blob, const char *name);
+int karo_fdt_create_fb_mode(void *blob, const char *name,
+                       struct fb_videomode *mode);
+int karo_fdt_get_backlight_polarity(const void *blob);
+int karo_fdt_get_backlight_gpio(const void *blob, struct gpio_desc *desc);
+#else
+static inline void karo_fdt_remove_node(void *blob, const char *node)
+{
+}
+static inline void karo_fdt_move_fdt(void)
+{
+}
+static inline void karo_fdt_fixup_touchpanel(void *blob, const char *panels[],
+                                       size_t num_panels)
+{
+}
+static inline void karo_fdt_fixup_usb_otg(void *blob, const char *node,
+                                       const char *phy,
+                                       const char *phy_supply)
+{
+}
+static inline void karo_fdt_fixup_flexcan(void *blob, int xcvr_present)
+{
+}
+static inline void karo_fdt_del_prop(void *blob, const char *compat,
+                               u32 offs, const char *prop)
+{
+}
+static inline void karo_fdt_enable_node(void *blob, const char *node,
+                                       int enable)
+{
+}
+static inline int karo_fdt_get_fb_mode(void *blob, const char *name,
+                               struct fb_videomode *fb_mode)
+{
+       return 0;
+}
+static inline int karo_fdt_update_fb_mode(void *blob, const char *name)
+{
+       return 0;
+}
+static inline int karo_fdt_create_fb_mode(void *blob,
+                                       const char *name,
+                                       struct fb_videomode *mode)
+{
+       return 0;
+}
+static inline int karo_fdt_get_backlight_polarity(const void *blob)
+{
+       return getenv_yesno("backlight_polarity");
+}
+static inline int karo_fdt_get_backlight_gpio(const void *blob,
+                                       struct gpio_desc *desc)
+{
+       return -ENOENT;
+}
+#endif
+
+#if defined(CONFIG_SYS_LVDS_IF) && defined(CONFIG_OF_LIBFDT)
+int karo_fdt_get_lcd_bus_width(const void *blob, int default_width);
+int karo_fdt_get_lvds_mapping(const void *blob, int default_mapping);
+u8 karo_fdt_get_lvds_channels(const void *blob);
+#else
+static inline int karo_fdt_get_lcd_bus_width(const void *blob, int default_width)
+{
+       return default_width;
+}
+static inline int karo_fdt_get_lvds_mapping(const void *blob, int default_mapping)
+{
+       return default_mapping;
+}
+static inline u8 karo_fdt_get_lvds_channels(const void *blob)
+{
+       return 0;
+}
+#endif
+
+static inline const char *karo_get_vmode(const char *video_mode)
+{
+       const char *vmode = NULL;
+
+       if (video_mode == NULL || strlen(video_mode) == 0)
+               return NULL;
+
+       vmode = strchr(video_mode, ':');
+       return vmode ? vmode + 1 : video_mode;
+}
+
+#ifdef CONFIG_LCD
+#ifdef CONFIG_VIDEO_IPUV3
+#include <mxcfb.h>
+#endif
+
+#ifndef FB_SYNC_CLK_LAT_FALL
+#define FB_SYNC_CLK_LAT_FALL           0
+#define FB_SYNC_OE_LOW_ACT             0
+#endif
+
+int karo_get_fb_mode(const char *name, struct fb_videomode **mode);
+#else
+static inline int karo_get_fb_mode(const char *name,
+                               struct fb_videomode **mode)
+{
+       return -EOPNOTSUPP;
+}
+#endif /* CONFIG_LCD */
+
+#ifdef CONFIG_SPLASH_SCREEN
+int karo_load_splashimage(int mode);
+#else
+static inline int karo_load_splashimage(int mode)
+{
+       return 0;
+}
+#endif /* CONFIG_SPLASH_SCREEN */
+
+#ifdef CONFIG_CMD_NAND
+int karo_nand_load_part(const char *part, void *addr, size_t len);
+#else
+static inline int karo_nand_load_part(const char *part, void *addr, size_t len)
+{
+       return -EOPNOTSUPP;
+}
+#endif
+
+#ifdef CONFIG_ENV_IS_IN_MMC
+int karo_mmc_load_part(const char *part, void *addr, size_t len);
+#else
+static inline int karo_mmc_load_part(const char *part, void *addr, size_t len)
+{
+       return -EOPNOTSUPP;
+}
+#endif
+
+static inline int karo_load_part(const char *part, void *addr, size_t len)
+{
+       int ret;
+
+       ret = karo_nand_load_part(part, addr, len);
+       if (ret == -EOPNOTSUPP)
+               return karo_mmc_load_part(part, addr, len);
+       return ret;
+}
+
+#define DIV_ROUND(n, d)                (((n) + (d) / 2) / (d))
diff --git a/board/karo/common/lcd.c b/board/karo/common/lcd.c
new file mode 100644 (file)
index 0000000..b914c18
--- /dev/null
@@ -0,0 +1,198 @@
+#include <common.h>
+#include <linux/fb.h>
+#ifdef CONFIG_VIDEO_IPUV3
+#include <mxcfb.h>
+#endif
+
+#include "karo.h"
+
+static struct fb_videomode karo_tx_fb_modes[] = {
+#ifndef CONFIG_SYS_LVDS_IF
+       {
+               /* Standard VGA timing */
+               .name           = "VGA",
+               .refresh        = 60,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = KHZ2PICOS(25175),
+               .left_margin    = 48,
+               .hsync_len      = 96,
+               .right_margin   = 16,
+               .upper_margin   = 31,
+               .vsync_len      = 2,
+               .lower_margin   = 12,
+               .sync           = FB_SYNC_CLK_LAT_FALL,
+       },
+       {
+               /* Emerging ETV570 640 x 480 display. Syncs low active,
+                * DE high active, 115.2 mm x 86.4 mm display area
+                * VGA compatible timing
+                */
+               .name           = "ETV570",
+               .refresh        = 60,
+               .xres           = 640,
+               .yres           = 480,
+               .pixclock       = KHZ2PICOS(25175),
+               .left_margin    = 114,
+               .hsync_len      = 30,
+               .right_margin   = 16,
+               .upper_margin   = 32,
+               .vsync_len      = 3,
+               .lower_margin   = 10,
+               .sync           = FB_SYNC_CLK_LAT_FALL,
+       },
+       {
+               /* Emerging ET0350G0DH6 320 x 240 display.
+                * 70.08 mm x 52.56 mm display area.
+                */
+               .name           = "ET0350",
+               .refresh        = 60,
+               .xres           = 320,
+               .yres           = 240,
+               .pixclock       = KHZ2PICOS(6500),
+               .left_margin    = 68 - 34,
+               .hsync_len      = 34,
+               .right_margin   = 20,
+               .upper_margin   = 18 - 3,
+               .vsync_len      = 3,
+               .lower_margin   = 4,
+               .sync           = FB_SYNC_CLK_LAT_FALL,
+       },
+       {
+               /* Emerging ET0430G0DH6 480 x 272 display.
+                * 95.04 mm x 53.856 mm display area.
+                */
+               .name           = "ET0430",
+               .refresh        = 60,
+               .xres           = 480,
+               .yres           = 272,
+               .pixclock       = KHZ2PICOS(9000),
+               .left_margin    = 2,
+               .hsync_len      = 41,
+               .right_margin   = 2,
+               .upper_margin   = 2,
+               .vsync_len      = 10,
+               .lower_margin   = 2,
+       },
+       {
+               /* Emerging ET0500G0DH6 800 x 480 display.
+                * 109.6 mm x 66.4 mm display area.
+                */
+               .name           = "ET0500",
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 480,
+               .pixclock       = KHZ2PICOS(33260),
+               .left_margin    = 216 - 128,
+               .hsync_len      = 128,
+               .right_margin   = 1056 - 800 - 216,
+               .upper_margin   = 35 - 2,
+               .vsync_len      = 2,
+               .lower_margin   = 525 - 480 - 35,
+               .sync           = FB_SYNC_CLK_LAT_FALL,
+       },
+       {
+               /* Emerging ETQ570G0DH6 320 x 240 display.
+                * 115.2 mm x 86.4 mm display area.
+                */
+               .name           = "ETQ570",
+               .refresh        = 60,
+               .xres           = 320,
+               .yres           = 240,
+               .pixclock       = KHZ2PICOS(6400),
+               .left_margin    = 38,
+               .hsync_len      = 30,
+               .right_margin   = 30,
+               .upper_margin   = 16, /* 15 according to datasheet */
+               .vsync_len      = 3, /* TVP -> 1>x>5 */
+               .lower_margin   = 4, /* 4.5 according to datasheet */
+               .sync           = FB_SYNC_CLK_LAT_FALL,
+       },
+       {
+               /* Emerging ET0700G0DH6 800 x 480 display.
+                * 152.4 mm x 91.44 mm display area.
+                */
+               .name           = "ET0700",
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 480,
+               .pixclock       = KHZ2PICOS(33260),
+               .left_margin    = 216 - 128,
+               .hsync_len      = 128,
+               .right_margin   = 1056 - 800 - 216,
+               .upper_margin   = 35 - 2,
+               .vsync_len      = 2,
+               .lower_margin   = 525 - 480 - 35,
+               .sync           = FB_SYNC_CLK_LAT_FALL,
+       },
+       {
+               /* Emerging ET070001DM6 800 x 480 display.
+                * 152.4 mm x 91.44 mm display area.
+                */
+               .name           = "ET070001DM6",
+               .refresh        = 60,
+               .xres           = 800,
+               .yres           = 480,
+               .pixclock       = KHZ2PICOS(33260),
+               .left_margin    = 216 - 128,
+               .hsync_len      = 128,
+               .right_margin   = 1056 - 800 - 216,
+               .upper_margin   = 35 - 2,
+               .vsync_len      = 2,
+               .lower_margin   = 525 - 480 - 35,
+               .sync           = 0,
+       },
+#else
+       {
+               /* HannStar HSD100PXN1
+                * 202.7m mm x 152.06 mm display area.
+                */
+               .name           = "HSD100PXN1",
+               .refresh        = 60,
+               .xres           = 1024,
+               .yres           = 768,
+               .pixclock       = KHZ2PICOS(65000),
+               .left_margin    = 0,
+               .hsync_len      = 0,
+               .right_margin   = 320,
+               .upper_margin   = 0,
+               .vsync_len      = 0,
+               .lower_margin   = 38,
+               .sync           = FB_SYNC_CLK_LAT_FALL,
+       },
+#endif
+       {
+               /* unnamed entry for assigning parameters parsed from 'video_mode' string */
+               .refresh        = 60,
+               .left_margin    = 48,
+               .hsync_len      = 96,
+               .right_margin   = 16,
+               .upper_margin   = 31,
+               .vsync_len      = 2,
+               .lower_margin   = 12,
+               .sync           = FB_SYNC_CLK_LAT_FALL,
+       },
+};
+
+int karo_get_fb_mode(const char *name, struct fb_videomode **mode)
+{
+       size_t i;
+
+       if (name == NULL) {
+               if (mode)
+                       *mode = karo_tx_fb_modes;
+               return ARRAY_SIZE(karo_tx_fb_modes);
+       }
+       for (i = 0; i < ARRAY_SIZE(karo_tx_fb_modes); i++) {
+               struct fb_videomode *m = &karo_tx_fb_modes[i];
+
+               if (m->name && strcmp(m->name, name) == 0) {
+                       if (mode)
+                               *mode = m;
+                       return i;
+               }
+       }
+       if (mode)
+               *mode = NULL;
+       return -ENOENT;
+}
diff --git a/board/karo/common/mmc.c b/board/karo/common/mmc.c
new file mode 100644 (file)
index 0000000..53dc00d
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * (C) Copyright 2014 Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <blk.h>
+#include <errno.h>
+#include <fat.h>
+#include <fdt_support.h>
+#include <fs.h>
+#include <libfdt.h>
+#include <mmc.h>
+#include <malloc.h>
+#include <part.h>
+#include <linux/err.h>
+#include <jffs2/load_kernel.h>
+
+#include "karo.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MAX_SEARCH_PARTITIONS 16
+
+static int find_partitions(const char *ifname, int devno, const char *partname,
+                       struct blk_desc **dev_desc, disk_partition_t *info)
+{
+       struct blk_desc *dd;
+       char dev_part_str[16];
+       int p;
+
+       dd = blk_get_devnum_by_typename(ifname, devno);
+       if (!dd || dd->type == DEV_TYPE_UNKNOWN) {
+               printf("** Bad device %s %d **\n", ifname, devno);
+               return -1;
+       }
+       part_init(dd);
+
+       /*
+        * No partition table on device,
+        * or user requested partition 0 (entire device).
+        */
+       if (dd->part_type == PART_TYPE_UNKNOWN) {
+               printf("** No partition table on device %s %d **\n",
+                       ifname, devno);
+               return -ENODEV;
+       }
+
+       printf("part type: %08x\n", dd->part_type);
+       for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) {
+               int ret;
+
+               if (partname) {
+                       ret = part_get_info(dd, p, info);
+                       if (ret == 0)
+                               ret = strncmp((char *)info->name, partname,
+                                       sizeof(info->name));
+               } else {
+                       ret = fat_register_device(dd, p);
+
+               }
+               if (ret)
+                       continue;
+
+               snprintf(dev_part_str, sizeof(dev_part_str), "%d:%d",
+                       devno, p);
+               ret = fs_set_blk_dev(ifname, dev_part_str, FS_TYPE_ANY);
+               if (ret == 0) {
+                       dd->log2blksz = LOG2(dd->blksz);
+                       *dev_desc = dd;
+                       return 0;
+               }
+       }
+       printf("** No valid partition on device %s %d **\n",
+               ifname, devno);
+       return -ENODEV;
+}
+
+static int karo_mmc_find_part(struct mmc *mmc, const char *part,
+                       const char *filename, int devno,
+                       disk_partition_t *part_info)
+{
+       int ret;
+       struct blk_desc *mmc_dev;
+
+#if defined(CONFIG_SYS_DTB_OFFSET) && defined(CONFIG_SYS_MMC_ENV_PART)
+       if (strcmp(part, "dtb") == 0) {
+               const int partnum = CONFIG_SYS_MMC_ENV_PART;
+
+               part_info->blksz = mmc->read_bl_len;
+               part_info->start = CONFIG_SYS_DTB_OFFSET / part_info->blksz;
+               part_info->size = CONFIG_SYS_DTB_PART_SIZE / part_info->blksz;
+               printf("Using virtual partition %s(%d) ["LBAF".."LBAF"]\n",
+                       part, partnum, part_info->start,
+                       part_info->start + part_info->size - 1);
+               return partnum;
+       }
+#endif
+       ret = find_partitions("mmc", devno, part, &mmc_dev, part_info);
+       if (ret < 0) {
+               printf("No (e)MMC partition found: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+int karo_mmc_load_part(const char *part_file, void *addr, size_t len)
+{
+       int ret;
+       struct mmc *mmc;
+       char *partname = strdup(part_file);
+       char *filename;
+       disk_partition_t part_info;
+       int devno = mmc_get_env_dev();
+       lbaint_t blk_cnt;
+
+       if (!partname)
+               return -ENOMEM;
+
+       mmc = find_mmc_device(devno);
+       if (!mmc) {
+               printf("Failed to find mmc%u\n", devno);
+               return -ENODEV;
+       }
+
+       if (mmc_init(mmc)) {
+               printf("Failed to init MMC device %d\n", devno);
+               return -EIO;
+       }
+
+       filename = strchr(partname, ':');
+       if (filename) {
+               *filename = '\0';
+               filename++;
+       } else {
+               filename = partname;
+       }
+
+       blk_cnt = DIV_ROUND_UP(len, mmc->read_bl_len);
+
+       ret = karo_mmc_find_part(mmc, partname, filename, devno, &part_info);
+       if (ret < 0)
+               goto out;
+
+       if (partname == filename) {
+               int partnum = ret;
+               struct blk_desc *desc = mmc_get_blk_desc(mmc);
+               int hwpart = desc->hwpart;
+               ulong retval;
+
+               if (part_info.start + blk_cnt < part_info.start) {
+                       printf("%s: given length 0x%08zx exceeds size of partition\n",
+                               __func__, len);
+                       ret = -EINVAL;
+                       goto out;
+               }
+               if (partnum != hwpart) {
+                       ret = blk_select_hwpart_devnum(IF_TYPE_MMC, devno,
+                                               partnum);
+                       if (ret)
+                               goto out;
+
+                       desc = mmc_get_blk_desc(mmc);
+               }
+               if (part_info.start + blk_cnt > desc->lba)
+                       blk_cnt = desc->lba - part_info.start;
+
+               debug("Reading 0x"LBAF" blks from MMC partition %d offset 0x"LBAF" to %p\n",
+                       blk_cnt, partnum, part_info.start, addr);
+
+               retval = blk_dread(desc, part_info.start, blk_cnt, addr);
+               if (partnum != hwpart)
+                       blk_select_hwpart_devnum(IF_TYPE_MMC, devno, hwpart);
+               if (IS_ERR_VALUE(retval) || retval == 0) {
+                       printf("Failed to read file %s from MMC partition %s\n",
+                               filename, partname);
+                       ret = retval ?: -EIO;
+                       goto out;
+               }
+               debug("Read %lu (%zu) byte from partition '%s' @ offset 0x"LBAF"\n",
+                       retval * mmc->read_bl_len, len, filename, part_info.start);
+       } else {
+               loff_t len_read;
+
+               debug("Trying to read (%zu) byte from file '%s' in mmc partition '%s'\n",
+                       len, filename, partname);
+               ret = fs_read(filename, (ulong)addr, 0, len, &len_read);
+               if (ret < 0) {
+                       printf("Failed to read %zu byte from '%s' in mmc partition '%s'; err: %d\n",
+                               len, filename, partname, ret);
+                       goto out;
+               }
+               debug("Read %llu bytes from %s\n", len_read, filename);
+       }
+out:
+       free(partname);
+       return ret;
+}
diff --git a/board/karo/common/splashimage.c b/board/karo/common/splashimage.c
new file mode 100644 (file)
index 0000000..e3072e8
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * (C) Copyright 2012 Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <common.h>
+#include <console.h>
+#include <errno.h>
+#include <lcd.h>
+#include <nand.h>
+#include <jffs2/load_kernel.h>
+
+#include "karo.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifndef CONFIG_DM_VIDEO
+static ulong calc_fbsize(void)
+{
+       return panel_info.vl_row * panel_info.vl_col *
+               NBITS(panel_info.vl_bpix) / 8;
+}
+#else
+static ulong calc_fbsize(void)
+{
+       return 1;
+}
+#endif
+
+int karo_load_splashimage(int mode)
+{
+       int ret;
+       unsigned long la = gd->fb_base;
+       char *splashimage = getenv("splashimage");
+       ulong fbsize = calc_fbsize();
+       char *end;
+
+       if (!la || !splashimage)
+               return 0;
+
+       if ((simple_strtoul(splashimage, &end, 16) != 0) &&
+               *end == '\0') {
+               if (mode)
+                       return 0;
+               la = simple_strtoul(splashimage, NULL, 16);
+               splashimage = "logo.bmp";
+       } else if (!mode) {
+               return 0;
+       }
+
+       if (had_ctrlc())
+               return -ENODEV;
+
+       ret = karo_load_part(splashimage, (void *)la, fbsize);
+       if (ret) {
+               printf("Failed to load logo from '%s': %d\n", splashimage, ret);
+               return ret;
+       }
+       return 0;
+}
diff --git a/board/karo/txsd/Kconfig b/board/karo/txsd/Kconfig
new file mode 100644 (file)
index 0000000..faa2668
--- /dev/null
@@ -0,0 +1,15 @@
+if TARGET_TXSD_410E
+
+config SYS_BOARD
+       default "txsd"
+
+config SYS_VENDOR
+       default "karo"
+
+config SYS_SOC
+       default "apq8016"
+
+config SYS_CONFIG_NAME
+       default "txsd"
+
+endif
diff --git a/board/karo/txsd/MAINTAINERS b/board/karo/txsd/MAINTAINERS
new file mode 100644 (file)
index 0000000..8d098a3
--- /dev/null
@@ -0,0 +1,6 @@
+TXSD410E BOARD
+M:     Lothar Waßmann <LW@KARO-electronics.de>
+S:     Maintained
+F:     board/karo/txsd/
+F:     include/configs/txsd.h
+F:     configs/txsd-410e_defconfig
diff --git a/board/karo/txsd/Makefile b/board/karo/txsd/Makefile
new file mode 100644 (file)
index 0000000..06b9f79
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2017  Lothar Waßmann <LW@KARO-electronics.de>
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y  := txsd.o
+extra-y += head.o
diff --git a/board/karo/txsd/README b/board/karo/txsd/README
new file mode 100644 (file)
index 0000000..07f15d5
--- /dev/null
@@ -0,0 +1,71 @@
+#
+# (C) Copyright 2016  Lothar Waßmann <LW@KARO-electronics.de>
+#
+# 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/karo/txsd/config.mk b/board/karo/txsd/config.mk
new file mode 100644 (file)
index 0000000..a070fc6
--- /dev/null
@@ -0,0 +1,25 @@
+LOGO_BMP = logos/karo.bmp
+PLATFORM_CPPFLAGS += -Werror
+
+CONFIG_ENV_SIZE := $(shell expr 128 \* 1024)
+CONFIG_U_BOOT_PART_SIZE := $(shell expr 4130 \* 512)
+CONFIG_U_BOOT_IMG_SIZE := $(shell expr 1 \* 1048576)
+
+CONFIG_ENV_OFFSET := $(CONFIG_U_BOOT_PART_SIZE)
+CONFIG_SYS_DTB_OFFSET := $(shell expr 3106 \* 512)
+CONFIG_MAX_DTB_SIZE := $(shell expr $(CONFIG_U_BOOT_PART_SIZE) - $(CONFIG_SYS_DTB_OFFSET))
+
+CONFIG_LOADADDR := $(shell expr `printf %u $(CONFIG_SYS_SDRAM_BASE)` + `printf %u 0x01000000`)
+CONFIG_FDTADDR := $(shell expr `printf %u $(CONFIG_SYS_SDRAM_BASE)` + `printf %u 0x03000000`)
+CONFIG_RDADDR := $(shell expr `printf %u $(CONFIG_SYS_SDRAM_BASE)` + `printf %u 0x03500000`)
+
+PLATFORM_CPPFLAGS += -DCONFIG_LOADADDR=$(shell printf "%08x" $(CONFIG_LOADADDR))
+PLATFORM_CPPFLAGS += -DCONFIG_FDTADDR=$(shell printf "%08x" $(CONFIG_FDTADDR))
+PLATFORM_CPPFLAGS += -DCONFIG_RDADDR=$(shell printf "%08x" $(CONFIG_RDADDR))
+
+PLATFORM_CPPFLAGS += -DCONFIG_ENV_OFFSET=$(shell printf "0x%x" $(CONFIG_ENV_OFFSET))
+PLATFORM_CPPFLAGS += -DCONFIG_ENV_SIZE=$(CONFIG_ENV_SIZE)
+PLATFORM_CPPFLAGS += -DCONFIG_MAX_DTB_SIZE=$(CONFIG_MAX_DTB_SIZE)
+PLATFORM_CPPFLAGS += -DCONFIG_SYS_DTB_PART_SIZE=$(CONFIG_MAX_DTB_SIZE)
+PLATFORM_CPPFLAGS += -DCONFIG_SYS_DTB_OFFSET=$(shell printf "0x%x" $(CONFIG_SYS_DTB_OFFSET))
+PLATFORM_CPPFLAGS += -DCONFIG_U_BOOT_IMG_SIZE=$(CONFIG_U_BOOT_IMG_SIZE)
diff --git a/board/karo/txsd/head.S b/board/karo/txsd/head.S
new file mode 100644 (file)
index 0000000..16dafac
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * ARM64 header for proper chain-loading with Little Kernel.
+ *
+ * (C) 2017 Lothar Waßmann <LW@KARO-electronics.de>
+ *   based on board/qualcomm/dragonboard410c/head.S
+ *     (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com>
+ *
+ * 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
+ *
+ * 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   'A','R','M','d'                 /* Magic number, "ARM\x64" */
+       .word   0                               /* reserved */
diff --git a/board/karo/txsd/txsd.c b/board/karo/txsd/txsd.c
new file mode 100644 (file)
index 0000000..0669bca
--- /dev/null
@@ -0,0 +1,614 @@
+/*
+ * Board init file for TXSD-410E
+ *
+ * (C) Copyright 2017  Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <console.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <lcd.h>
+#include <led.h>
+#include <mmc.h>
+#include <usb.h>
+#include <usb_ether.h>
+#include <asm/gpio.h>
+#ifdef DEBUG
+#include <asm/armv8/mmu.h>
+#endif
+#include <linux/fb.h>
+#include <spmi/spmi.h>
+#include <power/pmic.h>
+#include <power/pmic-qcom-smd-rpm.h>
+
+#include "../common/karo.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SHOW_ACTIVITY
+
+enum {
+       LED_STATE_INIT,
+       LED_STATE_ACTIVE,
+       LED_STATE_DISABLED,
+};
+
+static int led_state = LED_STATE_INIT;
+
+#define FDT_USER_LED_LABEL     "txsd-410e:green:user1"
+
+void show_activity(int arg)
+{
+       static struct udevice *led_dev;
+       static ulong last;
+       int ret;
+
+       if (led_state == LED_STATE_ACTIVE) {
+               static int led_on;
+
+               if (get_timer(last) > CONFIG_SYS_HZ) {
+                       last = get_timer(0);
+                       led_on = !led_on;
+                       ret = led_set_on(led_dev, led_on);
+                       if (ret != 0)
+                               goto disable;
+               }
+       } else if (led_state == LED_STATE_DISABLED) {
+               return;
+       } else if (led_state == LED_STATE_INIT) {
+               ret = led_get_by_label(FDT_USER_LED_LABEL, &led_dev);
+               if (ret) {
+                       printf("No '%s' LED found in DTB\n",
+                               FDT_USER_LED_LABEL);
+                       goto disable;
+               }
+               last = get_timer(0);
+               led_state = LED_STATE_ACTIVE;
+       } else {
+               printf("Invalid LED state: %d @ %p\n", led_state, &led_state);
+               goto disable;
+       }
+       return;
+
+disable:
+       led_state = LED_STATE_DISABLED;
+}
+#endif
+
+#ifdef CONFIG_LCD
+vidinfo_t panel_info = {
+       /* set to max. size supported by SoC */
+       .vl_col = 1920,
+       .vl_row = 1080,
+
+       .vl_bpix = LCD_COLOR32,    /* Bits per pixel, 0: 1bpp, 1: 2bpp, 2: 4bpp, 3: 8bpp ... */
+};
+
+static int lcd_enabled = 1;
+static int lcd_bl_polarity;
+static struct gpio_desc lcd_bl_gpio;
+
+void lcd_enable(void)
+{
+       if (lcd_bl_gpio.dev) {
+               dm_gpio_set_dir_flags(&lcd_bl_gpio, GPIOD_IS_OUT |
+                               (lcd_bl_polarity ? GPIOD_ACTIVE_LOW : 0));
+       }
+}
+
+void lcd_ctrl_init(void *lcdbase)
+{
+       int color_depth = 24;
+       const char *video_mode = karo_get_vmode(getenv("video_mode"));
+       const char *vm;
+       unsigned long val;
+       int refresh = 60;
+       struct fb_videomode *p;
+       struct fb_videomode fb_mode;
+       int xres_set = 0, yres_set = 0, bpp_set = 0, refresh_set = 0;
+
+       if (karo_get_fb_mode(NULL, &p) <= 0)
+               goto disable;
+
+       if (!lcd_enabled) {
+               debug("LCD disabled\n");
+               goto disable;
+       }
+
+       if (had_ctrlc() || video_mode == NULL) {
+               debug("Disabling LCD\n");
+               lcd_enabled = 0;
+               if (had_ctrlc())
+                       setenv("splashimage", NULL);
+               goto disable;
+       }
+
+       karo_fdt_move_fdt();
+       karo_fdt_get_backlight_gpio(gd->fdt_blob, &lcd_bl_gpio);
+       lcd_bl_polarity = karo_fdt_get_backlight_polarity(gd->fdt_blob);
+
+       vm = video_mode;
+       if (karo_fdt_get_fb_mode(gd->fdt_blob, video_mode, &fb_mode) == 0) {
+               p = &fb_mode;
+               debug("Using video mode from FDT\n");
+               vm += strlen(vm);
+               if (fb_mode.xres > panel_info.vl_col ||
+                       fb_mode.yres > panel_info.vl_row) {
+                       printf("video resolution from DT: %dx%d exceeds hardware limits: %dx%d\n",
+                               fb_mode.xres, fb_mode.yres,
+                               panel_info.vl_col, panel_info.vl_row);
+                       lcd_enabled = 0;
+                       goto disable;
+               }
+       }
+       if (p->name != NULL)
+               debug("Trying compiled-in video modes\n");
+       while (p->name != NULL) {
+               if (strcmp(p->name, vm) == 0) {
+                       debug("Using video mode: '%s'\n", p->name);
+                       vm += strlen(vm);
+                       break;
+               }
+               p++;
+       }
+       if (*vm != '\0')
+               debug("Trying to decode video_mode: '%s'\n", vm);
+       while (*vm != '\0') {
+               if (*vm >= '0' && *vm <= '9') {
+                       char *end;
+
+                       val = simple_strtoul(vm, &end, 0);
+                       if (end > vm) {
+                               if (!xres_set) {
+                                       if (val > panel_info.vl_col)
+                                               val = panel_info.vl_col;
+                                       p->xres = val;
+                                       panel_info.vl_col = val;
+                                       xres_set = 1;
+                               } else if (!yres_set) {
+                                       if (val > panel_info.vl_row)
+                                               val = panel_info.vl_row;
+                                       p->yres = val;
+                                       panel_info.vl_row = val;
+                                       yres_set = 1;
+                               } else if (!bpp_set) {
+                                       switch (val) {
+                                       case 24:
+                                       case 18:
+                                               color_depth = val;
+                                               break;
+
+                                       default:
+                                               printf("Invalid color depth: '%.*s' in video_mode; using default: '%u'\n",
+                                                       (int)(end - vm), vm, color_depth);
+                                       }
+                                       bpp_set = 1;
+                               } else if (!refresh_set) {
+                                       refresh = val;
+                                       refresh_set = 1;
+                               }
+                       }
+                       vm = end;
+               }
+               switch (*vm) {
+               case '@':
+                       bpp_set = 1;
+                       /* fallthru */
+               case '-':
+                       yres_set = 1;
+                       /* fallthru */
+               case 'x':
+                       xres_set = 1;
+                       /* fallthru */
+               case 'M':
+               case 'R':
+                       vm++;
+                       break;
+
+               default:
+                       if (*vm != '\0')
+                               vm++;
+               }
+       }
+       if (p->xres == 0 || p->yres == 0) {
+               int num_modes = karo_get_fb_mode(NULL, &p);
+               int i;
+
+               printf("Invalid video mode: %s\n", getenv("video_mode"));
+               lcd_enabled = 0;
+               printf("Supported video modes are:");
+               for (i = 0; i < num_modes; i++, p++) {
+                       if (p->name)
+                               printf(" %s", p->name);
+               }
+               printf("\n");
+               goto disable;
+       }
+       if (p->xres > panel_info.vl_col || p->yres > panel_info.vl_row) {
+               printf("video resolution: %dx%d exceeds hardware limits: %dx%d\n",
+                       p->xres, p->yres, panel_info.vl_col, panel_info.vl_row);
+               lcd_enabled = 0;
+               goto disable;
+       }
+       panel_info.vl_col = p->xres;
+       panel_info.vl_row = p->yres;
+
+       switch (color_depth) {
+       case 8:
+               panel_info.vl_bpix = LCD_COLOR8;
+               break;
+       case 16:
+               panel_info.vl_bpix = LCD_COLOR16;
+               break;
+       default:
+               panel_info.vl_bpix = LCD_COLOR32;
+       }
+
+       p->pixclock = KHZ2PICOS(refresh *
+               (p->xres + p->left_margin + p->right_margin + p->hsync_len) *
+               (p->yres + p->upper_margin + p->lower_margin + p->vsync_len) /
+                               1000);
+       debug("Pixel clock set to %lu.%03lu MHz\n",
+               PICOS2KHZ(p->pixclock) / 1000, PICOS2KHZ(p->pixclock) % 1000);
+
+       if (p != &fb_mode) {
+               int ret;
+
+               debug("Creating new display-timing node from '%s'\n",
+                       video_mode);
+               ret = karo_fdt_create_fb_mode(working_fdt, video_mode, p);
+               if (ret)
+                       printf("Failed to create new display-timing node from '%s': %d\n",
+                               video_mode, ret);
+       }
+
+#if 0
+       gpio_request_array(stk5_lcd_gpios, ARRAY_SIZE(stk5_lcd_gpios));
+       imx_iomux_v3_setup_multiple_pads(stk5_lcd_pads,
+                                       ARRAY_SIZE(stk5_lcd_pads));
+#endif
+       if (karo_load_splashimage(0) == 0) {
+               debug("Initializing LCD controller\n");
+       } else {
+               debug("Skipping initialization of LCD controller\n");
+       }
+       return;
+
+disable:
+       lcd_enabled = 0;
+       panel_info.vl_col = 0;
+       panel_info.vl_row = 0;
+}
+#endif /* CONFIG_LCD */
+
+void txsd_mmc_preinit(void)
+{
+       struct udevice *mmcdev;
+
+       for (uclass_first_device(UCLASS_MMC, &mmcdev); mmcdev;
+            uclass_next_device(&mmcdev)) {
+               struct mmc *m = mmc_get_mmc_dev(mmcdev);
+               if (m)
+                       mmc_set_preinit(m, 1);
+       }
+}
+
+int dram_init(void)
+{
+#ifdef DEBUG
+       const struct mm_region *mm = mem_map;
+       int i;
+
+       for (i = 0; mm->size; i++, mm++) {
+               printf("MMU region[%d]=%08llx..%08llx -> %08llx..%08llx size: %08llx Attrs: %08llx\n",
+                       i, mm->phys, mm->phys + mm->size - 1,
+                       mm->virt, mm->virt + mm->size - 1, mm->size, mm->attrs);
+       }
+#endif
+#if CONFIG_NR_DRAM_BANKS == 1
+       gd->ram_size = PHYS_SDRAM_1_SIZE;
+#else
+       gd->ram_size = PHYS_SDRAM_1_SIZE + PHYS_SDRAM_2_SIZE;
+#endif
+       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;
+       printf("RAM bank 0 size set to %lluMiB\n", gd->bd->bi_dram[0].size / SZ_1M);
+#if CONFIG_NR_DRAM_BANKS > 1
+       gd->bd->bi_dram[1].start = PHYS_SDRAM_2;
+       gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;
+       printf("RAM bank 1 size set to %lluMiB\n", gd->bd->bi_dram[1].size / SZ_1M);
+#endif
+       printf("Total RAM size: %lluMiB\n", gd->ram_size / SZ_1M);
+}
+
+/* run with default environment */
+int board_init(void)
+{
+       if (ctrlc()) {
+               printf("<CTRL-C> detected; safeboot enabled\n");
+               return 0;
+       }
+       txsd_mmc_preinit();
+       return 0;
+}
+
+/* run with env from mass storage device */
+static inline int fdt_err_to_errno(int fdterr)
+{
+       switch (-fdterr) {
+       case FDT_ERR_NOTFOUND:
+               return -ENOENT;
+       case FDT_ERR_EXISTS:
+               return -EEXIST;
+       case FDT_ERR_NOSPACE:
+               return -ENOMEM;
+       case FDT_ERR_BADOFFSET:
+       case FDT_ERR_BADPATH:
+       case FDT_ERR_BADPHANDLE:
+       case FDT_ERR_BADSTATE:
+               return -EINVAL;
+       case FDT_ERR_TRUNCATED:
+               return -EILSEQ;
+       case FDT_ERR_BADMAGIC:
+       case FDT_ERR_BADVERSION:
+       case FDT_ERR_BADSTRUCTURE:
+       case FDT_ERR_BADLAYOUT:
+       case FDT_ERR_INTERNAL:
+       case FDT_ERR_BADNCELLS:
+       case FDT_ERR_TOODEEP:
+               return -EINVAL;
+       }
+       return -EBADFD;
+}
+
+int board_prepare_usb(enum usb_init_type type)
+{
+       static struct gpio_desc vbusen;
+       static int inited;
+       int ret;
+
+       printf("Setting up USB port as %s\n",
+               type == USB_INIT_HOST ? "host" :
+               USB_INIT_DEVICE ? "device" : "invalid");
+       if (type != USB_INIT_HOST && type != USB_INIT_DEVICE)
+               printf("Invalid USB type: %08x\n", type);
+
+       if (!inited) {
+               int off = fdt_path_offset(gd->fdt_blob, "usbhost");
+
+               if (off < 0) {
+                       printf("Could not find 'usbost' node: %s\n",
+                               fdt_strerror(off));
+                       return -ENODEV;
+               }
+               ret = gpio_request_by_name_nodev(gd->fdt_blob, off,
+                                               "switch-gpio", 0, &vbusen, 0);
+               if (ret) {
+                       printf("Failed to request VBUSEN GPIO: %d\n", ret);
+                       return ret;
+               }
+               inited = 1;
+       }
+
+       ret = dm_gpio_set_value(&vbusen, type == USB_INIT_HOST);
+       if (ret == 0)
+               ret = dm_gpio_set_dir_flags(&vbusen, GPIOD_IS_OUT);
+       if (ret == 0)
+               ret = dm_gpio_set_value(&vbusen, type == USB_INIT_HOST);
+
+       return ret;
+}
+
+static int karo_spmi_init(void)
+{
+       int ret;
+       struct udevice *dev;
+
+       ret = uclass_get_device_by_name(UCLASS_SPMI, "spmi", &dev);
+       if (ret)
+               return ret;
+
+       /* Configure PON_PS_HOLD_RESET_CTL for HARD reset */
+       ret = spmi_reg_write(dev, 0, 8, 0x5a, 7);
+       return ret;
+}
+
+/* Check for <CTRL-C> - if pressed - stop autoboot */
+int misc_init_r(void)
+{
+       unsigned long fdt_addr __maybe_unused = getenv_ulong("fdtaddr", 16, 0);
+       int ret;
+
+       env_cleanup();
+
+       if (had_ctrlc()) {
+               setenv_ulong("safeboot", 1);
+               return 0;
+       }
+               setenv("safeboot", NULL);
+
+       ret = karo_spmi_init();
+       if (ret)
+               printf("Failed to initialize SPMI interface: %d\n", ret);
+
+       karo_fdt_move_fdt();
+
+       if (getenv("usbethaddr") && !had_ctrlc()) {
+               uchar mac_addr[ETH_ALEN];
+
+               ret = usb_init();
+               if (ret < 0) {
+                       printf("USB init failed: %d\n", ret);
+                       return 0;
+               }
+               if (eth_getenv_enetaddr("usbethaddr", mac_addr))
+                       printf("MAC address: %pM\n", mac_addr);
+
+       } else {
+               printf("'usbethaddr' not set; skipping USB initialization\n");
+       }
+       return 0;
+}
+
+#ifdef CONFIG_QCOM_SMD_RPM
+#define LDO(n, uV, en) uint32_t ldo##n[] = {                   \
+               LDOA_RES_TYPE, n, KEY_SOFTWARE_ENABLE, 4, GENERIC_##en, \
+               KEY_MICRO_VOLT, 4, uV, }
+
+static LDO(2, 1200000, ENABLE);                // LPDDR
+static LDO(3, 1150000, ENABLE);                // VDD_MEM, PLL, USB
+static LDO(5, 1800000, ENABLE);                // LPDDR I/O
+static LDO(7, 1800000, ENABLE);                // WLAN OSC, PLL2, VDDA2, USBPHY
+static LDO(8, 2900000, ENABLE);                // eMMC
+static LDO(15, 1800000, ENABLE);       // Basisboard VDDIO + L16
+static LDO(16, 1800000, ENABLE);       // Basisboard VDDIO + L15 (55mA)
+static LDO(17, 3300000, ENABLE);       // Basisboard VDD33 (450mA)
+
+static LDO(1, 1225000, DISABLE);       // ext. Conn.
+static LDO(6, 1800000, DISABLE);       // MIPI + Temp Sens.
+static LDO(9, 3300000, DISABLE);       // WLAN
+static LDO(11, 1900000, ENABLE);       // JTAG, ext. Conn. OWIRE
+static LDO(12, 2900000, ENABLE);       // SD-Card
+static LDO(13, 3075000, ENABLE);       // USBPHY
+
+static LDO(4, 1800000, DISABLE);       // NC
+static LDO(10, 1000000, DISABLE);      // NC
+static LDO(14, 1000000, DISABLE);      // NC
+static LDO(18, 1000000, DISABLE);      // NC
+
+#define _debug(fmt...) do {} while (0)
+
+static inline void __smd_regulator_control(uint32_t *data, size_t len,
+                               const char *name)
+{
+       int ret;
+
+       _debug("%s@%d: %sabling %s: %u.%03uV\n", __func__, __LINE__,
+               data[4] == GENERIC_ENABLE ? "En" : "Dis", name,
+               data[7] / 1000000, data[7] / 1000 % 1000);
+       ret = rpm_send_data(data, len, RPM_REQUEST_TYPE);
+       if (ret)
+               printf("Failed to configure regulator %s\n", name);
+       udelay(10000);
+}
+
+#define smd_regulator_control(n)       __smd_regulator_control(n, sizeof(n), #n)
+
+static void smd_pmic_setup(void)
+{
+       smd_rpm_init();
+
+       smd_regulator_control(ldo1);
+       smd_regulator_control(ldo2);
+       smd_regulator_control(ldo3);
+       smd_regulator_control(ldo4);
+       smd_regulator_control(ldo5);
+       smd_regulator_control(ldo6);
+       smd_regulator_control(ldo7);
+       smd_regulator_control(ldo8);
+       smd_regulator_control(ldo9);
+       smd_regulator_control(ldo10);
+       smd_regulator_control(ldo11);
+       smd_regulator_control(ldo12);
+       smd_regulator_control(ldo13);
+       smd_regulator_control(ldo14);
+       smd_regulator_control(ldo15);
+       smd_regulator_control(ldo16);
+       smd_regulator_control(ldo17);
+       smd_regulator_control(ldo18);
+
+       /* turn off unused regulators */
+       smd_regulator_control(ldo4);
+       smd_regulator_control(ldo10);
+       smd_regulator_control(ldo14);
+       smd_regulator_control(ldo18);
+
+       /* enable all essential regulators */
+       smd_regulator_control(ldo2);
+       smd_regulator_control(ldo3);
+       smd_regulator_control(ldo5);
+       smd_regulator_control(ldo7);
+       smd_regulator_control(ldo8);
+       smd_regulator_control(ldo15);
+       smd_regulator_control(ldo16);
+       smd_regulator_control(ldo17);
+
+       /* setup optional regulators */
+       smd_regulator_control(ldo1);
+       smd_regulator_control(ldo6);
+       smd_regulator_control(ldo9);
+       smd_regulator_control(ldo11);
+       smd_regulator_control(ldo12);
+       smd_regulator_control(ldo13);
+
+       smd_rpm_uninit();
+}
+#else
+static inline void smd_pmic_setup(void)
+{
+}
+#endif
+
+int board_late_init(void)
+{
+       if (!getenv("safeboot") && !ctrlc())
+               smd_pmic_setup();
+
+       clear_ctrlc();
+       return 0;
+}
+
+static const char *txsd_touchpanels[] = {
+       "edt,edt-ft5x06",
+       "eeti,egalax_ts",
+};
+
+int ft_board_setup(void *blob, bd_t *bd)
+{
+       int ret;
+       const char *video_mode = karo_get_vmode(getenv("video_mode"));
+
+       ret = fdt_increase_size(blob, 4096);
+       if (ret) {
+               printf("Failed to increase FDT size: %s\n", fdt_strerror(ret));
+               return ret;
+       }
+       karo_fdt_fixup_touchpanel(blob, txsd_touchpanels,
+                               ARRAY_SIZE(txsd_touchpanels));
+       karo_fdt_update_fb_mode(blob, video_mode);
+       smd_rpm_uninit();
+       return 0;
+}
+
+static int do_fastboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+       int ret;
+       struct udevice *dev;
+
+       ret = uclass_get_device_by_name(UCLASS_SPMI, "spmi", &dev);
+       if (ret) {
+               printf("Failed to get SPMI bus: %d\n", ret);
+               return CMD_RET_FAILURE;
+       }
+
+       ret = spmi_reg_write(dev, 0, 8, 0x8f, 8);
+       if (ret)
+               return CMD_RET_FAILURE;
+
+       do_reset(NULL, 0, 0, NULL);
+       return CMD_RET_FAILURE;
+}
+
+U_BOOT_CMD(
+       fastboot, 2, 1, do_fastboot,
+       "reboot into Fastboot protocol\n",
+       "    - run as a fastboot usb device"
+);
diff --git a/board/karo/txsd/u-boot.lds b/board/karo/txsd/u-boot.lds
new file mode 100644 (file)
index 0000000..885e973
--- /dev/null
@@ -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/karo/txsd/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*) }
+}
diff --git a/configs/txsd-410e_defconfig b/configs/txsd-410e_defconfig
new file mode 100644 (file)
index 0000000..5c8f74a
--- /dev/null
@@ -0,0 +1,76 @@
+CONFIG_ARM=y
+CONFIG_ARCH_SNAPDRAGON=y
+CONFIG_TARGET_TXSD_410E=y
+CONFIG_IDENT_STRING="\nKa-Ro electronics TXSD-410E"
+CONFIG_DEFAULT_DEVICE_TREE="txsd-410e"
+CONFIG_SD_BOOT=y
+CONFIG_BOOTDELAY=3
+CONFIG_SYS_NO_FLASH=y
+CONFIG_VERSION_VARIABLE=y
+CONFIG_SYS_PROMPT="TXSD U-Boot > "
+CONFIG_BLK=y
+CONFIG_CLK=y
+CONFIG_CMD_CPU=y # overridden by CONFIG_MP
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_SMD=y
+CONFIG_CMD_SPMI=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_TIMER=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_EXT2=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_EXT4_WRITE=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+# CONFIG_CMD_CRC32 is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+CONFIG_CPU=y
+CONFIG_DEBUG_TIMER_WRAP=y
+CONFIG_DEBUG_TIMER_WRAP_SECONDS=60
+# CONFIG_EFI_LOADER is not set
+CONFIG_MSM_GPIO=y
+CONFIG_PM8916_GPIO=y
+CONFIG_DM_ETH=y
+CONFIG_DM_I2C=y
+CONFIG_DM_I2C_GPIO=y
+CONFIG_DM_MMC=y
+CONFIG_DM_MMC_OPS=y
+CONFIG_DM_PMIC=y
+CONFIG_DM_RTC=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_MSM_SDHCI=y
+CONFIG_OF_BOARD_SETUP=y
+CONFIG_OF_CONTROL=y
+CONFIG_OF_SEPARATE=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+# CONFIG_REQUIRE_SERIAL_CONSOLE is not set
+CONFIG_PMIC_PM8916=y
+CONFIG_MSM_SERIAL=y
+CONFIG_QCOM_SMD=y
+CONFIG_QCOM_SMD_RPM=y
+CONFIG_SPMI_MSM=y
+CONFIG_SYSRESET=y
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+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
+CONFIG_CONSOLE_ROTATION=y
+CONFIG_VIDEO_BRIDGE=y
+# CONFIG_REGEX is not set
diff --git a/include/configs/txsd.h b/include/configs/txsd.h
new file mode 100644 (file)
index 0000000..81cdd9e
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Board configuration file for TXSD-410E
+ *
+ * (C) Copyright 2016  Lothar Waßmann <LW@KARO-electronics.de>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __CONFIGS_TXSD_H
+#define __CONFIGS_TXSD_H
+
+#include <linux/sizes.h>
+#include <asm/arch/sysmap-apq8016.h>
+
+#define CONFIG_ARMV8_PSCI
+#define CONFIG_MISC_INIT_R
+#define CONFIG_BOARD_LATE_INIT
+
+/* Physical Memory Map */
+#define CONFIG_NR_DRAM_BANKS           1
+#define CONFIG_SYS_TEXT_BASE           0x90080000
+#define CONFIG_SYS_SDRAM_BASE          0x90000000
+#define PHYS_SDRAM_1                   CONFIG_SYS_SDRAM_BASE
+#define PHYS_SDRAM_1_SIZE              (3 * SZ_256M)
+
+/* 986 MiB (the last 38MiB are secured for TrustZone by ATF */
+#define CONFIG_SYS_MEM_RESERVE_SECURE  (38 * SZ_1M)
+#define CONFIG_SYS_INIT_SP_ADDR                (CONFIG_SYS_SDRAM_BASE + 0x7fff0)
+
+#define CONFIG_SYS_LOAD_ADDR           _pfx(0x, CONFIG_LOADADDR)
+#define CONFIG_SYS_FDT_ADDR            _pfx(0x, CONFIG_FDTADDR)
+#define CONFIG_SYS_RD_ADDR             _pfx(0x, CONFIG_RDADDR)
+
+#define CONFIG_SYS_MEMTEST_START       PHYS_SDRAM_1
+#define CONFIG_SYS_MEMTEST_END         (PHYS_SDRAM_1 + SZ_512M)
+
+#define CONFIG_SYS_CACHELINE_SIZE      64
+
+/* 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/$(BOARDDIR)/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 relevant 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_RTL8152
+#define CONFIG_USB_ETHER_SMSC95XX
+
+/* LCD Logo and Splash screen support */
+#define CONFIG_LCD
+
+#ifdef CONFIG_LCD
+#define CONFIG_SYS_LVDS_IF
+#define CONFIG_SPLASH_SCREEN
+#define CONFIG_SPLASH_SCREEN_ALIGN
+
+#define CONFIG_LCD_LOGO
+#define LCD_BPP                                LCD_COLOR32
+#define CONFIG_CMD_BMP
+#define CONFIG_BMP_16BPP
+#define CONFIG_BMP_24BPP
+#define CONFIG_BMP_32BPP
+#define CONFIG_VIDEO_BMP_RLE8
+#endif /* CONFIG_LCD */
+
+/* Extra Commands */
+#define CONFIG_CMD_ENV
+#define CONFIG_CMD_GPT
+#define CONFIG_CMD_PART
+#define CONFIG_CMD_TFTP
+#define CONFIG_FAT_WRITE
+
+/* Enable that for switching of boot partitions */
+#define CONFIG_SUPPORT_EMMC_BOOT
+
+/* Partition table support */
+#define HAVE_BLOCK_DEVICE /* Needed for partition commands */
+#define CONFIG_PARTITION_UUIDS
+
+#define CONFIG_BOOTP_DNS
+#define CONFIG_BOOTP_GATEWAY
+#define CONFIG_BOOTP_SUBNETMASK
+
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_DOS_PARTITION
+#define CONFIG_EFI_PARTITION
+#define CONFIG_SUPPORT_RAW_INITRD
+#define CONFIG_SHOW_ACTIVITY
+
+#define xstr(s)                                str(s)
+#define str(s)                         #s
+#define __pfx(x, s)                    (x##s)
+#define _pfx(x, s)                     __pfx(x, s)
+
+/* BOOTP options */
+#define CONFIG_BOOTP_BOOTFILESIZE
+
+/* Environment - Boot*/
+
+#define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 1
+#define EMMC_BOOT_ACK_STR              "emmc_boot_ack=1\0"
+#define EMMC_BOOT_PART_STR             "emmc_boot_part="       \
+       xstr(CONFIG_SYS_MMCSD_FS_BOOT_PARTITION) "\0"
+
+#define CONFIG_BOOTCOMMAND             "run bootcmd_${boot_mode} bootm_cmd"
+#define CONFIG_SYS_AUTOLOAD            "no"
+
+/* Environment */
+#define CONFIG_EXTRA_ENV_SETTINGS                                      \
+       "autostart=no\0"                                                \
+       "baseboard=mb7\0"                                               \
+       "bootargs_mmc=run default_bootargs;setenv bootargs ${bootargs}" \
+       " root=PARTUUID=${rootpart_uuid} rootwait\0"                    \
+       "bootargs_nfs=run default_bootargs;setenv bootargs ${bootargs}" \
+       " root=/dev/nfs nfsroot=${nfs_server}:${nfsroot},nolock"        \
+       " ip=dhcp\0"                                                    \
+       "bootcmd_mmc=setenv autostart no;run bootargs_mmc"              \
+       ";load mmc ${bootpart} ${loadaddr} Image.gz\0"                  \
+       "bootcmd_net=setenv autoload y;setenv autostart n"              \
+       ";run bootargs_nfs;dhcp\0"                                      \
+       "bootcmd_nfs=setenv autoload y;setenv autostart n"              \
+       ";run bootargs_nfs;load mmc ${bootpart} ${loadaddr} Image.gz\0" \
+       "bootdelay=1\0"                                                 \
+       "bootm_cmd=booti ${loadaddr} - ${fdtaddr}\0"                    \
+       "boot_mode=mmc\0"                                               \
+       "bootpart=0:4\0"                                                \
+       "default_bootargs=setenv bootargs init=/linuxrc"                \
+       " console=ttyMSM0,115200n8 panic=1 ${append_bootargs}\0"        \
+       EMMC_BOOT_PART_STR                                              \
+       EMMC_BOOT_ACK_STR                                               \
+       "fdtaddr=" xstr(CONFIG_FDTADDR) "\0"                            \
+       "fdtcontroladdr=" xstr(CONFIG_FDTADDR) "\0"                     \
+       "fdtsave=fdt resize;setexpr fs ${fs} / 200"                     \
+       ";mmc write ${fdtaddr} c22 ${fs}\0"                             \
+       "fdt_high=0xffffffffffffffff\0"                                 \
+       "initrd_high=0xffffffffffffffff\0"                              \
+       "nfsroot=/tftpboot/rootfs\0"                                    \
+       "otg_mode=device\0"                                             \
+       "rdaddr=" xstr(CONFIG_RDADDR) "\0"                              \
+       "rootpart_uuid=7f63ea01-808e-ad2c-6a4b-8f386a2bd218\0"          \
+       "touchpanel=edt-ft5x06\0"                                       \
+       "video_mode=VGA\0"
+
+#define CONFIG_ENV_IS_IN_MMC
+#define CONFIG_SYS_MMC_ENV_DEV         0
+#define CONFIG_SYS_MMC_ENV_PART                0x0
+#define CONFIG_ENV_VARS_UBOOT_CONFIG
+#define CONFIG_ENV_OVERWRITE
+
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN          (CONFIG_ENV_SIZE + SZ_64M)
+
+/* 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)
+#define CONFIG_SYS_BARGSIZE            CONFIG_SYS_CBSIZE
+#define CONFIG_SYS_MAXARGS             64      /* max command args */
+#define CONFIG_CMDLINE_EDITING
+
+#endif /* __CONFIGS_TXSD_H */
index efa95f0..cec8783 100644 (file)
@@ -3044,6 +3044,7 @@ CONFIG_MARVELL_GPIO
 CONFIG_MARVELL_MFP
 CONFIG_MASK_AER_AO
 CONFIG_MAX_DSP_CPUS
+CONFIG_MAX_DTB_SIZE
 CONFIG_MAX_FPGA_DEVICES
 CONFIG_MAX_I2C_NUM
 CONFIG_MAX_MEM_MAPPED
@@ -3806,6 +3807,7 @@ CONFIG_RANDOM_UUID
 CONFIG_RAPIDIO
 CONFIG_RBTREE
 CONFIG_RCAR_BOARD_STRING
+CONFIG_RDADDR
 CONFIG_RD_LVL
 CONFIG_REALMODE_DEBUG
 CONFIG_RED_LED
@@ -5090,6 +5092,8 @@ CONFIG_SYS_DSPI_CTAR4
 CONFIG_SYS_DSPI_CTAR5
 CONFIG_SYS_DSPI_CTAR6
 CONFIG_SYS_DSPI_CTAR7
+CONFIG_SYS_DTB_OFFSET
+CONFIG_SYS_DTB_PART_SIZE
 CONFIG_SYS_DTT_ADM1021
 CONFIG_SYS_DTT_BUS_NUM
 CONFIG_SYS_DTT_HYSTERESIS
@@ -6373,6 +6377,7 @@ CONFIG_SYS_LS_MC_FW_IN_NOR
 CONFIG_SYS_LS_PPA_FW_ADDR
 CONFIG_SYS_LS_PPA_FW_IN_XIP
 CONFIG_SYS_LS_PPA_FW_IN_xxx
+CONFIG_SYS_LVDS_IF
 CONFIG_SYS_M41T11_BASE_YEAR
 CONFIG_SYS_M41T11_EXT_CENTURY_DATA
 CONFIG_SYS_MACB0_BASE
@@ -7395,6 +7400,7 @@ CONFIG_SYS_RCAR_I2C3_BASE
 CONFIG_SYS_RCAR_I2C3_SPEED
 CONFIG_SYS_RCCR
 CONFIG_SYS_RCWH_PCIHOST
+CONFIG_SYS_RD_ADDR
 CONFIG_SYS_READ_SPD
 CONFIG_SYS_REDUNDAND_ENVIRONMENT
 CONFIG_SYS_RELOC_MONITOR_BASE
@@ -8268,6 +8274,7 @@ CONFIG_USE_TTY
 CONFIG_UTBIPAR_INIT_TBIPA
 CONFIG_U_BOOT_HDR_ADDR
 CONFIG_U_BOOT_HDR_SIZE
+CONFIG_U_BOOT_IMG_SIZE
 CONFIG_U_QE
 CONFIG_V38B
 CONFIG_VAL