blob: c86f9b175206757b1d47d6a2a673699abac4d120 [file] [log] [blame]
// Copyright 2022 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/alloc_checker.h>
#include <hwreg/bitfields.h>
#include <soc/aml-common/aml-loopback-audio.h>
namespace audio::aml_g12 {
constexpr zx_off_t kLoopbackOffset = EE_AUDIO_LB_A_CTRL0;
constexpr zx_off_t kLoopbackSize = 4 * sizeof(uint32_t);
// LOOPBACK Registers.
class LbCtrl : public hwreg::RegisterBase<LbCtrl, uint32_t> {
public:
// For Common Chips.
DEF_BIT(31, enable);
DEF_BIT(30, mode);
// |Datain| packet_format, msb, lsb.
DEF_FIELD(15, 13, packet_format);
DEF_FIELD(12, 8, msb);
DEF_FIELD(7, 3, lsb);
// For S905D2.
static bool has_datain_channel_sel(metadata::AmlVersion version) {
return version == metadata::AmlVersion::kS905D2G;
}
// Max channel number of |Datain| source.
DEF_FIELD(26, 24, datain_channel_nums);
// Active channel mask of |Datain| source.
DEF_FIELD(23, 16, datain_channel_mask);
// For S905D2/S905D3/A1.
static bool has_datain_src(metadata::AmlVersion version) {
return version == metadata::AmlVersion::kS905D2G || version == metadata::AmlVersion::kS905D3G ||
version == metadata::AmlVersion::kA1;
}
// Source for LOOPBACK |Datain|.
DEF_FIELD(2, 0, datain_src);
static auto Get() { return hwreg::RegisterAddr<LbCtrl>(LB_A_CTRL0_OFFS); }
};
class LbCtrl1 : public hwreg::RegisterBase<LbCtrl1, uint32_t> {
public:
// For Common Chips.
// |Datalb| packet_format, msb, lsb.
DEF_FIELD(15, 13, packet_format);
DEF_FIELD(12, 8, msb);
DEF_FIELD(7, 3, lsb);
// For S905D2.
static bool has_datalb_channel_sel(metadata::AmlVersion version) {
return version == metadata::AmlVersion::kS905D2G;
}
// Max channel number of |Datalb| source.
DEF_FIELD(26, 24, datalb_channel_nums);
// Active channel mask of |Datalb| source.
DEF_FIELD(23, 16, datalb_channel_mask);
// For S905D2/S905D3/A1.
static bool has_datalb_src(metadata::AmlVersion version) {
return version == metadata::AmlVersion::kS905D2G || version == metadata::AmlVersion::kS905D3G ||
version == metadata::AmlVersion::kA1;
}
// Source for LOOPBACK |Datalb|.
DEF_FIELD(2, 0, datalb_src);
static auto Get() { return hwreg::RegisterAddr<LbCtrl1>(LB_A_CTRL1_OFFS); }
};
class LbCtrl2 : public hwreg::RegisterBase<LbCtrl2, uint32_t> {
public:
// For S905D3/A1/A5.
static bool has_datain_channel_sel(metadata::AmlVersion version) {
return version != metadata::AmlVersion::kS905D2G;
}
// Max channel number of |Datain| source.
DEF_FIELD(19, 16, datain_channel_nums);
// Active channel mask of |Datain| source.
DEF_FIELD(15, 0, datain_channel_mask);
// For A5.
static bool has_datain_src(metadata::AmlVersion version) {
return version == metadata::AmlVersion::kA5;
}
// Source for LOOPBACK |Datain|.
DEF_FIELD(24, 20, datain_src);
static auto Get() { return hwreg::RegisterAddr<LbCtrl2>(LB_A_CTRL2_OFFS); }
};
class LbCtrl3 : public hwreg::RegisterBase<LbCtrl3, uint32_t> {
public:
// For S905D3/A1/A5.
static bool has_datalb_channel_sel(metadata::AmlVersion version) {
return version != metadata::AmlVersion::kS905D2G;
}
// Max channel number of |Datalb| source.
DEF_FIELD(19, 16, datalb_channel_nums);
// Active channel mask of |Datalb| source.
DEF_FIELD(15, 0, datalb_channel_mask);
// For A5.
static bool has_datalb_src(metadata::AmlVersion version) {
return version == metadata::AmlVersion::kA5;
}
// Source for LOOPBACK |Datalb|.
DEF_FIELD(24, 20, datalb_src);
static auto Get() { return hwreg::RegisterAddr<LbCtrl3>(LB_A_CTRL3_OFFS); }
};
// End of LOOPBACK Registers
// static
std::unique_ptr<AmlLoopbackDevice> AmlLoopbackDevice::Create(const fdf::MmioBuffer& mmio,
const metadata::AmlVersion version,
metadata::AmlLoopbackConfig config) {
ZX_ASSERT_MSG((kLoopbackOffset + kLoopbackSize) < mmio.get_size(), "Out Of Mmio Region.");
fdf::MmioView view = mmio.View(kLoopbackOffset, kLoopbackSize);
fbl::AllocChecker ac;
auto dev = std::unique_ptr<AmlLoopbackDevice>(
new (&ac) AmlLoopbackDevice(std::move(view), version, config));
if (!ac.check()) {
return nullptr;
}
ZX_ASSERT(dev->Initialize() == ZX_OK);
return dev;
}
zx_status_t AmlLoopbackDevice::Initialize() {
if (datalb_chnum_ && !datain_chnum_) {
LbRateMode(true);
} else {
LbRateMode(false);
}
if (datain_chnum_) {
ConfigDataIn(datalb_chnum_, datain_chmask_, datain_src_);
}
if (datalb_chnum_) {
ConfigDataLb(datalb_chnum_, datalb_chmask_);
}
return ZX_OK;
}
void AmlLoopbackDevice::LbRateMode(bool is_lb_rate) {
LbCtrl::Get().ReadFrom(&view_).set_mode(is_lb_rate).WriteTo(&view_);
}
zx_status_t AmlLoopbackDevice::ConfigDataIn(uint32_t active_channels, uint32_t enable_mask,
uint32_t src_id) {
// LOOPBACK |Datain| Channel Config.
if (LbCtrl::has_datain_channel_sel(version_)) {
LbCtrl::Get()
.ReadFrom(&view_)
.set_datain_channel_nums(active_channels - 1)
.set_datain_channel_mask(enable_mask)
.WriteTo(&view_);
} else {
LbCtrl2::Get()
.ReadFrom(&view_)
.set_datain_channel_nums(active_channels - 1)
.set_datain_channel_mask(enable_mask)
.WriteTo(&view_);
}
// LOOPBACK |Datain| Source Config.
if (LbCtrl::has_datain_src(version_)) {
LbCtrl::Get().ReadFrom(&view_).set_datain_src(src_id).WriteTo(&view_);
} else {
LbCtrl2::Get().ReadFrom(&view_).set_datain_src(src_id).WriteTo(&view_);
}
// LOOPBACK |Datain| Packet.
LbCtrl::Get()
.ReadFrom(&view_)
.set_packet_format(0) // 32bits
.set_msb(31)
.set_lsb(0)
.WriteTo(&view_);
return ZX_OK;
}
zx_status_t AmlLoopbackDevice::ConfigDataLb(uint32_t active_channels, uint32_t enable_mask) {
// LOOPBACK |Datalb| Channel Config.
if (LbCtrl1::has_datalb_channel_sel(version_)) {
LbCtrl1::Get()
.ReadFrom(&view_)
.set_datalb_channel_nums(active_channels - 1)
.set_datalb_channel_mask(enable_mask)
.WriteTo(&view_);
} else {
LbCtrl3::Get()
.ReadFrom(&view_)
.set_datalb_channel_nums(active_channels - 1)
.set_datalb_channel_mask(enable_mask)
.WriteTo(&view_);
}
// LOOPBACK |Datalb| Source Config.
uint32_t src_id = {};
if (LbCtrl1::has_datalb_src(version_)) {
src_id = 0; // 'TDMIN_LB' - S905D2/S905D3/A1.
LbCtrl1::Get().ReadFrom(&view_).set_datalb_src(src_id).WriteTo(&view_);
} else {
src_id = 6; // 'TDMIN_LB' - A5.
LbCtrl3::Get().ReadFrom(&view_).set_datalb_src(src_id).WriteTo(&view_);
}
// LOOPBACK |Datalb| Packet.
LbCtrl1::Get()
.ReadFrom(&view_)
.set_packet_format(0) // 32bits
.set_msb(31)
.set_lsb(0)
.WriteTo(&view_);
return ZX_OK;
}
} // namespace audio::aml_g12