[Armadeus-commitlog] SF.net SVN: armadeus:[861] trunk
Brought to you by:
sszy
|
From: <ar...@us...> - 2008-07-28 15:23:54
|
Revision: 861
http://armadeus.svn.sourceforge.net/armadeus/?rev=861&view=rev
Author: artemys
Date: 2008-07-28 15:23:57 +0000 (Mon, 28 Jul 2008)
Log Message:
-----------
[LINUX] Add automatic generation of 013-imxfb patch + removing of PWM register update when doing imxfb_set_par()
Modified Paths:
--------------
trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.23.1/013-imxfb-improvements.diff
trunk/target/linux/Makefile
Added Paths:
-----------
trunk/target/linux/drivers/
trunk/target/linux/drivers/video/
trunk/target/linux/drivers/video/imxfb.c
Modified: trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.23.1/013-imxfb-improvements.diff
===================================================================
--- trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.23.1/013-imxfb-improvements.diff 2008-07-28 14:23:47 UTC (rev 860)
+++ trunk/buildroot/target/device/armadeus/linux/kernel-patches/2.6.23.1/013-imxfb-improvements.diff 2008-07-28 15:23:57 UTC (rev 861)
@@ -1,7 +1,8 @@
---- linux-2.6.23/drivers/video/imxfb.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.23-imx/drivers/video/imxfb.c 2006-10-01 14:22:39.000000000 +0200
-18:43:44.000000000 +0200
-+++ imxfb.c 2008-01-15 01:50:45.000000000 +0100
+PATCH AUTOMATICALLY GENERATED
+DON'T EDIT IT OR YOUR MODIFICATIONS WILL BE LOST
+(Take a look at armadeus/target/linux/ directory to know how to generate it)
+--- linux-2.6.23.1.original/drivers/video/imxfb.c 2007-10-12 18:43:44.000000000 +0200
++++ linux-2.6.23.1.mod/drivers/video/imxfb.c 2008-07-28 16:58:52.000000000 +0200
@@ -42,22 +42,48 @@
*/
#define DEBUG_VAR 1
@@ -63,7 +64,7 @@
static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info);
static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
-@@ -152,7 +178,6 @@ static int
+@@ -152,7 +178,6 @@
imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct imxfb_info *fbi = info->par;
@@ -71,7 +72,7 @@
if (var->xres < MIN_XRES)
var->xres = MIN_XRES;
-@@ -165,27 +190,39 @@ imxfb_check_var(struct fb_var_screeninfo
+@@ -165,27 +190,39 @@
var->xres_virtual = max(var->xres_virtual, var->xres);
var->yres_virtual = max(var->yres_virtual, var->yres);
@@ -125,7 +126,7 @@
pr_debug("RGBT length = %d:%d:%d:%d\n",
var->red.length, var->green.length, var->blue.length,
var->transp.length);
-@@ -248,10 +285,11 @@ static void imxfb_enable_controller(stru
+@@ -248,10 +285,11 @@
LCDC_RMCR = RMCR_LCDC_EN;
@@ -139,7 +140,7 @@
}
static void imxfb_disable_controller(struct imxfb_info *fbi)
-@@ -312,6 +350,7 @@ static int imxfb_activate_var(struct fb_
+@@ -312,6 +350,7 @@
pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
var->yres, var->vsync_len,
var->upper_margin, var->lower_margin);
@@ -147,11 +148,14 @@
#if DEBUG_VAR
if (var->xres < 16 || var->xres > 1024)
-@@ -349,7 +388,17 @@ static int imxfb_activate_var(struct fb_
+@@ -349,10 +388,17 @@
VCR_V_WAIT_2(var->lower_margin);
LCDC_SIZE = SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres);
- LCDC_PCR = fbi->pcr;
+- LCDC_PWMR = fbi->pwmr;
+- LCDC_LSCR1 = fbi->lscr1;
+- LCDC_DMACR = fbi->dmacr;
+ // On TFT LCD i.MXL can support 16, 12, 8, 4bpp with the same hardware interface (12 to 16 bits)
+ // So if userspace app wants a 8bpp screen switch to 8bpp (can save ressources, with SDL for ex)
+ if( (var->bits_per_pixel == 8) && (fbi->pcr & PCR_TFT) )
@@ -163,10 +167,10 @@
+ LCDC_PCR = fbi->pcr;
+
+ LCDC_VPW = VPW_VPW(var->xres * var->bits_per_pixel / 8 / 4);
- LCDC_PWMR = fbi->pwmr;
- LCDC_LSCR1 = fbi->lscr1;
- LCDC_DMACR = fbi->dmacr;
-@@ -391,7 +440,26 @@ static void imxfb_setup_gpio(struct imxf
+
+ return 0;
+ }
+@@ -391,7 +437,26 @@
case 1:
imx_gpio_mode(PD15_PF_LD0);
}
@@ -193,7 +197,7 @@
/* initialize GPIOs */
imx_gpio_mode(PD6_PF_LSCLK);
imx_gpio_mode(PD11_PF_CONTRAST);
-@@ -406,6 +474,7 @@ static void imxfb_setup_gpio(struct imxf
+@@ -406,6 +471,7 @@
imx_gpio_mode(PD9_PF_PS);
imx_gpio_mode(PD10_PF_SPL_SPR);
}
@@ -201,7 +205,7 @@
}
#ifdef CONFIG_PM
-@@ -469,9 +538,6 @@ static int __init imxfb_init_fbinfo(stru
+@@ -469,9 +535,6 @@
info->fbops = &imxfb_ops;
info->flags = FBINFO_FLAG_DEFAULT;
@@ -211,10 +215,24 @@
fbi->max_xres = inf->xres;
info->var.xres = inf->xres;
info->var.xres_virtual = inf->xres;
-Index: drivers/video/imxfb.h
-===================================================================
---- a/drivers/video/imxfb.h
-+++ b//dev/null
+@@ -596,6 +659,12 @@
+ imxfb_setup_gpio(fbi);
+
+ imxfb_set_par(info);
++ /* JB: The following parameters are only needed once at startup and so
++ removed from from imxfb_set_par()/imxfb_activate_var() */
++ LCDC_PWMR = fbi->pwmr;
++ LCDC_LSCR1 = fbi->lscr1;
++ LCDC_DMACR = fbi->dmacr;
++
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register framebuffer\n");
+PATCH AUTOMATICALLY GENERATED
+DON'T EDIT IT OR YOUR MODIFICATIONS WILL BE LOST
+(Take a look at armadeus/target/linux/ directory to know how to generate it)
+--- linux-2.6.23.1.original/drivers/video/imxfb.h 2007-10-12 18:43:44.000000000 +0200
++++ linux-2.6.23.1.mod/drivers/video/imxfb.h 1970-01-01 01:00:00.000000000 +0100
@@ -1,73 +0,0 @@
-/*
- * linux/drivers/video/imxfb.h
Modified: trunk/target/linux/Makefile
===================================================================
--- trunk/target/linux/Makefile 2008-07-28 14:23:47 UTC (rev 860)
+++ trunk/target/linux/Makefile 2008-07-28 15:23:57 UTC (rev 861)
@@ -64,7 +64,21 @@
### Other Patches: ---
+# Special case: drivers/video/imxfb.h doesn't exist
+FILES_O1=drivers/video/imxfb.c drivers/video/imxfb.h
+DEP_O1=drivers/video/imxfb.c
+TARGET_O1:=$(TMP_DIR)/013-imxfb-improvements.diff
+$(TARGET_O1): $(DEP_O1)
+ @$(START_CMD)
+ rm -f $@
+ for file in $(FILES_O1); do $(PATCH_CMD) --append $(LINUX_DIR_TO_DIFF)/$$file ../linux/$$file $@; echo " adding $$file"; done
+ @$(CLEAN_PATCH_CMD)
+ @echo
+PATCHES+=$(TARGET_O1)
+FILES+=$(FILES_O1)
+
+
### Patches generation: ---
.PHONY: clean all help show import patch patch_install
@@ -82,7 +96,7 @@
patch_install: patch
@cp -a $(PATCHES) $(PATCH_DIR)/
@echo "Patches installed, you can check the diff in $(PATCH_DIR)/"
- @echo " please don't commit only timestamp changes !"
+ @echo " please don't commit <<timestamp only>> changes !"
show:
@echo "Linux kernel files ($(LINUX_VERSION)) from which I can generate patch:"
@@ -91,7 +105,7 @@
@for patch in $(PATCHES); do echo " $$patch"; done
import:
- @for file in $(FILES); do cp $(LINUX_DIR)/$$file $$file; done
+ @for file in $(FILES); do if [ -f $(LINUX_DIR)/$$file ]; then cp $(LINUX_DIR)/$$file $$file; fi; done
@echo "Import done, check your modifications with svn status -q"
help:
Added: trunk/target/linux/drivers/video/imxfb.c
===================================================================
--- trunk/target/linux/drivers/video/imxfb.c (rev 0)
+++ trunk/target/linux/drivers/video/imxfb.c 2008-07-28 15:23:57 UTC (rev 861)
@@ -0,0 +1,749 @@
+/*
+ * linux/drivers/video/imxfb.c
+ *
+ * Freescale i.MX Frame Buffer device driver
+ *
+ * Copyright (C) 2004 Sascha Hauer, Pengutronix
+ * Based on acornfb.c Copyright (C) Russell King.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive for
+ * more details.
+ *
+ * Please direct your questions and comments on this driver to the following
+ * email address:
+ *
+ * lin...@li...
+ */
+
+//#define DEBUG 1
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/cpufreq.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/arch/imxfb.h>
+
+/*
+ * Complain if VAR is out of range.
+ */
+#define DEBUG_VAR 1
+
+struct imxfb_info {
+ struct device *dev;
+
+ u_int max_bpp;
+ u_int max_xres;
+ u_int max_yres;
+
+ /*
+ * These are the addresses we mapped
+ * the framebuffer memory region to.
+ */
+ dma_addr_t map_dma;
+ u_char * map_cpu;
+ u_int map_size;
+
+ u_char * screen_cpu;
+ dma_addr_t screen_dma;
+ u_int palette_size;
+
+ dma_addr_t dbar1;
+ dma_addr_t dbar2;
+
+ u_int pcr;
+ u_int pwmr;
+ u_int lscr1;
+ u_int dmacr;
+ u_int cmap_inverse:1,
+ cmap_static:1,
+ unused:30;
+
+ void (*lcd_power)(int);
+ void (*backlight_power)(int);
+};
+
+#define IMX_NAME "IMX"
+
+/*
+ * Minimum X and Y resolutions
+ */
+#define MIN_XRES 64
+#define MIN_YRES 64
+
+static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info);
+
+static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+#define LCDC_PALETTE(x) __REG2(IMX_LCDC_BASE+0x800, (x)<<2)
+static int
+imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int trans, struct fb_info *info)
+{
+ struct imxfb_info *fbi = info->par;
+ u_int val, ret = 1;
+
+#define CNVT_TOHW(val,width) ((((val)<<(width))+0x7FFF-(val))>>16)
+ if (regno < fbi->palette_size) {
+ val = (CNVT_TOHW(red, 4) << 8) |
+ (CNVT_TOHW(green,4) << 4) |
+ CNVT_TOHW(blue, 4);
+
+ LCDC_PALETTE(regno) = val;
+ ret = 0;
+ }
+ return ret;
+}
+
+static int
+imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+ u_int trans, struct fb_info *info)
+{
+ struct imxfb_info *fbi = info->par;
+ unsigned int val;
+ int ret = 1;
+
+ /*
+ * If inverse mode was selected, invert all the colours
+ * rather than the register number. The register number
+ * is what you poke into the framebuffer to produce the
+ * colour you requested.
+ */
+ if (fbi->cmap_inverse) {
+ red = 0xffff - red;
+ green = 0xffff - green;
+ blue = 0xffff - blue;
+ }
+
+ /*
+ * If greyscale is true, then we convert the RGB value
+ * to greyscale no mater what visual we are using.
+ */
+ if (info->var.grayscale)
+ red = green = blue = (19595 * red + 38470 * green +
+ 7471 * blue) >> 16;
+
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 12 or 16-bit True Colour. We encode the RGB value
+ * according to the RGB bitfield information.
+ */
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+
+ val = chan_to_field(red, &info->var.red);
+ val |= chan_to_field(green, &info->var.green);
+ val |= chan_to_field(blue, &info->var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ case FB_VISUAL_STATIC_PSEUDOCOLOR:
+ case FB_VISUAL_PSEUDOCOLOR:
+ ret = imxfb_setpalettereg(regno, red, green, blue, trans, info);
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * imxfb_check_var():
+ * Round up in the following order: bits_per_pixel, xres,
+ * yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+ * bitfields, horizontal timing, vertical timing.
+ */
+static int
+imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct imxfb_info *fbi = info->par;
+
+ if (var->xres < MIN_XRES)
+ var->xres = MIN_XRES;
+ if (var->yres < MIN_YRES)
+ var->yres = MIN_YRES;
+ if (var->xres > fbi->max_xres)
+ var->xres = fbi->max_xres;
+ if (var->yres > fbi->max_yres)
+ var->yres = fbi->max_yres;
+ var->xres_virtual = max(var->xres_virtual, var->xres);
+ var->yres_virtual = max(var->yres_virtual, var->yres);
+
+ memset(&var->transp, 0, sizeof(var->transp));
+
+ pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.length = var->bits_per_pixel;
+ var->red.offset = 0;
+ var->green.length = var->bits_per_pixel;
+ var->green.offset = 0;
+ var->blue.length = var->bits_per_pixel;
+ var->blue.offset = 0;
+ break;
+ case 16:
+ if (fbi->pcr & PCR_TFT) {
+ var->red.length = 5;
+ var->red.offset = 11;
+ var->green.length = 6;
+ var->green.offset = 5;
+ var->blue.length = 5;
+ var->blue.offset = 0;
+ } else {
+ var->red.length = 4;
+ var->red.offset = 8;
+ var->green.length = 4;
+ var->green.offset = 4;
+ var->blue.length = 4;
+ var->blue.offset = 0;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ pr_debug("RGBT length = %d:%d:%d:%d\n",
+ var->red.length, var->green.length, var->blue.length,
+ var->transp.length);
+
+ pr_debug("RGBT offset = %d:%d:%d:%d\n",
+ var->red.offset, var->green.offset, var->blue.offset,
+ var->transp.offset);
+
+ return 0;
+}
+
+/*
+ * imxfb_set_par():
+ * Set the user defined part of the display for the specified console
+ */
+static int imxfb_set_par(struct fb_info *info)
+{
+ struct imxfb_info *fbi = info->par;
+ struct fb_var_screeninfo *var = &info->var;
+
+ pr_debug("set_par\n");
+
+ if (var->bits_per_pixel == 16)
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ else if (!fbi->cmap_static)
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ else {
+ /*
+ * Some people have weird ideas about wanting static
+ * pseudocolor maps. I suspect their user space
+ * applications are broken.
+ */
+ info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+ }
+
+ info->fix.line_length = var->xres_virtual *
+ var->bits_per_pixel / 8;
+ fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
+
+ imxfb_activate_var(var, info);
+
+ return 0;
+}
+
+static void imxfb_enable_controller(struct imxfb_info *fbi)
+{
+ pr_debug("Enabling LCD controller\n");
+
+ /* initialize LCDC */
+ LCDC_RMCR &= ~RMCR_LCDC_EN; /* just to be safe... */
+
+ LCDC_SSA = fbi->screen_dma;
+ /* physical screen start address */
+ LCDC_VPW = VPW_VPW(fbi->max_xres * fbi->max_bpp / 8 / 4);
+
+ LCDC_POS = 0x00000000; /* panning offset 0 (0 pixel offset) */
+
+ /* disable hardware cursor */
+ LCDC_CPOS &= ~(CPOS_CC0 | CPOS_CC1);
+
+ LCDC_RMCR = RMCR_LCDC_EN;
+
+ if(fbi->lcd_power)
+ fbi->lcd_power(1);
+ /* enable backlight after LCD */
+ if(fbi->backlight_power)
+ fbi->backlight_power(1);
+}
+
+static void imxfb_disable_controller(struct imxfb_info *fbi)
+{
+ pr_debug("Disabling LCD controller\n");
+
+ if(fbi->backlight_power)
+ fbi->backlight_power(0);
+ if(fbi->lcd_power)
+ fbi->lcd_power(0);
+
+ LCDC_RMCR = 0;
+}
+
+static int imxfb_blank(int blank, struct fb_info *info)
+{
+ struct imxfb_info *fbi = info->par;
+
+ pr_debug("imxfb_blank: blank=%d\n", blank);
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ imxfb_disable_controller(fbi);
+ break;
+
+ case FB_BLANK_UNBLANK:
+ imxfb_enable_controller(fbi);
+ break;
+ }
+ return 0;
+}
+
+static struct fb_ops imxfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = imxfb_check_var,
+ .fb_set_par = imxfb_set_par,
+ .fb_setcolreg = imxfb_setcolreg,
+ .fb_fillrect = cfb_fillrect,
+ .fb_copyarea = cfb_copyarea,
+ .fb_imageblit = cfb_imageblit,
+ .fb_blank = imxfb_blank,
+};
+
+/*
+ * imxfb_activate_var():
+ * Configures LCD Controller based on entries in var parameter. Settings are
+ * only written to the controller if changes were made.
+ */
+static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ struct imxfb_info *fbi = info->par;
+ pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
+ var->xres, var->hsync_len,
+ var->left_margin, var->right_margin);
+ pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
+ var->yres, var->vsync_len,
+ var->upper_margin, var->lower_margin);
+ pr_debug("var: bpp=%d\n", var->bits_per_pixel);
+
+#if DEBUG_VAR
+ if (var->xres < 16 || var->xres > 1024)
+ printk(KERN_ERR "%s: invalid xres %d\n",
+ info->fix.id, var->xres);
+ if (var->hsync_len < 1 || var->hsync_len > 64)
+ printk(KERN_ERR "%s: invalid hsync_len %d\n",
+ info->fix.id, var->hsync_len);
+ if (var->left_margin > 255)
+ printk(KERN_ERR "%s: invalid left_margin %d\n",
+ info->fix.id, var->left_margin);
+ if (var->right_margin > 255)
+ printk(KERN_ERR "%s: invalid right_margin %d\n",
+ info->fix.id, var->right_margin);
+ if (var->yres < 1 || var->yres > 511)
+ printk(KERN_ERR "%s: invalid yres %d\n",
+ info->fix.id, var->yres);
+ if (var->vsync_len > 100)
+ printk(KERN_ERR "%s: invalid vsync_len %d\n",
+ info->fix.id, var->vsync_len);
+ if (var->upper_margin > 63)
+ printk(KERN_ERR "%s: invalid upper_margin %d\n",
+ info->fix.id, var->upper_margin);
+ if (var->lower_margin > 255)
+ printk(KERN_ERR "%s: invalid lower_margin %d\n",
+ info->fix.id, var->lower_margin);
+#endif
+
+ LCDC_HCR = HCR_H_WIDTH(var->hsync_len) |
+ HCR_H_WAIT_1(var->left_margin) |
+ HCR_H_WAIT_2(var->right_margin);
+
+ LCDC_VCR = VCR_V_WIDTH(var->vsync_len) |
+ VCR_V_WAIT_1(var->upper_margin) |
+ VCR_V_WAIT_2(var->lower_margin);
+
+ LCDC_SIZE = SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres);
+ // On TFT LCD i.MXL can support 16, 12, 8, 4bpp with the same hardware interface (12 to 16 bits)
+ // So if userspace app wants a 8bpp screen switch to 8bpp (can save ressources, with SDL for ex)
+ if( (var->bits_per_pixel == 8) && (fbi->pcr & PCR_TFT) )
+ {
+ pr_debug("Switching imxfb to 8bpp\n");
+ LCDC_PCR = (fbi->pcr & (~PCR_BPIX_MASK)) | PCR_BPIX_8 | PCR_END_BYTE_SWAP;
+ }
+ else
+ LCDC_PCR = fbi->pcr;
+
+ LCDC_VPW = VPW_VPW(var->xres * var->bits_per_pixel / 8 / 4);
+
+ return 0;
+}
+
+static void imxfb_setup_gpio(struct imxfb_info *fbi)
+{
+ int width;
+
+ LCDC_RMCR &= ~(RMCR_LCDC_EN | RMCR_SELF_REF);
+
+ if( fbi->pcr & PCR_TFT )
+ width = 16;
+ else
+ width = 1 << ((fbi->pcr >> 28) & 0x3);
+
+ switch(width) {
+ case 16:
+ imx_gpio_mode(PD30_PF_LD15);
+ imx_gpio_mode(PD29_PF_LD14);
+ imx_gpio_mode(PD28_PF_LD13);
+ imx_gpio_mode(PD27_PF_LD12);
+ imx_gpio_mode(PD26_PF_LD11);
+ imx_gpio_mode(PD25_PF_LD10);
+ imx_gpio_mode(PD24_PF_LD9);
+ imx_gpio_mode(PD23_PF_LD8);
+ case 8:
+ imx_gpio_mode(PD22_PF_LD7);
+ imx_gpio_mode(PD21_PF_LD6);
+ imx_gpio_mode(PD20_PF_LD5);
+ imx_gpio_mode(PD19_PF_LD4);
+ case 4:
+ imx_gpio_mode(PD18_PF_LD3);
+ imx_gpio_mode(PD17_PF_LD2);
+ case 2:
+ imx_gpio_mode(PD16_PF_LD1);
+ case 1:
+ imx_gpio_mode(PD15_PF_LD0);
+ }
+#ifdef CONFIG_MACH_APF9328
+ /* initialize standard GPIOs */
+ imx_gpio_mode(PD6_PF_LSCLK);
+ imx_gpio_mode(PD14_PF_FLM_VSYNC);
+ imx_gpio_mode(PD13_PF_LP_HSYNC);
+// imx_gpio_mode(PD12_PF_ACD_OE);
+
+ /* if != 0 */
+ if( fbi->pwmr ) {
+ imx_gpio_mode(PD11_PF_CONTRAST);
+ }
+
+ /* sharp display specific */
+ if( fbi->pcr & PCR_SHARP ) {
+ imx_gpio_mode(PD10_PF_SPL_SPR);
+ imx_gpio_mode(PD7_PF_REV);
+ imx_gpio_mode(PD8_PF_CLS);
+ imx_gpio_mode(PD9_PF_PS);
+ }
+#else
+ /* initialize GPIOs */
+ imx_gpio_mode(PD6_PF_LSCLK);
+ imx_gpio_mode(PD11_PF_CONTRAST);
+ imx_gpio_mode(PD14_PF_FLM_VSYNC);
+ imx_gpio_mode(PD13_PF_LP_HSYNC);
+ imx_gpio_mode(PD12_PF_ACD_OE);
+
+ /* These are only needed for Sharp HR TFT displays */
+ if (fbi->pcr & PCR_SHARP) {
+ imx_gpio_mode(PD7_PF_REV);
+ imx_gpio_mode(PD8_PF_CLS);
+ imx_gpio_mode(PD9_PF_PS);
+ imx_gpio_mode(PD10_PF_SPL_SPR);
+ }
+#endif //CONFIG_MACH_APF9328
+}
+
+#ifdef CONFIG_PM
+/*
+ * Power management hooks. Note that we won't be called from IRQ context,
+ * unlike the blank functions above, so we may sleep.
+ */
+static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct imxfb_info *fbi = platform_get_drvdata(dev);
+ pr_debug("%s\n",__FUNCTION__);
+
+ imxfb_disable_controller(fbi);
+ return 0;
+}
+
+static int imxfb_resume(struct platform_device *dev)
+{
+ struct imxfb_info *fbi = platform_get_drvdata(dev);
+ pr_debug("%s\n",__FUNCTION__);
+
+ imxfb_enable_controller(fbi);
+ return 0;
+}
+#else
+#define imxfb_suspend NULL
+#define imxfb_resume NULL
+#endif
+
+static int __init imxfb_init_fbinfo(struct device *dev)
+{
+ struct imxfb_mach_info *inf = dev->platform_data;
+ struct fb_info *info = dev_get_drvdata(dev);
+ struct imxfb_info *fbi = info->par;
+
+ pr_debug("%s\n",__FUNCTION__);
+
+ info->pseudo_palette = kmalloc( sizeof(u32) * 16, GFP_KERNEL);
+ if (!info->pseudo_palette)
+ return -ENOMEM;
+
+ memset(fbi, 0, sizeof(struct imxfb_info));
+ fbi->dev = dev;
+
+ strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
+
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.type_aux = 0;
+ info->fix.xpanstep = 0;
+ info->fix.ypanstep = 0;
+ info->fix.ywrapstep = 0;
+ info->fix.accel = FB_ACCEL_NONE;
+
+ info->var.nonstd = 0;
+ info->var.activate = FB_ACTIVATE_NOW;
+ info->var.height = -1;
+ info->var.width = -1;
+ info->var.accel_flags = 0;
+ info->var.vmode = FB_VMODE_NONINTERLACED;
+
+ info->fbops = &imxfb_ops;
+ info->flags = FBINFO_FLAG_DEFAULT;
+
+ fbi->max_xres = inf->xres;
+ info->var.xres = inf->xres;
+ info->var.xres_virtual = inf->xres;
+ fbi->max_yres = inf->yres;
+ info->var.yres = inf->yres;
+ info->var.yres_virtual = inf->yres;
+ fbi->max_bpp = inf->bpp;
+ info->var.bits_per_pixel = inf->bpp;
+ info->var.pixclock = inf->pixclock;
+ info->var.hsync_len = inf->hsync_len;
+ info->var.left_margin = inf->left_margin;
+ info->var.right_margin = inf->right_margin;
+ info->var.vsync_len = inf->vsync_len;
+ info->var.upper_margin = inf->upper_margin;
+ info->var.lower_margin = inf->lower_margin;
+ info->var.sync = inf->sync;
+ info->var.grayscale = inf->cmap_greyscale;
+ fbi->cmap_inverse = inf->cmap_inverse;
+ fbi->cmap_static = inf->cmap_static;
+ fbi->pcr = inf->pcr;
+ fbi->lscr1 = inf->lscr1;
+ fbi->dmacr = inf->dmacr;
+ fbi->pwmr = inf->pwmr;
+ fbi->lcd_power = inf->lcd_power;
+ fbi->backlight_power = inf->backlight_power;
+ info->fix.smem_len = fbi->max_xres * fbi->max_yres *
+ fbi->max_bpp / 8;
+
+ return 0;
+}
+
+/*
+ * Allocates the DRAM memory for the frame buffer. This buffer is
+ * remapped into a non-cached, non-buffered, memory region to
+ * allow pixel writes to occur without flushing the cache.
+ * Once this area is remapped, all virtual memory access to the
+ * video memory should occur at the new region.
+ */
+static int __init imxfb_map_video_memory(struct fb_info *info)
+{
+ struct imxfb_info *fbi = info->par;
+
+ fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
+ fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
+ &fbi->map_dma,GFP_KERNEL);
+
+ if (fbi->map_cpu) {
+ info->screen_base = fbi->map_cpu;
+ fbi->screen_cpu = fbi->map_cpu;
+ fbi->screen_dma = fbi->map_dma;
+ info->fix.smem_start = fbi->screen_dma;
+ }
+
+ return fbi->map_cpu ? 0 : -ENOMEM;
+}
+
+static int __init imxfb_probe(struct platform_device *pdev)
+{
+ struct imxfb_info *fbi;
+ struct fb_info *info;
+ struct imxfb_mach_info *inf;
+ struct resource *res;
+ int ret;
+
+ printk("i.MX Framebuffer driver\n");
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if(!res)
+ return -ENODEV;
+
+ inf = pdev->dev.platform_data;
+ if(!inf) {
+ dev_err(&pdev->dev,"No platform_data available\n");
+ return -ENOMEM;
+ }
+
+ info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
+ if(!info)
+ return -ENOMEM;
+
+ fbi = info->par;
+
+ platform_set_drvdata(pdev, info);
+
+ ret = imxfb_init_fbinfo(&pdev->dev);
+ if( ret < 0 )
+ goto failed_init;
+
+ res = request_mem_region(res->start, res->end - res->start + 1, "IMXFB");
+ if (!res) {
+ ret = -EBUSY;
+ goto failed_regs;
+ }
+
+ if (!inf->fixed_screen_cpu) {
+ ret = imxfb_map_video_memory(info);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
+ ret = -ENOMEM;
+ goto failed_map;
+ }
+ } else {
+ /* Fixed framebuffer mapping enables location of the screen in eSRAM */
+ fbi->map_cpu = inf->fixed_screen_cpu;
+ fbi->map_dma = inf->fixed_screen_dma;
+ info->screen_base = fbi->map_cpu;
+ fbi->screen_cpu = fbi->map_cpu;
+ fbi->screen_dma = fbi->map_dma;
+ info->fix.smem_start = fbi->screen_dma;
+ }
+
+ /*
+ * This makes sure that our colour bitfield
+ * descriptors are correctly initialised.
+ */
+ imxfb_check_var(&info->var, info);
+
+ ret = fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
+ if (ret < 0)
+ goto failed_cmap;
+
+ imxfb_setup_gpio(fbi);
+
+ imxfb_set_par(info);
+ /* JB: The following parameters are only needed once at startup and so
+ removed from from imxfb_set_par()/imxfb_activate_var() */
+ LCDC_PWMR = fbi->pwmr;
+ LCDC_LSCR1 = fbi->lscr1;
+ LCDC_DMACR = fbi->dmacr;
+
+ ret = register_framebuffer(info);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register framebuffer\n");
+ goto failed_register;
+ }
+
+ imxfb_enable_controller(fbi);
+
+ return 0;
+
+failed_register:
+ fb_dealloc_cmap(&info->cmap);
+failed_cmap:
+ if (!inf->fixed_screen_cpu)
+ dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
+ fbi->map_dma);
+failed_map:
+ kfree(info->pseudo_palette);
+failed_regs:
+ release_mem_region(res->start, res->end - res->start);
+failed_init:
+ platform_set_drvdata(pdev, NULL);
+ framebuffer_release(info);
+ return ret;
+}
+
+static int imxfb_remove(struct platform_device *pdev)
+{
+ struct fb_info *info = platform_get_drvdata(pdev);
+ struct imxfb_info *fbi = info->par;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ imxfb_disable_controller(fbi);
+
+ unregister_framebuffer(info);
+
+ fb_dealloc_cmap(&info->cmap);
+ kfree(info->pseudo_palette);
+ framebuffer_release(info);
+
+ release_mem_region(res->start, res->end - res->start + 1);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+void imxfb_shutdown(struct platform_device * dev)
+{
+ struct fb_info *info = platform_get_drvdata(dev);
+ struct imxfb_info *fbi = info->par;
+ imxfb_disable_controller(fbi);
+}
+
+static struct platform_driver imxfb_driver = {
+ .probe = imxfb_probe,
+ .suspend = imxfb_suspend,
+ .resume = imxfb_resume,
+ .remove = imxfb_remove,
+ .shutdown = imxfb_shutdown,
+ .driver = {
+ .name = "imx-fb",
+ },
+};
+
+int __init imxfb_init(void)
+{
+ return platform_driver_register(&imxfb_driver);
+}
+
+static void __exit imxfb_cleanup(void)
+{
+ platform_driver_unregister(&imxfb_driver);
+}
+
+module_init(imxfb_init);
+module_exit(imxfb_cleanup);
+
+MODULE_DESCRIPTION("Motorola i.MX framebuffer driver");
+MODULE_AUTHOR("Sascha Hauer, Pengutronix");
+MODULE_LICENSE("GPL");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|