cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gm12u320.c (22664B)


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