[dev][aml-ethernet-s912] Convert to a composite device driver.

This driver now uses composite protocol to access I2C and GPIOs.

TEST: pave vim2 over ethernet.
Change-Id: I6db6552be21b80e3aa79947c21feb4cc5044cbd7
diff --git a/zircon/system/dev/board/vim/vim-eth.cpp b/zircon/system/dev/board/vim/vim-eth.cpp
index 6f051da..f964e95 100644
--- a/zircon/system/dev/board/vim/vim-eth.cpp
+++ b/zircon/system/dev/board/vim/vim-eth.cpp
@@ -15,17 +15,9 @@
 #include <limits.h>
 
 #include "vim.h"
+#include "vim-gpios.h"
+
 namespace vim {
-static const pbus_gpio_t eth_board_gpios[] = {
-    {
-        // MAC_RST
-        .gpio = S912_GPIOZ(14),
-    },
-    {
-        // MAC_INTR (need to wire up interrupt?)
-        .gpio = S912_GPIOZ(15),
-    },
-};
 
 static const pbus_irq_t eth_mac_irqs[] = {
     {
@@ -96,13 +88,6 @@
     },
 };
 
-static const pbus_i2c_channel_t vim2_mcu_i2c[] = {
-    {
-        .bus_id = 1,
-        .address = 0x18,
-    },
-};
-
 static pbus_dev_t eth_board_dev = [](){
     pbus_dev_t dev;
     dev.name = "ethernet_mac";
@@ -111,10 +96,6 @@
     dev.did = PDEV_DID_AMLOGIC_ETH;
     dev.mmio_list = eth_board_mmios;
     dev.mmio_count = countof(eth_board_mmios);
-    dev.gpio_list = eth_board_gpios;
-    dev.gpio_count = countof(eth_board_gpios);
-    dev.i2c_channel_list = vim2_mcu_i2c;
-    dev.i2c_channel_count = countof(vim2_mcu_i2c);
     dev.metadata_list = eth_board_metadata;
     dev.metadata_count = countof(eth_board_metadata);
     return dev;
@@ -138,10 +119,43 @@
     return dev;
 }();
 
-// Composite binding rules for ethernet driver.
 static const zx_bind_inst_t root_match[] = {
     BI_MATCH(),
 };
+
+// Composite binding rules for ethernet board driver.
+const zx_bind_inst_t i2c_match[] = {
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_I2C),
+    BI_ABORT_IF(NE, BIND_I2C_BUS_ID, 1),
+    BI_MATCH_IF(EQ, BIND_I2C_ADDRESS, 0x18),
+};
+static const zx_bind_inst_t gpio_reset_match[] = {
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
+    BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_ETH_MAC_RST),
+};
+static const zx_bind_inst_t gpio_int_match[] = {
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
+    BI_MATCH_IF(EQ, BIND_GPIO_PIN, GPIO_ETH_MAC_INTR),
+};
+static const device_component_part_t i2c_component[] = {
+    { countof(root_match), root_match },
+    { countof(i2c_match), i2c_match },
+};
+static const device_component_part_t gpio_reset_component[] = {
+    { countof(root_match), root_match },
+    { countof(gpio_reset_match), gpio_reset_match },
+};
+static const device_component_part_t gpio_int_component[] = {
+    { countof(root_match), root_match },
+    { countof(gpio_int_match), gpio_int_match },
+};
+static const device_component_t eth_components[] = {
+    { countof(i2c_component), i2c_component },
+    { countof(gpio_reset_component), gpio_reset_component },
+    { countof(gpio_int_component), gpio_int_component },
+};
+
+// Composite binding rules for dwmac.
 static const zx_bind_inst_t eth_board_match[] = {
     BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_ETH_BOARD),
     BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_DESIGNWARE),
@@ -151,7 +165,7 @@
     { fbl::count_of(root_match), root_match },
     { fbl::count_of(eth_board_match), eth_board_match },
 };
-static const device_component_t components[] = {
+static const device_component_t dwmac_components[] = {
     { fbl::count_of(eth_board_component), eth_board_component },
 };
 
@@ -175,14 +189,17 @@
     gpio_impl_.SetAltFunction(S912_ETH_TXD2, S912_ETH_TXD2_FN);
     gpio_impl_.SetAltFunction(S912_ETH_TXD3, S912_ETH_TXD3_FN);
 
-    auto status = pbus_.DeviceAdd(&eth_board_dev);
+    // Add a composite device for ethernet board in a new devhost.
+    auto status = pbus_.CompositeDeviceAdd(&eth_board_dev, eth_components,
+                                           fbl::count_of(eth_components), UINT32_MAX);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "%s: pbus_device_add failed: %d\n", __func__, status);
+        zxlogf(ERROR, "%s: CompositeDeviceAdd failed: %d\n", __func__, status);
         return status;
     }
 
-    // Add a composite device for dwmac driver.
-    status = pbus_.CompositeDeviceAdd(&dwmac_dev, components, fbl::count_of(components), 1);
+    // Add a composite device for dwmac driver in the ethernet board driver's devhost.
+    status = pbus_.CompositeDeviceAdd(&dwmac_dev, dwmac_components, fbl::count_of(dwmac_components),
+                                      1);
     if (status != ZX_OK) {
         zxlogf(ERROR, "%s: CompositeDeviceAdd failed: %d\n", __func__, status);
         return status;
diff --git a/zircon/system/dev/board/vim/vim-gpio.cpp b/zircon/system/dev/board/vim/vim-gpio.cpp
index e78c8fc..0ed445d 100644
--- a/zircon/system/dev/board/vim/vim-gpio.cpp
+++ b/zircon/system/dev/board/vim/vim-gpio.cpp
@@ -87,7 +87,10 @@
     { GPIO_WIFI_DEBUG },
     // For thermal.
     { GPIO_THERMAL_FAN_O },
-    { GPIO_THERMAL_FAN_1 },    
+    { GPIO_THERMAL_FAN_1 },
+    // For ethernet.
+    { GPIO_ETH_MAC_RST },
+    { GPIO_ETH_MAC_INTR },
 };
 
 static const pbus_metadata_t gpio_metadata[] = {
diff --git a/zircon/system/dev/board/vim/vim-gpios.h b/zircon/system/dev/board/vim/vim-gpios.h
index 0a515a5..79ba905 100644
--- a/zircon/system/dev/board/vim/vim-gpios.h
+++ b/zircon/system/dev/board/vim/vim-gpios.h
@@ -9,3 +9,5 @@
 #define GPIO_WIFI_DEBUG     S912_GPIODV(13)
 #define GPIO_THERMAL_FAN_O  S912_GPIODV(14)
 #define GPIO_THERMAL_FAN_1  S912_GPIODV(15)
+#define GPIO_ETH_MAC_RST    S912_GPIOZ(14)
+#define GPIO_ETH_MAC_INTR   S912_GPIOZ(15)
diff --git a/zircon/system/dev/board/vim/vim-i2c.cpp b/zircon/system/dev/board/vim/vim-i2c.cpp
index 570d6d7..7f0dcbc5 100644
--- a/zircon/system/dev/board/vim/vim-i2c.cpp
+++ b/zircon/system/dev/board/vim/vim-i2c.cpp
@@ -75,6 +75,15 @@
         .pid = PDEV_PID_GENERIC,
         .did = PDEV_DID_LED2472G,
     },
+    // Ethernet
+    {
+        .bus_id = 1,
+        .address = 0x18,
+        // Binds to a composite device.
+        .vid = 0,
+        .pid = 0,
+        .did = 0,
+    },
 };
 
 static const pbus_metadata_t i2c_metadata[] = {
diff --git a/zircon/system/dev/ethernet/aml-ethernet-s912/BUILD.gn b/zircon/system/dev/ethernet/aml-ethernet-s912/BUILD.gn
index f1109e6..3446420 100644
--- a/zircon/system/dev/ethernet/aml-ethernet-s912/BUILD.gn
+++ b/zircon/system/dev/ethernet/aml-ethernet-s912/BUILD.gn
@@ -5,10 +5,10 @@
 driver("aml-ethernet-s912") {
   sources = [
     "aml-ethernet.cpp",
-    "binding.c",
   ]
   deps = [
     "$zx/system/banjo/ddk-protocol-clock",
+    "$zx/system/banjo/ddk-protocol-composite",
     "$zx/system/banjo/ddk-protocol-ethernet",
     "$zx/system/banjo/ddk-protocol-ethernet-board",
     "$zx/system/banjo/ddk-protocol-gpio",
diff --git a/zircon/system/dev/ethernet/aml-ethernet-s912/aml-ethernet.cpp b/zircon/system/dev/ethernet/aml-ethernet-s912/aml-ethernet.cpp
index 95f7312..8f2402c 100644
--- a/zircon/system/dev/ethernet/aml-ethernet-s912/aml-ethernet.cpp
+++ b/zircon/system/dev/ethernet/aml-ethernet-s912/aml-ethernet.cpp
@@ -10,6 +10,7 @@
 #include <ddk/metadata.h>
 #include <ddk/platform-defs.h>
 #include <ddk/protocol/i2c-lib.h>
+#include <ddk/protocol/composite.h>
 #include <ddk/protocol/ethernet.h>
 #include <ddk/protocol/platform/device.h>
 #include <ddk/protocol/platform-device-lib.h>
@@ -37,23 +38,52 @@
 }
 
 zx_status_t AmlEthernet::InitPdev() {
-    if (!pdev_.is_valid()) {
-        return ZX_ERR_NO_RESOURCES;
+    composite_protocol_t composite;
+
+    auto status = device_get_protocol(parent(), ZX_PROTOCOL_COMPOSITE, &composite);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "Could not get composite protocol\n");
+        return status;
     }
 
-    zx_status_t status;
-    for (uint32_t i = 0; i < countof(gpios_); i++) {
-        gpios_[i] = pdev_.GetGpio(i);
-        if (!gpios_[i].is_valid()) {
-            return ZX_ERR_NO_RESOURCES;
-        }
+    zx_device_t* components[COMPONENT_COUNT];
+    size_t actual;
+    composite_get_components(&composite, components, fbl::count_of(components), &actual);
+    if (actual != fbl::count_of(components)) {
+        zxlogf(ERROR, "could not get components\n");
+        return ZX_ERR_NOT_SUPPORTED;
     }
 
-    // I2c for MCU messages.
-    i2c_ = pdev_.GetI2c(0);
-    if (!i2c_.is_valid()) {
-        return ZX_ERR_NO_RESOURCES;
+    pdev_protocol_t pdev;
+    status = device_get_protocol(components[COMPONENT_PDEV], ZX_PROTOCOL_PDEV, &pdev);
+    if (status !=  ZX_OK) {
+        zxlogf(ERROR, "Could not get PDEV protocol\n");
+        return status;
     }
+    pdev_ = &pdev;
+
+    i2c_protocol_t i2c;
+    status = device_get_protocol(components[COMPONENT_I2C], ZX_PROTOCOL_I2C, &i2c);
+    if (status !=  ZX_OK) {
+        zxlogf(ERROR, "Could not get I2C protocol\n");
+        return status;
+    }
+    i2c_ = &i2c;
+
+    gpio_protocol_t gpio;
+    status = device_get_protocol(components[COMPONENT_RESET_GPIO], ZX_PROTOCOL_GPIO, &gpio);
+    if (status !=  ZX_OK) {
+        zxlogf(ERROR, "Could not get GPIO protocol\n");
+        return status;
+    }
+    gpios_[PHY_RESET] = &gpio;
+
+    status = device_get_protocol(components[COMPONENT_INTR_GPIO], ZX_PROTOCOL_GPIO, &gpio);
+    if (status !=  ZX_OK) {
+        zxlogf(ERROR, "Could not get GPIO protocol\n");
+        return status;
+    }
+    gpios_[PHY_INTR] = &gpio;
 
     // Map amlogic peripheral control registers.
     status = pdev_.MapMmio(MMIO_PERIPH, &periph_mmio_);
@@ -126,7 +156,7 @@
     delete this;
 }
 
-zx_status_t AmlEthernet::Create(zx_device_t* parent) {
+zx_status_t AmlEthernet::Create(void* ctx, zx_device_t* parent) {
     fbl::AllocChecker ac;
     auto eth_device = fbl::make_unique_checked<AmlEthernet>(&ac, parent);
     if (!ac.check()) {
@@ -152,8 +182,19 @@
     return ZX_OK;
 }
 
+static zx_driver_ops_t driver_ops = [](){
+    zx_driver_ops_t ops = {};
+    ops.version = DRIVER_OPS_VERSION;
+    ops.bind = AmlEthernet::Create;
+    return ops;
+}();
+
 } // namespace eth
 
-extern "C" zx_status_t aml_eth_bind(void* ctx, zx_device_t* parent) {
-    return eth::AmlEthernet::Create(parent);
-}
+// clang-format off
+ZIRCON_DRIVER_BEGIN(aml_eth, eth::driver_ops, "aml-ethernet", "0.1", 4)
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_COMPOSITE),
+    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_AMLOGIC),
+    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_AMLOGIC_S912),
+    BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_AMLOGIC_ETH),
+ZIRCON_DRIVER_END(aml_eth)
diff --git a/zircon/system/dev/ethernet/aml-ethernet-s912/aml-ethernet.h b/zircon/system/dev/ethernet/aml-ethernet-s912/aml-ethernet.h
index d401fcd..88d7478 100644
--- a/zircon/system/dev/ethernet/aml-ethernet-s912/aml-ethernet.h
+++ b/zircon/system/dev/ethernet/aml-ethernet-s912/aml-ethernet.h
@@ -24,9 +24,9 @@
     DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AmlEthernet);
 
     explicit AmlEthernet(zx_device_t* parent)
-        : DeviceType(parent), pdev_(parent) {}
+        : DeviceType(parent) {}
 
-    static zx_status_t Create(zx_device_t* parent);
+    static zx_status_t Create(void* ctx, zx_device_t* parent);
 
     // DDK Hooks.
     void DdkRelease();
@@ -36,6 +36,15 @@
     zx_status_t EthBoardResetPhy();
 
 private:
+    // Component Indexes.
+    enum {
+        COMPONENT_PDEV,
+        COMPONENT_I2C,
+        COMPONENT_RESET_GPIO,
+        COMPONENT_INTR_GPIO,
+        COMPONENT_COUNT,
+    };
+
     // GPIO Indexes.
     enum {
         PHY_RESET,
diff --git a/zircon/system/dev/ethernet/aml-ethernet-s912/binding.c b/zircon/system/dev/ethernet/aml-ethernet-s912/binding.c
deleted file mode 100644
index 604b76a..0000000
--- a/zircon/system/dev/ethernet/aml-ethernet-s912/binding.c
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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/device.h>
-#include <ddk/driver.h>
-#include <ddk/platform-defs.h>
-#include <stdlib.h>
-#include <string.h>
-
-extern zx_status_t aml_eth_bind(void* ctx, zx_device_t* parent);
-
-static zx_driver_ops_t aml_eth_driver_ops = {
-    .version = DRIVER_OPS_VERSION,
-    .bind = aml_eth_bind,
-};
-
-// clang-format off
-ZIRCON_DRIVER_BEGIN(aml_eth, aml_eth_driver_ops, "aml-ethernet", "0.1", 3)
-    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_AMLOGIC),
-    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_AMLOGIC_S912),
-    BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_AMLOGIC_ETH),
-ZIRCON_DRIVER_END(aml_eth)