1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * (C) COPYRIGHT 2018 ARM Limited. All rights reserved. |
4 | * Author: James.Qian.Wang <james.qian.wang@arm.com> |
5 | * |
6 | */ |
7 | #include <linux/clk.h> |
8 | #include <linux/pm_runtime.h> |
9 | #include <linux/spinlock.h> |
10 | |
11 | #include <drm/drm_atomic.h> |
12 | #include <drm/drm_atomic_helper.h> |
13 | #include <drm/drm_print.h> |
14 | #include <drm/drm_vblank.h> |
15 | #include <drm/drm_simple_kms_helper.h> |
16 | #include <drm/drm_bridge.h> |
17 | |
18 | #include "komeda_dev.h" |
19 | #include "komeda_kms.h" |
20 | |
21 | void komeda_crtc_get_color_config(struct drm_crtc_state *crtc_st, |
22 | u32 *color_depths, u32 *color_formats) |
23 | { |
24 | struct drm_connector *conn; |
25 | struct drm_connector_state *conn_st; |
26 | u32 conn_color_formats = ~0u; |
27 | int i, min_bpc = 31, conn_bpc = 0; |
28 | |
29 | for_each_new_connector_in_state(crtc_st->state, conn, conn_st, i) { |
30 | if (conn_st->crtc != crtc_st->crtc) |
31 | continue; |
32 | |
33 | conn_bpc = conn->display_info.bpc ? conn->display_info.bpc : 8; |
34 | conn_color_formats &= conn->display_info.color_formats; |
35 | |
36 | if (conn_bpc < min_bpc) |
37 | min_bpc = conn_bpc; |
38 | } |
39 | |
40 | /* connector doesn't config any color_format, use RGB444 as default */ |
41 | if (!conn_color_formats) |
42 | conn_color_formats = DRM_COLOR_FORMAT_RGB444; |
43 | |
44 | *color_depths = GENMASK(min_bpc, 0); |
45 | *color_formats = conn_color_formats; |
46 | } |
47 | |
48 | static void komeda_crtc_update_clock_ratio(struct komeda_crtc_state *kcrtc_st) |
49 | { |
50 | u64 pxlclk, aclk; |
51 | |
52 | if (!kcrtc_st->base.active) { |
53 | kcrtc_st->clock_ratio = 0; |
54 | return; |
55 | } |
56 | |
57 | pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000ULL; |
58 | aclk = komeda_crtc_get_aclk(kcrtc_st); |
59 | |
60 | kcrtc_st->clock_ratio = div64_u64(dividend: aclk << 32, divisor: pxlclk); |
61 | } |
62 | |
63 | /** |
64 | * komeda_crtc_atomic_check - build display output data flow |
65 | * @crtc: DRM crtc |
66 | * @state: the crtc state object |
67 | * |
68 | * crtc_atomic_check is the final check stage, so beside build a display data |
69 | * pipeline according to the crtc_state, but still needs to release or disable |
70 | * the unclaimed pipeline resources. |
71 | * |
72 | * RETURNS: |
73 | * Zero for success or -errno |
74 | */ |
75 | static int |
76 | komeda_crtc_atomic_check(struct drm_crtc *crtc, |
77 | struct drm_atomic_state *state) |
78 | { |
79 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, |
80 | crtc); |
81 | struct komeda_crtc *kcrtc = to_kcrtc(crtc); |
82 | struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc_state); |
83 | int err; |
84 | |
85 | if (drm_atomic_crtc_needs_modeset(state: crtc_state)) |
86 | komeda_crtc_update_clock_ratio(kcrtc_st); |
87 | |
88 | if (crtc_state->active) { |
89 | err = komeda_build_display_data_flow(kcrtc, kcrtc_st); |
90 | if (err) |
91 | return err; |
92 | } |
93 | |
94 | /* release unclaimed pipeline resources */ |
95 | err = komeda_release_unclaimed_resources(pipe: kcrtc->slave, kcrtc_st); |
96 | if (err) |
97 | return err; |
98 | |
99 | err = komeda_release_unclaimed_resources(pipe: kcrtc->master, kcrtc_st); |
100 | if (err) |
101 | return err; |
102 | |
103 | return 0; |
104 | } |
105 | |
106 | /* For active a crtc, mainly need two parts of preparation |
107 | * 1. adjust display operation mode. |
108 | * 2. enable needed clk |
109 | */ |
110 | static int |
111 | komeda_crtc_prepare(struct komeda_crtc *kcrtc) |
112 | { |
113 | struct komeda_dev *mdev = kcrtc->base.dev->dev_private; |
114 | struct komeda_pipeline *master = kcrtc->master; |
115 | struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(kcrtc->base.state); |
116 | struct drm_display_mode *mode = &kcrtc_st->base.adjusted_mode; |
117 | u32 new_mode; |
118 | int err; |
119 | |
120 | mutex_lock(&mdev->lock); |
121 | |
122 | new_mode = mdev->dpmode | BIT(master->id); |
123 | if (WARN_ON(new_mode == mdev->dpmode)) { |
124 | err = 0; |
125 | goto unlock; |
126 | } |
127 | |
128 | err = mdev->funcs->change_opmode(mdev, new_mode); |
129 | if (err) { |
130 | DRM_ERROR("failed to change opmode: 0x%x -> 0x%x.\n," , |
131 | mdev->dpmode, new_mode); |
132 | goto unlock; |
133 | } |
134 | |
135 | mdev->dpmode = new_mode; |
136 | /* Only need to enable aclk on single display mode, but no need to |
137 | * enable aclk it on dual display mode, since the dual mode always |
138 | * switch from single display mode, the aclk already enabled, no need |
139 | * to enable it again. |
140 | */ |
141 | if (new_mode != KOMEDA_MODE_DUAL_DISP) { |
142 | err = clk_set_rate(clk: mdev->aclk, rate: komeda_crtc_get_aclk(kcrtc_st)); |
143 | if (err) |
144 | DRM_ERROR("failed to set aclk.\n" ); |
145 | err = clk_prepare_enable(clk: mdev->aclk); |
146 | if (err) |
147 | DRM_ERROR("failed to enable aclk.\n" ); |
148 | } |
149 | |
150 | err = clk_set_rate(clk: master->pxlclk, rate: mode->crtc_clock * 1000); |
151 | if (err) |
152 | DRM_ERROR("failed to set pxlclk for pipe%d\n" , master->id); |
153 | err = clk_prepare_enable(clk: master->pxlclk); |
154 | if (err) |
155 | DRM_ERROR("failed to enable pxl clk for pipe%d.\n" , master->id); |
156 | |
157 | unlock: |
158 | mutex_unlock(lock: &mdev->lock); |
159 | |
160 | return err; |
161 | } |
162 | |
163 | static int |
164 | komeda_crtc_unprepare(struct komeda_crtc *kcrtc) |
165 | { |
166 | struct komeda_dev *mdev = kcrtc->base.dev->dev_private; |
167 | struct komeda_pipeline *master = kcrtc->master; |
168 | u32 new_mode; |
169 | int err; |
170 | |
171 | mutex_lock(&mdev->lock); |
172 | |
173 | new_mode = mdev->dpmode & (~BIT(master->id)); |
174 | |
175 | if (WARN_ON(new_mode == mdev->dpmode)) { |
176 | err = 0; |
177 | goto unlock; |
178 | } |
179 | |
180 | err = mdev->funcs->change_opmode(mdev, new_mode); |
181 | if (err) { |
182 | DRM_ERROR("failed to change opmode: 0x%x -> 0x%x.\n," , |
183 | mdev->dpmode, new_mode); |
184 | goto unlock; |
185 | } |
186 | |
187 | mdev->dpmode = new_mode; |
188 | |
189 | clk_disable_unprepare(clk: master->pxlclk); |
190 | if (new_mode == KOMEDA_MODE_INACTIVE) |
191 | clk_disable_unprepare(clk: mdev->aclk); |
192 | |
193 | unlock: |
194 | mutex_unlock(lock: &mdev->lock); |
195 | |
196 | return err; |
197 | } |
198 | |
199 | void komeda_crtc_handle_event(struct komeda_crtc *kcrtc, |
200 | struct komeda_events *evts) |
201 | { |
202 | struct drm_crtc *crtc = &kcrtc->base; |
203 | u32 events = evts->pipes[kcrtc->master->id]; |
204 | |
205 | if (events & KOMEDA_EVENT_VSYNC) |
206 | drm_crtc_handle_vblank(crtc); |
207 | |
208 | if (events & KOMEDA_EVENT_EOW) { |
209 | struct komeda_wb_connector *wb_conn = kcrtc->wb_conn; |
210 | |
211 | if (wb_conn) |
212 | drm_writeback_signal_completion(wb_connector: &wb_conn->base, status: 0); |
213 | else |
214 | DRM_WARN("CRTC[%d]: EOW happen but no wb_connector.\n" , |
215 | drm_crtc_index(&kcrtc->base)); |
216 | } |
217 | /* will handle it together with the write back support */ |
218 | if (events & KOMEDA_EVENT_EOW) |
219 | DRM_DEBUG("EOW.\n" ); |
220 | |
221 | if (events & KOMEDA_EVENT_FLIP) { |
222 | unsigned long flags; |
223 | struct drm_pending_vblank_event *event; |
224 | |
225 | spin_lock_irqsave(&crtc->dev->event_lock, flags); |
226 | if (kcrtc->disable_done) { |
227 | complete_all(kcrtc->disable_done); |
228 | kcrtc->disable_done = NULL; |
229 | } else if (crtc->state->event) { |
230 | event = crtc->state->event; |
231 | /* |
232 | * Consume event before notifying drm core that flip |
233 | * happened. |
234 | */ |
235 | crtc->state->event = NULL; |
236 | drm_crtc_send_vblank_event(crtc, e: event); |
237 | } else { |
238 | DRM_WARN("CRTC[%d]: FLIP happened but no pending commit.\n" , |
239 | drm_crtc_index(&kcrtc->base)); |
240 | } |
241 | spin_unlock_irqrestore(lock: &crtc->dev->event_lock, flags); |
242 | } |
243 | } |
244 | |
245 | static void |
246 | komeda_crtc_do_flush(struct drm_crtc *crtc, |
247 | struct drm_crtc_state *old) |
248 | { |
249 | struct komeda_crtc *kcrtc = to_kcrtc(crtc); |
250 | struct komeda_crtc_state *kcrtc_st = to_kcrtc_st(crtc->state); |
251 | struct komeda_dev *mdev = kcrtc->base.dev->dev_private; |
252 | struct komeda_pipeline *master = kcrtc->master; |
253 | struct komeda_pipeline *slave = kcrtc->slave; |
254 | struct komeda_wb_connector *wb_conn = kcrtc->wb_conn; |
255 | struct drm_connector_state *conn_st; |
256 | |
257 | DRM_DEBUG_ATOMIC("CRTC%d_FLUSH: active_pipes: 0x%x, affected: 0x%x.\n" , |
258 | drm_crtc_index(crtc), |
259 | kcrtc_st->active_pipes, kcrtc_st->affected_pipes); |
260 | |
261 | /* step 1: update the pipeline/component state to HW */ |
262 | if (has_bit(master->id, kcrtc_st->affected_pipes)) |
263 | komeda_pipeline_update(pipe: master, old_state: old->state); |
264 | |
265 | if (slave && has_bit(slave->id, kcrtc_st->affected_pipes)) |
266 | komeda_pipeline_update(pipe: slave, old_state: old->state); |
267 | |
268 | conn_st = wb_conn ? wb_conn->base.base.state : NULL; |
269 | if (conn_st && conn_st->writeback_job) |
270 | drm_writeback_queue_job(wb_connector: &wb_conn->base, conn_state: conn_st); |
271 | |
272 | /* step 2: notify the HW to kickoff the update */ |
273 | mdev->funcs->flush(mdev, master->id, kcrtc_st->active_pipes); |
274 | } |
275 | |
276 | static void |
277 | komeda_crtc_atomic_enable(struct drm_crtc *crtc, |
278 | struct drm_atomic_state *state) |
279 | { |
280 | struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state, |
281 | crtc); |
282 | pm_runtime_get_sync(dev: crtc->dev->dev); |
283 | komeda_crtc_prepare(to_kcrtc(crtc)); |
284 | drm_crtc_vblank_on(crtc); |
285 | WARN_ON(drm_crtc_vblank_get(crtc)); |
286 | komeda_crtc_do_flush(crtc, old); |
287 | } |
288 | |
289 | void |
290 | komeda_crtc_flush_and_wait_for_flip_done(struct komeda_crtc *kcrtc, |
291 | struct completion *input_flip_done) |
292 | { |
293 | struct drm_device *drm = kcrtc->base.dev; |
294 | struct komeda_dev *mdev = kcrtc->master->mdev; |
295 | struct completion *flip_done; |
296 | struct completion temp; |
297 | int timeout; |
298 | |
299 | /* if caller doesn't send a flip_done, use a private flip_done */ |
300 | if (input_flip_done) { |
301 | flip_done = input_flip_done; |
302 | } else { |
303 | init_completion(x: &temp); |
304 | kcrtc->disable_done = &temp; |
305 | flip_done = &temp; |
306 | } |
307 | |
308 | mdev->funcs->flush(mdev, kcrtc->master->id, 0); |
309 | |
310 | /* wait the flip take affect.*/ |
311 | timeout = wait_for_completion_timeout(x: flip_done, HZ); |
312 | if (timeout == 0) { |
313 | DRM_ERROR("wait pipe%d flip done timeout\n" , kcrtc->master->id); |
314 | if (!input_flip_done) { |
315 | unsigned long flags; |
316 | |
317 | spin_lock_irqsave(&drm->event_lock, flags); |
318 | kcrtc->disable_done = NULL; |
319 | spin_unlock_irqrestore(lock: &drm->event_lock, flags); |
320 | } |
321 | } |
322 | } |
323 | |
324 | static void |
325 | komeda_crtc_atomic_disable(struct drm_crtc *crtc, |
326 | struct drm_atomic_state *state) |
327 | { |
328 | struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state, |
329 | crtc); |
330 | struct komeda_crtc *kcrtc = to_kcrtc(crtc); |
331 | struct komeda_crtc_state *old_st = to_kcrtc_st(old); |
332 | struct komeda_pipeline *master = kcrtc->master; |
333 | struct komeda_pipeline *slave = kcrtc->slave; |
334 | struct completion *disable_done; |
335 | bool needs_phase2 = false; |
336 | |
337 | DRM_DEBUG_ATOMIC("CRTC%d_DISABLE: active_pipes: 0x%x, affected: 0x%x\n" , |
338 | drm_crtc_index(crtc), |
339 | old_st->active_pipes, old_st->affected_pipes); |
340 | |
341 | if (slave && has_bit(slave->id, old_st->active_pipes)) |
342 | komeda_pipeline_disable(pipe: slave, old_state: old->state); |
343 | |
344 | if (has_bit(master->id, old_st->active_pipes)) |
345 | needs_phase2 = komeda_pipeline_disable(pipe: master, old_state: old->state); |
346 | |
347 | /* crtc_disable has two scenarios according to the state->active switch. |
348 | * 1. active -> inactive |
349 | * this commit is a disable commit. and the commit will be finished |
350 | * or done after the disable operation. on this case we can directly |
351 | * use the crtc->state->event to tracking the HW disable operation. |
352 | * 2. active -> active |
353 | * the crtc->commit is not for disable, but a modeset operation when |
354 | * crtc is active, such commit actually has been completed by 3 |
355 | * DRM operations: |
356 | * crtc_disable, update_planes(crtc_flush), crtc_enable |
357 | * so on this case the crtc->commit is for the whole process. |
358 | * we can not use it for tracing the disable, we need a temporary |
359 | * flip_done for tracing the disable. and crtc->state->event for |
360 | * the crtc_enable operation. |
361 | * That's also the reason why skip modeset commit in |
362 | * komeda_crtc_atomic_flush() |
363 | */ |
364 | disable_done = (needs_phase2 || crtc->state->active) ? |
365 | NULL : &crtc->state->commit->flip_done; |
366 | |
367 | /* wait phase 1 disable done */ |
368 | komeda_crtc_flush_and_wait_for_flip_done(kcrtc, input_flip_done: disable_done); |
369 | |
370 | /* phase 2 */ |
371 | if (needs_phase2) { |
372 | komeda_pipeline_disable(pipe: kcrtc->master, old_state: old->state); |
373 | |
374 | disable_done = crtc->state->active ? |
375 | NULL : &crtc->state->commit->flip_done; |
376 | |
377 | komeda_crtc_flush_and_wait_for_flip_done(kcrtc, input_flip_done: disable_done); |
378 | } |
379 | |
380 | drm_crtc_vblank_put(crtc); |
381 | drm_crtc_vblank_off(crtc); |
382 | komeda_crtc_unprepare(kcrtc); |
383 | pm_runtime_put(dev: crtc->dev->dev); |
384 | } |
385 | |
386 | static void |
387 | komeda_crtc_atomic_flush(struct drm_crtc *crtc, |
388 | struct drm_atomic_state *state) |
389 | { |
390 | struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, |
391 | crtc); |
392 | struct drm_crtc_state *old = drm_atomic_get_old_crtc_state(state, |
393 | crtc); |
394 | /* commit with modeset will be handled in enable/disable */ |
395 | if (drm_atomic_crtc_needs_modeset(state: crtc_state)) |
396 | return; |
397 | |
398 | komeda_crtc_do_flush(crtc, old); |
399 | } |
400 | |
401 | /* Returns the minimum frequency of the aclk rate (main engine clock) in Hz */ |
402 | static unsigned long |
403 | komeda_calc_min_aclk_rate(struct komeda_crtc *kcrtc, |
404 | unsigned long pxlclk) |
405 | { |
406 | /* Once dual-link one display pipeline drives two display outputs, |
407 | * the aclk needs run on the double rate of pxlclk |
408 | */ |
409 | if (kcrtc->master->dual_link) |
410 | return pxlclk * 2; |
411 | else |
412 | return pxlclk; |
413 | } |
414 | |
415 | /* Get current aclk rate that specified by state */ |
416 | unsigned long komeda_crtc_get_aclk(struct komeda_crtc_state *kcrtc_st) |
417 | { |
418 | struct drm_crtc *crtc = kcrtc_st->base.crtc; |
419 | struct komeda_dev *mdev = crtc->dev->dev_private; |
420 | unsigned long pxlclk = kcrtc_st->base.adjusted_mode.crtc_clock * 1000; |
421 | unsigned long min_aclk; |
422 | |
423 | min_aclk = komeda_calc_min_aclk_rate(to_kcrtc(crtc), pxlclk); |
424 | |
425 | return clk_round_rate(clk: mdev->aclk, rate: min_aclk); |
426 | } |
427 | |
428 | static enum drm_mode_status |
429 | komeda_crtc_mode_valid(struct drm_crtc *crtc, const struct drm_display_mode *m) |
430 | { |
431 | struct komeda_dev *mdev = crtc->dev->dev_private; |
432 | struct komeda_crtc *kcrtc = to_kcrtc(crtc); |
433 | struct komeda_pipeline *master = kcrtc->master; |
434 | unsigned long min_pxlclk, min_aclk; |
435 | |
436 | if (m->flags & DRM_MODE_FLAG_INTERLACE) |
437 | return MODE_NO_INTERLACE; |
438 | |
439 | min_pxlclk = m->clock * 1000; |
440 | if (master->dual_link) |
441 | min_pxlclk /= 2; |
442 | |
443 | if (min_pxlclk != clk_round_rate(clk: master->pxlclk, rate: min_pxlclk)) { |
444 | DRM_DEBUG_ATOMIC("pxlclk doesn't support %lu Hz\n" , min_pxlclk); |
445 | |
446 | return MODE_NOCLOCK; |
447 | } |
448 | |
449 | min_aclk = komeda_calc_min_aclk_rate(to_kcrtc(crtc), pxlclk: min_pxlclk); |
450 | if (clk_round_rate(clk: mdev->aclk, rate: min_aclk) < min_aclk) { |
451 | DRM_DEBUG_ATOMIC("engine clk can't satisfy the requirement of %s-clk: %lu.\n" , |
452 | m->name, min_pxlclk); |
453 | |
454 | return MODE_CLOCK_HIGH; |
455 | } |
456 | |
457 | return MODE_OK; |
458 | } |
459 | |
460 | static bool komeda_crtc_mode_fixup(struct drm_crtc *crtc, |
461 | const struct drm_display_mode *m, |
462 | struct drm_display_mode *adjusted_mode) |
463 | { |
464 | struct komeda_crtc *kcrtc = to_kcrtc(crtc); |
465 | unsigned long clk_rate; |
466 | |
467 | drm_mode_set_crtcinfo(p: adjusted_mode, adjust_flags: 0); |
468 | /* In dual link half the horizontal settings */ |
469 | if (kcrtc->master->dual_link) { |
470 | adjusted_mode->crtc_clock /= 2; |
471 | adjusted_mode->crtc_hdisplay /= 2; |
472 | adjusted_mode->crtc_hsync_start /= 2; |
473 | adjusted_mode->crtc_hsync_end /= 2; |
474 | adjusted_mode->crtc_htotal /= 2; |
475 | } |
476 | |
477 | clk_rate = adjusted_mode->crtc_clock * 1000; |
478 | /* crtc_clock will be used as the komeda output pixel clock */ |
479 | adjusted_mode->crtc_clock = clk_round_rate(clk: kcrtc->master->pxlclk, |
480 | rate: clk_rate) / 1000; |
481 | |
482 | return true; |
483 | } |
484 | |
485 | static const struct drm_crtc_helper_funcs komeda_crtc_helper_funcs = { |
486 | .atomic_check = komeda_crtc_atomic_check, |
487 | .atomic_flush = komeda_crtc_atomic_flush, |
488 | .atomic_enable = komeda_crtc_atomic_enable, |
489 | .atomic_disable = komeda_crtc_atomic_disable, |
490 | .mode_valid = komeda_crtc_mode_valid, |
491 | .mode_fixup = komeda_crtc_mode_fixup, |
492 | }; |
493 | |
494 | static void komeda_crtc_reset(struct drm_crtc *crtc) |
495 | { |
496 | struct komeda_crtc_state *state; |
497 | |
498 | if (crtc->state) |
499 | __drm_atomic_helper_crtc_destroy_state(state: crtc->state); |
500 | |
501 | kfree(to_kcrtc_st(crtc->state)); |
502 | crtc->state = NULL; |
503 | |
504 | state = kzalloc(size: sizeof(*state), GFP_KERNEL); |
505 | if (state) |
506 | __drm_atomic_helper_crtc_reset(crtc, state: &state->base); |
507 | } |
508 | |
509 | static struct drm_crtc_state * |
510 | komeda_crtc_atomic_duplicate_state(struct drm_crtc *crtc) |
511 | { |
512 | struct komeda_crtc_state *old = to_kcrtc_st(crtc->state); |
513 | struct komeda_crtc_state *new; |
514 | |
515 | new = kzalloc(size: sizeof(*new), GFP_KERNEL); |
516 | if (!new) |
517 | return NULL; |
518 | |
519 | __drm_atomic_helper_crtc_duplicate_state(crtc, state: &new->base); |
520 | |
521 | new->affected_pipes = old->active_pipes; |
522 | new->clock_ratio = old->clock_ratio; |
523 | new->max_slave_zorder = old->max_slave_zorder; |
524 | |
525 | return &new->base; |
526 | } |
527 | |
528 | static void komeda_crtc_atomic_destroy_state(struct drm_crtc *crtc, |
529 | struct drm_crtc_state *state) |
530 | { |
531 | __drm_atomic_helper_crtc_destroy_state(state); |
532 | kfree(to_kcrtc_st(state)); |
533 | } |
534 | |
535 | static int komeda_crtc_vblank_enable(struct drm_crtc *crtc) |
536 | { |
537 | struct komeda_dev *mdev = crtc->dev->dev_private; |
538 | struct komeda_crtc *kcrtc = to_kcrtc(crtc); |
539 | |
540 | mdev->funcs->on_off_vblank(mdev, kcrtc->master->id, true); |
541 | return 0; |
542 | } |
543 | |
544 | static void komeda_crtc_vblank_disable(struct drm_crtc *crtc) |
545 | { |
546 | struct komeda_dev *mdev = crtc->dev->dev_private; |
547 | struct komeda_crtc *kcrtc = to_kcrtc(crtc); |
548 | |
549 | mdev->funcs->on_off_vblank(mdev, kcrtc->master->id, false); |
550 | } |
551 | |
552 | static const struct drm_crtc_funcs komeda_crtc_funcs = { |
553 | .destroy = drm_crtc_cleanup, |
554 | .set_config = drm_atomic_helper_set_config, |
555 | .page_flip = drm_atomic_helper_page_flip, |
556 | .reset = komeda_crtc_reset, |
557 | .atomic_duplicate_state = komeda_crtc_atomic_duplicate_state, |
558 | .atomic_destroy_state = komeda_crtc_atomic_destroy_state, |
559 | .enable_vblank = komeda_crtc_vblank_enable, |
560 | .disable_vblank = komeda_crtc_vblank_disable, |
561 | }; |
562 | |
563 | int komeda_kms_setup_crtcs(struct komeda_kms_dev *kms, |
564 | struct komeda_dev *mdev) |
565 | { |
566 | struct komeda_crtc *crtc; |
567 | struct komeda_pipeline *master; |
568 | char str[16]; |
569 | int i; |
570 | |
571 | kms->n_crtcs = 0; |
572 | |
573 | for (i = 0; i < mdev->n_pipelines; i++) { |
574 | crtc = &kms->crtcs[kms->n_crtcs]; |
575 | master = mdev->pipelines[i]; |
576 | |
577 | crtc->master = master; |
578 | crtc->slave = komeda_pipeline_get_slave(master); |
579 | |
580 | if (crtc->slave) |
581 | sprintf(buf: str, fmt: "pipe-%d" , crtc->slave->id); |
582 | else |
583 | sprintf(buf: str, fmt: "None" ); |
584 | |
585 | DRM_INFO("CRTC-%d: master(pipe-%d) slave(%s).\n" , |
586 | kms->n_crtcs, master->id, str); |
587 | |
588 | kms->n_crtcs++; |
589 | } |
590 | |
591 | return 0; |
592 | } |
593 | |
594 | static struct drm_plane * |
595 | get_crtc_primary(struct komeda_kms_dev *kms, struct komeda_crtc *crtc) |
596 | { |
597 | struct komeda_plane *kplane; |
598 | struct drm_plane *plane; |
599 | |
600 | drm_for_each_plane(plane, &kms->base) { |
601 | if (plane->type != DRM_PLANE_TYPE_PRIMARY) |
602 | continue; |
603 | |
604 | kplane = to_kplane(plane); |
605 | /* only master can be primary */ |
606 | if (kplane->layer->base.pipeline == crtc->master) |
607 | return plane; |
608 | } |
609 | |
610 | return NULL; |
611 | } |
612 | |
613 | static int komeda_crtc_add(struct komeda_kms_dev *kms, |
614 | struct komeda_crtc *kcrtc) |
615 | { |
616 | struct drm_crtc *crtc = &kcrtc->base; |
617 | struct drm_device *base = &kms->base; |
618 | struct drm_bridge *bridge; |
619 | int err; |
620 | |
621 | err = drm_crtc_init_with_planes(dev: base, crtc, |
622 | primary: get_crtc_primary(kms, crtc: kcrtc), NULL, |
623 | funcs: &komeda_crtc_funcs, NULL); |
624 | if (err) |
625 | return err; |
626 | |
627 | drm_crtc_helper_add(crtc, funcs: &komeda_crtc_helper_funcs); |
628 | |
629 | crtc->port = kcrtc->master->of_output_port; |
630 | |
631 | /* Construct an encoder for each pipeline and attach it to the remote |
632 | * bridge |
633 | */ |
634 | kcrtc->encoder.possible_crtcs = drm_crtc_mask(crtc); |
635 | err = drm_simple_encoder_init(dev: base, encoder: &kcrtc->encoder, |
636 | DRM_MODE_ENCODER_TMDS); |
637 | if (err) |
638 | return err; |
639 | |
640 | bridge = devm_drm_of_get_bridge(dev: base->dev, node: kcrtc->master->of_node, |
641 | port: KOMEDA_OF_PORT_OUTPUT, endpoint: 0); |
642 | if (IS_ERR(ptr: bridge)) |
643 | return PTR_ERR(ptr: bridge); |
644 | |
645 | err = drm_bridge_attach(encoder: &kcrtc->encoder, bridge, NULL, flags: 0); |
646 | |
647 | drm_crtc_enable_color_mgmt(crtc, degamma_lut_size: 0, has_ctm: true, KOMEDA_COLOR_LUT_SIZE); |
648 | |
649 | return err; |
650 | } |
651 | |
652 | int komeda_kms_add_crtcs(struct komeda_kms_dev *kms, struct komeda_dev *mdev) |
653 | { |
654 | int i, err; |
655 | |
656 | for (i = 0; i < kms->n_crtcs; i++) { |
657 | err = komeda_crtc_add(kms, kcrtc: &kms->crtcs[i]); |
658 | if (err) |
659 | return err; |
660 | } |
661 | |
662 | return 0; |
663 | } |
664 | |