Revert "[display][canvas] Port canvas driver from C to C++"

This reverts commit f01fb5b4f3a95e0024bc50dfa1ef43b613dc314c.

Reason for revert: causing device enumeration test failures

Original change's description:
> [display][canvas] Port canvas driver from C to C++
> 
> Ported the aml-canvas driver to use the C++ DDK template library.
> 
> Test: Added unit test 'aml-canvas-test' to verify device lifecycle and
> various canvas config and free behaviors. Also tested locally on devices
> that use the canvas driver. Brought up the virtual console and ran
> tests: 'gfxtest' and 'display-test --amlogic'. Verified that scenic
> comes up fine as well.
> 
> Change-Id: Iea588d2da97ecfa6a76b09b36fba40e197647f2a

TBR=payamm@google.com,surajmalhotra@google.com,rashaeqbal@google.com

Change-Id: I066590499e4a0923e13e7db493203b35f36f8373
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
diff --git a/zircon/system/dev/display/aml-canvas/BUILD.gn b/zircon/system/dev/display/aml-canvas/BUILD.gn
index 5c4ef9ad..cf0fc13 100644
--- a/zircon/system/dev/display/aml-canvas/BUILD.gn
+++ b/zircon/system/dev/display/aml-canvas/BUILD.gn
@@ -4,44 +4,13 @@
 
 driver("aml-canvas") {
   sources = [
-    "aml-canvas.cc",
+    "aml-canvas.c",
   ]
   deps = [
     "$zx/system/banjo/ddk.protocol.amlogiccanvas",
     "$zx/system/banjo/ddk.protocol.platform.device",
-    "$zx/system/dev/lib/device-protocol-pdev",
     "$zx/system/dev/lib/device-protocol-platform-device",
-    "$zx/system/dev/lib/mmio",
     "$zx/system/ulib/ddk",
-    "$zx/system/ulib/ddktl",
-    "$zx/system/ulib/fbl",
-    "$zx/system/ulib/hwreg",
     "$zx/system/ulib/zircon",
-    "$zx/system/ulib/zx",
-  ]
-}
-
-test("aml-canvas-test") {
-  testonly = true
-  output_name = "aml-canvas-test"
-  sources = [
-    "aml-canvas-test.cc",
-    "aml-canvas.cc",
-  ]
-  deps = [
-    "$zx/system/banjo/ddk.protocol.amlogiccanvas",
-    "$zx/system/banjo/ddk.protocol.platform.device",
-    "$zx/system/dev/lib/device-protocol-pdev",
-    "$zx/system/dev/lib/device-protocol-platform-device",
-    "$zx/system/dev/lib/fake-bti",
-    "$zx/system/dev/lib/fake_ddk",
-    "$zx/system/dev/lib/mock-mmio-reg",
-    "$zx/system/ulib/ddk",
-    "$zx/system/ulib/ddktl",
-    "$zx/system/ulib/fbl",
-    "$zx/system/ulib/hwreg",
-    "$zx/system/ulib/zircon",
-    "$zx/system/ulib/zx",
-    "$zx/system/ulib/zxtest",
   ]
 }
diff --git a/zircon/system/dev/display/aml-canvas/aml-canvas-test.cc b/zircon/system/dev/display/aml-canvas/aml-canvas-test.cc
deleted file mode 100644
index 8a872bf..0000000
--- a/zircon/system/dev/display/aml-canvas/aml-canvas-test.cc
+++ /dev/null
@@ -1,241 +0,0 @@
-// 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.
-
-#include "aml-canvas.h"
-
-#include <lib/fake-bti/bti.h>
-#include <lib/fake_ddk/fake_ddk.h>
-
-#include <vector>
-
-#include <mock-mmio-reg/mock-mmio-reg.h>
-#include <zxtest/zxtest.h>
-
-#include "dmc-regs.h"
-
-namespace {
-constexpr uint32_t kMmioRegSize = sizeof(uint32_t);
-constexpr uint32_t kMmioRegCount = (aml_canvas::kDmcCavMaxRegAddr + kMmioRegSize) / kMmioRegSize;
-constexpr uint32_t kVmoTestSize = PAGE_SIZE;
-
-constexpr canvas_info_t test_canvas_info = []() {
-  canvas_info_t ci = {};
-  ci.height = 240;
-  ci.stride_bytes = 16;
-  return ci;
-}();
-
-constexpr canvas_info_t invalid_canvas_info = []() {
-  canvas_info_t ci = {};
-  ci.height = 240;
-  ci.stride_bytes = 15;
-  return ci;
-}();
-}  // namespace
-
-namespace aml_canvas {
-
-template <typename T>
-ddk_mock::MockMmioReg& GetMockReg(ddk_mock::MockMmioRegRegion& registers) {
-  return registers[T::Get().addr()];
-}
-
-class AmlCanvasTest : public zxtest::Test {
- public:
-  AmlCanvasTest()
-      : mock_regs_(ddk_mock::MockMmioRegRegion(mock_reg_array_, kMmioRegSize, kMmioRegCount)) {
-    ddk::MmioBuffer mmio(mock_regs_.GetMmioBuffer());
-
-    zx::bti bti;
-    EXPECT_OK(fake_bti_create(bti.reset_and_get_address()));
-    fake_bti_ = zx::bti(bti.get());
-
-    fbl::AllocChecker ac;
-    canvas_ = fbl::make_unique_checked<AmlCanvas>(&ac, fake_ddk::kFakeParent, std::move(mmio),
-                                                  std::move(bti));
-    EXPECT_TRUE(ac.check());
-  }
-
-  ~AmlCanvasTest() {
-    if (fake_bti_.is_valid()) {
-      fake_bti_destroy(fake_bti_.get());
-    }
-  }
-
-  void TestLifecycle() {
-    fake_ddk::Bind ddk;
-    EXPECT_OK(canvas_->DdkAdd("aml-canvas"));
-    canvas_->DdkUnbind();
-    EXPECT_TRUE(ddk.Ok());
-    canvas_->DdkRelease();
-    __UNUSED auto ptr = canvas_.release();
-  }
-
-  zx_status_t CreateNewCanvas() {
-    zx::vmo vmo;
-    EXPECT_OK(zx::vmo::create(kVmoTestSize, 0, &vmo));
-
-    uint8_t index;
-    zx_status_t status = canvas_->AmlogicCanvasConfig(std::move(vmo), 0, &test_canvas_info, &index);
-    if (status != ZX_OK) {
-      return status;
-    }
-    canvas_indices_.push_back(index);
-    return status;
-  }
-
-  zx_status_t CreateNewCanvasInvalid() {
-    zx::vmo vmo;
-    EXPECT_OK(zx::vmo::create(kVmoTestSize, 0, &vmo));
-
-    uint8_t index;
-    return canvas_->AmlogicCanvasConfig(std::move(vmo), 0, &invalid_canvas_info, &index);
-  }
-
-  zx_status_t FreeCanvas(uint8_t index) {
-    auto it = std::find(canvas_indices_.begin(), canvas_indices_.end(), index);
-    if (it != canvas_indices_.end()) {
-      canvas_indices_.erase(it);
-    }
-    return canvas_->AmlogicCanvasFree(index);
-  }
-
-  zx_status_t FreeAllCanvases() {
-    zx_status_t status = ZX_OK;
-    while (!canvas_indices_.empty()) {
-      uint8_t index = canvas_indices_.back();
-      canvas_indices_.pop_back();
-      status = canvas_->AmlogicCanvasFree(index);
-      if (status != ZX_OK) {
-        return status;
-      }
-    }
-    return status;
-  }
-
-  void SetRegisterExpectations() {
-    GetMockReg<CanvasLutDataLow>(mock_regs_).ExpectWrite(CanvasLutDataLowValue());
-    GetMockReg<CanvasLutDataHigh>(mock_regs_).ExpectWrite(CanvasLutDataHighValue());
-    GetMockReg<CanvasLutAddr>(mock_regs_).ExpectWrite(CanvasLutAddrValue(NextCanvasIndex()));
-  }
-
-  void SetRegisterExpectations(uint8_t index) {
-    GetMockReg<CanvasLutDataLow>(mock_regs_).ExpectWrite(CanvasLutDataLowValue());
-    GetMockReg<CanvasLutDataHigh>(mock_regs_).ExpectWrite(CanvasLutDataHighValue());
-    GetMockReg<CanvasLutAddr>(mock_regs_).ExpectWrite(CanvasLutAddrValue(index));
-  }
-
-  void VerifyAll() {
-    GetMockReg<CanvasLutDataLow>(mock_regs_).VerifyAndClear();
-    GetMockReg<CanvasLutDataHigh>(mock_regs_).VerifyAndClear();
-    GetMockReg<CanvasLutAddr>(mock_regs_).VerifyAndClear();
-  }
-
- private:
-  uint8_t NextCanvasIndex() { return static_cast<uint8_t>(canvas_indices_.size()); }
-
-  uint32_t CanvasLutDataLowValue() {
-    auto data_low = CanvasLutDataLow::Get().FromValue(0);
-    data_low.SetDmcCavWidth(test_canvas_info.stride_bytes >> 3);
-    data_low.set_dmc_cav_addr(FAKE_BTI_PHYS_ADDR >> 3);
-    return data_low.reg_value();
-  }
-
-  uint32_t CanvasLutDataHighValue() {
-    auto data_high = CanvasLutDataHigh::Get().FromValue(0);
-    data_high.SetDmcCavWidth(test_canvas_info.stride_bytes >> 3);
-    data_high.set_dmc_cav_height(test_canvas_info.height);
-    data_high.set_dmc_cav_blkmode(test_canvas_info.blkmode);
-    data_high.set_dmc_cav_xwrap(test_canvas_info.wrap & CanvasLutDataHigh::kDmcCavXwrap ? 1 : 0);
-    data_high.set_dmc_cav_ywrap(test_canvas_info.wrap & CanvasLutDataHigh::kDmcCavYwrap ? 1 : 0);
-    data_high.set_dmc_cav_endianness(test_canvas_info.endianness);
-    return data_high.reg_value();
-  }
-
-  uint32_t CanvasLutAddrValue(uint8_t index) {
-    auto lut_addr = CanvasLutAddr::Get().FromValue(0);
-    lut_addr.set_dmc_cav_addr_index(index);
-    lut_addr.set_dmc_cav_addr_wr(1);
-    return lut_addr.reg_value();
-  }
-
-  std::vector<uint8_t> canvas_indices_;
-  ddk_mock::MockMmioReg mock_reg_array_[kMmioRegCount];
-  ddk_mock::MockMmioRegRegion mock_regs_;
-  zx::bti fake_bti_;
-  std::unique_ptr<AmlCanvas> canvas_;
-};
-
-TEST_F(AmlCanvasTest, DdkLifecyle) { TestLifecycle(); }
-
-TEST_F(AmlCanvasTest, CanvasConfigFreeSingle) {
-  SetRegisterExpectations();
-  EXPECT_OK(CreateNewCanvas());
-  ASSERT_NO_FATAL_FAILURES(VerifyAll());
-
-  EXPECT_OK(FreeAllCanvases());
-}
-
-TEST_F(AmlCanvasTest, CanvasConfigFreeMultipleSequential) {
-  // Create 5 canvases in sequence and verify that their indices are 0 through 4.
-  for (int i = 0; i < 5; i++) {
-    SetRegisterExpectations();
-    EXPECT_OK(CreateNewCanvas());
-    ASSERT_NO_FATAL_FAILURES(VerifyAll());
-  }
-
-  // Free all 5 canvases created above.
-  EXPECT_OK(FreeAllCanvases());
-}
-
-TEST_F(AmlCanvasTest, CanvasConfigFreeMultipleInterleaved) {
-  // Create 5 canvases in sequence.
-  for (int i = 0; i < 5; i++) {
-    SetRegisterExpectations();
-    EXPECT_OK(CreateNewCanvas());
-    ASSERT_NO_FATAL_FAILURES(VerifyAll());
-  }
-
-  // Free canvas index 1, so the next one created has index 1.
-  EXPECT_OK(FreeCanvas(1));
-
-  SetRegisterExpectations(1);
-  EXPECT_OK(CreateNewCanvas());
-  ASSERT_NO_FATAL_FAILURES(VerifyAll());
-
-  // Free canvas index 3, so the next one created has index 3.
-  EXPECT_OK(FreeCanvas(3));
-
-  SetRegisterExpectations(3);
-  EXPECT_OK(CreateNewCanvas());
-  ASSERT_NO_FATAL_FAILURES(VerifyAll());
-
-  EXPECT_OK(FreeAllCanvases());
-}
-
-TEST_F(AmlCanvasTest, CanvasFreeInvalidIndex) {
-  // Free a canvas without having created any.
-  EXPECT_EQ(FreeCanvas(0), ZX_ERR_INVALID_ARGS);
-}
-
-TEST_F(AmlCanvasTest, CanvasConfigMaxLimit) {
-  // Create canvases until the look-up table is full.
-  for (size_t i = 0; i < kNumCanvasEntries; i++) {
-    SetRegisterExpectations();
-    EXPECT_OK(CreateNewCanvas());
-    ASSERT_NO_FATAL_FAILURES(VerifyAll());
-  }
-
-  // Try to create another canvas, and verify that it fails.
-  EXPECT_EQ(CreateNewCanvas(), ZX_ERR_NOT_FOUND);
-
-  EXPECT_OK(FreeAllCanvases());
-}
-
-TEST_F(AmlCanvasTest, CanvasConfigUnaligned) {
-  // Try to create a canvas with unaligned canvas_info_t width, and verify that it fails.
-  EXPECT_EQ(CreateNewCanvasInvalid(), ZX_ERR_INVALID_ARGS);
-}
-
-}  //  namespace aml_canvas
diff --git a/zircon/system/dev/display/aml-canvas/aml-canvas.c b/zircon/system/dev/display/aml-canvas/aml-canvas.c
new file mode 100644
index 0000000..12eeeb6
--- /dev/null
+++ b/zircon/system/dev/display/aml-canvas/aml-canvas.c
@@ -0,0 +1,228 @@
+// 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 "aml-canvas.h"
+
+#include <assert.h>
+#include <lib/device-protocol/platform-device.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <threads.h>
+#include <unistd.h>
+#include <zircon/pixelformat.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/amlogiccanvas.h>
+#include <ddk/protocol/platform/device.h>
+
+static void aml_canvas_release(void* ctx) {
+  aml_canvas_t* canvas = ctx;
+  mmio_buffer_release(&canvas->dmc_regs);
+  for (uint32_t index = 0; index < NUM_CANVAS_ENTRIES; index++) {
+    if (canvas->pmt_handle[index] != ZX_HANDLE_INVALID) {
+      zx_pmt_unpin(canvas->pmt_handle[index]);
+      canvas->pmt_handle[index] = ZX_HANDLE_INVALID;
+    }
+  }
+  free(canvas);
+}
+
+static zx_status_t aml_canvas_config(void* ctx, zx_handle_t vmo, size_t offset,
+                                     const canvas_info_t* info, uint8_t* canvas_idx) {
+  aml_canvas_t* canvas = ctx;
+  zx_status_t status = ZX_OK;
+
+  if (!info || !canvas_idx) {
+    return ZX_ERR_INVALID_ARGS;
+  }
+
+  uint32_t size =
+      ROUNDUP((info->stride_bytes * info->height) + (offset & (PAGE_SIZE - 1)), PAGE_SIZE);
+  uint32_t index;
+  zx_paddr_t paddr;
+  mtx_lock(&canvas->lock);
+
+  uint32_t height = info->height;
+  uint32_t width = info->stride_bytes;
+
+  if (!(info->wrap & DMC_CAV_YWRAP)) {
+    // The precise height of the canvas doesn't matter if wrapping isn't in
+    // use (as long as the user doesn't try to read or write outside of
+    // the defined area).
+    height = ROUNDUP(height, 8);
+  }
+
+  if (!IS_ALIGNED(height, 8) || !IS_ALIGNED(width, 8)) {
+    CANVAS_ERROR("Height or width is not aligned\n");
+    status = ZX_ERR_INVALID_ARGS;
+    goto fail;
+  }
+
+  // find an unused canvas index
+  for (index = 0; index < NUM_CANVAS_ENTRIES; index++) {
+    if (canvas->pmt_handle[index] == ZX_HANDLE_INVALID) {
+      break;
+    }
+  }
+
+  if (index == NUM_CANVAS_ENTRIES) {
+    CANVAS_ERROR("All canvas indexes are currently in use\n");
+    status = ZX_ERR_NOT_FOUND;
+    goto fail;
+  }
+
+  uint32_t pin_flags = ZX_BTI_CONTIGUOUS;
+  if (info->flags & CANVAS_FLAGS_READ)
+    pin_flags |= ZX_BTI_PERM_READ;
+  if (info->flags & CANVAS_FLAGS_WRITE)
+    pin_flags |= ZX_BTI_PERM_WRITE;
+
+  status = zx_bti_pin(canvas->bti, pin_flags, vmo, offset & ~(PAGE_SIZE - 1), size, &paddr, 1,
+                      &canvas->pmt_handle[index]);
+  if (status != ZX_OK) {
+    CANVAS_ERROR("zx_bti_pin failed %d \n", status);
+    goto fail;
+  }
+
+  if (!IS_ALIGNED(paddr, 8)) {
+    CANVAS_ERROR("Physical address is not aligned\n");
+    status = ZX_ERR_INVALID_ARGS;
+    zx_handle_close(canvas->pmt_handle[index]);
+    canvas->pmt_handle[index] = ZX_HANDLE_INVALID;
+    status = ZX_ERR_INVALID_ARGS;
+    goto fail;
+  }
+
+  zx_paddr_t start_addr = paddr + (offset & (PAGE_SIZE - 1));
+
+  // set framebuffer address in DMC, read/modify/write
+  uint32_t value = ((start_addr >> 3) & DMC_CAV_ADDR_LMASK) |
+                   (((width >> 3) & DMC_CAV_WIDTH_LMASK) << DMC_CAV_WIDTH_LBIT);
+  WRITE32_DMC_REG(DMC_CAV_LUT_DATAL, value);
+
+  value = (((width >> 3) >> DMC_CAV_WIDTH_LWID) << DMC_CAV_WIDTH_HBIT) |
+          ((height & DMC_CAV_HEIGHT_MASK) << DMC_CAV_HEIGHT_BIT) |
+          ((info->blkmode & DMC_CAV_BLKMODE_MASK) << DMC_CAV_BLKMODE_BIT) |
+          ((info->wrap & DMC_CAV_XWRAP) ? DMC_CAV_XWRAP : 0) |
+          ((info->wrap & DMC_CAV_YWRAP) ? DMC_CAV_YWRAP : 0) |
+          ((info->endianness & DMC_CAV_ENDIANNESS_MASK) << DMC_CAV_ENDIANNESS_BIT);
+  WRITE32_DMC_REG(DMC_CAV_LUT_DATAH, value);
+
+  WRITE32_DMC_REG(DMC_CAV_LUT_ADDR, DMC_CAV_LUT_ADDR_WR_EN | index);
+
+  // read a cbus to make sure last write finish.
+  READ32_DMC_REG(DMC_CAV_LUT_DATAH);
+
+  *canvas_idx = index;
+fail:
+  zx_handle_close(vmo);
+  mtx_unlock(&canvas->lock);
+  return status;
+}
+
+static zx_status_t aml_canvas_free(void* ctx, uint8_t canvas_idx) {
+  aml_canvas_t* canvas = ctx;
+
+  mtx_lock(&canvas->lock);
+  zx_status_t status = ZX_OK;
+
+  if (canvas->pmt_handle[canvas_idx] == ZX_HANDLE_INVALID) {
+    CANVAS_ERROR("Freeing invalid canvas index: %d\n", canvas_idx);
+    status = ZX_ERR_INVALID_ARGS;
+  } else {
+    zx_pmt_unpin(canvas->pmt_handle[canvas_idx]);
+    canvas->pmt_handle[canvas_idx] = ZX_HANDLE_INVALID;
+  }
+
+  mtx_unlock(&canvas->lock);
+  return status;
+}
+
+static void aml_canvas_unbind(void* ctx) {
+  aml_canvas_t* canvas = ctx;
+  device_remove(canvas->zxdev);
+}
+
+static zx_protocol_device_t aml_canvas_device_protocol = {
+    .version = DEVICE_OPS_VERSION,
+    .release = aml_canvas_release,
+    .unbind = aml_canvas_unbind,
+};
+
+static amlogic_canvas_protocol_ops_t canvas_ops = {
+    .config = aml_canvas_config,
+    .free = aml_canvas_free,
+};
+
+static zx_status_t aml_canvas_bind(void* ctx, zx_device_t* parent) {
+  zx_status_t status = ZX_OK;
+
+  aml_canvas_t* canvas = calloc(1, sizeof(aml_canvas_t));
+  if (!canvas) {
+    return ZX_ERR_NO_MEMORY;
+  }
+
+  // Get device protocol
+  status = device_get_protocol(parent, ZX_PROTOCOL_PDEV, &canvas->pdev);
+  if (status != ZX_OK) {
+    CANVAS_ERROR("Could not get parent protocol\n");
+    goto fail;
+  }
+
+  // Get BTI handle
+  status = pdev_get_bti(&canvas->pdev, 0, &canvas->bti);
+  if (status != ZX_OK) {
+    CANVAS_ERROR("Could not get BTI handle\n");
+    goto fail;
+  }
+
+  // Map all MMIOs
+  status =
+      pdev_map_mmio_buffer(&canvas->pdev, 0, ZX_CACHE_POLICY_UNCACHED_DEVICE, &canvas->dmc_regs);
+  if (status != ZX_OK) {
+    CANVAS_ERROR("Could not map DMC registers %d\n", status);
+    goto fail;
+  }
+
+  mtx_init(&canvas->lock, mtx_plain);
+
+  device_add_args_t args = {
+      .version = DEVICE_ADD_ARGS_VERSION,
+      .name = "aml-canvas",
+      .ctx = canvas,
+      .ops = &aml_canvas_device_protocol,
+      .proto_id = ZX_PROTOCOL_AMLOGIC_CANVAS,
+      .proto_ops = &canvas_ops,
+      .flags = DEVICE_ADD_ALLOW_MULTI_COMPOSITE,
+  };
+
+  status = device_add(parent, &args, &canvas->zxdev);
+  if (status != ZX_OK) {
+    goto fail;
+  }
+
+  return ZX_OK;
+fail:
+  aml_canvas_release(canvas);
+  return status;
+}
+
+static zx_driver_ops_t aml_canvas_driver_ops = {
+    .version = DRIVER_OPS_VERSION,
+    .bind = aml_canvas_bind,
+};
+
+// clang-format off
+ZIRCON_DRIVER_BEGIN(aml_canvas, aml_canvas_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_AMLOGIC),
+  BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_GENERIC),
+  BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_AMLOGIC_CANVAS),
+ZIRCON_DRIVER_END(aml_canvas)
diff --git a/zircon/system/dev/display/aml-canvas/aml-canvas.cc b/zircon/system/dev/display/aml-canvas/aml-canvas.cc
deleted file mode 100644
index 55ff854..0000000
--- a/zircon/system/dev/display/aml-canvas/aml-canvas.cc
+++ /dev/null
@@ -1,220 +0,0 @@
-// 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.
-
-#include "aml-canvas.h"
-
-#include <assert.h>
-#include <lib/device-protocol/platform-device.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <zircon/pixelformat.h>
-
-#include <ddk/binding.h>
-#include <ddk/debug.h>
-#include <ddk/device.h>
-#include <ddk/driver.h>
-#include <fbl/algorithm.h>
-#include <fbl/alloc_checker.h>
-#include <fbl/auto_lock.h>
-
-#include "dmc-regs.h"
-
-namespace aml_canvas {
-
-zx_status_t AmlCanvas::AmlogicCanvasConfig(zx::vmo vmo, size_t offset, const canvas_info_t* info,
-                                           uint8_t* canvas_idx) {
-  if (!info || !canvas_idx) {
-    return ZX_ERR_INVALID_ARGS;
-  }
-
-  uint32_t size = fbl::round_up<uint32_t, uint32_t>(
-      (info->stride_bytes * info->height) + static_cast<uint32_t>(offset % PAGE_SIZE), PAGE_SIZE);
-  uint32_t index;
-  zx_paddr_t paddr;
-  fbl::AutoLock al(&lock_);
-
-  uint32_t height = info->height;
-  uint32_t width = info->stride_bytes;
-
-  if (!(info->wrap & CanvasLutDataHigh::kDmcCavYwrap)) {
-    // The precise height of the canvas doesn't matter if wrapping isn't in
-    // use (as long as the user doesn't try to read or write outside of
-    // the defined area).
-    height = fbl::round_up<uint32_t, uint32_t>(height, 8);
-  }
-
-  if (!IS_ALIGNED(height, 8) || !IS_ALIGNED(width, 8)) {
-    CANVAS_ERROR("Height or width is not aligned\n");
-    return ZX_ERR_INVALID_ARGS;
-  }
-
-  // find an unused canvas index
-  for (index = 0; index < kNumCanvasEntries; index++) {
-    if (!pmts_[index].is_valid()) {
-      break;
-    }
-  }
-
-  if (index == kNumCanvasEntries) {
-    CANVAS_ERROR("All canvas indices are currently in use\n");
-    return ZX_ERR_NOT_FOUND;
-  }
-
-  uint32_t pin_flags = ZX_BTI_CONTIGUOUS;
-  if (info->flags & CANVAS_FLAGS_READ) {
-    pin_flags |= ZX_BTI_PERM_READ;
-  }
-  if (info->flags & CANVAS_FLAGS_WRITE) {
-    pin_flags |= ZX_BTI_PERM_WRITE;
-  }
-
-  zx::pmt pmt;
-  zx_status_t status = bti_.pin(pin_flags, vmo, fbl::round_down<size_t, size_t>(offset, PAGE_SIZE),
-                                size, &paddr, 1, &pmt);
-  if (status != ZX_OK) {
-    CANVAS_ERROR("zx_bti_pin failed %d \n", status);
-    return status;
-  }
-
-  if (!IS_ALIGNED(paddr, 8)) {
-    CANVAS_ERROR("Physical address is not aligned\n");
-    status = ZX_ERR_INVALID_ARGS;
-    pmt.unpin();
-    return ZX_ERR_INVALID_ARGS;
-  }
-  pmts_[index].swap(pmt);
-
-  zx_paddr_t start_addr = paddr + (offset % PAGE_SIZE);
-
-  // set framebuffer address in DMC, read/modify/write
-  auto data_low = CanvasLutDataLow::Get().ReadFrom(&dmc_regs_);
-  data_low.SetDmcCavWidth(width >> 3);
-  data_low.set_dmc_cav_addr(static_cast<unsigned int>(start_addr >> 3));
-  data_low.WriteTo(&dmc_regs_);
-
-  auto data_high = CanvasLutDataHigh::Get().ReadFrom(&dmc_regs_);
-  data_high.SetDmcCavWidth(width >> 3);
-  data_high.set_dmc_cav_height(height);
-  data_high.set_dmc_cav_blkmode(info->blkmode);
-  data_high.set_dmc_cav_xwrap(info->wrap & CanvasLutDataHigh::kDmcCavXwrap ? 1 : 0);
-  data_high.set_dmc_cav_ywrap(info->wrap & CanvasLutDataHigh::kDmcCavYwrap ? 1 : 0);
-  data_high.set_dmc_cav_endianness(info->endianness);
-  data_high.WriteTo(&dmc_regs_);
-
-  auto lut_addr = CanvasLutAddr::Get().ReadFrom(&dmc_regs_);
-  lut_addr.set_dmc_cav_addr_index(index);
-  lut_addr.set_dmc_cav_addr_wr(1);
-  lut_addr.WriteTo(&dmc_regs_);
-
-  // read a cbus to make sure last write finished
-  CanvasLutDataHigh::Get().ReadFrom(&dmc_regs_);
-
-  *canvas_idx = static_cast<uint8_t>(index);
-
-  return status;
-}
-
-zx_status_t AmlCanvas::AmlogicCanvasFree(uint8_t canvas_idx) {
-  fbl::AutoLock al(&lock_);
-
-  if (!pmts_[canvas_idx].is_valid()) {
-    CANVAS_ERROR("Freeing invalid canvas index: %d\n", canvas_idx);
-    return ZX_ERR_INVALID_ARGS;
-  } else {
-    pmts_[canvas_idx].unpin();
-    pmts_[canvas_idx].reset();
-  }
-
-  return ZX_OK;
-}
-
-void AmlCanvas::DdkRelease() {
-  lock_.Acquire();
-  for (uint32_t index = 0; index < kNumCanvasEntries; index++) {
-    if (pmts_[index].is_valid()) {
-      pmts_[index].unpin();
-    }
-  }
-  lock_.Release();
-  delete this;
-}
-
-void AmlCanvas::DdkUnbind() { DdkRemove(); }
-
-// static funtion to create the canvas object and initialize its members
-zx_status_t AmlCanvas::Setup(zx_device_t* parent) {
-  // Get device protocol
-  ddk::PDev pdev(parent);
-  if (!pdev.is_valid()) {
-    CANVAS_ERROR("Could not get parent protocol\n");
-    return ZX_ERR_NO_RESOURCES;
-  }
-
-  // Get BTI handle
-  zx::bti bti;
-  zx_status_t status = pdev.GetBti(0, &bti);
-  if (status != ZX_OK) {
-    CANVAS_ERROR("Could not get BTI handle\n");
-    return status;
-  }
-
-  // Map all MMIOs
-  std::optional<ddk::MmioBuffer> mmio;
-  status = pdev.MapMmio(0, &mmio);
-  if (status != ZX_OK) {
-    CANVAS_ERROR("Could not map DMC registers %d\n", status);
-    return status;
-  }
-
-  fbl::AllocChecker ac;
-  auto canvas = fbl::make_unique_checked<aml_canvas::AmlCanvas>(&ac, parent, *std::move(mmio),
-                                                                std::move(bti));
-  if (!ac.check()) {
-    return ZX_ERR_NO_MEMORY;
-  }
-
-  status = canvas->DdkAdd("aml-canvas");
-  if (status != ZX_OK) {
-    CANVAS_ERROR("Could not add aml canvas device: %d\n", status);
-    return status;
-  }
-
-  // devmgr is now in charge of the memory for canvas
-  __UNUSED auto ptr = canvas.release();
-
-  return status;
-}
-
-}  // namespace aml_canvas
-
-namespace {
-
-static zx_status_t aml_canvas_bind(void* ctx, zx_device_t* parent) {
-  zx_status_t status = aml_canvas::AmlCanvas::Setup(parent);
-  if (status != ZX_OK) {
-    CANVAS_ERROR("Could not set up aml canvas device: %d\n", status);
-  }
-
-  return status;
-}
-
-static constexpr zx_driver_ops_t aml_canvas_driver_ops = []() {
-  zx_driver_ops_t ops = {};
-  ops.version = DRIVER_OPS_VERSION;
-  ops.bind = aml_canvas_bind;
-  return ops;
-}();
-
-}  // namespace
-
-// clang-format off
-ZIRCON_DRIVER_BEGIN(aml_canvas, aml_canvas_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_AMLOGIC),
-  BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_GENERIC),
-  BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_AMLOGIC_CANVAS),
-ZIRCON_DRIVER_END(aml_canvas)
diff --git a/zircon/system/dev/display/aml-canvas/aml-canvas.h b/zircon/system/dev/display/aml-canvas/aml-canvas.h
index 7f8ad4c..1a52030 100644
--- a/zircon/system/dev/display/aml-canvas/aml-canvas.h
+++ b/zircon/system/dev/display/aml-canvas/aml-canvas.h
@@ -5,56 +5,59 @@
 #ifndef ZIRCON_SYSTEM_DEV_DISPLAY_AML_CANVAS_AML_CANVAS_H_
 #define ZIRCON_SYSTEM_DEV_DISPLAY_AML_CANVAS_AML_CANVAS_H_
 
-#include <lib/device-protocol/pdev.h>
-#include <lib/mmio/mmio.h>
-
-#include <array>
-
+#include <ddk/device.h>
 #include <ddk/mmio-buffer.h>
 #include <ddk/platform-defs.h>
 #include <ddk/protocol/platform/device.h>
-#include <ddktl/device.h>
-#include <ddktl/protocol/amlogiccanvas.h>
-#include <fbl/mutex.h>
+#include <hw/reg.h>
+#include <threads.h>
+
+#define NUM_CANVAS_ENTRIES 256
+#define CANVAS_BYTE_STRIDE 32
 
 #define IS_ALIGNED(a, b) (!(((uintptr_t)(a)) & (((uintptr_t)(b)) - 1)))
 
 #define CANVAS_ERROR(fmt, ...) zxlogf(ERROR, "[%s %d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
 #define CANVAS_INFO(fmt, ...) zxlogf(INFO, "[%s %d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
 
-namespace aml_canvas {
+#define READ32_DMC_REG(a) readl(canvas->dmc_regs.vaddr + a)
+#define WRITE32_DMC_REG(a, v) writel(v, canvas->dmc_regs.vaddr + a)
 
-constexpr size_t kNumCanvasEntries = 256;
+#define DMC_CAV_LUT_DATAL (0x12 << 2)
+#define DMC_CAV_LUT_DATAH (0x13 << 2)
+#define DMC_CAV_LUT_ADDR (0x14 << 2)
 
-class AmlCanvas;
-using DeviceType = ddk::Device<AmlCanvas, ddk::Unbindable>;
+#define DMC_CAV_ADDR_LMASK 0x1fffffff
+#define DMC_CAV_WIDTH_LMASK 0x7
+#define DMC_CAV_WIDTH_LWID 3
+#define DMC_CAV_WIDTH_LBIT 29
 
-class AmlCanvas : public DeviceType,
-                  public ddk::AmlogicCanvasProtocol<AmlCanvas, ddk::base_protocol> {
- public:
-  AmlCanvas(zx_device_t* parent, ddk::MmioBuffer mmio, zx::bti bti)
-      : DeviceType(parent), dmc_regs_(std::move(mmio)), bti_(std::move(bti)) {}
+#define DMC_CAV_WIDTH_HMASK 0x1ff
+#define DMC_CAV_WIDTH_HBIT 0
+#define DMC_CAV_HEIGHT_MASK 0x1fff
+#define DMC_CAV_HEIGHT_BIT 9
 
-  // This function is called from the c-bind function upon driver matching
-  static zx_status_t Setup(zx_device_t* parent);
+#define DMC_CAV_BLKMODE_MASK 3
+#define DMC_CAV_BLKMODE_BIT 24
 
-  // Required by ddk::AmlogicCanvasProtocol
-  zx_status_t AmlogicCanvasConfig(zx::vmo vmo, size_t offset, const canvas_info_t* info,
-                                  uint8_t* canvas_idx);
-  zx_status_t AmlogicCanvasFree(uint8_t canvas_idx);
+#define DMC_CAV_ENDIANNESS_BIT 26
+#define DMC_CAV_ENDIANNESS_MASK 0xf
 
-  // Required by ddk::Device
-  void DdkRelease();
-  void DdkUnbind();
+#define DMC_CAV_LUT_ADDR_INDEX_MASK 0x7
+#define DMC_CAV_LUT_ADDR_RD_EN (1 << 8)
+#define DMC_CAV_LUT_ADDR_WR_EN (2 << 8)
 
- private:
-  fbl::Mutex lock_;
-  ddk::MmioBuffer dmc_regs_ __TA_GUARDED(lock_);
-  zx::bti bti_ __TA_GUARDED(lock_);
-  std::array<zx::pmt, kNumCanvasEntries> pmts_ __TA_GUARDED(lock_);
+#define DMC_CAV_YWRAP (1 << 23)
+#define DMC_CAV_XWRAP (1 << 22)
 
-};  // class AmlCanvas
-
-}  // namespace aml_canvas
+// Context for driver implementation.
+typedef struct {
+  zx_device_t* zxdev;
+  pdev_protocol_t pdev;
+  mmio_buffer_t dmc_regs;
+  mtx_t lock;
+  zx_handle_t bti;
+  zx_handle_t pmt_handle[NUM_CANVAS_ENTRIES];
+} aml_canvas_t;
 
 #endif  // ZIRCON_SYSTEM_DEV_DISPLAY_AML_CANVAS_AML_CANVAS_H_
diff --git a/zircon/system/dev/display/aml-canvas/dmc-regs.h b/zircon/system/dev/display/aml-canvas/dmc-regs.h
deleted file mode 100644
index 2c32804..0000000
--- a/zircon/system/dev/display/aml-canvas/dmc-regs.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// 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 ZIRCON_SYSTEM_DEV_DISPLAY_AML_CANVAS_DMC_REGS_H_
-#define ZIRCON_SYSTEM_DEV_DISPLAY_AML_CANVAS_DMC_REGS_H_
-
-#include <hw/reg.h>
-#include <hwreg/bitfields.h>
-
-namespace aml_canvas {
-
-constexpr uint32_t kDmcCavLutDataL = (0x12 << 2);
-constexpr uint32_t kDmcCavLutDataH = (0x13 << 2);
-constexpr uint32_t kDmcCavLutAddr = (0x14 << 2);
-constexpr uint32_t kDmcCavMaxRegAddr = kDmcCavLutAddr;
-
-// DMC_CAV_LUT_DATAL
-class CanvasLutDataLow : public hwreg::RegisterBase<CanvasLutDataLow, uint32_t> {
- public:
-  DEF_FIELD(31, 29, dmc_cav_width);
-  DEF_FIELD(28, 0, dmc_cav_addr);
-
-  static auto Get() { return hwreg::RegisterAddr<CanvasLutDataLow>(kDmcCavLutDataL); }
-
-  void SetDmcCavWidth(uint32_t width) { set_dmc_cav_width(width & kDmcCavWidthLmask_); }
-
- private:
-  // Mask to extract the bits of dmc_cav_width encoded in CanvasLutDataLow.
-  // The remaining bits go in CanvasLutDataHigh.
-  static constexpr uint32_t kDmcCavWidthLmask_ = 7;
-};
-
-// DMC_CAV_LUT_DATAH
-class CanvasLutDataHigh : public hwreg::RegisterBase<CanvasLutDataHigh, uint32_t> {
- public:
-  DEF_FIELD(29, 26, dmc_cav_endianness);
-  DEF_FIELD(25, 24, dmc_cav_blkmode);
-  DEF_BIT(23, dmc_cav_ywrap);
-  DEF_BIT(22, dmc_cav_xwrap);
-  DEF_FIELD(21, 9, dmc_cav_height);
-  DEF_FIELD(8, 0, dmc_cav_width);
-
-  static auto Get() { return hwreg::RegisterAddr<CanvasLutDataHigh>(kDmcCavLutDataH); }
-
-  void SetDmcCavWidth(uint32_t width) { set_dmc_cav_width(width >> kDmcCavWidthLwidth_); }
-
-  static constexpr uint32_t kDmcCavYwrap = (1 << 23);
-  static constexpr uint32_t kDmcCavXwrap = (1 << 22);
-
- private:
-  // Number of bits of dmc_cav_width encoded in CanvasLutDataLow.
-  static constexpr uint32_t kDmcCavWidthLwidth_ = 3;
-};
-
-// DMC_CAV_LUT_ADDR
-class CanvasLutAddr : public hwreg::RegisterBase<CanvasLutAddr, uint32_t> {
- public:
-  DEF_BIT(9, dmc_cav_addr_wr);
-  DEF_BIT(8, dmc_cav_addr_rd);
-  DEF_FIELD(7, 0, dmc_cav_addr_index);
-
-  static auto Get() { return hwreg::RegisterAddr<CanvasLutAddr>(kDmcCavLutAddr); }
-};
-
-}  // namespace aml_canvas
-
-#endif  // ZIRCON_SYSTEM_DEV_DISPLAY_AML_CANVAS_DMC_REGS_H_
diff --git a/zircon/system/utest/BUILD.gn b/zircon/system/utest/BUILD.gn
index 31d248a..8a712b5 100644
--- a/zircon/system/utest/BUILD.gn
+++ b/zircon/system/utest/BUILD.gn
@@ -52,7 +52,6 @@
       "$zx/system/dev/clk/msm8x53-clk:msm8x53-clk-test",
       "$zx/system/dev/clk/syn-clk:syn-clk-test",
       "$zx/system/dev/codec/alc5663:test",
-      "$zx/system/dev/display/aml-canvas:aml-canvas-test",
       "$zx/system/dev/display/display/test",
       "$zx/system/dev/display/mt8167s-display:tests",
       "$zx/system/dev/ethernet/ethernet:ethernet-unittest",