Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * linux/drivers/video/omap2/omapfb-sysfs.c
0004  *
0005  * Copyright (C) 2008 Nokia Corporation
0006  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
0007  *
0008  * Some code and ideas taken from drivers/video/omap/ driver
0009  * by Imre Deak.
0010  */
0011 
0012 #include <linux/fb.h>
0013 #include <linux/sysfs.h>
0014 #include <linux/device.h>
0015 #include <linux/uaccess.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/kernel.h>
0018 #include <linux/mm.h>
0019 #include <linux/omapfb.h>
0020 
0021 #include <video/omapfb_dss.h>
0022 #include <video/omapvrfb.h>
0023 
0024 #include "omapfb.h"
0025 
0026 static ssize_t show_rotate_type(struct device *dev,
0027         struct device_attribute *attr, char *buf)
0028 {
0029     struct fb_info *fbi = dev_get_drvdata(dev);
0030     struct omapfb_info *ofbi = FB2OFB(fbi);
0031 
0032     return sysfs_emit(buf, "%d\n", ofbi->rotation_type);
0033 }
0034 
0035 static ssize_t store_rotate_type(struct device *dev,
0036         struct device_attribute *attr,
0037         const char *buf, size_t count)
0038 {
0039     struct fb_info *fbi = dev_get_drvdata(dev);
0040     struct omapfb_info *ofbi = FB2OFB(fbi);
0041     struct omapfb2_mem_region *rg;
0042     int rot_type;
0043     int r;
0044 
0045     r = kstrtoint(buf, 0, &rot_type);
0046     if (r)
0047         return r;
0048 
0049     if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
0050         return -EINVAL;
0051 
0052     lock_fb_info(fbi);
0053 
0054     r = 0;
0055     if (rot_type == ofbi->rotation_type)
0056         goto out;
0057 
0058     rg = omapfb_get_mem_region(ofbi->region);
0059 
0060     if (rg->size) {
0061         r = -EBUSY;
0062         goto put_region;
0063     }
0064 
0065     ofbi->rotation_type = rot_type;
0066 
0067     /*
0068      * Since the VRAM for this FB is not allocated at the moment we don't
0069      * need to do any further parameter checking at this point.
0070      */
0071 put_region:
0072     omapfb_put_mem_region(rg);
0073 out:
0074     unlock_fb_info(fbi);
0075 
0076     return r ? r : count;
0077 }
0078 
0079 
0080 static ssize_t show_mirror(struct device *dev,
0081         struct device_attribute *attr, char *buf)
0082 {
0083     struct fb_info *fbi = dev_get_drvdata(dev);
0084     struct omapfb_info *ofbi = FB2OFB(fbi);
0085 
0086     return sysfs_emit(buf, "%d\n", ofbi->mirror);
0087 }
0088 
0089 static ssize_t store_mirror(struct device *dev,
0090         struct device_attribute *attr,
0091         const char *buf, size_t count)
0092 {
0093     struct fb_info *fbi = dev_get_drvdata(dev);
0094     struct omapfb_info *ofbi = FB2OFB(fbi);
0095     bool mirror;
0096     int r;
0097     struct fb_var_screeninfo new_var;
0098 
0099     r = strtobool(buf, &mirror);
0100     if (r)
0101         return r;
0102 
0103     lock_fb_info(fbi);
0104 
0105     ofbi->mirror = mirror;
0106 
0107     omapfb_get_mem_region(ofbi->region);
0108 
0109     memcpy(&new_var, &fbi->var, sizeof(new_var));
0110     r = check_fb_var(fbi, &new_var);
0111     if (r)
0112         goto out;
0113     memcpy(&fbi->var, &new_var, sizeof(fbi->var));
0114 
0115     set_fb_fix(fbi);
0116 
0117     r = omapfb_apply_changes(fbi, 0);
0118     if (r)
0119         goto out;
0120 
0121     r = count;
0122 out:
0123     omapfb_put_mem_region(ofbi->region);
0124 
0125     unlock_fb_info(fbi);
0126 
0127     return r;
0128 }
0129 
0130 static ssize_t show_overlays(struct device *dev,
0131         struct device_attribute *attr, char *buf)
0132 {
0133     struct fb_info *fbi = dev_get_drvdata(dev);
0134     struct omapfb_info *ofbi = FB2OFB(fbi);
0135     struct omapfb2_device *fbdev = ofbi->fbdev;
0136     ssize_t l = 0;
0137     int t;
0138 
0139     lock_fb_info(fbi);
0140     omapfb_lock(fbdev);
0141 
0142     for (t = 0; t < ofbi->num_overlays; t++) {
0143         struct omap_overlay *ovl = ofbi->overlays[t];
0144         int ovlnum;
0145 
0146         for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)
0147             if (ovl == fbdev->overlays[ovlnum])
0148                 break;
0149 
0150         l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
0151                 t == 0 ? "" : ",", ovlnum);
0152     }
0153 
0154     l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
0155 
0156     omapfb_unlock(fbdev);
0157     unlock_fb_info(fbi);
0158 
0159     return l;
0160 }
0161 
0162 static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,
0163         struct omap_overlay *ovl)
0164 {
0165     int i, t;
0166 
0167     for (i = 0; i < fbdev->num_fbs; i++) {
0168         struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);
0169 
0170         for (t = 0; t < ofbi->num_overlays; t++) {
0171             if (ofbi->overlays[t] == ovl)
0172                 return ofbi;
0173         }
0174     }
0175 
0176     return NULL;
0177 }
0178 
0179 static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
0180         const char *buf, size_t count)
0181 {
0182     struct fb_info *fbi = dev_get_drvdata(dev);
0183     struct omapfb_info *ofbi = FB2OFB(fbi);
0184     struct omapfb2_device *fbdev = ofbi->fbdev;
0185     struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];
0186     struct omap_overlay *ovl;
0187     int num_ovls, r, i;
0188     int len;
0189     bool added = false;
0190 
0191     num_ovls = 0;
0192 
0193     len = strlen(buf);
0194     if (buf[len - 1] == '\n')
0195         len = len - 1;
0196 
0197     lock_fb_info(fbi);
0198     omapfb_lock(fbdev);
0199 
0200     if (len > 0) {
0201         char *p = (char *)buf;
0202         int ovlnum;
0203 
0204         while (p < buf + len) {
0205             int found;
0206             if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {
0207                 r = -EINVAL;
0208                 goto out;
0209             }
0210 
0211             ovlnum = simple_strtoul(p, &p, 0);
0212             if (ovlnum > fbdev->num_overlays) {
0213                 r = -EINVAL;
0214                 goto out;
0215             }
0216 
0217             found = 0;
0218             for (i = 0; i < num_ovls; ++i) {
0219                 if (ovls[i] == fbdev->overlays[ovlnum]) {
0220                     found = 1;
0221                     break;
0222                 }
0223             }
0224 
0225             if (!found)
0226                 ovls[num_ovls++] = fbdev->overlays[ovlnum];
0227 
0228             p++;
0229         }
0230     }
0231 
0232     for (i = 0; i < num_ovls; ++i) {
0233         struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);
0234         if (ofbi2 && ofbi2 != ofbi) {
0235             dev_err(fbdev->dev, "overlay already in use\n");
0236             r = -EINVAL;
0237             goto out;
0238         }
0239     }
0240 
0241     /* detach unused overlays */
0242     for (i = 0; i < ofbi->num_overlays; ++i) {
0243         int t, found;
0244 
0245         ovl = ofbi->overlays[i];
0246 
0247         found = 0;
0248 
0249         for (t = 0; t < num_ovls; ++t) {
0250             if (ovl == ovls[t]) {
0251                 found = 1;
0252                 break;
0253             }
0254         }
0255 
0256         if (found)
0257             continue;
0258 
0259         DBG("detaching %d\n", ofbi->overlays[i]->id);
0260 
0261         omapfb_get_mem_region(ofbi->region);
0262 
0263         omapfb_overlay_enable(ovl, 0);
0264 
0265         if (ovl->manager)
0266             ovl->manager->apply(ovl->manager);
0267 
0268         omapfb_put_mem_region(ofbi->region);
0269 
0270         for (t = i + 1; t < ofbi->num_overlays; t++) {
0271             ofbi->rotation[t-1] = ofbi->rotation[t];
0272             ofbi->overlays[t-1] = ofbi->overlays[t];
0273         }
0274 
0275         ofbi->num_overlays--;
0276         i--;
0277     }
0278 
0279     for (i = 0; i < num_ovls; ++i) {
0280         int t, found;
0281 
0282         ovl = ovls[i];
0283 
0284         found = 0;
0285 
0286         for (t = 0; t < ofbi->num_overlays; ++t) {
0287             if (ovl == ofbi->overlays[t]) {
0288                 found = 1;
0289                 break;
0290             }
0291         }
0292 
0293         if (found)
0294             continue;
0295         ofbi->rotation[ofbi->num_overlays] = 0;
0296         ofbi->overlays[ofbi->num_overlays++] = ovl;
0297 
0298         added = true;
0299     }
0300 
0301     if (added) {
0302         omapfb_get_mem_region(ofbi->region);
0303 
0304         r = omapfb_apply_changes(fbi, 0);
0305 
0306         omapfb_put_mem_region(ofbi->region);
0307 
0308         if (r)
0309             goto out;
0310     }
0311 
0312     r = count;
0313 out:
0314     omapfb_unlock(fbdev);
0315     unlock_fb_info(fbi);
0316 
0317     return r;
0318 }
0319 
0320 static ssize_t show_overlays_rotate(struct device *dev,
0321         struct device_attribute *attr, char *buf)
0322 {
0323     struct fb_info *fbi = dev_get_drvdata(dev);
0324     struct omapfb_info *ofbi = FB2OFB(fbi);
0325     ssize_t l = 0;
0326     int t;
0327 
0328     lock_fb_info(fbi);
0329 
0330     for (t = 0; t < ofbi->num_overlays; t++) {
0331         l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d",
0332                 t == 0 ? "" : ",", ofbi->rotation[t]);
0333     }
0334 
0335     l += scnprintf(buf + l, PAGE_SIZE - l, "\n");
0336 
0337     unlock_fb_info(fbi);
0338 
0339     return l;
0340 }
0341 
0342 static ssize_t store_overlays_rotate(struct device *dev,
0343         struct device_attribute *attr, const char *buf, size_t count)
0344 {
0345     struct fb_info *fbi = dev_get_drvdata(dev);
0346     struct omapfb_info *ofbi = FB2OFB(fbi);
0347     int num_ovls = 0, r, i;
0348     int len;
0349     bool changed = false;
0350     u8 rotation[OMAPFB_MAX_OVL_PER_FB];
0351 
0352     len = strlen(buf);
0353     if (buf[len - 1] == '\n')
0354         len = len - 1;
0355 
0356     lock_fb_info(fbi);
0357 
0358     if (len > 0) {
0359         char *p = (char *)buf;
0360 
0361         while (p < buf + len) {
0362             int rot;
0363 
0364             if (num_ovls == ofbi->num_overlays) {
0365                 r = -EINVAL;
0366                 goto out;
0367             }
0368 
0369             rot = simple_strtoul(p, &p, 0);
0370             if (rot < 0 || rot > 3) {
0371                 r = -EINVAL;
0372                 goto out;
0373             }
0374 
0375             if (ofbi->rotation[num_ovls] != rot)
0376                 changed = true;
0377 
0378             rotation[num_ovls++] = rot;
0379 
0380             p++;
0381         }
0382     }
0383 
0384     if (num_ovls != ofbi->num_overlays) {
0385         r = -EINVAL;
0386         goto out;
0387     }
0388 
0389     if (changed) {
0390         for (i = 0; i < num_ovls; ++i)
0391             ofbi->rotation[i] = rotation[i];
0392 
0393         omapfb_get_mem_region(ofbi->region);
0394 
0395         r = omapfb_apply_changes(fbi, 0);
0396 
0397         omapfb_put_mem_region(ofbi->region);
0398 
0399         if (r)
0400             goto out;
0401 
0402         /* FIXME error handling? */
0403     }
0404 
0405     r = count;
0406 out:
0407     unlock_fb_info(fbi);
0408 
0409     return r;
0410 }
0411 
0412 static ssize_t show_size(struct device *dev,
0413         struct device_attribute *attr, char *buf)
0414 {
0415     struct fb_info *fbi = dev_get_drvdata(dev);
0416     struct omapfb_info *ofbi = FB2OFB(fbi);
0417 
0418     return sysfs_emit(buf, "%lu\n", ofbi->region->size);
0419 }
0420 
0421 static ssize_t store_size(struct device *dev, struct device_attribute *attr,
0422         const char *buf, size_t count)
0423 {
0424     struct fb_info *fbi = dev_get_drvdata(dev);
0425     struct omapfb_info *ofbi = FB2OFB(fbi);
0426     struct omapfb2_device *fbdev = ofbi->fbdev;
0427     struct omap_dss_device *display = fb2display(fbi);
0428     struct omapfb2_mem_region *rg;
0429     unsigned long size;
0430     int r;
0431     int i;
0432 
0433     r = kstrtoul(buf, 0, &size);
0434     if (r)
0435         return r;
0436 
0437     size = PAGE_ALIGN(size);
0438 
0439     lock_fb_info(fbi);
0440 
0441     if (display && display->driver->sync)
0442         display->driver->sync(display);
0443 
0444     rg = ofbi->region;
0445 
0446     down_write_nested(&rg->lock, rg->id);
0447     atomic_inc(&rg->lock_count);
0448 
0449     if (atomic_read(&rg->map_count)) {
0450         r = -EBUSY;
0451         goto out;
0452     }
0453 
0454     for (i = 0; i < fbdev->num_fbs; i++) {
0455         struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]);
0456         int j;
0457 
0458         if (ofbi2->region != rg)
0459             continue;
0460 
0461         for (j = 0; j < ofbi2->num_overlays; j++) {
0462             struct omap_overlay *ovl;
0463             ovl = ofbi2->overlays[j];
0464             if (ovl->is_enabled(ovl)) {
0465                 r = -EBUSY;
0466                 goto out;
0467             }
0468         }
0469     }
0470 
0471     if (size != ofbi->region->size) {
0472         r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type);
0473         if (r) {
0474             dev_err(dev, "realloc fbmem failed\n");
0475             goto out;
0476         }
0477     }
0478 
0479     r = count;
0480 out:
0481     atomic_dec(&rg->lock_count);
0482     up_write(&rg->lock);
0483 
0484     unlock_fb_info(fbi);
0485 
0486     return r;
0487 }
0488 
0489 static ssize_t show_phys(struct device *dev,
0490         struct device_attribute *attr, char *buf)
0491 {
0492     struct fb_info *fbi = dev_get_drvdata(dev);
0493     struct omapfb_info *ofbi = FB2OFB(fbi);
0494 
0495     return sysfs_emit(buf, "%0x\n", ofbi->region->paddr);
0496 }
0497 
0498 static ssize_t show_virt(struct device *dev,
0499         struct device_attribute *attr, char *buf)
0500 {
0501     struct fb_info *fbi = dev_get_drvdata(dev);
0502     struct omapfb_info *ofbi = FB2OFB(fbi);
0503 
0504     return sysfs_emit(buf, "%p\n", ofbi->region->vaddr);
0505 }
0506 
0507 static ssize_t show_upd_mode(struct device *dev,
0508         struct device_attribute *attr, char *buf)
0509 {
0510     struct fb_info *fbi = dev_get_drvdata(dev);
0511     enum omapfb_update_mode mode;
0512     int r;
0513 
0514     r = omapfb_get_update_mode(fbi, &mode);
0515 
0516     if (r)
0517         return r;
0518 
0519     return sysfs_emit(buf, "%u\n", (unsigned int)mode);
0520 }
0521 
0522 static ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr,
0523         const char *buf, size_t count)
0524 {
0525     struct fb_info *fbi = dev_get_drvdata(dev);
0526     unsigned mode;
0527     int r;
0528 
0529     r = kstrtouint(buf, 0, &mode);
0530     if (r)
0531         return r;
0532 
0533     r = omapfb_set_update_mode(fbi, mode);
0534     if (r)
0535         return r;
0536 
0537     return count;
0538 }
0539 
0540 static struct device_attribute omapfb_attrs[] = {
0541     __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,
0542             store_rotate_type),
0543     __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),
0544     __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),
0545     __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),
0546     __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,
0547             store_overlays_rotate),
0548     __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
0549     __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
0550     __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode),
0551 };
0552 
0553 int omapfb_create_sysfs(struct omapfb2_device *fbdev)
0554 {
0555     int i;
0556     int r;
0557 
0558     DBG("create sysfs for fbs\n");
0559     for (i = 0; i < fbdev->num_fbs; i++) {
0560         int t;
0561         for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {
0562             r = device_create_file(fbdev->fbs[i]->dev,
0563                     &omapfb_attrs[t]);
0564 
0565             if (r) {
0566                 dev_err(fbdev->dev, "failed to create sysfs "
0567                         "file\n");
0568                 return r;
0569             }
0570         }
0571     }
0572 
0573     return 0;
0574 }
0575 
0576 void omapfb_remove_sysfs(struct omapfb2_device *fbdev)
0577 {
0578     int i, t;
0579 
0580     DBG("remove sysfs for fbs\n");
0581     for (i = 0; i < fbdev->num_fbs; i++) {
0582         for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)
0583             device_remove_file(fbdev->fbs[i]->dev,
0584                     &omapfb_attrs[t]);
0585     }
0586 }
0587