summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/Kconfig40
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/video-uclass.c228
-rw-r--r--include/dm/uclass-id.h1
-rw-r--r--include/video.h168
5 files changed, 432 insertions, 6 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index caf1efcbb3..946d958f9f 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -4,6 +4,46 @@
menu "Graphics support"
+config DM_VIDEO
+ bool "Enable driver model support for LCD/video"
+ depends on DM
+ help
+ This enables driver model for LCD and video devices. These support
+ a bitmap display of various sizes and depths which can be drawn on
+ to display a command-line console or splash screen. Enabling this
+ option compiles in the video uclass and routes all LCD/video access
+ through this.
+
+config VIDEO_BPP8
+ bool "Support 8-bit-per-pixel displays"
+ depends on DM_VIDEO
+ default y if DM_VIDEO
+ help
+ Support drawing text and bitmaps onto a 8-bit-per-pixel display.
+ Enabling this will include code to support this display. Without
+ this option, such displays will not be supported and console output
+ will be empty.
+
+config VIDEO_BPP16
+ bool "Support 16-bit-per-pixel displays"
+ depends on DM_VIDEO
+ default y if DM_VIDEO
+ help
+ Support drawing text and bitmaps onto a 16-bit-per-pixel display.
+ Enabling this will include code to support this display. Without
+ this option, such displays will not be supported and console output
+ will be empty.
+
+config VIDEO_BPP32
+ bool "Support 32-bit-per-pixel displays"
+ depends on DM_VIDEO
+ default y if DM_VIDEO
+ help
+ Support drawing text and bitmaps onto a 32-bit-per-pixel display.
+ Enabling this will include code to support this display. Without
+ this option, such displays will not be supported and console output
+ will be empty.
+
config VIDEO_VESA
bool "Enable VESA video driver support"
default n
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index e85fd8a677..71920130e4 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -7,6 +7,7 @@
ifdef CONFIG_DM
obj-$(CONFIG_DISPLAY_PORT) += dp-uclass.o
+obj-$(CONFIG_DM_VIDEO) += video-uclass.o
endif
obj-$(CONFIG_ATI_RADEON_FB) += ati_radeon_fb.o videomodes.o
diff --git a/drivers/video/video-uclass.c b/drivers/video/video-uclass.c
new file mode 100644
index 0000000000..1615889626
--- /dev/null
+++ b/drivers/video/video-uclass.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2015 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mapmem.h>
+#include <stdio_dev.h>
+#include <video.h>
+#include <video_console.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include <dm/uclass-internal.h>
+#ifdef CONFIG_SANDBOX
+#include <asm/sdl.h>
+#endif
+
+/*
+ * Theory of operation:
+ *
+ * Before relocation each device is bound. The driver for each device must
+ * set the @align and @size values in struct video_uc_platdata. This
+ * information represents the requires size and alignment of the frame buffer
+ * for the device. The values can be an over-estimate but cannot be too
+ * small. The actual values will be suppled (in the same manner) by the bind()
+ * method after relocation.
+ *
+ * This information is then picked up by video_reserve() which works out how
+ * much memory is needed for all devices. This is allocated between
+ * gd->video_bottom and gd->video_top.
+ *
+ * After relocation the same process occurs. The driver supplies the same
+ * @size and @align information and this time video_post_bind() checks that
+ * the drivers does not overflow the allocated memory.
+ *
+ * The frame buffer address is actually set (to plat->base) in
+ * video_post_probe(). This function also clears the frame buffer and
+ * allocates a suitable text console device. This can then be used to write
+ * text to the video device.
+ */
+DECLARE_GLOBAL_DATA_PTR;
+
+static ulong alloc_fb(struct udevice *dev, ulong *addrp)
+{
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ ulong base, align, size;
+
+ align = plat->align ? plat->align : 1 << 20;
+ base = *addrp - plat->size;
+ base &= ~(align - 1);
+ plat->base = base;
+ size = *addrp - base;
+ *addrp = base;
+
+ return size;
+}
+
+int video_reserve(ulong *addrp)
+{
+ struct udevice *dev;
+ ulong size;
+
+ gd->video_top = *addrp;
+ for (uclass_find_first_device(UCLASS_VIDEO, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ size = alloc_fb(dev, addrp);
+ debug("%s: Reserving %lx bytes at %lx for video device '%s'\n",
+ __func__, size, *addrp, dev->name);
+ }
+ gd->video_bottom = *addrp;
+ debug("Video frame buffers from %lx to %lx\n", gd->video_bottom,
+ gd->video_top);
+
+ return 0;
+}
+
+static int video_clear(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ if (priv->bpix == VIDEO_BPP32) {
+ u32 *ppix = priv->fb;
+ u32 *end = priv->fb + priv->fb_size;
+
+ while (ppix < end)
+ *ppix++ = priv->colour_bg;
+ } else {
+ memset(priv->fb, priv->colour_bg, priv->fb_size);
+ }
+
+ return 0;
+}
+
+/* Flush video activity to the caches */
+void video_sync(struct udevice *vid)
+{
+ /*
+ * flush_dcache_range() is declared in common.h but it seems that some
+ * architectures do not actually implement it. Is there a way to find
+ * out whether it exists? For now, ARM is safe.
+ */
+#if defined(CONFIG_ARM) && !defined(CONFIG_SYS_DCACHE_OFF)
+ struct video_priv *priv = dev_get_uclass_priv(vid);
+
+ if (priv->flush_dcache) {
+ flush_dcache_range((ulong)priv->fb,
+ (ulong)priv->fb + priv->fb_size);
+ }
+#elif defined(CONFIG_VIDEO_SANDBOX_SDL)
+ struct video_priv *priv = dev_get_uclass_priv(vid);
+ static ulong last_sync;
+
+ if (get_timer(last_sync) > 10) {
+ sandbox_sdl_sync(priv->fb);
+ last_sync = get_timer(0);
+ }
+#endif
+}
+
+void video_sync_all(void)
+{
+ struct udevice *dev;
+
+ for (uclass_find_first_device(UCLASS_VIDEO, &dev);
+ dev;
+ uclass_find_next_device(&dev)) {
+ if (device_active(dev))
+ video_sync(dev);
+ }
+}
+
+int video_get_xsize(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ return priv->xsize;
+}
+
+int video_get_ysize(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ return priv->ysize;
+}
+
+/* Set up the colour map */
+static int video_pre_probe(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ priv->cmap = calloc(256, sizeof(ushort));
+ if (!priv->cmap)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int video_pre_remove(struct udevice *dev)
+{
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+
+ free(priv->cmap);
+
+ return 0;
+}
+
+/* Set up the display ready for use */
+static int video_post_probe(struct udevice *dev)
+{
+ struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+ struct video_priv *priv = dev_get_uclass_priv(dev);
+ char name[30], drv[15], *str;
+ struct udevice *cons;
+ int ret;
+
+ /* Set up the line and display size */
+ priv->fb = map_sysmem(plat->base, plat->size);
+ priv->line_length = priv->xsize * VNBYTES(priv->bpix);
+ priv->fb_size = priv->line_length * priv->ysize;
+
+ /* Set up colours - we could in future support other colours */
+#ifdef CONFIG_SYS_WHITE_ON_BLACK
+ priv->colour_fg = 0xffffff;
+#else
+ priv->colour_bg = 0xffffff;
+#endif
+ video_clear(dev);
+
+ return 0;
+};
+
+/* Post-relocation, allocate memory for the frame buffer */
+static int video_post_bind(struct udevice *dev)
+{
+ ulong addr = gd->video_top;
+ ulong size;
+
+ /* Before relocation there is nothing to do here */
+ if ((!gd->flags & GD_FLG_RELOC))
+ return 0;
+ size = alloc_fb(dev, &addr);
+ if (addr < gd->video_bottom) {
+ /* Device tree node may need the 'u-boot,dm-pre-reloc' tag */
+ printf("Video device '%s' cannot allocate frame buffer memory -ensure the device is set up before relocation\n",
+ dev->name);
+ return -ENOSPC;
+ }
+ debug("%s: Claiming %lx bytes at %lx for video device '%s'\n",
+ __func__, size, addr, dev->name);
+ gd->video_bottom = addr;
+
+ return 0;
+}
+
+UCLASS_DRIVER(video) = {
+ .id = UCLASS_VIDEO,
+ .name = "video",
+ .flags = DM_UC_FLAG_SEQ_ALIAS,
+ .post_bind = video_post_bind,
+ .pre_probe = video_pre_probe,
+ .post_probe = video_post_probe,
+ .pre_remove = video_pre_remove,
+ .per_device_auto_alloc_size = sizeof(struct video_priv),
+ .per_device_platdata_auto_alloc_size = sizeof(struct video_uc_platdata),
+};
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 27fa0b68db..3934375fff 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -66,6 +66,7 @@ enum uclass_id {
UCLASS_USB, /* USB bus */
UCLASS_USB_DEV_GENERIC, /* USB generic device */
UCLASS_USB_HUB, /* USB hub */
+ UCLASS_VIDEO, /* Video or LCD device */
UCLASS_VIDEO_BRIDGE, /* Video bridge, e.g. DisplayPort to LVDS */
UCLASS_COUNT,
diff --git a/include/video.h b/include/video.h
index 65e4ec1e1a..b20f06f335 100644
--- a/include/video.h
+++ b/include/video.h
@@ -1,14 +1,167 @@
/*
-** MPC823 Video Controller
-** =======================
-** (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
-** AIRVENT SAM s.p.a - RIMINI(ITALY)
-**
-*/
+ * Video uclass and legacy implementation
+ *
+ * Copyright (c) 2015 Google, Inc
+ *
+ * MPC823 Video Controller
+ * =======================
+ * (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
+ * AIRVENT SAM s.p.a - RIMINI(ITALY)
+ *
+ */
#ifndef _VIDEO_H_
#define _VIDEO_H_
+#ifdef CONFIG_DM_VIDEO
+
+#include <stdio_dev.h>
+
+struct video_uc_platdata {
+ uint align;
+ uint size;
+ ulong base;
+};
+
+/*
+ * Bits per pixel selector. Each value n is such that the bits-per-pixel is
+ * 2 ^ n
+ */
+enum video_log2_bpp {
+ VIDEO_BPP1 = 0,
+ VIDEO_BPP2,
+ VIDEO_BPP4,
+ VIDEO_BPP8,
+ VIDEO_BPP16,
+ VIDEO_BPP32,
+};
+
+/*
+ * Convert enum video_log2_bpp to bytes and bits. Note we omit the outer
+ * brackets to allow multiplication by fractional pixels.
+ */
+#define VNBYTES(bpix) (1 << (bpix)) / 8
+
+#define VNBITS(bpix) (1 << (bpix))
+
+/**
+ * struct video_priv - Device information used by the video uclass
+ *
+ * @xsize: Number of pixel columns (e.g. 1366)
+ * @ysize: Number of pixels rows (e.g.. 768)
+ * @tor: Display rotation (0=none, 1=90 degrees clockwise, etc.)
+ * @bpix: Encoded bits per pixel
+ * @fb: Frame buffer
+ * @fb_size: Frame buffer size
+ * @line_length: Length of each frame buffer line, in bytes
+ * @colour_fg: Foreground colour (pixel value)
+ * @colour_bg: Background colour (pixel value)
+ * @flush_dcache: true to enable flushing of the data cache after
+ * the LCD is updated
+ * @cmap: Colour map for 8-bit-per-pixel displays
+ */
+struct video_priv {
+ /* Things set up by the driver: */
+ ushort xsize;
+ ushort ysize;
+ ushort rot;
+ enum video_log2_bpp bpix;
+
+ /*
+ * Things that are private to the uclass: don't use these in the
+ * driver
+ */
+ void *fb;
+ int fb_size;
+ int line_length;
+ int colour_fg;
+ int colour_bg;
+ bool flush_dcache;
+ ushort *cmap;
+};
+
+/* Placeholder - there are no video operations at present */
+struct video_ops {
+};
+
+#define video_get_ops(dev) ((struct video_ops *)(dev)->driver->ops)
+
+/**
+ * video_reserve() - Reserve frame-buffer memory for video devices
+ *
+ * Note: This function is for internal use.
+ *
+ * This uses the uclass platdata's @size and @align members to figure out
+ * a size and position for each frame buffer as part of the pre-relocation
+ * process of determining the post-relocation memory layout.
+ *
+ * gd->video_top is set to the initial value of *@addrp and gd->video_bottom
+ * is set to the final value.
+ *
+ * @addrp: On entry, the top of available memory. On exit, the new top,
+ * after allocating the required memory.
+ * @return 0
+ */
+int video_reserve(ulong *addrp);
+
+/**
+ * video_sync() - Sync a device's frame buffer with its hardware
+ *
+ * Some frame buffers are cached or have a secondary frame buffer. This
+ * function syncs these up so that the current contents of the U-Boot frame
+ * buffer are displayed to the user.
+ *
+ * @dev: Device to sync
+ */
+void video_sync(struct udevice *vid);
+
+/**
+ * video_sync_all() - Sync all devices' frame buffers with there hardware
+ *
+ * This calls video_sync() on all active video devices.
+ */
+void video_sync_all(void);
+
+/**
+ * video_bmp_display() - Display a BMP file
+ *
+ * @dev: Device to display the bitmap on
+ * @bmp_image: Address of bitmap image to display
+ * @x: X position in pixels from the left
+ * @y: Y position in pixels from the top
+ * @align: true to adjust the coordinates to centre the image. If false
+ * the coordinates are used as is. If true:
+ *
+ * - if a coordinate is 0x7fff then the image will be centred in
+ * that direction
+ * - if a coordinate is -ve then it will be offset to the
+ * left/top of the centre by that many pixels
+ * - if a coordinate is positive it will be used unchnaged.
+ * @return 0 if OK, -ve on error
+ */
+int video_bmp_display(struct udevice *dev, ulong bmp_image, int x, int y,
+ bool align);
+
+/**
+ * video_get_xsize() - Get the width of the display in pixels
+ *
+ * @dev: Device to check
+ * @return device frame buffer width in pixels
+ */
+int video_get_xsize(struct udevice *dev);
+
+/**
+ * video_get_ysize() - Get the height of the display in pixels
+ *
+ * @dev: Device to check
+ * @return device frame buffer height in pixels
+ */
+int video_get_ysize(struct udevice *dev);
+
+#endif /* CONFIG_DM_VIDEO */
+
+#ifndef CONFIG_DM_VIDEO
+
/* Video functions */
struct stdio_dev;
@@ -73,4 +226,7 @@ int kwh043st20_f01_spi_startup(unsigned int bus, unsigned int cs,
int lg4573_spi_startup(unsigned int bus, unsigned int cs,
unsigned int max_hz, unsigned int spi_mode);
#endif
+
+#endif /* CONFIG_DM_VIDEO */
+
#endif
OpenPOWER on IntegriCloud