blob: 12ef1a04a312a928c2c43b455264a98a558c9c36 [file] [log] [blame]
// 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-gpio.h"
#include <lib/ddk/platform-defs.h>
#include <lib/driver/testing/cpp/driver_lifecycle.h>
#include <lib/driver/testing/cpp/driver_runtime.h>
#include <lib/driver/testing/cpp/test_environment.h>
#include <lib/driver/testing/cpp/test_node.h>
#include <gtest/gtest.h>
#include <mock-mmio-reg/mock-mmio-reg.h>
namespace {
constexpr size_t kGpioRegSize = 0x100;
constexpr size_t kInterruptRegSize = 0x30;
constexpr size_t kInterruptRegOffset = 0x3c00;
} // namespace
namespace gpio {
template <uint32_t kPid>
class FakePlatformDevice : public fidl::WireServer<fuchsia_hardware_platform_device::Device> {
public:
fuchsia_hardware_platform_device::Service::InstanceHandler GetInstanceHandler() {
return fuchsia_hardware_platform_device::Service::InstanceHandler({
.device = bindings_.CreateHandler(this, fdf::Dispatcher::GetCurrent()->async_dispatcher(),
fidl::kIgnoreBindingClosure),
});
}
void SetExpectedInterruptFlags(uint32_t flags) { expected_interrupt_flags_ = flags; }
private:
void GetMmioById(fuchsia_hardware_platform_device::wire::DeviceGetMmioByIdRequest* request,
GetMmioByIdCompleter::Sync& completer) override {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void GetMmioByName(fuchsia_hardware_platform_device::wire::DeviceGetMmioByNameRequest* request,
GetMmioByNameCompleter::Sync& completer) override {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void GetInterruptById(
fuchsia_hardware_platform_device::wire::DeviceGetInterruptByIdRequest* request,
GetInterruptByIdCompleter::Sync& completer) override {
EXPECT_EQ(request->flags, expected_interrupt_flags_);
zx::interrupt irq;
if (zx_status_t status = zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &irq);
status != ZX_OK) {
completer.ReplyError(status);
return;
}
completer.ReplySuccess(std::move(irq));
}
void GetInterruptByName(
fuchsia_hardware_platform_device::wire::DeviceGetInterruptByNameRequest* request,
GetInterruptByNameCompleter::Sync& completer) override {
zx::interrupt irq;
if (zx_status_t status = zx::interrupt::create(zx::resource(), 0, ZX_INTERRUPT_VIRTUAL, &irq);
status != ZX_OK) {
completer.ReplyError(status);
return;
}
completer.ReplySuccess(std::move(irq));
}
void GetBtiById(fuchsia_hardware_platform_device::wire::DeviceGetBtiByIdRequest* request,
GetBtiByIdCompleter::Sync& completer) override {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void GetBtiByName(fuchsia_hardware_platform_device::wire::DeviceGetBtiByNameRequest* request,
GetBtiByNameCompleter::Sync& completer) override {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void GetSmcById(fuchsia_hardware_platform_device::wire::DeviceGetSmcByIdRequest* request,
GetSmcByIdCompleter::Sync& completer) override {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void GetNodeDeviceInfo(GetNodeDeviceInfoCompleter::Sync& completer) override {
fidl::Arena arena;
auto info = fuchsia_hardware_platform_device::wire::NodeDeviceInfo::Builder(arena);
// Report kIrqCount IRQs even though we don't check on GetInterruptX calls.
static constexpr size_t kIrqCount = 3;
completer.ReplySuccess(info.vid(PDEV_VID_AMLOGIC).pid(kPid).irq_count(kIrqCount).Build());
}
void GetSmcByName(fuchsia_hardware_platform_device::wire::DeviceGetSmcByNameRequest* request,
GetSmcByNameCompleter::Sync& completer) override {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void GetBoardInfo(GetBoardInfoCompleter::Sync& completer) override {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void GetPowerConfiguration(GetPowerConfigurationCompleter::Sync& completer) override {
completer.ReplyError(ZX_ERR_NOT_SUPPORTED);
}
void handle_unknown_method(
fidl::UnknownMethodMetadata<fuchsia_hardware_platform_device::Device> metadata,
fidl::UnknownMethodCompleter::Sync& completer) override {
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
fidl::ServerBindingGroup<fuchsia_hardware_platform_device::Device> bindings_;
uint32_t expected_interrupt_flags_ = ZX_INTERRUPT_MODE_EDGE_HIGH;
};
class TestAmlGpioDriver : public AmlGpioDriver {
public:
TestAmlGpioDriver(fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher dispatcher)
: AmlGpioDriver(std::move(start_args), std::move(dispatcher)) {}
static DriverRegistration GetDriverRegistration() {
// Use a custom DriverRegistration to create the DUT. Without this, the non-test implementation
// will be used by default.
return FUCHSIA_DRIVER_REGISTRATION_V1(fdf_internal::DriverServer<TestAmlGpioDriver>::initialize,
fdf_internal::DriverServer<TestAmlGpioDriver>::destroy);
}
ddk_mock::MockMmioRegRegion& mmio() { return mock_mmio_gpio_; }
ddk_mock::MockMmioRegRegion& ao_mmio() { return mock_mmio_gpio_ao_; }
ddk_mock::MockMmioRegRegion& interrupt_mmio() { return mock_mmio_interrupt_; }
protected:
fpromise::promise<fdf::MmioBuffer, zx_status_t> MapMmio(
fidl::WireClient<fuchsia_hardware_platform_device::Device>& pdev, uint32_t mmio_id) override {
switch (mmio_id) {
case 0:
return fpromise::make_promise([&]() -> fpromise::result<fdf::MmioBuffer, zx_status_t> {
return fpromise::ok(mock_mmio_gpio_.GetMmioBuffer());
});
case 1:
return fpromise::make_promise([&]() -> fpromise::result<fdf::MmioBuffer, zx_status_t> {
return fpromise::ok(mock_mmio_gpio_ao_.GetMmioBuffer());
});
case 2:
return fpromise::make_promise([&]() -> fpromise::result<fdf::MmioBuffer, zx_status_t> {
return fpromise::ok(mock_mmio_interrupt_.GetMmioBuffer());
});
default:
return fpromise::make_promise([&]() -> fpromise::result<fdf::MmioBuffer, zx_status_t> {
return fpromise::error(ZX_ERR_BAD_STATE);
});
}
}
private:
ddk_mock::MockMmioRegRegion mock_mmio_gpio_{sizeof(uint32_t), kGpioRegSize};
ddk_mock::MockMmioRegRegion mock_mmio_gpio_ao_{sizeof(uint32_t), kGpioRegSize};
ddk_mock::MockMmioRegRegion mock_mmio_interrupt_{sizeof(uint32_t), kInterruptRegSize,
kInterruptRegOffset};
};
template <uint32_t kPid>
struct IncomingNamespace {
FakePlatformDevice<kPid> platform_device;
};
template <uint32_t kPid>
class AmlGpioTest : public testing::Test {
public:
AmlGpioTest() : node_server_("root"), dut_(TestAmlGpioDriver::GetDriverRegistration()) {}
void SetUp() override {
zx::result start_args = node_server_.CreateStartArgsAndServe();
ASSERT_TRUE(start_args.is_ok());
driver_outgoing_ = std::move(start_args->outgoing_directory_client);
{
zx::result result =
test_environment_.Initialize(std::move(start_args->incoming_directory_server));
ASSERT_TRUE(result.is_ok());
}
{
zx::result result = test_environment_.incoming_directory()
.AddService<fuchsia_hardware_platform_device::Service>(
incoming_.platform_device.GetInstanceHandler());
ASSERT_TRUE(result.is_ok());
}
zx::result start_result =
runtime_.RunToCompletion(dut_.Start(std::move(start_args->start_args)));
ASSERT_TRUE(start_result.is_ok());
ASSERT_NE(node_server_.children().find("aml-gpio"), node_server_.children().cend());
// Connect to the driver through its outgoing directory and get a gpioimpl client.
auto svc_endpoints = fidl::Endpoints<fuchsia_io::Directory>::Create();
EXPECT_EQ(fdio_open_at(driver_outgoing_.handle()->get(), "/svc",
static_cast<uint32_t>(fuchsia_io::OpenFlags::kDirectory),
svc_endpoints.server.TakeChannel().release()),
ZX_OK);
zx::result gpioimpl_client_end =
fdf::internal::DriverTransportConnect<fuchsia_hardware_gpioimpl::Service::Device>(
svc_endpoints.client, component::kDefaultInstance);
ASSERT_TRUE(gpioimpl_client_end.is_ok());
client_.Bind(*std::move(gpioimpl_client_end), fdf::Dispatcher::GetCurrent()->get());
}
void TearDown() override {
zx::result prepare_stop_result = runtime_.RunToCompletion(dut_.PrepareStop());
EXPECT_EQ(prepare_stop_result.status_value(), ZX_OK);
EXPECT_TRUE(dut_.Stop().is_ok());
}
protected:
void CheckA113GetInterrupt(uint32_t requested_interrupt_flags,
uint32_t expected_kernel_interrupt_flags,
uint32_t expected_register_polarity_values) {
incoming_.platform_device.SetExpectedInterruptFlags(expected_kernel_interrupt_flags);
interrupt_mmio()[0x3c20 * sizeof(uint32_t)]
.ExpectRead(0x00000000)
.ExpectWrite(expected_register_polarity_values);
// Modify IRQ index for IRQ pin.
interrupt_mmio()[0x3c21 * sizeof(uint32_t)].ExpectRead(0x00000000).ExpectWrite(0x00000048);
// Interrupt select filter.
interrupt_mmio()[0x3c23 * sizeof(uint32_t)].ExpectRead(0x00000000).ExpectWrite(0x00000007);
zx::interrupt out_int;
fdf::Arena arena('GPIO');
client_.buffer(arena)->GetInterrupt(0x0B, requested_interrupt_flags).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
ddk_mock::MockMmioRegRegion& mmio() { return dut_->mmio(); }
ddk_mock::MockMmioRegRegion& ao_mmio() { return dut_->ao_mmio(); }
ddk_mock::MockMmioRegRegion& interrupt_mmio() { return dut_->interrupt_mmio(); }
fdf_testing::DriverRuntime runtime_;
fdf::WireClient<fuchsia_hardware_gpioimpl::GpioImpl> client_;
private:
fidl::ClientEnd<fuchsia_io::Directory> driver_outgoing_;
fdf::UnownedSynchronizedDispatcher background_dispatcher_;
IncomingNamespace<kPid> incoming_;
fdf_testing::TestNode node_server_;
fdf_testing::TestEnvironment test_environment_;
fdf_testing::DriverUnderTest<TestAmlGpioDriver> dut_;
};
using A113AmlGpioTest = AmlGpioTest<PDEV_PID_AMLOGIC_A113>;
using S905d2AmlGpioTest = AmlGpioTest<PDEV_PID_AMLOGIC_S905D2>;
// GpioImplSetAltFunction Tests
TEST_F(A113AmlGpioTest, A113AltMode1) {
mmio()[0x24 * sizeof(uint32_t)].ExpectRead(0x00000000).ExpectWrite(0x00000001);
fdf::Arena arena('GPIO');
client_.buffer(arena)->SetAltFunction(0x00, 1).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(A113AmlGpioTest, A113AltMode2) {
mmio()[0x26 * sizeof(uint32_t)].ExpectRead(0x00000009 << 8).ExpectWrite(0x00000005 << 8);
fdf::Arena arena('GPIO');
client_.buffer(arena)->SetAltFunction(0x12, 5).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(A113AmlGpioTest, A113AltMode3) {
ao_mmio()[0x05 * sizeof(uint32_t)].ExpectRead(0x00000000).ExpectWrite(0x00000005 << 16);
fdf::Arena arena('GPIO');
client_.buffer(arena)->SetAltFunction(0x56, 5).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(S905d2AmlGpioTest, S905d2AltMode) {
mmio()[0xb6 * sizeof(uint32_t)].ExpectRead(0x00000000).ExpectWrite(0x00000001);
fdf::Arena arena('GPIO');
client_.buffer(arena)->SetAltFunction(0x00, 1).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(A113AmlGpioTest, AltModeFail1) {
fdf::Arena arena('GPIO');
client_.buffer(arena)->SetAltFunction(0x00, 16).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_FALSE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(A113AmlGpioTest, AltModeFail2) {
fdf::Arena arena('GPIO');
client_.buffer(arena)->SetAltFunction(0xFFFF, 1).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_FALSE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
// GpioImplConfigIn Tests
TEST_F(A113AmlGpioTest, A113NoPull0) {
mmio()[0x12 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // oen
mmio()[0x3c * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // pull
mmio()[0x4a * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFE); // pull_en
fdf::Arena arena('GPIO');
client_.buffer(arena)
->ConfigIn(0, fuchsia_hardware_gpio::GpioFlags::kNoPull)
.Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(A113AmlGpioTest, A113NoPullMid) {
mmio()[0x12 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // oen
mmio()[0x3c * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // pull
mmio()[0x4a * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFBFFFF); // pull_en
fdf::Arena arena('GPIO');
client_.buffer(arena)
->ConfigIn(0x12, fuchsia_hardware_gpio::GpioFlags::kNoPull)
.Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(A113AmlGpioTest, A113NoPullHigh) {
ao_mmio()[0x08 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // oen
ao_mmio()[0x0b * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // pull
ao_mmio()[0x0b * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFEFFFF); // pull_en
fdf::Arena arena('GPIO');
client_.buffer(arena)
->ConfigIn(0x56, fuchsia_hardware_gpio::GpioFlags::kNoPull)
.Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(S905d2AmlGpioTest, S905d2NoPull0) {
mmio()[0x1c * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // oen
mmio()[0x3e * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // pull
mmio()[0x4c * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFE); // pull_en
fdf::Arena arena('GPIO');
client_.buffer(arena)
->ConfigIn(0x0, fuchsia_hardware_gpio::GpioFlags::kNoPull)
.Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(S905d2AmlGpioTest, S905d2PullUp) {
mmio()[0x10 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // oen
mmio()[0x3a * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // pull
mmio()[0x48 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // pull_en
fdf::Arena arena('GPIO');
client_.buffer(arena)
->ConfigIn(0x21, fuchsia_hardware_gpio::GpioFlags::kPullUp)
.Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(S905d2AmlGpioTest, S905d2PullDown) {
mmio()[0x10 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // oen
mmio()[0x3a * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFE); // pull
mmio()[0x48 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // pull_en
fdf::Arena arena('GPIO');
client_.buffer(arena)
->ConfigIn(0x20, fuchsia_hardware_gpio::GpioFlags::kPullDown)
.Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(A113AmlGpioTest, A113NoPullFail) {
fdf::Arena arena('GPIO');
client_.buffer(arena)
->ConfigIn(0xFFFF, fuchsia_hardware_gpio::GpioFlags::kNoPull)
.Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_FALSE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
// GpioImplConfigOut Tests
TEST_F(A113AmlGpioTest, A113Out) {
mmio()[0x0d * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // output
mmio()[0x0c * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFB); // oen
fdf::Arena arena('GPIO');
client_.buffer(arena)->ConfigOut(0x19, 1).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
// GpioImplRead Tests
TEST_F(A113AmlGpioTest, A113Read) {
mmio()[0x12 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // oen
mmio()[0x3c * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // pull
mmio()[0x4a * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFDF); // pull_en
mmio()[0x14 * sizeof(uint32_t)].ExpectRead(0x00000020); // read 0x01.
mmio()[0x14 * sizeof(uint32_t)].ExpectRead(0x00000000); // read 0x00.
mmio()[0x14 * sizeof(uint32_t)].ExpectRead(0x00000020); // read 0x01.
fdf::Arena arena('GPIO');
client_.buffer(arena)
->ConfigIn(5, fuchsia_hardware_gpio::GpioFlags::kNoPull)
.Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
});
client_.buffer(arena)->Read(5).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
ASSERT_TRUE(result->is_ok());
EXPECT_EQ(result->value()->value, 0x01);
});
client_.buffer(arena)->Read(5).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
ASSERT_TRUE(result->is_ok());
EXPECT_EQ(result->value()->value, 0x00);
});
client_.buffer(arena)->Read(5).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
ASSERT_TRUE(result->is_ok());
EXPECT_EQ(result->value()->value, 0x01);
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
// GpioImplWrite Tests
TEST_F(A113AmlGpioTest, A113Write) {
mmio()[0x13 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // write
mmio()[0x13 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFBFFF); // write
mmio()[0x13 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFF); // write
fdf::Arena arena('GPIO');
client_.buffer(arena)->Write(14, 200).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
});
client_.buffer(arena)->Write(14, 0).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
});
client_.buffer(arena)->Write(14, 92).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
// GpioImplGetInterrupt Tests
TEST_F(A113AmlGpioTest, A113GetInterruptFail) {
fdf::Arena arena('GPIO');
client_.buffer(arena)->GetInterrupt(0xFFFF, ZX_INTERRUPT_MODE_EDGE_LOW).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_FALSE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(A113AmlGpioTest, A113GetInterruptEdgeLow) {
// Request edge low polarity. Expect the kernel polarity to be converted to edge high.
CheckA113GetInterrupt(ZX_INTERRUPT_MODE_EDGE_LOW, ZX_INTERRUPT_MODE_EDGE_HIGH, 0x0001'0001);
}
TEST_F(A113AmlGpioTest, A113GetInterruptEdgeHigh) {
// Request edge high polarity. Expect the kernel polarity to stay as edge high.
CheckA113GetInterrupt(ZX_INTERRUPT_MODE_EDGE_HIGH, ZX_INTERRUPT_MODE_EDGE_HIGH, 0x0000'0001);
}
TEST_F(A113AmlGpioTest, A113GetInterruptLevelLow) {
// Request level low polarity. Expect the kernel polarity to be converted to level high.
CheckA113GetInterrupt(ZX_INTERRUPT_MODE_LEVEL_LOW, ZX_INTERRUPT_MODE_LEVEL_HIGH, 0x0001'0000);
}
TEST_F(A113AmlGpioTest, A113GetInterruptLevelHigh) {
// Request level high polarity. Expect the kernel polarity to stay as level high.
CheckA113GetInterrupt(ZX_INTERRUPT_MODE_LEVEL_HIGH, ZX_INTERRUPT_MODE_LEVEL_HIGH, 0x0000'0000);
}
// GpioImplReleaseInterrupt Tests
TEST_F(A113AmlGpioTest, A113ReleaseInterruptFail) {
fdf::Arena arena('GPIO');
client_.buffer(arena)->ReleaseInterrupt(0x66).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_FALSE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(A113AmlGpioTest, A113ReleaseInterrupt) {
interrupt_mmio()[0x3c21 * sizeof(uint32_t)]
.ExpectRead(0x00000000)
.ExpectWrite(0x00000048); // modify
interrupt_mmio()[0x3c20 * sizeof(uint32_t)].ExpectRead(0x00000000).ExpectWrite(0x00010001);
interrupt_mmio()[0x3c23 * sizeof(uint32_t)].ExpectRead(0x00000000).ExpectWrite(0x00000007);
fdf::Arena arena('GPIO');
client_.buffer(arena)->GetInterrupt(0x0B, ZX_INTERRUPT_MODE_EDGE_LOW).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
client_.buffer(arena)->ReleaseInterrupt(0x0B).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
// GpioImplSetPolarity Tests
TEST_F(A113AmlGpioTest, A113InterruptSetPolarityEdge) {
interrupt_mmio()[0x3c21 * sizeof(uint32_t)]
.ExpectRead(0x00000000)
.ExpectWrite(0x00000048); // modify
interrupt_mmio()[0x3c20 * sizeof(uint32_t)].ExpectRead(0x00000000).ExpectWrite(0x00010001);
interrupt_mmio()[0x3c23 * sizeof(uint32_t)].ExpectRead(0x00000000).ExpectWrite(0x00000007);
interrupt_mmio()[0x3c20 * sizeof(uint32_t)]
.ExpectRead(0x00010001)
.ExpectWrite(0x00000001); // polarity + for any edge.
fdf::Arena arena('GPIO');
client_.buffer(arena)->GetInterrupt(0x0B, ZX_INTERRUPT_MODE_EDGE_LOW).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
client_.buffer(arena)
->SetPolarity(0x0B, fuchsia_hardware_gpio::GpioPolarity::kHigh)
.Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_TRUE(result->is_ok());
runtime_.Quit();
});
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
// GpioImplSetDriveStrength Tests
TEST_F(A113AmlGpioTest, A113SetDriveStrength) {
fdf::Arena arena('GPIO');
client_.buffer(arena)->SetDriveStrength(0x87, 2).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
EXPECT_FALSE(result->is_ok());
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(S905d2AmlGpioTest, S905d2SetDriveStrength) {
ao_mmio()[0x08 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFF).ExpectWrite(0xFFFFFFFB);
fdf::Arena arena('GPIO');
client_.buffer(arena)->SetDriveStrength(0x62, 3000).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
ASSERT_TRUE(result->is_ok());
EXPECT_EQ(result->value()->actual_ds_ua, 3000);
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
TEST_F(S905d2AmlGpioTest, S905d2GetDriveStrength) {
ao_mmio()[0x08 * sizeof(uint32_t)].ExpectRead(0xFFFFFFFB);
fdf::Arena arena('GPIO');
client_.buffer(arena)->GetDriveStrength(0x62).Then([&](auto& result) {
ASSERT_TRUE(result.ok());
ASSERT_TRUE(result->is_ok());
EXPECT_EQ(result->value()->result_ua, 3000);
runtime_.Quit();
});
runtime_.Run();
mmio().VerifyAll();
ao_mmio().VerifyAll();
interrupt_mmio().VerifyAll();
}
} // namespace gpio