aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorGrant Likely <grant.likely@secretlab.ca>2010-01-28 16:38:25 -0500
committerGrant Likely <grant.likely@secretlab.ca>2010-01-28 16:38:25 -0500
commit0ada0a73120c28cc432bcdbac061781465c2f48f (patch)
treed17cadd4ea47e25d9e48e7d409a39c84268fbd27 /drivers/video
parent6016a363f6b56b46b24655bcfc0499b715851cf3 (diff)
parent92dcffb916d309aa01778bf8963a6932e4014d07 (diff)
Merge commit 'v2.6.33-rc5' into secretlab/test-devicetree
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/Kconfig24
-rw-r--r--drivers/video/Makefile2
-rw-r--r--drivers/video/atafb.c3
-rw-r--r--drivers/video/atmel_lcdfb.c2
-rw-r--r--drivers/video/aty/atyfb_base.c4
-rw-r--r--drivers/video/backlight/adp5520_bl.c125
-rw-r--r--drivers/video/backlight/adx_bl.c2
-rw-r--r--drivers/video/backlight/atmel-pwm-bl.c4
-rw-r--r--drivers/video/backlight/backlight.c2
-rw-r--r--drivers/video/backlight/corgi_lcd.c2
-rw-r--r--drivers/video/backlight/cr_bllcd.c4
-rw-r--r--drivers/video/backlight/da903x_bl.c11
-rw-r--r--drivers/video/backlight/generic_bl.c2
-rw-r--r--drivers/video/backlight/hp680_bl.c2
-rw-r--r--drivers/video/backlight/jornada720_bl.c2
-rw-r--r--drivers/video/backlight/kb3886_bl.c2
-rw-r--r--drivers/video/backlight/lcd.c4
-rw-r--r--drivers/video/backlight/locomolcd.c2
-rw-r--r--drivers/video/backlight/mbp_nvidia_bl.c20
-rw-r--r--drivers/video/backlight/omap1_bl.c8
-rw-r--r--drivers/video/backlight/progear_bl.c2
-rw-r--r--drivers/video/backlight/pwm_bl.c11
-rw-r--r--drivers/video/backlight/tdo24m.c1
-rw-r--r--drivers/video/backlight/tosa_bl.c2
-rw-r--r--drivers/video/backlight/tosa_lcd.c2
-rw-r--r--drivers/video/backlight/wm831x_bl.c2
-rw-r--r--drivers/video/bfin-lq035q1-fb.c826
-rw-r--r--drivers/video/bfin-t350mcqb-fb.c32
-rw-r--r--drivers/video/broadsheetfb.c2
-rw-r--r--drivers/video/clps711xfb.c50
-rw-r--r--drivers/video/console/sticore.c2
-rw-r--r--drivers/video/console/vgacon.c5
-rw-r--r--drivers/video/cyber2000fb.c12
-rw-r--r--drivers/video/da8xx-fb.c186
-rw-r--r--drivers/video/display/display-sysfs.c2
-rw-r--r--drivers/video/ep93xx-fb.c2
-rw-r--r--drivers/video/fb_defio.c6
-rw-r--r--drivers/video/gbefb.c4
-rw-r--r--drivers/video/geode/display_gx.c4
-rw-r--r--drivers/video/geode/gxfb.h2
-rw-r--r--drivers/video/geode/gxfb_core.c2
-rw-r--r--drivers/video/geode/lxfb.h12
-rw-r--r--drivers/video/geode/lxfb_ops.c4
-rw-r--r--drivers/video/geode/suspend_gx.c2
-rw-r--r--drivers/video/geode/video_gx.c2
-rw-r--r--drivers/video/hecubafb.c2
-rw-r--r--drivers/video/hitfb.c2
-rw-r--r--drivers/video/i810/i810_dvt.c53
-rw-r--r--drivers/video/intelfb/intelfbdrv.c3
-rw-r--r--drivers/video/intelfb/intelfbhw.c47
-rw-r--r--drivers/video/intelfb/intelfbhw.h1
-rw-r--r--drivers/video/matrox/g450_pll.c3
-rw-r--r--drivers/video/maxinefb.c3
-rw-r--r--drivers/video/mb862xx/Makefile2
-rw-r--r--drivers/video/mb862xx/mb862xxfb.c14
-rw-r--r--drivers/video/mb862xx/mb862xxfb.h2
-rw-r--r--drivers/video/mb862xx/mb862xxfb_accel.c331
-rw-r--r--drivers/video/mb862xx/mb862xxfb_accel.h203
-rw-r--r--drivers/video/metronomefb.c2
-rw-r--r--drivers/video/modedb.c24
-rw-r--r--drivers/video/offb.c15
-rw-r--r--drivers/video/omap/Kconfig5
-rw-r--r--drivers/video/omap/Makefile1
-rw-r--r--drivers/video/omap/blizzard.c6
-rw-r--r--drivers/video/omap/dispc.c33
-rw-r--r--drivers/video/omap/hwa742.c7
-rw-r--r--drivers/video/omap/lcd_2430sdp.c9
-rw-r--r--drivers/video/omap/lcd_ams_delta.c9
-rw-r--r--drivers/video/omap/lcd_apollon.c5
-rw-r--r--drivers/video/omap/lcd_h3.c2
-rw-r--r--drivers/video/omap/lcd_h4.c2
-rw-r--r--drivers/video/omap/lcd_htcherald.c130
-rw-r--r--drivers/video/omap/lcd_inn1510.c4
-rw-r--r--drivers/video/omap/lcd_inn1610.c2
-rw-r--r--drivers/video/omap/lcd_ldp.c9
-rw-r--r--drivers/video/omap/lcd_mipid.c9
-rw-r--r--drivers/video/omap/lcd_omap2evm.c15
-rw-r--r--drivers/video/omap/lcd_omap3beagle.c8
-rw-r--r--drivers/video/omap/lcd_omap3evm.c15
-rw-r--r--drivers/video/omap/lcd_osk.c4
-rw-r--r--drivers/video/omap/lcd_overo.c7
-rw-r--r--drivers/video/omap/lcd_palmte.c4
-rw-r--r--drivers/video/omap/lcd_palmtt.c2
-rw-r--r--drivers/video/omap/lcd_palmz71.c2
-rw-r--r--drivers/video/omap/lcdc.c38
-rw-r--r--drivers/video/omap/omapfb.h229
-rw-r--r--drivers/video/omap/omapfb_main.c29
-rw-r--r--drivers/video/omap/rfbi.c7
-rw-r--r--drivers/video/omap/sossi.c5
-rw-r--r--drivers/video/omap2/Kconfig9
-rw-r--r--drivers/video/omap2/Makefile6
-rw-r--r--drivers/video/omap2/displays/Kconfig22
-rw-r--r--drivers/video/omap2/displays/Makefile4
-rw-r--r--drivers/video/omap2/displays/panel-generic.c104
-rw-r--r--drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c153
-rw-r--r--drivers/video/omap2/displays/panel-taal.c1003
-rw-r--r--drivers/video/omap2/dss/Kconfig96
-rw-r--r--drivers/video/omap2/dss/Makefile6
-rw-r--r--drivers/video/omap2/dss/core.c929
-rw-r--r--drivers/video/omap2/dss/dispc.c3161
-rw-r--r--drivers/video/omap2/dss/display.c671
-rw-r--r--drivers/video/omap2/dss/dpi.c399
-rw-r--r--drivers/video/omap2/dss/dsi.c3839
-rw-r--r--drivers/video/omap2/dss/dss.c596
-rw-r--r--drivers/video/omap2/dss/dss.h384
-rw-r--r--drivers/video/omap2/dss/manager.c1487
-rw-r--r--drivers/video/omap2/dss/overlay.c680
-rw-r--r--drivers/video/omap2/dss/rfbi.c1309
-rw-r--r--drivers/video/omap2/dss/sdi.c277
-rw-r--r--drivers/video/omap2/dss/venc.c797
-rw-r--r--drivers/video/omap2/omapfb/Kconfig37
-rw-r--r--drivers/video/omap2/omapfb/Makefile2
-rw-r--r--drivers/video/omap2/omapfb/omapfb-ioctl.c755
-rw-r--r--drivers/video/omap2/omapfb/omapfb-main.c2267
-rw-r--r--drivers/video/omap2/omapfb/omapfb-sysfs.c507
-rw-r--r--drivers/video/omap2/omapfb/omapfb.h146
-rw-r--r--drivers/video/omap2/vram.c655
-rw-r--r--drivers/video/omap2/vrfb.c315
-rw-r--r--drivers/video/output.c2
-rw-r--r--drivers/video/pmag-ba-fb.c3
-rw-r--r--drivers/video/pmagb-b-fb.c3
-rw-r--r--drivers/video/pxa168fb.c1
-rw-r--r--drivers/video/pxafb.c28
-rw-r--r--drivers/video/s3c-fb.c14
-rw-r--r--drivers/video/sgivwfb.c4
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c42
-rw-r--r--drivers/video/sis/sis_main.c2
-rw-r--r--drivers/video/sm501fb.c249
-rw-r--r--drivers/video/stifb.c4
-rw-r--r--drivers/video/tdfxfb.c2
-rw-r--r--drivers/video/via/accel.c5
-rw-r--r--drivers/video/via/dvi.c4
-rw-r--r--drivers/video/via/lcd.c40
-rw-r--r--drivers/video/via/viafbdev.c17
-rw-r--r--drivers/video/vt8623fb.c2
-rw-r--r--drivers/video/xen-fbfront.c5
136 files changed, 23317 insertions, 435 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 188e1ba3b69f..5a5c303a6373 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -5,6 +5,9 @@
5menu "Graphics support" 5menu "Graphics support"
6 depends on HAS_IOMEM 6 depends on HAS_IOMEM
7 7
8config HAVE_FB_ATMEL
9 bool
10
8source "drivers/char/agp/Kconfig" 11source "drivers/char/agp/Kconfig"
9 12
10source "drivers/gpu/vga/Kconfig" 13source "drivers/gpu/vga/Kconfig"
@@ -611,6 +614,21 @@ config FB_BFIN_T350MCQB
611 This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI 614 This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI
612 It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. 615 It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK.
613 616
617config FB_BFIN_LQ035Q1
618 tristate "SHARP LQ035Q1DH02 TFT LCD"
619 depends on FB && BLACKFIN && SPI
620 select FB_CFB_FILLRECT
621 select FB_CFB_COPYAREA
622 select FB_CFB_IMAGEBLIT
623 select BFIN_GPTIMERS
624 help
625 This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on
626 the Blackfin Landscape LCD EZ-Extender Card.
627 This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI
628 It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK.
629
630 To compile this driver as a module, choose M here: the
631 module will be called bfin-lq035q1-fb.
614 632
615config FB_STI 633config FB_STI
616 tristate "HP STI frame buffer device support" 634 tristate "HP STI frame buffer device support"
@@ -937,7 +955,7 @@ config FB_S1D13XXX
937 955
938config FB_ATMEL 956config FB_ATMEL
939 tristate "AT91/AT32 LCD Controller support" 957 tristate "AT91/AT32 LCD Controller support"
940 depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9G10 || ARCH_AT91SAM9263 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 || ARCH_AT91CAP9 || AVR32) 958 depends on FB && HAVE_FB_ATMEL
941 select FB_CFB_FILLRECT 959 select FB_CFB_FILLRECT
942 select FB_CFB_COPYAREA 960 select FB_CFB_COPYAREA
943 select FB_CFB_IMAGEBLIT 961 select FB_CFB_IMAGEBLIT
@@ -2063,6 +2081,7 @@ config XEN_FBDEV_FRONTEND
2063 select FB_SYS_IMAGEBLIT 2081 select FB_SYS_IMAGEBLIT
2064 select FB_SYS_FOPS 2082 select FB_SYS_FOPS
2065 select FB_DEFERRED_IO 2083 select FB_DEFERRED_IO
2084 select XEN_XENBUS_FRONTEND
2066 default y 2085 default y
2067 help 2086 help
2068 This driver implements the front-end of the Xen virtual 2087 This driver implements the front-end of the Xen virtual
@@ -2127,7 +2146,7 @@ config FB_PRE_INIT_FB
2127 the bootloader. 2146 the bootloader.
2128 2147
2129config FB_MSM 2148config FB_MSM
2130 tristate 2149 tristate "MSM Framebuffer support"
2131 depends on FB && ARCH_MSM 2150 depends on FB && ARCH_MSM
2132 select FB_CFB_FILLRECT 2151 select FB_CFB_FILLRECT
2133 select FB_CFB_COPYAREA 2152 select FB_CFB_COPYAREA
@@ -2161,6 +2180,7 @@ config FB_BROADSHEET
2161 a bridge adapter. 2180 a bridge adapter.
2162 2181
2163source "drivers/video/omap/Kconfig" 2182source "drivers/video/omap/Kconfig"
2183source "drivers/video/omap2/Kconfig"
2164 2184
2165source "drivers/video/backlight/Kconfig" 2185source "drivers/video/backlight/Kconfig"
2166source "drivers/video/display/Kconfig" 2186source "drivers/video/display/Kconfig"
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 80232e124889..4ecb30c4f3f2 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -124,6 +124,7 @@ obj-$(CONFIG_FB_SM501) += sm501fb.o
124obj-$(CONFIG_FB_XILINX) += xilinxfb.o 124obj-$(CONFIG_FB_XILINX) += xilinxfb.o
125obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o 125obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o
126obj-$(CONFIG_FB_OMAP) += omap/ 126obj-$(CONFIG_FB_OMAP) += omap/
127obj-y += omap2/
127obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o 128obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
128obj-$(CONFIG_FB_CARMINE) += carminefb.o 129obj-$(CONFIG_FB_CARMINE) += carminefb.o
129obj-$(CONFIG_FB_MB862XX) += mb862xx/ 130obj-$(CONFIG_FB_MB862XX) += mb862xx/
@@ -136,6 +137,7 @@ obj-$(CONFIG_FB_EFI) += efifb.o
136obj-$(CONFIG_FB_VGA16) += vga16fb.o 137obj-$(CONFIG_FB_VGA16) += vga16fb.o
137obj-$(CONFIG_FB_OF) += offb.o 138obj-$(CONFIG_FB_OF) += offb.o
138obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o 139obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o
140obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o
139obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o 141obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o
140obj-$(CONFIG_FB_MX3) += mx3fb.o 142obj-$(CONFIG_FB_MX3) += mx3fb.o
141obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o 143obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 37624f74e88b..b7687c55fe16 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -2242,6 +2242,9 @@ static int ext_setcolreg(unsigned int regno, unsigned int red,
2242 if (!external_vgaiobase) 2242 if (!external_vgaiobase)
2243 return 1; 2243 return 1;
2244 2244
2245 if (regno > 255)
2246 return 1;
2247
2245 switch (external_card_type) { 2248 switch (external_card_type) {
2246 case IS_VGA: 2249 case IS_VGA:
2247 OUTB(0x3c8, regno); 2250 OUTB(0x3c8, regno);
diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c
index d5e801076d33..3d886c6902f9 100644
--- a/drivers/video/atmel_lcdfb.c
+++ b/drivers/video/atmel_lcdfb.c
@@ -964,7 +964,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev)
964 if (sinfo->atmel_lcdfb_power_control) 964 if (sinfo->atmel_lcdfb_power_control)
965 sinfo->atmel_lcdfb_power_control(1); 965 sinfo->atmel_lcdfb_power_control(1);
966 966
967 dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n", 967 dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %d\n",
968 info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base); 968 info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
969 969
970 return 0; 970 return 0;
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index bb20987d58af..5f1b5807a48f 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -3276,7 +3276,7 @@ static void __devinit aty_init_lcd(struct atyfb_par *par, u32 bios_base)
3276 txtformat = "24 bit interface"; 3276 txtformat = "24 bit interface";
3277 break; 3277 break;
3278 default: 3278 default:
3279 txtformat = "unkown format"; 3279 txtformat = "unknown format";
3280 } 3280 }
3281 } else { 3281 } else {
3282 switch (format & 7) { 3282 switch (format & 7) {
@@ -3299,7 +3299,7 @@ static void __devinit aty_init_lcd(struct atyfb_par *par, u32 bios_base)
3299 txtformat = "262144 colours (FDPI-2 mode)"; 3299 txtformat = "262144 colours (FDPI-2 mode)";
3300 break; 3300 break;
3301 default: 3301 default:
3302 txtformat = "unkown format"; 3302 txtformat = "unknown format";
3303 } 3303 }
3304 } 3304 }
3305 PRINTKI("%s%s %s monitor detected: %s\n", 3305 PRINTKI("%s%s %s monitor detected: %s\n",
diff --git a/drivers/video/backlight/adp5520_bl.c b/drivers/video/backlight/adp5520_bl.c
index ad05da5ba3c7..86d95c228adb 100644
--- a/drivers/video/backlight/adp5520_bl.c
+++ b/drivers/video/backlight/adp5520_bl.c
@@ -15,7 +15,7 @@
15 15
16struct adp5520_bl { 16struct adp5520_bl {
17 struct device *master; 17 struct device *master;
18 struct adp5520_backlight_platfrom_data *pdata; 18 struct adp5520_backlight_platform_data *pdata;
19 struct mutex lock; 19 struct mutex lock;
20 unsigned long cached_daylight_max; 20 unsigned long cached_daylight_max;
21 int id; 21 int id;
@@ -31,29 +31,30 @@ static int adp5520_bl_set(struct backlight_device *bl, int brightness)
31 if (data->pdata->en_ambl_sens) { 31 if (data->pdata->en_ambl_sens) {
32 if ((brightness > 0) && (brightness < ADP5020_MAX_BRIGHTNESS)) { 32 if ((brightness > 0) && (brightness < ADP5020_MAX_BRIGHTNESS)) {
33 /* Disable Ambient Light auto adjust */ 33 /* Disable Ambient Light auto adjust */
34 ret |= adp5520_clr_bits(master, BL_CONTROL, 34 ret |= adp5520_clr_bits(master, ADP5520_BL_CONTROL,
35 BL_AUTO_ADJ); 35 ADP5520_BL_AUTO_ADJ);
36 ret |= adp5520_write(master, DAYLIGHT_MAX, brightness); 36 ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX,
37 brightness);
37 } else { 38 } else {
38 /* 39 /*
39 * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust 40 * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
40 * restore daylight l3 sysfs brightness 41 * restore daylight l3 sysfs brightness
41 */ 42 */
42 ret |= adp5520_write(master, DAYLIGHT_MAX, 43 ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX,
43 data->cached_daylight_max); 44 data->cached_daylight_max);
44 ret |= adp5520_set_bits(master, BL_CONTROL, 45 ret |= adp5520_set_bits(master, ADP5520_BL_CONTROL,
45 BL_AUTO_ADJ); 46 ADP5520_BL_AUTO_ADJ);
46 } 47 }
47 } else { 48 } else {
48 ret |= adp5520_write(master, DAYLIGHT_MAX, brightness); 49 ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX, brightness);
49 } 50 }
50 51
51 if (data->current_brightness && brightness == 0) 52 if (data->current_brightness && brightness == 0)
52 ret |= adp5520_set_bits(master, 53 ret |= adp5520_set_bits(master,
53 MODE_STATUS, DIM_EN); 54 ADP5520_MODE_STATUS, ADP5520_DIM_EN);
54 else if (data->current_brightness == 0 && brightness) 55 else if (data->current_brightness == 0 && brightness)
55 ret |= adp5520_clr_bits(master, 56 ret |= adp5520_clr_bits(master,
56 MODE_STATUS, DIM_EN); 57 ADP5520_MODE_STATUS, ADP5520_DIM_EN);
57 58
58 if (!ret) 59 if (!ret)
59 data->current_brightness = brightness; 60 data->current_brightness = brightness;
@@ -79,12 +80,12 @@ static int adp5520_bl_get_brightness(struct backlight_device *bl)
79 int error; 80 int error;
80 uint8_t reg_val; 81 uint8_t reg_val;
81 82
82 error = adp5520_read(data->master, BL_VALUE, &reg_val); 83 error = adp5520_read(data->master, ADP5520_BL_VALUE, &reg_val);
83 84
84 return error ? data->current_brightness : reg_val; 85 return error ? data->current_brightness : reg_val;
85} 86}
86 87
87static struct backlight_ops adp5520_bl_ops = { 88static const struct backlight_ops adp5520_bl_ops = {
88 .update_status = adp5520_bl_update_status, 89 .update_status = adp5520_bl_update_status,
89 .get_brightness = adp5520_bl_get_brightness, 90 .get_brightness = adp5520_bl_get_brightness,
90}; 91};
@@ -93,33 +94,46 @@ static int adp5520_bl_setup(struct backlight_device *bl)
93{ 94{
94 struct adp5520_bl *data = bl_get_data(bl); 95 struct adp5520_bl *data = bl_get_data(bl);
95 struct device *master = data->master; 96 struct device *master = data->master;
96 struct adp5520_backlight_platfrom_data *pdata = data->pdata; 97 struct adp5520_backlight_platform_data *pdata = data->pdata;
97 int ret = 0; 98 int ret = 0;
98 99
99 ret |= adp5520_write(master, DAYLIGHT_MAX, pdata->l1_daylight_max); 100 ret |= adp5520_write(master, ADP5520_DAYLIGHT_MAX,
100 ret |= adp5520_write(master, DAYLIGHT_DIM, pdata->l1_daylight_dim); 101 pdata->l1_daylight_max);
102 ret |= adp5520_write(master, ADP5520_DAYLIGHT_DIM,
103 pdata->l1_daylight_dim);
101 104
102 if (pdata->en_ambl_sens) { 105 if (pdata->en_ambl_sens) {
103 data->cached_daylight_max = pdata->l1_daylight_max; 106 data->cached_daylight_max = pdata->l1_daylight_max;
104 ret |= adp5520_write(master, OFFICE_MAX, pdata->l2_office_max); 107 ret |= adp5520_write(master, ADP5520_OFFICE_MAX,
105 ret |= adp5520_write(master, OFFICE_DIM, pdata->l2_office_dim); 108 pdata->l2_office_max);
106 ret |= adp5520_write(master, DARK_MAX, pdata->l3_dark_max); 109 ret |= adp5520_write(master, ADP5520_OFFICE_DIM,
107 ret |= adp5520_write(master, DARK_DIM, pdata->l3_dark_dim); 110 pdata->l2_office_dim);
108 ret |= adp5520_write(master, L2_TRIP, pdata->l2_trip); 111 ret |= adp5520_write(master, ADP5520_DARK_MAX,
109 ret |= adp5520_write(master, L2_HYS, pdata->l2_hyst); 112 pdata->l3_dark_max);
110 ret |= adp5520_write(master, L3_TRIP, pdata->l3_trip); 113 ret |= adp5520_write(master, ADP5520_DARK_DIM,
111 ret |= adp5520_write(master, L3_HYS, pdata->l3_hyst); 114 pdata->l3_dark_dim);
112 ret |= adp5520_write(master, ALS_CMPR_CFG, 115 ret |= adp5520_write(master, ADP5520_L2_TRIP,
113 ALS_CMPR_CFG_VAL(pdata->abml_filt, L3_EN)); 116 pdata->l2_trip);
117 ret |= adp5520_write(master, ADP5520_L2_HYS,
118 pdata->l2_hyst);
119 ret |= adp5520_write(master, ADP5520_L3_TRIP,
120 pdata->l3_trip);
121 ret |= adp5520_write(master, ADP5520_L3_HYS,
122 pdata->l3_hyst);
123 ret |= adp5520_write(master, ADP5520_ALS_CMPR_CFG,
124 ALS_CMPR_CFG_VAL(pdata->abml_filt,
125 ADP5520_L3_EN));
114 } 126 }
115 127
116 ret |= adp5520_write(master, BL_CONTROL, 128 ret |= adp5520_write(master, ADP5520_BL_CONTROL,
117 BL_CTRL_VAL(pdata->fade_led_law, pdata->en_ambl_sens)); 129 BL_CTRL_VAL(pdata->fade_led_law,
130 pdata->en_ambl_sens));
118 131
119 ret |= adp5520_write(master, BL_FADE, FADE_VAL(pdata->fade_in, 132 ret |= adp5520_write(master, ADP5520_BL_FADE, FADE_VAL(pdata->fade_in,
120 pdata->fade_out)); 133 pdata->fade_out));
121 134
122 ret |= adp5520_set_bits(master, MODE_STATUS, BL_EN | DIM_EN); 135 ret |= adp5520_set_bits(master, ADP5520_MODE_STATUS,
136 ADP5520_BL_EN | ADP5520_DIM_EN);
123 137
124 return ret; 138 return ret;
125} 139}
@@ -156,29 +170,31 @@ static ssize_t adp5520_store(struct device *dev, const char *buf,
156} 170}
157 171
158static ssize_t adp5520_bl_dark_max_show(struct device *dev, 172static ssize_t adp5520_bl_dark_max_show(struct device *dev,
159 struct device_attribute *attr, char *buf) 173 struct device_attribute *attr, char *buf)
160{ 174{
161 return adp5520_show(dev, buf, DARK_MAX); 175 return adp5520_show(dev, buf, ADP5520_DARK_MAX);
162} 176}
163 177
164static ssize_t adp5520_bl_dark_max_store(struct device *dev, 178static ssize_t adp5520_bl_dark_max_store(struct device *dev,
165 struct device_attribute *attr, const char *buf, size_t count) 179 struct device_attribute *attr,
180 const char *buf, size_t count)
166{ 181{
167 return adp5520_store(dev, buf, count, DARK_MAX); 182 return adp5520_store(dev, buf, count, ADP5520_DARK_MAX);
168} 183}
169static DEVICE_ATTR(dark_max, 0664, adp5520_bl_dark_max_show, 184static DEVICE_ATTR(dark_max, 0664, adp5520_bl_dark_max_show,
170 adp5520_bl_dark_max_store); 185 adp5520_bl_dark_max_store);
171 186
172static ssize_t adp5520_bl_office_max_show(struct device *dev, 187static ssize_t adp5520_bl_office_max_show(struct device *dev,
173 struct device_attribute *attr, char *buf) 188 struct device_attribute *attr, char *buf)
174{ 189{
175 return adp5520_show(dev, buf, OFFICE_MAX); 190 return adp5520_show(dev, buf, ADP5520_OFFICE_MAX);
176} 191}
177 192
178static ssize_t adp5520_bl_office_max_store(struct device *dev, 193static ssize_t adp5520_bl_office_max_store(struct device *dev,
179 struct device_attribute *attr, const char *buf, size_t count) 194 struct device_attribute *attr,
195 const char *buf, size_t count)
180{ 196{
181 return adp5520_store(dev, buf, count, OFFICE_MAX); 197 return adp5520_store(dev, buf, count, ADP5520_OFFICE_MAX);
182} 198}
183static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show, 199static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show,
184 adp5520_bl_office_max_store); 200 adp5520_bl_office_max_store);
@@ -186,16 +202,17 @@ static DEVICE_ATTR(office_max, 0664, adp5520_bl_office_max_show,
186static ssize_t adp5520_bl_daylight_max_show(struct device *dev, 202static ssize_t adp5520_bl_daylight_max_show(struct device *dev,
187 struct device_attribute *attr, char *buf) 203 struct device_attribute *attr, char *buf)
188{ 204{
189 return adp5520_show(dev, buf, DAYLIGHT_MAX); 205 return adp5520_show(dev, buf, ADP5520_DAYLIGHT_MAX);
190} 206}
191 207
192static ssize_t adp5520_bl_daylight_max_store(struct device *dev, 208static ssize_t adp5520_bl_daylight_max_store(struct device *dev,
193 struct device_attribute *attr, const char *buf, size_t count) 209 struct device_attribute *attr,
210 const char *buf, size_t count)
194{ 211{
195 struct adp5520_bl *data = dev_get_drvdata(dev); 212 struct adp5520_bl *data = dev_get_drvdata(dev);
196 213
197 strict_strtoul(buf, 10, &data->cached_daylight_max); 214 strict_strtoul(buf, 10, &data->cached_daylight_max);
198 return adp5520_store(dev, buf, count, DAYLIGHT_MAX); 215 return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_MAX);
199} 216}
200static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show, 217static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
201 adp5520_bl_daylight_max_store); 218 adp5520_bl_daylight_max_store);
@@ -203,14 +220,14 @@ static DEVICE_ATTR(daylight_max, 0664, adp5520_bl_daylight_max_show,
203static ssize_t adp5520_bl_dark_dim_show(struct device *dev, 220static ssize_t adp5520_bl_dark_dim_show(struct device *dev,
204 struct device_attribute *attr, char *buf) 221 struct device_attribute *attr, char *buf)
205{ 222{
206 return adp5520_show(dev, buf, DARK_DIM); 223 return adp5520_show(dev, buf, ADP5520_DARK_DIM);
207} 224}
208 225
209static ssize_t adp5520_bl_dark_dim_store(struct device *dev, 226static ssize_t adp5520_bl_dark_dim_store(struct device *dev,
210 struct device_attribute *attr, 227 struct device_attribute *attr,
211 const char *buf, size_t count) 228 const char *buf, size_t count)
212{ 229{
213 return adp5520_store(dev, buf, count, DARK_DIM); 230 return adp5520_store(dev, buf, count, ADP5520_DARK_DIM);
214} 231}
215static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show, 232static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show,
216 adp5520_bl_dark_dim_store); 233 adp5520_bl_dark_dim_store);
@@ -218,29 +235,29 @@ static DEVICE_ATTR(dark_dim, 0664, adp5520_bl_dark_dim_show,
218static ssize_t adp5520_bl_office_dim_show(struct device *dev, 235static ssize_t adp5520_bl_office_dim_show(struct device *dev,
219 struct device_attribute *attr, char *buf) 236 struct device_attribute *attr, char *buf)
220{ 237{
221 return adp5520_show(dev, buf, OFFICE_DIM); 238 return adp5520_show(dev, buf, ADP5520_OFFICE_DIM);
222} 239}
223 240
224static ssize_t adp5520_bl_office_dim_store(struct device *dev, 241static ssize_t adp5520_bl_office_dim_store(struct device *dev,
225 struct device_attribute *attr, 242 struct device_attribute *attr,
226 const char *buf, size_t count) 243 const char *buf, size_t count)
227{ 244{
228 return adp5520_store(dev, buf, count, OFFICE_DIM); 245 return adp5520_store(dev, buf, count, ADP5520_OFFICE_DIM);
229} 246}
230static DEVICE_ATTR(office_dim, 0664, adp5520_bl_office_dim_show, 247static DEVICE_ATTR(office_dim, 0664, adp5520_bl_office_dim_show,
231 adp5520_bl_office_dim_store); 248 adp5520_bl_office_dim_store);
232 249
233static ssize_t adp5520_bl_daylight_dim_show(struct device *dev, 250static ssize_t adp5520_bl_daylight_dim_show(struct device *dev,
234 struct device_attribute *attr, char *buf) 251 struct device_attribute *attr, char *buf)
235{ 252{
236 return adp5520_show(dev, buf, DAYLIGHT_DIM); 253 return adp5520_show(dev, buf, ADP5520_DAYLIGHT_DIM);
237} 254}
238 255
239static ssize_t adp5520_bl_daylight_dim_store(struct device *dev, 256static ssize_t adp5520_bl_daylight_dim_store(struct device *dev,
240 struct device_attribute *attr, 257 struct device_attribute *attr,
241 const char *buf, size_t count) 258 const char *buf, size_t count)
242{ 259{
243 return adp5520_store(dev, buf, count, DAYLIGHT_DIM); 260 return adp5520_store(dev, buf, count, ADP5520_DAYLIGHT_DIM);
244} 261}
245static DEVICE_ATTR(daylight_dim, 0664, adp5520_bl_daylight_dim_show, 262static DEVICE_ATTR(daylight_dim, 0664, adp5520_bl_daylight_dim_show,
246 adp5520_bl_daylight_dim_store); 263 adp5520_bl_daylight_dim_store);
@@ -316,7 +333,7 @@ static int __devexit adp5520_bl_remove(struct platform_device *pdev)
316 struct backlight_device *bl = platform_get_drvdata(pdev); 333 struct backlight_device *bl = platform_get_drvdata(pdev);
317 struct adp5520_bl *data = bl_get_data(bl); 334 struct adp5520_bl *data = bl_get_data(bl);
318 335
319 adp5520_clr_bits(data->master, MODE_STATUS, BL_EN); 336 adp5520_clr_bits(data->master, ADP5520_MODE_STATUS, ADP5520_BL_EN);
320 337
321 if (data->pdata->en_ambl_sens) 338 if (data->pdata->en_ambl_sens)
322 sysfs_remove_group(&bl->dev.kobj, 339 sysfs_remove_group(&bl->dev.kobj,
diff --git a/drivers/video/backlight/adx_bl.c b/drivers/video/backlight/adx_bl.c
index 2c3bdfc620b7..d769b0bab21a 100644
--- a/drivers/video/backlight/adx_bl.c
+++ b/drivers/video/backlight/adx_bl.c
@@ -61,7 +61,7 @@ static int adx_backlight_check_fb(struct fb_info *fb)
61 return 1; 61 return 1;
62} 62}
63 63
64static struct backlight_ops adx_backlight_ops = { 64static const struct backlight_ops adx_backlight_ops = {
65 .options = 0, 65 .options = 0,
66 .update_status = adx_backlight_update_status, 66 .update_status = adx_backlight_update_status,
67 .get_brightness = adx_backlight_get_brightness, 67 .get_brightness = adx_backlight_get_brightness,
diff --git a/drivers/video/backlight/atmel-pwm-bl.c b/drivers/video/backlight/atmel-pwm-bl.c
index 505c0823a105..f625ffc69ad3 100644
--- a/drivers/video/backlight/atmel-pwm-bl.c
+++ b/drivers/video/backlight/atmel-pwm-bl.c
@@ -113,7 +113,7 @@ static int atmel_pwm_bl_init_pwm(struct atmel_pwm_bl *pwmbl)
113 return pwm_channel_enable(&pwmbl->pwmc); 113 return pwm_channel_enable(&pwmbl->pwmc);
114} 114}
115 115
116static struct backlight_ops atmel_pwm_bl_ops = { 116static const struct backlight_ops atmel_pwm_bl_ops = {
117 .get_brightness = atmel_pwm_bl_get_intensity, 117 .get_brightness = atmel_pwm_bl_get_intensity,
118 .update_status = atmel_pwm_bl_set_intensity, 118 .update_status = atmel_pwm_bl_set_intensity,
119}; 119};
@@ -158,7 +158,7 @@ static int atmel_pwm_bl_probe(struct platform_device *pdev)
158 goto err_free_pwm; 158 goto err_free_pwm;
159 } 159 }
160 160
161 /* Turn display off by defatult. */ 161 /* Turn display off by default. */
162 retval = gpio_direction_output(pwmbl->gpio_on, 162 retval = gpio_direction_output(pwmbl->gpio_on,
163 0 ^ pdata->on_active_low); 163 0 ^ pdata->on_active_low);
164 if (retval) 164 if (retval)
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index 6615ac7fa60a..18829cf68b1b 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -269,7 +269,7 @@ EXPORT_SYMBOL(backlight_force_update);
269 * ERR_PTR() or a pointer to the newly allocated device. 269 * ERR_PTR() or a pointer to the newly allocated device.
270 */ 270 */
271struct backlight_device *backlight_device_register(const char *name, 271struct backlight_device *backlight_device_register(const char *name,
272 struct device *parent, void *devdata, struct backlight_ops *ops) 272 struct device *parent, void *devdata, const struct backlight_ops *ops)
273{ 273{
274 struct backlight_device *new_bd; 274 struct backlight_device *new_bd;
275 int rc; 275 int rc;
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c
index 96774949cd30..b4bcf8043797 100644
--- a/drivers/video/backlight/corgi_lcd.c
+++ b/drivers/video/backlight/corgi_lcd.c
@@ -451,7 +451,7 @@ void corgi_lcd_limit_intensity(int limit)
451} 451}
452EXPORT_SYMBOL(corgi_lcd_limit_intensity); 452EXPORT_SYMBOL(corgi_lcd_limit_intensity);
453 453
454static struct backlight_ops corgi_bl_ops = { 454static const struct backlight_ops corgi_bl_ops = {
455 .get_brightness = corgi_bl_get_intensity, 455 .get_brightness = corgi_bl_get_intensity,
456 .update_status = corgi_bl_update_status, 456 .update_status = corgi_bl_update_status,
457}; 457};
diff --git a/drivers/video/backlight/cr_bllcd.c b/drivers/video/backlight/cr_bllcd.c
index b9fe62b475c6..da86db4374a0 100644
--- a/drivers/video/backlight/cr_bllcd.c
+++ b/drivers/video/backlight/cr_bllcd.c
@@ -108,7 +108,7 @@ static int cr_backlight_get_intensity(struct backlight_device *bd)
108 return intensity; 108 return intensity;
109} 109}
110 110
111static struct backlight_ops cr_backlight_ops = { 111static const struct backlight_ops cr_backlight_ops = {
112 .get_brightness = cr_backlight_get_intensity, 112 .get_brightness = cr_backlight_get_intensity,
113 .update_status = cr_backlight_set_intensity, 113 .update_status = cr_backlight_set_intensity,
114}; 114};
@@ -201,7 +201,7 @@ static int cr_backlight_probe(struct platform_device *pdev)
201 if (IS_ERR(ldp)) { 201 if (IS_ERR(ldp)) {
202 backlight_device_unregister(bdp); 202 backlight_device_unregister(bdp);
203 pci_dev_put(lpc_dev); 203 pci_dev_put(lpc_dev);
204 return PTR_ERR(bdp); 204 return PTR_ERR(ldp);
205 } 205 }
206 206
207 pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR, 207 pci_read_config_dword(lpc_dev, CRVML_REG_GPIOBAR,
diff --git a/drivers/video/backlight/da903x_bl.c b/drivers/video/backlight/da903x_bl.c
index 701a1081e199..74cdc640173d 100644
--- a/drivers/video/backlight/da903x_bl.c
+++ b/drivers/video/backlight/da903x_bl.c
@@ -25,6 +25,7 @@
25 25
26#define DA9034_WLED_CONTROL1 0x3C 26#define DA9034_WLED_CONTROL1 0x3C
27#define DA9034_WLED_CONTROL2 0x3D 27#define DA9034_WLED_CONTROL2 0x3D
28#define DA9034_WLED_ISET(x) ((x) & 0x1f)
28 29
29#define DA9034_WLED_BOOST_EN (1 << 5) 30#define DA9034_WLED_BOOST_EN (1 << 5)
30 31
@@ -94,13 +95,14 @@ static int da903x_backlight_get_brightness(struct backlight_device *bl)
94 return data->current_brightness; 95 return data->current_brightness;
95} 96}
96 97
97static struct backlight_ops da903x_backlight_ops = { 98static const struct backlight_ops da903x_backlight_ops = {
98 .update_status = da903x_backlight_update_status, 99 .update_status = da903x_backlight_update_status,
99 .get_brightness = da903x_backlight_get_brightness, 100 .get_brightness = da903x_backlight_get_brightness,
100}; 101};
101 102
102static int da903x_backlight_probe(struct platform_device *pdev) 103static int da903x_backlight_probe(struct platform_device *pdev)
103{ 104{
105 struct da9034_backlight_pdata *pdata = pdev->dev.platform_data;
104 struct da903x_backlight_data *data; 106 struct da903x_backlight_data *data;
105 struct backlight_device *bl; 107 struct backlight_device *bl;
106 int max_brightness; 108 int max_brightness;
@@ -127,6 +129,11 @@ static int da903x_backlight_probe(struct platform_device *pdev)
127 data->da903x_dev = pdev->dev.parent; 129 data->da903x_dev = pdev->dev.parent;
128 data->current_brightness = 0; 130 data->current_brightness = 0;
129 131
132 /* adjust the WLED output current */
133 if (pdata)
134 da903x_write(data->da903x_dev, DA9034_WLED_CONTROL2,
135 DA9034_WLED_ISET(pdata->output_current));
136
130 bl = backlight_device_register(pdev->name, data->da903x_dev, 137 bl = backlight_device_register(pdev->name, data->da903x_dev,
131 data, &da903x_backlight_ops); 138 data, &da903x_backlight_ops);
132 if (IS_ERR(bl)) { 139 if (IS_ERR(bl)) {
@@ -170,7 +177,7 @@ static int da903x_backlight_resume(struct device *dev)
170 return 0; 177 return 0;
171} 178}
172 179
173static struct dev_pm_ops da903x_backlight_pm_ops = { 180static const struct dev_pm_ops da903x_backlight_pm_ops = {
174 .suspend = da903x_backlight_suspend, 181 .suspend = da903x_backlight_suspend,
175 .resume = da903x_backlight_resume, 182 .resume = da903x_backlight_resume,
176}; 183};
diff --git a/drivers/video/backlight/generic_bl.c b/drivers/video/backlight/generic_bl.c
index 6d27f62fdcd0..e6d348e63596 100644
--- a/drivers/video/backlight/generic_bl.c
+++ b/drivers/video/backlight/generic_bl.c
@@ -70,7 +70,7 @@ void corgibl_limit_intensity(int limit)
70} 70}
71EXPORT_SYMBOL(corgibl_limit_intensity); 71EXPORT_SYMBOL(corgibl_limit_intensity);
72 72
73static struct backlight_ops genericbl_ops = { 73static const struct backlight_ops genericbl_ops = {
74 .options = BL_CORE_SUSPENDRESUME, 74 .options = BL_CORE_SUSPENDRESUME,
75 .get_brightness = genericbl_get_intensity, 75 .get_brightness = genericbl_get_intensity,
76 .update_status = genericbl_send_intensity, 76 .update_status = genericbl_send_intensity,
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index 7fb4eefff80d..f7cc528d5be7 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -98,7 +98,7 @@ static int hp680bl_get_intensity(struct backlight_device *bd)
98 return current_intensity; 98 return current_intensity;
99} 99}
100 100
101static struct backlight_ops hp680bl_ops = { 101static const struct backlight_ops hp680bl_ops = {
102 .get_brightness = hp680bl_get_intensity, 102 .get_brightness = hp680bl_get_intensity,
103 .update_status = hp680bl_set_intensity, 103 .update_status = hp680bl_set_intensity,
104}; 104};
diff --git a/drivers/video/backlight/jornada720_bl.c b/drivers/video/backlight/jornada720_bl.c
index 7aed2565c1bd..db9071fc5665 100644
--- a/drivers/video/backlight/jornada720_bl.c
+++ b/drivers/video/backlight/jornada720_bl.c
@@ -93,7 +93,7 @@ out:
93 return ret; 93 return ret;
94} 94}
95 95
96static struct backlight_ops jornada_bl_ops = { 96static const struct backlight_ops jornada_bl_ops = {
97 .get_brightness = jornada_bl_get_brightness, 97 .get_brightness = jornada_bl_get_brightness,
98 .update_status = jornada_bl_update_status, 98 .update_status = jornada_bl_update_status,
99 .options = BL_CORE_SUSPENDRESUME, 99 .options = BL_CORE_SUSPENDRESUME,
diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c
index a38fda1742dd..939e7b830cf3 100644
--- a/drivers/video/backlight/kb3886_bl.c
+++ b/drivers/video/backlight/kb3886_bl.c
@@ -134,7 +134,7 @@ static int kb3886bl_get_intensity(struct backlight_device *bd)
134 return kb3886bl_intensity; 134 return kb3886bl_intensity;
135} 135}
136 136
137static struct backlight_ops kb3886bl_ops = { 137static const struct backlight_ops kb3886bl_ops = {
138 .get_brightness = kb3886bl_get_intensity, 138 .get_brightness = kb3886bl_get_intensity,
139 .update_status = kb3886bl_send_intensity, 139 .update_status = kb3886bl_send_intensity,
140}; 140};
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index a482dd7b0311..9b3be74cee5a 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -101,7 +101,7 @@ static ssize_t lcd_store_power(struct device *dev,
101 int power = simple_strtoul(buf, &endp, 0); 101 int power = simple_strtoul(buf, &endp, 0);
102 size_t size = endp - buf; 102 size_t size = endp - buf;
103 103
104 if (*endp && isspace(*endp)) 104 if (isspace(*endp))
105 size++; 105 size++;
106 if (size != count) 106 if (size != count)
107 return -EINVAL; 107 return -EINVAL;
@@ -140,7 +140,7 @@ static ssize_t lcd_store_contrast(struct device *dev,
140 int contrast = simple_strtoul(buf, &endp, 0); 140 int contrast = simple_strtoul(buf, &endp, 0);
141 size_t size = endp - buf; 141 size_t size = endp - buf;
142 142
143 if (*endp && isspace(*endp)) 143 if (isspace(*endp))
144 size++; 144 size++;
145 if (size != count) 145 if (size != count)
146 return -EINVAL; 146 return -EINVAL;
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index 6b488b8a7eee..00a9591b0003 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -141,7 +141,7 @@ static int locomolcd_get_intensity(struct backlight_device *bd)
141 return current_intensity; 141 return current_intensity;
142} 142}
143 143
144static struct backlight_ops locomobl_data = { 144static const struct backlight_ops locomobl_data = {
145 .get_brightness = locomolcd_get_intensity, 145 .get_brightness = locomolcd_get_intensity,
146 .update_status = locomolcd_set_intensity, 146 .update_status = locomolcd_set_intensity,
147}; 147};
diff --git a/drivers/video/backlight/mbp_nvidia_bl.c b/drivers/video/backlight/mbp_nvidia_bl.c
index 9edb8d7c295f..2e78b0784bdc 100644
--- a/drivers/video/backlight/mbp_nvidia_bl.c
+++ b/drivers/video/backlight/mbp_nvidia_bl.c
@@ -33,7 +33,7 @@ struct dmi_match_data {
33 unsigned long iostart; 33 unsigned long iostart;
34 unsigned long iolen; 34 unsigned long iolen;
35 /* Backlight operations structure. */ 35 /* Backlight operations structure. */
36 struct backlight_ops backlight_ops; 36 const struct backlight_ops backlight_ops;
37}; 37};
38 38
39/* Module parameters. */ 39/* Module parameters. */
@@ -220,6 +220,24 @@ static const struct dmi_system_id __initdata mbp_device_table[] = {
220 }, 220 },
221 { 221 {
222 .callback = mbp_dmi_match, 222 .callback = mbp_dmi_match,
223 .ident = "MacBookPro 5,3",
224 .matches = {
225 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
226 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,3"),
227 },
228 .driver_data = (void *)&nvidia_chipset_data,
229 },
230 {
231 .callback = mbp_dmi_match,
232 .ident = "MacBookPro 5,4",
233 .matches = {
234 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
235 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5,4"),
236 },
237 .driver_data = (void *)&nvidia_chipset_data,
238 },
239 {
240 .callback = mbp_dmi_match,
223 .ident = "MacBookPro 5,5", 241 .ident = "MacBookPro 5,5",
224 .matches = { 242 .matches = {
225 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), 243 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
diff --git a/drivers/video/backlight/omap1_bl.c b/drivers/video/backlight/omap1_bl.c
index cbad67e89826..a3a7f8938175 100644
--- a/drivers/video/backlight/omap1_bl.c
+++ b/drivers/video/backlight/omap1_bl.c
@@ -26,8 +26,8 @@
26#include <linux/backlight.h> 26#include <linux/backlight.h>
27 27
28#include <mach/hardware.h> 28#include <mach/hardware.h>
29#include <mach/board.h> 29#include <plat/board.h>
30#include <mach/mux.h> 30#include <plat/mux.h>
31 31
32#define OMAPBL_MAX_INTENSITY 0xff 32#define OMAPBL_MAX_INTENSITY 0xff
33 33
@@ -125,7 +125,7 @@ static int omapbl_get_intensity(struct backlight_device *dev)
125 return bl->current_intensity; 125 return bl->current_intensity;
126} 126}
127 127
128static struct backlight_ops omapbl_ops = { 128static const struct backlight_ops omapbl_ops = {
129 .get_brightness = omapbl_get_intensity, 129 .get_brightness = omapbl_get_intensity,
130 .update_status = omapbl_update_status, 130 .update_status = omapbl_update_status,
131}; 131};
@@ -139,8 +139,6 @@ static int omapbl_probe(struct platform_device *pdev)
139 if (!pdata) 139 if (!pdata)
140 return -ENXIO; 140 return -ENXIO;
141 141
142 omapbl_ops.check_fb = pdata->check_fb;
143
144 bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL); 142 bl = kzalloc(sizeof(struct omap_backlight), GFP_KERNEL);
145 if (unlikely(!bl)) 143 if (unlikely(!bl))
146 return -ENOMEM; 144 return -ENOMEM;
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c
index 9edaf24fd82d..075786e05034 100644
--- a/drivers/video/backlight/progear_bl.c
+++ b/drivers/video/backlight/progear_bl.c
@@ -54,7 +54,7 @@ static int progearbl_get_intensity(struct backlight_device *bd)
54 return intensity - HW_LEVEL_MIN; 54 return intensity - HW_LEVEL_MIN;
55} 55}
56 56
57static struct backlight_ops progearbl_ops = { 57static const struct backlight_ops progearbl_ops = {
58 .get_brightness = progearbl_get_intensity, 58 .get_brightness = progearbl_get_intensity,
59 .update_status = progearbl_set_intensity, 59 .update_status = progearbl_set_intensity,
60}; 60};
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index 887166267443..9d2ec2a1cce8 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -22,8 +22,10 @@
22 22
23struct pwm_bl_data { 23struct pwm_bl_data {
24 struct pwm_device *pwm; 24 struct pwm_device *pwm;
25 struct device *dev;
25 unsigned int period; 26 unsigned int period;
26 int (*notify)(int brightness); 27 int (*notify)(struct device *,
28 int brightness);
27}; 29};
28 30
29static int pwm_backlight_update_status(struct backlight_device *bl) 31static int pwm_backlight_update_status(struct backlight_device *bl)
@@ -39,7 +41,7 @@ static int pwm_backlight_update_status(struct backlight_device *bl)
39 brightness = 0; 41 brightness = 0;
40 42
41 if (pb->notify) 43 if (pb->notify)
42 brightness = pb->notify(brightness); 44 brightness = pb->notify(pb->dev, brightness);
43 45
44 if (brightness == 0) { 46 if (brightness == 0) {
45 pwm_config(pb->pwm, 0, pb->period); 47 pwm_config(pb->pwm, 0, pb->period);
@@ -56,7 +58,7 @@ static int pwm_backlight_get_brightness(struct backlight_device *bl)
56 return bl->props.brightness; 58 return bl->props.brightness;
57} 59}
58 60
59static struct backlight_ops pwm_backlight_ops = { 61static const struct backlight_ops pwm_backlight_ops = {
60 .update_status = pwm_backlight_update_status, 62 .update_status = pwm_backlight_update_status,
61 .get_brightness = pwm_backlight_get_brightness, 63 .get_brightness = pwm_backlight_get_brightness,
62}; 64};
@@ -88,6 +90,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
88 90
89 pb->period = data->pwm_period_ns; 91 pb->period = data->pwm_period_ns;
90 pb->notify = data->notify; 92 pb->notify = data->notify;
93 pb->dev = &pdev->dev;
91 94
92 pb->pwm = pwm_request(data->pwm_id, "backlight"); 95 pb->pwm = pwm_request(data->pwm_id, "backlight");
93 if (IS_ERR(pb->pwm)) { 96 if (IS_ERR(pb->pwm)) {
@@ -146,7 +149,7 @@ static int pwm_backlight_suspend(struct platform_device *pdev,
146 struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev); 149 struct pwm_bl_data *pb = dev_get_drvdata(&bl->dev);
147 150
148 if (pb->notify) 151 if (pb->notify)
149 pb->notify(0); 152 pb->notify(pb->dev, 0);
150 pwm_config(pb->pwm, 0, pb->period); 153 pwm_config(pb->pwm, 0, pb->period);
151 pwm_disable(pb->pwm); 154 pwm_disable(pb->pwm);
152 return 0; 155 return 0;
diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c
index bbfb502add67..4a3d46e08016 100644
--- a/drivers/video/backlight/tdo24m.c
+++ b/drivers/video/backlight/tdo24m.c
@@ -367,6 +367,7 @@ static int __devinit tdo24m_probe(struct spi_device *spi)
367 367
368 spi_message_init(m); 368 spi_message_init(m);
369 369
370 x->cs_change = 1;
370 x->tx_buf = &lcd->buf[0]; 371 x->tx_buf = &lcd->buf[0];
371 spi_message_add_tail(x, m); 372 spi_message_add_tail(x, m);
372 373
diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
index 43edbada12d1..e14ce4d469f5 100644
--- a/drivers/video/backlight/tosa_bl.c
+++ b/drivers/video/backlight/tosa_bl.c
@@ -72,7 +72,7 @@ static int tosa_bl_get_brightness(struct backlight_device *dev)
72 return props->brightness; 72 return props->brightness;
73} 73}
74 74
75static struct backlight_ops bl_ops = { 75static const struct backlight_ops bl_ops = {
76 .get_brightness = tosa_bl_get_brightness, 76 .get_brightness = tosa_bl_get_brightness,
77 .update_status = tosa_bl_update_status, 77 .update_status = tosa_bl_update_status,
78}; 78};
diff --git a/drivers/video/backlight/tosa_lcd.c b/drivers/video/backlight/tosa_lcd.c
index 50ec17dfc517..fa32b94a4546 100644
--- a/drivers/video/backlight/tosa_lcd.c
+++ b/drivers/video/backlight/tosa_lcd.c
@@ -177,7 +177,7 @@ static int __devinit tosa_lcd_probe(struct spi_device *spi)
177 if (!data) 177 if (!data)
178 return -ENOMEM; 178 return -ENOMEM;
179 179
180 data->is_vga = true; /* defaut to VGA mode */ 180 data->is_vga = true; /* default to VGA mode */
181 181
182 /* 182 /*
183 * bits_per_word cannot be configured in platform data 183 * bits_per_word cannot be configured in platform data
diff --git a/drivers/video/backlight/wm831x_bl.c b/drivers/video/backlight/wm831x_bl.c
index 467bdb7efb23..e32add37a203 100644
--- a/drivers/video/backlight/wm831x_bl.c
+++ b/drivers/video/backlight/wm831x_bl.c
@@ -112,7 +112,7 @@ static int wm831x_backlight_get_brightness(struct backlight_device *bl)
112 return data->current_brightness; 112 return data->current_brightness;
113} 113}
114 114
115static struct backlight_ops wm831x_backlight_ops = { 115static const struct backlight_ops wm831x_backlight_ops = {
116 .options = BL_CORE_SUSPENDRESUME, 116 .options = BL_CORE_SUSPENDRESUME,
117 .update_status = wm831x_backlight_update_status, 117 .update_status = wm831x_backlight_update_status,
118 .get_brightness = wm831x_backlight_get_brightness, 118 .get_brightness = wm831x_backlight_get_brightness,
diff --git a/drivers/video/bfin-lq035q1-fb.c b/drivers/video/bfin-lq035q1-fb.c
new file mode 100644
index 000000000000..b690c269784a
--- /dev/null
+++ b/drivers/video/bfin-lq035q1-fb.c
@@ -0,0 +1,826 @@
1/*
2 * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02
3 *
4 * Copyright 2008-2009 Analog Devices Inc.
5 * Licensed under the GPL-2 or later.
6 */
7
8#define DRIVER_NAME "bfin-lq035q1"
9#define pr_fmt(fmt) DRIVER_NAME ": " fmt
10
11#include <linux/module.h>
12#include <linux/kernel.h>
13#include <linux/errno.h>
14#include <linux/string.h>
15#include <linux/fb.h>
16#include <linux/init.h>
17#include <linux/types.h>
18#include <linux/interrupt.h>
19#include <linux/device.h>
20#include <linux/backlight.h>
21#include <linux/lcd.h>
22#include <linux/dma-mapping.h>
23#include <linux/platform_device.h>
24#include <linux/spi/spi.h>
25#include <linux/dma-mapping.h>
26
27#include <asm/blackfin.h>
28#include <asm/irq.h>
29#include <asm/dma.h>
30#include <asm/portmux.h>
31#include <asm/gptimers.h>
32
33#include <asm/bfin-lq035q1.h>
34
35#if defined(BF533_FAMILY) || defined(BF538_FAMILY)
36#define TIMER_HSYNC_id TIMER1_id
37#define TIMER_HSYNCbit TIMER1bit
38#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1
39#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1
40#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1
41
42#define TIMER_VSYNC_id TIMER2_id
43#define TIMER_VSYNCbit TIMER2bit
44#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2
45#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2
46#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2
47#else
48#define TIMER_HSYNC_id TIMER0_id
49#define TIMER_HSYNCbit TIMER0bit
50#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0
51#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0
52#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0
53
54#define TIMER_VSYNC_id TIMER1_id
55#define TIMER_VSYNCbit TIMER1bit
56#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1
57#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1
58#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1
59#endif
60
61#define LCD_X_RES 320 /* Horizontal Resolution */
62#define LCD_Y_RES 240 /* Vertical Resolution */
63#define DMA_BUS_SIZE 16
64
65#define USE_RGB565_16_BIT_PPI
66
67#ifdef USE_RGB565_16_BIT_PPI
68#define LCD_BPP 16 /* Bit Per Pixel */
69#define CLOCKS_PER_PIX 1
70#define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */
71#endif
72
73/* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD)
74 * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165
75 */
76
77#ifdef USE_RGB565_8_BIT_PPI
78#define LCD_BPP 16 /* Bit Per Pixel */
79#define CLOCKS_PER_PIX 2
80#define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */
81#endif
82
83#ifdef USE_RGB888_8_BIT_PPI
84#define LCD_BPP 24 /* Bit Per Pixel */
85#define CLOCKS_PER_PIX 3
86#define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */
87#endif
88
89 /*
90 * HS and VS timing parameters (all in number of PPI clk ticks)
91 */
92
93#define U_LINE 4 /* Blanking Lines */
94
95#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */
96#define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */
97#define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */
98#define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */
99
100#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */
101#define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */
102#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */
103
104#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8))
105
106#define BFIN_LCD_NBR_PALETTE_ENTRIES 256
107
108#define PPI_TX_MODE 0x2
109#define PPI_XFER_TYPE_11 0xC
110#define PPI_PORT_CFG_01 0x10
111#define PPI_POLS_1 0x8000
112
113#if (CLOCKS_PER_PIX > 1)
114#define PPI_PMODE (DLEN_8 | PACK_EN)
115#else
116#define PPI_PMODE (DLEN_16)
117#endif
118
119#define LQ035_INDEX 0x74
120#define LQ035_DATA 0x76
121
122#define LQ035_DRIVER_OUTPUT_CTL 0x1
123#define LQ035_SHUT_CTL 0x11
124
125#define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV)
126#define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK)
127
128#define LQ035_SHUT (1 << 0) /* Shutdown */
129#define LQ035_ON (0 << 0) /* Shutdown */
130
131struct bfin_lq035q1fb_info {
132 struct fb_info *fb;
133 struct device *dev;
134 struct spi_driver spidrv;
135 struct bfin_lq035q1fb_disp_info *disp_info;
136 unsigned char *fb_buffer; /* RGB Buffer */
137 dma_addr_t dma_handle;
138 int lq035_open_cnt;
139 int irq;
140 spinlock_t lock; /* lock */
141 u32 pseudo_pal[16];
142};
143
144static int nocursor;
145module_param(nocursor, int, 0644);
146MODULE_PARM_DESC(nocursor, "cursor enable/disable");
147
148struct spi_control {
149 unsigned short mode;
150};
151
152static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned short value)
153{
154 int ret;
155 u8 regs[3] = { LQ035_INDEX, 0, 0 };
156 u8 dat[3] = { LQ035_DATA, 0, 0 };
157
158 if (!spi)
159 return -ENODEV;
160
161 regs[2] = reg;
162 dat[1] = value >> 8;
163 dat[2] = value & 0xFF;
164
165 ret = spi_write(spi, regs, ARRAY_SIZE(regs));
166 ret |= spi_write(spi, dat, ARRAY_SIZE(dat));
167 return ret;
168}
169
170static int __devinit lq035q1_spidev_probe(struct spi_device *spi)
171{
172 int ret;
173 struct spi_control *ctl;
174 struct bfin_lq035q1fb_info *info = container_of(spi->dev.driver,
175 struct bfin_lq035q1fb_info,
176 spidrv.driver);
177
178 ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
179
180 if (!ctl)
181 return -ENOMEM;
182
183 ctl->mode = (info->disp_info->mode &
184 LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT;
185
186 ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON);
187 ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode);
188 if (ret)
189 return ret;
190
191 spi_set_drvdata(spi, ctl);
192
193 return 0;
194}
195
196static int lq035q1_spidev_remove(struct spi_device *spi)
197{
198 return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
199}
200
201#ifdef CONFIG_PM
202static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state)
203{
204 return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
205}
206
207static int lq035q1_spidev_resume(struct spi_device *spi)
208{
209 int ret;
210 struct spi_control *ctl = spi_get_drvdata(spi);
211
212 ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode);
213 if (ret)
214 return ret;
215
216 return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON);
217}
218#else
219# define lq035q1_spidev_suspend NULL
220# define lq035q1_spidev_resume NULL
221#endif
222
223/* Power down all displays on reboot, poweroff or halt */
224static void lq035q1_spidev_shutdown(struct spi_device *spi)
225{
226 lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT);
227}
228
229static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg)
230{
231 if (info->disp_info->use_bl)
232 gpio_set_value(info->disp_info->gpio_bl, arg);
233
234 return 0;
235}
236
237static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi)
238{
239 bfin_write_PPI_DELAY(H_START);
240 bfin_write_PPI_COUNT(H_ACTPIX - 1);
241 bfin_write_PPI_FRAME(V_LINES);
242
243 bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */
244 PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */
245 PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */
246 PPI_PMODE | /* 8/16 bit data length / PACK_EN? */
247 PPI_POLS_1); /* faling edge syncs POLS */
248}
249
250static inline void bfin_lq035q1_disable_ppi(void)
251{
252 bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN);
253}
254
255static inline void bfin_lq035q1_enable_ppi(void)
256{
257 bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN);
258}
259
260static void bfin_lq035q1_start_timers(void)
261{
262 enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit);
263}
264
265static void bfin_lq035q1_stop_timers(void)
266{
267 disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit);
268
269 set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN |
270 TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL |
271 TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF);
272
273}
274
275static void bfin_lq035q1_init_timers(void)
276{
277
278 bfin_lq035q1_stop_timers();
279
280 set_gptimer_period(TIMER_HSYNC_id, H_PERIOD);
281 set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE);
282 set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
283 TIMER_TIN_SEL | TIMER_CLK_SEL|
284 TIMER_EMU_RUN);
285
286 set_gptimer_period(TIMER_VSYNC_id, V_PERIOD);
287 set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE);
288 set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT |
289 TIMER_TIN_SEL | TIMER_CLK_SEL |
290 TIMER_EMU_RUN);
291
292}
293
294static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi)
295{
296
297 set_dma_config(CH_PPI,
298 set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO,
299 INTR_DISABLE, DIMENSION_2D,
300 DATA_SIZE_16,
301 DMA_NOSYNC_KEEP_DMA_BUF));
302 set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE);
303 set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8);
304 set_dma_y_count(CH_PPI, V_LINES);
305
306 set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8);
307 set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer);
308
309}
310
311#if (CLOCKS_PER_PIX == 1)
312static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
313 P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
314 P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
315 P_PPI0_D6, P_PPI0_D7, P_PPI0_D8,
316 P_PPI0_D9, P_PPI0_D10, P_PPI0_D11,
317 P_PPI0_D12, P_PPI0_D13, P_PPI0_D14,
318 P_PPI0_D15, 0};
319#else
320static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2,
321 P_PPI0_D0, P_PPI0_D1, P_PPI0_D2,
322 P_PPI0_D3, P_PPI0_D4, P_PPI0_D5,
323 P_PPI0_D6, P_PPI0_D7, 0};
324#endif
325
326static inline void bfin_lq035q1_free_ports(void)
327{
328 peripheral_free_list(ppi0_req_16);
329 if (ANOMALY_05000400)
330 gpio_free(P_IDENT(P_PPI0_FS3));
331}
332
333static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev)
334{
335 /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode:
336 * Drive PPI_FS3 Low
337 */
338 if (ANOMALY_05000400) {
339 int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3");
340 if (ret)
341 return ret;
342 gpio_direction_output(P_IDENT(P_PPI0_FS3), 0);
343 }
344
345 if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) {
346 dev_err(&pdev->dev, "requesting peripherals failed\n");
347 return -EFAULT;
348 }
349
350 return 0;
351}
352
353static int bfin_lq035q1_fb_open(struct fb_info *info, int user)
354{
355 struct bfin_lq035q1fb_info *fbi = info->par;
356
357 spin_lock(&fbi->lock);
358 fbi->lq035_open_cnt++;
359
360 if (fbi->lq035_open_cnt <= 1) {
361
362 bfin_lq035q1_disable_ppi();
363 SSYNC();
364
365 bfin_lq035q1_config_dma(fbi);
366 bfin_lq035q1_config_ppi(fbi);
367 bfin_lq035q1_init_timers();
368
369 /* start dma */
370 enable_dma(CH_PPI);
371 bfin_lq035q1_enable_ppi();
372 bfin_lq035q1_start_timers();
373 lq035q1_backlight(fbi, 1);
374 }
375
376 spin_unlock(&fbi->lock);
377
378 return 0;
379}
380
381static int bfin_lq035q1_fb_release(struct fb_info *info, int user)
382{
383 struct bfin_lq035q1fb_info *fbi = info->par;
384
385 spin_lock(&fbi->lock);
386
387 fbi->lq035_open_cnt--;
388
389 if (fbi->lq035_open_cnt <= 0) {
390 lq035q1_backlight(fbi, 0);
391 bfin_lq035q1_disable_ppi();
392 SSYNC();
393 disable_dma(CH_PPI);
394 bfin_lq035q1_stop_timers();
395 }
396
397 spin_unlock(&fbi->lock);
398
399 return 0;
400}
401
402static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var,
403 struct fb_info *info)
404{
405 switch (var->bits_per_pixel) {
406#if (LCD_BPP == 24)
407 case 24:/* TRUECOLOUR, 16m */
408#else
409 case 16:/* DIRECTCOLOUR, 64k */
410#endif
411 var->red.offset = info->var.red.offset;
412 var->green.offset = info->var.green.offset;
413 var->blue.offset = info->var.blue.offset;
414 var->red.length = info->var.red.length;
415 var->green.length = info->var.green.length;
416 var->blue.length = info->var.blue.length;
417 var->transp.offset = 0;
418 var->transp.length = 0;
419 var->transp.msb_right = 0;
420 var->red.msb_right = 0;
421 var->green.msb_right = 0;
422 var->blue.msb_right = 0;
423 break;
424 default:
425 pr_debug("%s: depth not supported: %u BPP\n", __func__,
426 var->bits_per_pixel);
427 return -EINVAL;
428 }
429
430 if (info->var.xres != var->xres || info->var.yres != var->yres ||
431 info->var.xres_virtual != var->xres_virtual ||
432 info->var.yres_virtual != var->yres_virtual) {
433 pr_debug("%s: Resolution not supported: X%u x Y%u \n",
434 __func__, var->xres, var->yres);
435 return -EINVAL;
436 }
437
438 /*
439 * Memory limit
440 */
441
442 if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) {
443 pr_debug("%s: Memory Limit requested yres_virtual = %u\n",
444 __func__, var->yres_virtual);
445 return -ENOMEM;
446 }
447
448
449 return 0;
450}
451
452int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
453{
454 if (nocursor)
455 return 0;
456 else
457 return -EINVAL; /* just to force soft_cursor() call */
458}
459
460static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green,
461 u_int blue, u_int transp,
462 struct fb_info *info)
463{
464 if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES)
465 return -EINVAL;
466
467 if (info->var.grayscale) {
468 /* grayscale = 0.30*R + 0.59*G + 0.11*B */
469 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
470 }
471
472 if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
473
474 u32 value;
475 /* Place color in the pseudopalette */
476 if (regno > 16)
477 return -EINVAL;
478
479 red >>= (16 - info->var.red.length);
480 green >>= (16 - info->var.green.length);
481 blue >>= (16 - info->var.blue.length);
482
483 value = (red << info->var.red.offset) |
484 (green << info->var.green.offset) |
485 (blue << info->var.blue.offset);
486 value &= 0xFFFFFF;
487
488 ((u32 *) (info->pseudo_palette))[regno] = value;
489
490 }
491
492 return 0;
493}
494
495static struct fb_ops bfin_lq035q1_fb_ops = {
496 .owner = THIS_MODULE,
497 .fb_open = bfin_lq035q1_fb_open,
498 .fb_release = bfin_lq035q1_fb_release,
499 .fb_check_var = bfin_lq035q1_fb_check_var,
500 .fb_fillrect = cfb_fillrect,
501 .fb_copyarea = cfb_copyarea,
502 .fb_imageblit = cfb_imageblit,
503 .fb_cursor = bfin_lq035q1_fb_cursor,
504 .fb_setcolreg = bfin_lq035q1_fb_setcolreg,
505};
506
507static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id)
508{
509 /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/
510
511 u16 status = bfin_read_PPI_STATUS();
512 bfin_write_PPI_STATUS(-1);
513
514 if (status) {
515 bfin_lq035q1_disable_ppi();
516 disable_dma(CH_PPI);
517
518 /* start dma */
519 enable_dma(CH_PPI);
520 bfin_lq035q1_enable_ppi();
521 bfin_write_PPI_STATUS(-1);
522 }
523
524 return IRQ_HANDLED;
525}
526
527static int __devinit bfin_lq035q1_probe(struct platform_device *pdev)
528{
529 struct bfin_lq035q1fb_info *info;
530 struct fb_info *fbinfo;
531 int ret;
532
533 ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI");
534 if (ret < 0) {
535 dev_err(&pdev->dev, "PPI DMA unavailable\n");
536 goto out1;
537 }
538
539 fbinfo = framebuffer_alloc(sizeof(*info), &pdev->dev);
540 if (!fbinfo) {
541 ret = -ENOMEM;
542 goto out2;
543 }
544
545 info = fbinfo->par;
546 info->fb = fbinfo;
547 info->dev = &pdev->dev;
548
549 info->disp_info = pdev->dev.platform_data;
550
551 platform_set_drvdata(pdev, fbinfo);
552
553 strcpy(fbinfo->fix.id, DRIVER_NAME);
554
555 fbinfo->fix.type = FB_TYPE_PACKED_PIXELS;
556 fbinfo->fix.type_aux = 0;
557 fbinfo->fix.xpanstep = 0;
558 fbinfo->fix.ypanstep = 0;
559 fbinfo->fix.ywrapstep = 0;
560 fbinfo->fix.accel = FB_ACCEL_NONE;
561 fbinfo->fix.visual = FB_VISUAL_TRUECOLOR;
562
563 fbinfo->var.nonstd = 0;
564 fbinfo->var.activate = FB_ACTIVATE_NOW;
565 fbinfo->var.height = -1;
566 fbinfo->var.width = -1;
567 fbinfo->var.accel_flags = 0;
568 fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
569
570 fbinfo->var.xres = LCD_X_RES;
571 fbinfo->var.xres_virtual = LCD_X_RES;
572 fbinfo->var.yres = LCD_Y_RES;
573 fbinfo->var.yres_virtual = LCD_Y_RES;
574 fbinfo->var.bits_per_pixel = LCD_BPP;
575
576 if (info->disp_info->mode & LQ035_BGR) {
577#if (LCD_BPP == 24)
578 fbinfo->var.red.offset = 0;
579 fbinfo->var.green.offset = 8;
580 fbinfo->var.blue.offset = 16;
581#else
582 fbinfo->var.red.offset = 0;
583 fbinfo->var.green.offset = 5;
584 fbinfo->var.blue.offset = 11;
585#endif
586 } else {
587#if (LCD_BPP == 24)
588 fbinfo->var.red.offset = 16;
589 fbinfo->var.green.offset = 8;
590 fbinfo->var.blue.offset = 0;
591#else
592 fbinfo->var.red.offset = 11;
593 fbinfo->var.green.offset = 5;
594 fbinfo->var.blue.offset = 0;
595#endif
596 }
597
598 fbinfo->var.transp.offset = 0;
599
600#if (LCD_BPP == 24)
601 fbinfo->var.red.length = 8;
602 fbinfo->var.green.length = 8;
603 fbinfo->var.blue.length = 8;
604#else
605 fbinfo->var.red.length = 5;
606 fbinfo->var.green.length = 6;
607 fbinfo->var.blue.length = 5;
608#endif
609
610 fbinfo->var.transp.length = 0;
611
612 fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8
613 + ACTIVE_VIDEO_MEM_OFFSET;
614
615 fbinfo->fix.line_length = fbinfo->var.xres_virtual *
616 fbinfo->var.bits_per_pixel / 8;
617
618
619 fbinfo->fbops = &bfin_lq035q1_fb_ops;
620 fbinfo->flags = FBINFO_FLAG_DEFAULT;
621
622 info->fb_buffer =
623 dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle,
624 GFP_KERNEL);
625
626 if (NULL == info->fb_buffer) {
627 dev_err(&pdev->dev, "couldn't allocate dma buffer\n");
628 ret = -ENOMEM;
629 goto out3;
630 }
631
632 fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
633 fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET;
634
635 fbinfo->fbops = &bfin_lq035q1_fb_ops;
636
637 fbinfo->pseudo_palette = &info->pseudo_pal;
638
639 ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0);
640 if (ret < 0) {
641 dev_err(&pdev->dev, "failed to allocate colormap (%d entries)\n",
642 BFIN_LCD_NBR_PALETTE_ENTRIES);
643 goto out4;
644 }
645
646 ret = bfin_lq035q1_request_ports(pdev);
647 if (ret) {
648 dev_err(&pdev->dev, "couldn't request gpio port\n");
649 goto out6;
650 }
651
652 info->irq = platform_get_irq(pdev, 0);
653 if (info->irq < 0) {
654 ret = -EINVAL;
655 goto out7;
656 }
657
658 ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED,
659 DRIVER_NAME" PPI ERROR", info);
660 if (ret < 0) {
661 dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n");
662 goto out7;
663 }
664
665 info->spidrv.driver.name = DRIVER_NAME"-spi";
666 info->spidrv.probe = lq035q1_spidev_probe;
667 info->spidrv.remove = __devexit_p(lq035q1_spidev_remove);
668 info->spidrv.shutdown = lq035q1_spidev_shutdown;
669 info->spidrv.suspend = lq035q1_spidev_suspend;
670 info->spidrv.resume = lq035q1_spidev_resume;
671
672 ret = spi_register_driver(&info->spidrv);
673 if (ret < 0) {
674 dev_err(&pdev->dev, "couldn't register SPI Interface\n");
675 goto out8;
676 }
677
678 if (info->disp_info->use_bl) {
679 ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight");
680
681 if (ret) {
682 dev_err(&pdev->dev, "failed to request GPIO %d\n",
683 info->disp_info->gpio_bl);
684 goto out9;
685 }
686 gpio_direction_output(info->disp_info->gpio_bl, 0);
687 }
688
689 ret = register_framebuffer(fbinfo);
690 if (ret < 0) {
691 dev_err(&pdev->dev, "unable to register framebuffer\n");
692 goto out10;
693 }
694
695 dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n",
696 LCD_X_RES, LCD_Y_RES, LCD_BPP);
697
698 return 0;
699
700 out10:
701 if (info->disp_info->use_bl)
702 gpio_free(info->disp_info->gpio_bl);
703 out9:
704 spi_unregister_driver(&info->spidrv);
705 out8:
706 free_irq(info->irq, info);
707 out7:
708 bfin_lq035q1_free_ports();
709 out6:
710 fb_dealloc_cmap(&fbinfo->cmap);
711 out4:
712 dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
713 info->dma_handle);
714 out3:
715 framebuffer_release(fbinfo);
716 out2:
717 free_dma(CH_PPI);
718 out1:
719 platform_set_drvdata(pdev, NULL);
720
721 return ret;
722}
723
724static int __devexit bfin_lq035q1_remove(struct platform_device *pdev)
725{
726 struct fb_info *fbinfo = platform_get_drvdata(pdev);
727 struct bfin_lq035q1fb_info *info = fbinfo->par;
728
729 if (info->disp_info->use_bl)
730 gpio_free(info->disp_info->gpio_bl);
731
732 spi_unregister_driver(&info->spidrv);
733
734 unregister_framebuffer(fbinfo);
735
736 free_dma(CH_PPI);
737 free_irq(info->irq, info);
738
739 if (info->fb_buffer != NULL)
740 dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer,
741 info->dma_handle);
742
743 fb_dealloc_cmap(&fbinfo->cmap);
744
745 bfin_lq035q1_free_ports();
746
747 platform_set_drvdata(pdev, NULL);
748 framebuffer_release(fbinfo);
749
750 dev_info(&pdev->dev, "unregistered LCD driver\n");
751
752 return 0;
753}
754
755#ifdef CONFIG_PM
756static int bfin_lq035q1_suspend(struct device *dev)
757{
758 struct fb_info *fbinfo = dev_get_drvdata(dev);
759 struct bfin_lq035q1fb_info *info = fbinfo->par;
760
761 if (info->lq035_open_cnt) {
762 lq035q1_backlight(info, 0);
763 bfin_lq035q1_disable_ppi();
764 SSYNC();
765 disable_dma(CH_PPI);
766 bfin_lq035q1_stop_timers();
767 bfin_write_PPI_STATUS(-1);
768 }
769
770 return 0;
771}
772
773static int bfin_lq035q1_resume(struct device *dev)
774{
775 struct fb_info *fbinfo = dev_get_drvdata(dev);
776 struct bfin_lq035q1fb_info *info = fbinfo->par;
777
778 if (info->lq035_open_cnt) {
779 bfin_lq035q1_disable_ppi();
780 SSYNC();
781
782 bfin_lq035q1_config_dma(info);
783 bfin_lq035q1_config_ppi(info);
784 bfin_lq035q1_init_timers();
785
786 /* start dma */
787 enable_dma(CH_PPI);
788 bfin_lq035q1_enable_ppi();
789 bfin_lq035q1_start_timers();
790 lq035q1_backlight(info, 1);
791 }
792
793 return 0;
794}
795
796static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = {
797 .suspend = bfin_lq035q1_suspend,
798 .resume = bfin_lq035q1_resume,
799};
800#endif
801
802static struct platform_driver bfin_lq035q1_driver = {
803 .probe = bfin_lq035q1_probe,
804 .remove = __devexit_p(bfin_lq035q1_remove),
805 .driver = {
806 .name = DRIVER_NAME,
807#ifdef CONFIG_PM
808 .pm = &bfin_lq035q1_dev_pm_ops,
809#endif
810 },
811};
812
813static int __init bfin_lq035q1_driver_init(void)
814{
815 return platform_driver_register(&bfin_lq035q1_driver);
816}
817module_init(bfin_lq035q1_driver_init);
818
819static void __exit bfin_lq035q1_driver_cleanup(void)
820{
821 platform_driver_unregister(&bfin_lq035q1_driver);
822}
823module_exit(bfin_lq035q1_driver_cleanup);
824
825MODULE_DESCRIPTION("Blackfin TFT LCD Driver");
826MODULE_LICENSE("GPL");
diff --git a/drivers/video/bfin-t350mcqb-fb.c b/drivers/video/bfin-t350mcqb-fb.c
index 5cc36cfbf07b..2549c53b26a0 100644
--- a/drivers/video/bfin-t350mcqb-fb.c
+++ b/drivers/video/bfin-t350mcqb-fb.c
@@ -487,8 +487,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev)
487 487
488 fbinfo->var.nonstd = 0; 488 fbinfo->var.nonstd = 0;
489 fbinfo->var.activate = FB_ACTIVATE_NOW; 489 fbinfo->var.activate = FB_ACTIVATE_NOW;
490 fbinfo->var.height = -1; 490 fbinfo->var.height = 53;
491 fbinfo->var.width = -1; 491 fbinfo->var.width = 70;
492 fbinfo->var.accel_flags = 0; 492 fbinfo->var.accel_flags = 0;
493 fbinfo->var.vmode = FB_VMODE_NONINTERLACED; 493 fbinfo->var.vmode = FB_VMODE_NONINTERLACED;
494 494
@@ -634,17 +634,35 @@ static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev)
634#ifdef CONFIG_PM 634#ifdef CONFIG_PM
635static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) 635static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state)
636{ 636{
637 bfin_t350mcqb_disable_ppi(); 637 struct fb_info *fbinfo = platform_get_drvdata(pdev);
638 disable_dma(CH_PPI); 638 struct bfin_t350mcqbfb_info *fbi = fbinfo->par;
639 bfin_write_PPI_STATUS(0xFFFF); 639
640 if (fbi->lq043_open_cnt) {
641 bfin_t350mcqb_disable_ppi();
642 disable_dma(CH_PPI);
643 bfin_t350mcqb_stop_timers();
644 bfin_write_PPI_STATUS(-1);
645 }
646
640 647
641 return 0; 648 return 0;
642} 649}
643 650
644static int bfin_t350mcqb_resume(struct platform_device *pdev) 651static int bfin_t350mcqb_resume(struct platform_device *pdev)
645{ 652{
646 enable_dma(CH_PPI); 653 struct fb_info *fbinfo = platform_get_drvdata(pdev);
647 bfin_t350mcqb_enable_ppi(); 654 struct bfin_t350mcqbfb_info *fbi = fbinfo->par;
655
656 if (fbi->lq043_open_cnt) {
657 bfin_t350mcqb_config_dma(fbi);
658 bfin_t350mcqb_config_ppi(fbi);
659 bfin_t350mcqb_init_timers();
660
661 /* start dma */
662 enable_dma(CH_PPI);
663 bfin_t350mcqb_enable_ppi();
664 bfin_t350mcqb_start_timers();
665 }
648 666
649 return 0; 667 return 0;
650} 668}
diff --git a/drivers/video/broadsheetfb.c b/drivers/video/broadsheetfb.c
index 509cb92e8731..df9ccb901d86 100644
--- a/drivers/video/broadsheetfb.c
+++ b/drivers/video/broadsheetfb.c
@@ -470,7 +470,7 @@ static int __devinit broadsheetfb_probe(struct platform_device *dev)
470 par->read_reg = broadsheet_read_reg; 470 par->read_reg = broadsheet_read_reg;
471 init_waitqueue_head(&par->waitq); 471 init_waitqueue_head(&par->waitq);
472 472
473 info->flags = FBINFO_FLAG_DEFAULT; 473 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
474 474
475 info->fbdefio = &broadsheetfb_defio; 475 info->fbdefio = &broadsheetfb_defio;
476 fb_deferred_io_init(info); 476 fb_deferred_io_init(info);
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index 16f5db471ab5..99b354b8e257 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -19,8 +19,10 @@
19 * 19 *
20 * Framebuffer driver for the CLPS7111 and EP7212 processors. 20 * Framebuffer driver for the CLPS7111 and EP7212 processors.
21 */ 21 */
22#include <linux/mm.h>
22#include <linux/module.h> 23#include <linux/module.h>
23#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/seq_file.h>
24#include <linux/slab.h> 26#include <linux/slab.h>
25#include <linux/fb.h> 27#include <linux/fb.h>
26#include <linux/init.h> 28#include <linux/init.h>
@@ -38,14 +40,6 @@ struct fb_info *cfb;
38 40
39#define CMAP_MAX_SIZE 16 41#define CMAP_MAX_SIZE 16
40 42
41/* The /proc entry for the backlight. */
42static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL;
43
44static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
45 int count, int *eof, void *data);
46static int clps7111fb_proc_backlight_write(struct file *file,
47 const char *buffer, unsigned long count, void *data);
48
49/* 43/*
50 * LCD AC Prescale. This comes from the LCD panel manufacturers specifications. 44 * LCD AC Prescale. This comes from the LCD panel manufacturers specifications.
51 * This determines how many clocks + 1 of CL1 before the M signal toggles. 45 * This determines how many clocks + 1 of CL1 before the M signal toggles.
@@ -221,26 +215,23 @@ static struct fb_ops clps7111fb_ops = {
221 .fb_imageblit = cfb_imageblit, 215 .fb_imageblit = cfb_imageblit,
222}; 216};
223 217
224static int 218static int backlight_proc_show(struct seq_file *m, void *v)
225clps7111fb_proc_backlight_read(char *page, char **start, off_t off,
226 int count, int *eof, void *data)
227{ 219{
228 /* We need at least two characters, one for the digit, and one for
229 * the terminating NULL. */
230 if (count < 2)
231 return -EINVAL;
232
233 if (machine_is_edb7211()) { 220 if (machine_is_edb7211()) {
234 return sprintf(page, "%d\n", 221 seq_printf(m, "%d\n",
235 (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0); 222 (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0);
236 } 223 }
237 224
238 return 0; 225 return 0;
239} 226}
240 227
241static int 228static int backlight_proc_open(struct inode *inode, struct file *file)
242clps7111fb_proc_backlight_write(struct file *file, const char *buffer, 229{
243 unsigned long count, void *data) 230 return single_open(file, backlight_proc_show, NULL);
231}
232
233static ssize_t backlight_proc_write(struct file *file, const char *buffer,
234 size_t count, loff_t *pos)
244{ 235{
245 unsigned char char_value; 236 unsigned char char_value;
246 int value; 237 int value;
@@ -271,6 +262,15 @@ clps7111fb_proc_backlight_write(struct file *file, const char *buffer,
271 return count; 262 return count;
272} 263}
273 264
265static const struct file_operations backlight_proc_fops = {
266 .owner = THIS_MODULE,
267 .open = backlight_proc_open,
268 .read = seq_read,
269 .llseek = seq_lseek,
270 .release = single_release,
271 .write = backlight_proc_write,
272};
273
274static void __init clps711x_guess_lcd_params(struct fb_info *info) 274static void __init clps711x_guess_lcd_params(struct fb_info *info)
275{ 275{
276 unsigned int lcdcon, syscon, size; 276 unsigned int lcdcon, syscon, size;
@@ -379,19 +379,11 @@ int __init clps711xfb_init(void)
379 379
380 fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0); 380 fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0);
381 381
382 /* Register the /proc entries. */ 382 if (!proc_create("backlight", 0444, NULL, &backlight_proc_fops)) {
383 clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444,
384 NULL);
385 if (clps7111fb_backlight_proc_entry == NULL) {
386 printk("Couldn't create the /proc entry for the backlight.\n"); 383 printk("Couldn't create the /proc entry for the backlight.\n");
387 return -EINVAL; 384 return -EINVAL;
388 } 385 }
389 386
390 clps7111fb_backlight_proc_entry->read_proc =
391 &clps7111fb_proc_backlight_read;
392 clps7111fb_backlight_proc_entry->write_proc =
393 &clps7111fb_proc_backlight_write;
394
395 /* 387 /*
396 * Power up the LCD 388 * Power up the LCD
397 */ 389 */
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index 857b3668b3ba..6468a297e341 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -436,7 +436,7 @@ sti_init_glob_cfg(struct sti_struct *sti,
436 (offs < PCI_BASE_ADDRESS_0 || 436 (offs < PCI_BASE_ADDRESS_0 ||
437 offs > PCI_BASE_ADDRESS_5)) { 437 offs > PCI_BASE_ADDRESS_5)) {
438 printk (KERN_WARNING 438 printk (KERN_WARNING
439 "STI pci region maping for region %d (%02x) can't be mapped\n", 439 "STI pci region mapping for region %d (%02x) can't be mapped\n",
440 i,sti->rm_entry[i]); 440 i,sti->rm_entry[i]);
441 continue; 441 continue;
442 } 442 }
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index da55ccaf4d55..cc4bbbe44aca 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -585,6 +585,11 @@ static void vgacon_init(struct vc_data *c, int init)
585 vgacon_uni_pagedir[1]++; 585 vgacon_uni_pagedir[1]++;
586 if (!vgacon_uni_pagedir[0] && p) 586 if (!vgacon_uni_pagedir[0] && p)
587 con_set_default_unimap(c); 587 con_set_default_unimap(c);
588
589 /* Only set the default if the user didn't deliberately override it */
590 if (global_cursor_default == -1)
591 global_cursor_default =
592 !(screen_info.flags & VIDEO_FLAGS_NOCURSOR);
588} 593}
589 594
590static void vgacon_deinit(struct vc_data *c) 595static void vgacon_deinit(struct vc_data *c)
diff --git a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
index da7c01b39be2..3a561df2e8a2 100644
--- a/drivers/video/cyber2000fb.c
+++ b/drivers/video/cyber2000fb.c
@@ -1573,15 +1573,15 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
1573 if (err) 1573 if (err)
1574 return err; 1574 return err;
1575 1575
1576 err = pci_request_regions(dev, name);
1577 if (err)
1578 return err;
1579
1580 err = -ENOMEM; 1576 err = -ENOMEM;
1581 cfb = cyberpro_alloc_fb_info(id->driver_data, name); 1577 cfb = cyberpro_alloc_fb_info(id->driver_data, name);
1582 if (!cfb) 1578 if (!cfb)
1583 goto failed_release; 1579 goto failed_release;
1584 1580
1581 err = pci_request_regions(dev, cfb->fb.fix.id);
1582 if (err)
1583 goto failed_regions;
1584
1585 cfb->dev = dev; 1585 cfb->dev = dev;
1586 cfb->region = pci_ioremap_bar(dev, 0); 1586 cfb->region = pci_ioremap_bar(dev, 0);
1587 if (!cfb->region) 1587 if (!cfb->region)
@@ -1633,10 +1633,10 @@ cyberpro_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
1633failed: 1633failed:
1634 iounmap(cfb->region); 1634 iounmap(cfb->region);
1635failed_ioremap: 1635failed_ioremap:
1636 pci_release_regions(dev);
1637failed_regions:
1636 cyberpro_free_fb_info(cfb); 1638 cyberpro_free_fb_info(cfb);
1637failed_release: 1639failed_release:
1638 pci_release_regions(dev);
1639
1640 return err; 1640 return err;
1641} 1641}
1642 1642
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 035d56835b75..369a5b3ac649 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -28,6 +28,8 @@
28#include <linux/uaccess.h> 28#include <linux/uaccess.h>
29#include <linux/interrupt.h> 29#include <linux/interrupt.h>
30#include <linux/clk.h> 30#include <linux/clk.h>
31#include <linux/cpufreq.h>
32#include <linux/console.h>
31#include <video/da8xx-fb.h> 33#include <video/da8xx-fb.h>
32 34
33#define DRIVER_NAME "da8xx_lcdc" 35#define DRIVER_NAME "da8xx_lcdc"
@@ -113,6 +115,12 @@ struct da8xx_fb_par {
113 unsigned short pseudo_palette[16]; 115 unsigned short pseudo_palette[16];
114 unsigned int databuf_sz; 116 unsigned int databuf_sz;
115 unsigned int palette_sz; 117 unsigned int palette_sz;
118 unsigned int pxl_clk;
119 int blank;
120#ifdef CONFIG_CPU_FREQ
121 struct notifier_block freq_transition;
122#endif
123 void (*panel_power_ctrl)(int);
116}; 124};
117 125
118/* Variable Screen Information */ 126/* Variable Screen Information */
@@ -155,7 +163,7 @@ struct da8xx_panel {
155 int vfp; /* Vertical front porch */ 163 int vfp; /* Vertical front porch */
156 int vbp; /* Vertical back porch */ 164 int vbp; /* Vertical back porch */
157 int vsw; /* Vertical Sync Pulse Width */ 165 int vsw; /* Vertical Sync Pulse Width */
158 int pxl_clk; /* Pixel clock */ 166 unsigned int pxl_clk; /* Pixel clock */
159 unsigned char invert_pxl_clk; /* Invert Pixel clock */ 167 unsigned char invert_pxl_clk; /* Invert Pixel clock */
160}; 168};
161 169
@@ -171,7 +179,7 @@ static struct da8xx_panel known_lcd_panels[] = {
171 .vfp = 2, 179 .vfp = 2,
172 .vbp = 2, 180 .vbp = 2,
173 .vsw = 0, 181 .vsw = 0,
174 .pxl_clk = 0x10, 182 .pxl_clk = 4608000,
175 .invert_pxl_clk = 1, 183 .invert_pxl_clk = 1,
176 }, 184 },
177 /* Sharp LK043T1DG01 */ 185 /* Sharp LK043T1DG01 */
@@ -185,13 +193,23 @@ static struct da8xx_panel known_lcd_panels[] = {
185 .vfp = 2, 193 .vfp = 2,
186 .vbp = 2, 194 .vbp = 2,
187 .vsw = 10, 195 .vsw = 10,
188 .pxl_clk = 0x12, 196 .pxl_clk = 7833600,
189 .invert_pxl_clk = 0, 197 .invert_pxl_clk = 0,
190 }, 198 },
191}; 199};
192 200
201/* Enable the Raster Engine of the LCD Controller */
202static inline void lcd_enable_raster(void)
203{
204 u32 reg;
205
206 reg = lcdc_read(LCD_RASTER_CTRL_REG);
207 if (!(reg & LCD_RASTER_ENABLE))
208 lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
209}
210
193/* Disable the Raster Engine of the LCD Controller */ 211/* Disable the Raster Engine of the LCD Controller */
194static void lcd_disable_raster(struct da8xx_fb_par *par) 212static inline void lcd_disable_raster(void)
195{ 213{
196 u32 reg; 214 u32 reg;
197 215
@@ -443,14 +461,25 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
443static void lcd_reset(struct da8xx_fb_par *par) 461static void lcd_reset(struct da8xx_fb_par *par)
444{ 462{
445 /* Disable the Raster if previously Enabled */ 463 /* Disable the Raster if previously Enabled */
446 if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) 464 lcd_disable_raster();
447 lcd_disable_raster(par);
448 465
449 /* DMA has to be disabled */ 466 /* DMA has to be disabled */
450 lcdc_write(0, LCD_DMA_CTRL_REG); 467 lcdc_write(0, LCD_DMA_CTRL_REG);
451 lcdc_write(0, LCD_RASTER_CTRL_REG); 468 lcdc_write(0, LCD_RASTER_CTRL_REG);
452} 469}
453 470
471static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
472{
473 unsigned int lcd_clk, div;
474
475 lcd_clk = clk_get_rate(par->lcdc_clk);
476 div = lcd_clk / par->pxl_clk;
477
478 /* Configure the LCD clock divisor. */
479 lcdc_write(LCD_CLK_DIVISOR(div) |
480 (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
481}
482
454static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, 483static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
455 struct da8xx_panel *panel) 484 struct da8xx_panel *panel)
456{ 485{
@@ -459,9 +488,8 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
459 488
460 lcd_reset(par); 489 lcd_reset(par);
461 490
462 /* Configure the LCD clock divisor. */ 491 /* Calculate the divider */
463 lcdc_write(LCD_CLK_DIVISOR(panel->pxl_clk) | 492 lcd_calc_clk_divider(par);
464 (LCD_RASTER_MODE & 0x1), LCD_CTRL_REG);
465 493
466 if (panel->invert_pxl_clk) 494 if (panel->invert_pxl_clk)
467 lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | 495 lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) |
@@ -513,13 +541,11 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
513static irqreturn_t lcdc_irq_handler(int irq, void *arg) 541static irqreturn_t lcdc_irq_handler(int irq, void *arg)
514{ 542{
515 u32 stat = lcdc_read(LCD_STAT_REG); 543 u32 stat = lcdc_read(LCD_STAT_REG);
516 u32 reg;
517 544
518 if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { 545 if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
519 reg = lcdc_read(LCD_RASTER_CTRL_REG); 546 lcd_disable_raster();
520 lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
521 lcdc_write(stat, LCD_STAT_REG); 547 lcdc_write(stat, LCD_STAT_REG);
522 lcdc_write(reg | LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); 548 lcd_enable_raster();
523 } else 549 } else
524 lcdc_write(stat, LCD_STAT_REG); 550 lcdc_write(stat, LCD_STAT_REG);
525 551
@@ -554,11 +580,11 @@ static int fb_check_var(struct fb_var_screeninfo *var,
554 var->transp.length = 0; 580 var->transp.length = 0;
555 break; 581 break;
556 case 16: /* RGB 565 */ 582 case 16: /* RGB 565 */
557 var->red.offset = 0; 583 var->red.offset = 11;
558 var->red.length = 5; 584 var->red.length = 5;
559 var->green.offset = 5; 585 var->green.offset = 5;
560 var->green.length = 6; 586 var->green.length = 6;
561 var->blue.offset = 11; 587 var->blue.offset = 0;
562 var->blue.length = 5; 588 var->blue.length = 5;
563 var->transp.offset = 0; 589 var->transp.offset = 0;
564 var->transp.length = 0; 590 var->transp.length = 0;
@@ -574,6 +600,38 @@ static int fb_check_var(struct fb_var_screeninfo *var,
574 return err; 600 return err;
575} 601}
576 602
603#ifdef CONFIG_CPU_FREQ
604static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb,
605 unsigned long val, void *data)
606{
607 struct da8xx_fb_par *par;
608
609 par = container_of(nb, struct da8xx_fb_par, freq_transition);
610 if (val == CPUFREQ_PRECHANGE) {
611 lcd_disable_raster();
612 } else if (val == CPUFREQ_POSTCHANGE) {
613 lcd_calc_clk_divider(par);
614 lcd_enable_raster();
615 }
616
617 return 0;
618}
619
620static inline int lcd_da8xx_cpufreq_register(struct da8xx_fb_par *par)
621{
622 par->freq_transition.notifier_call = lcd_da8xx_cpufreq_transition;
623
624 return cpufreq_register_notifier(&par->freq_transition,
625 CPUFREQ_TRANSITION_NOTIFIER);
626}
627
628static inline void lcd_da8xx_cpufreq_deregister(struct da8xx_fb_par *par)
629{
630 cpufreq_unregister_notifier(&par->freq_transition,
631 CPUFREQ_TRANSITION_NOTIFIER);
632}
633#endif
634
577static int __devexit fb_remove(struct platform_device *dev) 635static int __devexit fb_remove(struct platform_device *dev)
578{ 636{
579 struct fb_info *info = dev_get_drvdata(&dev->dev); 637 struct fb_info *info = dev_get_drvdata(&dev->dev);
@@ -581,8 +639,13 @@ static int __devexit fb_remove(struct platform_device *dev)
581 if (info) { 639 if (info) {
582 struct da8xx_fb_par *par = info->par; 640 struct da8xx_fb_par *par = info->par;
583 641
584 if (lcdc_read(LCD_RASTER_CTRL_REG) & LCD_RASTER_ENABLE) 642#ifdef CONFIG_CPU_FREQ
585 lcd_disable_raster(par); 643 lcd_da8xx_cpufreq_deregister(par);
644#endif
645 if (par->panel_power_ctrl)
646 par->panel_power_ctrl(0);
647
648 lcd_disable_raster();
586 lcdc_write(0, LCD_RASTER_CTRL_REG); 649 lcdc_write(0, LCD_RASTER_CTRL_REG);
587 650
588 /* disable DMA */ 651 /* disable DMA */
@@ -591,7 +654,7 @@ static int __devexit fb_remove(struct platform_device *dev)
591 unregister_framebuffer(info); 654 unregister_framebuffer(info);
592 fb_dealloc_cmap(&info->cmap); 655 fb_dealloc_cmap(&info->cmap);
593 dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, 656 dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
594 info->screen_base, 657 info->screen_base - PAGE_SIZE,
595 info->fix.smem_start); 658 info->fix.smem_start);
596 free_irq(par->irq, par); 659 free_irq(par->irq, par);
597 clk_disable(par->lcdc_clk); 660 clk_disable(par->lcdc_clk);
@@ -639,6 +702,35 @@ static int fb_ioctl(struct fb_info *info, unsigned int cmd,
639 return 0; 702 return 0;
640} 703}
641 704
705static int cfb_blank(int blank, struct fb_info *info)
706{
707 struct da8xx_fb_par *par = info->par;
708 int ret = 0;
709
710 if (par->blank == blank)
711 return 0;
712
713 par->blank = blank;
714 switch (blank) {
715 case FB_BLANK_UNBLANK:
716 if (par->panel_power_ctrl)
717 par->panel_power_ctrl(1);
718
719 lcd_enable_raster();
720 break;
721 case FB_BLANK_POWERDOWN:
722 if (par->panel_power_ctrl)
723 par->panel_power_ctrl(0);
724
725 lcd_disable_raster();
726 break;
727 default:
728 ret = -EINVAL;
729 }
730
731 return ret;
732}
733
642static struct fb_ops da8xx_fb_ops = { 734static struct fb_ops da8xx_fb_ops = {
643 .owner = THIS_MODULE, 735 .owner = THIS_MODULE,
644 .fb_check_var = fb_check_var, 736 .fb_check_var = fb_check_var,
@@ -647,6 +739,7 @@ static struct fb_ops da8xx_fb_ops = {
647 .fb_fillrect = cfb_fillrect, 739 .fb_fillrect = cfb_fillrect,
648 .fb_copyarea = cfb_copyarea, 740 .fb_copyarea = cfb_copyarea,
649 .fb_imageblit = cfb_imageblit, 741 .fb_imageblit = cfb_imageblit,
742 .fb_blank = cfb_blank,
650}; 743};
651 744
652static int __init fb_probe(struct platform_device *device) 745static int __init fb_probe(struct platform_device *device)
@@ -721,6 +814,12 @@ static int __init fb_probe(struct platform_device *device)
721 } 814 }
722 815
723 par = da8xx_fb_info->par; 816 par = da8xx_fb_info->par;
817 par->lcdc_clk = fb_clk;
818 par->pxl_clk = lcdc_info->pxl_clk;
819 if (fb_pdata->panel_power_ctrl) {
820 par->panel_power_ctrl = fb_pdata->panel_power_ctrl;
821 par->panel_power_ctrl(1);
822 }
724 823
725 if (lcd_init(par, lcd_cfg, lcdc_info) < 0) { 824 if (lcd_init(par, lcd_cfg, lcdc_info) < 0) {
726 dev_err(&device->dev, "lcd_init failed\n"); 825 dev_err(&device->dev, "lcd_init failed\n");
@@ -749,12 +848,11 @@ static int __init fb_probe(struct platform_device *device)
749 (PAGE_SIZE - par->palette_sz); 848 (PAGE_SIZE - par->palette_sz);
750 849
751 /* the rest of the frame buffer is pixel data */ 850 /* the rest of the frame buffer is pixel data */
851 da8xx_fb_info->screen_base = par->v_palette_base + par->palette_sz;
752 da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz; 852 da8xx_fb_fix.smem_start = par->p_palette_base + par->palette_sz;
753 da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz; 853 da8xx_fb_fix.smem_len = par->databuf_sz - par->palette_sz;
754 da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; 854 da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8;
755 855
756 par->lcdc_clk = fb_clk;
757
758 par->irq = platform_get_irq(device, 0); 856 par->irq = platform_get_irq(device, 0);
759 if (par->irq < 0) { 857 if (par->irq < 0) {
760 ret = -ENOENT; 858 ret = -ENOENT;
@@ -787,6 +885,8 @@ static int __init fb_probe(struct platform_device *device)
787 da8xx_fb_info->var = da8xx_fb_var; 885 da8xx_fb_info->var = da8xx_fb_var;
788 da8xx_fb_info->fbops = &da8xx_fb_ops; 886 da8xx_fb_info->fbops = &da8xx_fb_ops;
789 da8xx_fb_info->pseudo_palette = par->pseudo_palette; 887 da8xx_fb_info->pseudo_palette = par->pseudo_palette;
888 da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ?
889 FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
790 890
791 ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0); 891 ret = fb_alloc_cmap(&da8xx_fb_info->cmap, PALETTE_SIZE, 0);
792 if (ret) 892 if (ret)
@@ -811,12 +911,24 @@ static int __init fb_probe(struct platform_device *device)
811 goto err_dealloc_cmap; 911 goto err_dealloc_cmap;
812 } 912 }
813 913
914#ifdef CONFIG_CPU_FREQ
915 ret = lcd_da8xx_cpufreq_register(par);
916 if (ret) {
917 dev_err(&device->dev, "failed to register cpufreq\n");
918 goto err_cpu_freq;
919 }
920#endif
921
814 /* enable raster engine */ 922 /* enable raster engine */
815 lcdc_write(lcdc_read(LCD_RASTER_CTRL_REG) | 923 lcd_enable_raster();
816 LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG);
817 924
818 return 0; 925 return 0;
819 926
927#ifdef CONFIG_CPU_FREQ
928err_cpu_freq:
929 unregister_framebuffer(da8xx_fb_info);
930#endif
931
820err_dealloc_cmap: 932err_dealloc_cmap:
821 fb_dealloc_cmap(&da8xx_fb_info->cmap); 933 fb_dealloc_cmap(&da8xx_fb_info->cmap);
822 934
@@ -825,7 +937,7 @@ err_free_irq:
825 937
826err_release_fb_mem: 938err_release_fb_mem:
827 dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE, 939 dma_free_coherent(NULL, par->databuf_sz + PAGE_SIZE,
828 da8xx_fb_info->screen_base, 940 da8xx_fb_info->screen_base - PAGE_SIZE,
829 da8xx_fb_info->fix.smem_start); 941 da8xx_fb_info->fix.smem_start);
830 942
831err_release_fb: 943err_release_fb:
@@ -849,11 +961,35 @@ err_request_mem:
849#ifdef CONFIG_PM 961#ifdef CONFIG_PM
850static int fb_suspend(struct platform_device *dev, pm_message_t state) 962static int fb_suspend(struct platform_device *dev, pm_message_t state)
851{ 963{
852 return -EBUSY; 964 struct fb_info *info = platform_get_drvdata(dev);
965 struct da8xx_fb_par *par = info->par;
966
967 acquire_console_sem();
968 if (par->panel_power_ctrl)
969 par->panel_power_ctrl(0);
970
971 fb_set_suspend(info, 1);
972 lcd_disable_raster();
973 clk_disable(par->lcdc_clk);
974 release_console_sem();
975
976 return 0;
853} 977}
854static int fb_resume(struct platform_device *dev) 978static int fb_resume(struct platform_device *dev)
855{ 979{
856 return -EBUSY; 980 struct fb_info *info = platform_get_drvdata(dev);
981 struct da8xx_fb_par *par = info->par;
982
983 acquire_console_sem();
984 if (par->panel_power_ctrl)
985 par->panel_power_ctrl(1);
986
987 clk_enable(par->lcdc_clk);
988 lcd_enable_raster();
989 fb_set_suspend(info, 0);
990 release_console_sem();
991
992 return 0;
857} 993}
858#else 994#else
859#define fb_suspend NULL 995#define fb_suspend NULL
diff --git a/drivers/video/display/display-sysfs.c b/drivers/video/display/display-sysfs.c
index 4830b1bf51e5..80abbf323b99 100644
--- a/drivers/video/display/display-sysfs.c
+++ b/drivers/video/display/display-sysfs.c
@@ -67,7 +67,7 @@ static ssize_t display_store_contrast(struct device *dev,
67 contrast = simple_strtoul(buf, &endp, 0); 67 contrast = simple_strtoul(buf, &endp, 0);
68 size = endp - buf; 68 size = endp - buf;
69 69
70 if (*endp && isspace(*endp)) 70 if (isspace(*endp))
71 size++; 71 size++;
72 72
73 if (size != count) 73 if (size != count)
diff --git a/drivers/video/ep93xx-fb.c b/drivers/video/ep93xx-fb.c
index bd9d46f95291..27aab4a06198 100644
--- a/drivers/video/ep93xx-fb.c
+++ b/drivers/video/ep93xx-fb.c
@@ -358,6 +358,8 @@ static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red,
358 358
359 switch (info->fix.visual) { 359 switch (info->fix.visual) {
360 case FB_VISUAL_PSEUDOCOLOR: 360 case FB_VISUAL_PSEUDOCOLOR:
361 if (regno > 255)
362 return 1;
361 rgb = ((red & 0xff00) << 8) | (green & 0xff00) | 363 rgb = ((red & 0xff00) << 8) | (green & 0xff00) |
362 ((blue & 0xff00) >> 8); 364 ((blue & 0xff00) >> 8);
363 365
diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c
index c27ab1ed9604..44ce908a478b 100644
--- a/drivers/video/fb_defio.c
+++ b/drivers/video/fb_defio.c
@@ -71,7 +71,7 @@ int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync)
71{ 71{
72 struct fb_info *info = file->private_data; 72 struct fb_info *info = file->private_data;
73 73
74 /* Skip if deferred io is complied-in but disabled on this fbdev */ 74 /* Skip if deferred io is compiled-in but disabled on this fbdev */
75 if (!info->fbdefio) 75 if (!info->fbdefio)
76 return 0; 76 return 0;
77 77
@@ -144,7 +144,9 @@ static const struct address_space_operations fb_deferred_io_aops = {
144static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma) 144static int fb_deferred_io_mmap(struct fb_info *info, struct vm_area_struct *vma)
145{ 145{
146 vma->vm_ops = &fb_deferred_io_vm_ops; 146 vma->vm_ops = &fb_deferred_io_vm_ops;
147 vma->vm_flags |= ( VM_IO | VM_RESERVED | VM_DONTEXPAND ); 147 vma->vm_flags |= ( VM_RESERVED | VM_DONTEXPAND );
148 if (!(info->flags & FBINFO_VIRTFB))
149 vma->vm_flags |= VM_IO;
148 vma->vm_private_data = info; 150 vma->vm_private_data = info;
149 return 0; 151 return 0;
150} 152}
diff --git a/drivers/video/gbefb.c b/drivers/video/gbefb.c
index 1a83709f9611..695fa013fe7e 100644
--- a/drivers/video/gbefb.c
+++ b/drivers/video/gbefb.c
@@ -701,7 +701,7 @@ static int gbefb_set_par(struct fb_info *info)
701 blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit, 701 blocks of 512x128, 256x128 or 128x128 pixels, respectively for 8bit,
702 16bit and 32 bit modes (64 kB). They cover the screen with partial 702 16bit and 32 bit modes (64 kB). They cover the screen with partial
703 tiles on the right and/or bottom of the screen if needed. 703 tiles on the right and/or bottom of the screen if needed.
704 For exemple in 640x480 8 bit mode the mapping is: 704 For example in 640x480 8 bit mode the mapping is:
705 705
706 <-------- 640 -----> 706 <-------- 640 ----->
707 <---- 512 ----><128|384 offscreen> 707 <---- 512 ----><128|384 offscreen>
@@ -1147,7 +1147,7 @@ static int __init gbefb_probe(struct platform_device *p_dev)
1147 gbefb_setup(options); 1147 gbefb_setup(options);
1148#endif 1148#endif
1149 1149
1150 if (!request_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) { 1150 if (!request_mem_region(GBE_BASE, sizeof(struct sgi_gbe), "GBE")) {
1151 printk(KERN_ERR "gbefb: couldn't reserve mmio region\n"); 1151 printk(KERN_ERR "gbefb: couldn't reserve mmio region\n");
1152 ret = -EBUSY; 1152 ret = -EBUSY;
1153 goto out_release_framebuffer; 1153 goto out_release_framebuffer;
diff --git a/drivers/video/geode/display_gx.c b/drivers/video/geode/display_gx.c
index e759895bf3d3..f0af911a096d 100644
--- a/drivers/video/geode/display_gx.c
+++ b/drivers/video/geode/display_gx.c
@@ -17,7 +17,7 @@
17#include <asm/io.h> 17#include <asm/io.h>
18#include <asm/div64.h> 18#include <asm/div64.h>
19#include <asm/delay.h> 19#include <asm/delay.h>
20#include <asm/geode.h> 20#include <linux/cs5535.h>
21 21
22#include "gxfb.h" 22#include "gxfb.h"
23 23
@@ -25,7 +25,7 @@ unsigned int gx_frame_buffer_size(void)
25{ 25{
26 unsigned int val; 26 unsigned int val;
27 27
28 if (!geode_has_vsa2()) { 28 if (!cs5535_has_vsa2()) {
29 uint32_t hi, lo; 29 uint32_t hi, lo;
30 30
31 /* The number of pages is (PMAX - PMIN)+1 */ 31 /* The number of pages is (PMAX - PMIN)+1 */
diff --git a/drivers/video/geode/gxfb.h b/drivers/video/geode/gxfb.h
index 16a96f8fd8c5..d19e9378b0c0 100644
--- a/drivers/video/geode/gxfb.h
+++ b/drivers/video/geode/gxfb.h
@@ -340,7 +340,7 @@ static inline void write_fp(struct gxfb_par *par, int reg, uint32_t val)
340} 340}
341 341
342 342
343/* MSRs are defined in asm/geode.h; their bitfields are here */ 343/* MSRs are defined in linux/cs5535.h; their bitfields are here */
344 344
345#define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (1 << 3) 345#define MSR_GLCP_SYS_RSTPLL_DOTPOSTDIV3 (1 << 3)
346#define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (1 << 2) 346#define MSR_GLCP_SYS_RSTPLL_DOTPREMULT2 (1 << 2)
diff --git a/drivers/video/geode/gxfb_core.c b/drivers/video/geode/gxfb_core.c
index 2552cac39e1c..b3e639d1e12c 100644
--- a/drivers/video/geode/gxfb_core.c
+++ b/drivers/video/geode/gxfb_core.c
@@ -32,7 +32,7 @@
32#include <linux/suspend.h> 32#include <linux/suspend.h>
33#include <linux/init.h> 33#include <linux/init.h>
34#include <linux/pci.h> 34#include <linux/pci.h>
35#include <asm/geode.h> 35#include <linux/cs5535.h>
36 36
37#include "gxfb.h" 37#include "gxfb.h"
38 38
diff --git a/drivers/video/geode/lxfb.h b/drivers/video/geode/lxfb.h
index 6a51448fd3f7..cc781c00f75d 100644
--- a/drivers/video/geode/lxfb.h
+++ b/drivers/video/geode/lxfb.h
@@ -1,3 +1,13 @@
1/* Geode LX framebuffer driver
2 *
3 * Copyright (C) 2006-2007, Advanced Micro Devices,Inc.
4 * Copyright (c) 2008 Andres Salomon <dilinger@debian.org>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
1#ifndef _LXFB_H_ 11#ifndef _LXFB_H_
2#define _LXFB_H_ 12#define _LXFB_H_
3 13
@@ -409,7 +419,7 @@ static inline void write_fp(struct lxfb_par *par, int reg, uint32_t val)
409} 419}
410 420
411 421
412/* MSRs are defined in asm/geode.h; their bitfields are here */ 422/* MSRs are defined in linux/cs5535.h; their bitfields are here */
413 423
414#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */ 424#define MSR_GLCP_DOTPLL_LOCK (1 << 25) /* r/o */
415#define MSR_GLCP_DOTPLL_HALFPIX (1 << 24) 425#define MSR_GLCP_DOTPLL_HALFPIX (1 << 24)
diff --git a/drivers/video/geode/lxfb_ops.c b/drivers/video/geode/lxfb_ops.c
index b1cd49c99356..0e5d8c7c3eba 100644
--- a/drivers/video/geode/lxfb_ops.c
+++ b/drivers/video/geode/lxfb_ops.c
@@ -13,7 +13,7 @@
13#include <linux/fb.h> 13#include <linux/fb.h>
14#include <linux/uaccess.h> 14#include <linux/uaccess.h>
15#include <linux/delay.h> 15#include <linux/delay.h>
16#include <asm/geode.h> 16#include <linux/cs5535.h>
17 17
18#include "lxfb.h" 18#include "lxfb.h"
19 19
@@ -307,7 +307,7 @@ unsigned int lx_framebuffer_size(void)
307{ 307{
308 unsigned int val; 308 unsigned int val;
309 309
310 if (!geode_has_vsa2()) { 310 if (!cs5535_has_vsa2()) {
311 uint32_t hi, lo; 311 uint32_t hi, lo;
312 312
313 /* The number of pages is (PMAX - PMIN)+1 */ 313 /* The number of pages is (PMAX - PMIN)+1 */
diff --git a/drivers/video/geode/suspend_gx.c b/drivers/video/geode/suspend_gx.c
index 9aff32ef8bb6..1bb043d70c64 100644
--- a/drivers/video/geode/suspend_gx.c
+++ b/drivers/video/geode/suspend_gx.c
@@ -10,7 +10,7 @@
10#include <linux/fb.h> 10#include <linux/fb.h>
11#include <asm/io.h> 11#include <asm/io.h>
12#include <asm/msr.h> 12#include <asm/msr.h>
13#include <asm/geode.h> 13#include <linux/cs5535.h>
14#include <asm/delay.h> 14#include <asm/delay.h>
15 15
16#include "gxfb.h" 16#include "gxfb.h"
diff --git a/drivers/video/geode/video_gx.c b/drivers/video/geode/video_gx.c
index b8d52a8360db..6082f653c68a 100644
--- a/drivers/video/geode/video_gx.c
+++ b/drivers/video/geode/video_gx.c
@@ -16,7 +16,7 @@
16#include <asm/io.h> 16#include <asm/io.h>
17#include <asm/delay.h> 17#include <asm/delay.h>
18#include <asm/msr.h> 18#include <asm/msr.h>
19#include <asm/geode.h> 19#include <linux/cs5535.h>
20 20
21#include "gxfb.h" 21#include "gxfb.h"
22 22
diff --git a/drivers/video/hecubafb.c b/drivers/video/hecubafb.c
index 0b4bffbe67c8..f9d77adf035d 100644
--- a/drivers/video/hecubafb.c
+++ b/drivers/video/hecubafb.c
@@ -253,7 +253,7 @@ static int __devinit hecubafb_probe(struct platform_device *dev)
253 par->send_command = apollo_send_command; 253 par->send_command = apollo_send_command;
254 par->send_data = apollo_send_data; 254 par->send_data = apollo_send_data;
255 255
256 info->flags = FBINFO_FLAG_DEFAULT; 256 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
257 257
258 info->fbdefio = &hecubafb_defio; 258 info->fbdefio = &hecubafb_defio;
259 fb_deferred_io_init(info); 259 fb_deferred_io_init(info);
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
index e7116a6d82d3..73c83a8de2d3 100644
--- a/drivers/video/hitfb.c
+++ b/drivers/video/hitfb.c
@@ -456,7 +456,7 @@ static int hitfb_resume(struct device *dev)
456 return 0; 456 return 0;
457} 457}
458 458
459static struct dev_pm_ops hitfb_dev_pm_ops = { 459static const struct dev_pm_ops hitfb_dev_pm_ops = {
460 .suspend = hitfb_suspend, 460 .suspend = hitfb_suspend,
461 .resume = hitfb_resume, 461 .resume = hitfb_resume,
462}; 462};
diff --git a/drivers/video/i810/i810_dvt.c b/drivers/video/i810/i810_dvt.c
index 27fa703a2e0a..b4b3670667ab 100644
--- a/drivers/video/i810/i810_dvt.c
+++ b/drivers/video/i810/i810_dvt.c
@@ -212,24 +212,29 @@ inline void round_off_yres(u32 *xres, u32 *yres)
212 *yres = (*xres * 3) >> 2; 212 *yres = (*xres * 3) >> 2;
213} 213}
214 214
215void i810fb_encode_registers(const struct fb_var_screeninfo *var, 215static int i810fb_find_best_mode(u32 xres, u32 yres, u32 pixclock)
216 struct i810fb_par *par, u32 xres, u32 yres)
217{ 216{
218 u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0; 217 u32 diff = 0, diff_best = 0xFFFFFFFF, i = 0, i_best = 0;
219 u8 hfl; 218 u8 hfl = (u8) ((xres >> 3) - 1);
220 219
221 hfl = (u8) ((xres >> 3) - 1);
222 for (i = 0; i < ARRAY_SIZE(std_modes); i++) { 220 for (i = 0; i < ARRAY_SIZE(std_modes); i++) {
223 if (std_modes[i].cr01 == hfl) { 221 if (std_modes[i].cr01 == hfl) {
224 if (std_modes[i].pixclock <= par->regs.pixclock) 222 if (std_modes[i].pixclock <= pixclock)
225 diff = par->regs.pixclock - 223 diff = pixclock - std_modes[i].pixclock;
226 std_modes[i].pixclock;
227 if (diff < diff_best) { 224 if (diff < diff_best) {
228 i_best = i; 225 i_best = i;
229 diff_best = diff; 226 diff_best = diff;
230 } 227 }
231 } 228 }
232 } 229 }
230 return i_best;
231}
232
233void i810fb_encode_registers(const struct fb_var_screeninfo *var,
234 struct i810fb_par *par, u32 xres, u32 yres)
235{
236 u32 i_best = i810fb_find_best_mode(xres, yres, par->regs.pixclock);
237
233 par->regs = std_modes[i_best]; 238 par->regs = std_modes[i_best];
234 239
235 /* overlay */ 240 /* overlay */
@@ -239,36 +244,36 @@ void i810fb_encode_registers(const struct fb_var_screeninfo *var,
239 244
240void i810fb_fill_var_timings(struct fb_var_screeninfo *var) 245void i810fb_fill_var_timings(struct fb_var_screeninfo *var)
241{ 246{
242 struct i810fb_par par;
243 u32 total, xres, yres; 247 u32 total, xres, yres;
248 u32 mode, pixclock;
244 249
245 xres = var->xres; 250 xres = var->xres;
246 yres = var->yres; 251 yres = var->yres;
247 252
248 par.regs.pixclock = 1000000000/var->pixclock; 253 pixclock = 1000000000 / var->pixclock;
249 i810fb_encode_registers(var, &par, xres, yres); 254 mode = i810fb_find_best_mode(xres, yres, pixclock);
250 255
251 total = ((par.regs.cr00 | (par.regs.cr35 & 1) << 8) + 3) << 3; 256 total = (std_modes[mode].cr00 | (std_modes[mode].cr35 & 1) << 8) + 3;
257 total <<= 3;
252 258
253 var->pixclock = 1000000000/par.regs.pixclock; 259 var->pixclock = 1000000000 / std_modes[mode].pixclock;
254 var->right_margin = (par.regs.cr04 << 3) - xres; 260 var->right_margin = (std_modes[mode].cr04 << 3) - xres;
255 var->hsync_len = ((par.regs.cr05 & 0x1F) - 261 var->hsync_len = ((std_modes[mode].cr05 & 0x1F) -
256 (par.regs.cr04 & 0x1F)) << 3; 262 (std_modes[mode].cr04 & 0x1F)) << 3;
257 var->left_margin = (total - (xres + var->right_margin + 263 var->left_margin = (total - (xres + var->right_margin +
258 var->hsync_len)); 264 var->hsync_len));
259 var->sync = FB_SYNC_ON_GREEN; 265 var->sync = FB_SYNC_ON_GREEN;
260 if (~(par.regs.msr & (1 << 6))) 266 if (~(std_modes[mode].msr & (1 << 6)))
261 var->sync |= FB_SYNC_HOR_HIGH_ACT; 267 var->sync |= FB_SYNC_HOR_HIGH_ACT;
262 if (~(par.regs.msr & (1 << 7))) 268 if (~(std_modes[mode].msr & (1 << 7)))
263 var->sync |= FB_SYNC_VERT_HIGH_ACT; 269 var->sync |= FB_SYNC_VERT_HIGH_ACT;
264 270
265 271 total = (std_modes[mode].cr06 | (std_modes[mode].cr30 & 0xF) << 8) + 2;
266 total = ((par.regs.cr06 | (par.regs.cr30 & 0x0F) << 8)) + 2; 272 var->lower_margin = (std_modes[mode].cr10 |
267 var->lower_margin = (par.regs.cr10 | 273 (std_modes[mode].cr32 & 0x0F) << 8) - yres;
268 (par.regs.cr32 & 0x0F) << 8) - yres; 274 var->vsync_len = (std_modes[mode].cr11 & 0x0F) -
269 var->vsync_len = (par.regs.cr11 & 0x0F) - (var->lower_margin & 0x0F); 275 (var->lower_margin & 0x0F);
270 var->upper_margin = total - (yres + var->lower_margin + 276 var->upper_margin = total - (yres + var->lower_margin + var->vsync_len);
271 var->vsync_len);
272} 277}
273 278
274u32 i810_get_watermark(struct fb_var_screeninfo *var, 279u32 i810_get_watermark(struct fb_var_screeninfo *var,
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 0cafd642fbc0..5ba399991050 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -874,6 +874,9 @@ static int __devinit intelfb_pci_register(struct pci_dev *pdev,
874 if (bailearly == 18) 874 if (bailearly == 18)
875 bailout(dinfo); 875 bailout(dinfo);
876 876
877 /* read active pipe */
878 dinfo->pipe = intelfbhw_active_pipe(&dinfo->save_state);
879
877 /* Cursor initialisation */ 880 /* Cursor initialisation */
878 if (dinfo->hwcursor) { 881 if (dinfo->hwcursor) {
879 intelfbhw_cursor_init(dinfo); 882 intelfbhw_cursor_init(dinfo);
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 0689f97c5238..81627466804e 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -469,6 +469,32 @@ void intelfbhw_do_blank(int blank, struct fb_info *info)
469} 469}
470 470
471 471
472/* Check which pipe is connected to an active display plane. */
473int intelfbhw_active_pipe(const struct intelfb_hwstate *hw)
474{
475 int pipe = -1;
476
477 /* keep old default behaviour - prefer PIPE_A */
478 if (hw->disp_b_ctrl & DISPPLANE_PLANE_ENABLE) {
479 pipe = (hw->disp_b_ctrl >> DISPPLANE_SEL_PIPE_SHIFT);
480 pipe &= PIPE_MASK;
481 if (unlikely(pipe == PIPE_A))
482 return PIPE_A;
483 }
484 if (hw->disp_a_ctrl & DISPPLANE_PLANE_ENABLE) {
485 pipe = (hw->disp_a_ctrl >> DISPPLANE_SEL_PIPE_SHIFT);
486 pipe &= PIPE_MASK;
487 if (likely(pipe == PIPE_A))
488 return PIPE_A;
489 }
490 /* Impossible that no pipe is selected - return PIPE_A */
491 WARN_ON(pipe == -1);
492 if (unlikely(pipe == -1))
493 pipe = PIPE_A;
494
495 return pipe;
496}
497
472void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno, 498void intelfbhw_setcolreg(struct intelfb_info *dinfo, unsigned regno,
473 unsigned red, unsigned green, unsigned blue, 499 unsigned red, unsigned green, unsigned blue,
474 unsigned transp) 500 unsigned transp)
@@ -1019,7 +1045,7 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
1019 struct intelfb_hwstate *hw, 1045 struct intelfb_hwstate *hw,
1020 struct fb_var_screeninfo *var) 1046 struct fb_var_screeninfo *var)
1021{ 1047{
1022 int pipe = PIPE_A; 1048 int pipe = intelfbhw_active_pipe(hw);
1023 u32 *dpll, *fp0, *fp1; 1049 u32 *dpll, *fp0, *fp1;
1024 u32 m1, m2, n, p1, p2, clock_target, clock; 1050 u32 m1, m2, n, p1, p2, clock_target, clock;
1025 u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; 1051 u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive;
@@ -1033,12 +1059,6 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
1033 /* Disable VGA */ 1059 /* Disable VGA */
1034 hw->vgacntrl |= VGA_DISABLE; 1060 hw->vgacntrl |= VGA_DISABLE;
1035 1061
1036 /* Check whether pipe A or pipe B is enabled. */
1037 if (hw->pipe_a_conf & PIPECONF_ENABLE)
1038 pipe = PIPE_A;
1039 else if (hw->pipe_b_conf & PIPECONF_ENABLE)
1040 pipe = PIPE_B;
1041
1042 /* Set which pipe's registers will be set. */ 1062 /* Set which pipe's registers will be set. */
1043 if (pipe == PIPE_B) { 1063 if (pipe == PIPE_B) {
1044 dpll = &hw->dpll_b; 1064 dpll = &hw->dpll_b;
@@ -1262,7 +1282,6 @@ int intelfbhw_mode_to_hw(struct intelfb_info *dinfo,
1262int intelfbhw_program_mode(struct intelfb_info *dinfo, 1282int intelfbhw_program_mode(struct intelfb_info *dinfo,
1263 const struct intelfb_hwstate *hw, int blank) 1283 const struct intelfb_hwstate *hw, int blank)
1264{ 1284{
1265 int pipe = PIPE_A;
1266 u32 tmp; 1285 u32 tmp;
1267 const u32 *dpll, *fp0, *fp1, *pipe_conf; 1286 const u32 *dpll, *fp0, *fp1, *pipe_conf;
1268 const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss; 1287 const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss;
@@ -1272,7 +1291,7 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
1272 u32 src_size_reg; 1291 u32 src_size_reg;
1273 u32 count, tmp_val[3]; 1292 u32 count, tmp_val[3];
1274 1293
1275 /* Assume single pipe, display plane A, analog CRT. */ 1294 /* Assume single pipe */
1276 1295
1277#if VERBOSE > 0 1296#if VERBOSE > 0
1278 DBG_MSG("intelfbhw_program_mode\n"); 1297 DBG_MSG("intelfbhw_program_mode\n");
@@ -1283,15 +1302,9 @@ int intelfbhw_program_mode(struct intelfb_info *dinfo,
1283 tmp |= VGA_DISABLE; 1302 tmp |= VGA_DISABLE;
1284 OUTREG(VGACNTRL, tmp); 1303 OUTREG(VGACNTRL, tmp);
1285 1304
1286 /* Check whether pipe A or pipe B is enabled. */ 1305 dinfo->pipe = intelfbhw_active_pipe(hw);
1287 if (hw->pipe_a_conf & PIPECONF_ENABLE)
1288 pipe = PIPE_A;
1289 else if (hw->pipe_b_conf & PIPECONF_ENABLE)
1290 pipe = PIPE_B;
1291
1292 dinfo->pipe = pipe;
1293 1306
1294 if (pipe == PIPE_B) { 1307 if (dinfo->pipe == PIPE_B) {
1295 dpll = &hw->dpll_b; 1308 dpll = &hw->dpll_b;
1296 fp0 = &hw->fpb0; 1309 fp0 = &hw->fpb0;
1297 fp1 = &hw->fpb1; 1310 fp1 = &hw->fpb1;
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index 0b076bac321b..216ca20f259f 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -604,5 +604,6 @@ extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
604extern int intelfbhw_enable_irq(struct intelfb_info *dinfo); 604extern int intelfbhw_enable_irq(struct intelfb_info *dinfo);
605extern void intelfbhw_disable_irq(struct intelfb_info *dinfo); 605extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
606extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe); 606extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
607extern int intelfbhw_active_pipe(const struct intelfb_hwstate *hw);
607 608
608#endif /* _INTELFBHW_H */ 609#endif /* _INTELFBHW_H */
diff --git a/drivers/video/matrox/g450_pll.c b/drivers/video/matrox/g450_pll.c
index 09f6e045d5be..c15f8a57498e 100644
--- a/drivers/video/matrox/g450_pll.c
+++ b/drivers/video/matrox/g450_pll.c
@@ -368,7 +368,8 @@ static int __g450_setclk(struct matrox_fb_info *minfo, unsigned int fout,
368 M1064_XDVICLKCTRL_C1DVICLKEN | 368 M1064_XDVICLKCTRL_C1DVICLKEN |
369 M1064_XDVICLKCTRL_DVILOOPCTL | 369 M1064_XDVICLKCTRL_DVILOOPCTL |
370 M1064_XDVICLKCTRL_P1LOOPBWDTCTL; 370 M1064_XDVICLKCTRL_P1LOOPBWDTCTL;
371 matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); 371 /* Setting this breaks PC systems so don't do it */
372 /* matroxfb_DAC_out(minfo, M1064_XDVICLKCTRL, tmp); */
372 matroxfb_DAC_out(minfo, M1064_XPWRCTRL, 373 matroxfb_DAC_out(minfo, M1064_XPWRCTRL,
373 xpwrctrl); 374 xpwrctrl);
374 375
diff --git a/drivers/video/maxinefb.c b/drivers/video/maxinefb.c
index 5e91c2b30af9..7854c7a37dc5 100644
--- a/drivers/video/maxinefb.c
+++ b/drivers/video/maxinefb.c
@@ -92,6 +92,9 @@ static int maxinefb_setcolreg(unsigned regno, unsigned red, unsigned green,
92 /* value to be written into the palette reg. */ 92 /* value to be written into the palette reg. */
93 unsigned long hw_colorvalue = 0; 93 unsigned long hw_colorvalue = 0;
94 94
95 if (regno > 255)
96 return 1;
97
95 red >>= 8; /* The cmap fields are 16 bits */ 98 red >>= 8; /* The cmap fields are 16 bits */
96 green >>= 8; /* wide, but the harware colormap */ 99 green >>= 8; /* wide, but the harware colormap */
97 blue >>= 8; /* registers are only 8 bits wide */ 100 blue >>= 8; /* registers are only 8 bits wide */
diff --git a/drivers/video/mb862xx/Makefile b/drivers/video/mb862xx/Makefile
index 07664814bb1d..d7777714166b 100644
--- a/drivers/video/mb862xx/Makefile
+++ b/drivers/video/mb862xx/Makefile
@@ -2,4 +2,4 @@
2# Makefile for the MB862xx framebuffer driver 2# Makefile for the MB862xx framebuffer driver
3# 3#
4 4
5obj-$(CONFIG_FB_MB862XX) := mb862xxfb.o 5obj-$(CONFIG_FB_MB862XX) := mb862xxfb.o mb862xxfb_accel.o
diff --git a/drivers/video/mb862xx/mb862xxfb.c b/drivers/video/mb862xx/mb862xxfb.c
index a28e3cfbbf70..fabb0c59a211 100644
--- a/drivers/video/mb862xx/mb862xxfb.c
+++ b/drivers/video/mb862xx/mb862xxfb.c
@@ -214,6 +214,8 @@ static int mb862xxfb_set_par(struct fb_info *fbi)
214 unsigned long reg, sc; 214 unsigned long reg, sc;
215 215
216 dev_dbg(par->dev, "%s\n", __func__); 216 dev_dbg(par->dev, "%s\n", __func__);
217 if (par->type == BT_CORALP)
218 mb862xxfb_init_accel(fbi, fbi->var.xres);
217 219
218 if (par->pre_init) 220 if (par->pre_init)
219 return 0; 221 return 0;
@@ -453,6 +455,18 @@ static ssize_t mb862xxfb_show_dispregs(struct device *dev,
453 ptr += sprintf(ptr, "%08x = %08x\n", 455 ptr += sprintf(ptr, "%08x = %08x\n",
454 reg, inreg(disp, reg)); 456 reg, inreg(disp, reg));
455 457
458 for (reg = 0x400; reg <= 0x410; reg += 4)
459 ptr += sprintf(ptr, "geo %08x = %08x\n",
460 reg, inreg(geo, reg));
461
462 for (reg = 0x400; reg <= 0x410; reg += 4)
463 ptr += sprintf(ptr, "draw %08x = %08x\n",
464 reg, inreg(draw, reg));
465
466 for (reg = 0x440; reg <= 0x450; reg += 4)
467 ptr += sprintf(ptr, "draw %08x = %08x\n",
468 reg, inreg(draw, reg));
469
456 return ptr - buf; 470 return ptr - buf;
457} 471}
458 472
diff --git a/drivers/video/mb862xx/mb862xxfb.h b/drivers/video/mb862xx/mb862xxfb.h
index c4c8f4dd2217..d7e7cb76bbf2 100644
--- a/drivers/video/mb862xx/mb862xxfb.h
+++ b/drivers/video/mb862xx/mb862xxfb.h
@@ -61,6 +61,8 @@ struct mb862xxfb_par {
61 u32 pseudo_palette[16]; 61 u32 pseudo_palette[16];
62}; 62};
63 63
64extern void mb862xxfb_init_accel(struct fb_info *info, int xres);
65
64#if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC) 66#if defined(CONFIG_FB_MB862XX_LIME) && defined(CONFIG_FB_MB862XX_PCI_GDC)
65#error "Select Lime GDC or CoralP/Carmine support, but not both together" 67#error "Select Lime GDC or CoralP/Carmine support, but not both together"
66#endif 68#endif
diff --git a/drivers/video/mb862xx/mb862xxfb_accel.c b/drivers/video/mb862xx/mb862xxfb_accel.c
new file mode 100644
index 000000000000..049256052b1a
--- /dev/null
+++ b/drivers/video/mb862xx/mb862xxfb_accel.c
@@ -0,0 +1,331 @@
1/*
2 * drivers/mb862xx/mb862xxfb_accel.c
3 *
4 * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver acceleration support
5 *
6 * (C) 2007 Alexander Shishkin <virtuoso@slind.org>
7 * (C) 2009 Valentin Sitdikov <valentin.sitdikov@siemens.com>
8 * (C) 2009 Siemens AG
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 */
15#include <linux/fb.h>
16#include <linux/delay.h>
17#include <linux/init.h>
18#include <linux/interrupt.h>
19#include <linux/pci.h>
20#if defined(CONFIG_OF)
21#include <linux/of_platform.h>
22#endif
23#include "mb862xxfb.h"
24#include "mb862xx_reg.h"
25#include "mb862xxfb_accel.h"
26
27static void mb862xxfb_write_fifo(u32 count, u32 *data, struct fb_info *info)
28{
29 struct mb862xxfb_par *par = info->par;
30 static u32 free;
31
32 u32 total = 0;
33 while (total < count) {
34 if (free) {
35 outreg(geo, GDC_GEO_REG_INPUT_FIFO, data[total]);
36 total++;
37 free--;
38 } else {
39 free = (u32) inreg(draw, GDC_REG_FIFO_COUNT);
40 }
41 }
42}
43
44static void mb86290fb_copyarea(struct fb_info *info,
45 const struct fb_copyarea *area)
46{
47 __u32 cmd[6];
48
49 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
50 /* Set raster operation */
51 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
52 cmd[2] = GDC_TYPE_BLTCOPYP << 24;
53
54 if (area->sx >= area->dx && area->sy >= area->dy)
55 cmd[2] |= GDC_CMD_BLTCOPY_TOP_LEFT << 16;
56 else if (area->sx >= area->dx && area->sy <= area->dy)
57 cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_LEFT << 16;
58 else if (area->sx <= area->dx && area->sy >= area->dy)
59 cmd[2] |= GDC_CMD_BLTCOPY_TOP_RIGHT << 16;
60 else
61 cmd[2] |= GDC_CMD_BLTCOPY_BOTTOM_RIGHT << 16;
62
63 cmd[3] = (area->sy << 16) | area->sx;
64 cmd[4] = (area->dy << 16) | area->dx;
65 cmd[5] = (area->height << 16) | area->width;
66 mb862xxfb_write_fifo(6, cmd, info);
67}
68
69/*
70 * Fill in the cmd array /GDC FIFO commands/ to draw a 1bit image.
71 * Make sure cmd has enough room!
72 */
73static void mb86290fb_imageblit1(u32 *cmd, u16 step, u16 dx, u16 dy,
74 u16 width, u16 height, u32 fgcolor,
75 u32 bgcolor, const struct fb_image *image,
76 struct fb_info *info)
77{
78 int i;
79 unsigned const char *line;
80 u16 bytes;
81
82 /* set colors and raster operation regs */
83 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
84 /* Set raster operation */
85 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
86 cmd[2] =
87 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16);
88 cmd[3] = fgcolor;
89 cmd[4] =
90 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_BACK_COLOR << 16);
91 cmd[5] = bgcolor;
92
93 i = 0;
94 line = image->data;
95 bytes = (image->width + 7) >> 3;
96
97 /* and the image */
98 cmd[6] = (GDC_TYPE_DRAWBITMAPP << 24) |
99 (GDC_CMD_BITMAP << 16) | (2 + (step * height));
100 cmd[7] = (dy << 16) | dx;
101 cmd[8] = (height << 16) | width;
102
103 while (i < height) {
104 memcpy(&cmd[9 + i * step], line, step << 2);
105#ifdef __LITTLE_ENDIAN
106 {
107 int k = 0;
108 for (k = 0; k < step; k++)
109 cmd[9 + i * step + k] =
110 cpu_to_be32(cmd[9 + i * step + k]);
111 }
112#endif
113 line += bytes;
114 i++;
115 }
116}
117
118/*
119 * Fill in the cmd array /GDC FIFO commands/ to draw a 8bit image.
120 * Make sure cmd has enough room!
121 */
122static void mb86290fb_imageblit8(u32 *cmd, u16 step, u16 dx, u16 dy,
123 u16 width, u16 height, u32 fgcolor,
124 u32 bgcolor, const struct fb_image *image,
125 struct fb_info *info)
126{
127 int i, j;
128 unsigned const char *line, *ptr;
129 u16 bytes;
130
131 cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) |
132 (GDC_CMD_BLT_DRAW << 16) | (2 + (height * step));
133 cmd[1] = (dy << 16) | dx;
134 cmd[2] = (height << 16) | width;
135
136 i = 0;
137 line = ptr = image->data;
138 bytes = image->width;
139
140 while (i < height) {
141 ptr = line;
142 for (j = 0; j < step; j++) {
143 cmd[3 + i * step + j] =
144 (((u32 *) (info->pseudo_palette))[*ptr]) & 0xffff;
145 ptr++;
146 cmd[3 + i * step + j] |=
147 ((((u32 *) (info->
148 pseudo_palette))[*ptr]) & 0xffff) << 16;
149 ptr++;
150 }
151
152 line += bytes;
153 i++;
154 }
155}
156
157/*
158 * Fill in the cmd array /GDC FIFO commands/ to draw a 16bit image.
159 * Make sure cmd has enough room!
160 */
161static void mb86290fb_imageblit16(u32 *cmd, u16 step, u16 dx, u16 dy,
162 u16 width, u16 height, u32 fgcolor,
163 u32 bgcolor, const struct fb_image *image,
164 struct fb_info *info)
165{
166 int i;
167 unsigned const char *line;
168 u16 bytes;
169
170 i = 0;
171 line = image->data;
172 bytes = image->width << 1;
173
174 cmd[0] = (GDC_TYPE_DRAWBITMAPP << 24) |
175 (GDC_CMD_BLT_DRAW << 16) | (2 + step * height);
176 cmd[1] = (dy << 16) | dx;
177 cmd[2] = (height << 16) | width;
178
179 while (i < height) {
180 memcpy(&cmd[3 + i * step], line, step);
181 line += bytes;
182 i++;
183 }
184}
185
186static void mb86290fb_imageblit(struct fb_info *info,
187 const struct fb_image *image)
188{
189 int mdr;
190 u32 *cmd = NULL;
191 void (*cmdfn) (u32 *, u16, u16, u16, u16, u16, u32, u32,
192 const struct fb_image *, struct fb_info *) = NULL;
193 u32 cmdlen;
194 u32 fgcolor = 0, bgcolor = 0;
195 u16 step;
196
197 u16 width = image->width, height = image->height;
198 u16 dx = image->dx, dy = image->dy;
199 int x2, y2, vxres, vyres;
200
201 mdr = (GDC_ROP_COPY << 9);
202 x2 = image->dx + image->width;
203 y2 = image->dy + image->height;
204 vxres = info->var.xres_virtual;
205 vyres = info->var.yres_virtual;
206 x2 = min(x2, vxres);
207 y2 = min(y2, vyres);
208 width = x2 - dx;
209 height = y2 - dy;
210
211 switch (image->depth) {
212 case 1:
213 step = (width + 31) >> 5;
214 cmdlen = 9 + height * step;
215 cmdfn = mb86290fb_imageblit1;
216 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
217 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
218 fgcolor =
219 ((u32 *) (info->pseudo_palette))[image->fg_color];
220 bgcolor =
221 ((u32 *) (info->pseudo_palette))[image->bg_color];
222 } else {
223 fgcolor = image->fg_color;
224 bgcolor = image->bg_color;
225 }
226
227 break;
228
229 case 8:
230 step = (width + 1) >> 1;
231 cmdlen = 3 + height * step;
232 cmdfn = mb86290fb_imageblit8;
233 break;
234
235 case 16:
236 step = (width + 1) >> 1;
237 cmdlen = 3 + height * step;
238 cmdfn = mb86290fb_imageblit16;
239 break;
240
241 default:
242 cfb_imageblit(info, image);
243 return;
244 }
245
246 cmd = kmalloc(cmdlen * 4, GFP_DMA);
247 if (!cmd)
248 return cfb_imageblit(info, image);
249 cmdfn(cmd, step, dx, dy, width, height, fgcolor, bgcolor, image, info);
250 mb862xxfb_write_fifo(cmdlen, cmd, info);
251 kfree(cmd);
252}
253
254static void mb86290fb_fillrect(struct fb_info *info,
255 const struct fb_fillrect *rect)
256{
257
258 u32 x2, y2, vxres, vyres, height, width, fg;
259 u32 cmd[7];
260
261 vxres = info->var.xres_virtual;
262 vyres = info->var.yres_virtual;
263
264 if (!rect->width || !rect->height || rect->dx > vxres
265 || rect->dy > vyres)
266 return;
267
268 /* We could use hardware clipping but on many cards you get around
269 * hardware clipping by writing to framebuffer directly. */
270 x2 = rect->dx + rect->width;
271 y2 = rect->dy + rect->height;
272 x2 = min(x2, vxres);
273 y2 = min(y2, vyres);
274 width = x2 - rect->dx;
275 height = y2 - rect->dy;
276 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
277 info->fix.visual == FB_VISUAL_DIRECTCOLOR)
278 fg = ((u32 *) (info->pseudo_palette))[rect->color];
279 else
280 fg = rect->color;
281
282 switch (rect->rop) {
283
284 case ROP_XOR:
285 /* Set raster operation */
286 cmd[1] = (2 << 7) | (GDC_ROP_XOR << 9);
287 break;
288
289 case ROP_COPY:
290 /* Set raster operation */
291 cmd[1] = (2 << 7) | (GDC_ROP_COPY << 9);
292 break;
293
294 }
295
296 cmd[0] = (GDC_TYPE_SETREGISTER << 24) | (1 << 16) | GDC_REG_MODE_BITMAP;
297 /* cmd[1] set earlier */
298 cmd[2] =
299 (GDC_TYPE_SETCOLORREGISTER << 24) | (GDC_CMD_BODY_FORE_COLOR << 16);
300 cmd[3] = fg;
301 cmd[4] = (GDC_TYPE_DRAWRECTP << 24) | (GDC_CMD_BLT_FILL << 16);
302 cmd[5] = (rect->dy << 16) | (rect->dx);
303 cmd[6] = (height << 16) | width;
304
305 mb862xxfb_write_fifo(7, cmd, info);
306}
307
308void mb862xxfb_init_accel(struct fb_info *info, int xres)
309{
310 struct mb862xxfb_par *par = info->par;
311
312 if (info->var.bits_per_pixel == 32) {
313 info->fbops->fb_fillrect = cfb_fillrect;
314 info->fbops->fb_copyarea = cfb_copyarea;
315 info->fbops->fb_imageblit = cfb_imageblit;
316 } else {
317 outreg(disp, GC_L0EM, 3);
318 info->fbops->fb_fillrect = mb86290fb_fillrect;
319 info->fbops->fb_copyarea = mb86290fb_copyarea;
320 info->fbops->fb_imageblit = mb86290fb_imageblit;
321 }
322 outreg(draw, GDC_REG_DRAW_BASE, 0);
323 outreg(draw, GDC_REG_MODE_MISC, 0x8000);
324 outreg(draw, GDC_REG_X_RESOLUTION, xres);
325
326 info->flags |=
327 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
328 FBINFO_HWACCEL_IMAGEBLIT;
329 info->fix.accel = 0xff; /*FIXME: add right define */
330}
331EXPORT_SYMBOL(mb862xxfb_init_accel);
diff --git a/drivers/video/mb862xx/mb862xxfb_accel.h b/drivers/video/mb862xx/mb862xxfb_accel.h
new file mode 100644
index 000000000000..96a2dfef0f60
--- /dev/null
+++ b/drivers/video/mb862xx/mb862xxfb_accel.h
@@ -0,0 +1,203 @@
1#ifndef __MB826XXFB_ACCEL_H__
2#define __MB826XXFB_ACCEL_H__
3
4/* registers */
5#define GDC_GEO_REG_INPUT_FIFO 0x00000400L
6
7/* Special Registers */
8#define GDC_REG_CTRL 0x00000400L
9#define GDC_REG_FIFO_STATUS 0x00000404L
10#define GDC_REG_FIFO_COUNT 0x00000408L
11#define GDC_REG_SETUP_STATUS 0x0000040CL
12#define GDC_REG_DDA_STATUS 0x00000410L
13#define GDC_REG_ENGINE_STATUS 0x00000414L
14#define GDC_REG_ERROR_STATUS 0x00000418L
15#define GDC_REG_MODE_MISC 0x00000420L /* MDR0 */
16#define GDC_REG_MODE_LINE 0x00000424L /* MDR1 */
17#define GDC_REG_MODE_POLYGON 0x00000428L /* MDR2 */
18#define GDC_REG_MODE_TEXTURE 0x0000042CL /* MDR3 */
19#define GDC_REG_MODE_BITMAP 0x00000430L /* MDR4 */
20#define GDC_REG_MODE_EXTENSION 0x0000043CL /* MDR7 */
21
22/* Configuration Registers */
23#define GDC_REG_DRAW_BASE 0x00000440L
24#define GDC_REG_X_RESOLUTION 0x00000444L
25#define GDC_REG_Z_BASE 0x00000448L
26#define GDC_REG_TEXTURE_BASE 0x0000044CL
27#define GDC_REG_POLYGON_FLAG_BASE 0x00000450L
28#define GDC_REG_CLIP_XMIN 0x00000454L
29#define GDC_REG_CLIP_XMAX 0x00000458L
30#define GDC_REG_CLIP_YMIN 0x0000045CL
31#define GDC_REG_CLIP_YMAX 0x00000460L
32#define GDC_REG_TEXURE_SIZE 0x00000464L
33#define GDC_REG_TILE_SIZE 0x00000468L
34#define GDC_REG_TEX_BUF_OFFSET 0x0000046CL
35
36/* for MB86293 or later */
37#define GDC_REG_ALPHA_MAP_BASE 0x00000474L /* ABR */
38
39/* Constant Registers */
40#define GDC_REG_FOREGROUND_COLOR 0x00000480L
41#define GDC_REG_BACKGROUND_COLOR 0x00000484L
42#define GDC_REG_ALPHA 0x00000488L
43#define GDC_REG_LINE_PATTERN 0x0000048CL
44#define GDC_REG_TEX_BORDER_COLOR 0x00000494L
45#define GDC_REG_LINE_PATTERN_OFFSET 0x000003E0L
46
47/* Coomand Code */
48#define GDC_CMD_PIXEL 0x00000000L
49#define GDC_CMD_PIXEL_Z 0x00000001L
50
51#define GDC_CMD_X_VECTOR 0x00000020L
52#define GDC_CMD_Y_VECTOR 0x00000021L
53#define GDC_CMD_X_VECTOR_NOEND 0x00000022L
54#define GDC_CMD_Y_VECTOR_NOEND 0x00000023L
55#define GDC_CMD_X_VECTOR_BLPO 0x00000024L
56#define GDC_CMD_Y_VECTOR_BLPO 0x00000025L
57#define GDC_CMD_X_VECTOR_NOEND_BLPO 0x00000026L
58#define GDC_CMD_Y_VECTOR_NOEND_BLPO 0x00000027L
59#define GDC_CMD_AA_X_VECTOR 0x00000028L
60#define GDC_CMD_AA_Y_VECTOR 0x00000029L
61#define GDC_CMD_AA_X_VECTOR_NOEND 0x0000002AL
62#define GDC_CMD_AA_Y_VECTOR_NOEND 0x0000002BL
63#define GDC_CMD_AA_X_VECTOR_BLPO 0x0000002CL
64#define GDC_CMD_AA_Y_VECTOR_BLPO 0x0000002DL
65#define GDC_CMD_AA_X_VECTOR_NOEND_BLPO 0x0000002EL
66#define GDC_CMD_AA_Y_VECTOR_NOEND_BLPO 0x0000002FL
67
68#define GDC_CMD_0_VECTOR 0x00000030L
69#define GDC_CMD_1_VECTOR 0x00000031L
70#define GDC_CMD_0_VECTOR_NOEND 0x00000032L
71#define GDC_CMD_1_VECTOR_NOEND 0x00000033L
72#define GDC_CMD_0_VECTOR_BLPO 0x00000034L
73#define GDC_CMD_1_VECTOR_BLPO 0x00000035L
74#define GDC_CMD_0_VECTOR_NOEND_BLPO 0x00000036L
75#define GDC_CMD_1_VECTOR_NOEND_BLPO 0x00000037L
76#define GDC_CMD_AA_0_VECTOR 0x00000038L
77#define GDC_CMD_AA_1_VECTOR 0x00000039L
78#define GDC_CMD_AA_0_VECTOR_NOEND 0x0000003AL
79#define GDC_CMD_AA_1_VECTOR_NOEND 0x0000003BL
80#define GDC_CMD_AA_0_VECTOR_BLPO 0x0000003CL
81#define GDC_CMD_AA_1_VECTOR_BLPO 0x0000003DL
82#define GDC_CMD_AA_0_VECTOR_NOEND_BLPO 0x0000003EL
83#define GDC_CMD_AA_1_VECTOR_NOEND_BLPO 0x0000003FL
84
85#define GDC_CMD_BLT_FILL 0x00000041L
86#define GDC_CMD_BLT_DRAW 0x00000042L
87#define GDC_CMD_BITMAP 0x00000043L
88#define GDC_CMD_BLTCOPY_TOP_LEFT 0x00000044L
89#define GDC_CMD_BLTCOPY_TOP_RIGHT 0x00000045L
90#define GDC_CMD_BLTCOPY_BOTTOM_LEFT 0x00000046L
91#define GDC_CMD_BLTCOPY_BOTTOM_RIGHT 0x00000047L
92#define GDC_CMD_LOAD_TEXTURE 0x00000048L
93#define GDC_CMD_LOAD_TILE 0x00000049L
94
95#define GDC_CMD_TRAP_RIGHT 0x00000060L
96#define GDC_CMD_TRAP_LEFT 0x00000061L
97#define GDC_CMD_TRIANGLE_FAN 0x00000062L
98#define GDC_CMD_FLAG_TRIANGLE_FAN 0x00000063L
99
100#define GDC_CMD_FLUSH_FB 0x000000C1L
101#define GDC_CMD_FLUSH_Z 0x000000C2L
102
103#define GDC_CMD_POLYGON_BEGIN 0x000000E0L
104#define GDC_CMD_POLYGON_END 0x000000E1L
105#define GDC_CMD_CLEAR_POLY_FLAG 0x000000E2L
106#define GDC_CMD_NORMAL 0x000000FFL
107
108#define GDC_CMD_VECTOR_BLPO_FLAG 0x00040000L
109#define GDC_CMD_FAST_VECTOR_BLPO_FLAG 0x00000004L
110
111/* for MB86293 or later */
112#define GDC_CMD_MDR1 0x00000000L
113#define GDC_CMD_MDR1S 0x00000002L
114#define GDC_CMD_MDR1B 0x00000004L
115#define GDC_CMD_MDR2 0x00000001L
116#define GDC_CMD_MDR2S 0x00000003L
117#define GDC_CMD_MDR2TL 0x00000007L
118#define GDC_CMD_GMDR1E 0x00000010L
119#define GDC_CMD_GMDR2E 0x00000020L
120#define GDC_CMD_OVERLAP_SHADOW_XY 0x00000000L
121#define GDC_CMD_OVERLAP_SHADOW_XY_COMPOSITION 0x00000001L
122#define GDC_CMD_OVERLAP_Z_PACKED_ONBS 0x00000007L
123#define GDC_CMD_OVERLAP_Z_ORIGIN 0x00000000L
124#define GDC_CMD_OVERLAP_Z_NON_TOPLEFT 0x00000001L
125#define GDC_CMD_OVERLAP_Z_BORDER 0x00000002L
126#define GDC_CMD_OVERLAP_Z_SHADOW 0x00000003L
127#define GDC_CMD_BLTCOPY_ALT_ALPHA 0x00000000L /* Reserverd */
128#define GDC_CMD_DC_LOGOUT 0x00000000L /* Reserverd */
129#define GDC_CMD_BODY_FORE_COLOR 0x00000000L
130#define GDC_CMD_BODY_BACK_COLOR 0x00000001L
131#define GDC_CMD_SHADOW_FORE_COLOR 0x00000002L
132#define GDC_CMD_SHADOW_BACK_COLOR 0x00000003L
133#define GDC_CMD_BORDER_FORE_COLOR 0x00000004L
134#define GDC_CMD_BORDER_BACK_COLOR 0x00000005L
135
136/* Type Code Table */
137#define GDC_TYPE_G_NOP 0x00000020L
138#define GDC_TYPE_G_BEGIN 0x00000021L
139#define GDC_TYPE_G_BEGINCONT 0x00000022L
140#define GDC_TYPE_G_END 0x00000023L
141#define GDC_TYPE_G_VERTEX 0x00000030L
142#define GDC_TYPE_G_VERTEXLOG 0x00000032L
143#define GDC_TYPE_G_VERTEXNOPLOG 0x00000033L
144#define GDC_TYPE_G_INIT 0x00000040L
145#define GDC_TYPE_G_VIEWPORT 0x00000041L
146#define GDC_TYPE_G_DEPTHRANGE 0x00000042L
147#define GDC_TYPE_G_LOADMATRIX 0x00000043L
148#define GDC_TYPE_G_VIEWVOLUMEXYCLIP 0x00000044L
149#define GDC_TYPE_G_VIEWVOLUMEZCLIP 0x00000045L
150#define GDC_TYPE_G_VIEWVOLUMEWCLIP 0x00000046L
151#define GDC_TYPE_SETLVERTEX2I 0x00000072L
152#define GDC_TYPE_SETLVERTEX2IP 0x00000073L
153#define GDC_TYPE_SETMODEREGISTER 0x000000C0L
154#define GDC_TYPE_SETGMODEREGISTER 0x000000C1L
155#define GDC_TYPE_OVERLAPXYOFFT 0x000000C8L
156#define GDC_TYPE_OVERLAPZOFFT 0x000000C9L
157#define GDC_TYPE_DC_LOGOUTADDR 0x000000CCL
158#define GDC_TYPE_SETCOLORREGISTER 0x000000CEL
159#define GDC_TYPE_G_BEGINE 0x000000E1L
160#define GDC_TYPE_G_BEGINCONTE 0x000000E2L
161#define GDC_TYPE_G_ENDE 0x000000E3L
162#define GDC_TYPE_DRAWPIXEL 0x00000000L
163#define GDC_TYPE_DRAWPIXELZ 0x00000001L
164#define GDC_TYPE_DRAWLINE 0x00000002L
165#define GDC_TYPE_DRAWLINE2I 0x00000003L
166#define GDC_TYPE_DRAWLINE2IP 0x00000004L
167#define GDC_TYPE_DRAWTRAP 0x00000005L
168#define GDC_TYPE_DRAWVERTEX2I 0x00000006L
169#define GDC_TYPE_DRAWVERTEX2IP 0x00000007L
170#define GDC_TYPE_DRAWRECTP 0x00000009L
171#define GDC_TYPE_DRAWBITMAPP 0x0000000BL
172#define GDC_TYPE_BLTCOPYP 0x0000000DL
173#define GDC_TYPE_BLTCOPYALTERNATEP 0x0000000FL
174#define GDC_TYPE_LOADTEXTUREP 0x00000011L
175#define GDC_TYPE_BLTTEXTUREP 0x00000013L
176#define GDC_TYPE_BLTCOPYALTALPHABLENDP 0x0000001FL
177#define GDC_TYPE_SETVERTEX2I 0x00000070L
178#define GDC_TYPE_SETVERTEX2IP 0x00000071L
179#define GDC_TYPE_DRAW 0x000000F0L
180#define GDC_TYPE_SETREGISTER 0x000000F1L
181#define GDC_TYPE_SYNC 0x000000FCL
182#define GDC_TYPE_INTERRUPT 0x000000FDL
183#define GDC_TYPE_NOP 0x0
184
185/* Raster operation */
186#define GDC_ROP_CLEAR 0x0000
187#define GDC_ROP_AND 0x0001
188#define GDC_ROP_AND_REVERSE 0x0002
189#define GDC_ROP_COPY 0x0003
190#define GDC_ROP_AND_INVERTED 0x0004
191#define GDC_ROP_NOP 0x0005
192#define GDC_ROP_XOR 0x0006
193#define GDC_ROP_OR 0x0007
194#define GDC_ROP_NOR 0x0008
195#define GDC_ROP_EQUIV 0x0009
196#define GDC_ROP_INVERT 0x000A
197#define GDC_ROP_OR_REVERSE 0x000B
198#define GDC_ROP_COPY_INVERTED 0x000C
199#define GDC_ROP_OR_INVERTED 0x000D
200#define GDC_ROP_NAND 0x000E
201#define GDC_ROP_SET 0x000F
202
203#endif
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index df1f757a6161..661bfd20d194 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -700,7 +700,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev)
700 if (retval < 0) 700 if (retval < 0)
701 goto err_free_irq; 701 goto err_free_irq;
702 702
703 info->flags = FBINFO_FLAG_DEFAULT; 703 info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
704 704
705 info->fbdefio = &metronomefb_defio; 705 info->fbdefio = &metronomefb_defio;
706 fb_deferred_io_init(info); 706 fb_deferred_io_init(info);
diff --git a/drivers/video/modedb.c b/drivers/video/modedb.c
index 34e4e7995169..0129f1bc3522 100644
--- a/drivers/video/modedb.c
+++ b/drivers/video/modedb.c
@@ -13,6 +13,7 @@
13 13
14#include <linux/module.h> 14#include <linux/module.h>
15#include <linux/fb.h> 15#include <linux/fb.h>
16#include <linux/kernel.h>
16 17
17#undef DEBUG 18#undef DEBUG
18 19
@@ -402,21 +403,6 @@ const struct fb_videomode vesa_modes[] = {
402EXPORT_SYMBOL(vesa_modes); 403EXPORT_SYMBOL(vesa_modes);
403#endif /* CONFIG_FB_MODE_HELPERS */ 404#endif /* CONFIG_FB_MODE_HELPERS */
404 405
405static int my_atoi(const char *name)
406{
407 int val = 0;
408
409 for (;; name++) {
410 switch (*name) {
411 case '0' ... '9':
412 val = 10*val+(*name-'0');
413 break;
414 default:
415 return val;
416 }
417 }
418}
419
420/** 406/**
421 * fb_try_mode - test a video mode 407 * fb_try_mode - test a video mode
422 * @var: frame buffer user defined part of display 408 * @var: frame buffer user defined part of display
@@ -539,7 +525,7 @@ int fb_find_mode(struct fb_var_screeninfo *var,
539 namelen = i; 525 namelen = i;
540 if (!refresh_specified && !bpp_specified && 526 if (!refresh_specified && !bpp_specified &&
541 !yres_specified) { 527 !yres_specified) {
542 refresh = my_atoi(&name[i+1]); 528 refresh = simple_strtol(&name[i+1], NULL, 10);
543 refresh_specified = 1; 529 refresh_specified = 1;
544 if (cvt || rb) 530 if (cvt || rb)
545 cvt = 0; 531 cvt = 0;
@@ -549,7 +535,7 @@ int fb_find_mode(struct fb_var_screeninfo *var,
549 case '-': 535 case '-':
550 namelen = i; 536 namelen = i;
551 if (!bpp_specified && !yres_specified) { 537 if (!bpp_specified && !yres_specified) {
552 bpp = my_atoi(&name[i+1]); 538 bpp = simple_strtol(&name[i+1], NULL, 10);
553 bpp_specified = 1; 539 bpp_specified = 1;
554 if (cvt || rb) 540 if (cvt || rb)
555 cvt = 0; 541 cvt = 0;
@@ -558,7 +544,7 @@ int fb_find_mode(struct fb_var_screeninfo *var,
558 break; 544 break;
559 case 'x': 545 case 'x':
560 if (!yres_specified) { 546 if (!yres_specified) {
561 yres = my_atoi(&name[i+1]); 547 yres = simple_strtol(&name[i+1], NULL, 10);
562 yres_specified = 1; 548 yres_specified = 1;
563 } else 549 } else
564 goto done; 550 goto done;
@@ -586,7 +572,7 @@ int fb_find_mode(struct fb_var_screeninfo *var,
586 } 572 }
587 } 573 }
588 if (i < 0 && yres_specified) { 574 if (i < 0 && yres_specified) {
589 xres = my_atoi(name); 575 xres = simple_strtol(name, NULL, 10);
590 res_specified = 1; 576 res_specified = 1;
591 } 577 }
592done: 578done:
diff --git a/drivers/video/offb.c b/drivers/video/offb.c
index 4d8c54c23dd7..b043ac83c412 100644
--- a/drivers/video/offb.c
+++ b/drivers/video/offb.c
@@ -282,8 +282,17 @@ static int offb_set_par(struct fb_info *info)
282 return 0; 282 return 0;
283} 283}
284 284
285static void offb_destroy(struct fb_info *info)
286{
287 if (info->screen_base)
288 iounmap(info->screen_base);
289 release_mem_region(info->aperture_base, info->aperture_size);
290 framebuffer_release(info);
291}
292
285static struct fb_ops offb_ops = { 293static struct fb_ops offb_ops = {
286 .owner = THIS_MODULE, 294 .owner = THIS_MODULE,
295 .fb_destroy = offb_destroy,
287 .fb_setcolreg = offb_setcolreg, 296 .fb_setcolreg = offb_setcolreg,
288 .fb_set_par = offb_set_par, 297 .fb_set_par = offb_set_par,
289 .fb_blank = offb_blank, 298 .fb_blank = offb_blank,
@@ -482,10 +491,14 @@ static void __init offb_init_fb(const char *name, const char *full_name,
482 var->sync = 0; 491 var->sync = 0;
483 var->vmode = FB_VMODE_NONINTERLACED; 492 var->vmode = FB_VMODE_NONINTERLACED;
484 493
494 /* set offb aperture size for generic probing */
495 info->aperture_base = address;
496 info->aperture_size = fix->smem_len;
497
485 info->fbops = &offb_ops; 498 info->fbops = &offb_ops;
486 info->screen_base = ioremap(address, fix->smem_len); 499 info->screen_base = ioremap(address, fix->smem_len);
487 info->pseudo_palette = (void *) (info + 1); 500 info->pseudo_palette = (void *) (info + 1);
488 info->flags = FBINFO_DEFAULT | foreign_endian; 501 info->flags = FBINFO_DEFAULT | FBINFO_MISC_FIRMWARE | foreign_endian;
489 502
490 fb_alloc_cmap(&info->cmap, 256, 0); 503 fb_alloc_cmap(&info->cmap, 256, 0);
491 504
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index 551e3e9c4cbe..455c6055325d 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -1,6 +1,7 @@
1config FB_OMAP 1config FB_OMAP
2 tristate "OMAP frame buffer support (EXPERIMENTAL)" 2 tristate "OMAP frame buffer support (EXPERIMENTAL)"
3 depends on FB && ARCH_OMAP 3 depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")
4
4 select FB_CFB_FILLRECT 5 select FB_CFB_FILLRECT
5 select FB_CFB_COPYAREA 6 select FB_CFB_COPYAREA
6 select FB_CFB_IMAGEBLIT 7 select FB_CFB_IMAGEBLIT
@@ -72,7 +73,7 @@ config FB_OMAP_LCD_MIPID
72 73
73config FB_OMAP_BOOTLOADER_INIT 74config FB_OMAP_BOOTLOADER_INIT
74 bool "Check bootloader initialization" 75 bool "Check bootloader initialization"
75 depends on FB_OMAP 76 depends on FB_OMAP || FB_OMAP2
76 help 77 help
77 Say Y here if you want to enable checking if the bootloader has 78 Say Y here if you want to enable checking if the bootloader has
78 already initialized the display controller. In this case the 79 already initialized the display controller. In this case the
diff --git a/drivers/video/omap/Makefile b/drivers/video/omap/Makefile
index b63b198d1f03..49226a1b909e 100644
--- a/drivers/video/omap/Makefile
+++ b/drivers/video/omap/Makefile
@@ -35,6 +35,7 @@ objs-y$(CONFIG_MACH_OMAP3EVM) += lcd_omap3evm.o
35objs-y$(CONFIG_MACH_OMAP3_BEAGLE) += lcd_omap3beagle.o 35objs-y$(CONFIG_MACH_OMAP3_BEAGLE) += lcd_omap3beagle.o
36objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o 36objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
37objs-y$(CONFIG_MACH_OVERO) += lcd_overo.o 37objs-y$(CONFIG_MACH_OVERO) += lcd_overo.o
38objs-y$(CONFIG_MACH_HERALD) += lcd_htcherald.o
38 39
39omapfb-objs := $(objs-yy) 40omapfb-objs := $(objs-yy)
40 41
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c
index 70dadf9d2334..2ffb34af4c59 100644
--- a/drivers/video/omap/blizzard.c
+++ b/drivers/video/omap/blizzard.c
@@ -26,10 +26,10 @@
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/clk.h> 27#include <linux/clk.h>
28 28
29#include <mach/dma.h> 29#include <plat/dma.h>
30#include <mach/omapfb.h> 30#include <plat/blizzard.h>
31#include <mach/blizzard.h>
32 31
32#include "omapfb.h"
33#include "dispc.h" 33#include "dispc.h"
34 34
35#define MODULE_NAME "blizzard" 35#define MODULE_NAME "blizzard"
diff --git a/drivers/video/omap/dispc.c b/drivers/video/omap/dispc.c
index f16e42154229..e192b058a688 100644
--- a/drivers/video/omap/dispc.c
+++ b/drivers/video/omap/dispc.c
@@ -24,11 +24,12 @@
24#include <linux/vmalloc.h> 24#include <linux/vmalloc.h>
25#include <linux/clk.h> 25#include <linux/clk.h>
26#include <linux/io.h> 26#include <linux/io.h>
27#include <linux/platform_device.h>
27 28
28#include <mach/sram.h> 29#include <plat/sram.h>
29#include <mach/omapfb.h> 30#include <plat/board.h>
30#include <mach/board.h>
31 31
32#include "omapfb.h"
32#include "dispc.h" 33#include "dispc.h"
33 34
34#define MODULE_NAME "dispc" 35#define MODULE_NAME "dispc"
@@ -204,6 +205,7 @@ static u32 inline dispc_read_reg(int idx)
204/* Select RFBI or bypass mode */ 205/* Select RFBI or bypass mode */
205static void enable_rfbi_mode(int enable) 206static void enable_rfbi_mode(int enable)
206{ 207{
208 void __iomem *rfbi_control;
207 u32 l; 209 u32 l;
208 210
209 l = dispc_read_reg(DISPC_CONTROL); 211 l = dispc_read_reg(DISPC_CONTROL);
@@ -216,9 +218,15 @@ static void enable_rfbi_mode(int enable)
216 dispc_write_reg(DISPC_CONTROL, l); 218 dispc_write_reg(DISPC_CONTROL, l);
217 219
218 /* Set bypass mode in RFBI module */ 220 /* Set bypass mode in RFBI module */
219 l = __raw_readl(OMAP2_IO_ADDRESS(RFBI_CONTROL)); 221 rfbi_control = ioremap(RFBI_CONTROL, SZ_1K);
222 if (!rfbi_control) {
223 pr_err("Unable to ioremap rfbi_control\n");
224 return;
225 }
226 l = __raw_readl(rfbi_control);
220 l |= enable ? 0 : (1 << 1); 227 l |= enable ? 0 : (1 << 1);
221 __raw_writel(l, OMAP2_IO_ADDRESS(RFBI_CONTROL)); 228 __raw_writel(l, rfbi_control);
229 iounmap(rfbi_control);
222} 230}
223 231
224static void set_lcd_data_lines(int data_lines) 232static void set_lcd_data_lines(int data_lines)
@@ -907,20 +915,20 @@ static irqreturn_t omap_dispc_irq_handler(int irq, void *dev)
907 915
908static int get_dss_clocks(void) 916static int get_dss_clocks(void)
909{ 917{
910 dispc.dss_ick = clk_get(dispc.fbdev->dev, "ick"); 918 dispc.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick");
911 if (IS_ERR(dispc.dss_ick)) { 919 if (IS_ERR(dispc.dss_ick)) {
912 dev_err(dispc.fbdev->dev, "can't get ick\n"); 920 dev_err(dispc.fbdev->dev, "can't get ick\n");
913 return PTR_ERR(dispc.dss_ick); 921 return PTR_ERR(dispc.dss_ick);
914 } 922 }
915 923
916 dispc.dss1_fck = clk_get(dispc.fbdev->dev, "dss1_fck"); 924 dispc.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck");
917 if (IS_ERR(dispc.dss1_fck)) { 925 if (IS_ERR(dispc.dss1_fck)) {
918 dev_err(dispc.fbdev->dev, "can't get dss1_fck\n"); 926 dev_err(dispc.fbdev->dev, "can't get dss1_fck\n");
919 clk_put(dispc.dss_ick); 927 clk_put(dispc.dss_ick);
920 return PTR_ERR(dispc.dss1_fck); 928 return PTR_ERR(dispc.dss1_fck);
921 } 929 }
922 930
923 dispc.dss_54m_fck = clk_get(dispc.fbdev->dev, "tv_fck"); 931 dispc.dss_54m_fck = clk_get(&dispc.fbdev->dssdev->dev, "tv_fck");
924 if (IS_ERR(dispc.dss_54m_fck)) { 932 if (IS_ERR(dispc.dss_54m_fck)) {
925 dev_err(dispc.fbdev->dev, "can't get tv_fck\n"); 933 dev_err(dispc.fbdev->dev, "can't get tv_fck\n");
926 clk_put(dispc.dss_ick); 934 clk_put(dispc.dss_ick);
@@ -1367,6 +1375,7 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
1367 int r; 1375 int r;
1368 u32 l; 1376 u32 l;
1369 struct lcd_panel *panel = fbdev->panel; 1377 struct lcd_panel *panel = fbdev->panel;
1378 void __iomem *ram_fw_base;
1370 int tmo = 10000; 1379 int tmo = 10000;
1371 int skip_init = 0; 1380 int skip_init = 0;
1372 int i; 1381 int i;
@@ -1441,7 +1450,13 @@ static int omap_dispc_init(struct omapfb_device *fbdev, int ext_mode,
1441 } 1450 }
1442 1451
1443 /* L3 firewall setting: enable access to OCM RAM */ 1452 /* L3 firewall setting: enable access to OCM RAM */
1444 __raw_writel(0x402000b0, OMAP2_IO_ADDRESS(0x680050a0)); 1453 ram_fw_base = ioremap(0x68005000, SZ_1K);
1454 if (!ram_fw_base) {
1455 dev_err(dispc.fbdev->dev, "Cannot ioremap to enable OCM RAM\n");
1456 goto fail1;
1457 }
1458 __raw_writel(0x402000b0, ram_fw_base + 0xa0);
1459 iounmap(ram_fw_base);
1445 1460
1446 if ((r = alloc_palette_ram()) < 0) 1461 if ((r = alloc_palette_ram()) < 0)
1447 goto fail2; 1462 goto fail2;
diff --git a/drivers/video/omap/hwa742.c b/drivers/video/omap/hwa742.c
index ca51583ec98a..0016f77cd13f 100644
--- a/drivers/video/omap/hwa742.c
+++ b/drivers/video/omap/hwa742.c
@@ -25,10 +25,11 @@
25#include <linux/fb.h> 25#include <linux/fb.h>
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/clk.h> 27#include <linux/clk.h>
28#include <linux/interrupt.h>
28 29
29#include <mach/dma.h> 30#include <plat/dma.h>
30#include <mach/omapfb.h> 31#include <plat/hwa742.h>
31#include <mach/hwa742.h> 32#include "omapfb.h"
32 33
33#define HWA742_REV_CODE_REG 0x0 34#define HWA742_REV_CODE_REG 0x0
34#define HWA742_CONFIG_REG 0x2 35#define HWA742_CONFIG_REG 0x2
diff --git a/drivers/video/omap/lcd_2430sdp.c b/drivers/video/omap/lcd_2430sdp.c
index 393712b6f369..e3eccc9af78e 100644
--- a/drivers/video/omap/lcd_2430sdp.c
+++ b/drivers/video/omap/lcd_2430sdp.c
@@ -25,12 +25,13 @@
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/gpio.h> 27#include <linux/gpio.h>
28#include <linux/i2c/twl4030.h> 28#include <linux/i2c/twl.h>
29 29
30#include <mach/mux.h> 30#include <plat/mux.h>
31#include <mach/omapfb.h>
32#include <asm/mach-types.h> 31#include <asm/mach-types.h>
33 32
33#include "omapfb.h"
34
34#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO 91 35#define SDP2430_LCD_PANEL_BACKLIGHT_GPIO 91
35#define SDP2430_LCD_PANEL_ENABLE_GPIO 154 36#define SDP2430_LCD_PANEL_ENABLE_GPIO 154
36#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 24 37#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 24
@@ -51,7 +52,7 @@ static unsigned enable_gpio;
51#define TWL4030_VPLL2_DEV_GRP 0x33 52#define TWL4030_VPLL2_DEV_GRP 0x33
52#define TWL4030_VPLL2_DEDICATED 0x36 53#define TWL4030_VPLL2_DEDICATED 0x36
53 54
54#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v) 55#define t2_out(c, r, v) twl_i2c_write_u8(c, r, v)
55 56
56 57
57static int sdp2430_panel_init(struct lcd_panel *panel, 58static int sdp2430_panel_init(struct lcd_panel *panel,
diff --git a/drivers/video/omap/lcd_ams_delta.c b/drivers/video/omap/lcd_ams_delta.c
index 1f7439955e02..567db6ac32c8 100644
--- a/drivers/video/omap/lcd_ams_delta.c
+++ b/drivers/video/omap/lcd_ams_delta.c
@@ -25,9 +25,10 @@
25#include <linux/io.h> 25#include <linux/io.h>
26#include <linux/delay.h> 26#include <linux/delay.h>
27 27
28#include <mach/board-ams-delta.h> 28#include <plat/board-ams-delta.h>
29#include <mach/hardware.h> 29#include <mach/hardware.h>
30#include <mach/omapfb.h> 30
31#include "omapfb.h"
31 32
32#define AMS_DELTA_DEFAULT_CONTRAST 112 33#define AMS_DELTA_DEFAULT_CONTRAST 112
33 34
@@ -123,12 +124,12 @@ struct platform_driver ams_delta_panel_driver = {
123 }, 124 },
124}; 125};
125 126
126static int ams_delta_panel_drv_init(void) 127static int __init ams_delta_panel_drv_init(void)
127{ 128{
128 return platform_driver_register(&ams_delta_panel_driver); 129 return platform_driver_register(&ams_delta_panel_driver);
129} 130}
130 131
131static void ams_delta_panel_drv_cleanup(void) 132static void __exit ams_delta_panel_drv_cleanup(void)
132{ 133{
133 platform_driver_unregister(&ams_delta_panel_driver); 134 platform_driver_unregister(&ams_delta_panel_driver);
134} 135}
diff --git a/drivers/video/omap/lcd_apollon.c b/drivers/video/omap/lcd_apollon.c
index 626ae3a532ff..2be94eb3bbf5 100644
--- a/drivers/video/omap/lcd_apollon.c
+++ b/drivers/video/omap/lcd_apollon.c
@@ -25,8 +25,9 @@
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26 26
27#include <mach/gpio.h> 27#include <mach/gpio.h>
28#include <mach/mux.h> 28#include <plat/mux.h>
29#include <mach/omapfb.h> 29
30#include "omapfb.h"
30 31
31/* #define USE_35INCH_LCD 1 */ 32/* #define USE_35INCH_LCD 1 */
32 33
diff --git a/drivers/video/omap/lcd_h3.c b/drivers/video/omap/lcd_h3.c
index 417ae5efa8bb..8df688748b5a 100644
--- a/drivers/video/omap/lcd_h3.c
+++ b/drivers/video/omap/lcd_h3.c
@@ -24,7 +24,7 @@
24#include <linux/i2c/tps65010.h> 24#include <linux/i2c/tps65010.h>
25 25
26#include <mach/gpio.h> 26#include <mach/gpio.h>
27#include <mach/omapfb.h> 27#include "omapfb.h"
28 28
29#define MODULE_NAME "omapfb-lcd_h3" 29#define MODULE_NAME "omapfb-lcd_h3"
30 30
diff --git a/drivers/video/omap/lcd_h4.c b/drivers/video/omap/lcd_h4.c
index 0c398bda7601..03a06a982750 100644
--- a/drivers/video/omap/lcd_h4.c
+++ b/drivers/video/omap/lcd_h4.c
@@ -22,7 +22,7 @@
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24 24
25#include <mach/omapfb.h> 25#include "omapfb.h"
26 26
27static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) 27static int h4_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
28{ 28{
diff --git a/drivers/video/omap/lcd_htcherald.c b/drivers/video/omap/lcd_htcherald.c
new file mode 100644
index 000000000000..4802419da83b
--- /dev/null
+++ b/drivers/video/omap/lcd_htcherald.c
@@ -0,0 +1,130 @@
1/*
2 * File: drivers/video/omap/lcd-htcherald.c
3 *
4 * LCD panel support for the HTC Herald
5 *
6 * Copyright (C) 2009 Cory Maccarrone <darkstar6262@gmail.com>
7 * Copyright (C) 2009 Wing Linux
8 *
9 * Based on the lcd_htcwizard.c file from the linwizard project:
10 * Copyright (C) linwizard.sourceforge.net
11 * Author: Angelo Arrifano <miknix@gmail.com>
12 * Based on lcd_h4 by Imre Deak <imre.deak@nokia.com>
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29#include <linux/module.h>
30#include <linux/platform_device.h>
31
32#include "omapfb.h"
33
34static int htcherald_panel_init(struct lcd_panel *panel,
35 struct omapfb_device *fbdev)
36{
37 return 0;
38}
39
40static void htcherald_panel_cleanup(struct lcd_panel *panel)
41{
42}
43
44static int htcherald_panel_enable(struct lcd_panel *panel)
45{
46 return 0;
47}
48
49static void htcherald_panel_disable(struct lcd_panel *panel)
50{
51}
52
53static unsigned long htcherald_panel_get_caps(struct lcd_panel *panel)
54{
55 return 0;
56}
57
58/* Found on WIZ200 (miknix) and some HERA110 models (darkstar62) */
59struct lcd_panel htcherald_panel_1 = {
60 .name = "lcd_herald",
61 .config = OMAP_LCDC_PANEL_TFT |
62 OMAP_LCDC_INV_HSYNC |
63 OMAP_LCDC_INV_VSYNC |
64 OMAP_LCDC_INV_PIX_CLOCK,
65 .bpp = 16,
66 .data_lines = 16,
67 .x_res = 240,
68 .y_res = 320,
69 .pixel_clock = 6093,
70 .pcd = 0, /* 15 */
71 .hsw = 10,
72 .hfp = 10,
73 .hbp = 20,
74 .vsw = 3,
75 .vfp = 2,
76 .vbp = 2,
77
78 .init = htcherald_panel_init,
79 .cleanup = htcherald_panel_cleanup,
80 .enable = htcherald_panel_enable,
81 .disable = htcherald_panel_disable,
82 .get_caps = htcherald_panel_get_caps,
83};
84
85static int htcherald_panel_probe(struct platform_device *pdev)
86{
87 omapfb_register_panel(&htcherald_panel_1);
88 return 0;
89}
90
91static int htcherald_panel_remove(struct platform_device *pdev)
92{
93 return 0;
94}
95
96static int htcherald_panel_suspend(struct platform_device *pdev,
97 pm_message_t mesg)
98{
99 return 0;
100}
101
102static int htcherald_panel_resume(struct platform_device *pdev)
103{
104 return 0;
105}
106
107struct platform_driver htcherald_panel_driver = {
108 .probe = htcherald_panel_probe,
109 .remove = htcherald_panel_remove,
110 .suspend = htcherald_panel_suspend,
111 .resume = htcherald_panel_resume,
112 .driver = {
113 .name = "lcd_htcherald",
114 .owner = THIS_MODULE,
115 },
116};
117
118static int __init htcherald_panel_drv_init(void)
119{
120 return platform_driver_register(&htcherald_panel_driver);
121}
122
123static void __exit htcherald_panel_drv_cleanup(void)
124{
125 platform_driver_unregister(&htcherald_panel_driver);
126}
127
128module_init(htcherald_panel_drv_init);
129module_exit(htcherald_panel_drv_cleanup);
130
diff --git a/drivers/video/omap/lcd_inn1510.c b/drivers/video/omap/lcd_inn1510.c
index cdbd8bb607be..3271f1643b26 100644
--- a/drivers/video/omap/lcd_inn1510.c
+++ b/drivers/video/omap/lcd_inn1510.c
@@ -23,8 +23,8 @@
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24#include <linux/io.h> 24#include <linux/io.h>
25 25
26#include <mach/fpga.h> 26#include <plat/fpga.h>
27#include <mach/omapfb.h> 27#include "omapfb.h"
28 28
29static int innovator1510_panel_init(struct lcd_panel *panel, 29static int innovator1510_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev) 30 struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_inn1610.c b/drivers/video/omap/lcd_inn1610.c
index 268f7f808a4e..9fff86f67bde 100644
--- a/drivers/video/omap/lcd_inn1610.c
+++ b/drivers/video/omap/lcd_inn1610.c
@@ -23,7 +23,7 @@
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24 24
25#include <mach/gpio.h> 25#include <mach/gpio.h>
26#include <mach/omapfb.h> 26#include "omapfb.h"
27 27
28#define MODULE_NAME "omapfb-lcd_h3" 28#define MODULE_NAME "omapfb-lcd_h3"
29 29
diff --git a/drivers/video/omap/lcd_ldp.c b/drivers/video/omap/lcd_ldp.c
index dbfe8974fb94..0f5952cae85e 100644
--- a/drivers/video/omap/lcd_ldp.c
+++ b/drivers/video/omap/lcd_ldp.c
@@ -24,13 +24,14 @@
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/i2c/twl4030.h> 27#include <linux/i2c/twl.h>
28 28
29#include <mach/gpio.h> 29#include <mach/gpio.h>
30#include <mach/mux.h> 30#include <plat/mux.h>
31#include <mach/omapfb.h>
32#include <asm/mach-types.h> 31#include <asm/mach-types.h>
33 32
33#include "omapfb.h"
34
34#define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES) 35#define LCD_PANEL_BACKLIGHT_GPIO (15 + OMAP_MAX_GPIO_LINES)
35#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES) 36#define LCD_PANEL_ENABLE_GPIO (7 + OMAP_MAX_GPIO_LINES)
36 37
@@ -58,7 +59,7 @@
58#define TWL4030_VPLL2_DEV_GRP 0x33 59#define TWL4030_VPLL2_DEV_GRP 0x33
59#define TWL4030_VPLL2_DEDICATED 0x36 60#define TWL4030_VPLL2_DEDICATED 0x36
60 61
61#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v) 62#define t2_out(c, r, v) twl_i2c_write_u8(c, r, v)
62 63
63 64
64static int ldp_panel_init(struct lcd_panel *panel, 65static int ldp_panel_init(struct lcd_panel *panel,
diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c
index 918ee8934196..abe1c76a3257 100644
--- a/drivers/video/omap/lcd_mipid.c
+++ b/drivers/video/omap/lcd_mipid.c
@@ -23,8 +23,9 @@
23#include <linux/workqueue.h> 23#include <linux/workqueue.h>
24#include <linux/spi/spi.h> 24#include <linux/spi/spi.h>
25 25
26#include <mach/omapfb.h> 26#include <plat/lcd_mipid.h>
27#include <mach/lcd_mipid.h> 27
28#include "omapfb.h"
28 29
29#define MIPID_MODULE_NAME "lcd_mipid" 30#define MIPID_MODULE_NAME "lcd_mipid"
30 31
@@ -607,7 +608,7 @@ static struct spi_driver mipid_spi_driver = {
607 .remove = __devexit_p(mipid_spi_remove), 608 .remove = __devexit_p(mipid_spi_remove),
608}; 609};
609 610
610static int mipid_drv_init(void) 611static int __init mipid_drv_init(void)
611{ 612{
612 spi_register_driver(&mipid_spi_driver); 613 spi_register_driver(&mipid_spi_driver);
613 614
@@ -615,7 +616,7 @@ static int mipid_drv_init(void)
615} 616}
616module_init(mipid_drv_init); 617module_init(mipid_drv_init);
617 618
618static void mipid_drv_cleanup(void) 619static void __exit mipid_drv_cleanup(void)
619{ 620{
620 spi_unregister_driver(&mipid_spi_driver); 621 spi_unregister_driver(&mipid_spi_driver);
621} 622}
diff --git a/drivers/video/omap/lcd_omap2evm.c b/drivers/video/omap/lcd_omap2evm.c
index 7a2bbe2ecec3..7e7a65c08452 100644
--- a/drivers/video/omap/lcd_omap2evm.c
+++ b/drivers/video/omap/lcd_omap2evm.c
@@ -24,12 +24,13 @@
24#include <linux/module.h> 24#include <linux/module.h>
25#include <linux/platform_device.h> 25#include <linux/platform_device.h>
26#include <linux/gpio.h> 26#include <linux/gpio.h>
27#include <linux/i2c/twl4030.h> 27#include <linux/i2c/twl.h>
28 28
29#include <mach/mux.h> 29#include <plat/mux.h>
30#include <mach/omapfb.h>
31#include <asm/mach-types.h> 30#include <asm/mach-types.h>
32 31
32#include "omapfb.h"
33
33#define LCD_PANEL_ENABLE_GPIO 154 34#define LCD_PANEL_ENABLE_GPIO 154
34#define LCD_PANEL_LR 128 35#define LCD_PANEL_LR 128
35#define LCD_PANEL_UD 129 36#define LCD_PANEL_UD 129
@@ -60,9 +61,9 @@ static int omap2evm_panel_init(struct lcd_panel *panel,
60 gpio_direction_output(LCD_PANEL_LR, 1); 61 gpio_direction_output(LCD_PANEL_LR, 1);
61 gpio_direction_output(LCD_PANEL_UD, 1); 62 gpio_direction_output(LCD_PANEL_UD, 1);
62 63
63 twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN); 64 twl_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
64 twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON); 65 twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
65 twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF); 66 twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
66 bklight_level = 100; 67 bklight_level = 100;
67 68
68 return 0; 69 return 0;
@@ -100,7 +101,7 @@ static int omap2evm_bklight_setlevel(struct lcd_panel *panel,
100 u8 c; 101 u8 c;
101 if ((level >= 0) && (level <= 100)) { 102 if ((level >= 0) && (level <= 100)) {
102 c = (125 * (100 - level)) / 100 + 2; 103 c = (125 * (100 - level)) / 100 + 2;
103 twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF); 104 twl_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
104 bklight_level = level; 105 bklight_level = level;
105 } 106 }
106 return 0; 107 return 0;
diff --git a/drivers/video/omap/lcd_omap3beagle.c b/drivers/video/omap/lcd_omap3beagle.c
index 4011910123bf..ca75cc2a87a5 100644
--- a/drivers/video/omap/lcd_omap3beagle.c
+++ b/drivers/video/omap/lcd_omap3beagle.c
@@ -23,12 +23,14 @@
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <linux/gpio.h> 25#include <linux/gpio.h>
26#include <linux/i2c/twl4030.h> 26#include <linux/i2c/twl.h>
27 27
28#include <mach/mux.h> 28#include <plat/mux.h>
29#include <mach/omapfb.h> 29#include <plat/mux.h>
30#include <asm/mach-types.h> 30#include <asm/mach-types.h>
31 31
32#include "omapfb.h"
33
32#define LCD_PANEL_ENABLE_GPIO 170 34#define LCD_PANEL_ENABLE_GPIO 170
33 35
34static int omap3beagle_panel_init(struct lcd_panel *panel, 36static int omap3beagle_panel_init(struct lcd_panel *panel,
diff --git a/drivers/video/omap/lcd_omap3evm.c b/drivers/video/omap/lcd_omap3evm.c
index b6a4c2c57a2f..06840da0b094 100644
--- a/drivers/video/omap/lcd_omap3evm.c
+++ b/drivers/video/omap/lcd_omap3evm.c
@@ -23,12 +23,13 @@
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <linux/gpio.h> 25#include <linux/gpio.h>
26#include <linux/i2c/twl4030.h> 26#include <linux/i2c/twl.h>
27 27
28#include <mach/mux.h> 28#include <plat/mux.h>
29#include <mach/omapfb.h>
30#include <asm/mach-types.h> 29#include <asm/mach-types.h>
31 30
31#include "omapfb.h"
32
32#define LCD_PANEL_ENABLE_GPIO 153 33#define LCD_PANEL_ENABLE_GPIO 153
33#define LCD_PANEL_LR 2 34#define LCD_PANEL_LR 2
34#define LCD_PANEL_UD 3 35#define LCD_PANEL_UD 3
@@ -62,9 +63,9 @@ static int omap3evm_panel_init(struct lcd_panel *panel,
62 gpio_direction_output(LCD_PANEL_LR, 1); 63 gpio_direction_output(LCD_PANEL_LR, 1);
63 gpio_direction_output(LCD_PANEL_UD, 1); 64 gpio_direction_output(LCD_PANEL_UD, 1);
64 65
65 twl4030_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN); 66 twl_i2c_write_u8(TWL4030_MODULE_LED, 0x11, TWL_LED_LEDEN);
66 twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON); 67 twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x01, TWL_PWMA_PWMAON);
67 twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF); 68 twl_i2c_write_u8(TWL4030_MODULE_PWMA, 0x02, TWL_PWMA_PWMAOFF);
68 bklight_level = 100; 69 bklight_level = 100;
69 70
70 return 0; 71 return 0;
@@ -101,7 +102,7 @@ static int omap3evm_bklight_setlevel(struct lcd_panel *panel,
101 u8 c; 102 u8 c;
102 if ((level >= 0) && (level <= 100)) { 103 if ((level >= 0) && (level <= 100)) {
103 c = (125 * (100 - level)) / 100 + 2; 104 c = (125 * (100 - level)) / 100 + 2;
104 twl4030_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF); 105 twl_i2c_write_u8(TWL4030_MODULE_PWMA, c, TWL_PWMA_PWMAOFF);
105 bklight_level = level; 106 bklight_level = level;
106 } 107 }
107 return 0; 108 return 0;
diff --git a/drivers/video/omap/lcd_osk.c b/drivers/video/omap/lcd_osk.c
index b3fa88bc6269..b87e8b83f29c 100644
--- a/drivers/video/omap/lcd_osk.c
+++ b/drivers/video/omap/lcd_osk.c
@@ -24,8 +24,8 @@
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25 25
26#include <mach/gpio.h> 26#include <mach/gpio.h>
27#include <mach/mux.h> 27#include <plat/mux.h>
28#include <mach/omapfb.h> 28#include "omapfb.h"
29 29
30static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev) 30static int osk_panel_init(struct lcd_panel *panel, struct omapfb_device *fbdev)
31{ 31{
diff --git a/drivers/video/omap/lcd_overo.c b/drivers/video/omap/lcd_overo.c
index 2bc5c9268e5e..564933ffac6e 100644
--- a/drivers/video/omap/lcd_overo.c
+++ b/drivers/video/omap/lcd_overo.c
@@ -21,13 +21,14 @@
21 21
22#include <linux/module.h> 22#include <linux/module.h>
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24#include <linux/i2c/twl4030.h> 24#include <linux/i2c/twl.h>
25 25
26#include <mach/gpio.h> 26#include <mach/gpio.h>
27#include <mach/mux.h> 27#include <plat/mux.h>
28#include <mach/omapfb.h>
29#include <asm/mach-types.h> 28#include <asm/mach-types.h>
30 29
30#include "omapfb.h"
31
31#define LCD_ENABLE 144 32#define LCD_ENABLE 144
32 33
33static int overo_panel_init(struct lcd_panel *panel, 34static int overo_panel_init(struct lcd_panel *panel,
diff --git a/drivers/video/omap/lcd_palmte.c b/drivers/video/omap/lcd_palmte.c
index 4bf3c79f3cc7..4cb301750d02 100644
--- a/drivers/video/omap/lcd_palmte.c
+++ b/drivers/video/omap/lcd_palmte.c
@@ -23,8 +23,8 @@
23#include <linux/platform_device.h> 23#include <linux/platform_device.h>
24#include <linux/io.h> 24#include <linux/io.h>
25 25
26#include <mach/fpga.h> 26#include <plat/fpga.h>
27#include <mach/omapfb.h> 27#include "omapfb.h"
28 28
29static int palmte_panel_init(struct lcd_panel *panel, 29static int palmte_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev) 30 struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_palmtt.c b/drivers/video/omap/lcd_palmtt.c
index 48ea1f9f2cbf..ff0e6d7ab3a2 100644
--- a/drivers/video/omap/lcd_palmtt.c
+++ b/drivers/video/omap/lcd_palmtt.c
@@ -30,7 +30,7 @@ GPIO13 - screen blanking
30#include <linux/io.h> 30#include <linux/io.h>
31 31
32#include <mach/gpio.h> 32#include <mach/gpio.h>
33#include <mach/omapfb.h> 33#include "omapfb.h"
34 34
35static int palmtt_panel_init(struct lcd_panel *panel, 35static int palmtt_panel_init(struct lcd_panel *panel,
36 struct omapfb_device *fbdev) 36 struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcd_palmz71.c b/drivers/video/omap/lcd_palmz71.c
index 0697d29b4d3b..2334e56536bc 100644
--- a/drivers/video/omap/lcd_palmz71.c
+++ b/drivers/video/omap/lcd_palmz71.c
@@ -24,7 +24,7 @@
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <linux/io.h> 25#include <linux/io.h>
26 26
27#include <mach/omapfb.h> 27#include "omapfb.h"
28 28
29static int palmz71_panel_init(struct lcd_panel *panel, 29static int palmz71_panel_init(struct lcd_panel *panel,
30 struct omapfb_device *fbdev) 30 struct omapfb_device *fbdev)
diff --git a/drivers/video/omap/lcdc.c b/drivers/video/omap/lcdc.c
index ab3949256677..a33483910dc8 100644
--- a/drivers/video/omap/lcdc.c
+++ b/drivers/video/omap/lcdc.c
@@ -29,47 +29,17 @@
29#include <linux/vmalloc.h> 29#include <linux/vmalloc.h>
30#include <linux/clk.h> 30#include <linux/clk.h>
31 31
32#include <mach/dma.h> 32#include <mach/lcdc.h>
33#include <mach/omapfb.h> 33#include <plat/dma.h>
34 34
35#include <asm/mach-types.h> 35#include <asm/mach-types.h>
36 36
37#include "omapfb.h"
38
37#include "lcdc.h" 39#include "lcdc.h"
38 40
39#define MODULE_NAME "lcdc" 41#define MODULE_NAME "lcdc"
40 42
41#define OMAP_LCDC_BASE 0xfffec000
42#define OMAP_LCDC_SIZE 256
43#define OMAP_LCDC_IRQ INT_LCD_CTRL
44
45#define OMAP_LCDC_CONTROL (OMAP_LCDC_BASE + 0x00)
46#define OMAP_LCDC_TIMING0 (OMAP_LCDC_BASE + 0x04)
47#define OMAP_LCDC_TIMING1 (OMAP_LCDC_BASE + 0x08)
48#define OMAP_LCDC_TIMING2 (OMAP_LCDC_BASE + 0x0c)
49#define OMAP_LCDC_STATUS (OMAP_LCDC_BASE + 0x10)
50#define OMAP_LCDC_SUBPANEL (OMAP_LCDC_BASE + 0x14)
51#define OMAP_LCDC_LINE_INT (OMAP_LCDC_BASE + 0x18)
52#define OMAP_LCDC_DISPLAY_STATUS (OMAP_LCDC_BASE + 0x1c)
53
54#define OMAP_LCDC_STAT_DONE (1 << 0)
55#define OMAP_LCDC_STAT_VSYNC (1 << 1)
56#define OMAP_LCDC_STAT_SYNC_LOST (1 << 2)
57#define OMAP_LCDC_STAT_ABC (1 << 3)
58#define OMAP_LCDC_STAT_LINE_INT (1 << 4)
59#define OMAP_LCDC_STAT_FUF (1 << 5)
60#define OMAP_LCDC_STAT_LOADED_PALETTE (1 << 6)
61
62#define OMAP_LCDC_CTRL_LCD_EN (1 << 0)
63#define OMAP_LCDC_CTRL_LCD_TFT (1 << 7)
64#define OMAP_LCDC_CTRL_LINE_IRQ_CLR_SEL (1 << 10)
65
66#define OMAP_LCDC_IRQ_VSYNC (1 << 2)
67#define OMAP_LCDC_IRQ_DONE (1 << 3)
68#define OMAP_LCDC_IRQ_LOADED_PALETTE (1 << 4)
69#define OMAP_LCDC_IRQ_LINE_NIRQ (1 << 5)
70#define OMAP_LCDC_IRQ_LINE (1 << 6)
71#define OMAP_LCDC_IRQ_MASK (((1 << 5) - 1) << 2)
72
73#define MAX_PALETTE_SIZE PAGE_SIZE 43#define MAX_PALETTE_SIZE PAGE_SIZE
74 44
75enum lcdc_load_mode { 45enum lcdc_load_mode {
diff --git a/drivers/video/omap/omapfb.h b/drivers/video/omap/omapfb.h
new file mode 100644
index 000000000000..af3c9e571ec3
--- /dev/null
+++ b/drivers/video/omap/omapfb.h
@@ -0,0 +1,229 @@
1/*
2 * File: drivers/video/omap/omapfb.h
3 *
4 * Framebuffer driver for TI OMAP boards
5 *
6 * Copyright (C) 2004 Nokia Corporation
7 * Author: Imre Deak <imre.deak@nokia.com>
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24#ifndef __OMAPFB_H
25#define __OMAPFB_H
26
27#include <linux/fb.h>
28#include <linux/mutex.h>
29#include <linux/omapfb.h>
30
31#define OMAPFB_EVENT_READY 1
32#define OMAPFB_EVENT_DISABLED 2
33
34#define OMAP_LCDC_INV_VSYNC 0x0001
35#define OMAP_LCDC_INV_HSYNC 0x0002
36#define OMAP_LCDC_INV_PIX_CLOCK 0x0004
37#define OMAP_LCDC_INV_OUTPUT_EN 0x0008
38#define OMAP_LCDC_HSVS_RISING_EDGE 0x0010
39#define OMAP_LCDC_HSVS_OPPOSITE 0x0020
40
41#define OMAP_LCDC_SIGNAL_MASK 0x003f
42
43#define OMAP_LCDC_PANEL_TFT 0x0100
44
45#define OMAPFB_PLANE_XRES_MIN 8
46#define OMAPFB_PLANE_YRES_MIN 8
47
48struct omapfb_device;
49
50struct lcd_panel {
51 const char *name;
52 int config; /* TFT/STN, signal inversion */
53 int bpp; /* Pixel format in fb mem */
54 int data_lines; /* Lines on LCD HW interface */
55
56 int x_res, y_res;
57 int pixel_clock; /* In kHz */
58 int hsw; /* Horizontal synchronization
59 pulse width */
60 int hfp; /* Horizontal front porch */
61 int hbp; /* Horizontal back porch */
62 int vsw; /* Vertical synchronization
63 pulse width */
64 int vfp; /* Vertical front porch */
65 int vbp; /* Vertical back porch */
66 int acb; /* ac-bias pin frequency */
67 int pcd; /* pixel clock divider.
68 Obsolete use pixel_clock instead */
69
70 int (*init) (struct lcd_panel *panel,
71 struct omapfb_device *fbdev);
72 void (*cleanup) (struct lcd_panel *panel);
73 int (*enable) (struct lcd_panel *panel);
74 void (*disable) (struct lcd_panel *panel);
75 unsigned long (*get_caps) (struct lcd_panel *panel);
76 int (*set_bklight_level)(struct lcd_panel *panel,
77 unsigned int level);
78 unsigned int (*get_bklight_level)(struct lcd_panel *panel);
79 unsigned int (*get_bklight_max) (struct lcd_panel *panel);
80 int (*run_test) (struct lcd_panel *panel, int test_num);
81};
82
83struct extif_timings {
84 int cs_on_time;
85 int cs_off_time;
86 int we_on_time;
87 int we_off_time;
88 int re_on_time;
89 int re_off_time;
90 int we_cycle_time;
91 int re_cycle_time;
92 int cs_pulse_width;
93 int access_time;
94
95 int clk_div;
96
97 u32 tim[5]; /* set by extif->convert_timings */
98
99 int converted;
100};
101
102struct lcd_ctrl_extif {
103 int (*init) (struct omapfb_device *fbdev);
104 void (*cleanup) (void);
105 void (*get_clk_info) (u32 *clk_period, u32 *max_clk_div);
106 unsigned long (*get_max_tx_rate)(void);
107 int (*convert_timings) (struct extif_timings *timings);
108 void (*set_timings) (const struct extif_timings *timings);
109 void (*set_bits_per_cycle)(int bpc);
110 void (*write_command) (const void *buf, unsigned int len);
111 void (*read_data) (void *buf, unsigned int len);
112 void (*write_data) (const void *buf, unsigned int len);
113 void (*transfer_area) (int width, int height,
114 void (callback)(void *data), void *data);
115 int (*setup_tearsync) (unsigned pin_cnt,
116 unsigned hs_pulse_time, unsigned vs_pulse_time,
117 int hs_pol_inv, int vs_pol_inv, int div);
118 int (*enable_tearsync) (int enable, unsigned line);
119
120 unsigned long max_transmit_size;
121};
122
123struct omapfb_notifier_block {
124 struct notifier_block nb;
125 void *data;
126 int plane_idx;
127};
128
129typedef int (*omapfb_notifier_callback_t)(struct notifier_block *,
130 unsigned long event,
131 void *fbi);
132
133struct lcd_ctrl {
134 const char *name;
135 void *data;
136
137 int (*init) (struct omapfb_device *fbdev,
138 int ext_mode,
139 struct omapfb_mem_desc *req_md);
140 void (*cleanup) (void);
141 void (*bind_client) (struct omapfb_notifier_block *nb);
142 void (*get_caps) (int plane, struct omapfb_caps *caps);
143 int (*set_update_mode)(enum omapfb_update_mode mode);
144 enum omapfb_update_mode (*get_update_mode)(void);
145 int (*setup_plane) (int plane, int channel_out,
146 unsigned long offset,
147 int screen_width,
148 int pos_x, int pos_y, int width,
149 int height, int color_mode);
150 int (*set_rotate) (int angle);
151 int (*setup_mem) (int plane, size_t size,
152 int mem_type, unsigned long *paddr);
153 int (*mmap) (struct fb_info *info,
154 struct vm_area_struct *vma);
155 int (*set_scale) (int plane,
156 int orig_width, int orig_height,
157 int out_width, int out_height);
158 int (*enable_plane) (int plane, int enable);
159 int (*update_window) (struct fb_info *fbi,
160 struct omapfb_update_window *win,
161 void (*callback)(void *),
162 void *callback_data);
163 void (*sync) (void);
164 void (*suspend) (void);
165 void (*resume) (void);
166 int (*run_test) (int test_num);
167 int (*setcolreg) (u_int regno, u16 red, u16 green,
168 u16 blue, u16 transp,
169 int update_hw_mem);
170 int (*set_color_key) (struct omapfb_color_key *ck);
171 int (*get_color_key) (struct omapfb_color_key *ck);
172};
173
174enum omapfb_state {
175 OMAPFB_DISABLED = 0,
176 OMAPFB_SUSPENDED = 99,
177 OMAPFB_ACTIVE = 100
178};
179
180struct omapfb_plane_struct {
181 int idx;
182 struct omapfb_plane_info info;
183 enum omapfb_color_format color_mode;
184 struct omapfb_device *fbdev;
185};
186
187struct omapfb_device {
188 int state;
189 int ext_lcdc; /* Using external
190 LCD controller */
191 struct mutex rqueue_mutex;
192
193 int palette_size;
194 u32 pseudo_palette[17];
195
196 struct lcd_panel *panel; /* LCD panel */
197 const struct lcd_ctrl *ctrl; /* LCD controller */
198 const struct lcd_ctrl *int_ctrl; /* internal LCD ctrl */
199 struct lcd_ctrl_extif *ext_if; /* LCD ctrl external
200 interface */
201 struct device *dev;
202 struct fb_var_screeninfo new_var; /* for mode changes */
203
204 struct omapfb_mem_desc mem_desc;
205 struct fb_info *fb_info[OMAPFB_PLANE_NUM];
206
207 struct platform_device *dssdev; /* dummy dev for clocks */
208};
209
210#ifdef CONFIG_ARCH_OMAP1
211extern struct lcd_ctrl omap1_lcd_ctrl;
212#else
213extern struct lcd_ctrl omap2_disp_ctrl;
214#endif
215
216extern void omapfb_register_panel(struct lcd_panel *panel);
217extern void omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval);
218extern void omapfb_notify_clients(struct omapfb_device *fbdev,
219 unsigned long event);
220extern int omapfb_register_client(struct omapfb_notifier_block *nb,
221 omapfb_notifier_callback_t callback,
222 void *callback_data);
223extern int omapfb_unregister_client(struct omapfb_notifier_block *nb);
224extern int omapfb_update_window_async(struct fb_info *fbi,
225 struct omapfb_update_window *win,
226 void (*callback)(void *),
227 void *callback_data);
228
229#endif /* __OMAPFB_H */
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index 0d0c8c8b9b56..2c4f470fa086 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -28,9 +28,9 @@
28#include <linux/mm.h> 28#include <linux/mm.h>
29#include <linux/uaccess.h> 29#include <linux/uaccess.h>
30 30
31#include <mach/dma.h> 31#include <plat/dma.h>
32#include <mach/omapfb.h>
33 32
33#include "omapfb.h"
34#include "lcdc.h" 34#include "lcdc.h"
35#include "dispc.h" 35#include "dispc.h"
36 36
@@ -83,6 +83,19 @@ static struct caps_table_struct color_caps[] = {
83 { 1 << OMAPFB_COLOR_YUY422, "YUY422", }, 83 { 1 << OMAPFB_COLOR_YUY422, "YUY422", },
84}; 84};
85 85
86static void omapdss_release(struct device *dev)
87{
88}
89
90/* dummy device for clocks */
91static struct platform_device omapdss_device = {
92 .name = "omapdss",
93 .id = -1,
94 .dev = {
95 .release = omapdss_release,
96 },
97};
98
86/* 99/*
87 * --------------------------------------------------------------------------- 100 * ---------------------------------------------------------------------------
88 * LCD panel 101 * LCD panel
@@ -1700,6 +1713,7 @@ static int omapfb_do_probe(struct platform_device *pdev,
1700 1713
1701 fbdev->dev = &pdev->dev; 1714 fbdev->dev = &pdev->dev;
1702 fbdev->panel = panel; 1715 fbdev->panel = panel;
1716 fbdev->dssdev = &omapdss_device;
1703 platform_set_drvdata(pdev, fbdev); 1717 platform_set_drvdata(pdev, fbdev);
1704 1718
1705 mutex_init(&fbdev->rqueue_mutex); 1719 mutex_init(&fbdev->rqueue_mutex);
@@ -1814,8 +1828,16 @@ cleanup:
1814 1828
1815static int omapfb_probe(struct platform_device *pdev) 1829static int omapfb_probe(struct platform_device *pdev)
1816{ 1830{
1831 int r;
1832
1817 BUG_ON(fbdev_pdev != NULL); 1833 BUG_ON(fbdev_pdev != NULL);
1818 1834
1835 r = platform_device_register(&omapdss_device);
1836 if (r) {
1837 dev_err(&pdev->dev, "can't register omapdss device\n");
1838 return r;
1839 }
1840
1819 /* Delay actual initialization until the LCD is registered */ 1841 /* Delay actual initialization until the LCD is registered */
1820 fbdev_pdev = pdev; 1842 fbdev_pdev = pdev;
1821 if (fbdev_panel != NULL) 1843 if (fbdev_panel != NULL)
@@ -1843,6 +1865,9 @@ static int omapfb_remove(struct platform_device *pdev)
1843 fbdev->state = OMAPFB_DISABLED; 1865 fbdev->state = OMAPFB_DISABLED;
1844 omapfb_free_resources(fbdev, saved_state); 1866 omapfb_free_resources(fbdev, saved_state);
1845 1867
1868 platform_device_unregister(&omapdss_device);
1869 fbdev->dssdev = NULL;
1870
1846 return 0; 1871 return 0;
1847} 1872}
1848 1873
diff --git a/drivers/video/omap/rfbi.c b/drivers/video/omap/rfbi.c
index ee01e84e19c1..1162603c72e5 100644
--- a/drivers/video/omap/rfbi.c
+++ b/drivers/video/omap/rfbi.c
@@ -27,8 +27,7 @@
27#include <linux/clk.h> 27#include <linux/clk.h>
28#include <linux/io.h> 28#include <linux/io.h>
29 29
30#include <mach/omapfb.h> 30#include "omapfb.h"
31
32#include "dispc.h" 31#include "dispc.h"
33 32
34/* To work around an RFBI transfer rate limitation */ 33/* To work around an RFBI transfer rate limitation */
@@ -84,13 +83,13 @@ static inline u32 rfbi_read_reg(int idx)
84 83
85static int rfbi_get_clocks(void) 84static int rfbi_get_clocks(void)
86{ 85{
87 rfbi.dss_ick = clk_get(rfbi.fbdev->dev, "ick"); 86 rfbi.dss_ick = clk_get(&dispc.fbdev->dssdev->dev, "ick");
88 if (IS_ERR(rfbi.dss_ick)) { 87 if (IS_ERR(rfbi.dss_ick)) {
89 dev_err(rfbi.fbdev->dev, "can't get ick\n"); 88 dev_err(rfbi.fbdev->dev, "can't get ick\n");
90 return PTR_ERR(rfbi.dss_ick); 89 return PTR_ERR(rfbi.dss_ick);
91 } 90 }
92 91
93 rfbi.dss1_fck = clk_get(rfbi.fbdev->dev, "dss1_fck"); 92 rfbi.dss1_fck = clk_get(&dispc.fbdev->dssdev->dev, "dss1_fck");
94 if (IS_ERR(rfbi.dss1_fck)) { 93 if (IS_ERR(rfbi.dss1_fck)) {
95 dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n"); 94 dev_err(rfbi.fbdev->dev, "can't get dss1_fck\n");
96 clk_put(rfbi.dss_ick); 95 clk_put(rfbi.dss_ick);
diff --git a/drivers/video/omap/sossi.c b/drivers/video/omap/sossi.c
index a76946220249..8fb7c708f563 100644
--- a/drivers/video/omap/sossi.c
+++ b/drivers/video/omap/sossi.c
@@ -23,10 +23,11 @@
23#include <linux/clk.h> 23#include <linux/clk.h>
24#include <linux/irq.h> 24#include <linux/irq.h>
25#include <linux/io.h> 25#include <linux/io.h>
26#include <linux/interrupt.h>
26 27
27#include <mach/dma.h> 28#include <plat/dma.h>
28#include <mach/omapfb.h>
29 29
30#include "omapfb.h"
30#include "lcdc.h" 31#include "lcdc.h"
31 32
32#define MODULE_NAME "omapfb-sossi" 33#define MODULE_NAME "omapfb-sossi"
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig
new file mode 100644
index 000000000000..d877c361abda
--- /dev/null
+++ b/drivers/video/omap2/Kconfig
@@ -0,0 +1,9 @@
1config OMAP2_VRAM
2 bool
3
4config OMAP2_VRFB
5 bool
6
7source "drivers/video/omap2/dss/Kconfig"
8source "drivers/video/omap2/omapfb/Kconfig"
9source "drivers/video/omap2/displays/Kconfig"
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile
new file mode 100644
index 000000000000..d853d05dad31
--- /dev/null
+++ b/drivers/video/omap2/Makefile
@@ -0,0 +1,6 @@
1obj-$(CONFIG_OMAP2_VRAM) += vram.o
2obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
3
4obj-y += dss/
5obj-y += omapfb/
6obj-y += displays/
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig
new file mode 100644
index 000000000000..b12a59c9c50a
--- /dev/null
+++ b/drivers/video/omap2/displays/Kconfig
@@ -0,0 +1,22 @@
1menu "OMAP2/3 Display Device Drivers"
2 depends on OMAP2_DSS
3
4config PANEL_GENERIC
5 tristate "Generic Panel"
6 help
7 Generic panel driver.
8 Used for DVI output for Beagle and OMAP3 SDP.
9
10config PANEL_SHARP_LS037V7DW01
11 tristate "Sharp LS037V7DW01 LCD Panel"
12 depends on OMAP2_DSS
13 help
14 LCD Panel used in TI's SDP3430 and EVM boards
15
16config PANEL_TAAL
17 tristate "Taal DSI Panel"
18 depends on OMAP2_DSS_DSI
19 help
20 Taal DSI command mode panel from TPO.
21
22endmenu
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile
new file mode 100644
index 000000000000..955646440b3a
--- /dev/null
+++ b/drivers/video/omap2/displays/Makefile
@@ -0,0 +1,4 @@
1obj-$(CONFIG_PANEL_GENERIC) += panel-generic.o
2obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o
3
4obj-$(CONFIG_PANEL_TAAL) += panel-taal.o
diff --git a/drivers/video/omap2/displays/panel-generic.c b/drivers/video/omap2/displays/panel-generic.c
new file mode 100644
index 000000000000..eb48d1afd800
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-generic.c
@@ -0,0 +1,104 @@
1/*
2 * Generic panel support
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/module.h>
21#include <linux/delay.h>
22
23#include <plat/display.h>
24
25static struct omap_video_timings generic_panel_timings = {
26 /* 640 x 480 @ 60 Hz Reduced blanking VESA CVT 0.31M3-R */
27 .x_res = 640,
28 .y_res = 480,
29 .pixel_clock = 23500,
30 .hfp = 48,
31 .hsw = 32,
32 .hbp = 80,
33 .vfp = 3,
34 .vsw = 4,
35 .vbp = 7,
36};
37
38static int generic_panel_probe(struct omap_dss_device *dssdev)
39{
40 dssdev->panel.config = OMAP_DSS_LCD_TFT;
41 dssdev->panel.timings = generic_panel_timings;
42
43 return 0;
44}
45
46static void generic_panel_remove(struct omap_dss_device *dssdev)
47{
48}
49
50static int generic_panel_enable(struct omap_dss_device *dssdev)
51{
52 int r = 0;
53
54 if (dssdev->platform_enable)
55 r = dssdev->platform_enable(dssdev);
56
57 return r;
58}
59
60static void generic_panel_disable(struct omap_dss_device *dssdev)
61{
62 if (dssdev->platform_disable)
63 dssdev->platform_disable(dssdev);
64}
65
66static int generic_panel_suspend(struct omap_dss_device *dssdev)
67{
68 generic_panel_disable(dssdev);
69 return 0;
70}
71
72static int generic_panel_resume(struct omap_dss_device *dssdev)
73{
74 return generic_panel_enable(dssdev);
75}
76
77static struct omap_dss_driver generic_driver = {
78 .probe = generic_panel_probe,
79 .remove = generic_panel_remove,
80
81 .enable = generic_panel_enable,
82 .disable = generic_panel_disable,
83 .suspend = generic_panel_suspend,
84 .resume = generic_panel_resume,
85
86 .driver = {
87 .name = "generic_panel",
88 .owner = THIS_MODULE,
89 },
90};
91
92static int __init generic_panel_drv_init(void)
93{
94 return omap_dss_register_driver(&generic_driver);
95}
96
97static void __exit generic_panel_drv_exit(void)
98{
99 omap_dss_unregister_driver(&generic_driver);
100}
101
102module_init(generic_panel_drv_init);
103module_exit(generic_panel_drv_exit);
104MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
new file mode 100644
index 000000000000..bbe880bbe795
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c
@@ -0,0 +1,153 @@
1/*
2 * LCD panel driver for Sharp LS037V7DW01
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/module.h>
21#include <linux/delay.h>
22#include <linux/device.h>
23#include <linux/regulator/consumer.h>
24#include <linux/err.h>
25
26#include <plat/display.h>
27
28struct sharp_data {
29 /* XXX This regulator should actually be in SDP board file, not here,
30 * as it doesn't actually power the LCD, but something else that
31 * affects the output to LCD (I think. Somebody clarify). It doesn't do
32 * harm here, as SDP is the only board using this currently */
33 struct regulator *vdvi_reg;
34};
35
36static struct omap_video_timings sharp_ls_timings = {
37 .x_res = 480,
38 .y_res = 640,
39
40 .pixel_clock = 19200,
41
42 .hsw = 2,
43 .hfp = 1,
44 .hbp = 28,
45
46 .vsw = 1,
47 .vfp = 1,
48 .vbp = 1,
49};
50
51static int sharp_ls_panel_probe(struct omap_dss_device *dssdev)
52{
53 struct sharp_data *sd;
54
55 dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
56 OMAP_DSS_LCD_IHS;
57 dssdev->panel.acb = 0x28;
58 dssdev->panel.timings = sharp_ls_timings;
59
60 sd = kzalloc(sizeof(*sd), GFP_KERNEL);
61 if (!sd)
62 return -ENOMEM;
63
64 dev_set_drvdata(&dssdev->dev, sd);
65
66 sd->vdvi_reg = regulator_get(&dssdev->dev, "vdvi");
67 if (IS_ERR(sd->vdvi_reg)) {
68 kfree(sd);
69 pr_err("failed to get VDVI regulator\n");
70 return PTR_ERR(sd->vdvi_reg);
71 }
72
73 return 0;
74}
75
76static void sharp_ls_panel_remove(struct omap_dss_device *dssdev)
77{
78 struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
79
80 regulator_put(sd->vdvi_reg);
81
82 kfree(sd);
83}
84
85static int sharp_ls_panel_enable(struct omap_dss_device *dssdev)
86{
87 struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
88 int r = 0;
89
90 /* wait couple of vsyncs until enabling the LCD */
91 msleep(50);
92
93 regulator_enable(sd->vdvi_reg);
94
95 if (dssdev->platform_enable)
96 r = dssdev->platform_enable(dssdev);
97
98 return r;
99}
100
101static void sharp_ls_panel_disable(struct omap_dss_device *dssdev)
102{
103 struct sharp_data *sd = dev_get_drvdata(&dssdev->dev);
104
105 if (dssdev->platform_disable)
106 dssdev->platform_disable(dssdev);
107
108 regulator_disable(sd->vdvi_reg);
109
110 /* wait at least 5 vsyncs after disabling the LCD */
111
112 msleep(100);
113}
114
115static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev)
116{
117 sharp_ls_panel_disable(dssdev);
118 return 0;
119}
120
121static int sharp_ls_panel_resume(struct omap_dss_device *dssdev)
122{
123 return sharp_ls_panel_enable(dssdev);
124}
125
126static struct omap_dss_driver sharp_ls_driver = {
127 .probe = sharp_ls_panel_probe,
128 .remove = sharp_ls_panel_remove,
129
130 .enable = sharp_ls_panel_enable,
131 .disable = sharp_ls_panel_disable,
132 .suspend = sharp_ls_panel_suspend,
133 .resume = sharp_ls_panel_resume,
134
135 .driver = {
136 .name = "sharp_ls_panel",
137 .owner = THIS_MODULE,
138 },
139};
140
141static int __init sharp_ls_panel_drv_init(void)
142{
143 return omap_dss_register_driver(&sharp_ls_driver);
144}
145
146static void __exit sharp_ls_panel_drv_exit(void)
147{
148 omap_dss_unregister_driver(&sharp_ls_driver);
149}
150
151module_init(sharp_ls_panel_drv_init);
152module_exit(sharp_ls_panel_drv_exit);
153MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c
new file mode 100644
index 000000000000..1f01dfc5e52e
--- /dev/null
+++ b/drivers/video/omap2/displays/panel-taal.c
@@ -0,0 +1,1003 @@
1/*
2 * Taal DSI command mode panel
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20/*#define DEBUG*/
21
22#include <linux/module.h>
23#include <linux/delay.h>
24#include <linux/err.h>
25#include <linux/jiffies.h>
26#include <linux/sched.h>
27#include <linux/backlight.h>
28#include <linux/fb.h>
29#include <linux/interrupt.h>
30#include <linux/gpio.h>
31#include <linux/completion.h>
32#include <linux/workqueue.h>
33
34#include <plat/display.h>
35
36/* DSI Virtual channel. Hardcoded for now. */
37#define TCH 0
38
39#define DCS_READ_NUM_ERRORS 0x05
40#define DCS_READ_POWER_MODE 0x0a
41#define DCS_READ_MADCTL 0x0b
42#define DCS_READ_PIXEL_FORMAT 0x0c
43#define DCS_RDDSDR 0x0f
44#define DCS_SLEEP_IN 0x10
45#define DCS_SLEEP_OUT 0x11
46#define DCS_DISPLAY_OFF 0x28
47#define DCS_DISPLAY_ON 0x29
48#define DCS_COLUMN_ADDR 0x2a
49#define DCS_PAGE_ADDR 0x2b
50#define DCS_MEMORY_WRITE 0x2c
51#define DCS_TEAR_OFF 0x34
52#define DCS_TEAR_ON 0x35
53#define DCS_MEM_ACC_CTRL 0x36
54#define DCS_PIXEL_FORMAT 0x3a
55#define DCS_BRIGHTNESS 0x51
56#define DCS_CTRL_DISPLAY 0x53
57#define DCS_WRITE_CABC 0x55
58#define DCS_READ_CABC 0x56
59#define DCS_GET_ID1 0xda
60#define DCS_GET_ID2 0xdb
61#define DCS_GET_ID3 0xdc
62
63/* #define TAAL_USE_ESD_CHECK */
64#define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000)
65
66struct taal_data {
67 struct backlight_device *bldev;
68
69 unsigned long hw_guard_end; /* next value of jiffies when we can
70 * issue the next sleep in/out command
71 */
72 unsigned long hw_guard_wait; /* max guard time in jiffies */
73
74 struct omap_dss_device *dssdev;
75
76 bool enabled;
77 u8 rotate;
78 bool mirror;
79
80 bool te_enabled;
81 bool use_ext_te;
82 struct completion te_completion;
83
84 bool use_dsi_bl;
85
86 bool cabc_broken;
87 unsigned cabc_mode;
88
89 bool intro_printed;
90
91 struct workqueue_struct *esd_wq;
92 struct delayed_work esd_work;
93};
94
95static void taal_esd_work(struct work_struct *work);
96
97static void hw_guard_start(struct taal_data *td, int guard_msec)
98{
99 td->hw_guard_wait = msecs_to_jiffies(guard_msec);
100 td->hw_guard_end = jiffies + td->hw_guard_wait;
101}
102
103static void hw_guard_wait(struct taal_data *td)
104{
105 unsigned long wait = td->hw_guard_end - jiffies;
106
107 if ((long)wait > 0 && wait <= td->hw_guard_wait) {
108 set_current_state(TASK_UNINTERRUPTIBLE);
109 schedule_timeout(wait);
110 }
111}
112
113static int taal_dcs_read_1(u8 dcs_cmd, u8 *data)
114{
115 int r;
116 u8 buf[1];
117
118 r = dsi_vc_dcs_read(TCH, dcs_cmd, buf, 1);
119
120 if (r < 0)
121 return r;
122
123 *data = buf[0];
124
125 return 0;
126}
127
128static int taal_dcs_write_0(u8 dcs_cmd)
129{
130 return dsi_vc_dcs_write(TCH, &dcs_cmd, 1);
131}
132
133static int taal_dcs_write_1(u8 dcs_cmd, u8 param)
134{
135 u8 buf[2];
136 buf[0] = dcs_cmd;
137 buf[1] = param;
138 return dsi_vc_dcs_write(TCH, buf, 2);
139}
140
141static int taal_sleep_in(struct taal_data *td)
142
143{
144 u8 cmd;
145 int r;
146
147 hw_guard_wait(td);
148
149 cmd = DCS_SLEEP_IN;
150 r = dsi_vc_dcs_write_nosync(TCH, &cmd, 1);
151 if (r)
152 return r;
153
154 hw_guard_start(td, 120);
155
156 msleep(5);
157
158 return 0;
159}
160
161static int taal_sleep_out(struct taal_data *td)
162{
163 int r;
164
165 hw_guard_wait(td);
166
167 r = taal_dcs_write_0(DCS_SLEEP_OUT);
168 if (r)
169 return r;
170
171 hw_guard_start(td, 120);
172
173 msleep(5);
174
175 return 0;
176}
177
178static int taal_get_id(u8 *id1, u8 *id2, u8 *id3)
179{
180 int r;
181
182 r = taal_dcs_read_1(DCS_GET_ID1, id1);
183 if (r)
184 return r;
185 r = taal_dcs_read_1(DCS_GET_ID2, id2);
186 if (r)
187 return r;
188 r = taal_dcs_read_1(DCS_GET_ID3, id3);
189 if (r)
190 return r;
191
192 return 0;
193}
194
195static int taal_set_addr_mode(u8 rotate, bool mirror)
196{
197 int r;
198 u8 mode;
199 int b5, b6, b7;
200
201 r = taal_dcs_read_1(DCS_READ_MADCTL, &mode);
202 if (r)
203 return r;
204
205 switch (rotate) {
206 default:
207 case 0:
208 b7 = 0;
209 b6 = 0;
210 b5 = 0;
211 break;
212 case 1:
213 b7 = 0;
214 b6 = 1;
215 b5 = 1;
216 break;
217 case 2:
218 b7 = 1;
219 b6 = 1;
220 b5 = 0;
221 break;
222 case 3:
223 b7 = 1;
224 b6 = 0;
225 b5 = 1;
226 break;
227 }
228
229 if (mirror)
230 b6 = !b6;
231
232 mode &= ~((1<<7) | (1<<6) | (1<<5));
233 mode |= (b7 << 7) | (b6 << 6) | (b5 << 5);
234
235 return taal_dcs_write_1(DCS_MEM_ACC_CTRL, mode);
236}
237
238static int taal_set_update_window(u16 x, u16 y, u16 w, u16 h)
239{
240 int r;
241 u16 x1 = x;
242 u16 x2 = x + w - 1;
243 u16 y1 = y;
244 u16 y2 = y + h - 1;
245
246 u8 buf[5];
247 buf[0] = DCS_COLUMN_ADDR;
248 buf[1] = (x1 >> 8) & 0xff;
249 buf[2] = (x1 >> 0) & 0xff;
250 buf[3] = (x2 >> 8) & 0xff;
251 buf[4] = (x2 >> 0) & 0xff;
252
253 r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
254 if (r)
255 return r;
256
257 buf[0] = DCS_PAGE_ADDR;
258 buf[1] = (y1 >> 8) & 0xff;
259 buf[2] = (y1 >> 0) & 0xff;
260 buf[3] = (y2 >> 8) & 0xff;
261 buf[4] = (y2 >> 0) & 0xff;
262
263 r = dsi_vc_dcs_write_nosync(TCH, buf, sizeof(buf));
264 if (r)
265 return r;
266
267 dsi_vc_send_bta_sync(TCH);
268
269 return r;
270}
271
272static int taal_bl_update_status(struct backlight_device *dev)
273{
274 struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
275 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
276 int r;
277 int level;
278
279 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
280 dev->props.power == FB_BLANK_UNBLANK)
281 level = dev->props.brightness;
282 else
283 level = 0;
284
285 dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
286
287 if (td->use_dsi_bl) {
288 if (td->enabled) {
289 dsi_bus_lock();
290 r = taal_dcs_write_1(DCS_BRIGHTNESS, level);
291 dsi_bus_unlock();
292 if (r)
293 return r;
294 }
295 } else {
296 if (!dssdev->set_backlight)
297 return -EINVAL;
298
299 r = dssdev->set_backlight(dssdev, level);
300 if (r)
301 return r;
302 }
303
304 return 0;
305}
306
307static int taal_bl_get_intensity(struct backlight_device *dev)
308{
309 if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
310 dev->props.power == FB_BLANK_UNBLANK)
311 return dev->props.brightness;
312
313 return 0;
314}
315
316static struct backlight_ops taal_bl_ops = {
317 .get_brightness = taal_bl_get_intensity,
318 .update_status = taal_bl_update_status,
319};
320
321static void taal_get_timings(struct omap_dss_device *dssdev,
322 struct omap_video_timings *timings)
323{
324 *timings = dssdev->panel.timings;
325}
326
327static void taal_get_resolution(struct omap_dss_device *dssdev,
328 u16 *xres, u16 *yres)
329{
330 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
331
332 if (td->rotate == 0 || td->rotate == 2) {
333 *xres = dssdev->panel.timings.x_res;
334 *yres = dssdev->panel.timings.y_res;
335 } else {
336 *yres = dssdev->panel.timings.x_res;
337 *xres = dssdev->panel.timings.y_res;
338 }
339}
340
341static irqreturn_t taal_te_isr(int irq, void *data)
342{
343 struct omap_dss_device *dssdev = data;
344 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
345
346 complete_all(&td->te_completion);
347
348 return IRQ_HANDLED;
349}
350
351static ssize_t taal_num_errors_show(struct device *dev,
352 struct device_attribute *attr, char *buf)
353{
354 struct omap_dss_device *dssdev = to_dss_device(dev);
355 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
356 u8 errors;
357 int r;
358
359 if (td->enabled) {
360 dsi_bus_lock();
361 r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors);
362 dsi_bus_unlock();
363 } else {
364 r = -ENODEV;
365 }
366
367 if (r)
368 return r;
369
370 return snprintf(buf, PAGE_SIZE, "%d\n", errors);
371}
372
373static ssize_t taal_hw_revision_show(struct device *dev,
374 struct device_attribute *attr, char *buf)
375{
376 struct omap_dss_device *dssdev = to_dss_device(dev);
377 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
378 u8 id1, id2, id3;
379 int r;
380
381 if (td->enabled) {
382 dsi_bus_lock();
383 r = taal_get_id(&id1, &id2, &id3);
384 dsi_bus_unlock();
385 } else {
386 r = -ENODEV;
387 }
388
389 if (r)
390 return r;
391
392 return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x\n", id1, id2, id3);
393}
394
395static const char *cabc_modes[] = {
396 "off", /* used also always when CABC is not supported */
397 "ui",
398 "still-image",
399 "moving-image",
400};
401
402static ssize_t show_cabc_mode(struct device *dev,
403 struct device_attribute *attr,
404 char *buf)
405{
406 struct omap_dss_device *dssdev = to_dss_device(dev);
407 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
408 const char *mode_str;
409 int mode;
410 int len;
411
412 mode = td->cabc_mode;
413
414 mode_str = "unknown";
415 if (mode >= 0 && mode < ARRAY_SIZE(cabc_modes))
416 mode_str = cabc_modes[mode];
417 len = snprintf(buf, PAGE_SIZE, "%s\n", mode_str);
418
419 return len < PAGE_SIZE - 1 ? len : PAGE_SIZE - 1;
420}
421
422static ssize_t store_cabc_mode(struct device *dev,
423 struct device_attribute *attr,
424 const char *buf, size_t count)
425{
426 struct omap_dss_device *dssdev = to_dss_device(dev);
427 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
428 int i;
429
430 for (i = 0; i < ARRAY_SIZE(cabc_modes); i++) {
431 if (sysfs_streq(cabc_modes[i], buf))
432 break;
433 }
434
435 if (i == ARRAY_SIZE(cabc_modes))
436 return -EINVAL;
437
438 if (td->enabled) {
439 dsi_bus_lock();
440 if (!td->cabc_broken)
441 taal_dcs_write_1(DCS_WRITE_CABC, i);
442 dsi_bus_unlock();
443 }
444
445 td->cabc_mode = i;
446
447 return count;
448}
449
450static ssize_t show_cabc_available_modes(struct device *dev,
451 struct device_attribute *attr,
452 char *buf)
453{
454 int len;
455 int i;
456
457 for (i = 0, len = 0;
458 len < PAGE_SIZE && i < ARRAY_SIZE(cabc_modes); i++)
459 len += snprintf(&buf[len], PAGE_SIZE - len, "%s%s%s",
460 i ? " " : "", cabc_modes[i],
461 i == ARRAY_SIZE(cabc_modes) - 1 ? "\n" : "");
462
463 return len < PAGE_SIZE ? len : PAGE_SIZE - 1;
464}
465
466static DEVICE_ATTR(num_dsi_errors, S_IRUGO, taal_num_errors_show, NULL);
467static DEVICE_ATTR(hw_revision, S_IRUGO, taal_hw_revision_show, NULL);
468static DEVICE_ATTR(cabc_mode, S_IRUGO | S_IWUSR,
469 show_cabc_mode, store_cabc_mode);
470static DEVICE_ATTR(cabc_available_modes, S_IRUGO,
471 show_cabc_available_modes, NULL);
472
473static struct attribute *taal_attrs[] = {
474 &dev_attr_num_dsi_errors.attr,
475 &dev_attr_hw_revision.attr,
476 &dev_attr_cabc_mode.attr,
477 &dev_attr_cabc_available_modes.attr,
478 NULL,
479};
480
481static struct attribute_group taal_attr_group = {
482 .attrs = taal_attrs,
483};
484
485static int taal_probe(struct omap_dss_device *dssdev)
486{
487 struct taal_data *td;
488 struct backlight_device *bldev;
489 int r;
490
491 const struct omap_video_timings taal_panel_timings = {
492 .x_res = 864,
493 .y_res = 480,
494 };
495
496 dev_dbg(&dssdev->dev, "probe\n");
497
498 dssdev->panel.config = OMAP_DSS_LCD_TFT;
499 dssdev->panel.timings = taal_panel_timings;
500 dssdev->ctrl.pixel_size = 24;
501
502 td = kzalloc(sizeof(*td), GFP_KERNEL);
503 if (!td) {
504 r = -ENOMEM;
505 goto err0;
506 }
507 td->dssdev = dssdev;
508
509 td->esd_wq = create_singlethread_workqueue("taal_esd");
510 if (td->esd_wq == NULL) {
511 dev_err(&dssdev->dev, "can't create ESD workqueue\n");
512 r = -ENOMEM;
513 goto err2;
514 }
515 INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work);
516
517 dev_set_drvdata(&dssdev->dev, td);
518
519 dssdev->get_timings = taal_get_timings;
520 dssdev->get_resolution = taal_get_resolution;
521
522 /* if no platform set_backlight() defined, presume DSI backlight
523 * control */
524 if (!dssdev->set_backlight)
525 td->use_dsi_bl = true;
526
527 bldev = backlight_device_register("taal", &dssdev->dev, dssdev,
528 &taal_bl_ops);
529 if (IS_ERR(bldev)) {
530 r = PTR_ERR(bldev);
531 goto err1;
532 }
533
534 td->bldev = bldev;
535
536 bldev->props.fb_blank = FB_BLANK_UNBLANK;
537 bldev->props.power = FB_BLANK_UNBLANK;
538 if (td->use_dsi_bl) {
539 bldev->props.max_brightness = 255;
540 bldev->props.brightness = 255;
541 } else {
542 bldev->props.max_brightness = 127;
543 bldev->props.brightness = 127;
544 }
545
546 taal_bl_update_status(bldev);
547
548 if (dssdev->phy.dsi.ext_te) {
549 int gpio = dssdev->phy.dsi.ext_te_gpio;
550
551 r = gpio_request(gpio, "taal irq");
552 if (r) {
553 dev_err(&dssdev->dev, "GPIO request failed\n");
554 goto err3;
555 }
556
557 gpio_direction_input(gpio);
558
559 r = request_irq(gpio_to_irq(gpio), taal_te_isr,
560 IRQF_DISABLED | IRQF_TRIGGER_RISING,
561 "taal vsync", dssdev);
562
563 if (r) {
564 dev_err(&dssdev->dev, "IRQ request failed\n");
565 gpio_free(gpio);
566 goto err3;
567 }
568
569 init_completion(&td->te_completion);
570
571 td->use_ext_te = true;
572 }
573
574 r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group);
575 if (r) {
576 dev_err(&dssdev->dev, "failed to create sysfs files\n");
577 goto err4;
578 }
579
580 return 0;
581err4:
582 if (td->use_ext_te) {
583 int gpio = dssdev->phy.dsi.ext_te_gpio;
584 free_irq(gpio_to_irq(gpio), dssdev);
585 gpio_free(gpio);
586 }
587err3:
588 backlight_device_unregister(bldev);
589err2:
590 cancel_delayed_work_sync(&td->esd_work);
591 destroy_workqueue(td->esd_wq);
592err1:
593 kfree(td);
594err0:
595 return r;
596}
597
598static void taal_remove(struct omap_dss_device *dssdev)
599{
600 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
601 struct backlight_device *bldev;
602
603 dev_dbg(&dssdev->dev, "remove\n");
604
605 sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group);
606
607 if (td->use_ext_te) {
608 int gpio = dssdev->phy.dsi.ext_te_gpio;
609 free_irq(gpio_to_irq(gpio), dssdev);
610 gpio_free(gpio);
611 }
612
613 bldev = td->bldev;
614 bldev->props.power = FB_BLANK_POWERDOWN;
615 taal_bl_update_status(bldev);
616 backlight_device_unregister(bldev);
617
618 cancel_delayed_work_sync(&td->esd_work);
619 destroy_workqueue(td->esd_wq);
620
621 kfree(td);
622}
623
624static int taal_enable(struct omap_dss_device *dssdev)
625{
626 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
627 u8 id1, id2, id3;
628 int r;
629
630 dev_dbg(&dssdev->dev, "enable\n");
631
632 if (dssdev->platform_enable) {
633 r = dssdev->platform_enable(dssdev);
634 if (r)
635 return r;
636 }
637
638 /* it seems we have to wait a bit until taal is ready */
639 msleep(5);
640
641 r = taal_sleep_out(td);
642 if (r)
643 goto err;
644
645 r = taal_get_id(&id1, &id2, &id3);
646 if (r)
647 goto err;
648
649 /* on early revisions CABC is broken */
650 if (id2 == 0x00 || id2 == 0xff || id2 == 0x81)
651 td->cabc_broken = true;
652
653 taal_dcs_write_1(DCS_BRIGHTNESS, 0xff);
654 taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */
655
656 taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */
657
658 taal_set_addr_mode(td->rotate, td->mirror);
659 if (!td->cabc_broken)
660 taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode);
661
662 taal_dcs_write_0(DCS_DISPLAY_ON);
663
664#ifdef TAAL_USE_ESD_CHECK
665 queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
666#endif
667
668 td->enabled = 1;
669
670 if (!td->intro_printed) {
671 dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n",
672 id1, id2, id3);
673 if (td->cabc_broken)
674 dev_info(&dssdev->dev,
675 "old Taal version, CABC disabled\n");
676 td->intro_printed = true;
677 }
678
679 return 0;
680err:
681 if (dssdev->platform_disable)
682 dssdev->platform_disable(dssdev);
683
684 return r;
685}
686
687static void taal_disable(struct omap_dss_device *dssdev)
688{
689 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
690
691 dev_dbg(&dssdev->dev, "disable\n");
692
693 cancel_delayed_work(&td->esd_work);
694
695 taal_dcs_write_0(DCS_DISPLAY_OFF);
696 taal_sleep_in(td);
697
698 /* wait a bit so that the message goes through */
699 msleep(10);
700
701 if (dssdev->platform_disable)
702 dssdev->platform_disable(dssdev);
703
704 td->enabled = 0;
705}
706
707static int taal_suspend(struct omap_dss_device *dssdev)
708{
709 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
710 struct backlight_device *bldev = td->bldev;
711
712 bldev->props.power = FB_BLANK_POWERDOWN;
713 taal_bl_update_status(bldev);
714
715 return 0;
716}
717
718static int taal_resume(struct omap_dss_device *dssdev)
719{
720 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
721 struct backlight_device *bldev = td->bldev;
722
723 bldev->props.power = FB_BLANK_UNBLANK;
724 taal_bl_update_status(bldev);
725
726 return 0;
727}
728
729static void taal_setup_update(struct omap_dss_device *dssdev,
730 u16 x, u16 y, u16 w, u16 h)
731{
732 taal_set_update_window(x, y, w, h);
733}
734
735static int taal_enable_te(struct omap_dss_device *dssdev, bool enable)
736{
737 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
738 int r;
739
740 td->te_enabled = enable;
741
742 if (enable)
743 r = taal_dcs_write_1(DCS_TEAR_ON, 0);
744 else
745 r = taal_dcs_write_0(DCS_TEAR_OFF);
746
747 return r;
748}
749
750static int taal_wait_te(struct omap_dss_device *dssdev)
751{
752 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
753 long wait = msecs_to_jiffies(500);
754
755 if (!td->use_ext_te || !td->te_enabled)
756 return 0;
757
758 INIT_COMPLETION(td->te_completion);
759 wait = wait_for_completion_timeout(&td->te_completion, wait);
760 if (wait == 0) {
761 dev_err(&dssdev->dev, "timeout waiting TE\n");
762 return -ETIME;
763 }
764
765 return 0;
766}
767
768static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate)
769{
770 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
771 int r;
772
773 dev_dbg(&dssdev->dev, "rotate %d\n", rotate);
774
775 if (td->enabled) {
776 r = taal_set_addr_mode(rotate, td->mirror);
777
778 if (r)
779 return r;
780 }
781
782 td->rotate = rotate;
783
784 return 0;
785}
786
787static u8 taal_get_rotate(struct omap_dss_device *dssdev)
788{
789 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
790 return td->rotate;
791}
792
793static int taal_mirror(struct omap_dss_device *dssdev, bool enable)
794{
795 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
796 int r;
797
798 dev_dbg(&dssdev->dev, "mirror %d\n", enable);
799
800 if (td->enabled) {
801 r = taal_set_addr_mode(td->rotate, enable);
802
803 if (r)
804 return r;
805 }
806
807 td->mirror = enable;
808
809 return 0;
810}
811
812static bool taal_get_mirror(struct omap_dss_device *dssdev)
813{
814 struct taal_data *td = dev_get_drvdata(&dssdev->dev);
815 return td->mirror;
816}
817
818static int taal_run_test(struct omap_dss_device *dssdev, int test_num)
819{
820 u8 id1, id2, id3;
821 int r;
822
823 r = taal_dcs_read_1(DCS_GET_ID1, &id1);
824 if (r)
825 return r;
826 r = taal_dcs_read_1(DCS_GET_ID2, &id2);
827 if (r)
828 return r;
829 r = taal_dcs_read_1(DCS_GET_ID3, &id3);
830 if (r)
831 return r;
832
833 return 0;
834}
835
836static int taal_memory_read(struct omap_dss_device *dssdev,
837 void *buf, size_t size,
838 u16 x, u16 y, u16 w, u16 h)
839{
840 int r;
841 int first = 1;
842 int plen;
843 unsigned buf_used = 0;
844
845 if (size < w * h * 3)
846 return -ENOMEM;
847
848 size = min(w * h * 3,
849 dssdev->panel.timings.x_res *
850 dssdev->panel.timings.y_res * 3);
851
852 /* plen 1 or 2 goes into short packet. until checksum error is fixed,
853 * use short packets. plen 32 works, but bigger packets seem to cause
854 * an error. */
855 if (size % 2)
856 plen = 1;
857 else
858 plen = 2;
859
860 taal_setup_update(dssdev, x, y, w, h);
861
862 r = dsi_vc_set_max_rx_packet_size(TCH, plen);
863 if (r)
864 return r;
865
866 while (buf_used < size) {
867 u8 dcs_cmd = first ? 0x2e : 0x3e;
868 first = 0;
869
870 r = dsi_vc_dcs_read(TCH, dcs_cmd,
871 buf + buf_used, size - buf_used);
872
873 if (r < 0) {
874 dev_err(&dssdev->dev, "read error\n");
875 goto err;
876 }
877
878 buf_used += r;
879
880 if (r < plen) {
881 dev_err(&dssdev->dev, "short read\n");
882 break;
883 }
884
885 if (signal_pending(current)) {
886 dev_err(&dssdev->dev, "signal pending, "
887 "aborting memory read\n");
888 r = -ERESTARTSYS;
889 goto err;
890 }
891 }
892
893 r = buf_used;
894
895err:
896 dsi_vc_set_max_rx_packet_size(TCH, 1);
897
898 return r;
899}
900
901static void taal_esd_work(struct work_struct *work)
902{
903 struct taal_data *td = container_of(work, struct taal_data,
904 esd_work.work);
905 struct omap_dss_device *dssdev = td->dssdev;
906 u8 state1, state2;
907 int r;
908
909 if (!td->enabled)
910 return;
911
912 dsi_bus_lock();
913
914 r = taal_dcs_read_1(DCS_RDDSDR, &state1);
915 if (r) {
916 dev_err(&dssdev->dev, "failed to read Taal status\n");
917 goto err;
918 }
919
920 /* Run self diagnostics */
921 r = taal_sleep_out(td);
922 if (r) {
923 dev_err(&dssdev->dev, "failed to run Taal self-diagnostics\n");
924 goto err;
925 }
926
927 r = taal_dcs_read_1(DCS_RDDSDR, &state2);
928 if (r) {
929 dev_err(&dssdev->dev, "failed to read Taal status\n");
930 goto err;
931 }
932
933 /* Each sleep out command will trigger a self diagnostic and flip
934 * Bit6 if the test passes.
935 */
936 if (!((state1 ^ state2) & (1 << 6))) {
937 dev_err(&dssdev->dev, "LCD self diagnostics failed\n");
938 goto err;
939 }
940 /* Self-diagnostics result is also shown on TE GPIO line. We need
941 * to re-enable TE after self diagnostics */
942 if (td->use_ext_te && td->te_enabled)
943 taal_enable_te(dssdev, true);
944
945 dsi_bus_unlock();
946
947 queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
948
949 return;
950err:
951 dev_err(&dssdev->dev, "performing LCD reset\n");
952
953 taal_disable(dssdev);
954 taal_enable(dssdev);
955
956 dsi_bus_unlock();
957
958 queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD);
959}
960
961static struct omap_dss_driver taal_driver = {
962 .probe = taal_probe,
963 .remove = taal_remove,
964
965 .enable = taal_enable,
966 .disable = taal_disable,
967 .suspend = taal_suspend,
968 .resume = taal_resume,
969
970 .setup_update = taal_setup_update,
971 .enable_te = taal_enable_te,
972 .wait_for_te = taal_wait_te,
973 .set_rotate = taal_rotate,
974 .get_rotate = taal_get_rotate,
975 .set_mirror = taal_mirror,
976 .get_mirror = taal_get_mirror,
977 .run_test = taal_run_test,
978 .memory_read = taal_memory_read,
979
980 .driver = {
981 .name = "taal",
982 .owner = THIS_MODULE,
983 },
984};
985
986static int __init taal_init(void)
987{
988 omap_dss_register_driver(&taal_driver);
989
990 return 0;
991}
992
993static void __exit taal_exit(void)
994{
995 omap_dss_unregister_driver(&taal_driver);
996}
997
998module_init(taal_init);
999module_exit(taal_exit);
1000
1001MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
1002MODULE_DESCRIPTION("Taal Driver");
1003MODULE_LICENSE("GPL");
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
new file mode 100644
index 000000000000..c63ce767b277
--- /dev/null
+++ b/drivers/video/omap2/dss/Kconfig
@@ -0,0 +1,96 @@
1menuconfig OMAP2_DSS
2 tristate "OMAP2/3 Display Subsystem support (EXPERIMENTAL)"
3 depends on ARCH_OMAP2 || ARCH_OMAP3
4 help
5 OMAP2/3 Display Subsystem support.
6
7if OMAP2_DSS
8
9config OMAP2_VRAM_SIZE
10 int "VRAM size (MB)"
11 range 0 32
12 default 0
13 help
14 The amount of SDRAM to reserve at boot time for video RAM use.
15 This VRAM will be used by omapfb and other drivers that need
16 large continuous RAM area for video use.
17
18 You can also set this with "vram=<bytes>" kernel argument, or
19 in the board file.
20
21config OMAP2_DSS_DEBUG_SUPPORT
22 bool "Debug support"
23 default y
24 help
25 This enables debug messages. You need to enable printing
26 with 'debug' module parameter.
27
28config OMAP2_DSS_COLLECT_IRQ_STATS
29 bool "Collect DSS IRQ statistics"
30 depends on OMAP2_DSS_DEBUG_SUPPORT
31 default n
32 help
33 Collect DSS IRQ statistics, printable via debugfs
34
35config OMAP2_DSS_RFBI
36 bool "RFBI support"
37 default n
38 help
39 MIPI DBI, or RFBI (Remote Framebuffer Interface), support.
40
41config OMAP2_DSS_VENC
42 bool "VENC support"
43 default y
44 help
45 OMAP Video Encoder support.
46
47config OMAP2_DSS_SDI
48 bool "SDI support"
49 depends on ARCH_OMAP3
50 default n
51 help
52 SDI (Serial Display Interface) support.
53
54config OMAP2_DSS_DSI
55 bool "DSI support"
56 depends on ARCH_OMAP3
57 default n
58 help
59 MIPI DSI support.
60
61config OMAP2_DSS_USE_DSI_PLL
62 bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
63 default n
64 depends on OMAP2_DSS_DSI
65 help
66 Use DSI PLL to generate pixel clock. Currently only for DPI output.
67 DSI PLL can be used to generate higher and more precise pixel clocks.
68
69config OMAP2_DSS_FAKE_VSYNC
70 bool "Fake VSYNC irq from manual update displays"
71 default n
72 help
73 If this is selected, DSI will generate a fake DISPC VSYNC interrupt
74 when DSI has sent a frame. This is only needed with DSI or RFBI
75 displays using manual mode, and you want VSYNC to, for example,
76 time animation.
77
78config OMAP2_DSS_MIN_FCK_PER_PCK
79 int "Minimum FCK/PCK ratio (for scaling)"
80 range 0 32
81 default 0
82 help
83 This can be used to adjust the minimum FCK/PCK ratio.
84
85 With this you can make sure that DISPC FCK is at least
86 n x PCK. Video plane scaling requires higher FCK than
87 normally.
88
89 If this is set to 0, there's no extra constraint on the
90 DISPC FCK. However, the FCK will at minimum be
91 2xPCK (if active matrix) or 3xPCK (if passive matrix).
92
93 Max FCK is 173MHz, so this doesn't work if your PCK
94 is very high.
95
96endif
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile
new file mode 100644
index 000000000000..980c72c2db98
--- /dev/null
+++ b/drivers/video/omap2/dss/Makefile
@@ -0,0 +1,6 @@
1obj-$(CONFIG_OMAP2_DSS) += omapdss.o
2omapdss-y := core.o dss.o dispc.o dpi.o display.o manager.o overlay.o
3omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
4omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
5omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
6omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
new file mode 100644
index 000000000000..82918eec6d2e
--- /dev/null
+++ b/drivers/video/omap2/dss/core.c
@@ -0,0 +1,929 @@
1/*
2 * linux/drivers/video/omap2/dss/core.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "CORE"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/clk.h>
28#include <linux/err.h>
29#include <linux/platform_device.h>
30#include <linux/seq_file.h>
31#include <linux/debugfs.h>
32#include <linux/io.h>
33#include <linux/device.h>
34
35#include <plat/display.h>
36#include <plat/clock.h>
37
38#include "dss.h"
39
40static struct {
41 struct platform_device *pdev;
42 int ctx_id;
43
44 struct clk *dss_ick;
45 struct clk *dss1_fck;
46 struct clk *dss2_fck;
47 struct clk *dss_54m_fck;
48 struct clk *dss_96m_fck;
49 unsigned num_clks_enabled;
50} core;
51
52static void dss_clk_enable_all_no_ctx(void);
53static void dss_clk_disable_all_no_ctx(void);
54static void dss_clk_enable_no_ctx(enum dss_clock clks);
55static void dss_clk_disable_no_ctx(enum dss_clock clks);
56
57static char *def_disp_name;
58module_param_named(def_disp, def_disp_name, charp, 0);
59MODULE_PARM_DESC(def_disp_name, "default display name");
60
61#ifdef DEBUG
62unsigned int dss_debug;
63module_param_named(debug, dss_debug, bool, 0644);
64#endif
65
66/* CONTEXT */
67static int dss_get_ctx_id(void)
68{
69 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
70 int r;
71
72 if (!pdata->get_last_off_on_transaction_id)
73 return 0;
74 r = pdata->get_last_off_on_transaction_id(&core.pdev->dev);
75 if (r < 0) {
76 dev_err(&core.pdev->dev, "getting transaction ID failed, "
77 "will force context restore\n");
78 r = -1;
79 }
80 return r;
81}
82
83int dss_need_ctx_restore(void)
84{
85 int id = dss_get_ctx_id();
86
87 if (id < 0 || id != core.ctx_id) {
88 DSSDBG("ctx id %d -> id %d\n",
89 core.ctx_id, id);
90 core.ctx_id = id;
91 return 1;
92 } else {
93 return 0;
94 }
95}
96
97static void save_all_ctx(void)
98{
99 DSSDBG("save context\n");
100
101 dss_clk_enable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
102
103 dss_save_context();
104 dispc_save_context();
105#ifdef CONFIG_OMAP2_DSS_DSI
106 dsi_save_context();
107#endif
108
109 dss_clk_disable_no_ctx(DSS_CLK_ICK | DSS_CLK_FCK1);
110}
111
112static void restore_all_ctx(void)
113{
114 DSSDBG("restore context\n");
115
116 dss_clk_enable_all_no_ctx();
117
118 dss_restore_context();
119 dispc_restore_context();
120#ifdef CONFIG_OMAP2_DSS_DSI
121 dsi_restore_context();
122#endif
123
124 dss_clk_disable_all_no_ctx();
125}
126
127#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
128/* CLOCKS */
129static void core_dump_clocks(struct seq_file *s)
130{
131 int i;
132 struct clk *clocks[5] = {
133 core.dss_ick,
134 core.dss1_fck,
135 core.dss2_fck,
136 core.dss_54m_fck,
137 core.dss_96m_fck
138 };
139
140 seq_printf(s, "- CORE -\n");
141
142 seq_printf(s, "internal clk count\t\t%u\n", core.num_clks_enabled);
143
144 for (i = 0; i < 5; i++) {
145 if (!clocks[i])
146 continue;
147 seq_printf(s, "%-15s\t%lu\t%d\n",
148 clocks[i]->name,
149 clk_get_rate(clocks[i]),
150 clocks[i]->usecount);
151 }
152}
153#endif /* defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) */
154
155static int dss_get_clock(struct clk **clock, const char *clk_name)
156{
157 struct clk *clk;
158
159 clk = clk_get(&core.pdev->dev, clk_name);
160
161 if (IS_ERR(clk)) {
162 DSSERR("can't get clock %s", clk_name);
163 return PTR_ERR(clk);
164 }
165
166 *clock = clk;
167
168 DSSDBG("clk %s, rate %ld\n", clk_name, clk_get_rate(clk));
169
170 return 0;
171}
172
173static int dss_get_clocks(void)
174{
175 int r;
176
177 core.dss_ick = NULL;
178 core.dss1_fck = NULL;
179 core.dss2_fck = NULL;
180 core.dss_54m_fck = NULL;
181 core.dss_96m_fck = NULL;
182
183 r = dss_get_clock(&core.dss_ick, "ick");
184 if (r)
185 goto err;
186
187 r = dss_get_clock(&core.dss1_fck, "dss1_fck");
188 if (r)
189 goto err;
190
191 r = dss_get_clock(&core.dss2_fck, "dss2_fck");
192 if (r)
193 goto err;
194
195 r = dss_get_clock(&core.dss_54m_fck, "tv_fck");
196 if (r)
197 goto err;
198
199 r = dss_get_clock(&core.dss_96m_fck, "video_fck");
200 if (r)
201 goto err;
202
203 return 0;
204
205err:
206 if (core.dss_ick)
207 clk_put(core.dss_ick);
208 if (core.dss1_fck)
209 clk_put(core.dss1_fck);
210 if (core.dss2_fck)
211 clk_put(core.dss2_fck);
212 if (core.dss_54m_fck)
213 clk_put(core.dss_54m_fck);
214 if (core.dss_96m_fck)
215 clk_put(core.dss_96m_fck);
216
217 return r;
218}
219
220static void dss_put_clocks(void)
221{
222 if (core.dss_96m_fck)
223 clk_put(core.dss_96m_fck);
224 clk_put(core.dss_54m_fck);
225 clk_put(core.dss1_fck);
226 clk_put(core.dss2_fck);
227 clk_put(core.dss_ick);
228}
229
230unsigned long dss_clk_get_rate(enum dss_clock clk)
231{
232 switch (clk) {
233 case DSS_CLK_ICK:
234 return clk_get_rate(core.dss_ick);
235 case DSS_CLK_FCK1:
236 return clk_get_rate(core.dss1_fck);
237 case DSS_CLK_FCK2:
238 return clk_get_rate(core.dss2_fck);
239 case DSS_CLK_54M:
240 return clk_get_rate(core.dss_54m_fck);
241 case DSS_CLK_96M:
242 return clk_get_rate(core.dss_96m_fck);
243 }
244
245 BUG();
246 return 0;
247}
248
249static unsigned count_clk_bits(enum dss_clock clks)
250{
251 unsigned num_clks = 0;
252
253 if (clks & DSS_CLK_ICK)
254 ++num_clks;
255 if (clks & DSS_CLK_FCK1)
256 ++num_clks;
257 if (clks & DSS_CLK_FCK2)
258 ++num_clks;
259 if (clks & DSS_CLK_54M)
260 ++num_clks;
261 if (clks & DSS_CLK_96M)
262 ++num_clks;
263
264 return num_clks;
265}
266
267static void dss_clk_enable_no_ctx(enum dss_clock clks)
268{
269 unsigned num_clks = count_clk_bits(clks);
270
271 if (clks & DSS_CLK_ICK)
272 clk_enable(core.dss_ick);
273 if (clks & DSS_CLK_FCK1)
274 clk_enable(core.dss1_fck);
275 if (clks & DSS_CLK_FCK2)
276 clk_enable(core.dss2_fck);
277 if (clks & DSS_CLK_54M)
278 clk_enable(core.dss_54m_fck);
279 if (clks & DSS_CLK_96M)
280 clk_enable(core.dss_96m_fck);
281
282 core.num_clks_enabled += num_clks;
283}
284
285void dss_clk_enable(enum dss_clock clks)
286{
287 dss_clk_enable_no_ctx(clks);
288
289 if (cpu_is_omap34xx() && dss_need_ctx_restore())
290 restore_all_ctx();
291}
292
293static void dss_clk_disable_no_ctx(enum dss_clock clks)
294{
295 unsigned num_clks = count_clk_bits(clks);
296
297 if (clks & DSS_CLK_ICK)
298 clk_disable(core.dss_ick);
299 if (clks & DSS_CLK_FCK1)
300 clk_disable(core.dss1_fck);
301 if (clks & DSS_CLK_FCK2)
302 clk_disable(core.dss2_fck);
303 if (clks & DSS_CLK_54M)
304 clk_disable(core.dss_54m_fck);
305 if (clks & DSS_CLK_96M)
306 clk_disable(core.dss_96m_fck);
307
308 core.num_clks_enabled -= num_clks;
309}
310
311void dss_clk_disable(enum dss_clock clks)
312{
313 if (cpu_is_omap34xx()) {
314 unsigned num_clks = count_clk_bits(clks);
315
316 BUG_ON(core.num_clks_enabled < num_clks);
317
318 if (core.num_clks_enabled == num_clks)
319 save_all_ctx();
320 }
321
322 dss_clk_disable_no_ctx(clks);
323}
324
325static void dss_clk_enable_all_no_ctx(void)
326{
327 enum dss_clock clks;
328
329 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
330 if (cpu_is_omap34xx())
331 clks |= DSS_CLK_96M;
332 dss_clk_enable_no_ctx(clks);
333}
334
335static void dss_clk_disable_all_no_ctx(void)
336{
337 enum dss_clock clks;
338
339 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
340 if (cpu_is_omap34xx())
341 clks |= DSS_CLK_96M;
342 dss_clk_disable_no_ctx(clks);
343}
344
345static void dss_clk_disable_all(void)
346{
347 enum dss_clock clks;
348
349 clks = DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_FCK2 | DSS_CLK_54M;
350 if (cpu_is_omap34xx())
351 clks |= DSS_CLK_96M;
352 dss_clk_disable(clks);
353}
354
355/* DEBUGFS */
356#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
357static void dss_debug_dump_clocks(struct seq_file *s)
358{
359 core_dump_clocks(s);
360 dss_dump_clocks(s);
361 dispc_dump_clocks(s);
362#ifdef CONFIG_OMAP2_DSS_DSI
363 dsi_dump_clocks(s);
364#endif
365}
366
367static int dss_debug_show(struct seq_file *s, void *unused)
368{
369 void (*func)(struct seq_file *) = s->private;
370 func(s);
371 return 0;
372}
373
374static int dss_debug_open(struct inode *inode, struct file *file)
375{
376 return single_open(file, dss_debug_show, inode->i_private);
377}
378
379static const struct file_operations dss_debug_fops = {
380 .open = dss_debug_open,
381 .read = seq_read,
382 .llseek = seq_lseek,
383 .release = single_release,
384};
385
386static struct dentry *dss_debugfs_dir;
387
388static int dss_initialize_debugfs(void)
389{
390 dss_debugfs_dir = debugfs_create_dir("omapdss", NULL);
391 if (IS_ERR(dss_debugfs_dir)) {
392 int err = PTR_ERR(dss_debugfs_dir);
393 dss_debugfs_dir = NULL;
394 return err;
395 }
396
397 debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir,
398 &dss_debug_dump_clocks, &dss_debug_fops);
399
400 debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir,
401 &dispc_dump_irqs, &dss_debug_fops);
402
403#ifdef CONFIG_OMAP2_DSS_DSI
404 debugfs_create_file("dsi_irq", S_IRUGO, dss_debugfs_dir,
405 &dsi_dump_irqs, &dss_debug_fops);
406#endif
407
408 debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir,
409 &dss_dump_regs, &dss_debug_fops);
410 debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir,
411 &dispc_dump_regs, &dss_debug_fops);
412#ifdef CONFIG_OMAP2_DSS_RFBI
413 debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir,
414 &rfbi_dump_regs, &dss_debug_fops);
415#endif
416#ifdef CONFIG_OMAP2_DSS_DSI
417 debugfs_create_file("dsi", S_IRUGO, dss_debugfs_dir,
418 &dsi_dump_regs, &dss_debug_fops);
419#endif
420#ifdef CONFIG_OMAP2_DSS_VENC
421 debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir,
422 &venc_dump_regs, &dss_debug_fops);
423#endif
424 return 0;
425}
426
427static void dss_uninitialize_debugfs(void)
428{
429 if (dss_debugfs_dir)
430 debugfs_remove_recursive(dss_debugfs_dir);
431}
432#endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */
433
434/* PLATFORM DEVICE */
435static int omap_dss_probe(struct platform_device *pdev)
436{
437 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
438 int skip_init = 0;
439 int r;
440 int i;
441
442 core.pdev = pdev;
443
444 dss_init_overlay_managers(pdev);
445 dss_init_overlays(pdev);
446
447 r = dss_get_clocks();
448 if (r)
449 goto fail0;
450
451 dss_clk_enable_all_no_ctx();
452
453 core.ctx_id = dss_get_ctx_id();
454 DSSDBG("initial ctx id %u\n", core.ctx_id);
455
456#ifdef CONFIG_FB_OMAP_BOOTLOADER_INIT
457 /* DISPC_CONTROL */
458 if (omap_readl(0x48050440) & 1) /* LCD enabled? */
459 skip_init = 1;
460#endif
461
462 r = dss_init(skip_init);
463 if (r) {
464 DSSERR("Failed to initialize DSS\n");
465 goto fail0;
466 }
467
468#ifdef CONFIG_OMAP2_DSS_RFBI
469 r = rfbi_init();
470 if (r) {
471 DSSERR("Failed to initialize rfbi\n");
472 goto fail0;
473 }
474#endif
475
476 r = dpi_init();
477 if (r) {
478 DSSERR("Failed to initialize dpi\n");
479 goto fail0;
480 }
481
482 r = dispc_init();
483 if (r) {
484 DSSERR("Failed to initialize dispc\n");
485 goto fail0;
486 }
487#ifdef CONFIG_OMAP2_DSS_VENC
488 r = venc_init(pdev);
489 if (r) {
490 DSSERR("Failed to initialize venc\n");
491 goto fail0;
492 }
493#endif
494 if (cpu_is_omap34xx()) {
495#ifdef CONFIG_OMAP2_DSS_SDI
496 r = sdi_init(skip_init);
497 if (r) {
498 DSSERR("Failed to initialize SDI\n");
499 goto fail0;
500 }
501#endif
502#ifdef CONFIG_OMAP2_DSS_DSI
503 r = dsi_init(pdev);
504 if (r) {
505 DSSERR("Failed to initialize DSI\n");
506 goto fail0;
507 }
508#endif
509 }
510
511#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
512 r = dss_initialize_debugfs();
513 if (r)
514 goto fail0;
515#endif
516
517 for (i = 0; i < pdata->num_devices; ++i) {
518 struct omap_dss_device *dssdev = pdata->devices[i];
519
520 r = omap_dss_register_device(dssdev);
521 if (r)
522 DSSERR("device reg failed %d\n", i);
523
524 if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0)
525 pdata->default_device = dssdev;
526 }
527
528 dss_clk_disable_all();
529
530 return 0;
531
532 /* XXX fail correctly */
533fail0:
534 return r;
535}
536
537static int omap_dss_remove(struct platform_device *pdev)
538{
539 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
540 int i;
541 int c;
542
543#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT)
544 dss_uninitialize_debugfs();
545#endif
546
547#ifdef CONFIG_OMAP2_DSS_VENC
548 venc_exit();
549#endif
550 dispc_exit();
551 dpi_exit();
552#ifdef CONFIG_OMAP2_DSS_RFBI
553 rfbi_exit();
554#endif
555 if (cpu_is_omap34xx()) {
556#ifdef CONFIG_OMAP2_DSS_DSI
557 dsi_exit();
558#endif
559#ifdef CONFIG_OMAP2_DSS_SDI
560 sdi_exit();
561#endif
562 }
563
564 dss_exit();
565
566 /* these should be removed at some point */
567 c = core.dss_ick->usecount;
568 if (c > 0) {
569 DSSERR("warning: dss_ick usecount %d, disabling\n", c);
570 while (c-- > 0)
571 clk_disable(core.dss_ick);
572 }
573
574 c = core.dss1_fck->usecount;
575 if (c > 0) {
576 DSSERR("warning: dss1_fck usecount %d, disabling\n", c);
577 while (c-- > 0)
578 clk_disable(core.dss1_fck);
579 }
580
581 c = core.dss2_fck->usecount;
582 if (c > 0) {
583 DSSERR("warning: dss2_fck usecount %d, disabling\n", c);
584 while (c-- > 0)
585 clk_disable(core.dss2_fck);
586 }
587
588 c = core.dss_54m_fck->usecount;
589 if (c > 0) {
590 DSSERR("warning: dss_54m_fck usecount %d, disabling\n", c);
591 while (c-- > 0)
592 clk_disable(core.dss_54m_fck);
593 }
594
595 if (core.dss_96m_fck) {
596 c = core.dss_96m_fck->usecount;
597 if (c > 0) {
598 DSSERR("warning: dss_96m_fck usecount %d, disabling\n",
599 c);
600 while (c-- > 0)
601 clk_disable(core.dss_96m_fck);
602 }
603 }
604
605 dss_put_clocks();
606
607 dss_uninit_overlays(pdev);
608 dss_uninit_overlay_managers(pdev);
609
610 for (i = 0; i < pdata->num_devices; ++i)
611 omap_dss_unregister_device(pdata->devices[i]);
612
613 return 0;
614}
615
616static void omap_dss_shutdown(struct platform_device *pdev)
617{
618 DSSDBG("shutdown\n");
619 dss_disable_all_devices();
620}
621
622static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state)
623{
624 DSSDBG("suspend %d\n", state.event);
625
626 return dss_suspend_all_devices();
627}
628
629static int omap_dss_resume(struct platform_device *pdev)
630{
631 DSSDBG("resume\n");
632
633 return dss_resume_all_devices();
634}
635
636static struct platform_driver omap_dss_driver = {
637 .probe = omap_dss_probe,
638 .remove = omap_dss_remove,
639 .shutdown = omap_dss_shutdown,
640 .suspend = omap_dss_suspend,
641 .resume = omap_dss_resume,
642 .driver = {
643 .name = "omapdss",
644 .owner = THIS_MODULE,
645 },
646};
647
648/* BUS */
649static int dss_bus_match(struct device *dev, struct device_driver *driver)
650{
651 struct omap_dss_device *dssdev = to_dss_device(dev);
652
653 DSSDBG("bus_match. dev %s/%s, drv %s\n",
654 dev_name(dev), dssdev->driver_name, driver->name);
655
656 return strcmp(dssdev->driver_name, driver->name) == 0;
657}
658
659static ssize_t device_name_show(struct device *dev,
660 struct device_attribute *attr, char *buf)
661{
662 struct omap_dss_device *dssdev = to_dss_device(dev);
663 return snprintf(buf, PAGE_SIZE, "%s\n",
664 dssdev->name ?
665 dssdev->name : "");
666}
667
668static struct device_attribute default_dev_attrs[] = {
669 __ATTR(name, S_IRUGO, device_name_show, NULL),
670 __ATTR_NULL,
671};
672
673static ssize_t driver_name_show(struct device_driver *drv, char *buf)
674{
675 struct omap_dss_driver *dssdrv = to_dss_driver(drv);
676 return snprintf(buf, PAGE_SIZE, "%s\n",
677 dssdrv->driver.name ?
678 dssdrv->driver.name : "");
679}
680static struct driver_attribute default_drv_attrs[] = {
681 __ATTR(name, S_IRUGO, driver_name_show, NULL),
682 __ATTR_NULL,
683};
684
685static struct bus_type dss_bus_type = {
686 .name = "omapdss",
687 .match = dss_bus_match,
688 .dev_attrs = default_dev_attrs,
689 .drv_attrs = default_drv_attrs,
690};
691
692static void dss_bus_release(struct device *dev)
693{
694 DSSDBG("bus_release\n");
695}
696
697static struct device dss_bus = {
698 .release = dss_bus_release,
699};
700
701struct bus_type *dss_get_bus(void)
702{
703 return &dss_bus_type;
704}
705
706/* DRIVER */
707static int dss_driver_probe(struct device *dev)
708{
709 int r;
710 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
711 struct omap_dss_device *dssdev = to_dss_device(dev);
712 struct omap_dss_board_info *pdata = core.pdev->dev.platform_data;
713 bool force;
714
715 DSSDBG("driver_probe: dev %s/%s, drv %s\n",
716 dev_name(dev), dssdev->driver_name,
717 dssdrv->driver.name);
718
719 dss_init_device(core.pdev, dssdev);
720
721 /* skip this if the device is behind a ctrl */
722 if (!dssdev->panel.ctrl) {
723 force = pdata->default_device == dssdev;
724 dss_recheck_connections(dssdev, force);
725 }
726
727 r = dssdrv->probe(dssdev);
728
729 if (r) {
730 DSSERR("driver probe failed: %d\n", r);
731 return r;
732 }
733
734 DSSDBG("probe done for device %s\n", dev_name(dev));
735
736 dssdev->driver = dssdrv;
737
738 return 0;
739}
740
741static int dss_driver_remove(struct device *dev)
742{
743 struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver);
744 struct omap_dss_device *dssdev = to_dss_device(dev);
745
746 DSSDBG("driver_remove: dev %s/%s\n", dev_name(dev),
747 dssdev->driver_name);
748
749 dssdrv->remove(dssdev);
750
751 dss_uninit_device(core.pdev, dssdev);
752
753 dssdev->driver = NULL;
754
755 return 0;
756}
757
758int omap_dss_register_driver(struct omap_dss_driver *dssdriver)
759{
760 dssdriver->driver.bus = &dss_bus_type;
761 dssdriver->driver.probe = dss_driver_probe;
762 dssdriver->driver.remove = dss_driver_remove;
763 return driver_register(&dssdriver->driver);
764}
765EXPORT_SYMBOL(omap_dss_register_driver);
766
767void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver)
768{
769 driver_unregister(&dssdriver->driver);
770}
771EXPORT_SYMBOL(omap_dss_unregister_driver);
772
773/* DEVICE */
774static void reset_device(struct device *dev, int check)
775{
776 u8 *dev_p = (u8 *)dev;
777 u8 *dev_end = dev_p + sizeof(*dev);
778 void *saved_pdata;
779
780 saved_pdata = dev->platform_data;
781 if (check) {
782 /*
783 * Check if there is any other setting than platform_data
784 * in struct device; warn that these will be reset by our
785 * init.
786 */
787 dev->platform_data = NULL;
788 while (dev_p < dev_end) {
789 if (*dev_p) {
790 WARN("%s: struct device fields will be "
791 "discarded\n",
792 __func__);
793 break;
794 }
795 dev_p++;
796 }
797 }
798 memset(dev, 0, sizeof(*dev));
799 dev->platform_data = saved_pdata;
800}
801
802
803static void omap_dss_dev_release(struct device *dev)
804{
805 reset_device(dev, 0);
806}
807
808int omap_dss_register_device(struct omap_dss_device *dssdev)
809{
810 static int dev_num;
811 static int panel_num;
812 int r;
813
814 WARN_ON(!dssdev->driver_name);
815
816 reset_device(&dssdev->dev, 1);
817 dssdev->dev.bus = &dss_bus_type;
818 dssdev->dev.parent = &dss_bus;
819 dssdev->dev.release = omap_dss_dev_release;
820 dev_set_name(&dssdev->dev, "display%d", dev_num++);
821 r = device_register(&dssdev->dev);
822 if (r)
823 return r;
824
825 if (dssdev->ctrl.panel) {
826 struct omap_dss_device *panel = dssdev->ctrl.panel;
827
828 panel->panel.ctrl = dssdev;
829
830 reset_device(&panel->dev, 1);
831 panel->dev.bus = &dss_bus_type;
832 panel->dev.parent = &dssdev->dev;
833 panel->dev.release = omap_dss_dev_release;
834 dev_set_name(&panel->dev, "panel%d", panel_num++);
835 r = device_register(&panel->dev);
836 if (r)
837 return r;
838 }
839
840 return 0;
841}
842
843void omap_dss_unregister_device(struct omap_dss_device *dssdev)
844{
845 device_unregister(&dssdev->dev);
846
847 if (dssdev->ctrl.panel) {
848 struct omap_dss_device *panel = dssdev->ctrl.panel;
849 device_unregister(&panel->dev);
850 }
851}
852
853/* BUS */
854static int omap_dss_bus_register(void)
855{
856 int r;
857
858 r = bus_register(&dss_bus_type);
859 if (r) {
860 DSSERR("bus register failed\n");
861 return r;
862 }
863
864 dev_set_name(&dss_bus, "omapdss");
865 r = device_register(&dss_bus);
866 if (r) {
867 DSSERR("bus driver register failed\n");
868 bus_unregister(&dss_bus_type);
869 return r;
870 }
871
872 return 0;
873}
874
875/* INIT */
876
877#ifdef CONFIG_OMAP2_DSS_MODULE
878static void omap_dss_bus_unregister(void)
879{
880 device_unregister(&dss_bus);
881
882 bus_unregister(&dss_bus_type);
883}
884
885static int __init omap_dss_init(void)
886{
887 int r;
888
889 r = omap_dss_bus_register();
890 if (r)
891 return r;
892
893 r = platform_driver_register(&omap_dss_driver);
894 if (r) {
895 omap_dss_bus_unregister();
896 return r;
897 }
898
899 return 0;
900}
901
902static void __exit omap_dss_exit(void)
903{
904 platform_driver_unregister(&omap_dss_driver);
905
906 omap_dss_bus_unregister();
907}
908
909module_init(omap_dss_init);
910module_exit(omap_dss_exit);
911#else
912static int __init omap_dss_init(void)
913{
914 return omap_dss_bus_register();
915}
916
917static int __init omap_dss_init2(void)
918{
919 return platform_driver_register(&omap_dss_driver);
920}
921
922core_initcall(omap_dss_init);
923device_initcall(omap_dss_init2);
924#endif
925
926MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
927MODULE_DESCRIPTION("OMAP2/3 Display Subsystem");
928MODULE_LICENSE("GPL v2");
929
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
new file mode 100644
index 000000000000..de8bfbac9e26
--- /dev/null
+++ b/drivers/video/omap2/dss/dispc.c
@@ -0,0 +1,3161 @@
1/*
2 * linux/drivers/video/omap2/dss/dispc.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DISPC"
24
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/vmalloc.h>
28#include <linux/clk.h>
29#include <linux/io.h>
30#include <linux/jiffies.h>
31#include <linux/seq_file.h>
32#include <linux/delay.h>
33#include <linux/workqueue.h>
34
35#include <plat/sram.h>
36#include <plat/clock.h>
37
38#include <plat/display.h>
39
40#include "dss.h"
41
42/* DISPC */
43#define DISPC_BASE 0x48050400
44
45#define DISPC_SZ_REGS SZ_1K
46
47struct dispc_reg { u16 idx; };
48
49#define DISPC_REG(idx) ((const struct dispc_reg) { idx })
50
51/* DISPC common */
52#define DISPC_REVISION DISPC_REG(0x0000)
53#define DISPC_SYSCONFIG DISPC_REG(0x0010)
54#define DISPC_SYSSTATUS DISPC_REG(0x0014)
55#define DISPC_IRQSTATUS DISPC_REG(0x0018)
56#define DISPC_IRQENABLE DISPC_REG(0x001C)
57#define DISPC_CONTROL DISPC_REG(0x0040)
58#define DISPC_CONFIG DISPC_REG(0x0044)
59#define DISPC_CAPABLE DISPC_REG(0x0048)
60#define DISPC_DEFAULT_COLOR0 DISPC_REG(0x004C)
61#define DISPC_DEFAULT_COLOR1 DISPC_REG(0x0050)
62#define DISPC_TRANS_COLOR0 DISPC_REG(0x0054)
63#define DISPC_TRANS_COLOR1 DISPC_REG(0x0058)
64#define DISPC_LINE_STATUS DISPC_REG(0x005C)
65#define DISPC_LINE_NUMBER DISPC_REG(0x0060)
66#define DISPC_TIMING_H DISPC_REG(0x0064)
67#define DISPC_TIMING_V DISPC_REG(0x0068)
68#define DISPC_POL_FREQ DISPC_REG(0x006C)
69#define DISPC_DIVISOR DISPC_REG(0x0070)
70#define DISPC_GLOBAL_ALPHA DISPC_REG(0x0074)
71#define DISPC_SIZE_DIG DISPC_REG(0x0078)
72#define DISPC_SIZE_LCD DISPC_REG(0x007C)
73
74/* DISPC GFX plane */
75#define DISPC_GFX_BA0 DISPC_REG(0x0080)
76#define DISPC_GFX_BA1 DISPC_REG(0x0084)
77#define DISPC_GFX_POSITION DISPC_REG(0x0088)
78#define DISPC_GFX_SIZE DISPC_REG(0x008C)
79#define DISPC_GFX_ATTRIBUTES DISPC_REG(0x00A0)
80#define DISPC_GFX_FIFO_THRESHOLD DISPC_REG(0x00A4)
81#define DISPC_GFX_FIFO_SIZE_STATUS DISPC_REG(0x00A8)
82#define DISPC_GFX_ROW_INC DISPC_REG(0x00AC)
83#define DISPC_GFX_PIXEL_INC DISPC_REG(0x00B0)
84#define DISPC_GFX_WINDOW_SKIP DISPC_REG(0x00B4)
85#define DISPC_GFX_TABLE_BA DISPC_REG(0x00B8)
86
87#define DISPC_DATA_CYCLE1 DISPC_REG(0x01D4)
88#define DISPC_DATA_CYCLE2 DISPC_REG(0x01D8)
89#define DISPC_DATA_CYCLE3 DISPC_REG(0x01DC)
90
91#define DISPC_CPR_COEF_R DISPC_REG(0x0220)
92#define DISPC_CPR_COEF_G DISPC_REG(0x0224)
93#define DISPC_CPR_COEF_B DISPC_REG(0x0228)
94
95#define DISPC_GFX_PRELOAD DISPC_REG(0x022C)
96
97/* DISPC Video plane, n = 0 for VID1 and n = 1 for VID2 */
98#define DISPC_VID_REG(n, idx) DISPC_REG(0x00BC + (n)*0x90 + idx)
99
100#define DISPC_VID_BA0(n) DISPC_VID_REG(n, 0x0000)
101#define DISPC_VID_BA1(n) DISPC_VID_REG(n, 0x0004)
102#define DISPC_VID_POSITION(n) DISPC_VID_REG(n, 0x0008)
103#define DISPC_VID_SIZE(n) DISPC_VID_REG(n, 0x000C)
104#define DISPC_VID_ATTRIBUTES(n) DISPC_VID_REG(n, 0x0010)
105#define DISPC_VID_FIFO_THRESHOLD(n) DISPC_VID_REG(n, 0x0014)
106#define DISPC_VID_FIFO_SIZE_STATUS(n) DISPC_VID_REG(n, 0x0018)
107#define DISPC_VID_ROW_INC(n) DISPC_VID_REG(n, 0x001C)
108#define DISPC_VID_PIXEL_INC(n) DISPC_VID_REG(n, 0x0020)
109#define DISPC_VID_FIR(n) DISPC_VID_REG(n, 0x0024)
110#define DISPC_VID_PICTURE_SIZE(n) DISPC_VID_REG(n, 0x0028)
111#define DISPC_VID_ACCU0(n) DISPC_VID_REG(n, 0x002C)
112#define DISPC_VID_ACCU1(n) DISPC_VID_REG(n, 0x0030)
113
114/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
115#define DISPC_VID_FIR_COEF_H(n, i) DISPC_REG(0x00F0 + (n)*0x90 + (i)*0x8)
116/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
117#define DISPC_VID_FIR_COEF_HV(n, i) DISPC_REG(0x00F4 + (n)*0x90 + (i)*0x8)
118/* coef index i = {0, 1, 2, 3, 4} */
119#define DISPC_VID_CONV_COEF(n, i) DISPC_REG(0x0130 + (n)*0x90 + (i)*0x4)
120/* coef index i = {0, 1, 2, 3, 4, 5, 6, 7} */
121#define DISPC_VID_FIR_COEF_V(n, i) DISPC_REG(0x01E0 + (n)*0x20 + (i)*0x4)
122
123#define DISPC_VID_PRELOAD(n) DISPC_REG(0x230 + (n)*0x04)
124
125
126#define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
127 DISPC_IRQ_OCP_ERR | \
128 DISPC_IRQ_VID1_FIFO_UNDERFLOW | \
129 DISPC_IRQ_VID2_FIFO_UNDERFLOW | \
130 DISPC_IRQ_SYNC_LOST | \
131 DISPC_IRQ_SYNC_LOST_DIGIT)
132
133#define DISPC_MAX_NR_ISRS 8
134
135struct omap_dispc_isr_data {
136 omap_dispc_isr_t isr;
137 void *arg;
138 u32 mask;
139};
140
141#define REG_GET(idx, start, end) \
142 FLD_GET(dispc_read_reg(idx), start, end)
143
144#define REG_FLD_MOD(idx, val, start, end) \
145 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
146
147static const struct dispc_reg dispc_reg_att[] = { DISPC_GFX_ATTRIBUTES,
148 DISPC_VID_ATTRIBUTES(0),
149 DISPC_VID_ATTRIBUTES(1) };
150
151struct dispc_irq_stats {
152 unsigned long last_reset;
153 unsigned irq_count;
154 unsigned irqs[32];
155};
156
157static struct {
158 void __iomem *base;
159
160 u32 fifo_size[3];
161
162 spinlock_t irq_lock;
163 u32 irq_error_mask;
164 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
165 u32 error_irqs;
166 struct work_struct error_work;
167
168 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
169
170#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
171 spinlock_t irq_stats_lock;
172 struct dispc_irq_stats irq_stats;
173#endif
174} dispc;
175
176static void _omap_dispc_set_irqs(void);
177
178static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
179{
180 __raw_writel(val, dispc.base + idx.idx);
181}
182
183static inline u32 dispc_read_reg(const struct dispc_reg idx)
184{
185 return __raw_readl(dispc.base + idx.idx);
186}
187
188#define SR(reg) \
189 dispc.ctx[(DISPC_##reg).idx / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
190#define RR(reg) \
191 dispc_write_reg(DISPC_##reg, dispc.ctx[(DISPC_##reg).idx / sizeof(u32)])
192
193void dispc_save_context(void)
194{
195 if (cpu_is_omap24xx())
196 return;
197
198 SR(SYSCONFIG);
199 SR(IRQENABLE);
200 SR(CONTROL);
201 SR(CONFIG);
202 SR(DEFAULT_COLOR0);
203 SR(DEFAULT_COLOR1);
204 SR(TRANS_COLOR0);
205 SR(TRANS_COLOR1);
206 SR(LINE_NUMBER);
207 SR(TIMING_H);
208 SR(TIMING_V);
209 SR(POL_FREQ);
210 SR(DIVISOR);
211 SR(GLOBAL_ALPHA);
212 SR(SIZE_DIG);
213 SR(SIZE_LCD);
214
215 SR(GFX_BA0);
216 SR(GFX_BA1);
217 SR(GFX_POSITION);
218 SR(GFX_SIZE);
219 SR(GFX_ATTRIBUTES);
220 SR(GFX_FIFO_THRESHOLD);
221 SR(GFX_ROW_INC);
222 SR(GFX_PIXEL_INC);
223 SR(GFX_WINDOW_SKIP);
224 SR(GFX_TABLE_BA);
225
226 SR(DATA_CYCLE1);
227 SR(DATA_CYCLE2);
228 SR(DATA_CYCLE3);
229
230 SR(CPR_COEF_R);
231 SR(CPR_COEF_G);
232 SR(CPR_COEF_B);
233
234 SR(GFX_PRELOAD);
235
236 /* VID1 */
237 SR(VID_BA0(0));
238 SR(VID_BA1(0));
239 SR(VID_POSITION(0));
240 SR(VID_SIZE(0));
241 SR(VID_ATTRIBUTES(0));
242 SR(VID_FIFO_THRESHOLD(0));
243 SR(VID_ROW_INC(0));
244 SR(VID_PIXEL_INC(0));
245 SR(VID_FIR(0));
246 SR(VID_PICTURE_SIZE(0));
247 SR(VID_ACCU0(0));
248 SR(VID_ACCU1(0));
249
250 SR(VID_FIR_COEF_H(0, 0));
251 SR(VID_FIR_COEF_H(0, 1));
252 SR(VID_FIR_COEF_H(0, 2));
253 SR(VID_FIR_COEF_H(0, 3));
254 SR(VID_FIR_COEF_H(0, 4));
255 SR(VID_FIR_COEF_H(0, 5));
256 SR(VID_FIR_COEF_H(0, 6));
257 SR(VID_FIR_COEF_H(0, 7));
258
259 SR(VID_FIR_COEF_HV(0, 0));
260 SR(VID_FIR_COEF_HV(0, 1));
261 SR(VID_FIR_COEF_HV(0, 2));
262 SR(VID_FIR_COEF_HV(0, 3));
263 SR(VID_FIR_COEF_HV(0, 4));
264 SR(VID_FIR_COEF_HV(0, 5));
265 SR(VID_FIR_COEF_HV(0, 6));
266 SR(VID_FIR_COEF_HV(0, 7));
267
268 SR(VID_CONV_COEF(0, 0));
269 SR(VID_CONV_COEF(0, 1));
270 SR(VID_CONV_COEF(0, 2));
271 SR(VID_CONV_COEF(0, 3));
272 SR(VID_CONV_COEF(0, 4));
273
274 SR(VID_FIR_COEF_V(0, 0));
275 SR(VID_FIR_COEF_V(0, 1));
276 SR(VID_FIR_COEF_V(0, 2));
277 SR(VID_FIR_COEF_V(0, 3));
278 SR(VID_FIR_COEF_V(0, 4));
279 SR(VID_FIR_COEF_V(0, 5));
280 SR(VID_FIR_COEF_V(0, 6));
281 SR(VID_FIR_COEF_V(0, 7));
282
283 SR(VID_PRELOAD(0));
284
285 /* VID2 */
286 SR(VID_BA0(1));
287 SR(VID_BA1(1));
288 SR(VID_POSITION(1));
289 SR(VID_SIZE(1));
290 SR(VID_ATTRIBUTES(1));
291 SR(VID_FIFO_THRESHOLD(1));
292 SR(VID_ROW_INC(1));
293 SR(VID_PIXEL_INC(1));
294 SR(VID_FIR(1));
295 SR(VID_PICTURE_SIZE(1));
296 SR(VID_ACCU0(1));
297 SR(VID_ACCU1(1));
298
299 SR(VID_FIR_COEF_H(1, 0));
300 SR(VID_FIR_COEF_H(1, 1));
301 SR(VID_FIR_COEF_H(1, 2));
302 SR(VID_FIR_COEF_H(1, 3));
303 SR(VID_FIR_COEF_H(1, 4));
304 SR(VID_FIR_COEF_H(1, 5));
305 SR(VID_FIR_COEF_H(1, 6));
306 SR(VID_FIR_COEF_H(1, 7));
307
308 SR(VID_FIR_COEF_HV(1, 0));
309 SR(VID_FIR_COEF_HV(1, 1));
310 SR(VID_FIR_COEF_HV(1, 2));
311 SR(VID_FIR_COEF_HV(1, 3));
312 SR(VID_FIR_COEF_HV(1, 4));
313 SR(VID_FIR_COEF_HV(1, 5));
314 SR(VID_FIR_COEF_HV(1, 6));
315 SR(VID_FIR_COEF_HV(1, 7));
316
317 SR(VID_CONV_COEF(1, 0));
318 SR(VID_CONV_COEF(1, 1));
319 SR(VID_CONV_COEF(1, 2));
320 SR(VID_CONV_COEF(1, 3));
321 SR(VID_CONV_COEF(1, 4));
322
323 SR(VID_FIR_COEF_V(1, 0));
324 SR(VID_FIR_COEF_V(1, 1));
325 SR(VID_FIR_COEF_V(1, 2));
326 SR(VID_FIR_COEF_V(1, 3));
327 SR(VID_FIR_COEF_V(1, 4));
328 SR(VID_FIR_COEF_V(1, 5));
329 SR(VID_FIR_COEF_V(1, 6));
330 SR(VID_FIR_COEF_V(1, 7));
331
332 SR(VID_PRELOAD(1));
333}
334
335void dispc_restore_context(void)
336{
337 RR(SYSCONFIG);
338 RR(IRQENABLE);
339 /*RR(CONTROL);*/
340 RR(CONFIG);
341 RR(DEFAULT_COLOR0);
342 RR(DEFAULT_COLOR1);
343 RR(TRANS_COLOR0);
344 RR(TRANS_COLOR1);
345 RR(LINE_NUMBER);
346 RR(TIMING_H);
347 RR(TIMING_V);
348 RR(POL_FREQ);
349 RR(DIVISOR);
350 RR(GLOBAL_ALPHA);
351 RR(SIZE_DIG);
352 RR(SIZE_LCD);
353
354 RR(GFX_BA0);
355 RR(GFX_BA1);
356 RR(GFX_POSITION);
357 RR(GFX_SIZE);
358 RR(GFX_ATTRIBUTES);
359 RR(GFX_FIFO_THRESHOLD);
360 RR(GFX_ROW_INC);
361 RR(GFX_PIXEL_INC);
362 RR(GFX_WINDOW_SKIP);
363 RR(GFX_TABLE_BA);
364
365 RR(DATA_CYCLE1);
366 RR(DATA_CYCLE2);
367 RR(DATA_CYCLE3);
368
369 RR(CPR_COEF_R);
370 RR(CPR_COEF_G);
371 RR(CPR_COEF_B);
372
373 RR(GFX_PRELOAD);
374
375 /* VID1 */
376 RR(VID_BA0(0));
377 RR(VID_BA1(0));
378 RR(VID_POSITION(0));
379 RR(VID_SIZE(0));
380 RR(VID_ATTRIBUTES(0));
381 RR(VID_FIFO_THRESHOLD(0));
382 RR(VID_ROW_INC(0));
383 RR(VID_PIXEL_INC(0));
384 RR(VID_FIR(0));
385 RR(VID_PICTURE_SIZE(0));
386 RR(VID_ACCU0(0));
387 RR(VID_ACCU1(0));
388
389 RR(VID_FIR_COEF_H(0, 0));
390 RR(VID_FIR_COEF_H(0, 1));
391 RR(VID_FIR_COEF_H(0, 2));
392 RR(VID_FIR_COEF_H(0, 3));
393 RR(VID_FIR_COEF_H(0, 4));
394 RR(VID_FIR_COEF_H(0, 5));
395 RR(VID_FIR_COEF_H(0, 6));
396 RR(VID_FIR_COEF_H(0, 7));
397
398 RR(VID_FIR_COEF_HV(0, 0));
399 RR(VID_FIR_COEF_HV(0, 1));
400 RR(VID_FIR_COEF_HV(0, 2));
401 RR(VID_FIR_COEF_HV(0, 3));
402 RR(VID_FIR_COEF_HV(0, 4));
403 RR(VID_FIR_COEF_HV(0, 5));
404 RR(VID_FIR_COEF_HV(0, 6));
405 RR(VID_FIR_COEF_HV(0, 7));
406
407 RR(VID_CONV_COEF(0, 0));
408 RR(VID_CONV_COEF(0, 1));
409 RR(VID_CONV_COEF(0, 2));
410 RR(VID_CONV_COEF(0, 3));
411 RR(VID_CONV_COEF(0, 4));
412
413 RR(VID_FIR_COEF_V(0, 0));
414 RR(VID_FIR_COEF_V(0, 1));
415 RR(VID_FIR_COEF_V(0, 2));
416 RR(VID_FIR_COEF_V(0, 3));
417 RR(VID_FIR_COEF_V(0, 4));
418 RR(VID_FIR_COEF_V(0, 5));
419 RR(VID_FIR_COEF_V(0, 6));
420 RR(VID_FIR_COEF_V(0, 7));
421
422 RR(VID_PRELOAD(0));
423
424 /* VID2 */
425 RR(VID_BA0(1));
426 RR(VID_BA1(1));
427 RR(VID_POSITION(1));
428 RR(VID_SIZE(1));
429 RR(VID_ATTRIBUTES(1));
430 RR(VID_FIFO_THRESHOLD(1));
431 RR(VID_ROW_INC(1));
432 RR(VID_PIXEL_INC(1));
433 RR(VID_FIR(1));
434 RR(VID_PICTURE_SIZE(1));
435 RR(VID_ACCU0(1));
436 RR(VID_ACCU1(1));
437
438 RR(VID_FIR_COEF_H(1, 0));
439 RR(VID_FIR_COEF_H(1, 1));
440 RR(VID_FIR_COEF_H(1, 2));
441 RR(VID_FIR_COEF_H(1, 3));
442 RR(VID_FIR_COEF_H(1, 4));
443 RR(VID_FIR_COEF_H(1, 5));
444 RR(VID_FIR_COEF_H(1, 6));
445 RR(VID_FIR_COEF_H(1, 7));
446
447 RR(VID_FIR_COEF_HV(1, 0));
448 RR(VID_FIR_COEF_HV(1, 1));
449 RR(VID_FIR_COEF_HV(1, 2));
450 RR(VID_FIR_COEF_HV(1, 3));
451 RR(VID_FIR_COEF_HV(1, 4));
452 RR(VID_FIR_COEF_HV(1, 5));
453 RR(VID_FIR_COEF_HV(1, 6));
454 RR(VID_FIR_COEF_HV(1, 7));
455
456 RR(VID_CONV_COEF(1, 0));
457 RR(VID_CONV_COEF(1, 1));
458 RR(VID_CONV_COEF(1, 2));
459 RR(VID_CONV_COEF(1, 3));
460 RR(VID_CONV_COEF(1, 4));
461
462 RR(VID_FIR_COEF_V(1, 0));
463 RR(VID_FIR_COEF_V(1, 1));
464 RR(VID_FIR_COEF_V(1, 2));
465 RR(VID_FIR_COEF_V(1, 3));
466 RR(VID_FIR_COEF_V(1, 4));
467 RR(VID_FIR_COEF_V(1, 5));
468 RR(VID_FIR_COEF_V(1, 6));
469 RR(VID_FIR_COEF_V(1, 7));
470
471 RR(VID_PRELOAD(1));
472
473 /* enable last, because LCD & DIGIT enable are here */
474 RR(CONTROL);
475}
476
477#undef SR
478#undef RR
479
480static inline void enable_clocks(bool enable)
481{
482 if (enable)
483 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
484 else
485 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
486}
487
488bool dispc_go_busy(enum omap_channel channel)
489{
490 int bit;
491
492 if (channel == OMAP_DSS_CHANNEL_LCD)
493 bit = 5; /* GOLCD */
494 else
495 bit = 6; /* GODIGIT */
496
497 return REG_GET(DISPC_CONTROL, bit, bit) == 1;
498}
499
500void dispc_go(enum omap_channel channel)
501{
502 int bit;
503
504 enable_clocks(1);
505
506 if (channel == OMAP_DSS_CHANNEL_LCD)
507 bit = 0; /* LCDENABLE */
508 else
509 bit = 1; /* DIGITALENABLE */
510
511 /* if the channel is not enabled, we don't need GO */
512 if (REG_GET(DISPC_CONTROL, bit, bit) == 0)
513 goto end;
514
515 if (channel == OMAP_DSS_CHANNEL_LCD)
516 bit = 5; /* GOLCD */
517 else
518 bit = 6; /* GODIGIT */
519
520 if (REG_GET(DISPC_CONTROL, bit, bit) == 1) {
521 DSSERR("GO bit not down for channel %d\n", channel);
522 goto end;
523 }
524
525 DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : "DIGIT");
526
527 REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit);
528end:
529 enable_clocks(0);
530}
531
532static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value)
533{
534 BUG_ON(plane == OMAP_DSS_GFX);
535
536 dispc_write_reg(DISPC_VID_FIR_COEF_H(plane-1, reg), value);
537}
538
539static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
540{
541 BUG_ON(plane == OMAP_DSS_GFX);
542
543 dispc_write_reg(DISPC_VID_FIR_COEF_HV(plane-1, reg), value);
544}
545
546static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value)
547{
548 BUG_ON(plane == OMAP_DSS_GFX);
549
550 dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
551}
552
553static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
554 int vscaleup, int five_taps)
555{
556 /* Coefficients for horizontal up-sampling */
557 static const u32 coef_hup[8] = {
558 0x00800000,
559 0x0D7CF800,
560 0x1E70F5FF,
561 0x335FF5FE,
562 0xF74949F7,
563 0xF55F33FB,
564 0xF5701EFE,
565 0xF87C0DFF,
566 };
567
568 /* Coefficients for horizontal down-sampling */
569 static const u32 coef_hdown[8] = {
570 0x24382400,
571 0x28371FFE,
572 0x2C361BFB,
573 0x303516F9,
574 0x11343311,
575 0x1635300C,
576 0x1B362C08,
577 0x1F372804,
578 };
579
580 /* Coefficients for horizontal and vertical up-sampling */
581 static const u32 coef_hvup[2][8] = {
582 {
583 0x00800000,
584 0x037B02FF,
585 0x0C6F05FE,
586 0x205907FB,
587 0x00404000,
588 0x075920FE,
589 0x056F0CFF,
590 0x027B0300,
591 },
592 {
593 0x00800000,
594 0x0D7CF8FF,
595 0x1E70F5FE,
596 0x335FF5FB,
597 0xF7404000,
598 0xF55F33FE,
599 0xF5701EFF,
600 0xF87C0D00,
601 },
602 };
603
604 /* Coefficients for horizontal and vertical down-sampling */
605 static const u32 coef_hvdown[2][8] = {
606 {
607 0x24382400,
608 0x28391F04,
609 0x2D381B08,
610 0x3237170C,
611 0x123737F7,
612 0x173732F9,
613 0x1B382DFB,
614 0x1F3928FE,
615 },
616 {
617 0x24382400,
618 0x28371F04,
619 0x2C361B08,
620 0x3035160C,
621 0x113433F7,
622 0x163530F9,
623 0x1B362CFB,
624 0x1F3728FE,
625 },
626 };
627
628 /* Coefficients for vertical up-sampling */
629 static const u32 coef_vup[8] = {
630 0x00000000,
631 0x0000FF00,
632 0x0000FEFF,
633 0x0000FBFE,
634 0x000000F7,
635 0x0000FEFB,
636 0x0000FFFE,
637 0x000000FF,
638 };
639
640
641 /* Coefficients for vertical down-sampling */
642 static const u32 coef_vdown[8] = {
643 0x00000000,
644 0x000004FE,
645 0x000008FB,
646 0x00000CF9,
647 0x0000F711,
648 0x0000F90C,
649 0x0000FB08,
650 0x0000FE04,
651 };
652
653 const u32 *h_coef;
654 const u32 *hv_coef;
655 const u32 *hv_coef_mod;
656 const u32 *v_coef;
657 int i;
658
659 if (hscaleup)
660 h_coef = coef_hup;
661 else
662 h_coef = coef_hdown;
663
664 if (vscaleup) {
665 hv_coef = coef_hvup[five_taps];
666 v_coef = coef_vup;
667
668 if (hscaleup)
669 hv_coef_mod = NULL;
670 else
671 hv_coef_mod = coef_hvdown[five_taps];
672 } else {
673 hv_coef = coef_hvdown[five_taps];
674 v_coef = coef_vdown;
675
676 if (hscaleup)
677 hv_coef_mod = coef_hvup[five_taps];
678 else
679 hv_coef_mod = NULL;
680 }
681
682 for (i = 0; i < 8; i++) {
683 u32 h, hv;
684
685 h = h_coef[i];
686
687 hv = hv_coef[i];
688
689 if (hv_coef_mod) {
690 hv &= 0xffffff00;
691 hv |= (hv_coef_mod[i] & 0xff);
692 }
693
694 _dispc_write_firh_reg(plane, i, h);
695 _dispc_write_firhv_reg(plane, i, hv);
696 }
697
698 if (!five_taps)
699 return;
700
701 for (i = 0; i < 8; i++) {
702 u32 v;
703 v = v_coef[i];
704 _dispc_write_firv_reg(plane, i, v);
705 }
706}
707
708static void _dispc_setup_color_conv_coef(void)
709{
710 const struct color_conv_coef {
711 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
712 int full_range;
713 } ctbl_bt601_5 = {
714 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
715 };
716
717 const struct color_conv_coef *ct;
718
719#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
720
721 ct = &ctbl_bt601_5;
722
723 dispc_write_reg(DISPC_VID_CONV_COEF(0, 0), CVAL(ct->rcr, ct->ry));
724 dispc_write_reg(DISPC_VID_CONV_COEF(0, 1), CVAL(ct->gy, ct->rcb));
725 dispc_write_reg(DISPC_VID_CONV_COEF(0, 2), CVAL(ct->gcb, ct->gcr));
726 dispc_write_reg(DISPC_VID_CONV_COEF(0, 3), CVAL(ct->bcr, ct->by));
727 dispc_write_reg(DISPC_VID_CONV_COEF(0, 4), CVAL(0, ct->bcb));
728
729 dispc_write_reg(DISPC_VID_CONV_COEF(1, 0), CVAL(ct->rcr, ct->ry));
730 dispc_write_reg(DISPC_VID_CONV_COEF(1, 1), CVAL(ct->gy, ct->rcb));
731 dispc_write_reg(DISPC_VID_CONV_COEF(1, 2), CVAL(ct->gcb, ct->gcr));
732 dispc_write_reg(DISPC_VID_CONV_COEF(1, 3), CVAL(ct->bcr, ct->by));
733 dispc_write_reg(DISPC_VID_CONV_COEF(1, 4), CVAL(0, ct->bcb));
734
735#undef CVAL
736
737 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(0), ct->full_range, 11, 11);
738 REG_FLD_MOD(DISPC_VID_ATTRIBUTES(1), ct->full_range, 11, 11);
739}
740
741
742static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr)
743{
744 const struct dispc_reg ba0_reg[] = { DISPC_GFX_BA0,
745 DISPC_VID_BA0(0),
746 DISPC_VID_BA0(1) };
747
748 dispc_write_reg(ba0_reg[plane], paddr);
749}
750
751static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr)
752{
753 const struct dispc_reg ba1_reg[] = { DISPC_GFX_BA1,
754 DISPC_VID_BA1(0),
755 DISPC_VID_BA1(1) };
756
757 dispc_write_reg(ba1_reg[plane], paddr);
758}
759
760static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y)
761{
762 const struct dispc_reg pos_reg[] = { DISPC_GFX_POSITION,
763 DISPC_VID_POSITION(0),
764 DISPC_VID_POSITION(1) };
765
766 u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
767 dispc_write_reg(pos_reg[plane], val);
768}
769
770static void _dispc_set_pic_size(enum omap_plane plane, int width, int height)
771{
772 const struct dispc_reg siz_reg[] = { DISPC_GFX_SIZE,
773 DISPC_VID_PICTURE_SIZE(0),
774 DISPC_VID_PICTURE_SIZE(1) };
775 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
776 dispc_write_reg(siz_reg[plane], val);
777}
778
779static void _dispc_set_vid_size(enum omap_plane plane, int width, int height)
780{
781 u32 val;
782 const struct dispc_reg vsi_reg[] = { DISPC_VID_SIZE(0),
783 DISPC_VID_SIZE(1) };
784
785 BUG_ON(plane == OMAP_DSS_GFX);
786
787 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
788 dispc_write_reg(vsi_reg[plane-1], val);
789}
790
791static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha)
792{
793
794 BUG_ON(plane == OMAP_DSS_VIDEO1);
795
796 if (cpu_is_omap24xx())
797 return;
798
799 if (plane == OMAP_DSS_GFX)
800 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0);
801 else if (plane == OMAP_DSS_VIDEO2)
802 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16);
803}
804
805static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc)
806{
807 const struct dispc_reg ri_reg[] = { DISPC_GFX_PIXEL_INC,
808 DISPC_VID_PIXEL_INC(0),
809 DISPC_VID_PIXEL_INC(1) };
810
811 dispc_write_reg(ri_reg[plane], inc);
812}
813
814static void _dispc_set_row_inc(enum omap_plane plane, s32 inc)
815{
816 const struct dispc_reg ri_reg[] = { DISPC_GFX_ROW_INC,
817 DISPC_VID_ROW_INC(0),
818 DISPC_VID_ROW_INC(1) };
819
820 dispc_write_reg(ri_reg[plane], inc);
821}
822
823static void _dispc_set_color_mode(enum omap_plane plane,
824 enum omap_color_mode color_mode)
825{
826 u32 m = 0;
827
828 switch (color_mode) {
829 case OMAP_DSS_COLOR_CLUT1:
830 m = 0x0; break;
831 case OMAP_DSS_COLOR_CLUT2:
832 m = 0x1; break;
833 case OMAP_DSS_COLOR_CLUT4:
834 m = 0x2; break;
835 case OMAP_DSS_COLOR_CLUT8:
836 m = 0x3; break;
837 case OMAP_DSS_COLOR_RGB12U:
838 m = 0x4; break;
839 case OMAP_DSS_COLOR_ARGB16:
840 m = 0x5; break;
841 case OMAP_DSS_COLOR_RGB16:
842 m = 0x6; break;
843 case OMAP_DSS_COLOR_RGB24U:
844 m = 0x8; break;
845 case OMAP_DSS_COLOR_RGB24P:
846 m = 0x9; break;
847 case OMAP_DSS_COLOR_YUV2:
848 m = 0xa; break;
849 case OMAP_DSS_COLOR_UYVY:
850 m = 0xb; break;
851 case OMAP_DSS_COLOR_ARGB32:
852 m = 0xc; break;
853 case OMAP_DSS_COLOR_RGBA32:
854 m = 0xd; break;
855 case OMAP_DSS_COLOR_RGBX32:
856 m = 0xe; break;
857 default:
858 BUG(); break;
859 }
860
861 REG_FLD_MOD(dispc_reg_att[plane], m, 4, 1);
862}
863
864static void _dispc_set_channel_out(enum omap_plane plane,
865 enum omap_channel channel)
866{
867 int shift;
868 u32 val;
869
870 switch (plane) {
871 case OMAP_DSS_GFX:
872 shift = 8;
873 break;
874 case OMAP_DSS_VIDEO1:
875 case OMAP_DSS_VIDEO2:
876 shift = 16;
877 break;
878 default:
879 BUG();
880 return;
881 }
882
883 val = dispc_read_reg(dispc_reg_att[plane]);
884 val = FLD_MOD(val, channel, shift, shift);
885 dispc_write_reg(dispc_reg_att[plane], val);
886}
887
888void dispc_set_burst_size(enum omap_plane plane,
889 enum omap_burst_size burst_size)
890{
891 int shift;
892 u32 val;
893
894 enable_clocks(1);
895
896 switch (plane) {
897 case OMAP_DSS_GFX:
898 shift = 6;
899 break;
900 case OMAP_DSS_VIDEO1:
901 case OMAP_DSS_VIDEO2:
902 shift = 14;
903 break;
904 default:
905 BUG();
906 return;
907 }
908
909 val = dispc_read_reg(dispc_reg_att[plane]);
910 val = FLD_MOD(val, burst_size, shift+1, shift);
911 dispc_write_reg(dispc_reg_att[plane], val);
912
913 enable_clocks(0);
914}
915
916static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
917{
918 u32 val;
919
920 BUG_ON(plane == OMAP_DSS_GFX);
921
922 val = dispc_read_reg(dispc_reg_att[plane]);
923 val = FLD_MOD(val, enable, 9, 9);
924 dispc_write_reg(dispc_reg_att[plane], val);
925}
926
927void dispc_enable_replication(enum omap_plane plane, bool enable)
928{
929 int bit;
930
931 if (plane == OMAP_DSS_GFX)
932 bit = 5;
933 else
934 bit = 10;
935
936 enable_clocks(1);
937 REG_FLD_MOD(dispc_reg_att[plane], enable, bit, bit);
938 enable_clocks(0);
939}
940
941void dispc_set_lcd_size(u16 width, u16 height)
942{
943 u32 val;
944 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
945 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
946 enable_clocks(1);
947 dispc_write_reg(DISPC_SIZE_LCD, val);
948 enable_clocks(0);
949}
950
951void dispc_set_digit_size(u16 width, u16 height)
952{
953 u32 val;
954 BUG_ON((width > (1 << 11)) || (height > (1 << 11)));
955 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
956 enable_clocks(1);
957 dispc_write_reg(DISPC_SIZE_DIG, val);
958 enable_clocks(0);
959}
960
961static void dispc_read_plane_fifo_sizes(void)
962{
963 const struct dispc_reg fsz_reg[] = { DISPC_GFX_FIFO_SIZE_STATUS,
964 DISPC_VID_FIFO_SIZE_STATUS(0),
965 DISPC_VID_FIFO_SIZE_STATUS(1) };
966 u32 size;
967 int plane;
968
969 enable_clocks(1);
970
971 for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) {
972 if (cpu_is_omap24xx())
973 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 8, 0);
974 else if (cpu_is_omap34xx())
975 size = FLD_GET(dispc_read_reg(fsz_reg[plane]), 10, 0);
976 else
977 BUG();
978
979 dispc.fifo_size[plane] = size;
980 }
981
982 enable_clocks(0);
983}
984
985u32 dispc_get_plane_fifo_size(enum omap_plane plane)
986{
987 return dispc.fifo_size[plane];
988}
989
990void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high)
991{
992 const struct dispc_reg ftrs_reg[] = { DISPC_GFX_FIFO_THRESHOLD,
993 DISPC_VID_FIFO_THRESHOLD(0),
994 DISPC_VID_FIFO_THRESHOLD(1) };
995 enable_clocks(1);
996
997 DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n",
998 plane,
999 REG_GET(ftrs_reg[plane], 11, 0),
1000 REG_GET(ftrs_reg[plane], 27, 16),
1001 low, high);
1002
1003 if (cpu_is_omap24xx())
1004 dispc_write_reg(ftrs_reg[plane],
1005 FLD_VAL(high, 24, 16) | FLD_VAL(low, 8, 0));
1006 else
1007 dispc_write_reg(ftrs_reg[plane],
1008 FLD_VAL(high, 27, 16) | FLD_VAL(low, 11, 0));
1009
1010 enable_clocks(0);
1011}
1012
1013void dispc_enable_fifomerge(bool enable)
1014{
1015 enable_clocks(1);
1016
1017 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1018 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
1019
1020 enable_clocks(0);
1021}
1022
1023static void _dispc_set_fir(enum omap_plane plane, int hinc, int vinc)
1024{
1025 u32 val;
1026 const struct dispc_reg fir_reg[] = { DISPC_VID_FIR(0),
1027 DISPC_VID_FIR(1) };
1028
1029 BUG_ON(plane == OMAP_DSS_GFX);
1030
1031 if (cpu_is_omap24xx())
1032 val = FLD_VAL(vinc, 27, 16) | FLD_VAL(hinc, 11, 0);
1033 else
1034 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1035 dispc_write_reg(fir_reg[plane-1], val);
1036}
1037
1038static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
1039{
1040 u32 val;
1041 const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
1042 DISPC_VID_ACCU0(1) };
1043
1044 BUG_ON(plane == OMAP_DSS_GFX);
1045
1046 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1047 dispc_write_reg(ac0_reg[plane-1], val);
1048}
1049
1050static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
1051{
1052 u32 val;
1053 const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
1054 DISPC_VID_ACCU1(1) };
1055
1056 BUG_ON(plane == OMAP_DSS_GFX);
1057
1058 val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
1059 dispc_write_reg(ac1_reg[plane-1], val);
1060}
1061
1062
1063static void _dispc_set_scaling(enum omap_plane plane,
1064 u16 orig_width, u16 orig_height,
1065 u16 out_width, u16 out_height,
1066 bool ilace, bool five_taps,
1067 bool fieldmode)
1068{
1069 int fir_hinc;
1070 int fir_vinc;
1071 int hscaleup, vscaleup;
1072 int accu0 = 0;
1073 int accu1 = 0;
1074 u32 l;
1075
1076 BUG_ON(plane == OMAP_DSS_GFX);
1077
1078 hscaleup = orig_width <= out_width;
1079 vscaleup = orig_height <= out_height;
1080
1081 _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
1082
1083 if (!orig_width || orig_width == out_width)
1084 fir_hinc = 0;
1085 else
1086 fir_hinc = 1024 * orig_width / out_width;
1087
1088 if (!orig_height || orig_height == out_height)
1089 fir_vinc = 0;
1090 else
1091 fir_vinc = 1024 * orig_height / out_height;
1092
1093 _dispc_set_fir(plane, fir_hinc, fir_vinc);
1094
1095 l = dispc_read_reg(dispc_reg_att[plane]);
1096 l &= ~((0x0f << 5) | (0x3 << 21));
1097
1098 l |= fir_hinc ? (1 << 5) : 0;
1099 l |= fir_vinc ? (1 << 6) : 0;
1100
1101 l |= hscaleup ? 0 : (1 << 7);
1102 l |= vscaleup ? 0 : (1 << 8);
1103
1104 l |= five_taps ? (1 << 21) : 0;
1105 l |= five_taps ? (1 << 22) : 0;
1106
1107 dispc_write_reg(dispc_reg_att[plane], l);
1108
1109 /*
1110 * field 0 = even field = bottom field
1111 * field 1 = odd field = top field
1112 */
1113 if (ilace && !fieldmode) {
1114 accu1 = 0;
1115 accu0 = (fir_vinc / 2) & 0x3ff;
1116 if (accu0 >= 1024/2) {
1117 accu1 = 1024/2;
1118 accu0 -= accu1;
1119 }
1120 }
1121
1122 _dispc_set_vid_accu0(plane, 0, accu0);
1123 _dispc_set_vid_accu1(plane, 0, accu1);
1124}
1125
1126static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1127 bool mirroring, enum omap_color_mode color_mode)
1128{
1129 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1130 color_mode == OMAP_DSS_COLOR_UYVY) {
1131 int vidrot = 0;
1132
1133 if (mirroring) {
1134 switch (rotation) {
1135 case OMAP_DSS_ROT_0:
1136 vidrot = 2;
1137 break;
1138 case OMAP_DSS_ROT_90:
1139 vidrot = 1;
1140 break;
1141 case OMAP_DSS_ROT_180:
1142 vidrot = 0;
1143 break;
1144 case OMAP_DSS_ROT_270:
1145 vidrot = 3;
1146 break;
1147 }
1148 } else {
1149 switch (rotation) {
1150 case OMAP_DSS_ROT_0:
1151 vidrot = 0;
1152 break;
1153 case OMAP_DSS_ROT_90:
1154 vidrot = 1;
1155 break;
1156 case OMAP_DSS_ROT_180:
1157 vidrot = 2;
1158 break;
1159 case OMAP_DSS_ROT_270:
1160 vidrot = 3;
1161 break;
1162 }
1163 }
1164
1165 REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
1166
1167 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1168 REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
1169 else
1170 REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
1171 } else {
1172 REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
1173 REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
1174 }
1175}
1176
1177static int color_mode_to_bpp(enum omap_color_mode color_mode)
1178{
1179 switch (color_mode) {
1180 case OMAP_DSS_COLOR_CLUT1:
1181 return 1;
1182 case OMAP_DSS_COLOR_CLUT2:
1183 return 2;
1184 case OMAP_DSS_COLOR_CLUT4:
1185 return 4;
1186 case OMAP_DSS_COLOR_CLUT8:
1187 return 8;
1188 case OMAP_DSS_COLOR_RGB12U:
1189 case OMAP_DSS_COLOR_RGB16:
1190 case OMAP_DSS_COLOR_ARGB16:
1191 case OMAP_DSS_COLOR_YUV2:
1192 case OMAP_DSS_COLOR_UYVY:
1193 return 16;
1194 case OMAP_DSS_COLOR_RGB24P:
1195 return 24;
1196 case OMAP_DSS_COLOR_RGB24U:
1197 case OMAP_DSS_COLOR_ARGB32:
1198 case OMAP_DSS_COLOR_RGBA32:
1199 case OMAP_DSS_COLOR_RGBX32:
1200 return 32;
1201 default:
1202 BUG();
1203 }
1204}
1205
1206static s32 pixinc(int pixels, u8 ps)
1207{
1208 if (pixels == 1)
1209 return 1;
1210 else if (pixels > 1)
1211 return 1 + (pixels - 1) * ps;
1212 else if (pixels < 0)
1213 return 1 - (-pixels + 1) * ps;
1214 else
1215 BUG();
1216}
1217
1218static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1219 u16 screen_width,
1220 u16 width, u16 height,
1221 enum omap_color_mode color_mode, bool fieldmode,
1222 unsigned int field_offset,
1223 unsigned *offset0, unsigned *offset1,
1224 s32 *row_inc, s32 *pix_inc)
1225{
1226 u8 ps;
1227
1228 /* FIXME CLUT formats */
1229 switch (color_mode) {
1230 case OMAP_DSS_COLOR_CLUT1:
1231 case OMAP_DSS_COLOR_CLUT2:
1232 case OMAP_DSS_COLOR_CLUT4:
1233 case OMAP_DSS_COLOR_CLUT8:
1234 BUG();
1235 return;
1236 case OMAP_DSS_COLOR_YUV2:
1237 case OMAP_DSS_COLOR_UYVY:
1238 ps = 4;
1239 break;
1240 default:
1241 ps = color_mode_to_bpp(color_mode) / 8;
1242 break;
1243 }
1244
1245 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1246 width, height);
1247
1248 /*
1249 * field 0 = even field = bottom field
1250 * field 1 = odd field = top field
1251 */
1252 switch (rotation + mirror * 4) {
1253 case OMAP_DSS_ROT_0:
1254 case OMAP_DSS_ROT_180:
1255 /*
1256 * If the pixel format is YUV or UYVY divide the width
1257 * of the image by 2 for 0 and 180 degree rotation.
1258 */
1259 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1260 color_mode == OMAP_DSS_COLOR_UYVY)
1261 width = width >> 1;
1262 case OMAP_DSS_ROT_90:
1263 case OMAP_DSS_ROT_270:
1264 *offset1 = 0;
1265 if (field_offset)
1266 *offset0 = field_offset * screen_width * ps;
1267 else
1268 *offset0 = 0;
1269
1270 *row_inc = pixinc(1 + (screen_width - width) +
1271 (fieldmode ? screen_width : 0),
1272 ps);
1273 *pix_inc = pixinc(1, ps);
1274 break;
1275
1276 case OMAP_DSS_ROT_0 + 4:
1277 case OMAP_DSS_ROT_180 + 4:
1278 /* If the pixel format is YUV or UYVY divide the width
1279 * of the image by 2 for 0 degree and 180 degree
1280 */
1281 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1282 color_mode == OMAP_DSS_COLOR_UYVY)
1283 width = width >> 1;
1284 case OMAP_DSS_ROT_90 + 4:
1285 case OMAP_DSS_ROT_270 + 4:
1286 *offset1 = 0;
1287 if (field_offset)
1288 *offset0 = field_offset * screen_width * ps;
1289 else
1290 *offset0 = 0;
1291 *row_inc = pixinc(1 - (screen_width + width) -
1292 (fieldmode ? screen_width : 0),
1293 ps);
1294 *pix_inc = pixinc(1, ps);
1295 break;
1296
1297 default:
1298 BUG();
1299 }
1300}
1301
1302static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1303 u16 screen_width,
1304 u16 width, u16 height,
1305 enum omap_color_mode color_mode, bool fieldmode,
1306 unsigned int field_offset,
1307 unsigned *offset0, unsigned *offset1,
1308 s32 *row_inc, s32 *pix_inc)
1309{
1310 u8 ps;
1311 u16 fbw, fbh;
1312
1313 /* FIXME CLUT formats */
1314 switch (color_mode) {
1315 case OMAP_DSS_COLOR_CLUT1:
1316 case OMAP_DSS_COLOR_CLUT2:
1317 case OMAP_DSS_COLOR_CLUT4:
1318 case OMAP_DSS_COLOR_CLUT8:
1319 BUG();
1320 return;
1321 default:
1322 ps = color_mode_to_bpp(color_mode) / 8;
1323 break;
1324 }
1325
1326 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1327 width, height);
1328
1329 /* width & height are overlay sizes, convert to fb sizes */
1330
1331 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
1332 fbw = width;
1333 fbh = height;
1334 } else {
1335 fbw = height;
1336 fbh = width;
1337 }
1338
1339 /*
1340 * field 0 = even field = bottom field
1341 * field 1 = odd field = top field
1342 */
1343 switch (rotation + mirror * 4) {
1344 case OMAP_DSS_ROT_0:
1345 *offset1 = 0;
1346 if (field_offset)
1347 *offset0 = *offset1 + field_offset * screen_width * ps;
1348 else
1349 *offset0 = *offset1;
1350 *row_inc = pixinc(1 + (screen_width - fbw) +
1351 (fieldmode ? screen_width : 0),
1352 ps);
1353 *pix_inc = pixinc(1, ps);
1354 break;
1355 case OMAP_DSS_ROT_90:
1356 *offset1 = screen_width * (fbh - 1) * ps;
1357 if (field_offset)
1358 *offset0 = *offset1 + field_offset * ps;
1359 else
1360 *offset0 = *offset1;
1361 *row_inc = pixinc(screen_width * (fbh - 1) + 1 +
1362 (fieldmode ? 1 : 0), ps);
1363 *pix_inc = pixinc(-screen_width, ps);
1364 break;
1365 case OMAP_DSS_ROT_180:
1366 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1367 if (field_offset)
1368 *offset0 = *offset1 - field_offset * screen_width * ps;
1369 else
1370 *offset0 = *offset1;
1371 *row_inc = pixinc(-1 -
1372 (screen_width - fbw) -
1373 (fieldmode ? screen_width : 0),
1374 ps);
1375 *pix_inc = pixinc(-1, ps);
1376 break;
1377 case OMAP_DSS_ROT_270:
1378 *offset1 = (fbw - 1) * ps;
1379 if (field_offset)
1380 *offset0 = *offset1 - field_offset * ps;
1381 else
1382 *offset0 = *offset1;
1383 *row_inc = pixinc(-screen_width * (fbh - 1) - 1 -
1384 (fieldmode ? 1 : 0), ps);
1385 *pix_inc = pixinc(screen_width, ps);
1386 break;
1387
1388 /* mirroring */
1389 case OMAP_DSS_ROT_0 + 4:
1390 *offset1 = (fbw - 1) * ps;
1391 if (field_offset)
1392 *offset0 = *offset1 + field_offset * screen_width * ps;
1393 else
1394 *offset0 = *offset1;
1395 *row_inc = pixinc(screen_width * 2 - 1 +
1396 (fieldmode ? screen_width : 0),
1397 ps);
1398 *pix_inc = pixinc(-1, ps);
1399 break;
1400
1401 case OMAP_DSS_ROT_90 + 4:
1402 *offset1 = 0;
1403 if (field_offset)
1404 *offset0 = *offset1 + field_offset * ps;
1405 else
1406 *offset0 = *offset1;
1407 *row_inc = pixinc(-screen_width * (fbh - 1) + 1 +
1408 (fieldmode ? 1 : 0),
1409 ps);
1410 *pix_inc = pixinc(screen_width, ps);
1411 break;
1412
1413 case OMAP_DSS_ROT_180 + 4:
1414 *offset1 = screen_width * (fbh - 1) * ps;
1415 if (field_offset)
1416 *offset0 = *offset1 - field_offset * screen_width * ps;
1417 else
1418 *offset0 = *offset1;
1419 *row_inc = pixinc(1 - screen_width * 2 -
1420 (fieldmode ? screen_width : 0),
1421 ps);
1422 *pix_inc = pixinc(1, ps);
1423 break;
1424
1425 case OMAP_DSS_ROT_270 + 4:
1426 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
1427 if (field_offset)
1428 *offset0 = *offset1 - field_offset * ps;
1429 else
1430 *offset0 = *offset1;
1431 *row_inc = pixinc(screen_width * (fbh - 1) - 1 -
1432 (fieldmode ? 1 : 0),
1433 ps);
1434 *pix_inc = pixinc(-screen_width, ps);
1435 break;
1436
1437 default:
1438 BUG();
1439 }
1440}
1441
1442static unsigned long calc_fclk_five_taps(u16 width, u16 height,
1443 u16 out_width, u16 out_height, enum omap_color_mode color_mode)
1444{
1445 u32 fclk = 0;
1446 /* FIXME venc pclk? */
1447 u64 tmp, pclk = dispc_pclk_rate();
1448
1449 if (height > out_height) {
1450 /* FIXME get real display PPL */
1451 unsigned int ppl = 800;
1452
1453 tmp = pclk * height * out_width;
1454 do_div(tmp, 2 * out_height * ppl);
1455 fclk = tmp;
1456
1457 if (height > 2 * out_height) {
1458 if (ppl == out_width)
1459 return 0;
1460
1461 tmp = pclk * (height - 2 * out_height) * out_width;
1462 do_div(tmp, 2 * out_height * (ppl - out_width));
1463 fclk = max(fclk, (u32) tmp);
1464 }
1465 }
1466
1467 if (width > out_width) {
1468 tmp = pclk * width;
1469 do_div(tmp, out_width);
1470 fclk = max(fclk, (u32) tmp);
1471
1472 if (color_mode == OMAP_DSS_COLOR_RGB24U)
1473 fclk <<= 1;
1474 }
1475
1476 return fclk;
1477}
1478
1479static unsigned long calc_fclk(u16 width, u16 height,
1480 u16 out_width, u16 out_height)
1481{
1482 unsigned int hf, vf;
1483
1484 /*
1485 * FIXME how to determine the 'A' factor
1486 * for the no downscaling case ?
1487 */
1488
1489 if (width > 3 * out_width)
1490 hf = 4;
1491 else if (width > 2 * out_width)
1492 hf = 3;
1493 else if (width > out_width)
1494 hf = 2;
1495 else
1496 hf = 1;
1497
1498 if (height > out_height)
1499 vf = 2;
1500 else
1501 vf = 1;
1502
1503 /* FIXME venc pclk? */
1504 return dispc_pclk_rate() * vf * hf;
1505}
1506
1507void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
1508{
1509 enable_clocks(1);
1510 _dispc_set_channel_out(plane, channel_out);
1511 enable_clocks(0);
1512}
1513
1514static int _dispc_setup_plane(enum omap_plane plane,
1515 u32 paddr, u16 screen_width,
1516 u16 pos_x, u16 pos_y,
1517 u16 width, u16 height,
1518 u16 out_width, u16 out_height,
1519 enum omap_color_mode color_mode,
1520 bool ilace,
1521 enum omap_dss_rotation_type rotation_type,
1522 u8 rotation, int mirror,
1523 u8 global_alpha)
1524{
1525 const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
1526 bool five_taps = 0;
1527 bool fieldmode = 0;
1528 int cconv = 0;
1529 unsigned offset0, offset1;
1530 s32 row_inc;
1531 s32 pix_inc;
1532 u16 frame_height = height;
1533 unsigned int field_offset = 0;
1534
1535 if (paddr == 0)
1536 return -EINVAL;
1537
1538 if (ilace && height == out_height)
1539 fieldmode = 1;
1540
1541 if (ilace) {
1542 if (fieldmode)
1543 height /= 2;
1544 pos_y /= 2;
1545 out_height /= 2;
1546
1547 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
1548 "out_height %d\n",
1549 height, pos_y, out_height);
1550 }
1551
1552 if (plane == OMAP_DSS_GFX) {
1553 if (width != out_width || height != out_height)
1554 return -EINVAL;
1555
1556 switch (color_mode) {
1557 case OMAP_DSS_COLOR_ARGB16:
1558 case OMAP_DSS_COLOR_ARGB32:
1559 case OMAP_DSS_COLOR_RGBA32:
1560 case OMAP_DSS_COLOR_RGBX32:
1561 if (cpu_is_omap24xx())
1562 return -EINVAL;
1563 /* fall through */
1564 case OMAP_DSS_COLOR_RGB12U:
1565 case OMAP_DSS_COLOR_RGB16:
1566 case OMAP_DSS_COLOR_RGB24P:
1567 case OMAP_DSS_COLOR_RGB24U:
1568 break;
1569
1570 default:
1571 return -EINVAL;
1572 }
1573 } else {
1574 /* video plane */
1575
1576 unsigned long fclk = 0;
1577
1578 if (out_width < width / maxdownscale ||
1579 out_width > width * 8)
1580 return -EINVAL;
1581
1582 if (out_height < height / maxdownscale ||
1583 out_height > height * 8)
1584 return -EINVAL;
1585
1586 switch (color_mode) {
1587 case OMAP_DSS_COLOR_RGBX32:
1588 case OMAP_DSS_COLOR_RGB12U:
1589 if (cpu_is_omap24xx())
1590 return -EINVAL;
1591 /* fall through */
1592 case OMAP_DSS_COLOR_RGB16:
1593 case OMAP_DSS_COLOR_RGB24P:
1594 case OMAP_DSS_COLOR_RGB24U:
1595 break;
1596
1597 case OMAP_DSS_COLOR_ARGB16:
1598 case OMAP_DSS_COLOR_ARGB32:
1599 case OMAP_DSS_COLOR_RGBA32:
1600 if (cpu_is_omap24xx())
1601 return -EINVAL;
1602 if (plane == OMAP_DSS_VIDEO1)
1603 return -EINVAL;
1604 break;
1605
1606 case OMAP_DSS_COLOR_YUV2:
1607 case OMAP_DSS_COLOR_UYVY:
1608 cconv = 1;
1609 break;
1610
1611 default:
1612 return -EINVAL;
1613 }
1614
1615 /* Must use 5-tap filter? */
1616 five_taps = height > out_height * 2;
1617
1618 if (!five_taps) {
1619 fclk = calc_fclk(width, height,
1620 out_width, out_height);
1621
1622 /* Try 5-tap filter if 3-tap fclk is too high */
1623 if (cpu_is_omap34xx() && height > out_height &&
1624 fclk > dispc_fclk_rate())
1625 five_taps = true;
1626 }
1627
1628 if (width > (2048 >> five_taps)) {
1629 DSSERR("failed to set up scaling, fclk too low\n");
1630 return -EINVAL;
1631 }
1632
1633 if (five_taps)
1634 fclk = calc_fclk_five_taps(width, height,
1635 out_width, out_height, color_mode);
1636
1637 DSSDBG("required fclk rate = %lu Hz\n", fclk);
1638 DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate());
1639
1640 if (!fclk || fclk > dispc_fclk_rate()) {
1641 DSSERR("failed to set up scaling, "
1642 "required fclk rate = %lu Hz, "
1643 "current fclk rate = %lu Hz\n",
1644 fclk, dispc_fclk_rate());
1645 return -EINVAL;
1646 }
1647 }
1648
1649 if (ilace && !fieldmode) {
1650 /*
1651 * when downscaling the bottom field may have to start several
1652 * source lines below the top field. Unfortunately ACCUI
1653 * registers will only hold the fractional part of the offset
1654 * so the integer part must be added to the base address of the
1655 * bottom field.
1656 */
1657 if (!height || height == out_height)
1658 field_offset = 0;
1659 else
1660 field_offset = height / out_height / 2;
1661 }
1662
1663 /* Fields are independent but interleaved in memory. */
1664 if (fieldmode)
1665 field_offset = 1;
1666
1667 if (rotation_type == OMAP_DSS_ROT_DMA)
1668 calc_dma_rotation_offset(rotation, mirror,
1669 screen_width, width, frame_height, color_mode,
1670 fieldmode, field_offset,
1671 &offset0, &offset1, &row_inc, &pix_inc);
1672 else
1673 calc_vrfb_rotation_offset(rotation, mirror,
1674 screen_width, width, frame_height, color_mode,
1675 fieldmode, field_offset,
1676 &offset0, &offset1, &row_inc, &pix_inc);
1677
1678 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
1679 offset0, offset1, row_inc, pix_inc);
1680
1681 _dispc_set_color_mode(plane, color_mode);
1682
1683 _dispc_set_plane_ba0(plane, paddr + offset0);
1684 _dispc_set_plane_ba1(plane, paddr + offset1);
1685
1686 _dispc_set_row_inc(plane, row_inc);
1687 _dispc_set_pix_inc(plane, pix_inc);
1688
1689 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height,
1690 out_width, out_height);
1691
1692 _dispc_set_plane_pos(plane, pos_x, pos_y);
1693
1694 _dispc_set_pic_size(plane, width, height);
1695
1696 if (plane != OMAP_DSS_GFX) {
1697 _dispc_set_scaling(plane, width, height,
1698 out_width, out_height,
1699 ilace, five_taps, fieldmode);
1700 _dispc_set_vid_size(plane, out_width, out_height);
1701 _dispc_set_vid_color_conv(plane, cconv);
1702 }
1703
1704 _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode);
1705
1706 if (plane != OMAP_DSS_VIDEO1)
1707 _dispc_setup_global_alpha(plane, global_alpha);
1708
1709 return 0;
1710}
1711
1712static void _dispc_enable_plane(enum omap_plane plane, bool enable)
1713{
1714 REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 0, 0);
1715}
1716
1717static void dispc_disable_isr(void *data, u32 mask)
1718{
1719 struct completion *compl = data;
1720 complete(compl);
1721}
1722
1723static void _enable_lcd_out(bool enable)
1724{
1725 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0);
1726}
1727
1728void dispc_enable_lcd_out(bool enable)
1729{
1730 struct completion frame_done_completion;
1731 bool is_on;
1732 int r;
1733
1734 enable_clocks(1);
1735
1736 /* When we disable LCD output, we need to wait until frame is done.
1737 * Otherwise the DSS is still working, and turning off the clocks
1738 * prevents DSS from going to OFF mode */
1739 is_on = REG_GET(DISPC_CONTROL, 0, 0);
1740
1741 if (!enable && is_on) {
1742 init_completion(&frame_done_completion);
1743
1744 r = omap_dispc_register_isr(dispc_disable_isr,
1745 &frame_done_completion,
1746 DISPC_IRQ_FRAMEDONE);
1747
1748 if (r)
1749 DSSERR("failed to register FRAMEDONE isr\n");
1750 }
1751
1752 _enable_lcd_out(enable);
1753
1754 if (!enable && is_on) {
1755 if (!wait_for_completion_timeout(&frame_done_completion,
1756 msecs_to_jiffies(100)))
1757 DSSERR("timeout waiting for FRAME DONE\n");
1758
1759 r = omap_dispc_unregister_isr(dispc_disable_isr,
1760 &frame_done_completion,
1761 DISPC_IRQ_FRAMEDONE);
1762
1763 if (r)
1764 DSSERR("failed to unregister FRAMEDONE isr\n");
1765 }
1766
1767 enable_clocks(0);
1768}
1769
1770static void _enable_digit_out(bool enable)
1771{
1772 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1);
1773}
1774
1775void dispc_enable_digit_out(bool enable)
1776{
1777 struct completion frame_done_completion;
1778 int r;
1779
1780 enable_clocks(1);
1781
1782 if (REG_GET(DISPC_CONTROL, 1, 1) == enable) {
1783 enable_clocks(0);
1784 return;
1785 }
1786
1787 if (enable) {
1788 unsigned long flags;
1789 /* When we enable digit output, we'll get an extra digit
1790 * sync lost interrupt, that we need to ignore */
1791 spin_lock_irqsave(&dispc.irq_lock, flags);
1792 dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
1793 _omap_dispc_set_irqs();
1794 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1795 }
1796
1797 /* When we disable digit output, we need to wait until fields are done.
1798 * Otherwise the DSS is still working, and turning off the clocks
1799 * prevents DSS from going to OFF mode. And when enabling, we need to
1800 * wait for the extra sync losts */
1801 init_completion(&frame_done_completion);
1802
1803 r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion,
1804 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1805 if (r)
1806 DSSERR("failed to register EVSYNC isr\n");
1807
1808 _enable_digit_out(enable);
1809
1810 /* XXX I understand from TRM that we should only wait for the
1811 * current field to complete. But it seems we have to wait
1812 * for both fields */
1813 if (!wait_for_completion_timeout(&frame_done_completion,
1814 msecs_to_jiffies(100)))
1815 DSSERR("timeout waiting for EVSYNC\n");
1816
1817 if (!wait_for_completion_timeout(&frame_done_completion,
1818 msecs_to_jiffies(100)))
1819 DSSERR("timeout waiting for EVSYNC\n");
1820
1821 r = omap_dispc_unregister_isr(dispc_disable_isr,
1822 &frame_done_completion,
1823 DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD);
1824 if (r)
1825 DSSERR("failed to unregister EVSYNC isr\n");
1826
1827 if (enable) {
1828 unsigned long flags;
1829 spin_lock_irqsave(&dispc.irq_lock, flags);
1830 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
1831 dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT);
1832 _omap_dispc_set_irqs();
1833 spin_unlock_irqrestore(&dispc.irq_lock, flags);
1834 }
1835
1836 enable_clocks(0);
1837}
1838
1839void dispc_lcd_enable_signal_polarity(bool act_high)
1840{
1841 enable_clocks(1);
1842 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
1843 enable_clocks(0);
1844}
1845
1846void dispc_lcd_enable_signal(bool enable)
1847{
1848 enable_clocks(1);
1849 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
1850 enable_clocks(0);
1851}
1852
1853void dispc_pck_free_enable(bool enable)
1854{
1855 enable_clocks(1);
1856 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
1857 enable_clocks(0);
1858}
1859
1860void dispc_enable_fifohandcheck(bool enable)
1861{
1862 enable_clocks(1);
1863 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16);
1864 enable_clocks(0);
1865}
1866
1867
1868void dispc_set_lcd_display_type(enum omap_lcd_display_type type)
1869{
1870 int mode;
1871
1872 switch (type) {
1873 case OMAP_DSS_LCD_DISPLAY_STN:
1874 mode = 0;
1875 break;
1876
1877 case OMAP_DSS_LCD_DISPLAY_TFT:
1878 mode = 1;
1879 break;
1880
1881 default:
1882 BUG();
1883 return;
1884 }
1885
1886 enable_clocks(1);
1887 REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3);
1888 enable_clocks(0);
1889}
1890
1891void dispc_set_loadmode(enum omap_dss_load_mode mode)
1892{
1893 enable_clocks(1);
1894 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
1895 enable_clocks(0);
1896}
1897
1898
1899void dispc_set_default_color(enum omap_channel channel, u32 color)
1900{
1901 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1902 DISPC_DEFAULT_COLOR1 };
1903
1904 enable_clocks(1);
1905 dispc_write_reg(def_reg[channel], color);
1906 enable_clocks(0);
1907}
1908
1909u32 dispc_get_default_color(enum omap_channel channel)
1910{
1911 const struct dispc_reg def_reg[] = { DISPC_DEFAULT_COLOR0,
1912 DISPC_DEFAULT_COLOR1 };
1913 u32 l;
1914
1915 BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT &&
1916 channel != OMAP_DSS_CHANNEL_LCD);
1917
1918 enable_clocks(1);
1919 l = dispc_read_reg(def_reg[channel]);
1920 enable_clocks(0);
1921
1922 return l;
1923}
1924
1925void dispc_set_trans_key(enum omap_channel ch,
1926 enum omap_dss_trans_key_type type,
1927 u32 trans_key)
1928{
1929 const struct dispc_reg tr_reg[] = {
1930 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1931
1932 enable_clocks(1);
1933 if (ch == OMAP_DSS_CHANNEL_LCD)
1934 REG_FLD_MOD(DISPC_CONFIG, type, 11, 11);
1935 else /* OMAP_DSS_CHANNEL_DIGIT */
1936 REG_FLD_MOD(DISPC_CONFIG, type, 13, 13);
1937
1938 dispc_write_reg(tr_reg[ch], trans_key);
1939 enable_clocks(0);
1940}
1941
1942void dispc_get_trans_key(enum omap_channel ch,
1943 enum omap_dss_trans_key_type *type,
1944 u32 *trans_key)
1945{
1946 const struct dispc_reg tr_reg[] = {
1947 DISPC_TRANS_COLOR0, DISPC_TRANS_COLOR1 };
1948
1949 enable_clocks(1);
1950 if (type) {
1951 if (ch == OMAP_DSS_CHANNEL_LCD)
1952 *type = REG_GET(DISPC_CONFIG, 11, 11);
1953 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1954 *type = REG_GET(DISPC_CONFIG, 13, 13);
1955 else
1956 BUG();
1957 }
1958
1959 if (trans_key)
1960 *trans_key = dispc_read_reg(tr_reg[ch]);
1961 enable_clocks(0);
1962}
1963
1964void dispc_enable_trans_key(enum omap_channel ch, bool enable)
1965{
1966 enable_clocks(1);
1967 if (ch == OMAP_DSS_CHANNEL_LCD)
1968 REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10);
1969 else /* OMAP_DSS_CHANNEL_DIGIT */
1970 REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12);
1971 enable_clocks(0);
1972}
1973void dispc_enable_alpha_blending(enum omap_channel ch, bool enable)
1974{
1975 if (cpu_is_omap24xx())
1976 return;
1977
1978 enable_clocks(1);
1979 if (ch == OMAP_DSS_CHANNEL_LCD)
1980 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
1981 else /* OMAP_DSS_CHANNEL_DIGIT */
1982 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
1983 enable_clocks(0);
1984}
1985bool dispc_alpha_blending_enabled(enum omap_channel ch)
1986{
1987 bool enabled;
1988
1989 if (cpu_is_omap24xx())
1990 return false;
1991
1992 enable_clocks(1);
1993 if (ch == OMAP_DSS_CHANNEL_LCD)
1994 enabled = REG_GET(DISPC_CONFIG, 18, 18);
1995 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
1996 enabled = REG_GET(DISPC_CONFIG, 18, 18);
1997 else
1998 BUG();
1999 enable_clocks(0);
2000
2001 return enabled;
2002
2003}
2004
2005
2006bool dispc_trans_key_enabled(enum omap_channel ch)
2007{
2008 bool enabled;
2009
2010 enable_clocks(1);
2011 if (ch == OMAP_DSS_CHANNEL_LCD)
2012 enabled = REG_GET(DISPC_CONFIG, 10, 10);
2013 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
2014 enabled = REG_GET(DISPC_CONFIG, 12, 12);
2015 else
2016 BUG();
2017 enable_clocks(0);
2018
2019 return enabled;
2020}
2021
2022
2023void dispc_set_tft_data_lines(u8 data_lines)
2024{
2025 int code;
2026
2027 switch (data_lines) {
2028 case 12:
2029 code = 0;
2030 break;
2031 case 16:
2032 code = 1;
2033 break;
2034 case 18:
2035 code = 2;
2036 break;
2037 case 24:
2038 code = 3;
2039 break;
2040 default:
2041 BUG();
2042 return;
2043 }
2044
2045 enable_clocks(1);
2046 REG_FLD_MOD(DISPC_CONTROL, code, 9, 8);
2047 enable_clocks(0);
2048}
2049
2050void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode)
2051{
2052 u32 l;
2053 int stallmode;
2054 int gpout0 = 1;
2055 int gpout1;
2056
2057 switch (mode) {
2058 case OMAP_DSS_PARALLELMODE_BYPASS:
2059 stallmode = 0;
2060 gpout1 = 1;
2061 break;
2062
2063 case OMAP_DSS_PARALLELMODE_RFBI:
2064 stallmode = 1;
2065 gpout1 = 0;
2066 break;
2067
2068 case OMAP_DSS_PARALLELMODE_DSI:
2069 stallmode = 1;
2070 gpout1 = 1;
2071 break;
2072
2073 default:
2074 BUG();
2075 return;
2076 }
2077
2078 enable_clocks(1);
2079
2080 l = dispc_read_reg(DISPC_CONTROL);
2081
2082 l = FLD_MOD(l, stallmode, 11, 11);
2083 l = FLD_MOD(l, gpout0, 15, 15);
2084 l = FLD_MOD(l, gpout1, 16, 16);
2085
2086 dispc_write_reg(DISPC_CONTROL, l);
2087
2088 enable_clocks(0);
2089}
2090
2091static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp,
2092 int vsw, int vfp, int vbp)
2093{
2094 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2095 if (hsw < 1 || hsw > 64 ||
2096 hfp < 1 || hfp > 256 ||
2097 hbp < 1 || hbp > 256 ||
2098 vsw < 1 || vsw > 64 ||
2099 vfp < 0 || vfp > 255 ||
2100 vbp < 0 || vbp > 255)
2101 return false;
2102 } else {
2103 if (hsw < 1 || hsw > 256 ||
2104 hfp < 1 || hfp > 4096 ||
2105 hbp < 1 || hbp > 4096 ||
2106 vsw < 1 || vsw > 256 ||
2107 vfp < 0 || vfp > 4095 ||
2108 vbp < 0 || vbp > 4095)
2109 return false;
2110 }
2111
2112 return true;
2113}
2114
2115bool dispc_lcd_timings_ok(struct omap_video_timings *timings)
2116{
2117 return _dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2118 timings->hbp, timings->vsw,
2119 timings->vfp, timings->vbp);
2120}
2121
2122static void _dispc_set_lcd_timings(int hsw, int hfp, int hbp,
2123 int vsw, int vfp, int vbp)
2124{
2125 u32 timing_h, timing_v;
2126
2127 if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) {
2128 timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) |
2129 FLD_VAL(hbp-1, 27, 20);
2130
2131 timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) |
2132 FLD_VAL(vbp, 27, 20);
2133 } else {
2134 timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) |
2135 FLD_VAL(hbp-1, 31, 20);
2136
2137 timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) |
2138 FLD_VAL(vbp, 31, 20);
2139 }
2140
2141 enable_clocks(1);
2142 dispc_write_reg(DISPC_TIMING_H, timing_h);
2143 dispc_write_reg(DISPC_TIMING_V, timing_v);
2144 enable_clocks(0);
2145}
2146
2147/* change name to mode? */
2148void dispc_set_lcd_timings(struct omap_video_timings *timings)
2149{
2150 unsigned xtot, ytot;
2151 unsigned long ht, vt;
2152
2153 if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp,
2154 timings->hbp, timings->vsw,
2155 timings->vfp, timings->vbp))
2156 BUG();
2157
2158 _dispc_set_lcd_timings(timings->hsw, timings->hfp, timings->hbp,
2159 timings->vsw, timings->vfp, timings->vbp);
2160
2161 dispc_set_lcd_size(timings->x_res, timings->y_res);
2162
2163 xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp;
2164 ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp;
2165
2166 ht = (timings->pixel_clock * 1000) / xtot;
2167 vt = (timings->pixel_clock * 1000) / xtot / ytot;
2168
2169 DSSDBG("xres %u yres %u\n", timings->x_res, timings->y_res);
2170 DSSDBG("pck %u\n", timings->pixel_clock);
2171 DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
2172 timings->hsw, timings->hfp, timings->hbp,
2173 timings->vsw, timings->vfp, timings->vbp);
2174
2175 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
2176}
2177
2178static void dispc_set_lcd_divisor(u16 lck_div, u16 pck_div)
2179{
2180 BUG_ON(lck_div < 1);
2181 BUG_ON(pck_div < 2);
2182
2183 enable_clocks(1);
2184 dispc_write_reg(DISPC_DIVISOR,
2185 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
2186 enable_clocks(0);
2187}
2188
2189static void dispc_get_lcd_divisor(int *lck_div, int *pck_div)
2190{
2191 u32 l;
2192 l = dispc_read_reg(DISPC_DIVISOR);
2193 *lck_div = FLD_GET(l, 23, 16);
2194 *pck_div = FLD_GET(l, 7, 0);
2195}
2196
2197unsigned long dispc_fclk_rate(void)
2198{
2199 unsigned long r = 0;
2200
2201 if (dss_get_dispc_clk_source() == 0)
2202 r = dss_clk_get_rate(DSS_CLK_FCK1);
2203 else
2204#ifdef CONFIG_OMAP2_DSS_DSI
2205 r = dsi_get_dsi1_pll_rate();
2206#else
2207 BUG();
2208#endif
2209 return r;
2210}
2211
2212unsigned long dispc_lclk_rate(void)
2213{
2214 int lcd;
2215 unsigned long r;
2216 u32 l;
2217
2218 l = dispc_read_reg(DISPC_DIVISOR);
2219
2220 lcd = FLD_GET(l, 23, 16);
2221
2222 r = dispc_fclk_rate();
2223
2224 return r / lcd;
2225}
2226
2227unsigned long dispc_pclk_rate(void)
2228{
2229 int lcd, pcd;
2230 unsigned long r;
2231 u32 l;
2232
2233 l = dispc_read_reg(DISPC_DIVISOR);
2234
2235 lcd = FLD_GET(l, 23, 16);
2236 pcd = FLD_GET(l, 7, 0);
2237
2238 r = dispc_fclk_rate();
2239
2240 return r / lcd / pcd;
2241}
2242
2243void dispc_dump_clocks(struct seq_file *s)
2244{
2245 int lcd, pcd;
2246
2247 enable_clocks(1);
2248
2249 dispc_get_lcd_divisor(&lcd, &pcd);
2250
2251 seq_printf(s, "- DISPC -\n");
2252
2253 seq_printf(s, "dispc fclk source = %s\n",
2254 dss_get_dispc_clk_source() == 0 ?
2255 "dss1_alwon_fclk" : "dsi1_pll_fclk");
2256
2257 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
2258 seq_printf(s, "lck\t\t%-16lulck div\t%u\n", dispc_lclk_rate(), lcd);
2259 seq_printf(s, "pck\t\t%-16lupck div\t%u\n", dispc_pclk_rate(), pcd);
2260
2261 enable_clocks(0);
2262}
2263
2264#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2265void dispc_dump_irqs(struct seq_file *s)
2266{
2267 unsigned long flags;
2268 struct dispc_irq_stats stats;
2269
2270 spin_lock_irqsave(&dispc.irq_stats_lock, flags);
2271
2272 stats = dispc.irq_stats;
2273 memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats));
2274 dispc.irq_stats.last_reset = jiffies;
2275
2276 spin_unlock_irqrestore(&dispc.irq_stats_lock, flags);
2277
2278 seq_printf(s, "period %u ms\n",
2279 jiffies_to_msecs(jiffies - stats.last_reset));
2280
2281 seq_printf(s, "irqs %d\n", stats.irq_count);
2282#define PIS(x) \
2283 seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]);
2284
2285 PIS(FRAMEDONE);
2286 PIS(VSYNC);
2287 PIS(EVSYNC_EVEN);
2288 PIS(EVSYNC_ODD);
2289 PIS(ACBIAS_COUNT_STAT);
2290 PIS(PROG_LINE_NUM);
2291 PIS(GFX_FIFO_UNDERFLOW);
2292 PIS(GFX_END_WIN);
2293 PIS(PAL_GAMMA_MASK);
2294 PIS(OCP_ERR);
2295 PIS(VID1_FIFO_UNDERFLOW);
2296 PIS(VID1_END_WIN);
2297 PIS(VID2_FIFO_UNDERFLOW);
2298 PIS(VID2_END_WIN);
2299 PIS(SYNC_LOST);
2300 PIS(SYNC_LOST_DIGIT);
2301 PIS(WAKEUP);
2302#undef PIS
2303}
2304#else
2305void dispc_dump_irqs(struct seq_file *s) { }
2306#endif
2307
2308void dispc_dump_regs(struct seq_file *s)
2309{
2310#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dispc_read_reg(r))
2311
2312 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
2313
2314 DUMPREG(DISPC_REVISION);
2315 DUMPREG(DISPC_SYSCONFIG);
2316 DUMPREG(DISPC_SYSSTATUS);
2317 DUMPREG(DISPC_IRQSTATUS);
2318 DUMPREG(DISPC_IRQENABLE);
2319 DUMPREG(DISPC_CONTROL);
2320 DUMPREG(DISPC_CONFIG);
2321 DUMPREG(DISPC_CAPABLE);
2322 DUMPREG(DISPC_DEFAULT_COLOR0);
2323 DUMPREG(DISPC_DEFAULT_COLOR1);
2324 DUMPREG(DISPC_TRANS_COLOR0);
2325 DUMPREG(DISPC_TRANS_COLOR1);
2326 DUMPREG(DISPC_LINE_STATUS);
2327 DUMPREG(DISPC_LINE_NUMBER);
2328 DUMPREG(DISPC_TIMING_H);
2329 DUMPREG(DISPC_TIMING_V);
2330 DUMPREG(DISPC_POL_FREQ);
2331 DUMPREG(DISPC_DIVISOR);
2332 DUMPREG(DISPC_GLOBAL_ALPHA);
2333 DUMPREG(DISPC_SIZE_DIG);
2334 DUMPREG(DISPC_SIZE_LCD);
2335
2336 DUMPREG(DISPC_GFX_BA0);
2337 DUMPREG(DISPC_GFX_BA1);
2338 DUMPREG(DISPC_GFX_POSITION);
2339 DUMPREG(DISPC_GFX_SIZE);
2340 DUMPREG(DISPC_GFX_ATTRIBUTES);
2341 DUMPREG(DISPC_GFX_FIFO_THRESHOLD);
2342 DUMPREG(DISPC_GFX_FIFO_SIZE_STATUS);
2343 DUMPREG(DISPC_GFX_ROW_INC);
2344 DUMPREG(DISPC_GFX_PIXEL_INC);
2345 DUMPREG(DISPC_GFX_WINDOW_SKIP);
2346 DUMPREG(DISPC_GFX_TABLE_BA);
2347
2348 DUMPREG(DISPC_DATA_CYCLE1);
2349 DUMPREG(DISPC_DATA_CYCLE2);
2350 DUMPREG(DISPC_DATA_CYCLE3);
2351
2352 DUMPREG(DISPC_CPR_COEF_R);
2353 DUMPREG(DISPC_CPR_COEF_G);
2354 DUMPREG(DISPC_CPR_COEF_B);
2355
2356 DUMPREG(DISPC_GFX_PRELOAD);
2357
2358 DUMPREG(DISPC_VID_BA0(0));
2359 DUMPREG(DISPC_VID_BA1(0));
2360 DUMPREG(DISPC_VID_POSITION(0));
2361 DUMPREG(DISPC_VID_SIZE(0));
2362 DUMPREG(DISPC_VID_ATTRIBUTES(0));
2363 DUMPREG(DISPC_VID_FIFO_THRESHOLD(0));
2364 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(0));
2365 DUMPREG(DISPC_VID_ROW_INC(0));
2366 DUMPREG(DISPC_VID_PIXEL_INC(0));
2367 DUMPREG(DISPC_VID_FIR(0));
2368 DUMPREG(DISPC_VID_PICTURE_SIZE(0));
2369 DUMPREG(DISPC_VID_ACCU0(0));
2370 DUMPREG(DISPC_VID_ACCU1(0));
2371
2372 DUMPREG(DISPC_VID_BA0(1));
2373 DUMPREG(DISPC_VID_BA1(1));
2374 DUMPREG(DISPC_VID_POSITION(1));
2375 DUMPREG(DISPC_VID_SIZE(1));
2376 DUMPREG(DISPC_VID_ATTRIBUTES(1));
2377 DUMPREG(DISPC_VID_FIFO_THRESHOLD(1));
2378 DUMPREG(DISPC_VID_FIFO_SIZE_STATUS(1));
2379 DUMPREG(DISPC_VID_ROW_INC(1));
2380 DUMPREG(DISPC_VID_PIXEL_INC(1));
2381 DUMPREG(DISPC_VID_FIR(1));
2382 DUMPREG(DISPC_VID_PICTURE_SIZE(1));
2383 DUMPREG(DISPC_VID_ACCU0(1));
2384 DUMPREG(DISPC_VID_ACCU1(1));
2385
2386 DUMPREG(DISPC_VID_FIR_COEF_H(0, 0));
2387 DUMPREG(DISPC_VID_FIR_COEF_H(0, 1));
2388 DUMPREG(DISPC_VID_FIR_COEF_H(0, 2));
2389 DUMPREG(DISPC_VID_FIR_COEF_H(0, 3));
2390 DUMPREG(DISPC_VID_FIR_COEF_H(0, 4));
2391 DUMPREG(DISPC_VID_FIR_COEF_H(0, 5));
2392 DUMPREG(DISPC_VID_FIR_COEF_H(0, 6));
2393 DUMPREG(DISPC_VID_FIR_COEF_H(0, 7));
2394 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 0));
2395 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 1));
2396 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 2));
2397 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 3));
2398 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 4));
2399 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 5));
2400 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 6));
2401 DUMPREG(DISPC_VID_FIR_COEF_HV(0, 7));
2402 DUMPREG(DISPC_VID_CONV_COEF(0, 0));
2403 DUMPREG(DISPC_VID_CONV_COEF(0, 1));
2404 DUMPREG(DISPC_VID_CONV_COEF(0, 2));
2405 DUMPREG(DISPC_VID_CONV_COEF(0, 3));
2406 DUMPREG(DISPC_VID_CONV_COEF(0, 4));
2407 DUMPREG(DISPC_VID_FIR_COEF_V(0, 0));
2408 DUMPREG(DISPC_VID_FIR_COEF_V(0, 1));
2409 DUMPREG(DISPC_VID_FIR_COEF_V(0, 2));
2410 DUMPREG(DISPC_VID_FIR_COEF_V(0, 3));
2411 DUMPREG(DISPC_VID_FIR_COEF_V(0, 4));
2412 DUMPREG(DISPC_VID_FIR_COEF_V(0, 5));
2413 DUMPREG(DISPC_VID_FIR_COEF_V(0, 6));
2414 DUMPREG(DISPC_VID_FIR_COEF_V(0, 7));
2415
2416 DUMPREG(DISPC_VID_FIR_COEF_H(1, 0));
2417 DUMPREG(DISPC_VID_FIR_COEF_H(1, 1));
2418 DUMPREG(DISPC_VID_FIR_COEF_H(1, 2));
2419 DUMPREG(DISPC_VID_FIR_COEF_H(1, 3));
2420 DUMPREG(DISPC_VID_FIR_COEF_H(1, 4));
2421 DUMPREG(DISPC_VID_FIR_COEF_H(1, 5));
2422 DUMPREG(DISPC_VID_FIR_COEF_H(1, 6));
2423 DUMPREG(DISPC_VID_FIR_COEF_H(1, 7));
2424 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 0));
2425 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 1));
2426 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 2));
2427 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 3));
2428 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 4));
2429 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 5));
2430 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 6));
2431 DUMPREG(DISPC_VID_FIR_COEF_HV(1, 7));
2432 DUMPREG(DISPC_VID_CONV_COEF(1, 0));
2433 DUMPREG(DISPC_VID_CONV_COEF(1, 1));
2434 DUMPREG(DISPC_VID_CONV_COEF(1, 2));
2435 DUMPREG(DISPC_VID_CONV_COEF(1, 3));
2436 DUMPREG(DISPC_VID_CONV_COEF(1, 4));
2437 DUMPREG(DISPC_VID_FIR_COEF_V(1, 0));
2438 DUMPREG(DISPC_VID_FIR_COEF_V(1, 1));
2439 DUMPREG(DISPC_VID_FIR_COEF_V(1, 2));
2440 DUMPREG(DISPC_VID_FIR_COEF_V(1, 3));
2441 DUMPREG(DISPC_VID_FIR_COEF_V(1, 4));
2442 DUMPREG(DISPC_VID_FIR_COEF_V(1, 5));
2443 DUMPREG(DISPC_VID_FIR_COEF_V(1, 6));
2444 DUMPREG(DISPC_VID_FIR_COEF_V(1, 7));
2445
2446 DUMPREG(DISPC_VID_PRELOAD(0));
2447 DUMPREG(DISPC_VID_PRELOAD(1));
2448
2449 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
2450#undef DUMPREG
2451}
2452
2453static void _dispc_set_pol_freq(bool onoff, bool rf, bool ieo, bool ipc,
2454 bool ihs, bool ivs, u8 acbi, u8 acb)
2455{
2456 u32 l = 0;
2457
2458 DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
2459 onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
2460
2461 l |= FLD_VAL(onoff, 17, 17);
2462 l |= FLD_VAL(rf, 16, 16);
2463 l |= FLD_VAL(ieo, 15, 15);
2464 l |= FLD_VAL(ipc, 14, 14);
2465 l |= FLD_VAL(ihs, 13, 13);
2466 l |= FLD_VAL(ivs, 12, 12);
2467 l |= FLD_VAL(acbi, 11, 8);
2468 l |= FLD_VAL(acb, 7, 0);
2469
2470 enable_clocks(1);
2471 dispc_write_reg(DISPC_POL_FREQ, l);
2472 enable_clocks(0);
2473}
2474
2475void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb)
2476{
2477 _dispc_set_pol_freq((config & OMAP_DSS_LCD_ONOFF) != 0,
2478 (config & OMAP_DSS_LCD_RF) != 0,
2479 (config & OMAP_DSS_LCD_IEO) != 0,
2480 (config & OMAP_DSS_LCD_IPC) != 0,
2481 (config & OMAP_DSS_LCD_IHS) != 0,
2482 (config & OMAP_DSS_LCD_IVS) != 0,
2483 acbi, acb);
2484}
2485
2486/* with fck as input clock rate, find dispc dividers that produce req_pck */
2487void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
2488 struct dispc_clock_info *cinfo)
2489{
2490 u16 pcd_min = is_tft ? 2 : 3;
2491 unsigned long best_pck;
2492 u16 best_ld, cur_ld;
2493 u16 best_pd, cur_pd;
2494
2495 best_pck = 0;
2496 best_ld = 0;
2497 best_pd = 0;
2498
2499 for (cur_ld = 1; cur_ld <= 255; ++cur_ld) {
2500 unsigned long lck = fck / cur_ld;
2501
2502 for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) {
2503 unsigned long pck = lck / cur_pd;
2504 long old_delta = abs(best_pck - req_pck);
2505 long new_delta = abs(pck - req_pck);
2506
2507 if (best_pck == 0 || new_delta < old_delta) {
2508 best_pck = pck;
2509 best_ld = cur_ld;
2510 best_pd = cur_pd;
2511
2512 if (pck == req_pck)
2513 goto found;
2514 }
2515
2516 if (pck < req_pck)
2517 break;
2518 }
2519
2520 if (lck / pcd_min < req_pck)
2521 break;
2522 }
2523
2524found:
2525 cinfo->lck_div = best_ld;
2526 cinfo->pck_div = best_pd;
2527 cinfo->lck = fck / cinfo->lck_div;
2528 cinfo->pck = cinfo->lck / cinfo->pck_div;
2529}
2530
2531/* calculate clock rates using dividers in cinfo */
2532int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
2533 struct dispc_clock_info *cinfo)
2534{
2535 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
2536 return -EINVAL;
2537 if (cinfo->pck_div < 2 || cinfo->pck_div > 255)
2538 return -EINVAL;
2539
2540 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
2541 cinfo->pck = cinfo->lck / cinfo->pck_div;
2542
2543 return 0;
2544}
2545
2546int dispc_set_clock_div(struct dispc_clock_info *cinfo)
2547{
2548 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
2549 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
2550
2551 dispc_set_lcd_divisor(cinfo->lck_div, cinfo->pck_div);
2552
2553 return 0;
2554}
2555
2556int dispc_get_clock_div(struct dispc_clock_info *cinfo)
2557{
2558 unsigned long fck;
2559
2560 fck = dispc_fclk_rate();
2561
2562 cinfo->lck_div = REG_GET(DISPC_DIVISOR, 23, 16);
2563 cinfo->pck_div = REG_GET(DISPC_DIVISOR, 7, 0);
2564
2565 cinfo->lck = fck / cinfo->lck_div;
2566 cinfo->pck = cinfo->lck / cinfo->pck_div;
2567
2568 return 0;
2569}
2570
2571/* dispc.irq_lock has to be locked by the caller */
2572static void _omap_dispc_set_irqs(void)
2573{
2574 u32 mask;
2575 u32 old_mask;
2576 int i;
2577 struct omap_dispc_isr_data *isr_data;
2578
2579 mask = dispc.irq_error_mask;
2580
2581 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2582 isr_data = &dispc.registered_isr[i];
2583
2584 if (isr_data->isr == NULL)
2585 continue;
2586
2587 mask |= isr_data->mask;
2588 }
2589
2590 enable_clocks(1);
2591
2592 old_mask = dispc_read_reg(DISPC_IRQENABLE);
2593 /* clear the irqstatus for newly enabled irqs */
2594 dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask);
2595
2596 dispc_write_reg(DISPC_IRQENABLE, mask);
2597
2598 enable_clocks(0);
2599}
2600
2601int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2602{
2603 int i;
2604 int ret;
2605 unsigned long flags;
2606 struct omap_dispc_isr_data *isr_data;
2607
2608 if (isr == NULL)
2609 return -EINVAL;
2610
2611 spin_lock_irqsave(&dispc.irq_lock, flags);
2612
2613 /* check for duplicate entry */
2614 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2615 isr_data = &dispc.registered_isr[i];
2616 if (isr_data->isr == isr && isr_data->arg == arg &&
2617 isr_data->mask == mask) {
2618 ret = -EINVAL;
2619 goto err;
2620 }
2621 }
2622
2623 isr_data = NULL;
2624 ret = -EBUSY;
2625
2626 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2627 isr_data = &dispc.registered_isr[i];
2628
2629 if (isr_data->isr != NULL)
2630 continue;
2631
2632 isr_data->isr = isr;
2633 isr_data->arg = arg;
2634 isr_data->mask = mask;
2635 ret = 0;
2636
2637 break;
2638 }
2639
2640 _omap_dispc_set_irqs();
2641
2642 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2643
2644 return 0;
2645err:
2646 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2647
2648 return ret;
2649}
2650EXPORT_SYMBOL(omap_dispc_register_isr);
2651
2652int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask)
2653{
2654 int i;
2655 unsigned long flags;
2656 int ret = -EINVAL;
2657 struct omap_dispc_isr_data *isr_data;
2658
2659 spin_lock_irqsave(&dispc.irq_lock, flags);
2660
2661 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2662 isr_data = &dispc.registered_isr[i];
2663 if (isr_data->isr != isr || isr_data->arg != arg ||
2664 isr_data->mask != mask)
2665 continue;
2666
2667 /* found the correct isr */
2668
2669 isr_data->isr = NULL;
2670 isr_data->arg = NULL;
2671 isr_data->mask = 0;
2672
2673 ret = 0;
2674 break;
2675 }
2676
2677 if (ret == 0)
2678 _omap_dispc_set_irqs();
2679
2680 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2681
2682 return ret;
2683}
2684EXPORT_SYMBOL(omap_dispc_unregister_isr);
2685
2686#ifdef DEBUG
2687static void print_irq_status(u32 status)
2688{
2689 if ((status & dispc.irq_error_mask) == 0)
2690 return;
2691
2692 printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status);
2693
2694#define PIS(x) \
2695 if (status & DISPC_IRQ_##x) \
2696 printk(#x " ");
2697 PIS(GFX_FIFO_UNDERFLOW);
2698 PIS(OCP_ERR);
2699 PIS(VID1_FIFO_UNDERFLOW);
2700 PIS(VID2_FIFO_UNDERFLOW);
2701 PIS(SYNC_LOST);
2702 PIS(SYNC_LOST_DIGIT);
2703#undef PIS
2704
2705 printk("\n");
2706}
2707#endif
2708
2709/* Called from dss.c. Note that we don't touch clocks here,
2710 * but we presume they are on because we got an IRQ. However,
2711 * an irq handler may turn the clocks off, so we may not have
2712 * clock later in the function. */
2713void dispc_irq_handler(void)
2714{
2715 int i;
2716 u32 irqstatus;
2717 u32 handledirqs = 0;
2718 u32 unhandled_errors;
2719 struct omap_dispc_isr_data *isr_data;
2720 struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
2721
2722 spin_lock(&dispc.irq_lock);
2723
2724 irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
2725
2726#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2727 spin_lock(&dispc.irq_stats_lock);
2728 dispc.irq_stats.irq_count++;
2729 dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs);
2730 spin_unlock(&dispc.irq_stats_lock);
2731#endif
2732
2733#ifdef DEBUG
2734 if (dss_debug)
2735 print_irq_status(irqstatus);
2736#endif
2737 /* Ack the interrupt. Do it here before clocks are possibly turned
2738 * off */
2739 dispc_write_reg(DISPC_IRQSTATUS, irqstatus);
2740 /* flush posted write */
2741 dispc_read_reg(DISPC_IRQSTATUS);
2742
2743 /* make a copy and unlock, so that isrs can unregister
2744 * themselves */
2745 memcpy(registered_isr, dispc.registered_isr,
2746 sizeof(registered_isr));
2747
2748 spin_unlock(&dispc.irq_lock);
2749
2750 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
2751 isr_data = &registered_isr[i];
2752
2753 if (!isr_data->isr)
2754 continue;
2755
2756 if (isr_data->mask & irqstatus) {
2757 isr_data->isr(isr_data->arg, irqstatus);
2758 handledirqs |= isr_data->mask;
2759 }
2760 }
2761
2762 spin_lock(&dispc.irq_lock);
2763
2764 unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask;
2765
2766 if (unhandled_errors) {
2767 dispc.error_irqs |= unhandled_errors;
2768
2769 dispc.irq_error_mask &= ~unhandled_errors;
2770 _omap_dispc_set_irqs();
2771
2772 schedule_work(&dispc.error_work);
2773 }
2774
2775 spin_unlock(&dispc.irq_lock);
2776}
2777
2778static void dispc_error_worker(struct work_struct *work)
2779{
2780 int i;
2781 u32 errors;
2782 unsigned long flags;
2783
2784 spin_lock_irqsave(&dispc.irq_lock, flags);
2785 errors = dispc.error_irqs;
2786 dispc.error_irqs = 0;
2787 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2788
2789 if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) {
2790 DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n");
2791 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2792 struct omap_overlay *ovl;
2793 ovl = omap_dss_get_overlay(i);
2794
2795 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2796 continue;
2797
2798 if (ovl->id == 0) {
2799 dispc_enable_plane(ovl->id, 0);
2800 dispc_go(ovl->manager->id);
2801 mdelay(50);
2802 break;
2803 }
2804 }
2805 }
2806
2807 if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) {
2808 DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n");
2809 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2810 struct omap_overlay *ovl;
2811 ovl = omap_dss_get_overlay(i);
2812
2813 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2814 continue;
2815
2816 if (ovl->id == 1) {
2817 dispc_enable_plane(ovl->id, 0);
2818 dispc_go(ovl->manager->id);
2819 mdelay(50);
2820 break;
2821 }
2822 }
2823 }
2824
2825 if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) {
2826 DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n");
2827 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2828 struct omap_overlay *ovl;
2829 ovl = omap_dss_get_overlay(i);
2830
2831 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2832 continue;
2833
2834 if (ovl->id == 2) {
2835 dispc_enable_plane(ovl->id, 0);
2836 dispc_go(ovl->manager->id);
2837 mdelay(50);
2838 break;
2839 }
2840 }
2841 }
2842
2843 if (errors & DISPC_IRQ_SYNC_LOST) {
2844 struct omap_overlay_manager *manager = NULL;
2845 bool enable = false;
2846
2847 DSSERR("SYNC_LOST, disabling LCD\n");
2848
2849 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2850 struct omap_overlay_manager *mgr;
2851 mgr = omap_dss_get_overlay_manager(i);
2852
2853 if (mgr->id == OMAP_DSS_CHANNEL_LCD) {
2854 manager = mgr;
2855 enable = mgr->device->state ==
2856 OMAP_DSS_DISPLAY_ACTIVE;
2857 mgr->device->disable(mgr->device);
2858 break;
2859 }
2860 }
2861
2862 if (manager) {
2863 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2864 struct omap_overlay *ovl;
2865 ovl = omap_dss_get_overlay(i);
2866
2867 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2868 continue;
2869
2870 if (ovl->id != 0 && ovl->manager == manager)
2871 dispc_enable_plane(ovl->id, 0);
2872 }
2873
2874 dispc_go(manager->id);
2875 mdelay(50);
2876 if (enable)
2877 manager->device->enable(manager->device);
2878 }
2879 }
2880
2881 if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) {
2882 struct omap_overlay_manager *manager = NULL;
2883 bool enable = false;
2884
2885 DSSERR("SYNC_LOST_DIGIT, disabling TV\n");
2886
2887 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2888 struct omap_overlay_manager *mgr;
2889 mgr = omap_dss_get_overlay_manager(i);
2890
2891 if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) {
2892 manager = mgr;
2893 enable = mgr->device->state ==
2894 OMAP_DSS_DISPLAY_ACTIVE;
2895 mgr->device->disable(mgr->device);
2896 break;
2897 }
2898 }
2899
2900 if (manager) {
2901 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2902 struct omap_overlay *ovl;
2903 ovl = omap_dss_get_overlay(i);
2904
2905 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
2906 continue;
2907
2908 if (ovl->id != 0 && ovl->manager == manager)
2909 dispc_enable_plane(ovl->id, 0);
2910 }
2911
2912 dispc_go(manager->id);
2913 mdelay(50);
2914 if (enable)
2915 manager->device->enable(manager->device);
2916 }
2917 }
2918
2919 if (errors & DISPC_IRQ_OCP_ERR) {
2920 DSSERR("OCP_ERR\n");
2921 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
2922 struct omap_overlay_manager *mgr;
2923 mgr = omap_dss_get_overlay_manager(i);
2924
2925 if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC)
2926 mgr->device->disable(mgr->device);
2927 }
2928 }
2929
2930 spin_lock_irqsave(&dispc.irq_lock, flags);
2931 dispc.irq_error_mask |= errors;
2932 _omap_dispc_set_irqs();
2933 spin_unlock_irqrestore(&dispc.irq_lock, flags);
2934}
2935
2936int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout)
2937{
2938 void dispc_irq_wait_handler(void *data, u32 mask)
2939 {
2940 complete((struct completion *)data);
2941 }
2942
2943 int r;
2944 DECLARE_COMPLETION_ONSTACK(completion);
2945
2946 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2947 irqmask);
2948
2949 if (r)
2950 return r;
2951
2952 timeout = wait_for_completion_timeout(&completion, timeout);
2953
2954 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2955
2956 if (timeout == 0)
2957 return -ETIMEDOUT;
2958
2959 if (timeout == -ERESTARTSYS)
2960 return -ERESTARTSYS;
2961
2962 return 0;
2963}
2964
2965int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask,
2966 unsigned long timeout)
2967{
2968 void dispc_irq_wait_handler(void *data, u32 mask)
2969 {
2970 complete((struct completion *)data);
2971 }
2972
2973 int r;
2974 DECLARE_COMPLETION_ONSTACK(completion);
2975
2976 r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion,
2977 irqmask);
2978
2979 if (r)
2980 return r;
2981
2982 timeout = wait_for_completion_interruptible_timeout(&completion,
2983 timeout);
2984
2985 omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask);
2986
2987 if (timeout == 0)
2988 return -ETIMEDOUT;
2989
2990 if (timeout == -ERESTARTSYS)
2991 return -ERESTARTSYS;
2992
2993 return 0;
2994}
2995
2996#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
2997void dispc_fake_vsync_irq(void)
2998{
2999 u32 irqstatus = DISPC_IRQ_VSYNC;
3000 int i;
3001
3002 local_irq_disable();
3003
3004 for (i = 0; i < DISPC_MAX_NR_ISRS; i++) {
3005 struct omap_dispc_isr_data *isr_data;
3006 isr_data = &dispc.registered_isr[i];
3007
3008 if (!isr_data->isr)
3009 continue;
3010
3011 if (isr_data->mask & irqstatus)
3012 isr_data->isr(isr_data->arg, irqstatus);
3013 }
3014
3015 local_irq_enable();
3016}
3017#endif
3018
3019static void _omap_dispc_initialize_irq(void)
3020{
3021 unsigned long flags;
3022
3023 spin_lock_irqsave(&dispc.irq_lock, flags);
3024
3025 memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr));
3026
3027 dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR;
3028
3029 /* there's SYNC_LOST_DIGIT waiting after enabling the DSS,
3030 * so clear it */
3031 dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS));
3032
3033 _omap_dispc_set_irqs();
3034
3035 spin_unlock_irqrestore(&dispc.irq_lock, flags);
3036}
3037
3038void dispc_enable_sidle(void)
3039{
3040 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3041}
3042
3043void dispc_disable_sidle(void)
3044{
3045 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3046}
3047
3048static void _omap_dispc_initial_config(void)
3049{
3050 u32 l;
3051
3052 l = dispc_read_reg(DISPC_SYSCONFIG);
3053 l = FLD_MOD(l, 2, 13, 12); /* MIDLEMODE: smart standby */
3054 l = FLD_MOD(l, 2, 4, 3); /* SIDLEMODE: smart idle */
3055 l = FLD_MOD(l, 1, 2, 2); /* ENWAKEUP */
3056 l = FLD_MOD(l, 1, 0, 0); /* AUTOIDLE */
3057 dispc_write_reg(DISPC_SYSCONFIG, l);
3058
3059 /* FUNCGATED */
3060 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
3061
3062 /* L3 firewall setting: enable access to OCM RAM */
3063 /* XXX this should be somewhere in plat-omap */
3064 if (cpu_is_omap24xx())
3065 __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0));
3066
3067 _dispc_setup_color_conv_coef();
3068
3069 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3070
3071 dispc_read_plane_fifo_sizes();
3072}
3073
3074int dispc_init(void)
3075{
3076 u32 rev;
3077
3078 spin_lock_init(&dispc.irq_lock);
3079
3080#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3081 spin_lock_init(&dispc.irq_stats_lock);
3082 dispc.irq_stats.last_reset = jiffies;
3083#endif
3084
3085 INIT_WORK(&dispc.error_work, dispc_error_worker);
3086
3087 dispc.base = ioremap(DISPC_BASE, DISPC_SZ_REGS);
3088 if (!dispc.base) {
3089 DSSERR("can't ioremap DISPC\n");
3090 return -ENOMEM;
3091 }
3092
3093 enable_clocks(1);
3094
3095 _omap_dispc_initial_config();
3096
3097 _omap_dispc_initialize_irq();
3098
3099 dispc_save_context();
3100
3101 rev = dispc_read_reg(DISPC_REVISION);
3102 printk(KERN_INFO "OMAP DISPC rev %d.%d\n",
3103 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3104
3105 enable_clocks(0);
3106
3107 return 0;
3108}
3109
3110void dispc_exit(void)
3111{
3112 iounmap(dispc.base);
3113}
3114
3115int dispc_enable_plane(enum omap_plane plane, bool enable)
3116{
3117 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
3118
3119 enable_clocks(1);
3120 _dispc_enable_plane(plane, enable);
3121 enable_clocks(0);
3122
3123 return 0;
3124}
3125
3126int dispc_setup_plane(enum omap_plane plane,
3127 u32 paddr, u16 screen_width,
3128 u16 pos_x, u16 pos_y,
3129 u16 width, u16 height,
3130 u16 out_width, u16 out_height,
3131 enum omap_color_mode color_mode,
3132 bool ilace,
3133 enum omap_dss_rotation_type rotation_type,
3134 u8 rotation, bool mirror, u8 global_alpha)
3135{
3136 int r = 0;
3137
3138 DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> "
3139 "%dx%d, ilace %d, cmode %x, rot %d, mir %d\n",
3140 plane, paddr, screen_width, pos_x, pos_y,
3141 width, height,
3142 out_width, out_height,
3143 ilace, color_mode,
3144 rotation, mirror);
3145
3146 enable_clocks(1);
3147
3148 r = _dispc_setup_plane(plane,
3149 paddr, screen_width,
3150 pos_x, pos_y,
3151 width, height,
3152 out_width, out_height,
3153 color_mode, ilace,
3154 rotation_type,
3155 rotation, mirror,
3156 global_alpha);
3157
3158 enable_clocks(0);
3159
3160 return r;
3161}
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
new file mode 100644
index 000000000000..3b92b84b9560
--- /dev/null
+++ b/drivers/video/omap2/dss/display.c
@@ -0,0 +1,671 @@
1/*
2 * linux/drivers/video/omap2/dss/display.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DISPLAY"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/jiffies.h>
28#include <linux/list.h>
29#include <linux/platform_device.h>
30
31#include <plat/display.h>
32#include "dss.h"
33
34static LIST_HEAD(display_list);
35
36static ssize_t display_enabled_show(struct device *dev,
37 struct device_attribute *attr, char *buf)
38{
39 struct omap_dss_device *dssdev = to_dss_device(dev);
40 bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED;
41
42 return snprintf(buf, PAGE_SIZE, "%d\n", enabled);
43}
44
45static ssize_t display_enabled_store(struct device *dev,
46 struct device_attribute *attr,
47 const char *buf, size_t size)
48{
49 struct omap_dss_device *dssdev = to_dss_device(dev);
50 bool enabled, r;
51
52 enabled = simple_strtoul(buf, NULL, 10);
53
54 if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) {
55 if (enabled) {
56 r = dssdev->enable(dssdev);
57 if (r)
58 return r;
59 } else {
60 dssdev->disable(dssdev);
61 }
62 }
63
64 return size;
65}
66
67static ssize_t display_upd_mode_show(struct device *dev,
68 struct device_attribute *attr, char *buf)
69{
70 struct omap_dss_device *dssdev = to_dss_device(dev);
71 enum omap_dss_update_mode mode = OMAP_DSS_UPDATE_AUTO;
72 if (dssdev->get_update_mode)
73 mode = dssdev->get_update_mode(dssdev);
74 return snprintf(buf, PAGE_SIZE, "%d\n", mode);
75}
76
77static ssize_t display_upd_mode_store(struct device *dev,
78 struct device_attribute *attr,
79 const char *buf, size_t size)
80{
81 struct omap_dss_device *dssdev = to_dss_device(dev);
82 int val, r;
83 enum omap_dss_update_mode mode;
84
85 val = simple_strtoul(buf, NULL, 10);
86
87 switch (val) {
88 case OMAP_DSS_UPDATE_DISABLED:
89 case OMAP_DSS_UPDATE_AUTO:
90 case OMAP_DSS_UPDATE_MANUAL:
91 mode = (enum omap_dss_update_mode)val;
92 break;
93 default:
94 return -EINVAL;
95 }
96
97 r = dssdev->set_update_mode(dssdev, mode);
98 if (r)
99 return r;
100
101 return size;
102}
103
104static ssize_t display_tear_show(struct device *dev,
105 struct device_attribute *attr, char *buf)
106{
107 struct omap_dss_device *dssdev = to_dss_device(dev);
108 return snprintf(buf, PAGE_SIZE, "%d\n",
109 dssdev->get_te ? dssdev->get_te(dssdev) : 0);
110}
111
112static ssize_t display_tear_store(struct device *dev,
113 struct device_attribute *attr, const char *buf, size_t size)
114{
115 struct omap_dss_device *dssdev = to_dss_device(dev);
116 unsigned long te;
117 int r;
118
119 if (!dssdev->enable_te || !dssdev->get_te)
120 return -ENOENT;
121
122 te = simple_strtoul(buf, NULL, 0);
123
124 r = dssdev->enable_te(dssdev, te);
125 if (r)
126 return r;
127
128 return size;
129}
130
131static ssize_t display_timings_show(struct device *dev,
132 struct device_attribute *attr, char *buf)
133{
134 struct omap_dss_device *dssdev = to_dss_device(dev);
135 struct omap_video_timings t;
136
137 if (!dssdev->get_timings)
138 return -ENOENT;
139
140 dssdev->get_timings(dssdev, &t);
141
142 return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n",
143 t.pixel_clock,
144 t.x_res, t.hfp, t.hbp, t.hsw,
145 t.y_res, t.vfp, t.vbp, t.vsw);
146}
147
148static ssize_t display_timings_store(struct device *dev,
149 struct device_attribute *attr, const char *buf, size_t size)
150{
151 struct omap_dss_device *dssdev = to_dss_device(dev);
152 struct omap_video_timings t;
153 int r, found;
154
155 if (!dssdev->set_timings || !dssdev->check_timings)
156 return -ENOENT;
157
158 found = 0;
159#ifdef CONFIG_OMAP2_DSS_VENC
160 if (strncmp("pal", buf, 3) == 0) {
161 t = omap_dss_pal_timings;
162 found = 1;
163 } else if (strncmp("ntsc", buf, 4) == 0) {
164 t = omap_dss_ntsc_timings;
165 found = 1;
166 }
167#endif
168 if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu",
169 &t.pixel_clock,
170 &t.x_res, &t.hfp, &t.hbp, &t.hsw,
171 &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9)
172 return -EINVAL;
173
174 r = dssdev->check_timings(dssdev, &t);
175 if (r)
176 return r;
177
178 dssdev->set_timings(dssdev, &t);
179
180 return size;
181}
182
183static ssize_t display_rotate_show(struct device *dev,
184 struct device_attribute *attr, char *buf)
185{
186 struct omap_dss_device *dssdev = to_dss_device(dev);
187 int rotate;
188 if (!dssdev->get_rotate)
189 return -ENOENT;
190 rotate = dssdev->get_rotate(dssdev);
191 return snprintf(buf, PAGE_SIZE, "%u\n", rotate);
192}
193
194static ssize_t display_rotate_store(struct device *dev,
195 struct device_attribute *attr, const char *buf, size_t size)
196{
197 struct omap_dss_device *dssdev = to_dss_device(dev);
198 unsigned long rot;
199 int r;
200
201 if (!dssdev->set_rotate || !dssdev->get_rotate)
202 return -ENOENT;
203
204 rot = simple_strtoul(buf, NULL, 0);
205
206 r = dssdev->set_rotate(dssdev, rot);
207 if (r)
208 return r;
209
210 return size;
211}
212
213static ssize_t display_mirror_show(struct device *dev,
214 struct device_attribute *attr, char *buf)
215{
216 struct omap_dss_device *dssdev = to_dss_device(dev);
217 int mirror;
218 if (!dssdev->get_mirror)
219 return -ENOENT;
220 mirror = dssdev->get_mirror(dssdev);
221 return snprintf(buf, PAGE_SIZE, "%u\n", mirror);
222}
223
224static ssize_t display_mirror_store(struct device *dev,
225 struct device_attribute *attr, const char *buf, size_t size)
226{
227 struct omap_dss_device *dssdev = to_dss_device(dev);
228 unsigned long mirror;
229 int r;
230
231 if (!dssdev->set_mirror || !dssdev->get_mirror)
232 return -ENOENT;
233
234 mirror = simple_strtoul(buf, NULL, 0);
235
236 r = dssdev->set_mirror(dssdev, mirror);
237 if (r)
238 return r;
239
240 return size;
241}
242
243static ssize_t display_wss_show(struct device *dev,
244 struct device_attribute *attr, char *buf)
245{
246 struct omap_dss_device *dssdev = to_dss_device(dev);
247 unsigned int wss;
248
249 if (!dssdev->get_wss)
250 return -ENOENT;
251
252 wss = dssdev->get_wss(dssdev);
253
254 return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss);
255}
256
257static ssize_t display_wss_store(struct device *dev,
258 struct device_attribute *attr, const char *buf, size_t size)
259{
260 struct omap_dss_device *dssdev = to_dss_device(dev);
261 unsigned long wss;
262 int r;
263
264 if (!dssdev->get_wss || !dssdev->set_wss)
265 return -ENOENT;
266
267 if (strict_strtoul(buf, 0, &wss))
268 return -EINVAL;
269
270 if (wss > 0xfffff)
271 return -EINVAL;
272
273 r = dssdev->set_wss(dssdev, wss);
274 if (r)
275 return r;
276
277 return size;
278}
279
280static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
281 display_enabled_show, display_enabled_store);
282static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
283 display_upd_mode_show, display_upd_mode_store);
284static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR,
285 display_tear_show, display_tear_store);
286static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR,
287 display_timings_show, display_timings_store);
288static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR,
289 display_rotate_show, display_rotate_store);
290static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR,
291 display_mirror_show, display_mirror_store);
292static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
293 display_wss_show, display_wss_store);
294
295static struct device_attribute *display_sysfs_attrs[] = {
296 &dev_attr_enabled,
297 &dev_attr_update_mode,
298 &dev_attr_tear_elim,
299 &dev_attr_timings,
300 &dev_attr_rotate,
301 &dev_attr_mirror,
302 &dev_attr_wss,
303 NULL
304};
305
306static void default_get_resolution(struct omap_dss_device *dssdev,
307 u16 *xres, u16 *yres)
308{
309 *xres = dssdev->panel.timings.x_res;
310 *yres = dssdev->panel.timings.y_res;
311}
312
313void default_get_overlay_fifo_thresholds(enum omap_plane plane,
314 u32 fifo_size, enum omap_burst_size *burst_size,
315 u32 *fifo_low, u32 *fifo_high)
316{
317 unsigned burst_size_bytes;
318
319 *burst_size = OMAP_DSS_BURST_16x32;
320 burst_size_bytes = 16 * 32 / 8;
321
322 *fifo_high = fifo_size - 1;
323 *fifo_low = fifo_size - burst_size_bytes;
324}
325
326static int default_wait_vsync(struct omap_dss_device *dssdev)
327{
328 unsigned long timeout = msecs_to_jiffies(500);
329 u32 irq;
330
331 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC)
332 irq = DISPC_IRQ_EVSYNC_ODD;
333 else
334 irq = DISPC_IRQ_VSYNC;
335
336 return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
337}
338
339static int default_get_recommended_bpp(struct omap_dss_device *dssdev)
340{
341 if (dssdev->panel.recommended_bpp)
342 return dssdev->panel.recommended_bpp;
343
344 switch (dssdev->type) {
345 case OMAP_DISPLAY_TYPE_DPI:
346 if (dssdev->phy.dpi.data_lines == 24)
347 return 24;
348 else
349 return 16;
350
351 case OMAP_DISPLAY_TYPE_DBI:
352 case OMAP_DISPLAY_TYPE_DSI:
353 if (dssdev->ctrl.pixel_size == 24)
354 return 24;
355 else
356 return 16;
357 case OMAP_DISPLAY_TYPE_VENC:
358 case OMAP_DISPLAY_TYPE_SDI:
359 return 24;
360 return 24;
361 default:
362 BUG();
363 }
364}
365
366/* Checks if replication logic should be used. Only use for active matrix,
367 * when overlay is in RGB12U or RGB16 mode, and LCD interface is
368 * 18bpp or 24bpp */
369bool dss_use_replication(struct omap_dss_device *dssdev,
370 enum omap_color_mode mode)
371{
372 int bpp;
373
374 if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
375 return false;
376
377 if (dssdev->type == OMAP_DISPLAY_TYPE_DPI &&
378 (dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0)
379 return false;
380
381 switch (dssdev->type) {
382 case OMAP_DISPLAY_TYPE_DPI:
383 bpp = dssdev->phy.dpi.data_lines;
384 break;
385 case OMAP_DISPLAY_TYPE_VENC:
386 case OMAP_DISPLAY_TYPE_SDI:
387 bpp = 24;
388 break;
389 case OMAP_DISPLAY_TYPE_DBI:
390 case OMAP_DISPLAY_TYPE_DSI:
391 bpp = dssdev->ctrl.pixel_size;
392 break;
393 default:
394 BUG();
395 }
396
397 return bpp > 16;
398}
399
400void dss_init_device(struct platform_device *pdev,
401 struct omap_dss_device *dssdev)
402{
403 struct device_attribute *attr;
404 int i;
405 int r;
406
407 switch (dssdev->type) {
408 case OMAP_DISPLAY_TYPE_DPI:
409#ifdef CONFIG_OMAP2_DSS_RFBI
410 case OMAP_DISPLAY_TYPE_DBI:
411#endif
412#ifdef CONFIG_OMAP2_DSS_SDI
413 case OMAP_DISPLAY_TYPE_SDI:
414#endif
415#ifdef CONFIG_OMAP2_DSS_DSI
416 case OMAP_DISPLAY_TYPE_DSI:
417#endif
418#ifdef CONFIG_OMAP2_DSS_VENC
419 case OMAP_DISPLAY_TYPE_VENC:
420#endif
421 break;
422 default:
423 DSSERR("Support for display '%s' not compiled in.\n",
424 dssdev->name);
425 return;
426 }
427
428 dssdev->get_resolution = default_get_resolution;
429 dssdev->get_recommended_bpp = default_get_recommended_bpp;
430 dssdev->wait_vsync = default_wait_vsync;
431
432 switch (dssdev->type) {
433 case OMAP_DISPLAY_TYPE_DPI:
434 r = dpi_init_display(dssdev);
435 break;
436#ifdef CONFIG_OMAP2_DSS_RFBI
437 case OMAP_DISPLAY_TYPE_DBI:
438 r = rfbi_init_display(dssdev);
439 break;
440#endif
441#ifdef CONFIG_OMAP2_DSS_VENC
442 case OMAP_DISPLAY_TYPE_VENC:
443 r = venc_init_display(dssdev);
444 break;
445#endif
446#ifdef CONFIG_OMAP2_DSS_SDI
447 case OMAP_DISPLAY_TYPE_SDI:
448 r = sdi_init_display(dssdev);
449 break;
450#endif
451#ifdef CONFIG_OMAP2_DSS_DSI
452 case OMAP_DISPLAY_TYPE_DSI:
453 r = dsi_init_display(dssdev);
454 break;
455#endif
456 default:
457 BUG();
458 }
459
460 if (r) {
461 DSSERR("failed to init display %s\n", dssdev->name);
462 return;
463 }
464
465 /* create device sysfs files */
466 i = 0;
467 while ((attr = display_sysfs_attrs[i++]) != NULL) {
468 r = device_create_file(&dssdev->dev, attr);
469 if (r)
470 DSSERR("failed to create sysfs file\n");
471 }
472
473 /* create display? sysfs links */
474 r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj,
475 dev_name(&dssdev->dev));
476 if (r)
477 DSSERR("failed to create sysfs display link\n");
478}
479
480void dss_uninit_device(struct platform_device *pdev,
481 struct omap_dss_device *dssdev)
482{
483 struct device_attribute *attr;
484 int i = 0;
485
486 sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev));
487
488 while ((attr = display_sysfs_attrs[i++]) != NULL)
489 device_remove_file(&dssdev->dev, attr);
490
491 if (dssdev->manager)
492 dssdev->manager->unset_device(dssdev->manager);
493}
494
495static int dss_suspend_device(struct device *dev, void *data)
496{
497 int r;
498 struct omap_dss_device *dssdev = to_dss_device(dev);
499
500 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
501 dssdev->activate_after_resume = false;
502 return 0;
503 }
504
505 if (!dssdev->suspend) {
506 DSSERR("display '%s' doesn't implement suspend\n",
507 dssdev->name);
508 return -ENOSYS;
509 }
510
511 r = dssdev->suspend(dssdev);
512 if (r)
513 return r;
514
515 dssdev->activate_after_resume = true;
516
517 return 0;
518}
519
520int dss_suspend_all_devices(void)
521{
522 int r;
523 struct bus_type *bus = dss_get_bus();
524
525 r = bus_for_each_dev(bus, NULL, NULL, dss_suspend_device);
526 if (r) {
527 /* resume all displays that were suspended */
528 dss_resume_all_devices();
529 return r;
530 }
531
532 return 0;
533}
534
535static int dss_resume_device(struct device *dev, void *data)
536{
537 int r;
538 struct omap_dss_device *dssdev = to_dss_device(dev);
539
540 if (dssdev->activate_after_resume && dssdev->resume) {
541 r = dssdev->resume(dssdev);
542 if (r)
543 return r;
544 }
545
546 dssdev->activate_after_resume = false;
547
548 return 0;
549}
550
551int dss_resume_all_devices(void)
552{
553 struct bus_type *bus = dss_get_bus();
554
555 return bus_for_each_dev(bus, NULL, NULL, dss_resume_device);
556}
557
558static int dss_disable_device(struct device *dev, void *data)
559{
560 struct omap_dss_device *dssdev = to_dss_device(dev);
561 dssdev->disable(dssdev);
562 return 0;
563}
564
565void dss_disable_all_devices(void)
566{
567 struct bus_type *bus = dss_get_bus();
568 bus_for_each_dev(bus, NULL, NULL, dss_disable_device);
569}
570
571
572void omap_dss_get_device(struct omap_dss_device *dssdev)
573{
574 get_device(&dssdev->dev);
575}
576EXPORT_SYMBOL(omap_dss_get_device);
577
578void omap_dss_put_device(struct omap_dss_device *dssdev)
579{
580 put_device(&dssdev->dev);
581}
582EXPORT_SYMBOL(omap_dss_put_device);
583
584/* ref count of the found device is incremented. ref count
585 * of from-device is decremented. */
586struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
587{
588 struct device *dev;
589 struct device *dev_start = NULL;
590 struct omap_dss_device *dssdev = NULL;
591
592 int match(struct device *dev, void *data)
593 {
594 /* skip panels connected to controllers */
595 if (to_dss_device(dev)->panel.ctrl)
596 return 0;
597
598 return 1;
599 }
600
601 if (from)
602 dev_start = &from->dev;
603 dev = bus_find_device(dss_get_bus(), dev_start, NULL, match);
604 if (dev)
605 dssdev = to_dss_device(dev);
606 if (from)
607 put_device(&from->dev);
608
609 return dssdev;
610}
611EXPORT_SYMBOL(omap_dss_get_next_device);
612
613struct omap_dss_device *omap_dss_find_device(void *data,
614 int (*match)(struct omap_dss_device *dssdev, void *data))
615{
616 struct omap_dss_device *dssdev = NULL;
617
618 while ((dssdev = omap_dss_get_next_device(dssdev)) != NULL) {
619 if (match(dssdev, data))
620 return dssdev;
621 }
622
623 return NULL;
624}
625EXPORT_SYMBOL(omap_dss_find_device);
626
627int omap_dss_start_device(struct omap_dss_device *dssdev)
628{
629 int r;
630
631 if (!dssdev->driver) {
632 DSSDBG("no driver\n");
633 r = -ENODEV;
634 goto err0;
635 }
636
637 if (dssdev->ctrl.panel && !dssdev->ctrl.panel->driver) {
638 DSSDBG("no panel driver\n");
639 r = -ENODEV;
640 goto err0;
641 }
642
643 if (!try_module_get(dssdev->dev.driver->owner)) {
644 r = -ENODEV;
645 goto err0;
646 }
647
648 if (dssdev->ctrl.panel) {
649 if (!try_module_get(dssdev->ctrl.panel->dev.driver->owner)) {
650 r = -ENODEV;
651 goto err1;
652 }
653 }
654
655 return 0;
656err1:
657 module_put(dssdev->dev.driver->owner);
658err0:
659 return r;
660}
661EXPORT_SYMBOL(omap_dss_start_device);
662
663void omap_dss_stop_device(struct omap_dss_device *dssdev)
664{
665 if (dssdev->ctrl.panel)
666 module_put(dssdev->ctrl.panel->dev.driver->owner);
667
668 module_put(dssdev->dev.driver->owner);
669}
670EXPORT_SYMBOL(omap_dss_stop_device);
671
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
new file mode 100644
index 000000000000..2d71031baa25
--- /dev/null
+++ b/drivers/video/omap2/dss/dpi.c
@@ -0,0 +1,399 @@
1/*
2 * linux/drivers/video/omap2/dss/dpi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DPI"
24
25#include <linux/kernel.h>
26#include <linux/clk.h>
27#include <linux/delay.h>
28#include <linux/errno.h>
29
30#include <plat/display.h>
31#include <plat/cpu.h>
32
33#include "dss.h"
34
35static struct {
36 int update_enabled;
37} dpi;
38
39#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
40static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
41 unsigned long *fck, int *lck_div, int *pck_div)
42{
43 struct dsi_clock_info dsi_cinfo;
44 struct dispc_clock_info dispc_cinfo;
45 int r;
46
47 r = dsi_pll_calc_clock_div_pck(is_tft, pck_req, &dsi_cinfo,
48 &dispc_cinfo);
49 if (r)
50 return r;
51
52 r = dsi_pll_set_clock_div(&dsi_cinfo);
53 if (r)
54 return r;
55
56 dss_select_clk_source(0, 1);
57
58 r = dispc_set_clock_div(&dispc_cinfo);
59 if (r)
60 return r;
61
62 *fck = dsi_cinfo.dsi1_pll_fclk;
63 *lck_div = dispc_cinfo.lck_div;
64 *pck_div = dispc_cinfo.pck_div;
65
66 return 0;
67}
68#else
69static int dpi_set_dispc_clk(bool is_tft, unsigned long pck_req,
70 unsigned long *fck, int *lck_div, int *pck_div)
71{
72 struct dss_clock_info dss_cinfo;
73 struct dispc_clock_info dispc_cinfo;
74 int r;
75
76 r = dss_calc_clock_div(is_tft, pck_req, &dss_cinfo, &dispc_cinfo);
77 if (r)
78 return r;
79
80 r = dss_set_clock_div(&dss_cinfo);
81 if (r)
82 return r;
83
84 r = dispc_set_clock_div(&dispc_cinfo);
85 if (r)
86 return r;
87
88 *fck = dss_cinfo.fck;
89 *lck_div = dispc_cinfo.lck_div;
90 *pck_div = dispc_cinfo.pck_div;
91
92 return 0;
93}
94#endif
95
96static int dpi_set_mode(struct omap_dss_device *dssdev)
97{
98 struct omap_video_timings *t = &dssdev->panel.timings;
99 int lck_div, pck_div;
100 unsigned long fck;
101 unsigned long pck;
102 bool is_tft;
103 int r = 0;
104
105 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
106
107 dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
108 dssdev->panel.acb);
109
110 is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
111
112#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
113 r = dpi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
114 &fck, &lck_div, &pck_div);
115#else
116 r = dpi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
117 &fck, &lck_div, &pck_div);
118#endif
119 if (r)
120 goto err0;
121
122 pck = fck / lck_div / pck_div / 1000;
123
124 if (pck != t->pixel_clock) {
125 DSSWARN("Could not find exact pixel clock. "
126 "Requested %d kHz, got %lu kHz\n",
127 t->pixel_clock, pck);
128
129 t->pixel_clock = pck;
130 }
131
132 dispc_set_lcd_timings(t);
133
134err0:
135 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
136 return r;
137}
138
139static int dpi_basic_init(struct omap_dss_device *dssdev)
140{
141 bool is_tft;
142
143 is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
144
145 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
146 dispc_set_lcd_display_type(is_tft ? OMAP_DSS_LCD_DISPLAY_TFT :
147 OMAP_DSS_LCD_DISPLAY_STN);
148 dispc_set_tft_data_lines(dssdev->phy.dpi.data_lines);
149
150 return 0;
151}
152
153static int dpi_display_enable(struct omap_dss_device *dssdev)
154{
155 int r;
156
157 r = omap_dss_start_device(dssdev);
158 if (r) {
159 DSSERR("failed to start device\n");
160 goto err0;
161 }
162
163 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
164 DSSERR("display already enabled\n");
165 r = -EINVAL;
166 goto err1;
167 }
168
169 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
170
171 r = dpi_basic_init(dssdev);
172 if (r)
173 goto err2;
174
175#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
176 dss_clk_enable(DSS_CLK_FCK2);
177 r = dsi_pll_init(dssdev, 0, 1);
178 if (r)
179 goto err3;
180#endif
181 r = dpi_set_mode(dssdev);
182 if (r)
183 goto err4;
184
185 mdelay(2);
186
187 dispc_enable_lcd_out(1);
188
189 r = dssdev->driver->enable(dssdev);
190 if (r)
191 goto err5;
192
193 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
194
195 return 0;
196
197err5:
198 dispc_enable_lcd_out(0);
199err4:
200#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
201 dsi_pll_uninit();
202err3:
203 dss_clk_disable(DSS_CLK_FCK2);
204#endif
205err2:
206 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
207err1:
208 omap_dss_stop_device(dssdev);
209err0:
210 return r;
211}
212
213static int dpi_display_resume(struct omap_dss_device *dssdev);
214
215static void dpi_display_disable(struct omap_dss_device *dssdev)
216{
217 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
218 return;
219
220 if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
221 dpi_display_resume(dssdev);
222
223 dssdev->driver->disable(dssdev);
224
225 dispc_enable_lcd_out(0);
226
227#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
228 dss_select_clk_source(0, 0);
229 dsi_pll_uninit();
230 dss_clk_disable(DSS_CLK_FCK2);
231#endif
232
233 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
234
235 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
236
237 omap_dss_stop_device(dssdev);
238}
239
240static int dpi_display_suspend(struct omap_dss_device *dssdev)
241{
242 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
243 return -EINVAL;
244
245 DSSDBG("dpi_display_suspend\n");
246
247 if (dssdev->driver->suspend)
248 dssdev->driver->suspend(dssdev);
249
250 dispc_enable_lcd_out(0);
251
252 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
253
254 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
255
256 return 0;
257}
258
259static int dpi_display_resume(struct omap_dss_device *dssdev)
260{
261 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
262 return -EINVAL;
263
264 DSSDBG("dpi_display_resume\n");
265
266 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
267
268 dispc_enable_lcd_out(1);
269
270 if (dssdev->driver->resume)
271 dssdev->driver->resume(dssdev);
272
273 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
274
275 return 0;
276}
277
278static void dpi_set_timings(struct omap_dss_device *dssdev,
279 struct omap_video_timings *timings)
280{
281 DSSDBG("dpi_set_timings\n");
282 dssdev->panel.timings = *timings;
283 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
284 dpi_set_mode(dssdev);
285 dispc_go(OMAP_DSS_CHANNEL_LCD);
286 }
287}
288
289static int dpi_check_timings(struct omap_dss_device *dssdev,
290 struct omap_video_timings *timings)
291{
292 bool is_tft;
293 int r;
294 int lck_div, pck_div;
295 unsigned long fck;
296 unsigned long pck;
297
298 if (!dispc_lcd_timings_ok(timings))
299 return -EINVAL;
300
301 if (timings->pixel_clock == 0)
302 return -EINVAL;
303
304 is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
305
306#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
307 {
308 struct dsi_clock_info dsi_cinfo;
309 struct dispc_clock_info dispc_cinfo;
310 r = dsi_pll_calc_clock_div_pck(is_tft,
311 timings->pixel_clock * 1000,
312 &dsi_cinfo, &dispc_cinfo);
313
314 if (r)
315 return r;
316
317 fck = dsi_cinfo.dsi1_pll_fclk;
318 lck_div = dispc_cinfo.lck_div;
319 pck_div = dispc_cinfo.pck_div;
320 }
321#else
322 {
323 struct dss_clock_info dss_cinfo;
324 struct dispc_clock_info dispc_cinfo;
325 r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000,
326 &dss_cinfo, &dispc_cinfo);
327
328 if (r)
329 return r;
330
331 fck = dss_cinfo.fck;
332 lck_div = dispc_cinfo.lck_div;
333 pck_div = dispc_cinfo.pck_div;
334 }
335#endif
336
337 pck = fck / lck_div / pck_div / 1000;
338
339 timings->pixel_clock = pck;
340
341 return 0;
342}
343
344static void dpi_get_timings(struct omap_dss_device *dssdev,
345 struct omap_video_timings *timings)
346{
347 *timings = dssdev->panel.timings;
348}
349
350static int dpi_display_set_update_mode(struct omap_dss_device *dssdev,
351 enum omap_dss_update_mode mode)
352{
353 if (mode == OMAP_DSS_UPDATE_MANUAL)
354 return -EINVAL;
355
356 if (mode == OMAP_DSS_UPDATE_DISABLED) {
357 dispc_enable_lcd_out(0);
358 dpi.update_enabled = 0;
359 } else {
360 dispc_enable_lcd_out(1);
361 dpi.update_enabled = 1;
362 }
363
364 return 0;
365}
366
367static enum omap_dss_update_mode dpi_display_get_update_mode(
368 struct omap_dss_device *dssdev)
369{
370 return dpi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
371 OMAP_DSS_UPDATE_DISABLED;
372}
373
374int dpi_init_display(struct omap_dss_device *dssdev)
375{
376 DSSDBG("init_display\n");
377
378 dssdev->enable = dpi_display_enable;
379 dssdev->disable = dpi_display_disable;
380 dssdev->suspend = dpi_display_suspend;
381 dssdev->resume = dpi_display_resume;
382 dssdev->set_timings = dpi_set_timings;
383 dssdev->check_timings = dpi_check_timings;
384 dssdev->get_timings = dpi_get_timings;
385 dssdev->set_update_mode = dpi_display_set_update_mode;
386 dssdev->get_update_mode = dpi_display_get_update_mode;
387
388 return 0;
389}
390
391int dpi_init(void)
392{
393 return 0;
394}
395
396void dpi_exit(void)
397{
398}
399
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c
new file mode 100644
index 000000000000..6122178f5f85
--- /dev/null
+++ b/drivers/video/omap2/dss/dsi.c
@@ -0,0 +1,3839 @@
1/*
2 * linux/drivers/video/omap2/dss/dsi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#define DSS_SUBSYS_NAME "DSI"
21
22#include <linux/kernel.h>
23#include <linux/io.h>
24#include <linux/clk.h>
25#include <linux/device.h>
26#include <linux/err.h>
27#include <linux/interrupt.h>
28#include <linux/delay.h>
29#include <linux/mutex.h>
30#include <linux/seq_file.h>
31#include <linux/platform_device.h>
32#include <linux/regulator/consumer.h>
33#include <linux/kthread.h>
34#include <linux/wait.h>
35
36#include <plat/display.h>
37#include <plat/clock.h>
38
39#include "dss.h"
40
41/*#define VERBOSE_IRQ*/
42#define DSI_CATCH_MISSING_TE
43
44#define DSI_BASE 0x4804FC00
45
46struct dsi_reg { u16 idx; };
47
48#define DSI_REG(idx) ((const struct dsi_reg) { idx })
49
50#define DSI_SZ_REGS SZ_1K
51/* DSI Protocol Engine */
52
53#define DSI_REVISION DSI_REG(0x0000)
54#define DSI_SYSCONFIG DSI_REG(0x0010)
55#define DSI_SYSSTATUS DSI_REG(0x0014)
56#define DSI_IRQSTATUS DSI_REG(0x0018)
57#define DSI_IRQENABLE DSI_REG(0x001C)
58#define DSI_CTRL DSI_REG(0x0040)
59#define DSI_COMPLEXIO_CFG1 DSI_REG(0x0048)
60#define DSI_COMPLEXIO_IRQ_STATUS DSI_REG(0x004C)
61#define DSI_COMPLEXIO_IRQ_ENABLE DSI_REG(0x0050)
62#define DSI_CLK_CTRL DSI_REG(0x0054)
63#define DSI_TIMING1 DSI_REG(0x0058)
64#define DSI_TIMING2 DSI_REG(0x005C)
65#define DSI_VM_TIMING1 DSI_REG(0x0060)
66#define DSI_VM_TIMING2 DSI_REG(0x0064)
67#define DSI_VM_TIMING3 DSI_REG(0x0068)
68#define DSI_CLK_TIMING DSI_REG(0x006C)
69#define DSI_TX_FIFO_VC_SIZE DSI_REG(0x0070)
70#define DSI_RX_FIFO_VC_SIZE DSI_REG(0x0074)
71#define DSI_COMPLEXIO_CFG2 DSI_REG(0x0078)
72#define DSI_RX_FIFO_VC_FULLNESS DSI_REG(0x007C)
73#define DSI_VM_TIMING4 DSI_REG(0x0080)
74#define DSI_TX_FIFO_VC_EMPTINESS DSI_REG(0x0084)
75#define DSI_VM_TIMING5 DSI_REG(0x0088)
76#define DSI_VM_TIMING6 DSI_REG(0x008C)
77#define DSI_VM_TIMING7 DSI_REG(0x0090)
78#define DSI_STOPCLK_TIMING DSI_REG(0x0094)
79#define DSI_VC_CTRL(n) DSI_REG(0x0100 + (n * 0x20))
80#define DSI_VC_TE(n) DSI_REG(0x0104 + (n * 0x20))
81#define DSI_VC_LONG_PACKET_HEADER(n) DSI_REG(0x0108 + (n * 0x20))
82#define DSI_VC_LONG_PACKET_PAYLOAD(n) DSI_REG(0x010C + (n * 0x20))
83#define DSI_VC_SHORT_PACKET_HEADER(n) DSI_REG(0x0110 + (n * 0x20))
84#define DSI_VC_IRQSTATUS(n) DSI_REG(0x0118 + (n * 0x20))
85#define DSI_VC_IRQENABLE(n) DSI_REG(0x011C + (n * 0x20))
86
87/* DSIPHY_SCP */
88
89#define DSI_DSIPHY_CFG0 DSI_REG(0x200 + 0x0000)
90#define DSI_DSIPHY_CFG1 DSI_REG(0x200 + 0x0004)
91#define DSI_DSIPHY_CFG2 DSI_REG(0x200 + 0x0008)
92#define DSI_DSIPHY_CFG5 DSI_REG(0x200 + 0x0014)
93
94/* DSI_PLL_CTRL_SCP */
95
96#define DSI_PLL_CONTROL DSI_REG(0x300 + 0x0000)
97#define DSI_PLL_STATUS DSI_REG(0x300 + 0x0004)
98#define DSI_PLL_GO DSI_REG(0x300 + 0x0008)
99#define DSI_PLL_CONFIGURATION1 DSI_REG(0x300 + 0x000C)
100#define DSI_PLL_CONFIGURATION2 DSI_REG(0x300 + 0x0010)
101
102#define REG_GET(idx, start, end) \
103 FLD_GET(dsi_read_reg(idx), start, end)
104
105#define REG_FLD_MOD(idx, val, start, end) \
106 dsi_write_reg(idx, FLD_MOD(dsi_read_reg(idx), val, start, end))
107
108/* Global interrupts */
109#define DSI_IRQ_VC0 (1 << 0)
110#define DSI_IRQ_VC1 (1 << 1)
111#define DSI_IRQ_VC2 (1 << 2)
112#define DSI_IRQ_VC3 (1 << 3)
113#define DSI_IRQ_WAKEUP (1 << 4)
114#define DSI_IRQ_RESYNC (1 << 5)
115#define DSI_IRQ_PLL_LOCK (1 << 7)
116#define DSI_IRQ_PLL_UNLOCK (1 << 8)
117#define DSI_IRQ_PLL_RECALL (1 << 9)
118#define DSI_IRQ_COMPLEXIO_ERR (1 << 10)
119#define DSI_IRQ_HS_TX_TIMEOUT (1 << 14)
120#define DSI_IRQ_LP_RX_TIMEOUT (1 << 15)
121#define DSI_IRQ_TE_TRIGGER (1 << 16)
122#define DSI_IRQ_ACK_TRIGGER (1 << 17)
123#define DSI_IRQ_SYNC_LOST (1 << 18)
124#define DSI_IRQ_LDO_POWER_GOOD (1 << 19)
125#define DSI_IRQ_TA_TIMEOUT (1 << 20)
126#define DSI_IRQ_ERROR_MASK \
127 (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \
128 DSI_IRQ_TA_TIMEOUT)
129#define DSI_IRQ_CHANNEL_MASK 0xf
130
131/* Virtual channel interrupts */
132#define DSI_VC_IRQ_CS (1 << 0)
133#define DSI_VC_IRQ_ECC_CORR (1 << 1)
134#define DSI_VC_IRQ_PACKET_SENT (1 << 2)
135#define DSI_VC_IRQ_FIFO_TX_OVF (1 << 3)
136#define DSI_VC_IRQ_FIFO_RX_OVF (1 << 4)
137#define DSI_VC_IRQ_BTA (1 << 5)
138#define DSI_VC_IRQ_ECC_NO_CORR (1 << 6)
139#define DSI_VC_IRQ_FIFO_TX_UDF (1 << 7)
140#define DSI_VC_IRQ_PP_BUSY_CHANGE (1 << 8)
141#define DSI_VC_IRQ_ERROR_MASK \
142 (DSI_VC_IRQ_CS | DSI_VC_IRQ_ECC_CORR | DSI_VC_IRQ_FIFO_TX_OVF | \
143 DSI_VC_IRQ_FIFO_RX_OVF | DSI_VC_IRQ_ECC_NO_CORR | \
144 DSI_VC_IRQ_FIFO_TX_UDF)
145
146/* ComplexIO interrupts */
147#define DSI_CIO_IRQ_ERRSYNCESC1 (1 << 0)
148#define DSI_CIO_IRQ_ERRSYNCESC2 (1 << 1)
149#define DSI_CIO_IRQ_ERRSYNCESC3 (1 << 2)
150#define DSI_CIO_IRQ_ERRESC1 (1 << 5)
151#define DSI_CIO_IRQ_ERRESC2 (1 << 6)
152#define DSI_CIO_IRQ_ERRESC3 (1 << 7)
153#define DSI_CIO_IRQ_ERRCONTROL1 (1 << 10)
154#define DSI_CIO_IRQ_ERRCONTROL2 (1 << 11)
155#define DSI_CIO_IRQ_ERRCONTROL3 (1 << 12)
156#define DSI_CIO_IRQ_STATEULPS1 (1 << 15)
157#define DSI_CIO_IRQ_STATEULPS2 (1 << 16)
158#define DSI_CIO_IRQ_STATEULPS3 (1 << 17)
159#define DSI_CIO_IRQ_ERRCONTENTIONLP0_1 (1 << 20)
160#define DSI_CIO_IRQ_ERRCONTENTIONLP1_1 (1 << 21)
161#define DSI_CIO_IRQ_ERRCONTENTIONLP0_2 (1 << 22)
162#define DSI_CIO_IRQ_ERRCONTENTIONLP1_2 (1 << 23)
163#define DSI_CIO_IRQ_ERRCONTENTIONLP0_3 (1 << 24)
164#define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25)
165#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30)
166#define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31)
167
168#define DSI_DT_DCS_SHORT_WRITE_0 0x05
169#define DSI_DT_DCS_SHORT_WRITE_1 0x15
170#define DSI_DT_DCS_READ 0x06
171#define DSI_DT_SET_MAX_RET_PKG_SIZE 0x37
172#define DSI_DT_NULL_PACKET 0x09
173#define DSI_DT_DCS_LONG_WRITE 0x39
174
175#define DSI_DT_RX_ACK_WITH_ERR 0x02
176#define DSI_DT_RX_DCS_LONG_READ 0x1c
177#define DSI_DT_RX_SHORT_READ_1 0x21
178#define DSI_DT_RX_SHORT_READ_2 0x22
179
180#define FINT_MAX 2100000
181#define FINT_MIN 750000
182#define REGN_MAX (1 << 7)
183#define REGM_MAX ((1 << 11) - 1)
184#define REGM3_MAX (1 << 4)
185#define REGM4_MAX (1 << 4)
186#define LP_DIV_MAX ((1 << 13) - 1)
187
188enum fifo_size {
189 DSI_FIFO_SIZE_0 = 0,
190 DSI_FIFO_SIZE_32 = 1,
191 DSI_FIFO_SIZE_64 = 2,
192 DSI_FIFO_SIZE_96 = 3,
193 DSI_FIFO_SIZE_128 = 4,
194};
195
196enum dsi_vc_mode {
197 DSI_VC_MODE_L4 = 0,
198 DSI_VC_MODE_VP,
199};
200
201struct dsi_update_region {
202 bool dirty;
203 u16 x, y, w, h;
204 struct omap_dss_device *device;
205};
206
207struct dsi_irq_stats {
208 unsigned long last_reset;
209 unsigned irq_count;
210 unsigned dsi_irqs[32];
211 unsigned vc_irqs[4][32];
212 unsigned cio_irqs[32];
213};
214
215static struct
216{
217 void __iomem *base;
218
219 struct dsi_clock_info current_cinfo;
220
221 struct regulator *vdds_dsi_reg;
222
223 struct {
224 enum dsi_vc_mode mode;
225 struct omap_dss_device *dssdev;
226 enum fifo_size fifo_size;
227 int dest_per; /* destination peripheral 0-3 */
228 } vc[4];
229
230 struct mutex lock;
231 struct mutex bus_lock;
232
233 unsigned pll_locked;
234
235 struct completion bta_completion;
236
237 struct task_struct *thread;
238 wait_queue_head_t waitqueue;
239
240 spinlock_t update_lock;
241 bool framedone_received;
242 struct dsi_update_region update_region;
243 struct dsi_update_region active_update_region;
244 struct completion update_completion;
245
246 enum omap_dss_update_mode user_update_mode;
247 enum omap_dss_update_mode update_mode;
248 bool te_enabled;
249 bool use_ext_te;
250
251#ifdef DSI_CATCH_MISSING_TE
252 struct timer_list te_timer;
253#endif
254
255 unsigned long cache_req_pck;
256 unsigned long cache_clk_freq;
257 struct dsi_clock_info cache_cinfo;
258
259 u32 errors;
260 spinlock_t errors_lock;
261#ifdef DEBUG
262 ktime_t perf_setup_time;
263 ktime_t perf_start_time;
264 ktime_t perf_start_time_auto;
265 int perf_measure_frames;
266#endif
267 int debug_read;
268 int debug_write;
269
270#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
271 spinlock_t irq_stats_lock;
272 struct dsi_irq_stats irq_stats;
273#endif
274} dsi;
275
276#ifdef DEBUG
277static unsigned int dsi_perf;
278module_param_named(dsi_perf, dsi_perf, bool, 0644);
279#endif
280
281static inline void dsi_write_reg(const struct dsi_reg idx, u32 val)
282{
283 __raw_writel(val, dsi.base + idx.idx);
284}
285
286static inline u32 dsi_read_reg(const struct dsi_reg idx)
287{
288 return __raw_readl(dsi.base + idx.idx);
289}
290
291
292void dsi_save_context(void)
293{
294}
295
296void dsi_restore_context(void)
297{
298}
299
300void dsi_bus_lock(void)
301{
302 mutex_lock(&dsi.bus_lock);
303}
304EXPORT_SYMBOL(dsi_bus_lock);
305
306void dsi_bus_unlock(void)
307{
308 mutex_unlock(&dsi.bus_lock);
309}
310EXPORT_SYMBOL(dsi_bus_unlock);
311
312static inline int wait_for_bit_change(const struct dsi_reg idx, int bitnum,
313 int value)
314{
315 int t = 100000;
316
317 while (REG_GET(idx, bitnum, bitnum) != value) {
318 if (--t == 0)
319 return !value;
320 }
321
322 return value;
323}
324
325#ifdef DEBUG
326static void dsi_perf_mark_setup(void)
327{
328 dsi.perf_setup_time = ktime_get();
329}
330
331static void dsi_perf_mark_start(void)
332{
333 dsi.perf_start_time = ktime_get();
334}
335
336static void dsi_perf_mark_start_auto(void)
337{
338 dsi.perf_measure_frames = 0;
339 dsi.perf_start_time_auto = ktime_get();
340}
341
342static void dsi_perf_show(const char *name)
343{
344 ktime_t t, setup_time, trans_time;
345 u32 total_bytes;
346 u32 setup_us, trans_us, total_us;
347
348 if (!dsi_perf)
349 return;
350
351 if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED)
352 return;
353
354 t = ktime_get();
355
356 setup_time = ktime_sub(dsi.perf_start_time, dsi.perf_setup_time);
357 setup_us = (u32)ktime_to_us(setup_time);
358 if (setup_us == 0)
359 setup_us = 1;
360
361 trans_time = ktime_sub(t, dsi.perf_start_time);
362 trans_us = (u32)ktime_to_us(trans_time);
363 if (trans_us == 0)
364 trans_us = 1;
365
366 total_us = setup_us + trans_us;
367
368 total_bytes = dsi.active_update_region.w *
369 dsi.active_update_region.h *
370 dsi.active_update_region.device->ctrl.pixel_size / 8;
371
372 if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
373 static u32 s_total_trans_us, s_total_setup_us;
374 static u32 s_min_trans_us = 0xffffffff, s_min_setup_us;
375 static u32 s_max_trans_us, s_max_setup_us;
376 const int numframes = 100;
377 ktime_t total_time_auto;
378 u32 total_time_auto_us;
379
380 dsi.perf_measure_frames++;
381
382 if (setup_us < s_min_setup_us)
383 s_min_setup_us = setup_us;
384
385 if (setup_us > s_max_setup_us)
386 s_max_setup_us = setup_us;
387
388 s_total_setup_us += setup_us;
389
390 if (trans_us < s_min_trans_us)
391 s_min_trans_us = trans_us;
392
393 if (trans_us > s_max_trans_us)
394 s_max_trans_us = trans_us;
395
396 s_total_trans_us += trans_us;
397
398 if (dsi.perf_measure_frames < numframes)
399 return;
400
401 total_time_auto = ktime_sub(t, dsi.perf_start_time_auto);
402 total_time_auto_us = (u32)ktime_to_us(total_time_auto);
403
404 printk(KERN_INFO "DSI(%s): %u fps, setup %u/%u/%u, "
405 "trans %u/%u/%u\n",
406 name,
407 1000 * 1000 * numframes / total_time_auto_us,
408 s_min_setup_us,
409 s_max_setup_us,
410 s_total_setup_us / numframes,
411 s_min_trans_us,
412 s_max_trans_us,
413 s_total_trans_us / numframes);
414
415 s_total_setup_us = 0;
416 s_min_setup_us = 0xffffffff;
417 s_max_setup_us = 0;
418 s_total_trans_us = 0;
419 s_min_trans_us = 0xffffffff;
420 s_max_trans_us = 0;
421 dsi_perf_mark_start_auto();
422 } else {
423 printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), "
424 "%u bytes, %u kbytes/sec\n",
425 name,
426 setup_us,
427 trans_us,
428 total_us,
429 1000*1000 / total_us,
430 total_bytes,
431 total_bytes * 1000 / total_us);
432 }
433}
434#else
435#define dsi_perf_mark_setup()
436#define dsi_perf_mark_start()
437#define dsi_perf_mark_start_auto()
438#define dsi_perf_show(x)
439#endif
440
441static void print_irq_status(u32 status)
442{
443#ifndef VERBOSE_IRQ
444 if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0)
445 return;
446#endif
447 printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status);
448
449#define PIS(x) \
450 if (status & DSI_IRQ_##x) \
451 printk(#x " ");
452#ifdef VERBOSE_IRQ
453 PIS(VC0);
454 PIS(VC1);
455 PIS(VC2);
456 PIS(VC3);
457#endif
458 PIS(WAKEUP);
459 PIS(RESYNC);
460 PIS(PLL_LOCK);
461 PIS(PLL_UNLOCK);
462 PIS(PLL_RECALL);
463 PIS(COMPLEXIO_ERR);
464 PIS(HS_TX_TIMEOUT);
465 PIS(LP_RX_TIMEOUT);
466 PIS(TE_TRIGGER);
467 PIS(ACK_TRIGGER);
468 PIS(SYNC_LOST);
469 PIS(LDO_POWER_GOOD);
470 PIS(TA_TIMEOUT);
471#undef PIS
472
473 printk("\n");
474}
475
476static void print_irq_status_vc(int channel, u32 status)
477{
478#ifndef VERBOSE_IRQ
479 if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0)
480 return;
481#endif
482 printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status);
483
484#define PIS(x) \
485 if (status & DSI_VC_IRQ_##x) \
486 printk(#x " ");
487 PIS(CS);
488 PIS(ECC_CORR);
489#ifdef VERBOSE_IRQ
490 PIS(PACKET_SENT);
491#endif
492 PIS(FIFO_TX_OVF);
493 PIS(FIFO_RX_OVF);
494 PIS(BTA);
495 PIS(ECC_NO_CORR);
496 PIS(FIFO_TX_UDF);
497 PIS(PP_BUSY_CHANGE);
498#undef PIS
499 printk("\n");
500}
501
502static void print_irq_status_cio(u32 status)
503{
504 printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status);
505
506#define PIS(x) \
507 if (status & DSI_CIO_IRQ_##x) \
508 printk(#x " ");
509 PIS(ERRSYNCESC1);
510 PIS(ERRSYNCESC2);
511 PIS(ERRSYNCESC3);
512 PIS(ERRESC1);
513 PIS(ERRESC2);
514 PIS(ERRESC3);
515 PIS(ERRCONTROL1);
516 PIS(ERRCONTROL2);
517 PIS(ERRCONTROL3);
518 PIS(STATEULPS1);
519 PIS(STATEULPS2);
520 PIS(STATEULPS3);
521 PIS(ERRCONTENTIONLP0_1);
522 PIS(ERRCONTENTIONLP1_1);
523 PIS(ERRCONTENTIONLP0_2);
524 PIS(ERRCONTENTIONLP1_2);
525 PIS(ERRCONTENTIONLP0_3);
526 PIS(ERRCONTENTIONLP1_3);
527 PIS(ULPSACTIVENOT_ALL0);
528 PIS(ULPSACTIVENOT_ALL1);
529#undef PIS
530
531 printk("\n");
532}
533
534static int debug_irq;
535
536/* called from dss */
537void dsi_irq_handler(void)
538{
539 u32 irqstatus, vcstatus, ciostatus;
540 int i;
541
542 irqstatus = dsi_read_reg(DSI_IRQSTATUS);
543
544#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
545 spin_lock(&dsi.irq_stats_lock);
546 dsi.irq_stats.irq_count++;
547 dss_collect_irq_stats(irqstatus, dsi.irq_stats.dsi_irqs);
548#endif
549
550 if (irqstatus & DSI_IRQ_ERROR_MASK) {
551 DSSERR("DSI error, irqstatus %x\n", irqstatus);
552 print_irq_status(irqstatus);
553 spin_lock(&dsi.errors_lock);
554 dsi.errors |= irqstatus & DSI_IRQ_ERROR_MASK;
555 spin_unlock(&dsi.errors_lock);
556 } else if (debug_irq) {
557 print_irq_status(irqstatus);
558 }
559
560#ifdef DSI_CATCH_MISSING_TE
561 if (irqstatus & DSI_IRQ_TE_TRIGGER)
562 del_timer(&dsi.te_timer);
563#endif
564
565 for (i = 0; i < 4; ++i) {
566 if ((irqstatus & (1<<i)) == 0)
567 continue;
568
569 vcstatus = dsi_read_reg(DSI_VC_IRQSTATUS(i));
570
571#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
572 dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]);
573#endif
574
575 if (vcstatus & DSI_VC_IRQ_BTA)
576 complete(&dsi.bta_completion);
577
578 if (vcstatus & DSI_VC_IRQ_ERROR_MASK) {
579 DSSERR("DSI VC(%d) error, vc irqstatus %x\n",
580 i, vcstatus);
581 print_irq_status_vc(i, vcstatus);
582 } else if (debug_irq) {
583 print_irq_status_vc(i, vcstatus);
584 }
585
586 dsi_write_reg(DSI_VC_IRQSTATUS(i), vcstatus);
587 /* flush posted write */
588 dsi_read_reg(DSI_VC_IRQSTATUS(i));
589 }
590
591 if (irqstatus & DSI_IRQ_COMPLEXIO_ERR) {
592 ciostatus = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
593
594#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
595 dss_collect_irq_stats(ciostatus, dsi.irq_stats.cio_irqs);
596#endif
597
598 dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, ciostatus);
599 /* flush posted write */
600 dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
601
602 DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus);
603 print_irq_status_cio(ciostatus);
604 }
605
606 dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK);
607 /* flush posted write */
608 dsi_read_reg(DSI_IRQSTATUS);
609
610#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
611 spin_unlock(&dsi.irq_stats_lock);
612#endif
613}
614
615
616static void _dsi_initialize_irq(void)
617{
618 u32 l;
619 int i;
620
621 /* disable all interrupts */
622 dsi_write_reg(DSI_IRQENABLE, 0);
623 for (i = 0; i < 4; ++i)
624 dsi_write_reg(DSI_VC_IRQENABLE(i), 0);
625 dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, 0);
626
627 /* clear interrupt status */
628 l = dsi_read_reg(DSI_IRQSTATUS);
629 dsi_write_reg(DSI_IRQSTATUS, l & ~DSI_IRQ_CHANNEL_MASK);
630
631 for (i = 0; i < 4; ++i) {
632 l = dsi_read_reg(DSI_VC_IRQSTATUS(i));
633 dsi_write_reg(DSI_VC_IRQSTATUS(i), l);
634 }
635
636 l = dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS);
637 dsi_write_reg(DSI_COMPLEXIO_IRQ_STATUS, l);
638
639 /* enable error irqs */
640 l = DSI_IRQ_ERROR_MASK;
641#ifdef DSI_CATCH_MISSING_TE
642 l |= DSI_IRQ_TE_TRIGGER;
643#endif
644 dsi_write_reg(DSI_IRQENABLE, l);
645
646 l = DSI_VC_IRQ_ERROR_MASK;
647 for (i = 0; i < 4; ++i)
648 dsi_write_reg(DSI_VC_IRQENABLE(i), l);
649
650 /* XXX zonda responds incorrectly, causing control error:
651 Exit from LP-ESC mode to LP11 uses wrong transition states on the
652 data lines LP0 and LN0. */
653 dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE,
654 -1 & (~DSI_CIO_IRQ_ERRCONTROL2));
655}
656
657static u32 dsi_get_errors(void)
658{
659 unsigned long flags;
660 u32 e;
661 spin_lock_irqsave(&dsi.errors_lock, flags);
662 e = dsi.errors;
663 dsi.errors = 0;
664 spin_unlock_irqrestore(&dsi.errors_lock, flags);
665 return e;
666}
667
668static void dsi_vc_enable_bta_irq(int channel)
669{
670 u32 l;
671
672 dsi_write_reg(DSI_VC_IRQSTATUS(channel), DSI_VC_IRQ_BTA);
673
674 l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
675 l |= DSI_VC_IRQ_BTA;
676 dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
677}
678
679static void dsi_vc_disable_bta_irq(int channel)
680{
681 u32 l;
682
683 l = dsi_read_reg(DSI_VC_IRQENABLE(channel));
684 l &= ~DSI_VC_IRQ_BTA;
685 dsi_write_reg(DSI_VC_IRQENABLE(channel), l);
686}
687
688/* DSI func clock. this could also be DSI2_PLL_FCLK */
689static inline void enable_clocks(bool enable)
690{
691 if (enable)
692 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
693 else
694 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
695}
696
697/* source clock for DSI PLL. this could also be PCLKFREE */
698static inline void dsi_enable_pll_clock(bool enable)
699{
700 if (enable)
701 dss_clk_enable(DSS_CLK_FCK2);
702 else
703 dss_clk_disable(DSS_CLK_FCK2);
704
705 if (enable && dsi.pll_locked) {
706 if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1)
707 DSSERR("cannot lock PLL when enabling clocks\n");
708 }
709}
710
711#ifdef DEBUG
712static void _dsi_print_reset_status(void)
713{
714 u32 l;
715
716 if (!dss_debug)
717 return;
718
719 /* A dummy read using the SCP interface to any DSIPHY register is
720 * required after DSIPHY reset to complete the reset of the DSI complex
721 * I/O. */
722 l = dsi_read_reg(DSI_DSIPHY_CFG5);
723
724 printk(KERN_DEBUG "DSI resets: ");
725
726 l = dsi_read_reg(DSI_PLL_STATUS);
727 printk("PLL (%d) ", FLD_GET(l, 0, 0));
728
729 l = dsi_read_reg(DSI_COMPLEXIO_CFG1);
730 printk("CIO (%d) ", FLD_GET(l, 29, 29));
731
732 l = dsi_read_reg(DSI_DSIPHY_CFG5);
733 printk("PHY (%x, %d, %d, %d)\n",
734 FLD_GET(l, 28, 26),
735 FLD_GET(l, 29, 29),
736 FLD_GET(l, 30, 30),
737 FLD_GET(l, 31, 31));
738}
739#else
740#define _dsi_print_reset_status()
741#endif
742
743static inline int dsi_if_enable(bool enable)
744{
745 DSSDBG("dsi_if_enable(%d)\n", enable);
746
747 enable = enable ? 1 : 0;
748 REG_FLD_MOD(DSI_CTRL, enable, 0, 0); /* IF_EN */
749
750 if (wait_for_bit_change(DSI_CTRL, 0, enable) != enable) {
751 DSSERR("Failed to set dsi_if_enable to %d\n", enable);
752 return -EIO;
753 }
754
755 return 0;
756}
757
758unsigned long dsi_get_dsi1_pll_rate(void)
759{
760 return dsi.current_cinfo.dsi1_pll_fclk;
761}
762
763static unsigned long dsi_get_dsi2_pll_rate(void)
764{
765 return dsi.current_cinfo.dsi2_pll_fclk;
766}
767
768static unsigned long dsi_get_txbyteclkhs(void)
769{
770 return dsi.current_cinfo.clkin4ddr / 16;
771}
772
773static unsigned long dsi_fclk_rate(void)
774{
775 unsigned long r;
776
777 if (dss_get_dsi_clk_source() == 0) {
778 /* DSI FCLK source is DSS1_ALWON_FCK, which is dss1_fck */
779 r = dss_clk_get_rate(DSS_CLK_FCK1);
780 } else {
781 /* DSI FCLK source is DSI2_PLL_FCLK */
782 r = dsi_get_dsi2_pll_rate();
783 }
784
785 return r;
786}
787
788static int dsi_set_lp_clk_divisor(struct omap_dss_device *dssdev)
789{
790 unsigned long dsi_fclk;
791 unsigned lp_clk_div;
792 unsigned long lp_clk;
793
794 lp_clk_div = dssdev->phy.dsi.div.lp_clk_div;
795
796 if (lp_clk_div == 0 || lp_clk_div > LP_DIV_MAX)
797 return -EINVAL;
798
799 dsi_fclk = dsi_fclk_rate();
800
801 lp_clk = dsi_fclk / 2 / lp_clk_div;
802
803 DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
804 dsi.current_cinfo.lp_clk = lp_clk;
805 dsi.current_cinfo.lp_clk_div = lp_clk_div;
806
807 REG_FLD_MOD(DSI_CLK_CTRL, lp_clk_div, 12, 0); /* LP_CLK_DIVISOR */
808
809 REG_FLD_MOD(DSI_CLK_CTRL, dsi_fclk > 30000000 ? 1 : 0,
810 21, 21); /* LP_RX_SYNCHRO_ENABLE */
811
812 return 0;
813}
814
815
816enum dsi_pll_power_state {
817 DSI_PLL_POWER_OFF = 0x0,
818 DSI_PLL_POWER_ON_HSCLK = 0x1,
819 DSI_PLL_POWER_ON_ALL = 0x2,
820 DSI_PLL_POWER_ON_DIV = 0x3,
821};
822
823static int dsi_pll_power(enum dsi_pll_power_state state)
824{
825 int t = 0;
826
827 REG_FLD_MOD(DSI_CLK_CTRL, state, 31, 30); /* PLL_PWR_CMD */
828
829 /* PLL_PWR_STATUS */
830 while (FLD_GET(dsi_read_reg(DSI_CLK_CTRL), 29, 28) != state) {
831 if (++t > 1000) {
832 DSSERR("Failed to set DSI PLL power mode to %d\n",
833 state);
834 return -ENODEV;
835 }
836 udelay(1);
837 }
838
839 return 0;
840}
841
842/* calculate clock rates using dividers in cinfo */
843static int dsi_calc_clock_rates(struct dsi_clock_info *cinfo)
844{
845 if (cinfo->regn == 0 || cinfo->regn > REGN_MAX)
846 return -EINVAL;
847
848 if (cinfo->regm == 0 || cinfo->regm > REGM_MAX)
849 return -EINVAL;
850
851 if (cinfo->regm3 > REGM3_MAX)
852 return -EINVAL;
853
854 if (cinfo->regm4 > REGM4_MAX)
855 return -EINVAL;
856
857 if (cinfo->use_dss2_fck) {
858 cinfo->clkin = dss_clk_get_rate(DSS_CLK_FCK2);
859 /* XXX it is unclear if highfreq should be used
860 * with DSS2_FCK source also */
861 cinfo->highfreq = 0;
862 } else {
863 cinfo->clkin = dispc_pclk_rate();
864
865 if (cinfo->clkin < 32000000)
866 cinfo->highfreq = 0;
867 else
868 cinfo->highfreq = 1;
869 }
870
871 cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1));
872
873 if (cinfo->fint > FINT_MAX || cinfo->fint < FINT_MIN)
874 return -EINVAL;
875
876 cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
877
878 if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
879 return -EINVAL;
880
881 if (cinfo->regm3 > 0)
882 cinfo->dsi1_pll_fclk = cinfo->clkin4ddr / cinfo->regm3;
883 else
884 cinfo->dsi1_pll_fclk = 0;
885
886 if (cinfo->regm4 > 0)
887 cinfo->dsi2_pll_fclk = cinfo->clkin4ddr / cinfo->regm4;
888 else
889 cinfo->dsi2_pll_fclk = 0;
890
891 return 0;
892}
893
894int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
895 struct dsi_clock_info *dsi_cinfo,
896 struct dispc_clock_info *dispc_cinfo)
897{
898 struct dsi_clock_info cur, best;
899 struct dispc_clock_info best_dispc;
900 int min_fck_per_pck;
901 int match = 0;
902 unsigned long dss_clk_fck2;
903
904 dss_clk_fck2 = dss_clk_get_rate(DSS_CLK_FCK2);
905
906 if (req_pck == dsi.cache_req_pck &&
907 dsi.cache_cinfo.clkin == dss_clk_fck2) {
908 DSSDBG("DSI clock info found from cache\n");
909 *dsi_cinfo = dsi.cache_cinfo;
910 dispc_find_clk_divs(is_tft, req_pck, dsi_cinfo->dsi1_pll_fclk,
911 dispc_cinfo);
912 return 0;
913 }
914
915 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
916
917 if (min_fck_per_pck &&
918 req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
919 DSSERR("Requested pixel clock not possible with the current "
920 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
921 "the constraint off.\n");
922 min_fck_per_pck = 0;
923 }
924
925 DSSDBG("dsi_pll_calc\n");
926
927retry:
928 memset(&best, 0, sizeof(best));
929 memset(&best_dispc, 0, sizeof(best_dispc));
930
931 memset(&cur, 0, sizeof(cur));
932 cur.clkin = dss_clk_fck2;
933 cur.use_dss2_fck = 1;
934 cur.highfreq = 0;
935
936 /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */
937 /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */
938 /* To reduce PLL lock time, keep Fint high (around 2 MHz) */
939 for (cur.regn = 1; cur.regn < REGN_MAX; ++cur.regn) {
940 if (cur.highfreq == 0)
941 cur.fint = cur.clkin / cur.regn;
942 else
943 cur.fint = cur.clkin / (2 * cur.regn);
944
945 if (cur.fint > FINT_MAX || cur.fint < FINT_MIN)
946 continue;
947
948 /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */
949 for (cur.regm = 1; cur.regm < REGM_MAX; ++cur.regm) {
950 unsigned long a, b;
951
952 a = 2 * cur.regm * (cur.clkin/1000);
953 b = cur.regn * (cur.highfreq + 1);
954 cur.clkin4ddr = a / b * 1000;
955
956 if (cur.clkin4ddr > 1800 * 1000 * 1000)
957 break;
958
959 /* DSI1_PLL_FCLK(MHz) = DSIPHY(MHz) / regm3 < 173MHz */
960 for (cur.regm3 = 1; cur.regm3 < REGM3_MAX;
961 ++cur.regm3) {
962 struct dispc_clock_info cur_dispc;
963 cur.dsi1_pll_fclk = cur.clkin4ddr / cur.regm3;
964
965 /* this will narrow down the search a bit,
966 * but still give pixclocks below what was
967 * requested */
968 if (cur.dsi1_pll_fclk < req_pck)
969 break;
970
971 if (cur.dsi1_pll_fclk > DISPC_MAX_FCK)
972 continue;
973
974 if (min_fck_per_pck &&
975 cur.dsi1_pll_fclk <
976 req_pck * min_fck_per_pck)
977 continue;
978
979 match = 1;
980
981 dispc_find_clk_divs(is_tft, req_pck,
982 cur.dsi1_pll_fclk,
983 &cur_dispc);
984
985 if (abs(cur_dispc.pck - req_pck) <
986 abs(best_dispc.pck - req_pck)) {
987 best = cur;
988 best_dispc = cur_dispc;
989
990 if (cur_dispc.pck == req_pck)
991 goto found;
992 }
993 }
994 }
995 }
996found:
997 if (!match) {
998 if (min_fck_per_pck) {
999 DSSERR("Could not find suitable clock settings.\n"
1000 "Turning FCK/PCK constraint off and"
1001 "trying again.\n");
1002 min_fck_per_pck = 0;
1003 goto retry;
1004 }
1005
1006 DSSERR("Could not find suitable clock settings.\n");
1007
1008 return -EINVAL;
1009 }
1010
1011 /* DSI2_PLL_FCLK (regm4) is not used */
1012 best.regm4 = 0;
1013 best.dsi2_pll_fclk = 0;
1014
1015 if (dsi_cinfo)
1016 *dsi_cinfo = best;
1017 if (dispc_cinfo)
1018 *dispc_cinfo = best_dispc;
1019
1020 dsi.cache_req_pck = req_pck;
1021 dsi.cache_clk_freq = 0;
1022 dsi.cache_cinfo = best;
1023
1024 return 0;
1025}
1026
1027int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo)
1028{
1029 int r = 0;
1030 u32 l;
1031 int f;
1032
1033 DSSDBGF();
1034
1035 dsi.current_cinfo.fint = cinfo->fint;
1036 dsi.current_cinfo.clkin4ddr = cinfo->clkin4ddr;
1037 dsi.current_cinfo.dsi1_pll_fclk = cinfo->dsi1_pll_fclk;
1038 dsi.current_cinfo.dsi2_pll_fclk = cinfo->dsi2_pll_fclk;
1039
1040 dsi.current_cinfo.regn = cinfo->regn;
1041 dsi.current_cinfo.regm = cinfo->regm;
1042 dsi.current_cinfo.regm3 = cinfo->regm3;
1043 dsi.current_cinfo.regm4 = cinfo->regm4;
1044
1045 DSSDBG("DSI Fint %ld\n", cinfo->fint);
1046
1047 DSSDBG("clkin (%s) rate %ld, highfreq %d\n",
1048 cinfo->use_dss2_fck ? "dss2_fck" : "pclkfree",
1049 cinfo->clkin,
1050 cinfo->highfreq);
1051
1052 /* DSIPHY == CLKIN4DDR */
1053 DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu / %d = %lu\n",
1054 cinfo->regm,
1055 cinfo->regn,
1056 cinfo->clkin,
1057 cinfo->highfreq + 1,
1058 cinfo->clkin4ddr);
1059
1060 DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
1061 cinfo->clkin4ddr / 1000 / 1000 / 2);
1062
1063 DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
1064
1065 DSSDBG("regm3 = %d, dsi1_pll_fclk = %lu\n",
1066 cinfo->regm3, cinfo->dsi1_pll_fclk);
1067 DSSDBG("regm4 = %d, dsi2_pll_fclk = %lu\n",
1068 cinfo->regm4, cinfo->dsi2_pll_fclk);
1069
1070 REG_FLD_MOD(DSI_PLL_CONTROL, 0, 0, 0); /* DSI_PLL_AUTOMODE = manual */
1071
1072 l = dsi_read_reg(DSI_PLL_CONFIGURATION1);
1073 l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
1074 l = FLD_MOD(l, cinfo->regn - 1, 7, 1); /* DSI_PLL_REGN */
1075 l = FLD_MOD(l, cinfo->regm, 18, 8); /* DSI_PLL_REGM */
1076 l = FLD_MOD(l, cinfo->regm3 > 0 ? cinfo->regm3 - 1 : 0,
1077 22, 19); /* DSI_CLOCK_DIV */
1078 l = FLD_MOD(l, cinfo->regm4 > 0 ? cinfo->regm4 - 1 : 0,
1079 26, 23); /* DSIPROTO_CLOCK_DIV */
1080 dsi_write_reg(DSI_PLL_CONFIGURATION1, l);
1081
1082 BUG_ON(cinfo->fint < 750000 || cinfo->fint > 2100000);
1083 if (cinfo->fint < 1000000)
1084 f = 0x3;
1085 else if (cinfo->fint < 1250000)
1086 f = 0x4;
1087 else if (cinfo->fint < 1500000)
1088 f = 0x5;
1089 else if (cinfo->fint < 1750000)
1090 f = 0x6;
1091 else
1092 f = 0x7;
1093
1094 l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
1095 l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
1096 l = FLD_MOD(l, cinfo->use_dss2_fck ? 0 : 1,
1097 11, 11); /* DSI_PLL_CLKSEL */
1098 l = FLD_MOD(l, cinfo->highfreq,
1099 12, 12); /* DSI_PLL_HIGHFREQ */
1100 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1101 l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
1102 l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
1103 dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
1104
1105 REG_FLD_MOD(DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
1106
1107 if (wait_for_bit_change(DSI_PLL_GO, 0, 0) != 0) {
1108 DSSERR("dsi pll go bit not going down.\n");
1109 r = -EIO;
1110 goto err;
1111 }
1112
1113 if (wait_for_bit_change(DSI_PLL_STATUS, 1, 1) != 1) {
1114 DSSERR("cannot lock PLL\n");
1115 r = -EIO;
1116 goto err;
1117 }
1118
1119 dsi.pll_locked = 1;
1120
1121 l = dsi_read_reg(DSI_PLL_CONFIGURATION2);
1122 l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
1123 l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
1124 l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
1125 l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
1126 l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
1127 l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
1128 l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
1129 l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */
1130 l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */
1131 l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */
1132 l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */
1133 l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
1134 l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
1135 l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
1136 dsi_write_reg(DSI_PLL_CONFIGURATION2, l);
1137
1138 DSSDBG("PLL config done\n");
1139err:
1140 return r;
1141}
1142
1143int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
1144 bool enable_hsdiv)
1145{
1146 int r = 0;
1147 enum dsi_pll_power_state pwstate;
1148
1149 DSSDBG("PLL init\n");
1150
1151 enable_clocks(1);
1152 dsi_enable_pll_clock(1);
1153
1154 r = regulator_enable(dsi.vdds_dsi_reg);
1155 if (r)
1156 goto err0;
1157
1158 /* XXX PLL does not come out of reset without this... */
1159 dispc_pck_free_enable(1);
1160
1161 if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) {
1162 DSSERR("PLL not coming out of reset.\n");
1163 r = -ENODEV;
1164 goto err1;
1165 }
1166
1167 /* XXX ... but if left on, we get problems when planes do not
1168 * fill the whole display. No idea about this */
1169 dispc_pck_free_enable(0);
1170
1171 if (enable_hsclk && enable_hsdiv)
1172 pwstate = DSI_PLL_POWER_ON_ALL;
1173 else if (enable_hsclk)
1174 pwstate = DSI_PLL_POWER_ON_HSCLK;
1175 else if (enable_hsdiv)
1176 pwstate = DSI_PLL_POWER_ON_DIV;
1177 else
1178 pwstate = DSI_PLL_POWER_OFF;
1179
1180 r = dsi_pll_power(pwstate);
1181
1182 if (r)
1183 goto err1;
1184
1185 DSSDBG("PLL init done\n");
1186
1187 return 0;
1188err1:
1189 regulator_disable(dsi.vdds_dsi_reg);
1190err0:
1191 enable_clocks(0);
1192 dsi_enable_pll_clock(0);
1193 return r;
1194}
1195
1196void dsi_pll_uninit(void)
1197{
1198 enable_clocks(0);
1199 dsi_enable_pll_clock(0);
1200
1201 dsi.pll_locked = 0;
1202 dsi_pll_power(DSI_PLL_POWER_OFF);
1203 regulator_disable(dsi.vdds_dsi_reg);
1204 DSSDBG("PLL uninit done\n");
1205}
1206
1207void dsi_dump_clocks(struct seq_file *s)
1208{
1209 int clksel;
1210 struct dsi_clock_info *cinfo = &dsi.current_cinfo;
1211
1212 enable_clocks(1);
1213
1214 clksel = REG_GET(DSI_PLL_CONFIGURATION2, 11, 11);
1215
1216 seq_printf(s, "- DSI PLL -\n");
1217
1218 seq_printf(s, "dsi pll source = %s\n",
1219 clksel == 0 ?
1220 "dss2_alwon_fclk" : "pclkfree");
1221
1222 seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
1223
1224 seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n",
1225 cinfo->clkin4ddr, cinfo->regm);
1226
1227 seq_printf(s, "dsi1_pll_fck\t%-16luregm3 %u\t(%s)\n",
1228 cinfo->dsi1_pll_fclk,
1229 cinfo->regm3,
1230 dss_get_dispc_clk_source() == 0 ? "off" : "on");
1231
1232 seq_printf(s, "dsi2_pll_fck\t%-16luregm4 %u\t(%s)\n",
1233 cinfo->dsi2_pll_fclk,
1234 cinfo->regm4,
1235 dss_get_dsi_clk_source() == 0 ? "off" : "on");
1236
1237 seq_printf(s, "- DSI -\n");
1238
1239 seq_printf(s, "dsi fclk source = %s\n",
1240 dss_get_dsi_clk_source() == 0 ?
1241 "dss1_alwon_fclk" : "dsi2_pll_fclk");
1242
1243 seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate());
1244
1245 seq_printf(s, "DDR_CLK\t\t%lu\n",
1246 cinfo->clkin4ddr / 4);
1247
1248 seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs());
1249
1250 seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk);
1251
1252 seq_printf(s, "VP_CLK\t\t%lu\n"
1253 "VP_PCLK\t\t%lu\n",
1254 dispc_lclk_rate(),
1255 dispc_pclk_rate());
1256
1257 enable_clocks(0);
1258}
1259
1260#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
1261void dsi_dump_irqs(struct seq_file *s)
1262{
1263 unsigned long flags;
1264 struct dsi_irq_stats stats;
1265
1266 spin_lock_irqsave(&dsi.irq_stats_lock, flags);
1267
1268 stats = dsi.irq_stats;
1269 memset(&dsi.irq_stats, 0, sizeof(dsi.irq_stats));
1270 dsi.irq_stats.last_reset = jiffies;
1271
1272 spin_unlock_irqrestore(&dsi.irq_stats_lock, flags);
1273
1274 seq_printf(s, "period %u ms\n",
1275 jiffies_to_msecs(jiffies - stats.last_reset));
1276
1277 seq_printf(s, "irqs %d\n", stats.irq_count);
1278#define PIS(x) \
1279 seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]);
1280
1281 seq_printf(s, "-- DSI interrupts --\n");
1282 PIS(VC0);
1283 PIS(VC1);
1284 PIS(VC2);
1285 PIS(VC3);
1286 PIS(WAKEUP);
1287 PIS(RESYNC);
1288 PIS(PLL_LOCK);
1289 PIS(PLL_UNLOCK);
1290 PIS(PLL_RECALL);
1291 PIS(COMPLEXIO_ERR);
1292 PIS(HS_TX_TIMEOUT);
1293 PIS(LP_RX_TIMEOUT);
1294 PIS(TE_TRIGGER);
1295 PIS(ACK_TRIGGER);
1296 PIS(SYNC_LOST);
1297 PIS(LDO_POWER_GOOD);
1298 PIS(TA_TIMEOUT);
1299#undef PIS
1300
1301#define PIS(x) \
1302 seq_printf(s, "%-20s %10d %10d %10d %10d\n", #x, \
1303 stats.vc_irqs[0][ffs(DSI_VC_IRQ_##x)-1], \
1304 stats.vc_irqs[1][ffs(DSI_VC_IRQ_##x)-1], \
1305 stats.vc_irqs[2][ffs(DSI_VC_IRQ_##x)-1], \
1306 stats.vc_irqs[3][ffs(DSI_VC_IRQ_##x)-1]);
1307
1308 seq_printf(s, "-- VC interrupts --\n");
1309 PIS(CS);
1310 PIS(ECC_CORR);
1311 PIS(PACKET_SENT);
1312 PIS(FIFO_TX_OVF);
1313 PIS(FIFO_RX_OVF);
1314 PIS(BTA);
1315 PIS(ECC_NO_CORR);
1316 PIS(FIFO_TX_UDF);
1317 PIS(PP_BUSY_CHANGE);
1318#undef PIS
1319
1320#define PIS(x) \
1321 seq_printf(s, "%-20s %10d\n", #x, \
1322 stats.cio_irqs[ffs(DSI_CIO_IRQ_##x)-1]);
1323
1324 seq_printf(s, "-- CIO interrupts --\n");
1325 PIS(ERRSYNCESC1);
1326 PIS(ERRSYNCESC2);
1327 PIS(ERRSYNCESC3);
1328 PIS(ERRESC1);
1329 PIS(ERRESC2);
1330 PIS(ERRESC3);
1331 PIS(ERRCONTROL1);
1332 PIS(ERRCONTROL2);
1333 PIS(ERRCONTROL3);
1334 PIS(STATEULPS1);
1335 PIS(STATEULPS2);
1336 PIS(STATEULPS3);
1337 PIS(ERRCONTENTIONLP0_1);
1338 PIS(ERRCONTENTIONLP1_1);
1339 PIS(ERRCONTENTIONLP0_2);
1340 PIS(ERRCONTENTIONLP1_2);
1341 PIS(ERRCONTENTIONLP0_3);
1342 PIS(ERRCONTENTIONLP1_3);
1343 PIS(ULPSACTIVENOT_ALL0);
1344 PIS(ULPSACTIVENOT_ALL1);
1345#undef PIS
1346}
1347#endif
1348
1349void dsi_dump_regs(struct seq_file *s)
1350{
1351#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dsi_read_reg(r))
1352
1353 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1354
1355 DUMPREG(DSI_REVISION);
1356 DUMPREG(DSI_SYSCONFIG);
1357 DUMPREG(DSI_SYSSTATUS);
1358 DUMPREG(DSI_IRQSTATUS);
1359 DUMPREG(DSI_IRQENABLE);
1360 DUMPREG(DSI_CTRL);
1361 DUMPREG(DSI_COMPLEXIO_CFG1);
1362 DUMPREG(DSI_COMPLEXIO_IRQ_STATUS);
1363 DUMPREG(DSI_COMPLEXIO_IRQ_ENABLE);
1364 DUMPREG(DSI_CLK_CTRL);
1365 DUMPREG(DSI_TIMING1);
1366 DUMPREG(DSI_TIMING2);
1367 DUMPREG(DSI_VM_TIMING1);
1368 DUMPREG(DSI_VM_TIMING2);
1369 DUMPREG(DSI_VM_TIMING3);
1370 DUMPREG(DSI_CLK_TIMING);
1371 DUMPREG(DSI_TX_FIFO_VC_SIZE);
1372 DUMPREG(DSI_RX_FIFO_VC_SIZE);
1373 DUMPREG(DSI_COMPLEXIO_CFG2);
1374 DUMPREG(DSI_RX_FIFO_VC_FULLNESS);
1375 DUMPREG(DSI_VM_TIMING4);
1376 DUMPREG(DSI_TX_FIFO_VC_EMPTINESS);
1377 DUMPREG(DSI_VM_TIMING5);
1378 DUMPREG(DSI_VM_TIMING6);
1379 DUMPREG(DSI_VM_TIMING7);
1380 DUMPREG(DSI_STOPCLK_TIMING);
1381
1382 DUMPREG(DSI_VC_CTRL(0));
1383 DUMPREG(DSI_VC_TE(0));
1384 DUMPREG(DSI_VC_LONG_PACKET_HEADER(0));
1385 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(0));
1386 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(0));
1387 DUMPREG(DSI_VC_IRQSTATUS(0));
1388 DUMPREG(DSI_VC_IRQENABLE(0));
1389
1390 DUMPREG(DSI_VC_CTRL(1));
1391 DUMPREG(DSI_VC_TE(1));
1392 DUMPREG(DSI_VC_LONG_PACKET_HEADER(1));
1393 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(1));
1394 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(1));
1395 DUMPREG(DSI_VC_IRQSTATUS(1));
1396 DUMPREG(DSI_VC_IRQENABLE(1));
1397
1398 DUMPREG(DSI_VC_CTRL(2));
1399 DUMPREG(DSI_VC_TE(2));
1400 DUMPREG(DSI_VC_LONG_PACKET_HEADER(2));
1401 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(2));
1402 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(2));
1403 DUMPREG(DSI_VC_IRQSTATUS(2));
1404 DUMPREG(DSI_VC_IRQENABLE(2));
1405
1406 DUMPREG(DSI_VC_CTRL(3));
1407 DUMPREG(DSI_VC_TE(3));
1408 DUMPREG(DSI_VC_LONG_PACKET_HEADER(3));
1409 DUMPREG(DSI_VC_LONG_PACKET_PAYLOAD(3));
1410 DUMPREG(DSI_VC_SHORT_PACKET_HEADER(3));
1411 DUMPREG(DSI_VC_IRQSTATUS(3));
1412 DUMPREG(DSI_VC_IRQENABLE(3));
1413
1414 DUMPREG(DSI_DSIPHY_CFG0);
1415 DUMPREG(DSI_DSIPHY_CFG1);
1416 DUMPREG(DSI_DSIPHY_CFG2);
1417 DUMPREG(DSI_DSIPHY_CFG5);
1418
1419 DUMPREG(DSI_PLL_CONTROL);
1420 DUMPREG(DSI_PLL_STATUS);
1421 DUMPREG(DSI_PLL_GO);
1422 DUMPREG(DSI_PLL_CONFIGURATION1);
1423 DUMPREG(DSI_PLL_CONFIGURATION2);
1424
1425 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1426#undef DUMPREG
1427}
1428
1429enum dsi_complexio_power_state {
1430 DSI_COMPLEXIO_POWER_OFF = 0x0,
1431 DSI_COMPLEXIO_POWER_ON = 0x1,
1432 DSI_COMPLEXIO_POWER_ULPS = 0x2,
1433};
1434
1435static int dsi_complexio_power(enum dsi_complexio_power_state state)
1436{
1437 int t = 0;
1438
1439 /* PWR_CMD */
1440 REG_FLD_MOD(DSI_COMPLEXIO_CFG1, state, 28, 27);
1441
1442 /* PWR_STATUS */
1443 while (FLD_GET(dsi_read_reg(DSI_COMPLEXIO_CFG1), 26, 25) != state) {
1444 if (++t > 1000) {
1445 DSSERR("failed to set complexio power state to "
1446 "%d\n", state);
1447 return -ENODEV;
1448 }
1449 udelay(1);
1450 }
1451
1452 return 0;
1453}
1454
1455static void dsi_complexio_config(struct omap_dss_device *dssdev)
1456{
1457 u32 r;
1458
1459 int clk_lane = dssdev->phy.dsi.clk_lane;
1460 int data1_lane = dssdev->phy.dsi.data1_lane;
1461 int data2_lane = dssdev->phy.dsi.data2_lane;
1462 int clk_pol = dssdev->phy.dsi.clk_pol;
1463 int data1_pol = dssdev->phy.dsi.data1_pol;
1464 int data2_pol = dssdev->phy.dsi.data2_pol;
1465
1466 r = dsi_read_reg(DSI_COMPLEXIO_CFG1);
1467 r = FLD_MOD(r, clk_lane, 2, 0);
1468 r = FLD_MOD(r, clk_pol, 3, 3);
1469 r = FLD_MOD(r, data1_lane, 6, 4);
1470 r = FLD_MOD(r, data1_pol, 7, 7);
1471 r = FLD_MOD(r, data2_lane, 10, 8);
1472 r = FLD_MOD(r, data2_pol, 11, 11);
1473 dsi_write_reg(DSI_COMPLEXIO_CFG1, r);
1474
1475 /* The configuration of the DSI complex I/O (number of data lanes,
1476 position, differential order) should not be changed while
1477 DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for
1478 the hardware to take into account a new configuration of the complex
1479 I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to
1480 follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1,
1481 then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set
1482 DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the
1483 DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the
1484 DSI complex I/O configuration is unknown. */
1485
1486 /*
1487 REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
1488 REG_FLD_MOD(DSI_CTRL, 0, 0, 0);
1489 REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20);
1490 REG_FLD_MOD(DSI_CTRL, 1, 0, 0);
1491 */
1492}
1493
1494static inline unsigned ns2ddr(unsigned ns)
1495{
1496 /* convert time in ns to ddr ticks, rounding up */
1497 unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
1498 return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
1499}
1500
1501static inline unsigned ddr2ns(unsigned ddr)
1502{
1503 unsigned long ddr_clk = dsi.current_cinfo.clkin4ddr / 4;
1504 return ddr * 1000 * 1000 / (ddr_clk / 1000);
1505}
1506
1507static void dsi_complexio_timings(void)
1508{
1509 u32 r;
1510 u32 ths_prepare, ths_prepare_ths_zero, ths_trail, ths_exit;
1511 u32 tlpx_half, tclk_trail, tclk_zero;
1512 u32 tclk_prepare;
1513
1514 /* calculate timings */
1515
1516 /* 1 * DDR_CLK = 2 * UI */
1517
1518 /* min 40ns + 4*UI max 85ns + 6*UI */
1519 ths_prepare = ns2ddr(70) + 2;
1520
1521 /* min 145ns + 10*UI */
1522 ths_prepare_ths_zero = ns2ddr(175) + 2;
1523
1524 /* min max(8*UI, 60ns+4*UI) */
1525 ths_trail = ns2ddr(60) + 5;
1526
1527 /* min 100ns */
1528 ths_exit = ns2ddr(145);
1529
1530 /* tlpx min 50n */
1531 tlpx_half = ns2ddr(25);
1532
1533 /* min 60ns */
1534 tclk_trail = ns2ddr(60) + 2;
1535
1536 /* min 38ns, max 95ns */
1537 tclk_prepare = ns2ddr(65);
1538
1539 /* min tclk-prepare + tclk-zero = 300ns */
1540 tclk_zero = ns2ddr(260);
1541
1542 DSSDBG("ths_prepare %u (%uns), ths_prepare_ths_zero %u (%uns)\n",
1543 ths_prepare, ddr2ns(ths_prepare),
1544 ths_prepare_ths_zero, ddr2ns(ths_prepare_ths_zero));
1545 DSSDBG("ths_trail %u (%uns), ths_exit %u (%uns)\n",
1546 ths_trail, ddr2ns(ths_trail),
1547 ths_exit, ddr2ns(ths_exit));
1548
1549 DSSDBG("tlpx_half %u (%uns), tclk_trail %u (%uns), "
1550 "tclk_zero %u (%uns)\n",
1551 tlpx_half, ddr2ns(tlpx_half),
1552 tclk_trail, ddr2ns(tclk_trail),
1553 tclk_zero, ddr2ns(tclk_zero));
1554 DSSDBG("tclk_prepare %u (%uns)\n",
1555 tclk_prepare, ddr2ns(tclk_prepare));
1556
1557 /* program timings */
1558
1559 r = dsi_read_reg(DSI_DSIPHY_CFG0);
1560 r = FLD_MOD(r, ths_prepare, 31, 24);
1561 r = FLD_MOD(r, ths_prepare_ths_zero, 23, 16);
1562 r = FLD_MOD(r, ths_trail, 15, 8);
1563 r = FLD_MOD(r, ths_exit, 7, 0);
1564 dsi_write_reg(DSI_DSIPHY_CFG0, r);
1565
1566 r = dsi_read_reg(DSI_DSIPHY_CFG1);
1567 r = FLD_MOD(r, tlpx_half, 22, 16);
1568 r = FLD_MOD(r, tclk_trail, 15, 8);
1569 r = FLD_MOD(r, tclk_zero, 7, 0);
1570 dsi_write_reg(DSI_DSIPHY_CFG1, r);
1571
1572 r = dsi_read_reg(DSI_DSIPHY_CFG2);
1573 r = FLD_MOD(r, tclk_prepare, 7, 0);
1574 dsi_write_reg(DSI_DSIPHY_CFG2, r);
1575}
1576
1577
1578static int dsi_complexio_init(struct omap_dss_device *dssdev)
1579{
1580 int r = 0;
1581
1582 DSSDBG("dsi_complexio_init\n");
1583
1584 /* CIO_CLK_ICG, enable L3 clk to CIO */
1585 REG_FLD_MOD(DSI_CLK_CTRL, 1, 14, 14);
1586
1587 /* A dummy read using the SCP interface to any DSIPHY register is
1588 * required after DSIPHY reset to complete the reset of the DSI complex
1589 * I/O. */
1590 dsi_read_reg(DSI_DSIPHY_CFG5);
1591
1592 if (wait_for_bit_change(DSI_DSIPHY_CFG5, 30, 1) != 1) {
1593 DSSERR("ComplexIO PHY not coming out of reset.\n");
1594 r = -ENODEV;
1595 goto err;
1596 }
1597
1598 dsi_complexio_config(dssdev);
1599
1600 r = dsi_complexio_power(DSI_COMPLEXIO_POWER_ON);
1601
1602 if (r)
1603 goto err;
1604
1605 if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 29, 1) != 1) {
1606 DSSERR("ComplexIO not coming out of reset.\n");
1607 r = -ENODEV;
1608 goto err;
1609 }
1610
1611 if (wait_for_bit_change(DSI_COMPLEXIO_CFG1, 21, 1) != 1) {
1612 DSSERR("ComplexIO LDO power down.\n");
1613 r = -ENODEV;
1614 goto err;
1615 }
1616
1617 dsi_complexio_timings();
1618
1619 /*
1620 The configuration of the DSI complex I/O (number of data lanes,
1621 position, differential order) should not be changed while
1622 DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. For the
1623 hardware to recognize a new configuration of the complex I/O (done
1624 in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to follow
1625 this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, next
1626 reset the DSS.DSI_CTRL[0] IF_EN to 0, then set DSS.DSI_CLK_CTRL[20]
1627 LP_CLK_ENABLE to 1, and finally, set again the DSS.DSI_CTRL[0] IF_EN
1628 bit to 1. If the sequence is not followed, the DSi complex I/O
1629 configuration is undetermined.
1630 */
1631 dsi_if_enable(1);
1632 dsi_if_enable(0);
1633 REG_FLD_MOD(DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */
1634 dsi_if_enable(1);
1635 dsi_if_enable(0);
1636
1637 DSSDBG("CIO init done\n");
1638err:
1639 return r;
1640}
1641
1642static void dsi_complexio_uninit(void)
1643{
1644 dsi_complexio_power(DSI_COMPLEXIO_POWER_OFF);
1645}
1646
1647static int _dsi_wait_reset(void)
1648{
1649 int t = 0;
1650
1651 while (REG_GET(DSI_SYSSTATUS, 0, 0) == 0) {
1652 if (++t > 5) {
1653 DSSERR("soft reset failed\n");
1654 return -ENODEV;
1655 }
1656 udelay(1);
1657 }
1658
1659 return 0;
1660}
1661
1662static int _dsi_reset(void)
1663{
1664 /* Soft reset */
1665 REG_FLD_MOD(DSI_SYSCONFIG, 1, 1, 1);
1666 return _dsi_wait_reset();
1667}
1668
1669static void dsi_reset_tx_fifo(int channel)
1670{
1671 u32 mask;
1672 u32 l;
1673
1674 /* set fifosize of the channel to 0, then return the old size */
1675 l = dsi_read_reg(DSI_TX_FIFO_VC_SIZE);
1676
1677 mask = FLD_MASK((8 * channel) + 7, (8 * channel) + 4);
1678 dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l & ~mask);
1679
1680 dsi_write_reg(DSI_TX_FIFO_VC_SIZE, l);
1681}
1682
1683static void dsi_config_tx_fifo(enum fifo_size size1, enum fifo_size size2,
1684 enum fifo_size size3, enum fifo_size size4)
1685{
1686 u32 r = 0;
1687 int add = 0;
1688 int i;
1689
1690 dsi.vc[0].fifo_size = size1;
1691 dsi.vc[1].fifo_size = size2;
1692 dsi.vc[2].fifo_size = size3;
1693 dsi.vc[3].fifo_size = size4;
1694
1695 for (i = 0; i < 4; i++) {
1696 u8 v;
1697 int size = dsi.vc[i].fifo_size;
1698
1699 if (add + size > 4) {
1700 DSSERR("Illegal FIFO configuration\n");
1701 BUG();
1702 }
1703
1704 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
1705 r |= v << (8 * i);
1706 /*DSSDBG("TX FIFO vc %d: size %d, add %d\n", i, size, add); */
1707 add += size;
1708 }
1709
1710 dsi_write_reg(DSI_TX_FIFO_VC_SIZE, r);
1711}
1712
1713static void dsi_config_rx_fifo(enum fifo_size size1, enum fifo_size size2,
1714 enum fifo_size size3, enum fifo_size size4)
1715{
1716 u32 r = 0;
1717 int add = 0;
1718 int i;
1719
1720 dsi.vc[0].fifo_size = size1;
1721 dsi.vc[1].fifo_size = size2;
1722 dsi.vc[2].fifo_size = size3;
1723 dsi.vc[3].fifo_size = size4;
1724
1725 for (i = 0; i < 4; i++) {
1726 u8 v;
1727 int size = dsi.vc[i].fifo_size;
1728
1729 if (add + size > 4) {
1730 DSSERR("Illegal FIFO configuration\n");
1731 BUG();
1732 }
1733
1734 v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4);
1735 r |= v << (8 * i);
1736 /*DSSDBG("RX FIFO vc %d: size %d, add %d\n", i, size, add); */
1737 add += size;
1738 }
1739
1740 dsi_write_reg(DSI_RX_FIFO_VC_SIZE, r);
1741}
1742
1743static int dsi_force_tx_stop_mode_io(void)
1744{
1745 u32 r;
1746
1747 r = dsi_read_reg(DSI_TIMING1);
1748 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
1749 dsi_write_reg(DSI_TIMING1, r);
1750
1751 if (wait_for_bit_change(DSI_TIMING1, 15, 0) != 0) {
1752 DSSERR("TX_STOP bit not going down\n");
1753 return -EIO;
1754 }
1755
1756 return 0;
1757}
1758
1759static void dsi_vc_print_status(int channel)
1760{
1761 u32 r;
1762
1763 r = dsi_read_reg(DSI_VC_CTRL(channel));
1764 DSSDBG("vc %d: TX_FIFO_NOT_EMPTY %d, BTA_EN %d, VC_BUSY %d, "
1765 "TX_FIFO_FULL %d, RX_FIFO_NOT_EMPTY %d, ",
1766 channel,
1767 FLD_GET(r, 5, 5),
1768 FLD_GET(r, 6, 6),
1769 FLD_GET(r, 15, 15),
1770 FLD_GET(r, 16, 16),
1771 FLD_GET(r, 20, 20));
1772
1773 r = dsi_read_reg(DSI_TX_FIFO_VC_EMPTINESS);
1774 DSSDBG("EMPTINESS %d\n", (r >> (8 * channel)) & 0xff);
1775}
1776
1777static int dsi_vc_enable(int channel, bool enable)
1778{
1779 if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
1780 DSSDBG("dsi_vc_enable channel %d, enable %d\n",
1781 channel, enable);
1782
1783 enable = enable ? 1 : 0;
1784
1785 REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 0, 0);
1786
1787 if (wait_for_bit_change(DSI_VC_CTRL(channel), 0, enable) != enable) {
1788 DSSERR("Failed to set dsi_vc_enable to %d\n", enable);
1789 return -EIO;
1790 }
1791
1792 return 0;
1793}
1794
1795static void dsi_vc_initial_config(int channel)
1796{
1797 u32 r;
1798
1799 DSSDBGF("%d", channel);
1800
1801 r = dsi_read_reg(DSI_VC_CTRL(channel));
1802
1803 if (FLD_GET(r, 15, 15)) /* VC_BUSY */
1804 DSSERR("VC(%d) busy when trying to configure it!\n",
1805 channel);
1806
1807 r = FLD_MOD(r, 0, 1, 1); /* SOURCE, 0 = L4 */
1808 r = FLD_MOD(r, 0, 2, 2); /* BTA_SHORT_EN */
1809 r = FLD_MOD(r, 0, 3, 3); /* BTA_LONG_EN */
1810 r = FLD_MOD(r, 0, 4, 4); /* MODE, 0 = command */
1811 r = FLD_MOD(r, 1, 7, 7); /* CS_TX_EN */
1812 r = FLD_MOD(r, 1, 8, 8); /* ECC_TX_EN */
1813 r = FLD_MOD(r, 0, 9, 9); /* MODE_SPEED, high speed on/off */
1814
1815 r = FLD_MOD(r, 4, 29, 27); /* DMA_RX_REQ_NB = no dma */
1816 r = FLD_MOD(r, 4, 23, 21); /* DMA_TX_REQ_NB = no dma */
1817
1818 dsi_write_reg(DSI_VC_CTRL(channel), r);
1819
1820 dsi.vc[channel].mode = DSI_VC_MODE_L4;
1821}
1822
1823static void dsi_vc_config_l4(int channel)
1824{
1825 if (dsi.vc[channel].mode == DSI_VC_MODE_L4)
1826 return;
1827
1828 DSSDBGF("%d", channel);
1829
1830 dsi_vc_enable(channel, 0);
1831
1832 if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
1833 DSSERR("vc(%d) busy when trying to config for L4\n", channel);
1834
1835 REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */
1836
1837 dsi_vc_enable(channel, 1);
1838
1839 dsi.vc[channel].mode = DSI_VC_MODE_L4;
1840}
1841
1842static void dsi_vc_config_vp(int channel)
1843{
1844 if (dsi.vc[channel].mode == DSI_VC_MODE_VP)
1845 return;
1846
1847 DSSDBGF("%d", channel);
1848
1849 dsi_vc_enable(channel, 0);
1850
1851 if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */
1852 DSSERR("vc(%d) busy when trying to config for VP\n", channel);
1853
1854 REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */
1855
1856 dsi_vc_enable(channel, 1);
1857
1858 dsi.vc[channel].mode = DSI_VC_MODE_VP;
1859}
1860
1861
1862static void dsi_vc_enable_hs(int channel, bool enable)
1863{
1864 DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable);
1865
1866 dsi_vc_enable(channel, 0);
1867 dsi_if_enable(0);
1868
1869 REG_FLD_MOD(DSI_VC_CTRL(channel), enable, 9, 9);
1870
1871 dsi_vc_enable(channel, 1);
1872 dsi_if_enable(1);
1873
1874 dsi_force_tx_stop_mode_io();
1875}
1876
1877static void dsi_vc_flush_long_data(int channel)
1878{
1879 while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
1880 u32 val;
1881 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
1882 DSSDBG("\t\tb1 %#02x b2 %#02x b3 %#02x b4 %#02x\n",
1883 (val >> 0) & 0xff,
1884 (val >> 8) & 0xff,
1885 (val >> 16) & 0xff,
1886 (val >> 24) & 0xff);
1887 }
1888}
1889
1890static void dsi_show_rx_ack_with_err(u16 err)
1891{
1892 DSSERR("\tACK with ERROR (%#x):\n", err);
1893 if (err & (1 << 0))
1894 DSSERR("\t\tSoT Error\n");
1895 if (err & (1 << 1))
1896 DSSERR("\t\tSoT Sync Error\n");
1897 if (err & (1 << 2))
1898 DSSERR("\t\tEoT Sync Error\n");
1899 if (err & (1 << 3))
1900 DSSERR("\t\tEscape Mode Entry Command Error\n");
1901 if (err & (1 << 4))
1902 DSSERR("\t\tLP Transmit Sync Error\n");
1903 if (err & (1 << 5))
1904 DSSERR("\t\tHS Receive Timeout Error\n");
1905 if (err & (1 << 6))
1906 DSSERR("\t\tFalse Control Error\n");
1907 if (err & (1 << 7))
1908 DSSERR("\t\t(reserved7)\n");
1909 if (err & (1 << 8))
1910 DSSERR("\t\tECC Error, single-bit (corrected)\n");
1911 if (err & (1 << 9))
1912 DSSERR("\t\tECC Error, multi-bit (not corrected)\n");
1913 if (err & (1 << 10))
1914 DSSERR("\t\tChecksum Error\n");
1915 if (err & (1 << 11))
1916 DSSERR("\t\tData type not recognized\n");
1917 if (err & (1 << 12))
1918 DSSERR("\t\tInvalid VC ID\n");
1919 if (err & (1 << 13))
1920 DSSERR("\t\tInvalid Transmission Length\n");
1921 if (err & (1 << 14))
1922 DSSERR("\t\t(reserved14)\n");
1923 if (err & (1 << 15))
1924 DSSERR("\t\tDSI Protocol Violation\n");
1925}
1926
1927static u16 dsi_vc_flush_receive_data(int channel)
1928{
1929 /* RX_FIFO_NOT_EMPTY */
1930 while (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
1931 u32 val;
1932 u8 dt;
1933 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
1934 DSSDBG("\trawval %#08x\n", val);
1935 dt = FLD_GET(val, 5, 0);
1936 if (dt == DSI_DT_RX_ACK_WITH_ERR) {
1937 u16 err = FLD_GET(val, 23, 8);
1938 dsi_show_rx_ack_with_err(err);
1939 } else if (dt == DSI_DT_RX_SHORT_READ_1) {
1940 DSSDBG("\tDCS short response, 1 byte: %#x\n",
1941 FLD_GET(val, 23, 8));
1942 } else if (dt == DSI_DT_RX_SHORT_READ_2) {
1943 DSSDBG("\tDCS short response, 2 byte: %#x\n",
1944 FLD_GET(val, 23, 8));
1945 } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
1946 DSSDBG("\tDCS long response, len %d\n",
1947 FLD_GET(val, 23, 8));
1948 dsi_vc_flush_long_data(channel);
1949 } else {
1950 DSSERR("\tunknown datatype 0x%02x\n", dt);
1951 }
1952 }
1953 return 0;
1954}
1955
1956static int dsi_vc_send_bta(int channel)
1957{
1958 if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO &&
1959 (dsi.debug_write || dsi.debug_read))
1960 DSSDBG("dsi_vc_send_bta %d\n", channel);
1961
1962 WARN_ON(!mutex_is_locked(&dsi.bus_lock));
1963
1964 if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */
1965 DSSERR("rx fifo not empty when sending BTA, dumping data:\n");
1966 dsi_vc_flush_receive_data(channel);
1967 }
1968
1969 REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */
1970
1971 return 0;
1972}
1973
1974int dsi_vc_send_bta_sync(int channel)
1975{
1976 int r = 0;
1977 u32 err;
1978
1979 INIT_COMPLETION(dsi.bta_completion);
1980
1981 dsi_vc_enable_bta_irq(channel);
1982
1983 r = dsi_vc_send_bta(channel);
1984 if (r)
1985 goto err;
1986
1987 if (wait_for_completion_timeout(&dsi.bta_completion,
1988 msecs_to_jiffies(500)) == 0) {
1989 DSSERR("Failed to receive BTA\n");
1990 r = -EIO;
1991 goto err;
1992 }
1993
1994 err = dsi_get_errors();
1995 if (err) {
1996 DSSERR("Error while sending BTA: %x\n", err);
1997 r = -EIO;
1998 goto err;
1999 }
2000err:
2001 dsi_vc_disable_bta_irq(channel);
2002
2003 return r;
2004}
2005EXPORT_SYMBOL(dsi_vc_send_bta_sync);
2006
2007static inline void dsi_vc_write_long_header(int channel, u8 data_type,
2008 u16 len, u8 ecc)
2009{
2010 u32 val;
2011 u8 data_id;
2012
2013 WARN_ON(!mutex_is_locked(&dsi.bus_lock));
2014
2015 /*data_id = data_type | channel << 6; */
2016 data_id = data_type | dsi.vc[channel].dest_per << 6;
2017
2018 val = FLD_VAL(data_id, 7, 0) | FLD_VAL(len, 23, 8) |
2019 FLD_VAL(ecc, 31, 24);
2020
2021 dsi_write_reg(DSI_VC_LONG_PACKET_HEADER(channel), val);
2022}
2023
2024static inline void dsi_vc_write_long_payload(int channel,
2025 u8 b1, u8 b2, u8 b3, u8 b4)
2026{
2027 u32 val;
2028
2029 val = b4 << 24 | b3 << 16 | b2 << 8 | b1 << 0;
2030
2031/* DSSDBG("\twriting %02x, %02x, %02x, %02x (%#010x)\n",
2032 b1, b2, b3, b4, val); */
2033
2034 dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(channel), val);
2035}
2036
2037static int dsi_vc_send_long(int channel, u8 data_type, u8 *data, u16 len,
2038 u8 ecc)
2039{
2040 /*u32 val; */
2041 int i;
2042 u8 *p;
2043 int r = 0;
2044 u8 b1, b2, b3, b4;
2045
2046 if (dsi.debug_write)
2047 DSSDBG("dsi_vc_send_long, %d bytes\n", len);
2048
2049 /* len + header */
2050 if (dsi.vc[channel].fifo_size * 32 * 4 < len + 4) {
2051 DSSERR("unable to send long packet: packet too long.\n");
2052 return -EINVAL;
2053 }
2054
2055 dsi_vc_config_l4(channel);
2056
2057 dsi_vc_write_long_header(channel, data_type, len, ecc);
2058
2059 /*dsi_vc_print_status(0); */
2060
2061 p = data;
2062 for (i = 0; i < len >> 2; i++) {
2063 if (dsi.debug_write)
2064 DSSDBG("\tsending full packet %d\n", i);
2065 /*dsi_vc_print_status(0); */
2066
2067 b1 = *p++;
2068 b2 = *p++;
2069 b3 = *p++;
2070 b4 = *p++;
2071
2072 dsi_vc_write_long_payload(channel, b1, b2, b3, b4);
2073 }
2074
2075 i = len % 4;
2076 if (i) {
2077 b1 = 0; b2 = 0; b3 = 0;
2078
2079 if (dsi.debug_write)
2080 DSSDBG("\tsending remainder bytes %d\n", i);
2081
2082 switch (i) {
2083 case 3:
2084 b1 = *p++;
2085 b2 = *p++;
2086 b3 = *p++;
2087 break;
2088 case 2:
2089 b1 = *p++;
2090 b2 = *p++;
2091 break;
2092 case 1:
2093 b1 = *p++;
2094 break;
2095 }
2096
2097 dsi_vc_write_long_payload(channel, b1, b2, b3, 0);
2098 }
2099
2100 return r;
2101}
2102
2103static int dsi_vc_send_short(int channel, u8 data_type, u16 data, u8 ecc)
2104{
2105 u32 r;
2106 u8 data_id;
2107
2108 WARN_ON(!mutex_is_locked(&dsi.bus_lock));
2109
2110 if (dsi.debug_write)
2111 DSSDBG("dsi_vc_send_short(ch%d, dt %#x, b1 %#x, b2 %#x)\n",
2112 channel,
2113 data_type, data & 0xff, (data >> 8) & 0xff);
2114
2115 dsi_vc_config_l4(channel);
2116
2117 if (FLD_GET(dsi_read_reg(DSI_VC_CTRL(channel)), 16, 16)) {
2118 DSSERR("ERROR FIFO FULL, aborting transfer\n");
2119 return -EINVAL;
2120 }
2121
2122 data_id = data_type | dsi.vc[channel].dest_per << 6;
2123
2124 r = (data_id << 0) | (data << 8) | (ecc << 24);
2125
2126 dsi_write_reg(DSI_VC_SHORT_PACKET_HEADER(channel), r);
2127
2128 return 0;
2129}
2130
2131int dsi_vc_send_null(int channel)
2132{
2133 u8 nullpkg[] = {0, 0, 0, 0};
2134 return dsi_vc_send_long(channel, DSI_DT_NULL_PACKET, nullpkg, 4, 0);
2135}
2136EXPORT_SYMBOL(dsi_vc_send_null);
2137
2138int dsi_vc_dcs_write_nosync(int channel, u8 *data, int len)
2139{
2140 int r;
2141
2142 BUG_ON(len == 0);
2143
2144 if (len == 1) {
2145 r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_0,
2146 data[0], 0);
2147 } else if (len == 2) {
2148 r = dsi_vc_send_short(channel, DSI_DT_DCS_SHORT_WRITE_1,
2149 data[0] | (data[1] << 8), 0);
2150 } else {
2151 /* 0x39 = DCS Long Write */
2152 r = dsi_vc_send_long(channel, DSI_DT_DCS_LONG_WRITE,
2153 data, len, 0);
2154 }
2155
2156 return r;
2157}
2158EXPORT_SYMBOL(dsi_vc_dcs_write_nosync);
2159
2160int dsi_vc_dcs_write(int channel, u8 *data, int len)
2161{
2162 int r;
2163
2164 r = dsi_vc_dcs_write_nosync(channel, data, len);
2165 if (r)
2166 return r;
2167
2168 r = dsi_vc_send_bta_sync(channel);
2169
2170 return r;
2171}
2172EXPORT_SYMBOL(dsi_vc_dcs_write);
2173
2174int dsi_vc_dcs_read(int channel, u8 dcs_cmd, u8 *buf, int buflen)
2175{
2176 u32 val;
2177 u8 dt;
2178 int r;
2179
2180 if (dsi.debug_read)
2181 DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd);
2182
2183 r = dsi_vc_send_short(channel, DSI_DT_DCS_READ, dcs_cmd, 0);
2184 if (r)
2185 return r;
2186
2187 r = dsi_vc_send_bta_sync(channel);
2188 if (r)
2189 return r;
2190
2191 /* RX_FIFO_NOT_EMPTY */
2192 if (REG_GET(DSI_VC_CTRL(channel), 20, 20) == 0) {
2193 DSSERR("RX fifo empty when trying to read.\n");
2194 return -EIO;
2195 }
2196
2197 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
2198 if (dsi.debug_read)
2199 DSSDBG("\theader: %08x\n", val);
2200 dt = FLD_GET(val, 5, 0);
2201 if (dt == DSI_DT_RX_ACK_WITH_ERR) {
2202 u16 err = FLD_GET(val, 23, 8);
2203 dsi_show_rx_ack_with_err(err);
2204 return -EIO;
2205
2206 } else if (dt == DSI_DT_RX_SHORT_READ_1) {
2207 u8 data = FLD_GET(val, 15, 8);
2208 if (dsi.debug_read)
2209 DSSDBG("\tDCS short response, 1 byte: %02x\n", data);
2210
2211 if (buflen < 1)
2212 return -EIO;
2213
2214 buf[0] = data;
2215
2216 return 1;
2217 } else if (dt == DSI_DT_RX_SHORT_READ_2) {
2218 u16 data = FLD_GET(val, 23, 8);
2219 if (dsi.debug_read)
2220 DSSDBG("\tDCS short response, 2 byte: %04x\n", data);
2221
2222 if (buflen < 2)
2223 return -EIO;
2224
2225 buf[0] = data & 0xff;
2226 buf[1] = (data >> 8) & 0xff;
2227
2228 return 2;
2229 } else if (dt == DSI_DT_RX_DCS_LONG_READ) {
2230 int w;
2231 int len = FLD_GET(val, 23, 8);
2232 if (dsi.debug_read)
2233 DSSDBG("\tDCS long response, len %d\n", len);
2234
2235 if (len > buflen)
2236 return -EIO;
2237
2238 /* two byte checksum ends the packet, not included in len */
2239 for (w = 0; w < len + 2;) {
2240 int b;
2241 val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel));
2242 if (dsi.debug_read)
2243 DSSDBG("\t\t%02x %02x %02x %02x\n",
2244 (val >> 0) & 0xff,
2245 (val >> 8) & 0xff,
2246 (val >> 16) & 0xff,
2247 (val >> 24) & 0xff);
2248
2249 for (b = 0; b < 4; ++b) {
2250 if (w < len)
2251 buf[w] = (val >> (b * 8)) & 0xff;
2252 /* we discard the 2 byte checksum */
2253 ++w;
2254 }
2255 }
2256
2257 return len;
2258
2259 } else {
2260 DSSERR("\tunknown datatype 0x%02x\n", dt);
2261 return -EIO;
2262 }
2263}
2264EXPORT_SYMBOL(dsi_vc_dcs_read);
2265
2266
2267int dsi_vc_set_max_rx_packet_size(int channel, u16 len)
2268{
2269 int r;
2270 r = dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE,
2271 len, 0);
2272
2273 if (r)
2274 return r;
2275
2276 r = dsi_vc_send_bta_sync(channel);
2277
2278 return r;
2279}
2280EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size);
2281
2282static void dsi_set_lp_rx_timeout(unsigned long ns)
2283{
2284 u32 r;
2285 unsigned x4, x16;
2286 unsigned long fck;
2287 unsigned long ticks;
2288
2289 /* ticks in DSI_FCK */
2290
2291 fck = dsi_fclk_rate();
2292 ticks = (fck / 1000 / 1000) * ns / 1000;
2293 x4 = 0;
2294 x16 = 0;
2295
2296 if (ticks > 0x1fff) {
2297 ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
2298 x4 = 1;
2299 x16 = 0;
2300 }
2301
2302 if (ticks > 0x1fff) {
2303 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2304 x4 = 0;
2305 x16 = 1;
2306 }
2307
2308 if (ticks > 0x1fff) {
2309 ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
2310 x4 = 1;
2311 x16 = 1;
2312 }
2313
2314 if (ticks > 0x1fff) {
2315 DSSWARN("LP_TX_TO over limit, setting it to max\n");
2316 ticks = 0x1fff;
2317 x4 = 1;
2318 x16 = 1;
2319 }
2320
2321 r = dsi_read_reg(DSI_TIMING2);
2322 r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */
2323 r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */
2324 r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */
2325 r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */
2326 dsi_write_reg(DSI_TIMING2, r);
2327
2328 DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n",
2329 (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
2330 (fck / 1000 / 1000),
2331 ticks, x4 ? " x4" : "", x16 ? " x16" : "");
2332}
2333
2334static void dsi_set_ta_timeout(unsigned long ns)
2335{
2336 u32 r;
2337 unsigned x8, x16;
2338 unsigned long fck;
2339 unsigned long ticks;
2340
2341 /* ticks in DSI_FCK */
2342 fck = dsi_fclk_rate();
2343 ticks = (fck / 1000 / 1000) * ns / 1000;
2344 x8 = 0;
2345 x16 = 0;
2346
2347 if (ticks > 0x1fff) {
2348 ticks = (fck / 1000 / 1000) * ns / 1000 / 8;
2349 x8 = 1;
2350 x16 = 0;
2351 }
2352
2353 if (ticks > 0x1fff) {
2354 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2355 x8 = 0;
2356 x16 = 1;
2357 }
2358
2359 if (ticks > 0x1fff) {
2360 ticks = (fck / 1000 / 1000) * ns / 1000 / (8 * 16);
2361 x8 = 1;
2362 x16 = 1;
2363 }
2364
2365 if (ticks > 0x1fff) {
2366 DSSWARN("TA_TO over limit, setting it to max\n");
2367 ticks = 0x1fff;
2368 x8 = 1;
2369 x16 = 1;
2370 }
2371
2372 r = dsi_read_reg(DSI_TIMING1);
2373 r = FLD_MOD(r, 1, 31, 31); /* TA_TO */
2374 r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */
2375 r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */
2376 r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */
2377 dsi_write_reg(DSI_TIMING1, r);
2378
2379 DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n",
2380 (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) /
2381 (fck / 1000 / 1000),
2382 ticks, x8 ? " x8" : "", x16 ? " x16" : "");
2383}
2384
2385static void dsi_set_stop_state_counter(unsigned long ns)
2386{
2387 u32 r;
2388 unsigned x4, x16;
2389 unsigned long fck;
2390 unsigned long ticks;
2391
2392 /* ticks in DSI_FCK */
2393
2394 fck = dsi_fclk_rate();
2395 ticks = (fck / 1000 / 1000) * ns / 1000;
2396 x4 = 0;
2397 x16 = 0;
2398
2399 if (ticks > 0x1fff) {
2400 ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
2401 x4 = 1;
2402 x16 = 0;
2403 }
2404
2405 if (ticks > 0x1fff) {
2406 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2407 x4 = 0;
2408 x16 = 1;
2409 }
2410
2411 if (ticks > 0x1fff) {
2412 ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
2413 x4 = 1;
2414 x16 = 1;
2415 }
2416
2417 if (ticks > 0x1fff) {
2418 DSSWARN("STOP_STATE_COUNTER_IO over limit, "
2419 "setting it to max\n");
2420 ticks = 0x1fff;
2421 x4 = 1;
2422 x16 = 1;
2423 }
2424
2425 r = dsi_read_reg(DSI_TIMING1);
2426 r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */
2427 r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */
2428 r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */
2429 r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */
2430 dsi_write_reg(DSI_TIMING1, r);
2431
2432 DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n",
2433 (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
2434 (fck / 1000 / 1000),
2435 ticks, x4 ? " x4" : "", x16 ? " x16" : "");
2436}
2437
2438static void dsi_set_hs_tx_timeout(unsigned long ns)
2439{
2440 u32 r;
2441 unsigned x4, x16;
2442 unsigned long fck;
2443 unsigned long ticks;
2444
2445 /* ticks in TxByteClkHS */
2446
2447 fck = dsi_get_txbyteclkhs();
2448 ticks = (fck / 1000 / 1000) * ns / 1000;
2449 x4 = 0;
2450 x16 = 0;
2451
2452 if (ticks > 0x1fff) {
2453 ticks = (fck / 1000 / 1000) * ns / 1000 / 4;
2454 x4 = 1;
2455 x16 = 0;
2456 }
2457
2458 if (ticks > 0x1fff) {
2459 ticks = (fck / 1000 / 1000) * ns / 1000 / 16;
2460 x4 = 0;
2461 x16 = 1;
2462 }
2463
2464 if (ticks > 0x1fff) {
2465 ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16);
2466 x4 = 1;
2467 x16 = 1;
2468 }
2469
2470 if (ticks > 0x1fff) {
2471 DSSWARN("HS_TX_TO over limit, setting it to max\n");
2472 ticks = 0x1fff;
2473 x4 = 1;
2474 x16 = 1;
2475 }
2476
2477 r = dsi_read_reg(DSI_TIMING2);
2478 r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */
2479 r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */
2480 r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */
2481 r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */
2482 dsi_write_reg(DSI_TIMING2, r);
2483
2484 DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n",
2485 (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) /
2486 (fck / 1000 / 1000),
2487 ticks, x4 ? " x4" : "", x16 ? " x16" : "");
2488}
2489static int dsi_proto_config(struct omap_dss_device *dssdev)
2490{
2491 u32 r;
2492 int buswidth = 0;
2493
2494 dsi_config_tx_fifo(DSI_FIFO_SIZE_128,
2495 DSI_FIFO_SIZE_0,
2496 DSI_FIFO_SIZE_0,
2497 DSI_FIFO_SIZE_0);
2498
2499 dsi_config_rx_fifo(DSI_FIFO_SIZE_128,
2500 DSI_FIFO_SIZE_0,
2501 DSI_FIFO_SIZE_0,
2502 DSI_FIFO_SIZE_0);
2503
2504 /* XXX what values for the timeouts? */
2505 dsi_set_stop_state_counter(1000);
2506 dsi_set_ta_timeout(6400000);
2507 dsi_set_lp_rx_timeout(48000);
2508 dsi_set_hs_tx_timeout(1000000);
2509
2510 switch (dssdev->ctrl.pixel_size) {
2511 case 16:
2512 buswidth = 0;
2513 break;
2514 case 18:
2515 buswidth = 1;
2516 break;
2517 case 24:
2518 buswidth = 2;
2519 break;
2520 default:
2521 BUG();
2522 }
2523
2524 r = dsi_read_reg(DSI_CTRL);
2525 r = FLD_MOD(r, 1, 1, 1); /* CS_RX_EN */
2526 r = FLD_MOD(r, 1, 2, 2); /* ECC_RX_EN */
2527 r = FLD_MOD(r, 1, 3, 3); /* TX_FIFO_ARBITRATION */
2528 r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/
2529 r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */
2530 r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */
2531 r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */
2532 r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */
2533 r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */
2534 r = FLD_MOD(r, 1, 24, 24); /* DCS_CMD_ENABLE */
2535 r = FLD_MOD(r, 0, 25, 25); /* DCS_CMD_CODE, 1=start, 0=continue */
2536
2537 dsi_write_reg(DSI_CTRL, r);
2538
2539 dsi_vc_initial_config(0);
2540
2541 /* set all vc targets to peripheral 0 */
2542 dsi.vc[0].dest_per = 0;
2543 dsi.vc[1].dest_per = 0;
2544 dsi.vc[2].dest_per = 0;
2545 dsi.vc[3].dest_per = 0;
2546
2547 return 0;
2548}
2549
2550static void dsi_proto_timings(struct omap_dss_device *dssdev)
2551{
2552 unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail;
2553 unsigned tclk_pre, tclk_post;
2554 unsigned ths_prepare, ths_prepare_ths_zero, ths_zero;
2555 unsigned ths_trail, ths_exit;
2556 unsigned ddr_clk_pre, ddr_clk_post;
2557 unsigned enter_hs_mode_lat, exit_hs_mode_lat;
2558 unsigned ths_eot;
2559 u32 r;
2560
2561 r = dsi_read_reg(DSI_DSIPHY_CFG0);
2562 ths_prepare = FLD_GET(r, 31, 24);
2563 ths_prepare_ths_zero = FLD_GET(r, 23, 16);
2564 ths_zero = ths_prepare_ths_zero - ths_prepare;
2565 ths_trail = FLD_GET(r, 15, 8);
2566 ths_exit = FLD_GET(r, 7, 0);
2567
2568 r = dsi_read_reg(DSI_DSIPHY_CFG1);
2569 tlpx = FLD_GET(r, 22, 16) * 2;
2570 tclk_trail = FLD_GET(r, 15, 8);
2571 tclk_zero = FLD_GET(r, 7, 0);
2572
2573 r = dsi_read_reg(DSI_DSIPHY_CFG2);
2574 tclk_prepare = FLD_GET(r, 7, 0);
2575
2576 /* min 8*UI */
2577 tclk_pre = 20;
2578 /* min 60ns + 52*UI */
2579 tclk_post = ns2ddr(60) + 26;
2580
2581 /* ths_eot is 2 for 2 datalanes and 4 for 1 datalane */
2582 if (dssdev->phy.dsi.data1_lane != 0 &&
2583 dssdev->phy.dsi.data2_lane != 0)
2584 ths_eot = 2;
2585 else
2586 ths_eot = 4;
2587
2588 ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare,
2589 4);
2590 ddr_clk_post = DIV_ROUND_UP(tclk_post + ths_trail, 4) + ths_eot;
2591
2592 BUG_ON(ddr_clk_pre == 0 || ddr_clk_pre > 255);
2593 BUG_ON(ddr_clk_post == 0 || ddr_clk_post > 255);
2594
2595 r = dsi_read_reg(DSI_CLK_TIMING);
2596 r = FLD_MOD(r, ddr_clk_pre, 15, 8);
2597 r = FLD_MOD(r, ddr_clk_post, 7, 0);
2598 dsi_write_reg(DSI_CLK_TIMING, r);
2599
2600 DSSDBG("ddr_clk_pre %u, ddr_clk_post %u\n",
2601 ddr_clk_pre,
2602 ddr_clk_post);
2603
2604 enter_hs_mode_lat = 1 + DIV_ROUND_UP(tlpx, 4) +
2605 DIV_ROUND_UP(ths_prepare, 4) +
2606 DIV_ROUND_UP(ths_zero + 3, 4);
2607
2608 exit_hs_mode_lat = DIV_ROUND_UP(ths_trail + ths_exit, 4) + 1 + ths_eot;
2609
2610 r = FLD_VAL(enter_hs_mode_lat, 31, 16) |
2611 FLD_VAL(exit_hs_mode_lat, 15, 0);
2612 dsi_write_reg(DSI_VM_TIMING7, r);
2613
2614 DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n",
2615 enter_hs_mode_lat, exit_hs_mode_lat);
2616}
2617
2618
2619#define DSI_DECL_VARS \
2620 int __dsi_cb = 0; u32 __dsi_cv = 0;
2621
2622#define DSI_FLUSH(ch) \
2623 if (__dsi_cb > 0) { \
2624 /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \
2625 dsi_write_reg(DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \
2626 __dsi_cb = __dsi_cv = 0; \
2627 }
2628
2629#define DSI_PUSH(ch, data) \
2630 do { \
2631 __dsi_cv |= (data) << (__dsi_cb * 8); \
2632 /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \
2633 if (++__dsi_cb > 3) \
2634 DSI_FLUSH(ch); \
2635 } while (0)
2636
2637static int dsi_update_screen_l4(struct omap_dss_device *dssdev,
2638 int x, int y, int w, int h)
2639{
2640 /* Note: supports only 24bit colors in 32bit container */
2641 int first = 1;
2642 int fifo_stalls = 0;
2643 int max_dsi_packet_size;
2644 int max_data_per_packet;
2645 int max_pixels_per_packet;
2646 int pixels_left;
2647 int bytespp = dssdev->ctrl.pixel_size / 8;
2648 int scr_width;
2649 u32 __iomem *data;
2650 int start_offset;
2651 int horiz_inc;
2652 int current_x;
2653 struct omap_overlay *ovl;
2654
2655 debug_irq = 0;
2656
2657 DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n",
2658 x, y, w, h);
2659
2660 ovl = dssdev->manager->overlays[0];
2661
2662 if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U)
2663 return -EINVAL;
2664
2665 if (dssdev->ctrl.pixel_size != 24)
2666 return -EINVAL;
2667
2668 scr_width = ovl->info.screen_width;
2669 data = ovl->info.vaddr;
2670
2671 start_offset = scr_width * y + x;
2672 horiz_inc = scr_width - w;
2673 current_x = x;
2674
2675 /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes
2676 * in fifo */
2677
2678 /* When using CPU, max long packet size is TX buffer size */
2679 max_dsi_packet_size = dsi.vc[0].fifo_size * 32 * 4;
2680
2681 /* we seem to get better perf if we divide the tx fifo to half,
2682 and while the other half is being sent, we fill the other half
2683 max_dsi_packet_size /= 2; */
2684
2685 max_data_per_packet = max_dsi_packet_size - 4 - 1;
2686
2687 max_pixels_per_packet = max_data_per_packet / bytespp;
2688
2689 DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet);
2690
2691 pixels_left = w * h;
2692
2693 DSSDBG("total pixels %d\n", pixels_left);
2694
2695 data += start_offset;
2696
2697 while (pixels_left > 0) {
2698 /* 0x2c = write_memory_start */
2699 /* 0x3c = write_memory_continue */
2700 u8 dcs_cmd = first ? 0x2c : 0x3c;
2701 int pixels;
2702 DSI_DECL_VARS;
2703 first = 0;
2704
2705#if 1
2706 /* using fifo not empty */
2707 /* TX_FIFO_NOT_EMPTY */
2708 while (FLD_GET(dsi_read_reg(DSI_VC_CTRL(0)), 5, 5)) {
2709 fifo_stalls++;
2710 if (fifo_stalls > 0xfffff) {
2711 DSSERR("fifo stalls overflow, pixels left %d\n",
2712 pixels_left);
2713 dsi_if_enable(0);
2714 return -EIO;
2715 }
2716 udelay(1);
2717 }
2718#elif 1
2719 /* using fifo emptiness */
2720 while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 <
2721 max_dsi_packet_size) {
2722 fifo_stalls++;
2723 if (fifo_stalls > 0xfffff) {
2724 DSSERR("fifo stalls overflow, pixels left %d\n",
2725 pixels_left);
2726 dsi_if_enable(0);
2727 return -EIO;
2728 }
2729 }
2730#else
2731 while ((REG_GET(DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 == 0) {
2732 fifo_stalls++;
2733 if (fifo_stalls > 0xfffff) {
2734 DSSERR("fifo stalls overflow, pixels left %d\n",
2735 pixels_left);
2736 dsi_if_enable(0);
2737 return -EIO;
2738 }
2739 }
2740#endif
2741 pixels = min(max_pixels_per_packet, pixels_left);
2742
2743 pixels_left -= pixels;
2744
2745 dsi_vc_write_long_header(0, DSI_DT_DCS_LONG_WRITE,
2746 1 + pixels * bytespp, 0);
2747
2748 DSI_PUSH(0, dcs_cmd);
2749
2750 while (pixels-- > 0) {
2751 u32 pix = __raw_readl(data++);
2752
2753 DSI_PUSH(0, (pix >> 16) & 0xff);
2754 DSI_PUSH(0, (pix >> 8) & 0xff);
2755 DSI_PUSH(0, (pix >> 0) & 0xff);
2756
2757 current_x++;
2758 if (current_x == x+w) {
2759 current_x = x;
2760 data += horiz_inc;
2761 }
2762 }
2763
2764 DSI_FLUSH(0);
2765 }
2766
2767 return 0;
2768}
2769
2770static void dsi_update_screen_dispc(struct omap_dss_device *dssdev,
2771 u16 x, u16 y, u16 w, u16 h)
2772{
2773 unsigned bytespp;
2774 unsigned bytespl;
2775 unsigned bytespf;
2776 unsigned total_len;
2777 unsigned packet_payload;
2778 unsigned packet_len;
2779 u32 l;
2780 bool use_te_trigger;
2781 const unsigned channel = 0;
2782 /* line buffer is 1024 x 24bits */
2783 /* XXX: for some reason using full buffer size causes considerable TX
2784 * slowdown with update sizes that fill the whole buffer */
2785 const unsigned line_buf_size = 1023 * 3;
2786
2787 use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
2788
2789 if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
2790 DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n",
2791 x, y, w, h);
2792
2793 bytespp = dssdev->ctrl.pixel_size / 8;
2794 bytespl = w * bytespp;
2795 bytespf = bytespl * h;
2796
2797 /* NOTE: packet_payload has to be equal to N * bytespl, where N is
2798 * number of lines in a packet. See errata about VP_CLK_RATIO */
2799
2800 if (bytespf < line_buf_size)
2801 packet_payload = bytespf;
2802 else
2803 packet_payload = (line_buf_size) / bytespl * bytespl;
2804
2805 packet_len = packet_payload + 1; /* 1 byte for DCS cmd */
2806 total_len = (bytespf / packet_payload) * packet_len;
2807
2808 if (bytespf % packet_payload)
2809 total_len += (bytespf % packet_payload) + 1;
2810
2811 if (0)
2812 dsi_vc_print_status(1);
2813
2814 l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */
2815 dsi_write_reg(DSI_VC_TE(channel), l);
2816
2817 dsi_vc_write_long_header(channel, DSI_DT_DCS_LONG_WRITE, packet_len, 0);
2818
2819 if (use_te_trigger)
2820 l = FLD_MOD(l, 1, 30, 30); /* TE_EN */
2821 else
2822 l = FLD_MOD(l, 1, 31, 31); /* TE_START */
2823 dsi_write_reg(DSI_VC_TE(channel), l);
2824
2825 /* We put SIDLEMODE to no-idle for the duration of the transfer,
2826 * because DSS interrupts are not capable of waking up the CPU and the
2827 * framedone interrupt could be delayed for quite a long time. I think
2828 * the same goes for any DSS interrupts, but for some reason I have not
2829 * seen the problem anywhere else than here.
2830 */
2831 dispc_disable_sidle();
2832
2833 dss_start_update(dssdev);
2834
2835 if (use_te_trigger) {
2836 /* disable LP_RX_TO, so that we can receive TE. Time to wait
2837 * for TE is longer than the timer allows */
2838 REG_FLD_MOD(DSI_TIMING2, 0, 15, 15); /* LP_RX_TO */
2839
2840 dsi_vc_send_bta(channel);
2841
2842#ifdef DSI_CATCH_MISSING_TE
2843 mod_timer(&dsi.te_timer, jiffies + msecs_to_jiffies(250));
2844#endif
2845 }
2846}
2847
2848#ifdef DSI_CATCH_MISSING_TE
2849static void dsi_te_timeout(unsigned long arg)
2850{
2851 DSSERR("TE not received for 250ms!\n");
2852}
2853#endif
2854
2855static void dsi_framedone_irq_callback(void *data, u32 mask)
2856{
2857 /* Note: We get FRAMEDONE when DISPC has finished sending pixels and
2858 * turns itself off. However, DSI still has the pixels in its buffers,
2859 * and is sending the data.
2860 */
2861
2862 /* SIDLEMODE back to smart-idle */
2863 dispc_enable_sidle();
2864
2865 dsi.framedone_received = true;
2866 wake_up(&dsi.waitqueue);
2867}
2868
2869static void dsi_set_update_region(struct omap_dss_device *dssdev,
2870 u16 x, u16 y, u16 w, u16 h)
2871{
2872 spin_lock(&dsi.update_lock);
2873 if (dsi.update_region.dirty) {
2874 dsi.update_region.x = min(x, dsi.update_region.x);
2875 dsi.update_region.y = min(y, dsi.update_region.y);
2876 dsi.update_region.w = max(w, dsi.update_region.w);
2877 dsi.update_region.h = max(h, dsi.update_region.h);
2878 } else {
2879 dsi.update_region.x = x;
2880 dsi.update_region.y = y;
2881 dsi.update_region.w = w;
2882 dsi.update_region.h = h;
2883 }
2884
2885 dsi.update_region.device = dssdev;
2886 dsi.update_region.dirty = true;
2887
2888 spin_unlock(&dsi.update_lock);
2889
2890}
2891
2892static int dsi_set_update_mode(struct omap_dss_device *dssdev,
2893 enum omap_dss_update_mode mode)
2894{
2895 int r = 0;
2896 int i;
2897
2898 WARN_ON(!mutex_is_locked(&dsi.bus_lock));
2899
2900 if (dsi.update_mode != mode) {
2901 dsi.update_mode = mode;
2902
2903 /* Mark the overlays dirty, and do apply(), so that we get the
2904 * overlays configured properly after update mode change. */
2905 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
2906 struct omap_overlay *ovl;
2907 ovl = omap_dss_get_overlay(i);
2908 if (ovl->manager == dssdev->manager)
2909 ovl->info_dirty = true;
2910 }
2911
2912 r = dssdev->manager->apply(dssdev->manager);
2913
2914 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE &&
2915 mode == OMAP_DSS_UPDATE_AUTO) {
2916 u16 w, h;
2917
2918 DSSDBG("starting auto update\n");
2919
2920 dssdev->get_resolution(dssdev, &w, &h);
2921
2922 dsi_set_update_region(dssdev, 0, 0, w, h);
2923
2924 dsi_perf_mark_start_auto();
2925
2926 wake_up(&dsi.waitqueue);
2927 }
2928 }
2929
2930 return r;
2931}
2932
2933static int dsi_set_te(struct omap_dss_device *dssdev, bool enable)
2934{
2935 int r = 0;
2936
2937 if (dssdev->driver->enable_te) {
2938 r = dssdev->driver->enable_te(dssdev, enable);
2939 /* XXX for some reason, DSI TE breaks if we don't wait here.
2940 * Panel bug? Needs more studying */
2941 msleep(100);
2942 }
2943
2944 return r;
2945}
2946
2947static void dsi_handle_framedone(void)
2948{
2949 int r;
2950 const int channel = 0;
2951 bool use_te_trigger;
2952
2953 use_te_trigger = dsi.te_enabled && !dsi.use_ext_te;
2954
2955 if (dsi.update_mode != OMAP_DSS_UPDATE_AUTO)
2956 DSSDBG("FRAMEDONE\n");
2957
2958 if (use_te_trigger) {
2959 /* enable LP_RX_TO again after the TE */
2960 REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */
2961 }
2962
2963 /* Send BTA after the frame. We need this for the TE to work, as TE
2964 * trigger is only sent for BTAs without preceding packet. Thus we need
2965 * to BTA after the pixel packets so that next BTA will cause TE
2966 * trigger.
2967 *
2968 * This is not needed when TE is not in use, but we do it anyway to
2969 * make sure that the transfer has been completed. It would be more
2970 * optimal, but more complex, to wait only just before starting next
2971 * transfer. */
2972 r = dsi_vc_send_bta_sync(channel);
2973 if (r)
2974 DSSERR("BTA after framedone failed\n");
2975
2976 /* RX_FIFO_NOT_EMPTY */
2977 if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) {
2978 DSSERR("Received error during frame transfer:\n");
2979 dsi_vc_flush_receive_data(0);
2980 }
2981
2982#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC
2983 dispc_fake_vsync_irq();
2984#endif
2985}
2986
2987static int dsi_update_thread(void *data)
2988{
2989 unsigned long timeout;
2990 struct omap_dss_device *device;
2991 u16 x, y, w, h;
2992
2993 while (1) {
2994 bool sched;
2995
2996 wait_event_interruptible(dsi.waitqueue,
2997 dsi.update_mode == OMAP_DSS_UPDATE_AUTO ||
2998 (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
2999 dsi.update_region.dirty == true) ||
3000 kthread_should_stop());
3001
3002 if (kthread_should_stop())
3003 break;
3004
3005 dsi_bus_lock();
3006
3007 if (dsi.update_mode == OMAP_DSS_UPDATE_DISABLED ||
3008 kthread_should_stop()) {
3009 dsi_bus_unlock();
3010 break;
3011 }
3012
3013 dsi_perf_mark_setup();
3014
3015 if (dsi.update_region.dirty) {
3016 spin_lock(&dsi.update_lock);
3017 dsi.active_update_region = dsi.update_region;
3018 dsi.update_region.dirty = false;
3019 spin_unlock(&dsi.update_lock);
3020 }
3021
3022 device = dsi.active_update_region.device;
3023 x = dsi.active_update_region.x;
3024 y = dsi.active_update_region.y;
3025 w = dsi.active_update_region.w;
3026 h = dsi.active_update_region.h;
3027
3028 if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
3029
3030 if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL)
3031 dss_setup_partial_planes(device,
3032 &x, &y, &w, &h);
3033
3034 dispc_set_lcd_size(w, h);
3035 }
3036
3037 if (dsi.active_update_region.dirty) {
3038 dsi.active_update_region.dirty = false;
3039 /* XXX TODO we don't need to send the coords, if they
3040 * are the same that are already programmed to the
3041 * panel. That should speed up manual update a bit */
3042 device->driver->setup_update(device, x, y, w, h);
3043 }
3044
3045 dsi_perf_mark_start();
3046
3047 if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
3048 dsi_vc_config_vp(0);
3049
3050 if (dsi.te_enabled && dsi.use_ext_te)
3051 device->driver->wait_for_te(device);
3052
3053 dsi.framedone_received = false;
3054
3055 dsi_update_screen_dispc(device, x, y, w, h);
3056
3057 /* wait for framedone */
3058 timeout = msecs_to_jiffies(1000);
3059 wait_event_timeout(dsi.waitqueue,
3060 dsi.framedone_received == true,
3061 timeout);
3062
3063 if (!dsi.framedone_received) {
3064 DSSERR("framedone timeout\n");
3065 DSSERR("failed update %d,%d %dx%d\n",
3066 x, y, w, h);
3067
3068 dispc_enable_sidle();
3069 dispc_enable_lcd_out(0);
3070
3071 dsi_reset_tx_fifo(0);
3072 } else {
3073 dsi_handle_framedone();
3074 dsi_perf_show("DISPC");
3075 }
3076 } else {
3077 dsi_update_screen_l4(device, x, y, w, h);
3078 dsi_perf_show("L4");
3079 }
3080
3081 sched = atomic_read(&dsi.bus_lock.count) < 0;
3082
3083 complete_all(&dsi.update_completion);
3084
3085 dsi_bus_unlock();
3086
3087 /* XXX We need to give others chance to get the bus lock. Is
3088 * there a better way for this? */
3089 if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO && sched)
3090 schedule_timeout_interruptible(1);
3091 }
3092
3093 DSSDBG("update thread exiting\n");
3094
3095 return 0;
3096}
3097
3098
3099
3100/* Display funcs */
3101
3102static int dsi_display_init_dispc(struct omap_dss_device *dssdev)
3103{
3104 int r;
3105
3106 r = omap_dispc_register_isr(dsi_framedone_irq_callback, NULL,
3107 DISPC_IRQ_FRAMEDONE);
3108 if (r) {
3109 DSSERR("can't get FRAMEDONE irq\n");
3110 return r;
3111 }
3112
3113 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
3114
3115 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_DSI);
3116 dispc_enable_fifohandcheck(1);
3117
3118 dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
3119
3120 {
3121 struct omap_video_timings timings = {
3122 .hsw = 1,
3123 .hfp = 1,
3124 .hbp = 1,
3125 .vsw = 1,
3126 .vfp = 0,
3127 .vbp = 0,
3128 };
3129
3130 dispc_set_lcd_timings(&timings);
3131 }
3132
3133 return 0;
3134}
3135
3136static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev)
3137{
3138 omap_dispc_unregister_isr(dsi_framedone_irq_callback, NULL,
3139 DISPC_IRQ_FRAMEDONE);
3140}
3141
3142static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev)
3143{
3144 struct dsi_clock_info cinfo;
3145 int r;
3146
3147 /* we always use DSS2_FCK as input clock */
3148 cinfo.use_dss2_fck = true;
3149 cinfo.regn = dssdev->phy.dsi.div.regn;
3150 cinfo.regm = dssdev->phy.dsi.div.regm;
3151 cinfo.regm3 = dssdev->phy.dsi.div.regm3;
3152 cinfo.regm4 = dssdev->phy.dsi.div.regm4;
3153 r = dsi_calc_clock_rates(&cinfo);
3154 if (r)
3155 return r;
3156
3157 r = dsi_pll_set_clock_div(&cinfo);
3158 if (r) {
3159 DSSERR("Failed to set dsi clocks\n");
3160 return r;
3161 }
3162
3163 return 0;
3164}
3165
3166static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev)
3167{
3168 struct dispc_clock_info dispc_cinfo;
3169 int r;
3170 unsigned long long fck;
3171
3172 fck = dsi_get_dsi1_pll_rate();
3173
3174 dispc_cinfo.lck_div = dssdev->phy.dsi.div.lck_div;
3175 dispc_cinfo.pck_div = dssdev->phy.dsi.div.pck_div;
3176
3177 r = dispc_calc_clock_rates(fck, &dispc_cinfo);
3178 if (r) {
3179 DSSERR("Failed to calc dispc clocks\n");
3180 return r;
3181 }
3182
3183 r = dispc_set_clock_div(&dispc_cinfo);
3184 if (r) {
3185 DSSERR("Failed to set dispc clocks\n");
3186 return r;
3187 }
3188
3189 return 0;
3190}
3191
3192static int dsi_display_init_dsi(struct omap_dss_device *dssdev)
3193{
3194 int r;
3195
3196 _dsi_print_reset_status();
3197
3198 r = dsi_pll_init(dssdev, true, true);
3199 if (r)
3200 goto err0;
3201
3202 r = dsi_configure_dsi_clocks(dssdev);
3203 if (r)
3204 goto err1;
3205
3206 dss_select_clk_source(true, true);
3207
3208 DSSDBG("PLL OK\n");
3209
3210 r = dsi_configure_dispc_clocks(dssdev);
3211 if (r)
3212 goto err2;
3213
3214 r = dsi_complexio_init(dssdev);
3215 if (r)
3216 goto err2;
3217
3218 _dsi_print_reset_status();
3219
3220 dsi_proto_timings(dssdev);
3221 dsi_set_lp_clk_divisor(dssdev);
3222
3223 if (1)
3224 _dsi_print_reset_status();
3225
3226 r = dsi_proto_config(dssdev);
3227 if (r)
3228 goto err3;
3229
3230 /* enable interface */
3231 dsi_vc_enable(0, 1);
3232 dsi_if_enable(1);
3233 dsi_force_tx_stop_mode_io();
3234
3235 if (dssdev->driver->enable) {
3236 r = dssdev->driver->enable(dssdev);
3237 if (r)
3238 goto err4;
3239 }
3240
3241 /* enable high-speed after initial config */
3242 dsi_vc_enable_hs(0, 1);
3243
3244 return 0;
3245err4:
3246 dsi_if_enable(0);
3247err3:
3248 dsi_complexio_uninit();
3249err2:
3250 dss_select_clk_source(false, false);
3251err1:
3252 dsi_pll_uninit();
3253err0:
3254 return r;
3255}
3256
3257static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev)
3258{
3259 if (dssdev->driver->disable)
3260 dssdev->driver->disable(dssdev);
3261
3262 dss_select_clk_source(false, false);
3263 dsi_complexio_uninit();
3264 dsi_pll_uninit();
3265}
3266
3267static int dsi_core_init(void)
3268{
3269 /* Autoidle */
3270 REG_FLD_MOD(DSI_SYSCONFIG, 1, 0, 0);
3271
3272 /* ENWAKEUP */
3273 REG_FLD_MOD(DSI_SYSCONFIG, 1, 2, 2);
3274
3275 /* SIDLEMODE smart-idle */
3276 REG_FLD_MOD(DSI_SYSCONFIG, 2, 4, 3);
3277
3278 _dsi_initialize_irq();
3279
3280 return 0;
3281}
3282
3283static int dsi_display_enable(struct omap_dss_device *dssdev)
3284{
3285 int r = 0;
3286
3287 DSSDBG("dsi_display_enable\n");
3288
3289 mutex_lock(&dsi.lock);
3290 dsi_bus_lock();
3291
3292 r = omap_dss_start_device(dssdev);
3293 if (r) {
3294 DSSERR("failed to start device\n");
3295 goto err0;
3296 }
3297
3298 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
3299 DSSERR("dssdev already enabled\n");
3300 r = -EINVAL;
3301 goto err1;
3302 }
3303
3304 enable_clocks(1);
3305 dsi_enable_pll_clock(1);
3306
3307 r = _dsi_reset();
3308 if (r)
3309 goto err2;
3310
3311 dsi_core_init();
3312
3313 r = dsi_display_init_dispc(dssdev);
3314 if (r)
3315 goto err2;
3316
3317 r = dsi_display_init_dsi(dssdev);
3318 if (r)
3319 goto err3;
3320
3321 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
3322
3323 dsi.use_ext_te = dssdev->phy.dsi.ext_te;
3324 r = dsi_set_te(dssdev, dsi.te_enabled);
3325 if (r)
3326 goto err4;
3327
3328 dsi_set_update_mode(dssdev, dsi.user_update_mode);
3329
3330 dsi_bus_unlock();
3331 mutex_unlock(&dsi.lock);
3332
3333 return 0;
3334
3335err4:
3336
3337 dsi_display_uninit_dsi(dssdev);
3338err3:
3339 dsi_display_uninit_dispc(dssdev);
3340err2:
3341 enable_clocks(0);
3342 dsi_enable_pll_clock(0);
3343err1:
3344 omap_dss_stop_device(dssdev);
3345err0:
3346 dsi_bus_unlock();
3347 mutex_unlock(&dsi.lock);
3348 DSSDBG("dsi_display_enable FAILED\n");
3349 return r;
3350}
3351
3352static void dsi_display_disable(struct omap_dss_device *dssdev)
3353{
3354 DSSDBG("dsi_display_disable\n");
3355
3356 mutex_lock(&dsi.lock);
3357 dsi_bus_lock();
3358
3359 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
3360 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
3361 goto end;
3362
3363 dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
3364 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
3365
3366 dsi_display_uninit_dispc(dssdev);
3367
3368 dsi_display_uninit_dsi(dssdev);
3369
3370 enable_clocks(0);
3371 dsi_enable_pll_clock(0);
3372
3373 omap_dss_stop_device(dssdev);
3374end:
3375 dsi_bus_unlock();
3376 mutex_unlock(&dsi.lock);
3377}
3378
3379static int dsi_display_suspend(struct omap_dss_device *dssdev)
3380{
3381 DSSDBG("dsi_display_suspend\n");
3382
3383 mutex_lock(&dsi.lock);
3384 dsi_bus_lock();
3385
3386 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED ||
3387 dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
3388 goto end;
3389
3390 dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
3391 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
3392
3393 dsi_display_uninit_dispc(dssdev);
3394
3395 dsi_display_uninit_dsi(dssdev);
3396
3397 enable_clocks(0);
3398 dsi_enable_pll_clock(0);
3399end:
3400 dsi_bus_unlock();
3401 mutex_unlock(&dsi.lock);
3402
3403 return 0;
3404}
3405
3406static int dsi_display_resume(struct omap_dss_device *dssdev)
3407{
3408 int r;
3409
3410 DSSDBG("dsi_display_resume\n");
3411
3412 mutex_lock(&dsi.lock);
3413 dsi_bus_lock();
3414
3415 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
3416 DSSERR("dssdev not suspended\n");
3417 r = -EINVAL;
3418 goto err0;
3419 }
3420
3421 enable_clocks(1);
3422 dsi_enable_pll_clock(1);
3423
3424 r = _dsi_reset();
3425 if (r)
3426 goto err1;
3427
3428 dsi_core_init();
3429
3430 r = dsi_display_init_dispc(dssdev);
3431 if (r)
3432 goto err1;
3433
3434 r = dsi_display_init_dsi(dssdev);
3435 if (r)
3436 goto err2;
3437
3438 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
3439
3440 r = dsi_set_te(dssdev, dsi.te_enabled);
3441 if (r)
3442 goto err2;
3443
3444 dsi_set_update_mode(dssdev, dsi.user_update_mode);
3445
3446 dsi_bus_unlock();
3447 mutex_unlock(&dsi.lock);
3448
3449 return 0;
3450
3451err2:
3452 dsi_display_uninit_dispc(dssdev);
3453err1:
3454 enable_clocks(0);
3455 dsi_enable_pll_clock(0);
3456err0:
3457 dsi_bus_unlock();
3458 mutex_unlock(&dsi.lock);
3459 DSSDBG("dsi_display_resume FAILED\n");
3460 return r;
3461}
3462
3463static int dsi_display_update(struct omap_dss_device *dssdev,
3464 u16 x, u16 y, u16 w, u16 h)
3465{
3466 int r = 0;
3467 u16 dw, dh;
3468
3469 DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h);
3470
3471 mutex_lock(&dsi.lock);
3472
3473 if (dsi.update_mode != OMAP_DSS_UPDATE_MANUAL)
3474 goto end;
3475
3476 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
3477 goto end;
3478
3479 dssdev->get_resolution(dssdev, &dw, &dh);
3480
3481 if (x > dw || y > dh)
3482 goto end;
3483
3484 if (x + w > dw)
3485 w = dw - x;
3486
3487 if (y + h > dh)
3488 h = dh - y;
3489
3490 if (w == 0 || h == 0)
3491 goto end;
3492
3493 if (w == 1) {
3494 r = -EINVAL;
3495 goto end;
3496 }
3497
3498 dsi_set_update_region(dssdev, x, y, w, h);
3499
3500 wake_up(&dsi.waitqueue);
3501
3502end:
3503 mutex_unlock(&dsi.lock);
3504
3505 return r;
3506}
3507
3508static int dsi_display_sync(struct omap_dss_device *dssdev)
3509{
3510 bool wait;
3511
3512 DSSDBG("dsi_display_sync()\n");
3513
3514 mutex_lock(&dsi.lock);
3515 dsi_bus_lock();
3516
3517 if (dsi.update_mode == OMAP_DSS_UPDATE_MANUAL &&
3518 dsi.update_region.dirty) {
3519 INIT_COMPLETION(dsi.update_completion);
3520 wait = true;
3521 } else {
3522 wait = false;
3523 }
3524
3525 dsi_bus_unlock();
3526 mutex_unlock(&dsi.lock);
3527
3528 if (wait)
3529 wait_for_completion_interruptible(&dsi.update_completion);
3530
3531 DSSDBG("dsi_display_sync() done\n");
3532 return 0;
3533}
3534
3535static int dsi_display_set_update_mode(struct omap_dss_device *dssdev,
3536 enum omap_dss_update_mode mode)
3537{
3538 int r = 0;
3539
3540 DSSDBGF("%d", mode);
3541
3542 mutex_lock(&dsi.lock);
3543 dsi_bus_lock();
3544
3545 dsi.user_update_mode = mode;
3546 r = dsi_set_update_mode(dssdev, mode);
3547
3548 dsi_bus_unlock();
3549 mutex_unlock(&dsi.lock);
3550
3551 return r;
3552}
3553
3554static enum omap_dss_update_mode dsi_display_get_update_mode(
3555 struct omap_dss_device *dssdev)
3556{
3557 return dsi.update_mode;
3558}
3559
3560
3561static int dsi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
3562{
3563 int r = 0;
3564
3565 DSSDBGF("%d", enable);
3566
3567 if (!dssdev->driver->enable_te)
3568 return -ENOENT;
3569
3570 dsi_bus_lock();
3571
3572 dsi.te_enabled = enable;
3573
3574 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
3575 goto end;
3576
3577 r = dsi_set_te(dssdev, enable);
3578end:
3579 dsi_bus_unlock();
3580
3581 return r;
3582}
3583
3584static int dsi_display_get_te(struct omap_dss_device *dssdev)
3585{
3586 return dsi.te_enabled;
3587}
3588
3589static int dsi_display_set_rotate(struct omap_dss_device *dssdev, u8 rotate)
3590{
3591
3592 DSSDBGF("%d", rotate);
3593
3594 if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
3595 return -EINVAL;
3596
3597 dsi_bus_lock();
3598 dssdev->driver->set_rotate(dssdev, rotate);
3599 if (dsi.update_mode == OMAP_DSS_UPDATE_AUTO) {
3600 u16 w, h;
3601 /* the display dimensions may have changed, so set a new
3602 * update region */
3603 dssdev->get_resolution(dssdev, &w, &h);
3604 dsi_set_update_region(dssdev, 0, 0, w, h);
3605 }
3606 dsi_bus_unlock();
3607
3608 return 0;
3609}
3610
3611static u8 dsi_display_get_rotate(struct omap_dss_device *dssdev)
3612{
3613 if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate)
3614 return 0;
3615
3616 return dssdev->driver->get_rotate(dssdev);
3617}
3618
3619static int dsi_display_set_mirror(struct omap_dss_device *dssdev, bool mirror)
3620{
3621 DSSDBGF("%d", mirror);
3622
3623 if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
3624 return -EINVAL;
3625
3626 dsi_bus_lock();
3627 dssdev->driver->set_mirror(dssdev, mirror);
3628 dsi_bus_unlock();
3629
3630 return 0;
3631}
3632
3633static bool dsi_display_get_mirror(struct omap_dss_device *dssdev)
3634{
3635 if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror)
3636 return 0;
3637
3638 return dssdev->driver->get_mirror(dssdev);
3639}
3640
3641static int dsi_display_run_test(struct omap_dss_device *dssdev, int test_num)
3642{
3643 int r;
3644
3645 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
3646 return -EIO;
3647
3648 DSSDBGF("%d", test_num);
3649
3650 dsi_bus_lock();
3651
3652 /* run test first in low speed mode */
3653 dsi_vc_enable_hs(0, 0);
3654
3655 if (dssdev->driver->run_test) {
3656 r = dssdev->driver->run_test(dssdev, test_num);
3657 if (r)
3658 goto end;
3659 }
3660
3661 /* then in high speed */
3662 dsi_vc_enable_hs(0, 1);
3663
3664 if (dssdev->driver->run_test) {
3665 r = dssdev->driver->run_test(dssdev, test_num);
3666 if (r)
3667 goto end;
3668 }
3669
3670end:
3671 dsi_vc_enable_hs(0, 1);
3672
3673 dsi_bus_unlock();
3674
3675 return r;
3676}
3677
3678static int dsi_display_memory_read(struct omap_dss_device *dssdev,
3679 void *buf, size_t size,
3680 u16 x, u16 y, u16 w, u16 h)
3681{
3682 int r;
3683
3684 DSSDBGF("");
3685
3686 if (!dssdev->driver->memory_read)
3687 return -EINVAL;
3688
3689 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
3690 return -EIO;
3691
3692 dsi_bus_lock();
3693
3694 r = dssdev->driver->memory_read(dssdev, buf, size,
3695 x, y, w, h);
3696
3697 /* Memory read usually changes the update area. This will
3698 * force the next update to re-set the update area */
3699 dsi.active_update_region.dirty = true;
3700
3701 dsi_bus_unlock();
3702
3703 return r;
3704}
3705
3706void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
3707 u32 fifo_size, enum omap_burst_size *burst_size,
3708 u32 *fifo_low, u32 *fifo_high)
3709{
3710 unsigned burst_size_bytes;
3711
3712 *burst_size = OMAP_DSS_BURST_16x32;
3713 burst_size_bytes = 16 * 32 / 8;
3714
3715 *fifo_high = fifo_size - burst_size_bytes;
3716 *fifo_low = fifo_size - burst_size_bytes * 8;
3717}
3718
3719int dsi_init_display(struct omap_dss_device *dssdev)
3720{
3721 DSSDBG("DSI init\n");
3722
3723 dssdev->enable = dsi_display_enable;
3724 dssdev->disable = dsi_display_disable;
3725 dssdev->suspend = dsi_display_suspend;
3726 dssdev->resume = dsi_display_resume;
3727 dssdev->update = dsi_display_update;
3728 dssdev->sync = dsi_display_sync;
3729 dssdev->set_update_mode = dsi_display_set_update_mode;
3730 dssdev->get_update_mode = dsi_display_get_update_mode;
3731 dssdev->enable_te = dsi_display_enable_te;
3732 dssdev->get_te = dsi_display_get_te;
3733
3734 dssdev->get_rotate = dsi_display_get_rotate;
3735 dssdev->set_rotate = dsi_display_set_rotate;
3736
3737 dssdev->get_mirror = dsi_display_get_mirror;
3738 dssdev->set_mirror = dsi_display_set_mirror;
3739
3740 dssdev->run_test = dsi_display_run_test;
3741 dssdev->memory_read = dsi_display_memory_read;
3742
3743 /* XXX these should be figured out dynamically */
3744 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE |
3745 OMAP_DSS_DISPLAY_CAP_TEAR_ELIM;
3746
3747 dsi.vc[0].dssdev = dssdev;
3748 dsi.vc[1].dssdev = dssdev;
3749
3750 return 0;
3751}
3752
3753int dsi_init(struct platform_device *pdev)
3754{
3755 u32 rev;
3756 int r;
3757 struct sched_param param = {
3758 .sched_priority = MAX_USER_RT_PRIO-1
3759 };
3760
3761 spin_lock_init(&dsi.errors_lock);
3762 dsi.errors = 0;
3763
3764#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
3765 spin_lock_init(&dsi.irq_stats_lock);
3766 dsi.irq_stats.last_reset = jiffies;
3767#endif
3768
3769 init_completion(&dsi.bta_completion);
3770 init_completion(&dsi.update_completion);
3771
3772 dsi.thread = kthread_create(dsi_update_thread, NULL, "dsi");
3773 if (IS_ERR(dsi.thread)) {
3774 DSSERR("cannot create kthread\n");
3775 r = PTR_ERR(dsi.thread);
3776 goto err0;
3777 }
3778 sched_setscheduler(dsi.thread, SCHED_FIFO, &param);
3779
3780 init_waitqueue_head(&dsi.waitqueue);
3781 spin_lock_init(&dsi.update_lock);
3782
3783 mutex_init(&dsi.lock);
3784 mutex_init(&dsi.bus_lock);
3785
3786#ifdef DSI_CATCH_MISSING_TE
3787 init_timer(&dsi.te_timer);
3788 dsi.te_timer.function = dsi_te_timeout;
3789 dsi.te_timer.data = 0;
3790#endif
3791
3792 dsi.update_mode = OMAP_DSS_UPDATE_DISABLED;
3793 dsi.user_update_mode = OMAP_DSS_UPDATE_DISABLED;
3794
3795 dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS);
3796 if (!dsi.base) {
3797 DSSERR("can't ioremap DSI\n");
3798 r = -ENOMEM;
3799 goto err1;
3800 }
3801
3802 dsi.vdds_dsi_reg = regulator_get(&pdev->dev, "vdds_dsi");
3803 if (IS_ERR(dsi.vdds_dsi_reg)) {
3804 iounmap(dsi.base);
3805 DSSERR("can't get VDDS_DSI regulator\n");
3806 r = PTR_ERR(dsi.vdds_dsi_reg);
3807 goto err2;
3808 }
3809
3810 enable_clocks(1);
3811
3812 rev = dsi_read_reg(DSI_REVISION);
3813 printk(KERN_INFO "OMAP DSI rev %d.%d\n",
3814 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
3815
3816 enable_clocks(0);
3817
3818 wake_up_process(dsi.thread);
3819
3820 return 0;
3821err2:
3822 iounmap(dsi.base);
3823err1:
3824 kthread_stop(dsi.thread);
3825err0:
3826 return r;
3827}
3828
3829void dsi_exit(void)
3830{
3831 kthread_stop(dsi.thread);
3832
3833 regulator_put(dsi.vdds_dsi_reg);
3834
3835 iounmap(dsi.base);
3836
3837 DSSDBG("omap_dsi_exit\n");
3838}
3839
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c
new file mode 100644
index 000000000000..0a26b7d84d41
--- /dev/null
+++ b/drivers/video/omap2/dss/dss.c
@@ -0,0 +1,596 @@
1/*
2 * linux/drivers/video/omap2/dss/dss.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DSS"
24
25#include <linux/kernel.h>
26#include <linux/io.h>
27#include <linux/err.h>
28#include <linux/delay.h>
29#include <linux/interrupt.h>
30#include <linux/seq_file.h>
31#include <linux/clk.h>
32
33#include <plat/display.h>
34#include "dss.h"
35
36#define DSS_BASE 0x48050000
37
38#define DSS_SZ_REGS SZ_512
39
40struct dss_reg {
41 u16 idx;
42};
43
44#define DSS_REG(idx) ((const struct dss_reg) { idx })
45
46#define DSS_REVISION DSS_REG(0x0000)
47#define DSS_SYSCONFIG DSS_REG(0x0010)
48#define DSS_SYSSTATUS DSS_REG(0x0014)
49#define DSS_IRQSTATUS DSS_REG(0x0018)
50#define DSS_CONTROL DSS_REG(0x0040)
51#define DSS_SDI_CONTROL DSS_REG(0x0044)
52#define DSS_PLL_CONTROL DSS_REG(0x0048)
53#define DSS_SDI_STATUS DSS_REG(0x005C)
54
55#define REG_GET(idx, start, end) \
56 FLD_GET(dss_read_reg(idx), start, end)
57
58#define REG_FLD_MOD(idx, val, start, end) \
59 dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
60
61static struct {
62 void __iomem *base;
63
64 struct clk *dpll4_m4_ck;
65
66 unsigned long cache_req_pck;
67 unsigned long cache_prate;
68 struct dss_clock_info cache_dss_cinfo;
69 struct dispc_clock_info cache_dispc_cinfo;
70
71 u32 ctx[DSS_SZ_REGS / sizeof(u32)];
72} dss;
73
74static int _omap_dss_wait_reset(void);
75
76static inline void dss_write_reg(const struct dss_reg idx, u32 val)
77{
78 __raw_writel(val, dss.base + idx.idx);
79}
80
81static inline u32 dss_read_reg(const struct dss_reg idx)
82{
83 return __raw_readl(dss.base + idx.idx);
84}
85
86#define SR(reg) \
87 dss.ctx[(DSS_##reg).idx / sizeof(u32)] = dss_read_reg(DSS_##reg)
88#define RR(reg) \
89 dss_write_reg(DSS_##reg, dss.ctx[(DSS_##reg).idx / sizeof(u32)])
90
91void dss_save_context(void)
92{
93 if (cpu_is_omap24xx())
94 return;
95
96 SR(SYSCONFIG);
97 SR(CONTROL);
98
99#ifdef CONFIG_OMAP2_DSS_SDI
100 SR(SDI_CONTROL);
101 SR(PLL_CONTROL);
102#endif
103}
104
105void dss_restore_context(void)
106{
107 if (_omap_dss_wait_reset())
108 DSSERR("DSS not coming out of reset after sleep\n");
109
110 RR(SYSCONFIG);
111 RR(CONTROL);
112
113#ifdef CONFIG_OMAP2_DSS_SDI
114 RR(SDI_CONTROL);
115 RR(PLL_CONTROL);
116#endif
117}
118
119#undef SR
120#undef RR
121
122void dss_sdi_init(u8 datapairs)
123{
124 u32 l;
125
126 BUG_ON(datapairs > 3 || datapairs < 1);
127
128 l = dss_read_reg(DSS_SDI_CONTROL);
129 l = FLD_MOD(l, 0xf, 19, 15); /* SDI_PDIV */
130 l = FLD_MOD(l, datapairs-1, 3, 2); /* SDI_PRSEL */
131 l = FLD_MOD(l, 2, 1, 0); /* SDI_BWSEL */
132 dss_write_reg(DSS_SDI_CONTROL, l);
133
134 l = dss_read_reg(DSS_PLL_CONTROL);
135 l = FLD_MOD(l, 0x7, 25, 22); /* SDI_PLL_FREQSEL */
136 l = FLD_MOD(l, 0xb, 16, 11); /* SDI_PLL_REGN */
137 l = FLD_MOD(l, 0xb4, 10, 1); /* SDI_PLL_REGM */
138 dss_write_reg(DSS_PLL_CONTROL, l);
139}
140
141int dss_sdi_enable(void)
142{
143 unsigned long timeout;
144
145 dispc_pck_free_enable(1);
146
147 /* Reset SDI PLL */
148 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 18, 18); /* SDI_PLL_SYSRESET */
149 udelay(1); /* wait 2x PCLK */
150
151 /* Lock SDI PLL */
152 REG_FLD_MOD(DSS_PLL_CONTROL, 1, 28, 28); /* SDI_PLL_GOBIT */
153
154 /* Waiting for PLL lock request to complete */
155 timeout = jiffies + msecs_to_jiffies(500);
156 while (dss_read_reg(DSS_SDI_STATUS) & (1 << 6)) {
157 if (time_after_eq(jiffies, timeout)) {
158 DSSERR("PLL lock request timed out\n");
159 goto err1;
160 }
161 }
162
163 /* Clearing PLL_GO bit */
164 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 28, 28);
165
166 /* Waiting for PLL to lock */
167 timeout = jiffies + msecs_to_jiffies(500);
168 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 5))) {
169 if (time_after_eq(jiffies, timeout)) {
170 DSSERR("PLL lock timed out\n");
171 goto err1;
172 }
173 }
174
175 dispc_lcd_enable_signal(1);
176
177 /* Waiting for SDI reset to complete */
178 timeout = jiffies + msecs_to_jiffies(500);
179 while (!(dss_read_reg(DSS_SDI_STATUS) & (1 << 2))) {
180 if (time_after_eq(jiffies, timeout)) {
181 DSSERR("SDI reset timed out\n");
182 goto err2;
183 }
184 }
185
186 return 0;
187
188 err2:
189 dispc_lcd_enable_signal(0);
190 err1:
191 /* Reset SDI PLL */
192 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
193
194 dispc_pck_free_enable(0);
195
196 return -ETIMEDOUT;
197}
198
199void dss_sdi_disable(void)
200{
201 dispc_lcd_enable_signal(0);
202
203 dispc_pck_free_enable(0);
204
205 /* Reset SDI PLL */
206 REG_FLD_MOD(DSS_PLL_CONTROL, 0, 18, 18); /* SDI_PLL_SYSRESET */
207}
208
209void dss_dump_clocks(struct seq_file *s)
210{
211 unsigned long dpll4_ck_rate;
212 unsigned long dpll4_m4_ck_rate;
213
214 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
215
216 dpll4_ck_rate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
217 dpll4_m4_ck_rate = clk_get_rate(dss.dpll4_m4_ck);
218
219 seq_printf(s, "- DSS -\n");
220
221 seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate);
222
223 seq_printf(s, "dss1_alwon_fclk = %lu / %lu * 2 = %lu\n",
224 dpll4_ck_rate,
225 dpll4_ck_rate / dpll4_m4_ck_rate,
226 dss_clk_get_rate(DSS_CLK_FCK1));
227
228 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
229}
230
231void dss_dump_regs(struct seq_file *s)
232{
233#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r))
234
235 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
236
237 DUMPREG(DSS_REVISION);
238 DUMPREG(DSS_SYSCONFIG);
239 DUMPREG(DSS_SYSSTATUS);
240 DUMPREG(DSS_IRQSTATUS);
241 DUMPREG(DSS_CONTROL);
242 DUMPREG(DSS_SDI_CONTROL);
243 DUMPREG(DSS_PLL_CONTROL);
244 DUMPREG(DSS_SDI_STATUS);
245
246 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
247#undef DUMPREG
248}
249
250void dss_select_clk_source(bool dsi, bool dispc)
251{
252 u32 r;
253 r = dss_read_reg(DSS_CONTROL);
254 r = FLD_MOD(r, dsi, 1, 1); /* DSI_CLK_SWITCH */
255 r = FLD_MOD(r, dispc, 0, 0); /* DISPC_CLK_SWITCH */
256 dss_write_reg(DSS_CONTROL, r);
257}
258
259int dss_get_dsi_clk_source(void)
260{
261 return FLD_GET(dss_read_reg(DSS_CONTROL), 1, 1);
262}
263
264int dss_get_dispc_clk_source(void)
265{
266 return FLD_GET(dss_read_reg(DSS_CONTROL), 0, 0);
267}
268
269/* calculate clock rates using dividers in cinfo */
270int dss_calc_clock_rates(struct dss_clock_info *cinfo)
271{
272 unsigned long prate;
273
274 if (cinfo->fck_div > 16 || cinfo->fck_div == 0)
275 return -EINVAL;
276
277 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
278
279 cinfo->fck = prate / cinfo->fck_div;
280
281 return 0;
282}
283
284int dss_set_clock_div(struct dss_clock_info *cinfo)
285{
286 unsigned long prate;
287 int r;
288
289 if (cpu_is_omap34xx()) {
290 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
291 DSSDBG("dpll4_m4 = %ld\n", prate);
292
293 r = clk_set_rate(dss.dpll4_m4_ck, prate / cinfo->fck_div);
294 if (r)
295 return r;
296 }
297
298 DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div);
299
300 return 0;
301}
302
303int dss_get_clock_div(struct dss_clock_info *cinfo)
304{
305 cinfo->fck = dss_clk_get_rate(DSS_CLK_FCK1);
306
307 if (cpu_is_omap34xx()) {
308 unsigned long prate;
309 prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
310 cinfo->fck_div = prate / (cinfo->fck / 2);
311 } else {
312 cinfo->fck_div = 0;
313 }
314
315 return 0;
316}
317
318unsigned long dss_get_dpll4_rate(void)
319{
320 if (cpu_is_omap34xx())
321 return clk_get_rate(clk_get_parent(dss.dpll4_m4_ck));
322 else
323 return 0;
324}
325
326int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
327 struct dss_clock_info *dss_cinfo,
328 struct dispc_clock_info *dispc_cinfo)
329{
330 unsigned long prate;
331 struct dss_clock_info best_dss;
332 struct dispc_clock_info best_dispc;
333
334 unsigned long fck;
335
336 u16 fck_div;
337
338 int match = 0;
339 int min_fck_per_pck;
340
341 prate = dss_get_dpll4_rate();
342
343 fck = dss_clk_get_rate(DSS_CLK_FCK1);
344 if (req_pck == dss.cache_req_pck &&
345 ((cpu_is_omap34xx() && prate == dss.cache_prate) ||
346 dss.cache_dss_cinfo.fck == fck)) {
347 DSSDBG("dispc clock info found from cache.\n");
348 *dss_cinfo = dss.cache_dss_cinfo;
349 *dispc_cinfo = dss.cache_dispc_cinfo;
350 return 0;
351 }
352
353 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
354
355 if (min_fck_per_pck &&
356 req_pck * min_fck_per_pck > DISPC_MAX_FCK) {
357 DSSERR("Requested pixel clock not possible with the current "
358 "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning "
359 "the constraint off.\n");
360 min_fck_per_pck = 0;
361 }
362
363retry:
364 memset(&best_dss, 0, sizeof(best_dss));
365 memset(&best_dispc, 0, sizeof(best_dispc));
366
367 if (cpu_is_omap24xx()) {
368 struct dispc_clock_info cur_dispc;
369 /* XXX can we change the clock on omap2? */
370 fck = dss_clk_get_rate(DSS_CLK_FCK1);
371 fck_div = 1;
372
373 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
374 match = 1;
375
376 best_dss.fck = fck;
377 best_dss.fck_div = fck_div;
378
379 best_dispc = cur_dispc;
380
381 goto found;
382 } else if (cpu_is_omap34xx()) {
383 for (fck_div = 16; fck_div > 0; --fck_div) {
384 struct dispc_clock_info cur_dispc;
385
386 fck = prate / fck_div * 2;
387
388 if (fck > DISPC_MAX_FCK)
389 continue;
390
391 if (min_fck_per_pck &&
392 fck < req_pck * min_fck_per_pck)
393 continue;
394
395 match = 1;
396
397 dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc);
398
399 if (abs(cur_dispc.pck - req_pck) <
400 abs(best_dispc.pck - req_pck)) {
401
402 best_dss.fck = fck;
403 best_dss.fck_div = fck_div;
404
405 best_dispc = cur_dispc;
406
407 if (cur_dispc.pck == req_pck)
408 goto found;
409 }
410 }
411 } else {
412 BUG();
413 }
414
415found:
416 if (!match) {
417 if (min_fck_per_pck) {
418 DSSERR("Could not find suitable clock settings.\n"
419 "Turning FCK/PCK constraint off and"
420 "trying again.\n");
421 min_fck_per_pck = 0;
422 goto retry;
423 }
424
425 DSSERR("Could not find suitable clock settings.\n");
426
427 return -EINVAL;
428 }
429
430 if (dss_cinfo)
431 *dss_cinfo = best_dss;
432 if (dispc_cinfo)
433 *dispc_cinfo = best_dispc;
434
435 dss.cache_req_pck = req_pck;
436 dss.cache_prate = prate;
437 dss.cache_dss_cinfo = best_dss;
438 dss.cache_dispc_cinfo = best_dispc;
439
440 return 0;
441}
442
443
444
445static irqreturn_t dss_irq_handler_omap2(int irq, void *arg)
446{
447 dispc_irq_handler();
448
449 return IRQ_HANDLED;
450}
451
452static irqreturn_t dss_irq_handler_omap3(int irq, void *arg)
453{
454 u32 irqstatus;
455
456 irqstatus = dss_read_reg(DSS_IRQSTATUS);
457
458 if (irqstatus & (1<<0)) /* DISPC_IRQ */
459 dispc_irq_handler();
460#ifdef CONFIG_OMAP2_DSS_DSI
461 if (irqstatus & (1<<1)) /* DSI_IRQ */
462 dsi_irq_handler();
463#endif
464
465 return IRQ_HANDLED;
466}
467
468static int _omap_dss_wait_reset(void)
469{
470 int t = 0;
471
472 while (REG_GET(DSS_SYSSTATUS, 0, 0) == 0) {
473 if (++t > 1000) {
474 DSSERR("soft reset failed\n");
475 return -ENODEV;
476 }
477 udelay(1);
478 }
479
480 return 0;
481}
482
483static int _omap_dss_reset(void)
484{
485 /* Soft reset */
486 REG_FLD_MOD(DSS_SYSCONFIG, 1, 1, 1);
487 return _omap_dss_wait_reset();
488}
489
490void dss_set_venc_output(enum omap_dss_venc_type type)
491{
492 int l = 0;
493
494 if (type == OMAP_DSS_VENC_TYPE_COMPOSITE)
495 l = 0;
496 else if (type == OMAP_DSS_VENC_TYPE_SVIDEO)
497 l = 1;
498 else
499 BUG();
500
501 /* venc out selection. 0 = comp, 1 = svideo */
502 REG_FLD_MOD(DSS_CONTROL, l, 6, 6);
503}
504
505void dss_set_dac_pwrdn_bgz(bool enable)
506{
507 REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */
508}
509
510int dss_init(bool skip_init)
511{
512 int r;
513 u32 rev;
514
515 dss.base = ioremap(DSS_BASE, DSS_SZ_REGS);
516 if (!dss.base) {
517 DSSERR("can't ioremap DSS\n");
518 r = -ENOMEM;
519 goto fail0;
520 }
521
522 if (!skip_init) {
523 /* disable LCD and DIGIT output. This seems to fix the synclost
524 * problem that we get, if the bootloader starts the DSS and
525 * the kernel resets it */
526 omap_writel(omap_readl(0x48050440) & ~0x3, 0x48050440);
527
528 /* We need to wait here a bit, otherwise we sometimes start to
529 * get synclost errors, and after that only power cycle will
530 * restore DSS functionality. I have no idea why this happens.
531 * And we have to wait _before_ resetting the DSS, but after
532 * enabling clocks.
533 */
534 msleep(50);
535
536 _omap_dss_reset();
537 }
538
539 /* autoidle */
540 REG_FLD_MOD(DSS_SYSCONFIG, 1, 0, 0);
541
542 /* Select DPLL */
543 REG_FLD_MOD(DSS_CONTROL, 0, 0, 0);
544
545#ifdef CONFIG_OMAP2_DSS_VENC
546 REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */
547 REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */
548 REG_FLD_MOD(DSS_CONTROL, 0, 2, 2); /* venc clock mode = normal */
549#endif
550
551 r = request_irq(INT_24XX_DSS_IRQ,
552 cpu_is_omap24xx()
553 ? dss_irq_handler_omap2
554 : dss_irq_handler_omap3,
555 0, "OMAP DSS", NULL);
556
557 if (r < 0) {
558 DSSERR("omap2 dss: request_irq failed\n");
559 goto fail1;
560 }
561
562 if (cpu_is_omap34xx()) {
563 dss.dpll4_m4_ck = clk_get(NULL, "dpll4_m4_ck");
564 if (IS_ERR(dss.dpll4_m4_ck)) {
565 DSSERR("Failed to get dpll4_m4_ck\n");
566 r = PTR_ERR(dss.dpll4_m4_ck);
567 goto fail2;
568 }
569 }
570
571 dss_save_context();
572
573 rev = dss_read_reg(DSS_REVISION);
574 printk(KERN_INFO "OMAP DSS rev %d.%d\n",
575 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
576
577 return 0;
578
579fail2:
580 free_irq(INT_24XX_DSS_IRQ, NULL);
581fail1:
582 iounmap(dss.base);
583fail0:
584 return r;
585}
586
587void dss_exit(void)
588{
589 if (cpu_is_omap34xx())
590 clk_put(dss.dpll4_m4_ck);
591
592 free_irq(INT_24XX_DSS_IRQ, NULL);
593
594 iounmap(dss.base);
595}
596
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h
new file mode 100644
index 000000000000..2bcb1245d6c2
--- /dev/null
+++ b/drivers/video/omap2/dss/dss.h
@@ -0,0 +1,384 @@
1/*
2 * linux/drivers/video/omap2/dss/dss.h
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#ifndef __OMAP2_DSS_H
24#define __OMAP2_DSS_H
25
26#ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT
27#define DEBUG
28#endif
29
30#ifdef DEBUG
31extern unsigned int dss_debug;
32#ifdef DSS_SUBSYS_NAME
33#define DSSDBG(format, ...) \
34 if (dss_debug) \
35 printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \
36 ## __VA_ARGS__)
37#else
38#define DSSDBG(format, ...) \
39 if (dss_debug) \
40 printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__)
41#endif
42
43#ifdef DSS_SUBSYS_NAME
44#define DSSDBGF(format, ...) \
45 if (dss_debug) \
46 printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \
47 ": %s(" format ")\n", \
48 __func__, \
49 ## __VA_ARGS__)
50#else
51#define DSSDBGF(format, ...) \
52 if (dss_debug) \
53 printk(KERN_DEBUG "omapdss: " \
54 ": %s(" format ")\n", \
55 __func__, \
56 ## __VA_ARGS__)
57#endif
58
59#else /* DEBUG */
60#define DSSDBG(format, ...)
61#define DSSDBGF(format, ...)
62#endif
63
64
65#ifdef DSS_SUBSYS_NAME
66#define DSSERR(format, ...) \
67 printk(KERN_ERR "omapdss " DSS_SUBSYS_NAME " error: " format, \
68 ## __VA_ARGS__)
69#else
70#define DSSERR(format, ...) \
71 printk(KERN_ERR "omapdss error: " format, ## __VA_ARGS__)
72#endif
73
74#ifdef DSS_SUBSYS_NAME
75#define DSSINFO(format, ...) \
76 printk(KERN_INFO "omapdss " DSS_SUBSYS_NAME ": " format, \
77 ## __VA_ARGS__)
78#else
79#define DSSINFO(format, ...) \
80 printk(KERN_INFO "omapdss: " format, ## __VA_ARGS__)
81#endif
82
83#ifdef DSS_SUBSYS_NAME
84#define DSSWARN(format, ...) \
85 printk(KERN_WARNING "omapdss " DSS_SUBSYS_NAME ": " format, \
86 ## __VA_ARGS__)
87#else
88#define DSSWARN(format, ...) \
89 printk(KERN_WARNING "omapdss: " format, ## __VA_ARGS__)
90#endif
91
92/* OMAP TRM gives bitfields as start:end, where start is the higher bit
93 number. For example 7:0 */
94#define FLD_MASK(start, end) (((1 << ((start) - (end) + 1)) - 1) << (end))
95#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))
96#define FLD_GET(val, start, end) (((val) & FLD_MASK(start, end)) >> (end))
97#define FLD_MOD(orig, val, start, end) \
98 (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end))
99
100#define DISPC_MAX_FCK 173000000
101
102enum omap_burst_size {
103 OMAP_DSS_BURST_4x32 = 0,
104 OMAP_DSS_BURST_8x32 = 1,
105 OMAP_DSS_BURST_16x32 = 2,
106};
107
108enum omap_parallel_interface_mode {
109 OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */
110 OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */
111 OMAP_DSS_PARALLELMODE_DSI,
112};
113
114enum dss_clock {
115 DSS_CLK_ICK = 1 << 0,
116 DSS_CLK_FCK1 = 1 << 1,
117 DSS_CLK_FCK2 = 1 << 2,
118 DSS_CLK_54M = 1 << 3,
119 DSS_CLK_96M = 1 << 4,
120};
121
122struct dss_clock_info {
123 /* rates that we get with dividers below */
124 unsigned long fck;
125
126 /* dividers */
127 u16 fck_div;
128};
129
130struct dispc_clock_info {
131 /* rates that we get with dividers below */
132 unsigned long lck;
133 unsigned long pck;
134
135 /* dividers */
136 u16 lck_div;
137 u16 pck_div;
138};
139
140struct dsi_clock_info {
141 /* rates that we get with dividers below */
142 unsigned long fint;
143 unsigned long clkin4ddr;
144 unsigned long clkin;
145 unsigned long dsi1_pll_fclk;
146 unsigned long dsi2_pll_fclk;
147
148 unsigned long lp_clk;
149
150 /* dividers */
151 u16 regn;
152 u16 regm;
153 u16 regm3;
154 u16 regm4;
155
156 u16 lp_clk_div;
157
158 u8 highfreq;
159 bool use_dss2_fck;
160};
161
162struct seq_file;
163struct platform_device;
164
165/* core */
166void dss_clk_enable(enum dss_clock clks);
167void dss_clk_disable(enum dss_clock clks);
168unsigned long dss_clk_get_rate(enum dss_clock clk);
169int dss_need_ctx_restore(void);
170void dss_dump_clocks(struct seq_file *s);
171struct bus_type *dss_get_bus(void);
172
173/* display */
174int dss_suspend_all_devices(void);
175int dss_resume_all_devices(void);
176void dss_disable_all_devices(void);
177
178void dss_init_device(struct platform_device *pdev,
179 struct omap_dss_device *dssdev);
180void dss_uninit_device(struct platform_device *pdev,
181 struct omap_dss_device *dssdev);
182bool dss_use_replication(struct omap_dss_device *dssdev,
183 enum omap_color_mode mode);
184void default_get_overlay_fifo_thresholds(enum omap_plane plane,
185 u32 fifo_size, enum omap_burst_size *burst_size,
186 u32 *fifo_low, u32 *fifo_high);
187
188/* manager */
189int dss_init_overlay_managers(struct platform_device *pdev);
190void dss_uninit_overlay_managers(struct platform_device *pdev);
191int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl);
192void dss_setup_partial_planes(struct omap_dss_device *dssdev,
193 u16 *x, u16 *y, u16 *w, u16 *h);
194void dss_start_update(struct omap_dss_device *dssdev);
195
196/* overlay */
197void dss_init_overlays(struct platform_device *pdev);
198void dss_uninit_overlays(struct platform_device *pdev);
199int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev);
200void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr);
201#ifdef L4_EXAMPLE
202void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr);
203#endif
204void dss_recheck_connections(struct omap_dss_device *dssdev, bool force);
205
206/* DSS */
207int dss_init(bool skip_init);
208void dss_exit(void);
209
210void dss_save_context(void);
211void dss_restore_context(void);
212
213void dss_dump_regs(struct seq_file *s);
214
215void dss_sdi_init(u8 datapairs);
216int dss_sdi_enable(void);
217void dss_sdi_disable(void);
218
219void dss_select_clk_source(bool dsi, bool dispc);
220int dss_get_dsi_clk_source(void);
221int dss_get_dispc_clk_source(void);
222void dss_set_venc_output(enum omap_dss_venc_type type);
223void dss_set_dac_pwrdn_bgz(bool enable);
224
225unsigned long dss_get_dpll4_rate(void);
226int dss_calc_clock_rates(struct dss_clock_info *cinfo);
227int dss_set_clock_div(struct dss_clock_info *cinfo);
228int dss_get_clock_div(struct dss_clock_info *cinfo);
229int dss_calc_clock_div(bool is_tft, unsigned long req_pck,
230 struct dss_clock_info *dss_cinfo,
231 struct dispc_clock_info *dispc_cinfo);
232
233/* SDI */
234int sdi_init(bool skip_init);
235void sdi_exit(void);
236int sdi_init_display(struct omap_dss_device *display);
237
238/* DSI */
239int dsi_init(struct platform_device *pdev);
240void dsi_exit(void);
241
242void dsi_dump_clocks(struct seq_file *s);
243void dsi_dump_irqs(struct seq_file *s);
244void dsi_dump_regs(struct seq_file *s);
245
246void dsi_save_context(void);
247void dsi_restore_context(void);
248
249int dsi_init_display(struct omap_dss_device *display);
250void dsi_irq_handler(void);
251unsigned long dsi_get_dsi1_pll_rate(void);
252int dsi_pll_set_clock_div(struct dsi_clock_info *cinfo);
253int dsi_pll_calc_clock_div_pck(bool is_tft, unsigned long req_pck,
254 struct dsi_clock_info *cinfo,
255 struct dispc_clock_info *dispc_cinfo);
256int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk,
257 bool enable_hsdiv);
258void dsi_pll_uninit(void);
259void dsi_get_overlay_fifo_thresholds(enum omap_plane plane,
260 u32 fifo_size, enum omap_burst_size *burst_size,
261 u32 *fifo_low, u32 *fifo_high);
262
263/* DPI */
264int dpi_init(void);
265void dpi_exit(void);
266int dpi_init_display(struct omap_dss_device *dssdev);
267
268/* DISPC */
269int dispc_init(void);
270void dispc_exit(void);
271void dispc_dump_clocks(struct seq_file *s);
272void dispc_dump_irqs(struct seq_file *s);
273void dispc_dump_regs(struct seq_file *s);
274void dispc_irq_handler(void);
275void dispc_fake_vsync_irq(void);
276
277void dispc_save_context(void);
278void dispc_restore_context(void);
279
280void dispc_enable_sidle(void);
281void dispc_disable_sidle(void);
282
283void dispc_lcd_enable_signal_polarity(bool act_high);
284void dispc_lcd_enable_signal(bool enable);
285void dispc_pck_free_enable(bool enable);
286void dispc_enable_fifohandcheck(bool enable);
287
288void dispc_set_lcd_size(u16 width, u16 height);
289void dispc_set_digit_size(u16 width, u16 height);
290u32 dispc_get_plane_fifo_size(enum omap_plane plane);
291void dispc_setup_plane_fifo(enum omap_plane plane, u32 low, u32 high);
292void dispc_enable_fifomerge(bool enable);
293void dispc_set_burst_size(enum omap_plane plane,
294 enum omap_burst_size burst_size);
295
296void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr);
297void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr);
298void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y);
299void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height);
300void dispc_set_channel_out(enum omap_plane plane,
301 enum omap_channel channel_out);
302
303int dispc_setup_plane(enum omap_plane plane,
304 u32 paddr, u16 screen_width,
305 u16 pos_x, u16 pos_y,
306 u16 width, u16 height,
307 u16 out_width, u16 out_height,
308 enum omap_color_mode color_mode,
309 bool ilace,
310 enum omap_dss_rotation_type rotation_type,
311 u8 rotation, bool mirror,
312 u8 global_alpha);
313
314bool dispc_go_busy(enum omap_channel channel);
315void dispc_go(enum omap_channel channel);
316void dispc_enable_lcd_out(bool enable);
317void dispc_enable_digit_out(bool enable);
318int dispc_enable_plane(enum omap_plane plane, bool enable);
319void dispc_enable_replication(enum omap_plane plane, bool enable);
320
321void dispc_set_parallel_interface_mode(enum omap_parallel_interface_mode mode);
322void dispc_set_tft_data_lines(u8 data_lines);
323void dispc_set_lcd_display_type(enum omap_lcd_display_type type);
324void dispc_set_loadmode(enum omap_dss_load_mode mode);
325
326void dispc_set_default_color(enum omap_channel channel, u32 color);
327u32 dispc_get_default_color(enum omap_channel channel);
328void dispc_set_trans_key(enum omap_channel ch,
329 enum omap_dss_trans_key_type type,
330 u32 trans_key);
331void dispc_get_trans_key(enum omap_channel ch,
332 enum omap_dss_trans_key_type *type,
333 u32 *trans_key);
334void dispc_enable_trans_key(enum omap_channel ch, bool enable);
335void dispc_enable_alpha_blending(enum omap_channel ch, bool enable);
336bool dispc_trans_key_enabled(enum omap_channel ch);
337bool dispc_alpha_blending_enabled(enum omap_channel ch);
338
339bool dispc_lcd_timings_ok(struct omap_video_timings *timings);
340void dispc_set_lcd_timings(struct omap_video_timings *timings);
341unsigned long dispc_fclk_rate(void);
342unsigned long dispc_lclk_rate(void);
343unsigned long dispc_pclk_rate(void);
344void dispc_set_pol_freq(enum omap_panel_config config, u8 acbi, u8 acb);
345void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck,
346 struct dispc_clock_info *cinfo);
347int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
348 struct dispc_clock_info *cinfo);
349int dispc_set_clock_div(struct dispc_clock_info *cinfo);
350int dispc_get_clock_div(struct dispc_clock_info *cinfo);
351
352
353/* VENC */
354int venc_init(struct platform_device *pdev);
355void venc_exit(void);
356void venc_dump_regs(struct seq_file *s);
357int venc_init_display(struct omap_dss_device *display);
358
359/* RFBI */
360int rfbi_init(void);
361void rfbi_exit(void);
362void rfbi_dump_regs(struct seq_file *s);
363
364int rfbi_configure(int rfbi_module, int bpp, int lines);
365void rfbi_enable_rfbi(bool enable);
366void rfbi_transfer_area(u16 width, u16 height,
367 void (callback)(void *data), void *data);
368void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t);
369unsigned long rfbi_get_max_tx_rate(void);
370int rfbi_init_display(struct omap_dss_device *display);
371
372
373#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
374static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
375{
376 int b;
377 for (b = 0; b < 32; ++b) {
378 if (irqstatus & (1 << b))
379 irq_arr[b]++;
380 }
381}
382#endif
383
384#endif
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
new file mode 100644
index 000000000000..27d9c465c851
--- /dev/null
+++ b/drivers/video/omap2/dss/manager.c
@@ -0,0 +1,1487 @@
1/*
2 * linux/drivers/video/omap2/dss/manager.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "MANAGER"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/platform_device.h>
28#include <linux/spinlock.h>
29#include <linux/jiffies.h>
30
31#include <plat/display.h>
32#include <plat/cpu.h>
33
34#include "dss.h"
35
36static int num_managers;
37static struct list_head manager_list;
38
39static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf)
40{
41 return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name);
42}
43
44static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf)
45{
46 return snprintf(buf, PAGE_SIZE, "%s\n",
47 mgr->device ? mgr->device->name : "<none>");
48}
49
50static ssize_t manager_display_store(struct omap_overlay_manager *mgr,
51 const char *buf, size_t size)
52{
53 int r = 0;
54 size_t len = size;
55 struct omap_dss_device *dssdev = NULL;
56
57 int match(struct omap_dss_device *dssdev, void *data)
58 {
59 const char *str = data;
60 return sysfs_streq(dssdev->name, str);
61 }
62
63 if (buf[size-1] == '\n')
64 --len;
65
66 if (len > 0)
67 dssdev = omap_dss_find_device((void *)buf, match);
68
69 if (len > 0 && dssdev == NULL)
70 return -EINVAL;
71
72 if (dssdev)
73 DSSDBG("display %s found\n", dssdev->name);
74
75 if (mgr->device) {
76 r = mgr->unset_device(mgr);
77 if (r) {
78 DSSERR("failed to unset display\n");
79 goto put_device;
80 }
81 }
82
83 if (dssdev) {
84 r = mgr->set_device(mgr, dssdev);
85 if (r) {
86 DSSERR("failed to set manager\n");
87 goto put_device;
88 }
89
90 r = mgr->apply(mgr);
91 if (r) {
92 DSSERR("failed to apply dispc config\n");
93 goto put_device;
94 }
95 }
96
97put_device:
98 if (dssdev)
99 omap_dss_put_device(dssdev);
100
101 return r ? r : size;
102}
103
104static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr,
105 char *buf)
106{
107 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.default_color);
108}
109
110static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr,
111 const char *buf, size_t size)
112{
113 struct omap_overlay_manager_info info;
114 u32 color;
115 int r;
116
117 if (sscanf(buf, "%d", &color) != 1)
118 return -EINVAL;
119
120 mgr->get_manager_info(mgr, &info);
121
122 info.default_color = color;
123
124 r = mgr->set_manager_info(mgr, &info);
125 if (r)
126 return r;
127
128 r = mgr->apply(mgr);
129 if (r)
130 return r;
131
132 return size;
133}
134
135static const char *trans_key_type_str[] = {
136 "gfx-destination",
137 "video-source",
138};
139
140static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr,
141 char *buf)
142{
143 enum omap_dss_trans_key_type key_type;
144
145 key_type = mgr->info.trans_key_type;
146 BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str));
147
148 return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]);
149}
150
151static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr,
152 const char *buf, size_t size)
153{
154 enum omap_dss_trans_key_type key_type;
155 struct omap_overlay_manager_info info;
156 int r;
157
158 for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
159 key_type < ARRAY_SIZE(trans_key_type_str); key_type++) {
160 if (sysfs_streq(buf, trans_key_type_str[key_type]))
161 break;
162 }
163
164 if (key_type == ARRAY_SIZE(trans_key_type_str))
165 return -EINVAL;
166
167 mgr->get_manager_info(mgr, &info);
168
169 info.trans_key_type = key_type;
170
171 r = mgr->set_manager_info(mgr, &info);
172 if (r)
173 return r;
174
175 r = mgr->apply(mgr);
176 if (r)
177 return r;
178
179 return size;
180}
181
182static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr,
183 char *buf)
184{
185 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_key);
186}
187
188static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr,
189 const char *buf, size_t size)
190{
191 struct omap_overlay_manager_info info;
192 u32 key_value;
193 int r;
194
195 if (sscanf(buf, "%d", &key_value) != 1)
196 return -EINVAL;
197
198 mgr->get_manager_info(mgr, &info);
199
200 info.trans_key = key_value;
201
202 r = mgr->set_manager_info(mgr, &info);
203 if (r)
204 return r;
205
206 r = mgr->apply(mgr);
207 if (r)
208 return r;
209
210 return size;
211}
212
213static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr,
214 char *buf)
215{
216 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled);
217}
218
219static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr,
220 const char *buf, size_t size)
221{
222 struct omap_overlay_manager_info info;
223 int enable;
224 int r;
225
226 if (sscanf(buf, "%d", &enable) != 1)
227 return -EINVAL;
228
229 mgr->get_manager_info(mgr, &info);
230
231 info.trans_enabled = enable ? true : false;
232
233 r = mgr->set_manager_info(mgr, &info);
234 if (r)
235 return r;
236
237 r = mgr->apply(mgr);
238 if (r)
239 return r;
240
241 return size;
242}
243
244static ssize_t manager_alpha_blending_enabled_show(
245 struct omap_overlay_manager *mgr, char *buf)
246{
247 return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.alpha_enabled);
248}
249
250static ssize_t manager_alpha_blending_enabled_store(
251 struct omap_overlay_manager *mgr,
252 const char *buf, size_t size)
253{
254 struct omap_overlay_manager_info info;
255 int enable;
256 int r;
257
258 if (sscanf(buf, "%d", &enable) != 1)
259 return -EINVAL;
260
261 mgr->get_manager_info(mgr, &info);
262
263 info.alpha_enabled = enable ? true : false;
264
265 r = mgr->set_manager_info(mgr, &info);
266 if (r)
267 return r;
268
269 r = mgr->apply(mgr);
270 if (r)
271 return r;
272
273 return size;
274}
275
276struct manager_attribute {
277 struct attribute attr;
278 ssize_t (*show)(struct omap_overlay_manager *, char *);
279 ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t);
280};
281
282#define MANAGER_ATTR(_name, _mode, _show, _store) \
283 struct manager_attribute manager_attr_##_name = \
284 __ATTR(_name, _mode, _show, _store)
285
286static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL);
287static MANAGER_ATTR(display, S_IRUGO|S_IWUSR,
288 manager_display_show, manager_display_store);
289static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR,
290 manager_default_color_show, manager_default_color_store);
291static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR,
292 manager_trans_key_type_show, manager_trans_key_type_store);
293static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR,
294 manager_trans_key_value_show, manager_trans_key_value_store);
295static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR,
296 manager_trans_key_enabled_show,
297 manager_trans_key_enabled_store);
298static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR,
299 manager_alpha_blending_enabled_show,
300 manager_alpha_blending_enabled_store);
301
302
303static struct attribute *manager_sysfs_attrs[] = {
304 &manager_attr_name.attr,
305 &manager_attr_display.attr,
306 &manager_attr_default_color.attr,
307 &manager_attr_trans_key_type.attr,
308 &manager_attr_trans_key_value.attr,
309 &manager_attr_trans_key_enabled.attr,
310 &manager_attr_alpha_blending_enabled.attr,
311 NULL
312};
313
314static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr,
315 char *buf)
316{
317 struct omap_overlay_manager *manager;
318 struct manager_attribute *manager_attr;
319
320 manager = container_of(kobj, struct omap_overlay_manager, kobj);
321 manager_attr = container_of(attr, struct manager_attribute, attr);
322
323 if (!manager_attr->show)
324 return -ENOENT;
325
326 return manager_attr->show(manager, buf);
327}
328
329static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr,
330 const char *buf, size_t size)
331{
332 struct omap_overlay_manager *manager;
333 struct manager_attribute *manager_attr;
334
335 manager = container_of(kobj, struct omap_overlay_manager, kobj);
336 manager_attr = container_of(attr, struct manager_attribute, attr);
337
338 if (!manager_attr->store)
339 return -ENOENT;
340
341 return manager_attr->store(manager, buf, size);
342}
343
344static struct sysfs_ops manager_sysfs_ops = {
345 .show = manager_attr_show,
346 .store = manager_attr_store,
347};
348
349static struct kobj_type manager_ktype = {
350 .sysfs_ops = &manager_sysfs_ops,
351 .default_attrs = manager_sysfs_attrs,
352};
353
354/*
355 * We have 4 levels of cache for the dispc settings. First two are in SW and
356 * the latter two in HW.
357 *
358 * +--------------------+
359 * |overlay/manager_info|
360 * +--------------------+
361 * v
362 * apply()
363 * v
364 * +--------------------+
365 * | dss_cache |
366 * +--------------------+
367 * v
368 * configure()
369 * v
370 * +--------------------+
371 * | shadow registers |
372 * +--------------------+
373 * v
374 * VFP or lcd/digit_enable
375 * v
376 * +--------------------+
377 * | registers |
378 * +--------------------+
379 */
380
381struct overlay_cache_data {
382 /* If true, cache changed, but not written to shadow registers. Set
383 * in apply(), cleared when registers written. */
384 bool dirty;
385 /* If true, shadow registers contain changed values not yet in real
386 * registers. Set when writing to shadow registers, cleared at
387 * VSYNC/EVSYNC */
388 bool shadow_dirty;
389
390 bool enabled;
391
392 u32 paddr;
393 void __iomem *vaddr;
394 u16 screen_width;
395 u16 width;
396 u16 height;
397 enum omap_color_mode color_mode;
398 u8 rotation;
399 enum omap_dss_rotation_type rotation_type;
400 bool mirror;
401
402 u16 pos_x;
403 u16 pos_y;
404 u16 out_width; /* if 0, out_width == width */
405 u16 out_height; /* if 0, out_height == height */
406 u8 global_alpha;
407
408 enum omap_channel channel;
409 bool replication;
410 bool ilace;
411
412 enum omap_burst_size burst_size;
413 u32 fifo_low;
414 u32 fifo_high;
415
416 bool manual_update;
417};
418
419struct manager_cache_data {
420 /* If true, cache changed, but not written to shadow registers. Set
421 * in apply(), cleared when registers written. */
422 bool dirty;
423 /* If true, shadow registers contain changed values not yet in real
424 * registers. Set when writing to shadow registers, cleared at
425 * VSYNC/EVSYNC */
426 bool shadow_dirty;
427
428 u32 default_color;
429
430 enum omap_dss_trans_key_type trans_key_type;
431 u32 trans_key;
432 bool trans_enabled;
433
434 bool alpha_enabled;
435
436 bool manual_upd_display;
437 bool manual_update;
438 bool do_manual_update;
439
440 /* manual update region */
441 u16 x, y, w, h;
442};
443
444static struct {
445 spinlock_t lock;
446 struct overlay_cache_data overlay_cache[3];
447 struct manager_cache_data manager_cache[2];
448
449 bool irq_enabled;
450} dss_cache;
451
452
453
454static int omap_dss_set_device(struct omap_overlay_manager *mgr,
455 struct omap_dss_device *dssdev)
456{
457 int i;
458 int r;
459
460 if (dssdev->manager) {
461 DSSERR("display '%s' already has a manager '%s'\n",
462 dssdev->name, dssdev->manager->name);
463 return -EINVAL;
464 }
465
466 if ((mgr->supported_displays & dssdev->type) == 0) {
467 DSSERR("display '%s' does not support manager '%s'\n",
468 dssdev->name, mgr->name);
469 return -EINVAL;
470 }
471
472 for (i = 0; i < mgr->num_overlays; i++) {
473 struct omap_overlay *ovl = mgr->overlays[i];
474
475 if (ovl->manager != mgr || !ovl->info.enabled)
476 continue;
477
478 r = dss_check_overlay(ovl, dssdev);
479 if (r)
480 return r;
481 }
482
483 dssdev->manager = mgr;
484 mgr->device = dssdev;
485 mgr->device_changed = true;
486
487 return 0;
488}
489
490static int omap_dss_unset_device(struct omap_overlay_manager *mgr)
491{
492 if (!mgr->device) {
493 DSSERR("failed to unset display, display not set.\n");
494 return -EINVAL;
495 }
496
497 mgr->device->manager = NULL;
498 mgr->device = NULL;
499 mgr->device_changed = true;
500
501 return 0;
502}
503
504static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr)
505{
506 unsigned long timeout = msecs_to_jiffies(500);
507 struct manager_cache_data *mc;
508 enum omap_channel channel;
509 u32 irq;
510 int r;
511 int i;
512
513 if (!mgr->device)
514 return 0;
515
516 if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) {
517 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
518 channel = OMAP_DSS_CHANNEL_DIGIT;
519 } else {
520 if (mgr->device->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
521 enum omap_dss_update_mode mode;
522 mode = mgr->device->get_update_mode(mgr->device);
523 if (mode != OMAP_DSS_UPDATE_AUTO)
524 return 0;
525
526 irq = DISPC_IRQ_FRAMEDONE;
527 } else {
528 irq = DISPC_IRQ_VSYNC;
529 }
530 channel = OMAP_DSS_CHANNEL_LCD;
531 }
532
533 mc = &dss_cache.manager_cache[mgr->id];
534 i = 0;
535 while (1) {
536 unsigned long flags;
537 bool shadow_dirty, dirty;
538
539 spin_lock_irqsave(&dss_cache.lock, flags);
540 dirty = mc->dirty;
541 shadow_dirty = mc->shadow_dirty;
542 spin_unlock_irqrestore(&dss_cache.lock, flags);
543
544 if (!dirty && !shadow_dirty) {
545 r = 0;
546 break;
547 }
548
549 /* 4 iterations is the worst case:
550 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
551 * 2 - first VSYNC, dirty = true
552 * 3 - dirty = false, shadow_dirty = true
553 * 4 - shadow_dirty = false */
554 if (i++ == 3) {
555 DSSERR("mgr(%d)->wait_for_go() not finishing\n",
556 mgr->id);
557 r = 0;
558 break;
559 }
560
561 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
562 if (r == -ERESTARTSYS)
563 break;
564
565 if (r) {
566 DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id);
567 break;
568 }
569 }
570
571 return r;
572}
573
574int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl)
575{
576 unsigned long timeout = msecs_to_jiffies(500);
577 enum omap_channel channel;
578 struct overlay_cache_data *oc;
579 struct omap_dss_device *dssdev;
580 u32 irq;
581 int r;
582 int i;
583
584 if (!ovl->manager || !ovl->manager->device)
585 return 0;
586
587 dssdev = ovl->manager->device;
588
589 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
590 irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN;
591 channel = OMAP_DSS_CHANNEL_DIGIT;
592 } else {
593 if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
594 enum omap_dss_update_mode mode;
595 mode = dssdev->get_update_mode(dssdev);
596 if (mode != OMAP_DSS_UPDATE_AUTO)
597 return 0;
598
599 irq = DISPC_IRQ_FRAMEDONE;
600 } else {
601 irq = DISPC_IRQ_VSYNC;
602 }
603 channel = OMAP_DSS_CHANNEL_LCD;
604 }
605
606 oc = &dss_cache.overlay_cache[ovl->id];
607 i = 0;
608 while (1) {
609 unsigned long flags;
610 bool shadow_dirty, dirty;
611
612 spin_lock_irqsave(&dss_cache.lock, flags);
613 dirty = oc->dirty;
614 shadow_dirty = oc->shadow_dirty;
615 spin_unlock_irqrestore(&dss_cache.lock, flags);
616
617 if (!dirty && !shadow_dirty) {
618 r = 0;
619 break;
620 }
621
622 /* 4 iterations is the worst case:
623 * 1 - initial iteration, dirty = true (between VFP and VSYNC)
624 * 2 - first VSYNC, dirty = true
625 * 3 - dirty = false, shadow_dirty = true
626 * 4 - shadow_dirty = false */
627 if (i++ == 3) {
628 DSSERR("ovl(%d)->wait_for_go() not finishing\n",
629 ovl->id);
630 r = 0;
631 break;
632 }
633
634 r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout);
635 if (r == -ERESTARTSYS)
636 break;
637
638 if (r) {
639 DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id);
640 break;
641 }
642 }
643
644 return r;
645}
646
647static int overlay_enabled(struct omap_overlay *ovl)
648{
649 return ovl->info.enabled && ovl->manager && ovl->manager->device;
650}
651
652/* Is rect1 a subset of rect2? */
653static bool rectangle_subset(int x1, int y1, int w1, int h1,
654 int x2, int y2, int w2, int h2)
655{
656 if (x1 < x2 || y1 < y2)
657 return false;
658
659 if (x1 + w1 > x2 + w2)
660 return false;
661
662 if (y1 + h1 > y2 + h2)
663 return false;
664
665 return true;
666}
667
668/* Do rect1 and rect2 overlap? */
669static bool rectangle_intersects(int x1, int y1, int w1, int h1,
670 int x2, int y2, int w2, int h2)
671{
672 if (x1 >= x2 + w2)
673 return false;
674
675 if (x2 >= x1 + w1)
676 return false;
677
678 if (y1 >= y2 + h2)
679 return false;
680
681 if (y2 >= y1 + h1)
682 return false;
683
684 return true;
685}
686
687static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
688{
689 if (oc->out_width != 0 && oc->width != oc->out_width)
690 return true;
691
692 if (oc->out_height != 0 && oc->height != oc->out_height)
693 return true;
694
695 return false;
696}
697
698static int configure_overlay(enum omap_plane plane)
699{
700 struct overlay_cache_data *c;
701 struct manager_cache_data *mc;
702 u16 outw, outh;
703 u16 x, y, w, h;
704 u32 paddr;
705 int r;
706
707 DSSDBGF("%d", plane);
708
709 c = &dss_cache.overlay_cache[plane];
710
711 if (!c->enabled) {
712 dispc_enable_plane(plane, 0);
713 return 0;
714 }
715
716 mc = &dss_cache.manager_cache[c->channel];
717
718 x = c->pos_x;
719 y = c->pos_y;
720 w = c->width;
721 h = c->height;
722 outw = c->out_width == 0 ? c->width : c->out_width;
723 outh = c->out_height == 0 ? c->height : c->out_height;
724 paddr = c->paddr;
725
726 if (c->manual_update && mc->do_manual_update) {
727 unsigned bpp;
728 /* If the overlay is outside the update region, disable it */
729 if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
730 x, y, outw, outh)) {
731 dispc_enable_plane(plane, 0);
732 return 0;
733 }
734
735 switch (c->color_mode) {
736 case OMAP_DSS_COLOR_RGB16:
737 case OMAP_DSS_COLOR_ARGB16:
738 case OMAP_DSS_COLOR_YUV2:
739 case OMAP_DSS_COLOR_UYVY:
740 bpp = 16;
741 break;
742
743 case OMAP_DSS_COLOR_RGB24P:
744 bpp = 24;
745 break;
746
747 case OMAP_DSS_COLOR_RGB24U:
748 case OMAP_DSS_COLOR_ARGB32:
749 case OMAP_DSS_COLOR_RGBA32:
750 case OMAP_DSS_COLOR_RGBX32:
751 bpp = 32;
752 break;
753
754 default:
755 BUG();
756 }
757
758 if (dispc_is_overlay_scaled(c)) {
759 /* If the overlay is scaled, the update area has
760 * already been enlarged to cover the whole overlay. We
761 * only need to adjust x/y here */
762 x = c->pos_x - mc->x;
763 y = c->pos_y - mc->y;
764 } else {
765 if (mc->x > c->pos_x) {
766 x = 0;
767 w -= (mc->x - c->pos_x);
768 paddr += (mc->x - c->pos_x) * bpp / 8;
769 } else {
770 x = c->pos_x - mc->x;
771 }
772
773 if (mc->y > c->pos_y) {
774 y = 0;
775 h -= (mc->y - c->pos_y);
776 paddr += (mc->y - c->pos_y) * c->screen_width *
777 bpp / 8;
778 } else {
779 y = c->pos_y - mc->y;
780 }
781
782 if (mc->w < (x+w))
783 w -= (x+w) - (mc->w);
784
785 if (mc->h < (y+h))
786 h -= (y+h) - (mc->h);
787
788 outw = w;
789 outh = h;
790 }
791 }
792
793 r = dispc_setup_plane(plane,
794 paddr,
795 c->screen_width,
796 x, y,
797 w, h,
798 outw, outh,
799 c->color_mode,
800 c->ilace,
801 c->rotation_type,
802 c->rotation,
803 c->mirror,
804 c->global_alpha);
805
806 if (r) {
807 /* this shouldn't happen */
808 DSSERR("dispc_setup_plane failed for ovl %d\n", plane);
809 dispc_enable_plane(plane, 0);
810 return r;
811 }
812
813 dispc_enable_replication(plane, c->replication);
814
815 dispc_set_burst_size(plane, c->burst_size);
816 dispc_setup_plane_fifo(plane, c->fifo_low, c->fifo_high);
817
818 dispc_enable_plane(plane, 1);
819
820 return 0;
821}
822
823static void configure_manager(enum omap_channel channel)
824{
825 struct manager_cache_data *c;
826
827 DSSDBGF("%d", channel);
828
829 c = &dss_cache.manager_cache[channel];
830
831 dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
832 dispc_enable_trans_key(channel, c->trans_enabled);
833 dispc_enable_alpha_blending(channel, c->alpha_enabled);
834}
835
836/* configure_dispc() tries to write values from cache to shadow registers.
837 * It writes only to those managers/overlays that are not busy.
838 * returns 0 if everything could be written to shadow registers.
839 * returns 1 if not everything could be written to shadow registers. */
840static int configure_dispc(void)
841{
842 struct overlay_cache_data *oc;
843 struct manager_cache_data *mc;
844 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
845 const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
846 int i;
847 int r;
848 bool mgr_busy[2];
849 bool mgr_go[2];
850 bool busy;
851
852 r = 0;
853 busy = false;
854
855 mgr_busy[0] = dispc_go_busy(0);
856 mgr_busy[1] = dispc_go_busy(1);
857 mgr_go[0] = false;
858 mgr_go[1] = false;
859
860 /* Commit overlay settings */
861 for (i = 0; i < num_ovls; ++i) {
862 oc = &dss_cache.overlay_cache[i];
863 mc = &dss_cache.manager_cache[oc->channel];
864
865 if (!oc->dirty)
866 continue;
867
868 if (oc->manual_update && !mc->do_manual_update)
869 continue;
870
871 if (mgr_busy[oc->channel]) {
872 busy = true;
873 continue;
874 }
875
876 r = configure_overlay(i);
877 if (r)
878 DSSERR("configure_overlay %d failed\n", i);
879
880 oc->dirty = false;
881 oc->shadow_dirty = true;
882 mgr_go[oc->channel] = true;
883 }
884
885 /* Commit manager settings */
886 for (i = 0; i < num_mgrs; ++i) {
887 mc = &dss_cache.manager_cache[i];
888
889 if (!mc->dirty)
890 continue;
891
892 if (mc->manual_update && !mc->do_manual_update)
893 continue;
894
895 if (mgr_busy[i]) {
896 busy = true;
897 continue;
898 }
899
900 configure_manager(i);
901 mc->dirty = false;
902 mc->shadow_dirty = true;
903 mgr_go[i] = true;
904 }
905
906 /* set GO */
907 for (i = 0; i < num_mgrs; ++i) {
908 mc = &dss_cache.manager_cache[i];
909
910 if (!mgr_go[i])
911 continue;
912
913 /* We don't need GO with manual update display. LCD iface will
914 * always be turned off after frame, and new settings will be
915 * taken in to use at next update */
916 if (!mc->manual_upd_display)
917 dispc_go(i);
918 }
919
920 if (busy)
921 r = 1;
922 else
923 r = 0;
924
925 return r;
926}
927
928/* Configure dispc for partial update. Return possibly modified update
929 * area */
930void dss_setup_partial_planes(struct omap_dss_device *dssdev,
931 u16 *xi, u16 *yi, u16 *wi, u16 *hi)
932{
933 struct overlay_cache_data *oc;
934 struct manager_cache_data *mc;
935 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
936 struct omap_overlay_manager *mgr;
937 int i;
938 u16 x, y, w, h;
939 unsigned long flags;
940
941 x = *xi;
942 y = *yi;
943 w = *wi;
944 h = *hi;
945
946 DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
947 *xi, *yi, *wi, *hi);
948
949 mgr = dssdev->manager;
950
951 if (!mgr) {
952 DSSDBG("no manager\n");
953 return;
954 }
955
956 spin_lock_irqsave(&dss_cache.lock, flags);
957
958 /* We need to show the whole overlay if it is scaled. So look for
959 * those, and make the update area larger if found.
960 * Also mark the overlay cache dirty */
961 for (i = 0; i < num_ovls; ++i) {
962 unsigned x1, y1, x2, y2;
963 unsigned outw, outh;
964
965 oc = &dss_cache.overlay_cache[i];
966
967 if (oc->channel != mgr->id)
968 continue;
969
970 oc->dirty = true;
971
972 if (!oc->enabled)
973 continue;
974
975 if (!dispc_is_overlay_scaled(oc))
976 continue;
977
978 outw = oc->out_width == 0 ? oc->width : oc->out_width;
979 outh = oc->out_height == 0 ? oc->height : oc->out_height;
980
981 /* is the overlay outside the update region? */
982 if (!rectangle_intersects(x, y, w, h,
983 oc->pos_x, oc->pos_y,
984 outw, outh))
985 continue;
986
987 /* if the overlay totally inside the update region? */
988 if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh,
989 x, y, w, h))
990 continue;
991
992 if (x > oc->pos_x)
993 x1 = oc->pos_x;
994 else
995 x1 = x;
996
997 if (y > oc->pos_y)
998 y1 = oc->pos_y;
999 else
1000 y1 = y;
1001
1002 if ((x + w) < (oc->pos_x + outw))
1003 x2 = oc->pos_x + outw;
1004 else
1005 x2 = x + w;
1006
1007 if ((y + h) < (oc->pos_y + outh))
1008 y2 = oc->pos_y + outh;
1009 else
1010 y2 = y + h;
1011
1012 x = x1;
1013 y = y1;
1014 w = x2 - x1;
1015 h = y2 - y1;
1016
1017 DSSDBG("changing upd area due to ovl(%d) scaling %d,%d %dx%d\n",
1018 i, x, y, w, h);
1019 }
1020
1021 mc = &dss_cache.manager_cache[mgr->id];
1022 mc->do_manual_update = true;
1023 mc->x = x;
1024 mc->y = y;
1025 mc->w = w;
1026 mc->h = h;
1027
1028 configure_dispc();
1029
1030 mc->do_manual_update = false;
1031
1032 spin_unlock_irqrestore(&dss_cache.lock, flags);
1033
1034 *xi = x;
1035 *yi = y;
1036 *wi = w;
1037 *hi = h;
1038}
1039
1040void dss_start_update(struct omap_dss_device *dssdev)
1041{
1042 struct manager_cache_data *mc;
1043 struct overlay_cache_data *oc;
1044 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1045 const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1046 struct omap_overlay_manager *mgr;
1047 int i;
1048
1049 mgr = dssdev->manager;
1050
1051 for (i = 0; i < num_ovls; ++i) {
1052 oc = &dss_cache.overlay_cache[i];
1053 if (oc->channel != mgr->id)
1054 continue;
1055
1056 oc->shadow_dirty = false;
1057 }
1058
1059 for (i = 0; i < num_mgrs; ++i) {
1060 mc = &dss_cache.manager_cache[i];
1061 if (mgr->id != i)
1062 continue;
1063
1064 mc->shadow_dirty = false;
1065 }
1066
1067 dispc_enable_lcd_out(1);
1068}
1069
1070static void dss_apply_irq_handler(void *data, u32 mask)
1071{
1072 struct manager_cache_data *mc;
1073 struct overlay_cache_data *oc;
1074 const int num_ovls = ARRAY_SIZE(dss_cache.overlay_cache);
1075 const int num_mgrs = ARRAY_SIZE(dss_cache.manager_cache);
1076 int i, r;
1077 bool mgr_busy[2];
1078
1079 mgr_busy[0] = dispc_go_busy(0);
1080 mgr_busy[1] = dispc_go_busy(1);
1081
1082 spin_lock(&dss_cache.lock);
1083
1084 for (i = 0; i < num_ovls; ++i) {
1085 oc = &dss_cache.overlay_cache[i];
1086 if (!mgr_busy[oc->channel])
1087 oc->shadow_dirty = false;
1088 }
1089
1090 for (i = 0; i < num_mgrs; ++i) {
1091 mc = &dss_cache.manager_cache[i];
1092 if (!mgr_busy[i])
1093 mc->shadow_dirty = false;
1094 }
1095
1096 r = configure_dispc();
1097 if (r == 1)
1098 goto end;
1099
1100 /* re-read busy flags */
1101 mgr_busy[0] = dispc_go_busy(0);
1102 mgr_busy[1] = dispc_go_busy(1);
1103
1104 /* keep running as long as there are busy managers, so that
1105 * we can collect overlay-applied information */
1106 for (i = 0; i < num_mgrs; ++i) {
1107 if (mgr_busy[i])
1108 goto end;
1109 }
1110
1111 omap_dispc_unregister_isr(dss_apply_irq_handler, NULL,
1112 DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1113 DISPC_IRQ_EVSYNC_EVEN);
1114 dss_cache.irq_enabled = false;
1115
1116end:
1117 spin_unlock(&dss_cache.lock);
1118}
1119
1120static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr)
1121{
1122 struct overlay_cache_data *oc;
1123 struct manager_cache_data *mc;
1124 int i;
1125 struct omap_overlay *ovl;
1126 int num_planes_enabled = 0;
1127 bool use_fifomerge;
1128 unsigned long flags;
1129 int r;
1130
1131 DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name);
1132
1133 spin_lock_irqsave(&dss_cache.lock, flags);
1134
1135 /* Configure overlays */
1136 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1137 struct omap_dss_device *dssdev;
1138
1139 ovl = omap_dss_get_overlay(i);
1140
1141 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1142 continue;
1143
1144 oc = &dss_cache.overlay_cache[ovl->id];
1145
1146 if (!overlay_enabled(ovl)) {
1147 if (oc->enabled) {
1148 oc->enabled = false;
1149 oc->dirty = true;
1150 }
1151 continue;
1152 }
1153
1154 if (!ovl->info_dirty) {
1155 if (oc->enabled)
1156 ++num_planes_enabled;
1157 continue;
1158 }
1159
1160 dssdev = ovl->manager->device;
1161
1162 if (dss_check_overlay(ovl, dssdev)) {
1163 if (oc->enabled) {
1164 oc->enabled = false;
1165 oc->dirty = true;
1166 }
1167 continue;
1168 }
1169
1170 ovl->info_dirty = false;
1171 oc->dirty = true;
1172
1173 oc->paddr = ovl->info.paddr;
1174 oc->vaddr = ovl->info.vaddr;
1175 oc->screen_width = ovl->info.screen_width;
1176 oc->width = ovl->info.width;
1177 oc->height = ovl->info.height;
1178 oc->color_mode = ovl->info.color_mode;
1179 oc->rotation = ovl->info.rotation;
1180 oc->rotation_type = ovl->info.rotation_type;
1181 oc->mirror = ovl->info.mirror;
1182 oc->pos_x = ovl->info.pos_x;
1183 oc->pos_y = ovl->info.pos_y;
1184 oc->out_width = ovl->info.out_width;
1185 oc->out_height = ovl->info.out_height;
1186 oc->global_alpha = ovl->info.global_alpha;
1187
1188 oc->replication =
1189 dss_use_replication(dssdev, ovl->info.color_mode);
1190
1191 oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC;
1192
1193 oc->channel = ovl->manager->id;
1194
1195 oc->enabled = true;
1196
1197 oc->manual_update =
1198 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1199 dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
1200
1201 ++num_planes_enabled;
1202 }
1203
1204 /* Configure managers */
1205 list_for_each_entry(mgr, &manager_list, list) {
1206 struct omap_dss_device *dssdev;
1207
1208 if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC))
1209 continue;
1210
1211 mc = &dss_cache.manager_cache[mgr->id];
1212
1213 if (mgr->device_changed) {
1214 mgr->device_changed = false;
1215 mgr->info_dirty = true;
1216 }
1217
1218 if (!mgr->info_dirty)
1219 continue;
1220
1221 if (!mgr->device)
1222 continue;
1223
1224 dssdev = mgr->device;
1225
1226 mgr->info_dirty = false;
1227 mc->dirty = true;
1228
1229 mc->default_color = mgr->info.default_color;
1230 mc->trans_key_type = mgr->info.trans_key_type;
1231 mc->trans_key = mgr->info.trans_key;
1232 mc->trans_enabled = mgr->info.trans_enabled;
1233 mc->alpha_enabled = mgr->info.alpha_enabled;
1234
1235 mc->manual_upd_display =
1236 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1237
1238 mc->manual_update =
1239 dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE &&
1240 dssdev->get_update_mode(dssdev) != OMAP_DSS_UPDATE_AUTO;
1241 }
1242
1243 /* XXX TODO: Try to get fifomerge working. The problem is that it
1244 * affects both managers, not individually but at the same time. This
1245 * means the change has to be well synchronized. I guess the proper way
1246 * is to have a two step process for fifo merge:
1247 * fifomerge enable:
1248 * 1. disable other planes, leaving one plane enabled
1249 * 2. wait until the planes are disabled on HW
1250 * 3. config merged fifo thresholds, enable fifomerge
1251 * fifomerge disable:
1252 * 1. config unmerged fifo thresholds, disable fifomerge
1253 * 2. wait until fifo changes are in HW
1254 * 3. enable planes
1255 */
1256 use_fifomerge = false;
1257
1258 /* Configure overlay fifos */
1259 for (i = 0; i < omap_dss_get_num_overlays(); ++i) {
1260 struct omap_dss_device *dssdev;
1261 u32 size;
1262
1263 ovl = omap_dss_get_overlay(i);
1264
1265 if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC))
1266 continue;
1267
1268 oc = &dss_cache.overlay_cache[ovl->id];
1269
1270 if (!oc->enabled)
1271 continue;
1272
1273 dssdev = ovl->manager->device;
1274
1275 size = dispc_get_plane_fifo_size(ovl->id);
1276 if (use_fifomerge)
1277 size *= 3;
1278
1279 switch (dssdev->type) {
1280 case OMAP_DISPLAY_TYPE_DPI:
1281 case OMAP_DISPLAY_TYPE_DBI:
1282 case OMAP_DISPLAY_TYPE_SDI:
1283 case OMAP_DISPLAY_TYPE_VENC:
1284 default_get_overlay_fifo_thresholds(ovl->id, size,
1285 &oc->burst_size, &oc->fifo_low,
1286 &oc->fifo_high);
1287 break;
1288#ifdef CONFIG_OMAP2_DSS_DSI
1289 case OMAP_DISPLAY_TYPE_DSI:
1290 dsi_get_overlay_fifo_thresholds(ovl->id, size,
1291 &oc->burst_size, &oc->fifo_low,
1292 &oc->fifo_high);
1293 break;
1294#endif
1295 default:
1296 BUG();
1297 }
1298 }
1299
1300 r = 0;
1301 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1302 if (!dss_cache.irq_enabled) {
1303 r = omap_dispc_register_isr(dss_apply_irq_handler, NULL,
1304 DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD |
1305 DISPC_IRQ_EVSYNC_EVEN);
1306 dss_cache.irq_enabled = true;
1307 }
1308 configure_dispc();
1309 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1310
1311 spin_unlock_irqrestore(&dss_cache.lock, flags);
1312
1313 return r;
1314}
1315
1316static int dss_check_manager(struct omap_overlay_manager *mgr)
1317{
1318 /* OMAP supports only graphics source transparency color key and alpha
1319 * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */
1320
1321 if (mgr->info.alpha_enabled && mgr->info.trans_enabled &&
1322 mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST)
1323 return -EINVAL;
1324
1325 return 0;
1326}
1327
1328static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr,
1329 struct omap_overlay_manager_info *info)
1330{
1331 int r;
1332 struct omap_overlay_manager_info old_info;
1333
1334 old_info = mgr->info;
1335 mgr->info = *info;
1336
1337 r = dss_check_manager(mgr);
1338 if (r) {
1339 mgr->info = old_info;
1340 return r;
1341 }
1342
1343 mgr->info_dirty = true;
1344
1345 return 0;
1346}
1347
1348static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr,
1349 struct omap_overlay_manager_info *info)
1350{
1351 *info = mgr->info;
1352}
1353
1354static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager)
1355{
1356 ++num_managers;
1357 list_add_tail(&manager->list, &manager_list);
1358}
1359
1360int dss_init_overlay_managers(struct platform_device *pdev)
1361{
1362 int i, r;
1363
1364 spin_lock_init(&dss_cache.lock);
1365
1366 INIT_LIST_HEAD(&manager_list);
1367
1368 num_managers = 0;
1369
1370 for (i = 0; i < 2; ++i) {
1371 struct omap_overlay_manager *mgr;
1372 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1373
1374 BUG_ON(mgr == NULL);
1375
1376 switch (i) {
1377 case 0:
1378 mgr->name = "lcd";
1379 mgr->id = OMAP_DSS_CHANNEL_LCD;
1380 mgr->supported_displays =
1381 OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI |
1382 OMAP_DISPLAY_TYPE_SDI | OMAP_DISPLAY_TYPE_DSI;
1383 break;
1384 case 1:
1385 mgr->name = "tv";
1386 mgr->id = OMAP_DSS_CHANNEL_DIGIT;
1387 mgr->supported_displays = OMAP_DISPLAY_TYPE_VENC;
1388 break;
1389 }
1390
1391 mgr->set_device = &omap_dss_set_device;
1392 mgr->unset_device = &omap_dss_unset_device;
1393 mgr->apply = &omap_dss_mgr_apply;
1394 mgr->set_manager_info = &omap_dss_mgr_set_info;
1395 mgr->get_manager_info = &omap_dss_mgr_get_info;
1396 mgr->wait_for_go = &dss_mgr_wait_for_go;
1397
1398 mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC;
1399
1400 dss_overlay_setup_dispc_manager(mgr);
1401
1402 omap_dss_add_overlay_manager(mgr);
1403
1404 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1405 &pdev->dev.kobj, "manager%d", i);
1406
1407 if (r) {
1408 DSSERR("failed to create sysfs file\n");
1409 continue;
1410 }
1411 }
1412
1413#ifdef L4_EXAMPLE
1414 {
1415 int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr)
1416 {
1417 DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name);
1418
1419 return 0;
1420 }
1421
1422 struct omap_overlay_manager *mgr;
1423 mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
1424
1425 BUG_ON(mgr == NULL);
1426
1427 mgr->name = "l4";
1428 mgr->supported_displays =
1429 OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI;
1430
1431 mgr->set_device = &omap_dss_set_device;
1432 mgr->unset_device = &omap_dss_unset_device;
1433 mgr->apply = &omap_dss_mgr_apply_l4;
1434 mgr->set_manager_info = &omap_dss_mgr_set_info;
1435 mgr->get_manager_info = &omap_dss_mgr_get_info;
1436
1437 dss_overlay_setup_l4_manager(mgr);
1438
1439 omap_dss_add_overlay_manager(mgr);
1440
1441 r = kobject_init_and_add(&mgr->kobj, &manager_ktype,
1442 &pdev->dev.kobj, "managerl4");
1443
1444 if (r)
1445 DSSERR("failed to create sysfs file\n");
1446 }
1447#endif
1448
1449 return 0;
1450}
1451
1452void dss_uninit_overlay_managers(struct platform_device *pdev)
1453{
1454 struct omap_overlay_manager *mgr;
1455
1456 while (!list_empty(&manager_list)) {
1457 mgr = list_first_entry(&manager_list,
1458 struct omap_overlay_manager, list);
1459 list_del(&mgr->list);
1460 kobject_del(&mgr->kobj);
1461 kobject_put(&mgr->kobj);
1462 kfree(mgr);
1463 }
1464
1465 num_managers = 0;
1466}
1467
1468int omap_dss_get_num_overlay_managers(void)
1469{
1470 return num_managers;
1471}
1472EXPORT_SYMBOL(omap_dss_get_num_overlay_managers);
1473
1474struct omap_overlay_manager *omap_dss_get_overlay_manager(int num)
1475{
1476 int i = 0;
1477 struct omap_overlay_manager *mgr;
1478
1479 list_for_each_entry(mgr, &manager_list, list) {
1480 if (i++ == num)
1481 return mgr;
1482 }
1483
1484 return NULL;
1485}
1486EXPORT_SYMBOL(omap_dss_get_overlay_manager);
1487
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c
new file mode 100644
index 000000000000..b7f9a7339842
--- /dev/null
+++ b/drivers/video/omap2/dss/overlay.c
@@ -0,0 +1,680 @@
1/*
2 * linux/drivers/video/omap2/dss/overlay.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "OVERLAY"
24
25#include <linux/kernel.h>
26#include <linux/module.h>
27#include <linux/err.h>
28#include <linux/sysfs.h>
29#include <linux/kobject.h>
30#include <linux/platform_device.h>
31#include <linux/delay.h>
32
33#include <plat/display.h>
34#include <plat/cpu.h>
35
36#include "dss.h"
37
38static int num_overlays;
39static struct list_head overlay_list;
40
41static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf)
42{
43 return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name);
44}
45
46static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf)
47{
48 return snprintf(buf, PAGE_SIZE, "%s\n",
49 ovl->manager ? ovl->manager->name : "<none>");
50}
51
52static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf,
53 size_t size)
54{
55 int i, r;
56 struct omap_overlay_manager *mgr = NULL;
57 struct omap_overlay_manager *old_mgr;
58 int len = size;
59
60 if (buf[size-1] == '\n')
61 --len;
62
63 if (len > 0) {
64 for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) {
65 mgr = omap_dss_get_overlay_manager(i);
66
67 if (strncmp(buf, mgr->name, len) == 0)
68 break;
69
70 mgr = NULL;
71 }
72 }
73
74 if (len > 0 && mgr == NULL)
75 return -EINVAL;
76
77 if (mgr)
78 DSSDBG("manager %s found\n", mgr->name);
79
80 if (mgr == ovl->manager)
81 return size;
82
83 old_mgr = ovl->manager;
84
85 /* detach old manager */
86 if (old_mgr) {
87 r = ovl->unset_manager(ovl);
88 if (r) {
89 DSSERR("detach failed\n");
90 return r;
91 }
92
93 r = old_mgr->apply(old_mgr);
94 if (r)
95 return r;
96 }
97
98 if (mgr) {
99 r = ovl->set_manager(ovl, mgr);
100 if (r) {
101 DSSERR("Failed to attach overlay\n");
102 return r;
103 }
104
105 r = mgr->apply(mgr);
106 if (r)
107 return r;
108 }
109
110 return size;
111}
112
113static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf)
114{
115 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
116 ovl->info.width, ovl->info.height);
117}
118
119static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf)
120{
121 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width);
122}
123
124static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf)
125{
126 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
127 ovl->info.pos_x, ovl->info.pos_y);
128}
129
130static ssize_t overlay_position_store(struct omap_overlay *ovl,
131 const char *buf, size_t size)
132{
133 int r;
134 char *last;
135 struct omap_overlay_info info;
136
137 ovl->get_overlay_info(ovl, &info);
138
139 info.pos_x = simple_strtoul(buf, &last, 10);
140 ++last;
141 if (last - buf >= size)
142 return -EINVAL;
143
144 info.pos_y = simple_strtoul(last, &last, 10);
145
146 r = ovl->set_overlay_info(ovl, &info);
147 if (r)
148 return r;
149
150 if (ovl->manager) {
151 r = ovl->manager->apply(ovl->manager);
152 if (r)
153 return r;
154 }
155
156 return size;
157}
158
159static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf)
160{
161 return snprintf(buf, PAGE_SIZE, "%d,%d\n",
162 ovl->info.out_width, ovl->info.out_height);
163}
164
165static ssize_t overlay_output_size_store(struct omap_overlay *ovl,
166 const char *buf, size_t size)
167{
168 int r;
169 char *last;
170 struct omap_overlay_info info;
171
172 ovl->get_overlay_info(ovl, &info);
173
174 info.out_width = simple_strtoul(buf, &last, 10);
175 ++last;
176 if (last - buf >= size)
177 return -EINVAL;
178
179 info.out_height = simple_strtoul(last, &last, 10);
180
181 r = ovl->set_overlay_info(ovl, &info);
182 if (r)
183 return r;
184
185 if (ovl->manager) {
186 r = ovl->manager->apply(ovl->manager);
187 if (r)
188 return r;
189 }
190
191 return size;
192}
193
194static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf)
195{
196 return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled);
197}
198
199static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf,
200 size_t size)
201{
202 int r;
203 struct omap_overlay_info info;
204
205 ovl->get_overlay_info(ovl, &info);
206
207 info.enabled = simple_strtoul(buf, NULL, 10);
208
209 r = ovl->set_overlay_info(ovl, &info);
210 if (r)
211 return r;
212
213 if (ovl->manager) {
214 r = ovl->manager->apply(ovl->manager);
215 if (r)
216 return r;
217 }
218
219 return size;
220}
221
222static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf)
223{
224 return snprintf(buf, PAGE_SIZE, "%d\n",
225 ovl->info.global_alpha);
226}
227
228static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl,
229 const char *buf, size_t size)
230{
231 int r;
232 struct omap_overlay_info info;
233
234 ovl->get_overlay_info(ovl, &info);
235
236 /* Video1 plane does not support global alpha
237 * to always make it 255 completely opaque
238 */
239 if (ovl->id == OMAP_DSS_VIDEO1)
240 info.global_alpha = 255;
241 else
242 info.global_alpha = simple_strtoul(buf, NULL, 10);
243
244 r = ovl->set_overlay_info(ovl, &info);
245 if (r)
246 return r;
247
248 if (ovl->manager) {
249 r = ovl->manager->apply(ovl->manager);
250 if (r)
251 return r;
252 }
253
254 return size;
255}
256
257struct overlay_attribute {
258 struct attribute attr;
259 ssize_t (*show)(struct omap_overlay *, char *);
260 ssize_t (*store)(struct omap_overlay *, const char *, size_t);
261};
262
263#define OVERLAY_ATTR(_name, _mode, _show, _store) \
264 struct overlay_attribute overlay_attr_##_name = \
265 __ATTR(_name, _mode, _show, _store)
266
267static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL);
268static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR,
269 overlay_manager_show, overlay_manager_store);
270static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL);
271static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL);
272static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR,
273 overlay_position_show, overlay_position_store);
274static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR,
275 overlay_output_size_show, overlay_output_size_store);
276static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR,
277 overlay_enabled_show, overlay_enabled_store);
278static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR,
279 overlay_global_alpha_show, overlay_global_alpha_store);
280
281static struct attribute *overlay_sysfs_attrs[] = {
282 &overlay_attr_name.attr,
283 &overlay_attr_manager.attr,
284 &overlay_attr_input_size.attr,
285 &overlay_attr_screen_width.attr,
286 &overlay_attr_position.attr,
287 &overlay_attr_output_size.attr,
288 &overlay_attr_enabled.attr,
289 &overlay_attr_global_alpha.attr,
290 NULL
291};
292
293static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr,
294 char *buf)
295{
296 struct omap_overlay *overlay;
297 struct overlay_attribute *overlay_attr;
298
299 overlay = container_of(kobj, struct omap_overlay, kobj);
300 overlay_attr = container_of(attr, struct overlay_attribute, attr);
301
302 if (!overlay_attr->show)
303 return -ENOENT;
304
305 return overlay_attr->show(overlay, buf);
306}
307
308static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr,
309 const char *buf, size_t size)
310{
311 struct omap_overlay *overlay;
312 struct overlay_attribute *overlay_attr;
313
314 overlay = container_of(kobj, struct omap_overlay, kobj);
315 overlay_attr = container_of(attr, struct overlay_attribute, attr);
316
317 if (!overlay_attr->store)
318 return -ENOENT;
319
320 return overlay_attr->store(overlay, buf, size);
321}
322
323static struct sysfs_ops overlay_sysfs_ops = {
324 .show = overlay_attr_show,
325 .store = overlay_attr_store,
326};
327
328static struct kobj_type overlay_ktype = {
329 .sysfs_ops = &overlay_sysfs_ops,
330 .default_attrs = overlay_sysfs_attrs,
331};
332
333/* Check if overlay parameters are compatible with display */
334int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev)
335{
336 struct omap_overlay_info *info;
337 u16 outw, outh;
338 u16 dw, dh;
339
340 if (!dssdev)
341 return 0;
342
343 if (!ovl->info.enabled)
344 return 0;
345
346 info = &ovl->info;
347
348 if (info->paddr == 0) {
349 DSSDBG("check_overlay failed: paddr 0\n");
350 return -EINVAL;
351 }
352
353 dssdev->get_resolution(dssdev, &dw, &dh);
354
355 DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n",
356 ovl->id,
357 info->pos_x, info->pos_y,
358 info->width, info->height,
359 info->out_width, info->out_height,
360 dw, dh);
361
362 if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
363 outw = info->width;
364 outh = info->height;
365 } else {
366 if (info->out_width == 0)
367 outw = info->width;
368 else
369 outw = info->out_width;
370
371 if (info->out_height == 0)
372 outh = info->height;
373 else
374 outh = info->out_height;
375 }
376
377 if (dw < info->pos_x + outw) {
378 DSSDBG("check_overlay failed 1: %d < %d + %d\n",
379 dw, info->pos_x, outw);
380 return -EINVAL;
381 }
382
383 if (dh < info->pos_y + outh) {
384 DSSDBG("check_overlay failed 2: %d < %d + %d\n",
385 dh, info->pos_y, outh);
386 return -EINVAL;
387 }
388
389 if ((ovl->supported_modes & info->color_mode) == 0) {
390 DSSERR("overlay doesn't support mode %d\n", info->color_mode);
391 return -EINVAL;
392 }
393
394 return 0;
395}
396
397static int dss_ovl_set_overlay_info(struct omap_overlay *ovl,
398 struct omap_overlay_info *info)
399{
400 int r;
401 struct omap_overlay_info old_info;
402
403 old_info = ovl->info;
404 ovl->info = *info;
405
406 if (ovl->manager) {
407 r = dss_check_overlay(ovl, ovl->manager->device);
408 if (r) {
409 ovl->info = old_info;
410 return r;
411 }
412 }
413
414 ovl->info_dirty = true;
415
416 return 0;
417}
418
419static void dss_ovl_get_overlay_info(struct omap_overlay *ovl,
420 struct omap_overlay_info *info)
421{
422 *info = ovl->info;
423}
424
425static int dss_ovl_wait_for_go(struct omap_overlay *ovl)
426{
427 return dss_mgr_wait_for_go_ovl(ovl);
428}
429
430static int omap_dss_set_manager(struct omap_overlay *ovl,
431 struct omap_overlay_manager *mgr)
432{
433 if (!mgr)
434 return -EINVAL;
435
436 if (ovl->manager) {
437 DSSERR("overlay '%s' already has a manager '%s'\n",
438 ovl->name, ovl->manager->name);
439 return -EINVAL;
440 }
441
442 if (ovl->info.enabled) {
443 DSSERR("overlay has to be disabled to change the manager\n");
444 return -EINVAL;
445 }
446
447 ovl->manager = mgr;
448
449 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
450 /* XXX: on manual update display, in auto update mode, a bug happens
451 * here. When an overlay is first enabled on LCD, then it's disabled,
452 * and the manager is changed to TV, we sometimes get SYNC_LOST_DIGIT
453 * errors. Waiting before changing the channel_out fixes it. I'm
454 * guessing that the overlay is still somehow being used for the LCD,
455 * but I don't understand how or why. */
456 msleep(40);
457 dispc_set_channel_out(ovl->id, mgr->id);
458 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
459
460 return 0;
461}
462
463static int omap_dss_unset_manager(struct omap_overlay *ovl)
464{
465 int r;
466
467 if (!ovl->manager) {
468 DSSERR("failed to detach overlay: manager not set\n");
469 return -EINVAL;
470 }
471
472 if (ovl->info.enabled) {
473 DSSERR("overlay has to be disabled to unset the manager\n");
474 return -EINVAL;
475 }
476
477 r = ovl->wait_for_go(ovl);
478 if (r)
479 return r;
480
481 ovl->manager = NULL;
482
483 return 0;
484}
485
486int omap_dss_get_num_overlays(void)
487{
488 return num_overlays;
489}
490EXPORT_SYMBOL(omap_dss_get_num_overlays);
491
492struct omap_overlay *omap_dss_get_overlay(int num)
493{
494 int i = 0;
495 struct omap_overlay *ovl;
496
497 list_for_each_entry(ovl, &overlay_list, list) {
498 if (i++ == num)
499 return ovl;
500 }
501
502 return NULL;
503}
504EXPORT_SYMBOL(omap_dss_get_overlay);
505
506static void omap_dss_add_overlay(struct omap_overlay *overlay)
507{
508 ++num_overlays;
509 list_add_tail(&overlay->list, &overlay_list);
510}
511
512static struct omap_overlay *dispc_overlays[3];
513
514void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr)
515{
516 mgr->num_overlays = 3;
517 mgr->overlays = dispc_overlays;
518}
519
520#ifdef L4_EXAMPLE
521static struct omap_overlay *l4_overlays[1];
522void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr)
523{
524 mgr->num_overlays = 1;
525 mgr->overlays = l4_overlays;
526}
527#endif
528
529void dss_init_overlays(struct platform_device *pdev)
530{
531 int i, r;
532
533 INIT_LIST_HEAD(&overlay_list);
534
535 num_overlays = 0;
536
537 for (i = 0; i < 3; ++i) {
538 struct omap_overlay *ovl;
539 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
540
541 BUG_ON(ovl == NULL);
542
543 switch (i) {
544 case 0:
545 ovl->name = "gfx";
546 ovl->id = OMAP_DSS_GFX;
547 ovl->supported_modes = cpu_is_omap34xx() ?
548 OMAP_DSS_COLOR_GFX_OMAP3 :
549 OMAP_DSS_COLOR_GFX_OMAP2;
550 ovl->caps = OMAP_DSS_OVL_CAP_DISPC;
551 ovl->info.global_alpha = 255;
552 break;
553 case 1:
554 ovl->name = "vid1";
555 ovl->id = OMAP_DSS_VIDEO1;
556 ovl->supported_modes = cpu_is_omap34xx() ?
557 OMAP_DSS_COLOR_VID1_OMAP3 :
558 OMAP_DSS_COLOR_VID_OMAP2;
559 ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
560 OMAP_DSS_OVL_CAP_DISPC;
561 ovl->info.global_alpha = 255;
562 break;
563 case 2:
564 ovl->name = "vid2";
565 ovl->id = OMAP_DSS_VIDEO2;
566 ovl->supported_modes = cpu_is_omap34xx() ?
567 OMAP_DSS_COLOR_VID2_OMAP3 :
568 OMAP_DSS_COLOR_VID_OMAP2;
569 ovl->caps = OMAP_DSS_OVL_CAP_SCALE |
570 OMAP_DSS_OVL_CAP_DISPC;
571 ovl->info.global_alpha = 255;
572 break;
573 }
574
575 ovl->set_manager = &omap_dss_set_manager;
576 ovl->unset_manager = &omap_dss_unset_manager;
577 ovl->set_overlay_info = &dss_ovl_set_overlay_info;
578 ovl->get_overlay_info = &dss_ovl_get_overlay_info;
579 ovl->wait_for_go = &dss_ovl_wait_for_go;
580
581 omap_dss_add_overlay(ovl);
582
583 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
584 &pdev->dev.kobj, "overlay%d", i);
585
586 if (r) {
587 DSSERR("failed to create sysfs file\n");
588 continue;
589 }
590
591 dispc_overlays[i] = ovl;
592 }
593
594#ifdef L4_EXAMPLE
595 {
596 struct omap_overlay *ovl;
597 ovl = kzalloc(sizeof(*ovl), GFP_KERNEL);
598
599 BUG_ON(ovl == NULL);
600
601 ovl->name = "l4";
602 ovl->supported_modes = OMAP_DSS_COLOR_RGB24U;
603
604 ovl->set_manager = &omap_dss_set_manager;
605 ovl->unset_manager = &omap_dss_unset_manager;
606 ovl->set_overlay_info = &dss_ovl_set_overlay_info;
607 ovl->get_overlay_info = &dss_ovl_get_overlay_info;
608
609 omap_dss_add_overlay(ovl);
610
611 r = kobject_init_and_add(&ovl->kobj, &overlay_ktype,
612 &pdev->dev.kobj, "overlayl4");
613
614 if (r)
615 DSSERR("failed to create sysfs file\n");
616
617 l4_overlays[0] = ovl;
618 }
619#endif
620}
621
622/* connect overlays to the new device, if not already connected. if force
623 * selected, connect always. */
624void dss_recheck_connections(struct omap_dss_device *dssdev, bool force)
625{
626 int i;
627 struct omap_overlay_manager *lcd_mgr;
628 struct omap_overlay_manager *tv_mgr;
629 struct omap_overlay_manager *mgr = NULL;
630
631 lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD);
632 tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV);
633
634 if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) {
635 if (!lcd_mgr->device || force) {
636 if (lcd_mgr->device)
637 lcd_mgr->unset_device(lcd_mgr);
638 lcd_mgr->set_device(lcd_mgr, dssdev);
639 mgr = lcd_mgr;
640 }
641 }
642
643 if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) {
644 if (!tv_mgr->device || force) {
645 if (tv_mgr->device)
646 tv_mgr->unset_device(tv_mgr);
647 tv_mgr->set_device(tv_mgr, dssdev);
648 mgr = tv_mgr;
649 }
650 }
651
652 if (mgr) {
653 for (i = 0; i < 3; i++) {
654 struct omap_overlay *ovl;
655 ovl = omap_dss_get_overlay(i);
656 if (!ovl->manager || force) {
657 if (ovl->manager)
658 omap_dss_unset_manager(ovl);
659 omap_dss_set_manager(ovl, mgr);
660 }
661 }
662 }
663}
664
665void dss_uninit_overlays(struct platform_device *pdev)
666{
667 struct omap_overlay *ovl;
668
669 while (!list_empty(&overlay_list)) {
670 ovl = list_first_entry(&overlay_list,
671 struct omap_overlay, list);
672 list_del(&ovl->list);
673 kobject_del(&ovl->kobj);
674 kobject_put(&ovl->kobj);
675 kfree(ovl);
676 }
677
678 num_overlays = 0;
679}
680
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
new file mode 100644
index 000000000000..b936495c065d
--- /dev/null
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -0,0 +1,1309 @@
1/*
2 * linux/drivers/video/omap2/dss/rfbi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "RFBI"
24
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/vmalloc.h>
28#include <linux/clk.h>
29#include <linux/io.h>
30#include <linux/delay.h>
31#include <linux/kfifo.h>
32#include <linux/ktime.h>
33#include <linux/hrtimer.h>
34#include <linux/seq_file.h>
35
36#include <plat/display.h>
37#include "dss.h"
38
39/*#define MEASURE_PERF*/
40
41#define RFBI_BASE 0x48050800
42
43struct rfbi_reg { u16 idx; };
44
45#define RFBI_REG(idx) ((const struct rfbi_reg) { idx })
46
47#define RFBI_REVISION RFBI_REG(0x0000)
48#define RFBI_SYSCONFIG RFBI_REG(0x0010)
49#define RFBI_SYSSTATUS RFBI_REG(0x0014)
50#define RFBI_CONTROL RFBI_REG(0x0040)
51#define RFBI_PIXEL_CNT RFBI_REG(0x0044)
52#define RFBI_LINE_NUMBER RFBI_REG(0x0048)
53#define RFBI_CMD RFBI_REG(0x004c)
54#define RFBI_PARAM RFBI_REG(0x0050)
55#define RFBI_DATA RFBI_REG(0x0054)
56#define RFBI_READ RFBI_REG(0x0058)
57#define RFBI_STATUS RFBI_REG(0x005c)
58
59#define RFBI_CONFIG(n) RFBI_REG(0x0060 + (n)*0x18)
60#define RFBI_ONOFF_TIME(n) RFBI_REG(0x0064 + (n)*0x18)
61#define RFBI_CYCLE_TIME(n) RFBI_REG(0x0068 + (n)*0x18)
62#define RFBI_DATA_CYCLE1(n) RFBI_REG(0x006c + (n)*0x18)
63#define RFBI_DATA_CYCLE2(n) RFBI_REG(0x0070 + (n)*0x18)
64#define RFBI_DATA_CYCLE3(n) RFBI_REG(0x0074 + (n)*0x18)
65
66#define RFBI_VSYNC_WIDTH RFBI_REG(0x0090)
67#define RFBI_HSYNC_WIDTH RFBI_REG(0x0094)
68
69#define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param))
70
71#define REG_FLD_MOD(idx, val, start, end) \
72 rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end))
73
74/* To work around an RFBI transfer rate limitation */
75#define OMAP_RFBI_RATE_LIMIT 1
76
77enum omap_rfbi_cycleformat {
78 OMAP_DSS_RFBI_CYCLEFORMAT_1_1 = 0,
79 OMAP_DSS_RFBI_CYCLEFORMAT_2_1 = 1,
80 OMAP_DSS_RFBI_CYCLEFORMAT_3_1 = 2,
81 OMAP_DSS_RFBI_CYCLEFORMAT_3_2 = 3,
82};
83
84enum omap_rfbi_datatype {
85 OMAP_DSS_RFBI_DATATYPE_12 = 0,
86 OMAP_DSS_RFBI_DATATYPE_16 = 1,
87 OMAP_DSS_RFBI_DATATYPE_18 = 2,
88 OMAP_DSS_RFBI_DATATYPE_24 = 3,
89};
90
91enum omap_rfbi_parallelmode {
92 OMAP_DSS_RFBI_PARALLELMODE_8 = 0,
93 OMAP_DSS_RFBI_PARALLELMODE_9 = 1,
94 OMAP_DSS_RFBI_PARALLELMODE_12 = 2,
95 OMAP_DSS_RFBI_PARALLELMODE_16 = 3,
96};
97
98enum update_cmd {
99 RFBI_CMD_UPDATE = 0,
100 RFBI_CMD_SYNC = 1,
101};
102
103static int rfbi_convert_timings(struct rfbi_timings *t);
104static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div);
105static void process_cmd_fifo(void);
106
107static struct {
108 void __iomem *base;
109
110 unsigned long l4_khz;
111
112 enum omap_rfbi_datatype datatype;
113 enum omap_rfbi_parallelmode parallelmode;
114
115 enum omap_rfbi_te_mode te_mode;
116 int te_enabled;
117
118 void (*framedone_callback)(void *data);
119 void *framedone_callback_data;
120
121 struct omap_dss_device *dssdev[2];
122
123 struct kfifo cmd_fifo;
124 spinlock_t cmd_lock;
125 struct completion cmd_done;
126 atomic_t cmd_fifo_full;
127 atomic_t cmd_pending;
128#ifdef MEASURE_PERF
129 unsigned perf_bytes;
130 ktime_t perf_setup_time;
131 ktime_t perf_start_time;
132#endif
133} rfbi;
134
135struct update_region {
136 u16 x;
137 u16 y;
138 u16 w;
139 u16 h;
140};
141
142struct update_param {
143 u8 rfbi_module;
144 u8 cmd;
145
146 union {
147 struct update_region r;
148 struct completion *sync;
149 } par;
150};
151
152static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val)
153{
154 __raw_writel(val, rfbi.base + idx.idx);
155}
156
157static inline u32 rfbi_read_reg(const struct rfbi_reg idx)
158{
159 return __raw_readl(rfbi.base + idx.idx);
160}
161
162static void rfbi_enable_clocks(bool enable)
163{
164 if (enable)
165 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
166 else
167 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
168}
169
170void omap_rfbi_write_command(const void *buf, u32 len)
171{
172 rfbi_enable_clocks(1);
173 switch (rfbi.parallelmode) {
174 case OMAP_DSS_RFBI_PARALLELMODE_8:
175 {
176 const u8 *b = buf;
177 for (; len; len--)
178 rfbi_write_reg(RFBI_CMD, *b++);
179 break;
180 }
181
182 case OMAP_DSS_RFBI_PARALLELMODE_16:
183 {
184 const u16 *w = buf;
185 BUG_ON(len & 1);
186 for (; len; len -= 2)
187 rfbi_write_reg(RFBI_CMD, *w++);
188 break;
189 }
190
191 case OMAP_DSS_RFBI_PARALLELMODE_9:
192 case OMAP_DSS_RFBI_PARALLELMODE_12:
193 default:
194 BUG();
195 }
196 rfbi_enable_clocks(0);
197}
198EXPORT_SYMBOL(omap_rfbi_write_command);
199
200void omap_rfbi_read_data(void *buf, u32 len)
201{
202 rfbi_enable_clocks(1);
203 switch (rfbi.parallelmode) {
204 case OMAP_DSS_RFBI_PARALLELMODE_8:
205 {
206 u8 *b = buf;
207 for (; len; len--) {
208 rfbi_write_reg(RFBI_READ, 0);
209 *b++ = rfbi_read_reg(RFBI_READ);
210 }
211 break;
212 }
213
214 case OMAP_DSS_RFBI_PARALLELMODE_16:
215 {
216 u16 *w = buf;
217 BUG_ON(len & ~1);
218 for (; len; len -= 2) {
219 rfbi_write_reg(RFBI_READ, 0);
220 *w++ = rfbi_read_reg(RFBI_READ);
221 }
222 break;
223 }
224
225 case OMAP_DSS_RFBI_PARALLELMODE_9:
226 case OMAP_DSS_RFBI_PARALLELMODE_12:
227 default:
228 BUG();
229 }
230 rfbi_enable_clocks(0);
231}
232EXPORT_SYMBOL(omap_rfbi_read_data);
233
234void omap_rfbi_write_data(const void *buf, u32 len)
235{
236 rfbi_enable_clocks(1);
237 switch (rfbi.parallelmode) {
238 case OMAP_DSS_RFBI_PARALLELMODE_8:
239 {
240 const u8 *b = buf;
241 for (; len; len--)
242 rfbi_write_reg(RFBI_PARAM, *b++);
243 break;
244 }
245
246 case OMAP_DSS_RFBI_PARALLELMODE_16:
247 {
248 const u16 *w = buf;
249 BUG_ON(len & 1);
250 for (; len; len -= 2)
251 rfbi_write_reg(RFBI_PARAM, *w++);
252 break;
253 }
254
255 case OMAP_DSS_RFBI_PARALLELMODE_9:
256 case OMAP_DSS_RFBI_PARALLELMODE_12:
257 default:
258 BUG();
259
260 }
261 rfbi_enable_clocks(0);
262}
263EXPORT_SYMBOL(omap_rfbi_write_data);
264
265void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width,
266 u16 x, u16 y,
267 u16 w, u16 h)
268{
269 int start_offset = scr_width * y + x;
270 int horiz_offset = scr_width - w;
271 int i;
272
273 rfbi_enable_clocks(1);
274
275 if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
276 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
277 const u16 __iomem *pd = buf;
278 pd += start_offset;
279
280 for (; h; --h) {
281 for (i = 0; i < w; ++i) {
282 const u8 __iomem *b = (const u8 __iomem *)pd;
283 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
284 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
285 ++pd;
286 }
287 pd += horiz_offset;
288 }
289 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_24 &&
290 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_8) {
291 const u32 __iomem *pd = buf;
292 pd += start_offset;
293
294 for (; h; --h) {
295 for (i = 0; i < w; ++i) {
296 const u8 __iomem *b = (const u8 __iomem *)pd;
297 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+2));
298 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+1));
299 rfbi_write_reg(RFBI_PARAM, __raw_readb(b+0));
300 ++pd;
301 }
302 pd += horiz_offset;
303 }
304 } else if (rfbi.datatype == OMAP_DSS_RFBI_DATATYPE_16 &&
305 rfbi.parallelmode == OMAP_DSS_RFBI_PARALLELMODE_16) {
306 const u16 __iomem *pd = buf;
307 pd += start_offset;
308
309 for (; h; --h) {
310 for (i = 0; i < w; ++i) {
311 rfbi_write_reg(RFBI_PARAM, __raw_readw(pd));
312 ++pd;
313 }
314 pd += horiz_offset;
315 }
316 } else {
317 BUG();
318 }
319
320 rfbi_enable_clocks(0);
321}
322EXPORT_SYMBOL(omap_rfbi_write_pixels);
323
324#ifdef MEASURE_PERF
325static void perf_mark_setup(void)
326{
327 rfbi.perf_setup_time = ktime_get();
328}
329
330static void perf_mark_start(void)
331{
332 rfbi.perf_start_time = ktime_get();
333}
334
335static void perf_show(const char *name)
336{
337 ktime_t t, setup_time, trans_time;
338 u32 total_bytes;
339 u32 setup_us, trans_us, total_us;
340
341 t = ktime_get();
342
343 setup_time = ktime_sub(rfbi.perf_start_time, rfbi.perf_setup_time);
344 setup_us = (u32)ktime_to_us(setup_time);
345 if (setup_us == 0)
346 setup_us = 1;
347
348 trans_time = ktime_sub(t, rfbi.perf_start_time);
349 trans_us = (u32)ktime_to_us(trans_time);
350 if (trans_us == 0)
351 trans_us = 1;
352
353 total_us = setup_us + trans_us;
354
355 total_bytes = rfbi.perf_bytes;
356
357 DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, "
358 "%u kbytes/sec\n",
359 name,
360 setup_us,
361 trans_us,
362 total_us,
363 1000*1000 / total_us,
364 total_bytes,
365 total_bytes * 1000 / total_us);
366}
367#else
368#define perf_mark_setup()
369#define perf_mark_start()
370#define perf_show(x)
371#endif
372
373void rfbi_transfer_area(u16 width, u16 height,
374 void (callback)(void *data), void *data)
375{
376 u32 l;
377
378 /*BUG_ON(callback == 0);*/
379 BUG_ON(rfbi.framedone_callback != NULL);
380
381 DSSDBG("rfbi_transfer_area %dx%d\n", width, height);
382
383 dispc_set_lcd_size(width, height);
384
385 dispc_enable_lcd_out(1);
386
387 rfbi.framedone_callback = callback;
388 rfbi.framedone_callback_data = data;
389
390 rfbi_enable_clocks(1);
391
392 rfbi_write_reg(RFBI_PIXEL_CNT, width * height);
393
394 l = rfbi_read_reg(RFBI_CONTROL);
395 l = FLD_MOD(l, 1, 0, 0); /* enable */
396 if (!rfbi.te_enabled)
397 l = FLD_MOD(l, 1, 4, 4); /* ITE */
398
399 perf_mark_start();
400
401 rfbi_write_reg(RFBI_CONTROL, l);
402}
403
404static void framedone_callback(void *data, u32 mask)
405{
406 void (*callback)(void *data);
407
408 DSSDBG("FRAMEDONE\n");
409
410 perf_show("DISPC");
411
412 REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0);
413
414 rfbi_enable_clocks(0);
415
416 callback = rfbi.framedone_callback;
417 rfbi.framedone_callback = NULL;
418
419 /*callback(rfbi.framedone_callback_data);*/
420
421 atomic_set(&rfbi.cmd_pending, 0);
422
423 process_cmd_fifo();
424}
425
426#if 1 /* VERBOSE */
427static void rfbi_print_timings(void)
428{
429 u32 l;
430 u32 time;
431
432 l = rfbi_read_reg(RFBI_CONFIG(0));
433 time = 1000000000 / rfbi.l4_khz;
434 if (l & (1 << 4))
435 time *= 2;
436
437 DSSDBG("Tick time %u ps\n", time);
438 l = rfbi_read_reg(RFBI_ONOFF_TIME(0));
439 DSSDBG("CSONTIME %d, CSOFFTIME %d, WEONTIME %d, WEOFFTIME %d, "
440 "REONTIME %d, REOFFTIME %d\n",
441 l & 0x0f, (l >> 4) & 0x3f, (l >> 10) & 0x0f, (l >> 14) & 0x3f,
442 (l >> 20) & 0x0f, (l >> 24) & 0x3f);
443
444 l = rfbi_read_reg(RFBI_CYCLE_TIME(0));
445 DSSDBG("WECYCLETIME %d, RECYCLETIME %d, CSPULSEWIDTH %d, "
446 "ACCESSTIME %d\n",
447 (l & 0x3f), (l >> 6) & 0x3f, (l >> 12) & 0x3f,
448 (l >> 22) & 0x3f);
449}
450#else
451static void rfbi_print_timings(void) {}
452#endif
453
454
455
456
457static u32 extif_clk_period;
458
459static inline unsigned long round_to_extif_ticks(unsigned long ps, int div)
460{
461 int bus_tick = extif_clk_period * div;
462 return (ps + bus_tick - 1) / bus_tick * bus_tick;
463}
464
465static int calc_reg_timing(struct rfbi_timings *t, int div)
466{
467 t->clk_div = div;
468
469 t->cs_on_time = round_to_extif_ticks(t->cs_on_time, div);
470
471 t->we_on_time = round_to_extif_ticks(t->we_on_time, div);
472 t->we_off_time = round_to_extif_ticks(t->we_off_time, div);
473 t->we_cycle_time = round_to_extif_ticks(t->we_cycle_time, div);
474
475 t->re_on_time = round_to_extif_ticks(t->re_on_time, div);
476 t->re_off_time = round_to_extif_ticks(t->re_off_time, div);
477 t->re_cycle_time = round_to_extif_ticks(t->re_cycle_time, div);
478
479 t->access_time = round_to_extif_ticks(t->access_time, div);
480 t->cs_off_time = round_to_extif_ticks(t->cs_off_time, div);
481 t->cs_pulse_width = round_to_extif_ticks(t->cs_pulse_width, div);
482
483 DSSDBG("[reg]cson %d csoff %d reon %d reoff %d\n",
484 t->cs_on_time, t->cs_off_time, t->re_on_time, t->re_off_time);
485 DSSDBG("[reg]weon %d weoff %d recyc %d wecyc %d\n",
486 t->we_on_time, t->we_off_time, t->re_cycle_time,
487 t->we_cycle_time);
488 DSSDBG("[reg]rdaccess %d cspulse %d\n",
489 t->access_time, t->cs_pulse_width);
490
491 return rfbi_convert_timings(t);
492}
493
494static int calc_extif_timings(struct rfbi_timings *t)
495{
496 u32 max_clk_div;
497 int div;
498
499 rfbi_get_clk_info(&extif_clk_period, &max_clk_div);
500 for (div = 1; div <= max_clk_div; div++) {
501 if (calc_reg_timing(t, div) == 0)
502 break;
503 }
504
505 if (div <= max_clk_div)
506 return 0;
507
508 DSSERR("can't setup timings\n");
509 return -1;
510}
511
512
513void rfbi_set_timings(int rfbi_module, struct rfbi_timings *t)
514{
515 int r;
516
517 if (!t->converted) {
518 r = calc_extif_timings(t);
519 if (r < 0)
520 DSSERR("Failed to calc timings\n");
521 }
522
523 BUG_ON(!t->converted);
524
525 rfbi_enable_clocks(1);
526 rfbi_write_reg(RFBI_ONOFF_TIME(rfbi_module), t->tim[0]);
527 rfbi_write_reg(RFBI_CYCLE_TIME(rfbi_module), t->tim[1]);
528
529 /* TIMEGRANULARITY */
530 REG_FLD_MOD(RFBI_CONFIG(rfbi_module),
531 (t->tim[2] ? 1 : 0), 4, 4);
532
533 rfbi_print_timings();
534 rfbi_enable_clocks(0);
535}
536
537static int ps_to_rfbi_ticks(int time, int div)
538{
539 unsigned long tick_ps;
540 int ret;
541
542 /* Calculate in picosecs to yield more exact results */
543 tick_ps = 1000000000 / (rfbi.l4_khz) * div;
544
545 ret = (time + tick_ps - 1) / tick_ps;
546
547 return ret;
548}
549
550#ifdef OMAP_RFBI_RATE_LIMIT
551unsigned long rfbi_get_max_tx_rate(void)
552{
553 unsigned long l4_rate, dss1_rate;
554 int min_l4_ticks = 0;
555 int i;
556
557 /* According to TI this can't be calculated so make the
558 * adjustments for a couple of known frequencies and warn for
559 * others.
560 */
561 static const struct {
562 unsigned long l4_clk; /* HZ */
563 unsigned long dss1_clk; /* HZ */
564 unsigned long min_l4_ticks;
565 } ftab[] = {
566 { 55, 132, 7, }, /* 7.86 MPix/s */
567 { 110, 110, 12, }, /* 9.16 MPix/s */
568 { 110, 132, 10, }, /* 11 Mpix/s */
569 { 120, 120, 10, }, /* 12 Mpix/s */
570 { 133, 133, 10, }, /* 13.3 Mpix/s */
571 };
572
573 l4_rate = rfbi.l4_khz / 1000;
574 dss1_rate = dss_clk_get_rate(DSS_CLK_FCK1) / 1000000;
575
576 for (i = 0; i < ARRAY_SIZE(ftab); i++) {
577 /* Use a window instead of an exact match, to account
578 * for different DPLL multiplier / divider pairs.
579 */
580 if (abs(ftab[i].l4_clk - l4_rate) < 3 &&
581 abs(ftab[i].dss1_clk - dss1_rate) < 3) {
582 min_l4_ticks = ftab[i].min_l4_ticks;
583 break;
584 }
585 }
586 if (i == ARRAY_SIZE(ftab)) {
587 /* Can't be sure, return anyway the maximum not
588 * rate-limited. This might cause a problem only for the
589 * tearing synchronisation.
590 */
591 DSSERR("can't determine maximum RFBI transfer rate\n");
592 return rfbi.l4_khz * 1000;
593 }
594 return rfbi.l4_khz * 1000 / min_l4_ticks;
595}
596#else
597int rfbi_get_max_tx_rate(void)
598{
599 return rfbi.l4_khz * 1000;
600}
601#endif
602
603static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div)
604{
605 *clk_period = 1000000000 / rfbi.l4_khz;
606 *max_clk_div = 2;
607}
608
609static int rfbi_convert_timings(struct rfbi_timings *t)
610{
611 u32 l;
612 int reon, reoff, weon, weoff, cson, csoff, cs_pulse;
613 int actim, recyc, wecyc;
614 int div = t->clk_div;
615
616 if (div <= 0 || div > 2)
617 return -1;
618
619 /* Make sure that after conversion it still holds that:
620 * weoff > weon, reoff > reon, recyc >= reoff, wecyc >= weoff,
621 * csoff > cson, csoff >= max(weoff, reoff), actim > reon
622 */
623 weon = ps_to_rfbi_ticks(t->we_on_time, div);
624 weoff = ps_to_rfbi_ticks(t->we_off_time, div);
625 if (weoff <= weon)
626 weoff = weon + 1;
627 if (weon > 0x0f)
628 return -1;
629 if (weoff > 0x3f)
630 return -1;
631
632 reon = ps_to_rfbi_ticks(t->re_on_time, div);
633 reoff = ps_to_rfbi_ticks(t->re_off_time, div);
634 if (reoff <= reon)
635 reoff = reon + 1;
636 if (reon > 0x0f)
637 return -1;
638 if (reoff > 0x3f)
639 return -1;
640
641 cson = ps_to_rfbi_ticks(t->cs_on_time, div);
642 csoff = ps_to_rfbi_ticks(t->cs_off_time, div);
643 if (csoff <= cson)
644 csoff = cson + 1;
645 if (csoff < max(weoff, reoff))
646 csoff = max(weoff, reoff);
647 if (cson > 0x0f)
648 return -1;
649 if (csoff > 0x3f)
650 return -1;
651
652 l = cson;
653 l |= csoff << 4;
654 l |= weon << 10;
655 l |= weoff << 14;
656 l |= reon << 20;
657 l |= reoff << 24;
658
659 t->tim[0] = l;
660
661 actim = ps_to_rfbi_ticks(t->access_time, div);
662 if (actim <= reon)
663 actim = reon + 1;
664 if (actim > 0x3f)
665 return -1;
666
667 wecyc = ps_to_rfbi_ticks(t->we_cycle_time, div);
668 if (wecyc < weoff)
669 wecyc = weoff;
670 if (wecyc > 0x3f)
671 return -1;
672
673 recyc = ps_to_rfbi_ticks(t->re_cycle_time, div);
674 if (recyc < reoff)
675 recyc = reoff;
676 if (recyc > 0x3f)
677 return -1;
678
679 cs_pulse = ps_to_rfbi_ticks(t->cs_pulse_width, div);
680 if (cs_pulse > 0x3f)
681 return -1;
682
683 l = wecyc;
684 l |= recyc << 6;
685 l |= cs_pulse << 12;
686 l |= actim << 22;
687
688 t->tim[1] = l;
689
690 t->tim[2] = div - 1;
691
692 t->converted = 1;
693
694 return 0;
695}
696
697/* xxx FIX module selection missing */
698int omap_rfbi_setup_te(enum omap_rfbi_te_mode mode,
699 unsigned hs_pulse_time, unsigned vs_pulse_time,
700 int hs_pol_inv, int vs_pol_inv, int extif_div)
701{
702 int hs, vs;
703 int min;
704 u32 l;
705
706 hs = ps_to_rfbi_ticks(hs_pulse_time, 1);
707 vs = ps_to_rfbi_ticks(vs_pulse_time, 1);
708 if (hs < 2)
709 return -EDOM;
710 if (mode == OMAP_DSS_RFBI_TE_MODE_2)
711 min = 2;
712 else /* OMAP_DSS_RFBI_TE_MODE_1 */
713 min = 4;
714 if (vs < min)
715 return -EDOM;
716 if (vs == hs)
717 return -EINVAL;
718 rfbi.te_mode = mode;
719 DSSDBG("setup_te: mode %d hs %d vs %d hs_inv %d vs_inv %d\n",
720 mode, hs, vs, hs_pol_inv, vs_pol_inv);
721
722 rfbi_enable_clocks(1);
723 rfbi_write_reg(RFBI_HSYNC_WIDTH, hs);
724 rfbi_write_reg(RFBI_VSYNC_WIDTH, vs);
725
726 l = rfbi_read_reg(RFBI_CONFIG(0));
727 if (hs_pol_inv)
728 l &= ~(1 << 21);
729 else
730 l |= 1 << 21;
731 if (vs_pol_inv)
732 l &= ~(1 << 20);
733 else
734 l |= 1 << 20;
735 rfbi_enable_clocks(0);
736
737 return 0;
738}
739EXPORT_SYMBOL(omap_rfbi_setup_te);
740
741/* xxx FIX module selection missing */
742int omap_rfbi_enable_te(bool enable, unsigned line)
743{
744 u32 l;
745
746 DSSDBG("te %d line %d mode %d\n", enable, line, rfbi.te_mode);
747 if (line > (1 << 11) - 1)
748 return -EINVAL;
749
750 rfbi_enable_clocks(1);
751 l = rfbi_read_reg(RFBI_CONFIG(0));
752 l &= ~(0x3 << 2);
753 if (enable) {
754 rfbi.te_enabled = 1;
755 l |= rfbi.te_mode << 2;
756 } else
757 rfbi.te_enabled = 0;
758 rfbi_write_reg(RFBI_CONFIG(0), l);
759 rfbi_write_reg(RFBI_LINE_NUMBER, line);
760 rfbi_enable_clocks(0);
761
762 return 0;
763}
764EXPORT_SYMBOL(omap_rfbi_enable_te);
765
766#if 0
767static void rfbi_enable_config(int enable1, int enable2)
768{
769 u32 l;
770 int cs = 0;
771
772 if (enable1)
773 cs |= 1<<0;
774 if (enable2)
775 cs |= 1<<1;
776
777 rfbi_enable_clocks(1);
778
779 l = rfbi_read_reg(RFBI_CONTROL);
780
781 l = FLD_MOD(l, cs, 3, 2);
782 l = FLD_MOD(l, 0, 1, 1);
783
784 rfbi_write_reg(RFBI_CONTROL, l);
785
786
787 l = rfbi_read_reg(RFBI_CONFIG(0));
788 l = FLD_MOD(l, 0, 3, 2); /* TRIGGERMODE: ITE */
789 /*l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
790 /*l |= FLD_VAL(0, 8, 7); */ /* L4FORMAT, 1pix/L4 */
791
792 l = FLD_MOD(l, 0, 16, 16); /* A0POLARITY */
793 l = FLD_MOD(l, 1, 20, 20); /* TE_VSYNC_POLARITY */
794 l = FLD_MOD(l, 1, 21, 21); /* HSYNCPOLARITY */
795
796 l = FLD_MOD(l, OMAP_DSS_RFBI_PARALLELMODE_8, 1, 0);
797 rfbi_write_reg(RFBI_CONFIG(0), l);
798
799 rfbi_enable_clocks(0);
800}
801#endif
802
803int rfbi_configure(int rfbi_module, int bpp, int lines)
804{
805 u32 l;
806 int cycle1 = 0, cycle2 = 0, cycle3 = 0;
807 enum omap_rfbi_cycleformat cycleformat;
808 enum omap_rfbi_datatype datatype;
809 enum omap_rfbi_parallelmode parallelmode;
810
811 switch (bpp) {
812 case 12:
813 datatype = OMAP_DSS_RFBI_DATATYPE_12;
814 break;
815 case 16:
816 datatype = OMAP_DSS_RFBI_DATATYPE_16;
817 break;
818 case 18:
819 datatype = OMAP_DSS_RFBI_DATATYPE_18;
820 break;
821 case 24:
822 datatype = OMAP_DSS_RFBI_DATATYPE_24;
823 break;
824 default:
825 BUG();
826 return 1;
827 }
828 rfbi.datatype = datatype;
829
830 switch (lines) {
831 case 8:
832 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_8;
833 break;
834 case 9:
835 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_9;
836 break;
837 case 12:
838 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_12;
839 break;
840 case 16:
841 parallelmode = OMAP_DSS_RFBI_PARALLELMODE_16;
842 break;
843 default:
844 BUG();
845 return 1;
846 }
847 rfbi.parallelmode = parallelmode;
848
849 if ((bpp % lines) == 0) {
850 switch (bpp / lines) {
851 case 1:
852 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_1_1;
853 break;
854 case 2:
855 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_2_1;
856 break;
857 case 3:
858 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_1;
859 break;
860 default:
861 BUG();
862 return 1;
863 }
864 } else if ((2 * bpp % lines) == 0) {
865 if ((2 * bpp / lines) == 3)
866 cycleformat = OMAP_DSS_RFBI_CYCLEFORMAT_3_2;
867 else {
868 BUG();
869 return 1;
870 }
871 } else {
872 BUG();
873 return 1;
874 }
875
876 switch (cycleformat) {
877 case OMAP_DSS_RFBI_CYCLEFORMAT_1_1:
878 cycle1 = lines;
879 break;
880
881 case OMAP_DSS_RFBI_CYCLEFORMAT_2_1:
882 cycle1 = lines;
883 cycle2 = lines;
884 break;
885
886 case OMAP_DSS_RFBI_CYCLEFORMAT_3_1:
887 cycle1 = lines;
888 cycle2 = lines;
889 cycle3 = lines;
890 break;
891
892 case OMAP_DSS_RFBI_CYCLEFORMAT_3_2:
893 cycle1 = lines;
894 cycle2 = (lines / 2) | ((lines / 2) << 16);
895 cycle3 = (lines << 16);
896 break;
897 }
898
899 rfbi_enable_clocks(1);
900
901 REG_FLD_MOD(RFBI_CONTROL, 0, 3, 2); /* clear CS */
902
903 l = 0;
904 l |= FLD_VAL(parallelmode, 1, 0);
905 l |= FLD_VAL(0, 3, 2); /* TRIGGERMODE: ITE */
906 l |= FLD_VAL(0, 4, 4); /* TIMEGRANULARITY */
907 l |= FLD_VAL(datatype, 6, 5);
908 /* l |= FLD_VAL(2, 8, 7); */ /* L4FORMAT, 2pix/L4 */
909 l |= FLD_VAL(0, 8, 7); /* L4FORMAT, 1pix/L4 */
910 l |= FLD_VAL(cycleformat, 10, 9);
911 l |= FLD_VAL(0, 12, 11); /* UNUSEDBITS */
912 l |= FLD_VAL(0, 16, 16); /* A0POLARITY */
913 l |= FLD_VAL(0, 17, 17); /* REPOLARITY */
914 l |= FLD_VAL(0, 18, 18); /* WEPOLARITY */
915 l |= FLD_VAL(0, 19, 19); /* CSPOLARITY */
916 l |= FLD_VAL(1, 20, 20); /* TE_VSYNC_POLARITY */
917 l |= FLD_VAL(1, 21, 21); /* HSYNCPOLARITY */
918 rfbi_write_reg(RFBI_CONFIG(rfbi_module), l);
919
920 rfbi_write_reg(RFBI_DATA_CYCLE1(rfbi_module), cycle1);
921 rfbi_write_reg(RFBI_DATA_CYCLE2(rfbi_module), cycle2);
922 rfbi_write_reg(RFBI_DATA_CYCLE3(rfbi_module), cycle3);
923
924
925 l = rfbi_read_reg(RFBI_CONTROL);
926 l = FLD_MOD(l, rfbi_module+1, 3, 2); /* Select CSx */
927 l = FLD_MOD(l, 0, 1, 1); /* clear bypass */
928 rfbi_write_reg(RFBI_CONTROL, l);
929
930
931 DSSDBG("RFBI config: bpp %d, lines %d, cycles: 0x%x 0x%x 0x%x\n",
932 bpp, lines, cycle1, cycle2, cycle3);
933
934 rfbi_enable_clocks(0);
935
936 return 0;
937}
938EXPORT_SYMBOL(rfbi_configure);
939
940static int rfbi_find_display(struct omap_dss_device *dssdev)
941{
942 if (dssdev == rfbi.dssdev[0])
943 return 0;
944
945 if (dssdev == rfbi.dssdev[1])
946 return 1;
947
948 BUG();
949 return -1;
950}
951
952
953static void signal_fifo_waiters(void)
954{
955 if (atomic_read(&rfbi.cmd_fifo_full) > 0) {
956 /* DSSDBG("SIGNALING: Fifo not full for waiter!\n"); */
957 complete(&rfbi.cmd_done);
958 atomic_dec(&rfbi.cmd_fifo_full);
959 }
960}
961
962/* returns 1 for async op, and 0 for sync op */
963static int do_update(struct omap_dss_device *dssdev, struct update_region *upd)
964{
965 u16 x = upd->x;
966 u16 y = upd->y;
967 u16 w = upd->w;
968 u16 h = upd->h;
969
970 perf_mark_setup();
971
972 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
973 /*dssdev->driver->enable_te(dssdev, 1); */
974 dss_setup_partial_planes(dssdev, &x, &y, &w, &h);
975 }
976
977#ifdef MEASURE_PERF
978 rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */
979#endif
980
981 dssdev->driver->setup_update(dssdev, x, y, w, h);
982
983 if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) {
984 rfbi_transfer_area(w, h, NULL, NULL);
985 return 1;
986 } else {
987 struct omap_overlay *ovl;
988 void __iomem *addr;
989 int scr_width;
990
991 ovl = dssdev->manager->overlays[0];
992 scr_width = ovl->info.screen_width;
993 addr = ovl->info.vaddr;
994
995 omap_rfbi_write_pixels(addr, scr_width, x, y, w, h);
996
997 perf_show("L4");
998
999 return 0;
1000 }
1001}
1002
1003static void process_cmd_fifo(void)
1004{
1005 int len;
1006 struct update_param p;
1007 struct omap_dss_device *dssdev;
1008 unsigned long flags;
1009
1010 if (atomic_inc_return(&rfbi.cmd_pending) != 1)
1011 return;
1012
1013 while (true) {
1014 spin_lock_irqsave(&rfbi.cmd_lock, flags);
1015
1016 len = kfifo_out(&rfbi.cmd_fifo, (unsigned char *)&p,
1017 sizeof(struct update_param));
1018 if (len == 0) {
1019 DSSDBG("nothing more in fifo\n");
1020 atomic_set(&rfbi.cmd_pending, 0);
1021 spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
1022 break;
1023 }
1024
1025 /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/
1026
1027 spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
1028
1029 BUG_ON(len != sizeof(struct update_param));
1030 BUG_ON(p.rfbi_module > 1);
1031
1032 dssdev = rfbi.dssdev[p.rfbi_module];
1033
1034 if (p.cmd == RFBI_CMD_UPDATE) {
1035 if (do_update(dssdev, &p.par.r))
1036 break; /* async op */
1037 } else if (p.cmd == RFBI_CMD_SYNC) {
1038 DSSDBG("Signaling SYNC done!\n");
1039 complete(p.par.sync);
1040 } else
1041 BUG();
1042 }
1043
1044 signal_fifo_waiters();
1045}
1046
1047static void rfbi_push_cmd(struct update_param *p)
1048{
1049 int ret;
1050
1051 while (1) {
1052 unsigned long flags;
1053 int available;
1054
1055 spin_lock_irqsave(&rfbi.cmd_lock, flags);
1056 available = RFBI_CMD_FIFO_LEN_BYTES -
1057 kfifo_len(&rfbi.cmd_fifo);
1058
1059/* DSSDBG("%d bytes left in fifo\n", available); */
1060 if (available < sizeof(struct update_param)) {
1061 DSSDBG("Going to wait because FIFO FULL..\n");
1062 spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
1063 atomic_inc(&rfbi.cmd_fifo_full);
1064 wait_for_completion(&rfbi.cmd_done);
1065 /*DSSDBG("Woke up because fifo not full anymore\n");*/
1066 continue;
1067 }
1068
1069 ret = kfifo_in(&rfbi.cmd_fifo, (unsigned char *)p,
1070 sizeof(struct update_param));
1071/* DSSDBG("pushed %d bytes\n", ret);*/
1072
1073 spin_unlock_irqrestore(&rfbi.cmd_lock, flags);
1074
1075 BUG_ON(ret != sizeof(struct update_param));
1076
1077 break;
1078 }
1079}
1080
1081static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h)
1082{
1083 struct update_param p;
1084
1085 p.rfbi_module = rfbi_module;
1086 p.cmd = RFBI_CMD_UPDATE;
1087
1088 p.par.r.x = x;
1089 p.par.r.y = y;
1090 p.par.r.w = w;
1091 p.par.r.h = h;
1092
1093 DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h);
1094
1095 rfbi_push_cmd(&p);
1096
1097 process_cmd_fifo();
1098}
1099
1100static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp)
1101{
1102 struct update_param p;
1103
1104 p.rfbi_module = rfbi_module;
1105 p.cmd = RFBI_CMD_SYNC;
1106 p.par.sync = sync_comp;
1107
1108 rfbi_push_cmd(&p);
1109
1110 DSSDBG("RFBI sync pushed to cmd fifo\n");
1111
1112 process_cmd_fifo();
1113}
1114
1115void rfbi_dump_regs(struct seq_file *s)
1116{
1117#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r))
1118
1119 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
1120
1121 DUMPREG(RFBI_REVISION);
1122 DUMPREG(RFBI_SYSCONFIG);
1123 DUMPREG(RFBI_SYSSTATUS);
1124 DUMPREG(RFBI_CONTROL);
1125 DUMPREG(RFBI_PIXEL_CNT);
1126 DUMPREG(RFBI_LINE_NUMBER);
1127 DUMPREG(RFBI_CMD);
1128 DUMPREG(RFBI_PARAM);
1129 DUMPREG(RFBI_DATA);
1130 DUMPREG(RFBI_READ);
1131 DUMPREG(RFBI_STATUS);
1132
1133 DUMPREG(RFBI_CONFIG(0));
1134 DUMPREG(RFBI_ONOFF_TIME(0));
1135 DUMPREG(RFBI_CYCLE_TIME(0));
1136 DUMPREG(RFBI_DATA_CYCLE1(0));
1137 DUMPREG(RFBI_DATA_CYCLE2(0));
1138 DUMPREG(RFBI_DATA_CYCLE3(0));
1139
1140 DUMPREG(RFBI_CONFIG(1));
1141 DUMPREG(RFBI_ONOFF_TIME(1));
1142 DUMPREG(RFBI_CYCLE_TIME(1));
1143 DUMPREG(RFBI_DATA_CYCLE1(1));
1144 DUMPREG(RFBI_DATA_CYCLE2(1));
1145 DUMPREG(RFBI_DATA_CYCLE3(1));
1146
1147 DUMPREG(RFBI_VSYNC_WIDTH);
1148 DUMPREG(RFBI_HSYNC_WIDTH);
1149
1150 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
1151#undef DUMPREG
1152}
1153
1154int rfbi_init(void)
1155{
1156 u32 rev;
1157 u32 l;
1158 int r;
1159
1160 spin_lock_init(&rfbi.cmd_lock);
1161 r = kfifo_alloc(&rfbi.cmd_fifo, RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL);
1162 if (r)
1163 return r;
1164
1165 init_completion(&rfbi.cmd_done);
1166 atomic_set(&rfbi.cmd_fifo_full, 0);
1167 atomic_set(&rfbi.cmd_pending, 0);
1168
1169 rfbi.base = ioremap(RFBI_BASE, SZ_256);
1170 if (!rfbi.base) {
1171 DSSERR("can't ioremap RFBI\n");
1172 return -ENOMEM;
1173 }
1174
1175 rfbi_enable_clocks(1);
1176
1177 msleep(10);
1178
1179 rfbi.l4_khz = dss_clk_get_rate(DSS_CLK_ICK) / 1000;
1180
1181 /* Enable autoidle and smart-idle */
1182 l = rfbi_read_reg(RFBI_SYSCONFIG);
1183 l |= (1 << 0) | (2 << 3);
1184 rfbi_write_reg(RFBI_SYSCONFIG, l);
1185
1186 rev = rfbi_read_reg(RFBI_REVISION);
1187 printk(KERN_INFO "OMAP RFBI rev %d.%d\n",
1188 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
1189
1190 rfbi_enable_clocks(0);
1191
1192 return 0;
1193}
1194
1195void rfbi_exit(void)
1196{
1197 DSSDBG("rfbi_exit\n");
1198
1199 kfifo_free(&rfbi.cmd_fifo);
1200
1201 iounmap(rfbi.base);
1202}
1203
1204/* struct omap_display support */
1205static int rfbi_display_update(struct omap_dss_device *dssdev,
1206 u16 x, u16 y, u16 w, u16 h)
1207{
1208 int rfbi_module;
1209
1210 if (w == 0 || h == 0)
1211 return 0;
1212
1213 rfbi_module = rfbi_find_display(dssdev);
1214
1215 rfbi_push_update(rfbi_module, x, y, w, h);
1216
1217 return 0;
1218}
1219
1220static int rfbi_display_sync(struct omap_dss_device *dssdev)
1221{
1222 struct completion sync_comp;
1223 int rfbi_module;
1224
1225 rfbi_module = rfbi_find_display(dssdev);
1226
1227 init_completion(&sync_comp);
1228 rfbi_push_sync(rfbi_module, &sync_comp);
1229 DSSDBG("Waiting for SYNC to happen...\n");
1230 wait_for_completion(&sync_comp);
1231 DSSDBG("Released from SYNC\n");
1232 return 0;
1233}
1234
1235static int rfbi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
1236{
1237 dssdev->driver->enable_te(dssdev, enable);
1238 return 0;
1239}
1240
1241static int rfbi_display_enable(struct omap_dss_device *dssdev)
1242{
1243 int r;
1244
1245 r = omap_dss_start_device(dssdev);
1246 if (r) {
1247 DSSERR("failed to start device\n");
1248 goto err0;
1249 }
1250
1251 r = omap_dispc_register_isr(framedone_callback, NULL,
1252 DISPC_IRQ_FRAMEDONE);
1253 if (r) {
1254 DSSERR("can't get FRAMEDONE irq\n");
1255 goto err1;
1256 }
1257
1258 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
1259
1260 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_RFBI);
1261
1262 dispc_set_tft_data_lines(dssdev->ctrl.pixel_size);
1263
1264 rfbi_configure(dssdev->phy.rfbi.channel,
1265 dssdev->ctrl.pixel_size,
1266 dssdev->phy.rfbi.data_lines);
1267
1268 rfbi_set_timings(dssdev->phy.rfbi.channel,
1269 &dssdev->ctrl.rfbi_timings);
1270
1271
1272 if (dssdev->driver->enable) {
1273 r = dssdev->driver->enable(dssdev);
1274 if (r)
1275 goto err2;
1276 }
1277
1278 return 0;
1279err2:
1280 omap_dispc_unregister_isr(framedone_callback, NULL,
1281 DISPC_IRQ_FRAMEDONE);
1282err1:
1283 omap_dss_stop_device(dssdev);
1284err0:
1285 return r;
1286}
1287
1288static void rfbi_display_disable(struct omap_dss_device *dssdev)
1289{
1290 dssdev->driver->disable(dssdev);
1291 omap_dispc_unregister_isr(framedone_callback, NULL,
1292 DISPC_IRQ_FRAMEDONE);
1293 omap_dss_stop_device(dssdev);
1294}
1295
1296int rfbi_init_display(struct omap_dss_device *dssdev)
1297{
1298 dssdev->enable = rfbi_display_enable;
1299 dssdev->disable = rfbi_display_disable;
1300 dssdev->update = rfbi_display_update;
1301 dssdev->sync = rfbi_display_sync;
1302 dssdev->enable_te = rfbi_display_enable_te;
1303
1304 rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
1305
1306 dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE;
1307
1308 return 0;
1309}
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c
new file mode 100644
index 000000000000..c24f307d3da1
--- /dev/null
+++ b/drivers/video/omap2/dss/sdi.c
@@ -0,0 +1,277 @@
1/*
2 * linux/drivers/video/omap2/dss/sdi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 2 as published by
9 * the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#define DSS_SUBSYS_NAME "SDI"
21
22#include <linux/kernel.h>
23#include <linux/clk.h>
24#include <linux/delay.h>
25#include <linux/err.h>
26
27#include <plat/display.h>
28#include "dss.h"
29
30static struct {
31 bool skip_init;
32 bool update_enabled;
33} sdi;
34
35static void sdi_basic_init(void)
36{
37 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS);
38
39 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT);
40 dispc_set_tft_data_lines(24);
41 dispc_lcd_enable_signal_polarity(1);
42}
43
44static int sdi_display_enable(struct omap_dss_device *dssdev)
45{
46 struct omap_video_timings *t = &dssdev->panel.timings;
47 struct dss_clock_info dss_cinfo;
48 struct dispc_clock_info dispc_cinfo;
49 u16 lck_div, pck_div;
50 unsigned long fck;
51 unsigned long pck;
52 int r;
53
54 r = omap_dss_start_device(dssdev);
55 if (r) {
56 DSSERR("failed to start device\n");
57 goto err0;
58 }
59
60 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
61 DSSERR("dssdev already enabled\n");
62 r = -EINVAL;
63 goto err1;
64 }
65
66 /* In case of skip_init sdi_init has already enabled the clocks */
67 if (!sdi.skip_init)
68 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
69
70 sdi_basic_init();
71
72 /* 15.5.9.1.2 */
73 dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF;
74
75 dispc_set_pol_freq(dssdev->panel.config, dssdev->panel.acbi,
76 dssdev->panel.acb);
77
78 if (!sdi.skip_init) {
79 r = dss_calc_clock_div(1, t->pixel_clock * 1000,
80 &dss_cinfo, &dispc_cinfo);
81 } else {
82 r = dss_get_clock_div(&dss_cinfo);
83 r = dispc_get_clock_div(&dispc_cinfo);
84 }
85
86 if (r)
87 goto err2;
88
89 fck = dss_cinfo.fck;
90 lck_div = dispc_cinfo.lck_div;
91 pck_div = dispc_cinfo.pck_div;
92
93 pck = fck / lck_div / pck_div / 1000;
94
95 if (pck != t->pixel_clock) {
96 DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
97 "got %lu kHz\n",
98 t->pixel_clock, pck);
99
100 t->pixel_clock = pck;
101 }
102
103
104 dispc_set_lcd_timings(t);
105
106 r = dss_set_clock_div(&dss_cinfo);
107 if (r)
108 goto err2;
109
110 r = dispc_set_clock_div(&dispc_cinfo);
111 if (r)
112 goto err2;
113
114 if (!sdi.skip_init) {
115 dss_sdi_init(dssdev->phy.sdi.datapairs);
116 r = dss_sdi_enable();
117 if (r)
118 goto err1;
119 mdelay(2);
120 }
121
122 dispc_enable_lcd_out(1);
123
124 if (dssdev->driver->enable) {
125 r = dssdev->driver->enable(dssdev);
126 if (r)
127 goto err3;
128 }
129
130 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
131
132 sdi.skip_init = 0;
133
134 return 0;
135err3:
136 dispc_enable_lcd_out(0);
137err2:
138 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
139err1:
140 omap_dss_stop_device(dssdev);
141err0:
142 return r;
143}
144
145static int sdi_display_resume(struct omap_dss_device *dssdev);
146
147static void sdi_display_disable(struct omap_dss_device *dssdev)
148{
149 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
150 return;
151
152 if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED)
153 if (sdi_display_resume(dssdev))
154 return;
155
156 if (dssdev->driver->disable)
157 dssdev->driver->disable(dssdev);
158
159 dispc_enable_lcd_out(0);
160
161 dss_sdi_disable();
162
163 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
164
165 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
166
167 omap_dss_stop_device(dssdev);
168}
169
170static int sdi_display_suspend(struct omap_dss_device *dssdev)
171{
172 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
173 return -EINVAL;
174
175 if (dssdev->driver->suspend)
176 dssdev->driver->suspend(dssdev);
177
178 dispc_enable_lcd_out(0);
179
180 dss_sdi_disable();
181
182 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
183
184 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
185
186 return 0;
187}
188
189static int sdi_display_resume(struct omap_dss_device *dssdev)
190{
191 int r;
192
193 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
194 return -EINVAL;
195
196 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
197
198 r = dss_sdi_enable();
199 if (r)
200 goto err;
201 mdelay(2);
202
203 dispc_enable_lcd_out(1);
204
205 if (dssdev->driver->resume)
206 dssdev->driver->resume(dssdev);
207
208 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
209
210 return 0;
211err:
212 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
213 return r;
214}
215
216static int sdi_display_set_update_mode(struct omap_dss_device *dssdev,
217 enum omap_dss_update_mode mode)
218{
219 if (mode == OMAP_DSS_UPDATE_MANUAL)
220 return -EINVAL;
221
222 if (mode == OMAP_DSS_UPDATE_DISABLED) {
223 dispc_enable_lcd_out(0);
224 sdi.update_enabled = 0;
225 } else {
226 dispc_enable_lcd_out(1);
227 sdi.update_enabled = 1;
228 }
229
230 return 0;
231}
232
233static enum omap_dss_update_mode sdi_display_get_update_mode(
234 struct omap_dss_device *dssdev)
235{
236 return sdi.update_enabled ? OMAP_DSS_UPDATE_AUTO :
237 OMAP_DSS_UPDATE_DISABLED;
238}
239
240static void sdi_get_timings(struct omap_dss_device *dssdev,
241 struct omap_video_timings *timings)
242{
243 *timings = dssdev->panel.timings;
244}
245
246int sdi_init_display(struct omap_dss_device *dssdev)
247{
248 DSSDBG("SDI init\n");
249
250 dssdev->enable = sdi_display_enable;
251 dssdev->disable = sdi_display_disable;
252 dssdev->suspend = sdi_display_suspend;
253 dssdev->resume = sdi_display_resume;
254 dssdev->set_update_mode = sdi_display_set_update_mode;
255 dssdev->get_update_mode = sdi_display_get_update_mode;
256 dssdev->get_timings = sdi_get_timings;
257
258 return 0;
259}
260
261int sdi_init(bool skip_init)
262{
263 /* we store this for first display enable, then clear it */
264 sdi.skip_init = skip_init;
265
266 /*
267 * Enable clocks already here, otherwise there would be a toggle
268 * of them until sdi_display_enable is called.
269 */
270 if (skip_init)
271 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
272 return 0;
273}
274
275void sdi_exit(void)
276{
277}
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c
new file mode 100644
index 000000000000..749a5a0f5be4
--- /dev/null
+++ b/drivers/video/omap2/dss/venc.c
@@ -0,0 +1,797 @@
1/*
2 * linux/drivers/video/omap2/dss/venc.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * VENC settings from TI's DSS driver
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#define DSS_SUBSYS_NAME "VENC"
23
24#include <linux/kernel.h>
25#include <linux/module.h>
26#include <linux/clk.h>
27#include <linux/err.h>
28#include <linux/io.h>
29#include <linux/mutex.h>
30#include <linux/completion.h>
31#include <linux/delay.h>
32#include <linux/string.h>
33#include <linux/seq_file.h>
34#include <linux/platform_device.h>
35#include <linux/regulator/consumer.h>
36
37#include <plat/display.h>
38#include <plat/cpu.h>
39
40#include "dss.h"
41
42#define VENC_BASE 0x48050C00
43
44/* Venc registers */
45#define VENC_REV_ID 0x00
46#define VENC_STATUS 0x04
47#define VENC_F_CONTROL 0x08
48#define VENC_VIDOUT_CTRL 0x10
49#define VENC_SYNC_CTRL 0x14
50#define VENC_LLEN 0x1C
51#define VENC_FLENS 0x20
52#define VENC_HFLTR_CTRL 0x24
53#define VENC_CC_CARR_WSS_CARR 0x28
54#define VENC_C_PHASE 0x2C
55#define VENC_GAIN_U 0x30
56#define VENC_GAIN_V 0x34
57#define VENC_GAIN_Y 0x38
58#define VENC_BLACK_LEVEL 0x3C
59#define VENC_BLANK_LEVEL 0x40
60#define VENC_X_COLOR 0x44
61#define VENC_M_CONTROL 0x48
62#define VENC_BSTAMP_WSS_DATA 0x4C
63#define VENC_S_CARR 0x50
64#define VENC_LINE21 0x54
65#define VENC_LN_SEL 0x58
66#define VENC_L21__WC_CTL 0x5C
67#define VENC_HTRIGGER_VTRIGGER 0x60
68#define VENC_SAVID__EAVID 0x64
69#define VENC_FLEN__FAL 0x68
70#define VENC_LAL__PHASE_RESET 0x6C
71#define VENC_HS_INT_START_STOP_X 0x70
72#define VENC_HS_EXT_START_STOP_X 0x74
73#define VENC_VS_INT_START_X 0x78
74#define VENC_VS_INT_STOP_X__VS_INT_START_Y 0x7C
75#define VENC_VS_INT_STOP_Y__VS_EXT_START_X 0x80
76#define VENC_VS_EXT_STOP_X__VS_EXT_START_Y 0x84
77#define VENC_VS_EXT_STOP_Y 0x88
78#define VENC_AVID_START_STOP_X 0x90
79#define VENC_AVID_START_STOP_Y 0x94
80#define VENC_FID_INT_START_X__FID_INT_START_Y 0xA0
81#define VENC_FID_INT_OFFSET_Y__FID_EXT_START_X 0xA4
82#define VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y 0xA8
83#define VENC_TVDETGP_INT_START_STOP_X 0xB0
84#define VENC_TVDETGP_INT_START_STOP_Y 0xB4
85#define VENC_GEN_CTRL 0xB8
86#define VENC_OUTPUT_CONTROL 0xC4
87#define VENC_OUTPUT_TEST 0xC8
88#define VENC_DAC_B__DAC_C 0xC8
89
90struct venc_config {
91 u32 f_control;
92 u32 vidout_ctrl;
93 u32 sync_ctrl;
94 u32 llen;
95 u32 flens;
96 u32 hfltr_ctrl;
97 u32 cc_carr_wss_carr;
98 u32 c_phase;
99 u32 gain_u;
100 u32 gain_v;
101 u32 gain_y;
102 u32 black_level;
103 u32 blank_level;
104 u32 x_color;
105 u32 m_control;
106 u32 bstamp_wss_data;
107 u32 s_carr;
108 u32 line21;
109 u32 ln_sel;
110 u32 l21__wc_ctl;
111 u32 htrigger_vtrigger;
112 u32 savid__eavid;
113 u32 flen__fal;
114 u32 lal__phase_reset;
115 u32 hs_int_start_stop_x;
116 u32 hs_ext_start_stop_x;
117 u32 vs_int_start_x;
118 u32 vs_int_stop_x__vs_int_start_y;
119 u32 vs_int_stop_y__vs_ext_start_x;
120 u32 vs_ext_stop_x__vs_ext_start_y;
121 u32 vs_ext_stop_y;
122 u32 avid_start_stop_x;
123 u32 avid_start_stop_y;
124 u32 fid_int_start_x__fid_int_start_y;
125 u32 fid_int_offset_y__fid_ext_start_x;
126 u32 fid_ext_start_y__fid_ext_offset_y;
127 u32 tvdetgp_int_start_stop_x;
128 u32 tvdetgp_int_start_stop_y;
129 u32 gen_ctrl;
130};
131
132/* from TRM */
133static const struct venc_config venc_config_pal_trm = {
134 .f_control = 0,
135 .vidout_ctrl = 1,
136 .sync_ctrl = 0x40,
137 .llen = 0x35F, /* 863 */
138 .flens = 0x270, /* 624 */
139 .hfltr_ctrl = 0,
140 .cc_carr_wss_carr = 0x2F7225ED,
141 .c_phase = 0,
142 .gain_u = 0x111,
143 .gain_v = 0x181,
144 .gain_y = 0x140,
145 .black_level = 0x3B,
146 .blank_level = 0x3B,
147 .x_color = 0x7,
148 .m_control = 0x2,
149 .bstamp_wss_data = 0x3F,
150 .s_carr = 0x2A098ACB,
151 .line21 = 0,
152 .ln_sel = 0x01290015,
153 .l21__wc_ctl = 0x0000F603,
154 .htrigger_vtrigger = 0,
155
156 .savid__eavid = 0x06A70108,
157 .flen__fal = 0x00180270,
158 .lal__phase_reset = 0x00040135,
159 .hs_int_start_stop_x = 0x00880358,
160 .hs_ext_start_stop_x = 0x000F035F,
161 .vs_int_start_x = 0x01A70000,
162 .vs_int_stop_x__vs_int_start_y = 0x000001A7,
163 .vs_int_stop_y__vs_ext_start_x = 0x01AF0000,
164 .vs_ext_stop_x__vs_ext_start_y = 0x000101AF,
165 .vs_ext_stop_y = 0x00000025,
166 .avid_start_stop_x = 0x03530083,
167 .avid_start_stop_y = 0x026C002E,
168 .fid_int_start_x__fid_int_start_y = 0x0001008A,
169 .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
170 .fid_ext_start_y__fid_ext_offset_y = 0x01380001,
171
172 .tvdetgp_int_start_stop_x = 0x00140001,
173 .tvdetgp_int_start_stop_y = 0x00010001,
174 .gen_ctrl = 0x00FF0000,
175};
176
177/* from TRM */
178static const struct venc_config venc_config_ntsc_trm = {
179 .f_control = 0,
180 .vidout_ctrl = 1,
181 .sync_ctrl = 0x8040,
182 .llen = 0x359,
183 .flens = 0x20C,
184 .hfltr_ctrl = 0,
185 .cc_carr_wss_carr = 0x043F2631,
186 .c_phase = 0,
187 .gain_u = 0x102,
188 .gain_v = 0x16C,
189 .gain_y = 0x12F,
190 .black_level = 0x43,
191 .blank_level = 0x38,
192 .x_color = 0x7,
193 .m_control = 0x1,
194 .bstamp_wss_data = 0x38,
195 .s_carr = 0x21F07C1F,
196 .line21 = 0,
197 .ln_sel = 0x01310011,
198 .l21__wc_ctl = 0x0000F003,
199 .htrigger_vtrigger = 0,
200
201 .savid__eavid = 0x069300F4,
202 .flen__fal = 0x0016020C,
203 .lal__phase_reset = 0x00060107,
204 .hs_int_start_stop_x = 0x008E0350,
205 .hs_ext_start_stop_x = 0x000F0359,
206 .vs_int_start_x = 0x01A00000,
207 .vs_int_stop_x__vs_int_start_y = 0x020701A0,
208 .vs_int_stop_y__vs_ext_start_x = 0x01AC0024,
209 .vs_ext_stop_x__vs_ext_start_y = 0x020D01AC,
210 .vs_ext_stop_y = 0x00000006,
211 .avid_start_stop_x = 0x03480078,
212 .avid_start_stop_y = 0x02060024,
213 .fid_int_start_x__fid_int_start_y = 0x0001008A,
214 .fid_int_offset_y__fid_ext_start_x = 0x01AC0106,
215 .fid_ext_start_y__fid_ext_offset_y = 0x01060006,
216
217 .tvdetgp_int_start_stop_x = 0x00140001,
218 .tvdetgp_int_start_stop_y = 0x00010001,
219 .gen_ctrl = 0x00F90000,
220};
221
222static const struct venc_config venc_config_pal_bdghi = {
223 .f_control = 0,
224 .vidout_ctrl = 0,
225 .sync_ctrl = 0,
226 .hfltr_ctrl = 0,
227 .x_color = 0,
228 .line21 = 0,
229 .ln_sel = 21,
230 .htrigger_vtrigger = 0,
231 .tvdetgp_int_start_stop_x = 0x00140001,
232 .tvdetgp_int_start_stop_y = 0x00010001,
233 .gen_ctrl = 0x00FB0000,
234
235 .llen = 864-1,
236 .flens = 625-1,
237 .cc_carr_wss_carr = 0x2F7625ED,
238 .c_phase = 0xDF,
239 .gain_u = 0x111,
240 .gain_v = 0x181,
241 .gain_y = 0x140,
242 .black_level = 0x3e,
243 .blank_level = 0x3e,
244 .m_control = 0<<2 | 1<<1,
245 .bstamp_wss_data = 0x42,
246 .s_carr = 0x2a098acb,
247 .l21__wc_ctl = 0<<13 | 0x16<<8 | 0<<0,
248 .savid__eavid = 0x06A70108,
249 .flen__fal = 23<<16 | 624<<0,
250 .lal__phase_reset = 2<<17 | 310<<0,
251 .hs_int_start_stop_x = 0x00920358,
252 .hs_ext_start_stop_x = 0x000F035F,
253 .vs_int_start_x = 0x1a7<<16,
254 .vs_int_stop_x__vs_int_start_y = 0x000601A7,
255 .vs_int_stop_y__vs_ext_start_x = 0x01AF0036,
256 .vs_ext_stop_x__vs_ext_start_y = 0x27101af,
257 .vs_ext_stop_y = 0x05,
258 .avid_start_stop_x = 0x03530082,
259 .avid_start_stop_y = 0x0270002E,
260 .fid_int_start_x__fid_int_start_y = 0x0005008A,
261 .fid_int_offset_y__fid_ext_start_x = 0x002E0138,
262 .fid_ext_start_y__fid_ext_offset_y = 0x01380005,
263};
264
265const struct omap_video_timings omap_dss_pal_timings = {
266 .x_res = 720,
267 .y_res = 574,
268 .pixel_clock = 13500,
269 .hsw = 64,
270 .hfp = 12,
271 .hbp = 68,
272 .vsw = 5,
273 .vfp = 5,
274 .vbp = 41,
275};
276EXPORT_SYMBOL(omap_dss_pal_timings);
277
278const struct omap_video_timings omap_dss_ntsc_timings = {
279 .x_res = 720,
280 .y_res = 482,
281 .pixel_clock = 13500,
282 .hsw = 64,
283 .hfp = 16,
284 .hbp = 58,
285 .vsw = 6,
286 .vfp = 6,
287 .vbp = 31,
288};
289EXPORT_SYMBOL(omap_dss_ntsc_timings);
290
291static struct {
292 void __iomem *base;
293 struct mutex venc_lock;
294 u32 wss_data;
295 struct regulator *vdda_dac_reg;
296} venc;
297
298static inline void venc_write_reg(int idx, u32 val)
299{
300 __raw_writel(val, venc.base + idx);
301}
302
303static inline u32 venc_read_reg(int idx)
304{
305 u32 l = __raw_readl(venc.base + idx);
306 return l;
307}
308
309static void venc_write_config(const struct venc_config *config)
310{
311 DSSDBG("write venc conf\n");
312
313 venc_write_reg(VENC_LLEN, config->llen);
314 venc_write_reg(VENC_FLENS, config->flens);
315 venc_write_reg(VENC_CC_CARR_WSS_CARR, config->cc_carr_wss_carr);
316 venc_write_reg(VENC_C_PHASE, config->c_phase);
317 venc_write_reg(VENC_GAIN_U, config->gain_u);
318 venc_write_reg(VENC_GAIN_V, config->gain_v);
319 venc_write_reg(VENC_GAIN_Y, config->gain_y);
320 venc_write_reg(VENC_BLACK_LEVEL, config->black_level);
321 venc_write_reg(VENC_BLANK_LEVEL, config->blank_level);
322 venc_write_reg(VENC_M_CONTROL, config->m_control);
323 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
324 venc.wss_data);
325 venc_write_reg(VENC_S_CARR, config->s_carr);
326 venc_write_reg(VENC_L21__WC_CTL, config->l21__wc_ctl);
327 venc_write_reg(VENC_SAVID__EAVID, config->savid__eavid);
328 venc_write_reg(VENC_FLEN__FAL, config->flen__fal);
329 venc_write_reg(VENC_LAL__PHASE_RESET, config->lal__phase_reset);
330 venc_write_reg(VENC_HS_INT_START_STOP_X, config->hs_int_start_stop_x);
331 venc_write_reg(VENC_HS_EXT_START_STOP_X, config->hs_ext_start_stop_x);
332 venc_write_reg(VENC_VS_INT_START_X, config->vs_int_start_x);
333 venc_write_reg(VENC_VS_INT_STOP_X__VS_INT_START_Y,
334 config->vs_int_stop_x__vs_int_start_y);
335 venc_write_reg(VENC_VS_INT_STOP_Y__VS_EXT_START_X,
336 config->vs_int_stop_y__vs_ext_start_x);
337 venc_write_reg(VENC_VS_EXT_STOP_X__VS_EXT_START_Y,
338 config->vs_ext_stop_x__vs_ext_start_y);
339 venc_write_reg(VENC_VS_EXT_STOP_Y, config->vs_ext_stop_y);
340 venc_write_reg(VENC_AVID_START_STOP_X, config->avid_start_stop_x);
341 venc_write_reg(VENC_AVID_START_STOP_Y, config->avid_start_stop_y);
342 venc_write_reg(VENC_FID_INT_START_X__FID_INT_START_Y,
343 config->fid_int_start_x__fid_int_start_y);
344 venc_write_reg(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X,
345 config->fid_int_offset_y__fid_ext_start_x);
346 venc_write_reg(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y,
347 config->fid_ext_start_y__fid_ext_offset_y);
348
349 venc_write_reg(VENC_DAC_B__DAC_C, venc_read_reg(VENC_DAC_B__DAC_C));
350 venc_write_reg(VENC_VIDOUT_CTRL, config->vidout_ctrl);
351 venc_write_reg(VENC_HFLTR_CTRL, config->hfltr_ctrl);
352 venc_write_reg(VENC_X_COLOR, config->x_color);
353 venc_write_reg(VENC_LINE21, config->line21);
354 venc_write_reg(VENC_LN_SEL, config->ln_sel);
355 venc_write_reg(VENC_HTRIGGER_VTRIGGER, config->htrigger_vtrigger);
356 venc_write_reg(VENC_TVDETGP_INT_START_STOP_X,
357 config->tvdetgp_int_start_stop_x);
358 venc_write_reg(VENC_TVDETGP_INT_START_STOP_Y,
359 config->tvdetgp_int_start_stop_y);
360 venc_write_reg(VENC_GEN_CTRL, config->gen_ctrl);
361 venc_write_reg(VENC_F_CONTROL, config->f_control);
362 venc_write_reg(VENC_SYNC_CTRL, config->sync_ctrl);
363}
364
365static void venc_reset(void)
366{
367 int t = 1000;
368
369 venc_write_reg(VENC_F_CONTROL, 1<<8);
370 while (venc_read_reg(VENC_F_CONTROL) & (1<<8)) {
371 if (--t == 0) {
372 DSSERR("Failed to reset venc\n");
373 return;
374 }
375 }
376
377 /* the magical sleep that makes things work */
378 msleep(20);
379}
380
381static void venc_enable_clocks(int enable)
382{
383 if (enable)
384 dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
385 DSS_CLK_96M);
386 else
387 dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1 | DSS_CLK_54M |
388 DSS_CLK_96M);
389}
390
391static const struct venc_config *venc_timings_to_config(
392 struct omap_video_timings *timings)
393{
394 if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
395 return &venc_config_pal_trm;
396
397 if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
398 return &venc_config_ntsc_trm;
399
400 BUG();
401}
402
403
404
405
406
407/* driver */
408static int venc_panel_probe(struct omap_dss_device *dssdev)
409{
410 dssdev->panel.timings = omap_dss_pal_timings;
411
412 return 0;
413}
414
415static void venc_panel_remove(struct omap_dss_device *dssdev)
416{
417}
418
419static int venc_panel_enable(struct omap_dss_device *dssdev)
420{
421 int r = 0;
422
423 /* wait couple of vsyncs until enabling the LCD */
424 msleep(50);
425
426 if (dssdev->platform_enable)
427 r = dssdev->platform_enable(dssdev);
428
429 return r;
430}
431
432static void venc_panel_disable(struct omap_dss_device *dssdev)
433{
434 if (dssdev->platform_disable)
435 dssdev->platform_disable(dssdev);
436
437 /* wait at least 5 vsyncs after disabling the LCD */
438
439 msleep(100);
440}
441
442static int venc_panel_suspend(struct omap_dss_device *dssdev)
443{
444 venc_panel_disable(dssdev);
445 return 0;
446}
447
448static int venc_panel_resume(struct omap_dss_device *dssdev)
449{
450 return venc_panel_enable(dssdev);
451}
452
453static struct omap_dss_driver venc_driver = {
454 .probe = venc_panel_probe,
455 .remove = venc_panel_remove,
456
457 .enable = venc_panel_enable,
458 .disable = venc_panel_disable,
459 .suspend = venc_panel_suspend,
460 .resume = venc_panel_resume,
461
462 .driver = {
463 .name = "venc",
464 .owner = THIS_MODULE,
465 },
466};
467/* driver end */
468
469
470
471int venc_init(struct platform_device *pdev)
472{
473 u8 rev_id;
474
475 mutex_init(&venc.venc_lock);
476
477 venc.wss_data = 0;
478
479 venc.base = ioremap(VENC_BASE, SZ_1K);
480 if (!venc.base) {
481 DSSERR("can't ioremap VENC\n");
482 return -ENOMEM;
483 }
484
485 venc.vdda_dac_reg = regulator_get(&pdev->dev, "vdda_dac");
486 if (IS_ERR(venc.vdda_dac_reg)) {
487 iounmap(venc.base);
488 DSSERR("can't get VDDA_DAC regulator\n");
489 return PTR_ERR(venc.vdda_dac_reg);
490 }
491
492 venc_enable_clocks(1);
493
494 rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff);
495 printk(KERN_INFO "OMAP VENC rev %d\n", rev_id);
496
497 venc_enable_clocks(0);
498
499 return omap_dss_register_driver(&venc_driver);
500}
501
502void venc_exit(void)
503{
504 omap_dss_unregister_driver(&venc_driver);
505
506 regulator_put(venc.vdda_dac_reg);
507
508 iounmap(venc.base);
509}
510
511static void venc_power_on(struct omap_dss_device *dssdev)
512{
513 u32 l;
514
515 venc_enable_clocks(1);
516
517 venc_reset();
518 venc_write_config(venc_timings_to_config(&dssdev->panel.timings));
519
520 dss_set_venc_output(dssdev->phy.venc.type);
521 dss_set_dac_pwrdn_bgz(1);
522
523 l = 0;
524
525 if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE)
526 l |= 1 << 1;
527 else /* S-Video */
528 l |= (1 << 0) | (1 << 2);
529
530 if (dssdev->phy.venc.invert_polarity == false)
531 l |= 1 << 3;
532
533 venc_write_reg(VENC_OUTPUT_CONTROL, l);
534
535 dispc_set_digit_size(dssdev->panel.timings.x_res,
536 dssdev->panel.timings.y_res/2);
537
538 regulator_enable(venc.vdda_dac_reg);
539
540 if (dssdev->platform_enable)
541 dssdev->platform_enable(dssdev);
542
543 dispc_enable_digit_out(1);
544}
545
546static void venc_power_off(struct omap_dss_device *dssdev)
547{
548 venc_write_reg(VENC_OUTPUT_CONTROL, 0);
549 dss_set_dac_pwrdn_bgz(0);
550
551 dispc_enable_digit_out(0);
552
553 if (dssdev->platform_disable)
554 dssdev->platform_disable(dssdev);
555
556 regulator_disable(venc.vdda_dac_reg);
557
558 venc_enable_clocks(0);
559}
560
561static int venc_enable_display(struct omap_dss_device *dssdev)
562{
563 int r = 0;
564
565 DSSDBG("venc_enable_display\n");
566
567 mutex_lock(&venc.venc_lock);
568
569 if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
570 r = -EINVAL;
571 goto err;
572 }
573
574 venc_power_on(dssdev);
575
576 venc.wss_data = 0;
577
578 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
579err:
580 mutex_unlock(&venc.venc_lock);
581
582 return r;
583}
584
585static void venc_disable_display(struct omap_dss_device *dssdev)
586{
587 DSSDBG("venc_disable_display\n");
588
589 mutex_lock(&venc.venc_lock);
590
591 if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
592 goto end;
593
594 if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
595 /* suspended is the same as disabled with venc */
596 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
597 goto end;
598 }
599
600 venc_power_off(dssdev);
601
602 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
603end:
604 mutex_unlock(&venc.venc_lock);
605}
606
607static int venc_display_suspend(struct omap_dss_device *dssdev)
608{
609 int r = 0;
610
611 DSSDBG("venc_display_suspend\n");
612
613 mutex_lock(&venc.venc_lock);
614
615 if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
616 r = -EINVAL;
617 goto err;
618 }
619
620 venc_power_off(dssdev);
621
622 dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
623err:
624 mutex_unlock(&venc.venc_lock);
625
626 return r;
627}
628
629static int venc_display_resume(struct omap_dss_device *dssdev)
630{
631 int r = 0;
632
633 DSSDBG("venc_display_resume\n");
634
635 mutex_lock(&venc.venc_lock);
636
637 if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
638 r = -EINVAL;
639 goto err;
640 }
641
642 venc_power_on(dssdev);
643
644 dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
645err:
646 mutex_unlock(&venc.venc_lock);
647
648 return r;
649}
650
651static void venc_get_timings(struct omap_dss_device *dssdev,
652 struct omap_video_timings *timings)
653{
654 *timings = dssdev->panel.timings;
655}
656
657static void venc_set_timings(struct omap_dss_device *dssdev,
658 struct omap_video_timings *timings)
659{
660 DSSDBG("venc_set_timings\n");
661
662 /* Reset WSS data when the TV standard changes. */
663 if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings)))
664 venc.wss_data = 0;
665
666 dssdev->panel.timings = *timings;
667 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
668 /* turn the venc off and on to get new timings to use */
669 venc_disable_display(dssdev);
670 venc_enable_display(dssdev);
671 }
672}
673
674static int venc_check_timings(struct omap_dss_device *dssdev,
675 struct omap_video_timings *timings)
676{
677 DSSDBG("venc_check_timings\n");
678
679 if (memcmp(&omap_dss_pal_timings, timings, sizeof(*timings)) == 0)
680 return 0;
681
682 if (memcmp(&omap_dss_ntsc_timings, timings, sizeof(*timings)) == 0)
683 return 0;
684
685 return -EINVAL;
686}
687
688static u32 venc_get_wss(struct omap_dss_device *dssdev)
689{
690 /* Invert due to VENC_L21_WC_CTL:INV=1 */
691 return (venc.wss_data >> 8) ^ 0xfffff;
692}
693
694static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss)
695{
696 const struct venc_config *config;
697
698 DSSDBG("venc_set_wss\n");
699
700 mutex_lock(&venc.venc_lock);
701
702 config = venc_timings_to_config(&dssdev->panel.timings);
703
704 /* Invert due to VENC_L21_WC_CTL:INV=1 */
705 venc.wss_data = (wss ^ 0xfffff) << 8;
706
707 venc_enable_clocks(1);
708
709 venc_write_reg(VENC_BSTAMP_WSS_DATA, config->bstamp_wss_data |
710 venc.wss_data);
711
712 venc_enable_clocks(0);
713
714 mutex_unlock(&venc.venc_lock);
715
716 return 0;
717}
718
719static enum omap_dss_update_mode venc_display_get_update_mode(
720 struct omap_dss_device *dssdev)
721{
722 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
723 return OMAP_DSS_UPDATE_AUTO;
724 else
725 return OMAP_DSS_UPDATE_DISABLED;
726}
727
728int venc_init_display(struct omap_dss_device *dssdev)
729{
730 DSSDBG("init_display\n");
731
732 dssdev->enable = venc_enable_display;
733 dssdev->disable = venc_disable_display;
734 dssdev->suspend = venc_display_suspend;
735 dssdev->resume = venc_display_resume;
736 dssdev->get_timings = venc_get_timings;
737 dssdev->set_timings = venc_set_timings;
738 dssdev->check_timings = venc_check_timings;
739 dssdev->get_wss = venc_get_wss;
740 dssdev->set_wss = venc_set_wss;
741 dssdev->get_update_mode = venc_display_get_update_mode;
742
743 return 0;
744}
745
746void venc_dump_regs(struct seq_file *s)
747{
748#define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r))
749
750 venc_enable_clocks(1);
751
752 DUMPREG(VENC_F_CONTROL);
753 DUMPREG(VENC_VIDOUT_CTRL);
754 DUMPREG(VENC_SYNC_CTRL);
755 DUMPREG(VENC_LLEN);
756 DUMPREG(VENC_FLENS);
757 DUMPREG(VENC_HFLTR_CTRL);
758 DUMPREG(VENC_CC_CARR_WSS_CARR);
759 DUMPREG(VENC_C_PHASE);
760 DUMPREG(VENC_GAIN_U);
761 DUMPREG(VENC_GAIN_V);
762 DUMPREG(VENC_GAIN_Y);
763 DUMPREG(VENC_BLACK_LEVEL);
764 DUMPREG(VENC_BLANK_LEVEL);
765 DUMPREG(VENC_X_COLOR);
766 DUMPREG(VENC_M_CONTROL);
767 DUMPREG(VENC_BSTAMP_WSS_DATA);
768 DUMPREG(VENC_S_CARR);
769 DUMPREG(VENC_LINE21);
770 DUMPREG(VENC_LN_SEL);
771 DUMPREG(VENC_L21__WC_CTL);
772 DUMPREG(VENC_HTRIGGER_VTRIGGER);
773 DUMPREG(VENC_SAVID__EAVID);
774 DUMPREG(VENC_FLEN__FAL);
775 DUMPREG(VENC_LAL__PHASE_RESET);
776 DUMPREG(VENC_HS_INT_START_STOP_X);
777 DUMPREG(VENC_HS_EXT_START_STOP_X);
778 DUMPREG(VENC_VS_INT_START_X);
779 DUMPREG(VENC_VS_INT_STOP_X__VS_INT_START_Y);
780 DUMPREG(VENC_VS_INT_STOP_Y__VS_EXT_START_X);
781 DUMPREG(VENC_VS_EXT_STOP_X__VS_EXT_START_Y);
782 DUMPREG(VENC_VS_EXT_STOP_Y);
783 DUMPREG(VENC_AVID_START_STOP_X);
784 DUMPREG(VENC_AVID_START_STOP_Y);
785 DUMPREG(VENC_FID_INT_START_X__FID_INT_START_Y);
786 DUMPREG(VENC_FID_INT_OFFSET_Y__FID_EXT_START_X);
787 DUMPREG(VENC_FID_EXT_START_Y__FID_EXT_OFFSET_Y);
788 DUMPREG(VENC_TVDETGP_INT_START_STOP_X);
789 DUMPREG(VENC_TVDETGP_INT_START_STOP_Y);
790 DUMPREG(VENC_GEN_CTRL);
791 DUMPREG(VENC_OUTPUT_CONTROL);
792 DUMPREG(VENC_OUTPUT_TEST);
793
794 venc_enable_clocks(0);
795
796#undef DUMPREG
797}
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
new file mode 100644
index 000000000000..bb694cc52a50
--- /dev/null
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -0,0 +1,37 @@
1menuconfig FB_OMAP2
2 tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"
3 depends on FB && OMAP2_DSS
4
5 select OMAP2_VRAM
6 select OMAP2_VRFB
7 select FB_CFB_FILLRECT
8 select FB_CFB_COPYAREA
9 select FB_CFB_IMAGEBLIT
10 help
11 Frame buffer driver for OMAP2/3 based boards.
12
13config FB_OMAP2_DEBUG_SUPPORT
14 bool "Debug support for OMAP2/3 FB"
15 default y
16 depends on FB_OMAP2
17 help
18 Support for debug output. You have to enable the actual printing
19 with debug module parameter.
20
21config FB_OMAP2_FORCE_AUTO_UPDATE
22 bool "Force main display to automatic update mode"
23 depends on FB_OMAP2
24 help
25 Forces main display to automatic update mode (if possible),
26 and also enables tearsync (if possible). By default
27 displays that support manual update are started in manual
28 update mode.
29
30config FB_OMAP2_NUM_FBS
31 int "Number of framebuffers"
32 range 1 10
33 default 3
34 depends on FB_OMAP2
35 help
36 Select the number of framebuffers created. OMAP2/3 has 3 overlays
37 so normally this would be 3.
diff --git a/drivers/video/omap2/omapfb/Makefile b/drivers/video/omap2/omapfb/Makefile
new file mode 100644
index 000000000000..51c2e00d9bf8
--- /dev/null
+++ b/drivers/video/omap2/omapfb/Makefile
@@ -0,0 +1,2 @@
1obj-$(CONFIG_FB_OMAP2) += omapfb.o
2omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c
new file mode 100644
index 000000000000..4c4bafdfaa43
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c
@@ -0,0 +1,755 @@
1/*
2 * linux/drivers/video/omap2/omapfb-ioctl.c
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <linux/fb.h>
24#include <linux/device.h>
25#include <linux/uaccess.h>
26#include <linux/platform_device.h>
27#include <linux/mm.h>
28#include <linux/omapfb.h>
29#include <linux/vmalloc.h>
30
31#include <plat/display.h>
32#include <plat/vrfb.h>
33#include <plat/vram.h>
34
35#include "omapfb.h"
36
37static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
38{
39 struct omapfb_info *ofbi = FB2OFB(fbi);
40 struct omapfb2_device *fbdev = ofbi->fbdev;
41 struct omap_overlay *ovl;
42 struct omap_overlay_info info;
43 int r = 0;
44
45 DBG("omapfb_setup_plane\n");
46
47 if (ofbi->num_overlays != 1) {
48 r = -EINVAL;
49 goto out;
50 }
51
52 /* XXX uses only the first overlay */
53 ovl = ofbi->overlays[0];
54
55 if (pi->enabled && !ofbi->region.size) {
56 /*
57 * This plane's memory was freed, can't enable it
58 * until it's reallocated.
59 */
60 r = -EINVAL;
61 goto out;
62 }
63
64 ovl->get_overlay_info(ovl, &info);
65
66 info.pos_x = pi->pos_x;
67 info.pos_y = pi->pos_y;
68 info.out_width = pi->out_width;
69 info.out_height = pi->out_height;
70 info.enabled = pi->enabled;
71
72 r = ovl->set_overlay_info(ovl, &info);
73 if (r)
74 goto out;
75
76 if (ovl->manager) {
77 r = ovl->manager->apply(ovl->manager);
78 if (r)
79 goto out;
80 }
81
82out:
83 if (r)
84 dev_err(fbdev->dev, "setup_plane failed\n");
85 return r;
86}
87
88static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
89{
90 struct omapfb_info *ofbi = FB2OFB(fbi);
91
92 if (ofbi->num_overlays != 1) {
93 memset(pi, 0, sizeof(*pi));
94 } else {
95 struct omap_overlay_info *ovli;
96 struct omap_overlay *ovl;
97
98 ovl = ofbi->overlays[0];
99 ovli = &ovl->info;
100
101 pi->pos_x = ovli->pos_x;
102 pi->pos_y = ovli->pos_y;
103 pi->enabled = ovli->enabled;
104 pi->channel_out = 0; /* xxx */
105 pi->mirror = 0;
106 pi->out_width = ovli->out_width;
107 pi->out_height = ovli->out_height;
108 }
109
110 return 0;
111}
112
113static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
114{
115 struct omapfb_info *ofbi = FB2OFB(fbi);
116 struct omapfb2_device *fbdev = ofbi->fbdev;
117 struct omapfb2_mem_region *rg;
118 int r, i;
119 size_t size;
120
121 if (mi->type > OMAPFB_MEMTYPE_MAX)
122 return -EINVAL;
123
124 size = PAGE_ALIGN(mi->size);
125
126 rg = &ofbi->region;
127
128 for (i = 0; i < ofbi->num_overlays; i++) {
129 if (ofbi->overlays[i]->info.enabled)
130 return -EBUSY;
131 }
132
133 if (rg->size != size || rg->type != mi->type) {
134 r = omapfb_realloc_fbmem(fbi, size, mi->type);
135 if (r) {
136 dev_err(fbdev->dev, "realloc fbmem failed\n");
137 return r;
138 }
139 }
140
141 return 0;
142}
143
144static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
145{
146 struct omapfb_info *ofbi = FB2OFB(fbi);
147 struct omapfb2_mem_region *rg;
148
149 rg = &ofbi->region;
150 memset(mi, 0, sizeof(*mi));
151
152 mi->size = rg->size;
153 mi->type = rg->type;
154
155 return 0;
156}
157
158static int omapfb_update_window_nolock(struct fb_info *fbi,
159 u32 x, u32 y, u32 w, u32 h)
160{
161 struct omap_dss_device *display = fb2display(fbi);
162 u16 dw, dh;
163
164 if (!display)
165 return 0;
166
167 if (w == 0 || h == 0)
168 return 0;
169
170 display->get_resolution(display, &dw, &dh);
171
172 if (x + w > dw || y + h > dh)
173 return -EINVAL;
174
175 return display->update(display, x, y, w, h);
176}
177
178/* This function is exported for SGX driver use */
179int omapfb_update_window(struct fb_info *fbi,
180 u32 x, u32 y, u32 w, u32 h)
181{
182 struct omapfb_info *ofbi = FB2OFB(fbi);
183 struct omapfb2_device *fbdev = ofbi->fbdev;
184 int r;
185
186 omapfb_lock(fbdev);
187 lock_fb_info(fbi);
188
189 r = omapfb_update_window_nolock(fbi, x, y, w, h);
190
191 unlock_fb_info(fbi);
192 omapfb_unlock(fbdev);
193
194 return r;
195}
196EXPORT_SYMBOL(omapfb_update_window);
197
198static int omapfb_set_update_mode(struct fb_info *fbi,
199 enum omapfb_update_mode mode)
200{
201 struct omap_dss_device *display = fb2display(fbi);
202 enum omap_dss_update_mode um;
203 int r;
204
205 if (!display || !display->set_update_mode)
206 return -EINVAL;
207
208 switch (mode) {
209 case OMAPFB_UPDATE_DISABLED:
210 um = OMAP_DSS_UPDATE_DISABLED;
211 break;
212
213 case OMAPFB_AUTO_UPDATE:
214 um = OMAP_DSS_UPDATE_AUTO;
215 break;
216
217 case OMAPFB_MANUAL_UPDATE:
218 um = OMAP_DSS_UPDATE_MANUAL;
219 break;
220
221 default:
222 return -EINVAL;
223 }
224
225 r = display->set_update_mode(display, um);
226
227 return r;
228}
229
230static int omapfb_get_update_mode(struct fb_info *fbi,
231 enum omapfb_update_mode *mode)
232{
233 struct omap_dss_device *display = fb2display(fbi);
234 enum omap_dss_update_mode m;
235
236 if (!display || !display->get_update_mode)
237 return -EINVAL;
238
239 m = display->get_update_mode(display);
240
241 switch (m) {
242 case OMAP_DSS_UPDATE_DISABLED:
243 *mode = OMAPFB_UPDATE_DISABLED;
244 break;
245 case OMAP_DSS_UPDATE_AUTO:
246 *mode = OMAPFB_AUTO_UPDATE;
247 break;
248 case OMAP_DSS_UPDATE_MANUAL:
249 *mode = OMAPFB_MANUAL_UPDATE;
250 break;
251 default:
252 BUG();
253 }
254
255 return 0;
256}
257
258/* XXX this color key handling is a hack... */
259static struct omapfb_color_key omapfb_color_keys[2];
260
261static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
262 struct omapfb_color_key *ck)
263{
264 struct omap_overlay_manager_info info;
265 enum omap_dss_trans_key_type kt;
266 int r;
267
268 mgr->get_manager_info(mgr, &info);
269
270 if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
271 info.trans_enabled = false;
272 omapfb_color_keys[mgr->id] = *ck;
273
274 r = mgr->set_manager_info(mgr, &info);
275 if (r)
276 return r;
277
278 r = mgr->apply(mgr);
279
280 return r;
281 }
282
283 switch (ck->key_type) {
284 case OMAPFB_COLOR_KEY_GFX_DST:
285 kt = OMAP_DSS_COLOR_KEY_GFX_DST;
286 break;
287 case OMAPFB_COLOR_KEY_VID_SRC:
288 kt = OMAP_DSS_COLOR_KEY_VID_SRC;
289 break;
290 default:
291 return -EINVAL;
292 }
293
294 info.default_color = ck->background;
295 info.trans_key = ck->trans_key;
296 info.trans_key_type = kt;
297 info.trans_enabled = true;
298
299 omapfb_color_keys[mgr->id] = *ck;
300
301 r = mgr->set_manager_info(mgr, &info);
302 if (r)
303 return r;
304
305 r = mgr->apply(mgr);
306
307 return r;
308}
309
310static int omapfb_set_color_key(struct fb_info *fbi,
311 struct omapfb_color_key *ck)
312{
313 struct omapfb_info *ofbi = FB2OFB(fbi);
314 struct omapfb2_device *fbdev = ofbi->fbdev;
315 int r;
316 int i;
317 struct omap_overlay_manager *mgr = NULL;
318
319 omapfb_lock(fbdev);
320
321 for (i = 0; i < ofbi->num_overlays; i++) {
322 if (ofbi->overlays[i]->manager) {
323 mgr = ofbi->overlays[i]->manager;
324 break;
325 }
326 }
327
328 if (!mgr) {
329 r = -EINVAL;
330 goto err;
331 }
332
333 r = _omapfb_set_color_key(mgr, ck);
334err:
335 omapfb_unlock(fbdev);
336
337 return r;
338}
339
340static int omapfb_get_color_key(struct fb_info *fbi,
341 struct omapfb_color_key *ck)
342{
343 struct omapfb_info *ofbi = FB2OFB(fbi);
344 struct omapfb2_device *fbdev = ofbi->fbdev;
345 struct omap_overlay_manager *mgr = NULL;
346 int r = 0;
347 int i;
348
349 omapfb_lock(fbdev);
350
351 for (i = 0; i < ofbi->num_overlays; i++) {
352 if (ofbi->overlays[i]->manager) {
353 mgr = ofbi->overlays[i]->manager;
354 break;
355 }
356 }
357
358 if (!mgr) {
359 r = -EINVAL;
360 goto err;
361 }
362
363 *ck = omapfb_color_keys[mgr->id];
364err:
365 omapfb_unlock(fbdev);
366
367 return r;
368}
369
370static int omapfb_memory_read(struct fb_info *fbi,
371 struct omapfb_memory_read *mr)
372{
373 struct omap_dss_device *display = fb2display(fbi);
374 void *buf;
375 int r;
376
377 if (!display || !display->memory_read)
378 return -ENOENT;
379
380 if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))
381 return -EFAULT;
382
383 if (mr->w * mr->h * 3 > mr->buffer_size)
384 return -EINVAL;
385
386 buf = vmalloc(mr->buffer_size);
387 if (!buf) {
388 DBG("vmalloc failed\n");
389 return -ENOMEM;
390 }
391
392 r = display->memory_read(display, buf, mr->buffer_size,
393 mr->x, mr->y, mr->w, mr->h);
394
395 if (r > 0) {
396 if (copy_to_user(mr->buffer, buf, mr->buffer_size))
397 r = -EFAULT;
398 }
399
400 vfree(buf);
401
402 return r;
403}
404
405static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
406 struct omapfb_ovl_colormode *mode)
407{
408 int ovl_idx = mode->overlay_idx;
409 int mode_idx = mode->mode_idx;
410 struct omap_overlay *ovl;
411 enum omap_color_mode supported_modes;
412 struct fb_var_screeninfo var;
413 int i;
414
415 if (ovl_idx >= fbdev->num_overlays)
416 return -ENODEV;
417 ovl = fbdev->overlays[ovl_idx];
418 supported_modes = ovl->supported_modes;
419
420 mode_idx = mode->mode_idx;
421
422 for (i = 0; i < sizeof(supported_modes) * 8; i++) {
423 if (!(supported_modes & (1 << i)))
424 continue;
425 /*
426 * It's possible that the FB doesn't support a mode
427 * that is supported by the overlay, so call the
428 * following here.
429 */
430 if (dss_mode_to_fb_mode(1 << i, &var) < 0)
431 continue;
432
433 mode_idx--;
434 if (mode_idx < 0)
435 break;
436 }
437
438 if (i == sizeof(supported_modes) * 8)
439 return -ENOENT;
440
441 mode->bits_per_pixel = var.bits_per_pixel;
442 mode->nonstd = var.nonstd;
443 mode->red = var.red;
444 mode->green = var.green;
445 mode->blue = var.blue;
446 mode->transp = var.transp;
447
448 return 0;
449}
450
451static int omapfb_wait_for_go(struct fb_info *fbi)
452{
453 struct omapfb_info *ofbi = FB2OFB(fbi);
454 int r = 0;
455 int i;
456
457 for (i = 0; i < ofbi->num_overlays; ++i) {
458 struct omap_overlay *ovl = ofbi->overlays[i];
459 r = ovl->wait_for_go(ovl);
460 if (r)
461 break;
462 }
463
464 return r;
465}
466
467int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
468{
469 struct omapfb_info *ofbi = FB2OFB(fbi);
470 struct omapfb2_device *fbdev = ofbi->fbdev;
471 struct omap_dss_device *display = fb2display(fbi);
472
473 union {
474 struct omapfb_update_window_old uwnd_o;
475 struct omapfb_update_window uwnd;
476 struct omapfb_plane_info plane_info;
477 struct omapfb_caps caps;
478 struct omapfb_mem_info mem_info;
479 struct omapfb_color_key color_key;
480 struct omapfb_ovl_colormode ovl_colormode;
481 enum omapfb_update_mode update_mode;
482 int test_num;
483 struct omapfb_memory_read memory_read;
484 struct omapfb_vram_info vram_info;
485 struct omapfb_tearsync_info tearsync_info;
486 } p;
487
488 int r = 0;
489
490 switch (cmd) {
491 case OMAPFB_SYNC_GFX:
492 DBG("ioctl SYNC_GFX\n");
493 if (!display || !display->sync) {
494 /* DSS1 never returns an error here, so we neither */
495 /*r = -EINVAL;*/
496 break;
497 }
498
499 r = display->sync(display);
500 break;
501
502 case OMAPFB_UPDATE_WINDOW_OLD:
503 DBG("ioctl UPDATE_WINDOW_OLD\n");
504 if (!display || !display->update) {
505 r = -EINVAL;
506 break;
507 }
508
509 if (copy_from_user(&p.uwnd_o,
510 (void __user *)arg,
511 sizeof(p.uwnd_o))) {
512 r = -EFAULT;
513 break;
514 }
515
516 r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y,
517 p.uwnd_o.width, p.uwnd_o.height);
518 break;
519
520 case OMAPFB_UPDATE_WINDOW:
521 DBG("ioctl UPDATE_WINDOW\n");
522 if (!display || !display->update) {
523 r = -EINVAL;
524 break;
525 }
526
527 if (copy_from_user(&p.uwnd, (void __user *)arg,
528 sizeof(p.uwnd))) {
529 r = -EFAULT;
530 break;
531 }
532
533 r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y,
534 p.uwnd.width, p.uwnd.height);
535 break;
536
537 case OMAPFB_SETUP_PLANE:
538 DBG("ioctl SETUP_PLANE\n");
539 if (copy_from_user(&p.plane_info, (void __user *)arg,
540 sizeof(p.plane_info)))
541 r = -EFAULT;
542 else
543 r = omapfb_setup_plane(fbi, &p.plane_info);
544 break;
545
546 case OMAPFB_QUERY_PLANE:
547 DBG("ioctl QUERY_PLANE\n");
548 r = omapfb_query_plane(fbi, &p.plane_info);
549 if (r < 0)
550 break;
551 if (copy_to_user((void __user *)arg, &p.plane_info,
552 sizeof(p.plane_info)))
553 r = -EFAULT;
554 break;
555
556 case OMAPFB_SETUP_MEM:
557 DBG("ioctl SETUP_MEM\n");
558 if (copy_from_user(&p.mem_info, (void __user *)arg,
559 sizeof(p.mem_info)))
560 r = -EFAULT;
561 else
562 r = omapfb_setup_mem(fbi, &p.mem_info);
563 break;
564
565 case OMAPFB_QUERY_MEM:
566 DBG("ioctl QUERY_MEM\n");
567 r = omapfb_query_mem(fbi, &p.mem_info);
568 if (r < 0)
569 break;
570 if (copy_to_user((void __user *)arg, &p.mem_info,
571 sizeof(p.mem_info)))
572 r = -EFAULT;
573 break;
574
575 case OMAPFB_GET_CAPS:
576 DBG("ioctl GET_CAPS\n");
577 if (!display) {
578 r = -EINVAL;
579 break;
580 }
581
582 memset(&p.caps, 0, sizeof(p.caps));
583 if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
584 p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
585 if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
586 p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
587
588 if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
589 r = -EFAULT;
590 break;
591
592 case OMAPFB_GET_OVERLAY_COLORMODE:
593 DBG("ioctl GET_OVERLAY_COLORMODE\n");
594 if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
595 sizeof(p.ovl_colormode))) {
596 r = -EFAULT;
597 break;
598 }
599 r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
600 if (r < 0)
601 break;
602 if (copy_to_user((void __user *)arg, &p.ovl_colormode,
603 sizeof(p.ovl_colormode)))
604 r = -EFAULT;
605 break;
606
607 case OMAPFB_SET_UPDATE_MODE:
608 DBG("ioctl SET_UPDATE_MODE\n");
609 if (get_user(p.update_mode, (int __user *)arg))
610 r = -EFAULT;
611 else
612 r = omapfb_set_update_mode(fbi, p.update_mode);
613 break;
614
615 case OMAPFB_GET_UPDATE_MODE:
616 DBG("ioctl GET_UPDATE_MODE\n");
617 r = omapfb_get_update_mode(fbi, &p.update_mode);
618 if (r)
619 break;
620 if (put_user(p.update_mode,
621 (enum omapfb_update_mode __user *)arg))
622 r = -EFAULT;
623 break;
624
625 case OMAPFB_SET_COLOR_KEY:
626 DBG("ioctl SET_COLOR_KEY\n");
627 if (copy_from_user(&p.color_key, (void __user *)arg,
628 sizeof(p.color_key)))
629 r = -EFAULT;
630 else
631 r = omapfb_set_color_key(fbi, &p.color_key);
632 break;
633
634 case OMAPFB_GET_COLOR_KEY:
635 DBG("ioctl GET_COLOR_KEY\n");
636 r = omapfb_get_color_key(fbi, &p.color_key);
637 if (r)
638 break;
639 if (copy_to_user((void __user *)arg, &p.color_key,
640 sizeof(p.color_key)))
641 r = -EFAULT;
642 break;
643
644 case OMAPFB_WAITFORVSYNC:
645 DBG("ioctl WAITFORVSYNC\n");
646 if (!display) {
647 r = -EINVAL;
648 break;
649 }
650
651 r = display->wait_vsync(display);
652 break;
653
654 case OMAPFB_WAITFORGO:
655 DBG("ioctl WAITFORGO\n");
656 if (!display) {
657 r = -EINVAL;
658 break;
659 }
660
661 r = omapfb_wait_for_go(fbi);
662 break;
663
664 /* LCD and CTRL tests do the same thing for backward
665 * compatibility */
666 case OMAPFB_LCD_TEST:
667 DBG("ioctl LCD_TEST\n");
668 if (get_user(p.test_num, (int __user *)arg)) {
669 r = -EFAULT;
670 break;
671 }
672 if (!display || !display->run_test) {
673 r = -EINVAL;
674 break;
675 }
676
677 r = display->run_test(display, p.test_num);
678
679 break;
680
681 case OMAPFB_CTRL_TEST:
682 DBG("ioctl CTRL_TEST\n");
683 if (get_user(p.test_num, (int __user *)arg)) {
684 r = -EFAULT;
685 break;
686 }
687 if (!display || !display->run_test) {
688 r = -EINVAL;
689 break;
690 }
691
692 r = display->run_test(display, p.test_num);
693
694 break;
695
696 case OMAPFB_MEMORY_READ:
697 DBG("ioctl MEMORY_READ\n");
698
699 if (copy_from_user(&p.memory_read, (void __user *)arg,
700 sizeof(p.memory_read))) {
701 r = -EFAULT;
702 break;
703 }
704
705 r = omapfb_memory_read(fbi, &p.memory_read);
706
707 break;
708
709 case OMAPFB_GET_VRAM_INFO: {
710 unsigned long vram, free, largest;
711
712 DBG("ioctl GET_VRAM_INFO\n");
713
714 omap_vram_get_info(&vram, &free, &largest);
715 p.vram_info.total = vram;
716 p.vram_info.free = free;
717 p.vram_info.largest_free_block = largest;
718
719 if (copy_to_user((void __user *)arg, &p.vram_info,
720 sizeof(p.vram_info)))
721 r = -EFAULT;
722 break;
723 }
724
725 case OMAPFB_SET_TEARSYNC: {
726 DBG("ioctl SET_TEARSYNC\n");
727
728 if (copy_from_user(&p.tearsync_info, (void __user *)arg,
729 sizeof(p.tearsync_info))) {
730 r = -EFAULT;
731 break;
732 }
733
734 if (!display->enable_te) {
735 r = -ENODEV;
736 break;
737 }
738
739 r = display->enable_te(display, !!p.tearsync_info.enabled);
740
741 break;
742 }
743
744 default:
745 dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
746 r = -EINVAL;
747 }
748
749 if (r < 0)
750 DBG("ioctl failed: %d\n", r);
751
752 return r;
753}
754
755
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
new file mode 100644
index 000000000000..d17caef6915a
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -0,0 +1,2267 @@
1/*
2 * linux/drivers/video/omap2/omapfb-main.c
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <linux/module.h>
24#include <linux/delay.h>
25#include <linux/fb.h>
26#include <linux/dma-mapping.h>
27#include <linux/vmalloc.h>
28#include <linux/device.h>
29#include <linux/platform_device.h>
30#include <linux/omapfb.h>
31
32#include <plat/display.h>
33#include <plat/vram.h>
34#include <plat/vrfb.h>
35
36#include "omapfb.h"
37
38#define MODULE_NAME "omapfb"
39
40#define OMAPFB_PLANE_XRES_MIN 8
41#define OMAPFB_PLANE_YRES_MIN 8
42
43static char *def_mode;
44static char *def_vram;
45static int def_vrfb;
46static int def_rotate;
47static int def_mirror;
48
49#ifdef DEBUG
50unsigned int omapfb_debug;
51module_param_named(debug, omapfb_debug, bool, 0644);
52static unsigned int omapfb_test_pattern;
53module_param_named(test, omapfb_test_pattern, bool, 0644);
54#endif
55
56static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);
57
58#ifdef DEBUG
59static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)
60{
61 struct fb_var_screeninfo *var = &fbi->var;
62 struct fb_fix_screeninfo *fix = &fbi->fix;
63 void __iomem *addr = fbi->screen_base;
64 const unsigned bytespp = var->bits_per_pixel >> 3;
65 const unsigned line_len = fix->line_length / bytespp;
66
67 int r = (color >> 16) & 0xff;
68 int g = (color >> 8) & 0xff;
69 int b = (color >> 0) & 0xff;
70
71 if (var->bits_per_pixel == 16) {
72 u16 __iomem *p = (u16 __iomem *)addr;
73 p += y * line_len + x;
74
75 r = r * 32 / 256;
76 g = g * 64 / 256;
77 b = b * 32 / 256;
78
79 __raw_writew((r << 11) | (g << 5) | (b << 0), p);
80 } else if (var->bits_per_pixel == 24) {
81 u8 __iomem *p = (u8 __iomem *)addr;
82 p += (y * line_len + x) * 3;
83
84 __raw_writeb(b, p + 0);
85 __raw_writeb(g, p + 1);
86 __raw_writeb(r, p + 2);
87 } else if (var->bits_per_pixel == 32) {
88 u32 __iomem *p = (u32 __iomem *)addr;
89 p += y * line_len + x;
90 __raw_writel(color, p);
91 }
92}
93
94static void fill_fb(struct fb_info *fbi)
95{
96 struct fb_var_screeninfo *var = &fbi->var;
97 const short w = var->xres_virtual;
98 const short h = var->yres_virtual;
99 void __iomem *addr = fbi->screen_base;
100 int y, x;
101
102 if (!addr)
103 return;
104
105 DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);
106
107 for (y = 0; y < h; y++) {
108 for (x = 0; x < w; x++) {
109 if (x < 20 && y < 20)
110 draw_pixel(fbi, x, y, 0xffffff);
111 else if (x < 20 && (y > 20 && y < h - 20))
112 draw_pixel(fbi, x, y, 0xff);
113 else if (y < 20 && (x > 20 && x < w - 20))
114 draw_pixel(fbi, x, y, 0xff00);
115 else if (x > w - 20 && (y > 20 && y < h - 20))
116 draw_pixel(fbi, x, y, 0xff0000);
117 else if (y > h - 20 && (x > 20 && x < w - 20))
118 draw_pixel(fbi, x, y, 0xffff00);
119 else if (x == 20 || x == w - 20 ||
120 y == 20 || y == h - 20)
121 draw_pixel(fbi, x, y, 0xffffff);
122 else if (x == y || w - x == h - y)
123 draw_pixel(fbi, x, y, 0xff00ff);
124 else if (w - x == y || x == h - y)
125 draw_pixel(fbi, x, y, 0x00ffff);
126 else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {
127 int t = x * 3 / w;
128 unsigned r = 0, g = 0, b = 0;
129 unsigned c;
130 if (var->bits_per_pixel == 16) {
131 if (t == 0)
132 b = (y % 32) * 256 / 32;
133 else if (t == 1)
134 g = (y % 64) * 256 / 64;
135 else if (t == 2)
136 r = (y % 32) * 256 / 32;
137 } else {
138 if (t == 0)
139 b = (y % 256);
140 else if (t == 1)
141 g = (y % 256);
142 else if (t == 2)
143 r = (y % 256);
144 }
145 c = (r << 16) | (g << 8) | (b << 0);
146 draw_pixel(fbi, x, y, c);
147 } else {
148 draw_pixel(fbi, x, y, 0);
149 }
150 }
151 }
152}
153#endif
154
155static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)
156{
157 struct vrfb *vrfb = &ofbi->region.vrfb;
158 unsigned offset;
159
160 switch (rot) {
161 case FB_ROTATE_UR:
162 offset = 0;
163 break;
164 case FB_ROTATE_CW:
165 offset = vrfb->yoffset;
166 break;
167 case FB_ROTATE_UD:
168 offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;
169 break;
170 case FB_ROTATE_CCW:
171 offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;
172 break;
173 default:
174 BUG();
175 }
176
177 offset *= vrfb->bytespp;
178
179 return offset;
180}
181
182static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)
183{
184 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
185 return ofbi->region.vrfb.paddr[rot]
186 + omapfb_get_vrfb_offset(ofbi, rot);
187 } else {
188 return ofbi->region.paddr;
189 }
190}
191
192static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)
193{
194 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
195 return ofbi->region.vrfb.paddr[0];
196 else
197 return ofbi->region.paddr;
198}
199
200static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)
201{
202 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
203 return ofbi->region.vrfb.vaddr[0];
204 else
205 return ofbi->region.vaddr;
206}
207
208static struct omapfb_colormode omapfb_colormodes[] = {
209 {
210 .dssmode = OMAP_DSS_COLOR_UYVY,
211 .bits_per_pixel = 16,
212 .nonstd = OMAPFB_COLOR_YUV422,
213 }, {
214 .dssmode = OMAP_DSS_COLOR_YUV2,
215 .bits_per_pixel = 16,
216 .nonstd = OMAPFB_COLOR_YUY422,
217 }, {
218 .dssmode = OMAP_DSS_COLOR_ARGB16,
219 .bits_per_pixel = 16,
220 .red = { .length = 4, .offset = 8, .msb_right = 0 },
221 .green = { .length = 4, .offset = 4, .msb_right = 0 },
222 .blue = { .length = 4, .offset = 0, .msb_right = 0 },
223 .transp = { .length = 4, .offset = 12, .msb_right = 0 },
224 }, {
225 .dssmode = OMAP_DSS_COLOR_RGB16,
226 .bits_per_pixel = 16,
227 .red = { .length = 5, .offset = 11, .msb_right = 0 },
228 .green = { .length = 6, .offset = 5, .msb_right = 0 },
229 .blue = { .length = 5, .offset = 0, .msb_right = 0 },
230 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
231 }, {
232 .dssmode = OMAP_DSS_COLOR_RGB24P,
233 .bits_per_pixel = 24,
234 .red = { .length = 8, .offset = 16, .msb_right = 0 },
235 .green = { .length = 8, .offset = 8, .msb_right = 0 },
236 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
237 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
238 }, {
239 .dssmode = OMAP_DSS_COLOR_RGB24U,
240 .bits_per_pixel = 32,
241 .red = { .length = 8, .offset = 16, .msb_right = 0 },
242 .green = { .length = 8, .offset = 8, .msb_right = 0 },
243 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
244 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
245 }, {
246 .dssmode = OMAP_DSS_COLOR_ARGB32,
247 .bits_per_pixel = 32,
248 .red = { .length = 8, .offset = 16, .msb_right = 0 },
249 .green = { .length = 8, .offset = 8, .msb_right = 0 },
250 .blue = { .length = 8, .offset = 0, .msb_right = 0 },
251 .transp = { .length = 8, .offset = 24, .msb_right = 0 },
252 }, {
253 .dssmode = OMAP_DSS_COLOR_RGBA32,
254 .bits_per_pixel = 32,
255 .red = { .length = 8, .offset = 24, .msb_right = 0 },
256 .green = { .length = 8, .offset = 16, .msb_right = 0 },
257 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
258 .transp = { .length = 8, .offset = 0, .msb_right = 0 },
259 }, {
260 .dssmode = OMAP_DSS_COLOR_RGBX32,
261 .bits_per_pixel = 32,
262 .red = { .length = 8, .offset = 24, .msb_right = 0 },
263 .green = { .length = 8, .offset = 16, .msb_right = 0 },
264 .blue = { .length = 8, .offset = 8, .msb_right = 0 },
265 .transp = { .length = 0, .offset = 0, .msb_right = 0 },
266 },
267};
268
269static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,
270 struct omapfb_colormode *color)
271{
272 bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)
273 {
274 return f1->length == f2->length &&
275 f1->offset == f2->offset &&
276 f1->msb_right == f2->msb_right;
277 }
278
279 if (var->bits_per_pixel == 0 ||
280 var->red.length == 0 ||
281 var->blue.length == 0 ||
282 var->green.length == 0)
283 return 0;
284
285 return var->bits_per_pixel == color->bits_per_pixel &&
286 cmp_component(&var->red, &color->red) &&
287 cmp_component(&var->green, &color->green) &&
288 cmp_component(&var->blue, &color->blue) &&
289 cmp_component(&var->transp, &color->transp);
290}
291
292static void assign_colormode_to_var(struct fb_var_screeninfo *var,
293 struct omapfb_colormode *color)
294{
295 var->bits_per_pixel = color->bits_per_pixel;
296 var->nonstd = color->nonstd;
297 var->red = color->red;
298 var->green = color->green;
299 var->blue = color->blue;
300 var->transp = color->transp;
301}
302
303static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,
304 enum omap_color_mode *mode)
305{
306 enum omap_color_mode dssmode;
307 int i;
308
309 /* first match with nonstd field */
310 if (var->nonstd) {
311 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
312 struct omapfb_colormode *m = &omapfb_colormodes[i];
313 if (var->nonstd == m->nonstd) {
314 assign_colormode_to_var(var, m);
315 *mode = m->dssmode;
316 return 0;
317 }
318 }
319
320 return -EINVAL;
321 }
322
323 /* then try exact match of bpp and colors */
324 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
325 struct omapfb_colormode *m = &omapfb_colormodes[i];
326 if (cmp_var_to_colormode(var, m)) {
327 assign_colormode_to_var(var, m);
328 *mode = m->dssmode;
329 return 0;
330 }
331 }
332
333 /* match with bpp if user has not filled color fields
334 * properly */
335 switch (var->bits_per_pixel) {
336 case 1:
337 dssmode = OMAP_DSS_COLOR_CLUT1;
338 break;
339 case 2:
340 dssmode = OMAP_DSS_COLOR_CLUT2;
341 break;
342 case 4:
343 dssmode = OMAP_DSS_COLOR_CLUT4;
344 break;
345 case 8:
346 dssmode = OMAP_DSS_COLOR_CLUT8;
347 break;
348 case 12:
349 dssmode = OMAP_DSS_COLOR_RGB12U;
350 break;
351 case 16:
352 dssmode = OMAP_DSS_COLOR_RGB16;
353 break;
354 case 24:
355 dssmode = OMAP_DSS_COLOR_RGB24P;
356 break;
357 case 32:
358 dssmode = OMAP_DSS_COLOR_RGB24U;
359 break;
360 default:
361 return -EINVAL;
362 }
363
364 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
365 struct omapfb_colormode *m = &omapfb_colormodes[i];
366 if (dssmode == m->dssmode) {
367 assign_colormode_to_var(var, m);
368 *mode = m->dssmode;
369 return 0;
370 }
371 }
372
373 return -EINVAL;
374}
375
376static int check_fb_res_bounds(struct fb_var_screeninfo *var)
377{
378 int xres_min = OMAPFB_PLANE_XRES_MIN;
379 int xres_max = 2048;
380 int yres_min = OMAPFB_PLANE_YRES_MIN;
381 int yres_max = 2048;
382
383 /* XXX: some applications seem to set virtual res to 0. */
384 if (var->xres_virtual == 0)
385 var->xres_virtual = var->xres;
386
387 if (var->yres_virtual == 0)
388 var->yres_virtual = var->yres;
389
390 if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)
391 return -EINVAL;
392
393 if (var->xres < xres_min)
394 var->xres = xres_min;
395 if (var->yres < yres_min)
396 var->yres = yres_min;
397 if (var->xres > xres_max)
398 var->xres = xres_max;
399 if (var->yres > yres_max)
400 var->yres = yres_max;
401
402 if (var->xres > var->xres_virtual)
403 var->xres = var->xres_virtual;
404 if (var->yres > var->yres_virtual)
405 var->yres = var->yres_virtual;
406
407 return 0;
408}
409
410static void shrink_height(unsigned long max_frame_size,
411 struct fb_var_screeninfo *var)
412{
413 DBG("can't fit FB into memory, reducing y\n");
414 var->yres_virtual = max_frame_size /
415 (var->xres_virtual * var->bits_per_pixel >> 3);
416
417 if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)
418 var->yres_virtual = OMAPFB_PLANE_YRES_MIN;
419
420 if (var->yres > var->yres_virtual)
421 var->yres = var->yres_virtual;
422}
423
424static void shrink_width(unsigned long max_frame_size,
425 struct fb_var_screeninfo *var)
426{
427 DBG("can't fit FB into memory, reducing x\n");
428 var->xres_virtual = max_frame_size / var->yres_virtual /
429 (var->bits_per_pixel >> 3);
430
431 if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)
432 var->xres_virtual = OMAPFB_PLANE_XRES_MIN;
433
434 if (var->xres > var->xres_virtual)
435 var->xres = var->xres_virtual;
436}
437
438static int check_vrfb_fb_size(unsigned long region_size,
439 const struct fb_var_screeninfo *var)
440{
441 unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,
442 var->yres_virtual, var->bits_per_pixel >> 3);
443
444 return min_phys_size > region_size ? -EINVAL : 0;
445}
446
447static int check_fb_size(const struct omapfb_info *ofbi,
448 struct fb_var_screeninfo *var)
449{
450 unsigned long max_frame_size = ofbi->region.size;
451 int bytespp = var->bits_per_pixel >> 3;
452 unsigned long line_size = var->xres_virtual * bytespp;
453
454 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
455 /* One needs to check for both VRFB and OMAPFB limitations. */
456 if (check_vrfb_fb_size(max_frame_size, var))
457 shrink_height(omap_vrfb_max_height(
458 max_frame_size, var->xres_virtual, bytespp) *
459 line_size, var);
460
461 if (check_vrfb_fb_size(max_frame_size, var)) {
462 DBG("cannot fit FB to memory\n");
463 return -EINVAL;
464 }
465
466 return 0;
467 }
468
469 DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);
470
471 if (line_size * var->yres_virtual > max_frame_size)
472 shrink_height(max_frame_size, var);
473
474 if (line_size * var->yres_virtual > max_frame_size) {
475 shrink_width(max_frame_size, var);
476 line_size = var->xres_virtual * bytespp;
477 }
478
479 if (line_size * var->yres_virtual > max_frame_size) {
480 DBG("cannot fit FB to memory\n");
481 return -EINVAL;
482 }
483
484 return 0;
485}
486
487/*
488 * Consider if VRFB assisted rotation is in use and if the virtual space for
489 * the zero degree view needs to be mapped. The need for mapping also acts as
490 * the trigger for setting up the hardware on the context in question. This
491 * ensures that one does not attempt to access the virtual view before the
492 * hardware is serving the address translations.
493 */
494static int setup_vrfb_rotation(struct fb_info *fbi)
495{
496 struct omapfb_info *ofbi = FB2OFB(fbi);
497 struct omapfb2_mem_region *rg = &ofbi->region;
498 struct vrfb *vrfb = &rg->vrfb;
499 struct fb_var_screeninfo *var = &fbi->var;
500 struct fb_fix_screeninfo *fix = &fbi->fix;
501 unsigned bytespp;
502 bool yuv_mode;
503 enum omap_color_mode mode;
504 int r;
505 bool reconf;
506
507 if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)
508 return 0;
509
510 DBG("setup_vrfb_rotation\n");
511
512 r = fb_mode_to_dss_mode(var, &mode);
513 if (r)
514 return r;
515
516 bytespp = var->bits_per_pixel >> 3;
517
518 yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;
519
520 /* We need to reconfigure VRFB if the resolution changes, if yuv mode
521 * is enabled/disabled, or if bytes per pixel changes */
522
523 /* XXX we shouldn't allow this when framebuffer is mmapped */
524
525 reconf = false;
526
527 if (yuv_mode != vrfb->yuv_mode)
528 reconf = true;
529 else if (bytespp != vrfb->bytespp)
530 reconf = true;
531 else if (vrfb->xres != var->xres_virtual ||
532 vrfb->yres != var->yres_virtual)
533 reconf = true;
534
535 if (vrfb->vaddr[0] && reconf) {
536 fbi->screen_base = NULL;
537 fix->smem_start = 0;
538 fix->smem_len = 0;
539 iounmap(vrfb->vaddr[0]);
540 vrfb->vaddr[0] = NULL;
541 DBG("setup_vrfb_rotation: reset fb\n");
542 }
543
544 if (vrfb->vaddr[0])
545 return 0;
546
547 omap_vrfb_setup(&rg->vrfb, rg->paddr,
548 var->xres_virtual,
549 var->yres_virtual,
550 bytespp, yuv_mode);
551
552 /* Now one can ioremap the 0 angle view */
553 r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);
554 if (r)
555 return r;
556
557 /* used by open/write in fbmem.c */
558 fbi->screen_base = ofbi->region.vrfb.vaddr[0];
559
560 fix->smem_start = ofbi->region.vrfb.paddr[0];
561
562 switch (var->nonstd) {
563 case OMAPFB_COLOR_YUV422:
564 case OMAPFB_COLOR_YUY422:
565 fix->line_length =
566 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
567 break;
568 default:
569 fix->line_length =
570 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
571 break;
572 }
573
574 fix->smem_len = var->yres_virtual * fix->line_length;
575
576 return 0;
577}
578
579int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
580 struct fb_var_screeninfo *var)
581{
582 int i;
583
584 for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {
585 struct omapfb_colormode *mode = &omapfb_colormodes[i];
586 if (dssmode == mode->dssmode) {
587 assign_colormode_to_var(var, mode);
588 return 0;
589 }
590 }
591 return -ENOENT;
592}
593
594void set_fb_fix(struct fb_info *fbi)
595{
596 struct fb_fix_screeninfo *fix = &fbi->fix;
597 struct fb_var_screeninfo *var = &fbi->var;
598 struct omapfb_info *ofbi = FB2OFB(fbi);
599 struct omapfb2_mem_region *rg = &ofbi->region;
600
601 DBG("set_fb_fix\n");
602
603 /* used by open/write in fbmem.c */
604 fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);
605
606 /* used by mmap in fbmem.c */
607 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
608 switch (var->nonstd) {
609 case OMAPFB_COLOR_YUV422:
610 case OMAPFB_COLOR_YUY422:
611 fix->line_length =
612 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;
613 break;
614 default:
615 fix->line_length =
616 (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;
617 break;
618 }
619
620 fix->smem_len = var->yres_virtual * fix->line_length;
621 } else {
622 fix->line_length =
623 (var->xres_virtual * var->bits_per_pixel) >> 3;
624 fix->smem_len = rg->size;
625 }
626
627 fix->smem_start = omapfb_get_region_paddr(ofbi);
628
629 fix->type = FB_TYPE_PACKED_PIXELS;
630
631 if (var->nonstd)
632 fix->visual = FB_VISUAL_PSEUDOCOLOR;
633 else {
634 switch (var->bits_per_pixel) {
635 case 32:
636 case 24:
637 case 16:
638 case 12:
639 fix->visual = FB_VISUAL_TRUECOLOR;
640 /* 12bpp is stored in 16 bits */
641 break;
642 case 1:
643 case 2:
644 case 4:
645 case 8:
646 fix->visual = FB_VISUAL_PSEUDOCOLOR;
647 break;
648 }
649 }
650
651 fix->accel = FB_ACCEL_NONE;
652
653 fix->xpanstep = 1;
654 fix->ypanstep = 1;
655}
656
657/* check new var and possibly modify it to be ok */
658int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)
659{
660 struct omapfb_info *ofbi = FB2OFB(fbi);
661 struct omap_dss_device *display = fb2display(fbi);
662 enum omap_color_mode mode = 0;
663 int i;
664 int r;
665
666 DBG("check_fb_var %d\n", ofbi->id);
667
668 if (ofbi->region.size == 0)
669 return 0;
670
671 r = fb_mode_to_dss_mode(var, &mode);
672 if (r) {
673 DBG("cannot convert var to omap dss mode\n");
674 return r;
675 }
676
677 for (i = 0; i < ofbi->num_overlays; ++i) {
678 if ((ofbi->overlays[i]->supported_modes & mode) == 0) {
679 DBG("invalid mode\n");
680 return -EINVAL;
681 }
682 }
683
684 if (var->rotate < 0 || var->rotate > 3)
685 return -EINVAL;
686
687 if (check_fb_res_bounds(var))
688 return -EINVAL;
689
690 if (check_fb_size(ofbi, var))
691 return -EINVAL;
692
693 if (var->xres + var->xoffset > var->xres_virtual)
694 var->xoffset = var->xres_virtual - var->xres;
695 if (var->yres + var->yoffset > var->yres_virtual)
696 var->yoffset = var->yres_virtual - var->yres;
697
698 DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",
699 var->xres, var->yres,
700 var->xres_virtual, var->yres_virtual);
701
702 var->height = -1;
703 var->width = -1;
704 var->grayscale = 0;
705
706 if (display && display->get_timings) {
707 struct omap_video_timings timings;
708 display->get_timings(display, &timings);
709
710 /* pixclock in ps, the rest in pixclock */
711 var->pixclock = timings.pixel_clock != 0 ?
712 KHZ2PICOS(timings.pixel_clock) :
713 0;
714 var->left_margin = timings.hfp;
715 var->right_margin = timings.hbp;
716 var->upper_margin = timings.vfp;
717 var->lower_margin = timings.vbp;
718 var->hsync_len = timings.hsw;
719 var->vsync_len = timings.vsw;
720 } else {
721 var->pixclock = 0;
722 var->left_margin = 0;
723 var->right_margin = 0;
724 var->upper_margin = 0;
725 var->lower_margin = 0;
726 var->hsync_len = 0;
727 var->vsync_len = 0;
728 }
729
730 /* TODO: get these from panel->config */
731 var->vmode = FB_VMODE_NONINTERLACED;
732 var->sync = 0;
733
734 return 0;
735}
736
737/*
738 * ---------------------------------------------------------------------------
739 * fbdev framework callbacks
740 * ---------------------------------------------------------------------------
741 */
742static int omapfb_open(struct fb_info *fbi, int user)
743{
744 return 0;
745}
746
747static int omapfb_release(struct fb_info *fbi, int user)
748{
749#if 0
750 struct omapfb_info *ofbi = FB2OFB(fbi);
751 struct omapfb2_device *fbdev = ofbi->fbdev;
752 struct omap_dss_device *display = fb2display(fbi);
753
754 DBG("Closing fb with plane index %d\n", ofbi->id);
755
756 omapfb_lock(fbdev);
757
758 if (display && display->get_update_mode && display->update) {
759 /* XXX this update should be removed, I think. But it's
760 * good for debugging */
761 if (display->get_update_mode(display) ==
762 OMAP_DSS_UPDATE_MANUAL) {
763 u16 w, h;
764
765 if (display->sync)
766 display->sync(display);
767
768 display->get_resolution(display, &w, &h);
769 display->update(display, 0, 0, w, h);
770 }
771 }
772
773 if (display && display->sync)
774 display->sync(display);
775
776 omapfb_unlock(fbdev);
777#endif
778 return 0;
779}
780
781static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var,
782 struct fb_fix_screeninfo *fix, int rotation)
783{
784 unsigned offset;
785
786 offset = var->yoffset * fix->line_length +
787 var->xoffset * (var->bits_per_pixel >> 3);
788
789 return offset;
790}
791
792static unsigned calc_rotation_offset_vrfb(struct fb_var_screeninfo *var,
793 struct fb_fix_screeninfo *fix, int rotation)
794{
795 unsigned offset;
796
797 if (rotation == FB_ROTATE_UD)
798 offset = (var->yres_virtual - var->yres) *
799 fix->line_length;
800 else if (rotation == FB_ROTATE_CW)
801 offset = (var->yres_virtual - var->yres) *
802 (var->bits_per_pixel >> 3);
803 else
804 offset = 0;
805
806 if (rotation == FB_ROTATE_UR)
807 offset += var->yoffset * fix->line_length +
808 var->xoffset * (var->bits_per_pixel >> 3);
809 else if (rotation == FB_ROTATE_UD)
810 offset -= var->yoffset * fix->line_length +
811 var->xoffset * (var->bits_per_pixel >> 3);
812 else if (rotation == FB_ROTATE_CW)
813 offset -= var->xoffset * fix->line_length +
814 var->yoffset * (var->bits_per_pixel >> 3);
815 else if (rotation == FB_ROTATE_CCW)
816 offset += var->xoffset * fix->line_length +
817 var->yoffset * (var->bits_per_pixel >> 3);
818
819 return offset;
820}
821
822
823/* setup overlay according to the fb */
824static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,
825 u16 posx, u16 posy, u16 outw, u16 outh)
826{
827 int r = 0;
828 struct omapfb_info *ofbi = FB2OFB(fbi);
829 struct fb_var_screeninfo *var = &fbi->var;
830 struct fb_fix_screeninfo *fix = &fbi->fix;
831 enum omap_color_mode mode = 0;
832 int offset;
833 u32 data_start_p;
834 void __iomem *data_start_v;
835 struct omap_overlay_info info;
836 int xres, yres;
837 int screen_width;
838 int mirror;
839 int rotation = var->rotate;
840 int i;
841
842 for (i = 0; i < ofbi->num_overlays; i++) {
843 if (ovl != ofbi->overlays[i])
844 continue;
845
846 rotation = (rotation + ofbi->rotation[i]) % 4;
847 break;
848 }
849
850 DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,
851 posx, posy, outw, outh);
852
853 if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {
854 xres = var->yres;
855 yres = var->xres;
856 } else {
857 xres = var->xres;
858 yres = var->yres;
859 }
860
861
862 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
863 data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);
864 data_start_v = NULL;
865 } else {
866 data_start_p = omapfb_get_region_paddr(ofbi);
867 data_start_v = omapfb_get_region_vaddr(ofbi);
868 }
869
870 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
871 offset = calc_rotation_offset_vrfb(var, fix, rotation);
872 else
873 offset = calc_rotation_offset_dma(var, fix, rotation);
874
875 data_start_p += offset;
876 data_start_v += offset;
877
878 if (offset)
879 DBG("offset %d, %d = %d\n",
880 var->xoffset, var->yoffset, offset);
881
882 DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);
883
884 r = fb_mode_to_dss_mode(var, &mode);
885 if (r) {
886 DBG("fb_mode_to_dss_mode failed");
887 goto err;
888 }
889
890 switch (var->nonstd) {
891 case OMAPFB_COLOR_YUV422:
892 case OMAPFB_COLOR_YUY422:
893 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
894 screen_width = fix->line_length
895 / (var->bits_per_pixel >> 2);
896 break;
897 }
898 default:
899 screen_width = fix->line_length / (var->bits_per_pixel >> 3);
900 break;
901 }
902
903 ovl->get_overlay_info(ovl, &info);
904
905 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)
906 mirror = 0;
907 else
908 mirror = ofbi->mirror;
909
910 info.paddr = data_start_p;
911 info.vaddr = data_start_v;
912 info.screen_width = screen_width;
913 info.width = xres;
914 info.height = yres;
915 info.color_mode = mode;
916 info.rotation_type = ofbi->rotation_type;
917 info.rotation = rotation;
918 info.mirror = mirror;
919
920 info.pos_x = posx;
921 info.pos_y = posy;
922 info.out_width = outw;
923 info.out_height = outh;
924
925 r = ovl->set_overlay_info(ovl, &info);
926 if (r) {
927 DBG("ovl->setup_overlay_info failed\n");
928 goto err;
929 }
930
931 return 0;
932
933err:
934 DBG("setup_overlay failed\n");
935 return r;
936}
937
938/* apply var to the overlay */
939int omapfb_apply_changes(struct fb_info *fbi, int init)
940{
941 int r = 0;
942 struct omapfb_info *ofbi = FB2OFB(fbi);
943 struct fb_var_screeninfo *var = &fbi->var;
944 struct omap_overlay *ovl;
945 u16 posx, posy;
946 u16 outw, outh;
947 int i;
948
949#ifdef DEBUG
950 if (omapfb_test_pattern)
951 fill_fb(fbi);
952#endif
953
954 for (i = 0; i < ofbi->num_overlays; i++) {
955 ovl = ofbi->overlays[i];
956
957 DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);
958
959 if (ofbi->region.size == 0) {
960 /* the fb is not available. disable the overlay */
961 omapfb_overlay_enable(ovl, 0);
962 if (!init && ovl->manager)
963 ovl->manager->apply(ovl->manager);
964 continue;
965 }
966
967 if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {
968 int rotation = (var->rotate + ofbi->rotation[i]) % 4;
969 if (rotation == FB_ROTATE_CW ||
970 rotation == FB_ROTATE_CCW) {
971 outw = var->yres;
972 outh = var->xres;
973 } else {
974 outw = var->xres;
975 outh = var->yres;
976 }
977 } else {
978 outw = ovl->info.out_width;
979 outh = ovl->info.out_height;
980 }
981
982 if (init) {
983 posx = 0;
984 posy = 0;
985 } else {
986 posx = ovl->info.pos_x;
987 posy = ovl->info.pos_y;
988 }
989
990 r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);
991 if (r)
992 goto err;
993
994 if (!init && ovl->manager)
995 ovl->manager->apply(ovl->manager);
996 }
997 return 0;
998err:
999 DBG("apply_changes failed\n");
1000 return r;
1001}
1002
1003/* checks var and eventually tweaks it to something supported,
1004 * DO NOT MODIFY PAR */
1005static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)
1006{
1007 int r;
1008
1009 DBG("check_var(%d)\n", FB2OFB(fbi)->id);
1010
1011 r = check_fb_var(fbi, var);
1012
1013 return r;
1014}
1015
1016/* set the video mode according to info->var */
1017static int omapfb_set_par(struct fb_info *fbi)
1018{
1019 int r;
1020
1021 DBG("set_par(%d)\n", FB2OFB(fbi)->id);
1022
1023 set_fb_fix(fbi);
1024
1025 r = setup_vrfb_rotation(fbi);
1026 if (r)
1027 return r;
1028
1029 r = omapfb_apply_changes(fbi, 0);
1030
1031 return r;
1032}
1033
1034static int omapfb_pan_display(struct fb_var_screeninfo *var,
1035 struct fb_info *fbi)
1036{
1037 struct fb_var_screeninfo new_var;
1038 int r;
1039
1040 DBG("pan_display(%d)\n", FB2OFB(fbi)->id);
1041
1042 if (var->xoffset == fbi->var.xoffset &&
1043 var->yoffset == fbi->var.yoffset)
1044 return 0;
1045
1046 new_var = fbi->var;
1047 new_var.xoffset = var->xoffset;
1048 new_var.yoffset = var->yoffset;
1049
1050 fbi->var = new_var;
1051
1052 r = omapfb_apply_changes(fbi, 0);
1053
1054 return r;
1055}
1056
1057static void mmap_user_open(struct vm_area_struct *vma)
1058{
1059 struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1060
1061 atomic_inc(&ofbi->map_count);
1062}
1063
1064static void mmap_user_close(struct vm_area_struct *vma)
1065{
1066 struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;
1067
1068 atomic_dec(&ofbi->map_count);
1069}
1070
1071static struct vm_operations_struct mmap_user_ops = {
1072 .open = mmap_user_open,
1073 .close = mmap_user_close,
1074};
1075
1076static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
1077{
1078 struct omapfb_info *ofbi = FB2OFB(fbi);
1079 struct fb_fix_screeninfo *fix = &fbi->fix;
1080 unsigned long off;
1081 unsigned long start;
1082 u32 len;
1083
1084 if (vma->vm_end - vma->vm_start == 0)
1085 return 0;
1086 if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
1087 return -EINVAL;
1088 off = vma->vm_pgoff << PAGE_SHIFT;
1089
1090 start = omapfb_get_region_paddr(ofbi);
1091 len = fix->smem_len;
1092 if (off >= len)
1093 return -EINVAL;
1094 if ((vma->vm_end - vma->vm_start + off) > len)
1095 return -EINVAL;
1096
1097 off += start;
1098
1099 DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);
1100
1101 vma->vm_pgoff = off >> PAGE_SHIFT;
1102 vma->vm_flags |= VM_IO | VM_RESERVED;
1103 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1104 vma->vm_ops = &mmap_user_ops;
1105 vma->vm_private_data = ofbi;
1106 if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
1107 vma->vm_end - vma->vm_start, vma->vm_page_prot))
1108 return -EAGAIN;
1109 /* vm_ops.open won't be called for mmap itself. */
1110 atomic_inc(&ofbi->map_count);
1111 return 0;
1112}
1113
1114/* Store a single color palette entry into a pseudo palette or the hardware
1115 * palette if one is available. For now we support only 16bpp and thus store
1116 * the entry only to the pseudo palette.
1117 */
1118static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,
1119 u_int blue, u_int transp, int update_hw_pal)
1120{
1121 /*struct omapfb_info *ofbi = FB2OFB(fbi);*/
1122 /*struct omapfb2_device *fbdev = ofbi->fbdev;*/
1123 struct fb_var_screeninfo *var = &fbi->var;
1124 int r = 0;
1125
1126 enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */
1127
1128 /*switch (plane->color_mode) {*/
1129 switch (mode) {
1130 case OMAPFB_COLOR_YUV422:
1131 case OMAPFB_COLOR_YUV420:
1132 case OMAPFB_COLOR_YUY422:
1133 r = -EINVAL;
1134 break;
1135 case OMAPFB_COLOR_CLUT_8BPP:
1136 case OMAPFB_COLOR_CLUT_4BPP:
1137 case OMAPFB_COLOR_CLUT_2BPP:
1138 case OMAPFB_COLOR_CLUT_1BPP:
1139 /*
1140 if (fbdev->ctrl->setcolreg)
1141 r = fbdev->ctrl->setcolreg(regno, red, green, blue,
1142 transp, update_hw_pal);
1143 */
1144 /* Fallthrough */
1145 r = -EINVAL;
1146 break;
1147 case OMAPFB_COLOR_RGB565:
1148 case OMAPFB_COLOR_RGB444:
1149 case OMAPFB_COLOR_RGB24P:
1150 case OMAPFB_COLOR_RGB24U:
1151 if (r != 0)
1152 break;
1153
1154 if (regno < 0) {
1155 r = -EINVAL;
1156 break;
1157 }
1158
1159 if (regno < 16) {
1160 u16 pal;
1161 pal = ((red >> (16 - var->red.length)) <<
1162 var->red.offset) |
1163 ((green >> (16 - var->green.length)) <<
1164 var->green.offset) |
1165 (blue >> (16 - var->blue.length));
1166 ((u32 *)(fbi->pseudo_palette))[regno] = pal;
1167 }
1168 break;
1169 default:
1170 BUG();
1171 }
1172 return r;
1173}
1174
1175static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
1176 u_int transp, struct fb_info *info)
1177{
1178 DBG("setcolreg\n");
1179
1180 return _setcolreg(info, regno, red, green, blue, transp, 1);
1181}
1182
1183static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
1184{
1185 int count, index, r;
1186 u16 *red, *green, *blue, *transp;
1187 u16 trans = 0xffff;
1188
1189 DBG("setcmap\n");
1190
1191 red = cmap->red;
1192 green = cmap->green;
1193 blue = cmap->blue;
1194 transp = cmap->transp;
1195 index = cmap->start;
1196
1197 for (count = 0; count < cmap->len; count++) {
1198 if (transp)
1199 trans = *transp++;
1200 r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,
1201 count == cmap->len - 1);
1202 if (r != 0)
1203 return r;
1204 }
1205
1206 return 0;
1207}
1208
1209static int omapfb_blank(int blank, struct fb_info *fbi)
1210{
1211 struct omapfb_info *ofbi = FB2OFB(fbi);
1212 struct omapfb2_device *fbdev = ofbi->fbdev;
1213 struct omap_dss_device *display = fb2display(fbi);
1214 int do_update = 0;
1215 int r = 0;
1216
1217 omapfb_lock(fbdev);
1218
1219 switch (blank) {
1220 case FB_BLANK_UNBLANK:
1221 if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)
1222 goto exit;
1223
1224 if (display->resume)
1225 r = display->resume(display);
1226
1227 if (r == 0 && display->get_update_mode &&
1228 display->get_update_mode(display) ==
1229 OMAP_DSS_UPDATE_MANUAL)
1230 do_update = 1;
1231
1232 break;
1233
1234 case FB_BLANK_NORMAL:
1235 /* FB_BLANK_NORMAL could be implemented.
1236 * Needs DSS additions. */
1237 case FB_BLANK_VSYNC_SUSPEND:
1238 case FB_BLANK_HSYNC_SUSPEND:
1239 case FB_BLANK_POWERDOWN:
1240 if (display->state != OMAP_DSS_DISPLAY_ACTIVE)
1241 goto exit;
1242
1243 if (display->suspend)
1244 r = display->suspend(display);
1245
1246 break;
1247
1248 default:
1249 r = -EINVAL;
1250 }
1251
1252exit:
1253 omapfb_unlock(fbdev);
1254
1255 if (r == 0 && do_update && display->update) {
1256 u16 w, h;
1257 display->get_resolution(display, &w, &h);
1258
1259 r = display->update(display, 0, 0, w, h);
1260 }
1261
1262 return r;
1263}
1264
1265#if 0
1266/* XXX fb_read and fb_write are needed for VRFB */
1267ssize_t omapfb_write(struct fb_info *info, const char __user *buf,
1268 size_t count, loff_t *ppos)
1269{
1270 DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);
1271 /* XXX needed for VRFB */
1272 return count;
1273}
1274#endif
1275
1276static struct fb_ops omapfb_ops = {
1277 .owner = THIS_MODULE,
1278 .fb_open = omapfb_open,
1279 .fb_release = omapfb_release,
1280 .fb_fillrect = cfb_fillrect,
1281 .fb_copyarea = cfb_copyarea,
1282 .fb_imageblit = cfb_imageblit,
1283 .fb_blank = omapfb_blank,
1284 .fb_ioctl = omapfb_ioctl,
1285 .fb_check_var = omapfb_check_var,
1286 .fb_set_par = omapfb_set_par,
1287 .fb_pan_display = omapfb_pan_display,
1288 .fb_mmap = omapfb_mmap,
1289 .fb_setcolreg = omapfb_setcolreg,
1290 .fb_setcmap = omapfb_setcmap,
1291 /*.fb_write = omapfb_write,*/
1292};
1293
1294static void omapfb_free_fbmem(struct fb_info *fbi)
1295{
1296 struct omapfb_info *ofbi = FB2OFB(fbi);
1297 struct omapfb2_device *fbdev = ofbi->fbdev;
1298 struct omapfb2_mem_region *rg;
1299
1300 rg = &ofbi->region;
1301
1302 if (rg->paddr)
1303 if (omap_vram_free(rg->paddr, rg->size))
1304 dev_err(fbdev->dev, "VRAM FREE failed\n");
1305
1306 if (rg->vaddr)
1307 iounmap(rg->vaddr);
1308
1309 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1310 /* unmap the 0 angle rotation */
1311 if (rg->vrfb.vaddr[0]) {
1312 iounmap(rg->vrfb.vaddr[0]);
1313 omap_vrfb_release_ctx(&rg->vrfb);
1314 rg->vrfb.vaddr[0] = NULL;
1315 }
1316 }
1317
1318 rg->vaddr = NULL;
1319 rg->paddr = 0;
1320 rg->alloc = 0;
1321 rg->size = 0;
1322}
1323
1324static void clear_fb_info(struct fb_info *fbi)
1325{
1326 memset(&fbi->var, 0, sizeof(fbi->var));
1327 memset(&fbi->fix, 0, sizeof(fbi->fix));
1328 strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));
1329}
1330
1331static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)
1332{
1333 int i;
1334
1335 DBG("free all fbmem\n");
1336
1337 for (i = 0; i < fbdev->num_fbs; i++) {
1338 struct fb_info *fbi = fbdev->fbs[i];
1339 omapfb_free_fbmem(fbi);
1340 clear_fb_info(fbi);
1341 }
1342
1343 return 0;
1344}
1345
1346static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,
1347 unsigned long paddr)
1348{
1349 struct omapfb_info *ofbi = FB2OFB(fbi);
1350 struct omapfb2_device *fbdev = ofbi->fbdev;
1351 struct omapfb2_mem_region *rg;
1352 void __iomem *vaddr;
1353 int r;
1354
1355 rg = &ofbi->region;
1356 memset(rg, 0, sizeof(*rg));
1357
1358 size = PAGE_ALIGN(size);
1359
1360 if (!paddr) {
1361 DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);
1362 r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);
1363 } else {
1364 DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,
1365 ofbi->id);
1366 r = omap_vram_reserve(paddr, size);
1367 }
1368
1369 if (r) {
1370 dev_err(fbdev->dev, "failed to allocate framebuffer\n");
1371 return -ENOMEM;
1372 }
1373
1374 if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {
1375 vaddr = ioremap_wc(paddr, size);
1376
1377 if (!vaddr) {
1378 dev_err(fbdev->dev, "failed to ioremap framebuffer\n");
1379 omap_vram_free(paddr, size);
1380 return -ENOMEM;
1381 }
1382
1383 DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);
1384 } else {
1385 r = omap_vrfb_request_ctx(&rg->vrfb);
1386 if (r) {
1387 dev_err(fbdev->dev, "vrfb create ctx failed\n");
1388 return r;
1389 }
1390
1391 vaddr = NULL;
1392 }
1393
1394 rg->paddr = paddr;
1395 rg->vaddr = vaddr;
1396 rg->size = size;
1397 rg->alloc = 1;
1398
1399 return 0;
1400}
1401
1402/* allocate fbmem using display resolution as reference */
1403static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,
1404 unsigned long paddr)
1405{
1406 struct omapfb_info *ofbi = FB2OFB(fbi);
1407 struct omap_dss_device *display;
1408 int bytespp;
1409
1410 display = fb2display(fbi);
1411
1412 if (!display)
1413 return 0;
1414
1415 switch (display->get_recommended_bpp(display)) {
1416 case 16:
1417 bytespp = 2;
1418 break;
1419 case 24:
1420 bytespp = 4;
1421 break;
1422 default:
1423 bytespp = 4;
1424 break;
1425 }
1426
1427 if (!size) {
1428 u16 w, h;
1429
1430 display->get_resolution(display, &w, &h);
1431
1432 if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {
1433 size = max(omap_vrfb_min_phys_size(w, h, bytespp),
1434 omap_vrfb_min_phys_size(h, w, bytespp));
1435
1436 DBG("adjusting fb mem size for VRFB, %u -> %lu\n",
1437 w * h * bytespp, size);
1438 } else {
1439 size = w * h * bytespp;
1440 }
1441 }
1442
1443 if (!size)
1444 return 0;
1445
1446 return omapfb_alloc_fbmem(fbi, size, paddr);
1447}
1448
1449static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)
1450{
1451 enum omap_color_mode mode;
1452
1453 switch (fmt) {
1454 case OMAPFB_COLOR_RGB565:
1455 mode = OMAP_DSS_COLOR_RGB16;
1456 break;
1457 case OMAPFB_COLOR_YUV422:
1458 mode = OMAP_DSS_COLOR_YUV2;
1459 break;
1460 case OMAPFB_COLOR_CLUT_8BPP:
1461 mode = OMAP_DSS_COLOR_CLUT8;
1462 break;
1463 case OMAPFB_COLOR_CLUT_4BPP:
1464 mode = OMAP_DSS_COLOR_CLUT4;
1465 break;
1466 case OMAPFB_COLOR_CLUT_2BPP:
1467 mode = OMAP_DSS_COLOR_CLUT2;
1468 break;
1469 case OMAPFB_COLOR_CLUT_1BPP:
1470 mode = OMAP_DSS_COLOR_CLUT1;
1471 break;
1472 case OMAPFB_COLOR_RGB444:
1473 mode = OMAP_DSS_COLOR_RGB12U;
1474 break;
1475 case OMAPFB_COLOR_YUY422:
1476 mode = OMAP_DSS_COLOR_UYVY;
1477 break;
1478 case OMAPFB_COLOR_ARGB16:
1479 mode = OMAP_DSS_COLOR_ARGB16;
1480 break;
1481 case OMAPFB_COLOR_RGB24U:
1482 mode = OMAP_DSS_COLOR_RGB24U;
1483 break;
1484 case OMAPFB_COLOR_RGB24P:
1485 mode = OMAP_DSS_COLOR_RGB24P;
1486 break;
1487 case OMAPFB_COLOR_ARGB32:
1488 mode = OMAP_DSS_COLOR_ARGB32;
1489 break;
1490 case OMAPFB_COLOR_RGBA32:
1491 mode = OMAP_DSS_COLOR_RGBA32;
1492 break;
1493 case OMAPFB_COLOR_RGBX32:
1494 mode = OMAP_DSS_COLOR_RGBX32;
1495 break;
1496 default:
1497 mode = -EINVAL;
1498 }
1499
1500 return mode;
1501}
1502
1503static int omapfb_parse_vram_param(const char *param, int max_entries,
1504 unsigned long *sizes, unsigned long *paddrs)
1505{
1506 int fbnum;
1507 unsigned long size;
1508 unsigned long paddr = 0;
1509 char *p, *start;
1510
1511 start = (char *)param;
1512
1513 while (1) {
1514 p = start;
1515
1516 fbnum = simple_strtoul(p, &p, 10);
1517
1518 if (p == param)
1519 return -EINVAL;
1520
1521 if (*p != ':')
1522 return -EINVAL;
1523
1524 if (fbnum >= max_entries)
1525 return -EINVAL;
1526
1527 size = memparse(p + 1, &p);
1528
1529 if (!size)
1530 return -EINVAL;
1531
1532 paddr = 0;
1533
1534 if (*p == '@') {
1535 paddr = simple_strtoul(p + 1, &p, 16);
1536
1537 if (!paddr)
1538 return -EINVAL;
1539
1540 }
1541
1542 paddrs[fbnum] = paddr;
1543 sizes[fbnum] = size;
1544
1545 if (*p == 0)
1546 break;
1547
1548 if (*p != ',')
1549 return -EINVAL;
1550
1551 ++p;
1552
1553 start = p;
1554 }
1555
1556 return 0;
1557}
1558
1559static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)
1560{
1561 int i, r;
1562 unsigned long vram_sizes[10];
1563 unsigned long vram_paddrs[10];
1564
1565 memset(&vram_sizes, 0, sizeof(vram_sizes));
1566 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1567
1568 if (def_vram && omapfb_parse_vram_param(def_vram, 10,
1569 vram_sizes, vram_paddrs)) {
1570 dev_err(fbdev->dev, "failed to parse vram parameter\n");
1571
1572 memset(&vram_sizes, 0, sizeof(vram_sizes));
1573 memset(&vram_paddrs, 0, sizeof(vram_paddrs));
1574 }
1575
1576 if (fbdev->dev->platform_data) {
1577 struct omapfb_platform_data *opd;
1578 opd = fbdev->dev->platform_data;
1579 for (i = 0; i < opd->mem_desc.region_cnt; ++i) {
1580 if (!vram_sizes[i]) {
1581 unsigned long size;
1582 unsigned long paddr;
1583
1584 size = opd->mem_desc.region[i].size;
1585 paddr = opd->mem_desc.region[i].paddr;
1586
1587 vram_sizes[i] = size;
1588 vram_paddrs[i] = paddr;
1589 }
1590 }
1591 }
1592
1593 for (i = 0; i < fbdev->num_fbs; i++) {
1594 /* allocate memory automatically only for fb0, or if
1595 * excplicitly defined with vram or plat data option */
1596 if (i == 0 || vram_sizes[i] != 0) {
1597 r = omapfb_alloc_fbmem_display(fbdev->fbs[i],
1598 vram_sizes[i], vram_paddrs[i]);
1599
1600 if (r)
1601 return r;
1602 }
1603 }
1604
1605 for (i = 0; i < fbdev->num_fbs; i++) {
1606 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1607 struct omapfb2_mem_region *rg;
1608 rg = &ofbi->region;
1609
1610 DBG("region%d phys %08x virt %p size=%lu\n",
1611 i,
1612 rg->paddr,
1613 rg->vaddr,
1614 rg->size);
1615 }
1616
1617 return 0;
1618}
1619
1620int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)
1621{
1622 struct omapfb_info *ofbi = FB2OFB(fbi);
1623 struct omapfb2_device *fbdev = ofbi->fbdev;
1624 struct omap_dss_device *display = fb2display(fbi);
1625 struct omapfb2_mem_region *rg = &ofbi->region;
1626 unsigned long old_size = rg->size;
1627 unsigned long old_paddr = rg->paddr;
1628 int old_type = rg->type;
1629 int r;
1630
1631 if (type > OMAPFB_MEMTYPE_MAX)
1632 return -EINVAL;
1633
1634 size = PAGE_ALIGN(size);
1635
1636 if (old_size == size && old_type == type)
1637 return 0;
1638
1639 if (display && display->sync)
1640 display->sync(display);
1641
1642 omapfb_free_fbmem(fbi);
1643
1644 if (size == 0) {
1645 clear_fb_info(fbi);
1646 return 0;
1647 }
1648
1649 r = omapfb_alloc_fbmem(fbi, size, 0);
1650
1651 if (r) {
1652 if (old_size)
1653 omapfb_alloc_fbmem(fbi, old_size, old_paddr);
1654
1655 if (rg->size == 0)
1656 clear_fb_info(fbi);
1657
1658 return r;
1659 }
1660
1661 if (old_size == size)
1662 return 0;
1663
1664 if (old_size == 0) {
1665 DBG("initializing fb %d\n", ofbi->id);
1666 r = omapfb_fb_init(fbdev, fbi);
1667 if (r) {
1668 DBG("omapfb_fb_init failed\n");
1669 goto err;
1670 }
1671 r = omapfb_apply_changes(fbi, 1);
1672 if (r) {
1673 DBG("omapfb_apply_changes failed\n");
1674 goto err;
1675 }
1676 } else {
1677 struct fb_var_screeninfo new_var;
1678 memcpy(&new_var, &fbi->var, sizeof(new_var));
1679 r = check_fb_var(fbi, &new_var);
1680 if (r)
1681 goto err;
1682 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
1683 set_fb_fix(fbi);
1684 r = setup_vrfb_rotation(fbi);
1685 if (r)
1686 goto err;
1687 }
1688
1689 return 0;
1690err:
1691 omapfb_free_fbmem(fbi);
1692 clear_fb_info(fbi);
1693 return r;
1694}
1695
1696/* initialize fb_info, var, fix to something sane based on the display */
1697static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
1698{
1699 struct fb_var_screeninfo *var = &fbi->var;
1700 struct omap_dss_device *display = fb2display(fbi);
1701 struct omapfb_info *ofbi = FB2OFB(fbi);
1702 int r = 0;
1703
1704 fbi->fbops = &omapfb_ops;
1705 fbi->flags = FBINFO_FLAG_DEFAULT;
1706 fbi->pseudo_palette = fbdev->pseudo_palette;
1707
1708 if (ofbi->region.size == 0) {
1709 clear_fb_info(fbi);
1710 return 0;
1711 }
1712
1713 var->nonstd = 0;
1714 var->bits_per_pixel = 0;
1715
1716 var->rotate = def_rotate;
1717
1718 /*
1719 * Check if there is a default color format set in the board file,
1720 * and use this format instead the default deducted from the
1721 * display bpp.
1722 */
1723 if (fbdev->dev->platform_data) {
1724 struct omapfb_platform_data *opd;
1725 int id = ofbi->id;
1726
1727 opd = fbdev->dev->platform_data;
1728 if (opd->mem_desc.region[id].format_used) {
1729 enum omap_color_mode mode;
1730 enum omapfb_color_format format;
1731
1732 format = opd->mem_desc.region[id].format;
1733 mode = fb_format_to_dss_mode(format);
1734 if (mode < 0) {
1735 r = mode;
1736 goto err;
1737 }
1738 r = dss_mode_to_fb_mode(mode, var);
1739 if (r < 0)
1740 goto err;
1741 }
1742 }
1743
1744 if (display) {
1745 u16 w, h;
1746 int rotation = (var->rotate + ofbi->rotation[0]) % 4;
1747
1748 display->get_resolution(display, &w, &h);
1749
1750 if (rotation == FB_ROTATE_CW ||
1751 rotation == FB_ROTATE_CCW) {
1752 var->xres = h;
1753 var->yres = w;
1754 } else {
1755 var->xres = w;
1756 var->yres = h;
1757 }
1758
1759 var->xres_virtual = var->xres;
1760 var->yres_virtual = var->yres;
1761
1762 if (!var->bits_per_pixel) {
1763 switch (display->get_recommended_bpp(display)) {
1764 case 16:
1765 var->bits_per_pixel = 16;
1766 break;
1767 case 24:
1768 var->bits_per_pixel = 32;
1769 break;
1770 default:
1771 dev_err(fbdev->dev, "illegal display "
1772 "bpp\n");
1773 return -EINVAL;
1774 }
1775 }
1776 } else {
1777 /* if there's no display, let's just guess some basic values */
1778 var->xres = 320;
1779 var->yres = 240;
1780 var->xres_virtual = var->xres;
1781 var->yres_virtual = var->yres;
1782 if (!var->bits_per_pixel)
1783 var->bits_per_pixel = 16;
1784 }
1785
1786 r = check_fb_var(fbi, var);
1787 if (r)
1788 goto err;
1789
1790 set_fb_fix(fbi);
1791 r = setup_vrfb_rotation(fbi);
1792 if (r)
1793 goto err;
1794
1795 r = fb_alloc_cmap(&fbi->cmap, 256, 0);
1796 if (r)
1797 dev_err(fbdev->dev, "unable to allocate color map memory\n");
1798
1799err:
1800 return r;
1801}
1802
1803static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)
1804{
1805 fb_dealloc_cmap(&fbi->cmap);
1806}
1807
1808
1809static void omapfb_free_resources(struct omapfb2_device *fbdev)
1810{
1811 int i;
1812
1813 DBG("free_resources\n");
1814
1815 if (fbdev == NULL)
1816 return;
1817
1818 for (i = 0; i < fbdev->num_fbs; i++)
1819 unregister_framebuffer(fbdev->fbs[i]);
1820
1821 /* free the reserved fbmem */
1822 omapfb_free_all_fbmem(fbdev);
1823
1824 for (i = 0; i < fbdev->num_fbs; i++) {
1825 fbinfo_cleanup(fbdev, fbdev->fbs[i]);
1826 framebuffer_release(fbdev->fbs[i]);
1827 }
1828
1829 for (i = 0; i < fbdev->num_displays; i++) {
1830 if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)
1831 fbdev->displays[i]->disable(fbdev->displays[i]);
1832
1833 omap_dss_put_device(fbdev->displays[i]);
1834 }
1835
1836 dev_set_drvdata(fbdev->dev, NULL);
1837 kfree(fbdev);
1838}
1839
1840static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)
1841{
1842 int r, i;
1843
1844 fbdev->num_fbs = 0;
1845
1846 DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);
1847
1848 /* allocate fb_infos */
1849 for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {
1850 struct fb_info *fbi;
1851 struct omapfb_info *ofbi;
1852
1853 fbi = framebuffer_alloc(sizeof(struct omapfb_info),
1854 fbdev->dev);
1855
1856 if (fbi == NULL) {
1857 dev_err(fbdev->dev,
1858 "unable to allocate memory for plane info\n");
1859 return -ENOMEM;
1860 }
1861
1862 clear_fb_info(fbi);
1863
1864 fbdev->fbs[i] = fbi;
1865
1866 ofbi = FB2OFB(fbi);
1867 ofbi->fbdev = fbdev;
1868 ofbi->id = i;
1869
1870 /* assign these early, so that fb alloc can use them */
1871 ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :
1872 OMAP_DSS_ROT_DMA;
1873 ofbi->mirror = def_mirror;
1874
1875 fbdev->num_fbs++;
1876 }
1877
1878 DBG("fb_infos allocated\n");
1879
1880 /* assign overlays for the fbs */
1881 for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {
1882 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
1883
1884 ofbi->overlays[0] = fbdev->overlays[i];
1885 ofbi->num_overlays = 1;
1886 }
1887
1888 /* allocate fb memories */
1889 r = omapfb_allocate_all_fbs(fbdev);
1890 if (r) {
1891 dev_err(fbdev->dev, "failed to allocate fbmem\n");
1892 return r;
1893 }
1894
1895 DBG("fbmems allocated\n");
1896
1897 /* setup fb_infos */
1898 for (i = 0; i < fbdev->num_fbs; i++) {
1899 r = omapfb_fb_init(fbdev, fbdev->fbs[i]);
1900 if (r) {
1901 dev_err(fbdev->dev, "failed to setup fb_info\n");
1902 return r;
1903 }
1904 }
1905
1906 DBG("fb_infos initialized\n");
1907
1908 for (i = 0; i < fbdev->num_fbs; i++) {
1909 r = register_framebuffer(fbdev->fbs[i]);
1910 if (r != 0) {
1911 dev_err(fbdev->dev,
1912 "registering framebuffer %d failed\n", i);
1913 return r;
1914 }
1915 }
1916
1917 DBG("framebuffers registered\n");
1918
1919 for (i = 0; i < fbdev->num_fbs; i++) {
1920 r = omapfb_apply_changes(fbdev->fbs[i], 1);
1921 if (r) {
1922 dev_err(fbdev->dev, "failed to change mode\n");
1923 return r;
1924 }
1925 }
1926
1927 DBG("create sysfs for fbs\n");
1928 r = omapfb_create_sysfs(fbdev);
1929 if (r) {
1930 dev_err(fbdev->dev, "failed to create sysfs entries\n");
1931 return r;
1932 }
1933
1934 /* Enable fb0 */
1935 if (fbdev->num_fbs > 0) {
1936 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);
1937
1938 if (ofbi->num_overlays > 0) {
1939 struct omap_overlay *ovl = ofbi->overlays[0];
1940
1941 r = omapfb_overlay_enable(ovl, 1);
1942
1943 if (r) {
1944 dev_err(fbdev->dev,
1945 "failed to enable overlay\n");
1946 return r;
1947 }
1948 }
1949 }
1950
1951 DBG("create_framebuffers done\n");
1952
1953 return 0;
1954}
1955
1956static int omapfb_mode_to_timings(const char *mode_str,
1957 struct omap_video_timings *timings, u8 *bpp)
1958{
1959 struct fb_info fbi;
1960 struct fb_var_screeninfo var;
1961 struct fb_ops fbops;
1962 int r;
1963
1964#ifdef CONFIG_OMAP2_DSS_VENC
1965 if (strcmp(mode_str, "pal") == 0) {
1966 *timings = omap_dss_pal_timings;
1967 *bpp = 0;
1968 return 0;
1969 } else if (strcmp(mode_str, "ntsc") == 0) {
1970 *timings = omap_dss_ntsc_timings;
1971 *bpp = 0;
1972 return 0;
1973 }
1974#endif
1975
1976 /* this is quite a hack, but I wanted to use the modedb and for
1977 * that we need fb_info and var, so we create dummy ones */
1978
1979 memset(&fbi, 0, sizeof(fbi));
1980 memset(&var, 0, sizeof(var));
1981 memset(&fbops, 0, sizeof(fbops));
1982 fbi.fbops = &fbops;
1983
1984 r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);
1985
1986 if (r != 0) {
1987 timings->pixel_clock = PICOS2KHZ(var.pixclock);
1988 timings->hfp = var.left_margin;
1989 timings->hbp = var.right_margin;
1990 timings->vfp = var.upper_margin;
1991 timings->vbp = var.lower_margin;
1992 timings->hsw = var.hsync_len;
1993 timings->vsw = var.vsync_len;
1994 timings->x_res = var.xres;
1995 timings->y_res = var.yres;
1996
1997 switch (var.bits_per_pixel) {
1998 case 16:
1999 *bpp = 16;
2000 break;
2001 case 24:
2002 case 32:
2003 default:
2004 *bpp = 24;
2005 break;
2006 }
2007
2008 return 0;
2009 } else {
2010 return -EINVAL;
2011 }
2012}
2013
2014static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)
2015{
2016 int r;
2017 u8 bpp;
2018 struct omap_video_timings timings;
2019
2020 r = omapfb_mode_to_timings(mode_str, &timings, &bpp);
2021 if (r)
2022 return r;
2023
2024 display->panel.recommended_bpp = bpp;
2025
2026 if (!display->check_timings || !display->set_timings)
2027 return -EINVAL;
2028
2029 r = display->check_timings(display, &timings);
2030 if (r)
2031 return r;
2032
2033 display->set_timings(display, &timings);
2034
2035 return 0;
2036}
2037
2038static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)
2039{
2040 char *str, *options, *this_opt;
2041 int r = 0;
2042
2043 str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);
2044 strcpy(str, def_mode);
2045 options = str;
2046
2047 while (!r && (this_opt = strsep(&options, ",")) != NULL) {
2048 char *p, *display_str, *mode_str;
2049 struct omap_dss_device *display;
2050 int i;
2051
2052 p = strchr(this_opt, ':');
2053 if (!p) {
2054 r = -EINVAL;
2055 break;
2056 }
2057
2058 *p = 0;
2059 display_str = this_opt;
2060 mode_str = p + 1;
2061
2062 display = NULL;
2063 for (i = 0; i < fbdev->num_displays; ++i) {
2064 if (strcmp(fbdev->displays[i]->name,
2065 display_str) == 0) {
2066 display = fbdev->displays[i];
2067 break;
2068 }
2069 }
2070
2071 if (!display) {
2072 r = -EINVAL;
2073 break;
2074 }
2075
2076 r = omapfb_set_def_mode(display, mode_str);
2077 if (r)
2078 break;
2079 }
2080
2081 kfree(str);
2082
2083 return r;
2084}
2085
2086static int omapfb_probe(struct platform_device *pdev)
2087{
2088 struct omapfb2_device *fbdev = NULL;
2089 int r = 0;
2090 int i;
2091 struct omap_overlay *ovl;
2092 struct omap_dss_device *def_display;
2093 struct omap_dss_device *dssdev;
2094
2095 DBG("omapfb_probe\n");
2096
2097 if (pdev->num_resources != 0) {
2098 dev_err(&pdev->dev, "probed for an unknown device\n");
2099 r = -ENODEV;
2100 goto err0;
2101 }
2102
2103 fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);
2104 if (fbdev == NULL) {
2105 r = -ENOMEM;
2106 goto err0;
2107 }
2108
2109 mutex_init(&fbdev->mtx);
2110
2111 fbdev->dev = &pdev->dev;
2112 platform_set_drvdata(pdev, fbdev);
2113
2114 fbdev->num_displays = 0;
2115 dssdev = NULL;
2116 for_each_dss_dev(dssdev) {
2117 omap_dss_get_device(dssdev);
2118 if (!dssdev->driver) {
2119 dev_err(&pdev->dev, "no driver for display\n");
2120 r = -EINVAL;
2121 goto cleanup;
2122 }
2123 fbdev->displays[fbdev->num_displays++] = dssdev;
2124 }
2125
2126 if (fbdev->num_displays == 0) {
2127 dev_err(&pdev->dev, "no displays\n");
2128 r = -EINVAL;
2129 goto cleanup;
2130 }
2131
2132 fbdev->num_overlays = omap_dss_get_num_overlays();
2133 for (i = 0; i < fbdev->num_overlays; i++)
2134 fbdev->overlays[i] = omap_dss_get_overlay(i);
2135
2136 fbdev->num_managers = omap_dss_get_num_overlay_managers();
2137 for (i = 0; i < fbdev->num_managers; i++)
2138 fbdev->managers[i] = omap_dss_get_overlay_manager(i);
2139
2140 if (def_mode && strlen(def_mode) > 0) {
2141 if (omapfb_parse_def_modes(fbdev))
2142 dev_warn(&pdev->dev, "cannot parse default modes\n");
2143 }
2144
2145 r = omapfb_create_framebuffers(fbdev);
2146 if (r)
2147 goto cleanup;
2148
2149 for (i = 0; i < fbdev->num_managers; i++) {
2150 struct omap_overlay_manager *mgr;
2151 mgr = fbdev->managers[i];
2152 r = mgr->apply(mgr);
2153 if (r)
2154 dev_warn(fbdev->dev, "failed to apply dispc config\n");
2155 }
2156
2157 DBG("mgr->apply'ed\n");
2158
2159 /* gfx overlay should be the default one. find a display
2160 * connected to that, and use it as default display */
2161 ovl = omap_dss_get_overlay(0);
2162 if (ovl->manager && ovl->manager->device) {
2163 def_display = ovl->manager->device;
2164 } else {
2165 dev_warn(&pdev->dev, "cannot find default display\n");
2166 def_display = NULL;
2167 }
2168
2169 if (def_display) {
2170#ifndef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2171 u16 w, h;
2172#endif
2173 r = def_display->enable(def_display);
2174 if (r)
2175 dev_warn(fbdev->dev, "Failed to enable display '%s'\n",
2176 def_display->name);
2177
2178 /* set the update mode */
2179 if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
2180#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
2181 if (def_display->enable_te)
2182 def_display->enable_te(def_display, 1);
2183 if (def_display->set_update_mode)
2184 def_display->set_update_mode(def_display,
2185 OMAP_DSS_UPDATE_AUTO);
2186#else /* MANUAL_UPDATE */
2187 if (def_display->enable_te)
2188 def_display->enable_te(def_display, 0);
2189 if (def_display->set_update_mode)
2190 def_display->set_update_mode(def_display,
2191 OMAP_DSS_UPDATE_MANUAL);
2192
2193 def_display->get_resolution(def_display, &w, &h);
2194 def_display->update(def_display, 0, 0, w, h);
2195#endif
2196 } else {
2197 if (def_display->set_update_mode)
2198 def_display->set_update_mode(def_display,
2199 OMAP_DSS_UPDATE_AUTO);
2200 }
2201 }
2202
2203 return 0;
2204
2205cleanup:
2206 omapfb_free_resources(fbdev);
2207err0:
2208 dev_err(&pdev->dev, "failed to setup omapfb\n");
2209 return r;
2210}
2211
2212static int omapfb_remove(struct platform_device *pdev)
2213{
2214 struct omapfb2_device *fbdev = platform_get_drvdata(pdev);
2215
2216 /* FIXME: wait till completion of pending events */
2217
2218 omapfb_remove_sysfs(fbdev);
2219
2220 omapfb_free_resources(fbdev);
2221
2222 return 0;
2223}
2224
2225static struct platform_driver omapfb_driver = {
2226 .probe = omapfb_probe,
2227 .remove = omapfb_remove,
2228 .driver = {
2229 .name = "omapfb",
2230 .owner = THIS_MODULE,
2231 },
2232};
2233
2234static int __init omapfb_init(void)
2235{
2236 DBG("omapfb_init\n");
2237
2238 if (platform_driver_register(&omapfb_driver)) {
2239 printk(KERN_ERR "failed to register omapfb driver\n");
2240 return -ENODEV;
2241 }
2242
2243 return 0;
2244}
2245
2246static void __exit omapfb_exit(void)
2247{
2248 DBG("omapfb_exit\n");
2249 platform_driver_unregister(&omapfb_driver);
2250}
2251
2252module_param_named(mode, def_mode, charp, 0);
2253module_param_named(vram, def_vram, charp, 0);
2254module_param_named(rotate, def_rotate, int, 0);
2255module_param_named(vrfb, def_vrfb, bool, 0);
2256module_param_named(mirror, def_mirror, bool, 0);
2257
2258/* late_initcall to let panel/ctrl drivers loaded first.
2259 * I guess better option would be a more dynamic approach,
2260 * so that omapfb reacts to new panels when they are loaded */
2261late_initcall(omapfb_init);
2262/*module_init(omapfb_init);*/
2263module_exit(omapfb_exit);
2264
2265MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");
2266MODULE_DESCRIPTION("OMAP2/3 Framebuffer");
2267MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c
new file mode 100644
index 000000000000..62bb88f5c192
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c
@@ -0,0 +1,507 @@
1/*
2 * linux/drivers/video/omap2/omapfb-sysfs.c
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include <linux/fb.h>
24#include <linux/sysfs.h>
25#include <linux/device.h>
26#include <linux/uaccess.h>
27#include <linux/platform_device.h>
28#include <linux/kernel.h>
29#include <linux/mm.h>
30#include <linux/omapfb.h>
31
32#include <plat/display.h>
33#include <plat/vrfb.h>
34
35#include "omapfb.h"
36
37static ssize_t show_rotate_type(struct device *dev,
38 struct device_attribute *attr, char *buf)
39{
40 struct fb_info *fbi = dev_get_drvdata(dev);
41 struct omapfb_info *ofbi = FB2OFB(fbi);
42
43 return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
44}
45
46static ssize_t store_rotate_type(struct device *dev,
47 struct device_attribute *attr,
48 const char *buf, size_t count)
49{
50 struct fb_info *fbi = dev_get_drvdata(dev);
51 struct omapfb_info *ofbi = FB2OFB(fbi);
52 enum omap_dss_rotation_type rot_type;
53 int r;
54
55 rot_type = simple_strtoul(buf, NULL, 0);
56
57 if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
58 return -EINVAL;
59
60 lock_fb_info(fbi);
61
62 r = 0;
63 if (rot_type == ofbi->rotation_type)
64 goto out;
65
66 if (ofbi->region.size) {
67 r = -EBUSY;
68 goto out;
69 }
70
71 ofbi->rotation_type = rot_type;
72
73 /*
74 * Since the VRAM for this FB is not allocated at the moment we don't
75 * need to do any further parameter checking at this point.
76 */
77out:
78 unlock_fb_info(fbi);
79
80 return r ? r : count;
81}
82
83
84static ssize_t show_mirror(struct device *dev,
85 struct device_attribute *attr, char *buf)
86{
87 struct fb_info *fbi = dev_get_drvdata(dev);
88 struct omapfb_info *ofbi = FB2OFB(fbi);
89
90 return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
91}
92
93static ssize_t store_mirror(struct device *dev,
94 struct device_attribute *attr,
95 const char *buf, size_t count)
96{
97 struct fb_info *fbi = dev_get_drvdata(dev);
98 struct omapfb_info *ofbi = FB2OFB(fbi);
99 bool mirror;
100 int r;
101 struct fb_var_screeninfo new_var;
102
103 mirror = simple_strtoul(buf, NULL, 0);
104
105 if (mirror != 0 && mirror != 1)
106 return -EINVAL;
107
108 lock_fb_info(fbi);
109
110 ofbi->mirror = mirror;
111
112 memcpy(&new_var, &fbi->var, sizeof(new_var));
113 r = check_fb_var(fbi, &new_var);
114 if (r)
115 goto out;
116 memcpy(&fbi->var, &new_var, sizeof(fbi->var));
117
118 set_fb_fix(fbi);
119
120 r = omapfb_apply_changes(fbi, 0);
121 if (r)
122 goto out;
123
124 r = count;
125out:
126 unlock_fb_info(fbi);
127
128 return r;
129}
130
131static ssize_t show_overlays(struct device *dev,
132 struct device_attribute *attr, char *buf)
133{
134 struct fb_info *fbi = dev_get_drvdata(dev);
135 struct omapfb_info *ofbi = FB2OFB(fbi);
136 struct omapfb2_device *fbdev = ofbi->fbdev;
137 ssize_t l = 0;
138 int t;
139
140 omapfb_lock(fbdev);
141 lock_fb_info(fbi);
142
143 for (t = 0; t < ofbi->num_overlays; t++) {
144 struct omap_overlay *ovl = ofbi->overlays[t];
145 int ovlnum;
146
147 for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
148 if (ovl == fbdev->overlays[ovlnum])
149 break;
150
151 l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
152 t == 0 ? "" : ",", ovlnum);
153 }
154
155 l += snprintf(buf + l, PAGE_SIZE - l, "\n");
156
157 unlock_fb_info(fbi);
158 omapfb_unlock(fbdev);
159
160 return l;
161}
162
163static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
164 struct omap_overlay *ovl)
165{
166 int i, t;
167
168 for (i = 0; i < fbdev->num_fbs; i++) {
169 struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
170
171 for (t = 0; t < ofbi->num_overlays; t++) {
172 if (ofbi->overlays[t] == ovl)
173 return ofbi;
174 }
175 }
176
177 return NULL;
178}
179
180static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
181 const char *buf, size_t count)
182{
183 struct fb_info *fbi = dev_get_drvdata(dev);
184 struct omapfb_info *ofbi = FB2OFB(fbi);
185 struct omapfb2_device *fbdev = ofbi->fbdev;
186 struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
187 struct omap_overlay *ovl;
188 int num_ovls, r, i;
189 int len;
190 bool added = false;
191
192 num_ovls = 0;
193
194 len = strlen(buf);
195 if (buf[len - 1] == '\n')
196 len = len - 1;
197
198 omapfb_lock(fbdev);
199 lock_fb_info(fbi);
200
201 if (len > 0) {
202 char *p = (char *)buf;
203 int ovlnum;
204
205 while (p < buf + len) {
206 int found;
207 if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
208 r = -EINVAL;
209 goto out;
210 }
211
212 ovlnum = simple_strtoul(p, &p, 0);
213 if (ovlnum > fbdev->num_overlays) {
214 r = -EINVAL;
215 goto out;
216 }
217
218 found = 0;
219 for (i = 0; i < num_ovls; ++i) {
220 if (ovls[i] == fbdev->overlays[ovlnum]) {
221 found = 1;
222 break;
223 }
224 }
225
226 if (!found)
227 ovls[num_ovls++] = fbdev->overlays[ovlnum];
228
229 p++;
230 }
231 }
232
233 for (i = 0; i < num_ovls; ++i) {
234 struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
235 if (ofbi2 && ofbi2 != ofbi) {
236 dev_err(fbdev->dev, "overlay already in use\n");
237 r = -EINVAL;
238 goto out;
239 }
240 }
241
242 /* detach unused overlays */
243 for (i = 0; i < ofbi->num_overlays; ++i) {
244 int t, found;
245
246 ovl = ofbi->overlays[i];
247
248 found = 0;
249
250 for (t = 0; t < num_ovls; ++t) {
251 if (ovl == ovls[t]) {
252 found = 1;
253 break;
254 }
255 }
256
257 if (found)
258 continue;
259
260 DBG("detaching %d\n", ofbi->overlays[i]->id);
261
262 omapfb_overlay_enable(ovl, 0);
263
264 if (ovl->manager)
265 ovl->manager->apply(ovl->manager);
266
267 for (t = i + 1; t < ofbi->num_overlays; t++) {
268 ofbi->rotation[t-1] = ofbi->rotation[t];
269 ofbi->overlays[t-1] = ofbi->overlays[t];
270 }
271
272 ofbi->num_overlays--;
273 i--;
274 }
275
276 for (i = 0; i < num_ovls; ++i) {
277 int t, found;
278
279 ovl = ovls[i];
280
281 found = 0;
282
283 for (t = 0; t < ofbi->num_overlays; ++t) {
284 if (ovl == ofbi->overlays[t]) {
285 found = 1;
286 break;
287 }
288 }
289
290 if (found)
291 continue;
292 ofbi->rotation[ofbi->num_overlays] = 0;
293 ofbi->overlays[ofbi->num_overlays++] = ovl;
294
295 added = true;
296 }
297
298 if (added) {
299 r = omapfb_apply_changes(fbi, 0);
300 if (r)
301 goto out;
302 }
303
304 r = count;
305out:
306 unlock_fb_info(fbi);
307 omapfb_unlock(fbdev);
308
309 return r;
310}
311
312static ssize_t show_overlays_rotate(struct device *dev,
313 struct device_attribute *attr, char *buf)
314{
315 struct fb_info *fbi = dev_get_drvdata(dev);
316 struct omapfb_info *ofbi = FB2OFB(fbi);
317 ssize_t l = 0;
318 int t;
319
320 lock_fb_info(fbi);
321
322 for (t = 0; t < ofbi->num_overlays; t++) {
323 l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
324 t == 0 ? "" : ",", ofbi->rotation[t]);
325 }
326
327 l += snprintf(buf + l, PAGE_SIZE - l, "\n");
328
329 unlock_fb_info(fbi);
330
331 return l;
332}
333
334static ssize_t store_overlays_rotate(struct device *dev,
335 struct device_attribute *attr, const char *buf, size_t count)
336{
337 struct fb_info *fbi = dev_get_drvdata(dev);
338 struct omapfb_info *ofbi = FB2OFB(fbi);
339 int num_ovls = 0, r, i;
340 int len;
341 bool changed = false;
342 u8 rotation[OMAPFB_MAX_OVL_PER_FB];
343
344 len = strlen(buf);
345 if (buf[len - 1] == '\n')
346 len = len - 1;
347
348 lock_fb_info(fbi);
349
350 if (len > 0) {
351 char *p = (char *)buf;
352
353 while (p < buf + len) {
354 int rot;
355
356 if (num_ovls == ofbi->num_overlays) {
357 r = -EINVAL;
358 goto out;
359 }
360
361 rot = simple_strtoul(p, &p, 0);
362 if (rot < 0 || rot > 3) {
363 r = -EINVAL;
364 goto out;
365 }
366
367 if (ofbi->rotation[num_ovls] != rot)
368 changed = true;
369
370 rotation[num_ovls++] = rot;
371
372 p++;
373 }
374 }
375
376 if (num_ovls != ofbi->num_overlays) {
377 r = -EINVAL;
378 goto out;
379 }
380
381 if (changed) {
382 for (i = 0; i < num_ovls; ++i)
383 ofbi->rotation[i] = rotation[i];
384
385 r = omapfb_apply_changes(fbi, 0);
386 if (r)
387 goto out;
388
389 /* FIXME error handling? */
390 }
391
392 r = count;
393out:
394 unlock_fb_info(fbi);
395
396 return r;
397}
398
399static ssize_t show_size(struct device *dev,
400 struct device_attribute *attr, char *buf)
401{
402 struct fb_info *fbi = dev_get_drvdata(dev);
403 struct omapfb_info *ofbi = FB2OFB(fbi);
404
405 return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);
406}
407
408static ssize_t store_size(struct device *dev, struct device_attribute *attr,
409 const char *buf, size_t count)
410{
411 struct fb_info *fbi = dev_get_drvdata(dev);
412 struct omapfb_info *ofbi = FB2OFB(fbi);
413 unsigned long size;
414 int r;
415 int i;
416
417 size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));
418
419 lock_fb_info(fbi);
420
421 for (i = 0; i < ofbi->num_overlays; i++) {
422 if (ofbi->overlays[i]->info.enabled) {
423 r = -EBUSY;
424 goto out;
425 }
426 }
427
428 if (size != ofbi->region.size) {
429 r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);
430 if (r) {
431 dev_err(dev, "realloc fbmem failed\n");
432 goto out;
433 }
434 }
435
436 r = count;
437out:
438 unlock_fb_info(fbi);
439
440 return r;
441}
442
443static ssize_t show_phys(struct device *dev,
444 struct device_attribute *attr, char *buf)
445{
446 struct fb_info *fbi = dev_get_drvdata(dev);
447 struct omapfb_info *ofbi = FB2OFB(fbi);
448
449 return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);
450}
451
452static ssize_t show_virt(struct device *dev,
453 struct device_attribute *attr, char *buf)
454{
455 struct fb_info *fbi = dev_get_drvdata(dev);
456 struct omapfb_info *ofbi = FB2OFB(fbi);
457
458 return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);
459}
460
461static struct device_attribute omapfb_attrs[] = {
462 __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
463 store_rotate_type),
464 __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
465 __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
466 __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
467 __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
468 store_overlays_rotate),
469 __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
470 __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
471};
472
473int omapfb_create_sysfs(struct omapfb2_device *fbdev)
474{
475 int i;
476 int r;
477
478 DBG("create sysfs for fbs\n");
479 for (i = 0; i < fbdev->num_fbs; i++) {
480 int t;
481 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
482 r = device_create_file(fbdev->fbs[i]->dev,
483 &omapfb_attrs[t]);
484
485 if (r) {
486 dev_err(fbdev->dev, "failed to create sysfs "
487 "file\n");
488 return r;
489 }
490 }
491 }
492
493 return 0;
494}
495
496void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
497{
498 int i, t;
499
500 DBG("remove sysfs for fbs\n");
501 for (i = 0; i < fbdev->num_fbs; i++) {
502 for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
503 device_remove_file(fbdev->fbs[i]->dev,
504 &omapfb_attrs[t]);
505 }
506}
507
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
new file mode 100644
index 000000000000..f7c9c739e5ef
--- /dev/null
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -0,0 +1,146 @@
1/*
2 * linux/drivers/video/omap2/omapfb.h
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
24#define __DRIVERS_VIDEO_OMAP2_OMAPFB_H__
25
26#ifdef CONFIG_FB_OMAP2_DEBUG_SUPPORT
27#define DEBUG
28#endif
29
30#include <plat/display.h>
31
32#ifdef DEBUG
33extern unsigned int omapfb_debug;
34#define DBG(format, ...) \
35 if (omapfb_debug) \
36 printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)
37#else
38#define DBG(format, ...)
39#endif
40
41#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
42
43/* max number of overlays to which a framebuffer data can be direct */
44#define OMAPFB_MAX_OVL_PER_FB 3
45
46struct omapfb2_mem_region {
47 u32 paddr;
48 void __iomem *vaddr;
49 struct vrfb vrfb;
50 unsigned long size;
51 u8 type; /* OMAPFB_PLANE_MEM_* */
52 bool alloc; /* allocated by the driver */
53 bool map; /* kernel mapped by the driver */
54};
55
56/* appended to fb_info */
57struct omapfb_info {
58 int id;
59 struct omapfb2_mem_region region;
60 atomic_t map_count;
61 int num_overlays;
62 struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];
63 struct omapfb2_device *fbdev;
64 enum omap_dss_rotation_type rotation_type;
65 u8 rotation[OMAPFB_MAX_OVL_PER_FB];
66 bool mirror;
67};
68
69struct omapfb2_device {
70 struct device *dev;
71 struct mutex mtx;
72
73 u32 pseudo_palette[17];
74
75 int state;
76
77 unsigned num_fbs;
78 struct fb_info *fbs[10];
79
80 unsigned num_displays;
81 struct omap_dss_device *displays[10];
82 unsigned num_overlays;
83 struct omap_overlay *overlays[10];
84 unsigned num_managers;
85 struct omap_overlay_manager *managers[10];
86};
87
88struct omapfb_colormode {
89 enum omap_color_mode dssmode;
90 u32 bits_per_pixel;
91 u32 nonstd;
92 struct fb_bitfield red;
93 struct fb_bitfield green;
94 struct fb_bitfield blue;
95 struct fb_bitfield transp;
96};
97
98void set_fb_fix(struct fb_info *fbi);
99int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var);
100int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type);
101int omapfb_apply_changes(struct fb_info *fbi, int init);
102
103int omapfb_create_sysfs(struct omapfb2_device *fbdev);
104void omapfb_remove_sysfs(struct omapfb2_device *fbdev);
105
106int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);
107
108int dss_mode_to_fb_mode(enum omap_color_mode dssmode,
109 struct fb_var_screeninfo *var);
110
111/* find the display connected to this fb, if any */
112static inline struct omap_dss_device *fb2display(struct fb_info *fbi)
113{
114 struct omapfb_info *ofbi = FB2OFB(fbi);
115 int i;
116
117 /* XXX: returns the display connected to first attached overlay */
118 for (i = 0; i < ofbi->num_overlays; i++) {
119 if (ofbi->overlays[i]->manager)
120 return ofbi->overlays[i]->manager->device;
121 }
122
123 return NULL;
124}
125
126static inline void omapfb_lock(struct omapfb2_device *fbdev)
127{
128 mutex_lock(&fbdev->mtx);
129}
130
131static inline void omapfb_unlock(struct omapfb2_device *fbdev)
132{
133 mutex_unlock(&fbdev->mtx);
134}
135
136static inline int omapfb_overlay_enable(struct omap_overlay *ovl,
137 int enable)
138{
139 struct omap_overlay_info info;
140
141 ovl->get_overlay_info(ovl, &info);
142 info.enabled = enable;
143 return ovl->set_overlay_info(ovl, &info);
144}
145
146#endif
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c
new file mode 100644
index 000000000000..55a4de5e5d10
--- /dev/null
+++ b/drivers/video/omap2/vram.c
@@ -0,0 +1,655 @@
1/*
2 * VRAM manager for OMAP
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21/*#define DEBUG*/
22
23#include <linux/kernel.h>
24#include <linux/mm.h>
25#include <linux/list.h>
26#include <linux/seq_file.h>
27#include <linux/bootmem.h>
28#include <linux/completion.h>
29#include <linux/debugfs.h>
30#include <linux/jiffies.h>
31#include <linux/module.h>
32
33#include <asm/setup.h>
34
35#include <plat/sram.h>
36#include <plat/vram.h>
37#include <plat/dma.h>
38
39#ifdef DEBUG
40#define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__)
41#else
42#define DBG(format, ...)
43#endif
44
45#define OMAP2_SRAM_START 0x40200000
46/* Maximum size, in reality this is smaller if SRAM is partially locked. */
47#define OMAP2_SRAM_SIZE 0xa0000 /* 640k */
48
49/* postponed regions are used to temporarily store region information at boot
50 * time when we cannot yet allocate the region list */
51#define MAX_POSTPONED_REGIONS 10
52
53static bool vram_initialized;
54static int postponed_cnt;
55static struct {
56 unsigned long paddr;
57 size_t size;
58} postponed_regions[MAX_POSTPONED_REGIONS];
59
60struct vram_alloc {
61 struct list_head list;
62 unsigned long paddr;
63 unsigned pages;
64};
65
66struct vram_region {
67 struct list_head list;
68 struct list_head alloc_list;
69 unsigned long paddr;
70 unsigned pages;
71};
72
73static DEFINE_MUTEX(region_mutex);
74static LIST_HEAD(region_list);
75
76static inline int region_mem_type(unsigned long paddr)
77{
78 if (paddr >= OMAP2_SRAM_START &&
79 paddr < OMAP2_SRAM_START + OMAP2_SRAM_SIZE)
80 return OMAP_VRAM_MEMTYPE_SRAM;
81 else
82 return OMAP_VRAM_MEMTYPE_SDRAM;
83}
84
85static struct vram_region *omap_vram_create_region(unsigned long paddr,
86 unsigned pages)
87{
88 struct vram_region *rm;
89
90 rm = kzalloc(sizeof(*rm), GFP_KERNEL);
91
92 if (rm) {
93 INIT_LIST_HEAD(&rm->alloc_list);
94 rm->paddr = paddr;
95 rm->pages = pages;
96 }
97
98 return rm;
99}
100
101#if 0
102static void omap_vram_free_region(struct vram_region *vr)
103{
104 list_del(&vr->list);
105 kfree(vr);
106}
107#endif
108
109static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr,
110 unsigned long paddr, unsigned pages)
111{
112 struct vram_alloc *va;
113 struct vram_alloc *new;
114
115 new = kzalloc(sizeof(*va), GFP_KERNEL);
116
117 if (!new)
118 return NULL;
119
120 new->paddr = paddr;
121 new->pages = pages;
122
123 list_for_each_entry(va, &vr->alloc_list, list) {
124 if (va->paddr > new->paddr)
125 break;
126 }
127
128 list_add_tail(&new->list, &va->list);
129
130 return new;
131}
132
133static void omap_vram_free_allocation(struct vram_alloc *va)
134{
135 list_del(&va->list);
136 kfree(va);
137}
138
139int omap_vram_add_region(unsigned long paddr, size_t size)
140{
141 struct vram_region *rm;
142 unsigned pages;
143
144 if (vram_initialized) {
145 DBG("adding region paddr %08lx size %d\n",
146 paddr, size);
147
148 size &= PAGE_MASK;
149 pages = size >> PAGE_SHIFT;
150
151 rm = omap_vram_create_region(paddr, pages);
152 if (rm == NULL)
153 return -ENOMEM;
154
155 list_add(&rm->list, &region_list);
156 } else {
157 if (postponed_cnt == MAX_POSTPONED_REGIONS)
158 return -ENOMEM;
159
160 postponed_regions[postponed_cnt].paddr = paddr;
161 postponed_regions[postponed_cnt].size = size;
162
163 ++postponed_cnt;
164 }
165 return 0;
166}
167
168int omap_vram_free(unsigned long paddr, size_t size)
169{
170 struct vram_region *rm;
171 struct vram_alloc *alloc;
172 unsigned start, end;
173
174 DBG("free mem paddr %08lx size %d\n", paddr, size);
175
176 size = PAGE_ALIGN(size);
177
178 mutex_lock(&region_mutex);
179
180 list_for_each_entry(rm, &region_list, list) {
181 list_for_each_entry(alloc, &rm->alloc_list, list) {
182 start = alloc->paddr;
183 end = alloc->paddr + (alloc->pages >> PAGE_SHIFT);
184
185 if (start >= paddr && end < paddr + size)
186 goto found;
187 }
188 }
189
190 mutex_unlock(&region_mutex);
191 return -EINVAL;
192
193found:
194 omap_vram_free_allocation(alloc);
195
196 mutex_unlock(&region_mutex);
197 return 0;
198}
199EXPORT_SYMBOL(omap_vram_free);
200
201static int _omap_vram_reserve(unsigned long paddr, unsigned pages)
202{
203 struct vram_region *rm;
204 struct vram_alloc *alloc;
205 size_t size;
206
207 size = pages << PAGE_SHIFT;
208
209 list_for_each_entry(rm, &region_list, list) {
210 unsigned long start, end;
211
212 DBG("checking region %lx %d\n", rm->paddr, rm->pages);
213
214 if (region_mem_type(rm->paddr) != region_mem_type(paddr))
215 continue;
216
217 start = rm->paddr;
218 end = start + (rm->pages << PAGE_SHIFT) - 1;
219 if (start > paddr || end < paddr + size - 1)
220 continue;
221
222 DBG("block ok, checking allocs\n");
223
224 list_for_each_entry(alloc, &rm->alloc_list, list) {
225 end = alloc->paddr - 1;
226
227 if (start <= paddr && end >= paddr + size - 1)
228 goto found;
229
230 start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
231 }
232
233 end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1;
234
235 if (!(start <= paddr && end >= paddr + size - 1))
236 continue;
237found:
238 DBG("found area start %lx, end %lx\n", start, end);
239
240 if (omap_vram_create_allocation(rm, paddr, pages) == NULL)
241 return -ENOMEM;
242
243 return 0;
244 }
245
246 return -ENOMEM;
247}
248
249int omap_vram_reserve(unsigned long paddr, size_t size)
250{
251 unsigned pages;
252 int r;
253
254 DBG("reserve mem paddr %08lx size %d\n", paddr, size);
255
256 size = PAGE_ALIGN(size);
257 pages = size >> PAGE_SHIFT;
258
259 mutex_lock(&region_mutex);
260
261 r = _omap_vram_reserve(paddr, pages);
262
263 mutex_unlock(&region_mutex);
264
265 return r;
266}
267EXPORT_SYMBOL(omap_vram_reserve);
268
269static void _omap_vram_dma_cb(int lch, u16 ch_status, void *data)
270{
271 struct completion *compl = data;
272 complete(compl);
273}
274
275static int _omap_vram_clear(u32 paddr, unsigned pages)
276{
277 struct completion compl;
278 unsigned elem_count;
279 unsigned frame_count;
280 int r;
281 int lch;
282
283 init_completion(&compl);
284
285 r = omap_request_dma(OMAP_DMA_NO_DEVICE, "VRAM DMA",
286 _omap_vram_dma_cb,
287 &compl, &lch);
288 if (r) {
289 pr_err("VRAM: request_dma failed for memory clear\n");
290 return -EBUSY;
291 }
292
293 elem_count = pages * PAGE_SIZE / 4;
294 frame_count = 1;
295
296 omap_set_dma_transfer_params(lch, OMAP_DMA_DATA_TYPE_S32,
297 elem_count, frame_count,
298 OMAP_DMA_SYNC_ELEMENT,
299 0, 0);
300
301 omap_set_dma_dest_params(lch, 0, OMAP_DMA_AMODE_POST_INC,
302 paddr, 0, 0);
303
304 omap_set_dma_color_mode(lch, OMAP_DMA_CONSTANT_FILL, 0x000000);
305
306 omap_start_dma(lch);
307
308 if (wait_for_completion_timeout(&compl, msecs_to_jiffies(1000)) == 0) {
309 omap_stop_dma(lch);
310 pr_err("VRAM: dma timeout while clearing memory\n");
311 r = -EIO;
312 goto err;
313 }
314
315 r = 0;
316err:
317 omap_free_dma(lch);
318
319 return r;
320}
321
322static int _omap_vram_alloc(int mtype, unsigned pages, unsigned long *paddr)
323{
324 struct vram_region *rm;
325 struct vram_alloc *alloc;
326
327 list_for_each_entry(rm, &region_list, list) {
328 unsigned long start, end;
329
330 DBG("checking region %lx %d\n", rm->paddr, rm->pages);
331
332 if (region_mem_type(rm->paddr) != mtype)
333 continue;
334
335 start = rm->paddr;
336
337 list_for_each_entry(alloc, &rm->alloc_list, list) {
338 end = alloc->paddr;
339
340 if (end - start >= pages << PAGE_SHIFT)
341 goto found;
342
343 start = alloc->paddr + (alloc->pages << PAGE_SHIFT);
344 }
345
346 end = rm->paddr + (rm->pages << PAGE_SHIFT);
347found:
348 if (end - start < pages << PAGE_SHIFT)
349 continue;
350
351 DBG("found %lx, end %lx\n", start, end);
352
353 alloc = omap_vram_create_allocation(rm, start, pages);
354 if (alloc == NULL)
355 return -ENOMEM;
356
357 *paddr = start;
358
359 _omap_vram_clear(start, pages);
360
361 return 0;
362 }
363
364 return -ENOMEM;
365}
366
367int omap_vram_alloc(int mtype, size_t size, unsigned long *paddr)
368{
369 unsigned pages;
370 int r;
371
372 BUG_ON(mtype > OMAP_VRAM_MEMTYPE_MAX || !size);
373
374 DBG("alloc mem type %d size %d\n", mtype, size);
375
376 size = PAGE_ALIGN(size);
377 pages = size >> PAGE_SHIFT;
378
379 mutex_lock(&region_mutex);
380
381 r = _omap_vram_alloc(mtype, pages, paddr);
382
383 mutex_unlock(&region_mutex);
384
385 return r;
386}
387EXPORT_SYMBOL(omap_vram_alloc);
388
389void omap_vram_get_info(unsigned long *vram,
390 unsigned long *free_vram,
391 unsigned long *largest_free_block)
392{
393 struct vram_region *vr;
394 struct vram_alloc *va;
395
396 *vram = 0;
397 *free_vram = 0;
398 *largest_free_block = 0;
399
400 mutex_lock(&region_mutex);
401
402 list_for_each_entry(vr, &region_list, list) {
403 unsigned free;
404 unsigned long pa;
405
406 pa = vr->paddr;
407 *vram += vr->pages << PAGE_SHIFT;
408
409 list_for_each_entry(va, &vr->alloc_list, list) {
410 free = va->paddr - pa;
411 *free_vram += free;
412 if (free > *largest_free_block)
413 *largest_free_block = free;
414 pa = va->paddr + (va->pages << PAGE_SHIFT);
415 }
416
417 free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa;
418 *free_vram += free;
419 if (free > *largest_free_block)
420 *largest_free_block = free;
421 }
422
423 mutex_unlock(&region_mutex);
424}
425EXPORT_SYMBOL(omap_vram_get_info);
426
427#if defined(CONFIG_DEBUG_FS)
428static int vram_debug_show(struct seq_file *s, void *unused)
429{
430 struct vram_region *vr;
431 struct vram_alloc *va;
432 unsigned size;
433
434 mutex_lock(&region_mutex);
435
436 list_for_each_entry(vr, &region_list, list) {
437 size = vr->pages << PAGE_SHIFT;
438 seq_printf(s, "%08lx-%08lx (%d bytes)\n",
439 vr->paddr, vr->paddr + size - 1,
440 size);
441
442 list_for_each_entry(va, &vr->alloc_list, list) {
443 size = va->pages << PAGE_SHIFT;
444 seq_printf(s, " %08lx-%08lx (%d bytes)\n",
445 va->paddr, va->paddr + size - 1,
446 size);
447 }
448 }
449
450 mutex_unlock(&region_mutex);
451
452 return 0;
453}
454
455static int vram_debug_open(struct inode *inode, struct file *file)
456{
457 return single_open(file, vram_debug_show, inode->i_private);
458}
459
460static const struct file_operations vram_debug_fops = {
461 .open = vram_debug_open,
462 .read = seq_read,
463 .llseek = seq_lseek,
464 .release = single_release,
465};
466
467static int __init omap_vram_create_debugfs(void)
468{
469 struct dentry *d;
470
471 d = debugfs_create_file("vram", S_IRUGO, NULL,
472 NULL, &vram_debug_fops);
473 if (IS_ERR(d))
474 return PTR_ERR(d);
475
476 return 0;
477}
478#endif
479
480static __init int omap_vram_init(void)
481{
482 int i;
483
484 vram_initialized = 1;
485
486 for (i = 0; i < postponed_cnt; i++)
487 omap_vram_add_region(postponed_regions[i].paddr,
488 postponed_regions[i].size);
489
490#ifdef CONFIG_DEBUG_FS
491 if (omap_vram_create_debugfs())
492 pr_err("VRAM: Failed to create debugfs file\n");
493#endif
494
495 return 0;
496}
497
498arch_initcall(omap_vram_init);
499
500/* boottime vram alloc stuff */
501
502/* set from board file */
503static u32 omap_vram_sram_start __initdata;
504static u32 omap_vram_sram_size __initdata;
505
506/* set from board file */
507static u32 omap_vram_sdram_start __initdata;
508static u32 omap_vram_sdram_size __initdata;
509
510/* set from kernel cmdline */
511static u32 omap_vram_def_sdram_size __initdata;
512static u32 omap_vram_def_sdram_start __initdata;
513
514static void __init omap_vram_early_vram(char **p)
515{
516 omap_vram_def_sdram_size = memparse(*p, p);
517 if (**p == ',')
518 omap_vram_def_sdram_start = simple_strtoul((*p) + 1, p, 16);
519}
520__early_param("vram=", omap_vram_early_vram);
521
522/*
523 * Called from map_io. We need to call to this early enough so that we
524 * can reserve the fixed SDRAM regions before VM could get hold of them.
525 */
526void __init omap_vram_reserve_sdram(void)
527{
528 struct bootmem_data *bdata;
529 unsigned long sdram_start, sdram_size;
530 u32 paddr;
531 u32 size = 0;
532
533 /* cmdline arg overrides the board file definition */
534 if (omap_vram_def_sdram_size) {
535 size = omap_vram_def_sdram_size;
536 paddr = omap_vram_def_sdram_start;
537 }
538
539 if (!size) {
540 size = omap_vram_sdram_size;
541 paddr = omap_vram_sdram_start;
542 }
543
544#ifdef CONFIG_OMAP2_VRAM_SIZE
545 if (!size) {
546 size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024;
547 paddr = 0;
548 }
549#endif
550
551 if (!size)
552 return;
553
554 size = PAGE_ALIGN(size);
555
556 bdata = NODE_DATA(0)->bdata;
557 sdram_start = bdata->node_min_pfn << PAGE_SHIFT;
558 sdram_size = (bdata->node_low_pfn << PAGE_SHIFT) - sdram_start;
559
560 if (paddr) {
561 if ((paddr & ~PAGE_MASK) || paddr < sdram_start ||
562 paddr + size > sdram_start + sdram_size) {
563 pr_err("Illegal SDRAM region for VRAM\n");
564 return;
565 }
566
567 if (reserve_bootmem(paddr, size, BOOTMEM_EXCLUSIVE) < 0) {
568 pr_err("FB: failed to reserve VRAM\n");
569 return;
570 }
571 } else {
572 if (size > sdram_size) {
573 pr_err("Illegal SDRAM size for VRAM\n");
574 return;
575 }
576
577 paddr = virt_to_phys(alloc_bootmem_pages(size));
578 BUG_ON(paddr & ~PAGE_MASK);
579 }
580
581 omap_vram_add_region(paddr, size);
582
583 pr_info("Reserving %u bytes SDRAM for VRAM\n", size);
584}
585
586/*
587 * Called at sram init time, before anything is pushed to the SRAM stack.
588 * Because of the stack scheme, we will allocate everything from the
589 * start of the lowest address region to the end of SRAM. This will also
590 * include padding for page alignment and possible holes between regions.
591 *
592 * As opposed to the SDRAM case, we'll also do any dynamic allocations at
593 * this point, since the driver built as a module would have problem with
594 * freeing / reallocating the regions.
595 */
596unsigned long __init omap_vram_reserve_sram(unsigned long sram_pstart,
597 unsigned long sram_vstart,
598 unsigned long sram_size,
599 unsigned long pstart_avail,
600 unsigned long size_avail)
601{
602 unsigned long pend_avail;
603 unsigned long reserved;
604 u32 paddr;
605 u32 size;
606
607 paddr = omap_vram_sram_start;
608 size = omap_vram_sram_size;
609
610 if (!size)
611 return 0;
612
613 reserved = 0;
614 pend_avail = pstart_avail + size_avail;
615
616 if (!paddr) {
617 /* Dynamic allocation */
618 if ((size_avail & PAGE_MASK) < size) {
619 pr_err("Not enough SRAM for VRAM\n");
620 return 0;
621 }
622 size_avail = (size_avail - size) & PAGE_MASK;
623 paddr = pstart_avail + size_avail;
624 }
625
626 if (paddr < sram_pstart ||
627 paddr + size > sram_pstart + sram_size) {
628 pr_err("Illegal SRAM region for VRAM\n");
629 return 0;
630 }
631
632 /* Reserve everything above the start of the region. */
633 if (pend_avail - paddr > reserved)
634 reserved = pend_avail - paddr;
635 size_avail = pend_avail - reserved - pstart_avail;
636
637 omap_vram_add_region(paddr, size);
638
639 if (reserved)
640 pr_info("Reserving %lu bytes SRAM for VRAM\n", reserved);
641
642 return reserved;
643}
644
645void __init omap_vram_set_sdram_vram(u32 size, u32 start)
646{
647 omap_vram_sdram_start = start;
648 omap_vram_sdram_size = size;
649}
650
651void __init omap_vram_set_sram_vram(u32 size, u32 start)
652{
653 omap_vram_sram_start = start;
654 omap_vram_sram_size = size;
655}
diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c
new file mode 100644
index 000000000000..fd2271600370
--- /dev/null
+++ b/drivers/video/omap2/vrfb.c
@@ -0,0 +1,315 @@
1/*
2 * VRFB Rotation Engine
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 */
20
21/*#define DEBUG*/
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/ioport.h>
26#include <linux/io.h>
27#include <linux/bitops.h>
28#include <linux/mutex.h>
29
30#include <mach/io.h>
31#include <plat/vrfb.h>
32#include <plat/sdrc.h>
33
34#ifdef DEBUG
35#define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__)
36#else
37#define DBG(format, ...)
38#endif
39
40#define SMS_ROT_VIRT_BASE(context, rot) \
41 (((context >= 4) ? 0xD0000000 : 0x70000000) \
42 + (0x4000000 * (context)) \
43 + (0x1000000 * (rot)))
44
45#define OMAP_VRFB_SIZE (2048 * 2048 * 4)
46
47#define VRFB_PAGE_WIDTH_EXP 5 /* Assuming SDRAM pagesize= 1024 */
48#define VRFB_PAGE_HEIGHT_EXP 5 /* 1024 = 2^5 * 2^5 */
49#define VRFB_PAGE_WIDTH (1 << VRFB_PAGE_WIDTH_EXP)
50#define VRFB_PAGE_HEIGHT (1 << VRFB_PAGE_HEIGHT_EXP)
51#define SMS_IMAGEHEIGHT_OFFSET 16
52#define SMS_IMAGEWIDTH_OFFSET 0
53#define SMS_PH_OFFSET 8
54#define SMS_PW_OFFSET 4
55#define SMS_PS_OFFSET 0
56
57#define VRFB_NUM_CTXS 12
58/* bitmap of reserved contexts */
59static unsigned long ctx_map;
60
61static DEFINE_MUTEX(ctx_lock);
62
63/*
64 * Access to this happens from client drivers or the PM core after wake-up.
65 * For the first case we require locking at the driver level, for the second
66 * we don't need locking, since no drivers will run until after the wake-up
67 * has finished.
68 */
69static struct {
70 u32 physical_ba;
71 u32 control;
72 u32 size;
73} vrfb_hw_context[VRFB_NUM_CTXS];
74
75static inline void restore_hw_context(int ctx)
76{
77 omap2_sms_write_rot_control(vrfb_hw_context[ctx].control, ctx);
78 omap2_sms_write_rot_size(vrfb_hw_context[ctx].size, ctx);
79 omap2_sms_write_rot_physical_ba(vrfb_hw_context[ctx].physical_ba, ctx);
80}
81
82static u32 get_image_width_roundup(u16 width, u8 bytespp)
83{
84 unsigned long stride = width * bytespp;
85 unsigned long ceil_pages_per_stride = (stride / VRFB_PAGE_WIDTH) +
86 (stride % VRFB_PAGE_WIDTH != 0);
87
88 return ceil_pages_per_stride * VRFB_PAGE_WIDTH / bytespp;
89}
90
91/*
92 * This the extra space needed in the VRFB physical area for VRFB to safely wrap
93 * any memory accesses to the invisible part of the virtual view to the physical
94 * area.
95 */
96static inline u32 get_extra_physical_size(u16 image_width_roundup, u8 bytespp)
97{
98 return (OMAP_VRFB_LINE_LEN - image_width_roundup) * VRFB_PAGE_HEIGHT *
99 bytespp;
100}
101
102void omap_vrfb_restore_context(void)
103{
104 int i;
105 unsigned long map = ctx_map;
106
107 for (i = ffs(map); i; i = ffs(map)) {
108 /* i=1..32 */
109 i--;
110 map &= ~(1 << i);
111 restore_hw_context(i);
112 }
113}
114
115void omap_vrfb_adjust_size(u16 *width, u16 *height,
116 u8 bytespp)
117{
118 *width = ALIGN(*width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
119 *height = ALIGN(*height, VRFB_PAGE_HEIGHT);
120}
121EXPORT_SYMBOL(omap_vrfb_adjust_size);
122
123u32 omap_vrfb_min_phys_size(u16 width, u16 height, u8 bytespp)
124{
125 unsigned long image_width_roundup = get_image_width_roundup(width,
126 bytespp);
127
128 if (image_width_roundup > OMAP_VRFB_LINE_LEN)
129 return 0;
130
131 return (width * height * bytespp) + get_extra_physical_size(
132 image_width_roundup, bytespp);
133}
134EXPORT_SYMBOL(omap_vrfb_min_phys_size);
135
136u16 omap_vrfb_max_height(u32 phys_size, u16 width, u8 bytespp)
137{
138 unsigned long image_width_roundup = get_image_width_roundup(width,
139 bytespp);
140 unsigned long height;
141 unsigned long extra;
142
143 if (image_width_roundup > OMAP_VRFB_LINE_LEN)
144 return 0;
145
146 extra = get_extra_physical_size(image_width_roundup, bytespp);
147
148 if (phys_size < extra)
149 return 0;
150
151 height = (phys_size - extra) / (width * bytespp);
152
153 /* Virtual views provided by VRFB are limited to 2048x2048. */
154 return min_t(unsigned long, height, 2048);
155}
156EXPORT_SYMBOL(omap_vrfb_max_height);
157
158void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
159 u16 width, u16 height,
160 unsigned bytespp, bool yuv_mode)
161{
162 unsigned pixel_size_exp;
163 u16 vrfb_width;
164 u16 vrfb_height;
165 u8 ctx = vrfb->context;
166 u32 size;
167 u32 control;
168
169 DBG("omapfb_set_vrfb(%d, %lx, %dx%d, %d, %d)\n", ctx, paddr,
170 width, height, bytespp, yuv_mode);
171
172 /* For YUV2 and UYVY modes VRFB needs to handle pixels a bit
173 * differently. See TRM. */
174 if (yuv_mode) {
175 bytespp *= 2;
176 width /= 2;
177 }
178
179 if (bytespp == 4)
180 pixel_size_exp = 2;
181 else if (bytespp == 2)
182 pixel_size_exp = 1;
183 else
184 BUG();
185
186 vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
187 vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT);
188
189 DBG("vrfb w %u, h %u bytespp %d\n", vrfb_width, vrfb_height, bytespp);
190
191 size = vrfb_width << SMS_IMAGEWIDTH_OFFSET;
192 size |= vrfb_height << SMS_IMAGEHEIGHT_OFFSET;
193
194 control = pixel_size_exp << SMS_PS_OFFSET;
195 control |= VRFB_PAGE_WIDTH_EXP << SMS_PW_OFFSET;
196 control |= VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET;
197
198 vrfb_hw_context[ctx].physical_ba = paddr;
199 vrfb_hw_context[ctx].size = size;
200 vrfb_hw_context[ctx].control = control;
201
202 omap2_sms_write_rot_physical_ba(paddr, ctx);
203 omap2_sms_write_rot_size(size, ctx);
204 omap2_sms_write_rot_control(control, ctx);
205
206 DBG("vrfb offset pixels %d, %d\n",
207 vrfb_width - width, vrfb_height - height);
208
209 vrfb->xres = width;
210 vrfb->yres = height;
211 vrfb->xoffset = vrfb_width - width;
212 vrfb->yoffset = vrfb_height - height;
213 vrfb->bytespp = bytespp;
214 vrfb->yuv_mode = yuv_mode;
215}
216EXPORT_SYMBOL(omap_vrfb_setup);
217
218int omap_vrfb_map_angle(struct vrfb *vrfb, u16 height, u8 rot)
219{
220 unsigned long size = height * OMAP_VRFB_LINE_LEN * vrfb->bytespp;
221
222 vrfb->vaddr[rot] = ioremap_wc(vrfb->paddr[rot], size);
223
224 if (!vrfb->vaddr[rot]) {
225 printk(KERN_ERR "vrfb: ioremap failed\n");
226 return -ENOMEM;
227 }
228
229 DBG("ioremapped vrfb area %d of size %lu into %p\n", rot, size,
230 vrfb->vaddr[rot]);
231
232 return 0;
233}
234EXPORT_SYMBOL(omap_vrfb_map_angle);
235
236void omap_vrfb_release_ctx(struct vrfb *vrfb)
237{
238 int rot;
239 int ctx = vrfb->context;
240
241 if (ctx == 0xff)
242 return;
243
244 DBG("release ctx %d\n", ctx);
245
246 mutex_lock(&ctx_lock);
247
248 BUG_ON(!(ctx_map & (1 << ctx)));
249
250 clear_bit(ctx, &ctx_map);
251
252 for (rot = 0; rot < 4; ++rot) {
253 if (vrfb->paddr[rot]) {
254 release_mem_region(vrfb->paddr[rot], OMAP_VRFB_SIZE);
255 vrfb->paddr[rot] = 0;
256 }
257 }
258
259 vrfb->context = 0xff;
260
261 mutex_unlock(&ctx_lock);
262}
263EXPORT_SYMBOL(omap_vrfb_release_ctx);
264
265int omap_vrfb_request_ctx(struct vrfb *vrfb)
266{
267 int rot;
268 u32 paddr;
269 u8 ctx;
270 int r;
271
272 DBG("request ctx\n");
273
274 mutex_lock(&ctx_lock);
275
276 for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx)
277 if ((ctx_map & (1 << ctx)) == 0)
278 break;
279
280 if (ctx == VRFB_NUM_CTXS) {
281 pr_err("vrfb: no free contexts\n");
282 r = -EBUSY;
283 goto out;
284 }
285
286 DBG("found free ctx %d\n", ctx);
287
288 set_bit(ctx, &ctx_map);
289
290 memset(vrfb, 0, sizeof(*vrfb));
291
292 vrfb->context = ctx;
293
294 for (rot = 0; rot < 4; ++rot) {
295 paddr = SMS_ROT_VIRT_BASE(ctx, rot);
296 if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) {
297 pr_err("vrfb: failed to reserve VRFB "
298 "area for ctx %d, rotation %d\n",
299 ctx, rot * 90);
300 omap_vrfb_release_ctx(vrfb);
301 r = -ENOMEM;
302 goto out;
303 }
304
305 vrfb->paddr[rot] = paddr;
306
307 DBG("VRFB %d/%d: %lx\n", ctx, rot*90, vrfb->paddr[rot]);
308 }
309
310 r = 0;
311out:
312 mutex_unlock(&ctx_lock);
313 return r;
314}
315EXPORT_SYMBOL(omap_vrfb_request_ctx);
diff --git a/drivers/video/output.c b/drivers/video/output.c
index 5e6439ae7394..5137aa016b83 100644
--- a/drivers/video/output.c
+++ b/drivers/video/output.c
@@ -50,7 +50,7 @@ static ssize_t video_output_store_state(struct device *dev,
50 int request_state = simple_strtoul(buf,&endp,0); 50 int request_state = simple_strtoul(buf,&endp,0);
51 size_t size = endp - buf; 51 size_t size = endp - buf;
52 52
53 if (*endp && isspace(*endp)) 53 if (isspace(*endp))
54 size++; 54 size++;
55 if (size != count) 55 if (size != count)
56 return -EINVAL; 56 return -EINVAL;
diff --git a/drivers/video/pmag-ba-fb.c b/drivers/video/pmag-ba-fb.c
index 0573ec685a57..0f361b6100d2 100644
--- a/drivers/video/pmag-ba-fb.c
+++ b/drivers/video/pmag-ba-fb.c
@@ -98,7 +98,8 @@ static int pmagbafb_setcolreg(unsigned int regno, unsigned int red,
98{ 98{
99 struct pmagbafb_par *par = info->par; 99 struct pmagbafb_par *par = info->par;
100 100
101 BUG_ON(regno >= info->cmap.len); 101 if (regno >= info->cmap.len)
102 return 1;
102 103
103 red >>= 8; /* The cmap fields are 16 bits */ 104 red >>= 8; /* The cmap fields are 16 bits */
104 green >>= 8; /* wide, but the hardware colormap */ 105 green >>= 8; /* wide, but the hardware colormap */
diff --git a/drivers/video/pmagb-b-fb.c b/drivers/video/pmagb-b-fb.c
index 98748723af9f..2de0806421b4 100644
--- a/drivers/video/pmagb-b-fb.c
+++ b/drivers/video/pmagb-b-fb.c
@@ -102,7 +102,8 @@ static int pmagbbfb_setcolreg(unsigned int regno, unsigned int red,
102{ 102{
103 struct pmagbbfb_par *par = info->par; 103 struct pmagbbfb_par *par = info->par;
104 104
105 BUG_ON(regno >= info->cmap.len); 105 if (regno >= info->cmap.len)
106 return 1;
106 107
107 red >>= 8; /* The cmap fields are 16 bits */ 108 red >>= 8; /* The cmap fields are 16 bits */
108 green >>= 8; /* wide, but the hardware colormap */ 109 green >>= 8; /* wide, but the hardware colormap */
diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c
index 84d8327e47db..75285d3f393c 100644
--- a/drivers/video/pxa168fb.c
+++ b/drivers/video/pxa168fb.c
@@ -687,6 +687,7 @@ static int __init pxa168fb_probe(struct platform_device *pdev)
687 } 687 }
688 688
689 info->fix.smem_start = (unsigned long)fbi->fb_start_dma; 689 info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
690 set_graphics_start(info, 0, 0);
690 691
691 /* 692 /*
692 * Set video mode according to platform data. 693 * Set video mode according to platform data.
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 1820c4a24434..825b665245bb 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -80,7 +80,8 @@
80static int pxafb_activate_var(struct fb_var_screeninfo *var, 80static int pxafb_activate_var(struct fb_var_screeninfo *var,
81 struct pxafb_info *); 81 struct pxafb_info *);
82static void set_ctrlr_state(struct pxafb_info *fbi, u_int state); 82static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
83static void setup_base_frame(struct pxafb_info *fbi, int branch); 83static void setup_base_frame(struct pxafb_info *fbi,
84 struct fb_var_screeninfo *var, int branch);
84static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal, 85static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
85 unsigned long offset, size_t size); 86 unsigned long offset, size_t size);
86 87
@@ -397,6 +398,7 @@ static void pxafb_setmode(struct fb_var_screeninfo *var,
397 var->lower_margin = mode->lower_margin; 398 var->lower_margin = mode->lower_margin;
398 var->sync = mode->sync; 399 var->sync = mode->sync;
399 var->grayscale = mode->cmap_greyscale; 400 var->grayscale = mode->cmap_greyscale;
401 var->transp.length = mode->transparency;
400 402
401 /* set the initial RGBA bitfields */ 403 /* set the initial RGBA bitfields */
402 pxafb_set_pixfmt(var, mode->depth); 404 pxafb_set_pixfmt(var, mode->depth);
@@ -531,12 +533,22 @@ static int pxafb_pan_display(struct fb_var_screeninfo *var,
531 struct fb_info *info) 533 struct fb_info *info)
532{ 534{
533 struct pxafb_info *fbi = (struct pxafb_info *)info; 535 struct pxafb_info *fbi = (struct pxafb_info *)info;
536 struct fb_var_screeninfo newvar;
534 int dma = DMA_MAX + DMA_BASE; 537 int dma = DMA_MAX + DMA_BASE;
535 538
536 if (fbi->state != C_ENABLE) 539 if (fbi->state != C_ENABLE)
537 return 0; 540 return 0;
538 541
539 setup_base_frame(fbi, 1); 542 /* Only take .xoffset, .yoffset and .vmode & FB_VMODE_YWRAP from what
543 * was passed in and copy the rest from the old screeninfo.
544 */
545 memcpy(&newvar, &fbi->fb.var, sizeof(newvar));
546 newvar.xoffset = var->xoffset;
547 newvar.yoffset = var->yoffset;
548 newvar.vmode &= ~FB_VMODE_YWRAP;
549 newvar.vmode |= var->vmode & FB_VMODE_YWRAP;
550
551 setup_base_frame(fbi, &newvar, 1);
540 552
541 if (fbi->lccr0 & LCCR0_SDS) 553 if (fbi->lccr0 & LCCR0_SDS)
542 lcd_writel(fbi, FBR1, fbi->fdadr[dma + 1] | 0x1); 554 lcd_writel(fbi, FBR1, fbi->fdadr[dma + 1] | 0x1);
@@ -1052,9 +1064,10 @@ static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
1052 return 0; 1064 return 0;
1053} 1065}
1054 1066
1055static void setup_base_frame(struct pxafb_info *fbi, int branch) 1067static void setup_base_frame(struct pxafb_info *fbi,
1068 struct fb_var_screeninfo *var,
1069 int branch)
1056{ 1070{
1057 struct fb_var_screeninfo *var = &fbi->fb.var;
1058 struct fb_fix_screeninfo *fix = &fbi->fb.fix; 1071 struct fb_fix_screeninfo *fix = &fbi->fb.fix;
1059 int nbytes, dma, pal, bpp = var->bits_per_pixel; 1072 int nbytes, dma, pal, bpp = var->bits_per_pixel;
1060 unsigned long offset; 1073 unsigned long offset;
@@ -1210,11 +1223,12 @@ static int pxafb_smart_thread(void *arg)
1210 struct pxafb_info *fbi = arg; 1223 struct pxafb_info *fbi = arg;
1211 struct pxafb_mach_info *inf = fbi->dev->platform_data; 1224 struct pxafb_mach_info *inf = fbi->dev->platform_data;
1212 1225
1213 if (!fbi || !inf->smart_update) { 1226 if (!inf->smart_update) {
1214 pr_err("%s: not properly initialized, thread terminated\n", 1227 pr_err("%s: not properly initialized, thread terminated\n",
1215 __func__); 1228 __func__);
1216 return -EINVAL; 1229 return -EINVAL;
1217 } 1230 }
1231 inf = fbi->dev->platform_data;
1218 1232
1219 pr_debug("%s(): task starting\n", __func__); 1233 pr_debug("%s(): task starting\n", __func__);
1220 1234
@@ -1332,7 +1346,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var,
1332#endif 1346#endif
1333 setup_parallel_timing(fbi, var); 1347 setup_parallel_timing(fbi, var);
1334 1348
1335 setup_base_frame(fbi, 0); 1349 setup_base_frame(fbi, var, 0);
1336 1350
1337 fbi->reg_lccr0 = fbi->lccr0 | 1351 fbi->reg_lccr0 = fbi->lccr0 |
1338 (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | 1352 (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
@@ -1654,7 +1668,7 @@ static int pxafb_resume(struct device *dev)
1654 return 0; 1668 return 0;
1655} 1669}
1656 1670
1657static struct dev_pm_ops pxafb_pm_ops = { 1671static const struct dev_pm_ops pxafb_pm_ops = {
1658 .suspend = pxafb_suspend, 1672 .suspend = pxafb_suspend,
1659 .resume = pxafb_resume, 1673 .resume = pxafb_resume,
1660}; 1674};
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c
index adf9632c6b1f..53cb722c45a0 100644
--- a/drivers/video/s3c-fb.c
+++ b/drivers/video/s3c-fb.c
@@ -211,21 +211,23 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var,
211 211
212/** 212/**
213 * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock. 213 * s3c_fb_calc_pixclk() - calculate the divider to create the pixel clock.
214 * @id: window id.
215 * @sfb: The hardware state. 214 * @sfb: The hardware state.
216 * @pixclock: The pixel clock wanted, in picoseconds. 215 * @pixclock: The pixel clock wanted, in picoseconds.
217 * 216 *
218 * Given the specified pixel clock, work out the necessary divider to get 217 * Given the specified pixel clock, work out the necessary divider to get
219 * close to the output frequency. 218 * close to the output frequency.
220 */ 219 */
221static int s3c_fb_calc_pixclk(unsigned char id, struct s3c_fb *sfb, unsigned int pixclk) 220static int s3c_fb_calc_pixclk(struct s3c_fb *sfb, unsigned int pixclk)
222{ 221{
223 struct s3c_fb_pd_win *win = sfb->pdata->win[id];
224 unsigned long clk = clk_get_rate(sfb->bus_clk); 222 unsigned long clk = clk_get_rate(sfb->bus_clk);
223 unsigned long long tmp;
225 unsigned int result; 224 unsigned int result;
226 225
227 pixclk *= win->win_mode.refresh; 226 tmp = (unsigned long long)clk;
228 result = clk / pixclk; 227 tmp *= pixclk;
228
229 do_div(tmp, 1000000000UL);
230 result = (unsigned int)tmp / 1000;
229 231
230 dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n", 232 dev_dbg(sfb->dev, "pixclk=%u, clk=%lu, div=%d (%lu)\n",
231 pixclk, clk, result, clk / result); 233 pixclk, clk, result, clk / result);
@@ -301,7 +303,7 @@ static int s3c_fb_set_par(struct fb_info *info)
301 /* use window 0 as the basis for the lcd output timings */ 303 /* use window 0 as the basis for the lcd output timings */
302 304
303 if (win_no == 0) { 305 if (win_no == 0) {
304 clkdiv = s3c_fb_calc_pixclk(win_no, sfb, var->pixclock); 306 clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock);
305 307
306 data = sfb->pdata->vidcon0; 308 data = sfb->pdata->vidcon0;
307 data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); 309 data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index bba53714a7b1..f86012239bff 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -260,13 +260,13 @@ static int sgivwfb_check_var(struct fb_var_screeninfo *var,
260 var->grayscale = 0; /* No grayscale for now */ 260 var->grayscale = 0; /* No grayscale for now */
261 261
262 /* determine valid resolution and timing */ 262 /* determine valid resolution and timing */
263 for (min_mode = 0; min_mode < DBE_VT_SIZE; min_mode++) { 263 for (min_mode = 0; min_mode < ARRAY_SIZE(dbeVTimings); min_mode++) {
264 if (dbeVTimings[min_mode].width >= var->xres && 264 if (dbeVTimings[min_mode].width >= var->xres &&
265 dbeVTimings[min_mode].height >= var->yres) 265 dbeVTimings[min_mode].height >= var->yres)
266 break; 266 break;
267 } 267 }
268 268
269 if (min_mode == DBE_VT_SIZE) 269 if (min_mode == ARRAY_SIZE(dbeVTimings))
270 return -EINVAL; /* Resolution to high */ 270 return -EINVAL; /* Resolution to high */
271 271
272 /* XXX FIXME - should try to pick best refresh rate */ 272 /* XXX FIXME - should try to pick best refresh rate */
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index 3ad5157f9899..a69830d26f7f 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -281,18 +281,42 @@ static void sh_mobile_lcdc_deferred_io(struct fb_info *info,
281 struct list_head *pagelist) 281 struct list_head *pagelist)
282{ 282{
283 struct sh_mobile_lcdc_chan *ch = info->par; 283 struct sh_mobile_lcdc_chan *ch = info->par;
284 unsigned int nr_pages; 284 struct sh_mobile_lcdc_board_cfg *bcfg = &ch->cfg.board_cfg;
285 285
286 /* enable clocks before accessing hardware */ 286 /* enable clocks before accessing hardware */
287 sh_mobile_lcdc_clk_on(ch->lcdc); 287 sh_mobile_lcdc_clk_on(ch->lcdc);
288 288
289 nr_pages = sh_mobile_lcdc_sginit(info, pagelist); 289 /*
290 dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); 290 * It's possible to get here without anything on the pagelist via
291 291 * sh_mobile_lcdc_deferred_io_touch() or via a userspace fsync()
292 /* trigger panel update */ 292 * invocation. In the former case, the acceleration routines are
293 lcdc_write_chan(ch, LDSM2R, 1); 293 * stepped in to when using the framebuffer console causing the
294 294 * workqueue to be scheduled without any dirty pages on the list.
295 dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE); 295 *
296 * Despite this, a panel update is still needed given that the
297 * acceleration routines have their own methods for writing in
298 * that still need to be updated.
299 *
300 * The fsync() and empty pagelist case could be optimized for,
301 * but we don't bother, as any application exhibiting such
302 * behaviour is fundamentally broken anyways.
303 */
304 if (!list_empty(pagelist)) {
305 unsigned int nr_pages = sh_mobile_lcdc_sginit(info, pagelist);
306
307 /* trigger panel update */
308 dma_map_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
309 if (bcfg->start_transfer)
310 bcfg->start_transfer(bcfg->board_data, ch,
311 &sh_mobile_lcdc_sys_bus_ops);
312 lcdc_write_chan(ch, LDSM2R, 1);
313 dma_unmap_sg(info->dev, ch->sglist, nr_pages, DMA_TO_DEVICE);
314 } else {
315 if (bcfg->start_transfer)
316 bcfg->start_transfer(bcfg->board_data, ch,
317 &sh_mobile_lcdc_sys_bus_ops);
318 lcdc_write_chan(ch, LDSM2R, 1);
319 }
296} 320}
297 321
298static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info) 322static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
@@ -874,7 +898,7 @@ static int sh_mobile_lcdc_runtime_resume(struct device *dev)
874 return 0; 898 return 0;
875} 899}
876 900
877static struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { 901static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
878 .suspend = sh_mobile_lcdc_suspend, 902 .suspend = sh_mobile_lcdc_suspend,
879 .resume = sh_mobile_lcdc_resume, 903 .resume = sh_mobile_lcdc_resume,
880 .runtime_suspend = sh_mobile_lcdc_runtime_suspend, 904 .runtime_suspend = sh_mobile_lcdc_runtime_suspend,
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index a4e05e4d7501..9d2b6bc49036 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -2115,7 +2115,7 @@ sisfb_detect_VB_connect(struct sis_video_info *ivideo)
2115 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) && 2115 if( (!(ivideo->vbflags2 & VB2_SISBRIDGE)) &&
2116 (!((ivideo->sisvga_engine == SIS_315_VGA) && 2116 (!((ivideo->sisvga_engine == SIS_315_VGA) &&
2117 (ivideo->vbflags2 & VB2_CHRONTEL))) ) { 2117 (ivideo->vbflags2 & VB2_CHRONTEL))) ) {
2118 if(ivideo->sisfb_tvstd & (TV_PALN | TV_PALN | TV_NTSCJ)) { 2118 if(ivideo->sisfb_tvstd & (TV_PALM | TV_PALN | TV_NTSCJ)) {
2119 ivideo->sisfb_tvstd = -1; 2119 ivideo->sisfb_tvstd = -1;
2120 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n"); 2120 printk(KERN_ERR "sisfb: PALM/PALN/NTSCJ not supported\n");
2121 } 2121 }
diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c
index 924d79462780..35370d0ecf03 100644
--- a/drivers/video/sm501fb.c
+++ b/drivers/video/sm501fb.c
@@ -29,8 +29,8 @@
29#include <linux/platform_device.h> 29#include <linux/platform_device.h>
30#include <linux/clk.h> 30#include <linux/clk.h>
31#include <linux/console.h> 31#include <linux/console.h>
32#include <linux/io.h>
32 33
33#include <asm/io.h>
34#include <asm/uaccess.h> 34#include <asm/uaccess.h>
35#include <asm/div64.h> 35#include <asm/div64.h>
36 36
@@ -66,6 +66,7 @@ struct sm501fb_info {
66 struct fb_info *fb[2]; /* fb info for both heads */ 66 struct fb_info *fb[2]; /* fb info for both heads */
67 struct resource *fbmem_res; /* framebuffer resource */ 67 struct resource *fbmem_res; /* framebuffer resource */
68 struct resource *regs_res; /* registers resource */ 68 struct resource *regs_res; /* registers resource */
69 struct resource *regs2d_res; /* 2d registers resource */
69 struct sm501_platdata_fb *pdata; /* our platform data */ 70 struct sm501_platdata_fb *pdata; /* our platform data */
70 71
71 unsigned long pm_crt_ctrl; /* pm: crt ctrl save */ 72 unsigned long pm_crt_ctrl; /* pm: crt ctrl save */
@@ -73,6 +74,7 @@ struct sm501fb_info {
73 int irq; 74 int irq;
74 int swap_endian; /* set to swap rgb=>bgr */ 75 int swap_endian; /* set to swap rgb=>bgr */
75 void __iomem *regs; /* remapped registers */ 76 void __iomem *regs; /* remapped registers */
77 void __iomem *regs2d; /* 2d remapped registers */
76 void __iomem *fbmem; /* remapped framebuffer */ 78 void __iomem *fbmem; /* remapped framebuffer */
77 size_t fbmem_len; /* length of remapped region */ 79 size_t fbmem_len; /* length of remapped region */
78}; 80};
@@ -123,9 +125,9 @@ static inline void sm501fb_sync_regs(struct sm501fb_info *info)
123 * This is an attempt to lay out memory for the two framebuffers and 125 * This is an attempt to lay out memory for the two framebuffers and
124 * everything else 126 * everything else
125 * 127 *
126 * |fbmem_res->start fbmem_res->end| 128 * |fbmem_res->start fbmem_res->end|
127 * | | 129 * | |
128 * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K | 130 * |fb[0].fix.smem_start | |fb[1].fix.smem_start | 2K |
129 * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-| 131 * |-> fb[0].fix.smem_len <-| spare |-> fb[1].fix.smem_len <-|-> cursors <-|
130 * 132 *
131 * The "spare" space is for the 2d engine data 133 * The "spare" space is for the 2d engine data
@@ -1246,7 +1248,173 @@ static ssize_t sm501fb_debug_show_pnl(struct device *dev,
1246 1248
1247static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL); 1249static DEVICE_ATTR(fbregs_pnl, 0444, sm501fb_debug_show_pnl, NULL);
1248 1250
1249/* framebuffer ops */ 1251/* acceleration operations */
1252static int sm501fb_sync(struct fb_info *info)
1253{
1254 int count = 1000000;
1255 struct sm501fb_par *par = info->par;
1256 struct sm501fb_info *fbi = par->info;
1257
1258 /* wait for the 2d engine to be ready */
1259 while ((count > 0) &&
1260 (readl(fbi->regs + SM501_SYSTEM_CONTROL) &
1261 SM501_SYSCTRL_2D_ENGINE_STATUS) != 0)
1262 count--;
1263
1264 if (count <= 0) {
1265 dev_err(info->dev, "Timeout waiting for 2d engine sync\n");
1266 return 1;
1267 }
1268 return 0;
1269}
1270
1271static void sm501fb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
1272{
1273 struct sm501fb_par *par = info->par;
1274 struct sm501fb_info *fbi = par->info;
1275 int width = area->width;
1276 int height = area->height;
1277 int sx = area->sx;
1278 int sy = area->sy;
1279 int dx = area->dx;
1280 int dy = area->dy;
1281 unsigned long rtl = 0;
1282
1283 /* source clip */
1284 if ((sx >= info->var.xres_virtual) ||
1285 (sy >= info->var.yres_virtual))
1286 /* source Area not within virtual screen, skipping */
1287 return;
1288 if ((sx + width) >= info->var.xres_virtual)
1289 width = info->var.xres_virtual - sx - 1;
1290 if ((sy + height) >= info->var.yres_virtual)
1291 height = info->var.yres_virtual - sy - 1;
1292
1293 /* dest clip */
1294 if ((dx >= info->var.xres_virtual) ||
1295 (dy >= info->var.yres_virtual))
1296 /* Destination Area not within virtual screen, skipping */
1297 return;
1298 if ((dx + width) >= info->var.xres_virtual)
1299 width = info->var.xres_virtual - dx - 1;
1300 if ((dy + height) >= info->var.yres_virtual)
1301 height = info->var.yres_virtual - dy - 1;
1302
1303 if ((sx < dx) || (sy < dy)) {
1304 rtl = 1 << 27;
1305 sx += width - 1;
1306 dx += width - 1;
1307 sy += height - 1;
1308 dy += height - 1;
1309 }
1310
1311 if (sm501fb_sync(info))
1312 return;
1313
1314 /* set the base addresses */
1315 writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
1316 writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE);
1317
1318 /* set the window width */
1319 writel((info->var.xres << 16) | info->var.xres,
1320 fbi->regs2d + SM501_2D_WINDOW_WIDTH);
1321
1322 /* set window stride */
1323 writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
1324 fbi->regs2d + SM501_2D_PITCH);
1325
1326 /* set data format */
1327 switch (info->var.bits_per_pixel) {
1328 case 8:
1329 writel(0, fbi->regs2d + SM501_2D_STRETCH);
1330 break;
1331 case 16:
1332 writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
1333 break;
1334 case 32:
1335 writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
1336 break;
1337 }
1338
1339 /* 2d compare mask */
1340 writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
1341
1342 /* 2d mask */
1343 writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
1344
1345 /* source and destination x y */
1346 writel((sx << 16) | sy, fbi->regs2d + SM501_2D_SOURCE);
1347 writel((dx << 16) | dy, fbi->regs2d + SM501_2D_DESTINATION);
1348
1349 /* w/h */
1350 writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
1351
1352 /* do area move */
1353 writel(0x800000cc | rtl, fbi->regs2d + SM501_2D_CONTROL);
1354}
1355
1356static void sm501fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
1357{
1358 struct sm501fb_par *par = info->par;
1359 struct sm501fb_info *fbi = par->info;
1360 int width = rect->width, height = rect->height;
1361
1362 if ((rect->dx >= info->var.xres_virtual) ||
1363 (rect->dy >= info->var.yres_virtual))
1364 /* Rectangle not within virtual screen, skipping */
1365 return;
1366 if ((rect->dx + width) >= info->var.xres_virtual)
1367 width = info->var.xres_virtual - rect->dx - 1;
1368 if ((rect->dy + height) >= info->var.yres_virtual)
1369 height = info->var.yres_virtual - rect->dy - 1;
1370
1371 if (sm501fb_sync(info))
1372 return;
1373
1374 /* set the base addresses */
1375 writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_SOURCE_BASE);
1376 writel(par->screen.sm_addr, fbi->regs2d + SM501_2D_DESTINATION_BASE);
1377
1378 /* set the window width */
1379 writel((info->var.xres << 16) | info->var.xres,
1380 fbi->regs2d + SM501_2D_WINDOW_WIDTH);
1381
1382 /* set window stride */
1383 writel((info->var.xres_virtual << 16) | info->var.xres_virtual,
1384 fbi->regs2d + SM501_2D_PITCH);
1385
1386 /* set data format */
1387 switch (info->var.bits_per_pixel) {
1388 case 8:
1389 writel(0, fbi->regs2d + SM501_2D_STRETCH);
1390 break;
1391 case 16:
1392 writel(0x00100000, fbi->regs2d + SM501_2D_STRETCH);
1393 break;
1394 case 32:
1395 writel(0x00200000, fbi->regs2d + SM501_2D_STRETCH);
1396 break;
1397 }
1398
1399 /* 2d compare mask */
1400 writel(0xffffffff, fbi->regs2d + SM501_2D_COLOR_COMPARE_MASK);
1401
1402 /* 2d mask */
1403 writel(0xffffffff, fbi->regs2d + SM501_2D_MASK);
1404
1405 /* colour */
1406 writel(rect->color, fbi->regs2d + SM501_2D_FOREGROUND);
1407
1408 /* x y */
1409 writel((rect->dx << 16) | rect->dy, fbi->regs2d + SM501_2D_DESTINATION);
1410
1411 /* w/h */
1412 writel((width << 16) | height, fbi->regs2d + SM501_2D_DIMENSION);
1413
1414 /* do rectangle fill */
1415 writel(0x800100cc, fbi->regs2d + SM501_2D_CONTROL);
1416}
1417
1250 1418
1251static struct fb_ops sm501fb_ops_crt = { 1419static struct fb_ops sm501fb_ops_crt = {
1252 .owner = THIS_MODULE, 1420 .owner = THIS_MODULE,
@@ -1256,9 +1424,10 @@ static struct fb_ops sm501fb_ops_crt = {
1256 .fb_setcolreg = sm501fb_setcolreg, 1424 .fb_setcolreg = sm501fb_setcolreg,
1257 .fb_pan_display = sm501fb_pan_crt, 1425 .fb_pan_display = sm501fb_pan_crt,
1258 .fb_cursor = sm501fb_cursor, 1426 .fb_cursor = sm501fb_cursor,
1259 .fb_fillrect = cfb_fillrect, 1427 .fb_fillrect = sm501fb_fillrect,
1260 .fb_copyarea = cfb_copyarea, 1428 .fb_copyarea = sm501fb_copyarea,
1261 .fb_imageblit = cfb_imageblit, 1429 .fb_imageblit = cfb_imageblit,
1430 .fb_sync = sm501fb_sync,
1262}; 1431};
1263 1432
1264static struct fb_ops sm501fb_ops_pnl = { 1433static struct fb_ops sm501fb_ops_pnl = {
@@ -1269,9 +1438,10 @@ static struct fb_ops sm501fb_ops_pnl = {
1269 .fb_blank = sm501fb_blank_pnl, 1438 .fb_blank = sm501fb_blank_pnl,
1270 .fb_setcolreg = sm501fb_setcolreg, 1439 .fb_setcolreg = sm501fb_setcolreg,
1271 .fb_cursor = sm501fb_cursor, 1440 .fb_cursor = sm501fb_cursor,
1272 .fb_fillrect = cfb_fillrect, 1441 .fb_fillrect = sm501fb_fillrect,
1273 .fb_copyarea = cfb_copyarea, 1442 .fb_copyarea = sm501fb_copyarea,
1274 .fb_imageblit = cfb_imageblit, 1443 .fb_imageblit = cfb_imageblit,
1444 .fb_sync = sm501fb_sync,
1275}; 1445};
1276 1446
1277/* sm501_init_cursor 1447/* sm501_init_cursor
@@ -1329,7 +1499,8 @@ static int sm501fb_start(struct sm501fb_info *info,
1329 dev_warn(dev, "no irq for device\n"); 1499 dev_warn(dev, "no irq for device\n");
1330 } 1500 }
1331 1501
1332 /* allocate, reserve and remap resources for registers */ 1502 /* allocate, reserve and remap resources for display
1503 * controller registers */
1333 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1504 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1334 if (res == NULL) { 1505 if (res == NULL) {
1335 dev_err(dev, "no resource definition for registers\n"); 1506 dev_err(dev, "no resource definition for registers\n");
@@ -1338,7 +1509,7 @@ static int sm501fb_start(struct sm501fb_info *info,
1338 } 1509 }
1339 1510
1340 info->regs_res = request_mem_region(res->start, 1511 info->regs_res = request_mem_region(res->start,
1341 res->end - res->start, 1512 resource_size(res),
1342 pdev->name); 1513 pdev->name);
1343 1514
1344 if (info->regs_res == NULL) { 1515 if (info->regs_res == NULL) {
@@ -1347,37 +1518,63 @@ static int sm501fb_start(struct sm501fb_info *info,
1347 goto err_release; 1518 goto err_release;
1348 } 1519 }
1349 1520
1350 info->regs = ioremap(res->start, (res->end - res->start)+1); 1521 info->regs = ioremap(res->start, resource_size(res));
1351 if (info->regs == NULL) { 1522 if (info->regs == NULL) {
1352 dev_err(dev, "cannot remap registers\n"); 1523 dev_err(dev, "cannot remap registers\n");
1353 ret = -ENXIO; 1524 ret = -ENXIO;
1354 goto err_regs_res; 1525 goto err_regs_res;
1355 } 1526 }
1356 1527
1528 /* allocate, reserve and remap resources for 2d
1529 * controller registers */
1530 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1531 if (res == NULL) {
1532 dev_err(dev, "no resource definition for 2d registers\n");
1533 ret = -ENOENT;
1534 goto err_regs_map;
1535 }
1536
1537 info->regs2d_res = request_mem_region(res->start,
1538 resource_size(res),
1539 pdev->name);
1540
1541 if (info->regs2d_res == NULL) {
1542 dev_err(dev, "cannot claim registers\n");
1543 ret = -ENXIO;
1544 goto err_regs_map;
1545 }
1546
1547 info->regs2d = ioremap(res->start, resource_size(res));
1548 if (info->regs2d == NULL) {
1549 dev_err(dev, "cannot remap registers\n");
1550 ret = -ENXIO;
1551 goto err_regs2d_res;
1552 }
1553
1357 /* allocate, reserve resources for framebuffer */ 1554 /* allocate, reserve resources for framebuffer */
1358 res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 1555 res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
1359 if (res == NULL) { 1556 if (res == NULL) {
1360 dev_err(dev, "no memory resource defined\n"); 1557 dev_err(dev, "no memory resource defined\n");
1361 ret = -ENXIO; 1558 ret = -ENXIO;
1362 goto err_regs_map; 1559 goto err_regs2d_map;
1363 } 1560 }
1364 1561
1365 info->fbmem_res = request_mem_region(res->start, 1562 info->fbmem_res = request_mem_region(res->start,
1366 (res->end - res->start)+1, 1563 resource_size(res),
1367 pdev->name); 1564 pdev->name);
1368 if (info->fbmem_res == NULL) { 1565 if (info->fbmem_res == NULL) {
1369 dev_err(dev, "cannot claim framebuffer\n"); 1566 dev_err(dev, "cannot claim framebuffer\n");
1370 ret = -ENXIO; 1567 ret = -ENXIO;
1371 goto err_regs_map; 1568 goto err_regs2d_map;
1372 } 1569 }
1373 1570
1374 info->fbmem = ioremap(res->start, (res->end - res->start)+1); 1571 info->fbmem = ioremap(res->start, resource_size(res));
1375 if (info->fbmem == NULL) { 1572 if (info->fbmem == NULL) {
1376 dev_err(dev, "cannot remap framebuffer\n"); 1573 dev_err(dev, "cannot remap framebuffer\n");
1377 goto err_mem_res; 1574 goto err_mem_res;
1378 } 1575 }
1379 1576
1380 info->fbmem_len = (res->end - res->start)+1; 1577 info->fbmem_len = resource_size(res);
1381 1578
1382 /* clear framebuffer memory - avoids garbage data on unused fb */ 1579 /* clear framebuffer memory - avoids garbage data on unused fb */
1383 memset(info->fbmem, 0, info->fbmem_len); 1580 memset(info->fbmem, 0, info->fbmem_len);
@@ -1389,8 +1586,10 @@ static int sm501fb_start(struct sm501fb_info *info,
1389 /* enable display controller */ 1586 /* enable display controller */
1390 sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); 1587 sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1);
1391 1588
1392 /* setup cursors */ 1589 /* enable 2d controller */
1590 sm501_unit_power(dev->parent, SM501_GATE_2D_ENGINE, 1);
1393 1591
1592 /* setup cursors */
1394 sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR); 1593 sm501_init_cursor(info->fb[HEAD_CRT], SM501_DC_CRT_HWC_ADDR);
1395 sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR); 1594 sm501_init_cursor(info->fb[HEAD_PANEL], SM501_DC_PANEL_HWC_ADDR);
1396 1595
@@ -1400,6 +1599,13 @@ static int sm501fb_start(struct sm501fb_info *info,
1400 release_resource(info->fbmem_res); 1599 release_resource(info->fbmem_res);
1401 kfree(info->fbmem_res); 1600 kfree(info->fbmem_res);
1402 1601
1602 err_regs2d_map:
1603 iounmap(info->regs2d);
1604
1605 err_regs2d_res:
1606 release_resource(info->regs2d_res);
1607 kfree(info->regs2d_res);
1608
1403 err_regs_map: 1609 err_regs_map:
1404 iounmap(info->regs); 1610 iounmap(info->regs);
1405 1611
@@ -1420,6 +1626,10 @@ static void sm501fb_stop(struct sm501fb_info *info)
1420 release_resource(info->fbmem_res); 1626 release_resource(info->fbmem_res);
1421 kfree(info->fbmem_res); 1627 kfree(info->fbmem_res);
1422 1628
1629 iounmap(info->regs2d);
1630 release_resource(info->regs2d_res);
1631 kfree(info->regs2d_res);
1632
1423 iounmap(info->regs); 1633 iounmap(info->regs);
1424 release_resource(info->regs_res); 1634 release_resource(info->regs_res);
1425 kfree(info->regs_res); 1635 kfree(info->regs_res);
@@ -1486,7 +1696,8 @@ static int sm501fb_init_fb(struct fb_info *fb,
1486 par->ops.fb_cursor = NULL; 1696 par->ops.fb_cursor = NULL;
1487 1697
1488 fb->fbops = &par->ops; 1698 fb->fbops = &par->ops;
1489 fb->flags = FBINFO_FLAG_DEFAULT | 1699 fb->flags = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST |
1700 FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT |
1490 FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; 1701 FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN;
1491 1702
1492 /* fixed data */ 1703 /* fixed data */
diff --git a/drivers/video/stifb.c b/drivers/video/stifb.c
index 6120f0c526fe..876648e15e9d 100644
--- a/drivers/video/stifb.c
+++ b/drivers/video/stifb.c
@@ -756,9 +756,9 @@ hyperResetPlanes(struct stifb_info *fb, int enable)
756 if (fb->info.var.bits_per_pixel == 32) 756 if (fb->info.var.bits_per_pixel == 32)
757 controlPlaneReg = 0x04000F00; 757 controlPlaneReg = 0x04000F00;
758 else 758 else
759 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enought, but lets clear all 4 bits */ 759 controlPlaneReg = 0x00000F00; /* 0x00000800 should be enough, but lets clear all 4 bits */
760 else 760 else
761 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enought, but lets clear all 4 bits */ 761 controlPlaneReg = 0x00000F00; /* 0x00000100 should be enough, but lets clear all 4 bits */
762 762
763 switch (enable) { 763 switch (enable) {
764 case ENABLE: 764 case ENABLE:
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index ff43c8885028..980548390048 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -52,7 +52,7 @@
52 * 52 *
53 * 0.1.3 (released 1999-11-02) added Attila's panning support, code 53 * 0.1.3 (released 1999-11-02) added Attila's panning support, code
54 * reorg, hwcursor address page size alignment 54 * reorg, hwcursor address page size alignment
55 * (for mmaping both frame buffer and regs), 55 * (for mmapping both frame buffer and regs),
56 * and my changes to get rid of hardcoded 56 * and my changes to get rid of hardcoded
57 * VGA i/o register locations (uses PCI 57 * VGA i/o register locations (uses PCI
58 * configuration info now) 58 * configuration info now)
diff --git a/drivers/video/via/accel.c b/drivers/video/via/accel.c
index 9d4f3a49ba4a..d5077dfa9e00 100644
--- a/drivers/video/via/accel.c
+++ b/drivers/video/via/accel.c
@@ -137,7 +137,7 @@ static int hw_bitblt_1(void __iomem *engine, u8 op, u32 width, u32 height,
137 tmp, dst_pitch); 137 tmp, dst_pitch);
138 return -EINVAL; 138 return -EINVAL;
139 } 139 }
140 tmp = (tmp >> 3) | (dst_pitch << (16 - 3)); 140 tmp = VIA_PITCH_ENABLE | (tmp >> 3) | (dst_pitch << (16 - 3));
141 writel(tmp, engine + 0x38); 141 writel(tmp, engine + 0x38);
142 142
143 if (op == VIA_BITBLT_FILL) 143 if (op == VIA_BITBLT_FILL)
@@ -352,6 +352,9 @@ int viafb_init_engine(struct fb_info *info)
352 viapar->shared->vq_vram_addr = viapar->fbmem_free; 352 viapar->shared->vq_vram_addr = viapar->fbmem_free;
353 viapar->fbmem_used += VQ_SIZE; 353 viapar->fbmem_used += VQ_SIZE;
354 354
355 /* Init 2D engine reg to reset 2D engine */
356 writel(0x0, engine + VIA_REG_KEYCONTROL);
357
355 /* Init AGP and VQ regs */ 358 /* Init AGP and VQ regs */
356 switch (chip_name) { 359 switch (chip_name) {
357 case UNICHROME_K8M890: 360 case UNICHROME_K8M890:
diff --git a/drivers/video/via/dvi.c b/drivers/video/via/dvi.c
index c5c32b6b6e6c..67b36932212b 100644
--- a/drivers/video/via/dvi.c
+++ b/drivers/video/via/dvi.c
@@ -467,7 +467,7 @@ static int dvi_get_panel_size_from_DDCv1(void)
467 default: 467 default:
468 viaparinfo->tmds_setting_info->dvi_panel_size = 468 viaparinfo->tmds_setting_info->dvi_panel_size =
469 VIA_RES_1024X768; 469 VIA_RES_1024X768;
470 DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d !\ 470 DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d !\
471 set default panel size.\n", max_h); 471 set default panel size.\n", max_h);
472 break; 472 break;
473 } 473 }
@@ -534,7 +534,7 @@ static int dvi_get_panel_size_from_DDCv2(void)
534 default: 534 default:
535 viaparinfo->tmds_setting_info->dvi_panel_size = 535 viaparinfo->tmds_setting_info->dvi_panel_size =
536 VIA_RES_1024X768; 536 VIA_RES_1024X768;
537 DEBUG_MSG(KERN_INFO "Unknow panel size max resolution = %d!\ 537 DEBUG_MSG(KERN_INFO "Unknown panel size max resolution = %d!\
538 set default panel size.\n", HSize); 538 set default panel size.\n", HSize);
539 break; 539 break;
540 } 540 }
diff --git a/drivers/video/via/lcd.c b/drivers/video/via/lcd.c
index e3e597f937a5..09353e2b92f6 100644
--- a/drivers/video/via/lcd.c
+++ b/drivers/video/via/lcd.c
@@ -1134,45 +1134,33 @@ static void integrated_lvds_enable(struct lvds_setting_information
1134 *plvds_setting_info, 1134 *plvds_setting_info,
1135 struct lvds_chip_information *plvds_chip_info) 1135 struct lvds_chip_information *plvds_chip_info)
1136{ 1136{
1137 bool turn_on_first_powersequence = false;
1138 bool turn_on_second_powersequence = false;
1139
1140 DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n", 1137 DEBUG_MSG(KERN_INFO "integrated_lvds_enable, out_interface:%d\n",
1141 plvds_chip_info->output_interface); 1138 plvds_chip_info->output_interface);
1142 if (plvds_setting_info->lcd_mode == LCD_SPWG) 1139 if (plvds_setting_info->lcd_mode == LCD_SPWG)
1143 viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1); 1140 viafb_write_reg_mask(CRD2, VIACR, 0x00, BIT0 + BIT1);
1144 else 1141 else
1145 viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1); 1142 viafb_write_reg_mask(CRD2, VIACR, 0x03, BIT0 + BIT1);
1146 if (INTERFACE_LVDS0LVDS1 == plvds_chip_info->output_interface)
1147 turn_on_first_powersequence = true;
1148 if (INTERFACE_LVDS0 == plvds_chip_info->output_interface)
1149 turn_on_first_powersequence = true;
1150 if (INTERFACE_LVDS1 == plvds_chip_info->output_interface)
1151 turn_on_second_powersequence = true;
1152
1153 if (turn_on_second_powersequence) {
1154 /* Use second power sequence control: */
1155
1156 /* Use hardware control power sequence. */
1157 viafb_write_reg_mask(CRD3, VIACR, 0, BIT0);
1158
1159 /* Turn on back light. */
1160 viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7);
1161 1143
1162 /* Turn on hardware power sequence. */ 1144 switch (plvds_chip_info->output_interface) {
1163 viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1); 1145 case INTERFACE_LVDS0LVDS1:
1164 } 1146 case INTERFACE_LVDS0:
1165 if (turn_on_first_powersequence) {
1166 /* Use first power sequence control: */ 1147 /* Use first power sequence control: */
1167
1168 /* Use hardware control power sequence. */ 1148 /* Use hardware control power sequence. */
1169 viafb_write_reg_mask(CR91, VIACR, 0, BIT0); 1149 viafb_write_reg_mask(CR91, VIACR, 0, BIT0);
1170
1171 /* Turn on back light. */ 1150 /* Turn on back light. */
1172 viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7); 1151 viafb_write_reg_mask(CR91, VIACR, 0, BIT6 + BIT7);
1173
1174 /* Turn on hardware power sequence. */ 1152 /* Turn on hardware power sequence. */
1175 viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3); 1153 viafb_write_reg_mask(CR6A, VIACR, 0x08, BIT3);
1154 break;
1155 case INTERFACE_LVDS1:
1156 /* Use second power sequence control: */
1157 /* Use hardware control power sequence. */
1158 viafb_write_reg_mask(CRD3, VIACR, 0, BIT0);
1159 /* Turn on back light. */
1160 viafb_write_reg_mask(CRD3, VIACR, 0, BIT6 + BIT7);
1161 /* Turn on hardware power sequence. */
1162 viafb_write_reg_mask(CRD4, VIACR, 0x02, BIT1);
1163 break;
1176 } 1164 }
1177 1165
1178 /* Turn DFP High/Low pad on. */ 1166 /* Turn DFP High/Low pad on. */
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c
index 56ec696e8afa..3028e7ddc3b5 100644
--- a/drivers/video/via/viafbdev.c
+++ b/drivers/video/via/viafbdev.c
@@ -177,16 +177,15 @@ static int viafb_set_par(struct fb_info *info)
177 } 177 }
178 178
179 if (vmode_index != VIA_RES_INVALID) { 179 if (vmode_index != VIA_RES_INVALID) {
180 viafb_setmode(vmode_index, info->var.xres, info->var.yres,
181 info->var.bits_per_pixel, vmode_index1,
182 viafb_second_xres, viafb_second_yres, viafb_bpp1);
183
184 viafb_update_fix(info); 180 viafb_update_fix(info);
185 viafb_bpp = info->var.bits_per_pixel; 181 viafb_bpp = info->var.bits_per_pixel;
186 if (info->var.accel_flags & FB_ACCELF_TEXT) 182 if (info->var.accel_flags & FB_ACCELF_TEXT)
187 info->flags &= ~FBINFO_HWACCEL_DISABLED; 183 info->flags &= ~FBINFO_HWACCEL_DISABLED;
188 else 184 else
189 info->flags |= FBINFO_HWACCEL_DISABLED; 185 info->flags |= FBINFO_HWACCEL_DISABLED;
186 viafb_setmode(vmode_index, info->var.xres, info->var.yres,
187 info->var.bits_per_pixel, vmode_index1,
188 viafb_second_xres, viafb_second_yres, viafb_bpp1);
190 } 189 }
191 190
192 return 0; 191 return 0;
@@ -680,7 +679,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
680 if (!viafb_gamma_table) 679 if (!viafb_gamma_table)
681 return -ENOMEM; 680 return -ENOMEM;
682 if (copy_from_user(viafb_gamma_table, argp, 681 if (copy_from_user(viafb_gamma_table, argp,
683 sizeof(viafb_gamma_table))) { 682 256 * sizeof(u32))) {
684 kfree(viafb_gamma_table); 683 kfree(viafb_gamma_table);
685 return -EFAULT; 684 return -EFAULT;
686 } 685 }
@@ -694,7 +693,7 @@ static int viafb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
694 return -ENOMEM; 693 return -ENOMEM;
695 viafb_get_gamma_table(viafb_gamma_table); 694 viafb_get_gamma_table(viafb_gamma_table);
696 if (copy_to_user(argp, viafb_gamma_table, 695 if (copy_to_user(argp, viafb_gamma_table,
697 sizeof(viafb_gamma_table))) { 696 256 * sizeof(u32))) {
698 kfree(viafb_gamma_table); 697 kfree(viafb_gamma_table);
699 return -EFAULT; 698 return -EFAULT;
700 } 699 }
@@ -872,7 +871,9 @@ static int viafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
872 if (info->flags & FBINFO_HWACCEL_DISABLED || info != viafbinfo) 871 if (info->flags & FBINFO_HWACCEL_DISABLED || info != viafbinfo)
873 return -ENODEV; 872 return -ENODEV;
874 873
875 if (chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2) 874 /* LCD ouput does not support hw cursors (at least on VN896) */
875 if ((chip_name == UNICHROME_CLE266 && viapar->iga_path == IGA2) ||
876 viafb_LCD_ON)
876 return -ENODEV; 877 return -ENODEV;
877 878
878 viafb_show_hw_cursor(info, HW_Cursor_OFF); 879 viafb_show_hw_cursor(info, HW_Cursor_OFF);
@@ -1797,7 +1798,7 @@ static const struct file_operations viafb_vt1636_proc_fops = {
1797static void viafb_init_proc(struct proc_dir_entry **viafb_entry) 1798static void viafb_init_proc(struct proc_dir_entry **viafb_entry)
1798{ 1799{
1799 *viafb_entry = proc_mkdir("viafb", NULL); 1800 *viafb_entry = proc_mkdir("viafb", NULL);
1800 if (viafb_entry) { 1801 if (*viafb_entry) {
1801 proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops); 1802 proc_create("dvp0", 0, *viafb_entry, &viafb_dvp0_proc_fops);
1802 proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops); 1803 proc_create("dvp1", 0, *viafb_entry, &viafb_dvp1_proc_fops);
1803 proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops); 1804 proc_create("dfph", 0, *viafb_entry, &viafb_dfph_proc_fops);
diff --git a/drivers/video/vt8623fb.c b/drivers/video/vt8623fb.c
index 3df17dc8c3d7..65ccd215d496 100644
--- a/drivers/video/vt8623fb.c
+++ b/drivers/video/vt8623fb.c
@@ -446,7 +446,7 @@ static int vt8623fb_set_par(struct fb_info *info)
446 446
447 svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus 447 svga_wseq_mask(0x1E, 0xF0, 0xF0); // DI/DVP bus
448 svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus 448 svga_wseq_mask(0x2A, 0x0F, 0x0F); // DI/DVP bus
449 svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read treshold 449 svga_wseq_mask(0x16, 0x08, 0xBF); // FIFO read threshold
450 vga_wseq(NULL, 0x17, 0x1F); // FIFO depth 450 vga_wseq(NULL, 0x17, 0x1F); // FIFO depth
451 vga_wseq(NULL, 0x18, 0x4E); 451 vga_wseq(NULL, 0x18, 0x4E);
452 svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ? 452 svga_wseq_mask(0x1A, 0x08, 0x08); // enable MMIO ?
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c
index 54cd91610174..603598f4dbb1 100644
--- a/drivers/video/xen-fbfront.c
+++ b/drivers/video/xen-fbfront.c
@@ -25,7 +25,10 @@
25#include <linux/module.h> 25#include <linux/module.h>
26#include <linux/vmalloc.h> 26#include <linux/vmalloc.h>
27#include <linux/mm.h> 27#include <linux/mm.h>
28
28#include <asm/xen/hypervisor.h> 29#include <asm/xen/hypervisor.h>
30
31#include <xen/xen.h>
29#include <xen/events.h> 32#include <xen/events.h>
30#include <xen/page.h> 33#include <xen/page.h>
31#include <xen/interface/io/fbif.h> 34#include <xen/interface/io/fbif.h>
@@ -440,7 +443,7 @@ static int __devinit xenfb_probe(struct xenbus_device *dev,
440 fb_info->fix.type = FB_TYPE_PACKED_PIXELS; 443 fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
441 fb_info->fix.accel = FB_ACCEL_NONE; 444 fb_info->fix.accel = FB_ACCEL_NONE;
442 445
443 fb_info->flags = FBINFO_FLAG_DEFAULT; 446 fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
444 447
445 ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); 448 ret = fb_alloc_cmap(&fb_info->cmap, 256, 0);
446 if (ret < 0) { 449 if (ret < 0) {