1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2012 Russell King |
4 | * Rewritten from the dovefb driver, and Armada510 manuals. |
5 | */ |
6 | |
7 | #include <linux/clk.h> |
8 | #include <linux/component.h> |
9 | #include <linux/module.h> |
10 | #include <linux/of_device.h> |
11 | #include <linux/platform_device.h> |
12 | |
13 | #include <drm/drm_atomic.h> |
14 | #include <drm/drm_atomic_helper.h> |
15 | #include <drm/drm_probe_helper.h> |
16 | #include <drm/drm_vblank.h> |
17 | |
18 | #include "armada_crtc.h" |
19 | #include "armada_drm.h" |
20 | #include "armada_fb.h" |
21 | #include "armada_gem.h" |
22 | #include "armada_hw.h" |
23 | #include "armada_plane.h" |
24 | #include "armada_trace.h" |
25 | |
26 | /* |
27 | * A note about interlacing. Let's consider HDMI 1920x1080i. |
28 | * The timing parameters we have from X are: |
29 | * Hact HsyA HsyI Htot Vact VsyA VsyI Vtot |
30 | * 1920 2448 2492 2640 1080 1084 1094 1125 |
31 | * Which get translated to: |
32 | * Hact HsyA HsyI Htot Vact VsyA VsyI Vtot |
33 | * 1920 2448 2492 2640 540 542 547 562 |
34 | * |
35 | * This is how it is defined by CEA-861-D - line and pixel numbers are |
36 | * referenced to the rising edge of VSYNC and HSYNC. Total clocks per |
37 | * line: 2640. The odd frame, the first active line is at line 21, and |
38 | * the even frame, the first active line is 584. |
39 | * |
40 | * LN: 560 561 562 563 567 568 569 |
41 | * DE: ~~~|____________________________//__________________________ |
42 | * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____ |
43 | * VSYNC: _________________________|~~~~~~//~~~~~~~~~~~~~~~|__________ |
44 | * 22 blanking lines. VSYNC at 1320 (referenced to the HSYNC rising edge). |
45 | * |
46 | * LN: 1123 1124 1125 1 5 6 7 |
47 | * DE: ~~~|____________________________//__________________________ |
48 | * HSYNC: ____|~|_____|~|_____|~|_____|~|_//__|~|_____|~|_____|~|_____ |
49 | * VSYNC: ____________________|~~~~~~~~~~~//~~~~~~~~~~|_______________ |
50 | * 23 blanking lines |
51 | * |
52 | * The Armada LCD Controller line and pixel numbers are, like X timings, |
53 | * referenced to the top left of the active frame. |
54 | * |
55 | * So, translating these to our LCD controller: |
56 | * Odd frame, 563 total lines, VSYNC at line 543-548, pixel 1128. |
57 | * Even frame, 562 total lines, VSYNC at line 542-547, pixel 2448. |
58 | * Note: Vsync front porch remains constant! |
59 | * |
60 | * if (odd_frame) { |
61 | * vtotal = mode->crtc_vtotal + 1; |
62 | * vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay + 1; |
63 | * vhorizpos = mode->crtc_hsync_start - mode->crtc_htotal / 2 |
64 | * } else { |
65 | * vtotal = mode->crtc_vtotal; |
66 | * vbackporch = mode->crtc_vsync_start - mode->crtc_vdisplay; |
67 | * vhorizpos = mode->crtc_hsync_start; |
68 | * } |
69 | * vfrontporch = mode->crtc_vtotal - mode->crtc_vsync_end; |
70 | * |
71 | * So, we need to reprogram these registers on each vsync event: |
72 | * LCD_SPU_V_PORCH, LCD_SPU_ADV_REG, LCD_SPUT_V_H_TOTAL |
73 | * |
74 | * Note: we do not use the frame done interrupts because these appear |
75 | * to happen too early, and lead to jitter on the display (presumably |
76 | * they occur at the end of the last active line, before the vsync back |
77 | * porch, which we're reprogramming.) |
78 | */ |
79 | |
80 | void |
81 | armada_drm_crtc_update_regs(struct armada_crtc *dcrtc, struct armada_regs *regs) |
82 | { |
83 | while (regs->offset != ~0) { |
84 | void __iomem *reg = dcrtc->base + regs->offset; |
85 | uint32_t val; |
86 | |
87 | val = regs->mask; |
88 | if (val != 0) |
89 | val &= readl_relaxed(reg); |
90 | writel_relaxed(val | regs->val, reg); |
91 | ++regs; |
92 | } |
93 | } |
94 | |
95 | static void armada_drm_crtc_update(struct armada_crtc *dcrtc, bool enable) |
96 | { |
97 | uint32_t dumb_ctrl; |
98 | |
99 | dumb_ctrl = dcrtc->cfg_dumb_ctrl; |
100 | |
101 | if (enable) |
102 | dumb_ctrl |= CFG_DUMB_ENA; |
103 | |
104 | /* |
105 | * When the dumb interface isn't in DUMB24_RGB888_0 mode, it might |
106 | * be using SPI or GPIO. If we set this to DUMB_BLANK, we will |
107 | * force LCD_D[23:0] to output blank color, overriding the GPIO or |
108 | * SPI usage. So leave it as-is unless in DUMB24_RGB888_0 mode. |
109 | */ |
110 | if (!enable && (dumb_ctrl & DUMB_MASK) == DUMB24_RGB888_0) { |
111 | dumb_ctrl &= ~DUMB_MASK; |
112 | dumb_ctrl |= DUMB_BLANK; |
113 | } |
114 | |
115 | armada_updatel(val: dumb_ctrl, |
116 | mask: ~(CFG_INV_CSYNC | CFG_INV_HSYNC | CFG_INV_VSYNC), |
117 | ptr: dcrtc->base + LCD_SPU_DUMB_CTRL); |
118 | } |
119 | |
120 | static void armada_drm_crtc_queue_state_event(struct drm_crtc *crtc) |
121 | { |
122 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
123 | struct drm_pending_vblank_event *event; |
124 | |
125 | /* If we have an event, we need vblank events enabled */ |
126 | event = xchg(&crtc->state->event, NULL); |
127 | if (event) { |
128 | WARN_ON(drm_crtc_vblank_get(crtc) != 0); |
129 | dcrtc->event = event; |
130 | } |
131 | } |
132 | |
133 | static void armada_drm_update_gamma(struct drm_crtc *crtc) |
134 | { |
135 | struct drm_property_blob *blob = crtc->state->gamma_lut; |
136 | void __iomem *base = drm_to_armada_crtc(crtc)->base; |
137 | int i; |
138 | |
139 | if (blob) { |
140 | struct drm_color_lut *lut = blob->data; |
141 | |
142 | armada_updatel(val: CFG_CSB_256x8, mask: CFG_CSB_256x8 | CFG_PDWN256x8, |
143 | ptr: base + LCD_SPU_SRAM_PARA1); |
144 | |
145 | for (i = 0; i < 256; i++) { |
146 | writel_relaxed(drm_color_lut_extract(lut[i].red, 8), |
147 | base + LCD_SPU_SRAM_WRDAT); |
148 | writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_YR, |
149 | base + LCD_SPU_SRAM_CTRL); |
150 | readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN); |
151 | writel_relaxed(drm_color_lut_extract(lut[i].green, 8), |
152 | base + LCD_SPU_SRAM_WRDAT); |
153 | writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_UG, |
154 | base + LCD_SPU_SRAM_CTRL); |
155 | readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN); |
156 | writel_relaxed(drm_color_lut_extract(lut[i].blue, 8), |
157 | base + LCD_SPU_SRAM_WRDAT); |
158 | writel_relaxed(i | SRAM_WRITE | SRAM_GAMMA_VB, |
159 | base + LCD_SPU_SRAM_CTRL); |
160 | readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN); |
161 | } |
162 | armada_updatel(val: CFG_GAMMA_ENA, mask: CFG_GAMMA_ENA, |
163 | ptr: base + LCD_SPU_DMA_CTRL0); |
164 | } else { |
165 | armada_updatel(val: 0, mask: CFG_GAMMA_ENA, ptr: base + LCD_SPU_DMA_CTRL0); |
166 | armada_updatel(val: CFG_PDWN256x8, mask: CFG_CSB_256x8 | CFG_PDWN256x8, |
167 | ptr: base + LCD_SPU_SRAM_PARA1); |
168 | } |
169 | } |
170 | |
171 | static enum drm_mode_status armada_drm_crtc_mode_valid(struct drm_crtc *crtc, |
172 | const struct drm_display_mode *mode) |
173 | { |
174 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
175 | |
176 | if (mode->vscan > 1) |
177 | return MODE_NO_VSCAN; |
178 | |
179 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) |
180 | return MODE_NO_DBLESCAN; |
181 | |
182 | if (mode->flags & DRM_MODE_FLAG_HSKEW) |
183 | return MODE_H_ILLEGAL; |
184 | |
185 | /* We can't do interlaced modes if we don't have the SPU_ADV_REG */ |
186 | if (!dcrtc->variant->has_spu_adv_reg && |
187 | mode->flags & DRM_MODE_FLAG_INTERLACE) |
188 | return MODE_NO_INTERLACE; |
189 | |
190 | if (mode->flags & (DRM_MODE_FLAG_BCAST | DRM_MODE_FLAG_PIXMUX | |
191 | DRM_MODE_FLAG_CLKDIV2)) |
192 | return MODE_BAD; |
193 | |
194 | return MODE_OK; |
195 | } |
196 | |
197 | /* The mode_config.mutex will be held for this call */ |
198 | static bool armada_drm_crtc_mode_fixup(struct drm_crtc *crtc, |
199 | const struct drm_display_mode *mode, struct drm_display_mode *adj) |
200 | { |
201 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
202 | int ret; |
203 | |
204 | /* |
205 | * Set CRTC modesetting parameters for the adjusted mode. This is |
206 | * applied after the connectors, bridges, and encoders have fixed up |
207 | * this mode, as described above drm_atomic_helper_check_modeset(). |
208 | */ |
209 | drm_mode_set_crtcinfo(p: adj, CRTC_INTERLACE_HALVE_V); |
210 | |
211 | /* |
212 | * Validate the adjusted mode in case an encoder/bridge has set |
213 | * something we don't support. |
214 | */ |
215 | if (armada_drm_crtc_mode_valid(crtc, mode: adj) != MODE_OK) |
216 | return false; |
217 | |
218 | /* Check whether the display mode is possible */ |
219 | ret = dcrtc->variant->compute_clock(dcrtc, adj, NULL); |
220 | if (ret) |
221 | return false; |
222 | |
223 | return true; |
224 | } |
225 | |
226 | /* These are locked by dev->vbl_lock */ |
227 | static void armada_drm_crtc_disable_irq(struct armada_crtc *dcrtc, u32 mask) |
228 | { |
229 | if (dcrtc->irq_ena & mask) { |
230 | dcrtc->irq_ena &= ~mask; |
231 | writel(val: dcrtc->irq_ena, addr: dcrtc->base + LCD_SPU_IRQ_ENA); |
232 | } |
233 | } |
234 | |
235 | static void armada_drm_crtc_enable_irq(struct armada_crtc *dcrtc, u32 mask) |
236 | { |
237 | if ((dcrtc->irq_ena & mask) != mask) { |
238 | dcrtc->irq_ena |= mask; |
239 | writel(val: dcrtc->irq_ena, addr: dcrtc->base + LCD_SPU_IRQ_ENA); |
240 | if (readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR) & mask) |
241 | writel(val: 0, addr: dcrtc->base + LCD_SPU_IRQ_ISR); |
242 | } |
243 | } |
244 | |
245 | static void armada_drm_crtc_irq(struct armada_crtc *dcrtc, u32 stat) |
246 | { |
247 | struct drm_pending_vblank_event *event; |
248 | void __iomem *base = dcrtc->base; |
249 | |
250 | if (stat & DMA_FF_UNDERFLOW) |
251 | DRM_ERROR("video underflow on crtc %u\n" , dcrtc->num); |
252 | if (stat & GRA_FF_UNDERFLOW) |
253 | DRM_ERROR("graphics underflow on crtc %u\n" , dcrtc->num); |
254 | |
255 | if (stat & VSYNC_IRQ) |
256 | drm_crtc_handle_vblank(crtc: &dcrtc->crtc); |
257 | |
258 | spin_lock(lock: &dcrtc->irq_lock); |
259 | if (stat & GRA_FRAME_IRQ && dcrtc->interlaced) { |
260 | int i = stat & GRA_FRAME_IRQ0 ? 0 : 1; |
261 | uint32_t val; |
262 | |
263 | writel_relaxed(dcrtc->v[i].spu_v_porch, base + LCD_SPU_V_PORCH); |
264 | writel_relaxed(dcrtc->v[i].spu_v_h_total, |
265 | base + LCD_SPUT_V_H_TOTAL); |
266 | |
267 | val = readl_relaxed(base + LCD_SPU_ADV_REG); |
268 | val &= ~(ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | ADV_VSYNCOFFEN); |
269 | val |= dcrtc->v[i].spu_adv_reg; |
270 | writel_relaxed(val, base + LCD_SPU_ADV_REG); |
271 | } |
272 | |
273 | if (stat & dcrtc->irq_ena & DUMB_FRAMEDONE) { |
274 | if (dcrtc->update_pending) { |
275 | armada_drm_crtc_update_regs(dcrtc, regs: dcrtc->regs); |
276 | dcrtc->update_pending = false; |
277 | } |
278 | if (dcrtc->cursor_update) { |
279 | writel_relaxed(dcrtc->cursor_hw_pos, |
280 | base + LCD_SPU_HWC_OVSA_HPXL_VLN); |
281 | writel_relaxed(dcrtc->cursor_hw_sz, |
282 | base + LCD_SPU_HWC_HPXL_VLN); |
283 | armada_updatel(val: CFG_HWC_ENA, |
284 | mask: CFG_HWC_ENA | CFG_HWC_1BITMOD | |
285 | CFG_HWC_1BITENA, |
286 | ptr: base + LCD_SPU_DMA_CTRL0); |
287 | dcrtc->cursor_update = false; |
288 | } |
289 | armada_drm_crtc_disable_irq(dcrtc, mask: DUMB_FRAMEDONE_ENA); |
290 | } |
291 | spin_unlock(lock: &dcrtc->irq_lock); |
292 | |
293 | if (stat & VSYNC_IRQ && !dcrtc->update_pending) { |
294 | event = xchg(&dcrtc->event, NULL); |
295 | if (event) { |
296 | spin_lock(lock: &dcrtc->crtc.dev->event_lock); |
297 | drm_crtc_send_vblank_event(crtc: &dcrtc->crtc, e: event); |
298 | spin_unlock(lock: &dcrtc->crtc.dev->event_lock); |
299 | drm_crtc_vblank_put(crtc: &dcrtc->crtc); |
300 | } |
301 | } |
302 | } |
303 | |
304 | static irqreturn_t armada_drm_irq(int irq, void *arg) |
305 | { |
306 | struct armada_crtc *dcrtc = arg; |
307 | u32 v, stat = readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR); |
308 | |
309 | /* |
310 | * Reading the ISR appears to clear bits provided CLEAN_SPU_IRQ_ISR |
311 | * is set. Writing has some other effect to acknowledge the IRQ - |
312 | * without this, we only get a single IRQ. |
313 | */ |
314 | writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); |
315 | |
316 | trace_armada_drm_irq(crtc: &dcrtc->crtc, stat); |
317 | |
318 | /* Mask out those interrupts we haven't enabled */ |
319 | v = stat & dcrtc->irq_ena; |
320 | |
321 | if (v & (VSYNC_IRQ|GRA_FRAME_IRQ|DUMB_FRAMEDONE)) { |
322 | armada_drm_crtc_irq(dcrtc, stat); |
323 | return IRQ_HANDLED; |
324 | } |
325 | return IRQ_NONE; |
326 | } |
327 | |
328 | /* The mode_config.mutex will be held for this call */ |
329 | static void armada_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) |
330 | { |
331 | struct drm_display_mode *adj = &crtc->state->adjusted_mode; |
332 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
333 | struct armada_regs regs[17]; |
334 | uint32_t lm, rm, tm, bm, val, sclk; |
335 | unsigned long flags; |
336 | unsigned i; |
337 | bool interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); |
338 | |
339 | i = 0; |
340 | rm = adj->crtc_hsync_start - adj->crtc_hdisplay; |
341 | lm = adj->crtc_htotal - adj->crtc_hsync_end; |
342 | bm = adj->crtc_vsync_start - adj->crtc_vdisplay; |
343 | tm = adj->crtc_vtotal - adj->crtc_vsync_end; |
344 | |
345 | DRM_DEBUG_KMS("[CRTC:%d:%s] mode " DRM_MODE_FMT "\n" , |
346 | crtc->base.id, crtc->name, DRM_MODE_ARG(adj)); |
347 | DRM_DEBUG_KMS("lm %d rm %d tm %d bm %d\n" , lm, rm, tm, bm); |
348 | |
349 | /* Now compute the divider for real */ |
350 | dcrtc->variant->compute_clock(dcrtc, adj, &sclk); |
351 | |
352 | armada_reg_queue_set(regs, i, sclk, LCD_CFG_SCLK_DIV); |
353 | |
354 | spin_lock_irqsave(&dcrtc->irq_lock, flags); |
355 | |
356 | dcrtc->interlaced = interlaced; |
357 | /* Even interlaced/progressive frame */ |
358 | dcrtc->v[1].spu_v_h_total = adj->crtc_vtotal << 16 | |
359 | adj->crtc_htotal; |
360 | dcrtc->v[1].spu_v_porch = tm << 16 | bm; |
361 | val = adj->crtc_hsync_start; |
362 | dcrtc->v[1].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; |
363 | |
364 | if (interlaced) { |
365 | /* Odd interlaced frame */ |
366 | val -= adj->crtc_htotal / 2; |
367 | dcrtc->v[0].spu_adv_reg = val << 20 | val | ADV_VSYNCOFFEN; |
368 | dcrtc->v[0].spu_v_h_total = dcrtc->v[1].spu_v_h_total + |
369 | (1 << 16); |
370 | dcrtc->v[0].spu_v_porch = dcrtc->v[1].spu_v_porch + 1; |
371 | } else { |
372 | dcrtc->v[0] = dcrtc->v[1]; |
373 | } |
374 | |
375 | val = adj->crtc_vdisplay << 16 | adj->crtc_hdisplay; |
376 | |
377 | armada_reg_queue_set(regs, i, val, LCD_SPU_V_H_ACTIVE); |
378 | armada_reg_queue_set(regs, i, (lm << 16) | rm, LCD_SPU_H_PORCH); |
379 | armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_porch, LCD_SPU_V_PORCH); |
380 | armada_reg_queue_set(regs, i, dcrtc->v[0].spu_v_h_total, |
381 | LCD_SPUT_V_H_TOTAL); |
382 | |
383 | if (dcrtc->variant->has_spu_adv_reg) |
384 | armada_reg_queue_mod(regs, i, dcrtc->v[0].spu_adv_reg, |
385 | ADV_VSYNC_L_OFF | ADV_VSYNC_H_OFF | |
386 | ADV_VSYNCOFFEN, LCD_SPU_ADV_REG); |
387 | |
388 | val = adj->flags & DRM_MODE_FLAG_NVSYNC ? CFG_VSYNC_INV : 0; |
389 | armada_reg_queue_mod(regs, i, val, CFG_VSYNC_INV, LCD_SPU_DMA_CTRL1); |
390 | |
391 | /* |
392 | * The documentation doesn't indicate what the normal state of |
393 | * the sync signals are. Sebastian Hesselbart kindly probed |
394 | * these signals on his board to determine their state. |
395 | * |
396 | * The non-inverted state of the sync signals is active high. |
397 | * Setting these bits makes the appropriate signal active low. |
398 | */ |
399 | val = 0; |
400 | if (adj->flags & DRM_MODE_FLAG_NCSYNC) |
401 | val |= CFG_INV_CSYNC; |
402 | if (adj->flags & DRM_MODE_FLAG_NHSYNC) |
403 | val |= CFG_INV_HSYNC; |
404 | if (adj->flags & DRM_MODE_FLAG_NVSYNC) |
405 | val |= CFG_INV_VSYNC; |
406 | armada_reg_queue_mod(regs, i, val, CFG_INV_CSYNC | CFG_INV_HSYNC | |
407 | CFG_INV_VSYNC, LCD_SPU_DUMB_CTRL); |
408 | armada_reg_queue_end(regs, i); |
409 | |
410 | armada_drm_crtc_update_regs(dcrtc, regs); |
411 | spin_unlock_irqrestore(lock: &dcrtc->irq_lock, flags); |
412 | } |
413 | |
414 | static int armada_drm_crtc_atomic_check(struct drm_crtc *crtc, |
415 | struct drm_atomic_state *state) |
416 | { |
417 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, |
418 | crtc); |
419 | DRM_DEBUG_KMS("[CRTC:%d:%s]\n" , crtc->base.id, crtc->name); |
420 | |
421 | if (crtc_state->gamma_lut && drm_color_lut_size(blob: crtc_state->gamma_lut) != 256) |
422 | return -EINVAL; |
423 | |
424 | if (crtc_state->color_mgmt_changed) |
425 | crtc_state->planes_changed = true; |
426 | |
427 | return 0; |
428 | } |
429 | |
430 | static void armada_drm_crtc_atomic_begin(struct drm_crtc *crtc, |
431 | struct drm_atomic_state *state) |
432 | { |
433 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, |
434 | crtc); |
435 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
436 | |
437 | DRM_DEBUG_KMS("[CRTC:%d:%s]\n" , crtc->base.id, crtc->name); |
438 | |
439 | if (crtc_state->color_mgmt_changed) |
440 | armada_drm_update_gamma(crtc); |
441 | |
442 | dcrtc->regs_idx = 0; |
443 | dcrtc->regs = dcrtc->atomic_regs; |
444 | } |
445 | |
446 | static void armada_drm_crtc_atomic_flush(struct drm_crtc *crtc, |
447 | struct drm_atomic_state *state) |
448 | { |
449 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, |
450 | crtc); |
451 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
452 | |
453 | DRM_DEBUG_KMS("[CRTC:%d:%s]\n" , crtc->base.id, crtc->name); |
454 | |
455 | armada_reg_queue_end(dcrtc->regs, dcrtc->regs_idx); |
456 | |
457 | /* |
458 | * If we aren't doing a full modeset, then we need to queue |
459 | * the event here. |
460 | */ |
461 | if (!drm_atomic_crtc_needs_modeset(state: crtc_state)) { |
462 | dcrtc->update_pending = true; |
463 | armada_drm_crtc_queue_state_event(crtc); |
464 | spin_lock_irq(lock: &dcrtc->irq_lock); |
465 | armada_drm_crtc_enable_irq(dcrtc, mask: DUMB_FRAMEDONE_ENA); |
466 | spin_unlock_irq(lock: &dcrtc->irq_lock); |
467 | } else { |
468 | spin_lock_irq(lock: &dcrtc->irq_lock); |
469 | armada_drm_crtc_update_regs(dcrtc, regs: dcrtc->regs); |
470 | spin_unlock_irq(lock: &dcrtc->irq_lock); |
471 | } |
472 | } |
473 | |
474 | static void armada_drm_crtc_atomic_disable(struct drm_crtc *crtc, |
475 | struct drm_atomic_state *state) |
476 | { |
477 | struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, |
478 | crtc); |
479 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
480 | struct drm_pending_vblank_event *event; |
481 | |
482 | DRM_DEBUG_KMS("[CRTC:%d:%s]\n" , crtc->base.id, crtc->name); |
483 | |
484 | if (old_state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) |
485 | drm_crtc_vblank_put(crtc); |
486 | |
487 | drm_crtc_vblank_off(crtc); |
488 | armada_drm_crtc_update(dcrtc, enable: false); |
489 | |
490 | if (!crtc->state->active) { |
491 | /* |
492 | * This modeset will be leaving the CRTC disabled, so |
493 | * call the backend to disable upstream clocks etc. |
494 | */ |
495 | if (dcrtc->variant->disable) |
496 | dcrtc->variant->disable(dcrtc); |
497 | |
498 | /* |
499 | * We will not receive any further vblank events. |
500 | * Send the flip_done event manually. |
501 | */ |
502 | event = crtc->state->event; |
503 | crtc->state->event = NULL; |
504 | if (event) { |
505 | spin_lock_irq(lock: &crtc->dev->event_lock); |
506 | drm_crtc_send_vblank_event(crtc, e: event); |
507 | spin_unlock_irq(lock: &crtc->dev->event_lock); |
508 | } |
509 | } |
510 | } |
511 | |
512 | static void armada_drm_crtc_atomic_enable(struct drm_crtc *crtc, |
513 | struct drm_atomic_state *state) |
514 | { |
515 | struct drm_crtc_state *old_state = drm_atomic_get_old_crtc_state(state, |
516 | crtc); |
517 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
518 | |
519 | DRM_DEBUG_KMS("[CRTC:%d:%s]\n" , crtc->base.id, crtc->name); |
520 | |
521 | if (!old_state->active) { |
522 | /* |
523 | * This modeset is enabling the CRTC after it having |
524 | * been disabled. Reverse the call to ->disable in |
525 | * the atomic_disable(). |
526 | */ |
527 | if (dcrtc->variant->enable) |
528 | dcrtc->variant->enable(dcrtc, &crtc->state->adjusted_mode); |
529 | } |
530 | armada_drm_crtc_update(dcrtc, enable: true); |
531 | drm_crtc_vblank_on(crtc); |
532 | |
533 | if (crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) |
534 | WARN_ON(drm_crtc_vblank_get(crtc)); |
535 | |
536 | armada_drm_crtc_queue_state_event(crtc); |
537 | } |
538 | |
539 | static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = { |
540 | .mode_valid = armada_drm_crtc_mode_valid, |
541 | .mode_fixup = armada_drm_crtc_mode_fixup, |
542 | .mode_set_nofb = armada_drm_crtc_mode_set_nofb, |
543 | .atomic_check = armada_drm_crtc_atomic_check, |
544 | .atomic_begin = armada_drm_crtc_atomic_begin, |
545 | .atomic_flush = armada_drm_crtc_atomic_flush, |
546 | .atomic_disable = armada_drm_crtc_atomic_disable, |
547 | .atomic_enable = armada_drm_crtc_atomic_enable, |
548 | }; |
549 | |
550 | static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix, |
551 | unsigned stride, unsigned width, unsigned height) |
552 | { |
553 | uint32_t addr; |
554 | unsigned y; |
555 | |
556 | addr = SRAM_HWC32_RAM1; |
557 | for (y = 0; y < height; y++) { |
558 | uint32_t *p = &pix[y * stride]; |
559 | unsigned x; |
560 | |
561 | for (x = 0; x < width; x++, p++) { |
562 | uint32_t val = *p; |
563 | |
564 | /* |
565 | * In "ARGB888" (HWC32) mode, writing to the SRAM |
566 | * requires these bits to contain: |
567 | * 31:24 = alpha 23:16 = blue 15:8 = green 7:0 = red |
568 | * So, it's actually ABGR8888. This is independent |
569 | * of the SWAPRB bits in DMA control register 0. |
570 | */ |
571 | val = (val & 0xff00ff00) | |
572 | (val & 0x000000ff) << 16 | |
573 | (val & 0x00ff0000) >> 16; |
574 | |
575 | writel_relaxed(val, |
576 | base + LCD_SPU_SRAM_WRDAT); |
577 | writel_relaxed(addr | SRAM_WRITE, |
578 | base + LCD_SPU_SRAM_CTRL); |
579 | readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN); |
580 | addr += 1; |
581 | if ((addr & 0x00ff) == 0) |
582 | addr += 0xf00; |
583 | if ((addr & 0x30ff) == 0) |
584 | addr = SRAM_HWC32_RAM2; |
585 | } |
586 | } |
587 | } |
588 | |
589 | static void armada_drm_crtc_cursor_tran(void __iomem *base) |
590 | { |
591 | unsigned addr; |
592 | |
593 | for (addr = 0; addr < 256; addr++) { |
594 | /* write the default value */ |
595 | writel_relaxed(0x55555555, base + LCD_SPU_SRAM_WRDAT); |
596 | writel_relaxed(addr | SRAM_WRITE | SRAM_HWC32_TRAN, |
597 | base + LCD_SPU_SRAM_CTRL); |
598 | } |
599 | } |
600 | |
601 | static int armada_drm_crtc_cursor_update(struct armada_crtc *dcrtc, bool reload) |
602 | { |
603 | uint32_t xoff, xscr, w = dcrtc->cursor_w, s; |
604 | uint32_t yoff, yscr, h = dcrtc->cursor_h; |
605 | uint32_t para1; |
606 | |
607 | /* |
608 | * Calculate the visible width and height of the cursor, |
609 | * screen position, and the position in the cursor bitmap. |
610 | */ |
611 | if (dcrtc->cursor_x < 0) { |
612 | xoff = -dcrtc->cursor_x; |
613 | xscr = 0; |
614 | w -= min(xoff, w); |
615 | } else if (dcrtc->cursor_x + w > dcrtc->crtc.mode.hdisplay) { |
616 | xoff = 0; |
617 | xscr = dcrtc->cursor_x; |
618 | w = max_t(int, dcrtc->crtc.mode.hdisplay - dcrtc->cursor_x, 0); |
619 | } else { |
620 | xoff = 0; |
621 | xscr = dcrtc->cursor_x; |
622 | } |
623 | |
624 | if (dcrtc->cursor_y < 0) { |
625 | yoff = -dcrtc->cursor_y; |
626 | yscr = 0; |
627 | h -= min(yoff, h); |
628 | } else if (dcrtc->cursor_y + h > dcrtc->crtc.mode.vdisplay) { |
629 | yoff = 0; |
630 | yscr = dcrtc->cursor_y; |
631 | h = max_t(int, dcrtc->crtc.mode.vdisplay - dcrtc->cursor_y, 0); |
632 | } else { |
633 | yoff = 0; |
634 | yscr = dcrtc->cursor_y; |
635 | } |
636 | |
637 | /* On interlaced modes, the vertical cursor size must be halved */ |
638 | s = dcrtc->cursor_w; |
639 | if (dcrtc->interlaced) { |
640 | s *= 2; |
641 | yscr /= 2; |
642 | h /= 2; |
643 | } |
644 | |
645 | if (!dcrtc->cursor_obj || !h || !w) { |
646 | spin_lock_irq(lock: &dcrtc->irq_lock); |
647 | dcrtc->cursor_update = false; |
648 | armada_updatel(val: 0, mask: CFG_HWC_ENA, ptr: dcrtc->base + LCD_SPU_DMA_CTRL0); |
649 | spin_unlock_irq(lock: &dcrtc->irq_lock); |
650 | return 0; |
651 | } |
652 | |
653 | spin_lock_irq(lock: &dcrtc->irq_lock); |
654 | para1 = readl_relaxed(dcrtc->base + LCD_SPU_SRAM_PARA1); |
655 | armada_updatel(val: CFG_CSB_256x32, mask: CFG_CSB_256x32 | CFG_PDWN256x32, |
656 | ptr: dcrtc->base + LCD_SPU_SRAM_PARA1); |
657 | spin_unlock_irq(lock: &dcrtc->irq_lock); |
658 | |
659 | /* |
660 | * Initialize the transparency if the SRAM was powered down. |
661 | * We must also reload the cursor data as well. |
662 | */ |
663 | if (!(para1 & CFG_CSB_256x32)) { |
664 | armada_drm_crtc_cursor_tran(base: dcrtc->base); |
665 | reload = true; |
666 | } |
667 | |
668 | if (dcrtc->cursor_hw_sz != (h << 16 | w)) { |
669 | spin_lock_irq(lock: &dcrtc->irq_lock); |
670 | dcrtc->cursor_update = false; |
671 | armada_updatel(val: 0, mask: CFG_HWC_ENA, ptr: dcrtc->base + LCD_SPU_DMA_CTRL0); |
672 | spin_unlock_irq(lock: &dcrtc->irq_lock); |
673 | reload = true; |
674 | } |
675 | if (reload) { |
676 | struct armada_gem_object *obj = dcrtc->cursor_obj; |
677 | uint32_t *pix; |
678 | /* Set the top-left corner of the cursor image */ |
679 | pix = obj->addr; |
680 | pix += yoff * s + xoff; |
681 | armada_load_cursor_argb(base: dcrtc->base, pix, stride: s, width: w, height: h); |
682 | } |
683 | |
684 | /* Reload the cursor position, size and enable in the IRQ handler */ |
685 | spin_lock_irq(lock: &dcrtc->irq_lock); |
686 | dcrtc->cursor_hw_pos = yscr << 16 | xscr; |
687 | dcrtc->cursor_hw_sz = h << 16 | w; |
688 | dcrtc->cursor_update = true; |
689 | armada_drm_crtc_enable_irq(dcrtc, mask: DUMB_FRAMEDONE_ENA); |
690 | spin_unlock_irq(lock: &dcrtc->irq_lock); |
691 | |
692 | return 0; |
693 | } |
694 | |
695 | static void cursor_update(void *data) |
696 | { |
697 | armada_drm_crtc_cursor_update(dcrtc: data, reload: true); |
698 | } |
699 | |
700 | static int armada_drm_crtc_cursor_set(struct drm_crtc *crtc, |
701 | struct drm_file *file, uint32_t handle, uint32_t w, uint32_t h) |
702 | { |
703 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
704 | struct armada_gem_object *obj = NULL; |
705 | int ret; |
706 | |
707 | /* If no cursor support, replicate drm's return value */ |
708 | if (!dcrtc->variant->has_spu_adv_reg) |
709 | return -ENXIO; |
710 | |
711 | if (handle && w > 0 && h > 0) { |
712 | /* maximum size is 64x32 or 32x64 */ |
713 | if (w > 64 || h > 64 || (w > 32 && h > 32)) |
714 | return -ENOMEM; |
715 | |
716 | obj = armada_gem_object_lookup(dfile: file, handle); |
717 | if (!obj) |
718 | return -ENOENT; |
719 | |
720 | /* Must be a kernel-mapped object */ |
721 | if (!obj->addr) { |
722 | drm_gem_object_put(obj: &obj->obj); |
723 | return -EINVAL; |
724 | } |
725 | |
726 | if (obj->obj.size < w * h * 4) { |
727 | DRM_ERROR("buffer is too small\n" ); |
728 | drm_gem_object_put(obj: &obj->obj); |
729 | return -ENOMEM; |
730 | } |
731 | } |
732 | |
733 | if (dcrtc->cursor_obj) { |
734 | dcrtc->cursor_obj->update = NULL; |
735 | dcrtc->cursor_obj->update_data = NULL; |
736 | drm_gem_object_put(obj: &dcrtc->cursor_obj->obj); |
737 | } |
738 | dcrtc->cursor_obj = obj; |
739 | dcrtc->cursor_w = w; |
740 | dcrtc->cursor_h = h; |
741 | ret = armada_drm_crtc_cursor_update(dcrtc, reload: true); |
742 | if (obj) { |
743 | obj->update_data = dcrtc; |
744 | obj->update = cursor_update; |
745 | } |
746 | |
747 | return ret; |
748 | } |
749 | |
750 | static int armada_drm_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) |
751 | { |
752 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
753 | int ret; |
754 | |
755 | /* If no cursor support, replicate drm's return value */ |
756 | if (!dcrtc->variant->has_spu_adv_reg) |
757 | return -EFAULT; |
758 | |
759 | dcrtc->cursor_x = x; |
760 | dcrtc->cursor_y = y; |
761 | ret = armada_drm_crtc_cursor_update(dcrtc, reload: false); |
762 | |
763 | return ret; |
764 | } |
765 | |
766 | static void armada_drm_crtc_destroy(struct drm_crtc *crtc) |
767 | { |
768 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
769 | struct armada_private *priv = drm_to_armada_dev(crtc->dev); |
770 | |
771 | if (dcrtc->cursor_obj) |
772 | drm_gem_object_put(obj: &dcrtc->cursor_obj->obj); |
773 | |
774 | priv->dcrtc[dcrtc->num] = NULL; |
775 | drm_crtc_cleanup(crtc: &dcrtc->crtc); |
776 | |
777 | if (dcrtc->variant->disable) |
778 | dcrtc->variant->disable(dcrtc); |
779 | |
780 | writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ENA); |
781 | |
782 | of_node_put(node: dcrtc->crtc.port); |
783 | |
784 | kfree(objp: dcrtc); |
785 | } |
786 | |
787 | static int armada_drm_crtc_late_register(struct drm_crtc *crtc) |
788 | { |
789 | if (IS_ENABLED(CONFIG_DEBUG_FS)) |
790 | armada_drm_crtc_debugfs_init(drm_to_armada_crtc(crtc)); |
791 | |
792 | return 0; |
793 | } |
794 | |
795 | /* These are called under the vbl_lock. */ |
796 | static int armada_drm_crtc_enable_vblank(struct drm_crtc *crtc) |
797 | { |
798 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
799 | unsigned long flags; |
800 | |
801 | spin_lock_irqsave(&dcrtc->irq_lock, flags); |
802 | armada_drm_crtc_enable_irq(dcrtc, mask: VSYNC_IRQ_ENA); |
803 | spin_unlock_irqrestore(lock: &dcrtc->irq_lock, flags); |
804 | return 0; |
805 | } |
806 | |
807 | static void armada_drm_crtc_disable_vblank(struct drm_crtc *crtc) |
808 | { |
809 | struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); |
810 | unsigned long flags; |
811 | |
812 | spin_lock_irqsave(&dcrtc->irq_lock, flags); |
813 | armada_drm_crtc_disable_irq(dcrtc, mask: VSYNC_IRQ_ENA); |
814 | spin_unlock_irqrestore(lock: &dcrtc->irq_lock, flags); |
815 | } |
816 | |
817 | static const struct drm_crtc_funcs armada_crtc_funcs = { |
818 | .reset = drm_atomic_helper_crtc_reset, |
819 | .cursor_set = armada_drm_crtc_cursor_set, |
820 | .cursor_move = armada_drm_crtc_cursor_move, |
821 | .destroy = armada_drm_crtc_destroy, |
822 | .set_config = drm_atomic_helper_set_config, |
823 | .page_flip = drm_atomic_helper_page_flip, |
824 | .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state, |
825 | .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state, |
826 | .late_register = armada_drm_crtc_late_register, |
827 | .enable_vblank = armada_drm_crtc_enable_vblank, |
828 | .disable_vblank = armada_drm_crtc_disable_vblank, |
829 | }; |
830 | |
831 | int armada_crtc_select_clock(struct armada_crtc *dcrtc, |
832 | struct armada_clk_result *res, |
833 | const struct armada_clocking_params *params, |
834 | struct clk *clks[], size_t num_clks, |
835 | unsigned long desired_khz) |
836 | { |
837 | unsigned long desired_hz = desired_khz * 1000; |
838 | unsigned long desired_clk_hz; // requested clk input |
839 | unsigned long real_clk_hz; // actual clk input |
840 | unsigned long real_hz; // actual pixel clk |
841 | unsigned long permillage; |
842 | struct clk *clk; |
843 | u32 div; |
844 | int i; |
845 | |
846 | DRM_DEBUG_KMS("[CRTC:%u:%s] desired clock=%luHz\n" , |
847 | dcrtc->crtc.base.id, dcrtc->crtc.name, desired_hz); |
848 | |
849 | for (i = 0; i < num_clks; i++) { |
850 | clk = clks[i]; |
851 | if (!clk) |
852 | continue; |
853 | |
854 | if (params->settable & BIT(i)) { |
855 | real_clk_hz = clk_round_rate(clk, rate: desired_hz); |
856 | desired_clk_hz = desired_hz; |
857 | } else { |
858 | real_clk_hz = clk_get_rate(clk); |
859 | desired_clk_hz = real_clk_hz; |
860 | } |
861 | |
862 | /* If the clock can do exactly the desired rate, we're done */ |
863 | if (real_clk_hz == desired_hz) { |
864 | real_hz = real_clk_hz; |
865 | div = 1; |
866 | goto found; |
867 | } |
868 | |
869 | /* Calculate the divider - if invalid, we can't do this rate */ |
870 | div = DIV_ROUND_CLOSEST(real_clk_hz, desired_hz); |
871 | if (div == 0 || div > params->div_max) |
872 | continue; |
873 | |
874 | /* Calculate the actual rate - HDMI requires -0.6%..+0.5% */ |
875 | real_hz = DIV_ROUND_CLOSEST(real_clk_hz, div); |
876 | |
877 | DRM_DEBUG_KMS("[CRTC:%u:%s] clk=%u %luHz div=%u real=%luHz\n" , |
878 | dcrtc->crtc.base.id, dcrtc->crtc.name, |
879 | i, real_clk_hz, div, real_hz); |
880 | |
881 | /* Avoid repeated division */ |
882 | if (real_hz < desired_hz) { |
883 | permillage = real_hz / desired_khz; |
884 | if (permillage < params->permillage_min) |
885 | continue; |
886 | } else { |
887 | permillage = DIV_ROUND_UP(real_hz, desired_khz); |
888 | if (permillage > params->permillage_max) |
889 | continue; |
890 | } |
891 | goto found; |
892 | } |
893 | |
894 | return -ERANGE; |
895 | |
896 | found: |
897 | DRM_DEBUG_KMS("[CRTC:%u:%s] selected clk=%u %luHz div=%u real=%luHz\n" , |
898 | dcrtc->crtc.base.id, dcrtc->crtc.name, |
899 | i, real_clk_hz, div, real_hz); |
900 | |
901 | res->desired_clk_hz = desired_clk_hz; |
902 | res->clk = clk; |
903 | res->div = div; |
904 | |
905 | return i; |
906 | } |
907 | |
908 | static int armada_drm_crtc_create(struct drm_device *drm, struct device *dev, |
909 | struct resource *res, int irq, const struct armada_variant *variant, |
910 | struct device_node *port) |
911 | { |
912 | struct armada_private *priv = drm_to_armada_dev(drm); |
913 | struct armada_crtc *dcrtc; |
914 | struct drm_plane *primary; |
915 | void __iomem *base; |
916 | int ret; |
917 | |
918 | base = devm_ioremap_resource(dev, res); |
919 | if (IS_ERR(ptr: base)) |
920 | return PTR_ERR(ptr: base); |
921 | |
922 | dcrtc = kzalloc(size: sizeof(*dcrtc), GFP_KERNEL); |
923 | if (!dcrtc) { |
924 | DRM_ERROR("failed to allocate Armada crtc\n" ); |
925 | return -ENOMEM; |
926 | } |
927 | |
928 | if (dev != drm->dev) |
929 | dev_set_drvdata(dev, data: dcrtc); |
930 | |
931 | dcrtc->variant = variant; |
932 | dcrtc->base = base; |
933 | dcrtc->num = drm->mode_config.num_crtc; |
934 | dcrtc->cfg_dumb_ctrl = DUMB24_RGB888_0; |
935 | dcrtc->spu_iopad_ctrl = CFG_VSCALE_LN_EN | CFG_IOPAD_DUMB24; |
936 | spin_lock_init(&dcrtc->irq_lock); |
937 | dcrtc->irq_ena = CLEAN_SPU_IRQ_ISR; |
938 | |
939 | /* Initialize some registers which we don't otherwise set */ |
940 | writel_relaxed(0x00000001, dcrtc->base + LCD_CFG_SCLK_DIV); |
941 | writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_BLANKCOLOR); |
942 | writel_relaxed(dcrtc->spu_iopad_ctrl, |
943 | dcrtc->base + LCD_SPU_IOPAD_CONTROL); |
944 | writel_relaxed(0x00000000, dcrtc->base + LCD_SPU_SRAM_PARA0); |
945 | writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | |
946 | CFG_PDWN32x32 | CFG_PDWN16x66 | CFG_PDWN32x66 | |
947 | CFG_PDWN64x66, dcrtc->base + LCD_SPU_SRAM_PARA1); |
948 | writel_relaxed(0x2032ff81, dcrtc->base + LCD_SPU_DMA_CTRL1); |
949 | writel_relaxed(dcrtc->irq_ena, dcrtc->base + LCD_SPU_IRQ_ENA); |
950 | readl_relaxed(dcrtc->base + LCD_SPU_IRQ_ISR); |
951 | writel_relaxed(0, dcrtc->base + LCD_SPU_IRQ_ISR); |
952 | |
953 | ret = devm_request_irq(dev, irq, handler: armada_drm_irq, irqflags: 0, devname: "armada_drm_crtc" , |
954 | dev_id: dcrtc); |
955 | if (ret < 0) |
956 | goto err_crtc; |
957 | |
958 | if (dcrtc->variant->init) { |
959 | ret = dcrtc->variant->init(dcrtc, dev); |
960 | if (ret) |
961 | goto err_crtc; |
962 | } |
963 | |
964 | /* Ensure AXI pipeline is enabled */ |
965 | armada_updatel(val: CFG_ARBFAST_ENA, mask: 0, ptr: dcrtc->base + LCD_SPU_DMA_CTRL0); |
966 | |
967 | priv->dcrtc[dcrtc->num] = dcrtc; |
968 | |
969 | dcrtc->crtc.port = port; |
970 | |
971 | primary = kzalloc(size: sizeof(*primary), GFP_KERNEL); |
972 | if (!primary) { |
973 | ret = -ENOMEM; |
974 | goto err_crtc; |
975 | } |
976 | |
977 | ret = armada_drm_primary_plane_init(drm, primary); |
978 | if (ret) { |
979 | kfree(objp: primary); |
980 | goto err_crtc; |
981 | } |
982 | |
983 | ret = drm_crtc_init_with_planes(dev: drm, crtc: &dcrtc->crtc, primary, NULL, |
984 | funcs: &armada_crtc_funcs, NULL); |
985 | if (ret) |
986 | goto err_crtc_init; |
987 | |
988 | drm_crtc_helper_add(crtc: &dcrtc->crtc, funcs: &armada_crtc_helper_funcs); |
989 | |
990 | ret = drm_mode_crtc_set_gamma_size(crtc: &dcrtc->crtc, gamma_size: 256); |
991 | if (ret) |
992 | return ret; |
993 | |
994 | drm_crtc_enable_color_mgmt(crtc: &dcrtc->crtc, degamma_lut_size: 0, has_ctm: false, gamma_lut_size: 256); |
995 | |
996 | return armada_overlay_plane_create(drm, 1 << dcrtc->num); |
997 | |
998 | err_crtc_init: |
999 | primary->funcs->destroy(primary); |
1000 | err_crtc: |
1001 | kfree(objp: dcrtc); |
1002 | |
1003 | return ret; |
1004 | } |
1005 | |
1006 | static int |
1007 | armada_lcd_bind(struct device *dev, struct device *master, void *data) |
1008 | { |
1009 | struct platform_device *pdev = to_platform_device(dev); |
1010 | struct drm_device *drm = data; |
1011 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1012 | int irq = platform_get_irq(pdev, 0); |
1013 | const struct armada_variant *variant; |
1014 | struct device_node *port = NULL; |
1015 | |
1016 | if (irq < 0) |
1017 | return irq; |
1018 | |
1019 | if (!dev->of_node) { |
1020 | const struct platform_device_id *id; |
1021 | |
1022 | id = platform_get_device_id(pdev); |
1023 | if (!id) |
1024 | return -ENXIO; |
1025 | |
1026 | variant = (const struct armada_variant *)id->driver_data; |
1027 | } else { |
1028 | const struct of_device_id *match; |
1029 | struct device_node *np, *parent = dev->of_node; |
1030 | |
1031 | match = of_match_device(matches: dev->driver->of_match_table, dev); |
1032 | if (!match) |
1033 | return -ENXIO; |
1034 | |
1035 | np = of_get_child_by_name(node: parent, name: "ports" ); |
1036 | if (np) |
1037 | parent = np; |
1038 | port = of_get_child_by_name(node: parent, name: "port" ); |
1039 | of_node_put(node: np); |
1040 | if (!port) { |
1041 | dev_err(dev, "no port node found in %pOF\n" , parent); |
1042 | return -ENXIO; |
1043 | } |
1044 | |
1045 | variant = match->data; |
1046 | } |
1047 | |
1048 | return armada_drm_crtc_create(drm, dev, res, irq, variant, port); |
1049 | } |
1050 | |
1051 | static void |
1052 | armada_lcd_unbind(struct device *dev, struct device *master, void *data) |
1053 | { |
1054 | struct armada_crtc *dcrtc = dev_get_drvdata(dev); |
1055 | |
1056 | armada_drm_crtc_destroy(crtc: &dcrtc->crtc); |
1057 | } |
1058 | |
1059 | static const struct component_ops armada_lcd_ops = { |
1060 | .bind = armada_lcd_bind, |
1061 | .unbind = armada_lcd_unbind, |
1062 | }; |
1063 | |
1064 | static int armada_lcd_probe(struct platform_device *pdev) |
1065 | { |
1066 | return component_add(&pdev->dev, &armada_lcd_ops); |
1067 | } |
1068 | |
1069 | static int armada_lcd_remove(struct platform_device *pdev) |
1070 | { |
1071 | component_del(&pdev->dev, &armada_lcd_ops); |
1072 | return 0; |
1073 | } |
1074 | |
1075 | static const struct of_device_id armada_lcd_of_match[] = { |
1076 | { |
1077 | .compatible = "marvell,dove-lcd" , |
1078 | .data = &armada510_ops, |
1079 | }, |
1080 | {} |
1081 | }; |
1082 | MODULE_DEVICE_TABLE(of, armada_lcd_of_match); |
1083 | |
1084 | static const struct platform_device_id armada_lcd_platform_ids[] = { |
1085 | { |
1086 | .name = "armada-lcd" , |
1087 | .driver_data = (unsigned long)&armada510_ops, |
1088 | }, { |
1089 | .name = "armada-510-lcd" , |
1090 | .driver_data = (unsigned long)&armada510_ops, |
1091 | }, |
1092 | { }, |
1093 | }; |
1094 | MODULE_DEVICE_TABLE(platform, armada_lcd_platform_ids); |
1095 | |
1096 | struct platform_driver armada_lcd_platform_driver = { |
1097 | .probe = armada_lcd_probe, |
1098 | .remove = armada_lcd_remove, |
1099 | .driver = { |
1100 | .name = "armada-lcd" , |
1101 | .owner = THIS_MODULE, |
1102 | .of_match_table = armada_lcd_of_match, |
1103 | }, |
1104 | .id_table = armada_lcd_platform_ids, |
1105 | }; |
1106 | |