xref: /openbmc/linux/drivers/gpu/drm/gud/gud_drv.c (revision 40e1a70b)
1*40e1a70bSNoralf Trønnes // SPDX-License-Identifier: MIT
2*40e1a70bSNoralf Trønnes /*
3*40e1a70bSNoralf Trønnes  * Copyright 2020 Noralf Trønnes
4*40e1a70bSNoralf Trønnes  */
5*40e1a70bSNoralf Trønnes 
6*40e1a70bSNoralf Trønnes #include <linux/dma-buf.h>
7*40e1a70bSNoralf Trønnes #include <linux/dma-mapping.h>
8*40e1a70bSNoralf Trønnes #include <linux/lz4.h>
9*40e1a70bSNoralf Trønnes #include <linux/module.h>
10*40e1a70bSNoralf Trønnes #include <linux/platform_device.h>
11*40e1a70bSNoralf Trønnes #include <linux/string_helpers.h>
12*40e1a70bSNoralf Trønnes #include <linux/usb.h>
13*40e1a70bSNoralf Trønnes #include <linux/vmalloc.h>
14*40e1a70bSNoralf Trønnes #include <linux/workqueue.h>
15*40e1a70bSNoralf Trønnes 
16*40e1a70bSNoralf Trønnes #include <drm/drm_atomic_helper.h>
17*40e1a70bSNoralf Trønnes #include <drm/drm_damage_helper.h>
18*40e1a70bSNoralf Trønnes #include <drm/drm_debugfs.h>
19*40e1a70bSNoralf Trønnes #include <drm/drm_drv.h>
20*40e1a70bSNoralf Trønnes #include <drm/drm_fb_helper.h>
21*40e1a70bSNoralf Trønnes #include <drm/drm_fourcc.h>
22*40e1a70bSNoralf Trønnes #include <drm/drm_gem_atomic_helper.h>
23*40e1a70bSNoralf Trønnes #include <drm/drm_gem_framebuffer_helper.h>
24*40e1a70bSNoralf Trønnes #include <drm/drm_gem_shmem_helper.h>
25*40e1a70bSNoralf Trønnes #include <drm/drm_managed.h>
26*40e1a70bSNoralf Trønnes #include <drm/drm_print.h>
27*40e1a70bSNoralf Trønnes #include <drm/drm_probe_helper.h>
28*40e1a70bSNoralf Trønnes #include <drm/drm_simple_kms_helper.h>
29*40e1a70bSNoralf Trønnes #include <drm/gud.h>
30*40e1a70bSNoralf Trønnes 
31*40e1a70bSNoralf Trønnes #include "gud_internal.h"
32*40e1a70bSNoralf Trønnes 
33*40e1a70bSNoralf Trønnes /* Only used internally */
34*40e1a70bSNoralf Trønnes static const struct drm_format_info gud_drm_format_r1 = {
35*40e1a70bSNoralf Trønnes 	.format = GUD_DRM_FORMAT_R1,
36*40e1a70bSNoralf Trønnes 	.num_planes = 1,
37*40e1a70bSNoralf Trønnes 	.char_per_block = { 1, 0, 0 },
38*40e1a70bSNoralf Trønnes 	.block_w = { 8, 0, 0 },
39*40e1a70bSNoralf Trønnes 	.block_h = { 1, 0, 0 },
40*40e1a70bSNoralf Trønnes 	.hsub = 1,
41*40e1a70bSNoralf Trønnes 	.vsub = 1,
42*40e1a70bSNoralf Trønnes };
43*40e1a70bSNoralf Trønnes 
44*40e1a70bSNoralf Trønnes static const struct drm_format_info gud_drm_format_xrgb1111 = {
45*40e1a70bSNoralf Trønnes 	.format = GUD_DRM_FORMAT_XRGB1111,
46*40e1a70bSNoralf Trønnes 	.num_planes = 1,
47*40e1a70bSNoralf Trønnes 	.char_per_block = { 1, 0, 0 },
48*40e1a70bSNoralf Trønnes 	.block_w = { 2, 0, 0 },
49*40e1a70bSNoralf Trønnes 	.block_h = { 1, 0, 0 },
50*40e1a70bSNoralf Trønnes 	.hsub = 1,
51*40e1a70bSNoralf Trønnes 	.vsub = 1,
52*40e1a70bSNoralf Trønnes };
53*40e1a70bSNoralf Trønnes 
54*40e1a70bSNoralf Trønnes static int gud_usb_control_msg(struct usb_interface *intf, bool in,
55*40e1a70bSNoralf Trønnes 			       u8 request, u16 value, void *buf, size_t len)
56*40e1a70bSNoralf Trønnes {
57*40e1a70bSNoralf Trønnes 	u8 requesttype = USB_TYPE_VENDOR | USB_RECIP_INTERFACE;
58*40e1a70bSNoralf Trønnes 	u8 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
59*40e1a70bSNoralf Trønnes 	struct usb_device *usb = interface_to_usbdev(intf);
60*40e1a70bSNoralf Trønnes 	unsigned int pipe;
61*40e1a70bSNoralf Trønnes 
62*40e1a70bSNoralf Trønnes 	if (len && !buf)
63*40e1a70bSNoralf Trønnes 		return -EINVAL;
64*40e1a70bSNoralf Trønnes 
65*40e1a70bSNoralf Trønnes 	if (in) {
66*40e1a70bSNoralf Trønnes 		pipe = usb_rcvctrlpipe(usb, 0);
67*40e1a70bSNoralf Trønnes 		requesttype |= USB_DIR_IN;
68*40e1a70bSNoralf Trønnes 	} else {
69*40e1a70bSNoralf Trønnes 		pipe = usb_sndctrlpipe(usb, 0);
70*40e1a70bSNoralf Trønnes 		requesttype |= USB_DIR_OUT;
71*40e1a70bSNoralf Trønnes 	}
72*40e1a70bSNoralf Trønnes 
73*40e1a70bSNoralf Trønnes 	return usb_control_msg(usb, pipe, request, requesttype, value,
74*40e1a70bSNoralf Trønnes 			       ifnum, buf, len, USB_CTRL_GET_TIMEOUT);
75*40e1a70bSNoralf Trønnes }
76*40e1a70bSNoralf Trønnes 
77*40e1a70bSNoralf Trønnes static int gud_get_display_descriptor(struct usb_interface *intf,
78*40e1a70bSNoralf Trønnes 				      struct gud_display_descriptor_req *desc)
79*40e1a70bSNoralf Trønnes {
80*40e1a70bSNoralf Trønnes 	void *buf;
81*40e1a70bSNoralf Trønnes 	int ret;
82*40e1a70bSNoralf Trønnes 
83*40e1a70bSNoralf Trønnes 	buf = kmalloc(sizeof(*desc), GFP_KERNEL);
84*40e1a70bSNoralf Trønnes 	if (!buf)
85*40e1a70bSNoralf Trønnes 		return -ENOMEM;
86*40e1a70bSNoralf Trønnes 
87*40e1a70bSNoralf Trønnes 	ret = gud_usb_control_msg(intf, true, GUD_REQ_GET_DESCRIPTOR, 0, buf, sizeof(*desc));
88*40e1a70bSNoralf Trønnes 	memcpy(desc, buf, sizeof(*desc));
89*40e1a70bSNoralf Trønnes 	kfree(buf);
90*40e1a70bSNoralf Trønnes 	if (ret < 0)
91*40e1a70bSNoralf Trønnes 		return ret;
92*40e1a70bSNoralf Trønnes 	if (ret != sizeof(*desc))
93*40e1a70bSNoralf Trønnes 		return -EIO;
94*40e1a70bSNoralf Trønnes 
95*40e1a70bSNoralf Trønnes 	if (desc->magic != le32_to_cpu(GUD_DISPLAY_MAGIC))
96*40e1a70bSNoralf Trønnes 		return -ENODATA;
97*40e1a70bSNoralf Trønnes 
98*40e1a70bSNoralf Trønnes 	DRM_DEV_DEBUG_DRIVER(&intf->dev,
99*40e1a70bSNoralf Trønnes 			     "version=%u flags=0x%x compression=0x%x max_buffer_size=%u\n",
100*40e1a70bSNoralf Trønnes 			     desc->version, le32_to_cpu(desc->flags), desc->compression,
101*40e1a70bSNoralf Trønnes 			     le32_to_cpu(desc->max_buffer_size));
102*40e1a70bSNoralf Trønnes 
103*40e1a70bSNoralf Trønnes 	if (!desc->version || !desc->max_width || !desc->max_height ||
104*40e1a70bSNoralf Trønnes 	    le32_to_cpu(desc->min_width) > le32_to_cpu(desc->max_width) ||
105*40e1a70bSNoralf Trønnes 	    le32_to_cpu(desc->min_height) > le32_to_cpu(desc->max_height))
106*40e1a70bSNoralf Trønnes 		return -EINVAL;
107*40e1a70bSNoralf Trønnes 
108*40e1a70bSNoralf Trønnes 	return 0;
109*40e1a70bSNoralf Trønnes }
110*40e1a70bSNoralf Trønnes 
111*40e1a70bSNoralf Trønnes static int gud_status_to_errno(u8 status)
112*40e1a70bSNoralf Trønnes {
113*40e1a70bSNoralf Trønnes 	switch (status) {
114*40e1a70bSNoralf Trønnes 	case GUD_STATUS_OK:
115*40e1a70bSNoralf Trønnes 		return 0;
116*40e1a70bSNoralf Trønnes 	case GUD_STATUS_BUSY:
117*40e1a70bSNoralf Trønnes 		return -EBUSY;
118*40e1a70bSNoralf Trønnes 	case GUD_STATUS_REQUEST_NOT_SUPPORTED:
119*40e1a70bSNoralf Trønnes 		return -EOPNOTSUPP;
120*40e1a70bSNoralf Trønnes 	case GUD_STATUS_PROTOCOL_ERROR:
121*40e1a70bSNoralf Trønnes 		return -EPROTO;
122*40e1a70bSNoralf Trønnes 	case GUD_STATUS_INVALID_PARAMETER:
123*40e1a70bSNoralf Trønnes 		return -EINVAL;
124*40e1a70bSNoralf Trønnes 	case GUD_STATUS_ERROR:
125*40e1a70bSNoralf Trønnes 		return -EREMOTEIO;
126*40e1a70bSNoralf Trønnes 	default:
127*40e1a70bSNoralf Trønnes 		return -EREMOTEIO;
128*40e1a70bSNoralf Trønnes 	}
129*40e1a70bSNoralf Trønnes }
130*40e1a70bSNoralf Trønnes 
131*40e1a70bSNoralf Trønnes static int gud_usb_get_status(struct usb_interface *intf)
132*40e1a70bSNoralf Trønnes {
133*40e1a70bSNoralf Trønnes 	int ret, status = -EIO;
134*40e1a70bSNoralf Trønnes 	u8 *buf;
135*40e1a70bSNoralf Trønnes 
136*40e1a70bSNoralf Trønnes 	buf = kmalloc(sizeof(*buf), GFP_KERNEL);
137*40e1a70bSNoralf Trønnes 	if (!buf)
138*40e1a70bSNoralf Trønnes 		return -ENOMEM;
139*40e1a70bSNoralf Trønnes 
140*40e1a70bSNoralf Trønnes 	ret = gud_usb_control_msg(intf, true, GUD_REQ_GET_STATUS, 0, buf, sizeof(*buf));
141*40e1a70bSNoralf Trønnes 	if (ret == sizeof(*buf))
142*40e1a70bSNoralf Trønnes 		status = gud_status_to_errno(*buf);
143*40e1a70bSNoralf Trønnes 	kfree(buf);
144*40e1a70bSNoralf Trønnes 
145*40e1a70bSNoralf Trønnes 	if (ret < 0)
146*40e1a70bSNoralf Trønnes 		return ret;
147*40e1a70bSNoralf Trønnes 
148*40e1a70bSNoralf Trønnes 	return status;
149*40e1a70bSNoralf Trønnes }
150*40e1a70bSNoralf Trønnes 
151*40e1a70bSNoralf Trønnes static int gud_usb_transfer(struct gud_device *gdrm, bool in, u8 request, u16 index,
152*40e1a70bSNoralf Trønnes 			    void *buf, size_t len)
153*40e1a70bSNoralf Trønnes {
154*40e1a70bSNoralf Trønnes 	struct usb_interface *intf = to_usb_interface(gdrm->drm.dev);
155*40e1a70bSNoralf Trønnes 	int idx, ret;
156*40e1a70bSNoralf Trønnes 
157*40e1a70bSNoralf Trønnes 	drm_dbg(&gdrm->drm, "%s: request=0x%x index=%u len=%zu\n",
158*40e1a70bSNoralf Trønnes 		in ? "get" : "set", request, index, len);
159*40e1a70bSNoralf Trønnes 
160*40e1a70bSNoralf Trønnes 	if (!drm_dev_enter(&gdrm->drm, &idx))
161*40e1a70bSNoralf Trønnes 		return -ENODEV;
162*40e1a70bSNoralf Trønnes 
163*40e1a70bSNoralf Trønnes 	mutex_lock(&gdrm->ctrl_lock);
164*40e1a70bSNoralf Trønnes 
165*40e1a70bSNoralf Trønnes 	ret = gud_usb_control_msg(intf, in, request, index, buf, len);
166*40e1a70bSNoralf Trønnes 	if (ret == -EPIPE || ((gdrm->flags & GUD_DISPLAY_FLAG_STATUS_ON_SET) && !in && ret >= 0)) {
167*40e1a70bSNoralf Trønnes 		int status;
168*40e1a70bSNoralf Trønnes 
169*40e1a70bSNoralf Trønnes 		status = gud_usb_get_status(intf);
170*40e1a70bSNoralf Trønnes 		if (status < 0) {
171*40e1a70bSNoralf Trønnes 			ret = status;
172*40e1a70bSNoralf Trønnes 		} else if (ret < 0) {
173*40e1a70bSNoralf Trønnes 			dev_err_once(gdrm->drm.dev,
174*40e1a70bSNoralf Trønnes 				     "Unexpected status OK for failed transfer\n");
175*40e1a70bSNoralf Trønnes 			ret = -EPIPE;
176*40e1a70bSNoralf Trønnes 		}
177*40e1a70bSNoralf Trønnes 	}
178*40e1a70bSNoralf Trønnes 
179*40e1a70bSNoralf Trønnes 	if (ret < 0) {
180*40e1a70bSNoralf Trønnes 		drm_dbg(&gdrm->drm, "ret=%d\n", ret);
181*40e1a70bSNoralf Trønnes 		gdrm->stats_num_errors++;
182*40e1a70bSNoralf Trønnes 	}
183*40e1a70bSNoralf Trønnes 
184*40e1a70bSNoralf Trønnes 	mutex_unlock(&gdrm->ctrl_lock);
185*40e1a70bSNoralf Trønnes 	drm_dev_exit(idx);
186*40e1a70bSNoralf Trønnes 
187*40e1a70bSNoralf Trønnes 	return ret;
188*40e1a70bSNoralf Trønnes }
189*40e1a70bSNoralf Trønnes 
190*40e1a70bSNoralf Trønnes /*
191*40e1a70bSNoralf Trønnes  * @buf cannot be allocated on the stack.
192*40e1a70bSNoralf Trønnes  * Returns number of bytes received or negative error code on failure.
193*40e1a70bSNoralf Trønnes  */
194*40e1a70bSNoralf Trønnes int gud_usb_get(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t max_len)
195*40e1a70bSNoralf Trønnes {
196*40e1a70bSNoralf Trønnes 	return gud_usb_transfer(gdrm, true, request, index, buf, max_len);
197*40e1a70bSNoralf Trønnes }
198*40e1a70bSNoralf Trønnes 
199*40e1a70bSNoralf Trønnes /*
200*40e1a70bSNoralf Trønnes  * @buf can be allocated on the stack or NULL.
201*40e1a70bSNoralf Trønnes  * Returns zero on success or negative error code on failure.
202*40e1a70bSNoralf Trønnes  */
203*40e1a70bSNoralf Trønnes int gud_usb_set(struct gud_device *gdrm, u8 request, u16 index, void *buf, size_t len)
204*40e1a70bSNoralf Trønnes {
205*40e1a70bSNoralf Trønnes 	void *trbuf = NULL;
206*40e1a70bSNoralf Trønnes 	int ret;
207*40e1a70bSNoralf Trønnes 
208*40e1a70bSNoralf Trønnes 	if (buf && len) {
209*40e1a70bSNoralf Trønnes 		trbuf = kmemdup(buf, len, GFP_KERNEL);
210*40e1a70bSNoralf Trønnes 		if (!trbuf)
211*40e1a70bSNoralf Trønnes 			return -ENOMEM;
212*40e1a70bSNoralf Trønnes 	}
213*40e1a70bSNoralf Trønnes 
214*40e1a70bSNoralf Trønnes 	ret = gud_usb_transfer(gdrm, false, request, index, trbuf, len);
215*40e1a70bSNoralf Trønnes 	kfree(trbuf);
216*40e1a70bSNoralf Trønnes 	if (ret < 0)
217*40e1a70bSNoralf Trønnes 		return ret;
218*40e1a70bSNoralf Trønnes 
219*40e1a70bSNoralf Trønnes 	return ret != len ? -EIO : 0;
220*40e1a70bSNoralf Trønnes }
221*40e1a70bSNoralf Trønnes 
222*40e1a70bSNoralf Trønnes /*
223*40e1a70bSNoralf Trønnes  * @val can be allocated on the stack.
224*40e1a70bSNoralf Trønnes  * Returns zero on success or negative error code on failure.
225*40e1a70bSNoralf Trønnes  */
226*40e1a70bSNoralf Trønnes int gud_usb_get_u8(struct gud_device *gdrm, u8 request, u16 index, u8 *val)
227*40e1a70bSNoralf Trønnes {
228*40e1a70bSNoralf Trønnes 	u8 *buf;
229*40e1a70bSNoralf Trønnes 	int ret;
230*40e1a70bSNoralf Trønnes 
231*40e1a70bSNoralf Trønnes 	buf = kmalloc(sizeof(*val), GFP_KERNEL);
232*40e1a70bSNoralf Trønnes 	if (!buf)
233*40e1a70bSNoralf Trønnes 		return -ENOMEM;
234*40e1a70bSNoralf Trønnes 
235*40e1a70bSNoralf Trønnes 	ret = gud_usb_get(gdrm, request, index, buf, sizeof(*val));
236*40e1a70bSNoralf Trønnes 	*val = *buf;
237*40e1a70bSNoralf Trønnes 	kfree(buf);
238*40e1a70bSNoralf Trønnes 	if (ret < 0)
239*40e1a70bSNoralf Trønnes 		return ret;
240*40e1a70bSNoralf Trønnes 
241*40e1a70bSNoralf Trønnes 	return ret != sizeof(*val) ? -EIO : 0;
242*40e1a70bSNoralf Trønnes }
243*40e1a70bSNoralf Trønnes 
244*40e1a70bSNoralf Trønnes /* Returns zero on success or negative error code on failure. */
245*40e1a70bSNoralf Trønnes int gud_usb_set_u8(struct gud_device *gdrm, u8 request, u8 val)
246*40e1a70bSNoralf Trønnes {
247*40e1a70bSNoralf Trønnes 	return gud_usb_set(gdrm, request, 0, &val, sizeof(val));
248*40e1a70bSNoralf Trønnes }
249*40e1a70bSNoralf Trønnes 
250*40e1a70bSNoralf Trønnes static int gud_get_properties(struct gud_device *gdrm)
251*40e1a70bSNoralf Trønnes {
252*40e1a70bSNoralf Trønnes 	struct gud_property_req *properties;
253*40e1a70bSNoralf Trønnes 	unsigned int i, num_properties;
254*40e1a70bSNoralf Trønnes 	int ret;
255*40e1a70bSNoralf Trønnes 
256*40e1a70bSNoralf Trønnes 	properties = kcalloc(GUD_PROPERTIES_MAX_NUM, sizeof(*properties), GFP_KERNEL);
257*40e1a70bSNoralf Trønnes 	if (!properties)
258*40e1a70bSNoralf Trønnes 		return -ENOMEM;
259*40e1a70bSNoralf Trønnes 
260*40e1a70bSNoralf Trønnes 	ret = gud_usb_get(gdrm, GUD_REQ_GET_PROPERTIES, 0,
261*40e1a70bSNoralf Trønnes 			  properties, GUD_PROPERTIES_MAX_NUM * sizeof(*properties));
262*40e1a70bSNoralf Trønnes 	if (ret <= 0)
263*40e1a70bSNoralf Trønnes 		goto out;
264*40e1a70bSNoralf Trønnes 	if (ret % sizeof(*properties)) {
265*40e1a70bSNoralf Trønnes 		ret = -EIO;
266*40e1a70bSNoralf Trønnes 		goto out;
267*40e1a70bSNoralf Trønnes 	}
268*40e1a70bSNoralf Trønnes 
269*40e1a70bSNoralf Trønnes 	num_properties = ret / sizeof(*properties);
270*40e1a70bSNoralf Trønnes 	ret = 0;
271*40e1a70bSNoralf Trønnes 
272*40e1a70bSNoralf Trønnes 	gdrm->properties = drmm_kcalloc(&gdrm->drm, num_properties, sizeof(*gdrm->properties),
273*40e1a70bSNoralf Trønnes 					GFP_KERNEL);
274*40e1a70bSNoralf Trønnes 	if (!gdrm->properties) {
275*40e1a70bSNoralf Trønnes 		ret = -ENOMEM;
276*40e1a70bSNoralf Trønnes 		goto out;
277*40e1a70bSNoralf Trønnes 	}
278*40e1a70bSNoralf Trønnes 
279*40e1a70bSNoralf Trønnes 	for (i = 0; i < num_properties; i++) {
280*40e1a70bSNoralf Trønnes 		u16 prop = le16_to_cpu(properties[i].prop);
281*40e1a70bSNoralf Trønnes 		u64 val = le64_to_cpu(properties[i].val);
282*40e1a70bSNoralf Trønnes 
283*40e1a70bSNoralf Trønnes 		switch (prop) {
284*40e1a70bSNoralf Trønnes 		case GUD_PROPERTY_ROTATION:
285*40e1a70bSNoralf Trønnes 			/*
286*40e1a70bSNoralf Trønnes 			 * DRM UAPI matches the protocol so use the value directly,
287*40e1a70bSNoralf Trønnes 			 * but mask out any additions on future devices.
288*40e1a70bSNoralf Trønnes 			 */
289*40e1a70bSNoralf Trønnes 			val &= GUD_ROTATION_MASK;
290*40e1a70bSNoralf Trønnes 			ret = drm_plane_create_rotation_property(&gdrm->pipe.plane,
291*40e1a70bSNoralf Trønnes 								 DRM_MODE_ROTATE_0, val);
292*40e1a70bSNoralf Trønnes 			break;
293*40e1a70bSNoralf Trønnes 		default:
294*40e1a70bSNoralf Trønnes 			/* New ones might show up in future devices, skip those we don't know. */
295*40e1a70bSNoralf Trønnes 			drm_dbg(&gdrm->drm, "Ignoring unknown property: %u\n", prop);
296*40e1a70bSNoralf Trønnes 			continue;
297*40e1a70bSNoralf Trønnes 		}
298*40e1a70bSNoralf Trønnes 
299*40e1a70bSNoralf Trønnes 		if (ret)
300*40e1a70bSNoralf Trønnes 			goto out;
301*40e1a70bSNoralf Trønnes 
302*40e1a70bSNoralf Trønnes 		gdrm->properties[gdrm->num_properties++] = prop;
303*40e1a70bSNoralf Trønnes 	}
304*40e1a70bSNoralf Trønnes out:
305*40e1a70bSNoralf Trønnes 	kfree(properties);
306*40e1a70bSNoralf Trønnes 
307*40e1a70bSNoralf Trønnes 	return ret;
308*40e1a70bSNoralf Trønnes }
309*40e1a70bSNoralf Trønnes 
310*40e1a70bSNoralf Trønnes /*
311*40e1a70bSNoralf Trønnes  * FIXME: Dma-buf sharing requires DMA support by the importing device.
312*40e1a70bSNoralf Trønnes  *        This function is a workaround to make USB devices work as well.
313*40e1a70bSNoralf Trønnes  *        See todo.rst for how to fix the issue in the dma-buf framework.
314*40e1a70bSNoralf Trønnes  */
315*40e1a70bSNoralf Trønnes static struct drm_gem_object *gud_gem_prime_import(struct drm_device *drm, struct dma_buf *dma_buf)
316*40e1a70bSNoralf Trønnes {
317*40e1a70bSNoralf Trønnes 	struct gud_device *gdrm = to_gud_device(drm);
318*40e1a70bSNoralf Trønnes 
319*40e1a70bSNoralf Trønnes 	if (!gdrm->dmadev)
320*40e1a70bSNoralf Trønnes 		return ERR_PTR(-ENODEV);
321*40e1a70bSNoralf Trønnes 
322*40e1a70bSNoralf Trønnes 	return drm_gem_prime_import_dev(drm, dma_buf, gdrm->dmadev);
323*40e1a70bSNoralf Trønnes }
324*40e1a70bSNoralf Trønnes 
325*40e1a70bSNoralf Trønnes static int gud_stats_debugfs(struct seq_file *m, void *data)
326*40e1a70bSNoralf Trønnes {
327*40e1a70bSNoralf Trønnes 	struct drm_info_node *node = m->private;
328*40e1a70bSNoralf Trønnes 	struct gud_device *gdrm = to_gud_device(node->minor->dev);
329*40e1a70bSNoralf Trønnes 	char buf[10];
330*40e1a70bSNoralf Trønnes 
331*40e1a70bSNoralf Trønnes 	string_get_size(gdrm->bulk_len, 1, STRING_UNITS_2, buf, sizeof(buf));
332*40e1a70bSNoralf Trønnes 	seq_printf(m, "Max buffer size: %s\n", buf);
333*40e1a70bSNoralf Trønnes 	seq_printf(m, "Number of errors:  %u\n", gdrm->stats_num_errors);
334*40e1a70bSNoralf Trønnes 
335*40e1a70bSNoralf Trønnes 	seq_puts(m, "Compression:      ");
336*40e1a70bSNoralf Trønnes 	if (gdrm->compression & GUD_COMPRESSION_LZ4)
337*40e1a70bSNoralf Trønnes 		seq_puts(m, " lz4");
338*40e1a70bSNoralf Trønnes 	if (!gdrm->compression)
339*40e1a70bSNoralf Trønnes 		seq_puts(m, " none");
340*40e1a70bSNoralf Trønnes 	seq_puts(m, "\n");
341*40e1a70bSNoralf Trønnes 
342*40e1a70bSNoralf Trønnes 	if (gdrm->compression) {
343*40e1a70bSNoralf Trønnes 		u64 remainder;
344*40e1a70bSNoralf Trønnes 		u64 ratio = div64_u64_rem(gdrm->stats_length, gdrm->stats_actual_length,
345*40e1a70bSNoralf Trønnes 					  &remainder);
346*40e1a70bSNoralf Trønnes 		u64 ratio_frac = div64_u64(remainder * 10, gdrm->stats_actual_length);
347*40e1a70bSNoralf Trønnes 
348*40e1a70bSNoralf Trønnes 		seq_printf(m, "Compression ratio: %llu.%llu\n", ratio, ratio_frac);
349*40e1a70bSNoralf Trønnes 	}
350*40e1a70bSNoralf Trønnes 
351*40e1a70bSNoralf Trønnes 	return 0;
352*40e1a70bSNoralf Trønnes }
353*40e1a70bSNoralf Trønnes 
354*40e1a70bSNoralf Trønnes static const struct drm_info_list gud_debugfs_list[] = {
355*40e1a70bSNoralf Trønnes 	{ "stats", gud_stats_debugfs, 0, NULL },
356*40e1a70bSNoralf Trønnes };
357*40e1a70bSNoralf Trønnes 
358*40e1a70bSNoralf Trønnes static void gud_debugfs_init(struct drm_minor *minor)
359*40e1a70bSNoralf Trønnes {
360*40e1a70bSNoralf Trønnes 	drm_debugfs_create_files(gud_debugfs_list, ARRAY_SIZE(gud_debugfs_list),
361*40e1a70bSNoralf Trønnes 				 minor->debugfs_root, minor);
362*40e1a70bSNoralf Trønnes }
363*40e1a70bSNoralf Trønnes 
364*40e1a70bSNoralf Trønnes static const struct drm_simple_display_pipe_funcs gud_pipe_funcs = {
365*40e1a70bSNoralf Trønnes 	.check      = gud_pipe_check,
366*40e1a70bSNoralf Trønnes 	.update	    = gud_pipe_update,
367*40e1a70bSNoralf Trønnes 	.prepare_fb = drm_gem_simple_display_pipe_prepare_fb,
368*40e1a70bSNoralf Trønnes };
369*40e1a70bSNoralf Trønnes 
370*40e1a70bSNoralf Trønnes static const struct drm_mode_config_funcs gud_mode_config_funcs = {
371*40e1a70bSNoralf Trønnes 	.fb_create = drm_gem_fb_create_with_dirty,
372*40e1a70bSNoralf Trønnes 	.atomic_check = drm_atomic_helper_check,
373*40e1a70bSNoralf Trønnes 	.atomic_commit = drm_atomic_helper_commit,
374*40e1a70bSNoralf Trønnes };
375*40e1a70bSNoralf Trønnes 
376*40e1a70bSNoralf Trønnes static const u64 gud_pipe_modifiers[] = {
377*40e1a70bSNoralf Trønnes 	DRM_FORMAT_MOD_LINEAR,
378*40e1a70bSNoralf Trønnes 	DRM_FORMAT_MOD_INVALID
379*40e1a70bSNoralf Trønnes };
380*40e1a70bSNoralf Trønnes 
381*40e1a70bSNoralf Trønnes DEFINE_DRM_GEM_FOPS(gud_fops);
382*40e1a70bSNoralf Trønnes 
383*40e1a70bSNoralf Trønnes static const struct drm_driver gud_drm_driver = {
384*40e1a70bSNoralf Trønnes 	.driver_features	= DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
385*40e1a70bSNoralf Trønnes 	.fops			= &gud_fops,
386*40e1a70bSNoralf Trønnes 	DRM_GEM_SHMEM_DRIVER_OPS,
387*40e1a70bSNoralf Trønnes 	.gem_prime_import	= gud_gem_prime_import,
388*40e1a70bSNoralf Trønnes 	.debugfs_init		= gud_debugfs_init,
389*40e1a70bSNoralf Trønnes 
390*40e1a70bSNoralf Trønnes 	.name			= "gud",
391*40e1a70bSNoralf Trønnes 	.desc			= "Generic USB Display",
392*40e1a70bSNoralf Trønnes 	.date			= "20200422",
393*40e1a70bSNoralf Trønnes 	.major			= 1,
394*40e1a70bSNoralf Trønnes 	.minor			= 0,
395*40e1a70bSNoralf Trønnes };
396*40e1a70bSNoralf Trønnes 
397*40e1a70bSNoralf Trønnes static void gud_free_buffers_and_mutex(struct drm_device *drm, void *unused)
398*40e1a70bSNoralf Trønnes {
399*40e1a70bSNoralf Trønnes 	struct gud_device *gdrm = to_gud_device(drm);
400*40e1a70bSNoralf Trønnes 
401*40e1a70bSNoralf Trønnes 	vfree(gdrm->compress_buf);
402*40e1a70bSNoralf Trønnes 	kfree(gdrm->bulk_buf);
403*40e1a70bSNoralf Trønnes 	mutex_destroy(&gdrm->ctrl_lock);
404*40e1a70bSNoralf Trønnes 	mutex_destroy(&gdrm->damage_lock);
405*40e1a70bSNoralf Trønnes }
406*40e1a70bSNoralf Trønnes 
407*40e1a70bSNoralf Trønnes static int gud_probe(struct usb_interface *intf, const struct usb_device_id *id)
408*40e1a70bSNoralf Trønnes {
409*40e1a70bSNoralf Trønnes 	const struct drm_format_info *xrgb8888_emulation_format = NULL;
410*40e1a70bSNoralf Trønnes 	bool rgb565_supported = false, xrgb8888_supported = false;
411*40e1a70bSNoralf Trønnes 	unsigned int num_formats_dev, num_formats = 0;
412*40e1a70bSNoralf Trønnes 	struct usb_endpoint_descriptor *bulk_out;
413*40e1a70bSNoralf Trønnes 	struct gud_display_descriptor_req desc;
414*40e1a70bSNoralf Trønnes 	struct device *dev = &intf->dev;
415*40e1a70bSNoralf Trønnes 	size_t max_buffer_size = 0;
416*40e1a70bSNoralf Trønnes 	struct gud_device *gdrm;
417*40e1a70bSNoralf Trønnes 	struct drm_device *drm;
418*40e1a70bSNoralf Trønnes 	u8 *formats_dev;
419*40e1a70bSNoralf Trønnes 	u32 *formats;
420*40e1a70bSNoralf Trønnes 	int ret, i;
421*40e1a70bSNoralf Trønnes 
422*40e1a70bSNoralf Trønnes 	ret = usb_find_bulk_out_endpoint(intf->cur_altsetting, &bulk_out);
423*40e1a70bSNoralf Trønnes 	if (ret)
424*40e1a70bSNoralf Trønnes 		return ret;
425*40e1a70bSNoralf Trønnes 
426*40e1a70bSNoralf Trønnes 	ret = gud_get_display_descriptor(intf, &desc);
427*40e1a70bSNoralf Trønnes 	if (ret) {
428*40e1a70bSNoralf Trønnes 		DRM_DEV_DEBUG_DRIVER(dev, "Not a display interface: ret=%d\n", ret);
429*40e1a70bSNoralf Trønnes 		return -ENODEV;
430*40e1a70bSNoralf Trønnes 	}
431*40e1a70bSNoralf Trønnes 
432*40e1a70bSNoralf Trønnes 	if (desc.version > 1) {
433*40e1a70bSNoralf Trønnes 		dev_err(dev, "Protocol version %u is not supported\n", desc.version);
434*40e1a70bSNoralf Trønnes 		return -ENODEV;
435*40e1a70bSNoralf Trønnes 	}
436*40e1a70bSNoralf Trønnes 
437*40e1a70bSNoralf Trønnes 	gdrm = devm_drm_dev_alloc(dev, &gud_drm_driver, struct gud_device, drm);
438*40e1a70bSNoralf Trønnes 	if (IS_ERR(gdrm))
439*40e1a70bSNoralf Trønnes 		return PTR_ERR(gdrm);
440*40e1a70bSNoralf Trønnes 
441*40e1a70bSNoralf Trønnes 	drm = &gdrm->drm;
442*40e1a70bSNoralf Trønnes 	drm->mode_config.funcs = &gud_mode_config_funcs;
443*40e1a70bSNoralf Trønnes 	ret = drmm_mode_config_init(drm);
444*40e1a70bSNoralf Trønnes 	if (ret)
445*40e1a70bSNoralf Trønnes 		return ret;
446*40e1a70bSNoralf Trønnes 
447*40e1a70bSNoralf Trønnes 	gdrm->flags = le32_to_cpu(desc.flags);
448*40e1a70bSNoralf Trønnes 	gdrm->compression = desc.compression & GUD_COMPRESSION_LZ4;
449*40e1a70bSNoralf Trønnes 
450*40e1a70bSNoralf Trønnes 	if (gdrm->flags & GUD_DISPLAY_FLAG_FULL_UPDATE && gdrm->compression)
451*40e1a70bSNoralf Trønnes 		return -EINVAL;
452*40e1a70bSNoralf Trønnes 
453*40e1a70bSNoralf Trønnes 	mutex_init(&gdrm->ctrl_lock);
454*40e1a70bSNoralf Trønnes 	mutex_init(&gdrm->damage_lock);
455*40e1a70bSNoralf Trønnes 	INIT_WORK(&gdrm->work, gud_flush_work);
456*40e1a70bSNoralf Trønnes 	gud_clear_damage(gdrm);
457*40e1a70bSNoralf Trønnes 
458*40e1a70bSNoralf Trønnes 	ret = drmm_add_action_or_reset(drm, gud_free_buffers_and_mutex, NULL);
459*40e1a70bSNoralf Trønnes 	if (ret)
460*40e1a70bSNoralf Trønnes 		return ret;
461*40e1a70bSNoralf Trønnes 
462*40e1a70bSNoralf Trønnes 	drm->mode_config.min_width = le32_to_cpu(desc.min_width);
463*40e1a70bSNoralf Trønnes 	drm->mode_config.max_width = le32_to_cpu(desc.max_width);
464*40e1a70bSNoralf Trønnes 	drm->mode_config.min_height = le32_to_cpu(desc.min_height);
465*40e1a70bSNoralf Trønnes 	drm->mode_config.max_height = le32_to_cpu(desc.max_height);
466*40e1a70bSNoralf Trønnes 
467*40e1a70bSNoralf Trønnes 	formats_dev = devm_kmalloc(dev, GUD_FORMATS_MAX_NUM, GFP_KERNEL);
468*40e1a70bSNoralf Trønnes 	/* Add room for emulated XRGB8888 */
469*40e1a70bSNoralf Trønnes 	formats = devm_kmalloc_array(dev, GUD_FORMATS_MAX_NUM + 1, sizeof(*formats), GFP_KERNEL);
470*40e1a70bSNoralf Trønnes 	if (!formats_dev || !formats)
471*40e1a70bSNoralf Trønnes 		return -ENOMEM;
472*40e1a70bSNoralf Trønnes 
473*40e1a70bSNoralf Trønnes 	ret = gud_usb_get(gdrm, GUD_REQ_GET_FORMATS, 0, formats_dev, GUD_FORMATS_MAX_NUM);
474*40e1a70bSNoralf Trønnes 	if (ret < 0)
475*40e1a70bSNoralf Trønnes 		return ret;
476*40e1a70bSNoralf Trønnes 
477*40e1a70bSNoralf Trønnes 	num_formats_dev = ret;
478*40e1a70bSNoralf Trønnes 	for (i = 0; i < num_formats_dev; i++) {
479*40e1a70bSNoralf Trønnes 		const struct drm_format_info *info;
480*40e1a70bSNoralf Trønnes 		size_t fmt_buf_size;
481*40e1a70bSNoralf Trønnes 		u32 format;
482*40e1a70bSNoralf Trønnes 
483*40e1a70bSNoralf Trønnes 		format = gud_to_fourcc(formats_dev[i]);
484*40e1a70bSNoralf Trønnes 		if (!format) {
485*40e1a70bSNoralf Trønnes 			drm_dbg(drm, "Unsupported format: 0x%02x\n", formats_dev[i]);
486*40e1a70bSNoralf Trønnes 			continue;
487*40e1a70bSNoralf Trønnes 		}
488*40e1a70bSNoralf Trønnes 
489*40e1a70bSNoralf Trønnes 		if (format == GUD_DRM_FORMAT_R1)
490*40e1a70bSNoralf Trønnes 			info = &gud_drm_format_r1;
491*40e1a70bSNoralf Trønnes 		else if (format == GUD_DRM_FORMAT_XRGB1111)
492*40e1a70bSNoralf Trønnes 			info = &gud_drm_format_xrgb1111;
493*40e1a70bSNoralf Trønnes 		else
494*40e1a70bSNoralf Trønnes 			info = drm_format_info(format);
495*40e1a70bSNoralf Trønnes 
496*40e1a70bSNoralf Trønnes 		switch (format) {
497*40e1a70bSNoralf Trønnes 		case GUD_DRM_FORMAT_R1:
498*40e1a70bSNoralf Trønnes 			fallthrough;
499*40e1a70bSNoralf Trønnes 		case GUD_DRM_FORMAT_XRGB1111:
500*40e1a70bSNoralf Trønnes 			if (!xrgb8888_emulation_format)
501*40e1a70bSNoralf Trønnes 				xrgb8888_emulation_format = info;
502*40e1a70bSNoralf Trønnes 			break;
503*40e1a70bSNoralf Trønnes 		case DRM_FORMAT_RGB565:
504*40e1a70bSNoralf Trønnes 			rgb565_supported = true;
505*40e1a70bSNoralf Trønnes 			if (!xrgb8888_emulation_format)
506*40e1a70bSNoralf Trønnes 				xrgb8888_emulation_format = info;
507*40e1a70bSNoralf Trønnes 			break;
508*40e1a70bSNoralf Trønnes 		case DRM_FORMAT_XRGB8888:
509*40e1a70bSNoralf Trønnes 			xrgb8888_supported = true;
510*40e1a70bSNoralf Trønnes 			break;
511*40e1a70bSNoralf Trønnes 		};
512*40e1a70bSNoralf Trønnes 
513*40e1a70bSNoralf Trønnes 		fmt_buf_size = drm_format_info_min_pitch(info, 0, drm->mode_config.max_width) *
514*40e1a70bSNoralf Trønnes 			       drm->mode_config.max_height;
515*40e1a70bSNoralf Trønnes 		max_buffer_size = max(max_buffer_size, fmt_buf_size);
516*40e1a70bSNoralf Trønnes 
517*40e1a70bSNoralf Trønnes 		if (format == GUD_DRM_FORMAT_R1 || format == GUD_DRM_FORMAT_XRGB1111)
518*40e1a70bSNoralf Trønnes 			continue; /* Internal not for userspace */
519*40e1a70bSNoralf Trønnes 
520*40e1a70bSNoralf Trønnes 		formats[num_formats++] = format;
521*40e1a70bSNoralf Trønnes 	}
522*40e1a70bSNoralf Trønnes 
523*40e1a70bSNoralf Trønnes 	if (!num_formats && !xrgb8888_emulation_format) {
524*40e1a70bSNoralf Trønnes 		dev_err(dev, "No supported pixel formats found\n");
525*40e1a70bSNoralf Trønnes 		return -EINVAL;
526*40e1a70bSNoralf Trønnes 	}
527*40e1a70bSNoralf Trønnes 
528*40e1a70bSNoralf Trønnes 	/* Prefer speed over color depth */
529*40e1a70bSNoralf Trønnes 	if (rgb565_supported)
530*40e1a70bSNoralf Trønnes 		drm->mode_config.preferred_depth = 16;
531*40e1a70bSNoralf Trønnes 
532*40e1a70bSNoralf Trønnes 	if (!xrgb8888_supported && xrgb8888_emulation_format) {
533*40e1a70bSNoralf Trønnes 		gdrm->xrgb8888_emulation_format = xrgb8888_emulation_format;
534*40e1a70bSNoralf Trønnes 		formats[num_formats++] = DRM_FORMAT_XRGB8888;
535*40e1a70bSNoralf Trønnes 	}
536*40e1a70bSNoralf Trønnes 
537*40e1a70bSNoralf Trønnes 	if (desc.max_buffer_size)
538*40e1a70bSNoralf Trønnes 		max_buffer_size = le32_to_cpu(desc.max_buffer_size);
539*40e1a70bSNoralf Trønnes retry:
540*40e1a70bSNoralf Trønnes 	/*
541*40e1a70bSNoralf Trønnes 	 * Use plain kmalloc here since devm_kmalloc() places struct devres at the beginning
542*40e1a70bSNoralf Trønnes 	 * of the buffer it allocates. This wastes a lot of memory when allocating big buffers.
543*40e1a70bSNoralf Trønnes 	 * Asking for 2M would actually allocate 4M. This would also prevent getting the biggest
544*40e1a70bSNoralf Trønnes 	 * possible buffer potentially leading to split transfers.
545*40e1a70bSNoralf Trønnes 	 */
546*40e1a70bSNoralf Trønnes 	gdrm->bulk_buf = kmalloc(max_buffer_size, GFP_KERNEL | __GFP_NOWARN);
547*40e1a70bSNoralf Trønnes 	if (!gdrm->bulk_buf) {
548*40e1a70bSNoralf Trønnes 		max_buffer_size = roundup_pow_of_two(max_buffer_size) / 2;
549*40e1a70bSNoralf Trønnes 		if (max_buffer_size < SZ_512K)
550*40e1a70bSNoralf Trønnes 			return -ENOMEM;
551*40e1a70bSNoralf Trønnes 		goto retry;
552*40e1a70bSNoralf Trønnes 	}
553*40e1a70bSNoralf Trønnes 
554*40e1a70bSNoralf Trønnes 	gdrm->bulk_pipe = usb_sndbulkpipe(interface_to_usbdev(intf), usb_endpoint_num(bulk_out));
555*40e1a70bSNoralf Trønnes 	gdrm->bulk_len = max_buffer_size;
556*40e1a70bSNoralf Trønnes 
557*40e1a70bSNoralf Trønnes 	if (gdrm->compression & GUD_COMPRESSION_LZ4) {
558*40e1a70bSNoralf Trønnes 		gdrm->lz4_comp_mem = devm_kmalloc(dev, LZ4_MEM_COMPRESS, GFP_KERNEL);
559*40e1a70bSNoralf Trønnes 		if (!gdrm->lz4_comp_mem)
560*40e1a70bSNoralf Trønnes 			return -ENOMEM;
561*40e1a70bSNoralf Trønnes 
562*40e1a70bSNoralf Trønnes 		gdrm->compress_buf = vmalloc(gdrm->bulk_len);
563*40e1a70bSNoralf Trønnes 		if (!gdrm->compress_buf)
564*40e1a70bSNoralf Trønnes 			return -ENOMEM;
565*40e1a70bSNoralf Trønnes 	}
566*40e1a70bSNoralf Trønnes 
567*40e1a70bSNoralf Trønnes 	ret = drm_simple_display_pipe_init(drm, &gdrm->pipe, &gud_pipe_funcs,
568*40e1a70bSNoralf Trønnes 					   formats, num_formats,
569*40e1a70bSNoralf Trønnes 					   gud_pipe_modifiers, NULL);
570*40e1a70bSNoralf Trønnes 	if (ret)
571*40e1a70bSNoralf Trønnes 		return ret;
572*40e1a70bSNoralf Trønnes 
573*40e1a70bSNoralf Trønnes 	devm_kfree(dev, formats);
574*40e1a70bSNoralf Trønnes 	devm_kfree(dev, formats_dev);
575*40e1a70bSNoralf Trønnes 
576*40e1a70bSNoralf Trønnes 	ret = gud_get_properties(gdrm);
577*40e1a70bSNoralf Trønnes 	if (ret) {
578*40e1a70bSNoralf Trønnes 		dev_err(dev, "Failed to get properties (error=%d)\n", ret);
579*40e1a70bSNoralf Trønnes 		return ret;
580*40e1a70bSNoralf Trønnes 	}
581*40e1a70bSNoralf Trønnes 
582*40e1a70bSNoralf Trønnes 	drm_plane_enable_fb_damage_clips(&gdrm->pipe.plane);
583*40e1a70bSNoralf Trønnes 
584*40e1a70bSNoralf Trønnes 	ret = gud_get_connectors(gdrm);
585*40e1a70bSNoralf Trønnes 	if (ret) {
586*40e1a70bSNoralf Trønnes 		dev_err(dev, "Failed to get connectors (error=%d)\n", ret);
587*40e1a70bSNoralf Trønnes 		return ret;
588*40e1a70bSNoralf Trønnes 	}
589*40e1a70bSNoralf Trønnes 
590*40e1a70bSNoralf Trønnes 	drm_mode_config_reset(drm);
591*40e1a70bSNoralf Trønnes 
592*40e1a70bSNoralf Trønnes 	usb_set_intfdata(intf, gdrm);
593*40e1a70bSNoralf Trønnes 
594*40e1a70bSNoralf Trønnes 	gdrm->dmadev = usb_intf_get_dma_device(intf);
595*40e1a70bSNoralf Trønnes 	if (!gdrm->dmadev)
596*40e1a70bSNoralf Trønnes 		dev_warn(dev, "buffer sharing not supported");
597*40e1a70bSNoralf Trønnes 
598*40e1a70bSNoralf Trønnes 	ret = drm_dev_register(drm, 0);
599*40e1a70bSNoralf Trønnes 	if (ret) {
600*40e1a70bSNoralf Trønnes 		put_device(gdrm->dmadev);
601*40e1a70bSNoralf Trønnes 		return ret;
602*40e1a70bSNoralf Trønnes 	}
603*40e1a70bSNoralf Trønnes 
604*40e1a70bSNoralf Trønnes 	drm_kms_helper_poll_init(drm);
605*40e1a70bSNoralf Trønnes 
606*40e1a70bSNoralf Trønnes 	drm_fbdev_generic_setup(drm, 0);
607*40e1a70bSNoralf Trønnes 
608*40e1a70bSNoralf Trønnes 	return 0;
609*40e1a70bSNoralf Trønnes }
610*40e1a70bSNoralf Trønnes 
611*40e1a70bSNoralf Trønnes static void gud_disconnect(struct usb_interface *interface)
612*40e1a70bSNoralf Trønnes {
613*40e1a70bSNoralf Trønnes 	struct gud_device *gdrm = usb_get_intfdata(interface);
614*40e1a70bSNoralf Trønnes 	struct drm_device *drm = &gdrm->drm;
615*40e1a70bSNoralf Trønnes 
616*40e1a70bSNoralf Trønnes 	drm_dbg(drm, "%s:\n", __func__);
617*40e1a70bSNoralf Trønnes 
618*40e1a70bSNoralf Trønnes 	drm_kms_helper_poll_fini(drm);
619*40e1a70bSNoralf Trønnes 	drm_dev_unplug(drm);
620*40e1a70bSNoralf Trønnes 	drm_atomic_helper_shutdown(drm);
621*40e1a70bSNoralf Trønnes 	put_device(gdrm->dmadev);
622*40e1a70bSNoralf Trønnes 	gdrm->dmadev = NULL;
623*40e1a70bSNoralf Trønnes }
624*40e1a70bSNoralf Trønnes 
625*40e1a70bSNoralf Trønnes static int gud_suspend(struct usb_interface *intf, pm_message_t message)
626*40e1a70bSNoralf Trønnes {
627*40e1a70bSNoralf Trønnes 	struct gud_device *gdrm = usb_get_intfdata(intf);
628*40e1a70bSNoralf Trønnes 
629*40e1a70bSNoralf Trønnes 	return drm_mode_config_helper_suspend(&gdrm->drm);
630*40e1a70bSNoralf Trønnes }
631*40e1a70bSNoralf Trønnes 
632*40e1a70bSNoralf Trønnes static int gud_resume(struct usb_interface *intf)
633*40e1a70bSNoralf Trønnes {
634*40e1a70bSNoralf Trønnes 	struct gud_device *gdrm = usb_get_intfdata(intf);
635*40e1a70bSNoralf Trønnes 
636*40e1a70bSNoralf Trønnes 	drm_mode_config_helper_resume(&gdrm->drm);
637*40e1a70bSNoralf Trønnes 
638*40e1a70bSNoralf Trønnes 	return 0;
639*40e1a70bSNoralf Trønnes }
640*40e1a70bSNoralf Trønnes 
641*40e1a70bSNoralf Trønnes static const struct usb_device_id gud_id_table[] = {
642*40e1a70bSNoralf Trønnes 	{ USB_DEVICE_INTERFACE_CLASS(0x1d50, 0x614d, USB_CLASS_VENDOR_SPEC) },
643*40e1a70bSNoralf Trønnes 	{ }
644*40e1a70bSNoralf Trønnes };
645*40e1a70bSNoralf Trønnes 
646*40e1a70bSNoralf Trønnes MODULE_DEVICE_TABLE(usb, gud_id_table);
647*40e1a70bSNoralf Trønnes 
648*40e1a70bSNoralf Trønnes static struct usb_driver gud_usb_driver = {
649*40e1a70bSNoralf Trønnes 	.name		= "gud",
650*40e1a70bSNoralf Trønnes 	.probe		= gud_probe,
651*40e1a70bSNoralf Trønnes 	.disconnect	= gud_disconnect,
652*40e1a70bSNoralf Trønnes 	.id_table	= gud_id_table,
653*40e1a70bSNoralf Trønnes 	.suspend	= gud_suspend,
654*40e1a70bSNoralf Trønnes 	.resume		= gud_resume,
655*40e1a70bSNoralf Trønnes 	.reset_resume	= gud_resume,
656*40e1a70bSNoralf Trønnes };
657*40e1a70bSNoralf Trønnes 
658*40e1a70bSNoralf Trønnes module_usb_driver(gud_usb_driver);
659*40e1a70bSNoralf Trønnes 
660*40e1a70bSNoralf Trønnes MODULE_AUTHOR("Noralf Trønnes");
661*40e1a70bSNoralf Trønnes MODULE_LICENSE("Dual MIT/GPL");
662