diff options
author | Boris Brezillon <boris.brezillon@free-electrons.com> | 2015-02-05 10:32:33 -0500 |
---|---|---|
committer | Boris Brezillon <boris.brezillon@free-electrons.com> | 2015-02-22 15:00:06 -0500 |
commit | 2389fc1305fc1e2cf8b310a75463fefd3058bf48 (patch) | |
tree | 2f85d867f87406bbb0256cdffb3f85478e133326 /drivers/gpu/drm | |
parent | 45ee2dbc65cbf6910892c480e6f428be342fa733 (diff) |
drm: atmel-hlcdc: Atomic mode-setting conversion
Convert the HLCDC driver to atomic mode-setting.
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Tested-by: Sylvain Rochet <sylvain.rochet@finsecur.com>
Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 291 | ||||
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h | 59 | ||||
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 41 | ||||
-rw-r--r-- | drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | 549 |
7 files changed, 455 insertions, 496 deletions
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index 0409b907de5d..b0c06272a1cb 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | |||
@@ -37,14 +37,14 @@ | |||
37 | * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device | 37 | * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device |
38 | * @event: pointer to the current page flip event | 38 | * @event: pointer to the current page flip event |
39 | * @id: CRTC id (returned by drm_crtc_index) | 39 | * @id: CRTC id (returned by drm_crtc_index) |
40 | * @dpms: DPMS mode | 40 | * @enabled: CRTC state |
41 | */ | 41 | */ |
42 | struct atmel_hlcdc_crtc { | 42 | struct atmel_hlcdc_crtc { |
43 | struct drm_crtc base; | 43 | struct drm_crtc base; |
44 | struct atmel_hlcdc_dc *dc; | 44 | struct atmel_hlcdc_dc *dc; |
45 | struct drm_pending_vblank_event *event; | 45 | struct drm_pending_vblank_event *event; |
46 | int id; | 46 | int id; |
47 | int dpms; | 47 | bool enabled; |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static inline struct atmel_hlcdc_crtc * | 50 | static inline struct atmel_hlcdc_crtc * |
@@ -53,86 +53,17 @@ drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc) | |||
53 | return container_of(crtc, struct atmel_hlcdc_crtc, base); | 53 | return container_of(crtc, struct atmel_hlcdc_crtc, base); |
54 | } | 54 | } |
55 | 55 | ||
56 | static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode) | 56 | static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c) |
57 | { | 57 | { |
58 | struct drm_device *dev = c->dev; | ||
59 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); | 58 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); |
60 | struct regmap *regmap = crtc->dc->hlcdc->regmap; | 59 | struct regmap *regmap = crtc->dc->hlcdc->regmap; |
61 | unsigned int status; | 60 | struct drm_display_mode *adj = &c->state->adjusted_mode; |
62 | |||
63 | if (mode != DRM_MODE_DPMS_ON) | ||
64 | mode = DRM_MODE_DPMS_OFF; | ||
65 | |||
66 | if (crtc->dpms == mode) | ||
67 | return; | ||
68 | |||
69 | pm_runtime_get_sync(dev->dev); | ||
70 | |||
71 | if (mode != DRM_MODE_DPMS_ON) { | ||
72 | regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP); | ||
73 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
74 | (status & ATMEL_HLCDC_DISP)) | ||
75 | cpu_relax(); | ||
76 | |||
77 | regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC); | ||
78 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
79 | (status & ATMEL_HLCDC_SYNC)) | ||
80 | cpu_relax(); | ||
81 | |||
82 | regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK); | ||
83 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
84 | (status & ATMEL_HLCDC_PIXEL_CLK)) | ||
85 | cpu_relax(); | ||
86 | |||
87 | clk_disable_unprepare(crtc->dc->hlcdc->sys_clk); | ||
88 | |||
89 | pm_runtime_allow(dev->dev); | ||
90 | } else { | ||
91 | pm_runtime_forbid(dev->dev); | ||
92 | |||
93 | clk_prepare_enable(crtc->dc->hlcdc->sys_clk); | ||
94 | |||
95 | regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK); | ||
96 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
97 | !(status & ATMEL_HLCDC_PIXEL_CLK)) | ||
98 | cpu_relax(); | ||
99 | |||
100 | |||
101 | regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC); | ||
102 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
103 | !(status & ATMEL_HLCDC_SYNC)) | ||
104 | cpu_relax(); | ||
105 | |||
106 | regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP); | ||
107 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
108 | !(status & ATMEL_HLCDC_DISP)) | ||
109 | cpu_relax(); | ||
110 | } | ||
111 | |||
112 | pm_runtime_put_sync(dev->dev); | ||
113 | |||
114 | crtc->dpms = mode; | ||
115 | } | ||
116 | |||
117 | static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c, | ||
118 | struct drm_display_mode *mode, | ||
119 | struct drm_display_mode *adj, | ||
120 | int x, int y, | ||
121 | struct drm_framebuffer *old_fb) | ||
122 | { | ||
123 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); | ||
124 | struct regmap *regmap = crtc->dc->hlcdc->regmap; | ||
125 | struct drm_plane *plane = c->primary; | ||
126 | struct drm_framebuffer *fb; | ||
127 | unsigned long mode_rate; | 61 | unsigned long mode_rate; |
128 | struct videomode vm; | 62 | struct videomode vm; |
129 | unsigned long prate; | 63 | unsigned long prate; |
130 | unsigned int cfg; | 64 | unsigned int cfg; |
131 | int div; | 65 | int div; |
132 | 66 | ||
133 | if (atmel_hlcdc_dc_mode_valid(crtc->dc, adj) != MODE_OK) | ||
134 | return -EINVAL; | ||
135 | |||
136 | vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay; | 67 | vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay; |
137 | vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end; | 68 | vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end; |
138 | vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start; | 69 | vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start; |
@@ -156,7 +87,7 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c, | |||
156 | cfg = ATMEL_HLCDC_CLKPOL; | 87 | cfg = ATMEL_HLCDC_CLKPOL; |
157 | 88 | ||
158 | prate = clk_get_rate(crtc->dc->hlcdc->sys_clk); | 89 | prate = clk_get_rate(crtc->dc->hlcdc->sys_clk); |
159 | mode_rate = mode->crtc_clock * 1000; | 90 | mode_rate = adj->crtc_clock * 1000; |
160 | if ((prate / 2) < mode_rate) { | 91 | if ((prate / 2) < mode_rate) { |
161 | prate *= 2; | 92 | prate *= 2; |
162 | cfg |= ATMEL_HLCDC_CLKSEL; | 93 | cfg |= ATMEL_HLCDC_CLKSEL; |
@@ -174,10 +105,10 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c, | |||
174 | 105 | ||
175 | cfg = 0; | 106 | cfg = 0; |
176 | 107 | ||
177 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | 108 | if (adj->flags & DRM_MODE_FLAG_NVSYNC) |
178 | cfg |= ATMEL_HLCDC_VSPOL; | 109 | cfg |= ATMEL_HLCDC_VSPOL; |
179 | 110 | ||
180 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | 111 | if (adj->flags & DRM_MODE_FLAG_NHSYNC) |
181 | cfg |= ATMEL_HLCDC_HSPOL; | 112 | cfg |= ATMEL_HLCDC_HSPOL; |
182 | 113 | ||
183 | regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5), | 114 | regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5), |
@@ -187,77 +118,132 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c, | |||
187 | ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO | | 118 | ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO | |
188 | ATMEL_HLCDC_GUARDTIME_MASK, | 119 | ATMEL_HLCDC_GUARDTIME_MASK, |
189 | cfg); | 120 | cfg); |
190 | |||
191 | fb = plane->fb; | ||
192 | plane->fb = old_fb; | ||
193 | |||
194 | return atmel_hlcdc_plane_update_with_mode(plane, c, fb, 0, 0, | ||
195 | adj->hdisplay, adj->vdisplay, | ||
196 | x << 16, y << 16, | ||
197 | adj->hdisplay << 16, | ||
198 | adj->vdisplay << 16, | ||
199 | adj); | ||
200 | } | 121 | } |
201 | 122 | ||
202 | int atmel_hlcdc_crtc_mode_set_base(struct drm_crtc *c, int x, int y, | 123 | static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc, |
203 | struct drm_framebuffer *old_fb) | 124 | const struct drm_display_mode *mode, |
125 | struct drm_display_mode *adjusted_mode) | ||
204 | { | 126 | { |
205 | struct drm_plane *plane = c->primary; | 127 | return true; |
206 | struct drm_framebuffer *fb = plane->fb; | ||
207 | struct drm_display_mode *mode = &c->hwmode; | ||
208 | |||
209 | plane->fb = old_fb; | ||
210 | |||
211 | return plane->funcs->update_plane(plane, c, fb, | ||
212 | 0, 0, | ||
213 | mode->hdisplay, | ||
214 | mode->vdisplay, | ||
215 | x << 16, y << 16, | ||
216 | mode->hdisplay << 16, | ||
217 | mode->vdisplay << 16); | ||
218 | } | 128 | } |
219 | 129 | ||
220 | static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc) | 130 | static void atmel_hlcdc_crtc_disable(struct drm_crtc *c) |
221 | { | 131 | { |
222 | atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | 132 | struct drm_device *dev = c->dev; |
133 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); | ||
134 | struct regmap *regmap = crtc->dc->hlcdc->regmap; | ||
135 | unsigned int status; | ||
136 | |||
137 | if (!crtc->enabled) | ||
138 | return; | ||
139 | |||
140 | drm_crtc_vblank_off(c); | ||
141 | |||
142 | pm_runtime_get_sync(dev->dev); | ||
143 | |||
144 | regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP); | ||
145 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
146 | (status & ATMEL_HLCDC_DISP)) | ||
147 | cpu_relax(); | ||
148 | |||
149 | regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC); | ||
150 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
151 | (status & ATMEL_HLCDC_SYNC)) | ||
152 | cpu_relax(); | ||
153 | |||
154 | regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK); | ||
155 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
156 | (status & ATMEL_HLCDC_PIXEL_CLK)) | ||
157 | cpu_relax(); | ||
158 | |||
159 | clk_disable_unprepare(crtc->dc->hlcdc->sys_clk); | ||
160 | |||
161 | pm_runtime_allow(dev->dev); | ||
162 | |||
163 | pm_runtime_put_sync(dev->dev); | ||
164 | |||
165 | crtc->enabled = false; | ||
223 | } | 166 | } |
224 | 167 | ||
225 | static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc) | 168 | static void atmel_hlcdc_crtc_enable(struct drm_crtc *c) |
226 | { | 169 | { |
227 | atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON); | 170 | struct drm_device *dev = c->dev; |
171 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); | ||
172 | struct regmap *regmap = crtc->dc->hlcdc->regmap; | ||
173 | unsigned int status; | ||
174 | |||
175 | if (crtc->enabled) | ||
176 | return; | ||
177 | |||
178 | pm_runtime_get_sync(dev->dev); | ||
179 | |||
180 | pm_runtime_forbid(dev->dev); | ||
181 | |||
182 | clk_prepare_enable(crtc->dc->hlcdc->sys_clk); | ||
183 | |||
184 | regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK); | ||
185 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
186 | !(status & ATMEL_HLCDC_PIXEL_CLK)) | ||
187 | cpu_relax(); | ||
188 | |||
189 | |||
190 | regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC); | ||
191 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
192 | !(status & ATMEL_HLCDC_SYNC)) | ||
193 | cpu_relax(); | ||
194 | |||
195 | regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP); | ||
196 | while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) && | ||
197 | !(status & ATMEL_HLCDC_DISP)) | ||
198 | cpu_relax(); | ||
199 | |||
200 | pm_runtime_put_sync(dev->dev); | ||
201 | |||
202 | drm_crtc_vblank_on(c); | ||
203 | |||
204 | crtc->enabled = true; | ||
228 | } | 205 | } |
229 | 206 | ||
230 | static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc, | 207 | static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c, |
231 | const struct drm_display_mode *mode, | 208 | struct drm_crtc_state *s) |
232 | struct drm_display_mode *adjusted_mode) | ||
233 | { | 209 | { |
234 | return true; | 210 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); |
211 | |||
212 | if (atmel_hlcdc_dc_mode_valid(crtc->dc, &s->adjusted_mode) != MODE_OK) | ||
213 | return -EINVAL; | ||
214 | |||
215 | return 0; | ||
235 | } | 216 | } |
236 | 217 | ||
237 | static void atmel_hlcdc_crtc_disable(struct drm_crtc *crtc) | 218 | static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c) |
238 | { | 219 | { |
239 | struct drm_plane *plane; | 220 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); |
240 | 221 | ||
241 | atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); | 222 | if (c->state->event) { |
242 | crtc->primary->funcs->disable_plane(crtc->primary); | 223 | c->state->event->pipe = drm_crtc_index(c); |
243 | 224 | ||
244 | drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { | 225 | WARN_ON(drm_crtc_vblank_get(c) != 0); |
245 | if (plane->crtc != crtc) | ||
246 | continue; | ||
247 | 226 | ||
248 | plane->funcs->disable_plane(crtc->primary); | 227 | crtc->event = c->state->event; |
249 | plane->crtc = NULL; | 228 | c->state->event = NULL; |
250 | } | 229 | } |
251 | } | 230 | } |
252 | 231 | ||
232 | static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc) | ||
233 | { | ||
234 | /* TODO: write common plane control register if available */ | ||
235 | } | ||
236 | |||
253 | static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = { | 237 | static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = { |
254 | .mode_fixup = atmel_hlcdc_crtc_mode_fixup, | 238 | .mode_fixup = atmel_hlcdc_crtc_mode_fixup, |
255 | .dpms = atmel_hlcdc_crtc_dpms, | 239 | .mode_set = drm_helper_crtc_mode_set, |
256 | .mode_set = atmel_hlcdc_crtc_mode_set, | 240 | .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb, |
257 | .mode_set_base = atmel_hlcdc_crtc_mode_set_base, | 241 | .mode_set_base = drm_helper_crtc_mode_set_base, |
258 | .prepare = atmel_hlcdc_crtc_prepare, | ||
259 | .commit = atmel_hlcdc_crtc_commit, | ||
260 | .disable = atmel_hlcdc_crtc_disable, | 242 | .disable = atmel_hlcdc_crtc_disable, |
243 | .enable = atmel_hlcdc_crtc_enable, | ||
244 | .atomic_check = atmel_hlcdc_crtc_atomic_check, | ||
245 | .atomic_begin = atmel_hlcdc_crtc_atomic_begin, | ||
246 | .atomic_flush = atmel_hlcdc_crtc_atomic_flush, | ||
261 | }; | 247 | }; |
262 | 248 | ||
263 | static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c) | 249 | static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c) |
@@ -306,61 +292,13 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c) | |||
306 | atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c)); | 292 | atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c)); |
307 | } | 293 | } |
308 | 294 | ||
309 | static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c, | ||
310 | struct drm_framebuffer *fb, | ||
311 | struct drm_pending_vblank_event *event, | ||
312 | uint32_t page_flip_flags) | ||
313 | { | ||
314 | struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); | ||
315 | struct atmel_hlcdc_plane_update_req req; | ||
316 | struct drm_plane *plane = c->primary; | ||
317 | struct drm_device *dev = c->dev; | ||
318 | unsigned long flags; | ||
319 | int ret = 0; | ||
320 | |||
321 | spin_lock_irqsave(&dev->event_lock, flags); | ||
322 | if (crtc->event) | ||
323 | ret = -EBUSY; | ||
324 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
325 | |||
326 | if (ret) | ||
327 | return ret; | ||
328 | |||
329 | memset(&req, 0, sizeof(req)); | ||
330 | req.crtc_x = 0; | ||
331 | req.crtc_y = 0; | ||
332 | req.crtc_h = c->mode.crtc_vdisplay; | ||
333 | req.crtc_w = c->mode.crtc_hdisplay; | ||
334 | req.src_x = c->x << 16; | ||
335 | req.src_y = c->y << 16; | ||
336 | req.src_w = req.crtc_w << 16; | ||
337 | req.src_h = req.crtc_h << 16; | ||
338 | req.fb = fb; | ||
339 | |||
340 | ret = atmel_hlcdc_plane_prepare_update_req(plane, &req, &c->hwmode); | ||
341 | if (ret) | ||
342 | return ret; | ||
343 | |||
344 | if (event) { | ||
345 | drm_vblank_get(c->dev, crtc->id); | ||
346 | spin_lock_irqsave(&dev->event_lock, flags); | ||
347 | crtc->event = event; | ||
348 | spin_unlock_irqrestore(&dev->event_lock, flags); | ||
349 | } | ||
350 | |||
351 | ret = atmel_hlcdc_plane_apply_update_req(plane, &req); | ||
352 | if (ret) | ||
353 | crtc->event = NULL; | ||
354 | else | ||
355 | plane->fb = fb; | ||
356 | |||
357 | return ret; | ||
358 | } | ||
359 | |||
360 | static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = { | 295 | static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = { |
361 | .page_flip = atmel_hlcdc_crtc_page_flip, | 296 | .page_flip = drm_atomic_helper_page_flip, |
362 | .set_config = drm_crtc_helper_set_config, | 297 | .set_config = drm_atomic_helper_set_config, |
363 | .destroy = atmel_hlcdc_crtc_destroy, | 298 | .destroy = atmel_hlcdc_crtc_destroy, |
299 | .reset = drm_atomic_helper_crtc_reset, | ||
300 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, | ||
301 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, | ||
364 | }; | 302 | }; |
365 | 303 | ||
366 | int atmel_hlcdc_crtc_create(struct drm_device *dev) | 304 | int atmel_hlcdc_crtc_create(struct drm_device *dev) |
@@ -375,7 +313,6 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev) | |||
375 | if (!crtc) | 313 | if (!crtc) |
376 | return -ENOMEM; | 314 | return -ENOMEM; |
377 | 315 | ||
378 | crtc->dpms = DRM_MODE_DPMS_OFF; | ||
379 | crtc->dc = dc; | 316 | crtc->dc = dc; |
380 | 317 | ||
381 | ret = drm_crtc_init_with_planes(dev, &crtc->base, | 318 | ret = drm_crtc_init_with_planes(dev, &crtc->base, |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 7320a6c6613f..47fd1470f755 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | |||
@@ -222,6 +222,8 @@ static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev) | |||
222 | static const struct drm_mode_config_funcs mode_config_funcs = { | 222 | static const struct drm_mode_config_funcs mode_config_funcs = { |
223 | .fb_create = atmel_hlcdc_fb_create, | 223 | .fb_create = atmel_hlcdc_fb_create, |
224 | .output_poll_changed = atmel_hlcdc_fb_output_poll_changed, | 224 | .output_poll_changed = atmel_hlcdc_fb_output_poll_changed, |
225 | .atomic_check = drm_atomic_helper_check, | ||
226 | .atomic_commit = drm_atomic_helper_commit, | ||
225 | }; | 227 | }; |
226 | 228 | ||
227 | static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev) | 229 | static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev) |
@@ -319,6 +321,8 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev) | |||
319 | goto err_periph_clk_disable; | 321 | goto err_periph_clk_disable; |
320 | } | 322 | } |
321 | 323 | ||
324 | drm_mode_config_reset(dev); | ||
325 | |||
322 | ret = drm_vblank_init(dev, 1); | 326 | ret = drm_vblank_init(dev, 1); |
323 | if (ret < 0) { | 327 | if (ret < 0) { |
324 | dev_err(dev->dev, "failed to initialize vblank\n"); | 328 | dev_err(dev->dev, "failed to initialize vblank\n"); |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h index 7bc96af3397a..015c3f13b7f8 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h | |||
@@ -26,11 +26,14 @@ | |||
26 | #include <linux/irqdomain.h> | 26 | #include <linux/irqdomain.h> |
27 | #include <linux/pwm.h> | 27 | #include <linux/pwm.h> |
28 | 28 | ||
29 | #include <drm/drm_atomic.h> | ||
30 | #include <drm/drm_atomic_helper.h> | ||
29 | #include <drm/drm_crtc.h> | 31 | #include <drm/drm_crtc.h> |
30 | #include <drm/drm_crtc_helper.h> | 32 | #include <drm/drm_crtc_helper.h> |
31 | #include <drm/drm_fb_cma_helper.h> | 33 | #include <drm/drm_fb_cma_helper.h> |
32 | #include <drm/drm_gem_cma_helper.h> | 34 | #include <drm/drm_gem_cma_helper.h> |
33 | #include <drm/drm_panel.h> | 35 | #include <drm/drm_panel.h> |
36 | #include <drm/drm_plane_helper.h> | ||
34 | #include <drm/drmP.h> | 37 | #include <drm/drmP.h> |
35 | 38 | ||
36 | #include "atmel_hlcdc_layer.h" | 39 | #include "atmel_hlcdc_layer.h" |
@@ -69,7 +72,6 @@ struct atmel_hlcdc_dc_desc { | |||
69 | */ | 72 | */ |
70 | struct atmel_hlcdc_plane_properties { | 73 | struct atmel_hlcdc_plane_properties { |
71 | struct drm_property *alpha; | 74 | struct drm_property *alpha; |
72 | struct drm_property *rotation; | ||
73 | }; | 75 | }; |
74 | 76 | ||
75 | /** | 77 | /** |
@@ -84,7 +86,6 @@ struct atmel_hlcdc_plane { | |||
84 | struct drm_plane base; | 86 | struct drm_plane base; |
85 | struct atmel_hlcdc_layer layer; | 87 | struct atmel_hlcdc_layer layer; |
86 | struct atmel_hlcdc_plane_properties *properties; | 88 | struct atmel_hlcdc_plane_properties *properties; |
87 | unsigned int rotation; | ||
88 | }; | 89 | }; |
89 | 90 | ||
90 | static inline struct atmel_hlcdc_plane * | 91 | static inline struct atmel_hlcdc_plane * |
@@ -100,43 +101,6 @@ atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l) | |||
100 | } | 101 | } |
101 | 102 | ||
102 | /** | 103 | /** |
103 | * Atmel HLCDC Plane update request structure. | ||
104 | * | ||
105 | * @crtc_x: x position of the plane relative to the CRTC | ||
106 | * @crtc_y: y position of the plane relative to the CRTC | ||
107 | * @crtc_w: visible width of the plane | ||
108 | * @crtc_h: visible height of the plane | ||
109 | * @src_x: x buffer position | ||
110 | * @src_y: y buffer position | ||
111 | * @src_w: buffer width | ||
112 | * @src_h: buffer height | ||
113 | * @fb: framebuffer object object | ||
114 | * @bpp: bytes per pixel deduced from pixel_format | ||
115 | * @offsets: offsets to apply to the GEM buffers | ||
116 | * @xstride: value to add to the pixel pointer between each line | ||
117 | * @pstride: value to add to the pixel pointer between each pixel | ||
118 | * @nplanes: number of planes (deduced from pixel_format) | ||
119 | */ | ||
120 | struct atmel_hlcdc_plane_update_req { | ||
121 | int crtc_x; | ||
122 | int crtc_y; | ||
123 | unsigned int crtc_w; | ||
124 | unsigned int crtc_h; | ||
125 | uint32_t src_x; | ||
126 | uint32_t src_y; | ||
127 | uint32_t src_w; | ||
128 | uint32_t src_h; | ||
129 | struct drm_framebuffer *fb; | ||
130 | |||
131 | /* These fields are private and should not be touched */ | ||
132 | int bpp[ATMEL_HLCDC_MAX_PLANES]; | ||
133 | unsigned int offsets[ATMEL_HLCDC_MAX_PLANES]; | ||
134 | int xstride[ATMEL_HLCDC_MAX_PLANES]; | ||
135 | int pstride[ATMEL_HLCDC_MAX_PLANES]; | ||
136 | int nplanes; | ||
137 | }; | ||
138 | |||
139 | /** | ||
140 | * Atmel HLCDC Planes. | 104 | * Atmel HLCDC Planes. |
141 | * | 105 | * |
142 | * This structure stores the instantiated HLCDC Planes and can be accessed by | 106 | * This structure stores the instantiated HLCDC Planes and can be accessed by |
@@ -184,23 +148,6 @@ int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc, | |||
184 | struct atmel_hlcdc_planes * | 148 | struct atmel_hlcdc_planes * |
185 | atmel_hlcdc_create_planes(struct drm_device *dev); | 149 | atmel_hlcdc_create_planes(struct drm_device *dev); |
186 | 150 | ||
187 | int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p, | ||
188 | struct atmel_hlcdc_plane_update_req *req, | ||
189 | const struct drm_display_mode *mode); | ||
190 | |||
191 | int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p, | ||
192 | struct atmel_hlcdc_plane_update_req *req); | ||
193 | |||
194 | int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p, | ||
195 | struct drm_crtc *crtc, | ||
196 | struct drm_framebuffer *fb, | ||
197 | int crtc_x, int crtc_y, | ||
198 | unsigned int crtc_w, | ||
199 | unsigned int crtc_h, | ||
200 | uint32_t src_x, uint32_t src_y, | ||
201 | uint32_t src_w, uint32_t src_h, | ||
202 | const struct drm_display_mode *mode); | ||
203 | |||
204 | void atmel_hlcdc_crtc_irq(struct drm_crtc *c); | 151 | void atmel_hlcdc_crtc_irq(struct drm_crtc *c); |
205 | 152 | ||
206 | void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc, | 153 | void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc, |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c index 063d2a7b941f..d1dca39b76dd 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c | |||
@@ -298,7 +298,7 @@ void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer) | |||
298 | spin_unlock_irqrestore(&layer->lock, flags); | 298 | spin_unlock_irqrestore(&layer->lock, flags); |
299 | } | 299 | } |
300 | 300 | ||
301 | int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer) | 301 | void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer) |
302 | { | 302 | { |
303 | struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma; | 303 | struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma; |
304 | struct atmel_hlcdc_layer_update *upd = &layer->update; | 304 | struct atmel_hlcdc_layer_update *upd = &layer->update; |
@@ -340,8 +340,6 @@ int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer) | |||
340 | dma->status = ATMEL_HLCDC_LAYER_DISABLED; | 340 | dma->status = ATMEL_HLCDC_LAYER_DISABLED; |
341 | 341 | ||
342 | spin_unlock_irqrestore(&layer->lock, flags); | 342 | spin_unlock_irqrestore(&layer->lock, flags); |
343 | |||
344 | return 0; | ||
345 | } | 343 | } |
346 | 344 | ||
347 | int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer) | 345 | int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer) |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h index 27e56c0862ec..9beabc940bce 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h | |||
@@ -120,6 +120,7 @@ | |||
120 | #define ATMEL_HLCDC_LAYER_DISCEN BIT(11) | 120 | #define ATMEL_HLCDC_LAYER_DISCEN BIT(11) |
121 | #define ATMEL_HLCDC_LAYER_GA_SHIFT 16 | 121 | #define ATMEL_HLCDC_LAYER_GA_SHIFT 16 |
122 | #define ATMEL_HLCDC_LAYER_GA_MASK GENMASK(23, ATMEL_HLCDC_LAYER_GA_SHIFT) | 122 | #define ATMEL_HLCDC_LAYER_GA_MASK GENMASK(23, ATMEL_HLCDC_LAYER_GA_SHIFT) |
123 | #define ATMEL_HLCDC_LAYER_GA(x) ((x) << ATMEL_HLCDC_LAYER_GA_SHIFT) | ||
123 | 124 | ||
124 | #define ATMEL_HLCDC_LAYER_CSC_CFG(p, o) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o) | 125 | #define ATMEL_HLCDC_LAYER_CSC_CFG(p, o) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o) |
125 | 126 | ||
@@ -376,7 +377,7 @@ int atmel_hlcdc_layer_init(struct drm_device *dev, | |||
376 | void atmel_hlcdc_layer_cleanup(struct drm_device *dev, | 377 | void atmel_hlcdc_layer_cleanup(struct drm_device *dev, |
377 | struct atmel_hlcdc_layer *layer); | 378 | struct atmel_hlcdc_layer *layer); |
378 | 379 | ||
379 | int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer); | 380 | void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer); |
380 | 381 | ||
381 | int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer); | 382 | int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer); |
382 | 383 | ||
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c index c402192362c5..9c4513005310 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | |||
@@ -86,25 +86,22 @@ atmel_hlcdc_rgb_output_to_panel(struct atmel_hlcdc_rgb_output *output) | |||
86 | return container_of(output, struct atmel_hlcdc_panel, base); | 86 | return container_of(output, struct atmel_hlcdc_panel, base); |
87 | } | 87 | } |
88 | 88 | ||
89 | static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder, | 89 | static void atmel_hlcdc_panel_encoder_enable(struct drm_encoder *encoder) |
90 | int mode) | ||
91 | { | 90 | { |
92 | struct atmel_hlcdc_rgb_output *rgb = | 91 | struct atmel_hlcdc_rgb_output *rgb = |
93 | drm_encoder_to_atmel_hlcdc_rgb_output(encoder); | 92 | drm_encoder_to_atmel_hlcdc_rgb_output(encoder); |
94 | struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb); | 93 | struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb); |
95 | 94 | ||
96 | if (mode != DRM_MODE_DPMS_ON) | 95 | drm_panel_enable(panel->panel); |
97 | mode = DRM_MODE_DPMS_OFF; | 96 | } |
98 | |||
99 | if (mode == rgb->dpms) | ||
100 | return; | ||
101 | 97 | ||
102 | if (mode != DRM_MODE_DPMS_ON) | 98 | static void atmel_hlcdc_panel_encoder_disable(struct drm_encoder *encoder) |
103 | drm_panel_disable(panel->panel); | 99 | { |
104 | else | 100 | struct atmel_hlcdc_rgb_output *rgb = |
105 | drm_panel_enable(panel->panel); | 101 | drm_encoder_to_atmel_hlcdc_rgb_output(encoder); |
102 | struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb); | ||
106 | 103 | ||
107 | rgb->dpms = mode; | 104 | drm_panel_disable(panel->panel); |
108 | } | 105 | } |
109 | 106 | ||
110 | static bool | 107 | static bool |
@@ -115,16 +112,6 @@ atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder, | |||
115 | return true; | 112 | return true; |
116 | } | 113 | } |
117 | 114 | ||
118 | static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder) | ||
119 | { | ||
120 | atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); | ||
121 | } | ||
122 | |||
123 | static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder) | ||
124 | { | ||
125 | atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON); | ||
126 | } | ||
127 | |||
128 | static void | 115 | static void |
129 | atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder, | 116 | atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder, |
130 | struct drm_display_mode *mode, | 117 | struct drm_display_mode *mode, |
@@ -156,11 +143,10 @@ atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder, | |||
156 | } | 143 | } |
157 | 144 | ||
158 | static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = { | 145 | static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = { |
159 | .dpms = atmel_hlcdc_panel_encoder_dpms, | ||
160 | .mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup, | 146 | .mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup, |
161 | .prepare = atmel_hlcdc_panel_encoder_prepare, | ||
162 | .commit = atmel_hlcdc_panel_encoder_commit, | ||
163 | .mode_set = atmel_hlcdc_rgb_encoder_mode_set, | 147 | .mode_set = atmel_hlcdc_rgb_encoder_mode_set, |
148 | .disable = atmel_hlcdc_panel_encoder_disable, | ||
149 | .enable = atmel_hlcdc_panel_encoder_enable, | ||
164 | }; | 150 | }; |
165 | 151 | ||
166 | static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder) | 152 | static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder) |
@@ -226,10 +212,13 @@ atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector) | |||
226 | } | 212 | } |
227 | 213 | ||
228 | static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = { | 214 | static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = { |
229 | .dpms = drm_helper_connector_dpms, | 215 | .dpms = drm_atomic_helper_connector_dpms, |
230 | .detect = atmel_hlcdc_panel_connector_detect, | 216 | .detect = atmel_hlcdc_panel_connector_detect, |
231 | .fill_modes = drm_helper_probe_single_connector_modes, | 217 | .fill_modes = drm_helper_probe_single_connector_modes, |
232 | .destroy = atmel_hlcdc_panel_connector_destroy, | 218 | .destroy = atmel_hlcdc_panel_connector_destroy, |
219 | .reset = drm_atomic_helper_connector_reset, | ||
220 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, | ||
221 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | ||
233 | }; | 222 | }; |
234 | 223 | ||
235 | static int atmel_hlcdc_create_panel_output(struct drm_device *dev, | 224 | static int atmel_hlcdc_create_panel_output(struct drm_device *dev, |
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c index c5892dcfd745..6c6fcaef356d 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c | |||
@@ -19,6 +19,52 @@ | |||
19 | 19 | ||
20 | #include "atmel_hlcdc_dc.h" | 20 | #include "atmel_hlcdc_dc.h" |
21 | 21 | ||
22 | /** | ||
23 | * Atmel HLCDC Plane state structure. | ||
24 | * | ||
25 | * @base: DRM plane state | ||
26 | * @crtc_x: x position of the plane relative to the CRTC | ||
27 | * @crtc_y: y position of the plane relative to the CRTC | ||
28 | * @crtc_w: visible width of the plane | ||
29 | * @crtc_h: visible height of the plane | ||
30 | * @src_x: x buffer position | ||
31 | * @src_y: y buffer position | ||
32 | * @src_w: buffer width | ||
33 | * @src_h: buffer height | ||
34 | * @alpha: alpha blending of the plane | ||
35 | * @bpp: bytes per pixel deduced from pixel_format | ||
36 | * @offsets: offsets to apply to the GEM buffers | ||
37 | * @xstride: value to add to the pixel pointer between each line | ||
38 | * @pstride: value to add to the pixel pointer between each pixel | ||
39 | * @nplanes: number of planes (deduced from pixel_format) | ||
40 | */ | ||
41 | struct atmel_hlcdc_plane_state { | ||
42 | struct drm_plane_state base; | ||
43 | int crtc_x; | ||
44 | int crtc_y; | ||
45 | unsigned int crtc_w; | ||
46 | unsigned int crtc_h; | ||
47 | uint32_t src_x; | ||
48 | uint32_t src_y; | ||
49 | uint32_t src_w; | ||
50 | uint32_t src_h; | ||
51 | |||
52 | u8 alpha; | ||
53 | |||
54 | /* These fields are private and should not be touched */ | ||
55 | int bpp[ATMEL_HLCDC_MAX_PLANES]; | ||
56 | unsigned int offsets[ATMEL_HLCDC_MAX_PLANES]; | ||
57 | int xstride[ATMEL_HLCDC_MAX_PLANES]; | ||
58 | int pstride[ATMEL_HLCDC_MAX_PLANES]; | ||
59 | int nplanes; | ||
60 | }; | ||
61 | |||
62 | static inline struct atmel_hlcdc_plane_state * | ||
63 | drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s) | ||
64 | { | ||
65 | return container_of(s, struct atmel_hlcdc_plane_state, base); | ||
66 | } | ||
67 | |||
22 | #define SUBPIXEL_MASK 0xffff | 68 | #define SUBPIXEL_MASK 0xffff |
23 | 69 | ||
24 | static uint32_t rgb_formats[] = { | 70 | static uint32_t rgb_formats[] = { |
@@ -128,7 +174,7 @@ static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode) | |||
128 | return 0; | 174 | return 0; |
129 | } | 175 | } |
130 | 176 | ||
131 | static bool atmel_hlcdc_format_embedds_alpha(u32 format) | 177 | static bool atmel_hlcdc_format_embeds_alpha(u32 format) |
132 | { | 178 | { |
133 | int i; | 179 | int i; |
134 | 180 | ||
@@ -204,7 +250,7 @@ static u32 heo_upscaling_ycoef[] = { | |||
204 | 250 | ||
205 | static void | 251 | static void |
206 | atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane, | 252 | atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane, |
207 | struct atmel_hlcdc_plane_update_req *req) | 253 | struct atmel_hlcdc_plane_state *state) |
208 | { | 254 | { |
209 | const struct atmel_hlcdc_layer_cfg_layout *layout = | 255 | const struct atmel_hlcdc_layer_cfg_layout *layout = |
210 | &plane->layer.desc->layout; | 256 | &plane->layer.desc->layout; |
@@ -213,69 +259,69 @@ atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane, | |||
213 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 259 | atmel_hlcdc_layer_update_cfg(&plane->layer, |
214 | layout->size, | 260 | layout->size, |
215 | 0xffffffff, | 261 | 0xffffffff, |
216 | (req->crtc_w - 1) | | 262 | (state->crtc_w - 1) | |
217 | ((req->crtc_h - 1) << 16)); | 263 | ((state->crtc_h - 1) << 16)); |
218 | 264 | ||
219 | if (layout->memsize) | 265 | if (layout->memsize) |
220 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 266 | atmel_hlcdc_layer_update_cfg(&plane->layer, |
221 | layout->memsize, | 267 | layout->memsize, |
222 | 0xffffffff, | 268 | 0xffffffff, |
223 | (req->src_w - 1) | | 269 | (state->src_w - 1) | |
224 | ((req->src_h - 1) << 16)); | 270 | ((state->src_h - 1) << 16)); |
225 | 271 | ||
226 | if (layout->pos) | 272 | if (layout->pos) |
227 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 273 | atmel_hlcdc_layer_update_cfg(&plane->layer, |
228 | layout->pos, | 274 | layout->pos, |
229 | 0xffffffff, | 275 | 0xffffffff, |
230 | req->crtc_x | | 276 | state->crtc_x | |
231 | (req->crtc_y << 16)); | 277 | (state->crtc_y << 16)); |
232 | 278 | ||
233 | /* TODO: rework the rescaling part */ | 279 | /* TODO: rework the rescaling part */ |
234 | if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) { | 280 | if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) { |
235 | u32 factor_reg = 0; | 281 | u32 factor_reg = 0; |
236 | 282 | ||
237 | if (req->crtc_w != req->src_w) { | 283 | if (state->crtc_w != state->src_w) { |
238 | int i; | 284 | int i; |
239 | u32 factor; | 285 | u32 factor; |
240 | u32 *coeff_tab = heo_upscaling_xcoef; | 286 | u32 *coeff_tab = heo_upscaling_xcoef; |
241 | u32 max_memsize; | 287 | u32 max_memsize; |
242 | 288 | ||
243 | if (req->crtc_w < req->src_w) | 289 | if (state->crtc_w < state->src_w) |
244 | coeff_tab = heo_downscaling_xcoef; | 290 | coeff_tab = heo_downscaling_xcoef; |
245 | for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++) | 291 | for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++) |
246 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 292 | atmel_hlcdc_layer_update_cfg(&plane->layer, |
247 | 17 + i, | 293 | 17 + i, |
248 | 0xffffffff, | 294 | 0xffffffff, |
249 | coeff_tab[i]); | 295 | coeff_tab[i]); |
250 | factor = ((8 * 256 * req->src_w) - (256 * 4)) / | 296 | factor = ((8 * 256 * state->src_w) - (256 * 4)) / |
251 | req->crtc_w; | 297 | state->crtc_w; |
252 | factor++; | 298 | factor++; |
253 | max_memsize = ((factor * req->crtc_w) + (256 * 4)) / | 299 | max_memsize = ((factor * state->crtc_w) + (256 * 4)) / |
254 | 2048; | 300 | 2048; |
255 | if (max_memsize > req->src_w) | 301 | if (max_memsize > state->src_w) |
256 | factor--; | 302 | factor--; |
257 | factor_reg |= factor | 0x80000000; | 303 | factor_reg |= factor | 0x80000000; |
258 | } | 304 | } |
259 | 305 | ||
260 | if (req->crtc_h != req->src_h) { | 306 | if (state->crtc_h != state->src_h) { |
261 | int i; | 307 | int i; |
262 | u32 factor; | 308 | u32 factor; |
263 | u32 *coeff_tab = heo_upscaling_ycoef; | 309 | u32 *coeff_tab = heo_upscaling_ycoef; |
264 | u32 max_memsize; | 310 | u32 max_memsize; |
265 | 311 | ||
266 | if (req->crtc_w < req->src_w) | 312 | if (state->crtc_w < state->src_w) |
267 | coeff_tab = heo_downscaling_ycoef; | 313 | coeff_tab = heo_downscaling_ycoef; |
268 | for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++) | 314 | for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++) |
269 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 315 | atmel_hlcdc_layer_update_cfg(&plane->layer, |
270 | 33 + i, | 316 | 33 + i, |
271 | 0xffffffff, | 317 | 0xffffffff, |
272 | coeff_tab[i]); | 318 | coeff_tab[i]); |
273 | factor = ((8 * 256 * req->src_w) - (256 * 4)) / | 319 | factor = ((8 * 256 * state->src_w) - (256 * 4)) / |
274 | req->crtc_w; | 320 | state->crtc_w; |
275 | factor++; | 321 | factor++; |
276 | max_memsize = ((factor * req->crtc_w) + (256 * 4)) / | 322 | max_memsize = ((factor * state->crtc_w) + (256 * 4)) / |
277 | 2048; | 323 | 2048; |
278 | if (max_memsize > req->src_w) | 324 | if (max_memsize > state->src_w) |
279 | factor--; | 325 | factor--; |
280 | factor_reg |= (factor << 16) | 0x80000000; | 326 | factor_reg |= (factor << 16) | 0x80000000; |
281 | } | 327 | } |
@@ -287,7 +333,7 @@ atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane, | |||
287 | 333 | ||
288 | static void | 334 | static void |
289 | atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, | 335 | atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, |
290 | struct atmel_hlcdc_plane_update_req *req) | 336 | struct atmel_hlcdc_plane_state *state) |
291 | { | 337 | { |
292 | const struct atmel_hlcdc_layer_cfg_layout *layout = | 338 | const struct atmel_hlcdc_layer_cfg_layout *layout = |
293 | &plane->layer.desc->layout; | 339 | &plane->layer.desc->layout; |
@@ -297,10 +343,11 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, | |||
297 | cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL | | 343 | cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL | |
298 | ATMEL_HLCDC_LAYER_ITER; | 344 | ATMEL_HLCDC_LAYER_ITER; |
299 | 345 | ||
300 | if (atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format)) | 346 | if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)) |
301 | cfg |= ATMEL_HLCDC_LAYER_LAEN; | 347 | cfg |= ATMEL_HLCDC_LAYER_LAEN; |
302 | else | 348 | else |
303 | cfg |= ATMEL_HLCDC_LAYER_GAEN; | 349 | cfg |= ATMEL_HLCDC_LAYER_GAEN | |
350 | ATMEL_HLCDC_LAYER_GA(state->alpha); | ||
304 | } | 351 | } |
305 | 352 | ||
306 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 353 | atmel_hlcdc_layer_update_cfg(&plane->layer, |
@@ -312,24 +359,26 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, | |||
312 | ATMEL_HLCDC_LAYER_ITER2BL | | 359 | ATMEL_HLCDC_LAYER_ITER2BL | |
313 | ATMEL_HLCDC_LAYER_ITER | | 360 | ATMEL_HLCDC_LAYER_ITER | |
314 | ATMEL_HLCDC_LAYER_GAEN | | 361 | ATMEL_HLCDC_LAYER_GAEN | |
362 | ATMEL_HLCDC_LAYER_GA_MASK | | ||
315 | ATMEL_HLCDC_LAYER_LAEN | | 363 | ATMEL_HLCDC_LAYER_LAEN | |
316 | ATMEL_HLCDC_LAYER_OVR | | 364 | ATMEL_HLCDC_LAYER_OVR | |
317 | ATMEL_HLCDC_LAYER_DMA, cfg); | 365 | ATMEL_HLCDC_LAYER_DMA, cfg); |
318 | } | 366 | } |
319 | 367 | ||
320 | static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane, | 368 | static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane, |
321 | struct atmel_hlcdc_plane_update_req *req) | 369 | struct atmel_hlcdc_plane_state *state) |
322 | { | 370 | { |
323 | u32 cfg; | 371 | u32 cfg; |
324 | int ret; | 372 | int ret; |
325 | 373 | ||
326 | ret = atmel_hlcdc_format_to_plane_mode(req->fb->pixel_format, &cfg); | 374 | ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format, |
375 | &cfg); | ||
327 | if (ret) | 376 | if (ret) |
328 | return; | 377 | return; |
329 | 378 | ||
330 | if ((req->fb->pixel_format == DRM_FORMAT_YUV422 || | 379 | if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 || |
331 | req->fb->pixel_format == DRM_FORMAT_NV61) && | 380 | state->base.fb->pixel_format == DRM_FORMAT_NV61) && |
332 | (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270)))) | 381 | (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270)))) |
333 | cfg |= ATMEL_HLCDC_YUV422ROT; | 382 | cfg |= ATMEL_HLCDC_YUV422ROT; |
334 | 383 | ||
335 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 384 | atmel_hlcdc_layer_update_cfg(&plane->layer, |
@@ -341,7 +390,7 @@ static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane, | |||
341 | * Rotation optimization is not working on RGB888 (rotation is still | 390 | * Rotation optimization is not working on RGB888 (rotation is still |
342 | * working but without any optimization). | 391 | * working but without any optimization). |
343 | */ | 392 | */ |
344 | if (req->fb->pixel_format == DRM_FORMAT_RGB888) | 393 | if (state->base.fb->pixel_format == DRM_FORMAT_RGB888) |
345 | cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS; | 394 | cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS; |
346 | else | 395 | else |
347 | cfg = 0; | 396 | cfg = 0; |
@@ -352,73 +401,44 @@ static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane, | |||
352 | } | 401 | } |
353 | 402 | ||
354 | static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane, | 403 | static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane, |
355 | struct atmel_hlcdc_plane_update_req *req) | 404 | struct atmel_hlcdc_plane_state *state) |
356 | { | 405 | { |
357 | struct atmel_hlcdc_layer *layer = &plane->layer; | 406 | struct atmel_hlcdc_layer *layer = &plane->layer; |
358 | const struct atmel_hlcdc_layer_cfg_layout *layout = | 407 | const struct atmel_hlcdc_layer_cfg_layout *layout = |
359 | &layer->desc->layout; | 408 | &layer->desc->layout; |
360 | int i; | 409 | int i; |
361 | 410 | ||
362 | atmel_hlcdc_layer_update_set_fb(&plane->layer, req->fb, req->offsets); | 411 | atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb, |
412 | state->offsets); | ||
363 | 413 | ||
364 | for (i = 0; i < req->nplanes; i++) { | 414 | for (i = 0; i < state->nplanes; i++) { |
365 | if (layout->xstride[i]) { | 415 | if (layout->xstride[i]) { |
366 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 416 | atmel_hlcdc_layer_update_cfg(&plane->layer, |
367 | layout->xstride[i], | 417 | layout->xstride[i], |
368 | 0xffffffff, | 418 | 0xffffffff, |
369 | req->xstride[i]); | 419 | state->xstride[i]); |
370 | } | 420 | } |
371 | 421 | ||
372 | if (layout->pstride[i]) { | 422 | if (layout->pstride[i]) { |
373 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 423 | atmel_hlcdc_layer_update_cfg(&plane->layer, |
374 | layout->pstride[i], | 424 | layout->pstride[i], |
375 | 0xffffffff, | 425 | 0xffffffff, |
376 | req->pstride[i]); | 426 | state->pstride[i]); |
377 | } | 427 | } |
378 | } | 428 | } |
379 | } | 429 | } |
380 | 430 | ||
381 | static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p, | 431 | static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p, |
382 | struct atmel_hlcdc_plane_update_req *req, | 432 | struct drm_plane_state *s) |
383 | const struct drm_display_mode *mode) | ||
384 | { | 433 | { |
385 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); | 434 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); |
435 | struct atmel_hlcdc_plane_state *state = | ||
436 | drm_plane_state_to_atmel_hlcdc_plane_state(s); | ||
386 | const struct atmel_hlcdc_layer_cfg_layout *layout = | 437 | const struct atmel_hlcdc_layer_cfg_layout *layout = |
387 | &plane->layer.desc->layout; | 438 | &plane->layer.desc->layout; |
388 | 439 | struct drm_framebuffer *fb = state->base.fb; | |
389 | if (!layout->size && | 440 | const struct drm_display_mode *mode; |
390 | (mode->hdisplay != req->crtc_w || | 441 | struct drm_crtc_state *crtc_state; |
391 | mode->vdisplay != req->crtc_h)) | ||
392 | return -EINVAL; | ||
393 | |||
394 | if (plane->layer.desc->max_height && | ||
395 | req->crtc_h > plane->layer.desc->max_height) | ||
396 | return -EINVAL; | ||
397 | |||
398 | if (plane->layer.desc->max_width && | ||
399 | req->crtc_w > plane->layer.desc->max_width) | ||
400 | return -EINVAL; | ||
401 | |||
402 | if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) && | ||
403 | (!layout->memsize || | ||
404 | atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format))) | ||
405 | return -EINVAL; | ||
406 | |||
407 | if (req->crtc_x < 0 || req->crtc_y < 0) | ||
408 | return -EINVAL; | ||
409 | |||
410 | if (req->crtc_w + req->crtc_x > mode->hdisplay || | ||
411 | req->crtc_h + req->crtc_y > mode->vdisplay) | ||
412 | return -EINVAL; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p, | ||
418 | struct atmel_hlcdc_plane_update_req *req, | ||
419 | const struct drm_display_mode *mode) | ||
420 | { | ||
421 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); | ||
422 | unsigned int patched_crtc_w; | 442 | unsigned int patched_crtc_w; |
423 | unsigned int patched_crtc_h; | 443 | unsigned int patched_crtc_h; |
424 | unsigned int patched_src_w; | 444 | unsigned int patched_src_w; |
@@ -430,196 +450,194 @@ int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p, | |||
430 | int vsub = 1; | 450 | int vsub = 1; |
431 | int i; | 451 | int i; |
432 | 452 | ||
433 | if ((req->src_x | req->src_y | req->src_w | req->src_h) & | 453 | if (!state->base.crtc || !fb) |
454 | return 0; | ||
455 | |||
456 | crtc_state = s->state->crtc_states[drm_crtc_index(s->crtc)]; | ||
457 | mode = &crtc_state->adjusted_mode; | ||
458 | |||
459 | state->src_x = s->src_x; | ||
460 | state->src_y = s->src_y; | ||
461 | state->src_h = s->src_h; | ||
462 | state->src_w = s->src_w; | ||
463 | state->crtc_x = s->crtc_x; | ||
464 | state->crtc_y = s->crtc_y; | ||
465 | state->crtc_h = s->crtc_h; | ||
466 | state->crtc_w = s->crtc_w; | ||
467 | if ((state->src_x | state->src_y | state->src_w | state->src_h) & | ||
434 | SUBPIXEL_MASK) | 468 | SUBPIXEL_MASK) |
435 | return -EINVAL; | 469 | return -EINVAL; |
436 | 470 | ||
437 | req->src_x >>= 16; | 471 | state->src_x >>= 16; |
438 | req->src_y >>= 16; | 472 | state->src_y >>= 16; |
439 | req->src_w >>= 16; | 473 | state->src_w >>= 16; |
440 | req->src_h >>= 16; | 474 | state->src_h >>= 16; |
441 | 475 | ||
442 | req->nplanes = drm_format_num_planes(req->fb->pixel_format); | 476 | state->nplanes = drm_format_num_planes(fb->pixel_format); |
443 | if (req->nplanes > ATMEL_HLCDC_MAX_PLANES) | 477 | if (state->nplanes > ATMEL_HLCDC_MAX_PLANES) |
444 | return -EINVAL; | 478 | return -EINVAL; |
445 | 479 | ||
446 | /* | 480 | /* |
447 | * Swap width and size in case of 90 or 270 degrees rotation | 481 | * Swap width and size in case of 90 or 270 degrees rotation |
448 | */ | 482 | */ |
449 | if (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) { | 483 | if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) { |
450 | tmp = req->crtc_w; | 484 | tmp = state->crtc_w; |
451 | req->crtc_w = req->crtc_h; | 485 | state->crtc_w = state->crtc_h; |
452 | req->crtc_h = tmp; | 486 | state->crtc_h = tmp; |
453 | tmp = req->src_w; | 487 | tmp = state->src_w; |
454 | req->src_w = req->src_h; | 488 | state->src_w = state->src_h; |
455 | req->src_h = tmp; | 489 | state->src_h = tmp; |
456 | } | 490 | } |
457 | 491 | ||
458 | if (req->crtc_x + req->crtc_w > mode->hdisplay) | 492 | if (state->crtc_x + state->crtc_w > mode->hdisplay) |
459 | patched_crtc_w = mode->hdisplay - req->crtc_x; | 493 | patched_crtc_w = mode->hdisplay - state->crtc_x; |
460 | else | 494 | else |
461 | patched_crtc_w = req->crtc_w; | 495 | patched_crtc_w = state->crtc_w; |
462 | 496 | ||
463 | if (req->crtc_x < 0) { | 497 | if (state->crtc_x < 0) { |
464 | patched_crtc_w += req->crtc_x; | 498 | patched_crtc_w += state->crtc_x; |
465 | x_offset = -req->crtc_x; | 499 | x_offset = -state->crtc_x; |
466 | req->crtc_x = 0; | 500 | state->crtc_x = 0; |
467 | } | 501 | } |
468 | 502 | ||
469 | if (req->crtc_y + req->crtc_h > mode->vdisplay) | 503 | if (state->crtc_y + state->crtc_h > mode->vdisplay) |
470 | patched_crtc_h = mode->vdisplay - req->crtc_y; | 504 | patched_crtc_h = mode->vdisplay - state->crtc_y; |
471 | else | 505 | else |
472 | patched_crtc_h = req->crtc_h; | 506 | patched_crtc_h = state->crtc_h; |
473 | 507 | ||
474 | if (req->crtc_y < 0) { | 508 | if (state->crtc_y < 0) { |
475 | patched_crtc_h += req->crtc_y; | 509 | patched_crtc_h += state->crtc_y; |
476 | y_offset = -req->crtc_y; | 510 | y_offset = -state->crtc_y; |
477 | req->crtc_y = 0; | 511 | state->crtc_y = 0; |
478 | } | 512 | } |
479 | 513 | ||
480 | patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w, | 514 | patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w, |
481 | req->crtc_w); | 515 | state->crtc_w); |
482 | patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h, | 516 | patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h, |
483 | req->crtc_h); | 517 | state->crtc_h); |
484 | 518 | ||
485 | hsub = drm_format_horz_chroma_subsampling(req->fb->pixel_format); | 519 | hsub = drm_format_horz_chroma_subsampling(fb->pixel_format); |
486 | vsub = drm_format_vert_chroma_subsampling(req->fb->pixel_format); | 520 | vsub = drm_format_vert_chroma_subsampling(fb->pixel_format); |
487 | 521 | ||
488 | for (i = 0; i < req->nplanes; i++) { | 522 | for (i = 0; i < state->nplanes; i++) { |
489 | unsigned int offset = 0; | 523 | unsigned int offset = 0; |
490 | int xdiv = i ? hsub : 1; | 524 | int xdiv = i ? hsub : 1; |
491 | int ydiv = i ? vsub : 1; | 525 | int ydiv = i ? vsub : 1; |
492 | 526 | ||
493 | req->bpp[i] = drm_format_plane_cpp(req->fb->pixel_format, i); | 527 | state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i); |
494 | if (!req->bpp[i]) | 528 | if (!state->bpp[i]) |
495 | return -EINVAL; | 529 | return -EINVAL; |
496 | 530 | ||
497 | switch (plane->rotation & 0xf) { | 531 | switch (state->base.rotation & 0xf) { |
498 | case BIT(DRM_ROTATE_90): | 532 | case BIT(DRM_ROTATE_90): |
499 | offset = ((y_offset + req->src_y + patched_src_w - 1) / | 533 | offset = ((y_offset + state->src_y + patched_src_w - 1) / |
500 | ydiv) * req->fb->pitches[i]; | 534 | ydiv) * fb->pitches[i]; |
501 | offset += ((x_offset + req->src_x) / xdiv) * | 535 | offset += ((x_offset + state->src_x) / xdiv) * |
502 | req->bpp[i]; | 536 | state->bpp[i]; |
503 | req->xstride[i] = ((patched_src_w - 1) / ydiv) * | 537 | state->xstride[i] = ((patched_src_w - 1) / ydiv) * |
504 | req->fb->pitches[i]; | 538 | fb->pitches[i]; |
505 | req->pstride[i] = -req->fb->pitches[i] - req->bpp[i]; | 539 | state->pstride[i] = -fb->pitches[i] - state->bpp[i]; |
506 | break; | 540 | break; |
507 | case BIT(DRM_ROTATE_180): | 541 | case BIT(DRM_ROTATE_180): |
508 | offset = ((y_offset + req->src_y + patched_src_h - 1) / | 542 | offset = ((y_offset + state->src_y + patched_src_h - 1) / |
509 | ydiv) * req->fb->pitches[i]; | 543 | ydiv) * fb->pitches[i]; |
510 | offset += ((x_offset + req->src_x + patched_src_w - 1) / | 544 | offset += ((x_offset + state->src_x + patched_src_w - 1) / |
511 | xdiv) * req->bpp[i]; | 545 | xdiv) * state->bpp[i]; |
512 | req->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) * | 546 | state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) * |
513 | req->bpp[i]) - req->fb->pitches[i]; | 547 | state->bpp[i]) - fb->pitches[i]; |
514 | req->pstride[i] = -2 * req->bpp[i]; | 548 | state->pstride[i] = -2 * state->bpp[i]; |
515 | break; | 549 | break; |
516 | case BIT(DRM_ROTATE_270): | 550 | case BIT(DRM_ROTATE_270): |
517 | offset = ((y_offset + req->src_y) / ydiv) * | 551 | offset = ((y_offset + state->src_y) / ydiv) * |
518 | req->fb->pitches[i]; | 552 | fb->pitches[i]; |
519 | offset += ((x_offset + req->src_x + patched_src_h - 1) / | 553 | offset += ((x_offset + state->src_x + patched_src_h - 1) / |
520 | xdiv) * req->bpp[i]; | 554 | xdiv) * state->bpp[i]; |
521 | req->xstride[i] = -(((patched_src_w - 1) / ydiv) * | 555 | state->xstride[i] = -(((patched_src_w - 1) / ydiv) * |
522 | req->fb->pitches[i]) - | 556 | fb->pitches[i]) - |
523 | (2 * req->bpp[i]); | 557 | (2 * state->bpp[i]); |
524 | req->pstride[i] = req->fb->pitches[i] - req->bpp[i]; | 558 | state->pstride[i] = fb->pitches[i] - state->bpp[i]; |
525 | break; | 559 | break; |
526 | case BIT(DRM_ROTATE_0): | 560 | case BIT(DRM_ROTATE_0): |
527 | default: | 561 | default: |
528 | offset = ((y_offset + req->src_y) / ydiv) * | 562 | offset = ((y_offset + state->src_y) / ydiv) * |
529 | req->fb->pitches[i]; | 563 | fb->pitches[i]; |
530 | offset += ((x_offset + req->src_x) / xdiv) * | 564 | offset += ((x_offset + state->src_x) / xdiv) * |
531 | req->bpp[i]; | 565 | state->bpp[i]; |
532 | req->xstride[i] = req->fb->pitches[i] - | 566 | state->xstride[i] = fb->pitches[i] - |
533 | ((patched_src_w / xdiv) * | 567 | ((patched_src_w / xdiv) * |
534 | req->bpp[i]); | 568 | state->bpp[i]); |
535 | req->pstride[i] = 0; | 569 | state->pstride[i] = 0; |
536 | break; | 570 | break; |
537 | } | 571 | } |
538 | 572 | ||
539 | req->offsets[i] = offset + req->fb->offsets[i]; | 573 | state->offsets[i] = offset + fb->offsets[i]; |
540 | } | 574 | } |
541 | 575 | ||
542 | req->src_w = patched_src_w; | 576 | state->src_w = patched_src_w; |
543 | req->src_h = patched_src_h; | 577 | state->src_h = patched_src_h; |
544 | req->crtc_w = patched_crtc_w; | 578 | state->crtc_w = patched_crtc_w; |
545 | req->crtc_h = patched_crtc_h; | 579 | state->crtc_h = patched_crtc_h; |
546 | 580 | ||
547 | return atmel_hlcdc_plane_check_update_req(p, req, mode); | 581 | if (!layout->size && |
548 | } | 582 | (mode->hdisplay != state->crtc_w || |
583 | mode->vdisplay != state->crtc_h)) | ||
584 | return -EINVAL; | ||
549 | 585 | ||
550 | int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p, | 586 | if (plane->layer.desc->max_height && |
551 | struct atmel_hlcdc_plane_update_req *req) | 587 | state->crtc_h > plane->layer.desc->max_height) |
552 | { | 588 | return -EINVAL; |
553 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); | ||
554 | int ret; | ||
555 | 589 | ||
556 | ret = atmel_hlcdc_layer_update_start(&plane->layer); | 590 | if (plane->layer.desc->max_width && |
557 | if (ret) | 591 | state->crtc_w > plane->layer.desc->max_width) |
558 | return ret; | 592 | return -EINVAL; |
559 | 593 | ||
560 | atmel_hlcdc_plane_update_pos_and_size(plane, req); | 594 | if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) && |
561 | atmel_hlcdc_plane_update_general_settings(plane, req); | 595 | (!layout->memsize || |
562 | atmel_hlcdc_plane_update_format(plane, req); | 596 | atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))) |
563 | atmel_hlcdc_plane_update_buffers(plane, req); | 597 | return -EINVAL; |
564 | 598 | ||
565 | atmel_hlcdc_layer_update_commit(&plane->layer); | 599 | if (state->crtc_x < 0 || state->crtc_y < 0) |
600 | return -EINVAL; | ||
601 | |||
602 | if (state->crtc_w + state->crtc_x > mode->hdisplay || | ||
603 | state->crtc_h + state->crtc_y > mode->vdisplay) | ||
604 | return -EINVAL; | ||
566 | 605 | ||
567 | return 0; | 606 | return 0; |
568 | } | 607 | } |
569 | 608 | ||
570 | int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p, | 609 | static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p, |
571 | struct drm_crtc *crtc, | 610 | struct drm_framebuffer *fb) |
572 | struct drm_framebuffer *fb, | ||
573 | int crtc_x, int crtc_y, | ||
574 | unsigned int crtc_w, | ||
575 | unsigned int crtc_h, | ||
576 | uint32_t src_x, uint32_t src_y, | ||
577 | uint32_t src_w, uint32_t src_h, | ||
578 | const struct drm_display_mode *mode) | ||
579 | { | 611 | { |
580 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); | 612 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); |
581 | struct atmel_hlcdc_plane_update_req req; | ||
582 | int ret = 0; | ||
583 | |||
584 | memset(&req, 0, sizeof(req)); | ||
585 | req.crtc_x = crtc_x; | ||
586 | req.crtc_y = crtc_y; | ||
587 | req.crtc_w = crtc_w; | ||
588 | req.crtc_h = crtc_h; | ||
589 | req.src_x = src_x; | ||
590 | req.src_y = src_y; | ||
591 | req.src_w = src_w; | ||
592 | req.src_h = src_h; | ||
593 | req.fb = fb; | ||
594 | |||
595 | ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req, mode); | ||
596 | if (ret) | ||
597 | return ret; | ||
598 | 613 | ||
599 | if (!req.crtc_h || !req.crtc_w) | 614 | return atmel_hlcdc_layer_update_start(&plane->layer); |
600 | return atmel_hlcdc_layer_disable(&plane->layer); | ||
601 | |||
602 | return atmel_hlcdc_plane_apply_update_req(&plane->base, &req); | ||
603 | } | 615 | } |
604 | 616 | ||
605 | static int atmel_hlcdc_plane_update(struct drm_plane *p, | 617 | static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p, |
606 | struct drm_crtc *crtc, | 618 | struct drm_plane_state *old_s) |
607 | struct drm_framebuffer *fb, | ||
608 | int crtc_x, int crtc_y, | ||
609 | unsigned int crtc_w, unsigned int crtc_h, | ||
610 | uint32_t src_x, uint32_t src_y, | ||
611 | uint32_t src_w, uint32_t src_h) | ||
612 | { | 619 | { |
613 | return atmel_hlcdc_plane_update_with_mode(p, crtc, fb, crtc_x, crtc_y, | 620 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); |
614 | crtc_w, crtc_h, src_x, src_y, | 621 | struct atmel_hlcdc_plane_state *state = |
615 | src_w, src_h, &crtc->hwmode); | 622 | drm_plane_state_to_atmel_hlcdc_plane_state(p->state); |
623 | |||
624 | if (!p->state->crtc || !p->state->fb) | ||
625 | return; | ||
626 | |||
627 | atmel_hlcdc_plane_update_pos_and_size(plane, state); | ||
628 | atmel_hlcdc_plane_update_general_settings(plane, state); | ||
629 | atmel_hlcdc_plane_update_format(plane, state); | ||
630 | atmel_hlcdc_plane_update_buffers(plane, state); | ||
631 | |||
632 | atmel_hlcdc_layer_update_commit(&plane->layer); | ||
616 | } | 633 | } |
617 | 634 | ||
618 | static int atmel_hlcdc_plane_disable(struct drm_plane *p) | 635 | static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p, |
636 | struct drm_plane_state *old_state) | ||
619 | { | 637 | { |
620 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); | 638 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); |
621 | 639 | ||
622 | return atmel_hlcdc_layer_disable(&plane->layer); | 640 | atmel_hlcdc_layer_disable(&plane->layer); |
623 | } | 641 | } |
624 | 642 | ||
625 | static void atmel_hlcdc_plane_destroy(struct drm_plane *p) | 643 | static void atmel_hlcdc_plane_destroy(struct drm_plane *p) |
@@ -635,38 +653,36 @@ static void atmel_hlcdc_plane_destroy(struct drm_plane *p) | |||
635 | devm_kfree(p->dev->dev, plane); | 653 | devm_kfree(p->dev->dev, plane); |
636 | } | 654 | } |
637 | 655 | ||
638 | static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane, | 656 | static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p, |
639 | u8 alpha) | 657 | struct drm_plane_state *s, |
658 | struct drm_property *property, | ||
659 | uint64_t val) | ||
640 | { | 660 | { |
641 | atmel_hlcdc_layer_update_start(&plane->layer); | 661 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); |
642 | atmel_hlcdc_layer_update_cfg(&plane->layer, | 662 | struct atmel_hlcdc_plane_properties *props = plane->properties; |
643 | plane->layer.desc->layout.general_config, | 663 | struct atmel_hlcdc_plane_state *state = |
644 | ATMEL_HLCDC_LAYER_GA_MASK, | 664 | drm_plane_state_to_atmel_hlcdc_plane_state(s); |
645 | alpha << ATMEL_HLCDC_LAYER_GA_SHIFT); | ||
646 | atmel_hlcdc_layer_update_commit(&plane->layer); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | 665 | ||
651 | static int atmel_hlcdc_plane_set_rotation(struct atmel_hlcdc_plane *plane, | 666 | if (property == props->alpha) |
652 | unsigned int rotation) | 667 | state->alpha = val; |
653 | { | 668 | else |
654 | plane->rotation = rotation; | 669 | return -EINVAL; |
655 | 670 | ||
656 | return 0; | 671 | return 0; |
657 | } | 672 | } |
658 | 673 | ||
659 | static int atmel_hlcdc_plane_set_property(struct drm_plane *p, | 674 | static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p, |
660 | struct drm_property *property, | 675 | const struct drm_plane_state *s, |
661 | uint64_t value) | 676 | struct drm_property *property, |
677 | uint64_t *val) | ||
662 | { | 678 | { |
663 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); | 679 | struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); |
664 | struct atmel_hlcdc_plane_properties *props = plane->properties; | 680 | struct atmel_hlcdc_plane_properties *props = plane->properties; |
681 | const struct atmel_hlcdc_plane_state *state = | ||
682 | container_of(s, const struct atmel_hlcdc_plane_state, base); | ||
665 | 683 | ||
666 | if (property == props->alpha) | 684 | if (property == props->alpha) |
667 | atmel_hlcdc_plane_set_alpha(plane, value); | 685 | *val = state->alpha; |
668 | else if (property == props->rotation) | ||
669 | atmel_hlcdc_plane_set_rotation(plane, value); | ||
670 | else | 686 | else |
671 | return -EINVAL; | 687 | return -EINVAL; |
672 | 688 | ||
@@ -694,8 +710,8 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane, | |||
694 | 710 | ||
695 | if (desc->layout.xstride && desc->layout.pstride) | 711 | if (desc->layout.xstride && desc->layout.pstride) |
696 | drm_object_attach_property(&plane->base.base, | 712 | drm_object_attach_property(&plane->base.base, |
697 | props->rotation, | 713 | plane->base.dev->mode_config.rotation_property, |
698 | BIT(DRM_ROTATE_0)); | 714 | BIT(DRM_ROTATE_0)); |
699 | 715 | ||
700 | if (desc->layout.csc) { | 716 | if (desc->layout.csc) { |
701 | /* | 717 | /* |
@@ -717,11 +733,74 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane, | |||
717 | } | 733 | } |
718 | } | 734 | } |
719 | 735 | ||
736 | static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = { | ||
737 | .prepare_fb = atmel_hlcdc_plane_prepare_fb, | ||
738 | .atomic_check = atmel_hlcdc_plane_atomic_check, | ||
739 | .atomic_update = atmel_hlcdc_plane_atomic_update, | ||
740 | .atomic_disable = atmel_hlcdc_plane_atomic_disable, | ||
741 | }; | ||
742 | |||
743 | static void atmel_hlcdc_plane_reset(struct drm_plane *p) | ||
744 | { | ||
745 | struct atmel_hlcdc_plane_state *state; | ||
746 | |||
747 | if (p->state) { | ||
748 | state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state); | ||
749 | |||
750 | if (state->base.fb) | ||
751 | drm_framebuffer_unreference(state->base.fb); | ||
752 | |||
753 | kfree(state); | ||
754 | p->state = NULL; | ||
755 | } | ||
756 | |||
757 | state = kzalloc(sizeof(*state), GFP_KERNEL); | ||
758 | if (state) { | ||
759 | state->alpha = 255; | ||
760 | p->state = &state->base; | ||
761 | p->state->plane = p; | ||
762 | } | ||
763 | } | ||
764 | |||
765 | static struct drm_plane_state * | ||
766 | atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p) | ||
767 | { | ||
768 | struct atmel_hlcdc_plane_state *state = | ||
769 | drm_plane_state_to_atmel_hlcdc_plane_state(p->state); | ||
770 | struct atmel_hlcdc_plane_state *copy; | ||
771 | |||
772 | copy = kmemdup(state, sizeof(*state), GFP_KERNEL); | ||
773 | if (!copy) | ||
774 | return NULL; | ||
775 | |||
776 | if (copy->base.fb) | ||
777 | drm_framebuffer_reference(copy->base.fb); | ||
778 | |||
779 | return ©->base; | ||
780 | } | ||
781 | |||
782 | static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane, | ||
783 | struct drm_plane_state *s) | ||
784 | { | ||
785 | struct atmel_hlcdc_plane_state *state = | ||
786 | drm_plane_state_to_atmel_hlcdc_plane_state(s); | ||
787 | |||
788 | if (s->fb) | ||
789 | drm_framebuffer_unreference(s->fb); | ||
790 | |||
791 | kfree(state); | ||
792 | } | ||
793 | |||
720 | static struct drm_plane_funcs layer_plane_funcs = { | 794 | static struct drm_plane_funcs layer_plane_funcs = { |
721 | .update_plane = atmel_hlcdc_plane_update, | 795 | .update_plane = drm_atomic_helper_update_plane, |
722 | .disable_plane = atmel_hlcdc_plane_disable, | 796 | .disable_plane = drm_atomic_helper_disable_plane, |
723 | .set_property = atmel_hlcdc_plane_set_property, | 797 | .set_property = drm_atomic_helper_plane_set_property, |
724 | .destroy = atmel_hlcdc_plane_destroy, | 798 | .destroy = atmel_hlcdc_plane_destroy, |
799 | .reset = atmel_hlcdc_plane_reset, | ||
800 | .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state, | ||
801 | .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state, | ||
802 | .atomic_set_property = atmel_hlcdc_plane_atomic_set_property, | ||
803 | .atomic_get_property = atmel_hlcdc_plane_atomic_get_property, | ||
725 | }; | 804 | }; |
726 | 805 | ||
727 | static struct atmel_hlcdc_plane * | 806 | static struct atmel_hlcdc_plane * |
@@ -755,6 +834,9 @@ atmel_hlcdc_plane_create(struct drm_device *dev, | |||
755 | if (ret) | 834 | if (ret) |
756 | return ERR_PTR(ret); | 835 | return ERR_PTR(ret); |
757 | 836 | ||
837 | drm_plane_helper_add(&plane->base, | ||
838 | &atmel_hlcdc_layer_plane_helper_funcs); | ||
839 | |||
758 | /* Set default property values*/ | 840 | /* Set default property values*/ |
759 | atmel_hlcdc_plane_init_properties(plane, desc, props); | 841 | atmel_hlcdc_plane_init_properties(plane, desc, props); |
760 | 842 | ||
@@ -774,12 +856,13 @@ atmel_hlcdc_plane_create_properties(struct drm_device *dev) | |||
774 | if (!props->alpha) | 856 | if (!props->alpha) |
775 | return ERR_PTR(-ENOMEM); | 857 | return ERR_PTR(-ENOMEM); |
776 | 858 | ||
777 | props->rotation = drm_mode_create_rotation_property(dev, | 859 | dev->mode_config.rotation_property = |
778 | BIT(DRM_ROTATE_0) | | 860 | drm_mode_create_rotation_property(dev, |
779 | BIT(DRM_ROTATE_90) | | 861 | BIT(DRM_ROTATE_0) | |
780 | BIT(DRM_ROTATE_180) | | 862 | BIT(DRM_ROTATE_90) | |
781 | BIT(DRM_ROTATE_270)); | 863 | BIT(DRM_ROTATE_180) | |
782 | if (!props->rotation) | 864 | BIT(DRM_ROTATE_270)); |
865 | if (!dev->mode_config.rotation_property) | ||
783 | return ERR_PTR(-ENOMEM); | 866 | return ERR_PTR(-ENOMEM); |
784 | 867 | ||
785 | return props; | 868 | return props; |