From: Juergen Beisert <jbe@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Juergen Beisert <juergen@kreuzholzen.de>
Subject: [PATCH 08/12] Add a video driver for S3C2440 bases platforms
Date: Tue, 26 Oct 2010 13:31:44 +0200 [thread overview]
Message-ID: <1288092708-5187-9-git-send-email-jbe@pengutronix.de> (raw)
In-Reply-To: <1288092708-5187-1-git-send-email-jbe@pengutronix.de>
From: Juergen Beisert <juergen@kreuzholzen.de>
Signed-off-by: Juergen Beisert <juergen@kreuzholzen.de>
---
arch/arm/mach-s3c24xx/include/mach/fb.h | 40 +++
drivers/video/Kconfig | 6 +
drivers/video/Makefile | 1 +
drivers/video/s3c.c | 452 +++++++++++++++++++++++++++++++
4 files changed, 499 insertions(+), 0 deletions(-)
create mode 100644 arch/arm/mach-s3c24xx/include/mach/fb.h
create mode 100644 drivers/video/s3c.c
diff --git a/arch/arm/mach-s3c24xx/include/mach/fb.h b/arch/arm/mach-s3c24xx/include/mach/fb.h
new file mode 100644
index 0000000..eec6164
--- /dev/null
+++ b/arch/arm/mach-s3c24xx/include/mach/fb.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 Juergen Beisert
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#ifndef __MACH_FB_H_
+# define __MACH_FB_H_
+
+#include <fb.h>
+
+struct s3c_fb_platform_data {
+
+ const struct fb_videomode *mode_list;
+ unsigned mode_cnt;
+
+ int passive_display; /**< enable support for STN or CSTN displays */
+
+ void *framebuffer; /**< force framebuffer base address */
+ unsigned size; /**< force framebuffer size */
+
+ /** hook to enable backlight and stuff */
+ void (*enable)(int);
+};
+
+#endif /* __MACH_FB_H_ */
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index d7f3d01..5a5edd2 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -39,4 +39,10 @@ config DRIVER_VIDEO_IMX_IPU
Add support for the IPU framebuffer device found on
i.MX31 and i.MX35 CPUs.
+config S3C_VIDEO
+ bool "S3C244x framebuffer driver"
+ depends on ARCH_S3C24xx
+ help
+ Add support for the S3C244x LCD controller.
+
endif
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 179f0c4..4287fc8 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_VIDEO) += fb.o
obj-$(CONFIG_DRIVER_VIDEO_IMX) += imx.o
obj-$(CONFIG_DRIVER_VIDEO_IMX_IPU) += imx-ipu-fb.o
+obj-$(CONFIG_S3C_VIDEO) += s3c.o
diff --git a/drivers/video/s3c.c b/drivers/video/s3c.c
new file mode 100644
index 0000000..8ae5785
--- /dev/null
+++ b/drivers/video/s3c.c
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2010 Juergen Beisert
+ *
+ * This driver is based on a patch found in the web:
+ * (C) Copyright 2006 by OpenMoko, Inc.
+ * Author: Harald Welte <laforge at openmoko.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+/* #define DEBUG */
+
+#include <common.h>
+#include <init.h>
+#include <fb.h>
+#include <driver.h>
+#include <malloc.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <mach/gpio.h>
+#include <mach/s3c24xx-generic.h>
+#include <mach/s3c24x0-clocks.h>
+#include <mach/fb.h>
+
+#define LCDCON1 0x00
+# define PNRMODE(x) (((x) & 3) << 5)
+# define BPPMODE(x) (((x) & 0xf) << 1)
+# define SET_CLKVAL(x) (((x) & 0x3ff) << 8)
+# define GET_CLKVAL(x) (((x) >> 8) & 0x3ff)
+# define ENVID (1 << 0)
+
+#define LCDCON2 0x04
+# define SET_VBPD(x) (((x) & 0xff) << 24)
+# define SET_LINEVAL(x) (((x) & 0x3ff) << 14)
+# define SET_VFPD(x) (((x) & 0xff) << 6)
+# define SET_VSPW(x) ((x) & 0x3f)
+
+#define LCDCON3 0x08
+# define SET_HBPD(x) (((x) & 0x7f) << 19)
+# define SET_HOZVAL(x) (((x) & 0x7ff) << 8)
+# define SET_HFPD(x) ((x) & 0xff)
+
+#define LCDCON4 0x0c
+# define SET_HSPW(x) ((x) & 0xff)
+
+#define LCDCON5 0x10
+# define BPP24BL (1 << 12)
+# define FRM565 (1 << 11)
+# define INV_CLK (1 << 10)
+# define INV_HS (1 << 9)
+# define INV_VS (1 << 8)
+# define INV_DTA (1 << 7)
+# define INV_DE (1 << 6)
+# define INV_PWREN (1 << 5)
+# define INV_LEND (1 << 4) /* FIXME */
+# define ENA_PWREN (1 << 3)
+# define ENA_LEND (1 << 2) /* FIXME */
+# define BSWP (1 << 1)
+# define HWSWP (1 << 0)
+
+#define LCDSADDR1 0x14
+# define SET_LCDBANK(x) (((x) & 0x1ff) << 21)
+# define GET_LCDBANK(x) (((x) >> 21) & 0x1ff)
+# define SET_LCDBASEU(x) ((x) & 0x1fffff)
+# define GET_LCDBASEU(x) ((x) & 0x1fffff)
+
+#define LCDSADDR2 0x18
+# define SET_LCDBASEL(x) ((x) & 0x1fffff)
+# define GET_LCDBASEL(x) ((x) & 0x1fffff)
+
+#define LCDSADDR3 0x1c
+# define SET_OFFSIZE(x) (((x) & 0x7ff) << 11)
+# define GET_OFFSIZE(x) (((x) >> 11) & 0x7ff)
+# define SET_PAGE_WIDTH(x) ((x) & 0x3ff)
+# define GET_PAGE_WIDTH(x) ((x) & 0x3ff)
+
+#define RED_LUT 0x20
+#define GREEN_LUT 0x24
+#define BLUE_LUT 0x28
+
+#define DITHMODE 0x4c
+
+#define TPAL 0x50
+
+#define LCDINTPND 0x54
+
+#define LCDSRCPND 0x58
+
+#define LCDINTMSK 0x5c
+# define FIWSEL (1 << 2)
+
+#define TCONSEL 0x60
+
+#define RED 0
+#define GREEN 1
+#define BLUE 2
+#define TRANSP 3
+
+struct s3cfb_host {
+ struct fb_host fb_data;
+ struct device_d *hw_dev;
+ void __iomem *base;
+};
+
+#define fb_info_to_s3cfb_host(x) ((struct s3cfb_host*)((x)->host))
+#define s3cfb_host_to_s3c_fb_platform_data(x) ((struct s3c_fb_platform_data*)((x)->hw_dev->platform_data))
+
+/* the RGB565 true colour mode */
+static const struct fb_bitfield def_rgb565[] = {
+ [RED] = {
+ .offset = 11,
+ .length = 5,
+ },
+ [GREEN] = {
+ .offset = 5,
+ .length = 6,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 5,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+/* the RGB888 true colour mode */
+static const struct fb_bitfield def_rgb888[] = {
+ [RED] = {
+ .offset = 16,
+ .length = 8,
+ },
+ [GREEN] = {
+ .offset = 8,
+ .length = 8,
+ },
+ [BLUE] = {
+ .offset = 0,
+ .length = 8,
+ },
+ [TRANSP] = { /* no support for transparency */
+ .length = 0,
+ }
+};
+
+/**
+ * @param fb_info Framebuffer information
+ */
+static void s3cfb_enable_controller(struct fb_info *fb_info)
+{
+ struct s3cfb_host *fbh = fb_info_to_s3cfb_host(fb_info);
+ struct s3c_fb_platform_data *pdata = s3cfb_host_to_s3c_fb_platform_data(fbh);
+ uint32_t con1;
+
+ pr_debug("%s called\n", __func__);
+
+ con1 = readl(fbh->base + LCDCON1);
+
+ con1 |= ENVID;
+
+ writel(con1, fbh->base + LCDCON1);
+
+ if (pdata->enable)
+ (pdata->enable)(1);
+}
+
+/**
+ * @param fb_info Framebuffer information
+ */
+static void s3cfb_disable_controller(struct fb_info *fb_info)
+{
+ struct s3cfb_host *fbh = fb_info_to_s3cfb_host(fb_info);
+ struct s3c_fb_platform_data *pdata = s3cfb_host_to_s3c_fb_platform_data(fbh);
+ uint32_t con1;
+
+ pr_debug("%s called\n", __func__);
+
+ if (pdata->enable)
+ (pdata->enable)(0);
+
+ con1 = readl(fbh->base + LCDCON1);
+
+ con1 &= ~ENVID;
+
+ writel(con1, fbh->base + LCDCON1);
+}
+
+/**
+ * Prepare the video hardware for a specified video mode
+ * @param fb_info Framebuffer information
+ * @param mode The video mode description to initialize
+ * @return 0 on success
+ */
+static int s3cfb_initialize_mode(struct fb_info *fb_info, const struct fb_videomode *mode)
+{
+ struct s3cfb_host *fbh = fb_info_to_s3cfb_host(fb_info);
+ struct s3c_fb_platform_data *pdata = s3cfb_host_to_s3c_fb_platform_data(fbh);
+ unsigned size, hclk, div;
+ uint32_t con1, con2, con3, con4, con5 = 0;
+
+ pr_debug("%s called\n", __func__);
+
+ if (pdata->passive_display != 0) {
+ pr_err("Passive displays are currently not supported\n");
+ return -EINVAL;
+ }
+
+ /*
+ * we need at least this amount of memory for the framebuffer
+ */
+ size = mode->xres * mode->yres * (fb_info->bits_per_pixel >> 3);
+ if (fb_info->fb_dev->size != 0) {
+ if (size > fb_info->fb_dev->size) {
+ pr_err("Cannot initialize video mode '%s': Its too large. "
+ "Required bytes are %u, available only %u\n",
+ mode->name, size, fb_info->fb_dev->size);
+ return -EINVAL;
+ }
+ } else
+ fb_info->fb_dev->size = size;
+
+ /*
+ * if no framebuffer memory was specified yet, allocate one,
+ * and allocate more memory, on user request
+ */
+ if (fb_info->fb_dev->map_base == 0U)
+ fb_info->fb_dev->map_base = (resource_size_t)xzalloc(fb_info->fb_dev->size);
+
+ /* its useful to enable the unit's clock */
+ s3c244x_mod_clock(CLK_LCDC, 1);
+
+ /* ensure video output is _off_ */
+ writel(0x00000000, fbh->base + LCDCON1);
+
+ hclk = s3c24xx_get_hclk() / 1000U; /* hclk in kHz */
+ div = hclk / PICOS2KHZ(mode->pixclock);
+ if (div < 3)
+ div = 3;
+ /* pixel clock is: (hclk) / ((div + 1) * 2) */
+ div += 1;
+ div >>= 1;
+ div -= 1;
+
+ con1 = PNRMODE(3) | SET_CLKVAL(div); /* PNRMODE=3 is TFT */
+
+ switch (fb_info->bits_per_pixel) {
+#if 0
+ /* TODO add CLUT based modes */
+ case 1:
+ con1 |= BPPMODE(8);
+ break;
+ case 2:
+ con1 |= BPPMODE(9);
+ break;
+ case 4:
+ con1 |= BPPMODE(10);
+ break;
+ case 8:
+ con1 |= BPPMODE(11);
+ break;
+#endif
+ case 16:
+ con1 |= BPPMODE(12);
+ con5 |= FRM565;
+ fb_info->red = def_rgb565[RED];
+ fb_info->green = def_rgb565[GREEN];
+ fb_info->blue = def_rgb565[BLUE];
+ fb_info->transp = def_rgb565[TRANSP];
+ break;
+ case 24:
+ con1 |= BPPMODE(13);
+ con5 |= BPP24BL; /* FIXME */
+ fb_info->red = def_rgb888[RED];
+ fb_info->green = def_rgb888[GREEN];
+ fb_info->blue = def_rgb888[BLUE];
+ fb_info->transp = def_rgb888[TRANSP];
+ break;
+ default:
+ pr_err("Invalid bits per pixel value: %u\n", fb_info->bits_per_pixel);
+ return -EINVAL;
+ }
+
+ /* 'normal' in register description means positive logic */
+ if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
+ con5 |= INV_HS;
+ if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
+ con5 |= INV_VS;
+ if (!(mode->sync & FB_SYNC_DE_HIGH_ACT))
+ con5 |= INV_DE;
+ if (mode->sync & FB_SYNC_CLK_INVERT)
+ con5 |= INV_CLK; /* display should latch at the rising edge */
+ if (mode->sync & FB_SYNC_SWAP_RGB)
+ con5 |= HWSWP;
+
+ /* TODO power enable config via platform data */
+
+ /* vertical timing */
+ con2 = SET_VBPD(mode->upper_margin - 1) |
+ SET_LINEVAL(mode->yres - 1) |
+ SET_VFPD(mode->lower_margin - 1) |
+ SET_VSPW(mode->vsync_len - 1);
+
+ /* horizontal timing */
+ con3 = SET_HBPD(mode->left_margin - 1) |
+ SET_HOZVAL(mode->xres - 1) |
+ SET_HFPD(mode->right_margin - 1);
+ con4 = SET_HSPW(mode->hsync_len - 1);
+
+ /* basic timing setup */
+ writel(con1, fbh->base + LCDCON1);
+ pr_debug(" Writing %08X into %08X (con1)\n", con1, fbh->base + LCDCON1);
+ writel(con2, fbh->base + LCDCON2);
+ pr_debug(" Writing %08X into %08X (con2)\n", con2, fbh->base + LCDCON2);
+ writel(con3, fbh->base + LCDCON3);
+ pr_debug(" Writing %08X into %08X (con3)\n", con3, fbh->base + LCDCON3);
+ writel(con4, fbh->base + LCDCON4);
+ pr_debug(" Writing %08X into %08X (con4)\n", con4, fbh->base + LCDCON4);
+ writel(con5, fbh->base + LCDCON5);
+ pr_debug(" Writing %08X into %08X (con5)\n", con5, fbh->base + LCDCON5);
+
+ pr_debug("Setting up the fb baseadress to %08X\n", fb_info->fb_dev->map_base);
+
+ /* framebuffer memory setup */
+ writel(fb_info->fb_dev->map_base >> 1, fbh->base + LCDSADDR1);
+ size = mode->xres * (fb_info->bits_per_pixel >> 3) * (mode->yres);
+ writel(SET_LCDBASEL((fb_info->fb_dev->map_base + size) >> 1), fbh->base + LCDSADDR2);
+
+ writel(SET_OFFSIZE(0) |
+ SET_PAGE_WIDTH((mode->xres * fb_info->bits_per_pixel) >> 4),
+ fbh->base + LCDSADDR3);
+
+ writel(FIWSEL, fbh->base + LCDINTMSK);
+
+ return 0;
+}
+
+/**
+ * Print some information about the current hardware state
+ * @param hw_dev S3C video device
+ */
+#ifdef CONFIG_VIDEO_INFO_VERBOSE
+static void s3cfb_info(struct device_d *hw_dev)
+{
+ uint32_t con1, addr1, addr2, addr3;
+
+ con1 = readl(hw_dev->map_base + LCDCON1);
+ addr1 = readl(hw_dev->map_base + LCDSADDR1);
+ addr2 = readl(hw_dev->map_base + LCDSADDR2);
+ addr3 = readl(hw_dev->map_base + LCDSADDR3);
+
+ printf(" Video hardware info:\n");
+ printf(" Video clock is running at %u Hz\n", s3c24xx_get_hclk() / ((GET_CLKVAL(con1) + 1) * 2));
+ printf(" Video memory bank starts at 0x%08X\n", GET_LCDBANK(addr1) << 22);
+ printf(" Video memory bank offset: 0x%08X\n", GET_LCDBASEU(addr1));
+ printf(" Video memory end: 0x%08X\n", GET_LCDBASEU(addr2));
+ printf(" Virtual screen offset size: %u half words\n", GET_OFFSIZE(addr3));
+ printf(" Virtual screen page width: %u half words\n", GET_PAGE_WIDTH(addr3));
+}
+#endif
+
+/*
+ * There is only one video hardware instance available.
+ * It makes no sense to dynamically allocate this data
+ */
+static struct s3cfb_host host_data = {
+ .fb_data.fb_mode = s3cfb_initialize_mode,
+ .fb_data.fb_enable = s3cfb_enable_controller,
+ .fb_data.fb_disable = s3cfb_disable_controller,
+};
+
+static int s3cfb_probe(struct device_d *hw_dev)
+{
+ struct s3c_fb_platform_data *pdata = hw_dev->platform_data;
+ struct device_d *fb_dev;
+
+ pr_debug("%s called\n", __func__);
+
+ if (pdata == NULL) {
+ pr_debug("Framebuffer driver missing platform data");
+ return -ENODEV;
+ }
+
+ /* enable unit's clock */
+ s3c244x_mod_clock(CLK_LCDC, 1);
+
+ writel(0, hw_dev->map_base + LCDCON1);
+ /* off may be means high level (FIXME itlp specific) */
+ writel(0, hw_dev->map_base + LCDCON5);
+
+ /* disable it again until user request */
+ s3c244x_mod_clock(CLK_LCDC, 0);
+
+ /* add runtime hardware info */
+ host_data.hw_dev = hw_dev;
+ host_data.base = (void*)hw_dev->map_base;
+
+ /* add runtime video info */
+ host_data.fb_data.mode = pdata->mode_list;
+ host_data.fb_data.mode_cnt = pdata->mode_cnt;
+
+ fb_dev = register_framebuffer(&host_data.fb_data, pdata->framebuffer, pdata->size);
+ if (fb_dev == NULL) {
+ pr_err("Failed to register framebuffer\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct driver_d s3cfb_driver = {
+ .name = "s3cfb",
+ .probe = s3cfb_probe,
+#ifdef CONFIG_VIDEO_INFO_VERBOSE
+ .info = s3cfb_info,
+#endif
+};
+
+static int s3cfb_init(void)
+{
+ return register_driver(&s3cfb_driver);
+}
+
+device_initcall(s3cfb_init);
+
+/**
+ * The S3C244x LCD controller supports passive (CSTN/STN) and active (TFT) LC displays
+ *
+ * The driver itself currently supports only active TFT LC displays in the follwing manner:
+ *
+ * * Palletized colours
+ * - 1 bpp
+ * - 2 bpp
+ * - 4 bpp
+ * - 8 bpp
+ * * True colours
+ * - 16 bpp
+ * - 24 bpp
+ */
--
1.7.2.3
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
next prev parent reply other threads:[~2010-10-26 11:32 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-10-26 11:31 [PATCHv2] Add dynamic video initialization to barebox Juergen Beisert
2010-10-26 11:31 ` [PATCH 01/12] Separate framebuffer platformdata and the videomode Juergen Beisert
2010-10-26 11:31 ` [PATCH 02/12] Add more flags for sync control Juergen Beisert
2010-10-26 11:31 ` [PATCH 03/12] Bring in dynamic videomode selection at runtime Juergen Beisert
2010-11-01 13:47 ` Sascha Hauer
2010-11-15 10:04 ` Juergen Beisert
2010-11-17 8:27 ` Sascha Hauer
2010-11-01 14:16 ` Sascha Hauer
2010-11-15 10:08 ` Juergen Beisert
2010-10-26 11:31 ` [PATCH 04/12] Remove the old videomode functions Juergen Beisert
2010-10-26 11:31 ` [PATCH 05/12] Add verbose framebuffer device info Juergen Beisert
2010-10-26 11:31 ` [PATCH 06/12] Adapt the existing imx fb driver to support runtime videomode selection Juergen Beisert
2010-10-26 11:31 ` [PATCH 07/12] Adapt the existing imx-ipu " Juergen Beisert
2010-10-26 11:31 ` Juergen Beisert [this message]
2010-11-01 14:41 ` [PATCH 08/12] Add a video driver for S3C2440 bases platforms Sascha Hauer
2010-11-15 11:35 ` Juergen Beisert
2010-11-17 8:36 ` Sascha Hauer
2010-10-26 11:31 ` [PATCH 09/12] STM378x: Add video driver for this platform Juergen Beisert
2010-10-26 11:31 ` [PATCH 10/12] Remove variable size restrictions Juergen Beisert
2010-10-26 11:31 ` [PATCH 11/12] Add doxygen documentation to the framebfuffer code Juergen Beisert
2010-10-26 11:31 ` [PATCH 12/12] Provide more driver specific data in a videomode Juergen Beisert
2010-11-01 13:19 ` [PATCHv2] Add dynamic video initialization to barebox Sascha Hauer
2010-11-01 13:29 ` Eric Bénard
2010-11-01 14:18 ` Sascha Hauer
2010-11-15 9:57 ` Juergen Beisert
2010-11-15 10:25 ` Belisko Marek
2010-11-17 8:44 ` Sascha Hauer
2010-11-18 8:18 ` Belisko Marek
2010-11-18 10:09 ` Sascha Hauer
2010-11-17 8:43 ` Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1288092708-5187-9-git-send-email-jbe@pengutronix.de \
--to=jbe@pengutronix.de \
--cc=barebox@lists.infradead.org \
--cc=juergen@kreuzholzen.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox