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",