Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2019 Hans de Goede <hdegoede@redhat.com>
4 */
5
6#include <linux/dma-buf.h>
7#include <linux/module.h>
8#include <linux/usb.h>
9
10#include <drm/drm_atomic_helper.h>
11#include <drm/drm_atomic_state_helper.h>
12#include <drm/drm_connector.h>
13#include <drm/drm_damage_helper.h>
14#include <drm/drm_drv.h>
15#include <drm/drm_fb_helper.h>
16#include <drm/drm_file.h>
17#include <drm/drm_format_helper.h>
18#include <drm/drm_fourcc.h>
19#include <drm/drm_gem_shmem_helper.h>
20#include <drm/drm_gem_framebuffer_helper.h>
21#include <drm/drm_ioctl.h>
22#include <drm/drm_managed.h>
23#include <drm/drm_modeset_helper_vtables.h>
24#include <drm/drm_probe_helper.h>
25#include <drm/drm_simple_kms_helper.h>
26
27static bool eco_mode;
28module_param(eco_mode, bool, 0644);
29MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)");
30
31#define DRIVER_NAME "gm12u320"
32#define DRIVER_DESC "Grain Media GM12U320 USB projector display"
33#define DRIVER_DATE "2019"
34#define DRIVER_MAJOR 1
35#define DRIVER_MINOR 0
36
37/*
38 * The DLP has an actual width of 854 pixels, but that is not a multiple
39 * of 8, breaking things left and right, so we export a width of 848.
40 */
41#define GM12U320_USER_WIDTH 848
42#define GM12U320_REAL_WIDTH 854
43#define GM12U320_HEIGHT 480
44
45#define GM12U320_BLOCK_COUNT 20
46
47#define GM12U320_ERR(fmt, ...) \
48 DRM_DEV_ERROR(gm12u320->dev.dev, fmt, ##__VA_ARGS__)
49
50#define MISC_RCV_EPT 1
51#define DATA_RCV_EPT 2
52#define DATA_SND_EPT 3
53#define MISC_SND_EPT 4
54
55#define DATA_BLOCK_HEADER_SIZE 84
56#define DATA_BLOCK_CONTENT_SIZE 64512
57#define DATA_BLOCK_FOOTER_SIZE 20
58#define DATA_BLOCK_SIZE (DATA_BLOCK_HEADER_SIZE + \
59 DATA_BLOCK_CONTENT_SIZE + \
60 DATA_BLOCK_FOOTER_SIZE)
61#define DATA_LAST_BLOCK_CONTENT_SIZE 4032
62#define DATA_LAST_BLOCK_SIZE (DATA_BLOCK_HEADER_SIZE + \
63 DATA_LAST_BLOCK_CONTENT_SIZE + \
64 DATA_BLOCK_FOOTER_SIZE)
65
66#define CMD_SIZE 31
67#define READ_STATUS_SIZE 13
68#define MISC_VALUE_SIZE 4
69
70#define CMD_TIMEOUT msecs_to_jiffies(200)
71#define DATA_TIMEOUT msecs_to_jiffies(1000)
72#define IDLE_TIMEOUT msecs_to_jiffies(2000)
73#define FIRST_FRAME_TIMEOUT msecs_to_jiffies(2000)
74
75#define MISC_REQ_GET_SET_ECO_A 0xff
76#define MISC_REQ_GET_SET_ECO_B 0x35
77/* Windows driver does once every second, with arg d = 1, other args 0 */
78#define MISC_REQ_UNKNOWN1_A 0xff
79#define MISC_REQ_UNKNOWN1_B 0x38
80/* Windows driver does this on init, with arg a, b = 0, c = 0xa0, d = 4 */
81#define MISC_REQ_UNKNOWN2_A 0xa5
82#define MISC_REQ_UNKNOWN2_B 0x00
83
84struct gm12u320_device {
85 struct drm_device dev;
86 struct drm_simple_display_pipe pipe;
87 struct drm_connector conn;
88 unsigned char *cmd_buf;
89 unsigned char *data_buf[GM12U320_BLOCK_COUNT];
90 struct {
91 struct delayed_work work;
92 struct mutex lock;
93 struct drm_framebuffer *fb;
94 struct drm_rect rect;
95 int frame;
96 int draw_status_timeout;
97 } fb_update;
98};
99
100#define to_gm12u320(__dev) container_of(__dev, struct gm12u320_device, dev)
101
102static const char cmd_data[CMD_SIZE] = {
103 0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
104 0x68, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x10, 0xff,
105 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x80, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
107};
108
109static const char cmd_draw[CMD_SIZE] = {
110 0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xfe,
112 0x00, 0x00, 0x00, 0xc0, 0xd1, 0x05, 0x00, 0x40,
113 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
114};
115
116static const char cmd_misc[CMD_SIZE] = {
117 0x55, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00,
118 0x04, 0x00, 0x00, 0x00, 0x80, 0x01, 0x10, 0xfd,
119 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x00,
120 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
121};
122
123static const char data_block_header[DATA_BLOCK_HEADER_SIZE] = {
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0xfb, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x04, 0x15, 0x00, 0x00, 0xfc, 0x00, 0x00,
134 0x01, 0x00, 0x00, 0xdb
135};
136
137static const char data_last_block_header[DATA_BLOCK_HEADER_SIZE] = {
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0xfb, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147 0x2a, 0x00, 0x20, 0x00, 0xc0, 0x0f, 0x00, 0x00,
148 0x01, 0x00, 0x00, 0xd7
149};
150
151static const char data_block_footer[DATA_BLOCK_FOOTER_SIZE] = {
152 0xfb, 0x14, 0x02, 0x20, 0x00, 0x00, 0x00, 0x00,
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x80, 0x00, 0x00, 0x4f
155};
156
157static inline struct usb_device *gm12u320_to_usb_device(struct gm12u320_device *gm12u320)
158{
159 return interface_to_usbdev(to_usb_interface(gm12u320->dev.dev));
160}
161
162static int gm12u320_usb_alloc(struct gm12u320_device *gm12u320)
163{
164 int i, block_size;
165 const char *hdr;
166
167 gm12u320->cmd_buf = drmm_kmalloc(&gm12u320->dev, CMD_SIZE, GFP_KERNEL);
168 if (!gm12u320->cmd_buf)
169 return -ENOMEM;
170
171 for (i = 0; i < GM12U320_BLOCK_COUNT; i++) {
172 if (i == GM12U320_BLOCK_COUNT - 1) {
173 block_size = DATA_LAST_BLOCK_SIZE;
174 hdr = data_last_block_header;
175 } else {
176 block_size = DATA_BLOCK_SIZE;
177 hdr = data_block_header;
178 }
179
180 gm12u320->data_buf[i] = drmm_kzalloc(&gm12u320->dev,
181 block_size, GFP_KERNEL);
182 if (!gm12u320->data_buf[i])
183 return -ENOMEM;
184
185 memcpy(gm12u320->data_buf[i], hdr, DATA_BLOCK_HEADER_SIZE);
186 memcpy(gm12u320->data_buf[i] +
187 (block_size - DATA_BLOCK_FOOTER_SIZE),
188 data_block_footer, DATA_BLOCK_FOOTER_SIZE);
189 }
190
191 return 0;
192}
193
194static int gm12u320_misc_request(struct gm12u320_device *gm12u320,
195 u8 req_a, u8 req_b,
196 u8 arg_a, u8 arg_b, u8 arg_c, u8 arg_d)
197{
198 struct usb_device *udev = gm12u320_to_usb_device(gm12u320);
199 int ret, len;
200
201 memcpy(gm12u320->cmd_buf, &cmd_misc, CMD_SIZE);
202 gm12u320->cmd_buf[20] = req_a;
203 gm12u320->cmd_buf[21] = req_b;
204 gm12u320->cmd_buf[22] = arg_a;
205 gm12u320->cmd_buf[23] = arg_b;
206 gm12u320->cmd_buf[24] = arg_c;
207 gm12u320->cmd_buf[25] = arg_d;
208
209 /* Send request */
210 ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, MISC_SND_EPT),
211 gm12u320->cmd_buf, CMD_SIZE, &len, CMD_TIMEOUT);
212 if (ret || len != CMD_SIZE) {
213 GM12U320_ERR("Misc. req. error %d\n", ret);
214 return -EIO;
215 }
216
217 /* Read value */
218 ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, MISC_RCV_EPT),
219 gm12u320->cmd_buf, MISC_VALUE_SIZE, &len,
220 DATA_TIMEOUT);
221 if (ret || len != MISC_VALUE_SIZE) {
222 GM12U320_ERR("Misc. value error %d\n", ret);
223 return -EIO;
224 }
225 /* cmd_buf[0] now contains the read value, which we don't use */
226
227 /* Read status */
228 ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, MISC_RCV_EPT),
229 gm12u320->cmd_buf, READ_STATUS_SIZE, &len,
230 CMD_TIMEOUT);
231 if (ret || len != READ_STATUS_SIZE) {
232 GM12U320_ERR("Misc. status error %d\n", ret);
233 return -EIO;
234 }
235
236 return 0;
237}
238
239static void gm12u320_32bpp_to_24bpp_packed(u8 *dst, u8 *src, int len)
240{
241 while (len--) {
242 *dst++ = *src++;
243 *dst++ = *src++;
244 *dst++ = *src++;
245 src++;
246 }
247}
248
249static void gm12u320_copy_fb_to_blocks(struct gm12u320_device *gm12u320)
250{
251 int block, dst_offset, len, remain, ret, x1, x2, y1, y2;
252 struct drm_framebuffer *fb;
253 struct dma_buf_map map;
254 void *vaddr;
255 u8 *src;
256
257 mutex_lock(&gm12u320->fb_update.lock);
258
259 if (!gm12u320->fb_update.fb)
260 goto unlock;
261
262 fb = gm12u320->fb_update.fb;
263 x1 = gm12u320->fb_update.rect.x1;
264 x2 = gm12u320->fb_update.rect.x2;
265 y1 = gm12u320->fb_update.rect.y1;
266 y2 = gm12u320->fb_update.rect.y2;
267
268 ret = drm_gem_shmem_vmap(fb->obj[0], &map);
269 if (ret) {
270 GM12U320_ERR("failed to vmap fb: %d\n", ret);
271 goto put_fb;
272 }
273 vaddr = map.vaddr; /* TODO: Use mapping abstraction properly */
274
275 if (fb->obj[0]->import_attach) {
276 ret = dma_buf_begin_cpu_access(
277 fb->obj[0]->import_attach->dmabuf, DMA_FROM_DEVICE);
278 if (ret) {
279 GM12U320_ERR("dma_buf_begin_cpu_access err: %d\n", ret);
280 goto vunmap;
281 }
282 }
283
284 src = vaddr + y1 * fb->pitches[0] + x1 * 4;
285
286 x1 += (GM12U320_REAL_WIDTH - GM12U320_USER_WIDTH) / 2;
287 x2 += (GM12U320_REAL_WIDTH - GM12U320_USER_WIDTH) / 2;
288
289 for (; y1 < y2; y1++) {
290 remain = 0;
291 len = (x2 - x1) * 3;
292 dst_offset = (y1 * GM12U320_REAL_WIDTH + x1) * 3;
293 block = dst_offset / DATA_BLOCK_CONTENT_SIZE;
294 dst_offset %= DATA_BLOCK_CONTENT_SIZE;
295
296 if ((dst_offset + len) > DATA_BLOCK_CONTENT_SIZE) {
297 remain = dst_offset + len - DATA_BLOCK_CONTENT_SIZE;
298 len = DATA_BLOCK_CONTENT_SIZE - dst_offset;
299 }
300
301 dst_offset += DATA_BLOCK_HEADER_SIZE;
302 len /= 3;
303
304 gm12u320_32bpp_to_24bpp_packed(
305 gm12u320->data_buf[block] + dst_offset,
306 src, len);
307
308 if (remain) {
309 block++;
310 dst_offset = DATA_BLOCK_HEADER_SIZE;
311 gm12u320_32bpp_to_24bpp_packed(
312 gm12u320->data_buf[block] + dst_offset,
313 src + len * 4, remain / 3);
314 }
315 src += fb->pitches[0];
316 }
317
318 if (fb->obj[0]->import_attach) {
319 ret = dma_buf_end_cpu_access(fb->obj[0]->import_attach->dmabuf,
320 DMA_FROM_DEVICE);
321 if (ret)
322 GM12U320_ERR("dma_buf_end_cpu_access err: %d\n", ret);
323 }
324vunmap:
325 drm_gem_shmem_vunmap(fb->obj[0], &map);
326put_fb:
327 drm_framebuffer_put(fb);
328 gm12u320->fb_update.fb = NULL;
329unlock:
330 mutex_unlock(&gm12u320->fb_update.lock);
331}
332
333static void gm12u320_fb_update_work(struct work_struct *work)
334{
335 struct gm12u320_device *gm12u320 =
336 container_of(to_delayed_work(work), struct gm12u320_device,
337 fb_update.work);
338 struct usb_device *udev = gm12u320_to_usb_device(gm12u320);
339 int block, block_size, len;
340 int ret = 0;
341
342 gm12u320_copy_fb_to_blocks(gm12u320);
343
344 for (block = 0; block < GM12U320_BLOCK_COUNT; block++) {
345 if (block == GM12U320_BLOCK_COUNT - 1)
346 block_size = DATA_LAST_BLOCK_SIZE;
347 else
348 block_size = DATA_BLOCK_SIZE;
349
350 /* Send data command to device */
351 memcpy(gm12u320->cmd_buf, cmd_data, CMD_SIZE);
352 gm12u320->cmd_buf[8] = block_size & 0xff;
353 gm12u320->cmd_buf[9] = block_size >> 8;
354 gm12u320->cmd_buf[20] = 0xfc - block * 4;
355 gm12u320->cmd_buf[21] =
356 block | (gm12u320->fb_update.frame << 7);
357
358 ret = usb_bulk_msg(udev,
359 usb_sndbulkpipe(udev, DATA_SND_EPT),
360 gm12u320->cmd_buf, CMD_SIZE, &len,
361 CMD_TIMEOUT);
362 if (ret || len != CMD_SIZE)
363 goto err;
364
365 /* Send data block to device */
366 ret = usb_bulk_msg(udev,
367 usb_sndbulkpipe(udev, DATA_SND_EPT),
368 gm12u320->data_buf[block], block_size,
369 &len, DATA_TIMEOUT);
370 if (ret || len != block_size)
371 goto err;
372
373 /* Read status */
374 ret = usb_bulk_msg(udev,
375 usb_rcvbulkpipe(udev, DATA_RCV_EPT),
376 gm12u320->cmd_buf, READ_STATUS_SIZE, &len,
377 CMD_TIMEOUT);
378 if (ret || len != READ_STATUS_SIZE)
379 goto err;
380 }
381
382 /* Send draw command to device */
383 memcpy(gm12u320->cmd_buf, cmd_draw, CMD_SIZE);
384 ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, DATA_SND_EPT),
385 gm12u320->cmd_buf, CMD_SIZE, &len, CMD_TIMEOUT);
386 if (ret || len != CMD_SIZE)
387 goto err;
388
389 /* Read status */
390 ret = usb_bulk_msg(udev, usb_rcvbulkpipe(udev, DATA_RCV_EPT),
391 gm12u320->cmd_buf, READ_STATUS_SIZE, &len,
392 gm12u320->fb_update.draw_status_timeout);
393 if (ret || len != READ_STATUS_SIZE)
394 goto err;
395
396 gm12u320->fb_update.draw_status_timeout = CMD_TIMEOUT;
397 gm12u320->fb_update.frame = !gm12u320->fb_update.frame;
398
399 /*
400 * We must draw a frame every 2s otherwise the projector
401 * switches back to showing its logo.
402 */
403 queue_delayed_work(system_long_wq, &gm12u320->fb_update.work,
404 IDLE_TIMEOUT);
405
406 return;
407err:
408 /* Do not log errors caused by module unload or device unplug */
409 if (ret != -ENODEV && ret != -ECONNRESET && ret != -ESHUTDOWN)
410 GM12U320_ERR("Frame update error: %d\n", ret);
411}
412
413static void gm12u320_fb_mark_dirty(struct drm_framebuffer *fb,
414 struct drm_rect *dirty)
415{
416 struct gm12u320_device *gm12u320 = to_gm12u320(fb->dev);
417 struct drm_framebuffer *old_fb = NULL;
418 bool wakeup = false;
419
420 mutex_lock(&gm12u320->fb_update.lock);
421
422 if (gm12u320->fb_update.fb != fb) {
423 old_fb = gm12u320->fb_update.fb;
424 drm_framebuffer_get(fb);
425 gm12u320->fb_update.fb = fb;
426 gm12u320->fb_update.rect = *dirty;
427 wakeup = true;
428 } else {
429 struct drm_rect *rect = &gm12u320->fb_update.rect;
430
431 rect->x1 = min(rect->x1, dirty->x1);
432 rect->y1 = min(rect->y1, dirty->y1);
433 rect->x2 = max(rect->x2, dirty->x2);
434 rect->y2 = max(rect->y2, dirty->y2);
435 }
436
437 mutex_unlock(&gm12u320->fb_update.lock);
438
439 if (wakeup)
440 mod_delayed_work(system_long_wq, &gm12u320->fb_update.work, 0);
441
442 if (old_fb)
443 drm_framebuffer_put(old_fb);
444}
445
446static void gm12u320_stop_fb_update(struct gm12u320_device *gm12u320)
447{
448 struct drm_framebuffer *old_fb;
449
450 cancel_delayed_work_sync(&gm12u320->fb_update.work);
451
452 mutex_lock(&gm12u320->fb_update.lock);
453 old_fb = gm12u320->fb_update.fb;
454 gm12u320->fb_update.fb = NULL;
455 mutex_unlock(&gm12u320->fb_update.lock);
456
457 drm_framebuffer_put(old_fb);
458}
459
460static int gm12u320_set_ecomode(struct gm12u320_device *gm12u320)
461{
462 return gm12u320_misc_request(gm12u320, MISC_REQ_GET_SET_ECO_A,
463 MISC_REQ_GET_SET_ECO_B, 0x01 /* set */,
464 eco_mode ? 0x01 : 0x00, 0x00, 0x01);
465}
466
467/* ------------------------------------------------------------------ */
468/* gm12u320 connector */
469
470/*
471 * We use fake EDID info so that userspace know that it is dealing with
472 * an Acer projector, rather then listing this as an "unknown" monitor.
473 * Note this assumes this driver is only ever used with the Acer C120, if we
474 * add support for other devices the vendor and model should be parameterized.
475 */
476static struct edid gm12u320_edid = {
477 .header = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 },
478 .mfg_id = { 0x04, 0x72 }, /* "ACR" */
479 .prod_code = { 0x20, 0xc1 }, /* C120h */
480 .serial = 0xaa55aa55,
481 .mfg_week = 1,
482 .mfg_year = 16,
483 .version = 1, /* EDID 1.3 */
484 .revision = 3, /* EDID 1.3 */
485 .input = 0x08, /* Analog input */
486 .features = 0x0a, /* Pref timing in DTD 1 */
487 .standard_timings = { { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 },
488 { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 } },
489 .detailed_timings = { {
490 .pixel_clock = 3383,
491 /* hactive = 848, hblank = 256 */
492 .data.pixel_data.hactive_lo = 0x50,
493 .data.pixel_data.hblank_lo = 0x00,
494 .data.pixel_data.hactive_hblank_hi = 0x31,
495 /* vactive = 480, vblank = 28 */
496 .data.pixel_data.vactive_lo = 0xe0,
497 .data.pixel_data.vblank_lo = 0x1c,
498 .data.pixel_data.vactive_vblank_hi = 0x10,
499 /* hsync offset 40 pw 128, vsync offset 1 pw 4 */
500 .data.pixel_data.hsync_offset_lo = 0x28,
501 .data.pixel_data.hsync_pulse_width_lo = 0x80,
502 .data.pixel_data.vsync_offset_pulse_width_lo = 0x14,
503 .data.pixel_data.hsync_vsync_offset_pulse_width_hi = 0x00,
504 /* Digital separate syncs, hsync+, vsync+ */
505 .data.pixel_data.misc = 0x1e,
506 }, {
507 .pixel_clock = 0,
508 .data.other_data.type = 0xfd, /* Monitor ranges */
509 .data.other_data.data.range.min_vfreq = 59,
510 .data.other_data.data.range.max_vfreq = 61,
511 .data.other_data.data.range.min_hfreq_khz = 29,
512 .data.other_data.data.range.max_hfreq_khz = 32,
513 .data.other_data.data.range.pixel_clock_mhz = 4, /* 40 MHz */
514 .data.other_data.data.range.flags = 0,
515 .data.other_data.data.range.formula.cvt = {
516 0xa0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 },
517 }, {
518 .pixel_clock = 0,
519 .data.other_data.type = 0xfc, /* Model string */
520 .data.other_data.data.str.str = {
521 'P', 'r', 'o', 'j', 'e', 'c', 't', 'o', 'r', '\n',
522 ' ', ' ', ' ' },
523 }, {
524 .pixel_clock = 0,
525 .data.other_data.type = 0xfe, /* Unspecified text / padding */
526 .data.other_data.data.str.str = {
527 '\n', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
528 ' ', ' ', ' ' },
529 } },
530 .checksum = 0x13,
531};
532
533static int gm12u320_conn_get_modes(struct drm_connector *connector)
534{
535 drm_connector_update_edid_property(connector, &gm12u320_edid);
536 return drm_add_edid_modes(connector, &gm12u320_edid);
537}
538
539static const struct drm_connector_helper_funcs gm12u320_conn_helper_funcs = {
540 .get_modes = gm12u320_conn_get_modes,
541};
542
543static const struct drm_connector_funcs gm12u320_conn_funcs = {
544 .fill_modes = drm_helper_probe_single_connector_modes,
545 .destroy = drm_connector_cleanup,
546 .reset = drm_atomic_helper_connector_reset,
547 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
548 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
549};
550
551static int gm12u320_conn_init(struct gm12u320_device *gm12u320)
552{
553 drm_connector_helper_add(&gm12u320->conn, &gm12u320_conn_helper_funcs);
554 return drm_connector_init(&gm12u320->dev, &gm12u320->conn,
555 &gm12u320_conn_funcs, DRM_MODE_CONNECTOR_VGA);
556}
557
558/* ------------------------------------------------------------------ */
559/* gm12u320 (simple) display pipe */
560
561static void gm12u320_pipe_enable(struct drm_simple_display_pipe *pipe,
562 struct drm_crtc_state *crtc_state,
563 struct drm_plane_state *plane_state)
564{
565 struct drm_rect rect = { 0, 0, GM12U320_USER_WIDTH, GM12U320_HEIGHT };
566 struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev);
567
568 gm12u320->fb_update.draw_status_timeout = FIRST_FRAME_TIMEOUT;
569 gm12u320_fb_mark_dirty(plane_state->fb, &rect);
570}
571
572static void gm12u320_pipe_disable(struct drm_simple_display_pipe *pipe)
573{
574 struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev);
575
576 gm12u320_stop_fb_update(gm12u320);
577}
578
579static void gm12u320_pipe_update(struct drm_simple_display_pipe *pipe,
580 struct drm_plane_state *old_state)
581{
582 struct drm_plane_state *state = pipe->plane.state;
583 struct drm_rect rect;
584
585 if (drm_atomic_helper_damage_merged(old_state, state, &rect))
586 gm12u320_fb_mark_dirty(pipe->plane.state->fb, &rect);
587}
588
589static const struct drm_simple_display_pipe_funcs gm12u320_pipe_funcs = {
590 .enable = gm12u320_pipe_enable,
591 .disable = gm12u320_pipe_disable,
592 .update = gm12u320_pipe_update,
593};
594
595static const uint32_t gm12u320_pipe_formats[] = {
596 DRM_FORMAT_XRGB8888,
597};
598
599static const uint64_t gm12u320_pipe_modifiers[] = {
600 DRM_FORMAT_MOD_LINEAR,
601 DRM_FORMAT_MOD_INVALID
602};
603
604DEFINE_DRM_GEM_FOPS(gm12u320_fops);
605
606static const struct drm_driver gm12u320_drm_driver = {
607 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
608
609 .name = DRIVER_NAME,
610 .desc = DRIVER_DESC,
611 .date = DRIVER_DATE,
612 .major = DRIVER_MAJOR,
613 .minor = DRIVER_MINOR,
614
615 .fops = &gm12u320_fops,
616 DRM_GEM_SHMEM_DRIVER_OPS,
617};
618
619static const struct drm_mode_config_funcs gm12u320_mode_config_funcs = {
620 .fb_create = drm_gem_fb_create_with_dirty,
621 .atomic_check = drm_atomic_helper_check,
622 .atomic_commit = drm_atomic_helper_commit,
623};
624
625static int gm12u320_usb_probe(struct usb_interface *interface,
626 const struct usb_device_id *id)
627{
628 struct gm12u320_device *gm12u320;
629 struct drm_device *dev;
630 int ret;
631
632 /*
633 * The gm12u320 presents itself to the system as 2 usb mass-storage
634 * interfaces, we only care about / need the first one.
635 */
636 if (interface->cur_altsetting->desc.bInterfaceNumber != 0)
637 return -ENODEV;
638
639 gm12u320 = devm_drm_dev_alloc(&interface->dev, &gm12u320_drm_driver,
640 struct gm12u320_device, dev);
641 if (IS_ERR(gm12u320))
642 return PTR_ERR(gm12u320);
643
644 INIT_DELAYED_WORK(&gm12u320->fb_update.work, gm12u320_fb_update_work);
645 mutex_init(&gm12u320->fb_update.lock);
646
647 dev = &gm12u320->dev;
648
649 ret = drmm_mode_config_init(dev);
650 if (ret)
651 return ret;
652
653 dev->mode_config.min_width = GM12U320_USER_WIDTH;
654 dev->mode_config.max_width = GM12U320_USER_WIDTH;
655 dev->mode_config.min_height = GM12U320_HEIGHT;
656 dev->mode_config.max_height = GM12U320_HEIGHT;
657 dev->mode_config.funcs = &gm12u320_mode_config_funcs;
658
659 ret = gm12u320_usb_alloc(gm12u320);
660 if (ret)
661 return ret;
662
663 ret = gm12u320_set_ecomode(gm12u320);
664 if (ret)
665 return ret;
666
667 ret = gm12u320_conn_init(gm12u320);
668 if (ret)
669 return ret;
670
671 ret = drm_simple_display_pipe_init(&gm12u320->dev,
672 &gm12u320->pipe,
673 &gm12u320_pipe_funcs,
674 gm12u320_pipe_formats,
675 ARRAY_SIZE(gm12u320_pipe_formats),
676 gm12u320_pipe_modifiers,
677 &gm12u320->conn);
678 if (ret)
679 return ret;
680
681 drm_mode_config_reset(dev);
682
683 usb_set_intfdata(interface, dev);
684 ret = drm_dev_register(dev, 0);
685 if (ret)
686 return ret;
687
688 drm_fbdev_generic_setup(dev, 0);
689
690 return 0;
691}
692
693static void gm12u320_usb_disconnect(struct usb_interface *interface)
694{
695 struct drm_device *dev = usb_get_intfdata(interface);
696
697 drm_dev_unplug(dev);
698 drm_atomic_helper_shutdown(dev);
699}
700
701static __maybe_unused int gm12u320_suspend(struct usb_interface *interface,
702 pm_message_t message)
703{
704 struct drm_device *dev = usb_get_intfdata(interface);
705
706 return drm_mode_config_helper_suspend(dev);
707}
708
709static __maybe_unused int gm12u320_resume(struct usb_interface *interface)
710{
711 struct drm_device *dev = usb_get_intfdata(interface);
712 struct gm12u320_device *gm12u320 = to_gm12u320(dev);
713
714 gm12u320_set_ecomode(gm12u320);
715
716 return drm_mode_config_helper_resume(dev);
717}
718
719static const struct usb_device_id id_table[] = {
720 { USB_DEVICE(0x1de1, 0xc102) },
721 {},
722};
723MODULE_DEVICE_TABLE(usb, id_table);
724
725static struct usb_driver gm12u320_usb_driver = {
726 .name = "gm12u320",
727 .probe = gm12u320_usb_probe,
728 .disconnect = gm12u320_usb_disconnect,
729 .id_table = id_table,
730#ifdef CONFIG_PM
731 .suspend = gm12u320_suspend,
732 .resume = gm12u320_resume,
733 .reset_resume = gm12u320_resume,
734#endif
735};
736
737module_usb_driver(gm12u320_usb_driver);
738MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
739MODULE_LICENSE("GPL");