blob: 8c13b6fb88d7a4aba9f2299f8e18f83d7c20120c [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 <fbl/array.h>
#include <mock-mmio-reg/mock-mmio-reg.h>
#include <mock/ddktl/protocol/shareddma.h>
#include <soc/as370/as370-dma.h>
#include <soc/as370/syn-audio-in.h>
#include <zxtest/zxtest.h>
bool operator==(const shared_dma_protocol_t& a, const shared_dma_protocol_t& b) { return true; }
bool operator==(const dma_notify_t& a, const dma_notify_t& b) { return true; }
class CicFilterTest : public CicFilter {
public:
explicit CicFilterTest() : CicFilter() {}
uint32_t Filter(uint32_t index, void* input, uint32_t input_size, void* output,
uint32_t input_total_channels, uint32_t input_channel,
uint32_t output_total_channels, uint32_t output_channel,
uint32_t multiplier_shift) {
return 4; // mock decodes 4 bytes.
}
};
class SynAudioInDeviceTest : public SynAudioInDevice {
public:
static std::unique_ptr<SynAudioInDeviceTest> Create(ddk::MockSharedDma* dma) {
static fbl::Array<ddk_mock::MockMmioReg> unused_mocks =
fbl::Array(new ddk_mock::MockMmioReg[1], 1);
static ddk_mock::MockMmioRegRegion unused_region(unused_mocks.data(), sizeof(uint32_t), 1);
ddk::MmioBuffer b1(unused_region.GetMmioBuffer());
ddk::MmioBuffer b2(unused_region.GetMmioBuffer());
ddk::MmioBuffer b3(unused_region.GetMmioBuffer());
fbl::AllocChecker ac;
auto dev = std::unique_ptr<SynAudioInDeviceTest>(new (&ac) SynAudioInDeviceTest(
std::move(b1), std::move(b2), std::move(b3), dma->GetProto()));
if (!ac.check()) {
return nullptr;
}
return dev;
}
SynAudioInDeviceTest(ddk::MmioBuffer mmio_global, ddk::MmioBuffer mmio_avio,
ddk::MmioBuffer mmio_i2s, ddk::SharedDmaProtocolClient dma)
: SynAudioInDevice(std::move(mmio_global), std::move(mmio_avio), std::move(mmio_i2s),
std::move(dma)) {
cic_filter_ = std::make_unique<CicFilterTest>();
dma_buffer_size_[0] = 0x10;
if (kNumberOfDmas > 1) {
dma_buffer_size_[1] = 0x20;
}
}
bool HasAtLeastTwoDmas() { return kNumberOfDmas >= 2; }
};
namespace audio {
TEST(SynapticsAudioInTest, ProcessDmaSimple) {
ddk::MockSharedDma dma;
auto dev = SynAudioInDeviceTest::Create(&dma);
dma.ExpectGetTransferSize(4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x8, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dev->ProcessDma(0);
dma.VerifyAndClear();
}
TEST(SynapticsAudioInTest, ProcessDmaWarp) {
ddk::MockSharedDma dma;
auto dev = SynAudioInDeviceTest::Create(&dma);
dma.ExpectGetTransferSize(4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x8, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x0, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x8, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dev->ProcessDma(0);
dma.VerifyAndClear();
}
TEST(SynapticsAudioInTest, ProcessDmaIrregular) {
ddk::MockSharedDma dma;
auto dev = SynAudioInDeviceTest::Create(&dma);
dma.ExpectGetTransferSize(4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x8, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dev->ProcessDma(0);
dma.VerifyAndClear();
}
TEST(SynapticsAudioInTest, ProcessDmaOverflow) {
ddk::MockSharedDma dma;
auto dev = SynAudioInDeviceTest::Create(&dma);
dma.ExpectGetTransferSize(4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW0);
dev->ProcessDma(0);
dma.VerifyAndClear();
}
TEST(SynapticsAudioInTest, ProcessDmaPdm0AndPdm1) {
ddk::MockSharedDma dma;
auto dev = SynAudioInDeviceTest::Create(&dma);
if (!dev->HasAtLeastTwoDmas()) {
return;
}
// every call to ProcessDma gets transfer size from PDM0.
dma.ExpectGetTransferSize(4, DmaId::kDmaIdPdmW0);
dma.ExpectGetTransferSize(4, DmaId::kDmaIdPdmW0);
dma.ExpectGetTransferSize(4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x8, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x0, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0x8, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0x10, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0x14, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0x18, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0x1c, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0x0, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0x4, DmaId::kDmaIdPdmW1);
dma.ExpectGetBufferPosition(0x8, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dma.ExpectGetBufferPosition(0xc, DmaId::kDmaIdPdmW0);
dev->ProcessDma(0);
dev->ProcessDma(1);
dev->ProcessDma(0);
dma.VerifyAndClear();
}
TEST(SynapticsAudioInTest, FifoDepth) {
ddk::MockSharedDma dma;
auto dev = SynAudioInDeviceTest::Create(&dma);
// 16384 PDM DMA transfer size as used for PDM, generates 1024 samples at 48KHz 16 bits.
dma.ExpectGetTransferSize(16384, DmaId::kDmaIdPdmW0);
// 12288 = 3 channels x 1024 samples per DMA x 2 bytes per sample x 2 for ping-pong.
ASSERT_EQ(dev->FifoDepth(), 12288);
dma.VerifyAndClear();
}
} // namespace audio