| // 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 "msm8x53-power.h" |
| |
| #include <soc/msm8x53/msm8x53-power.h> |
| #include <fbl/auto_call.h> |
| #include <mock-mmio-reg/mock-mmio-reg.h> |
| #include <zxtest/zxtest.h> |
| |
| namespace { |
| |
| static constexpr uint32_t kPmicArbCoreMmioRegCount = 768; |
| static constexpr uint32_t kPmicArbChnlsMmioRegCount = 768; |
| static constexpr uint32_t kPmicArbObsvrMmioRegCount = 768; |
| static constexpr uint32_t kDummyRegCount = 100; |
| |
| } // namespace |
| |
| namespace power { |
| |
| class Msm8x53PowerTest : public Msm8x53Power { |
| public: |
| Msm8x53PowerTest(ddk_mock::MockMmioRegRegion& core_mmio_registers, |
| ddk_mock::MockMmioRegRegion& chnls_mmio_registers, |
| ddk_mock::MockMmioRegRegion& obsvr_mmio_registers, |
| ddk_mock::MockMmioRegRegion& intr_mmio_registers, |
| ddk_mock::MockMmioRegRegion& cfg_mmio_registers) |
| : Msm8x53Power(nullptr, ddk::MmioBuffer(core_mmio_registers.GetMmioBuffer()), |
| ddk::MmioBuffer(chnls_mmio_registers.GetMmioBuffer()), |
| ddk::MmioBuffer(obsvr_mmio_registers.GetMmioBuffer()), |
| ddk::MmioBuffer(intr_mmio_registers.GetMmioBuffer()), |
| ddk::MmioBuffer(cfg_mmio_registers.GetMmioBuffer())) {} |
| zx_status_t InvokePmicArbInit() { return PmicArbInit(); } |
| |
| uint32_t GetApid(uint32_t ppid) { return ppid_to_apid_[ppid]; } |
| |
| void SetApid(uint32_t ppid, uint32_t apid) { ppid_to_apid_[ppid] = apid; } |
| }; |
| |
| template <class T> |
| ddk_mock::MockMmioReg& GetMockReg(ddk_mock::MockMmioRegRegion& registers) { |
| return registers[T::Get().addr()]; |
| } |
| |
| template <class T> |
| ddk_mock::MockMmioReg& GetMockReg(int reg_offset, ddk_mock::MockMmioRegRegion& registers) { |
| return registers[T::Get(reg_offset).addr()]; |
| } |
| |
| TEST(PowerTest, PmicArbInit) { |
| ddk_mock::MockMmioReg core_reg_array[kPmicArbCoreMmioRegCount]; |
| ddk_mock::MockMmioRegRegion mock_core_regs(core_reg_array, sizeof(uint32_t), |
| kPmicArbCoreMmioRegCount); |
| |
| ddk_mock::MockMmioReg dummy_reg_array[kDummyRegCount]; |
| ddk_mock::MockMmioRegRegion mock_dummy_regs(dummy_reg_array, sizeof(uint32_t), kDummyRegCount); |
| |
| Msm8x53PowerTest power(mock_core_regs, mock_dummy_regs, mock_dummy_regs, mock_dummy_regs, |
| mock_dummy_regs); |
| |
| // Check Version. If not 2, PmicArbInit fails. |
| GetMockReg<PmicArbVersion>(mock_core_regs).ExpectRead(kPmicArbVersionTwo); |
| |
| // Check the APID -> PPID mapping for peripheral id 0, 1, 14 |
| mock_core_regs[PMIC_ARB_CORE_CHANNEL_INFO_OFFSET(0)].ExpectRead( |
| PmicArbCoreChannelInfo().set_slave_id(0xe).set_periph_id(0x8).reg_value()); |
| mock_core_regs[PMIC_ARB_CORE_CHANNEL_INFO_OFFSET(1)].ExpectRead( |
| PmicArbCoreChannelInfo().set_slave_id(0x0).set_periph_id(0x77).reg_value()); |
| mock_core_regs[PMIC_ARB_CORE_CHANNEL_INFO_OFFSET(14)].ExpectRead( |
| PmicArbCoreChannelInfo().set_slave_id(0x2).set_periph_id(0x1b).reg_value()); |
| |
| EXPECT_OK(power.InvokePmicArbInit()); |
| ASSERT_EQ(power.GetApid(PPID(0xe, 0x8)), 0); |
| ASSERT_EQ(power.GetApid(PPID(0x0, 0x77)), 1); |
| ASSERT_EQ(power.GetApid(PPID(0x2, 0x1b)), 14); |
| } |
| |
| TEST(PowerTest, PmicWritePmicCtrlReg) { |
| ddk_mock::MockMmioReg chnls_reg_array[kPmicArbChnlsMmioRegCount]; |
| ddk_mock::MockMmioRegRegion mock_chnls_regs(chnls_reg_array, sizeof(uint32_t), |
| kPmicArbChnlsMmioRegCount); |
| |
| ddk_mock::MockMmioReg obsvr_reg_array[kPmicArbObsvrMmioRegCount]; |
| ddk_mock::MockMmioRegRegion mock_obsvr_regs(obsvr_reg_array, sizeof(uint32_t), |
| kPmicArbObsvrMmioRegCount); |
| |
| ddk_mock::MockMmioReg dummy_reg_array[kDummyRegCount]; |
| ddk_mock::MockMmioRegRegion mock_dummy_regs(dummy_reg_array, sizeof(uint32_t), kDummyRegCount); |
| |
| Msm8x53PowerTest power(mock_dummy_regs, mock_chnls_regs, mock_obsvr_regs, mock_dummy_regs, |
| mock_dummy_regs); |
| |
| uint32_t apid = 0; |
| // Disabling the interrupt |
| uint32_t cmd_cfg_offset = PMIC_ARB_CHANNEL_CMD_CONFIG_OFFSET(apid); |
| mock_chnls_regs[cmd_cfg_offset].ExpectRead(0xFFFFFFFF).ExpectWrite(0x0); |
| // Set the ppid to apid mapping |
| uint32_t slave_id = 0x3; |
| uint32_t periph_id = 0xc0; |
| uint32_t write_value = 0x80; |
| uint32_t reg_offset = 0x70; |
| uint32_t write_addr = 0x3c070; |
| power.SetApid(PPID(slave_id, periph_id), apid); |
| |
| // Write first 4 bytes to WDATA0 |
| mock_chnls_regs[PMIC_ARB_CHANNEL_CMD_WDATA0_OFFSET(apid)] |
| .ExpectRead(0x00000000) |
| .ExpectWrite(PmicArbCoreChannelCmdWData().set_data(write_value).reg_value()); |
| |
| // Write the CMD |
| uint32_t cmd_offset = PMIC_ARB_CHANNEL_CMD_OFFSET(apid); |
| mock_chnls_regs[cmd_offset] |
| .ExpectRead(0x00000000) |
| .ExpectWrite(PmicArbCoreChannelCmdInfo() |
| .set_byte_cnt(0) |
| .set_reg_offset_addr(reg_offset) |
| .set_periph_id(periph_id) |
| .set_slave_id(slave_id) |
| .set_priority(0) |
| .set_opcode(kSpmiCmdRegWriteOpcode) |
| .reg_value()); |
| |
| // Write CMD Completion |
| mock_chnls_regs[PMIC_ARB_CHANNEL_CMD_STATUS_OFFSET(apid)].ExpectRead( |
| PmicArbCoreChannelCmdStatus() |
| .set_status(PmicArbCoreChannelCmdStatus::kPmicArbCmdDone) |
| .reg_value()); |
| |
| EXPECT_OK(power.PowerImplWritePmicCtrlReg(kPmicCtrlReg, write_addr, write_value)); |
| mock_chnls_regs.VerifyAll(); |
| } |
| |
| TEST(PowerTest, PmicReadPmicCtrlReg) { |
| ddk_mock::MockMmioReg obsvr_reg_array[kPmicArbObsvrMmioRegCount]; |
| ddk_mock::MockMmioRegRegion mock_obsvr_regs(obsvr_reg_array, sizeof(uint32_t), |
| kPmicArbObsvrMmioRegCount); |
| |
| ddk_mock::MockMmioReg dummy_reg_array[kDummyRegCount]; |
| ddk_mock::MockMmioRegRegion mock_dummy_regs(dummy_reg_array, sizeof(uint32_t), kDummyRegCount); |
| |
| Msm8x53PowerTest power(mock_dummy_regs, mock_dummy_regs, mock_obsvr_regs, mock_dummy_regs, |
| mock_dummy_regs); |
| |
| uint32_t apid = 0; |
| // Disabling the interrupt |
| uint32_t cmd_cfg_offset = PMIC_ARB_CHANNEL_CMD_CONFIG_OFFSET(apid); |
| mock_obsvr_regs[cmd_cfg_offset].ExpectRead(0xFFFFFFFF).ExpectWrite(0x0); |
| // Set the ppid to apid mapping |
| uint32_t slave_id = 0x3; |
| uint32_t periph_id = 0xc0; |
| uint32_t expected_value = 0x80; |
| uint32_t reg_offset = 0x70; |
| uint32_t read_addr = 0x3c070; |
| uint32_t read_data; |
| power.SetApid(PPID(slave_id, periph_id), apid); |
| |
| // Write the Read CMD |
| uint32_t cmd_offset = PMIC_ARB_CHANNEL_CMD_OFFSET(apid); |
| mock_obsvr_regs[cmd_offset] |
| .ExpectRead(0x00000000) |
| .ExpectWrite(PmicArbCoreChannelCmdInfo() |
| .set_byte_cnt(0) |
| .set_reg_offset_addr(reg_offset) |
| .set_periph_id(periph_id) |
| .set_slave_id(slave_id) |
| .set_priority(0) |
| .set_opcode(kSpmiCmdRegReadOpcode) |
| .reg_value()); |
| |
| // Write CMD Completion to unblock the test |
| mock_obsvr_regs[PMIC_ARB_CHANNEL_CMD_STATUS_OFFSET(apid)].ExpectRead( |
| PmicArbCoreChannelCmdStatus() |
| .set_status(PmicArbCoreChannelCmdStatus::kPmicArbCmdDone) |
| .reg_value()); |
| // Read first 4 bytes to RDATA0 |
| mock_obsvr_regs[PMIC_ARB_CHANNEL_CMD_RDATA0_OFFSET(apid)].ExpectRead( |
| PmicArbCoreChannelCmdRData().set_data(expected_value).reg_value()); |
| |
| EXPECT_OK(power.PowerImplReadPmicCtrlReg(kPmicCtrlReg, read_addr, &read_data)); |
| mock_obsvr_regs.VerifyAll(); |
| ASSERT_EQ(read_data, expected_value); |
| } |
| |
| } // namespace power |