checkpoint madrone-usb

Change-Id: I41ba7e1f5bb0362152ddd294ce4cd27f1887f84e
diff --git a/system/dev/board/imx8mevk/imx8mevk-usb.c b/system/dev/board/imx8mevk/imx8mevk-usb.c
index 8febdcc..7276061 100644
--- a/system/dev/board/imx8mevk/imx8mevk-usb.c
+++ b/system/dev/board/imx8mevk/imx8mevk-usb.c
@@ -93,7 +93,7 @@
     }
 };
 
-// USB1 is USB-A port, host only
+// USB2 is USB-A port, host only
 static const pbus_dev_t usb2_dev = {
     .name = "dwc3-2",
     .vid = PDEV_VID_GENERIC,
@@ -110,9 +110,31 @@
 };
 
 zx_status_t imx_usb_phy_init(zx_paddr_t usb_base, size_t usb_length, zx_handle_t bti) {
+    // turn on usb via smc calls
+    zx_smc_parameters_t otg1_en_params = {.func_id = IMX8M_SIP_GPC,
+                                          .arg1 = IMX8M_SIP_CONFIG_GPC_PM_DOMAIN,
+                                          .arg2 = IMX8M_PD_USB_OTG1,
+                                          .arg3 = 1};
+    zx_smc_result_t smc_result;
+    zx_status_t status = zx_smc_call(get_root_resource(), &otg1_en_params, &smc_result);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "%s: SMC call to turn USB on failed %d\n", __FUNCTION__, status);
+        return status;
+    }
+
+    zx_smc_parameters_t otg2_en_params = {.func_id = IMX8M_SIP_GPC,
+                                          .arg1 = IMX8M_SIP_CONFIG_GPC_PM_DOMAIN,
+                                          .arg2 = IMX8M_PD_USB_OTG2,
+                                          .arg3 = 1};
+    status = zx_smc_call(get_root_resource(), &otg2_en_params, &smc_result);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "%s: SMC call to turn USB on failed %d\n", __FUNCTION__, status);
+        return status;
+    }
+
     uint32_t reg;
     io_buffer_t usb_buf;
-    zx_status_t status = io_buffer_init_physical(&usb_buf, bti, usb_base, usb_length,
+    status = io_buffer_init_physical(&usb_buf, bti, usb_base, usb_length,
                                         get_root_resource(), ZX_CACHE_POLICY_UNCACHED_DEVICE);
     if (status != ZX_OK) {
         zxlogf(ERROR, "%s io_buffer_init_physical failed %d\n", __FUNCTION__, status);
@@ -146,28 +168,6 @@
     zx_status_t status;
     zx_handle_t bti;
 
-    // turn on usb via smc calls
-    zx_smc_parameters_t otg1_en_params = {.func_id = IMX8M_SIP_GPC,
-                                          .arg1 = IMX8M_SIP_CONFIG_GPC_PM_DOMAIN,
-                                          .arg2 = IMX8M_PD_USB_OTG1,
-                                          .arg3 = 1};
-    zx_smc_result_t smc_result;
-    status = zx_smc_call(get_root_resource(), &otg1_en_params, &smc_result);
-    if (status != ZX_OK) {
-        zxlogf(ERROR, "%s: SMC call to turn USB on failed %d\n", __FUNCTION__, status);
-        return status;
-    }
-
-    zx_smc_parameters_t otg2_en_params = {.func_id = IMX8M_SIP_GPC,
-                                          .arg1 = IMX8M_SIP_CONFIG_GPC_PM_DOMAIN,
-                                          .arg2 = IMX8M_PD_USB_OTG2,
-                                          .arg3 = 1};
-    status = zx_smc_call(get_root_resource(), &otg2_en_params, &smc_result);
-    if (status != ZX_OK) {
-        zxlogf(ERROR, "%s: SMC call to turn USB on failed %d\n", __FUNCTION__, status);
-        return status;
-    }
-
     status = iommu_get_bti(&bus->iommu, 0, BTI_BOARD, &bti);
     if (status != ZX_OK) {
         zxlogf(ERROR, "%s: iommu_get_bti failed %d\n", __FUNCTION__, status);
diff --git a/system/dev/board/imx8mevk/imx8mevk.c b/system/dev/board/imx8mevk/imx8mevk.c
index 261709c..9bad241 100644
--- a/system/dev/board/imx8mevk/imx8mevk.c
+++ b/system/dev/board/imx8mevk/imx8mevk.c
@@ -121,8 +121,13 @@
         gpio_set_alt_function(&bus->gpio, 0, imx8mevk_pinmux[i]);
     }
 
-    if ((status = imx_usb_init(bus)) != ZX_OK) {
-        zxlogf(ERROR, "%s: failed %d\n", __FUNCTION__, status);
+    if (bus->board == BOARD_MADRONE) {
+        status = madrone_usb_init(bus);
+    } else {
+        status = imx_usb_init(bus);
+    }
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "%s: USB init failed %d\n", __FUNCTION__, status);
         goto fail;
     }
 
@@ -160,6 +165,13 @@
         goto fail;
     }
 
+    const char* board_name = pbus_get_board_name(&bus->pbus);
+    if (!strcmp(board_name, "madrone")) {
+        bus->board = BOARD_MADRONE;
+    } else {
+        bus->board = BOARD_IMX8M_EVK;
+    }
+
     // get default BTI from the dummy IOMMU implementation in the platform bus
     status = device_get_protocol(parent, ZX_PROTOCOL_IOMMU, &bus->iommu);
     if (status != ZX_OK) {
diff --git a/system/dev/board/imx8mevk/imx8mevk.h b/system/dev/board/imx8mevk/imx8mevk.h
index 03a2399..d9e60f0 100644
--- a/system/dev/board/imx8mevk/imx8mevk.h
+++ b/system/dev/board/imx8mevk/imx8mevk.h
@@ -18,20 +18,25 @@
     BTI_DISPLAY,
     BTI_GPU,
     BTI_SDHCI,
-
 };
 
+typedef enum {
+    BOARD_IMX8M_EVK,
+    BOARD_MADRONE,
+} imx8_board_t;
+
 typedef struct {
     platform_bus_protocol_t     pbus;
     zx_device_t*                parent;
     iommu_protocol_t            iommu;
     gpio_protocol_t             gpio;
     zx_handle_t                 bti_handle;
-    uint32_t                    soc_pid;
+    imx8_board_t                board;
 } imx8mevk_bus_t;
 
-
 zx_status_t imx8m_gpio_init(imx8mevk_bus_t* bus);
+zx_status_t imx_usb_phy_init(zx_paddr_t usb_base, size_t usb_length, zx_handle_t bti);
 zx_status_t imx_usb_init(imx8mevk_bus_t* bus);
+zx_status_t madrone_usb_init(imx8mevk_bus_t* bus);
 zx_status_t imx_gpu_init(imx8mevk_bus_t* bus);
 zx_status_t imx8m_sdhci_init(imx8mevk_bus_t* bus);
\ No newline at end of file
diff --git a/system/dev/board/imx8mevk/madrone-usb.c b/system/dev/board/imx8mevk/madrone-usb.c
new file mode 100644
index 0000000..79252c6
--- /dev/null
+++ b/system/dev/board/imx8mevk/madrone-usb.c
@@ -0,0 +1,163 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdio.h>
+
+#include <ddk/debug.h>
+#include <ddk/metadata.h>
+#include <ddk/protocol/platform-defs.h>
+#include <ddk/protocol/usb-mode-switch.h>
+#include <soc/imx8m/imx8m-gpio.h>
+#include <soc/imx8m/imx8m-hw.h>
+#include <soc/imx8m/imx8m-sip.h>
+#include <zircon/syscalls/smc.h>
+
+#include "imx8mevk.h"
+
+static const pbus_mmio_t dwc3_mmios[] = {
+    {
+        .base = IMX8M_USB1_BASE,
+        .length = IMX8M_USB1_LENGTH,
+    },
+};
+
+static const pbus_irq_t dwc3_irqs[] = {
+    {
+        .irq = IMX8M_A53_INTR_USB1,
+        .mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
+    },
+};
+
+static const pbus_bti_t dwc3_btis[] = {
+    {
+        .iommu_index = 0,
+        .bti_id = BTI_USB1,
+    },
+};
+
+static usb_mode_t dwc3_mode = USB_MODE_HOST;
+
+static const pbus_metadata_t dwc3_metadata[] = {
+    {
+        .type       = DEVICE_METADATA_USB_MODE,
+        .data       = &dwc3_mode,
+        .len        = sizeof(dwc3_mode),
+    }
+};
+
+static const pbus_dev_t madrone_usb_children[] = {
+    {
+        .name = "dwc3",
+        .vid = PDEV_VID_GENERIC,
+        .pid = PDEV_PID_GENERIC,
+        .did = PDEV_DID_USB_DWC3,
+        .mmios = dwc3_mmios,
+        .mmio_count = countof(dwc3_mmios),
+        .irqs = dwc3_irqs,
+        .irq_count = countof(dwc3_irqs),
+        .btis = dwc3_btis,
+        .bti_count = countof(dwc3_btis),
+        .metadata = dwc3_metadata,
+        .metadata_count = countof(dwc3_metadata),
+    },
+};
+
+static const pbus_gpio_t madrone_usb_gpios[] = {
+    {
+        .gpio = IMX_GPIO_PIN(5, 4), // first argument is 1-based
+    },
+};
+
+const pbus_dev_t madrone_usb_dev = {
+    .name = "madrone-usb",
+    .vid = PDEV_VID_GOOGLE,
+    .pid = PDEV_PID_MADRONE,
+    .did = PDEV_DID_MADRONE_USB,
+    .gpios = madrone_usb_gpios,
+    .gpio_count = countof(madrone_usb_gpios),
+    .children = madrone_usb_children,
+    .child_count = countof(madrone_usb_children),
+};
+
+static const pbus_mmio_t usb2_mmios[] = {
+    {
+        .base = IMX8M_USB2_BASE,
+        .length = IMX8M_USB2_LENGTH,
+    },
+};
+static const pbus_irq_t usb2_irqs[] = {
+    {
+        .irq = IMX8M_A53_INTR_USB2,
+        .mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
+    },
+};
+
+static const pbus_bti_t usb2_btis[] = {
+    {
+        .iommu_index = 0,
+        .bti_id = BTI_USB2,
+    },
+};
+
+static usb_mode_t usb2_mode = USB_MODE_HOST;
+
+static const pbus_metadata_t usb2_metadata[] = {
+    {
+        .type       = DEVICE_METADATA_USB_MODE,
+        .data       = &usb2_mode,
+        .len        = sizeof(usb2_mode),
+    }
+};
+
+// USB2 is USB-A port, host only
+static const pbus_dev_t usb2_dev = {
+    .name = "dwc3-2",
+    .vid = PDEV_VID_GENERIC,
+    .pid = PDEV_PID_GENERIC,
+    .did = PDEV_DID_USB_XHCI,
+    .mmios = usb2_mmios,
+    .mmio_count = countof(usb2_mmios),
+    .irqs = usb2_irqs,
+    .irq_count = countof(usb2_irqs),
+    .btis = usb2_btis,
+    .bti_count = countof(usb2_btis),
+    .metadata = usb2_metadata,
+    .metadata_count = countof(usb2_metadata),
+};
+
+
+zx_status_t madrone_usb_init(imx8mevk_bus_t* bus) {
+    zx_status_t status;
+    zx_handle_t bti;
+
+    status = iommu_get_bti(&bus->iommu, 0, BTI_BOARD, &bti);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "%s: iommu_get_bti failed %d\n", __FUNCTION__, status);
+        return status;
+    }
+
+    status = imx_usb_phy_init(IMX8M_USB1_BASE, IMX8M_USB1_LENGTH, bti);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "%s: imx_usb_phy_init failed %d\n", __FUNCTION__, status);
+        zx_handle_close(bti);
+        return status;
+    }
+    status = imx_usb_phy_init(IMX8M_USB2_BASE, IMX8M_USB2_LENGTH, bti);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "%s: imx_usb_phy_init failed %d\n", __FUNCTION__, status);
+        zx_handle_close(bti);
+        return status;
+    }
+    zx_handle_close(bti);
+
+    if ((status = pbus_device_add(&bus->pbus, &madrone_usb_dev)) != ZX_OK) {
+        zxlogf(ERROR, "imx_usb_init could not add madrone_usb_dev: %d\n", status);
+        return status;
+    }
+    if ((status = pbus_device_add(&bus->pbus, &usb2_dev)) != ZX_OK) {
+        zxlogf(ERROR, "imx_usb_init could not add usb2_dev: %d\n", status);
+        return status;
+    }
+    return ZX_OK;
+}
diff --git a/system/dev/board/imx8mevk/rules.mk b/system/dev/board/imx8mevk/rules.mk
index b435bfe..e914224 100644
--- a/system/dev/board/imx8mevk/rules.mk
+++ b/system/dev/board/imx8mevk/rules.mk
@@ -14,7 +14,7 @@
     $(LOCAL_DIR)/imx8mevk-gpu.c \
     $(LOCAL_DIR)/imx8mevk-usb.c \
     $(LOCAL_DIR)/imx8mevk-sdhci.c \
-
+    $(LOCAL_DIR)/madrone-usb.c \
 
 MODULE_STATIC_LIBS := \
     system/dev/lib/imx8m \
diff --git a/system/dev/usb/madrone-usb/bind.c b/system/dev/usb/madrone-usb/bind.c
new file mode 100644
index 0000000..53eec9b
--- /dev/null
+++ b/system/dev/usb/madrone-usb/bind.c
@@ -0,0 +1,21 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ddk/binding.h>
+#include <ddk/driver.h>
+#include <ddk/protocol/platform-defs.h>
+
+extern zx_status_t madrone_usb_bind(void* ctx, zx_device_t* parent);
+
+static zx_driver_ops_t madrone_usb_driver_ops = {
+    .version = DRIVER_OPS_VERSION,
+    .bind = madrone_usb_bind,
+};
+
+ZIRCON_DRIVER_BEGIN(madrone_usb, madrone_usb_driver_ops, "zircon", "0.1", 4)
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PLATFORM_DEV),
+    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_GOOGLE),
+    BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_MADRONE),
+    BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_MADRONE_USB),
+ZIRCON_DRIVER_END(hikey_usb)
diff --git a/system/dev/usb/madrone-usb/madrone-usb.cpp b/system/dev/usb/madrone-usb/madrone-usb.cpp
new file mode 100644
index 0000000..798c06a
--- /dev/null
+++ b/system/dev/usb/madrone-usb/madrone-usb.cpp
@@ -0,0 +1,127 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "madrone-usb.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <ddk/binding.h>
+#include <ddk/debug.h>
+#include <ddk/device.h>
+#include <ddk/driver.h>
+#include <ddk/protocol/platform-defs.h>
+#include <ddk/protocol/platform-device.h>
+#include <ddktl/protocol/gpio.h>
+#include <fbl/unique_ptr.h>
+
+namespace madrone_usb {
+
+zx_status_t MadroneUsb::Create(zx_device_t* parent) {
+    fbl::AllocChecker ac;
+    auto bus = fbl::make_unique_checked<MadroneUsb>(&ac, parent);
+    if (!ac.check()) {
+        return ZX_ERR_NO_MEMORY;
+    }
+
+    auto status = bus->Init();
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    // devmgr is now in charge of the device.
+    __UNUSED auto* dummy = bus.release();
+    return ZX_OK;
+}
+
+zx_status_t MadroneUsb::Init() {
+    platform_device_protocol_t pdev;
+
+    auto status = device_get_protocol(parent(), ZX_PROTOCOL_PLATFORM_DEV, &pdev);
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    status = device_get_protocol(parent(), ZX_PROTOCOL_GPIO, &gpio_);
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    ddk::GpioProtocolProxy gpio(&gpio_);
+    if (status != ZX_OK) {
+        return status;
+    }
+    status = gpio.Config(0, GPIO_DIR_IN | GPIO_TRIGGER_RISING | GPIO_TRIGGER_FALLING);
+
+    status = gpio.GetInterrupt(0, ZX_INTERRUPT_MODE_EDGE_BOTH, interrupt_.reset_and_get_address());
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    zx_device_prop_t props[] = {
+        {BIND_PLATFORM_DEV_VID, 0, PDEV_VID_GENERIC},
+        {BIND_PLATFORM_DEV_PID, 0, PDEV_PID_GENERIC},
+        {BIND_PLATFORM_DEV_DID, 0, PDEV_DID_USB_DWC3},
+    };
+
+    device_add_args_t args = {};
+    args.version = DEVICE_ADD_ARGS_VERSION;
+    args.name = "dwc3";
+    args.ctx = this;
+    args.ops = &ddk_device_proto_;
+    args.props = props;
+    args.prop_count = countof(props);
+    args.proto_id = ddk_proto_id_;
+    args.proto_ops = ddk_proto_ops_;
+
+    status = pdev_device_add(&pdev, 0, &args, &zxdev_);
+    if (status != ZX_OK) {
+        return status;
+    }
+
+    auto thunk = [](void* arg) { return static_cast<MadroneUsb*>(arg)->InterruptThread(); };
+    thrd_create_with_name(&interrupt_thread_, thunk, this, "MadroneUsb::InterruptThread");
+    return ZX_OK;
+}
+
+int MadroneUsb::InterruptThread() {
+    while (true) {
+        zx::time timestamp;
+        auto status = interrupt_.wait(&timestamp);
+        printf("MadroneUsb::InterruptThread got %d\n", status);
+    }
+    return 0;
+}
+
+zx_status_t MadroneUsb::UmsSetMode(usb_mode_t mode) {
+/*
+    if (mode == usb_mode_) {
+        return ZX_OK;
+    }
+    if (mode == USB_MODE_OTG) {
+        return ZX_ERR_NOT_SUPPORTED;
+    }
+
+    ddk::GpioProtocolProxy gpio(&gpio_);
+    gpio.Write(HUB_VDD33_EN, mode == USB_MODE_HOST);
+    gpio.Write(VBUS_TYPEC, mode == USB_MODE_HOST);
+    gpio.Write(USBSW_SW_SEL, mode == USB_MODE_HOST);
+
+    usb_mode_ = mode;
+*/
+    return ZX_OK;
+}
+
+void MadroneUsb::DdkRelease() {
+    delete this;
+}
+
+} // namespace madrone_usb
+
+zx_status_t madrone_usb_bind(void* ctx, zx_device_t* parent) {
+    return madrone_usb::MadroneUsb::Create(parent);
+}
diff --git a/system/dev/usb/madrone-usb/madrone-usb.h b/system/dev/usb/madrone-usb/madrone-usb.h
new file mode 100644
index 0000000..2bc7c28
--- /dev/null
+++ b/system/dev/usb/madrone-usb/madrone-usb.h
@@ -0,0 +1,53 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <threads.h>
+
+#include <ddk/device.h>
+#include <ddktl/device.h>
+#include <ddktl/protocol/gpio.h>
+#include <ddktl/protocol/usb-mode-switch.h>
+#include <fbl/macros.h>
+#include <lib/zx/interrupt.h>
+
+namespace madrone_usb {
+
+class MadroneUsb;
+using MadroneUsbType = ddk::Device<MadroneUsb>;
+
+// This is the main class for the platform bus driver.
+class MadroneUsb : public MadroneUsbType, public ddk::UmsProtocol<MadroneUsb> {
+public:
+    explicit MadroneUsb(zx_device_t* parent)
+        : MadroneUsbType(parent), usb_mode_(USB_MODE_NONE) {}
+
+    static zx_status_t Create(zx_device_t* parent);
+
+    // Device protocol implementation.
+    void DdkRelease();
+
+    // USB mode switch protocol implementation.
+    zx_status_t UmsSetMode(usb_mode_t mode);
+
+private:
+    DISALLOW_COPY_ASSIGN_AND_MOVE(MadroneUsb);
+
+    zx_status_t Init();
+
+    int InterruptThread();
+
+    gpio_protocol_t gpio_;
+    usb_mode_t usb_mode_;
+
+    thrd_t interrupt_thread_;
+    zx::interrupt interrupt_;
+};
+
+} // namespace madrone_usb
+
+__BEGIN_CDECLS
+zx_status_t madrone_usb_bind(void* ctx, zx_device_t* parent);
+__END_CDECLS
diff --git a/system/dev/usb/madrone-usb/rules.mk b/system/dev/usb/madrone-usb/rules.mk
new file mode 100644
index 0000000..3a773d8
--- /dev/null
+++ b/system/dev/usb/madrone-usb/rules.mk
@@ -0,0 +1,27 @@
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+MODULE := $(LOCAL_DIR)
+
+MODULE_TYPE := driver
+
+MODULE_SRCS := \
+    $(LOCAL_DIR)/bind.c \
+    $(LOCAL_DIR)/madrone-usb.cpp \
+
+MODULE_STATIC_LIBS := \
+    system/ulib/ddk \
+    system/ulib/ddktl \
+    system/ulib/fbl \
+    system/ulib/zx \
+    system/ulib/zxcpp \
+
+MODULE_LIBS := \
+    system/ulib/driver \
+    system/ulib/zircon \
+    system/ulib/c \
+
+include make/module.mk
diff --git a/system/ulib/ddk/include/ddk/protocol/platform-defs.h b/system/ulib/ddk/include/ddk/protocol/platform-defs.h
index 764b255..b61b8d5 100644
--- a/system/ulib/ddk/include/ddk/protocol/platform-defs.h
+++ b/system/ulib/ddk/include/ddk/protocol/platform-defs.h
@@ -57,6 +57,7 @@
 #define PDEV_DID_GAUSS_LED          4
 #define PDEV_DID_ASTRO_FOCALTOUCH   5
 #define PDEV_DID_ASTRO_GOODIXTOUCH  6
+#define PDEV_DID_MADRONE_USB        7
 
 
 // Khadas