1
2
3
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_modeset_helper_vtables.h>
23#include <drm/drm_probe_helper.h>
24#include <drm/drm_simple_kms_helper.h>
25
26static bool eco_mode;
27module_param(eco_mode, bool, 0644);
28MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)");
29
30#define DRIVER_NAME "gm12u320"
31#define DRIVER_DESC "Grain Media GM12U320 USB projector display"
32#define DRIVER_DATE "2019"
33#define DRIVER_MAJOR 1
34#define DRIVER_MINOR 0
35
36
37
38
39
40#define GM12U320_USER_WIDTH 848
41#define GM12U320_REAL_WIDTH 854
42#define GM12U320_HEIGHT 480
43
44#define GM12U320_BLOCK_COUNT 20
45
46#define GM12U320_ERR(fmt, ...) \
47 DRM_DEV_ERROR(&gm12u320->udev->dev, fmt, ##__VA_ARGS__)
48
49#define MISC_RCV_EPT 1
50#define DATA_RCV_EPT 2
51#define DATA_SND_EPT 3
52#define MISC_SND_EPT 4
53
54#define DATA_BLOCK_HEADER_SIZE 84
55#define DATA_BLOCK_CONTENT_SIZE 64512
56#define DATA_BLOCK_FOOTER_SIZE 20
57#define DATA_BLOCK_SIZE (DATA_BLOCK_HEADER_SIZE + \
58 DATA_BLOCK_CONTENT_SIZE + \
59 DATA_BLOCK_FOOTER_SIZE)
60#define DATA_LAST_BLOCK_CONTENT_SIZE 4032
61#define DATA_LAST_BLOCK_SIZE (DATA_BLOCK_HEADER_SIZE + \
62 DATA_LAST_BLOCK_CONTENT_SIZE + \
63 DATA_BLOCK_FOOTER_SIZE)
64
65#define CMD_SIZE 31
66#define READ_STATUS_SIZE 13
67#define MISC_VALUE_SIZE 4
68
69#define CMD_TIMEOUT msecs_to_jiffies(200)
70#define DATA_TIMEOUT msecs_to_jiffies(1000)
71#define IDLE_TIMEOUT msecs_to_jiffies(2000)
72#define FIRST_FRAME_TIMEOUT msecs_to_jiffies(2000)
73
74#define MISC_REQ_GET_SET_ECO_A 0xff
75#define MISC_REQ_GET_SET_ECO_B 0x35
76
77#define MISC_REQ_UNKNOWN1_A 0xff
78#define MISC_REQ_UNKNOWN1_B 0x38
79
80#define MISC_REQ_UNKNOWN2_A 0xa5
81#define MISC_REQ_UNKNOWN2_B 0x00
82
83struct gm12u320_device {
84 struct drm_device dev;
85 struct drm_simple_display_pipe pipe;
86 struct drm_connector conn;
87 struct usb_device *udev;
88 unsigned char *cmd_buf;
89 unsigned char *data_buf[GM12U320_BLOCK_COUNT];
90 bool pipe_enabled;
91 struct {
92 bool run;
93 struct workqueue_struct *workq;
94 struct work_struct work;
95 wait_queue_head_t waitq;
96 struct mutex lock;
97 struct drm_framebuffer *fb;
98 struct drm_rect rect;
99 } fb_update;
100};
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 int gm12u320_usb_alloc(struct gm12u320_device *gm12u320)
158{
159 int i, block_size;
160 const char *hdr;
161
162 gm12u320->cmd_buf = kmalloc(CMD_SIZE, GFP_KERNEL);
163 if (!gm12u320->cmd_buf)
164 return -ENOMEM;
165
166 for (i = 0; i < GM12U320_BLOCK_COUNT; i++) {
167 if (i == GM12U320_BLOCK_COUNT - 1) {
168 block_size = DATA_LAST_BLOCK_SIZE;
169 hdr = data_last_block_header;
170 } else {
171 block_size = DATA_BLOCK_SIZE;
172 hdr = data_block_header;
173 }
174
175 gm12u320->data_buf[i] = kzalloc(block_size, GFP_KERNEL);
176 if (!gm12u320->data_buf[i])
177 return -ENOMEM;
178
179 memcpy(gm12u320->data_buf[i], hdr, DATA_BLOCK_HEADER_SIZE);
180 memcpy(gm12u320->data_buf[i] +
181 (block_size - DATA_BLOCK_FOOTER_SIZE),
182 data_block_footer, DATA_BLOCK_FOOTER_SIZE);
183 }
184
185 gm12u320->fb_update.workq = create_singlethread_workqueue(DRIVER_NAME);
186 if (!gm12u320->fb_update.workq)
187 return -ENOMEM;
188
189 return 0;
190}
191
192static void gm12u320_usb_free(struct gm12u320_device *gm12u320)
193{
194 int i;
195
196 if (gm12u320->fb_update.workq)
197 destroy_workqueue(gm12u320->fb_update.workq);
198
199 for (i = 0; i < GM12U320_BLOCK_COUNT; i++)
200 kfree(gm12u320->data_buf[i]);
201
202 kfree(gm12u320->cmd_buf);
203}
204
205static int gm12u320_misc_request(struct gm12u320_device *gm12u320,
206 u8 req_a, u8 req_b,
207 u8 arg_a, u8 arg_b, u8 arg_c, u8 arg_d)
208{
209 int ret, len;
210
211 memcpy(gm12u320->cmd_buf, &cmd_misc, CMD_SIZE);
212 gm12u320->cmd_buf[20] = req_a;
213 gm12u320->cmd_buf[21] = req_b;
214 gm12u320->cmd_buf[22] = arg_a;
215 gm12u320->cmd_buf[23] = arg_b;
216 gm12u320->cmd_buf[24] = arg_c;
217 gm12u320->cmd_buf[25] = arg_d;
218
219
220 ret = usb_bulk_msg(gm12u320->udev,
221 usb_sndbulkpipe(gm12u320->udev, MISC_SND_EPT),
222 gm12u320->cmd_buf, CMD_SIZE, &len, CMD_TIMEOUT);
223 if (ret || len != CMD_SIZE) {
224 GM12U320_ERR("Misc. req. error %d\n", ret);
225 return -EIO;
226 }
227
228
229 ret = usb_bulk_msg(gm12u320->udev,
230 usb_rcvbulkpipe(gm12u320->udev, MISC_RCV_EPT),
231 gm12u320->cmd_buf, MISC_VALUE_SIZE, &len,
232 DATA_TIMEOUT);
233 if (ret || len != MISC_VALUE_SIZE) {
234 GM12U320_ERR("Misc. value error %d\n", ret);
235 return -EIO;
236 }
237
238
239
240 ret = usb_bulk_msg(gm12u320->udev,
241 usb_rcvbulkpipe(gm12u320->udev, MISC_RCV_EPT),
242 gm12u320->cmd_buf, READ_STATUS_SIZE, &len,
243 CMD_TIMEOUT);
244 if (ret || len != READ_STATUS_SIZE) {
245 GM12U320_ERR("Misc. status error %d\n", ret);
246 return -EIO;
247 }
248
249 return 0;
250}
251
252static void gm12u320_32bpp_to_24bpp_packed(u8 *dst, u8 *src, int len)
253{
254 while (len--) {
255 *dst++ = *src++;
256 *dst++ = *src++;
257 *dst++ = *src++;
258 src++;
259 }
260}
261
262static void gm12u320_copy_fb_to_blocks(struct gm12u320_device *gm12u320)
263{
264 int block, dst_offset, len, remain, ret, x1, x2, y1, y2;
265 struct drm_framebuffer *fb;
266 void *vaddr;
267 u8 *src;
268
269 mutex_lock(&gm12u320->fb_update.lock);
270
271 if (!gm12u320->fb_update.fb)
272 goto unlock;
273
274 fb = gm12u320->fb_update.fb;
275 x1 = gm12u320->fb_update.rect.x1;
276 x2 = gm12u320->fb_update.rect.x2;
277 y1 = gm12u320->fb_update.rect.y1;
278 y2 = gm12u320->fb_update.rect.y2;
279
280 vaddr = drm_gem_shmem_vmap(fb->obj[0]);
281 if (IS_ERR(vaddr)) {
282 GM12U320_ERR("failed to vmap fb: %ld\n", PTR_ERR(vaddr));
283 goto put_fb;
284 }
285
286 if (fb->obj[0]->import_attach) {
287 ret = dma_buf_begin_cpu_access(
288 fb->obj[0]->import_attach->dmabuf, DMA_FROM_DEVICE);
289 if (ret) {
290 GM12U320_ERR("dma_buf_begin_cpu_access err: %d\n", ret);
291 goto vunmap;
292 }
293 }
294
295 src = vaddr + y1 * fb->pitches[0] + x1 * 4;
296
297 x1 += (GM12U320_REAL_WIDTH - GM12U320_USER_WIDTH) / 2;
298 x2 += (GM12U320_REAL_WIDTH - GM12U320_USER_WIDTH) / 2;
299
300 for (; y1 < y2; y1++) {
301 remain = 0;
302 len = (x2 - x1) * 3;
303 dst_offset = (y1 * GM12U320_REAL_WIDTH + x1) * 3;
304 block = dst_offset / DATA_BLOCK_CONTENT_SIZE;
305 dst_offset %= DATA_BLOCK_CONTENT_SIZE;
306
307 if ((dst_offset + len) > DATA_BLOCK_CONTENT_SIZE) {
308 remain = dst_offset + len - DATA_BLOCK_CONTENT_SIZE;
309 len = DATA_BLOCK_CONTENT_SIZE - dst_offset;
310 }
311
312 dst_offset += DATA_BLOCK_HEADER_SIZE;
313 len /= 3;
314
315 gm12u320_32bpp_to_24bpp_packed(
316 gm12u320->data_buf[block] + dst_offset,
317 src, len);
318
319 if (remain) {
320 block++;
321 dst_offset = DATA_BLOCK_HEADER_SIZE;
322 gm12u320_32bpp_to_24bpp_packed(
323 gm12u320->data_buf[block] + dst_offset,
324 src + len * 4, remain / 3);
325 }
326 src += fb->pitches[0];
327 }
328
329 if (fb->obj[0]->import_attach) {
330 ret = dma_buf_end_cpu_access(fb->obj[0]->import_attach->dmabuf,
331 DMA_FROM_DEVICE);
332 if (ret)
333 GM12U320_ERR("dma_buf_end_cpu_access err: %d\n", ret);
334 }
335vunmap:
336 drm_gem_shmem_vunmap(fb->obj[0], vaddr);
337put_fb:
338 drm_framebuffer_put(fb);
339 gm12u320->fb_update.fb = NULL;
340unlock:
341 mutex_unlock(&gm12u320->fb_update.lock);
342}
343
344static void gm12u320_fb_update_work(struct work_struct *work)
345{
346 struct gm12u320_device *gm12u320 =
347 container_of(work, struct gm12u320_device, fb_update.work);
348 int draw_status_timeout = FIRST_FRAME_TIMEOUT;
349 int block, block_size, len;
350 int frame = 0;
351 int ret = 0;
352
353 while (gm12u320->fb_update.run) {
354 gm12u320_copy_fb_to_blocks(gm12u320);
355
356 for (block = 0; block < GM12U320_BLOCK_COUNT; block++) {
357 if (block == GM12U320_BLOCK_COUNT - 1)
358 block_size = DATA_LAST_BLOCK_SIZE;
359 else
360 block_size = DATA_BLOCK_SIZE;
361
362
363 memcpy(gm12u320->cmd_buf, cmd_data, CMD_SIZE);
364 gm12u320->cmd_buf[8] = block_size & 0xff;
365 gm12u320->cmd_buf[9] = block_size >> 8;
366 gm12u320->cmd_buf[20] = 0xfc - block * 4;
367 gm12u320->cmd_buf[21] = block | (frame << 7);
368
369 ret = usb_bulk_msg(gm12u320->udev,
370 usb_sndbulkpipe(gm12u320->udev, DATA_SND_EPT),
371 gm12u320->cmd_buf, CMD_SIZE, &len,
372 CMD_TIMEOUT);
373 if (ret || len != CMD_SIZE)
374 goto err;
375
376
377 ret = usb_bulk_msg(gm12u320->udev,
378 usb_sndbulkpipe(gm12u320->udev, DATA_SND_EPT),
379 gm12u320->data_buf[block], block_size,
380 &len, DATA_TIMEOUT);
381 if (ret || len != block_size)
382 goto err;
383
384
385 ret = usb_bulk_msg(gm12u320->udev,
386 usb_rcvbulkpipe(gm12u320->udev, DATA_RCV_EPT),
387 gm12u320->cmd_buf, READ_STATUS_SIZE, &len,
388 CMD_TIMEOUT);
389 if (ret || len != READ_STATUS_SIZE)
390 goto err;
391 }
392
393
394 memcpy(gm12u320->cmd_buf, cmd_draw, CMD_SIZE);
395 ret = usb_bulk_msg(gm12u320->udev,
396 usb_sndbulkpipe(gm12u320->udev, DATA_SND_EPT),
397 gm12u320->cmd_buf, CMD_SIZE, &len, CMD_TIMEOUT);
398 if (ret || len != CMD_SIZE)
399 goto err;
400
401
402 ret = usb_bulk_msg(gm12u320->udev,
403 usb_rcvbulkpipe(gm12u320->udev, DATA_RCV_EPT),
404 gm12u320->cmd_buf, READ_STATUS_SIZE, &len,
405 draw_status_timeout);
406 if (ret || len != READ_STATUS_SIZE)
407 goto err;
408
409 draw_status_timeout = CMD_TIMEOUT;
410 frame = !frame;
411
412
413
414
415
416 wait_event_timeout(gm12u320->fb_update.waitq,
417 !gm12u320->fb_update.run ||
418 gm12u320->fb_update.fb != NULL,
419 IDLE_TIMEOUT);
420 }
421 return;
422err:
423
424 if (ret != -ENODEV && ret != -ECONNRESET && ret != -ESHUTDOWN)
425 GM12U320_ERR("Frame update error: %d\n", ret);
426}
427
428static void gm12u320_fb_mark_dirty(struct drm_framebuffer *fb,
429 struct drm_rect *dirty)
430{
431 struct gm12u320_device *gm12u320 = fb->dev->dev_private;
432 struct drm_framebuffer *old_fb = NULL;
433 bool wakeup = false;
434
435 mutex_lock(&gm12u320->fb_update.lock);
436
437 if (gm12u320->fb_update.fb != fb) {
438 old_fb = gm12u320->fb_update.fb;
439 drm_framebuffer_get(fb);
440 gm12u320->fb_update.fb = fb;
441 gm12u320->fb_update.rect = *dirty;
442 wakeup = true;
443 } else {
444 struct drm_rect *rect = &gm12u320->fb_update.rect;
445
446 rect->x1 = min(rect->x1, dirty->x1);
447 rect->y1 = min(rect->y1, dirty->y1);
448 rect->x2 = max(rect->x2, dirty->x2);
449 rect->y2 = max(rect->y2, dirty->y2);
450 }
451
452 mutex_unlock(&gm12u320->fb_update.lock);
453
454 if (wakeup)
455 wake_up(&gm12u320->fb_update.waitq);
456
457 if (old_fb)
458 drm_framebuffer_put(old_fb);
459}
460
461static void gm12u320_start_fb_update(struct gm12u320_device *gm12u320)
462{
463 mutex_lock(&gm12u320->fb_update.lock);
464 gm12u320->fb_update.run = true;
465 mutex_unlock(&gm12u320->fb_update.lock);
466
467 queue_work(gm12u320->fb_update.workq, &gm12u320->fb_update.work);
468}
469
470static void gm12u320_stop_fb_update(struct gm12u320_device *gm12u320)
471{
472 mutex_lock(&gm12u320->fb_update.lock);
473 gm12u320->fb_update.run = false;
474 mutex_unlock(&gm12u320->fb_update.lock);
475
476 wake_up(&gm12u320->fb_update.waitq);
477 cancel_work_sync(&gm12u320->fb_update.work);
478
479 mutex_lock(&gm12u320->fb_update.lock);
480 if (gm12u320->fb_update.fb) {
481 drm_framebuffer_put(gm12u320->fb_update.fb);
482 gm12u320->fb_update.fb = NULL;
483 }
484 mutex_unlock(&gm12u320->fb_update.lock);
485}
486
487static int gm12u320_set_ecomode(struct gm12u320_device *gm12u320)
488{
489 return gm12u320_misc_request(gm12u320, MISC_REQ_GET_SET_ECO_A,
490 MISC_REQ_GET_SET_ECO_B, 0x01 ,
491 eco_mode ? 0x01 : 0x00, 0x00, 0x01);
492}
493
494
495
496
497
498
499
500
501
502
503static struct edid gm12u320_edid = {
504 .header = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 },
505 .mfg_id = { 0x04, 0x72 },
506 .prod_code = { 0x20, 0xc1 },
507 .serial = 0xaa55aa55,
508 .mfg_week = 1,
509 .mfg_year = 16,
510 .version = 1,
511 .revision = 3,
512 .input = 0x08,
513 .features = 0x0a,
514 .standard_timings = { { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 },
515 { 1, 1 }, { 1, 1 }, { 1, 1 }, { 1, 1 } },
516 .detailed_timings = { {
517 .pixel_clock = 3383,
518
519 .data.pixel_data.hactive_lo = 0x50,
520 .data.pixel_data.hblank_lo = 0x00,
521 .data.pixel_data.hactive_hblank_hi = 0x31,
522
523 .data.pixel_data.vactive_lo = 0xe0,
524 .data.pixel_data.vblank_lo = 0x1c,
525 .data.pixel_data.vactive_vblank_hi = 0x10,
526
527 .data.pixel_data.hsync_offset_lo = 0x28,
528 .data.pixel_data.hsync_pulse_width_lo = 0x80,
529 .data.pixel_data.vsync_offset_pulse_width_lo = 0x14,
530 .data.pixel_data.hsync_vsync_offset_pulse_width_hi = 0x00,
531
532 .data.pixel_data.misc = 0x1e,
533 }, {
534 .pixel_clock = 0,
535 .data.other_data.type = 0xfd,
536 .data.other_data.data.range.min_vfreq = 59,
537 .data.other_data.data.range.max_vfreq = 61,
538 .data.other_data.data.range.min_hfreq_khz = 29,
539 .data.other_data.data.range.max_hfreq_khz = 32,
540 .data.other_data.data.range.pixel_clock_mhz = 4,
541 .data.other_data.data.range.flags = 0,
542 .data.other_data.data.range.formula.cvt = {
543 0xa0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 },
544 }, {
545 .pixel_clock = 0,
546 .data.other_data.type = 0xfc,
547 .data.other_data.data.str.str = {
548 'P', 'r', 'o', 'j', 'e', 'c', 't', 'o', 'r', '\n',
549 ' ', ' ', ' ' },
550 }, {
551 .pixel_clock = 0,
552 .data.other_data.type = 0xfe,
553 .data.other_data.data.str.str = {
554 '\n', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
555 ' ', ' ', ' ' },
556 } },
557 .checksum = 0x13,
558};
559
560static int gm12u320_conn_get_modes(struct drm_connector *connector)
561{
562 drm_connector_update_edid_property(connector, &gm12u320_edid);
563 return drm_add_edid_modes(connector, &gm12u320_edid);
564}
565
566static const struct drm_connector_helper_funcs gm12u320_conn_helper_funcs = {
567 .get_modes = gm12u320_conn_get_modes,
568};
569
570static const struct drm_connector_funcs gm12u320_conn_funcs = {
571 .fill_modes = drm_helper_probe_single_connector_modes,
572 .destroy = drm_connector_cleanup,
573 .reset = drm_atomic_helper_connector_reset,
574 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
575 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
576};
577
578static int gm12u320_conn_init(struct gm12u320_device *gm12u320)
579{
580 drm_connector_helper_add(&gm12u320->conn, &gm12u320_conn_helper_funcs);
581 return drm_connector_init(&gm12u320->dev, &gm12u320->conn,
582 &gm12u320_conn_funcs, DRM_MODE_CONNECTOR_VGA);
583}
584
585
586
587
588static void gm12u320_pipe_enable(struct drm_simple_display_pipe *pipe,
589 struct drm_crtc_state *crtc_state,
590 struct drm_plane_state *plane_state)
591{
592 struct gm12u320_device *gm12u320 = pipe->crtc.dev->dev_private;
593 struct drm_rect rect = { 0, 0, GM12U320_USER_WIDTH, GM12U320_HEIGHT };
594
595 gm12u320_fb_mark_dirty(plane_state->fb, &rect);
596 gm12u320_start_fb_update(gm12u320);
597 gm12u320->pipe_enabled = true;
598}
599
600static void gm12u320_pipe_disable(struct drm_simple_display_pipe *pipe)
601{
602 struct gm12u320_device *gm12u320 = pipe->crtc.dev->dev_private;
603
604 gm12u320_stop_fb_update(gm12u320);
605 gm12u320->pipe_enabled = false;
606}
607
608static void gm12u320_pipe_update(struct drm_simple_display_pipe *pipe,
609 struct drm_plane_state *old_state)
610{
611 struct drm_plane_state *state = pipe->plane.state;
612 struct drm_rect rect;
613
614 if (drm_atomic_helper_damage_merged(old_state, state, &rect))
615 gm12u320_fb_mark_dirty(pipe->plane.state->fb, &rect);
616}
617
618static const struct drm_simple_display_pipe_funcs gm12u320_pipe_funcs = {
619 .enable = gm12u320_pipe_enable,
620 .disable = gm12u320_pipe_disable,
621 .update = gm12u320_pipe_update,
622};
623
624static const uint32_t gm12u320_pipe_formats[] = {
625 DRM_FORMAT_XRGB8888,
626};
627
628static const uint64_t gm12u320_pipe_modifiers[] = {
629 DRM_FORMAT_MOD_LINEAR,
630 DRM_FORMAT_MOD_INVALID
631};
632
633static void gm12u320_driver_release(struct drm_device *dev)
634{
635 struct gm12u320_device *gm12u320 = dev->dev_private;
636
637 gm12u320_usb_free(gm12u320);
638 drm_mode_config_cleanup(dev);
639 drm_dev_fini(dev);
640 kfree(gm12u320);
641}
642
643DEFINE_DRM_GEM_FOPS(gm12u320_fops);
644
645static struct drm_driver gm12u320_drm_driver = {
646 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
647
648 .name = DRIVER_NAME,
649 .desc = DRIVER_DESC,
650 .date = DRIVER_DATE,
651 .major = DRIVER_MAJOR,
652 .minor = DRIVER_MINOR,
653
654 .release = gm12u320_driver_release,
655 .fops = &gm12u320_fops,
656 DRM_GEM_SHMEM_DRIVER_OPS,
657};
658
659static const struct drm_mode_config_funcs gm12u320_mode_config_funcs = {
660 .fb_create = drm_gem_fb_create_with_dirty,
661 .atomic_check = drm_atomic_helper_check,
662 .atomic_commit = drm_atomic_helper_commit,
663};
664
665static int gm12u320_usb_probe(struct usb_interface *interface,
666 const struct usb_device_id *id)
667{
668 struct gm12u320_device *gm12u320;
669 struct drm_device *dev;
670 int ret;
671
672
673
674
675
676 if (interface->cur_altsetting->desc.bInterfaceNumber != 0)
677 return -ENODEV;
678
679 gm12u320 = kzalloc(sizeof(*gm12u320), GFP_KERNEL);
680 if (gm12u320 == NULL)
681 return -ENOMEM;
682
683 gm12u320->udev = interface_to_usbdev(interface);
684 INIT_WORK(&gm12u320->fb_update.work, gm12u320_fb_update_work);
685 mutex_init(&gm12u320->fb_update.lock);
686 init_waitqueue_head(&gm12u320->fb_update.waitq);
687
688 dev = &gm12u320->dev;
689 ret = drm_dev_init(dev, &gm12u320_drm_driver, &interface->dev);
690 if (ret) {
691 kfree(gm12u320);
692 return ret;
693 }
694 dev->dev_private = gm12u320;
695
696 drm_mode_config_init(dev);
697 dev->mode_config.min_width = GM12U320_USER_WIDTH;
698 dev->mode_config.max_width = GM12U320_USER_WIDTH;
699 dev->mode_config.min_height = GM12U320_HEIGHT;
700 dev->mode_config.max_height = GM12U320_HEIGHT;
701 dev->mode_config.funcs = &gm12u320_mode_config_funcs;
702
703 ret = gm12u320_usb_alloc(gm12u320);
704 if (ret)
705 goto err_put;
706
707 ret = gm12u320_set_ecomode(gm12u320);
708 if (ret)
709 goto err_put;
710
711 ret = gm12u320_conn_init(gm12u320);
712 if (ret)
713 goto err_put;
714
715 ret = drm_simple_display_pipe_init(&gm12u320->dev,
716 &gm12u320->pipe,
717 &gm12u320_pipe_funcs,
718 gm12u320_pipe_formats,
719 ARRAY_SIZE(gm12u320_pipe_formats),
720 gm12u320_pipe_modifiers,
721 &gm12u320->conn);
722 if (ret)
723 goto err_put;
724
725 drm_mode_config_reset(dev);
726
727 usb_set_intfdata(interface, dev);
728 ret = drm_dev_register(dev, 0);
729 if (ret)
730 goto err_put;
731
732 drm_fbdev_generic_setup(dev, 0);
733
734 return 0;
735
736err_put:
737 drm_dev_put(dev);
738 return ret;
739}
740
741static void gm12u320_usb_disconnect(struct usb_interface *interface)
742{
743 struct drm_device *dev = usb_get_intfdata(interface);
744 struct gm12u320_device *gm12u320 = dev->dev_private;
745
746 gm12u320_stop_fb_update(gm12u320);
747 drm_dev_unplug(dev);
748 drm_dev_put(dev);
749}
750
751static __maybe_unused int gm12u320_suspend(struct usb_interface *interface,
752 pm_message_t message)
753{
754 struct drm_device *dev = usb_get_intfdata(interface);
755 struct gm12u320_device *gm12u320 = dev->dev_private;
756
757 if (gm12u320->pipe_enabled)
758 gm12u320_stop_fb_update(gm12u320);
759
760 return 0;
761}
762
763static __maybe_unused int gm12u320_resume(struct usb_interface *interface)
764{
765 struct drm_device *dev = usb_get_intfdata(interface);
766 struct gm12u320_device *gm12u320 = dev->dev_private;
767
768 gm12u320_set_ecomode(gm12u320);
769 if (gm12u320->pipe_enabled)
770 gm12u320_start_fb_update(gm12u320);
771
772 return 0;
773}
774
775static const struct usb_device_id id_table[] = {
776 { USB_DEVICE(0x1de1, 0xc102) },
777 {},
778};
779MODULE_DEVICE_TABLE(usb, id_table);
780
781static struct usb_driver gm12u320_usb_driver = {
782 .name = "gm12u320",
783 .probe = gm12u320_usb_probe,
784 .disconnect = gm12u320_usb_disconnect,
785 .id_table = id_table,
786#ifdef CONFIG_PM
787 .suspend = gm12u320_suspend,
788 .resume = gm12u320_resume,
789 .reset_resume = gm12u320_resume,
790#endif
791};
792
793module_usb_driver(gm12u320_usb_driver);
794MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
795MODULE_LICENSE("GPL");
796