// 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 <fuchsia/hardware/shareddma/cpp/banjo-mock.h>

#include <fbl/array.h>
#include <mock-mmio-reg/mock-mmio-reg.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
