]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/gpu/drm/vc4/vc4_firmware_kms.c
drm/vc4: Fix sending of page flip completion events in FKMS mode.
[mirror_ubuntu-artful-kernel.git] / drivers / gpu / drm / vc4 / vc4_firmware_kms.c
1 /*
2 * Copyright (C) 2016 Broadcom
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9 /**
10 * DOC: VC4 firmware KMS module.
11 *
12 * As a hack to get us from the current closed source driver world
13 * toward a totally open stack, implement KMS on top of the Raspberry
14 * Pi's firmware display stack.
15 */
16
17 #include "drm/drm_atomic_helper.h"
18 #include "drm/drm_plane_helper.h"
19 #include "drm/drm_crtc_helper.h"
20 #include "linux/clk.h"
21 #include "linux/debugfs.h"
22 #include "drm/drm_fb_cma_helper.h"
23 #include "linux/component.h"
24 #include "linux/of_device.h"
25 #include "vc4_drv.h"
26 #include "vc4_regs.h"
27 #include <soc/bcm2835/raspberrypi-firmware.h>
28
29 /* The firmware delivers a vblank interrupt to us through the SMI
30 * hardware, which has only this one register.
31 */
32 #define SMICS 0x0
33 #define SMICS_INTERRUPTS (BIT(9) | BIT(10) | BIT(11))
34
35 struct vc4_crtc {
36 struct drm_crtc base;
37 struct drm_encoder *encoder;
38 struct drm_connector *connector;
39 void __iomem *regs;
40
41 struct drm_pending_vblank_event *event;
42 };
43
44 static inline struct vc4_crtc *to_vc4_crtc(struct drm_crtc *crtc)
45 {
46 return container_of(crtc, struct vc4_crtc, base);
47 }
48
49 struct vc4_fkms_encoder {
50 struct drm_encoder base;
51 };
52
53 static inline struct vc4_fkms_encoder *
54 to_vc4_fkms_encoder(struct drm_encoder *encoder)
55 {
56 return container_of(encoder, struct vc4_fkms_encoder, base);
57 }
58
59 /* VC4 FKMS connector KMS struct */
60 struct vc4_fkms_connector {
61 struct drm_connector base;
62
63 /* Since the connector is attached to just the one encoder,
64 * this is the reference to it so we can do the best_encoder()
65 * hook.
66 */
67 struct drm_encoder *encoder;
68 };
69
70 static inline struct vc4_fkms_connector *
71 to_vc4_fkms_connector(struct drm_connector *connector)
72 {
73 return container_of(connector, struct vc4_fkms_connector, base);
74 }
75
76 /* Firmware's structure for making an FB mbox call. */
77 struct fbinfo_s {
78 u32 xres, yres, xres_virtual, yres_virtual;
79 u32 pitch, bpp;
80 u32 xoffset, yoffset;
81 u32 base;
82 u32 screen_size;
83 u16 cmap[256];
84 };
85
86 struct vc4_fkms_plane {
87 struct drm_plane base;
88 struct fbinfo_s *fbinfo;
89 dma_addr_t fbinfo_bus_addr;
90 u32 pitch;
91 };
92
93 static inline struct vc4_fkms_plane *to_vc4_fkms_plane(struct drm_plane *plane)
94 {
95 return (struct vc4_fkms_plane *)plane;
96 }
97
98 /* Turns the display on/off. */
99 static int vc4_plane_set_primary_blank(struct drm_plane *plane, bool blank)
100 {
101 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
102
103 u32 packet = blank;
104
105 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary plane %s",
106 plane->base.id, plane->name,
107 blank ? "blank" : "unblank");
108
109 return rpi_firmware_property(vc4->firmware,
110 RPI_FIRMWARE_FRAMEBUFFER_BLANK,
111 &packet, sizeof(packet));
112 }
113
114 static void vc4_primary_plane_atomic_update(struct drm_plane *plane,
115 struct drm_plane_state *old_state)
116 {
117 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
118 struct vc4_fkms_plane *vc4_plane = to_vc4_fkms_plane(plane);
119 struct drm_plane_state *state = plane->state;
120 struct drm_framebuffer *fb = state->fb;
121 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
122 volatile struct fbinfo_s *fbinfo = vc4_plane->fbinfo;
123 u32 bpp = 32;
124 int ret;
125
126 vc4_plane_set_primary_blank(plane, false);
127
128 fbinfo->xres = state->crtc_w;
129 fbinfo->yres = state->crtc_h;
130 fbinfo->xres_virtual = state->crtc_w;
131 fbinfo->yres_virtual = state->crtc_h;
132 fbinfo->bpp = bpp;
133 fbinfo->xoffset = state->crtc_x;
134 fbinfo->yoffset = state->crtc_y;
135 fbinfo->base = bo->paddr + fb->offsets[0];
136 fbinfo->pitch = fb->pitches[0];
137 /* A bug in the firmware makes it so that if the fb->base is
138 * set to nonzero, the configured pitch gets overwritten with
139 * the previous pitch. So, to get the configured pitch
140 * recomputed, we have to make it allocate itself a new buffer
141 * in VC memory, first.
142 */
143 if (vc4_plane->pitch != fb->pitches[0]) {
144 u32 saved_base = fbinfo->base;
145 fbinfo->base = 0;
146
147 ret = rpi_firmware_transaction(vc4->firmware,
148 RPI_FIRMWARE_CHAN_FB,
149 vc4_plane->fbinfo_bus_addr);
150 fbinfo->base = saved_base;
151
152 vc4_plane->pitch = fbinfo->pitch;
153 WARN_ON_ONCE(vc4_plane->pitch != fb->pitches[0]);
154 }
155
156 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] primary update %dx%d@%d +%d,%d 0x%08x/%d\n",
157 plane->base.id, plane->name,
158 state->crtc_w,
159 state->crtc_h,
160 bpp,
161 state->crtc_x,
162 state->crtc_y,
163 bo->paddr + fb->offsets[0],
164 fb->pitches[0]);
165
166 ret = rpi_firmware_transaction(vc4->firmware,
167 RPI_FIRMWARE_CHAN_FB,
168 vc4_plane->fbinfo_bus_addr);
169 WARN_ON_ONCE(fbinfo->pitch != fb->pitches[0]);
170 WARN_ON_ONCE(fbinfo->base != bo->paddr + fb->offsets[0]);
171 }
172
173 static void vc4_primary_plane_atomic_disable(struct drm_plane *plane,
174 struct drm_plane_state *old_state)
175 {
176 vc4_plane_set_primary_blank(plane, true);
177 }
178
179 static void vc4_cursor_plane_atomic_update(struct drm_plane *plane,
180 struct drm_plane_state *old_state)
181 {
182 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
183 struct drm_plane_state *state = plane->state;
184 struct drm_framebuffer *fb = state->fb;
185 struct drm_gem_cma_object *bo = drm_fb_cma_get_gem_obj(fb, 0);
186 int ret;
187 u32 packet_state[] = { true, state->crtc_x, state->crtc_y, 0 };
188 u32 packet_info[] = { state->crtc_w, state->crtc_h,
189 0, /* unused */
190 bo->paddr + fb->offsets[0],
191 0, 0, /* hotx, hoty */};
192 WARN_ON_ONCE(fb->pitches[0] != state->crtc_w * 4);
193
194 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] update %dx%d cursor at %d,%d (0x%08x/%d)",
195 plane->base.id, plane->name,
196 state->crtc_w,
197 state->crtc_h,
198 state->crtc_x,
199 state->crtc_y,
200 bo->paddr + fb->offsets[0],
201 fb->pitches[0]);
202
203 ret = rpi_firmware_property(vc4->firmware,
204 RPI_FIRMWARE_SET_CURSOR_STATE,
205 &packet_state,
206 sizeof(packet_state));
207 if (ret || packet_state[0] != 0)
208 DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
209
210 ret = rpi_firmware_property(vc4->firmware,
211 RPI_FIRMWARE_SET_CURSOR_INFO,
212 &packet_info,
213 sizeof(packet_info));
214 if (ret || packet_info[0] != 0)
215 DRM_ERROR("Failed to set cursor info: 0x%08x\n", packet_info[0]);
216 }
217
218 static void vc4_cursor_plane_atomic_disable(struct drm_plane *plane,
219 struct drm_plane_state *old_state)
220 {
221 struct vc4_dev *vc4 = to_vc4_dev(plane->dev);
222 u32 packet_state[] = { false, 0, 0, 0 };
223 int ret;
224
225 DRM_DEBUG_ATOMIC("[PLANE:%d:%s] disabling cursor", plane->base.id, plane->name);
226
227 ret = rpi_firmware_property(vc4->firmware,
228 RPI_FIRMWARE_SET_CURSOR_STATE,
229 &packet_state,
230 sizeof(packet_state));
231 if (ret || packet_state[0] != 0)
232 DRM_ERROR("Failed to set cursor state: 0x%08x\n", packet_state[0]);
233 }
234
235 static int vc4_plane_atomic_check(struct drm_plane *plane,
236 struct drm_plane_state *state)
237 {
238 return 0;
239 }
240
241 static void vc4_plane_destroy(struct drm_plane *plane)
242 {
243 drm_plane_helper_disable(plane);
244 drm_plane_cleanup(plane);
245 }
246
247 static const struct drm_plane_funcs vc4_plane_funcs = {
248 .update_plane = drm_atomic_helper_update_plane,
249 .disable_plane = drm_atomic_helper_disable_plane,
250 .destroy = vc4_plane_destroy,
251 .set_property = NULL,
252 .reset = drm_atomic_helper_plane_reset,
253 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
254 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
255 };
256
257 static const struct drm_plane_helper_funcs vc4_primary_plane_helper_funcs = {
258 .prepare_fb = NULL,
259 .cleanup_fb = NULL,
260 .atomic_check = vc4_plane_atomic_check,
261 .atomic_update = vc4_primary_plane_atomic_update,
262 .atomic_disable = vc4_primary_plane_atomic_disable,
263 };
264
265 static const struct drm_plane_helper_funcs vc4_cursor_plane_helper_funcs = {
266 .prepare_fb = NULL,
267 .cleanup_fb = NULL,
268 .atomic_check = vc4_plane_atomic_check,
269 .atomic_update = vc4_cursor_plane_atomic_update,
270 .atomic_disable = vc4_cursor_plane_atomic_disable,
271 };
272
273 static struct drm_plane *vc4_fkms_plane_init(struct drm_device *dev,
274 enum drm_plane_type type)
275 {
276 struct drm_plane *plane = NULL;
277 struct vc4_fkms_plane *vc4_plane;
278 u32 xrgb8888 = DRM_FORMAT_XRGB8888;
279 u32 argb8888 = DRM_FORMAT_ARGB8888;
280 int ret = 0;
281 bool primary = (type == DRM_PLANE_TYPE_PRIMARY);
282
283 vc4_plane = devm_kzalloc(dev->dev, sizeof(*vc4_plane),
284 GFP_KERNEL);
285 if (!vc4_plane) {
286 ret = -ENOMEM;
287 goto fail;
288 }
289
290 plane = &vc4_plane->base;
291 ret = drm_universal_plane_init(dev, plane, 0xff,
292 &vc4_plane_funcs,
293 primary ? &xrgb8888 : &argb8888, 1,
294 type, primary ? "primary" : "cursor");
295
296 if (type == DRM_PLANE_TYPE_PRIMARY) {
297 vc4_plane->fbinfo =
298 dma_alloc_coherent(dev->dev,
299 sizeof(*vc4_plane->fbinfo),
300 &vc4_plane->fbinfo_bus_addr,
301 GFP_KERNEL);
302 memset(vc4_plane->fbinfo, 0, sizeof(*vc4_plane->fbinfo));
303
304 drm_plane_helper_add(plane, &vc4_primary_plane_helper_funcs);
305 } else {
306 drm_plane_helper_add(plane, &vc4_cursor_plane_helper_funcs);
307 }
308
309 return plane;
310 fail:
311 if (plane)
312 vc4_plane_destroy(plane);
313
314 return ERR_PTR(ret);
315 }
316
317 static void vc4_crtc_mode_set_nofb(struct drm_crtc *crtc)
318 {
319 /* Everyting is handled in the planes. */
320 }
321
322 static void vc4_crtc_disable(struct drm_crtc *crtc)
323 {
324 }
325
326 static void vc4_crtc_enable(struct drm_crtc *crtc)
327 {
328 }
329
330 static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
331 struct drm_crtc_state *state)
332 {
333 return 0;
334 }
335
336 static void vc4_crtc_atomic_flush(struct drm_crtc *crtc,
337 struct drm_crtc_state *old_state)
338 {
339 struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
340 struct drm_device *dev = crtc->dev;
341
342 if (crtc->state->event) {
343 unsigned long flags;
344
345 crtc->state->event->pipe = drm_crtc_index(crtc);
346
347 WARN_ON(drm_crtc_vblank_get(crtc) != 0);
348
349 spin_lock_irqsave(&dev->event_lock, flags);
350 vc4_crtc->event = crtc->state->event;
351 crtc->state->event = NULL;
352 spin_unlock_irqrestore(&dev->event_lock, flags);
353 }
354 }
355
356 static void vc4_crtc_handle_page_flip(struct vc4_crtc *vc4_crtc)
357 {
358 struct drm_crtc *crtc = &vc4_crtc->base;
359 struct drm_device *dev = crtc->dev;
360 unsigned long flags;
361
362 spin_lock_irqsave(&dev->event_lock, flags);
363 if (vc4_crtc->event) {
364 drm_crtc_send_vblank_event(crtc, vc4_crtc->event);
365 vc4_crtc->event = NULL;
366 drm_crtc_vblank_put(crtc);
367 }
368 spin_unlock_irqrestore(&dev->event_lock, flags);
369 }
370
371 static irqreturn_t vc4_crtc_irq_handler(int irq, void *data)
372 {
373 struct vc4_crtc *vc4_crtc = data;
374 u32 stat = readl(vc4_crtc->regs + SMICS);
375 irqreturn_t ret = IRQ_NONE;
376
377 if (stat & SMICS_INTERRUPTS) {
378 writel(0, vc4_crtc->regs + SMICS);
379 drm_crtc_handle_vblank(&vc4_crtc->base);
380 vc4_crtc_handle_page_flip(vc4_crtc);
381 ret = IRQ_HANDLED;
382 }
383
384 return ret;
385 }
386
387 static int vc4_page_flip(struct drm_crtc *crtc,
388 struct drm_framebuffer *fb,
389 struct drm_pending_vblank_event *event,
390 uint32_t flags, struct drm_modeset_acquire_ctx *ctx)
391 {
392 if (flags & DRM_MODE_PAGE_FLIP_ASYNC) {
393 DRM_ERROR("Async flips aren't allowed\n");
394 return -EINVAL;
395 }
396
397 return drm_atomic_helper_page_flip(crtc, fb, event, flags, ctx);
398 }
399
400 static const struct drm_crtc_funcs vc4_crtc_funcs = {
401 .set_config = drm_atomic_helper_set_config,
402 .destroy = drm_crtc_cleanup,
403 .page_flip = vc4_page_flip,
404 .set_property = NULL,
405 .cursor_set = NULL, /* handled by drm_mode_cursor_universal */
406 .cursor_move = NULL, /* handled by drm_mode_cursor_universal */
407 .reset = drm_atomic_helper_crtc_reset,
408 .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
409 .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
410 };
411
412 static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
413 .mode_set_nofb = vc4_crtc_mode_set_nofb,
414 .disable = vc4_crtc_disable,
415 .enable = vc4_crtc_enable,
416 .atomic_check = vc4_crtc_atomic_check,
417 .atomic_flush = vc4_crtc_atomic_flush,
418 };
419
420 /* Frees the page flip event when the DRM device is closed with the
421 * event still outstanding.
422 */
423 void vc4_fkms_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
424 {
425 struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
426 struct drm_device *dev = crtc->dev;
427 unsigned long flags;
428
429 spin_lock_irqsave(&dev->event_lock, flags);
430
431 if (vc4_crtc->event && vc4_crtc->event->base.file_priv == file) {
432 kfree(&vc4_crtc->event->base);
433 drm_crtc_vblank_put(crtc);
434 vc4_crtc->event = NULL;
435 }
436
437 spin_unlock_irqrestore(&dev->event_lock, flags);
438 }
439
440 static const struct of_device_id vc4_firmware_kms_dt_match[] = {
441 { .compatible = "raspberrypi,rpi-firmware-kms" },
442 {}
443 };
444
445 static enum drm_connector_status
446 vc4_fkms_connector_detect(struct drm_connector *connector, bool force)
447 {
448 return connector_status_connected;
449 }
450
451 static int vc4_fkms_connector_get_modes(struct drm_connector *connector)
452 {
453 struct drm_device *dev = connector->dev;
454 struct vc4_dev *vc4 = to_vc4_dev(dev);
455 u32 wh[2] = {0, 0};
456 int ret;
457 struct drm_display_mode *mode;
458
459 ret = rpi_firmware_property(vc4->firmware,
460 RPI_FIRMWARE_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT,
461 &wh, sizeof(wh));
462 if (ret) {
463 DRM_ERROR("Failed to get screen size: %d (0x%08x 0x%08x)\n",
464 ret, wh[0], wh[1]);
465 return 0;
466 }
467
468 mode = drm_cvt_mode(dev, wh[0], wh[1], 60 /* vrefresh */,
469 0, 0, false);
470 drm_mode_probed_add(connector, mode);
471
472 return 1;
473 }
474
475 static struct drm_encoder *
476 vc4_fkms_connector_best_encoder(struct drm_connector *connector)
477 {
478 struct vc4_fkms_connector *fkms_connector =
479 to_vc4_fkms_connector(connector);
480 return fkms_connector->encoder;
481 }
482
483 static void vc4_fkms_connector_destroy(struct drm_connector *connector)
484 {
485 drm_connector_unregister(connector);
486 drm_connector_cleanup(connector);
487 }
488
489 static const struct drm_connector_funcs vc4_fkms_connector_funcs = {
490 .dpms = drm_atomic_helper_connector_dpms,
491 .detect = vc4_fkms_connector_detect,
492 .fill_modes = drm_helper_probe_single_connector_modes,
493 .destroy = vc4_fkms_connector_destroy,
494 .reset = drm_atomic_helper_connector_reset,
495 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
496 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
497 };
498
499 static const struct drm_connector_helper_funcs vc4_fkms_connector_helper_funcs = {
500 .get_modes = vc4_fkms_connector_get_modes,
501 .best_encoder = vc4_fkms_connector_best_encoder,
502 };
503
504 static struct drm_connector *vc4_fkms_connector_init(struct drm_device *dev,
505 struct drm_encoder *encoder)
506 {
507 struct drm_connector *connector = NULL;
508 struct vc4_fkms_connector *fkms_connector;
509 int ret = 0;
510
511 fkms_connector = devm_kzalloc(dev->dev, sizeof(*fkms_connector),
512 GFP_KERNEL);
513 if (!fkms_connector) {
514 ret = -ENOMEM;
515 goto fail;
516 }
517 connector = &fkms_connector->base;
518
519 fkms_connector->encoder = encoder;
520
521 drm_connector_init(dev, connector, &vc4_fkms_connector_funcs,
522 DRM_MODE_CONNECTOR_HDMIA);
523 drm_connector_helper_add(connector, &vc4_fkms_connector_helper_funcs);
524
525 connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
526 DRM_CONNECTOR_POLL_DISCONNECT);
527
528 connector->interlace_allowed = 0;
529 connector->doublescan_allowed = 0;
530
531 drm_mode_connector_attach_encoder(connector, encoder);
532
533 return connector;
534
535 fail:
536 if (connector)
537 vc4_fkms_connector_destroy(connector);
538
539 return ERR_PTR(ret);
540 }
541
542 static void vc4_fkms_encoder_destroy(struct drm_encoder *encoder)
543 {
544 drm_encoder_cleanup(encoder);
545 }
546
547 static const struct drm_encoder_funcs vc4_fkms_encoder_funcs = {
548 .destroy = vc4_fkms_encoder_destroy,
549 };
550
551 static void vc4_fkms_encoder_enable(struct drm_encoder *encoder)
552 {
553 }
554
555 static void vc4_fkms_encoder_disable(struct drm_encoder *encoder)
556 {
557 }
558
559 static const struct drm_encoder_helper_funcs vc4_fkms_encoder_helper_funcs = {
560 .enable = vc4_fkms_encoder_enable,
561 .disable = vc4_fkms_encoder_disable,
562 };
563
564 static int vc4_fkms_bind(struct device *dev, struct device *master, void *data)
565 {
566 struct platform_device *pdev = to_platform_device(dev);
567 struct drm_device *drm = dev_get_drvdata(master);
568 struct vc4_dev *vc4 = to_vc4_dev(drm);
569 struct vc4_crtc *vc4_crtc;
570 struct vc4_fkms_encoder *vc4_encoder;
571 struct drm_crtc *crtc;
572 struct drm_plane *primary_plane, *cursor_plane, *destroy_plane, *temp;
573 struct device_node *firmware_node;
574 int ret;
575
576 vc4->firmware_kms = true;
577
578 vc4_crtc = devm_kzalloc(dev, sizeof(*vc4_crtc), GFP_KERNEL);
579 if (!vc4_crtc)
580 return -ENOMEM;
581 crtc = &vc4_crtc->base;
582
583 firmware_node = of_parse_phandle(dev->of_node, "brcm,firmware", 0);
584 vc4->firmware = rpi_firmware_get(firmware_node);
585 if (!vc4->firmware) {
586 DRM_DEBUG("Failed to get Raspberry Pi firmware reference.\n");
587 return -EPROBE_DEFER;
588 }
589 of_node_put(firmware_node);
590
591 /* Map the SMI interrupt reg */
592 vc4_crtc->regs = vc4_ioremap_regs(pdev, 0);
593 if (IS_ERR(vc4_crtc->regs))
594 return PTR_ERR(vc4_crtc->regs);
595
596 /* For now, we create just the primary and the legacy cursor
597 * planes. We should be able to stack more planes on easily,
598 * but to do that we would need to compute the bandwidth
599 * requirement of the plane configuration, and reject ones
600 * that will take too much.
601 */
602 primary_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_PRIMARY);
603 if (IS_ERR(primary_plane)) {
604 dev_err(dev, "failed to construct primary plane\n");
605 ret = PTR_ERR(primary_plane);
606 goto err;
607 }
608
609 cursor_plane = vc4_fkms_plane_init(drm, DRM_PLANE_TYPE_CURSOR);
610 if (IS_ERR(cursor_plane)) {
611 dev_err(dev, "failed to construct cursor plane\n");
612 ret = PTR_ERR(cursor_plane);
613 goto err;
614 }
615
616 drm_crtc_init_with_planes(drm, crtc, primary_plane, cursor_plane,
617 &vc4_crtc_funcs, NULL);
618 drm_crtc_helper_add(crtc, &vc4_crtc_helper_funcs);
619 primary_plane->crtc = crtc;
620 cursor_plane->crtc = crtc;
621
622 vc4_encoder = devm_kzalloc(dev, sizeof(*vc4_encoder), GFP_KERNEL);
623 if (!vc4_encoder)
624 return -ENOMEM;
625 vc4_crtc->encoder = &vc4_encoder->base;
626 vc4_encoder->base.possible_crtcs |= drm_crtc_mask(crtc) ;
627 drm_encoder_init(drm, &vc4_encoder->base, &vc4_fkms_encoder_funcs,
628 DRM_MODE_ENCODER_TMDS, NULL);
629 drm_encoder_helper_add(&vc4_encoder->base,
630 &vc4_fkms_encoder_helper_funcs);
631
632 vc4_crtc->connector = vc4_fkms_connector_init(drm, &vc4_encoder->base);
633 if (IS_ERR(vc4_crtc->connector)) {
634 ret = PTR_ERR(vc4_crtc->connector);
635 goto err_destroy_encoder;
636 }
637
638 writel(0, vc4_crtc->regs + SMICS);
639 ret = devm_request_irq(dev, platform_get_irq(pdev, 0),
640 vc4_crtc_irq_handler, 0, "vc4 firmware kms",
641 vc4_crtc);
642 if (ret)
643 goto err_destroy_connector;
644
645 platform_set_drvdata(pdev, vc4_crtc);
646
647 return 0;
648
649 err_destroy_connector:
650 vc4_fkms_connector_destroy(vc4_crtc->connector);
651 err_destroy_encoder:
652 vc4_fkms_encoder_destroy(vc4_crtc->encoder);
653 list_for_each_entry_safe(destroy_plane, temp,
654 &drm->mode_config.plane_list, head) {
655 if (destroy_plane->possible_crtcs == 1 << drm_crtc_index(crtc))
656 destroy_plane->funcs->destroy(destroy_plane);
657 }
658 err:
659 return ret;
660 }
661
662 static void vc4_fkms_unbind(struct device *dev, struct device *master,
663 void *data)
664 {
665 struct platform_device *pdev = to_platform_device(dev);
666 struct vc4_crtc *vc4_crtc = dev_get_drvdata(dev);
667
668 vc4_fkms_connector_destroy(vc4_crtc->connector);
669 vc4_fkms_encoder_destroy(vc4_crtc->encoder);
670 drm_crtc_cleanup(&vc4_crtc->base);
671
672 platform_set_drvdata(pdev, NULL);
673 }
674
675 static const struct component_ops vc4_fkms_ops = {
676 .bind = vc4_fkms_bind,
677 .unbind = vc4_fkms_unbind,
678 };
679
680 static int vc4_fkms_probe(struct platform_device *pdev)
681 {
682 return component_add(&pdev->dev, &vc4_fkms_ops);
683 }
684
685 static int vc4_fkms_remove(struct platform_device *pdev)
686 {
687 component_del(&pdev->dev, &vc4_fkms_ops);
688 return 0;
689 }
690
691 struct platform_driver vc4_firmware_kms_driver = {
692 .probe = vc4_fkms_probe,
693 .remove = vc4_fkms_remove,
694 .driver = {
695 .name = "vc4_firmware_kms",
696 .of_match_table = vc4_firmware_kms_dt_match,
697 },
698 };