1// Copyright 2016 The Fuchsia Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include <ddk/debug.h> 6#include <ddk/device.h> 7#include <ddk/driver.h> 8#include <ddk/protocol/pci.h> 9#include <ddktl/protocol/display-controller.h> 10#include <hw/pci.h> 11 12#include <assert.h> 13#include <zircon/process.h> 14#include <zircon/syscalls.h> 15#include <zircon/types.h> 16#include <stdio.h> 17#include <stdlib.h> 18#include <string.h> 19#include <unistd.h> 20 21#include "simple-display.h" 22 23// implement display controller protocol 24static constexpr uint64_t kDisplayId = 1; 25 26static void* const kImageHandle = reinterpret_cast<void*>(0xdecafc0ffee); 27 28void SimpleDisplay::SetDisplayControllerCb(void* cb_ctx, display_controller_cb_t* cb) { 29 cb_ctx_ = cb_ctx; 30 cb_ = cb; 31 32 added_display_args_t args = {}; 33 args.display_id = kDisplayId; 34 args.edid_present = false; 35 args.panel.params.height = height_; 36 args.panel.params.width = width_; 37 args.panel.params.refresh_rate_e2 = 3000; // Just guess that it's 30fps 38 args.pixel_formats = &format_; 39 args.pixel_format_count = 1; 40 41 cb->on_displays_changed(cb_ctx, &args, 1, nullptr, 0); 42} 43 44zx_status_t SimpleDisplay::ImportVmoImage(image_t* image, const zx::vmo& vmo, size_t offset) { 45 zx_info_handle_basic_t import_info; 46 size_t actual, avail; 47 zx_status_t status = vmo.get_info(ZX_INFO_HANDLE_BASIC, 48 &import_info, sizeof(import_info), &actual, &avail); 49 if (status != ZX_OK) { 50 return status; 51 } 52 if (import_info.koid != framebuffer_koid_) { 53 return ZX_ERR_INVALID_ARGS; 54 } 55 if (image->width != width_ || image->height != height_ 56 || image->pixel_format != format_ || offset != 0) { 57 return ZX_ERR_INVALID_ARGS; 58 } 59 image->handle = kImageHandle; 60 return ZX_OK; 61} 62 63void SimpleDisplay::ReleaseImage(image_t* image) { 64 // noop 65} 66 67void SimpleDisplay::CheckConfiguration(const display_config_t** display_configs, 68 uint32_t* display_cfg_result, 69 uint32_t** layer_cfg_results, 70 uint32_t display_count) { 71 *display_cfg_result = CONFIG_DISPLAY_OK; 72 if (display_count != 1) { 73 ZX_DEBUG_ASSERT(display_count == 0); 74 return; 75 } 76 ZX_DEBUG_ASSERT(display_configs[0]->display_id == kDisplayId); 77 bool success; 78 if (display_configs[0]->layer_count != 1) { 79 success = false; 80 } else { 81 primary_layer_t* layer = &display_configs[0]->layers[0]->cfg.primary; 82 frame_t frame = { 83 .x_pos = 0, .y_pos = 0, .width = width_, .height = height_, 84 }; 85 success = display_configs[0]->layers[0]->type == LAYER_PRIMARY 86 && layer->transform_mode == FRAME_TRANSFORM_IDENTITY 87 && layer->image.width == width_ 88 && layer->image.height == height_ 89 && memcmp(&layer->dest_frame, &frame, sizeof(frame_t)) == 0 90 && memcmp(&layer->src_frame, &frame, sizeof(frame_t)) == 0 91 && display_configs[0]->cc_flags == 0 92 && layer->alpha_mode == ALPHA_DISABLE; 93 } 94 if (!success) { 95 layer_cfg_results[0][0] = CLIENT_MERGE_BASE; 96 for (unsigned i = 1; i < display_configs[0]->layer_count; i++) { 97 layer_cfg_results[0][i] = CLIENT_MERGE_SRC; 98 } 99 } 100} 101 102void SimpleDisplay::ApplyConfiguration(const display_config_t** display_config, 103 uint32_t display_count) { 104 bool has_image = display_count != 0 && display_config[0]->layer_count != 0; 105 void* handles[] = { kImageHandle }; 106 if (cb_) { 107 cb_->on_display_vsync(cb_ctx_, kDisplayId, zx_clock_get(ZX_CLOCK_MONOTONIC), 108 handles, has_image); 109 } 110} 111 112uint32_t SimpleDisplay::ComputeLinearStride(uint32_t width, zx_pixel_format_t format) { 113 return (width == width_ && format == format_) ? stride_ : 0; 114} 115 116zx_status_t SimpleDisplay::AllocateVmo(uint64_t size, zx_handle_t* vmo_out) { 117 zx_info_handle_count handle_count; 118 size_t actual, avail; 119 zx_status_t status = framebuffer_handle_.get_info(ZX_INFO_HANDLE_COUNT, &handle_count, 120 sizeof(handle_count), &actual, &avail); 121 if (status != ZX_OK) { 122 return status; 123 } 124 if (handle_count.handle_count != 1) { 125 return ZX_ERR_NO_RESOURCES; 126 } 127 if (size > height_ * stride_ * ZX_PIXEL_FORMAT_BYTES(format_)) { 128 return ZX_ERR_OUT_OF_RANGE; 129 } 130 return zx_handle_duplicate(framebuffer_handle_.get(), ZX_RIGHT_SAME_RIGHTS, vmo_out); 131} 132 133// implement device protocol 134 135void SimpleDisplay::DdkUnbind() { 136 DdkRemove(); 137} 138 139void SimpleDisplay::DdkRelease() { 140 delete this; 141} 142 143// implement driver object: 144 145zx_status_t SimpleDisplay::Bind(const char* name, fbl::unique_ptr<SimpleDisplay>* vbe_ptr) { 146 zx_info_handle_basic_t framebuffer_info; 147 size_t actual, avail; 148 zx_status_t status = framebuffer_handle_.get_info( 149 ZX_INFO_HANDLE_BASIC, &framebuffer_info, sizeof(framebuffer_info), &actual, &avail); 150 if (status != ZX_OK) { 151 printf("%s: failed to id framebuffer: %d\n", name, status); 152 return status; 153 } 154 framebuffer_koid_ = framebuffer_info.koid; 155 156 status = DdkAdd(name); 157 if (status != ZX_OK) { 158 return status; 159 } 160 // DevMgr now owns this pointer, release it to avoid destroying the object 161 // when device goes out of scope. 162 __UNUSED auto ptr = vbe_ptr->release(); 163 164 zxlogf(INFO, "%s: initialized display, %u x %u (stride=%u format=%08x)\n", 165 name, width_, height_, stride_, format_); 166 167 return ZX_OK; 168} 169 170SimpleDisplay::SimpleDisplay(zx_device_t* parent, zx_handle_t vmo, 171 uintptr_t framebuffer, uint64_t framebuffer_size, 172 uint32_t width, uint32_t height, 173 uint32_t stride, zx_pixel_format_t format) 174 : DeviceType(parent), framebuffer_handle_(vmo), 175 framebuffer_(framebuffer), framebuffer_size_(framebuffer_size), 176 width_(width), height_(height), stride_(stride), format_(format) { } 177 178SimpleDisplay::~SimpleDisplay() { 179 zx_vmar_unmap(zx_vmar_root_self(), framebuffer_, framebuffer_size_); 180} 181 182zx_status_t bind_simple_pci_display_bootloader(zx_device_t* dev, const char* name, uint32_t bar) { 183 uint32_t format, width, height, stride; 184 zx_status_t status = zx_framebuffer_get_info(get_root_resource(), &format, 185 &width, &height, &stride); 186 if (status != ZX_OK) { 187 printf("%s: failed to get bootloader dimensions: %d\n", name, status); 188 return ZX_ERR_NOT_SUPPORTED; 189 } 190 191 return bind_simple_pci_display(dev, name, bar, width, height, stride, format); 192} 193 194zx_status_t bind_simple_pci_display(zx_device_t* dev, const char* name, uint32_t bar, 195 uint32_t width, uint32_t height, 196 uint32_t stride, zx_pixel_format_t format) { 197 pci_protocol_t pci; 198 zx_status_t status; 199 if (device_get_protocol(dev, ZX_PROTOCOL_PCI, &pci)) { 200 return ZX_ERR_NOT_SUPPORTED; 201 } 202 203 void* framebuffer; 204 uint64_t framebuffer_size; 205 zx_handle_t framebuffer_handle; 206 // map framebuffer window 207 status = pci_map_bar(&pci, bar, ZX_CACHE_POLICY_WRITE_COMBINING, 208 &framebuffer, &framebuffer_size, &framebuffer_handle); 209 if (status != ZX_OK) { 210 printf("%s: failed to map pci bar %d: %d\n", name, bar, status); 211 return status; 212 } 213 214 fbl::AllocChecker ac; 215 fbl::unique_ptr<SimpleDisplay> display(new (&ac) SimpleDisplay( 216 dev, framebuffer_handle, (uintptr_t) framebuffer, 217 framebuffer_size, width, height, stride, format)); 218 if (!ac.check()) { 219 zx_handle_close(framebuffer_handle); 220 return ZX_ERR_NO_MEMORY; 221 } 222 223 return display->Bind(name, &display); 224} 225