diff options
Diffstat (limited to 'drivers')
62 files changed, 3618 insertions, 3392 deletions
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 202d1b4b9bee..35cc526e6c93 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c | |||
| @@ -44,8 +44,6 @@ | |||
| 44 | #include <media/v4l2-device.h> | 44 | #include <media/v4l2-device.h> |
| 45 | #include <media/v4l2-ioctl.h> | 45 | #include <media/v4l2-ioctl.h> |
| 46 | 46 | ||
| 47 | #include <plat/cpu.h> | ||
| 48 | #include <linux/omap-dma.h> | ||
| 49 | #include <video/omapvrfb.h> | 47 | #include <video/omapvrfb.h> |
| 50 | #include <video/omapdss.h> | 48 | #include <video/omapdss.h> |
| 51 | 49 | ||
| @@ -2043,7 +2041,7 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) | |||
| 2043 | vout->vid_info.id = k + 1; | 2041 | vout->vid_info.id = k + 1; |
| 2044 | 2042 | ||
| 2045 | /* Set VRFB as rotation_type for omap2 and omap3 */ | 2043 | /* Set VRFB as rotation_type for omap2 and omap3 */ |
| 2046 | if (cpu_is_omap24xx() || cpu_is_omap34xx()) | 2044 | if (omap_vout_dss_omap24xx() || omap_vout_dss_omap34xx()) |
| 2047 | vout->vid_info.rotation_type = VOUT_ROT_VRFB; | 2045 | vout->vid_info.rotation_type = VOUT_ROT_VRFB; |
| 2048 | 2046 | ||
| 2049 | /* Setup the default configuration for the video devices | 2047 | /* Setup the default configuration for the video devices |
| @@ -2160,14 +2158,23 @@ static int __init omap_vout_probe(struct platform_device *pdev) | |||
| 2160 | struct omap_dss_device *def_display; | 2158 | struct omap_dss_device *def_display; |
| 2161 | struct omap2video_device *vid_dev = NULL; | 2159 | struct omap2video_device *vid_dev = NULL; |
| 2162 | 2160 | ||
| 2161 | ret = omapdss_compat_init(); | ||
| 2162 | if (ret) { | ||
| 2163 | dev_err(&pdev->dev, "failed to init dss\n"); | ||
| 2164 | return ret; | ||
| 2165 | } | ||
| 2166 | |||
| 2163 | if (pdev->num_resources == 0) { | 2167 | if (pdev->num_resources == 0) { |
| 2164 | dev_err(&pdev->dev, "probed for an unknown device\n"); | 2168 | dev_err(&pdev->dev, "probed for an unknown device\n"); |
| 2165 | return -ENODEV; | 2169 | ret = -ENODEV; |
| 2170 | goto err_dss_init; | ||
| 2166 | } | 2171 | } |
| 2167 | 2172 | ||
| 2168 | vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL); | 2173 | vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL); |
| 2169 | if (vid_dev == NULL) | 2174 | if (vid_dev == NULL) { |
| 2170 | return -ENOMEM; | 2175 | ret = -ENOMEM; |
| 2176 | goto err_dss_init; | ||
| 2177 | } | ||
| 2171 | 2178 | ||
| 2172 | vid_dev->num_displays = 0; | 2179 | vid_dev->num_displays = 0; |
| 2173 | for_each_dss_dev(dssdev) { | 2180 | for_each_dss_dev(dssdev) { |
| @@ -2262,6 +2269,8 @@ probe_err1: | |||
| 2262 | } | 2269 | } |
| 2263 | probe_err0: | 2270 | probe_err0: |
| 2264 | kfree(vid_dev); | 2271 | kfree(vid_dev); |
| 2272 | err_dss_init: | ||
| 2273 | omapdss_compat_uninit(); | ||
| 2265 | return ret; | 2274 | return ret; |
| 2266 | } | 2275 | } |
| 2267 | 2276 | ||
diff --git a/drivers/media/platform/omap/omap_voutlib.c b/drivers/media/platform/omap/omap_voutlib.c index 115408b9274f..80b0d88f125c 100644 --- a/drivers/media/platform/omap/omap_voutlib.c +++ b/drivers/media/platform/omap/omap_voutlib.c | |||
| @@ -26,7 +26,7 @@ | |||
| 26 | 26 | ||
| 27 | #include <linux/dma-mapping.h> | 27 | #include <linux/dma-mapping.h> |
| 28 | 28 | ||
| 29 | #include <plat/cpu.h> | 29 | #include <video/omapdss.h> |
| 30 | 30 | ||
| 31 | #include "omap_voutlib.h" | 31 | #include "omap_voutlib.h" |
| 32 | 32 | ||
| @@ -124,7 +124,7 @@ int omap_vout_new_window(struct v4l2_rect *crop, | |||
| 124 | win->chromakey = new_win->chromakey; | 124 | win->chromakey = new_win->chromakey; |
| 125 | 125 | ||
| 126 | /* Adjust the cropping window to allow for resizing limitation */ | 126 | /* Adjust the cropping window to allow for resizing limitation */ |
| 127 | if (cpu_is_omap24xx()) { | 127 | if (omap_vout_dss_omap24xx()) { |
| 128 | /* For 24xx limit is 8x to 1/2x scaling. */ | 128 | /* For 24xx limit is 8x to 1/2x scaling. */ |
| 129 | if ((crop->height/win->w.height) >= 2) | 129 | if ((crop->height/win->w.height) >= 2) |
| 130 | crop->height = win->w.height * 2; | 130 | crop->height = win->w.height * 2; |
| @@ -140,7 +140,7 @@ int omap_vout_new_window(struct v4l2_rect *crop, | |||
| 140 | if (crop->height != win->w.height) | 140 | if (crop->height != win->w.height) |
| 141 | crop->width = 768; | 141 | crop->width = 768; |
| 142 | } | 142 | } |
| 143 | } else if (cpu_is_omap34xx()) { | 143 | } else if (omap_vout_dss_omap34xx()) { |
| 144 | /* For 34xx limit is 8x to 1/4x scaling. */ | 144 | /* For 34xx limit is 8x to 1/4x scaling. */ |
| 145 | if ((crop->height/win->w.height) >= 4) | 145 | if ((crop->height/win->w.height) >= 4) |
| 146 | crop->height = win->w.height * 4; | 146 | crop->height = win->w.height * 4; |
| @@ -196,7 +196,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, | |||
| 196 | if (try_crop.width <= 0 || try_crop.height <= 0) | 196 | if (try_crop.width <= 0 || try_crop.height <= 0) |
| 197 | return -EINVAL; | 197 | return -EINVAL; |
| 198 | 198 | ||
| 199 | if (cpu_is_omap24xx()) { | 199 | if (omap_vout_dss_omap24xx()) { |
| 200 | if (try_crop.height != win->w.height) { | 200 | if (try_crop.height != win->w.height) { |
| 201 | /* If we're resizing vertically, we can't support a | 201 | /* If we're resizing vertically, we can't support a |
| 202 | * crop width wider than 768 pixels. | 202 | * crop width wider than 768 pixels. |
| @@ -207,9 +207,9 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, | |||
| 207 | } | 207 | } |
| 208 | /* vertical resizing */ | 208 | /* vertical resizing */ |
| 209 | vresize = (1024 * try_crop.height) / win->w.height; | 209 | vresize = (1024 * try_crop.height) / win->w.height; |
| 210 | if (cpu_is_omap24xx() && (vresize > 2048)) | 210 | if (omap_vout_dss_omap24xx() && (vresize > 2048)) |
| 211 | vresize = 2048; | 211 | vresize = 2048; |
| 212 | else if (cpu_is_omap34xx() && (vresize > 4096)) | 212 | else if (omap_vout_dss_omap34xx() && (vresize > 4096)) |
| 213 | vresize = 4096; | 213 | vresize = 4096; |
| 214 | 214 | ||
| 215 | win->w.height = ((1024 * try_crop.height) / vresize) & ~1; | 215 | win->w.height = ((1024 * try_crop.height) / vresize) & ~1; |
| @@ -226,9 +226,9 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, | |||
| 226 | } | 226 | } |
| 227 | /* horizontal resizing */ | 227 | /* horizontal resizing */ |
| 228 | hresize = (1024 * try_crop.width) / win->w.width; | 228 | hresize = (1024 * try_crop.width) / win->w.width; |
| 229 | if (cpu_is_omap24xx() && (hresize > 2048)) | 229 | if (omap_vout_dss_omap24xx() && (hresize > 2048)) |
| 230 | hresize = 2048; | 230 | hresize = 2048; |
| 231 | else if (cpu_is_omap34xx() && (hresize > 4096)) | 231 | else if (omap_vout_dss_omap34xx() && (hresize > 4096)) |
| 232 | hresize = 4096; | 232 | hresize = 4096; |
| 233 | 233 | ||
| 234 | win->w.width = ((1024 * try_crop.width) / hresize) & ~1; | 234 | win->w.width = ((1024 * try_crop.width) / hresize) & ~1; |
| @@ -243,7 +243,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, | |||
| 243 | if (try_crop.width == 0) | 243 | if (try_crop.width == 0) |
| 244 | try_crop.width = 2; | 244 | try_crop.width = 2; |
| 245 | } | 245 | } |
| 246 | if (cpu_is_omap24xx()) { | 246 | if (omap_vout_dss_omap24xx()) { |
| 247 | if ((try_crop.height/win->w.height) >= 2) | 247 | if ((try_crop.height/win->w.height) >= 2) |
| 248 | try_crop.height = win->w.height * 2; | 248 | try_crop.height = win->w.height * 2; |
| 249 | 249 | ||
| @@ -258,7 +258,7 @@ int omap_vout_new_crop(struct v4l2_pix_format *pix, | |||
| 258 | if (try_crop.height != win->w.height) | 258 | if (try_crop.height != win->w.height) |
| 259 | try_crop.width = 768; | 259 | try_crop.width = 768; |
| 260 | } | 260 | } |
| 261 | } else if (cpu_is_omap34xx()) { | 261 | } else if (omap_vout_dss_omap34xx()) { |
| 262 | if ((try_crop.height/win->w.height) >= 4) | 262 | if ((try_crop.height/win->w.height) >= 4) |
| 263 | try_crop.height = win->w.height * 4; | 263 | try_crop.height = win->w.height * 4; |
| 264 | 264 | ||
| @@ -337,3 +337,21 @@ void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size) | |||
| 337 | } | 337 | } |
| 338 | free_pages((unsigned long) virtaddr, order); | 338 | free_pages((unsigned long) virtaddr, order); |
| 339 | } | 339 | } |
| 340 | |||
| 341 | bool omap_vout_dss_omap24xx(void) | ||
| 342 | { | ||
| 343 | return omapdss_get_version() == OMAPDSS_VER_OMAP24xx; | ||
| 344 | } | ||
| 345 | |||
| 346 | bool omap_vout_dss_omap34xx(void) | ||
| 347 | { | ||
| 348 | switch (omapdss_get_version()) { | ||
| 349 | case OMAPDSS_VER_OMAP34xx_ES1: | ||
| 350 | case OMAPDSS_VER_OMAP34xx_ES3: | ||
| 351 | case OMAPDSS_VER_OMAP3630: | ||
| 352 | case OMAPDSS_VER_AM35xx: | ||
| 353 | return true; | ||
| 354 | default: | ||
| 355 | return false; | ||
| 356 | } | ||
| 357 | } | ||
diff --git a/drivers/media/platform/omap/omap_voutlib.h b/drivers/media/platform/omap/omap_voutlib.h index e51750a597e3..f9d1c0779f33 100644 --- a/drivers/media/platform/omap/omap_voutlib.h +++ b/drivers/media/platform/omap/omap_voutlib.h | |||
| @@ -32,5 +32,8 @@ void omap_vout_new_format(struct v4l2_pix_format *pix, | |||
| 32 | struct v4l2_window *win); | 32 | struct v4l2_window *win); |
| 33 | unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr); | 33 | unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr); |
| 34 | void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size); | 34 | void omap_vout_free_buffer(unsigned long virtaddr, u32 buf_size); |
| 35 | |||
| 36 | bool omap_vout_dss_omap24xx(void); | ||
| 37 | bool omap_vout_dss_omap34xx(void); | ||
| 35 | #endif /* #ifndef OMAP_VOUTLIB_H */ | 38 | #endif /* #ifndef OMAP_VOUTLIB_H */ |
| 36 | 39 | ||
diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index d4823fd67768..84943e5ba1d6 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c | |||
| @@ -565,6 +565,14 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
| 565 | 565 | ||
| 566 | dev->dev_private = priv; | 566 | dev->dev_private = priv; |
| 567 | 567 | ||
| 568 | ret = omapdss_compat_init(); | ||
| 569 | if (ret) { | ||
| 570 | dev_err(dev->dev, "coult not init omapdss\n"); | ||
| 571 | dev->dev_private = NULL; | ||
| 572 | kfree(priv); | ||
| 573 | return ret; | ||
| 574 | } | ||
| 575 | |||
| 568 | priv->wq = alloc_ordered_workqueue("omapdrm", 0); | 576 | priv->wq = alloc_ordered_workqueue("omapdrm", 0); |
| 569 | 577 | ||
| 570 | INIT_LIST_HEAD(&priv->obj_list); | 578 | INIT_LIST_HEAD(&priv->obj_list); |
| @@ -576,6 +584,7 @@ static int dev_load(struct drm_device *dev, unsigned long flags) | |||
| 576 | dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); | 584 | dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret); |
| 577 | dev->dev_private = NULL; | 585 | dev->dev_private = NULL; |
| 578 | kfree(priv); | 586 | kfree(priv); |
| 587 | omapdss_compat_uninit(); | ||
| 579 | return ret; | 588 | return ret; |
| 580 | } | 589 | } |
| 581 | 590 | ||
| @@ -610,6 +619,8 @@ static int dev_unload(struct drm_device *dev) | |||
| 610 | flush_workqueue(priv->wq); | 619 | flush_workqueue(priv->wq); |
| 611 | destroy_workqueue(priv->wq); | 620 | destroy_workqueue(priv->wq); |
| 612 | 621 | ||
| 622 | omapdss_compat_uninit(); | ||
| 623 | |||
| 613 | kfree(dev->dev_private); | 624 | kfree(dev->dev_private); |
| 614 | dev->dev_private = NULL; | 625 | dev->dev_private = NULL; |
| 615 | 626 | ||
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index d08d7998a4aa..9c31277b3a81 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
| @@ -2045,7 +2045,7 @@ config FB_S3C_DEBUG_REGWRITE | |||
| 2045 | bool "Debug register writes" | 2045 | bool "Debug register writes" |
| 2046 | depends on FB_S3C | 2046 | depends on FB_S3C |
| 2047 | ---help--- | 2047 | ---help--- |
| 2048 | Show all register writes via printk(KERN_DEBUG) | 2048 | Show all register writes via pr_debug() |
| 2049 | 2049 | ||
| 2050 | config FB_S3C2410 | 2050 | config FB_S3C2410 |
| 2051 | tristate "S3C2410 LCD framebuffer support" | 2051 | tristate "S3C2410 LCD framebuffer support" |
| @@ -2442,4 +2442,19 @@ config FB_SH_MOBILE_MERAM | |||
| 2442 | Up to 4 memory channels can be configured, allowing 4 RGB or | 2442 | Up to 4 memory channels can be configured, allowing 4 RGB or |
| 2443 | 2 YCbCr framebuffers to be configured. | 2443 | 2 YCbCr framebuffers to be configured. |
| 2444 | 2444 | ||
| 2445 | config FB_SSD1307 | ||
| 2446 | tristate "Solomon SSD1307 framebuffer support" | ||
| 2447 | depends on FB && I2C | ||
| 2448 | depends on OF | ||
| 2449 | depends on GENERIC_GPIO | ||
| 2450 | select FB_SYS_FOPS | ||
| 2451 | select FB_SYS_FILLRECT | ||
| 2452 | select FB_SYS_COPYAREA | ||
| 2453 | select FB_SYS_IMAGEBLIT | ||
| 2454 | select FB_DEFERRED_IO | ||
| 2455 | select PWM | ||
| 2456 | help | ||
| 2457 | This driver implements support for the Solomon SSD1307 | ||
| 2458 | OLED controller over I2C. | ||
| 2459 | |||
| 2445 | endmenu | 2460 | endmenu |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 23e948ebfab8..768a137a1bac 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
| @@ -161,6 +161,7 @@ obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o | |||
| 161 | obj-$(CONFIG_FB_MX3) += mx3fb.o | 161 | obj-$(CONFIG_FB_MX3) += mx3fb.o |
| 162 | obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o | 162 | obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o |
| 163 | obj-$(CONFIG_FB_MXS) += mxsfb.o | 163 | obj-$(CONFIG_FB_MXS) += mxsfb.o |
| 164 | obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o | ||
| 164 | 165 | ||
| 165 | # the test framebuffer is last | 166 | # the test framebuffer is last |
| 166 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o | 167 | obj-$(CONFIG_FB_VIRTUAL) += vfb.o |
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c index 25f835bf3d72..46dd8f5d2e9e 100644 --- a/drivers/video/console/softcursor.c +++ b/drivers/video/console/softcursor.c | |||
| @@ -35,8 +35,7 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor) | |||
| 35 | dsize = s_pitch * cursor->image.height; | 35 | dsize = s_pitch * cursor->image.height; |
| 36 | 36 | ||
| 37 | if (dsize + sizeof(struct fb_image) != ops->cursor_size) { | 37 | if (dsize + sizeof(struct fb_image) != ops->cursor_size) { |
| 38 | if (ops->cursor_src != NULL) | 38 | kfree(ops->cursor_src); |
| 39 | kfree(ops->cursor_src); | ||
| 40 | ops->cursor_size = dsize + sizeof(struct fb_image); | 39 | ops->cursor_size = dsize + sizeof(struct fb_image); |
| 41 | 40 | ||
| 42 | ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC); | 41 | ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC); |
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 80665f66ac1a..46534e00fe01 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c | |||
| @@ -213,62 +213,51 @@ static struct fb_fix_screeninfo da8xx_fb_fix __devinitdata = { | |||
| 213 | .accel = FB_ACCEL_NONE | 213 | .accel = FB_ACCEL_NONE |
| 214 | }; | 214 | }; |
| 215 | 215 | ||
| 216 | struct da8xx_panel { | 216 | static struct fb_videomode known_lcd_panels[] = { |
| 217 | const char name[25]; /* Full name <vendor>_<model> */ | ||
| 218 | unsigned short width; | ||
| 219 | unsigned short height; | ||
| 220 | int hfp; /* Horizontal front porch */ | ||
| 221 | int hbp; /* Horizontal back porch */ | ||
| 222 | int hsw; /* Horizontal Sync Pulse Width */ | ||
| 223 | int vfp; /* Vertical front porch */ | ||
| 224 | int vbp; /* Vertical back porch */ | ||
| 225 | int vsw; /* Vertical Sync Pulse Width */ | ||
| 226 | unsigned int pxl_clk; /* Pixel clock */ | ||
| 227 | unsigned char invert_pxl_clk; /* Invert Pixel clock */ | ||
| 228 | }; | ||
| 229 | |||
| 230 | static struct da8xx_panel known_lcd_panels[] = { | ||
| 231 | /* Sharp LCD035Q3DG01 */ | 217 | /* Sharp LCD035Q3DG01 */ |
| 232 | [0] = { | 218 | [0] = { |
| 233 | .name = "Sharp_LCD035Q3DG01", | 219 | .name = "Sharp_LCD035Q3DG01", |
| 234 | .width = 320, | 220 | .xres = 320, |
| 235 | .height = 240, | 221 | .yres = 240, |
| 236 | .hfp = 8, | 222 | .pixclock = 4608000, |
| 237 | .hbp = 6, | 223 | .left_margin = 6, |
| 238 | .hsw = 0, | 224 | .right_margin = 8, |
| 239 | .vfp = 2, | 225 | .upper_margin = 2, |
| 240 | .vbp = 2, | 226 | .lower_margin = 2, |
| 241 | .vsw = 0, | 227 | .hsync_len = 0, |
| 242 | .pxl_clk = 4608000, | 228 | .vsync_len = 0, |
| 243 | .invert_pxl_clk = 1, | 229 | .sync = FB_SYNC_CLK_INVERT | |
| 230 | FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
| 244 | }, | 231 | }, |
| 245 | /* Sharp LK043T1DG01 */ | 232 | /* Sharp LK043T1DG01 */ |
| 246 | [1] = { | 233 | [1] = { |
| 247 | .name = "Sharp_LK043T1DG01", | 234 | .name = "Sharp_LK043T1DG01", |
| 248 | .width = 480, | 235 | .xres = 480, |
| 249 | .height = 272, | 236 | .yres = 272, |
| 250 | .hfp = 2, | 237 | .pixclock = 7833600, |
| 251 | .hbp = 2, | 238 | .left_margin = 2, |
| 252 | .hsw = 41, | 239 | .right_margin = 2, |
| 253 | .vfp = 2, | 240 | .upper_margin = 2, |
| 254 | .vbp = 2, | 241 | .lower_margin = 2, |
| 255 | .vsw = 10, | 242 | .hsync_len = 41, |
| 256 | .pxl_clk = 7833600, | 243 | .vsync_len = 10, |
| 257 | .invert_pxl_clk = 0, | 244 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
| 245 | .flag = 0, | ||
| 258 | }, | 246 | }, |
| 259 | [2] = { | 247 | [2] = { |
| 260 | /* Hitachi SP10Q010 */ | 248 | /* Hitachi SP10Q010 */ |
| 261 | .name = "SP10Q010", | 249 | .name = "SP10Q010", |
| 262 | .width = 320, | 250 | .xres = 320, |
| 263 | .height = 240, | 251 | .yres = 240, |
| 264 | .hfp = 10, | 252 | .pixclock = 7833600, |
| 265 | .hbp = 10, | 253 | .left_margin = 10, |
| 266 | .hsw = 10, | 254 | .right_margin = 10, |
| 267 | .vfp = 10, | 255 | .upper_margin = 10, |
| 268 | .vbp = 10, | 256 | .lower_margin = 10, |
| 269 | .vsw = 10, | 257 | .hsync_len = 10, |
| 270 | .pxl_clk = 7833600, | 258 | .vsync_len = 10, |
| 271 | .invert_pxl_clk = 0, | 259 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, |
| 260 | .flag = 0, | ||
| 272 | }, | 261 | }, |
| 273 | }; | 262 | }; |
| 274 | 263 | ||
| @@ -399,10 +388,9 @@ static int lcd_cfg_dma(int burst_size, int fifo_th) | |||
| 399 | reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8); | 388 | reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8); |
| 400 | break; | 389 | break; |
| 401 | case 16: | 390 | case 16: |
| 391 | default: | ||
| 402 | reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16); | 392 | reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16); |
| 403 | break; | 393 | break; |
| 404 | default: | ||
| 405 | return -EINVAL; | ||
| 406 | } | 394 | } |
| 407 | 395 | ||
| 408 | reg |= (fifo_th << 8); | 396 | reg |= (fifo_th << 8); |
| @@ -447,7 +435,8 @@ static void lcd_cfg_vertical_sync(int back_porch, int pulse_width, | |||
| 447 | lcdc_write(reg, LCD_RASTER_TIMING_1_REG); | 435 | lcdc_write(reg, LCD_RASTER_TIMING_1_REG); |
| 448 | } | 436 | } |
| 449 | 437 | ||
| 450 | static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) | 438 | static int lcd_cfg_display(const struct lcd_ctrl_config *cfg, |
| 439 | struct fb_videomode *panel) | ||
| 451 | { | 440 | { |
| 452 | u32 reg; | 441 | u32 reg; |
| 453 | u32 reg_int; | 442 | u32 reg_int; |
| @@ -456,7 +445,7 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) | |||
| 456 | LCD_MONO_8BIT_MODE | | 445 | LCD_MONO_8BIT_MODE | |
| 457 | LCD_MONOCHROME_MODE); | 446 | LCD_MONOCHROME_MODE); |
| 458 | 447 | ||
| 459 | switch (cfg->p_disp_panel->panel_shade) { | 448 | switch (cfg->panel_shade) { |
| 460 | case MONOCHROME: | 449 | case MONOCHROME: |
| 461 | reg |= LCD_MONOCHROME_MODE; | 450 | reg |= LCD_MONOCHROME_MODE; |
| 462 | if (cfg->mono_8bit_mode) | 451 | if (cfg->mono_8bit_mode) |
| @@ -469,7 +458,9 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) | |||
| 469 | break; | 458 | break; |
| 470 | 459 | ||
| 471 | case COLOR_PASSIVE: | 460 | case COLOR_PASSIVE: |
| 472 | if (cfg->stn_565_mode) | 461 | /* AC bias applicable only for Pasive panels */ |
| 462 | lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt); | ||
| 463 | if (cfg->bpp == 12 && cfg->stn_565_mode) | ||
| 473 | reg |= LCD_STN_565_ENABLE; | 464 | reg |= LCD_STN_565_ENABLE; |
| 474 | break; | 465 | break; |
| 475 | 466 | ||
| @@ -490,22 +481,19 @@ static int lcd_cfg_display(const struct lcd_ctrl_config *cfg) | |||
| 490 | 481 | ||
| 491 | reg = lcdc_read(LCD_RASTER_TIMING_2_REG); | 482 | reg = lcdc_read(LCD_RASTER_TIMING_2_REG); |
| 492 | 483 | ||
| 493 | if (cfg->sync_ctrl) | 484 | reg |= LCD_SYNC_CTRL; |
| 494 | reg |= LCD_SYNC_CTRL; | ||
| 495 | else | ||
| 496 | reg &= ~LCD_SYNC_CTRL; | ||
| 497 | 485 | ||
| 498 | if (cfg->sync_edge) | 486 | if (cfg->sync_edge) |
| 499 | reg |= LCD_SYNC_EDGE; | 487 | reg |= LCD_SYNC_EDGE; |
| 500 | else | 488 | else |
| 501 | reg &= ~LCD_SYNC_EDGE; | 489 | reg &= ~LCD_SYNC_EDGE; |
| 502 | 490 | ||
| 503 | if (cfg->invert_line_clock) | 491 | if (panel->sync & FB_SYNC_HOR_HIGH_ACT) |
| 504 | reg |= LCD_INVERT_LINE_CLOCK; | 492 | reg |= LCD_INVERT_LINE_CLOCK; |
| 505 | else | 493 | else |
| 506 | reg &= ~LCD_INVERT_LINE_CLOCK; | 494 | reg &= ~LCD_INVERT_LINE_CLOCK; |
| 507 | 495 | ||
| 508 | if (cfg->invert_frm_clock) | 496 | if (panel->sync & FB_SYNC_VERT_HIGH_ACT) |
| 509 | reg |= LCD_INVERT_FRAME_CLOCK; | 497 | reg |= LCD_INVERT_FRAME_CLOCK; |
| 510 | else | 498 | else |
| 511 | reg &= ~LCD_INVERT_FRAME_CLOCK; | 499 | reg &= ~LCD_INVERT_FRAME_CLOCK; |
| @@ -728,7 +716,7 @@ static void lcd_calc_clk_divider(struct da8xx_fb_par *par) | |||
| 728 | } | 716 | } |
| 729 | 717 | ||
| 730 | static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | 718 | static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, |
| 731 | struct da8xx_panel *panel) | 719 | struct fb_videomode *panel) |
| 732 | { | 720 | { |
| 733 | u32 bpp; | 721 | u32 bpp; |
| 734 | int ret = 0; | 722 | int ret = 0; |
| @@ -738,7 +726,7 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | |||
| 738 | /* Calculate the divider */ | 726 | /* Calculate the divider */ |
| 739 | lcd_calc_clk_divider(par); | 727 | lcd_calc_clk_divider(par); |
| 740 | 728 | ||
| 741 | if (panel->invert_pxl_clk) | 729 | if (panel->sync & FB_SYNC_CLK_INVERT) |
| 742 | lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | | 730 | lcdc_write((lcdc_read(LCD_RASTER_TIMING_2_REG) | |
| 743 | LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG); | 731 | LCD_INVERT_PIXEL_CLOCK), LCD_RASTER_TIMING_2_REG); |
| 744 | else | 732 | else |
| @@ -750,30 +738,23 @@ static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg, | |||
| 750 | if (ret < 0) | 738 | if (ret < 0) |
| 751 | return ret; | 739 | return ret; |
| 752 | 740 | ||
| 753 | /* Configure the AC bias properties. */ | ||
| 754 | lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt); | ||
| 755 | |||
| 756 | /* Configure the vertical and horizontal sync properties. */ | 741 | /* Configure the vertical and horizontal sync properties. */ |
| 757 | lcd_cfg_vertical_sync(panel->vbp, panel->vsw, panel->vfp); | 742 | lcd_cfg_vertical_sync(panel->lower_margin, panel->vsync_len, |
| 758 | lcd_cfg_horizontal_sync(panel->hbp, panel->hsw, panel->hfp); | 743 | panel->upper_margin); |
| 744 | lcd_cfg_horizontal_sync(panel->right_margin, panel->hsync_len, | ||
| 745 | panel->left_margin); | ||
| 759 | 746 | ||
| 760 | /* Configure for disply */ | 747 | /* Configure for disply */ |
| 761 | ret = lcd_cfg_display(cfg); | 748 | ret = lcd_cfg_display(cfg, panel); |
| 762 | if (ret < 0) | 749 | if (ret < 0) |
| 763 | return ret; | 750 | return ret; |
| 764 | 751 | ||
| 765 | if (QVGA != cfg->p_disp_panel->panel_type) | 752 | bpp = cfg->bpp; |
| 766 | return -EINVAL; | ||
| 767 | 753 | ||
| 768 | if (cfg->bpp <= cfg->p_disp_panel->max_bpp && | ||
| 769 | cfg->bpp >= cfg->p_disp_panel->min_bpp) | ||
| 770 | bpp = cfg->bpp; | ||
| 771 | else | ||
| 772 | bpp = cfg->p_disp_panel->max_bpp; | ||
| 773 | if (bpp == 12) | 754 | if (bpp == 12) |
| 774 | bpp = 16; | 755 | bpp = 16; |
| 775 | ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->width, | 756 | ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->xres, |
| 776 | (unsigned int)panel->height, bpp, | 757 | (unsigned int)panel->yres, bpp, |
| 777 | cfg->raster_order); | 758 | cfg->raster_order); |
| 778 | if (ret < 0) | 759 | if (ret < 0) |
| 779 | return ret; | 760 | return ret; |
| @@ -1235,7 +1216,7 @@ static int __devinit fb_probe(struct platform_device *device) | |||
| 1235 | struct da8xx_lcdc_platform_data *fb_pdata = | 1216 | struct da8xx_lcdc_platform_data *fb_pdata = |
| 1236 | device->dev.platform_data; | 1217 | device->dev.platform_data; |
| 1237 | struct lcd_ctrl_config *lcd_cfg; | 1218 | struct lcd_ctrl_config *lcd_cfg; |
| 1238 | struct da8xx_panel *lcdc_info; | 1219 | struct fb_videomode *lcdc_info; |
| 1239 | struct fb_info *da8xx_fb_info; | 1220 | struct fb_info *da8xx_fb_info; |
| 1240 | struct clk *fb_clk = NULL; | 1221 | struct clk *fb_clk = NULL; |
| 1241 | struct da8xx_fb_par *par; | 1222 | struct da8xx_fb_par *par; |
| @@ -1267,7 +1248,7 @@ static int __devinit fb_probe(struct platform_device *device) | |||
| 1267 | goto err_request_mem; | 1248 | goto err_request_mem; |
| 1268 | } | 1249 | } |
| 1269 | 1250 | ||
| 1270 | fb_clk = clk_get(&device->dev, NULL); | 1251 | fb_clk = clk_get(&device->dev, "fck"); |
| 1271 | if (IS_ERR(fb_clk)) { | 1252 | if (IS_ERR(fb_clk)) { |
| 1272 | dev_err(&device->dev, "Can not get device clock\n"); | 1253 | dev_err(&device->dev, "Can not get device clock\n"); |
| 1273 | ret = -ENODEV; | 1254 | ret = -ENODEV; |
| @@ -1283,6 +1264,7 @@ static int __devinit fb_probe(struct platform_device *device) | |||
| 1283 | lcd_revision = LCD_VERSION_1; | 1264 | lcd_revision = LCD_VERSION_1; |
| 1284 | break; | 1265 | break; |
| 1285 | case 0x4F200800: | 1266 | case 0x4F200800: |
| 1267 | case 0x4F201000: | ||
| 1286 | lcd_revision = LCD_VERSION_2; | 1268 | lcd_revision = LCD_VERSION_2; |
| 1287 | break; | 1269 | break; |
| 1288 | default: | 1270 | default: |
| @@ -1323,7 +1305,7 @@ static int __devinit fb_probe(struct platform_device *device) | |||
| 1323 | #ifdef CONFIG_CPU_FREQ | 1305 | #ifdef CONFIG_CPU_FREQ |
| 1324 | par->lcd_fck_rate = clk_get_rate(fb_clk); | 1306 | par->lcd_fck_rate = clk_get_rate(fb_clk); |
| 1325 | #endif | 1307 | #endif |
| 1326 | par->pxl_clk = lcdc_info->pxl_clk; | 1308 | par->pxl_clk = lcdc_info->pixclock; |
| 1327 | if (fb_pdata->panel_power_ctrl) { | 1309 | if (fb_pdata->panel_power_ctrl) { |
| 1328 | par->panel_power_ctrl = fb_pdata->panel_power_ctrl; | 1310 | par->panel_power_ctrl = fb_pdata->panel_power_ctrl; |
| 1329 | par->panel_power_ctrl(1); | 1311 | par->panel_power_ctrl(1); |
| @@ -1336,8 +1318,8 @@ static int __devinit fb_probe(struct platform_device *device) | |||
| 1336 | } | 1318 | } |
| 1337 | 1319 | ||
| 1338 | /* allocate frame buffer */ | 1320 | /* allocate frame buffer */ |
| 1339 | par->vram_size = lcdc_info->width * lcdc_info->height * lcd_cfg->bpp; | 1321 | par->vram_size = lcdc_info->xres * lcdc_info->yres * lcd_cfg->bpp; |
| 1340 | ulcm = lcm((lcdc_info->width * lcd_cfg->bpp)/8, PAGE_SIZE); | 1322 | ulcm = lcm((lcdc_info->xres * lcd_cfg->bpp)/8, PAGE_SIZE); |
| 1341 | par->vram_size = roundup(par->vram_size/8, ulcm); | 1323 | par->vram_size = roundup(par->vram_size/8, ulcm); |
| 1342 | par->vram_size = par->vram_size * LCD_NUM_BUFFERS; | 1324 | par->vram_size = par->vram_size * LCD_NUM_BUFFERS; |
| 1343 | 1325 | ||
| @@ -1355,10 +1337,10 @@ static int __devinit fb_probe(struct platform_device *device) | |||
| 1355 | da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt; | 1337 | da8xx_fb_info->screen_base = (char __iomem *) par->vram_virt; |
| 1356 | da8xx_fb_fix.smem_start = par->vram_phys; | 1338 | da8xx_fb_fix.smem_start = par->vram_phys; |
| 1357 | da8xx_fb_fix.smem_len = par->vram_size; | 1339 | da8xx_fb_fix.smem_len = par->vram_size; |
| 1358 | da8xx_fb_fix.line_length = (lcdc_info->width * lcd_cfg->bpp) / 8; | 1340 | da8xx_fb_fix.line_length = (lcdc_info->xres * lcd_cfg->bpp) / 8; |
| 1359 | 1341 | ||
| 1360 | par->dma_start = par->vram_phys; | 1342 | par->dma_start = par->vram_phys; |
| 1361 | par->dma_end = par->dma_start + lcdc_info->height * | 1343 | par->dma_end = par->dma_start + lcdc_info->yres * |
| 1362 | da8xx_fb_fix.line_length - 1; | 1344 | da8xx_fb_fix.line_length - 1; |
| 1363 | 1345 | ||
| 1364 | /* allocate palette buffer */ | 1346 | /* allocate palette buffer */ |
| @@ -1384,22 +1366,22 @@ static int __devinit fb_probe(struct platform_device *device) | |||
| 1384 | /* Initialize par */ | 1366 | /* Initialize par */ |
| 1385 | da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp; | 1367 | da8xx_fb_info->var.bits_per_pixel = lcd_cfg->bpp; |
| 1386 | 1368 | ||
| 1387 | da8xx_fb_var.xres = lcdc_info->width; | 1369 | da8xx_fb_var.xres = lcdc_info->xres; |
| 1388 | da8xx_fb_var.xres_virtual = lcdc_info->width; | 1370 | da8xx_fb_var.xres_virtual = lcdc_info->xres; |
| 1389 | 1371 | ||
| 1390 | da8xx_fb_var.yres = lcdc_info->height; | 1372 | da8xx_fb_var.yres = lcdc_info->yres; |
| 1391 | da8xx_fb_var.yres_virtual = lcdc_info->height * LCD_NUM_BUFFERS; | 1373 | da8xx_fb_var.yres_virtual = lcdc_info->yres * LCD_NUM_BUFFERS; |
| 1392 | 1374 | ||
| 1393 | da8xx_fb_var.grayscale = | 1375 | da8xx_fb_var.grayscale = |
| 1394 | lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0; | 1376 | lcd_cfg->panel_shade == MONOCHROME ? 1 : 0; |
| 1395 | da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp; | 1377 | da8xx_fb_var.bits_per_pixel = lcd_cfg->bpp; |
| 1396 | 1378 | ||
| 1397 | da8xx_fb_var.hsync_len = lcdc_info->hsw; | 1379 | da8xx_fb_var.hsync_len = lcdc_info->hsync_len; |
| 1398 | da8xx_fb_var.vsync_len = lcdc_info->vsw; | 1380 | da8xx_fb_var.vsync_len = lcdc_info->vsync_len; |
| 1399 | da8xx_fb_var.right_margin = lcdc_info->hfp; | 1381 | da8xx_fb_var.right_margin = lcdc_info->right_margin; |
| 1400 | da8xx_fb_var.left_margin = lcdc_info->hbp; | 1382 | da8xx_fb_var.left_margin = lcdc_info->left_margin; |
| 1401 | da8xx_fb_var.lower_margin = lcdc_info->vfp; | 1383 | da8xx_fb_var.lower_margin = lcdc_info->lower_margin; |
| 1402 | da8xx_fb_var.upper_margin = lcdc_info->vbp; | 1384 | da8xx_fb_var.upper_margin = lcdc_info->upper_margin; |
| 1403 | da8xx_fb_var.pixclock = da8xxfb_pixel_clk_period(par); | 1385 | da8xx_fb_var.pixclock = da8xxfb_pixel_clk_period(par); |
| 1404 | 1386 | ||
| 1405 | /* Initialize fbinfo */ | 1387 | /* Initialize fbinfo */ |
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c index d55470e75412..28fd686c6b81 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/video/exynos/exynos_dp_core.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
| 21 | #include <linux/of.h> | ||
| 21 | 22 | ||
| 22 | #include <video/exynos_dp.h> | 23 | #include <video/exynos_dp.h> |
| 23 | 24 | ||
| @@ -48,10 +49,6 @@ static int exynos_dp_detect_hpd(struct exynos_dp_device *dp) | |||
| 48 | { | 49 | { |
| 49 | int timeout_loop = 0; | 50 | int timeout_loop = 0; |
| 50 | 51 | ||
| 51 | exynos_dp_init_hpd(dp); | ||
| 52 | |||
| 53 | usleep_range(200, 210); | ||
| 54 | |||
| 55 | while (exynos_dp_get_plug_in_status(dp) != 0) { | 52 | while (exynos_dp_get_plug_in_status(dp) != 0) { |
| 56 | timeout_loop++; | 53 | timeout_loop++; |
| 57 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { | 54 | if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) { |
| @@ -90,9 +87,11 @@ static int exynos_dp_read_edid(struct exynos_dp_device *dp) | |||
| 90 | */ | 87 | */ |
| 91 | 88 | ||
| 92 | /* Read Extension Flag, Number of 128-byte EDID extension blocks */ | 89 | /* Read Extension Flag, Number of 128-byte EDID extension blocks */ |
| 93 | exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, | 90 | retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR, |
| 94 | EDID_EXTENSION_FLAG, | 91 | EDID_EXTENSION_FLAG, |
| 95 | &extend_block); | 92 | &extend_block); |
| 93 | if (retval) | ||
| 94 | return retval; | ||
| 96 | 95 | ||
| 97 | if (extend_block > 0) { | 96 | if (extend_block > 0) { |
| 98 | dev_dbg(dp->dev, "EDID data includes a single extension!\n"); | 97 | dev_dbg(dp->dev, "EDID data includes a single extension!\n"); |
| @@ -181,14 +180,15 @@ static int exynos_dp_handle_edid(struct exynos_dp_device *dp) | |||
| 181 | int retval; | 180 | int retval; |
| 182 | 181 | ||
| 183 | /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */ | 182 | /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */ |
| 184 | exynos_dp_read_bytes_from_dpcd(dp, | 183 | retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV, |
| 185 | DPCD_ADDR_DPCD_REV, | 184 | 12, buf); |
| 186 | 12, buf); | 185 | if (retval) |
| 186 | return retval; | ||
| 187 | 187 | ||
| 188 | /* Read EDID */ | 188 | /* Read EDID */ |
| 189 | for (i = 0; i < 3; i++) { | 189 | for (i = 0; i < 3; i++) { |
| 190 | retval = exynos_dp_read_edid(dp); | 190 | retval = exynos_dp_read_edid(dp); |
| 191 | if (retval == 0) | 191 | if (!retval) |
| 192 | break; | 192 | break; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| @@ -261,11 +261,10 @@ static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp, | |||
| 261 | } | 261 | } |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | static void exynos_dp_link_start(struct exynos_dp_device *dp) | 264 | static int exynos_dp_link_start(struct exynos_dp_device *dp) |
| 265 | { | 265 | { |
| 266 | u8 buf[4]; | 266 | u8 buf[4]; |
| 267 | int lane; | 267 | int lane, lane_count, pll_tries, retval; |
| 268 | int lane_count; | ||
| 269 | 268 | ||
| 270 | lane_count = dp->link_train.lane_count; | 269 | lane_count = dp->link_train.lane_count; |
| 271 | 270 | ||
| @@ -275,10 +274,6 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) | |||
| 275 | for (lane = 0; lane < lane_count; lane++) | 274 | for (lane = 0; lane < lane_count; lane++) |
| 276 | dp->link_train.cr_loop[lane] = 0; | 275 | dp->link_train.cr_loop[lane] = 0; |
| 277 | 276 | ||
| 278 | /* Set sink to D0 (Sink Not Ready) mode. */ | ||
| 279 | exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_SINK_POWER_STATE, | ||
| 280 | DPCD_SET_POWER_STATE_D0); | ||
| 281 | |||
| 282 | /* Set link rate and count as you want to establish*/ | 277 | /* Set link rate and count as you want to establish*/ |
| 283 | exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate); | 278 | exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate); |
| 284 | exynos_dp_set_lane_count(dp, dp->link_train.lane_count); | 279 | exynos_dp_set_lane_count(dp, dp->link_train.lane_count); |
| @@ -286,29 +281,46 @@ static void exynos_dp_link_start(struct exynos_dp_device *dp) | |||
| 286 | /* Setup RX configuration */ | 281 | /* Setup RX configuration */ |
| 287 | buf[0] = dp->link_train.link_rate; | 282 | buf[0] = dp->link_train.link_rate; |
| 288 | buf[1] = dp->link_train.lane_count; | 283 | buf[1] = dp->link_train.lane_count; |
| 289 | exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, | 284 | retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET, |
| 290 | 2, buf); | 285 | 2, buf); |
| 286 | if (retval) | ||
| 287 | return retval; | ||
| 291 | 288 | ||
| 292 | /* Set TX pre-emphasis to minimum */ | 289 | /* Set TX pre-emphasis to minimum */ |
| 293 | for (lane = 0; lane < lane_count; lane++) | 290 | for (lane = 0; lane < lane_count; lane++) |
| 294 | exynos_dp_set_lane_lane_pre_emphasis(dp, | 291 | exynos_dp_set_lane_lane_pre_emphasis(dp, |
| 295 | PRE_EMPHASIS_LEVEL_0, lane); | 292 | PRE_EMPHASIS_LEVEL_0, lane); |
| 296 | 293 | ||
| 294 | /* Wait for PLL lock */ | ||
| 295 | pll_tries = 0; | ||
| 296 | while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | ||
| 297 | if (pll_tries == DP_TIMEOUT_LOOP_COUNT) { | ||
| 298 | dev_err(dp->dev, "Wait for PLL lock timed out\n"); | ||
| 299 | return -ETIMEDOUT; | ||
| 300 | } | ||
| 301 | |||
| 302 | pll_tries++; | ||
| 303 | usleep_range(90, 120); | ||
| 304 | } | ||
| 305 | |||
| 297 | /* Set training pattern 1 */ | 306 | /* Set training pattern 1 */ |
| 298 | exynos_dp_set_training_pattern(dp, TRAINING_PTN1); | 307 | exynos_dp_set_training_pattern(dp, TRAINING_PTN1); |
| 299 | 308 | ||
| 300 | /* Set RX training pattern */ | 309 | /* Set RX training pattern */ |
| 301 | exynos_dp_write_byte_to_dpcd(dp, | 310 | retval = exynos_dp_write_byte_to_dpcd(dp, |
| 302 | DPCD_ADDR_TRAINING_PATTERN_SET, | 311 | DPCD_ADDR_TRAINING_PATTERN_SET, |
| 303 | DPCD_SCRAMBLING_DISABLED | | 312 | DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1); |
| 304 | DPCD_TRAINING_PATTERN_1); | 313 | if (retval) |
| 314 | return retval; | ||
| 305 | 315 | ||
| 306 | for (lane = 0; lane < lane_count; lane++) | 316 | for (lane = 0; lane < lane_count; lane++) |
| 307 | buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | | 317 | buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 | |
| 308 | DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; | 318 | DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0; |
| 309 | exynos_dp_write_bytes_to_dpcd(dp, | 319 | |
| 310 | DPCD_ADDR_TRAINING_LANE0_SET, | 320 | retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, |
| 311 | lane_count, buf); | 321 | lane_count, buf); |
| 322 | |||
| 323 | return retval; | ||
| 312 | } | 324 | } |
| 313 | 325 | ||
| 314 | static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane) | 326 | static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane) |
| @@ -332,18 +344,17 @@ static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count) | |||
| 332 | return 0; | 344 | return 0; |
| 333 | } | 345 | } |
| 334 | 346 | ||
| 335 | static int exynos_dp_channel_eq_ok(u8 link_align[3], int lane_count) | 347 | static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align, |
| 348 | int lane_count) | ||
| 336 | { | 349 | { |
| 337 | int lane; | 350 | int lane; |
| 338 | u8 lane_align; | ||
| 339 | u8 lane_status; | 351 | u8 lane_status; |
| 340 | 352 | ||
| 341 | lane_align = link_align[2]; | 353 | if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0) |
| 342 | if ((lane_align & DPCD_INTERLANE_ALIGN_DONE) == 0) | ||
| 343 | return -EINVAL; | 354 | return -EINVAL; |
| 344 | 355 | ||
| 345 | for (lane = 0; lane < lane_count; lane++) { | 356 | for (lane = 0; lane < lane_count; lane++) { |
| 346 | lane_status = exynos_dp_get_lane_status(link_align, lane); | 357 | lane_status = exynos_dp_get_lane_status(link_status, lane); |
| 347 | lane_status &= DPCD_CHANNEL_EQ_BITS; | 358 | lane_status &= DPCD_CHANNEL_EQ_BITS; |
| 348 | if (lane_status != DPCD_CHANNEL_EQ_BITS) | 359 | if (lane_status != DPCD_CHANNEL_EQ_BITS) |
| 349 | return -EINVAL; | 360 | return -EINVAL; |
| @@ -427,60 +438,60 @@ static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp) | |||
| 427 | dp->link_train.lt_state = FAILED; | 438 | dp->link_train.lt_state = FAILED; |
| 428 | } | 439 | } |
| 429 | 440 | ||
| 430 | static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | 441 | static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp, |
| 442 | u8 adjust_request[2]) | ||
| 431 | { | 443 | { |
| 432 | u8 link_status[2]; | 444 | int lane, lane_count; |
| 433 | int lane; | 445 | u8 voltage_swing, pre_emphasis, training_lane; |
| 434 | int lane_count; | ||
| 435 | 446 | ||
| 436 | u8 adjust_request[2]; | 447 | lane_count = dp->link_train.lane_count; |
| 437 | u8 voltage_swing; | 448 | for (lane = 0; lane < lane_count; lane++) { |
| 438 | u8 pre_emphasis; | 449 | voltage_swing = exynos_dp_get_adjust_request_voltage( |
| 439 | u8 training_lane; | 450 | adjust_request, lane); |
| 451 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
| 452 | adjust_request, lane); | ||
| 453 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
| 454 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
| 455 | |||
| 456 | if (voltage_swing == VOLTAGE_LEVEL_3) | ||
| 457 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
| 458 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
| 459 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
| 460 | |||
| 461 | dp->link_train.training_lane[lane] = training_lane; | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | ||
| 466 | { | ||
| 467 | int lane, lane_count, retval; | ||
| 468 | u8 voltage_swing, pre_emphasis, training_lane; | ||
| 469 | u8 link_status[2], adjust_request[2]; | ||
| 440 | 470 | ||
| 441 | usleep_range(100, 101); | 471 | usleep_range(100, 101); |
| 442 | 472 | ||
| 443 | lane_count = dp->link_train.lane_count; | 473 | lane_count = dp->link_train.lane_count; |
| 444 | 474 | ||
| 445 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | 475 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
| 446 | 2, link_status); | 476 | DPCD_ADDR_LANE0_1_STATUS, 2, link_status); |
| 477 | if (retval) | ||
| 478 | return retval; | ||
| 479 | |||
| 480 | retval = exynos_dp_read_bytes_from_dpcd(dp, | ||
| 481 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); | ||
| 482 | if (retval) | ||
| 483 | return retval; | ||
| 447 | 484 | ||
| 448 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | 485 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { |
| 449 | /* set training pattern 2 for EQ */ | 486 | /* set training pattern 2 for EQ */ |
| 450 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); | 487 | exynos_dp_set_training_pattern(dp, TRAINING_PTN2); |
| 451 | 488 | ||
| 452 | for (lane = 0; lane < lane_count; lane++) { | 489 | retval = exynos_dp_write_byte_to_dpcd(dp, |
| 453 | exynos_dp_read_bytes_from_dpcd(dp, | 490 | DPCD_ADDR_TRAINING_PATTERN_SET, |
| 454 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | 491 | DPCD_SCRAMBLING_DISABLED | |
| 455 | 2, adjust_request); | 492 | DPCD_TRAINING_PATTERN_2); |
| 456 | voltage_swing = exynos_dp_get_adjust_request_voltage( | 493 | if (retval) |
| 457 | adjust_request, lane); | 494 | return retval; |
| 458 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
| 459 | adjust_request, lane); | ||
| 460 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
| 461 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
| 462 | |||
| 463 | if (voltage_swing == VOLTAGE_LEVEL_3) | ||
| 464 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
| 465 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
| 466 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
| 467 | |||
| 468 | dp->link_train.training_lane[lane] = training_lane; | ||
| 469 | |||
| 470 | exynos_dp_set_lane_link_training(dp, | ||
| 471 | dp->link_train.training_lane[lane], | ||
| 472 | lane); | ||
| 473 | } | ||
| 474 | |||
| 475 | exynos_dp_write_byte_to_dpcd(dp, | ||
| 476 | DPCD_ADDR_TRAINING_PATTERN_SET, | ||
| 477 | DPCD_SCRAMBLING_DISABLED | | ||
| 478 | DPCD_TRAINING_PATTERN_2); | ||
| 479 | |||
| 480 | exynos_dp_write_bytes_to_dpcd(dp, | ||
| 481 | DPCD_ADDR_TRAINING_LANE0_SET, | ||
| 482 | lane_count, | ||
| 483 | dp->link_train.training_lane); | ||
| 484 | 495 | ||
| 485 | dev_info(dp->dev, "Link Training Clock Recovery success\n"); | 496 | dev_info(dp->dev, "Link Training Clock Recovery success\n"); |
| 486 | dp->link_train.lt_state = EQUALIZER_TRAINING; | 497 | dp->link_train.lt_state = EQUALIZER_TRAINING; |
| @@ -488,152 +499,116 @@ static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp) | |||
| 488 | for (lane = 0; lane < lane_count; lane++) { | 499 | for (lane = 0; lane < lane_count; lane++) { |
| 489 | training_lane = exynos_dp_get_lane_link_training( | 500 | training_lane = exynos_dp_get_lane_link_training( |
| 490 | dp, lane); | 501 | dp, lane); |
| 491 | exynos_dp_read_bytes_from_dpcd(dp, | ||
| 492 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | ||
| 493 | 2, adjust_request); | ||
| 494 | voltage_swing = exynos_dp_get_adjust_request_voltage( | 502 | voltage_swing = exynos_dp_get_adjust_request_voltage( |
| 495 | adjust_request, lane); | 503 | adjust_request, lane); |
| 496 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | 504 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( |
| 497 | adjust_request, lane); | 505 | adjust_request, lane); |
| 498 | 506 | ||
| 499 | if (voltage_swing == VOLTAGE_LEVEL_3 || | 507 | if (DPCD_VOLTAGE_SWING_GET(training_lane) == |
| 500 | pre_emphasis == PRE_EMPHASIS_LEVEL_3) { | 508 | voltage_swing && |
| 501 | dev_err(dp->dev, "voltage or pre emphasis reached max level\n"); | 509 | DPCD_PRE_EMPHASIS_GET(training_lane) == |
| 502 | goto reduce_link_rate; | 510 | pre_emphasis) |
| 503 | } | ||
| 504 | |||
| 505 | if ((DPCD_VOLTAGE_SWING_GET(training_lane) == | ||
| 506 | voltage_swing) && | ||
| 507 | (DPCD_PRE_EMPHASIS_GET(training_lane) == | ||
| 508 | pre_emphasis)) { | ||
| 509 | dp->link_train.cr_loop[lane]++; | 511 | dp->link_train.cr_loop[lane]++; |
| 510 | if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP) { | ||
| 511 | dev_err(dp->dev, "CR Max loop\n"); | ||
| 512 | goto reduce_link_rate; | ||
| 513 | } | ||
| 514 | } | ||
| 515 | |||
| 516 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
| 517 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
| 518 | 512 | ||
| 519 | if (voltage_swing == VOLTAGE_LEVEL_3) | 513 | if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP || |
| 520 | training_lane |= DPCD_MAX_SWING_REACHED; | 514 | voltage_swing == VOLTAGE_LEVEL_3 || |
| 521 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | 515 | pre_emphasis == PRE_EMPHASIS_LEVEL_3) { |
| 522 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | 516 | dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n", |
| 517 | dp->link_train.cr_loop[lane], | ||
| 518 | voltage_swing, pre_emphasis); | ||
| 519 | exynos_dp_reduce_link_rate(dp); | ||
| 520 | return -EIO; | ||
| 521 | } | ||
| 522 | } | ||
| 523 | } | ||
| 523 | 524 | ||
| 524 | dp->link_train.training_lane[lane] = training_lane; | 525 | exynos_dp_get_adjust_training_lane(dp, adjust_request); |
| 525 | 526 | ||
| 526 | exynos_dp_set_lane_link_training(dp, | 527 | for (lane = 0; lane < lane_count; lane++) |
| 527 | dp->link_train.training_lane[lane], lane); | 528 | exynos_dp_set_lane_link_training(dp, |
| 528 | } | 529 | dp->link_train.training_lane[lane], lane); |
| 529 | 530 | ||
| 530 | exynos_dp_write_bytes_to_dpcd(dp, | 531 | retval = exynos_dp_write_bytes_to_dpcd(dp, |
| 531 | DPCD_ADDR_TRAINING_LANE0_SET, | 532 | DPCD_ADDR_TRAINING_LANE0_SET, lane_count, |
| 532 | lane_count, | ||
| 533 | dp->link_train.training_lane); | 533 | dp->link_train.training_lane); |
| 534 | } | 534 | if (retval) |
| 535 | 535 | return retval; | |
| 536 | return 0; | ||
| 537 | 536 | ||
| 538 | reduce_link_rate: | 537 | return retval; |
| 539 | exynos_dp_reduce_link_rate(dp); | ||
| 540 | return -EIO; | ||
| 541 | } | 538 | } |
| 542 | 539 | ||
| 543 | static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) | 540 | static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp) |
| 544 | { | 541 | { |
| 545 | u8 link_status[2]; | 542 | int lane, lane_count, retval; |
| 546 | u8 link_align[3]; | ||
| 547 | int lane; | ||
| 548 | int lane_count; | ||
| 549 | u32 reg; | 543 | u32 reg; |
| 550 | 544 | u8 link_align, link_status[2], adjust_request[2]; | |
| 551 | u8 adjust_request[2]; | ||
| 552 | u8 voltage_swing; | ||
| 553 | u8 pre_emphasis; | ||
| 554 | u8 training_lane; | ||
| 555 | 545 | ||
| 556 | usleep_range(400, 401); | 546 | usleep_range(400, 401); |
| 557 | 547 | ||
| 558 | lane_count = dp->link_train.lane_count; | 548 | lane_count = dp->link_train.lane_count; |
| 559 | 549 | ||
| 560 | exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_LANE0_1_STATUS, | 550 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
| 561 | 2, link_status); | 551 | DPCD_ADDR_LANE0_1_STATUS, 2, link_status); |
| 552 | if (retval) | ||
| 553 | return retval; | ||
| 562 | 554 | ||
| 563 | if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) { | 555 | if (exynos_dp_clock_recovery_ok(link_status, lane_count)) { |
| 564 | link_align[0] = link_status[0]; | 556 | exynos_dp_reduce_link_rate(dp); |
| 565 | link_align[1] = link_status[1]; | 557 | return -EIO; |
| 558 | } | ||
| 566 | 559 | ||
| 567 | exynos_dp_read_byte_from_dpcd(dp, | 560 | retval = exynos_dp_read_bytes_from_dpcd(dp, |
| 568 | DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, | 561 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request); |
| 569 | &link_align[2]); | 562 | if (retval) |
| 563 | return retval; | ||
| 570 | 564 | ||
| 571 | for (lane = 0; lane < lane_count; lane++) { | 565 | retval = exynos_dp_read_byte_from_dpcd(dp, |
| 572 | exynos_dp_read_bytes_from_dpcd(dp, | 566 | DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align); |
| 573 | DPCD_ADDR_ADJUST_REQUEST_LANE0_1, | 567 | if (retval) |
| 574 | 2, adjust_request); | 568 | return retval; |
| 575 | voltage_swing = exynos_dp_get_adjust_request_voltage( | ||
| 576 | adjust_request, lane); | ||
| 577 | pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis( | ||
| 578 | adjust_request, lane); | ||
| 579 | training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) | | ||
| 580 | DPCD_PRE_EMPHASIS_SET(pre_emphasis); | ||
| 581 | 569 | ||
| 582 | if (voltage_swing == VOLTAGE_LEVEL_3) | 570 | exynos_dp_get_adjust_training_lane(dp, adjust_request); |
| 583 | training_lane |= DPCD_MAX_SWING_REACHED; | ||
| 584 | if (pre_emphasis == PRE_EMPHASIS_LEVEL_3) | ||
| 585 | training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED; | ||
| 586 | 571 | ||
| 587 | dp->link_train.training_lane[lane] = training_lane; | 572 | if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) { |
| 588 | } | 573 | /* traing pattern Set to Normal */ |
| 574 | exynos_dp_training_pattern_dis(dp); | ||
| 589 | 575 | ||
| 590 | if (exynos_dp_channel_eq_ok(link_align, lane_count) == 0) { | 576 | dev_info(dp->dev, "Link Training success!\n"); |
| 591 | /* traing pattern Set to Normal */ | ||
| 592 | exynos_dp_training_pattern_dis(dp); | ||
| 593 | 577 | ||
| 594 | dev_info(dp->dev, "Link Training success!\n"); | 578 | exynos_dp_get_link_bandwidth(dp, ®); |
| 595 | 579 | dp->link_train.link_rate = reg; | |
| 596 | exynos_dp_get_link_bandwidth(dp, ®); | 580 | dev_dbg(dp->dev, "final bandwidth = %.2x\n", |
| 597 | dp->link_train.link_rate = reg; | 581 | dp->link_train.link_rate); |
| 598 | dev_dbg(dp->dev, "final bandwidth = %.2x\n", | ||
| 599 | dp->link_train.link_rate); | ||
| 600 | 582 | ||
| 601 | exynos_dp_get_lane_count(dp, ®); | 583 | exynos_dp_get_lane_count(dp, ®); |
| 602 | dp->link_train.lane_count = reg; | 584 | dp->link_train.lane_count = reg; |
| 603 | dev_dbg(dp->dev, "final lane count = %.2x\n", | 585 | dev_dbg(dp->dev, "final lane count = %.2x\n", |
| 604 | dp->link_train.lane_count); | 586 | dp->link_train.lane_count); |
| 605 | 587 | ||
| 606 | /* set enhanced mode if available */ | 588 | /* set enhanced mode if available */ |
| 607 | exynos_dp_set_enhanced_mode(dp); | 589 | exynos_dp_set_enhanced_mode(dp); |
| 608 | dp->link_train.lt_state = FINISHED; | 590 | dp->link_train.lt_state = FINISHED; |
| 609 | } else { | ||
| 610 | /* not all locked */ | ||
| 611 | dp->link_train.eq_loop++; | ||
| 612 | 591 | ||
| 613 | if (dp->link_train.eq_loop > MAX_EQ_LOOP) { | 592 | return 0; |
| 614 | dev_err(dp->dev, "EQ Max loop\n"); | 593 | } |
| 615 | goto reduce_link_rate; | ||
| 616 | } | ||
| 617 | 594 | ||
| 618 | for (lane = 0; lane < lane_count; lane++) | 595 | /* not all locked */ |
| 619 | exynos_dp_set_lane_link_training(dp, | 596 | dp->link_train.eq_loop++; |
| 620 | dp->link_train.training_lane[lane], | ||
| 621 | lane); | ||
| 622 | 597 | ||
| 623 | exynos_dp_write_bytes_to_dpcd(dp, | 598 | if (dp->link_train.eq_loop > MAX_EQ_LOOP) { |
| 624 | DPCD_ADDR_TRAINING_LANE0_SET, | 599 | dev_err(dp->dev, "EQ Max loop\n"); |
| 625 | lane_count, | 600 | exynos_dp_reduce_link_rate(dp); |
| 626 | dp->link_train.training_lane); | 601 | return -EIO; |
| 627 | } | ||
| 628 | } else { | ||
| 629 | goto reduce_link_rate; | ||
| 630 | } | 602 | } |
| 631 | 603 | ||
| 632 | return 0; | 604 | for (lane = 0; lane < lane_count; lane++) |
| 605 | exynos_dp_set_lane_link_training(dp, | ||
| 606 | dp->link_train.training_lane[lane], lane); | ||
| 607 | |||
| 608 | retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET, | ||
| 609 | lane_count, dp->link_train.training_lane); | ||
| 633 | 610 | ||
| 634 | reduce_link_rate: | 611 | return retval; |
| 635 | exynos_dp_reduce_link_rate(dp); | ||
| 636 | return -EIO; | ||
| 637 | } | 612 | } |
| 638 | 613 | ||
| 639 | static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, | 614 | static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp, |
| @@ -701,16 +676,17 @@ static void exynos_dp_init_training(struct exynos_dp_device *dp, | |||
| 701 | 676 | ||
| 702 | static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) | 677 | static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) |
| 703 | { | 678 | { |
| 704 | int retval = 0; | 679 | int retval = 0, training_finished = 0; |
| 705 | int training_finished = 0; | ||
| 706 | 680 | ||
| 707 | dp->link_train.lt_state = START; | 681 | dp->link_train.lt_state = START; |
| 708 | 682 | ||
| 709 | /* Process here */ | 683 | /* Process here */ |
| 710 | while (!training_finished) { | 684 | while (!retval && !training_finished) { |
| 711 | switch (dp->link_train.lt_state) { | 685 | switch (dp->link_train.lt_state) { |
| 712 | case START: | 686 | case START: |
| 713 | exynos_dp_link_start(dp); | 687 | retval = exynos_dp_link_start(dp); |
| 688 | if (retval) | ||
| 689 | dev_err(dp->dev, "LT link start failed!\n"); | ||
| 714 | break; | 690 | break; |
| 715 | case CLOCK_RECOVERY: | 691 | case CLOCK_RECOVERY: |
| 716 | retval = exynos_dp_process_clock_recovery(dp); | 692 | retval = exynos_dp_process_clock_recovery(dp); |
| @@ -729,6 +705,8 @@ static int exynos_dp_sw_link_training(struct exynos_dp_device *dp) | |||
| 729 | return -EREMOTEIO; | 705 | return -EREMOTEIO; |
| 730 | } | 706 | } |
| 731 | } | 707 | } |
| 708 | if (retval) | ||
| 709 | dev_err(dp->dev, "eDP link training failed (%d)\n", retval); | ||
| 732 | 710 | ||
| 733 | return retval; | 711 | return retval; |
| 734 | } | 712 | } |
| @@ -752,19 +730,15 @@ static int exynos_dp_set_link_train(struct exynos_dp_device *dp, | |||
| 752 | return retval; | 730 | return retval; |
| 753 | } | 731 | } |
| 754 | 732 | ||
| 755 | static int exynos_dp_config_video(struct exynos_dp_device *dp, | 733 | static int exynos_dp_config_video(struct exynos_dp_device *dp) |
| 756 | struct video_info *video_info) | ||
| 757 | { | 734 | { |
| 758 | int retval = 0; | 735 | int retval = 0; |
| 759 | int timeout_loop = 0; | 736 | int timeout_loop = 0; |
| 760 | int done_count = 0; | 737 | int done_count = 0; |
| 761 | 738 | ||
| 762 | exynos_dp_config_video_slave_mode(dp, video_info); | 739 | exynos_dp_config_video_slave_mode(dp); |
| 763 | 740 | ||
| 764 | exynos_dp_set_video_color_format(dp, video_info->color_depth, | 741 | exynos_dp_set_video_color_format(dp); |
| 765 | video_info->color_space, | ||
| 766 | video_info->dynamic_range, | ||
| 767 | video_info->ycbcr_coeff); | ||
| 768 | 742 | ||
| 769 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { | 743 | if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) { |
| 770 | dev_err(dp->dev, "PLL is not locked yet.\n"); | 744 | dev_err(dp->dev, "PLL is not locked yet.\n"); |
| @@ -852,10 +826,213 @@ static irqreturn_t exynos_dp_irq_handler(int irq, void *arg) | |||
| 852 | { | 826 | { |
| 853 | struct exynos_dp_device *dp = arg; | 827 | struct exynos_dp_device *dp = arg; |
| 854 | 828 | ||
| 855 | dev_err(dp->dev, "exynos_dp_irq_handler\n"); | 829 | enum dp_irq_type irq_type; |
| 830 | |||
| 831 | irq_type = exynos_dp_get_irq_type(dp); | ||
| 832 | switch (irq_type) { | ||
| 833 | case DP_IRQ_TYPE_HP_CABLE_IN: | ||
| 834 | dev_dbg(dp->dev, "Received irq - cable in\n"); | ||
| 835 | schedule_work(&dp->hotplug_work); | ||
| 836 | exynos_dp_clear_hotplug_interrupts(dp); | ||
| 837 | break; | ||
| 838 | case DP_IRQ_TYPE_HP_CABLE_OUT: | ||
| 839 | dev_dbg(dp->dev, "Received irq - cable out\n"); | ||
| 840 | exynos_dp_clear_hotplug_interrupts(dp); | ||
| 841 | break; | ||
| 842 | case DP_IRQ_TYPE_HP_CHANGE: | ||
| 843 | /* | ||
| 844 | * We get these change notifications once in a while, but there | ||
| 845 | * is nothing we can do with them. Just ignore it for now and | ||
| 846 | * only handle cable changes. | ||
| 847 | */ | ||
| 848 | dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n"); | ||
| 849 | exynos_dp_clear_hotplug_interrupts(dp); | ||
| 850 | break; | ||
| 851 | default: | ||
| 852 | dev_err(dp->dev, "Received irq - unknown type!\n"); | ||
| 853 | break; | ||
| 854 | } | ||
| 856 | return IRQ_HANDLED; | 855 | return IRQ_HANDLED; |
| 857 | } | 856 | } |
| 858 | 857 | ||
| 858 | static void exynos_dp_hotplug(struct work_struct *work) | ||
| 859 | { | ||
| 860 | struct exynos_dp_device *dp; | ||
| 861 | int ret; | ||
| 862 | |||
| 863 | dp = container_of(work, struct exynos_dp_device, hotplug_work); | ||
| 864 | |||
| 865 | ret = exynos_dp_detect_hpd(dp); | ||
| 866 | if (ret) { | ||
| 867 | /* Cable has been disconnected, we're done */ | ||
| 868 | return; | ||
| 869 | } | ||
| 870 | |||
| 871 | ret = exynos_dp_handle_edid(dp); | ||
| 872 | if (ret) { | ||
| 873 | dev_err(dp->dev, "unable to handle edid\n"); | ||
| 874 | return; | ||
| 875 | } | ||
| 876 | |||
| 877 | ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count, | ||
| 878 | dp->video_info->link_rate); | ||
| 879 | if (ret) { | ||
| 880 | dev_err(dp->dev, "unable to do link train\n"); | ||
| 881 | return; | ||
| 882 | } | ||
| 883 | |||
| 884 | exynos_dp_enable_scramble(dp, 1); | ||
| 885 | exynos_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
| 886 | exynos_dp_enable_enhanced_mode(dp, 1); | ||
| 887 | |||
| 888 | exynos_dp_set_lane_count(dp, dp->video_info->lane_count); | ||
| 889 | exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); | ||
| 890 | |||
| 891 | exynos_dp_init_video(dp); | ||
| 892 | ret = exynos_dp_config_video(dp); | ||
| 893 | if (ret) | ||
| 894 | dev_err(dp->dev, "unable to config video\n"); | ||
| 895 | } | ||
| 896 | |||
| 897 | #ifdef CONFIG_OF | ||
| 898 | static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev) | ||
| 899 | { | ||
| 900 | struct device_node *dp_node = dev->of_node; | ||
| 901 | struct exynos_dp_platdata *pd; | ||
| 902 | struct video_info *dp_video_config; | ||
| 903 | |||
| 904 | pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); | ||
| 905 | if (!pd) { | ||
| 906 | dev_err(dev, "memory allocation for pdata failed\n"); | ||
| 907 | return ERR_PTR(-ENOMEM); | ||
| 908 | } | ||
| 909 | dp_video_config = devm_kzalloc(dev, | ||
| 910 | sizeof(*dp_video_config), GFP_KERNEL); | ||
| 911 | |||
| 912 | if (!dp_video_config) { | ||
| 913 | dev_err(dev, "memory allocation for video config failed\n"); | ||
| 914 | return ERR_PTR(-ENOMEM); | ||
| 915 | } | ||
| 916 | pd->video_info = dp_video_config; | ||
| 917 | |||
| 918 | dp_video_config->h_sync_polarity = | ||
| 919 | of_property_read_bool(dp_node, "hsync-active-high"); | ||
| 920 | |||
| 921 | dp_video_config->v_sync_polarity = | ||
| 922 | of_property_read_bool(dp_node, "vsync-active-high"); | ||
| 923 | |||
| 924 | dp_video_config->interlaced = | ||
| 925 | of_property_read_bool(dp_node, "interlaced"); | ||
| 926 | |||
| 927 | if (of_property_read_u32(dp_node, "samsung,color-space", | ||
| 928 | &dp_video_config->color_space)) { | ||
| 929 | dev_err(dev, "failed to get color-space\n"); | ||
| 930 | return ERR_PTR(-EINVAL); | ||
| 931 | } | ||
| 932 | |||
| 933 | if (of_property_read_u32(dp_node, "samsung,dynamic-range", | ||
| 934 | &dp_video_config->dynamic_range)) { | ||
| 935 | dev_err(dev, "failed to get dynamic-range\n"); | ||
| 936 | return ERR_PTR(-EINVAL); | ||
| 937 | } | ||
| 938 | |||
| 939 | if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff", | ||
| 940 | &dp_video_config->ycbcr_coeff)) { | ||
| 941 | dev_err(dev, "failed to get ycbcr-coeff\n"); | ||
| 942 | return ERR_PTR(-EINVAL); | ||
| 943 | } | ||
| 944 | |||
| 945 | if (of_property_read_u32(dp_node, "samsung,color-depth", | ||
| 946 | &dp_video_config->color_depth)) { | ||
| 947 | dev_err(dev, "failed to get color-depth\n"); | ||
| 948 | return ERR_PTR(-EINVAL); | ||
| 949 | } | ||
| 950 | |||
| 951 | if (of_property_read_u32(dp_node, "samsung,link-rate", | ||
| 952 | &dp_video_config->link_rate)) { | ||
| 953 | dev_err(dev, "failed to get link-rate\n"); | ||
| 954 | return ERR_PTR(-EINVAL); | ||
| 955 | } | ||
| 956 | |||
| 957 | if (of_property_read_u32(dp_node, "samsung,lane-count", | ||
| 958 | &dp_video_config->lane_count)) { | ||
| 959 | dev_err(dev, "failed to get lane-count\n"); | ||
| 960 | return ERR_PTR(-EINVAL); | ||
| 961 | } | ||
| 962 | |||
| 963 | return pd; | ||
| 964 | } | ||
| 965 | |||
| 966 | static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) | ||
| 967 | { | ||
| 968 | struct device_node *dp_phy_node; | ||
| 969 | u32 phy_base; | ||
| 970 | |||
| 971 | dp_phy_node = of_find_node_by_name(dp->dev->of_node, "dptx-phy"); | ||
| 972 | if (!dp_phy_node) { | ||
| 973 | dev_err(dp->dev, "could not find dptx-phy node\n"); | ||
| 974 | return -ENODEV; | ||
| 975 | } | ||
| 976 | |||
| 977 | if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) { | ||
| 978 | dev_err(dp->dev, "faild to get reg for dptx-phy\n"); | ||
| 979 | return -EINVAL; | ||
| 980 | } | ||
| 981 | |||
| 982 | if (of_property_read_u32(dp_phy_node, "samsung,enable-mask", | ||
| 983 | &dp->enable_mask)) { | ||
| 984 | dev_err(dp->dev, "faild to get enable-mask for dptx-phy\n"); | ||
| 985 | return -EINVAL; | ||
| 986 | } | ||
| 987 | |||
| 988 | dp->phy_addr = ioremap(phy_base, SZ_4); | ||
| 989 | if (!dp->phy_addr) { | ||
| 990 | dev_err(dp->dev, "failed to ioremap dp-phy\n"); | ||
| 991 | return -ENOMEM; | ||
| 992 | } | ||
| 993 | |||
| 994 | return 0; | ||
| 995 | } | ||
| 996 | |||
| 997 | static void exynos_dp_phy_init(struct exynos_dp_device *dp) | ||
| 998 | { | ||
| 999 | u32 reg; | ||
| 1000 | |||
| 1001 | reg = __raw_readl(dp->phy_addr); | ||
| 1002 | reg |= dp->enable_mask; | ||
| 1003 | __raw_writel(reg, dp->phy_addr); | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | static void exynos_dp_phy_exit(struct exynos_dp_device *dp) | ||
| 1007 | { | ||
| 1008 | u32 reg; | ||
| 1009 | |||
| 1010 | reg = __raw_readl(dp->phy_addr); | ||
| 1011 | reg &= ~(dp->enable_mask); | ||
| 1012 | __raw_writel(reg, dp->phy_addr); | ||
| 1013 | } | ||
| 1014 | #else | ||
| 1015 | static struct exynos_dp_platdata *exynos_dp_dt_parse_pdata(struct device *dev) | ||
| 1016 | { | ||
| 1017 | return NULL; | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp) | ||
| 1021 | { | ||
| 1022 | return -EINVAL; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | static void exynos_dp_phy_init(struct exynos_dp_device *dp) | ||
| 1026 | { | ||
| 1027 | return; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | static void exynos_dp_phy_exit(struct exynos_dp_device *dp) | ||
| 1031 | { | ||
| 1032 | return; | ||
| 1033 | } | ||
| 1034 | #endif /* CONFIG_OF */ | ||
| 1035 | |||
| 859 | static int __devinit exynos_dp_probe(struct platform_device *pdev) | 1036 | static int __devinit exynos_dp_probe(struct platform_device *pdev) |
| 860 | { | 1037 | { |
| 861 | struct resource *res; | 1038 | struct resource *res; |
| @@ -864,12 +1041,6 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
| 864 | 1041 | ||
| 865 | int ret = 0; | 1042 | int ret = 0; |
| 866 | 1043 | ||
| 867 | pdata = pdev->dev.platform_data; | ||
| 868 | if (!pdata) { | ||
| 869 | dev_err(&pdev->dev, "no platform data\n"); | ||
| 870 | return -EINVAL; | ||
| 871 | } | ||
| 872 | |||
| 873 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), | 1044 | dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device), |
| 874 | GFP_KERNEL); | 1045 | GFP_KERNEL); |
| 875 | if (!dp) { | 1046 | if (!dp) { |
| @@ -879,6 +1050,22 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
| 879 | 1050 | ||
| 880 | dp->dev = &pdev->dev; | 1051 | dp->dev = &pdev->dev; |
| 881 | 1052 | ||
| 1053 | if (pdev->dev.of_node) { | ||
| 1054 | pdata = exynos_dp_dt_parse_pdata(&pdev->dev); | ||
| 1055 | if (IS_ERR(pdata)) | ||
| 1056 | return PTR_ERR(pdata); | ||
| 1057 | |||
| 1058 | ret = exynos_dp_dt_parse_phydata(dp); | ||
| 1059 | if (ret) | ||
| 1060 | return ret; | ||
| 1061 | } else { | ||
| 1062 | pdata = pdev->dev.platform_data; | ||
| 1063 | if (!pdata) { | ||
| 1064 | dev_err(&pdev->dev, "no platform data\n"); | ||
| 1065 | return -EINVAL; | ||
| 1066 | } | ||
| 1067 | } | ||
| 1068 | |||
| 882 | dp->clock = devm_clk_get(&pdev->dev, "dp"); | 1069 | dp->clock = devm_clk_get(&pdev->dev, "dp"); |
| 883 | if (IS_ERR(dp->clock)) { | 1070 | if (IS_ERR(dp->clock)) { |
| 884 | dev_err(&pdev->dev, "failed to get clock\n"); | 1071 | dev_err(&pdev->dev, "failed to get clock\n"); |
| @@ -896,50 +1083,29 @@ static int __devinit exynos_dp_probe(struct platform_device *pdev) | |||
| 896 | } | 1083 | } |
| 897 | 1084 | ||
| 898 | dp->irq = platform_get_irq(pdev, 0); | 1085 | dp->irq = platform_get_irq(pdev, 0); |
| 899 | if (!dp->irq) { | 1086 | if (dp->irq == -ENXIO) { |
| 900 | dev_err(&pdev->dev, "failed to get irq\n"); | 1087 | dev_err(&pdev->dev, "failed to get irq\n"); |
| 901 | return -ENODEV; | 1088 | return -ENODEV; |
| 902 | } | 1089 | } |
| 903 | 1090 | ||
| 904 | ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, | 1091 | INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug); |
| 905 | "exynos-dp", dp); | ||
| 906 | if (ret) { | ||
| 907 | dev_err(&pdev->dev, "failed to request irq\n"); | ||
| 908 | return ret; | ||
| 909 | } | ||
| 910 | 1092 | ||
| 911 | dp->video_info = pdata->video_info; | 1093 | dp->video_info = pdata->video_info; |
| 912 | if (pdata->phy_init) | ||
| 913 | pdata->phy_init(); | ||
| 914 | |||
| 915 | exynos_dp_init_dp(dp); | ||
| 916 | |||
| 917 | ret = exynos_dp_detect_hpd(dp); | ||
| 918 | if (ret) { | ||
| 919 | dev_err(&pdev->dev, "unable to detect hpd\n"); | ||
| 920 | return ret; | ||
| 921 | } | ||
| 922 | 1094 | ||
| 923 | exynos_dp_handle_edid(dp); | 1095 | if (pdev->dev.of_node) { |
| 924 | 1096 | if (dp->phy_addr) | |
| 925 | ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count, | 1097 | exynos_dp_phy_init(dp); |
| 926 | dp->video_info->link_rate); | 1098 | } else { |
| 927 | if (ret) { | 1099 | if (pdata->phy_init) |
| 928 | dev_err(&pdev->dev, "unable to do link train\n"); | 1100 | pdata->phy_init(); |
| 929 | return ret; | ||
| 930 | } | 1101 | } |
| 931 | 1102 | ||
| 932 | exynos_dp_enable_scramble(dp, 1); | 1103 | exynos_dp_init_dp(dp); |
| 933 | exynos_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
| 934 | exynos_dp_enable_enhanced_mode(dp, 1); | ||
| 935 | |||
| 936 | exynos_dp_set_lane_count(dp, dp->video_info->lane_count); | ||
| 937 | exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); | ||
| 938 | 1104 | ||
| 939 | exynos_dp_init_video(dp); | 1105 | ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0, |
| 940 | ret = exynos_dp_config_video(dp, dp->video_info); | 1106 | "exynos-dp", dp); |
| 941 | if (ret) { | 1107 | if (ret) { |
| 942 | dev_err(&pdev->dev, "unable to config video\n"); | 1108 | dev_err(&pdev->dev, "failed to request irq\n"); |
| 943 | return ret; | 1109 | return ret; |
| 944 | } | 1110 | } |
| 945 | 1111 | ||
| @@ -953,23 +1119,41 @@ static int __devexit exynos_dp_remove(struct platform_device *pdev) | |||
| 953 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; | 1119 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; |
| 954 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); | 1120 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); |
| 955 | 1121 | ||
| 956 | if (pdata && pdata->phy_exit) | 1122 | disable_irq(dp->irq); |
| 957 | pdata->phy_exit(); | 1123 | |
| 1124 | if (work_pending(&dp->hotplug_work)) | ||
| 1125 | flush_work(&dp->hotplug_work); | ||
| 1126 | |||
| 1127 | if (pdev->dev.of_node) { | ||
| 1128 | if (dp->phy_addr) | ||
| 1129 | exynos_dp_phy_exit(dp); | ||
| 1130 | } else { | ||
| 1131 | if (pdata->phy_exit) | ||
| 1132 | pdata->phy_exit(); | ||
| 1133 | } | ||
| 958 | 1134 | ||
| 959 | clk_disable_unprepare(dp->clock); | 1135 | clk_disable_unprepare(dp->clock); |
| 960 | 1136 | ||
| 1137 | |||
| 961 | return 0; | 1138 | return 0; |
| 962 | } | 1139 | } |
| 963 | 1140 | ||
| 964 | #ifdef CONFIG_PM_SLEEP | 1141 | #ifdef CONFIG_PM_SLEEP |
| 965 | static int exynos_dp_suspend(struct device *dev) | 1142 | static int exynos_dp_suspend(struct device *dev) |
| 966 | { | 1143 | { |
| 967 | struct platform_device *pdev = to_platform_device(dev); | 1144 | struct exynos_dp_platdata *pdata = dev->platform_data; |
| 968 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; | 1145 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
| 969 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); | ||
| 970 | 1146 | ||
| 971 | if (pdata && pdata->phy_exit) | 1147 | if (work_pending(&dp->hotplug_work)) |
| 972 | pdata->phy_exit(); | 1148 | flush_work(&dp->hotplug_work); |
| 1149 | |||
| 1150 | if (dev->of_node) { | ||
| 1151 | if (dp->phy_addr) | ||
| 1152 | exynos_dp_phy_exit(dp); | ||
| 1153 | } else { | ||
| 1154 | if (pdata->phy_exit) | ||
| 1155 | pdata->phy_exit(); | ||
| 1156 | } | ||
| 973 | 1157 | ||
| 974 | clk_disable_unprepare(dp->clock); | 1158 | clk_disable_unprepare(dp->clock); |
| 975 | 1159 | ||
| @@ -978,32 +1162,22 @@ static int exynos_dp_suspend(struct device *dev) | |||
| 978 | 1162 | ||
| 979 | static int exynos_dp_resume(struct device *dev) | 1163 | static int exynos_dp_resume(struct device *dev) |
| 980 | { | 1164 | { |
| 981 | struct platform_device *pdev = to_platform_device(dev); | 1165 | struct exynos_dp_platdata *pdata = dev->platform_data; |
| 982 | struct exynos_dp_platdata *pdata = pdev->dev.platform_data; | 1166 | struct exynos_dp_device *dp = dev_get_drvdata(dev); |
| 983 | struct exynos_dp_device *dp = platform_get_drvdata(pdev); | ||
| 984 | 1167 | ||
| 985 | if (pdata && pdata->phy_init) | 1168 | if (dev->of_node) { |
| 986 | pdata->phy_init(); | 1169 | if (dp->phy_addr) |
| 1170 | exynos_dp_phy_init(dp); | ||
| 1171 | } else { | ||
| 1172 | if (pdata->phy_init) | ||
| 1173 | pdata->phy_init(); | ||
| 1174 | } | ||
| 987 | 1175 | ||
| 988 | clk_prepare_enable(dp->clock); | 1176 | clk_prepare_enable(dp->clock); |
| 989 | 1177 | ||
| 990 | exynos_dp_init_dp(dp); | 1178 | exynos_dp_init_dp(dp); |
| 991 | 1179 | ||
| 992 | exynos_dp_detect_hpd(dp); | 1180 | enable_irq(dp->irq); |
| 993 | exynos_dp_handle_edid(dp); | ||
| 994 | |||
| 995 | exynos_dp_set_link_train(dp, dp->video_info->lane_count, | ||
| 996 | dp->video_info->link_rate); | ||
| 997 | |||
| 998 | exynos_dp_enable_scramble(dp, 1); | ||
| 999 | exynos_dp_enable_rx_to_enhanced_mode(dp, 1); | ||
| 1000 | exynos_dp_enable_enhanced_mode(dp, 1); | ||
| 1001 | |||
| 1002 | exynos_dp_set_lane_count(dp, dp->video_info->lane_count); | ||
| 1003 | exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate); | ||
| 1004 | |||
| 1005 | exynos_dp_init_video(dp); | ||
| 1006 | exynos_dp_config_video(dp, dp->video_info); | ||
| 1007 | 1181 | ||
| 1008 | return 0; | 1182 | return 0; |
| 1009 | } | 1183 | } |
| @@ -1013,6 +1187,12 @@ static const struct dev_pm_ops exynos_dp_pm_ops = { | |||
| 1013 | SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume) | 1187 | SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume) |
| 1014 | }; | 1188 | }; |
| 1015 | 1189 | ||
| 1190 | static const struct of_device_id exynos_dp_match[] = { | ||
| 1191 | { .compatible = "samsung,exynos5-dp" }, | ||
| 1192 | {}, | ||
| 1193 | }; | ||
| 1194 | MODULE_DEVICE_TABLE(of, exynos_dp_match); | ||
| 1195 | |||
| 1016 | static struct platform_driver exynos_dp_driver = { | 1196 | static struct platform_driver exynos_dp_driver = { |
| 1017 | .probe = exynos_dp_probe, | 1197 | .probe = exynos_dp_probe, |
| 1018 | .remove = __devexit_p(exynos_dp_remove), | 1198 | .remove = __devexit_p(exynos_dp_remove), |
| @@ -1020,6 +1200,7 @@ static struct platform_driver exynos_dp_driver = { | |||
| 1020 | .name = "exynos-dp", | 1200 | .name = "exynos-dp", |
| 1021 | .owner = THIS_MODULE, | 1201 | .owner = THIS_MODULE, |
| 1022 | .pm = &exynos_dp_pm_ops, | 1202 | .pm = &exynos_dp_pm_ops, |
| 1203 | .of_match_table = of_match_ptr(exynos_dp_match), | ||
| 1023 | }, | 1204 | }, |
| 1024 | }; | 1205 | }; |
| 1025 | 1206 | ||
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h index 57b8a6531c0e..6c567bbf2fb8 100644 --- a/drivers/video/exynos/exynos_dp_core.h +++ b/drivers/video/exynos/exynos_dp_core.h | |||
| @@ -13,6 +13,13 @@ | |||
| 13 | #ifndef _EXYNOS_DP_CORE_H | 13 | #ifndef _EXYNOS_DP_CORE_H |
| 14 | #define _EXYNOS_DP_CORE_H | 14 | #define _EXYNOS_DP_CORE_H |
| 15 | 15 | ||
| 16 | enum dp_irq_type { | ||
| 17 | DP_IRQ_TYPE_HP_CABLE_IN, | ||
| 18 | DP_IRQ_TYPE_HP_CABLE_OUT, | ||
| 19 | DP_IRQ_TYPE_HP_CHANGE, | ||
| 20 | DP_IRQ_TYPE_UNKNOWN, | ||
| 21 | }; | ||
| 22 | |||
| 16 | struct link_train { | 23 | struct link_train { |
| 17 | int eq_loop; | 24 | int eq_loop; |
| 18 | int cr_loop[4]; | 25 | int cr_loop[4]; |
| @@ -29,9 +36,12 @@ struct exynos_dp_device { | |||
| 29 | struct clk *clock; | 36 | struct clk *clock; |
| 30 | unsigned int irq; | 37 | unsigned int irq; |
| 31 | void __iomem *reg_base; | 38 | void __iomem *reg_base; |
| 39 | void __iomem *phy_addr; | ||
| 40 | unsigned int enable_mask; | ||
| 32 | 41 | ||
| 33 | struct video_info *video_info; | 42 | struct video_info *video_info; |
| 34 | struct link_train link_train; | 43 | struct link_train link_train; |
| 44 | struct work_struct hotplug_work; | ||
| 35 | }; | 45 | }; |
| 36 | 46 | ||
| 37 | /* exynos_dp_reg.c */ | 47 | /* exynos_dp_reg.c */ |
| @@ -50,6 +60,8 @@ void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp, | |||
| 50 | bool enable); | 60 | bool enable); |
| 51 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp); | 61 | void exynos_dp_init_analog_func(struct exynos_dp_device *dp); |
| 52 | void exynos_dp_init_hpd(struct exynos_dp_device *dp); | 62 | void exynos_dp_init_hpd(struct exynos_dp_device *dp); |
| 63 | enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp); | ||
| 64 | void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp); | ||
| 53 | void exynos_dp_reset_aux(struct exynos_dp_device *dp); | 65 | void exynos_dp_reset_aux(struct exynos_dp_device *dp); |
| 54 | void exynos_dp_init_aux(struct exynos_dp_device *dp); | 66 | void exynos_dp_init_aux(struct exynos_dp_device *dp); |
| 55 | int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp); | 67 | int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp); |
| @@ -107,11 +119,7 @@ u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp); | |||
| 107 | void exynos_dp_reset_macro(struct exynos_dp_device *dp); | 119 | void exynos_dp_reset_macro(struct exynos_dp_device *dp); |
| 108 | void exynos_dp_init_video(struct exynos_dp_device *dp); | 120 | void exynos_dp_init_video(struct exynos_dp_device *dp); |
| 109 | 121 | ||
| 110 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, | 122 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp); |
| 111 | u32 color_depth, | ||
| 112 | u32 color_space, | ||
| 113 | u32 dynamic_range, | ||
| 114 | u32 ycbcr_coeff); | ||
| 115 | int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp); | 123 | int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp); |
| 116 | void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, | 124 | void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp, |
| 117 | enum clock_recovery_m_value_type type, | 125 | enum clock_recovery_m_value_type type, |
| @@ -121,8 +129,7 @@ void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type); | |||
| 121 | void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable); | 129 | void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable); |
| 122 | void exynos_dp_start_video(struct exynos_dp_device *dp); | 130 | void exynos_dp_start_video(struct exynos_dp_device *dp); |
| 123 | int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp); | 131 | int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp); |
| 124 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp, | 132 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp); |
| 125 | struct video_info *video_info); | ||
| 126 | void exynos_dp_enable_scrambling(struct exynos_dp_device *dp); | 133 | void exynos_dp_enable_scrambling(struct exynos_dp_device *dp); |
| 127 | void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); | 134 | void exynos_dp_disable_scrambling(struct exynos_dp_device *dp); |
| 128 | 135 | ||
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c index 3f5ca8a0d5ea..29d9d035c73a 100644 --- a/drivers/video/exynos/exynos_dp_reg.c +++ b/drivers/video/exynos/exynos_dp_reg.c | |||
| @@ -19,11 +19,11 @@ | |||
| 19 | #include "exynos_dp_core.h" | 19 | #include "exynos_dp_core.h" |
| 20 | #include "exynos_dp_reg.h" | 20 | #include "exynos_dp_reg.h" |
| 21 | 21 | ||
| 22 | #define COMMON_INT_MASK_1 (0) | 22 | #define COMMON_INT_MASK_1 0 |
| 23 | #define COMMON_INT_MASK_2 (0) | 23 | #define COMMON_INT_MASK_2 0 |
| 24 | #define COMMON_INT_MASK_3 (0) | 24 | #define COMMON_INT_MASK_3 0 |
| 25 | #define COMMON_INT_MASK_4 (0) | 25 | #define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG) |
| 26 | #define INT_STA_MASK (0) | 26 | #define INT_STA_MASK INT_HPD |
| 27 | 27 | ||
| 28 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable) | 28 | void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable) |
| 29 | { | 29 | { |
| @@ -88,7 +88,7 @@ void exynos_dp_init_analog_param(struct exynos_dp_device *dp) | |||
| 88 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp) | 88 | void exynos_dp_init_interrupt(struct exynos_dp_device *dp) |
| 89 | { | 89 | { |
| 90 | /* Set interrupt pin assertion polarity as high */ | 90 | /* Set interrupt pin assertion polarity as high */ |
| 91 | writel(INT_POL, dp->reg_base + EXYNOS_DP_INT_CTL); | 91 | writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL); |
| 92 | 92 | ||
| 93 | /* Clear pending regisers */ | 93 | /* Clear pending regisers */ |
| 94 | writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); | 94 | writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1); |
| @@ -324,7 +324,7 @@ void exynos_dp_init_analog_func(struct exynos_dp_device *dp) | |||
| 324 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); | 324 | writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | void exynos_dp_init_hpd(struct exynos_dp_device *dp) | 327 | void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp) |
| 328 | { | 328 | { |
| 329 | u32 reg; | 329 | u32 reg; |
| 330 | 330 | ||
| @@ -333,12 +333,38 @@ void exynos_dp_init_hpd(struct exynos_dp_device *dp) | |||
| 333 | 333 | ||
| 334 | reg = INT_HPD; | 334 | reg = INT_HPD; |
| 335 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); | 335 | writel(reg, dp->reg_base + EXYNOS_DP_INT_STA); |
| 336 | } | ||
| 337 | |||
| 338 | void exynos_dp_init_hpd(struct exynos_dp_device *dp) | ||
| 339 | { | ||
| 340 | u32 reg; | ||
| 341 | |||
| 342 | exynos_dp_clear_hotplug_interrupts(dp); | ||
| 336 | 343 | ||
| 337 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); | 344 | reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3); |
| 338 | reg &= ~(F_HPD | HPD_CTRL); | 345 | reg &= ~(F_HPD | HPD_CTRL); |
| 339 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); | 346 | writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3); |
| 340 | } | 347 | } |
| 341 | 348 | ||
| 349 | enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp) | ||
| 350 | { | ||
| 351 | u32 reg; | ||
| 352 | |||
| 353 | /* Parse hotplug interrupt status register */ | ||
| 354 | reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4); | ||
| 355 | |||
| 356 | if (reg & PLUG) | ||
| 357 | return DP_IRQ_TYPE_HP_CABLE_IN; | ||
| 358 | |||
| 359 | if (reg & HPD_LOST) | ||
| 360 | return DP_IRQ_TYPE_HP_CABLE_OUT; | ||
| 361 | |||
| 362 | if (reg & HOTPLUG_CHG) | ||
| 363 | return DP_IRQ_TYPE_HP_CHANGE; | ||
| 364 | |||
| 365 | return DP_IRQ_TYPE_UNKNOWN; | ||
| 366 | } | ||
| 367 | |||
| 342 | void exynos_dp_reset_aux(struct exynos_dp_device *dp) | 368 | void exynos_dp_reset_aux(struct exynos_dp_device *dp) |
| 343 | { | 369 | { |
| 344 | u32 reg; | 370 | u32 reg; |
| @@ -491,7 +517,7 @@ int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp, | |||
| 491 | int i; | 517 | int i; |
| 492 | int retval; | 518 | int retval; |
| 493 | 519 | ||
| 494 | for (i = 0; i < 10; i++) { | 520 | for (i = 0; i < 3; i++) { |
| 495 | /* Clear AUX CH data buffer */ | 521 | /* Clear AUX CH data buffer */ |
| 496 | reg = BUF_CLR; | 522 | reg = BUF_CLR; |
| 497 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | 523 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); |
| @@ -552,7 +578,7 @@ int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp, | |||
| 552 | else | 578 | else |
| 553 | cur_data_count = count - start_offset; | 579 | cur_data_count = count - start_offset; |
| 554 | 580 | ||
| 555 | for (i = 0; i < 10; i++) { | 581 | for (i = 0; i < 3; i++) { |
| 556 | /* Select DPCD device address */ | 582 | /* Select DPCD device address */ |
| 557 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | 583 | reg = AUX_ADDR_7_0(reg_addr + start_offset); |
| 558 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | 584 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); |
| @@ -617,7 +643,7 @@ int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp, | |||
| 617 | cur_data_count = count - start_offset; | 643 | cur_data_count = count - start_offset; |
| 618 | 644 | ||
| 619 | /* AUX CH Request Transaction process */ | 645 | /* AUX CH Request Transaction process */ |
| 620 | for (i = 0; i < 10; i++) { | 646 | for (i = 0; i < 3; i++) { |
| 621 | /* Select DPCD device address */ | 647 | /* Select DPCD device address */ |
| 622 | reg = AUX_ADDR_7_0(reg_addr + start_offset); | 648 | reg = AUX_ADDR_7_0(reg_addr + start_offset); |
| 623 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); | 649 | writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0); |
| @@ -700,17 +726,15 @@ int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp, | |||
| 700 | int i; | 726 | int i; |
| 701 | int retval; | 727 | int retval; |
| 702 | 728 | ||
| 703 | for (i = 0; i < 10; i++) { | 729 | for (i = 0; i < 3; i++) { |
| 704 | /* Clear AUX CH data buffer */ | 730 | /* Clear AUX CH data buffer */ |
| 705 | reg = BUF_CLR; | 731 | reg = BUF_CLR; |
| 706 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | 732 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); |
| 707 | 733 | ||
| 708 | /* Select EDID device */ | 734 | /* Select EDID device */ |
| 709 | retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr); | 735 | retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr); |
| 710 | if (retval != 0) { | 736 | if (retval != 0) |
| 711 | dev_err(dp->dev, "Select EDID device fail!\n"); | ||
| 712 | continue; | 737 | continue; |
| 713 | } | ||
| 714 | 738 | ||
| 715 | /* | 739 | /* |
| 716 | * Set I2C transaction and read data | 740 | * Set I2C transaction and read data |
| @@ -750,7 +774,7 @@ int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp, | |||
| 750 | int retval = 0; | 774 | int retval = 0; |
| 751 | 775 | ||
| 752 | for (i = 0; i < count; i += 16) { | 776 | for (i = 0; i < count; i += 16) { |
| 753 | for (j = 0; j < 100; j++) { | 777 | for (j = 0; j < 3; j++) { |
| 754 | /* Clear AUX CH data buffer */ | 778 | /* Clear AUX CH data buffer */ |
| 755 | reg = BUF_CLR; | 779 | reg = BUF_CLR; |
| 756 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); | 780 | writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL); |
| @@ -1034,24 +1058,20 @@ void exynos_dp_init_video(struct exynos_dp_device *dp) | |||
| 1034 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); | 1058 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8); |
| 1035 | } | 1059 | } |
| 1036 | 1060 | ||
| 1037 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp, | 1061 | void exynos_dp_set_video_color_format(struct exynos_dp_device *dp) |
| 1038 | u32 color_depth, | ||
| 1039 | u32 color_space, | ||
| 1040 | u32 dynamic_range, | ||
| 1041 | u32 ycbcr_coeff) | ||
| 1042 | { | 1062 | { |
| 1043 | u32 reg; | 1063 | u32 reg; |
| 1044 | 1064 | ||
| 1045 | /* Configure the input color depth, color space, dynamic range */ | 1065 | /* Configure the input color depth, color space, dynamic range */ |
| 1046 | reg = (dynamic_range << IN_D_RANGE_SHIFT) | | 1066 | reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) | |
| 1047 | (color_depth << IN_BPC_SHIFT) | | 1067 | (dp->video_info->color_depth << IN_BPC_SHIFT) | |
| 1048 | (color_space << IN_COLOR_F_SHIFT); | 1068 | (dp->video_info->color_space << IN_COLOR_F_SHIFT); |
| 1049 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2); | 1069 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2); |
| 1050 | 1070 | ||
| 1051 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ | 1071 | /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */ |
| 1052 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); | 1072 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3); |
| 1053 | reg &= ~IN_YC_COEFFI_MASK; | 1073 | reg &= ~IN_YC_COEFFI_MASK; |
| 1054 | if (ycbcr_coeff) | 1074 | if (dp->video_info->ycbcr_coeff) |
| 1055 | reg |= IN_YC_COEFFI_ITU709; | 1075 | reg |= IN_YC_COEFFI_ITU709; |
| 1056 | else | 1076 | else |
| 1057 | reg |= IN_YC_COEFFI_ITU601; | 1077 | reg |= IN_YC_COEFFI_ITU601; |
| @@ -1178,8 +1198,7 @@ int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp) | |||
| 1178 | return 0; | 1198 | return 0; |
| 1179 | } | 1199 | } |
| 1180 | 1200 | ||
| 1181 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp, | 1201 | void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp) |
| 1182 | struct video_info *video_info) | ||
| 1183 | { | 1202 | { |
| 1184 | u32 reg; | 1203 | u32 reg; |
| 1185 | 1204 | ||
| @@ -1190,17 +1209,17 @@ void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp, | |||
| 1190 | 1209 | ||
| 1191 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1210 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
| 1192 | reg &= ~INTERACE_SCAN_CFG; | 1211 | reg &= ~INTERACE_SCAN_CFG; |
| 1193 | reg |= (video_info->interlaced << 2); | 1212 | reg |= (dp->video_info->interlaced << 2); |
| 1194 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1213 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
| 1195 | 1214 | ||
| 1196 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1215 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
| 1197 | reg &= ~VSYNC_POLARITY_CFG; | 1216 | reg &= ~VSYNC_POLARITY_CFG; |
| 1198 | reg |= (video_info->v_sync_polarity << 1); | 1217 | reg |= (dp->video_info->v_sync_polarity << 1); |
| 1199 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1218 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
| 1200 | 1219 | ||
| 1201 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1220 | reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
| 1202 | reg &= ~HSYNC_POLARITY_CFG; | 1221 | reg &= ~HSYNC_POLARITY_CFG; |
| 1203 | reg |= (video_info->h_sync_polarity << 0); | 1222 | reg |= (dp->video_info->h_sync_polarity << 0); |
| 1204 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); | 1223 | writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10); |
| 1205 | 1224 | ||
| 1206 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; | 1225 | reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE; |
diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h index 1f2f014cfe88..2e9bd0e0b9f2 100644 --- a/drivers/video/exynos/exynos_dp_reg.h +++ b/drivers/video/exynos/exynos_dp_reg.h | |||
| @@ -242,7 +242,8 @@ | |||
| 242 | 242 | ||
| 243 | /* EXYNOS_DP_INT_CTL */ | 243 | /* EXYNOS_DP_INT_CTL */ |
| 244 | #define SOFT_INT_CTRL (0x1 << 2) | 244 | #define SOFT_INT_CTRL (0x1 << 2) |
| 245 | #define INT_POL (0x1 << 0) | 245 | #define INT_POL1 (0x1 << 1) |
| 246 | #define INT_POL0 (0x1 << 0) | ||
| 246 | 247 | ||
| 247 | /* EXYNOS_DP_SYS_CTL_1 */ | 248 | /* EXYNOS_DP_SYS_CTL_1 */ |
| 248 | #define DET_STA (0x1 << 2) | 249 | #define DET_STA (0x1 << 2) |
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c index ede9e55413f8..d3fc92eaee89 100644 --- a/drivers/video/fsl-diu-fb.c +++ b/drivers/video/fsl-diu-fb.c | |||
| @@ -337,13 +337,11 @@ struct mfb_info { | |||
| 337 | int registered; | 337 | int registered; |
| 338 | unsigned long pseudo_palette[16]; | 338 | unsigned long pseudo_palette[16]; |
| 339 | struct diu_ad *ad; | 339 | struct diu_ad *ad; |
| 340 | int cursor_reset; | ||
| 341 | unsigned char g_alpha; | 340 | unsigned char g_alpha; |
| 342 | unsigned int count; | 341 | unsigned int count; |
| 343 | int x_aoi_d; /* aoi display x offset to physical screen */ | 342 | int x_aoi_d; /* aoi display x offset to physical screen */ |
| 344 | int y_aoi_d; /* aoi display y offset to physical screen */ | 343 | int y_aoi_d; /* aoi display y offset to physical screen */ |
| 345 | struct fsl_diu_data *parent; | 344 | struct fsl_diu_data *parent; |
| 346 | u8 *edid_data; | ||
| 347 | }; | 345 | }; |
| 348 | 346 | ||
| 349 | /** | 347 | /** |
| @@ -378,6 +376,8 @@ struct fsl_diu_data { | |||
| 378 | struct diu_ad ad[NUM_AOIS] __aligned(8); | 376 | struct diu_ad ad[NUM_AOIS] __aligned(8); |
| 379 | u8 gamma[256 * 3] __aligned(32); | 377 | u8 gamma[256 * 3] __aligned(32); |
| 380 | u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32); | 378 | u8 cursor[MAX_CURS * MAX_CURS * 2] __aligned(32); |
| 379 | uint8_t edid_data[EDID_LENGTH]; | ||
| 380 | bool has_edid; | ||
| 381 | } __aligned(32); | 381 | } __aligned(32); |
| 382 | 382 | ||
| 383 | /* Determine the DMA address of a member of the fsl_diu_data structure */ | 383 | /* Determine the DMA address of a member of the fsl_diu_data structure */ |
| @@ -430,6 +430,22 @@ static struct mfb_info mfb_template[] = { | |||
| 430 | }, | 430 | }, |
| 431 | }; | 431 | }; |
| 432 | 432 | ||
| 433 | #ifdef DEBUG | ||
| 434 | static void __attribute__ ((unused)) fsl_diu_dump(struct diu __iomem *hw) | ||
| 435 | { | ||
| 436 | mb(); | ||
| 437 | pr_debug("DIU: desc=%08x,%08x,%08x, gamma=%08x pallete=%08x " | ||
| 438 | "cursor=%08x curs_pos=%08x diu_mode=%08x bgnd=%08x " | ||
| 439 | "disp_size=%08x hsyn_para=%08x vsyn_para=%08x syn_pol=%08x " | ||
| 440 | "thresholds=%08x int_mask=%08x plut=%08x\n", | ||
| 441 | hw->desc[0], hw->desc[1], hw->desc[2], hw->gamma, | ||
| 442 | hw->pallete, hw->cursor, hw->curs_pos, hw->diu_mode, | ||
| 443 | hw->bgnd, hw->disp_size, hw->hsyn_para, hw->vsyn_para, | ||
| 444 | hw->syn_pol, hw->thresholds, hw->int_mask, hw->plut); | ||
| 445 | rmb(); | ||
| 446 | } | ||
| 447 | #endif | ||
| 448 | |||
| 433 | /** | 449 | /** |
| 434 | * fsl_diu_name_to_port - convert a port name to a monitor port enum | 450 | * fsl_diu_name_to_port - convert a port name to a monitor port enum |
| 435 | * | 451 | * |
| @@ -481,8 +497,7 @@ static void fsl_diu_enable_panel(struct fb_info *info) | |||
| 481 | 497 | ||
| 482 | switch (mfbi->index) { | 498 | switch (mfbi->index) { |
| 483 | case PLANE0: | 499 | case PLANE0: |
| 484 | if (hw->desc[0] != ad->paddr) | 500 | wr_reg_wa(&hw->desc[0], ad->paddr); |
| 485 | wr_reg_wa(&hw->desc[0], ad->paddr); | ||
| 486 | break; | 501 | break; |
| 487 | case PLANE1_AOI0: | 502 | case PLANE1_AOI0: |
| 488 | cmfbi = &data->mfb[2]; | 503 | cmfbi = &data->mfb[2]; |
| @@ -534,8 +549,7 @@ static void fsl_diu_disable_panel(struct fb_info *info) | |||
| 534 | 549 | ||
| 535 | switch (mfbi->index) { | 550 | switch (mfbi->index) { |
| 536 | case PLANE0: | 551 | case PLANE0: |
| 537 | if (hw->desc[0] != data->dummy_ad.paddr) | 552 | wr_reg_wa(&hw->desc[0], 0); |
| 538 | wr_reg_wa(&hw->desc[0], data->dummy_ad.paddr); | ||
| 539 | break; | 553 | break; |
| 540 | case PLANE1_AOI0: | 554 | case PLANE1_AOI0: |
| 541 | cmfbi = &data->mfb[2]; | 555 | cmfbi = &data->mfb[2]; |
| @@ -792,7 +806,8 @@ static void update_lcdc(struct fb_info *info) | |||
| 792 | 806 | ||
| 793 | hw = data->diu_reg; | 807 | hw = data->diu_reg; |
| 794 | 808 | ||
| 795 | diu_ops.set_monitor_port(data->monitor_port); | 809 | if (diu_ops.set_monitor_port) |
| 810 | diu_ops.set_monitor_port(data->monitor_port); | ||
| 796 | gamma_table_base = data->gamma; | 811 | gamma_table_base = data->gamma; |
| 797 | 812 | ||
| 798 | /* Prep for DIU init - gamma table, cursor table */ | 813 | /* Prep for DIU init - gamma table, cursor table */ |
| @@ -811,12 +826,8 @@ static void update_lcdc(struct fb_info *info) | |||
| 811 | out_be32(&hw->gamma, DMA_ADDR(data, gamma)); | 826 | out_be32(&hw->gamma, DMA_ADDR(data, gamma)); |
| 812 | out_be32(&hw->cursor, DMA_ADDR(data, cursor)); | 827 | out_be32(&hw->cursor, DMA_ADDR(data, cursor)); |
| 813 | 828 | ||
| 814 | out_be32(&hw->bgnd, 0x007F7F7F); /* BGND */ | 829 | out_be32(&hw->bgnd, 0x007F7F7F); /* Set background to grey */ |
| 815 | out_be32(&hw->bgnd_wb, 0); /* BGND_WB */ | 830 | out_be32(&hw->disp_size, (var->yres << 16) | var->xres); |
| 816 | out_be32(&hw->disp_size, (var->yres << 16 | var->xres)); | ||
| 817 | /* DISP SIZE */ | ||
| 818 | out_be32(&hw->wb_size, 0); /* WB SIZE */ | ||
| 819 | out_be32(&hw->wb_mem_addr, 0); /* WB MEM ADDR */ | ||
| 820 | 831 | ||
| 821 | /* Horizontal and vertical configuration register */ | 832 | /* Horizontal and vertical configuration register */ |
| 822 | temp = var->left_margin << 22 | /* BP_H */ | 833 | temp = var->left_margin << 22 | /* BP_H */ |
| @@ -833,9 +844,20 @@ static void update_lcdc(struct fb_info *info) | |||
| 833 | 844 | ||
| 834 | diu_ops.set_pixel_clock(var->pixclock); | 845 | diu_ops.set_pixel_clock(var->pixclock); |
| 835 | 846 | ||
| 836 | out_be32(&hw->syn_pol, 0); /* SYNC SIGNALS POLARITY */ | 847 | #ifndef CONFIG_PPC_MPC512x |
| 837 | out_be32(&hw->int_status, 0); /* INTERRUPT STATUS */ | 848 | /* |
| 849 | * The PLUT register is defined differently on the MPC5121 than it | ||
| 850 | * is on other SOCs. Unfortunately, there's no documentation that | ||
| 851 | * explains how it's supposed to be programmed, so for now, we leave | ||
| 852 | * it at the default value on the MPC5121. | ||
| 853 | * | ||
| 854 | * For other SOCs, program it for the highest priority, which will | ||
| 855 | * reduce the chance of underrun. Technically, we should scale the | ||
| 856 | * priority to match the screen resolution, but doing that properly | ||
| 857 | * requires delicate fine-tuning for each use-case. | ||
| 858 | */ | ||
| 838 | out_be32(&hw->plut, 0x01F5F666); | 859 | out_be32(&hw->plut, 0x01F5F666); |
| 860 | #endif | ||
| 839 | 861 | ||
| 840 | /* Enable the DIU */ | 862 | /* Enable the DIU */ |
| 841 | enable_lcdc(info); | 863 | enable_lcdc(info); |
| @@ -965,7 +987,6 @@ static int fsl_diu_set_par(struct fb_info *info) | |||
| 965 | hw = data->diu_reg; | 987 | hw = data->diu_reg; |
| 966 | 988 | ||
| 967 | set_fix(info); | 989 | set_fix(info); |
| 968 | mfbi->cursor_reset = 1; | ||
| 969 | 990 | ||
| 970 | len = info->var.yres_virtual * info->fix.line_length; | 991 | len = info->var.yres_virtual * info->fix.line_length; |
| 971 | /* Alloc & dealloc each time resolution/bpp change */ | 992 | /* Alloc & dealloc each time resolution/bpp change */ |
| @@ -1107,6 +1128,12 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, | |||
| 1107 | 1128 | ||
| 1108 | if (!arg) | 1129 | if (!arg) |
| 1109 | return -EINVAL; | 1130 | return -EINVAL; |
| 1131 | |||
| 1132 | dev_dbg(info->dev, "ioctl %08x (dir=%s%s type=%u nr=%u size=%u)\n", cmd, | ||
| 1133 | _IOC_DIR(cmd) & _IOC_READ ? "R" : "", | ||
| 1134 | _IOC_DIR(cmd) & _IOC_WRITE ? "W" : "", | ||
| 1135 | _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd)); | ||
| 1136 | |||
| 1110 | switch (cmd) { | 1137 | switch (cmd) { |
| 1111 | case MFB_SET_PIXFMT_OLD: | 1138 | case MFB_SET_PIXFMT_OLD: |
| 1112 | dev_warn(info->dev, | 1139 | dev_warn(info->dev, |
| @@ -1180,6 +1207,23 @@ static int fsl_diu_ioctl(struct fb_info *info, unsigned int cmd, | |||
| 1180 | ad->ckmin_b = ck.blue_min; | 1207 | ad->ckmin_b = ck.blue_min; |
| 1181 | } | 1208 | } |
| 1182 | break; | 1209 | break; |
| 1210 | #ifdef CONFIG_PPC_MPC512x | ||
| 1211 | case MFB_SET_GAMMA: { | ||
| 1212 | struct fsl_diu_data *data = mfbi->parent; | ||
| 1213 | |||
| 1214 | if (copy_from_user(data->gamma, buf, sizeof(data->gamma))) | ||
| 1215 | return -EFAULT; | ||
| 1216 | setbits32(&data->diu_reg->gamma, 0); /* Force table reload */ | ||
| 1217 | break; | ||
| 1218 | } | ||
| 1219 | case MFB_GET_GAMMA: { | ||
| 1220 | struct fsl_diu_data *data = mfbi->parent; | ||
| 1221 | |||
| 1222 | if (copy_to_user(buf, data->gamma, sizeof(data->gamma))) | ||
| 1223 | return -EFAULT; | ||
| 1224 | break; | ||
| 1225 | } | ||
| 1226 | #endif | ||
| 1183 | default: | 1227 | default: |
| 1184 | dev_err(info->dev, "unknown ioctl command (0x%08X)\n", cmd); | 1228 | dev_err(info->dev, "unknown ioctl command (0x%08X)\n", cmd); |
| 1185 | return -ENOIOCTLCMD; | 1229 | return -ENOIOCTLCMD; |
| @@ -1206,8 +1250,22 @@ static int fsl_diu_open(struct fb_info *info, int user) | |||
| 1206 | res = fsl_diu_set_par(info); | 1250 | res = fsl_diu_set_par(info); |
| 1207 | if (res < 0) | 1251 | if (res < 0) |
| 1208 | mfbi->count--; | 1252 | mfbi->count--; |
| 1209 | else | 1253 | else { |
| 1254 | struct fsl_diu_data *data = mfbi->parent; | ||
| 1255 | |||
| 1256 | #ifdef CONFIG_NOT_COHERENT_CACHE | ||
| 1257 | /* | ||
| 1258 | * Enable underrun detection and vertical sync | ||
| 1259 | * interrupts. | ||
| 1260 | */ | ||
| 1261 | clrbits32(&data->diu_reg->int_mask, | ||
| 1262 | INT_UNDRUN | INT_VSYNC); | ||
| 1263 | #else | ||
| 1264 | /* Enable underrun detection */ | ||
| 1265 | clrbits32(&data->diu_reg->int_mask, INT_UNDRUN); | ||
| 1266 | #endif | ||
| 1210 | fsl_diu_enable_panel(info); | 1267 | fsl_diu_enable_panel(info); |
| 1268 | } | ||
| 1211 | } | 1269 | } |
| 1212 | 1270 | ||
| 1213 | spin_unlock(&diu_lock); | 1271 | spin_unlock(&diu_lock); |
| @@ -1223,8 +1281,13 @@ static int fsl_diu_release(struct fb_info *info, int user) | |||
| 1223 | 1281 | ||
| 1224 | spin_lock(&diu_lock); | 1282 | spin_lock(&diu_lock); |
| 1225 | mfbi->count--; | 1283 | mfbi->count--; |
| 1226 | if (mfbi->count == 0) | 1284 | if (mfbi->count == 0) { |
| 1285 | struct fsl_diu_data *data = mfbi->parent; | ||
| 1286 | |||
| 1287 | /* Disable interrupts */ | ||
| 1288 | out_be32(&data->diu_reg->int_mask, 0xffffffff); | ||
| 1227 | fsl_diu_disable_panel(info); | 1289 | fsl_diu_disable_panel(info); |
| 1290 | } | ||
| 1228 | 1291 | ||
| 1229 | spin_unlock(&diu_lock); | 1292 | spin_unlock(&diu_lock); |
| 1230 | return res; | 1293 | return res; |
| @@ -1248,6 +1311,7 @@ static int __devinit install_fb(struct fb_info *info) | |||
| 1248 | { | 1311 | { |
| 1249 | int rc; | 1312 | int rc; |
| 1250 | struct mfb_info *mfbi = info->par; | 1313 | struct mfb_info *mfbi = info->par; |
| 1314 | struct fsl_diu_data *data = mfbi->parent; | ||
| 1251 | const char *aoi_mode, *init_aoi_mode = "320x240"; | 1315 | const char *aoi_mode, *init_aoi_mode = "320x240"; |
| 1252 | struct fb_videomode *db = fsl_diu_mode_db; | 1316 | struct fb_videomode *db = fsl_diu_mode_db; |
| 1253 | unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db); | 1317 | unsigned int dbsize = ARRAY_SIZE(fsl_diu_mode_db); |
| @@ -1264,9 +1328,9 @@ static int __devinit install_fb(struct fb_info *info) | |||
| 1264 | return rc; | 1328 | return rc; |
| 1265 | 1329 | ||
| 1266 | if (mfbi->index == PLANE0) { | 1330 | if (mfbi->index == PLANE0) { |
| 1267 | if (mfbi->edid_data) { | 1331 | if (data->has_edid) { |
| 1268 | /* Now build modedb from EDID */ | 1332 | /* Now build modedb from EDID */ |
| 1269 | fb_edid_to_monspecs(mfbi->edid_data, &info->monspecs); | 1333 | fb_edid_to_monspecs(data->edid_data, &info->monspecs); |
| 1270 | fb_videomode_to_modelist(info->monspecs.modedb, | 1334 | fb_videomode_to_modelist(info->monspecs.modedb, |
| 1271 | info->monspecs.modedb_len, | 1335 | info->monspecs.modedb_len, |
| 1272 | &info->modelist); | 1336 | &info->modelist); |
| @@ -1284,7 +1348,7 @@ static int __devinit install_fb(struct fb_info *info) | |||
| 1284 | * For plane 0 we continue and look into | 1348 | * For plane 0 we continue and look into |
| 1285 | * driver's internal modedb. | 1349 | * driver's internal modedb. |
| 1286 | */ | 1350 | */ |
| 1287 | if ((mfbi->index == PLANE0) && mfbi->edid_data) | 1351 | if ((mfbi->index == PLANE0) && data->has_edid) |
| 1288 | has_default_mode = 0; | 1352 | has_default_mode = 0; |
| 1289 | else | 1353 | else |
| 1290 | return -EINVAL; | 1354 | return -EINVAL; |
| @@ -1348,9 +1412,6 @@ static void uninstall_fb(struct fb_info *info) | |||
| 1348 | if (!mfbi->registered) | 1412 | if (!mfbi->registered) |
| 1349 | return; | 1413 | return; |
| 1350 | 1414 | ||
| 1351 | if (mfbi->index == PLANE0) | ||
| 1352 | kfree(mfbi->edid_data); | ||
| 1353 | |||
| 1354 | unregister_framebuffer(info); | 1415 | unregister_framebuffer(info); |
| 1355 | unmap_video_memory(info); | 1416 | unmap_video_memory(info); |
| 1356 | if (&info->cmap) | 1417 | if (&info->cmap) |
| @@ -1362,7 +1423,7 @@ static void uninstall_fb(struct fb_info *info) | |||
| 1362 | static irqreturn_t fsl_diu_isr(int irq, void *dev_id) | 1423 | static irqreturn_t fsl_diu_isr(int irq, void *dev_id) |
| 1363 | { | 1424 | { |
| 1364 | struct diu __iomem *hw = dev_id; | 1425 | struct diu __iomem *hw = dev_id; |
| 1365 | unsigned int status = in_be32(&hw->int_status); | 1426 | uint32_t status = in_be32(&hw->int_status); |
| 1366 | 1427 | ||
| 1367 | if (status) { | 1428 | if (status) { |
| 1368 | /* This is the workaround for underrun */ | 1429 | /* This is the workaround for underrun */ |
| @@ -1387,40 +1448,6 @@ static irqreturn_t fsl_diu_isr(int irq, void *dev_id) | |||
| 1387 | return IRQ_NONE; | 1448 | return IRQ_NONE; |
| 1388 | } | 1449 | } |
| 1389 | 1450 | ||
| 1390 | static int request_irq_local(struct fsl_diu_data *data) | ||
| 1391 | { | ||
| 1392 | struct diu __iomem *hw = data->diu_reg; | ||
| 1393 | u32 ints; | ||
| 1394 | int ret; | ||
| 1395 | |||
| 1396 | /* Read to clear the status */ | ||
| 1397 | in_be32(&hw->int_status); | ||
| 1398 | |||
| 1399 | ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb", hw); | ||
| 1400 | if (!ret) { | ||
| 1401 | ints = INT_PARERR | INT_LS_BF_VS; | ||
| 1402 | #if !defined(CONFIG_NOT_COHERENT_CACHE) | ||
| 1403 | ints |= INT_VSYNC; | ||
| 1404 | #endif | ||
| 1405 | |||
| 1406 | /* Read to clear the status */ | ||
| 1407 | in_be32(&hw->int_status); | ||
| 1408 | out_be32(&hw->int_mask, ints); | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | return ret; | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | static void free_irq_local(struct fsl_diu_data *data) | ||
| 1415 | { | ||
| 1416 | struct diu __iomem *hw = data->diu_reg; | ||
| 1417 | |||
| 1418 | /* Disable all LCDC interrupt */ | ||
| 1419 | out_be32(&hw->int_mask, 0x1f); | ||
| 1420 | |||
| 1421 | free_irq(data->irq, NULL); | ||
| 1422 | } | ||
| 1423 | |||
| 1424 | #ifdef CONFIG_PM | 1451 | #ifdef CONFIG_PM |
| 1425 | /* | 1452 | /* |
| 1426 | * Power management hooks. Note that we won't be called from IRQ context, | 1453 | * Power management hooks. Note that we won't be called from IRQ context, |
| @@ -1496,8 +1523,8 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
| 1496 | struct device_node *np = pdev->dev.of_node; | 1523 | struct device_node *np = pdev->dev.of_node; |
| 1497 | struct mfb_info *mfbi; | 1524 | struct mfb_info *mfbi; |
| 1498 | struct fsl_diu_data *data; | 1525 | struct fsl_diu_data *data; |
| 1499 | int diu_mode; | ||
| 1500 | dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */ | 1526 | dma_addr_t dma_addr; /* DMA addr of fsl_diu_data struct */ |
| 1527 | const void *prop; | ||
| 1501 | unsigned int i; | 1528 | unsigned int i; |
| 1502 | int ret; | 1529 | int ret; |
| 1503 | 1530 | ||
| @@ -1541,17 +1568,13 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
| 1541 | memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); | 1568 | memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); |
| 1542 | mfbi->parent = data; | 1569 | mfbi->parent = data; |
| 1543 | mfbi->ad = &data->ad[i]; | 1570 | mfbi->ad = &data->ad[i]; |
| 1571 | } | ||
| 1544 | 1572 | ||
| 1545 | if (mfbi->index == PLANE0) { | 1573 | /* Get the EDID data from the device tree, if present */ |
| 1546 | const u8 *prop; | 1574 | prop = of_get_property(np, "edid", &ret); |
| 1547 | int len; | 1575 | if (prop && ret == EDID_LENGTH) { |
| 1548 | 1576 | memcpy(data->edid_data, prop, EDID_LENGTH); | |
| 1549 | /* Get EDID */ | 1577 | data->has_edid = true; |
| 1550 | prop = of_get_property(np, "edid", &len); | ||
| 1551 | if (prop && len == EDID_LENGTH) | ||
| 1552 | mfbi->edid_data = kmemdup(prop, EDID_LENGTH, | ||
| 1553 | GFP_KERNEL); | ||
| 1554 | } | ||
| 1555 | } | 1578 | } |
| 1556 | 1579 | ||
| 1557 | data->diu_reg = of_iomap(np, 0); | 1580 | data->diu_reg = of_iomap(np, 0); |
| @@ -1561,10 +1584,6 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
| 1561 | goto error; | 1584 | goto error; |
| 1562 | } | 1585 | } |
| 1563 | 1586 | ||
| 1564 | diu_mode = in_be32(&data->diu_reg->diu_mode); | ||
| 1565 | if (diu_mode == MFB_MODE0) | ||
| 1566 | out_be32(&data->diu_reg->diu_mode, 0); /* disable DIU */ | ||
| 1567 | |||
| 1568 | /* Get the IRQ of the DIU */ | 1587 | /* Get the IRQ of the DIU */ |
| 1569 | data->irq = irq_of_parse_and_map(np, 0); | 1588 | data->irq = irq_of_parse_and_map(np, 0); |
| 1570 | 1589 | ||
| @@ -1586,11 +1605,11 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
| 1586 | data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad); | 1605 | data->dummy_ad.paddr = DMA_ADDR(data, dummy_ad); |
| 1587 | 1606 | ||
| 1588 | /* | 1607 | /* |
| 1589 | * Let DIU display splash screen if it was pre-initialized | 1608 | * Let DIU continue to display splash screen if it was pre-initialized |
| 1590 | * by the bootloader, set dummy area descriptor otherwise. | 1609 | * by the bootloader; otherwise, clear the display. |
| 1591 | */ | 1610 | */ |
| 1592 | if (diu_mode == MFB_MODE0) | 1611 | if (in_be32(&data->diu_reg->diu_mode) == MFB_MODE0) |
| 1593 | out_be32(&data->diu_reg->desc[0], data->dummy_ad.paddr); | 1612 | out_be32(&data->diu_reg->desc[0], 0); |
| 1594 | 1613 | ||
| 1595 | out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr); | 1614 | out_be32(&data->diu_reg->desc[1], data->dummy_ad.paddr); |
| 1596 | out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr); | 1615 | out_be32(&data->diu_reg->desc[2], data->dummy_ad.paddr); |
| @@ -1603,7 +1622,16 @@ static int __devinit fsl_diu_probe(struct platform_device *pdev) | |||
| 1603 | } | 1622 | } |
| 1604 | } | 1623 | } |
| 1605 | 1624 | ||
| 1606 | if (request_irq_local(data)) { | 1625 | /* |
| 1626 | * Older versions of U-Boot leave interrupts enabled, so disable | ||
| 1627 | * all of them and clear the status register. | ||
| 1628 | */ | ||
| 1629 | out_be32(&data->diu_reg->int_mask, 0xffffffff); | ||
| 1630 | in_be32(&data->diu_reg->int_status); | ||
| 1631 | |||
| 1632 | ret = request_irq(data->irq, fsl_diu_isr, 0, "fsl-diu-fb", | ||
| 1633 | &data->diu_reg); | ||
| 1634 | if (ret) { | ||
| 1607 | dev_err(&pdev->dev, "could not claim irq\n"); | 1635 | dev_err(&pdev->dev, "could not claim irq\n"); |
| 1608 | goto error; | 1636 | goto error; |
| 1609 | } | 1637 | } |
| @@ -1638,7 +1666,8 @@ static int fsl_diu_remove(struct platform_device *pdev) | |||
| 1638 | 1666 | ||
| 1639 | data = dev_get_drvdata(&pdev->dev); | 1667 | data = dev_get_drvdata(&pdev->dev); |
| 1640 | disable_lcdc(&data->fsl_diu_info[0]); | 1668 | disable_lcdc(&data->fsl_diu_info[0]); |
| 1641 | free_irq_local(data); | 1669 | |
| 1670 | free_irq(data->irq, &data->diu_reg); | ||
| 1642 | 1671 | ||
| 1643 | for (i = 0; i < NUM_AOIS; i++) | 1672 | for (i = 0; i < NUM_AOIS; i++) |
| 1644 | uninstall_fb(&data->fsl_diu_info[i]); | 1673 | uninstall_fb(&data->fsl_diu_info[i]); |
| @@ -1741,6 +1770,9 @@ static int __init fsl_diu_init(void) | |||
| 1741 | coherence_data_size = be32_to_cpup(prop) * 13; | 1770 | coherence_data_size = be32_to_cpup(prop) * 13; |
| 1742 | coherence_data_size /= 8; | 1771 | coherence_data_size /= 8; |
| 1743 | 1772 | ||
| 1773 | pr_debug("fsl-diu-fb: coherence data size is %zu bytes\n", | ||
| 1774 | coherence_data_size); | ||
| 1775 | |||
| 1744 | prop = of_get_property(np, "d-cache-line-size", NULL); | 1776 | prop = of_get_property(np, "d-cache-line-size", NULL); |
| 1745 | if (prop == NULL) { | 1777 | if (prop == NULL) { |
| 1746 | pr_err("fsl-diu-fb: missing 'd-cache-line-size' property' " | 1778 | pr_err("fsl-diu-fb: missing 'd-cache-line-size' property' " |
| @@ -1750,10 +1782,17 @@ static int __init fsl_diu_init(void) | |||
| 1750 | } | 1782 | } |
| 1751 | d_cache_line_size = be32_to_cpup(prop); | 1783 | d_cache_line_size = be32_to_cpup(prop); |
| 1752 | 1784 | ||
| 1785 | pr_debug("fsl-diu-fb: cache lines size is %u bytes\n", | ||
| 1786 | d_cache_line_size); | ||
| 1787 | |||
| 1753 | of_node_put(np); | 1788 | of_node_put(np); |
| 1754 | coherence_data = vmalloc(coherence_data_size); | 1789 | coherence_data = vmalloc(coherence_data_size); |
| 1755 | if (!coherence_data) | 1790 | if (!coherence_data) { |
| 1791 | pr_err("fsl-diu-fb: could not allocate coherence data " | ||
| 1792 | "(size=%zu)\n", coherence_data_size); | ||
| 1756 | return -ENOMEM; | 1793 | return -ENOMEM; |
| 1794 | } | ||
| 1795 | |||
| 1757 | #endif | 1796 | #endif |
| 1758 | 1797 | ||
| 1759 | ret = platform_driver_register(&fsl_diu_driver); | 1798 | ret = platform_driver_register(&fsl_diu_driver); |
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig index d877c361abda..346d67d6cf4d 100644 --- a/drivers/video/omap2/Kconfig +++ b/drivers/video/omap2/Kconfig | |||
| @@ -1,6 +1,3 @@ | |||
| 1 | config OMAP2_VRAM | ||
| 2 | bool | ||
| 3 | |||
| 4 | config OMAP2_VRFB | 1 | config OMAP2_VRFB |
| 5 | bool | 2 | bool |
| 6 | 3 | ||
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile index 5ddef129f798..5ea7cb9aed17 100644 --- a/drivers/video/omap2/Makefile +++ b/drivers/video/omap2/Makefile | |||
| @@ -1,4 +1,3 @@ | |||
| 1 | obj-$(CONFIG_OMAP2_VRAM) += vram.o | ||
| 2 | obj-$(CONFIG_OMAP2_VRFB) += vrfb.o | 1 | obj-$(CONFIG_OMAP2_VRFB) += vrfb.o |
| 3 | 2 | ||
| 4 | obj-$(CONFIG_OMAP2_DSS) += dss/ | 3 | obj-$(CONFIG_OMAP2_DSS) += dss/ |
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index c835aa70f96f..65eb76c840a1 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c | |||
| @@ -710,27 +710,6 @@ static void acx_panel_disable(struct omap_dss_device *dssdev) | |||
| 710 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 710 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
| 711 | } | 711 | } |
| 712 | 712 | ||
| 713 | static int acx_panel_suspend(struct omap_dss_device *dssdev) | ||
| 714 | { | ||
| 715 | dev_dbg(&dssdev->dev, "%s\n", __func__); | ||
| 716 | acx_panel_power_off(dssdev); | ||
| 717 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 718 | return 0; | ||
| 719 | } | ||
| 720 | |||
| 721 | static int acx_panel_resume(struct omap_dss_device *dssdev) | ||
| 722 | { | ||
| 723 | int r; | ||
| 724 | |||
| 725 | dev_dbg(&dssdev->dev, "%s\n", __func__); | ||
| 726 | r = acx_panel_power_on(dssdev); | ||
| 727 | if (r) | ||
| 728 | return r; | ||
| 729 | |||
| 730 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 731 | return 0; | ||
| 732 | } | ||
| 733 | |||
| 734 | static void acx_panel_set_timings(struct omap_dss_device *dssdev, | 713 | static void acx_panel_set_timings(struct omap_dss_device *dssdev, |
| 735 | struct omap_video_timings *timings) | 714 | struct omap_video_timings *timings) |
| 736 | { | 715 | { |
| @@ -752,8 +731,6 @@ static struct omap_dss_driver acx_panel_driver = { | |||
| 752 | 731 | ||
| 753 | .enable = acx_panel_enable, | 732 | .enable = acx_panel_enable, |
| 754 | .disable = acx_panel_disable, | 733 | .disable = acx_panel_disable, |
| 755 | .suspend = acx_panel_suspend, | ||
| 756 | .resume = acx_panel_resume, | ||
| 757 | 734 | ||
| 758 | .set_timings = acx_panel_set_timings, | 735 | .set_timings = acx_panel_set_timings, |
| 759 | .check_timings = acx_panel_check_timings, | 736 | .check_timings = acx_panel_check_timings, |
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 88295c526815..54ca8ae21078 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c | |||
| @@ -688,40 +688,6 @@ static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) | |||
| 688 | mutex_unlock(&drv_data->lock); | 688 | mutex_unlock(&drv_data->lock); |
| 689 | } | 689 | } |
| 690 | 690 | ||
| 691 | static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev) | ||
| 692 | { | ||
| 693 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | ||
| 694 | |||
| 695 | mutex_lock(&drv_data->lock); | ||
| 696 | |||
| 697 | generic_dpi_panel_power_off(dssdev); | ||
| 698 | |||
| 699 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 700 | |||
| 701 | mutex_unlock(&drv_data->lock); | ||
| 702 | |||
| 703 | return 0; | ||
| 704 | } | ||
| 705 | |||
| 706 | static int generic_dpi_panel_resume(struct omap_dss_device *dssdev) | ||
| 707 | { | ||
| 708 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | ||
| 709 | int r; | ||
| 710 | |||
| 711 | mutex_lock(&drv_data->lock); | ||
| 712 | |||
| 713 | r = generic_dpi_panel_power_on(dssdev); | ||
| 714 | if (r) | ||
| 715 | goto err; | ||
| 716 | |||
| 717 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 718 | |||
| 719 | err: | ||
| 720 | mutex_unlock(&drv_data->lock); | ||
| 721 | |||
| 722 | return r; | ||
| 723 | } | ||
| 724 | |||
| 725 | static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, | 691 | static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, |
| 726 | struct omap_video_timings *timings) | 692 | struct omap_video_timings *timings) |
| 727 | { | 693 | { |
| @@ -769,8 +735,6 @@ static struct omap_dss_driver dpi_driver = { | |||
| 769 | 735 | ||
| 770 | .enable = generic_dpi_panel_enable, | 736 | .enable = generic_dpi_panel_enable, |
| 771 | .disable = generic_dpi_panel_disable, | 737 | .disable = generic_dpi_panel_disable, |
| 772 | .suspend = generic_dpi_panel_suspend, | ||
| 773 | .resume = generic_dpi_panel_resume, | ||
| 774 | 738 | ||
| 775 | .set_timings = generic_dpi_panel_set_timings, | 739 | .set_timings = generic_dpi_panel_set_timings, |
| 776 | .get_timings = generic_dpi_panel_get_timings, | 740 | .get_timings = generic_dpi_panel_get_timings, |
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 90c1cabf244e..ace419b801eb 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c | |||
| @@ -143,46 +143,12 @@ static void lb035q02_panel_disable(struct omap_dss_device *dssdev) | |||
| 143 | mutex_unlock(&ld->lock); | 143 | mutex_unlock(&ld->lock); |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | static int lb035q02_panel_suspend(struct omap_dss_device *dssdev) | ||
| 147 | { | ||
| 148 | struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); | ||
| 149 | |||
| 150 | mutex_lock(&ld->lock); | ||
| 151 | |||
| 152 | lb035q02_panel_power_off(dssdev); | ||
| 153 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 154 | |||
| 155 | mutex_unlock(&ld->lock); | ||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | static int lb035q02_panel_resume(struct omap_dss_device *dssdev) | ||
| 160 | { | ||
| 161 | struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); | ||
| 162 | int r; | ||
| 163 | |||
| 164 | mutex_lock(&ld->lock); | ||
| 165 | |||
| 166 | r = lb035q02_panel_power_on(dssdev); | ||
| 167 | if (r) | ||
| 168 | goto err; | ||
| 169 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 170 | |||
| 171 | mutex_unlock(&ld->lock); | ||
| 172 | return 0; | ||
| 173 | err: | ||
| 174 | mutex_unlock(&ld->lock); | ||
| 175 | return r; | ||
| 176 | } | ||
| 177 | |||
| 178 | static struct omap_dss_driver lb035q02_driver = { | 146 | static struct omap_dss_driver lb035q02_driver = { |
| 179 | .probe = lb035q02_panel_probe, | 147 | .probe = lb035q02_panel_probe, |
| 180 | .remove = lb035q02_panel_remove, | 148 | .remove = lb035q02_panel_remove, |
| 181 | 149 | ||
| 182 | .enable = lb035q02_panel_enable, | 150 | .enable = lb035q02_panel_enable, |
| 183 | .disable = lb035q02_panel_disable, | 151 | .disable = lb035q02_panel_disable, |
| 184 | .suspend = lb035q02_panel_suspend, | ||
| 185 | .resume = lb035q02_panel_resume, | ||
| 186 | 152 | ||
| 187 | .driver = { | 153 | .driver = { |
| 188 | .name = "lgphilips_lb035q02_panel", | 154 | .name = "lgphilips_lb035q02_panel", |
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c index 3fc5ad081a21..d1cb722fcdbc 100644 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ b/drivers/video/omap2/displays/panel-n8x0.c | |||
| @@ -574,54 +574,6 @@ static void n8x0_panel_disable(struct omap_dss_device *dssdev) | |||
| 574 | mutex_unlock(&ddata->lock); | 574 | mutex_unlock(&ddata->lock); |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | static int n8x0_panel_suspend(struct omap_dss_device *dssdev) | ||
| 578 | { | ||
| 579 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
| 580 | |||
| 581 | dev_dbg(&dssdev->dev, "suspend\n"); | ||
| 582 | |||
| 583 | mutex_lock(&ddata->lock); | ||
| 584 | |||
| 585 | rfbi_bus_lock(); | ||
| 586 | |||
| 587 | n8x0_panel_power_off(dssdev); | ||
| 588 | |||
| 589 | rfbi_bus_unlock(); | ||
| 590 | |||
| 591 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 592 | |||
| 593 | mutex_unlock(&ddata->lock); | ||
| 594 | |||
| 595 | return 0; | ||
| 596 | } | ||
| 597 | |||
| 598 | static int n8x0_panel_resume(struct omap_dss_device *dssdev) | ||
| 599 | { | ||
| 600 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
| 601 | int r; | ||
| 602 | |||
| 603 | dev_dbg(&dssdev->dev, "resume\n"); | ||
| 604 | |||
| 605 | mutex_lock(&ddata->lock); | ||
| 606 | |||
| 607 | rfbi_bus_lock(); | ||
| 608 | |||
| 609 | r = n8x0_panel_power_on(dssdev); | ||
| 610 | |||
| 611 | rfbi_bus_unlock(); | ||
| 612 | |||
| 613 | if (r) { | ||
| 614 | mutex_unlock(&ddata->lock); | ||
| 615 | return r; | ||
| 616 | } | ||
| 617 | |||
| 618 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 619 | |||
| 620 | mutex_unlock(&ddata->lock); | ||
| 621 | |||
| 622 | return 0; | ||
| 623 | } | ||
| 624 | |||
| 625 | static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev, | 577 | static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev, |
| 626 | u16 *xres, u16 *yres) | 578 | u16 *xres, u16 *yres) |
| 627 | { | 579 | { |
| @@ -683,8 +635,6 @@ static struct omap_dss_driver n8x0_panel_driver = { | |||
| 683 | 635 | ||
| 684 | .enable = n8x0_panel_enable, | 636 | .enable = n8x0_panel_enable, |
| 685 | .disable = n8x0_panel_disable, | 637 | .disable = n8x0_panel_disable, |
| 686 | .suspend = n8x0_panel_suspend, | ||
| 687 | .resume = n8x0_panel_resume, | ||
| 688 | 638 | ||
| 689 | .update = n8x0_panel_update, | 639 | .update = n8x0_panel_update, |
| 690 | .sync = n8x0_panel_sync, | 640 | .sync = n8x0_panel_sync, |
| @@ -702,18 +652,25 @@ static struct omap_dss_driver n8x0_panel_driver = { | |||
| 702 | 652 | ||
| 703 | static int mipid_spi_probe(struct spi_device *spi) | 653 | static int mipid_spi_probe(struct spi_device *spi) |
| 704 | { | 654 | { |
| 655 | int r; | ||
| 656 | |||
| 705 | dev_dbg(&spi->dev, "mipid_spi_probe\n"); | 657 | dev_dbg(&spi->dev, "mipid_spi_probe\n"); |
| 706 | 658 | ||
| 707 | spi->mode = SPI_MODE_0; | 659 | spi->mode = SPI_MODE_0; |
| 708 | 660 | ||
| 709 | s_drv_data.spidev = spi; | 661 | s_drv_data.spidev = spi; |
| 710 | 662 | ||
| 711 | return 0; | 663 | r = omap_dss_register_driver(&n8x0_panel_driver); |
| 664 | if (r) | ||
| 665 | pr_err("n8x0_panel: dss driver registration failed\n"); | ||
| 666 | |||
| 667 | return r; | ||
| 712 | } | 668 | } |
| 713 | 669 | ||
| 714 | static int mipid_spi_remove(struct spi_device *spi) | 670 | static int mipid_spi_remove(struct spi_device *spi) |
| 715 | { | 671 | { |
| 716 | dev_dbg(&spi->dev, "mipid_spi_remove\n"); | 672 | dev_dbg(&spi->dev, "mipid_spi_remove\n"); |
| 673 | omap_dss_unregister_driver(&n8x0_panel_driver); | ||
| 717 | return 0; | 674 | return 0; |
| 718 | } | 675 | } |
| 719 | 676 | ||
| @@ -725,34 +682,6 @@ static struct spi_driver mipid_spi_driver = { | |||
| 725 | .probe = mipid_spi_probe, | 682 | .probe = mipid_spi_probe, |
| 726 | .remove = __devexit_p(mipid_spi_remove), | 683 | .remove = __devexit_p(mipid_spi_remove), |
| 727 | }; | 684 | }; |
| 685 | module_spi_driver(mipid_spi_driver); | ||
| 728 | 686 | ||
| 729 | static int __init n8x0_panel_drv_init(void) | ||
| 730 | { | ||
| 731 | int r; | ||
| 732 | |||
| 733 | r = spi_register_driver(&mipid_spi_driver); | ||
| 734 | if (r) { | ||
| 735 | pr_err("n8x0_panel: spi driver registration failed\n"); | ||
| 736 | return r; | ||
| 737 | } | ||
| 738 | |||
| 739 | r = omap_dss_register_driver(&n8x0_panel_driver); | ||
| 740 | if (r) { | ||
| 741 | pr_err("n8x0_panel: dss driver registration failed\n"); | ||
| 742 | spi_unregister_driver(&mipid_spi_driver); | ||
| 743 | return r; | ||
| 744 | } | ||
| 745 | |||
| 746 | return 0; | ||
| 747 | } | ||
| 748 | |||
| 749 | static void __exit n8x0_panel_drv_exit(void) | ||
| 750 | { | ||
| 751 | spi_unregister_driver(&mipid_spi_driver); | ||
| 752 | |||
| 753 | omap_dss_unregister_driver(&n8x0_panel_driver); | ||
| 754 | } | ||
| 755 | |||
| 756 | module_init(n8x0_panel_drv_init); | ||
| 757 | module_exit(n8x0_panel_drv_exit); | ||
| 758 | MODULE_LICENSE("GPL"); | 687 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index 908fd268f3dc..2a79c283bebe 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c | |||
| @@ -236,28 +236,6 @@ static void nec_8048_panel_disable(struct omap_dss_device *dssdev) | |||
| 236 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 236 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
| 237 | } | 237 | } |
| 238 | 238 | ||
| 239 | static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) | ||
| 240 | { | ||
| 241 | nec_8048_panel_power_off(dssdev); | ||
| 242 | |||
| 243 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 244 | |||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int nec_8048_panel_resume(struct omap_dss_device *dssdev) | ||
| 249 | { | ||
| 250 | int r; | ||
| 251 | |||
| 252 | r = nec_8048_panel_power_on(dssdev); | ||
| 253 | if (r) | ||
| 254 | return r; | ||
| 255 | |||
| 256 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) | 239 | static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) |
| 262 | { | 240 | { |
| 263 | return 16; | 241 | return 16; |
| @@ -268,8 +246,6 @@ static struct omap_dss_driver nec_8048_driver = { | |||
| 268 | .remove = nec_8048_panel_remove, | 246 | .remove = nec_8048_panel_remove, |
| 269 | .enable = nec_8048_panel_enable, | 247 | .enable = nec_8048_panel_enable, |
| 270 | .disable = nec_8048_panel_disable, | 248 | .disable = nec_8048_panel_disable, |
| 271 | .suspend = nec_8048_panel_suspend, | ||
| 272 | .resume = nec_8048_panel_resume, | ||
| 273 | .get_recommended_bpp = nec_8048_recommended_bpp, | 249 | .get_recommended_bpp = nec_8048_recommended_bpp, |
| 274 | 250 | ||
| 275 | .driver = { | 251 | .driver = { |
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c index 9df87640ddd2..1b94018aac3e 100644 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ b/drivers/video/omap2/displays/panel-picodlp.c | |||
| @@ -50,6 +50,7 @@ struct picodlp_i2c_data { | |||
| 50 | 50 | ||
| 51 | static struct i2c_device_id picodlp_i2c_id[] = { | 51 | static struct i2c_device_id picodlp_i2c_id[] = { |
| 52 | { "picodlp_i2c_driver", 0 }, | 52 | { "picodlp_i2c_driver", 0 }, |
| 53 | { } | ||
| 53 | }; | 54 | }; |
| 54 | 55 | ||
| 55 | struct picodlp_i2c_command { | 56 | struct picodlp_i2c_command { |
| @@ -503,47 +504,6 @@ static void picodlp_panel_disable(struct omap_dss_device *dssdev) | |||
| 503 | dev_dbg(&dssdev->dev, "disabling picodlp panel\n"); | 504 | dev_dbg(&dssdev->dev, "disabling picodlp panel\n"); |
| 504 | } | 505 | } |
| 505 | 506 | ||
| 506 | static int picodlp_panel_suspend(struct omap_dss_device *dssdev) | ||
| 507 | { | ||
| 508 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | ||
| 509 | |||
| 510 | mutex_lock(&picod->lock); | ||
| 511 | /* Turn off DLP Power */ | ||
| 512 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | ||
| 513 | mutex_unlock(&picod->lock); | ||
| 514 | dev_err(&dssdev->dev, "unable to suspend picodlp panel," | ||
| 515 | " panel is not ACTIVE\n"); | ||
| 516 | return -EINVAL; | ||
| 517 | } | ||
| 518 | |||
| 519 | picodlp_panel_power_off(dssdev); | ||
| 520 | |||
| 521 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 522 | mutex_unlock(&picod->lock); | ||
| 523 | |||
| 524 | dev_dbg(&dssdev->dev, "suspending picodlp panel\n"); | ||
| 525 | return 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | static int picodlp_panel_resume(struct omap_dss_device *dssdev) | ||
| 529 | { | ||
| 530 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | ||
| 531 | int r; | ||
| 532 | |||
| 533 | mutex_lock(&picod->lock); | ||
| 534 | if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { | ||
| 535 | mutex_unlock(&picod->lock); | ||
| 536 | dev_err(&dssdev->dev, "unable to resume picodlp panel," | ||
| 537 | " panel is not ACTIVE\n"); | ||
| 538 | return -EINVAL; | ||
| 539 | } | ||
| 540 | |||
| 541 | r = picodlp_panel_power_on(dssdev); | ||
| 542 | mutex_unlock(&picod->lock); | ||
| 543 | dev_dbg(&dssdev->dev, "resuming picodlp panel\n"); | ||
| 544 | return r; | ||
| 545 | } | ||
| 546 | |||
| 547 | static void picodlp_get_resolution(struct omap_dss_device *dssdev, | 507 | static void picodlp_get_resolution(struct omap_dss_device *dssdev, |
| 548 | u16 *xres, u16 *yres) | 508 | u16 *xres, u16 *yres) |
| 549 | { | 509 | { |
| @@ -560,9 +520,6 @@ static struct omap_dss_driver picodlp_driver = { | |||
| 560 | 520 | ||
| 561 | .get_resolution = picodlp_get_resolution, | 521 | .get_resolution = picodlp_get_resolution, |
| 562 | 522 | ||
| 563 | .suspend = picodlp_panel_suspend, | ||
| 564 | .resume = picodlp_panel_resume, | ||
| 565 | |||
| 566 | .driver = { | 523 | .driver = { |
| 567 | .name = "picodlp_panel", | 524 | .name = "picodlp_panel", |
| 568 | .owner = THIS_MODULE, | 525 | .owner = THIS_MODULE, |
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index 1ec3b277ff15..cada8c621e01 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c | |||
| @@ -194,29 +194,12 @@ static void sharp_ls_panel_disable(struct omap_dss_device *dssdev) | |||
| 194 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 194 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev) | ||
| 198 | { | ||
| 199 | sharp_ls_power_off(dssdev); | ||
| 200 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | static int sharp_ls_panel_resume(struct omap_dss_device *dssdev) | ||
| 205 | { | ||
| 206 | int r; | ||
| 207 | r = sharp_ls_power_on(dssdev); | ||
| 208 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 209 | return r; | ||
| 210 | } | ||
| 211 | |||
| 212 | static struct omap_dss_driver sharp_ls_driver = { | 197 | static struct omap_dss_driver sharp_ls_driver = { |
| 213 | .probe = sharp_ls_panel_probe, | 198 | .probe = sharp_ls_panel_probe, |
| 214 | .remove = __exit_p(sharp_ls_panel_remove), | 199 | .remove = __exit_p(sharp_ls_panel_remove), |
| 215 | 200 | ||
| 216 | .enable = sharp_ls_panel_enable, | 201 | .enable = sharp_ls_panel_enable, |
| 217 | .disable = sharp_ls_panel_disable, | 202 | .disable = sharp_ls_panel_disable, |
| 218 | .suspend = sharp_ls_panel_suspend, | ||
| 219 | .resume = sharp_ls_panel_resume, | ||
| 220 | 203 | ||
| 221 | .driver = { | 204 | .driver = { |
| 222 | .name = "sharp_ls_panel", | 205 | .name = "sharp_ls_panel", |
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index f2f644680ca8..a32407a5735a 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
| @@ -1245,76 +1245,6 @@ static void taal_disable(struct omap_dss_device *dssdev) | |||
| 1245 | mutex_unlock(&td->lock); | 1245 | mutex_unlock(&td->lock); |
| 1246 | } | 1246 | } |
| 1247 | 1247 | ||
| 1248 | static int taal_suspend(struct omap_dss_device *dssdev) | ||
| 1249 | { | ||
| 1250 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
| 1251 | int r; | ||
| 1252 | |||
| 1253 | dev_dbg(&dssdev->dev, "suspend\n"); | ||
| 1254 | |||
| 1255 | mutex_lock(&td->lock); | ||
| 1256 | |||
| 1257 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | ||
| 1258 | r = -EINVAL; | ||
| 1259 | goto err; | ||
| 1260 | } | ||
| 1261 | |||
| 1262 | taal_cancel_ulps_work(dssdev); | ||
| 1263 | taal_cancel_esd_work(dssdev); | ||
| 1264 | |||
| 1265 | dsi_bus_lock(dssdev); | ||
| 1266 | |||
| 1267 | r = taal_wake_up(dssdev); | ||
| 1268 | if (!r) | ||
| 1269 | taal_power_off(dssdev); | ||
| 1270 | |||
| 1271 | dsi_bus_unlock(dssdev); | ||
| 1272 | |||
| 1273 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 1274 | |||
| 1275 | mutex_unlock(&td->lock); | ||
| 1276 | |||
| 1277 | return 0; | ||
| 1278 | err: | ||
| 1279 | mutex_unlock(&td->lock); | ||
| 1280 | return r; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | static int taal_resume(struct omap_dss_device *dssdev) | ||
| 1284 | { | ||
| 1285 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
| 1286 | int r; | ||
| 1287 | |||
| 1288 | dev_dbg(&dssdev->dev, "resume\n"); | ||
| 1289 | |||
| 1290 | mutex_lock(&td->lock); | ||
| 1291 | |||
| 1292 | if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { | ||
| 1293 | r = -EINVAL; | ||
| 1294 | goto err; | ||
| 1295 | } | ||
| 1296 | |||
| 1297 | dsi_bus_lock(dssdev); | ||
| 1298 | |||
| 1299 | r = taal_power_on(dssdev); | ||
| 1300 | |||
| 1301 | dsi_bus_unlock(dssdev); | ||
| 1302 | |||
| 1303 | if (r) { | ||
| 1304 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
| 1305 | } else { | ||
| 1306 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 1307 | taal_queue_esd_work(dssdev); | ||
| 1308 | } | ||
| 1309 | |||
| 1310 | mutex_unlock(&td->lock); | ||
| 1311 | |||
| 1312 | return r; | ||
| 1313 | err: | ||
| 1314 | mutex_unlock(&td->lock); | ||
| 1315 | return r; | ||
| 1316 | } | ||
| 1317 | |||
| 1318 | static void taal_framedone_cb(int err, void *data) | 1248 | static void taal_framedone_cb(int err, void *data) |
| 1319 | { | 1249 | { |
| 1320 | struct omap_dss_device *dssdev = data; | 1250 | struct omap_dss_device *dssdev = data; |
| @@ -1818,8 +1748,6 @@ static struct omap_dss_driver taal_driver = { | |||
| 1818 | 1748 | ||
| 1819 | .enable = taal_enable, | 1749 | .enable = taal_enable, |
| 1820 | .disable = taal_disable, | 1750 | .disable = taal_disable, |
| 1821 | .suspend = taal_suspend, | ||
| 1822 | .resume = taal_resume, | ||
| 1823 | 1751 | ||
| 1824 | .update = taal_update, | 1752 | .update = taal_update, |
| 1825 | .sync = taal_sync, | 1753 | .sync = taal_sync, |
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c index 383811cf8648..8281baafe1ef 100644 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ b/drivers/video/omap2/displays/panel-tfp410.c | |||
| @@ -189,37 +189,6 @@ static void tfp410_disable(struct omap_dss_device *dssdev) | |||
| 189 | mutex_unlock(&ddata->lock); | 189 | mutex_unlock(&ddata->lock); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | static int tfp410_suspend(struct omap_dss_device *dssdev) | ||
| 193 | { | ||
| 194 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
| 195 | |||
| 196 | mutex_lock(&ddata->lock); | ||
| 197 | |||
| 198 | tfp410_power_off(dssdev); | ||
| 199 | |||
| 200 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 201 | |||
| 202 | mutex_unlock(&ddata->lock); | ||
| 203 | |||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | |||
| 207 | static int tfp410_resume(struct omap_dss_device *dssdev) | ||
| 208 | { | ||
| 209 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
| 210 | int r; | ||
| 211 | |||
| 212 | mutex_lock(&ddata->lock); | ||
| 213 | |||
| 214 | r = tfp410_power_on(dssdev); | ||
| 215 | if (r == 0) | ||
| 216 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 217 | |||
| 218 | mutex_unlock(&ddata->lock); | ||
| 219 | |||
| 220 | return r; | ||
| 221 | } | ||
| 222 | |||
| 223 | static void tfp410_set_timings(struct omap_dss_device *dssdev, | 192 | static void tfp410_set_timings(struct omap_dss_device *dssdev, |
| 224 | struct omap_video_timings *timings) | 193 | struct omap_video_timings *timings) |
| 225 | { | 194 | { |
| @@ -355,8 +324,6 @@ static struct omap_dss_driver tfp410_driver = { | |||
| 355 | 324 | ||
| 356 | .enable = tfp410_enable, | 325 | .enable = tfp410_enable, |
| 357 | .disable = tfp410_disable, | 326 | .disable = tfp410_disable, |
| 358 | .suspend = tfp410_suspend, | ||
| 359 | .resume = tfp410_resume, | ||
| 360 | 327 | ||
| 361 | .set_timings = tfp410_set_timings, | 328 | .set_timings = tfp410_set_timings, |
| 362 | .get_timings = tfp410_get_timings, | 329 | .get_timings = tfp410_get_timings, |
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index b5e6dbc59f0a..316b3da6d2cb 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c | |||
| @@ -401,24 +401,6 @@ static void tpo_td043_disable(struct omap_dss_device *dssdev) | |||
| 401 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 401 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
| 402 | } | 402 | } |
| 403 | 403 | ||
| 404 | static int tpo_td043_suspend(struct omap_dss_device *dssdev) | ||
| 405 | { | ||
| 406 | dev_dbg(&dssdev->dev, "suspend\n"); | ||
| 407 | |||
| 408 | tpo_td043_disable_dss(dssdev); | ||
| 409 | |||
| 410 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 411 | |||
| 412 | return 0; | ||
| 413 | } | ||
| 414 | |||
| 415 | static int tpo_td043_resume(struct omap_dss_device *dssdev) | ||
| 416 | { | ||
| 417 | dev_dbg(&dssdev->dev, "resume\n"); | ||
| 418 | |||
| 419 | return tpo_td043_enable_dss(dssdev); | ||
| 420 | } | ||
| 421 | |||
| 422 | static int tpo_td043_probe(struct omap_dss_device *dssdev) | 404 | static int tpo_td043_probe(struct omap_dss_device *dssdev) |
| 423 | { | 405 | { |
| 424 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 406 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); |
| @@ -500,8 +482,6 @@ static struct omap_dss_driver tpo_td043_driver = { | |||
| 500 | 482 | ||
| 501 | .enable = tpo_td043_enable, | 483 | .enable = tpo_td043_enable, |
| 502 | .disable = tpo_td043_disable, | 484 | .disable = tpo_td043_disable, |
| 503 | .suspend = tpo_td043_suspend, | ||
| 504 | .resume = tpo_td043_resume, | ||
| 505 | .set_mirror = tpo_td043_set_hmirror, | 485 | .set_mirror = tpo_td043_set_hmirror, |
| 506 | .get_mirror = tpo_td043_get_hmirror, | 486 | .get_mirror = tpo_td043_get_hmirror, |
| 507 | 487 | ||
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index 80f5390aa136..cb0f145c7077 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig | |||
| @@ -1,33 +1,30 @@ | |||
| 1 | menuconfig OMAP2_DSS | 1 | menuconfig OMAP2_DSS |
| 2 | tristate "OMAP2+ Display Subsystem support" | 2 | tristate "OMAP2+ Display Subsystem support" |
| 3 | depends on ARCH_OMAP2PLUS | ||
| 4 | help | 3 | help |
| 5 | OMAP2+ Display Subsystem support. | 4 | OMAP2+ Display Subsystem support. |
| 6 | 5 | ||
| 7 | if OMAP2_DSS | 6 | if OMAP2_DSS |
| 8 | 7 | ||
| 9 | config OMAP2_VRAM_SIZE | 8 | config OMAP2_DSS_DEBUG |
| 10 | int "VRAM size (MB)" | 9 | bool "Debug support" |
| 11 | range 0 32 | 10 | default n |
| 12 | default 0 | ||
| 13 | help | 11 | help |
| 14 | The amount of SDRAM to reserve at boot time for video RAM use. | 12 | This enables printing of debug messages. Alternatively, debug messages |
| 15 | This VRAM will be used by omapfb and other drivers that need | 13 | can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting |
| 16 | large continuous RAM area for video use. | 14 | appropriate flags in <debugfs>/dynamic_debug/control. |
| 17 | 15 | ||
| 18 | You can also set this with "vram=<bytes>" kernel argument, or | 16 | config OMAP2_DSS_DEBUGFS |
| 19 | in the board file. | 17 | bool "Debugfs filesystem support" |
| 20 | 18 | depends on DEBUG_FS | |
| 21 | config OMAP2_DSS_DEBUG_SUPPORT | 19 | default n |
| 22 | bool "Debug support" | ||
| 23 | default y | ||
| 24 | help | 20 | help |
| 25 | This enables debug messages. You need to enable printing | 21 | This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables |
| 26 | with 'debug' module parameter. | 22 | querying about clock configuration and register configuration of dss, |
| 23 | dispc, dsi, hdmi and rfbi. | ||
| 27 | 24 | ||
| 28 | config OMAP2_DSS_COLLECT_IRQ_STATS | 25 | config OMAP2_DSS_COLLECT_IRQ_STATS |
| 29 | bool "Collect DSS IRQ statistics" | 26 | bool "Collect DSS IRQ statistics" |
| 30 | depends on OMAP2_DSS_DEBUG_SUPPORT | 27 | depends on OMAP2_DSS_DEBUGFS |
| 31 | default n | 28 | default n |
| 32 | help | 29 | help |
| 33 | Collect DSS IRQ statistics, printable via debugfs. | 30 | Collect DSS IRQ statistics, printable via debugfs. |
| @@ -62,7 +59,6 @@ config OMAP2_DSS_VENC | |||
| 62 | 59 | ||
| 63 | config OMAP4_DSS_HDMI | 60 | config OMAP4_DSS_HDMI |
| 64 | bool "HDMI support" | 61 | bool "HDMI support" |
| 65 | depends on ARCH_OMAP4 | ||
| 66 | default y | 62 | default y |
| 67 | help | 63 | help |
| 68 | HDMI Interface. This adds the High Definition Multimedia Interface. | 64 | HDMI Interface. This adds the High Definition Multimedia Interface. |
| @@ -70,11 +66,9 @@ config OMAP4_DSS_HDMI | |||
| 70 | 66 | ||
| 71 | config OMAP4_DSS_HDMI_AUDIO | 67 | config OMAP4_DSS_HDMI_AUDIO |
| 72 | bool | 68 | bool |
| 73 | depends on OMAP4_DSS_HDMI | ||
| 74 | 69 | ||
| 75 | config OMAP2_DSS_SDI | 70 | config OMAP2_DSS_SDI |
| 76 | bool "SDI support" | 71 | bool "SDI support" |
| 77 | depends on ARCH_OMAP3 | ||
| 78 | default n | 72 | default n |
| 79 | help | 73 | help |
| 80 | SDI (Serial Display Interface) support. | 74 | SDI (Serial Display Interface) support. |
| @@ -84,7 +78,6 @@ config OMAP2_DSS_SDI | |||
| 84 | 78 | ||
| 85 | config OMAP2_DSS_DSI | 79 | config OMAP2_DSS_DSI |
| 86 | bool "DSI support" | 80 | bool "DSI support" |
| 87 | depends on ARCH_OMAP3 || ARCH_OMAP4 || ARCH_OMAP5 | ||
| 88 | default n | 81 | default n |
| 89 | help | 82 | help |
| 90 | MIPI DSI (Display Serial Interface) support. | 83 | MIPI DSI (Display Serial Interface) support. |
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 4549869bfe1a..61949ff7940c 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile | |||
| @@ -1,6 +1,10 @@ | |||
| 1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o | 1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o |
| 2 | # Core DSS files | ||
| 2 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ | 3 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ |
| 3 | manager.o manager-sysfs.o overlay.o overlay-sysfs.o output.o apply.o | 4 | output.o |
| 5 | # DSS compat layer files | ||
| 6 | omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ | ||
| 7 | dispc-compat.o display-sysfs.o | ||
| 4 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o | 8 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o |
| 5 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o | 9 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o |
| 6 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o | 10 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o |
| @@ -8,3 +12,4 @@ omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o | |||
| 8 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o | 12 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o |
| 9 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ | 13 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ |
| 10 | hdmi_panel.o ti_hdmi_4xxx_ip.o | 14 | hdmi_panel.o ti_hdmi_4xxx_ip.o |
| 15 | ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG | ||
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c index 19d66f471b4b..d446bdfc4c82 100644 --- a/drivers/video/omap2/dss/apply.c +++ b/drivers/video/omap2/dss/apply.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #define DSS_SUBSYS_NAME "APPLY" | 18 | #define DSS_SUBSYS_NAME "APPLY" |
| 19 | 19 | ||
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/module.h> | ||
| 21 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
| 22 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
| 23 | #include <linux/jiffies.h> | 24 | #include <linux/jiffies.h> |
| @@ -26,6 +27,7 @@ | |||
| 26 | 27 | ||
| 27 | #include "dss.h" | 28 | #include "dss.h" |
| 28 | #include "dss_features.h" | 29 | #include "dss_features.h" |
| 30 | #include "dispc-compat.h" | ||
| 29 | 31 | ||
| 30 | /* | 32 | /* |
| 31 | * We have 4 levels of cache for the dispc settings. First two are in SW and | 33 | * We have 4 levels of cache for the dispc settings. First two are in SW and |
| @@ -70,7 +72,6 @@ struct ovl_priv_data { | |||
| 70 | bool shadow_extra_info_dirty; | 72 | bool shadow_extra_info_dirty; |
| 71 | 73 | ||
| 72 | bool enabled; | 74 | bool enabled; |
| 73 | enum omap_channel channel; | ||
| 74 | u32 fifo_low, fifo_high; | 75 | u32 fifo_low, fifo_high; |
| 75 | 76 | ||
| 76 | /* | 77 | /* |
| @@ -105,6 +106,9 @@ struct mgr_priv_data { | |||
| 105 | 106 | ||
| 106 | struct omap_video_timings timings; | 107 | struct omap_video_timings timings; |
| 107 | struct dss_lcd_mgr_config lcd_config; | 108 | struct dss_lcd_mgr_config lcd_config; |
| 109 | |||
| 110 | void (*framedone_handler)(void *); | ||
| 111 | void *framedone_handler_data; | ||
| 108 | }; | 112 | }; |
| 109 | 113 | ||
| 110 | static struct { | 114 | static struct { |
| @@ -132,7 +136,7 @@ static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) | |||
| 132 | return &dss_data.mgr_priv_data_array[mgr->id]; | 136 | return &dss_data.mgr_priv_data_array[mgr->id]; |
| 133 | } | 137 | } |
| 134 | 138 | ||
| 135 | void dss_apply_init(void) | 139 | static void apply_init_priv(void) |
| 136 | { | 140 | { |
| 137 | const int num_ovls = dss_feat_get_num_ovls(); | 141 | const int num_ovls = dss_feat_get_num_ovls(); |
| 138 | struct mgr_priv_data *mp; | 142 | struct mgr_priv_data *mp; |
| @@ -414,11 +418,46 @@ static void wait_pending_extra_info_updates(void) | |||
| 414 | r = wait_for_completion_timeout(&extra_updated_completion, t); | 418 | r = wait_for_completion_timeout(&extra_updated_completion, t); |
| 415 | if (r == 0) | 419 | if (r == 0) |
| 416 | DSSWARN("timeout in wait_pending_extra_info_updates\n"); | 420 | DSSWARN("timeout in wait_pending_extra_info_updates\n"); |
| 417 | else if (r < 0) | ||
| 418 | DSSERR("wait_pending_extra_info_updates failed: %d\n", r); | ||
| 419 | } | 421 | } |
| 420 | 422 | ||
| 421 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | 423 | static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) |
| 424 | { | ||
| 425 | return ovl->manager ? | ||
| 426 | (ovl->manager->output ? ovl->manager->output->device : NULL) : | ||
| 427 | NULL; | ||
| 428 | } | ||
| 429 | |||
| 430 | static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) | ||
| 431 | { | ||
| 432 | return mgr->output ? mgr->output->device : NULL; | ||
| 433 | } | ||
| 434 | |||
| 435 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | ||
| 436 | { | ||
| 437 | unsigned long timeout = msecs_to_jiffies(500); | ||
| 438 | struct omap_dss_device *dssdev = mgr->get_device(mgr); | ||
| 439 | u32 irq; | ||
| 440 | int r; | ||
| 441 | |||
| 442 | r = dispc_runtime_get(); | ||
| 443 | if (r) | ||
| 444 | return r; | ||
| 445 | |||
| 446 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) | ||
| 447 | irq = DISPC_IRQ_EVSYNC_ODD; | ||
| 448 | else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) | ||
| 449 | irq = DISPC_IRQ_EVSYNC_EVEN; | ||
| 450 | else | ||
| 451 | irq = dispc_mgr_get_vsync_irq(mgr->id); | ||
| 452 | |||
| 453 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
| 454 | |||
| 455 | dispc_runtime_put(); | ||
| 456 | |||
| 457 | return r; | ||
| 458 | } | ||
| 459 | |||
| 460 | static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | ||
| 422 | { | 461 | { |
| 423 | unsigned long timeout = msecs_to_jiffies(500); | 462 | unsigned long timeout = msecs_to_jiffies(500); |
| 424 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 463 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
| @@ -488,7 +527,7 @@ int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | |||
| 488 | return r; | 527 | return r; |
| 489 | } | 528 | } |
| 490 | 529 | ||
| 491 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | 530 | static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) |
| 492 | { | 531 | { |
| 493 | unsigned long timeout = msecs_to_jiffies(500); | 532 | unsigned long timeout = msecs_to_jiffies(500); |
| 494 | struct ovl_priv_data *op; | 533 | struct ovl_priv_data *op; |
| @@ -573,7 +612,7 @@ static void dss_ovl_write_regs(struct omap_overlay *ovl) | |||
| 573 | struct mgr_priv_data *mp; | 612 | struct mgr_priv_data *mp; |
| 574 | int r; | 613 | int r; |
| 575 | 614 | ||
| 576 | DSSDBGF("%d", ovl->id); | 615 | DSSDBG("writing ovl %d regs", ovl->id); |
| 577 | 616 | ||
| 578 | if (!op->enabled || !op->info_dirty) | 617 | if (!op->enabled || !op->info_dirty) |
| 579 | return; | 618 | return; |
| @@ -608,7 +647,7 @@ static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) | |||
| 608 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 647 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
| 609 | struct mgr_priv_data *mp; | 648 | struct mgr_priv_data *mp; |
| 610 | 649 | ||
| 611 | DSSDBGF("%d", ovl->id); | 650 | DSSDBG("writing ovl %d regs extra", ovl->id); |
| 612 | 651 | ||
| 613 | if (!op->extra_info_dirty) | 652 | if (!op->extra_info_dirty) |
| 614 | return; | 653 | return; |
| @@ -617,7 +656,6 @@ static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) | |||
| 617 | * disabled */ | 656 | * disabled */ |
| 618 | 657 | ||
| 619 | dispc_ovl_enable(ovl->id, op->enabled); | 658 | dispc_ovl_enable(ovl->id, op->enabled); |
| 620 | dispc_ovl_set_channel_out(ovl->id, op->channel); | ||
| 621 | dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); | 659 | dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); |
| 622 | 660 | ||
| 623 | mp = get_mgr_priv(ovl->manager); | 661 | mp = get_mgr_priv(ovl->manager); |
| @@ -632,7 +670,7 @@ static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) | |||
| 632 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 670 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
| 633 | struct omap_overlay *ovl; | 671 | struct omap_overlay *ovl; |
| 634 | 672 | ||
| 635 | DSSDBGF("%d", mgr->id); | 673 | DSSDBG("writing mgr %d regs", mgr->id); |
| 636 | 674 | ||
| 637 | if (!mp->enabled) | 675 | if (!mp->enabled) |
| 638 | return; | 676 | return; |
| @@ -658,7 +696,7 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) | |||
| 658 | { | 696 | { |
| 659 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 697 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
| 660 | 698 | ||
| 661 | DSSDBGF("%d", mgr->id); | 699 | DSSDBG("writing mgr %d regs extra", mgr->id); |
| 662 | 700 | ||
| 663 | if (!mp->extra_info_dirty) | 701 | if (!mp->extra_info_dirty) |
| 664 | return; | 702 | return; |
| @@ -666,22 +704,8 @@ static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) | |||
| 666 | dispc_mgr_set_timings(mgr->id, &mp->timings); | 704 | dispc_mgr_set_timings(mgr->id, &mp->timings); |
| 667 | 705 | ||
| 668 | /* lcd_config parameters */ | 706 | /* lcd_config parameters */ |
| 669 | if (dss_mgr_is_lcd(mgr->id)) { | 707 | if (dss_mgr_is_lcd(mgr->id)) |
| 670 | dispc_mgr_set_io_pad_mode(mp->lcd_config.io_pad_mode); | 708 | dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config); |
| 671 | |||
| 672 | dispc_mgr_enable_stallmode(mgr->id, mp->lcd_config.stallmode); | ||
| 673 | dispc_mgr_enable_fifohandcheck(mgr->id, | ||
| 674 | mp->lcd_config.fifohandcheck); | ||
| 675 | |||
| 676 | dispc_mgr_set_clock_div(mgr->id, &mp->lcd_config.clock_info); | ||
| 677 | |||
| 678 | dispc_mgr_set_tft_data_lines(mgr->id, | ||
| 679 | mp->lcd_config.video_port_width); | ||
| 680 | |||
| 681 | dispc_lcd_enable_signal_polarity(mp->lcd_config.lcden_sig_polarity); | ||
| 682 | |||
| 683 | dispc_mgr_set_lcd_type_tft(mgr->id); | ||
| 684 | } | ||
| 685 | 709 | ||
| 686 | mp->extra_info_dirty = false; | 710 | mp->extra_info_dirty = false; |
| 687 | if (mp->updating) | 711 | if (mp->updating) |
| @@ -761,7 +785,7 @@ static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) | |||
| 761 | } | 785 | } |
| 762 | } | 786 | } |
| 763 | 787 | ||
| 764 | void dss_mgr_start_update(struct omap_overlay_manager *mgr) | 788 | static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr) |
| 765 | { | 789 | { |
| 766 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 790 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
| 767 | unsigned long flags; | 791 | unsigned long flags; |
| @@ -786,9 +810,7 @@ void dss_mgr_start_update(struct omap_overlay_manager *mgr) | |||
| 786 | if (!dss_data.irq_enabled && need_isr()) | 810 | if (!dss_data.irq_enabled && need_isr()) |
| 787 | dss_register_vsync_isr(); | 811 | dss_register_vsync_isr(); |
| 788 | 812 | ||
| 789 | dispc_mgr_enable(mgr->id, true); | 813 | dispc_mgr_enable_sync(mgr->id); |
| 790 | |||
| 791 | mgr_clear_shadow_dirty(mgr); | ||
| 792 | 814 | ||
| 793 | spin_unlock_irqrestore(&data_lock, flags); | 815 | spin_unlock_irqrestore(&data_lock, flags); |
| 794 | } | 816 | } |
| @@ -845,7 +867,6 @@ static void dss_apply_irq_handler(void *data, u32 mask) | |||
| 845 | for (i = 0; i < num_mgrs; i++) { | 867 | for (i = 0; i < num_mgrs; i++) { |
| 846 | struct omap_overlay_manager *mgr; | 868 | struct omap_overlay_manager *mgr; |
| 847 | struct mgr_priv_data *mp; | 869 | struct mgr_priv_data *mp; |
| 848 | bool was_updating; | ||
| 849 | 870 | ||
| 850 | mgr = omap_dss_get_overlay_manager(i); | 871 | mgr = omap_dss_get_overlay_manager(i); |
| 851 | mp = get_mgr_priv(mgr); | 872 | mp = get_mgr_priv(mgr); |
| @@ -853,7 +874,6 @@ static void dss_apply_irq_handler(void *data, u32 mask) | |||
| 853 | if (!mp->enabled) | 874 | if (!mp->enabled) |
| 854 | continue; | 875 | continue; |
| 855 | 876 | ||
| 856 | was_updating = mp->updating; | ||
| 857 | mp->updating = dispc_mgr_is_enabled(i); | 877 | mp->updating = dispc_mgr_is_enabled(i); |
| 858 | 878 | ||
| 859 | if (!mgr_manual_update(mgr)) { | 879 | if (!mgr_manual_update(mgr)) { |
| @@ -872,6 +892,21 @@ static void dss_apply_irq_handler(void *data, u32 mask) | |||
| 872 | if (!extra_updating) | 892 | if (!extra_updating) |
| 873 | complete_all(&extra_updated_completion); | 893 | complete_all(&extra_updated_completion); |
| 874 | 894 | ||
| 895 | /* call framedone handlers for manual update displays */ | ||
| 896 | for (i = 0; i < num_mgrs; i++) { | ||
| 897 | struct omap_overlay_manager *mgr; | ||
| 898 | struct mgr_priv_data *mp; | ||
| 899 | |||
| 900 | mgr = omap_dss_get_overlay_manager(i); | ||
| 901 | mp = get_mgr_priv(mgr); | ||
| 902 | |||
| 903 | if (!mgr_manual_update(mgr) || !mp->framedone_handler) | ||
| 904 | continue; | ||
| 905 | |||
| 906 | if (mask & dispc_mgr_get_framedone_irq(i)) | ||
| 907 | mp->framedone_handler(mp->framedone_handler_data); | ||
| 908 | } | ||
| 909 | |||
| 875 | if (!need_isr()) | 910 | if (!need_isr()) |
| 876 | dss_unregister_vsync_isr(); | 911 | dss_unregister_vsync_isr(); |
| 877 | 912 | ||
| @@ -906,7 +941,7 @@ static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) | |||
| 906 | mp->info = mp->user_info; | 941 | mp->info = mp->user_info; |
| 907 | } | 942 | } |
| 908 | 943 | ||
| 909 | int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) | 944 | static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) |
| 910 | { | 945 | { |
| 911 | unsigned long flags; | 946 | unsigned long flags; |
| 912 | struct omap_overlay *ovl; | 947 | struct omap_overlay *ovl; |
| @@ -1005,7 +1040,7 @@ static void dss_setup_fifos(void) | |||
| 1005 | } | 1040 | } |
| 1006 | } | 1041 | } |
| 1007 | 1042 | ||
| 1008 | int dss_mgr_enable(struct omap_overlay_manager *mgr) | 1043 | static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr) |
| 1009 | { | 1044 | { |
| 1010 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1045 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
| 1011 | unsigned long flags; | 1046 | unsigned long flags; |
| @@ -1035,10 +1070,13 @@ int dss_mgr_enable(struct omap_overlay_manager *mgr) | |||
| 1035 | if (!mgr_manual_update(mgr)) | 1070 | if (!mgr_manual_update(mgr)) |
| 1036 | mp->updating = true; | 1071 | mp->updating = true; |
| 1037 | 1072 | ||
| 1073 | if (!dss_data.irq_enabled && need_isr()) | ||
| 1074 | dss_register_vsync_isr(); | ||
| 1075 | |||
| 1038 | spin_unlock_irqrestore(&data_lock, flags); | 1076 | spin_unlock_irqrestore(&data_lock, flags); |
| 1039 | 1077 | ||
| 1040 | if (!mgr_manual_update(mgr)) | 1078 | if (!mgr_manual_update(mgr)) |
| 1041 | dispc_mgr_enable(mgr->id, true); | 1079 | dispc_mgr_enable_sync(mgr->id); |
| 1042 | 1080 | ||
| 1043 | out: | 1081 | out: |
| 1044 | mutex_unlock(&apply_lock); | 1082 | mutex_unlock(&apply_lock); |
| @@ -1052,7 +1090,7 @@ err: | |||
| 1052 | return r; | 1090 | return r; |
| 1053 | } | 1091 | } |
| 1054 | 1092 | ||
| 1055 | void dss_mgr_disable(struct omap_overlay_manager *mgr) | 1093 | static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr) |
| 1056 | { | 1094 | { |
| 1057 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1095 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
| 1058 | unsigned long flags; | 1096 | unsigned long flags; |
| @@ -1063,7 +1101,7 @@ void dss_mgr_disable(struct omap_overlay_manager *mgr) | |||
| 1063 | goto out; | 1101 | goto out; |
| 1064 | 1102 | ||
| 1065 | if (!mgr_manual_update(mgr)) | 1103 | if (!mgr_manual_update(mgr)) |
| 1066 | dispc_mgr_enable(mgr->id, false); | 1104 | dispc_mgr_disable_sync(mgr->id); |
| 1067 | 1105 | ||
| 1068 | spin_lock_irqsave(&data_lock, flags); | 1106 | spin_lock_irqsave(&data_lock, flags); |
| 1069 | 1107 | ||
| @@ -1076,7 +1114,7 @@ out: | |||
| 1076 | mutex_unlock(&apply_lock); | 1114 | mutex_unlock(&apply_lock); |
| 1077 | } | 1115 | } |
| 1078 | 1116 | ||
| 1079 | int dss_mgr_set_info(struct omap_overlay_manager *mgr, | 1117 | static int dss_mgr_set_info(struct omap_overlay_manager *mgr, |
| 1080 | struct omap_overlay_manager_info *info) | 1118 | struct omap_overlay_manager_info *info) |
| 1081 | { | 1119 | { |
| 1082 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1120 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
| @@ -1097,7 +1135,7 @@ int dss_mgr_set_info(struct omap_overlay_manager *mgr, | |||
| 1097 | return 0; | 1135 | return 0; |
| 1098 | } | 1136 | } |
| 1099 | 1137 | ||
| 1100 | void dss_mgr_get_info(struct omap_overlay_manager *mgr, | 1138 | static void dss_mgr_get_info(struct omap_overlay_manager *mgr, |
| 1101 | struct omap_overlay_manager_info *info) | 1139 | struct omap_overlay_manager_info *info) |
| 1102 | { | 1140 | { |
| 1103 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1141 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
| @@ -1110,7 +1148,7 @@ void dss_mgr_get_info(struct omap_overlay_manager *mgr, | |||
| 1110 | spin_unlock_irqrestore(&data_lock, flags); | 1148 | spin_unlock_irqrestore(&data_lock, flags); |
| 1111 | } | 1149 | } |
| 1112 | 1150 | ||
| 1113 | int dss_mgr_set_output(struct omap_overlay_manager *mgr, | 1151 | static int dss_mgr_set_output(struct omap_overlay_manager *mgr, |
| 1114 | struct omap_dss_output *output) | 1152 | struct omap_dss_output *output) |
| 1115 | { | 1153 | { |
| 1116 | int r; | 1154 | int r; |
| @@ -1142,7 +1180,7 @@ err: | |||
| 1142 | return r; | 1180 | return r; |
| 1143 | } | 1181 | } |
| 1144 | 1182 | ||
| 1145 | int dss_mgr_unset_output(struct omap_overlay_manager *mgr) | 1183 | static int dss_mgr_unset_output(struct omap_overlay_manager *mgr) |
| 1146 | { | 1184 | { |
| 1147 | int r; | 1185 | int r; |
| 1148 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | 1186 | struct mgr_priv_data *mp = get_mgr_priv(mgr); |
| @@ -1189,7 +1227,7 @@ static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, | |||
| 1189 | mp->extra_info_dirty = true; | 1227 | mp->extra_info_dirty = true; |
| 1190 | } | 1228 | } |
| 1191 | 1229 | ||
| 1192 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, | 1230 | static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr, |
| 1193 | const struct omap_video_timings *timings) | 1231 | const struct omap_video_timings *timings) |
| 1194 | { | 1232 | { |
| 1195 | unsigned long flags; | 1233 | unsigned long flags; |
| @@ -1217,7 +1255,7 @@ static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, | |||
| 1217 | mp->extra_info_dirty = true; | 1255 | mp->extra_info_dirty = true; |
| 1218 | } | 1256 | } |
| 1219 | 1257 | ||
| 1220 | void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, | 1258 | static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr, |
| 1221 | const struct dss_lcd_mgr_config *config) | 1259 | const struct dss_lcd_mgr_config *config) |
| 1222 | { | 1260 | { |
| 1223 | unsigned long flags; | 1261 | unsigned long flags; |
| @@ -1236,7 +1274,7 @@ out: | |||
| 1236 | spin_unlock_irqrestore(&data_lock, flags); | 1274 | spin_unlock_irqrestore(&data_lock, flags); |
| 1237 | } | 1275 | } |
| 1238 | 1276 | ||
| 1239 | int dss_ovl_set_info(struct omap_overlay *ovl, | 1277 | static int dss_ovl_set_info(struct omap_overlay *ovl, |
| 1240 | struct omap_overlay_info *info) | 1278 | struct omap_overlay_info *info) |
| 1241 | { | 1279 | { |
| 1242 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1280 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
| @@ -1257,7 +1295,7 @@ int dss_ovl_set_info(struct omap_overlay *ovl, | |||
| 1257 | return 0; | 1295 | return 0; |
| 1258 | } | 1296 | } |
| 1259 | 1297 | ||
| 1260 | void dss_ovl_get_info(struct omap_overlay *ovl, | 1298 | static void dss_ovl_get_info(struct omap_overlay *ovl, |
| 1261 | struct omap_overlay_info *info) | 1299 | struct omap_overlay_info *info) |
| 1262 | { | 1300 | { |
| 1263 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1301 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
| @@ -1270,7 +1308,7 @@ void dss_ovl_get_info(struct omap_overlay *ovl, | |||
| 1270 | spin_unlock_irqrestore(&data_lock, flags); | 1308 | spin_unlock_irqrestore(&data_lock, flags); |
| 1271 | } | 1309 | } |
| 1272 | 1310 | ||
| 1273 | int dss_ovl_set_manager(struct omap_overlay *ovl, | 1311 | static int dss_ovl_set_manager(struct omap_overlay *ovl, |
| 1274 | struct omap_overlay_manager *mgr) | 1312 | struct omap_overlay_manager *mgr) |
| 1275 | { | 1313 | { |
| 1276 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1314 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
| @@ -1289,45 +1327,40 @@ int dss_ovl_set_manager(struct omap_overlay *ovl, | |||
| 1289 | goto err; | 1327 | goto err; |
| 1290 | } | 1328 | } |
| 1291 | 1329 | ||
| 1330 | r = dispc_runtime_get(); | ||
| 1331 | if (r) | ||
| 1332 | goto err; | ||
| 1333 | |||
| 1292 | spin_lock_irqsave(&data_lock, flags); | 1334 | spin_lock_irqsave(&data_lock, flags); |
| 1293 | 1335 | ||
| 1294 | if (op->enabled) { | 1336 | if (op->enabled) { |
| 1295 | spin_unlock_irqrestore(&data_lock, flags); | 1337 | spin_unlock_irqrestore(&data_lock, flags); |
| 1296 | DSSERR("overlay has to be disabled to change the manager\n"); | 1338 | DSSERR("overlay has to be disabled to change the manager\n"); |
| 1297 | r = -EINVAL; | 1339 | r = -EINVAL; |
| 1298 | goto err; | 1340 | goto err1; |
| 1299 | } | 1341 | } |
| 1300 | 1342 | ||
| 1301 | op->channel = mgr->id; | 1343 | dispc_ovl_set_channel_out(ovl->id, mgr->id); |
| 1302 | op->extra_info_dirty = true; | ||
| 1303 | 1344 | ||
| 1304 | ovl->manager = mgr; | 1345 | ovl->manager = mgr; |
| 1305 | list_add_tail(&ovl->list, &mgr->overlays); | 1346 | list_add_tail(&ovl->list, &mgr->overlays); |
| 1306 | 1347 | ||
| 1307 | spin_unlock_irqrestore(&data_lock, flags); | 1348 | spin_unlock_irqrestore(&data_lock, flags); |
| 1308 | 1349 | ||
| 1309 | /* XXX: When there is an overlay on a DSI manual update display, and | 1350 | dispc_runtime_put(); |
| 1310 | * the overlay is first disabled, then moved to tv, and enabled, we | ||
| 1311 | * seem to get SYNC_LOST_DIGIT error. | ||
| 1312 | * | ||
| 1313 | * Waiting doesn't seem to help, but updating the manual update display | ||
| 1314 | * after disabling the overlay seems to fix this. This hints that the | ||
| 1315 | * overlay is perhaps somehow tied to the LCD output until the output | ||
| 1316 | * is updated. | ||
| 1317 | * | ||
| 1318 | * Userspace workaround for this is to update the LCD after disabling | ||
| 1319 | * the overlay, but before moving the overlay to TV. | ||
| 1320 | */ | ||
| 1321 | 1351 | ||
| 1322 | mutex_unlock(&apply_lock); | 1352 | mutex_unlock(&apply_lock); |
| 1323 | 1353 | ||
| 1324 | return 0; | 1354 | return 0; |
| 1355 | |||
| 1356 | err1: | ||
| 1357 | dispc_runtime_put(); | ||
| 1325 | err: | 1358 | err: |
| 1326 | mutex_unlock(&apply_lock); | 1359 | mutex_unlock(&apply_lock); |
| 1327 | return r; | 1360 | return r; |
| 1328 | } | 1361 | } |
| 1329 | 1362 | ||
| 1330 | int dss_ovl_unset_manager(struct omap_overlay *ovl) | 1363 | static int dss_ovl_unset_manager(struct omap_overlay *ovl) |
| 1331 | { | 1364 | { |
| 1332 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1365 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
| 1333 | unsigned long flags; | 1366 | unsigned long flags; |
| @@ -1355,9 +1388,24 @@ int dss_ovl_unset_manager(struct omap_overlay *ovl) | |||
| 1355 | /* wait for pending extra_info updates to ensure the ovl is disabled */ | 1388 | /* wait for pending extra_info updates to ensure the ovl is disabled */ |
| 1356 | wait_pending_extra_info_updates(); | 1389 | wait_pending_extra_info_updates(); |
| 1357 | 1390 | ||
| 1391 | /* | ||
| 1392 | * For a manual update display, there is no guarantee that the overlay | ||
| 1393 | * is really disabled in HW, we may need an extra update from this | ||
| 1394 | * manager before the configurations can go in. Return an error if the | ||
| 1395 | * overlay needed an update from the manager. | ||
| 1396 | * | ||
| 1397 | * TODO: Instead of returning an error, try to do a dummy manager update | ||
| 1398 | * here to disable the overlay in hardware. Use the *GATED fields in | ||
| 1399 | * the DISPC_CONFIG registers to do a dummy update. | ||
| 1400 | */ | ||
| 1358 | spin_lock_irqsave(&data_lock, flags); | 1401 | spin_lock_irqsave(&data_lock, flags); |
| 1359 | 1402 | ||
| 1360 | op->channel = -1; | 1403 | if (ovl_manual_update(ovl) && op->extra_info_dirty) { |
| 1404 | spin_unlock_irqrestore(&data_lock, flags); | ||
| 1405 | DSSERR("need an update to change the manager\n"); | ||
| 1406 | r = -EINVAL; | ||
| 1407 | goto err; | ||
| 1408 | } | ||
| 1361 | 1409 | ||
| 1362 | ovl->manager = NULL; | 1410 | ovl->manager = NULL; |
| 1363 | list_del(&ovl->list); | 1411 | list_del(&ovl->list); |
| @@ -1372,7 +1420,7 @@ err: | |||
| 1372 | return r; | 1420 | return r; |
| 1373 | } | 1421 | } |
| 1374 | 1422 | ||
| 1375 | bool dss_ovl_is_enabled(struct omap_overlay *ovl) | 1423 | static bool dss_ovl_is_enabled(struct omap_overlay *ovl) |
| 1376 | { | 1424 | { |
| 1377 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1425 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
| 1378 | unsigned long flags; | 1426 | unsigned long flags; |
| @@ -1387,7 +1435,7 @@ bool dss_ovl_is_enabled(struct omap_overlay *ovl) | |||
| 1387 | return e; | 1435 | return e; |
| 1388 | } | 1436 | } |
| 1389 | 1437 | ||
| 1390 | int dss_ovl_enable(struct omap_overlay *ovl) | 1438 | static int dss_ovl_enable(struct omap_overlay *ovl) |
| 1391 | { | 1439 | { |
| 1392 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1440 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
| 1393 | unsigned long flags; | 1441 | unsigned long flags; |
| @@ -1437,7 +1485,7 @@ err1: | |||
| 1437 | return r; | 1485 | return r; |
| 1438 | } | 1486 | } |
| 1439 | 1487 | ||
| 1440 | int dss_ovl_disable(struct omap_overlay *ovl) | 1488 | static int dss_ovl_disable(struct omap_overlay *ovl) |
| 1441 | { | 1489 | { |
| 1442 | struct ovl_priv_data *op = get_ovl_priv(ovl); | 1490 | struct ovl_priv_data *op = get_ovl_priv(ovl); |
| 1443 | unsigned long flags; | 1491 | unsigned long flags; |
| @@ -1472,3 +1520,152 @@ err: | |||
| 1472 | return r; | 1520 | return r; |
| 1473 | } | 1521 | } |
| 1474 | 1522 | ||
| 1523 | static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr, | ||
| 1524 | void (*handler)(void *), void *data) | ||
| 1525 | { | ||
| 1526 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
| 1527 | |||
| 1528 | if (mp->framedone_handler) | ||
| 1529 | return -EBUSY; | ||
| 1530 | |||
| 1531 | mp->framedone_handler = handler; | ||
| 1532 | mp->framedone_handler_data = data; | ||
| 1533 | |||
| 1534 | return 0; | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr, | ||
| 1538 | void (*handler)(void *), void *data) | ||
| 1539 | { | ||
| 1540 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
| 1541 | |||
| 1542 | WARN_ON(mp->framedone_handler != handler || | ||
| 1543 | mp->framedone_handler_data != data); | ||
| 1544 | |||
| 1545 | mp->framedone_handler = NULL; | ||
| 1546 | mp->framedone_handler_data = NULL; | ||
| 1547 | } | ||
| 1548 | |||
| 1549 | static const struct dss_mgr_ops apply_mgr_ops = { | ||
| 1550 | .start_update = dss_mgr_start_update_compat, | ||
| 1551 | .enable = dss_mgr_enable_compat, | ||
| 1552 | .disable = dss_mgr_disable_compat, | ||
| 1553 | .set_timings = dss_mgr_set_timings_compat, | ||
| 1554 | .set_lcd_config = dss_mgr_set_lcd_config_compat, | ||
| 1555 | .register_framedone_handler = dss_mgr_register_framedone_handler_compat, | ||
| 1556 | .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat, | ||
| 1557 | }; | ||
| 1558 | |||
| 1559 | static int compat_refcnt; | ||
| 1560 | static DEFINE_MUTEX(compat_init_lock); | ||
| 1561 | |||
| 1562 | int omapdss_compat_init(void) | ||
| 1563 | { | ||
| 1564 | struct platform_device *pdev = dss_get_core_pdev(); | ||
| 1565 | struct omap_dss_device *dssdev = NULL; | ||
| 1566 | int i, r; | ||
| 1567 | |||
| 1568 | mutex_lock(&compat_init_lock); | ||
| 1569 | |||
| 1570 | if (compat_refcnt++ > 0) | ||
| 1571 | goto out; | ||
| 1572 | |||
| 1573 | apply_init_priv(); | ||
| 1574 | |||
| 1575 | dss_init_overlay_managers(pdev); | ||
| 1576 | dss_init_overlays(pdev); | ||
| 1577 | |||
| 1578 | for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { | ||
| 1579 | struct omap_overlay_manager *mgr; | ||
| 1580 | |||
| 1581 | mgr = omap_dss_get_overlay_manager(i); | ||
| 1582 | |||
| 1583 | mgr->set_output = &dss_mgr_set_output; | ||
| 1584 | mgr->unset_output = &dss_mgr_unset_output; | ||
| 1585 | mgr->apply = &omap_dss_mgr_apply; | ||
| 1586 | mgr->set_manager_info = &dss_mgr_set_info; | ||
| 1587 | mgr->get_manager_info = &dss_mgr_get_info; | ||
| 1588 | mgr->wait_for_go = &dss_mgr_wait_for_go; | ||
| 1589 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; | ||
| 1590 | mgr->get_device = &dss_mgr_get_device; | ||
| 1591 | } | ||
| 1592 | |||
| 1593 | for (i = 0; i < omap_dss_get_num_overlays(); i++) { | ||
| 1594 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
| 1595 | |||
| 1596 | ovl->is_enabled = &dss_ovl_is_enabled; | ||
| 1597 | ovl->enable = &dss_ovl_enable; | ||
| 1598 | ovl->disable = &dss_ovl_disable; | ||
| 1599 | ovl->set_manager = &dss_ovl_set_manager; | ||
| 1600 | ovl->unset_manager = &dss_ovl_unset_manager; | ||
| 1601 | ovl->set_overlay_info = &dss_ovl_set_info; | ||
| 1602 | ovl->get_overlay_info = &dss_ovl_get_info; | ||
| 1603 | ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; | ||
| 1604 | ovl->get_device = &dss_ovl_get_device; | ||
| 1605 | } | ||
| 1606 | |||
| 1607 | r = dss_install_mgr_ops(&apply_mgr_ops); | ||
| 1608 | if (r) | ||
| 1609 | goto err_mgr_ops; | ||
| 1610 | |||
| 1611 | for_each_dss_dev(dssdev) { | ||
| 1612 | r = display_init_sysfs(pdev, dssdev); | ||
| 1613 | /* XXX uninit sysfs files on error */ | ||
| 1614 | if (r) | ||
| 1615 | goto err_disp_sysfs; | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | dispc_runtime_get(); | ||
| 1619 | |||
| 1620 | r = dss_dispc_initialize_irq(); | ||
| 1621 | if (r) | ||
| 1622 | goto err_init_irq; | ||
| 1623 | |||
| 1624 | dispc_runtime_put(); | ||
| 1625 | |||
| 1626 | out: | ||
| 1627 | mutex_unlock(&compat_init_lock); | ||
| 1628 | |||
| 1629 | return 0; | ||
| 1630 | |||
| 1631 | err_init_irq: | ||
| 1632 | dispc_runtime_put(); | ||
| 1633 | |||
| 1634 | err_disp_sysfs: | ||
| 1635 | dss_uninstall_mgr_ops(); | ||
| 1636 | |||
| 1637 | err_mgr_ops: | ||
| 1638 | dss_uninit_overlay_managers(pdev); | ||
| 1639 | dss_uninit_overlays(pdev); | ||
| 1640 | |||
| 1641 | compat_refcnt--; | ||
| 1642 | |||
| 1643 | mutex_unlock(&compat_init_lock); | ||
| 1644 | |||
| 1645 | return r; | ||
| 1646 | } | ||
| 1647 | EXPORT_SYMBOL(omapdss_compat_init); | ||
| 1648 | |||
| 1649 | void omapdss_compat_uninit(void) | ||
| 1650 | { | ||
| 1651 | struct platform_device *pdev = dss_get_core_pdev(); | ||
| 1652 | struct omap_dss_device *dssdev = NULL; | ||
| 1653 | |||
| 1654 | mutex_lock(&compat_init_lock); | ||
| 1655 | |||
| 1656 | if (--compat_refcnt > 0) | ||
| 1657 | goto out; | ||
| 1658 | |||
| 1659 | dss_dispc_uninitialize_irq(); | ||
| 1660 | |||
| 1661 | for_each_dss_dev(dssdev) | ||
| 1662 | display_uninit_sysfs(pdev, dssdev); | ||
| 1663 | |||
| 1664 | dss_uninstall_mgr_ops(); | ||
| 1665 | |||
| 1666 | dss_uninit_overlay_managers(pdev); | ||
| 1667 | dss_uninit_overlays(pdev); | ||
| 1668 | out: | ||
| 1669 | mutex_unlock(&compat_init_lock); | ||
| 1670 | } | ||
| 1671 | EXPORT_SYMBOL(omapdss_compat_uninit); | ||
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index d94ef9e31a35..f8779d4750ba 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c | |||
| @@ -53,15 +53,23 @@ static char *def_disp_name; | |||
| 53 | module_param_named(def_disp, def_disp_name, charp, 0); | 53 | module_param_named(def_disp, def_disp_name, charp, 0); |
| 54 | MODULE_PARM_DESC(def_disp, "default display name"); | 54 | MODULE_PARM_DESC(def_disp, "default display name"); |
| 55 | 55 | ||
| 56 | #ifdef DEBUG | 56 | const char *omapdss_get_default_display_name(void) |
| 57 | bool dss_debug; | ||
| 58 | module_param_named(debug, dss_debug, bool, 0644); | ||
| 59 | #endif | ||
| 60 | |||
| 61 | const char *dss_get_default_display_name(void) | ||
| 62 | { | 57 | { |
| 63 | return core.default_display_name; | 58 | return core.default_display_name; |
| 64 | } | 59 | } |
| 60 | EXPORT_SYMBOL(omapdss_get_default_display_name); | ||
| 61 | |||
| 62 | enum omapdss_version omapdss_get_version(void) | ||
| 63 | { | ||
| 64 | struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; | ||
| 65 | return pdata->version; | ||
| 66 | } | ||
| 67 | EXPORT_SYMBOL(omapdss_get_version); | ||
| 68 | |||
| 69 | struct platform_device *dss_get_core_pdev(void) | ||
| 70 | { | ||
| 71 | return core.pdev; | ||
| 72 | } | ||
| 65 | 73 | ||
| 66 | /* REGULATORS */ | 74 | /* REGULATORS */ |
| 67 | 75 | ||
| @@ -93,21 +101,6 @@ struct regulator *dss_get_vdds_sdi(void) | |||
| 93 | return reg; | 101 | return reg; |
| 94 | } | 102 | } |
| 95 | 103 | ||
| 96 | int dss_get_ctx_loss_count(struct device *dev) | ||
| 97 | { | ||
| 98 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; | ||
| 99 | int cnt; | ||
| 100 | |||
| 101 | if (!board_data->get_context_loss_count) | ||
| 102 | return -ENOENT; | ||
| 103 | |||
| 104 | cnt = board_data->get_context_loss_count(dev); | ||
| 105 | |||
| 106 | WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); | ||
| 107 | |||
| 108 | return cnt; | ||
| 109 | } | ||
| 110 | |||
| 111 | int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask) | 104 | int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask) |
| 112 | { | 105 | { |
| 113 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; | 106 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; |
| @@ -122,7 +115,7 @@ void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask) | |||
| 122 | { | 115 | { |
| 123 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; | 116 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; |
| 124 | 117 | ||
| 125 | if (!board_data->dsi_enable_pads) | 118 | if (!board_data->dsi_disable_pads) |
| 126 | return; | 119 | return; |
| 127 | 120 | ||
| 128 | return board_data->dsi_disable_pads(dsi_id, lane_mask); | 121 | return board_data->dsi_disable_pads(dsi_id, lane_mask); |
| @@ -138,7 +131,7 @@ int dss_set_min_bus_tput(struct device *dev, unsigned long tput) | |||
| 138 | return 0; | 131 | return 0; |
| 139 | } | 132 | } |
| 140 | 133 | ||
| 141 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) | 134 | #if defined(CONFIG_OMAP2_DSS_DEBUGFS) |
| 142 | static int dss_debug_show(struct seq_file *s, void *unused) | 135 | static int dss_debug_show(struct seq_file *s, void *unused) |
| 143 | { | 136 | { |
| 144 | void (*func)(struct seq_file *) = s->private; | 137 | void (*func)(struct seq_file *) = s->private; |
| @@ -193,7 +186,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) | |||
| 193 | 186 | ||
| 194 | return 0; | 187 | return 0; |
| 195 | } | 188 | } |
| 196 | #else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ | 189 | #else /* CONFIG_OMAP2_DSS_DEBUGFS */ |
| 197 | static inline int dss_initialize_debugfs(void) | 190 | static inline int dss_initialize_debugfs(void) |
| 198 | { | 191 | { |
| 199 | return 0; | 192 | return 0; |
| @@ -205,7 +198,7 @@ int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) | |||
| 205 | { | 198 | { |
| 206 | return 0; | 199 | return 0; |
| 207 | } | 200 | } |
| 208 | #endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ | 201 | #endif /* CONFIG_OMAP2_DSS_DEBUGFS */ |
| 209 | 202 | ||
| 210 | /* PLATFORM DEVICE */ | 203 | /* PLATFORM DEVICE */ |
| 211 | static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) | 204 | static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) |
| @@ -237,12 +230,7 @@ static int __init omap_dss_probe(struct platform_device *pdev) | |||
| 237 | 230 | ||
| 238 | core.pdev = pdev; | 231 | core.pdev = pdev; |
| 239 | 232 | ||
| 240 | dss_features_init(pdata->version); | 233 | dss_features_init(omapdss_get_version()); |
| 241 | |||
| 242 | dss_apply_init(); | ||
| 243 | |||
| 244 | dss_init_overlay_managers(pdev); | ||
| 245 | dss_init_overlays(pdev); | ||
| 246 | 234 | ||
| 247 | r = dss_initialize_debugfs(); | 235 | r = dss_initialize_debugfs(); |
| 248 | if (r) | 236 | if (r) |
| @@ -268,9 +256,6 @@ static int omap_dss_remove(struct platform_device *pdev) | |||
| 268 | 256 | ||
| 269 | dss_uninitialize_debugfs(); | 257 | dss_uninitialize_debugfs(); |
| 270 | 258 | ||
| 271 | dss_uninit_overlays(pdev); | ||
| 272 | dss_uninit_overlay_managers(pdev); | ||
| 273 | |||
| 274 | return 0; | 259 | return 0; |
| 275 | } | 260 | } |
| 276 | 261 | ||
| @@ -358,15 +343,10 @@ static int dss_driver_probe(struct device *dev) | |||
| 358 | dev_name(dev), dssdev->driver_name, | 343 | dev_name(dev), dssdev->driver_name, |
| 359 | dssdrv->driver.name); | 344 | dssdrv->driver.name); |
| 360 | 345 | ||
| 361 | r = dss_init_device(core.pdev, dssdev); | ||
| 362 | if (r) | ||
| 363 | return r; | ||
| 364 | |||
| 365 | r = dssdrv->probe(dssdev); | 346 | r = dssdrv->probe(dssdev); |
| 366 | 347 | ||
| 367 | if (r) { | 348 | if (r) { |
| 368 | DSSERR("driver probe failed: %d\n", r); | 349 | DSSERR("driver probe failed: %d\n", r); |
| 369 | dss_uninit_device(core.pdev, dssdev); | ||
| 370 | return r; | 350 | return r; |
| 371 | } | 351 | } |
| 372 | 352 | ||
| @@ -387,8 +367,6 @@ static int dss_driver_remove(struct device *dev) | |||
| 387 | 367 | ||
| 388 | dssdrv->remove(dssdev); | 368 | dssdrv->remove(dssdev); |
| 389 | 369 | ||
| 390 | dss_uninit_device(core.pdev, dssdev); | ||
| 391 | |||
| 392 | dssdev->driver = NULL; | 370 | dssdev->driver = NULL; |
| 393 | 371 | ||
| 394 | return 0; | 372 | return 0; |
| @@ -507,6 +485,9 @@ static int __init omap_dss_bus_register(void) | |||
| 507 | 485 | ||
| 508 | /* INIT */ | 486 | /* INIT */ |
| 509 | static int (*dss_output_drv_reg_funcs[])(void) __initdata = { | 487 | static int (*dss_output_drv_reg_funcs[])(void) __initdata = { |
| 488 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
| 489 | dsi_init_platform_driver, | ||
| 490 | #endif | ||
| 510 | #ifdef CONFIG_OMAP2_DSS_DPI | 491 | #ifdef CONFIG_OMAP2_DSS_DPI |
| 511 | dpi_init_platform_driver, | 492 | dpi_init_platform_driver, |
| 512 | #endif | 493 | #endif |
| @@ -519,15 +500,15 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = { | |||
| 519 | #ifdef CONFIG_OMAP2_DSS_VENC | 500 | #ifdef CONFIG_OMAP2_DSS_VENC |
| 520 | venc_init_platform_driver, | 501 | venc_init_platform_driver, |
| 521 | #endif | 502 | #endif |
| 522 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
| 523 | dsi_init_platform_driver, | ||
| 524 | #endif | ||
| 525 | #ifdef CONFIG_OMAP4_DSS_HDMI | 503 | #ifdef CONFIG_OMAP4_DSS_HDMI |
| 526 | hdmi_init_platform_driver, | 504 | hdmi_init_platform_driver, |
| 527 | #endif | 505 | #endif |
| 528 | }; | 506 | }; |
| 529 | 507 | ||
| 530 | static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { | 508 | static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { |
| 509 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
| 510 | dsi_uninit_platform_driver, | ||
| 511 | #endif | ||
| 531 | #ifdef CONFIG_OMAP2_DSS_DPI | 512 | #ifdef CONFIG_OMAP2_DSS_DPI |
| 532 | dpi_uninit_platform_driver, | 513 | dpi_uninit_platform_driver, |
| 533 | #endif | 514 | #endif |
| @@ -540,9 +521,6 @@ static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { | |||
| 540 | #ifdef CONFIG_OMAP2_DSS_VENC | 521 | #ifdef CONFIG_OMAP2_DSS_VENC |
| 541 | venc_uninit_platform_driver, | 522 | venc_uninit_platform_driver, |
| 542 | #endif | 523 | #endif |
| 543 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
| 544 | dsi_uninit_platform_driver, | ||
| 545 | #endif | ||
| 546 | #ifdef CONFIG_OMAP4_DSS_HDMI | 524 | #ifdef CONFIG_OMAP4_DSS_HDMI |
| 547 | hdmi_uninit_platform_driver, | 525 | hdmi_uninit_platform_driver, |
| 548 | #endif | 526 | #endif |
diff --git a/drivers/video/omap2/dss/dispc-compat.c b/drivers/video/omap2/dss/dispc-compat.c new file mode 100644 index 000000000000..928884c9a0a9 --- /dev/null +++ b/drivers/video/omap2/dss/dispc-compat.c | |||
| @@ -0,0 +1,667 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Texas Instruments | ||
| 3 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License along with | ||
| 15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #define DSS_SUBSYS_NAME "APPLY" | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/slab.h> | ||
| 23 | #include <linux/spinlock.h> | ||
| 24 | #include <linux/jiffies.h> | ||
| 25 | #include <linux/delay.h> | ||
| 26 | #include <linux/interrupt.h> | ||
| 27 | #include <linux/seq_file.h> | ||
| 28 | |||
| 29 | #include <video/omapdss.h> | ||
| 30 | |||
| 31 | #include "dss.h" | ||
| 32 | #include "dss_features.h" | ||
| 33 | #include "dispc-compat.h" | ||
| 34 | |||
| 35 | #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ | ||
| 36 | DISPC_IRQ_OCP_ERR | \ | ||
| 37 | DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ | ||
| 38 | DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ | ||
| 39 | DISPC_IRQ_SYNC_LOST | \ | ||
| 40 | DISPC_IRQ_SYNC_LOST_DIGIT) | ||
| 41 | |||
| 42 | #define DISPC_MAX_NR_ISRS 8 | ||
| 43 | |||
| 44 | struct omap_dispc_isr_data { | ||
| 45 | omap_dispc_isr_t isr; | ||
| 46 | void *arg; | ||
| 47 | u32 mask; | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct dispc_irq_stats { | ||
| 51 | unsigned long last_reset; | ||
| 52 | unsigned irq_count; | ||
| 53 | unsigned irqs[32]; | ||
| 54 | }; | ||
| 55 | |||
| 56 | static struct { | ||
| 57 | spinlock_t irq_lock; | ||
| 58 | u32 irq_error_mask; | ||
| 59 | struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; | ||
| 60 | u32 error_irqs; | ||
| 61 | struct work_struct error_work; | ||
| 62 | |||
| 63 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 64 | spinlock_t irq_stats_lock; | ||
| 65 | struct dispc_irq_stats irq_stats; | ||
| 66 | #endif | ||
| 67 | } dispc_compat; | ||
| 68 | |||
| 69 | |||
| 70 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 71 | static void dispc_dump_irqs(struct seq_file *s) | ||
| 72 | { | ||
| 73 | unsigned long flags; | ||
| 74 | struct dispc_irq_stats stats; | ||
| 75 | |||
| 76 | spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags); | ||
| 77 | |||
| 78 | stats = dispc_compat.irq_stats; | ||
| 79 | memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats)); | ||
| 80 | dispc_compat.irq_stats.last_reset = jiffies; | ||
| 81 | |||
| 82 | spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags); | ||
| 83 | |||
| 84 | seq_printf(s, "period %u ms\n", | ||
| 85 | jiffies_to_msecs(jiffies - stats.last_reset)); | ||
| 86 | |||
| 87 | seq_printf(s, "irqs %d\n", stats.irq_count); | ||
| 88 | #define PIS(x) \ | ||
| 89 | seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); | ||
| 90 | |||
| 91 | PIS(FRAMEDONE); | ||
| 92 | PIS(VSYNC); | ||
| 93 | PIS(EVSYNC_EVEN); | ||
| 94 | PIS(EVSYNC_ODD); | ||
| 95 | PIS(ACBIAS_COUNT_STAT); | ||
| 96 | PIS(PROG_LINE_NUM); | ||
| 97 | PIS(GFX_FIFO_UNDERFLOW); | ||
| 98 | PIS(GFX_END_WIN); | ||
| 99 | PIS(PAL_GAMMA_MASK); | ||
| 100 | PIS(OCP_ERR); | ||
| 101 | PIS(VID1_FIFO_UNDERFLOW); | ||
| 102 | PIS(VID1_END_WIN); | ||
| 103 | PIS(VID2_FIFO_UNDERFLOW); | ||
| 104 | PIS(VID2_END_WIN); | ||
| 105 | if (dss_feat_get_num_ovls() > 3) { | ||
| 106 | PIS(VID3_FIFO_UNDERFLOW); | ||
| 107 | PIS(VID3_END_WIN); | ||
| 108 | } | ||
| 109 | PIS(SYNC_LOST); | ||
| 110 | PIS(SYNC_LOST_DIGIT); | ||
| 111 | PIS(WAKEUP); | ||
| 112 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
| 113 | PIS(FRAMEDONE2); | ||
| 114 | PIS(VSYNC2); | ||
| 115 | PIS(ACBIAS_COUNT_STAT2); | ||
| 116 | PIS(SYNC_LOST2); | ||
| 117 | } | ||
| 118 | if (dss_has_feature(FEAT_MGR_LCD3)) { | ||
| 119 | PIS(FRAMEDONE3); | ||
| 120 | PIS(VSYNC3); | ||
| 121 | PIS(ACBIAS_COUNT_STAT3); | ||
| 122 | PIS(SYNC_LOST3); | ||
| 123 | } | ||
| 124 | #undef PIS | ||
| 125 | } | ||
| 126 | #endif | ||
| 127 | |||
| 128 | /* dispc.irq_lock has to be locked by the caller */ | ||
| 129 | static void _omap_dispc_set_irqs(void) | ||
| 130 | { | ||
| 131 | u32 mask; | ||
| 132 | int i; | ||
| 133 | struct omap_dispc_isr_data *isr_data; | ||
| 134 | |||
| 135 | mask = dispc_compat.irq_error_mask; | ||
| 136 | |||
| 137 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 138 | isr_data = &dispc_compat.registered_isr[i]; | ||
| 139 | |||
| 140 | if (isr_data->isr == NULL) | ||
| 141 | continue; | ||
| 142 | |||
| 143 | mask |= isr_data->mask; | ||
| 144 | } | ||
| 145 | |||
| 146 | dispc_write_irqenable(mask); | ||
| 147 | } | ||
| 148 | |||
| 149 | int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) | ||
| 150 | { | ||
| 151 | int i; | ||
| 152 | int ret; | ||
| 153 | unsigned long flags; | ||
| 154 | struct omap_dispc_isr_data *isr_data; | ||
| 155 | |||
| 156 | if (isr == NULL) | ||
| 157 | return -EINVAL; | ||
| 158 | |||
| 159 | spin_lock_irqsave(&dispc_compat.irq_lock, flags); | ||
| 160 | |||
| 161 | /* check for duplicate entry */ | ||
| 162 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 163 | isr_data = &dispc_compat.registered_isr[i]; | ||
| 164 | if (isr_data->isr == isr && isr_data->arg == arg && | ||
| 165 | isr_data->mask == mask) { | ||
| 166 | ret = -EINVAL; | ||
| 167 | goto err; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | isr_data = NULL; | ||
| 172 | ret = -EBUSY; | ||
| 173 | |||
| 174 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 175 | isr_data = &dispc_compat.registered_isr[i]; | ||
| 176 | |||
| 177 | if (isr_data->isr != NULL) | ||
| 178 | continue; | ||
| 179 | |||
| 180 | isr_data->isr = isr; | ||
| 181 | isr_data->arg = arg; | ||
| 182 | isr_data->mask = mask; | ||
| 183 | ret = 0; | ||
| 184 | |||
| 185 | break; | ||
| 186 | } | ||
| 187 | |||
| 188 | if (ret) | ||
| 189 | goto err; | ||
| 190 | |||
| 191 | _omap_dispc_set_irqs(); | ||
| 192 | |||
| 193 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
| 194 | |||
| 195 | return 0; | ||
| 196 | err: | ||
| 197 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
| 198 | |||
| 199 | return ret; | ||
| 200 | } | ||
| 201 | EXPORT_SYMBOL(omap_dispc_register_isr); | ||
| 202 | |||
| 203 | int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) | ||
| 204 | { | ||
| 205 | int i; | ||
| 206 | unsigned long flags; | ||
| 207 | int ret = -EINVAL; | ||
| 208 | struct omap_dispc_isr_data *isr_data; | ||
| 209 | |||
| 210 | spin_lock_irqsave(&dispc_compat.irq_lock, flags); | ||
| 211 | |||
| 212 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 213 | isr_data = &dispc_compat.registered_isr[i]; | ||
| 214 | if (isr_data->isr != isr || isr_data->arg != arg || | ||
| 215 | isr_data->mask != mask) | ||
| 216 | continue; | ||
| 217 | |||
| 218 | /* found the correct isr */ | ||
| 219 | |||
| 220 | isr_data->isr = NULL; | ||
| 221 | isr_data->arg = NULL; | ||
| 222 | isr_data->mask = 0; | ||
| 223 | |||
| 224 | ret = 0; | ||
| 225 | break; | ||
| 226 | } | ||
| 227 | |||
| 228 | if (ret == 0) | ||
| 229 | _omap_dispc_set_irqs(); | ||
| 230 | |||
| 231 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
| 232 | |||
| 233 | return ret; | ||
| 234 | } | ||
| 235 | EXPORT_SYMBOL(omap_dispc_unregister_isr); | ||
| 236 | |||
| 237 | static void print_irq_status(u32 status) | ||
| 238 | { | ||
| 239 | if ((status & dispc_compat.irq_error_mask) == 0) | ||
| 240 | return; | ||
| 241 | |||
| 242 | #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : "" | ||
| 243 | |||
| 244 | pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n", | ||
| 245 | status, | ||
| 246 | PIS(OCP_ERR), | ||
| 247 | PIS(GFX_FIFO_UNDERFLOW), | ||
| 248 | PIS(VID1_FIFO_UNDERFLOW), | ||
| 249 | PIS(VID2_FIFO_UNDERFLOW), | ||
| 250 | dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "", | ||
| 251 | PIS(SYNC_LOST), | ||
| 252 | PIS(SYNC_LOST_DIGIT), | ||
| 253 | dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "", | ||
| 254 | dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : ""); | ||
| 255 | #undef PIS | ||
| 256 | } | ||
| 257 | |||
| 258 | /* Called from dss.c. Note that we don't touch clocks here, | ||
| 259 | * but we presume they are on because we got an IRQ. However, | ||
| 260 | * an irq handler may turn the clocks off, so we may not have | ||
| 261 | * clock later in the function. */ | ||
| 262 | static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) | ||
| 263 | { | ||
| 264 | int i; | ||
| 265 | u32 irqstatus, irqenable; | ||
| 266 | u32 handledirqs = 0; | ||
| 267 | u32 unhandled_errors; | ||
| 268 | struct omap_dispc_isr_data *isr_data; | ||
| 269 | struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; | ||
| 270 | |||
| 271 | spin_lock(&dispc_compat.irq_lock); | ||
| 272 | |||
| 273 | irqstatus = dispc_read_irqstatus(); | ||
| 274 | irqenable = dispc_read_irqenable(); | ||
| 275 | |||
| 276 | /* IRQ is not for us */ | ||
| 277 | if (!(irqstatus & irqenable)) { | ||
| 278 | spin_unlock(&dispc_compat.irq_lock); | ||
| 279 | return IRQ_NONE; | ||
| 280 | } | ||
| 281 | |||
| 282 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 283 | spin_lock(&dispc_compat.irq_stats_lock); | ||
| 284 | dispc_compat.irq_stats.irq_count++; | ||
| 285 | dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs); | ||
| 286 | spin_unlock(&dispc_compat.irq_stats_lock); | ||
| 287 | #endif | ||
| 288 | |||
| 289 | print_irq_status(irqstatus); | ||
| 290 | |||
| 291 | /* Ack the interrupt. Do it here before clocks are possibly turned | ||
| 292 | * off */ | ||
| 293 | dispc_clear_irqstatus(irqstatus); | ||
| 294 | /* flush posted write */ | ||
| 295 | dispc_read_irqstatus(); | ||
| 296 | |||
| 297 | /* make a copy and unlock, so that isrs can unregister | ||
| 298 | * themselves */ | ||
| 299 | memcpy(registered_isr, dispc_compat.registered_isr, | ||
| 300 | sizeof(registered_isr)); | ||
| 301 | |||
| 302 | spin_unlock(&dispc_compat.irq_lock); | ||
| 303 | |||
| 304 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 305 | isr_data = ®istered_isr[i]; | ||
| 306 | |||
| 307 | if (!isr_data->isr) | ||
| 308 | continue; | ||
| 309 | |||
| 310 | if (isr_data->mask & irqstatus) { | ||
| 311 | isr_data->isr(isr_data->arg, irqstatus); | ||
| 312 | handledirqs |= isr_data->mask; | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 316 | spin_lock(&dispc_compat.irq_lock); | ||
| 317 | |||
| 318 | unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask; | ||
| 319 | |||
| 320 | if (unhandled_errors) { | ||
| 321 | dispc_compat.error_irqs |= unhandled_errors; | ||
| 322 | |||
| 323 | dispc_compat.irq_error_mask &= ~unhandled_errors; | ||
| 324 | _omap_dispc_set_irqs(); | ||
| 325 | |||
| 326 | schedule_work(&dispc_compat.error_work); | ||
| 327 | } | ||
| 328 | |||
| 329 | spin_unlock(&dispc_compat.irq_lock); | ||
| 330 | |||
| 331 | return IRQ_HANDLED; | ||
| 332 | } | ||
| 333 | |||
| 334 | static void dispc_error_worker(struct work_struct *work) | ||
| 335 | { | ||
| 336 | int i; | ||
| 337 | u32 errors; | ||
| 338 | unsigned long flags; | ||
| 339 | static const unsigned fifo_underflow_bits[] = { | ||
| 340 | DISPC_IRQ_GFX_FIFO_UNDERFLOW, | ||
| 341 | DISPC_IRQ_VID1_FIFO_UNDERFLOW, | ||
| 342 | DISPC_IRQ_VID2_FIFO_UNDERFLOW, | ||
| 343 | DISPC_IRQ_VID3_FIFO_UNDERFLOW, | ||
| 344 | }; | ||
| 345 | |||
| 346 | spin_lock_irqsave(&dispc_compat.irq_lock, flags); | ||
| 347 | errors = dispc_compat.error_irqs; | ||
| 348 | dispc_compat.error_irqs = 0; | ||
| 349 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
| 350 | |||
| 351 | dispc_runtime_get(); | ||
| 352 | |||
| 353 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
| 354 | struct omap_overlay *ovl; | ||
| 355 | unsigned bit; | ||
| 356 | |||
| 357 | ovl = omap_dss_get_overlay(i); | ||
| 358 | bit = fifo_underflow_bits[i]; | ||
| 359 | |||
| 360 | if (bit & errors) { | ||
| 361 | DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", | ||
| 362 | ovl->name); | ||
| 363 | dispc_ovl_enable(ovl->id, false); | ||
| 364 | dispc_mgr_go(ovl->manager->id); | ||
| 365 | msleep(50); | ||
| 366 | } | ||
| 367 | } | ||
| 368 | |||
| 369 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
| 370 | struct omap_overlay_manager *mgr; | ||
| 371 | unsigned bit; | ||
| 372 | |||
| 373 | mgr = omap_dss_get_overlay_manager(i); | ||
| 374 | bit = dispc_mgr_get_sync_lost_irq(i); | ||
| 375 | |||
| 376 | if (bit & errors) { | ||
| 377 | int j; | ||
| 378 | |||
| 379 | DSSERR("SYNC_LOST on channel %s, restarting the output " | ||
| 380 | "with video overlays disabled\n", | ||
| 381 | mgr->name); | ||
| 382 | |||
| 383 | dss_mgr_disable(mgr); | ||
| 384 | |||
| 385 | for (j = 0; j < omap_dss_get_num_overlays(); ++j) { | ||
| 386 | struct omap_overlay *ovl; | ||
| 387 | ovl = omap_dss_get_overlay(j); | ||
| 388 | |||
| 389 | if (ovl->id != OMAP_DSS_GFX && | ||
| 390 | ovl->manager == mgr) | ||
| 391 | ovl->disable(ovl); | ||
| 392 | } | ||
| 393 | |||
| 394 | dss_mgr_enable(mgr); | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | if (errors & DISPC_IRQ_OCP_ERR) { | ||
| 399 | DSSERR("OCP_ERR\n"); | ||
| 400 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
| 401 | struct omap_overlay_manager *mgr; | ||
| 402 | |||
| 403 | mgr = omap_dss_get_overlay_manager(i); | ||
| 404 | dss_mgr_disable(mgr); | ||
| 405 | } | ||
| 406 | } | ||
| 407 | |||
| 408 | spin_lock_irqsave(&dispc_compat.irq_lock, flags); | ||
| 409 | dispc_compat.irq_error_mask |= errors; | ||
| 410 | _omap_dispc_set_irqs(); | ||
| 411 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
| 412 | |||
| 413 | dispc_runtime_put(); | ||
| 414 | } | ||
| 415 | |||
| 416 | int dss_dispc_initialize_irq(void) | ||
| 417 | { | ||
| 418 | int r; | ||
| 419 | |||
| 420 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 421 | spin_lock_init(&dispc_compat.irq_stats_lock); | ||
| 422 | dispc_compat.irq_stats.last_reset = jiffies; | ||
| 423 | dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); | ||
| 424 | #endif | ||
| 425 | |||
| 426 | spin_lock_init(&dispc_compat.irq_lock); | ||
| 427 | |||
| 428 | memset(dispc_compat.registered_isr, 0, | ||
| 429 | sizeof(dispc_compat.registered_isr)); | ||
| 430 | |||
| 431 | dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR; | ||
| 432 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
| 433 | dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; | ||
| 434 | if (dss_has_feature(FEAT_MGR_LCD3)) | ||
| 435 | dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3; | ||
| 436 | if (dss_feat_get_num_ovls() > 3) | ||
| 437 | dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; | ||
| 438 | |||
| 439 | /* | ||
| 440 | * there's SYNC_LOST_DIGIT waiting after enabling the DSS, | ||
| 441 | * so clear it | ||
| 442 | */ | ||
| 443 | dispc_clear_irqstatus(dispc_read_irqstatus()); | ||
| 444 | |||
| 445 | INIT_WORK(&dispc_compat.error_work, dispc_error_worker); | ||
| 446 | |||
| 447 | _omap_dispc_set_irqs(); | ||
| 448 | |||
| 449 | r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat); | ||
| 450 | if (r) { | ||
| 451 | DSSERR("dispc_request_irq failed\n"); | ||
| 452 | return r; | ||
| 453 | } | ||
| 454 | |||
| 455 | return 0; | ||
| 456 | } | ||
| 457 | |||
| 458 | void dss_dispc_uninitialize_irq(void) | ||
| 459 | { | ||
| 460 | dispc_free_irq(&dispc_compat); | ||
| 461 | } | ||
| 462 | |||
| 463 | static void dispc_mgr_disable_isr(void *data, u32 mask) | ||
| 464 | { | ||
| 465 | struct completion *compl = data; | ||
| 466 | complete(compl); | ||
| 467 | } | ||
| 468 | |||
| 469 | static void dispc_mgr_enable_lcd_out(enum omap_channel channel) | ||
| 470 | { | ||
| 471 | dispc_mgr_enable(channel, true); | ||
| 472 | } | ||
| 473 | |||
| 474 | static void dispc_mgr_disable_lcd_out(enum omap_channel channel) | ||
| 475 | { | ||
| 476 | DECLARE_COMPLETION_ONSTACK(framedone_compl); | ||
| 477 | int r; | ||
| 478 | u32 irq; | ||
| 479 | |||
| 480 | if (dispc_mgr_is_enabled(channel) == false) | ||
| 481 | return; | ||
| 482 | |||
| 483 | /* | ||
| 484 | * When we disable LCD output, we need to wait for FRAMEDONE to know | ||
| 485 | * that DISPC has finished with the LCD output. | ||
| 486 | */ | ||
| 487 | |||
| 488 | irq = dispc_mgr_get_framedone_irq(channel); | ||
| 489 | |||
| 490 | r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, | ||
| 491 | irq); | ||
| 492 | if (r) | ||
| 493 | DSSERR("failed to register FRAMEDONE isr\n"); | ||
| 494 | |||
| 495 | dispc_mgr_enable(channel, false); | ||
| 496 | |||
| 497 | /* if we couldn't register for framedone, just sleep and exit */ | ||
| 498 | if (r) { | ||
| 499 | msleep(100); | ||
| 500 | return; | ||
| 501 | } | ||
| 502 | |||
| 503 | if (!wait_for_completion_timeout(&framedone_compl, | ||
| 504 | msecs_to_jiffies(100))) | ||
| 505 | DSSERR("timeout waiting for FRAME DONE\n"); | ||
| 506 | |||
| 507 | r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, | ||
| 508 | irq); | ||
| 509 | if (r) | ||
| 510 | DSSERR("failed to unregister FRAMEDONE isr\n"); | ||
| 511 | } | ||
| 512 | |||
| 513 | static void dispc_digit_out_enable_isr(void *data, u32 mask) | ||
| 514 | { | ||
| 515 | struct completion *compl = data; | ||
| 516 | |||
| 517 | /* ignore any sync lost interrupts */ | ||
| 518 | if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD)) | ||
| 519 | complete(compl); | ||
| 520 | } | ||
| 521 | |||
| 522 | static void dispc_mgr_enable_digit_out(void) | ||
| 523 | { | ||
| 524 | DECLARE_COMPLETION_ONSTACK(vsync_compl); | ||
| 525 | int r; | ||
| 526 | u32 irq_mask; | ||
| 527 | |||
| 528 | if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true) | ||
| 529 | return; | ||
| 530 | |||
| 531 | /* | ||
| 532 | * Digit output produces some sync lost interrupts during the first | ||
| 533 | * frame when enabling. Those need to be ignored, so we register for the | ||
| 534 | * sync lost irq to prevent the error handler from triggering. | ||
| 535 | */ | ||
| 536 | |||
| 537 | irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) | | ||
| 538 | dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT); | ||
| 539 | |||
| 540 | r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl, | ||
| 541 | irq_mask); | ||
| 542 | if (r) { | ||
| 543 | DSSERR("failed to register %x isr\n", irq_mask); | ||
| 544 | return; | ||
| 545 | } | ||
| 546 | |||
| 547 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true); | ||
| 548 | |||
| 549 | /* wait for the first evsync */ | ||
| 550 | if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100))) | ||
| 551 | DSSERR("timeout waiting for digit out to start\n"); | ||
| 552 | |||
| 553 | r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl, | ||
| 554 | irq_mask); | ||
| 555 | if (r) | ||
| 556 | DSSERR("failed to unregister %x isr\n", irq_mask); | ||
| 557 | } | ||
| 558 | |||
| 559 | static void dispc_mgr_disable_digit_out(void) | ||
| 560 | { | ||
| 561 | DECLARE_COMPLETION_ONSTACK(framedone_compl); | ||
| 562 | int r, i; | ||
| 563 | u32 irq_mask; | ||
| 564 | int num_irqs; | ||
| 565 | |||
| 566 | if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false) | ||
| 567 | return; | ||
| 568 | |||
| 569 | /* | ||
| 570 | * When we disable the digit output, we need to wait for FRAMEDONE to | ||
| 571 | * know that DISPC has finished with the output. | ||
| 572 | */ | ||
| 573 | |||
| 574 | irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT); | ||
| 575 | num_irqs = 1; | ||
| 576 | |||
| 577 | if (!irq_mask) { | ||
| 578 | /* | ||
| 579 | * omap 2/3 don't have framedone irq for TV, so we need to use | ||
| 580 | * vsyncs for this. | ||
| 581 | */ | ||
| 582 | |||
| 583 | irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT); | ||
| 584 | /* | ||
| 585 | * We need to wait for both even and odd vsyncs. Note that this | ||
| 586 | * is not totally reliable, as we could get a vsync interrupt | ||
| 587 | * before we disable the output, which leads to timeout in the | ||
| 588 | * wait_for_completion. | ||
| 589 | */ | ||
| 590 | num_irqs = 2; | ||
| 591 | } | ||
| 592 | |||
| 593 | r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, | ||
| 594 | irq_mask); | ||
| 595 | if (r) | ||
| 596 | DSSERR("failed to register %x isr\n", irq_mask); | ||
| 597 | |||
| 598 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false); | ||
| 599 | |||
| 600 | /* if we couldn't register the irq, just sleep and exit */ | ||
| 601 | if (r) { | ||
| 602 | msleep(100); | ||
| 603 | return; | ||
| 604 | } | ||
| 605 | |||
| 606 | for (i = 0; i < num_irqs; ++i) { | ||
| 607 | if (!wait_for_completion_timeout(&framedone_compl, | ||
| 608 | msecs_to_jiffies(100))) | ||
| 609 | DSSERR("timeout waiting for digit out to stop\n"); | ||
| 610 | } | ||
| 611 | |||
| 612 | r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, | ||
| 613 | irq_mask); | ||
| 614 | if (r) | ||
| 615 | DSSERR("failed to unregister %x isr\n", irq_mask); | ||
| 616 | } | ||
| 617 | |||
| 618 | void dispc_mgr_enable_sync(enum omap_channel channel) | ||
| 619 | { | ||
| 620 | if (dss_mgr_is_lcd(channel)) | ||
| 621 | dispc_mgr_enable_lcd_out(channel); | ||
| 622 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) | ||
| 623 | dispc_mgr_enable_digit_out(); | ||
| 624 | else | ||
| 625 | WARN_ON(1); | ||
| 626 | } | ||
| 627 | |||
| 628 | void dispc_mgr_disable_sync(enum omap_channel channel) | ||
| 629 | { | ||
| 630 | if (dss_mgr_is_lcd(channel)) | ||
| 631 | dispc_mgr_disable_lcd_out(channel); | ||
| 632 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) | ||
| 633 | dispc_mgr_disable_digit_out(); | ||
| 634 | else | ||
| 635 | WARN_ON(1); | ||
| 636 | } | ||
| 637 | |||
| 638 | int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, | ||
| 639 | unsigned long timeout) | ||
| 640 | { | ||
| 641 | void dispc_irq_wait_handler(void *data, u32 mask) | ||
| 642 | { | ||
| 643 | complete((struct completion *)data); | ||
| 644 | } | ||
| 645 | |||
| 646 | int r; | ||
| 647 | DECLARE_COMPLETION_ONSTACK(completion); | ||
| 648 | |||
| 649 | r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, | ||
| 650 | irqmask); | ||
| 651 | |||
| 652 | if (r) | ||
| 653 | return r; | ||
| 654 | |||
| 655 | timeout = wait_for_completion_interruptible_timeout(&completion, | ||
| 656 | timeout); | ||
| 657 | |||
| 658 | omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); | ||
| 659 | |||
| 660 | if (timeout == 0) | ||
| 661 | return -ETIMEDOUT; | ||
| 662 | |||
| 663 | if (timeout == -ERESTARTSYS) | ||
| 664 | return -ERESTARTSYS; | ||
| 665 | |||
| 666 | return 0; | ||
| 667 | } | ||
diff --git a/drivers/video/omap2/dss/dispc-compat.h b/drivers/video/omap2/dss/dispc-compat.h new file mode 100644 index 000000000000..14a69b3d4fb0 --- /dev/null +++ b/drivers/video/omap2/dss/dispc-compat.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Texas Instruments | ||
| 3 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published by | ||
| 7 | * the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License along with | ||
| 15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef __OMAP2_DSS_DISPC_COMPAT_H | ||
| 19 | #define __OMAP2_DSS_DISPC_COMPAT_H | ||
| 20 | |||
| 21 | void dispc_mgr_enable_sync(enum omap_channel channel); | ||
| 22 | void dispc_mgr_disable_sync(enum omap_channel channel); | ||
| 23 | |||
| 24 | int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, | ||
| 25 | unsigned long timeout); | ||
| 26 | |||
| 27 | int dss_dispc_initialize_irq(void); | ||
| 28 | void dss_dispc_uninitialize_irq(void); | ||
| 29 | |||
| 30 | #endif | ||
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index a5ab354f267a..05ff2b91d9e8 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
| @@ -33,9 +33,9 @@ | |||
| 33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
| 34 | #include <linux/workqueue.h> | 34 | #include <linux/workqueue.h> |
| 35 | #include <linux/hardirq.h> | 35 | #include <linux/hardirq.h> |
| 36 | #include <linux/interrupt.h> | ||
| 37 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
| 38 | #include <linux/pm_runtime.h> | 37 | #include <linux/pm_runtime.h> |
| 38 | #include <linux/sizes.h> | ||
| 39 | 39 | ||
| 40 | #include <video/omapdss.h> | 40 | #include <video/omapdss.h> |
| 41 | 41 | ||
| @@ -46,21 +46,6 @@ | |||
| 46 | /* DISPC */ | 46 | /* DISPC */ |
| 47 | #define DISPC_SZ_REGS SZ_4K | 47 | #define DISPC_SZ_REGS SZ_4K |
| 48 | 48 | ||
| 49 | #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ | ||
| 50 | DISPC_IRQ_OCP_ERR | \ | ||
| 51 | DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ | ||
| 52 | DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ | ||
| 53 | DISPC_IRQ_SYNC_LOST | \ | ||
| 54 | DISPC_IRQ_SYNC_LOST_DIGIT) | ||
| 55 | |||
| 56 | #define DISPC_MAX_NR_ISRS 8 | ||
| 57 | |||
| 58 | struct omap_dispc_isr_data { | ||
| 59 | omap_dispc_isr_t isr; | ||
| 60 | void *arg; | ||
| 61 | u32 mask; | ||
| 62 | }; | ||
| 63 | |||
| 64 | enum omap_burst_size { | 49 | enum omap_burst_size { |
| 65 | BURST_SIZE_X2 = 0, | 50 | BURST_SIZE_X2 = 0, |
| 66 | BURST_SIZE_X4 = 1, | 51 | BURST_SIZE_X4 = 1, |
| @@ -73,12 +58,6 @@ enum omap_burst_size { | |||
| 73 | #define REG_FLD_MOD(idx, val, start, end) \ | 58 | #define REG_FLD_MOD(idx, val, start, end) \ |
| 74 | dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) | 59 | dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) |
| 75 | 60 | ||
| 76 | struct dispc_irq_stats { | ||
| 77 | unsigned long last_reset; | ||
| 78 | unsigned irq_count; | ||
| 79 | unsigned irqs[32]; | ||
| 80 | }; | ||
| 81 | |||
| 82 | struct dispc_features { | 61 | struct dispc_features { |
| 83 | u8 sw_start; | 62 | u8 sw_start; |
| 84 | u8 fp_start; | 63 | u8 fp_start; |
| @@ -86,19 +65,26 @@ struct dispc_features { | |||
| 86 | u16 sw_max; | 65 | u16 sw_max; |
| 87 | u16 vp_max; | 66 | u16 vp_max; |
| 88 | u16 hp_max; | 67 | u16 hp_max; |
| 89 | int (*calc_scaling) (enum omap_plane plane, | 68 | u8 mgr_width_start; |
| 69 | u8 mgr_height_start; | ||
| 70 | u16 mgr_width_max; | ||
| 71 | u16 mgr_height_max; | ||
| 72 | int (*calc_scaling) (unsigned long pclk, unsigned long lclk, | ||
| 90 | const struct omap_video_timings *mgr_timings, | 73 | const struct omap_video_timings *mgr_timings, |
| 91 | u16 width, u16 height, u16 out_width, u16 out_height, | 74 | u16 width, u16 height, u16 out_width, u16 out_height, |
| 92 | enum omap_color_mode color_mode, bool *five_taps, | 75 | enum omap_color_mode color_mode, bool *five_taps, |
| 93 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | 76 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, |
| 94 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem); | 77 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem); |
| 95 | unsigned long (*calc_core_clk) (enum omap_plane plane, | 78 | unsigned long (*calc_core_clk) (unsigned long pclk, |
| 96 | u16 width, u16 height, u16 out_width, u16 out_height, | 79 | u16 width, u16 height, u16 out_width, u16 out_height, |
| 97 | bool mem_to_mem); | 80 | bool mem_to_mem); |
| 98 | u8 num_fifos; | 81 | u8 num_fifos; |
| 99 | 82 | ||
| 100 | /* swap GFX & WB fifos */ | 83 | /* swap GFX & WB fifos */ |
| 101 | bool gfx_fifo_workaround:1; | 84 | bool gfx_fifo_workaround:1; |
| 85 | |||
| 86 | /* no DISPC_IRQ_FRAMEDONETV on this SoC */ | ||
| 87 | bool no_framedone_tv:1; | ||
| 102 | }; | 88 | }; |
| 103 | 89 | ||
| 104 | #define DISPC_MAX_NR_FIFOS 5 | 90 | #define DISPC_MAX_NR_FIFOS 5 |
| @@ -110,27 +96,15 @@ static struct { | |||
| 110 | int ctx_loss_cnt; | 96 | int ctx_loss_cnt; |
| 111 | 97 | ||
| 112 | int irq; | 98 | int irq; |
| 113 | struct clk *dss_clk; | ||
| 114 | 99 | ||
| 115 | u32 fifo_size[DISPC_MAX_NR_FIFOS]; | 100 | u32 fifo_size[DISPC_MAX_NR_FIFOS]; |
| 116 | /* maps which plane is using a fifo. fifo-id -> plane-id */ | 101 | /* maps which plane is using a fifo. fifo-id -> plane-id */ |
| 117 | int fifo_assignment[DISPC_MAX_NR_FIFOS]; | 102 | int fifo_assignment[DISPC_MAX_NR_FIFOS]; |
| 118 | 103 | ||
| 119 | spinlock_t irq_lock; | ||
| 120 | u32 irq_error_mask; | ||
| 121 | struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; | ||
| 122 | u32 error_irqs; | ||
| 123 | struct work_struct error_work; | ||
| 124 | |||
| 125 | bool ctx_valid; | 104 | bool ctx_valid; |
| 126 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; | 105 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; |
| 127 | 106 | ||
| 128 | const struct dispc_features *feat; | 107 | const struct dispc_features *feat; |
| 129 | |||
| 130 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 131 | spinlock_t irq_stats_lock; | ||
| 132 | struct dispc_irq_stats irq_stats; | ||
| 133 | #endif | ||
| 134 | } dispc; | 108 | } dispc; |
| 135 | 109 | ||
| 136 | enum omap_color_component { | 110 | enum omap_color_component { |
| @@ -186,7 +160,7 @@ static const struct { | |||
| 186 | [OMAP_DSS_CHANNEL_DIGIT] = { | 160 | [OMAP_DSS_CHANNEL_DIGIT] = { |
| 187 | .name = "DIGIT", | 161 | .name = "DIGIT", |
| 188 | .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN, | 162 | .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN, |
| 189 | .framedone_irq = 0, | 163 | .framedone_irq = DISPC_IRQ_FRAMEDONETV, |
| 190 | .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT, | 164 | .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT, |
| 191 | .reg_desc = { | 165 | .reg_desc = { |
| 192 | [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 }, | 166 | [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 }, |
| @@ -241,7 +215,6 @@ struct color_conv_coef { | |||
| 241 | int full_range; | 215 | int full_range; |
| 242 | }; | 216 | }; |
| 243 | 217 | ||
| 244 | static void _omap_dispc_set_irqs(void); | ||
| 245 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); | 218 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); |
| 246 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); | 219 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); |
| 247 | 220 | ||
| @@ -374,7 +347,7 @@ static void dispc_save_context(void) | |||
| 374 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | 347 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) |
| 375 | SR(DIVISOR); | 348 | SR(DIVISOR); |
| 376 | 349 | ||
| 377 | dispc.ctx_loss_cnt = dss_get_ctx_loss_count(&dispc.pdev->dev); | 350 | dispc.ctx_loss_cnt = dss_get_ctx_loss_count(); |
| 378 | dispc.ctx_valid = true; | 351 | dispc.ctx_valid = true; |
| 379 | 352 | ||
| 380 | DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); | 353 | DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); |
| @@ -389,7 +362,7 @@ static void dispc_restore_context(void) | |||
| 389 | if (!dispc.ctx_valid) | 362 | if (!dispc.ctx_valid) |
| 390 | return; | 363 | return; |
| 391 | 364 | ||
| 392 | ctx = dss_get_ctx_loss_count(&dispc.pdev->dev); | 365 | ctx = dss_get_ctx_loss_count(); |
| 393 | 366 | ||
| 394 | if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) | 367 | if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) |
| 395 | return; | 368 | return; |
| @@ -496,7 +469,7 @@ static void dispc_restore_context(void) | |||
| 496 | if (dss_has_feature(FEAT_MGR_LCD3)) | 469 | if (dss_has_feature(FEAT_MGR_LCD3)) |
| 497 | RR(CONTROL3); | 470 | RR(CONTROL3); |
| 498 | /* clear spurious SYNC_LOST_DIGIT interrupts */ | 471 | /* clear spurious SYNC_LOST_DIGIT interrupts */ |
| 499 | dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); | 472 | dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT); |
| 500 | 473 | ||
| 501 | /* | 474 | /* |
| 502 | * enable last so IRQs won't trigger before | 475 | * enable last so IRQs won't trigger before |
| @@ -520,6 +493,7 @@ int dispc_runtime_get(void) | |||
| 520 | WARN_ON(r < 0); | 493 | WARN_ON(r < 0); |
| 521 | return r < 0 ? r : 0; | 494 | return r < 0 ? r : 0; |
| 522 | } | 495 | } |
| 496 | EXPORT_SYMBOL(dispc_runtime_get); | ||
| 523 | 497 | ||
| 524 | void dispc_runtime_put(void) | 498 | void dispc_runtime_put(void) |
| 525 | { | 499 | { |
| @@ -530,16 +504,28 @@ void dispc_runtime_put(void) | |||
| 530 | r = pm_runtime_put_sync(&dispc.pdev->dev); | 504 | r = pm_runtime_put_sync(&dispc.pdev->dev); |
| 531 | WARN_ON(r < 0 && r != -ENOSYS); | 505 | WARN_ON(r < 0 && r != -ENOSYS); |
| 532 | } | 506 | } |
| 507 | EXPORT_SYMBOL(dispc_runtime_put); | ||
| 533 | 508 | ||
| 534 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) | 509 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) |
| 535 | { | 510 | { |
| 536 | return mgr_desc[channel].vsync_irq; | 511 | return mgr_desc[channel].vsync_irq; |
| 537 | } | 512 | } |
| 513 | EXPORT_SYMBOL(dispc_mgr_get_vsync_irq); | ||
| 538 | 514 | ||
| 539 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) | 515 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) |
| 540 | { | 516 | { |
| 517 | if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv) | ||
| 518 | return 0; | ||
| 519 | |||
| 541 | return mgr_desc[channel].framedone_irq; | 520 | return mgr_desc[channel].framedone_irq; |
| 542 | } | 521 | } |
| 522 | EXPORT_SYMBOL(dispc_mgr_get_framedone_irq); | ||
| 523 | |||
| 524 | u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel) | ||
| 525 | { | ||
| 526 | return mgr_desc[channel].sync_lost_irq; | ||
| 527 | } | ||
| 528 | EXPORT_SYMBOL(dispc_mgr_get_sync_lost_irq); | ||
| 543 | 529 | ||
| 544 | u32 dispc_wb_get_framedone_irq(void) | 530 | u32 dispc_wb_get_framedone_irq(void) |
| 545 | { | 531 | { |
| @@ -550,28 +536,18 @@ bool dispc_mgr_go_busy(enum omap_channel channel) | |||
| 550 | { | 536 | { |
| 551 | return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; | 537 | return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; |
| 552 | } | 538 | } |
| 539 | EXPORT_SYMBOL(dispc_mgr_go_busy); | ||
| 553 | 540 | ||
| 554 | void dispc_mgr_go(enum omap_channel channel) | 541 | void dispc_mgr_go(enum omap_channel channel) |
| 555 | { | 542 | { |
| 556 | bool enable_bit, go_bit; | 543 | WARN_ON(dispc_mgr_is_enabled(channel) == false); |
| 557 | 544 | WARN_ON(dispc_mgr_go_busy(channel)); | |
| 558 | /* if the channel is not enabled, we don't need GO */ | ||
| 559 | enable_bit = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE) == 1; | ||
| 560 | |||
| 561 | if (!enable_bit) | ||
| 562 | return; | ||
| 563 | |||
| 564 | go_bit = mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; | ||
| 565 | |||
| 566 | if (go_bit) { | ||
| 567 | DSSERR("GO bit not down for channel %d\n", channel); | ||
| 568 | return; | ||
| 569 | } | ||
| 570 | 545 | ||
| 571 | DSSDBG("GO %s\n", mgr_desc[channel].name); | 546 | DSSDBG("GO %s\n", mgr_desc[channel].name); |
| 572 | 547 | ||
| 573 | mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); | 548 | mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); |
| 574 | } | 549 | } |
| 550 | EXPORT_SYMBOL(dispc_mgr_go); | ||
| 575 | 551 | ||
| 576 | bool dispc_wb_go_busy(void) | 552 | bool dispc_wb_go_busy(void) |
| 577 | { | 553 | { |
| @@ -975,6 +951,7 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) | |||
| 975 | } | 951 | } |
| 976 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); | 952 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); |
| 977 | } | 953 | } |
| 954 | EXPORT_SYMBOL(dispc_ovl_set_channel_out); | ||
| 978 | 955 | ||
| 979 | static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) | 956 | static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) |
| 980 | { | 957 | { |
| @@ -1040,7 +1017,7 @@ static void dispc_configure_burst_sizes(void) | |||
| 1040 | const int burst_size = BURST_SIZE_X8; | 1017 | const int burst_size = BURST_SIZE_X8; |
| 1041 | 1018 | ||
| 1042 | /* Configure burst size always to maximum size */ | 1019 | /* Configure burst size always to maximum size */ |
| 1043 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) | 1020 | for (i = 0; i < dss_feat_get_num_ovls(); ++i) |
| 1044 | dispc_ovl_set_burst_size(i, burst_size); | 1021 | dispc_ovl_set_burst_size(i, burst_size); |
| 1045 | } | 1022 | } |
| 1046 | 1023 | ||
| @@ -1074,7 +1051,7 @@ static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) | |||
| 1074 | } | 1051 | } |
| 1075 | 1052 | ||
| 1076 | static void dispc_mgr_set_cpr_coef(enum omap_channel channel, | 1053 | static void dispc_mgr_set_cpr_coef(enum omap_channel channel, |
| 1077 | struct omap_dss_cpr_coefs *coefs) | 1054 | const struct omap_dss_cpr_coefs *coefs) |
| 1078 | { | 1055 | { |
| 1079 | u32 coef_r, coef_g, coef_b; | 1056 | u32 coef_r, coef_g, coef_b; |
| 1080 | 1057 | ||
| @@ -1122,7 +1099,9 @@ static void dispc_mgr_set_size(enum omap_channel channel, u16 width, | |||
| 1122 | { | 1099 | { |
| 1123 | u32 val; | 1100 | u32 val; |
| 1124 | 1101 | ||
| 1125 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | 1102 | val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) | |
| 1103 | FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0); | ||
| 1104 | |||
| 1126 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); | 1105 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); |
| 1127 | } | 1106 | } |
| 1128 | 1107 | ||
| @@ -1244,7 +1223,7 @@ void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | |||
| 1244 | 1223 | ||
| 1245 | if (use_fifomerge) { | 1224 | if (use_fifomerge) { |
| 1246 | total_fifo_size = 0; | 1225 | total_fifo_size = 0; |
| 1247 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) | 1226 | for (i = 0; i < dss_feat_get_num_ovls(); ++i) |
| 1248 | total_fifo_size += dispc_ovl_get_fifo_size(i); | 1227 | total_fifo_size += dispc_ovl_get_fifo_size(i); |
| 1249 | } else { | 1228 | } else { |
| 1250 | total_fifo_size = ovl_fifo_size; | 1229 | total_fifo_size = ovl_fifo_size; |
| @@ -1989,16 +1968,14 @@ static void calc_tiler_rotation_offset(u16 screen_width, u16 width, | |||
| 1989 | * This function is used to avoid synclosts in OMAP3, because of some | 1968 | * This function is used to avoid synclosts in OMAP3, because of some |
| 1990 | * undocumented horizontal position and timing related limitations. | 1969 | * undocumented horizontal position and timing related limitations. |
| 1991 | */ | 1970 | */ |
| 1992 | static int check_horiz_timing_omap3(enum omap_plane plane, | 1971 | static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk, |
| 1993 | const struct omap_video_timings *t, u16 pos_x, | 1972 | const struct omap_video_timings *t, u16 pos_x, |
| 1994 | u16 width, u16 height, u16 out_width, u16 out_height) | 1973 | u16 width, u16 height, u16 out_width, u16 out_height) |
| 1995 | { | 1974 | { |
| 1996 | int DS = DIV_ROUND_UP(height, out_height); | 1975 | const int ds = DIV_ROUND_UP(height, out_height); |
| 1997 | unsigned long nonactive; | 1976 | unsigned long nonactive; |
| 1998 | static const u8 limits[3] = { 8, 10, 20 }; | 1977 | static const u8 limits[3] = { 8, 10, 20 }; |
| 1999 | u64 val, blank; | 1978 | u64 val, blank; |
| 2000 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
| 2001 | unsigned long lclk = dispc_plane_lclk_rate(plane); | ||
| 2002 | int i; | 1979 | int i; |
| 2003 | 1980 | ||
| 2004 | nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; | 1981 | nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; |
| @@ -2020,8 +1997,8 @@ static int check_horiz_timing_omap3(enum omap_plane plane, | |||
| 2020 | */ | 1997 | */ |
| 2021 | val = div_u64((u64)(nonactive - pos_x) * lclk, pclk); | 1998 | val = div_u64((u64)(nonactive - pos_x) * lclk, pclk); |
| 2022 | DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n", | 1999 | DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n", |
| 2023 | val, max(0, DS - 2) * width); | 2000 | val, max(0, ds - 2) * width); |
| 2024 | if (val < max(0, DS - 2) * width) | 2001 | if (val < max(0, ds - 2) * width) |
| 2025 | return -EINVAL; | 2002 | return -EINVAL; |
| 2026 | 2003 | ||
| 2027 | /* | 2004 | /* |
| @@ -2031,21 +2008,20 @@ static int check_horiz_timing_omap3(enum omap_plane plane, | |||
| 2031 | */ | 2008 | */ |
| 2032 | val = div_u64((u64)nonactive * lclk, pclk); | 2009 | val = div_u64((u64)nonactive * lclk, pclk); |
| 2033 | DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n", | 2010 | DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n", |
| 2034 | val, max(0, DS - 1) * width); | 2011 | val, max(0, ds - 1) * width); |
| 2035 | if (val < max(0, DS - 1) * width) | 2012 | if (val < max(0, ds - 1) * width) |
| 2036 | return -EINVAL; | 2013 | return -EINVAL; |
| 2037 | 2014 | ||
| 2038 | return 0; | 2015 | return 0; |
| 2039 | } | 2016 | } |
| 2040 | 2017 | ||
| 2041 | static unsigned long calc_core_clk_five_taps(enum omap_plane plane, | 2018 | static unsigned long calc_core_clk_five_taps(unsigned long pclk, |
| 2042 | const struct omap_video_timings *mgr_timings, u16 width, | 2019 | const struct omap_video_timings *mgr_timings, u16 width, |
| 2043 | u16 height, u16 out_width, u16 out_height, | 2020 | u16 height, u16 out_width, u16 out_height, |
| 2044 | enum omap_color_mode color_mode) | 2021 | enum omap_color_mode color_mode) |
| 2045 | { | 2022 | { |
| 2046 | u32 core_clk = 0; | 2023 | u32 core_clk = 0; |
| 2047 | u64 tmp; | 2024 | u64 tmp; |
| 2048 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
| 2049 | 2025 | ||
| 2050 | if (height <= out_height && width <= out_width) | 2026 | if (height <= out_height && width <= out_width) |
| 2051 | return (unsigned long) pclk; | 2027 | return (unsigned long) pclk; |
| @@ -2079,22 +2055,19 @@ static unsigned long calc_core_clk_five_taps(enum omap_plane plane, | |||
| 2079 | return core_clk; | 2055 | return core_clk; |
| 2080 | } | 2056 | } |
| 2081 | 2057 | ||
| 2082 | static unsigned long calc_core_clk_24xx(enum omap_plane plane, u16 width, | 2058 | static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width, |
| 2083 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) | 2059 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) |
| 2084 | { | 2060 | { |
| 2085 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
| 2086 | |||
| 2087 | if (height > out_height && width > out_width) | 2061 | if (height > out_height && width > out_width) |
| 2088 | return pclk * 4; | 2062 | return pclk * 4; |
| 2089 | else | 2063 | else |
| 2090 | return pclk * 2; | 2064 | return pclk * 2; |
| 2091 | } | 2065 | } |
| 2092 | 2066 | ||
| 2093 | static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width, | 2067 | static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width, |
| 2094 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) | 2068 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) |
| 2095 | { | 2069 | { |
| 2096 | unsigned int hf, vf; | 2070 | unsigned int hf, vf; |
| 2097 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
| 2098 | 2071 | ||
| 2099 | /* | 2072 | /* |
| 2100 | * FIXME how to determine the 'A' factor | 2073 | * FIXME how to determine the 'A' factor |
| @@ -2117,11 +2090,9 @@ static unsigned long calc_core_clk_34xx(enum omap_plane plane, u16 width, | |||
| 2117 | return pclk * vf * hf; | 2090 | return pclk * vf * hf; |
| 2118 | } | 2091 | } |
| 2119 | 2092 | ||
| 2120 | static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width, | 2093 | static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width, |
| 2121 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) | 2094 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) |
| 2122 | { | 2095 | { |
| 2123 | unsigned long pclk; | ||
| 2124 | |||
| 2125 | /* | 2096 | /* |
| 2126 | * If the overlay/writeback is in mem to mem mode, there are no | 2097 | * If the overlay/writeback is in mem to mem mode, there are no |
| 2127 | * downscaling limitations with respect to pixel clock, return 1 as | 2098 | * downscaling limitations with respect to pixel clock, return 1 as |
| @@ -2131,15 +2102,13 @@ static unsigned long calc_core_clk_44xx(enum omap_plane plane, u16 width, | |||
| 2131 | if (mem_to_mem) | 2102 | if (mem_to_mem) |
| 2132 | return 1; | 2103 | return 1; |
| 2133 | 2104 | ||
| 2134 | pclk = dispc_plane_pclk_rate(plane); | ||
| 2135 | |||
| 2136 | if (width > out_width) | 2105 | if (width > out_width) |
| 2137 | return DIV_ROUND_UP(pclk, out_width) * width; | 2106 | return DIV_ROUND_UP(pclk, out_width) * width; |
| 2138 | else | 2107 | else |
| 2139 | return pclk; | 2108 | return pclk; |
| 2140 | } | 2109 | } |
| 2141 | 2110 | ||
| 2142 | static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, | 2111 | static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, |
| 2143 | const struct omap_video_timings *mgr_timings, | 2112 | const struct omap_video_timings *mgr_timings, |
| 2144 | u16 width, u16 height, u16 out_width, u16 out_height, | 2113 | u16 width, u16 height, u16 out_width, u16 out_height, |
| 2145 | enum omap_color_mode color_mode, bool *five_taps, | 2114 | enum omap_color_mode color_mode, bool *five_taps, |
| @@ -2157,7 +2126,7 @@ static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, | |||
| 2157 | do { | 2126 | do { |
| 2158 | in_height = DIV_ROUND_UP(height, *decim_y); | 2127 | in_height = DIV_ROUND_UP(height, *decim_y); |
| 2159 | in_width = DIV_ROUND_UP(width, *decim_x); | 2128 | in_width = DIV_ROUND_UP(width, *decim_x); |
| 2160 | *core_clk = dispc.feat->calc_core_clk(plane, in_width, | 2129 | *core_clk = dispc.feat->calc_core_clk(pclk, in_width, |
| 2161 | in_height, out_width, out_height, mem_to_mem); | 2130 | in_height, out_width, out_height, mem_to_mem); |
| 2162 | error = (in_width > maxsinglelinewidth || !*core_clk || | 2131 | error = (in_width > maxsinglelinewidth || !*core_clk || |
| 2163 | *core_clk > dispc_core_clk_rate()); | 2132 | *core_clk > dispc_core_clk_rate()); |
| @@ -2180,7 +2149,7 @@ static int dispc_ovl_calc_scaling_24xx(enum omap_plane plane, | |||
| 2180 | return 0; | 2149 | return 0; |
| 2181 | } | 2150 | } |
| 2182 | 2151 | ||
| 2183 | static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, | 2152 | static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk, |
| 2184 | const struct omap_video_timings *mgr_timings, | 2153 | const struct omap_video_timings *mgr_timings, |
| 2185 | u16 width, u16 height, u16 out_width, u16 out_height, | 2154 | u16 width, u16 height, u16 out_width, u16 out_height, |
| 2186 | enum omap_color_mode color_mode, bool *five_taps, | 2155 | enum omap_color_mode color_mode, bool *five_taps, |
| @@ -2196,10 +2165,10 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, | |||
| 2196 | do { | 2165 | do { |
| 2197 | in_height = DIV_ROUND_UP(height, *decim_y); | 2166 | in_height = DIV_ROUND_UP(height, *decim_y); |
| 2198 | in_width = DIV_ROUND_UP(width, *decim_x); | 2167 | in_width = DIV_ROUND_UP(width, *decim_x); |
| 2199 | *core_clk = calc_core_clk_five_taps(plane, mgr_timings, | 2168 | *core_clk = calc_core_clk_five_taps(pclk, mgr_timings, |
| 2200 | in_width, in_height, out_width, out_height, color_mode); | 2169 | in_width, in_height, out_width, out_height, color_mode); |
| 2201 | 2170 | ||
| 2202 | error = check_horiz_timing_omap3(plane, mgr_timings, | 2171 | error = check_horiz_timing_omap3(pclk, lclk, mgr_timings, |
| 2203 | pos_x, in_width, in_height, out_width, | 2172 | pos_x, in_width, in_height, out_width, |
| 2204 | out_height); | 2173 | out_height); |
| 2205 | 2174 | ||
| @@ -2208,7 +2177,7 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, | |||
| 2208 | in_height < out_height * 2) | 2177 | in_height < out_height * 2) |
| 2209 | *five_taps = false; | 2178 | *five_taps = false; |
| 2210 | if (!*five_taps) | 2179 | if (!*five_taps) |
| 2211 | *core_clk = dispc.feat->calc_core_clk(plane, in_width, | 2180 | *core_clk = dispc.feat->calc_core_clk(pclk, in_width, |
| 2212 | in_height, out_width, out_height, | 2181 | in_height, out_width, out_height, |
| 2213 | mem_to_mem); | 2182 | mem_to_mem); |
| 2214 | 2183 | ||
| @@ -2227,8 +2196,8 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, | |||
| 2227 | } | 2196 | } |
| 2228 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); | 2197 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); |
| 2229 | 2198 | ||
| 2230 | if (check_horiz_timing_omap3(plane, mgr_timings, pos_x, width, height, | 2199 | if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, width, |
| 2231 | out_width, out_height)){ | 2200 | height, out_width, out_height)){ |
| 2232 | DSSERR("horizontal timing too tight\n"); | 2201 | DSSERR("horizontal timing too tight\n"); |
| 2233 | return -EINVAL; | 2202 | return -EINVAL; |
| 2234 | } | 2203 | } |
| @@ -2246,7 +2215,7 @@ static int dispc_ovl_calc_scaling_34xx(enum omap_plane plane, | |||
| 2246 | return 0; | 2215 | return 0; |
| 2247 | } | 2216 | } |
| 2248 | 2217 | ||
| 2249 | static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, | 2218 | static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, |
| 2250 | const struct omap_video_timings *mgr_timings, | 2219 | const struct omap_video_timings *mgr_timings, |
| 2251 | u16 width, u16 height, u16 out_width, u16 out_height, | 2220 | u16 width, u16 height, u16 out_width, u16 out_height, |
| 2252 | enum omap_color_mode color_mode, bool *five_taps, | 2221 | enum omap_color_mode color_mode, bool *five_taps, |
| @@ -2258,14 +2227,14 @@ static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, | |||
| 2258 | u16 in_height = DIV_ROUND_UP(height, *decim_y); | 2227 | u16 in_height = DIV_ROUND_UP(height, *decim_y); |
| 2259 | const int maxsinglelinewidth = | 2228 | const int maxsinglelinewidth = |
| 2260 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | 2229 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); |
| 2261 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
| 2262 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | 2230 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); |
| 2263 | 2231 | ||
| 2264 | if (mem_to_mem) | 2232 | if (mem_to_mem) { |
| 2265 | in_width_max = DIV_ROUND_UP(out_width, maxdownscale); | 2233 | in_width_max = out_width * maxdownscale; |
| 2266 | else | 2234 | } else { |
| 2267 | in_width_max = dispc_core_clk_rate() / | 2235 | in_width_max = dispc_core_clk_rate() / |
| 2268 | DIV_ROUND_UP(pclk, out_width); | 2236 | DIV_ROUND_UP(pclk, out_width); |
| 2237 | } | ||
| 2269 | 2238 | ||
| 2270 | *decim_x = DIV_ROUND_UP(width, in_width_max); | 2239 | *decim_x = DIV_ROUND_UP(width, in_width_max); |
| 2271 | 2240 | ||
| @@ -2283,12 +2252,12 @@ static int dispc_ovl_calc_scaling_44xx(enum omap_plane plane, | |||
| 2283 | return -EINVAL; | 2252 | return -EINVAL; |
| 2284 | } | 2253 | } |
| 2285 | 2254 | ||
| 2286 | *core_clk = dispc.feat->calc_core_clk(plane, in_width, in_height, | 2255 | *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height, |
| 2287 | out_width, out_height, mem_to_mem); | 2256 | out_width, out_height, mem_to_mem); |
| 2288 | return 0; | 2257 | return 0; |
| 2289 | } | 2258 | } |
| 2290 | 2259 | ||
| 2291 | static int dispc_ovl_calc_scaling(enum omap_plane plane, | 2260 | static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, |
| 2292 | enum omap_overlay_caps caps, | 2261 | enum omap_overlay_caps caps, |
| 2293 | const struct omap_video_timings *mgr_timings, | 2262 | const struct omap_video_timings *mgr_timings, |
| 2294 | u16 width, u16 height, u16 out_width, u16 out_height, | 2263 | u16 width, u16 height, u16 out_width, u16 out_height, |
| @@ -2307,9 +2276,14 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
| 2307 | if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) | 2276 | if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) |
| 2308 | return -EINVAL; | 2277 | return -EINVAL; |
| 2309 | 2278 | ||
| 2310 | *x_predecim = max_decim_limit; | 2279 | if (mem_to_mem) { |
| 2311 | *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && | 2280 | *x_predecim = *y_predecim = 1; |
| 2312 | dss_has_feature(FEAT_BURST_2D)) ? 2 : max_decim_limit; | 2281 | } else { |
| 2282 | *x_predecim = max_decim_limit; | ||
| 2283 | *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && | ||
| 2284 | dss_has_feature(FEAT_BURST_2D)) ? | ||
| 2285 | 2 : max_decim_limit; | ||
| 2286 | } | ||
| 2313 | 2287 | ||
| 2314 | if (color_mode == OMAP_DSS_COLOR_CLUT1 || | 2288 | if (color_mode == OMAP_DSS_COLOR_CLUT1 || |
| 2315 | color_mode == OMAP_DSS_COLOR_CLUT2 || | 2289 | color_mode == OMAP_DSS_COLOR_CLUT2 || |
| @@ -2330,7 +2304,7 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
| 2330 | if (decim_y > *y_predecim || out_height > height * 8) | 2304 | if (decim_y > *y_predecim || out_height > height * 8) |
| 2331 | return -EINVAL; | 2305 | return -EINVAL; |
| 2332 | 2306 | ||
| 2333 | ret = dispc.feat->calc_scaling(plane, mgr_timings, width, height, | 2307 | ret = dispc.feat->calc_scaling(pclk, lclk, mgr_timings, width, height, |
| 2334 | out_width, out_height, color_mode, five_taps, | 2308 | out_width, out_height, color_mode, five_taps, |
| 2335 | x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, | 2309 | x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, |
| 2336 | mem_to_mem); | 2310 | mem_to_mem); |
| @@ -2353,6 +2327,47 @@ static int dispc_ovl_calc_scaling(enum omap_plane plane, | |||
| 2353 | return 0; | 2327 | return 0; |
| 2354 | } | 2328 | } |
| 2355 | 2329 | ||
| 2330 | int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel, | ||
| 2331 | const struct omap_overlay_info *oi, | ||
| 2332 | const struct omap_video_timings *timings, | ||
| 2333 | int *x_predecim, int *y_predecim) | ||
| 2334 | { | ||
| 2335 | enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane); | ||
| 2336 | bool five_taps = true; | ||
| 2337 | bool fieldmode = 0; | ||
| 2338 | u16 in_height = oi->height; | ||
| 2339 | u16 in_width = oi->width; | ||
| 2340 | bool ilace = timings->interlace; | ||
| 2341 | u16 out_width, out_height; | ||
| 2342 | int pos_x = oi->pos_x; | ||
| 2343 | unsigned long pclk = dispc_mgr_pclk_rate(channel); | ||
| 2344 | unsigned long lclk = dispc_mgr_lclk_rate(channel); | ||
| 2345 | |||
| 2346 | out_width = oi->out_width == 0 ? oi->width : oi->out_width; | ||
| 2347 | out_height = oi->out_height == 0 ? oi->height : oi->out_height; | ||
| 2348 | |||
| 2349 | if (ilace && oi->height == out_height) | ||
| 2350 | fieldmode = 1; | ||
| 2351 | |||
| 2352 | if (ilace) { | ||
| 2353 | if (fieldmode) | ||
| 2354 | in_height /= 2; | ||
| 2355 | out_height /= 2; | ||
| 2356 | |||
| 2357 | DSSDBG("adjusting for ilace: height %d, out_height %d\n", | ||
| 2358 | in_height, out_height); | ||
| 2359 | } | ||
| 2360 | |||
| 2361 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) | ||
| 2362 | return -EINVAL; | ||
| 2363 | |||
| 2364 | return dispc_ovl_calc_scaling(pclk, lclk, caps, timings, in_width, | ||
| 2365 | in_height, out_width, out_height, oi->color_mode, | ||
| 2366 | &five_taps, x_predecim, y_predecim, pos_x, | ||
| 2367 | oi->rotation_type, false); | ||
| 2368 | } | ||
| 2369 | EXPORT_SYMBOL(dispc_ovl_check); | ||
| 2370 | |||
| 2356 | static int dispc_ovl_setup_common(enum omap_plane plane, | 2371 | static int dispc_ovl_setup_common(enum omap_plane plane, |
| 2357 | enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, | 2372 | enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, |
| 2358 | u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, | 2373 | u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, |
| @@ -2368,12 +2383,14 @@ static int dispc_ovl_setup_common(enum omap_plane plane, | |||
| 2368 | unsigned offset0, offset1; | 2383 | unsigned offset0, offset1; |
| 2369 | s32 row_inc; | 2384 | s32 row_inc; |
| 2370 | s32 pix_inc; | 2385 | s32 pix_inc; |
| 2371 | u16 frame_height = height; | 2386 | u16 frame_width, frame_height; |
| 2372 | unsigned int field_offset = 0; | 2387 | unsigned int field_offset = 0; |
| 2373 | u16 in_height = height; | 2388 | u16 in_height = height; |
| 2374 | u16 in_width = width; | 2389 | u16 in_width = width; |
| 2375 | int x_predecim = 1, y_predecim = 1; | 2390 | int x_predecim = 1, y_predecim = 1; |
| 2376 | bool ilace = mgr_timings->interlace; | 2391 | bool ilace = mgr_timings->interlace; |
| 2392 | unsigned long pclk = dispc_plane_pclk_rate(plane); | ||
| 2393 | unsigned long lclk = dispc_plane_lclk_rate(plane); | ||
| 2377 | 2394 | ||
| 2378 | if (paddr == 0) | 2395 | if (paddr == 0) |
| 2379 | return -EINVAL; | 2396 | return -EINVAL; |
| @@ -2398,7 +2415,7 @@ static int dispc_ovl_setup_common(enum omap_plane plane, | |||
| 2398 | if (!dss_feat_color_mode_supported(plane, color_mode)) | 2415 | if (!dss_feat_color_mode_supported(plane, color_mode)) |
| 2399 | return -EINVAL; | 2416 | return -EINVAL; |
| 2400 | 2417 | ||
| 2401 | r = dispc_ovl_calc_scaling(plane, caps, mgr_timings, in_width, | 2418 | r = dispc_ovl_calc_scaling(pclk, lclk, caps, mgr_timings, in_width, |
| 2402 | in_height, out_width, out_height, color_mode, | 2419 | in_height, out_width, out_height, color_mode, |
| 2403 | &five_taps, &x_predecim, &y_predecim, pos_x, | 2420 | &five_taps, &x_predecim, &y_predecim, pos_x, |
| 2404 | rotation_type, mem_to_mem); | 2421 | rotation_type, mem_to_mem); |
| @@ -2436,20 +2453,28 @@ static int dispc_ovl_setup_common(enum omap_plane plane, | |||
| 2436 | row_inc = 0; | 2453 | row_inc = 0; |
| 2437 | pix_inc = 0; | 2454 | pix_inc = 0; |
| 2438 | 2455 | ||
| 2456 | if (plane == OMAP_DSS_WB) { | ||
| 2457 | frame_width = out_width; | ||
| 2458 | frame_height = out_height; | ||
| 2459 | } else { | ||
| 2460 | frame_width = in_width; | ||
| 2461 | frame_height = height; | ||
| 2462 | } | ||
| 2463 | |||
| 2439 | if (rotation_type == OMAP_DSS_ROT_TILER) | 2464 | if (rotation_type == OMAP_DSS_ROT_TILER) |
| 2440 | calc_tiler_rotation_offset(screen_width, in_width, | 2465 | calc_tiler_rotation_offset(screen_width, frame_width, |
| 2441 | color_mode, fieldmode, field_offset, | 2466 | color_mode, fieldmode, field_offset, |
| 2442 | &offset0, &offset1, &row_inc, &pix_inc, | 2467 | &offset0, &offset1, &row_inc, &pix_inc, |
| 2443 | x_predecim, y_predecim); | 2468 | x_predecim, y_predecim); |
| 2444 | else if (rotation_type == OMAP_DSS_ROT_DMA) | 2469 | else if (rotation_type == OMAP_DSS_ROT_DMA) |
| 2445 | calc_dma_rotation_offset(rotation, mirror, | 2470 | calc_dma_rotation_offset(rotation, mirror, screen_width, |
| 2446 | screen_width, in_width, frame_height, | 2471 | frame_width, frame_height, |
| 2447 | color_mode, fieldmode, field_offset, | 2472 | color_mode, fieldmode, field_offset, |
| 2448 | &offset0, &offset1, &row_inc, &pix_inc, | 2473 | &offset0, &offset1, &row_inc, &pix_inc, |
| 2449 | x_predecim, y_predecim); | 2474 | x_predecim, y_predecim); |
| 2450 | else | 2475 | else |
| 2451 | calc_vrfb_rotation_offset(rotation, mirror, | 2476 | calc_vrfb_rotation_offset(rotation, mirror, |
| 2452 | screen_width, in_width, frame_height, | 2477 | screen_width, frame_width, frame_height, |
| 2453 | color_mode, fieldmode, field_offset, | 2478 | color_mode, fieldmode, field_offset, |
| 2454 | &offset0, &offset1, &row_inc, &pix_inc, | 2479 | &offset0, &offset1, &row_inc, &pix_inc, |
| 2455 | x_predecim, y_predecim); | 2480 | x_predecim, y_predecim); |
| @@ -2503,7 +2528,7 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, | |||
| 2503 | bool mem_to_mem) | 2528 | bool mem_to_mem) |
| 2504 | { | 2529 | { |
| 2505 | int r; | 2530 | int r; |
| 2506 | struct omap_overlay *ovl = omap_dss_get_overlay(plane); | 2531 | enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane); |
| 2507 | enum omap_channel channel; | 2532 | enum omap_channel channel; |
| 2508 | 2533 | ||
| 2509 | channel = dispc_ovl_get_channel_out(plane); | 2534 | channel = dispc_ovl_get_channel_out(plane); |
| @@ -2514,7 +2539,7 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, | |||
| 2514 | oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, | 2539 | oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, |
| 2515 | oi->color_mode, oi->rotation, oi->mirror, channel, replication); | 2540 | oi->color_mode, oi->rotation, oi->mirror, channel, replication); |
| 2516 | 2541 | ||
| 2517 | r = dispc_ovl_setup_common(plane, ovl->caps, oi->paddr, oi->p_uv_addr, | 2542 | r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr, |
| 2518 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, | 2543 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, |
| 2519 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, | 2544 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, |
| 2520 | oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, | 2545 | oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, |
| @@ -2522,6 +2547,7 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, | |||
| 2522 | 2547 | ||
| 2523 | return r; | 2548 | return r; |
| 2524 | } | 2549 | } |
| 2550 | EXPORT_SYMBOL(dispc_ovl_setup); | ||
| 2525 | 2551 | ||
| 2526 | int dispc_wb_setup(const struct omap_dss_writeback_info *wi, | 2552 | int dispc_wb_setup(const struct omap_dss_writeback_info *wi, |
| 2527 | bool mem_to_mem, const struct omap_video_timings *mgr_timings) | 2553 | bool mem_to_mem, const struct omap_video_timings *mgr_timings) |
| @@ -2582,192 +2608,39 @@ int dispc_ovl_enable(enum omap_plane plane, bool enable) | |||
| 2582 | 2608 | ||
| 2583 | return 0; | 2609 | return 0; |
| 2584 | } | 2610 | } |
| 2611 | EXPORT_SYMBOL(dispc_ovl_enable); | ||
| 2585 | 2612 | ||
| 2586 | static void dispc_disable_isr(void *data, u32 mask) | 2613 | bool dispc_ovl_enabled(enum omap_plane plane) |
| 2587 | { | 2614 | { |
| 2588 | struct completion *compl = data; | 2615 | return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); |
| 2589 | complete(compl); | ||
| 2590 | } | 2616 | } |
| 2617 | EXPORT_SYMBOL(dispc_ovl_enabled); | ||
| 2591 | 2618 | ||
| 2592 | static void _enable_lcd_out(enum omap_channel channel, bool enable) | 2619 | void dispc_mgr_enable(enum omap_channel channel, bool enable) |
| 2593 | { | 2620 | { |
| 2594 | mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable); | 2621 | mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable); |
| 2595 | /* flush posted write */ | 2622 | /* flush posted write */ |
| 2596 | mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); | 2623 | mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); |
| 2597 | } | 2624 | } |
| 2598 | 2625 | EXPORT_SYMBOL(dispc_mgr_enable); | |
| 2599 | static void dispc_mgr_enable_lcd_out(enum omap_channel channel, bool enable) | ||
| 2600 | { | ||
| 2601 | struct completion frame_done_completion; | ||
| 2602 | bool is_on; | ||
| 2603 | int r; | ||
| 2604 | u32 irq; | ||
| 2605 | |||
| 2606 | /* When we disable LCD output, we need to wait until frame is done. | ||
| 2607 | * Otherwise the DSS is still working, and turning off the clocks | ||
| 2608 | * prevents DSS from going to OFF mode */ | ||
| 2609 | is_on = mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); | ||
| 2610 | |||
| 2611 | irq = mgr_desc[channel].framedone_irq; | ||
| 2612 | |||
| 2613 | if (!enable && is_on) { | ||
| 2614 | init_completion(&frame_done_completion); | ||
| 2615 | |||
| 2616 | r = omap_dispc_register_isr(dispc_disable_isr, | ||
| 2617 | &frame_done_completion, irq); | ||
| 2618 | |||
| 2619 | if (r) | ||
| 2620 | DSSERR("failed to register FRAMEDONE isr\n"); | ||
| 2621 | } | ||
| 2622 | |||
| 2623 | _enable_lcd_out(channel, enable); | ||
| 2624 | |||
| 2625 | if (!enable && is_on) { | ||
| 2626 | if (!wait_for_completion_timeout(&frame_done_completion, | ||
| 2627 | msecs_to_jiffies(100))) | ||
| 2628 | DSSERR("timeout waiting for FRAME DONE\n"); | ||
| 2629 | |||
| 2630 | r = omap_dispc_unregister_isr(dispc_disable_isr, | ||
| 2631 | &frame_done_completion, irq); | ||
| 2632 | |||
| 2633 | if (r) | ||
| 2634 | DSSERR("failed to unregister FRAMEDONE isr\n"); | ||
| 2635 | } | ||
| 2636 | } | ||
| 2637 | |||
| 2638 | static void _enable_digit_out(bool enable) | ||
| 2639 | { | ||
| 2640 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); | ||
| 2641 | /* flush posted write */ | ||
| 2642 | dispc_read_reg(DISPC_CONTROL); | ||
| 2643 | } | ||
| 2644 | |||
| 2645 | static void dispc_mgr_enable_digit_out(bool enable) | ||
| 2646 | { | ||
| 2647 | struct completion frame_done_completion; | ||
| 2648 | enum dss_hdmi_venc_clk_source_select src; | ||
| 2649 | int r, i; | ||
| 2650 | u32 irq_mask; | ||
| 2651 | int num_irqs; | ||
| 2652 | |||
| 2653 | if (REG_GET(DISPC_CONTROL, 1, 1) == enable) | ||
| 2654 | return; | ||
| 2655 | |||
| 2656 | src = dss_get_hdmi_venc_clk_source(); | ||
| 2657 | |||
| 2658 | if (enable) { | ||
| 2659 | unsigned long flags; | ||
| 2660 | /* When we enable digit output, we'll get an extra digit | ||
| 2661 | * sync lost interrupt, that we need to ignore */ | ||
| 2662 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
| 2663 | dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; | ||
| 2664 | _omap_dispc_set_irqs(); | ||
| 2665 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
| 2666 | } | ||
| 2667 | |||
| 2668 | /* When we disable digit output, we need to wait until fields are done. | ||
| 2669 | * Otherwise the DSS is still working, and turning off the clocks | ||
| 2670 | * prevents DSS from going to OFF mode. And when enabling, we need to | ||
| 2671 | * wait for the extra sync losts */ | ||
| 2672 | init_completion(&frame_done_completion); | ||
| 2673 | |||
| 2674 | if (src == DSS_HDMI_M_PCLK && enable == false) { | ||
| 2675 | irq_mask = DISPC_IRQ_FRAMEDONETV; | ||
| 2676 | num_irqs = 1; | ||
| 2677 | } else { | ||
| 2678 | irq_mask = DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD; | ||
| 2679 | /* XXX I understand from TRM that we should only wait for the | ||
| 2680 | * current field to complete. But it seems we have to wait for | ||
| 2681 | * both fields */ | ||
| 2682 | num_irqs = 2; | ||
| 2683 | } | ||
| 2684 | |||
| 2685 | r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion, | ||
| 2686 | irq_mask); | ||
| 2687 | if (r) | ||
| 2688 | DSSERR("failed to register %x isr\n", irq_mask); | ||
| 2689 | |||
| 2690 | _enable_digit_out(enable); | ||
| 2691 | |||
| 2692 | for (i = 0; i < num_irqs; ++i) { | ||
| 2693 | if (!wait_for_completion_timeout(&frame_done_completion, | ||
| 2694 | msecs_to_jiffies(100))) | ||
| 2695 | DSSERR("timeout waiting for digit out to %s\n", | ||
| 2696 | enable ? "start" : "stop"); | ||
| 2697 | } | ||
| 2698 | |||
| 2699 | r = omap_dispc_unregister_isr(dispc_disable_isr, &frame_done_completion, | ||
| 2700 | irq_mask); | ||
| 2701 | if (r) | ||
| 2702 | DSSERR("failed to unregister %x isr\n", irq_mask); | ||
| 2703 | |||
| 2704 | if (enable) { | ||
| 2705 | unsigned long flags; | ||
| 2706 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
| 2707 | dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST_DIGIT; | ||
| 2708 | dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); | ||
| 2709 | _omap_dispc_set_irqs(); | ||
| 2710 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
| 2711 | } | ||
| 2712 | } | ||
| 2713 | 2626 | ||
| 2714 | bool dispc_mgr_is_enabled(enum omap_channel channel) | 2627 | bool dispc_mgr_is_enabled(enum omap_channel channel) |
| 2715 | { | 2628 | { |
| 2716 | return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); | 2629 | return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); |
| 2717 | } | 2630 | } |
| 2718 | 2631 | EXPORT_SYMBOL(dispc_mgr_is_enabled); | |
| 2719 | void dispc_mgr_enable(enum omap_channel channel, bool enable) | ||
| 2720 | { | ||
| 2721 | if (dss_mgr_is_lcd(channel)) | ||
| 2722 | dispc_mgr_enable_lcd_out(channel, enable); | ||
| 2723 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) | ||
| 2724 | dispc_mgr_enable_digit_out(enable); | ||
| 2725 | else | ||
| 2726 | BUG(); | ||
| 2727 | } | ||
| 2728 | 2632 | ||
| 2729 | void dispc_wb_enable(bool enable) | 2633 | void dispc_wb_enable(bool enable) |
| 2730 | { | 2634 | { |
| 2731 | enum omap_plane plane = OMAP_DSS_WB; | 2635 | dispc_ovl_enable(OMAP_DSS_WB, enable); |
| 2732 | struct completion frame_done_completion; | ||
| 2733 | bool is_on; | ||
| 2734 | int r; | ||
| 2735 | u32 irq; | ||
| 2736 | |||
| 2737 | is_on = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); | ||
| 2738 | irq = DISPC_IRQ_FRAMEDONEWB; | ||
| 2739 | |||
| 2740 | if (!enable && is_on) { | ||
| 2741 | init_completion(&frame_done_completion); | ||
| 2742 | |||
| 2743 | r = omap_dispc_register_isr(dispc_disable_isr, | ||
| 2744 | &frame_done_completion, irq); | ||
| 2745 | if (r) | ||
| 2746 | DSSERR("failed to register FRAMEDONEWB isr\n"); | ||
| 2747 | } | ||
| 2748 | |||
| 2749 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); | ||
| 2750 | |||
| 2751 | if (!enable && is_on) { | ||
| 2752 | if (!wait_for_completion_timeout(&frame_done_completion, | ||
| 2753 | msecs_to_jiffies(100))) | ||
| 2754 | DSSERR("timeout waiting for FRAMEDONEWB\n"); | ||
| 2755 | |||
| 2756 | r = omap_dispc_unregister_isr(dispc_disable_isr, | ||
| 2757 | &frame_done_completion, irq); | ||
| 2758 | if (r) | ||
| 2759 | DSSERR("failed to unregister FRAMEDONEWB isr\n"); | ||
| 2760 | } | ||
| 2761 | } | 2636 | } |
| 2762 | 2637 | ||
| 2763 | bool dispc_wb_is_enabled(void) | 2638 | bool dispc_wb_is_enabled(void) |
| 2764 | { | 2639 | { |
| 2765 | enum omap_plane plane = OMAP_DSS_WB; | 2640 | return dispc_ovl_enabled(OMAP_DSS_WB); |
| 2766 | |||
| 2767 | return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); | ||
| 2768 | } | 2641 | } |
| 2769 | 2642 | ||
| 2770 | void dispc_lcd_enable_signal_polarity(bool act_high) | 2643 | static void dispc_lcd_enable_signal_polarity(bool act_high) |
| 2771 | { | 2644 | { |
| 2772 | if (!dss_has_feature(FEAT_LCDENABLEPOL)) | 2645 | if (!dss_has_feature(FEAT_LCDENABLEPOL)) |
| 2773 | return; | 2646 | return; |
| @@ -2791,13 +2664,13 @@ void dispc_pck_free_enable(bool enable) | |||
| 2791 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); | 2664 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); |
| 2792 | } | 2665 | } |
| 2793 | 2666 | ||
| 2794 | void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable) | 2667 | static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable) |
| 2795 | { | 2668 | { |
| 2796 | mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable); | 2669 | mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable); |
| 2797 | } | 2670 | } |
| 2798 | 2671 | ||
| 2799 | 2672 | ||
| 2800 | void dispc_mgr_set_lcd_type_tft(enum omap_channel channel) | 2673 | static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel) |
| 2801 | { | 2674 | { |
| 2802 | mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1); | 2675 | mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1); |
| 2803 | } | 2676 | } |
| @@ -2840,7 +2713,7 @@ static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, | |||
| 2840 | } | 2713 | } |
| 2841 | 2714 | ||
| 2842 | void dispc_mgr_setup(enum omap_channel channel, | 2715 | void dispc_mgr_setup(enum omap_channel channel, |
| 2843 | struct omap_overlay_manager_info *info) | 2716 | const struct omap_overlay_manager_info *info) |
| 2844 | { | 2717 | { |
| 2845 | dispc_mgr_set_default_color(channel, info->default_color); | 2718 | dispc_mgr_set_default_color(channel, info->default_color); |
| 2846 | dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); | 2719 | dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); |
| @@ -2852,8 +2725,9 @@ void dispc_mgr_setup(enum omap_channel channel, | |||
| 2852 | dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); | 2725 | dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); |
| 2853 | } | 2726 | } |
| 2854 | } | 2727 | } |
| 2728 | EXPORT_SYMBOL(dispc_mgr_setup); | ||
| 2855 | 2729 | ||
| 2856 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) | 2730 | static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) |
| 2857 | { | 2731 | { |
| 2858 | int code; | 2732 | int code; |
| 2859 | 2733 | ||
| @@ -2878,7 +2752,7 @@ void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) | |||
| 2878 | mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code); | 2752 | mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code); |
| 2879 | } | 2753 | } |
| 2880 | 2754 | ||
| 2881 | void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) | 2755 | static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) |
| 2882 | { | 2756 | { |
| 2883 | u32 l; | 2757 | u32 l; |
| 2884 | int gpout0, gpout1; | 2758 | int gpout0, gpout1; |
| @@ -2907,15 +2781,33 @@ void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) | |||
| 2907 | dispc_write_reg(DISPC_CONTROL, l); | 2781 | dispc_write_reg(DISPC_CONTROL, l); |
| 2908 | } | 2782 | } |
| 2909 | 2783 | ||
| 2910 | void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) | 2784 | static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) |
| 2911 | { | 2785 | { |
| 2912 | mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable); | 2786 | mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable); |
| 2913 | } | 2787 | } |
| 2914 | 2788 | ||
| 2789 | void dispc_mgr_set_lcd_config(enum omap_channel channel, | ||
| 2790 | const struct dss_lcd_mgr_config *config) | ||
| 2791 | { | ||
| 2792 | dispc_mgr_set_io_pad_mode(config->io_pad_mode); | ||
| 2793 | |||
| 2794 | dispc_mgr_enable_stallmode(channel, config->stallmode); | ||
| 2795 | dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck); | ||
| 2796 | |||
| 2797 | dispc_mgr_set_clock_div(channel, &config->clock_info); | ||
| 2798 | |||
| 2799 | dispc_mgr_set_tft_data_lines(channel, config->video_port_width); | ||
| 2800 | |||
| 2801 | dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity); | ||
| 2802 | |||
| 2803 | dispc_mgr_set_lcd_type_tft(channel); | ||
| 2804 | } | ||
| 2805 | EXPORT_SYMBOL(dispc_mgr_set_lcd_config); | ||
| 2806 | |||
| 2915 | static bool _dispc_mgr_size_ok(u16 width, u16 height) | 2807 | static bool _dispc_mgr_size_ok(u16 width, u16 height) |
| 2916 | { | 2808 | { |
| 2917 | return width <= dss_feat_get_param_max(FEAT_PARAM_MGR_WIDTH) && | 2809 | return width <= dispc.feat->mgr_width_max && |
| 2918 | height <= dss_feat_get_param_max(FEAT_PARAM_MGR_HEIGHT); | 2810 | height <= dispc.feat->mgr_height_max; |
| 2919 | } | 2811 | } |
| 2920 | 2812 | ||
| 2921 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, | 2813 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, |
| @@ -3010,7 +2902,7 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, | |||
| 3010 | 2902 | ||
| 3011 | /* change name to mode? */ | 2903 | /* change name to mode? */ |
| 3012 | void dispc_mgr_set_timings(enum omap_channel channel, | 2904 | void dispc_mgr_set_timings(enum omap_channel channel, |
| 3013 | struct omap_video_timings *timings) | 2905 | const struct omap_video_timings *timings) |
| 3014 | { | 2906 | { |
| 3015 | unsigned xtot, ytot; | 2907 | unsigned xtot, ytot; |
| 3016 | unsigned long ht, vt; | 2908 | unsigned long ht, vt; |
| @@ -3049,6 +2941,7 @@ void dispc_mgr_set_timings(enum omap_channel channel, | |||
| 3049 | 2941 | ||
| 3050 | dispc_mgr_set_size(channel, t.x_res, t.y_res); | 2942 | dispc_mgr_set_size(channel, t.x_res, t.y_res); |
| 3051 | } | 2943 | } |
| 2944 | EXPORT_SYMBOL(dispc_mgr_set_timings); | ||
| 3052 | 2945 | ||
| 3053 | static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, | 2946 | static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, |
| 3054 | u16 pck_div) | 2947 | u16 pck_div) |
| @@ -3076,7 +2969,7 @@ unsigned long dispc_fclk_rate(void) | |||
| 3076 | 2969 | ||
| 3077 | switch (dss_get_dispc_clk_source()) { | 2970 | switch (dss_get_dispc_clk_source()) { |
| 3078 | case OMAP_DSS_CLK_SRC_FCK: | 2971 | case OMAP_DSS_CLK_SRC_FCK: |
| 3079 | r = clk_get_rate(dispc.dss_clk); | 2972 | r = dss_get_dispc_clk_rate(); |
| 3080 | break; | 2973 | break; |
| 3081 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | 2974 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: |
| 3082 | dsidev = dsi_get_dsidev_from_id(0); | 2975 | dsidev = dsi_get_dsidev_from_id(0); |
| @@ -3101,28 +2994,32 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) | |||
| 3101 | unsigned long r; | 2994 | unsigned long r; |
| 3102 | u32 l; | 2995 | u32 l; |
| 3103 | 2996 | ||
| 3104 | l = dispc_read_reg(DISPC_DIVISORo(channel)); | 2997 | if (dss_mgr_is_lcd(channel)) { |
| 2998 | l = dispc_read_reg(DISPC_DIVISORo(channel)); | ||
| 3105 | 2999 | ||
| 3106 | lcd = FLD_GET(l, 23, 16); | 3000 | lcd = FLD_GET(l, 23, 16); |
| 3107 | 3001 | ||
| 3108 | switch (dss_get_lcd_clk_source(channel)) { | 3002 | switch (dss_get_lcd_clk_source(channel)) { |
| 3109 | case OMAP_DSS_CLK_SRC_FCK: | 3003 | case OMAP_DSS_CLK_SRC_FCK: |
| 3110 | r = clk_get_rate(dispc.dss_clk); | 3004 | r = dss_get_dispc_clk_rate(); |
| 3111 | break; | 3005 | break; |
| 3112 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | 3006 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: |
| 3113 | dsidev = dsi_get_dsidev_from_id(0); | 3007 | dsidev = dsi_get_dsidev_from_id(0); |
| 3114 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); | 3008 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); |
| 3115 | break; | 3009 | break; |
| 3116 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: | 3010 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: |
| 3117 | dsidev = dsi_get_dsidev_from_id(1); | 3011 | dsidev = dsi_get_dsidev_from_id(1); |
| 3118 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); | 3012 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); |
| 3119 | break; | 3013 | break; |
| 3120 | default: | 3014 | default: |
| 3121 | BUG(); | 3015 | BUG(); |
| 3122 | return 0; | 3016 | return 0; |
| 3123 | } | 3017 | } |
| 3124 | 3018 | ||
| 3125 | return r / lcd; | 3019 | return r / lcd; |
| 3020 | } else { | ||
| 3021 | return dispc_fclk_rate(); | ||
| 3022 | } | ||
| 3126 | } | 3023 | } |
| 3127 | 3024 | ||
| 3128 | unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) | 3025 | unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) |
| @@ -3172,21 +3069,28 @@ unsigned long dispc_core_clk_rate(void) | |||
| 3172 | 3069 | ||
| 3173 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) | 3070 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) |
| 3174 | { | 3071 | { |
| 3175 | enum omap_channel channel = dispc_ovl_get_channel_out(plane); | 3072 | enum omap_channel channel; |
| 3073 | |||
| 3074 | if (plane == OMAP_DSS_WB) | ||
| 3075 | return 0; | ||
| 3076 | |||
| 3077 | channel = dispc_ovl_get_channel_out(plane); | ||
| 3176 | 3078 | ||
| 3177 | return dispc_mgr_pclk_rate(channel); | 3079 | return dispc_mgr_pclk_rate(channel); |
| 3178 | } | 3080 | } |
| 3179 | 3081 | ||
| 3180 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) | 3082 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) |
| 3181 | { | 3083 | { |
| 3182 | enum omap_channel channel = dispc_ovl_get_channel_out(plane); | 3084 | enum omap_channel channel; |
| 3183 | 3085 | ||
| 3184 | if (dss_mgr_is_lcd(channel)) | 3086 | if (plane == OMAP_DSS_WB) |
| 3185 | return dispc_mgr_lclk_rate(channel); | 3087 | return 0; |
| 3186 | else | 3088 | |
| 3187 | return dispc_fclk_rate(); | 3089 | channel = dispc_ovl_get_channel_out(plane); |
| 3188 | 3090 | ||
| 3091 | return dispc_mgr_lclk_rate(channel); | ||
| 3189 | } | 3092 | } |
| 3093 | |||
| 3190 | static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) | 3094 | static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) |
| 3191 | { | 3095 | { |
| 3192 | int lcd, pcd; | 3096 | int lcd, pcd; |
| @@ -3244,64 +3148,6 @@ void dispc_dump_clocks(struct seq_file *s) | |||
| 3244 | dispc_runtime_put(); | 3148 | dispc_runtime_put(); |
| 3245 | } | 3149 | } |
| 3246 | 3150 | ||
| 3247 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 3248 | void dispc_dump_irqs(struct seq_file *s) | ||
| 3249 | { | ||
| 3250 | unsigned long flags; | ||
| 3251 | struct dispc_irq_stats stats; | ||
| 3252 | |||
| 3253 | spin_lock_irqsave(&dispc.irq_stats_lock, flags); | ||
| 3254 | |||
| 3255 | stats = dispc.irq_stats; | ||
| 3256 | memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats)); | ||
| 3257 | dispc.irq_stats.last_reset = jiffies; | ||
| 3258 | |||
| 3259 | spin_unlock_irqrestore(&dispc.irq_stats_lock, flags); | ||
| 3260 | |||
| 3261 | seq_printf(s, "period %u ms\n", | ||
| 3262 | jiffies_to_msecs(jiffies - stats.last_reset)); | ||
| 3263 | |||
| 3264 | seq_printf(s, "irqs %d\n", stats.irq_count); | ||
| 3265 | #define PIS(x) \ | ||
| 3266 | seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); | ||
| 3267 | |||
| 3268 | PIS(FRAMEDONE); | ||
| 3269 | PIS(VSYNC); | ||
| 3270 | PIS(EVSYNC_EVEN); | ||
| 3271 | PIS(EVSYNC_ODD); | ||
| 3272 | PIS(ACBIAS_COUNT_STAT); | ||
| 3273 | PIS(PROG_LINE_NUM); | ||
| 3274 | PIS(GFX_FIFO_UNDERFLOW); | ||
| 3275 | PIS(GFX_END_WIN); | ||
| 3276 | PIS(PAL_GAMMA_MASK); | ||
| 3277 | PIS(OCP_ERR); | ||
| 3278 | PIS(VID1_FIFO_UNDERFLOW); | ||
| 3279 | PIS(VID1_END_WIN); | ||
| 3280 | PIS(VID2_FIFO_UNDERFLOW); | ||
| 3281 | PIS(VID2_END_WIN); | ||
| 3282 | if (dss_feat_get_num_ovls() > 3) { | ||
| 3283 | PIS(VID3_FIFO_UNDERFLOW); | ||
| 3284 | PIS(VID3_END_WIN); | ||
| 3285 | } | ||
| 3286 | PIS(SYNC_LOST); | ||
| 3287 | PIS(SYNC_LOST_DIGIT); | ||
| 3288 | PIS(WAKEUP); | ||
| 3289 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
| 3290 | PIS(FRAMEDONE2); | ||
| 3291 | PIS(VSYNC2); | ||
| 3292 | PIS(ACBIAS_COUNT_STAT2); | ||
| 3293 | PIS(SYNC_LOST2); | ||
| 3294 | } | ||
| 3295 | if (dss_has_feature(FEAT_MGR_LCD3)) { | ||
| 3296 | PIS(FRAMEDONE3); | ||
| 3297 | PIS(VSYNC3); | ||
| 3298 | PIS(ACBIAS_COUNT_STAT3); | ||
| 3299 | PIS(SYNC_LOST3); | ||
| 3300 | } | ||
| 3301 | #undef PIS | ||
| 3302 | } | ||
| 3303 | #endif | ||
| 3304 | |||
| 3305 | static void dispc_dump_regs(struct seq_file *s) | 3151 | static void dispc_dump_regs(struct seq_file *s) |
| 3306 | { | 3152 | { |
| 3307 | int i, j; | 3153 | int i, j; |
| @@ -3351,7 +3197,7 @@ static void dispc_dump_regs(struct seq_file *s) | |||
| 3351 | 3197 | ||
| 3352 | #define DISPC_REG(i, name) name(i) | 3198 | #define DISPC_REG(i, name) name(i) |
| 3353 | #define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ | 3199 | #define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ |
| 3354 | 48 - strlen(#r) - strlen(p_names[i]), " ", \ | 3200 | (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \ |
| 3355 | dispc_read_reg(DISPC_REG(i, r))) | 3201 | dispc_read_reg(DISPC_REG(i, r))) |
| 3356 | 3202 | ||
| 3357 | p_names = mgr_names; | 3203 | p_names = mgr_names; |
| @@ -3428,7 +3274,7 @@ static void dispc_dump_regs(struct seq_file *s) | |||
| 3428 | #define DISPC_REG(plane, name, i) name(plane, i) | 3274 | #define DISPC_REG(plane, name, i) name(plane, i) |
| 3429 | #define DUMPREG(plane, name, i) \ | 3275 | #define DUMPREG(plane, name, i) \ |
| 3430 | seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \ | 3276 | seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \ |
| 3431 | 46 - strlen(#name) - strlen(p_names[plane]), " ", \ | 3277 | (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \ |
| 3432 | dispc_read_reg(DISPC_REG(plane, name, i))) | 3278 | dispc_read_reg(DISPC_REG(plane, name, i))) |
| 3433 | 3279 | ||
| 3434 | /* Video pipeline coefficient registers */ | 3280 | /* Video pipeline coefficient registers */ |
| @@ -3531,7 +3377,7 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | |||
| 3531 | } | 3377 | } |
| 3532 | 3378 | ||
| 3533 | void dispc_mgr_set_clock_div(enum omap_channel channel, | 3379 | void dispc_mgr_set_clock_div(enum omap_channel channel, |
| 3534 | struct dispc_clock_info *cinfo) | 3380 | const struct dispc_clock_info *cinfo) |
| 3535 | { | 3381 | { |
| 3536 | DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); | 3382 | DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); |
| 3537 | DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); | 3383 | DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); |
| @@ -3555,403 +3401,34 @@ int dispc_mgr_get_clock_div(enum omap_channel channel, | |||
| 3555 | return 0; | 3401 | return 0; |
| 3556 | } | 3402 | } |
| 3557 | 3403 | ||
| 3558 | /* dispc.irq_lock has to be locked by the caller */ | 3404 | u32 dispc_read_irqstatus(void) |
| 3559 | static void _omap_dispc_set_irqs(void) | ||
| 3560 | { | 3405 | { |
| 3561 | u32 mask; | 3406 | return dispc_read_reg(DISPC_IRQSTATUS); |
| 3562 | u32 old_mask; | ||
| 3563 | int i; | ||
| 3564 | struct omap_dispc_isr_data *isr_data; | ||
| 3565 | |||
| 3566 | mask = dispc.irq_error_mask; | ||
| 3567 | |||
| 3568 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 3569 | isr_data = &dispc.registered_isr[i]; | ||
| 3570 | |||
| 3571 | if (isr_data->isr == NULL) | ||
| 3572 | continue; | ||
| 3573 | |||
| 3574 | mask |= isr_data->mask; | ||
| 3575 | } | ||
| 3576 | |||
| 3577 | old_mask = dispc_read_reg(DISPC_IRQENABLE); | ||
| 3578 | /* clear the irqstatus for newly enabled irqs */ | ||
| 3579 | dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask); | ||
| 3580 | |||
| 3581 | dispc_write_reg(DISPC_IRQENABLE, mask); | ||
| 3582 | } | ||
| 3583 | |||
| 3584 | int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) | ||
| 3585 | { | ||
| 3586 | int i; | ||
| 3587 | int ret; | ||
| 3588 | unsigned long flags; | ||
| 3589 | struct omap_dispc_isr_data *isr_data; | ||
| 3590 | |||
| 3591 | if (isr == NULL) | ||
| 3592 | return -EINVAL; | ||
| 3593 | |||
| 3594 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
| 3595 | |||
| 3596 | /* check for duplicate entry */ | ||
| 3597 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 3598 | isr_data = &dispc.registered_isr[i]; | ||
| 3599 | if (isr_data->isr == isr && isr_data->arg == arg && | ||
| 3600 | isr_data->mask == mask) { | ||
| 3601 | ret = -EINVAL; | ||
| 3602 | goto err; | ||
| 3603 | } | ||
| 3604 | } | ||
| 3605 | |||
| 3606 | isr_data = NULL; | ||
| 3607 | ret = -EBUSY; | ||
| 3608 | |||
| 3609 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 3610 | isr_data = &dispc.registered_isr[i]; | ||
| 3611 | |||
| 3612 | if (isr_data->isr != NULL) | ||
| 3613 | continue; | ||
| 3614 | |||
| 3615 | isr_data->isr = isr; | ||
| 3616 | isr_data->arg = arg; | ||
| 3617 | isr_data->mask = mask; | ||
| 3618 | ret = 0; | ||
| 3619 | |||
| 3620 | break; | ||
| 3621 | } | ||
| 3622 | |||
| 3623 | if (ret) | ||
| 3624 | goto err; | ||
| 3625 | |||
| 3626 | _omap_dispc_set_irqs(); | ||
| 3627 | |||
| 3628 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
| 3629 | |||
| 3630 | return 0; | ||
| 3631 | err: | ||
| 3632 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
| 3633 | |||
| 3634 | return ret; | ||
| 3635 | } | ||
| 3636 | EXPORT_SYMBOL(omap_dispc_register_isr); | ||
| 3637 | |||
| 3638 | int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) | ||
| 3639 | { | ||
| 3640 | int i; | ||
| 3641 | unsigned long flags; | ||
| 3642 | int ret = -EINVAL; | ||
| 3643 | struct omap_dispc_isr_data *isr_data; | ||
| 3644 | |||
| 3645 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
| 3646 | |||
| 3647 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 3648 | isr_data = &dispc.registered_isr[i]; | ||
| 3649 | if (isr_data->isr != isr || isr_data->arg != arg || | ||
| 3650 | isr_data->mask != mask) | ||
| 3651 | continue; | ||
| 3652 | |||
| 3653 | /* found the correct isr */ | ||
| 3654 | |||
| 3655 | isr_data->isr = NULL; | ||
| 3656 | isr_data->arg = NULL; | ||
| 3657 | isr_data->mask = 0; | ||
| 3658 | |||
| 3659 | ret = 0; | ||
| 3660 | break; | ||
| 3661 | } | ||
| 3662 | |||
| 3663 | if (ret == 0) | ||
| 3664 | _omap_dispc_set_irqs(); | ||
| 3665 | |||
| 3666 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
| 3667 | |||
| 3668 | return ret; | ||
| 3669 | } | ||
| 3670 | EXPORT_SYMBOL(omap_dispc_unregister_isr); | ||
| 3671 | |||
| 3672 | #ifdef DEBUG | ||
| 3673 | static void print_irq_status(u32 status) | ||
| 3674 | { | ||
| 3675 | if ((status & dispc.irq_error_mask) == 0) | ||
| 3676 | return; | ||
| 3677 | |||
| 3678 | printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status); | ||
| 3679 | |||
| 3680 | #define PIS(x) \ | ||
| 3681 | if (status & DISPC_IRQ_##x) \ | ||
| 3682 | printk(#x " "); | ||
| 3683 | PIS(GFX_FIFO_UNDERFLOW); | ||
| 3684 | PIS(OCP_ERR); | ||
| 3685 | PIS(VID1_FIFO_UNDERFLOW); | ||
| 3686 | PIS(VID2_FIFO_UNDERFLOW); | ||
| 3687 | if (dss_feat_get_num_ovls() > 3) | ||
| 3688 | PIS(VID3_FIFO_UNDERFLOW); | ||
| 3689 | PIS(SYNC_LOST); | ||
| 3690 | PIS(SYNC_LOST_DIGIT); | ||
| 3691 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
| 3692 | PIS(SYNC_LOST2); | ||
| 3693 | if (dss_has_feature(FEAT_MGR_LCD3)) | ||
| 3694 | PIS(SYNC_LOST3); | ||
| 3695 | #undef PIS | ||
| 3696 | |||
| 3697 | printk("\n"); | ||
| 3698 | } | ||
| 3699 | #endif | ||
| 3700 | |||
| 3701 | /* Called from dss.c. Note that we don't touch clocks here, | ||
| 3702 | * but we presume they are on because we got an IRQ. However, | ||
| 3703 | * an irq handler may turn the clocks off, so we may not have | ||
| 3704 | * clock later in the function. */ | ||
| 3705 | static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) | ||
| 3706 | { | ||
| 3707 | int i; | ||
| 3708 | u32 irqstatus, irqenable; | ||
| 3709 | u32 handledirqs = 0; | ||
| 3710 | u32 unhandled_errors; | ||
| 3711 | struct omap_dispc_isr_data *isr_data; | ||
| 3712 | struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; | ||
| 3713 | |||
| 3714 | spin_lock(&dispc.irq_lock); | ||
| 3715 | |||
| 3716 | irqstatus = dispc_read_reg(DISPC_IRQSTATUS); | ||
| 3717 | irqenable = dispc_read_reg(DISPC_IRQENABLE); | ||
| 3718 | |||
| 3719 | /* IRQ is not for us */ | ||
| 3720 | if (!(irqstatus & irqenable)) { | ||
| 3721 | spin_unlock(&dispc.irq_lock); | ||
| 3722 | return IRQ_NONE; | ||
| 3723 | } | ||
| 3724 | |||
| 3725 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 3726 | spin_lock(&dispc.irq_stats_lock); | ||
| 3727 | dispc.irq_stats.irq_count++; | ||
| 3728 | dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs); | ||
| 3729 | spin_unlock(&dispc.irq_stats_lock); | ||
| 3730 | #endif | ||
| 3731 | |||
| 3732 | #ifdef DEBUG | ||
| 3733 | if (dss_debug) | ||
| 3734 | print_irq_status(irqstatus); | ||
| 3735 | #endif | ||
| 3736 | /* Ack the interrupt. Do it here before clocks are possibly turned | ||
| 3737 | * off */ | ||
| 3738 | dispc_write_reg(DISPC_IRQSTATUS, irqstatus); | ||
| 3739 | /* flush posted write */ | ||
| 3740 | dispc_read_reg(DISPC_IRQSTATUS); | ||
| 3741 | |||
| 3742 | /* make a copy and unlock, so that isrs can unregister | ||
| 3743 | * themselves */ | ||
| 3744 | memcpy(registered_isr, dispc.registered_isr, | ||
| 3745 | sizeof(registered_isr)); | ||
| 3746 | |||
| 3747 | spin_unlock(&dispc.irq_lock); | ||
| 3748 | |||
| 3749 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
| 3750 | isr_data = ®istered_isr[i]; | ||
| 3751 | |||
| 3752 | if (!isr_data->isr) | ||
| 3753 | continue; | ||
| 3754 | |||
| 3755 | if (isr_data->mask & irqstatus) { | ||
| 3756 | isr_data->isr(isr_data->arg, irqstatus); | ||
| 3757 | handledirqs |= isr_data->mask; | ||
| 3758 | } | ||
| 3759 | } | ||
| 3760 | |||
| 3761 | spin_lock(&dispc.irq_lock); | ||
| 3762 | |||
| 3763 | unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask; | ||
| 3764 | |||
| 3765 | if (unhandled_errors) { | ||
| 3766 | dispc.error_irqs |= unhandled_errors; | ||
| 3767 | |||
| 3768 | dispc.irq_error_mask &= ~unhandled_errors; | ||
| 3769 | _omap_dispc_set_irqs(); | ||
| 3770 | |||
| 3771 | schedule_work(&dispc.error_work); | ||
| 3772 | } | ||
| 3773 | |||
| 3774 | spin_unlock(&dispc.irq_lock); | ||
| 3775 | |||
| 3776 | return IRQ_HANDLED; | ||
| 3777 | } | ||
| 3778 | |||
| 3779 | static void dispc_error_worker(struct work_struct *work) | ||
| 3780 | { | ||
| 3781 | int i; | ||
| 3782 | u32 errors; | ||
| 3783 | unsigned long flags; | ||
| 3784 | static const unsigned fifo_underflow_bits[] = { | ||
| 3785 | DISPC_IRQ_GFX_FIFO_UNDERFLOW, | ||
| 3786 | DISPC_IRQ_VID1_FIFO_UNDERFLOW, | ||
| 3787 | DISPC_IRQ_VID2_FIFO_UNDERFLOW, | ||
| 3788 | DISPC_IRQ_VID3_FIFO_UNDERFLOW, | ||
| 3789 | }; | ||
| 3790 | |||
| 3791 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
| 3792 | errors = dispc.error_irqs; | ||
| 3793 | dispc.error_irqs = 0; | ||
| 3794 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
| 3795 | |||
| 3796 | dispc_runtime_get(); | ||
| 3797 | |||
| 3798 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
| 3799 | struct omap_overlay *ovl; | ||
| 3800 | unsigned bit; | ||
| 3801 | |||
| 3802 | ovl = omap_dss_get_overlay(i); | ||
| 3803 | bit = fifo_underflow_bits[i]; | ||
| 3804 | |||
| 3805 | if (bit & errors) { | ||
| 3806 | DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", | ||
| 3807 | ovl->name); | ||
| 3808 | dispc_ovl_enable(ovl->id, false); | ||
| 3809 | dispc_mgr_go(ovl->manager->id); | ||
| 3810 | msleep(50); | ||
| 3811 | } | ||
| 3812 | } | ||
| 3813 | |||
| 3814 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
| 3815 | struct omap_overlay_manager *mgr; | ||
| 3816 | unsigned bit; | ||
| 3817 | |||
| 3818 | mgr = omap_dss_get_overlay_manager(i); | ||
| 3819 | bit = mgr_desc[i].sync_lost_irq; | ||
| 3820 | |||
| 3821 | if (bit & errors) { | ||
| 3822 | struct omap_dss_device *dssdev = mgr->get_device(mgr); | ||
| 3823 | bool enable; | ||
| 3824 | |||
| 3825 | DSSERR("SYNC_LOST on channel %s, restarting the output " | ||
| 3826 | "with video overlays disabled\n", | ||
| 3827 | mgr->name); | ||
| 3828 | |||
| 3829 | enable = dssdev->state == OMAP_DSS_DISPLAY_ACTIVE; | ||
| 3830 | dssdev->driver->disable(dssdev); | ||
| 3831 | |||
| 3832 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
| 3833 | struct omap_overlay *ovl; | ||
| 3834 | ovl = omap_dss_get_overlay(i); | ||
| 3835 | |||
| 3836 | if (ovl->id != OMAP_DSS_GFX && | ||
| 3837 | ovl->manager == mgr) | ||
| 3838 | dispc_ovl_enable(ovl->id, false); | ||
| 3839 | } | ||
| 3840 | |||
| 3841 | dispc_mgr_go(mgr->id); | ||
| 3842 | msleep(50); | ||
| 3843 | |||
| 3844 | if (enable) | ||
| 3845 | dssdev->driver->enable(dssdev); | ||
| 3846 | } | ||
| 3847 | } | ||
| 3848 | |||
| 3849 | if (errors & DISPC_IRQ_OCP_ERR) { | ||
| 3850 | DSSERR("OCP_ERR\n"); | ||
| 3851 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
| 3852 | struct omap_overlay_manager *mgr; | ||
| 3853 | struct omap_dss_device *dssdev; | ||
| 3854 | |||
| 3855 | mgr = omap_dss_get_overlay_manager(i); | ||
| 3856 | dssdev = mgr->get_device(mgr); | ||
| 3857 | |||
| 3858 | if (dssdev && dssdev->driver) | ||
| 3859 | dssdev->driver->disable(dssdev); | ||
| 3860 | } | ||
| 3861 | } | ||
| 3862 | |||
| 3863 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
| 3864 | dispc.irq_error_mask |= errors; | ||
| 3865 | _omap_dispc_set_irqs(); | ||
| 3866 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
| 3867 | |||
| 3868 | dispc_runtime_put(); | ||
| 3869 | } | 3407 | } |
| 3408 | EXPORT_SYMBOL(dispc_read_irqstatus); | ||
| 3870 | 3409 | ||
| 3871 | int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout) | 3410 | void dispc_clear_irqstatus(u32 mask) |
| 3872 | { | 3411 | { |
| 3873 | void dispc_irq_wait_handler(void *data, u32 mask) | 3412 | dispc_write_reg(DISPC_IRQSTATUS, mask); |
| 3874 | { | ||
| 3875 | complete((struct completion *)data); | ||
| 3876 | } | ||
| 3877 | |||
| 3878 | int r; | ||
| 3879 | DECLARE_COMPLETION_ONSTACK(completion); | ||
| 3880 | |||
| 3881 | r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, | ||
| 3882 | irqmask); | ||
| 3883 | |||
| 3884 | if (r) | ||
| 3885 | return r; | ||
| 3886 | |||
| 3887 | timeout = wait_for_completion_timeout(&completion, timeout); | ||
| 3888 | |||
| 3889 | omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); | ||
| 3890 | |||
| 3891 | if (timeout == 0) | ||
| 3892 | return -ETIMEDOUT; | ||
| 3893 | |||
| 3894 | if (timeout == -ERESTARTSYS) | ||
| 3895 | return -ERESTARTSYS; | ||
| 3896 | |||
| 3897 | return 0; | ||
| 3898 | } | 3413 | } |
| 3414 | EXPORT_SYMBOL(dispc_clear_irqstatus); | ||
| 3899 | 3415 | ||
| 3900 | int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, | 3416 | u32 dispc_read_irqenable(void) |
| 3901 | unsigned long timeout) | ||
| 3902 | { | 3417 | { |
| 3903 | void dispc_irq_wait_handler(void *data, u32 mask) | 3418 | return dispc_read_reg(DISPC_IRQENABLE); |
| 3904 | { | ||
| 3905 | complete((struct completion *)data); | ||
| 3906 | } | ||
| 3907 | |||
| 3908 | int r; | ||
| 3909 | DECLARE_COMPLETION_ONSTACK(completion); | ||
| 3910 | |||
| 3911 | r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, | ||
| 3912 | irqmask); | ||
| 3913 | |||
| 3914 | if (r) | ||
| 3915 | return r; | ||
| 3916 | |||
| 3917 | timeout = wait_for_completion_interruptible_timeout(&completion, | ||
| 3918 | timeout); | ||
| 3919 | |||
| 3920 | omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); | ||
| 3921 | |||
| 3922 | if (timeout == 0) | ||
| 3923 | return -ETIMEDOUT; | ||
| 3924 | |||
| 3925 | if (timeout == -ERESTARTSYS) | ||
| 3926 | return -ERESTARTSYS; | ||
| 3927 | |||
| 3928 | return 0; | ||
| 3929 | } | 3419 | } |
| 3420 | EXPORT_SYMBOL(dispc_read_irqenable); | ||
| 3930 | 3421 | ||
| 3931 | static void _omap_dispc_initialize_irq(void) | 3422 | void dispc_write_irqenable(u32 mask) |
| 3932 | { | 3423 | { |
| 3933 | unsigned long flags; | 3424 | u32 old_mask = dispc_read_reg(DISPC_IRQENABLE); |
| 3934 | |||
| 3935 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
| 3936 | |||
| 3937 | memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr)); | ||
| 3938 | |||
| 3939 | dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; | ||
| 3940 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
| 3941 | dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; | ||
| 3942 | if (dss_has_feature(FEAT_MGR_LCD3)) | ||
| 3943 | dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST3; | ||
| 3944 | if (dss_feat_get_num_ovls() > 3) | ||
| 3945 | dispc.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; | ||
| 3946 | |||
| 3947 | /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, | ||
| 3948 | * so clear it */ | ||
| 3949 | dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS)); | ||
| 3950 | 3425 | ||
| 3951 | _omap_dispc_set_irqs(); | 3426 | /* clear the irqstatus for newly enabled irqs */ |
| 3427 | dispc_clear_irqstatus((mask ^ old_mask) & mask); | ||
| 3952 | 3428 | ||
| 3953 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | 3429 | dispc_write_reg(DISPC_IRQENABLE, mask); |
| 3954 | } | 3430 | } |
| 3431 | EXPORT_SYMBOL(dispc_write_irqenable); | ||
| 3955 | 3432 | ||
| 3956 | void dispc_enable_sidle(void) | 3433 | void dispc_enable_sidle(void) |
| 3957 | { | 3434 | { |
| @@ -3998,9 +3475,14 @@ static const struct dispc_features omap24xx_dispc_feats __initconst = { | |||
| 3998 | .sw_max = 64, | 3475 | .sw_max = 64, |
| 3999 | .vp_max = 255, | 3476 | .vp_max = 255, |
| 4000 | .hp_max = 256, | 3477 | .hp_max = 256, |
| 3478 | .mgr_width_start = 10, | ||
| 3479 | .mgr_height_start = 26, | ||
| 3480 | .mgr_width_max = 2048, | ||
| 3481 | .mgr_height_max = 2048, | ||
| 4001 | .calc_scaling = dispc_ovl_calc_scaling_24xx, | 3482 | .calc_scaling = dispc_ovl_calc_scaling_24xx, |
| 4002 | .calc_core_clk = calc_core_clk_24xx, | 3483 | .calc_core_clk = calc_core_clk_24xx, |
| 4003 | .num_fifos = 3, | 3484 | .num_fifos = 3, |
| 3485 | .no_framedone_tv = true, | ||
| 4004 | }; | 3486 | }; |
| 4005 | 3487 | ||
| 4006 | static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { | 3488 | static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { |
| @@ -4010,9 +3492,14 @@ static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { | |||
| 4010 | .sw_max = 64, | 3492 | .sw_max = 64, |
| 4011 | .vp_max = 255, | 3493 | .vp_max = 255, |
| 4012 | .hp_max = 256, | 3494 | .hp_max = 256, |
| 3495 | .mgr_width_start = 10, | ||
| 3496 | .mgr_height_start = 26, | ||
| 3497 | .mgr_width_max = 2048, | ||
| 3498 | .mgr_height_max = 2048, | ||
| 4013 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | 3499 | .calc_scaling = dispc_ovl_calc_scaling_34xx, |
| 4014 | .calc_core_clk = calc_core_clk_34xx, | 3500 | .calc_core_clk = calc_core_clk_34xx, |
| 4015 | .num_fifos = 3, | 3501 | .num_fifos = 3, |
| 3502 | .no_framedone_tv = true, | ||
| 4016 | }; | 3503 | }; |
| 4017 | 3504 | ||
| 4018 | static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { | 3505 | static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { |
| @@ -4022,9 +3509,14 @@ static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { | |||
| 4022 | .sw_max = 256, | 3509 | .sw_max = 256, |
| 4023 | .vp_max = 4095, | 3510 | .vp_max = 4095, |
| 4024 | .hp_max = 4096, | 3511 | .hp_max = 4096, |
| 3512 | .mgr_width_start = 10, | ||
| 3513 | .mgr_height_start = 26, | ||
| 3514 | .mgr_width_max = 2048, | ||
| 3515 | .mgr_height_max = 2048, | ||
| 4025 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | 3516 | .calc_scaling = dispc_ovl_calc_scaling_34xx, |
| 4026 | .calc_core_clk = calc_core_clk_34xx, | 3517 | .calc_core_clk = calc_core_clk_34xx, |
| 4027 | .num_fifos = 3, | 3518 | .num_fifos = 3, |
| 3519 | .no_framedone_tv = true, | ||
| 4028 | }; | 3520 | }; |
| 4029 | 3521 | ||
| 4030 | static const struct dispc_features omap44xx_dispc_feats __initconst = { | 3522 | static const struct dispc_features omap44xx_dispc_feats __initconst = { |
| @@ -4034,6 +3526,27 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = { | |||
| 4034 | .sw_max = 256, | 3526 | .sw_max = 256, |
| 4035 | .vp_max = 4095, | 3527 | .vp_max = 4095, |
| 4036 | .hp_max = 4096, | 3528 | .hp_max = 4096, |
| 3529 | .mgr_width_start = 10, | ||
| 3530 | .mgr_height_start = 26, | ||
| 3531 | .mgr_width_max = 2048, | ||
| 3532 | .mgr_height_max = 2048, | ||
| 3533 | .calc_scaling = dispc_ovl_calc_scaling_44xx, | ||
| 3534 | .calc_core_clk = calc_core_clk_44xx, | ||
| 3535 | .num_fifos = 5, | ||
| 3536 | .gfx_fifo_workaround = true, | ||
| 3537 | }; | ||
| 3538 | |||
| 3539 | static const struct dispc_features omap54xx_dispc_feats __initconst = { | ||
| 3540 | .sw_start = 7, | ||
| 3541 | .fp_start = 19, | ||
| 3542 | .bp_start = 31, | ||
| 3543 | .sw_max = 256, | ||
| 3544 | .vp_max = 4095, | ||
| 3545 | .hp_max = 4096, | ||
| 3546 | .mgr_width_start = 11, | ||
| 3547 | .mgr_height_start = 27, | ||
| 3548 | .mgr_width_max = 4096, | ||
| 3549 | .mgr_height_max = 4096, | ||
| 4037 | .calc_scaling = dispc_ovl_calc_scaling_44xx, | 3550 | .calc_scaling = dispc_ovl_calc_scaling_44xx, |
| 4038 | .calc_core_clk = calc_core_clk_44xx, | 3551 | .calc_core_clk = calc_core_clk_44xx, |
| 4039 | .num_fifos = 5, | 3552 | .num_fifos = 5, |
| @@ -4042,7 +3555,6 @@ static const struct dispc_features omap44xx_dispc_feats __initconst = { | |||
| 4042 | 3555 | ||
| 4043 | static int __init dispc_init_features(struct platform_device *pdev) | 3556 | static int __init dispc_init_features(struct platform_device *pdev) |
| 4044 | { | 3557 | { |
| 4045 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
| 4046 | const struct dispc_features *src; | 3558 | const struct dispc_features *src; |
| 4047 | struct dispc_features *dst; | 3559 | struct dispc_features *dst; |
| 4048 | 3560 | ||
| @@ -4052,7 +3564,7 @@ static int __init dispc_init_features(struct platform_device *pdev) | |||
| 4052 | return -ENOMEM; | 3564 | return -ENOMEM; |
| 4053 | } | 3565 | } |
| 4054 | 3566 | ||
| 4055 | switch (pdata->version) { | 3567 | switch (omapdss_get_version()) { |
| 4056 | case OMAPDSS_VER_OMAP24xx: | 3568 | case OMAPDSS_VER_OMAP24xx: |
| 4057 | src = &omap24xx_dispc_feats; | 3569 | src = &omap24xx_dispc_feats; |
| 4058 | break; | 3570 | break; |
| @@ -4074,7 +3586,7 @@ static int __init dispc_init_features(struct platform_device *pdev) | |||
| 4074 | break; | 3586 | break; |
| 4075 | 3587 | ||
| 4076 | case OMAPDSS_VER_OMAP5: | 3588 | case OMAPDSS_VER_OMAP5: |
| 4077 | src = &omap44xx_dispc_feats; | 3589 | src = &omap54xx_dispc_feats; |
| 4078 | break; | 3590 | break; |
| 4079 | 3591 | ||
| 4080 | default: | 3592 | default: |
| @@ -4087,13 +3599,25 @@ static int __init dispc_init_features(struct platform_device *pdev) | |||
| 4087 | return 0; | 3599 | return 0; |
| 4088 | } | 3600 | } |
| 4089 | 3601 | ||
| 3602 | int dispc_request_irq(irq_handler_t handler, void *dev_id) | ||
| 3603 | { | ||
| 3604 | return devm_request_irq(&dispc.pdev->dev, dispc.irq, handler, | ||
| 3605 | IRQF_SHARED, "OMAP DISPC", dev_id); | ||
| 3606 | } | ||
| 3607 | EXPORT_SYMBOL(dispc_request_irq); | ||
| 3608 | |||
| 3609 | void dispc_free_irq(void *dev_id) | ||
| 3610 | { | ||
| 3611 | devm_free_irq(&dispc.pdev->dev, dispc.irq, dev_id); | ||
| 3612 | } | ||
| 3613 | EXPORT_SYMBOL(dispc_free_irq); | ||
| 3614 | |||
| 4090 | /* DISPC HW IP initialisation */ | 3615 | /* DISPC HW IP initialisation */ |
| 4091 | static int __init omap_dispchw_probe(struct platform_device *pdev) | 3616 | static int __init omap_dispchw_probe(struct platform_device *pdev) |
| 4092 | { | 3617 | { |
| 4093 | u32 rev; | 3618 | u32 rev; |
| 4094 | int r = 0; | 3619 | int r = 0; |
| 4095 | struct resource *dispc_mem; | 3620 | struct resource *dispc_mem; |
| 4096 | struct clk *clk; | ||
| 4097 | 3621 | ||
| 4098 | dispc.pdev = pdev; | 3622 | dispc.pdev = pdev; |
| 4099 | 3623 | ||
| @@ -4101,15 +3625,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) | |||
| 4101 | if (r) | 3625 | if (r) |
| 4102 | return r; | 3626 | return r; |
| 4103 | 3627 | ||
| 4104 | spin_lock_init(&dispc.irq_lock); | ||
| 4105 | |||
| 4106 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 4107 | spin_lock_init(&dispc.irq_stats_lock); | ||
| 4108 | dispc.irq_stats.last_reset = jiffies; | ||
| 4109 | #endif | ||
| 4110 | |||
| 4111 | INIT_WORK(&dispc.error_work, dispc_error_worker); | ||
| 4112 | |||
| 4113 | dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); | 3628 | dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); |
| 4114 | if (!dispc_mem) { | 3629 | if (!dispc_mem) { |
| 4115 | DSSERR("can't get IORESOURCE_MEM DISPC\n"); | 3630 | DSSERR("can't get IORESOURCE_MEM DISPC\n"); |
| @@ -4129,22 +3644,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) | |||
| 4129 | return -ENODEV; | 3644 | return -ENODEV; |
| 4130 | } | 3645 | } |
| 4131 | 3646 | ||
| 4132 | r = devm_request_irq(&pdev->dev, dispc.irq, omap_dispc_irq_handler, | ||
| 4133 | IRQF_SHARED, "OMAP DISPC", dispc.pdev); | ||
| 4134 | if (r < 0) { | ||
| 4135 | DSSERR("request_irq failed\n"); | ||
| 4136 | return r; | ||
| 4137 | } | ||
| 4138 | |||
| 4139 | clk = clk_get(&pdev->dev, "fck"); | ||
| 4140 | if (IS_ERR(clk)) { | ||
| 4141 | DSSERR("can't get fck\n"); | ||
| 4142 | r = PTR_ERR(clk); | ||
| 4143 | return r; | ||
| 4144 | } | ||
| 4145 | |||
| 4146 | dispc.dss_clk = clk; | ||
| 4147 | |||
| 4148 | pm_runtime_enable(&pdev->dev); | 3647 | pm_runtime_enable(&pdev->dev); |
| 4149 | 3648 | ||
| 4150 | r = dispc_runtime_get(); | 3649 | r = dispc_runtime_get(); |
| @@ -4153,8 +3652,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) | |||
| 4153 | 3652 | ||
| 4154 | _omap_dispc_initial_config(); | 3653 | _omap_dispc_initial_config(); |
| 4155 | 3654 | ||
| 4156 | _omap_dispc_initialize_irq(); | ||
| 4157 | |||
| 4158 | rev = dispc_read_reg(DISPC_REVISION); | 3655 | rev = dispc_read_reg(DISPC_REVISION); |
| 4159 | dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", | 3656 | dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", |
| 4160 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | 3657 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); |
| @@ -4163,14 +3660,10 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) | |||
| 4163 | 3660 | ||
| 4164 | dss_debugfs_create_file("dispc", dispc_dump_regs); | 3661 | dss_debugfs_create_file("dispc", dispc_dump_regs); |
| 4165 | 3662 | ||
| 4166 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
| 4167 | dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); | ||
| 4168 | #endif | ||
| 4169 | return 0; | 3663 | return 0; |
| 4170 | 3664 | ||
| 4171 | err_runtime_get: | 3665 | err_runtime_get: |
| 4172 | pm_runtime_disable(&pdev->dev); | 3666 | pm_runtime_disable(&pdev->dev); |
| 4173 | clk_put(dispc.dss_clk); | ||
| 4174 | return r; | 3667 | return r; |
| 4175 | } | 3668 | } |
| 4176 | 3669 | ||
| @@ -4178,8 +3671,6 @@ static int __exit omap_dispchw_remove(struct platform_device *pdev) | |||
| 4178 | { | 3671 | { |
| 4179 | pm_runtime_disable(&pdev->dev); | 3672 | pm_runtime_disable(&pdev->dev); |
| 4180 | 3673 | ||
| 4181 | clk_put(dispc.dss_clk); | ||
| 4182 | |||
| 4183 | return 0; | 3674 | return 0; |
| 4184 | } | 3675 | } |
| 4185 | 3676 | ||
diff --git a/drivers/video/omap2/dss/display-sysfs.c b/drivers/video/omap2/dss/display-sysfs.c new file mode 100644 index 000000000000..18211a9ab354 --- /dev/null +++ b/drivers/video/omap2/dss/display-sysfs.c | |||
| @@ -0,0 +1,321 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009 Nokia Corporation | ||
| 3 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
| 4 | * | ||
| 5 | * Some code and ideas taken from drivers/video/omap/ driver | ||
| 6 | * by Imre Deak. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify it | ||
| 9 | * under the terms of the GNU General Public License version 2 as published by | ||
| 10 | * the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 15 | * more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License along with | ||
| 18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #define DSS_SUBSYS_NAME "DISPLAY" | ||
| 22 | |||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/jiffies.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | |||
| 28 | #include <video/omapdss.h> | ||
| 29 | #include "dss.h" | ||
| 30 | #include "dss_features.h" | ||
| 31 | |||
| 32 | static ssize_t display_enabled_show(struct device *dev, | ||
| 33 | struct device_attribute *attr, char *buf) | ||
| 34 | { | ||
| 35 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 36 | bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED; | ||
| 37 | |||
| 38 | return snprintf(buf, PAGE_SIZE, "%d\n", enabled); | ||
| 39 | } | ||
| 40 | |||
| 41 | static ssize_t display_enabled_store(struct device *dev, | ||
| 42 | struct device_attribute *attr, | ||
| 43 | const char *buf, size_t size) | ||
| 44 | { | ||
| 45 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 46 | int r; | ||
| 47 | bool enabled; | ||
| 48 | |||
| 49 | r = strtobool(buf, &enabled); | ||
| 50 | if (r) | ||
| 51 | return r; | ||
| 52 | |||
| 53 | if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { | ||
| 54 | if (enabled) { | ||
| 55 | r = dssdev->driver->enable(dssdev); | ||
| 56 | if (r) | ||
| 57 | return r; | ||
| 58 | } else { | ||
| 59 | dssdev->driver->disable(dssdev); | ||
| 60 | } | ||
| 61 | } | ||
| 62 | |||
| 63 | return size; | ||
| 64 | } | ||
| 65 | |||
| 66 | static ssize_t display_tear_show(struct device *dev, | ||
| 67 | struct device_attribute *attr, char *buf) | ||
| 68 | { | ||
| 69 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 70 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
| 71 | dssdev->driver->get_te ? | ||
| 72 | dssdev->driver->get_te(dssdev) : 0); | ||
| 73 | } | ||
| 74 | |||
| 75 | static ssize_t display_tear_store(struct device *dev, | ||
| 76 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 77 | { | ||
| 78 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 79 | int r; | ||
| 80 | bool te; | ||
| 81 | |||
| 82 | if (!dssdev->driver->enable_te || !dssdev->driver->get_te) | ||
| 83 | return -ENOENT; | ||
| 84 | |||
| 85 | r = strtobool(buf, &te); | ||
| 86 | if (r) | ||
| 87 | return r; | ||
| 88 | |||
| 89 | r = dssdev->driver->enable_te(dssdev, te); | ||
| 90 | if (r) | ||
| 91 | return r; | ||
| 92 | |||
| 93 | return size; | ||
| 94 | } | ||
| 95 | |||
| 96 | static ssize_t display_timings_show(struct device *dev, | ||
| 97 | struct device_attribute *attr, char *buf) | ||
| 98 | { | ||
| 99 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 100 | struct omap_video_timings t; | ||
| 101 | |||
| 102 | if (!dssdev->driver->get_timings) | ||
| 103 | return -ENOENT; | ||
| 104 | |||
| 105 | dssdev->driver->get_timings(dssdev, &t); | ||
| 106 | |||
| 107 | return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n", | ||
| 108 | t.pixel_clock, | ||
| 109 | t.x_res, t.hfp, t.hbp, t.hsw, | ||
| 110 | t.y_res, t.vfp, t.vbp, t.vsw); | ||
| 111 | } | ||
| 112 | |||
| 113 | static ssize_t display_timings_store(struct device *dev, | ||
| 114 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 115 | { | ||
| 116 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 117 | struct omap_video_timings t = dssdev->panel.timings; | ||
| 118 | int r, found; | ||
| 119 | |||
| 120 | if (!dssdev->driver->set_timings || !dssdev->driver->check_timings) | ||
| 121 | return -ENOENT; | ||
| 122 | |||
| 123 | found = 0; | ||
| 124 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
| 125 | if (strncmp("pal", buf, 3) == 0) { | ||
| 126 | t = omap_dss_pal_timings; | ||
| 127 | found = 1; | ||
| 128 | } else if (strncmp("ntsc", buf, 4) == 0) { | ||
| 129 | t = omap_dss_ntsc_timings; | ||
| 130 | found = 1; | ||
| 131 | } | ||
| 132 | #endif | ||
| 133 | if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu", | ||
| 134 | &t.pixel_clock, | ||
| 135 | &t.x_res, &t.hfp, &t.hbp, &t.hsw, | ||
| 136 | &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9) | ||
| 137 | return -EINVAL; | ||
| 138 | |||
| 139 | r = dssdev->driver->check_timings(dssdev, &t); | ||
| 140 | if (r) | ||
| 141 | return r; | ||
| 142 | |||
| 143 | dssdev->driver->disable(dssdev); | ||
| 144 | dssdev->driver->set_timings(dssdev, &t); | ||
| 145 | r = dssdev->driver->enable(dssdev); | ||
| 146 | if (r) | ||
| 147 | return r; | ||
| 148 | |||
| 149 | return size; | ||
| 150 | } | ||
| 151 | |||
| 152 | static ssize_t display_rotate_show(struct device *dev, | ||
| 153 | struct device_attribute *attr, char *buf) | ||
| 154 | { | ||
| 155 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 156 | int rotate; | ||
| 157 | if (!dssdev->driver->get_rotate) | ||
| 158 | return -ENOENT; | ||
| 159 | rotate = dssdev->driver->get_rotate(dssdev); | ||
| 160 | return snprintf(buf, PAGE_SIZE, "%u\n", rotate); | ||
| 161 | } | ||
| 162 | |||
| 163 | static ssize_t display_rotate_store(struct device *dev, | ||
| 164 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 165 | { | ||
| 166 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 167 | int rot, r; | ||
| 168 | |||
| 169 | if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) | ||
| 170 | return -ENOENT; | ||
| 171 | |||
| 172 | r = kstrtoint(buf, 0, &rot); | ||
| 173 | if (r) | ||
| 174 | return r; | ||
| 175 | |||
| 176 | r = dssdev->driver->set_rotate(dssdev, rot); | ||
| 177 | if (r) | ||
| 178 | return r; | ||
| 179 | |||
| 180 | return size; | ||
| 181 | } | ||
| 182 | |||
| 183 | static ssize_t display_mirror_show(struct device *dev, | ||
| 184 | struct device_attribute *attr, char *buf) | ||
| 185 | { | ||
| 186 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 187 | int mirror; | ||
| 188 | if (!dssdev->driver->get_mirror) | ||
| 189 | return -ENOENT; | ||
| 190 | mirror = dssdev->driver->get_mirror(dssdev); | ||
| 191 | return snprintf(buf, PAGE_SIZE, "%u\n", mirror); | ||
| 192 | } | ||
| 193 | |||
| 194 | static ssize_t display_mirror_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 | int r; | ||
| 199 | bool mirror; | ||
| 200 | |||
| 201 | if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) | ||
| 202 | return -ENOENT; | ||
| 203 | |||
| 204 | r = strtobool(buf, &mirror); | ||
| 205 | if (r) | ||
| 206 | return r; | ||
| 207 | |||
| 208 | r = dssdev->driver->set_mirror(dssdev, mirror); | ||
| 209 | if (r) | ||
| 210 | return r; | ||
| 211 | |||
| 212 | return size; | ||
| 213 | } | ||
| 214 | |||
| 215 | static ssize_t display_wss_show(struct device *dev, | ||
| 216 | struct device_attribute *attr, char *buf) | ||
| 217 | { | ||
| 218 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 219 | unsigned int wss; | ||
| 220 | |||
| 221 | if (!dssdev->driver->get_wss) | ||
| 222 | return -ENOENT; | ||
| 223 | |||
| 224 | wss = dssdev->driver->get_wss(dssdev); | ||
| 225 | |||
| 226 | return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss); | ||
| 227 | } | ||
| 228 | |||
| 229 | static ssize_t display_wss_store(struct device *dev, | ||
| 230 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 231 | { | ||
| 232 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 233 | u32 wss; | ||
| 234 | int r; | ||
| 235 | |||
| 236 | if (!dssdev->driver->get_wss || !dssdev->driver->set_wss) | ||
| 237 | return -ENOENT; | ||
| 238 | |||
| 239 | r = kstrtou32(buf, 0, &wss); | ||
| 240 | if (r) | ||
| 241 | return r; | ||
| 242 | |||
| 243 | if (wss > 0xfffff) | ||
| 244 | return -EINVAL; | ||
| 245 | |||
| 246 | r = dssdev->driver->set_wss(dssdev, wss); | ||
| 247 | if (r) | ||
| 248 | return r; | ||
| 249 | |||
| 250 | return size; | ||
| 251 | } | ||
| 252 | |||
| 253 | static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, | ||
| 254 | display_enabled_show, display_enabled_store); | ||
| 255 | static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, | ||
| 256 | display_tear_show, display_tear_store); | ||
| 257 | static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR, | ||
| 258 | display_timings_show, display_timings_store); | ||
| 259 | static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR, | ||
| 260 | display_rotate_show, display_rotate_store); | ||
| 261 | static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, | ||
| 262 | display_mirror_show, display_mirror_store); | ||
| 263 | static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, | ||
| 264 | display_wss_show, display_wss_store); | ||
| 265 | |||
| 266 | static struct device_attribute *display_sysfs_attrs[] = { | ||
| 267 | &dev_attr_enabled, | ||
| 268 | &dev_attr_tear_elim, | ||
| 269 | &dev_attr_timings, | ||
| 270 | &dev_attr_rotate, | ||
| 271 | &dev_attr_mirror, | ||
| 272 | &dev_attr_wss, | ||
| 273 | NULL | ||
| 274 | }; | ||
| 275 | |||
| 276 | int display_init_sysfs(struct platform_device *pdev, | ||
| 277 | struct omap_dss_device *dssdev) | ||
| 278 | { | ||
| 279 | struct device_attribute *attr; | ||
| 280 | int i, r; | ||
| 281 | |||
| 282 | /* create device sysfs files */ | ||
| 283 | i = 0; | ||
| 284 | while ((attr = display_sysfs_attrs[i++]) != NULL) { | ||
| 285 | r = device_create_file(&dssdev->dev, attr); | ||
| 286 | if (r) { | ||
| 287 | for (i = i - 2; i >= 0; i--) { | ||
| 288 | attr = display_sysfs_attrs[i]; | ||
| 289 | device_remove_file(&dssdev->dev, attr); | ||
| 290 | } | ||
| 291 | |||
| 292 | DSSERR("failed to create sysfs file\n"); | ||
| 293 | return r; | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | /* create display? sysfs links */ | ||
| 298 | r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, | ||
| 299 | dev_name(&dssdev->dev)); | ||
| 300 | if (r) { | ||
| 301 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
| 302 | device_remove_file(&dssdev->dev, attr); | ||
| 303 | |||
| 304 | DSSERR("failed to create sysfs display link\n"); | ||
| 305 | return r; | ||
| 306 | } | ||
| 307 | |||
| 308 | return 0; | ||
| 309 | } | ||
| 310 | |||
| 311 | void display_uninit_sysfs(struct platform_device *pdev, | ||
| 312 | struct omap_dss_device *dssdev) | ||
| 313 | { | ||
| 314 | struct device_attribute *attr; | ||
| 315 | int i = 0; | ||
| 316 | |||
| 317 | sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev)); | ||
| 318 | |||
| 319 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
| 320 | device_remove_file(&dssdev->dev, attr); | ||
| 321 | } | ||
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index ccf8550fafde..0aa8ad8f9667 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c | |||
| @@ -31,250 +31,6 @@ | |||
| 31 | #include "dss.h" | 31 | #include "dss.h" |
| 32 | #include "dss_features.h" | 32 | #include "dss_features.h" |
| 33 | 33 | ||
| 34 | static ssize_t display_enabled_show(struct device *dev, | ||
| 35 | struct device_attribute *attr, char *buf) | ||
| 36 | { | ||
| 37 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 38 | bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED; | ||
| 39 | |||
| 40 | return snprintf(buf, PAGE_SIZE, "%d\n", enabled); | ||
| 41 | } | ||
| 42 | |||
| 43 | static ssize_t display_enabled_store(struct device *dev, | ||
| 44 | struct device_attribute *attr, | ||
| 45 | const char *buf, size_t size) | ||
| 46 | { | ||
| 47 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 48 | int r; | ||
| 49 | bool enabled; | ||
| 50 | |||
| 51 | r = strtobool(buf, &enabled); | ||
| 52 | if (r) | ||
| 53 | return r; | ||
| 54 | |||
| 55 | if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { | ||
| 56 | if (enabled) { | ||
| 57 | r = dssdev->driver->enable(dssdev); | ||
| 58 | if (r) | ||
| 59 | return r; | ||
| 60 | } else { | ||
| 61 | dssdev->driver->disable(dssdev); | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | return size; | ||
| 66 | } | ||
| 67 | |||
| 68 | static ssize_t display_tear_show(struct device *dev, | ||
| 69 | struct device_attribute *attr, char *buf) | ||
| 70 | { | ||
| 71 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 72 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
| 73 | dssdev->driver->get_te ? | ||
| 74 | dssdev->driver->get_te(dssdev) : 0); | ||
| 75 | } | ||
| 76 | |||
| 77 | static ssize_t display_tear_store(struct device *dev, | ||
| 78 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 79 | { | ||
| 80 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 81 | int r; | ||
| 82 | bool te; | ||
| 83 | |||
| 84 | if (!dssdev->driver->enable_te || !dssdev->driver->get_te) | ||
| 85 | return -ENOENT; | ||
| 86 | |||
| 87 | r = strtobool(buf, &te); | ||
| 88 | if (r) | ||
| 89 | return r; | ||
| 90 | |||
| 91 | r = dssdev->driver->enable_te(dssdev, te); | ||
| 92 | if (r) | ||
| 93 | return r; | ||
| 94 | |||
| 95 | return size; | ||
| 96 | } | ||
| 97 | |||
| 98 | static ssize_t display_timings_show(struct device *dev, | ||
| 99 | struct device_attribute *attr, char *buf) | ||
| 100 | { | ||
| 101 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 102 | struct omap_video_timings t; | ||
| 103 | |||
| 104 | if (!dssdev->driver->get_timings) | ||
| 105 | return -ENOENT; | ||
| 106 | |||
| 107 | dssdev->driver->get_timings(dssdev, &t); | ||
| 108 | |||
| 109 | return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n", | ||
| 110 | t.pixel_clock, | ||
| 111 | t.x_res, t.hfp, t.hbp, t.hsw, | ||
| 112 | t.y_res, t.vfp, t.vbp, t.vsw); | ||
| 113 | } | ||
| 114 | |||
| 115 | static ssize_t display_timings_store(struct device *dev, | ||
| 116 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 117 | { | ||
| 118 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 119 | struct omap_video_timings t = dssdev->panel.timings; | ||
| 120 | int r, found; | ||
| 121 | |||
| 122 | if (!dssdev->driver->set_timings || !dssdev->driver->check_timings) | ||
| 123 | return -ENOENT; | ||
| 124 | |||
| 125 | found = 0; | ||
| 126 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
| 127 | if (strncmp("pal", buf, 3) == 0) { | ||
| 128 | t = omap_dss_pal_timings; | ||
| 129 | found = 1; | ||
| 130 | } else if (strncmp("ntsc", buf, 4) == 0) { | ||
| 131 | t = omap_dss_ntsc_timings; | ||
| 132 | found = 1; | ||
| 133 | } | ||
| 134 | #endif | ||
| 135 | if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu", | ||
| 136 | &t.pixel_clock, | ||
| 137 | &t.x_res, &t.hfp, &t.hbp, &t.hsw, | ||
| 138 | &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9) | ||
| 139 | return -EINVAL; | ||
| 140 | |||
| 141 | r = dssdev->driver->check_timings(dssdev, &t); | ||
| 142 | if (r) | ||
| 143 | return r; | ||
| 144 | |||
| 145 | dssdev->driver->disable(dssdev); | ||
| 146 | dssdev->driver->set_timings(dssdev, &t); | ||
| 147 | r = dssdev->driver->enable(dssdev); | ||
| 148 | if (r) | ||
| 149 | return r; | ||
| 150 | |||
| 151 | return size; | ||
| 152 | } | ||
| 153 | |||
| 154 | static ssize_t display_rotate_show(struct device *dev, | ||
| 155 | struct device_attribute *attr, char *buf) | ||
| 156 | { | ||
| 157 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 158 | int rotate; | ||
| 159 | if (!dssdev->driver->get_rotate) | ||
| 160 | return -ENOENT; | ||
| 161 | rotate = dssdev->driver->get_rotate(dssdev); | ||
| 162 | return snprintf(buf, PAGE_SIZE, "%u\n", rotate); | ||
| 163 | } | ||
| 164 | |||
| 165 | static ssize_t display_rotate_store(struct device *dev, | ||
| 166 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 167 | { | ||
| 168 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 169 | int rot, r; | ||
| 170 | |||
| 171 | if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) | ||
| 172 | return -ENOENT; | ||
| 173 | |||
| 174 | r = kstrtoint(buf, 0, &rot); | ||
| 175 | if (r) | ||
| 176 | return r; | ||
| 177 | |||
| 178 | r = dssdev->driver->set_rotate(dssdev, rot); | ||
| 179 | if (r) | ||
| 180 | return r; | ||
| 181 | |||
| 182 | return size; | ||
| 183 | } | ||
| 184 | |||
| 185 | static ssize_t display_mirror_show(struct device *dev, | ||
| 186 | struct device_attribute *attr, char *buf) | ||
| 187 | { | ||
| 188 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 189 | int mirror; | ||
| 190 | if (!dssdev->driver->get_mirror) | ||
| 191 | return -ENOENT; | ||
| 192 | mirror = dssdev->driver->get_mirror(dssdev); | ||
| 193 | return snprintf(buf, PAGE_SIZE, "%u\n", mirror); | ||
| 194 | } | ||
| 195 | |||
| 196 | static ssize_t display_mirror_store(struct device *dev, | ||
| 197 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 198 | { | ||
| 199 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 200 | int r; | ||
| 201 | bool mirror; | ||
| 202 | |||
| 203 | if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) | ||
| 204 | return -ENOENT; | ||
| 205 | |||
| 206 | r = strtobool(buf, &mirror); | ||
| 207 | if (r) | ||
| 208 | return r; | ||
| 209 | |||
| 210 | r = dssdev->driver->set_mirror(dssdev, mirror); | ||
| 211 | if (r) | ||
| 212 | return r; | ||
| 213 | |||
| 214 | return size; | ||
| 215 | } | ||
| 216 | |||
| 217 | static ssize_t display_wss_show(struct device *dev, | ||
| 218 | struct device_attribute *attr, char *buf) | ||
| 219 | { | ||
| 220 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 221 | unsigned int wss; | ||
| 222 | |||
| 223 | if (!dssdev->driver->get_wss) | ||
| 224 | return -ENOENT; | ||
| 225 | |||
| 226 | wss = dssdev->driver->get_wss(dssdev); | ||
| 227 | |||
| 228 | return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss); | ||
| 229 | } | ||
| 230 | |||
| 231 | static ssize_t display_wss_store(struct device *dev, | ||
| 232 | struct device_attribute *attr, const char *buf, size_t size) | ||
| 233 | { | ||
| 234 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
| 235 | u32 wss; | ||
| 236 | int r; | ||
| 237 | |||
| 238 | if (!dssdev->driver->get_wss || !dssdev->driver->set_wss) | ||
| 239 | return -ENOENT; | ||
| 240 | |||
| 241 | r = kstrtou32(buf, 0, &wss); | ||
| 242 | if (r) | ||
| 243 | return r; | ||
| 244 | |||
| 245 | if (wss > 0xfffff) | ||
| 246 | return -EINVAL; | ||
| 247 | |||
| 248 | r = dssdev->driver->set_wss(dssdev, wss); | ||
| 249 | if (r) | ||
| 250 | return r; | ||
| 251 | |||
| 252 | return size; | ||
| 253 | } | ||
| 254 | |||
| 255 | static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, | ||
| 256 | display_enabled_show, display_enabled_store); | ||
| 257 | static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, | ||
| 258 | display_tear_show, display_tear_store); | ||
| 259 | static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR, | ||
| 260 | display_timings_show, display_timings_store); | ||
| 261 | static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR, | ||
| 262 | display_rotate_show, display_rotate_store); | ||
| 263 | static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, | ||
| 264 | display_mirror_show, display_mirror_store); | ||
| 265 | static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, | ||
| 266 | display_wss_show, display_wss_store); | ||
| 267 | |||
| 268 | static struct device_attribute *display_sysfs_attrs[] = { | ||
| 269 | &dev_attr_enabled, | ||
| 270 | &dev_attr_tear_elim, | ||
| 271 | &dev_attr_timings, | ||
| 272 | &dev_attr_rotate, | ||
| 273 | &dev_attr_mirror, | ||
| 274 | &dev_attr_wss, | ||
| 275 | NULL | ||
| 276 | }; | ||
| 277 | |||
| 278 | void omapdss_default_get_resolution(struct omap_dss_device *dssdev, | 34 | void omapdss_default_get_resolution(struct omap_dss_device *dssdev, |
| 279 | u16 *xres, u16 *yres) | 35 | u16 *xres, u16 *yres) |
| 280 | { | 36 | { |
| @@ -320,136 +76,8 @@ void omapdss_default_get_timings(struct omap_dss_device *dssdev, | |||
| 320 | } | 76 | } |
| 321 | EXPORT_SYMBOL(omapdss_default_get_timings); | 77 | EXPORT_SYMBOL(omapdss_default_get_timings); |
| 322 | 78 | ||
| 323 | /* | ||
| 324 | * Connect dssdev to a manager if the manager is free or if force is specified. | ||
| 325 | * Connect all overlays to that manager if they are free or if force is | ||
| 326 | * specified. | ||
| 327 | */ | ||
| 328 | static int dss_init_connections(struct omap_dss_device *dssdev, bool force) | ||
| 329 | { | ||
| 330 | struct omap_dss_output *out; | ||
| 331 | struct omap_overlay_manager *mgr; | ||
| 332 | int i, r; | ||
| 333 | |||
| 334 | out = omapdss_get_output_from_dssdev(dssdev); | ||
| 335 | |||
| 336 | WARN_ON(dssdev->output); | ||
| 337 | WARN_ON(out->device); | ||
| 338 | |||
| 339 | r = omapdss_output_set_device(out, dssdev); | ||
| 340 | if (r) { | ||
| 341 | DSSERR("failed to connect output to new device\n"); | ||
| 342 | return r; | ||
| 343 | } | ||
| 344 | |||
| 345 | mgr = omap_dss_get_overlay_manager(dssdev->channel); | ||
| 346 | |||
| 347 | if (mgr->output && !force) | ||
| 348 | return 0; | ||
| 349 | |||
| 350 | if (mgr->output) | ||
| 351 | mgr->unset_output(mgr); | ||
| 352 | |||
| 353 | r = mgr->set_output(mgr, out); | ||
| 354 | if (r) { | ||
| 355 | DSSERR("failed to connect manager to output of new device\n"); | ||
| 356 | |||
| 357 | /* remove the output-device connection we just made */ | ||
| 358 | omapdss_output_unset_device(out); | ||
| 359 | return r; | ||
| 360 | } | ||
| 361 | |||
| 362 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
| 363 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
| 364 | |||
| 365 | if (!ovl->manager || force) { | ||
| 366 | if (ovl->manager) | ||
| 367 | ovl->unset_manager(ovl); | ||
| 368 | |||
| 369 | r = ovl->set_manager(ovl, mgr); | ||
| 370 | if (r) { | ||
| 371 | DSSERR("failed to set initial overlay\n"); | ||
| 372 | return r; | ||
| 373 | } | ||
| 374 | } | ||
| 375 | } | ||
| 376 | |||
| 377 | return 0; | ||
| 378 | } | ||
| 379 | |||
| 380 | static void dss_uninit_connections(struct omap_dss_device *dssdev) | ||
| 381 | { | ||
| 382 | if (dssdev->output) { | ||
| 383 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
| 384 | |||
| 385 | if (mgr) | ||
| 386 | mgr->unset_output(mgr); | ||
| 387 | |||
| 388 | omapdss_output_unset_device(dssdev->output); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | int dss_init_device(struct platform_device *pdev, | ||
| 393 | struct omap_dss_device *dssdev) | ||
| 394 | { | ||
| 395 | struct device_attribute *attr; | ||
| 396 | int i, r; | ||
| 397 | const char *def_disp_name = dss_get_default_display_name(); | ||
| 398 | bool force; | ||
| 399 | |||
| 400 | force = def_disp_name && strcmp(def_disp_name, dssdev->name) == 0; | ||
| 401 | dss_init_connections(dssdev, force); | ||
| 402 | |||
| 403 | /* create device sysfs files */ | ||
| 404 | i = 0; | ||
| 405 | while ((attr = display_sysfs_attrs[i++]) != NULL) { | ||
| 406 | r = device_create_file(&dssdev->dev, attr); | ||
| 407 | if (r) { | ||
| 408 | for (i = i - 2; i >= 0; i--) { | ||
| 409 | attr = display_sysfs_attrs[i]; | ||
| 410 | device_remove_file(&dssdev->dev, attr); | ||
| 411 | } | ||
| 412 | |||
| 413 | dss_uninit_connections(dssdev); | ||
| 414 | |||
| 415 | DSSERR("failed to create sysfs file\n"); | ||
| 416 | return r; | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | /* create display? sysfs links */ | ||
| 421 | r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, | ||
| 422 | dev_name(&dssdev->dev)); | ||
| 423 | if (r) { | ||
| 424 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
| 425 | device_remove_file(&dssdev->dev, attr); | ||
| 426 | |||
| 427 | dss_uninit_connections(dssdev); | ||
| 428 | |||
| 429 | DSSERR("failed to create sysfs display link\n"); | ||
| 430 | return r; | ||
| 431 | } | ||
| 432 | |||
| 433 | return 0; | ||
| 434 | } | ||
| 435 | |||
| 436 | void dss_uninit_device(struct platform_device *pdev, | ||
| 437 | struct omap_dss_device *dssdev) | ||
| 438 | { | ||
| 439 | struct device_attribute *attr; | ||
| 440 | int i = 0; | ||
| 441 | |||
| 442 | sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev)); | ||
| 443 | |||
| 444 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
| 445 | device_remove_file(&dssdev->dev, attr); | ||
| 446 | |||
| 447 | dss_uninit_connections(dssdev); | ||
| 448 | } | ||
| 449 | |||
| 450 | static int dss_suspend_device(struct device *dev, void *data) | 79 | static int dss_suspend_device(struct device *dev, void *data) |
| 451 | { | 80 | { |
| 452 | int r; | ||
| 453 | struct omap_dss_device *dssdev = to_dss_device(dev); | 81 | struct omap_dss_device *dssdev = to_dss_device(dev); |
| 454 | 82 | ||
| 455 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 83 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { |
| @@ -457,15 +85,7 @@ static int dss_suspend_device(struct device *dev, void *data) | |||
| 457 | return 0; | 85 | return 0; |
| 458 | } | 86 | } |
| 459 | 87 | ||
| 460 | if (!dssdev->driver->suspend) { | 88 | dssdev->driver->disable(dssdev); |
| 461 | DSSERR("display '%s' doesn't implement suspend\n", | ||
| 462 | dssdev->name); | ||
| 463 | return -ENOSYS; | ||
| 464 | } | ||
| 465 | |||
| 466 | r = dssdev->driver->suspend(dssdev); | ||
| 467 | if (r) | ||
| 468 | return r; | ||
| 469 | 89 | ||
| 470 | dssdev->activate_after_resume = true; | 90 | dssdev->activate_after_resume = true; |
| 471 | 91 | ||
| @@ -492,8 +112,8 @@ static int dss_resume_device(struct device *dev, void *data) | |||
| 492 | int r; | 112 | int r; |
| 493 | struct omap_dss_device *dssdev = to_dss_device(dev); | 113 | struct omap_dss_device *dssdev = to_dss_device(dev); |
| 494 | 114 | ||
| 495 | if (dssdev->activate_after_resume && dssdev->driver->resume) { | 115 | if (dssdev->activate_after_resume) { |
| 496 | r = dssdev->driver->resume(dssdev); | 116 | r = dssdev->driver->enable(dssdev); |
| 497 | if (r) | 117 | if (r) |
| 498 | return r; | 118 | return r; |
| 499 | } | 119 | } |
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 56748cf8760e..4af136a04e53 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c | |||
| @@ -49,34 +49,53 @@ static struct { | |||
| 49 | struct omap_dss_output output; | 49 | struct omap_dss_output output; |
| 50 | } dpi; | 50 | } dpi; |
| 51 | 51 | ||
| 52 | static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) | 52 | static struct platform_device *dpi_get_dsidev(enum omap_channel channel) |
| 53 | { | 53 | { |
| 54 | int dsi_module; | 54 | /* |
| 55 | 55 | * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL | |
| 56 | dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1; | 56 | * would also be used for DISPC fclk. Meaning, when the DPI output is |
| 57 | * disabled, DISPC clock will be disabled, and TV out will stop. | ||
| 58 | */ | ||
| 59 | switch (omapdss_get_version()) { | ||
| 60 | case OMAPDSS_VER_OMAP24xx: | ||
| 61 | case OMAPDSS_VER_OMAP34xx_ES1: | ||
| 62 | case OMAPDSS_VER_OMAP34xx_ES3: | ||
| 63 | case OMAPDSS_VER_OMAP3630: | ||
| 64 | case OMAPDSS_VER_AM35xx: | ||
| 65 | return NULL; | ||
| 66 | default: | ||
| 67 | break; | ||
| 68 | } | ||
| 57 | 69 | ||
| 58 | return dsi_get_dsidev_from_id(dsi_module); | 70 | switch (channel) { |
| 71 | case OMAP_DSS_CHANNEL_LCD: | ||
| 72 | return dsi_get_dsidev_from_id(0); | ||
| 73 | case OMAP_DSS_CHANNEL_LCD2: | ||
| 74 | return dsi_get_dsidev_from_id(1); | ||
| 75 | default: | ||
| 76 | return NULL; | ||
| 77 | } | ||
| 59 | } | 78 | } |
| 60 | 79 | ||
| 61 | static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev) | 80 | static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) |
| 62 | { | 81 | { |
| 63 | if (dssdev->clocks.dispc.dispc_fclk_src == | 82 | switch (channel) { |
| 64 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || | 83 | case OMAP_DSS_CHANNEL_LCD: |
| 65 | dssdev->clocks.dispc.dispc_fclk_src == | 84 | return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC; |
| 66 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC || | 85 | case OMAP_DSS_CHANNEL_LCD2: |
| 67 | dssdev->clocks.dispc.channel.lcd_clk_src == | 86 | return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; |
| 68 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || | 87 | default: |
| 69 | dssdev->clocks.dispc.channel.lcd_clk_src == | 88 | /* this shouldn't happen */ |
| 70 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC) | 89 | WARN_ON(1); |
| 71 | return true; | 90 | return OMAP_DSS_CLK_SRC_FCK; |
| 72 | else | 91 | } |
| 73 | return false; | ||
| 74 | } | 92 | } |
| 75 | 93 | ||
| 76 | static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, | 94 | static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, |
| 77 | unsigned long pck_req, unsigned long *fck, int *lck_div, | 95 | unsigned long pck_req, unsigned long *fck, int *lck_div, |
| 78 | int *pck_div) | 96 | int *pck_div) |
| 79 | { | 97 | { |
| 98 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
| 80 | struct dsi_clock_info dsi_cinfo; | 99 | struct dsi_clock_info dsi_cinfo; |
| 81 | struct dispc_clock_info dispc_cinfo; | 100 | struct dispc_clock_info dispc_cinfo; |
| 82 | int r; | 101 | int r; |
| @@ -90,7 +109,8 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, | |||
| 90 | if (r) | 109 | if (r) |
| 91 | return r; | 110 | return r; |
| 92 | 111 | ||
| 93 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); | 112 | dss_select_lcd_clk_source(mgr->id, |
| 113 | dpi_get_alt_clk_src(mgr->id)); | ||
| 94 | 114 | ||
| 95 | dpi.mgr_config.clock_info = dispc_cinfo; | 115 | dpi.mgr_config.clock_info = dispc_cinfo; |
| 96 | 116 | ||
| @@ -135,7 +155,7 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) | |||
| 135 | unsigned long pck; | 155 | unsigned long pck; |
| 136 | int r = 0; | 156 | int r = 0; |
| 137 | 157 | ||
| 138 | if (dpi_use_dsi_pll(dssdev)) | 158 | if (dpi.dsidev) |
| 139 | r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, | 159 | r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, |
| 140 | &lck_div, &pck_div); | 160 | &lck_div, &pck_div); |
| 141 | else | 161 | else |
| @@ -214,7 +234,7 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
| 214 | if (r) | 234 | if (r) |
| 215 | goto err_src_sel; | 235 | goto err_src_sel; |
| 216 | 236 | ||
| 217 | if (dpi_use_dsi_pll(dssdev)) { | 237 | if (dpi.dsidev) { |
| 218 | r = dsi_runtime_get(dpi.dsidev); | 238 | r = dsi_runtime_get(dpi.dsidev); |
| 219 | if (r) | 239 | if (r) |
| 220 | goto err_get_dsi; | 240 | goto err_get_dsi; |
| @@ -242,10 +262,10 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
| 242 | 262 | ||
| 243 | err_mgr_enable: | 263 | err_mgr_enable: |
| 244 | err_set_mode: | 264 | err_set_mode: |
| 245 | if (dpi_use_dsi_pll(dssdev)) | 265 | if (dpi.dsidev) |
| 246 | dsi_pll_uninit(dpi.dsidev, true); | 266 | dsi_pll_uninit(dpi.dsidev, true); |
| 247 | err_dsi_pll_init: | 267 | err_dsi_pll_init: |
| 248 | if (dpi_use_dsi_pll(dssdev)) | 268 | if (dpi.dsidev) |
| 249 | dsi_runtime_put(dpi.dsidev); | 269 | dsi_runtime_put(dpi.dsidev); |
| 250 | err_get_dsi: | 270 | err_get_dsi: |
| 251 | err_src_sel: | 271 | err_src_sel: |
| @@ -271,8 +291,8 @@ void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | |||
| 271 | 291 | ||
| 272 | dss_mgr_disable(mgr); | 292 | dss_mgr_disable(mgr); |
| 273 | 293 | ||
| 274 | if (dpi_use_dsi_pll(dssdev)) { | 294 | if (dpi.dsidev) { |
| 275 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | 295 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); |
| 276 | dsi_pll_uninit(dpi.dsidev, true); | 296 | dsi_pll_uninit(dpi.dsidev, true); |
| 277 | dsi_runtime_put(dpi.dsidev); | 297 | dsi_runtime_put(dpi.dsidev); |
| 278 | } | 298 | } |
| @@ -311,13 +331,13 @@ int dpi_check_timings(struct omap_dss_device *dssdev, | |||
| 311 | unsigned long pck; | 331 | unsigned long pck; |
| 312 | struct dispc_clock_info dispc_cinfo; | 332 | struct dispc_clock_info dispc_cinfo; |
| 313 | 333 | ||
| 314 | if (dss_mgr_check_timings(mgr, timings)) | 334 | if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) |
| 315 | return -EINVAL; | 335 | return -EINVAL; |
| 316 | 336 | ||
| 317 | if (timings->pixel_clock == 0) | 337 | if (timings->pixel_clock == 0) |
| 318 | return -EINVAL; | 338 | return -EINVAL; |
| 319 | 339 | ||
| 320 | if (dpi_use_dsi_pll(dssdev)) { | 340 | if (dpi.dsidev) { |
| 321 | struct dsi_clock_info dsi_cinfo; | 341 | struct dsi_clock_info dsi_cinfo; |
| 322 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, | 342 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, |
| 323 | timings->pixel_clock * 1000, | 343 | timings->pixel_clock * 1000, |
| @@ -359,8 +379,32 @@ void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) | |||
| 359 | } | 379 | } |
| 360 | EXPORT_SYMBOL(omapdss_dpi_set_data_lines); | 380 | EXPORT_SYMBOL(omapdss_dpi_set_data_lines); |
| 361 | 381 | ||
| 382 | static int __init dpi_verify_dsi_pll(struct platform_device *dsidev) | ||
| 383 | { | ||
| 384 | int r; | ||
| 385 | |||
| 386 | /* do initial setup with the PLL to see if it is operational */ | ||
| 387 | |||
| 388 | r = dsi_runtime_get(dsidev); | ||
| 389 | if (r) | ||
| 390 | return r; | ||
| 391 | |||
| 392 | r = dsi_pll_init(dsidev, 0, 1); | ||
| 393 | if (r) { | ||
| 394 | dsi_runtime_put(dsidev); | ||
| 395 | return r; | ||
| 396 | } | ||
| 397 | |||
| 398 | dsi_pll_uninit(dsidev, true); | ||
| 399 | dsi_runtime_put(dsidev); | ||
| 400 | |||
| 401 | return 0; | ||
| 402 | } | ||
| 403 | |||
| 362 | static int __init dpi_init_display(struct omap_dss_device *dssdev) | 404 | static int __init dpi_init_display(struct omap_dss_device *dssdev) |
| 363 | { | 405 | { |
| 406 | struct platform_device *dsidev; | ||
| 407 | |||
| 364 | DSSDBG("init_display\n"); | 408 | DSSDBG("init_display\n"); |
| 365 | 409 | ||
| 366 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && | 410 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && |
| @@ -377,19 +421,30 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) | |||
| 377 | dpi.vdds_dsi_reg = vdds_dsi; | 421 | dpi.vdds_dsi_reg = vdds_dsi; |
| 378 | } | 422 | } |
| 379 | 423 | ||
| 380 | if (dpi_use_dsi_pll(dssdev)) { | 424 | /* |
| 381 | enum omap_dss_clk_source dispc_fclk_src = | 425 | * XXX We shouldn't need dssdev->channel for this. The dsi pll clock |
| 382 | dssdev->clocks.dispc.dispc_fclk_src; | 426 | * source for DPI is SoC integration detail, not something that should |
| 383 | dpi.dsidev = dpi_get_dsidev(dispc_fclk_src); | 427 | * be configured in the dssdev |
| 428 | */ | ||
| 429 | dsidev = dpi_get_dsidev(dssdev->channel); | ||
| 430 | |||
| 431 | if (dsidev && dpi_verify_dsi_pll(dsidev)) { | ||
| 432 | dsidev = NULL; | ||
| 433 | DSSWARN("DSI PLL not operational\n"); | ||
| 384 | } | 434 | } |
| 385 | 435 | ||
| 436 | if (dsidev) | ||
| 437 | DSSDBG("using DSI PLL for DPI clock\n"); | ||
| 438 | |||
| 439 | dpi.dsidev = dsidev; | ||
| 440 | |||
| 386 | return 0; | 441 | return 0; |
| 387 | } | 442 | } |
| 388 | 443 | ||
| 389 | static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) | 444 | static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) |
| 390 | { | 445 | { |
| 391 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 446 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
| 392 | const char *def_disp_name = dss_get_default_display_name(); | 447 | const char *def_disp_name = omapdss_get_default_display_name(); |
| 393 | struct omap_dss_device *def_dssdev; | 448 | struct omap_dss_device *def_dssdev; |
| 394 | int i; | 449 | int i; |
| 395 | 450 | ||
| @@ -438,9 +493,18 @@ static void __init dpi_probe_pdata(struct platform_device *dpidev) | |||
| 438 | return; | 493 | return; |
| 439 | } | 494 | } |
| 440 | 495 | ||
| 496 | r = omapdss_output_set_device(&dpi.output, dssdev); | ||
| 497 | if (r) { | ||
| 498 | DSSERR("failed to connect output to new device: %s\n", | ||
| 499 | dssdev->name); | ||
| 500 | dss_put_device(dssdev); | ||
| 501 | return; | ||
| 502 | } | ||
| 503 | |||
| 441 | r = dss_add_device(dssdev); | 504 | r = dss_add_device(dssdev); |
| 442 | if (r) { | 505 | if (r) { |
| 443 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | 506 | DSSERR("device %s register failed: %d\n", dssdev->name, r); |
| 507 | omapdss_output_unset_device(&dpi.output); | ||
| 444 | dss_put_device(dssdev); | 508 | dss_put_device(dssdev); |
| 445 | return; | 509 | return; |
| 446 | } | 510 | } |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index bee92846cfab..28d41d16b7be 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
| @@ -45,7 +45,6 @@ | |||
| 45 | #include "dss.h" | 45 | #include "dss.h" |
| 46 | #include "dss_features.h" | 46 | #include "dss_features.h" |
| 47 | 47 | ||
| 48 | /*#define VERBOSE_IRQ*/ | ||
| 49 | #define DSI_CATCH_MISSING_TE | 48 | #define DSI_CATCH_MISSING_TE |
| 50 | 49 | ||
| 51 | struct dsi_reg { u16 idx; }; | 50 | struct dsi_reg { u16 idx; }; |
| @@ -535,42 +534,38 @@ static inline void dsi_perf_show(struct platform_device *dsidev, | |||
| 535 | } | 534 | } |
| 536 | #endif | 535 | #endif |
| 537 | 536 | ||
| 537 | static int verbose_irq; | ||
| 538 | |||
| 538 | static void print_irq_status(u32 status) | 539 | static void print_irq_status(u32 status) |
| 539 | { | 540 | { |
| 540 | if (status == 0) | 541 | if (status == 0) |
| 541 | return; | 542 | return; |
| 542 | 543 | ||
| 543 | #ifndef VERBOSE_IRQ | 544 | if (!verbose_irq && (status & ~DSI_IRQ_CHANNEL_MASK) == 0) |
| 544 | if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0) | ||
| 545 | return; | 545 | return; |
| 546 | #endif | ||
| 547 | printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status); | ||
| 548 | 546 | ||
| 549 | #define PIS(x) \ | 547 | #define PIS(x) (status & DSI_IRQ_##x) ? (#x " ") : "" |
| 550 | if (status & DSI_IRQ_##x) \ | 548 | |
| 551 | printk(#x " "); | 549 | pr_debug("DSI IRQ: 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", |
| 552 | #ifdef VERBOSE_IRQ | 550 | status, |
| 553 | PIS(VC0); | 551 | verbose_irq ? PIS(VC0) : "", |
| 554 | PIS(VC1); | 552 | verbose_irq ? PIS(VC1) : "", |
| 555 | PIS(VC2); | 553 | verbose_irq ? PIS(VC2) : "", |
| 556 | PIS(VC3); | 554 | verbose_irq ? PIS(VC3) : "", |
| 557 | #endif | 555 | PIS(WAKEUP), |
| 558 | PIS(WAKEUP); | 556 | PIS(RESYNC), |
| 559 | PIS(RESYNC); | 557 | PIS(PLL_LOCK), |
| 560 | PIS(PLL_LOCK); | 558 | PIS(PLL_UNLOCK), |
| 561 | PIS(PLL_UNLOCK); | 559 | PIS(PLL_RECALL), |
| 562 | PIS(PLL_RECALL); | 560 | PIS(COMPLEXIO_ERR), |
| 563 | PIS(COMPLEXIO_ERR); | 561 | PIS(HS_TX_TIMEOUT), |
| 564 | PIS(HS_TX_TIMEOUT); | 562 | PIS(LP_RX_TIMEOUT), |
| 565 | PIS(LP_RX_TIMEOUT); | 563 | PIS(TE_TRIGGER), |
| 566 | PIS(TE_TRIGGER); | 564 | PIS(ACK_TRIGGER), |
| 567 | PIS(ACK_TRIGGER); | 565 | PIS(SYNC_LOST), |
| 568 | PIS(SYNC_LOST); | 566 | PIS(LDO_POWER_GOOD), |
| 569 | PIS(LDO_POWER_GOOD); | 567 | PIS(TA_TIMEOUT)); |
| 570 | PIS(TA_TIMEOUT); | ||
| 571 | #undef PIS | 568 | #undef PIS |
| 572 | |||
| 573 | printk("\n"); | ||
| 574 | } | 569 | } |
| 575 | 570 | ||
| 576 | static void print_irq_status_vc(int channel, u32 status) | 571 | static void print_irq_status_vc(int channel, u32 status) |
| @@ -578,28 +573,24 @@ static void print_irq_status_vc(int channel, u32 status) | |||
| 578 | if (status == 0) | 573 | if (status == 0) |
| 579 | return; | 574 | return; |
| 580 | 575 | ||
| 581 | #ifndef VERBOSE_IRQ | 576 | if (!verbose_irq && (status & ~DSI_VC_IRQ_PACKET_SENT) == 0) |
| 582 | if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0) | ||
| 583 | return; | 577 | return; |
| 584 | #endif | ||
| 585 | printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status); | ||
| 586 | 578 | ||
| 587 | #define PIS(x) \ | 579 | #define PIS(x) (status & DSI_VC_IRQ_##x) ? (#x " ") : "" |
| 588 | if (status & DSI_VC_IRQ_##x) \ | 580 | |
| 589 | printk(#x " "); | 581 | pr_debug("DSI VC(%d) IRQ 0x%x: %s%s%s%s%s%s%s%s%s\n", |
| 590 | PIS(CS); | 582 | channel, |
| 591 | PIS(ECC_CORR); | 583 | status, |
| 592 | #ifdef VERBOSE_IRQ | 584 | PIS(CS), |
| 593 | PIS(PACKET_SENT); | 585 | PIS(ECC_CORR), |
| 594 | #endif | 586 | PIS(ECC_NO_CORR), |
| 595 | PIS(FIFO_TX_OVF); | 587 | verbose_irq ? PIS(PACKET_SENT) : "", |
| 596 | PIS(FIFO_RX_OVF); | 588 | PIS(BTA), |
| 597 | PIS(BTA); | 589 | PIS(FIFO_TX_OVF), |
| 598 | PIS(ECC_NO_CORR); | 590 | PIS(FIFO_RX_OVF), |
| 599 | PIS(FIFO_TX_UDF); | 591 | PIS(FIFO_TX_UDF), |
| 600 | PIS(PP_BUSY_CHANGE); | 592 | PIS(PP_BUSY_CHANGE)); |
| 601 | #undef PIS | 593 | #undef PIS |
| 602 | printk("\n"); | ||
| 603 | } | 594 | } |
| 604 | 595 | ||
| 605 | static void print_irq_status_cio(u32 status) | 596 | static void print_irq_status_cio(u32 status) |
| @@ -607,34 +598,31 @@ static void print_irq_status_cio(u32 status) | |||
| 607 | if (status == 0) | 598 | if (status == 0) |
| 608 | return; | 599 | return; |
| 609 | 600 | ||
| 610 | printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status); | 601 | #define PIS(x) (status & DSI_CIO_IRQ_##x) ? (#x " ") : "" |
| 611 | 602 | ||
| 612 | #define PIS(x) \ | 603 | pr_debug("DSI CIO IRQ 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", |
| 613 | if (status & DSI_CIO_IRQ_##x) \ | 604 | status, |
| 614 | printk(#x " "); | 605 | PIS(ERRSYNCESC1), |
| 615 | PIS(ERRSYNCESC1); | 606 | PIS(ERRSYNCESC2), |
| 616 | PIS(ERRSYNCESC2); | 607 | PIS(ERRSYNCESC3), |
| 617 | PIS(ERRSYNCESC3); | 608 | PIS(ERRESC1), |
| 618 | PIS(ERRESC1); | 609 | PIS(ERRESC2), |
| 619 | PIS(ERRESC2); | 610 | PIS(ERRESC3), |
| 620 | PIS(ERRESC3); | 611 | PIS(ERRCONTROL1), |
| 621 | PIS(ERRCONTROL1); | 612 | PIS(ERRCONTROL2), |
| 622 | PIS(ERRCONTROL2); | 613 | PIS(ERRCONTROL3), |
| 623 | PIS(ERRCONTROL3); | 614 | PIS(STATEULPS1), |
| 624 | PIS(STATEULPS1); | 615 | PIS(STATEULPS2), |
| 625 | PIS(STATEULPS2); | 616 | PIS(STATEULPS3), |
| 626 | PIS(STATEULPS3); | 617 | PIS(ERRCONTENTIONLP0_1), |
| 627 | PIS(ERRCONTENTIONLP0_1); | 618 | PIS(ERRCONTENTIONLP1_1), |
| 628 | PIS(ERRCONTENTIONLP1_1); | 619 | PIS(ERRCONTENTIONLP0_2), |
| 629 | PIS(ERRCONTENTIONLP0_2); | 620 | PIS(ERRCONTENTIONLP1_2), |
| 630 | PIS(ERRCONTENTIONLP1_2); | 621 | PIS(ERRCONTENTIONLP0_3), |
| 631 | PIS(ERRCONTENTIONLP0_3); | 622 | PIS(ERRCONTENTIONLP1_3), |
| 632 | PIS(ERRCONTENTIONLP1_3); | 623 | PIS(ULPSACTIVENOT_ALL0), |
| 633 | PIS(ULPSACTIVENOT_ALL0); | 624 | PIS(ULPSACTIVENOT_ALL1)); |
| 634 | PIS(ULPSACTIVENOT_ALL1); | ||
| 635 | #undef PIS | 625 | #undef PIS |
| 636 | |||
| 637 | printk("\n"); | ||
| 638 | } | 626 | } |
| 639 | 627 | ||
| 640 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 628 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
| @@ -1116,28 +1104,16 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, | |||
| 1116 | } | 1104 | } |
| 1117 | } | 1105 | } |
| 1118 | 1106 | ||
| 1119 | #ifdef DEBUG | ||
| 1120 | static void _dsi_print_reset_status(struct platform_device *dsidev) | 1107 | static void _dsi_print_reset_status(struct platform_device *dsidev) |
| 1121 | { | 1108 | { |
| 1122 | u32 l; | 1109 | u32 l; |
| 1123 | int b0, b1, b2; | 1110 | int b0, b1, b2; |
| 1124 | 1111 | ||
| 1125 | if (!dss_debug) | ||
| 1126 | return; | ||
| 1127 | |||
| 1128 | /* A dummy read using the SCP interface to any DSIPHY register is | 1112 | /* A dummy read using the SCP interface to any DSIPHY register is |
| 1129 | * required after DSIPHY reset to complete the reset of the DSI complex | 1113 | * required after DSIPHY reset to complete the reset of the DSI complex |
| 1130 | * I/O. */ | 1114 | * I/O. */ |
| 1131 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); | 1115 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); |
| 1132 | 1116 | ||
| 1133 | printk(KERN_DEBUG "DSI resets: "); | ||
| 1134 | |||
| 1135 | l = dsi_read_reg(dsidev, DSI_PLL_STATUS); | ||
| 1136 | printk("PLL (%d) ", FLD_GET(l, 0, 0)); | ||
| 1137 | |||
| 1138 | l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); | ||
| 1139 | printk("CIO (%d) ", FLD_GET(l, 29, 29)); | ||
| 1140 | |||
| 1141 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { | 1117 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { |
| 1142 | b0 = 28; | 1118 | b0 = 28; |
| 1143 | b1 = 27; | 1119 | b1 = 27; |
| @@ -1148,18 +1124,21 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) | |||
| 1148 | b2 = 26; | 1124 | b2 = 26; |
| 1149 | } | 1125 | } |
| 1150 | 1126 | ||
| 1151 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); | 1127 | #define DSI_FLD_GET(fld, start, end)\ |
| 1152 | printk("PHY (%x%x%x, %d, %d, %d)\n", | 1128 | FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end) |
| 1153 | FLD_GET(l, b0, b0), | 1129 | |
| 1154 | FLD_GET(l, b1, b1), | 1130 | pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n", |
| 1155 | FLD_GET(l, b2, b2), | 1131 | DSI_FLD_GET(PLL_STATUS, 0, 0), |
| 1156 | FLD_GET(l, 29, 29), | 1132 | DSI_FLD_GET(COMPLEXIO_CFG1, 29, 29), |
| 1157 | FLD_GET(l, 30, 30), | 1133 | DSI_FLD_GET(DSIPHY_CFG5, b0, b0), |
| 1158 | FLD_GET(l, 31, 31)); | 1134 | DSI_FLD_GET(DSIPHY_CFG5, b1, b1), |
| 1135 | DSI_FLD_GET(DSIPHY_CFG5, b2, b2), | ||
| 1136 | DSI_FLD_GET(DSIPHY_CFG5, 29, 29), | ||
| 1137 | DSI_FLD_GET(DSIPHY_CFG5, 30, 30), | ||
| 1138 | DSI_FLD_GET(DSIPHY_CFG5, 31, 31)); | ||
| 1139 | |||
| 1140 | #undef DSI_FLD_GET | ||
| 1159 | } | 1141 | } |
| 1160 | #else | ||
| 1161 | #define _dsi_print_reset_status(x) | ||
| 1162 | #endif | ||
| 1163 | 1142 | ||
| 1164 | static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) | 1143 | static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) |
| 1165 | { | 1144 | { |
| @@ -1407,6 +1386,11 @@ retry: | |||
| 1407 | cur.dsi_pll_hsdiv_dispc_clk = | 1386 | cur.dsi_pll_hsdiv_dispc_clk = |
| 1408 | cur.clkin4ddr / cur.regm_dispc; | 1387 | cur.clkin4ddr / cur.regm_dispc; |
| 1409 | 1388 | ||
| 1389 | if (cur.regm_dispc > 1 && | ||
| 1390 | cur.regm_dispc % 2 != 0 && | ||
| 1391 | req_pck >= 1000000) | ||
| 1392 | continue; | ||
| 1393 | |||
| 1410 | /* this will narrow down the search a bit, | 1394 | /* this will narrow down the search a bit, |
| 1411 | * but still give pixclocks below what was | 1395 | * but still give pixclocks below what was |
| 1412 | * requested */ | 1396 | * requested */ |
| @@ -1621,7 +1605,7 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
| 1621 | u8 regn_start, regn_end, regm_start, regm_end; | 1605 | u8 regn_start, regn_end, regm_start, regm_end; |
| 1622 | u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end; | 1606 | u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end; |
| 1623 | 1607 | ||
| 1624 | DSSDBGF(); | 1608 | DSSDBG("DSI PLL clock config starts"); |
| 1625 | 1609 | ||
| 1626 | dsi->current_cinfo.clkin = cinfo->clkin; | 1610 | dsi->current_cinfo.clkin = cinfo->clkin; |
| 1627 | dsi->current_cinfo.fint = cinfo->fint; | 1611 | dsi->current_cinfo.fint = cinfo->fint; |
| @@ -1757,11 +1741,21 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, | |||
| 1757 | 1741 | ||
| 1758 | DSSDBG("PLL init\n"); | 1742 | DSSDBG("PLL init\n"); |
| 1759 | 1743 | ||
| 1744 | /* | ||
| 1745 | * It seems that on many OMAPs we need to enable both to have a | ||
| 1746 | * functional HSDivider. | ||
| 1747 | */ | ||
| 1748 | enable_hsclk = enable_hsdiv = true; | ||
| 1749 | |||
| 1760 | if (dsi->vdds_dsi_reg == NULL) { | 1750 | if (dsi->vdds_dsi_reg == NULL) { |
| 1761 | struct regulator *vdds_dsi; | 1751 | struct regulator *vdds_dsi; |
| 1762 | 1752 | ||
| 1763 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); | 1753 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); |
| 1764 | 1754 | ||
| 1755 | /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ | ||
| 1756 | if (IS_ERR(vdds_dsi)) | ||
| 1757 | vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); | ||
| 1758 | |||
| 1765 | if (IS_ERR(vdds_dsi)) { | 1759 | if (IS_ERR(vdds_dsi)) { |
| 1766 | DSSERR("can't get VDDS_DSI regulator\n"); | 1760 | DSSERR("can't get VDDS_DSI regulator\n"); |
| 1767 | return PTR_ERR(vdds_dsi); | 1761 | return PTR_ERR(vdds_dsi); |
| @@ -2440,7 +2434,7 @@ static int dsi_cio_init(struct platform_device *dsidev) | |||
| 2440 | int r; | 2434 | int r; |
| 2441 | u32 l; | 2435 | u32 l; |
| 2442 | 2436 | ||
| 2443 | DSSDBGF(); | 2437 | DSSDBG("DSI CIO init starts"); |
| 2444 | 2438 | ||
| 2445 | r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); | 2439 | r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); |
| 2446 | if (r) | 2440 | if (r) |
| @@ -2791,7 +2785,7 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) | |||
| 2791 | { | 2785 | { |
| 2792 | u32 r; | 2786 | u32 r; |
| 2793 | 2787 | ||
| 2794 | DSSDBGF("%d", channel); | 2788 | DSSDBG("Initial config of virtual channel %d", channel); |
| 2795 | 2789 | ||
| 2796 | r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); | 2790 | r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); |
| 2797 | 2791 | ||
| @@ -2823,7 +2817,7 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel, | |||
| 2823 | if (dsi->vc[channel].source == source) | 2817 | if (dsi->vc[channel].source == source) |
| 2824 | return 0; | 2818 | return 0; |
| 2825 | 2819 | ||
| 2826 | DSSDBGF("%d", channel); | 2820 | DSSDBG("Source config of virtual channel %d", channel); |
| 2827 | 2821 | ||
| 2828 | dsi_sync_vc(dsidev, channel); | 2822 | dsi_sync_vc(dsidev, channel); |
| 2829 | 2823 | ||
| @@ -3581,7 +3575,7 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
| 3581 | int r, i; | 3575 | int r, i; |
| 3582 | unsigned mask; | 3576 | unsigned mask; |
| 3583 | 3577 | ||
| 3584 | DSSDBGF(); | 3578 | DSSDBG("Entering ULPS"); |
| 3585 | 3579 | ||
| 3586 | WARN_ON(!dsi_bus_is_locked(dsidev)); | 3580 | WARN_ON(!dsi_bus_is_locked(dsidev)); |
| 3587 | 3581 | ||
| @@ -4285,7 +4279,7 @@ int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, | |||
| 4285 | unsigned long pck; | 4279 | unsigned long pck; |
| 4286 | int r; | 4280 | int r; |
| 4287 | 4281 | ||
| 4288 | DSSDBGF("ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); | 4282 | DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); |
| 4289 | 4283 | ||
| 4290 | mutex_lock(&dsi->lock); | 4284 | mutex_lock(&dsi->lock); |
| 4291 | 4285 | ||
| @@ -4541,7 +4535,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) | |||
| 4541 | dsi_handle_framedone(dsi->pdev, -ETIMEDOUT); | 4535 | dsi_handle_framedone(dsi->pdev, -ETIMEDOUT); |
| 4542 | } | 4536 | } |
| 4543 | 4537 | ||
| 4544 | static void dsi_framedone_irq_callback(void *data, u32 mask) | 4538 | static void dsi_framedone_irq_callback(void *data) |
| 4545 | { | 4539 | { |
| 4546 | struct platform_device *dsidev = (struct platform_device *) data; | 4540 | struct platform_device *dsidev = (struct platform_device *) data; |
| 4547 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4541 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| @@ -4615,7 +4609,6 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
| 4615 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4609 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 4616 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 4610 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
| 4617 | int r; | 4611 | int r; |
| 4618 | u32 irq = 0; | ||
| 4619 | 4612 | ||
| 4620 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { | 4613 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { |
| 4621 | dsi->timings.hsw = 1; | 4614 | dsi->timings.hsw = 1; |
| @@ -4625,12 +4618,10 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
| 4625 | dsi->timings.vfp = 0; | 4618 | dsi->timings.vfp = 0; |
| 4626 | dsi->timings.vbp = 0; | 4619 | dsi->timings.vbp = 0; |
| 4627 | 4620 | ||
| 4628 | irq = dispc_mgr_get_framedone_irq(mgr->id); | 4621 | r = dss_mgr_register_framedone_handler(mgr, |
| 4629 | 4622 | dsi_framedone_irq_callback, dsidev); | |
| 4630 | r = omap_dispc_register_isr(dsi_framedone_irq_callback, | ||
| 4631 | (void *) dsidev, irq); | ||
| 4632 | if (r) { | 4623 | if (r) { |
| 4633 | DSSERR("can't get FRAMEDONE irq\n"); | 4624 | DSSERR("can't register FRAMEDONE handler\n"); |
| 4634 | goto err; | 4625 | goto err; |
| 4635 | } | 4626 | } |
| 4636 | 4627 | ||
| @@ -4668,8 +4659,8 @@ static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | |||
| 4668 | return 0; | 4659 | return 0; |
| 4669 | err1: | 4660 | err1: |
| 4670 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) | 4661 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) |
| 4671 | omap_dispc_unregister_isr(dsi_framedone_irq_callback, | 4662 | dss_mgr_unregister_framedone_handler(mgr, |
| 4672 | (void *) dsidev, irq); | 4663 | dsi_framedone_irq_callback, dsidev); |
| 4673 | err: | 4664 | err: |
| 4674 | return r; | 4665 | return r; |
| 4675 | } | 4666 | } |
| @@ -4680,14 +4671,9 @@ static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) | |||
| 4680 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4671 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 4681 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 4672 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
| 4682 | 4673 | ||
| 4683 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { | 4674 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) |
| 4684 | u32 irq; | 4675 | dss_mgr_unregister_framedone_handler(mgr, |
| 4685 | 4676 | dsi_framedone_irq_callback, dsidev); | |
| 4686 | irq = dispc_mgr_get_framedone_irq(mgr->id); | ||
| 4687 | |||
| 4688 | omap_dispc_unregister_isr(dsi_framedone_irq_callback, | ||
| 4689 | (void *) dsidev, irq); | ||
| 4690 | } | ||
| 4691 | } | 4677 | } |
| 4692 | 4678 | ||
| 4693 | static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) | 4679 | static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) |
| @@ -4730,7 +4716,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
| 4730 | if (r) | 4716 | if (r) |
| 4731 | goto err1; | 4717 | goto err1; |
| 4732 | 4718 | ||
| 4733 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); | ||
| 4734 | dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); | 4719 | dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); |
| 4735 | dss_select_lcd_clk_source(mgr->id, | 4720 | dss_select_lcd_clk_source(mgr->id, |
| 4736 | dssdev->clocks.dispc.channel.lcd_clk_src); | 4721 | dssdev->clocks.dispc.channel.lcd_clk_src); |
| @@ -4765,7 +4750,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
| 4765 | err3: | 4750 | err3: |
| 4766 | dsi_cio_uninit(dsidev); | 4751 | dsi_cio_uninit(dsidev); |
| 4767 | err2: | 4752 | err2: |
| 4768 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | ||
| 4769 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); | 4753 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); |
| 4770 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | 4754 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); |
| 4771 | 4755 | ||
| @@ -4792,7 +4776,6 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, | |||
| 4792 | dsi_vc_enable(dsidev, 2, 0); | 4776 | dsi_vc_enable(dsidev, 2, 0); |
| 4793 | dsi_vc_enable(dsidev, 3, 0); | 4777 | dsi_vc_enable(dsidev, 3, 0); |
| 4794 | 4778 | ||
| 4795 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | ||
| 4796 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); | 4779 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); |
| 4797 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | 4780 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); |
| 4798 | dsi_cio_uninit(dsidev); | 4781 | dsi_cio_uninit(dsidev); |
| @@ -4981,6 +4964,10 @@ static int __init dsi_init_display(struct omap_dss_device *dssdev) | |||
| 4981 | 4964 | ||
| 4982 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); | 4965 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); |
| 4983 | 4966 | ||
| 4967 | /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ | ||
| 4968 | if (IS_ERR(vdds_dsi)) | ||
| 4969 | vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); | ||
| 4970 | |||
| 4984 | if (IS_ERR(vdds_dsi)) { | 4971 | if (IS_ERR(vdds_dsi)) { |
| 4985 | DSSERR("can't get VDDS_DSI regulator\n"); | 4972 | DSSERR("can't get VDDS_DSI regulator\n"); |
| 4986 | return PTR_ERR(vdds_dsi); | 4973 | return PTR_ERR(vdds_dsi); |
| @@ -5121,7 +5108,7 @@ static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *p | |||
| 5121 | { | 5108 | { |
| 5122 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 5109 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
| 5123 | struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); | 5110 | struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); |
| 5124 | const char *def_disp_name = dss_get_default_display_name(); | 5111 | const char *def_disp_name = omapdss_get_default_display_name(); |
| 5125 | struct omap_dss_device *def_dssdev; | 5112 | struct omap_dss_device *def_dssdev; |
| 5126 | int i; | 5113 | int i; |
| 5127 | 5114 | ||
| @@ -5151,6 +5138,7 @@ static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *p | |||
| 5151 | 5138 | ||
| 5152 | static void __init dsi_probe_pdata(struct platform_device *dsidev) | 5139 | static void __init dsi_probe_pdata(struct platform_device *dsidev) |
| 5153 | { | 5140 | { |
| 5141 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 5154 | struct omap_dss_device *plat_dssdev; | 5142 | struct omap_dss_device *plat_dssdev; |
| 5155 | struct omap_dss_device *dssdev; | 5143 | struct omap_dss_device *dssdev; |
| 5156 | int r; | 5144 | int r; |
| @@ -5173,9 +5161,18 @@ static void __init dsi_probe_pdata(struct platform_device *dsidev) | |||
| 5173 | return; | 5161 | return; |
| 5174 | } | 5162 | } |
| 5175 | 5163 | ||
| 5164 | r = omapdss_output_set_device(&dsi->output, dssdev); | ||
| 5165 | if (r) { | ||
| 5166 | DSSERR("failed to connect output to new device: %s\n", | ||
| 5167 | dssdev->name); | ||
| 5168 | dss_put_device(dssdev); | ||
| 5169 | return; | ||
| 5170 | } | ||
| 5171 | |||
| 5176 | r = dss_add_device(dssdev); | 5172 | r = dss_add_device(dssdev); |
| 5177 | if (r) { | 5173 | if (r) { |
| 5178 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | 5174 | DSSERR("device %s register failed: %d\n", dssdev->name, r); |
| 5175 | omapdss_output_unset_device(&dsi->output); | ||
| 5179 | dss_put_device(dssdev); | 5176 | dss_put_device(dssdev); |
| 5180 | return; | 5177 | return; |
| 5181 | } | 5178 | } |
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 602102cebcbf..054c2a22b3f1 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
| 33 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
| 34 | #include <linux/gfp.h> | 34 | #include <linux/gfp.h> |
| 35 | #include <linux/sizes.h> | ||
| 35 | 36 | ||
| 36 | #include <video/omapdss.h> | 37 | #include <video/omapdss.h> |
| 37 | 38 | ||
| @@ -76,6 +77,7 @@ static struct { | |||
| 76 | 77 | ||
| 77 | struct clk *dpll4_m4_ck; | 78 | struct clk *dpll4_m4_ck; |
| 78 | struct clk *dss_clk; | 79 | struct clk *dss_clk; |
| 80 | unsigned long dss_clk_rate; | ||
| 79 | 81 | ||
| 80 | unsigned long cache_req_pck; | 82 | unsigned long cache_req_pck; |
| 81 | unsigned long cache_prate; | 83 | unsigned long cache_prate; |
| @@ -96,6 +98,8 @@ static const char * const dss_generic_clk_source_names[] = { | |||
| 96 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", | 98 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", |
| 97 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", | 99 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", |
| 98 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", | 100 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", |
| 101 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC", | ||
| 102 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI", | ||
| 99 | }; | 103 | }; |
| 100 | 104 | ||
| 101 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) | 105 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) |
| @@ -151,6 +155,21 @@ static void dss_restore_context(void) | |||
| 151 | #undef SR | 155 | #undef SR |
| 152 | #undef RR | 156 | #undef RR |
| 153 | 157 | ||
| 158 | int dss_get_ctx_loss_count(void) | ||
| 159 | { | ||
| 160 | struct omap_dss_board_info *board_data = dss.pdev->dev.platform_data; | ||
| 161 | int cnt; | ||
| 162 | |||
| 163 | if (!board_data->get_context_loss_count) | ||
| 164 | return -ENOENT; | ||
| 165 | |||
| 166 | cnt = board_data->get_context_loss_count(&dss.pdev->dev); | ||
| 167 | |||
| 168 | WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); | ||
| 169 | |||
| 170 | return cnt; | ||
| 171 | } | ||
| 172 | |||
| 154 | void dss_sdi_init(int datapairs) | 173 | void dss_sdi_init(int datapairs) |
| 155 | { | 174 | { |
| 156 | u32 l; | 175 | u32 l; |
| @@ -301,7 +320,7 @@ static void dss_dump_regs(struct seq_file *s) | |||
| 301 | #undef DUMPREG | 320 | #undef DUMPREG |
| 302 | } | 321 | } |
| 303 | 322 | ||
| 304 | void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) | 323 | static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) |
| 305 | { | 324 | { |
| 306 | struct platform_device *dsidev; | 325 | struct platform_device *dsidev; |
| 307 | int b; | 326 | int b; |
| @@ -372,8 +391,10 @@ void dss_select_lcd_clk_source(enum omap_channel channel, | |||
| 372 | struct platform_device *dsidev; | 391 | struct platform_device *dsidev; |
| 373 | int b, ix, pos; | 392 | int b, ix, pos; |
| 374 | 393 | ||
| 375 | if (!dss_has_feature(FEAT_LCD_CLK_SRC)) | 394 | if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { |
| 395 | dss_select_dispc_clk_source(clk_src); | ||
| 376 | return; | 396 | return; |
| 397 | } | ||
| 377 | 398 | ||
| 378 | switch (clk_src) { | 399 | switch (clk_src) { |
| 379 | case OMAP_DSS_CLK_SRC_FCK: | 400 | case OMAP_DSS_CLK_SRC_FCK: |
| @@ -429,6 +450,29 @@ enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) | |||
| 429 | } | 450 | } |
| 430 | } | 451 | } |
| 431 | 452 | ||
| 453 | /* calculate clock rates using dividers in cinfo */ | ||
| 454 | int dss_calc_clock_rates(struct dss_clock_info *cinfo) | ||
| 455 | { | ||
| 456 | if (dss.dpll4_m4_ck) { | ||
| 457 | unsigned long prate; | ||
| 458 | |||
| 459 | if (cinfo->fck_div > dss.feat->fck_div_max || | ||
| 460 | cinfo->fck_div == 0) | ||
| 461 | return -EINVAL; | ||
| 462 | |||
| 463 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | ||
| 464 | |||
| 465 | cinfo->fck = prate / cinfo->fck_div * | ||
| 466 | dss.feat->dss_fck_multiplier; | ||
| 467 | } else { | ||
| 468 | if (cinfo->fck_div != 0) | ||
| 469 | return -EINVAL; | ||
| 470 | cinfo->fck = clk_get_rate(dss.dss_clk); | ||
| 471 | } | ||
| 472 | |||
| 473 | return 0; | ||
| 474 | } | ||
| 475 | |||
| 432 | int dss_set_clock_div(struct dss_clock_info *cinfo) | 476 | int dss_set_clock_div(struct dss_clock_info *cinfo) |
| 433 | { | 477 | { |
| 434 | if (dss.dpll4_m4_ck) { | 478 | if (dss.dpll4_m4_ck) { |
| @@ -446,6 +490,10 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) | |||
| 446 | return -EINVAL; | 490 | return -EINVAL; |
| 447 | } | 491 | } |
| 448 | 492 | ||
| 493 | dss.dss_clk_rate = clk_get_rate(dss.dss_clk); | ||
| 494 | |||
| 495 | WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch"); | ||
| 496 | |||
| 449 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); | 497 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); |
| 450 | 498 | ||
| 451 | return 0; | 499 | return 0; |
| @@ -459,6 +507,41 @@ unsigned long dss_get_dpll4_rate(void) | |||
| 459 | return 0; | 507 | return 0; |
| 460 | } | 508 | } |
| 461 | 509 | ||
| 510 | unsigned long dss_get_dispc_clk_rate(void) | ||
| 511 | { | ||
| 512 | return dss.dss_clk_rate; | ||
| 513 | } | ||
| 514 | |||
| 515 | static int dss_setup_default_clock(void) | ||
| 516 | { | ||
| 517 | unsigned long max_dss_fck, prate; | ||
| 518 | unsigned fck_div; | ||
| 519 | struct dss_clock_info dss_cinfo = { 0 }; | ||
| 520 | int r; | ||
| 521 | |||
| 522 | if (dss.dpll4_m4_ck == NULL) | ||
| 523 | return 0; | ||
| 524 | |||
| 525 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
| 526 | |||
| 527 | prate = dss_get_dpll4_rate(); | ||
| 528 | |||
| 529 | fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier, | ||
| 530 | max_dss_fck); | ||
| 531 | |||
| 532 | dss_cinfo.fck_div = fck_div; | ||
| 533 | |||
| 534 | r = dss_calc_clock_rates(&dss_cinfo); | ||
| 535 | if (r) | ||
| 536 | return r; | ||
| 537 | |||
| 538 | r = dss_set_clock_div(&dss_cinfo); | ||
| 539 | if (r) | ||
| 540 | return r; | ||
| 541 | |||
| 542 | return 0; | ||
| 543 | } | ||
| 544 | |||
| 462 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | 545 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, |
| 463 | struct dispc_clock_info *dispc_cinfo) | 546 | struct dispc_clock_info *dispc_cinfo) |
| 464 | { | 547 | { |
| @@ -748,7 +831,7 @@ static void dss_runtime_put(void) | |||
| 748 | } | 831 | } |
| 749 | 832 | ||
| 750 | /* DEBUGFS */ | 833 | /* DEBUGFS */ |
| 751 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) | 834 | #if defined(CONFIG_OMAP2_DSS_DEBUGFS) |
| 752 | void dss_debug_dump_clocks(struct seq_file *s) | 835 | void dss_debug_dump_clocks(struct seq_file *s) |
| 753 | { | 836 | { |
| 754 | dss_dump_clocks(s); | 837 | dss_dump_clocks(s); |
| @@ -796,7 +879,6 @@ static const struct dss_features omap54xx_dss_feats __initconst = { | |||
| 796 | 879 | ||
| 797 | static int __init dss_init_features(struct platform_device *pdev) | 880 | static int __init dss_init_features(struct platform_device *pdev) |
| 798 | { | 881 | { |
| 799 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
| 800 | const struct dss_features *src; | 882 | const struct dss_features *src; |
| 801 | struct dss_features *dst; | 883 | struct dss_features *dst; |
| 802 | 884 | ||
| @@ -806,7 +888,7 @@ static int __init dss_init_features(struct platform_device *pdev) | |||
| 806 | return -ENOMEM; | 888 | return -ENOMEM; |
| 807 | } | 889 | } |
| 808 | 890 | ||
| 809 | switch (pdata->version) { | 891 | switch (omapdss_get_version()) { |
| 810 | case OMAPDSS_VER_OMAP24xx: | 892 | case OMAPDSS_VER_OMAP24xx: |
| 811 | src = &omap24xx_dss_feats; | 893 | src = &omap24xx_dss_feats; |
| 812 | break; | 894 | break; |
| @@ -871,15 +953,23 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) | |||
| 871 | if (r) | 953 | if (r) |
| 872 | return r; | 954 | return r; |
| 873 | 955 | ||
| 956 | r = dss_setup_default_clock(); | ||
| 957 | if (r) | ||
| 958 | goto err_setup_clocks; | ||
| 959 | |||
| 874 | pm_runtime_enable(&pdev->dev); | 960 | pm_runtime_enable(&pdev->dev); |
| 875 | 961 | ||
| 876 | r = dss_runtime_get(); | 962 | r = dss_runtime_get(); |
| 877 | if (r) | 963 | if (r) |
| 878 | goto err_runtime_get; | 964 | goto err_runtime_get; |
| 879 | 965 | ||
| 966 | dss.dss_clk_rate = clk_get_rate(dss.dss_clk); | ||
| 967 | |||
| 880 | /* Select DPLL */ | 968 | /* Select DPLL */ |
| 881 | REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); | 969 | REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); |
| 882 | 970 | ||
| 971 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | ||
| 972 | |||
| 883 | #ifdef CONFIG_OMAP2_DSS_VENC | 973 | #ifdef CONFIG_OMAP2_DSS_VENC |
| 884 | REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ | 974 | REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ |
| 885 | REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ | 975 | REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ |
| @@ -903,6 +993,7 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) | |||
| 903 | 993 | ||
| 904 | err_runtime_get: | 994 | err_runtime_get: |
| 905 | pm_runtime_disable(&pdev->dev); | 995 | pm_runtime_disable(&pdev->dev); |
| 996 | err_setup_clocks: | ||
| 906 | dss_put_clocks(); | 997 | dss_put_clocks(); |
| 907 | return r; | 998 | return r; |
| 908 | } | 999 | } |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 6728892f9dad..610c8e563daa 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
| @@ -23,44 +23,20 @@ | |||
| 23 | #ifndef __OMAP2_DSS_H | 23 | #ifndef __OMAP2_DSS_H |
| 24 | #define __OMAP2_DSS_H | 24 | #define __OMAP2_DSS_H |
| 25 | 25 | ||
| 26 | #ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT | 26 | #include <linux/interrupt.h> |
| 27 | #define DEBUG | ||
| 28 | #endif | ||
| 29 | 27 | ||
| 30 | #ifdef DEBUG | 28 | #ifdef pr_fmt |
| 31 | extern bool dss_debug; | 29 | #undef pr_fmt |
| 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 | 30 | #endif |
| 42 | 31 | ||
| 43 | #ifdef DSS_SUBSYS_NAME | 32 | #ifdef DSS_SUBSYS_NAME |
| 44 | #define DSSDBGF(format, ...) \ | 33 | #define pr_fmt(fmt) DSS_SUBSYS_NAME ": " fmt |
| 45 | if (dss_debug) \ | ||
| 46 | printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \ | ||
| 47 | ": %s(" format ")\n", \ | ||
| 48 | __func__, \ | ||
| 49 | ## __VA_ARGS__) | ||
| 50 | #else | 34 | #else |
| 51 | #define DSSDBGF(format, ...) \ | 35 | #define pr_fmt(fmt) fmt |
| 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 | 36 | #endif |
| 63 | 37 | ||
| 38 | #define DSSDBG(format, ...) \ | ||
| 39 | pr_debug(format, ## __VA_ARGS__) | ||
| 64 | 40 | ||
| 65 | #ifdef DSS_SUBSYS_NAME | 41 | #ifdef DSS_SUBSYS_NAME |
| 66 | #define DSSERR(format, ...) \ | 42 | #define DSSERR(format, ...) \ |
| @@ -186,11 +162,10 @@ struct seq_file; | |||
| 186 | struct platform_device; | 162 | struct platform_device; |
| 187 | 163 | ||
| 188 | /* core */ | 164 | /* core */ |
| 189 | const char *dss_get_default_display_name(void); | 165 | struct platform_device *dss_get_core_pdev(void); |
| 190 | struct bus_type *dss_get_bus(void); | 166 | struct bus_type *dss_get_bus(void); |
| 191 | struct regulator *dss_get_vdds_dsi(void); | 167 | struct regulator *dss_get_vdds_dsi(void); |
| 192 | struct regulator *dss_get_vdds_sdi(void); | 168 | struct regulator *dss_get_vdds_sdi(void); |
| 193 | int dss_get_ctx_loss_count(struct device *dev); | ||
| 194 | int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask); | 169 | int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask); |
| 195 | void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); | 170 | void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); |
| 196 | int dss_set_min_bus_tput(struct device *dev, unsigned long tput); | 171 | int dss_set_min_bus_tput(struct device *dev, unsigned long tput); |
| @@ -204,55 +179,18 @@ void dss_put_device(struct omap_dss_device *dssdev); | |||
| 204 | void dss_copy_device_pdata(struct omap_dss_device *dst, | 179 | void dss_copy_device_pdata(struct omap_dss_device *dst, |
| 205 | const struct omap_dss_device *src); | 180 | const struct omap_dss_device *src); |
| 206 | 181 | ||
| 207 | /* apply */ | ||
| 208 | void dss_apply_init(void); | ||
| 209 | int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr); | ||
| 210 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); | ||
| 211 | void dss_mgr_start_update(struct omap_overlay_manager *mgr); | ||
| 212 | int omap_dss_mgr_apply(struct omap_overlay_manager *mgr); | ||
| 213 | |||
| 214 | int dss_mgr_enable(struct omap_overlay_manager *mgr); | ||
| 215 | void dss_mgr_disable(struct omap_overlay_manager *mgr); | ||
| 216 | int dss_mgr_set_info(struct omap_overlay_manager *mgr, | ||
| 217 | struct omap_overlay_manager_info *info); | ||
| 218 | void dss_mgr_get_info(struct omap_overlay_manager *mgr, | ||
| 219 | struct omap_overlay_manager_info *info); | ||
| 220 | int dss_mgr_set_device(struct omap_overlay_manager *mgr, | ||
| 221 | struct omap_dss_device *dssdev); | ||
| 222 | int dss_mgr_unset_device(struct omap_overlay_manager *mgr); | ||
| 223 | int dss_mgr_set_output(struct omap_overlay_manager *mgr, | ||
| 224 | struct omap_dss_output *output); | ||
| 225 | int dss_mgr_unset_output(struct omap_overlay_manager *mgr); | ||
| 226 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, | ||
| 227 | const struct omap_video_timings *timings); | ||
| 228 | void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, | ||
| 229 | const struct dss_lcd_mgr_config *config); | ||
| 230 | const struct omap_video_timings *dss_mgr_get_timings(struct omap_overlay_manager *mgr); | ||
| 231 | |||
| 232 | bool dss_ovl_is_enabled(struct omap_overlay *ovl); | ||
| 233 | int dss_ovl_enable(struct omap_overlay *ovl); | ||
| 234 | int dss_ovl_disable(struct omap_overlay *ovl); | ||
| 235 | int dss_ovl_set_info(struct omap_overlay *ovl, | ||
| 236 | struct omap_overlay_info *info); | ||
| 237 | void dss_ovl_get_info(struct omap_overlay *ovl, | ||
| 238 | struct omap_overlay_info *info); | ||
| 239 | int dss_ovl_set_manager(struct omap_overlay *ovl, | ||
| 240 | struct omap_overlay_manager *mgr); | ||
| 241 | int dss_ovl_unset_manager(struct omap_overlay *ovl); | ||
| 242 | |||
| 243 | /* output */ | 182 | /* output */ |
| 244 | void dss_register_output(struct omap_dss_output *out); | 183 | void dss_register_output(struct omap_dss_output *out); |
| 245 | void dss_unregister_output(struct omap_dss_output *out); | 184 | void dss_unregister_output(struct omap_dss_output *out); |
| 246 | struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev); | ||
| 247 | 185 | ||
| 248 | /* display */ | 186 | /* display */ |
| 249 | int dss_suspend_all_devices(void); | 187 | int dss_suspend_all_devices(void); |
| 250 | int dss_resume_all_devices(void); | 188 | int dss_resume_all_devices(void); |
| 251 | void dss_disable_all_devices(void); | 189 | void dss_disable_all_devices(void); |
| 252 | 190 | ||
| 253 | int dss_init_device(struct platform_device *pdev, | 191 | int display_init_sysfs(struct platform_device *pdev, |
| 254 | struct omap_dss_device *dssdev); | 192 | struct omap_dss_device *dssdev); |
| 255 | void dss_uninit_device(struct platform_device *pdev, | 193 | void display_uninit_sysfs(struct platform_device *pdev, |
| 256 | struct omap_dss_device *dssdev); | 194 | struct omap_dss_device *dssdev); |
| 257 | 195 | ||
| 258 | /* manager */ | 196 | /* manager */ |
| @@ -299,21 +237,23 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl); | |||
| 299 | int dss_init_platform_driver(void) __init; | 237 | int dss_init_platform_driver(void) __init; |
| 300 | void dss_uninit_platform_driver(void); | 238 | void dss_uninit_platform_driver(void); |
| 301 | 239 | ||
| 240 | unsigned long dss_get_dispc_clk_rate(void); | ||
| 302 | int dss_dpi_select_source(enum omap_channel channel); | 241 | int dss_dpi_select_source(enum omap_channel channel); |
| 303 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); | 242 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); |
| 304 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); | 243 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); |
| 305 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); | 244 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); |
| 306 | void dss_dump_clocks(struct seq_file *s); | 245 | void dss_dump_clocks(struct seq_file *s); |
| 307 | 246 | ||
| 308 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) | 247 | #if defined(CONFIG_OMAP2_DSS_DEBUGFS) |
| 309 | void dss_debug_dump_clocks(struct seq_file *s); | 248 | void dss_debug_dump_clocks(struct seq_file *s); |
| 310 | #endif | 249 | #endif |
| 311 | 250 | ||
| 251 | int dss_get_ctx_loss_count(void); | ||
| 252 | |||
| 312 | void dss_sdi_init(int datapairs); | 253 | void dss_sdi_init(int datapairs); |
| 313 | int dss_sdi_enable(void); | 254 | int dss_sdi_enable(void); |
| 314 | void dss_sdi_disable(void); | 255 | void dss_sdi_disable(void); |
| 315 | 256 | ||
| 316 | void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src); | ||
| 317 | void dss_select_dsi_clk_source(int dsi_module, | 257 | void dss_select_dsi_clk_source(int dsi_module, |
| 318 | enum omap_dss_clk_source clk_src); | 258 | enum omap_dss_clk_source clk_src); |
| 319 | void dss_select_lcd_clk_source(enum omap_channel channel, | 259 | void dss_select_lcd_clk_source(enum omap_channel channel, |
| @@ -326,6 +266,7 @@ void dss_set_venc_output(enum omap_dss_venc_type type); | |||
| 326 | void dss_set_dac_pwrdn_bgz(bool enable); | 266 | void dss_set_dac_pwrdn_bgz(bool enable); |
| 327 | 267 | ||
| 328 | unsigned long dss_get_dpll4_rate(void); | 268 | unsigned long dss_get_dpll4_rate(void); |
| 269 | int dss_calc_clock_rates(struct dss_clock_info *cinfo); | ||
| 329 | int dss_set_clock_div(struct dss_clock_info *cinfo); | 270 | int dss_set_clock_div(struct dss_clock_info *cinfo); |
| 330 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | 271 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, |
| 331 | struct dispc_clock_info *dispc_cinfo); | 272 | struct dispc_clock_info *dispc_cinfo); |
| @@ -413,8 +354,6 @@ static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev) | |||
| 413 | } | 354 | } |
| 414 | static inline struct platform_device *dsi_get_dsidev_from_id(int module) | 355 | static inline struct platform_device *dsi_get_dsidev_from_id(int module) |
| 415 | { | 356 | { |
| 416 | WARN("%s: DSI not compiled in, returning platform device as NULL\n", | ||
| 417 | __func__); | ||
| 418 | return NULL; | 357 | return NULL; |
| 419 | } | 358 | } |
| 420 | #endif | 359 | #endif |
| @@ -427,15 +366,10 @@ void dpi_uninit_platform_driver(void) __exit; | |||
| 427 | int dispc_init_platform_driver(void) __init; | 366 | int dispc_init_platform_driver(void) __init; |
| 428 | void dispc_uninit_platform_driver(void) __exit; | 367 | void dispc_uninit_platform_driver(void) __exit; |
| 429 | void dispc_dump_clocks(struct seq_file *s); | 368 | void dispc_dump_clocks(struct seq_file *s); |
| 430 | void dispc_irq_handler(void); | ||
| 431 | |||
| 432 | int dispc_runtime_get(void); | ||
| 433 | void dispc_runtime_put(void); | ||
| 434 | 369 | ||
| 435 | void dispc_enable_sidle(void); | 370 | void dispc_enable_sidle(void); |
| 436 | void dispc_disable_sidle(void); | 371 | void dispc_disable_sidle(void); |
| 437 | 372 | ||
| 438 | void dispc_lcd_enable_signal_polarity(bool act_high); | ||
| 439 | void dispc_lcd_enable_signal(bool enable); | 373 | void dispc_lcd_enable_signal(bool enable); |
| 440 | void dispc_pck_free_enable(bool enable); | 374 | void dispc_pck_free_enable(bool enable); |
| 441 | void dispc_enable_fifomerge(bool enable); | 375 | void dispc_enable_fifomerge(bool enable); |
| @@ -455,36 +389,14 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); | |||
| 455 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | 389 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, |
| 456 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, | 390 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, |
| 457 | bool manual_update); | 391 | bool manual_update); |
| 458 | int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, | 392 | |
| 459 | bool replication, const struct omap_video_timings *mgr_timings, | ||
| 460 | bool mem_to_mem); | ||
| 461 | int dispc_ovl_enable(enum omap_plane plane, bool enable); | ||
| 462 | void dispc_ovl_set_channel_out(enum omap_plane plane, | ||
| 463 | enum omap_channel channel); | ||
| 464 | |||
| 465 | void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable); | ||
| 466 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); | ||
| 467 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); | ||
| 468 | bool dispc_mgr_go_busy(enum omap_channel channel); | ||
| 469 | void dispc_mgr_go(enum omap_channel channel); | ||
| 470 | bool dispc_mgr_is_enabled(enum omap_channel channel); | ||
| 471 | void dispc_mgr_enable(enum omap_channel channel, bool enable); | ||
| 472 | bool dispc_mgr_is_channel_enabled(enum omap_channel channel); | ||
| 473 | void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode); | ||
| 474 | void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable); | ||
| 475 | void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines); | ||
| 476 | void dispc_mgr_set_lcd_type_tft(enum omap_channel channel); | ||
| 477 | void dispc_mgr_set_timings(enum omap_channel channel, | ||
| 478 | struct omap_video_timings *timings); | ||
| 479 | unsigned long dispc_mgr_lclk_rate(enum omap_channel channel); | 393 | unsigned long dispc_mgr_lclk_rate(enum omap_channel channel); |
| 480 | unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); | 394 | unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); |
| 481 | unsigned long dispc_core_clk_rate(void); | 395 | unsigned long dispc_core_clk_rate(void); |
| 482 | void dispc_mgr_set_clock_div(enum omap_channel channel, | 396 | void dispc_mgr_set_clock_div(enum omap_channel channel, |
| 483 | struct dispc_clock_info *cinfo); | 397 | const struct dispc_clock_info *cinfo); |
| 484 | int dispc_mgr_get_clock_div(enum omap_channel channel, | 398 | int dispc_mgr_get_clock_div(enum omap_channel channel, |
| 485 | struct dispc_clock_info *cinfo); | 399 | struct dispc_clock_info *cinfo); |
| 486 | void dispc_mgr_setup(enum omap_channel channel, | ||
| 487 | struct omap_overlay_manager_info *info); | ||
| 488 | 400 | ||
| 489 | u32 dispc_wb_get_framedone_irq(void); | 401 | u32 dispc_wb_get_framedone_irq(void); |
| 490 | bool dispc_wb_go_busy(void); | 402 | bool dispc_wb_go_busy(void); |
| @@ -536,6 +448,8 @@ static inline unsigned long hdmi_get_pixel_clock(void) | |||
| 536 | #endif | 448 | #endif |
| 537 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); | 449 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); |
| 538 | void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); | 450 | void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); |
| 451 | int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev); | ||
| 452 | void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev); | ||
| 539 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, | 453 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, |
| 540 | struct omap_video_timings *timings); | 454 | struct omap_video_timings *timings); |
| 541 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | 455 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 3e8287c8709d..18688c12e30d 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
| 21 | #include <linux/module.h> | ||
| 21 | #include <linux/types.h> | 22 | #include <linux/types.h> |
| 22 | #include <linux/err.h> | 23 | #include <linux/err.h> |
| 23 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| @@ -429,8 +430,6 @@ static const struct dss_param_range omap2_dss_param_range[] = { | |||
| 429 | * scaler cannot scale a image with width more than 768. | 430 | * scaler cannot scale a image with width more than 768. |
| 430 | */ | 431 | */ |
| 431 | [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, | 432 | [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, |
| 432 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | ||
| 433 | [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, | ||
| 434 | }; | 433 | }; |
| 435 | 434 | ||
| 436 | static const struct dss_param_range omap3_dss_param_range[] = { | 435 | static const struct dss_param_range omap3_dss_param_range[] = { |
| @@ -445,8 +444,6 @@ static const struct dss_param_range omap3_dss_param_range[] = { | |||
| 445 | [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, | 444 | [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, |
| 446 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 445 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
| 447 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, | 446 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, |
| 448 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | ||
| 449 | [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, | ||
| 450 | }; | 447 | }; |
| 451 | 448 | ||
| 452 | static const struct dss_param_range omap4_dss_param_range[] = { | 449 | static const struct dss_param_range omap4_dss_param_range[] = { |
| @@ -461,8 +458,6 @@ static const struct dss_param_range omap4_dss_param_range[] = { | |||
| 461 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, | 458 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, |
| 462 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 459 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
| 463 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | 460 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, |
| 464 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | ||
| 465 | [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, | ||
| 466 | }; | 461 | }; |
| 467 | 462 | ||
| 468 | static const struct dss_param_range omap5_dss_param_range[] = { | 463 | static const struct dss_param_range omap5_dss_param_range[] = { |
| @@ -477,8 +472,6 @@ static const struct dss_param_range omap5_dss_param_range[] = { | |||
| 477 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, | 472 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, |
| 478 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 473 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
| 479 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | 474 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, |
| 480 | [FEAT_PARAM_MGR_WIDTH] = { 1, 2048 }, | ||
| 481 | [FEAT_PARAM_MGR_HEIGHT] = { 1, 2048 }, | ||
| 482 | }; | 475 | }; |
| 483 | 476 | ||
| 484 | static const enum dss_feat_id omap2_dss_feat_list[] = { | 477 | static const enum dss_feat_id omap2_dss_feat_list[] = { |
| @@ -820,6 +813,7 @@ static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { | |||
| 820 | .audio_start = ti_hdmi_4xxx_audio_start, | 813 | .audio_start = ti_hdmi_4xxx_audio_start, |
| 821 | .audio_stop = ti_hdmi_4xxx_audio_stop, | 814 | .audio_stop = ti_hdmi_4xxx_audio_stop, |
| 822 | .audio_config = ti_hdmi_4xxx_audio_config, | 815 | .audio_config = ti_hdmi_4xxx_audio_config, |
| 816 | .audio_get_dma_port = ti_hdmi_4xxx_audio_get_dma_port, | ||
| 823 | #endif | 817 | #endif |
| 824 | 818 | ||
| 825 | }; | 819 | }; |
| @@ -846,11 +840,13 @@ int dss_feat_get_num_mgrs(void) | |||
| 846 | { | 840 | { |
| 847 | return omap_current_dss_features->num_mgrs; | 841 | return omap_current_dss_features->num_mgrs; |
| 848 | } | 842 | } |
| 843 | EXPORT_SYMBOL(dss_feat_get_num_mgrs); | ||
| 849 | 844 | ||
| 850 | int dss_feat_get_num_ovls(void) | 845 | int dss_feat_get_num_ovls(void) |
| 851 | { | 846 | { |
| 852 | return omap_current_dss_features->num_ovls; | 847 | return omap_current_dss_features->num_ovls; |
| 853 | } | 848 | } |
| 849 | EXPORT_SYMBOL(dss_feat_get_num_ovls); | ||
| 854 | 850 | ||
| 855 | int dss_feat_get_num_wbs(void) | 851 | int dss_feat_get_num_wbs(void) |
| 856 | { | 852 | { |
| @@ -871,16 +867,19 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel | |||
| 871 | { | 867 | { |
| 872 | return omap_current_dss_features->supported_displays[channel]; | 868 | return omap_current_dss_features->supported_displays[channel]; |
| 873 | } | 869 | } |
| 870 | EXPORT_SYMBOL(dss_feat_get_supported_displays); | ||
| 874 | 871 | ||
| 875 | enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel) | 872 | enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel) |
| 876 | { | 873 | { |
| 877 | return omap_current_dss_features->supported_outputs[channel]; | 874 | return omap_current_dss_features->supported_outputs[channel]; |
| 878 | } | 875 | } |
| 876 | EXPORT_SYMBOL(dss_feat_get_supported_outputs); | ||
| 879 | 877 | ||
| 880 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) | 878 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) |
| 881 | { | 879 | { |
| 882 | return omap_current_dss_features->supported_color_modes[plane]; | 880 | return omap_current_dss_features->supported_color_modes[plane]; |
| 883 | } | 881 | } |
| 882 | EXPORT_SYMBOL(dss_feat_get_supported_color_modes); | ||
| 884 | 883 | ||
| 885 | enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane) | 884 | enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane) |
| 886 | { | 885 | { |
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index fc492ef72a51..489b9bec4a6d 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h | |||
| @@ -98,19 +98,12 @@ enum dss_range_param { | |||
| 98 | FEAT_PARAM_DSI_FCK, | 98 | FEAT_PARAM_DSI_FCK, |
| 99 | FEAT_PARAM_DOWNSCALE, | 99 | FEAT_PARAM_DOWNSCALE, |
| 100 | FEAT_PARAM_LINEWIDTH, | 100 | FEAT_PARAM_LINEWIDTH, |
| 101 | FEAT_PARAM_MGR_WIDTH, | ||
| 102 | FEAT_PARAM_MGR_HEIGHT, | ||
| 103 | }; | 101 | }; |
| 104 | 102 | ||
| 105 | /* DSS Feature Functions */ | 103 | /* DSS Feature Functions */ |
| 106 | int dss_feat_get_num_mgrs(void); | ||
| 107 | int dss_feat_get_num_ovls(void); | ||
| 108 | int dss_feat_get_num_wbs(void); | 104 | int dss_feat_get_num_wbs(void); |
| 109 | unsigned long dss_feat_get_param_min(enum dss_range_param param); | 105 | unsigned long dss_feat_get_param_min(enum dss_range_param param); |
| 110 | unsigned long dss_feat_get_param_max(enum dss_range_param param); | 106 | unsigned long dss_feat_get_param_max(enum dss_range_param param); |
| 111 | enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); | ||
| 112 | enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel); | ||
| 113 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); | ||
| 114 | enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); | 107 | enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); |
| 115 | bool dss_feat_color_mode_supported(enum omap_plane plane, | 108 | bool dss_feat_color_mode_supported(enum omap_plane plane, |
| 116 | enum omap_color_mode color_mode); | 109 | enum omap_color_mode color_mode); |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 0d6d7213a858..769d0828581c 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
| @@ -60,6 +60,7 @@ | |||
| 60 | static struct { | 60 | static struct { |
| 61 | struct mutex lock; | 61 | struct mutex lock; |
| 62 | struct platform_device *pdev; | 62 | struct platform_device *pdev; |
| 63 | |||
| 63 | struct hdmi_ip_data ip_data; | 64 | struct hdmi_ip_data ip_data; |
| 64 | 65 | ||
| 65 | struct clk *sys_clk; | 66 | struct clk *sys_clk; |
| @@ -295,6 +296,12 @@ static const struct hdmi_config vesa_timings[] = { | |||
| 295 | false, }, | 296 | false, }, |
| 296 | { 0x55, HDMI_DVI }, | 297 | { 0x55, HDMI_DVI }, |
| 297 | }, | 298 | }, |
| 299 | { | ||
| 300 | { 1920, 1200, 154000, 32, 48, 80, 6, 3, 26, | ||
| 301 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, | ||
| 302 | false, }, | ||
| 303 | { 0x44, HDMI_DVI }, | ||
| 304 | }, | ||
| 298 | }; | 305 | }; |
| 299 | 306 | ||
| 300 | static int hdmi_runtime_get(void) | 307 | static int hdmi_runtime_get(void) |
| @@ -323,7 +330,6 @@ static void hdmi_runtime_put(void) | |||
| 323 | 330 | ||
| 324 | static int __init hdmi_init_display(struct omap_dss_device *dssdev) | 331 | static int __init hdmi_init_display(struct omap_dss_device *dssdev) |
| 325 | { | 332 | { |
| 326 | struct omap_dss_board_info *pdata = hdmi.pdev->dev.platform_data; | ||
| 327 | int r; | 333 | int r; |
| 328 | 334 | ||
| 329 | struct gpio gpios[] = { | 335 | struct gpio gpios[] = { |
| @@ -334,13 +340,17 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev) | |||
| 334 | 340 | ||
| 335 | DSSDBG("init_display\n"); | 341 | DSSDBG("init_display\n"); |
| 336 | 342 | ||
| 337 | dss_init_hdmi_ip_ops(&hdmi.ip_data, pdata->version); | 343 | dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); |
| 338 | 344 | ||
| 339 | if (hdmi.vdda_hdmi_dac_reg == NULL) { | 345 | if (hdmi.vdda_hdmi_dac_reg == NULL) { |
| 340 | struct regulator *reg; | 346 | struct regulator *reg; |
| 341 | 347 | ||
| 342 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); | 348 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); |
| 343 | 349 | ||
| 350 | /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ | ||
| 351 | if (IS_ERR(reg)) | ||
| 352 | reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); | ||
| 353 | |||
| 344 | if (IS_ERR(reg)) { | 354 | if (IS_ERR(reg)) { |
| 345 | DSSERR("can't get VDDA_HDMI_DAC regulator\n"); | 355 | DSSERR("can't get VDDA_HDMI_DAC regulator\n"); |
| 346 | return PTR_ERR(reg); | 356 | return PTR_ERR(reg); |
| @@ -356,7 +366,7 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev) | |||
| 356 | return 0; | 366 | return 0; |
| 357 | } | 367 | } |
| 358 | 368 | ||
| 359 | static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev) | 369 | static void hdmi_uninit_display(struct omap_dss_device *dssdev) |
| 360 | { | 370 | { |
| 361 | DSSDBG("uninit_display\n"); | 371 | DSSDBG("uninit_display\n"); |
| 362 | 372 | ||
| @@ -399,7 +409,8 @@ static bool hdmi_timings_compare(struct omap_video_timings *timing1, | |||
| 399 | { | 409 | { |
| 400 | int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; | 410 | int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; |
| 401 | 411 | ||
| 402 | if ((timing2->pixel_clock == timing1->pixel_clock) && | 412 | if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) == |
| 413 | DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) && | ||
| 403 | (timing2->x_res == timing1->x_res) && | 414 | (timing2->x_res == timing1->x_res) && |
| 404 | (timing2->y_res == timing1->y_res)) { | 415 | (timing2->y_res == timing1->y_res)) { |
| 405 | 416 | ||
| @@ -501,12 +512,9 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | |||
| 501 | DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); | 512 | DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); |
| 502 | } | 513 | } |
| 503 | 514 | ||
| 504 | static int hdmi_power_on(struct omap_dss_device *dssdev) | 515 | static int hdmi_power_on_core(struct omap_dss_device *dssdev) |
| 505 | { | 516 | { |
| 506 | int r; | 517 | int r; |
| 507 | struct omap_video_timings *p; | ||
| 508 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
| 509 | unsigned long phy; | ||
| 510 | 518 | ||
| 511 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); | 519 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); |
| 512 | gpio_set_value(hdmi.ls_oe_gpio, 1); | 520 | gpio_set_value(hdmi.ls_oe_gpio, 1); |
| @@ -522,6 +530,38 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
| 522 | if (r) | 530 | if (r) |
| 523 | goto err_runtime_get; | 531 | goto err_runtime_get; |
| 524 | 532 | ||
| 533 | /* Make selection of HDMI in DSS */ | ||
| 534 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); | ||
| 535 | |||
| 536 | return 0; | ||
| 537 | |||
| 538 | err_runtime_get: | ||
| 539 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
| 540 | err_vdac_enable: | ||
| 541 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | ||
| 542 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
| 543 | return r; | ||
| 544 | } | ||
| 545 | |||
| 546 | static void hdmi_power_off_core(struct omap_dss_device *dssdev) | ||
| 547 | { | ||
| 548 | hdmi_runtime_put(); | ||
| 549 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
| 550 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | ||
| 551 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
| 552 | } | ||
| 553 | |||
| 554 | static int hdmi_power_on_full(struct omap_dss_device *dssdev) | ||
| 555 | { | ||
| 556 | int r; | ||
| 557 | struct omap_video_timings *p; | ||
| 558 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
| 559 | unsigned long phy; | ||
| 560 | |||
| 561 | r = hdmi_power_on_core(dssdev); | ||
| 562 | if (r) | ||
| 563 | return r; | ||
| 564 | |||
| 525 | dss_mgr_disable(mgr); | 565 | dss_mgr_disable(mgr); |
| 526 | 566 | ||
| 527 | p = &hdmi.ip_data.cfg.timings; | 567 | p = &hdmi.ip_data.cfg.timings; |
| @@ -549,17 +589,6 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
| 549 | 589 | ||
| 550 | hdmi.ip_data.ops->video_configure(&hdmi.ip_data); | 590 | hdmi.ip_data.ops->video_configure(&hdmi.ip_data); |
| 551 | 591 | ||
| 552 | /* Make selection of HDMI in DSS */ | ||
| 553 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); | ||
| 554 | |||
| 555 | /* Select the dispc clock source as PRCM clock, to ensure that it is not | ||
| 556 | * DSI PLL source as the clock selected by DSI PLL might not be | ||
| 557 | * sufficient for the resolution selected / that can be changed | ||
| 558 | * dynamically by user. This can be moved to single location , say | ||
| 559 | * Boardfile. | ||
| 560 | */ | ||
| 561 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); | ||
| 562 | |||
| 563 | /* bypass TV gamma table */ | 592 | /* bypass TV gamma table */ |
| 564 | dispc_enable_gamma_table(0); | 593 | dispc_enable_gamma_table(0); |
| 565 | 594 | ||
| @@ -583,16 +612,11 @@ err_vid_enable: | |||
| 583 | err_phy_enable: | 612 | err_phy_enable: |
| 584 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 613 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
| 585 | err_pll_enable: | 614 | err_pll_enable: |
| 586 | hdmi_runtime_put(); | 615 | hdmi_power_off_core(dssdev); |
| 587 | err_runtime_get: | ||
| 588 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
| 589 | err_vdac_enable: | ||
| 590 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | ||
| 591 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
| 592 | return -EIO; | 616 | return -EIO; |
| 593 | } | 617 | } |
| 594 | 618 | ||
| 595 | static void hdmi_power_off(struct omap_dss_device *dssdev) | 619 | static void hdmi_power_off_full(struct omap_dss_device *dssdev) |
| 596 | { | 620 | { |
| 597 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 621 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
| 598 | 622 | ||
| @@ -601,12 +625,8 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) | |||
| 601 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); | 625 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
| 602 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 626 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
| 603 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 627 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
| 604 | hdmi_runtime_put(); | ||
| 605 | |||
| 606 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
| 607 | 628 | ||
| 608 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | 629 | hdmi_power_off_core(dssdev); |
| 609 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
| 610 | } | 630 | } |
| 611 | 631 | ||
| 612 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | 632 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, |
| @@ -716,7 +736,7 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) | |||
| 716 | goto err0; | 736 | goto err0; |
| 717 | } | 737 | } |
| 718 | 738 | ||
| 719 | r = hdmi_power_on(dssdev); | 739 | r = hdmi_power_on_full(dssdev); |
| 720 | if (r) { | 740 | if (r) { |
| 721 | DSSERR("failed to power on device\n"); | 741 | DSSERR("failed to power on device\n"); |
| 722 | goto err1; | 742 | goto err1; |
| @@ -738,13 +758,48 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
| 738 | 758 | ||
| 739 | mutex_lock(&hdmi.lock); | 759 | mutex_lock(&hdmi.lock); |
| 740 | 760 | ||
| 741 | hdmi_power_off(dssdev); | 761 | hdmi_power_off_full(dssdev); |
| 742 | 762 | ||
| 743 | omap_dss_stop_device(dssdev); | 763 | omap_dss_stop_device(dssdev); |
| 744 | 764 | ||
| 745 | mutex_unlock(&hdmi.lock); | 765 | mutex_unlock(&hdmi.lock); |
| 746 | } | 766 | } |
| 747 | 767 | ||
| 768 | int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev) | ||
| 769 | { | ||
| 770 | int r = 0; | ||
| 771 | |||
| 772 | DSSDBG("ENTER omapdss_hdmi_core_enable\n"); | ||
| 773 | |||
| 774 | mutex_lock(&hdmi.lock); | ||
| 775 | |||
| 776 | hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; | ||
| 777 | |||
| 778 | r = hdmi_power_on_core(dssdev); | ||
| 779 | if (r) { | ||
| 780 | DSSERR("failed to power on device\n"); | ||
| 781 | goto err0; | ||
| 782 | } | ||
| 783 | |||
| 784 | mutex_unlock(&hdmi.lock); | ||
| 785 | return 0; | ||
| 786 | |||
| 787 | err0: | ||
| 788 | mutex_unlock(&hdmi.lock); | ||
| 789 | return r; | ||
| 790 | } | ||
| 791 | |||
| 792 | void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev) | ||
| 793 | { | ||
| 794 | DSSDBG("Enter omapdss_hdmi_core_disable\n"); | ||
| 795 | |||
| 796 | mutex_lock(&hdmi.lock); | ||
| 797 | |||
| 798 | hdmi_power_off_core(dssdev); | ||
| 799 | |||
| 800 | mutex_unlock(&hdmi.lock); | ||
| 801 | } | ||
| 802 | |||
| 748 | static int hdmi_get_clocks(struct platform_device *pdev) | 803 | static int hdmi_get_clocks(struct platform_device *pdev) |
| 749 | { | 804 | { |
| 750 | struct clk *clk; | 805 | struct clk *clk; |
| @@ -913,7 +968,7 @@ int hdmi_audio_config(struct omap_dss_audio *audio) | |||
| 913 | static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) | 968 | static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) |
| 914 | { | 969 | { |
| 915 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 970 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
| 916 | const char *def_disp_name = dss_get_default_display_name(); | 971 | const char *def_disp_name = omapdss_get_default_display_name(); |
| 917 | struct omap_dss_device *def_dssdev; | 972 | struct omap_dss_device *def_dssdev; |
| 918 | int i; | 973 | int i; |
| 919 | 974 | ||
| @@ -971,9 +1026,19 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) | |||
| 971 | return; | 1026 | return; |
| 972 | } | 1027 | } |
| 973 | 1028 | ||
| 1029 | r = omapdss_output_set_device(&hdmi.output, dssdev); | ||
| 1030 | if (r) { | ||
| 1031 | DSSERR("failed to connect output to new device: %s\n", | ||
| 1032 | dssdev->name); | ||
| 1033 | dss_put_device(dssdev); | ||
| 1034 | return; | ||
| 1035 | } | ||
| 1036 | |||
| 974 | r = dss_add_device(dssdev); | 1037 | r = dss_add_device(dssdev); |
| 975 | if (r) { | 1038 | if (r) { |
| 976 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | 1039 | DSSERR("device %s register failed: %d\n", dssdev->name, r); |
| 1040 | omapdss_output_unset_device(&hdmi.output); | ||
| 1041 | hdmi_uninit_display(dssdev); | ||
| 977 | dss_put_device(dssdev); | 1042 | dss_put_device(dssdev); |
| 978 | return; | 1043 | return; |
| 979 | } | 1044 | } |
| @@ -1000,22 +1065,22 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev) | |||
| 1000 | /* HDMI HW IP initialisation */ | 1065 | /* HDMI HW IP initialisation */ |
| 1001 | static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | 1066 | static int __init omapdss_hdmihw_probe(struct platform_device *pdev) |
| 1002 | { | 1067 | { |
| 1003 | struct resource *hdmi_mem; | 1068 | struct resource *res; |
| 1004 | int r; | 1069 | int r; |
| 1005 | 1070 | ||
| 1006 | hdmi.pdev = pdev; | 1071 | hdmi.pdev = pdev; |
| 1007 | 1072 | ||
| 1008 | mutex_init(&hdmi.lock); | 1073 | mutex_init(&hdmi.lock); |
| 1074 | mutex_init(&hdmi.ip_data.lock); | ||
| 1009 | 1075 | ||
| 1010 | hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); | 1076 | res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); |
| 1011 | if (!hdmi_mem) { | 1077 | if (!res) { |
| 1012 | DSSERR("can't get IORESOURCE_MEM HDMI\n"); | 1078 | DSSERR("can't get IORESOURCE_MEM HDMI\n"); |
| 1013 | return -EINVAL; | 1079 | return -EINVAL; |
| 1014 | } | 1080 | } |
| 1015 | 1081 | ||
| 1016 | /* Base address taken from platform */ | 1082 | /* Base address taken from platform */ |
| 1017 | hdmi.ip_data.base_wp = ioremap(hdmi_mem->start, | 1083 | hdmi.ip_data.base_wp = devm_request_and_ioremap(&pdev->dev, res); |
| 1018 | resource_size(hdmi_mem)); | ||
| 1019 | if (!hdmi.ip_data.base_wp) { | 1084 | if (!hdmi.ip_data.base_wp) { |
| 1020 | DSSERR("can't ioremap WP\n"); | 1085 | DSSERR("can't ioremap WP\n"); |
| 1021 | return -ENOMEM; | 1086 | return -ENOMEM; |
| @@ -1023,7 +1088,7 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 1023 | 1088 | ||
| 1024 | r = hdmi_get_clocks(pdev); | 1089 | r = hdmi_get_clocks(pdev); |
| 1025 | if (r) { | 1090 | if (r) { |
| 1026 | iounmap(hdmi.ip_data.base_wp); | 1091 | DSSERR("can't get clocks\n"); |
| 1027 | return r; | 1092 | return r; |
| 1028 | } | 1093 | } |
| 1029 | 1094 | ||
| @@ -1034,9 +1099,11 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 1034 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; | 1099 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; |
| 1035 | hdmi.ip_data.phy_offset = HDMI_PHY; | 1100 | hdmi.ip_data.phy_offset = HDMI_PHY; |
| 1036 | 1101 | ||
| 1037 | mutex_init(&hdmi.ip_data.lock); | 1102 | r = hdmi_panel_init(); |
| 1038 | 1103 | if (r) { | |
| 1039 | hdmi_panel_init(); | 1104 | DSSERR("can't init panel\n"); |
| 1105 | goto err_panel_init; | ||
| 1106 | } | ||
| 1040 | 1107 | ||
| 1041 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | 1108 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); |
| 1042 | 1109 | ||
| @@ -1045,6 +1112,10 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 1045 | hdmi_probe_pdata(pdev); | 1112 | hdmi_probe_pdata(pdev); |
| 1046 | 1113 | ||
| 1047 | return 0; | 1114 | return 0; |
| 1115 | |||
| 1116 | err_panel_init: | ||
| 1117 | hdmi_put_clocks(); | ||
| 1118 | return r; | ||
| 1048 | } | 1119 | } |
| 1049 | 1120 | ||
| 1050 | static int __exit hdmi_remove_child(struct device *dev, void *data) | 1121 | static int __exit hdmi_remove_child(struct device *dev, void *data) |
| @@ -1068,8 +1139,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | |||
| 1068 | 1139 | ||
| 1069 | hdmi_put_clocks(); | 1140 | hdmi_put_clocks(); |
| 1070 | 1141 | ||
| 1071 | iounmap(hdmi.ip_data.base_wp); | ||
| 1072 | |||
| 1073 | return 0; | 1142 | return 0; |
| 1074 | } | 1143 | } |
| 1075 | 1144 | ||
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c index 69fb115bab32..dfb8eda81b61 100644 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ b/drivers/video/omap2/dss/hdmi_panel.c | |||
| @@ -280,58 +280,6 @@ static void hdmi_panel_disable(struct omap_dss_device *dssdev) | |||
| 280 | mutex_unlock(&hdmi.lock); | 280 | mutex_unlock(&hdmi.lock); |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | static int hdmi_panel_suspend(struct omap_dss_device *dssdev) | ||
| 284 | { | ||
| 285 | int r = 0; | ||
| 286 | |||
| 287 | mutex_lock(&hdmi.lock); | ||
| 288 | |||
| 289 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | ||
| 290 | r = -EINVAL; | ||
| 291 | goto err; | ||
| 292 | } | ||
| 293 | |||
| 294 | /* | ||
| 295 | * TODO: notify audio users that the display was suspended. For now, | ||
| 296 | * disable audio locally to not break our audio state machine. | ||
| 297 | */ | ||
| 298 | hdmi_panel_audio_disable(dssdev); | ||
| 299 | |||
| 300 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
| 301 | omapdss_hdmi_display_disable(dssdev); | ||
| 302 | |||
| 303 | err: | ||
| 304 | mutex_unlock(&hdmi.lock); | ||
| 305 | |||
| 306 | return r; | ||
| 307 | } | ||
| 308 | |||
| 309 | static int hdmi_panel_resume(struct omap_dss_device *dssdev) | ||
| 310 | { | ||
| 311 | int r = 0; | ||
| 312 | |||
| 313 | mutex_lock(&hdmi.lock); | ||
| 314 | |||
| 315 | if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { | ||
| 316 | r = -EINVAL; | ||
| 317 | goto err; | ||
| 318 | } | ||
| 319 | |||
| 320 | r = omapdss_hdmi_display_enable(dssdev); | ||
| 321 | if (r) { | ||
| 322 | DSSERR("failed to power on\n"); | ||
| 323 | goto err; | ||
| 324 | } | ||
| 325 | /* TODO: notify audio users that the panel resumed. */ | ||
| 326 | |||
| 327 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
| 328 | |||
| 329 | err: | ||
| 330 | mutex_unlock(&hdmi.lock); | ||
| 331 | |||
| 332 | return r; | ||
| 333 | } | ||
| 334 | |||
| 335 | static void hdmi_get_timings(struct omap_dss_device *dssdev, | 283 | static void hdmi_get_timings(struct omap_dss_device *dssdev, |
| 336 | struct omap_video_timings *timings) | 284 | struct omap_video_timings *timings) |
| 337 | { | 285 | { |
| @@ -379,20 +327,22 @@ static int hdmi_check_timings(struct omap_dss_device *dssdev, | |||
| 379 | static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) | 327 | static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) |
| 380 | { | 328 | { |
| 381 | int r; | 329 | int r; |
| 330 | bool need_enable; | ||
| 382 | 331 | ||
| 383 | mutex_lock(&hdmi.lock); | 332 | mutex_lock(&hdmi.lock); |
| 384 | 333 | ||
| 385 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 334 | need_enable = dssdev->state == OMAP_DSS_DISPLAY_DISABLED; |
| 386 | r = omapdss_hdmi_display_enable(dssdev); | 335 | |
| 336 | if (need_enable) { | ||
| 337 | r = omapdss_hdmi_core_enable(dssdev); | ||
| 387 | if (r) | 338 | if (r) |
| 388 | goto err; | 339 | goto err; |
| 389 | } | 340 | } |
| 390 | 341 | ||
| 391 | r = omapdss_hdmi_read_edid(buf, len); | 342 | r = omapdss_hdmi_read_edid(buf, len); |
| 392 | 343 | ||
| 393 | if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED || | 344 | if (need_enable) |
| 394 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) | 345 | omapdss_hdmi_core_disable(dssdev); |
| 395 | omapdss_hdmi_display_disable(dssdev); | ||
| 396 | err: | 346 | err: |
| 397 | mutex_unlock(&hdmi.lock); | 347 | mutex_unlock(&hdmi.lock); |
| 398 | 348 | ||
| @@ -402,20 +352,22 @@ err: | |||
| 402 | static bool hdmi_detect(struct omap_dss_device *dssdev) | 352 | static bool hdmi_detect(struct omap_dss_device *dssdev) |
| 403 | { | 353 | { |
| 404 | int r; | 354 | int r; |
| 355 | bool need_enable; | ||
| 405 | 356 | ||
| 406 | mutex_lock(&hdmi.lock); | 357 | mutex_lock(&hdmi.lock); |
| 407 | 358 | ||
| 408 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 359 | need_enable = dssdev->state == OMAP_DSS_DISPLAY_DISABLED; |
| 409 | r = omapdss_hdmi_display_enable(dssdev); | 360 | |
| 361 | if (need_enable) { | ||
| 362 | r = omapdss_hdmi_core_enable(dssdev); | ||
| 410 | if (r) | 363 | if (r) |
| 411 | goto err; | 364 | goto err; |
| 412 | } | 365 | } |
| 413 | 366 | ||
| 414 | r = omapdss_hdmi_detect(); | 367 | r = omapdss_hdmi_detect(); |
| 415 | 368 | ||
| 416 | if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED || | 369 | if (need_enable) |
| 417 | dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) | 370 | omapdss_hdmi_core_disable(dssdev); |
| 418 | omapdss_hdmi_display_disable(dssdev); | ||
| 419 | err: | 371 | err: |
| 420 | mutex_unlock(&hdmi.lock); | 372 | mutex_unlock(&hdmi.lock); |
| 421 | 373 | ||
| @@ -427,8 +379,6 @@ static struct omap_dss_driver hdmi_driver = { | |||
| 427 | .remove = hdmi_panel_remove, | 379 | .remove = hdmi_panel_remove, |
| 428 | .enable = hdmi_panel_enable, | 380 | .enable = hdmi_panel_enable, |
| 429 | .disable = hdmi_panel_disable, | 381 | .disable = hdmi_panel_disable, |
| 430 | .suspend = hdmi_panel_suspend, | ||
| 431 | .resume = hdmi_panel_resume, | ||
| 432 | .get_timings = hdmi_get_timings, | 382 | .get_timings = hdmi_get_timings, |
| 433 | .set_timings = hdmi_set_timings, | 383 | .set_timings = hdmi_set_timings, |
| 434 | .check_timings = hdmi_check_timings, | 384 | .check_timings = hdmi_check_timings, |
| @@ -454,9 +404,7 @@ int hdmi_panel_init(void) | |||
| 454 | spin_lock_init(&hdmi.audio_lock); | 404 | spin_lock_init(&hdmi.audio_lock); |
| 455 | #endif | 405 | #endif |
| 456 | 406 | ||
| 457 | omap_dss_register_driver(&hdmi_driver); | 407 | return omap_dss_register_driver(&hdmi_driver); |
| 458 | |||
| 459 | return 0; | ||
| 460 | } | 408 | } |
| 461 | 409 | ||
| 462 | void hdmi_panel_exit(void) | 410 | void hdmi_panel_exit(void) |
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index c54d2f620ce3..2551eaa14c42 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c | |||
| @@ -36,36 +36,6 @@ | |||
| 36 | static int num_managers; | 36 | static int num_managers; |
| 37 | static struct omap_overlay_manager *managers; | 37 | static struct omap_overlay_manager *managers; |
| 38 | 38 | ||
| 39 | static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) | ||
| 40 | { | ||
| 41 | return mgr->output ? mgr->output->device : NULL; | ||
| 42 | } | ||
| 43 | |||
| 44 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | ||
| 45 | { | ||
| 46 | unsigned long timeout = msecs_to_jiffies(500); | ||
| 47 | struct omap_dss_device *dssdev = mgr->get_device(mgr); | ||
| 48 | u32 irq; | ||
| 49 | int r; | ||
| 50 | |||
| 51 | r = dispc_runtime_get(); | ||
| 52 | if (r) | ||
| 53 | return r; | ||
| 54 | |||
| 55 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) | ||
| 56 | irq = DISPC_IRQ_EVSYNC_ODD; | ||
| 57 | else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) | ||
| 58 | irq = DISPC_IRQ_EVSYNC_EVEN; | ||
| 59 | else | ||
| 60 | irq = dispc_mgr_get_vsync_irq(mgr->id); | ||
| 61 | |||
| 62 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
| 63 | |||
| 64 | dispc_runtime_put(); | ||
| 65 | |||
| 66 | return r; | ||
| 67 | } | ||
| 68 | |||
| 69 | int dss_init_overlay_managers(struct platform_device *pdev) | 39 | int dss_init_overlay_managers(struct platform_device *pdev) |
| 70 | { | 40 | { |
| 71 | int i, r; | 41 | int i, r; |
| @@ -99,15 +69,6 @@ int dss_init_overlay_managers(struct platform_device *pdev) | |||
| 99 | break; | 69 | break; |
| 100 | } | 70 | } |
| 101 | 71 | ||
| 102 | mgr->set_output = &dss_mgr_set_output; | ||
| 103 | mgr->unset_output = &dss_mgr_unset_output; | ||
| 104 | mgr->apply = &omap_dss_mgr_apply; | ||
| 105 | mgr->set_manager_info = &dss_mgr_set_info; | ||
| 106 | mgr->get_manager_info = &dss_mgr_get_info; | ||
| 107 | mgr->wait_for_go = &dss_mgr_wait_for_go; | ||
| 108 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; | ||
| 109 | mgr->get_device = &dss_mgr_get_device; | ||
| 110 | |||
| 111 | mgr->caps = 0; | 72 | mgr->caps = 0; |
| 112 | mgr->supported_displays = | 73 | mgr->supported_displays = |
| 113 | dss_feat_get_supported_displays(mgr->id); | 74 | dss_feat_get_supported_displays(mgr->id); |
diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c index 813f26682b7a..79dea1a1a732 100644 --- a/drivers/video/omap2/dss/output.c +++ b/drivers/video/omap2/dss/output.c | |||
| @@ -114,35 +114,67 @@ struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) | |||
| 114 | return NULL; | 114 | return NULL; |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | struct omap_dss_output *omapdss_get_output_from_dssdev(struct omap_dss_device *dssdev) | 117 | static const struct dss_mgr_ops *dss_mgr_ops; |
| 118 | |||
| 119 | int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) | ||
| 118 | { | 120 | { |
| 119 | struct omap_dss_output *out = NULL; | 121 | if (dss_mgr_ops) |
| 120 | enum omap_dss_output_id id; | 122 | return -EBUSY; |
| 121 | 123 | ||
| 122 | switch (dssdev->type) { | 124 | dss_mgr_ops = mgr_ops; |
| 123 | case OMAP_DISPLAY_TYPE_DPI: | 125 | |
| 124 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_DPI); | 126 | return 0; |
| 125 | break; | 127 | } |
| 126 | case OMAP_DISPLAY_TYPE_DBI: | 128 | EXPORT_SYMBOL(dss_install_mgr_ops); |
| 127 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_DBI); | 129 | |
| 128 | break; | 130 | void dss_uninstall_mgr_ops(void) |
| 129 | case OMAP_DISPLAY_TYPE_SDI: | 131 | { |
| 130 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_SDI); | 132 | dss_mgr_ops = NULL; |
| 131 | break; | 133 | } |
| 132 | case OMAP_DISPLAY_TYPE_VENC: | 134 | EXPORT_SYMBOL(dss_uninstall_mgr_ops); |
| 133 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_VENC); | 135 | |
| 134 | break; | 136 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, |
| 135 | case OMAP_DISPLAY_TYPE_HDMI: | 137 | const struct omap_video_timings *timings) |
| 136 | out = omap_dss_get_output(OMAP_DSS_OUTPUT_HDMI); | 138 | { |
| 137 | break; | 139 | dss_mgr_ops->set_timings(mgr, timings); |
| 138 | case OMAP_DISPLAY_TYPE_DSI: | 140 | } |
| 139 | id = dssdev->phy.dsi.module == 0 ? OMAP_DSS_OUTPUT_DSI1 : | 141 | EXPORT_SYMBOL(dss_mgr_set_timings); |
| 140 | OMAP_DSS_OUTPUT_DSI2; | 142 | |
| 141 | out = omap_dss_get_output(id); | 143 | void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, |
| 142 | break; | 144 | const struct dss_lcd_mgr_config *config) |
| 143 | default: | 145 | { |
| 144 | break; | 146 | dss_mgr_ops->set_lcd_config(mgr, config); |
| 145 | } | 147 | } |
| 148 | EXPORT_SYMBOL(dss_mgr_set_lcd_config); | ||
| 149 | |||
| 150 | int dss_mgr_enable(struct omap_overlay_manager *mgr) | ||
| 151 | { | ||
| 152 | return dss_mgr_ops->enable(mgr); | ||
| 153 | } | ||
| 154 | EXPORT_SYMBOL(dss_mgr_enable); | ||
| 155 | |||
| 156 | void dss_mgr_disable(struct omap_overlay_manager *mgr) | ||
| 157 | { | ||
| 158 | dss_mgr_ops->disable(mgr); | ||
| 159 | } | ||
| 160 | EXPORT_SYMBOL(dss_mgr_disable); | ||
| 146 | 161 | ||
| 147 | return out; | 162 | void dss_mgr_start_update(struct omap_overlay_manager *mgr) |
| 163 | { | ||
| 164 | dss_mgr_ops->start_update(mgr); | ||
| 165 | } | ||
| 166 | EXPORT_SYMBOL(dss_mgr_start_update); | ||
| 167 | |||
| 168 | int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr, | ||
| 169 | void (*handler)(void *), void *data) | ||
| 170 | { | ||
| 171 | return dss_mgr_ops->register_framedone_handler(mgr, handler, data); | ||
| 172 | } | ||
| 173 | EXPORT_SYMBOL(dss_mgr_register_framedone_handler); | ||
| 174 | |||
| 175 | void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr, | ||
| 176 | void (*handler)(void *), void *data) | ||
| 177 | { | ||
| 178 | dss_mgr_ops->unregister_framedone_handler(mgr, handler, data); | ||
| 148 | } | 179 | } |
| 180 | EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); | ||
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 45f4994bc6b0..eccde322c28a 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c | |||
| @@ -38,13 +38,6 @@ | |||
| 38 | static int num_overlays; | 38 | static int num_overlays; |
| 39 | static struct omap_overlay *overlays; | 39 | static struct omap_overlay *overlays; |
| 40 | 40 | ||
| 41 | static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) | ||
| 42 | { | ||
| 43 | return ovl->manager ? | ||
| 44 | (ovl->manager->output ? ovl->manager->output->device : NULL) : | ||
| 45 | NULL; | ||
| 46 | } | ||
| 47 | |||
| 48 | int omap_dss_get_num_overlays(void) | 41 | int omap_dss_get_num_overlays(void) |
| 49 | { | 42 | { |
| 50 | return num_overlays; | 43 | return num_overlays; |
| @@ -93,16 +86,6 @@ void dss_init_overlays(struct platform_device *pdev) | |||
| 93 | break; | 86 | break; |
| 94 | } | 87 | } |
| 95 | 88 | ||
| 96 | ovl->is_enabled = &dss_ovl_is_enabled; | ||
| 97 | ovl->enable = &dss_ovl_enable; | ||
| 98 | ovl->disable = &dss_ovl_disable; | ||
| 99 | ovl->set_manager = &dss_ovl_set_manager; | ||
| 100 | ovl->unset_manager = &dss_ovl_unset_manager; | ||
| 101 | ovl->set_overlay_info = &dss_ovl_set_info; | ||
| 102 | ovl->get_overlay_info = &dss_ovl_get_info; | ||
| 103 | ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; | ||
| 104 | ovl->get_device = &dss_ovl_get_device; | ||
| 105 | |||
| 106 | ovl->caps = dss_feat_get_overlay_caps(ovl->id); | 89 | ovl->caps = dss_feat_get_overlay_caps(ovl->id); |
| 107 | ovl->supported_modes = | 90 | ovl->supported_modes = |
| 108 | dss_feat_get_supported_color_modes(ovl->id); | 91 | dss_feat_get_supported_color_modes(ovl->id); |
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 7282e5af3e1a..e903dd3f54d9 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
| @@ -342,7 +342,7 @@ static int rfbi_transfer_area(struct omap_dss_device *dssdev, | |||
| 342 | return 0; | 342 | return 0; |
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | static void framedone_callback(void *data, u32 mask) | 345 | static void framedone_callback(void *data) |
| 346 | { | 346 | { |
| 347 | void (*callback)(void *data); | 347 | void (*callback)(void *data); |
| 348 | 348 | ||
| @@ -908,8 +908,8 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) | |||
| 908 | goto err0; | 908 | goto err0; |
| 909 | } | 909 | } |
| 910 | 910 | ||
| 911 | r = omap_dispc_register_isr(framedone_callback, NULL, | 911 | r = dss_mgr_register_framedone_handler(out->manager, |
| 912 | DISPC_IRQ_FRAMEDONE); | 912 | framedone_callback, NULL); |
| 913 | if (r) { | 913 | if (r) { |
| 914 | DSSERR("can't get FRAMEDONE irq\n"); | 914 | DSSERR("can't get FRAMEDONE irq\n"); |
| 915 | goto err1; | 915 | goto err1; |
| @@ -933,8 +933,10 @@ EXPORT_SYMBOL(omapdss_rfbi_display_enable); | |||
| 933 | 933 | ||
| 934 | void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) | 934 | void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) |
| 935 | { | 935 | { |
| 936 | omap_dispc_unregister_isr(framedone_callback, NULL, | 936 | struct omap_dss_output *out = dssdev->output; |
| 937 | DISPC_IRQ_FRAMEDONE); | 937 | |
| 938 | dss_mgr_unregister_framedone_handler(out->manager, | ||
| 939 | framedone_callback, NULL); | ||
| 938 | omap_dss_stop_device(dssdev); | 940 | omap_dss_stop_device(dssdev); |
| 939 | 941 | ||
| 940 | rfbi_runtime_put(); | 942 | rfbi_runtime_put(); |
| @@ -950,7 +952,7 @@ static int __init rfbi_init_display(struct omap_dss_device *dssdev) | |||
| 950 | static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev) | 952 | static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev) |
| 951 | { | 953 | { |
| 952 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 954 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
| 953 | const char *def_disp_name = dss_get_default_display_name(); | 955 | const char *def_disp_name = omapdss_get_default_display_name(); |
| 954 | struct omap_dss_device *def_dssdev; | 956 | struct omap_dss_device *def_dssdev; |
| 955 | int i; | 957 | int i; |
| 956 | 958 | ||
| @@ -999,9 +1001,18 @@ static void __init rfbi_probe_pdata(struct platform_device *rfbidev) | |||
| 999 | return; | 1001 | return; |
| 1000 | } | 1002 | } |
| 1001 | 1003 | ||
| 1004 | r = omapdss_output_set_device(&rfbi.output, dssdev); | ||
| 1005 | if (r) { | ||
| 1006 | DSSERR("failed to connect output to new device: %s\n", | ||
| 1007 | dssdev->name); | ||
| 1008 | dss_put_device(dssdev); | ||
| 1009 | return; | ||
| 1010 | } | ||
| 1011 | |||
| 1002 | r = dss_add_device(dssdev); | 1012 | r = dss_add_device(dssdev); |
| 1003 | if (r) { | 1013 | if (r) { |
| 1004 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | 1014 | DSSERR("device %s register failed: %d\n", dssdev->name, r); |
| 1015 | omapdss_output_unset_device(&rfbi.output); | ||
| 1005 | dss_put_device(dssdev); | 1016 | dss_put_device(dssdev); |
| 1006 | return; | 1017 | return; |
| 1007 | } | 1018 | } |
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 7760851f6e5d..62b5374ce438 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c | |||
| @@ -205,7 +205,7 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev) | |||
| 205 | static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) | 205 | static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) |
| 206 | { | 206 | { |
| 207 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 207 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
| 208 | const char *def_disp_name = dss_get_default_display_name(); | 208 | const char *def_disp_name = omapdss_get_default_display_name(); |
| 209 | struct omap_dss_device *def_dssdev; | 209 | struct omap_dss_device *def_dssdev; |
| 210 | int i; | 210 | int i; |
| 211 | 211 | ||
| @@ -254,9 +254,18 @@ static void __init sdi_probe_pdata(struct platform_device *sdidev) | |||
| 254 | return; | 254 | return; |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | r = omapdss_output_set_device(&sdi.output, dssdev); | ||
| 258 | if (r) { | ||
| 259 | DSSERR("failed to connect output to new device: %s\n", | ||
| 260 | dssdev->name); | ||
| 261 | dss_put_device(dssdev); | ||
| 262 | return; | ||
| 263 | } | ||
| 264 | |||
| 257 | r = dss_add_device(dssdev); | 265 | r = dss_add_device(dssdev); |
| 258 | if (r) { | 266 | if (r) { |
| 259 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | 267 | DSSERR("device %s register failed: %d\n", dssdev->name, r); |
| 268 | omapdss_output_unset_device(&sdi.output); | ||
| 260 | dss_put_device(dssdev); | 269 | dss_put_device(dssdev); |
| 261 | return; | 270 | return; |
| 262 | } | 271 | } |
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h index b046c208cb97..216aa704f9d7 100644 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ b/drivers/video/omap2/dss/ti_hdmi.h | |||
| @@ -102,6 +102,8 @@ struct ti_hdmi_ip_ops { | |||
| 102 | 102 | ||
| 103 | int (*audio_config)(struct hdmi_ip_data *ip_data, | 103 | int (*audio_config)(struct hdmi_ip_data *ip_data, |
| 104 | struct omap_dss_audio *audio); | 104 | struct omap_dss_audio *audio); |
| 105 | |||
| 106 | int (*audio_get_dma_port)(u32 *offset, u32 *size); | ||
| 105 | #endif | 107 | #endif |
| 106 | 108 | ||
| 107 | }; | 109 | }; |
| @@ -183,5 +185,6 @@ int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data); | |||
| 183 | void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data); | 185 | void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data); |
| 184 | int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data, | 186 | int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data, |
| 185 | struct omap_dss_audio *audio); | 187 | struct omap_dss_audio *audio); |
| 188 | int ti_hdmi_4xxx_audio_get_dma_port(u32 *offset, u32 *size); | ||
| 186 | #endif | 189 | #endif |
| 187 | #endif | 190 | #endif |
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c index c23b85a20cdc..e18b222ed739 100644 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c | |||
| @@ -899,7 +899,7 @@ void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | |||
| 899 | #define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\ | 899 | #define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\ |
| 900 | hdmi_read_reg(hdmi_av_base(ip_data), r)) | 900 | hdmi_read_reg(hdmi_av_base(ip_data), r)) |
| 901 | #define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \ | 901 | #define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \ |
| 902 | (i < 10) ? 32 - strlen(#r) : 31 - strlen(#r), " ", \ | 902 | (i < 10) ? 32 - (int)strlen(#r) : 31 - (int)strlen(#r), " ", \ |
| 903 | hdmi_read_reg(hdmi_av_base(ip_data), CORE_REG(i, r))) | 903 | hdmi_read_reg(hdmi_av_base(ip_data), CORE_REG(i, r))) |
| 904 | 904 | ||
| 905 | DUMPCORE(HDMI_CORE_SYS_VND_IDL); | 905 | DUMPCORE(HDMI_CORE_SYS_VND_IDL); |
| @@ -1418,4 +1418,13 @@ void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data) | |||
| 1418 | REG_FLD_MOD(hdmi_wp_base(ip_data), | 1418 | REG_FLD_MOD(hdmi_wp_base(ip_data), |
| 1419 | HDMI_WP_AUDIO_CTRL, false, 30, 30); | 1419 | HDMI_WP_AUDIO_CTRL, false, 30, 30); |
| 1420 | } | 1420 | } |
| 1421 | |||
| 1422 | int ti_hdmi_4xxx_audio_get_dma_port(u32 *offset, u32 *size) | ||
| 1423 | { | ||
| 1424 | if (!offset || !size) | ||
| 1425 | return -EINVAL; | ||
| 1426 | *offset = HDMI_WP_AUDIO_DATA; | ||
| 1427 | *size = 4; | ||
| 1428 | return 0; | ||
| 1429 | } | ||
| 1421 | #endif | 1430 | #endif |
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 56efa3bb465d..006caf3cb509 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c | |||
| @@ -744,7 +744,7 @@ static void venc_put_clocks(void) | |||
| 744 | static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) | 744 | static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) |
| 745 | { | 745 | { |
| 746 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 746 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
| 747 | const char *def_disp_name = dss_get_default_display_name(); | 747 | const char *def_disp_name = omapdss_get_default_display_name(); |
| 748 | struct omap_dss_device *def_dssdev; | 748 | struct omap_dss_device *def_dssdev; |
| 749 | int i; | 749 | int i; |
| 750 | 750 | ||
| @@ -795,9 +795,18 @@ static void __init venc_probe_pdata(struct platform_device *vencdev) | |||
| 795 | return; | 795 | return; |
| 796 | } | 796 | } |
| 797 | 797 | ||
| 798 | r = omapdss_output_set_device(&venc.output, dssdev); | ||
| 799 | if (r) { | ||
| 800 | DSSERR("failed to connect output to new device: %s\n", | ||
| 801 | dssdev->name); | ||
| 802 | dss_put_device(dssdev); | ||
| 803 | return; | ||
| 804 | } | ||
| 805 | |||
| 798 | r = dss_add_device(dssdev); | 806 | r = dss_add_device(dssdev); |
| 799 | if (r) { | 807 | if (r) { |
| 800 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | 808 | DSSERR("device %s register failed: %d\n", dssdev->name, r); |
| 809 | omapdss_output_unset_device(&venc.output); | ||
| 801 | dss_put_device(dssdev); | 810 | dss_put_device(dssdev); |
| 802 | return; | 811 | return; |
| 803 | } | 812 | } |
diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c index d55b8784ecfd..0d2b1a0834a0 100644 --- a/drivers/video/omap2/dss/venc_panel.c +++ b/drivers/video/omap2/dss/venc_panel.c | |||
| @@ -157,12 +157,6 @@ static void venc_panel_disable(struct omap_dss_device *dssdev) | |||
| 157 | if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) | 157 | if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) |
| 158 | goto end; | 158 | goto end; |
| 159 | 159 | ||
| 160 | if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { | ||
| 161 | /* suspended is the same as disabled with venc */ | ||
| 162 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
| 163 | goto end; | ||
| 164 | } | ||
| 165 | |||
| 166 | omapdss_venc_display_disable(dssdev); | 160 | omapdss_venc_display_disable(dssdev); |
| 167 | 161 | ||
| 168 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 162 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
| @@ -170,17 +164,6 @@ end: | |||
| 170 | mutex_unlock(&venc_panel.lock); | 164 | mutex_unlock(&venc_panel.lock); |
| 171 | } | 165 | } |
| 172 | 166 | ||
| 173 | static int venc_panel_suspend(struct omap_dss_device *dssdev) | ||
| 174 | { | ||
| 175 | venc_panel_disable(dssdev); | ||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | static int venc_panel_resume(struct omap_dss_device *dssdev) | ||
| 180 | { | ||
| 181 | return venc_panel_enable(dssdev); | ||
| 182 | } | ||
| 183 | |||
| 184 | static void venc_panel_set_timings(struct omap_dss_device *dssdev, | 167 | static void venc_panel_set_timings(struct omap_dss_device *dssdev, |
| 185 | struct omap_video_timings *timings) | 168 | struct omap_video_timings *timings) |
| 186 | { | 169 | { |
| @@ -222,8 +205,6 @@ static struct omap_dss_driver venc_driver = { | |||
| 222 | 205 | ||
| 223 | .enable = venc_panel_enable, | 206 | .enable = venc_panel_enable, |
| 224 | .disable = venc_panel_disable, | 207 | .disable = venc_panel_disable, |
| 225 | .suspend = venc_panel_suspend, | ||
| 226 | .resume = venc_panel_resume, | ||
| 227 | 208 | ||
| 228 | .get_resolution = omapdss_default_get_resolution, | 209 | .get_resolution = omapdss_default_get_resolution, |
| 229 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | 210 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, |
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig index 4ea17dc3258c..4cb12ce68855 100644 --- a/drivers/video/omap2/omapfb/Kconfig +++ b/drivers/video/omap2/omapfb/Kconfig | |||
| @@ -2,7 +2,6 @@ menuconfig FB_OMAP2 | |||
| 2 | tristate "OMAP2+ frame buffer support" | 2 | tristate "OMAP2+ frame buffer support" |
| 3 | depends on FB && OMAP2_DSS && !DRM_OMAP | 3 | depends on FB && OMAP2_DSS && !DRM_OMAP |
| 4 | 4 | ||
| 5 | select OMAP2_VRAM | ||
| 6 | select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 | 5 | select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 |
| 7 | select FB_CFB_FILLRECT | 6 | select FB_CFB_FILLRECT |
| 8 | select FB_CFB_COPYAREA | 7 | select FB_CFB_COPYAREA |
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 532a31b3d96b..d30b45d72649 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
| @@ -28,10 +28,10 @@ | |||
| 28 | #include <linux/omapfb.h> | 28 | #include <linux/omapfb.h> |
| 29 | #include <linux/vmalloc.h> | 29 | #include <linux/vmalloc.h> |
| 30 | #include <linux/export.h> | 30 | #include <linux/export.h> |
| 31 | #include <linux/sizes.h> | ||
| 31 | 32 | ||
| 32 | #include <video/omapdss.h> | 33 | #include <video/omapdss.h> |
| 33 | #include <video/omapvrfb.h> | 34 | #include <video/omapvrfb.h> |
| 34 | #include <plat/vram.h> | ||
| 35 | 35 | ||
| 36 | #include "omapfb.h" | 36 | #include "omapfb.h" |
| 37 | 37 | ||
| @@ -211,6 +211,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
| 211 | { | 211 | { |
| 212 | struct omapfb_info *ofbi = FB2OFB(fbi); | 212 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 213 | struct omapfb2_device *fbdev = ofbi->fbdev; | 213 | struct omapfb2_device *fbdev = ofbi->fbdev; |
| 214 | struct omap_dss_device *display = fb2display(fbi); | ||
| 214 | struct omapfb2_mem_region *rg; | 215 | struct omapfb2_mem_region *rg; |
| 215 | int r = 0, i; | 216 | int r = 0, i; |
| 216 | size_t size; | 217 | size_t size; |
| @@ -220,6 +221,9 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
| 220 | 221 | ||
| 221 | size = PAGE_ALIGN(mi->size); | 222 | size = PAGE_ALIGN(mi->size); |
| 222 | 223 | ||
| 224 | if (display && display->driver->sync) | ||
| 225 | display->driver->sync(display); | ||
| 226 | |||
| 223 | rg = ofbi->region; | 227 | rg = ofbi->region; |
| 224 | 228 | ||
| 225 | down_write_nested(&rg->lock, rg->id); | 229 | down_write_nested(&rg->lock, rg->id); |
| @@ -279,7 +283,7 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
| 279 | return 0; | 283 | return 0; |
| 280 | } | 284 | } |
| 281 | 285 | ||
| 282 | static int omapfb_update_window_nolock(struct fb_info *fbi, | 286 | static int omapfb_update_window(struct fb_info *fbi, |
| 283 | u32 x, u32 y, u32 w, u32 h) | 287 | u32 x, u32 y, u32 w, u32 h) |
| 284 | { | 288 | { |
| 285 | struct omap_dss_device *display = fb2display(fbi); | 289 | struct omap_dss_device *display = fb2display(fbi); |
| @@ -299,27 +303,6 @@ static int omapfb_update_window_nolock(struct fb_info *fbi, | |||
| 299 | return display->driver->update(display, x, y, w, h); | 303 | return display->driver->update(display, x, y, w, h); |
| 300 | } | 304 | } |
| 301 | 305 | ||
| 302 | /* This function is exported for SGX driver use */ | ||
| 303 | int omapfb_update_window(struct fb_info *fbi, | ||
| 304 | u32 x, u32 y, u32 w, u32 h) | ||
| 305 | { | ||
| 306 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
| 307 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
| 308 | int r; | ||
| 309 | |||
| 310 | if (!lock_fb_info(fbi)) | ||
| 311 | return -ENODEV; | ||
| 312 | omapfb_lock(fbdev); | ||
| 313 | |||
| 314 | r = omapfb_update_window_nolock(fbi, x, y, w, h); | ||
| 315 | |||
| 316 | omapfb_unlock(fbdev); | ||
| 317 | unlock_fb_info(fbi); | ||
| 318 | |||
| 319 | return r; | ||
| 320 | } | ||
| 321 | EXPORT_SYMBOL(omapfb_update_window); | ||
| 322 | |||
| 323 | int omapfb_set_update_mode(struct fb_info *fbi, | 306 | int omapfb_set_update_mode(struct fb_info *fbi, |
| 324 | enum omapfb_update_mode mode) | 307 | enum omapfb_update_mode mode) |
| 325 | { | 308 | { |
| @@ -646,7 +629,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
| 646 | break; | 629 | break; |
| 647 | } | 630 | } |
| 648 | 631 | ||
| 649 | r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y, | 632 | r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y, |
| 650 | p.uwnd_o.width, p.uwnd_o.height); | 633 | p.uwnd_o.width, p.uwnd_o.height); |
| 651 | break; | 634 | break; |
| 652 | 635 | ||
| @@ -663,7 +646,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
| 663 | break; | 646 | break; |
| 664 | } | 647 | } |
| 665 | 648 | ||
| 666 | r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y, | 649 | r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y, |
| 667 | p.uwnd.width, p.uwnd.height); | 650 | p.uwnd.width, p.uwnd.height); |
| 668 | break; | 651 | break; |
| 669 | 652 | ||
| @@ -853,14 +836,15 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
| 853 | break; | 836 | break; |
| 854 | 837 | ||
| 855 | case OMAPFB_GET_VRAM_INFO: { | 838 | case OMAPFB_GET_VRAM_INFO: { |
| 856 | unsigned long vram, free, largest; | ||
| 857 | |||
| 858 | DBG("ioctl GET_VRAM_INFO\n"); | 839 | DBG("ioctl GET_VRAM_INFO\n"); |
| 859 | 840 | ||
| 860 | omap_vram_get_info(&vram, &free, &largest); | 841 | /* |
| 861 | p.vram_info.total = vram; | 842 | * We don't have the ability to get this vram info anymore. |
| 862 | p.vram_info.free = free; | 843 | * Fill in something that should keep the applications working. |
| 863 | p.vram_info.largest_free_block = largest; | 844 | */ |
| 845 | p.vram_info.total = SZ_1M * 64; | ||
| 846 | p.vram_info.free = SZ_1M * 64; | ||
| 847 | p.vram_info.largest_free_block = SZ_1M * 64; | ||
| 864 | 848 | ||
| 865 | if (copy_to_user((void __user *)arg, &p.vram_info, | 849 | if (copy_to_user((void __user *)arg, &p.vram_info, |
| 866 | sizeof(p.vram_info))) | 850 | sizeof(p.vram_info))) |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index bc225e46fdd2..ca585ef37f25 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
| @@ -31,7 +31,6 @@ | |||
| 31 | #include <linux/omapfb.h> | 31 | #include <linux/omapfb.h> |
| 32 | 32 | ||
| 33 | #include <video/omapdss.h> | 33 | #include <video/omapdss.h> |
| 34 | #include <plat/vram.h> | ||
| 35 | #include <video/omapvrfb.h> | 34 | #include <video/omapvrfb.h> |
| 36 | 35 | ||
| 37 | #include "omapfb.h" | 36 | #include "omapfb.h" |
| @@ -1258,11 +1257,10 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
| 1258 | 1257 | ||
| 1259 | switch (blank) { | 1258 | switch (blank) { |
| 1260 | case FB_BLANK_UNBLANK: | 1259 | case FB_BLANK_UNBLANK: |
| 1261 | if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) | 1260 | if (display->state == OMAP_DSS_DISPLAY_ACTIVE) |
| 1262 | goto exit; | 1261 | goto exit; |
| 1263 | 1262 | ||
| 1264 | if (display->driver->resume) | 1263 | r = display->driver->enable(display); |
| 1265 | r = display->driver->resume(display); | ||
| 1266 | 1264 | ||
| 1267 | if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && | 1265 | if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && |
| 1268 | d->update_mode == OMAPFB_AUTO_UPDATE && | 1266 | d->update_mode == OMAPFB_AUTO_UPDATE && |
| @@ -1283,8 +1281,7 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
| 1283 | if (d->auto_update_work_enabled) | 1281 | if (d->auto_update_work_enabled) |
| 1284 | omapfb_stop_auto_update(fbdev, display); | 1282 | omapfb_stop_auto_update(fbdev, display); |
| 1285 | 1283 | ||
| 1286 | if (display->driver->suspend) | 1284 | display->driver->disable(display); |
| 1287 | r = display->driver->suspend(display); | ||
| 1288 | 1285 | ||
| 1289 | break; | 1286 | break; |
| 1290 | 1287 | ||
| @@ -1335,24 +1332,25 @@ static void omapfb_free_fbmem(struct fb_info *fbi) | |||
| 1335 | 1332 | ||
| 1336 | rg = ofbi->region; | 1333 | rg = ofbi->region; |
| 1337 | 1334 | ||
| 1338 | WARN_ON(atomic_read(&rg->map_count)); | 1335 | if (rg->token == NULL) |
| 1339 | 1336 | return; | |
| 1340 | if (rg->paddr) | ||
| 1341 | if (omap_vram_free(rg->paddr, rg->size)) | ||
| 1342 | dev_err(fbdev->dev, "VRAM FREE failed\n"); | ||
| 1343 | 1337 | ||
| 1344 | if (rg->vaddr) | 1338 | WARN_ON(atomic_read(&rg->map_count)); |
| 1345 | iounmap(rg->vaddr); | ||
| 1346 | 1339 | ||
| 1347 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { | 1340 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { |
| 1348 | /* unmap the 0 angle rotation */ | 1341 | /* unmap the 0 angle rotation */ |
| 1349 | if (rg->vrfb.vaddr[0]) { | 1342 | if (rg->vrfb.vaddr[0]) { |
| 1350 | iounmap(rg->vrfb.vaddr[0]); | 1343 | iounmap(rg->vrfb.vaddr[0]); |
| 1351 | omap_vrfb_release_ctx(&rg->vrfb); | ||
| 1352 | rg->vrfb.vaddr[0] = NULL; | 1344 | rg->vrfb.vaddr[0] = NULL; |
| 1353 | } | 1345 | } |
| 1346 | |||
| 1347 | omap_vrfb_release_ctx(&rg->vrfb); | ||
| 1354 | } | 1348 | } |
| 1355 | 1349 | ||
| 1350 | dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle, | ||
| 1351 | &rg->attrs); | ||
| 1352 | |||
| 1353 | rg->token = NULL; | ||
| 1356 | rg->vaddr = NULL; | 1354 | rg->vaddr = NULL; |
| 1357 | rg->paddr = 0; | 1355 | rg->paddr = 0; |
| 1358 | rg->alloc = 0; | 1356 | rg->alloc = 0; |
| @@ -1387,7 +1385,9 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, | |||
| 1387 | struct omapfb_info *ofbi = FB2OFB(fbi); | 1385 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 1388 | struct omapfb2_device *fbdev = ofbi->fbdev; | 1386 | struct omapfb2_device *fbdev = ofbi->fbdev; |
| 1389 | struct omapfb2_mem_region *rg; | 1387 | struct omapfb2_mem_region *rg; |
| 1390 | void __iomem *vaddr; | 1388 | void *token; |
| 1389 | DEFINE_DMA_ATTRS(attrs); | ||
| 1390 | dma_addr_t dma_handle; | ||
| 1391 | int r; | 1391 | int r; |
| 1392 | 1392 | ||
| 1393 | rg = ofbi->region; | 1393 | rg = ofbi->region; |
| @@ -1402,42 +1402,40 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, | |||
| 1402 | 1402 | ||
| 1403 | size = PAGE_ALIGN(size); | 1403 | size = PAGE_ALIGN(size); |
| 1404 | 1404 | ||
| 1405 | if (!paddr) { | 1405 | dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); |
| 1406 | DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); | ||
| 1407 | r = omap_vram_alloc(size, &paddr); | ||
| 1408 | } else { | ||
| 1409 | DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr, | ||
| 1410 | ofbi->id); | ||
| 1411 | r = omap_vram_reserve(paddr, size); | ||
| 1412 | } | ||
| 1413 | 1406 | ||
| 1414 | if (r) { | 1407 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) |
| 1408 | dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); | ||
| 1409 | |||
| 1410 | DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); | ||
| 1411 | |||
| 1412 | token = dma_alloc_attrs(fbdev->dev, size, &dma_handle, | ||
| 1413 | GFP_KERNEL, &attrs); | ||
| 1414 | |||
| 1415 | if (token == NULL) { | ||
| 1415 | dev_err(fbdev->dev, "failed to allocate framebuffer\n"); | 1416 | dev_err(fbdev->dev, "failed to allocate framebuffer\n"); |
| 1416 | return -ENOMEM; | 1417 | return -ENOMEM; |
| 1417 | } | 1418 | } |
| 1418 | 1419 | ||
| 1419 | if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) { | 1420 | DBG("allocated VRAM paddr %lx, vaddr %p\n", |
| 1420 | vaddr = ioremap_wc(paddr, size); | 1421 | (unsigned long)dma_handle, token); |
| 1421 | |||
| 1422 | if (!vaddr) { | ||
| 1423 | dev_err(fbdev->dev, "failed to ioremap framebuffer\n"); | ||
| 1424 | omap_vram_free(paddr, size); | ||
| 1425 | return -ENOMEM; | ||
| 1426 | } | ||
| 1427 | 1422 | ||
| 1428 | DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr); | 1423 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { |
| 1429 | } else { | ||
| 1430 | r = omap_vrfb_request_ctx(&rg->vrfb); | 1424 | r = omap_vrfb_request_ctx(&rg->vrfb); |
| 1431 | if (r) { | 1425 | if (r) { |
| 1426 | dma_free_attrs(fbdev->dev, size, token, dma_handle, | ||
| 1427 | &attrs); | ||
| 1432 | dev_err(fbdev->dev, "vrfb create ctx failed\n"); | 1428 | dev_err(fbdev->dev, "vrfb create ctx failed\n"); |
| 1433 | return r; | 1429 | return r; |
| 1434 | } | 1430 | } |
| 1435 | |||
| 1436 | vaddr = NULL; | ||
| 1437 | } | 1431 | } |
| 1438 | 1432 | ||
| 1439 | rg->paddr = paddr; | 1433 | rg->attrs = attrs; |
| 1440 | rg->vaddr = vaddr; | 1434 | rg->token = token; |
| 1435 | rg->dma_handle = dma_handle; | ||
| 1436 | |||
| 1437 | rg->paddr = (unsigned long)dma_handle; | ||
| 1438 | rg->vaddr = (void __iomem *)token; | ||
| 1441 | rg->size = size; | 1439 | rg->size = size; |
| 1442 | rg->alloc = 1; | 1440 | rg->alloc = 1; |
| 1443 | 1441 | ||
| @@ -1531,6 +1529,9 @@ static int omapfb_parse_vram_param(const char *param, int max_entries, | |||
| 1531 | 1529 | ||
| 1532 | } | 1530 | } |
| 1533 | 1531 | ||
| 1532 | WARN_ONCE(paddr, | ||
| 1533 | "reserving memory at predefined address not supported\n"); | ||
| 1534 | |||
| 1534 | paddrs[fbnum] = paddr; | 1535 | paddrs[fbnum] = paddr; |
| 1535 | sizes[fbnum] = size; | 1536 | sizes[fbnum] = size; |
| 1536 | 1537 | ||
| @@ -1610,7 +1611,6 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | |||
| 1610 | { | 1611 | { |
| 1611 | struct omapfb_info *ofbi = FB2OFB(fbi); | 1612 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 1612 | struct omapfb2_device *fbdev = ofbi->fbdev; | 1613 | struct omapfb2_device *fbdev = ofbi->fbdev; |
| 1613 | struct omap_dss_device *display = fb2display(fbi); | ||
| 1614 | struct omapfb2_mem_region *rg = ofbi->region; | 1614 | struct omapfb2_mem_region *rg = ofbi->region; |
| 1615 | unsigned long old_size = rg->size; | 1615 | unsigned long old_size = rg->size; |
| 1616 | unsigned long old_paddr = rg->paddr; | 1616 | unsigned long old_paddr = rg->paddr; |
| @@ -1625,9 +1625,6 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | |||
| 1625 | if (old_size == size && old_type == type) | 1625 | if (old_size == size && old_type == type) |
| 1626 | return 0; | 1626 | return 0; |
| 1627 | 1627 | ||
| 1628 | if (display && display->driver->sync) | ||
| 1629 | display->driver->sync(display); | ||
| 1630 | |||
| 1631 | omapfb_free_fbmem(fbi); | 1628 | omapfb_free_fbmem(fbi); |
| 1632 | 1629 | ||
| 1633 | if (size == 0) { | 1630 | if (size == 0) { |
| @@ -1882,7 +1879,6 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) | |||
| 1882 | } | 1879 | } |
| 1883 | 1880 | ||
| 1884 | dev_set_drvdata(fbdev->dev, NULL); | 1881 | dev_set_drvdata(fbdev->dev, NULL); |
| 1885 | kfree(fbdev); | ||
| 1886 | } | 1882 | } |
| 1887 | 1883 | ||
| 1888 | static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | 1884 | static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) |
| @@ -2258,26 +2254,28 @@ static int omapfb_find_best_mode(struct omap_dss_device *display, | |||
| 2258 | { | 2254 | { |
| 2259 | struct fb_monspecs *specs; | 2255 | struct fb_monspecs *specs; |
| 2260 | u8 *edid; | 2256 | u8 *edid; |
| 2261 | int r, i, best_xres, best_idx, len; | 2257 | int r, i, best_idx, len; |
| 2262 | 2258 | ||
| 2263 | if (!display->driver->read_edid) | 2259 | if (!display->driver->read_edid) |
| 2264 | return -ENODEV; | 2260 | return -ENODEV; |
| 2265 | 2261 | ||
| 2266 | len = 0x80 * 2; | 2262 | len = 0x80 * 2; |
| 2267 | edid = kmalloc(len, GFP_KERNEL); | 2263 | edid = kmalloc(len, GFP_KERNEL); |
| 2264 | if (edid == NULL) | ||
| 2265 | return -ENOMEM; | ||
| 2268 | 2266 | ||
| 2269 | r = display->driver->read_edid(display, edid, len); | 2267 | r = display->driver->read_edid(display, edid, len); |
| 2270 | if (r < 0) | 2268 | if (r < 0) |
| 2271 | goto err1; | 2269 | goto err1; |
| 2272 | 2270 | ||
| 2273 | specs = kzalloc(sizeof(*specs), GFP_KERNEL); | 2271 | specs = kzalloc(sizeof(*specs), GFP_KERNEL); |
| 2272 | if (specs == NULL) { | ||
| 2273 | r = -ENOMEM; | ||
| 2274 | goto err1; | ||
| 2275 | } | ||
| 2274 | 2276 | ||
| 2275 | fb_edid_to_monspecs(edid, specs); | 2277 | fb_edid_to_monspecs(edid, specs); |
| 2276 | 2278 | ||
| 2277 | if (edid[126] > 0) | ||
| 2278 | fb_edid_add_monspecs(edid + 0x80, specs); | ||
| 2279 | |||
| 2280 | best_xres = 0; | ||
| 2281 | best_idx = -1; | 2279 | best_idx = -1; |
| 2282 | 2280 | ||
| 2283 | for (i = 0; i < specs->modedb_len; ++i) { | 2281 | for (i = 0; i < specs->modedb_len; ++i) { |
| @@ -2293,16 +2291,20 @@ static int omapfb_find_best_mode(struct omap_dss_device *display, | |||
| 2293 | if (m->xres == 2880 || m->xres == 1440) | 2291 | if (m->xres == 2880 || m->xres == 1440) |
| 2294 | continue; | 2292 | continue; |
| 2295 | 2293 | ||
| 2294 | if (m->vmode & FB_VMODE_INTERLACED || | ||
| 2295 | m->vmode & FB_VMODE_DOUBLE) | ||
| 2296 | continue; | ||
| 2297 | |||
| 2296 | fb_videomode_to_omap_timings(m, display, &t); | 2298 | fb_videomode_to_omap_timings(m, display, &t); |
| 2297 | 2299 | ||
| 2298 | r = display->driver->check_timings(display, &t); | 2300 | r = display->driver->check_timings(display, &t); |
| 2299 | if (r == 0 && best_xres < m->xres) { | 2301 | if (r == 0) { |
| 2300 | best_xres = m->xres; | ||
| 2301 | best_idx = i; | 2302 | best_idx = i; |
| 2303 | break; | ||
| 2302 | } | 2304 | } |
| 2303 | } | 2305 | } |
| 2304 | 2306 | ||
| 2305 | if (best_xres == 0) { | 2307 | if (best_idx == -1) { |
| 2306 | r = -ENOENT; | 2308 | r = -ENOENT; |
| 2307 | goto err2; | 2309 | goto err2; |
| 2308 | } | 2310 | } |
| @@ -2371,15 +2373,62 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, | |||
| 2371 | return 0; | 2373 | return 0; |
| 2372 | } | 2374 | } |
| 2373 | 2375 | ||
| 2376 | static int omapfb_init_connections(struct omapfb2_device *fbdev, | ||
| 2377 | struct omap_dss_device *def_dssdev) | ||
| 2378 | { | ||
| 2379 | int i, r; | ||
| 2380 | struct omap_overlay_manager *mgr; | ||
| 2381 | |||
| 2382 | if (!def_dssdev->output) { | ||
| 2383 | dev_err(fbdev->dev, "no output for the default display\n"); | ||
| 2384 | return -EINVAL; | ||
| 2385 | } | ||
| 2386 | |||
| 2387 | for (i = 0; i < fbdev->num_displays; ++i) { | ||
| 2388 | struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; | ||
| 2389 | struct omap_dss_output *out = dssdev->output; | ||
| 2390 | |||
| 2391 | mgr = omap_dss_get_overlay_manager(dssdev->channel); | ||
| 2392 | |||
| 2393 | if (!mgr || !out) | ||
| 2394 | continue; | ||
| 2395 | |||
| 2396 | if (mgr->output) | ||
| 2397 | mgr->unset_output(mgr); | ||
| 2398 | |||
| 2399 | mgr->set_output(mgr, out); | ||
| 2400 | } | ||
| 2401 | |||
| 2402 | mgr = def_dssdev->output->manager; | ||
| 2403 | |||
| 2404 | if (!mgr) { | ||
| 2405 | dev_err(fbdev->dev, "no ovl manager for the default display\n"); | ||
| 2406 | return -EINVAL; | ||
| 2407 | } | ||
| 2408 | |||
| 2409 | for (i = 0; i < fbdev->num_overlays; i++) { | ||
| 2410 | struct omap_overlay *ovl = fbdev->overlays[i]; | ||
| 2411 | |||
| 2412 | if (ovl->manager) | ||
| 2413 | ovl->unset_manager(ovl); | ||
| 2414 | |||
| 2415 | r = ovl->set_manager(ovl, mgr); | ||
| 2416 | if (r) | ||
| 2417 | dev_warn(fbdev->dev, | ||
| 2418 | "failed to connect overlay %s to manager %s\n", | ||
| 2419 | ovl->name, mgr->name); | ||
| 2420 | } | ||
| 2421 | |||
| 2422 | return 0; | ||
| 2423 | } | ||
| 2424 | |||
| 2374 | static int __init omapfb_probe(struct platform_device *pdev) | 2425 | static int __init omapfb_probe(struct platform_device *pdev) |
| 2375 | { | 2426 | { |
| 2376 | struct omapfb2_device *fbdev = NULL; | 2427 | struct omapfb2_device *fbdev = NULL; |
| 2377 | int r = 0; | 2428 | int r = 0; |
| 2378 | int i; | 2429 | int i; |
| 2379 | struct omap_overlay *ovl; | ||
| 2380 | struct omap_dss_device *def_display; | 2430 | struct omap_dss_device *def_display; |
| 2381 | struct omap_dss_device *dssdev; | 2431 | struct omap_dss_device *dssdev; |
| 2382 | struct omap_dss_device *ovl_device; | ||
| 2383 | 2432 | ||
| 2384 | DBG("omapfb_probe\n"); | 2433 | DBG("omapfb_probe\n"); |
| 2385 | 2434 | ||
| @@ -2389,7 +2438,8 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
| 2389 | goto err0; | 2438 | goto err0; |
| 2390 | } | 2439 | } |
| 2391 | 2440 | ||
| 2392 | fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL); | 2441 | fbdev = devm_kzalloc(&pdev->dev, sizeof(struct omapfb2_device), |
| 2442 | GFP_KERNEL); | ||
| 2393 | if (fbdev == NULL) { | 2443 | if (fbdev == NULL) { |
| 2394 | r = -ENOMEM; | 2444 | r = -ENOMEM; |
| 2395 | goto err0; | 2445 | goto err0; |
| @@ -2401,13 +2451,15 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
| 2401 | "ignoring the module parameter vrfb=y\n"); | 2451 | "ignoring the module parameter vrfb=y\n"); |
| 2402 | } | 2452 | } |
| 2403 | 2453 | ||
| 2454 | r = omapdss_compat_init(); | ||
| 2455 | if (r) | ||
| 2456 | goto err0; | ||
| 2404 | 2457 | ||
| 2405 | mutex_init(&fbdev->mtx); | 2458 | mutex_init(&fbdev->mtx); |
| 2406 | 2459 | ||
| 2407 | fbdev->dev = &pdev->dev; | 2460 | fbdev->dev = &pdev->dev; |
| 2408 | platform_set_drvdata(pdev, fbdev); | 2461 | platform_set_drvdata(pdev, fbdev); |
| 2409 | 2462 | ||
| 2410 | r = 0; | ||
| 2411 | fbdev->num_displays = 0; | 2463 | fbdev->num_displays = 0; |
| 2412 | dssdev = NULL; | 2464 | dssdev = NULL; |
| 2413 | for_each_dss_dev(dssdev) { | 2465 | for_each_dss_dev(dssdev) { |
| @@ -2430,9 +2482,6 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
| 2430 | d->update_mode = OMAPFB_AUTO_UPDATE; | 2482 | d->update_mode = OMAPFB_AUTO_UPDATE; |
| 2431 | } | 2483 | } |
| 2432 | 2484 | ||
| 2433 | if (r) | ||
| 2434 | goto cleanup; | ||
| 2435 | |||
| 2436 | if (fbdev->num_displays == 0) { | 2485 | if (fbdev->num_displays == 0) { |
| 2437 | dev_err(&pdev->dev, "no displays\n"); | 2486 | dev_err(&pdev->dev, "no displays\n"); |
| 2438 | r = -EINVAL; | 2487 | r = -EINVAL; |
| @@ -2447,15 +2496,33 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
| 2447 | for (i = 0; i < fbdev->num_managers; i++) | 2496 | for (i = 0; i < fbdev->num_managers; i++) |
| 2448 | fbdev->managers[i] = omap_dss_get_overlay_manager(i); | 2497 | fbdev->managers[i] = omap_dss_get_overlay_manager(i); |
| 2449 | 2498 | ||
| 2450 | /* gfx overlay should be the default one. find a display | 2499 | def_display = NULL; |
| 2451 | * connected to that, and use it as default display */ | 2500 | |
| 2452 | ovl = omap_dss_get_overlay(0); | 2501 | for (i = 0; i < fbdev->num_displays; ++i) { |
| 2453 | ovl_device = ovl->get_device(ovl); | 2502 | struct omap_dss_device *dssdev; |
| 2454 | if (ovl_device) { | 2503 | const char *def_name; |
| 2455 | def_display = ovl_device; | 2504 | |
| 2456 | } else { | 2505 | def_name = omapdss_get_default_display_name(); |
| 2457 | dev_warn(&pdev->dev, "cannot find default display\n"); | 2506 | |
| 2458 | def_display = NULL; | 2507 | dssdev = fbdev->displays[i].dssdev; |
| 2508 | |||
| 2509 | if (def_name == NULL || | ||
| 2510 | (dssdev->name && strcmp(def_name, dssdev->name) == 0)) { | ||
| 2511 | def_display = dssdev; | ||
| 2512 | break; | ||
| 2513 | } | ||
| 2514 | } | ||
| 2515 | |||
| 2516 | if (def_display == NULL) { | ||
| 2517 | dev_err(fbdev->dev, "failed to find default display\n"); | ||
| 2518 | r = -EINVAL; | ||
| 2519 | goto cleanup; | ||
| 2520 | } | ||
| 2521 | |||
| 2522 | r = omapfb_init_connections(fbdev, def_display); | ||
| 2523 | if (r) { | ||
| 2524 | dev_err(fbdev->dev, "failed to init overlay connections\n"); | ||
| 2525 | goto cleanup; | ||
| 2459 | } | 2526 | } |
| 2460 | 2527 | ||
| 2461 | if (def_mode && strlen(def_mode) > 0) { | 2528 | if (def_mode && strlen(def_mode) > 0) { |
| @@ -2506,6 +2573,7 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
| 2506 | 2573 | ||
| 2507 | cleanup: | 2574 | cleanup: |
| 2508 | omapfb_free_resources(fbdev); | 2575 | omapfb_free_resources(fbdev); |
| 2576 | omapdss_compat_uninit(); | ||
| 2509 | err0: | 2577 | err0: |
| 2510 | dev_err(&pdev->dev, "failed to setup omapfb\n"); | 2578 | dev_err(&pdev->dev, "failed to setup omapfb\n"); |
| 2511 | return r; | 2579 | return r; |
| @@ -2521,6 +2589,8 @@ static int __exit omapfb_remove(struct platform_device *pdev) | |||
| 2521 | 2589 | ||
| 2522 | omapfb_free_resources(fbdev); | 2590 | omapfb_free_resources(fbdev); |
| 2523 | 2591 | ||
| 2592 | omapdss_compat_uninit(); | ||
| 2593 | |||
| 2524 | return 0; | 2594 | return 0; |
| 2525 | } | 2595 | } |
| 2526 | 2596 | ||
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 17aa174e187c..18fa9e1d0033 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c | |||
| @@ -441,6 +441,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, | |||
| 441 | struct fb_info *fbi = dev_get_drvdata(dev); | 441 | struct fb_info *fbi = dev_get_drvdata(dev); |
| 442 | struct omapfb_info *ofbi = FB2OFB(fbi); | 442 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 443 | struct omapfb2_device *fbdev = ofbi->fbdev; | 443 | struct omapfb2_device *fbdev = ofbi->fbdev; |
| 444 | struct omap_dss_device *display = fb2display(fbi); | ||
| 444 | struct omapfb2_mem_region *rg; | 445 | struct omapfb2_mem_region *rg; |
| 445 | unsigned long size; | 446 | unsigned long size; |
| 446 | int r; | 447 | int r; |
| @@ -455,6 +456,9 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, | |||
| 455 | if (!lock_fb_info(fbi)) | 456 | if (!lock_fb_info(fbi)) |
| 456 | return -ENODEV; | 457 | return -ENODEV; |
| 457 | 458 | ||
| 459 | if (display && display->driver->sync) | ||
| 460 | display->driver->sync(display); | ||
| 461 | |||
| 458 | rg = ofbi->region; | 462 | rg = ofbi->region; |
| 459 | 463 | ||
| 460 | down_write_nested(&rg->lock, rg->id); | 464 | down_write_nested(&rg->lock, rg->id); |
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index 5ced9b334d35..623cd872a367 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h | |||
| @@ -28,6 +28,8 @@ | |||
| 28 | #endif | 28 | #endif |
| 29 | 29 | ||
| 30 | #include <linux/rwsem.h> | 30 | #include <linux/rwsem.h> |
| 31 | #include <linux/dma-attrs.h> | ||
| 32 | #include <linux/dma-mapping.h> | ||
| 31 | 33 | ||
| 32 | #include <video/omapdss.h> | 34 | #include <video/omapdss.h> |
| 33 | 35 | ||
| @@ -49,6 +51,9 @@ extern bool omapfb_debug; | |||
| 49 | 51 | ||
| 50 | struct omapfb2_mem_region { | 52 | struct omapfb2_mem_region { |
| 51 | int id; | 53 | int id; |
| 54 | struct dma_attrs attrs; | ||
| 55 | void *token; | ||
| 56 | dma_addr_t dma_handle; | ||
| 52 | u32 paddr; | 57 | u32 paddr; |
| 53 | void __iomem *vaddr; | 58 | void __iomem *vaddr; |
| 54 | struct vrfb vrfb; | 59 | struct vrfb vrfb; |
| @@ -124,9 +129,6 @@ void omapfb_remove_sysfs(struct omapfb2_device *fbdev); | |||
| 124 | 129 | ||
| 125 | int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg); | 130 | int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg); |
| 126 | 131 | ||
| 127 | int omapfb_update_window(struct fb_info *fbi, | ||
| 128 | u32 x, u32 y, u32 w, u32 h); | ||
| 129 | |||
| 130 | int dss_mode_to_fb_mode(enum omap_color_mode dssmode, | 132 | int dss_mode_to_fb_mode(enum omap_color_mode dssmode, |
| 131 | struct fb_var_screeninfo *var); | 133 | struct fb_var_screeninfo *var); |
| 132 | 134 | ||
| @@ -144,16 +146,16 @@ int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode); | |||
| 144 | static inline struct omap_dss_device *fb2display(struct fb_info *fbi) | 146 | static inline struct omap_dss_device *fb2display(struct fb_info *fbi) |
| 145 | { | 147 | { |
| 146 | struct omapfb_info *ofbi = FB2OFB(fbi); | 148 | struct omapfb_info *ofbi = FB2OFB(fbi); |
| 147 | int i; | 149 | struct omap_overlay *ovl; |
| 148 | 150 | ||
| 149 | /* XXX: returns the display connected to first attached overlay */ | 151 | /* XXX: returns the display connected to first attached overlay */ |
| 150 | for (i = 0; i < ofbi->num_overlays; i++) { | ||
| 151 | struct omap_overlay *ovl = ofbi->overlays[i]; | ||
| 152 | 152 | ||
| 153 | return ovl->get_device(ovl); | 153 | if (ofbi->num_overlays == 0) |
| 154 | } | 154 | return NULL; |
| 155 | 155 | ||
| 156 | return NULL; | 156 | ovl = ofbi->overlays[0]; |
| 157 | |||
| 158 | return ovl->get_device(ovl); | ||
| 157 | } | 159 | } |
| 158 | 160 | ||
| 159 | static inline struct omapfb_display_data *get_display_data( | 161 | static inline struct omapfb_display_data *get_display_data( |
diff --git a/drivers/video/omap2/vram.c b/drivers/video/omap2/vram.c deleted file mode 100644 index f2b15c4a75bc..000000000000 --- a/drivers/video/omap2/vram.c +++ /dev/null | |||
| @@ -1,514 +0,0 @@ | |||
| 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/slab.h> | ||
| 27 | #include <linux/seq_file.h> | ||
| 28 | #include <linux/memblock.h> | ||
| 29 | #include <linux/completion.h> | ||
| 30 | #include <linux/debugfs.h> | ||
| 31 | #include <linux/jiffies.h> | ||
| 32 | #include <linux/module.h> | ||
| 33 | |||
| 34 | #include <asm/setup.h> | ||
| 35 | |||
| 36 | #include <plat/vram.h> | ||
| 37 | |||
| 38 | #ifdef DEBUG | ||
| 39 | #define DBG(format, ...) pr_debug("VRAM: " format, ## __VA_ARGS__) | ||
| 40 | #else | ||
| 41 | #define DBG(format, ...) | ||
| 42 | #endif | ||
| 43 | |||
| 44 | /* postponed regions are used to temporarily store region information at boot | ||
| 45 | * time when we cannot yet allocate the region list */ | ||
| 46 | #define MAX_POSTPONED_REGIONS 10 | ||
| 47 | |||
| 48 | static bool vram_initialized; | ||
| 49 | static int postponed_cnt; | ||
| 50 | static struct { | ||
| 51 | unsigned long paddr; | ||
| 52 | size_t size; | ||
| 53 | } postponed_regions[MAX_POSTPONED_REGIONS]; | ||
| 54 | |||
| 55 | struct vram_alloc { | ||
| 56 | struct list_head list; | ||
| 57 | unsigned long paddr; | ||
| 58 | unsigned pages; | ||
| 59 | }; | ||
| 60 | |||
| 61 | struct vram_region { | ||
| 62 | struct list_head list; | ||
| 63 | struct list_head alloc_list; | ||
| 64 | unsigned long paddr; | ||
| 65 | unsigned pages; | ||
| 66 | }; | ||
| 67 | |||
| 68 | static DEFINE_MUTEX(region_mutex); | ||
| 69 | static LIST_HEAD(region_list); | ||
| 70 | |||
| 71 | static struct vram_region *omap_vram_create_region(unsigned long paddr, | ||
| 72 | unsigned pages) | ||
| 73 | { | ||
| 74 | struct vram_region *rm; | ||
| 75 | |||
| 76 | rm = kzalloc(sizeof(*rm), GFP_KERNEL); | ||
| 77 | |||
| 78 | if (rm) { | ||
| 79 | INIT_LIST_HEAD(&rm->alloc_list); | ||
| 80 | rm->paddr = paddr; | ||
| 81 | rm->pages = pages; | ||
| 82 | } | ||
| 83 | |||
| 84 | return rm; | ||
| 85 | } | ||
| 86 | |||
| 87 | #if 0 | ||
| 88 | static void omap_vram_free_region(struct vram_region *vr) | ||
| 89 | { | ||
| 90 | list_del(&vr->list); | ||
| 91 | kfree(vr); | ||
| 92 | } | ||
| 93 | #endif | ||
| 94 | |||
| 95 | static struct vram_alloc *omap_vram_create_allocation(struct vram_region *vr, | ||
| 96 | unsigned long paddr, unsigned pages) | ||
| 97 | { | ||
| 98 | struct vram_alloc *va; | ||
| 99 | struct vram_alloc *new; | ||
| 100 | |||
| 101 | new = kzalloc(sizeof(*va), GFP_KERNEL); | ||
| 102 | |||
| 103 | if (!new) | ||
| 104 | return NULL; | ||
| 105 | |||
| 106 | new->paddr = paddr; | ||
| 107 | new->pages = pages; | ||
| 108 | |||
| 109 | list_for_each_entry(va, &vr->alloc_list, list) { | ||
| 110 | if (va->paddr > new->paddr) | ||
| 111 | break; | ||
| 112 | } | ||
| 113 | |||
| 114 | list_add_tail(&new->list, &va->list); | ||
| 115 | |||
| 116 | return new; | ||
| 117 | } | ||
| 118 | |||
| 119 | static void omap_vram_free_allocation(struct vram_alloc *va) | ||
| 120 | { | ||
| 121 | list_del(&va->list); | ||
| 122 | kfree(va); | ||
| 123 | } | ||
| 124 | |||
| 125 | int omap_vram_add_region(unsigned long paddr, size_t size) | ||
| 126 | { | ||
| 127 | struct vram_region *rm; | ||
| 128 | unsigned pages; | ||
| 129 | |||
| 130 | if (vram_initialized) { | ||
| 131 | DBG("adding region paddr %08lx size %d\n", | ||
| 132 | paddr, size); | ||
| 133 | |||
| 134 | size &= PAGE_MASK; | ||
| 135 | pages = size >> PAGE_SHIFT; | ||
| 136 | |||
| 137 | rm = omap_vram_create_region(paddr, pages); | ||
| 138 | if (rm == NULL) | ||
| 139 | return -ENOMEM; | ||
| 140 | |||
| 141 | list_add(&rm->list, ®ion_list); | ||
| 142 | } else { | ||
| 143 | if (postponed_cnt == MAX_POSTPONED_REGIONS) | ||
| 144 | return -ENOMEM; | ||
| 145 | |||
| 146 | postponed_regions[postponed_cnt].paddr = paddr; | ||
| 147 | postponed_regions[postponed_cnt].size = size; | ||
| 148 | |||
| 149 | ++postponed_cnt; | ||
| 150 | } | ||
| 151 | return 0; | ||
| 152 | } | ||
| 153 | |||
| 154 | int omap_vram_free(unsigned long paddr, size_t size) | ||
| 155 | { | ||
| 156 | struct vram_region *rm; | ||
| 157 | struct vram_alloc *alloc; | ||
| 158 | unsigned start, end; | ||
| 159 | |||
| 160 | DBG("free mem paddr %08lx size %d\n", paddr, size); | ||
| 161 | |||
| 162 | size = PAGE_ALIGN(size); | ||
| 163 | |||
| 164 | mutex_lock(®ion_mutex); | ||
| 165 | |||
| 166 | list_for_each_entry(rm, ®ion_list, list) { | ||
| 167 | list_for_each_entry(alloc, &rm->alloc_list, list) { | ||
| 168 | start = alloc->paddr; | ||
| 169 | end = alloc->paddr + (alloc->pages >> PAGE_SHIFT); | ||
| 170 | |||
| 171 | if (start >= paddr && end < paddr + size) | ||
| 172 | goto found; | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | mutex_unlock(®ion_mutex); | ||
| 177 | return -EINVAL; | ||
| 178 | |||
| 179 | found: | ||
| 180 | omap_vram_free_allocation(alloc); | ||
| 181 | |||
| 182 | mutex_unlock(®ion_mutex); | ||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | EXPORT_SYMBOL(omap_vram_free); | ||
| 186 | |||
| 187 | static int _omap_vram_reserve(unsigned long paddr, unsigned pages) | ||
| 188 | { | ||
| 189 | struct vram_region *rm; | ||
| 190 | struct vram_alloc *alloc; | ||
| 191 | size_t size; | ||
| 192 | |||
| 193 | size = pages << PAGE_SHIFT; | ||
| 194 | |||
| 195 | list_for_each_entry(rm, ®ion_list, list) { | ||
| 196 | unsigned long start, end; | ||
| 197 | |||
| 198 | DBG("checking region %lx %d\n", rm->paddr, rm->pages); | ||
| 199 | |||
| 200 | start = rm->paddr; | ||
| 201 | end = start + (rm->pages << PAGE_SHIFT) - 1; | ||
| 202 | if (start > paddr || end < paddr + size - 1) | ||
| 203 | continue; | ||
| 204 | |||
| 205 | DBG("block ok, checking allocs\n"); | ||
| 206 | |||
| 207 | list_for_each_entry(alloc, &rm->alloc_list, list) { | ||
| 208 | end = alloc->paddr - 1; | ||
| 209 | |||
| 210 | if (start <= paddr && end >= paddr + size - 1) | ||
| 211 | goto found; | ||
| 212 | |||
| 213 | start = alloc->paddr + (alloc->pages << PAGE_SHIFT); | ||
| 214 | } | ||
| 215 | |||
| 216 | end = rm->paddr + (rm->pages << PAGE_SHIFT) - 1; | ||
| 217 | |||
| 218 | if (!(start <= paddr && end >= paddr + size - 1)) | ||
| 219 | continue; | ||
| 220 | found: | ||
| 221 | DBG("found area start %lx, end %lx\n", start, end); | ||
| 222 | |||
| 223 | if (omap_vram_create_allocation(rm, paddr, pages) == NULL) | ||
| 224 | return -ENOMEM; | ||
| 225 | |||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | return -ENOMEM; | ||
| 230 | } | ||
| 231 | |||
| 232 | int omap_vram_reserve(unsigned long paddr, size_t size) | ||
| 233 | { | ||
| 234 | unsigned pages; | ||
| 235 | int r; | ||
| 236 | |||
| 237 | DBG("reserve mem paddr %08lx size %d\n", paddr, size); | ||
| 238 | |||
| 239 | size = PAGE_ALIGN(size); | ||
| 240 | pages = size >> PAGE_SHIFT; | ||
| 241 | |||
| 242 | mutex_lock(®ion_mutex); | ||
| 243 | |||
| 244 | r = _omap_vram_reserve(paddr, pages); | ||
| 245 | |||
| 246 | mutex_unlock(®ion_mutex); | ||
| 247 | |||
| 248 | return r; | ||
| 249 | } | ||
| 250 | EXPORT_SYMBOL(omap_vram_reserve); | ||
| 251 | |||
| 252 | static int _omap_vram_alloc(unsigned pages, unsigned long *paddr) | ||
| 253 | { | ||
| 254 | struct vram_region *rm; | ||
| 255 | struct vram_alloc *alloc; | ||
| 256 | |||
| 257 | list_for_each_entry(rm, ®ion_list, list) { | ||
| 258 | unsigned long start, end; | ||
| 259 | |||
| 260 | DBG("checking region %lx %d\n", rm->paddr, rm->pages); | ||
| 261 | |||
| 262 | start = rm->paddr; | ||
| 263 | |||
| 264 | list_for_each_entry(alloc, &rm->alloc_list, list) { | ||
| 265 | end = alloc->paddr; | ||
| 266 | |||
| 267 | if (end - start >= pages << PAGE_SHIFT) | ||
| 268 | goto found; | ||
| 269 | |||
| 270 | start = alloc->paddr + (alloc->pages << PAGE_SHIFT); | ||
| 271 | } | ||
| 272 | |||
| 273 | end = rm->paddr + (rm->pages << PAGE_SHIFT); | ||
| 274 | found: | ||
| 275 | if (end - start < pages << PAGE_SHIFT) | ||
| 276 | continue; | ||
| 277 | |||
| 278 | DBG("found %lx, end %lx\n", start, end); | ||
| 279 | |||
| 280 | alloc = omap_vram_create_allocation(rm, start, pages); | ||
| 281 | if (alloc == NULL) | ||
| 282 | return -ENOMEM; | ||
| 283 | |||
| 284 | *paddr = start; | ||
| 285 | |||
| 286 | return 0; | ||
| 287 | } | ||
| 288 | |||
| 289 | return -ENOMEM; | ||
| 290 | } | ||
| 291 | |||
| 292 | int omap_vram_alloc(size_t size, unsigned long *paddr) | ||
| 293 | { | ||
| 294 | unsigned pages; | ||
| 295 | int r; | ||
| 296 | |||
| 297 | BUG_ON(!size); | ||
| 298 | |||
| 299 | DBG("alloc mem size %d\n", size); | ||
| 300 | |||
| 301 | size = PAGE_ALIGN(size); | ||
| 302 | pages = size >> PAGE_SHIFT; | ||
| 303 | |||
| 304 | mutex_lock(®ion_mutex); | ||
| 305 | |||
| 306 | r = _omap_vram_alloc(pages, paddr); | ||
| 307 | |||
| 308 | mutex_unlock(®ion_mutex); | ||
| 309 | |||
| 310 | return r; | ||
| 311 | } | ||
| 312 | EXPORT_SYMBOL(omap_vram_alloc); | ||
| 313 | |||
| 314 | void omap_vram_get_info(unsigned long *vram, | ||
| 315 | unsigned long *free_vram, | ||
| 316 | unsigned long *largest_free_block) | ||
| 317 | { | ||
| 318 | struct vram_region *vr; | ||
| 319 | struct vram_alloc *va; | ||
| 320 | |||
| 321 | *vram = 0; | ||
| 322 | *free_vram = 0; | ||
| 323 | *largest_free_block = 0; | ||
| 324 | |||
| 325 | mutex_lock(®ion_mutex); | ||
| 326 | |||
| 327 | list_for_each_entry(vr, ®ion_list, list) { | ||
| 328 | unsigned free; | ||
| 329 | unsigned long pa; | ||
| 330 | |||
| 331 | pa = vr->paddr; | ||
| 332 | *vram += vr->pages << PAGE_SHIFT; | ||
| 333 | |||
| 334 | list_for_each_entry(va, &vr->alloc_list, list) { | ||
| 335 | free = va->paddr - pa; | ||
| 336 | *free_vram += free; | ||
| 337 | if (free > *largest_free_block) | ||
| 338 | *largest_free_block = free; | ||
| 339 | pa = va->paddr + (va->pages << PAGE_SHIFT); | ||
| 340 | } | ||
| 341 | |||
| 342 | free = vr->paddr + (vr->pages << PAGE_SHIFT) - pa; | ||
| 343 | *free_vram += free; | ||
| 344 | if (free > *largest_free_block) | ||
| 345 | *largest_free_block = free; | ||
| 346 | } | ||
| 347 | |||
| 348 | mutex_unlock(®ion_mutex); | ||
| 349 | } | ||
| 350 | EXPORT_SYMBOL(omap_vram_get_info); | ||
| 351 | |||
| 352 | #if defined(CONFIG_DEBUG_FS) | ||
| 353 | static int vram_debug_show(struct seq_file *s, void *unused) | ||
| 354 | { | ||
| 355 | struct vram_region *vr; | ||
| 356 | struct vram_alloc *va; | ||
| 357 | unsigned size; | ||
| 358 | |||
| 359 | mutex_lock(®ion_mutex); | ||
| 360 | |||
| 361 | list_for_each_entry(vr, ®ion_list, list) { | ||
| 362 | size = vr->pages << PAGE_SHIFT; | ||
| 363 | seq_printf(s, "%08lx-%08lx (%d bytes)\n", | ||
| 364 | vr->paddr, vr->paddr + size - 1, | ||
| 365 | size); | ||
| 366 | |||
| 367 | list_for_each_entry(va, &vr->alloc_list, list) { | ||
| 368 | size = va->pages << PAGE_SHIFT; | ||
| 369 | seq_printf(s, " %08lx-%08lx (%d bytes)\n", | ||
| 370 | va->paddr, va->paddr + size - 1, | ||
| 371 | size); | ||
| 372 | } | ||
| 373 | } | ||
| 374 | |||
| 375 | mutex_unlock(®ion_mutex); | ||
| 376 | |||
| 377 | return 0; | ||
| 378 | } | ||
| 379 | |||
| 380 | static int vram_debug_open(struct inode *inode, struct file *file) | ||
| 381 | { | ||
| 382 | return single_open(file, vram_debug_show, inode->i_private); | ||
| 383 | } | ||
| 384 | |||
| 385 | static const struct file_operations vram_debug_fops = { | ||
| 386 | .open = vram_debug_open, | ||
| 387 | .read = seq_read, | ||
| 388 | .llseek = seq_lseek, | ||
| 389 | .release = single_release, | ||
| 390 | }; | ||
| 391 | |||
| 392 | static int __init omap_vram_create_debugfs(void) | ||
| 393 | { | ||
| 394 | struct dentry *d; | ||
| 395 | |||
| 396 | d = debugfs_create_file("vram", S_IRUGO, NULL, | ||
| 397 | NULL, &vram_debug_fops); | ||
| 398 | if (IS_ERR(d)) | ||
| 399 | return PTR_ERR(d); | ||
| 400 | |||
| 401 | return 0; | ||
| 402 | } | ||
| 403 | #endif | ||
| 404 | |||
| 405 | static __init int omap_vram_init(void) | ||
| 406 | { | ||
| 407 | int i; | ||
| 408 | |||
| 409 | vram_initialized = 1; | ||
| 410 | |||
| 411 | for (i = 0; i < postponed_cnt; i++) | ||
| 412 | omap_vram_add_region(postponed_regions[i].paddr, | ||
| 413 | postponed_regions[i].size); | ||
| 414 | |||
| 415 | #ifdef CONFIG_DEBUG_FS | ||
| 416 | if (omap_vram_create_debugfs()) | ||
| 417 | pr_err("VRAM: Failed to create debugfs file\n"); | ||
| 418 | #endif | ||
| 419 | |||
| 420 | return 0; | ||
| 421 | } | ||
| 422 | |||
| 423 | arch_initcall(omap_vram_init); | ||
| 424 | |||
| 425 | /* boottime vram alloc stuff */ | ||
| 426 | |||
| 427 | /* set from board file */ | ||
| 428 | static u32 omap_vram_sdram_start __initdata; | ||
| 429 | static u32 omap_vram_sdram_size __initdata; | ||
| 430 | |||
| 431 | /* set from kernel cmdline */ | ||
| 432 | static u32 omap_vram_def_sdram_size __initdata; | ||
| 433 | static u32 omap_vram_def_sdram_start __initdata; | ||
| 434 | |||
| 435 | static int __init omap_vram_early_vram(char *p) | ||
| 436 | { | ||
| 437 | omap_vram_def_sdram_size = memparse(p, &p); | ||
| 438 | if (*p == ',') | ||
| 439 | omap_vram_def_sdram_start = simple_strtoul(p + 1, &p, 16); | ||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | early_param("vram", omap_vram_early_vram); | ||
| 443 | |||
| 444 | /* | ||
| 445 | * Called from map_io. We need to call to this early enough so that we | ||
| 446 | * can reserve the fixed SDRAM regions before VM could get hold of them. | ||
| 447 | */ | ||
| 448 | void __init omap_vram_reserve_sdram_memblock(void) | ||
| 449 | { | ||
| 450 | u32 paddr; | ||
| 451 | u32 size = 0; | ||
| 452 | |||
| 453 | /* cmdline arg overrides the board file definition */ | ||
| 454 | if (omap_vram_def_sdram_size) { | ||
| 455 | size = omap_vram_def_sdram_size; | ||
| 456 | paddr = omap_vram_def_sdram_start; | ||
| 457 | } | ||
| 458 | |||
| 459 | if (!size) { | ||
| 460 | size = omap_vram_sdram_size; | ||
| 461 | paddr = omap_vram_sdram_start; | ||
| 462 | } | ||
| 463 | |||
| 464 | #ifdef CONFIG_OMAP2_VRAM_SIZE | ||
| 465 | if (!size) { | ||
| 466 | size = CONFIG_OMAP2_VRAM_SIZE * 1024 * 1024; | ||
| 467 | paddr = 0; | ||
| 468 | } | ||
| 469 | #endif | ||
| 470 | |||
| 471 | if (!size) | ||
| 472 | return; | ||
| 473 | |||
| 474 | size = ALIGN(size, SZ_2M); | ||
| 475 | |||
| 476 | if (paddr) { | ||
| 477 | if (paddr & ~PAGE_MASK) { | ||
| 478 | pr_err("VRAM start address 0x%08x not page aligned\n", | ||
| 479 | paddr); | ||
| 480 | return; | ||
| 481 | } | ||
| 482 | |||
| 483 | if (!memblock_is_region_memory(paddr, size)) { | ||
| 484 | pr_err("Illegal SDRAM region 0x%08x..0x%08x for VRAM\n", | ||
| 485 | paddr, paddr + size - 1); | ||
| 486 | return; | ||
| 487 | } | ||
| 488 | |||
| 489 | if (memblock_is_region_reserved(paddr, size)) { | ||
| 490 | pr_err("FB: failed to reserve VRAM - busy\n"); | ||
| 491 | return; | ||
| 492 | } | ||
| 493 | |||
| 494 | if (memblock_reserve(paddr, size) < 0) { | ||
| 495 | pr_err("FB: failed to reserve VRAM - no memory\n"); | ||
| 496 | return; | ||
| 497 | } | ||
| 498 | } else { | ||
| 499 | paddr = memblock_alloc(size, SZ_2M); | ||
| 500 | } | ||
| 501 | |||
| 502 | memblock_free(paddr, size); | ||
| 503 | memblock_remove(paddr, size); | ||
| 504 | |||
| 505 | omap_vram_add_region(paddr, size); | ||
| 506 | |||
| 507 | pr_info("Reserving %u bytes SDRAM for VRAM\n", size); | ||
| 508 | } | ||
| 509 | |||
| 510 | void __init omap_vram_set_sdram_vram(u32 size, u32 start) | ||
| 511 | { | ||
| 512 | omap_vram_sdram_start = start; | ||
| 513 | omap_vram_sdram_size = size; | ||
| 514 | } | ||
diff --git a/drivers/video/s3c-fb.c b/drivers/video/s3c-fb.c index 2ed7b633bbd9..1a00ad241edd 100644 --- a/drivers/video/s3c-fb.c +++ b/drivers/video/s3c-fb.c | |||
| @@ -189,7 +189,7 @@ struct s3c_fb_vsync { | |||
| 189 | 189 | ||
| 190 | /** | 190 | /** |
| 191 | * struct s3c_fb - overall hardware state of the hardware | 191 | * struct s3c_fb - overall hardware state of the hardware |
| 192 | * @slock: The spinlock protection for this data sturucture. | 192 | * @slock: The spinlock protection for this data structure. |
| 193 | * @dev: The device that we bound to, for printing, etc. | 193 | * @dev: The device that we bound to, for printing, etc. |
| 194 | * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. | 194 | * @bus_clk: The clk (hclk) feeding our interface and possibly pixclk. |
| 195 | * @lcd_clk: The clk (sclk) feeding pixclk. | 195 | * @lcd_clk: The clk (sclk) feeding pixclk. |
| @@ -268,10 +268,10 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, | |||
| 268 | case 8: | 268 | case 8: |
| 269 | if (sfb->variant.palette[win->index] != 0) { | 269 | if (sfb->variant.palette[win->index] != 0) { |
| 270 | /* non palletised, A:1,R:2,G:3,B:2 mode */ | 270 | /* non palletised, A:1,R:2,G:3,B:2 mode */ |
| 271 | var->red.offset = 4; | 271 | var->red.offset = 5; |
| 272 | var->green.offset = 2; | 272 | var->green.offset = 2; |
| 273 | var->blue.offset = 0; | 273 | var->blue.offset = 0; |
| 274 | var->red.length = 5; | 274 | var->red.length = 2; |
| 275 | var->green.length = 3; | 275 | var->green.length = 3; |
| 276 | var->blue.length = 2; | 276 | var->blue.length = 2; |
| 277 | var->transp.offset = 7; | 277 | var->transp.offset = 7; |
| @@ -288,6 +288,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, | |||
| 288 | /* 666 with one bit alpha/transparency */ | 288 | /* 666 with one bit alpha/transparency */ |
| 289 | var->transp.offset = 18; | 289 | var->transp.offset = 18; |
| 290 | var->transp.length = 1; | 290 | var->transp.length = 1; |
| 291 | /* drop through */ | ||
| 291 | case 18: | 292 | case 18: |
| 292 | var->bits_per_pixel = 32; | 293 | var->bits_per_pixel = 32; |
| 293 | 294 | ||
| @@ -329,6 +330,7 @@ static int s3c_fb_check_var(struct fb_var_screeninfo *var, | |||
| 329 | 330 | ||
| 330 | default: | 331 | default: |
| 331 | dev_err(sfb->dev, "invalid bpp\n"); | 332 | dev_err(sfb->dev, "invalid bpp\n"); |
| 333 | return -EINVAL; | ||
| 332 | } | 334 | } |
| 333 | 335 | ||
| 334 | dev_dbg(sfb->dev, "%s: verified parameters\n", __func__); | 336 | dev_dbg(sfb->dev, "%s: verified parameters\n", __func__); |
| @@ -1544,8 +1546,7 @@ static int __devexit s3c_fb_remove(struct platform_device *pdev) | |||
| 1544 | #ifdef CONFIG_PM_SLEEP | 1546 | #ifdef CONFIG_PM_SLEEP |
| 1545 | static int s3c_fb_suspend(struct device *dev) | 1547 | static int s3c_fb_suspend(struct device *dev) |
| 1546 | { | 1548 | { |
| 1547 | struct platform_device *pdev = to_platform_device(dev); | 1549 | struct s3c_fb *sfb = dev_get_drvdata(dev); |
| 1548 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | ||
| 1549 | struct s3c_fb_win *win; | 1550 | struct s3c_fb_win *win; |
| 1550 | int win_no; | 1551 | int win_no; |
| 1551 | 1552 | ||
| @@ -1572,8 +1573,7 @@ static int s3c_fb_suspend(struct device *dev) | |||
| 1572 | 1573 | ||
| 1573 | static int s3c_fb_resume(struct device *dev) | 1574 | static int s3c_fb_resume(struct device *dev) |
| 1574 | { | 1575 | { |
| 1575 | struct platform_device *pdev = to_platform_device(dev); | 1576 | struct s3c_fb *sfb = dev_get_drvdata(dev); |
| 1576 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | ||
| 1577 | struct s3c_fb_platdata *pd = sfb->pdata; | 1577 | struct s3c_fb_platdata *pd = sfb->pdata; |
| 1578 | struct s3c_fb_win *win; | 1578 | struct s3c_fb_win *win; |
| 1579 | int win_no; | 1579 | int win_no; |
| @@ -1623,7 +1623,7 @@ static int s3c_fb_resume(struct device *dev) | |||
| 1623 | if (!win) | 1623 | if (!win) |
| 1624 | continue; | 1624 | continue; |
| 1625 | 1625 | ||
| 1626 | dev_dbg(&pdev->dev, "resuming window %d\n", win_no); | 1626 | dev_dbg(dev, "resuming window %d\n", win_no); |
| 1627 | s3c_fb_set_par(win->fbinfo); | 1627 | s3c_fb_set_par(win->fbinfo); |
| 1628 | } | 1628 | } |
| 1629 | 1629 | ||
| @@ -1636,8 +1636,7 @@ static int s3c_fb_resume(struct device *dev) | |||
| 1636 | #ifdef CONFIG_PM_RUNTIME | 1636 | #ifdef CONFIG_PM_RUNTIME |
| 1637 | static int s3c_fb_runtime_suspend(struct device *dev) | 1637 | static int s3c_fb_runtime_suspend(struct device *dev) |
| 1638 | { | 1638 | { |
| 1639 | struct platform_device *pdev = to_platform_device(dev); | 1639 | struct s3c_fb *sfb = dev_get_drvdata(dev); |
| 1640 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | ||
| 1641 | 1640 | ||
| 1642 | if (!sfb->variant.has_clksel) | 1641 | if (!sfb->variant.has_clksel) |
| 1643 | clk_disable_unprepare(sfb->lcd_clk); | 1642 | clk_disable_unprepare(sfb->lcd_clk); |
| @@ -1649,8 +1648,7 @@ static int s3c_fb_runtime_suspend(struct device *dev) | |||
| 1649 | 1648 | ||
| 1650 | static int s3c_fb_runtime_resume(struct device *dev) | 1649 | static int s3c_fb_runtime_resume(struct device *dev) |
| 1651 | { | 1650 | { |
| 1652 | struct platform_device *pdev = to_platform_device(dev); | 1651 | struct s3c_fb *sfb = dev_get_drvdata(dev); |
| 1653 | struct s3c_fb *sfb = platform_get_drvdata(pdev); | ||
| 1654 | struct s3c_fb_platdata *pd = sfb->pdata; | 1652 | struct s3c_fb_platdata *pd = sfb->pdata; |
| 1655 | 1653 | ||
| 1656 | clk_prepare_enable(sfb->bus_clk); | 1654 | clk_prepare_enable(sfb->bus_clk); |
| @@ -1910,7 +1908,7 @@ static struct s3c_fb_driverdata s3c_fb_data_exynos4 = { | |||
| 1910 | static struct s3c_fb_driverdata s3c_fb_data_exynos5 = { | 1908 | static struct s3c_fb_driverdata s3c_fb_data_exynos5 = { |
| 1911 | .variant = { | 1909 | .variant = { |
| 1912 | .nr_windows = 5, | 1910 | .nr_windows = 5, |
| 1913 | .vidtcon = VIDTCON0, | 1911 | .vidtcon = FIMD_V8_VIDTCON0, |
| 1914 | .wincon = WINCON(0), | 1912 | .wincon = WINCON(0), |
| 1915 | .winmap = WINxMAP(0), | 1913 | .winmap = WINxMAP(0), |
| 1916 | .keycon = WKEYCON, | 1914 | .keycon = WKEYCON, |
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 3951fdae5f68..f4962292792c 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c | |||
| @@ -127,13 +127,12 @@ static void sh_mipi_shutdown(struct platform_device *pdev) | |||
| 127 | sh_mipi_dsi_enable(mipi, false); | 127 | sh_mipi_dsi_enable(mipi, false); |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | static int sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata) | 130 | static int sh_mipi_setup(struct sh_mipi *mipi, const struct fb_videomode *mode) |
| 131 | { | 131 | { |
| 132 | void __iomem *base = mipi->base; | 132 | void __iomem *base = mipi->base; |
| 133 | struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; | 133 | struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data; |
| 134 | u32 pctype, datatype, pixfmt, linelength, vmctr2; | 134 | u32 pctype, datatype, pixfmt, linelength, vmctr2; |
| 135 | u32 tmp, top, bottom, delay, div; | 135 | u32 tmp, top, bottom, delay, div; |
| 136 | bool yuv; | ||
| 137 | int bpp; | 136 | int bpp; |
| 138 | 137 | ||
| 139 | /* | 138 | /* |
| @@ -146,95 +145,79 @@ static int sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata) | |||
| 146 | pctype = 0; | 145 | pctype = 0; |
| 147 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 146 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
| 148 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 147 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
| 149 | linelength = ch->lcd_modes[0].xres * 3; | 148 | linelength = mode->xres * 3; |
| 150 | yuv = false; | ||
| 151 | break; | 149 | break; |
| 152 | case MIPI_RGB565: | 150 | case MIPI_RGB565: |
| 153 | pctype = 1; | 151 | pctype = 1; |
| 154 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 152 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
| 155 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 153 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
| 156 | linelength = ch->lcd_modes[0].xres * 2; | 154 | linelength = mode->xres * 2; |
| 157 | yuv = false; | ||
| 158 | break; | 155 | break; |
| 159 | case MIPI_RGB666_LP: | 156 | case MIPI_RGB666_LP: |
| 160 | pctype = 2; | 157 | pctype = 2; |
| 161 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 158 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
| 162 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 159 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
| 163 | linelength = ch->lcd_modes[0].xres * 3; | 160 | linelength = mode->xres * 3; |
| 164 | yuv = false; | ||
| 165 | break; | 161 | break; |
| 166 | case MIPI_RGB666: | 162 | case MIPI_RGB666: |
| 167 | pctype = 3; | 163 | pctype = 3; |
| 168 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 164 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
| 169 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | 165 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; |
| 170 | linelength = (ch->lcd_modes[0].xres * 18 + 7) / 8; | 166 | linelength = (mode->xres * 18 + 7) / 8; |
| 171 | yuv = false; | ||
| 172 | break; | 167 | break; |
| 173 | case MIPI_BGR888: | 168 | case MIPI_BGR888: |
| 174 | pctype = 8; | 169 | pctype = 8; |
| 175 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 170 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
| 176 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 171 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
| 177 | linelength = ch->lcd_modes[0].xres * 3; | 172 | linelength = mode->xres * 3; |
| 178 | yuv = false; | ||
| 179 | break; | 173 | break; |
| 180 | case MIPI_BGR565: | 174 | case MIPI_BGR565: |
| 181 | pctype = 9; | 175 | pctype = 9; |
| 182 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 176 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
| 183 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 177 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
| 184 | linelength = ch->lcd_modes[0].xres * 2; | 178 | linelength = mode->xres * 2; |
| 185 | yuv = false; | ||
| 186 | break; | 179 | break; |
| 187 | case MIPI_BGR666_LP: | 180 | case MIPI_BGR666_LP: |
| 188 | pctype = 0xa; | 181 | pctype = 0xa; |
| 189 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 182 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
| 190 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 183 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
| 191 | linelength = ch->lcd_modes[0].xres * 3; | 184 | linelength = mode->xres * 3; |
| 192 | yuv = false; | ||
| 193 | break; | 185 | break; |
| 194 | case MIPI_BGR666: | 186 | case MIPI_BGR666: |
| 195 | pctype = 0xb; | 187 | pctype = 0xb; |
| 196 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 188 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
| 197 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | 189 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; |
| 198 | linelength = (ch->lcd_modes[0].xres * 18 + 7) / 8; | 190 | linelength = (mode->xres * 18 + 7) / 8; |
| 199 | yuv = false; | ||
| 200 | break; | 191 | break; |
| 201 | case MIPI_YUYV: | 192 | case MIPI_YUYV: |
| 202 | pctype = 4; | 193 | pctype = 4; |
| 203 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | 194 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; |
| 204 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 195 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
| 205 | linelength = ch->lcd_modes[0].xres * 2; | 196 | linelength = mode->xres * 2; |
| 206 | yuv = true; | ||
| 207 | break; | 197 | break; |
| 208 | case MIPI_UYVY: | 198 | case MIPI_UYVY: |
| 209 | pctype = 5; | 199 | pctype = 5; |
| 210 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | 200 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; |
| 211 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 201 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
| 212 | linelength = ch->lcd_modes[0].xres * 2; | 202 | linelength = mode->xres * 2; |
| 213 | yuv = true; | ||
| 214 | break; | 203 | break; |
| 215 | case MIPI_YUV420_L: | 204 | case MIPI_YUV420_L: |
| 216 | pctype = 6; | 205 | pctype = 6; |
| 217 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | 206 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; |
| 218 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | 207 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; |
| 219 | linelength = (ch->lcd_modes[0].xres * 12 + 7) / 8; | 208 | linelength = (mode->xres * 12 + 7) / 8; |
| 220 | yuv = true; | ||
| 221 | break; | 209 | break; |
| 222 | case MIPI_YUV420: | 210 | case MIPI_YUV420: |
| 223 | pctype = 7; | 211 | pctype = 7; |
| 224 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | 212 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; |
| 225 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | 213 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; |
| 226 | /* Length of U/V line */ | 214 | /* Length of U/V line */ |
| 227 | linelength = (ch->lcd_modes[0].xres + 1) / 2; | 215 | linelength = (mode->xres + 1) / 2; |
| 228 | yuv = true; | ||
| 229 | break; | 216 | break; |
| 230 | default: | 217 | default: |
| 231 | return -EINVAL; | 218 | return -EINVAL; |
| 232 | } | 219 | } |
| 233 | 220 | ||
| 234 | if ((yuv && ch->interface_type != YUV422) || | ||
| 235 | (!yuv && ch->interface_type != RGB24)) | ||
| 236 | return -EINVAL; | ||
| 237 | |||
| 238 | if (!pdata->lane) | 221 | if (!pdata->lane) |
| 239 | return -EINVAL; | 222 | return -EINVAL; |
| 240 | 223 | ||
| @@ -293,7 +276,7 @@ static int sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata) | |||
| 293 | */ | 276 | */ |
| 294 | iowrite32(0x00000006, mipi->linkbase + DTCTR); | 277 | iowrite32(0x00000006, mipi->linkbase + DTCTR); |
| 295 | /* VSYNC width = 2 (<< 17) */ | 278 | /* VSYNC width = 2 (<< 17) */ |
| 296 | iowrite32((ch->lcd_modes[0].vsync_len << pdata->vsynw_offset) | | 279 | iowrite32((mode->vsync_len << pdata->vsynw_offset) | |
| 297 | (pdata->clksrc << 16) | (pctype << 12) | datatype, | 280 | (pdata->clksrc << 16) | (pctype << 12) | datatype, |
| 298 | mipi->linkbase + VMCTR1); | 281 | mipi->linkbase + VMCTR1); |
| 299 | 282 | ||
| @@ -327,7 +310,7 @@ static int sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata) | |||
| 327 | top = linelength << 16; /* RGBLEN */ | 310 | top = linelength << 16; /* RGBLEN */ |
| 328 | bottom = 0x00000001; | 311 | bottom = 0x00000001; |
| 329 | if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */ | 312 | if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */ |
| 330 | bottom = (pdata->lane * ch->lcd_modes[0].hsync_len) - 10; | 313 | bottom = (pdata->lane * mode->hsync_len) - 10; |
| 331 | iowrite32(top | bottom , mipi->linkbase + VMLEN1); | 314 | iowrite32(top | bottom , mipi->linkbase + VMLEN1); |
| 332 | 315 | ||
| 333 | /* | 316 | /* |
| @@ -347,18 +330,18 @@ static int sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata) | |||
| 347 | div = 2; | 330 | div = 2; |
| 348 | 331 | ||
| 349 | if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */ | 332 | if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */ |
| 350 | top = ch->lcd_modes[0].hsync_len + ch->lcd_modes[0].left_margin; | 333 | top = mode->hsync_len + mode->left_margin; |
| 351 | top = ((pdata->lane * top / div) - 10) << 16; | 334 | top = ((pdata->lane * top / div) - 10) << 16; |
| 352 | } | 335 | } |
| 353 | if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */ | 336 | if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */ |
| 354 | bottom = ch->lcd_modes[0].right_margin; | 337 | bottom = mode->right_margin; |
| 355 | bottom = (pdata->lane * bottom / div) - 12; | 338 | bottom = (pdata->lane * bottom / div) - 12; |
| 356 | } | 339 | } |
| 357 | 340 | ||
| 358 | bpp = linelength / ch->lcd_modes[0].xres; /* byte / pixel */ | 341 | bpp = linelength / mode->xres; /* byte / pixel */ |
| 359 | if ((pdata->lane / div) > bpp) { | 342 | if ((pdata->lane / div) > bpp) { |
| 360 | tmp = ch->lcd_modes[0].xres / bpp; /* output cycle */ | 343 | tmp = mode->xres / bpp; /* output cycle */ |
| 361 | tmp = ch->lcd_modes[0].xres - tmp; /* (input - output) cycle */ | 344 | tmp = mode->xres - tmp; /* (input - output) cycle */ |
| 362 | delay = (pdata->lane * tmp); | 345 | delay = (pdata->lane * tmp); |
| 363 | } | 346 | } |
| 364 | 347 | ||
| @@ -369,7 +352,7 @@ static int sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata) | |||
| 369 | /* setup LCD panel */ | 352 | /* setup LCD panel */ |
| 370 | 353 | ||
| 371 | /* cf. drivers/video/omap/lcd_mipid.c */ | 354 | /* cf. drivers/video/omap/lcd_mipid.c */ |
| 372 | sh_mipi_dcs(ch->chan, MIPI_DCS_EXIT_SLEEP_MODE); | 355 | sh_mipi_dcs(pdata->channel, MIPI_DCS_EXIT_SLEEP_MODE); |
| 373 | msleep(120); | 356 | msleep(120); |
| 374 | /* | 357 | /* |
| 375 | * [7] - Page Address Mode | 358 | * [7] - Page Address Mode |
| @@ -381,11 +364,11 @@ static int sh_mipi_setup(struct sh_mipi *mipi, struct sh_mipi_dsi_info *pdata) | |||
| 381 | * [1] - Flip Horizontal | 364 | * [1] - Flip Horizontal |
| 382 | * [0] - Flip Vertical | 365 | * [0] - Flip Vertical |
| 383 | */ | 366 | */ |
| 384 | sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_ADDRESS_MODE, 0x00); | 367 | sh_mipi_dcs_param(pdata->channel, MIPI_DCS_SET_ADDRESS_MODE, 0x00); |
| 385 | /* cf. set_data_lines() */ | 368 | /* cf. set_data_lines() */ |
| 386 | sh_mipi_dcs_param(ch->chan, MIPI_DCS_SET_PIXEL_FORMAT, | 369 | sh_mipi_dcs_param(pdata->channel, MIPI_DCS_SET_PIXEL_FORMAT, |
| 387 | pixfmt << 4); | 370 | pixfmt << 4); |
| 388 | sh_mipi_dcs(ch->chan, MIPI_DCS_SET_DISPLAY_ON); | 371 | sh_mipi_dcs(pdata->channel, MIPI_DCS_SET_DISPLAY_ON); |
| 389 | 372 | ||
| 390 | /* Enable timeout counters */ | 373 | /* Enable timeout counters */ |
| 391 | iowrite32(0x00000f00, base + DSICTRL); | 374 | iowrite32(0x00000f00, base + DSICTRL); |
| @@ -405,7 +388,7 @@ static int mipi_display_on(struct sh_mobile_lcdc_entity *entity) | |||
| 405 | if (ret < 0) | 388 | if (ret < 0) |
| 406 | goto mipi_display_on_fail1; | 389 | goto mipi_display_on_fail1; |
| 407 | 390 | ||
| 408 | ret = sh_mipi_setup(mipi, pdata); | 391 | ret = sh_mipi_setup(mipi, &entity->def_mode); |
| 409 | if (ret < 0) | 392 | if (ret < 0) |
| 410 | goto mipi_display_on_fail2; | 393 | goto mipi_display_on_fail2; |
| 411 | 394 | ||
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 699487c287b2..e78fe4bc1524 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
| @@ -438,7 +438,7 @@ static unsigned long lcdc_sys_read_data(void *handle) | |||
| 438 | return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK; | 438 | return lcdc_read(ch->lcdc, _LDDRDR) & LDDRDR_DRD_MASK; |
| 439 | } | 439 | } |
| 440 | 440 | ||
| 441 | struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { | 441 | static struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { |
| 442 | lcdc_sys_write_index, | 442 | lcdc_sys_write_index, |
| 443 | lcdc_sys_write_data, | 443 | lcdc_sys_write_data, |
| 444 | lcdc_sys_read_data, | 444 | lcdc_sys_read_data, |
| @@ -586,8 +586,8 @@ static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch, | |||
| 586 | * Just turn on, if we run a resume here, the | 586 | * Just turn on, if we run a resume here, the |
| 587 | * logo disappears. | 587 | * logo disappears. |
| 588 | */ | 588 | */ |
| 589 | info->var.width = monspec->max_x * 10; | 589 | info->var.width = ch->display.width; |
| 590 | info->var.height = monspec->max_y * 10; | 590 | info->var.height = ch->display.height; |
| 591 | sh_mobile_lcdc_display_on(ch); | 591 | sh_mobile_lcdc_display_on(ch); |
| 592 | } else { | 592 | } else { |
| 593 | /* New monitor or have to wake up */ | 593 | /* New monitor or have to wake up */ |
| @@ -1614,6 +1614,15 @@ static int sh_mobile_lcdc_overlay_blank(int blank, struct fb_info *info) | |||
| 1614 | return 1; | 1614 | return 1; |
| 1615 | } | 1615 | } |
| 1616 | 1616 | ||
| 1617 | static int | ||
| 1618 | sh_mobile_lcdc_overlay_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
| 1619 | { | ||
| 1620 | struct sh_mobile_lcdc_overlay *ovl = info->par; | ||
| 1621 | |||
| 1622 | return dma_mmap_coherent(ovl->channel->lcdc->dev, vma, ovl->fb_mem, | ||
| 1623 | ovl->dma_handle, ovl->fb_size); | ||
| 1624 | } | ||
| 1625 | |||
| 1617 | static struct fb_ops sh_mobile_lcdc_overlay_ops = { | 1626 | static struct fb_ops sh_mobile_lcdc_overlay_ops = { |
| 1618 | .owner = THIS_MODULE, | 1627 | .owner = THIS_MODULE, |
| 1619 | .fb_read = fb_sys_read, | 1628 | .fb_read = fb_sys_read, |
| @@ -1626,6 +1635,7 @@ static struct fb_ops sh_mobile_lcdc_overlay_ops = { | |||
| 1626 | .fb_ioctl = sh_mobile_lcdc_overlay_ioctl, | 1635 | .fb_ioctl = sh_mobile_lcdc_overlay_ioctl, |
| 1627 | .fb_check_var = sh_mobile_lcdc_overlay_check_var, | 1636 | .fb_check_var = sh_mobile_lcdc_overlay_check_var, |
| 1628 | .fb_set_par = sh_mobile_lcdc_overlay_set_par, | 1637 | .fb_set_par = sh_mobile_lcdc_overlay_set_par, |
| 1638 | .fb_mmap = sh_mobile_lcdc_overlay_mmap, | ||
| 1629 | }; | 1639 | }; |
| 1630 | 1640 | ||
| 1631 | static void | 1641 | static void |
| @@ -2093,6 +2103,15 @@ static int sh_mobile_lcdc_blank(int blank, struct fb_info *info) | |||
| 2093 | return 0; | 2103 | return 0; |
| 2094 | } | 2104 | } |
| 2095 | 2105 | ||
| 2106 | static int | ||
| 2107 | sh_mobile_lcdc_mmap(struct fb_info *info, struct vm_area_struct *vma) | ||
| 2108 | { | ||
| 2109 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
| 2110 | |||
| 2111 | return dma_mmap_coherent(ch->lcdc->dev, vma, ch->fb_mem, | ||
| 2112 | ch->dma_handle, ch->fb_size); | ||
| 2113 | } | ||
| 2114 | |||
| 2096 | static struct fb_ops sh_mobile_lcdc_ops = { | 2115 | static struct fb_ops sh_mobile_lcdc_ops = { |
| 2097 | .owner = THIS_MODULE, | 2116 | .owner = THIS_MODULE, |
| 2098 | .fb_setcolreg = sh_mobile_lcdc_setcolreg, | 2117 | .fb_setcolreg = sh_mobile_lcdc_setcolreg, |
| @@ -2108,6 +2127,7 @@ static struct fb_ops sh_mobile_lcdc_ops = { | |||
| 2108 | .fb_release = sh_mobile_lcdc_release, | 2127 | .fb_release = sh_mobile_lcdc_release, |
| 2109 | .fb_check_var = sh_mobile_lcdc_check_var, | 2128 | .fb_check_var = sh_mobile_lcdc_check_var, |
| 2110 | .fb_set_par = sh_mobile_lcdc_set_par, | 2129 | .fb_set_par = sh_mobile_lcdc_set_par, |
| 2130 | .fb_mmap = sh_mobile_lcdc_mmap, | ||
| 2111 | }; | 2131 | }; |
| 2112 | 2132 | ||
| 2113 | static void | 2133 | static void |
| @@ -2167,7 +2187,7 @@ sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch) | |||
| 2167 | 2187 | ||
| 2168 | static int __devinit | 2188 | static int __devinit |
| 2169 | sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, | 2189 | sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, |
| 2170 | const struct fb_videomode *mode, | 2190 | const struct fb_videomode *modes, |
| 2171 | unsigned int num_modes) | 2191 | unsigned int num_modes) |
| 2172 | { | 2192 | { |
| 2173 | struct sh_mobile_lcdc_priv *priv = ch->lcdc; | 2193 | struct sh_mobile_lcdc_priv *priv = ch->lcdc; |
| @@ -2193,7 +2213,7 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, | |||
| 2193 | info->pseudo_palette = &ch->pseudo_palette; | 2213 | info->pseudo_palette = &ch->pseudo_palette; |
| 2194 | info->par = ch; | 2214 | info->par = ch; |
| 2195 | 2215 | ||
| 2196 | fb_videomode_to_modelist(mode, num_modes, &info->modelist); | 2216 | fb_videomode_to_modelist(modes, num_modes, &info->modelist); |
| 2197 | 2217 | ||
| 2198 | ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); | 2218 | ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); |
| 2199 | if (ret < 0) { | 2219 | if (ret < 0) { |
| @@ -2227,9 +2247,9 @@ sh_mobile_lcdc_channel_fb_init(struct sh_mobile_lcdc_chan *ch, | |||
| 2227 | * default. | 2247 | * default. |
| 2228 | */ | 2248 | */ |
| 2229 | var = &info->var; | 2249 | var = &info->var; |
| 2230 | fb_videomode_to_var(var, mode); | 2250 | fb_videomode_to_var(var, modes); |
| 2231 | var->width = ch->cfg->panel_cfg.width; | 2251 | var->width = ch->display.width; |
| 2232 | var->height = ch->cfg->panel_cfg.height; | 2252 | var->height = ch->display.height; |
| 2233 | var->xres_virtual = ch->xres_virtual; | 2253 | var->xres_virtual = ch->xres_virtual; |
| 2234 | var->yres_virtual = ch->yres_virtual; | 2254 | var->yres_virtual = ch->yres_virtual; |
| 2235 | var->activate = FB_ACTIVATE_NOW; | 2255 | var->activate = FB_ACTIVATE_NOW; |
| @@ -2262,6 +2282,7 @@ static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev) | |||
| 2262 | bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) | 2282 | bdev->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) |
| 2263 | brightness = 0; | 2283 | brightness = 0; |
| 2264 | 2284 | ||
| 2285 | ch->bl_brightness = brightness; | ||
| 2265 | return ch->cfg->bl_info.set_brightness(brightness); | 2286 | return ch->cfg->bl_info.set_brightness(brightness); |
| 2266 | } | 2287 | } |
| 2267 | 2288 | ||
| @@ -2269,7 +2290,7 @@ static int sh_mobile_lcdc_get_brightness(struct backlight_device *bdev) | |||
| 2269 | { | 2290 | { |
| 2270 | struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); | 2291 | struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev); |
| 2271 | 2292 | ||
| 2272 | return ch->cfg->bl_info.get_brightness(); | 2293 | return ch->bl_brightness; |
| 2273 | } | 2294 | } |
| 2274 | 2295 | ||
| 2275 | static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev, | 2296 | static int sh_mobile_lcdc_check_fb(struct backlight_device *bdev, |
| @@ -2516,10 +2537,10 @@ static int __devinit sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan * | |||
| 2516 | } | 2537 | } |
| 2517 | 2538 | ||
| 2518 | static int __devinit | 2539 | static int __devinit |
| 2519 | sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_priv *priv, | 2540 | sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_overlay *ovl) |
| 2520 | struct sh_mobile_lcdc_overlay *ovl) | ||
| 2521 | { | 2541 | { |
| 2522 | const struct sh_mobile_lcdc_format_info *format; | 2542 | const struct sh_mobile_lcdc_format_info *format; |
| 2543 | struct device *dev = ovl->channel->lcdc->dev; | ||
| 2523 | int ret; | 2544 | int ret; |
| 2524 | 2545 | ||
| 2525 | if (ovl->cfg->fourcc == 0) | 2546 | if (ovl->cfg->fourcc == 0) |
| @@ -2528,7 +2549,7 @@ sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_priv *priv, | |||
| 2528 | /* Validate the format. */ | 2549 | /* Validate the format. */ |
| 2529 | format = sh_mobile_format_info(ovl->cfg->fourcc); | 2550 | format = sh_mobile_format_info(ovl->cfg->fourcc); |
| 2530 | if (format == NULL) { | 2551 | if (format == NULL) { |
| 2531 | dev_err(priv->dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc); | 2552 | dev_err(dev, "Invalid FOURCC %08x\n", ovl->cfg->fourcc); |
| 2532 | return -EINVAL; | 2553 | return -EINVAL; |
| 2533 | } | 2554 | } |
| 2534 | 2555 | ||
| @@ -2556,10 +2577,10 @@ sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_priv *priv, | |||
| 2556 | /* Allocate frame buffer memory. */ | 2577 | /* Allocate frame buffer memory. */ |
| 2557 | ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres | 2578 | ovl->fb_size = ovl->cfg->max_xres * ovl->cfg->max_yres |
| 2558 | * format->bpp / 8 * 2; | 2579 | * format->bpp / 8 * 2; |
| 2559 | ovl->fb_mem = dma_alloc_coherent(priv->dev, ovl->fb_size, | 2580 | ovl->fb_mem = dma_alloc_coherent(dev, ovl->fb_size, &ovl->dma_handle, |
| 2560 | &ovl->dma_handle, GFP_KERNEL); | 2581 | GFP_KERNEL); |
| 2561 | if (!ovl->fb_mem) { | 2582 | if (!ovl->fb_mem) { |
| 2562 | dev_err(priv->dev, "unable to allocate buffer\n"); | 2583 | dev_err(dev, "unable to allocate buffer\n"); |
| 2563 | return -ENOMEM; | 2584 | return -ENOMEM; |
| 2564 | } | 2585 | } |
| 2565 | 2586 | ||
| @@ -2571,11 +2592,11 @@ sh_mobile_lcdc_overlay_init(struct sh_mobile_lcdc_priv *priv, | |||
| 2571 | } | 2592 | } |
| 2572 | 2593 | ||
| 2573 | static int __devinit | 2594 | static int __devinit |
| 2574 | sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | 2595 | sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch) |
| 2575 | struct sh_mobile_lcdc_chan *ch) | ||
| 2576 | { | 2596 | { |
| 2577 | const struct sh_mobile_lcdc_format_info *format; | 2597 | const struct sh_mobile_lcdc_format_info *format; |
| 2578 | const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg; | 2598 | const struct sh_mobile_lcdc_chan_cfg *cfg = ch->cfg; |
| 2599 | struct device *dev = ch->lcdc->dev; | ||
| 2579 | const struct fb_videomode *max_mode; | 2600 | const struct fb_videomode *max_mode; |
| 2580 | const struct fb_videomode *mode; | 2601 | const struct fb_videomode *mode; |
| 2581 | unsigned int num_modes; | 2602 | unsigned int num_modes; |
| @@ -2588,7 +2609,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | |||
| 2588 | /* Validate the format. */ | 2609 | /* Validate the format. */ |
| 2589 | format = sh_mobile_format_info(cfg->fourcc); | 2610 | format = sh_mobile_format_info(cfg->fourcc); |
| 2590 | if (format == NULL) { | 2611 | if (format == NULL) { |
| 2591 | dev_err(priv->dev, "Invalid FOURCC %08x.\n", cfg->fourcc); | 2612 | dev_err(dev, "Invalid FOURCC %08x.\n", cfg->fourcc); |
| 2592 | return -EINVAL; | 2613 | return -EINVAL; |
| 2593 | } | 2614 | } |
| 2594 | 2615 | ||
| @@ -2604,7 +2625,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | |||
| 2604 | /* NV12/NV21 buffers must have even number of lines */ | 2625 | /* NV12/NV21 buffers must have even number of lines */ |
| 2605 | if ((cfg->fourcc == V4L2_PIX_FMT_NV12 || | 2626 | if ((cfg->fourcc == V4L2_PIX_FMT_NV12 || |
| 2606 | cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) { | 2627 | cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) { |
| 2607 | dev_err(priv->dev, "yres must be multiple of 2 for " | 2628 | dev_err(dev, "yres must be multiple of 2 for " |
| 2608 | "YCbCr420 mode.\n"); | 2629 | "YCbCr420 mode.\n"); |
| 2609 | return -EINVAL; | 2630 | return -EINVAL; |
| 2610 | } | 2631 | } |
| @@ -2618,7 +2639,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | |||
| 2618 | if (!max_size) | 2639 | if (!max_size) |
| 2619 | max_size = MAX_XRES * MAX_YRES; | 2640 | max_size = MAX_XRES * MAX_YRES; |
| 2620 | else | 2641 | else |
| 2621 | dev_dbg(priv->dev, "Found largest videomode %ux%u\n", | 2642 | dev_dbg(dev, "Found largest videomode %ux%u\n", |
| 2622 | max_mode->xres, max_mode->yres); | 2643 | max_mode->xres, max_mode->yres); |
| 2623 | 2644 | ||
| 2624 | if (cfg->lcd_modes == NULL) { | 2645 | if (cfg->lcd_modes == NULL) { |
| @@ -2652,10 +2673,10 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | |||
| 2652 | 2673 | ||
| 2653 | /* Allocate frame buffer memory. */ | 2674 | /* Allocate frame buffer memory. */ |
| 2654 | ch->fb_size = max_size * format->bpp / 8 * 2; | 2675 | ch->fb_size = max_size * format->bpp / 8 * 2; |
| 2655 | ch->fb_mem = dma_alloc_coherent(priv->dev, ch->fb_size, &ch->dma_handle, | 2676 | ch->fb_mem = dma_alloc_coherent(dev, ch->fb_size, &ch->dma_handle, |
| 2656 | GFP_KERNEL); | 2677 | GFP_KERNEL); |
| 2657 | if (ch->fb_mem == NULL) { | 2678 | if (ch->fb_mem == NULL) { |
| 2658 | dev_err(priv->dev, "unable to allocate buffer\n"); | 2679 | dev_err(dev, "unable to allocate buffer\n"); |
| 2659 | return -ENOMEM; | 2680 | return -ENOMEM; |
| 2660 | } | 2681 | } |
| 2661 | 2682 | ||
| @@ -2663,8 +2684,7 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_priv *priv, | |||
| 2663 | if (cfg->tx_dev) { | 2684 | if (cfg->tx_dev) { |
| 2664 | if (!cfg->tx_dev->dev.driver || | 2685 | if (!cfg->tx_dev->dev.driver || |
| 2665 | !try_module_get(cfg->tx_dev->dev.driver->owner)) { | 2686 | !try_module_get(cfg->tx_dev->dev.driver->owner)) { |
| 2666 | dev_warn(priv->dev, | 2687 | dev_warn(dev, "unable to get transmitter device\n"); |
| 2667 | "unable to get transmitter device\n"); | ||
| 2668 | return -EINVAL; | 2688 | return -EINVAL; |
| 2669 | } | 2689 | } |
| 2670 | ch->tx_dev = platform_get_drvdata(cfg->tx_dev); | 2690 | ch->tx_dev = platform_get_drvdata(cfg->tx_dev); |
| @@ -2772,9 +2792,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
| 2772 | pm_runtime_enable(&pdev->dev); | 2792 | pm_runtime_enable(&pdev->dev); |
| 2773 | 2793 | ||
| 2774 | for (i = 0; i < num_channels; i++) { | 2794 | for (i = 0; i < num_channels; i++) { |
| 2775 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; | 2795 | struct sh_mobile_lcdc_chan *ch = &priv->ch[i]; |
| 2776 | 2796 | ||
| 2777 | error = sh_mobile_lcdc_channel_init(priv, ch); | 2797 | error = sh_mobile_lcdc_channel_init(ch); |
| 2778 | if (error) | 2798 | if (error) |
| 2779 | goto err1; | 2799 | goto err1; |
| 2780 | } | 2800 | } |
| @@ -2785,7 +2805,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
| 2785 | ovl->cfg = &pdata->overlays[i]; | 2805 | ovl->cfg = &pdata->overlays[i]; |
| 2786 | ovl->channel = &priv->ch[0]; | 2806 | ovl->channel = &priv->ch[0]; |
| 2787 | 2807 | ||
| 2788 | error = sh_mobile_lcdc_overlay_init(priv, ovl); | 2808 | error = sh_mobile_lcdc_overlay_init(ovl); |
| 2789 | if (error) | 2809 | if (error) |
| 2790 | goto err1; | 2810 | goto err1; |
| 2791 | } | 2811 | } |
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h index 0f92f6544b94..f839adef1d90 100644 --- a/drivers/video/sh_mobile_lcdcfb.h +++ b/drivers/video/sh_mobile_lcdcfb.h | |||
| @@ -94,6 +94,7 @@ struct sh_mobile_lcdc_chan { | |||
| 94 | 94 | ||
| 95 | /* Backlight */ | 95 | /* Backlight */ |
| 96 | struct backlight_device *bl; | 96 | struct backlight_device *bl; |
| 97 | unsigned int bl_brightness; | ||
| 97 | 98 | ||
| 98 | /* FB */ | 99 | /* FB */ |
| 99 | struct fb_info *info; | 100 | struct fb_info *info; |
diff --git a/drivers/video/ssd1307fb.c b/drivers/video/ssd1307fb.c new file mode 100644 index 000000000000..6101f5c2f62f --- /dev/null +++ b/drivers/video/ssd1307fb.c | |||
| @@ -0,0 +1,396 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the Solomon SSD1307 OLED controler | ||
| 3 | * | ||
| 4 | * Copyright 2012 Free Electrons | ||
| 5 | * | ||
| 6 | * Licensed under the GPLv2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/i2c.h> | ||
| 12 | #include <linux/fb.h> | ||
| 13 | #include <linux/uaccess.h> | ||
| 14 | #include <linux/of_device.h> | ||
| 15 | #include <linux/of_gpio.h> | ||
| 16 | #include <linux/pwm.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | |||
| 19 | #define SSD1307FB_WIDTH 96 | ||
| 20 | #define SSD1307FB_HEIGHT 16 | ||
| 21 | |||
| 22 | #define SSD1307FB_DATA 0x40 | ||
| 23 | #define SSD1307FB_COMMAND 0x80 | ||
| 24 | |||
| 25 | #define SSD1307FB_CONTRAST 0x81 | ||
| 26 | #define SSD1307FB_SEG_REMAP_ON 0xa1 | ||
| 27 | #define SSD1307FB_DISPLAY_OFF 0xae | ||
| 28 | #define SSD1307FB_DISPLAY_ON 0xaf | ||
| 29 | #define SSD1307FB_START_PAGE_ADDRESS 0xb0 | ||
| 30 | |||
| 31 | struct ssd1307fb_par { | ||
| 32 | struct i2c_client *client; | ||
| 33 | struct fb_info *info; | ||
| 34 | struct pwm_device *pwm; | ||
| 35 | u32 pwm_period; | ||
| 36 | int reset; | ||
| 37 | }; | ||
| 38 | |||
| 39 | static struct fb_fix_screeninfo ssd1307fb_fix __devinitdata = { | ||
| 40 | .id = "Solomon SSD1307", | ||
| 41 | .type = FB_TYPE_PACKED_PIXELS, | ||
| 42 | .visual = FB_VISUAL_MONO10, | ||
| 43 | .xpanstep = 0, | ||
| 44 | .ypanstep = 0, | ||
| 45 | .ywrapstep = 0, | ||
| 46 | .line_length = SSD1307FB_WIDTH / 8, | ||
| 47 | .accel = FB_ACCEL_NONE, | ||
| 48 | }; | ||
| 49 | |||
| 50 | static struct fb_var_screeninfo ssd1307fb_var __devinitdata = { | ||
| 51 | .xres = SSD1307FB_WIDTH, | ||
| 52 | .yres = SSD1307FB_HEIGHT, | ||
| 53 | .xres_virtual = SSD1307FB_WIDTH, | ||
| 54 | .yres_virtual = SSD1307FB_HEIGHT, | ||
| 55 | .bits_per_pixel = 1, | ||
| 56 | }; | ||
| 57 | |||
| 58 | static int ssd1307fb_write_array(struct i2c_client *client, u8 type, u8 *cmd, u32 len) | ||
| 59 | { | ||
| 60 | u8 *buf; | ||
| 61 | int ret = 0; | ||
| 62 | |||
| 63 | buf = kzalloc(len + 1, GFP_KERNEL); | ||
| 64 | if (!buf) { | ||
| 65 | dev_err(&client->dev, "Couldn't allocate sending buffer.\n"); | ||
| 66 | return -ENOMEM; | ||
| 67 | } | ||
| 68 | |||
| 69 | buf[0] = type; | ||
| 70 | memcpy(buf + 1, cmd, len); | ||
| 71 | |||
| 72 | ret = i2c_master_send(client, buf, len + 1); | ||
| 73 | if (ret != len + 1) { | ||
| 74 | dev_err(&client->dev, "Couldn't send I2C command.\n"); | ||
| 75 | goto error; | ||
| 76 | } | ||
| 77 | |||
| 78 | error: | ||
| 79 | kfree(buf); | ||
| 80 | return ret; | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline int ssd1307fb_write_cmd_array(struct i2c_client *client, u8 *cmd, u32 len) | ||
| 84 | { | ||
| 85 | return ssd1307fb_write_array(client, SSD1307FB_COMMAND, cmd, len); | ||
| 86 | } | ||
| 87 | |||
| 88 | static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd) | ||
| 89 | { | ||
| 90 | return ssd1307fb_write_cmd_array(client, &cmd, 1); | ||
| 91 | } | ||
| 92 | |||
| 93 | static inline int ssd1307fb_write_data_array(struct i2c_client *client, u8 *cmd, u32 len) | ||
| 94 | { | ||
| 95 | return ssd1307fb_write_array(client, SSD1307FB_DATA, cmd, len); | ||
| 96 | } | ||
| 97 | |||
| 98 | static inline int ssd1307fb_write_data(struct i2c_client *client, u8 data) | ||
| 99 | { | ||
| 100 | return ssd1307fb_write_data_array(client, &data, 1); | ||
| 101 | } | ||
| 102 | |||
| 103 | static void ssd1307fb_update_display(struct ssd1307fb_par *par) | ||
| 104 | { | ||
| 105 | u8 *vmem = par->info->screen_base; | ||
| 106 | int i, j, k; | ||
| 107 | |||
| 108 | /* | ||
| 109 | * The screen is divided in pages, each having a height of 8 | ||
| 110 | * pixels, and the width of the screen. When sending a byte of | ||
| 111 | * data to the controller, it gives the 8 bits for the current | ||
| 112 | * column. I.e, the first byte are the 8 bits of the first | ||
| 113 | * column, then the 8 bits for the second column, etc. | ||
| 114 | * | ||
| 115 | * | ||
| 116 | * Representation of the screen, assuming it is 5 bits | ||
| 117 | * wide. Each letter-number combination is a bit that controls | ||
| 118 | * one pixel. | ||
| 119 | * | ||
| 120 | * A0 A1 A2 A3 A4 | ||
| 121 | * B0 B1 B2 B3 B4 | ||
| 122 | * C0 C1 C2 C3 C4 | ||
| 123 | * D0 D1 D2 D3 D4 | ||
| 124 | * E0 E1 E2 E3 E4 | ||
| 125 | * F0 F1 F2 F3 F4 | ||
| 126 | * G0 G1 G2 G3 G4 | ||
| 127 | * H0 H1 H2 H3 H4 | ||
| 128 | * | ||
| 129 | * If you want to update this screen, you need to send 5 bytes: | ||
| 130 | * (1) A0 B0 C0 D0 E0 F0 G0 H0 | ||
| 131 | * (2) A1 B1 C1 D1 E1 F1 G1 H1 | ||
| 132 | * (3) A2 B2 C2 D2 E2 F2 G2 H2 | ||
| 133 | * (4) A3 B3 C3 D3 E3 F3 G3 H3 | ||
| 134 | * (5) A4 B4 C4 D4 E4 F4 G4 H4 | ||
| 135 | */ | ||
| 136 | |||
| 137 | for (i = 0; i < (SSD1307FB_HEIGHT / 8); i++) { | ||
| 138 | ssd1307fb_write_cmd(par->client, SSD1307FB_START_PAGE_ADDRESS + (i + 1)); | ||
| 139 | ssd1307fb_write_cmd(par->client, 0x00); | ||
| 140 | ssd1307fb_write_cmd(par->client, 0x10); | ||
| 141 | |||
| 142 | for (j = 0; j < SSD1307FB_WIDTH; j++) { | ||
| 143 | u8 buf = 0; | ||
| 144 | for (k = 0; k < 8; k++) { | ||
| 145 | u32 page_length = SSD1307FB_WIDTH * i; | ||
| 146 | u32 index = page_length + (SSD1307FB_WIDTH * k + j) / 8; | ||
| 147 | u8 byte = *(vmem + index); | ||
| 148 | u8 bit = byte & (1 << (7 - (j % 8))); | ||
| 149 | bit = bit >> (7 - (j % 8)); | ||
| 150 | buf |= bit << k; | ||
| 151 | } | ||
| 152 | ssd1307fb_write_data(par->client, buf); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | |||
| 158 | static ssize_t ssd1307fb_write(struct fb_info *info, const char __user *buf, | ||
| 159 | size_t count, loff_t *ppos) | ||
| 160 | { | ||
| 161 | struct ssd1307fb_par *par = info->par; | ||
| 162 | unsigned long total_size; | ||
| 163 | unsigned long p = *ppos; | ||
| 164 | u8 __iomem *dst; | ||
| 165 | |||
| 166 | total_size = info->fix.smem_len; | ||
| 167 | |||
| 168 | if (p > total_size) | ||
| 169 | return -EINVAL; | ||
| 170 | |||
| 171 | if (count + p > total_size) | ||
| 172 | count = total_size - p; | ||
| 173 | |||
| 174 | if (!count) | ||
| 175 | return -EINVAL; | ||
| 176 | |||
| 177 | dst = (void __force *) (info->screen_base + p); | ||
| 178 | |||
| 179 | if (copy_from_user(dst, buf, count)) | ||
| 180 | return -EFAULT; | ||
| 181 | |||
| 182 | ssd1307fb_update_display(par); | ||
| 183 | |||
| 184 | *ppos += count; | ||
| 185 | |||
| 186 | return count; | ||
| 187 | } | ||
| 188 | |||
| 189 | static void ssd1307fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) | ||
| 190 | { | ||
| 191 | struct ssd1307fb_par *par = info->par; | ||
| 192 | sys_fillrect(info, rect); | ||
| 193 | ssd1307fb_update_display(par); | ||
| 194 | } | ||
| 195 | |||
| 196 | static void ssd1307fb_copyarea(struct fb_info *info, const struct fb_copyarea *area) | ||
| 197 | { | ||
| 198 | struct ssd1307fb_par *par = info->par; | ||
| 199 | sys_copyarea(info, area); | ||
| 200 | ssd1307fb_update_display(par); | ||
| 201 | } | ||
| 202 | |||
| 203 | static void ssd1307fb_imageblit(struct fb_info *info, const struct fb_image *image) | ||
| 204 | { | ||
| 205 | struct ssd1307fb_par *par = info->par; | ||
| 206 | sys_imageblit(info, image); | ||
| 207 | ssd1307fb_update_display(par); | ||
| 208 | } | ||
| 209 | |||
| 210 | static struct fb_ops ssd1307fb_ops = { | ||
| 211 | .owner = THIS_MODULE, | ||
| 212 | .fb_read = fb_sys_read, | ||
| 213 | .fb_write = ssd1307fb_write, | ||
| 214 | .fb_fillrect = ssd1307fb_fillrect, | ||
| 215 | .fb_copyarea = ssd1307fb_copyarea, | ||
| 216 | .fb_imageblit = ssd1307fb_imageblit, | ||
| 217 | }; | ||
| 218 | |||
| 219 | static void ssd1307fb_deferred_io(struct fb_info *info, | ||
| 220 | struct list_head *pagelist) | ||
| 221 | { | ||
| 222 | ssd1307fb_update_display(info->par); | ||
| 223 | } | ||
| 224 | |||
| 225 | static struct fb_deferred_io ssd1307fb_defio = { | ||
| 226 | .delay = HZ, | ||
| 227 | .deferred_io = ssd1307fb_deferred_io, | ||
| 228 | }; | ||
| 229 | |||
| 230 | static int __devinit ssd1307fb_probe(struct i2c_client *client, const struct i2c_device_id *id) | ||
| 231 | { | ||
| 232 | struct fb_info *info; | ||
| 233 | u32 vmem_size = SSD1307FB_WIDTH * SSD1307FB_HEIGHT / 8; | ||
| 234 | struct ssd1307fb_par *par; | ||
| 235 | u8 *vmem; | ||
| 236 | int ret; | ||
| 237 | |||
| 238 | if (!client->dev.of_node) { | ||
| 239 | dev_err(&client->dev, "No device tree data found!\n"); | ||
| 240 | return -EINVAL; | ||
| 241 | } | ||
| 242 | |||
| 243 | info = framebuffer_alloc(sizeof(struct ssd1307fb_par), &client->dev); | ||
| 244 | if (!info) { | ||
| 245 | dev_err(&client->dev, "Couldn't allocate framebuffer.\n"); | ||
| 246 | return -ENOMEM; | ||
| 247 | } | ||
| 248 | |||
| 249 | vmem = devm_kzalloc(&client->dev, vmem_size, GFP_KERNEL); | ||
| 250 | if (!vmem) { | ||
| 251 | dev_err(&client->dev, "Couldn't allocate graphical memory.\n"); | ||
| 252 | ret = -ENOMEM; | ||
| 253 | goto fb_alloc_error; | ||
| 254 | } | ||
| 255 | |||
| 256 | info->fbops = &ssd1307fb_ops; | ||
| 257 | info->fix = ssd1307fb_fix; | ||
| 258 | info->fbdefio = &ssd1307fb_defio; | ||
| 259 | |||
| 260 | info->var = ssd1307fb_var; | ||
| 261 | info->var.red.length = 1; | ||
| 262 | info->var.red.offset = 0; | ||
| 263 | info->var.green.length = 1; | ||
| 264 | info->var.green.offset = 0; | ||
| 265 | info->var.blue.length = 1; | ||
| 266 | info->var.blue.offset = 0; | ||
| 267 | |||
| 268 | info->screen_base = (u8 __force __iomem *)vmem; | ||
| 269 | info->fix.smem_start = (unsigned long)vmem; | ||
| 270 | info->fix.smem_len = vmem_size; | ||
| 271 | |||
| 272 | fb_deferred_io_init(info); | ||
| 273 | |||
| 274 | par = info->par; | ||
| 275 | par->info = info; | ||
| 276 | par->client = client; | ||
| 277 | |||
| 278 | par->reset = of_get_named_gpio(client->dev.of_node, | ||
| 279 | "reset-gpios", 0); | ||
| 280 | if (!gpio_is_valid(par->reset)) { | ||
| 281 | ret = -EINVAL; | ||
| 282 | goto reset_oled_error; | ||
| 283 | } | ||
| 284 | |||
| 285 | ret = devm_gpio_request_one(&client->dev, par->reset, | ||
| 286 | GPIOF_OUT_INIT_HIGH, | ||
| 287 | "oled-reset"); | ||
| 288 | if (ret) { | ||
| 289 | dev_err(&client->dev, | ||
| 290 | "failed to request gpio %d: %d\n", | ||
| 291 | par->reset, ret); | ||
| 292 | goto reset_oled_error; | ||
| 293 | } | ||
| 294 | |||
| 295 | par->pwm = pwm_get(&client->dev, NULL); | ||
| 296 | if (IS_ERR(par->pwm)) { | ||
| 297 | dev_err(&client->dev, "Could not get PWM from device tree!\n"); | ||
| 298 | ret = PTR_ERR(par->pwm); | ||
| 299 | goto pwm_error; | ||
| 300 | } | ||
| 301 | |||
| 302 | par->pwm_period = pwm_get_period(par->pwm); | ||
| 303 | |||
| 304 | dev_dbg(&client->dev, "Using PWM%d with a %dns period.\n", par->pwm->pwm, par->pwm_period); | ||
| 305 | |||
| 306 | ret = register_framebuffer(info); | ||
| 307 | if (ret) { | ||
| 308 | dev_err(&client->dev, "Couldn't register the framebuffer\n"); | ||
| 309 | goto fbreg_error; | ||
| 310 | } | ||
| 311 | |||
| 312 | i2c_set_clientdata(client, info); | ||
| 313 | |||
| 314 | /* Reset the screen */ | ||
| 315 | gpio_set_value(par->reset, 0); | ||
| 316 | udelay(4); | ||
| 317 | gpio_set_value(par->reset, 1); | ||
| 318 | udelay(4); | ||
| 319 | |||
| 320 | /* Enable the PWM */ | ||
| 321 | pwm_config(par->pwm, par->pwm_period / 2, par->pwm_period); | ||
| 322 | pwm_enable(par->pwm); | ||
| 323 | |||
| 324 | /* Map column 127 of the OLED to segment 0 */ | ||
| 325 | ret = ssd1307fb_write_cmd(client, SSD1307FB_SEG_REMAP_ON); | ||
| 326 | if (ret < 0) { | ||
| 327 | dev_err(&client->dev, "Couldn't remap the screen.\n"); | ||
| 328 | goto remap_error; | ||
| 329 | } | ||
| 330 | |||
| 331 | /* Turn on the display */ | ||
| 332 | ret = ssd1307fb_write_cmd(client, SSD1307FB_DISPLAY_ON); | ||
| 333 | if (ret < 0) { | ||
| 334 | dev_err(&client->dev, "Couldn't turn the display on.\n"); | ||
| 335 | goto remap_error; | ||
| 336 | } | ||
| 337 | |||
| 338 | dev_info(&client->dev, "fb%d: %s framebuffer device registered, using %d bytes of video memory\n", info->node, info->fix.id, vmem_size); | ||
| 339 | |||
| 340 | return 0; | ||
| 341 | |||
| 342 | remap_error: | ||
| 343 | unregister_framebuffer(info); | ||
| 344 | pwm_disable(par->pwm); | ||
| 345 | fbreg_error: | ||
| 346 | pwm_put(par->pwm); | ||
| 347 | pwm_error: | ||
| 348 | reset_oled_error: | ||
| 349 | fb_deferred_io_cleanup(info); | ||
| 350 | fb_alloc_error: | ||
| 351 | framebuffer_release(info); | ||
| 352 | return ret; | ||
| 353 | } | ||
| 354 | |||
| 355 | static int __devexit ssd1307fb_remove(struct i2c_client *client) | ||
| 356 | { | ||
| 357 | struct fb_info *info = i2c_get_clientdata(client); | ||
| 358 | struct ssd1307fb_par *par = info->par; | ||
| 359 | |||
| 360 | unregister_framebuffer(info); | ||
| 361 | pwm_disable(par->pwm); | ||
| 362 | pwm_put(par->pwm); | ||
| 363 | fb_deferred_io_cleanup(info); | ||
| 364 | framebuffer_release(info); | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 369 | static const struct i2c_device_id ssd1307fb_i2c_id[] = { | ||
| 370 | { "ssd1307fb", 0 }, | ||
| 371 | { } | ||
| 372 | }; | ||
| 373 | MODULE_DEVICE_TABLE(i2c, ssd1307fb_i2c_id); | ||
| 374 | |||
| 375 | static const struct of_device_id ssd1307fb_of_match[] = { | ||
| 376 | { .compatible = "solomon,ssd1307fb-i2c" }, | ||
| 377 | {}, | ||
| 378 | }; | ||
| 379 | MODULE_DEVICE_TABLE(of, ssd1307fb_of_match); | ||
| 380 | |||
| 381 | static struct i2c_driver ssd1307fb_driver = { | ||
| 382 | .probe = ssd1307fb_probe, | ||
| 383 | .remove = __devexit_p(ssd1307fb_remove), | ||
| 384 | .id_table = ssd1307fb_i2c_id, | ||
| 385 | .driver = { | ||
| 386 | .name = "ssd1307fb", | ||
| 387 | .of_match_table = of_match_ptr(ssd1307fb_of_match), | ||
| 388 | .owner = THIS_MODULE, | ||
| 389 | }, | ||
| 390 | }; | ||
| 391 | |||
| 392 | module_i2c_driver(ssd1307fb_driver); | ||
| 393 | |||
| 394 | MODULE_DESCRIPTION("FB driver for the Solomon SSD1307 OLED controler"); | ||
| 395 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||
| 396 | MODULE_LICENSE("GPL"); | ||
