[raspberry][zircon][device drivers]   RPI4 device drivers

first device driver (GPIO) works (I/Os, IRQs, AltFuncs, etc)

for boot psci needs BL31 (ARM Trusted Firmware) installed on SD

platfrom bus starts a dummy rpi4 board driver
i2c, sd, eth etc. drivers are bound but don't work yet
they are only templates copied from vim3

Change-Id: I73521bbd7acabecddc232e2dd41c6a3ad20d8f08
diff --git a/build/images/zedboot/BUILD.gn b/build/images/zedboot/BUILD.gn
index e8b0b70..d98e019 100644
--- a/build/images/zedboot/BUILD.gn
+++ b/build/images/zedboot/BUILD.gn
@@ -17,9 +17,6 @@
   core_package_name = "core-invalid"
 }
 
-# Zedboot must be included to pave devices until recovery has a replacement
-# mechanism. Products can specify recovery_label to determine which
-# image to include in zircon-r.
 use_zedboot_as_recovery = false
 zedboot_metadata_slot = "zedboot"
 if (get_label_info(recovery_label, "label_with_toolchain") ==
diff --git a/kernel/target/all-boards.list b/kernel/target/all-boards.list
new file mode 100644
index 0000000..870ee54
--- /dev/null
+++ b/kernel/target/all-boards.list
@@ -0,0 +1,9 @@
+[arm64]
+gauss
+hikey960
+qemu
+vim2
+imx8mevk
+[x64]
+pc
+pi4
diff --git a/src/devices/board/drivers/rpi4/BUILD.gn b/src/devices/board/drivers/rpi4/BUILD.gn
index e71443f..53bbb48 100644
--- a/src/devices/board/drivers/rpi4/BUILD.gn
+++ b/src/devices/board/drivers/rpi4/BUILD.gn
@@ -33,21 +33,17 @@
     "//sdk/banjo/ddk.protocol.iommu",
     "//sdk/banjo/ddk.protocol.platform.bus",
     "//sdk/banjo/ddk.protocol.platform.device",
-    "//sdk/banjo/ddk.protocol.scpi",
     "//sdk/banjo/ddk.protocol.sdmmc",
-    "//sdk/banjo/ddk.protocol.serial",
-    "//sdk/fidl/fuchsia.hardware.serial:fuchsia.hardware.serial_c",
-    "//sdk/fidl/fuchsia.hardware.thermal:fuchsia.hardware.thermal_c",
     "//sdk/fidl/fuchsia.sysmem:fuchsia.sysmem_c",
     "//src/devices/lib/amlogic",
     "//src/devices/lib/broadcom",
     "//src/devices/lib/driver",
     "//src/devices/lib/mmio",
-    "//src/devices/usb/lib/usb",
     "//src/lib/ddk",
     "//src/lib/ddktl",
     "//zircon/public/lib/fbl",
     "//zircon/public/lib/hwreg",
+    "//zircon/public/lib/zircon-internal",
     "//zircon/public/lib/zx",
   ]
 }
diff --git a/src/devices/board/drivers/rpi4/rpi4-gpio.cc b/src/devices/board/drivers/rpi4/rpi4-gpio.cc
index 873a698..004eed1 100644
--- a/src/devices/board/drivers/rpi4/rpi4-gpio.cc
+++ b/src/devices/board/drivers/rpi4/rpi4-gpio.cc
@@ -4,76 +4,46 @@
 
 // for the time being it's only a template copy from vim3
 
+#include "rpi4.h"
+
+#include <ddk/binding.h>
 #include <ddk/debug.h>
-#include <ddk/device.h>
 #include <ddk/metadata.h>
 #include <ddk/metadata/gpio.h>
 #include <ddk/platform-defs.h>
-#include <ddk/protocol/platform/bus.h>
-#include <soc/aml-a311d/a311d-gpio.h>
-#include <soc/aml-a311d/a311d-hw.h>
 
+#include <soc/bcm2711/bcm2711-gpio.h>
+#include <soc/bcm2711/bcm2711-hw.h>
 #include "rpi4-gpios.h"
-#include "rpi4.h"
+
+#define GPIO_TEST
 
 namespace rpi4 {
 
 static const pbus_mmio_t gpio_mmios[] = {
     {
-        .base = A311D_GPIO_BASE,
-        .length = A311D_GPIO_LENGTH,
-    },
-    {
-        .base = A311D_GPIO_AO_BASE,
-        .length = A311D_GPIO_AO_LENGTH,
-    },
-    {
-        .base = A311D_GPIO_INTERRUPT_BASE,
-        .length = A311D_GPIO_INTERRUPT_LENGTH,
+        // manage in one contiguous space
+        .base = BCM2711_GPIO_BASE,
+        .length = BCM2711_GPIO_LENGTH,
     },
 };
 
 static const pbus_irq_t gpio_irqs[] = {
     {
-        .irq = A311D_GPIO_IRQ_0,
+        .irq = BCM2711_GPIO_IRQ_0,
         .mode = ZX_INTERRUPT_MODE_DEFAULT,
     },
     {
-        .irq = A311D_GPIO_IRQ_1,
-        .mode = ZX_INTERRUPT_MODE_DEFAULT,
-    },
-    {
-        .irq = A311D_GPIO_IRQ_2,
-        .mode = ZX_INTERRUPT_MODE_DEFAULT,
-    },
-    {
-        .irq = A311D_GPIO_IRQ_3,
-        .mode = ZX_INTERRUPT_MODE_DEFAULT,
-    },
-    {
-        .irq = A311D_GPIO_IRQ_4,
-        .mode = ZX_INTERRUPT_MODE_DEFAULT,
-    },
-    {
-        .irq = A311D_GPIO_IRQ_5,
-        .mode = ZX_INTERRUPT_MODE_DEFAULT,
-    },
-    {
-        .irq = A311D_GPIO_IRQ_6,
-        .mode = ZX_INTERRUPT_MODE_DEFAULT,
-    },
-    {
-        .irq = A311D_GPIO_IRQ_7,
+        .irq = BCM2711_GPIO_IRQ_1,
         .mode = ZX_INTERRUPT_MODE_DEFAULT,
     },
 };
 
 // GPIOs to expose from generic GPIO driver.
 static const gpio_pin_t gpio_pins[] = {
-    {VIM3_J4_PIN_39},
-    {VIM3_ETH_MAC_INTR},
-    {A311D_GPIOBOOT(12)},
-    {A311D_GPIOX(6)},
+      {BCM2711_GPIO_PIN(21)},
+      {BCM2711_GPIO_PIN(20)},
+      {BCM2711_GPIO_PIN(16)},
 };
 
 static const pbus_metadata_t gpio_metadata[] = {
@@ -87,9 +57,9 @@
 static pbus_dev_t gpio_dev = []() {
   pbus_dev_t dev = {};
   dev.name = "gpio";
-  dev.vid = PDEV_VID_AMLOGIC;
-  dev.pid = PDEV_PID_AMLOGIC_A311D;
-  dev.did = PDEV_DID_AMLOGIC_GPIO;
+  dev.vid = PDEV_VID_BROADCOM;
+  dev.pid = PDEV_PID_BCM2711;
+  dev.did = PDEV_DID_BCM_GPIO;
   dev.mmio_list = gpio_mmios;
   dev.mmio_count = countof(gpio_mmios);
   dev.irq_list = gpio_irqs;
@@ -100,6 +70,7 @@
 }();
 
 zx_status_t Rpi4::GpioInit() {
+
   zx_status_t status = pbus_.ProtocolDeviceAdd(ZX_PROTOCOL_GPIO_IMPL, &gpio_dev);
   if (status != ZX_OK) {
     zxlogf(ERROR, "%s: ProtocolDeviceAdd failed %d", __func__, status);
@@ -112,6 +83,57 @@
     return ZX_ERR_INTERNAL;
   }
 
+#ifdef GPIO_TEST
+
+  static const zx_bind_inst_t root_match[] = {
+      BI_MATCH(),
+  };
+  static const zx_bind_inst_t gpio_button_match[] = {
+      BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
+      BI_MATCH_IF(EQ, BIND_GPIO_PIN, BCM2711_GPIO_PIN(21)),
+  };
+  static const zx_bind_inst_t gpio_led_match[] = {
+      BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_GPIO),
+      BI_MATCH_IF(EQ, BIND_GPIO_PIN, BCM2711_GPIO_PIN(20)),
+  };
+  static const device_fragment_part_t gpio_button_fragment[] = {
+      {countof(root_match), root_match},
+      {countof(gpio_button_match), gpio_button_match},
+  };
+  static const device_fragment_part_t gpio_led_fragment[] = {
+      {countof(root_match), root_match},
+      {countof(gpio_led_match), gpio_led_match},
+  };
+  static const device_fragment_t fragments[] = {
+      // according to gpio-test.h's enum { GPIO_LED, GPIO_BUTTON,}
+      {countof(gpio_led_fragment), gpio_led_fragment},
+      {countof(gpio_button_fragment), gpio_button_fragment},
+  };
+
+  constexpr 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_GPIO_TEST},
+  };
+
+  const composite_device_desc_t comp_desc = {
+      .props = props,
+      .props_count = countof(props),
+      .fragments = fragments,
+      .fragments_count = countof(fragments),
+      .coresident_device_index = 0,
+      .metadata_list = nullptr,
+      .metadata_count = 0,
+  };
+
+  status = DdkAddComposite("gpio-test", &comp_desc);
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "%s: CompositeDeviceAdd failed: %d", __func__, status);
+    return status;
+  }
+
+#endif
+
   return ZX_OK;
 }
 
diff --git a/src/devices/board/drivers/rpi4/rpi4-gpios.h b/src/devices/board/drivers/rpi4/rpi4-gpios.h
index f7e733a..254f258 100644
--- a/src/devices/board/drivers/rpi4/rpi4-gpios.h
+++ b/src/devices/board/drivers/rpi4/rpi4-gpios.h
@@ -5,8 +5,6 @@
 #ifndef SRC_DEVICES_BOARD_DRIVERS_VIM3_VIM3_GPIOS_H_
 #define SRC_DEVICES_BOARD_DRIVERS_VIM3_VIM3_GPIOS_H_
 
-#include <soc/aml-a311d/a311d-gpio.h>
-
 // VIM3 specific assignments should be placed in this file.
 // SoC specific definitions should be placed in soc/aml-a311d-gpio.h
 
diff --git a/src/devices/board/drivers/rpi4/rpi4.cc b/src/devices/board/drivers/rpi4/rpi4.cc
index 2681b0e..da6e72c 100644
--- a/src/devices/board/drivers/rpi4/rpi4.cc
+++ b/src/devices/board/drivers/rpi4/rpi4.cc
@@ -2,49 +2,34 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// for the time being it's only a template copy from vim3
-
 #include "rpi4.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/platform-defs.h>
-#include <ddk/protocol/gpio.h>
-#include <ddk/protocol/platform/device.h>
-#include <fbl/algorithm.h>
 #include <fbl/alloc_checker.h>
 
 namespace rpi4 {
 
 zx_status_t Rpi4::Create(void* ctx, zx_device_t* parent) {
-  pbus_protocol_t pbus;
-  iommu_protocol_t iommu;
 
+  pbus_protocol_t pbus;
   auto status = device_get_protocol(parent, ZX_PROTOCOL_PBUS, &pbus);
   if (status != ZX_OK) {
     return status;
   }
 
+  iommu_protocol_t iommu;
   status = device_get_protocol(parent, ZX_PROTOCOL_IOMMU, &iommu);
   if (status != ZX_OK) {
     return status;
   }
-  printf("# after get ZX_PROTOCOL_PBUS and ZX_PROTOCOL_IOMMU\n");
 
   fbl::AllocChecker ac;
   auto board = fbl::make_unique_checked<Rpi4>(&ac, parent, &pbus, &iommu);
   if (!ac.check()) {
     return ZX_ERR_NO_MEMORY;
   }
-  printf("# after fbl::make_unique_checked<Rpi4>(&ac, parent, &pbus, &iommu)\n");
 
   status = board->DdkAdd("rpi4");
   if (status != ZX_OK) {
@@ -83,6 +68,7 @@
     init_txn_->Reply(ZX_ERR_INTERNAL);
     return status;
   }
+
   if ((status = EthInit()) != ZX_OK) {
     zxlogf(ERROR, "EthInit() failed: %d", status);
     init_txn_->Reply(ZX_ERR_INTERNAL);
@@ -108,11 +94,13 @@
     init_txn_->Reply(ZX_ERR_INTERNAL);
     return status;
   }
+
   init_txn_->Reply(status);
   return ZX_OK;
 }
 
 void Rpi4::DdkInit(ddk::InitTxn txn) {
+
   init_txn_ = std::move(txn);
   int rc = thrd_create_with_name(
       &thread_, [](void* arg) -> int { return reinterpret_cast<Rpi4*>(arg)->Thread(); }, this,
diff --git a/src/devices/board/drivers/rpi4/rpi4.h b/src/devices/board/drivers/rpi4/rpi4.h
index d9c0827..3c629b8 100644
--- a/src/devices/board/drivers/rpi4/rpi4.h
+++ b/src/devices/board/drivers/rpi4/rpi4.h
@@ -8,17 +8,13 @@
 #define SRC_DEVICES_BOARD_DRIVERS_RPI4_RPI4_H_
 
 #include <threads.h>
-
 #include <optional>
 
-#include <ddk/device.h>
 #include <ddktl/device.h>
 #include <ddktl/protocol/clockimpl.h>
 #include <ddktl/protocol/gpioimpl.h>
 #include <ddktl/protocol/iommu.h>
 #include <ddktl/protocol/platform/bus.h>
-#include <fbl/macros.h>
-#include <soc/aml-a311d/a311d-hw.h>
 
 namespace rpi4 {
 
diff --git a/src/devices/gpio/drivers/bcm2711-gpio/BUILD.gn b/src/devices/gpio/drivers/bcm2711-gpio/BUILD.gn
new file mode 100644
index 0000000..34f6c87
--- /dev/null
+++ b/src/devices/gpio/drivers/bcm2711-gpio/BUILD.gn
@@ -0,0 +1,30 @@
+# Copyright 2019 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.
+
+import("//build/config/fuchsia/rules.gni")
+
+driver_module("bcm2711-gpio") {
+  defines = [ "_ALL_SOURCE" ]
+  configs += [ "//build/config/fuchsia:enable_zircon_asserts" ]
+  configs -= [ "//build/config/fuchsia:no_cpp_standard_library" ]
+  configs += [ "//build/config/fuchsia:static_cpp_standard_library" ]
+  configs += [ "//build/unification/config:zircon-migrated" ]
+  sources = [ "bcm2711-gpio.cc" ]
+  deps = [
+    "//sdk/banjo/ddk.protocol.gpio",
+    "//sdk/banjo/ddk.protocol.gpioimpl",
+    "//sdk/banjo/ddk.protocol.platform.bus",
+    "//src/devices/bus/lib/device-protocol-pdev",
+    "//src/devices/lib/broadcom",
+    "//src/devices/lib/driver",
+    "//src/devices/lib/mmio",
+    "//src/lib/ddk",
+    "//src/lib/ddktl",
+    "//zircon/public/lib/fbl",
+    "//zircon/public/lib/zircon-internal",
+    "//zircon/public/lib/hwreg",
+    "//zircon/public/lib/sync",
+    "//zircon/public/lib/zx",
+  ]
+}
diff --git a/src/devices/gpio/drivers/bcm2711-gpio/bcm2711-gpio.cc b/src/devices/gpio/drivers/bcm2711-gpio/bcm2711-gpio.cc
new file mode 100644
index 0000000..f054ec8
--- /dev/null
+++ b/src/devices/gpio/drivers/bcm2711-gpio/bcm2711-gpio.cc
@@ -0,0 +1,515 @@
+// Copyright 2017 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 "bcm2711-gpio.h"
+
+#include <ddk/binding.h>
+#include <ddk/platform-defs.h>
+#include <fbl/alloc_checker.h>
+
+#include <soc/bcm2711/bcm2711-gpio.h>
+#include <soc/bcm2711/bcm2711-hw.h>
+
+namespace gpio {
+
+// MMIO as defined in rpi4 board driver
+// defined only one contiguous space
+enum {
+  MMIO_GPIO = 0,                // started from BCM2711_GPIO_BASE
+};
+
+zx_status_t Bcm2711Gpio::Create(void* ctx, zx_device_t* parent) {
+
+  zx_status_t status;
+  pbus_protocol_t pbus;
+  if ((status = device_get_protocol(parent, ZX_PROTOCOL_PBUS, &pbus)) != ZX_OK) {
+    zxlogf(ERROR, "Bcm2711Gpio::Create: ZX_PROTOCOL_PBUS not available");
+    return status;
+  }
+
+  ddk::PDev pdev(parent);
+  std::optional<ddk::MmioBuffer> mmio_gpio;
+  if ((status = pdev.MapMmio(MMIO_GPIO, &mmio_gpio)) != ZX_OK) {
+    zxlogf(ERROR, "Bcm2711Gpio::Create: MapMmio failed");
+    return status;
+  }
+
+  pdev_device_info_t info;
+  if ((status = pdev.GetDeviceInfo(&info)) != ZX_OK) {
+    zxlogf(ERROR, "Bcm2711Gpio::Create: GetDeviceInfo failed");
+    return status;
+  }
+
+  fbl::AllocChecker ac;
+  fbl::Array<zx::interrupt>
+      port_interrupts(new (&ac) zx::interrupt[info.irq_count], info.irq_count);
+  if (!ac.check()) {
+    zxlogf(ERROR, "Bcm2711Gpio::Create: port interrupts alloc failed");
+    return ZX_ERR_NO_RESOURCES;
+  }
+
+  for (uint32_t i = 0; i < port_interrupts.size(); i++) {
+    zx::interrupt interrupt;
+    if ((status = pdev.GetInterrupt(i, &interrupt)) != ZX_OK) {
+      zxlogf(ERROR, "Bcm2711Gpio::Create: GetInterrupt failed %d", status);
+      return status;
+    }
+    port_interrupts[i] = std::move(interrupt);
+  }
+
+  std::unique_ptr<Bcm2711Gpio> device(new (&ac) Bcm2711Gpio(parent, 
+          *std::move(mmio_gpio), std::move(port_interrupts)));
+  if (!ac.check()) {
+    zxlogf(ERROR, "Bcm2711Gpio::Create: device object alloc failed");
+    return ZX_ERR_NO_MEMORY;
+  }
+
+  if ((status = device->Init()) != ZX_OK) {
+    zxlogf(ERROR, "Bcm2711Gpio::Create: Init failed");
+    return status;
+  }
+
+  device->Bind(pbus);
+
+  if ((status = device->DdkAdd(
+          ddk::DeviceAddArgs("bcm2711-gpio").set_proto_id(ZX_PROTOCOL_GPIO_IMPL))) != ZX_OK) {
+    zxlogf(ERROR, "Bcm2711Gpio::Create: DdkAdd failed");
+    return status;
+  }
+
+  __UNUSED auto* unused = device.release();
+
+  return ZX_OK;
+}
+
+zx_status_t Bcm2711Gpio::Init() {
+
+  zx_status_t status = zx::port::create(ZX_PORT_BIND_TO_INTERRUPT, &port_);
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "Bcm2711Gpio::Init: zx_port_create failed %d", status);
+    return status;
+  }
+
+  fbl::AutoLock al(&irq_lock_);
+
+  uint32_t port_key = 0;
+  for (const zx::interrupt& port_interrupt : port_interrupts_) {
+    status = port_interrupt.bind(port_, port_key++, ZX_INTERRUPT_BIND);
+    if (status != ZX_OK) {
+      zxlogf(ERROR, "Bcm2711Gpio::Init: zx_interrupt_bind failed %d", status);
+      return status;
+    }
+  }
+
+  const size_t interrupt_count = BCM2711_GPIO_REG_SIZE * BCM2711_GPIO_INT_REG_NUM;
+
+  fbl::AllocChecker ac;
+  gpio_interrupts_ = fbl::Array(new (&ac) zx::interrupt[interrupt_count], interrupt_count);
+  if (!ac.check()) {
+    zxlogf(ERROR, "Bcm2711Gpio::Init: gpio_interrupts_ alloc failed");
+    return ZX_ERR_NO_MEMORY;
+  }
+
+  auto cb = [](void* arg) -> int { return reinterpret_cast<Bcm2711Gpio*>(arg)->Thread(); };
+  status = thrd_create_with_name(&thread_, cb, this, "bcm2711-gpio-thread");
+  if (status != thrd_success) {
+    zxlogf(ERROR, "Bcm2711Gpio::Init: thrd_create_with_name failed %d", status);
+    return ZX_ERR_INTERNAL;
+  }
+
+  return ZX_OK;
+}
+
+void Bcm2711Gpio::Bind(const pbus_protocol_t& pbus) {
+
+  gpio_impl_protocol_t gpio_proto = {
+      .ops = &gpio_impl_protocol_ops_,
+      .ctx = this,
+  };
+
+  pbus_register_protocol(&pbus, ZX_PROTOCOL_GPIO_IMPL, &gpio_proto, sizeof(gpio_proto));
+}
+
+int Bcm2711Gpio::Thread() {
+
+  while (true) {
+
+    zx_port_packet_t packet;
+    zx_status_t status = port_.wait(zx::time::infinite(), &packet);
+    if (status != ZX_OK) {
+      zxlogf(ERROR, "Bcm2711Gpio::Thread: port wait failed: %d", status);
+      return thrd_error;
+    }
+
+    fbl::AutoLock al(&irq_lock_);
+
+    if (packet.key > port_interrupts_.size()) {
+      zxlogf(WARNING, "Bcm2711Gpio::Thread: received interrupt from invalid port");
+      continue;
+    }
+    if (packet.key == port_interrupts_.size()) {
+      zxlogf(INFO, "As370Gpio thread terminating");
+      return thrd_success;
+    }
+
+    {
+      fbl::AutoLock al(&mmio_lock_);
+
+      uint32_t index;
+      uint32_t event_reg = mmio_.Read32(BCM2711_GPIO_EDS0);      
+      if (packet.key == 0) {
+        for (index = 0; index <= BCM2711_GPIO_BANK0_END; index++) {      
+          if (event_reg & (1 << index)) {
+            uint64_t gpio_offset = index;
+
+            // Notify if interrupt is enabled for the GPIO pin.
+            if(gpio_interrupts_[gpio_offset]) {
+              status = gpio_interrupts_[gpio_offset].trigger(
+                  0, zx::time(packet.interrupt.timestamp));
+              if (status != ZX_OK) {
+                zxlogf(ERROR, "Bcm2711Gpio::Thread: zx_interrupt_trigger failed %d", status);
+              }
+              mmio_.Write32(event_reg, BCM2711_GPIO_EDS0);
+            }
+          }
+        }
+      } else if (packet.key == 1) {
+        for (index = BCM2711_GPIO_BANK0_END + 1; index < BCM2711_GPIO_REG_SIZE; index++) {  
+          if (event_reg & (1 << index)) {
+            uint64_t gpio_offset = index;
+
+            // Notify if interrupt is enabled for the GPIO pin.
+            if(gpio_interrupts_[gpio_offset]) {
+              status = gpio_interrupts_[gpio_offset].trigger(
+                  0, zx::time(packet.interrupt.timestamp));
+              if (status != ZX_OK) {
+                zxlogf(ERROR, "Bcm2711Gpio::Thread: zx_interrupt_trigger failed %d", status);
+              }
+              mmio_.Write32(event_reg, BCM2711_GPIO_EDS0);
+
+            }
+          }
+        }
+        event_reg = mmio_.Read32(BCM2711_GPIO_EDS0 + sizeof(uint32_t));
+        for (index = 0; index < BCM2711_GPIO_REG_SIZE; index++) {  
+          if (event_reg & (1 << index)) {
+            uint64_t gpio_offset = BCM2711_GPIO_REG_SIZE + index;
+
+            // Notify if interrupt is enabled for the GPIO pin.
+            if(gpio_interrupts_[gpio_offset]) {
+              status = gpio_interrupts_[gpio_offset].trigger(
+                  0, zx::time(packet.interrupt.timestamp));
+              if (status != ZX_OK) {
+                zxlogf(ERROR, "Bcm2711Gpio::Thread: zx_interrupt_trigger failed %d", status);
+              }
+              mmio_.Write32(event_reg, BCM2711_GPIO_EDS0 + sizeof(uint32_t));
+            }
+          }
+        }  
+      } else {
+        zxlogf(WARNING, "Bcm2711Gpio::Thread: received interrupt from invalid port");
+        continue;
+      }
+      port_interrupts_[packet.key].ack();  
+    }
+  }
+  return thrd_success;
+}
+
+zx_status_t Bcm2711Gpio::GpioImplConfigIn(uint32_t index, uint32_t flags) {
+
+  if (index > BCM2711_GPIO_MAX_PIN) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplConfigIn: pin index out of range %u", index);
+    return ZX_ERR_OUT_OF_RANGE;
+  }
+
+  // Set the GPIO as pull-up or pull-down
+  uint32_t pull_reg_val;
+  switch (flags & GPIO_PULL_MASK) {
+    case GPIO_PULL_DOWN:
+      pull_reg_val = BCM2711_GPIO_PULL_DOWN;
+      break;
+    case GPIO_PULL_UP:
+      pull_reg_val = BCM2711_GPIO_PULL_UP;
+      break;
+    default:
+      pull_reg_val = BCM2711_GPIO_NO_RESISTOR;
+  }
+
+  {
+    fbl::AutoLock al(&mmio_lock_);
+
+    mmio_.ModifyBits32(pull_reg_val, (2 * index) % BCM2711_GPIO_REG_SIZE, 2,
+        BCM2711_GPIO_PUP_PDN_CNTRL_REG0 + index / (BCM2711_GPIO_REG_SIZE / 2) * sizeof(uint32_t));
+
+    mmio_.ModifyBits32(BCM2711_GPIO_FSEL_INPUT, (index *3) % 30, 3,
+        BCM2711_GPIO_FSEL0 + index / 10 * sizeof(uint32_t));
+  }
+
+  return ZX_OK;
+}
+
+zx_status_t Bcm2711Gpio::GpioImplConfigOut(uint32_t index, uint8_t initial_value) {
+
+  if (index > BCM2711_GPIO_MAX_PIN) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplConfigOut: pin index out of range %u", index);
+    return ZX_ERR_OUT_OF_RANGE;
+  }
+
+  {
+    fbl::AutoLock al(&mmio_lock_);
+
+    uint32_t regval = BCM2711_GPIO_MASK(index);
+    if (initial_value) {
+      mmio_.Write32(regval, BCM2711_GPIO_SET0 + index / BCM2711_GPIO_REG_SIZE * sizeof(uint32_t));
+    } else {
+      mmio_.Write32(regval, BCM2711_GPIO_CLR0 + index / BCM2711_GPIO_REG_SIZE * sizeof(uint32_t));
+    }
+
+    mmio_.ModifyBits32(BCM2711_GPIO_FSEL_OUTPUT, (index * 3) % 30, 3,
+        BCM2711_GPIO_FSEL0 + index / 10 * sizeof(uint32_t));
+  }
+  return ZX_OK;
+}
+
+// Configure a pin for an alternate function specified by fn
+zx_status_t Bcm2711Gpio::GpioImplSetAltFunction(const uint32_t index, const uint64_t fn) {
+
+  if (index > BCM2711_GPIO_MAX_PIN) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplSetAltFunction: pin index out of range %u", index);
+    return ZX_ERR_OUT_OF_RANGE;
+  }
+
+  if (fn / BCM2711_GPIO_FSEL_ALT_NUM != index ) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplSetAltFunction: pin %u and AltFunction missmatch", index);
+    return ZX_ERR_OUT_OF_RANGE;
+  }
+
+  {
+    fbl::AutoLock al(&mmio_lock_);
+
+    uint32_t regval;
+    switch (fn % BCM2711_GPIO_FSEL_ALT_NUM ) {
+      case 0:
+        regval = BCM2711_GPIO_FSEL_ALTFUN0;
+        break;
+      case 1:
+        regval = BCM2711_GPIO_FSEL_ALTFUN1;
+        break;
+      case 2:
+        regval = BCM2711_GPIO_FSEL_ALTFUN2;
+        break;
+      case 3:
+        regval = BCM2711_GPIO_FSEL_ALTFUN3;
+        break;
+      case 4:
+        regval = BCM2711_GPIO_FSEL_ALTFUN4;
+        break;
+      case 5:
+        regval = BCM2711_GPIO_FSEL_ALTFUN5;
+        break;
+    }
+    mmio_.ModifyBits32(regval, (fn / BCM2711_GPIO_FSEL_ALT_NUM * 3) % 30, 3,
+        BCM2711_GPIO_FSEL0 + fn / (BCM2711_GPIO_FSEL_ALT_NUM * 10) * sizeof(uint32_t));
+  }
+  return ZX_OK;
+}
+
+zx_status_t Bcm2711Gpio::GpioImplRead(uint32_t index, uint8_t* out_value) {
+
+  if (index > BCM2711_GPIO_MAX_PIN) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplRead: pin index out of range %u", index);
+    return ZX_ERR_OUT_OF_RANGE;
+  }
+
+  uint32_t regval = 0;
+  {
+    fbl::AutoLock al(&mmio_lock_);
+    regval = mmio_.Read32(BCM2711_GPIO_LEV0 + index / BCM2711_GPIO_REG_SIZE * sizeof(uint32_t));
+  }
+
+  if (regval & BCM2711_GPIO_MASK(index)) {
+    *out_value = 1;
+  } else {
+    *out_value = 0;
+  }
+
+  return ZX_OK;
+}
+
+zx_status_t Bcm2711Gpio::GpioImplWrite(uint32_t index, uint8_t value) {
+
+  if (index > BCM2711_GPIO_MAX_PIN) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplWrite: pin index out of range %u", index);
+    return ZX_ERR_OUT_OF_RANGE;
+  }
+
+  {
+    fbl::AutoLock al(&mmio_lock_);
+
+    uint32_t regval = BCM2711_GPIO_MASK(index);
+    if (value) {
+      mmio_.Write32(regval, BCM2711_GPIO_SET0 + index / BCM2711_GPIO_REG_SIZE * sizeof(uint32_t));
+    } else {
+      mmio_.Write32(regval, BCM2711_GPIO_CLR0 + index / BCM2711_GPIO_REG_SIZE * sizeof(uint32_t));
+    }
+  }
+  return ZX_OK;
+}
+
+zx_status_t Bcm2711Gpio::GpioImplGetInterrupt(uint32_t index, uint32_t flags, zx::interrupt* out_irq) {
+
+  if (index > BCM2711_GPIO_MAX_PIN) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplWrite: pin index out of range %u", index);
+    return ZX_ERR_OUT_OF_RANGE;
+  }
+
+  fbl::AutoLock al(&irq_lock_);
+
+  // Map GPIO banks to ports/IRQs
+  uint32_t port;
+  if (index <= BCM2711_GPIO_BANK0_END) {
+    port = 0;
+  } else {
+    port = 1;
+  }
+
+  // Check necessary IRQs
+  if (port + 1 > port_interrupts_.size()) {
+    zxlogf(ERROR, "Missing IRQ for GPIO Bank%u", port);
+    return ZX_ERR_NO_RESOURCES;
+  }
+
+  if (gpio_interrupts_[index]) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplGetInterrupt:"
+                  "Interrupt already configured for this pin %u", index);
+    return ZX_ERR_ALREADY_EXISTS;
+  }
+
+  // Configure GPIO Interrupt EDGE and Polarity
+  uint32_t mode_reg = 0;
+  uint32_t irq_reg_index = index / BCM2711_GPIO_REG_SIZE; 
+  switch (flags & ZX_INTERRUPT_MODE_MASK) {
+    case ZX_INTERRUPT_MODE_EDGE_HIGH:
+      mode_reg = BCM2711_GPIO_REN0 + irq_reg_index * sizeof(uint32_t);
+      break;
+    case ZX_INTERRUPT_MODE_EDGE_LOW:
+      mode_reg = BCM2711_GPIO_FEN0 + irq_reg_index * sizeof(uint32_t);
+      break;
+    case ZX_INTERRUPT_MODE_LEVEL_HIGH:
+      mode_reg = BCM2711_GPIO_HEN0 + irq_reg_index * sizeof(uint32_t);
+      break;
+    case ZX_INTERRUPT_MODE_LEVEL_LOW:
+      mode_reg = BCM2711_GPIO_LEN0 + irq_reg_index * sizeof(uint32_t);
+      break;
+    case ZX_INTERRUPT_MODE_EDGE_BOTH:
+      return ZX_ERR_NOT_SUPPORTED;
+    default:
+      return ZX_ERR_INVALID_ARGS;
+  }
+
+  {
+    fbl::AutoLock al(&mmio_lock_);
+    mmio_.SetBit<uint32_t>(index % BCM2711_GPIO_REG_SIZE, mode_reg);
+  }
+
+  // Get virtual interrupts for pin and bookkeeping
+  zx::interrupt irq;
+  zx_status_t status = zx::interrupt::create(zx::resource(), port, ZX_INTERRUPT_VIRTUAL, &irq);
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplGetInterrupt: zx::interrupt::create failed %d ", status);
+    return status;
+  }
+  status = irq.duplicate(ZX_RIGHT_SAME_RIGHTS, out_irq);
+  if (status != ZX_OK) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplGetInterrupt: interrupt.duplicate failed %d ", status);
+    return status;
+  }
+  // Alloc/assign interrupt to pin
+  gpio_interrupts_[index] = std::move(irq);
+
+  return status;
+}
+
+zx_status_t Bcm2711Gpio::GpioImplReleaseInterrupt(uint32_t index) {
+
+  fbl::AutoLock al(&irq_lock_);
+  if ( !gpio_interrupts_[index] ) {
+    return ZX_ERR_BAD_STATE;
+  }
+  gpio_interrupts_[index].destroy();
+  gpio_interrupts_[index].reset();
+
+  {
+    fbl::AutoLock al(&mmio_lock_);
+
+    uint32_t irq_reg_index = index / BCM2711_GPIO_REG_SIZE; 
+    mmio_.ClearBit<uint32_t>(index % BCM2711_GPIO_REG_SIZE, 
+                             BCM2711_GPIO_REN0 + irq_reg_index * sizeof(uint32_t));
+    mmio_.ClearBit<uint32_t>(index % BCM2711_GPIO_REG_SIZE, 
+                             BCM2711_GPIO_FEN0 + irq_reg_index * sizeof(uint32_t));
+    mmio_.ClearBit<uint32_t>(index % BCM2711_GPIO_REG_SIZE, 
+                             BCM2711_GPIO_HEN0 + irq_reg_index * sizeof(uint32_t));
+    mmio_.ClearBit<uint32_t>(index % BCM2711_GPIO_REG_SIZE, 
+                             BCM2711_GPIO_LEN0 + irq_reg_index * sizeof(uint32_t));
+  }
+  return ZX_OK;
+}
+
+zx_status_t Bcm2711Gpio::GpioImplSetPolarity(uint32_t index, uint32_t polarity) {
+
+  if (index > BCM2711_GPIO_MAX_PIN) {
+    zxlogf(ERROR, "Bcm2711Gpio::GpioImplWrite: pin index out of range %u", index);
+    return ZX_ERR_OUT_OF_RANGE;
+  }
+
+  //Configure GPIO Interrupt Polarity
+  uint32_t mode_reg = 0;
+  switch (polarity) {
+    case GPIO_POLARITY_LOW:
+      mode_reg = BCM2711_GPIO_LEN0 + index / BCM2711_GPIO_REG_SIZE * sizeof(uint32_t);
+      break;
+    case GPIO_POLARITY_HIGH:
+      mode_reg = BCM2711_GPIO_HEN0 + index / BCM2711_GPIO_REG_SIZE * sizeof(uint32_t);
+      break;
+    default:
+      return ZX_ERR_INVALID_ARGS;
+  }
+
+  {
+    fbl::AutoLock al(&mmio_lock_);
+    mmio_.SetBit<uint32_t>(index % BCM2711_GPIO_REG_SIZE, mode_reg);
+  } 
+  return ZX_OK;
+}
+
+void Bcm2711Gpio::Shutdown() {
+
+  fbl::AutoLock al(&irq_lock_);
+  zx_port_packet packet = {port_interrupts_.size(), ZX_PKT_TYPE_USER, ZX_OK, {}};
+  port_.queue(&packet);
+  thrd_join(thread_, nullptr);
+}
+
+void Bcm2711Gpio::DdkUnbindNew(ddk::UnbindTxn txn) {
+  Shutdown();
+  txn.Reply();
+}
+
+static constexpr zx_driver_ops_t driver_ops = []() {
+  zx_driver_ops_t ops = {};
+  ops.version = DRIVER_OPS_VERSION;
+  ops.bind = Bcm2711Gpio::Create;
+  return ops;
+}();
+
+}  // namespace gpio
+
+// clang-format off
+ZIRCON_DRIVER_BEGIN(Bcm2711_gpio, gpio::driver_ops, "zircon", "0.1", 4)
+    BI_ABORT_IF(NE, BIND_PROTOCOL, ZX_PROTOCOL_PDEV),
+    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_BROADCOM),
+    BI_ABORT_IF(NE, BIND_PLATFORM_DEV_DID, PDEV_DID_BCM_GPIO),
+    BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_PID, PDEV_PID_BCM2711),
+ZIRCON_DRIVER_END(Bcm2711_gpio)
diff --git a/src/devices/gpio/drivers/bcm2711-gpio/bcm2711-gpio.h b/src/devices/gpio/drivers/bcm2711-gpio/bcm2711-gpio.h
new file mode 100644
index 0000000..da79f5f
--- /dev/null
+++ b/src/devices/gpio/drivers/bcm2711-gpio/bcm2711-gpio.h
@@ -0,0 +1,65 @@
+// Copyright 2019 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.
+
+#ifndef SRC_DEVICES_GPIO_DRIVERS_BCM2711_GPIO_BCM2711_GPIO_H_
+#define SRC_DEVICES_GPIO_DRIVERS_BCM2711_GPIO_BCM2711_GPIO_H_
+
+#include <lib/device-protocol/pdev.h>
+#include <lib/mmio/mmio.h>
+#include <lib/zircon-internal/thread_annotations.h>
+
+#include <ddk/protocol/platform/bus.h>
+#include <ddktl/device.h>
+#include <ddktl/protocol/gpioimpl.h>
+#include <fbl/array.h>
+#include <fbl/auto_lock.h>
+
+namespace gpio {
+
+class Bcm2711Gpio;
+using DeviceType = ddk::Device<Bcm2711Gpio, ddk::UnbindableNew>;
+
+class Bcm2711Gpio : public DeviceType, public ddk::GpioImplProtocol<Bcm2711Gpio, ddk::base_protocol> {
+ public:
+  static zx_status_t Create(void* ctx, zx_device_t* parent);
+
+  zx_status_t GpioImplConfigIn(uint32_t index, uint32_t flags);
+  zx_status_t GpioImplConfigOut(uint32_t index, uint8_t initial_value);
+  zx_status_t GpioImplSetAltFunction(uint32_t index, uint64_t function);
+  zx_status_t GpioImplRead(uint32_t index, uint8_t* out_value);
+  zx_status_t GpioImplWrite(uint32_t index, uint8_t value);
+  zx_status_t GpioImplGetInterrupt(uint32_t index, uint32_t flags, zx::interrupt* out_irq);
+  zx_status_t GpioImplReleaseInterrupt(uint32_t index);
+  zx_status_t GpioImplSetPolarity(uint32_t index, gpio_polarity_t polarity);
+  zx_status_t GpioImplSetDriveStrength(uint32_t index, uint8_t m_a) { return ZX_ERR_NOT_SUPPORTED; }
+
+  void DdkUnbindNew(ddk::UnbindTxn txn);
+  void DdkRelease() { delete this; }
+  void Shutdown();
+
+ private:
+  explicit Bcm2711Gpio(zx_device_t* parent, ddk::MmioBuffer mmio_gpio,
+                       fbl::Array<zx::interrupt> port_interrupts)
+      : DeviceType(parent),
+        pdev_(parent),
+        mmio_(std::move(mmio_gpio)),
+        port_interrupts_(std::move(port_interrupts)) {}
+
+  zx_status_t Init();
+  void Bind(const pbus_protocol_t& pbus);
+  int Thread();
+
+  ddk::PDev pdev_;
+  fbl::Mutex mmio_lock_;
+  ddk::MmioBuffer mmio_ TA_GUARDED(mmio_lock_);
+  fbl::Mutex irq_lock_ TA_ACQ_BEFORE(mmio_lock_);  
+  fbl::Array<zx::interrupt> port_interrupts_ TA_GUARDED(irq_lock_);
+  fbl::Array<zx::interrupt> gpio_interrupts_ TA_GUARDED(irq_lock_);
+  zx::port port_;
+  thrd_t thread_;
+};
+
+}  // namespace gpio
+
+#endif  // SRC_DEVICES_GPIO_DRIVERS_BCM2711_GPIO_BCM2711_GPIO_H_
diff --git a/src/devices/lib/broadcom/BUILD.gn b/src/devices/lib/broadcom/BUILD.gn
index b246368..8517e8a 100644
--- a/src/devices/lib/broadcom/BUILD.gn
+++ b/src/devices/lib/broadcom/BUILD.gn
@@ -6,6 +6,10 @@
 
 zx_library("broadcom") {
   sdk = "source"
-  sdk_headers = [ "wifi/wifi-config.h" ]
+  sdk_headers = [ 
+    "soc/bcm2711/bcm2711-gpio.h",
+    "soc/bcm2711/bcm2711-hw.h",
+    "wifi/wifi-config.h",
+  ]
   sources = []
 }
diff --git a/src/devices/lib/broadcom/include/soc/bcm2711/bcm2711-gpio.h b/src/devices/lib/broadcom/include/soc/bcm2711/bcm2711-gpio.h
new file mode 100644
index 0000000..b8cfae6
--- /dev/null
+++ b/src/devices/lib/broadcom/include/soc/bcm2711/bcm2711-gpio.h
@@ -0,0 +1,397 @@
+// Copyright 2020 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.
+
+#ifndef SRC_DEVICES_LIB_BROADCOM_INCLUDE_SOC_BCM2711_BCM2711_GPIO_H_
+#define SRC_DEVICES_LIB_BROADCOM_INCLUDE_SOC_BCM2711_BCM2711_GPIO_H_
+
+// General register params
+#define BCM2711_GPIO_REG_SIZE 32        // 32 pins per regs
+#define BCM2711_GPIO_INT_REG_NUM 2      // number of interrupt event and config regs
+
+// GPIO Function Select
+#define BCM2711_GPIO_FSEL0 0x00
+
+#define BCM2711_GPIO_FSEL_INPUT 0b000
+#define BCM2711_GPIO_FSEL_OUTPUT 0b001
+#define BCM2711_GPIO_FSEL_ALTFUN0 0b100
+#define BCM2711_GPIO_FSEL_ALTFUN1 0b101
+#define BCM2711_GPIO_FSEL_ALTFUN2 0b110
+#define BCM2711_GPIO_FSEL_ALTFUN3 0b111
+#define BCM2711_GPIO_FSEL_ALTFUN4 0b011
+#define BCM2711_GPIO_FSEL_ALTFUN5 0b010
+#define BCM2711_GPIO_FSEL_ALT_NUM 6
+
+#define BCM2711_GPIO_FSEL_MASK(x) (0b111 << ((3 * x) % 30)) // 10 pins per regs
+
+// general mask and shift macros for pin operations
+#define BCM2711_GPIO_PIN(x) x
+#define BCM2711_GPIO_MASK(x) (1u << (x % BCM2711_GPIO_REG_SIZE)) 
+
+// GPIO Pin Output Set
+#define BCM2711_GPIO_SET0 0x1c
+
+// GPIO Pin Output Clear
+#define BCM2711_GPIO_CLR0 0x28
+
+// GPIO Pin Level
+#define BCM2711_GPIO_LEV0 0x34
+
+// GPIO Pin Event Detect Status
+#define BCM2711_GPIO_EDS0 0x40
+
+// GPIO Pin Rising Edge Detect Enable
+#define BCM2711_GPIO_REN0 0x4c
+
+// GPIO Pin Falling Edge Detect Enable
+#define BCM2711_GPIO_FEN0 0x58
+
+// GPIO Pin High Detect Enable
+#define BCM2711_GPIO_HEN0 0x64
+
+// GPIO Pin Low Detect Enable
+#define BCM2711_GPIO_LEN0 0x70
+
+// GPIO Pin Async. Rising Edge Detect
+#define BCM2711_GPIO_AREN0 0x7c
+
+#define BCM2711_GPIO_ASYNC_RISING_EDGE_DETECT_DISABLED 0
+#define BCM2711_GPIO_ASYNC_RISING_EDGE_DETECT_ENABLED 1
+
+// GPIO Pin Async. Falling Edge Detect
+#define BCM2711_GPIO_AFEN0 0x88
+
+#define BCM2711_GPIO_ASYNC_FALLING_EDGE_DETECT_DISABLED 0
+#define BCM2711_GPIO_ASYNC_FALLING_EDGE_DETECT_ENABLED 1
+
+// GPIO Pull-up / Pull-down
+#define BCM2711_GPIO_PUP_PDN_CNTRL_REG0 0xe4
+
+#define BCM2711_GPIO_NO_RESISTOR 0b00
+#define BCM2711_GPIO_PULL_UP 0b01
+#define BCM2711_GPIO_PULL_DOWN 0b10
+
+// Alternative Function Assignments
+#define BCM2711_GPIO_00_SDA0                0
+#define BCM2711_GPIO_00_SA5                 1
+#define BCM2711_GPIO_00_PCLK                2
+#define BCM2711_GPIO_00_SPI3_CE0_N          3
+#define BCM2711_GPIO_00_TXD2                4
+#define BCM2711_GPIO_00_SDA6                5
+
+#define BCM2711_GPIO_01_SCL0                6
+#define BCM2711_GPIO_01_SA4                 7
+#define BCM2711_GPIO_01_DE                  8
+#define BCM2711_GPIO_01_SPI3_MISO           9
+#define BCM2711_GPIO_01_RXD2               10
+#define BCM2711_GPIO_01_SCL6               11
+
+#define BCM2711_GPIO_02_SDA1               12
+#define BCM2711_GPIO_02_SA3                13
+#define BCM2711_GPIO_02_LCD_VSYNC          14
+#define BCM2711_GPIO_02_SPI3_MOSI          15
+#define BCM2711_GPIO_02_CTS2               16
+#define BCM2711_GPIO_02_SDA3               17
+
+#define BCM2711_GPIO_03_SCL1               18
+#define BCM2711_GPIO_03_SA2                19
+#define BCM2711_GPIO_03_LCD_HSYNC          20
+#define BCM2711_GPIO_03_SPI3_SCLK          21
+#define BCM2711_GPIO_03_RTS2               22
+#define BCM2711_GPIO_03_SCL3               23
+
+#define BCM2711_GPIO_04_GPCLK0             24
+#define BCM2711_GPIO_04_SA1                25
+#define BCM2711_GPIO_04_DPI_D0             26
+#define BCM2711_GPIO_04_SPI4_CE0_N         27
+#define BCM2711_GPIO_04_TXD3               28
+#define BCM2711_GPIO_04_SDA3               29
+
+#define BCM2711_GPIO_05_GPCLK1             30
+#define BCM2711_GPIO_05_SA0                31
+#define BCM2711_GPIO_05_DPI_D1             32
+#define BCM2711_GPIO_05_SPI4_MISO          33
+#define BCM2711_GPIO_05_RXD3               34
+#define BCM2711_GPIO_05_SCL3               35
+
+#define BCM2711_GPIO_06_GPCLK2             36
+#define BCM2711_GPIO_06_SOE_N_SE           37
+#define BCM2711_GPIO_06_DPI_D2             38
+#define BCM2711_GPIO_06_SPI4_MOSI          39
+#define BCM2711_GPIO_06_CTS3               40
+#define BCM2711_GPIO_06_SDA4               41
+
+#define BCM2711_GPIO_07_SPI0_CE1_N         42
+#define BCM2711_GPIO_07_SWE_N_SRW_N        43
+#define BCM2711_GPIO_07_DPI_D3             44
+#define BCM2711_GPIO_07_SPI4_SCLK          45
+#define BCM2711_GPIO_07_RTS3               46
+#define BCM2711_GPIO_07_SCL4               47
+
+#define BCM2711_GPIO_08_SPI0_CE0_N         48
+#define BCM2711_GPIO_08_SD0                49
+#define BCM2711_GPIO_08_DPI_D4             50
+#define BCM2711_GPIO_08_BSCSL_CE_N         51
+#define BCM2711_GPIO_08_TXD4               52
+#define BCM2711_GPIO_08_SDA4               53
+
+#define BCM2711_GPIO_09_SPI0_MISO          54
+#define BCM2711_GPIO_09_SD1                55
+#define BCM2711_GPIO_09_DPI_D5             56
+#define BCM2711_GPIO_09_BSCSL_MISO         57
+#define BCM2711_GPIO_09_RXD4               58
+#define BCM2711_GPIO_09_SCL4               59
+
+#define BCM2711_GPIO_10_SPI0_MOSI          60
+#define BCM2711_GPIO_10_SD2                61
+#define BCM2711_GPIO_10_DPI_D6             62
+#define BCM2711_GPIO_10_BSCSL_SDA_MOSI     63
+#define BCM2711_GPIO_10_CTS4               64
+#define BCM2711_GPIO_10_SDA5               65
+
+#define BCM2711_GPIO_11_SPI0_CLK           66
+#define BCM2711_GPIO_11_SD3                67
+#define BCM2711_GPIO_11_DPI_D7             68
+#define BCM2711_GPIO_11_BSCSL_SCL_SCLK     69
+#define BCM2711_GPIO_11_RTS4               70
+#define BCM2711_GPIO_11_SCL5               71
+
+#define BCM2711_GPIO_12_PWM0_0             72
+#define BCM2711_GPIO_12_SD4                73
+#define BCM2711_GPIO_12_DPI_D8             74
+#define BCM2711_GPIO_12_SPI5_CE0_N         75
+#define BCM2711_GPIO_12_TXD5               76
+#define BCM2711_GPIO_12_SDA5               77
+
+#define BCM2711_GPIO_13_PWM0_1             78
+#define BCM2711_GPIO_13_SD5                79
+#define BCM2711_GPIO_13_DPI_D9             80
+#define BCM2711_GPIO_13_SPI5_MISO          81
+#define BCM2711_GPIO_13_RXD5               82
+#define BCM2711_GPIO_13_SCL5               83
+
+#define BCM2711_GPIO_14_TXD0               84
+#define BCM2711_GPIO_14_SD6                85
+#define BCM2711_GPIO_14_DPI_D10            86
+#define BCM2711_GPIO_14_SPI5_MOSI          87
+#define BCM2711_GPIO_14_CTS5               88
+#define BCM2711_GPIO_14_TXD1               89
+
+#define BCM2711_GPIO_15_RXD0               90
+#define BCM2711_GPIO_15_SD7                91
+#define BCM2711_GPIO_15_DPI_D11            92
+#define BCM2711_GPIO_15_SPI5_SCLK          93
+#define BCM2711_GPIO_15_RTS5               94
+#define BCM2711_GPIO_15_RXD1               95
+
+                                           //
+#define BCM2711_GPIO_16_SD8                97
+#define BCM2711_GPIO_16_DPI_D12            98
+#define BCM2711_GPIO_16_CTS0               99
+#define BCM2711_GPIO_16_SPI1_CE2_N        100
+#define BCM2711_GPIO_16_CTS1              101
+
+                                           //
+#define BCM2711_GPIO_17_SD9               103
+#define BCM2711_GPIO_17_DPI_D13           104
+#define BCM2711_GPIO_17_RTS0              105
+#define BCM2711_GPIO_17_SPI1_CE1_N        106
+#define BCM2711_GPIO_17_RTS1              107
+
+#define BCM2711_GPIO_18_PCM_CLK           108
+#define BCM2711_GPIO_18_SD10              109
+#define BCM2711_GPIO_18_DPI_D14           110
+#define BCM2711_GPIO_18_SPI6_CE0_N        111
+#define BCM2711_GPIO_18_SPI1_CE0_N        112
+#define BCM2711_GPIO_18_PWM0_0            113
+
+#define BCM2711_GPIO_19_PCM_FS            114
+#define BCM2711_GPIO_19_SD11              115
+#define BCM2711_GPIO_19_DPI_D15           116
+#define BCM2711_GPIO_19_SPI6_MISO         117
+#define BCM2711_GPIO_19_SPI1_MISO         118
+#define BCM2711_GPIO_19_PWM0_1            119
+
+#define BCM2711_GPIO_20_PCM_DIN           120
+#define BCM2711_GPIO_20_SD12              121
+#define BCM2711_GPIO_20_DPI_D16           122
+#define BCM2711_GPIO_20_SPI6_MOSI         123
+#define BCM2711_GPIO_20_SPI1_MOSI         124
+#define BCM2711_GPIO_20_GPCLK0            125
+
+#define BCM2711_GPIO_21_PCM_DOUT          126
+#define BCM2711_GPIO_21_SD13              127
+#define BCM2711_GPIO_21_DPI_D17           128
+#define BCM2711_GPIO_21_SPI6_SCLK         129
+#define BCM2711_GPIO_21_SPI1_SCLK         130
+#define BCM2711_GPIO_21_GPCLK1            131
+
+#define BCM2711_GPIO_22_SD0_CLK           132
+#define BCM2711_GPIO_22_SD14              133
+#define BCM2711_GPIO_22_DPI_D18           134
+#define BCM2711_GPIO_22_SD1_CLK           135
+#define BCM2711_GPIO_22_ARM_TRST          136
+#define BCM2711_GPIO_22_SDA6              137
+
+#define BCM2711_GPIO_23_SD0_CMD           138
+#define BCM2711_GPIO_23_SD15              139
+#define BCM2711_GPIO_23_DPI_D19           140
+#define BCM2711_GPIO_23_SD1_CMD           141
+#define BCM2711_GPIO_23_ARM_RTCK          142
+#define BCM2711_GPIO_23_SCL6              143
+
+#define BCM2711_GPIO_24_SD0_DAT0          144
+#define BCM2711_GPIO_24_SD16              145
+#define BCM2711_GPIO_24_DPI_D20           146
+#define BCM2711_GPIO_24_SD1_DAT0          147
+#define BCM2711_GPIO_24_ARM_TDO           148
+#define BCM2711_GPIO_24_SPI3_CE1_N        149
+
+#define BCM2711_GPIO_25_SD0_DAT1          150
+#define BCM2711_GPIO_25_SD17              151
+#define BCM2711_GPIO_25_DPI_D21           152
+#define BCM2711_GPIO_25_SD1_DAT1          153
+#define BCM2711_GPIO_25_ARM_TCK           154
+#define BCM2711_GPIO_25_SPI4_CE1_N        155
+
+#define BCM2711_GPIO_26_SD0_DAT2          156
+                                           //
+#define BCM2711_GPIO_26_DPI_D22           158
+#define BCM2711_GPIO_26_SD1_DAT2          159
+#define BCM2711_GPIO_26_ARM_TDI           160
+#define BCM2711_GPIO_26_SPI5_CE1_N        161
+
+#define BCM2711_GPIO_27_SD0_DAT3          162
+                                           //
+#define BCM2711_GPIO_27_DPI_D23           164
+#define BCM2711_GPIO_27_SD1_DAT3          165
+#define BCM2711_GPIO_27_ARM_TMS           166
+#define BCM2711_GPIO_27_SPI6_CE1_N        167
+
+#define BCM2711_GPIO_28_SDA0              168
+#define BCM2711_GPIO_28_SA5               169
+#define BCM2711_GPIO_28_PCM_CLK           170
+                                           //
+#define BCM2711_GPIO_28_MII_A_RX_ERR      172
+#define BCM2711_GPIO_28_RGMII_MDIO        173
+
+#define BCM2711_GPIO_29_SCL0              174
+#define BCM2711_GPIO_29_SA4               175
+#define BCM2711_GPIO_29_PCM_FS            176
+                                           //
+#define BCM2711_GPIO_29_MII_A_TX_ERR      178
+#define BCM2711_GPIO_29_RGMII_MDC         179
+
+                                           //
+#define BCM2711_GPIO_30_SA3               181
+#define BCM2711_GPIO_30_PCM_DIN           182
+#define BCM2711_GPIO_30_CTS0              183
+#define BCM2711_GPIO_30_MII_A_CRS         184
+#define BCM2711_GPIO_30_CTS1              185
+
+                                           //
+#define BCM2711_GPIO_31_SA2               187
+#define BCM2711_GPIO_31_PCM_DOUT          188
+#define BCM2711_GPIO_31_RTS0              189
+#define BCM2711_GPIO_31_MII_A_COL         190
+#define BCM2711_GPIO_31_RTS1              191
+
+#define BCM2711_GPIO_32_GPCLK0            192
+#define BCM2711_GPIO_32_SA1               193
+                                           //
+#define BCM2711_GPIO_32_TXD0              195
+#define BCM2711_GPIO_32_SD_CARD_PRES      196
+#define BCM2711_GPIO_32_TXD1              197
+
+                                           //
+#define BCM2711_GPIO_33_SA0               199
+                                           //
+#define BCM2711_GPIO_33_RXD0              201
+#define BCM2711_GPIO_33_SD_CARD_WRPROT    202
+#define BCM2711_GPIO_33_RXD1              203
+
+#define BCM2711_GPIO_34_GPCLK0            204    
+#define BCM2711_GPIO_34_SOE_N_SE          205
+                                           //
+#define BCM2711_GPIO_34_SD1_CLK           207
+#define BCM2711_GPIO_34_SD_CARD_LED       208
+#define BCM2711_GPIO_34_RGMII_IRQ         209
+
+#define BCM2711_GPIO_35_SPI0_CE1_N        210
+#define BCM2711_GPIO_35_SWE_N_SRW_N       211
+                                           //
+#define BCM2711_GPIO_35_SD1_CMD           213
+#define BCM2711_GPIO_35_RGMII_START_STOP  214
+                                           //
+
+#define BCM2711_GPIO_36_SPI0_CE0_N        216
+#define BCM2711_GPIO_36_SD0               217
+#define BCM2711_GPIO_36_TXD0              218
+#define BCM2711_GPIO_36_SD1_DAT0          219
+#define BCM2711_GPIO_36_RGMII_RX_OK       220
+#define BCM2711_GPIO_36_MII_A_RX_ERR      221
+
+#define BCM2711_GPIO_37_SPI0_MISO         222
+#define BCM2711_GPIO_37_SD1               223
+#define BCM2711_GPIO_37_RXD0              224
+#define BCM2711_GPIO_37_SD1_DAT1          225
+#define BCM2711_GPIO_37_RGMII_MDIO        226
+#define BCM2711_GPIO_37_MII_A_TX_ERR      227
+
+#define BCM2711_GPIO_38_SPI0_MOSI         228
+#define BCM2711_GPIO_38_SD2               229
+#define BCM2711_GPIO_38_RTS0              230
+#define BCM2711_GPIO_38_SD1_DAT2          231
+#define BCM2711_GPIO_38_RGMII_MDC         232
+#define BCM2711_GPIO_38_MII_A_CRS         233
+
+#define BCM2711_GPIO_39_SPI0_CLK          234
+#define BCM2711_GPIO_39_SD3               235
+#define BCM2711_GPIO_39_CTS0              236
+#define BCM2711_GPIO_39_SD1_DAT3          237
+#define BCM2711_GPIO_39_RGMII_IRQ         238
+#define BCM2711_GPIO_39_MII_A_COL         239
+
+#define BCM2711_GPIO_40_PWM1_0            240
+#define BCM2711_GPIO_40_SD4               241
+                                           //
+#define BCM2711_GPIO_40_SD1_DAT4          243
+#define BCM2711_GPIO_40_SPI0_MISO         244
+#define BCM2711_GPIO_40_TXD1              245
+
+#define BCM2711_GPIO_41_PWM1_1            246
+#define BCM2711_GPIO_41_SD5               247
+                                           //
+#define BCM2711_GPIO_41_SD1_DAT5          249
+#define BCM2711_GPIO_41_SPI0_MOSI         250
+#define BCM2711_GPIO_41_RXD1              251
+
+#define BCM2711_GPIO_42_GPCLK1            252
+#define BCM2711_GPIO_42_SD6               253
+                                           //
+#define BCM2711_GPIO_42_SD1_DAT6          255
+#define BCM2711_GPIO_42_SPI0_SCLK         256
+#define BCM2711_GPIO_42_RTS1              257
+
+#define BCM2711_GPIO_43_GPCLK2            258
+#define BCM2711_GPIO_43_SD7               259
+                                           //
+#define BCM2711_GPIO_43_SD1_DAT7          261
+#define BCM2711_GPIO_43_SPI0_CE0_N        262
+#define BCM2711_GPIO_43_CTS1              263
+
+#define BCM2711_GPIO_44_GPCLK1            264
+#define BCM2711_GPIO_44_SDA0              265
+#define BCM2711_GPIO_44_SDA1              266
+                                           //
+#define BCM2711_GPIO_44_SPI0_CE1_N        268
+#define BCM2711_GPIO_44_SD_CARD_VOLT      269
+
+#define BCM2711_GPIO_45_PWM0_1            270
+#define BCM2711_GPIO_45_SCL0              271
+#define BCM2711_GPIO_45_SCL1              272
+                                           //
+#define BCM2711_GPIO_45_SPI0_CE2_N        274
+#define BCM2711_GPIO_45_SD_CARD_PWR0      275
+
+#endif  // SRC_DEVICES_LIB_BROADCOM_INCLUDE_SOC_BCM2711_BCM2711_GPIO_H_
diff --git a/src/devices/lib/broadcom/include/soc/bcm2711/bcm2711-hw.h b/src/devices/lib/broadcom/include/soc/bcm2711/bcm2711-hw.h
new file mode 100644
index 0000000..93ac379
--- /dev/null
+++ b/src/devices/lib/broadcom/include/soc/bcm2711/bcm2711-hw.h
@@ -0,0 +1,20 @@
+// Copyright 2020 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.
+
+#ifndef SRC_DEVICES_LIB_BROADCOM_INCLUDE_SOC_BCM2711_BCM2711_HW_H_
+#define SRC_DEVICES_LIB_BROADCOM_INCLUDE_SOC_BCM2711_BCM2711_HW_H_
+
+// GPIO base
+#define BCM2711_GPIO_BASE 0xfe200000
+#define BCM2711_GPIO_LENGTH 0x100
+
+// GPIO IRQs
+#define BCM2711_GPIO_IRQ_0 145                        // GIC_SPI 113
+#define BCM2711_GPIO_IRQ_1 146                        // GIC_SPI 114
+
+// GPIO bank boundaries
+#define BCM2711_GPIO_MAX_PIN 45                       //  0 - 45
+#define BCM2711_GPIO_BANK0_END 27                     //  0 - 27
+
+#endif  // SRC_DEVICES_LIB_BROADCOM_INCLUDE_SOC_BCM2711_BCM2711_HW_H_
diff --git a/zircon/system/ulib/ddk-platform-defs/include/lib/ddk/platform-defs.h b/zircon/system/ulib/ddk-platform-defs/include/lib/ddk/platform-defs.h
index 201a9b8..aa7b598 100644
--- a/zircon/system/ulib/ddk-platform-defs/include/lib/ddk/platform-defs.h
+++ b/zircon/system/ulib/ddk-platform-defs/include/lib/ddk/platform-defs.h
@@ -171,6 +171,7 @@
 #define PDEV_PID_BCM2711            0x03
 
 #define PDEV_DID_BCM_WIFI           0x01
+#define PDEV_DID_BCM_GPIO           0x02
 
 //Hardkernel
 #define PDEV_VID_HARDKERNEL         0x07