Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal/fbdev-3.x into fbdev-next

Conflicts:
	drivers/video/atmel_lcdfb.c
This commit is contained in:
Florian Tobias Schandinat 2011-08-29 09:14:30 +00:00
commit d4a7dbfdf1
28 changed files with 1039 additions and 303 deletions

View file

@ -66,8 +66,8 @@ struct fsl_diu_shared_fb {
bool in_use; bool in_use;
}; };
unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel, u32 mpc512x_get_pixel_format(enum fsl_diu_monitor_port port,
int monitor_port) unsigned int bits_per_pixel)
{ {
switch (bits_per_pixel) { switch (bits_per_pixel) {
case 32: case 32:
@ -80,11 +80,12 @@ unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
return 0x00000400; return 0x00000400;
} }
void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base) void mpc512x_set_gamma_table(enum fsl_diu_monitor_port port,
char *gamma_table_base)
{ {
} }
void mpc512x_set_monitor_port(int monitor_port) void mpc512x_set_monitor_port(enum fsl_diu_monitor_port port)
{ {
} }
@ -182,14 +183,10 @@ void mpc512x_set_pixel_clock(unsigned int pixclock)
iounmap(ccm); iounmap(ccm);
} }
ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf) enum fsl_diu_monitor_port
mpc512x_valid_monitor_port(enum fsl_diu_monitor_port port)
{ {
return sprintf(buf, "0 - 5121 LCD\n"); return FSL_DIU_PORT_DVI;
}
int mpc512x_set_sysfs_monitor_port(int val)
{
return 0;
} }
static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb; static struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
@ -332,8 +329,7 @@ void __init mpc512x_setup_diu(void)
diu_ops.set_gamma_table = mpc512x_set_gamma_table; diu_ops.set_gamma_table = mpc512x_set_gamma_table;
diu_ops.set_monitor_port = mpc512x_set_monitor_port; diu_ops.set_monitor_port = mpc512x_set_monitor_port;
diu_ops.set_pixel_clock = mpc512x_set_pixel_clock; diu_ops.set_pixel_clock = mpc512x_set_pixel_clock;
diu_ops.show_monitor_port = mpc512x_show_monitor_port; diu_ops.valid_monitor_port = mpc512x_valid_monitor_port;
diu_ops.set_sysfs_monitor_port = mpc512x_set_sysfs_monitor_port;
diu_ops.release_bootmem = mpc512x_release_bootmem; diu_ops.release_bootmem = mpc512x_release_bootmem;
#endif #endif
} }

View file

@ -93,8 +93,8 @@
* The Area Descriptor is a 32-bit value that determine which bits in each * The Area Descriptor is a 32-bit value that determine which bits in each
* pixel are to be used for each color. * pixel are to be used for each color.
*/ */
static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel, static u32 p1022ds_get_pixel_format(enum fsl_diu_monitor_port port,
int monitor_port) unsigned int bits_per_pixel)
{ {
switch (bits_per_pixel) { switch (bits_per_pixel) {
case 32: case 32:
@ -118,7 +118,8 @@ static unsigned int p1022ds_get_pixel_format(unsigned int bits_per_pixel,
* On some boards, the gamma table for some ports may need to be modified. * On some boards, the gamma table for some ports may need to be modified.
* This is not the case on the P1022DS, so we do nothing. * This is not the case on the P1022DS, so we do nothing.
*/ */
static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base) static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port,
char *gamma_table_base)
{ {
} }
@ -126,7 +127,7 @@ static void p1022ds_set_gamma_table(int monitor_port, char *gamma_table_base)
* p1022ds_set_monitor_port: switch the output to a different monitor port * p1022ds_set_monitor_port: switch the output to a different monitor port
* *
*/ */
static void p1022ds_set_monitor_port(int monitor_port) static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port)
{ {
struct device_node *pixis_node; struct device_node *pixis_node;
void __iomem *pixis; void __iomem *pixis;
@ -145,19 +146,21 @@ static void p1022ds_set_monitor_port(int monitor_port)
} }
brdcfg1 = pixis + 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */ brdcfg1 = pixis + 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */
switch (monitor_port) { switch (port) {
case 0: /* DVI */ case FSL_DIU_PORT_DVI:
printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
/* Enable the DVI port, disable the DFP and the backlight */ /* Enable the DVI port, disable the DFP and the backlight */
clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT, clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT,
PX_BRDCFG1_DVIEN); PX_BRDCFG1_DVIEN);
break; break;
case 1: /* Single link LVDS */ case FSL_DIU_PORT_LVDS:
printk(KERN_INFO "%s:%u\n", __func__, __LINE__);
/* Enable the DFP port, disable the DVI and the backlight */ /* Enable the DFP port, disable the DVI and the backlight */
clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT, clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT,
PX_BRDCFG1_DFPEN); PX_BRDCFG1_DFPEN);
break; break;
default: default:
pr_err("p1022ds: unsupported monitor port %i\n", monitor_port); pr_err("p1022ds: unsupported monitor port %i\n", port);
} }
iounmap(pixis); iounmap(pixis);
@ -214,23 +217,18 @@ void p1022ds_set_pixel_clock(unsigned int pixclock)
} }
/** /**
* p1022ds_show_monitor_port: show the current monitor * p1022ds_valid_monitor_port: set the monitor port for sysfs
*
* This function returns a string indicating whether the current monitor is
* set to DVI or LVDS.
*/ */
ssize_t p1022ds_show_monitor_port(int monitor_port, char *buf) enum fsl_diu_monitor_port
p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port)
{ {
return sprintf(buf, "%c0 - DVI\n%c1 - Single link LVDS\n", switch (port) {
monitor_port == 0 ? '*' : ' ', monitor_port == 1 ? '*' : ' '); case FSL_DIU_PORT_DVI:
} case FSL_DIU_PORT_LVDS:
return port;
/** default:
* p1022ds_set_sysfs_monitor_port: set the monitor port for sysfs return FSL_DIU_PORT_DVI; /* Dual-link LVDS is not supported */
*/ }
int p1022ds_set_sysfs_monitor_port(int val)
{
return val < 2 ? val : 0;
} }
#endif #endif
@ -305,8 +303,7 @@ static void __init p1022_ds_setup_arch(void)
diu_ops.set_gamma_table = p1022ds_set_gamma_table; diu_ops.set_gamma_table = p1022ds_set_gamma_table;
diu_ops.set_monitor_port = p1022ds_set_monitor_port; diu_ops.set_monitor_port = p1022ds_set_monitor_port;
diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; diu_ops.set_pixel_clock = p1022ds_set_pixel_clock;
diu_ops.show_monitor_port = p1022ds_show_monitor_port; diu_ops.valid_monitor_port = p1022ds_valid_monitor_port;
diu_ops.set_sysfs_monitor_port = p1022ds_set_sysfs_monitor_port;
#endif #endif
#ifdef CONFIG_SMP #ifdef CONFIG_SMP

View file

@ -152,10 +152,10 @@ machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices);
(c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \ (c2 << AD_COMP_2_SHIFT) | (c1 << AD_COMP_1_SHIFT) | \
(c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT)) (c0 << AD_COMP_0_SHIFT) | (size << AD_PIXEL_S_SHIFT))
unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel, u32 mpc8610hpcd_get_pixel_format(enum fsl_diu_monitor_port port,
int monitor_port) unsigned int bits_per_pixel)
{ {
static const unsigned long pixelformat[][3] = { static const u32 pixelformat[][3] = {
{ {
MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8), MAKE_AD(3, 0, 2, 1, 3, 8, 8, 8, 8),
MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0), MAKE_AD(4, 2, 0, 1, 2, 8, 8, 8, 0),
@ -170,7 +170,8 @@ unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel,
unsigned int arch_monitor; unsigned int arch_monitor;
/* The DVI port is mis-wired on revision 1 of this board. */ /* The DVI port is mis-wired on revision 1 of this board. */
arch_monitor = ((*pixis_arch == 0x01) && (monitor_port == 0))? 0 : 1; arch_monitor =
((*pixis_arch == 0x01) && (port == FSL_DIU_PORT_DVI)) ? 0 : 1;
switch (bits_per_pixel) { switch (bits_per_pixel) {
case 32: case 32:
@ -185,10 +186,11 @@ unsigned int mpc8610hpcd_get_pixel_format(unsigned int bits_per_pixel,
} }
} }
void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base) void mpc8610hpcd_set_gamma_table(enum fsl_diu_monitor_port port,
char *gamma_table_base)
{ {
int i; int i;
if (monitor_port == 2) { /* dual link LVDS */ if (port == FSL_DIU_PORT_DLVDS) {
for (i = 0; i < 256*3; i++) for (i = 0; i < 256*3; i++)
gamma_table_base[i] = (gamma_table_base[i] << 2) | gamma_table_base[i] = (gamma_table_base[i] << 2) |
((gamma_table_base[i] >> 6) & 0x03); ((gamma_table_base[i] >> 6) & 0x03);
@ -199,17 +201,21 @@ void mpc8610hpcd_set_gamma_table(int monitor_port, char *gamma_table_base)
#define PX_BRDCFG0_DLINK (1 << 4) #define PX_BRDCFG0_DLINK (1 << 4)
#define PX_BRDCFG0_DIU_MASK (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK) #define PX_BRDCFG0_DIU_MASK (PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK)
void mpc8610hpcd_set_monitor_port(int monitor_port) void mpc8610hpcd_set_monitor_port(enum fsl_diu_monitor_port port)
{ {
static const u8 bdcfg[] = { switch (port) {
PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK, case FSL_DIU_PORT_DVI:
PX_BRDCFG0_DLINK,
0,
};
if (monitor_port < 3)
clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK, clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK,
bdcfg[monitor_port]); PX_BRDCFG0_DVISEL | PX_BRDCFG0_DLINK);
break;
case FSL_DIU_PORT_LVDS:
clrsetbits_8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK,
PX_BRDCFG0_DLINK);
break;
case FSL_DIU_PORT_DLVDS:
clrbits8(pixis_bdcfg0, PX_BRDCFG0_DIU_MASK);
break;
}
} }
/** /**
@ -262,20 +268,10 @@ void mpc8610hpcd_set_pixel_clock(unsigned int pixclock)
iounmap(guts); iounmap(guts);
} }
ssize_t mpc8610hpcd_show_monitor_port(int monitor_port, char *buf) enum fsl_diu_monitor_port
mpc8610hpcd_valid_monitor_port(enum fsl_diu_monitor_port port)
{ {
return snprintf(buf, PAGE_SIZE, return port;
"%c0 - DVI\n"
"%c1 - Single link LVDS\n"
"%c2 - Dual link LVDS\n",
monitor_port == 0 ? '*' : ' ',
monitor_port == 1 ? '*' : ' ',
monitor_port == 2 ? '*' : ' ');
}
int mpc8610hpcd_set_sysfs_monitor_port(int val)
{
return val < 3 ? val : 0;
} }
#endif #endif
@ -307,8 +303,7 @@ static void __init mpc86xx_hpcd_setup_arch(void)
diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table; diu_ops.set_gamma_table = mpc8610hpcd_set_gamma_table;
diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port; diu_ops.set_monitor_port = mpc8610hpcd_set_monitor_port;
diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock; diu_ops.set_pixel_clock = mpc8610hpcd_set_pixel_clock;
diu_ops.show_monitor_port = mpc8610hpcd_show_monitor_port; diu_ops.valid_monitor_port = mpc8610hpcd_valid_monitor_port;
diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port;
#endif #endif
pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis"); pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis");

View file

@ -22,15 +22,24 @@ struct device_node;
extern void fsl_rstcr_restart(char *cmd); extern void fsl_rstcr_restart(char *cmd);
#if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE)
/* The different ports that the DIU can be connected to */
enum fsl_diu_monitor_port {
FSL_DIU_PORT_DVI, /* DVI */
FSL_DIU_PORT_LVDS, /* Single-link LVDS */
FSL_DIU_PORT_DLVDS /* Dual-link LVDS */
};
struct platform_diu_data_ops { struct platform_diu_data_ops {
unsigned int (*get_pixel_format) (unsigned int bits_per_pixel, u32 (*get_pixel_format)(enum fsl_diu_monitor_port port,
int monitor_port); unsigned int bpp);
void (*set_gamma_table) (int monitor_port, char *gamma_table_base); void (*set_gamma_table)(enum fsl_diu_monitor_port port,
void (*set_monitor_port) (int monitor_port); char *gamma_table_base);
void (*set_pixel_clock) (unsigned int pixclock); void (*set_monitor_port)(enum fsl_diu_monitor_port port);
ssize_t (*show_monitor_port) (int monitor_port, char *buf); void (*set_pixel_clock)(unsigned int pixclock);
int (*set_sysfs_monitor_port) (int val); enum fsl_diu_monitor_port (*valid_monitor_port)
void (*release_bootmem) (void); (enum fsl_diu_monitor_port port);
void (*release_bootmem)(void);
}; };
extern struct platform_diu_data_ops diu_ops; extern struct platform_diu_data_ops diu_ops;

View file

@ -259,6 +259,15 @@ config FB_TILEBLITTING
comment "Frame buffer hardware drivers" comment "Frame buffer hardware drivers"
depends on FB depends on FB
config FB_GRVGA
tristate "Aeroflex Gaisler framebuffer support"
depends on FB && SPARC
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
---help---
This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler.
config FB_CIRRUS config FB_CIRRUS
tristate "Cirrus Logic support" tristate "Cirrus Logic support"
depends on FB && (ZORRO || PCI) depends on FB && (ZORRO || PCI)
@ -1756,9 +1765,10 @@ config FB_AU1100
config FB_AU1200 config FB_AU1200
bool "Au1200 LCD Driver" bool "Au1200 LCD Driver"
depends on (FB = y) && MIPS && SOC_AU1200 depends on (FB = y) && MIPS && SOC_AU1200
select FB_CFB_FILLRECT select FB_SYS_FILLRECT
select FB_CFB_COPYAREA select FB_SYS_COPYAREA
select FB_CFB_IMAGEBLIT select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
help help
This is the framebuffer driver for the AMD Au1200 SOC. It can drive This is the framebuffer driver for the AMD Au1200 SOC. It can drive
various panels and CRTs by passing in kernel cmd line option various panels and CRTs by passing in kernel cmd line option

View file

@ -33,6 +33,7 @@ obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o
obj-$(CONFIG_FB_ARC) += arcfb.o obj-$(CONFIG_FB_ARC) += arcfb.o
obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o
obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o
obj-$(CONFIG_FB_GRVGA) += grvga.o
obj-$(CONFIG_FB_PM2) += pm2fb.o obj-$(CONFIG_FB_PM2) += pm2fb.o
obj-$(CONFIG_FB_PM3) += pm3fb.o obj-$(CONFIG_FB_PM3) += pm3fb.o

View file

@ -46,14 +46,6 @@
#include <asm/mach-au1x00/au1000.h> #include <asm/mach-au1x00/au1000.h>
#include "au1200fb.h" #include "au1200fb.h"
#ifdef CONFIG_PM
#include <asm/mach-au1x00/au1xxx_pm.h>
#endif
#ifndef CONFIG_FB_AU1200_DEVS
#define CONFIG_FB_AU1200_DEVS 4
#endif
#define DRIVER_NAME "au1200fb" #define DRIVER_NAME "au1200fb"
#define DRIVER_DESC "LCD controller driver for AU1200 processors" #define DRIVER_DESC "LCD controller driver for AU1200 processors"
@ -150,7 +142,7 @@ struct au1200_lcd_iodata_t {
/* Private, per-framebuffer management information (independent of the panel itself) */ /* Private, per-framebuffer management information (independent of the panel itself) */
struct au1200fb_device { struct au1200fb_device {
struct fb_info fb_info; /* FB driver info record */ struct fb_info *fb_info; /* FB driver info record */
int plane; int plane;
unsigned char* fb_mem; /* FrameBuffer memory map */ unsigned char* fb_mem; /* FrameBuffer memory map */
@ -158,7 +150,6 @@ struct au1200fb_device {
dma_addr_t fb_phys; dma_addr_t fb_phys;
}; };
static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
/********************************************************************/ /********************************************************************/
/* LCD controller restrictions */ /* LCD controller restrictions */
@ -171,10 +162,18 @@ static struct au1200fb_device _au1200fb_devices[CONFIG_FB_AU1200_DEVS];
/* Default number of visible screen buffer to allocate */ /* Default number of visible screen buffer to allocate */
#define AU1200FB_NBR_VIDEO_BUFFERS 1 #define AU1200FB_NBR_VIDEO_BUFFERS 1
/* Default maximum number of fb devices to create */
#define MAX_DEVICE_COUNT 4
/* Default window configuration entry to use (see windows[]) */
#define DEFAULT_WINDOW_INDEX 2
/********************************************************************/ /********************************************************************/
static struct fb_info *_au1200fb_infos[MAX_DEVICE_COUNT];
static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR; static struct au1200_lcd *lcd = (struct au1200_lcd *) AU1200_LCD_ADDR;
static int window_index = 2; /* default is zero */ static int device_count = MAX_DEVICE_COUNT;
static int window_index = DEFAULT_WINDOW_INDEX; /* default is zero */
static int panel_index = 2; /* default is zero */ static int panel_index = 2; /* default is zero */
static struct window_settings *win; static struct window_settings *win;
static struct panel_settings *panel; static struct panel_settings *panel;
@ -205,12 +204,6 @@ struct window_settings {
extern int board_au1200fb_panel_init (void); extern int board_au1200fb_panel_init (void);
extern int board_au1200fb_panel_shutdown (void); extern int board_au1200fb_panel_shutdown (void);
#ifdef CONFIG_PM
int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
au1xxx_request_t request, void *data);
au1xxx_power_dev_t *LCD_pm_dev;
#endif
/* /*
* Default window configurations * Default window configurations
*/ */
@ -652,25 +645,6 @@ static struct panel_settings known_lcd_panels[] =
/********************************************************************/ /********************************************************************/
#ifdef CONFIG_PM
static int set_brightness(unsigned int brightness)
{
unsigned int hi1, divider;
/* limit brightness pwm duty to >= 30/1600 */
if (brightness < 30) {
brightness = 30;
}
divider = (lcd->pwmdiv & 0x3FFFF) + 1;
hi1 = (lcd->pwmhi >> 16) + 1;
hi1 = (((brightness & 0xFF) + 1) * divider >> 8);
lcd->pwmhi &= 0xFFFF;
lcd->pwmhi |= (hi1 << 16);
return brightness;
}
#endif /* CONFIG_PM */
static int winbpp (unsigned int winctrl1) static int winbpp (unsigned int winctrl1)
{ {
int bits = 0; int bits = 0;
@ -712,8 +686,8 @@ static int fbinfo2index (struct fb_info *fb_info)
{ {
int i; int i;
for (i = 0; i < CONFIG_FB_AU1200_DEVS; ++i) { for (i = 0; i < device_count; ++i) {
if (fb_info == (struct fb_info *)(&_au1200fb_devices[i].fb_info)) if (fb_info == _au1200fb_infos[i])
return i; return i;
} }
printk("au1200fb: ERROR: fbinfo2index failed!\n"); printk("au1200fb: ERROR: fbinfo2index failed!\n");
@ -962,7 +936,7 @@ static void au1200_setmode(struct au1200fb_device *fbdev)
lcd->window[plane].winctrl2 = ( 0 lcd->window[plane].winctrl2 = ( 0
| LCD_WINCTRL2_CKMODE_00 | LCD_WINCTRL2_CKMODE_00
| LCD_WINCTRL2_DBM | LCD_WINCTRL2_DBM
| LCD_WINCTRL2_BX_N( fbdev->fb_info.fix.line_length) | LCD_WINCTRL2_BX_N(fbdev->fb_info->fix.line_length)
| LCD_WINCTRL2_SCX_1 | LCD_WINCTRL2_SCX_1
| LCD_WINCTRL2_SCY_1 | LCD_WINCTRL2_SCY_1
) ; ) ;
@ -1050,7 +1024,7 @@ static void au1200fb_update_fbinfo(struct fb_info *fbi)
static int au1200fb_fb_check_var(struct fb_var_screeninfo *var, static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
struct fb_info *fbi) struct fb_info *fbi)
{ {
struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; struct au1200fb_device *fbdev = fbi->par;
u32 pixclock; u32 pixclock;
int screen_size, plane; int screen_size, plane;
@ -1142,7 +1116,7 @@ static int au1200fb_fb_check_var(struct fb_var_screeninfo *var,
*/ */
static int au1200fb_fb_set_par(struct fb_info *fbi) static int au1200fb_fb_set_par(struct fb_info *fbi)
{ {
struct au1200fb_device *fbdev = (struct au1200fb_device *)fbi; struct au1200fb_device *fbdev = fbi->par;
au1200fb_update_fbinfo(fbi); au1200fb_update_fbinfo(fbi);
au1200_setmode(fbdev); au1200_setmode(fbdev);
@ -1246,11 +1220,7 @@ static int au1200fb_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
{ {
unsigned int len; unsigned int len;
unsigned long start=0, off; unsigned long start=0, off;
struct au1200fb_device *fbdev = (struct au1200fb_device *) info; struct au1200fb_device *fbdev = info->par;
#ifdef CONFIG_PM
au1xxx_pm_access(LCD_pm_dev);
#endif
if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) { if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT)) {
return -EINVAL; return -EINVAL;
@ -1461,10 +1431,6 @@ static int au1200fb_ioctl(struct fb_info *info, unsigned int cmd,
int plane; int plane;
int val; int val;
#ifdef CONFIG_PM
au1xxx_pm_access(LCD_pm_dev);
#endif
plane = fbinfo2index(info); plane = fbinfo2index(info);
print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane); print_dbg("au1200fb: ioctl %d on plane %d\n", cmd, plane);
@ -1536,9 +1502,11 @@ static struct fb_ops au1200fb_fb_ops = {
.fb_set_par = au1200fb_fb_set_par, .fb_set_par = au1200fb_fb_set_par,
.fb_setcolreg = au1200fb_fb_setcolreg, .fb_setcolreg = au1200fb_fb_setcolreg,
.fb_blank = au1200fb_fb_blank, .fb_blank = au1200fb_fb_blank,
.fb_fillrect = cfb_fillrect, .fb_fillrect = sys_fillrect,
.fb_copyarea = cfb_copyarea, .fb_copyarea = sys_copyarea,
.fb_imageblit = cfb_imageblit, .fb_imageblit = sys_imageblit,
.fb_read = fb_sys_read,
.fb_write = fb_sys_write,
.fb_sync = NULL, .fb_sync = NULL,
.fb_ioctl = au1200fb_ioctl, .fb_ioctl = au1200fb_ioctl,
.fb_mmap = au1200fb_fb_mmap, .fb_mmap = au1200fb_fb_mmap,
@ -1561,10 +1529,9 @@ static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id)
static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev) static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
{ {
struct fb_info *fbi = &fbdev->fb_info; struct fb_info *fbi = fbdev->fb_info;
int bpp; int bpp;
memset(fbi, 0, sizeof(struct fb_info));
fbi->fbops = &au1200fb_fb_ops; fbi->fbops = &au1200fb_fb_ops;
bpp = winbpp(win->w[fbdev->plane].mode_winctrl1); bpp = winbpp(win->w[fbdev->plane].mode_winctrl1);
@ -1623,24 +1590,36 @@ static int au1200fb_init_fbinfo(struct au1200fb_device *fbdev)
/* AU1200 LCD controller device driver */ /* AU1200 LCD controller device driver */
static int au1200fb_drv_probe(struct platform_device *dev) static int __devinit au1200fb_drv_probe(struct platform_device *dev)
{ {
struct au1200fb_device *fbdev; struct au1200fb_device *fbdev;
struct fb_info *fbi = NULL;
unsigned long page; unsigned long page;
int bpp, plane, ret; int bpp, plane, ret, irq;
if (!dev) /* shut gcc up */
return -EINVAL; ret = 0;
fbdev = NULL;
for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) { /* Kickstart the panel */
au1200_setpanel(panel);
for (plane = 0; plane < device_count; ++plane) {
bpp = winbpp(win->w[plane].mode_winctrl1); bpp = winbpp(win->w[plane].mode_winctrl1);
if (win->w[plane].xres == 0) if (win->w[plane].xres == 0)
win->w[plane].xres = panel->Xres; win->w[plane].xres = panel->Xres;
if (win->w[plane].yres == 0) if (win->w[plane].yres == 0)
win->w[plane].yres = panel->Yres; win->w[plane].yres = panel->Yres;
fbdev = &_au1200fb_devices[plane]; fbi = framebuffer_alloc(sizeof(struct au1200fb_device),
memset(fbdev, 0, sizeof(struct au1200fb_device)); &dev->dev);
if (!fbi)
goto failed;
_au1200fb_infos[plane] = fbi;
fbdev = fbi->par;
fbdev->fb_info = fbi;
fbdev->plane = plane; fbdev->plane = plane;
/* Allocate the framebuffer to the maximum screen size */ /* Allocate the framebuffer to the maximum screen size */
@ -1673,30 +1652,31 @@ static int au1200fb_drv_probe(struct platform_device *dev)
goto failed; goto failed;
/* Register new framebuffer */ /* Register new framebuffer */
if ((ret = register_framebuffer(&fbdev->fb_info)) < 0) { ret = register_framebuffer(fbi);
if (ret < 0) {
print_err("cannot register new framebuffer"); print_err("cannot register new framebuffer");
goto failed; goto failed;
} }
au1200fb_fb_set_par(&fbdev->fb_info); au1200fb_fb_set_par(fbi);
#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
if (plane == 0) if (plane == 0)
if (fb_prepare_logo(&fbdev->fb_info, FB_ROTATE_UR)) { if (fb_prepare_logo(fbi, FB_ROTATE_UR)) {
/* Start display and show logo on boot */ /* Start display and show logo on boot */
fb_set_cmap(&fbdev->fb_info.cmap, fb_set_cmap(&fbi->cmap, fbi);
&fbdev->fb_info); fb_show_logo(fbi, FB_ROTATE_UR);
fb_show_logo(&fbdev->fb_info, FB_ROTATE_UR);
} }
#endif #endif
} }
/* Now hook interrupt too */ /* Now hook interrupt too */
if ((ret = request_irq(AU1200_LCD_INT, au1200fb_handle_irq, irq = platform_get_irq(dev, 0);
IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev)) < 0) { ret = request_irq(irq, au1200fb_handle_irq,
IRQF_DISABLED | IRQF_SHARED, "lcd", (void *)dev);
if (ret) {
print_err("fail to request interrupt line %d (err: %d)", print_err("fail to request interrupt line %d (err: %d)",
AU1200_LCD_INT, ret); irq, ret);
goto failed; goto failed;
} }
@ -1705,84 +1685,108 @@ static int au1200fb_drv_probe(struct platform_device *dev)
failed: failed:
/* NOTE: This only does the current plane/window that failed; others are still active */ /* NOTE: This only does the current plane/window that failed; others are still active */
if (fbdev->fb_mem) if (fbdev->fb_mem)
dma_free_noncoherent(dev, PAGE_ALIGN(fbdev->fb_len), dma_free_noncoherent(&dev->dev, PAGE_ALIGN(fbdev->fb_len),
fbdev->fb_mem, fbdev->fb_phys); fbdev->fb_mem, fbdev->fb_phys);
if (fbdev->fb_info.cmap.len != 0) if (fbi) {
fb_dealloc_cmap(&fbdev->fb_info.cmap); if (fbi->cmap.len != 0)
if (fbdev->fb_info.pseudo_palette) fb_dealloc_cmap(&fbi->cmap);
kfree(fbdev->fb_info.pseudo_palette); kfree(fbi->pseudo_palette);
}
if (plane == 0) if (plane == 0)
free_irq(AU1200_LCD_INT, (void*)dev); free_irq(AU1200_LCD_INT, (void*)dev);
return ret; return ret;
} }
static int au1200fb_drv_remove(struct platform_device *dev) static int __devexit au1200fb_drv_remove(struct platform_device *dev)
{ {
struct au1200fb_device *fbdev; struct au1200fb_device *fbdev;
struct fb_info *fbi;
int plane; int plane;
if (!dev)
return -ENODEV;
/* Turn off the panel */ /* Turn off the panel */
au1200_setpanel(NULL); au1200_setpanel(NULL);
for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) for (plane = 0; plane < device_count; ++plane) {
{ fbi = _au1200fb_infos[plane];
fbdev = &_au1200fb_devices[plane]; fbdev = fbi->par;
/* Clean up all probe data */ /* Clean up all probe data */
unregister_framebuffer(&fbdev->fb_info); unregister_framebuffer(fbi);
if (fbdev->fb_mem) if (fbdev->fb_mem)
dma_free_noncoherent(&dev->dev, dma_free_noncoherent(&dev->dev,
PAGE_ALIGN(fbdev->fb_len), PAGE_ALIGN(fbdev->fb_len),
fbdev->fb_mem, fbdev->fb_phys); fbdev->fb_mem, fbdev->fb_phys);
if (fbdev->fb_info.cmap.len != 0) if (fbi->cmap.len != 0)
fb_dealloc_cmap(&fbdev->fb_info.cmap); fb_dealloc_cmap(&fbi->cmap);
if (fbdev->fb_info.pseudo_palette) kfree(fbi->pseudo_palette);
kfree(fbdev->fb_info.pseudo_palette);
framebuffer_release(fbi);
_au1200fb_infos[plane] = NULL;
} }
free_irq(AU1200_LCD_INT, (void *)dev); free_irq(platform_get_irq(dev, 0), (void *)dev);
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int au1200fb_drv_suspend(struct platform_device *dev, u32 state) static int au1200fb_drv_suspend(struct device *dev)
{ {
/* TODO */ au1200_setpanel(NULL);
lcd->outmask = 0;
au_sync();
return 0; return 0;
} }
static int au1200fb_drv_resume(struct platform_device *dev) static int au1200fb_drv_resume(struct device *dev)
{ {
/* TODO */ struct fb_info *fbi;
int i;
/* Kickstart the panel */
au1200_setpanel(panel);
for (i = 0; i < device_count; i++) {
fbi = _au1200fb_infos[i];
au1200fb_fb_set_par(fbi);
}
return 0; return 0;
} }
static const struct dev_pm_ops au1200fb_pmops = {
.suspend = au1200fb_drv_suspend,
.resume = au1200fb_drv_resume,
.freeze = au1200fb_drv_suspend,
.thaw = au1200fb_drv_resume,
};
#define AU1200FB_PMOPS (&au1200fb_pmops)
#else
#define AU1200FB_PMOPS NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
static struct platform_driver au1200fb_driver = { static struct platform_driver au1200fb_driver = {
.driver = { .driver = {
.name = "au1200-lcd", .name = "au1200-lcd",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = AU1200FB_PMOPS,
}, },
.probe = au1200fb_drv_probe, .probe = au1200fb_drv_probe,
.remove = au1200fb_drv_remove, .remove = __devexit_p(au1200fb_drv_remove),
#ifdef CONFIG_PM
.suspend = au1200fb_drv_suspend,
.resume = au1200fb_drv_resume,
#endif
}; };
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* Kernel driver */ /* Kernel driver */
static void au1200fb_setup(void) static int au1200fb_setup(void)
{ {
char* options = NULL; char *options = NULL;
char* this_opt; char *this_opt, *endptr;
int num_panels = ARRAY_SIZE(known_lcd_panels); int num_panels = ARRAY_SIZE(known_lcd_panels);
int panel_idx = -1; int panel_idx = -1;
@ -1827,70 +1831,42 @@ static void au1200fb_setup(void)
nohwcursor = 1; nohwcursor = 1;
} }
else if (strncmp(this_opt, "devices:", 8) == 0) {
this_opt += 8;
device_count = simple_strtol(this_opt,
&endptr, 0);
if ((device_count < 0) ||
(device_count > MAX_DEVICE_COUNT))
device_count = MAX_DEVICE_COUNT;
}
else if (strncmp(this_opt, "wincfg:", 7) == 0) {
this_opt += 7;
window_index = simple_strtol(this_opt,
&endptr, 0);
if ((window_index < 0) ||
(window_index >= ARRAY_SIZE(windows)))
window_index = DEFAULT_WINDOW_INDEX;
}
else if (strncmp(this_opt, "off", 3) == 0)
return 1;
/* Unsupported option */ /* Unsupported option */
else { else {
print_warn("Unsupported option \"%s\"", this_opt); print_warn("Unsupported option \"%s\"", this_opt);
} }
} }
} }
return 0;
} }
#ifdef CONFIG_PM
static int au1200fb_pm_callback(au1xxx_power_dev_t *dev,
au1xxx_request_t request, void *data) {
int retval = -1;
unsigned int d = 0;
unsigned int brightness = 0;
if (request == AU1XXX_PM_SLEEP) {
board_au1200fb_panel_shutdown();
}
else if (request == AU1XXX_PM_WAKEUP) {
if(dev->prev_state == SLEEP_STATE)
{
int plane;
au1200_setpanel(panel);
for (plane = 0; plane < CONFIG_FB_AU1200_DEVS; ++plane) {
struct au1200fb_device *fbdev;
fbdev = &_au1200fb_devices[plane];
au1200fb_fb_set_par(&fbdev->fb_info);
}
}
d = *((unsigned int*)data);
if(d <=10) brightness = 26;
else if(d<=20) brightness = 51;
else if(d<=30) brightness = 77;
else if(d<=40) brightness = 102;
else if(d<=50) brightness = 128;
else if(d<=60) brightness = 153;
else if(d<=70) brightness = 179;
else if(d<=80) brightness = 204;
else if(d<=90) brightness = 230;
else brightness = 255;
set_brightness(brightness);
} else if (request == AU1XXX_PM_GETSTATUS) {
return dev->cur_state;
} else if (request == AU1XXX_PM_ACCESS) {
if (dev->cur_state != SLEEP_STATE)
return retval;
else {
au1200_setpanel(panel);
}
} else if (request == AU1XXX_PM_IDLE) {
} else if (request == AU1XXX_PM_CLEANUP) {
}
return retval;
}
#endif
static int __init au1200fb_init(void) static int __init au1200fb_init(void)
{ {
print_info("" DRIVER_DESC ""); print_info("" DRIVER_DESC "");
/* Setup driver with options */ /* Setup driver with options */
au1200fb_setup(); if (au1200fb_setup())
return -ENODEV;
/* Point to the panel selected */ /* Point to the panel selected */
panel = &known_lcd_panels[panel_index]; panel = &known_lcd_panels[panel_index];
@ -1899,17 +1875,6 @@ static int __init au1200fb_init(void)
printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name); printk(DRIVER_NAME ": Panel %d %s\n", panel_index, panel->name);
printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name); printk(DRIVER_NAME ": Win %d %s\n", window_index, win->name);
/* Kickstart the panel, the framebuffers/windows come soon enough */
au1200_setpanel(panel);
#ifdef CONFIG_PM
LCD_pm_dev = new_au1xxx_power_device("LCD", &au1200fb_pm_callback, NULL);
if ( LCD_pm_dev == NULL)
printk(KERN_INFO "Unable to create a power management device entry for the au1200fb.\n");
else
printk(KERN_INFO "Power management device entry for the au1200fb loaded.\n");
#endif
return platform_driver_register(&au1200fb_driver); return platform_driver_register(&au1200fb_driver);
} }

View file

@ -7,7 +7,6 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/pm.h> #include <linux/pm.h>

View file

@ -7,7 +7,6 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/pm.h> #include <linux/pm.h>

View file

@ -32,11 +32,11 @@
#define CARMINEFB_DEFAULT_VIDEO_MODE 1 #define CARMINEFB_DEFAULT_VIDEO_MODE 1
static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE; static unsigned int fb_mode = CARMINEFB_DEFAULT_VIDEO_MODE;
module_param(fb_mode, uint, 444); module_param(fb_mode, uint, 0444);
MODULE_PARM_DESC(fb_mode, "Initial video mode as integer."); MODULE_PARM_DESC(fb_mode, "Initial video mode as integer.");
static char *fb_mode_str; static char *fb_mode_str;
module_param(fb_mode_str, charp, 444); module_param(fb_mode_str, charp, 0444);
MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters."); MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
/* /*
@ -46,7 +46,7 @@ MODULE_PARM_DESC(fb_mode_str, "Initial video mode in characters.");
* 0b010 Display 1 * 0b010 Display 1
*/ */
static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1; static int fb_displays = CARMINE_USE_DISPLAY0 | CARMINE_USE_DISPLAY1;
module_param(fb_displays, int, 444); module_param(fb_displays, int, 0444);
MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used"); MODULE_PARM_DESC(fb_displays, "Bit mode, which displays are used");
struct carmine_hw { struct carmine_hw {

View file

@ -550,7 +550,7 @@ static void control_set_hardware(struct fb_info_control *p, struct fb_par_contro
/* /*
* Parse user speficied options (`video=controlfb:') * Parse user specified options (`video=controlfb:')
*/ */
static void __init control_setup(char *options) static void __init control_setup(char *options)
{ {

View file

@ -35,6 +35,9 @@
#define DRIVER_NAME "da8xx_lcdc" #define DRIVER_NAME "da8xx_lcdc"
#define LCD_VERSION_1 1
#define LCD_VERSION_2 2
/* LCD Status Register */ /* LCD Status Register */
#define LCD_END_OF_FRAME1 BIT(9) #define LCD_END_OF_FRAME1 BIT(9)
#define LCD_END_OF_FRAME0 BIT(8) #define LCD_END_OF_FRAME0 BIT(8)
@ -49,7 +52,9 @@
#define LCD_DMA_BURST_4 0x2 #define LCD_DMA_BURST_4 0x2
#define LCD_DMA_BURST_8 0x3 #define LCD_DMA_BURST_8 0x3
#define LCD_DMA_BURST_16 0x4 #define LCD_DMA_BURST_16 0x4
#define LCD_END_OF_FRAME_INT_ENA BIT(2) #define LCD_V1_END_OF_FRAME_INT_ENA BIT(2)
#define LCD_V2_END_OF_FRAME0_INT_ENA BIT(8)
#define LCD_V2_END_OF_FRAME1_INT_ENA BIT(9)
#define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0) #define LCD_DUAL_FRAME_BUFFER_ENABLE BIT(0)
/* LCD Control Register */ /* LCD Control Register */
@ -65,12 +70,18 @@
#define LCD_MONO_8BIT_MODE BIT(9) #define LCD_MONO_8BIT_MODE BIT(9)
#define LCD_RASTER_ORDER BIT(8) #define LCD_RASTER_ORDER BIT(8)
#define LCD_TFT_MODE BIT(7) #define LCD_TFT_MODE BIT(7)
#define LCD_UNDERFLOW_INT_ENA BIT(6) #define LCD_V1_UNDERFLOW_INT_ENA BIT(6)
#define LCD_PL_ENABLE BIT(4) #define LCD_V2_UNDERFLOW_INT_ENA BIT(5)
#define LCD_V1_PL_INT_ENA BIT(4)
#define LCD_V2_PL_INT_ENA BIT(6)
#define LCD_MONOCHROME_MODE BIT(1) #define LCD_MONOCHROME_MODE BIT(1)
#define LCD_RASTER_ENABLE BIT(0) #define LCD_RASTER_ENABLE BIT(0)
#define LCD_TFT_ALT_ENABLE BIT(23) #define LCD_TFT_ALT_ENABLE BIT(23)
#define LCD_STN_565_ENABLE BIT(24) #define LCD_STN_565_ENABLE BIT(24)
#define LCD_V2_DMA_CLK_EN BIT(2)
#define LCD_V2_LIDD_CLK_EN BIT(1)
#define LCD_V2_CORE_CLK_EN BIT(0)
#define LCD_V2_LPP_B10 26
/* LCD Raster Timing 2 Register */ /* LCD Raster Timing 2 Register */
#define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16)
@ -82,6 +93,7 @@
#define LCD_INVERT_FRAME_CLOCK BIT(20) #define LCD_INVERT_FRAME_CLOCK BIT(20)
/* LCD Block */ /* LCD Block */
#define LCD_PID_REG 0x0
#define LCD_CTRL_REG 0x4 #define LCD_CTRL_REG 0x4
#define LCD_STAT_REG 0x8 #define LCD_STAT_REG 0x8
#define LCD_RASTER_CTRL_REG 0x28 #define LCD_RASTER_CTRL_REG 0x28
@ -94,6 +106,17 @@
#define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C #define LCD_DMA_FRM_BUF_BASE_ADDR_1_REG 0x4C
#define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50 #define LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG 0x50
/* Interrupt Registers available only in Version 2 */
#define LCD_RAW_STAT_REG 0x58
#define LCD_MASKED_STAT_REG 0x5c
#define LCD_INT_ENABLE_SET_REG 0x60
#define LCD_INT_ENABLE_CLR_REG 0x64
#define LCD_END_OF_INT_IND_REG 0x68
/* Clock registers available only on Version 2 */
#define LCD_CLK_ENABLE_REG 0x6c
#define LCD_CLK_RESET_REG 0x70
#define LCD_NUM_BUFFERS 2 #define LCD_NUM_BUFFERS 2
#define WSI_TIMEOUT 50 #define WSI_TIMEOUT 50
@ -105,6 +128,8 @@
static resource_size_t da8xx_fb_reg_base; static resource_size_t da8xx_fb_reg_base;
static struct resource *lcdc_regs; static struct resource *lcdc_regs;
static unsigned int lcd_revision;
static irq_handler_t lcdc_irq_handler;
static inline unsigned int lcdc_read(unsigned int addr) static inline unsigned int lcdc_read(unsigned int addr)
{ {
@ -240,6 +265,7 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
u32 end; u32 end;
u32 reg_ras; u32 reg_ras;
u32 reg_dma; u32 reg_dma;
u32 reg_int;
/* init reg to clear PLM (loading mode) fields */ /* init reg to clear PLM (loading mode) fields */
reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
@ -252,7 +278,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
end = par->dma_end; end = par->dma_end;
reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY); reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
reg_dma |= LCD_END_OF_FRAME_INT_ENA; if (lcd_revision == LCD_VERSION_1) {
reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA;
} else {
reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
LCD_V2_END_OF_FRAME0_INT_ENA |
LCD_V2_END_OF_FRAME1_INT_ENA;
lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
}
reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
@ -264,7 +297,14 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
end = start + par->palette_sz - 1; end = start + par->palette_sz - 1;
reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY); reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
reg_ras |= LCD_PL_ENABLE;
if (lcd_revision == LCD_VERSION_1) {
reg_ras |= LCD_V1_PL_INT_ENA;
} else {
reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
LCD_V2_PL_INT_ENA;
lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
}
lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); lcdc_write(start, LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); lcdc_write(end, LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
@ -348,6 +388,7 @@ static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
{ {
u32 reg; u32 reg;
u32 reg_int;
reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE | reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(LCD_TFT_MODE |
LCD_MONO_8BIT_MODE | LCD_MONO_8BIT_MODE |
@ -375,7 +416,13 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
} }
/* enable additional interrupts here */ /* enable additional interrupts here */
reg |= LCD_UNDERFLOW_INT_ENA; if (lcd_revision == LCD_VERSION_1) {
reg |= LCD_V1_UNDERFLOW_INT_ENA;
} else {
reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) |
LCD_V2_UNDERFLOW_INT_ENA;
lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG);
}
lcdc_write(reg, LCD_RASTER_CTRL_REG); lcdc_write(reg, LCD_RASTER_CTRL_REG);
@ -511,6 +558,9 @@ static void lcd_reset(struct da8xx_fb_par *par)
/* DMA has to be disabled */ /* DMA has to be disabled */
lcdc_write(0, LCD_DMA_CTRL_REG); lcdc_write(0, LCD_DMA_CTRL_REG);
lcdc_write(0, LCD_RASTER_CTRL_REG); lcdc_write(0, LCD_RASTER_CTRL_REG);
if (lcd_revision == LCD_VERSION_2)
lcdc_write(0, LCD_INT_ENABLE_SET_REG);
} }
static void lcd_calc_clk_divider(struct da8xx_fb_par *par) static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
@ -523,6 +573,11 @@ static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
/* Configure the LCD clock divisor. */ /* Configure the LCD clock divisor. */
lcdc_write(LCD_CLK_DIVISOR(div) | lcdc_write(LCD_CLK_DIVISOR(div) |
(LCD_RASTER_MODE & 0x1), LCD_CTRL_REG); (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
if (lcd_revision == LCD_VERSION_2)
lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN |
LCD_V2_CORE_CLK_EN, LCD_CLK_ENABLE_REG);
} }
static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
@ -583,7 +638,63 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
return 0; return 0;
} }
static irqreturn_t lcdc_irq_handler(int irq, void *arg) /* IRQ handler for version 2 of LCDC */
static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg)
{
struct da8xx_fb_par *par = arg;
u32 stat = lcdc_read(LCD_MASKED_STAT_REG);
u32 reg_int;
if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
lcd_disable_raster();
lcdc_write(stat, LCD_MASKED_STAT_REG);
lcd_enable_raster();
} else if (stat & LCD_PL_LOAD_DONE) {
/*
* Must disable raster before changing state of any control bit.
* And also must be disabled before clearing the PL loading
* interrupt via the following write to the status register. If
* this is done after then one gets multiple PL done interrupts.
*/
lcd_disable_raster();
lcdc_write(stat, LCD_MASKED_STAT_REG);
/* Disable PL completion inerrupt */
reg_int = lcdc_read(LCD_INT_ENABLE_CLR_REG) |
(LCD_V2_PL_INT_ENA);
lcdc_write(reg_int, LCD_INT_ENABLE_CLR_REG);
/* Setup and start data loading mode */
lcd_blit(LOAD_DATA, par);
} else {
lcdc_write(stat, LCD_MASKED_STAT_REG);
if (stat & LCD_END_OF_FRAME0) {
lcdc_write(par->dma_start,
LCD_DMA_FRM_BUF_BASE_ADDR_0_REG);
lcdc_write(par->dma_end,
LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG);
par->vsync_flag = 1;
wake_up_interruptible(&par->vsync_wait);
}
if (stat & LCD_END_OF_FRAME1) {
lcdc_write(par->dma_start,
LCD_DMA_FRM_BUF_BASE_ADDR_1_REG);
lcdc_write(par->dma_end,
LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG);
par->vsync_flag = 1;
wake_up_interruptible(&par->vsync_wait);
}
}
lcdc_write(0, LCD_END_OF_INT_IND_REG);
return IRQ_HANDLED;
}
/* IRQ handler for version 1 LCDC */
static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg)
{ {
struct da8xx_fb_par *par = arg; struct da8xx_fb_par *par = arg;
u32 stat = lcdc_read(LCD_STAT_REG); u32 stat = lcdc_read(LCD_STAT_REG);
@ -606,7 +717,7 @@ static irqreturn_t lcdc_irq_handler(int irq, void *arg)
/* Disable PL completion inerrupt */ /* Disable PL completion inerrupt */
reg_ras = lcdc_read(LCD_RASTER_CTRL_REG); reg_ras = lcdc_read(LCD_RASTER_CTRL_REG);
reg_ras &= ~LCD_PL_ENABLE; reg_ras &= ~LCD_V1_PL_INT_ENA;
lcdc_write(reg_ras, LCD_RASTER_CTRL_REG); lcdc_write(reg_ras, LCD_RASTER_CTRL_REG);
/* Setup and start data loading mode */ /* Setup and start data loading mode */
@ -945,6 +1056,22 @@ static int __devinit fb_probe(struct platform_device *device)
if (ret) if (ret)
goto err_clk_put; goto err_clk_put;
/* Determine LCD IP Version */
switch (lcdc_read(LCD_PID_REG)) {
case 0x4C100102:
lcd_revision = LCD_VERSION_1;
break;
case 0x4F200800:
lcd_revision = LCD_VERSION_2;
break;
default:
dev_warn(&device->dev, "Unknown PID Reg value 0x%x, "
"defaulting to LCD revision 1\n",
lcdc_read(LCD_PID_REG));
lcd_revision = LCD_VERSION_1;
break;
}
for (i = 0, lcdc_info = known_lcd_panels; for (i = 0, lcdc_info = known_lcd_panels;
i < ARRAY_SIZE(known_lcd_panels); i < ARRAY_SIZE(known_lcd_panels);
i++, lcdc_info++) { i++, lcdc_info++) {
@ -1085,7 +1212,13 @@ static int __devinit fb_probe(struct platform_device *device)
} }
#endif #endif
ret = request_irq(par->irq, lcdc_irq_handler, 0, DRIVER_NAME, par); if (lcd_revision == LCD_VERSION_1)
lcdc_irq_handler = lcdc_irq_handler_rev01;
else
lcdc_irq_handler = lcdc_irq_handler_rev02;
ret = request_irq(par->irq, lcdc_irq_handler, 0,
DRIVER_NAME, par);
if (ret) if (ret)
goto irq_freq; goto irq_freq;
return 0; return 0;

View file

@ -223,8 +223,7 @@ void fb_deferred_io_cleanup(struct fb_info *info)
int i; int i;
BUG_ON(!fbdefio); BUG_ON(!fbdefio);
cancel_delayed_work(&info->deferred_work); cancel_delayed_work_sync(&info->deferred_work);
flush_scheduled_work();
/* clear out the mapping that we setup */ /* clear out the mapping that we setup */
for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) { for (i = 0 ; i < info->fix.smem_len; i += PAGE_SIZE) {

View file

@ -31,8 +31,6 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h> #include <sysdev/fsl_soc.h>
#include <linux/fsl-diu-fb.h> #include <linux/fsl-diu-fb.h>
#include "edid.h" #include "edid.h"
@ -183,7 +181,8 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
static char *fb_mode = "1024x768-32@60"; static char *fb_mode = "1024x768-32@60";
static unsigned long default_bpp = 32; static unsigned long default_bpp = 32;
static int monitor_port; static enum fsl_diu_monitor_port monitor_port;
static char *monitor_string;
#if defined(CONFIG_NOT_COHERENT_CACHE) #if defined(CONFIG_NOT_COHERENT_CACHE)
static u8 *coherence_data; static u8 *coherence_data;
@ -201,7 +200,7 @@ struct fsl_diu_data {
void *dummy_aoi_virt; void *dummy_aoi_virt;
unsigned int irq; unsigned int irq;
int fb_enabled; int fb_enabled;
int monitor_port; enum fsl_diu_monitor_port monitor_port;
}; };
struct mfb_info { struct mfb_info {
@ -281,6 +280,37 @@ static struct diu_hw dr = {
static struct diu_pool pool; static struct diu_pool pool;
/**
* fsl_diu_name_to_port - convert a port name to a monitor port enum
*
* Takes the name of a monitor port ("dvi", "lvds", or "dlvds") and returns
* the enum fsl_diu_monitor_port that corresponds to that string.
*
* For compatibility with older versions, a number ("0", "1", or "2") is also
* supported.
*
* If the string is unknown, DVI is assumed.
*
* If the particular port is not supported by the platform, another port
* (platform-specific) is chosen instead.
*/
static enum fsl_diu_monitor_port fsl_diu_name_to_port(const char *s)
{
enum fsl_diu_monitor_port port = FSL_DIU_PORT_DVI;
unsigned long val;
if (s) {
if (!strict_strtoul(s, 10, &val) && (val <= 2))
port = (enum fsl_diu_monitor_port) val;
else if (strncmp(s, "lvds", 4) == 0)
port = FSL_DIU_PORT_LVDS;
else if (strncmp(s, "dlvds", 5) == 0)
port = FSL_DIU_PORT_DLVDS;
}
return diu_ops.valid_monitor_port(port);
}
/** /**
* fsl_diu_alloc - allocate memory for the DIU * fsl_diu_alloc - allocate memory for the DIU
* @size: number of bytes to allocate * @size: number of bytes to allocate
@ -831,9 +861,8 @@ static int fsl_diu_set_par(struct fb_info *info)
} }
} }
ad->pix_fmt = ad->pix_fmt = diu_ops.get_pixel_format(machine_data->monitor_port,
diu_ops.get_pixel_format(var->bits_per_pixel, var->bits_per_pixel);
machine_data->monitor_port);
ad->addr = cpu_to_le32(info->fix.smem_start); ad->addr = cpu_to_le32(info->fix.smem_start);
ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) | ad->src_size_g_alpha = cpu_to_le32((var->yres_virtual << 12) |
var->xres_virtual) | mfbi->g_alpha; var->xres_virtual) | mfbi->g_alpha;
@ -1439,16 +1468,12 @@ static void free_buf(struct device *dev, struct diu_addr *buf, u32 size,
static ssize_t store_monitor(struct device *device, static ssize_t store_monitor(struct device *device,
struct device_attribute *attr, const char *buf, size_t count) struct device_attribute *attr, const char *buf, size_t count)
{ {
int old_monitor_port; enum fsl_diu_monitor_port old_monitor_port;
unsigned long val;
struct fsl_diu_data *machine_data = struct fsl_diu_data *machine_data =
container_of(attr, struct fsl_diu_data, dev_attr); container_of(attr, struct fsl_diu_data, dev_attr);
if (strict_strtoul(buf, 10, &val))
return 0;
old_monitor_port = machine_data->monitor_port; old_monitor_port = machine_data->monitor_port;
machine_data->monitor_port = diu_ops.set_sysfs_monitor_port(val); machine_data->monitor_port = fsl_diu_name_to_port(buf);
if (old_monitor_port != machine_data->monitor_port) { if (old_monitor_port != machine_data->monitor_port) {
/* All AOIs need adjust pixel format /* All AOIs need adjust pixel format
@ -1468,7 +1493,17 @@ static ssize_t show_monitor(struct device *device,
{ {
struct fsl_diu_data *machine_data = struct fsl_diu_data *machine_data =
container_of(attr, struct fsl_diu_data, dev_attr); container_of(attr, struct fsl_diu_data, dev_attr);
return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
switch (machine_data->monitor_port) {
case FSL_DIU_PORT_DVI:
return sprintf(buf, "DVI\n");
case FSL_DIU_PORT_LVDS:
return sprintf(buf, "Single-link LVDS\n");
case FSL_DIU_PORT_DLVDS:
return sprintf(buf, "Dual-link LVDS\n");
}
return 0;
} }
static int __devinit fsl_diu_probe(struct platform_device *ofdev) static int __devinit fsl_diu_probe(struct platform_device *ofdev)
@ -1692,8 +1727,7 @@ static int __init fsl_diu_setup(char *options)
if (!*opt) if (!*opt)
continue; continue;
if (!strncmp(opt, "monitor=", 8)) { if (!strncmp(opt, "monitor=", 8)) {
if (!strict_strtoul(opt + 8, 10, &val) && (val <= 2)) monitor_port = fsl_diu_name_to_port(opt + 8);
monitor_port = val;
} else if (!strncmp(opt, "bpp=", 4)) { } else if (!strncmp(opt, "bpp=", 4)) {
if (!strict_strtoul(opt + 4, 10, &val)) if (!strict_strtoul(opt + 4, 10, &val))
default_bpp = val; default_bpp = val;
@ -1746,6 +1780,8 @@ static int __init fsl_diu_init(void)
if (fb_get_options("fslfb", &option)) if (fb_get_options("fslfb", &option))
return -ENODEV; return -ENODEV;
fsl_diu_setup(option); fsl_diu_setup(option);
#else
monitor_port = fsl_diu_name_to_port(monitor_string);
#endif #endif
printk(KERN_INFO "Freescale DIU driver\n"); printk(KERN_INFO "Freescale DIU driver\n");
@ -1812,7 +1848,7 @@ MODULE_PARM_DESC(mode,
"Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" "); "Specify resolution as \"<xres>x<yres>[-<bpp>][@<refresh>]\" ");
module_param_named(bpp, default_bpp, ulong, 0); module_param_named(bpp, default_bpp, ulong, 0);
MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode"); MODULE_PARM_DESC(bpp, "Specify bit-per-pixel if not specified mode");
module_param_named(monitor, monitor_port, int, 0); module_param_named(monitor, monitor_string, charp, 0);
MODULE_PARM_DESC(monitor, MODULE_PARM_DESC(monitor, "Specify the monitor port "
"Specify the monitor port (0, 1 or 2) if supported by the platform"); "(\"dvi\", \"lvds\", or \"dlvds\") if supported by the platform");

579
drivers/video/grvga.c Normal file
View file

@ -0,0 +1,579 @@
/*
* Driver for Aeroflex Gaisler SVGACTRL framebuffer device.
*
* 2011 (c) Aeroflex Gaisler AB
*
* Full documentation of the core can be found here:
* http://www.gaisler.com/products/grlib/grip.pdf
*
* 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.
*
* Contributors: Kristoffer Glembo <kristoffer@gaisler.com>
*
*/
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/mm.h>
#include <linux/fb.h>
#include <linux/io.h>
struct grvga_regs {
u32 status; /* 0x00 */
u32 video_length; /* 0x04 */
u32 front_porch; /* 0x08 */
u32 sync_length; /* 0x0C */
u32 line_length; /* 0x10 */
u32 fb_pos; /* 0x14 */
u32 clk_vector[4]; /* 0x18 */
u32 clut; /* 0x20 */
};
struct grvga_par {
struct grvga_regs *regs;
u32 color_palette[16]; /* 16 entry pseudo palette used by fbcon in true color mode */
int clk_sel;
int fb_alloced; /* = 1 if framebuffer is allocated in main memory */
};
static const struct fb_videomode grvga_modedb[] = {
{
/* 640x480 @ 60 Hz */
NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2,
0, FB_VMODE_NONINTERLACED
}, {
/* 800x600 @ 60 Hz */
NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
0, FB_VMODE_NONINTERLACED
}, {
/* 800x600 @ 72 Hz */
NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
0, FB_VMODE_NONINTERLACED
}, {
/* 1024x768 @ 60 Hz */
NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
0, FB_VMODE_NONINTERLACED
}
};
static struct fb_fix_screeninfo grvga_fix __initdata = {
.id = "AG SVGACTRL",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_PSEUDOCOLOR,
.xpanstep = 0,
.ypanstep = 1,
.ywrapstep = 0,
.accel = FB_ACCEL_NONE,
};
static int grvga_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct grvga_par *par = info->par;
int i;
if (!var->xres)
var->xres = 1;
if (!var->yres)
var->yres = 1;
if (var->bits_per_pixel <= 8)
var->bits_per_pixel = 8;
else if (var->bits_per_pixel <= 16)
var->bits_per_pixel = 16;
else if (var->bits_per_pixel <= 24)
var->bits_per_pixel = 24;
else if (var->bits_per_pixel <= 32)
var->bits_per_pixel = 32;
else
return -EINVAL;
var->xres_virtual = var->xres;
var->yres_virtual = 2*var->yres;
if (info->fix.smem_len) {
if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len)
return -ENOMEM;
}
/* Which clocks that are available can be read out in these registers */
for (i = 0; i <= 3 ; i++) {
if (var->pixclock == par->regs->clk_vector[i])
break;
}
if (i <= 3)
par->clk_sel = i;
else
return -EINVAL;
switch (info->var.bits_per_pixel) {
case 8:
var->red = (struct fb_bitfield) {0, 8, 0}; /* offset, length, msb-right */
var->green = (struct fb_bitfield) {0, 8, 0};
var->blue = (struct fb_bitfield) {0, 8, 0};
var->transp = (struct fb_bitfield) {0, 0, 0};
break;
case 16:
var->red = (struct fb_bitfield) {11, 5, 0};
var->green = (struct fb_bitfield) {5, 6, 0};
var->blue = (struct fb_bitfield) {0, 5, 0};
var->transp = (struct fb_bitfield) {0, 0, 0};
break;
case 24:
case 32:
var->red = (struct fb_bitfield) {16, 8, 0};
var->green = (struct fb_bitfield) {8, 8, 0};
var->blue = (struct fb_bitfield) {0, 8, 0};
var->transp = (struct fb_bitfield) {24, 8, 0};
break;
default:
return -EINVAL;
}
return 0;
}
static int grvga_set_par(struct fb_info *info)
{
u32 func = 0;
struct grvga_par *par = info->par;
__raw_writel(((info->var.yres - 1) << 16) | (info->var.xres - 1),
&par->regs->video_length);
__raw_writel((info->var.lower_margin << 16) | (info->var.right_margin),
&par->regs->front_porch);
__raw_writel((info->var.vsync_len << 16) | (info->var.hsync_len),
&par->regs->sync_length);
__raw_writel(((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) |
(info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1),
&par->regs->line_length);
switch (info->var.bits_per_pixel) {
case 8:
info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
func = 1;
break;
case 16:
info->fix.visual = FB_VISUAL_TRUECOLOR;
func = 2;
break;
case 24:
case 32:
info->fix.visual = FB_VISUAL_TRUECOLOR;
func = 3;
break;
default:
return -EINVAL;
}
__raw_writel((par->clk_sel << 6) | (func << 4) | 1,
&par->regs->status);
info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8;
return 0;
}
static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
{
struct grvga_par *par;
par = info->par;
if (regno >= 256) /* Size of CLUT */
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;
}
#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
red = CNVT_TOHW(red, info->var.red.length);
green = CNVT_TOHW(green, info->var.green.length);
blue = CNVT_TOHW(blue, info->var.blue.length);
transp = CNVT_TOHW(transp, info->var.transp.length);
#undef CNVT_TOHW
/* In PSEUDOCOLOR we use the hardware CLUT */
if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
__raw_writel((regno << 24) | (red << 16) | (green << 8) | blue,
&par->regs->clut);
/* Truecolor uses the pseudo palette */
else if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
u32 v;
if (regno >= 16)
return -EINVAL;
v = (red << info->var.red.offset) |
(green << info->var.green.offset) |
(blue << info->var.blue.offset) |
(transp << info->var.transp.offset);
((u32 *) (info->pseudo_palette))[regno] = v;
}
return 0;
}
static int grvga_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
struct grvga_par *par = info->par;
struct fb_fix_screeninfo *fix = &info->fix;
u32 base_addr;
if (var->xoffset != 0)
return -EINVAL;
base_addr = fix->smem_start + (var->yoffset * fix->line_length);
base_addr &= ~3UL;
/* Set framebuffer base address */
__raw_writel(base_addr,
&par->regs->fb_pos);
return 0;
}
static struct fb_ops grvga_ops = {
.owner = THIS_MODULE,
.fb_check_var = grvga_check_var,
.fb_set_par = grvga_set_par,
.fb_setcolreg = grvga_setcolreg,
.fb_pan_display = grvga_pan_display,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit
};
static int __init grvga_parse_custom(char *options,
struct fb_var_screeninfo *screendata)
{
char *this_opt;
int count = 0;
if (!options || !*options)
return -1;
while ((this_opt = strsep(&options, " ")) != NULL) {
if (!*this_opt)
continue;
switch (count) {
case 0:
screendata->pixclock = simple_strtoul(this_opt, NULL, 0);
count++;
break;
case 1:
screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0);
count++;
break;
case 2:
screendata->right_margin = simple_strtoul(this_opt, NULL, 0);
count++;
break;
case 3:
screendata->hsync_len = simple_strtoul(this_opt, NULL, 0);
count++;
break;
case 4:
screendata->left_margin = simple_strtoul(this_opt, NULL, 0);
count++;
break;
case 5:
screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0);
count++;
break;
case 6:
screendata->lower_margin = simple_strtoul(this_opt, NULL, 0);
count++;
break;
case 7:
screendata->vsync_len = simple_strtoul(this_opt, NULL, 0);
count++;
break;
case 8:
screendata->upper_margin = simple_strtoul(this_opt, NULL, 0);
count++;
break;
case 9:
screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0);
count++;
break;
default:
return -1;
}
}
screendata->activate = FB_ACTIVATE_NOW;
screendata->vmode = FB_VMODE_NONINTERLACED;
return 0;
}
static int __devinit grvga_probe(struct platform_device *dev)
{
struct fb_info *info;
int retval = -ENOMEM;
unsigned long virtual_start;
unsigned long grvga_fix_addr = 0;
unsigned long physical_start = 0;
unsigned long grvga_mem_size = 0;
struct grvga_par *par = NULL;
char *options = NULL, *mode_opt = NULL;
info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev);
if (!info) {
dev_err(&dev->dev, "framebuffer_alloc failed\n");
return -ENOMEM;
}
/* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
*
* If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters
* If address is left out, we allocate memory,
* if size is left out we only allocate enough to support the given mode.
*/
if (fb_get_options("grvga", &options)) {
retval = -ENODEV;
goto err;
}
if (!options || !*options)
options = "640x480-8@60";
while (1) {
char *this_opt = strsep(&options, ",");
if (!this_opt)
break;
if (!strncmp(this_opt, "custom", 6)) {
if (grvga_parse_custom(this_opt, &info->var) < 0) {
dev_err(&dev->dev, "Failed to parse custom mode (%s).\n", this_opt);
retval = -EINVAL;
goto err1;
}
} else if (!strncmp(this_opt, "addr", 4))
grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16);
else if (!strncmp(this_opt, "size", 4))
grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0);
else
mode_opt = this_opt;
}
par = info->par;
info->fbops = &grvga_ops;
info->fix = grvga_fix;
info->pseudo_palette = par->color_palette;
info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
info->fix.smem_len = grvga_mem_size;
if (!request_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]), "grlib-svgactrl regs")) {
dev_err(&dev->dev, "registers already mapped\n");
retval = -EBUSY;
goto err;
}
par->regs = of_ioremap(&dev->resource[0], 0,
resource_size(&dev->resource[0]),
"grlib-svgactrl regs");
if (!par->regs) {
dev_err(&dev->dev, "failed to map registers\n");
retval = -ENOMEM;
goto err1;
}
retval = fb_alloc_cmap(&info->cmap, 256, 0);
if (retval < 0) {
dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");
retval = -ENOMEM;
goto err2;
}
if (mode_opt) {
retval = fb_find_mode(&info->var, info, mode_opt,
grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);
if (!retval || retval == 4) {
retval = -EINVAL;
goto err3;
}
}
if (!grvga_mem_size)
grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8;
if (grvga_fix_addr) {
/* Got framebuffer base address from argument list */
physical_start = grvga_fix_addr;
if (!request_mem_region(physical_start, grvga_mem_size, dev->name)) {
dev_err(&dev->dev, "failed to request memory region\n");
retval = -ENOMEM;
goto err3;
}
virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size);
if (!virtual_start) {
dev_err(&dev->dev, "error mapping framebuffer memory\n");
retval = -ENOMEM;
goto err4;
}
} else { /* Allocate frambuffer memory */
unsigned long page;
virtual_start = (unsigned long) __get_free_pages(GFP_DMA,
get_order(grvga_mem_size));
if (!virtual_start) {
dev_err(&dev->dev,
"unable to allocate framebuffer memory (%lu bytes)\n",
grvga_mem_size);
retval = -ENOMEM;
goto err3;
}
physical_start = dma_map_single(&dev->dev, (void *)virtual_start, grvga_mem_size, DMA_TO_DEVICE);
/* Set page reserved so that mmap will work. This is necessary
* since we'll be remapping normal memory.
*/
for (page = virtual_start;
page < PAGE_ALIGN(virtual_start + grvga_mem_size);
page += PAGE_SIZE) {
SetPageReserved(virt_to_page(page));
}
par->fb_alloced = 1;
}
memset((unsigned long *) virtual_start, 0, grvga_mem_size);
info->screen_base = (char __iomem *) virtual_start;
info->fix.smem_start = physical_start;
info->fix.smem_len = grvga_mem_size;
dev_set_drvdata(&dev->dev, info);
dev_info(&dev->dev,
"Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ %p\n",
info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel,
grvga_mem_size >> 10, info->screen_base);
retval = register_framebuffer(info);
if (retval < 0) {
dev_err(&dev->dev, "failed to register framebuffer\n");
goto err4;
}
__raw_writel(physical_start, &par->regs->fb_pos);
__raw_writel(__raw_readl(&par->regs->status) | 1, /* Enable framebuffer */
&par->regs->status);
return 0;
err4:
dev_set_drvdata(&dev->dev, NULL);
if (grvga_fix_addr) {
release_mem_region(physical_start, grvga_mem_size);
iounmap((void *)virtual_start);
} else
kfree((void *)virtual_start);
err3:
fb_dealloc_cmap(&info->cmap);
err2:
of_iounmap(&dev->resource[0], par->regs,
resource_size(&dev->resource[0]));
err1:
release_mem_region(dev->resource[0].start, resource_size(&dev->resource[0]));
err:
framebuffer_release(info);
return retval;
}
static int __devexit grvga_remove(struct platform_device *device)
{
struct fb_info *info = dev_get_drvdata(&device->dev);
struct grvga_par *par = info->par;
if (info) {
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
of_iounmap(&device->resource[0], par->regs,
resource_size(&device->resource[0]));
release_mem_region(device->resource[0].start, resource_size(&device->resource[0]));
if (!par->fb_alloced) {
release_mem_region(info->fix.smem_start, info->fix.smem_len);
iounmap(info->screen_base);
} else
kfree((void *)info->screen_base);
framebuffer_release(info);
dev_set_drvdata(&device->dev, NULL);
}
return 0;
}
static struct of_device_id svgactrl_of_match[] = {
{
.name = "GAISLER_SVGACTRL",
},
{
.name = "01_063",
},
{},
};
MODULE_DEVICE_TABLE(of, svgactrl_of_match);
static struct platform_driver grvga_driver = {
.driver = {
.name = "grlib-svgactrl",
.owner = THIS_MODULE,
.of_match_table = svgactrl_of_match,
},
.probe = grvga_probe,
.remove = __devexit_p(grvga_remove),
};
static int __init grvga_init(void)
{
return platform_driver_register(&grvga_driver);
}
static void __exit grvga_exit(void)
{
platform_driver_unregister(&grvga_driver);
}
module_init(grvga_init);
module_exit(grvga_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Aeroflex Gaisler");
MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver");

View file

@ -421,7 +421,8 @@ int mdp_probe(struct platform_device *pdev)
clk = clk_get(&pdev->dev, "mdp_clk"); clk = clk_get(&pdev->dev, "mdp_clk");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
printk(KERN_INFO "mdp: failed to get mdp clk"); printk(KERN_INFO "mdp: failed to get mdp clk");
return PTR_ERR(clk); ret = PTR_ERR(clk);
goto error_get_clk;
} }
ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp); ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp);
@ -495,6 +496,7 @@ int mdp_probe(struct platform_device *pdev)
error_device_register: error_device_register:
free_irq(mdp->irq, mdp); free_irq(mdp->irq, mdp);
error_request_irq: error_request_irq:
error_get_clk:
iounmap(mdp->base); iounmap(mdp->base);
error_get_irq: error_get_irq:
error_ioremap: error_ioremap:

View file

@ -490,7 +490,7 @@ static int platinum_var_to_par(struct fb_var_screeninfo *var,
/* /*
* Parse user speficied options (`video=platinumfb:') * Parse user specified options (`video=platinumfb:')
*/ */
static int __init platinumfb_setup(char *options) static int __init platinumfb_setup(char *options)
{ {

View file

@ -1773,7 +1773,7 @@ MODULE_DEVICE_TABLE(pci, pm2fb_id_table);
#ifndef MODULE #ifndef MODULE
/** /**
* Parse user speficied options. * Parse user specified options.
* *
* This is, comma-separated options following `video=pm2fb:'. * This is, comma-separated options following `video=pm2fb:'.
*/ */

View file

@ -1525,7 +1525,7 @@ static int __init pm3fb_setup(char *options)
{ {
char *this_opt; char *this_opt;
/* Parse user speficied options (`video=pm3fb:') */ /* Parse user specified options (`video=pm3fb:') */
if (!options || !*options) if (!options || !*options)
return 0; return 0;

View file

@ -31,8 +31,6 @@
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>

View file

@ -767,7 +767,6 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
static int s3c2410fb_cpufreq_transition(struct notifier_block *nb, static int s3c2410fb_cpufreq_transition(struct notifier_block *nb,
unsigned long val, void *data) unsigned long val, void *data)
{ {
struct cpufreq_freqs *freqs = data;
struct s3c2410fb_info *info; struct s3c2410fb_info *info;
struct fb_info *fbinfo; struct fb_info *fbinfo;
long delta_f; long delta_f;

View file

@ -1505,7 +1505,7 @@ static struct pci_driver s3fb_pci_driver = {
.resume = s3_pci_resume, .resume = s3_pci_resume,
}; };
/* Parse user speficied options */ /* Parse user specified options */
#ifndef MODULE #ifndef MODULE
static int __init s3fb_setup(char *options) static int __init s3fb_setup(char *options)

View file

@ -989,7 +989,7 @@ static struct platform_device *xxxfb_device;
*/ */
int __init xxxfb_setup(char *options) int __init xxxfb_setup(char *options)
{ {
/* Parse user speficied options (`video=xxxfb:') */ /* Parse user specified options (`video=xxxfb:') */
} }
#endif /* MODULE */ #endif /* MODULE */

View file

@ -48,13 +48,22 @@ static const u32 udlfb_info_flags = FBINFO_DEFAULT | FBINFO_READS_FAST |
FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR; FBINFO_HWACCEL_COPYAREA | FBINFO_MISC_ALWAYS_SETPAR;
/* /*
* There are many DisplayLink-based products, all with unique PIDs. We are able * There are many DisplayLink-based graphics products, all with unique PIDs.
* to support all volume ones (circa 2009) with a single driver, so we match * So we match on DisplayLink's VID + Vendor-Defined Interface Class (0xff)
* globally on VID. TODO: Probe() needs to detect when we might be running * We also require a match on SubClass (0x00) and Protocol (0x00),
* "future" chips, and bail on those, so a compatible driver can match. * which is compatible with all known USB 2.0 era graphics chips and firmware,
* but allows DisplayLink to increment those for any future incompatible chips
*/ */
static struct usb_device_id id_table[] = { static struct usb_device_id id_table[] = {
{.idVendor = 0x17e9, .match_flags = USB_DEVICE_ID_MATCH_VENDOR,}, {.idVendor = 0x17e9,
.bInterfaceClass = 0xff,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
USB_DEVICE_ID_MATCH_INT_PROTOCOL,
},
{}, {},
}; };
MODULE_DEVICE_TABLE(usb, id_table); MODULE_DEVICE_TABLE(usb, id_table);
@ -1613,7 +1622,7 @@ static int dlfb_usb_probe(struct usb_interface *interface,
/* We don't register a new USB class. Our client interface is fbdev */ /* We don't register a new USB class. Our client interface is fbdev */
/* allocates framebuffer driver structure, not framebuffer memory */ /* allocates framebuffer driver structure, not framebuffer memory */
info = framebuffer_alloc(0, &usbdev->dev); info = framebuffer_alloc(0, &interface->dev);
if (!info) { if (!info) {
retval = -ENOMEM; retval = -ENOMEM;
pr_err("framebuffer_alloc failed\n"); pr_err("framebuffer_alloc failed\n");

View file

@ -555,7 +555,7 @@ static int __init valkyrie_init_info(struct fb_info *info,
/* /*
* Parse user speficied options (`video=valkyriefb:') * Parse user specified options (`video=valkyriefb:')
*/ */
int __init valkyriefb_setup(char *options) int __init valkyriefb_setup(char *options)
{ {

View file

@ -28,6 +28,11 @@
#include <linux/types.h> #include <linux/types.h>
#define VIA_PITCH_SIZE (1<<3)
#define VIA_PITCH_MAX 0x3FF8
void via_set_primary_address(u32 addr); void via_set_primary_address(u32 addr);
void via_set_secondary_address(u32 addr); void via_set_secondary_address(u32 addr);
void via_set_primary_pitch(u32 pitch); void via_set_primary_pitch(u32 pitch);

View file

@ -151,7 +151,8 @@ static void viafb_update_fix(struct fb_info *info)
info->fix.visual = info->fix.visual =
bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; bpp == 8 ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
info->fix.line_length = (info->var.xres_virtual * bpp / 8 + 7) & ~7; info->fix.line_length = ALIGN(info->var.xres_virtual * bpp / 8,
VIA_PITCH_SIZE);
} }
static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix, static void viafb_setup_fixinfo(struct fb_fix_screeninfo *fix,
@ -238,8 +239,12 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
depth = 24; depth = 24;
viafb_fill_var_color_info(var, depth); viafb_fill_var_color_info(var, depth);
line = (var->xres_virtual * var->bits_per_pixel / 8 + 7) & ~7; if (var->xres_virtual < var->xres)
if (line * var->yres_virtual > ppar->memsize) var->xres_virtual = var->xres;
line = ALIGN(var->xres_virtual * var->bits_per_pixel / 8,
VIA_PITCH_SIZE);
if (line > VIA_PITCH_MAX || line * var->yres_virtual > ppar->memsize)
return -EINVAL; return -EINVAL;
/* Based on var passed in to calculate the refresh, /* Based on var passed in to calculate the refresh,
@ -348,8 +353,9 @@ static int viafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info) struct fb_info *info)
{ {
struct viafb_par *viapar = info->par; struct viafb_par *viapar = info->par;
u32 vram_addr = (var->yoffset * var->xres_virtual + var->xoffset) u32 vram_addr = viapar->vram_addr
* (var->bits_per_pixel / 8) + viapar->vram_addr; + var->yoffset * info->fix.line_length
+ var->xoffset * info->var.bits_per_pixel / 8;
DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr); DEBUG_MSG(KERN_DEBUG "viafb_pan_display, address = %d\n", vram_addr);
if (!viafb_dual_fb) { if (!viafb_dual_fb) {

View file

@ -23,7 +23,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/version.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/mm.h> #include <linux/mm.h>