blob: 96ece7bd5059ed3ac11cd6b1a9268dbcb6bfd82f [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.
#ifndef SRC_GRAPHICS_DISPLAY_DRIVERS_DSI_DW_DSI_DW_H_
#define SRC_GRAPHICS_DISPLAY_DRIVERS_DSI_DW_DSI_DW_H_
#include <fuchsia/hardware/dsi/cpp/banjo.h>
#include <fuchsia/hardware/dsi/llcpp/fidl.h>
#include <fuchsia/hardware/dsiimpl/cpp/banjo.h>
#include <fuchsia/hardware/platform/device/c/banjo.h>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async-loop/default.h>
#include <lib/async/dispatcher.h>
#include <lib/ddk/driver.h>
#include <lib/device-protocol/pdev.h>
#include <lib/device-protocol/platform-device.h>
#include <lib/fidl/llcpp/async_binding.h>
#include <lib/fidl/llcpp/server.h>
#include <lib/fidl/llcpp/types.h>
#include <lib/fidl/llcpp/vector_view.h>
#include <lib/mipi-dsi/mipi-dsi.h>
#include <lib/mmio/mmio.h>
#include <lib/zircon-internal/thread_annotations.h>
#include <lib/zx/bti.h>
#include <lib/zx/channel.h>
#include <unistd.h>
#include <zircon/compiler.h>
#include <zircon/errors.h>
#include <zircon/types.h>
#include <memory>
#include <optional>
#include <ddktl/device.h>
#include <ddktl/protocol/empty-protocol.h>
#include <fbl/auto_lock.h>
#include <fbl/mutex.h>
#include "dw-mipi-dsi-reg.h"
#define DSI_ERROR(fmt, ...) zxlogf(ERROR, "[%s %d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
#define DSI_INFO(fmt, ...) zxlogf(INFO, "[%s %d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
#define DSI_SPEW(fmt, ...) zxlogf(TRACE, "[%s %d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
#define DSI_TRACE zxlogf(INFO, "[%s %d]", __func__, __LINE__)
namespace dsi_dw {
class DsiDwBase;
class DsiDw;
namespace fidl_dsi = fuchsia_hardware_dsi;
using DeviceTypeBase = ddk::Device<DsiDwBase, ddk::Unbindable, ddk::Messageable>;
class DsiDwBase : public DeviceTypeBase,
public ddk::EmptyProtocol<ZX_PROTOCOL_DSI_BASE>,
public fidl::WireInterface<fuchsia_hardware_dsi::DsiBase> {
public:
DsiDwBase(zx_device_t* parent, DsiDw* dsidw) : DeviceTypeBase(parent), dsidw_(dsidw) {}
zx_status_t Bind();
// FIDL
void SendCmd(fuchsia_hardware_dsi::wire::MipiDsiCmd cmd, ::fidl::VectorView<uint8_t> txdata,
SendCmdCompleter::Sync& _completer) override;
void DdkUnbind(ddk::UnbindTxn txn);
void DdkRelease();
zx_status_t DdkMessage(fidl_incoming_msg_t* msg, fidl_txn_t* txn);
private:
DsiDw* dsidw_;
};
using DeviceType = ddk::Device<DsiDw, ddk::Unbindable>;
class DsiDw : public DeviceType, public ddk::DsiImplProtocol<DsiDw, ddk::base_protocol> {
public:
DsiDw(zx_device_t* parent) : DeviceType(parent), pdev_(parent) {}
// This function is called from the c-bind function upon driver matching
zx_status_t Bind();
// Part of ZX_DSIIMPL_PROTOCOL
zx_status_t DsiImplConfig(const dsi_config_t* dsi_config);
void DsiImplPowerUp();
void DsiImplPowerDown();
void DsiImplSetMode(dsi_mode_t mode);
zx_status_t DsiImplSendCmd(const mipi_dsi_cmd_t* cmd_list, size_t cmd_count);
bool DsiImplIsPoweredUp();
void DsiImplReset() { DsiImplPowerDown(); }
zx_status_t DsiImplPhyConfig(const dsi_config_t* dsi_config) { return ZX_OK; }
void DsiImplPhyPowerUp();
void DsiImplPhyPowerDown();
void DsiImplPhySendCode(uint32_t code, uint32_t parameter);
zx_status_t DsiImplPhyWaitForReady();
void DsiImplPrintDsiRegisters();
zx_status_t DsiImplWriteReg(uint32_t reg, uint32_t val);
zx_status_t DsiImplReadReg(uint32_t reg, uint32_t* val);
zx_status_t DsiImplEnableBist(uint32_t pattern);
void DdkUnbind(ddk::UnbindTxn txn);
void DdkRelease();
private:
inline bool IsPldREmpty() TA_REQ(command_lock_);
inline bool IsPldRFull() TA_REQ(command_lock_);
inline bool IsPldWEmpty() TA_REQ(command_lock_);
inline bool IsPldWFull() TA_REQ(command_lock_);
inline bool IsCmdEmpty() TA_REQ(command_lock_);
inline bool IsCmdFull() TA_REQ(command_lock_);
zx_status_t WaitforFifo(uint32_t bit, bool val) TA_REQ(command_lock_);
zx_status_t WaitforPldWNotFull() TA_REQ(command_lock_);
zx_status_t WaitforPldWEmpty() TA_REQ(command_lock_);
zx_status_t WaitforPldRFull() TA_REQ(command_lock_);
zx_status_t WaitforPldRNotEmpty() TA_REQ(command_lock_);
zx_status_t WaitforCmdNotFull() TA_REQ(command_lock_);
zx_status_t WaitforCmdEmpty() TA_REQ(command_lock_);
void DumpCmd(const mipi_dsi_cmd_t& cmd);
zx_status_t GenericPayloadRead(uint32_t* data) TA_REQ(command_lock_);
zx_status_t GenericHdrWrite(uint32_t data) TA_REQ(command_lock_);
zx_status_t GenericPayloadWrite(uint32_t data) TA_REQ(command_lock_);
void EnableBta() TA_REQ(command_lock_);
void DisableBta() TA_REQ(command_lock_);
zx_status_t WaitforBtaAck() TA_REQ(command_lock_);
zx_status_t GenWriteShort(const mipi_dsi_cmd_t& cmd) TA_REQ(command_lock_);
zx_status_t DcsWriteShort(const mipi_dsi_cmd_t& cmd) TA_REQ(command_lock_);
zx_status_t GenWriteLong(const mipi_dsi_cmd_t& cmd) TA_REQ(command_lock_);
zx_status_t DcsWriteShort(const fidl_dsi::wire::MipiDsiCmd& cmd,
fidl::VectorView<uint8_t>& txdata) TA_REQ(command_lock_);
zx_status_t GenRead(const mipi_dsi_cmd_t& cmd) TA_REQ(command_lock_);
zx_status_t SendCommand(const mipi_dsi_cmd_t& cmd);
zx_status_t SendCommand(const fidl_dsi::wire::MipiDsiCmd& cmd, fidl::VectorView<uint8_t>& txdata,
fidl::VectorView<uint8_t>& response);
zx_status_t GetColorCode(color_code_t c, bool& packed, uint8_t& code);
zx_status_t GetVideoMode(video_mode_t v, uint8_t& mode);
std::optional<ddk::MmioBuffer> dsi_mmio_;
pdev_protocol_t pdev_proto_ = {nullptr, nullptr};
ddk::PDev pdev_;
// This lock is used to synchronize SendCmd issued from FIDL server and Banjo interface
fbl::Mutex command_lock_;
friend DsiDwBase;
};
} // namespace dsi_dw
#endif // SRC_GRAPHICS_DISPLAY_DRIVERS_DSI_DW_DSI_DW_H_