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:
Charles E. Youse 2019-05-29 10:52:31 -07:00 committed by Andrew Boie
parent a1a3a4fced
commit 4c63e29aec
9 changed files with 275 additions and 31 deletions

View file

@ -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

View file

@ -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"
# #

View file

@ -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

View file

@ -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 */

View file

@ -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)

View file

@ -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

View 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
};

View file

@ -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)

View 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_ */