Merge commit 'v2.6.36-rc3' into x86/memblock

Conflicts:
	arch/x86/kernel/trampoline.c
	mm/memblock.c

Merge reason: Resolve the conflicts, update to latest upstream.

Signed-off-by: Ingo Molnar <[email protected]>
This commit is contained in:
Ingo Molnar 2010-08-31 09:45:21 +02:00
commit daab7fc734
8185 changed files with 510523 additions and 574313 deletions

View file

@ -1505,7 +1505,7 @@ config FB_SIS_315
config FB_VIA
tristate "VIA UniChrome (Pro) and Chrome9 display support"
depends on FB && PCI
depends on FB && PCI && X86
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@ -1871,6 +1871,7 @@ config FB_MBX_DEBUG
config FB_FSL_DIU
tristate "Freescale DIU framebuffer support"
depends on FB && FSL_SOC
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@ -1895,6 +1896,13 @@ config FB_W100
If unsure, say N.
config SH_MIPI_DSI
tristate
depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
config SH_LCD_MIPI_DSI
bool
config FB_SH_MOBILE_LCDC
tristate "SuperH Mobile LCDC framebuffer support"
depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
@ -1903,9 +1911,17 @@ config FB_SH_MOBILE_LCDC
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
select FB_DEFERRED_IO
select SH_MIPI_DSI if SH_LCD_MIPI_DSI
---help---
Frame buffer driver for the on-chip SH-Mobile LCD controller.
config FB_SH_MOBILE_HDMI
tristate "SuperH Mobile HDMI controller support"
depends on FB_SH_MOBILE_LCDC
select FB_MODE_HELPERS
---help---
Driver for the on-chip SH-Mobile HDMI controller.
config FB_TMIO
tristate "Toshiba Mobile IO FrameBuffer support"
depends on FB && MFD_CORE
@ -1930,7 +1946,7 @@ config FB_TMIO_ACCELL
config FB_S3C
tristate "Samsung S3C framebuffer support"
depends on FB && ARCH_S3C64XX
depends on FB && S3C_DEV_FB
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@ -2229,6 +2245,15 @@ config FB_BROADSHEET
and could also have been called by other names when coupled with
a bridge adapter.
config FB_JZ4740
tristate "JZ4740 LCD framebuffer support"
depends on FB && MACH_JZ4740
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
help
Framebuffer support for the JZ4740 SoC.
source "drivers/video/omap/Kconfig"
source "drivers/video/omap2/Kconfig"

View file

@ -123,6 +123,8 @@ obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o
obj-$(CONFIG_FB_PS3) += ps3fb.o
obj-$(CONFIG_FB_SM501) += sm501fb.o
obj-$(CONFIG_FB_XILINX) += xilinxfb.o
obj-$(CONFIG_SH_MIPI_DSI) += sh_mipi_dsi.o
obj-$(CONFIG_FB_SH_MOBILE_HDMI) += sh_mobile_hdmi.o
obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
obj-$(CONFIG_FB_OMAP) += omap/
obj-y += omap2/
@ -131,6 +133,7 @@ obj-$(CONFIG_FB_CARMINE) += carminefb.o
obj-$(CONFIG_FB_MB862XX) += mb862xx/
obj-$(CONFIG_FB_MSM) += msm/
obj-$(CONFIG_FB_NUC900) += nuc900fb.o
obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o

View file

@ -80,7 +80,10 @@ static void clcdfb_disable(struct clcd_fb *fb)
/*
* Disable CLCD clock source.
*/
clk_disable(fb->clk);
if (fb->clk_enabled) {
fb->clk_enabled = false;
clk_disable(fb->clk);
}
}
static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
@ -88,7 +91,10 @@ static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
/*
* Enable the CLCD clock source.
*/
clk_enable(fb->clk);
if (!fb->clk_enabled) {
fb->clk_enabled = true;
clk_enable(fb->clk);
}
/*
* Bring up by first enabling..

View file

@ -2,7 +2,7 @@
* Backlight control code for Sharp Zaurus SL-5500
*
* Copyright 2005 John Lenz <lenz@cs.wisc.edu>
* Maintainer: Pavel Machek <pavel@suse.cz> (unless John wants to :-)
* Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-)
* GPL v2
*
* This driver assumes single CPU. That's okay, because collie is
@ -246,6 +246,6 @@ static void __exit locomolcd_exit(void)
module_init(locomolcd_init);
module_exit(locomolcd_exit);
MODULE_AUTHOR("John Lenz <[email protected]>, Pavel Machek <pavel@suse.cz>");
MODULE_AUTHOR("John Lenz <[email protected]>, Pavel Machek <pavel@ucw.cz>");
MODULE_DESCRIPTION("Collie LCD driver");
MODULE_LICENSE("GPL");

View file

@ -273,7 +273,7 @@ static int __devinit bw2_do_default_mode(struct bw2_par *par,
return 0;
}
static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *match)
static int __devinit bw2_probe(struct platform_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
struct fb_info *info;
@ -350,7 +350,7 @@ out_err:
return err;
}
static int __devexit bw2_remove(struct of_device *op)
static int __devexit bw2_remove(struct platform_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
struct bw2_par *par = info->par;
@ -390,12 +390,12 @@ static int __init bw2_init(void)
if (fb_get_options("bw2fb", NULL))
return -ENODEV;
return of_register_driver(&bw2_driver, &of_bus_type);
return of_register_platform_driver(&bw2_driver);
}
static void __exit bw2_exit(void)
{
of_unregister_driver(&bw2_driver);
of_unregister_platform_driver(&bw2_driver);
}
module_init(bw2_init);

View file

@ -432,7 +432,7 @@ static int init_hardware(struct carmine_hw *hw)
u32 loops;
u32 ret;
/* Initalize Carmine */
/* Initialize Carmine */
/* Sets internal clock */
c_set_hw_reg(hw, CARMINE_CTL_REG + CARMINE_CTL_REG_CLOCK_ENABLE,
CARMINE_DFLT_IP_CLOCK_ENABLE);

View file

@ -446,7 +446,7 @@ static struct sbus_mmap_map __cg14_mmap_map[CG14_MMAP_ENTRIES] __devinitdata = {
{ .size = 0 }
};
static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
static void cg14_unmap_regs(struct platform_device *op, struct fb_info *info,
struct cg14_par *par)
{
if (par->regs)
@ -463,7 +463,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info,
info->screen_base, info->fix.smem_len);
}
static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match)
static int __devinit cg14_probe(struct platform_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
struct fb_info *info;
@ -570,7 +570,7 @@ out_err:
return err;
}
static int __devexit cg14_remove(struct of_device *op)
static int __devexit cg14_remove(struct platform_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
struct cg14_par *par = info->par;
@ -610,12 +610,12 @@ static int __init cg14_init(void)
if (fb_get_options("cg14fb", NULL))
return -ENODEV;
return of_register_driver(&cg14_driver, &of_bus_type);
return of_register_platform_driver(&cg14_driver);
}
static void __exit cg14_exit(void)
{
of_unregister_driver(&cg14_driver);
of_unregister_platform_driver(&cg14_driver);
}
module_init(cg14_init);

View file

@ -346,7 +346,7 @@ static int __devinit cg3_do_default_mode(struct cg3_par *par)
return 0;
}
static int __devinit cg3_probe(struct of_device *op,
static int __devinit cg3_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
@ -433,7 +433,7 @@ out_err:
return err;
}
static int __devexit cg3_remove(struct of_device *op)
static int __devexit cg3_remove(struct platform_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
struct cg3_par *par = info->par;
@ -477,12 +477,12 @@ static int __init cg3_init(void)
if (fb_get_options("cg3fb", NULL))
return -ENODEV;
return of_register_driver(&cg3_driver, &of_bus_type);
return of_register_platform_driver(&cg3_driver);
}
static void __exit cg3_exit(void)
{
of_unregister_driver(&cg3_driver);
of_unregister_platform_driver(&cg3_driver);
}
module_init(cg3_init);

View file

@ -718,7 +718,7 @@ static void __devinit cg6_chip_init(struct fb_info *info)
sbus_writel(info->var.yres - 1, &fbc->clipmaxy);
}
static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
static void cg6_unmap_regs(struct platform_device *op, struct fb_info *info,
struct cg6_par *par)
{
if (par->fbc)
@ -737,7 +737,7 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info,
info->fix.smem_len);
}
static int __devinit cg6_probe(struct of_device *op,
static int __devinit cg6_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
@ -827,7 +827,7 @@ out_err:
return err;
}
static int __devexit cg6_remove(struct of_device *op)
static int __devexit cg6_remove(struct platform_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
struct cg6_par *par = info->par;
@ -870,12 +870,12 @@ static int __init cg6_init(void)
if (fb_get_options("cg6fb", NULL))
return -ENODEV;
return of_register_driver(&cg6_driver, &of_bus_type);
return of_register_platform_driver(&cg6_driver);
}
static void __exit cg6_exit(void)
{
of_unregister_driver(&cg6_driver);
of_unregister_platform_driver(&cg6_driver);
}
module_init(cg6_init);

View file

@ -6,7 +6,7 @@ menu "Console display driver support"
config VGA_CONSOLE
bool "VGA text console" if EMBEDDED || !X86
depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH && !BLACKFIN && !AVR32 && !MN10300
depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER)
default y
help
Saying Y here will allow you to use Linux in text mode through a

View file

@ -22,7 +22,7 @@
/*
* Accelerated handlers.
*/
static inline void update_attr(u8 *dst, u8 *src, int attribute,
static void update_attr(u8 *dst, u8 *src, int attribute,
struct vc_data *vc)
{
int i, offset = (vc->vc_font.height < 10) ? 1 : 2;

View file

@ -283,10 +283,11 @@ static inline int fbcon_is_inactive(struct vc_data *vc, struct fb_info *info)
struct fbcon_ops *ops = info->fbcon_par;
return (info->state != FBINFO_STATE_RUNNING ||
vc->vc_mode != KD_TEXT || ops->graphics);
vc->vc_mode != KD_TEXT || ops->graphics) &&
!vt_force_oops_output(vc);
}
static inline int get_color(struct vc_data *vc, struct fb_info *info,
static int get_color(struct vc_data *vc, struct fb_info *info,
u16 c, int is_fg)
{
int depth = fb_get_color_depth(&info->var, &info->fix);
@ -1073,6 +1074,7 @@ static void fbcon_init(struct vc_data *vc, int init)
if (p->userfont)
charcnt = FNTCHARCNT(p->fontdata);
vc->vc_panic_force_write = !!(info->flags & FBINFO_CAN_FORCE_OUTPUT);
vc->vc_can_do_color = (fb_get_color_depth(&info->var, &info->fix)!=1);
vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800;
if (charcnt == 256) {
@ -2342,6 +2344,30 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
return 0;
}
static int fbcon_debug_enter(struct vc_data *vc)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par;
ops->save_graphics = ops->graphics;
ops->graphics = 0;
if (info->fbops->fb_debug_enter)
info->fbops->fb_debug_enter(info);
fbcon_set_palette(vc, color_table);
return 0;
}
static int fbcon_debug_leave(struct vc_data *vc)
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_ops *ops = info->fbcon_par;
ops->graphics = ops->save_graphics;
if (info->fbops->fb_debug_leave)
info->fbops->fb_debug_leave(info);
return 0;
}
static int fbcon_get_font(struct vc_data *vc, struct console_font *font)
{
u8 *fontdata = vc->vc_font.data;
@ -3276,6 +3302,8 @@ static const struct consw fb_con = {
.con_screen_pos = fbcon_screen_pos,
.con_getxy = fbcon_getxy,
.con_resize = fbcon_resize,
.con_debug_enter = fbcon_debug_enter,
.con_debug_leave = fbcon_debug_leave,
};
static struct notifier_block fbcon_event_notifier = {

View file

@ -74,6 +74,7 @@ struct fbcon_ops {
int cursor_reset;
int blank_state;
int graphics;
int save_graphics; /* for debug enter/leave */
int flags;
int rotate;
int cur_rotate;

View file

@ -22,7 +22,7 @@
* Rotation 270 degrees
*/
static inline void ccw_update_attr(u8 *dst, u8 *src, int attribute,
static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
struct vc_data *vc)
{
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;

View file

@ -22,7 +22,7 @@
* Rotation 90 degrees
*/
static inline void cw_update_attr(u8 *dst, u8 *src, int attribute,
static void cw_update_attr(u8 *dst, u8 *src, int attribute,
struct vc_data *vc)
{
int i, j, offset = (vc->vc_font.height < 10) ? 1 : 2;

View file

@ -22,7 +22,7 @@
* Rotation 180 degrees
*/
static inline void ud_update_attr(u8 *dst, u8 *src, int attribute,
static void ud_update_attr(u8 *dst, u8 *src, int attribute,
struct vc_data *vc)
{
int i, offset = (vc->vc_font.height < 10) ? 1 : 2;

View file

@ -1108,7 +1108,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
charmap += 4 * cmapsz;
#endif
unlock_kernel();
spin_lock_irq(&vga_lock);
/* First, the Sequencer */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
@ -1192,7 +1191,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512)
vga_wattr(state->vgabase, VGA_AR_ENABLE_DISPLAY, 0);
}
spin_unlock_irq(&vga_lock);
lock_kernel();
return 0;
}

View file

@ -40,6 +40,8 @@
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>

View file

@ -16,7 +16,7 @@
#include <video/vga.h>
static struct fb_var_screeninfo efifb_defined __initdata = {
static struct fb_var_screeninfo efifb_defined __devinitdata = {
.activate = FB_ACTIVATE_NOW,
.height = -1,
.width = -1,
@ -27,7 +27,7 @@ static struct fb_var_screeninfo efifb_defined __initdata = {
.vmode = FB_VMODE_NONINTERLACED,
};
static struct fb_fix_screeninfo efifb_fix __initdata = {
static struct fb_fix_screeninfo efifb_fix __devinitdata = {
.id = "EFI VGA",
.type = FB_TYPE_PACKED_PIXELS,
.accel = FB_ACCEL_NONE,
@ -59,7 +59,7 @@ static struct efifb_dmi_info {
int stride;
int width;
int height;
} dmi_list[] = {
} dmi_list[] __initdata = {
[M_I17] = { "i17", 0x80010000, 1472 * 4, 1440, 900 },
[M_I20] = { "i20", 0x80010000, 1728 * 4, 1680, 1050 }, /* guess */
[M_I20_SR] = { "imac7", 0x40010000, 1728 * 4, 1680, 1050 },
@ -83,7 +83,7 @@ static int set_system(const struct dmi_system_id *id);
DMI_MATCH(DMI_PRODUCT_NAME, name) }, \
&dmi_list[enumid] }
static struct dmi_system_id __initdata dmi_system_table[] = {
static const struct dmi_system_id dmi_system_table[] __initconst = {
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac4,1", M_I17),
/* At least one of these two will be right; maybe both? */
EFIFB_DMI_SYSTEM_ID("Apple Computer, Inc.", "iMac5,1", M_I20),

View file

@ -1362,6 +1362,7 @@ fb_mmap(struct file *file, struct vm_area_struct * vma)
vma->vm_pgoff = off >> PAGE_SHIFT;
/* This is an IO map - tell maydump to skip this VMA */
vma->vm_flags |= VM_IO | VM_RESERVED;
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
fb_pgprotect(file, vma, off);
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
@ -1786,7 +1787,7 @@ static int ofonly __read_mostly;
int fb_get_options(char *name, char **option)
{
char *opt, *options = NULL;
int opt_len, retval = 0;
int retval = 0;
int name_len = strlen(name), i;
if (name_len && ofonly && strncmp(name, "offb", 4))
@ -1796,8 +1797,7 @@ int fb_get_options(char *name, char **option)
for (i = 0; i < FB_MAX; i++) {
if (video_options[i] == NULL)
continue;
opt_len = strlen(video_options[i]);
if (!opt_len)
if (!video_options[i][0])
continue;
opt = video_options[i];
if (!strncmp(name, opt, name_len) &&

View file

@ -893,7 +893,7 @@ static void ffb_init_fix(struct fb_info *info)
info->fix.accel = FB_ACCEL_SUN_CREATOR;
}
static int __devinit ffb_probe(struct of_device *op,
static int __devinit ffb_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
@ -1023,7 +1023,7 @@ out_err:
return err;
}
static int __devexit ffb_remove(struct of_device *op)
static int __devexit ffb_remove(struct platform_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
struct ffb_par *par = info->par;
@ -1067,12 +1067,12 @@ static int __init ffb_init(void)
if (fb_get_options("ffb", NULL))
return -ENODEV;
return of_register_driver(&ffb_driver, &of_bus_type);
return of_register_platform_driver(&ffb_driver);
}
static void __exit ffb_exit(void)
{
of_unregister_driver(&ffb_driver);
of_unregister_platform_driver(&ffb_driver);
}
module_init(ffb_init);

View file

@ -34,7 +34,8 @@
#include <linux/of_platform.h>
#include <sysdev/fsl_soc.h>
#include "fsl-diu-fb.h"
#include <linux/fsl-diu-fb.h>
#include "edid.h"
/*
* These parameters give default parameters
@ -217,6 +218,7 @@ struct mfb_info {
int x_aoi_d; /* aoi display x offset to physical screen */
int y_aoi_d; /* aoi display y offset to physical screen */
struct fsl_diu_data *parent;
u8 *edid_data;
};
@ -317,6 +319,17 @@ static void fsl_diu_free(void *virt, size_t size)
free_pages_exact(virt, size);
}
/*
* Workaround for failed writing desc register of planes.
* Needed with MPC5121 DIU rev 2.0 silicon.
*/
void wr_reg_wa(u32 *reg, u32 val)
{
do {
out_be32(reg, val);
} while (in_be32(reg) != val);
}
static int fsl_diu_enable_panel(struct fb_info *info)
{
struct mfb_info *pmfbi, *cmfbi, *mfbi = info->par;
@ -330,7 +343,7 @@ static int fsl_diu_enable_panel(struct fb_info *info)
switch (mfbi->index) {
case 0: /* plane 0 */
if (hw->desc[0] != ad->paddr)
out_be32(&hw->desc[0], ad->paddr);
wr_reg_wa(&hw->desc[0], ad->paddr);
break;
case 1: /* plane 1 AOI 0 */
cmfbi = machine_data->fsl_diu_info[2]->par;
@ -340,7 +353,7 @@ static int fsl_diu_enable_panel(struct fb_info *info)
cpu_to_le32(cmfbi->ad->paddr);
else
ad->next_ad = 0;
out_be32(&hw->desc[1], ad->paddr);
wr_reg_wa(&hw->desc[1], ad->paddr);
}
break;
case 3: /* plane 2 AOI 0 */
@ -351,14 +364,14 @@ static int fsl_diu_enable_panel(struct fb_info *info)
cpu_to_le32(cmfbi->ad->paddr);
else
ad->next_ad = 0;
out_be32(&hw->desc[2], ad->paddr);
wr_reg_wa(&hw->desc[2], ad->paddr);
}
break;
case 2: /* plane 1 AOI 1 */
pmfbi = machine_data->fsl_diu_info[1]->par;
ad->next_ad = 0;
if (hw->desc[1] == machine_data->dummy_ad->paddr)
out_be32(&hw->desc[1], ad->paddr);
wr_reg_wa(&hw->desc[1], ad->paddr);
else /* AOI0 open */
pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
break;
@ -366,7 +379,7 @@ static int fsl_diu_enable_panel(struct fb_info *info)
pmfbi = machine_data->fsl_diu_info[3]->par;
ad->next_ad = 0;
if (hw->desc[2] == machine_data->dummy_ad->paddr)
out_be32(&hw->desc[2], ad->paddr);
wr_reg_wa(&hw->desc[2], ad->paddr);
else /* AOI0 was open */
pmfbi->ad->next_ad = cpu_to_le32(ad->paddr);
break;
@ -390,27 +403,24 @@ static int fsl_diu_disable_panel(struct fb_info *info)
switch (mfbi->index) {
case 0: /* plane 0 */
if (hw->desc[0] != machine_data->dummy_ad->paddr)
out_be32(&hw->desc[0],
machine_data->dummy_ad->paddr);
wr_reg_wa(&hw->desc[0], machine_data->dummy_ad->paddr);
break;
case 1: /* plane 1 AOI 0 */
cmfbi = machine_data->fsl_diu_info[2]->par;
if (cmfbi->count > 0) /* AOI1 is open */
out_be32(&hw->desc[1], cmfbi->ad->paddr);
wr_reg_wa(&hw->desc[1], cmfbi->ad->paddr);
/* move AOI1 to the first */
else /* AOI1 was closed */
out_be32(&hw->desc[1],
machine_data->dummy_ad->paddr);
wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
/* close AOI 0 */
break;
case 3: /* plane 2 AOI 0 */
cmfbi = machine_data->fsl_diu_info[4]->par;
if (cmfbi->count > 0) /* AOI1 is open */
out_be32(&hw->desc[2], cmfbi->ad->paddr);
wr_reg_wa(&hw->desc[2], cmfbi->ad->paddr);
/* move AOI1 to the first */
else /* AOI1 was closed */
out_be32(&hw->desc[2],
machine_data->dummy_ad->paddr);
wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
/* close AOI 0 */
break;
case 2: /* plane 1 AOI 1 */
@ -421,7 +431,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
/* AOI0 is open, must be the first */
pmfbi->ad->next_ad = 0;
} else /* AOI1 is the first in the chain */
out_be32(&hw->desc[1], machine_data->dummy_ad->paddr);
wr_reg_wa(&hw->desc[1], machine_data->dummy_ad->paddr);
/* close AOI 1 */
break;
case 4: /* plane 2 AOI 1 */
@ -432,7 +442,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
/* AOI0 is open, must be the first */
pmfbi->ad->next_ad = 0;
} else /* AOI1 is the first in the chain */
out_be32(&hw->desc[2], machine_data->dummy_ad->paddr);
wr_reg_wa(&hw->desc[2], machine_data->dummy_ad->paddr);
/* close AOI 1 */
break;
default:
@ -1100,6 +1110,10 @@ static int fsl_diu_open(struct fb_info *info, int user)
struct mfb_info *mfbi = info->par;
int res = 0;
/* free boot splash memory on first /dev/fb0 open */
if (!mfbi->index && diu_ops.release_bootmem)
diu_ops.release_bootmem();
spin_lock(&diu_lock);
mfbi->count++;
if (mfbi->count == 1) {
@ -1173,18 +1187,30 @@ static int __devinit install_fb(struct fb_info *info)
int rc;
struct mfb_info *mfbi = info->par;
const char *aoi_mode, *init_aoi_mode = "320x240";
struct fb_videomode *db = fsl_diu_mode_db;
unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db);
int has_default_mode = 1;
if (init_fbinfo(info))
return -EINVAL;
if (mfbi->index == 0) /* plane 0 */
if (mfbi->index == 0) { /* plane 0 */
if (mfbi->edid_data) {
/* Now build modedb from EDID */
fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs);
fb_videomode_to_modelist(info->monspecs.modedb,
info->monspecs.modedb_len,
&info->modelist);
db = info->monspecs.modedb;
dbsize = info->monspecs.modedb_len;
}
aoi_mode = fb_mode;
else
} else {
aoi_mode = init_aoi_mode;
}
pr_debug("mode used = %s\n", aoi_mode);
rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp);
rc = fb_find_mode(&info->var, info, aoi_mode, db, dbsize,
&fsl_diu_default_mode, default_bpp);
switch (rc) {
case 1:
pr_debug("using mode specified in @mode\n");
@ -1202,10 +1228,50 @@ static int __devinit install_fb(struct fb_info *info)
default:
pr_debug("rc = %d\n", rc);
pr_debug("failed to find mode\n");
return -EINVAL;
/*
* For plane 0 we continue and look into
* driver's internal modedb.
*/
if (mfbi->index == 0 && mfbi->edid_data)
has_default_mode = 0;
else
return -EINVAL;
break;
}
if (!has_default_mode) {
rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
ARRAY_SIZE(fsl_diu_mode_db),
&fsl_diu_default_mode,
default_bpp);
if (rc > 0 && rc < 5)
has_default_mode = 1;
}
/* Still not found, use preferred mode from database if any */
if (!has_default_mode && info->monspecs.modedb) {
struct fb_monspecs *specs = &info->monspecs;
struct fb_videomode *modedb = &specs->modedb[0];
/*
* Get preferred timing. If not found,
* first mode in database will be used.
*/
if (specs->misc & FB_MISC_1ST_DETAIL) {
int i;
for (i = 0; i < specs->modedb_len; i++) {
if (specs->modedb[i].flag & FB_MODE_IS_FIRST) {
modedb = &specs->modedb[i];
break;
}
}
}
info->var.bits_per_pixel = default_bpp;
fb_videomode_to_var(&info->var, modedb);
}
pr_debug("xres_virtual %d\n", info->var.xres_virtual);
pr_debug("bits_per_pixel %d\n", info->var.bits_per_pixel);
@ -1244,6 +1310,9 @@ static void uninstall_fb(struct fb_info *info)
if (!mfbi->registered)
return;
if (mfbi->index == 0)
kfree(mfbi->edid_data);
unregister_framebuffer(info);
unmap_video_memory(info);
if (&info->cmap)
@ -1324,7 +1393,7 @@ static void free_irq_local(int irq)
* Power management hooks. Note that we won't be called from IRQ context,
* unlike the blank functions above, so we may sleep.
*/
static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state)
static int fsl_diu_suspend(struct platform_device *ofdev, pm_message_t state)
{
struct fsl_diu_data *machine_data;
@ -1334,7 +1403,7 @@ static int fsl_diu_suspend(struct of_device *ofdev, pm_message_t state)
return 0;
}
static int fsl_diu_resume(struct of_device *ofdev)
static int fsl_diu_resume(struct platform_device *ofdev)
{
struct fsl_diu_data *machine_data;
@ -1418,7 +1487,7 @@ static ssize_t show_monitor(struct device *device,
return diu_ops.show_monitor_port(machine_data->monitor_port, buf);
}
static int __devinit fsl_diu_probe(struct of_device *ofdev,
static int __devinit fsl_diu_probe(struct platform_device *ofdev,
const struct of_device_id *match)
{
struct device_node *np = ofdev->dev.of_node;
@ -1427,6 +1496,7 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
int ret, i, error = 0;
struct resource res;
struct fsl_diu_data *machine_data;
int diu_mode;
machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
if (!machine_data)
@ -1443,6 +1513,17 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
mfbi = machine_data->fsl_diu_info[i]->par;
memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info));
mfbi->parent = machine_data;
if (mfbi->index == 0) {
const u8 *prop;
int len;
/* Get EDID */
prop = of_get_property(np, "edid", &len);
if (prop && len == EDID_LENGTH)
mfbi->edid_data = kmemdup(prop, EDID_LENGTH,
GFP_KERNEL);
}
}
ret = of_address_to_resource(np, 0, &res);
@ -1463,7 +1544,9 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
goto error2;
}
out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU anyway*/
diu_mode = in_be32(&dr.diu_reg->diu_mode);
if (diu_mode != MFB_MODE1)
out_be32(&dr.diu_reg->diu_mode, 0); /* disable DIU */
/* Get the IRQ of the DIU */
machine_data->irq = irq_of_parse_and_map(np, 0);
@ -1511,7 +1594,13 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
machine_data->dummy_ad->offset_xyd = 0;
machine_data->dummy_ad->next_ad = 0;
out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
/*
* Let DIU display splash screen if it was pre-initialized
* by the bootloader, set dummy area descriptor otherwise.
*/
if (diu_mode != MFB_MODE1)
out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
@ -1578,7 +1667,7 @@ error2:
}
static int fsl_diu_remove(struct of_device *ofdev)
static int fsl_diu_remove(struct platform_device *ofdev)
{
struct fsl_diu_data *machine_data;
int i;

View file

@ -1,223 +0,0 @@
/*
* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
*
* Freescale DIU Frame Buffer device driver
*
* Authors: Hongjun Chen <hong-jun.chen@freescale.com>
* Paul Widmer <paul.widmer@freescale.com>
* Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
* York Sun <yorksun@freescale.com>
*
* Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
*
* 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.
*
*/
#ifndef __FSL_DIU_FB_H__
#define __FSL_DIU_FB_H__
/* Arbitrary threshold to determine the allocation method
* See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory()
*/
#define MEM_ALLOC_THRESHOLD (1024*768*4+32)
/* Minimum value that the pixel clock can be set to in pico seconds
* This is determined by platform clock/3 where the minimum platform
* clock is 533MHz. This gives 5629 pico seconds.
*/
#define MIN_PIX_CLK 5629
#define MAX_PIX_CLK 96096
#include <linux/types.h>
struct mfb_alpha {
int enable;
int alpha;
};
struct mfb_chroma_key {
int enable;
__u8 red_max;
__u8 green_max;
__u8 blue_max;
__u8 red_min;
__u8 green_min;
__u8 blue_min;
};
struct aoi_display_offset {
int x_aoi_d;
int y_aoi_d;
};
#define MFB_SET_CHROMA_KEY _IOW('M', 1, struct mfb_chroma_key)
#define MFB_WAIT_FOR_VSYNC _IOW('F', 0x20, u_int32_t)
#define MFB_SET_BRIGHTNESS _IOW('M', 3, __u8)
#define MFB_SET_ALPHA 0x80014d00
#define MFB_GET_ALPHA 0x40014d00
#define MFB_SET_AOID 0x80084d04
#define MFB_GET_AOID 0x40084d04
#define MFB_SET_PIXFMT 0x80014d08
#define MFB_GET_PIXFMT 0x40014d08
#define FBIOGET_GWINFO 0x46E0
#define FBIOPUT_GWINFO 0x46E1
#ifdef __KERNEL__
#include <linux/spinlock.h>
/*
* These are the fields of area descriptor(in DDR memory) for every plane
*/
struct diu_ad {
/* Word 0(32-bit) in DDR memory */
/* __u16 comp; */
/* __u16 pixel_s:2; */
/* __u16 pallete:1; */
/* __u16 red_c:2; */
/* __u16 green_c:2; */
/* __u16 blue_c:2; */
/* __u16 alpha_c:3; */
/* __u16 byte_f:1; */
/* __u16 res0:3; */
__be32 pix_fmt; /* hard coding pixel format */
/* Word 1(32-bit) in DDR memory */
__le32 addr;
/* Word 2(32-bit) in DDR memory */
/* __u32 delta_xs:11; */
/* __u32 res1:1; */
/* __u32 delta_ys:11; */
/* __u32 res2:1; */
/* __u32 g_alpha:8; */
__le32 src_size_g_alpha;
/* Word 3(32-bit) in DDR memory */
/* __u32 delta_xi:11; */
/* __u32 res3:5; */
/* __u32 delta_yi:11; */
/* __u32 res4:3; */
/* __u32 flip:2; */
__le32 aoi_size;
/* Word 4(32-bit) in DDR memory */
/*__u32 offset_xi:11;
__u32 res5:5;
__u32 offset_yi:11;
__u32 res6:5;
*/
__le32 offset_xyi;
/* Word 5(32-bit) in DDR memory */
/*__u32 offset_xd:11;
__u32 res7:5;
__u32 offset_yd:11;
__u32 res8:5; */
__le32 offset_xyd;
/* Word 6(32-bit) in DDR memory */
__u8 ckmax_r;
__u8 ckmax_g;
__u8 ckmax_b;
__u8 res9;
/* Word 7(32-bit) in DDR memory */
__u8 ckmin_r;
__u8 ckmin_g;
__u8 ckmin_b;
__u8 res10;
/* __u32 res10:8; */
/* Word 8(32-bit) in DDR memory */
__le32 next_ad;
/* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
__u32 paddr;
} __attribute__ ((packed));
/* DIU register map */
struct diu {
__be32 desc[3];
__be32 gamma;
__be32 pallete;
__be32 cursor;
__be32 curs_pos;
__be32 diu_mode;
__be32 bgnd;
__be32 bgnd_wb;
__be32 disp_size;
__be32 wb_size;
__be32 wb_mem_addr;
__be32 hsyn_para;
__be32 vsyn_para;
__be32 syn_pol;
__be32 thresholds;
__be32 int_status;
__be32 int_mask;
__be32 colorbar[8];
__be32 filling;
__be32 plut;
} __attribute__ ((packed));
struct diu_hw {
struct diu *diu_reg;
spinlock_t reg_lock;
__u32 mode; /* DIU operation mode */
};
struct diu_addr {
__u8 __iomem *vaddr; /* Virtual address */
dma_addr_t paddr; /* Physical address */
__u32 offset;
};
struct diu_pool {
struct diu_addr ad;
struct diu_addr gamma;
struct diu_addr pallete;
struct diu_addr cursor;
};
#define FSL_DIU_BASE_OFFSET 0x2C000 /* Offset of DIU */
#define INT_LCDC 64 /* DIU interrupt number */
#define FSL_AOI_NUM 6 /* 5 AOIs and one dummy AOI */
/* 1 for plane 0, 2 for plane 1&2 each */
/* Minimum X and Y resolutions */
#define MIN_XRES 64
#define MIN_YRES 64
/* HW cursor parameters */
#define MAX_CURS 32
/* Modes of operation of DIU */
#define MFB_MODE0 0 /* DIU off */
#define MFB_MODE1 1 /* All three planes output to display */
#define MFB_MODE2 2 /* Plane 1 to display, planes 2+3 written back*/
#define MFB_MODE3 3 /* All three planes written back to memory */
#define MFB_MODE4 4 /* Color bar generation */
/* INT_STATUS/INT_MASK field descriptions */
#define INT_VSYNC 0x01 /* Vsync interrupt */
#define INT_VSYNC_WB 0x02 /* Vsync interrupt for write back operation */
#define INT_UNDRUN 0x04 /* Under run exception interrupt */
#define INT_PARERR 0x08 /* Display parameters error interrupt */
#define INT_LS_BF_VS 0x10 /* Lines before vsync. interrupt */
/* Panels'operation modes */
#define MFB_TYPE_OUTPUT 0 /* Panel output to display */
#define MFB_TYPE_OFF 1 /* Panel off */
#define MFB_TYPE_WB 2 /* Panel written back to memory */
#define MFB_TYPE_TEST 3 /* Panel generate color bar */
#endif /* __KERNEL__ */
#endif /* __FSL_DIU_FB_H__ */

View file

@ -368,7 +368,7 @@ static int __init iga_init(struct fb_info *info, struct iga_par *par)
return 1;
}
int __init igafb_init(void)
static int __init igafb_init(void)
{
struct fb_info *info;
struct pci_dev *pdev;
@ -531,6 +531,7 @@ int __init igafb_init(void)
iounmap(info->screen_base);
kfree(par->mmap_map);
kfree(info);
return -ENODEV;
}
#ifdef CONFIG_SPARC
@ -556,7 +557,7 @@ int __init igafb_init(void)
return 0;
}
int __init igafb_setup(char *options)
static int __init igafb_setup(char *options)
{
char *this_opt;

View file

@ -40,6 +40,12 @@
*/
#define DEBUG_VAR 1
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) || \
(defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE) && \
defined(CONFIG_FB_IMX_MODULE))
#define PWMR_BACKLIGHT_AVAILABLE
#endif
#define DRIVER_NAME "imx-fb"
#define LCDC_SSA 0x00
@ -175,7 +181,9 @@ struct imxfb_info {
struct imx_fb_videomode *mode;
int num_modes;
#ifdef PWMR_BACKLIGHT_AVAILABLE
struct backlight_device *bl;
#endif
void (*lcd_power)(int);
void (*backlight_power)(int);
@ -450,8 +458,7 @@ static int imxfb_set_par(struct fb_info *info)
return 0;
}
#ifdef PWMR_BACKLIGHT_AVAILABLE
static int imxfb_bl_get_brightness(struct backlight_device *bl)
{
struct imxfb_info *fbi = bl_get_data(bl);
@ -516,6 +523,7 @@ static void imxfb_exit_backlight(struct imxfb_info *fbi)
if (fbi->bl)
backlight_device_unregister(fbi->bl);
}
#endif
static void imxfb_enable_controller(struct imxfb_info *fbi)
{
@ -647,6 +655,9 @@ static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *inf
fbi->regs + LCDC_SIZE);
writel(fbi->pcr, fbi->regs + LCDC_PCR);
#ifndef PWMR_BACKLIGHT_AVAILABLE
writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
#endif
writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
@ -847,7 +858,9 @@ static int __init imxfb_probe(struct platform_device *pdev)
imxfb_enable_controller(fbi);
fbi->pdev = pdev;
#ifdef PWMR_BACKLIGHT_AVAILABLE
imxfb_init_backlight(fbi);
#endif
return 0;
@ -885,7 +898,9 @@ static int __devexit imxfb_remove(struct platform_device *pdev)
imxfb_disable_controller(fbi);
#ifdef PWMR_BACKLIGHT_AVAILABLE
imxfb_exit_backlight(fbi);
#endif
unregister_framebuffer(info);
pdata = pdev->dev.platform_data;

847
drivers/video/jz4740_fb.c Normal file
View file

@ -0,0 +1,847 @@
/*
* Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de>
* JZ4740 SoC LCD framebuffer driver
*
* 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.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/console.h>
#include <linux/fb.h>
#include <linux/dma-mapping.h>
#include <asm/mach-jz4740/jz4740_fb.h>
#include <asm/mach-jz4740/gpio.h>
#define JZ_REG_LCD_CFG 0x00
#define JZ_REG_LCD_VSYNC 0x04
#define JZ_REG_LCD_HSYNC 0x08
#define JZ_REG_LCD_VAT 0x0C
#define JZ_REG_LCD_DAH 0x10
#define JZ_REG_LCD_DAV 0x14
#define JZ_REG_LCD_PS 0x18
#define JZ_REG_LCD_CLS 0x1C
#define JZ_REG_LCD_SPL 0x20
#define JZ_REG_LCD_REV 0x24
#define JZ_REG_LCD_CTRL 0x30
#define JZ_REG_LCD_STATE 0x34
#define JZ_REG_LCD_IID 0x38
#define JZ_REG_LCD_DA0 0x40
#define JZ_REG_LCD_SA0 0x44
#define JZ_REG_LCD_FID0 0x48
#define JZ_REG_LCD_CMD0 0x4C
#define JZ_REG_LCD_DA1 0x50
#define JZ_REG_LCD_SA1 0x54
#define JZ_REG_LCD_FID1 0x58
#define JZ_REG_LCD_CMD1 0x5C
#define JZ_LCD_CFG_SLCD BIT(31)
#define JZ_LCD_CFG_PS_DISABLE BIT(23)
#define JZ_LCD_CFG_CLS_DISABLE BIT(22)
#define JZ_LCD_CFG_SPL_DISABLE BIT(21)
#define JZ_LCD_CFG_REV_DISABLE BIT(20)
#define JZ_LCD_CFG_HSYNCM BIT(19)
#define JZ_LCD_CFG_PCLKM BIT(18)
#define JZ_LCD_CFG_INV BIT(17)
#define JZ_LCD_CFG_SYNC_DIR BIT(16)
#define JZ_LCD_CFG_PS_POLARITY BIT(15)
#define JZ_LCD_CFG_CLS_POLARITY BIT(14)
#define JZ_LCD_CFG_SPL_POLARITY BIT(13)
#define JZ_LCD_CFG_REV_POLARITY BIT(12)
#define JZ_LCD_CFG_HSYNC_ACTIVE_LOW BIT(11)
#define JZ_LCD_CFG_PCLK_FALLING_EDGE BIT(10)
#define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9)
#define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8)
#define JZ_LCD_CFG_18_BIT BIT(7)
#define JZ_LCD_CFG_PDW (BIT(5) | BIT(4))
#define JZ_LCD_CFG_MODE_MASK 0xf
#define JZ_LCD_CTRL_BURST_4 (0x0 << 28)
#define JZ_LCD_CTRL_BURST_8 (0x1 << 28)
#define JZ_LCD_CTRL_BURST_16 (0x2 << 28)
#define JZ_LCD_CTRL_RGB555 BIT(27)
#define JZ_LCD_CTRL_OFUP BIT(26)
#define JZ_LCD_CTRL_FRC_GRAYSCALE_16 (0x0 << 24)
#define JZ_LCD_CTRL_FRC_GRAYSCALE_4 (0x1 << 24)
#define JZ_LCD_CTRL_FRC_GRAYSCALE_2 (0x2 << 24)
#define JZ_LCD_CTRL_PDD_MASK (0xff << 16)
#define JZ_LCD_CTRL_EOF_IRQ BIT(13)
#define JZ_LCD_CTRL_SOF_IRQ BIT(12)
#define JZ_LCD_CTRL_OFU_IRQ BIT(11)
#define JZ_LCD_CTRL_IFU0_IRQ BIT(10)
#define JZ_LCD_CTRL_IFU1_IRQ BIT(9)
#define JZ_LCD_CTRL_DD_IRQ BIT(8)
#define JZ_LCD_CTRL_QDD_IRQ BIT(7)
#define JZ_LCD_CTRL_REVERSE_ENDIAN BIT(6)
#define JZ_LCD_CTRL_LSB_FISRT BIT(5)
#define JZ_LCD_CTRL_DISABLE BIT(4)
#define JZ_LCD_CTRL_ENABLE BIT(3)
#define JZ_LCD_CTRL_BPP_1 0x0
#define JZ_LCD_CTRL_BPP_2 0x1
#define JZ_LCD_CTRL_BPP_4 0x2
#define JZ_LCD_CTRL_BPP_8 0x3
#define JZ_LCD_CTRL_BPP_15_16 0x4
#define JZ_LCD_CTRL_BPP_18_24 0x5
#define JZ_LCD_CMD_SOF_IRQ BIT(15)
#define JZ_LCD_CMD_EOF_IRQ BIT(16)
#define JZ_LCD_CMD_ENABLE_PAL BIT(12)
#define JZ_LCD_SYNC_MASK 0x3ff
#define JZ_LCD_STATE_DISABLED BIT(0)
struct jzfb_framedesc {
uint32_t next;
uint32_t addr;
uint32_t id;
uint32_t cmd;
} __packed;
struct jzfb {
struct fb_info *fb;
struct platform_device *pdev;
void __iomem *base;
struct resource *mem;
struct jz4740_fb_platform_data *pdata;
size_t vidmem_size;
void *vidmem;
dma_addr_t vidmem_phys;
struct jzfb_framedesc *framedesc;
dma_addr_t framedesc_phys;
struct clk *ldclk;
struct clk *lpclk;
unsigned is_enabled:1;
struct mutex lock;
uint32_t pseudo_palette[16];
};
static const struct fb_fix_screeninfo jzfb_fix __devinitdata = {
.id = "JZ4740 FB",
.type = FB_TYPE_PACKED_PIXELS,
.visual = FB_VISUAL_TRUECOLOR,
.xpanstep = 0,
.ypanstep = 0,
.ywrapstep = 0,
.accel = FB_ACCEL_NONE,
};
static const struct jz_gpio_bulk_request jz_lcd_ctrl_pins[] = {
JZ_GPIO_BULK_PIN(LCD_PCLK),
JZ_GPIO_BULK_PIN(LCD_HSYNC),
JZ_GPIO_BULK_PIN(LCD_VSYNC),
JZ_GPIO_BULK_PIN(LCD_DE),
JZ_GPIO_BULK_PIN(LCD_PS),
JZ_GPIO_BULK_PIN(LCD_REV),
JZ_GPIO_BULK_PIN(LCD_CLS),
JZ_GPIO_BULK_PIN(LCD_SPL),
};
static const struct jz_gpio_bulk_request jz_lcd_data_pins[] = {
JZ_GPIO_BULK_PIN(LCD_DATA0),
JZ_GPIO_BULK_PIN(LCD_DATA1),
JZ_GPIO_BULK_PIN(LCD_DATA2),
JZ_GPIO_BULK_PIN(LCD_DATA3),
JZ_GPIO_BULK_PIN(LCD_DATA4),
JZ_GPIO_BULK_PIN(LCD_DATA5),
JZ_GPIO_BULK_PIN(LCD_DATA6),
JZ_GPIO_BULK_PIN(LCD_DATA7),
JZ_GPIO_BULK_PIN(LCD_DATA8),
JZ_GPIO_BULK_PIN(LCD_DATA9),
JZ_GPIO_BULK_PIN(LCD_DATA10),
JZ_GPIO_BULK_PIN(LCD_DATA11),
JZ_GPIO_BULK_PIN(LCD_DATA12),
JZ_GPIO_BULK_PIN(LCD_DATA13),
JZ_GPIO_BULK_PIN(LCD_DATA14),
JZ_GPIO_BULK_PIN(LCD_DATA15),
JZ_GPIO_BULK_PIN(LCD_DATA16),
JZ_GPIO_BULK_PIN(LCD_DATA17),
};
static unsigned int jzfb_num_ctrl_pins(struct jzfb *jzfb)
{
unsigned int num;
switch (jzfb->pdata->lcd_type) {
case JZ_LCD_TYPE_GENERIC_16_BIT:
num = 4;
break;
case JZ_LCD_TYPE_GENERIC_18_BIT:
num = 4;
break;
case JZ_LCD_TYPE_8BIT_SERIAL:
num = 3;
break;
case JZ_LCD_TYPE_SPECIAL_TFT_1:
case JZ_LCD_TYPE_SPECIAL_TFT_2:
case JZ_LCD_TYPE_SPECIAL_TFT_3:
num = 8;
break;
default:
num = 0;
break;
}
return num;
}
static unsigned int jzfb_num_data_pins(struct jzfb *jzfb)
{
unsigned int num;
switch (jzfb->pdata->lcd_type) {
case JZ_LCD_TYPE_GENERIC_16_BIT:
num = 16;
break;
case JZ_LCD_TYPE_GENERIC_18_BIT:
num = 18;
break;
case JZ_LCD_TYPE_8BIT_SERIAL:
num = 8;
break;
case JZ_LCD_TYPE_SPECIAL_TFT_1:
case JZ_LCD_TYPE_SPECIAL_TFT_2:
case JZ_LCD_TYPE_SPECIAL_TFT_3:
if (jzfb->pdata->bpp == 18)
num = 18;
else
num = 16;
break;
default:
num = 0;
break;
}
return num;
}
/* Based on CNVT_TOHW macro from skeletonfb.c */
static inline uint32_t jzfb_convert_color_to_hw(unsigned val,
struct fb_bitfield *bf)
{
return (((val << bf->length) + 0x7FFF - val) >> 16) << bf->offset;
}
static int jzfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *fb)
{
uint32_t color;
if (regno >= 16)
return -EINVAL;
color = jzfb_convert_color_to_hw(red, &fb->var.red);
color |= jzfb_convert_color_to_hw(green, &fb->var.green);
color |= jzfb_convert_color_to_hw(blue, &fb->var.blue);
color |= jzfb_convert_color_to_hw(transp, &fb->var.transp);
((uint32_t *)(fb->pseudo_palette))[regno] = color;
return 0;
}
static int jzfb_get_controller_bpp(struct jzfb *jzfb)
{
switch (jzfb->pdata->bpp) {
case 18:
case 24:
return 32;
case 15:
return 16;
default:
return jzfb->pdata->bpp;
}
}
static struct fb_videomode *jzfb_get_mode(struct jzfb *jzfb,
struct fb_var_screeninfo *var)
{
size_t i;
struct fb_videomode *mode = jzfb->pdata->modes;
for (i = 0; i < jzfb->pdata->num_modes; ++i, ++mode) {
if (mode->xres == var->xres && mode->yres == var->yres)
return mode;
}
return NULL;
}
static int jzfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb)
{
struct jzfb *jzfb = fb->par;
struct fb_videomode *mode;
if (var->bits_per_pixel != jzfb_get_controller_bpp(jzfb) &&
var->bits_per_pixel != jzfb->pdata->bpp)
return -EINVAL;
mode = jzfb_get_mode(jzfb, var);
if (mode == NULL)
return -EINVAL;
fb_videomode_to_var(var, mode);
switch (jzfb->pdata->bpp) {
case 8:
break;
case 15:
var->red.offset = 10;
var->red.length = 5;
var->green.offset = 6;
var->green.length = 5;
var->blue.offset = 0;
var->blue.length = 5;
break;
case 16:
var->red.offset = 11;
var->red.length = 5;
var->green.offset = 5;
var->green.length = 6;
var->blue.offset = 0;
var->blue.length = 5;
break;
case 18:
var->red.offset = 16;
var->red.length = 6;
var->green.offset = 8;
var->green.length = 6;
var->blue.offset = 0;
var->blue.length = 6;
var->bits_per_pixel = 32;
break;
case 32:
case 24:
var->transp.offset = 24;
var->transp.length = 8;
var->red.offset = 16;
var->red.length = 8;
var->green.offset = 8;
var->green.length = 8;
var->blue.offset = 0;
var->blue.length = 8;
var->bits_per_pixel = 32;
break;
default:
break;
}
return 0;
}
static int jzfb_set_par(struct fb_info *info)
{
struct jzfb *jzfb = info->par;
struct jz4740_fb_platform_data *pdata = jzfb->pdata;
struct fb_var_screeninfo *var = &info->var;
struct fb_videomode *mode;
uint16_t hds, vds;
uint16_t hde, vde;
uint16_t ht, vt;
uint32_t ctrl;
uint32_t cfg;
unsigned long rate;
mode = jzfb_get_mode(jzfb, var);
if (mode == NULL)
return -EINVAL;
if (mode == info->mode)
return 0;
info->mode = mode;
hds = mode->hsync_len + mode->left_margin;
hde = hds + mode->xres;
ht = hde + mode->right_margin;
vds = mode->vsync_len + mode->upper_margin;
vde = vds + mode->yres;
vt = vde + mode->lower_margin;
ctrl = JZ_LCD_CTRL_OFUP | JZ_LCD_CTRL_BURST_16;
switch (pdata->bpp) {
case 1:
ctrl |= JZ_LCD_CTRL_BPP_1;
break;
case 2:
ctrl |= JZ_LCD_CTRL_BPP_2;
break;
case 4:
ctrl |= JZ_LCD_CTRL_BPP_4;
break;
case 8:
ctrl |= JZ_LCD_CTRL_BPP_8;
break;
case 15:
ctrl |= JZ_LCD_CTRL_RGB555; /* Falltrough */
case 16:
ctrl |= JZ_LCD_CTRL_BPP_15_16;
break;
case 18:
case 24:
case 32:
ctrl |= JZ_LCD_CTRL_BPP_18_24;
break;
default:
break;
}
cfg = pdata->lcd_type & 0xf;
if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT))
cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW;
if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT))
cfg |= JZ_LCD_CFG_VSYNC_ACTIVE_LOW;
if (pdata->pixclk_falling_edge)
cfg |= JZ_LCD_CFG_PCLK_FALLING_EDGE;
if (pdata->date_enable_active_low)
cfg |= JZ_LCD_CFG_DE_ACTIVE_LOW;
if (pdata->lcd_type == JZ_LCD_TYPE_GENERIC_18_BIT)
cfg |= JZ_LCD_CFG_18_BIT;
if (mode->pixclock) {
rate = PICOS2KHZ(mode->pixclock) * 1000;
mode->refresh = rate / vt / ht;
} else {
if (pdata->lcd_type == JZ_LCD_TYPE_8BIT_SERIAL)
rate = mode->refresh * (vt + 2 * mode->xres) * ht;
else
rate = mode->refresh * vt * ht;
mode->pixclock = KHZ2PICOS(rate / 1000);
}
mutex_lock(&jzfb->lock);
if (!jzfb->is_enabled)
clk_enable(jzfb->ldclk);
else
ctrl |= JZ_LCD_CTRL_ENABLE;
switch (pdata->lcd_type) {
case JZ_LCD_TYPE_SPECIAL_TFT_1:
case JZ_LCD_TYPE_SPECIAL_TFT_2:
case JZ_LCD_TYPE_SPECIAL_TFT_3:
writel(pdata->special_tft_config.spl, jzfb->base + JZ_REG_LCD_SPL);
writel(pdata->special_tft_config.cls, jzfb->base + JZ_REG_LCD_CLS);
writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_PS);
writel(pdata->special_tft_config.ps, jzfb->base + JZ_REG_LCD_REV);
break;
default:
cfg |= JZ_LCD_CFG_PS_DISABLE;
cfg |= JZ_LCD_CFG_CLS_DISABLE;
cfg |= JZ_LCD_CFG_SPL_DISABLE;
cfg |= JZ_LCD_CFG_REV_DISABLE;
break;
}
writel(mode->hsync_len, jzfb->base + JZ_REG_LCD_HSYNC);
writel(mode->vsync_len, jzfb->base + JZ_REG_LCD_VSYNC);
writel((ht << 16) | vt, jzfb->base + JZ_REG_LCD_VAT);
writel((hds << 16) | hde, jzfb->base + JZ_REG_LCD_DAH);
writel((vds << 16) | vde, jzfb->base + JZ_REG_LCD_DAV);
writel(cfg, jzfb->base + JZ_REG_LCD_CFG);
writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
if (!jzfb->is_enabled)
clk_disable(jzfb->ldclk);
mutex_unlock(&jzfb->lock);
clk_set_rate(jzfb->lpclk, rate);
clk_set_rate(jzfb->ldclk, rate * 3);
return 0;
}
static void jzfb_enable(struct jzfb *jzfb)
{
uint32_t ctrl;
clk_enable(jzfb->ldclk);
jz_gpio_bulk_resume(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
jz_gpio_bulk_resume(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
writel(0, jzfb->base + JZ_REG_LCD_STATE);
writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0);
ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL);
ctrl |= JZ_LCD_CTRL_ENABLE;
ctrl &= ~JZ_LCD_CTRL_DISABLE;
writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
}
static void jzfb_disable(struct jzfb *jzfb)
{
uint32_t ctrl;
ctrl = readl(jzfb->base + JZ_REG_LCD_CTRL);
ctrl |= JZ_LCD_CTRL_DISABLE;
writel(ctrl, jzfb->base + JZ_REG_LCD_CTRL);
do {
ctrl = readl(jzfb->base + JZ_REG_LCD_STATE);
} while (!(ctrl & JZ_LCD_STATE_DISABLED));
jz_gpio_bulk_suspend(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
jz_gpio_bulk_suspend(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
clk_disable(jzfb->ldclk);
}
static int jzfb_blank(int blank_mode, struct fb_info *info)
{
struct jzfb *jzfb = info->par;
switch (blank_mode) {
case FB_BLANK_UNBLANK:
mutex_lock(&jzfb->lock);
if (jzfb->is_enabled) {
mutex_unlock(&jzfb->lock);
return 0;
}
jzfb_enable(jzfb);
jzfb->is_enabled = 1;
mutex_unlock(&jzfb->lock);
break;
default:
mutex_lock(&jzfb->lock);
if (!jzfb->is_enabled) {
mutex_unlock(&jzfb->lock);
return 0;
}
jzfb_disable(jzfb);
jzfb->is_enabled = 0;
mutex_unlock(&jzfb->lock);
break;
}
return 0;
}
static int jzfb_alloc_devmem(struct jzfb *jzfb)
{
int max_videosize = 0;
struct fb_videomode *mode = jzfb->pdata->modes;
void *page;
int i;
for (i = 0; i < jzfb->pdata->num_modes; ++mode, ++i) {
if (max_videosize < mode->xres * mode->yres)
max_videosize = mode->xres * mode->yres;
}
max_videosize *= jzfb_get_controller_bpp(jzfb) >> 3;
jzfb->framedesc = dma_alloc_coherent(&jzfb->pdev->dev,
sizeof(*jzfb->framedesc),
&jzfb->framedesc_phys, GFP_KERNEL);
if (!jzfb->framedesc)
return -ENOMEM;
jzfb->vidmem_size = PAGE_ALIGN(max_videosize);
jzfb->vidmem = dma_alloc_coherent(&jzfb->pdev->dev,
jzfb->vidmem_size,
&jzfb->vidmem_phys, GFP_KERNEL);
if (!jzfb->vidmem)
goto err_free_framedesc;
for (page = jzfb->vidmem;
page < jzfb->vidmem + PAGE_ALIGN(jzfb->vidmem_size);
page += PAGE_SIZE) {
SetPageReserved(virt_to_page(page));
}
jzfb->framedesc->next = jzfb->framedesc_phys;
jzfb->framedesc->addr = jzfb->vidmem_phys;
jzfb->framedesc->id = 0xdeafbead;
jzfb->framedesc->cmd = 0;
jzfb->framedesc->cmd |= max_videosize / 4;
return 0;
err_free_framedesc:
dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc),
jzfb->framedesc, jzfb->framedesc_phys);
return -ENOMEM;
}
static void jzfb_free_devmem(struct jzfb *jzfb)
{
dma_free_coherent(&jzfb->pdev->dev, jzfb->vidmem_size,
jzfb->vidmem, jzfb->vidmem_phys);
dma_free_coherent(&jzfb->pdev->dev, sizeof(*jzfb->framedesc),
jzfb->framedesc, jzfb->framedesc_phys);
}
static struct fb_ops jzfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = jzfb_check_var,
.fb_set_par = jzfb_set_par,
.fb_blank = jzfb_blank,
.fb_fillrect = sys_fillrect,
.fb_copyarea = sys_copyarea,
.fb_imageblit = sys_imageblit,
.fb_setcolreg = jzfb_setcolreg,
};
static int __devinit jzfb_probe(struct platform_device *pdev)
{
int ret;
struct jzfb *jzfb;
struct fb_info *fb;
struct jz4740_fb_platform_data *pdata = pdev->dev.platform_data;
struct resource *mem;
if (!pdata) {
dev_err(&pdev->dev, "Missing platform data\n");
return -ENXIO;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(&pdev->dev, "Failed to get register memory resource\n");
return -ENXIO;
}
mem = request_mem_region(mem->start, resource_size(mem), pdev->name);
if (!mem) {
dev_err(&pdev->dev, "Failed to request register memory region\n");
return -EBUSY;
}
fb = framebuffer_alloc(sizeof(struct jzfb), &pdev->dev);
if (!fb) {
dev_err(&pdev->dev, "Failed to allocate framebuffer device\n");
ret = -ENOMEM;
goto err_release_mem_region;
}
fb->fbops = &jzfb_ops;
fb->flags = FBINFO_DEFAULT;
jzfb = fb->par;
jzfb->pdev = pdev;
jzfb->pdata = pdata;
jzfb->mem = mem;
jzfb->ldclk = clk_get(&pdev->dev, "lcd");
if (IS_ERR(jzfb->ldclk)) {
ret = PTR_ERR(jzfb->ldclk);
dev_err(&pdev->dev, "Failed to get lcd clock: %d\n", ret);
goto err_framebuffer_release;
}
jzfb->lpclk = clk_get(&pdev->dev, "lcd_pclk");
if (IS_ERR(jzfb->lpclk)) {
ret = PTR_ERR(jzfb->lpclk);
dev_err(&pdev->dev, "Failed to get lcd pixel clock: %d\n", ret);
goto err_put_ldclk;
}
jzfb->base = ioremap(mem->start, resource_size(mem));
if (!jzfb->base) {
dev_err(&pdev->dev, "Failed to ioremap register memory region\n");
ret = -EBUSY;
goto err_put_lpclk;
}
platform_set_drvdata(pdev, jzfb);
mutex_init(&jzfb->lock);
fb_videomode_to_modelist(pdata->modes, pdata->num_modes,
&fb->modelist);
fb_videomode_to_var(&fb->var, pdata->modes);
fb->var.bits_per_pixel = pdata->bpp;
jzfb_check_var(&fb->var, fb);
ret = jzfb_alloc_devmem(jzfb);
if (ret) {
dev_err(&pdev->dev, "Failed to allocate video memory\n");
goto err_iounmap;
}
fb->fix = jzfb_fix;
fb->fix.line_length = fb->var.bits_per_pixel * fb->var.xres / 8;
fb->fix.mmio_start = mem->start;
fb->fix.mmio_len = resource_size(mem);
fb->fix.smem_start = jzfb->vidmem_phys;
fb->fix.smem_len = fb->fix.line_length * fb->var.yres;
fb->screen_base = jzfb->vidmem;
fb->pseudo_palette = jzfb->pseudo_palette;
fb_alloc_cmap(&fb->cmap, 256, 0);
clk_enable(jzfb->ldclk);
jzfb->is_enabled = 1;
writel(jzfb->framedesc->next, jzfb->base + JZ_REG_LCD_DA0);
fb->mode = NULL;
jzfb_set_par(fb);
jz_gpio_bulk_request(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
jz_gpio_bulk_request(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
ret = register_framebuffer(fb);
if (ret) {
dev_err(&pdev->dev, "Failed to register framebuffer: %d\n", ret);
goto err_free_devmem;
}
jzfb->fb = fb;
return 0;
err_free_devmem:
jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
fb_dealloc_cmap(&fb->cmap);
jzfb_free_devmem(jzfb);
err_iounmap:
iounmap(jzfb->base);
err_put_lpclk:
clk_put(jzfb->lpclk);
err_put_ldclk:
clk_put(jzfb->ldclk);
err_framebuffer_release:
framebuffer_release(fb);
err_release_mem_region:
release_mem_region(mem->start, resource_size(mem));
return ret;
}
static int __devexit jzfb_remove(struct platform_device *pdev)
{
struct jzfb *jzfb = platform_get_drvdata(pdev);
jzfb_blank(FB_BLANK_POWERDOWN, jzfb->fb);
jz_gpio_bulk_free(jz_lcd_ctrl_pins, jzfb_num_ctrl_pins(jzfb));
jz_gpio_bulk_free(jz_lcd_data_pins, jzfb_num_data_pins(jzfb));
iounmap(jzfb->base);
release_mem_region(jzfb->mem->start, resource_size(jzfb->mem));
fb_dealloc_cmap(&jzfb->fb->cmap);
jzfb_free_devmem(jzfb);
platform_set_drvdata(pdev, NULL);
clk_put(jzfb->lpclk);
clk_put(jzfb->ldclk);
framebuffer_release(jzfb->fb);
return 0;
}
#ifdef CONFIG_PM
static int jzfb_suspend(struct device *dev)
{
struct jzfb *jzfb = dev_get_drvdata(dev);
acquire_console_sem();
fb_set_suspend(jzfb->fb, 1);
release_console_sem();
mutex_lock(&jzfb->lock);
if (jzfb->is_enabled)
jzfb_disable(jzfb);
mutex_unlock(&jzfb->lock);
return 0;
}
static int jzfb_resume(struct device *dev)
{
struct jzfb *jzfb = dev_get_drvdata(dev);
clk_enable(jzfb->ldclk);
mutex_lock(&jzfb->lock);
if (jzfb->is_enabled)
jzfb_enable(jzfb);
mutex_unlock(&jzfb->lock);
acquire_console_sem();
fb_set_suspend(jzfb->fb, 0);
release_console_sem();
return 0;
}
static const struct dev_pm_ops jzfb_pm_ops = {
.suspend = jzfb_suspend,
.resume = jzfb_resume,
.poweroff = jzfb_suspend,
.restore = jzfb_resume,
};
#define JZFB_PM_OPS (&jzfb_pm_ops)
#else
#define JZFB_PM_OPS NULL
#endif
static struct platform_driver jzfb_driver = {
.probe = jzfb_probe,
.remove = __devexit_p(jzfb_remove),
.driver = {
.name = "jz4740-fb",
.pm = JZFB_PM_OPS,
},
};
static int __init jzfb_init(void)
{
return platform_driver_register(&jzfb_driver);
}
module_init(jzfb_init);
static void __exit jzfb_exit(void)
{
platform_driver_unregister(&jzfb_driver);
}
module_exit(jzfb_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lars-Peter Clausen <[email protected]>");
MODULE_DESCRIPTION("JZ4740 SoC LCD framebuffer driver");
MODULE_ALIAS("platform:jz4740-fb");

View file

@ -529,7 +529,7 @@ static void leo_fixup_var_rgb(struct fb_var_screeninfo *var)
var->transp.length = 0;
}
static void leo_unmap_regs(struct of_device *op, struct fb_info *info,
static void leo_unmap_regs(struct platform_device *op, struct fb_info *info,
struct leo_par *par)
{
if (par->lc_ss0_usr)
@ -547,7 +547,7 @@ static void leo_unmap_regs(struct of_device *op, struct fb_info *info,
of_iounmap(&op->resource[0], info->screen_base, 0x800000);
}
static int __devinit leo_probe(struct of_device *op,
static int __devinit leo_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
@ -637,7 +637,7 @@ out_err:
return err;
}
static int __devexit leo_remove(struct of_device *op)
static int __devexit leo_remove(struct platform_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
struct leo_par *par = info->par;
@ -677,12 +677,12 @@ static int __init leo_init(void)
if (fb_get_options("leofb", NULL))
return -ENODEV;
return of_register_driver(&leo_driver, &of_bus_type);
return of_register_platform_driver(&leo_driver);
}
static void __exit leo_exit(void)
{
of_unregister_driver(&leo_driver);
of_unregister_platform_driver(&leo_driver);
}
module_init(leo_init);

View file

@ -191,7 +191,7 @@ static void* i2c_matroxfb_probe(struct matrox_fb_info* minfo) {
};
i2c_new_probed_device(&m2info->maven.adapter,
&maven_info, addr_list);
&maven_info, addr_list, NULL);
}
}
return m2info;

View file

@ -151,13 +151,13 @@ static inline void mga_writel(vaddr_t va, unsigned int offs, u_int32_t value) {
static inline void mga_memcpy_toio(vaddr_t va, const void* src, int len) {
#if defined(__alpha__) || defined(__i386__) || defined(__x86_64__)
/*
* memcpy_toio works for us if:
* iowrite32_rep works for us if:
* (1) Copies data as 32bit quantities, not byte after byte,
* (2) Performs LE ordered stores, and
* (3) It copes with unaligned source (destination is guaranteed to be page
* aligned and length is guaranteed to be multiple of 4).
*/
memcpy_toio(va.vaddr, src, len);
iowrite32_rep(va.vaddr, src, len >> 2);
#else
u_int32_t __iomem* addr = va.vaddr;

View file

@ -550,7 +550,7 @@ static int mb862xx_gdc_init(struct mb862xxfb_par *par)
return 0;
}
static int __devinit of_platform_mb862xx_probe(struct of_device *ofdev,
static int __devinit of_platform_mb862xx_probe(struct platform_device *ofdev,
const struct of_device_id *id)
{
struct device_node *np = ofdev->dev.of_node;
@ -669,7 +669,7 @@ fbrel:
return ret;
}
static int __devexit of_platform_mb862xx_remove(struct of_device *ofdev)
static int __devexit of_platform_mb862xx_remove(struct platform_device *ofdev)
{
struct fb_info *fbi = dev_get_drvdata(&ofdev->dev);
struct mb862xxfb_par *par = fbi->par;

View file

@ -187,10 +187,8 @@ static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask);
static void mddi_handle_rev_data_avail(struct mddi_info *mddi)
{
union mddi_rev *rev = mddi->rev_data;
uint32_t rev_data_count;
uint32_t rev_crc_err_count;
int i;
struct reg_read_info *ri;
size_t prev_offset;
uint16_t length;
@ -670,7 +668,7 @@ static int __init mddi_rev_data_setup(struct mddi_info *mddi)
return 0;
}
static int __init mddi_probe(struct platform_device *pdev)
static int __devinit mddi_probe(struct platform_device *pdev)
{
struct msm_mddi_platform_data *pdata = pdev->dev.platform_data;
struct mddi_info *mddi = &mddi_info[pdev->id];

View file

@ -258,7 +258,6 @@ int get_img(struct mdp_img *img, struct fb_info *info,
{
int put_needed, ret = 0;
struct file *file;
unsigned long vstart;
file = fget_light(img->memory_id, &put_needed);
if (file == NULL)

View file

@ -19,13 +19,14 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/interrupt.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/prom.h>
#ifdef CONFIG_PPC64
#include <asm/pci-bridge.h>

View file

@ -25,7 +25,6 @@
#include <linux/platform_device.h>
#include <mach/gpio.h>
#include <plat/mux.h>
#include "omapfb.h"
@ -34,8 +33,6 @@
static int apollon_panel_init(struct lcd_panel *panel,
struct omapfb_device *fbdev)
{
/* configure LCD PWR_EN */
omap_cfg_reg(M21_242X_GPIO11);
return 0;
}

View file

@ -592,7 +592,7 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
r = omapdss_sdi_display_enable(dssdev);
if (r) {
pr_err("%s sdi enable failed\n", __func__);
return r;
goto fail_unlock;
}
/*FIXME tweak me */
@ -633,6 +633,8 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev)
return acx565akm_bl_update_status(md->bl_dev);
fail:
omapdss_sdi_display_disable(dssdev);
fail_unlock:
mutex_unlock(&md->mutex);
return r;
}

View file

@ -28,12 +28,13 @@
#include <linux/fb.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
#include <plat/display.h>
#include <plat/nokia-dsi-panel.h>
/* DSI Virtual channel. Hardcoded for now. */
#define TCH 0
@ -62,11 +63,136 @@
#define DCS_GET_ID2 0xdb
#define DCS_GET_ID3 0xdc
/* #define TAAL_USE_ESD_CHECK */
#define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
static irqreturn_t taal_te_isr(int irq, void *data);
static void taal_te_timeout_work_callback(struct work_struct *work);
static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable);
struct panel_regulator {
struct regulator *regulator;
const char *name;
int min_uV;
int max_uV;
};
static void free_regulators(struct panel_regulator *regulators, int n)
{
int i;
for (i = 0; i < n; i++) {
/* disable/put in reverse order */
regulator_disable(regulators[n - i - 1].regulator);
regulator_put(regulators[n - i - 1].regulator);
}
}
static int init_regulators(struct omap_dss_device *dssdev,
struct panel_regulator *regulators, int n)
{
int r, i, v;
for (i = 0; i < n; i++) {
struct regulator *reg;
reg = regulator_get(&dssdev->dev, regulators[i].name);
if (IS_ERR(reg)) {
dev_err(&dssdev->dev, "failed to get regulator %s\n",
regulators[i].name);
r = PTR_ERR(reg);
goto err;
}
/* FIXME: better handling of fixed vs. variable regulators */
v = regulator_get_voltage(reg);
if (v < regulators[i].min_uV || v > regulators[i].max_uV) {
r = regulator_set_voltage(reg, regulators[i].min_uV,
regulators[i].max_uV);
if (r) {
dev_err(&dssdev->dev,
"failed to set regulator %s voltage\n",
regulators[i].name);
regulator_put(reg);
goto err;
}
}
r = regulator_enable(reg);
if (r) {
dev_err(&dssdev->dev, "failed to enable regulator %s\n",
regulators[i].name);
regulator_put(reg);
goto err;
}
regulators[i].regulator = reg;
}
return 0;
err:
free_regulators(regulators, i);
return r;
}
/**
* struct panel_config - panel configuration
* @name: panel name
* @type: panel type
* @timings: panel resolution
* @sleep: various panel specific delays, passed to msleep() if non-zero
* @reset_sequence: reset sequence timings, passed to udelay() if non-zero
* @regulators: array of panel regulators
* @num_regulators: number of regulators in the array
*/
struct panel_config {
const char *name;
int type;
struct omap_video_timings timings;
struct {
unsigned int sleep_in;
unsigned int sleep_out;
unsigned int hw_reset;
unsigned int enable_te;
} sleep;
struct {
unsigned int high;
unsigned int low;
} reset_sequence;
struct panel_regulator *regulators;
int num_regulators;
};
enum {
PANEL_TAAL,
};
static struct panel_config panel_configs[] = {
{
.name = "taal",
.type = PANEL_TAAL,
.timings = {
.x_res = 864,
.y_res = 480,
},
.sleep = {
.sleep_in = 5,
.sleep_out = 5,
.hw_reset = 5,
.enable_te = 100, /* possible panel bug */
},
.reset_sequence = {
.high = 10,
.low = 10,
},
},
};
struct taal_data {
struct mutex lock;
@ -84,8 +210,15 @@ struct taal_data {
bool mirror;
bool te_enabled;
bool use_ext_te;
struct completion te_completion;
atomic_t do_update;
struct {
u16 x;
u16 y;
u16 w;
u16 h;
} update_region;
struct delayed_work te_timeout_work;
bool use_dsi_bl;
@ -96,8 +229,16 @@ struct taal_data {
struct workqueue_struct *esd_wq;
struct delayed_work esd_work;
struct panel_config *panel_config;
};
static inline struct nokia_dsi_panel_data
*get_panel_data(const struct omap_dss_device *dssdev)
{
return (struct nokia_dsi_panel_data *) dssdev->data;
}
static void taal_esd_work(struct work_struct *work);
static void hw_guard_start(struct taal_data *td, int guard_msec)
@ -159,7 +300,8 @@ static int taal_sleep_in(struct taal_data *td)
hw_guard_start(td, 120);
msleep(5);
if (td->panel_config->sleep.sleep_in)
msleep(td->panel_config->sleep.sleep_in);
return 0;
}
@ -176,7 +318,8 @@ static int taal_sleep_out(struct taal_data *td)
hw_guard_start(td, 120);
msleep(5);
if (td->panel_config->sleep.sleep_out)
msleep(td->panel_config->sleep.sleep_out);
return 0;
}
@ -279,6 +422,7 @@ static int taal_bl_update_status(struct backlight_device *dev)
{
struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
int level;
@ -290,24 +434,26 @@ static int taal_bl_update_status(struct backlight_device *dev)
dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
mutex_lock(&td->lock);
if (td->use_dsi_bl) {
if (td->enabled) {
dsi_bus_lock();
r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
dsi_bus_unlock();
if (r)
return r;
} else {
r = 0;
}
} else {
if (!dssdev->set_backlight)
return -EINVAL;
r = dssdev->set_backlight(dssdev, level);
if (r)
return r;
if (!panel_data->set_backlight)
r = -EINVAL;
else
r = panel_data->set_backlight(dssdev, level);
}
return 0;
mutex_unlock(&td->lock);
return r;
}
static int taal_bl_get_intensity(struct backlight_device *dev)
@ -344,16 +490,6 @@ static void taal_get_resolution(struct omap_dss_device *dssdev,
}
}
static irqreturn_t taal_te_isr(int irq, void *data)
{
struct omap_dss_device *dssdev = data;
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
complete_all(&td->te_completion);
return IRQ_HANDLED;
}
static ssize_t taal_num_errors_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@ -362,6 +498,8 @@ static ssize_t taal_num_errors_show(struct device *dev,
u8 errors;
int r;
mutex_lock(&td->lock);
if (td->enabled) {
dsi_bus_lock();
r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
@ -370,6 +508,8 @@ static ssize_t taal_num_errors_show(struct device *dev,
r = -ENODEV;
}
mutex_unlock(&td->lock);
if (r)
return r;
@ -384,6 +524,8 @@ static ssize_t taal_hw_revision_show(struct device *dev,
u8 id1, id2, id3;
int r;
mutex_lock(&td->lock);
if (td->enabled) {
dsi_bus_lock();
r = taal_get_id(&id1, &id2, &id3);
@ -392,6 +534,8 @@ static ssize_t taal_hw_revision_show(struct device *dev,
r = -ENODEV;
}
mutex_unlock(&td->lock);
if (r)
return r;
@ -441,6 +585,8 @@ static ssize_t store_cabc_mode(struct device *dev,
if (i == ARRAY_SIZE(cabc_modes))
return -EINVAL;
mutex_lock(&td->lock);
if (td->enabled) {
dsi_bus_lock();
if (!td->cabc_broken)
@ -450,6 +596,8 @@ static ssize_t store_cabc_mode(struct device *dev,
td->cabc_mode = i;
mutex_unlock(&td->lock);
return count;
}
@ -488,47 +636,93 @@ static struct attribute_group taal_attr_group = {
.attrs = taal_attrs,
};
static void taal_hw_reset(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
if (panel_data->reset_gpio == -1)
return;
gpio_set_value(panel_data->reset_gpio, 1);
if (td->panel_config->reset_sequence.high)
udelay(td->panel_config->reset_sequence.high);
/* reset the panel */
gpio_set_value(panel_data->reset_gpio, 0);
/* assert reset */
if (td->panel_config->reset_sequence.low)
udelay(td->panel_config->reset_sequence.low);
gpio_set_value(panel_data->reset_gpio, 1);
/* wait after releasing reset */
if (td->panel_config->sleep.hw_reset)
msleep(td->panel_config->sleep.hw_reset);
}
static int taal_probe(struct omap_dss_device *dssdev)
{
struct backlight_properties props;
struct taal_data *td;
struct backlight_device *bldev;
int r;
const struct omap_video_timings taal_panel_timings = {
.x_res = 864,
.y_res = 480,
};
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
struct panel_config *panel_config = NULL;
int r, i;
dev_dbg(&dssdev->dev, "probe\n");
if (!panel_data || !panel_data->name) {
r = -EINVAL;
goto err;
}
for (i = 0; i < ARRAY_SIZE(panel_configs); i++) {
if (strcmp(panel_data->name, panel_configs[i].name) == 0) {
panel_config = &panel_configs[i];
break;
}
}
if (!panel_config) {
r = -EINVAL;
goto err;
}
dssdev->panel.config = OMAP_DSS_LCD_TFT;
dssdev->panel.timings = taal_panel_timings;
dssdev->panel.timings = panel_config->timings;
dssdev->ctrl.pixel_size = 24;
td = kzalloc(sizeof(*td), GFP_KERNEL);
if (!td) {
r = -ENOMEM;
goto err0;
goto err;
}
td->dssdev = dssdev;
td->panel_config = panel_config;
mutex_init(&td->lock);
atomic_set(&td->do_update, 0);
r = init_regulators(dssdev, panel_config->regulators,
panel_config->num_regulators);
if (r)
goto err_reg;
td->esd_wq = create_singlethread_workqueue("taal_esd");
if (td->esd_wq == NULL) {
dev_err(&dssdev->dev, "can't create ESD workqueue\n");
r = -ENOMEM;
goto err1;
goto err_wq;
}
INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
dev_set_drvdata(&dssdev->dev, td);
taal_hw_reset(dssdev);
/* if no platform set_backlight() defined, presume DSI backlight
* control */
memset(&props, 0, sizeof(struct backlight_properties));
if (!dssdev->set_backlight)
if (!panel_data->set_backlight)
td->use_dsi_bl = true;
if (td->use_dsi_bl)
@ -539,7 +733,7 @@ static int taal_probe(struct omap_dss_device *dssdev)
&taal_bl_ops, &props);
if (IS_ERR(bldev)) {
r = PTR_ERR(bldev);
goto err2;
goto err_bl;
}
td->bldev = bldev;
@ -553,13 +747,13 @@ static int taal_probe(struct omap_dss_device *dssdev)
taal_bl_update_status(bldev);
if (dssdev->phy.dsi.ext_te) {
int gpio = dssdev->phy.dsi.ext_te_gpio;
if (panel_data->use_ext_te) {
int gpio = panel_data->ext_te_gpio;
r = gpio_request(gpio, "taal irq");
if (r) {
dev_err(&dssdev->dev, "GPIO request failed\n");
goto err3;
goto err_gpio;
}
gpio_direction_input(gpio);
@ -571,49 +765,52 @@ static int taal_probe(struct omap_dss_device *dssdev)
if (r) {
dev_err(&dssdev->dev, "IRQ request failed\n");
gpio_free(gpio);
goto err3;
goto err_irq;
}
init_completion(&td->te_completion);
INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work,
taal_te_timeout_work_callback);
td->use_ext_te = true;
dev_dbg(&dssdev->dev, "Using GPIO TE\n");
}
r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
if (r) {
dev_err(&dssdev->dev, "failed to create sysfs files\n");
goto err4;
goto err_sysfs;
}
return 0;
err4:
if (td->use_ext_te) {
int gpio = dssdev->phy.dsi.ext_te_gpio;
free_irq(gpio_to_irq(gpio), dssdev);
gpio_free(gpio);
}
err3:
err_sysfs:
if (panel_data->use_ext_te)
free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev);
err_irq:
if (panel_data->use_ext_te)
gpio_free(panel_data->ext_te_gpio);
err_gpio:
backlight_device_unregister(bldev);
err2:
cancel_delayed_work_sync(&td->esd_work);
err_bl:
destroy_workqueue(td->esd_wq);
err1:
err_wq:
free_regulators(panel_config->regulators, panel_config->num_regulators);
err_reg:
kfree(td);
err0:
err:
return r;
}
static void taal_remove(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
struct backlight_device *bldev;
dev_dbg(&dssdev->dev, "remove\n");
sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
if (td->use_ext_te) {
int gpio = dssdev->phy.dsi.ext_te_gpio;
if (panel_data->use_ext_te) {
int gpio = panel_data->ext_te_gpio;
free_irq(gpio_to_irq(gpio), dssdev);
gpio_free(gpio);
}
@ -623,9 +820,15 @@ static void taal_remove(struct omap_dss_device *dssdev)
taal_bl_update_status(bldev);
backlight_device_unregister(bldev);
cancel_delayed_work_sync(&td->esd_work);
cancel_delayed_work(&td->esd_work);
destroy_workqueue(td->esd_wq);
/* reset, to be sure that the panel is in a valid state */
taal_hw_reset(dssdev);
free_regulators(td->panel_config->regulators,
td->panel_config->num_regulators);
kfree(td);
}
@ -635,23 +838,14 @@ static int taal_power_on(struct omap_dss_device *dssdev)
u8 id1, id2, id3;
int r;
if (dssdev->platform_enable) {
r = dssdev->platform_enable(dssdev);
if (r)
return r;
}
/* it seems we have to wait a bit until taal is ready */
msleep(5);
dsi_bus_lock();
r = omapdss_dsi_display_enable(dssdev);
if (r) {
dev_err(&dssdev->dev, "failed to enable DSI\n");
goto err0;
}
taal_hw_reset(dssdev);
omapdss_dsi_vc_enable_hs(TCH, false);
r = taal_sleep_out(td);
@ -662,34 +856,47 @@ static int taal_power_on(struct omap_dss_device *dssdev)
if (r)
goto err;
/* on early revisions CABC is broken */
if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
/* on early Taal revisions CABC is broken */
if (td->panel_config->type == PANEL_TAAL &&
(id2 == 0x00 || id2 == 0xff || id2 == 0x81))
td->cabc_broken = true;
taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */
r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
if (r)
goto err;
taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
r = taal_dcs_write_1(DCS_CTRL_DISPLAY,
(1<<2) | (1<<5)); /* BL | BCTRL */
if (r)
goto err;
taal_set_addr_mode(td->rotate, td->mirror);
if (!td->cabc_broken)
taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
r = taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
if (r)
goto err;
taal_dcs_write_0(DCS_DISPLAY_ON);
r = taal_set_addr_mode(td->rotate, td->mirror);
if (r)
goto err;
if (!td->cabc_broken) {
r = taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
if (r)
goto err;
}
r = taal_dcs_write_0(DCS_DISPLAY_ON);
if (r)
goto err;
r = _taal_enable_te(dssdev, td->te_enabled);
if (r)
goto err;
#ifdef TAAL_USE_ESD_CHECK
queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
#endif
td->enabled = 1;
if (!td->intro_printed) {
dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n",
id1, id2, id3);
dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n",
td->panel_config->name, id1, id2, id3);
if (td->cabc_broken)
dev_info(&dssdev->dev,
"old Taal version, CABC disabled\n");
@ -698,46 +905,44 @@ static int taal_power_on(struct omap_dss_device *dssdev)
omapdss_dsi_vc_enable_hs(TCH, true);
dsi_bus_unlock();
return 0;
err:
dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n");
taal_hw_reset(dssdev);
omapdss_dsi_display_disable(dssdev);
err0:
dsi_bus_unlock();
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
return r;
}
static void taal_power_off(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int r;
dsi_bus_lock();
r = taal_dcs_write_0(DCS_DISPLAY_OFF);
if (!r) {
r = taal_sleep_in(td);
/* HACK: wait a bit so that the message goes through */
msleep(10);
}
cancel_delayed_work(&td->esd_work);
taal_dcs_write_0(DCS_DISPLAY_OFF);
taal_sleep_in(td);
/* wait a bit so that the message goes through */
msleep(10);
if (r) {
dev_err(&dssdev->dev,
"error disabling panel, issuing HW reset\n");
taal_hw_reset(dssdev);
}
omapdss_dsi_display_disable(dssdev);
if (dssdev->platform_disable)
dssdev->platform_disable(dssdev);
td->enabled = 0;
dsi_bus_unlock();
}
static int taal_enable(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
dev_dbg(&dssdev->dev, "enable\n");
@ -749,10 +954,19 @@ static int taal_enable(struct omap_dss_device *dssdev)
goto err;
}
dsi_bus_lock();
r = taal_power_on(dssdev);
dsi_bus_unlock();
if (r)
goto err;
if (panel_data->use_esd_check)
queue_delayed_work(td->esd_wq, &td->esd_work,
TAAL_ESD_CHECK_PERIOD);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
mutex_unlock(&td->lock);
@ -772,9 +986,15 @@ static void taal_disable(struct omap_dss_device *dssdev)
mutex_lock(&td->lock);
cancel_delayed_work(&td->esd_work);
dsi_bus_lock();
if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
taal_power_off(dssdev);
dsi_bus_unlock();
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
mutex_unlock(&td->lock);
@ -794,7 +1014,14 @@ static int taal_suspend(struct omap_dss_device *dssdev)
goto err;
}
cancel_delayed_work(&td->esd_work);
dsi_bus_lock();
taal_power_off(dssdev);
dsi_bus_unlock();
dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
mutex_unlock(&td->lock);
@ -808,6 +1035,7 @@ err:
static int taal_resume(struct omap_dss_device *dssdev)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
dev_dbg(&dssdev->dev, "resume\n");
@ -819,8 +1047,20 @@ static int taal_resume(struct omap_dss_device *dssdev)
goto err;
}
dsi_bus_lock();
r = taal_power_on(dssdev);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
dsi_bus_unlock();
if (r) {
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
} else {
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
if (panel_data->use_esd_check)
queue_delayed_work(td->esd_wq, &td->esd_work,
TAAL_ESD_CHECK_PERIOD);
}
mutex_unlock(&td->lock);
@ -837,10 +1077,52 @@ static void taal_framedone_cb(int err, void *data)
dsi_bus_unlock();
}
static irqreturn_t taal_te_isr(int irq, void *data)
{
struct omap_dss_device *dssdev = data;
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
int old;
int r;
old = atomic_cmpxchg(&td->do_update, 1, 0);
if (old) {
cancel_delayed_work(&td->te_timeout_work);
r = omap_dsi_update(dssdev, TCH,
td->update_region.x,
td->update_region.y,
td->update_region.w,
td->update_region.h,
taal_framedone_cb, dssdev);
if (r)
goto err;
}
return IRQ_HANDLED;
err:
dev_err(&dssdev->dev, "start update failed\n");
dsi_bus_unlock();
return IRQ_HANDLED;
}
static void taal_te_timeout_work_callback(struct work_struct *work)
{
struct taal_data *td = container_of(work, struct taal_data,
te_timeout_work.work);
struct omap_dss_device *dssdev = td->dssdev;
dev_err(&dssdev->dev, "TE not received for 250ms!\n");
atomic_set(&td->do_update, 0);
dsi_bus_unlock();
}
static int taal_update(struct omap_dss_device *dssdev,
u16 x, u16 y, u16 w, u16 h)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h);
@ -853,7 +1135,7 @@ static int taal_update(struct omap_dss_device *dssdev,
goto err;
}
r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h);
r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true);
if (r)
goto err;
@ -861,10 +1143,21 @@ static int taal_update(struct omap_dss_device *dssdev,
if (r)
goto err;
r = omap_dsi_update(dssdev, TCH, x, y, w, h,
taal_framedone_cb, dssdev);
if (r)
goto err;
if (td->te_enabled && panel_data->use_ext_te) {
td->update_region.x = x;
td->update_region.y = y;
td->update_region.w = w;
td->update_region.h = h;
barrier();
schedule_delayed_work(&td->te_timeout_work,
msecs_to_jiffies(250));
atomic_set(&td->do_update, 1);
} else {
r = omap_dsi_update(dssdev, TCH, x, y, w, h,
taal_framedone_cb, dssdev);
if (r)
goto err;
}
/* note: no bus_unlock here. unlock is in framedone_cb */
mutex_unlock(&td->lock);
@ -894,20 +1187,19 @@ static int taal_sync(struct omap_dss_device *dssdev)
static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable)
{
struct taal_data *td = dev_get_drvdata(&dssdev->dev);
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
int r;
td->te_enabled = enable;
if (enable)
r = taal_dcs_write_1(DCS_TEAR_ON, 0);
else
r = taal_dcs_write_0(DCS_TEAR_OFF);
omapdss_dsi_enable_te(dssdev, enable);
if (!panel_data->use_ext_te)
omapdss_dsi_enable_te(dssdev, enable);
/* XXX for some reason, DSI TE breaks if we don't wait here.
* Panel bug? Needs more studying */
msleep(100);
if (td->panel_config->sleep.enable_te)
msleep(td->panel_config->sleep.enable_te);
return r;
}
@ -918,10 +1210,26 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
int r;
mutex_lock(&td->lock);
if (td->te_enabled == enable)
goto end;
dsi_bus_lock();
r = _taal_enable_te(dssdev, enable);
if (td->enabled) {
r = _taal_enable_te(dssdev, enable);
if (r)
goto err;
}
td->te_enabled = enable;
dsi_bus_unlock();
end:
mutex_unlock(&td->lock);
return 0;
err:
dsi_bus_unlock();
mutex_unlock(&td->lock);
@ -948,6 +1256,10 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
mutex_lock(&td->lock);
if (td->rotate == rotate)
goto end;
dsi_bus_lock();
if (td->enabled) {
@ -959,6 +1271,7 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
td->rotate = rotate;
dsi_bus_unlock();
end:
mutex_unlock(&td->lock);
return 0;
err:
@ -987,6 +1300,10 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
dev_dbg(&dssdev->dev, "mirror %d\n", enable);
mutex_lock(&td->lock);
if (td->mirror == enable)
goto end;
dsi_bus_lock();
if (td->enabled) {
r = taal_set_addr_mode(td->rotate, enable);
@ -997,6 +1314,7 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
td->mirror = enable;
dsi_bus_unlock();
end:
mutex_unlock(&td->lock);
return 0;
err:
@ -1024,23 +1342,30 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
int r;
mutex_lock(&td->lock);
if (!td->enabled) {
r = -ENODEV;
goto err1;
}
dsi_bus_lock();
r = taal_dcs_read_1(DCS_GET_ID1, &id1);
if (r)
goto err;
goto err2;
r = taal_dcs_read_1(DCS_GET_ID2, &id2);
if (r)
goto err;
goto err2;
r = taal_dcs_read_1(DCS_GET_ID3, &id3);
if (r)
goto err;
goto err2;
dsi_bus_unlock();
mutex_unlock(&td->lock);
return 0;
err:
err2:
dsi_bus_unlock();
err1:
mutex_unlock(&td->lock);
return r;
}
@ -1128,6 +1453,7 @@ static void taal_esd_work(struct work_struct *work)
struct taal_data *td = container_of(work, struct taal_data,
esd_work.work);
struct omap_dss_device *dssdev = td->dssdev;
struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev);
u8 state1, state2;
int r;
@ -1168,7 +1494,7 @@ static void taal_esd_work(struct work_struct *work)
}
/* Self-diagnostics result is also shown on TE GPIO line. We need
* to re-enable TE after self diagnostics */
if (td->use_ext_te && td->te_enabled) {
if (td->te_enabled && panel_data->use_ext_te) {
r = taal_dcs_write_1(DCS_TEAR_ON, 0);
if (r)
goto err;
@ -1184,6 +1510,7 @@ err:
dev_err(&dssdev->dev, "performing LCD reset\n");
taal_power_off(dssdev);
taal_hw_reset(dssdev);
taal_power_on(dssdev);
dsi_bus_unlock();

View file

@ -73,8 +73,12 @@ static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev)
static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev)
{
dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS;
dssdev->panel.config = OMAP_DSS_LCD_TFT |
OMAP_DSS_LCD_IVS |
OMAP_DSS_LCD_IHS |
OMAP_DSS_LCD_IPC |
OMAP_DSS_LCD_ONOFF;
dssdev->panel.timings = toppoly_tdo_panel_timings;
return 0;

View file

@ -31,6 +31,7 @@
#include <linux/seq_file.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/hardirq.h>
#include <plat/sram.h>
#include <plat/clock.h>
@ -335,7 +336,7 @@ void dispc_save_context(void)
void dispc_restore_context(void)
{
RR(SYSCONFIG);
RR(IRQENABLE);
/*RR(IRQENABLE);*/
/*RR(CONTROL);*/
RR(CONFIG);
RR(DEFAULT_COLOR0);
@ -472,6 +473,15 @@ void dispc_restore_context(void)
/* enable last, because LCD & DIGIT enable are here */
RR(CONTROL);
/* clear spurious SYNC_LOST_DIGIT interrupts */
dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
/*
* enable last so IRQs won't trigger before
* the context is fully restored
*/
RR(IRQENABLE);
}
#undef SR
@ -3019,7 +3029,7 @@ void dispc_fake_vsync_irq(void)
u32 irqstatus = DISPC_IRQ_VSYNC;
int i;
local_irq_disable();
WARN_ON(!in_interrupt());
for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
struct omap_dispc_isr_data *isr_data;
@ -3031,8 +3041,6 @@ void dispc_fake_vsync_irq(void)
if (isr_data->mask & irqstatus)
isr_data->isr(isr_data->arg, irqstatus);
}
local_irq_enable();
}
#endif

View file

@ -82,6 +82,9 @@ static ssize_t display_upd_mode_store(struct device *dev,
int val, r;
enum omap_dss_update_mode mode;
if (!dssdev->driver->set_update_mode)
return -EINVAL;
val = simple_strtoul(buf, NULL, 10);
switch (val) {
@ -343,7 +346,6 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev)
case OMAP_DISPLAY_TYPE_VENC:
case OMAP_DISPLAY_TYPE_SDI:
return 24;
return 24;
default:
BUG();
}

View file

@ -165,6 +165,14 @@ struct dsi_reg { u16 idx; };
#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
#define DSI_CIO_IRQ_ERROR_MASK \
(DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \
DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \
DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRCONTROL1 | \
DSI_CIO_IRQ_ERRCONTROL2 | DSI_CIO_IRQ_ERRCONTROL3 | \
DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \
DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \
DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3)
#define DSI_DT_DCS_SHORT_WRITE_0 0x05
#define DSI_DT_DCS_SHORT_WRITE_1 0x15
@ -232,13 +240,15 @@ static struct
unsigned pll_locked;
struct completion bta_completion;
void (*bta_callback)(void);
int update_channel;
struct dsi_update_region update_region;
bool te_enabled;
struct work_struct framedone_work;
struct workqueue_struct *workqueue;
void (*framedone_callback)(int, void *);
void *framedone_data;
@ -509,9 +519,13 @@ void dsi_irq_handler(void)
dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
#endif
if (vcstatus & DSI_VC_IRQ_BTA)
if (vcstatus & DSI_VC_IRQ_BTA) {
complete(&dsi.bta_completion);
if (dsi.bta_callback)
dsi.bta_callback();
}
if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
i, vcstatus);
@ -536,8 +550,12 @@ void dsi_irq_handler(void)
/* flush posted write */
dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
print_irq_status_cio(ciostatus);
if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) {
DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
print_irq_status_cio(ciostatus);
} else if (debug_irq) {
print_irq_status_cio(ciostatus);
}
}
dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
@ -584,11 +602,8 @@ static void _dsi_initialize_irq(void)
for (i = 0; i < 4; ++i)
dsi_write_reg(DSI_VC_IRQENABLE(i), l);
/* XXX zonda responds incorrectly, causing control error:
Exit from LP-ESC mode to LP11 uses wrong transition states on the
data lines LP0 and LN0. */
dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE,
-1 & (~DSI_CIO_IRQ_ERRCONTROL2));
l = DSI_CIO_IRQ_ERROR_MASK;
dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l);
}
static u32 dsi_get_errors(void)
@ -1098,6 +1113,7 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
DSSERR("PLL not coming out of reset.\n");
r = -ENODEV;
dispc_pck_free_enable(0);
goto err1;
}
@ -1740,42 +1756,52 @@ static void dsi_vc_initial_config(int channel)
dsi.vc[channel].mode = DSI_VC_MODE_L4;
}
static void dsi_vc_config_l4(int channel)
static int dsi_vc_config_l4(int channel)
{
if (dsi.vc[channel].mode == DSI_VC_MODE_L4)
return;
return 0;
DSSDBGF("%d", channel);
dsi_vc_enable(channel, 0);
if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
/* VC_BUSY */
if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) {
DSSERR("vc(%d) busy when trying to config for L4\n", channel);
return -EIO;
}
REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
dsi_vc_enable(channel, 1);
dsi.vc[channel].mode = DSI_VC_MODE_L4;
return 0;
}
static void dsi_vc_config_vp(int channel)
static int dsi_vc_config_vp(int channel)
{
if (dsi.vc[channel].mode == DSI_VC_MODE_VP)
return;
return 0;
DSSDBGF("%d", channel);
dsi_vc_enable(channel, 0);
if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
/* VC_BUSY */
if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) {
DSSERR("vc(%d) busy when trying to config for VP\n", channel);
return -EIO;
}
REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
dsi_vc_enable(channel, 1);
dsi.vc[channel].mode = DSI_VC_MODE_VP;
return 0;
}
@ -1854,19 +1880,19 @@ static u16 dsi_vc_flush_receive_data(int channel)
u32 val;
u8 dt;
val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
DSSDBG("\trawval %#08x\n", val);
DSSERR("\trawval %#08x\n", val);
dt = FLD_GET(val, 5, 0);
if (dt == DSI_DT_RX_ACK_WITH_ERR) {
u16 err = FLD_GET(val, 23, 8);
dsi_show_rx_ack_with_err(err);
} else if (dt == DSI_DT_RX_SHORT_READ_1) {
DSSDBG("\tDCS short response, 1 byte: %#x\n",
DSSERR("\tDCS short response, 1 byte: %#x\n",
FLD_GET(val, 23, 8));
} else if (dt == DSI_DT_RX_SHORT_READ_2) {
DSSDBG("\tDCS short response, 2 byte: %#x\n",
DSSERR("\tDCS short response, 2 byte: %#x\n",
FLD_GET(val, 23, 8));
} else if (dt == DSI_DT_RX_DCS_LONG_READ) {
DSSDBG("\tDCS long response, len %d\n",
DSSERR("\tDCS long response, len %d\n",
FLD_GET(val, 23, 8));
dsi_vc_flush_long_data(channel);
} else {
@ -2087,6 +2113,13 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len)
if (r)
goto err;
if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */
DSSERR("rx fifo not empty after write, dumping data:\n");
dsi_vc_flush_receive_data(channel);
r = -EIO;
goto err;
}
return 0;
err:
DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n",
@ -2233,11 +2266,12 @@ int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data)
}
EXPORT_SYMBOL(dsi_vc_dcs_read_1);
int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data)
int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2)
{
u8 buf[2];
int r;
r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2);
r = dsi_vc_dcs_read(channel, dcs_cmd, buf, 2);
if (r < 0)
return r;
@ -2245,231 +2279,122 @@ int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data)
if (r != 2)
return -EIO;
*data1 = buf[0];
*data2 = buf[1];
return 0;
}
EXPORT_SYMBOL(dsi_vc_dcs_read_2);
int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
{
int r;
r = dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
len, 0);
if (r)
return r;
r = dsi_vc_send_bta_sync(channel);
return r;
}
EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
static void dsi_set_lp_rx_timeout(unsigned long ns)
static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16)
{
u32 r;
unsigned x4, x16;
unsigned long fck;
unsigned long ticks;
unsigned long total_ticks;
u32 r;
BUG_ON(ticks > 0x1fff);
/* ticks in DSI_FCK */
fck = dsi_fclk_rate();
ticks = (fck / 1000 / 1000) * ns / 1000;
x4 = 0;
x16 = 0;
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
x4 = 1;
x16 = 0;
}
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
x4 = 0;
x16 = 1;
}
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
x4 = 1;
x16 = 1;
}
if (ticks > 0x1fff) {
DSSWARN("LP_TX_TO over limit, setting it to max\n");
ticks = 0x1fff;
x4 = 1;
x16 = 1;
}
r = dsi_read_reg(DSI_TIMING2);
r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */
r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */
r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */
r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */
r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
dsi_write_reg(DSI_TIMING2, r);
DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n",
(ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
(fck / 1000 / 1000),
ticks, x4 ? " x4" : "", x16 ? " x16" : "");
total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n",
total_ticks,
ticks, x4 ? " x4" : "", x16 ? " x16" : "",
(total_ticks * 1000) / (fck / 1000 / 1000));
}
static void dsi_set_ta_timeout(unsigned long ns)
static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16)
{
u32 r;
unsigned x8, x16;
unsigned long fck;
unsigned long ticks;
unsigned long total_ticks;
u32 r;
BUG_ON(ticks > 0x1fff);
/* ticks in DSI_FCK */
fck = dsi_fclk_rate();
ticks = (fck / 1000 / 1000) * ns / 1000;
x8 = 0;
x16 = 0;
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / 8;
x8 = 1;
x16 = 0;
}
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
x8 = 0;
x16 = 1;
}
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / (8 * 16);
x8 = 1;
x16 = 1;
}
if (ticks > 0x1fff) {
DSSWARN("TA_TO over limit, setting it to max\n");
ticks = 0x1fff;
x8 = 1;
x16 = 1;
}
r = dsi_read_reg(DSI_TIMING1);
r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */
r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */
r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */
r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */
r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
dsi_write_reg(DSI_TIMING1, r);
DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n",
(ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) /
(fck / 1000 / 1000),
ticks, x8 ? " x8" : "", x16 ? " x16" : "");
total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1);
DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n",
total_ticks,
ticks, x8 ? " x8" : "", x16 ? " x16" : "",
(total_ticks * 1000) / (fck / 1000 / 1000));
}
static void dsi_set_stop_state_counter(unsigned long ns)
static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16)
{
u32 r;
unsigned x4, x16;
unsigned long fck;
unsigned long ticks;
unsigned long total_ticks;
u32 r;
BUG_ON(ticks > 0x1fff);
/* ticks in DSI_FCK */
fck = dsi_fclk_rate();
ticks = (fck / 1000 / 1000) * ns / 1000;
x4 = 0;
x16 = 0;
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
x4 = 1;
x16 = 0;
}
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
x4 = 0;
x16 = 1;
}
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
x4 = 1;
x16 = 1;
}
if (ticks > 0x1fff) {
DSSWARN("STOP_STATE_COUNTER_IO over limit, "
"setting it to max\n");
ticks = 0x1fff;
x4 = 1;
x16 = 1;
}
r = dsi_read_reg(DSI_TIMING1);
r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */
r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */
r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */
r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */
r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
dsi_write_reg(DSI_TIMING1, r);
DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n",
(ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
(fck / 1000 / 1000),
ticks, x4 ? " x4" : "", x16 ? " x16" : "");
total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n",
total_ticks,
ticks, x4 ? " x4" : "", x16 ? " x16" : "",
(total_ticks * 1000) / (fck / 1000 / 1000));
}
static void dsi_set_hs_tx_timeout(unsigned long ns)
static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16)
{
u32 r;
unsigned x4, x16;
unsigned long fck;
unsigned long ticks;
unsigned long total_ticks;
u32 r;
BUG_ON(ticks > 0x1fff);
/* ticks in TxByteClkHS */
fck = dsi_get_txbyteclkhs();
ticks = (fck / 1000 / 1000) * ns / 1000;
x4 = 0;
x16 = 0;
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
x4 = 1;
x16 = 0;
}
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
x4 = 0;
x16 = 1;
}
if (ticks > 0x1fff) {
ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
x4 = 1;
x16 = 1;
}
if (ticks > 0x1fff) {
DSSWARN("HS_TX_TO over limit, setting it to max\n");
ticks = 0x1fff;
x4 = 1;
x16 = 1;
}
r = dsi_read_reg(DSI_TIMING2);
r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */
r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */
r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */
r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */
r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
dsi_write_reg(DSI_TIMING2, r);
DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n",
(ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
(fck / 1000 / 1000),
ticks, x4 ? " x4" : "", x16 ? " x16" : "");
total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1);
DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n",
total_ticks,
ticks, x4 ? " x4" : "", x16 ? " x16" : "",
(total_ticks * 1000) / (fck / 1000 / 1000));
}
static int dsi_proto_config(struct omap_dss_device *dssdev)
{
@ -2487,10 +2412,10 @@ static int dsi_proto_config(struct omap_dss_device *dssdev)
DSI_FIFO_SIZE_32);
/* XXX what values for the timeouts? */
dsi_set_stop_state_counter(1000);
dsi_set_ta_timeout(6400000);
dsi_set_lp_rx_timeout(48000);
dsi_set_hs_tx_timeout(1000000);
dsi_set_stop_state_counter(0x1000, false, false);
dsi_set_ta_timeout(0x1fff, true, true);
dsi_set_lp_rx_timeout(0x1fff, true, true);
dsi_set_hs_tx_timeout(0x1fff, true, true);
switch (dssdev->ctrl.pixel_size) {
case 16:
@ -2759,6 +2684,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
unsigned packet_payload;
unsigned packet_len;
u32 l;
int r;
const unsigned channel = dsi.update_channel;
/* line buffer is 1024 x 24bits */
/* XXX: for some reason using full buffer size causes considerable TX
@ -2809,8 +2735,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
dsi_perf_mark_start();
schedule_delayed_work(&dsi.framedone_timeout_work,
r = queue_delayed_work(dsi.workqueue, &dsi.framedone_timeout_work,
msecs_to_jiffies(250));
BUG_ON(r == 0);
dss_start_update(dssdev);
@ -2834,107 +2761,108 @@ static void dsi_te_timeout(unsigned long arg)
}
#endif
static void dsi_handle_framedone(int error)
{
const int channel = dsi.update_channel;
cancel_delayed_work(&dsi.framedone_timeout_work);
dsi_vc_disable_bta_irq(channel);
/* SIDLEMODE back to smart-idle */
dispc_enable_sidle();
dsi.bta_callback = NULL;
if (dsi.te_enabled) {
/* enable LP_RX_TO again after the TE */
REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
/* RX_FIFO_NOT_EMPTY */
if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
DSSERR("Received error during frame transfer:\n");
dsi_vc_flush_receive_data(channel);
if (!error)
error = -EIO;
}
dsi.framedone_callback(error, dsi.framedone_data);
if (!error)
dsi_perf_show("DISPC");
}
static void dsi_framedone_timeout_work_callback(struct work_struct *work)
{
int r;
const int channel = dsi.update_channel;
/* XXX While extremely unlikely, we could get FRAMEDONE interrupt after
* 250ms which would conflict with this timeout work. What should be
* done is first cancel the transfer on the HW, and then cancel the
* possibly scheduled framedone work. However, cancelling the transfer
* on the HW is buggy, and would probably require resetting the whole
* DSI */
DSSERR("Framedone not received for 250ms!\n");
/* SIDLEMODE back to smart-idle */
dispc_enable_sidle();
if (dsi.te_enabled) {
/* enable LP_RX_TO again after the TE */
REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
/* Send BTA after the frame. We need this for the TE to work, as TE
* trigger is only sent for BTAs without preceding packet. Thus we need
* to BTA after the pixel packets so that next BTA will cause TE
* trigger.
*
* This is not needed when TE is not in use, but we do it anyway to
* make sure that the transfer has been completed. It would be more
* optimal, but more complex, to wait only just before starting next
* transfer. */
r = dsi_vc_send_bta_sync(channel);
if (r)
DSSERR("BTA after framedone failed\n");
/* RX_FIFO_NOT_EMPTY */
if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
DSSERR("Received error during frame transfer:\n");
dsi_vc_flush_receive_data(channel);
}
dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data);
dsi_handle_framedone(-ETIMEDOUT);
}
static void dsi_framedone_irq_callback(void *data, u32 mask)
static void dsi_framedone_bta_callback(void)
{
/* Note: We get FRAMEDONE when DISPC has finished sending pixels and
* turns itself off. However, DSI still has the pixels in its buffers,
* and is sending the data.
*/
/* SIDLEMODE back to smart-idle */
dispc_enable_sidle();
schedule_work(&dsi.framedone_work);
}
static void dsi_handle_framedone(void)
{
int r;
const int channel = dsi.update_channel;
DSSDBG("FRAMEDONE\n");
if (dsi.te_enabled) {
/* enable LP_RX_TO again after the TE */
REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
/* Send BTA after the frame. We need this for the TE to work, as TE
* trigger is only sent for BTAs without preceding packet. Thus we need
* to BTA after the pixel packets so that next BTA will cause TE
* trigger.
*
* This is not needed when TE is not in use, but we do it anyway to
* make sure that the transfer has been completed. It would be more
* optimal, but more complex, to wait only just before starting next
* transfer. */
r = dsi_vc_send_bta_sync(channel);
if (r)
DSSERR("BTA after framedone failed\n");
/* RX_FIFO_NOT_EMPTY */
if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
DSSERR("Received error during frame transfer:\n");
dsi_vc_flush_receive_data(channel);
}
dsi_handle_framedone(0);
#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
dispc_fake_vsync_irq();
#endif
}
static void dsi_framedone_work_callback(struct work_struct *work)
static void dsi_framedone_irq_callback(void *data, u32 mask)
{
DSSDBGF();
const int channel = dsi.update_channel;
int r;
cancel_delayed_work_sync(&dsi.framedone_timeout_work);
/* Note: We get FRAMEDONE when DISPC has finished sending pixels and
* turns itself off. However, DSI still has the pixels in its buffers,
* and is sending the data.
*/
dsi_handle_framedone();
if (dsi.te_enabled) {
/* enable LP_RX_TO again after the TE */
REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
}
dsi_perf_show("DISPC");
/* Send BTA after the frame. We need this for the TE to work, as TE
* trigger is only sent for BTAs without preceding packet. Thus we need
* to BTA after the pixel packets so that next BTA will cause TE
* trigger.
*
* This is not needed when TE is not in use, but we do it anyway to
* make sure that the transfer has been completed. It would be more
* optimal, but more complex, to wait only just before starting next
* transfer.
*
* Also, as there's no interrupt telling when the transfer has been
* done and the channel could be reconfigured, the only way is to
* busyloop until TE_SIZE is zero. With BTA we can do this
* asynchronously.
* */
dsi.framedone_callback(0, dsi.framedone_data);
dsi.bta_callback = dsi_framedone_bta_callback;
barrier();
dsi_vc_enable_bta_irq(channel);
r = dsi_vc_send_bta(channel);
if (r) {
DSSERR("BTA after framedone failed\n");
dsi_handle_framedone(-EIO);
}
}
int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
u16 *x, u16 *y, u16 *w, u16 *h)
u16 *x, u16 *y, u16 *w, u16 *h,
bool enlarge_update_area)
{
u16 dw, dh;
@ -2958,7 +2886,8 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev,
dsi_perf_mark_setup();
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
dss_setup_partial_planes(dssdev, x, y, w, h);
dss_setup_partial_planes(dssdev, x, y, w, h,
enlarge_update_area);
dispc_set_lcd_size(*w, *h);
}
@ -2973,6 +2902,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
{
dsi.update_channel = channel;
/* OMAP DSS cannot send updates of odd widths.
* omap_dsi_prepare_update() makes the widths even, but add a BUG_ON
* here to make sure we catch erroneous updates. Otherwise we'll only
* see rather obscure HW error happening, as DSS halts. */
BUG_ON(x % 2 == 1);
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
dsi.framedone_callback = callback;
dsi.framedone_data = data;
@ -2985,7 +2920,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev,
dsi_update_screen_dispc(dssdev, x, y, w, h);
} else {
dsi_update_screen_l4(dssdev, x, y, w, h);
int r;
r = dsi_update_screen_l4(dssdev, x, y, w, h);
if (r)
return r;
dsi_perf_show("L4");
callback(0, data);
}
@ -3048,8 +2988,10 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
cinfo.regm3 = dssdev->phy.dsi.div.regm3;
cinfo.regm4 = dssdev->phy.dsi.div.regm4;
r = dsi_calc_clock_rates(&cinfo);
if (r)
if (r) {
DSSERR("Failed to calc dsi clocks\n");
return r;
}
r = dsi_pll_set_clock_div(&cinfo);
if (r) {
@ -3147,6 +3089,13 @@ err0:
static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
{
/* disable interface */
dsi_if_enable(0);
dsi_vc_enable(0, 0);
dsi_vc_enable(1, 0);
dsi_vc_enable(2, 0);
dsi_vc_enable(3, 0);
dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK);
dsi_complexio_uninit();
@ -3257,7 +3206,7 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
burst_size_bytes = 16 * 32 / 8;
*fifo_high = fifo_size - burst_size_bytes;
*fifo_low = fifo_size - burst_size_bytes * 8;
*fifo_low = fifo_size - burst_size_bytes * 2;
}
int dsi_init_display(struct omap_dss_device *dssdev)
@ -3274,6 +3223,18 @@ int dsi_init_display(struct omap_dss_device *dssdev)
return 0;
}
void dsi_wait_dsi1_pll_active(void)
{
if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1)
DSSERR("DSI1 PLL clock not active\n");
}
void dsi_wait_dsi2_pll_active(void)
{
if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1)
DSSERR("DSI2 PLL clock not active\n");
}
int dsi_init(struct platform_device *pdev)
{
u32 rev;
@ -3292,7 +3253,10 @@ int dsi_init(struct platform_device *pdev)
mutex_init(&dsi.lock);
sema_init(&dsi.bus_lock, 1);
INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback);
dsi.workqueue = create_singlethread_workqueue("dsi");
if (dsi.workqueue == NULL)
return -ENOMEM;
INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work,
dsi_framedone_timeout_work_callback);
@ -3328,6 +3292,7 @@ int dsi_init(struct platform_device *pdev)
err2:
iounmap(dsi.base);
err1:
destroy_workqueue(dsi.workqueue);
return r;
}
@ -3335,6 +3300,8 @@ void dsi_exit(void)
{
iounmap(dsi.base);
destroy_workqueue(dsi.workqueue);
DSSDBG("omap_dsi_exit\n");
}

View file

@ -265,6 +265,9 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src)
b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
if (clk_src == DSS_SRC_DSI1_PLL_FCLK)
dsi_wait_dsi1_pll_active();
REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */
dss.dispc_clk_source = clk_src;
@ -279,6 +282,9 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src)
b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1;
if (clk_src == DSS_SRC_DSI2_PLL_FCLK)
dsi_wait_dsi2_pll_active();
REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */
dss.dsi_clk_source = clk_src;

View file

@ -199,7 +199,8 @@ int dss_init_overlay_managers(struct platform_device *pdev);
void dss_uninit_overlay_managers(struct platform_device *pdev);
int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
void dss_setup_partial_planes(struct omap_dss_device *dssdev,
u16 *x, u16 *y, u16 *w, u16 *h);
u16 *x, u16 *y, u16 *w, u16 *h,
bool enlarge_update_area);
void dss_start_update(struct omap_dss_device *dssdev);
/* overlay */
@ -281,6 +282,8 @@ void dsi_pll_uninit(void);
void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
u32 fifo_size, enum omap_burst_size *burst_size,
u32 *fifo_low, u32 *fifo_high);
void dsi_wait_dsi1_pll_active(void);
void dsi_wait_dsi2_pll_active(void);
#else
static inline int dsi_init(struct platform_device *pdev)
{
@ -289,6 +292,12 @@ static inline int dsi_init(struct platform_device *pdev)
static inline void dsi_exit(void)
{
}
static inline void dsi_wait_dsi1_pll_active(void)
{
}
static inline void dsi_wait_dsi2_pll_active(void)
{
}
#endif
/* DPI */

View file

@ -440,6 +440,10 @@ struct manager_cache_data {
/* manual update region */
u16 x, y, w, h;
/* enlarge the update area if the update area contains scaled
* overlays */
bool enlarge_update_area;
};
static struct {
@ -525,7 +529,7 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
int i;
struct omap_dss_device *dssdev = mgr->device;
if (!dssdev)
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0;
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
@ -596,11 +600,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
int r;
int i;
if (!ovl->manager || !ovl->manager->device)
if (!ovl->manager)
return 0;
dssdev = ovl->manager->device;
if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
return 0;
if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
channel = OMAP_DSS_CHANNEL_DIGIT;
@ -718,6 +725,7 @@ static int configure_overlay(enum omap_plane plane)
u16 x, y, w, h;
u32 paddr;
int r;
u16 orig_w, orig_h, orig_outw, orig_outh;
DSSDBGF("%d", plane);
@ -738,8 +746,16 @@ static int configure_overlay(enum omap_plane plane)
outh = c->out_height == 0 ? c->height : c->out_height;
paddr = c->paddr;
orig_w = w;
orig_h = h;
orig_outw = outw;
orig_outh = outh;
if (c->manual_update && mc->do_manual_update) {
unsigned bpp;
unsigned scale_x_m = w, scale_x_d = outw;
unsigned scale_y_m = h, scale_y_d = outh;
/* If the overlay is outside the update region, disable it */
if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
x, y, outw, outh)) {
@ -770,38 +786,47 @@ static int configure_overlay(enum omap_plane plane)
BUG();
}
if (dispc_is_overlay_scaled(c)) {
/* If the overlay is scaled, the update area has
* already been enlarged to cover the whole overlay. We
* only need to adjust x/y here */
x = c->pos_x - mc->x;
y = c->pos_y - mc->y;
if (mc->x > c->pos_x) {
x = 0;
outw -= (mc->x - c->pos_x);
paddr += (mc->x - c->pos_x) *
scale_x_m / scale_x_d * bpp / 8;
} else {
if (mc->x > c->pos_x) {
x = 0;
w -= (mc->x - c->pos_x);
paddr += (mc->x - c->pos_x) * bpp / 8;
} else {
x = c->pos_x - mc->x;
}
x = c->pos_x - mc->x;
}
if (mc->y > c->pos_y) {
y = 0;
h -= (mc->y - c->pos_y);
paddr += (mc->y - c->pos_y) * c->screen_width *
bpp / 8;
} else {
y = c->pos_y - mc->y;
}
if (mc->y > c->pos_y) {
y = 0;
outh -= (mc->y - c->pos_y);
paddr += (mc->y - c->pos_y) *
scale_y_m / scale_y_d *
c->screen_width * bpp / 8;
} else {
y = c->pos_y - mc->y;
}
if (mc->w < (x+w))
w -= (x+w) - (mc->w);
if (mc->w < (x + outw))
outw -= (x + outw) - (mc->w);
if (mc->h < (y+h))
h -= (y+h) - (mc->h);
if (mc->h < (y + outh))
outh -= (y + outh) - (mc->h);
outw = w;
outh = h;
w = w * outw / orig_outw;
h = h * outh / orig_outh;
/* YUV mode overlay's input width has to be even and the
* algorithm above may adjust the width to be odd.
*
* Here we adjust the width if needed, preferring to increase
* the width if the original width was bigger.
*/
if ((w & 1) &&
(c->color_mode == OMAP_DSS_COLOR_YUV2 ||
c->color_mode == OMAP_DSS_COLOR_UYVY)) {
if (orig_w > w)
w += 1;
else
w -= 1;
}
}
@ -960,7 +985,7 @@ static void make_even(u16 *x, u16 *w)
/* Configure dispc for partial update. Return possibly modified update
* area */
void dss_setup_partial_planes(struct omap_dss_device *dssdev,
u16 *xi, u16 *yi, u16 *wi, u16 *hi)
u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area)
{
struct overlay_cache_data *oc;
struct manager_cache_data *mc;
@ -969,6 +994,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
int i;
u16 x, y, w, h;
unsigned long flags;
bool area_changed;
x = *xi;
y = *yi;
@ -989,73 +1015,91 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev,
spin_lock_irqsave(&dss_cache.lock, flags);
/* We need to show the whole overlay if it is scaled. So look for
* those, and make the update area larger if found.
* Also mark the overlay cache dirty */
for (i = 0; i < num_ovls; ++i) {
unsigned x1, y1, x2, y2;
unsigned outw, outh;
/*
* Execute the outer loop until the inner loop has completed
* once without increasing the update area. This will ensure that
* all scaled overlays end up completely within the update area.
*/
do {
area_changed = false;
oc = &dss_cache.overlay_cache[i];
/* We need to show the whole overlay if it is scaled. So look
* for those, and make the update area larger if found.
* Also mark the overlay cache dirty */
for (i = 0; i < num_ovls; ++i) {
unsigned x1, y1, x2, y2;
unsigned outw, outh;
if (oc->channel != mgr->id)
continue;
oc = &dss_cache.overlay_cache[i];
oc->dirty = true;
if (oc->channel != mgr->id)
continue;
if (!oc->enabled)
continue;
oc->dirty = true;
if (!dispc_is_overlay_scaled(oc))
continue;
if (!enlarge_update_area)
continue;
outw = oc->out_width == 0 ? oc->width : oc->out_width;
outh = oc->out_height == 0 ? oc->height : oc->out_height;
if (!oc->enabled)
continue;
/* is the overlay outside the update region? */
if (!rectangle_intersects(x, y, w, h,
oc->pos_x, oc->pos_y,
outw, outh))
continue;
if (!dispc_is_overlay_scaled(oc))
continue;
/* if the overlay totally inside the update region? */
if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
x, y, w, h))
continue;
outw = oc->out_width == 0 ?
oc->width : oc->out_width;
outh = oc->out_height == 0 ?
oc->height : oc->out_height;
if (x > oc->pos_x)
x1 = oc->pos_x;
else
x1 = x;
/* is the overlay outside the update region? */
if (!rectangle_intersects(x, y, w, h,
oc->pos_x, oc->pos_y,
outw, outh))
continue;
if (y > oc->pos_y)
y1 = oc->pos_y;
else
y1 = y;
/* if the overlay totally inside the update region? */
if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
x, y, w, h))
continue;
if ((x + w) < (oc->pos_x + outw))
x2 = oc->pos_x + outw;
else
x2 = x + w;
if (x > oc->pos_x)
x1 = oc->pos_x;
else
x1 = x;
if ((y + h) < (oc->pos_y + outh))
y2 = oc->pos_y + outh;
else
y2 = y + h;
if (y > oc->pos_y)
y1 = oc->pos_y;
else
y1 = y;
x = x1;
y = y1;
w = x2 - x1;
h = y2 - y1;
if ((x + w) < (oc->pos_x + outw))
x2 = oc->pos_x + outw;
else
x2 = x + w;
make_even(&x, &w);
if ((y + h) < (oc->pos_y + outh))
y2 = oc->pos_y + outh;
else
y2 = y + h;
DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
x = x1;
y = y1;
w = x2 - x1;
h = y2 - y1;
make_even(&x, &w);
DSSDBG("changing upd area due to ovl(%d) "
"scaling %d,%d %dx%d\n",
i, x, y, w, h);
}
area_changed = true;
}
} while (area_changed);
mc = &dss_cache.manager_cache[mgr->id];
mc->do_manual_update = true;
mc->enlarge_update_area = enlarge_update_area;
mc->x = x;
mc->y = y;
mc->w = w;

View file

@ -65,7 +65,7 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
mgr = omap_dss_get_overlay_manager(i);
if (strncmp(buf, mgr->name, len) == 0)
if (sysfs_streq(buf, mgr->name))
break;
mgr = NULL;

View file

@ -886,7 +886,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev,
return -EINVAL;
if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
dss_setup_partial_planes(dssdev, x, y, w, h);
dss_setup_partial_planes(dssdev, x, y, w, h, true);
dispc_set_lcd_size(*w, *h);
}

View file

@ -34,12 +34,37 @@
#include "omapfb.h"
static u8 get_mem_idx(struct omapfb_info *ofbi)
{
if (ofbi->id == ofbi->region->id)
return 0;
return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id;
}
static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi,
u8 mem_idx)
{
struct omapfb2_device *fbdev = ofbi->fbdev;
if (mem_idx & OMAPFB_MEM_IDX_ENABLED)
mem_idx &= OMAPFB_MEM_IDX_MASK;
else
mem_idx = ofbi->id;
if (mem_idx >= fbdev->num_fbs)
return NULL;
return &fbdev->regions[mem_idx];
}
static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_overlay *ovl;
struct omap_overlay_info info;
struct omap_overlay_info old_info;
struct omapfb2_mem_region *old_rg, *new_rg;
int r = 0;
DBG("omapfb_setup_plane\n");
@ -52,36 +77,106 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
/* XXX uses only the first overlay */
ovl = ofbi->overlays[0];
if (pi->enabled && !ofbi->region.size) {
old_rg = ofbi->region;
new_rg = get_mem_region(ofbi, pi->mem_idx);
if (!new_rg) {
r = -EINVAL;
goto out;
}
/* Take the locks in a specific order to keep lockdep happy */
if (old_rg->id < new_rg->id) {
omapfb_get_mem_region(old_rg);
omapfb_get_mem_region(new_rg);
} else if (new_rg->id < old_rg->id) {
omapfb_get_mem_region(new_rg);
omapfb_get_mem_region(old_rg);
} else
omapfb_get_mem_region(old_rg);
if (pi->enabled && !new_rg->size) {
/*
* This plane's memory was freed, can't enable it
* until it's reallocated.
*/
r = -EINVAL;
goto out;
goto put_mem;
}
ovl->get_overlay_info(ovl, &info);
ovl->get_overlay_info(ovl, &old_info);
info.pos_x = pi->pos_x;
info.pos_y = pi->pos_y;
info.out_width = pi->out_width;
info.out_height = pi->out_height;
info.enabled = pi->enabled;
if (old_rg != new_rg) {
ofbi->region = new_rg;
set_fb_fix(fbi);
}
r = ovl->set_overlay_info(ovl, &info);
if (r)
goto out;
if (pi->enabled) {
struct omap_overlay_info info;
if (ovl->manager) {
r = ovl->manager->apply(ovl->manager);
r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,
pi->out_width, pi->out_height);
if (r)
goto out;
goto undo;
ovl->get_overlay_info(ovl, &info);
if (!info.enabled) {
info.enabled = pi->enabled;
r = ovl->set_overlay_info(ovl, &info);
if (r)
goto undo;
}
} else {
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
info.enabled = pi->enabled;
info.pos_x = pi->pos_x;
info.pos_y = pi->pos_y;
info.out_width = pi->out_width;
info.out_height = pi->out_height;
r = ovl->set_overlay_info(ovl, &info);
if (r)
goto undo;
}
out:
if (r)
dev_err(fbdev->dev, "setup_plane failed\n");
if (ovl->manager)
ovl->manager->apply(ovl->manager);
/* Release the locks in a specific order to keep lockdep happy */
if (old_rg->id > new_rg->id) {
omapfb_put_mem_region(old_rg);
omapfb_put_mem_region(new_rg);
} else if (new_rg->id > old_rg->id) {
omapfb_put_mem_region(new_rg);
omapfb_put_mem_region(old_rg);
} else
omapfb_put_mem_region(old_rg);
return 0;
undo:
if (old_rg != new_rg) {
ofbi->region = old_rg;
set_fb_fix(fbi);
}
ovl->set_overlay_info(ovl, &old_info);
put_mem:
/* Release the locks in a specific order to keep lockdep happy */
if (old_rg->id > new_rg->id) {
omapfb_put_mem_region(old_rg);
omapfb_put_mem_region(new_rg);
} else if (new_rg->id > old_rg->id) {
omapfb_put_mem_region(new_rg);
omapfb_put_mem_region(old_rg);
} else
omapfb_put_mem_region(old_rg);
out:
dev_err(fbdev->dev, "setup_plane failed\n");
return r;
}
@ -92,8 +187,8 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
if (ofbi->num_overlays != 1) {
memset(pi, 0, sizeof(*pi));
} else {
struct omap_overlay_info *ovli;
struct omap_overlay *ovl;
struct omap_overlay_info *ovli;
ovl = ofbi->overlays[0];
ovli = &ovl->info;
@ -103,6 +198,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
pi->enabled = ovli->enabled;
pi->channel_out = 0; /* xxx */
pi->mirror = 0;
pi->mem_idx = get_mem_idx(ofbi);
pi->out_width = ovli->out_width;
pi->out_height = ovli->out_height;
}
@ -115,7 +211,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg;
int r, i;
int r = 0, i;
size_t size;
if (mi->type > OMAPFB_MEMTYPE_MAX)
@ -123,22 +219,44 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
size = PAGE_ALIGN(mi->size);
rg = &ofbi->region;
rg = ofbi->region;
for (i = 0; i < ofbi->num_overlays; i++) {
if (ofbi->overlays[i]->info.enabled)
return -EBUSY;
down_write_nested(&rg->lock, rg->id);
atomic_inc(&rg->lock_count);
if (atomic_read(&rg->map_count)) {
r = -EBUSY;
goto out;
}
for (i = 0; i < fbdev->num_fbs; i++) {
struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
int j;
if (ofbi2->region != rg)
continue;
for (j = 0; j < ofbi2->num_overlays; j++) {
if (ofbi2->overlays[j]->info.enabled) {
r = -EBUSY;
goto out;
}
}
}
if (rg->size != size || rg->type != mi->type) {
r = omapfb_realloc_fbmem(fbi, size, mi->type);
if (r) {
dev_err(fbdev->dev, "realloc fbmem failed\n");
return r;
goto out;
}
}
return 0;
out:
atomic_dec(&rg->lock_count);
up_write(&rg->lock);
return r;
}
static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
@ -146,12 +264,14 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg;
rg = &ofbi->region;
rg = omapfb_get_mem_region(ofbi->region);
memset(mi, 0, sizeof(*mi));
mi->size = rg->size;
mi->type = rg->type;
omapfb_put_mem_region(rg);
return 0;
}
@ -490,6 +610,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
struct omapfb_vram_info vram_info;
struct omapfb_tearsync_info tearsync_info;
struct omapfb_display_info display_info;
u32 crt;
} p;
int r = 0;
@ -648,6 +769,17 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
r = -EFAULT;
break;
case FBIO_WAITFORVSYNC:
if (get_user(p.crt, (__u32 __user *)arg)) {
r = -EFAULT;
break;
}
if (p.crt != 0) {
r = -ENODEV;
break;
}
/* FALLTHROUGH */
case OMAPFB_WAITFORVSYNC:
DBG("ioctl WAITFORVSYNC\n");
if (!display) {
@ -738,7 +870,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
break;
}
if (!display->driver->enable_te) {
if (!display || !display->driver->enable_te) {
r = -ENODEV;
break;
}

View file

@ -157,7 +157,7 @@ static void fill_fb(struct fb_info *fbi)
static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
{
const struct vrfb *vrfb = &ofbi->region.vrfb;
const struct vrfb *vrfb = &ofbi->region->vrfb;
unsigned offset;
switch (rot) {
@ -185,27 +185,27 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot)
static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
return ofbi->region.vrfb.paddr[rot]
return ofbi->region->vrfb.paddr[rot]
+ omapfb_get_vrfb_offset(ofbi, rot);
} else {
return ofbi->region.paddr;
return ofbi->region->paddr;
}
}
static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.paddr[0];
return ofbi->region->vrfb.paddr[0];
else
return ofbi->region.paddr;
return ofbi->region->paddr;
}
static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi)
{
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
return ofbi->region.vrfb.vaddr[0];
return ofbi->region->vrfb.vaddr[0];
else
return ofbi->region.vaddr;
return ofbi->region->vaddr;
}
static struct omapfb_colormode omapfb_colormodes[] = {
@ -450,7 +450,7 @@ static int check_vrfb_fb_size(unsigned long region_size,
static int check_fb_size(const struct omapfb_info *ofbi,
struct fb_var_screeninfo *var)
{
unsigned long max_frame_size = ofbi->region.size;
unsigned long max_frame_size = ofbi->region->size;
int bytespp = var->bits_per_pixel >> 3;
unsigned long line_size = var->xres_virtual * bytespp;
@ -497,7 +497,7 @@ static int check_fb_size(const struct omapfb_info *ofbi,
static int setup_vrfb_rotation(struct fb_info *fbi)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg = &ofbi->region;
struct omapfb2_mem_region *rg = ofbi->region;
struct vrfb *vrfb = &rg->vrfb;
struct fb_var_screeninfo *var = &fbi->var;
struct fb_fix_screeninfo *fix = &fbi->fix;
@ -558,9 +558,9 @@ static int setup_vrfb_rotation(struct fb_info *fbi)
return r;
/* used by open/write in fbmem.c */
fbi->screen_base = ofbi->region.vrfb.vaddr[0];
fbi->screen_base = ofbi->region->vrfb.vaddr[0];
fix->smem_start = ofbi->region.vrfb.paddr[0];
fix->smem_start = ofbi->region->vrfb.paddr[0];
switch (var->nonstd) {
case OMAPFB_COLOR_YUV422:
@ -599,7 +599,7 @@ void set_fb_fix(struct fb_info *fbi)
struct fb_fix_screeninfo *fix = &fbi->fix;
struct fb_var_screeninfo *var = &fbi->var;
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg = &ofbi->region;
struct omapfb2_mem_region *rg = ofbi->region;
DBG("set_fb_fix\n");
@ -668,8 +668,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
DBG("check_fb_var %d\n", ofbi->id);
if (ofbi->region.size == 0)
return 0;
WARN_ON(!atomic_read(&ofbi->region->lock_count));
r = fb_mode_to_dss_mode(var, &mode);
if (r) {
@ -684,13 +683,14 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
}
}
if (var->rotate < 0 || var->rotate > 3)
if (var->rotate > 3)
return -EINVAL;
if (check_fb_res_bounds(var))
return -EINVAL;
if (check_fb_size(ofbi, var))
/* When no memory is allocated ignore the size check */
if (ofbi->region->size != 0 && check_fb_size(ofbi, var))
return -EINVAL;
if (var->xres + var->xoffset > var->xres_virtual)
@ -822,9 +822,43 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var,
return offset;
}
static void omapfb_calc_addr(const struct omapfb_info *ofbi,
const struct fb_var_screeninfo *var,
const struct fb_fix_screeninfo *fix,
int rotation, u32 *paddr, void __iomem **vaddr)
{
u32 data_start_p;
void __iomem *data_start_v;
int offset;
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
data_start_v = NULL;
} else {
data_start_p = omapfb_get_region_paddr(ofbi);
data_start_v = omapfb_get_region_vaddr(ofbi);
}
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
offset = calc_rotation_offset_vrfb(var, fix, rotation);
else
offset = calc_rotation_offset_dma(var, fix, rotation);
data_start_p += offset;
data_start_v += offset;
if (offset)
DBG("offset %d, %d = %d\n",
var->xoffset, var->yoffset, offset);
DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
*paddr = data_start_p;
*vaddr = data_start_v;
}
/* setup overlay according to the fb */
static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
u16 posx, u16 posy, u16 outw, u16 outh)
{
int r = 0;
@ -832,9 +866,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
struct fb_var_screeninfo *var = &fbi->var;
struct fb_fix_screeninfo *fix = &fbi->fix;
enum omap_color_mode mode = 0;
int offset;
u32 data_start_p;
void __iomem *data_start_v;
u32 data_start_p = 0;
void __iomem *data_start_v = NULL;
struct omap_overlay_info info;
int xres, yres;
int screen_width;
@ -842,6 +875,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
int rotation = var->rotate;
int i;
WARN_ON(!atomic_read(&ofbi->region->lock_count));
for (i = 0; i < ofbi->num_overlays; i++) {
if (ovl != ofbi->overlays[i])
continue;
@ -861,28 +896,9 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
yres = var->yres;
}
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
data_start_v = NULL;
} else {
data_start_p = omapfb_get_region_paddr(ofbi);
data_start_v = omapfb_get_region_vaddr(ofbi);
}
if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
offset = calc_rotation_offset_vrfb(var, fix, rotation);
else
offset = calc_rotation_offset_dma(var, fix, rotation);
data_start_p += offset;
data_start_v += offset;
if (offset)
DBG("offset %d, %d = %d\n",
var->xoffset, var->yoffset, offset);
DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
if (ofbi->region->size)
omapfb_calc_addr(ofbi, var, fix, rotation,
&data_start_p, &data_start_v);
r = fb_mode_to_dss_mode(var, &mode);
if (r) {
@ -954,12 +970,14 @@ int omapfb_apply_changes(struct fb_info *fbi, int init)
fill_fb(fbi);
#endif
WARN_ON(!atomic_read(&ofbi->region->lock_count));
for (i = 0; i < ofbi->num_overlays; i++) {
ovl = ofbi->overlays[i];
DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
if (ofbi->region.size == 0) {
if (ofbi->region->size == 0) {
/* the fb is not available. disable the overlay */
omapfb_overlay_enable(ovl, 0);
if (!init && ovl->manager)
@ -1007,36 +1025,48 @@ err:
* DO NOT MODIFY PAR */
static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
int r;
DBG("check_var(%d)\n", FB2OFB(fbi)->id);
omapfb_get_mem_region(ofbi->region);
r = check_fb_var(fbi, var);
omapfb_put_mem_region(ofbi->region);
return r;
}
/* set the video mode according to info->var */
static int omapfb_set_par(struct fb_info *fbi)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
int r;
DBG("set_par(%d)\n", FB2OFB(fbi)->id);
omapfb_get_mem_region(ofbi->region);
set_fb_fix(fbi);
r = setup_vrfb_rotation(fbi);
if (r)
return r;
goto out;
r = omapfb_apply_changes(fbi, 0);
out:
omapfb_put_mem_region(ofbi->region);
return r;
}
static int omapfb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *fbi)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_var_screeninfo new_var;
int r;
@ -1052,23 +1082,31 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var,
fbi->var = new_var;
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 0);
omapfb_put_mem_region(ofbi->region);
return r;
}
static void mmap_user_open(struct vm_area_struct *vma)
{
struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
struct omapfb2_mem_region *rg = vma->vm_private_data;
atomic_inc(&ofbi->map_count);
omapfb_get_mem_region(rg);
atomic_inc(&rg->map_count);
omapfb_put_mem_region(rg);
}
static void mmap_user_close(struct vm_area_struct *vma)
{
struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
struct omapfb2_mem_region *rg = vma->vm_private_data;
atomic_dec(&ofbi->map_count);
omapfb_get_mem_region(rg);
atomic_dec(&rg->map_count);
omapfb_put_mem_region(rg);
}
static struct vm_operations_struct mmap_user_ops = {
@ -1080,9 +1118,11 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
{
struct omapfb_info *ofbi = FB2OFB(fbi);
struct fb_fix_screeninfo *fix = &fbi->fix;
struct omapfb2_mem_region *rg;
unsigned long off;
unsigned long start;
u32 len;
int r = -EINVAL;
if (vma->vm_end - vma->vm_start == 0)
return 0;
@ -1090,12 +1130,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return -EINVAL;
off = vma->vm_pgoff << PAGE_SHIFT;
rg = omapfb_get_mem_region(ofbi->region);
start = omapfb_get_region_paddr(ofbi);
len = fix->smem_len;
if (off >= len)
return -EINVAL;
goto error;
if ((vma->vm_end - vma->vm_start + off) > len)
return -EINVAL;
goto error;
off += start;
@ -1105,13 +1147,25 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
vma->vm_flags |= VM_IO | VM_RESERVED;
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_ops = &mmap_user_ops;
vma->vm_private_data = ofbi;
vma->vm_private_data = rg;
if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
vma->vm_end - vma->vm_start,
vma->vm_page_prot)) {
r = -EAGAIN;
goto error;
}
/* vm_ops.open won't be called for mmap itself. */
atomic_inc(&ofbi->map_count);
atomic_inc(&rg->map_count);
omapfb_put_mem_region(rg);
return 0;
error:
omapfb_put_mem_region(ofbi->region);
return r;
}
/* Store a single color palette entry into a pseudo palette or the hardware
@ -1154,11 +1208,6 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
if (r != 0)
break;
if (regno < 0) {
r = -EINVAL;
break;
}
if (regno < 16) {
u16 pal;
pal = ((red >> (16 - var->red.length)) <<
@ -1217,6 +1266,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi)
int do_update = 0;
int r = 0;
if (!display)
return -EINVAL;
omapfb_lock(fbdev);
switch (blank) {
@ -1300,7 +1352,9 @@ static void omapfb_free_fbmem(struct fb_info *fbi)
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg;
rg = &ofbi->region;
rg = ofbi->region;
WARN_ON(atomic_read(&rg->map_count));
if (rg->paddr)
if (omap_vram_free(rg->paddr, rg->size))
@ -1355,8 +1409,15 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
void __iomem *vaddr;
int r;
rg = &ofbi->region;
memset(rg, 0, sizeof(*rg));
rg = ofbi->region;
rg->paddr = 0;
rg->vaddr = NULL;
memset(&rg->vrfb, 0, sizeof rg->vrfb);
rg->size = 0;
rg->type = 0;
rg->alloc = false;
rg->map = false;
size = PAGE_ALIGN(size);
@ -1609,7 +1670,7 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
for (i = 0; i < fbdev->num_fbs; i++) {
struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
struct omapfb2_mem_region *rg;
rg = &ofbi->region;
rg = ofbi->region;
DBG("region%d phys %08x virt %p size=%lu\n",
i,
@ -1626,7 +1687,7 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omap_dss_device *display = fb2display(fbi);
struct omapfb2_mem_region *rg = &ofbi->region;
struct omapfb2_mem_region *rg = ofbi->region;
unsigned long old_size = rg->size;
unsigned long old_paddr = rg->paddr;
int old_type = rg->type;
@ -1709,7 +1770,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
fbi->flags = FBINFO_FLAG_DEFAULT;
fbi->pseudo_palette = fbdev->pseudo_palette;
if (ofbi->region.size == 0) {
if (ofbi->region->size == 0) {
clear_fb_info(fbi);
return 0;
}
@ -1871,6 +1932,10 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
ofbi->fbdev = fbdev;
ofbi->id = i;
ofbi->region = &fbdev->regions[i];
ofbi->region->id = i;
init_rwsem(&ofbi->region->lock);
/* assign these early, so that fb alloc can use them */
ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
OMAP_DSS_ROT_DMA;
@ -1900,7 +1965,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
/* setup fb_infos */
for (i = 0; i < fbdev->num_fbs; i++) {
r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
struct fb_info *fbi = fbdev->fbs[i];
struct omapfb_info *ofbi = FB2OFB(fbi);
omapfb_get_mem_region(ofbi->region);
r = omapfb_fb_init(fbdev, fbi);
omapfb_put_mem_region(ofbi->region);
if (r) {
dev_err(fbdev->dev, "failed to setup fb_info\n");
return r;
@ -1921,20 +1992,19 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
DBG("framebuffers registered\n");
for (i = 0; i < fbdev->num_fbs; i++) {
r = omapfb_apply_changes(fbdev->fbs[i], 1);
struct fb_info *fbi = fbdev->fbs[i];
struct omapfb_info *ofbi = FB2OFB(fbi);
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 1);
omapfb_put_mem_region(ofbi->region);
if (r) {
dev_err(fbdev->dev, "failed to change mode\n");
return r;
}
}
DBG("create sysfs for fbs\n");
r = omapfb_create_sysfs(fbdev);
if (r) {
dev_err(fbdev->dev, "failed to create sysfs entries\n");
return r;
}
/* Enable fb0 */
if (fbdev->num_fbs > 0) {
struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
@ -1968,11 +2038,11 @@ static int omapfb_mode_to_timings(const char *mode_str,
#ifdef CONFIG_OMAP2_DSS_VENC
if (strcmp(mode_str, "pal") == 0) {
*timings = omap_dss_pal_timings;
*bpp = 0;
*bpp = 24;
return 0;
} else if (strcmp(mode_str, "ntsc") == 0) {
*timings = omap_dss_ntsc_timings;
*bpp = 0;
*bpp = 24;
return 0;
}
#endif
@ -2220,6 +2290,13 @@ static int omapfb_probe(struct platform_device *pdev)
}
}
DBG("create sysfs for fbs\n");
r = omapfb_create_sysfs(fbdev);
if (r) {
dev_err(fbdev->dev, "failed to create sysfs entries\n");
goto cleanup;
}
return 0;
cleanup:

View file

@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev,
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_mem_region *rg;
enum omap_dss_rotation_type rot_type;
int r;
@ -64,9 +65,11 @@ static ssize_t store_rotate_type(struct device *dev,
if (rot_type == ofbi->rotation_type)
goto out;
if (ofbi->region.size) {
rg = omapfb_get_mem_region(ofbi->region);
if (rg->size) {
r = -EBUSY;
goto out;
goto put_region;
}
ofbi->rotation_type = rot_type;
@ -75,6 +78,8 @@ static ssize_t store_rotate_type(struct device *dev,
* Since the VRAM for this FB is not allocated at the moment we don't
* need to do any further parameter checking at this point.
*/
put_region:
omapfb_put_mem_region(rg);
out:
unlock_fb_info(fbi);
@ -97,7 +102,7 @@ static ssize_t store_mirror(struct device *dev,
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
bool mirror;
unsigned long mirror;
int r;
struct fb_var_screeninfo new_var;
@ -111,6 +116,8 @@ static ssize_t store_mirror(struct device *dev,
ofbi->mirror = mirror;
omapfb_get_mem_region(ofbi->region);
memcpy(&new_var, &fbi->var, sizeof(new_var));
r = check_fb_var(fbi, &new_var);
if (r)
@ -125,6 +132,8 @@ static ssize_t store_mirror(struct device *dev,
r = count;
out:
omapfb_put_mem_region(ofbi->region);
unlock_fb_info(fbi);
return r;
@ -263,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
DBG("detaching %d\n", ofbi->overlays[i]->id);
omapfb_get_mem_region(ofbi->region);
omapfb_overlay_enable(ovl, 0);
if (ovl->manager)
ovl->manager->apply(ovl->manager);
omapfb_put_mem_region(ofbi->region);
for (t = i + 1; t < ofbi->num_overlays; t++) {
ofbi->rotation[t-1] = ofbi->rotation[t];
ofbi->overlays[t-1] = ofbi->overlays[t];
@ -300,7 +313,12 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
}
if (added) {
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 0);
omapfb_put_mem_region(ofbi->region);
if (r)
goto out;
}
@ -388,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev,
for (i = 0; i < num_ovls; ++i)
ofbi->rotation[i] = rotation[i];
omapfb_get_mem_region(ofbi->region);
r = omapfb_apply_changes(fbi, 0);
omapfb_put_mem_region(ofbi->region);
if (r)
goto out;
@ -408,7 +431,7 @@ static ssize_t show_size(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
}
static ssize_t store_size(struct device *dev, struct device_attribute *attr,
@ -416,6 +439,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
{
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
struct omapfb2_device *fbdev = ofbi->fbdev;
struct omapfb2_mem_region *rg;
unsigned long size;
int r;
int i;
@ -425,15 +450,33 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
if (!lock_fb_info(fbi))
return -ENODEV;
for (i = 0; i < ofbi->num_overlays; i++) {
if (ofbi->overlays[i]->info.enabled) {
r = -EBUSY;
goto out;
rg = ofbi->region;
down_write_nested(&rg->lock, rg->id);
atomic_inc(&rg->lock_count);
if (atomic_read(&rg->map_count)) {
r = -EBUSY;
goto out;
}
for (i = 0; i < fbdev->num_fbs; i++) {
struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
int j;
if (ofbi2->region != rg)
continue;
for (j = 0; j < ofbi2->num_overlays; j++) {
if (ofbi2->overlays[j]->info.enabled) {
r = -EBUSY;
goto out;
}
}
}
if (size != ofbi->region.size) {
r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
if (size != ofbi->region->size) {
r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
if (r) {
dev_err(dev, "realloc fbmem failed\n");
goto out;
@ -442,6 +485,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,
r = count;
out:
atomic_dec(&rg->lock_count);
up_write(&rg->lock);
unlock_fb_info(fbi);
return r;
@ -453,7 +499,7 @@ static ssize_t show_phys(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
}
static ssize_t show_virt(struct device *dev,
@ -462,7 +508,7 @@ static ssize_t show_virt(struct device *dev,
struct fb_info *fbi = dev_get_drvdata(dev);
struct omapfb_info *ofbi = FB2OFB(fbi);
return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
}
static struct device_attribute omapfb_attrs[] = {

View file

@ -27,6 +27,8 @@
#define DEBUG
#endif
#include <linux/rwsem.h>
#include <plat/display.h>
#ifdef DEBUG
@ -44,6 +46,7 @@ extern unsigned int omapfb_debug;
#define OMAPFB_MAX_OVL_PER_FB 3
struct omapfb2_mem_region {
int id;
u32 paddr;
void __iomem *vaddr;
struct vrfb vrfb;
@ -51,13 +54,15 @@ struct omapfb2_mem_region {
u8 type; /* OMAPFB_PLANE_MEM_* */
bool alloc; /* allocated by the driver */
bool map; /* kernel mapped by the driver */
atomic_t map_count;
struct rw_semaphore lock;
atomic_t lock_count;
};
/* appended to fb_info */
struct omapfb_info {
int id;
struct omapfb2_mem_region region;
atomic_t map_count;
struct omapfb2_mem_region *region;
int num_overlays;
struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
struct omapfb2_device *fbdev;
@ -76,6 +81,7 @@ struct omapfb2_device {
unsigned num_fbs;
struct fb_info *fbs[10];
struct omapfb2_mem_region regions[10];
unsigned num_displays;
struct omap_dss_device *displays[10];
@ -117,6 +123,9 @@ int omapfb_update_window(struct fb_info *fbi,
int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
struct fb_var_screeninfo *var);
int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
u16 posx, u16 posy, u16 outw, u16 outh);
/* find the display connected to this fb, if any */
static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
{
@ -148,8 +157,24 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
struct omap_overlay_info info;
ovl->get_overlay_info(ovl, &info);
if (info.enabled == enable)
return 0;
info.enabled = enable;
return ovl->set_overlay_info(ovl, &info);
}
static inline struct omapfb2_mem_region *
omapfb_get_mem_region(struct omapfb2_mem_region *rg)
{
down_read_nested(&rg->lock, rg->id);
atomic_inc(&rg->lock_count);
return rg;
}
static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg)
{
atomic_dec(&rg->lock_count);
up_read(&rg->lock);
}
#endif

View file

@ -249,7 +249,7 @@ static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_no
info->fix.accel = FB_ACCEL_SUN_CGTHREE;
}
static int __devinit p9100_probe(struct of_device *op, const struct of_device_id *match)
static int __devinit p9100_probe(struct platform_device *op, const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
struct fb_info *info;
@ -326,7 +326,7 @@ out_err:
return err;
}
static int __devexit p9100_remove(struct of_device *op)
static int __devexit p9100_remove(struct platform_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
struct p9100_par *par = info->par;
@ -367,12 +367,12 @@ static int __init p9100_init(void)
if (fb_get_options("p9100fb", NULL))
return -ENODEV;
return of_register_driver(&p9100_driver, &of_bus_type);
return of_register_platform_driver(&p9100_driver);
}
static void __exit p9100_exit(void)
{
of_unregister_driver(&p9100_driver);
of_unregister_platform_driver(&p9100_driver);
}
module_init(p9100_init);

View file

@ -533,7 +533,7 @@ static int __init platinumfb_setup(char *options)
#define invalidate_cache(addr)
#endif
static int __devinit platinumfb_probe(struct of_device* odev,
static int __devinit platinumfb_probe(struct platform_device* odev,
const struct of_device_id *match)
{
struct device_node *dp = odev->dev.of_node;
@ -646,7 +646,7 @@ static int __devinit platinumfb_probe(struct of_device* odev,
return rc;
}
static int __devexit platinumfb_remove(struct of_device* odev)
static int __devexit platinumfb_remove(struct platform_device* odev)
{
struct fb_info *info = dev_get_drvdata(&odev->dev);
struct fb_info_platinum *pinfo = info->par;

File diff suppressed because it is too large Load diff

505
drivers/video/sh_mipi_dsi.c Normal file
View file

@ -0,0 +1,505 @@
/*
* Renesas SH-mobile MIPI DSI support
*
* Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
* This is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
#include <video/mipi_display.h>
#include <video/sh_mipi_dsi.h>
#include <video/sh_mobile_lcdc.h>
#define CMTSRTCTR 0x80d0
#define CMTSRTREQ 0x8070
#define DSIINTE 0x0060
/* E.g., sh7372 has 2 MIPI-DSIs - one for each LCDC */
#define MAX_SH_MIPI_DSI 2
struct sh_mipi {
void __iomem *base;
struct clk *dsit_clk;
struct clk *dsip_clk;
};
static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI];
/* Protect the above array */
static DEFINE_MUTEX(array_lock);
static struct sh_mipi *sh_mipi_by_handle(int handle)
{
if (handle >= ARRAY_SIZE(mipi_dsi) || handle < 0)
return NULL;
return mipi_dsi[handle];
}
static int sh_mipi_send_short(struct sh_mipi *mipi, u8 dsi_cmd,
u8 cmd, u8 param)
{
u32 data = (dsi_cmd << 24) | (cmd << 16) | (param << 8);
int cnt = 100;
/* transmit a short packet to LCD panel */
iowrite32(1 | data, mipi->base + 0x80d0); /* CMTSRTCTR */
iowrite32(1, mipi->base + 0x8070); /* CMTSRTREQ */
while ((ioread32(mipi->base + 0x8070) & 1) && --cnt)
udelay(1);
return cnt ? 0 : -ETIMEDOUT;
}
#define LCD_CHAN2MIPI(c) ((c) < LCDC_CHAN_MAINLCD || (c) > LCDC_CHAN_SUBLCD ? \
-EINVAL : (c) - 1)
static int sh_mipi_dcs(int handle, u8 cmd)
{
struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
if (!mipi)
return -ENODEV;
return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE, cmd, 0);
}
static int sh_mipi_dcs_param(int handle, u8 cmd, u8 param)
{
struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
if (!mipi)
return -ENODEV;
return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd,
param);
}
static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable)
{
/*
* enable LCDC data tx, transition to LPS after completion of each HS
* packet
*/
iowrite32(0x00000002 | enable, mipi->base + 0x8000); /* DTCTR */
}
static void sh_mipi_shutdown(struct platform_device *pdev)
{
struct sh_mipi *mipi = platform_get_drvdata(pdev);
sh_mipi_dsi_enable(mipi, false);
}
static void mipi_display_on(void *arg, struct fb_info *info)
{
struct sh_mipi *mipi = arg;
sh_mipi_dsi_enable(mipi, true);
}
static void mipi_display_off(void *arg)
{
struct sh_mipi *mipi = arg;
sh_mipi_dsi_enable(mipi, false);
}
static int __init sh_mipi_setup(struct sh_mipi *mipi,
struct sh_mipi_dsi_info *pdata)
{
void __iomem *base = mipi->base;
struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan;
u32 pctype, datatype, pixfmt;
u32 linelength;
bool yuv;
/* Select data format */
switch (pdata->data_format) {
case MIPI_RGB888:
pctype = 0;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
linelength = ch->lcd_cfg.xres * 3;
yuv = false;
break;
case MIPI_RGB565:
pctype = 1;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
linelength = ch->lcd_cfg.xres * 2;
yuv = false;
break;
case MIPI_RGB666_LP:
pctype = 2;
datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
linelength = ch->lcd_cfg.xres * 3;
yuv = false;
break;
case MIPI_RGB666:
pctype = 3;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
linelength = (ch->lcd_cfg.xres * 18 + 7) / 8;
yuv = false;
break;
case MIPI_BGR888:
pctype = 8;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
linelength = ch->lcd_cfg.xres * 3;
yuv = false;
break;
case MIPI_BGR565:
pctype = 9;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
linelength = ch->lcd_cfg.xres * 2;
yuv = false;
break;
case MIPI_BGR666_LP:
pctype = 0xa;
datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
linelength = ch->lcd_cfg.xres * 3;
yuv = false;
break;
case MIPI_BGR666:
pctype = 0xb;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
linelength = (ch->lcd_cfg.xres * 18 + 7) / 8;
yuv = false;
break;
case MIPI_YUYV:
pctype = 4;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
linelength = ch->lcd_cfg.xres * 2;
yuv = true;
break;
case MIPI_UYVY:
pctype = 5;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
linelength = ch->lcd_cfg.xres * 2;
yuv = true;
break;
case MIPI_YUV420_L:
pctype = 6;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
linelength = (ch->lcd_cfg.xres * 12 + 7) / 8;
yuv = true;
break;
case MIPI_YUV420:
pctype = 7;
datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
/* Length of U/V line */
linelength = (ch->lcd_cfg.xres + 1) / 2;
yuv = true;
break;
default:
return -EINVAL;
}
if ((yuv && ch->interface_type != YUV422) ||
(!yuv && ch->interface_type != RGB24))
return -EINVAL;
/* reset DSI link */
iowrite32(0x00000001, base); /* SYSCTRL */
/* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */
udelay(50);
iowrite32(0x00000000, base); /* SYSCTRL */
/* setup DSI link */
/*
* Default = ULPS enable |
* Contention detection enabled |
* EoT packet transmission enable |
* CRC check enable |
* ECC check enable
* additionally enable first two lanes
*/
iowrite32(0x00003703, base + 0x04); /* SYSCONF */
/*
* T_wakeup = 0x7000
* T_hs-trail = 3
* T_hs-prepare = 3
* T_clk-trail = 3
* T_clk-prepare = 2
*/
iowrite32(0x70003332, base + 0x08); /* TIMSET */
/* no responses requested */
iowrite32(0x00000000, base + 0x18); /* RESREQSET0 */
/* request response to packets of type 0x28 */
iowrite32(0x00000100, base + 0x1c); /* RESREQSET1 */
/* High-speed transmission timeout, default 0xffffffff */
iowrite32(0x0fffffff, base + 0x20); /* HSTTOVSET */
/* LP reception timeout, default 0xffffffff */
iowrite32(0x0fffffff, base + 0x24); /* LPRTOVSET */
/* Turn-around timeout, default 0xffffffff */
iowrite32(0x0fffffff, base + 0x28); /* TATOVSET */
/* Peripheral reset timeout, default 0xffffffff */
iowrite32(0x0fffffff, base + 0x2c); /* PRTOVSET */
/* Enable timeout counters */
iowrite32(0x00000f00, base + 0x30); /* DSICTRL */
/* Interrupts not used, disable all */
iowrite32(0, base + DSIINTE);
/* DSI-Tx bias on */
iowrite32(0x00000001, base + 0x70); /* PHYCTRL */
udelay(200);
/* Deassert resets, power on, set multiplier */
iowrite32(0x03070b01, base + 0x70); /* PHYCTRL */
/* setup l-bridge */
/*
* Enable transmission of all packets,
* transmit LPS after each HS packet completion
*/
iowrite32(0x00000006, base + 0x8000); /* DTCTR */
/* VSYNC width = 2 (<< 17) */
iowrite32(0x00040000 | (pctype << 12) | datatype, base + 0x8020); /* VMCTR1 */
/*
* Non-burst mode with sync pulses: VSE and HSE are output,
* HSA period allowed, no commands in LP
*/
iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */
/*
* 0x660 = 1632 bytes per line (RGB24, 544 pixels: see
* sh_mobile_lcdc_info.ch[0].lcd_cfg.xres), HSALEN = 1 - default
* (unused, since VMCTR2[HSABM] = 0)
*/
iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */
msleep(5);
/* setup LCD panel */
/* cf. drivers/video/omap/lcd_mipid.c */
sh_mipi_dcs(ch->chan, MIPI_DCS_EXIT_SLEEP_MODE);
msleep(120);
/*
* [7] - Page Address Mode
* [6] - Column Address Mode
* [5] - Page / Column Address Mode
* [4] - Display Device Line Refresh Order
* [3] - RGB/BGR Order
* [2] - Display Data Latch Data Order
* [1] - Flip Horizontal
* [0] - Flip Vertical
*/
sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
/* cf. set_data_lines() */
sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_PIXEL_FORMAT,
pixfmt << 4);
sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON);
return 0;
}
static int __init sh_mipi_probe(struct platform_device *pdev)
{
struct sh_mipi *mipi;
struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
unsigned long rate, f_current;
int idx = pdev->id, ret;
char dsip_clk[] = "dsi.p_clk";
if (!res || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
return -ENODEV;
mutex_lock(&array_lock);
if (idx < 0)
for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++)
;
if (idx == ARRAY_SIZE(mipi_dsi)) {
ret = -EBUSY;
goto efindslot;
}
mipi = kzalloc(sizeof(*mipi), GFP_KERNEL);
if (!mipi) {
ret = -ENOMEM;
goto ealloc;
}
if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
dev_err(&pdev->dev, "MIPI register region already claimed\n");
ret = -EBUSY;
goto ereqreg;
}
mipi->base = ioremap(res->start, resource_size(res));
if (!mipi->base) {
ret = -ENOMEM;
goto emap;
}
mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk");
if (IS_ERR(mipi->dsit_clk)) {
ret = PTR_ERR(mipi->dsit_clk);
goto eclktget;
}
f_current = clk_get_rate(mipi->dsit_clk);
/* 80MHz required by the datasheet */
rate = clk_round_rate(mipi->dsit_clk, 80000000);
if (rate > 0 && rate != f_current)
ret = clk_set_rate(mipi->dsit_clk, rate);
else
ret = rate;
if (ret < 0)
goto esettrate;
dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate);
sprintf(dsip_clk, "dsi%1.1dp_clk", idx);
mipi->dsip_clk = clk_get(&pdev->dev, dsip_clk);
if (IS_ERR(mipi->dsip_clk)) {
ret = PTR_ERR(mipi->dsip_clk);
goto eclkpget;
}
f_current = clk_get_rate(mipi->dsip_clk);
/* Between 10 and 50MHz */
rate = clk_round_rate(mipi->dsip_clk, 24000000);
if (rate > 0 && rate != f_current)
ret = clk_set_rate(mipi->dsip_clk, rate);
else
ret = rate;
if (ret < 0)
goto esetprate;
dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate);
msleep(10);
ret = clk_enable(mipi->dsit_clk);
if (ret < 0)
goto eclkton;
ret = clk_enable(mipi->dsip_clk);
if (ret < 0)
goto eclkpon;
mipi_dsi[idx] = mipi;
ret = sh_mipi_setup(mipi, pdata);
if (ret < 0)
goto emipisetup;
mutex_unlock(&array_lock);
platform_set_drvdata(pdev, mipi);
/* Set up LCDC callbacks */
pdata->lcd_chan->board_cfg.board_data = mipi;
pdata->lcd_chan->board_cfg.display_on = mipi_display_on;
pdata->lcd_chan->board_cfg.display_off = mipi_display_off;
return 0;
emipisetup:
mipi_dsi[idx] = NULL;
clk_disable(mipi->dsip_clk);
eclkpon:
clk_disable(mipi->dsit_clk);
eclkton:
esetprate:
clk_put(mipi->dsip_clk);
eclkpget:
esettrate:
clk_put(mipi->dsit_clk);
eclktget:
iounmap(mipi->base);
emap:
release_mem_region(res->start, resource_size(res));
ereqreg:
kfree(mipi);
ealloc:
efindslot:
mutex_unlock(&array_lock);
return ret;
}
static int __exit sh_mipi_remove(struct platform_device *pdev)
{
struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct sh_mipi *mipi = platform_get_drvdata(pdev);
int i, ret;
mutex_lock(&array_lock);
for (i = 0; i < ARRAY_SIZE(mipi_dsi) && mipi_dsi[i] != mipi; i++)
;
if (i == ARRAY_SIZE(mipi_dsi)) {
ret = -EINVAL;
} else {
ret = 0;
mipi_dsi[i] = NULL;
}
mutex_unlock(&array_lock);
if (ret < 0)
return ret;
pdata->lcd_chan->board_cfg.display_on = NULL;
pdata->lcd_chan->board_cfg.display_off = NULL;
pdata->lcd_chan->board_cfg.board_data = NULL;
clk_disable(mipi->dsip_clk);
clk_disable(mipi->dsit_clk);
clk_put(mipi->dsit_clk);
clk_put(mipi->dsip_clk);
iounmap(mipi->base);
if (res)
release_mem_region(res->start, resource_size(res));
platform_set_drvdata(pdev, NULL);
kfree(mipi);
return 0;
}
static struct platform_driver sh_mipi_driver = {
.remove = __exit_p(sh_mipi_remove),
.shutdown = sh_mipi_shutdown,
.driver = {
.name = "sh-mipi-dsi",
},
};
static int __init sh_mipi_init(void)
{
return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe);
}
module_init(sh_mipi_init);
static void __exit sh_mipi_exit(void)
{
platform_driver_unregister(&sh_mipi_driver);
}
module_exit(sh_mipi_exit);
MODULE_AUTHOR("Guennadi Liakhovetski <[email protected]>");
MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load diff

View file

@ -56,6 +56,7 @@ static int lcdc_shared_regs[] = {
/* per-channel registers */
enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R,
LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR,
LDHAJR,
NR_CH_REGS };
static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
@ -74,6 +75,7 @@ static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
[LDVLNR] = 0x450,
[LDVSYNR] = 0x454,
[LDPMR] = 0x460,
[LDHAJR] = 0x4a0,
};
static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
@ -137,6 +139,7 @@ struct sh_mobile_lcdc_priv {
struct clk *dot_clk;
unsigned long lddckr;
struct sh_mobile_lcdc_chan ch[2];
struct notifier_block notifier;
unsigned long saved_shared_regs[NR_SHARED_REGS];
int started;
};
@ -404,6 +407,56 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv,
lcdc_write(priv, _LDDCKSTPR, 1); /* stop dotclock */
}
static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch)
{
struct fb_var_screeninfo *var = &ch->info->var;
unsigned long h_total, hsync_pos;
u32 tmp;
tmp = ch->ldmt1r_value;
tmp |= (var->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28;
tmp |= (var->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27;
tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0;
tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0;
tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0;
tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0;
tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0;
lcdc_write_chan(ch, LDMT1R, tmp);
/* setup SYS bus */
lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r);
lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r);
/* horizontal configuration */
h_total = var->xres + var->hsync_len +
var->left_margin + var->right_margin;
tmp = h_total / 8; /* HTCN */
tmp |= (var->xres / 8) << 16; /* HDCN */
lcdc_write_chan(ch, LDHCNR, tmp);
hsync_pos = var->xres + var->right_margin;
tmp = hsync_pos / 8; /* HSYNP */
tmp |= (var->hsync_len / 8) << 16; /* HSYNW */
lcdc_write_chan(ch, LDHSYNR, tmp);
/* vertical configuration */
tmp = var->yres + var->vsync_len +
var->upper_margin + var->lower_margin; /* VTLN */
tmp |= var->yres << 16; /* VDLN */
lcdc_write_chan(ch, LDVLNR, tmp);
tmp = var->yres + var->lower_margin; /* VSYNP */
tmp |= var->vsync_len << 16; /* VSYNW */
lcdc_write_chan(ch, LDVSYNR, tmp);
/* Adjust horizontal synchronisation for HDMI */
tmp = ((var->xres & 7) << 24) |
((h_total & 7) << 16) |
((var->hsync_len & 7) << 8) |
hsync_pos;
lcdc_write_chan(ch, LDHAJR, tmp);
}
static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
{
struct sh_mobile_lcdc_chan *ch;
@ -470,49 +523,11 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
if (!ch->enabled)
continue;
tmp = ch->ldmt1r_value;
tmp |= (lcd_cfg->sync & FB_SYNC_VERT_HIGH_ACT) ? 0 : 1 << 28;
tmp |= (lcd_cfg->sync & FB_SYNC_HOR_HIGH_ACT) ? 0 : 1 << 27;
tmp |= (ch->cfg.flags & LCDC_FLAGS_DWPOL) ? 1 << 26 : 0;
tmp |= (ch->cfg.flags & LCDC_FLAGS_DIPOL) ? 1 << 25 : 0;
tmp |= (ch->cfg.flags & LCDC_FLAGS_DAPOL) ? 1 << 24 : 0;
tmp |= (ch->cfg.flags & LCDC_FLAGS_HSCNT) ? 1 << 17 : 0;
tmp |= (ch->cfg.flags & LCDC_FLAGS_DWCNT) ? 1 << 16 : 0;
lcdc_write_chan(ch, LDMT1R, tmp);
/* setup SYS bus */
lcdc_write_chan(ch, LDMT2R, ch->cfg.sys_bus_cfg.ldmt2r);
lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r);
/* horizontal configuration */
tmp = lcd_cfg->xres + lcd_cfg->hsync_len;
tmp += lcd_cfg->left_margin;
tmp += lcd_cfg->right_margin;
tmp /= 8; /* HTCN */
tmp |= (lcd_cfg->xres / 8) << 16; /* HDCN */
lcdc_write_chan(ch, LDHCNR, tmp);
tmp = lcd_cfg->xres;
tmp += lcd_cfg->right_margin;
tmp /= 8; /* HSYNP */
tmp |= (lcd_cfg->hsync_len / 8) << 16; /* HSYNW */
lcdc_write_chan(ch, LDHSYNR, tmp);
sh_mobile_lcdc_geometry(ch);
/* power supply */
lcdc_write_chan(ch, LDPMR, 0);
/* vertical configuration */
tmp = lcd_cfg->yres + lcd_cfg->vsync_len;
tmp += lcd_cfg->upper_margin;
tmp += lcd_cfg->lower_margin; /* VTLN */
tmp |= lcd_cfg->yres << 16; /* VDLN */
lcdc_write_chan(ch, LDVLNR, tmp);
tmp = lcd_cfg->yres;
tmp += lcd_cfg->lower_margin; /* VSYNP */
tmp |= lcd_cfg->vsync_len << 16; /* VSYNW */
lcdc_write_chan(ch, LDVSYNR, tmp);
board_cfg = &ch->cfg.board_cfg;
if (board_cfg->setup_sys)
ret = board_cfg->setup_sys(board_cfg->board_data, ch,
@ -577,7 +592,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv)
board_cfg = &ch->cfg.board_cfg;
if (board_cfg->display_on)
board_cfg->display_on(board_cfg->board_data);
board_cfg->display_on(board_cfg->board_data, ch->info);
}
return 0;
@ -943,6 +958,62 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
.runtime_resume = sh_mobile_lcdc_runtime_resume,
};
static int sh_mobile_lcdc_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
struct fb_event *event = data;
struct fb_info *info = event->info;
struct sh_mobile_lcdc_chan *ch = info->par;
struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg;
struct fb_var_screeninfo *var;
if (&ch->lcdc->notifier != nb)
return 0;
dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
__func__, action, event->data);
switch(action) {
case FB_EVENT_SUSPEND:
if (board_cfg->display_off)
board_cfg->display_off(board_cfg->board_data);
pm_runtime_put(info->device);
break;
case FB_EVENT_RESUME:
var = &info->var;
/* HDMI must be enabled before LCDC configuration */
if (board_cfg->display_on)
board_cfg->display_on(board_cfg->board_data, ch->info);
/* Check if the new display is not in our modelist */
if (ch->info->modelist.next &&
!fb_match_mode(var, &ch->info->modelist)) {
struct fb_videomode mode;
int ret;
/* Can we handle this display? */
if (var->xres > ch->cfg.lcd_cfg.xres ||
var->yres > ch->cfg.lcd_cfg.yres)
return -ENOMEM;
/* Add to the modelist */
fb_var_to_videomode(&mode, var);
ret = fb_add_videomode(&mode, &ch->info->modelist);
if (ret < 0)
return ret;
}
pm_runtime_get_sync(info->device);
sh_mobile_lcdc_geometry(ch);
break;
}
return 0;
}
static int sh_mobile_lcdc_remove(struct platform_device *pdev);
static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
@ -1020,15 +1091,19 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1;
}
priv->base = ioremap_nocache(res->start, resource_size(res));
if (!priv->base)
goto err1;
error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv);
if (error) {
dev_err(&pdev->dev, "unable to setup clocks\n");
goto err1;
}
priv->base = ioremap_nocache(res->start, (res->end - res->start) + 1);
for (i = 0; i < j; i++) {
struct fb_var_screeninfo *var;
struct fb_videomode *lcd_cfg;
cfg = &priv->ch[i].cfg;
priv->ch[i].info = framebuffer_alloc(0, &pdev->dev);
@ -1039,22 +1114,33 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
}
info = priv->ch[i].info;
var = &info->var;
lcd_cfg = &cfg->lcd_cfg;
info->fbops = &sh_mobile_lcdc_ops;
info->var.xres = info->var.xres_virtual = cfg->lcd_cfg.xres;
info->var.yres = cfg->lcd_cfg.yres;
var->xres = var->xres_virtual = lcd_cfg->xres;
var->yres = lcd_cfg->yres;
/* Default Y virtual resolution is 2x panel size */
info->var.yres_virtual = info->var.yres * 2;
info->var.width = cfg->lcd_size_cfg.width;
info->var.height = cfg->lcd_size_cfg.height;
info->var.activate = FB_ACTIVATE_NOW;
error = sh_mobile_lcdc_set_bpp(&info->var, cfg->bpp);
var->yres_virtual = var->yres * 2;
var->width = cfg->lcd_size_cfg.width;
var->height = cfg->lcd_size_cfg.height;
var->activate = FB_ACTIVATE_NOW;
var->left_margin = lcd_cfg->left_margin;
var->right_margin = lcd_cfg->right_margin;
var->upper_margin = lcd_cfg->upper_margin;
var->lower_margin = lcd_cfg->lower_margin;
var->hsync_len = lcd_cfg->hsync_len;
var->vsync_len = lcd_cfg->vsync_len;
var->sync = lcd_cfg->sync;
var->pixclock = lcd_cfg->pixclock;
error = sh_mobile_lcdc_set_bpp(var, cfg->bpp);
if (error)
break;
info->fix = sh_mobile_lcdc_fix;
info->fix.line_length = cfg->lcd_cfg.xres * (cfg->bpp / 8);
info->fix.line_length = lcd_cfg->xres * (cfg->bpp / 8);
info->fix.smem_len = info->fix.line_length *
info->var.yres_virtual;
var->yres_virtual;
buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,
&priv->ch[i].dma_handle, GFP_KERNEL);
@ -1119,10 +1205,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
ch->cfg.bpp);
/* deferred io mode: disable clock to save power */
if (info->fbdefio)
if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
sh_mobile_lcdc_clk_off(priv);
}
/* Failure ignored */
priv->notifier.notifier_call = sh_mobile_lcdc_notify;
fb_register_client(&priv->notifier);
return 0;
err1:
sh_mobile_lcdc_remove(pdev);
@ -1136,6 +1226,8 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
struct fb_info *info;
int i;
fb_unregister_client(&priv->notifier);
for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
if (priv->ch[i].info && priv->ch[i].info->dev)
unregister_framebuffer(priv->ch[i].info);

View file

@ -111,7 +111,7 @@ static int __devinit gfb_set_fbinfo(struct gfb_info *gp)
return 0;
}
static int __devinit gfb_probe(struct of_device *op,
static int __devinit gfb_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
@ -172,7 +172,7 @@ err_out:
return err;
}
static int __devexit gfb_remove(struct of_device *op)
static int __devexit gfb_remove(struct platform_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
struct gfb_info *gp = info->par;
@ -213,12 +213,12 @@ static int __init gfb_init(void)
if (fb_get_options("gfb", NULL))
return -ENODEV;
return of_register_driver(&gfb_driver, &of_bus_type);
return of_register_platform_driver(&gfb_driver);
}
static void __exit gfb_exit(void)
{
of_unregister_driver(&gfb_driver);
of_unregister_platform_driver(&gfb_driver);
}
module_init(gfb_init);

View file

@ -342,7 +342,7 @@ tcx_init_fix(struct fb_info *info, int linebytes)
info->fix.accel = FB_ACCEL_SUN_TCX;
}
static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
static void tcx_unmap_regs(struct platform_device *op, struct fb_info *info,
struct tcx_par *par)
{
if (par->tec)
@ -362,7 +362,7 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
info->screen_base, info->fix.smem_len);
}
static int __devinit tcx_probe(struct of_device *op,
static int __devinit tcx_probe(struct platform_device *op,
const struct of_device_id *match)
{
struct device_node *dp = op->dev.of_node;
@ -486,7 +486,7 @@ out_err:
return err;
}
static int __devexit tcx_remove(struct of_device *op)
static int __devexit tcx_remove(struct platform_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
struct tcx_par *par = info->par;
@ -526,12 +526,12 @@ static int __init tcx_init(void)
if (fb_get_options("tcxfb", NULL))
return -ENODEV;
return of_register_driver(&tcx_driver, &of_bus_type);
return of_register_platform_driver(&tcx_driver);
}
static void __exit tcx_exit(void)
{
of_unregister_driver(&tcx_driver);
of_unregister_platform_driver(&tcx_driver);
}
module_init(tcx_init);

View file

@ -1571,8 +1571,8 @@ out_err_iobase:
if (default_par->mtrr_handle >= 0)
mtrr_del(default_par->mtrr_handle, info->fix.smem_start,
info->fix.smem_len);
release_mem_region(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2));
release_region(pci_resource_start(pdev, 2),
pci_resource_len(pdev, 2));
out_err_screenbase:
if (info->screen_base)
iounmap(info->screen_base);

View file

@ -305,7 +305,7 @@ tgafb_set_par(struct fb_info *info)
TGA_WRITE_REG(par, htimings, TGA_HORIZ_REG);
TGA_WRITE_REG(par, vtimings, TGA_VERT_REG);
/* Initalise RAMDAC. */
/* Initialise RAMDAC. */
if (tga_type == TGA_TYPE_8PLANE && tga_bus_pci) {
/* Init BT485 RAMDAC registers. */

View file

@ -1977,8 +1977,7 @@ static void __devexit uvesafb_exit(void)
module_exit(uvesafb_exit);
#define param_get_scroll NULL
static int param_set_scroll(const char *val, struct kernel_param *kp)
static int param_set_scroll(const char *val, const struct kernel_param *kp)
{
ypan = 0;
@ -1993,7 +1992,9 @@ static int param_set_scroll(const char *val, struct kernel_param *kp)
return 0;
}
static struct kernel_param_ops param_ops_scroll = {
.set = param_set_scroll,
};
#define param_check_scroll(name, p) __param_check(name, p, void)
module_param_named(scroll, ypan, scroll, 0);

View file

@ -160,7 +160,6 @@ struct lvds_setting_information {
int v_active;
int bpp;
int refresh_rate;
int get_lcd_size_method;
int lcd_panel_id;
int lcd_panel_hres;
int lcd_panel_vres;

View file

@ -23,143 +23,341 @@
#include "global.h"
static struct pll_map pll_value[] = {
{CLK_25_175M, CLE266_PLL_25_175M, K800_PLL_25_175M,
CX700_25_175M, VX855_25_175M},
{CLK_29_581M, CLE266_PLL_29_581M, K800_PLL_29_581M,
CX700_29_581M, VX855_29_581M},
{CLK_26_880M, CLE266_PLL_26_880M, K800_PLL_26_880M,
CX700_26_880M, VX855_26_880M},
{CLK_31_490M, CLE266_PLL_31_490M, K800_PLL_31_490M,
CX700_31_490M, VX855_31_490M},
{CLK_31_500M, CLE266_PLL_31_500M, K800_PLL_31_500M,
CX700_31_500M, VX855_31_500M},
{CLK_31_728M, CLE266_PLL_31_728M, K800_PLL_31_728M,
CX700_31_728M, VX855_31_728M},
{CLK_32_668M, CLE266_PLL_32_668M, K800_PLL_32_668M,
CX700_32_668M, VX855_32_668M},
{CLK_36_000M, CLE266_PLL_36_000M, K800_PLL_36_000M,
CX700_36_000M, VX855_36_000M},
{CLK_40_000M, CLE266_PLL_40_000M, K800_PLL_40_000M,
CX700_40_000M, VX855_40_000M},
{CLK_41_291M, CLE266_PLL_41_291M, K800_PLL_41_291M,
CX700_41_291M, VX855_41_291M},
{CLK_43_163M, CLE266_PLL_43_163M, K800_PLL_43_163M,
CX700_43_163M, VX855_43_163M},
{CLK_45_250M, CLE266_PLL_45_250M, K800_PLL_45_250M,
CX700_45_250M, VX855_45_250M},
{CLK_46_000M, CLE266_PLL_46_000M, K800_PLL_46_000M,
CX700_46_000M, VX855_46_000M},
{CLK_46_996M, CLE266_PLL_46_996M, K800_PLL_46_996M,
CX700_46_996M, VX855_46_996M},
{CLK_48_000M, CLE266_PLL_48_000M, K800_PLL_48_000M,
CX700_48_000M, VX855_48_000M},
{CLK_48_875M, CLE266_PLL_48_875M, K800_PLL_48_875M,
CX700_48_875M, VX855_48_875M},
{CLK_49_500M, CLE266_PLL_49_500M, K800_PLL_49_500M,
CX700_49_500M, VX855_49_500M},
{CLK_52_406M, CLE266_PLL_52_406M, K800_PLL_52_406M,
CX700_52_406M, VX855_52_406M},
{CLK_52_977M, CLE266_PLL_52_977M, K800_PLL_52_977M,
CX700_52_977M, VX855_52_977M},
{CLK_56_250M, CLE266_PLL_56_250M, K800_PLL_56_250M,
CX700_56_250M, VX855_56_250M},
{CLK_57_275M, 0, 0, 0, VX855_57_275M},
{CLK_60_466M, CLE266_PLL_60_466M, K800_PLL_60_466M,
CX700_60_466M, VX855_60_466M},
{CLK_61_500M, CLE266_PLL_61_500M, K800_PLL_61_500M,
CX700_61_500M, VX855_61_500M},
{CLK_65_000M, CLE266_PLL_65_000M, K800_PLL_65_000M,
CX700_65_000M, VX855_65_000M},
{CLK_65_178M, CLE266_PLL_65_178M, K800_PLL_65_178M,
CX700_65_178M, VX855_65_178M},
{CLK_66_750M, CLE266_PLL_66_750M, K800_PLL_66_750M,
CX700_66_750M, VX855_66_750M},
{CLK_68_179M, CLE266_PLL_68_179M, K800_PLL_68_179M,
CX700_68_179M, VX855_68_179M},
{CLK_69_924M, CLE266_PLL_69_924M, K800_PLL_69_924M,
CX700_69_924M, VX855_69_924M},
{CLK_70_159M, CLE266_PLL_70_159M, K800_PLL_70_159M,
CX700_70_159M, VX855_70_159M},
{CLK_72_000M, CLE266_PLL_72_000M, K800_PLL_72_000M,
CX700_72_000M, VX855_72_000M},
{CLK_78_750M, CLE266_PLL_78_750M, K800_PLL_78_750M,
CX700_78_750M, VX855_78_750M},
{CLK_80_136M, CLE266_PLL_80_136M, K800_PLL_80_136M,
CX700_80_136M, VX855_80_136M},
{CLK_83_375M, CLE266_PLL_83_375M, K800_PLL_83_375M,
CX700_83_375M, VX855_83_375M},
{CLK_83_950M, CLE266_PLL_83_950M, K800_PLL_83_950M,
CX700_83_950M, VX855_83_950M},
{CLK_84_750M, CLE266_PLL_84_750M, K800_PLL_84_750M,
CX700_84_750M, VX855_84_750M},
{CLK_85_860M, CLE266_PLL_85_860M, K800_PLL_85_860M,
CX700_85_860M, VX855_85_860M},
{CLK_88_750M, CLE266_PLL_88_750M, K800_PLL_88_750M,
CX700_88_750M, VX855_88_750M},
{CLK_94_500M, CLE266_PLL_94_500M, K800_PLL_94_500M,
CX700_94_500M, VX855_94_500M},
{CLK_97_750M, CLE266_PLL_97_750M, K800_PLL_97_750M,
CX700_97_750M, VX855_97_750M},
{CLK_101_000M, CLE266_PLL_101_000M, K800_PLL_101_000M,
CX700_101_000M, VX855_101_000M},
{CLK_106_500M, CLE266_PLL_106_500M, K800_PLL_106_500M,
CX700_106_500M, VX855_106_500M},
{CLK_108_000M, CLE266_PLL_108_000M, K800_PLL_108_000M,
CX700_108_000M, VX855_108_000M},
{CLK_113_309M, CLE266_PLL_113_309M, K800_PLL_113_309M,
CX700_113_309M, VX855_113_309M},
{CLK_118_840M, CLE266_PLL_118_840M, K800_PLL_118_840M,
CX700_118_840M, VX855_118_840M},
{CLK_119_000M, CLE266_PLL_119_000M, K800_PLL_119_000M,
CX700_119_000M, VX855_119_000M},
{CLK_121_750M, CLE266_PLL_121_750M, K800_PLL_121_750M,
CX700_121_750M, 0},
{CLK_125_104M, CLE266_PLL_125_104M, K800_PLL_125_104M,
CX700_125_104M, 0},
{CLK_133_308M, CLE266_PLL_133_308M, K800_PLL_133_308M,
CX700_133_308M, 0},
{CLK_135_000M, CLE266_PLL_135_000M, K800_PLL_135_000M,
CX700_135_000M, VX855_135_000M},
{CLK_136_700M, CLE266_PLL_136_700M, K800_PLL_136_700M,
CX700_136_700M, VX855_136_700M},
{CLK_138_400M, CLE266_PLL_138_400M, K800_PLL_138_400M,
CX700_138_400M, VX855_138_400M},
{CLK_146_760M, CLE266_PLL_146_760M, K800_PLL_146_760M,
CX700_146_760M, VX855_146_760M},
{CLK_153_920M, CLE266_PLL_153_920M, K800_PLL_153_920M,
CX700_153_920M, VX855_153_920M},
{CLK_156_000M, CLE266_PLL_156_000M, K800_PLL_156_000M,
CX700_156_000M, VX855_156_000M},
{CLK_157_500M, CLE266_PLL_157_500M, K800_PLL_157_500M,
CX700_157_500M, VX855_157_500M},
{CLK_162_000M, CLE266_PLL_162_000M, K800_PLL_162_000M,
CX700_162_000M, VX855_162_000M},
{CLK_187_000M, CLE266_PLL_187_000M, K800_PLL_187_000M,
CX700_187_000M, VX855_187_000M},
{CLK_193_295M, CLE266_PLL_193_295M, K800_PLL_193_295M,
CX700_193_295M, VX855_193_295M},
{CLK_202_500M, CLE266_PLL_202_500M, K800_PLL_202_500M,
CX700_202_500M, VX855_202_500M},
{CLK_204_000M, CLE266_PLL_204_000M, K800_PLL_204_000M,
CX700_204_000M, VX855_204_000M},
{CLK_218_500M, CLE266_PLL_218_500M, K800_PLL_218_500M,
CX700_218_500M, VX855_218_500M},
{CLK_234_000M, CLE266_PLL_234_000M, K800_PLL_234_000M,
CX700_234_000M, VX855_234_000M},
{CLK_267_250M, CLE266_PLL_267_250M, K800_PLL_267_250M,
CX700_267_250M, VX855_267_250M},
{CLK_297_500M, CLE266_PLL_297_500M, K800_PLL_297_500M,
CX700_297_500M, VX855_297_500M},
{CLK_74_481M, CLE266_PLL_74_481M, K800_PLL_74_481M,
CX700_74_481M, VX855_74_481M},
{CLK_172_798M, CLE266_PLL_172_798M, K800_PLL_172_798M,
CX700_172_798M, VX855_172_798M},
{CLK_122_614M, CLE266_PLL_122_614M, K800_PLL_122_614M,
CX700_122_614M, VX855_122_614M},
{CLK_74_270M, CLE266_PLL_74_270M, K800_PLL_74_270M,
CX700_74_270M, 0},
{CLK_148_500M, CLE266_PLL_148_500M, K800_PLL_148_500M,
CX700_148_500M, VX855_148_500M}
{25175000,
{99, 7, 3},
{85, 3, 4}, /* ignoring bit difference: 0x00008000 */
{141, 5, 4},
{141, 5, 4} },
{29581000,
{33, 4, 2},
{66, 2, 4}, /* ignoring bit difference: 0x00808000 */
{166, 5, 4}, /* ignoring bit difference: 0x00008000 */
{165, 5, 4} },
{26880000,
{15, 4, 1},
{30, 2, 3}, /* ignoring bit difference: 0x00808000 */
{150, 5, 4},
{150, 5, 4} },
{31500000,
{53, 3, 3}, /* ignoring bit difference: 0x00008000 */
{141, 4, 4}, /* ignoring bit difference: 0x00008000 */
{176, 5, 4},
{176, 5, 4} },
{31728000,
{31, 7, 1},
{177, 5, 4}, /* ignoring bit difference: 0x00008000 */
{177, 5, 4},
{142, 4, 4} },
{32688000,
{73, 4, 3},
{146, 4, 4}, /* ignoring bit difference: 0x00008000 */
{183, 5, 4},
{146, 4, 4} },
{36000000,
{101, 5, 3}, /* ignoring bit difference: 0x00008000 */
{161, 4, 4}, /* ignoring bit difference: 0x00008000 */
{202, 5, 4},
{161, 4, 4} },
{40000000,
{89, 4, 3},
{89, 4, 3}, /* ignoring bit difference: 0x00008000 */
{112, 5, 3},
{112, 5, 3} },
{41291000,
{23, 4, 1},
{69, 3, 3}, /* ignoring bit difference: 0x00008000 */
{115, 5, 3},
{115, 5, 3} },
{43163000,
{121, 5, 3},
{121, 5, 3}, /* ignoring bit difference: 0x00008000 */
{121, 5, 3},
{121, 5, 3} },
{45250000,
{127, 5, 3},
{127, 5, 3}, /* ignoring bit difference: 0x00808000 */
{127, 5, 3},
{127, 5, 3} },
{46000000,
{90, 7, 2},
{103, 4, 3}, /* ignoring bit difference: 0x00008000 */
{129, 5, 3},
{103, 4, 3} },
{46996000,
{105, 4, 3}, /* ignoring bit difference: 0x00008000 */
{131, 5, 3}, /* ignoring bit difference: 0x00808000 */
{131, 5, 3}, /* ignoring bit difference: 0x00808000 */
{105, 4, 3} },
{48000000,
{67, 20, 0},
{134, 5, 3}, /* ignoring bit difference: 0x00808000 */
{134, 5, 3},
{134, 5, 3} },
{48875000,
{99, 29, 0},
{82, 3, 3}, /* ignoring bit difference: 0x00808000 */
{82, 3, 3}, /* ignoring bit difference: 0x00808000 */
{137, 5, 3} },
{49500000,
{83, 6, 2},
{83, 3, 3}, /* ignoring bit difference: 0x00008000 */
{138, 5, 3},
{83, 3, 3} },
{52406000,
{117, 4, 3},
{117, 4, 3}, /* ignoring bit difference: 0x00008000 */
{117, 4, 3},
{88, 3, 3} },
{52977000,
{37, 5, 1},
{148, 5, 3}, /* ignoring bit difference: 0x00808000 */
{148, 5, 3},
{148, 5, 3} },
{56250000,
{55, 7, 1}, /* ignoring bit difference: 0x00008000 */
{126, 4, 3}, /* ignoring bit difference: 0x00008000 */
{157, 5, 3},
{157, 5, 3} },
{57275000,
{0, 0, 0},
{2, 2, 0},
{2, 2, 0},
{157, 5, 3} }, /* ignoring bit difference: 0x00808000 */
{60466000,
{76, 9, 1},
{169, 5, 3}, /* ignoring bit difference: 0x00808000 */
{169, 5, 3}, /* FIXED: old = {72, 2, 3} */
{169, 5, 3} },
{61500000,
{86, 20, 0},
{172, 5, 3}, /* ignoring bit difference: 0x00808000 */
{172, 5, 3},
{172, 5, 3} },
{65000000,
{109, 6, 2}, /* ignoring bit difference: 0x00008000 */
{109, 3, 3}, /* ignoring bit difference: 0x00008000 */
{109, 3, 3},
{109, 3, 3} },
{65178000,
{91, 5, 2},
{182, 5, 3}, /* ignoring bit difference: 0x00808000 */
{109, 3, 3},
{182, 5, 3} },
{66750000,
{75, 4, 2},
{150, 4, 3}, /* ignoring bit difference: 0x00808000 */
{150, 4, 3},
{112, 3, 3} },
{68179000,
{19, 4, 0},
{114, 3, 3}, /* ignoring bit difference: 0x00008000 */
{190, 5, 3},
{191, 5, 3} },
{69924000,
{83, 17, 0},
{195, 5, 3}, /* ignoring bit difference: 0x00808000 */
{195, 5, 3},
{195, 5, 3} },
{70159000,
{98, 20, 0},
{196, 5, 3}, /* ignoring bit difference: 0x00808000 */
{196, 5, 3},
{195, 5, 3} },
{72000000,
{121, 24, 0},
{161, 4, 3}, /* ignoring bit difference: 0x00808000 */
{161, 4, 3},
{161, 4, 3} },
{78750000,
{33, 3, 1},
{66, 3, 2}, /* ignoring bit difference: 0x00008000 */
{110, 5, 2},
{110, 5, 2} },
{80136000,
{28, 5, 0},
{68, 3, 2}, /* ignoring bit difference: 0x00008000 */
{112, 5, 2},
{112, 5, 2} },
{83375000,
{93, 2, 3},
{93, 4, 2}, /* ignoring bit difference: 0x00800000 */
{93, 4, 2}, /* ignoring bit difference: 0x00800000 */
{117, 5, 2} },
{83950000,
{41, 7, 0},
{117, 5, 2}, /* ignoring bit difference: 0x00008000 */
{117, 5, 2},
{117, 5, 2} },
{84750000,
{118, 5, 2},
{118, 5, 2}, /* ignoring bit difference: 0x00808000 */
{118, 5, 2},
{118, 5, 2} },
{85860000,
{84, 7, 1},
{120, 5, 2}, /* ignoring bit difference: 0x00808000 */
{120, 5, 2},
{118, 5, 2} },
{88750000,
{31, 5, 0},
{124, 5, 2}, /* ignoring bit difference: 0x00808000 */
{174, 7, 2}, /* ignoring bit difference: 0x00808000 */
{124, 5, 2} },
{94500000,
{33, 5, 0},
{132, 5, 2}, /* ignoring bit difference: 0x00008000 */
{132, 5, 2},
{132, 5, 2} },
{97750000,
{82, 6, 1},
{137, 5, 2}, /* ignoring bit difference: 0x00808000 */
{137, 5, 2},
{137, 5, 2} },
{101000000,
{127, 9, 1},
{141, 5, 2}, /* ignoring bit difference: 0x00808000 */
{141, 5, 2},
{141, 5, 2} },
{106500000,
{119, 4, 2},
{119, 4, 2}, /* ignoring bit difference: 0x00808000 */
{119, 4, 2},
{149, 5, 2} },
{108000000,
{121, 4, 2},
{121, 4, 2}, /* ignoring bit difference: 0x00808000 */
{151, 5, 2},
{151, 5, 2} },
{113309000,
{95, 12, 0},
{95, 3, 2}, /* ignoring bit difference: 0x00808000 */
{95, 3, 2},
{159, 5, 2} },
{118840000,
{83, 5, 1},
{166, 5, 2}, /* ignoring bit difference: 0x00808000 */
{166, 5, 2},
{166, 5, 2} },
{119000000,
{108, 13, 0},
{133, 4, 2}, /* ignoring bit difference: 0x00808000 */
{133, 4, 2},
{167, 5, 2} },
{121750000,
{85, 5, 1},
{170, 5, 2}, /* ignoring bit difference: 0x00808000 */
{68, 2, 2},
{0, 0, 0} },
{125104000,
{53, 6, 0}, /* ignoring bit difference: 0x00008000 */
{106, 3, 2}, /* ignoring bit difference: 0x00008000 */
{175, 5, 2},
{0, 0, 0} },
{135000000,
{94, 5, 1},
{28, 3, 0}, /* ignoring bit difference: 0x00804000 */
{151, 4, 2},
{189, 5, 2} },
{136700000,
{115, 12, 0},
{191, 5, 2}, /* ignoring bit difference: 0x00808000 */
{191, 5, 2},
{191, 5, 2} },
{138400000,
{87, 9, 0},
{116, 3, 2}, /* ignoring bit difference: 0x00808000 */
{116, 3, 2},
{194, 5, 2} },
{146760000,
{103, 5, 1},
{206, 5, 2}, /* ignoring bit difference: 0x00808000 */
{206, 5, 2},
{206, 5, 2} },
{153920000,
{86, 8, 0},
{86, 4, 1}, /* ignoring bit difference: 0x00808000 */
{86, 4, 1},
{86, 4, 1} }, /* FIXED: old = {84, 2, 1} */
{156000000,
{109, 5, 1},
{109, 5, 1}, /* ignoring bit difference: 0x00808000 */
{109, 5, 1},
{108, 5, 1} },
{157500000,
{55, 5, 0}, /* ignoring bit difference: 0x00008000 */
{22, 2, 0}, /* ignoring bit difference: 0x00802000 */
{110, 5, 1},
{110, 5, 1} },
{162000000,
{113, 5, 1},
{113, 5, 1}, /* ignoring bit difference: 0x00808000 */
{113, 5, 1},
{113, 5, 1} },
{187000000,
{118, 9, 0},
{131, 5, 1}, /* ignoring bit difference: 0x00808000 */
{131, 5, 1},
{131, 5, 1} },
{193295000,
{108, 8, 0},
{81, 3, 1}, /* ignoring bit difference: 0x00808000 */
{135, 5, 1},
{135, 5, 1} },
{202500000,
{99, 7, 0},
{85, 3, 1}, /* ignoring bit difference: 0x00808000 */
{142, 5, 1},
{142, 5, 1} },
{204000000,
{100, 7, 0},
{143, 5, 1}, /* ignoring bit difference: 0x00808000 */
{143, 5, 1},
{143, 5, 1} },
{218500000,
{92, 6, 0},
{153, 5, 1}, /* ignoring bit difference: 0x00808000 */
{153, 5, 1},
{153, 5, 1} },
{234000000,
{98, 6, 0},
{98, 3, 1}, /* ignoring bit difference: 0x00008000 */
{98, 3, 1},
{164, 5, 1} },
{267250000,
{112, 6, 0},
{112, 3, 1}, /* ignoring bit difference: 0x00808000 */
{187, 5, 1},
{187, 5, 1} },
{297500000,
{102, 5, 0}, /* ignoring bit difference: 0x00008000 */
{166, 4, 1}, /* ignoring bit difference: 0x00008000 */
{208, 5, 1},
{208, 5, 1} },
{74481000,
{26, 5, 0},
{125, 3, 3}, /* ignoring bit difference: 0x00808000 */
{208, 5, 3},
{209, 5, 3} },
{172798000,
{121, 5, 1},
{121, 5, 1}, /* ignoring bit difference: 0x00808000 */
{121, 5, 1},
{121, 5, 1} },
{122614000,
{60, 7, 0},
{137, 4, 2}, /* ignoring bit difference: 0x00808000 */
{137, 4, 2},
{172, 5, 2} },
{74270000,
{83, 8, 1},
{208, 5, 3},
{208, 5, 3},
{0, 0, 0} },
{148500000,
{83, 8, 0},
{208, 5, 2},
{166, 4, 2},
{208, 5, 2} }
};
static struct fifo_depth_select display_fifo_depth_reg = {
@ -1360,40 +1558,70 @@ void viafb_load_FIFO_reg(int set_iga, int hor_active, int ver_active)
}
static u32 cle266_encode_pll(struct pll_config pll)
{
return (pll.multiplier << 8)
| (pll.rshift << 6)
| pll.divisor;
}
static u32 k800_encode_pll(struct pll_config pll)
{
return ((pll.divisor - 2) << 16)
| (pll.rshift << 10)
| (pll.multiplier - 2);
}
static u32 vx855_encode_pll(struct pll_config pll)
{
return (pll.divisor << 16)
| (pll.rshift << 10)
| pll.multiplier;
}
u32 viafb_get_clk_value(int clk)
{
int i;
u32 value = 0;
int i = 0;
for (i = 0; i < NUM_TOTAL_PLL_TABLE; i++) {
if (clk == pll_value[i].clk) {
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
return pll_value[i].cle266_pll;
while (i < NUM_TOTAL_PLL_TABLE && clk != pll_value[i].clk)
i++;
case UNICHROME_K800:
case UNICHROME_PM800:
case UNICHROME_CN700:
return pll_value[i].k800_pll;
if (i == NUM_TOTAL_PLL_TABLE) {
printk(KERN_WARNING "viafb_get_clk_value: PLL lookup failed!");
} else {
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
value = cle266_encode_pll(pll_value[i].cle266_pll);
break;
case UNICHROME_CX700:
case UNICHROME_K8M890:
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
return pll_value[i].cx700_pll;
case UNICHROME_VX855:
return pll_value[i].vx855_pll;
}
case UNICHROME_K800:
case UNICHROME_PM800:
case UNICHROME_CN700:
value = k800_encode_pll(pll_value[i].k800_pll);
break;
case UNICHROME_CX700:
case UNICHROME_CN750:
case UNICHROME_K8M890:
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
value = k800_encode_pll(pll_value[i].cx700_pll);
break;
case UNICHROME_VX855:
value = vx855_encode_pll(pll_value[i].vx855_pll);
break;
}
}
DEBUG_MSG(KERN_INFO "Can't find match PLL value\n\n");
return 0;
return value;
}
/* Set VCLK*/
void viafb_set_vclock(u32 CLK, int set_iga)
void viafb_set_vclock(u32 clk, int set_iga)
{
/* H.W. Reset : ON */
viafb_write_reg_mask(CR17, VIACR, 0x00, BIT7);
@ -1403,26 +1631,23 @@ void viafb_set_vclock(u32 CLK, int set_iga)
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
viafb_write_reg(SR46, VIASR, CLK / 0x100);
viafb_write_reg(SR47, VIASR, CLK % 0x100);
via_write_reg(VIASR, SR46, (clk & 0x00FF));
via_write_reg(VIASR, SR47, (clk & 0xFF00) >> 8);
break;
case UNICHROME_K800:
case UNICHROME_PM800:
case UNICHROME_CN700:
case UNICHROME_CX700:
case UNICHROME_CN750:
case UNICHROME_K8M890:
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
case UNICHROME_VX855:
viafb_write_reg(SR44, VIASR, CLK / 0x10000);
DEBUG_MSG(KERN_INFO "\nSR44=%x", CLK / 0x10000);
viafb_write_reg(SR45, VIASR, (CLK & 0xFFFF) / 0x100);
DEBUG_MSG(KERN_INFO "\nSR45=%x",
(CLK & 0xFFFF) / 0x100);
viafb_write_reg(SR46, VIASR, CLK % 0x100);
DEBUG_MSG(KERN_INFO "\nSR46=%x", CLK % 0x100);
via_write_reg(VIASR, SR44, (clk & 0x0000FF));
via_write_reg(VIASR, SR45, (clk & 0x00FF00) >> 8);
via_write_reg(VIASR, SR46, (clk & 0xFF0000) >> 16);
break;
}
}
@ -1432,22 +1657,23 @@ void viafb_set_vclock(u32 CLK, int set_iga)
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
case UNICHROME_K400:
viafb_write_reg(SR44, VIASR, CLK / 0x100);
viafb_write_reg(SR45, VIASR, CLK % 0x100);
via_write_reg(VIASR, SR44, (clk & 0x00FF));
via_write_reg(VIASR, SR45, (clk & 0xFF00) >> 8);
break;
case UNICHROME_K800:
case UNICHROME_PM800:
case UNICHROME_CN700:
case UNICHROME_CX700:
case UNICHROME_CN750:
case UNICHROME_K8M890:
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_VX800:
case UNICHROME_VX855:
viafb_write_reg(SR4A, VIASR, CLK / 0x10000);
viafb_write_reg(SR4B, VIASR, (CLK & 0xFFFF) / 0x100);
viafb_write_reg(SR4C, VIASR, CLK % 0x100);
via_write_reg(VIASR, SR4A, (clk & 0x0000FF));
via_write_reg(VIASR, SR4B, (clk & 0x00FF00) >> 8);
via_write_reg(VIASR, SR4C, (clk & 0xFF0000) >> 16);
break;
}
}
@ -1791,8 +2017,6 @@ void viafb_init_chip_info(int chip_type)
viafb_set_iga_path();
viaparinfo->lvds_setting_info->display_method = viafb_lcd_dsp_method;
viaparinfo->lvds_setting_info->get_lcd_size_method =
GET_LCD_SIZE_BY_USER_SETTING;
viaparinfo->lvds_setting_info->lcd_mode = viafb_lcd_mode;
viaparinfo->lvds_setting_info2->display_method =
viaparinfo->lvds_setting_info->display_method;
@ -1946,13 +2170,6 @@ static void init_tmds_chip_info(void)
static void init_lvds_chip_info(void)
{
if (viafb_lcd_panel_id > LCD_PANEL_ID_MAXIMUM)
viaparinfo->lvds_setting_info->get_lcd_size_method =
GET_LCD_SIZE_BY_VGA_BIOS;
else
viaparinfo->lvds_setting_info->get_lcd_size_method =
GET_LCD_SIZE_BY_USER_SETTING;
viafb_lvds_trasmitter_identify();
viafb_init_lcd_size();
viafb_init_lvds_output_interface(&viaparinfo->chip_info->lvds_chip_info,

View file

@ -700,12 +700,18 @@ struct _lcd_scaling_factor {
struct _lcd_ver_scaling_factor lcd_ver_scaling_factor;
};
struct pll_config {
u16 multiplier;
u8 divisor;
u8 rshift;
};
struct pll_map {
u32 clk;
u32 cle266_pll;
u32 k800_pll;
u32 cx700_pll;
u32 vx855_pll;
struct pll_config cle266_pll;
struct pll_config k800_pll;
struct pll_config cx700_pll;
struct pll_config vx855_pll;
};
struct rgbLUT {

View file

@ -35,11 +35,9 @@
#define VIAFB_GET_SAMM_INFO 0x56494107 /* 'VIA\07' */
#define VIAFB_TURN_ON_OUTPUT_DEVICE 0x56494108 /* 'VIA\08' */
#define VIAFB_TURN_OFF_OUTPUT_DEVICE 0x56494109 /* 'VIA\09' */
#define VIAFB_SET_DEVICE 0x5649410A
#define VIAFB_GET_DEVICE 0x5649410B
#define VIAFB_GET_DRIVER_VERSION 0x56494112 /* 'VIA\12' */
#define VIAFB_GET_CHIP_INFO 0x56494113 /* 'VIA\13' */
#define VIAFB_SET_DEVICE_INFO 0x56494114
#define VIAFB_GET_DEVICE_INFO 0x56494115
#define VIAFB_GET_DEVICE_SUPPORT 0x56494118
@ -50,7 +48,6 @@
#define VIAFB_GET_GAMMA_LUT 0x56494124
#define VIAFB_SET_GAMMA_LUT 0x56494125
#define VIAFB_GET_GAMMA_SUPPORT_STATE 0x56494126
#define VIAFB_SET_SECOND_MODE 0x56494129
#define VIAFB_SYNC_SURFACE 0x56494130
#define VIAFB_GET_DRIVER_CAPS 0x56494131
#define VIAFB_GET_IGA_SCALING_INFO 0x56494132

View file

@ -75,8 +75,6 @@ static void check_diport_of_integrated_lvds(
static struct display_timing lcd_centering_timging(struct display_timing
mode_crt_reg,
struct display_timing panel_crt_reg);
static void viafb_load_scaling_factor_for_p4m900(int set_hres,
int set_vres, int panel_hres, int panel_vres);
static int check_lvds_chip(int device_id_subaddr, int device_id)
{
@ -89,33 +87,8 @@ static int check_lvds_chip(int device_id_subaddr, int device_id)
void viafb_init_lcd_size(void)
{
DEBUG_MSG(KERN_INFO "viafb_init_lcd_size()\n");
DEBUG_MSG(KERN_INFO
"viaparinfo->lvds_setting_info->get_lcd_size_method %d\n",
viaparinfo->lvds_setting_info->get_lcd_size_method);
switch (viaparinfo->lvds_setting_info->get_lcd_size_method) {
case GET_LCD_SIZE_BY_SYSTEM_BIOS:
break;
case GET_LCD_SZIE_BY_HW_STRAPPING:
break;
case GET_LCD_SIZE_BY_VGA_BIOS:
DEBUG_MSG(KERN_INFO "Get LCD Size method by VGA BIOS !!\n");
fp_id_to_vindex(viafb_lcd_panel_id);
DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n",
viaparinfo->lvds_setting_info->lcd_panel_id);
break;
case GET_LCD_SIZE_BY_USER_SETTING:
DEBUG_MSG(KERN_INFO "Get LCD Size method by user setting !!\n");
fp_id_to_vindex(viafb_lcd_panel_id);
DEBUG_MSG(KERN_INFO "LCD Panel_ID = %d\n",
viaparinfo->lvds_setting_info->lcd_panel_id);
break;
default:
DEBUG_MSG(KERN_INFO "viafb_init_lcd_size fail\n");
viaparinfo->lvds_setting_info->lcd_panel_id =
LCD_PANEL_ID1_800X600;
fp_id_to_vindex(LCD_PANEL_ID1_800X600);
}
fp_id_to_vindex(viafb_lcd_panel_id);
viaparinfo->lvds_setting_info2->lcd_panel_id =
viaparinfo->lvds_setting_info->lcd_panel_id;
viaparinfo->lvds_setting_info2->lcd_panel_hres =
@ -437,14 +410,9 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
/* LCD Scaling Enable */
viafb_write_reg_mask(CR79, VIACR, 0x07, BIT0 + BIT1 + BIT2);
if (UNICHROME_P4M900 == viaparinfo->chip_info->gfx_chip_name) {
viafb_load_scaling_factor_for_p4m900(set_hres, set_vres,
panel_hres, panel_vres);
return;
}
/* Check if expansion for horizontal */
if (set_hres != panel_hres) {
if (set_hres < panel_hres) {
/* Load Horizontal Scaling Factor */
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
@ -464,6 +432,10 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
case UNICHROME_CX700:
case UNICHROME_K8M890:
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_CN750:
case UNICHROME_VX800:
case UNICHROME_VX855:
reg_value =
K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
/* Horizontal scaling enabled */
@ -483,7 +455,7 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
}
/* Check if expansion for vertical */
if (set_vres != panel_vres) {
if (set_vres < panel_vres) {
/* Load Vertical Scaling Factor */
switch (viaparinfo->chip_info->gfx_chip_name) {
case UNICHROME_CLE266:
@ -503,6 +475,10 @@ static void load_lcd_scaling(int set_hres, int set_vres, int panel_hres,
case UNICHROME_CX700:
case UNICHROME_K8M890:
case UNICHROME_P4M890:
case UNICHROME_P4M900:
case UNICHROME_CN750:
case UNICHROME_VX800:
case UNICHROME_VX855:
reg_value =
K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
/* Vertical scaling enabled */
@ -648,9 +624,8 @@ void viafb_lcd_set_mode(struct crt_mode_table *mode_crt_table,
(mode_crt_reg, panel_crt_reg), IGA1);
} else {
/* Expansion */
if ((plvds_setting_info->display_method ==
LCD_EXPANDSION) & ((set_hres != panel_hres)
|| (set_vres != panel_vres))) {
if (plvds_setting_info->display_method == LCD_EXPANDSION
&& (set_hres < panel_hres || set_vres < panel_vres)) {
/* expansion timing IGA2 loaded panel set timing*/
viafb_load_crtc_timing(panel_crt_reg, IGA2);
DEBUG_MSG(KERN_INFO "viafb_load_crtc_timing!!\n");
@ -1139,69 +1114,3 @@ bool viafb_lcd_get_mobile_state(bool *mobile)
return false;
}
}
static void viafb_load_scaling_factor_for_p4m900(int set_hres,
int set_vres, int panel_hres, int panel_vres)
{
int h_scaling_factor;
int v_scaling_factor;
u8 cra2 = 0;
u8 cr77 = 0;
u8 cr78 = 0;
u8 cr79 = 0;
u8 cr9f = 0;
/* Check if expansion for horizontal */
if (set_hres < panel_hres) {
/* Load Horizontal Scaling Factor */
/* For VIA_K8M800 or later chipsets. */
h_scaling_factor =
K800_LCD_HOR_SCF_FORMULA(set_hres, panel_hres);
/* HSCaleFactor[1:0] at CR9F[1:0] */
cr9f = h_scaling_factor & 0x0003;
/* HSCaleFactor[9:2] at CR77[7:0] */
cr77 = (h_scaling_factor & 0x03FC) >> 2;
/* HSCaleFactor[11:10] at CR79[5:4] */
cr79 = (h_scaling_factor & 0x0C00) >> 10;
cr79 <<= 4;
/* Horizontal scaling enabled */
cra2 = 0xC0;
DEBUG_MSG(KERN_INFO "Horizontal Scaling value = %d\n",
h_scaling_factor);
} else {
/* Horizontal scaling disabled */
cra2 = 0x00;
}
/* Check if expansion for vertical */
if (set_vres < panel_vres) {
/* Load Vertical Scaling Factor */
/* For VIA_K8M800 or later chipsets. */
v_scaling_factor =
K800_LCD_VER_SCF_FORMULA(set_vres, panel_vres);
/* Vertical scaling enabled */
cra2 |= 0x08;
/* VSCaleFactor[0] at CR79[3] */
cr79 |= ((v_scaling_factor & 0x0001) << 3);
/* VSCaleFactor[8:1] at CR78[7:0] */
cr78 |= (v_scaling_factor & 0x01FE) >> 1;
/* VSCaleFactor[10:9] at CR79[7:6] */
cr79 |= ((v_scaling_factor & 0x0600) >> 9) << 6;
DEBUG_MSG(KERN_INFO "Vertical Scaling value = %d\n",
v_scaling_factor);
} else {
/* Vertical scaling disabled */
cra2 |= 0x00;
}
viafb_write_reg_mask(CRA2, VIACR, cra2, BIT3 + BIT6 + BIT7);
viafb_write_reg_mask(CR77, VIACR, cr77, 0xFF);
viafb_write_reg_mask(CR78, VIACR, cr78, 0xFF);
viafb_write_reg_mask(CR79, VIACR, cr79, 0xF8);
viafb_write_reg_mask(CR9F, VIACR, cr9f, BIT0 + BIT1);
}

View file

@ -28,11 +28,6 @@
#define VT3271_DEVICE_ID_REG 0x02
#define VT3271_DEVICE_ID 0x71
#define GET_LCD_SIZE_BY_SYSTEM_BIOS 0x01
#define GET_LCD_SIZE_BY_VGA_BIOS 0x02
#define GET_LCD_SZIE_BY_HW_STRAPPING 0x03
#define GET_LCD_SIZE_BY_USER_SETTING 0x04
/* Definition DVI Panel ID*/
/* Resolution: 640x480, Channel: single, Dithering: Enable */
#define LCD_PANEL_ID0_640X480 0x00

View file

@ -631,7 +631,6 @@
#define CLK_25_175M 25175000
#define CLK_26_880M 26880000
#define CLK_29_581M 29581000
#define CLK_31_490M 31490000
#define CLK_31_500M 31500000
#define CLK_31_728M 31728000
#define CLK_32_668M 32688000
@ -676,7 +675,6 @@
#define CLK_119_000M 119000000
#define CLK_121_750M 121750000 /* 121.704MHz */
#define CLK_125_104M 125104000
#define CLK_133_308M 133308000
#define CLK_135_000M 135000000
#define CLK_136_700M 136700000
#define CLK_138_400M 138400000
@ -699,313 +697,6 @@
#define CLK_172_798M 172798000
#define CLK_122_614M 122614000
/* CLE266 PLL value
*/
#define CLE266_PLL_25_175M 0x0000C763
#define CLE266_PLL_26_880M 0x0000440F
#define CLE266_PLL_29_581M 0x00008421
#define CLE266_PLL_31_490M 0x00004721
#define CLE266_PLL_31_500M 0x0000C3B5
#define CLE266_PLL_31_728M 0x0000471F
#define CLE266_PLL_32_668M 0x0000C449
#define CLE266_PLL_36_000M 0x0000C5E5
#define CLE266_PLL_40_000M 0x0000C459
#define CLE266_PLL_41_291M 0x00004417
#define CLE266_PLL_43_163M 0x0000C579
#define CLE266_PLL_45_250M 0x0000C57F /* 45.46MHz */
#define CLE266_PLL_46_000M 0x0000875A
#define CLE266_PLL_46_996M 0x0000C4E9
#define CLE266_PLL_48_000M 0x00001443
#define CLE266_PLL_48_875M 0x00001D63
#define CLE266_PLL_49_500M 0x00008653
#define CLE266_PLL_52_406M 0x0000C475
#define CLE266_PLL_52_977M 0x00004525
#define CLE266_PLL_56_250M 0x000047B7
#define CLE266_PLL_60_466M 0x0000494C
#define CLE266_PLL_61_500M 0x00001456
#define CLE266_PLL_65_000M 0x000086ED
#define CLE266_PLL_65_178M 0x0000855B
#define CLE266_PLL_66_750M 0x0000844B /* 67.116MHz */
#define CLE266_PLL_68_179M 0x00000413
#define CLE266_PLL_69_924M 0x00001153
#define CLE266_PLL_70_159M 0x00001462
#define CLE266_PLL_72_000M 0x00001879
#define CLE266_PLL_74_270M 0x00004853
#define CLE266_PLL_78_750M 0x00004321
#define CLE266_PLL_80_136M 0x0000051C
#define CLE266_PLL_83_375M 0x0000C25D
#define CLE266_PLL_83_950M 0x00000729
#define CLE266_PLL_84_750M 0x00008576 /* 84.537MHz */
#define CLE266_PLL_85_860M 0x00004754
#define CLE266_PLL_88_750M 0x0000051F
#define CLE266_PLL_94_500M 0x00000521
#define CLE266_PLL_97_750M 0x00004652
#define CLE266_PLL_101_000M 0x0000497F
#define CLE266_PLL_106_500M 0x00008477 /* 106.491463 MHz */
#define CLE266_PLL_108_000M 0x00008479
#define CLE266_PLL_113_309M 0x00000C5F
#define CLE266_PLL_118_840M 0x00004553
#define CLE266_PLL_119_000M 0x00000D6C
#define CLE266_PLL_121_750M 0x00004555 /* 121.704MHz */
#define CLE266_PLL_125_104M 0x000006B5
#define CLE266_PLL_133_308M 0x0000465F
#define CLE266_PLL_135_000M 0x0000455E
#define CLE266_PLL_136_700M 0x00000C73
#define CLE266_PLL_138_400M 0x00000957
#define CLE266_PLL_146_760M 0x00004567
#define CLE266_PLL_148_500M 0x00000853
#define CLE266_PLL_153_920M 0x00000856
#define CLE266_PLL_156_000M 0x0000456D
#define CLE266_PLL_157_500M 0x000005B7
#define CLE266_PLL_162_000M 0x00004571
#define CLE266_PLL_187_000M 0x00000976
#define CLE266_PLL_193_295M 0x0000086C
#define CLE266_PLL_202_500M 0x00000763
#define CLE266_PLL_204_000M 0x00000764
#define CLE266_PLL_218_500M 0x0000065C
#define CLE266_PLL_234_000M 0x00000662
#define CLE266_PLL_267_250M 0x00000670
#define CLE266_PLL_297_500M 0x000005E6
#define CLE266_PLL_74_481M 0x0000051A
#define CLE266_PLL_172_798M 0x00004579
#define CLE266_PLL_122_614M 0x0000073C
/* K800 PLL value
*/
#define K800_PLL_25_175M 0x00539001
#define K800_PLL_26_880M 0x001C8C80
#define K800_PLL_29_581M 0x00409080
#define K800_PLL_31_490M 0x006F9001
#define K800_PLL_31_500M 0x008B9002
#define K800_PLL_31_728M 0x00AF9003
#define K800_PLL_32_668M 0x00909002
#define K800_PLL_36_000M 0x009F9002
#define K800_PLL_40_000M 0x00578C02
#define K800_PLL_41_291M 0x00438C01
#define K800_PLL_43_163M 0x00778C03
#define K800_PLL_45_250M 0x007D8C83 /* 45.46MHz */
#define K800_PLL_46_000M 0x00658C02
#define K800_PLL_46_996M 0x00818C83
#define K800_PLL_48_000M 0x00848C83
#define K800_PLL_48_875M 0x00508C81
#define K800_PLL_49_500M 0x00518C01
#define K800_PLL_52_406M 0x00738C02
#define K800_PLL_52_977M 0x00928C83
#define K800_PLL_56_250M 0x007C8C02
#define K800_PLL_60_466M 0x00A78C83
#define K800_PLL_61_500M 0x00AA8C83
#define K800_PLL_65_000M 0x006B8C01
#define K800_PLL_65_178M 0x00B48C83
#define K800_PLL_66_750M 0x00948C82 /* 67.116MHz */
#define K800_PLL_68_179M 0x00708C01
#define K800_PLL_69_924M 0x00C18C83
#define K800_PLL_70_159M 0x00C28C83
#define K800_PLL_72_000M 0x009F8C82
#define K800_PLL_74_270M 0x00ce0c03
#define K800_PLL_78_750M 0x00408801
#define K800_PLL_80_136M 0x00428801
#define K800_PLL_83_375M 0x005B0882
#define K800_PLL_83_950M 0x00738803
#define K800_PLL_84_750M 0x00748883 /* 84.477MHz */
#define K800_PLL_85_860M 0x00768883
#define K800_PLL_88_750M 0x007A8883
#define K800_PLL_94_500M 0x00828803
#define K800_PLL_97_750M 0x00878883
#define K800_PLL_101_000M 0x008B8883
#define K800_PLL_106_500M 0x00758882 /* 106.491463 MHz */
#define K800_PLL_108_000M 0x00778882
#define K800_PLL_113_309M 0x005D8881
#define K800_PLL_118_840M 0x00A48883
#define K800_PLL_119_000M 0x00838882
#define K800_PLL_121_750M 0x00A88883 /* 121.704MHz */
#define K800_PLL_125_104M 0x00688801
#define K800_PLL_133_308M 0x005D8801
#define K800_PLL_135_000M 0x001A4081
#define K800_PLL_136_700M 0x00BD8883
#define K800_PLL_138_400M 0x00728881
#define K800_PLL_146_760M 0x00CC8883
#define K800_PLL_148_500M 0x00ce0803
#define K800_PLL_153_920M 0x00548482
#define K800_PLL_156_000M 0x006B8483
#define K800_PLL_157_500M 0x00142080
#define K800_PLL_162_000M 0x006F8483
#define K800_PLL_187_000M 0x00818483
#define K800_PLL_193_295M 0x004F8481
#define K800_PLL_202_500M 0x00538481
#define K800_PLL_204_000M 0x008D8483
#define K800_PLL_218_500M 0x00978483
#define K800_PLL_234_000M 0x00608401
#define K800_PLL_267_250M 0x006E8481
#define K800_PLL_297_500M 0x00A48402
#define K800_PLL_74_481M 0x007B8C81
#define K800_PLL_172_798M 0x00778483
#define K800_PLL_122_614M 0x00878882
/* PLL for VT3324 */
#define CX700_25_175M 0x008B1003
#define CX700_26_719M 0x00931003
#define CX700_26_880M 0x00941003
#define CX700_29_581M 0x00A49003
#define CX700_31_490M 0x00AE1003
#define CX700_31_500M 0x00AE1003
#define CX700_31_728M 0x00AF1003
#define CX700_32_668M 0x00B51003
#define CX700_36_000M 0x00C81003
#define CX700_40_000M 0x006E0C03
#define CX700_41_291M 0x00710C03
#define CX700_43_163M 0x00770C03
#define CX700_45_250M 0x007D0C03 /* 45.46MHz */
#define CX700_46_000M 0x007F0C03
#define CX700_46_996M 0x00818C83
#define CX700_48_000M 0x00840C03
#define CX700_48_875M 0x00508C81
#define CX700_49_500M 0x00880C03
#define CX700_52_406M 0x00730C02
#define CX700_52_977M 0x00920C03
#define CX700_56_250M 0x009B0C03
#define CX700_60_466M 0x00460C00
#define CX700_61_500M 0x00AA0C03
#define CX700_65_000M 0x006B0C01
#define CX700_65_178M 0x006B0C01
#define CX700_66_750M 0x00940C02 /*67.116MHz */
#define CX700_68_179M 0x00BC0C03
#define CX700_69_924M 0x00C10C03
#define CX700_70_159M 0x00C20C03
#define CX700_72_000M 0x009F0C02
#define CX700_74_270M 0x00CE0C03
#define CX700_74_481M 0x00CE0C03
#define CX700_78_750M 0x006C0803
#define CX700_80_136M 0x006E0803
#define CX700_83_375M 0x005B0882
#define CX700_83_950M 0x00730803
#define CX700_84_750M 0x00740803 /* 84.537Mhz */
#define CX700_85_860M 0x00760803
#define CX700_88_750M 0x00AC8885
#define CX700_94_500M 0x00820803
#define CX700_97_750M 0x00870803
#define CX700_101_000M 0x008B0803
#define CX700_106_500M 0x00750802
#define CX700_108_000M 0x00950803
#define CX700_113_309M 0x005D0801
#define CX700_118_840M 0x00A40803
#define CX700_119_000M 0x00830802
#define CX700_121_750M 0x00420800 /* 121.704MHz */
#define CX700_125_104M 0x00AD0803
#define CX700_133_308M 0x00930802
#define CX700_135_000M 0x00950802
#define CX700_136_700M 0x00BD0803
#define CX700_138_400M 0x00720801
#define CX700_146_760M 0x00CC0803
#define CX700_148_500M 0x00a40802
#define CX700_153_920M 0x00540402
#define CX700_156_000M 0x006B0403
#define CX700_157_500M 0x006C0403
#define CX700_162_000M 0x006F0403
#define CX700_172_798M 0x00770403
#define CX700_187_000M 0x00810403
#define CX700_193_295M 0x00850403
#define CX700_202_500M 0x008C0403
#define CX700_204_000M 0x008D0403
#define CX700_218_500M 0x00970403
#define CX700_234_000M 0x00600401
#define CX700_267_250M 0x00B90403
#define CX700_297_500M 0x00CE0403
#define CX700_122_614M 0x00870802
/* PLL for VX855 */
#define VX855_22_000M 0x007B1005
#define VX855_25_175M 0x008D1005
#define VX855_26_719M 0x00961005
#define VX855_26_880M 0x00961005
#define VX855_27_000M 0x00971005
#define VX855_29_581M 0x00A51005
#define VX855_29_829M 0x00641003
#define VX855_31_490M 0x00B01005
#define VX855_31_500M 0x00B01005
#define VX855_31_728M 0x008E1004
#define VX855_32_668M 0x00921004
#define VX855_36_000M 0x00A11004
#define VX855_40_000M 0x00700C05
#define VX855_41_291M 0x00730C05
#define VX855_43_163M 0x00790C05
#define VX855_45_250M 0x007F0C05 /* 45.46MHz */
#define VX855_46_000M 0x00670C04
#define VX855_46_996M 0x00690C04
#define VX855_48_000M 0x00860C05
#define VX855_48_875M 0x00890C05
#define VX855_49_500M 0x00530C03
#define VX855_52_406M 0x00580C03
#define VX855_52_977M 0x00940C05
#define VX855_56_250M 0x009D0C05
#define VX855_57_275M 0x009D8C85 /* Used by XO panel */
#define VX855_60_466M 0x00A90C05
#define VX855_61_500M 0x00AC0C05
#define VX855_65_000M 0x006D0C03
#define VX855_65_178M 0x00B60C05
#define VX855_66_750M 0x00700C03 /*67.116MHz */
#define VX855_67_295M 0x00BC0C05
#define VX855_68_179M 0x00BF0C05
#define VX855_68_369M 0x00BF0C05
#define VX855_69_924M 0x00C30C05
#define VX855_70_159M 0x00C30C05
#define VX855_72_000M 0x00A10C04
#define VX855_73_023M 0x00CC0C05
#define VX855_74_481M 0x00D10C05
#define VX855_78_750M 0x006E0805
#define VX855_79_466M 0x006F0805
#define VX855_80_136M 0x00700805
#define VX855_81_627M 0x00720805
#define VX855_83_375M 0x00750805
#define VX855_83_527M 0x00750805
#define VX855_83_950M 0x00750805
#define VX855_84_537M 0x00760805
#define VX855_84_750M 0x00760805 /* 84.537Mhz */
#define VX855_85_500M 0x00760805 /* 85.909080 MHz*/
#define VX855_85_860M 0x00760805
#define VX855_85_909M 0x00760805
#define VX855_88_750M 0x007C0805
#define VX855_89_489M 0x007D0805
#define VX855_94_500M 0x00840805
#define VX855_96_648M 0x00870805
#define VX855_97_750M 0x00890805
#define VX855_101_000M 0x008D0805
#define VX855_106_500M 0x00950805
#define VX855_108_000M 0x00970805
#define VX855_110_125M 0x00990805
#define VX855_112_000M 0x009D0805
#define VX855_113_309M 0x009F0805
#define VX855_115_000M 0x00A10805
#define VX855_118_840M 0x00A60805
#define VX855_119_000M 0x00A70805
#define VX855_121_750M 0x00AA0805 /* 121.704MHz */
#define VX855_122_614M 0x00AC0805
#define VX855_126_266M 0x00B10805
#define VX855_130_250M 0x00B60805 /* 130.250 */
#define VX855_135_000M 0x00BD0805
#define VX855_136_700M 0x00BF0805
#define VX855_137_750M 0x00C10805
#define VX855_138_400M 0x00C20805
#define VX855_144_300M 0x00CA0805
#define VX855_146_760M 0x00CE0805
#define VX855_148_500M 0x00D00805
#define VX855_153_920M 0x00540402
#define VX855_156_000M 0x006C0405
#define VX855_156_867M 0x006E0405
#define VX855_157_500M 0x006E0405
#define VX855_162_000M 0x00710405
#define VX855_172_798M 0x00790405
#define VX855_187_000M 0x00830405
#define VX855_193_295M 0x00870405
#define VX855_202_500M 0x008E0405
#define VX855_204_000M 0x008F0405
#define VX855_218_500M 0x00990405
#define VX855_229_500M 0x00A10405
#define VX855_234_000M 0x00A40405
#define VX855_267_250M 0x00BB0405
#define VX855_297_500M 0x00D00405
#define VX855_339_500M 0x00770005
#define VX855_340_772M 0x00770005
/* Definition CRTC Timing Index */
#define H_TOTAL_INDEX 0

View file

@ -64,7 +64,7 @@ static inline int viafb_mmio_read(int reg)
*/
static u32 viafb_enabled_ints;
static void viafb_int_init(void)
static void __devinit viafb_int_init(void)
{
viafb_enabled_ints = 0;
@ -489,7 +489,7 @@ out_unmap:
return ret;
}
static void __devexit via_pci_teardown_mmio(struct viafb_dev *vdev)
static void via_pci_teardown_mmio(struct viafb_dev *vdev)
{
iounmap(vdev->fbmem);
iounmap(vdev->engine_mmio);
@ -548,7 +548,7 @@ static int __devinit via_setup_subdevs(struct viafb_dev *vdev)
return 0;
}
static void __devexit via_teardown_subdevs(void)
static void via_teardown_subdevs(void)
{
int i;
@ -613,22 +613,24 @@ static void __devexit via_pci_remove(struct pci_dev *pdev)
static struct pci_device_id via_pci_table[] __devinitdata = {
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CLE266_DID),
.driver_data = UNICHROME_CLE266 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID),
.driver_data = UNICHROME_PM800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K400_DID),
.driver_data = UNICHROME_K400 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K800_DID),
.driver_data = UNICHROME_K800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID),
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_PM800_DID),
.driver_data = UNICHROME_PM800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN700_DID),
.driver_data = UNICHROME_CN700 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID),
.driver_data = UNICHROME_K8M890 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CX700_DID),
.driver_data = UNICHROME_CX700 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID),
.driver_data = UNICHROME_P4M900 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_CN750_DID),
.driver_data = UNICHROME_CN750 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_K8M890_DID),
.driver_data = UNICHROME_K8M890 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M890_DID),
.driver_data = UNICHROME_P4M890 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_P4M900_DID),
.driver_data = UNICHROME_P4M900 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX800_DID),
.driver_data = UNICHROME_VX800 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, UNICHROME_VX855_DID),

View file

@ -73,7 +73,7 @@ struct viafb_gpio_cfg {
struct gpio_chip gpio_chip;
struct viafb_dev *vdev;
struct viafb_gpio *active_gpios[VIAFB_NUM_GPIOS];
char *gpio_names[VIAFB_NUM_GPIOS];
const char *gpio_names[VIAFB_NUM_GPIOS];
};
/*

View file

@ -49,11 +49,6 @@ char *viafb_active_dev;
char *viafb_lcd_port = "";
char *viafb_dvi_port = "";
static void viafb_set_device(struct device_t active_dev);
static int apply_device_setting(struct viafb_ioctl_setting setting_info,
struct fb_info *info);
static void apply_second_mode_setting(struct fb_var_screeninfo
*sec_var);
static void retrieve_device_setting(struct viafb_ioctl_setting
*setting_info);
static int viafb_pan_display(struct fb_var_screeninfo *var,
@ -221,9 +216,9 @@ static int viafb_check_var(struct fb_var_screeninfo *var,
/* Adjust var according to our driver's own table */
viafb_fill_var_timing_info(var, viafb_refresh, vmode_entry);
if (info->var.accel_flags & FB_ACCELF_TEXT &&
if (var->accel_flags & FB_ACCELF_TEXT &&
!ppar->shared->vdev->engine_mmio)
info->var.accel_flags = 0;
var->accel_flags = 0;
return 0;
}
@ -234,6 +229,7 @@ static int viafb_set_par(struct fb_info *info)
struct VideoModeTable *vmode_entry, *vmode_entry1 = NULL;
DEBUG_MSG(KERN_INFO "viafb_set_par!\n");
viafb_update_fix(info);
viapar->depth = fb_get_color_depth(&info->var, &info->fix);
viafb_update_device_setting(viafbinfo->var.xres, viafbinfo->var.yres,
viafbinfo->var.bits_per_pixel, viafb_refresh, 0);
@ -257,7 +253,6 @@ static int viafb_set_par(struct fb_info *info)
}
if (vmode_entry) {
viafb_update_fix(info);
if (viafb_dual_fb && viapar->iga_path == IGA2)
viafb_bpp1 = info->var.bits_per_pixel;
else
@ -478,13 +473,6 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
if (gpu32 & LCD_Device)
viafb_lcd_disable();
break;
case VIAFB_SET_DEVICE:
if (copy_from_user(&u.active_dev, (void *)argp,
sizeof(u.active_dev)))
return -EFAULT;
viafb_set_device(u.active_dev);
viafb_set_par(info);
break;
case VIAFB_GET_DEVICE:
u.active_dev.crt = viafb_CRT_ON;
u.active_dev.dvi = viafb_DVI_ON;
@ -527,21 +515,6 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
break;
case VIAFB_SET_DEVICE_INFO:
if (copy_from_user(&u.viafb_setting,
argp, sizeof(u.viafb_setting)))
return -EFAULT;
if (apply_device_setting(u.viafb_setting, info) < 0)
return -EINVAL;
break;
case VIAFB_SET_SECOND_MODE:
if (copy_from_user(&u.sec_var, argp, sizeof(u.sec_var)))
return -EFAULT;
apply_second_mode_setting(&u.sec_var);
break;
case VIAFB_GET_DEVICE_INFO:
retrieve_device_setting(&u.viafb_setting);
@ -913,112 +886,6 @@ static int viafb_sync(struct fb_info *info)
return 0;
}
static void check_available_device_to_enable(int device_id)
{
int device_num = 0;
/* Initialize: */
viafb_CRT_ON = STATE_OFF;
viafb_DVI_ON = STATE_OFF;
viafb_LCD_ON = STATE_OFF;
viafb_LCD2_ON = STATE_OFF;
viafb_DeviceStatus = None_Device;
if ((device_id & CRT_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
viafb_CRT_ON = STATE_ON;
device_num++;
viafb_DeviceStatus |= CRT_Device;
}
if ((device_id & DVI_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
viafb_DVI_ON = STATE_ON;
device_num++;
viafb_DeviceStatus |= DVI_Device;
}
if ((device_id & LCD_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
viafb_LCD_ON = STATE_ON;
device_num++;
viafb_DeviceStatus |= LCD_Device;
}
if ((device_id & LCD2_Device) && (device_num < MAX_ACTIVE_DEV_NUM)) {
viafb_LCD2_ON = STATE_ON;
device_num++;
viafb_DeviceStatus |= LCD2_Device;
}
if (viafb_DeviceStatus == None_Device) {
/* Use CRT as default active device: */
viafb_CRT_ON = STATE_ON;
viafb_DeviceStatus = CRT_Device;
}
DEBUG_MSG(KERN_INFO "Device Status:%x", viafb_DeviceStatus);
}
static void viafb_set_device(struct device_t active_dev)
{
/* Check available device to enable: */
int device_id = None_Device;
if (active_dev.crt)
device_id |= CRT_Device;
if (active_dev.dvi)
device_id |= DVI_Device;
if (active_dev.lcd)
device_id |= LCD_Device;
check_available_device_to_enable(device_id);
/* Check property of LCD: */
if (viafb_LCD_ON) {
if (active_dev.lcd_dsp_cent) {
viaparinfo->lvds_setting_info->display_method =
viafb_lcd_dsp_method = LCD_CENTERING;
} else {
viaparinfo->lvds_setting_info->display_method =
viafb_lcd_dsp_method = LCD_EXPANDSION;
}
if (active_dev.lcd_mode == LCD_SPWG) {
viaparinfo->lvds_setting_info->lcd_mode =
viafb_lcd_mode = LCD_SPWG;
} else {
viaparinfo->lvds_setting_info->lcd_mode =
viafb_lcd_mode = LCD_OPENLDI;
}
if (active_dev.lcd_panel_id <= LCD_PANEL_ID_MAXIMUM) {
viafb_lcd_panel_id = active_dev.lcd_panel_id;
viafb_init_lcd_size();
}
}
/* Check property of mode: */
if (!active_dev.xres1)
viafb_second_xres = 640;
else
viafb_second_xres = active_dev.xres1;
if (!active_dev.yres1)
viafb_second_yres = 480;
else
viafb_second_yres = active_dev.yres1;
if (active_dev.bpp != 0)
viafb_bpp = active_dev.bpp;
if (active_dev.bpp1 != 0)
viafb_bpp1 = active_dev.bpp1;
if (active_dev.refresh != 0)
viafb_refresh = active_dev.refresh;
if (active_dev.refresh1 != 0)
viafb_refresh1 = active_dev.refresh1;
if ((active_dev.samm == STATE_OFF) || (active_dev.samm == STATE_ON))
viafb_SAMM_ON = active_dev.samm;
viafb_primary_dev = active_dev.primary_dev;
via_set_primary_address(0);
via_set_secondary_address(viafb_SAMM_ON ? viafb_second_offset : 0);
viafb_set_iga_path();
}
static int get_primary_device(void)
{
int primary_device = 0;
@ -1060,124 +927,6 @@ static int get_primary_device(void)
return primary_device;
}
static void apply_second_mode_setting(struct fb_var_screeninfo
*sec_var)
{
u32 htotal, vtotal, long_refresh;
htotal = sec_var->xres + sec_var->left_margin +
sec_var->right_margin + sec_var->hsync_len;
vtotal = sec_var->yres + sec_var->upper_margin +
sec_var->lower_margin + sec_var->vsync_len;
if ((sec_var->xres_virtual * (sec_var->bits_per_pixel >> 3)) & 0x1F) {
/*Is 32 bytes alignment? */
/*32 pixel alignment */
sec_var->xres_virtual = (sec_var->xres_virtual + 31) & ~31;
}
htotal = sec_var->xres + sec_var->left_margin +
sec_var->right_margin + sec_var->hsync_len;
vtotal = sec_var->yres + sec_var->upper_margin +
sec_var->lower_margin + sec_var->vsync_len;
long_refresh = 1000000000UL / sec_var->pixclock * 1000;
long_refresh /= (htotal * vtotal);
viafb_second_xres = sec_var->xres;
viafb_second_yres = sec_var->yres;
viafb_second_virtual_xres = sec_var->xres_virtual;
viafb_second_virtual_yres = sec_var->yres_virtual;
viafb_bpp1 = sec_var->bits_per_pixel;
viafb_refresh1 = viafb_get_refresh(sec_var->xres, sec_var->yres,
long_refresh);
}
static int apply_device_setting(struct viafb_ioctl_setting setting_info,
struct fb_info *info)
{
int need_set_mode = 0;
DEBUG_MSG(KERN_INFO "apply_device_setting\n");
if (setting_info.device_flag) {
need_set_mode = 1;
check_available_device_to_enable(setting_info.device_status);
}
/* Unlock LCD's operation according to LCD flag
and check if the setting value is valid. */
/* If the value is valid, apply the new setting value to the device. */
if (viafb_LCD_ON) {
if (setting_info.lcd_operation_flag & OP_LCD_CENTERING) {
need_set_mode = 1;
if (setting_info.lcd_attributes.display_center) {
/* Centering */
viaparinfo->lvds_setting_info->display_method =
LCD_CENTERING;
viafb_lcd_dsp_method = LCD_CENTERING;
viaparinfo->lvds_setting_info2->display_method =
viafb_lcd_dsp_method = LCD_CENTERING;
} else {
/* expandsion */
viaparinfo->lvds_setting_info->display_method =
LCD_EXPANDSION;
viafb_lcd_dsp_method = LCD_EXPANDSION;
viaparinfo->lvds_setting_info2->display_method =
LCD_EXPANDSION;
viafb_lcd_dsp_method = LCD_EXPANDSION;
}
}
if (setting_info.lcd_operation_flag & OP_LCD_MODE) {
need_set_mode = 1;
if (setting_info.lcd_attributes.lcd_mode ==
LCD_SPWG) {
viaparinfo->lvds_setting_info->lcd_mode =
viafb_lcd_mode = LCD_SPWG;
} else {
viaparinfo->lvds_setting_info->lcd_mode =
viafb_lcd_mode = LCD_OPENLDI;
}
viaparinfo->lvds_setting_info2->lcd_mode =
viaparinfo->lvds_setting_info->lcd_mode;
}
if (setting_info.lcd_operation_flag & OP_LCD_PANEL_ID) {
need_set_mode = 1;
if (setting_info.lcd_attributes.panel_id <=
LCD_PANEL_ID_MAXIMUM) {
viafb_lcd_panel_id =
setting_info.lcd_attributes.panel_id;
viafb_init_lcd_size();
}
}
}
if (0 != (setting_info.samm_status & OP_SAMM)) {
setting_info.samm_status =
setting_info.samm_status & (~OP_SAMM);
if (setting_info.samm_status == 0
|| setting_info.samm_status == 1) {
viafb_SAMM_ON = setting_info.samm_status;
if (viafb_SAMM_ON)
viafb_primary_dev = setting_info.primary_device;
via_set_primary_address(0);
via_set_secondary_address(viafb_SAMM_ON ?
viafb_second_offset : 0);
viafb_set_iga_path();
}
need_set_mode = 1;
}
if (!need_set_mode) {
;
} else {
viafb_set_iga_path();
viafb_set_par(info);
}
return true;
}
static void retrieve_device_setting(struct viafb_ioctl_setting
*setting_info)
{
@ -1776,10 +1525,6 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
parse_lcd_port();
parse_dvi_port();
/* for dual-fb must viafb_SAMM_ON=1 and viafb_dual_fb=1 */
if (!viafb_SAMM_ON)
viafb_dual_fb = 0;
viafb_init_chip_info(vdev->chip_type);
/*
* The framebuffer will have been successfully mapped by
@ -1823,30 +1568,13 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev)
parse_mode(viafb_mode1, &viafb_second_xres,
&viafb_second_yres);
if (0 == viafb_second_virtual_xres) {
switch (viafb_second_xres) {
case 1400:
viafb_second_virtual_xres = 1408;
break;
default:
viafb_second_virtual_xres = viafb_second_xres;
break;
}
}
if (0 == viafb_second_virtual_yres)
viafb_second_virtual_yres = viafb_second_yres;
viafb_second_virtual_xres = viafb_second_xres;
viafb_second_virtual_yres = viafb_second_yres;
}
default_var.xres = default_xres;
default_var.yres = default_yres;
switch (default_xres) {
case 1400:
default_var.xres_virtual = 1408;
break;
default:
default_var.xres_virtual = default_xres;
break;
}
default_var.xres_virtual = default_xres;
default_var.yres_virtual = default_yres;
default_var.bits_per_pixel = viafb_bpp;
default_var.pixclock =

View file

@ -726,7 +726,9 @@ static int __devinit vt8623_pci_probe(struct pci_dev *dev, const struct pci_devi
/* Prepare startup mode */
kparam_block_sysfs_write(mode_option);
rc = fb_find_mode(&(info->var), info, mode_option, NULL, 0, NULL, 8);
kparam_unblock_sysfs_write(mode_option);
if (! ((rc == 1) || (rc == 2))) {
rc = -EINVAL;
dev_err(info->device, "mode %s not found\n", mode_option);

View file

@ -858,9 +858,9 @@ unsigned long w100fb_gpio_read(int port)
void w100fb_gpio_write(int port, unsigned long value)
{
if (port==W100_GPIO_PORT_A)
value = writel(value, remapped_regs + mmGPIO_DATA);
writel(value, remapped_regs + mmGPIO_DATA);
else
value = writel(value, remapped_regs + mmGPIO_DATA2);
writel(value, remapped_regs + mmGPIO_DATA2);
}
EXPORT_SYMBOL(w100fb_gpio_read);
EXPORT_SYMBOL(w100fb_gpio_write);

View file

@ -684,7 +684,7 @@ static struct xenbus_driver xenfb_driver = {
static int __init xenfb_init(void)
{
if (!xen_domain())
if (!xen_pv_domain())
return -ENODEV;
/* Nothing to do if running in dom0. */

View file

@ -397,7 +397,7 @@ static int xilinxfb_release(struct device *dev)
*/
static int __devinit
xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
xilinxfb_of_probe(struct platform_device *op, const struct of_device_id *match)
{
const u32 *prop;
u32 *p;
@ -477,7 +477,7 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
return -ENODEV;
}
static int __devexit xilinxfb_of_remove(struct of_device *op)
static int __devexit xilinxfb_of_remove(struct platform_device *op)
{
return xilinxfb_release(&op->dev);
}
@ -485,6 +485,8 @@ static int __devexit xilinxfb_of_remove(struct of_device *op)
/* Match table for of_platform binding */
static struct of_device_id xilinxfb_of_match[] __devinitdata = {
{ .compatible = "xlnx,xps-tft-1.00.a", },
{ .compatible = "xlnx,xps-tft-2.00.a", },
{ .compatible = "xlnx,xps-tft-2.01.a", },
{ .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
{ .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", },
{},