blob: 189f03d0992b07a58d480e4a4b14d643470d0955 [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-thermal.h"
#include <fidl/fuchsia.hardware.pwm/cpp/wire_test_base.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/default.h>
#include <lib/async_patterns/testing/cpp/dispatcher_bound.h>
#include <lib/ddk/device.h>
#include <lib/mmio/mmio-buffer.h>
#include <lib/mmio/mmio.h>
#include <stdint.h>
#include <zircon/assert.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <cstddef>
#include <list>
#include <memory>
#include <fbl/alloc_checker.h>
#include <fbl/array.h>
#include <mock-mmio-reg-zxtest/mock-mmio-reg.h>
#include <zxtest/zxtest.h>
#include "src/devices/lib/mmio/test-helper.h"
bool operator==(const fuchsia_hardware_pwm::wire::PwmConfig& lhs,
const fuchsia_hardware_pwm::wire::PwmConfig& rhs) {
return (lhs.polarity == rhs.polarity) && (lhs.period_ns == rhs.period_ns) &&
(lhs.duty_cycle == rhs.duty_cycle) &&
(lhs.mode_config.count() == rhs.mode_config.count()) &&
(reinterpret_cast<aml_pwm::mode_config*>(lhs.mode_config.data())->mode ==
reinterpret_cast<aml_pwm::mode_config*>(rhs.mode_config.data())->mode);
}
namespace {
constexpr size_t kRegSize = 0x00002000 / sizeof(uint32_t); // in 32 bits chunks.
// Temperature Sensor
// Copied from sherlock-thermal.cc
constexpr fuchsia_hardware_thermal::wire::ThermalTemperatureInfo TripPoint(float temp_c,
float hysteresis_c,
uint16_t cpu_opp_big,
uint16_t cpu_opp_little,
uint16_t gpu_opp) {
return {
.up_temp_celsius = temp_c + hysteresis_c,
.down_temp_celsius = temp_c - hysteresis_c,
.fan_level = 0,
.big_cluster_dvfs_opp = cpu_opp_big,
.little_cluster_dvfs_opp = cpu_opp_little,
.gpu_clk_freq_source = gpu_opp,
};
}
constexpr fuchsia_hardware_thermal::wire::ThermalDeviceInfo
sherlock_thermal_config =
{
.active_cooling = false,
.passive_cooling = true,
.gpu_throttling = true,
.num_trip_points = 6,
.big_little = true,
.critical_temp_celsius = 102.0f,
.trip_point_info =
{
TripPoint(55.0f, 2.0f, 9, 10, 4),
TripPoint(75.0f, 2.0f, 8, 9, 4),
TripPoint(80.0f, 2.0f, 7, 8, 3),
TripPoint(90.0f, 2.0f, 6, 7, 3),
TripPoint(95.0f, 2.0f, 5, 6, 3),
TripPoint(100.0f, 2.0f, 4, 5, 2),
// 0 Kelvin is impossible, marks end of TripPoints
TripPoint(-273.15f, 2.0f, 0, 0, 0),
},
.opps =
{
fuchsia_hardware_thermal::wire::OperatingPoint{
.opp =
{
fuchsia_hardware_thermal::wire::OperatingPointEntry{
.freq_hz = 100000000, .volt_uv = 751000},
{.freq_hz = 250000000, .volt_uv = 751000},
{.freq_hz = 500000000, .volt_uv = 751000},
{.freq_hz = 667000000, .volt_uv = 751000},
{.freq_hz = 1000000000, .volt_uv = 771000},
{.freq_hz = 1200000000, .volt_uv = 771000},
{.freq_hz = 1398000000, .volt_uv = 791000},
{.freq_hz = 1512000000, .volt_uv = 821000},
{.freq_hz = 1608000000, .volt_uv = 861000},
{.freq_hz = 1704000000, .volt_uv = 891000},
{.freq_hz = 1704000000, .volt_uv = 891000},
},
.latency = 0,
.count = 11,
},
{
.opp =
{
fuchsia_hardware_thermal::wire::OperatingPointEntry{
.freq_hz = 100000000, .volt_uv = 731000},
{.freq_hz = 250000000, .volt_uv = 731000},
{.freq_hz = 500000000, .volt_uv = 731000},
{.freq_hz = 667000000, .volt_uv = 731000},
{.freq_hz = 1000000000, .volt_uv = 731000},
{.freq_hz = 1200000000, .volt_uv = 731000},
{.freq_hz = 1398000000, .volt_uv = 761000},
{.freq_hz = 1512000000, .volt_uv = 791000},
{.freq_hz = 1608000000, .volt_uv = 831000},
{.freq_hz = 1704000000, .volt_uv = 861000},
{.freq_hz = 1896000000, .volt_uv = 1011000},
},
.latency = 0,
.count = 11,
},
},
};
constexpr fuchsia_hardware_thermal::wire::ThermalDeviceInfo astro_thermal_config =
{
.active_cooling = false,
.passive_cooling = true,
.gpu_throttling = true,
.num_trip_points = 7,
.big_little = false,
.critical_temp_celsius = 102.0f,
.trip_point_info =
{
TripPoint(0.0f, 2.0f, 10, 0, 5),
TripPoint(75.0f, 2.0f, 9, 0, 4),
TripPoint(80.0f, 2.0f, 8, 0, 3),
TripPoint(85.0f, 2.0f, 7, 0, 3),
TripPoint(90.0f, 2.0f, 6, 0, 2),
TripPoint(95.0f, 2.0f, 5, 0, 1),
TripPoint(100.0f, 2.0f, 4, 0, 0),
// 0 Kelvin is impossible, marks end of TripPoints
TripPoint(-273.15f, 2.0f, 0, 0, 0),
},
.opps =
{
fuchsia_hardware_thermal::wire::OperatingPoint{
.opp =
{
fuchsia_hardware_thermal::wire::OperatingPointEntry{
.freq_hz = 100'000'000, .volt_uv = 731'000},
{.freq_hz = 250'000'000, .volt_uv = 731'000},
{.freq_hz = 500'000'000, .volt_uv = 731'000},
{.freq_hz = 667'000'000, .volt_uv = 731'000},
{.freq_hz = 1'000'000'000, .volt_uv = 731'000},
{.freq_hz = 1'200'000'000, .volt_uv = 731'000},
{.freq_hz = 1'398'000'000, .volt_uv = 761'000},
{.freq_hz = 1'512'000'000, .volt_uv = 791'000},
{.freq_hz = 1'608'000'000, .volt_uv = 831'000},
{.freq_hz = 1'704'000'000, .volt_uv = 861'000},
{.freq_hz = 1'896'000'000, .volt_uv = 981'000},
},
.latency = 0,
.count = 11,
},
},
};
constexpr fuchsia_hardware_thermal::wire::ThermalDeviceInfo nelson_thermal_config = {
.active_cooling = false,
.passive_cooling = true,
.gpu_throttling = true,
.num_trip_points = 5,
.big_little = false,
.critical_temp_celsius = 110.0f,
.trip_point_info =
{
TripPoint(0.0f, 5.0f, 11, 0, 5),
TripPoint(60.0f, 5.0f, 9, 0, 4),
TripPoint(75.0f, 5.0f, 8, 0, 3),
TripPoint(80.0f, 5.0f, 7, 0, 2),
TripPoint(110.0f, 1.0f, 0, 0, 0),
// 0 Kelvin is impossible, marks end of TripPoints
TripPoint(-273.15f, 2.0f, 0, 0, 0),
},
.opps =
{
fuchsia_hardware_thermal::wire::OperatingPoint{
.opp =
{
fuchsia_hardware_thermal::wire::OperatingPointEntry{.freq_hz = 100'000'000,
.volt_uv = 760'000},
{.freq_hz = 250'000'000, .volt_uv = 760'000},
{.freq_hz = 500'000'000, .volt_uv = 760'000},
{.freq_hz = 667'000'000, .volt_uv = 780'000},
{.freq_hz = 1'000'000'000, .volt_uv = 800'000},
{.freq_hz = 1'200'000'000, .volt_uv = 810'000},
{.freq_hz = 1'404'000'000, .volt_uv = 820'000},
{.freq_hz = 1'512'000'000, .volt_uv = 830'000},
{.freq_hz = 1'608'000'000, .volt_uv = 860'000},
{.freq_hz = 1'704'000'000, .volt_uv = 900'000},
{.freq_hz = 1'800'000'000, .volt_uv = 940'000},
{.freq_hz = 1'908'000'000, .volt_uv = 970'000},
},
.latency = 0,
.count = 12,
},
},
};
// Voltage Regulator
// Copied from sherlock-thermal.cc
aml_thermal_info_t fake_thermal_info = {
.voltage_table =
{
{1022000, 0}, {1011000, 3}, {1001000, 6}, {991000, 10}, {981000, 13}, {971000, 16},
{961000, 20}, {951000, 23}, {941000, 26}, {931000, 30}, {921000, 33}, {911000, 36},
{901000, 40}, {891000, 43}, {881000, 46}, {871000, 50}, {861000, 53}, {851000, 56},
{841000, 60}, {831000, 63}, {821000, 67}, {811000, 70}, {801000, 73}, {791000, 76},
{781000, 80}, {771000, 83}, {761000, 86}, {751000, 90}, {741000, 93}, {731000, 96},
{721000, 100},
},
.initial_cluster_frequencies =
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wc99-designator"
[static_cast<uint32_t>(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain)] =
1'000'000'000,
[static_cast<uint32_t>(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain)] =
1'200'000'000,
#pragma GCC diagnostic pop
},
.voltage_pwm_period_ns = 1250,
.opps = {},
.cluster_id_map = {},
};
constexpr aml_thermal_info_t nelson_thermal_info = {
.voltage_table =
{
{1'050'000, 0}, {1'040'000, 3}, {1'030'000, 6}, {1'020'000, 8}, {1'010'000, 11},
{1'000'000, 14}, {990'000, 17}, {980'000, 20}, {970'000, 23}, {960'000, 26},
{950'000, 29}, {940'000, 31}, {930'000, 34}, {920'000, 37}, {910'000, 40},
{900'000, 43}, {890'000, 45}, {880'000, 48}, {870'000, 51}, {860'000, 54},
{850'000, 56}, {840'000, 59}, {830'000, 62}, {820'000, 65}, {810'000, 68},
{800'000, 70}, {790'000, 73}, {780'000, 76}, {770'000, 79}, {760'000, 81},
{750'000, 84}, {740'000, 87}, {730'000, 89}, {720'000, 92}, {710'000, 95},
{700'000, 98}, {690'000, 100},
},
.initial_cluster_frequencies =
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wc99-designator"
[static_cast<uint32_t>(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain)] =
1'000'000'000,
#pragma GCC diagnostic pop
},
.voltage_pwm_period_ns = 1500,
.opps = {},
.cluster_id_map = {},
};
} // namespace
namespace thermal {
// Temperature Sensor
class FakeAmlTSensor : public AmlTSensor {
public:
static std::unique_ptr<FakeAmlTSensor> Create(fdf::MmioBuffer pll_mmio, fdf::MmioBuffer trim_mmio,
fdf::MmioBuffer hiu_mmio, bool less) {
fbl::AllocChecker ac;
auto test = fbl::make_unique_checked<FakeAmlTSensor>(&ac, std::move(pll_mmio),
std::move(trim_mmio), std::move(hiu_mmio));
if (!ac.check()) {
return nullptr;
}
auto config = sherlock_thermal_config;
if (less) {
config.num_trip_points = 2;
config.trip_point_info[2].up_temp_celsius = -273.15f + 2.0f;
}
EXPECT_OK(test->InitSensor(config));
return test;
}
explicit FakeAmlTSensor(fdf::MmioBuffer pll_mmio, fdf::MmioBuffer trim_mmio,
fdf::MmioBuffer hiu_mmio)
: AmlTSensor(std::move(pll_mmio), std::move(trim_mmio), std::move(hiu_mmio)) {}
};
class AmlTSensorTest : public zxtest::Test {
public:
void SetUp() override {
fbl::AllocChecker ac;
mock_pll_mmio_ =
fbl::make_unique_checked<ddk_mock::MockMmioRegRegion>(&ac, sizeof(uint32_t), kRegSize);
if (!ac.check()) {
zxlogf(ERROR, "AmlTSensorTest::SetUp: mock_pll_mmio_ alloc failed");
return;
}
mock_trim_mmio_ =
fbl::make_unique_checked<ddk_mock::MockMmioRegRegion>(&ac, sizeof(uint32_t), kRegSize);
if (!ac.check()) {
zxlogf(ERROR, "AmlTSensorTest::SetUp: mock_trim_mmio_ alloc failed");
return;
}
mock_hiu_mmio_ =
fbl::make_unique_checked<ddk_mock::MockMmioRegRegion>(&ac, sizeof(uint32_t), kRegSize);
if (!ac.check()) {
zxlogf(ERROR, "AmlTSensorTest::SetUp: mock_hiu_mmio_ alloc failed");
return;
}
(*mock_trim_mmio_)[0].ExpectRead(0x00000000); // trim_info_
(*mock_hiu_mmio_)[(0x64 << 2)].ExpectWrite(0x130U); // set clock
(*mock_pll_mmio_)[(0x1 << 2)].ExpectRead(0x00000000).ExpectWrite(0x63B); // sensor ctl
}
void Create(bool less) {
// InitTripPoints
if (!less) {
(*mock_pll_mmio_)[(0x5 << 2)]
.ExpectRead(0x00000000) // set thresholds 4, rise
.ExpectWrite(0x00027E);
(*mock_pll_mmio_)[(0x7 << 2)]
.ExpectRead(0x00000000) // set thresholds 4, fall
.ExpectWrite(0x000272);
(*mock_pll_mmio_)[(0x5 << 2)]
.ExpectRead(0x00000000) // set thresholds 3, rise
.ExpectWrite(0x272000);
(*mock_pll_mmio_)[(0x7 << 2)]
.ExpectRead(0x00000000) // set thresholds 3, fall
.ExpectWrite(0x268000);
(*mock_pll_mmio_)[(0x4 << 2)]
.ExpectRead(0x00000000) // set thresholds 2, rise
.ExpectWrite(0x00025A);
(*mock_pll_mmio_)[(0x6 << 2)]
.ExpectRead(0x00000000) // set thresholds 2, fall
.ExpectWrite(0x000251);
}
(*mock_pll_mmio_)[(0x4 << 2)]
.ExpectRead(0x00000000) // set thresholds 1, rise
.ExpectWrite(0x250000);
(*mock_pll_mmio_)[(0x6 << 2)]
.ExpectRead(0x00000000) // set thresholds 1, fall
.ExpectWrite(0x245000);
(*mock_pll_mmio_)[(0x1 << 2)]
.ExpectRead(0x00000000) // clear IRQs
.ExpectWrite(0x00FF0000);
(*mock_pll_mmio_)[(0x1 << 2)]
.ExpectRead(0x00000000) // clear IRQs
.ExpectWrite(0x00000000);
if (!less) {
(*mock_pll_mmio_)[(0x1 << 2)]
.ExpectRead(0x00000000) // enable IRQs
.ExpectWrite(0x0F008000);
} else {
(*mock_pll_mmio_)[(0x1 << 2)]
.ExpectRead(0x00000000) // enable IRQs
.ExpectWrite(0x01008000);
}
// Enable SoC reset at 102.0f
(*mock_pll_mmio_)[(0x2 << 2)].ExpectRead(0x0);
(*mock_pll_mmio_)[(0x2 << 2)].ExpectWrite(0xc0ff2880);
fdf::MmioBuffer pll_mmio(mock_pll_mmio_->GetMmioBuffer());
fdf::MmioBuffer trim_mmio(mock_trim_mmio_->GetMmioBuffer());
fdf::MmioBuffer hiu_mmio(mock_hiu_mmio_->GetMmioBuffer());
tsensor_ = FakeAmlTSensor::Create(std::move(pll_mmio), std::move(trim_mmio),
std::move(hiu_mmio), less);
ASSERT_TRUE(tsensor_ != nullptr);
}
void TearDown() override {
// Verify
mock_pll_mmio_->VerifyAll();
mock_trim_mmio_->VerifyAll();
mock_hiu_mmio_->VerifyAll();
}
protected:
std::unique_ptr<FakeAmlTSensor> tsensor_;
std::unique_ptr<ddk_mock::MockMmioRegRegion> mock_pll_mmio_;
std::unique_ptr<ddk_mock::MockMmioRegRegion> mock_trim_mmio_;
std::unique_ptr<ddk_mock::MockMmioRegRegion> mock_hiu_mmio_;
};
TEST_F(AmlTSensorTest, ReadTemperatureCelsiusTest0) {
Create(false);
for (int j = 0; j < 0x10; j++) {
(*mock_pll_mmio_)[(0x10 << 2)].ExpectRead(0x0000);
}
float val = tsensor_->ReadTemperatureCelsius();
EXPECT_EQ(val, 0.0);
}
TEST_F(AmlTSensorTest, ReadTemperatureCelsiusTest1) {
Create(false);
for (int j = 0; j < 0x10; j++) {
(*mock_pll_mmio_)[(0x10 << 2)].ExpectRead(0x18A9);
}
float val = tsensor_->ReadTemperatureCelsius();
EXPECT_EQ(val, 429496704.0);
}
TEST_F(AmlTSensorTest, ReadTemperatureCelsiusTest2) {
Create(false);
for (int j = 0; j < 0x10; j++) {
(*mock_pll_mmio_)[(0x10 << 2)].ExpectRead(0x32A7);
}
float val = tsensor_->ReadTemperatureCelsius();
EXPECT_EQ(val, 0.0);
}
TEST_F(AmlTSensorTest, ReadTemperatureCelsiusTest3) {
Create(false);
(*mock_pll_mmio_)[(0x10 << 2)].ExpectRead(0x18A9);
(*mock_pll_mmio_)[(0x10 << 2)].ExpectRead(0x18AA);
for (int j = 0; j < 0xE; j++) {
(*mock_pll_mmio_)[(0x10 << 2)].ExpectRead(0x0000);
}
float val = tsensor_->ReadTemperatureCelsius();
EXPECT_EQ(val, 429496704.0);
}
TEST_F(AmlTSensorTest, GetStateChangePortTest) {
Create(false);
zx_handle_t port;
EXPECT_OK(tsensor_->GetStateChangePort(&port));
}
TEST_F(AmlTSensorTest, LessTripPointsTest) { Create(true); }
// Voltage Regulator
class FakeAmlVoltageRegulator : public AmlVoltageRegulator {
public:
static std::unique_ptr<FakeAmlVoltageRegulator> Create(
fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> big_cluster_pwm,
fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> little_cluster_pwm, uint32_t pid) {
fbl::AllocChecker ac;
auto test = fbl::make_unique_checked<FakeAmlVoltageRegulator>(&ac);
if (!ac.check()) {
return nullptr;
}
const auto& config = (pid == 4 ? sherlock_thermal_config : astro_thermal_config);
EXPECT_OK(test->Init(std::move(big_cluster_pwm), std::move(little_cluster_pwm), config,
&fake_thermal_info));
return test;
}
};
class MockPwmServer final : public fidl::testing::WireTestBase<fuchsia_hardware_pwm::Pwm> {
public:
void SetConfig(SetConfigRequestView request, SetConfigCompleter::Sync& completer) override {
ASSERT_GT(expect_configs_.size(), 0);
auto expect_config = expect_configs_.front();
ASSERT_EQ(request->config, expect_config);
expect_configs_.pop_front();
mode_config_buffers_.pop_front();
completer.ReplySuccess();
}
void Enable(EnableCompleter::Sync& completer) override {
ASSERT_TRUE(expect_enable_);
expect_enable_ = false;
completer.ReplySuccess();
}
void ExpectSetConfig(fuchsia_hardware_pwm::wire::PwmConfig config) {
std::unique_ptr<uint8_t[]> mode_config =
std::make_unique<uint8_t[]>(config.mode_config.count());
memcpy(mode_config.get(), config.mode_config.data(), config.mode_config.count());
auto copy = config;
copy.mode_config =
fidl::VectorView<uint8_t>::FromExternal(mode_config.get(), config.mode_config.count());
expect_configs_.push_back(std::move(copy));
mode_config_buffers_.push_back(std::move(mode_config));
}
void ExpectEnable() { expect_enable_ = true; }
void NotImplemented_(const std::string& name, ::fidl::CompleterBase& completer) override {
completer.Close(ZX_ERR_NOT_SUPPORTED);
}
fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> BindServer() {
zx::result endpoints = fidl::CreateEndpoints<fuchsia_hardware_pwm::Pwm>();
EXPECT_TRUE(endpoints.is_ok());
fidl::BindServer(async_get_default_dispatcher(), std::move(endpoints->server), this);
return fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm>(std::move(endpoints->client));
}
void VerifyAndClear() {
ASSERT_EQ(expect_configs_.size(), 0);
ASSERT_EQ(mode_config_buffers_.size(), 0);
ASSERT_FALSE(expect_enable_);
}
private:
std::list<fuchsia_hardware_pwm::wire::PwmConfig> expect_configs_;
std::list<std::unique_ptr<uint8_t[]>> mode_config_buffers_;
bool expect_enable_ = false;
};
class AmlVoltageRegulatorTest : public zxtest::Test {
public:
void SetUp() override { EXPECT_OK(pwm_loop_.StartThread("pwm-servers")); }
void TearDown() override {
// Verify
big_cluster_pwm_.SyncCall(&MockPwmServer::VerifyAndClear);
little_cluster_pwm_.SyncCall(&MockPwmServer::VerifyAndClear);
pwm_loop_.Shutdown();
}
void Create(uint32_t pid) {
aml_pwm::mode_config on = {aml_pwm::Mode::kOn, {}};
fuchsia_hardware_pwm::wire::PwmConfig cfg = {
false, 1250, 43,
fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(&on), sizeof(on))};
switch (pid) {
case 4: { // Sherlock
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectEnable);
cfg.duty_cycle = 43;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
little_cluster_pwm_.SyncCall(&MockPwmServer::ExpectEnable);
cfg.duty_cycle = 3;
little_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
break;
}
case 3: { // Astro
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectEnable);
cfg.duty_cycle = 13;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
break;
}
default:
zxlogf(ERROR, "AmlVoltageRegulatorTest::Create: unsupported SOC PID %u", pid);
return;
}
auto big_cluster_pwm_client = big_cluster_pwm_.SyncCall(&MockPwmServer::BindServer);
auto little_cluster_pwm_client = little_cluster_pwm_.SyncCall(&MockPwmServer::BindServer);
voltage_regulator_ = FakeAmlVoltageRegulator::Create(std::move(big_cluster_pwm_client),
std::move(little_cluster_pwm_client), pid);
ASSERT_TRUE(voltage_regulator_ != nullptr);
}
protected:
std::unique_ptr<FakeAmlVoltageRegulator> voltage_regulator_;
// Mmio Regs and Regions
async::Loop pwm_loop_{&kAsyncLoopConfigNoAttachToCurrentThread};
async_patterns::TestDispatcherBound<MockPwmServer> big_cluster_pwm_{pwm_loop_.dispatcher(),
std::in_place};
async_patterns::TestDispatcherBound<MockPwmServer> little_cluster_pwm_{pwm_loop_.dispatcher(),
std::in_place};
};
TEST_F(AmlVoltageRegulatorTest, SherlockGetVoltageTest) {
Create(4);
uint32_t val = voltage_regulator_->GetVoltage(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 891000);
val = voltage_regulator_->GetVoltage(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain);
EXPECT_EQ(val, 1011000);
}
TEST_F(AmlVoltageRegulatorTest, AstroGetVoltageTest) {
Create(3);
uint32_t val = voltage_regulator_->GetVoltage(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 981000);
}
TEST_F(AmlVoltageRegulatorTest, SherlockSetVoltageTest) {
Create(4);
// SetBigClusterVoltage(761000)
aml_pwm::mode_config on = {aml_pwm::Mode::kOn, {}};
fuchsia_hardware_pwm::wire::PwmConfig cfg = {
false, 1250, 53,
fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(&on), sizeof(on))};
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 63;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 73;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 83;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 86;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
EXPECT_OK(voltage_regulator_->SetVoltage(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain, 761000));
uint32_t val = voltage_regulator_->GetVoltage(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 761000);
// SetLittleClusterVoltage(911000)
cfg.duty_cycle = 13;
little_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 23;
little_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 33;
little_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 36;
little_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
EXPECT_OK(voltage_regulator_->SetVoltage(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain, 911000));
val = voltage_regulator_->GetVoltage(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain);
EXPECT_EQ(val, 911000);
}
TEST_F(AmlVoltageRegulatorTest, AstroSetVoltageTest) {
Create(3);
// SetBigClusterVoltage(861000)
aml_pwm::mode_config on = {aml_pwm::Mode::kOn, {}};
fuchsia_hardware_pwm::wire::PwmConfig cfg = {
false, 1250, 23,
fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(&on), sizeof(on))};
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 33;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 43;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
cfg.duty_cycle = 53;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
EXPECT_OK(voltage_regulator_->SetVoltage(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain, 861000));
uint32_t val = voltage_regulator_->GetVoltage(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 861000);
}
// CPU Frequency and Scaling
class FakeAmlCpuFrequency : public AmlCpuFrequency {
public:
static std::unique_ptr<FakeAmlCpuFrequency> Create(fdf::MmioBuffer hiu_mmio,
fdf::MmioBuffer mock_hiu_internal_mmio,
uint32_t pid) {
const auto& config = (pid == 4 ? sherlock_thermal_config : astro_thermal_config);
fbl::AllocChecker ac;
auto test = fbl::make_unique_checked<FakeAmlCpuFrequency>(
&ac, std::move(hiu_mmio), std::move(mock_hiu_internal_mmio), config, fake_thermal_info);
if (!ac.check()) {
return nullptr;
}
EXPECT_OK(test->Init());
return test;
}
FakeAmlCpuFrequency(fdf::MmioBuffer hiu_mmio, fdf::MmioBuffer hiu_internal_mmio,
const fuchsia_hardware_thermal::wire::ThermalDeviceInfo& thermal_config,
const aml_thermal_info_t& thermal_info)
: AmlCpuFrequency(std::move(hiu_mmio), std::move(hiu_internal_mmio), thermal_config,
thermal_info) {}
};
class AmlCpuFrequencyTest : public zxtest::Test {
public:
void SetUp() override {
fbl::AllocChecker ac;
mock_hiu_mmio_ =
fbl::make_unique_checked<ddk_mock::MockMmioRegRegion>(&ac, sizeof(uint32_t), kRegSize);
if (!ac.check()) {
zxlogf(ERROR, "AmlCpuFrequencyTest::SetUp: mock_hiu_mmio_ alloc failed");
return;
}
hiu_internal_mmio_ = fdf_testing::CreateMmioBuffer(kRegSize * sizeof(uint32_t));
if (!ac.check()) {
zxlogf(ERROR, "AmlCpuFrequencyTest::SetUp: hiu_internal_mmio_ alloc failed");
return;
}
mock_hiu_internal_mmio_ = hiu_internal_mmio_->View(0);
InitHiuInternalMmio();
}
void TearDown() override {
// Verify
mock_hiu_mmio_->VerifyAll();
}
void Create(uint32_t pid) {
switch (pid) {
case 4: { // Sherlock
// Big
(*mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectRead(0x00000000); // WaitForBusyCpu
(*mock_hiu_mmio_)[520]
.ExpectRead(0x00000000)
.ExpectWrite(0x00010400); // Dynamic mux 0 is in use
// Little
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000); // WaitForBusyCpu
(*mock_hiu_mmio_)[412]
.ExpectRead(0x00000000)
.ExpectWrite(0x00010400); // Dynamic mux 0 is in use
break;
}
case 3: { // Astro
// Big
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000); // WaitForBusyCpu
(*mock_hiu_mmio_)[412]
.ExpectRead(0x00000000)
.ExpectWrite(0x00010400); // Dynamic mux 0 is in use
break;
}
default:
zxlogf(ERROR, "AmlCpuFrequencyTest::Create: unsupported SOC PID %u", pid);
return;
}
fdf::MmioBuffer hiu_mmio(mock_hiu_mmio_->GetMmioBuffer());
cpufreq_scaling_ =
FakeAmlCpuFrequency::Create(std::move(hiu_mmio), mock_hiu_internal_mmio_->View(0), pid);
ASSERT_TRUE(cpufreq_scaling_ != nullptr);
}
void InitHiuInternalMmio() {
for (uint32_t i = 0; i < hiu_internal_mmio_->get_size(); i += sizeof(uint32_t)) {
hiu_internal_mmio_->Write32((1 << 31), i);
}
}
protected:
std::unique_ptr<FakeAmlCpuFrequency> cpufreq_scaling_;
// Mmio Regs and Regions
std::optional<fdf::MmioBuffer> hiu_internal_mmio_;
std::unique_ptr<ddk_mock::MockMmioRegRegion> mock_hiu_mmio_;
std::optional<fdf::MmioBuffer> mock_hiu_internal_mmio_;
};
TEST_F(AmlCpuFrequencyTest, SherlockGetFrequencyTest) {
Create(4);
InitHiuInternalMmio();
uint32_t val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 1000000000);
InitHiuInternalMmio();
val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain);
EXPECT_EQ(val, 1000000000);
}
TEST_F(AmlCpuFrequencyTest, AstroGetFrequencyTest) {
Create(3);
InitHiuInternalMmio();
uint32_t val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 1000000000);
}
TEST_F(AmlCpuFrequencyTest, SherlockSetFrequencyTest0) {
Create(4);
// Big
(*mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectWrite(0x00350400);
InitHiuInternalMmio();
EXPECT_OK(cpufreq_scaling_->SetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain, 250000000));
InitHiuInternalMmio();
uint32_t val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 250000000);
// Little
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00350400);
InitHiuInternalMmio();
EXPECT_OK(cpufreq_scaling_->SetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain, 250000000));
InitHiuInternalMmio();
val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain);
EXPECT_EQ(val, 250000000);
}
TEST_F(AmlCpuFrequencyTest, SherlockSetFrequencyTest1) {
Create(4);
// Big
(*mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectWrite(0x00000800);
InitHiuInternalMmio();
EXPECT_OK(cpufreq_scaling_->SetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain, 1536000000));
InitHiuInternalMmio();
uint32_t val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 1536000000);
(*mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectWrite(0x00010400);
(*mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectWrite(0x00000800);
InitHiuInternalMmio();
EXPECT_OK(cpufreq_scaling_->SetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain, 1494000000));
InitHiuInternalMmio();
val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 1494000000);
// Little
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00000800);
InitHiuInternalMmio();
EXPECT_OK(cpufreq_scaling_->SetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain, 1200000000));
InitHiuInternalMmio();
val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain);
EXPECT_EQ(val, 1200000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00010400);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00000800);
InitHiuInternalMmio();
EXPECT_OK(cpufreq_scaling_->SetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain, 1398000000));
InitHiuInternalMmio();
val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain);
EXPECT_EQ(val, 1398000000);
}
TEST_F(AmlCpuFrequencyTest, AstroSetFrequencyTest0) {
Create(3);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00350400);
InitHiuInternalMmio();
EXPECT_OK(cpufreq_scaling_->SetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain, 250000000));
InitHiuInternalMmio();
uint32_t val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 250000000);
}
TEST_F(AmlCpuFrequencyTest, AstroSetFrequencyTest1) {
Create(3);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00000800);
InitHiuInternalMmio();
EXPECT_OK(cpufreq_scaling_->SetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain, 1536000000));
InitHiuInternalMmio();
uint32_t val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 1536000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x10400);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00000800);
InitHiuInternalMmio();
EXPECT_OK(cpufreq_scaling_->SetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain, 1494000000));
InitHiuInternalMmio();
val = cpufreq_scaling_->GetFrequency(
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain);
EXPECT_EQ(val, 1494000000);
}
// Thermal
class FakeAmlThermal : public AmlThermal {
public:
static std::unique_ptr<FakeAmlThermal> Create(
fdf::MmioBuffer tsensor_pll_mmio, fdf::MmioBuffer tsensor_trim_mmio,
fdf::MmioBuffer tsensor_hiu_mmio,
fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> big_cluster_pwm,
fidl::WireSyncClient<fuchsia_hardware_pwm::Pwm> little_cluster_pwm,
fdf::MmioBuffer cpufreq_scaling_hiu_mmio,
fdf::MmioBuffer cpufreq_scaling_mock_hiu_internal_mmio, uint32_t pid) {
fbl::AllocChecker ac;
const auto& config = (pid == 4 ? sherlock_thermal_config
: (pid == 5 ? nelson_thermal_config : astro_thermal_config));
const auto& info = (pid == 5 ? nelson_thermal_info : fake_thermal_info);
// Temperature Sensor
auto tsensor = fbl::make_unique_checked<AmlTSensor>(&ac, std::move(tsensor_pll_mmio),
std::move(tsensor_trim_mmio),
std::move(tsensor_hiu_mmio));
if (!ac.check()) {
return nullptr;
}
EXPECT_OK(tsensor->InitSensor(config));
// Voltage Regulator
zx_status_t status = ZX_OK;
auto voltage_regulator = fbl::make_unique_checked<AmlVoltageRegulator>(&ac);
if (!ac.check() || (status != ZX_OK)) {
return nullptr;
}
EXPECT_OK(voltage_regulator->Init(std::move(big_cluster_pwm), std::move(little_cluster_pwm),
config, &info));
// CPU Frequency and Scaling
auto cpufreq_scaling = fbl::make_unique_checked<AmlCpuFrequency>(
&ac, std::move(cpufreq_scaling_hiu_mmio), std::move(cpufreq_scaling_mock_hiu_internal_mmio),
config, fake_thermal_info);
if (!ac.check()) {
return nullptr;
}
EXPECT_OK(cpufreq_scaling->Init());
auto test = fbl::make_unique_checked<FakeAmlThermal>(
&ac, std::move(tsensor), std::move(voltage_regulator), std::move(cpufreq_scaling), config);
if (!ac.check()) {
return nullptr;
}
// SetTarget
EXPECT_OK(test->SetTarget(config.trip_point_info[0].big_cluster_dvfs_opp,
fuchsia_hardware_thermal::wire::PowerDomain::kBigClusterPowerDomain));
if (config.big_little) {
EXPECT_OK(
test->SetTarget(config.trip_point_info[0].little_cluster_dvfs_opp,
fuchsia_hardware_thermal::wire::PowerDomain::kLittleClusterPowerDomain));
}
return test;
}
void DdkRelease() { delete this; }
FakeAmlThermal(std::unique_ptr<thermal::AmlTSensor> tsensor,
std::unique_ptr<thermal::AmlVoltageRegulator> voltage_regulator,
std::unique_ptr<thermal::AmlCpuFrequency> cpufreq_scaling,
const fuchsia_hardware_thermal::wire::ThermalDeviceInfo& thermal_config)
: AmlThermal(nullptr, std::move(tsensor), std::move(voltage_regulator),
std::move(cpufreq_scaling), thermal_config) {}
};
class AmlThermalTest : public zxtest::Test {
public:
void SetUp() override {
fbl::AllocChecker ac;
// Temperature Sensor
tsensor_mock_pll_mmio_ =
fbl::make_unique_checked<ddk_mock::MockMmioRegRegion>(&ac, sizeof(uint32_t), kRegSize);
if (!ac.check()) {
zxlogf(ERROR, "AmlThermalTest::SetUp: mock_pll_mmio_ alloc failed");
return;
}
tsensor_mock_trim_mmio_ =
fbl::make_unique_checked<ddk_mock::MockMmioRegRegion>(&ac, sizeof(uint32_t), kRegSize);
if (!ac.check()) {
zxlogf(ERROR, "AmlThermalTest::SetUp: mock_trim_mmio_ alloc failed");
return;
}
tsensor_mock_hiu_mmio_ =
fbl::make_unique_checked<ddk_mock::MockMmioRegRegion>(&ac, sizeof(uint32_t), kRegSize);
if (!ac.check()) {
zxlogf(ERROR, "AmlThermalTest::SetUp: mock_hiu_mmio_ alloc failed");
return;
}
(*tsensor_mock_trim_mmio_)[0].ExpectRead(0x00000000); // trim_info_
(*tsensor_mock_hiu_mmio_)[(0x64 << 2)].ExpectWrite(0x130U); // set clock
(*tsensor_mock_pll_mmio_)[(0x1 << 2)].ExpectRead(0x00000000).ExpectWrite(0x63B); // sensor ctl
(*tsensor_mock_pll_mmio_)[(0x1 << 2)]
.ExpectRead(0x00000000) // clear IRQs
.ExpectWrite(0x00FF0000);
(*tsensor_mock_pll_mmio_)[(0x1 << 2)]
.ExpectRead(0x00000000) // clear IRQs
.ExpectWrite(0x00000000);
(*tsensor_mock_pll_mmio_)[(0x1 << 2)]
.ExpectRead(0x00000000) // enable IRQs
.ExpectWrite(0x0F008000);
// CPU Frequency and Scaling
cpufreq_scaling_mock_hiu_mmio_ =
fbl::make_unique_checked<ddk_mock::MockMmioRegRegion>(&ac, sizeof(uint32_t), kRegSize);
if (!ac.check()) {
zxlogf(ERROR, "AmlThermalTest::SetUp: cpufreq_scaling_mock_hiu_mmio_ alloc failed");
return;
}
cpufreq_scaling_hiu_internal_mmio_ = fdf_testing::CreateMmioBuffer(kRegSize * sizeof(uint32_t));
cpufreq_scaling_mock_hiu_internal_mmio_ = cpufreq_scaling_hiu_internal_mmio_->View(0);
InitHiuInternalMmio();
EXPECT_OK(pwm_loop_.StartThread("pwm-servers"));
}
void TearDown() override {
// Verify
tsensor_mock_pll_mmio_->VerifyAll();
tsensor_mock_trim_mmio_->VerifyAll();
tsensor_mock_hiu_mmio_->VerifyAll();
big_cluster_pwm_.SyncCall(&MockPwmServer::VerifyAndClear);
little_cluster_pwm_.SyncCall(&MockPwmServer::VerifyAndClear);
cpufreq_scaling_mock_hiu_mmio_->VerifyAll();
pwm_loop_.Shutdown();
// Tear down
thermal_device_ = nullptr;
}
void Create(uint32_t pid) {
ddk_mock::MockMmioRegRegion& tsensor_mmio = *tsensor_mock_pll_mmio_;
aml_pwm::mode_config on = {aml_pwm::Mode::kOn, {}};
fuchsia_hardware_pwm::wire::PwmConfig cfg = {
false, 1250, 43,
fidl::VectorView<uint8_t>::FromExternal(reinterpret_cast<uint8_t*>(&on), sizeof(on))};
switch (pid) {
case 4: { // Sherlock
// Voltage Regulator
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectEnable);
cfg.duty_cycle = 43;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
little_cluster_pwm_.SyncCall(&MockPwmServer::ExpectEnable);
cfg.duty_cycle = 3;
little_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
// CPU Frequency and Scaling
// Big
(*cpufreq_scaling_mock_hiu_mmio_)[520]
.ExpectRead(0x00000000)
.ExpectRead(0x00000000); // WaitForBusyCpu
(*cpufreq_scaling_mock_hiu_mmio_)[520]
.ExpectRead(0x00000000)
.ExpectWrite(0x00010400); // Dynamic mux 0 is in use
// Little
(*cpufreq_scaling_mock_hiu_mmio_)[412]
.ExpectRead(0x00000000)
.ExpectRead(0x00000000); // WaitForBusyCpu
(*cpufreq_scaling_mock_hiu_mmio_)[412]
.ExpectRead(0x00000000)
.ExpectWrite(0x00010400); // Dynamic mux 0 is in use
// SetTarget
(*cpufreq_scaling_mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*cpufreq_scaling_mock_hiu_mmio_)[520].ExpectRead(0x00000000).ExpectWrite(0x00000800);
(*cpufreq_scaling_mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*cpufreq_scaling_mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00000800);
// InitTripPoints
tsensor_mmio[(0x5 << 2)].ExpectWrite(0x00027E); // set thresholds 4, rise
tsensor_mmio[(0x7 << 2)].ExpectWrite(0x000272); // set thresholds 4, fall
tsensor_mmio[(0x5 << 2)].ExpectWrite(0x27227E); // set thresholds 3, rise
tsensor_mmio[(0x7 << 2)].ExpectWrite(0x268272); // set thresholds 3, fall
tsensor_mmio[(0x4 << 2)].ExpectWrite(0x00025A); // set thresholds 2, rise
tsensor_mmio[(0x6 << 2)].ExpectWrite(0x000251); // set thresholds 2, fall
tsensor_mmio[(0x4 << 2)].ExpectWrite(0x25025A); // set thresholds 1, rise
tsensor_mmio[(0x6 << 2)].ExpectWrite(0x245251); // set thresholds 1, fall
break;
}
case 3: { // Astro
// Voltage Regulator
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectEnable);
cfg.duty_cycle = 13;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
// CPU Frequency and Scaling
(*cpufreq_scaling_mock_hiu_mmio_)[412]
.ExpectRead(0x00000000)
.ExpectRead(0x00000000); // WaitForBusyCpu
(*cpufreq_scaling_mock_hiu_mmio_)[412]
.ExpectRead(0x00000000)
.ExpectWrite(0x00010400); // Dynamic mux 0 is in use
// SetTarget
(*cpufreq_scaling_mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*cpufreq_scaling_mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00000800);
// InitTripPoints
tsensor_mmio[(0x5 << 2)].ExpectWrite(0x000272); // set thresholds 4, rise
tsensor_mmio[(0x7 << 2)].ExpectWrite(0x000268); // set thresholds 4, fall
tsensor_mmio[(0x5 << 2)].ExpectWrite(0x266272); // set thresholds 3, rise
tsensor_mmio[(0x7 << 2)].ExpectWrite(0x25c268); // set thresholds 3, fall
tsensor_mmio[(0x4 << 2)].ExpectWrite(0x00025A); // set thresholds 2, rise
tsensor_mmio[(0x6 << 2)].ExpectWrite(0x000251); // set thresholds 2, fall
tsensor_mmio[(0x4 << 2)].ExpectWrite(0x25025A); // set thresholds 1, rise
tsensor_mmio[(0x6 << 2)].ExpectWrite(0x245251); // set thresholds 1, fall
break;
}
case 5: { // Nelson
// Voltage Regulator
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectEnable);
cfg.period_ns = 1500;
cfg.duty_cycle = 23;
big_cluster_pwm_.SyncCall(&MockPwmServer::ExpectSetConfig, cfg);
// CPU Frequency and Scaling
(*cpufreq_scaling_mock_hiu_mmio_)[412]
.ExpectRead(0x00000000)
.ExpectRead(0x00000000); // WaitForBusyCpu
(*cpufreq_scaling_mock_hiu_mmio_)[412]
.ExpectRead(0x00000000)
.ExpectWrite(0x00010400); // Dynamic mux 0 is in use
// SetTarget
(*cpufreq_scaling_mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectRead(0x00000000);
(*cpufreq_scaling_mock_hiu_mmio_)[412].ExpectRead(0x00000000).ExpectWrite(0x00000800);
// InitTripPoints
tsensor_mmio[(0x5 << 2)].ExpectWrite(0x00029D); // set thresholds 4, rise
tsensor_mmio[(0x7 << 2)].ExpectWrite(0x000299); // set thresholds 4, fall
tsensor_mmio[(0x5 << 2)].ExpectWrite(0x26329D); // set thresholds 3, rise
tsensor_mmio[(0x7 << 2)].ExpectWrite(0x24A299); // set thresholds 3, fall
tsensor_mmio[(0x4 << 2)].ExpectWrite(0x000257); // set thresholds 2, rise
tsensor_mmio[(0x6 << 2)].ExpectWrite(0x00023F); // set thresholds 2, fall
tsensor_mmio[(0x4 << 2)].ExpectWrite(0x236257); // set thresholds 1, rise
tsensor_mmio[(0x6 << 2)].ExpectWrite(0x21F23F); // set thresholds 1, fall
break;
}
default:
zxlogf(ERROR, "AmlThermalTest::Create: unsupported SOC PID %u", pid);
return;
}
fdf::MmioBuffer tsensor_pll_mmio(tsensor_mock_pll_mmio_->GetMmioBuffer());
fdf::MmioBuffer tsensor_trim_mmio(tsensor_mock_trim_mmio_->GetMmioBuffer());
fdf::MmioBuffer tsensor_hiu_mmio(tsensor_mock_hiu_mmio_->GetMmioBuffer());
auto big_cluster_pwm_client = big_cluster_pwm_.SyncCall(&MockPwmServer::BindServer);
auto little_cluster_pwm_client = little_cluster_pwm_.SyncCall(&MockPwmServer::BindServer);
fdf::MmioBuffer cpufreq_scaling_hiu_mmio(cpufreq_scaling_mock_hiu_mmio_->GetMmioBuffer());
thermal_device_ = FakeAmlThermal::Create(
std::move(tsensor_pll_mmio), std::move(tsensor_trim_mmio), std::move(tsensor_hiu_mmio),
std::move(big_cluster_pwm_client), std::move(little_cluster_pwm_client),
std::move(cpufreq_scaling_hiu_mmio), cpufreq_scaling_mock_hiu_internal_mmio_->View(0), pid);
ASSERT_TRUE(thermal_device_ != nullptr);
}
void InitHiuInternalMmio() {
for (uint32_t i = 0; i < kRegSize; i += sizeof(uint32_t)) {
cpufreq_scaling_hiu_internal_mmio_->Write32((1 << 31), i);
}
}
protected:
std::unique_ptr<FakeAmlThermal> thermal_device_;
// Temperature Sensor
std::unique_ptr<ddk_mock::MockMmioRegRegion> tsensor_mock_pll_mmio_;
std::unique_ptr<ddk_mock::MockMmioRegRegion> tsensor_mock_trim_mmio_;
std::unique_ptr<ddk_mock::MockMmioRegRegion> tsensor_mock_hiu_mmio_;
// Voltage Regulator
async::Loop pwm_loop_{&kAsyncLoopConfigNoAttachToCurrentThread};
async_patterns::TestDispatcherBound<MockPwmServer> big_cluster_pwm_{pwm_loop_.dispatcher(),
std::in_place};
async_patterns::TestDispatcherBound<MockPwmServer> little_cluster_pwm_{pwm_loop_.dispatcher(),
std::in_place};
// CPU Frequency and Scaling
std::optional<fdf::MmioBuffer> cpufreq_scaling_hiu_internal_mmio_;
std::unique_ptr<ddk_mock::MockMmioRegRegion> cpufreq_scaling_mock_hiu_mmio_;
std::optional<fdf::MmioBuffer> cpufreq_scaling_mock_hiu_internal_mmio_;
};
TEST_F(AmlThermalTest, SherlockInitTest) {
Create(4);
ASSERT_TRUE(true);
}
TEST_F(AmlThermalTest, AstroInitTest) {
Create(3);
ASSERT_TRUE(true);
}
TEST_F(AmlThermalTest, NelsonInitTest) { Create(5); }
} // namespace thermal