1 // SPDX-License-Identifier: MIT
3 * Copyright 2020 Noralf Trønnes
6 #include <linux/backlight.h>
7 #include <linux/workqueue.h>
9 #include <drm/drm_atomic.h>
10 #include <drm/drm_atomic_state_helper.h>
11 #include <drm/drm_connector.h>
12 #include <drm/drm_drv.h>
13 #include <drm/drm_edid.h>
14 #include <drm/drm_encoder.h>
15 #include <drm/drm_file.h>
16 #include <drm/drm_modeset_helper_vtables.h>
17 #include <drm/drm_print.h>
18 #include <drm/drm_probe_helper.h>
19 #include <drm/drm_simple_kms_helper.h>
22 #include "gud_internal.h"
24 struct gud_connector {
25 struct drm_connector connector;
26 struct drm_encoder encoder;
27 struct backlight_device *backlight;
28 struct work_struct backlight_work;
30 /* Supported properties */
32 unsigned int num_properties;
34 /* Initial gadget tv state if applicable, applied on state reset */
35 struct drm_tv_connector_state initial_tv_state;
38 * Initial gadget backlight brightness if applicable, applied on state reset.
39 * The value -ENODEV is used to signal no backlight.
41 int initial_brightness;
44 static inline struct gud_connector *to_gud_connector(struct drm_connector *connector)
46 return container_of(connector, struct gud_connector, connector);
49 static void gud_conn_err(struct drm_connector *connector, const char *msg, int ret)
51 dev_err(connector->dev->dev, "%s: %s (ret=%d)\n", connector->name, msg, ret);
55 * Use a worker to avoid taking kms locks inside the backlight lock.
56 * Other display drivers use backlight within their kms locks.
57 * This avoids inconsistent locking rules, which would upset lockdep.
59 static void gud_connector_backlight_update_status_work(struct work_struct *work)
61 struct gud_connector *gconn = container_of(work, struct gud_connector, backlight_work);
62 struct drm_connector *connector = &gconn->connector;
63 struct drm_connector_state *connector_state;
64 struct drm_device *drm = connector->dev;
65 struct drm_modeset_acquire_ctx ctx;
66 struct drm_atomic_state *state;
69 if (!drm_dev_enter(drm, &idx))
72 state = drm_atomic_state_alloc(drm);
78 drm_modeset_acquire_init(&ctx, 0);
79 state->acquire_ctx = &ctx;
81 connector_state = drm_atomic_get_connector_state(state, connector);
82 if (IS_ERR(connector_state)) {
83 ret = PTR_ERR(connector_state);
87 /* Reuse tv.brightness to avoid having to subclass */
88 connector_state->tv.brightness = gconn->backlight->props.brightness;
90 ret = drm_atomic_commit(state);
92 if (ret == -EDEADLK) {
93 drm_atomic_state_clear(state);
94 drm_modeset_backoff(&ctx);
98 drm_atomic_state_put(state);
100 drm_modeset_drop_locks(&ctx);
101 drm_modeset_acquire_fini(&ctx);
106 dev_err(drm->dev, "Failed to update backlight, err=%d\n", ret);
109 static int gud_connector_backlight_update_status(struct backlight_device *bd)
111 struct drm_connector *connector = bl_get_data(bd);
112 struct gud_connector *gconn = to_gud_connector(connector);
114 /* The USB timeout is 5 seconds so use system_long_wq for worst case scenario */
115 queue_work(system_long_wq, &gconn->backlight_work);
120 static const struct backlight_ops gud_connector_backlight_ops = {
121 .update_status = gud_connector_backlight_update_status,
124 static int gud_connector_backlight_register(struct gud_connector *gconn)
126 struct drm_connector *connector = &gconn->connector;
127 struct backlight_device *bd;
129 const struct backlight_properties props = {
130 .type = BACKLIGHT_RAW,
131 .scale = BACKLIGHT_SCALE_NON_LINEAR,
132 .max_brightness = 100,
133 .brightness = gconn->initial_brightness,
136 name = kasprintf(GFP_KERNEL, "card%d-%s-backlight",
137 connector->dev->primary->index, connector->name);
141 bd = backlight_device_register(name, connector->kdev, connector,
142 &gud_connector_backlight_ops, &props);
147 gconn->backlight = bd;
152 static int gud_connector_detect(struct drm_connector *connector,
153 struct drm_modeset_acquire_ctx *ctx, bool force)
155 struct gud_device *gdrm = to_gud_device(connector->dev);
159 if (!drm_dev_enter(connector->dev, &idx))
160 return connector_status_disconnected;
163 ret = gud_usb_set(gdrm, GUD_REQ_SET_CONNECTOR_FORCE_DETECT,
164 connector->index, NULL, 0);
166 ret = connector_status_unknown;
171 ret = gud_usb_get_u8(gdrm, GUD_REQ_GET_CONNECTOR_STATUS, connector->index, &status);
173 ret = connector_status_unknown;
177 switch (status & GUD_CONNECTOR_STATUS_CONNECTED_MASK) {
178 case GUD_CONNECTOR_STATUS_DISCONNECTED:
179 ret = connector_status_disconnected;
181 case GUD_CONNECTOR_STATUS_CONNECTED:
182 ret = connector_status_connected;
185 ret = connector_status_unknown;
189 if (status & GUD_CONNECTOR_STATUS_CHANGED)
190 connector->epoch_counter += 1;
197 struct gud_connector_get_edid_ctx {
203 static int gud_connector_get_edid_block(void *data, u8 *buf, unsigned int block, size_t len)
205 struct gud_connector_get_edid_ctx *ctx = data;
206 size_t start = block * EDID_LENGTH;
208 ctx->edid_override = false;
210 if (start + len > ctx->len)
213 memcpy(buf, ctx->buf + start, len);
218 static int gud_connector_get_modes(struct drm_connector *connector)
220 struct gud_device *gdrm = to_gud_device(connector->dev);
221 struct gud_display_mode_req *reqmodes = NULL;
222 struct gud_connector_get_edid_ctx edid_ctx;
223 unsigned int i, num_modes = 0;
224 struct edid *edid = NULL;
227 if (!drm_dev_enter(connector->dev, &idx))
230 edid_ctx.edid_override = true;
231 edid_ctx.buf = kmalloc(GUD_CONNECTOR_MAX_EDID_LEN, GFP_KERNEL);
235 ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_EDID, connector->index,
236 edid_ctx.buf, GUD_CONNECTOR_MAX_EDID_LEN);
237 if (ret > 0 && ret % EDID_LENGTH) {
238 gud_conn_err(connector, "Invalid EDID size", ret);
239 } else if (ret > 0) {
241 edid = drm_do_get_edid(connector, gud_connector_get_edid_block, &edid_ctx);
245 drm_connector_update_edid_property(connector, edid);
247 if (edid && edid_ctx.edid_override)
250 reqmodes = kmalloc_array(GUD_CONNECTOR_MAX_NUM_MODES, sizeof(*reqmodes), GFP_KERNEL);
254 ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_MODES, connector->index,
255 reqmodes, GUD_CONNECTOR_MAX_NUM_MODES * sizeof(*reqmodes));
258 if (ret % sizeof(*reqmodes)) {
259 gud_conn_err(connector, "Invalid display mode array size", ret);
263 num_modes = ret / sizeof(*reqmodes);
265 for (i = 0; i < num_modes; i++) {
266 struct drm_display_mode *mode;
268 mode = drm_mode_create(connector->dev);
274 gud_to_display_mode(mode, &reqmodes[i]);
275 drm_mode_probed_add(connector, mode);
279 num_modes = drm_add_edid_modes(connector, edid);
288 static int gud_connector_atomic_check(struct drm_connector *connector,
289 struct drm_atomic_state *state)
291 struct drm_connector_state *new_state;
292 struct drm_crtc_state *new_crtc_state;
293 struct drm_connector_state *old_state;
295 new_state = drm_atomic_get_new_connector_state(state, connector);
296 if (!new_state->crtc)
299 old_state = drm_atomic_get_old_connector_state(state, connector);
300 new_crtc_state = drm_atomic_get_new_crtc_state(state, new_state->crtc);
302 if (old_state->tv.margins.left != new_state->tv.margins.left ||
303 old_state->tv.margins.right != new_state->tv.margins.right ||
304 old_state->tv.margins.top != new_state->tv.margins.top ||
305 old_state->tv.margins.bottom != new_state->tv.margins.bottom ||
306 old_state->tv.legacy_mode != new_state->tv.legacy_mode ||
307 old_state->tv.brightness != new_state->tv.brightness ||
308 old_state->tv.contrast != new_state->tv.contrast ||
309 old_state->tv.flicker_reduction != new_state->tv.flicker_reduction ||
310 old_state->tv.overscan != new_state->tv.overscan ||
311 old_state->tv.saturation != new_state->tv.saturation ||
312 old_state->tv.hue != new_state->tv.hue)
313 new_crtc_state->connectors_changed = true;
318 static const struct drm_connector_helper_funcs gud_connector_helper_funcs = {
319 .detect_ctx = gud_connector_detect,
320 .get_modes = gud_connector_get_modes,
321 .atomic_check = gud_connector_atomic_check,
324 static int gud_connector_late_register(struct drm_connector *connector)
326 struct gud_connector *gconn = to_gud_connector(connector);
328 if (gconn->initial_brightness < 0)
331 return gud_connector_backlight_register(gconn);
334 static void gud_connector_early_unregister(struct drm_connector *connector)
336 struct gud_connector *gconn = to_gud_connector(connector);
338 backlight_device_unregister(gconn->backlight);
339 cancel_work_sync(&gconn->backlight_work);
342 static void gud_connector_destroy(struct drm_connector *connector)
344 struct gud_connector *gconn = to_gud_connector(connector);
346 drm_connector_cleanup(connector);
347 kfree(gconn->properties);
351 static void gud_connector_reset(struct drm_connector *connector)
353 struct gud_connector *gconn = to_gud_connector(connector);
355 drm_atomic_helper_connector_reset(connector);
356 connector->state->tv = gconn->initial_tv_state;
357 /* Set margins from command line */
358 drm_atomic_helper_connector_tv_margins_reset(connector);
359 if (gconn->initial_brightness >= 0)
360 connector->state->tv.brightness = gconn->initial_brightness;
363 static const struct drm_connector_funcs gud_connector_funcs = {
364 .fill_modes = drm_helper_probe_single_connector_modes,
365 .late_register = gud_connector_late_register,
366 .early_unregister = gud_connector_early_unregister,
367 .destroy = gud_connector_destroy,
368 .reset = gud_connector_reset,
369 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
370 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
374 * The tv.mode property is shared among the connectors and its enum names are
375 * driver specific. This means that if more than one connector uses tv.mode,
376 * the enum names has to be the same.
378 static int gud_connector_add_tv_mode(struct gud_device *gdrm, struct drm_connector *connector)
380 size_t buf_len = GUD_CONNECTOR_TV_MODE_MAX_NUM * GUD_CONNECTOR_TV_MODE_NAME_LEN;
381 const char *modes[GUD_CONNECTOR_TV_MODE_MAX_NUM];
382 unsigned int i, num_modes;
386 buf = kmalloc(buf_len, GFP_KERNEL);
390 ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_TV_MODE_VALUES,
391 connector->index, buf, buf_len);
394 if (!ret || ret % GUD_CONNECTOR_TV_MODE_NAME_LEN) {
399 num_modes = ret / GUD_CONNECTOR_TV_MODE_NAME_LEN;
400 for (i = 0; i < num_modes; i++)
401 modes[i] = &buf[i * GUD_CONNECTOR_TV_MODE_NAME_LEN];
403 ret = drm_mode_create_tv_properties_legacy(connector->dev, num_modes, modes);
407 gud_conn_err(connector, "Failed to add TV modes", ret);
412 static struct drm_property *
413 gud_connector_property_lookup(struct drm_connector *connector, u16 prop)
415 struct drm_mode_config *config = &connector->dev->mode_config;
418 case GUD_PROPERTY_TV_LEFT_MARGIN:
419 return config->tv_left_margin_property;
420 case GUD_PROPERTY_TV_RIGHT_MARGIN:
421 return config->tv_right_margin_property;
422 case GUD_PROPERTY_TV_TOP_MARGIN:
423 return config->tv_top_margin_property;
424 case GUD_PROPERTY_TV_BOTTOM_MARGIN:
425 return config->tv_bottom_margin_property;
426 case GUD_PROPERTY_TV_MODE:
427 return config->legacy_tv_mode_property;
428 case GUD_PROPERTY_TV_BRIGHTNESS:
429 return config->tv_brightness_property;
430 case GUD_PROPERTY_TV_CONTRAST:
431 return config->tv_contrast_property;
432 case GUD_PROPERTY_TV_FLICKER_REDUCTION:
433 return config->tv_flicker_reduction_property;
434 case GUD_PROPERTY_TV_OVERSCAN:
435 return config->tv_overscan_property;
436 case GUD_PROPERTY_TV_SATURATION:
437 return config->tv_saturation_property;
438 case GUD_PROPERTY_TV_HUE:
439 return config->tv_hue_property;
441 return ERR_PTR(-EINVAL);
445 static unsigned int *gud_connector_tv_state_val(u16 prop, struct drm_tv_connector_state *state)
448 case GUD_PROPERTY_TV_LEFT_MARGIN:
449 return &state->margins.left;
450 case GUD_PROPERTY_TV_RIGHT_MARGIN:
451 return &state->margins.right;
452 case GUD_PROPERTY_TV_TOP_MARGIN:
453 return &state->margins.top;
454 case GUD_PROPERTY_TV_BOTTOM_MARGIN:
455 return &state->margins.bottom;
456 case GUD_PROPERTY_TV_MODE:
457 return &state->legacy_mode;
458 case GUD_PROPERTY_TV_BRIGHTNESS:
459 return &state->brightness;
460 case GUD_PROPERTY_TV_CONTRAST:
461 return &state->contrast;
462 case GUD_PROPERTY_TV_FLICKER_REDUCTION:
463 return &state->flicker_reduction;
464 case GUD_PROPERTY_TV_OVERSCAN:
465 return &state->overscan;
466 case GUD_PROPERTY_TV_SATURATION:
467 return &state->saturation;
468 case GUD_PROPERTY_TV_HUE:
471 return ERR_PTR(-EINVAL);
475 static int gud_connector_add_properties(struct gud_device *gdrm, struct gud_connector *gconn)
477 struct drm_connector *connector = &gconn->connector;
478 struct drm_device *drm = &gdrm->drm;
479 struct gud_property_req *properties;
480 unsigned int i, num_properties;
483 properties = kcalloc(GUD_CONNECTOR_PROPERTIES_MAX_NUM, sizeof(*properties), GFP_KERNEL);
487 ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTOR_PROPERTIES, connector->index,
488 properties, GUD_CONNECTOR_PROPERTIES_MAX_NUM * sizeof(*properties));
491 if (ret % sizeof(*properties)) {
496 num_properties = ret / sizeof(*properties);
499 gconn->properties = kcalloc(num_properties, sizeof(*gconn->properties), GFP_KERNEL);
500 if (!gconn->properties) {
505 for (i = 0; i < num_properties; i++) {
506 u16 prop = le16_to_cpu(properties[i].prop);
507 u64 val = le64_to_cpu(properties[i].val);
508 struct drm_property *property;
509 unsigned int *state_val;
511 drm_dbg(drm, "property: %u = %llu(0x%llx)\n", prop, val, val);
514 case GUD_PROPERTY_TV_LEFT_MARGIN:
516 case GUD_PROPERTY_TV_RIGHT_MARGIN:
518 case GUD_PROPERTY_TV_TOP_MARGIN:
520 case GUD_PROPERTY_TV_BOTTOM_MARGIN:
521 ret = drm_mode_create_tv_margin_properties(drm);
525 case GUD_PROPERTY_TV_MODE:
526 ret = gud_connector_add_tv_mode(gdrm, connector);
530 case GUD_PROPERTY_TV_BRIGHTNESS:
532 case GUD_PROPERTY_TV_CONTRAST:
534 case GUD_PROPERTY_TV_FLICKER_REDUCTION:
536 case GUD_PROPERTY_TV_OVERSCAN:
538 case GUD_PROPERTY_TV_SATURATION:
540 case GUD_PROPERTY_TV_HUE:
541 /* This is a no-op if already added. */
542 ret = drm_mode_create_tv_properties_legacy(drm, 0, NULL);
546 case GUD_PROPERTY_BACKLIGHT_BRIGHTNESS:
551 gconn->initial_brightness = val;
554 /* New ones might show up in future devices, skip those we don't know. */
555 drm_dbg(drm, "Ignoring unknown property: %u\n", prop);
559 gconn->properties[gconn->num_properties++] = prop;
561 if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS)
562 continue; /* not a DRM property */
564 property = gud_connector_property_lookup(connector, prop);
565 if (WARN_ON(IS_ERR(property)))
568 state_val = gud_connector_tv_state_val(prop, &gconn->initial_tv_state);
569 if (WARN_ON(IS_ERR(state_val)))
573 drm_object_attach_property(&connector->base, property, 0);
581 int gud_connector_fill_properties(struct drm_connector_state *connector_state,
582 struct gud_property_req *properties)
584 struct gud_connector *gconn = to_gud_connector(connector_state->connector);
587 for (i = 0; i < gconn->num_properties; i++) {
588 u16 prop = gconn->properties[i];
591 if (prop == GUD_PROPERTY_BACKLIGHT_BRIGHTNESS) {
592 val = connector_state->tv.brightness;
594 unsigned int *state_val;
596 state_val = gud_connector_tv_state_val(prop, &connector_state->tv);
597 if (WARN_ON_ONCE(IS_ERR(state_val)))
598 return PTR_ERR(state_val);
603 properties[i].prop = cpu_to_le16(prop);
604 properties[i].val = cpu_to_le64(val);
607 return gconn->num_properties;
610 static int gud_connector_create(struct gud_device *gdrm, unsigned int index,
611 struct gud_connector_descriptor_req *desc)
613 struct drm_device *drm = &gdrm->drm;
614 struct gud_connector *gconn;
615 struct drm_connector *connector;
616 struct drm_encoder *encoder;
617 int ret, connector_type;
620 gconn = kzalloc(sizeof(*gconn), GFP_KERNEL);
624 INIT_WORK(&gconn->backlight_work, gud_connector_backlight_update_status_work);
625 gconn->initial_brightness = -ENODEV;
626 flags = le32_to_cpu(desc->flags);
627 connector = &gconn->connector;
629 drm_dbg(drm, "Connector: index=%u type=%u flags=0x%x\n", index, desc->connector_type, flags);
631 switch (desc->connector_type) {
632 case GUD_CONNECTOR_TYPE_PANEL:
633 connector_type = DRM_MODE_CONNECTOR_USB;
635 case GUD_CONNECTOR_TYPE_VGA:
636 connector_type = DRM_MODE_CONNECTOR_VGA;
638 case GUD_CONNECTOR_TYPE_DVI:
639 connector_type = DRM_MODE_CONNECTOR_DVID;
641 case GUD_CONNECTOR_TYPE_COMPOSITE:
642 connector_type = DRM_MODE_CONNECTOR_Composite;
644 case GUD_CONNECTOR_TYPE_SVIDEO:
645 connector_type = DRM_MODE_CONNECTOR_SVIDEO;
647 case GUD_CONNECTOR_TYPE_COMPONENT:
648 connector_type = DRM_MODE_CONNECTOR_Component;
650 case GUD_CONNECTOR_TYPE_DISPLAYPORT:
651 connector_type = DRM_MODE_CONNECTOR_DisplayPort;
653 case GUD_CONNECTOR_TYPE_HDMI:
654 connector_type = DRM_MODE_CONNECTOR_HDMIA;
656 default: /* future types */
657 connector_type = DRM_MODE_CONNECTOR_USB;
661 drm_connector_helper_add(connector, &gud_connector_helper_funcs);
662 ret = drm_connector_init(drm, connector, &gud_connector_funcs, connector_type);
668 if (WARN_ON(connector->index != index))
671 if (flags & GUD_CONNECTOR_FLAGS_POLL_STATUS)
672 connector->polled = (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT);
673 if (flags & GUD_CONNECTOR_FLAGS_INTERLACE)
674 connector->interlace_allowed = true;
675 if (flags & GUD_CONNECTOR_FLAGS_DOUBLESCAN)
676 connector->doublescan_allowed = true;
678 ret = gud_connector_add_properties(gdrm, gconn);
680 gud_conn_err(connector, "Failed to add properties", ret);
684 /* The first connector is attached to the existing simple pipe encoder */
685 if (!connector->index) {
686 encoder = &gdrm->pipe.encoder;
688 encoder = &gconn->encoder;
690 ret = drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
694 encoder->possible_crtcs = 1;
697 return drm_connector_attach_encoder(connector, encoder);
700 int gud_get_connectors(struct gud_device *gdrm)
702 struct gud_connector_descriptor_req *descs;
703 unsigned int i, num_connectors;
706 descs = kmalloc_array(GUD_CONNECTORS_MAX_NUM, sizeof(*descs), GFP_KERNEL);
710 ret = gud_usb_get(gdrm, GUD_REQ_GET_CONNECTORS, 0,
711 descs, GUD_CONNECTORS_MAX_NUM * sizeof(*descs));
714 if (!ret || ret % sizeof(*descs)) {
719 num_connectors = ret / sizeof(*descs);
721 for (i = 0; i < num_connectors; i++) {
722 ret = gud_connector_create(gdrm, i, &descs[i]);