blob: 93354ed539c3674e79f04b9c7cf13da6f5349e40 [file]
// 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.
#ifndef SRC_MEDIA_DRIVERS_AMLOGIC_ENCODER_DEVICE_CTX_H_
#define SRC_MEDIA_DRIVERS_AMLOGIC_ENCODER_DEVICE_CTX_H_
#include <fuchsia/hardware/mediacodec/c/fidl.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/device-protocol/pdev.h>
#include <lib/device-protocol/platform-device.h>
#include <lib/fidl-utils/bind.h>
#include <zircon/fidl.h>
#include <memory>
#include <thread>
#include <unordered_map>
#include <ddk/driver.h>
#include <ddk/platform-defs.h>
#include <ddk/protocol/amlogiccanvas.h>
#include <ddk/protocol/platform/device.h>
#include <ddk/protocol/sysmem.h>
#include <ddktl/device.h>
#include <ddktl/protocol/empty-protocol.h>
#include "src/media/drivers/amlogic_encoder/local_codec_factory.h"
#include "src/media/drivers/amlogic_encoder/registers.h"
enum class SocType {
kUnknown,
// These should be ordered from oldest to newest.
kG12A = 2, // S905D2
kG12B = 3, // T931
};
// Returns true if |a| is newer than or the same as |b|.
inline bool IsDeviceAtLeast(SocType a, SocType b) {
return static_cast<int>(a) >= static_cast<int>(b);
}
class DeviceCtx;
using DeviceType = ddk::Device<DeviceCtx, ddk::UnbindableNew, ddk::Messageable>;
// Manages context for the device's lifetime.
class DeviceCtx : public DeviceType, public ddk::EmptyProtocol<ZX_PROTOCOL_MEDIA_CODEC> {
public:
// Creates and binds an instance of `DeviceCtx`. If successful, returns ZX_OK
// and a bound instance of `DeviceCtx`, otherwise an error status and
// `nullptr`.
static std::pair<zx_status_t, std::unique_ptr<DeviceCtx>> Bind(zx_device_t* parent);
explicit DeviceCtx(zx_device_t* parent)
: DeviceType(parent),
loop_(&kAsyncLoopConfigNoAttachToCurrentThread),
codec_admission_control_(std::make_unique<CodecAdmissionControl>(loop_.dispatcher())) {}
DeviceCtx(const DeviceCtx&) = delete;
DeviceCtx& operator=(const DeviceCtx&) = delete;
~DeviceCtx() { ShutDown(); }
// media codec FIDL implementation
void GetCodecFactory(zx::channel request);
// Methods required by the ddk.
void DdkRelease();
void DdkUnbindNew(ddk::UnbindTxn txn);
zx_status_t DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn);
zx::unowned_bti bti() { return zx::unowned_bti(bti_); }
// This gets started connecting to sysmem, but returns an InterfaceHandle
// instead of InterfacePtr so that the caller can bind to the dispatcher.
fidl::InterfaceHandle<fuchsia::sysmem::Allocator> ConnectToSysmem();
// encoder control
zx_status_t StartEncoder();
zx_status_t StopEncoder();
zx_status_t WaitForIdle();
zx_status_t EncodeFrame(const CodecBuffer* buffer, uint8_t* data, uint32_t len);
void ReturnBuffer(const CodecBuffer* buffer);
void SetOutputBuffers(std::vector<const CodecBuffer*> buffers);
// TODO(afoxley), this should likely take some encoder specific info struct. The intention is to
// support quality adjustments on the fly.
void SetEncodeParams(fuchsia::media::FormatDetails format_details);
private:
void ShutDown();
zx_status_t Init();
zx_status_t Start();
zx_status_t LoadFirmware();
pdev_protocol_t pdev_;
amlogic_canvas_protocol_t canvas_;
sysmem_protocol_t sysmem_;
SocType soc_type_ = SocType::kUnknown;
std::unique_ptr<CbusRegisterIo> cbus_;
std::unique_ptr<DosRegisterIo> dosbus_;
zx::bti bti_;
zx::interrupt enc_interrupt_handle_;
std::thread enc_interrupt_thread_;
async::Loop loop_;
thrd_t loop_thread_;
// FIDL interfaces
std::unordered_map<LocalCodecFactory*, std::unique_ptr<LocalCodecFactory>> codec_factories_;
std::unique_ptr<CodecAdmissionControl> codec_admission_control_;
std::unique_ptr<CodecImpl> codec_instance_;
};
#endif // SRC_MEDIA_DRIVERS_AMLOGIC_ENCODER_DEVICE_CTX_H_