linux/drivers/gpu/drm/tiny/gm12u320.c
<<
>>
Prefs
   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_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 * The DLP has an actual width of 854 pixels, but that is not a multiple
  38 * of 8, breaking things left and right, so we export a width of 848.
  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/* Windows driver does once every second, with arg d = 1, other args 0 */
  77#define MISC_REQ_UNKNOWN1_A             0xff
  78#define MISC_REQ_UNKNOWN1_B             0x38
  79/* Windows driver does this on init, with arg a, b = 0, c = 0xa0, d = 4 */
  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        /* Send request */
 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        /* Read value */
 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        /* cmd_buf[0] now contains the read value, which we don't use */
 238
 239        /* Read status */
 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                        /* Send data command to device */
 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                        /* Send data block to device */
 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                        /* Read status */
 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                /* Send draw command to device */
 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                /* Read status */
 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                 * We must draw a frame every 2s otherwise the projector
 414                 * switches back to showing its logo.
 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        /* Do not log errors caused by module unload or device unplug */
 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 /* set */,
 491                                     eco_mode ? 0x01 : 0x00, 0x00, 0x01);
 492}
 493
 494/* ------------------------------------------------------------------ */
 495/* gm12u320 connector                                                 */
 496
 497/*
 498 * We use fake EDID info so that userspace know that it is dealing with
 499 * an Acer projector, rather then listing this as an "unknown" monitor.
 500 * Note this assumes this driver is only ever used with the Acer C120, if we
 501 * add support for other devices the vendor and model should be parameterized.
 502 */
 503static struct edid gm12u320_edid = {
 504        .header         = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 },
 505        .mfg_id         = { 0x04, 0x72 },       /* "ACR" */
 506        .prod_code      = { 0x20, 0xc1 },       /* C120h */
 507        .serial         = 0xaa55aa55,
 508        .mfg_week       = 1,
 509        .mfg_year       = 16,
 510        .version        = 1,                    /* EDID 1.3 */
 511        .revision       = 3,                    /* EDID 1.3 */
 512        .input          = 0x08,                 /* Analog input */
 513        .features       = 0x0a,                 /* Pref timing in DTD 1 */
 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                /* hactive = 848, hblank = 256 */
 519                .data.pixel_data.hactive_lo = 0x50,
 520                .data.pixel_data.hblank_lo = 0x00,
 521                .data.pixel_data.hactive_hblank_hi = 0x31,
 522                /* vactive = 480, vblank = 28 */
 523                .data.pixel_data.vactive_lo = 0xe0,
 524                .data.pixel_data.vblank_lo = 0x1c,
 525                .data.pixel_data.vactive_vblank_hi = 0x10,
 526                /* hsync offset 40 pw 128, vsync offset 1 pw 4 */
 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                /* Digital separate syncs, hsync+, vsync+ */
 532                .data.pixel_data.misc = 0x1e,
 533        }, {
 534                .pixel_clock = 0,
 535                .data.other_data.type = 0xfd, /* Monitor ranges */
 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, /* 40 MHz */
 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, /* Model string */
 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, /* Unspecified text / padding */
 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/* gm12u320 (simple) display pipe                                     */
 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         * The gm12u320 presents itself to the system as 2 usb mass-storage
 674         * interfaces, we only care about / need the first one.
 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