| // 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-clk.h" |
| |
| #include <lib/ddk/platform-defs.h> |
| #include <lib/mmio-ptr/fake.h> |
| |
| #include <soc/aml-meson/aml-clk-common.h> |
| #include <soc/aml-meson/axg-clk.h> |
| #include <soc/aml-meson/g12a-clk.h> |
| #include <soc/aml-meson/sm1-clk.h> |
| #include <soc/aml-s905d2/s905d2-hw.h> |
| #include <soc/aml-s905d3/s905d3-hw.h> |
| #include <soc/aml-s912/s912-hw.h> |
| #include <zxtest/zxtest.h> |
| |
| #include "aml-axg-blocks.h" |
| #include "aml-g12a-blocks.h" |
| #include "aml-g12b-blocks.h" |
| #include "aml-sm1-blocks.h" |
| |
| namespace amlogic_clock { |
| |
| namespace { |
| constexpr uint64_t kilohertz(uint64_t hz) { return hz * 1000; } |
| constexpr uint64_t megahertz(uint64_t hz) { return kilohertz(hz) * 1000; } |
| constexpr uint64_t gigahertz(uint64_t hz) { return megahertz(hz) * 1000; } |
| |
| constexpr uint32_t kCpuClkSupportedFrequencies[] = { |
| 100'000'000, 250'000'000, 500'000'000, 667'000'000, 1'000'000'000, 1'200'000'000, |
| 1'398'000'000, 1'512'000'000, 1'608'000'000, 1'704'000'000, 1'896'000'000, |
| }; |
| |
| } // namespace |
| |
| class AmlClockTest : public AmlClock { |
| public: |
| AmlClockTest(mmio_buffer_t mmio_buffer, mmio_buffer_t dosbus_buffer, uint32_t did) |
| : AmlClock(nullptr, ddk::MmioBuffer(mmio_buffer), ddk::MmioBuffer(dosbus_buffer), |
| std::nullopt, did) {} |
| ~AmlClockTest() = default; |
| }; |
| |
| std::tuple<std::unique_ptr<uint8_t[]>, mmio_buffer_t> MakeDosbusMmio() { |
| auto value = std::make_unique<uint8_t[]>(S912_DOS_LENGTH); |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(value.get()); |
| buffer.offset = 0; |
| buffer.size = S912_DOS_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| return std::make_tuple(std::move(value), buffer); |
| } |
| |
| TEST(ClkTestAml, AxgEnableDisableAll) { |
| auto actual = std::make_unique<uint8_t[]>(S912_HIU_LENGTH); |
| auto expected = std::make_unique<uint8_t[]>(S912_HIU_LENGTH); |
| |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(actual.get()); |
| buffer.offset = 0; |
| buffer.size = S912_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_AXG_CLK); |
| |
| // Initialization sets a bunch of registers that we don't care about, so we |
| // can reset the array to a clean slate. |
| memset(actual.get(), 0, S912_HIU_LENGTH); |
| memset(expected.get(), 0, S912_HIU_LENGTH); |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S912_HIU_LENGTH), 0); |
| |
| constexpr uint16_t kClkStart = 0; |
| constexpr uint16_t kClkEnd = static_cast<uint16_t>(axg_clk::CLK_AXG_COUNT); |
| |
| for (uint16_t i = kClkStart; i < kClkEnd; ++i) { |
| if (axg_clk_gates[i].register_set != kMesonRegisterSetHiu) |
| continue; |
| const uint32_t reg = axg_clk_gates[i].reg; |
| const uint32_t bit = (1u << axg_clk_gates[i].bit); |
| uint32_t* ptr = reinterpret_cast<uint32_t*>(&expected[reg]); |
| (*ptr) |= bit; |
| |
| const uint32_t clk_i = aml_clk_common::AmlClkId(i, aml_clk_common::aml_clk_type::kMesonGate); |
| zx_status_t st = clk.ClockImplEnable(clk_i); |
| EXPECT_OK(st); |
| } |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S912_HIU_LENGTH), 0); |
| |
| for (uint16_t i = kClkStart; i < kClkEnd; ++i) { |
| if (axg_clk_gates[i].register_set != kMesonRegisterSetHiu) |
| continue; |
| const uint32_t reg = axg_clk_gates[i].reg; |
| const uint32_t bit = (1u << axg_clk_gates[i].bit); |
| uint32_t* ptr = reinterpret_cast<uint32_t*>(&expected[reg]); |
| (*ptr) &= ~(bit); |
| |
| const uint32_t clk_i = aml_clk_common::AmlClkId(i, aml_clk_common::aml_clk_type::kMesonGate); |
| zx_status_t st = clk.ClockImplDisable(clk_i); |
| EXPECT_OK(st); |
| } |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S912_HIU_LENGTH), 0); |
| } |
| |
| TEST(ClkTestAml, G12aEnableDisableAll) { |
| auto actual = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| auto expected = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(actual.get()); |
| buffer.offset = 0; |
| buffer.size = S905D2_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_G12A_CLK); |
| |
| // Initialization sets a bunch of registers that we don't care about, so we |
| // can reset the array to a clean slate. |
| memset(actual.get(), 0, S905D2_HIU_LENGTH); |
| memset(expected.get(), 0, S905D2_HIU_LENGTH); |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S905D2_HIU_LENGTH), 0); |
| |
| constexpr uint16_t kClkStart = 0; |
| constexpr uint16_t kClkEnd = static_cast<uint16_t>(g12a_clk::CLK_G12A_COUNT); |
| |
| for (uint16_t i = kClkStart; i < kClkEnd; ++i) { |
| if (g12a_clk_gates[i].register_set != kMesonRegisterSetHiu) |
| continue; |
| const uint32_t reg = g12a_clk_gates[i].reg; |
| const uint32_t bit = (1u << g12a_clk_gates[i].bit); |
| uint32_t* ptr = reinterpret_cast<uint32_t*>(&expected[reg]); |
| (*ptr) |= bit; |
| |
| const uint32_t clk_i = aml_clk_common::AmlClkId(i, aml_clk_common::aml_clk_type::kMesonGate); |
| zx_status_t st = clk.ClockImplEnable(clk_i); |
| EXPECT_OK(st); |
| } |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S905D2_HIU_LENGTH), 0); |
| |
| for (uint16_t i = kClkStart; i < kClkEnd; ++i) { |
| if (g12a_clk_gates[i].register_set != kMesonRegisterSetHiu) |
| continue; |
| const uint32_t reg = g12a_clk_gates[i].reg; |
| const uint32_t bit = (1u << g12a_clk_gates[i].bit); |
| uint32_t* ptr = reinterpret_cast<uint32_t*>(&expected[reg]); |
| (*ptr) &= ~(bit); |
| |
| const uint32_t clk_i = aml_clk_common::AmlClkId(i, aml_clk_common::aml_clk_type::kMesonGate); |
| zx_status_t st = clk.ClockImplDisable(clk_i); |
| EXPECT_OK(st); |
| } |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S905D2_HIU_LENGTH), 0); |
| } |
| |
| TEST(ClkTestAml, Sm1EnableDisableAll) { |
| auto actual = std::make_unique<uint8_t[]>(S905D3_HIU_LENGTH); |
| auto expected = std::make_unique<uint8_t[]>(S905D3_HIU_LENGTH); |
| |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(actual.get()); |
| buffer.offset = 0; |
| buffer.size = S905D3_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_SM1_CLK); |
| |
| // Initialization sets a bunch of registers that we don't care about, so we |
| // can reset the array to a clean slate. |
| memset(actual.get(), 0, S905D3_HIU_LENGTH); |
| memset(expected.get(), 0, S905D3_HIU_LENGTH); |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S905D3_HIU_LENGTH), 0); |
| |
| constexpr uint16_t kClkStart = 0; |
| constexpr uint16_t kClkEnd = static_cast<uint16_t>(sm1_clk::CLK_SM1_GATE_COUNT); |
| |
| for (uint16_t i = kClkStart; i < kClkEnd; ++i) { |
| if (sm1_clk_gates[i].register_set != kMesonRegisterSetHiu) |
| continue; |
| const uint32_t reg = sm1_clk_gates[i].reg; |
| const uint32_t bit = (1u << sm1_clk_gates[i].bit); |
| uint32_t* ptr = reinterpret_cast<uint32_t*>(&expected[reg]); |
| (*ptr) |= bit; |
| |
| const uint32_t clk_i = aml_clk_common::AmlClkId(i, aml_clk_common::aml_clk_type::kMesonGate); |
| zx_status_t st = clk.ClockImplEnable(clk_i); |
| EXPECT_OK(st); |
| } |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S905D3_HIU_LENGTH), 0); |
| |
| for (uint16_t i = kClkStart; i < kClkEnd; ++i) { |
| if (sm1_clk_gates[i].register_set != kMesonRegisterSetHiu) |
| continue; |
| const uint32_t reg = sm1_clk_gates[i].reg; |
| const uint32_t bit = (1u << sm1_clk_gates[i].bit); |
| uint32_t* ptr = reinterpret_cast<uint32_t*>(&expected[reg]); |
| (*ptr) &= ~(bit); |
| |
| const uint32_t clk_i = aml_clk_common::AmlClkId(i, aml_clk_common::aml_clk_type::kMesonGate); |
| zx_status_t st = clk.ClockImplDisable(clk_i); |
| EXPECT_OK(st); |
| } |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S905D3_HIU_LENGTH), 0); |
| } |
| |
| TEST(ClkTestAml, G12aEnableDos) { |
| auto actual = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(actual.get()); |
| buffer.offset = 0; |
| buffer.size = S905D2_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_G12A_CLK); |
| memset(dos_data.get(), 0, S905D2_DOS_LENGTH); |
| |
| zx_status_t st = clk.ClockImplEnable(g12a_clk::CLK_DOS_GCLK_VDEC); |
| EXPECT_OK(st); |
| |
| EXPECT_EQ(0x3ff, reinterpret_cast<uint32_t*>(dos_data.get())[0x3f01]); |
| } |
| |
| static void TestPlls(const uint32_t did) { |
| auto ignored = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(ignored.get()); |
| buffer.offset = 0; |
| buffer.size = S905D2_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| AmlClockTest clk(buffer, dos_buffer, did); |
| |
| constexpr uint16_t kPllStart = 0; |
| constexpr uint16_t kPllEnd = HIU_PLL_COUNT; |
| |
| for (uint16_t i = kPllStart; i < kPllEnd; i++) { |
| const uint32_t clkid = aml_clk_common::AmlClkId(i, aml_clk_common::aml_clk_type::kMesonPll); |
| |
| zx_status_t st; |
| uint64_t best_supported_rate; |
| constexpr uint64_t kMaxRateHz = gigahertz(1); |
| st = clk.ClockImplQuerySupportedRate(clkid, kMaxRateHz, &best_supported_rate); |
| EXPECT_OK(st); |
| |
| EXPECT_LE(best_supported_rate, kMaxRateHz); |
| |
| st = clk.ClockImplSetRate(clkid, best_supported_rate); |
| EXPECT_OK(st); |
| } |
| } |
| |
| TEST(ClkTestAml, G12aSetRate) { TestPlls(PDEV_DID_AMLOGIC_G12A_CLK); } |
| |
| TEST(ClkTestAml, G12bSetRate) { TestPlls(PDEV_DID_AMLOGIC_G12B_CLK); } |
| |
| TEST(ClkTestAml, Sm1MuxRo) { |
| auto regs = std::make_unique<uint8_t[]>(S905D3_HIU_LENGTH); |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(regs.get()); |
| buffer.offset = 0; |
| buffer.size = S905D3_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_SM1_CLK); |
| |
| // Ensure that SetInput fails for RO muxes. |
| zx_status_t st = clk.ClockImplSetInput(sm1_clk::CLK_MPEG_CLK_SEL, 0); |
| EXPECT_NOT_OK(st); |
| |
| // Make sure we can read the number of parents. |
| uint32_t out_num_inputs = 0; |
| st = clk.ClockImplGetNumInputs(sm1_clk::CLK_MPEG_CLK_SEL, &out_num_inputs); |
| EXPECT_OK(st); |
| EXPECT_GT(out_num_inputs, 0); |
| |
| // Make sure that we can read the current parent of the mux. |
| uint32_t out_input = UINT32_MAX; |
| st = clk.ClockImplGetInput(sm1_clk::CLK_MPEG_CLK_SEL, &out_input); |
| EXPECT_OK(st); |
| EXPECT_NE(out_input, UINT32_MAX); |
| |
| // Also ensure that we didn't whack any registers for a read-only mux. |
| for (size_t i = 0; i < S905D3_HIU_LENGTH; i++) { |
| EXPECT_EQ(0, regs.get()[i]); |
| } |
| } |
| |
| TEST(ClkTestAml, Sm1Mux) { |
| constexpr uint32_t kTestMux = sm1_clk::CLK_CTS_VIPNANOQ_AXI_CLK_MUX; |
| |
| constexpr uint16_t kTestMuxIdx = aml_clk_common::AmlClkIndex(kTestMux); |
| |
| const meson_clk_mux_t& test_mux = sm1_muxes[kTestMuxIdx]; |
| |
| auto regs = std::make_unique<uint8_t[]>(S905D3_HIU_LENGTH); |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(regs.get()); |
| buffer.offset = 0; |
| buffer.size = S905D3_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_SM1_CLK); |
| |
| const uint32_t newParentIdx = test_mux.n_inputs - 1; |
| zx_status_t st = clk.ClockImplSetInput(kTestMux, newParentIdx); |
| EXPECT_OK(st); |
| |
| const uint32_t actual_regval = reinterpret_cast<uint32_t*>(regs.get())[test_mux.reg >> 2]; |
| const uint32_t expected_regval = (newParentIdx & test_mux.mask) << test_mux.shift; |
| EXPECT_EQ(expected_regval, actual_regval); |
| |
| // Make sure we can read the number of parents. |
| uint32_t out_num_inputs = 0; |
| st = clk.ClockImplGetNumInputs(kTestMux, &out_num_inputs); |
| EXPECT_OK(st); |
| EXPECT_EQ(out_num_inputs, test_mux.n_inputs); |
| |
| // Make sure that we can read the current parent of the mux. |
| uint32_t out_input = UINT32_MAX; |
| st = clk.ClockImplGetInput(kTestMux, &out_input); |
| EXPECT_OK(st); |
| EXPECT_EQ(out_input, newParentIdx); |
| } |
| |
| TEST(ClkTestAml, TestCpuClkSetRate) { |
| constexpr uint32_t kTestCpuClk = g12a_clk::CLK_SYS_CPU_CLK; |
| |
| auto regs = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(regs.get()); |
| buffer.offset = 0; |
| buffer.size = S905D2_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_G12A_CLK); |
| |
| zx_status_t st; |
| for (size_t i = 0; i < countof(kCpuClkSupportedFrequencies); i++) { |
| st = clk.ClockImplSetRate(kTestCpuClk, kCpuClkSupportedFrequencies[i]); |
| EXPECT_OK(st); |
| |
| st = clk.ClockImplSetRate(kTestCpuClk, kCpuClkSupportedFrequencies[i] + 1); |
| EXPECT_NOT_OK(st); |
| } |
| } |
| |
| TEST(ClkTestAml, TestCpuClkQuerySupportedRates) { |
| constexpr uint32_t kTestCpuClk = g12a_clk::CLK_SYS_CPU_CLK; |
| constexpr uint32_t kJustOver1GHz = gigahertz(1) + 1; |
| |
| auto regs = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(regs.get()); |
| buffer.offset = 0; |
| buffer.size = S905D2_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_G12A_CLK); |
| |
| uint64_t rate; |
| zx_status_t st = clk.ClockImplQuerySupportedRate(kTestCpuClk, kJustOver1GHz, &rate); |
| EXPECT_OK(st); |
| EXPECT_EQ(rate, gigahertz(1)); |
| } |
| |
| TEST(ClkTestAml, TestCpuClkGetRate) { |
| constexpr uint32_t kTestCpuClk = g12a_clk::CLK_SYS_CPU_CLK; |
| constexpr uint32_t kOneGHz = gigahertz(1); |
| |
| auto regs = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(regs.get()); |
| buffer.offset = 0; |
| buffer.size = S905D2_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_G12A_CLK); |
| zx_status_t st; |
| |
| st = clk.ClockImplSetRate(kTestCpuClk, kOneGHz); |
| EXPECT_OK(st); |
| |
| uint64_t rate; |
| st = clk.ClockImplGetRate(kTestCpuClk, &rate); |
| EXPECT_OK(st); |
| EXPECT_EQ(rate, kOneGHz); |
| } |
| |
| TEST(ClkTestAml, TestCpuClkG12b) { |
| constexpr uint32_t kTestCpuBigClk = g12b_clk::CLK_SYS_CPU_BIG_CLK; |
| constexpr uint32_t kTestCpuLittleClk = g12b_clk::CLK_SYS_CPU_LITTLE_CLK; |
| constexpr uint32_t kBigClockTestFreq = gigahertz(1); |
| constexpr uint32_t kLittleClockTestFreq = megahertz(1800); |
| |
| auto regs = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(regs.get()); |
| buffer.offset = 0; |
| buffer.size = S905D2_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_G12B_CLK); |
| zx_status_t st; |
| |
| st = clk.ClockImplSetRate(kTestCpuBigClk, kBigClockTestFreq); |
| EXPECT_OK(st); |
| |
| uint64_t rate; |
| st = clk.ClockImplGetRate(kTestCpuBigClk, &rate); |
| EXPECT_OK(st); |
| EXPECT_EQ(rate, kBigClockTestFreq); |
| |
| st = clk.ClockImplSetRate(kTestCpuLittleClk, kLittleClockTestFreq); |
| EXPECT_OK(st); |
| |
| st = clk.ClockImplGetRate(kTestCpuLittleClk, &rate); |
| EXPECT_OK(st); |
| EXPECT_EQ(rate, kLittleClockTestFreq); |
| } |
| |
| TEST(ClkTestAml, DisableRefZero) { |
| // Attempts to disable a clock that has never been enabled. |
| // Confirm that this is fatal. |
| auto actual = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| auto expected = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(actual.get()); |
| buffer.offset = 0; |
| buffer.size = S905D2_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_G12A_CLK); |
| |
| // Initialization sets a bunch of registers that we don't care about, so we |
| // can reset the array to a clean slate. |
| memset(actual.get(), 0, S905D2_HIU_LENGTH); |
| memset(expected.get(), 0, S905D2_HIU_LENGTH); |
| |
| EXPECT_EQ(memcmp(actual.get(), expected.get(), S905D2_HIU_LENGTH), 0); |
| |
| constexpr uint16_t kTestClock = 0; |
| const uint32_t clk_id = |
| aml_clk_common::AmlClkId(kTestClock, aml_clk_common::aml_clk_type::kMesonGate); |
| |
| ASSERT_DEATH(([&clk]() { clk.ClockImplDisable(clk_id); }), |
| "Failed to crash when trying to disable already disabled clock."); |
| } |
| |
| TEST(ClkTestAml, EnableDisableRefCount) { |
| zx_status_t st; |
| auto actual = std::make_unique<uint8_t[]>(S905D2_HIU_LENGTH); |
| |
| mmio_buffer_t buffer; |
| buffer.vaddr = FakeMmioPtr(actual.get()); |
| buffer.offset = 0; |
| buffer.size = S905D2_HIU_LENGTH; |
| buffer.vmo = ZX_HANDLE_INVALID; |
| |
| auto [dos_data, dos_buffer] = MakeDosbusMmio(); |
| AmlClockTest clk(buffer, dos_buffer, PDEV_DID_AMLOGIC_G12A_CLK); |
| |
| // Initialization sets a bunch of registers that we don't care about, so we |
| // can reset the array to a clean slate. |
| memset(actual.get(), 0, S905D2_HIU_LENGTH); |
| |
| constexpr uint16_t kTestClock = 0; |
| constexpr uint32_t kTestClockId = |
| aml_clk_common::AmlClkId(kTestClock, aml_clk_common::aml_clk_type::kMesonGate); |
| constexpr uint32_t reg = g12a_clk_gates[kTestClock].reg; |
| constexpr uint32_t bit = (1u << g12a_clk_gates[kTestClock].bit); |
| uint32_t* reg_ptr = reinterpret_cast<uint32_t*>(&actual.get()[reg]); |
| |
| // Enable the test clock and verify that the register was written. |
| st = clk.ClockImplEnable(kTestClockId); |
| EXPECT_OK(st); |
| EXPECT_EQ((*reg_ptr), bit); |
| |
| // Zero out the register and enable the clock again. Since the driver |
| // should already think the clock is enabled, this should be a no-op. |
| *reg_ptr = 0; |
| st = clk.ClockImplEnable(kTestClockId); |
| EXPECT_OK(st); |
| EXPECT_EQ((*reg_ptr), 0); // Make sure the driver didn't touch the register. |
| |
| // This time we fill the registers with Fs and try disabling the clock. Since |
| // it's been enabled twice, the first disable should only drop a ref rather than |
| // actually disabling clock hardware. |
| *reg_ptr = 0xffffffff; |
| st = clk.ClockImplDisable(kTestClockId); |
| EXPECT_OK(st); |
| EXPECT_EQ((*reg_ptr), 0xffffffff); // Make sure the driver didn't touch the register. |
| |
| // The second call to disable should actually disable the clock hardware. |
| *reg_ptr = 0xffffffff; |
| st = clk.ClockImplDisable(kTestClockId); |
| EXPECT_OK(st); |
| EXPECT_EQ((*reg_ptr), |
| (0xffffffff & (~bit))); // Make sure the driver actually disabled the hardware. |
| } |
| |
| } // namespace amlogic_clock |