blob: b95b0e1ddd0968d0b510d44421b2499ab0f03c10 [file] [log] [blame]
// Copyright 2017 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.
#pragma once
#include <ddk/io-buffer.h>
#include <ddk/protocol/i2c.h>
#include <ddk/protocol/platform/device.h>
#include <ddktl/device-internal.h>
#include <ddktl/device.h>
#include <lib/mmio/mmio.h>
#include <ddktl/protocol/empty-protocol.h>
#include <fbl/mutex.h>
#include <fbl/vector.h>
#include <fuchsia/hardware/audio/c/fidl.h>
#include <lib/zx/bti.h>
#include <lib/zx/vmo.h>
#include <zircon/listnode.h>
#include <audio-proto/audio-proto.h>
#include <dispatcher-pool/dispatcher-channel.h>
#include <dispatcher-pool/dispatcher-execution-domain.h>
#include <dispatcher-pool/dispatcher-timer.h>
#include <soc/aml-a113/aml-tdm.h>
#include <optional>
#include <utility>
namespace audio {
namespace gauss {
class TdmOutputStream;
using TdmAudioStreamBase = ddk::Device<TdmOutputStream,
ddk::Messageable,
ddk::Unbindable>;
class TdmOutputStream : public TdmAudioStreamBase,
public ddk::EmptyProtocol<ZX_PROTOCOL_AUDIO_OUTPUT>,
public fbl::RefCounted<TdmOutputStream> {
public:
static zx_status_t Create(zx_device_t* parent);
//void PrintDebugPrefix() const;
// DDK device implementation
void DdkUnbind();
void DdkRelease();
zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) {
return fuchsia_hardware_audio_Device_dispatch(this, txn, msg, &AUDIO_FIDL_THUNKS);
}
private:
static int IrqThread(void* arg);
friend class fbl::RefPtr<TdmOutputStream>;
// TODO(hollande) - the fifo bytes are adjustable on the audio fifos and should be scaled
// with the desired sample rate. Since this first pass has a fixed sample
// sample rate we will set as constant for now.
// We are using fifo C at this stage, which is max of 128 (64-bit wide)
// Using 64 levels for now.
static constexpr uint8_t kFifoDepth = 0x40;
TdmOutputStream(zx_device_t* parent,
fbl::RefPtr<dispatcher::ExecutionDomain>&& default_domain)
: TdmAudioStreamBase(parent),
default_domain_(std::move(default_domain)),
create_time_(zx_clock_get_monotonic()) { }
virtual ~TdmOutputStream();
// Device FIDL implementation
zx_status_t GetChannel(fidl_txn_t* txn);
zx_status_t Bind(const char* devname);
void ReleaseRingBufferLocked() __TA_REQUIRES(lock_);
zx_status_t AddFormats(fbl::Vector<audio_stream_format_range_t>* supported_formats);
// Thunks for dispatching stream channel events.
zx_status_t ProcessStreamChannel(dispatcher::Channel* channel, bool privileged);
void DeactivateStreamChannel(const dispatcher::Channel* channel);
zx_status_t OnGetStreamFormatsLocked(dispatcher::Channel* channel,
const audio_proto::StreamGetFmtsReq& req) const
__TA_REQUIRES(lock_);
zx_status_t OnSetStreamFormatLocked(dispatcher::Channel* channel,
const audio_proto::StreamSetFmtReq& req,
bool privileged)
__TA_REQUIRES(lock_);
zx_status_t OnGetGainLocked(dispatcher::Channel* channel,
const audio_proto::GetGainReq& req) const
__TA_REQUIRES(lock_);
zx_status_t OnSetGainLocked(dispatcher::Channel* channel, const audio_proto::SetGainReq& req)
__TA_REQUIRES(lock_);
zx_status_t OnPlugDetectLocked(dispatcher::Channel* channel,
const audio_proto::PlugDetectReq& req) __TA_REQUIRES(lock_);
zx_status_t OnGetUniqueIdLocked(dispatcher::Channel* channel,
const audio_proto::GetUniqueIdReq& req) const
__TA_REQUIRES(lock_);
zx_status_t OnGetStringLocked(dispatcher::Channel* channel,
const audio_proto::GetStringReq& req) const
__TA_REQUIRES(lock_);
// Thunks for dispatching ring buffer channel events.
zx_status_t ProcessRingBufferChannel(dispatcher::Channel * channel);
void DeactivateRingBufferChannel(const dispatcher::Channel* channel);
zx_status_t SetModuleClocks();
zx_status_t ProcessRingNotification();
// Stream command handlers
// Ring buffer command handlers
zx_status_t OnGetFifoDepthLocked(
dispatcher::Channel* channel,
const audio_proto::RingBufGetFifoDepthReq& req) const __TA_REQUIRES(lock_);
zx_status_t OnGetBufferLocked(dispatcher::Channel* channel,
const audio_proto::RingBufGetBufferReq& req) __TA_REQUIRES(lock_);
zx_status_t OnStartLocked(dispatcher::Channel* channel, const audio_proto::RingBufStartReq& req)
__TA_REQUIRES(lock_);
zx_status_t OnStopLocked(dispatcher::Channel* channel, const audio_proto::RingBufStopReq& req)
__TA_REQUIRES(lock_);
static fuchsia_hardware_audio_Device_ops_t AUDIO_FIDL_THUNKS;
fbl::Mutex lock_;
fbl::Mutex req_lock_ __TA_ACQUIRED_AFTER(lock_);
// Dispatcher framework state
fbl::RefPtr<dispatcher::Channel> stream_channel_ __TA_GUARDED(lock_);
fbl::RefPtr<dispatcher::Channel> rb_channel_ __TA_GUARDED(lock_);
fbl::RefPtr<dispatcher::ExecutionDomain> default_domain_;
// control registers for the tdm block
std::optional<ddk::MmioBuffer> mmio_;
fbl::RefPtr<dispatcher::Timer> notify_timer_;
// TODO(johngro) : support parsing and selecting from all of the format
// descriptors present for a stream, not just a single format (with multiple
// sample rates).
fbl::Vector<audio_stream_format_range_t> supported_formats_;
pdev_protocol_t pdev_;
i2c_protocol_t i2c_;
fbl::unique_ptr<Tas57xx> left_sub_;
fbl::unique_ptr<Tas57xx> right_sub_;
fbl::unique_ptr<Tas57xx> tweeters_;
float current_gain_= -20.0;
uint32_t frame_size_;
uint32_t fifo_bytes_;
const zx_time_t create_time_;
uint32_t us_per_notification_ = 0;
volatile bool running_;
zx::bti bti_;
io_buffer_t ring_buffer_;
void* ring_buffer_virt_ = nullptr;
uint32_t ring_buffer_phys_ = 0;
uint32_t ring_buffer_size_ = 0;
};
} // namespace usb
} // namespace audio