[vim][display] Implement display ioctls
The get_fb ioctl can grab the real framebuffer, so an unnecessary copy
is avoided. This code is mostly temporary until the real GPU display API
is implemented.
This is a reland of 1229a100c04db0ec1d3fb3fe545252f9d4e808ad with a fix
for cache flushing through the ioctl.
Change-Id: I3965399ac00fc23d580f84e33cfd604d2a232276
diff --git a/system/dev/display/vim-display/vim-display.c b/system/dev/display/vim-display/vim-display.c
index 755f9b3..d0e0418 100644
--- a/system/dev/display/vim-display/vim-display.c
+++ b/system/dev/display/vim-display/vim-display.c
@@ -2,25 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "vim-display.h"
+#include "hdmitx.h"
#include <assert.h>
+#include <ddk/binding.h>
+#include <ddk/debug.h>
+#include <ddk/device.h>
+#include <ddk/driver.h>
+#include <ddk/io-buffer.h>
+#include <ddk/protocol/display.h>
+#include <ddk/protocol/platform-defs.h>
+#include <ddk/protocol/platform-device.h>
+#include <hw/reg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <ddk/device.h>
-#include <ddk/driver.h>
-#include <ddk/debug.h>
-#include <ddk/binding.h>
-#include <ddk/io-buffer.h>
-#include <ddk/protocol/display.h>
-#include <ddk/protocol/platform-defs.h>
-#include <ddk/protocol/platform-device.h>
-#include <zircon/syscalls.h>
#include <zircon/assert.h>
-#include <hw/reg.h>
-#include "vim-display.h"
-#include "hdmitx.h"
+#include <zircon/device/display.h>
+#include <zircon/syscalls.h>
/* Default formats */
static const uint8_t _ginput_color_format = HDMI_COLOR_FORMAT_444;
@@ -55,18 +56,44 @@
return ZX_OK;
}
-static void vc_flush_framebuffer(void* ctx) {
- vim2_display_t* display = ctx;
+static void flush_framebuffer(vim2_display_t* display) {
pdev_vmo_buffer_cache_flush(&display->fbuffer, 0,
(display->disp_info.stride * display->disp_info.height *
ZX_PIXEL_FORMAT_BYTES(display->disp_info.format)));
}
+static void vc_flush_framebuffer(void* ctx) {
+ flush_framebuffer(ctx);
+}
+
+static void vc_display_set_ownership_change_callback(void* ctx, zx_display_cb_t callback,
+ void* cookie) {
+ vim2_display_t* display = ctx;
+ display->ownership_change_callback = callback;
+ display->ownership_change_cookie = cookie;
+}
+
+static void vc_display_acquire_or_release_display(void* ctx, bool acquire) {
+ vim2_display_t* display = ctx;
+
+ if (acquire) {
+ display->console_visible = true;
+ if (display->ownership_change_callback)
+ display->ownership_change_callback(true, display->ownership_change_cookie);
+ } else if (!acquire) {
+ display->console_visible = false;
+ if (display->ownership_change_callback)
+ display->ownership_change_callback(false, display->ownership_change_cookie);
+ }
+}
+
static display_protocol_ops_t vc_display_proto = {
.set_mode = vc_set_mode,
.get_mode = vc_get_mode,
.get_framebuffer = vc_get_framebuffer,
- .flush = vc_flush_framebuffer
+ .flush = vc_flush_framebuffer,
+ .set_ownership_change_callback = vc_display_set_ownership_change_callback,
+ .acquire_or_release_display = vc_display_acquire_or_release_display,
};
static void display_release(void* ctx) {
@@ -92,8 +119,78 @@
.release = display_release,
};
+struct display_client_device {
+ vim2_display_t* display;
+ zx_device_t* device;
+};
+
+static zx_status_t display_client_ioctl(void* ctx, uint32_t op, const void* in_buf, size_t in_len,
+ void* out_buf, size_t out_len, size_t* out_actual) {
+ struct display_client_device* client_struct = ctx;
+ vim2_display_t* display = client_struct->display;
+ switch (op) {
+ case IOCTL_DISPLAY_GET_FB: {
+ if (out_len < sizeof(ioctl_display_get_fb_t))
+ return ZX_ERR_INVALID_ARGS;
+ ioctl_display_get_fb_t* description = (ioctl_display_get_fb_t*)(out_buf);
+ zx_status_t status = zx_handle_duplicate(display->fbuffer.handle, ZX_RIGHT_SAME_RIGHTS, &description->vmo);
+ if (status != ZX_OK)
+ return ZX_ERR_NO_RESOURCES;
+ description->info = display->disp_info;
+ *out_actual = sizeof(ioctl_display_get_fb_t);
+ if (display->ownership_change_callback)
+ display->ownership_change_callback(false, display->ownership_change_cookie);
+ return ZX_OK;
+ }
+ case IOCTL_DISPLAY_FLUSH_FB:
+ case IOCTL_DISPLAY_FLUSH_FB_REGION:
+ flush_framebuffer(display);
+ return ZX_OK;
+ default:
+ DISP_ERROR("Invalid ioctl %d\n", op);
+ return ZX_ERR_INVALID_ARGS;
+ }
+}
+
+static zx_status_t display_client_close(void* ctx, uint32_t flags) {
+ struct display_client_device* client_struct = ctx;
+ vim2_display_t* display = client_struct->display;
+ if (display->ownership_change_callback)
+ display->ownership_change_callback(true, display->ownership_change_cookie);
+ free(ctx);
+ return ZX_OK;
+}
+
+static zx_protocol_device_t client_device_proto = {
+ .version = DEVICE_OPS_VERSION,
+ .ioctl = display_client_ioctl,
+ .close = display_client_close,
+};
+
+static zx_status_t vc_open(void* ctx, zx_device_t** dev_out, uint32_t flags) {
+ struct display_client_device* s = calloc(1, sizeof(struct display_client_device));
+
+ s->display = ctx;
+
+ device_add_args_t vc_fbuff_args = {
+ .version = DEVICE_ADD_ARGS_VERSION,
+ .name = "vim2-display",
+ .ctx = s,
+ .ops = &client_device_proto,
+ .flags = DEVICE_ADD_INSTANCE,
+ };
+ zx_status_t status = device_add(s->display->fbdevice, &vc_fbuff_args, &s->device);
+ if (status != ZX_OK) {
+ free(s);
+ return status;
+ }
+ *dev_out = s->device;
+ return ZX_OK;
+}
+
static zx_protocol_device_t display_device_proto = {
.version = DEVICE_OPS_VERSION,
+ .open = vc_open,
};
static zx_status_t setup_hdmi(vim2_display_t* display)
@@ -118,12 +215,13 @@
display->disp_info.width = display->p->timings.hactive;
display->disp_info.height = display->p->timings.vactive;
display->disp_info.stride = display->p->timings.hactive;
+ display->disp_info.pixelsize = ZX_PIXEL_FORMAT_BYTES(display->disp_info.format);
- status = pdev_map_contig_buffer(&display->pdev,
- (display->disp_info.stride * display->disp_info.height *
- ZX_PIXEL_FORMAT_BYTES(display->disp_info.format)),
- 0, ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, ZX_CACHE_POLICY_CACHED,
- &display->fbuffer);
+ status = pdev_map_contig_buffer(&display->pdev,
+ (display->disp_info.stride * display->disp_info.height *
+ ZX_PIXEL_FORMAT_BYTES(display->disp_info.format)),
+ 0, ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, ZX_CACHE_POLICY_CACHED,
+ &display->fbuffer);
if (status != ZX_OK) {
return status;
}
@@ -219,6 +317,7 @@
}
display->parent = parent;
+ display->console_visible = true;
zx_status_t status = device_get_protocol(parent, ZX_PROTOCOL_PLATFORM_DEV, &display->pdev);
if (status != ZX_OK) {
diff --git a/system/dev/display/vim-display/vim-display.h b/system/dev/display/vim-display/vim-display.h
index 31854c0..091808f 100644
--- a/system/dev/display/vim-display/vim-display.h
+++ b/system/dev/display/vim-display/vim-display.h
@@ -4,13 +4,15 @@
#pragma once
+#include "edid.h"
#include <assert.h>
+#include <ddk/protocol/display.h>
+#include <ddk/protocol/gpio.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "edid.h"
-#include <ddk/protocol/gpio.h>
+#include <zircon/device/display.h>
#define DISP_ERROR(fmt, ...) zxlogf(ERROR, "[%s %d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
#define DISP_INFO(fmt, ...) zxlogf(INFO, "[%s %d]" fmt, __func__, __LINE__, ##__VA_ARGS__)
@@ -52,7 +54,9 @@
disp_timing_t std_disp_timing;
disp_timing_t pref_disp_timing;
-
+ bool console_visible;
+ zx_display_cb_t ownership_change_callback;
+ void* ownership_change_cookie;
} vim2_display_t;
zx_status_t configure_canvas(vim2_display_t* display);
@@ -60,4 +64,4 @@
void osd_debug_dump_register_all(vim2_display_t* display);
void osd_dump(vim2_display_t* display);
zx_status_t get_preferred_res(vim2_display_t* display, uint16_t edid_buf_size);
-struct hdmi_param** get_supported_formats(void);
\ No newline at end of file
+struct hdmi_param** get_supported_formats(void);