1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2012 Red Hat
4 * based in parts on udlfb.c:
5 * Copyright (C) 2009 Roberto De Ioris <roberto@unbit.it>
6 * Copyright (C) 2009 Jaya Kumar <jayakumar.lkml@gmail.com>
7 * Copyright (C) 2009 Bernie Thompson <bernie@plugable.com>
10 #include <drm/drm_atomic_state_helper.h>
11 #include <drm/drm_crtc_helper.h>
12 #include <drm/drm_probe_helper.h>
14 #include "udl_connector.h"
17 static int udl_get_edid_block(void *data
, u8
*buf
, unsigned int block
,
22 struct udl_device
*udl
= data
;
23 struct usb_device
*udev
= udl_to_usb_device(udl
);
25 read_buff
= kmalloc(2, GFP_KERNEL
);
29 for (i
= 0; i
< len
; i
++) {
30 int bval
= (i
+ block
* EDID_LENGTH
) << 8;
31 ret
= usb_control_msg(udev
, usb_rcvctrlpipe(udev
, 0),
32 0x02, (0x80 | (0x02 << 5)), bval
,
33 0xA1, read_buff
, 2, HZ
);
35 DRM_ERROR("Read EDID byte %d failed err %x\n", i
, ret
);
39 buf
[i
] = read_buff
[1];
46 static int udl_get_modes(struct drm_connector
*connector
)
48 struct udl_drm_connector
*udl_connector
=
49 container_of(connector
,
50 struct udl_drm_connector
,
53 drm_connector_update_edid_property(connector
, udl_connector
->edid
);
54 if (udl_connector
->edid
)
55 return drm_add_edid_modes(connector
, udl_connector
->edid
);
59 static enum drm_mode_status
udl_mode_valid(struct drm_connector
*connector
,
60 struct drm_display_mode
*mode
)
62 struct udl_device
*udl
= to_udl(connector
->dev
);
63 if (!udl
->sku_pixel_limit
)
66 if (mode
->vdisplay
* mode
->hdisplay
> udl
->sku_pixel_limit
)
67 return MODE_VIRTUAL_Y
;
72 static enum drm_connector_status
73 udl_detect(struct drm_connector
*connector
, bool force
)
75 struct udl_device
*udl
= to_udl(connector
->dev
);
76 struct udl_drm_connector
*udl_connector
=
77 container_of(connector
,
78 struct udl_drm_connector
,
81 /* cleanup previous edid */
82 if (udl_connector
->edid
!= NULL
) {
83 kfree(udl_connector
->edid
);
84 udl_connector
->edid
= NULL
;
87 udl_connector
->edid
= drm_do_get_edid(connector
, udl_get_edid_block
, udl
);
88 if (!udl_connector
->edid
)
89 return connector_status_disconnected
;
91 return connector_status_connected
;
94 static void udl_connector_destroy(struct drm_connector
*connector
)
96 struct udl_drm_connector
*udl_connector
=
97 container_of(connector
,
98 struct udl_drm_connector
,
101 drm_connector_cleanup(connector
);
102 kfree(udl_connector
->edid
);
106 static const struct drm_connector_helper_funcs udl_connector_helper_funcs
= {
107 .get_modes
= udl_get_modes
,
108 .mode_valid
= udl_mode_valid
,
111 static const struct drm_connector_funcs udl_connector_funcs
= {
112 .reset
= drm_atomic_helper_connector_reset
,
113 .detect
= udl_detect
,
114 .fill_modes
= drm_helper_probe_single_connector_modes
,
115 .destroy
= udl_connector_destroy
,
116 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
117 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
120 struct drm_connector
*udl_connector_init(struct drm_device
*dev
)
122 struct udl_drm_connector
*udl_connector
;
123 struct drm_connector
*connector
;
125 udl_connector
= kzalloc(sizeof(struct udl_drm_connector
), GFP_KERNEL
);
127 return ERR_PTR(-ENOMEM
);
129 connector
= &udl_connector
->connector
;
130 drm_connector_init(dev
, connector
, &udl_connector_funcs
,
131 DRM_MODE_CONNECTOR_DVII
);
132 drm_connector_helper_add(connector
, &udl_connector_helper_funcs
);
134 connector
->polled
= DRM_CONNECTOR_POLL_HPD
|
135 DRM_CONNECTOR_POLL_CONNECT
| DRM_CONNECTOR_POLL_DISCONNECT
;