forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-05-13 9d77db3c730780c8ef5ccd4b66403ff5675cfe4e
kernel/drivers/gpu/drm/udl/udl_modeset.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
23 * Copyright (C) 2012 Red Hat
34 *
....@@ -6,16 +7,22 @@
67 * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
78 * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
89
9
- * This file is subject to the terms and conditions of the GNU General Public
10
- * License v2. See the file COPYING in the main directory of this archive for
11
- * more details.
1210 */
1311
14
-#include <drm/drmP.h>
15
-#include <drm/drm_crtc.h>
12
+#include <linux/dma-buf.h>
13
+
14
+#include <drm/drm_atomic_helper.h>
1615 #include <drm/drm_crtc_helper.h>
17
-#include <drm/drm_plane_helper.h>
16
+#include <drm/drm_damage_helper.h>
17
+#include <drm/drm_fourcc.h>
18
+#include <drm/drm_gem_framebuffer_helper.h>
19
+#include <drm/drm_gem_shmem_helper.h>
20
+#include <drm/drm_modeset_helper_vtables.h>
21
+#include <drm/drm_vblank.h>
22
+
1823 #include "udl_drv.h"
24
+
25
+#define UDL_COLOR_DEPTH_16BPP 0
1926
2027 /*
2128 * All DisplayLink bulk operations start with 0xAF, followed by specific code
....@@ -40,31 +47,9 @@
4047 return udl_set_register(buf, 0xFF, 0xFF);
4148 }
4249
43
-/*
44
- * On/Off for driving the DisplayLink framebuffer to the display
45
- * 0x00 H and V sync on
46
- * 0x01 H and V sync off (screen blank but powered)
47
- * 0x07 DPMS powerdown (requires modeset to come back)
48
- */
49
-static char *udl_set_blank(char *buf, int dpms_mode)
50
+static char *udl_set_blank_mode(char *buf, u8 mode)
5051 {
51
- u8 reg;
52
- switch (dpms_mode) {
53
- case DRM_MODE_DPMS_OFF:
54
- reg = 0x07;
55
- break;
56
- case DRM_MODE_DPMS_STANDBY:
57
- reg = 0x05;
58
- break;
59
- case DRM_MODE_DPMS_SUSPEND:
60
- reg = 0x01;
61
- break;
62
- case DRM_MODE_DPMS_ON:
63
- reg = 0x00;
64
- break;
65
- }
66
-
67
- return udl_set_register(buf, 0x1f, reg);
52
+ return udl_set_register(buf, UDL_REG_BLANK_MODE, mode);
6853 }
6954
7055 static char *udl_set_color_depth(char *buf, u8 selection)
....@@ -230,10 +215,15 @@
230215 static int udl_crtc_write_mode_to_hw(struct drm_crtc *crtc)
231216 {
232217 struct drm_device *dev = crtc->dev;
233
- struct udl_device *udl = dev->dev_private;
218
+ struct udl_device *udl = to_udl(dev);
234219 struct urb *urb;
235220 char *buf;
236221 int retval;
222
+
223
+ if (udl->mode_buf_len == 0) {
224
+ DRM_ERROR("No mode set\n");
225
+ return -EINVAL;
226
+ }
237227
238228 urb = udl_get_urb(dev);
239229 if (!urb)
....@@ -247,80 +237,152 @@
247237 return retval;
248238 }
249239
250
-
251
-static void udl_crtc_dpms(struct drm_crtc *crtc, int mode)
240
+static long udl_log_cpp(unsigned int cpp)
252241 {
253
- struct drm_device *dev = crtc->dev;
254
- struct udl_device *udl = dev->dev_private;
255
- int retval;
242
+ if (WARN_ON(!is_power_of_2(cpp)))
243
+ return -EINVAL;
244
+ return __ffs(cpp);
245
+}
256246
257
- if (mode == DRM_MODE_DPMS_OFF) {
258
- char *buf;
259
- struct urb *urb;
260
- urb = udl_get_urb(dev);
261
- if (!urb)
262
- return;
247
+static int udl_aligned_damage_clip(struct drm_rect *clip, int x, int y,
248
+ int width, int height)
249
+{
250
+ int x1, x2;
263251
264
- buf = (char *)urb->transfer_buffer;
265
- buf = udl_vidreg_lock(buf);
266
- buf = udl_set_blank(buf, mode);
267
- buf = udl_vidreg_unlock(buf);
252
+ if (WARN_ON_ONCE(x < 0) ||
253
+ WARN_ON_ONCE(y < 0) ||
254
+ WARN_ON_ONCE(width < 0) ||
255
+ WARN_ON_ONCE(height < 0))
256
+ return -EINVAL;
268257
269
- buf = udl_dummy_render(buf);
270
- retval = udl_submit_urb(dev, urb, buf - (char *)
271
- urb->transfer_buffer);
272
- } else {
273
- if (udl->mode_buf_len == 0) {
274
- DRM_ERROR("Trying to enable DPMS with no mode\n");
275
- return;
276
- }
277
- udl_crtc_write_mode_to_hw(crtc);
258
+ x1 = ALIGN_DOWN(x, sizeof(unsigned long));
259
+ x2 = ALIGN(width + (x - x1), sizeof(unsigned long)) + x1;
260
+
261
+ clip->x1 = x1;
262
+ clip->y1 = y;
263
+ clip->x2 = x2;
264
+ clip->y2 = y + height;
265
+
266
+ return 0;
267
+}
268
+
269
+static int udl_handle_damage(struct drm_framebuffer *fb, int x, int y,
270
+ int width, int height)
271
+{
272
+ struct drm_device *dev = fb->dev;
273
+ struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach;
274
+ int i, ret, tmp_ret;
275
+ char *cmd;
276
+ struct urb *urb;
277
+ struct drm_rect clip;
278
+ int log_bpp;
279
+ void *vaddr;
280
+
281
+ ret = udl_log_cpp(fb->format->cpp[0]);
282
+ if (ret < 0)
283
+ return ret;
284
+ log_bpp = ret;
285
+
286
+ ret = udl_aligned_damage_clip(&clip, x, y, width, height);
287
+ if (ret)
288
+ return ret;
289
+ else if ((clip.x2 > fb->width) || (clip.y2 > fb->height))
290
+ return -EINVAL;
291
+
292
+ if (import_attach) {
293
+ ret = dma_buf_begin_cpu_access(import_attach->dmabuf,
294
+ DMA_FROM_DEVICE);
295
+ if (ret)
296
+ return ret;
278297 }
279298
299
+ vaddr = drm_gem_shmem_vmap(fb->obj[0]);
300
+ if (IS_ERR(vaddr)) {
301
+ DRM_ERROR("failed to vmap fb\n");
302
+ goto out_dma_buf_end_cpu_access;
303
+ }
304
+
305
+ urb = udl_get_urb(dev);
306
+ if (!urb) {
307
+ ret = -ENOMEM;
308
+ goto out_drm_gem_shmem_vunmap;
309
+ }
310
+ cmd = urb->transfer_buffer;
311
+
312
+ for (i = clip.y1; i < clip.y2; i++) {
313
+ const int line_offset = fb->pitches[0] * i;
314
+ const int byte_offset = line_offset + (clip.x1 << log_bpp);
315
+ const int dev_byte_offset = (fb->width * i + clip.x1) << log_bpp;
316
+ const int byte_width = (clip.x2 - clip.x1) << log_bpp;
317
+ ret = udl_render_hline(dev, log_bpp, &urb, (char *)vaddr,
318
+ &cmd, byte_offset, dev_byte_offset,
319
+ byte_width);
320
+ if (ret)
321
+ goto out_drm_gem_shmem_vunmap;
322
+ }
323
+
324
+ if (cmd > (char *)urb->transfer_buffer) {
325
+ /* Send partial buffer remaining before exiting */
326
+ int len;
327
+ if (cmd < (char *)urb->transfer_buffer + urb->transfer_buffer_length)
328
+ *cmd++ = 0xAF;
329
+ len = cmd - (char *)urb->transfer_buffer;
330
+ ret = udl_submit_urb(dev, urb, len);
331
+ } else {
332
+ udl_urb_completion(urb);
333
+ }
334
+
335
+ ret = 0;
336
+
337
+out_drm_gem_shmem_vunmap:
338
+ drm_gem_shmem_vunmap(fb->obj[0], vaddr);
339
+out_dma_buf_end_cpu_access:
340
+ if (import_attach) {
341
+ tmp_ret = dma_buf_end_cpu_access(import_attach->dmabuf,
342
+ DMA_FROM_DEVICE);
343
+ if (tmp_ret && !ret)
344
+ ret = tmp_ret; /* only update ret if not set yet */
345
+ }
346
+
347
+ return ret;
280348 }
281349
282
-#if 0
283
-static int
284
-udl_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
285
- int x, int y, enum mode_set_atomic state)
350
+/*
351
+ * Simple display pipeline
352
+ */
353
+
354
+static const uint32_t udl_simple_display_pipe_formats[] = {
355
+ DRM_FORMAT_RGB565,
356
+ DRM_FORMAT_XRGB8888,
357
+};
358
+
359
+static enum drm_mode_status
360
+udl_simple_display_pipe_mode_valid(struct drm_simple_display_pipe *pipe,
361
+ const struct drm_display_mode *mode)
286362 {
287
- return 0;
363
+ return MODE_OK;
288364 }
289365
290
-static int
291
-udl_pipe_set_base(struct drm_crtc *crtc, int x, int y,
292
- struct drm_framebuffer *old_fb)
366
+static void
367
+udl_simple_display_pipe_enable(struct drm_simple_display_pipe *pipe,
368
+ struct drm_crtc_state *crtc_state,
369
+ struct drm_plane_state *plane_state)
293370 {
294
- return 0;
295
-}
296
-#endif
297
-
298
-static int udl_crtc_mode_set(struct drm_crtc *crtc,
299
- struct drm_display_mode *mode,
300
- struct drm_display_mode *adjusted_mode,
301
- int x, int y,
302
- struct drm_framebuffer *old_fb)
303
-
304
-{
371
+ struct drm_crtc *crtc = &pipe->crtc;
305372 struct drm_device *dev = crtc->dev;
306
- struct udl_framebuffer *ufb = to_udl_fb(crtc->primary->fb);
307
- struct udl_device *udl = dev->dev_private;
373
+ struct drm_framebuffer *fb = plane_state->fb;
374
+ struct udl_device *udl = to_udl(dev);
375
+ struct drm_display_mode *mode = &crtc_state->mode;
308376 char *buf;
309377 char *wrptr;
310
- int color_depth = 0;
311
-
312
- udl->crtc = crtc;
378
+ int color_depth = UDL_COLOR_DEPTH_16BPP;
313379
314380 buf = (char *)udl->mode_buf;
315381
316
- /* for now we just clip 24 -> 16 - if we fix that fix this */
317
- /*if (crtc->fb->bits_per_pixel != 16)
318
- color_depth = 1; */
319
-
320382 /* This first section has to do with setting the base address on the
321
- * controller * associated with the display. There are 2 base
322
- * pointers, currently, we only * use the 16 bpp segment.
323
- */
383
+ * controller associated with the display. There are 2 base
384
+ * pointers, currently, we only use the 16 bpp segment.
385
+ */
324386 wrptr = udl_vidreg_lock(buf);
325387 wrptr = udl_set_color_depth(wrptr, color_depth);
326388 /* set base for 16bpp segment to 0 */
....@@ -328,109 +390,86 @@
328390 /* set base for 8bpp segment to end of fb */
329391 wrptr = udl_set_base8bpp(wrptr, 2 * mode->vdisplay * mode->hdisplay);
330392
331
- wrptr = udl_set_vid_cmds(wrptr, adjusted_mode);
332
- wrptr = udl_set_blank(wrptr, DRM_MODE_DPMS_ON);
393
+ wrptr = udl_set_vid_cmds(wrptr, mode);
394
+ wrptr = udl_set_blank_mode(wrptr, UDL_BLANK_MODE_ON);
333395 wrptr = udl_vidreg_unlock(wrptr);
334396
335397 wrptr = udl_dummy_render(wrptr);
336398
337
- if (old_fb) {
338
- struct udl_framebuffer *uold_fb = to_udl_fb(old_fb);
339
- uold_fb->active_16 = false;
340
- }
341
- ufb->active_16 = true;
342399 udl->mode_buf_len = wrptr - buf;
343400
344
- /* damage all of it */
345
- udl_handle_damage(ufb, 0, 0, ufb->base.width, ufb->base.height);
346
- return 0;
401
+ udl_handle_damage(fb, 0, 0, fb->width, fb->height);
402
+
403
+ /* enable display */
404
+ udl_crtc_write_mode_to_hw(crtc);
347405 }
348406
349
-
350
-static void udl_crtc_disable(struct drm_crtc *crtc)
407
+static void
408
+udl_simple_display_pipe_disable(struct drm_simple_display_pipe *pipe)
351409 {
352
- udl_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
353
-}
354
-
355
-static void udl_crtc_destroy(struct drm_crtc *crtc)
356
-{
357
- drm_crtc_cleanup(crtc);
358
- kfree(crtc);
359
-}
360
-
361
-static int udl_crtc_page_flip(struct drm_crtc *crtc,
362
- struct drm_framebuffer *fb,
363
- struct drm_pending_vblank_event *event,
364
- uint32_t page_flip_flags,
365
- struct drm_modeset_acquire_ctx *ctx)
366
-{
367
- struct udl_framebuffer *ufb = to_udl_fb(fb);
410
+ struct drm_crtc *crtc = &pipe->crtc;
368411 struct drm_device *dev = crtc->dev;
412
+ struct urb *urb;
413
+ char *buf;
369414
370
- struct drm_framebuffer *old_fb = crtc->primary->fb;
371
- if (old_fb) {
372
- struct udl_framebuffer *uold_fb = to_udl_fb(old_fb);
373
- uold_fb->active_16 = false;
374
- }
375
- ufb->active_16 = true;
415
+ urb = udl_get_urb(dev);
416
+ if (!urb)
417
+ return;
376418
377
- udl_handle_damage(ufb, 0, 0, fb->width, fb->height);
419
+ buf = (char *)urb->transfer_buffer;
420
+ buf = udl_vidreg_lock(buf);
421
+ buf = udl_set_blank_mode(buf, UDL_BLANK_MODE_POWERDOWN);
422
+ buf = udl_vidreg_unlock(buf);
423
+ buf = udl_dummy_render(buf);
378424
379
- spin_lock_irq(&dev->event_lock);
380
- if (event)
381
- drm_crtc_send_vblank_event(crtc, event);
382
- spin_unlock_irq(&dev->event_lock);
383
- crtc->primary->fb = fb;
384
-
385
- return 0;
425
+ udl_submit_urb(dev, urb, buf - (char *)urb->transfer_buffer);
386426 }
387427
388
-static void udl_crtc_prepare(struct drm_crtc *crtc)
428
+static void
429
+udl_simple_display_pipe_update(struct drm_simple_display_pipe *pipe,
430
+ struct drm_plane_state *old_plane_state)
389431 {
432
+ struct drm_plane_state *state = pipe->plane.state;
433
+ struct drm_framebuffer *fb = state->fb;
434
+ struct drm_rect rect;
435
+
436
+ if (!fb)
437
+ return;
438
+
439
+ if (drm_atomic_helper_damage_merged(old_plane_state, state, &rect))
440
+ udl_handle_damage(fb, rect.x1, rect.y1, rect.x2 - rect.x1,
441
+ rect.y2 - rect.y1);
390442 }
391443
392
-static void udl_crtc_commit(struct drm_crtc *crtc)
393
-{
394
- udl_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
395
-}
396
-
397
-static const struct drm_crtc_helper_funcs udl_helper_funcs = {
398
- .dpms = udl_crtc_dpms,
399
- .mode_set = udl_crtc_mode_set,
400
- .prepare = udl_crtc_prepare,
401
- .commit = udl_crtc_commit,
402
- .disable = udl_crtc_disable,
444
+static const
445
+struct drm_simple_display_pipe_funcs udl_simple_display_pipe_funcs = {
446
+ .mode_valid = udl_simple_display_pipe_mode_valid,
447
+ .enable = udl_simple_display_pipe_enable,
448
+ .disable = udl_simple_display_pipe_disable,
449
+ .update = udl_simple_display_pipe_update,
450
+ .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
403451 };
404452
405
-static const struct drm_crtc_funcs udl_crtc_funcs = {
406
- .set_config = drm_crtc_helper_set_config,
407
- .destroy = udl_crtc_destroy,
408
- .page_flip = udl_crtc_page_flip,
409
-};
410
-
411
-static int udl_crtc_init(struct drm_device *dev)
412
-{
413
- struct drm_crtc *crtc;
414
-
415
- crtc = kzalloc(sizeof(struct drm_crtc) + sizeof(struct drm_connector *), GFP_KERNEL);
416
- if (crtc == NULL)
417
- return -ENOMEM;
418
-
419
- drm_crtc_init(dev, crtc, &udl_crtc_funcs);
420
- drm_crtc_helper_add(crtc, &udl_helper_funcs);
421
-
422
- return 0;
423
-}
453
+/*
454
+ * Modesetting
455
+ */
424456
425457 static const struct drm_mode_config_funcs udl_mode_funcs = {
426
- .fb_create = udl_fb_user_fb_create,
427
- .output_poll_changed = NULL,
458
+ .fb_create = drm_gem_fb_create_with_dirty,
459
+ .atomic_check = drm_atomic_helper_check,
460
+ .atomic_commit = drm_atomic_helper_commit,
428461 };
429462
430463 int udl_modeset_init(struct drm_device *dev)
431464 {
432
- struct drm_encoder *encoder;
433
- drm_mode_config_init(dev);
465
+ size_t format_count = ARRAY_SIZE(udl_simple_display_pipe_formats);
466
+ struct udl_device *udl = to_udl(dev);
467
+ struct drm_connector *connector;
468
+ int ret;
469
+
470
+ ret = drmm_mode_config_init(dev);
471
+ if (ret)
472
+ return ret;
434473
435474 dev->mode_config.min_width = 640;
436475 dev->mode_config.min_height = 480;
....@@ -439,32 +478,24 @@
439478 dev->mode_config.max_height = 2048;
440479
441480 dev->mode_config.prefer_shadow = 0;
442
- dev->mode_config.preferred_depth = 24;
481
+ dev->mode_config.preferred_depth = 16;
443482
444483 dev->mode_config.funcs = &udl_mode_funcs;
445484
446
- udl_crtc_init(dev);
485
+ connector = udl_connector_init(dev);
486
+ if (IS_ERR(connector))
487
+ return PTR_ERR(connector);
447488
448
- encoder = udl_encoder_init(dev);
489
+ format_count = ARRAY_SIZE(udl_simple_display_pipe_formats);
449490
450
- udl_connector_init(dev, encoder);
491
+ ret = drm_simple_display_pipe_init(dev, &udl->display_pipe,
492
+ &udl_simple_display_pipe_funcs,
493
+ udl_simple_display_pipe_formats,
494
+ format_count, NULL, connector);
495
+ if (ret)
496
+ return ret;
497
+
498
+ drm_mode_config_reset(dev);
451499
452500 return 0;
453
-}
454
-
455
-void udl_modeset_restore(struct drm_device *dev)
456
-{
457
- struct udl_device *udl = dev->dev_private;
458
- struct udl_framebuffer *ufb;
459
-
460
- if (!udl->crtc || !udl->crtc->primary->fb)
461
- return;
462
- udl_crtc_commit(udl->crtc);
463
- ufb = to_udl_fb(udl->crtc->primary->fb);
464
- udl_handle_damage(ufb, 0, 0, ufb->base.width, ufb->base.height);
465
-}
466
-
467
-void udl_modeset_cleanup(struct drm_device *dev)
468
-{
469
- drm_mode_config_cleanup(dev);
470501 }