18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/drivers/video/omap2/omapfb-sysfs.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation 68c2ecf20Sopenharmony_ci * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Some code and ideas taken from drivers/video/omap/ driver 98c2ecf20Sopenharmony_ci * by Imre Deak. 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/fb.h> 138c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 148c2ecf20Sopenharmony_ci#include <linux/device.h> 158c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/mm.h> 198c2ecf20Sopenharmony_ci#include <linux/omapfb.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <video/omapfb_dss.h> 228c2ecf20Sopenharmony_ci#include <video/omapvrfb.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "omapfb.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic ssize_t show_rotate_type(struct device *dev, 278c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 308c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic ssize_t store_rotate_type(struct device *dev, 368c2ecf20Sopenharmony_ci struct device_attribute *attr, 378c2ecf20Sopenharmony_ci const char *buf, size_t count) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 408c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 418c2ecf20Sopenharmony_ci struct omapfb2_mem_region *rg; 428c2ecf20Sopenharmony_ci int rot_type; 438c2ecf20Sopenharmony_ci int r; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci r = kstrtoint(buf, 0, &rot_type); 468c2ecf20Sopenharmony_ci if (r) 478c2ecf20Sopenharmony_ci return r; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB) 508c2ecf20Sopenharmony_ci return -EINVAL; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci lock_fb_info(fbi); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci r = 0; 558c2ecf20Sopenharmony_ci if (rot_type == ofbi->rotation_type) 568c2ecf20Sopenharmony_ci goto out; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci rg = omapfb_get_mem_region(ofbi->region); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci if (rg->size) { 618c2ecf20Sopenharmony_ci r = -EBUSY; 628c2ecf20Sopenharmony_ci goto put_region; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci ofbi->rotation_type = rot_type; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* 688c2ecf20Sopenharmony_ci * Since the VRAM for this FB is not allocated at the moment we don't 698c2ecf20Sopenharmony_ci * need to do any further parameter checking at this point. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ciput_region: 728c2ecf20Sopenharmony_ci omapfb_put_mem_region(rg); 738c2ecf20Sopenharmony_ciout: 748c2ecf20Sopenharmony_ci unlock_fb_info(fbi); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci return r ? r : count; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic ssize_t show_mirror(struct device *dev, 818c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 848c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic ssize_t store_mirror(struct device *dev, 908c2ecf20Sopenharmony_ci struct device_attribute *attr, 918c2ecf20Sopenharmony_ci const char *buf, size_t count) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 948c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 958c2ecf20Sopenharmony_ci bool mirror; 968c2ecf20Sopenharmony_ci int r; 978c2ecf20Sopenharmony_ci struct fb_var_screeninfo new_var; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci r = strtobool(buf, &mirror); 1008c2ecf20Sopenharmony_ci if (r) 1018c2ecf20Sopenharmony_ci return r; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci lock_fb_info(fbi); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci ofbi->mirror = mirror; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci omapfb_get_mem_region(ofbi->region); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci memcpy(&new_var, &fbi->var, sizeof(new_var)); 1108c2ecf20Sopenharmony_ci r = check_fb_var(fbi, &new_var); 1118c2ecf20Sopenharmony_ci if (r) 1128c2ecf20Sopenharmony_ci goto out; 1138c2ecf20Sopenharmony_ci memcpy(&fbi->var, &new_var, sizeof(fbi->var)); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci set_fb_fix(fbi); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci r = omapfb_apply_changes(fbi, 0); 1188c2ecf20Sopenharmony_ci if (r) 1198c2ecf20Sopenharmony_ci goto out; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci r = count; 1228c2ecf20Sopenharmony_ciout: 1238c2ecf20Sopenharmony_ci omapfb_put_mem_region(ofbi->region); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci unlock_fb_info(fbi); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return r; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic ssize_t show_overlays(struct device *dev, 1318c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 1348c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 1358c2ecf20Sopenharmony_ci struct omapfb2_device *fbdev = ofbi->fbdev; 1368c2ecf20Sopenharmony_ci ssize_t l = 0; 1378c2ecf20Sopenharmony_ci int t; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci lock_fb_info(fbi); 1408c2ecf20Sopenharmony_ci omapfb_lock(fbdev); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci for (t = 0; t < ofbi->num_overlays; t++) { 1438c2ecf20Sopenharmony_ci struct omap_overlay *ovl = ofbi->overlays[t]; 1448c2ecf20Sopenharmony_ci int ovlnum; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum) 1478c2ecf20Sopenharmony_ci if (ovl == fbdev->overlays[ovlnum]) 1488c2ecf20Sopenharmony_ci break; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d", 1518c2ecf20Sopenharmony_ci t == 0 ? "" : ",", ovlnum); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci l += scnprintf(buf + l, PAGE_SIZE - l, "\n"); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci omapfb_unlock(fbdev); 1578c2ecf20Sopenharmony_ci unlock_fb_info(fbi); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return l; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev, 1638c2ecf20Sopenharmony_ci struct omap_overlay *ovl) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci int i, t; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci for (i = 0; i < fbdev->num_fbs; i++) { 1688c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci for (t = 0; t < ofbi->num_overlays; t++) { 1718c2ecf20Sopenharmony_ci if (ofbi->overlays[t] == ovl) 1728c2ecf20Sopenharmony_ci return ofbi; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return NULL; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic ssize_t store_overlays(struct device *dev, struct device_attribute *attr, 1808c2ecf20Sopenharmony_ci const char *buf, size_t count) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 1838c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 1848c2ecf20Sopenharmony_ci struct omapfb2_device *fbdev = ofbi->fbdev; 1858c2ecf20Sopenharmony_ci struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB]; 1868c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 1878c2ecf20Sopenharmony_ci int num_ovls, r, i; 1888c2ecf20Sopenharmony_ci int len; 1898c2ecf20Sopenharmony_ci bool added = false; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci num_ovls = 0; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci len = strlen(buf); 1948c2ecf20Sopenharmony_ci if (buf[len - 1] == '\n') 1958c2ecf20Sopenharmony_ci len = len - 1; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci lock_fb_info(fbi); 1988c2ecf20Sopenharmony_ci omapfb_lock(fbdev); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci if (len > 0) { 2018c2ecf20Sopenharmony_ci char *p = (char *)buf; 2028c2ecf20Sopenharmony_ci int ovlnum; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci while (p < buf + len) { 2058c2ecf20Sopenharmony_ci int found; 2068c2ecf20Sopenharmony_ci if (num_ovls == OMAPFB_MAX_OVL_PER_FB) { 2078c2ecf20Sopenharmony_ci r = -EINVAL; 2088c2ecf20Sopenharmony_ci goto out; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci ovlnum = simple_strtoul(p, &p, 0); 2128c2ecf20Sopenharmony_ci if (ovlnum > fbdev->num_overlays) { 2138c2ecf20Sopenharmony_ci r = -EINVAL; 2148c2ecf20Sopenharmony_ci goto out; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci found = 0; 2188c2ecf20Sopenharmony_ci for (i = 0; i < num_ovls; ++i) { 2198c2ecf20Sopenharmony_ci if (ovls[i] == fbdev->overlays[ovlnum]) { 2208c2ecf20Sopenharmony_ci found = 1; 2218c2ecf20Sopenharmony_ci break; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (!found) 2268c2ecf20Sopenharmony_ci ovls[num_ovls++] = fbdev->overlays[ovlnum]; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci p++; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci for (i = 0; i < num_ovls; ++i) { 2338c2ecf20Sopenharmony_ci struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]); 2348c2ecf20Sopenharmony_ci if (ofbi2 && ofbi2 != ofbi) { 2358c2ecf20Sopenharmony_ci dev_err(fbdev->dev, "overlay already in use\n"); 2368c2ecf20Sopenharmony_ci r = -EINVAL; 2378c2ecf20Sopenharmony_ci goto out; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* detach unused overlays */ 2428c2ecf20Sopenharmony_ci for (i = 0; i < ofbi->num_overlays; ++i) { 2438c2ecf20Sopenharmony_ci int t, found; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci ovl = ofbi->overlays[i]; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci found = 0; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci for (t = 0; t < num_ovls; ++t) { 2508c2ecf20Sopenharmony_ci if (ovl == ovls[t]) { 2518c2ecf20Sopenharmony_ci found = 1; 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (found) 2578c2ecf20Sopenharmony_ci continue; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci DBG("detaching %d\n", ofbi->overlays[i]->id); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci omapfb_get_mem_region(ofbi->region); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci omapfb_overlay_enable(ovl, 0); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (ovl->manager) 2668c2ecf20Sopenharmony_ci ovl->manager->apply(ovl->manager); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci omapfb_put_mem_region(ofbi->region); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci for (t = i + 1; t < ofbi->num_overlays; t++) { 2718c2ecf20Sopenharmony_ci ofbi->rotation[t-1] = ofbi->rotation[t]; 2728c2ecf20Sopenharmony_ci ofbi->overlays[t-1] = ofbi->overlays[t]; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci ofbi->num_overlays--; 2768c2ecf20Sopenharmony_ci i--; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci for (i = 0; i < num_ovls; ++i) { 2808c2ecf20Sopenharmony_ci int t, found; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci ovl = ovls[i]; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci found = 0; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci for (t = 0; t < ofbi->num_overlays; ++t) { 2878c2ecf20Sopenharmony_ci if (ovl == ofbi->overlays[t]) { 2888c2ecf20Sopenharmony_ci found = 1; 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (found) 2948c2ecf20Sopenharmony_ci continue; 2958c2ecf20Sopenharmony_ci ofbi->rotation[ofbi->num_overlays] = 0; 2968c2ecf20Sopenharmony_ci ofbi->overlays[ofbi->num_overlays++] = ovl; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci added = true; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci if (added) { 3028c2ecf20Sopenharmony_ci omapfb_get_mem_region(ofbi->region); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci r = omapfb_apply_changes(fbi, 0); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci omapfb_put_mem_region(ofbi->region); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (r) 3098c2ecf20Sopenharmony_ci goto out; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci r = count; 3138c2ecf20Sopenharmony_ciout: 3148c2ecf20Sopenharmony_ci omapfb_unlock(fbdev); 3158c2ecf20Sopenharmony_ci unlock_fb_info(fbi); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return r; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic ssize_t show_overlays_rotate(struct device *dev, 3218c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 3248c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 3258c2ecf20Sopenharmony_ci ssize_t l = 0; 3268c2ecf20Sopenharmony_ci int t; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci lock_fb_info(fbi); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci for (t = 0; t < ofbi->num_overlays; t++) { 3318c2ecf20Sopenharmony_ci l += scnprintf(buf + l, PAGE_SIZE - l, "%s%d", 3328c2ecf20Sopenharmony_ci t == 0 ? "" : ",", ofbi->rotation[t]); 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci l += scnprintf(buf + l, PAGE_SIZE - l, "\n"); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci unlock_fb_info(fbi); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return l; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic ssize_t store_overlays_rotate(struct device *dev, 3438c2ecf20Sopenharmony_ci struct device_attribute *attr, const char *buf, size_t count) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 3468c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 3478c2ecf20Sopenharmony_ci int num_ovls = 0, r, i; 3488c2ecf20Sopenharmony_ci int len; 3498c2ecf20Sopenharmony_ci bool changed = false; 3508c2ecf20Sopenharmony_ci u8 rotation[OMAPFB_MAX_OVL_PER_FB]; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci len = strlen(buf); 3538c2ecf20Sopenharmony_ci if (buf[len - 1] == '\n') 3548c2ecf20Sopenharmony_ci len = len - 1; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci lock_fb_info(fbi); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (len > 0) { 3598c2ecf20Sopenharmony_ci char *p = (char *)buf; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci while (p < buf + len) { 3628c2ecf20Sopenharmony_ci int rot; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci if (num_ovls == ofbi->num_overlays) { 3658c2ecf20Sopenharmony_ci r = -EINVAL; 3668c2ecf20Sopenharmony_ci goto out; 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci rot = simple_strtoul(p, &p, 0); 3708c2ecf20Sopenharmony_ci if (rot < 0 || rot > 3) { 3718c2ecf20Sopenharmony_ci r = -EINVAL; 3728c2ecf20Sopenharmony_ci goto out; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci if (ofbi->rotation[num_ovls] != rot) 3768c2ecf20Sopenharmony_ci changed = true; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci rotation[num_ovls++] = rot; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci p++; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (num_ovls != ofbi->num_overlays) { 3858c2ecf20Sopenharmony_ci r = -EINVAL; 3868c2ecf20Sopenharmony_ci goto out; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (changed) { 3908c2ecf20Sopenharmony_ci for (i = 0; i < num_ovls; ++i) 3918c2ecf20Sopenharmony_ci ofbi->rotation[i] = rotation[i]; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci omapfb_get_mem_region(ofbi->region); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci r = omapfb_apply_changes(fbi, 0); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci omapfb_put_mem_region(ofbi->region); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (r) 4008c2ecf20Sopenharmony_ci goto out; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci /* FIXME error handling? */ 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci r = count; 4068c2ecf20Sopenharmony_ciout: 4078c2ecf20Sopenharmony_ci unlock_fb_info(fbi); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return r; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_cistatic ssize_t show_size(struct device *dev, 4138c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 4168c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic ssize_t store_size(struct device *dev, struct device_attribute *attr, 4228c2ecf20Sopenharmony_ci const char *buf, size_t count) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 4258c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 4268c2ecf20Sopenharmony_ci struct omapfb2_device *fbdev = ofbi->fbdev; 4278c2ecf20Sopenharmony_ci struct omap_dss_device *display = fb2display(fbi); 4288c2ecf20Sopenharmony_ci struct omapfb2_mem_region *rg; 4298c2ecf20Sopenharmony_ci unsigned long size; 4308c2ecf20Sopenharmony_ci int r; 4318c2ecf20Sopenharmony_ci int i; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci r = kstrtoul(buf, 0, &size); 4348c2ecf20Sopenharmony_ci if (r) 4358c2ecf20Sopenharmony_ci return r; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci size = PAGE_ALIGN(size); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci lock_fb_info(fbi); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (display && display->driver->sync) 4428c2ecf20Sopenharmony_ci display->driver->sync(display); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci rg = ofbi->region; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci down_write_nested(&rg->lock, rg->id); 4478c2ecf20Sopenharmony_ci atomic_inc(&rg->lock_count); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (atomic_read(&rg->map_count)) { 4508c2ecf20Sopenharmony_ci r = -EBUSY; 4518c2ecf20Sopenharmony_ci goto out; 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci for (i = 0; i < fbdev->num_fbs; i++) { 4558c2ecf20Sopenharmony_ci struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); 4568c2ecf20Sopenharmony_ci int j; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (ofbi2->region != rg) 4598c2ecf20Sopenharmony_ci continue; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci for (j = 0; j < ofbi2->num_overlays; j++) { 4628c2ecf20Sopenharmony_ci struct omap_overlay *ovl; 4638c2ecf20Sopenharmony_ci ovl = ofbi2->overlays[j]; 4648c2ecf20Sopenharmony_ci if (ovl->is_enabled(ovl)) { 4658c2ecf20Sopenharmony_ci r = -EBUSY; 4668c2ecf20Sopenharmony_ci goto out; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (size != ofbi->region->size) { 4728c2ecf20Sopenharmony_ci r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type); 4738c2ecf20Sopenharmony_ci if (r) { 4748c2ecf20Sopenharmony_ci dev_err(dev, "realloc fbmem failed\n"); 4758c2ecf20Sopenharmony_ci goto out; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci r = count; 4808c2ecf20Sopenharmony_ciout: 4818c2ecf20Sopenharmony_ci atomic_dec(&rg->lock_count); 4828c2ecf20Sopenharmony_ci up_write(&rg->lock); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci unlock_fb_info(fbi); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci return r; 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic ssize_t show_phys(struct device *dev, 4908c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 4938c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr); 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic ssize_t show_virt(struct device *dev, 4998c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5008c2ecf20Sopenharmony_ci{ 5018c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 5028c2ecf20Sopenharmony_ci struct omapfb_info *ofbi = FB2OFB(fbi); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr); 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cistatic ssize_t show_upd_mode(struct device *dev, 5088c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 5118c2ecf20Sopenharmony_ci enum omapfb_update_mode mode; 5128c2ecf20Sopenharmony_ci int r; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci r = omapfb_get_update_mode(fbi, &mode); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (r) 5178c2ecf20Sopenharmony_ci return r; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%u\n", (unsigned)mode); 5208c2ecf20Sopenharmony_ci} 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_cistatic ssize_t store_upd_mode(struct device *dev, struct device_attribute *attr, 5238c2ecf20Sopenharmony_ci const char *buf, size_t count) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 5268c2ecf20Sopenharmony_ci unsigned mode; 5278c2ecf20Sopenharmony_ci int r; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci r = kstrtouint(buf, 0, &mode); 5308c2ecf20Sopenharmony_ci if (r) 5318c2ecf20Sopenharmony_ci return r; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci r = omapfb_set_update_mode(fbi, mode); 5348c2ecf20Sopenharmony_ci if (r) 5358c2ecf20Sopenharmony_ci return r; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return count; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic struct device_attribute omapfb_attrs[] = { 5418c2ecf20Sopenharmony_ci __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type, 5428c2ecf20Sopenharmony_ci store_rotate_type), 5438c2ecf20Sopenharmony_ci __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror), 5448c2ecf20Sopenharmony_ci __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size), 5458c2ecf20Sopenharmony_ci __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays), 5468c2ecf20Sopenharmony_ci __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate, 5478c2ecf20Sopenharmony_ci store_overlays_rotate), 5488c2ecf20Sopenharmony_ci __ATTR(phys_addr, S_IRUGO, show_phys, NULL), 5498c2ecf20Sopenharmony_ci __ATTR(virt_addr, S_IRUGO, show_virt, NULL), 5508c2ecf20Sopenharmony_ci __ATTR(update_mode, S_IRUGO | S_IWUSR, show_upd_mode, store_upd_mode), 5518c2ecf20Sopenharmony_ci}; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ciint omapfb_create_sysfs(struct omapfb2_device *fbdev) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci int i; 5568c2ecf20Sopenharmony_ci int r; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci DBG("create sysfs for fbs\n"); 5598c2ecf20Sopenharmony_ci for (i = 0; i < fbdev->num_fbs; i++) { 5608c2ecf20Sopenharmony_ci int t; 5618c2ecf20Sopenharmony_ci for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) { 5628c2ecf20Sopenharmony_ci r = device_create_file(fbdev->fbs[i]->dev, 5638c2ecf20Sopenharmony_ci &omapfb_attrs[t]); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (r) { 5668c2ecf20Sopenharmony_ci dev_err(fbdev->dev, "failed to create sysfs " 5678c2ecf20Sopenharmony_ci "file\n"); 5688c2ecf20Sopenharmony_ci return r; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return 0; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_civoid omapfb_remove_sysfs(struct omapfb2_device *fbdev) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci int i, t; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci DBG("remove sysfs for fbs\n"); 5818c2ecf20Sopenharmony_ci for (i = 0; i < fbdev->num_fbs; i++) { 5828c2ecf20Sopenharmony_ci for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) 5838c2ecf20Sopenharmony_ci device_remove_file(fbdev->fbs[i]->dev, 5848c2ecf20Sopenharmony_ci &omapfb_attrs[t]); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 588