blob: f35ae703e497c98f93508e468c54b0274ed19bcb [file] [log] [blame]
// Copyright 2023 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_mipi_dsi_mcuxpresso/framebuffer_device.h"
#include "common.h"
#include "pw_assert/assert.h"
#include "pw_status/try.h"
using pw::framebuffer_pool::FramebufferPool;
namespace pw::mipi::dsi {
namespace {
FramebufferDevice::WriteCallback s_write_callback;
void* s_current_write_buffer;
} // namespace
FramebufferDevice::FramebufferDevice(uint8_t layer)
: dc_(nullptr), layer_(layer), enabled_(false) {
VIDEO_MEMPOOL_InitEmpty(&video_mempool_);
}
Status FramebufferDevice::Init(const dc_fb_t* dc,
const FramebufferPool& framebuffer_pool) {
PW_TRY(InitDisplayController(dc));
PW_TRY(InitVideoMemPool(framebuffer_pool));
// Only allow one framebuffer to be checked out at a time. This could be
// increased to the pool size if the completion callback mechanism is
// improved to allow more than one write at a time.
framebuffer_semaphore_.release(1);
return OkStatus();
}
Status FramebufferDevice::InitDisplayController(const dc_fb_t* dc) {
PW_ASSERT(!dc_);
dc_ = dc;
status_t status = dc_->ops->init(dc);
if (status != kStatus_Success) {
return MCUXpressoToPigweedStatus(status);
}
dc_fb_info_t buff_info;
status = dc_->ops->getLayerDefaultConfig(dc_, layer_, &buff_info);
if (status != kStatus_Success) {
return MCUXpressoToPigweedStatus(status);
}
dc_->ops->setCallback(dc_, layer_, BufferSwitchOffCallback, this);
status = dc_->ops->setLayerConfig(dc_, layer_, &buff_info);
if (status != kStatus_Success) {
return MCUXpressoToPigweedStatus(status);
}
return OkStatus();
}
Status FramebufferDevice::InitVideoMemPool(
const FramebufferPool& framebuffer_pool) {
if (enabled_) {
return Status::FailedPrecondition();
}
const FramebufferPool::BufferArray& buffers =
framebuffer_pool.GetBuffersForInit();
for (size_t i = 0; i < buffers.size(); i++) {
VIDEO_MEMPOOL_Put(&video_mempool_, buffers[i]);
}
return OkStatus();
}
Status FramebufferDevice::Close() {
if (!dc_)
return Status::FailedPrecondition();
status_t status = dc_->ops->deinit(dc_);
dc_ = nullptr;
return MCUXpressoToPigweedStatus(status);
}
Status FramebufferDevice::Enable() {
if (enabled_)
return OkStatus();
status_t status = kStatus_Success;
if ((dc_->ops->getProperty(dc_) & (uint32_t)kDC_FB_ReserveFrameBuffer) ==
0U) {
status = dc_->ops->enableLayer(dc_, layer_);
if (status != kStatus_Success) {
enabled_ = true;
}
}
return MCUXpressoToPigweedStatus(status);
}
Status FramebufferDevice::Disable() {
if (!enabled_)
return OkStatus();
status_t status = dc_->ops->disableLayer(dc_, layer_);
enabled_ = false;
return MCUXpressoToPigweedStatus(status);
}
void FramebufferDevice::WriteFramebuffer(void* frameBuffer,
WriteCallback write_callback) {
PW_ASSERT(!s_write_callback);
s_write_callback = std::move(write_callback);
s_current_write_buffer = frameBuffer;
Status s = MCUXpressoToPigweedStatus(
dc_->ops->setFrameBuffer(dc_, layer_, frameBuffer));
if (!s.ok())
WriteComplete(s_current_write_buffer, s);
}
void* FramebufferDevice::GetFramebuffer() {
framebuffer_semaphore_.acquire();
return VIDEO_MEMPOOL_Get(&video_mempool_);
}
void FramebufferDevice::WriteComplete(void* buffer, Status s) {
PW_ASSERT(buffer == s_current_write_buffer);
PW_ASSERT(s_write_callback);
framebuffer_semaphore_.release();
s_current_write_buffer = nullptr;
s_write_callback(buffer, s);
}
void FramebufferDevice::BufferSwitchOff(void* buffer) {
VIDEO_MEMPOOL_Put(&video_mempool_, buffer);
WriteComplete(buffer, OkStatus());
}
// static
void FramebufferDevice::BufferSwitchOffCallback(void* param, void* buffer) {
PW_ASSERT(param != nullptr);
static_cast<FramebufferDevice*>(param)->BufferSwitchOff(buffer);
}
} // namespace pw::mipi::dsi