[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