WIP FPC-III support
[linux/fpc-iii.git] / drivers / gpu / drm / tiny / gm12u320.c
blob33f65f4626e5a3cb2e66722aa20a36300d0044d7
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright 2019 Hans de Goede <hdegoede@redhat.com>
4 */
6 #include <linux/dma-buf.h>
7 #include <linux/module.h>
8 #include <linux/usb.h>
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>
27 static bool eco_mode;
28 module_param(eco_mode, bool, 0644);
29 MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)");
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
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.
41 #define GM12U320_USER_WIDTH 848
42 #define GM12U320_REAL_WIDTH 854
43 #define GM12U320_HEIGHT 480
45 #define GM12U320_BLOCK_COUNT 20
47 #define GM12U320_ERR(fmt, ...) \
48 DRM_DEV_ERROR(gm12u320->dev.dev, fmt, ##__VA_ARGS__)
50 #define MISC_RCV_EPT 1
51 #define DATA_RCV_EPT 2
52 #define DATA_SND_EPT 3
53 #define MISC_SND_EPT 4
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)
66 #define CMD_SIZE 31
67 #define READ_STATUS_SIZE 13
68 #define MISC_VALUE_SIZE 4
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)
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
84 struct 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;
100 #define to_gm12u320(__dev) container_of(__dev, struct gm12u320_device, dev)
102 static 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
109 static 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
116 static 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
123 static 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
137 static 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
151 static 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
157 static inline struct usb_device *gm12u320_to_usb_device(struct gm12u320_device *gm12u320)
159 return interface_to_usbdev(to_usb_interface(gm12u320->dev.dev));
162 static int gm12u320_usb_alloc(struct gm12u320_device *gm12u320)
164 int i, block_size;
165 const char *hdr;
167 gm12u320->cmd_buf = drmm_kmalloc(&gm12u320->dev, CMD_SIZE, GFP_KERNEL);
168 if (!gm12u320->cmd_buf)
169 return -ENOMEM;
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;
180 gm12u320->data_buf[i] = drmm_kzalloc(&gm12u320->dev,
181 block_size, GFP_KERNEL);
182 if (!gm12u320->data_buf[i])
183 return -ENOMEM;
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);
191 return 0;
194 static 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)
198 struct usb_device *udev = gm12u320_to_usb_device(gm12u320);
199 int ret, len;
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;
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;
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;
225 /* cmd_buf[0] now contains the read value, which we don't use */
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;
236 return 0;
239 static void gm12u320_32bpp_to_24bpp_packed(u8 *dst, u8 *src, int len)
241 while (len--) {
242 *dst++ = *src++;
243 *dst++ = *src++;
244 *dst++ = *src++;
245 src++;
249 static void gm12u320_copy_fb_to_blocks(struct gm12u320_device *gm12u320)
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;
257 mutex_lock(&gm12u320->fb_update.lock);
259 if (!gm12u320->fb_update.fb)
260 goto unlock;
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;
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;
273 vaddr = map.vaddr; /* TODO: Use mapping abstraction properly */
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;
284 src = vaddr + y1 * fb->pitches[0] + x1 * 4;
286 x1 += (GM12U320_REAL_WIDTH - GM12U320_USER_WIDTH) / 2;
287 x2 += (GM12U320_REAL_WIDTH - GM12U320_USER_WIDTH) / 2;
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;
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;
301 dst_offset += DATA_BLOCK_HEADER_SIZE;
302 len /= 3;
304 gm12u320_32bpp_to_24bpp_packed(
305 gm12u320->data_buf[block] + dst_offset,
306 src, len);
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);
315 src += fb->pitches[0];
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);
324 vunmap:
325 drm_gem_shmem_vunmap(fb->obj[0], &map);
326 put_fb:
327 drm_framebuffer_put(fb);
328 gm12u320->fb_update.fb = NULL;
329 unlock:
330 mutex_unlock(&gm12u320->fb_update.lock);
333 static void gm12u320_fb_update_work(struct work_struct *work)
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;
342 gm12u320_copy_fb_to_blocks(gm12u320);
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;
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);
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;
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;
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;
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;
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;
396 gm12u320->fb_update.draw_status_timeout = CMD_TIMEOUT;
397 gm12u320->fb_update.frame = !gm12u320->fb_update.frame;
400 * We must draw a frame every 2s otherwise the projector
401 * switches back to showing its logo.
403 queue_delayed_work(system_long_wq, &gm12u320->fb_update.work,
404 IDLE_TIMEOUT);
406 return;
407 err:
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);
413 static void gm12u320_fb_mark_dirty(struct drm_framebuffer *fb,
414 struct drm_rect *dirty)
416 struct gm12u320_device *gm12u320 = to_gm12u320(fb->dev);
417 struct drm_framebuffer *old_fb = NULL;
418 bool wakeup = false;
420 mutex_lock(&gm12u320->fb_update.lock);
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;
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);
437 mutex_unlock(&gm12u320->fb_update.lock);
439 if (wakeup)
440 mod_delayed_work(system_long_wq, &gm12u320->fb_update.work, 0);
442 if (old_fb)
443 drm_framebuffer_put(old_fb);
446 static void gm12u320_stop_fb_update(struct gm12u320_device *gm12u320)
448 struct drm_framebuffer *old_fb;
450 cancel_delayed_work_sync(&gm12u320->fb_update.work);
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);
457 drm_framebuffer_put(old_fb);
460 static int gm12u320_set_ecomode(struct gm12u320_device *gm12u320)
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);
467 /* ------------------------------------------------------------------ */
468 /* gm12u320 connector */
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.
476 static 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,
533 static int gm12u320_conn_get_modes(struct drm_connector *connector)
535 drm_connector_update_edid_property(connector, &gm12u320_edid);
536 return drm_add_edid_modes(connector, &gm12u320_edid);
539 static const struct drm_connector_helper_funcs gm12u320_conn_helper_funcs = {
540 .get_modes = gm12u320_conn_get_modes,
543 static 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,
551 static int gm12u320_conn_init(struct gm12u320_device *gm12u320)
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);
558 /* ------------------------------------------------------------------ */
559 /* gm12u320 (simple) display pipe */
561 static void gm12u320_pipe_enable(struct drm_simple_display_pipe *pipe,
562 struct drm_crtc_state *crtc_state,
563 struct drm_plane_state *plane_state)
565 struct drm_rect rect = { 0, 0, GM12U320_USER_WIDTH, GM12U320_HEIGHT };
566 struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev);
568 gm12u320->fb_update.draw_status_timeout = FIRST_FRAME_TIMEOUT;
569 gm12u320_fb_mark_dirty(plane_state->fb, &rect);
572 static void gm12u320_pipe_disable(struct drm_simple_display_pipe *pipe)
574 struct gm12u320_device *gm12u320 = to_gm12u320(pipe->crtc.dev);
576 gm12u320_stop_fb_update(gm12u320);
579 static void gm12u320_pipe_update(struct drm_simple_display_pipe *pipe,
580 struct drm_plane_state *old_state)
582 struct drm_plane_state *state = pipe->plane.state;
583 struct drm_rect rect;
585 if (drm_atomic_helper_damage_merged(old_state, state, &rect))
586 gm12u320_fb_mark_dirty(pipe->plane.state->fb, &rect);
589 static 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,
595 static const uint32_t gm12u320_pipe_formats[] = {
596 DRM_FORMAT_XRGB8888,
599 static const uint64_t gm12u320_pipe_modifiers[] = {
600 DRM_FORMAT_MOD_LINEAR,
601 DRM_FORMAT_MOD_INVALID
604 DEFINE_DRM_GEM_FOPS(gm12u320_fops);
606 static const struct drm_driver gm12u320_drm_driver = {
607 .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_ATOMIC,
609 .name = DRIVER_NAME,
610 .desc = DRIVER_DESC,
611 .date = DRIVER_DATE,
612 .major = DRIVER_MAJOR,
613 .minor = DRIVER_MINOR,
615 .fops = &gm12u320_fops,
616 DRM_GEM_SHMEM_DRIVER_OPS,
619 static 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,
625 static int gm12u320_usb_probe(struct usb_interface *interface,
626 const struct usb_device_id *id)
628 struct gm12u320_device *gm12u320;
629 struct drm_device *dev;
630 int ret;
633 * The gm12u320 presents itself to the system as 2 usb mass-storage
634 * interfaces, we only care about / need the first one.
636 if (interface->cur_altsetting->desc.bInterfaceNumber != 0)
637 return -ENODEV;
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);
644 INIT_DELAYED_WORK(&gm12u320->fb_update.work, gm12u320_fb_update_work);
645 mutex_init(&gm12u320->fb_update.lock);
647 dev = &gm12u320->dev;
649 ret = drmm_mode_config_init(dev);
650 if (ret)
651 return ret;
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;
659 ret = gm12u320_usb_alloc(gm12u320);
660 if (ret)
661 return ret;
663 ret = gm12u320_set_ecomode(gm12u320);
664 if (ret)
665 return ret;
667 ret = gm12u320_conn_init(gm12u320);
668 if (ret)
669 return ret;
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;
681 drm_mode_config_reset(dev);
683 usb_set_intfdata(interface, dev);
684 ret = drm_dev_register(dev, 0);
685 if (ret)
686 return ret;
688 drm_fbdev_generic_setup(dev, 0);
690 return 0;
693 static void gm12u320_usb_disconnect(struct usb_interface *interface)
695 struct drm_device *dev = usb_get_intfdata(interface);
697 drm_dev_unplug(dev);
698 drm_atomic_helper_shutdown(dev);
701 static __maybe_unused int gm12u320_suspend(struct usb_interface *interface,
702 pm_message_t message)
704 struct drm_device *dev = usb_get_intfdata(interface);
706 return drm_mode_config_helper_suspend(dev);
709 static __maybe_unused int gm12u320_resume(struct usb_interface *interface)
711 struct drm_device *dev = usb_get_intfdata(interface);
712 struct gm12u320_device *gm12u320 = to_gm12u320(dev);
714 gm12u320_set_ecomode(gm12u320);
716 return drm_mode_config_helper_resume(dev);
719 static const struct usb_device_id id_table[] = {
720 { USB_DEVICE(0x1de1, 0xc102) },
723 MODULE_DEVICE_TABLE(usb, id_table);
725 static 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
737 module_usb_driver(gm12u320_usb_driver);
738 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
739 MODULE_LICENSE("GPL");