blob: 265e1e7a587e6997a3ed58494fa06aee7510fb00 [file] [log] [blame] [edit]
// Copyright 2018 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 <fidl/fuchsia.boot/cpp/wire.h>
#include <lib/device-protocol/pci.h>
#include <lib/driver/component/cpp/driver_export.h>
#include <lib/driver/logging/cpp/logger.h>
#include <lib/image-format/image_format.h>
#include <lib/zbi-format/graphics.h>
#include <lib/zbi-format/zbi.h>
#include <lib/zx/result.h>
#include <fbl/alloc_checker.h>
#include "src/graphics/display/lib/api-types/cpp/pixel-format.h"
#include "src/graphics/display/lib/framebuffer-display/framebuffer-display-driver.h"
#include "src/graphics/display/lib/framebuffer-display/framebuffer-display.h"
namespace framebuffer_display {
namespace {
class FramebufferIntelDisplayDriver final : public FramebufferDisplayDriver {
public:
explicit FramebufferIntelDisplayDriver(fdf::DriverStartArgs start_args,
fdf::UnownedSynchronizedDispatcher driver_dispatcher);
FramebufferIntelDisplayDriver(const FramebufferIntelDisplayDriver&) = delete;
FramebufferIntelDisplayDriver(FramebufferIntelDisplayDriver&&) = delete;
FramebufferIntelDisplayDriver& operator=(const FramebufferIntelDisplayDriver&) = delete;
FramebufferIntelDisplayDriver& operator=(FramebufferIntelDisplayDriver&&) = delete;
~FramebufferIntelDisplayDriver() override;
// FramebufferDisplayDriver:
zx::result<> ConfigureHardware() override;
zx::result<fdf::MmioBuffer> GetFrameBufferMmioBuffer() override;
zx::result<DisplayProperties> GetDisplayProperties() override;
private:
zx::result<zbi_swfb_t> GetFramebufferInfo();
};
FramebufferIntelDisplayDriver::FramebufferIntelDisplayDriver(
fdf::DriverStartArgs start_args, fdf::UnownedSynchronizedDispatcher driver_dispatcher)
: FramebufferDisplayDriver("framebuffer-intel-display", std::move(start_args),
std::move(driver_dispatcher)) {}
FramebufferIntelDisplayDriver::~FramebufferIntelDisplayDriver() = default;
zx::result<> FramebufferIntelDisplayDriver::ConfigureHardware() { return zx::ok(); }
zx::result<fdf::MmioBuffer> FramebufferIntelDisplayDriver::GetFrameBufferMmioBuffer() {
zx::result<fidl::ClientEnd<fuchsia_hardware_pci::Device>> pci_result =
incoming()->Connect<fuchsia_hardware_pci::Service::Device>("pci");
if (pci_result.is_error()) {
fdf::error("Failed to connect to PCI protocol: {}", pci_result);
return pci_result.take_error();
}
ddk::Pci pci(std::move(pci_result).value());
ZX_DEBUG_ASSERT(pci.is_valid());
std::optional<fdf::MmioBuffer> framebuffer_mmio;
static constexpr uint32_t kIntelFramebufferPciBarIndex = 2;
zx_status_t status =
pci.MapMmio(kIntelFramebufferPciBarIndex, ZX_CACHE_POLICY_WRITE_COMBINING, &framebuffer_mmio);
if (status != ZX_OK) {
fdf::error("Failed to map PCI bar {}: {}", kIntelFramebufferPciBarIndex,
zx::make_result(status));
return zx::error(status);
}
ZX_DEBUG_ASSERT(framebuffer_mmio.has_value());
return zx::ok(std::move(framebuffer_mmio).value());
}
zx::result<zbi_swfb_t> FramebufferIntelDisplayDriver::GetFramebufferInfo() {
zx::result boot_items_client = incoming()->Connect<fuchsia_boot::Items>();
if (boot_items_client.is_error()) {
fdf::error("Failed to connect to fuchsia.boot/Items: {}", boot_items_client);
return boot_items_client.take_error();
}
fidl::WireResult result = fidl::WireCall(*boot_items_client)->Get2(ZBI_TYPE_FRAMEBUFFER, {});
if (!result.ok()) {
fdf::error("Failed to call fuchsia.boot/Items.Get2: {}", result.status_string());
return zx::error(result.status());
}
if (result->is_error()) {
fdf::error("Failed to get framebuffer boot item: {}", zx::make_result(result->error_value()));
return zx::error(result->error_value());
}
fidl::VectorView items = result->value()->retrieved_items;
if (items.size() == 0) {
return zx::error(ZX_ERR_NOT_FOUND);
}
if (items[0].length < sizeof(zbi_swfb_t)) {
return zx::error(ZX_ERR_BAD_STATE);
}
zbi_swfb_t framebuffer_info;
zx_status_t status = items[0].payload.read(&framebuffer_info, 0, sizeof(framebuffer_info));
if (status != ZX_OK) {
return zx::error(status);
}
return zx::ok(framebuffer_info);
}
zx::result<DisplayProperties> FramebufferIntelDisplayDriver::GetDisplayProperties() {
zx::result framebuffer_info = GetFramebufferInfo();
if (framebuffer_info.is_error()) {
fdf::error("Failed to get bootloader dimensions: {}", framebuffer_info);
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
zbi_pixel_format_t format = framebuffer_info->format;
uint32_t width = framebuffer_info->width;
uint32_t height = framebuffer_info->height;
uint32_t stride = framebuffer_info->stride;
ZX_DEBUG_ASSERT(width <= std::numeric_limits<int32_t>::max());
ZX_DEBUG_ASSERT(height <= std::numeric_limits<int32_t>::max());
ZX_DEBUG_ASSERT(stride <= std::numeric_limits<int32_t>::max());
fpromise::result<fuchsia_images2::wire::PixelFormat> sysmem2_format_type_result =
ImageFormatConvertZbiToSysmemPixelFormat_v2(format);
if (!sysmem2_format_type_result.is_ok()) {
fdf::error("Failed to convert framebuffer format: {}", static_cast<uint32_t>(format));
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
fuchsia_images2::wire::PixelFormat sysmem2_format = sysmem2_format_type_result.take_value();
if (!display::PixelFormat::IsSupported(sysmem2_format)) {
fdf::error("Unsupported framebuffer format: {}", static_cast<uint32_t>(sysmem2_format));
return zx::error(ZX_ERR_NOT_SUPPORTED);
}
display::PixelFormat pixel_format(sysmem2_format);
const DisplayProperties properties = {
.width_px = static_cast<int32_t>(width),
.height_px = static_cast<int32_t>(height),
.row_stride_px = static_cast<int32_t>(stride),
.pixel_format = pixel_format,
};
return zx::ok(properties);
}
} // namespace
} // namespace framebuffer_display
FUCHSIA_DRIVER_EXPORT(framebuffer_display::FramebufferIntelDisplayDriver);