aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c294
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c51
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h59
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c4
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h3
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c41
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c639
7 files changed, 605 insertions, 486 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..b81cea6baeea 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -21,6 +21,7 @@
21#include <linux/clk.h> 21#include <linux/clk.h>
22#include <linux/pm.h> 22#include <linux/pm.h>
23#include <linux/pm_runtime.h> 23#include <linux/pm_runtime.h>
24#include <linux/pinctrl/consumer.h>
24 25
25#include <drm/drm_crtc.h> 26#include <drm/drm_crtc.h>
26#include <drm/drm_crtc_helper.h> 27#include <drm/drm_crtc_helper.h>
@@ -37,14 +38,14 @@
37 * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device 38 * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
38 * @event: pointer to the current page flip event 39 * @event: pointer to the current page flip event
39 * @id: CRTC id (returned by drm_crtc_index) 40 * @id: CRTC id (returned by drm_crtc_index)
40 * @dpms: DPMS mode 41 * @enabled: CRTC state
41 */ 42 */
42struct atmel_hlcdc_crtc { 43struct atmel_hlcdc_crtc {
43 struct drm_crtc base; 44 struct drm_crtc base;
44 struct atmel_hlcdc_dc *dc; 45 struct atmel_hlcdc_dc *dc;
45 struct drm_pending_vblank_event *event; 46 struct drm_pending_vblank_event *event;
46 int id; 47 int id;
47 int dpms; 48 bool enabled;
48}; 49};
49 50
50static inline struct atmel_hlcdc_crtc * 51static inline struct atmel_hlcdc_crtc *
@@ -53,86 +54,17 @@ drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
53 return container_of(crtc, struct atmel_hlcdc_crtc, base); 54 return container_of(crtc, struct atmel_hlcdc_crtc, base);
54} 55}
55 56
56static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode) 57static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
57{
58 struct drm_device *dev = c->dev;
59 struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
60 struct regmap *regmap = crtc->dc->hlcdc->regmap;
61 unsigned int status;
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
117static 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{ 58{
123 struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); 59 struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
124 struct regmap *regmap = crtc->dc->hlcdc->regmap; 60 struct regmap *regmap = crtc->dc->hlcdc->regmap;
125 struct drm_plane *plane = c->primary; 61 struct drm_display_mode *adj = &c->state->adjusted_mode;
126 struct drm_framebuffer *fb;
127 unsigned long mode_rate; 62 unsigned long mode_rate;
128 struct videomode vm; 63 struct videomode vm;
129 unsigned long prate; 64 unsigned long prate;
130 unsigned int cfg; 65 unsigned int cfg;
131 int div; 66 int div;
132 67
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; 68 vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
137 vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end; 69 vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
138 vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start; 70 vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start;
@@ -156,7 +88,7 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
156 cfg = ATMEL_HLCDC_CLKPOL; 88 cfg = ATMEL_HLCDC_CLKPOL;
157 89
158 prate = clk_get_rate(crtc->dc->hlcdc->sys_clk); 90 prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
159 mode_rate = mode->crtc_clock * 1000; 91 mode_rate = adj->crtc_clock * 1000;
160 if ((prate / 2) < mode_rate) { 92 if ((prate / 2) < mode_rate) {
161 prate *= 2; 93 prate *= 2;
162 cfg |= ATMEL_HLCDC_CLKSEL; 94 cfg |= ATMEL_HLCDC_CLKSEL;
@@ -174,10 +106,10 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
174 106
175 cfg = 0; 107 cfg = 0;
176 108
177 if (mode->flags & DRM_MODE_FLAG_NVSYNC) 109 if (adj->flags & DRM_MODE_FLAG_NVSYNC)
178 cfg |= ATMEL_HLCDC_VSPOL; 110 cfg |= ATMEL_HLCDC_VSPOL;
179 111
180 if (mode->flags & DRM_MODE_FLAG_NHSYNC) 112 if (adj->flags & DRM_MODE_FLAG_NHSYNC)
181 cfg |= ATMEL_HLCDC_HSPOL; 113 cfg |= ATMEL_HLCDC_HSPOL;
182 114
183 regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5), 115 regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
@@ -187,77 +119,134 @@ static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
187 ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO | 119 ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
188 ATMEL_HLCDC_GUARDTIME_MASK, 120 ATMEL_HLCDC_GUARDTIME_MASK,
189 cfg); 121 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} 122}
201 123
202int atmel_hlcdc_crtc_mode_set_base(struct drm_crtc *c, int x, int y, 124static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
203 struct drm_framebuffer *old_fb) 125 const struct drm_display_mode *mode,
126 struct drm_display_mode *adjusted_mode)
204{ 127{
205 struct drm_plane *plane = c->primary; 128 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} 129}
219 130
220static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc) 131static void atmel_hlcdc_crtc_disable(struct drm_crtc *c)
221{ 132{
222 atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 133 struct drm_device *dev = c->dev;
134 struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
135 struct regmap *regmap = crtc->dc->hlcdc->regmap;
136 unsigned int status;
137
138 if (!crtc->enabled)
139 return;
140
141 drm_crtc_vblank_off(c);
142
143 pm_runtime_get_sync(dev->dev);
144
145 regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
146 while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
147 (status & ATMEL_HLCDC_DISP))
148 cpu_relax();
149
150 regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
151 while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
152 (status & ATMEL_HLCDC_SYNC))
153 cpu_relax();
154
155 regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
156 while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
157 (status & ATMEL_HLCDC_PIXEL_CLK))
158 cpu_relax();
159
160 clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
161 pinctrl_pm_select_sleep_state(dev->dev);
162
163 pm_runtime_allow(dev->dev);
164
165 pm_runtime_put_sync(dev->dev);
166
167 crtc->enabled = false;
223} 168}
224 169
225static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc) 170static void atmel_hlcdc_crtc_enable(struct drm_crtc *c)
226{ 171{
227 atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON); 172 struct drm_device *dev = c->dev;
173 struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
174 struct regmap *regmap = crtc->dc->hlcdc->regmap;
175 unsigned int status;
176
177 if (crtc->enabled)
178 return;
179
180 pm_runtime_get_sync(dev->dev);
181
182 pm_runtime_forbid(dev->dev);
183
184 pinctrl_pm_select_default_state(dev->dev);
185 clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
186
187 regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
188 while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
189 !(status & ATMEL_HLCDC_PIXEL_CLK))
190 cpu_relax();
191
192
193 regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
194 while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
195 !(status & ATMEL_HLCDC_SYNC))
196 cpu_relax();
197
198 regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
199 while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
200 !(status & ATMEL_HLCDC_DISP))
201 cpu_relax();
202
203 pm_runtime_put_sync(dev->dev);
204
205 drm_crtc_vblank_on(c);
206
207 crtc->enabled = true;
228} 208}
229 209
230static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc, 210static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c,
231 const struct drm_display_mode *mode, 211 struct drm_crtc_state *s)
232 struct drm_display_mode *adjusted_mode)
233{ 212{
234 return true; 213 struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
214
215 if (atmel_hlcdc_dc_mode_valid(crtc->dc, &s->adjusted_mode) != MODE_OK)
216 return -EINVAL;
217
218 return atmel_hlcdc_plane_prepare_disc_area(s);
235} 219}
236 220
237static void atmel_hlcdc_crtc_disable(struct drm_crtc *crtc) 221static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c)
238{ 222{
239 struct drm_plane *plane; 223 struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
240 224
241 atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); 225 if (c->state->event) {
242 crtc->primary->funcs->disable_plane(crtc->primary); 226 c->state->event->pipe = drm_crtc_index(c);
243 227
244 drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { 228 WARN_ON(drm_crtc_vblank_get(c) != 0);
245 if (plane->crtc != crtc)
246 continue;
247 229
248 plane->funcs->disable_plane(crtc->primary); 230 crtc->event = c->state->event;
249 plane->crtc = NULL; 231 c->state->event = NULL;
250 } 232 }
251} 233}
252 234
235static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc)
236{
237 /* TODO: write common plane control register if available */
238}
239
253static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = { 240static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
254 .mode_fixup = atmel_hlcdc_crtc_mode_fixup, 241 .mode_fixup = atmel_hlcdc_crtc_mode_fixup,
255 .dpms = atmel_hlcdc_crtc_dpms, 242 .mode_set = drm_helper_crtc_mode_set,
256 .mode_set = atmel_hlcdc_crtc_mode_set, 243 .mode_set_nofb = atmel_hlcdc_crtc_mode_set_nofb,
257 .mode_set_base = atmel_hlcdc_crtc_mode_set_base, 244 .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, 245 .disable = atmel_hlcdc_crtc_disable,
246 .enable = atmel_hlcdc_crtc_enable,
247 .atomic_check = atmel_hlcdc_crtc_atomic_check,
248 .atomic_begin = atmel_hlcdc_crtc_atomic_begin,
249 .atomic_flush = atmel_hlcdc_crtc_atomic_flush,
261}; 250};
262 251
263static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c) 252static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
@@ -306,61 +295,13 @@ void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
306 atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c)); 295 atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
307} 296}
308 297
309static 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
360static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = { 298static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
361 .page_flip = atmel_hlcdc_crtc_page_flip, 299 .page_flip = drm_atomic_helper_page_flip,
362 .set_config = drm_crtc_helper_set_config, 300 .set_config = drm_atomic_helper_set_config,
363 .destroy = atmel_hlcdc_crtc_destroy, 301 .destroy = atmel_hlcdc_crtc_destroy,
302 .reset = drm_atomic_helper_crtc_reset,
303 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
304 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
364}; 305};
365 306
366int atmel_hlcdc_crtc_create(struct drm_device *dev) 307int atmel_hlcdc_crtc_create(struct drm_device *dev)
@@ -375,7 +316,6 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev)
375 if (!crtc) 316 if (!crtc)
376 return -ENOMEM; 317 return -ENOMEM;
377 318
378 crtc->dpms = DRM_MODE_DPMS_OFF;
379 crtc->dc = dc; 319 crtc->dc = dc;
380 320
381 ret = drm_crtc_init_with_planes(dev, &crtc->base, 321 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..01afeafe17b1 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)
222static const struct drm_mode_config_funcs mode_config_funcs = { 222static 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
227static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev) 229static 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");
@@ -557,6 +561,52 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
557 return 0; 561 return 0;
558} 562}
559 563
564#ifdef CONFIG_PM
565static int atmel_hlcdc_dc_drm_suspend(struct device *dev)
566{
567 struct drm_device *drm_dev = dev_get_drvdata(dev);
568 struct drm_crtc *crtc;
569
570 if (pm_runtime_suspended(dev))
571 return 0;
572
573 drm_modeset_lock_all(drm_dev);
574 list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
575 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
576 if (crtc->enabled) {
577 crtc_funcs->disable(crtc);
578 /* save enable state for resume */
579 crtc->enabled = true;
580 }
581 }
582 drm_modeset_unlock_all(drm_dev);
583 return 0;
584}
585
586static int atmel_hlcdc_dc_drm_resume(struct device *dev)
587{
588 struct drm_device *drm_dev = dev_get_drvdata(dev);
589 struct drm_crtc *crtc;
590
591 if (pm_runtime_suspended(dev))
592 return 0;
593
594 drm_modeset_lock_all(drm_dev);
595 list_for_each_entry(crtc, &drm_dev->mode_config.crtc_list, head) {
596 struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
597 if (crtc->enabled) {
598 crtc->enabled = false;
599 crtc_funcs->enable(crtc);
600 }
601 }
602 drm_modeset_unlock_all(drm_dev);
603 return 0;
604}
605#endif
606
607static SIMPLE_DEV_PM_OPS(atmel_hlcdc_dc_drm_pm_ops,
608 atmel_hlcdc_dc_drm_suspend, atmel_hlcdc_dc_drm_resume);
609
560static const struct of_device_id atmel_hlcdc_dc_of_match[] = { 610static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
561 { .compatible = "atmel,hlcdc-display-controller" }, 611 { .compatible = "atmel,hlcdc-display-controller" },
562 { }, 612 { },
@@ -567,6 +617,7 @@ static struct platform_driver atmel_hlcdc_dc_platform_driver = {
567 .remove = atmel_hlcdc_dc_drm_remove, 617 .remove = atmel_hlcdc_dc_drm_remove,
568 .driver = { 618 .driver = {
569 .name = "atmel-hlcdc-display-controller", 619 .name = "atmel-hlcdc-display-controller",
620 .pm = &atmel_hlcdc_dc_drm_pm_ops,
570 .of_match_table = atmel_hlcdc_dc_of_match, 621 .of_match_table = atmel_hlcdc_dc_of_match,
571 }, 622 },
572}; 623};
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
index 7bc96af3397a..1ea9c2ccd8a7 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 */
70struct atmel_hlcdc_plane_properties { 73struct 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
90static inline struct atmel_hlcdc_plane * 91static 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 */
120struct 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,22 +148,7 @@ int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
184struct atmel_hlcdc_planes * 148struct atmel_hlcdc_planes *
185atmel_hlcdc_create_planes(struct drm_device *dev); 149atmel_hlcdc_create_planes(struct drm_device *dev);
186 150
187int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p, 151int atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state);
188 struct atmel_hlcdc_plane_update_req *req,
189 const struct drm_display_mode *mode);
190
191int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
192 struct atmel_hlcdc_plane_update_req *req);
193
194int 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 152
204void atmel_hlcdc_crtc_irq(struct drm_crtc *c); 153void atmel_hlcdc_crtc_irq(struct drm_crtc *c);
205 154
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
301int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer) 301void 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
347int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer) 345int 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,
376void atmel_hlcdc_layer_cleanup(struct drm_device *dev, 377void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
377 struct atmel_hlcdc_layer *layer); 378 struct atmel_hlcdc_layer *layer);
378 379
379int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer); 380void atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
380 381
381int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer); 382int 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
89static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder, 89static 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) 98static 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
110static bool 107static 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
118static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder)
119{
120 atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
121}
122
123static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder)
124{
125 atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
126}
127
128static void 115static void
129atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder, 116atmel_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
158static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = { 145static 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
166static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder) 152static 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
228static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = { 214static 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
235static int atmel_hlcdc_create_panel_output(struct drm_device *dev, 224static 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..dbf97d999d40 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -19,6 +19,59 @@
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 */
41struct 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 bool disc_updated;
55
56 int disc_x;
57 int disc_y;
58 int disc_w;
59 int disc_h;
60
61 /* These fields are private and should not be touched */
62 int bpp[ATMEL_HLCDC_MAX_PLANES];
63 unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
64 int xstride[ATMEL_HLCDC_MAX_PLANES];
65 int pstride[ATMEL_HLCDC_MAX_PLANES];
66 int nplanes;
67};
68
69static inline struct atmel_hlcdc_plane_state *
70drm_plane_state_to_atmel_hlcdc_plane_state(struct drm_plane_state *s)
71{
72 return container_of(s, struct atmel_hlcdc_plane_state, base);
73}
74
22#define SUBPIXEL_MASK 0xffff 75#define SUBPIXEL_MASK 0xffff
23 76
24static uint32_t rgb_formats[] = { 77static uint32_t rgb_formats[] = {
@@ -128,7 +181,7 @@ static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
128 return 0; 181 return 0;
129} 182}
130 183
131static bool atmel_hlcdc_format_embedds_alpha(u32 format) 184static bool atmel_hlcdc_format_embeds_alpha(u32 format)
132{ 185{
133 int i; 186 int i;
134 187
@@ -204,7 +257,7 @@ static u32 heo_upscaling_ycoef[] = {
204 257
205static void 258static void
206atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane, 259atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
207 struct atmel_hlcdc_plane_update_req *req) 260 struct atmel_hlcdc_plane_state *state)
208{ 261{
209 const struct atmel_hlcdc_layer_cfg_layout *layout = 262 const struct atmel_hlcdc_layer_cfg_layout *layout =
210 &plane->layer.desc->layout; 263 &plane->layer.desc->layout;
@@ -213,69 +266,69 @@ atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
213 atmel_hlcdc_layer_update_cfg(&plane->layer, 266 atmel_hlcdc_layer_update_cfg(&plane->layer,
214 layout->size, 267 layout->size,
215 0xffffffff, 268 0xffffffff,
216 (req->crtc_w - 1) | 269 (state->crtc_w - 1) |
217 ((req->crtc_h - 1) << 16)); 270 ((state->crtc_h - 1) << 16));
218 271
219 if (layout->memsize) 272 if (layout->memsize)
220 atmel_hlcdc_layer_update_cfg(&plane->layer, 273 atmel_hlcdc_layer_update_cfg(&plane->layer,
221 layout->memsize, 274 layout->memsize,
222 0xffffffff, 275 0xffffffff,
223 (req->src_w - 1) | 276 (state->src_w - 1) |
224 ((req->src_h - 1) << 16)); 277 ((state->src_h - 1) << 16));
225 278
226 if (layout->pos) 279 if (layout->pos)
227 atmel_hlcdc_layer_update_cfg(&plane->layer, 280 atmel_hlcdc_layer_update_cfg(&plane->layer,
228 layout->pos, 281 layout->pos,
229 0xffffffff, 282 0xffffffff,
230 req->crtc_x | 283 state->crtc_x |
231 (req->crtc_y << 16)); 284 (state->crtc_y << 16));
232 285
233 /* TODO: rework the rescaling part */ 286 /* TODO: rework the rescaling part */
234 if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) { 287 if (state->crtc_w != state->src_w || state->crtc_h != state->src_h) {
235 u32 factor_reg = 0; 288 u32 factor_reg = 0;
236 289
237 if (req->crtc_w != req->src_w) { 290 if (state->crtc_w != state->src_w) {
238 int i; 291 int i;
239 u32 factor; 292 u32 factor;
240 u32 *coeff_tab = heo_upscaling_xcoef; 293 u32 *coeff_tab = heo_upscaling_xcoef;
241 u32 max_memsize; 294 u32 max_memsize;
242 295
243 if (req->crtc_w < req->src_w) 296 if (state->crtc_w < state->src_w)
244 coeff_tab = heo_downscaling_xcoef; 297 coeff_tab = heo_downscaling_xcoef;
245 for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++) 298 for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
246 atmel_hlcdc_layer_update_cfg(&plane->layer, 299 atmel_hlcdc_layer_update_cfg(&plane->layer,
247 17 + i, 300 17 + i,
248 0xffffffff, 301 0xffffffff,
249 coeff_tab[i]); 302 coeff_tab[i]);
250 factor = ((8 * 256 * req->src_w) - (256 * 4)) / 303 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
251 req->crtc_w; 304 state->crtc_w;
252 factor++; 305 factor++;
253 max_memsize = ((factor * req->crtc_w) + (256 * 4)) / 306 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
254 2048; 307 2048;
255 if (max_memsize > req->src_w) 308 if (max_memsize > state->src_w)
256 factor--; 309 factor--;
257 factor_reg |= factor | 0x80000000; 310 factor_reg |= factor | 0x80000000;
258 } 311 }
259 312
260 if (req->crtc_h != req->src_h) { 313 if (state->crtc_h != state->src_h) {
261 int i; 314 int i;
262 u32 factor; 315 u32 factor;
263 u32 *coeff_tab = heo_upscaling_ycoef; 316 u32 *coeff_tab = heo_upscaling_ycoef;
264 u32 max_memsize; 317 u32 max_memsize;
265 318
266 if (req->crtc_w < req->src_w) 319 if (state->crtc_w < state->src_w)
267 coeff_tab = heo_downscaling_ycoef; 320 coeff_tab = heo_downscaling_ycoef;
268 for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++) 321 for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
269 atmel_hlcdc_layer_update_cfg(&plane->layer, 322 atmel_hlcdc_layer_update_cfg(&plane->layer,
270 33 + i, 323 33 + i,
271 0xffffffff, 324 0xffffffff,
272 coeff_tab[i]); 325 coeff_tab[i]);
273 factor = ((8 * 256 * req->src_w) - (256 * 4)) / 326 factor = ((8 * 256 * state->src_w) - (256 * 4)) /
274 req->crtc_w; 327 state->crtc_w;
275 factor++; 328 factor++;
276 max_memsize = ((factor * req->crtc_w) + (256 * 4)) / 329 max_memsize = ((factor * state->crtc_w) + (256 * 4)) /
277 2048; 330 2048;
278 if (max_memsize > req->src_w) 331 if (max_memsize > state->src_w)
279 factor--; 332 factor--;
280 factor_reg |= (factor << 16) | 0x80000000; 333 factor_reg |= (factor << 16) | 0x80000000;
281 } 334 }
@@ -287,7 +340,7 @@ atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
287 340
288static void 341static void
289atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane, 342atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
290 struct atmel_hlcdc_plane_update_req *req) 343 struct atmel_hlcdc_plane_state *state)
291{ 344{
292 const struct atmel_hlcdc_layer_cfg_layout *layout = 345 const struct atmel_hlcdc_layer_cfg_layout *layout =
293 &plane->layer.desc->layout; 346 &plane->layer.desc->layout;
@@ -297,10 +350,11 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
297 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL | 350 cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
298 ATMEL_HLCDC_LAYER_ITER; 351 ATMEL_HLCDC_LAYER_ITER;
299 352
300 if (atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format)) 353 if (atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format))
301 cfg |= ATMEL_HLCDC_LAYER_LAEN; 354 cfg |= ATMEL_HLCDC_LAYER_LAEN;
302 else 355 else
303 cfg |= ATMEL_HLCDC_LAYER_GAEN; 356 cfg |= ATMEL_HLCDC_LAYER_GAEN |
357 ATMEL_HLCDC_LAYER_GA(state->alpha);
304 } 358 }
305 359
306 atmel_hlcdc_layer_update_cfg(&plane->layer, 360 atmel_hlcdc_layer_update_cfg(&plane->layer,
@@ -312,24 +366,26 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
312 ATMEL_HLCDC_LAYER_ITER2BL | 366 ATMEL_HLCDC_LAYER_ITER2BL |
313 ATMEL_HLCDC_LAYER_ITER | 367 ATMEL_HLCDC_LAYER_ITER |
314 ATMEL_HLCDC_LAYER_GAEN | 368 ATMEL_HLCDC_LAYER_GAEN |
369 ATMEL_HLCDC_LAYER_GA_MASK |
315 ATMEL_HLCDC_LAYER_LAEN | 370 ATMEL_HLCDC_LAYER_LAEN |
316 ATMEL_HLCDC_LAYER_OVR | 371 ATMEL_HLCDC_LAYER_OVR |
317 ATMEL_HLCDC_LAYER_DMA, cfg); 372 ATMEL_HLCDC_LAYER_DMA, cfg);
318} 373}
319 374
320static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane, 375static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
321 struct atmel_hlcdc_plane_update_req *req) 376 struct atmel_hlcdc_plane_state *state)
322{ 377{
323 u32 cfg; 378 u32 cfg;
324 int ret; 379 int ret;
325 380
326 ret = atmel_hlcdc_format_to_plane_mode(req->fb->pixel_format, &cfg); 381 ret = atmel_hlcdc_format_to_plane_mode(state->base.fb->pixel_format,
382 &cfg);
327 if (ret) 383 if (ret)
328 return; 384 return;
329 385
330 if ((req->fb->pixel_format == DRM_FORMAT_YUV422 || 386 if ((state->base.fb->pixel_format == DRM_FORMAT_YUV422 ||
331 req->fb->pixel_format == DRM_FORMAT_NV61) && 387 state->base.fb->pixel_format == DRM_FORMAT_NV61) &&
332 (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270)))) 388 (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
333 cfg |= ATMEL_HLCDC_YUV422ROT; 389 cfg |= ATMEL_HLCDC_YUV422ROT;
334 390
335 atmel_hlcdc_layer_update_cfg(&plane->layer, 391 atmel_hlcdc_layer_update_cfg(&plane->layer,
@@ -341,7 +397,7 @@ static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
341 * Rotation optimization is not working on RGB888 (rotation is still 397 * Rotation optimization is not working on RGB888 (rotation is still
342 * working but without any optimization). 398 * working but without any optimization).
343 */ 399 */
344 if (req->fb->pixel_format == DRM_FORMAT_RGB888) 400 if (state->base.fb->pixel_format == DRM_FORMAT_RGB888)
345 cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS; 401 cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
346 else 402 else
347 cfg = 0; 403 cfg = 0;
@@ -352,73 +408,142 @@ static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
352} 408}
353 409
354static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane, 410static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
355 struct atmel_hlcdc_plane_update_req *req) 411 struct atmel_hlcdc_plane_state *state)
356{ 412{
357 struct atmel_hlcdc_layer *layer = &plane->layer; 413 struct atmel_hlcdc_layer *layer = &plane->layer;
358 const struct atmel_hlcdc_layer_cfg_layout *layout = 414 const struct atmel_hlcdc_layer_cfg_layout *layout =
359 &layer->desc->layout; 415 &layer->desc->layout;
360 int i; 416 int i;
361 417
362 atmel_hlcdc_layer_update_set_fb(&plane->layer, req->fb, req->offsets); 418 atmel_hlcdc_layer_update_set_fb(&plane->layer, state->base.fb,
419 state->offsets);
363 420
364 for (i = 0; i < req->nplanes; i++) { 421 for (i = 0; i < state->nplanes; i++) {
365 if (layout->xstride[i]) { 422 if (layout->xstride[i]) {
366 atmel_hlcdc_layer_update_cfg(&plane->layer, 423 atmel_hlcdc_layer_update_cfg(&plane->layer,
367 layout->xstride[i], 424 layout->xstride[i],
368 0xffffffff, 425 0xffffffff,
369 req->xstride[i]); 426 state->xstride[i]);
370 } 427 }
371 428
372 if (layout->pstride[i]) { 429 if (layout->pstride[i]) {
373 atmel_hlcdc_layer_update_cfg(&plane->layer, 430 atmel_hlcdc_layer_update_cfg(&plane->layer,
374 layout->pstride[i], 431 layout->pstride[i],
375 0xffffffff, 432 0xffffffff,
376 req->pstride[i]); 433 state->pstride[i]);
377 } 434 }
378 } 435 }
379} 436}
380 437
381static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p, 438int
382 struct atmel_hlcdc_plane_update_req *req, 439atmel_hlcdc_plane_prepare_disc_area(struct drm_crtc_state *c_state)
383 const struct drm_display_mode *mode)
384{ 440{
385 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 441 int disc_x = 0, disc_y = 0, disc_w = 0, disc_h = 0;
386 const struct atmel_hlcdc_layer_cfg_layout *layout = 442 const struct atmel_hlcdc_layer_cfg_layout *layout;
387 &plane->layer.desc->layout; 443 struct atmel_hlcdc_plane_state *primary_state;
444 struct drm_plane_state *primary_s;
445 struct atmel_hlcdc_plane *primary;
446 struct drm_plane *ovl;
447
448 primary = drm_plane_to_atmel_hlcdc_plane(c_state->crtc->primary);
449 layout = &primary->layer.desc->layout;
450 if (!layout->disc_pos || !layout->disc_size)
451 return 0;
452
453 primary_s = drm_atomic_get_plane_state(c_state->state,
454 &primary->base);
455 if (IS_ERR(primary_s))
456 return PTR_ERR(primary_s);
457
458 primary_state = drm_plane_state_to_atmel_hlcdc_plane_state(primary_s);
459
460 drm_atomic_crtc_state_for_each_plane(ovl, c_state) {
461 struct atmel_hlcdc_plane_state *ovl_state;
462 struct drm_plane_state *ovl_s;
463
464 if (ovl == c_state->crtc->primary)
465 continue;
388 466
389 if (!layout->size && 467 ovl_s = drm_atomic_get_plane_state(c_state->state, ovl);
390 (mode->hdisplay != req->crtc_w || 468 if (IS_ERR(ovl_s))
391 mode->vdisplay != req->crtc_h)) 469 return PTR_ERR(ovl_s);
392 return -EINVAL;
393 470
394 if (plane->layer.desc->max_height && 471 ovl_state = drm_plane_state_to_atmel_hlcdc_plane_state(ovl_s);
395 req->crtc_h > plane->layer.desc->max_height)
396 return -EINVAL;
397 472
398 if (plane->layer.desc->max_width && 473 if (!ovl_s->fb ||
399 req->crtc_w > plane->layer.desc->max_width) 474 atmel_hlcdc_format_embeds_alpha(ovl_s->fb->pixel_format) ||
400 return -EINVAL; 475 ovl_state->alpha != 255)
476 continue;
401 477
402 if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) && 478 /* TODO: implement a smarter hidden area detection */
403 (!layout->memsize || 479 if (ovl_state->crtc_h * ovl_state->crtc_w < disc_h * disc_w)
404 atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format))) 480 continue;
405 return -EINVAL;
406 481
407 if (req->crtc_x < 0 || req->crtc_y < 0) 482 disc_x = ovl_state->crtc_x;
408 return -EINVAL; 483 disc_y = ovl_state->crtc_y;
484 disc_h = ovl_state->crtc_h;
485 disc_w = ovl_state->crtc_w;
486 }
409 487
410 if (req->crtc_w + req->crtc_x > mode->hdisplay || 488 if (disc_x == primary_state->disc_x &&
411 req->crtc_h + req->crtc_y > mode->vdisplay) 489 disc_y == primary_state->disc_y &&
412 return -EINVAL; 490 disc_w == primary_state->disc_w &&
491 disc_h == primary_state->disc_h)
492 return 0;
493
494
495 primary_state->disc_x = disc_x;
496 primary_state->disc_y = disc_y;
497 primary_state->disc_w = disc_w;
498 primary_state->disc_h = disc_h;
499 primary_state->disc_updated = true;
413 500
414 return 0; 501 return 0;
415} 502}
416 503
417int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p, 504static void
418 struct atmel_hlcdc_plane_update_req *req, 505atmel_hlcdc_plane_update_disc_area(struct atmel_hlcdc_plane *plane,
419 const struct drm_display_mode *mode) 506 struct atmel_hlcdc_plane_state *state)
507{
508 const struct atmel_hlcdc_layer_cfg_layout *layout =
509 &plane->layer.desc->layout;
510 int disc_surface = 0;
511
512 if (!state->disc_updated)
513 return;
514
515 disc_surface = state->disc_h * state->disc_w;
516
517 atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
518 ATMEL_HLCDC_LAYER_DISCEN,
519 disc_surface ? ATMEL_HLCDC_LAYER_DISCEN : 0);
520
521 if (!disc_surface)
522 return;
523
524 atmel_hlcdc_layer_update_cfg(&plane->layer,
525 layout->disc_pos,
526 0xffffffff,
527 state->disc_x | (state->disc_y << 16));
528
529 atmel_hlcdc_layer_update_cfg(&plane->layer,
530 layout->disc_size,
531 0xffffffff,
532 (state->disc_w - 1) |
533 ((state->disc_h - 1) << 16));
534}
535
536static int atmel_hlcdc_plane_atomic_check(struct drm_plane *p,
537 struct drm_plane_state *s)
420{ 538{
421 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 539 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
540 struct atmel_hlcdc_plane_state *state =
541 drm_plane_state_to_atmel_hlcdc_plane_state(s);
542 const struct atmel_hlcdc_layer_cfg_layout *layout =
543 &plane->layer.desc->layout;
544 struct drm_framebuffer *fb = state->base.fb;
545 const struct drm_display_mode *mode;
546 struct drm_crtc_state *crtc_state;
422 unsigned int patched_crtc_w; 547 unsigned int patched_crtc_w;
423 unsigned int patched_crtc_h; 548 unsigned int patched_crtc_h;
424 unsigned int patched_src_w; 549 unsigned int patched_src_w;
@@ -430,196 +555,195 @@ int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
430 int vsub = 1; 555 int vsub = 1;
431 int i; 556 int i;
432 557
433 if ((req->src_x | req->src_y | req->src_w | req->src_h) & 558 if (!state->base.crtc || !fb)
559 return 0;
560
561 crtc_state = s->state->crtc_states[drm_crtc_index(s->crtc)];
562 mode = &crtc_state->adjusted_mode;
563
564 state->src_x = s->src_x;
565 state->src_y = s->src_y;
566 state->src_h = s->src_h;
567 state->src_w = s->src_w;
568 state->crtc_x = s->crtc_x;
569 state->crtc_y = s->crtc_y;
570 state->crtc_h = s->crtc_h;
571 state->crtc_w = s->crtc_w;
572 if ((state->src_x | state->src_y | state->src_w | state->src_h) &
434 SUBPIXEL_MASK) 573 SUBPIXEL_MASK)
435 return -EINVAL; 574 return -EINVAL;
436 575
437 req->src_x >>= 16; 576 state->src_x >>= 16;
438 req->src_y >>= 16; 577 state->src_y >>= 16;
439 req->src_w >>= 16; 578 state->src_w >>= 16;
440 req->src_h >>= 16; 579 state->src_h >>= 16;
441 580
442 req->nplanes = drm_format_num_planes(req->fb->pixel_format); 581 state->nplanes = drm_format_num_planes(fb->pixel_format);
443 if (req->nplanes > ATMEL_HLCDC_MAX_PLANES) 582 if (state->nplanes > ATMEL_HLCDC_MAX_PLANES)
444 return -EINVAL; 583 return -EINVAL;
445 584
446 /* 585 /*
447 * Swap width and size in case of 90 or 270 degrees rotation 586 * Swap width and size in case of 90 or 270 degrees rotation
448 */ 587 */
449 if (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) { 588 if (state->base.rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
450 tmp = req->crtc_w; 589 tmp = state->crtc_w;
451 req->crtc_w = req->crtc_h; 590 state->crtc_w = state->crtc_h;
452 req->crtc_h = tmp; 591 state->crtc_h = tmp;
453 tmp = req->src_w; 592 tmp = state->src_w;
454 req->src_w = req->src_h; 593 state->src_w = state->src_h;
455 req->src_h = tmp; 594 state->src_h = tmp;
456 } 595 }
457 596
458 if (req->crtc_x + req->crtc_w > mode->hdisplay) 597 if (state->crtc_x + state->crtc_w > mode->hdisplay)
459 patched_crtc_w = mode->hdisplay - req->crtc_x; 598 patched_crtc_w = mode->hdisplay - state->crtc_x;
460 else 599 else
461 patched_crtc_w = req->crtc_w; 600 patched_crtc_w = state->crtc_w;
462 601
463 if (req->crtc_x < 0) { 602 if (state->crtc_x < 0) {
464 patched_crtc_w += req->crtc_x; 603 patched_crtc_w += state->crtc_x;
465 x_offset = -req->crtc_x; 604 x_offset = -state->crtc_x;
466 req->crtc_x = 0; 605 state->crtc_x = 0;
467 } 606 }
468 607
469 if (req->crtc_y + req->crtc_h > mode->vdisplay) 608 if (state->crtc_y + state->crtc_h > mode->vdisplay)
470 patched_crtc_h = mode->vdisplay - req->crtc_y; 609 patched_crtc_h = mode->vdisplay - state->crtc_y;
471 else 610 else
472 patched_crtc_h = req->crtc_h; 611 patched_crtc_h = state->crtc_h;
473 612
474 if (req->crtc_y < 0) { 613 if (state->crtc_y < 0) {
475 patched_crtc_h += req->crtc_y; 614 patched_crtc_h += state->crtc_y;
476 y_offset = -req->crtc_y; 615 y_offset = -state->crtc_y;
477 req->crtc_y = 0; 616 state->crtc_y = 0;
478 } 617 }
479 618
480 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w, 619 patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * state->src_w,
481 req->crtc_w); 620 state->crtc_w);
482 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h, 621 patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * state->src_h,
483 req->crtc_h); 622 state->crtc_h);
484 623
485 hsub = drm_format_horz_chroma_subsampling(req->fb->pixel_format); 624 hsub = drm_format_horz_chroma_subsampling(fb->pixel_format);
486 vsub = drm_format_vert_chroma_subsampling(req->fb->pixel_format); 625 vsub = drm_format_vert_chroma_subsampling(fb->pixel_format);
487 626
488 for (i = 0; i < req->nplanes; i++) { 627 for (i = 0; i < state->nplanes; i++) {
489 unsigned int offset = 0; 628 unsigned int offset = 0;
490 int xdiv = i ? hsub : 1; 629 int xdiv = i ? hsub : 1;
491 int ydiv = i ? vsub : 1; 630 int ydiv = i ? vsub : 1;
492 631
493 req->bpp[i] = drm_format_plane_cpp(req->fb->pixel_format, i); 632 state->bpp[i] = drm_format_plane_cpp(fb->pixel_format, i);
494 if (!req->bpp[i]) 633 if (!state->bpp[i])
495 return -EINVAL; 634 return -EINVAL;
496 635
497 switch (plane->rotation & 0xf) { 636 switch (state->base.rotation & 0xf) {
498 case BIT(DRM_ROTATE_90): 637 case BIT(DRM_ROTATE_90):
499 offset = ((y_offset + req->src_y + patched_src_w - 1) / 638 offset = ((y_offset + state->src_y + patched_src_w - 1) /
500 ydiv) * req->fb->pitches[i]; 639 ydiv) * fb->pitches[i];
501 offset += ((x_offset + req->src_x) / xdiv) * 640 offset += ((x_offset + state->src_x) / xdiv) *
502 req->bpp[i]; 641 state->bpp[i];
503 req->xstride[i] = ((patched_src_w - 1) / ydiv) * 642 state->xstride[i] = ((patched_src_w - 1) / ydiv) *
504 req->fb->pitches[i]; 643 fb->pitches[i];
505 req->pstride[i] = -req->fb->pitches[i] - req->bpp[i]; 644 state->pstride[i] = -fb->pitches[i] - state->bpp[i];
506 break; 645 break;
507 case BIT(DRM_ROTATE_180): 646 case BIT(DRM_ROTATE_180):
508 offset = ((y_offset + req->src_y + patched_src_h - 1) / 647 offset = ((y_offset + state->src_y + patched_src_h - 1) /
509 ydiv) * req->fb->pitches[i]; 648 ydiv) * fb->pitches[i];
510 offset += ((x_offset + req->src_x + patched_src_w - 1) / 649 offset += ((x_offset + state->src_x + patched_src_w - 1) /
511 xdiv) * req->bpp[i]; 650 xdiv) * state->bpp[i];
512 req->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) * 651 state->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
513 req->bpp[i]) - req->fb->pitches[i]; 652 state->bpp[i]) - fb->pitches[i];
514 req->pstride[i] = -2 * req->bpp[i]; 653 state->pstride[i] = -2 * state->bpp[i];
515 break; 654 break;
516 case BIT(DRM_ROTATE_270): 655 case BIT(DRM_ROTATE_270):
517 offset = ((y_offset + req->src_y) / ydiv) * 656 offset = ((y_offset + state->src_y) / ydiv) *
518 req->fb->pitches[i]; 657 fb->pitches[i];
519 offset += ((x_offset + req->src_x + patched_src_h - 1) / 658 offset += ((x_offset + state->src_x + patched_src_h - 1) /
520 xdiv) * req->bpp[i]; 659 xdiv) * state->bpp[i];
521 req->xstride[i] = -(((patched_src_w - 1) / ydiv) * 660 state->xstride[i] = -(((patched_src_w - 1) / ydiv) *
522 req->fb->pitches[i]) - 661 fb->pitches[i]) -
523 (2 * req->bpp[i]); 662 (2 * state->bpp[i]);
524 req->pstride[i] = req->fb->pitches[i] - req->bpp[i]; 663 state->pstride[i] = fb->pitches[i] - state->bpp[i];
525 break; 664 break;
526 case BIT(DRM_ROTATE_0): 665 case BIT(DRM_ROTATE_0):
527 default: 666 default:
528 offset = ((y_offset + req->src_y) / ydiv) * 667 offset = ((y_offset + state->src_y) / ydiv) *
529 req->fb->pitches[i]; 668 fb->pitches[i];
530 offset += ((x_offset + req->src_x) / xdiv) * 669 offset += ((x_offset + state->src_x) / xdiv) *
531 req->bpp[i]; 670 state->bpp[i];
532 req->xstride[i] = req->fb->pitches[i] - 671 state->xstride[i] = fb->pitches[i] -
533 ((patched_src_w / xdiv) * 672 ((patched_src_w / xdiv) *
534 req->bpp[i]); 673 state->bpp[i]);
535 req->pstride[i] = 0; 674 state->pstride[i] = 0;
536 break; 675 break;
537 } 676 }
538 677
539 req->offsets[i] = offset + req->fb->offsets[i]; 678 state->offsets[i] = offset + fb->offsets[i];
540 } 679 }
541 680
542 req->src_w = patched_src_w; 681 state->src_w = patched_src_w;
543 req->src_h = patched_src_h; 682 state->src_h = patched_src_h;
544 req->crtc_w = patched_crtc_w; 683 state->crtc_w = patched_crtc_w;
545 req->crtc_h = patched_crtc_h; 684 state->crtc_h = patched_crtc_h;
546 685
547 return atmel_hlcdc_plane_check_update_req(p, req, mode); 686 if (!layout->size &&
548} 687 (mode->hdisplay != state->crtc_w ||
688 mode->vdisplay != state->crtc_h))
689 return -EINVAL;
549 690
550int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p, 691 if (plane->layer.desc->max_height &&
551 struct atmel_hlcdc_plane_update_req *req) 692 state->crtc_h > plane->layer.desc->max_height)
552{ 693 return -EINVAL;
553 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
554 int ret;
555 694
556 ret = atmel_hlcdc_layer_update_start(&plane->layer); 695 if (plane->layer.desc->max_width &&
557 if (ret) 696 state->crtc_w > plane->layer.desc->max_width)
558 return ret; 697 return -EINVAL;
559 698
560 atmel_hlcdc_plane_update_pos_and_size(plane, req); 699 if ((state->crtc_h != state->src_h || state->crtc_w != state->src_w) &&
561 atmel_hlcdc_plane_update_general_settings(plane, req); 700 (!layout->memsize ||
562 atmel_hlcdc_plane_update_format(plane, req); 701 atmel_hlcdc_format_embeds_alpha(state->base.fb->pixel_format)))
563 atmel_hlcdc_plane_update_buffers(plane, req); 702 return -EINVAL;
564 703
565 atmel_hlcdc_layer_update_commit(&plane->layer); 704 if (state->crtc_x < 0 || state->crtc_y < 0)
705 return -EINVAL;
706
707 if (state->crtc_w + state->crtc_x > mode->hdisplay ||
708 state->crtc_h + state->crtc_y > mode->vdisplay)
709 return -EINVAL;
566 710
567 return 0; 711 return 0;
568} 712}
569 713
570int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p, 714static int atmel_hlcdc_plane_prepare_fb(struct drm_plane *p,
571 struct drm_crtc *crtc, 715 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{ 716{
580 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 717 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 718
599 if (!req.crtc_h || !req.crtc_w) 719 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} 720}
604 721
605static int atmel_hlcdc_plane_update(struct drm_plane *p, 722static void atmel_hlcdc_plane_atomic_update(struct drm_plane *p,
606 struct drm_crtc *crtc, 723 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{ 724{
613 return atmel_hlcdc_plane_update_with_mode(p, crtc, fb, crtc_x, crtc_y, 725 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
614 crtc_w, crtc_h, src_x, src_y, 726 struct atmel_hlcdc_plane_state *state =
615 src_w, src_h, &crtc->hwmode); 727 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
728
729 if (!p->state->crtc || !p->state->fb)
730 return;
731
732 atmel_hlcdc_plane_update_pos_and_size(plane, state);
733 atmel_hlcdc_plane_update_general_settings(plane, state);
734 atmel_hlcdc_plane_update_format(plane, state);
735 atmel_hlcdc_plane_update_buffers(plane, state);
736 atmel_hlcdc_plane_update_disc_area(plane, state);
737
738 atmel_hlcdc_layer_update_commit(&plane->layer);
616} 739}
617 740
618static int atmel_hlcdc_plane_disable(struct drm_plane *p) 741static void atmel_hlcdc_plane_atomic_disable(struct drm_plane *p,
742 struct drm_plane_state *old_state)
619{ 743{
620 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 744 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
621 745
622 return atmel_hlcdc_layer_disable(&plane->layer); 746 atmel_hlcdc_layer_disable(&plane->layer);
623} 747}
624 748
625static void atmel_hlcdc_plane_destroy(struct drm_plane *p) 749static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
@@ -635,38 +759,36 @@ static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
635 devm_kfree(p->dev->dev, plane); 759 devm_kfree(p->dev->dev, plane);
636} 760}
637 761
638static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane, 762static int atmel_hlcdc_plane_atomic_set_property(struct drm_plane *p,
639 u8 alpha) 763 struct drm_plane_state *s,
764 struct drm_property *property,
765 uint64_t val)
640{ 766{
641 atmel_hlcdc_layer_update_start(&plane->layer); 767 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
642 atmel_hlcdc_layer_update_cfg(&plane->layer, 768 struct atmel_hlcdc_plane_properties *props = plane->properties;
643 plane->layer.desc->layout.general_config, 769 struct atmel_hlcdc_plane_state *state =
644 ATMEL_HLCDC_LAYER_GA_MASK, 770 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 771
651static int atmel_hlcdc_plane_set_rotation(struct atmel_hlcdc_plane *plane, 772 if (property == props->alpha)
652 unsigned int rotation) 773 state->alpha = val;
653{ 774 else
654 plane->rotation = rotation; 775 return -EINVAL;
655 776
656 return 0; 777 return 0;
657} 778}
658 779
659static int atmel_hlcdc_plane_set_property(struct drm_plane *p, 780static int atmel_hlcdc_plane_atomic_get_property(struct drm_plane *p,
660 struct drm_property *property, 781 const struct drm_plane_state *s,
661 uint64_t value) 782 struct drm_property *property,
783 uint64_t *val)
662{ 784{
663 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p); 785 struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
664 struct atmel_hlcdc_plane_properties *props = plane->properties; 786 struct atmel_hlcdc_plane_properties *props = plane->properties;
787 const struct atmel_hlcdc_plane_state *state =
788 container_of(s, const struct atmel_hlcdc_plane_state, base);
665 789
666 if (property == props->alpha) 790 if (property == props->alpha)
667 atmel_hlcdc_plane_set_alpha(plane, value); 791 *val = state->alpha;
668 else if (property == props->rotation)
669 atmel_hlcdc_plane_set_rotation(plane, value);
670 else 792 else
671 return -EINVAL; 793 return -EINVAL;
672 794
@@ -694,8 +816,8 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
694 816
695 if (desc->layout.xstride && desc->layout.pstride) 817 if (desc->layout.xstride && desc->layout.pstride)
696 drm_object_attach_property(&plane->base.base, 818 drm_object_attach_property(&plane->base.base,
697 props->rotation, 819 plane->base.dev->mode_config.rotation_property,
698 BIT(DRM_ROTATE_0)); 820 BIT(DRM_ROTATE_0));
699 821
700 if (desc->layout.csc) { 822 if (desc->layout.csc) {
701 /* 823 /*
@@ -717,11 +839,76 @@ static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
717 } 839 }
718} 840}
719 841
842static struct drm_plane_helper_funcs atmel_hlcdc_layer_plane_helper_funcs = {
843 .prepare_fb = atmel_hlcdc_plane_prepare_fb,
844 .atomic_check = atmel_hlcdc_plane_atomic_check,
845 .atomic_update = atmel_hlcdc_plane_atomic_update,
846 .atomic_disable = atmel_hlcdc_plane_atomic_disable,
847};
848
849static void atmel_hlcdc_plane_reset(struct drm_plane *p)
850{
851 struct atmel_hlcdc_plane_state *state;
852
853 if (p->state) {
854 state = drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
855
856 if (state->base.fb)
857 drm_framebuffer_unreference(state->base.fb);
858
859 kfree(state);
860 p->state = NULL;
861 }
862
863 state = kzalloc(sizeof(*state), GFP_KERNEL);
864 if (state) {
865 state->alpha = 255;
866 p->state = &state->base;
867 p->state->plane = p;
868 }
869}
870
871static struct drm_plane_state *
872atmel_hlcdc_plane_atomic_duplicate_state(struct drm_plane *p)
873{
874 struct atmel_hlcdc_plane_state *state =
875 drm_plane_state_to_atmel_hlcdc_plane_state(p->state);
876 struct atmel_hlcdc_plane_state *copy;
877
878 copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
879 if (!copy)
880 return NULL;
881
882 copy->disc_updated = false;
883
884 if (copy->base.fb)
885 drm_framebuffer_reference(copy->base.fb);
886
887 return &copy->base;
888}
889
890static void atmel_hlcdc_plane_atomic_destroy_state(struct drm_plane *plane,
891 struct drm_plane_state *s)
892{
893 struct atmel_hlcdc_plane_state *state =
894 drm_plane_state_to_atmel_hlcdc_plane_state(s);
895
896 if (s->fb)
897 drm_framebuffer_unreference(s->fb);
898
899 kfree(state);
900}
901
720static struct drm_plane_funcs layer_plane_funcs = { 902static struct drm_plane_funcs layer_plane_funcs = {
721 .update_plane = atmel_hlcdc_plane_update, 903 .update_plane = drm_atomic_helper_update_plane,
722 .disable_plane = atmel_hlcdc_plane_disable, 904 .disable_plane = drm_atomic_helper_disable_plane,
723 .set_property = atmel_hlcdc_plane_set_property, 905 .set_property = drm_atomic_helper_plane_set_property,
724 .destroy = atmel_hlcdc_plane_destroy, 906 .destroy = atmel_hlcdc_plane_destroy,
907 .reset = atmel_hlcdc_plane_reset,
908 .atomic_duplicate_state = atmel_hlcdc_plane_atomic_duplicate_state,
909 .atomic_destroy_state = atmel_hlcdc_plane_atomic_destroy_state,
910 .atomic_set_property = atmel_hlcdc_plane_atomic_set_property,
911 .atomic_get_property = atmel_hlcdc_plane_atomic_get_property,
725}; 912};
726 913
727static struct atmel_hlcdc_plane * 914static struct atmel_hlcdc_plane *
@@ -755,6 +942,9 @@ atmel_hlcdc_plane_create(struct drm_device *dev,
755 if (ret) 942 if (ret)
756 return ERR_PTR(ret); 943 return ERR_PTR(ret);
757 944
945 drm_plane_helper_add(&plane->base,
946 &atmel_hlcdc_layer_plane_helper_funcs);
947
758 /* Set default property values*/ 948 /* Set default property values*/
759 atmel_hlcdc_plane_init_properties(plane, desc, props); 949 atmel_hlcdc_plane_init_properties(plane, desc, props);
760 950
@@ -774,12 +964,13 @@ atmel_hlcdc_plane_create_properties(struct drm_device *dev)
774 if (!props->alpha) 964 if (!props->alpha)
775 return ERR_PTR(-ENOMEM); 965 return ERR_PTR(-ENOMEM);
776 966
777 props->rotation = drm_mode_create_rotation_property(dev, 967 dev->mode_config.rotation_property =
778 BIT(DRM_ROTATE_0) | 968 drm_mode_create_rotation_property(dev,
779 BIT(DRM_ROTATE_90) | 969 BIT(DRM_ROTATE_0) |
780 BIT(DRM_ROTATE_180) | 970 BIT(DRM_ROTATE_90) |
781 BIT(DRM_ROTATE_270)); 971 BIT(DRM_ROTATE_180) |
782 if (!props->rotation) 972 BIT(DRM_ROTATE_270));
973 if (!dev->mode_config.rotation_property)
783 return ERR_PTR(-ENOMEM); 974 return ERR_PTR(-ENOMEM);
784 975
785 return props; 976 return props;