arch/x86: drivers/display: add framebuffer driver w/ multiboot support
A basic display driver is added for a generic 32-bpp framebuffer. Glue logic is added to the x86 arch to request the intitialization of a linear framebuffer by the Multiboot loader (GRUB) and connect it to this generic driver. Signed-off-by: Charles E. Youse <charles.youse@intel.com>
This commit is contained in:
parent
a1a3a4fced
commit
4c63e29aec
|
@ -113,6 +113,7 @@
|
||||||
/drivers/clock_control/*stm32f4* @rsalveti @idlethread
|
/drivers/clock_control/*stm32f4* @rsalveti @idlethread
|
||||||
/drivers/counter/ @nordic-krch
|
/drivers/counter/ @nordic-krch
|
||||||
/drivers/display/ @vanwinkeljan
|
/drivers/display/ @vanwinkeljan
|
||||||
|
/drivers/display/display_framebuf.c @gnuless
|
||||||
/drivers/dma/*sam0* @Sizurka
|
/drivers/dma/*sam0* @Sizurka
|
||||||
/drivers/ethernet/ @jukkar @tbursztyka @pfalcon
|
/drivers/ethernet/ @jukkar @tbursztyka @pfalcon
|
||||||
/drivers/flash/ @nashif
|
/drivers/flash/ @nashif
|
||||||
|
@ -217,6 +218,7 @@
|
||||||
/include/device.h @wentongwu @nashif
|
/include/device.h @wentongwu @nashif
|
||||||
/include/display.h @vanwinkeljan
|
/include/display.h @vanwinkeljan
|
||||||
/include/display/ @vanwinkeljan
|
/include/display/ @vanwinkeljan
|
||||||
|
/include/display/framebuf.h @gnuless
|
||||||
/include/drivers/bluetooth/ @joerchan @jhedberg @Vudentz
|
/include/drivers/bluetooth/ @joerchan @jhedberg @Vudentz
|
||||||
/include/drivers/led/ht16k33.h @henrikbrixandersen
|
/include/drivers/led/ht16k33.h @henrikbrixandersen
|
||||||
/include/drivers/modem/ @mike-scott
|
/include/drivers/modem/ @mike-scott
|
||||||
|
|
|
@ -30,6 +30,29 @@ config X86_MULTIBOOT_INFO
|
||||||
display driver) need to refer to information in this structure,
|
display driver) need to refer to information in this structure,
|
||||||
and so set this option to preserve the data in a permanent location.
|
and so set this option to preserve the data in a permanent location.
|
||||||
|
|
||||||
|
if X86_MULTIBOOT
|
||||||
|
|
||||||
|
config X86_MULTIBOOT_FRAMEBUF
|
||||||
|
bool "Multiboot framebuffer support"
|
||||||
|
default n
|
||||||
|
select DISPLAY
|
||||||
|
select FRAMEBUF_DISPLAY
|
||||||
|
select X86_MULTIBOOT_INFO
|
||||||
|
|
||||||
|
if X86_MULTIBOOT_FRAMEBUF
|
||||||
|
|
||||||
|
config X86_MULTIBOOT_FRAMEBUF_X
|
||||||
|
int "Multiboot framebuffer X pixels"
|
||||||
|
default 640
|
||||||
|
|
||||||
|
config X86_MULTIBOOT_FRAMEBUF_Y
|
||||||
|
int "Multiboot framebuffer Y pixels"
|
||||||
|
default 480
|
||||||
|
|
||||||
|
endif # X86_MULTIBOOT_FRAMEBUF
|
||||||
|
|
||||||
|
endif # X86_MULTIBOOT
|
||||||
|
|
||||||
source "arch/x86/core/Kconfig"
|
source "arch/x86/core/Kconfig"
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -507,34 +507,26 @@ z_x86_idt:
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_X86_MULTIBOOT
|
#ifdef CONFIG_X86_MULTIBOOT
|
||||||
/* Multiboot header definition is needed for some bootloaders */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The multiboot header must be in the first 8 Kb of the kernel image
|
* The multiboot header must be in the first 8 Kb of the kernel image
|
||||||
* (not including the ELF section header(s)) and be aligned on a
|
* (not including the ELF section header(s)) and be aligned on a
|
||||||
* 4 byte boundary.
|
* 4 byte boundary. See include/arch/x86/multiboot.h for more info.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.balign 4,0x90
|
.balign 4,0x90
|
||||||
|
|
||||||
.long X86_MULTIBOOT_HEADER_MAGIC
|
.long X86_MULTIBOOT_HEADER_MAGIC
|
||||||
|
.long X86_MULTIBOOT_HEADER_FLAGS
|
||||||
|
.long -(X86_MULTIBOOT_HEADER_MAGIC + X86_MULTIBOOT_HEADER_FLAGS)
|
||||||
|
|
||||||
/*
|
#ifdef CONFIG_X86_MULTIBOOT_FRAMEBUF
|
||||||
* Flags = no bits are being set, specifically bit 16 is not being
|
.fill 5,4,0 /* (unused exec layout) */
|
||||||
* set since the supplied kernel image is an ELF file, and the
|
.long 0 /* linear graphics mode */
|
||||||
* multiboot loader shall use the information from the program and
|
.long CONFIG_X86_MULTIBOOT_FRAMEBUF_X /* width */
|
||||||
* section header to load and boot the kernel image.
|
.long CONFIG_X86_MULTIBOOT_FRAMEBUF_Y /* height */
|
||||||
*/
|
.long 32 /* depth */
|
||||||
|
#endif /* CONFIG_X86_MULTIBOOT_FRAMEBUF */
|
||||||
|
|
||||||
.long 0x00000000
|
|
||||||
|
|
||||||
/*
|
|
||||||
* checksum = 32-bit unsigned value which, when added to the other
|
|
||||||
* magic fields (i.e. "magic" and "flags"), must have a 32-bit
|
|
||||||
* unsigned sum of zero.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.long -(X86_MULTIBOOT_HEADER_MAGIC + 0)
|
|
||||||
#endif /* CONFIG_X86_MULTIBOOT */
|
#endif /* CONFIG_X86_MULTIBOOT */
|
||||||
|
|
||||||
#ifdef CONFIG_SET_GDT
|
#ifdef CONFIG_SET_GDT
|
||||||
|
|
|
@ -11,4 +11,59 @@
|
||||||
|
|
||||||
struct x86_multiboot_info x86_multiboot_info;
|
struct x86_multiboot_info x86_multiboot_info;
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_MULTIBOOT_FRAMEBUF
|
||||||
|
|
||||||
|
#include <display/framebuf.h>
|
||||||
|
|
||||||
|
static struct framebuf_dev_data multiboot_framebuf_data = {
|
||||||
|
.width = CONFIG_X86_MULTIBOOT_FRAMEBUF_X,
|
||||||
|
.height = CONFIG_X86_MULTIBOOT_FRAMEBUF_Y
|
||||||
|
};
|
||||||
|
|
||||||
|
static int multiboot_framebuf_init(struct device *dev)
|
||||||
|
{
|
||||||
|
struct framebuf_dev_data *data = FRAMEBUF_DATA(dev);
|
||||||
|
struct x86_multiboot_info *info = &x86_multiboot_info;
|
||||||
|
|
||||||
|
if ((info->flags & X86_MULTIBOOT_INFO_FLAGS_FB) &&
|
||||||
|
(info->fb_width >= CONFIG_X86_MULTIBOOT_FRAMEBUF_X) &&
|
||||||
|
(info->fb_height >= CONFIG_X86_MULTIBOOT_FRAMEBUF_Y) &&
|
||||||
|
(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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
u16_t adj_x;
|
||||||
|
u16_t adj_y;
|
||||||
|
u32_t *buffer;
|
||||||
|
|
||||||
|
adj_x = info->fb_width - CONFIG_X86_MULTIBOOT_FRAMEBUF_X;
|
||||||
|
adj_y = info->fb_height - CONFIG_X86_MULTIBOOT_FRAMEBUF_Y;
|
||||||
|
buffer = (uint32_t *) info->fb_addr_lo;
|
||||||
|
data->pitch = (info->fb_pitch / 4) + adj_x;
|
||||||
|
adj_x /= 2;
|
||||||
|
adj_y /= 2;
|
||||||
|
buffer = (uint32_t *) info->fb_addr_lo;
|
||||||
|
buffer += adj_x;
|
||||||
|
buffer += adj_y * data->pitch;
|
||||||
|
data->buffer = buffer;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEVICE_AND_API_INIT(multiboot_framebuf,
|
||||||
|
"FRAMEBUF",
|
||||||
|
multiboot_framebuf_init,
|
||||||
|
&multiboot_framebuf_data,
|
||||||
|
NULL,
|
||||||
|
PRE_KERNEL_1,
|
||||||
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||||
|
&framebuf_display_api);
|
||||||
|
|
||||||
|
#endif /* CONFIG_X86_MULTIBOOT_FRAMEBUF */
|
||||||
|
|
||||||
#endif /* CONFIG_X86_MULTIBOOT_INFO */
|
#endif /* CONFIG_X86_MULTIBOOT_INFO */
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_DISPLAY_MCUX_ELCDIF display_mcux_elcdif.c)
|
zephyr_sources_ifdef(CONFIG_DISPLAY_MCUX_ELCDIF display_mcux_elcdif.c)
|
||||||
zephyr_sources_ifdef(CONFIG_GROVE_LCD_RGB grove_lcd_rgb.c)
|
zephyr_sources_ifdef(CONFIG_GROVE_LCD_RGB grove_lcd_rgb.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_SSD1306 ssd1306.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_SSD1673 ssd1673.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_SDL_DISPLAY display_sdl.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_DUMMY_DISPLAY display_dummy.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_FRAMEBUF_DISPLAY display_framebuf.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_ILI9340 display_ili9340.c)
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_MICROBIT_DISPLAY
|
zephyr_sources_ifdef(CONFIG_MICROBIT_DISPLAY
|
||||||
mb_display.c
|
mb_display.c
|
||||||
mb_font.c
|
mb_font.c
|
||||||
)
|
)
|
||||||
zephyr_sources_ifdef(CONFIG_ILI9340 display_ili9340.c)
|
|
||||||
zephyr_sources_ifdef(CONFIG_ILI9340_LCD_ADAFRUIT_1480
|
zephyr_sources_ifdef(CONFIG_ILI9340_LCD_ADAFRUIT_1480
|
||||||
display_ili9340_adafruit_1480.c
|
display_ili9340_adafruit_1480.c
|
||||||
)
|
)
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_ILI9340_LCD_SEEED_TFTV2
|
zephyr_sources_ifdef(CONFIG_ILI9340_LCD_SEEED_TFTV2
|
||||||
display_ili9340_seeed_tftv2.c
|
display_ili9340_seeed_tftv2.c
|
||||||
)
|
)
|
||||||
zephyr_sources_ifdef(CONFIG_SSD1306 ssd1306.c)
|
|
||||||
zephyr_sources_ifdef(CONFIG_SSD1673 ssd1673.c)
|
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_SDL_DISPLAY display_sdl.c)
|
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_DUMMY_DISPLAY display_dummy.c)
|
|
||||||
|
|
||||||
|
|
|
@ -22,11 +22,15 @@ source "drivers/display/Kconfig.mcux_elcdif"
|
||||||
source "drivers/display/Kconfig.microbit"
|
source "drivers/display/Kconfig.microbit"
|
||||||
source "drivers/display/Kconfig.ili9340"
|
source "drivers/display/Kconfig.ili9340"
|
||||||
source "drivers/display/Kconfig.sdl"
|
source "drivers/display/Kconfig.sdl"
|
||||||
|
|
||||||
source "drivers/display/Kconfig.ssd1306"
|
source "drivers/display/Kconfig.ssd1306"
|
||||||
|
|
||||||
source "drivers/display/Kconfig.ssd1673"
|
source "drivers/display/Kconfig.ssd1673"
|
||||||
|
|
||||||
source "drivers/display/Kconfig.dummy"
|
source "drivers/display/Kconfig.dummy"
|
||||||
|
|
||||||
|
config FRAMEBUF_DISPLAY
|
||||||
|
# Hidden, selected by client drivers.
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
Enable framebuffer-based display 'helper' driver.
|
||||||
|
|
||||||
endif # DISPLAY
|
endif # DISPLAY
|
||||||
|
|
134
drivers/display/display_framebuf.c
Normal file
134
drivers/display/display_framebuf.c
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel Corp.
|
||||||
|
*
|
||||||
|
* This is most of the display driver for a "standard" 32-bpp framebuffer.
|
||||||
|
* Device-specific drivers must still create the device instance and initialize
|
||||||
|
* it accordingly, but this driver implements most/all of the API functions.
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <display.h>
|
||||||
|
#include <display/framebuf.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static int framebuf_blanking_on(const struct device *dev)
|
||||||
|
{
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int framebuf_blanking_off(const struct device *dev)
|
||||||
|
{
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *framebuf_get_framebuffer(const struct device *dev)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int framebuf_set_brightness(const struct device *dev,
|
||||||
|
const u8_t brightness)
|
||||||
|
{
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int framebuf_set_contrast(const struct device *dev,
|
||||||
|
const u8_t contrast)
|
||||||
|
{
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct framebuf_dev_data *data = FRAMEBUF_DATA(dev);
|
||||||
|
|
||||||
|
caps->x_resolution = data->width;
|
||||||
|
caps->y_resolution = data->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 u16_t x,
|
||||||
|
const u16_t y,
|
||||||
|
const struct display_buffer_descriptor *desc,
|
||||||
|
const void *buf)
|
||||||
|
{
|
||||||
|
struct framebuf_dev_data *data = FRAMEBUF_DATA(dev);
|
||||||
|
u32_t *dst = data->buffer;
|
||||||
|
const u32_t *src = buf;
|
||||||
|
u32_t row;
|
||||||
|
|
||||||
|
dst += x;
|
||||||
|
dst += (y * data->pitch);
|
||||||
|
|
||||||
|
for (row = 0; row < desc->height; ++row) {
|
||||||
|
(void) memcpy(dst, src, desc->width * sizeof(u32_t));
|
||||||
|
dst += data->pitch;
|
||||||
|
src += desc->pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int framebuf_read(const struct device *dev, const u16_t x,
|
||||||
|
const u16_t y,
|
||||||
|
const struct display_buffer_descriptor *desc,
|
||||||
|
void *buf)
|
||||||
|
{
|
||||||
|
struct framebuf_dev_data *data = FRAMEBUF_DATA(dev);
|
||||||
|
u32_t *src = data->buffer;
|
||||||
|
u32_t *dst = buf;
|
||||||
|
u32_t row;
|
||||||
|
|
||||||
|
src += x;
|
||||||
|
src += (y * data->pitch);
|
||||||
|
|
||||||
|
for (row = 0; row < desc->height; ++row) {
|
||||||
|
(void) memcpy(dst, src, desc->width * sizeof(u32_t));
|
||||||
|
src += data->pitch;
|
||||||
|
dst += desc->pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct display_driver_api framebuf_display_api = {
|
||||||
|
.blanking_on = framebuf_blanking_on,
|
||||||
|
.blanking_off = framebuf_blanking_off,
|
||||||
|
.write = framebuf_write,
|
||||||
|
.read = framebuf_read,
|
||||||
|
.get_framebuffer = framebuf_get_framebuffer,
|
||||||
|
.set_brightness = framebuf_set_brightness,
|
||||||
|
.set_contrast = framebuf_set_contrast,
|
||||||
|
.get_capabilities = framebuf_get_capabilities,
|
||||||
|
.set_pixel_format = framebuf_set_pixel_format,
|
||||||
|
.set_orientation = framebuf_set_orientation
|
||||||
|
};
|
|
@ -42,6 +42,18 @@ extern struct x86_multiboot_info x86_multiboot_info;
|
||||||
#define X86_MULTIBOOT_HEADER_MAGIC 0x1BADB002
|
#define X86_MULTIBOOT_HEADER_MAGIC 0x1BADB002
|
||||||
#define X86_MULTIBOOT_EAX_MAGIC 0x2BADB002
|
#define X86_MULTIBOOT_EAX_MAGIC 0x2BADB002
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Typically, we put no flags in the multiboot header, as it exists solely
|
||||||
|
* to reassure the loader that we're a valid binary. The exception to this
|
||||||
|
* is when we want the loader to configure the framebuffer for us.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef CONFIG_X86_MULTIBOOT_FRAMEBUF
|
||||||
|
#define X86_MULTIBOOT_HEADER_FLAGS 4
|
||||||
|
#else
|
||||||
|
#define X86_MULTIBOOT_HEADER_FLAGS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
/* The fb_* fields are valid if X86_MULTIBOOT_INFO_FLAGS_FB is set. */
|
/* The fb_* fields are valid if X86_MULTIBOOT_INFO_FLAGS_FB is set. */
|
||||||
|
|
||||||
#define X86_MULTIBOOT_INFO_FLAGS_FB (1 << 12)
|
#define X86_MULTIBOOT_INFO_FLAGS_FB (1 << 12)
|
||||||
|
|
23
include/display/framebuf.h
Normal file
23
include/display/framebuf.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Intel Corp.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_DISPLAY_FRAMEBUF_H_
|
||||||
|
#define ZEPHYR_INCLUDE_DISPLAY_FRAMEBUF_H_
|
||||||
|
|
||||||
|
#include <display.h>
|
||||||
|
|
||||||
|
extern const struct display_driver_api framebuf_display_api;
|
||||||
|
|
||||||
|
struct framebuf_dev_data {
|
||||||
|
void *buffer;
|
||||||
|
u32_t pitch;
|
||||||
|
u16_t width;
|
||||||
|
u16_t height;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define FRAMEBUF_DATA(dev) ((struct framebuf_dev_data *) ((dev)->driver_data))
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_DISPLAY_FRAMEBUF_H_ */
|
Loading…
Reference in a new issue