ipq40xx: add Edgecore OAP-100 support
authorJohn Crispin <john@phrozen.org>
Mon, 7 Sep 2020 11:08:41 +0000 (13:08 +0200)
committerJohn Crispin <john@phrozen.org>
Thu, 17 Sep 2020 06:43:07 +0000 (08:43 +0200)
flashing the unit
* first update to latest edcore FW as per the PDF instructions
* boot the initramfs
  - tftpboot 0x88000000 openwrt-ipq40xx-generic-edgecore_oap100-initramfs-fit-uImage.itb; bootm
* inside the initramfs call the following commiands
  - ubiattach -p /dev/mtd0
  - ubirmvol /dev/ubi0 -n0
  - ubirmvol /dev/ubi0 -n1
  - ubirmvol /dev/ubi0 -n2
* scp the sysupgrade image to the board and call
  - sysupgrade -n openwrt-ipq40xx-generic-edgecore_oap100-squashfs-nand-sysupgrade.bin

Signed-off-by: John Crispin <john@phrozen.org>
package/firmware/ipq-wifi/Makefile
package/firmware/ipq-wifi/board-edgecore_oap100.qca4019 [new file with mode: 0644]
target/linux/ipq40xx/base-files/etc/board.d/01_leds
target/linux/ipq40xx/base-files/etc/board.d/02_network
target/linux/ipq40xx/base-files/etc/hotplug.d/firmware/11-ath10k-caldata
target/linux/ipq40xx/base-files/lib/upgrade/platform.sh
target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-oap100.dts [new file with mode: 0755]
target/linux/ipq40xx/image/Makefile
target/linux/ipq40xx/patches-5.4/100-GPIO-add-named-gpio-exports.patch [new file with mode: 0644]
target/linux/ipq40xx/patches-5.4/901-arm-boot-add-dts-files.patch

index 963cf2d7c4ef836be272168d2ae04374e261de0c..387b23d5563fd7a276c8ce17ecb527da2ccc7787 100644 (file)
@@ -33,6 +33,7 @@ ALLWIFIBOARDS:= \
        dlink_dap2610 \
        edgecore_ecw5211 \
        edgecore_ecw5410 \
+       edgecore_oap100 \
        engenius_eap2200 \
        engenius_emd1 \
        engenius_emr3500 \
@@ -109,6 +110,7 @@ $(eval $(call generate-ipq-wifi-package,cellc_rtl30vw, Cell C RTL30VW))
 $(eval $(call generate-ipq-wifi-package,dlink_dap2610,D-Link DAP-2610))
 $(eval $(call generate-ipq-wifi-package,edgecore_ecw5211,Edgecore ECW5211))
 $(eval $(call generate-ipq-wifi-package,edgecore_ecw5410,Edgecore ECW5410))
+$(eval $(call generate-ipq-wifi-package,edgecore_oap100,Edgecore OAP100))
 $(eval $(call generate-ipq-wifi-package,engenius_eap2200,EnGenius EAP2200))
 $(eval $(call generate-ipq-wifi-package,engenius_emd1,EnGenius EMD1))
 $(eval $(call generate-ipq-wifi-package,engenius_emr3500,EnGenius EMR3500))
diff --git a/package/firmware/ipq-wifi/board-edgecore_oap100.qca4019 b/package/firmware/ipq-wifi/board-edgecore_oap100.qca4019
new file mode 100644 (file)
index 0000000..9f1b5c9
Binary files /dev/null and b/package/firmware/ipq-wifi/board-edgecore_oap100.qca4019 differ
index e9e0de9da9fc5c06dbb3c7d1377aa2e91827f3aa..313722ffb01da66bb4a56dda7fcdef7fe1dcd4af 100755 (executable)
@@ -27,6 +27,10 @@ avm,fritzbox-7530 |\
 glinet,gl-b1300)
        ucidef_set_led_wlan "wlan" "WLAN" "${boardname}:green:wlan" "phy0tpt"
        ;;
+edgecore,oap100)
+       ucidef_set_led_wlan "wlan2g" "WLAN2G" "${boardname}:blue:wlan2g" "phy0tpt"
+       ucidef_set_led_wlan "wlan5g" "WLAN5G" "${boardname}:blue:wlan5g" "phy1tpt"
+       ;;
 engenius,eap1300)
        ucidef_set_led_netdev "lan" "LAN" "${boardname}:blue:lan" "eth0"
        ucidef_set_led_wlan "wlan2g" "WLAN2G" "${boardname}:blue:wlan2g" "phy0tpt"
index 571479aaf210e897d85d3e7dc5e9f295db087118..5c1bdc51ceef69428a33e634f5bd659bbd9afbc8 100755 (executable)
@@ -39,6 +39,7 @@ ipq40xx_setup_interfaces()
        asus,map-ac2200|\
        cilab,meshpoint-one|\
        edgecore,ecw5211|\
+       edgecore,oap100|\
        openmesh,a42|\
        openmesh,a62)
                ucidef_set_interfaces_lan_wan "eth1" "eth0"
index d85424142b306dd040169765d0f47108faa35756..d68e8d54b8ad3e8456a98808607a4bc21b4014bc 100644 (file)
@@ -94,6 +94,7 @@ case "$FIRMWARE" in
        compex,wpj419 |\
        compex,wpj428 |\
        edgecore,ecw5211 |\
+       edgecore,oap100 |\
        engenius,eap1300 |\
        engenius,eap2200 |\
        openmesh,a42 |\
@@ -188,6 +189,7 @@ case "$FIRMWARE" in
        compex,wpj419 |\
        compex,wpj428 |\
        edgecore,ecw5211 |\
+       edgecore,oap100 |\
        engenius,eap1300 |\
        engenius,eap2200 |\
        openmesh,a42 |\
index ae5a0a7c1b3f4baced6033a8eacaa53469ccdb67..0bae8e16817c45ecf992e9605f584842568f0d2f 100644 (file)
@@ -67,6 +67,7 @@ platform_do_upgrade() {
        buffalo,wtr-m2133hp |\
        cilab,meshpoint-one |\
        edgecore,ecw5211 |\
+       edgecore,oap100 |\
        engenius,eap2200 |\
        mobipromo,cm520-79f |\
        qxwlan,e2600ac-c2)
diff --git a/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-oap100.dts b/target/linux/ipq40xx/files/arch/arm/boot/dts/qcom-ipq4019-oap100.dts
new file mode 100755 (executable)
index 0000000..2a92a5d
--- /dev/null
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
+
+#include "qcom-ipq4019.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/soc/qcom,tcsr.h>
+
+/ {
+       model = "EdgeCore OAP-100";
+       compatible = "edgecore,oap100";
+
+       aliases {
+               led-boot = &led_system;
+               led-failsafe = &led_system;
+               led-running = &led_system;
+               led-upgrade = &led_system;
+       };
+
+       chosen {
+               bootargs-append = " root=/dev/ubiblock0_1";
+       };
+
+       soc {
+               mdio@90000 {
+                       status = "okay";
+                       pinctrl-0 = <&mdio_pins>;
+                       pinctrl-names = "default";
+               };
+
+               ess-psgmii@98000 {
+                       status = "okay";
+               };
+
+               tcsr@1949000 {
+                       compatible = "qcom,tcsr";
+                       reg = <0x1949000 0x100>;
+                       qcom,wifi_glb_cfg = <TCSR_WIFI_GLB_CFG>;
+               };
+
+               ess_tcsr@1953000 {
+                       compatible = "qcom,tcsr";
+                       reg = <0x1953000 0x1000>;
+                       qcom,ess-interface-select = <TCSR_ESS_PSGMII>;
+               };
+
+               tcsr@1957000 {
+                       compatible = "qcom,tcsr";
+                       reg = <0x1957000 0x100>;
+                       qcom,wifi_noc_memtype_m0_m2 = <TCSR_WIFI_NOC_MEMTYPE_M0_M2>;
+               };
+
+               tcsr@194b000 {
+                       /* select hostmode */
+                       compatible = "qcom,tcsr";
+                       reg = <0x194b000 0x100>;
+                       qcom,usb-hsphy-mode-select = <TCSR_USB_HSPHY_HOST_MODE>;
+                       status = "okay";
+               };
+
+               usb2@60f8800 {
+                       status = "okay";
+
+                       dwc3@6000000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               usb2_port1: port@1 {
+                                       reg = <1>;
+                                       #trigger-source-cells = <0>;
+                               };
+                       };
+               };
+
+               usb3@8af8800 {
+                       status = "okay";
+
+                       dwc3@8a00000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+
+                               usb3_port1: port@1 {
+                                       reg = <1>;
+                                       #trigger-source-cells = <0>;
+                               };
+
+                               usb3_port2: port@2 {
+                                       reg = <2>;
+                                       #trigger-source-cells = <0>;
+                               };
+                       };
+               };
+
+               crypto@8e3a000 {
+                       status = "okay";
+               };
+
+               watchdog@b017000 {
+                       status = "okay";
+               };
+
+               ess-switch@c000000 {
+                       status = "okay";
+                       switch_mac_mode = <0x0>; /* mac mode for RGMII RMII */
+                       switch_initvlas = <0x0007c 0x54>; /* port0 status */
+                       switch_lan_bmp = <0x10>;
+               };
+
+               edma@c080000 {
+                       status = "okay";
+               };
+       };
+
+       key {
+               compatible = "gpio-keys";
+
+               button@1 {
+                       label = "reset";
+                       linux,code = <KEY_RESTART>;
+                       gpios = <&tlmm 18 GPIO_ACTIVE_LOW>;
+                       linux,input-type = <1>;
+               };
+       };
+
+       leds {
+               compatible = "gpio-leds";
+
+               led_system: led_system {
+                       label = "oap100:green:system";
+                       gpios = <&tlmm 22 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_2g {
+                       label = "oap100:blue:wlan2g";
+                       gpios = <&tlmm 34 GPIO_ACTIVE_HIGH>;
+               };
+
+               led_5g {
+                       label = "oap100:blue:wlan5g";
+                       gpios = <&tlmm 35 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
+       gpio_export {
+               compatible = "gpio-export";
+               #size-cells = <0>;
+
+               usb {
+                       gpio-export,name = "usb-power";
+                       gpio-export,output = <1>;
+                       gpios = <&tlmm 44 GPIO_ACTIVE_HIGH>;
+               };
+
+               poe {
+                       gpio-export,name = "poe-power";
+                       gpio-export,output = <0>;
+                       gpios = <&tlmm 45 GPIO_ACTIVE_HIGH>;
+               };
+       };
+};
+
+&tlmm {
+       serial_0_pins: serial_pinmux {
+               mux {
+                       pins = "gpio16", "gpio17";
+                       function = "blsp_uart0";
+                       bias-disable;
+               };
+       };
+
+       spi_0_pins: spi_0_pinmux {
+               pinmux {
+                       function = "blsp_spi0";
+                       pins = "gpio13", "gpio14", "gpio15";
+                       drive-strength = <12>;
+                       bias-disable;
+               };
+
+               pinmux_cs {
+                       function = "gpio";
+                       pins = "gpio12";
+                       drive-strength = <2>;
+                       bias-disable;
+                       output-high;
+               };
+       };
+
+       nand_pins: nand_pins {
+               pullups {
+                       pins = "gpio53", "gpio58", "gpio59";
+                       function = "qpic";
+                       bias-pull-up;
+               };
+
+               pulldowns {
+                       pins = "gpio54", "gpio55", "gpio56",
+                               "gpio57", "gpio60", "gpio61",
+                               "gpio62", "gpio63", "gpio64",
+                               "gpio65", "gpio66", "gpio67",
+                               "gpio68", "gpio69";
+                       function = "qpic";
+                       bias-pull-down;
+               };
+       };
+
+       mdio_pins: mdio_pinmux {
+               mux_1 {
+                       pins = "gpio6";
+                       function = "mdio";
+                       bias-pull-up;
+               };
+               mux_2 {
+                       pins = "gpio7";
+                       function = "mdc";
+                       bias-pull-up;
+               };
+       };
+};
+
+&cryptobam {
+       status = "okay";
+};
+
+&blsp1_spi1 {
+       pinctrl-0 = <&spi_0_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+       cs-gpios = <&tlmm 12 GPIO_ACTIVE_HIGH>;
+
+       flash@0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "jedec,spi-nor";
+               reg = <0>;
+               linux,modalias = "m25p80", "gd25q256";
+               spi-max-frequency = <24000000>;
+
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition0@0 {
+                               label = "0:SBL1";
+                               reg = <0x00000000 0x00040000>;
+                               read-only;
+                       };
+                       partition1@40000 {
+                               label = "0:MIBIB";
+                               reg = <0x00040000 0x00020000>;
+                               read-only;
+                       };
+                       partition2@60000 {
+                               label = "0:QSEE";
+                               reg = <0x00060000 0x00060000>;
+                               read-only;
+                       };
+                       partition3@c0000 {
+                               label = "0:CDT";
+                               reg = <0x000c0000 0x00010000>;
+                               read-only;
+                       };
+                       partition4@d0000 {
+                               label = "0:DDRPARAMS";
+                               reg = <0x000d0000 0x00010000>;
+                               read-only;
+                       };
+                       partition5@e0000 {
+                               label = "0:APPSBLENV";
+                               reg = <0x000e0000 0x00010000>;
+                               read-only;
+                       };
+                       partition6@f0000 {
+                               label = "0:APPSBL";
+                               reg = <0x000f0000 0x00080000>;
+                               read-only;
+                       };
+                       partition7@170000 {
+                               label = "0:ART";
+                               reg = <0x00170000 0x00010000>;
+                               read-only;
+                       };
+               };
+       };
+};
+
+&nand {
+       pinctrl-0 = <&nand_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+
+       nand@0 {
+               partitions {
+                       compatible = "fixed-partitions";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+
+                       partition@0 {
+                               label = "rootfs";
+                               reg = <0x00000000 0x4000000>;
+                       };
+               };
+       };
+};
+
+&blsp_dma {
+       status = "okay";
+};
+
+&blsp1_uart1 {
+       pinctrl-0 = <&serial_0_pins>;
+       pinctrl-names = "default";
+       status = "okay";
+};
+
+&qpic_bam {
+       status = "okay";
+};
+
+&wifi0 {
+       status = "okay";
+       qcom,ath10k-calibration-variant = "Edgecore OAP100";
+};
+
+&wifi1 {
+       status = "okay";
+       qcom,ath10k-calibration-variant = "Edgecore OAP100";
+};
+
+&usb3_ss_phy {
+       status = "okay";
+};
+
+&usb3_hs_phy {
+       status = "okay";
+};
+
+&usb2_hs_phy {
+       status = "okay";
+};
index 127af99ce582b36fd4e7b48e993a581193102ed2..0f03e1f4297955390ea692d173e50714c5166e6b 100644 (file)
@@ -356,6 +356,19 @@ define Device/edgecore_ecw5211
 endef
 TARGET_DEVICES += edgecore_ecw5211
 
+define Device/edgecore_oap100
+       $(call Device/FitImage)
+       $(call Device/UbiFit)
+       DEVICE_TITLE := Edgecore OAP100
+       BLOCKSIZE := 128k
+       PAGESIZE := 2048
+       IMAGES := nand-sysupgrade.bin
+       DEVICE_DTS_CONFIG := config@ap.dk07.1-c1
+       DEVICE_DTS := qcom-ipq4019-oap100
+       DEVICE_PACKAGES := ipq-wifi-edgecore_oap100 kmod-usb-acm kmod-usb-net kmod-usb-net-cdc-qmi uqmi
+endef
+TARGET_DEVICES += edgecore_oap100
+
 define Device/engenius_eap1300
        $(call Device/FitImage)
        DEVICE_VENDOR := EnGenius
diff --git a/target/linux/ipq40xx/patches-5.4/100-GPIO-add-named-gpio-exports.patch b/target/linux/ipq40xx/patches-5.4/100-GPIO-add-named-gpio-exports.patch
new file mode 100644 (file)
index 0000000..61ed9ea
--- /dev/null
@@ -0,0 +1,165 @@
+From 4267880319bc1a2270d352e0ded6d6386242a7ef Mon Sep 17 00:00:00 2001
+From: John Crispin <blogic@openwrt.org>
+Date: Tue, 12 Aug 2014 20:49:27 +0200
+Subject: [PATCH 24/53] GPIO: add named gpio exports
+
+Signed-off-by: John Crispin <blogic@openwrt.org>
+---
+ drivers/gpio/gpiolib-of.c     |   68 +++++++++++++++++++++++++++++++++++++++++
+ drivers/gpio/gpiolib-sysfs.c  |   10 +++++-
+ include/asm-generic/gpio.h    |    6 ++++
+ include/linux/gpio/consumer.h |    8 +++++
+ 4 files changed, 91 insertions(+), 1 deletion(-)
+
+--- a/drivers/gpio/gpiolib-of.c
++++ b/drivers/gpio/gpiolib-of.c
+@@ -23,6 +23,8 @@
+ #include <linux/pinctrl/pinctrl.h>
+ #include <linux/slab.h>
+ #include <linux/gpio/machine.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
+ #include "gpiolib.h"
+@@ -513,3 +515,68 @@ void of_gpiochip_remove(struct gpio_chip
+       gpiochip_remove_pin_ranges(chip);
+       of_node_put(chip->of_node);
+ }
++
++static struct of_device_id gpio_export_ids[] = {
++      { .compatible = "gpio-export" },
++      { /* sentinel */ }
++};
++
++static int of_gpio_export_probe(struct platform_device *pdev)
++{
++      struct device_node *np = pdev->dev.of_node;
++      struct device_node *cnp;
++      u32 val;
++      int nb = 0;
++
++      for_each_child_of_node(np, cnp) {
++              const char *name = NULL;
++              int gpio;
++              bool dmc;
++              int max_gpio = 1;
++              int i;
++
++              of_property_read_string(cnp, "gpio-export,name", &name);
++
++              if (!name)
++                      max_gpio = of_gpio_count(cnp);
++
++              for (i = 0; i < max_gpio; i++) {
++                      unsigned flags = 0;
++                      enum of_gpio_flags of_flags;
++
++                      gpio = of_get_gpio_flags(cnp, i, &of_flags);
++                      if (!gpio_is_valid(gpio))
++                              return gpio;
++
++                      if (of_flags == OF_GPIO_ACTIVE_LOW)
++                              flags |= GPIOF_ACTIVE_LOW;
++
++                      if (!of_property_read_u32(cnp, "gpio-export,output", &val))
++                              flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
++                      else
++                              flags |= GPIOF_IN;
++
++                      if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
++                              continue;
++
++                      dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
++                      gpio_export_with_name(gpio, dmc, name);
++                      nb++;
++              }
++      }
++
++      dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
++
++      return 0;
++}
++
++static struct platform_driver gpio_export_driver = {
++      .driver         = {
++              .name           = "gpio-export",
++              .owner  = THIS_MODULE,
++              .of_match_table = of_match_ptr(gpio_export_ids),
++      },
++      .probe          = of_gpio_export_probe,
++};
++
++module_platform_driver(gpio_export_driver);
+--- a/drivers/gpio/gpiolib-sysfs.c
++++ b/drivers/gpio/gpiolib-sysfs.c
+@@ -553,7 +553,7 @@ static struct class gpio_class = {
+  *
+  * Returns zero on success, else an error.
+  */
+-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
+ {
+       struct gpio_chip        *chip;
+       struct gpio_device      *gdev;
+@@ -615,6 +615,8 @@ int gpiod_export(struct gpio_desc *desc,
+       offset = gpio_chip_hwgpio(desc);
+       if (chip->names && chip->names[offset])
+               ioname = chip->names[offset];
++      if (name)
++              ioname = name;
+       dev = device_create_with_groups(&gpio_class, &gdev->dev,
+                                       MKDEV(0, 0), data, gpio_groups,
+@@ -636,6 +638,12 @@ err_unlock:
+       gpiod_dbg(desc, "%s: status %d\n", __func__, status);
+       return status;
+ }
++EXPORT_SYMBOL_GPL(__gpiod_export);
++
++int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
++{
++      return __gpiod_export(desc, direction_may_change, NULL);
++}
+ EXPORT_SYMBOL_GPL(gpiod_export);
+ static int match_export(struct device *dev, const void *desc)
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -127,6 +127,12 @@ static inline int gpio_export(unsigned g
+       return gpiod_export(gpio_to_desc(gpio), direction_may_change);
+ }
++int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
++static inline int gpio_export_with_name(unsigned gpio, bool direction_may_change, const char *name)
++{
++      return __gpiod_export(gpio_to_desc(gpio), direction_may_change, name);
++}
++
+ static inline int gpio_export_link(struct device *dev, const char *name,
+                                  unsigned gpio)
+ {
+--- a/include/linux/gpio/consumer.h
++++ b/include/linux/gpio/consumer.h
+@@ -451,6 +451,7 @@ struct gpio_desc *devm_fwnode_get_gpiod_
+ #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
++int _gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
+ int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
+ int gpiod_export_link(struct device *dev, const char *name,
+                     struct gpio_desc *desc);
+@@ -458,6 +459,13 @@ void gpiod_unexport(struct gpio_desc *de
+ #else  /* CONFIG_GPIOLIB && CONFIG_GPIO_SYSFS */
++static inline int _gpiod_export(struct gpio_desc *desc,
++                             bool direction_may_change,
++                             const char *name)
++{
++      return -ENOSYS;
++}
++
+ static inline int gpiod_export(struct gpio_desc *desc,
+                              bool direction_may_change)
+ {
index ea45606c27a8e6c7053c9a4cf7626ac1da6c25ca..e2dc45a39fac0bce7933618e8d1ec009928cc916 100644 (file)
@@ -12,7 +12,7 @@ Index: linux-5.4.63/arch/arm/boot/dts/Makefile
 ===================================================================
 --- linux-5.4.63.orig/arch/arm/boot/dts/Makefile
 +++ linux-5.4.63/arch/arm/boot/dts/Makefile
-@@ -837,11 +837,51 @@ dtb-$(CONFIG_ARCH_QCOM) += \
+@@ -837,11 +837,52 @@ dtb-$(CONFIG_ARCH_QCOM) += \
        qcom-apq8074-dragonboard.dtb \
        qcom-apq8084-ifc6540.dtb \
        qcom-apq8084-mtp.dtb \
@@ -32,6 +32,7 @@ Index: linux-5.4.63/arch/arm/boot/dts/Makefile
 +      qcom-ipq4018-jalapeno.dtb \
 +      qcom-ipq4018-meshpoint-one.dtb \
 +      qcom-ipq4018-nbg6617.dtb \
++      qcom-ipq4019-oap100.dtb \
 +      qcom-ipq4018-rt-ac58u.dtb \
 +      qcom-ipq4018-wre6606.dtb \
        qcom-ipq4019-ap.dk01.1-c1.dtb \