linux/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * linux/drivers/video/omap2/omapfb-sysfs.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/sysfs.h>
  14#include <linux/device.h>
  15#include <linux/uaccess.h>
  16#include <linux/platform_device.h>
  17#include <linux/kernel.h>
  18#include <linux/mm.h>
  19#include <linux/omapfb.h>
  20
  21#include <video/omapfb_dss.h>
  22#include <video/omapvrfb.h>
  23
  24#include "omapfb.h"
  25
  26static ssize_t show_rotate_type(struct device *dev,
  27                struct device_attribute *attr, char *buf)
  28{
  29        struct fb_info *fbi = dev_get_drvdata(dev);
  30        struct omapfb_info *ofbi = FB2OFB(fbi);
  31
  32        return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);
  33}
  34
  35static ssize_t store_rotate_type(struct device *dev,
  36                struct device_attribute *attr,
  37                const char *buf, size_t count)
  38{
  39        struct fb_info *fbi = dev_get_drvdata(dev);
  40        struct omapfb_info *ofbi = FB2OFB(fbi);
  41        struct omapfb2_mem_region *rg;
  42        int rot_type;
  43        int r;
  44
  45        r = kstrtoint(buf, 0, &rot_type);
  46        if (r)
  47                return r;
  48
  49        if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
  50                return -EINVAL;
  51
  52        lock_fb_info(fbi);
  53
  54        r = 0;
  55        if (rot_type == ofbi->rotation_type)
  56                goto out;
  57
  58        rg = omapfb_get_mem_region(ofbi->region);
  59
  60        if (rg->size) {
  61                r = -EBUSY;
  62                goto put_region;
  63        }
  64
  65        ofbi->rotation_type = rot_type;
  66
  67        /*
  68         * Since the VRAM for this FB is not allocated at the moment we don't
  69         * need to do any further parameter checking at this point.
  70         */
  71put_region:
  72        omapfb_put_mem_region(rg);
  73out:
  74        unlock_fb_info(fbi);
  75
  76        return r ? r : count;
  77}
  78
  79
  80static ssize_t show_mirror(struct device *dev,
  81                struct device_attribute *attr, char *buf)
  82{
  83        struct fb_info *fbi = dev_get_drvdata(dev);
  84        struct omapfb_info *ofbi = FB2OFB(fbi);
  85
  86        return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);
  87}
  88
  89static ssize_t store_mirror(struct device *dev,
  90                struct device_attribute *attr,
  91                const char *buf, size_t count)
  92{
  93        struct fb_info *fbi = dev_get_drvdata(dev);
  94        struct omapfb_info *ofbi = FB2OFB(fbi);
  95        bool mirror;
  96        int r;
  97        struct fb_var_screeninfo new_var;
  98
  99        r = strtobool(buf, &mirror);
 100        if (r)
 101                return r;
 102
 103        lock_fb_info(fbi);
 104
 105        ofbi->mirror = mirror;
 106
 107        omapfb_get_mem_region(ofbi->region);
 108
 109        memcpy(&new_var, &fbi->var, sizeof(new_var));
 110        r = check_fb_var(fbi, &new_var);
 111        if (r)
 112                goto out;
 113        memcpy(&fbi->var, &new_var, sizeof(fbi->var));
 114
 115        set_fb_fix(fbi);
 116
 117        r = omapfb_apply_changes(fbi, 0);
 118        if (r)
 119                goto out;
 120
 121        r = count;
 122out:
 123        omapfb_put_mem_region(ofbi->region);
 124
 125        unlock_fb_info(fbi);
 126
 127        return r;
 128}
 129
 130static ssize_t show_overlays(struct device *dev,
 131                struct device_attribute *attr, char *buf)
 132{
 133        struct fb_info *fbi = dev_get_drvdata(dev);
 134        struct omapfb_info *ofbi = FB2OFB(fbi);
 135        struct omapfb2_device *fbdev = ofbi->fbdev;
 136        ssize_t l = 0;
 137        int t;
 138
 139        lock_fb_info(fbi);
 140        omapfb_lock(fbdev);
 141
 142        for (t = 0; t < ofbi->num_overlays; t++) {
 143                struct omap_overlay *ovl = ofbi->overlays[t];
 144                int ovlnum;
 145
 146                for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
 147                        if (ovl == fbdev->overlays[ovlnum])
 148                                break;
 149
 150                l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
 151                                t == 0 ? "" : ",", ovlnum);
 152        }
 153
 154        l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
 155
 156        omapfb_unlock(fbdev);
 157        unlock_fb_info(fbi);
 158
 159        return l;
 160}
 161
 162static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
 163                struct omap_overlay *ovl)
 164{
 165        int i, t;
 166
 167        for (i = 0; i < fbdev->num_fbs; i++) {
 168                struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
 169
 170                for (t = 0; t < ofbi->num_overlays; t++) {
 171                        if (ofbi->overlays[t] == ovl)
 172                                return ofbi;
 173                }
 174        }
 175
 176        return NULL;
 177}
 178
 179static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
 180                const char *buf, size_t count)
 181{
 182        struct fb_info *fbi = dev_get_drvdata(dev);
 183        struct omapfb_info *ofbi = FB2OFB(fbi);
 184        struct omapfb2_device *fbdev = ofbi->fbdev;
 185        struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
 186        struct omap_overlay *ovl;
 187        int num_ovls, r, i;
 188        int len;
 189        bool added = false;
 190
 191        num_ovls = 0;
 192
 193        len = strlen(buf);
 194        if (buf[len - 1] == '\n')
 195                len = len - 1;
 196
 197        lock_fb_info(fbi);
 198        omapfb_lock(fbdev);
 199
 200        if (len > 0) {
 201                char *p = (char *)buf;
 202                int ovlnum;
 203
 204                while (p < buf + len) {
 205                        int found;
 206                        if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
 207                                r = -EINVAL;
 208                                goto out;
 209                        }
 210
 211                        ovlnum = simple_strtoul(p, &p, 0);
 212                        if (ovlnum > fbdev->num_overlays) {
 213                                r = -EINVAL;
 214                                goto out;
 215                        }
 216
 217                        found = 0;
 218                        for (i = 0; i < num_ovls; ++i) {
 219                                if (ovls[i] == fbdev->overlays[ovlnum]) {
 220                                        found = 1;
 221                                        break;
 222                                }
 223                        }
 224
 225                        if (!found)
 226                                ovls[num_ovls++] = fbdev->overlays[ovlnum];
 227
 228                        p++;
 229                }
 230        }
 231
 232        for (i = 0; i < num_ovls; ++i) {
 233                struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
 234                if (ofbi2 && ofbi2 != ofbi) {
 235                        dev_err(fbdev->dev, "overlay already in use\n");
 236                        r = -EINVAL;
 237                        goto out;
 238                }
 239        }
 240
 241        /* detach unused overlays */
 242        for (i = 0; i < ofbi->num_overlays; ++i) {
 243                int t, found;
 244
 245                ovl = ofbi->overlays[i];
 246
 247                found = 0;
 248
 249                for (t = 0; t < num_ovls; ++t) {
 250                        if (ovl == ovls[t]) {
 251                                found = 1;
 252                                break;
 253                        }
 254                }
 255
 256                if (found)
 257                        continue;
 258
 259                DBG("detaching %d\n", ofbi->overlays[i]->id);
 260
 261                omapfb_get_mem_region(ofbi->region);
 262
 263                omapfb_overlay_enable(ovl, 0);
 264
 265                if (ovl->manager)
 266                        ovl->manager->apply(ovl->manager);
 267
 268                omapfb_put_mem_region(ofbi->region);
 269
 270                for (t = i + 1; t < ofbi->num_overlays; t++) {
 271                        ofbi->rotation[t-1] = ofbi->rotation[t];
 272                        ofbi->overlays[t-1] = ofbi->overlays[t];
 273                }
 274
 275                ofbi->num_overlays--;
 276                i--;
 277        }
 278
 279        for (i = 0; i < num_ovls; ++i) {
 280                int t, found;
 281
 282                ovl = ovls[i];
 283
 284                found = 0;
 285
 286                for (t = 0; t < ofbi->num_overlays; ++t) {
 287                        if (ovl == ofbi->overlays[t]) {
 288                                found = 1;
 289                                break;
 290                        }
 291                }
 292
 293                if (found)
 294                        continue;
 295                ofbi->rotation[ofbi->num_overlays] = 0;
 296                ofbi->overlays[ofbi->num_overlays++] = ovl;
 297
 298                added = true;
 299        }
 300
 301        if (added) {
 302                omapfb_get_mem_region(ofbi->region);
 303
 304                r = omapfb_apply_changes(fbi, 0);
 305
 306                omapfb_put_mem_region(ofbi->region);
 307
 308                if (r)
 309                        goto out;
 310        }
 311
 312        r = count;
 313out:
 314        omapfb_unlock(fbdev);
 315        unlock_fb_info(fbi);
 316
 317        return r;
 318}
 319
 320static ssize_t show_overlays_rotate(struct device *dev,
 321                struct device_attribute *attr, char *buf)
 322{
 323        struct fb_info *fbi = dev_get_drvdata(dev);
 324        struct omapfb_info *ofbi = FB2OFB(fbi);
 325        ssize_t l = 0;
 326        int t;
 327
 328        lock_fb_info(fbi);
 329
 330        for (t = 0; t < ofbi->num_overlays; t++) {
 331                l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
 332                                t == 0 ? "" : ",", ofbi->rotation[t]);
 333        }
 334
 335        l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
 336
 337        unlock_fb_info(fbi);
 338
 339        return l;
 340}
 341
 342static ssize_t store_overlays_rotate(struct device *dev,
 343                struct device_attribute *attr, const char *buf, size_t count)
 344{
 345        struct fb_info *fbi = dev_get_drvdata(dev);
 346        struct omapfb_info *ofbi = FB2OFB(fbi);
 347        int num_ovls = 0, r, i;
 348        int len;
 349        bool changed = false;
 350        u8 rotation[OMAPFB_MAX_OVL_PER_FB];
 351
 352        len = strlen(buf);
 353        if (buf[len - 1] == '\n')
 354                len = len - 1;
 355
 356        lock_fb_info(fbi);
 357
 358        if (len > 0) {
 359                char *p = (char *)buf;
 360
 361                while (p < buf + len) {
 362                        int rot;
 363
 364                        if (num_ovls == ofbi->num_overlays) {
 365                                r = -EINVAL;
 366                                goto out;
 367                        }
 368
 369                        rot = simple_strtoul(p, &p, 0);
 370                        if (rot < 0 || rot > 3) {
 371                                r = -EINVAL;
 372                                goto out;
 373                        }
 374
 375                        if (ofbi->rotation[num_ovls] != rot)
 376                                changed = true;
 377
 378                        rotation[num_ovls++] = rot;
 379
 380                        p++;
 381                }
 382        }
 383
 384        if (num_ovls != ofbi->num_overlays) {
 385                r = -EINVAL;
 386                goto out;
 387        }
 388
 389        if (changed) {
 390                for (i = 0; i < num_ovls; ++i)
 391                        ofbi->rotation[i] = rotation[i];
 392
 393                omapfb_get_mem_region(ofbi->region);
 394
 395                r = omapfb_apply_changes(fbi, 0);
 396
 397                omapfb_put_mem_region(ofbi->region);
 398
 399                if (r)
 400                        goto out;
 401
 402                /* FIXME error handling? */
 403        }
 404
 405        r = count;
 406out:
 407        unlock_fb_info(fbi);
 408
 409        return r;
 410}
 411
 412static ssize_t show_size(struct device *dev,
 413                struct device_attribute *attr, char *buf)
 414{
 415        struct fb_info *fbi = dev_get_drvdata(dev);
 416        struct omapfb_info *ofbi = FB2OFB(fbi);
 417
 418        return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size);
 419}
 420
 421static ssize_t store_size(struct device *dev, struct device_attribute *attr,
 422                const char *buf, size_t count)
 423{
 424        struct fb_info *fbi = dev_get_drvdata(dev);
 425        struct omapfb_info *ofbi = FB2OFB(fbi);
 426        struct omapfb2_device *fbdev = ofbi->fbdev;
 427        struct omap_dss_device *display = fb2display(fbi);
 428        struct omapfb2_mem_region *rg;
 429        unsigned long size;
 430        int r;
 431        int i;
 432
 433        r = kstrtoul(buf, 0, &size);
 434        if (r)
 435                return r;
 436
 437        size = PAGE_ALIGN(size);
 438
 439        lock_fb_info(fbi);
 440
 441        if (display && display->driver->sync)
 442                display->driver->sync(display);
 443
 444        rg = ofbi->region;
 445
 446        down_write_nested(&rg->lock, rg->id);
 447        atomic_inc(&rg->lock_count);
 448
 449        if (atomic_read(&rg->map_count)) {
 450                r = -EBUSY;
 451                goto out;
 452        }
 453
 454        for (i = 0; i < fbdev->num_fbs; i++) {
 455                struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
 456                int j;
 457
 458                if (ofbi2->region != rg)
 459                        continue;
 460
 461                for (j = 0; j < ofbi2->num_overlays; j++) {
 462                        struct omap_overlay *ovl;
 463                        ovl = ofbi2->overlays[j];
 464                        if (ovl->is_enabled(ovl)) {
 465                                r = -EBUSY;
 466                                goto out;
 467                        }
 468                }
 469        }
 470
 471        if (size != ofbi->region->size) {
 472                r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
 473                if (r) {
 474                        dev_err(dev, "realloc fbmem failed\n");
 475                        goto out;
 476                }
 477        }
 478
 479        r = count;
 480out:
 481        atomic_dec(&rg->lock_count);
 482        up_write(&rg->lock);
 483
 484        unlock_fb_info(fbi);
 485
 486        return r;
 487}
 488
 489static ssize_t show_phys(struct device *dev,
 490                struct device_attribute *attr, char *buf)
 491{
 492        struct fb_info *fbi = dev_get_drvdata(dev);
 493        struct omapfb_info *ofbi = FB2OFB(fbi);
 494
 495        return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr);
 496}
 497
 498static ssize_t show_virt(struct device *dev,
 499                struct device_attribute *attr, char *buf)
 500{
 501        struct fb_info *fbi = dev_get_drvdata(dev);
 502        struct omapfb_info *ofbi = FB2OFB(fbi);
 503
 504        return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr);
 505}
 506
 507static ssize_t show_upd_mode(struct device *dev,
 508                struct device_attribute *attr, char *buf)
 509{
 510        struct fb_info *fbi = dev_get_drvdata(dev);
 511        enum omapfb_update_mode mode;
 512        int r;
 513
 514        r = omapfb_get_update_mode(fbi, &mode);
 515
 516        if (r)
 517                return r;
 518
 519        return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode);
 520}
 521
 522static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
 523                const char *buf, size_t count)
 524{
 525        struct fb_info *fbi = dev_get_drvdata(dev);
 526        unsigned mode;
 527        int r;
 528
 529        r = kstrtouint(buf, 0, &mode);
 530        if (r)
 531                return r;
 532
 533        r = omapfb_set_update_mode(fbi, mode);
 534        if (r)
 535                return r;
 536
 537        return count;
 538}
 539
 540static struct device_attribute omapfb_attrs[] = {
 541        __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
 542                        store_rotate_type),
 543        __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
 544        __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
 545        __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
 546        __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
 547                        store_overlays_rotate),
 548        __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
 549        __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
 550        __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
 551};
 552
 553int omapfb_create_sysfs(struct omapfb2_device *fbdev)
 554{
 555        int i;
 556        int r;
 557
 558        DBG("create sysfs for fbs\n");
 559        for (i = 0; i < fbdev->num_fbs; i++) {
 560                int t;
 561                for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
 562                        r = device_create_file(fbdev->fbs[i]->dev,
 563                                        &omapfb_attrs[t]);
 564
 565                        if (r) {
 566                                dev_err(fbdev->dev, "failed to create sysfs "
 567                                                "file\n");
 568                                return r;
 569                        }
 570                }
 571        }
 572
 573        return 0;
 574}
 575
 576void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
 577{
 578        int i, t;
 579
 580        DBG("remove sysfs for fbs\n");
 581        for (i = 0; i < fbdev->num_fbs; i++) {
 582                for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
 583                        device_remove_file(fbdev->fbs[i]->dev,
 584                                        &omapfb_attrs[t]);
 585        }
 586}
 587
 588