You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
3.9 KiB
160 lines
3.9 KiB
/* |
|
* Copyright (c) 2019 Intel Corp. |
|
* |
|
* This code attempts to be endian-agnostic. It manipulates the framebuffer |
|
* address space only in 32-bit words (and assumes those words are 0xAARRGGBB). |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#define DT_DRV_COMPAT intel_multiboot_framebuffer |
|
|
|
#include <errno.h> |
|
|
|
#include <zephyr/arch/x86/multiboot.h> |
|
#include <zephyr/devicetree.h> |
|
#include <zephyr/drivers/display.h> |
|
#include <string.h> |
|
|
|
struct framebuf_dev_config { |
|
uint16_t width; |
|
uint16_t height; |
|
}; |
|
|
|
struct framebuf_dev_data { |
|
void *buffer; |
|
uint32_t pitch; |
|
}; |
|
|
|
static int framebuf_set_pixel_format(const struct device *dev, |
|
const enum display_pixel_format format) |
|
{ |
|
switch (format) { |
|
case PIXEL_FORMAT_ARGB_8888: |
|
return 0; |
|
default: |
|
return -ENOTSUP; |
|
} |
|
} |
|
|
|
static int framebuf_set_orientation(const struct device *dev, |
|
const enum display_orientation orientation) |
|
{ |
|
switch (orientation) { |
|
case DISPLAY_ORIENTATION_NORMAL: |
|
return 0; |
|
default: |
|
return -ENOTSUP; |
|
} |
|
} |
|
|
|
static void framebuf_get_capabilities(const struct device *dev, |
|
struct display_capabilities *caps) |
|
{ |
|
const struct framebuf_dev_config *config = dev->config; |
|
|
|
caps->x_resolution = config->width; |
|
caps->y_resolution = config->height; |
|
caps->supported_pixel_formats = PIXEL_FORMAT_ARGB_8888; |
|
caps->screen_info = 0; |
|
caps->current_pixel_format = PIXEL_FORMAT_ARGB_8888; |
|
caps->current_orientation = DISPLAY_ORIENTATION_NORMAL; |
|
} |
|
|
|
static int framebuf_write(const struct device *dev, const uint16_t x, |
|
const uint16_t y, |
|
const struct display_buffer_descriptor *desc, |
|
const void *buf) |
|
{ |
|
struct framebuf_dev_data *data = dev->data; |
|
uint32_t *dst = data->buffer; |
|
const uint32_t *src = buf; |
|
uint32_t row; |
|
|
|
dst += x; |
|
dst += (y * data->pitch); |
|
|
|
for (row = 0; row < desc->height; ++row) { |
|
(void) memcpy(dst, src, desc->width * sizeof(uint32_t)); |
|
dst += data->pitch; |
|
src += desc->pitch; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static int framebuf_read(const struct device *dev, const uint16_t x, |
|
const uint16_t y, |
|
const struct display_buffer_descriptor *desc, |
|
void *buf) |
|
{ |
|
struct framebuf_dev_data *data = dev->data; |
|
uint32_t *src = data->buffer; |
|
uint32_t *dst = buf; |
|
uint32_t row; |
|
|
|
src += x; |
|
src += (y * data->pitch); |
|
|
|
for (row = 0; row < desc->height; ++row) { |
|
(void) memcpy(dst, src, desc->width * sizeof(uint32_t)); |
|
src += data->pitch; |
|
dst += desc->pitch; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
DEVICE_API(display, framebuf_display_api) = { |
|
.write = framebuf_write, |
|
.read = framebuf_read, |
|
.get_capabilities = framebuf_get_capabilities, |
|
.set_pixel_format = framebuf_set_pixel_format, |
|
.set_orientation = framebuf_set_orientation |
|
}; |
|
|
|
static int multiboot_framebuf_init(const struct device *dev) |
|
{ |
|
const struct framebuf_dev_config *config = dev->config; |
|
struct framebuf_dev_data *data = dev->data; |
|
struct multiboot_info *info = &multiboot_info; |
|
|
|
if ((info->flags & MULTIBOOT_INFO_FLAGS_FB) && |
|
(info->fb_width >= config->width) && |
|
(info->fb_height >= config->height) && |
|
(info->fb_bpp == 32) && (info->fb_addr_hi == 0)) { |
|
/* |
|
* We have a usable multiboot framebuffer - it is 32 bpp |
|
* and at least as large as the requested dimensions. Compute |
|
* the pitch and adjust the start address center our canvas. |
|
*/ |
|
|
|
uint16_t adj_x; |
|
uint16_t adj_y; |
|
uint32_t *buffer; |
|
|
|
adj_x = info->fb_width - config->width; |
|
adj_y = info->fb_height - config->height; |
|
data->pitch = (info->fb_pitch / 4) + adj_x; |
|
adj_x /= 2U; |
|
adj_y /= 2U; |
|
buffer = (uint32_t *) (uintptr_t) info->fb_addr_lo; |
|
buffer += adj_x; |
|
buffer += adj_y * data->pitch; |
|
data->buffer = buffer; |
|
return 0; |
|
} else { |
|
return -ENOTSUP; |
|
} |
|
} |
|
|
|
static const struct framebuf_dev_config config = { |
|
.width = DT_INST_PROP(0, width), |
|
.height = DT_INST_PROP(0, height), |
|
}; |
|
|
|
static struct framebuf_dev_data data; |
|
|
|
DEVICE_DT_INST_DEFINE(0, multiboot_framebuf_init, NULL, &data, &config, |
|
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, |
|
&framebuf_display_api);
|
|
|