linux/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * linux/drivers/video/omap2/omapfb-ioctl.c
   4 *
   5 * Copyright (C) 2008 Nokia Corporation
   6 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
   7 *
   8 * Some code and ideas taken from drivers/video/omap/ driver
   9 * by Imre Deak.
  10 */
  11
  12#include <linux/fb.h>
  13#include <linux/device.h>
  14#include <linux/uaccess.h>
  15#include <linux/platform_device.h>
  16#include <linux/mm.h>
  17#include <linux/omapfb.h>
  18#include <linux/vmalloc.h>
  19#include <linux/export.h>
  20#include <linux/sizes.h>
  21
  22#include <video/omapfb_dss.h>
  23#include <video/omapvrfb.h>
  24
  25#include "omapfb.h"
  26
  27static u8 get_mem_idx(struct omapfb_info *ofbi)
  28{
  29        if (ofbi->id == ofbi->region->id)
  30                return 0;
  31
  32        return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id;
  33}
  34
  35static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi,
  36                                                 u8 mem_idx)
  37{
  38        struct omapfb2_device *fbdev = ofbi->fbdev;
  39
  40        if (mem_idx & OMAPFB_MEM_IDX_ENABLED)
  41                mem_idx &= OMAPFB_MEM_IDX_MASK;
  42        else
  43                mem_idx = ofbi->id;
  44
  45        if (mem_idx >= fbdev->num_fbs)
  46                return NULL;
  47
  48        return &fbdev->regions[mem_idx];
  49}
  50
  51static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
  52{
  53        struct omapfb_info *ofbi = FB2OFB(fbi);
  54        struct omapfb2_device *fbdev = ofbi->fbdev;
  55        struct omap_overlay *ovl;
  56        struct omap_overlay_info old_info;
  57        struct omapfb2_mem_region *old_rg, *new_rg;
  58        int r = 0;
  59
  60        DBG("omapfb_setup_plane\n");
  61
  62        if (ofbi->num_overlays == 0) {
  63                r = -EINVAL;
  64                goto out;
  65        }
  66
  67        /* XXX uses only the first overlay */
  68        ovl = ofbi->overlays[0];
  69
  70        old_rg = ofbi->region;
  71        new_rg = get_mem_region(ofbi, pi->mem_idx);
  72        if (!new_rg) {
  73                r = -EINVAL;
  74                goto out;
  75        }
  76
  77        /* Take the locks in a specific order to keep lockdep happy */
  78        if (old_rg->id < new_rg->id) {
  79                omapfb_get_mem_region(old_rg);
  80                omapfb_get_mem_region(new_rg);
  81        } else if (new_rg->id < old_rg->id) {
  82                omapfb_get_mem_region(new_rg);
  83                omapfb_get_mem_region(old_rg);
  84        } else
  85                omapfb_get_mem_region(old_rg);
  86
  87        if (pi->enabled && !new_rg->size) {
  88                /*
  89                 * This plane's memory was freed, can't enable it
  90                 * until it's reallocated.
  91                 */
  92                r = -EINVAL;
  93                goto put_mem;
  94        }
  95
  96        ovl->get_overlay_info(ovl, &old_info);
  97
  98        if (old_rg != new_rg) {
  99                ofbi->region = new_rg;
 100                set_fb_fix(fbi);
 101        }
 102
 103        if (!pi->enabled) {
 104                r = ovl->disable(ovl);
 105                if (r)
 106                        goto undo;
 107        }
 108
 109        if (pi->enabled) {
 110                r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y,
 111                        pi->out_width, pi->out_height);
 112                if (r)
 113                        goto undo;
 114        } else {
 115                struct omap_overlay_info info;
 116
 117                ovl->get_overlay_info(ovl, &info);
 118
 119                info.pos_x = pi->pos_x;
 120                info.pos_y = pi->pos_y;
 121                info.out_width = pi->out_width;
 122                info.out_height = pi->out_height;
 123
 124                r = ovl->set_overlay_info(ovl, &info);
 125                if (r)
 126                        goto undo;
 127        }
 128
 129        if (ovl->manager) {
 130                r = ovl->manager->apply(ovl->manager);
 131                if (r)
 132                        goto undo;
 133        }
 134
 135        if (pi->enabled) {
 136                r = ovl->enable(ovl);
 137                if (r)
 138                        goto undo;
 139        }
 140
 141        /* Release the locks in a specific order to keep lockdep happy */
 142        if (old_rg->id > new_rg->id) {
 143                omapfb_put_mem_region(old_rg);
 144                omapfb_put_mem_region(new_rg);
 145        } else if (new_rg->id > old_rg->id) {
 146                omapfb_put_mem_region(new_rg);
 147                omapfb_put_mem_region(old_rg);
 148        } else
 149                omapfb_put_mem_region(old_rg);
 150
 151        return 0;
 152
 153 undo:
 154        if (old_rg != new_rg) {
 155                ofbi->region = old_rg;
 156                set_fb_fix(fbi);
 157        }
 158
 159        ovl->set_overlay_info(ovl, &old_info);
 160 put_mem:
 161        /* Release the locks in a specific order to keep lockdep happy */
 162        if (old_rg->id > new_rg->id) {
 163                omapfb_put_mem_region(old_rg);
 164                omapfb_put_mem_region(new_rg);
 165        } else if (new_rg->id > old_rg->id) {
 166                omapfb_put_mem_region(new_rg);
 167                omapfb_put_mem_region(old_rg);
 168        } else
 169                omapfb_put_mem_region(old_rg);
 170 out:
 171        dev_err(fbdev->dev, "setup_plane failed\n");
 172
 173        return r;
 174}
 175
 176static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
 177{
 178        struct omapfb_info *ofbi = FB2OFB(fbi);
 179
 180        if (ofbi->num_overlays == 0) {
 181                memset(pi, 0, sizeof(*pi));
 182        } else {
 183                struct omap_overlay *ovl;
 184                struct omap_overlay_info ovli;
 185
 186                ovl = ofbi->overlays[0];
 187                ovl->get_overlay_info(ovl, &ovli);
 188
 189                pi->pos_x = ovli.pos_x;
 190                pi->pos_y = ovli.pos_y;
 191                pi->enabled = ovl->is_enabled(ovl);
 192                pi->channel_out = 0; /* xxx */
 193                pi->mirror = 0;
 194                pi->mem_idx = get_mem_idx(ofbi);
 195                pi->out_width = ovli.out_width;
 196                pi->out_height = ovli.out_height;
 197        }
 198
 199        return 0;
 200}
 201
 202static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
 203{
 204        struct omapfb_info *ofbi = FB2OFB(fbi);
 205        struct omapfb2_device *fbdev = ofbi->fbdev;
 206        struct omap_dss_device *display = fb2display(fbi);
 207        struct omapfb2_mem_region *rg;
 208        int r = 0, i;
 209        size_t size;
 210
 211        if (mi->type != OMAPFB_MEMTYPE_SDRAM)
 212                return -EINVAL;
 213
 214        size = PAGE_ALIGN(mi->size);
 215
 216        if (display && display->driver->sync)
 217                display->driver->sync(display);
 218
 219        rg = ofbi->region;
 220
 221        down_write_nested(&rg->lock, rg->id);
 222        atomic_inc(&rg->lock_count);
 223
 224        if (rg->size == size && rg->type == mi->type)
 225                goto out;
 226
 227        if (atomic_read(&rg->map_count)) {
 228                r = -EBUSY;
 229                goto out;
 230        }
 231
 232        for (i = 0; i < fbdev->num_fbs; i++) {
 233                struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
 234                int j;
 235
 236                if (ofbi2->region != rg)
 237                        continue;
 238
 239                for (j = 0; j < ofbi2->num_overlays; j++) {
 240                        struct omap_overlay *ovl;
 241                        ovl = ofbi2->overlays[j];
 242                        if (ovl->is_enabled(ovl)) {
 243                                r = -EBUSY;
 244                                goto out;
 245                        }
 246                }
 247        }
 248
 249        r = omapfb_realloc_fbmem(fbi, size, mi->type);
 250        if (r) {
 251                dev_err(fbdev->dev, "realloc fbmem failed\n");
 252                goto out;
 253        }
 254
 255 out:
 256        atomic_dec(&rg->lock_count);
 257        up_write(&rg->lock);
 258
 259        return r;
 260}
 261
 262static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
 263{
 264        struct omapfb_info *ofbi = FB2OFB(fbi);
 265        struct omapfb2_mem_region *rg;
 266
 267        rg = omapfb_get_mem_region(ofbi->region);
 268        memset(mi, 0, sizeof(*mi));
 269
 270        mi->size = rg->size;
 271        mi->type = rg->type;
 272
 273        omapfb_put_mem_region(rg);
 274
 275        return 0;
 276}
 277
 278static int omapfb_update_window(struct fb_info *fbi,
 279                u32 x, u32 y, u32 w, u32 h)
 280{
 281        struct omap_dss_device *display = fb2display(fbi);
 282        u16 dw, dh;
 283
 284        if (!display)
 285                return 0;
 286
 287        if (w == 0 || h == 0)
 288                return 0;
 289
 290        display->driver->get_resolution(display, &dw, &dh);
 291
 292        if (x + w > dw || y + h > dh)
 293                return -EINVAL;
 294
 295        return display->driver->update(display, x, y, w, h);
 296}
 297
 298int omapfb_set_update_mode(struct fb_info *fbi,
 299                                   enum omapfb_update_mode mode)
 300{
 301        struct omap_dss_device *display = fb2display(fbi);
 302        struct omapfb_info *ofbi = FB2OFB(fbi);
 303        struct omapfb2_device *fbdev = ofbi->fbdev;
 304        struct omapfb_display_data *d;
 305        int r;
 306
 307        if (!display)
 308                return -EINVAL;
 309
 310        if (mode != OMAPFB_AUTO_UPDATE && mode != OMAPFB_MANUAL_UPDATE)
 311                return -EINVAL;
 312
 313        omapfb_lock(fbdev);
 314
 315        d = get_display_data(fbdev, display);
 316
 317        if (d->update_mode == mode) {
 318                omapfb_unlock(fbdev);
 319                return 0;
 320        }
 321
 322        r = 0;
 323
 324        if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
 325                if (mode == OMAPFB_AUTO_UPDATE)
 326                        omapfb_start_auto_update(fbdev, display);
 327                else /* MANUAL_UPDATE */
 328                        omapfb_stop_auto_update(fbdev, display);
 329
 330                d->update_mode = mode;
 331        } else { /* AUTO_UPDATE */
 332                if (mode == OMAPFB_MANUAL_UPDATE)
 333                        r = -EINVAL;
 334        }
 335
 336        omapfb_unlock(fbdev);
 337
 338        return r;
 339}
 340
 341int omapfb_get_update_mode(struct fb_info *fbi,
 342                enum omapfb_update_mode *mode)
 343{
 344        struct omap_dss_device *display = fb2display(fbi);
 345        struct omapfb_info *ofbi = FB2OFB(fbi);
 346        struct omapfb2_device *fbdev = ofbi->fbdev;
 347        struct omapfb_display_data *d;
 348
 349        if (!display)
 350                return -EINVAL;
 351
 352        omapfb_lock(fbdev);
 353
 354        d = get_display_data(fbdev, display);
 355
 356        *mode = d->update_mode;
 357
 358        omapfb_unlock(fbdev);
 359
 360        return 0;
 361}
 362
 363/* XXX this color key handling is a hack... */
 364static struct omapfb_color_key omapfb_color_keys[2];
 365
 366static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,
 367                struct omapfb_color_key *ck)
 368{
 369        struct omap_overlay_manager_info info;
 370        enum omap_dss_trans_key_type kt;
 371        int r;
 372
 373        mgr->get_manager_info(mgr, &info);
 374
 375        if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {
 376                info.trans_enabled = false;
 377                omapfb_color_keys[mgr->id] = *ck;
 378
 379                r = mgr->set_manager_info(mgr, &info);
 380                if (r)
 381                        return r;
 382
 383                r = mgr->apply(mgr);
 384
 385                return r;
 386        }
 387
 388        switch (ck->key_type) {
 389        case OMAPFB_COLOR_KEY_GFX_DST:
 390                kt = OMAP_DSS_COLOR_KEY_GFX_DST;
 391                break;
 392        case OMAPFB_COLOR_KEY_VID_SRC:
 393                kt = OMAP_DSS_COLOR_KEY_VID_SRC;
 394                break;
 395        default:
 396                return -EINVAL;
 397        }
 398
 399        info.default_color = ck->background;
 400        info.trans_key = ck->trans_key;
 401        info.trans_key_type = kt;
 402        info.trans_enabled = true;
 403
 404        omapfb_color_keys[mgr->id] = *ck;
 405
 406        r = mgr->set_manager_info(mgr, &info);
 407        if (r)
 408                return r;
 409
 410        r = mgr->apply(mgr);
 411
 412        return r;
 413}
 414
 415static int omapfb_set_color_key(struct fb_info *fbi,
 416                struct omapfb_color_key *ck)
 417{
 418        struct omapfb_info *ofbi = FB2OFB(fbi);
 419        struct omapfb2_device *fbdev = ofbi->fbdev;
 420        int r;
 421        int i;
 422        struct omap_overlay_manager *mgr = NULL;
 423
 424        omapfb_lock(fbdev);
 425
 426        for (i = 0; i < ofbi->num_overlays; i++) {
 427                if (ofbi->overlays[i]->manager) {
 428                        mgr = ofbi->overlays[i]->manager;
 429                        break;
 430                }
 431        }
 432
 433        if (!mgr) {
 434                r = -EINVAL;
 435                goto err;
 436        }
 437
 438        r = _omapfb_set_color_key(mgr, ck);
 439err:
 440        omapfb_unlock(fbdev);
 441
 442        return r;
 443}
 444
 445static int omapfb_get_color_key(struct fb_info *fbi,
 446                struct omapfb_color_key *ck)
 447{
 448        struct omapfb_info *ofbi = FB2OFB(fbi);
 449        struct omapfb2_device *fbdev = ofbi->fbdev;
 450        struct omap_overlay_manager *mgr = NULL;
 451        int r = 0;
 452        int i;
 453
 454        omapfb_lock(fbdev);
 455
 456        for (i = 0; i < ofbi->num_overlays; i++) {
 457                if (ofbi->overlays[i]->manager) {
 458                        mgr = ofbi->overlays[i]->manager;
 459                        break;
 460                }
 461        }
 462
 463        if (!mgr) {
 464                r = -EINVAL;
 465                goto err;
 466        }
 467
 468        *ck = omapfb_color_keys[mgr->id];
 469err:
 470        omapfb_unlock(fbdev);
 471
 472        return r;
 473}
 474
 475static int omapfb_memory_read(struct fb_info *fbi,
 476                struct omapfb_memory_read *mr)
 477{
 478        struct omap_dss_device *display = fb2display(fbi);
 479        void *buf;
 480        int r;
 481
 482        if (!display || !display->driver->memory_read)
 483                return -ENOENT;
 484
 485        if (mr->w > 4096 || mr->h > 4096)
 486                return -EINVAL;
 487
 488        if (mr->w * mr->h * 3 > mr->buffer_size)
 489                return -EINVAL;
 490
 491        buf = vmalloc(mr->buffer_size);
 492        if (!buf) {
 493                DBG("vmalloc failed\n");
 494                return -ENOMEM;
 495        }
 496
 497        r = display->driver->memory_read(display, buf, mr->buffer_size,
 498                        mr->x, mr->y, mr->w, mr->h);
 499
 500        if (r > 0) {
 501                if (copy_to_user(mr->buffer, buf, r))
 502                        r = -EFAULT;
 503        }
 504
 505        vfree(buf);
 506
 507        return r;
 508}
 509
 510static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,
 511                             struct omapfb_ovl_colormode *mode)
 512{
 513        int ovl_idx = mode->overlay_idx;
 514        int mode_idx = mode->mode_idx;
 515        struct omap_overlay *ovl;
 516        enum omap_color_mode supported_modes;
 517        struct fb_var_screeninfo var;
 518        int i;
 519
 520        if (ovl_idx >= fbdev->num_overlays)
 521                return -ENODEV;
 522        ovl = fbdev->overlays[ovl_idx];
 523        supported_modes = ovl->supported_modes;
 524
 525        mode_idx = mode->mode_idx;
 526
 527        for (i = 0; i < sizeof(supported_modes) * 8; i++) {
 528                if (!(supported_modes & (1 << i)))
 529                        continue;
 530                /*
 531                 * It's possible that the FB doesn't support a mode
 532                 * that is supported by the overlay, so call the
 533                 * following here.
 534                 */
 535                if (dss_mode_to_fb_mode(1 << i, &var) < 0)
 536                        continue;
 537
 538                mode_idx--;
 539                if (mode_idx < 0)
 540                        break;
 541        }
 542
 543        if (i == sizeof(supported_modes) * 8)
 544                return -ENOENT;
 545
 546        mode->bits_per_pixel = var.bits_per_pixel;
 547        mode->nonstd = var.nonstd;
 548        mode->red = var.red;
 549        mode->green = var.green;
 550        mode->blue = var.blue;
 551        mode->transp = var.transp;
 552
 553        return 0;
 554}
 555
 556static int omapfb_wait_for_go(struct fb_info *fbi)
 557{
 558        struct omapfb_info *ofbi = FB2OFB(fbi);
 559        int r = 0;
 560        int i;
 561
 562        for (i = 0; i < ofbi->num_overlays; ++i) {
 563                struct omap_overlay *ovl = ofbi->overlays[i];
 564                r = ovl->wait_for_go(ovl);
 565                if (r)
 566                        break;
 567        }
 568
 569        return r;
 570}
 571
 572int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
 573{
 574        struct omapfb_info *ofbi = FB2OFB(fbi);
 575        struct omapfb2_device *fbdev = ofbi->fbdev;
 576        struct omap_dss_device *display = fb2display(fbi);
 577        struct omap_overlay_manager *mgr;
 578
 579        union {
 580                struct omapfb_update_window_old uwnd_o;
 581                struct omapfb_update_window     uwnd;
 582                struct omapfb_plane_info        plane_info;
 583                struct omapfb_caps              caps;
 584                struct omapfb_mem_info          mem_info;
 585                struct omapfb_color_key         color_key;
 586                struct omapfb_ovl_colormode     ovl_colormode;
 587                enum omapfb_update_mode         update_mode;
 588                int test_num;
 589                struct omapfb_memory_read       memory_read;
 590                struct omapfb_vram_info         vram_info;
 591                struct omapfb_tearsync_info     tearsync_info;
 592                struct omapfb_display_info      display_info;
 593                u32                             crt;
 594        } p;
 595
 596        int r = 0;
 597
 598        memset(&p, 0, sizeof(p));
 599
 600        switch (cmd) {
 601        case OMAPFB_SYNC_GFX:
 602                DBG("ioctl SYNC_GFX\n");
 603                if (!display || !display->driver->sync) {
 604                        /* DSS1 never returns an error here, so we neither */
 605                        /*r = -EINVAL;*/
 606                        break;
 607                }
 608
 609                r = display->driver->sync(display);
 610                break;
 611
 612        case OMAPFB_UPDATE_WINDOW_OLD:
 613                DBG("ioctl UPDATE_WINDOW_OLD\n");
 614                if (!display || !display->driver->update) {
 615                        r = -EINVAL;
 616                        break;
 617                }
 618
 619                if (copy_from_user(&p.uwnd_o,
 620                                        (void __user *)arg,
 621                                        sizeof(p.uwnd_o))) {
 622                        r = -EFAULT;
 623                        break;
 624                }
 625
 626                r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y,
 627                                p.uwnd_o.width, p.uwnd_o.height);
 628                break;
 629
 630        case OMAPFB_UPDATE_WINDOW:
 631                DBG("ioctl UPDATE_WINDOW\n");
 632                if (!display || !display->driver->update) {
 633                        r = -EINVAL;
 634                        break;
 635                }
 636
 637                if (copy_from_user(&p.uwnd, (void __user *)arg,
 638                                        sizeof(p.uwnd))) {
 639                        r = -EFAULT;
 640                        break;
 641                }
 642
 643                r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y,
 644                                p.uwnd.width, p.uwnd.height);
 645                break;
 646
 647        case OMAPFB_SETUP_PLANE:
 648                DBG("ioctl SETUP_PLANE\n");
 649                if (copy_from_user(&p.plane_info, (void __user *)arg,
 650                                        sizeof(p.plane_info)))
 651                        r = -EFAULT;
 652                else
 653                        r = omapfb_setup_plane(fbi, &p.plane_info);
 654                break;
 655
 656        case OMAPFB_QUERY_PLANE:
 657                DBG("ioctl QUERY_PLANE\n");
 658                r = omapfb_query_plane(fbi, &p.plane_info);
 659                if (r < 0)
 660                        break;
 661                if (copy_to_user((void __user *)arg, &p.plane_info,
 662                                        sizeof(p.plane_info)))
 663                        r = -EFAULT;
 664                break;
 665
 666        case OMAPFB_SETUP_MEM:
 667                DBG("ioctl SETUP_MEM\n");
 668                if (copy_from_user(&p.mem_info, (void __user *)arg,
 669                                        sizeof(p.mem_info)))
 670                        r = -EFAULT;
 671                else
 672                        r = omapfb_setup_mem(fbi, &p.mem_info);
 673                break;
 674
 675        case OMAPFB_QUERY_MEM:
 676                DBG("ioctl QUERY_MEM\n");
 677                r = omapfb_query_mem(fbi, &p.mem_info);
 678                if (r < 0)
 679                        break;
 680                if (copy_to_user((void __user *)arg, &p.mem_info,
 681                                        sizeof(p.mem_info)))
 682                        r = -EFAULT;
 683                break;
 684
 685        case OMAPFB_GET_CAPS:
 686                DBG("ioctl GET_CAPS\n");
 687                if (!display) {
 688                        r = -EINVAL;
 689                        break;
 690                }
 691
 692                memset(&p.caps, 0, sizeof(p.caps));
 693                if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)
 694                        p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;
 695                if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)
 696                        p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;
 697
 698                if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))
 699                        r = -EFAULT;
 700                break;
 701
 702        case OMAPFB_GET_OVERLAY_COLORMODE:
 703                DBG("ioctl GET_OVERLAY_COLORMODE\n");
 704                if (copy_from_user(&p.ovl_colormode, (void __user *)arg,
 705                                   sizeof(p.ovl_colormode))) {
 706                        r = -EFAULT;
 707                        break;
 708                }
 709                r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);
 710                if (r < 0)
 711                        break;
 712                if (copy_to_user((void __user *)arg, &p.ovl_colormode,
 713                                 sizeof(p.ovl_colormode)))
 714                        r = -EFAULT;
 715                break;
 716
 717        case OMAPFB_SET_UPDATE_MODE:
 718                DBG("ioctl SET_UPDATE_MODE\n");
 719                if (get_user(p.update_mode, (int __user *)arg))
 720                        r = -EFAULT;
 721                else
 722                        r = omapfb_set_update_mode(fbi, p.update_mode);
 723                break;
 724
 725        case OMAPFB_GET_UPDATE_MODE:
 726                DBG("ioctl GET_UPDATE_MODE\n");
 727                r = omapfb_get_update_mode(fbi, &p.update_mode);
 728                if (r)
 729                        break;
 730                if (put_user(p.update_mode,
 731                                        (enum omapfb_update_mode __user *)arg))
 732                        r = -EFAULT;
 733                break;
 734
 735        case OMAPFB_SET_COLOR_KEY:
 736                DBG("ioctl SET_COLOR_KEY\n");
 737                if (copy_from_user(&p.color_key, (void __user *)arg,
 738                                   sizeof(p.color_key)))
 739                        r = -EFAULT;
 740                else
 741                        r = omapfb_set_color_key(fbi, &p.color_key);
 742                break;
 743
 744        case OMAPFB_GET_COLOR_KEY:
 745                DBG("ioctl GET_COLOR_KEY\n");
 746                r = omapfb_get_color_key(fbi, &p.color_key);
 747                if (r)
 748                        break;
 749                if (copy_to_user((void __user *)arg, &p.color_key,
 750                                 sizeof(p.color_key)))
 751                        r = -EFAULT;
 752                break;
 753
 754        case FBIO_WAITFORVSYNC:
 755                if (get_user(p.crt, (__u32 __user *)arg)) {
 756                        r = -EFAULT;
 757                        break;
 758                }
 759                if (p.crt != 0) {
 760                        r = -ENODEV;
 761                        break;
 762                }
 763                fallthrough;
 764
 765        case OMAPFB_WAITFORVSYNC:
 766                DBG("ioctl WAITFORVSYNC\n");
 767
 768                if (!display) {
 769                        r = -EINVAL;
 770                        break;
 771                }
 772
 773                mgr = omapdss_find_mgr_from_display(display);
 774                if (!mgr) {
 775                        r = -EINVAL;
 776                        break;
 777                }
 778
 779                r = mgr->wait_for_vsync(mgr);
 780                break;
 781
 782        case OMAPFB_WAITFORGO:
 783                DBG("ioctl WAITFORGO\n");
 784                if (!display) {
 785                        r = -EINVAL;
 786                        break;
 787                }
 788
 789                r = omapfb_wait_for_go(fbi);
 790                break;
 791
 792        /* LCD and CTRL tests do the same thing for backward
 793         * compatibility */
 794        case OMAPFB_LCD_TEST:
 795                DBG("ioctl LCD_TEST\n");
 796                if (get_user(p.test_num, (int __user *)arg)) {
 797                        r = -EFAULT;
 798                        break;
 799                }
 800                if (!display || !display->driver->run_test) {
 801                        r = -EINVAL;
 802                        break;
 803                }
 804
 805                r = display->driver->run_test(display, p.test_num);
 806
 807                break;
 808
 809        case OMAPFB_CTRL_TEST:
 810                DBG("ioctl CTRL_TEST\n");
 811                if (get_user(p.test_num, (int __user *)arg)) {
 812                        r = -EFAULT;
 813                        break;
 814                }
 815                if (!display || !display->driver->run_test) {
 816                        r = -EINVAL;
 817                        break;
 818                }
 819
 820                r = display->driver->run_test(display, p.test_num);
 821
 822                break;
 823
 824        case OMAPFB_MEMORY_READ:
 825                DBG("ioctl MEMORY_READ\n");
 826
 827                if (copy_from_user(&p.memory_read, (void __user *)arg,
 828                                        sizeof(p.memory_read))) {
 829                        r = -EFAULT;
 830                        break;
 831                }
 832
 833                r = omapfb_memory_read(fbi, &p.memory_read);
 834
 835                break;
 836
 837        case OMAPFB_GET_VRAM_INFO: {
 838                DBG("ioctl GET_VRAM_INFO\n");
 839
 840                /*
 841                 * We don't have the ability to get this vram info anymore.
 842                 * Fill in something that should keep the applications working.
 843                 */
 844                p.vram_info.total = SZ_1M * 64;
 845                p.vram_info.free = SZ_1M * 64;
 846                p.vram_info.largest_free_block = SZ_1M * 64;
 847
 848                if (copy_to_user((void __user *)arg, &p.vram_info,
 849                                        sizeof(p.vram_info)))
 850                        r = -EFAULT;
 851                break;
 852        }
 853
 854        case OMAPFB_SET_TEARSYNC: {
 855                DBG("ioctl SET_TEARSYNC\n");
 856
 857                if (copy_from_user(&p.tearsync_info, (void __user *)arg,
 858                                        sizeof(p.tearsync_info))) {
 859                        r = -EFAULT;
 860                        break;
 861                }
 862
 863                if (!display || !display->driver->enable_te) {
 864                        r = -ENODEV;
 865                        break;
 866                }
 867
 868                r = display->driver->enable_te(display,
 869                                !!p.tearsync_info.enabled);
 870
 871                break;
 872        }
 873
 874        case OMAPFB_GET_DISPLAY_INFO: {
 875                u16 xres, yres;
 876
 877                DBG("ioctl GET_DISPLAY_INFO\n");
 878
 879                if (display == NULL) {
 880                        r = -ENODEV;
 881                        break;
 882                }
 883
 884                display->driver->get_resolution(display, &xres, &yres);
 885
 886                p.display_info.xres = xres;
 887                p.display_info.yres = yres;
 888
 889                if (display->driver->get_dimensions) {
 890                        u32 w, h;
 891                        display->driver->get_dimensions(display, &w, &h);
 892                        p.display_info.width = w;
 893                        p.display_info.height = h;
 894                } else {
 895                        p.display_info.width = 0;
 896                        p.display_info.height = 0;
 897                }
 898
 899                if (copy_to_user((void __user *)arg, &p.display_info,
 900                                        sizeof(p.display_info)))
 901                        r = -EFAULT;
 902                break;
 903        }
 904
 905        default:
 906                dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);
 907                r = -EINVAL;
 908        }
 909
 910        if (r < 0)
 911                DBG("ioctl failed: %d\n", r);
 912
 913        return r;
 914}
 915
 916
 917