aa10a18ec57ea8be9eab23ea41a6c717d60242cc
[openwrt/staging/noltari.git] / target / linux / bcm27xx / patches-5.10 / 950-0709-drm-Add-GUD-USB-Display-driver.patch
1 From 140a4e12d8ec470fe0807931893d3d48ffda46b3 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org>
3 Date: Sat, 13 Mar 2021 12:25:45 +0100
4 Subject: [PATCH] drm: Add GUD USB Display driver
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 [ Upstream commit 40e1a70b4aedf2859a1829991b48ef0ebe650bf2 ]
10
11 This adds a USB display driver with the intention that it can be
12 used with future USB interfaced low end displays/adapters. The Linux
13 gadget device driver will serve as the canonical device implementation.
14
15 The following DRM properties are supported:
16 - Plane rotation
17 - Connector TV properties
18
19 There is also support for backlight brightness exposed as a backlight
20 device.
21
22 Display modes can be made available to the host driver either as DRM
23 display modes or through EDID. If both are present, EDID is just passed
24 on to userspace.
25
26 Performance is preferred over color depth, so if the device supports
27 RGB565, DRM_CAP_DUMB_PREFERRED_DEPTH will return 16.
28
29 If the device transfer buffer can't fit an uncompressed framebuffer
30 update, the update is split up into parts that do fit.
31
32 Optimal user experience is achieved by providing damage reports either by
33 setting FB_DAMAGE_CLIPS on pageflips or calling DRM_IOCTL_MODE_DIRTYFB.
34
35 LZ4 compression is used if the device supports it.
36
37 The driver supports a one bit monochrome transfer format: R1. This is not
38 implemented in the gadget driver. It is added in preparation for future
39 monochrome e-ink displays.
40
41 The driver is MIT licensed to smooth the path for any BSD port of the
42 driver.
43
44 v2:
45 - Use devm_drm_dev_alloc() and drmm_mode_config_init()
46 - drm_fbdev_generic_setup: Use preferred_bpp=0, 16 was a copy paste error
47 - The drm_backlight_helper is dropped, copy in the code
48 - Support protocol version backwards compatibility for device
49
50 v3:
51 - Use donated Openmoko USB pid
52 - Use direct compression from framebuffer when pitch matches, not only on
53 full frames, so split updates can benefit
54 - Use __le16 in struct gud_drm_req_get_connector_status
55 - Set edid property when the device only provides edid
56 - Clear compression fields in struct gud_drm_req_set_buffer
57 - Fix protocol version negotiation
58 - Remove mode->vrefresh, it's calculated
59
60 v4:
61 - Drop the status req polling which was a workaround for something that
62 turned out to be a dwc2 udc driver problem
63 - Add a flag for the Linux gadget to require a status request on
64 SET operations. Other devices will only get status req on STALL errors
65 - Use protocol specific error codes (Peter)
66 - Add a flag for devices that want to receive the entire framebuffer on
67 each flush (Lubomir)
68 - Retry a failed framebuffer flush
69 - If mode has changed wait for worker and clear pending damage before
70 queuing up new damage, fb width/height might have changed
71 - Increase error counter on bulk transfer failures
72 - Use DRM_MODE_CONNECTOR_USB
73 - Handle R1 kmalloc error (Peter)
74 - Don't try and replicate the USB get descriptor request standard for the
75 display descriptor (Peter)
76 - Make max_buffer_size optional (Peter), drop the pow2 requirement since
77 it's not necessary anymore.
78 - Don't pre-alloc a control request buffer, it was only 4k
79 - Let gud.h describe the whole protocol explicitly and don't let DRM
80 leak into it (Peter)
81 - Drop display mode .hskew and .vscan from the protocol
82 - Shorten names: s/GUD_DRM_/GUD_/ s/gud_drm_/gud_/ (Peter)
83 - Fix gud_pipe_check() connector picking when switching connector
84 - Drop gud_drm_driver_gem_create_object() cached is default now
85 - Retrieve USB device from struct drm_device.dev instead of keeping a
86 pointer
87 - Honour fb->offsets[0]
88 - Fix mode fetching when connector status is forced
89 - Check EDID length reported by the device
90 - Use drm_do_get_edid() so userspace can overrride EDID
91 - Set epoch counter to signal connector status change
92 - gud_drm_driver can be const now
93
94 v5:
95 - GUD_DRM_FORMAT_R1: Use non-human ascii values (Daniel)
96 - Change name to: GUD USB Display (Thomas, Simon)
97 - Change one __u32 -> __le32 in protocol header
98 - Always log fb flush errors, unless the previous one failed
99 - Run backlight update in a worker to avoid upsetting lockdep (Daniel)
100 - Drop backlight_ops.get_brightness, there's no readback from the device
101 so it doesn't really add anything.
102 - Set dma mask, needed by dma-buf importers
103
104 v6:
105 - Use obj-y in Makefile (Peter)
106 - Fix missing le32_to_cpu() when using GUD_DISPLAY_MAGIC (Peter)
107 - Set initial brightness on backlight device
108
109 v7:
110 - LZ4_compress_default() can return zero, check for that
111 - Fix memory leak in gud_pipe_check() error path (Peter)
112 - Improve debug and error messages (Peter)
113 - Don't pass length in protocol structs (Peter)
114 - Pass USB interface to gud_usb_control_msg() et al. (Peter)
115 - Improve gud_connector_fill_properties() (Peter)
116 - Add GUD_PIXEL_FORMAT_RGB111 (Peter)
117 - Remove GUD_REQ_SET_VERSION (Peter)
118 - Fix DRM_IOCTL_MODE_OBJ_SETPROPERTY and the rotation property
119 - Fix dma-buf import (Thomas)
120
121 v8:
122 - Forgot to filter RGB111 from reaching userspace
123 - Handle a device that only returns unknown device properties (Peter)
124 - s/GUD_PIXEL_FORMAT_RGB111/GUD_PIXEL_FORMAT_XRGB1111/ (Peter)
125 - Fix R1 and XRGB1111 format conversion
126 - Add FIXME about Big Endian being broken (Peter, Ilia)
127
128 Cc: Lubomir Rintel <lkundrak@v3.sk>
129 Acked-by: Daniel Vetter <daniel.vetter@ffwll.ch>
130 Reviewed-by: Peter Stuge <peter@stuge.se>
131 Tested-by: Peter Stuge <peter@stuge.se>
132 Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
133 Link: https://patchwork.freedesktop.org/patch/msgid/20210313112545.37527-4-noralf@tronnes.org
134 [ backport changes:
135 - Remove include drm_gem_atomic_helper.h
136 - s/drm_gem_simple_display_pipe_prepare_fb/drm_gem_fb_simple_display_pipe_prepare_fb/
137 - Remove const from gud_drm_driver
138 - Change drm_gem_shmem_{vmap,vunmap} signatures
139 - Add gud_gem_create_object() to get cached memory mapping.
140 ]
141 Signed-off-by: Noralf Trønnes <noralf@tronnes.org>
142 ---
143 MAINTAINERS | 8 +
144 drivers/gpu/drm/Kconfig | 2 +
145 drivers/gpu/drm/Makefile | 1 +
146 drivers/gpu/drm/gud/Kconfig | 14 +
147 drivers/gpu/drm/gud/Makefile | 4 +
148 drivers/gpu/drm/gud/gud_connector.c | 729 ++++++++++++++++++++++++++++
149 drivers/gpu/drm/gud/gud_drv.c | 674 +++++++++++++++++++++++++
150 drivers/gpu/drm/gud/gud_internal.h | 154 ++++++
151 drivers/gpu/drm/gud/gud_pipe.c | 551 +++++++++++++++++++++
152 include/drm/gud.h | 333 +++++++++++++
153 10 files changed, 2470 insertions(+)
154 create mode 100644 drivers/gpu/drm/gud/Kconfig
155 create mode 100644 drivers/gpu/drm/gud/Makefile
156 create mode 100644 drivers/gpu/drm/gud/gud_connector.c
157 create mode 100644 drivers/gpu/drm/gud/gud_drv.c
158 create mode 100644 drivers/gpu/drm/gud/gud_internal.h
159 create mode 100644 drivers/gpu/drm/gud/gud_pipe.c
160 create mode 100644 include/drm/gud.h
161
162 --- a/MAINTAINERS
163 +++ b/MAINTAINERS
164 @@ -5526,6 +5526,14 @@ S: Maintained
165 F: Documentation/devicetree/bindings/display/panel/feiyang,fy07024di26a30d.yaml
166 F: drivers/gpu/drm/panel/panel-feiyang-fy07024di26a30d.c
167
168 +DRM DRIVER FOR GENERIC USB DISPLAY
169 +M: Noralf Trønnes <noralf@tronnes.org>
170 +S: Maintained
171 +W: https://github.com/notro/gud/wiki
172 +T: git git://anongit.freedesktop.org/drm/drm-misc
173 +F: drivers/gpu/drm/gud/
174 +F: include/drm/gud.h
175 +
176 DRM DRIVER FOR GRAIN MEDIA GM12U320 PROJECTORS
177 M: Hans de Goede <hdegoede@redhat.com>
178 S: Maintained
179 --- a/drivers/gpu/drm/Kconfig
180 +++ b/drivers/gpu/drm/Kconfig
181 @@ -392,6 +392,8 @@ source "drivers/gpu/drm/tidss/Kconfig"
182
183 source "drivers/gpu/drm/xlnx/Kconfig"
184
185 +source "drivers/gpu/drm/gud/Kconfig"
186 +
187 # Keep legacy drivers last
188
189 menuconfig DRM_LEGACY
190 --- a/drivers/gpu/drm/Makefile
191 +++ b/drivers/gpu/drm/Makefile
192 @@ -124,3 +124,4 @@ obj-$(CONFIG_DRM_ASPEED_GFX) += aspeed/
193 obj-$(CONFIG_DRM_MCDE) += mcde/
194 obj-$(CONFIG_DRM_TIDSS) += tidss/
195 obj-y += xlnx/
196 +obj-y += gud/
197 --- /dev/null
198 +++ b/drivers/gpu/drm/gud/Kconfig
199 @@ -0,0 +1,14 @@
200 +# SPDX-License-Identifier: GPL-2.0
201 +
202 +config DRM_GUD
203 + tristate "GUD USB Display"
204 + depends on DRM && USB
205 + select LZ4_COMPRESS
206 + select DRM_KMS_HELPER
207 + select DRM_GEM_SHMEM_HELPER
208 + select BACKLIGHT_CLASS_DEVICE
209 + help
210 + This is a DRM display driver for GUD USB Displays or display
211 + adapters.
212 +
213 + If M is selected the module will be called gud.
214 --- /dev/null
215 +++ b/drivers/gpu/drm/gud/Makefile
216 @@ -0,0 +1,4 @@
217 +# SPDX-License-Identifier: GPL-2.0
218 +
219 +gud-y := gud_drv.o gud_pipe.o gud_connector.o
220 +obj-$(CONFIG_DRM_GUD) += gud.o
221 --- /dev/null
222 +++ b/drivers/gpu/drm/gud/gud_connector.c
223 @@ -0,0 +1,729 @@
224 +// SPDX-License-Identifier: MIT
225 +/*
226 + * Copyright 2020 Noralf Trønnes
227 + */
228 +
229 +#include <linux/backlight.h>
230 +#include <linux/workqueue.h>
231 +
232 +#include <drm/drm_atomic.h>
233 +#include <drm/drm_atomic_state_helper.h>
234 +#include <drm/drm_connector.h>
235 +#include <drm/drm_drv.h>
236 +#include <drm/drm_encoder.h>
237 +#include <drm/drm_file.h>
238 +#include <drm/drm_modeset_helper_vtables.h>
239 +#include <drm/drm_print.h>
240 +#include <drm/drm_probe_helper.h>
241 +#include <drm/drm_simple_kms_helper.h>
242 +#include <drm/gud.h>
243 +
244 +#include "gud_internal.h"
245 +
246 +struct gud_connector {
247 + struct drm_connector connector;
248 + struct drm_encoder encoder;
249 + struct backlight_device *backlight;
250 + struct work_struct backlight_work;
251 +
252 + /* Supported properties */
253 + u16 *properties;
254 + unsigned int num_properties;
255 +
256 + /* Initial gadget tv state if applicable, applied on state reset */
257 + struct drm_tv_connector_state initial_tv_state;
258 +
259 + /*
260 + * Initial gadget backlight brightness if applicable, applied on state reset.
261 + * The value -ENODEV is used to signal no backlight.
262 + */
263 + int initial_brightness;
264 +};
265 +
266 +static inline struct gud_connector *to_gud_connector(struct drm_connector *connector)
267 +{
268 + return container_of(connector, struct gud_connector, connector);
269 +}
270 +
271 +static void gud_conn_err(struct drm_connector *connector, const char *msg, int ret)
272 +{
273 + dev_err(connector->dev->dev, "%s: %s (ret=%d)\n", connector->name, msg, ret);
274 +}
275 +
276 +/*
277 + * Use a worker to avoid taking kms locks inside the backlight lock.
278 + * Other display drivers use backlight within their kms locks.
279 + * This avoids inconsistent locking rules, which would upset lockdep.
280 + */
281 +static void gud_connector_backlight_update_status_work(struct work_struct *work)
282 +{
283 + struct gud_connector *gconn = container_of(work, struct gud_connector, backlight_work);
284 + struct drm_connector *connector = &gconn->connector;
285 + struct drm_connector_state *connector_state;
286 + struct drm_device *drm = connector->dev;
287 + struct drm_modeset_acquire_ctx ctx;
288 + struct drm_atomic_state *state;
289 + int idx, ret;
290 +
291 + if (!drm_dev_enter(drm, &idx))
292 + return;
293 +
294 + state = drm_atomic_state_alloc(drm);
295 + if (!state) {
296 + ret = -ENOMEM;
297 + goto exit;
298 + }
299 +
300 + drm_modeset_acquire_init(&ctx, 0);
301 + state->acquire_ctx = &ctx;
302 +retry:
303 + connector_state = drm_atomic_get_connector_state(state, connector);
304 + if (IS_ERR(connector_state)) {
305 + ret = PTR_ERR(connector_state);
306 + goto out;
307 + }
308 +
309 + /* Reuse tv.brightness to avoid having to subclass */
310 + connector_state->tv.brightness = gconn->backlight->props.brightness;
311 +
312 + ret = drm_atomic_commit(state);
313 +out:
314 + if (ret == -EDEADLK) {
315 + drm_atomic_state_clear(state);
316 + drm_modeset_backoff(&ctx);
317 + goto retry;
318 + }
319 +
320 + drm_atomic_state_put(state);
321 +
322 + drm_modeset_drop_locks(&ctx);
323 + drm_modeset_acquire_fini(&ctx);
324 +exit:
325 + drm_dev_exit(idx);
326 +
327 + if (ret)
328 + dev_err(drm->dev, "Failed to update backlight, err=%d\n", ret);
329 +}
330 +
331 +static int gud_connector_backlight_update_status(struct backlight_device *bd)
332 +{
333 + struct drm_connector *connector = bl_get_data(bd);
334 + struct gud_connector *gconn = to_gud_connector(connector);
335 +
336 + /* The USB timeout is 5 seconds so use system_long_wq for worst case scenario */
337 + queue_work(system_long_wq, &gconn->backlight_work);
338 +
339 + return 0;
340 +}
341 +
342 +static const struct backlight_ops gud_connector_backlight_ops = {
343 + .update_status = gud_connector_backlight_update_status,
344 +};
345 +
346 +static int gud_connector_backlight_register(struct gud_connector *gconn)
347 +{
348 + struct drm_connector *connector = &gconn->connector;
349 + struct backlight_device *bd;
350 + const char *name;
351 + const struct backlight_properties props = {
352 + .type = BACKLIGHT_RAW,
353 + .scale = BACKLIGHT_SCALE_NON_LINEAR,
354 + .max_brightness = 100,
355 + .brightness = gconn->initial_brightness,
356 + };
357 +
358 + name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
359 + connector->dev->primary->index, connector->name);
360 + if (!name)
361 + return -ENOMEM;
362 +
363 + bd = backlight_device_register(name, connector->kdev, connector,
364 + &gud_connector_backlight_ops, &props);
365 + kfree(name);
366 + if (IS_ERR(bd))
367 + return PTR_ERR(bd);
368 +
369 + gconn->backlight = bd;
370 +
371 + return 0;
372 +}
373 +
374 +static int gud_connector_detect(struct drm_connector *connector,
375 + struct drm_modeset_acquire_ctx *ctx, bool force)
376 +{
377 + struct gud_device *gdrm = to_gud_device(connector->dev);
378 + int idx, ret;
379 + u8 status;
380 +
381 + if (!drm_dev_enter(connector->dev, &idx))
382 + return connector_status_disconnected;
383 +
384 + if (force) {
385 + ret = gud_usb_set(gdrm, GUD_REQ_SET_CONNECTOR_FORCE_DETECT,
386 + connector->index, NULL, 0);
387 + if (ret) {
388 + ret = connector_status_unknown;
389 + goto exit;
390 + }
391 + }
392 +
393 + ret = gud_usb_get_u8(gdrm, GUD_REQ_GET_CONNECTOR_STATUS, connector->index, &status);
394 + if (ret) {
395 + ret = connector_status_unknown;
396 + goto exit;
397 + }
398 +
399 + switch (status & GUD_CONNECTOR_STATUS_CONNECTED_MASK) {
400 + case GUD_CONNECTOR_STATUS_DISCONNECTED:
401 + ret = connector_status_disconnected;
402 + break;
403 + case GUD_CONNECTOR_STATUS_CONNECTED:
404 + ret = connector_status_connected;
405 + break;
406 + default:
407 + ret = connector_status_unknown;
408 + break;
409 + };
410 +
411 + if (status & GUD_CONNECTOR_STATUS_CHANGED)
412 + connector->epoch_counter += 1;
413 +exit:
414 + drm_dev_exit(idx);
415 +
416 + return ret;
417 +}
418 +
419 +struct gud_connector_get_edid_ctx {
420 + void *buf;
421 + size_t len;
422 + bool edid_override;
423 +};
424 +
425 +static int gud_connector_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
426 +{
427 + struct gud_connector_get_edid_ctx *ctx = data;
428 + size_t start = block * EDID_LENGTH;
429 +
430 + ctx->edid_override = false;
431 +
432 + if (start + len > ctx->len)
433 + return -1;
434 +
435 + memcpy(buf, ctx->buf + start, len);
436 +
437 + return 0;
438 +}
439 +
440 +static int gud_connector_get_modes(struct drm_connector *connector)
441 +{
442 + struct gud_device *gdrm = to_gud_device(connector->dev);
443 + struct gud_display_mode_req *reqmodes = NULL;
444 + struct gud_connector_get_edid_ctx edid_ctx;
445 + unsigned int i, num_modes = 0;
446 + struct edid *edid = NULL;
447 + int idx, ret;
448 +
449 + if (!drm_dev_enter(connector->dev, &idx))
450 + return 0;
451 +
452 + edid_ctx.edid_override = true;
453 + edid_ctx.buf = kmalloc(GUD_CONNECTOR_MAX_EDID_LEN, GFP_KERNEL);
454 + if (!edid_ctx.buf)
455 + goto out;
456 +
457 + ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_EDID, connector->index,
458 + edid_ctx.buf, GUD_CONNECTOR_MAX_EDID_LEN);
459 + if (ret > 0 && ret % EDID_LENGTH) {
460 + gud_conn_err(connector, "Invalid EDID size", ret);
461 + } else if (ret > 0) {
462 + edid_ctx.len = ret;
463 + edid = drm_do_get_edid(connector, gud_connector_get_edid_block, &edid_ctx);
464 + }
465 +
466 + kfree(edid_ctx.buf);
467 + drm_connector_update_edid_property(connector, edid);
468 +
469 + if (edid && edid_ctx.edid_override)
470 + goto out;
471 +
472 + reqmodes = kmalloc_array(GUD_CONNECTOR_MAX_NUM_MODES, sizeof(*reqmodes), GFP_KERNEL);
473 + if (!reqmodes)
474 + goto out;
475 +
476 + ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_MODES, connector->index,
477 + reqmodes, GUD_CONNECTOR_MAX_NUM_MODES * sizeof(*reqmodes));
478 + if (ret <= 0)
479 + goto out;
480 + if (ret % sizeof(*reqmodes)) {
481 + gud_conn_err(connector, "Invalid display mode array size", ret);
482 + goto out;
483 + }
484 +
485 + num_modes = ret / sizeof(*reqmodes);
486 +
487 + for (i = 0; i < num_modes; i++) {
488 + struct drm_display_mode *mode;
489 +
490 + mode = drm_mode_create(connector->dev);
491 + if (!mode) {
492 + num_modes = i;
493 + goto out;
494 + }
495 +
496 + gud_to_display_mode(mode, &reqmodes[i]);
497 + drm_mode_probed_add(connector, mode);
498 + }
499 +out:
500 + if (!num_modes)
501 + num_modes = drm_add_edid_modes(connector, edid);
502 +
503 + kfree(reqmodes);
504 + kfree(edid);
505 + drm_dev_exit(idx);
506 +
507 + return num_modes;
508 +}
509 +
510 +static int gud_connector_atomic_check(struct drm_connector *connector,
511 + struct drm_atomic_state *state)
512 +{
513 + struct drm_connector_state *new_state;
514 + struct drm_crtc_state *new_crtc_state;
515 + struct drm_connector_state *old_state;
516 +
517 + new_state = drm_atomic_get_new_connector_state(state, connector);
518 + if (!new_state->crtc)
519 + return 0;
520 +
521 + old_state = drm_atomic_get_old_connector_state(state, connector);
522 + new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
523 +
524 + if (old_state->tv.margins.left != new_state->tv.margins.left ||
525 + old_state->tv.margins.right != new_state->tv.margins.right ||
526 + old_state->tv.margins.top != new_state->tv.margins.top ||
527 + old_state->tv.margins.bottom != new_state->tv.margins.bottom ||
528 + old_state->tv.mode != new_state->tv.mode ||
529 + old_state->tv.brightness != new_state->tv.brightness ||
530 + old_state->tv.contrast != new_state->tv.contrast ||
531 + old_state->tv.flicker_reduction != new_state->tv.flicker_reduction ||
532 + old_state->tv.overscan != new_state->tv.overscan ||
533 + old_state->tv.saturation != new_state->tv.saturation ||
534 + old_state->tv.hue != new_state->tv.hue)
535 + new_crtc_state->connectors_changed = true;
536 +
537 + return 0;
538 +}
539 +
540 +static const struct drm_connector_helper_funcs gud_connector_helper_funcs = {
541 + .detect_ctx = gud_connector_detect,
542 + .get_modes = gud_connector_get_modes,
543 + .atomic_check = gud_connector_atomic_check,
544 +};
545 +
546 +static int gud_connector_late_register(struct drm_connector *connector)
547 +{
548 + struct gud_connector *gconn = to_gud_connector(connector);
549 +
550 + if (gconn->initial_brightness < 0)
551 + return 0;
552 +
553 + return gud_connector_backlight_register(gconn);
554 +}
555 +
556 +static void gud_connector_early_unregister(struct drm_connector *connector)
557 +{
558 + struct gud_connector *gconn = to_gud_connector(connector);
559 +
560 + backlight_device_unregister(gconn->backlight);
561 + cancel_work_sync(&gconn->backlight_work);
562 +}
563 +
564 +static void gud_connector_destroy(struct drm_connector *connector)
565 +{
566 + struct gud_connector *gconn = to_gud_connector(connector);
567 +
568 + drm_connector_cleanup(connector);
569 + kfree(gconn->properties);
570 + kfree(gconn);
571 +}
572 +
573 +static void gud_connector_reset(struct drm_connector *connector)
574 +{
575 + struct gud_connector *gconn = to_gud_connector(connector);
576 +
577 + drm_atomic_helper_connector_reset(connector);
578 + connector->state->tv = gconn->initial_tv_state;
579 + /* Set margins from command line */
580 + drm_atomic_helper_connector_tv_reset(connector);
581 + if (gconn->initial_brightness >= 0)
582 + connector->state->tv.brightness = gconn->initial_brightness;
583 +}
584 +
585 +static const struct drm_connector_funcs gud_connector_funcs = {
586 + .fill_modes = drm_helper_probe_single_connector_modes,
587 + .late_register = gud_connector_late_register,
588 + .early_unregister = gud_connector_early_unregister,
589 + .destroy = gud_connector_destroy,
590 + .reset = gud_connector_reset,
591 + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
592 + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
593 +};
594 +
595 +/*
596 + * The tv.mode property is shared among the connectors and its enum names are
597 + * driver specific. This means that if more than one connector uses tv.mode,
598 + * the enum names has to be the same.
599 + */
600 +static int gud_connector_add_tv_mode(struct gud_device *gdrm, struct drm_connector *connector)
601 +{
602 + size_t buf_len = GUD_CONNECTOR_TV_MODE_MAX_NUM * GUD_CONNECTOR_TV_MODE_NAME_LEN;
603 + const char *modes[GUD_CONNECTOR_TV_MODE_MAX_NUM];
604 + unsigned int i, num_modes;
605 + char *buf;
606 + int ret;
607 +
608 + buf = kmalloc(buf_len, GFP_KERNEL);
609 + if (!buf)
610 + return -ENOMEM;
611 +
612 + ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_TV_MODE_VALUES,
613 + connector->index, buf, buf_len);
614 + if (ret < 0)
615 + goto free;
616 + if (!ret || ret % GUD_CONNECTOR_TV_MODE_NAME_LEN) {
617 + ret = -EIO;
618 + goto free;
619 + }
620 +
621 + num_modes = ret / GUD_CONNECTOR_TV_MODE_NAME_LEN;
622 + for (i = 0; i < num_modes; i++)
623 + modes[i] = &buf[i * GUD_CONNECTOR_TV_MODE_NAME_LEN];
624 +
625 + ret = drm_mode_create_tv_properties(connector->dev, num_modes, modes);
626 +free:
627 + kfree(buf);
628 + if (ret < 0)
629 + gud_conn_err(connector, "Failed to add TV modes", ret);
630 +
631 + return ret;
632 +}
633 +
634 +static struct drm_property *
635 +gud_connector_property_lookup(struct drm_connector *connector, u16 prop)
636 +{
637 + struct drm_mode_config *config = &connector->dev->mode_config;
638 +
639 + switch (prop) {
640 + case GUD_PROPERTY_TV_LEFT_MARGIN:
641 + return config->tv_left_margin_property;
642 + case GUD_PROPERTY_TV_RIGHT_MARGIN:
643 + return config->tv_right_margin_property;
644 + case GUD_PROPERTY_TV_TOP_MARGIN:
645 + return config->tv_top_margin_property;
646 + case GUD_PROPERTY_TV_BOTTOM_MARGIN:
647 + return config->tv_bottom_margin_property;
648 + case GUD_PROPERTY_TV_MODE:
649 + return config->tv_mode_property;
650 + case GUD_PROPERTY_TV_BRIGHTNESS:
651 + return config->tv_brightness_property;
652 + case GUD_PROPERTY_TV_CONTRAST:
653 + return config->tv_contrast_property;
654 + case GUD_PROPERTY_TV_FLICKER_REDUCTION:
655 + return config->tv_flicker_reduction_property;
656 + case GUD_PROPERTY_TV_OVERSCAN:
657 + return config->tv_overscan_property;
658 + case GUD_PROPERTY_TV_SATURATION:
659 + return config->tv_saturation_property;
660 + case GUD_PROPERTY_TV_HUE:
661 + return config->tv_hue_property;
662 + default:
663 + return ERR_PTR(-EINVAL);
664 + }
665 +}
666 +
667 +static unsigned int *gud_connector_tv_state_val(u16 prop, struct drm_tv_connector_state *state)
668 +{
669 + switch (prop) {
670 + case GUD_PROPERTY_TV_LEFT_MARGIN:
671 + return &state->margins.left;
672 + case GUD_PROPERTY_TV_RIGHT_MARGIN:
673 + return &state->margins.right;
674 + case GUD_PROPERTY_TV_TOP_MARGIN:
675 + return &state->margins.top;
676 + case GUD_PROPERTY_TV_BOTTOM_MARGIN:
677 + return &state->margins.bottom;
678 + case GUD_PROPERTY_TV_MODE:
679 + return &state->mode;
680 + case GUD_PROPERTY_TV_BRIGHTNESS:
681 + return &state->brightness;
682 + case GUD_PROPERTY_TV_CONTRAST:
683 + return &state->contrast;
684 + case GUD_PROPERTY_TV_FLICKER_REDUCTION:
685 + return &state->flicker_reduction;
686 + case GUD_PROPERTY_TV_OVERSCAN:
687 + return &state->overscan;
688 + case GUD_PROPERTY_TV_SATURATION:
689 + return &state->saturation;
690 + case GUD_PROPERTY_TV_HUE:
691 + return &state->hue;
692 + default:
693 + return ERR_PTR(-EINVAL);
694 + }
695 +}
696 +
697 +static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_connector *gconn)
698 +{
699 + struct drm_connector *connector = &gconn->connector;
700 + struct drm_device *drm = &gdrm->drm;
701 + struct gud_property_req *properties;
702 + unsigned int i, num_properties;
703 + int ret;
704 +
705 + properties = kcalloc(GUD_CONNECTOR_PROPERTIES_MAX_NUM, sizeof(*properties), GFP_KERNEL);
706 + if (!properties)
707 + return -ENOMEM;
708 +
709 + ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_PROPERTIES, connector->index,
710 + properties, GUD_CONNECTOR_PROPERTIES_MAX_NUM * sizeof(*properties));
711 + if (ret <= 0)
712 + goto out;
713 + if (ret % sizeof(*properties)) {
714 + ret = -EIO;
715 + goto out;
716 + }
717 +
718 + num_properties = ret / sizeof(*properties);
719 + ret = 0;
720 +
721 + gconn->properties = kcalloc(num_properties, sizeof(*gconn->properties), GFP_KERNEL);
722 + if (!gconn->properties) {
723 + ret = -ENOMEM;
724 + goto out;
725 + }
726 +
727 + for (i = 0; i < num_properties; i++) {
728 + u16 prop = le16_to_cpu(properties[i].prop);
729 + u64 val = le64_to_cpu(properties[i].val);
730 + struct drm_property *property;
731 + unsigned int *state_val;
732 +
733 + drm_dbg(drm, "property: %u = %llu(0x%llx)\n", prop, val, val);
734 +
735 + switch (prop) {
736 + case GUD_PROPERTY_TV_LEFT_MARGIN:
737 + fallthrough;
738 + case GUD_PROPERTY_TV_RIGHT_MARGIN:
739 + fallthrough;
740 + case GUD_PROPERTY_TV_TOP_MARGIN:
741 + fallthrough;
742 + case GUD_PROPERTY_TV_BOTTOM_MARGIN:
743 + ret = drm_mode_create_tv_margin_properties(drm);
744 + if (ret)
745 + goto out;
746 + break;
747 + case GUD_PROPERTY_TV_MODE:
748 + ret = gud_connector_add_tv_mode(gdrm, connector);
749 + if (ret)
750 + goto out;
751 + break;
752 + case GUD_PROPERTY_TV_BRIGHTNESS:
753 + fallthrough;
754 + case GUD_PROPERTY_TV_CONTRAST:
755 + fallthrough;
756 + case GUD_PROPERTY_TV_FLICKER_REDUCTION:
757 + fallthrough;
758 + case GUD_PROPERTY_TV_OVERSCAN:
759 + fallthrough;
760 + case GUD_PROPERTY_TV_SATURATION:
761 + fallthrough;
762 + case GUD_PROPERTY_TV_HUE:
763 + /* This is a no-op if already added. */
764 + ret = drm_mode_create_tv_properties(drm, 0, NULL);
765 + if (ret)
766 + goto out;
767 + break;
768 + case GUD_PROPERTY_BACKLIGHT_BRIGHTNESS:
769 + if (val > 100) {
770 + ret = -EINVAL;
771 + goto out;
772 + }
773 + gconn->initial_brightness = val;
774 + break;
775 + default:
776 + /* New ones might show up in future devices, skip those we don't know. */
777 + drm_dbg(drm, "Ignoring unknown property: %u\n", prop);
778 + continue;
779 + }
780 +
781 + gconn->properties[gconn->num_properties++] = prop;
782 +
783 + if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS)
784 + continue; /* not a DRM property */
785 +
786 + property = gud_connector_property_lookup(connector, prop);
787 + if (WARN_ON(IS_ERR(property)))
788 + continue;
789 +
790 + state_val = gud_connector_tv_state_val(prop, &gconn->initial_tv_state);
791 + if (WARN_ON(IS_ERR(state_val)))
792 + continue;
793 +
794 + *state_val = val;
795 + drm_object_attach_property(&connector->base, property, 0);
796 + }
797 +out:
798 + kfree(properties);
799 +
800 + return ret;
801 +}
802 +
803 +int gud_connector_fill_properties(struct drm_connector_state *connector_state,
804 + struct gud_property_req *properties)
805 +{
806 + struct gud_connector *gconn = to_gud_connector(connector_state->connector);
807 + unsigned int i;
808 +
809 + for (i = 0; i < gconn->num_properties; i++) {
810 + u16 prop = gconn->properties[i];
811 + u64 val;
812 +
813 + if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS) {
814 + val = connector_state->tv.brightness;
815 + } else {
816 + unsigned int *state_val;
817 +
818 + state_val = gud_connector_tv_state_val(prop, &connector_state->tv);
819 + if (WARN_ON_ONCE(IS_ERR(state_val)))
820 + return PTR_ERR(state_val);
821 +
822 + val = *state_val;
823 + }
824 +
825 + properties[i].prop = cpu_to_le16(prop);
826 + properties[i].val = cpu_to_le64(val);
827 + }
828 +
829 + return gconn->num_properties;
830 +}
831 +
832 +static int gud_connector_create(struct gud_device *gdrm, unsigned int index,
833 + struct gud_connector_descriptor_req *desc)
834 +{
835 + struct drm_device *drm = &gdrm->drm;
836 + struct gud_connector *gconn;
837 + struct drm_connector *connector;
838 + struct drm_encoder *encoder;
839 + int ret, connector_type;
840 + u32 flags;
841 +
842 + gconn = kzalloc(sizeof(*gconn), GFP_KERNEL);
843 + if (!gconn)
844 + return -ENOMEM;
845 +
846 + INIT_WORK(&gconn->backlight_work, gud_connector_backlight_update_status_work);
847 + gconn->initial_brightness = -ENODEV;
848 + flags = le32_to_cpu(desc->flags);
849 + connector = &gconn->connector;
850 +
851 + drm_dbg(drm, "Connector: index=%u type=%u flags=0x%x\n", index, desc->connector_type, flags);
852 +
853 + switch (desc->connector_type) {
854 + case GUD_CONNECTOR_TYPE_PANEL:
855 + connector_type = DRM_MODE_CONNECTOR_USB;
856 + break;
857 + case GUD_CONNECTOR_TYPE_VGA:
858 + connector_type = DRM_MODE_CONNECTOR_VGA;
859 + break;
860 + case GUD_CONNECTOR_TYPE_DVI:
861 + connector_type = DRM_MODE_CONNECTOR_DVID;
862 + break;
863 + case GUD_CONNECTOR_TYPE_COMPOSITE:
864 + connector_type = DRM_MODE_CONNECTOR_Composite;
865 + break;
866 + case GUD_CONNECTOR_TYPE_SVIDEO:
867 + connector_type = DRM_MODE_CONNECTOR_SVIDEO;
868 + break;
869 + case GUD_CONNECTOR_TYPE_COMPONENT:
870 + connector_type = DRM_MODE_CONNECTOR_Component;
871 + break;
872 + case GUD_CONNECTOR_TYPE_DISPLAYPORT:
873 + connector_type = DRM_MODE_CONNECTOR_DisplayPort;
874 + break;
875 + case GUD_CONNECTOR_TYPE_HDMI:
876 + connector_type = DRM_MODE_CONNECTOR_HDMIA;
877 + break;
878 + default: /* future types */
879 + connector_type = DRM_MODE_CONNECTOR_USB;
880 + break;
881 + };
882 +
883 + drm_connector_helper_add(connector, &gud_connector_helper_funcs);
884 + ret = drm_connector_init(drm, connector, &gud_connector_funcs, connector_type);
885 + if (ret) {
886 + kfree(connector);
887 + return ret;
888 + }
889 +
890 + if (WARN_ON(connector->index != index))
891 + return -EINVAL;
892 +
893 + if (flags & GUD_CONNECTOR_FLAGS_POLL_STATUS)
894 + connector->polled = (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT);
895 + if (flags & GUD_CONNECTOR_FLAGS_INTERLACE)
896 + connector->interlace_allowed = true;
897 + if (flags & GUD_CONNECTOR_FLAGS_DOUBLESCAN)
898 + connector->doublescan_allowed = true;
899 +
900 + ret = gud_connector_add_properties(gdrm, gconn);
901 + if (ret) {
902 + gud_conn_err(connector, "Failed to add properties", ret);
903 + return ret;
904 + }
905 +
906 + /* The first connector is attached to the existing simple pipe encoder */
907 + if (!connector->index) {
908 + encoder = &gdrm->pipe.encoder;
909 + } else {
910 + encoder = &gconn->encoder;
911 +
912 + ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
913 + if (ret)
914 + return ret;
915 +
916 + encoder->possible_crtcs = 1;
917 + }
918 +
919 + return drm_connector_attach_encoder(connector, encoder);
920 +}
921 +
922 +int gud_get_connectors(struct gud_device *gdrm)
923 +{
924 + struct gud_connector_descriptor_req *descs;
925 + unsigned int i, num_connectors;
926 + int ret;
927 +
928 + descs = kmalloc_array(GUD_CONNECTORS_MAX_NUM, sizeof(*descs), GFP_KERNEL);
929 + if (!descs)
930 + return -ENOMEM;
931 +
932 + ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTORS, 0,
933 + descs, GUD_CONNECTORS_MAX_NUM * sizeof(descs));
934 + if (ret < 0)
935 + goto free;
936 + if (!ret || ret % sizeof(*descs)) {
937 + ret = -EIO;
938 + goto free;
939 + }
940 +
941 + num_connectors = ret / sizeof(*descs);
942 +
943 + for (i = 0; i < num_connectors; i++) {
944 + ret = gud_connector_create(gdrm, i, &descs[i]);
945 + if (ret)
946 + goto free;
947 + }
948 +free:
949 + kfree(descs);
950 +
951 + return ret;
952 +}
953 --- /dev/null
954 +++ b/drivers/gpu/drm/gud/gud_drv.c
955 @@ -0,0 +1,674 @@
956 +// SPDX-License-Identifier: MIT
957 +/*
958 + * Copyright 2020 Noralf Trønnes
959 + */
960 +
961 +#include <linux/dma-buf.h>
962 +#include <linux/dma-mapping.h>
963 +#include <linux/lz4.h>
964 +#include <linux/module.h>
965 +#include <linux/platform_device.h>
966 +#include <linux/string_helpers.h>
967 +#include <linux/usb.h>
968 +#include <linux/vmalloc.h>
969 +#include <linux/workqueue.h>
970 +
971 +#include <drm/drm_atomic_helper.h>
972 +#include <drm/drm_damage_helper.h>
973 +#include <drm/drm_debugfs.h>
974 +#include <drm/drm_drv.h>
975 +#include <drm/drm_fb_helper.h>
976 +#include <drm/drm_fourcc.h>
977 +#include <drm/drm_gem_framebuffer_helper.h>
978 +#include <drm/drm_gem_shmem_helper.h>
979 +#include <drm/drm_managed.h>
980 +#include <drm/drm_print.h>
981 +#include <drm/drm_probe_helper.h>
982 +#include <drm/drm_simple_kms_helper.h>
983 +#include <drm/gud.h>
984 +
985 +#include "gud_internal.h"
986 +
987 +/* Only used internally */
988 +static const struct drm_format_info gud_drm_format_r1 = {
989 + .format = GUD_DRM_FORMAT_R1,
990 + .num_planes = 1,
991 + .char_per_block = { 1, 0, 0 },
992 + .block_w = { 8, 0, 0 },
993 + .block_h = { 1, 0, 0 },
994 + .hsub = 1,
995 + .vsub = 1,
996 +};
997 +
998 +static const struct drm_format_info gud_drm_format_xrgb1111 = {
999 + .format = GUD_DRM_FORMAT_XRGB1111,
1000 + .num_planes = 1,
1001 + .char_per_block = { 1, 0, 0 },
1002 + .block_w = { 2, 0, 0 },
1003 + .block_h = { 1, 0, 0 },
1004 + .hsub = 1,
1005 + .vsub = 1,
1006 +};
1007 +
1008 +static int gud_usb_control_msg(struct usb_interface *intf, bool in,
1009 + u8 request, u16 value, void *buf, size_t len)
1010 +{
1011 + u8 requesttype = USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
1012 + u8 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
1013 + struct usb_device *usb = interface_to_usbdev(intf);
1014 + unsigned int pipe;
1015 +
1016 + if (len && !buf)
1017 + return -EINVAL;
1018 +
1019 + if (in) {
1020 + pipe = usb_rcvctrlpipe(usb, 0);
1021 + requesttype |= USB_DIR_IN;
1022 + } else {
1023 + pipe = usb_sndctrlpipe(usb, 0);
1024 + requesttype |= USB_DIR_OUT;
1025 + }
1026 +
1027 + return usb_control_msg(usb, pipe, request, requesttype, value,
1028 + ifnum, buf, len, USB_CTRL_GET_TIMEOUT);
1029 +}
1030 +
1031 +static int gud_get_display_descriptor(struct usb_interface *intf,
1032 + struct gud_display_descriptor_req *desc)
1033 +{
1034 + void *buf;
1035 + int ret;
1036 +
1037 + buf = kmalloc(sizeof(*desc), GFP_KERNEL);
1038 + if (!buf)
1039 + return -ENOMEM;
1040 +
1041 + ret = gud_usb_control_msg(intf, true, GUD_REQ_GET_DESCRIPTOR, 0, buf, sizeof(*desc));
1042 + memcpy(desc, buf, sizeof(*desc));
1043 + kfree(buf);
1044 + if (ret < 0)
1045 + return ret;
1046 + if (ret != sizeof(*desc))
1047 + return -EIO;
1048 +
1049 + if (desc->magic != le32_to_cpu(GUD_DISPLAY_MAGIC))
1050 + return -ENODATA;
1051 +
1052 + DRM_DEV_DEBUG_DRIVER(&intf->dev,
1053 + "version=%u flags=0x%x compression=0x%x max_buffer_size=%u\n",
1054 + desc->version, le32_to_cpu(desc->flags), desc->compression,
1055 + le32_to_cpu(desc->max_buffer_size));
1056 +
1057 + if (!desc->version || !desc->max_width || !desc->max_height ||
1058 + le32_to_cpu(desc->min_width) > le32_to_cpu(desc->max_width) ||
1059 + le32_to_cpu(desc->min_height) > le32_to_cpu(desc->max_height))
1060 + return -EINVAL;
1061 +
1062 + return 0;
1063 +}
1064 +
1065 +static int gud_status_to_errno(u8 status)
1066 +{
1067 + switch (status) {
1068 + case GUD_STATUS_OK:
1069 + return 0;
1070 + case GUD_STATUS_BUSY:
1071 + return -EBUSY;
1072 + case GUD_STATUS_REQUEST_NOT_SUPPORTED:
1073 + return -EOPNOTSUPP;
1074 + case GUD_STATUS_PROTOCOL_ERROR:
1075 + return -EPROTO;
1076 + case GUD_STATUS_INVALID_PARAMETER:
1077 + return -EINVAL;
1078 + case GUD_STATUS_ERROR:
1079 + return -EREMOTEIO;
1080 + default:
1081 + return -EREMOTEIO;
1082 + }
1083 +}
1084 +
1085 +static int gud_usb_get_status(struct usb_interface *intf)
1086 +{
1087 + int ret, status = -EIO;
1088 + u8 *buf;
1089 +
1090 + buf = kmalloc(sizeof(*buf), GFP_KERNEL);
1091 + if (!buf)
1092 + return -ENOMEM;
1093 +
1094 + ret = gud_usb_control_msg(intf, true, GUD_REQ_GET_STATUS, 0, buf, sizeof(*buf));
1095 + if (ret == sizeof(*buf))
1096 + status = gud_status_to_errno(*buf);
1097 + kfree(buf);
1098 +
1099 + if (ret < 0)
1100 + return ret;
1101 +
1102 + return status;
1103 +}
1104 +
1105 +static int gud_usb_transfer(struct gud_device *gdrm, bool in, u8 request, u16 index,
1106 + void *buf, size_t len)
1107 +{
1108 + struct usb_interface *intf = to_usb_interface(gdrm->drm.dev);
1109 + int idx, ret;
1110 +
1111 + drm_dbg(&gdrm->drm, "%s: request=0x%x index=%u len=%zu\n",
1112 + in ? "get" : "set", request, index, len);
1113 +
1114 + if (!drm_dev_enter(&gdrm->drm, &idx))
1115 + return -ENODEV;
1116 +
1117 + mutex_lock(&gdrm->ctrl_lock);
1118 +
1119 + ret = gud_usb_control_msg(intf, in, request, index, buf, len);
1120 + if (ret == -EPIPE || ((gdrm->flags & GUD_DISPLAY_FLAG_STATUS_ON_SET) && !in && ret >= 0)) {
1121 + int status;
1122 +
1123 + status = gud_usb_get_status(intf);
1124 + if (status < 0) {
1125 + ret = status;
1126 + } else if (ret < 0) {
1127 + dev_err_once(gdrm->drm.dev,
1128 + "Unexpected status OK for failed transfer\n");
1129 + ret = -EPIPE;
1130 + }
1131 + }
1132 +
1133 + if (ret < 0) {
1134 + drm_dbg(&gdrm->drm, "ret=%d\n", ret);
1135 + gdrm->stats_num_errors++;
1136 + }
1137 +
1138 + mutex_unlock(&gdrm->ctrl_lock);
1139 + drm_dev_exit(idx);
1140 +
1141 + return ret;
1142 +}
1143 +
1144 +/*
1145 + * @buf cannot be allocated on the stack.
1146 + * Returns number of bytes received or negative error code on failure.
1147 + */
1148 +int gud_usb_get(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t max_len)
1149 +{
1150 + return gud_usb_transfer(gdrm, true, request, index, buf, max_len);
1151 +}
1152 +
1153 +/*
1154 + * @buf can be allocated on the stack or NULL.
1155 + * Returns zero on success or negative error code on failure.
1156 + */
1157 +int gud_usb_set(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t len)
1158 +{
1159 + void *trbuf = NULL;
1160 + int ret;
1161 +
1162 + if (buf && len) {
1163 + trbuf = kmemdup(buf, len, GFP_KERNEL);
1164 + if (!trbuf)
1165 + return -ENOMEM;
1166 + }
1167 +
1168 + ret = gud_usb_transfer(gdrm, false, request, index, trbuf, len);
1169 + kfree(trbuf);
1170 + if (ret < 0)
1171 + return ret;
1172 +
1173 + return ret != len ? -EIO : 0;
1174 +}
1175 +
1176 +/*
1177 + * @val can be allocated on the stack.
1178 + * Returns zero on success or negative error code on failure.
1179 + */
1180 +int gud_usb_get_u8(struct gud_device *gdrm, u8 request, u16 index, u8 *val)
1181 +{
1182 + u8 *buf;
1183 + int ret;
1184 +
1185 + buf = kmalloc(sizeof(*val), GFP_KERNEL);
1186 + if (!buf)
1187 + return -ENOMEM;
1188 +
1189 + ret = gud_usb_get(gdrm, request, index, buf, sizeof(*val));
1190 + *val = *buf;
1191 + kfree(buf);
1192 + if (ret < 0)
1193 + return ret;
1194 +
1195 + return ret != sizeof(*val) ? -EIO : 0;
1196 +}
1197 +
1198 +/* Returns zero on success or negative error code on failure. */
1199 +int gud_usb_set_u8(struct gud_device *gdrm, u8 request, u8 val)
1200 +{
1201 + return gud_usb_set(gdrm, request, 0, &val, sizeof(val));
1202 +}
1203 +
1204 +static int gud_get_properties(struct gud_device *gdrm)
1205 +{
1206 + struct gud_property_req *properties;
1207 + unsigned int i, num_properties;
1208 + int ret;
1209 +
1210 + properties = kcalloc(GUD_PROPERTIES_MAX_NUM, sizeof(*properties), GFP_KERNEL);
1211 + if (!properties)
1212 + return -ENOMEM;
1213 +
1214 + ret = gud_usb_get(gdrm, GUD_REQ_GET_PROPERTIES, 0,
1215 + properties, GUD_PROPERTIES_MAX_NUM * sizeof(*properties));
1216 + if (ret <= 0)
1217 + goto out;
1218 + if (ret % sizeof(*properties)) {
1219 + ret = -EIO;
1220 + goto out;
1221 + }
1222 +
1223 + num_properties = ret / sizeof(*properties);
1224 + ret = 0;
1225 +
1226 + gdrm->properties = drmm_kcalloc(&gdrm->drm, num_properties, sizeof(*gdrm->properties),
1227 + GFP_KERNEL);
1228 + if (!gdrm->properties) {
1229 + ret = -ENOMEM;
1230 + goto out;
1231 + }
1232 +
1233 + for (i = 0; i < num_properties; i++) {
1234 + u16 prop = le16_to_cpu(properties[i].prop);
1235 + u64 val = le64_to_cpu(properties[i].val);
1236 +
1237 + switch (prop) {
1238 + case GUD_PROPERTY_ROTATION:
1239 + /*
1240 + * DRM UAPI matches the protocol so use the value directly,
1241 + * but mask out any additions on future devices.
1242 + */
1243 + val &= GUD_ROTATION_MASK;
1244 + ret = drm_plane_create_rotation_property(&gdrm->pipe.plane,
1245 + DRM_MODE_ROTATE_0, val);
1246 + break;
1247 + default:
1248 + /* New ones might show up in future devices, skip those we don't know. */
1249 + drm_dbg(&gdrm->drm, "Ignoring unknown property: %u\n", prop);
1250 + continue;
1251 + }
1252 +
1253 + if (ret)
1254 + goto out;
1255 +
1256 + gdrm->properties[gdrm->num_properties++] = prop;
1257 + }
1258 +out:
1259 + kfree(properties);
1260 +
1261 + return ret;
1262 +}
1263 +
1264 +static struct drm_gem_object *gud_gem_create_object(struct drm_device *dev, size_t size)
1265 +{
1266 + struct drm_gem_shmem_object *shmem;
1267 +
1268 + shmem = kzalloc(sizeof(*shmem), GFP_KERNEL);
1269 + if (!shmem)
1270 + return NULL;
1271 +
1272 + shmem->map_cached = true;
1273 +
1274 + return &shmem->base;
1275 +}
1276 +
1277 +/*
1278 + * FIXME: Dma-buf sharing requires DMA support by the importing device.
1279 + * This function is a workaround to make USB devices work as well.
1280 + * See todo.rst for how to fix the issue in the dma-buf framework.
1281 + */
1282 +static struct drm_gem_object *gud_gem_prime_import(struct drm_device *drm, struct dma_buf *dma_buf)
1283 +{
1284 + struct gud_device *gdrm = to_gud_device(drm);
1285 +
1286 + if (!gdrm->dmadev)
1287 + return ERR_PTR(-ENODEV);
1288 +
1289 + return drm_gem_prime_import_dev(drm, dma_buf, gdrm->dmadev);
1290 +}
1291 +
1292 +static int gud_stats_debugfs(struct seq_file *m, void *data)
1293 +{
1294 + struct drm_info_node *node = m->private;
1295 + struct gud_device *gdrm = to_gud_device(node->minor->dev);
1296 + char buf[10];
1297 +
1298 + string_get_size(gdrm->bulk_len, 1, STRING_UNITS_2, buf, sizeof(buf));
1299 + seq_printf(m, "Max buffer size: %s\n", buf);
1300 + seq_printf(m, "Number of errors: %u\n", gdrm->stats_num_errors);
1301 +
1302 + seq_puts(m, "Compression: ");
1303 + if (gdrm->compression & GUD_COMPRESSION_LZ4)
1304 + seq_puts(m, " lz4");
1305 + if (!gdrm->compression)
1306 + seq_puts(m, " none");
1307 + seq_puts(m, "\n");
1308 +
1309 + if (gdrm->compression) {
1310 + u64 remainder;
1311 + u64 ratio = div64_u64_rem(gdrm->stats_length, gdrm->stats_actual_length,
1312 + &remainder);
1313 + u64 ratio_frac = div64_u64(remainder * 10, gdrm->stats_actual_length);
1314 +
1315 + seq_printf(m, "Compression ratio: %llu.%llu\n", ratio, ratio_frac);
1316 + }
1317 +
1318 + return 0;
1319 +}
1320 +
1321 +static const struct drm_info_list gud_debugfs_list[] = {
1322 + { "stats", gud_stats_debugfs, 0, NULL },
1323 +};
1324 +
1325 +static void gud_debugfs_init(struct drm_minor *minor)
1326 +{
1327 + drm_debugfs_create_files(gud_debugfs_list, ARRAY_SIZE(gud_debugfs_list),
1328 + minor->debugfs_root, minor);
1329 +}
1330 +
1331 +static const struct drm_simple_display_pipe_funcs gud_pipe_funcs = {
1332 + .check = gud_pipe_check,
1333 + .update = gud_pipe_update,
1334 + .prepare_fb = drm_gem_fb_simple_display_pipe_prepare_fb,
1335 +};
1336 +
1337 +static const struct drm_mode_config_funcs gud_mode_config_funcs = {
1338 + .fb_create = drm_gem_fb_create_with_dirty,
1339 + .atomic_check = drm_atomic_helper_check,
1340 + .atomic_commit = drm_atomic_helper_commit,
1341 +};
1342 +
1343 +static const u64 gud_pipe_modifiers[] = {
1344 + DRM_FORMAT_MOD_LINEAR,
1345 + DRM_FORMAT_MOD_INVALID
1346 +};
1347 +
1348 +DEFINE_DRM_GEM_FOPS(gud_fops);
1349 +
1350 +static struct drm_driver gud_drm_driver = {
1351 + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
1352 + .fops = &gud_fops,
1353 + DRM_GEM_SHMEM_DRIVER_OPS,
1354 + .gem_create_object = gud_gem_create_object,
1355 + .gem_prime_import = gud_gem_prime_import,
1356 + .debugfs_init = gud_debugfs_init,
1357 +
1358 + .name = "gud",
1359 + .desc = "Generic USB Display",
1360 + .date = "20200422",
1361 + .major = 1,
1362 + .minor = 0,
1363 +};
1364 +
1365 +static void gud_free_buffers_and_mutex(struct drm_device *drm, void *unused)
1366 +{
1367 + struct gud_device *gdrm = to_gud_device(drm);
1368 +
1369 + vfree(gdrm->compress_buf);
1370 + kfree(gdrm->bulk_buf);
1371 + mutex_destroy(&gdrm->ctrl_lock);
1372 + mutex_destroy(&gdrm->damage_lock);
1373 +}
1374 +
1375 +static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
1376 +{
1377 + const struct drm_format_info *xrgb8888_emulation_format = NULL;
1378 + bool rgb565_supported = false, xrgb8888_supported = false;
1379 + unsigned int num_formats_dev, num_formats = 0;
1380 + struct usb_endpoint_descriptor *bulk_out;
1381 + struct gud_display_descriptor_req desc;
1382 + struct device *dev = &intf->dev;
1383 + size_t max_buffer_size = 0;
1384 + struct gud_device *gdrm;
1385 + struct drm_device *drm;
1386 + u8 *formats_dev;
1387 + u32 *formats;
1388 + int ret, i;
1389 +
1390 + ret = usb_find_bulk_out_endpoint(intf->cur_altsetting, &bulk_out);
1391 + if (ret)
1392 + return ret;
1393 +
1394 + ret = gud_get_display_descriptor(intf, &desc);
1395 + if (ret) {
1396 + DRM_DEV_DEBUG_DRIVER(dev, "Not a display interface: ret=%d\n", ret);
1397 + return -ENODEV;
1398 + }
1399 +
1400 + if (desc.version > 1) {
1401 + dev_err(dev, "Protocol version %u is not supported\n", desc.version);
1402 + return -ENODEV;
1403 + }
1404 +
1405 + gdrm = devm_drm_dev_alloc(dev, &gud_drm_driver, struct gud_device, drm);
1406 + if (IS_ERR(gdrm))
1407 + return PTR_ERR(gdrm);
1408 +
1409 + drm = &gdrm->drm;
1410 + drm->mode_config.funcs = &gud_mode_config_funcs;
1411 + ret = drmm_mode_config_init(drm);
1412 + if (ret)
1413 + return ret;
1414 +
1415 + gdrm->flags = le32_to_cpu(desc.flags);
1416 + gdrm->compression = desc.compression & GUD_COMPRESSION_LZ4;
1417 +
1418 + if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE && gdrm->compression)
1419 + return -EINVAL;
1420 +
1421 + mutex_init(&gdrm->ctrl_lock);
1422 + mutex_init(&gdrm->damage_lock);
1423 + INIT_WORK(&gdrm->work, gud_flush_work);
1424 + gud_clear_damage(gdrm);
1425 +
1426 + ret = drmm_add_action_or_reset(drm, gud_free_buffers_and_mutex, NULL);
1427 + if (ret)
1428 + return ret;
1429 +
1430 + drm->mode_config.min_width = le32_to_cpu(desc.min_width);
1431 + drm->mode_config.max_width = le32_to_cpu(desc.max_width);
1432 + drm->mode_config.min_height = le32_to_cpu(desc.min_height);
1433 + drm->mode_config.max_height = le32_to_cpu(desc.max_height);
1434 +
1435 + formats_dev = devm_kmalloc(dev, GUD_FORMATS_MAX_NUM, GFP_KERNEL);
1436 + /* Add room for emulated XRGB8888 */
1437 + formats = devm_kmalloc_array(dev, GUD_FORMATS_MAX_NUM + 1, sizeof(*formats), GFP_KERNEL);
1438 + if (!formats_dev || !formats)
1439 + return -ENOMEM;
1440 +
1441 + ret = gud_usb_get(gdrm, GUD_REQ_GET_FORMATS, 0, formats_dev, GUD_FORMATS_MAX_NUM);
1442 + if (ret < 0)
1443 + return ret;
1444 +
1445 + num_formats_dev = ret;
1446 + for (i = 0; i < num_formats_dev; i++) {
1447 + const struct drm_format_info *info;
1448 + size_t fmt_buf_size;
1449 + u32 format;
1450 +
1451 + format = gud_to_fourcc(formats_dev[i]);
1452 + if (!format) {
1453 + drm_dbg(drm, "Unsupported format: 0x%02x\n", formats_dev[i]);
1454 + continue;
1455 + }
1456 +
1457 + if (format == GUD_DRM_FORMAT_R1)
1458 + info = &gud_drm_format_r1;
1459 + else if (format == GUD_DRM_FORMAT_XRGB1111)
1460 + info = &gud_drm_format_xrgb1111;
1461 + else
1462 + info = drm_format_info(format);
1463 +
1464 + switch (format) {
1465 + case GUD_DRM_FORMAT_R1:
1466 + fallthrough;
1467 + case GUD_DRM_FORMAT_XRGB1111:
1468 + if (!xrgb8888_emulation_format)
1469 + xrgb8888_emulation_format = info;
1470 + break;
1471 + case DRM_FORMAT_RGB565:
1472 + rgb565_supported = true;
1473 + if (!xrgb8888_emulation_format)
1474 + xrgb8888_emulation_format = info;
1475 + break;
1476 + case DRM_FORMAT_XRGB8888:
1477 + xrgb8888_supported = true;
1478 + break;
1479 + };
1480 +
1481 + fmt_buf_size = drm_format_info_min_pitch(info, 0, drm->mode_config.max_width) *
1482 + drm->mode_config.max_height;
1483 + max_buffer_size = max(max_buffer_size, fmt_buf_size);
1484 +
1485 + if (format == GUD_DRM_FORMAT_R1 || format == GUD_DRM_FORMAT_XRGB1111)
1486 + continue; /* Internal not for userspace */
1487 +
1488 + formats[num_formats++] = format;
1489 + }
1490 +
1491 + if (!num_formats && !xrgb8888_emulation_format) {
1492 + dev_err(dev, "No supported pixel formats found\n");
1493 + return -EINVAL;
1494 + }
1495 +
1496 + /* Prefer speed over color depth */
1497 + if (rgb565_supported)
1498 + drm->mode_config.preferred_depth = 16;
1499 +
1500 + if (!xrgb8888_supported && xrgb8888_emulation_format) {
1501 + gdrm->xrgb8888_emulation_format = xrgb8888_emulation_format;
1502 + formats[num_formats++] = DRM_FORMAT_XRGB8888;
1503 + }
1504 +
1505 + if (desc.max_buffer_size)
1506 + max_buffer_size = le32_to_cpu(desc.max_buffer_size);
1507 +retry:
1508 + /*
1509 + * Use plain kmalloc here since devm_kmalloc() places struct devres at the beginning
1510 + * of the buffer it allocates. This wastes a lot of memory when allocating big buffers.
1511 + * Asking for 2M would actually allocate 4M. This would also prevent getting the biggest
1512 + * possible buffer potentially leading to split transfers.
1513 + */
1514 + gdrm->bulk_buf = kmalloc(max_buffer_size, GFP_KERNEL | __GFP_NOWARN);
1515 + if (!gdrm->bulk_buf) {
1516 + max_buffer_size = roundup_pow_of_two(max_buffer_size) / 2;
1517 + if (max_buffer_size < SZ_512K)
1518 + return -ENOMEM;
1519 + goto retry;
1520 + }
1521 +
1522 + gdrm->bulk_pipe = usb_sndbulkpipe(interface_to_usbdev(intf), usb_endpoint_num(bulk_out));
1523 + gdrm->bulk_len = max_buffer_size;
1524 +
1525 + if (gdrm->compression & GUD_COMPRESSION_LZ4) {
1526 + gdrm->lz4_comp_mem = devm_kmalloc(dev, LZ4_MEM_COMPRESS, GFP_KERNEL);
1527 + if (!gdrm->lz4_comp_mem)
1528 + return -ENOMEM;
1529 +
1530 + gdrm->compress_buf = vmalloc(gdrm->bulk_len);
1531 + if (!gdrm->compress_buf)
1532 + return -ENOMEM;
1533 + }
1534 +
1535 + ret = drm_simple_display_pipe_init(drm, &gdrm->pipe, &gud_pipe_funcs,
1536 + formats, num_formats,
1537 + gud_pipe_modifiers, NULL);
1538 + if (ret)
1539 + return ret;
1540 +
1541 + devm_kfree(dev, formats);
1542 + devm_kfree(dev, formats_dev);
1543 +
1544 + ret = gud_get_properties(gdrm);
1545 + if (ret) {
1546 + dev_err(dev, "Failed to get properties (error=%d)\n", ret);
1547 + return ret;
1548 + }
1549 +
1550 + drm_plane_enable_fb_damage_clips(&gdrm->pipe.plane);
1551 +
1552 + ret = gud_get_connectors(gdrm);
1553 + if (ret) {
1554 + dev_err(dev, "Failed to get connectors (error=%d)\n", ret);
1555 + return ret;
1556 + }
1557 +
1558 + drm_mode_config_reset(drm);
1559 +
1560 + usb_set_intfdata(intf, gdrm);
1561 +
1562 + gdrm->dmadev = usb_intf_get_dma_device(intf);
1563 + if (!gdrm->dmadev)
1564 + dev_warn(dev, "buffer sharing not supported");
1565 +
1566 + ret = drm_dev_register(drm, 0);
1567 + if (ret) {
1568 + put_device(gdrm->dmadev);
1569 + return ret;
1570 + }
1571 +
1572 + drm_kms_helper_poll_init(drm);
1573 +
1574 + drm_fbdev_generic_setup(drm, 0);
1575 +
1576 + return 0;
1577 +}
1578 +
1579 +static void gud_disconnect(struct usb_interface *interface)
1580 +{
1581 + struct gud_device *gdrm = usb_get_intfdata(interface);
1582 + struct drm_device *drm = &gdrm->drm;
1583 +
1584 + drm_dbg(drm, "%s:\n", __func__);
1585 +
1586 + drm_kms_helper_poll_fini(drm);
1587 + drm_dev_unplug(drm);
1588 + drm_atomic_helper_shutdown(drm);
1589 + put_device(gdrm->dmadev);
1590 + gdrm->dmadev = NULL;
1591 +}
1592 +
1593 +static int gud_suspend(struct usb_interface *intf, pm_message_t message)
1594 +{
1595 + struct gud_device *gdrm = usb_get_intfdata(intf);
1596 +
1597 + return drm_mode_config_helper_suspend(&gdrm->drm);
1598 +}
1599 +
1600 +static int gud_resume(struct usb_interface *intf)
1601 +{
1602 + struct gud_device *gdrm = usb_get_intfdata(intf);
1603 +
1604 + drm_mode_config_helper_resume(&gdrm->drm);
1605 +
1606 + return 0;
1607 +}
1608 +
1609 +static const struct usb_device_id gud_id_table[] = {
1610 + { USB_DEVICE_INTERFACE_CLASS(0x1d50, 0x614d, USB_CLASS_VENDOR_SPEC) },
1611 + { }
1612 +};
1613 +
1614 +MODULE_DEVICE_TABLE(usb, gud_id_table);
1615 +
1616 +static struct usb_driver gud_usb_driver = {
1617 + .name = "gud",
1618 + .probe = gud_probe,
1619 + .disconnect = gud_disconnect,
1620 + .id_table = gud_id_table,
1621 + .suspend = gud_suspend,
1622 + .resume = gud_resume,
1623 + .reset_resume = gud_resume,
1624 +};
1625 +
1626 +module_usb_driver(gud_usb_driver);
1627 +
1628 +MODULE_AUTHOR("Noralf Trønnes");
1629 +MODULE_LICENSE("Dual MIT/GPL");
1630 --- /dev/null
1631 +++ b/drivers/gpu/drm/gud/gud_internal.h
1632 @@ -0,0 +1,154 @@
1633 +/* SPDX-License-Identifier: MIT */
1634 +
1635 +#ifndef __LINUX_GUD_INTERNAL_H
1636 +#define __LINUX_GUD_INTERNAL_H
1637 +
1638 +#include <linux/list.h>
1639 +#include <linux/mutex.h>
1640 +#include <linux/usb.h>
1641 +#include <linux/workqueue.h>
1642 +#include <uapi/drm/drm_fourcc.h>
1643 +
1644 +#include <drm/drm_modes.h>
1645 +#include <drm/drm_simple_kms_helper.h>
1646 +
1647 +struct gud_device {
1648 + struct drm_device drm;
1649 + struct drm_simple_display_pipe pipe;
1650 + struct device *dmadev;
1651 + struct work_struct work;
1652 + u32 flags;
1653 + const struct drm_format_info *xrgb8888_emulation_format;
1654 +
1655 + u16 *properties;
1656 + unsigned int num_properties;
1657 +
1658 + unsigned int bulk_pipe;
1659 + void *bulk_buf;
1660 + size_t bulk_len;
1661 +
1662 + u8 compression;
1663 + void *lz4_comp_mem;
1664 + void *compress_buf;
1665 +
1666 + u64 stats_length;
1667 + u64 stats_actual_length;
1668 + unsigned int stats_num_errors;
1669 +
1670 + struct mutex ctrl_lock; /* Serialize get/set and status transfers */
1671 +
1672 + struct mutex damage_lock; /* Protects the following members: */
1673 + struct drm_framebuffer *fb;
1674 + struct drm_rect damage;
1675 + bool prev_flush_failed;
1676 +};
1677 +
1678 +static inline struct gud_device *to_gud_device(struct drm_device *drm)
1679 +{
1680 + return container_of(drm, struct gud_device, drm);
1681 +}
1682 +
1683 +static inline struct usb_device *gud_to_usb_device(struct gud_device *gdrm)
1684 +{
1685 + return interface_to_usbdev(to_usb_interface(gdrm->drm.dev));
1686 +}
1687 +
1688 +int gud_usb_get(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t len);
1689 +int gud_usb_set(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t len);
1690 +int gud_usb_get_u8(struct gud_device *gdrm, u8 request, u16 index, u8 *val);
1691 +int gud_usb_set_u8(struct gud_device *gdrm, u8 request, u8 val);
1692 +
1693 +void gud_clear_damage(struct gud_device *gdrm);
1694 +void gud_flush_work(struct work_struct *work);
1695 +int gud_pipe_check(struct drm_simple_display_pipe *pipe,
1696 + struct drm_plane_state *new_plane_state,
1697 + struct drm_crtc_state *new_crtc_state);
1698 +void gud_pipe_update(struct drm_simple_display_pipe *pipe,
1699 + struct drm_plane_state *old_state);
1700 +int gud_connector_fill_properties(struct drm_connector_state *connector_state,
1701 + struct gud_property_req *properties);
1702 +int gud_get_connectors(struct gud_device *gdrm);
1703 +
1704 +/* Driver internal fourcc transfer formats */
1705 +#define GUD_DRM_FORMAT_R1 0x00000122
1706 +#define GUD_DRM_FORMAT_XRGB1111 0x03121722
1707 +
1708 +static inline u8 gud_from_fourcc(u32 fourcc)
1709 +{
1710 + switch (fourcc) {
1711 + case GUD_DRM_FORMAT_R1:
1712 + return GUD_PIXEL_FORMAT_R1;
1713 + case GUD_DRM_FORMAT_XRGB1111:
1714 + return GUD_PIXEL_FORMAT_XRGB1111;
1715 + case DRM_FORMAT_RGB565:
1716 + return GUD_PIXEL_FORMAT_RGB565;
1717 + case DRM_FORMAT_XRGB8888:
1718 + return GUD_PIXEL_FORMAT_XRGB8888;
1719 + case DRM_FORMAT_ARGB8888:
1720 + return GUD_PIXEL_FORMAT_ARGB8888;
1721 + };
1722 +
1723 + return 0;
1724 +}
1725 +
1726 +static inline u32 gud_to_fourcc(u8 format)
1727 +{
1728 + switch (format) {
1729 + case GUD_PIXEL_FORMAT_R1:
1730 + return GUD_DRM_FORMAT_R1;
1731 + case GUD_PIXEL_FORMAT_XRGB1111:
1732 + return GUD_DRM_FORMAT_XRGB1111;
1733 + case GUD_PIXEL_FORMAT_RGB565:
1734 + return DRM_FORMAT_RGB565;
1735 + case GUD_PIXEL_FORMAT_XRGB8888:
1736 + return DRM_FORMAT_XRGB8888;
1737 + case GUD_PIXEL_FORMAT_ARGB8888:
1738 + return DRM_FORMAT_ARGB8888;
1739 + };
1740 +
1741 + return 0;
1742 +}
1743 +
1744 +static inline void gud_from_display_mode(struct gud_display_mode_req *dst,
1745 + const struct drm_display_mode *src)
1746 +{
1747 + u32 flags = src->flags & GUD_DISPLAY_MODE_FLAG_USER_MASK;
1748 +
1749 + if (src->type & DRM_MODE_TYPE_PREFERRED)
1750 + flags |= GUD_DISPLAY_MODE_FLAG_PREFERRED;
1751 +
1752 + dst->clock = cpu_to_le32(src->clock);
1753 + dst->hdisplay = cpu_to_le16(src->hdisplay);
1754 + dst->hsync_start = cpu_to_le16(src->hsync_start);
1755 + dst->hsync_end = cpu_to_le16(src->hsync_end);
1756 + dst->htotal = cpu_to_le16(src->htotal);
1757 + dst->vdisplay = cpu_to_le16(src->vdisplay);
1758 + dst->vsync_start = cpu_to_le16(src->vsync_start);
1759 + dst->vsync_end = cpu_to_le16(src->vsync_end);
1760 + dst->vtotal = cpu_to_le16(src->vtotal);
1761 + dst->flags = cpu_to_le32(flags);
1762 +}
1763 +
1764 +static inline void gud_to_display_mode(struct drm_display_mode *dst,
1765 + const struct gud_display_mode_req *src)
1766 +{
1767 + u32 flags = le32_to_cpu(src->flags);
1768 +
1769 + memset(dst, 0, sizeof(*dst));
1770 + dst->clock = le32_to_cpu(src->clock);
1771 + dst->hdisplay = le16_to_cpu(src->hdisplay);
1772 + dst->hsync_start = le16_to_cpu(src->hsync_start);
1773 + dst->hsync_end = le16_to_cpu(src->hsync_end);
1774 + dst->htotal = le16_to_cpu(src->htotal);
1775 + dst->vdisplay = le16_to_cpu(src->vdisplay);
1776 + dst->vsync_start = le16_to_cpu(src->vsync_start);
1777 + dst->vsync_end = le16_to_cpu(src->vsync_end);
1778 + dst->vtotal = le16_to_cpu(src->vtotal);
1779 + dst->flags = flags & GUD_DISPLAY_MODE_FLAG_USER_MASK;
1780 + dst->type = DRM_MODE_TYPE_DRIVER;
1781 + if (flags & GUD_DISPLAY_MODE_FLAG_PREFERRED)
1782 + dst->type |= DRM_MODE_TYPE_PREFERRED;
1783 + drm_mode_set_name(dst);
1784 +}
1785 +
1786 +#endif
1787 --- /dev/null
1788 +++ b/drivers/gpu/drm/gud/gud_pipe.c
1789 @@ -0,0 +1,551 @@
1790 +// SPDX-License-Identifier: MIT
1791 +/*
1792 + * Copyright 2020 Noralf Trønnes
1793 + */
1794 +
1795 +#include <linux/dma-buf.h>
1796 +#include <linux/lz4.h>
1797 +#include <linux/usb.h>
1798 +#include <linux/workqueue.h>
1799 +
1800 +#include <drm/drm_atomic.h>
1801 +#include <drm/drm_connector.h>
1802 +#include <drm/drm_damage_helper.h>
1803 +#include <drm/drm_drv.h>
1804 +#include <drm/drm_format_helper.h>
1805 +#include <drm/drm_fourcc.h>
1806 +#include <drm/drm_framebuffer.h>
1807 +#include <drm/drm_gem_shmem_helper.h>
1808 +#include <drm/drm_print.h>
1809 +#include <drm/drm_rect.h>
1810 +#include <drm/drm_simple_kms_helper.h>
1811 +#include <drm/gud.h>
1812 +
1813 +#include "gud_internal.h"
1814 +
1815 +/*
1816 + * FIXME: The driver is probably broken on Big Endian machines.
1817 + * See discussion:
1818 + * https://lore.kernel.org/dri-devel/CAKb7UvihLX0hgBOP3VBG7O+atwZcUVCPVuBdfmDMpg0NjXe-cQ@mail.gmail.com/
1819 + */
1820 +
1821 +static bool gud_is_big_endian(void)
1822 +{
1823 +#if defined(__BIG_ENDIAN)
1824 + return true;
1825 +#else
1826 + return false;
1827 +#endif
1828 +}
1829 +
1830 +static size_t gud_xrgb8888_to_r124(u8 *dst, const struct drm_format_info *format,
1831 + void *src, struct drm_framebuffer *fb,
1832 + struct drm_rect *rect)
1833 +{
1834 + unsigned int block_width = drm_format_info_block_width(format, 0);
1835 + unsigned int bits_per_pixel = 8 / block_width;
1836 + unsigned int x, y, width, height;
1837 + u8 pix, *pix8, *block = dst; /* Assign to silence compiler warning */
1838 + size_t len;
1839 + void *buf;
1840 +
1841 + WARN_ON_ONCE(format->char_per_block[0] != 1);
1842 +
1843 + /* Start on a byte boundary */
1844 + rect->x1 = ALIGN_DOWN(rect->x1, block_width);
1845 + width = drm_rect_width(rect);
1846 + height = drm_rect_height(rect);
1847 + len = drm_format_info_min_pitch(format, 0, width) * height;
1848 +
1849 + buf = kmalloc(width * height, GFP_KERNEL);
1850 + if (!buf)
1851 + return 0;
1852 +
1853 + drm_fb_xrgb8888_to_gray8(buf, src, fb, rect);
1854 + pix8 = buf;
1855 +
1856 + for (y = 0; y < height; y++) {
1857 + for (x = 0; x < width; x++) {
1858 + unsigned int pixpos = x % block_width; /* within byte from the left */
1859 + unsigned int pixshift = (block_width - pixpos - 1) * bits_per_pixel;
1860 +
1861 + if (!pixpos) {
1862 + block = dst++;
1863 + *block = 0;
1864 + }
1865 +
1866 + pix = (*pix8++) >> (8 - bits_per_pixel);
1867 + *block |= pix << pixshift;
1868 + }
1869 + }
1870 +
1871 + kfree(buf);
1872 +
1873 + return len;
1874 +}
1875 +
1876 +static size_t gud_xrgb8888_to_color(u8 *dst, const struct drm_format_info *format,
1877 + void *src, struct drm_framebuffer *fb,
1878 + struct drm_rect *rect)
1879 +{
1880 + unsigned int block_width = drm_format_info_block_width(format, 0);
1881 + unsigned int bits_per_pixel = 8 / block_width;
1882 + u8 r, g, b, pix, *block = dst; /* Assign to silence compiler warning */
1883 + unsigned int x, y, width;
1884 + u32 *pix32;
1885 + size_t len;
1886 +
1887 + /* Start on a byte boundary */
1888 + rect->x1 = ALIGN_DOWN(rect->x1, block_width);
1889 + width = drm_rect_width(rect);
1890 + len = drm_format_info_min_pitch(format, 0, width) * drm_rect_height(rect);
1891 +
1892 + for (y = rect->y1; y < rect->y2; y++) {
1893 + pix32 = src + (y * fb->pitches[0]);
1894 + pix32 += rect->x1;
1895 +
1896 + for (x = 0; x < width; x++) {
1897 + unsigned int pixpos = x % block_width; /* within byte from the left */
1898 + unsigned int pixshift = (block_width - pixpos - 1) * bits_per_pixel;
1899 +
1900 + if (!pixpos) {
1901 + block = dst++;
1902 + *block = 0;
1903 + }
1904 +
1905 + r = *pix32 >> 16;
1906 + g = *pix32 >> 8;
1907 + b = *pix32++;
1908 +
1909 + switch (format->format) {
1910 + case GUD_DRM_FORMAT_XRGB1111:
1911 + pix = ((r >> 7) << 2) | ((g >> 7) << 1) | (b >> 7);
1912 + break;
1913 + default:
1914 + WARN_ON_ONCE(1);
1915 + return len;
1916 + };
1917 +
1918 + *block |= pix << pixshift;
1919 + }
1920 + }
1921 +
1922 + return len;
1923 +}
1924 +
1925 +static int gud_prep_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
1926 + const struct drm_format_info *format, struct drm_rect *rect,
1927 + struct gud_set_buffer_req *req)
1928 +{
1929 + struct dma_buf_attachment *import_attach = fb->obj[0]->import_attach;
1930 + u8 compression = gdrm->compression;
1931 + void *vmap, *vaddr, *buf;
1932 + size_t pitch, len;
1933 + int ret = 0;
1934 +
1935 + pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(rect));
1936 + len = pitch * drm_rect_height(rect);
1937 + if (len > gdrm->bulk_len)
1938 + return -E2BIG;
1939 +
1940 + vmap = drm_gem_shmem_vmap(fb->obj[0]);
1941 + if (!vmap)
1942 + return -ENOMEM;
1943 +
1944 + vaddr = vmap + fb->offsets[0];
1945 +
1946 + if (import_attach) {
1947 + ret = dma_buf_begin_cpu_access(import_attach->dmabuf, DMA_FROM_DEVICE);
1948 + if (ret)
1949 + goto vunmap;
1950 + }
1951 +retry:
1952 + if (compression)
1953 + buf = gdrm->compress_buf;
1954 + else
1955 + buf = gdrm->bulk_buf;
1956 +
1957 + /*
1958 + * Imported buffers are assumed to be write-combined and thus uncached
1959 + * with slow reads (at least on ARM).
1960 + */
1961 + if (format != fb->format) {
1962 + if (format->format == GUD_DRM_FORMAT_R1) {
1963 + len = gud_xrgb8888_to_r124(buf, format, vaddr, fb, rect);
1964 + if (!len) {
1965 + ret = -ENOMEM;
1966 + goto end_cpu_access;
1967 + }
1968 + } else if (format->format == DRM_FORMAT_RGB565) {
1969 + drm_fb_xrgb8888_to_rgb565(buf, vaddr, fb, rect, gud_is_big_endian());
1970 + } else {
1971 + len = gud_xrgb8888_to_color(buf, format, vaddr, fb, rect);
1972 + }
1973 + } else if (gud_is_big_endian() && format->cpp[0] > 1) {
1974 + drm_fb_swab(buf, vaddr, fb, rect, !import_attach);
1975 + } else if (compression && !import_attach && pitch == fb->pitches[0]) {
1976 + /* can compress directly from the framebuffer */
1977 + buf = vaddr + rect->y1 * pitch;
1978 + } else {
1979 + drm_fb_memcpy(buf, vaddr, fb, rect);
1980 + }
1981 +
1982 + memset(req, 0, sizeof(*req));
1983 + req->x = cpu_to_le32(rect->x1);
1984 + req->y = cpu_to_le32(rect->y1);
1985 + req->width = cpu_to_le32(drm_rect_width(rect));
1986 + req->height = cpu_to_le32(drm_rect_height(rect));
1987 + req->length = cpu_to_le32(len);
1988 +
1989 + if (compression & GUD_COMPRESSION_LZ4) {
1990 + int complen;
1991 +
1992 + complen = LZ4_compress_default(buf, gdrm->bulk_buf, len, len, gdrm->lz4_comp_mem);
1993 + if (complen <= 0) {
1994 + compression = 0;
1995 + goto retry;
1996 + }
1997 +
1998 + req->compression = GUD_COMPRESSION_LZ4;
1999 + req->compressed_length = cpu_to_le32(complen);
2000 + }
2001 +
2002 +end_cpu_access:
2003 + if (import_attach)
2004 + dma_buf_end_cpu_access(import_attach->dmabuf, DMA_FROM_DEVICE);
2005 +vunmap:
2006 + drm_gem_shmem_vunmap(fb->obj[0], vmap);
2007 +
2008 + return ret;
2009 +}
2010 +
2011 +static int gud_flush_rect(struct gud_device *gdrm, struct drm_framebuffer *fb,
2012 + const struct drm_format_info *format, struct drm_rect *rect)
2013 +{
2014 + struct usb_device *usb = gud_to_usb_device(gdrm);
2015 + struct gud_set_buffer_req req;
2016 + int ret, actual_length;
2017 + size_t len, trlen;
2018 +
2019 + drm_dbg(&gdrm->drm, "Flushing [FB:%d] " DRM_RECT_FMT "\n", fb->base.id, DRM_RECT_ARG(rect));
2020 +
2021 + ret = gud_prep_flush(gdrm, fb, format, rect, &req);
2022 + if (ret)
2023 + return ret;
2024 +
2025 + len = le32_to_cpu(req.length);
2026 +
2027 + if (req.compression)
2028 + trlen = le32_to_cpu(req.compressed_length);
2029 + else
2030 + trlen = len;
2031 +
2032 + gdrm->stats_length += len;
2033 + /* Did it wrap around? */
2034 + if (gdrm->stats_length <= len && gdrm->stats_actual_length) {
2035 + gdrm->stats_length = len;
2036 + gdrm->stats_actual_length = 0;
2037 + }
2038 + gdrm->stats_actual_length += trlen;
2039 +
2040 + if (!(gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE) || gdrm->prev_flush_failed) {
2041 + ret = gud_usb_set(gdrm, GUD_REQ_SET_BUFFER, 0, &req, sizeof(req));
2042 + if (ret)
2043 + return ret;
2044 + }
2045 +
2046 + ret = usb_bulk_msg(usb, gdrm->bulk_pipe, gdrm->bulk_buf, trlen,
2047 + &actual_length, msecs_to_jiffies(3000));
2048 + if (!ret && trlen != actual_length)
2049 + ret = -EIO;
2050 + if (ret)
2051 + gdrm->stats_num_errors++;
2052 +
2053 + return ret;
2054 +}
2055 +
2056 +void gud_clear_damage(struct gud_device *gdrm)
2057 +{
2058 + gdrm->damage.x1 = INT_MAX;
2059 + gdrm->damage.y1 = INT_MAX;
2060 + gdrm->damage.x2 = 0;
2061 + gdrm->damage.y2 = 0;
2062 +}
2063 +
2064 +static void gud_add_damage(struct gud_device *gdrm, struct drm_rect *damage)
2065 +{
2066 + gdrm->damage.x1 = min(gdrm->damage.x1, damage->x1);
2067 + gdrm->damage.y1 = min(gdrm->damage.y1, damage->y1);
2068 + gdrm->damage.x2 = max(gdrm->damage.x2, damage->x2);
2069 + gdrm->damage.y2 = max(gdrm->damage.y2, damage->y2);
2070 +}
2071 +
2072 +static void gud_retry_failed_flush(struct gud_device *gdrm, struct drm_framebuffer *fb,
2073 + struct drm_rect *damage)
2074 +{
2075 + /*
2076 + * pipe_update waits for the worker when the display mode is going to change.
2077 + * This ensures that the width and height is still the same making it safe to
2078 + * add back the damage.
2079 + */
2080 +
2081 + mutex_lock(&gdrm->damage_lock);
2082 + if (!gdrm->fb) {
2083 + drm_framebuffer_get(fb);
2084 + gdrm->fb = fb;
2085 + }
2086 + gud_add_damage(gdrm, damage);
2087 + mutex_unlock(&gdrm->damage_lock);
2088 +
2089 + /* Retry only once to avoid a possible storm in case of continues errors. */
2090 + if (!gdrm->prev_flush_failed)
2091 + queue_work(system_long_wq, &gdrm->work);
2092 + gdrm->prev_flush_failed = true;
2093 +}
2094 +
2095 +void gud_flush_work(struct work_struct *work)
2096 +{
2097 + struct gud_device *gdrm = container_of(work, struct gud_device, work);
2098 + const struct drm_format_info *format;
2099 + struct drm_framebuffer *fb;
2100 + struct drm_rect damage;
2101 + unsigned int i, lines;
2102 + int idx, ret = 0;
2103 + size_t pitch;
2104 +
2105 + if (!drm_dev_enter(&gdrm->drm, &idx))
2106 + return;
2107 +
2108 + mutex_lock(&gdrm->damage_lock);
2109 + fb = gdrm->fb;
2110 + gdrm->fb = NULL;
2111 + damage = gdrm->damage;
2112 + gud_clear_damage(gdrm);
2113 + mutex_unlock(&gdrm->damage_lock);
2114 +
2115 + if (!fb)
2116 + goto out;
2117 +
2118 + format = fb->format;
2119 + if (format->format == DRM_FORMAT_XRGB8888 && gdrm->xrgb8888_emulation_format)
2120 + format = gdrm->xrgb8888_emulation_format;
2121 +
2122 + /* Split update if it's too big */
2123 + pitch = drm_format_info_min_pitch(format, 0, drm_rect_width(&damage));
2124 + lines = drm_rect_height(&damage);
2125 +
2126 + if (gdrm->bulk_len < lines * pitch)
2127 + lines = gdrm->bulk_len / pitch;
2128 +
2129 + for (i = 0; i < DIV_ROUND_UP(drm_rect_height(&damage), lines); i++) {
2130 + struct drm_rect rect = damage;
2131 +
2132 + rect.y1 += i * lines;
2133 + rect.y2 = min_t(u32, rect.y1 + lines, damage.y2);
2134 +
2135 + ret = gud_flush_rect(gdrm, fb, format, &rect);
2136 + if (ret) {
2137 + if (ret != -ENODEV && ret != -ECONNRESET &&
2138 + ret != -ESHUTDOWN && ret != -EPROTO) {
2139 + bool prev_flush_failed = gdrm->prev_flush_failed;
2140 +
2141 + gud_retry_failed_flush(gdrm, fb, &damage);
2142 + if (!prev_flush_failed)
2143 + dev_err_ratelimited(fb->dev->dev,
2144 + "Failed to flush framebuffer: error=%d\n", ret);
2145 + }
2146 + break;
2147 + }
2148 +
2149 + gdrm->prev_flush_failed = false;
2150 + }
2151 +
2152 + drm_framebuffer_put(fb);
2153 +out:
2154 + drm_dev_exit(idx);
2155 +}
2156 +
2157 +static void gud_fb_queue_damage(struct gud_device *gdrm, struct drm_framebuffer *fb,
2158 + struct drm_rect *damage)
2159 +{
2160 + struct drm_framebuffer *old_fb = NULL;
2161 +
2162 + mutex_lock(&gdrm->damage_lock);
2163 +
2164 + if (fb != gdrm->fb) {
2165 + old_fb = gdrm->fb;
2166 + drm_framebuffer_get(fb);
2167 + gdrm->fb = fb;
2168 + }
2169 +
2170 + gud_add_damage(gdrm, damage);
2171 +
2172 + mutex_unlock(&gdrm->damage_lock);
2173 +
2174 + queue_work(system_long_wq, &gdrm->work);
2175 +
2176 + if (old_fb)
2177 + drm_framebuffer_put(old_fb);
2178 +}
2179 +
2180 +int gud_pipe_check(struct drm_simple_display_pipe *pipe,
2181 + struct drm_plane_state *new_plane_state,
2182 + struct drm_crtc_state *new_crtc_state)
2183 +{
2184 + struct gud_device *gdrm = to_gud_device(pipe->crtc.dev);
2185 + struct drm_plane_state *old_plane_state = pipe->plane.state;
2186 + const struct drm_display_mode *mode = &new_crtc_state->mode;
2187 + struct drm_atomic_state *state = new_plane_state->state;
2188 + struct drm_framebuffer *old_fb = old_plane_state->fb;
2189 + struct drm_connector_state *connector_state = NULL;
2190 + struct drm_framebuffer *fb = new_plane_state->fb;
2191 + const struct drm_format_info *format = fb->format;
2192 + struct drm_connector *connector;
2193 + unsigned int i, num_properties;
2194 + struct gud_state_req *req;
2195 + int idx, ret;
2196 + size_t len;
2197 +
2198 + if (WARN_ON_ONCE(!fb))
2199 + return -EINVAL;
2200 +
2201 + if (old_plane_state->rotation != new_plane_state->rotation)
2202 + new_crtc_state->mode_changed = true;
2203 +
2204 + if (old_fb && old_fb->format != format)
2205 + new_crtc_state->mode_changed = true;
2206 +
2207 + if (!new_crtc_state->mode_changed && !new_crtc_state->connectors_changed)
2208 + return 0;
2209 +
2210 + /* Only one connector is supported */
2211 + if (hweight32(new_crtc_state->connector_mask) != 1)
2212 + return -EINVAL;
2213 +
2214 + if (format->format == DRM_FORMAT_XRGB8888 && gdrm->xrgb8888_emulation_format)
2215 + format = gdrm->xrgb8888_emulation_format;
2216 +
2217 + for_each_new_connector_in_state(state, connector, connector_state, i) {
2218 + if (connector_state->crtc)
2219 + break;
2220 + }
2221 +
2222 + /*
2223 + * DRM_IOCTL_MODE_OBJ_SETPROPERTY on the rotation property will not have
2224 + * the connector included in the state.
2225 + */
2226 + if (!connector_state) {
2227 + struct drm_connector_list_iter conn_iter;
2228 +
2229 + drm_connector_list_iter_begin(pipe->crtc.dev, &conn_iter);
2230 + drm_for_each_connector_iter(connector, &conn_iter) {
2231 + if (connector->state->crtc) {
2232 + connector_state = connector->state;
2233 + break;
2234 + }
2235 + }
2236 + drm_connector_list_iter_end(&conn_iter);
2237 + }
2238 +
2239 + if (WARN_ON_ONCE(!connector_state))
2240 + return -ENOENT;
2241 +
2242 + len = struct_size(req, properties,
2243 + GUD_PROPERTIES_MAX_NUM + GUD_CONNECTOR_PROPERTIES_MAX_NUM);
2244 + req = kzalloc(len, GFP_KERNEL);
2245 + if (!req)
2246 + return -ENOMEM;
2247 +
2248 + gud_from_display_mode(&req->mode, mode);
2249 +
2250 + req->format = gud_from_fourcc(format->format);
2251 + if (WARN_ON_ONCE(!req->format)) {
2252 + ret = -EINVAL;
2253 + goto out;
2254 + }
2255 +
2256 + req->connector = drm_connector_index(connector_state->connector);
2257 +
2258 + ret = gud_connector_fill_properties(connector_state, req->properties);
2259 + if (ret < 0)
2260 + goto out;
2261 +
2262 + num_properties = ret;
2263 + for (i = 0; i < gdrm->num_properties; i++) {
2264 + u16 prop = gdrm->properties[i];
2265 + u64 val;
2266 +
2267 + switch (prop) {
2268 + case GUD_PROPERTY_ROTATION:
2269 + /* DRM UAPI matches the protocol so use value directly */
2270 + val = new_plane_state->rotation;
2271 + break;
2272 + default:
2273 + WARN_ON_ONCE(1);
2274 + ret = -EINVAL;
2275 + goto out;
2276 + }
2277 +
2278 + req->properties[num_properties + i].prop = cpu_to_le16(prop);
2279 + req->properties[num_properties + i].val = cpu_to_le64(val);
2280 + num_properties++;
2281 + }
2282 +
2283 + if (drm_dev_enter(fb->dev, &idx)) {
2284 + len = struct_size(req, properties, num_properties);
2285 + ret = gud_usb_set(gdrm, GUD_REQ_SET_STATE_CHECK, 0, req, len);
2286 + drm_dev_exit(idx);
2287 + } else {
2288 + ret = -ENODEV;
2289 + }
2290 +out:
2291 + kfree(req);
2292 +
2293 + return ret;
2294 +}
2295 +
2296 +void gud_pipe_update(struct drm_simple_display_pipe *pipe,
2297 + struct drm_plane_state *old_state)
2298 +{
2299 + struct drm_device *drm = pipe->crtc.dev;
2300 + struct gud_device *gdrm = to_gud_device(drm);
2301 + struct drm_plane_state *state = pipe->plane.state;
2302 + struct drm_framebuffer *fb = state->fb;
2303 + struct drm_crtc *crtc = &pipe->crtc;
2304 + struct drm_rect damage;
2305 + int idx;
2306 +
2307 + if (crtc->state->mode_changed || !crtc->state->enable) {
2308 + cancel_work_sync(&gdrm->work);
2309 + mutex_lock(&gdrm->damage_lock);
2310 + if (gdrm->fb) {
2311 + drm_framebuffer_put(gdrm->fb);
2312 + gdrm->fb = NULL;
2313 + }
2314 + gud_clear_damage(gdrm);
2315 + mutex_unlock(&gdrm->damage_lock);
2316 + }
2317 +
2318 + if (!drm_dev_enter(drm, &idx))
2319 + return;
2320 +
2321 + if (!old_state->fb)
2322 + gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 1);
2323 +
2324 + if (fb && (crtc->state->mode_changed || crtc->state->connectors_changed))
2325 + gud_usb_set(gdrm, GUD_REQ_SET_STATE_COMMIT, 0, NULL, 0);
2326 +
2327 + if (crtc->state->active_changed)
2328 + gud_usb_set_u8(gdrm, GUD_REQ_SET_DISPLAY_ENABLE, crtc->state->active);
2329 +
2330 + if (drm_atomic_helper_damage_merged(old_state, state, &damage)) {
2331 + if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE)
2332 + drm_rect_init(&damage, 0, 0, fb->width, fb->height);
2333 + gud_fb_queue_damage(gdrm, fb, &damage);
2334 + }
2335 +
2336 + if (!crtc->state->enable)
2337 + gud_usb_set_u8(gdrm, GUD_REQ_SET_CONTROLLER_ENABLE, 0);
2338 +
2339 + drm_dev_exit(idx);
2340 +}
2341 --- /dev/null
2342 +++ b/include/drm/gud.h
2343 @@ -0,0 +1,333 @@
2344 +/* SPDX-License-Identifier: MIT */
2345 +/*
2346 + * Copyright 2020 Noralf Trønnes
2347 + */
2348 +
2349 +#ifndef __LINUX_GUD_H
2350 +#define __LINUX_GUD_H
2351 +
2352 +#include <linux/types.h>
2353 +
2354 +/*
2355 + * struct gud_display_descriptor_req - Display descriptor
2356 + * @magic: Magic value GUD_DISPLAY_MAGIC
2357 + * @version: Protocol version
2358 + * @flags: Flags
2359 + * - STATUS_ON_SET: Always do a status request after a SET request.
2360 + * This is used by the Linux gadget driver since it has
2361 + * no way to control the status stage of a control OUT
2362 + * request that has a payload.
2363 + * - FULL_UPDATE: Always send the entire framebuffer when flushing changes.
2364 + * The GUD_REQ_SET_BUFFER request will not be sent
2365 + * before each bulk transfer, it will only be sent if the
2366 + * previous bulk transfer had failed. This gives the device
2367 + * a chance to reset its state machine if needed.
2368 + * This flag can not be used in combination with compression.
2369 + * @compression: Supported compression types
2370 + * - GUD_COMPRESSION_LZ4: LZ4 lossless compression.
2371 + * @max_buffer_size: Maximum buffer size the device can handle (optional).
2372 + * This is useful for devices that don't have a big enough
2373 + * buffer to decompress the entire framebuffer in one go.
2374 + * @min_width: Minimum pixel width the controller can handle
2375 + * @max_width: Maximum width
2376 + * @min_height: Minimum height
2377 + * @max_height: Maximum height
2378 + *
2379 + * Devices that have only one display mode will have min_width == max_width
2380 + * and min_height == max_height.
2381 + */
2382 +struct gud_display_descriptor_req {
2383 + __le32 magic;
2384 +#define GUD_DISPLAY_MAGIC 0x1d50614d
2385 + __u8 version;
2386 + __le32 flags;
2387 +#define GUD_DISPLAY_FLAG_STATUS_ON_SET BIT(0)
2388 +#define GUD_DISPLAY_FLAG_FULL_UPDATE BIT(1)
2389 + __u8 compression;
2390 +#define GUD_COMPRESSION_LZ4 BIT(0)
2391 + __le32 max_buffer_size;
2392 + __le32 min_width;
2393 + __le32 max_width;
2394 + __le32 min_height;
2395 + __le32 max_height;
2396 +} __packed;
2397 +
2398 +/*
2399 + * struct gud_property_req - Property
2400 + * @prop: Property
2401 + * @val: Value
2402 + */
2403 +struct gud_property_req {
2404 + __le16 prop;
2405 + __le64 val;
2406 +} __packed;
2407 +
2408 +/*
2409 + * struct gud_display_mode_req - Display mode
2410 + * @clock: Pixel clock in kHz
2411 + * @hdisplay: Horizontal display size
2412 + * @hsync_start: Horizontal sync start
2413 + * @hsync_end: Horizontal sync end
2414 + * @htotal: Horizontal total size
2415 + * @vdisplay: Vertical display size
2416 + * @vsync_start: Vertical sync start
2417 + * @vsync_end: Vertical sync end
2418 + * @vtotal: Vertical total size
2419 + * @flags: Bits 0-13 are the same as in the RandR protocol and also what DRM uses.
2420 + * The deprecated bits are reused for internal protocol flags leaving us
2421 + * free to follow DRM for the other bits in the future.
2422 + * - FLAG_PREFERRED: Set on the preferred display mode.
2423 + */
2424 +struct gud_display_mode_req {
2425 + __le32 clock;
2426 + __le16 hdisplay;
2427 + __le16 hsync_start;
2428 + __le16 hsync_end;
2429 + __le16 htotal;
2430 + __le16 vdisplay;
2431 + __le16 vsync_start;
2432 + __le16 vsync_end;
2433 + __le16 vtotal;
2434 + __le32 flags;
2435 +#define GUD_DISPLAY_MODE_FLAG_PHSYNC BIT(0)
2436 +#define GUD_DISPLAY_MODE_FLAG_NHSYNC BIT(1)
2437 +#define GUD_DISPLAY_MODE_FLAG_PVSYNC BIT(2)
2438 +#define GUD_DISPLAY_MODE_FLAG_NVSYNC BIT(3)
2439 +#define GUD_DISPLAY_MODE_FLAG_INTERLACE BIT(4)
2440 +#define GUD_DISPLAY_MODE_FLAG_DBLSCAN BIT(5)
2441 +#define GUD_DISPLAY_MODE_FLAG_CSYNC BIT(6)
2442 +#define GUD_DISPLAY_MODE_FLAG_PCSYNC BIT(7)
2443 +#define GUD_DISPLAY_MODE_FLAG_NCSYNC BIT(8)
2444 +#define GUD_DISPLAY_MODE_FLAG_HSKEW BIT(9)
2445 +/* BCast and PixelMultiplex are deprecated */
2446 +#define GUD_DISPLAY_MODE_FLAG_DBLCLK BIT(12)
2447 +#define GUD_DISPLAY_MODE_FLAG_CLKDIV2 BIT(13)
2448 +#define GUD_DISPLAY_MODE_FLAG_USER_MASK \
2449 + (GUD_DISPLAY_MODE_FLAG_PHSYNC | GUD_DISPLAY_MODE_FLAG_NHSYNC | \
2450 + GUD_DISPLAY_MODE_FLAG_PVSYNC | GUD_DISPLAY_MODE_FLAG_NVSYNC | \
2451 + GUD_DISPLAY_MODE_FLAG_INTERLACE | GUD_DISPLAY_MODE_FLAG_DBLSCAN | \
2452 + GUD_DISPLAY_MODE_FLAG_CSYNC | GUD_DISPLAY_MODE_FLAG_PCSYNC | \
2453 + GUD_DISPLAY_MODE_FLAG_NCSYNC | GUD_DISPLAY_MODE_FLAG_HSKEW | \
2454 + GUD_DISPLAY_MODE_FLAG_DBLCLK | GUD_DISPLAY_MODE_FLAG_CLKDIV2)
2455 +/* Internal protocol flags */
2456 +#define GUD_DISPLAY_MODE_FLAG_PREFERRED BIT(10)
2457 +} __packed;
2458 +
2459 +/*
2460 + * struct gud_connector_descriptor_req - Connector descriptor
2461 + * @connector_type: Connector type (GUD_CONNECTOR_TYPE_*).
2462 + * If the host doesn't support the type it should fall back to PANEL.
2463 + * @flags: Flags
2464 + * - POLL_STATUS: Connector status can change (polled every 10 seconds)
2465 + * - INTERLACE: Interlaced modes are supported
2466 + * - DOUBLESCAN: Doublescan modes are supported
2467 + */
2468 +struct gud_connector_descriptor_req {
2469 + __u8 connector_type;
2470 +#define GUD_CONNECTOR_TYPE_PANEL 0
2471 +#define GUD_CONNECTOR_TYPE_VGA 1
2472 +#define GUD_CONNECTOR_TYPE_COMPOSITE 2
2473 +#define GUD_CONNECTOR_TYPE_SVIDEO 3
2474 +#define GUD_CONNECTOR_TYPE_COMPONENT 4
2475 +#define GUD_CONNECTOR_TYPE_DVI 5
2476 +#define GUD_CONNECTOR_TYPE_DISPLAYPORT 6
2477 +#define GUD_CONNECTOR_TYPE_HDMI 7
2478 + __le32 flags;
2479 +#define GUD_CONNECTOR_FLAGS_POLL_STATUS BIT(0)
2480 +#define GUD_CONNECTOR_FLAGS_INTERLACE BIT(1)
2481 +#define GUD_CONNECTOR_FLAGS_DOUBLESCAN BIT(2)
2482 +} __packed;
2483 +
2484 +/*
2485 + * struct gud_set_buffer_req - Set buffer transfer info
2486 + * @x: X position of rectangle
2487 + * @y: Y position
2488 + * @width: Pixel width of rectangle
2489 + * @height: Pixel height
2490 + * @length: Buffer length in bytes
2491 + * @compression: Transfer compression
2492 + * @compressed_length: Compressed buffer length
2493 + *
2494 + * This request is issued right before the bulk transfer.
2495 + * @x, @y, @width and @height specifies the rectangle where the buffer should be
2496 + * placed inside the framebuffer.
2497 + */
2498 +struct gud_set_buffer_req {
2499 + __le32 x;
2500 + __le32 y;
2501 + __le32 width;
2502 + __le32 height;
2503 + __le32 length;
2504 + __u8 compression;
2505 + __le32 compressed_length;
2506 +} __packed;
2507 +
2508 +/*
2509 + * struct gud_state_req - Display state
2510 + * @mode: Display mode
2511 + * @format: Pixel format GUD_PIXEL_FORMAT_*
2512 + * @connector: Connector index
2513 + * @properties: Array of properties
2514 + *
2515 + * The entire state is transferred each time there's a change.
2516 + */
2517 +struct gud_state_req {
2518 + struct gud_display_mode_req mode;
2519 + __u8 format;
2520 + __u8 connector;
2521 + struct gud_property_req properties[];
2522 +} __packed;
2523 +
2524 +/* List of supported connector properties: */
2525 +
2526 +/* Margins in pixels to deal with overscan, range 0-100 */
2527 +#define GUD_PROPERTY_TV_LEFT_MARGIN 1
2528 +#define GUD_PROPERTY_TV_RIGHT_MARGIN 2
2529 +#define GUD_PROPERTY_TV_TOP_MARGIN 3
2530 +#define GUD_PROPERTY_TV_BOTTOM_MARGIN 4
2531 +#define GUD_PROPERTY_TV_MODE 5
2532 +/* Brightness in percent, range 0-100 */
2533 +#define GUD_PROPERTY_TV_BRIGHTNESS 6
2534 +/* Contrast in percent, range 0-100 */
2535 +#define GUD_PROPERTY_TV_CONTRAST 7
2536 +/* Flicker reduction in percent, range 0-100 */
2537 +#define GUD_PROPERTY_TV_FLICKER_REDUCTION 8
2538 +/* Overscan in percent, range 0-100 */
2539 +#define GUD_PROPERTY_TV_OVERSCAN 9
2540 +/* Saturation in percent, range 0-100 */
2541 +#define GUD_PROPERTY_TV_SATURATION 10
2542 +/* Hue in percent, range 0-100 */
2543 +#define GUD_PROPERTY_TV_HUE 11
2544 +
2545 +/*
2546 + * Backlight brightness is in the range 0-100 inclusive. The value represents the human perceptual
2547 + * brightness and not a linear PWM value. 0 is minimum brightness which should not turn the
2548 + * backlight completely off. The DPMS connector property should be used to control power which will
2549 + * trigger a GUD_REQ_SET_DISPLAY_ENABLE request.
2550 + *
2551 + * This does not map to a DRM property, it is used with the backlight device.
2552 + */
2553 +#define GUD_PROPERTY_BACKLIGHT_BRIGHTNESS 12
2554 +
2555 +/* List of supported properties that are not connector propeties: */
2556 +
2557 +/*
2558 + * Plane rotation. Should return the supported bitmask on
2559 + * GUD_REQ_GET_PROPERTIES. GUD_ROTATION_0 is mandatory.
2560 + *
2561 + * Note: This is not display rotation so 90/270 will need scaling to make it fit (unless squared).
2562 + */
2563 +#define GUD_PROPERTY_ROTATION 50
2564 + #define GUD_ROTATION_0 BIT(0)
2565 + #define GUD_ROTATION_90 BIT(1)
2566 + #define GUD_ROTATION_180 BIT(2)
2567 + #define GUD_ROTATION_270 BIT(3)
2568 + #define GUD_ROTATION_REFLECT_X BIT(4)
2569 + #define GUD_ROTATION_REFLECT_Y BIT(5)
2570 + #define GUD_ROTATION_MASK (GUD_ROTATION_0 | GUD_ROTATION_90 | \
2571 + GUD_ROTATION_180 | GUD_ROTATION_270 | \
2572 + GUD_ROTATION_REFLECT_X | GUD_ROTATION_REFLECT_Y)
2573 +
2574 +/* USB Control requests: */
2575 +
2576 +/* Get status from the last GET/SET control request. Value is u8. */
2577 +#define GUD_REQ_GET_STATUS 0x00
2578 + /* Status values: */
2579 + #define GUD_STATUS_OK 0x00
2580 + #define GUD_STATUS_BUSY 0x01
2581 + #define GUD_STATUS_REQUEST_NOT_SUPPORTED 0x02
2582 + #define GUD_STATUS_PROTOCOL_ERROR 0x03
2583 + #define GUD_STATUS_INVALID_PARAMETER 0x04
2584 + #define GUD_STATUS_ERROR 0x05
2585 +
2586 +/* Get display descriptor as a &gud_display_descriptor_req */
2587 +#define GUD_REQ_GET_DESCRIPTOR 0x01
2588 +
2589 +/* Get supported pixel formats as a byte array of GUD_PIXEL_FORMAT_* */
2590 +#define GUD_REQ_GET_FORMATS 0x40
2591 + #define GUD_FORMATS_MAX_NUM 32
2592 + /* R1 is a 1-bit monochrome transfer format presented to userspace as XRGB8888 */
2593 + #define GUD_PIXEL_FORMAT_R1 0x01
2594 + #define GUD_PIXEL_FORMAT_XRGB1111 0x20
2595 + #define GUD_PIXEL_FORMAT_RGB565 0x40
2596 + #define GUD_PIXEL_FORMAT_XRGB8888 0x80
2597 + #define GUD_PIXEL_FORMAT_ARGB8888 0x81
2598 +
2599 +/*
2600 + * Get supported properties that are not connector propeties as a &gud_property_req array.
2601 + * gud_property_req.val often contains the initial value for the property.
2602 + */
2603 +#define GUD_REQ_GET_PROPERTIES 0x41
2604 + #define GUD_PROPERTIES_MAX_NUM 32
2605 +
2606 +/* Connector requests have the connector index passed in the wValue field */
2607 +
2608 +/* Get connector descriptors as an array of &gud_connector_descriptor_req */
2609 +#define GUD_REQ_GET_CONNECTORS 0x50
2610 + #define GUD_CONNECTORS_MAX_NUM 32
2611 +
2612 +/*
2613 + * Get properties supported by the connector as a &gud_property_req array.
2614 + * gud_property_req.val often contains the initial value for the property.
2615 + */
2616 +#define GUD_REQ_GET_CONNECTOR_PROPERTIES 0x51
2617 + #define GUD_CONNECTOR_PROPERTIES_MAX_NUM 32
2618 +
2619 +/*
2620 + * Issued when there's a TV_MODE property present.
2621 + * Gets an array of the supported TV_MODE names each entry of length
2622 + * GUD_CONNECTOR_TV_MODE_NAME_LEN. Names must be NUL-terminated.
2623 + */
2624 +#define GUD_REQ_GET_CONNECTOR_TV_MODE_VALUES 0x52
2625 + #define GUD_CONNECTOR_TV_MODE_NAME_LEN 16
2626 + #define GUD_CONNECTOR_TV_MODE_MAX_NUM 16
2627 +
2628 +/* When userspace checks connector status, this is issued first, not used for poll requests. */
2629 +#define GUD_REQ_SET_CONNECTOR_FORCE_DETECT 0x53
2630 +
2631 +/*
2632 + * Get connector status. Value is u8.
2633 + *
2634 + * Userspace will get a HOTPLUG uevent if one of the following is true:
2635 + * - Connection status has changed since last
2636 + * - CHANGED is set
2637 + */
2638 +#define GUD_REQ_GET_CONNECTOR_STATUS 0x54
2639 + #define GUD_CONNECTOR_STATUS_DISCONNECTED 0x00
2640 + #define GUD_CONNECTOR_STATUS_CONNECTED 0x01
2641 + #define GUD_CONNECTOR_STATUS_UNKNOWN 0x02
2642 + #define GUD_CONNECTOR_STATUS_CONNECTED_MASK 0x03
2643 + #define GUD_CONNECTOR_STATUS_CHANGED BIT(7)
2644 +
2645 +/*
2646 + * Display modes can be fetched as either EDID data or an array of &gud_display_mode_req.
2647 + *
2648 + * If GUD_REQ_GET_CONNECTOR_MODES returns zero, EDID is used to create display modes.
2649 + * If both display modes and EDID are returned, EDID is just passed on to userspace
2650 + * in the EDID connector property.
2651 + */
2652 +
2653 +/* Get &gud_display_mode_req array of supported display modes */
2654 +#define GUD_REQ_GET_CONNECTOR_MODES 0x55
2655 + #define GUD_CONNECTOR_MAX_NUM_MODES 128
2656 +
2657 +/* Get Extended Display Identification Data */
2658 +#define GUD_REQ_GET_CONNECTOR_EDID 0x56
2659 + #define GUD_CONNECTOR_MAX_EDID_LEN 2048
2660 +
2661 +/* Set buffer properties before bulk transfer as &gud_set_buffer_req */
2662 +#define GUD_REQ_SET_BUFFER 0x60
2663 +
2664 +/* Check display configuration as &gud_state_req */
2665 +#define GUD_REQ_SET_STATE_CHECK 0x61
2666 +
2667 +/* Apply the previous STATE_CHECK configuration */
2668 +#define GUD_REQ_SET_STATE_COMMIT 0x62
2669 +
2670 +/* Enable/disable the display controller, value is u8: 0/1 */
2671 +#define GUD_REQ_SET_CONTROLLER_ENABLE 0x63
2672 +
2673 +/* Enable/disable display/output (DPMS), value is u8: 0/1 */
2674 +#define GUD_REQ_SET_DISPLAY_ENABLE 0x64
2675 +
2676 +#endif