blob: d0533cb18ff78feadff08ccd7cdb3cfcdf3c97ad [file] [log] [blame]
// Copyright 2017 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 <ddk/debug.h>
#include <cpuid.h>
#include <string.h>
#include <zx/vmar.h>
#include <zx/vmo.h>
#include "display-device.h"
#include "intel-i915.h"
#include "registers.h"
namespace i915 {
DisplayDevice::DisplayDevice(Controller* controller)
: DisplayDeviceType(controller->zxdev()), controller_(controller) {}
DisplayDevice::~DisplayDevice() {
if (framebuffer_) {
zx::vmar::root_self().unmap(framebuffer_, framebuffer_size_);
}
}
// implement device protocol
void DisplayDevice::DdkRelease() {
delete this;
}
// implement display protocol
zx_status_t DisplayDevice::SetMode(zx_display_info_t* info) {
return ZX_ERR_NOT_SUPPORTED;
}
zx_status_t DisplayDevice::GetMode(zx_display_info_t* info) {
assert(info);
memcpy(info, &info_, sizeof(zx_display_info_t));
return ZX_OK;
}
zx_status_t DisplayDevice::GetFramebuffer(void** framebuffer) {
assert(framebuffer);
*framebuffer = reinterpret_cast<void*>(framebuffer_);
return ZX_OK;
}
void DisplayDevice::Flush() {
// TODO(ZX-1413): Use uncacheable memory for fb or use some zx cache primitive when available
unsigned int a, b, c, d;
if (!__get_cpuid(1, &a, &b, &c, &d)) {
return;
}
uint64_t cacheline_size = 8 * ((b >> 8) & 0xff);
uint8_t* p = reinterpret_cast<uint8_t*>(framebuffer_ & ~(cacheline_size - 1));
uint8_t* end = reinterpret_cast<uint8_t*>(framebuffer_ + framebuffer_size_);
while (p < end) {
__builtin_ia32_clflush(p);
p += cacheline_size;
}
}
bool DisplayDevice::Init() {
if (!Init(&info_)) {
return false;
}
framebuffer_size_ = info_.stride * info_.height * info_.pixelsize;
zx_status_t status = zx::vmo::create(framebuffer_size_, 0, &framebuffer_vmo_);
if (status != ZX_OK) {
zxlogf(ERROR, "i915: Failed to allocate framebuffer (%d)\n", status);
return false;
}
status = framebuffer_vmo_.op_range(ZX_VMO_OP_COMMIT, 0, framebuffer_size_, nullptr, 0);
if (status != ZX_OK) {
zxlogf(ERROR, "i915: Failed to commit VMO (%d)\n", status);
return false;
}
status = zx::vmar::root_self().map(0, framebuffer_vmo_, 0, framebuffer_size_,
ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &framebuffer_);
if (status != ZX_OK) {
zxlogf(ERROR, "i915: Failed to map framebuffer (%d)\n", status);
return false;
}
uint32_t fb_gfx_addr;
if (!controller_->gtt()->Insert(controller_->mmio_space(),
&framebuffer_vmo_, framebuffer_size_,
registers::PlaneSurface::kTrailingPtePadding, &fb_gfx_addr)) {
zxlogf(ERROR, "i915: Failed to allocate gfx address for framebuffer\n");
return false;
}
// TODO(ZX-1413): set the stride and format
auto plane_surface = registers::PlaneSurface::Get().ReadFrom(controller_->mmio_space());
plane_surface.surface_base_addr().set(fb_gfx_addr >> plane_surface.kRShiftCount);
plane_surface.WriteTo(controller_->mmio_space());
return true;
}
} // namespace i915