aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2017-01-22 19:17:06 -0500
committerDave Airlie <airlied@redhat.com>2017-01-22 19:17:06 -0500
commit01f5e6912c8abc8a23248e6cf66939756f0fb27c (patch)
treed2bfbad945b715a433eec6200c827f5b4e2138b4
parentd64a1661c8f783214e1a4fd9d38c2919d5b8231d (diff)
parent42f7f3c4811b3149253ecf2e133832c969884466 (diff)
Merge tag 'omapdrm-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux into drm-next
omapdrm changes for 4.11 The main change here is the IRQ code cleanup, which gives us properly working vblank counts and timestamps. We also get much less calls to runtime PM gets & puts. * tag 'omapdrm-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba/linux: (26 commits) drm/omap: panel-sony-acx565akm.c: Add MODULE_ALIAS drm/omap: dsi: fix compile errors when enabling debug prints drm: omapdrm: Perform initialization/cleanup at probe/remove time drm: Move vblank cleanup from unregister to release drm: omapdrm: Use sizeof(*var) instead of sizeof(type) for structures drm: omapdrm: Remove global variables drm: omapdrm: Simplify IRQ wait implementation drm: omapdrm: Inline the pipe2vbl function drm: omapdrm: Don't call DISPC power handling in IRQ wait functions drm: omapdrm: Remove unused parameter from omap_drm_irq handler drm: omapdrm: Don't expose the omap_irq_(un)register() functions drm: omapdrm: Keep vblank interrupt enabled while CRTC is active drm: omapdrm: Use a spinlock to protect the CRTC pending flag drm: omapdrm: Prevent processing the same event multiple times drm: omapdrm: Check the CRTC software state at enable/disable time drm: omapdrm: Let the DRM core skip plane commit on inactive CRTCs drm: omapdrm: Replace DSS manager state check with omapdrm CRTC state drm: omapdrm: Handle OCP error IRQ directly drm: omapdrm: Handle CRTC error IRQs directly drm: omapdrm: Handle FIFO underflow IRQs internally ...
-rw-r--r--drivers/gpu/drm/drm_drv.c4
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c2
-rw-r--r--drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c1
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dispc.c27
-rw-r--r--drivers/gpu/drm/omapdrm/dss/dsi.c18
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c3
-rw-r--r--drivers/gpu/drm/omapdrm/dss/omapdss.h1
-rw-r--r--drivers/gpu/drm/omapdrm/omap_connector.c6
-rw-r--r--drivers/gpu/drm/omapdrm/omap_crtc.c154
-rw-r--r--drivers/gpu/drm/omapdrm/omap_dmm_tiler.c4
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.c216
-rw-r--r--drivers/gpu/drm/omapdrm/omap_drv.h51
-rw-r--r--drivers/gpu/drm/omapdrm/omap_encoder.c2
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fb.c164
-rw-r--r--drivers/gpu/drm/omapdrm/omap_irq.c242
-rw-r--r--drivers/gpu/drm/omapdrm/omap_plane.c24
-rw-r--r--include/uapi/drm/Kbuild1
17 files changed, 441 insertions, 479 deletions
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 1b11ab628da7..72116978ec06 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -598,6 +598,8 @@ static void drm_dev_release(struct kref *ref)
598{ 598{
599 struct drm_device *dev = container_of(ref, struct drm_device, ref); 599 struct drm_device *dev = container_of(ref, struct drm_device, ref);
600 600
601 drm_vblank_cleanup(dev);
602
601 if (drm_core_check_feature(dev, DRIVER_GEM)) 603 if (drm_core_check_feature(dev, DRIVER_GEM))
602 drm_gem_destroy(dev); 604 drm_gem_destroy(dev);
603 605
@@ -805,8 +807,6 @@ void drm_dev_unregister(struct drm_device *dev)
805 if (dev->agp) 807 if (dev->agp)
806 drm_pci_agp_destroy(dev); 808 drm_pci_agp_destroy(dev);
807 809
808 drm_vblank_cleanup(dev);
809
810 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head) 810 list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
811 drm_legacy_rmmap(dev, r_list->map); 811 drm_legacy_rmmap(dev, r_list->map);
812 812
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
index dc026a843712..a2bb855a2851 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-dsi-cm.c
@@ -1253,7 +1253,7 @@ static int dsicm_probe(struct platform_device *pdev)
1253 dsicm_hw_reset(ddata); 1253 dsicm_hw_reset(ddata);
1254 1254
1255 if (ddata->use_dsi_backlight) { 1255 if (ddata->use_dsi_backlight) {
1256 memset(&props, 0, sizeof(struct backlight_properties)); 1256 memset(&props, 0, sizeof(props));
1257 props.max_brightness = 255; 1257 props.max_brightness = 255;
1258 1258
1259 props.type = BACKLIGHT_RAW; 1259 props.type = BACKLIGHT_RAW;
diff --git a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
index 746cb8d9cba1..5ab39e0060f2 100644
--- a/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
+++ b/drivers/gpu/drm/omapdrm/displays/panel-sony-acx565akm.c
@@ -909,6 +909,7 @@ static struct spi_driver acx565akm_driver = {
909 909
910module_spi_driver(acx565akm_driver); 910module_spi_driver(acx565akm_driver);
911 911
912MODULE_ALIAS("spi:sony,acx565akm");
912MODULE_AUTHOR("Nokia Corporation"); 913MODULE_AUTHOR("Nokia Corporation");
913MODULE_DESCRIPTION("acx565akm LCD Driver"); 914MODULE_DESCRIPTION("acx565akm LCD Driver");
914MODULE_LICENSE("GPL"); 915MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/omapdrm/dss/dispc.c b/drivers/gpu/drm/omapdrm/dss/dispc.c
index c839f6456db2..5554b72cf56a 100644
--- a/drivers/gpu/drm/omapdrm/dss/dispc.c
+++ b/drivers/gpu/drm/omapdrm/dss/dispc.c
@@ -620,6 +620,19 @@ u32 dispc_wb_get_framedone_irq(void)
620 return DISPC_IRQ_FRAMEDONEWB; 620 return DISPC_IRQ_FRAMEDONEWB;
621} 621}
622 622
623void dispc_mgr_enable(enum omap_channel channel, bool enable)
624{
625 mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
626 /* flush posted write */
627 mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
628}
629EXPORT_SYMBOL(dispc_mgr_enable);
630
631static bool dispc_mgr_is_enabled(enum omap_channel channel)
632{
633 return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
634}
635
623bool dispc_mgr_go_busy(enum omap_channel channel) 636bool dispc_mgr_go_busy(enum omap_channel channel)
624{ 637{
625 return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; 638 return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
@@ -2901,20 +2914,6 @@ enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channe
2901} 2914}
2902EXPORT_SYMBOL(dispc_mgr_get_supported_outputs); 2915EXPORT_SYMBOL(dispc_mgr_get_supported_outputs);
2903 2916
2904void dispc_mgr_enable(enum omap_channel channel, bool enable)
2905{
2906 mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
2907 /* flush posted write */
2908 mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
2909}
2910EXPORT_SYMBOL(dispc_mgr_enable);
2911
2912bool dispc_mgr_is_enabled(enum omap_channel channel)
2913{
2914 return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
2915}
2916EXPORT_SYMBOL(dispc_mgr_is_enabled);
2917
2918void dispc_wb_enable(bool enable) 2917void dispc_wb_enable(bool enable)
2919{ 2918{
2920 dispc_ovl_enable(OMAP_DSS_WB, enable); 2919 dispc_ovl_enable(OMAP_DSS_WB, enable);
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index f060bda31235..f74615d005a8 100644
--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -4336,7 +4336,7 @@ static void print_dsi_vm(const char *str,
4336 4336
4337 wc = DIV_ROUND_UP(t->hact * t->bitspp, 8); 4337 wc = DIV_ROUND_UP(t->hact * t->bitspp, 8);
4338 pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */ 4338 pps = DIV_ROUND_UP(wc + 6, t->ndl); /* pixel packet size */
4339 bl = t->hss + t->hsa + t->hse + t->hbp + t->hfront_porch; 4339 bl = t->hss + t->hsa + t->hse + t->hbp + t->hfp;
4340 tot = bl + pps; 4340 tot = bl + pps;
4341 4341
4342#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk)) 4342#define TO_DSI_T(x) ((u32)div64_u64((u64)x * 1000000000llu, byteclk))
@@ -4345,14 +4345,14 @@ static void print_dsi_vm(const char *str,
4345 "%u/%u/%u/%u/%u/%u = %u + %u = %u\n", 4345 "%u/%u/%u/%u/%u/%u = %u + %u = %u\n",
4346 str, 4346 str,
4347 byteclk, 4347 byteclk,
4348 t->hss, t->hsa, t->hse, t->hbp, pps, t->hfront_porch, 4348 t->hss, t->hsa, t->hse, t->hbp, pps, t->hfp,
4349 bl, pps, tot, 4349 bl, pps, tot,
4350 TO_DSI_T(t->hss), 4350 TO_DSI_T(t->hss),
4351 TO_DSI_T(t->hsa), 4351 TO_DSI_T(t->hsa),
4352 TO_DSI_T(t->hse), 4352 TO_DSI_T(t->hse),
4353 TO_DSI_T(t->hbp), 4353 TO_DSI_T(t->hbp),
4354 TO_DSI_T(pps), 4354 TO_DSI_T(pps),
4355 TO_DSI_T(t->hfront_porch), 4355 TO_DSI_T(t->hfp),
4356 4356
4357 TO_DSI_T(bl), 4357 TO_DSI_T(bl),
4358 TO_DSI_T(pps), 4358 TO_DSI_T(pps),
@@ -4367,7 +4367,7 @@ static void print_dispc_vm(const char *str, const struct videomode *vm)
4367 int hact, bl, tot; 4367 int hact, bl, tot;
4368 4368
4369 hact = vm->hactive; 4369 hact = vm->hactive;
4370 bl = vm->hsync_len + vm->hbp + vm->hfront_porch; 4370 bl = vm->hsync_len + vm->hback_porch + vm->hfront_porch;
4371 tot = hact + bl; 4371 tot = hact + bl;
4372 4372
4373#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck)) 4373#define TO_DISPC_T(x) ((u32)div64_u64((u64)x * 1000000000llu, pck))
@@ -4376,10 +4376,10 @@ static void print_dispc_vm(const char *str, const struct videomode *vm)
4376 "%u/%u/%u/%u = %u + %u = %u\n", 4376 "%u/%u/%u/%u = %u + %u = %u\n",
4377 str, 4377 str,
4378 pck, 4378 pck,
4379 vm->hsync_len, vm->hbp, hact, vm->hfront_porch, 4379 vm->hsync_len, vm->hback_porch, hact, vm->hfront_porch,
4380 bl, hact, tot, 4380 bl, hact, tot,
4381 TO_DISPC_T(vm->hsync_len), 4381 TO_DISPC_T(vm->hsync_len),
4382 TO_DISPC_T(vm->hbp), 4382 TO_DISPC_T(vm->hback_porch),
4383 TO_DISPC_T(hact), 4383 TO_DISPC_T(hact),
4384 TO_DISPC_T(vm->hfront_porch), 4384 TO_DISPC_T(vm->hfront_porch),
4385 TO_DISPC_T(bl), 4385 TO_DISPC_T(bl),
@@ -4401,12 +4401,12 @@ static void print_dsi_dispc_vm(const char *str,
4401 dsi_tput = (u64)byteclk * t->ndl * 8; 4401 dsi_tput = (u64)byteclk * t->ndl * 8;
4402 pck = (u32)div64_u64(dsi_tput, t->bitspp); 4402 pck = (u32)div64_u64(dsi_tput, t->bitspp);
4403 dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl); 4403 dsi_hact = DIV_ROUND_UP(DIV_ROUND_UP(t->hact * t->bitspp, 8) + 6, t->ndl);
4404 dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfront_porch; 4404 dsi_htot = t->hss + t->hsa + t->hse + t->hbp + dsi_hact + t->hfp;
4405 4405
4406 vm.pixelclock = pck; 4406 vm.pixelclock = pck;
4407 vm.hsync_len = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk); 4407 vm.hsync_len = div64_u64((u64)(t->hsa + t->hse) * pck, byteclk);
4408 vm.hbp = div64_u64((u64)t->hbp * pck, byteclk); 4408 vm.hback_porch = div64_u64((u64)t->hbp * pck, byteclk);
4409 vm.hfront_porch = div64_u64((u64)t->hfront_porch * pck, byteclk); 4409 vm.hfront_porch = div64_u64((u64)t->hfp * pck, byteclk);
4410 vm.hactive = t->hact; 4410 vm.hactive = t->hact;
4411 4411
4412 print_dispc_vm(str, &vm); 4412 print_dispc_vm(str, &vm);
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
index 136d30484d02..bf626acae271 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss-boot-init.c
@@ -119,8 +119,7 @@ static void __init omapdss_omapify_node(struct device_node *node)
119 119
120static void __init omapdss_add_to_list(struct device_node *node, bool root) 120static void __init omapdss_add_to_list(struct device_node *node, bool root)
121{ 121{
122 struct dss_conv_node *n = kmalloc(sizeof(struct dss_conv_node), 122 struct dss_conv_node *n = kmalloc(sizeof(*n), GFP_KERNEL);
123 GFP_KERNEL);
124 if (n) { 123 if (n) {
125 n->node = node; 124 n->node = node;
126 n->root = root; 125 n->root = root;
diff --git a/drivers/gpu/drm/omapdrm/dss/omapdss.h b/drivers/gpu/drm/omapdrm/dss/omapdss.h
index b420dde8c0fb..5b3b961127bd 100644
--- a/drivers/gpu/drm/omapdrm/dss/omapdss.h
+++ b/drivers/gpu/drm/omapdrm/dss/omapdss.h
@@ -856,7 +856,6 @@ int dispc_runtime_get(void);
856void dispc_runtime_put(void); 856void dispc_runtime_put(void);
857 857
858void dispc_mgr_enable(enum omap_channel channel, bool enable); 858void dispc_mgr_enable(enum omap_channel channel, bool enable);
859bool dispc_mgr_is_enabled(enum omap_channel channel);
860u32 dispc_mgr_get_vsync_irq(enum omap_channel channel); 859u32 dispc_mgr_get_vsync_irq(enum omap_channel channel);
861u32 dispc_mgr_get_framedone_irq(enum omap_channel channel); 860u32 dispc_mgr_get_framedone_irq(enum omap_channel channel);
862u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel); 861u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel);
diff --git a/drivers/gpu/drm/omapdrm/omap_connector.c b/drivers/gpu/drm/omapdrm/omap_connector.c
index 2580e8673908..f90e2d22c5ec 100644
--- a/drivers/gpu/drm/omapdrm/omap_connector.c
+++ b/drivers/gpu/drm/omapdrm/omap_connector.c
@@ -162,7 +162,7 @@ static int omap_connector_mode_valid(struct drm_connector *connector,
162 162
163 dssdrv->get_timings(dssdev, &t); 163 dssdrv->get_timings(dssdev, &t);
164 164
165 if (memcmp(&vm, &t, sizeof(struct videomode))) 165 if (memcmp(&vm, &t, sizeof(vm)))
166 r = -EINVAL; 166 r = -EINVAL;
167 else 167 else
168 r = 0; 168 r = 0;
@@ -217,7 +217,7 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
217 217
218 omap_dss_get_device(dssdev); 218 omap_dss_get_device(dssdev);
219 219
220 omap_connector = kzalloc(sizeof(struct omap_connector), GFP_KERNEL); 220 omap_connector = kzalloc(sizeof(*omap_connector), GFP_KERNEL);
221 if (!omap_connector) 221 if (!omap_connector)
222 goto fail; 222 goto fail;
223 223
@@ -240,8 +240,6 @@ struct drm_connector *omap_connector_init(struct drm_device *dev,
240 connector->interlace_allowed = 1; 240 connector->interlace_allowed = 1;
241 connector->doublescan_allowed = 0; 241 connector->doublescan_allowed = 0;
242 242
243 drm_connector_register(connector);
244
245 return connector; 243 return connector;
246 244
247fail: 245fail:
diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c
index 8dea89030e66..dd47dc191e6b 100644
--- a/drivers/gpu/drm/omapdrm/omap_crtc.c
+++ b/drivers/gpu/drm/omapdrm/omap_crtc.c
@@ -36,26 +36,18 @@ struct omap_crtc {
36 36
37 struct videomode vm; 37 struct videomode vm;
38 38
39 struct omap_drm_irq vblank_irq;
40 struct omap_drm_irq error_irq;
41
42 bool ignore_digit_sync_lost; 39 bool ignore_digit_sync_lost;
43 40
41 bool enabled;
44 bool pending; 42 bool pending;
45 wait_queue_head_t pending_wait; 43 wait_queue_head_t pending_wait;
44 struct drm_pending_vblank_event *event;
46}; 45};
47 46
48/* ----------------------------------------------------------------------------- 47/* -----------------------------------------------------------------------------
49 * Helper Functions 48 * Helper Functions
50 */ 49 */
51 50
52uint32_t pipe2vbl(struct drm_crtc *crtc)
53{
54 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
55
56 return dispc_mgr_get_vsync_irq(omap_crtc->channel);
57}
58
59struct videomode *omap_crtc_timings(struct drm_crtc *crtc) 51struct videomode *omap_crtc_timings(struct drm_crtc *crtc)
60{ 52{
61 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 53 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -68,6 +60,19 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc)
68 return omap_crtc->channel; 60 return omap_crtc->channel;
69} 61}
70 62
63static bool omap_crtc_is_pending(struct drm_crtc *crtc)
64{
65 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
66 unsigned long flags;
67 bool pending;
68
69 spin_lock_irqsave(&crtc->dev->event_lock, flags);
70 pending = omap_crtc->pending;
71 spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
72
73 return pending;
74}
75
71int omap_crtc_wait_pending(struct drm_crtc *crtc) 76int omap_crtc_wait_pending(struct drm_crtc *crtc)
72{ 77{
73 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 78 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
@@ -77,7 +82,7 @@ int omap_crtc_wait_pending(struct drm_crtc *crtc)
77 * a single frame refresh even on slower displays. 82 * a single frame refresh even on slower displays.
78 */ 83 */
79 return wait_event_timeout(omap_crtc->pending_wait, 84 return wait_event_timeout(omap_crtc->pending_wait,
80 !omap_crtc->pending, 85 !omap_crtc_is_pending(crtc),
81 msecs_to_jiffies(250)); 86 msecs_to_jiffies(250));
82} 87}
83 88
@@ -135,14 +140,15 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
135 u32 framedone_irq, vsync_irq; 140 u32 framedone_irq, vsync_irq;
136 int ret; 141 int ret;
137 142
143 if (WARN_ON(omap_crtc->enabled == enable))
144 return;
145
138 if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) { 146 if (omap_crtc_output[channel]->output_type == OMAP_DISPLAY_TYPE_HDMI) {
139 dispc_mgr_enable(channel, enable); 147 dispc_mgr_enable(channel, enable);
148 omap_crtc->enabled = enable;
140 return; 149 return;
141 } 150 }
142 151
143 if (dispc_mgr_is_enabled(channel) == enable)
144 return;
145
146 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) { 152 if (omap_crtc->channel == OMAP_DSS_CHANNEL_DIGIT) {
147 /* 153 /*
148 * Digit output produces some sync lost interrupts during the 154 * Digit output produces some sync lost interrupts during the
@@ -173,6 +179,7 @@ static void omap_crtc_set_enabled(struct drm_crtc *crtc, bool enable)
173 } 179 }
174 180
175 dispc_mgr_enable(channel, enable); 181 dispc_mgr_enable(channel, enable);
182 omap_crtc->enabled = enable;
176 183
177 ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100)); 184 ret = omap_irq_wait(dev, wait, msecs_to_jiffies(100));
178 if (ret) { 185 if (ret) {
@@ -259,26 +266,9 @@ static const struct dss_mgr_ops mgr_ops = {
259 * Setup, Flush and Page Flip 266 * Setup, Flush and Page Flip
260 */ 267 */
261 268
262static void omap_crtc_complete_page_flip(struct drm_crtc *crtc) 269void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus)
263{ 270{
264 struct drm_pending_vblank_event *event; 271 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
265 struct drm_device *dev = crtc->dev;
266 unsigned long flags;
267
268 event = crtc->state->event;
269
270 if (!event)
271 return;
272
273 spin_lock_irqsave(&dev->event_lock, flags);
274 drm_crtc_send_vblank_event(crtc, event);
275 spin_unlock_irqrestore(&dev->event_lock, flags);
276}
277
278static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
279{
280 struct omap_crtc *omap_crtc =
281 container_of(irq, struct omap_crtc, error_irq);
282 272
283 if (omap_crtc->ignore_digit_sync_lost) { 273 if (omap_crtc->ignore_digit_sync_lost) {
284 irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT; 274 irqstatus &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
@@ -289,29 +279,38 @@ static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
289 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus); 279 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_crtc->name, irqstatus);
290} 280}
291 281
292static void omap_crtc_vblank_irq(struct omap_drm_irq *irq, uint32_t irqstatus) 282void omap_crtc_vblank_irq(struct drm_crtc *crtc)
293{ 283{
294 struct omap_crtc *omap_crtc = 284 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
295 container_of(irq, struct omap_crtc, vblank_irq); 285 bool pending;
296 struct drm_device *dev = omap_crtc->base.dev;
297 286
298 if (dispc_mgr_go_busy(omap_crtc->channel)) 287 spin_lock(&crtc->dev->event_lock);
288 /*
289 * If the dispc is busy we're racing the flush operation. Try again on
290 * the next vblank interrupt.
291 */
292 if (dispc_mgr_go_busy(omap_crtc->channel)) {
293 spin_unlock(&crtc->dev->event_lock);
299 return; 294 return;
295 }
300 296
301 DBG("%s: apply done", omap_crtc->name); 297 /* Send the vblank event if one has been requested. */
302 298 if (omap_crtc->event) {
303 __omap_irq_unregister(dev, &omap_crtc->vblank_irq); 299 drm_crtc_send_vblank_event(crtc, omap_crtc->event);
300 omap_crtc->event = NULL;
301 }
304 302
305 rmb(); 303 pending = omap_crtc->pending;
306 WARN_ON(!omap_crtc->pending);
307 omap_crtc->pending = false; 304 omap_crtc->pending = false;
308 wmb(); 305 spin_unlock(&crtc->dev->event_lock);
309 306
310 /* wake up userspace */ 307 if (pending)
311 omap_crtc_complete_page_flip(&omap_crtc->base); 308 drm_crtc_vblank_put(crtc);
312 309
313 /* wake up omap_atomic_complete */ 310 /* Wake up omap_atomic_complete. */
314 wake_up(&omap_crtc->pending_wait); 311 wake_up(&omap_crtc->pending_wait);
312
313 DBG("%s: apply done", omap_crtc->name);
315} 314}
316 315
317/* ----------------------------------------------------------------------------- 316/* -----------------------------------------------------------------------------
@@ -324,9 +323,6 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
324 323
325 DBG("%s", omap_crtc->name); 324 DBG("%s", omap_crtc->name);
326 325
327 WARN_ON(omap_crtc->vblank_irq.registered);
328 omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
329
330 drm_crtc_cleanup(crtc); 326 drm_crtc_cleanup(crtc);
331 327
332 kfree(omap_crtc); 328 kfree(omap_crtc);
@@ -335,17 +331,18 @@ static void omap_crtc_destroy(struct drm_crtc *crtc)
335static void omap_crtc_enable(struct drm_crtc *crtc) 331static void omap_crtc_enable(struct drm_crtc *crtc)
336{ 332{
337 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 333 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
334 int ret;
338 335
339 DBG("%s", omap_crtc->name); 336 DBG("%s", omap_crtc->name);
340 337
341 rmb(); 338 spin_lock_irq(&crtc->dev->event_lock);
339 drm_crtc_vblank_on(crtc);
340 ret = drm_crtc_vblank_get(crtc);
341 WARN_ON(ret != 0);
342
342 WARN_ON(omap_crtc->pending); 343 WARN_ON(omap_crtc->pending);
343 omap_crtc->pending = true; 344 omap_crtc->pending = true;
344 wmb(); 345 spin_unlock_irq(&crtc->dev->event_lock);
345
346 omap_irq_register(crtc->dev, &omap_crtc->vblank_irq);
347
348 drm_crtc_vblank_on(crtc);
349} 346}
350 347
351static void omap_crtc_disable(struct drm_crtc *crtc) 348static void omap_crtc_disable(struct drm_crtc *crtc)
@@ -390,16 +387,15 @@ static int omap_crtc_atomic_check(struct drm_crtc *crtc,
390} 387}
391 388
392static void omap_crtc_atomic_begin(struct drm_crtc *crtc, 389static void omap_crtc_atomic_begin(struct drm_crtc *crtc,
393 struct drm_crtc_state *old_crtc_state) 390 struct drm_crtc_state *old_crtc_state)
394{ 391{
395} 392}
396 393
397static void omap_crtc_atomic_flush(struct drm_crtc *crtc, 394static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
398 struct drm_crtc_state *old_crtc_state) 395 struct drm_crtc_state *old_crtc_state)
399{ 396{
400 struct omap_crtc *omap_crtc = to_omap_crtc(crtc); 397 struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
401 398 int ret;
402 WARN_ON(omap_crtc->vblank_irq.registered);
403 399
404 if (crtc->state->color_mgmt_changed) { 400 if (crtc->state->color_mgmt_changed) {
405 struct drm_color_lut *lut = NULL; 401 struct drm_color_lut *lut = NULL;
@@ -414,18 +410,30 @@ static void omap_crtc_atomic_flush(struct drm_crtc *crtc,
414 dispc_mgr_set_gamma(omap_crtc->channel, lut, length); 410 dispc_mgr_set_gamma(omap_crtc->channel, lut, length);
415 } 411 }
416 412
417 if (dispc_mgr_is_enabled(omap_crtc->channel)) { 413 /*
414 * Only flush the CRTC if it is currently enabled. CRTCs that require a
415 * mode set are disabled prior plane updates and enabled afterwards.
416 * They are thus not active (regardless of what their CRTC core state
417 * reports) and the DRM core could thus call this function even though
418 * the CRTC is currently disabled. Do nothing in that case.
419 */
420 if (!omap_crtc->enabled)
421 return;
422
423 DBG("%s: GO", omap_crtc->name);
418 424
419 DBG("%s: GO", omap_crtc->name); 425 ret = drm_crtc_vblank_get(crtc);
426 WARN_ON(ret != 0);
420 427
421 rmb(); 428 spin_lock_irq(&crtc->dev->event_lock);
422 WARN_ON(omap_crtc->pending); 429 dispc_mgr_go(omap_crtc->channel);
423 omap_crtc->pending = true;
424 wmb();
425 430
426 dispc_mgr_go(omap_crtc->channel); 431 WARN_ON(omap_crtc->pending);
427 omap_irq_register(crtc->dev, &omap_crtc->vblank_irq); 432 omap_crtc->pending = true;
428 } 433
434 if (crtc->state->event)
435 omap_crtc->event = crtc->state->event;
436 spin_unlock_irq(&crtc->dev->event_lock);
429} 437}
430 438
431static bool omap_crtc_is_plane_prop(struct drm_crtc *crtc, 439static bool omap_crtc_is_plane_prop(struct drm_crtc *crtc,
@@ -546,14 +554,6 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev,
546 omap_crtc->channel = channel; 554 omap_crtc->channel = channel;
547 omap_crtc->name = channel_names[channel]; 555 omap_crtc->name = channel_names[channel];
548 556
549 omap_crtc->vblank_irq.irqmask = pipe2vbl(crtc);
550 omap_crtc->vblank_irq.irq = omap_crtc_vblank_irq;
551
552 omap_crtc->error_irq.irqmask =
553 dispc_mgr_get_sync_lost_irq(channel);
554 omap_crtc->error_irq.irq = omap_crtc_error_irq;
555 omap_irq_register(dev, &omap_crtc->error_irq);
556
557 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL, 557 ret = drm_crtc_init_with_planes(dev, crtc, plane, NULL,
558 &omap_crtc_funcs, NULL); 558 &omap_crtc_funcs, NULL);
559 if (ret < 0) { 559 if (ret < 0) {
diff --git a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
index 4ceed7a9762f..3cab06661a08 100644
--- a/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
+++ b/drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
@@ -224,7 +224,7 @@ static void dmm_txn_append(struct dmm_txn *txn, struct pat_area *area,
224 int rows = (1 + area->y1 - area->y0); 224 int rows = (1 + area->y1 - area->y0);
225 int i = columns*rows; 225 int i = columns*rows;
226 226
227 pat = alloc_dma(txn, sizeof(struct pat), &pat_pa); 227 pat = alloc_dma(txn, sizeof(*pat), &pat_pa);
228 228
229 if (txn->last_pat) 229 if (txn->last_pat)
230 txn->last_pat->next_pa = (uint32_t)pat_pa; 230 txn->last_pat->next_pa = (uint32_t)pat_pa;
@@ -735,7 +735,7 @@ static int omap_dmm_probe(struct platform_device *dev)
735 735
736 /* alloc engines */ 736 /* alloc engines */
737 omap_dmm->engines = kcalloc(omap_dmm->num_engines, 737 omap_dmm->engines = kcalloc(omap_dmm->num_engines,
738 sizeof(struct refill_engine), GFP_KERNEL); 738 sizeof(*omap_dmm->engines), GFP_KERNEL);
739 if (!omap_dmm->engines) { 739 if (!omap_dmm->engines) {
740 ret = -ENOMEM; 740 ret = -ENOMEM;
741 goto fail; 741 goto fail;
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.c b/drivers/gpu/drm/omapdrm/omap_drv.c
index 4fd2e1799a88..00aa214b7560 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.c
+++ b/drivers/gpu/drm/omapdrm/omap_drv.c
@@ -96,7 +96,8 @@ static void omap_atomic_complete(struct omap_atomic_state_commit *commit)
96 dispc_runtime_get(); 96 dispc_runtime_get();
97 97
98 drm_atomic_helper_commit_modeset_disables(dev, old_state); 98 drm_atomic_helper_commit_modeset_disables(dev, old_state);
99 drm_atomic_helper_commit_planes(dev, old_state, 0); 99 drm_atomic_helper_commit_planes(dev, old_state,
100 DRM_PLANE_COMMIT_ACTIVE_ONLY);
100 drm_atomic_helper_commit_modeset_enables(dev, old_state); 101 drm_atomic_helper_commit_modeset_enables(dev, old_state);
101 102
102 omap_atomic_wait_for_completion(dev, old_state); 103 omap_atomic_wait_for_completion(dev, old_state);
@@ -315,8 +316,6 @@ static int omap_modeset_init(struct drm_device *dev)
315 316
316 drm_mode_config_init(dev); 317 drm_mode_config_init(dev);
317 318
318 omap_drm_irq_install(dev);
319
320 ret = omap_modeset_init_properties(dev); 319 ret = omap_modeset_init_properties(dev);
321 if (ret < 0) 320 if (ret < 0)
322 return ret; 321 return ret;
@@ -489,12 +488,9 @@ static int omap_modeset_init(struct drm_device *dev)
489 488
490 drm_mode_config_reset(dev); 489 drm_mode_config_reset(dev);
491 490
492 return 0; 491 omap_drm_irq_install(dev);
493}
494 492
495static void omap_modeset_free(struct drm_device *dev) 493 return 0;
496{
497 drm_mode_config_cleanup(dev);
498} 494}
499 495
500/* 496/*
@@ -632,93 +628,6 @@ static const struct drm_ioctl_desc ioctls[DRM_COMMAND_END - DRM_COMMAND_BASE] =
632 * drm driver funcs 628 * drm driver funcs
633 */ 629 */
634 630
635/**
636 * load - setup chip and create an initial config
637 * @dev: DRM device
638 * @flags: startup flags
639 *
640 * The driver load routine has to do several things:
641 * - initialize the memory manager
642 * - allocate initial config memory
643 * - setup the DRM framebuffer with the allocated memory
644 */
645static int dev_load(struct drm_device *dev, unsigned long flags)
646{
647 struct omap_drm_platform_data *pdata = dev->dev->platform_data;
648 struct omap_drm_private *priv;
649 unsigned int i;
650 int ret;
651
652 DBG("load: dev=%p", dev);
653
654 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
655 if (!priv)
656 return -ENOMEM;
657
658 priv->omaprev = pdata->omaprev;
659
660 dev->dev_private = priv;
661
662 priv->wq = alloc_ordered_workqueue("omapdrm", 0);
663 init_waitqueue_head(&priv->commit.wait);
664 spin_lock_init(&priv->commit.lock);
665
666 spin_lock_init(&priv->list_lock);
667 INIT_LIST_HEAD(&priv->obj_list);
668
669 omap_gem_init(dev);
670
671 ret = omap_modeset_init(dev);
672 if (ret) {
673 dev_err(dev->dev, "omap_modeset_init failed: ret=%d\n", ret);
674 dev->dev_private = NULL;
675 kfree(priv);
676 return ret;
677 }
678
679 /* Initialize vblank handling, start with all CRTCs disabled. */
680 ret = drm_vblank_init(dev, priv->num_crtcs);
681 if (ret)
682 dev_warn(dev->dev, "could not init vblank\n");
683
684 for (i = 0; i < priv->num_crtcs; i++)
685 drm_crtc_vblank_off(priv->crtcs[i]);
686
687 priv->fbdev = omap_fbdev_init(dev);
688
689 /* store off drm_device for use in pm ops */
690 dev_set_drvdata(dev->dev, dev);
691
692 drm_kms_helper_poll_init(dev);
693
694 return 0;
695}
696
697static void dev_unload(struct drm_device *dev)
698{
699 struct omap_drm_private *priv = dev->dev_private;
700
701 DBG("unload: dev=%p", dev);
702
703 drm_kms_helper_poll_fini(dev);
704
705 if (priv->fbdev)
706 omap_fbdev_free(dev);
707
708 omap_modeset_free(dev);
709 omap_gem_deinit(dev);
710
711 destroy_workqueue(priv->wq);
712
713 drm_vblank_cleanup(dev);
714 omap_drm_irq_uninstall(dev);
715
716 kfree(dev->dev_private);
717 dev->dev_private = NULL;
718
719 dev_set_drvdata(dev->dev, NULL);
720}
721
722static int dev_open(struct drm_device *dev, struct drm_file *file) 631static int dev_open(struct drm_device *dev, struct drm_file *file)
723{ 632{
724 file->driver_priv = NULL; 633 file->driver_priv = NULL;
@@ -803,8 +712,6 @@ static const struct file_operations omapdriver_fops = {
803static struct drm_driver omap_drm_driver = { 712static struct drm_driver omap_drm_driver = {
804 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME | 713 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME |
805 DRIVER_ATOMIC, 714 DRIVER_ATOMIC,
806 .load = dev_load,
807 .unload = dev_unload,
808 .open = dev_open, 715 .open = dev_open,
809 .lastclose = dev_lastclose, 716 .lastclose = dev_lastclose,
810 .get_vblank_counter = drm_vblank_no_hw_counter, 717 .get_vblank_counter = drm_vblank_no_hw_counter,
@@ -834,30 +741,125 @@ static struct drm_driver omap_drm_driver = {
834 .patchlevel = DRIVER_PATCHLEVEL, 741 .patchlevel = DRIVER_PATCHLEVEL,
835}; 742};
836 743
837static int pdev_probe(struct platform_device *device) 744static int pdev_probe(struct platform_device *pdev)
838{ 745{
839 int r; 746 struct omap_drm_platform_data *pdata = pdev->dev.platform_data;
747 struct omap_drm_private *priv;
748 struct drm_device *ddev;
749 unsigned int i;
750 int ret;
751
752 DBG("%s", pdev->name);
840 753
841 if (omapdss_is_initialized() == false) 754 if (omapdss_is_initialized() == false)
842 return -EPROBE_DEFER; 755 return -EPROBE_DEFER;
843 756
844 omap_crtc_pre_init(); 757 omap_crtc_pre_init();
845 758
846 r = omap_connect_dssdevs(); 759 ret = omap_connect_dssdevs();
847 if (r) { 760 if (ret)
848 omap_crtc_pre_uninit(); 761 goto err_crtc_uninit;
849 return r; 762
763 /* Allocate and initialize the driver private structure. */
764 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
765 if (!priv) {
766 ret = -ENOMEM;
767 goto err_disconnect_dssdevs;
850 } 768 }
851 769
852 DBG("%s", device->name); 770 priv->omaprev = pdata->omaprev;
853 return drm_platform_init(&omap_drm_driver, device); 771 priv->wq = alloc_ordered_workqueue("omapdrm", 0);
772
773 init_waitqueue_head(&priv->commit.wait);
774 spin_lock_init(&priv->commit.lock);
775 spin_lock_init(&priv->list_lock);
776 INIT_LIST_HEAD(&priv->obj_list);
777
778 /* Allocate and initialize the DRM device. */
779 ddev = drm_dev_alloc(&omap_drm_driver, &pdev->dev);
780 if (IS_ERR(ddev)) {
781 ret = PTR_ERR(ddev);
782 goto err_free_priv;
783 }
784
785 ddev->dev_private = priv;
786 platform_set_drvdata(pdev, ddev);
787
788 omap_gem_init(ddev);
789
790 ret = omap_modeset_init(ddev);
791 if (ret) {
792 dev_err(&pdev->dev, "omap_modeset_init failed: ret=%d\n", ret);
793 goto err_free_drm_dev;
794 }
795
796 /* Initialize vblank handling, start with all CRTCs disabled. */
797 ret = drm_vblank_init(ddev, priv->num_crtcs);
798 if (ret) {
799 dev_err(&pdev->dev, "could not init vblank\n");
800 goto err_cleanup_modeset;
801 }
802
803 for (i = 0; i < priv->num_crtcs; i++)
804 drm_crtc_vblank_off(priv->crtcs[i]);
805
806 priv->fbdev = omap_fbdev_init(ddev);
807
808 drm_kms_helper_poll_init(ddev);
809
810 /*
811 * Register the DRM device with the core and the connectors with
812 * sysfs.
813 */
814 ret = drm_dev_register(ddev, 0);
815 if (ret)
816 goto err_cleanup_helpers;
817
818 return 0;
819
820err_cleanup_helpers:
821 drm_kms_helper_poll_fini(ddev);
822 if (priv->fbdev)
823 omap_fbdev_free(ddev);
824err_cleanup_modeset:
825 drm_mode_config_cleanup(ddev);
826 omap_drm_irq_uninstall(ddev);
827err_free_drm_dev:
828 omap_gem_deinit(ddev);
829 drm_dev_unref(ddev);
830err_free_priv:
831 destroy_workqueue(priv->wq);
832 kfree(priv);
833err_disconnect_dssdevs:
834 omap_disconnect_dssdevs();
835err_crtc_uninit:
836 omap_crtc_pre_uninit();
837 return ret;
854} 838}
855 839
856static int pdev_remove(struct platform_device *device) 840static int pdev_remove(struct platform_device *pdev)
857{ 841{
842 struct drm_device *ddev = platform_get_drvdata(pdev);
843 struct omap_drm_private *priv = ddev->dev_private;
844
858 DBG(""); 845 DBG("");
859 846
860 drm_put_dev(platform_get_drvdata(device)); 847 drm_dev_unregister(ddev);
848
849 drm_kms_helper_poll_fini(ddev);
850
851 if (priv->fbdev)
852 omap_fbdev_free(ddev);
853
854 drm_mode_config_cleanup(ddev);
855
856 omap_drm_irq_uninstall(ddev);
857 omap_gem_deinit(ddev);
858
859 drm_dev_unref(ddev);
860
861 destroy_workqueue(priv->wq);
862 kfree(priv);
861 863
862 omap_disconnect_dssdevs(); 864 omap_disconnect_dssdevs();
863 omap_crtc_pre_uninit(); 865 omap_crtc_pre_uninit();
diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h
index 7d9dd5400cef..b20377efd01b 100644
--- a/drivers/gpu/drm/omapdrm/omap_drv.h
+++ b/drivers/gpu/drm/omapdrm/omap_drv.h
@@ -48,19 +48,6 @@ struct omap_drm_window {
48 uint32_t src_w, src_h; 48 uint32_t src_w, src_h;
49}; 49};
50 50
51/* For transiently registering for different DSS irqs that various parts
52 * of the KMS code need during setup/configuration. We these are not
53 * necessarily the same as what drm_vblank_get/put() are requesting, and
54 * the hysteresis in drm_vblank_put() is not necessarily desirable for
55 * internal housekeeping related irq usage.
56 */
57struct omap_drm_irq {
58 struct list_head node;
59 uint32_t irqmask;
60 bool registered;
61 void (*irq)(struct omap_drm_irq *irq, uint32_t irqstatus);
62};
63
64/* For KMS code that needs to wait for a certain # of IRQs: 51/* For KMS code that needs to wait for a certain # of IRQs:
65 */ 52 */
66struct omap_irq_wait; 53struct omap_irq_wait;
@@ -101,9 +88,9 @@ struct omap_drm_private {
101 struct drm_property *zorder_prop; 88 struct drm_property *zorder_prop;
102 89
103 /* irq handling: */ 90 /* irq handling: */
104 struct list_head irq_list; /* list of omap_drm_irq */ 91 spinlock_t wait_lock; /* protects the wait_list */
105 uint32_t vblank_mask; /* irq bits set for userspace vblank */ 92 struct list_head wait_list; /* list of omap_irq_wait */
106 struct omap_drm_irq error_handler; 93 uint32_t irq_mask; /* enabled irqs in addition to wait_list */
107 94
108 /* atomic commit */ 95 /* atomic commit */
109 struct { 96 struct {
@@ -128,10 +115,6 @@ int omap_gem_resume(struct device *dev);
128 115
129int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe); 116int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe);
130void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe); 117void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe);
131void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);
132void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
133void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);
134void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
135void omap_drm_irq_uninstall(struct drm_device *dev); 118void omap_drm_irq_uninstall(struct drm_device *dev);
136int omap_drm_irq_install(struct drm_device *dev); 119int omap_drm_irq_install(struct drm_device *dev);
137 120
@@ -155,6 +138,8 @@ void omap_crtc_pre_uninit(void);
155struct drm_crtc *omap_crtc_init(struct drm_device *dev, 138struct drm_crtc *omap_crtc_init(struct drm_device *dev,
156 struct drm_plane *plane, enum omap_channel channel, int id); 139 struct drm_plane *plane, enum omap_channel channel, int id);
157int omap_crtc_wait_pending(struct drm_crtc *crtc); 140int omap_crtc_wait_pending(struct drm_crtc *crtc);
141void omap_crtc_error_irq(struct drm_crtc *crtc, uint32_t irqstatus);
142void omap_crtc_vblank_irq(struct drm_crtc *crtc);
158 143
159struct drm_plane *omap_plane_init(struct drm_device *dev, 144struct drm_plane *omap_plane_init(struct drm_device *dev,
160 int id, enum drm_plane_type type, 145 int id, enum drm_plane_type type,
@@ -233,32 +218,6 @@ struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev,
233 struct dma_buf *buffer); 218 struct dma_buf *buffer);
234 219
235/* map crtc to vblank mask */ 220/* map crtc to vblank mask */
236uint32_t pipe2vbl(struct drm_crtc *crtc);
237struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder); 221struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder);
238 222
239/* should these be made into common util helpers?
240 */
241
242static inline int objects_lookup(
243 struct drm_file *filp, uint32_t pixel_format,
244 struct drm_gem_object **bos, const uint32_t *handles)
245{
246 int i, n = drm_format_num_planes(pixel_format);
247
248 for (i = 0; i < n; i++) {
249 bos[i] = drm_gem_object_lookup(filp, handles[i]);
250 if (!bos[i])
251 goto fail;
252
253 }
254
255 return 0;
256
257fail:
258 while (--i > 0)
259 drm_gem_object_unreference_unlocked(bos[i]);
260
261 return -ENOENT;
262}
263
264#endif /* __OMAP_DRV_H__ */ 223#endif /* __OMAP_DRV_H__ */
diff --git a/drivers/gpu/drm/omapdrm/omap_encoder.c b/drivers/gpu/drm/omapdrm/omap_encoder.c
index a20f30039aee..86c977b7189a 100644
--- a/drivers/gpu/drm/omapdrm/omap_encoder.c
+++ b/drivers/gpu/drm/omapdrm/omap_encoder.c
@@ -117,7 +117,7 @@ static int omap_encoder_update(struct drm_encoder *encoder,
117 117
118 dssdrv->get_timings(dssdev, &t); 118 dssdrv->get_timings(dssdev, &t);
119 119
120 if (memcmp(vm, &t, sizeof(struct videomode))) 120 if (memcmp(vm, &t, sizeof(*vm)))
121 ret = -EINVAL; 121 ret = -EINVAL;
122 else 122 else
123 ret = 0; 123 ret = 0;
diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c
index bd6b94c38613..29dc677dd4d3 100644
--- a/drivers/gpu/drm/omapdrm/omap_fb.c
+++ b/drivers/gpu/drm/omapdrm/omap_fb.c
@@ -29,37 +29,30 @@
29 * framebuffer funcs 29 * framebuffer funcs
30 */ 30 */
31 31
32/* per-format info: */ 32/* DSS to DRM formats mapping */
33struct format { 33static const struct {
34 enum omap_color_mode dss_format; 34 enum omap_color_mode dss_format;
35 uint32_t pixel_format; 35 uint32_t pixel_format;
36 struct { 36} formats[] = {
37 int stride_bpp; /* this times width is stride */
38 int sub_y; /* sub-sample in y dimension */
39 } planes[4];
40 bool yuv;
41};
42
43static const struct format formats[] = {
44 /* 16bpp [A]RGB: */ 37 /* 16bpp [A]RGB: */
45 { OMAP_DSS_COLOR_RGB16, DRM_FORMAT_RGB565, {{2, 1}}, false }, /* RGB16-565 */ 38 { OMAP_DSS_COLOR_RGB16, DRM_FORMAT_RGB565 }, /* RGB16-565 */
46 { OMAP_DSS_COLOR_RGB12U, DRM_FORMAT_RGBX4444, {{2, 1}}, false }, /* RGB12x-4444 */ 39 { OMAP_DSS_COLOR_RGB12U, DRM_FORMAT_RGBX4444 }, /* RGB12x-4444 */
47 { OMAP_DSS_COLOR_RGBX16, DRM_FORMAT_XRGB4444, {{2, 1}}, false }, /* xRGB12-4444 */ 40 { OMAP_DSS_COLOR_RGBX16, DRM_FORMAT_XRGB4444 }, /* xRGB12-4444 */
48 { OMAP_DSS_COLOR_RGBA16, DRM_FORMAT_RGBA4444, {{2, 1}}, false }, /* RGBA12-4444 */ 41 { OMAP_DSS_COLOR_RGBA16, DRM_FORMAT_RGBA4444 }, /* RGBA12-4444 */
49 { OMAP_DSS_COLOR_ARGB16, DRM_FORMAT_ARGB4444, {{2, 1}}, false }, /* ARGB16-4444 */ 42 { OMAP_DSS_COLOR_ARGB16, DRM_FORMAT_ARGB4444 }, /* ARGB16-4444 */
50 { OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555, {{2, 1}}, false }, /* xRGB15-1555 */ 43 { OMAP_DSS_COLOR_XRGB16_1555, DRM_FORMAT_XRGB1555 }, /* xRGB15-1555 */
51 { OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555, {{2, 1}}, false }, /* ARGB16-1555 */ 44 { OMAP_DSS_COLOR_ARGB16_1555, DRM_FORMAT_ARGB1555 }, /* ARGB16-1555 */
52 /* 24bpp RGB: */ 45 /* 24bpp RGB: */
53 { OMAP_DSS_COLOR_RGB24P, DRM_FORMAT_RGB888, {{3, 1}}, false }, /* RGB24-888 */ 46 { OMAP_DSS_COLOR_RGB24P, DRM_FORMAT_RGB888 }, /* RGB24-888 */
54 /* 32bpp [A]RGB: */ 47 /* 32bpp [A]RGB: */
55 { OMAP_DSS_COLOR_RGBX32, DRM_FORMAT_RGBX8888, {{4, 1}}, false }, /* RGBx24-8888 */ 48 { OMAP_DSS_COLOR_RGBX32, DRM_FORMAT_RGBX8888 }, /* RGBx24-8888 */
56 { OMAP_DSS_COLOR_RGB24U, DRM_FORMAT_XRGB8888, {{4, 1}}, false }, /* xRGB24-8888 */ 49 { OMAP_DSS_COLOR_RGB24U, DRM_FORMAT_XRGB8888 }, /* xRGB24-8888 */
57 { OMAP_DSS_COLOR_RGBA32, DRM_FORMAT_RGBA8888, {{4, 1}}, false }, /* RGBA32-8888 */ 50 { OMAP_DSS_COLOR_RGBA32, DRM_FORMAT_RGBA8888 }, /* RGBA32-8888 */
58 { OMAP_DSS_COLOR_ARGB32, DRM_FORMAT_ARGB8888, {{4, 1}}, false }, /* ARGB32-8888 */ 51 { OMAP_DSS_COLOR_ARGB32, DRM_FORMAT_ARGB8888 }, /* ARGB32-8888 */
59 /* YUV: */ 52 /* YUV: */
60 { OMAP_DSS_COLOR_NV12, DRM_FORMAT_NV12, {{1, 1}, {1, 2}}, true }, 53 { OMAP_DSS_COLOR_NV12, DRM_FORMAT_NV12 },
61 { OMAP_DSS_COLOR_YUV2, DRM_FORMAT_YUYV, {{2, 1}}, true }, 54 { OMAP_DSS_COLOR_YUV2, DRM_FORMAT_YUYV },
62 { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY, {{2, 1}}, true }, 55 { OMAP_DSS_COLOR_UYVY, DRM_FORMAT_UYVY },
63}; 56};
64 57
65/* convert from overlay's pixel formats bitmask to an array of fourcc's */ 58/* convert from overlay's pixel formats bitmask to an array of fourcc's */
@@ -89,8 +82,9 @@ struct plane {
89struct omap_framebuffer { 82struct omap_framebuffer {
90 struct drm_framebuffer base; 83 struct drm_framebuffer base;
91 int pin_count; 84 int pin_count;
92 const struct format *format; 85 const struct drm_format_info *format;
93 struct plane planes[4]; 86 enum omap_color_mode dss_format;
87 struct plane planes[2];
94 /* lock for pinning (pin_count and planes.paddr) */ 88 /* lock for pinning (pin_count and planes.paddr) */
95 struct mutex lock; 89 struct mutex lock;
96}; 90};
@@ -128,13 +122,13 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = {
128}; 122};
129 123
130static uint32_t get_linear_addr(struct plane *plane, 124static uint32_t get_linear_addr(struct plane *plane,
131 const struct format *format, int n, int x, int y) 125 const struct drm_format_info *format, int n, int x, int y)
132{ 126{
133 uint32_t offset; 127 uint32_t offset;
134 128
135 offset = plane->offset + 129 offset = plane->offset
136 (x * format->planes[n].stride_bpp) + 130 + (x * format->cpp[n] / (n == 0 ? 1 : format->hsub))
137 (y * plane->pitch / format->planes[n].sub_y); 131 + (y * plane->pitch / (n == 0 ? 1 : format->vsub));
138 132
139 return plane->paddr + offset; 133 return plane->paddr + offset;
140} 134}
@@ -153,11 +147,11 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
153 struct omap_drm_window *win, struct omap_overlay_info *info) 147 struct omap_drm_window *win, struct omap_overlay_info *info)
154{ 148{
155 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); 149 struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb);
156 const struct format *format = omap_fb->format; 150 const struct drm_format_info *format = omap_fb->format;
157 struct plane *plane = &omap_fb->planes[0]; 151 struct plane *plane = &omap_fb->planes[0];
158 uint32_t x, y, orient = 0; 152 uint32_t x, y, orient = 0;
159 153
160 info->color_mode = format->dss_format; 154 info->color_mode = omap_fb->dss_format;
161 155
162 info->pos_x = win->crtc_x; 156 info->pos_x = win->crtc_x;
163 info->pos_y = win->crtc_y; 157 info->pos_y = win->crtc_y;
@@ -231,9 +225,9 @@ void omap_framebuffer_update_scanout(struct drm_framebuffer *fb,
231 } 225 }
232 226
233 /* convert to pixels: */ 227 /* convert to pixels: */
234 info->screen_width /= format->planes[0].stride_bpp; 228 info->screen_width /= format->cpp[0];
235 229
236 if (format->dss_format == OMAP_DSS_COLOR_NV12) { 230 if (omap_fb->dss_format == OMAP_DSS_COLOR_NV12) {
237 plane = &omap_fb->planes[1]; 231 plane = &omap_fb->planes[1];
238 232
239 if (info->rotation_type == OMAP_DSS_ROT_TILER) { 233 if (info->rotation_type == OMAP_DSS_ROT_TILER) {
@@ -360,47 +354,58 @@ void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m)
360struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, 354struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev,
361 struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) 355 struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd)
362{ 356{
357 unsigned int num_planes = drm_format_num_planes(mode_cmd->pixel_format);
363 struct drm_gem_object *bos[4]; 358 struct drm_gem_object *bos[4];
364 struct drm_framebuffer *fb; 359 struct drm_framebuffer *fb;
365 int ret; 360 int i;
366 361
367 ret = objects_lookup(file, mode_cmd->pixel_format, 362 for (i = 0; i < num_planes; i++) {
368 bos, mode_cmd->handles); 363 bos[i] = drm_gem_object_lookup(file, mode_cmd->handles[i]);
369 if (ret) 364 if (!bos[i]) {
370 return ERR_PTR(ret); 365 fb = ERR_PTR(-ENOENT);
366 goto error;
367 }
368 }
371 369
372 fb = omap_framebuffer_init(dev, mode_cmd, bos); 370 fb = omap_framebuffer_init(dev, mode_cmd, bos);
373 if (IS_ERR(fb)) { 371 if (IS_ERR(fb))
374 int i, n = drm_format_num_planes(mode_cmd->pixel_format); 372 goto error;
375 for (i = 0; i < n; i++) 373
376 drm_gem_object_unreference_unlocked(bos[i]); 374 return fb;
377 return fb; 375
378 } 376error:
377 while (--i > 0)
378 drm_gem_object_unreference_unlocked(bos[i]);
379
379 return fb; 380 return fb;
380} 381}
381 382
382struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, 383struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
383 const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) 384 const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos)
384{ 385{
386 const struct drm_format_info *format = NULL;
385 struct omap_framebuffer *omap_fb = NULL; 387 struct omap_framebuffer *omap_fb = NULL;
386 struct drm_framebuffer *fb = NULL; 388 struct drm_framebuffer *fb = NULL;
387 const struct format *format = NULL; 389 enum omap_color_mode dss_format = 0;
388 int ret, i, n = drm_format_num_planes(mode_cmd->pixel_format); 390 unsigned int pitch = mode_cmd->pitches[0];
391 int ret, i;
389 392
390 DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)", 393 DBG("create framebuffer: dev=%p, mode_cmd=%p (%dx%d@%4.4s)",
391 dev, mode_cmd, mode_cmd->width, mode_cmd->height, 394 dev, mode_cmd, mode_cmd->width, mode_cmd->height,
392 (char *)&mode_cmd->pixel_format); 395 (char *)&mode_cmd->pixel_format);
393 396
397 format = drm_format_info(mode_cmd->pixel_format);
398
394 for (i = 0; i < ARRAY_SIZE(formats); i++) { 399 for (i = 0; i < ARRAY_SIZE(formats); i++) {
395 if (formats[i].pixel_format == mode_cmd->pixel_format) { 400 if (formats[i].pixel_format == mode_cmd->pixel_format) {
396 format = &formats[i]; 401 dss_format = formats[i].dss_format;
397 break; 402 break;
398 } 403 }
399 } 404 }
400 405
401 if (!format) { 406 if (!format || !dss_format) {
402 dev_err(dev->dev, "unsupported pixel format: %4.4s\n", 407 dev_dbg(dev->dev, "unsupported pixel format: %4.4s\n",
403 (char *)&mode_cmd->pixel_format); 408 (char *)&mode_cmd->pixel_format);
404 ret = -EINVAL; 409 ret = -EINVAL;
405 goto fail; 410 goto fail;
406 } 411 }
@@ -413,40 +418,39 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
413 418
414 fb = &omap_fb->base; 419 fb = &omap_fb->base;
415 omap_fb->format = format; 420 omap_fb->format = format;
421 omap_fb->dss_format = dss_format;
416 mutex_init(&omap_fb->lock); 422 mutex_init(&omap_fb->lock);
417 423
418 for (i = 0; i < n; i++) { 424 /*
419 struct plane *plane = &omap_fb->planes[i]; 425 * The code below assumes that no format use more than two planes, and
420 int size, pitch = mode_cmd->pitches[i]; 426 * that the two planes of multiplane formats need the same number of
421 427 * bytes per pixel.
422 if (pitch < (mode_cmd->width * format->planes[i].stride_bpp)) { 428 */
423 dev_err(dev->dev, "provided buffer pitch is too small! %d < %d\n", 429 if (format->num_planes == 2 && pitch != mode_cmd->pitches[1]) {
424 pitch, mode_cmd->width * format->planes[i].stride_bpp); 430 dev_dbg(dev->dev, "pitches differ between planes 0 and 1\n");
425 ret = -EINVAL; 431 ret = -EINVAL;
426 goto fail; 432 goto fail;
427 } 433 }
428 434
429 if (pitch % format->planes[i].stride_bpp != 0) { 435 if (pitch % format->cpp[0]) {
430 dev_err(dev->dev, 436 dev_dbg(dev->dev,
431 "buffer pitch (%d bytes) is not a multiple of pixel size (%d bytes)\n", 437 "buffer pitch (%u bytes) is not a multiple of pixel size (%u bytes)\n",
432 pitch, format->planes[i].stride_bpp); 438 pitch, format->cpp[0]);
433 ret = -EINVAL; 439 ret = -EINVAL;
434 goto fail; 440 goto fail;
435 } 441 }
436 442
437 size = pitch * mode_cmd->height / format->planes[i].sub_y; 443 for (i = 0; i < format->num_planes; i++) {
444 struct plane *plane = &omap_fb->planes[i];
445 unsigned int vsub = i == 0 ? 1 : format->vsub;
446 unsigned int size;
438 447
439 if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) { 448 size = pitch * mode_cmd->height / vsub;
440 dev_err(dev->dev, "provided buffer object is too small! %d < %d\n",
441 bos[i]->size - mode_cmd->offsets[i], size);
442 ret = -EINVAL;
443 goto fail;
444 }
445 449
446 if (i > 0 && pitch != mode_cmd->pitches[i - 1]) { 450 if (size > omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i]) {
447 dev_err(dev->dev, 451 dev_dbg(dev->dev,
448 "pitches are not the same between framebuffer planes %d != %d\n", 452 "provided buffer object is too small! %d < %d\n",
449 pitch, mode_cmd->pitches[i - 1]); 453 bos[i]->size - mode_cmd->offsets[i], size);
450 ret = -EINVAL; 454 ret = -EINVAL;
451 goto fail; 455 goto fail;
452 } 456 }
diff --git a/drivers/gpu/drm/omapdrm/omap_irq.c b/drivers/gpu/drm/omapdrm/omap_irq.c
index 60e1e8016708..9adfa7c99695 100644
--- a/drivers/gpu/drm/omapdrm/omap_irq.c
+++ b/drivers/gpu/drm/omapdrm/omap_irq.c
@@ -19,25 +19,24 @@
19 19
20#include "omap_drv.h" 20#include "omap_drv.h"
21 21
22static DEFINE_SPINLOCK(list_lock); 22struct omap_irq_wait {
23 23 struct list_head node;
24static void omap_irq_error_handler(struct omap_drm_irq *irq, 24 wait_queue_head_t wq;
25 uint32_t irqstatus) 25 uint32_t irqmask;
26{ 26 int count;
27 DRM_ERROR("errors: %08x\n", irqstatus); 27};
28}
29 28
30/* call with list_lock and dispc runtime held */ 29/* call with wait_lock and dispc runtime held */
31static void omap_irq_update(struct drm_device *dev) 30static void omap_irq_update(struct drm_device *dev)
32{ 31{
33 struct omap_drm_private *priv = dev->dev_private; 32 struct omap_drm_private *priv = dev->dev_private;
34 struct omap_drm_irq *irq; 33 struct omap_irq_wait *wait;
35 uint32_t irqmask = priv->vblank_mask; 34 uint32_t irqmask = priv->irq_mask;
36 35
37 assert_spin_locked(&list_lock); 36 assert_spin_locked(&priv->wait_lock);
38 37
39 list_for_each_entry(irq, &priv->irq_list, node) 38 list_for_each_entry(wait, &priv->wait_list, node)
40 irqmask |= irq->irqmask; 39 irqmask |= wait->irqmask;
41 40
42 DBG("irqmask=%08x", irqmask); 41 DBG("irqmask=%08x", irqmask);
43 42
@@ -45,90 +44,48 @@ static void omap_irq_update(struct drm_device *dev)
45 dispc_read_irqenable(); /* flush posted write */ 44 dispc_read_irqenable(); /* flush posted write */
46} 45}
47 46
48void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq) 47static void omap_irq_wait_handler(struct omap_irq_wait *wait)
49{
50 struct omap_drm_private *priv = dev->dev_private;
51 unsigned long flags;
52
53 spin_lock_irqsave(&list_lock, flags);
54
55 if (!WARN_ON(irq->registered)) {
56 irq->registered = true;
57 list_add(&irq->node, &priv->irq_list);
58 omap_irq_update(dev);
59 }
60
61 spin_unlock_irqrestore(&list_lock, flags);
62}
63
64void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
65{
66 dispc_runtime_get();
67
68 __omap_irq_register(dev, irq);
69
70 dispc_runtime_put();
71}
72
73void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
74{ 48{
75 unsigned long flags;
76
77 spin_lock_irqsave(&list_lock, flags);
78
79 if (!WARN_ON(!irq->registered)) {
80 irq->registered = false;
81 list_del(&irq->node);
82 omap_irq_update(dev);
83 }
84
85 spin_unlock_irqrestore(&list_lock, flags);
86}
87
88void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
89{
90 dispc_runtime_get();
91
92 __omap_irq_unregister(dev, irq);
93
94 dispc_runtime_put();
95}
96
97struct omap_irq_wait {
98 struct omap_drm_irq irq;
99 int count;
100};
101
102static DECLARE_WAIT_QUEUE_HEAD(wait_event);
103
104static void wait_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
105{
106 struct omap_irq_wait *wait =
107 container_of(irq, struct omap_irq_wait, irq);
108 wait->count--; 49 wait->count--;
109 wake_up_all(&wait_event); 50 wake_up(&wait->wq);
110} 51}
111 52
112struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev, 53struct omap_irq_wait * omap_irq_wait_init(struct drm_device *dev,
113 uint32_t irqmask, int count) 54 uint32_t irqmask, int count)
114{ 55{
56 struct omap_drm_private *priv = dev->dev_private;
115 struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL); 57 struct omap_irq_wait *wait = kzalloc(sizeof(*wait), GFP_KERNEL);
116 wait->irq.irq = wait_irq; 58 unsigned long flags;
117 wait->irq.irqmask = irqmask; 59
60 init_waitqueue_head(&wait->wq);
61 wait->irqmask = irqmask;
118 wait->count = count; 62 wait->count = count;
119 omap_irq_register(dev, &wait->irq); 63
64 spin_lock_irqsave(&priv->wait_lock, flags);
65 list_add(&wait->node, &priv->wait_list);
66 omap_irq_update(dev);
67 spin_unlock_irqrestore(&priv->wait_lock, flags);
68
120 return wait; 69 return wait;
121} 70}
122 71
123int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait, 72int omap_irq_wait(struct drm_device *dev, struct omap_irq_wait *wait,
124 unsigned long timeout) 73 unsigned long timeout)
125{ 74{
126 int ret = wait_event_timeout(wait_event, (wait->count <= 0), timeout); 75 struct omap_drm_private *priv = dev->dev_private;
127 omap_irq_unregister(dev, &wait->irq); 76 unsigned long flags;
77 int ret;
78
79 ret = wait_event_timeout(wait->wq, (wait->count <= 0), timeout);
80
81 spin_lock_irqsave(&priv->wait_lock, flags);
82 list_del(&wait->node);
83 omap_irq_update(dev);
84 spin_unlock_irqrestore(&priv->wait_lock, flags);
85
128 kfree(wait); 86 kfree(wait);
129 if (ret == 0) 87
130 return -1; 88 return ret == 0 ? -1 : 0;
131 return 0;
132} 89}
133 90
134/** 91/**
@@ -152,10 +109,10 @@ int omap_irq_enable_vblank(struct drm_device *dev, unsigned int pipe)
152 109
153 DBG("dev=%p, crtc=%u", dev, pipe); 110 DBG("dev=%p, crtc=%u", dev, pipe);
154 111
155 spin_lock_irqsave(&list_lock, flags); 112 spin_lock_irqsave(&priv->wait_lock, flags);
156 priv->vblank_mask |= pipe2vbl(crtc); 113 priv->irq_mask |= dispc_mgr_get_vsync_irq(omap_crtc_channel(crtc));
157 omap_irq_update(dev); 114 omap_irq_update(dev);
158 spin_unlock_irqrestore(&list_lock, flags); 115 spin_unlock_irqrestore(&priv->wait_lock, flags);
159 116
160 return 0; 117 return 0;
161} 118}
@@ -177,17 +134,66 @@ void omap_irq_disable_vblank(struct drm_device *dev, unsigned int pipe)
177 134
178 DBG("dev=%p, crtc=%u", dev, pipe); 135 DBG("dev=%p, crtc=%u", dev, pipe);
179 136
180 spin_lock_irqsave(&list_lock, flags); 137 spin_lock_irqsave(&priv->wait_lock, flags);
181 priv->vblank_mask &= ~pipe2vbl(crtc); 138 priv->irq_mask &= ~dispc_mgr_get_vsync_irq(omap_crtc_channel(crtc));
182 omap_irq_update(dev); 139 omap_irq_update(dev);
183 spin_unlock_irqrestore(&list_lock, flags); 140 spin_unlock_irqrestore(&priv->wait_lock, flags);
141}
142
143static void omap_irq_fifo_underflow(struct omap_drm_private *priv,
144 u32 irqstatus)
145{
146 static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL,
147 DEFAULT_RATELIMIT_BURST);
148 static const struct {
149 const char *name;
150 u32 mask;
151 } sources[] = {
152 { "gfx", DISPC_IRQ_GFX_FIFO_UNDERFLOW },
153 { "vid1", DISPC_IRQ_VID1_FIFO_UNDERFLOW },
154 { "vid2", DISPC_IRQ_VID2_FIFO_UNDERFLOW },
155 { "vid3", DISPC_IRQ_VID3_FIFO_UNDERFLOW },
156 };
157
158 const u32 mask = DISPC_IRQ_GFX_FIFO_UNDERFLOW
159 | DISPC_IRQ_VID1_FIFO_UNDERFLOW
160 | DISPC_IRQ_VID2_FIFO_UNDERFLOW
161 | DISPC_IRQ_VID3_FIFO_UNDERFLOW;
162 unsigned int i;
163
164 spin_lock(&priv->wait_lock);
165 irqstatus &= priv->irq_mask & mask;
166 spin_unlock(&priv->wait_lock);
167
168 if (!irqstatus)
169 return;
170
171 if (!__ratelimit(&_rs))
172 return;
173
174 DRM_ERROR("FIFO underflow on ");
175
176 for (i = 0; i < ARRAY_SIZE(sources); ++i) {
177 if (sources[i].mask & irqstatus)
178 pr_cont("%s ", sources[i].name);
179 }
180
181 pr_cont("(0x%08x)\n", irqstatus);
182}
183
184static void omap_irq_ocp_error_handler(u32 irqstatus)
185{
186 if (!(irqstatus & DISPC_IRQ_OCP_ERR))
187 return;
188
189 DRM_ERROR("OCP error\n");
184} 190}
185 191
186static irqreturn_t omap_irq_handler(int irq, void *arg) 192static irqreturn_t omap_irq_handler(int irq, void *arg)
187{ 193{
188 struct drm_device *dev = (struct drm_device *) arg; 194 struct drm_device *dev = (struct drm_device *) arg;
189 struct omap_drm_private *priv = dev->dev_private; 195 struct omap_drm_private *priv = dev->dev_private;
190 struct omap_drm_irq *handler, *n; 196 struct omap_irq_wait *wait, *n;
191 unsigned long flags; 197 unsigned long flags;
192 unsigned int id; 198 unsigned int id;
193 u32 irqstatus; 199 u32 irqstatus;
@@ -200,24 +206,37 @@ static irqreturn_t omap_irq_handler(int irq, void *arg)
200 206
201 for (id = 0; id < priv->num_crtcs; id++) { 207 for (id = 0; id < priv->num_crtcs; id++) {
202 struct drm_crtc *crtc = priv->crtcs[id]; 208 struct drm_crtc *crtc = priv->crtcs[id];
209 enum omap_channel channel = omap_crtc_channel(crtc);
203 210
204 if (irqstatus & pipe2vbl(crtc)) 211 if (irqstatus & dispc_mgr_get_vsync_irq(channel)) {
205 drm_handle_vblank(dev, id); 212 drm_handle_vblank(dev, id);
213 omap_crtc_vblank_irq(crtc);
214 }
215
216 if (irqstatus & dispc_mgr_get_sync_lost_irq(channel))
217 omap_crtc_error_irq(crtc, irqstatus);
206 } 218 }
207 219
208 spin_lock_irqsave(&list_lock, flags); 220 omap_irq_ocp_error_handler(irqstatus);
209 list_for_each_entry_safe(handler, n, &priv->irq_list, node) { 221 omap_irq_fifo_underflow(priv, irqstatus);
210 if (handler->irqmask & irqstatus) { 222
211 spin_unlock_irqrestore(&list_lock, flags); 223 spin_lock_irqsave(&priv->wait_lock, flags);
212 handler->irq(handler, handler->irqmask & irqstatus); 224 list_for_each_entry_safe(wait, n, &priv->wait_list, node) {
213 spin_lock_irqsave(&list_lock, flags); 225 if (wait->irqmask & irqstatus)
214 } 226 omap_irq_wait_handler(wait);
215 } 227 }
216 spin_unlock_irqrestore(&list_lock, flags); 228 spin_unlock_irqrestore(&priv->wait_lock, flags);
217 229
218 return IRQ_HANDLED; 230 return IRQ_HANDLED;
219} 231}
220 232
233static const u32 omap_underflow_irqs[] = {
234 [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
235 [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
236 [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
237 [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
238};
239
221/* 240/*
222 * We need a special version, instead of just using drm_irq_install(), 241 * We need a special version, instead of just using drm_irq_install(),
223 * because we need to register the irq via omapdss. Once omapdss and 242 * because we need to register the irq via omapdss. Once omapdss and
@@ -228,10 +247,25 @@ static irqreturn_t omap_irq_handler(int irq, void *arg)
228int omap_drm_irq_install(struct drm_device *dev) 247int omap_drm_irq_install(struct drm_device *dev)
229{ 248{
230 struct omap_drm_private *priv = dev->dev_private; 249 struct omap_drm_private *priv = dev->dev_private;
231 struct omap_drm_irq *error_handler = &priv->error_handler; 250 unsigned int num_mgrs = dss_feat_get_num_mgrs();
251 unsigned int max_planes;
252 unsigned int i;
232 int ret; 253 int ret;
233 254
234 INIT_LIST_HEAD(&priv->irq_list); 255 spin_lock_init(&priv->wait_lock);
256 INIT_LIST_HEAD(&priv->wait_list);
257
258 priv->irq_mask = DISPC_IRQ_OCP_ERR;
259
260 max_planes = min(ARRAY_SIZE(priv->planes),
261 ARRAY_SIZE(omap_underflow_irqs));
262 for (i = 0; i < max_planes; ++i) {
263 if (priv->planes[i])
264 priv->irq_mask |= omap_underflow_irqs[i];
265 }
266
267 for (i = 0; i < num_mgrs; ++i)
268 priv->irq_mask |= dispc_mgr_get_sync_lost_irq(i);
235 269
236 dispc_runtime_get(); 270 dispc_runtime_get();
237 dispc_clear_irqstatus(0xffffffff); 271 dispc_clear_irqstatus(0xffffffff);
@@ -241,16 +275,6 @@ int omap_drm_irq_install(struct drm_device *dev)
241 if (ret < 0) 275 if (ret < 0)
242 return ret; 276 return ret;
243 277
244 error_handler->irq = omap_irq_error_handler;
245 error_handler->irqmask = DISPC_IRQ_OCP_ERR;
246
247 /* for now ignore DISPC_IRQ_SYNC_LOST_DIGIT.. really I think
248 * we just need to ignore it while enabling tv-out
249 */
250 error_handler->irqmask &= ~DISPC_IRQ_SYNC_LOST_DIGIT;
251
252 omap_irq_register(dev, error_handler);
253
254 dev->irq_enabled = true; 278 dev->irq_enabled = true;
255 279
256 return 0; 280 return 0;
diff --git a/drivers/gpu/drm/omapdrm/omap_plane.c b/drivers/gpu/drm/omapdrm/omap_plane.c
index 82b2c23d6769..386d90af70f7 100644
--- a/drivers/gpu/drm/omapdrm/omap_plane.c
+++ b/drivers/gpu/drm/omapdrm/omap_plane.c
@@ -43,8 +43,6 @@ struct omap_plane {
43 43
44 uint32_t nformats; 44 uint32_t nformats;
45 uint32_t formats[32]; 45 uint32_t formats[32];
46
47 struct omap_drm_irq error_irq;
48}; 46};
49 47
50struct omap_plane_state { 48struct omap_plane_state {
@@ -204,8 +202,6 @@ static void omap_plane_destroy(struct drm_plane *plane)
204 202
205 DBG("%s", omap_plane->name); 203 DBG("%s", omap_plane->name);
206 204
207 omap_irq_unregister(plane->dev, &omap_plane->error_irq);
208
209 drm_plane_cleanup(plane); 205 drm_plane_cleanup(plane);
210 206
211 kfree(omap_plane); 207 kfree(omap_plane);
@@ -332,14 +328,6 @@ static const struct drm_plane_funcs omap_plane_funcs = {
332 .atomic_get_property = omap_plane_atomic_get_property, 328 .atomic_get_property = omap_plane_atomic_get_property,
333}; 329};
334 330
335static void omap_plane_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
336{
337 struct omap_plane *omap_plane =
338 container_of(irq, struct omap_plane, error_irq);
339 DRM_ERROR_RATELIMITED("%s: errors: %08x\n", omap_plane->name,
340 irqstatus);
341}
342
343static const char *plane_names[] = { 331static const char *plane_names[] = {
344 [OMAP_DSS_GFX] = "gfx", 332 [OMAP_DSS_GFX] = "gfx",
345 [OMAP_DSS_VIDEO1] = "vid1", 333 [OMAP_DSS_VIDEO1] = "vid1",
@@ -347,13 +335,6 @@ static const char *plane_names[] = {
347 [OMAP_DSS_VIDEO3] = "vid3", 335 [OMAP_DSS_VIDEO3] = "vid3",
348}; 336};
349 337
350static const uint32_t error_irqs[] = {
351 [OMAP_DSS_GFX] = DISPC_IRQ_GFX_FIFO_UNDERFLOW,
352 [OMAP_DSS_VIDEO1] = DISPC_IRQ_VID1_FIFO_UNDERFLOW,
353 [OMAP_DSS_VIDEO2] = DISPC_IRQ_VID2_FIFO_UNDERFLOW,
354 [OMAP_DSS_VIDEO3] = DISPC_IRQ_VID3_FIFO_UNDERFLOW,
355};
356
357/* initialize plane */ 338/* initialize plane */
358struct drm_plane *omap_plane_init(struct drm_device *dev, 339struct drm_plane *omap_plane_init(struct drm_device *dev,
359 int id, enum drm_plane_type type, 340 int id, enum drm_plane_type type,
@@ -377,10 +358,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
377 358
378 plane = &omap_plane->base; 359 plane = &omap_plane->base;
379 360
380 omap_plane->error_irq.irqmask = error_irqs[id];
381 omap_plane->error_irq.irq = omap_plane_error_irq;
382 omap_irq_register(dev, &omap_plane->error_irq);
383
384 ret = drm_universal_plane_init(dev, plane, possible_crtcs, 361 ret = drm_universal_plane_init(dev, plane, possible_crtcs,
385 &omap_plane_funcs, omap_plane->formats, 362 &omap_plane_funcs, omap_plane->formats,
386 omap_plane->nformats, type, NULL); 363 omap_plane->nformats, type, NULL);
@@ -394,7 +371,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev,
394 return plane; 371 return plane;
395 372
396error: 373error:
397 omap_irq_unregister(plane->dev, &omap_plane->error_irq);
398 kfree(omap_plane); 374 kfree(omap_plane);
399 return NULL; 375 return NULL;
400} 376}
diff --git a/include/uapi/drm/Kbuild b/include/uapi/drm/Kbuild
index 9355dd8eff3b..c97addd08f8c 100644
--- a/include/uapi/drm/Kbuild
+++ b/include/uapi/drm/Kbuild
@@ -9,6 +9,7 @@ header-y += i810_drm.h
9header-y += i915_drm.h 9header-y += i915_drm.h
10header-y += mga_drm.h 10header-y += mga_drm.h
11header-y += nouveau_drm.h 11header-y += nouveau_drm.h
12header-y += omap_drm.h
12header-y += qxl_drm.h 13header-y += qxl_drm.h
13header-y += r128_drm.h 14header-y += r128_drm.h
14header-y += radeon_drm.h 15header-y += radeon_drm.h