lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Date:	Mon, 12 May 2008 18:49:07 +0800
From:	Bryan Wu <cooloney@...nel.org>
To:	adaplas@...il.com, linux-fbdev-devel@...ts.sourceforge.net
Cc:	linux-kernel@...r.kernel.org,
	Harald Krapfenbauer <harald.krapfenbauer@...etechnix.at>,
	Michael Hennerich <michael.hennerich@...log.com>,
	Bryan Wu <cooloney@...nel.org>
Subject: [PATCH 1/1] [Video/Framebuffer]: Hitachi TX09D70VM1CDA TFT LCD framebuffer driver

From: Harald Krapfenbauer <harald.krapfenbauer@...etechnix.at>

Signed-off-by: Harald Krapfenbauer <harald.krapfenbauer@...etechnix.at>
Signed-off-by: Michael Hennerich <michael.hennerich@...log.com>
Signed-off-by: Bryan Wu <cooloney@...nel.org>
---
 drivers/video/Kconfig        |   36 ++
 drivers/video/Makefile       |    1 +
 drivers/video/hitachi-tx09.c |  794 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 831 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/hitachi-tx09.c

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index bb1dada..4a56985 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -600,6 +600,42 @@ config FB_BFIN_T350MCQB
 	 It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK.
 
 
+config FB_HITACHI_TX09
+	tristate "Hitachi TX09D70VM1CDA TFT LCD"
+	depends on FB && (BF537 || BF561)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This is the framebuffer device for a HITACHI TX09D70VM1CDA
+	  TFT LCD attached to a CM-BF537E or CM-BF561 from Bluetechnix.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called hitachi-tx09.
+
+config FB_HITACHI_TX09_LANDSCAPE
+	bool "Use Landscape 320x240 instead of Portrait 240x320"
+	depends on FB_HITACHI_TX09
+	default n
+	help
+	  Use 320x240 instead of native 240x320 Resolution
+
+config FB_HITACHI_TX09_REFRESHRATE
+	int "Refresh rate"
+	depends on FB_HITACHI_TX09
+	range 25 70
+	default 52
+	help
+	  Refresh rate of the LCD in Hz. According to data sheet, must
+	  be in the interval [52...68].
+
+config CONFIG_FB_HITACHI_TX09_CURSOR
+	bool "Enable/Disable cursor"
+	depends on FB_HITACHI_TX09
+	default n
+	help
+	  Enable the cursor
+
 config FB_STI
 	tristate "HP STI frame buffer device support"
 	depends on FB && PARISC
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 04bca35..51fe9ab 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -117,6 +117,7 @@ obj-$(CONFIG_FB_SM501)            += sm501fb.o
 obj-$(CONFIG_FB_XILINX)           += xilinxfb.o
 obj-$(CONFIG_FB_OMAP)             += omap/
 obj-$(CONFIG_XEN_FBDEV_FRONTEND)  += xen-fbfront.o
+obj-$(CONFIG_FB_HITACHI_TX09)     += hitachi-tx09.o
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
diff --git a/drivers/video/hitachi-tx09.c b/drivers/video/hitachi-tx09.c
new file mode 100644
index 0000000..e53de0a
--- /dev/null
+++ b/drivers/video/hitachi-tx09.c
@@ -0,0 +1,794 @@
+/*
+ * drivers/video/hitachi-tx09.c
+ * Date: 2007-11-22
+ *
+ * Framebuffer driver for the Hitachi TX09D70VM1CDA TFT LCD written
+ * by Harald Krapfenbauer <harald.krapfenbauer@...etechnix.at>
+ *
+ * Thanks to Michael Hennerich from Analog Devices Inc. for his support
+ * and the bf537-lq035.c TFT driver!
+ *
+ * For more information, please read the data sheet:
+ * http://www.hitachi-displays-eu.com/doc/TX09D70VM1CDA.PDF
+ *
+ * This program is free software; you can distribute it and/or modify it
+ * under the terms of the GNU General Public License (Version 2) as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/delay.h>
+#include <linux/fb.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/backlight.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <asm/dma.h>
+#include <asm/portmux.h>
+
+#define DRIVER_NAME "hitachi-tx09"
+
+#define MAX_BRIGHTNESS 100
+#define BFIN_LCD_NBR_PALETTE_ENTRIES	256
+
+#undef BITREVERSED		/* colors bitreversed? (only needed for older EXT-CAM boards) */
+
+#define PPI0_16 {P_PPI0_CLK, P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, P_PPI0_D3, \
+		P_PPI0_D4, P_PPI0_D5, P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, P_PPI0_D9, P_PPI0_D10, \
+		P_PPI0_D11, P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, P_PPI0_D15, 0}
+
+#ifdef CONFIG_BFIN537_BLUETECHNIX_CM
+
+#define TIMER_DCLK 3
+#define TIMER_HSYNC 0
+#define TIMER_DTMG 1
+#define TIMER_VSYNC 6
+#define TIMER_BACKLIGHT 4
+#define PCI_PIN GPIO_PF14
+#define TIMERS {P_TMR0, P_TMR1, P_TMR3, P_TMR4, P_TMR6, 0}
+#define WRITE_PPI_CONTROL(x) bfin_write_PPI_CONTROL(x)
+#define READ_PPI_CONTROL bfin_read_PPI_CONTROL
+#define WRITE_PPI_DELAY(x) bfin_write_PPI_DELAY(x)
+#define WRITE_PPI_COUNT(x) bfin_write_PPI_COUNT(x)
+
+#else
+
+#ifdef CONFIG_BFIN561_BLUETECHNIX_CM
+
+#define TIMER_DCLK 6
+#define TIMER_HSYNC 8
+#define TIMER_DTMG 9
+#define TIMER_VSYNC 1
+#define TIMER_BACKLIGHT 5
+#define PCI_PIN GPIO_PF0
+#define TIMERS {P_TMR1, P_TMR5, P_TMR6, P_TMR8, P_TMR9, 0}
+#define WRITE_PPI_CONTROL(x) bfin_write_PPI0_CONTROL(x)
+#define READ_PPI_CONTROL bfin_read_PPI0_CONTROL
+#define WRITE_PPI_DELAY(x) bfin_write_PPI0_DELAY(x)
+#define WRITE_PPI_COUNT(x) bfin_write_PPI0_COUNT(x)
+
+#else
+#error The Hitachi TX-09 frame buffer driver only supports Bluetechnix CM-BF537E and CM-BF561
+#endif
+
+#endif
+
+#define BFIN_WRITE(a, b) CONCAT(bfin_write_TIMER, a, _, b)
+#define BFIN_READ(a, b)  CONCAT(bfin_read_TIMER, a, _, b)
+#define CONCAT(a, b, c, d) a ## b ## c ## d
+
+static unsigned char *fb_buffer;	/* RGB Buffer */
+static dma_addr_t dma_handle;
+static unsigned long *dma_desc_table;
+static unsigned long current_brightness;	/* backlight */
+static int tx09_open_cnt;
+static int tx09_mmap;
+static struct backlight_device *bl_dev;
+static int t_conf_done;
+static DEFINE_SPINLOCK(tx09_lock);
+
+static void set_backlight(int val)
+{
+	unsigned long timer_period;
+
+	pr_debug("%s to %d\n", __FUNCTION__, val);
+
+	if (val < 0)
+		val = 0;
+	if (val > MAX_BRIGHTNESS)
+		val = MAX_BRIGHTNESS;
+
+	current_brightness = val;
+
+#ifdef CONFIG_BFIN561_BLUETECHNIX_CM
+	bfin_write_TMRS8_DISABLE(1 << TIMER_BACKLIGHT);
+#else
+	bfin_write_TIMER_DISABLE(1 << TIMER_BACKLIGHT);
+#endif
+	SSYNC();
+
+	timer_period = get_sclk() / 100000;
+	BFIN_WRITE(TIMER_BACKLIGHT, WIDTH) ((timer_period * val) / 100);
+
+#ifdef CONFIG_BFIN561_BLUETECHNIX_CM
+	bfin_write_TMRS8_ENABLE(1 << TIMER_BACKLIGHT);
+#else
+	bfin_write_TIMER_ENABLE(1 << TIMER_BACKLIGHT);
+#endif
+
+	SSYNC();
+}
+
+static void start_timers(void)
+{
+	unsigned long flags;
+
+	local_irq_save(flags);
+
+#ifdef CONFIG_BFIN561_BLUETECHNIX_CM
+	bfin_write_TMRS4_ENABLE((1 << (TIMER_HSYNC - 8)) |
+				(1 << (TIMER_DTMG - 8)));
+	bfin_write_TMRS8_ENABLE(1 << TIMER_VSYNC);
+	SSYNC();
+	bfin_write_TMRS8_ENABLE(1 << TIMER_DCLK);
+#else
+	bfin_write_TIMER_ENABLE((1 << TIMER_HSYNC) | (1 << TIMER_DTMG) |
+				(1 << TIMER_VSYNC));
+	SSYNC();
+	bfin_write_TIMER_ENABLE(1 << TIMER_DCLK);
+#endif
+	SSYNC();
+	mdelay(50);
+	gpio_set_value(PCI_PIN, 1);
+	SSYNC();
+#ifdef CONFIG_BFIN561_BLUETECHNIX_CM
+	bfin_write_TMRS8_ENABLE(1 << TIMER_BACKLIGHT);
+#else
+	bfin_write_TIMER_ENABLE(1 << TIMER_BACKLIGHT);
+#endif
+	SSYNC();
+
+	local_irq_restore(flags);
+}
+
+static void stop_timers(void)
+{
+	unsigned long flags;
+	long old_value = 0, new_value = 0;
+
+	local_irq_save(flags);
+
+#ifdef CONFIG_BFIN561_BLUETECHNIX_CM
+	bfin_write_TMRS8_DISABLE(1 << TIMER_BACKLIGHT);
+#else
+	bfin_write_TIMER_DISABLE(1 << TIMER_BACKLIGHT);
+#endif
+	gpio_set_value(PCI_PIN, 0);
+
+	while (1) {
+		old_value = new_value;
+		new_value = BFIN_READ(TIMER_VSYNC, COUNTER) ();
+		if ((old_value - new_value) > 45000) {
+#ifdef CONFIG_BFIN561_BLUETECHNIX_CM
+			bfin_write_TMRS8_DISABLE((1 << TIMER_DCLK) |
+						 (1 << TIMER_VSYNC));
+			bfin_write_TMRS4_DISABLE((1 << (TIMER_HSYNC - 8)) |
+						 (1 << (TIMER_DTMG - 8)));
+#else
+			bfin_write_TIMER_DISABLE((1 << TIMER_VSYNC) |
+						 (1 << TIMER_HSYNC) |
+						 (1 <<	TIMER_DTMG) |
+						 (1 << TIMER_DCLK));
+#endif
+			break;
+		}
+	}
+
+	local_irq_restore(flags);
+}
+
+static void config_timers(void)
+{
+	unsigned long timer_period = 0;
+
+	pr_debug("%s\n", __FUNCTION__);
+
+	/* stop timers */
+#ifdef CONFIG_BFIN561_BLUETECHNIX_CM
+	bfin_write_TMRS8_DISABLE((1 << TIMER_DCLK) | (1 << TIMER_VSYNC) |
+				 (1 << TIMER_BACKLIGHT));
+	bfin_write_TMRS4_DISABLE((1 << (TIMER_HSYNC - 8)) |
+				 (1 << (TIMER_DTMG - 8)));
+#else
+	bfin_write_TIMER_DISABLE((1 << TIMER_VSYNC) | (1 << TIMER_HSYNC) |
+				 (1 << TIMER_DTMG) | (1 << TIMER_DCLK) |
+				 (1 << TIMER_BACKLIGHT));
+#endif
+	SSYNC();
+
+	/* dclk clock output */
+	BFIN_WRITE(TIMER_DCLK, CONFIG) (PERIOD_CNT | PULSE_HI | PWM_OUT);
+	timer_period =
+	    get_sclk() / (CONFIG_FB_HITACHI_TX09_REFRESHRATE * 89271);
+	BFIN_WRITE(TIMER_DCLK, PERIOD) (timer_period);
+	BFIN_WRITE(TIMER_DCLK, WIDTH) (timer_period / 2);
+	SSYNC();
+
+	/* brightness timer */
+	BFIN_WRITE(TIMER_BACKLIGHT, CONFIG) (PERIOD_CNT | PULSE_HI | PWM_OUT);
+	timer_period = get_sclk() / 100000;
+	BFIN_WRITE(TIMER_BACKLIGHT, PERIOD) (timer_period);
+	BFIN_WRITE(TIMER_BACKLIGHT, WIDTH) (timer_period - 1);	/* 100% duty cycle */
+	SSYNC();
+
+	/* hsync timer */
+	BFIN_WRITE(TIMER_HSYNC, CONFIG) (CLK_SEL | TIN_SEL | PERIOD_CNT | PWM_OUT);	/* clocked by PPI_clk */
+	BFIN_WRITE(TIMER_HSYNC, PERIOD) (273);	/* 240 + 33 blanking */
+	BFIN_WRITE(TIMER_HSYNC, WIDTH) (5);
+	SSYNC();
+
+	/* dtmg timer */
+	BFIN_WRITE(TIMER_DTMG, CONFIG) (CLK_SEL | TIN_SEL | PERIOD_CNT | PWM_OUT);	/* clocked by PPI_clk */
+	BFIN_WRITE(TIMER_DTMG, PERIOD) (273);
+	BFIN_WRITE(TIMER_DTMG, WIDTH) (33);
+	SSYNC();
+
+	/* vsync timer */
+	BFIN_WRITE(TIMER_VSYNC, CONFIG) (CLK_SEL | TIN_SEL | PERIOD_CNT | PWM_OUT);	/* clocked by PPI_clk */
+	BFIN_WRITE(TIMER_VSYNC, PERIOD) (89271);
+	BFIN_WRITE(TIMER_VSYNC, WIDTH) (1911);
+	SSYNC();
+
+	t_conf_done = 1;
+}
+
+static void config_ppi(void)
+{
+	/* configure PPI registers */
+	WRITE_PPI_DELAY(27);
+	WRITE_PPI_COUNT(240 - 1);
+	WRITE_PPI_CONTROL(0x380e);
+}
+
+static int config_dma(void)
+{
+	u32 i = 0;
+
+	pr_debug("%s\n", __FUNCTION__);
+
+	/* fill descriptor table */
+	for (i = 0; i < 326; i++) {
+		/* point to next desc table */
+		dma_desc_table[2 * i] =
+		    (unsigned long)&dma_desc_table[2 * i + 2];
+	}
+	/* last descriptor points to first */
+	dma_desc_table[2 * 326] = (unsigned long)&dma_desc_table[0];
+
+#ifdef CONFIG_FB_HITACHI_TX09_LANDSCAPE
+
+	dma_desc_table[0 + 1] = (unsigned long)fb_buffer;
+	for (i = 0; i < 7; i++) {
+		/* blanking lines point to first line of fb_buffer */
+		dma_desc_table[2 * i + 1] = (unsigned long)fb_buffer + 319 * 2;
+	}
+	for (i = 7; i < 327; i++) {
+		/* visible lines */
+		dma_desc_table[2 * i + 1] =
+		    (unsigned long)fb_buffer + (319 - (i - 7)) * 2;
+	}
+
+#else				/* portrait mode */
+
+	for (i = 0; i < 7; i++) {
+		/* blanking lines point to first line of fb_buffer */
+		dma_desc_table[2 * i + 1] = (unsigned long)fb_buffer;
+	}
+	for (i = 7; i < 327; i++) {
+		/* visible lines */
+		dma_desc_table[2 * i + 1] =
+		    (unsigned long)fb_buffer + 2 * 240 * (i - 7);
+	}
+
+#endif
+
+#ifdef CONFIG_FB_HITACHI_TX09_LANDSCAPE
+	set_dma_x_count(CH_PPI, 240);
+	set_dma_x_modify(CH_PPI, 2 * 320);
+	set_dma_y_count(CH_PPI, 0);
+	set_dma_y_modify(CH_PPI, 0);
+	set_dma_next_desc_addr(CH_PPI, (unsigned long)dma_desc_table[2 * 326]);
+#else
+	set_dma_x_count(CH_PPI, 240);
+	set_dma_x_modify(CH_PPI, 2);
+	set_dma_y_count(CH_PPI, 0);
+	set_dma_y_modify(CH_PPI, 0);
+	set_dma_next_desc_addr(CH_PPI, (unsigned long)dma_desc_table[2 * 326]);
+#endif
+
+	set_dma_config(CH_PPI, 0x7404);
+
+	return 0;
+}
+
+static int request_ports(int action)
+{
+	u16 ppi_req[] = PPI0_16;
+	u16 tmr_req[] = TIMERS;
+
+	if (action) {
+		if (peripheral_request_list(ppi_req, DRIVER_NAME)) {
+			printk(KERN_ERR DRIVER_NAME
+			       ": Requesting Peripherals PPI faild\n");
+			return -EFAULT;
+		}
+
+		if (peripheral_request_list(tmr_req, DRIVER_NAME)) {
+			peripheral_free_list(ppi_req);
+			printk(KERN_ERR DRIVER_NAME
+			       ": Requesting Peripherals TMR faild\n");
+			return -EFAULT;
+		}
+
+		if (gpio_request(PCI_PIN, DRIVER_NAME)) {
+			peripheral_free_list(ppi_req);
+			peripheral_free_list(tmr_req);
+			printk(KERN_ERR ": Requesting GPIO %d faild\n", PCI_PIN);
+			return -EFAULT;
+		}
+
+		gpio_direction_output(PCI_PIN, 0);
+		SSYNC();
+	} else {
+		peripheral_free_list(ppi_req);
+		peripheral_free_list(tmr_req);
+
+		gpio_free(PCI_PIN);
+	}
+	return 0;
+}
+
+static struct fb_info tx09_fb;
+
+static struct fb_var_screeninfo tx09_fb_defined = {
+#ifdef CONFIG_FB_HITACHI_TX09_LANDSCAPE
+	.xres = 320,
+	.yres = 240,
+	.xres_virtual = 320,
+	.yres_virtual = 240,
+#else
+	.xres = 240,
+	.yres = 320,
+	.xres_virtual = 240,
+	.yres_virtual = 320,
+#endif
+	.bits_per_pixel = 16,
+	.activate = FB_ACTIVATE_TEST,
+	.height = -1,
+	.width = -1,
+#ifdef BITREVERSED
+	.red = {0, 5, 1},	/* offset, length, msb right */
+	.green = {5, 6, 1},
+	.blue = {11, 5, 1},
+#else
+	.red = {0, 5, 0},
+	.green = {5, 6, 0},
+	.blue = {11, 5, 0},
+#endif
+	.transp = {0, 0, 0},
+	.left_margin = 0,
+	.right_margin = 0,
+	.upper_margin = 0,
+	.lower_margin = 0,
+};
+
+static struct fb_fix_screeninfo tx09_fb_fix = {
+	.id = DRIVER_NAME,
+	.smem_len = 320 * 240 * 2,
+	.type = FB_TYPE_PACKED_PIXELS,
+	.visual = FB_VISUAL_TRUECOLOR,
+	.xpanstep = 0,
+	.ypanstep = 0,
+#ifdef CONFIG_FB_HITACHI_TX09_LANDSCAPE
+	.line_length = 320 * 2,
+#else
+	.line_length = 240 * 2,
+#endif
+	.accel = FB_ACCEL_NONE,
+};
+
+static int tx09_fb_open(struct fb_info *info, int user)
+{
+	unsigned long flags;
+
+	pr_debug("%s\n", __FUNCTION__);
+
+	spin_lock_irqsave(&tx09_lock, flags);
+	tx09_open_cnt++;	/* increase counter */
+	spin_unlock_irqrestore(&tx09_lock, flags);
+
+	if (tx09_open_cnt <= 1) {	/* opened the first time */
+
+		/* stop PPI */
+		WRITE_PPI_CONTROL(0);
+		SSYNC();
+
+		/* configure dma stuff */
+		config_dma();
+
+		config_ppi();
+
+		/* start dma */
+		enable_dma(CH_PPI);
+		SSYNC();
+
+		/* start PPI */
+		WRITE_PPI_CONTROL(READ_PPI_CONTROL() | PORT_EN);
+		SSYNC();
+
+		if (!t_conf_done)
+			config_timers();
+
+		start_timers();
+	}
+
+	return 0;
+}
+
+static int tx09_fb_release(struct fb_info *info, int user)
+{
+	unsigned long flags;
+
+	pr_debug("%s\n", __FUNCTION__);
+
+	spin_lock_irqsave(&tx09_lock, flags);
+	tx09_open_cnt--;
+	tx09_mmap = 0;
+	spin_unlock_irqrestore(&tx09_lock, flags);
+
+	if (tx09_open_cnt <= 0) {
+		stop_timers();
+
+		WRITE_PPI_CONTROL(0);
+		SSYNC();
+
+		disable_dma(CH_PPI);
+	}
+
+	return 0;
+}
+
+static int tx09_fb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	pr_debug("%s\n", __FUNCTION__);
+
+	if (var->bits_per_pixel != 16) {
+		pr_debug("%s: depth not supported: %u BPP\n", __FUNCTION__,
+			 var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	if (info->var.xres != var->xres || info->var.yres != var->yres ||
+	    info->var.xres_virtual != var->xres_virtual
+	    || info->var.yres_virtual != var->yres_virtual) {
+		pr_debug("%s: Resolution not supported: X%u x Y%u\n",
+			 __FUNCTION__, var->xres, var->yres);
+		return -EINVAL;
+	}
+
+	if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
+		pr_debug("%s: Memory limit requested yres_virtual = %u\n",
+			 __FUNCTION__, var->yres_virtual);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int tx09_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
+{
+	unsigned long flags;
+
+	pr_debug("%s\n", __FUNCTION__);
+
+	if (tx09_mmap)
+		return -1;	/* already mmap'ed */
+
+	spin_lock_irqsave(&tx09_lock, flags);
+	tx09_mmap = 1;
+	spin_unlock_irqrestore(&tx09_lock, flags);
+
+	vma->vm_start = (unsigned long)fb_buffer;
+	vma->vm_end = vma->vm_start + 320 * 240 * 2;
+	vma->vm_flags |= VM_MAYSHARE | VM_SHARED;
+
+	return 0;
+}
+
+int tx09_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+
+#ifdef CONFIG_FB_HITACHI_TX09_CURSOR
+	return -EINVAL;		/* just to force soft_cursor() call */
+#else
+	return 0;
+#endif
+
+}
+
+static int tx09_fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+			     u_int transp, struct fb_info *info)
+{
+	if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES)
+		return -EINVAL;
+
+	if (info->var.grayscale) {
+		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
+		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
+	}
+
+	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
+		u32 value;
+		/* Place color in the pseudopalette */
+		if (regno > 16)
+			return -EINVAL;
+		red >>= (16 - info->var.red.length);
+		green >>= (16 - info->var.green.length);
+		blue >>= (16 - info->var.blue.length);
+		value =
+		    (red << info->var.red.offset) | (green << info->var.green.
+						     offset) | (blue << info->
+								var.blue.
+								offset);
+		value &= 0xFFFF;
+		((u32 *) (info->pseudo_palette))[regno] = value;
+	}
+	return 0;
+}
+
+static struct fb_ops tx09_fb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = tx09_fb_open,
+	.fb_release = tx09_fb_release,
+	.fb_check_var = tx09_fb_check_var,
+	.fb_fillrect = cfb_fillrect,
+	.fb_copyarea = cfb_copyarea,
+	.fb_imageblit = cfb_imageblit,
+	.fb_mmap = tx09_fb_mmap,
+	.fb_cursor = tx09_fb_cursor,
+	.fb_setcolreg = tx09_fb_setcolreg,
+};
+
+static int bl_update_properties(struct backlight_device *bd)
+{
+	pr_debug("%s\n", __FUNCTION__);
+	set_backlight(bd->props.brightness);
+	return 0;
+}
+
+static int bl_get_brightness(struct backlight_device *bd)
+{
+	pr_debug("%s\n", __FUNCTION__);
+	return current_brightness;
+}
+
+static struct backlight_ops tx09fb_bl_ops = {
+	.get_brightness = bl_get_brightness,
+	.update_status = bl_update_properties,
+};
+
+static int __init tx09_probe(struct platform_device *pdev)
+{
+	pr_debug("%s\n", __FUNCTION__);
+
+	printk(KERN_INFO DRIVER_NAME ": FrameBuffer initializing...\n");
+
+	/* dma channel */
+	if (request_dma(CH_PPI, "BF533_PPI_DMA") < 0) {
+		printk(KERN_ERR DRIVER_NAME ": couldn't request PPI dma.\n");
+		return -EFAULT;
+	}
+
+	/* gpio ports */
+	if (request_ports(1)) {
+		printk(KERN_ERR DRIVER_NAME ": couldn't request gpio port.\n");
+		free_dma(CH_PPI);
+		return -EFAULT;
+	}
+
+	/* frame buffer */
+	fb_buffer = dma_alloc_coherent(NULL, 240 * 320 * 2, &dma_handle, GFP_KERNEL);	/* 7 blanking lines, 2 bytes/pixel */
+	if (fb_buffer == NULL) {
+		printk(KERN_ERR DRIVER_NAME
+		       ": couldn't allocate dma buffer.\n");
+		free_dma(CH_PPI);
+		request_ports(0);
+		return -ENOMEM;
+	}
+
+	/* dma descriptor list */
+#if L1_DATA_A_LENGTH != 0
+	dma_desc_table =
+	    (unsigned long *)l1_data_sram_alloc(sizeof(unsigned long) * 2 *
+						(320 + 7));
+#else
+	dma_desc_table =
+	    dma_alloc_coherent(NULL, sizeof(unsigned long) * 2 * (320 + 7),
+			       &dma_handle, 0);
+#endif
+
+	if (dma_desc_table == NULL) {
+		printk(KERN_ERR DRIVER_NAME
+		       ": couldn't allocate dma descriptor.\n");
+		free_dma(CH_PPI);
+		request_ports(0);
+		dma_free_coherent(NULL, 240 * 320 * 2, fb_buffer, dma_handle);
+		return -ENOMEM;
+	}
+
+	memset(fb_buffer, 0, 240 * 320 * 2);
+
+	tx09_fb.screen_base = (void *)fb_buffer;
+	tx09_fb_fix.smem_start = (int)fb_buffer;
+
+	tx09_fb.fbops = &tx09_fb_ops;
+	tx09_fb.var = tx09_fb_defined;
+
+	tx09_fb.fix = tx09_fb_fix;
+	tx09_fb.flags = FBINFO_DEFAULT;
+
+	/* pseudo palette */
+
+	tx09_fb.pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+
+	if (!tx09_fb.pseudo_palette) {
+		printk(KERN_ERR DRIVER_NAME
+		       "Failed to allocate pseudo palette\n");
+		free_dma(CH_PPI);
+		request_ports(0);
+		dma_free_coherent(NULL, 240 * 320 * 2, fb_buffer, dma_handle);
+		return -ENOMEM;
+	}
+	memset(tx09_fb.pseudo_palette, 0, sizeof(u32) * 16);
+
+	/* color map */
+	if (fb_alloc_cmap(&tx09_fb.cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0) < 0) {
+		printk(KERN_ERR DRIVER_NAME
+		       "Failed to allocate colormap (%d entries)\n",
+		       BFIN_LCD_NBR_PALETTE_ENTRIES);
+		free_dma(CH_PPI);
+		request_ports(0);
+		dma_free_coherent(NULL, 240 * 320 * 2, fb_buffer, dma_handle);
+		kfree(tx09_fb.pseudo_palette);
+		return -EFAULT;
+	}
+
+	/* register framebuffer */
+	if (register_framebuffer(&tx09_fb) < 0) {
+		printk(KERN_ERR DRIVER_NAME
+		       ": unable to register framebuffer.\n");
+		free_dma(CH_PPI);
+		request_ports(0);
+		dma_free_coherent(NULL, 240 * 320 * 2, fb_buffer, dma_handle);
+		fb_buffer = NULL;
+		return -EINVAL;
+	}
+
+	/* backlight device */
+	bl_dev =
+	    backlight_device_register("hitachi-bl", NULL, NULL, &tx09fb_bl_ops);
+	bl_dev->props.max_brightness = MAX_BRIGHTNESS;
+
+	printk(KERN_INFO "Done.\n");
+
+	return 0;
+}
+
+static int tx09_remove(struct platform_device *pdev)
+{
+	pr_debug("%s\n", __FUNCTION__);
+
+	if (fb_buffer != NULL)
+		dma_free_coherent(NULL, 240 * 320 * 2, fb_buffer, dma_handle);
+
+#if L1_DATA_A_LENGTH != 0
+	if (dma_desc_table)
+		l1_data_sram_free(dma_desc_table);
+#else
+	if (dma_desc_table)
+		dma_free_coherent(NULL, sizeof(unsigned long) * 2 * (320 + 7),
+				  &dma_handle, 0);
+#endif
+
+	stop_timers();
+
+	free_dma(CH_PPI);
+
+	kfree(tx09_fb.pseudo_palette);
+	fb_dealloc_cmap(&tx09_fb.cmap);
+
+	backlight_device_unregister(bl_dev);
+
+	unregister_framebuffer(&tx09_fb);
+
+	request_ports(0);
+
+	printk(KERN_INFO DRIVER_NAME ": Unregistered LCD driver.\n");
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int tx09_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	if (tx09_open_cnt > 0) {
+		WRITE_PPI_CONTROL(0);
+		SSYNC();
+		disable_dma(CH_PPI);
+	}
+	return 0;
+}
+
+static int tx09_resume(struct platform_device *pdev)
+{
+	if (tx09_open_cnt > 0) {
+		WRITE_PPI_CONTROL(0);
+		SSYNC();
+
+		config_dma();
+		config_ppi();
+
+		enable_dma(CH_PPI);
+		SSYNC();
+		WRITE_PPI_CONTROL(READ_PPI_CONTROL() | PORT_EN);
+		SSYNC();
+	}
+	return 0;
+}
+#else
+#define tx09_suspend NULL
+#define tx09_resume  NULL
+#endif
+
+static struct platform_driver tx09_driver = {
+	.probe = tx09_probe,
+	.remove = tx09_remove,
+	.suspend = tx09_suspend,
+	.resume = tx09_resume,
+	.driver = {
+		   .name = DRIVER_NAME,
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __devinit tx09_driver_init(void)
+{
+	return platform_driver_register(&tx09_driver);
+}
+
+static void __exit tx09_driver_cleanup(void)
+{
+	platform_driver_unregister(&tx09_driver);
+}
+
+MODULE_DESCRIPTION("Hitachi TX09D70VM1CDA TFT LCD Driver");
+MODULE_AUTHOR("Harald Krapfenbauer");
+MODULE_LICENSE("GPL");
+
+module_init(tx09_driver_init);
+module_exit(tx09_driver_cleanup);
-- 
1.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ