blob: 31d7cd47fb5a0e5510a0a6130623fa7cd8611d39 [file] [log] [blame]
// 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.
#include "vs680-thermal.h"
#include <fuchsia/hardware/clock/cpp/banjo-mock.h>
#include <fuchsia/hardware/power/cpp/banjo-mock.h>
#include <lib/fake_ddk/fidl-helper.h>
#include <lib/mmio-ptr/fake.h>
#include <lib/zx/clock.h>
#include <memory>
#include <zxtest/zxtest.h>
namespace {
bool FloatNear(float a, float b) { return std::abs(a - b) < 0.001f; }
} // namespace
namespace thermal {
using ThermalClient = fidl::WireSyncClient<fuchsia_hardware_thermal::Device>;
class Vs680ThermalTest : public zxtest::Test {
public:
Vs680ThermalTest() {}
void SetUp() override {
ddk::MmioBuffer mmio({FakeMmioPtr(registers_), 0, sizeof(registers_), ZX_HANDLE_INVALID});
ASSERT_OK(zx::interrupt::create({}, 0, ZX_INTERRUPT_VIRTUAL, &interrupt_));
zx::interrupt dut_interrupt;
ASSERT_OK(interrupt_.duplicate(ZX_RIGHT_SAME_RIGHTS, &dut_interrupt));
dut_.reset(new Vs680Thermal(nullptr, std::move(mmio), std::move(dut_interrupt),
clock_.GetProto(), power_.GetProto(), zx::msec(1)));
ASSERT_OK(messenger_.SetMessageOp(
dut_.get(), [](void* ctx, fidl_incoming_msg_t* msg, fidl_txn_t* txn) -> zx_status_t {
return static_cast<Vs680Thermal*>(ctx)->DdkMessage(msg, txn);
}));
power_.ExpectRegisterPowerDomain(ZX_OK, 800'000, 800'000);
clock_.ExpectSetRate(ZX_OK, 1'800'000'000);
power_.ExpectRequestVoltage(ZX_OK, 800'000, 800'000);
ASSERT_OK(dut_->Init());
// Init() started the interrupt thread, so DdkRelease must be called before destruction of the
// Vs680Thermal object.
}
void TearDown() override {
dut_->DdkRelease();
dut_.release();
}
protected:
uint32_t registers_[0x180 / 4];
zx::interrupt interrupt_;
ddk::MockClock clock_;
ddk::MockPower power_;
std::unique_ptr<Vs680Thermal> dut_;
fake_ddk::FidlMessenger messenger_;
};
TEST_F(Vs680ThermalTest, GetTemperature) {
ThermalClient client(std::move(messenger_.local()));
auto result = client.GetTemperatureCelsius();
EXPECT_OK(result->status);
EXPECT_TRUE(FloatNear(result->temp, 0.0f));
registers_[0x108 / 4] = 311;
EXPECT_OK(interrupt_.trigger(0, zx::clock::get_monotonic()));
// Rather than trying to synchronize with the polling thread, just loop until we get the value we
// expect.
auto temp = result->temp;
while (!FloatNear(temp, 37.812f)) {
auto result = client.GetTemperatureCelsius();
EXPECT_OK(result->status);
temp = result->temp;
}
registers_[0x108 / 4] = 358;
EXPECT_OK(interrupt_.trigger(0, zx::clock::get_monotonic()));
temp = result->temp;
while (!FloatNear(temp, 48.576f)) {
auto result = client.GetTemperatureCelsius();
EXPECT_OK(result->status);
temp = result->temp;
}
}
TEST_F(Vs680ThermalTest, OperatingPoints) {
ThermalClient client(std::move(messenger_.local()));
auto get_result = client.GetDvfsOperatingPoint(PowerDomain::BIG_CLUSTER_POWER_DOMAIN);
EXPECT_OK(get_result->status);
EXPECT_EQ(get_result->op_idx, 0);
clock_.ExpectSetRate(ZX_OK, 1'800'000'000);
power_.ExpectRequestVoltage(ZX_OK, 800'000, 800'000);
auto set_result = client.SetDvfsOperatingPoint(0, PowerDomain::BIG_CLUSTER_POWER_DOMAIN);
EXPECT_OK(set_result->status);
ASSERT_NO_FATAL_FAILURES(clock_.VerifyAndClear());
ASSERT_NO_FATAL_FAILURES(power_.VerifyAndClear());
}
} // namespace thermal