diff options
author | Dave Airlie <airlied@redhat.com> | 2016-03-07 19:49:58 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2016-03-07 19:49:58 -0500 |
commit | d8c61663c7a8e5041f5c2a4b142f24d0d7861ad6 (patch) | |
tree | 7951d4e7b86b4c390e0883c847b1f2e32bb51a2f | |
parent | a90cc3f25065e5e8d5e336c75b04d5882912871f (diff) | |
parent | d0ec32caef0baa490b419895ef61c8481d49f7cd (diff) |
Merge tag 'tilcdc-4.6' of https://github.com/jsarha/linux into drm-next
tilcdc changes for v4.6
Accumulated fixes and improvements from ti-linux-4.1.
* Almost complete rewrite of pagefliping code
* dma-buf support
* pinctrl support
* lot of fixes and cleanups
* tag 'tilcdc-4.6' of https://github.com/jsarha/linux: (22 commits)
drm/tilcdc: Use devm_kzalloc() and devm_kcalloc() for private data
drm/tilcdc: Initialize crtc->port
drm/tilcdc: Disable sync lost interrupt if it fires on every frame
drm/tilcdc: Add prints on sync lost and FIFO underrun interrupts
drm/tilcdc: Remove the duplicate LCDC_INT_ENABLE_SET_REG in registers[]
drm/tilcdc: Fix interrupt enable/disable code for version 2 tilcdc
drm/tilcdc: Do not update the next frame buffer close to vertical blank
drm/tilcdc: Get rid of complex ping-pong mechanism
drm/tilcdc: cleanup irq handling
drm/tilcdc: remove broken error handling
drm/tilcdc: split reset to a separate function
drm/tilcdc: disable crtc on unload
drm/tilcdc: cleanup runtime PM handling
drm/tilcdc: Allocate register storage based on the actual number registers
drm/tilcdc: fix build error when !CONFIG_CPU_FREQ
drm/tilcdc: Implement dma-buf support for tilcdc
drm/tilcdc: disable the lcd controller/dma engine when suspend invoked
drm/tilcdc: make frame_done interrupt active at all times
drm/tilcdc: fix kernel panic on suspend when no hdmi monitor connected
drm/tilcdc: adopt pinctrl support
...
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_crtc.c | 313 | ||||
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_drv.c | 130 | ||||
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_drv.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_panel.c | 20 | ||||
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_tfp410.c | 24 |
5 files changed, 300 insertions, 192 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index 4802da8e6d6f..051e5e1b7ad6 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c | |||
@@ -21,25 +21,31 @@ | |||
21 | #include "tilcdc_drv.h" | 21 | #include "tilcdc_drv.h" |
22 | #include "tilcdc_regs.h" | 22 | #include "tilcdc_regs.h" |
23 | 23 | ||
24 | #define TILCDC_VBLANK_SAFETY_THRESHOLD_US 1000 | ||
25 | |||
24 | struct tilcdc_crtc { | 26 | struct tilcdc_crtc { |
25 | struct drm_crtc base; | 27 | struct drm_crtc base; |
26 | 28 | ||
27 | const struct tilcdc_panel_info *info; | 29 | const struct tilcdc_panel_info *info; |
28 | uint32_t dirty; | ||
29 | dma_addr_t start, end; | ||
30 | struct drm_pending_vblank_event *event; | 30 | struct drm_pending_vblank_event *event; |
31 | int dpms; | 31 | int dpms; |
32 | wait_queue_head_t frame_done_wq; | 32 | wait_queue_head_t frame_done_wq; |
33 | bool frame_done; | 33 | bool frame_done; |
34 | spinlock_t irq_lock; | ||
34 | 35 | ||
35 | /* fb currently set to scanout 0/1: */ | 36 | ktime_t last_vblank; |
36 | struct drm_framebuffer *scanout[2]; | 37 | |
38 | struct drm_framebuffer *curr_fb; | ||
39 | struct drm_framebuffer *next_fb; | ||
37 | 40 | ||
38 | /* for deferred fb unref's: */ | 41 | /* for deferred fb unref's: */ |
39 | struct drm_flip_work unref_work; | 42 | struct drm_flip_work unref_work; |
40 | 43 | ||
41 | /* Only set if an external encoder is connected */ | 44 | /* Only set if an external encoder is connected */ |
42 | bool simulate_vesa_sync; | 45 | bool simulate_vesa_sync; |
46 | |||
47 | int sync_lost_count; | ||
48 | bool frame_intact; | ||
43 | }; | 49 | }; |
44 | #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) | 50 | #define to_tilcdc_crtc(x) container_of(x, struct tilcdc_crtc, base) |
45 | 51 | ||
@@ -54,79 +60,53 @@ static void unref_worker(struct drm_flip_work *work, void *val) | |||
54 | mutex_unlock(&dev->mode_config.mutex); | 60 | mutex_unlock(&dev->mode_config.mutex); |
55 | } | 61 | } |
56 | 62 | ||
57 | static void set_scanout(struct drm_crtc *crtc, int n) | 63 | static void set_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) |
58 | { | 64 | { |
59 | static const uint32_t base_reg[] = { | ||
60 | LCDC_DMA_FB_BASE_ADDR_0_REG, | ||
61 | LCDC_DMA_FB_BASE_ADDR_1_REG, | ||
62 | }; | ||
63 | static const uint32_t ceil_reg[] = { | ||
64 | LCDC_DMA_FB_CEILING_ADDR_0_REG, | ||
65 | LCDC_DMA_FB_CEILING_ADDR_1_REG, | ||
66 | }; | ||
67 | static const uint32_t stat[] = { | ||
68 | LCDC_END_OF_FRAME0, LCDC_END_OF_FRAME1, | ||
69 | }; | ||
70 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 65 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
71 | struct drm_device *dev = crtc->dev; | 66 | struct drm_device *dev = crtc->dev; |
72 | struct tilcdc_drm_private *priv = dev->dev_private; | ||
73 | |||
74 | pm_runtime_get_sync(dev->dev); | ||
75 | tilcdc_write(dev, base_reg[n], tilcdc_crtc->start); | ||
76 | tilcdc_write(dev, ceil_reg[n], tilcdc_crtc->end); | ||
77 | if (tilcdc_crtc->scanout[n]) { | ||
78 | drm_flip_work_queue(&tilcdc_crtc->unref_work, tilcdc_crtc->scanout[n]); | ||
79 | drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq); | ||
80 | } | ||
81 | tilcdc_crtc->scanout[n] = crtc->primary->fb; | ||
82 | drm_framebuffer_reference(tilcdc_crtc->scanout[n]); | ||
83 | tilcdc_crtc->dirty &= ~stat[n]; | ||
84 | pm_runtime_put_sync(dev->dev); | ||
85 | } | ||
86 | |||
87 | static void update_scanout(struct drm_crtc *crtc) | ||
88 | { | ||
89 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | ||
90 | struct drm_device *dev = crtc->dev; | ||
91 | struct drm_framebuffer *fb = crtc->primary->fb; | ||
92 | struct drm_gem_cma_object *gem; | 67 | struct drm_gem_cma_object *gem; |
93 | unsigned int depth, bpp; | 68 | unsigned int depth, bpp; |
69 | dma_addr_t start, end; | ||
94 | 70 | ||
95 | drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); | 71 | drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); |
96 | gem = drm_fb_cma_get_gem_obj(fb, 0); | 72 | gem = drm_fb_cma_get_gem_obj(fb, 0); |
97 | 73 | ||
98 | tilcdc_crtc->start = gem->paddr + fb->offsets[0] + | 74 | start = gem->paddr + fb->offsets[0] + |
99 | (crtc->y * fb->pitches[0]) + (crtc->x * bpp/8); | 75 | crtc->y * fb->pitches[0] + |
76 | crtc->x * bpp / 8; | ||
100 | 77 | ||
101 | tilcdc_crtc->end = tilcdc_crtc->start + | 78 | end = start + (crtc->mode.vdisplay * fb->pitches[0]); |
102 | (crtc->mode.vdisplay * fb->pitches[0]); | ||
103 | 79 | ||
104 | if (tilcdc_crtc->dpms == DRM_MODE_DPMS_ON) { | 80 | tilcdc_write(dev, LCDC_DMA_FB_BASE_ADDR_0_REG, start); |
105 | /* already enabled, so just mark the frames that need | 81 | tilcdc_write(dev, LCDC_DMA_FB_CEILING_ADDR_0_REG, end); |
106 | * updating and they will be updated on vblank: | 82 | |
107 | */ | 83 | if (tilcdc_crtc->curr_fb) |
108 | tilcdc_crtc->dirty |= LCDC_END_OF_FRAME0 | LCDC_END_OF_FRAME1; | 84 | drm_flip_work_queue(&tilcdc_crtc->unref_work, |
109 | drm_vblank_get(dev, 0); | 85 | tilcdc_crtc->curr_fb); |
110 | } else { | 86 | |
111 | /* not enabled yet, so update registers immediately: */ | 87 | tilcdc_crtc->curr_fb = fb; |
112 | set_scanout(crtc, 0); | ||
113 | set_scanout(crtc, 1); | ||
114 | } | ||
115 | } | 88 | } |
116 | 89 | ||
117 | static void start(struct drm_crtc *crtc) | 90 | static void reset(struct drm_crtc *crtc) |
118 | { | 91 | { |
119 | struct drm_device *dev = crtc->dev; | 92 | struct drm_device *dev = crtc->dev; |
120 | struct tilcdc_drm_private *priv = dev->dev_private; | 93 | struct tilcdc_drm_private *priv = dev->dev_private; |
121 | 94 | ||
122 | if (priv->rev == 2) { | 95 | if (priv->rev != 2) |
123 | tilcdc_set(dev, LCDC_CLK_RESET_REG, LCDC_CLK_MAIN_RESET); | 96 | return; |
124 | msleep(1); | 97 | |
125 | tilcdc_clear(dev, LCDC_CLK_RESET_REG, LCDC_CLK_MAIN_RESET); | 98 | tilcdc_set(dev, LCDC_CLK_RESET_REG, LCDC_CLK_MAIN_RESET); |
126 | msleep(1); | 99 | usleep_range(250, 1000); |
127 | } | 100 | tilcdc_clear(dev, LCDC_CLK_RESET_REG, LCDC_CLK_MAIN_RESET); |
101 | } | ||
128 | 102 | ||
129 | tilcdc_set(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE); | 103 | static void start(struct drm_crtc *crtc) |
104 | { | ||
105 | struct drm_device *dev = crtc->dev; | ||
106 | |||
107 | reset(crtc); | ||
108 | |||
109 | tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_DUAL_FRAME_BUFFER_ENABLE); | ||
130 | tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_PALETTE_LOAD_MODE(DATA_ONLY)); | 110 | tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_PALETTE_LOAD_MODE(DATA_ONLY)); |
131 | tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); | 111 | tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); |
132 | } | 112 | } |
@@ -138,17 +118,31 @@ static void stop(struct drm_crtc *crtc) | |||
138 | tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); | 118 | tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); |
139 | } | 119 | } |
140 | 120 | ||
141 | static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode); | ||
142 | static void tilcdc_crtc_destroy(struct drm_crtc *crtc) | 121 | static void tilcdc_crtc_destroy(struct drm_crtc *crtc) |
143 | { | 122 | { |
144 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 123 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
145 | 124 | ||
146 | tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | 125 | tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
147 | 126 | ||
127 | of_node_put(crtc->port); | ||
148 | drm_crtc_cleanup(crtc); | 128 | drm_crtc_cleanup(crtc); |
149 | drm_flip_work_cleanup(&tilcdc_crtc->unref_work); | 129 | drm_flip_work_cleanup(&tilcdc_crtc->unref_work); |
130 | } | ||
131 | |||
132 | static int tilcdc_verify_fb(struct drm_crtc *crtc, struct drm_framebuffer *fb) | ||
133 | { | ||
134 | struct drm_device *dev = crtc->dev; | ||
135 | unsigned int depth, bpp; | ||
136 | |||
137 | drm_fb_get_bpp_depth(fb->pixel_format, &depth, &bpp); | ||
138 | |||
139 | if (fb->pitches[0] != crtc->mode.hdisplay * bpp / 8) { | ||
140 | dev_err(dev->dev, | ||
141 | "Invalid pitch: fb and crtc widths must be the same"); | ||
142 | return -EINVAL; | ||
143 | } | ||
150 | 144 | ||
151 | kfree(tilcdc_crtc); | 145 | return 0; |
152 | } | 146 | } |
153 | 147 | ||
154 | static int tilcdc_crtc_page_flip(struct drm_crtc *crtc, | 148 | static int tilcdc_crtc_page_flip(struct drm_crtc *crtc, |
@@ -158,20 +152,48 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc, | |||
158 | { | 152 | { |
159 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 153 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
160 | struct drm_device *dev = crtc->dev; | 154 | struct drm_device *dev = crtc->dev; |
155 | int r; | ||
156 | unsigned long flags; | ||
157 | s64 tdiff; | ||
158 | ktime_t next_vblank; | ||
159 | |||
160 | r = tilcdc_verify_fb(crtc, fb); | ||
161 | if (r) | ||
162 | return r; | ||
161 | 163 | ||
162 | if (tilcdc_crtc->event) { | 164 | if (tilcdc_crtc->event) { |
163 | dev_err(dev->dev, "already pending page flip!\n"); | 165 | dev_err(dev->dev, "already pending page flip!\n"); |
164 | return -EBUSY; | 166 | return -EBUSY; |
165 | } | 167 | } |
166 | 168 | ||
169 | drm_framebuffer_reference(fb); | ||
170 | |||
167 | crtc->primary->fb = fb; | 171 | crtc->primary->fb = fb; |
172 | |||
173 | pm_runtime_get_sync(dev->dev); | ||
174 | |||
175 | spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags); | ||
176 | |||
177 | next_vblank = ktime_add_us(tilcdc_crtc->last_vblank, | ||
178 | 1000000 / crtc->hwmode.vrefresh); | ||
179 | |||
180 | tdiff = ktime_to_us(ktime_sub(next_vblank, ktime_get())); | ||
181 | |||
182 | if (tdiff >= TILCDC_VBLANK_SAFETY_THRESHOLD_US) | ||
183 | set_scanout(crtc, fb); | ||
184 | else | ||
185 | tilcdc_crtc->next_fb = fb; | ||
186 | |||
168 | tilcdc_crtc->event = event; | 187 | tilcdc_crtc->event = event; |
169 | update_scanout(crtc); | 188 | |
189 | spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags); | ||
190 | |||
191 | pm_runtime_put_sync(dev->dev); | ||
170 | 192 | ||
171 | return 0; | 193 | return 0; |
172 | } | 194 | } |
173 | 195 | ||
174 | static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode) | 196 | void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode) |
175 | { | 197 | { |
176 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 198 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
177 | struct drm_device *dev = crtc->dev; | 199 | struct drm_device *dev = crtc->dev; |
@@ -186,10 +208,8 @@ static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
186 | 208 | ||
187 | tilcdc_crtc->dpms = mode; | 209 | tilcdc_crtc->dpms = mode; |
188 | 210 | ||
189 | pm_runtime_get_sync(dev->dev); | ||
190 | |||
191 | if (mode == DRM_MODE_DPMS_ON) { | 211 | if (mode == DRM_MODE_DPMS_ON) { |
192 | pm_runtime_forbid(dev->dev); | 212 | pm_runtime_get_sync(dev->dev); |
193 | start(crtc); | 213 | start(crtc); |
194 | } else { | 214 | } else { |
195 | tilcdc_crtc->frame_done = false; | 215 | tilcdc_crtc->frame_done = false; |
@@ -207,10 +227,23 @@ static void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode) | |||
207 | if (ret == 0) | 227 | if (ret == 0) |
208 | dev_err(dev->dev, "timeout waiting for framedone\n"); | 228 | dev_err(dev->dev, "timeout waiting for framedone\n"); |
209 | } | 229 | } |
210 | pm_runtime_allow(dev->dev); | ||
211 | } | ||
212 | 230 | ||
213 | pm_runtime_put_sync(dev->dev); | 231 | pm_runtime_put_sync(dev->dev); |
232 | |||
233 | if (tilcdc_crtc->next_fb) { | ||
234 | drm_flip_work_queue(&tilcdc_crtc->unref_work, | ||
235 | tilcdc_crtc->next_fb); | ||
236 | tilcdc_crtc->next_fb = NULL; | ||
237 | } | ||
238 | |||
239 | if (tilcdc_crtc->curr_fb) { | ||
240 | drm_flip_work_queue(&tilcdc_crtc->unref_work, | ||
241 | tilcdc_crtc->curr_fb); | ||
242 | tilcdc_crtc->curr_fb = NULL; | ||
243 | } | ||
244 | |||
245 | drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq); | ||
246 | } | ||
214 | } | 247 | } |
215 | 248 | ||
216 | static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, | 249 | static bool tilcdc_crtc_mode_fixup(struct drm_crtc *crtc, |
@@ -272,6 +305,10 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, | |||
272 | if (WARN_ON(!info)) | 305 | if (WARN_ON(!info)) |
273 | return -EINVAL; | 306 | return -EINVAL; |
274 | 307 | ||
308 | ret = tilcdc_verify_fb(crtc, crtc->primary->fb); | ||
309 | if (ret) | ||
310 | return ret; | ||
311 | |||
275 | pm_runtime_get_sync(dev->dev); | 312 | pm_runtime_get_sync(dev->dev); |
276 | 313 | ||
277 | /* Configure the Burst Size and fifo threshold of DMA: */ | 314 | /* Configure the Burst Size and fifo threshold of DMA: */ |
@@ -419,8 +456,10 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, | |||
419 | else | 456 | else |
420 | tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER); | 457 | tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ORDER); |
421 | 458 | ||
459 | drm_framebuffer_reference(crtc->primary->fb); | ||
460 | |||
461 | set_scanout(crtc, crtc->primary->fb); | ||
422 | 462 | ||
423 | update_scanout(crtc); | ||
424 | tilcdc_crtc_update_clk(crtc); | 463 | tilcdc_crtc_update_clk(crtc); |
425 | 464 | ||
426 | pm_runtime_put_sync(dev->dev); | 465 | pm_runtime_put_sync(dev->dev); |
@@ -431,7 +470,21 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, | |||
431 | static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | 470 | static int tilcdc_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, |
432 | struct drm_framebuffer *old_fb) | 471 | struct drm_framebuffer *old_fb) |
433 | { | 472 | { |
434 | update_scanout(crtc); | 473 | struct drm_device *dev = crtc->dev; |
474 | int r; | ||
475 | |||
476 | r = tilcdc_verify_fb(crtc, crtc->primary->fb); | ||
477 | if (r) | ||
478 | return r; | ||
479 | |||
480 | drm_framebuffer_reference(crtc->primary->fb); | ||
481 | |||
482 | pm_runtime_get_sync(dev->dev); | ||
483 | |||
484 | set_scanout(crtc, crtc->primary->fb); | ||
485 | |||
486 | pm_runtime_put_sync(dev->dev); | ||
487 | |||
435 | return 0; | 488 | return 0; |
436 | } | 489 | } |
437 | 490 | ||
@@ -573,7 +626,8 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc) | |||
573 | struct drm_device *dev = crtc->dev; | 626 | struct drm_device *dev = crtc->dev; |
574 | struct tilcdc_drm_private *priv = dev->dev_private; | 627 | struct tilcdc_drm_private *priv = dev->dev_private; |
575 | int dpms = tilcdc_crtc->dpms; | 628 | int dpms = tilcdc_crtc->dpms; |
576 | unsigned int lcd_clk, div; | 629 | unsigned long lcd_clk; |
630 | const unsigned clkdiv = 2; /* using a fixed divider of 2 */ | ||
577 | int ret; | 631 | int ret; |
578 | 632 | ||
579 | pm_runtime_get_sync(dev->dev); | 633 | pm_runtime_get_sync(dev->dev); |
@@ -581,22 +635,21 @@ void tilcdc_crtc_update_clk(struct drm_crtc *crtc) | |||
581 | if (dpms == DRM_MODE_DPMS_ON) | 635 | if (dpms == DRM_MODE_DPMS_ON) |
582 | tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | 636 | tilcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); |
583 | 637 | ||
584 | /* in raster mode, minimum divisor is 2: */ | 638 | /* mode.clock is in KHz, set_rate wants parameter in Hz */ |
585 | ret = clk_set_rate(priv->disp_clk, crtc->mode.clock * 1000 * 2); | 639 | ret = clk_set_rate(priv->clk, crtc->mode.clock * 1000 * clkdiv); |
586 | if (ret) { | 640 | if (ret < 0) { |
587 | dev_err(dev->dev, "failed to set display clock rate to: %d\n", | 641 | dev_err(dev->dev, "failed to set display clock rate to: %d\n", |
588 | crtc->mode.clock); | 642 | crtc->mode.clock); |
589 | goto out; | 643 | goto out; |
590 | } | 644 | } |
591 | 645 | ||
592 | lcd_clk = clk_get_rate(priv->clk); | 646 | lcd_clk = clk_get_rate(priv->clk); |
593 | div = lcd_clk / (crtc->mode.clock * 1000); | ||
594 | 647 | ||
595 | DBG("lcd_clk=%u, mode clock=%d, div=%u", lcd_clk, crtc->mode.clock, div); | 648 | DBG("lcd_clk=%lu, mode clock=%d, div=%u", |
596 | DBG("fck=%lu, dpll_disp_ck=%lu", clk_get_rate(priv->clk), clk_get_rate(priv->disp_clk)); | 649 | lcd_clk, crtc->mode.clock, clkdiv); |
597 | 650 | ||
598 | /* Configure the LCD clock divisor. */ | 651 | /* Configure the LCD clock divisor. */ |
599 | tilcdc_write(dev, LCDC_CTRL_REG, LCDC_CLK_DIVISOR(div) | | 652 | tilcdc_write(dev, LCDC_CTRL_REG, LCDC_CLK_DIVISOR(clkdiv) | |
600 | LCDC_RASTER_MODE); | 653 | LCDC_RASTER_MODE); |
601 | 654 | ||
602 | if (priv->rev == 2) | 655 | if (priv->rev == 2) |
@@ -611,44 +664,58 @@ out: | |||
611 | pm_runtime_put_sync(dev->dev); | 664 | pm_runtime_put_sync(dev->dev); |
612 | } | 665 | } |
613 | 666 | ||
667 | #define SYNC_LOST_COUNT_LIMIT 50 | ||
668 | |||
614 | irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) | 669 | irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) |
615 | { | 670 | { |
616 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); | 671 | struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); |
617 | struct drm_device *dev = crtc->dev; | 672 | struct drm_device *dev = crtc->dev; |
618 | struct tilcdc_drm_private *priv = dev->dev_private; | 673 | struct tilcdc_drm_private *priv = dev->dev_private; |
619 | uint32_t stat = tilcdc_read_irqstatus(dev); | 674 | uint32_t stat; |
620 | 675 | ||
621 | if ((stat & LCDC_SYNC_LOST) && (stat & LCDC_FIFO_UNDERFLOW)) { | 676 | stat = tilcdc_read_irqstatus(dev); |
622 | stop(crtc); | 677 | tilcdc_clear_irqstatus(dev, stat); |
623 | dev_err(dev->dev, "error: %08x\n", stat); | 678 | |
624 | tilcdc_clear_irqstatus(dev, stat); | 679 | if (stat & LCDC_END_OF_FRAME0) { |
625 | start(crtc); | ||
626 | } else if (stat & LCDC_PL_LOAD_DONE) { | ||
627 | tilcdc_clear_irqstatus(dev, stat); | ||
628 | } else { | ||
629 | struct drm_pending_vblank_event *event; | ||
630 | unsigned long flags; | 680 | unsigned long flags; |
631 | uint32_t dirty = tilcdc_crtc->dirty & stat; | 681 | bool skip_event = false; |
682 | ktime_t now; | ||
683 | |||
684 | now = ktime_get(); | ||
632 | 685 | ||
633 | tilcdc_clear_irqstatus(dev, stat); | 686 | drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq); |
634 | 687 | ||
635 | if (dirty & LCDC_END_OF_FRAME0) | 688 | spin_lock_irqsave(&tilcdc_crtc->irq_lock, flags); |
636 | set_scanout(crtc, 0); | ||
637 | 689 | ||
638 | if (dirty & LCDC_END_OF_FRAME1) | 690 | tilcdc_crtc->last_vblank = now; |
639 | set_scanout(crtc, 1); | 691 | |
692 | if (tilcdc_crtc->next_fb) { | ||
693 | set_scanout(crtc, tilcdc_crtc->next_fb); | ||
694 | tilcdc_crtc->next_fb = NULL; | ||
695 | skip_event = true; | ||
696 | } | ||
697 | |||
698 | spin_unlock_irqrestore(&tilcdc_crtc->irq_lock, flags); | ||
640 | 699 | ||
641 | drm_handle_vblank(dev, 0); | 700 | drm_handle_vblank(dev, 0); |
642 | 701 | ||
643 | spin_lock_irqsave(&dev->event_lock, flags); | 702 | if (!skip_event) { |
644 | event = tilcdc_crtc->event; | 703 | struct drm_pending_vblank_event *event; |
645 | tilcdc_crtc->event = NULL; | 704 | |
646 | if (event) | 705 | spin_lock_irqsave(&dev->event_lock, flags); |
647 | drm_send_vblank_event(dev, 0, event); | 706 | |
648 | spin_unlock_irqrestore(&dev->event_lock, flags); | 707 | event = tilcdc_crtc->event; |
708 | tilcdc_crtc->event = NULL; | ||
709 | if (event) | ||
710 | drm_send_vblank_event(dev, 0, event); | ||
711 | |||
712 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
713 | } | ||
649 | 714 | ||
650 | if (dirty && !tilcdc_crtc->dirty) | 715 | if (tilcdc_crtc->frame_intact) |
651 | drm_vblank_put(dev, 0); | 716 | tilcdc_crtc->sync_lost_count = 0; |
717 | else | ||
718 | tilcdc_crtc->frame_intact = true; | ||
652 | } | 719 | } |
653 | 720 | ||
654 | if (priv->rev == 2) { | 721 | if (priv->rev == 2) { |
@@ -659,16 +726,34 @@ irqreturn_t tilcdc_crtc_irq(struct drm_crtc *crtc) | |||
659 | tilcdc_write(dev, LCDC_END_OF_INT_IND_REG, 0); | 726 | tilcdc_write(dev, LCDC_END_OF_INT_IND_REG, 0); |
660 | } | 727 | } |
661 | 728 | ||
729 | if (stat & LCDC_SYNC_LOST) { | ||
730 | dev_err_ratelimited(dev->dev, "%s(0x%08x): Sync lost", | ||
731 | __func__, stat); | ||
732 | tilcdc_crtc->frame_intact = false; | ||
733 | if (tilcdc_crtc->sync_lost_count++ > SYNC_LOST_COUNT_LIMIT) { | ||
734 | dev_err(dev->dev, | ||
735 | "%s(0x%08x): Sync lost flood detected, disabling the interrupt", | ||
736 | __func__, stat); | ||
737 | tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG, | ||
738 | LCDC_SYNC_LOST); | ||
739 | } | ||
740 | } | ||
741 | |||
742 | if (stat & LCDC_FIFO_UNDERFLOW) | ||
743 | dev_err_ratelimited(dev->dev, "%s(0x%08x): FIFO underfow", | ||
744 | __func__, stat); | ||
745 | |||
662 | return IRQ_HANDLED; | 746 | return IRQ_HANDLED; |
663 | } | 747 | } |
664 | 748 | ||
665 | struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev) | 749 | struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev) |
666 | { | 750 | { |
751 | struct tilcdc_drm_private *priv = dev->dev_private; | ||
667 | struct tilcdc_crtc *tilcdc_crtc; | 752 | struct tilcdc_crtc *tilcdc_crtc; |
668 | struct drm_crtc *crtc; | 753 | struct drm_crtc *crtc; |
669 | int ret; | 754 | int ret; |
670 | 755 | ||
671 | tilcdc_crtc = kzalloc(sizeof(*tilcdc_crtc), GFP_KERNEL); | 756 | tilcdc_crtc = devm_kzalloc(dev->dev, sizeof(*tilcdc_crtc), GFP_KERNEL); |
672 | if (!tilcdc_crtc) { | 757 | if (!tilcdc_crtc) { |
673 | dev_err(dev->dev, "allocation failed\n"); | 758 | dev_err(dev->dev, "allocation failed\n"); |
674 | return NULL; | 759 | return NULL; |
@@ -682,12 +767,32 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev) | |||
682 | drm_flip_work_init(&tilcdc_crtc->unref_work, | 767 | drm_flip_work_init(&tilcdc_crtc->unref_work, |
683 | "unref", unref_worker); | 768 | "unref", unref_worker); |
684 | 769 | ||
770 | spin_lock_init(&tilcdc_crtc->irq_lock); | ||
771 | |||
685 | ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs); | 772 | ret = drm_crtc_init(dev, crtc, &tilcdc_crtc_funcs); |
686 | if (ret < 0) | 773 | if (ret < 0) |
687 | goto fail; | 774 | goto fail; |
688 | 775 | ||
689 | drm_crtc_helper_add(crtc, &tilcdc_crtc_helper_funcs); | 776 | drm_crtc_helper_add(crtc, &tilcdc_crtc_helper_funcs); |
690 | 777 | ||
778 | if (priv->is_componentized) { | ||
779 | struct device_node *ports = | ||
780 | of_get_child_by_name(dev->dev->of_node, "ports"); | ||
781 | |||
782 | if (ports) { | ||
783 | crtc->port = of_get_child_by_name(ports, "port"); | ||
784 | of_node_put(ports); | ||
785 | } else { | ||
786 | crtc->port = | ||
787 | of_get_child_by_name(dev->dev->of_node, "port"); | ||
788 | } | ||
789 | if (!crtc->port) { /* This should never happen */ | ||
790 | dev_err(dev->dev, "Port node not found in %s\n", | ||
791 | dev->dev->of_node->full_name); | ||
792 | goto fail; | ||
793 | } | ||
794 | } | ||
795 | |||
691 | return crtc; | 796 | return crtc; |
692 | 797 | ||
693 | fail: | 798 | fail: |
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 8190ac3b1b32..709bc903524d 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c | |||
@@ -18,6 +18,8 @@ | |||
18 | /* LCDC DRM driver, based on da8xx-fb */ | 18 | /* LCDC DRM driver, based on da8xx-fb */ |
19 | 19 | ||
20 | #include <linux/component.h> | 20 | #include <linux/component.h> |
21 | #include <linux/pinctrl/consumer.h> | ||
22 | #include <linux/suspend.h> | ||
21 | 23 | ||
22 | #include "tilcdc_drv.h" | 24 | #include "tilcdc_drv.h" |
23 | #include "tilcdc_regs.h" | 25 | #include "tilcdc_regs.h" |
@@ -110,6 +112,8 @@ static int tilcdc_unload(struct drm_device *dev) | |||
110 | { | 112 | { |
111 | struct tilcdc_drm_private *priv = dev->dev_private; | 113 | struct tilcdc_drm_private *priv = dev->dev_private; |
112 | 114 | ||
115 | tilcdc_crtc_dpms(priv->crtc, DRM_MODE_DPMS_OFF); | ||
116 | |||
113 | tilcdc_remove_external_encoders(dev); | 117 | tilcdc_remove_external_encoders(dev); |
114 | 118 | ||
115 | drm_fbdev_cma_fini(priv->fbdev); | 119 | drm_fbdev_cma_fini(priv->fbdev); |
@@ -139,11 +143,11 @@ static int tilcdc_unload(struct drm_device *dev) | |||
139 | 143 | ||
140 | pm_runtime_disable(dev->dev); | 144 | pm_runtime_disable(dev->dev); |
141 | 145 | ||
142 | kfree(priv); | ||
143 | |||
144 | return 0; | 146 | return 0; |
145 | } | 147 | } |
146 | 148 | ||
149 | static size_t tilcdc_num_regs(void); | ||
150 | |||
147 | static int tilcdc_load(struct drm_device *dev, unsigned long flags) | 151 | static int tilcdc_load(struct drm_device *dev, unsigned long flags) |
148 | { | 152 | { |
149 | struct platform_device *pdev = dev->platformdev; | 153 | struct platform_device *pdev = dev->platformdev; |
@@ -154,8 +158,12 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) | |||
154 | u32 bpp = 0; | 158 | u32 bpp = 0; |
155 | int ret; | 159 | int ret; |
156 | 160 | ||
157 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 161 | priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL); |
158 | if (!priv) { | 162 | if (priv) |
163 | priv->saved_register = | ||
164 | devm_kcalloc(dev->dev, tilcdc_num_regs(), | ||
165 | sizeof(*priv->saved_register), GFP_KERNEL); | ||
166 | if (!priv || !priv->saved_register) { | ||
159 | dev_err(dev->dev, "failed to allocate private data\n"); | 167 | dev_err(dev->dev, "failed to allocate private data\n"); |
160 | return -ENOMEM; | 168 | return -ENOMEM; |
161 | } | 169 | } |
@@ -168,7 +176,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) | |||
168 | priv->wq = alloc_ordered_workqueue("tilcdc", 0); | 176 | priv->wq = alloc_ordered_workqueue("tilcdc", 0); |
169 | if (!priv->wq) { | 177 | if (!priv->wq) { |
170 | ret = -ENOMEM; | 178 | ret = -ENOMEM; |
171 | goto fail_free_priv; | 179 | goto fail_unset_priv; |
172 | } | 180 | } |
173 | 181 | ||
174 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 182 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -192,13 +200,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) | |||
192 | goto fail_iounmap; | 200 | goto fail_iounmap; |
193 | } | 201 | } |
194 | 202 | ||
195 | priv->disp_clk = clk_get(dev->dev, "dpll_disp_ck"); | ||
196 | if (IS_ERR(priv->clk)) { | ||
197 | dev_err(dev->dev, "failed to get display clock\n"); | ||
198 | ret = -ENODEV; | ||
199 | goto fail_put_clk; | ||
200 | } | ||
201 | |||
202 | #ifdef CONFIG_CPU_FREQ | 203 | #ifdef CONFIG_CPU_FREQ |
203 | priv->lcd_fck_rate = clk_get_rate(priv->clk); | 204 | priv->lcd_fck_rate = clk_get_rate(priv->clk); |
204 | priv->freq_transition.notifier_call = cpufreq_transition; | 205 | priv->freq_transition.notifier_call = cpufreq_transition; |
@@ -206,7 +207,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) | |||
206 | CPUFREQ_TRANSITION_NOTIFIER); | 207 | CPUFREQ_TRANSITION_NOTIFIER); |
207 | if (ret) { | 208 | if (ret) { |
208 | dev_err(dev->dev, "failed to register cpufreq notifier\n"); | 209 | dev_err(dev->dev, "failed to register cpufreq notifier\n"); |
209 | goto fail_put_disp_clk; | 210 | goto fail_put_clk; |
210 | } | 211 | } |
211 | #endif | 212 | #endif |
212 | 213 | ||
@@ -227,7 +228,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) | |||
227 | DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); | 228 | DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); |
228 | 229 | ||
229 | pm_runtime_enable(dev->dev); | 230 | pm_runtime_enable(dev->dev); |
230 | pm_runtime_irq_safe(dev->dev); | ||
231 | 231 | ||
232 | /* Determine LCD IP Version */ | 232 | /* Determine LCD IP Version */ |
233 | pm_runtime_get_sync(dev->dev); | 233 | pm_runtime_get_sync(dev->dev); |
@@ -330,11 +330,9 @@ fail_cpufreq_unregister: | |||
330 | #ifdef CONFIG_CPU_FREQ | 330 | #ifdef CONFIG_CPU_FREQ |
331 | cpufreq_unregister_notifier(&priv->freq_transition, | 331 | cpufreq_unregister_notifier(&priv->freq_transition, |
332 | CPUFREQ_TRANSITION_NOTIFIER); | 332 | CPUFREQ_TRANSITION_NOTIFIER); |
333 | fail_put_disp_clk: | ||
334 | clk_put(priv->disp_clk); | ||
335 | #endif | ||
336 | 333 | ||
337 | fail_put_clk: | 334 | fail_put_clk: |
335 | #endif | ||
338 | clk_put(priv->clk); | 336 | clk_put(priv->clk); |
339 | 337 | ||
340 | fail_iounmap: | 338 | fail_iounmap: |
@@ -344,9 +342,9 @@ fail_free_wq: | |||
344 | flush_workqueue(priv->wq); | 342 | flush_workqueue(priv->wq); |
345 | destroy_workqueue(priv->wq); | 343 | destroy_workqueue(priv->wq); |
346 | 344 | ||
347 | fail_free_priv: | 345 | fail_unset_priv: |
348 | dev->dev_private = NULL; | 346 | dev->dev_private = NULL; |
349 | kfree(priv); | 347 | |
350 | return ret; | 348 | return ret; |
351 | } | 349 | } |
352 | 350 | ||
@@ -373,10 +371,14 @@ static int tilcdc_irq_postinstall(struct drm_device *dev) | |||
373 | struct tilcdc_drm_private *priv = dev->dev_private; | 371 | struct tilcdc_drm_private *priv = dev->dev_private; |
374 | 372 | ||
375 | /* enable FIFO underflow irq: */ | 373 | /* enable FIFO underflow irq: */ |
376 | if (priv->rev == 1) | 374 | if (priv->rev == 1) { |
377 | tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_V1_UNDERFLOW_INT_ENA); | 375 | tilcdc_set(dev, LCDC_RASTER_CTRL_REG, LCDC_V1_UNDERFLOW_INT_ENA); |
378 | else | 376 | } else { |
379 | tilcdc_set(dev, LCDC_INT_ENABLE_SET_REG, LCDC_V2_UNDERFLOW_INT_ENA); | 377 | tilcdc_write(dev, LCDC_INT_ENABLE_SET_REG, |
378 | LCDC_V2_UNDERFLOW_INT_ENA | | ||
379 | LCDC_V2_END_OF_FRAME0_INT_ENA | | ||
380 | LCDC_FRAME_DONE | LCDC_SYNC_LOST); | ||
381 | } | ||
380 | 382 | ||
381 | return 0; | 383 | return 0; |
382 | } | 384 | } |
@@ -391,43 +393,21 @@ static void tilcdc_irq_uninstall(struct drm_device *dev) | |||
391 | LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA); | 393 | LCDC_V1_UNDERFLOW_INT_ENA | LCDC_V1_PL_INT_ENA); |
392 | tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_V1_END_OF_FRAME_INT_ENA); | 394 | tilcdc_clear(dev, LCDC_DMA_CTRL_REG, LCDC_V1_END_OF_FRAME_INT_ENA); |
393 | } else { | 395 | } else { |
394 | tilcdc_clear(dev, LCDC_INT_ENABLE_SET_REG, | 396 | tilcdc_write(dev, LCDC_INT_ENABLE_CLR_REG, |
395 | LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA | | 397 | LCDC_V2_UNDERFLOW_INT_ENA | LCDC_V2_PL_INT_ENA | |
396 | LCDC_V2_END_OF_FRAME0_INT_ENA | LCDC_V2_END_OF_FRAME1_INT_ENA | | 398 | LCDC_V2_END_OF_FRAME0_INT_ENA | |
397 | LCDC_FRAME_DONE); | 399 | LCDC_FRAME_DONE | LCDC_SYNC_LOST); |
398 | } | ||
399 | |||
400 | } | ||
401 | |||
402 | static void enable_vblank(struct drm_device *dev, bool enable) | ||
403 | { | ||
404 | struct tilcdc_drm_private *priv = dev->dev_private; | ||
405 | u32 reg, mask; | ||
406 | |||
407 | if (priv->rev == 1) { | ||
408 | reg = LCDC_DMA_CTRL_REG; | ||
409 | mask = LCDC_V1_END_OF_FRAME_INT_ENA; | ||
410 | } else { | ||
411 | reg = LCDC_INT_ENABLE_SET_REG; | ||
412 | mask = LCDC_V2_END_OF_FRAME0_INT_ENA | | ||
413 | LCDC_V2_END_OF_FRAME1_INT_ENA | LCDC_FRAME_DONE; | ||
414 | } | 400 | } |
415 | |||
416 | if (enable) | ||
417 | tilcdc_set(dev, reg, mask); | ||
418 | else | ||
419 | tilcdc_clear(dev, reg, mask); | ||
420 | } | 401 | } |
421 | 402 | ||
422 | static int tilcdc_enable_vblank(struct drm_device *dev, unsigned int pipe) | 403 | static int tilcdc_enable_vblank(struct drm_device *dev, unsigned int pipe) |
423 | { | 404 | { |
424 | enable_vblank(dev, true); | ||
425 | return 0; | 405 | return 0; |
426 | } | 406 | } |
427 | 407 | ||
428 | static void tilcdc_disable_vblank(struct drm_device *dev, unsigned int pipe) | 408 | static void tilcdc_disable_vblank(struct drm_device *dev, unsigned int pipe) |
429 | { | 409 | { |
430 | enable_vblank(dev, false); | 410 | return; |
431 | } | 411 | } |
432 | 412 | ||
433 | #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PM_SLEEP) | 413 | #if defined(CONFIG_DEBUG_FS) || defined(CONFIG_PM_SLEEP) |
@@ -454,13 +434,22 @@ static const struct { | |||
454 | /* new in revision 2: */ | 434 | /* new in revision 2: */ |
455 | REG(2, false, LCDC_RAW_STAT_REG), | 435 | REG(2, false, LCDC_RAW_STAT_REG), |
456 | REG(2, false, LCDC_MASKED_STAT_REG), | 436 | REG(2, false, LCDC_MASKED_STAT_REG), |
457 | REG(2, false, LCDC_INT_ENABLE_SET_REG), | 437 | REG(2, true, LCDC_INT_ENABLE_SET_REG), |
458 | REG(2, false, LCDC_INT_ENABLE_CLR_REG), | 438 | REG(2, false, LCDC_INT_ENABLE_CLR_REG), |
459 | REG(2, false, LCDC_END_OF_INT_IND_REG), | 439 | REG(2, false, LCDC_END_OF_INT_IND_REG), |
460 | REG(2, true, LCDC_CLK_ENABLE_REG), | 440 | REG(2, true, LCDC_CLK_ENABLE_REG), |
461 | REG(2, true, LCDC_INT_ENABLE_SET_REG), | ||
462 | #undef REG | 441 | #undef REG |
463 | }; | 442 | }; |
443 | |||
444 | static size_t tilcdc_num_regs(void) | ||
445 | { | ||
446 | return ARRAY_SIZE(registers); | ||
447 | } | ||
448 | #else | ||
449 | static size_t tilcdc_num_regs(void) | ||
450 | { | ||
451 | return 0; | ||
452 | } | ||
464 | #endif | 453 | #endif |
465 | 454 | ||
466 | #ifdef CONFIG_DEBUG_FS | 455 | #ifdef CONFIG_DEBUG_FS |
@@ -547,7 +536,8 @@ static const struct file_operations fops = { | |||
547 | }; | 536 | }; |
548 | 537 | ||
549 | static struct drm_driver tilcdc_driver = { | 538 | static struct drm_driver tilcdc_driver = { |
550 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET, | 539 | .driver_features = (DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET | |
540 | DRIVER_PRIME), | ||
551 | .load = tilcdc_load, | 541 | .load = tilcdc_load, |
552 | .unload = tilcdc_unload, | 542 | .unload = tilcdc_unload, |
553 | .lastclose = tilcdc_lastclose, | 543 | .lastclose = tilcdc_lastclose, |
@@ -564,6 +554,16 @@ static struct drm_driver tilcdc_driver = { | |||
564 | .dumb_create = drm_gem_cma_dumb_create, | 554 | .dumb_create = drm_gem_cma_dumb_create, |
565 | .dumb_map_offset = drm_gem_cma_dumb_map_offset, | 555 | .dumb_map_offset = drm_gem_cma_dumb_map_offset, |
566 | .dumb_destroy = drm_gem_dumb_destroy, | 556 | .dumb_destroy = drm_gem_dumb_destroy, |
557 | |||
558 | .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | ||
559 | .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | ||
560 | .gem_prime_import = drm_gem_prime_import, | ||
561 | .gem_prime_export = drm_gem_prime_export, | ||
562 | .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, | ||
563 | .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, | ||
564 | .gem_prime_vmap = drm_gem_cma_prime_vmap, | ||
565 | .gem_prime_vunmap = drm_gem_cma_prime_vunmap, | ||
566 | .gem_prime_mmap = drm_gem_cma_prime_mmap, | ||
567 | #ifdef CONFIG_DEBUG_FS | 567 | #ifdef CONFIG_DEBUG_FS |
568 | .debugfs_init = tilcdc_debugfs_init, | 568 | .debugfs_init = tilcdc_debugfs_init, |
569 | .debugfs_cleanup = tilcdc_debugfs_cleanup, | 569 | .debugfs_cleanup = tilcdc_debugfs_cleanup, |
@@ -589,11 +589,24 @@ static int tilcdc_pm_suspend(struct device *dev) | |||
589 | 589 | ||
590 | drm_kms_helper_poll_disable(ddev); | 590 | drm_kms_helper_poll_disable(ddev); |
591 | 591 | ||
592 | /* Select sleep pin state */ | ||
593 | pinctrl_pm_select_sleep_state(dev); | ||
594 | |||
595 | if (pm_runtime_suspended(dev)) { | ||
596 | priv->ctx_valid = false; | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | /* Disable the LCDC controller, to avoid locking up the PRCM */ | ||
601 | tilcdc_crtc_dpms(priv->crtc, DRM_MODE_DPMS_OFF); | ||
602 | |||
592 | /* Save register state: */ | 603 | /* Save register state: */ |
593 | for (i = 0; i < ARRAY_SIZE(registers); i++) | 604 | for (i = 0; i < ARRAY_SIZE(registers); i++) |
594 | if (registers[i].save && (priv->rev >= registers[i].rev)) | 605 | if (registers[i].save && (priv->rev >= registers[i].rev)) |
595 | priv->saved_register[n++] = tilcdc_read(ddev, registers[i].reg); | 606 | priv->saved_register[n++] = tilcdc_read(ddev, registers[i].reg); |
596 | 607 | ||
608 | priv->ctx_valid = true; | ||
609 | |||
597 | return 0; | 610 | return 0; |
598 | } | 611 | } |
599 | 612 | ||
@@ -603,10 +616,17 @@ static int tilcdc_pm_resume(struct device *dev) | |||
603 | struct tilcdc_drm_private *priv = ddev->dev_private; | 616 | struct tilcdc_drm_private *priv = ddev->dev_private; |
604 | unsigned i, n = 0; | 617 | unsigned i, n = 0; |
605 | 618 | ||
606 | /* Restore register state: */ | 619 | /* Select default pin state */ |
607 | for (i = 0; i < ARRAY_SIZE(registers); i++) | 620 | pinctrl_pm_select_default_state(dev); |
608 | if (registers[i].save && (priv->rev >= registers[i].rev)) | 621 | |
609 | tilcdc_write(ddev, registers[i].reg, priv->saved_register[n++]); | 622 | if (priv->ctx_valid == true) { |
623 | /* Restore register state: */ | ||
624 | for (i = 0; i < ARRAY_SIZE(registers); i++) | ||
625 | if (registers[i].save && | ||
626 | (priv->rev >= registers[i].rev)) | ||
627 | tilcdc_write(ddev, registers[i].reg, | ||
628 | priv->saved_register[n++]); | ||
629 | } | ||
610 | 630 | ||
611 | drm_kms_helper_poll_enable(ddev); | 631 | drm_kms_helper_poll_enable(ddev); |
612 | 632 | ||
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h index 66105d8dc620..c1de18bae415 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h | |||
@@ -49,7 +49,6 @@ | |||
49 | struct tilcdc_drm_private { | 49 | struct tilcdc_drm_private { |
50 | void __iomem *mmio; | 50 | void __iomem *mmio; |
51 | 51 | ||
52 | struct clk *disp_clk; /* display dpll */ | ||
53 | struct clk *clk; /* functional clock */ | 52 | struct clk *clk; /* functional clock */ |
54 | int rev; /* IP revision */ | 53 | int rev; /* IP revision */ |
55 | 54 | ||
@@ -67,7 +66,8 @@ struct tilcdc_drm_private { | |||
67 | uint32_t max_width; | 66 | uint32_t max_width; |
68 | 67 | ||
69 | /* register contents saved across suspend/resume: */ | 68 | /* register contents saved across suspend/resume: */ |
70 | u32 saved_register[12]; | 69 | u32 *saved_register; |
70 | bool ctx_valid; | ||
71 | 71 | ||
72 | #ifdef CONFIG_CPU_FREQ | 72 | #ifdef CONFIG_CPU_FREQ |
73 | struct notifier_block freq_transition; | 73 | struct notifier_block freq_transition; |
@@ -171,5 +171,6 @@ void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc, | |||
171 | bool simulate_vesa_sync); | 171 | bool simulate_vesa_sync); |
172 | int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode); | 172 | int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode); |
173 | int tilcdc_crtc_max_width(struct drm_crtc *crtc); | 173 | int tilcdc_crtc_max_width(struct drm_crtc *crtc); |
174 | void tilcdc_crtc_dpms(struct drm_crtc *crtc, int mode); | ||
174 | 175 | ||
175 | #endif /* __TILCDC_DRV_H__ */ | 176 | #endif /* __TILCDC_DRV_H__ */ |
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 8dcf02a79b23..ff7774c17d7c 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c | |||
@@ -45,14 +45,6 @@ struct panel_encoder { | |||
45 | }; | 45 | }; |
46 | #define to_panel_encoder(x) container_of(x, struct panel_encoder, base) | 46 | #define to_panel_encoder(x) container_of(x, struct panel_encoder, base) |
47 | 47 | ||
48 | |||
49 | static void panel_encoder_destroy(struct drm_encoder *encoder) | ||
50 | { | ||
51 | struct panel_encoder *panel_encoder = to_panel_encoder(encoder); | ||
52 | drm_encoder_cleanup(encoder); | ||
53 | kfree(panel_encoder); | ||
54 | } | ||
55 | |||
56 | static void panel_encoder_dpms(struct drm_encoder *encoder, int mode) | 48 | static void panel_encoder_dpms(struct drm_encoder *encoder, int mode) |
57 | { | 49 | { |
58 | struct panel_encoder *panel_encoder = to_panel_encoder(encoder); | 50 | struct panel_encoder *panel_encoder = to_panel_encoder(encoder); |
@@ -90,7 +82,7 @@ static void panel_encoder_mode_set(struct drm_encoder *encoder, | |||
90 | } | 82 | } |
91 | 83 | ||
92 | static const struct drm_encoder_funcs panel_encoder_funcs = { | 84 | static const struct drm_encoder_funcs panel_encoder_funcs = { |
93 | .destroy = panel_encoder_destroy, | 85 | .destroy = drm_encoder_cleanup, |
94 | }; | 86 | }; |
95 | 87 | ||
96 | static const struct drm_encoder_helper_funcs panel_encoder_helper_funcs = { | 88 | static const struct drm_encoder_helper_funcs panel_encoder_helper_funcs = { |
@@ -107,7 +99,8 @@ static struct drm_encoder *panel_encoder_create(struct drm_device *dev, | |||
107 | struct drm_encoder *encoder; | 99 | struct drm_encoder *encoder; |
108 | int ret; | 100 | int ret; |
109 | 101 | ||
110 | panel_encoder = kzalloc(sizeof(*panel_encoder), GFP_KERNEL); | 102 | panel_encoder = devm_kzalloc(dev->dev, sizeof(*panel_encoder), |
103 | GFP_KERNEL); | ||
111 | if (!panel_encoder) { | 104 | if (!panel_encoder) { |
112 | dev_err(dev->dev, "allocation failed\n"); | 105 | dev_err(dev->dev, "allocation failed\n"); |
113 | return NULL; | 106 | return NULL; |
@@ -128,7 +121,7 @@ static struct drm_encoder *panel_encoder_create(struct drm_device *dev, | |||
128 | return encoder; | 121 | return encoder; |
129 | 122 | ||
130 | fail: | 123 | fail: |
131 | panel_encoder_destroy(encoder); | 124 | drm_encoder_cleanup(encoder); |
132 | return NULL; | 125 | return NULL; |
133 | } | 126 | } |
134 | 127 | ||
@@ -147,10 +140,8 @@ struct panel_connector { | |||
147 | 140 | ||
148 | static void panel_connector_destroy(struct drm_connector *connector) | 141 | static void panel_connector_destroy(struct drm_connector *connector) |
149 | { | 142 | { |
150 | struct panel_connector *panel_connector = to_panel_connector(connector); | ||
151 | drm_connector_unregister(connector); | 143 | drm_connector_unregister(connector); |
152 | drm_connector_cleanup(connector); | 144 | drm_connector_cleanup(connector); |
153 | kfree(panel_connector); | ||
154 | } | 145 | } |
155 | 146 | ||
156 | static enum drm_connector_status panel_connector_detect( | 147 | static enum drm_connector_status panel_connector_detect( |
@@ -223,7 +214,8 @@ static struct drm_connector *panel_connector_create(struct drm_device *dev, | |||
223 | struct drm_connector *connector; | 214 | struct drm_connector *connector; |
224 | int ret; | 215 | int ret; |
225 | 216 | ||
226 | panel_connector = kzalloc(sizeof(*panel_connector), GFP_KERNEL); | 217 | panel_connector = devm_kzalloc(dev->dev, sizeof(*panel_connector), |
218 | GFP_KERNEL); | ||
227 | if (!panel_connector) { | 219 | if (!panel_connector) { |
228 | dev_err(dev->dev, "allocation failed\n"); | 220 | dev_err(dev->dev, "allocation failed\n"); |
229 | return NULL; | 221 | return NULL; |
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c index 1c230172b402..7716f42f8aab 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_tfp410.c | |||
@@ -54,14 +54,6 @@ struct tfp410_encoder { | |||
54 | }; | 54 | }; |
55 | #define to_tfp410_encoder(x) container_of(x, struct tfp410_encoder, base) | 55 | #define to_tfp410_encoder(x) container_of(x, struct tfp410_encoder, base) |
56 | 56 | ||
57 | |||
58 | static void tfp410_encoder_destroy(struct drm_encoder *encoder) | ||
59 | { | ||
60 | struct tfp410_encoder *tfp410_encoder = to_tfp410_encoder(encoder); | ||
61 | drm_encoder_cleanup(encoder); | ||
62 | kfree(tfp410_encoder); | ||
63 | } | ||
64 | |||
65 | static void tfp410_encoder_dpms(struct drm_encoder *encoder, int mode) | 57 | static void tfp410_encoder_dpms(struct drm_encoder *encoder, int mode) |
66 | { | 58 | { |
67 | struct tfp410_encoder *tfp410_encoder = to_tfp410_encoder(encoder); | 59 | struct tfp410_encoder *tfp410_encoder = to_tfp410_encoder(encoder); |
@@ -99,7 +91,7 @@ static void tfp410_encoder_mode_set(struct drm_encoder *encoder, | |||
99 | } | 91 | } |
100 | 92 | ||
101 | static const struct drm_encoder_funcs tfp410_encoder_funcs = { | 93 | static const struct drm_encoder_funcs tfp410_encoder_funcs = { |
102 | .destroy = tfp410_encoder_destroy, | 94 | .destroy = drm_encoder_cleanup, |
103 | }; | 95 | }; |
104 | 96 | ||
105 | static const struct drm_encoder_helper_funcs tfp410_encoder_helper_funcs = { | 97 | static const struct drm_encoder_helper_funcs tfp410_encoder_helper_funcs = { |
@@ -116,7 +108,8 @@ static struct drm_encoder *tfp410_encoder_create(struct drm_device *dev, | |||
116 | struct drm_encoder *encoder; | 108 | struct drm_encoder *encoder; |
117 | int ret; | 109 | int ret; |
118 | 110 | ||
119 | tfp410_encoder = kzalloc(sizeof(*tfp410_encoder), GFP_KERNEL); | 111 | tfp410_encoder = devm_kzalloc(dev->dev, sizeof(*tfp410_encoder), |
112 | GFP_KERNEL); | ||
120 | if (!tfp410_encoder) { | 113 | if (!tfp410_encoder) { |
121 | dev_err(dev->dev, "allocation failed\n"); | 114 | dev_err(dev->dev, "allocation failed\n"); |
122 | return NULL; | 115 | return NULL; |
@@ -138,7 +131,7 @@ static struct drm_encoder *tfp410_encoder_create(struct drm_device *dev, | |||
138 | return encoder; | 131 | return encoder; |
139 | 132 | ||
140 | fail: | 133 | fail: |
141 | tfp410_encoder_destroy(encoder); | 134 | drm_encoder_cleanup(encoder); |
142 | return NULL; | 135 | return NULL; |
143 | } | 136 | } |
144 | 137 | ||
@@ -157,10 +150,8 @@ struct tfp410_connector { | |||
157 | 150 | ||
158 | static void tfp410_connector_destroy(struct drm_connector *connector) | 151 | static void tfp410_connector_destroy(struct drm_connector *connector) |
159 | { | 152 | { |
160 | struct tfp410_connector *tfp410_connector = to_tfp410_connector(connector); | ||
161 | drm_connector_unregister(connector); | 153 | drm_connector_unregister(connector); |
162 | drm_connector_cleanup(connector); | 154 | drm_connector_cleanup(connector); |
163 | kfree(tfp410_connector); | ||
164 | } | 155 | } |
165 | 156 | ||
166 | static enum drm_connector_status tfp410_connector_detect( | 157 | static enum drm_connector_status tfp410_connector_detect( |
@@ -228,7 +219,8 @@ static struct drm_connector *tfp410_connector_create(struct drm_device *dev, | |||
228 | struct drm_connector *connector; | 219 | struct drm_connector *connector; |
229 | int ret; | 220 | int ret; |
230 | 221 | ||
231 | tfp410_connector = kzalloc(sizeof(*tfp410_connector), GFP_KERNEL); | 222 | tfp410_connector = devm_kzalloc(dev->dev, sizeof(*tfp410_connector), |
223 | GFP_KERNEL); | ||
232 | if (!tfp410_connector) { | 224 | if (!tfp410_connector) { |
233 | dev_err(dev->dev, "allocation failed\n"); | 225 | dev_err(dev->dev, "allocation failed\n"); |
234 | return NULL; | 226 | return NULL; |
@@ -313,7 +305,7 @@ static int tfp410_probe(struct platform_device *pdev) | |||
313 | return -ENXIO; | 305 | return -ENXIO; |
314 | } | 306 | } |
315 | 307 | ||
316 | tfp410_mod = kzalloc(sizeof(*tfp410_mod), GFP_KERNEL); | 308 | tfp410_mod = devm_kzalloc(&pdev->dev, sizeof(*tfp410_mod), GFP_KERNEL); |
317 | if (!tfp410_mod) | 309 | if (!tfp410_mod) |
318 | return -ENOMEM; | 310 | return -ENOMEM; |
319 | 311 | ||
@@ -366,7 +358,6 @@ fail_adapter: | |||
366 | i2c_put_adapter(tfp410_mod->i2c); | 358 | i2c_put_adapter(tfp410_mod->i2c); |
367 | 359 | ||
368 | fail: | 360 | fail: |
369 | kfree(tfp410_mod); | ||
370 | tilcdc_module_cleanup(mod); | 361 | tilcdc_module_cleanup(mod); |
371 | return ret; | 362 | return ret; |
372 | } | 363 | } |
@@ -380,7 +371,6 @@ static int tfp410_remove(struct platform_device *pdev) | |||
380 | gpio_free(tfp410_mod->gpio); | 371 | gpio_free(tfp410_mod->gpio); |
381 | 372 | ||
382 | tilcdc_module_cleanup(mod); | 373 | tilcdc_module_cleanup(mod); |
383 | kfree(tfp410_mod); | ||
384 | 374 | ||
385 | return 0; | 375 | return 0; |
386 | } | 376 | } |