| // 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 |