blob: 5ee2c2371b3b3d19a29ef2127aae71d1a25f87f5 [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 "power.h"
#include <lib/fake_ddk/fake_ddk.h>
#include <memory>
#include <zxtest/zxtest.h>
#include "ddk/protocol/powerimpl.h"
#include "ddktl/protocol/power.h"
#include "ddktl/protocol/powerimpl.h"
namespace power {
class FakePower : public ddk::PowerProtocol<FakePower> {
public:
FakePower() : proto_{.ops = &power_protocol_ops_, .ctx = this} {}
ddk::PowerProtocolClient GetClient() const { return ddk::PowerProtocolClient(&proto_); }
zx_status_t PowerRegisterPowerDomain(uint32_t min_needed_voltage_uV,
uint32_t max_supported_voltage_uV) {
power_domain_registered_count_++;
return ZX_OK;
}
zx_status_t PowerUnregisterPowerDomain() {
power_domain_unregistered_count_++;
return ZX_OK;
}
zx_status_t PowerGetPowerDomainStatus(power_domain_status_t* out_status) { return ZX_OK; }
zx_status_t PowerGetSupportedVoltageRange(uint32_t* min_voltage, uint32_t* max_voltage) {
return ZX_OK;
}
zx_status_t PowerRequestVoltage(uint32_t voltage, uint32_t* actual_voltage) { return ZX_OK; }
zx_status_t PowerGetCurrentVoltage(uint32_t index, uint32_t* current_voltage) { return ZX_OK; }
zx_status_t PowerWritePmicCtrlReg(uint32_t reg_addr, uint32_t value) { return ZX_OK; }
zx_status_t PowerReadPmicCtrlReg(uint32_t reg_addr, uint32_t* out_value) { return ZX_OK; }
uint32_t power_domain_registered_count() { return power_domain_registered_count_; }
uint32_t power_domain_unregistered_count() { return power_domain_unregistered_count_; }
private:
power_protocol_t proto_;
uint32_t power_domain_registered_count_ = 0;
uint32_t power_domain_unregistered_count_ = 0;
};
class FakePowerImpl : public ddk::PowerImplProtocol<FakePowerImpl> {
public:
FakePowerImpl() : proto_{.ops = &power_impl_protocol_ops_, .ctx = this} {}
ddk::PowerImplProtocolClient GetClient() const { return ddk::PowerImplProtocolClient(&proto_); }
zx_status_t PowerImplGetCurrentVoltage(uint32_t index, uint32_t* current_voltage) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t PowerImplDisablePowerDomain(uint32_t index) {
power_domain_disabled_count_++;
return ZX_OK;
}
zx_status_t PowerImplEnablePowerDomain(uint32_t index) {
power_domain_enabled_count_++;
return ZX_OK;
}
zx_status_t PowerImplGetPowerDomainStatus(uint32_t index, power_domain_status_t* out_status) {
return ZX_OK;
}
zx_status_t PowerImplGetSupportedVoltageRange(uint32_t index, uint32_t* min_voltage,
uint32_t* max_voltage) {
return ZX_OK;
}
zx_status_t PowerImplRequestVoltage(uint32_t index, uint32_t voltage, uint32_t* actual_voltage) {
*actual_voltage = voltage;
return ZX_OK;
}
zx_status_t PowerImplWritePmicCtrlReg(uint32_t index, uint32_t reg_addr, uint32_t value) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t PowerImplReadPmicCtrlReg(uint32_t index, uint32_t addr, uint32_t* value) {
return ZX_ERR_NOT_SUPPORTED;
}
uint32_t power_domain_enabled_count() { return power_domain_enabled_count_; }
uint32_t power_domain_disabled_count() { return power_domain_disabled_count_; }
private:
power_impl_protocol_t proto_;
uint32_t power_domain_enabled_count_ = 0;
uint32_t power_domain_disabled_count_ = 0;
};
class GenericPowerTest : public zxtest::Test {
public:
explicit GenericPowerTest() {}
void SetUp() override {
power_impl_ = std::make_unique<FakePowerImpl>();
parent_power_ = std::make_unique<FakePower>();
dut_ = std::make_unique<PowerDevice>(fake_ddk::kFakeParent, 0, power_impl_->GetClient(),
parent_power_->GetClient(), 10, 1000, false);
dut_->DdkOpenProtocolSessionMultibindable(ZX_PROTOCOL_POWER, &proto_ctx_);
}
protected:
std::unique_ptr<PowerDevice> dut_;
power_protocol_t proto_ctx_;
std::unique_ptr<FakePower> parent_power_;
std::unique_ptr<FakePowerImpl> power_impl_;
};
TEST_F(GenericPowerTest, RegisterDomain) {
ddk::PowerProtocolClient proto_client = ddk::PowerProtocolClient(&proto_ctx_);
proto_client.RegisterPowerDomain(20, 800);
EXPECT_EQ(dut_->GetDependentCount(), 1);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
}
TEST_F(GenericPowerTest, RegisterTwice) {
ddk::PowerProtocolClient proto_client = ddk::PowerProtocolClient(&proto_ctx_);
EXPECT_OK(proto_client.RegisterPowerDomain(20, 800));
EXPECT_EQ(dut_->GetDependentCount(), 1);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
EXPECT_OK(proto_client.RegisterPowerDomain(20, 800));
EXPECT_EQ(dut_->GetDependentCount(), 1);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
}
TEST_F(GenericPowerTest, UnregisterDomain) {
ddk::PowerProtocolClient proto_client = ddk::PowerProtocolClient(&proto_ctx_);
EXPECT_OK(proto_client.RegisterPowerDomain(20, 800));
EXPECT_EQ(dut_->GetDependentCount(), 1);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
EXPECT_OK(proto_client.UnregisterPowerDomain());
EXPECT_EQ(dut_->GetDependentCount(), 0);
EXPECT_EQ(parent_power_->power_domain_unregistered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_disabled_count(), 1);
}
TEST_F(GenericPowerTest, UnregisterTwice) {
ddk::PowerProtocolClient proto_client = ddk::PowerProtocolClient(&proto_ctx_);
EXPECT_OK(proto_client.RegisterPowerDomain(20, 800));
EXPECT_EQ(dut_->GetDependentCount(), 1);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
EXPECT_OK(proto_client.UnregisterPowerDomain());
EXPECT_EQ(dut_->GetDependentCount(), 0);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
EXPECT_EQ(proto_client.UnregisterPowerDomain(), ZX_ERR_UNAVAILABLE);
EXPECT_EQ(dut_->GetDependentCount(), 0);
}
TEST_F(GenericPowerTest, DependentCount_TwoChildren) {
ddk::PowerProtocolClient proto_client = ddk::PowerProtocolClient(&proto_ctx_);
proto_client.RegisterPowerDomain(20, 800);
EXPECT_EQ(dut_->GetDependentCount(), 1);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
power_protocol_t proto_ctx_2;
dut_->DdkOpenProtocolSessionMultibindable(ZX_PROTOCOL_POWER, &proto_ctx_2);
ddk::PowerProtocolClient proto_client_2 = ddk::PowerProtocolClient(&proto_ctx_2);
EXPECT_EQ(dut_->GetDependentCount(), 1);
proto_client_2.RegisterPowerDomain(50, 400);
EXPECT_EQ(dut_->GetDependentCount(), 2);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
}
TEST_F(GenericPowerTest, GetSupportedVoltageRange) {
ddk::PowerProtocolClient proto_client = ddk::PowerProtocolClient(&proto_ctx_);
uint32_t min_voltage = 0;
uint32_t max_voltage = 0;
proto_client.GetSupportedVoltageRange(&min_voltage, &max_voltage);
EXPECT_EQ(min_voltage, 10);
EXPECT_EQ(max_voltage, 1000);
}
TEST_F(GenericPowerTest, RequestVoltage_UnsuppportedVoltage) {
ddk::PowerProtocolClient proto_client = ddk::PowerProtocolClient(&proto_ctx_);
proto_client.RegisterPowerDomain(20, 800);
uint32_t min_voltage = 0;
uint32_t max_voltage = 0;
proto_client.GetSupportedVoltageRange(&min_voltage, &max_voltage);
EXPECT_EQ(min_voltage, 10);
EXPECT_EQ(max_voltage, 1000);
uint32_t out_voltage = 0;
EXPECT_EQ(proto_client.RequestVoltage(1010, &out_voltage), ZX_ERR_INVALID_ARGS);
}
TEST_F(GenericPowerTest, RequestVoltage) {
ddk::PowerProtocolClient proto_client = ddk::PowerProtocolClient(&proto_ctx_);
EXPECT_OK(proto_client.RegisterPowerDomain(20, 800));
EXPECT_EQ(dut_->GetDependentCount(), 1);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
power_protocol_t proto_ctx_2;
dut_->DdkOpenProtocolSessionMultibindable(ZX_PROTOCOL_POWER, &proto_ctx_2);
ddk::PowerProtocolClient proto_client_2 = ddk::PowerProtocolClient(&proto_ctx_2);
EXPECT_EQ(dut_->GetDependentCount(), 1);
EXPECT_OK(proto_client_2.RegisterPowerDomain(10, 400));
EXPECT_EQ(dut_->GetDependentCount(), 2);
uint32_t out_actual_voltage = 0;
EXPECT_OK(proto_client_2.RequestVoltage(900, &out_actual_voltage));
EXPECT_EQ(out_actual_voltage, 400);
EXPECT_OK(proto_client_2.RequestVoltage(15, &out_actual_voltage));
EXPECT_EQ(out_actual_voltage, 20);
EXPECT_OK(proto_client_2.UnregisterPowerDomain());
EXPECT_EQ(dut_->GetDependentCount(), 1);
EXPECT_OK(proto_client.RequestVoltage(900, &out_actual_voltage));
EXPECT_EQ(out_actual_voltage, 800);
EXPECT_OK(proto_client.RequestVoltage(15, &out_actual_voltage));
EXPECT_EQ(out_actual_voltage, 20);
}
TEST_F(GenericPowerTest, RequestVoltage_Unregistered) {
ddk::PowerProtocolClient proto_client = ddk::PowerProtocolClient(&proto_ctx_);
uint32_t out_actual_voltage;
EXPECT_EQ(proto_client.RequestVoltage(900, &out_actual_voltage), ZX_ERR_UNAVAILABLE);
}
TEST_F(GenericPowerTest, FixedVoltageDomain) {
auto dut_fixed = std::make_unique<PowerDevice>(fake_ddk::kFakeParent, 1, power_impl_->GetClient(),
parent_power_->GetClient(), 1000, 1000, true);
power_protocol_t proto_ctx_2;
dut_fixed->DdkOpenProtocolSessionMultibindable(ZX_PROTOCOL_POWER, &proto_ctx_2);
ddk::PowerProtocolClient proto_client_2 = ddk::PowerProtocolClient(&proto_ctx_2);
EXPECT_OK(proto_client_2.RegisterPowerDomain(0, 0));
EXPECT_EQ(dut_fixed->GetDependentCount(), 1);
EXPECT_EQ(parent_power_->power_domain_registered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_enabled_count(), 1);
uint32_t min_voltage = 0, max_voltage = 0;
EXPECT_EQ(proto_client_2.GetSupportedVoltageRange(&min_voltage, &max_voltage),
ZX_ERR_NOT_SUPPORTED);
uint32_t out_voltage = 0;
EXPECT_EQ(proto_client_2.RequestVoltage(900, &out_voltage), ZX_ERR_NOT_SUPPORTED);
EXPECT_OK(proto_client_2.UnregisterPowerDomain());
EXPECT_EQ(dut_fixed->GetDependentCount(), 0);
EXPECT_EQ(parent_power_->power_domain_unregistered_count(), 1);
EXPECT_EQ(power_impl_->power_domain_disabled_count(), 1);
}
} // namespace power