···5555 .num_resources = 0,5656};57575858+void omapfb_set_platform_data(struct omapfb_platform_data *data)5959+{6060+}6161+5862static inline int ranges_overlap(unsigned long start1, unsigned long size1,5963 unsigned long start2, unsigned long size2)6064{···331327332328arch_initcall(omap_init_fb);333329334334-#else330330+#elif defined(CONFIG_FB_OMAP2) || defined(CONFIG_FB_OMAP2_MODULE)331331+332332+static u64 omap_fb_dma_mask = ~(u32)0;333333+static struct omapfb_platform_data omapfb_config;334334+335335+static struct platform_device omap_fb_device = {336336+ .name = "omapfb",337337+ .id = -1,338338+ .dev = {339339+ .dma_mask = &omap_fb_dma_mask,340340+ .coherent_dma_mask = ~(u32)0,341341+ .platform_data = &omapfb_config,342342+ },343343+ .num_resources = 0,344344+};345345+346346+void omapfb_set_platform_data(struct omapfb_platform_data *data)347347+{348348+ omapfb_config = *data;349349+}350350+351351+static inline int omap_init_fb(void)352352+{353353+ return platform_device_register(&omap_fb_device);354354+}355355+356356+arch_initcall(omap_init_fb);335357336358void omapfb_reserve_sdram(void) {}337359unsigned long omapfb_reserve_sram(unsigned long sram_pstart,···369339 return 0;370340}371341342342+#else343343+344344+void omapfb_set_platform_data(struct omapfb_platform_data *data)345345+{346346+}347347+348348+void omapfb_reserve_sdram(void) {}349349+unsigned long omapfb_reserve_sram(unsigned long sram_pstart,350350+ unsigned long sram_vstart,351351+ unsigned long sram_size,352352+ unsigned long start_avail,353353+ unsigned long size_avail)354354+{355355+ return 0;356356+}372357373358#endif
+3-2
drivers/video/omap/Kconfig
···11config FB_OMAP22 tristate "OMAP frame buffer support (EXPERIMENTAL)"33- depends on FB && ARCH_OMAP33+ depends on FB && ARCH_OMAP && (OMAP2_DSS = "n")44+45 select FB_CFB_FILLRECT56 select FB_CFB_COPYAREA67 select FB_CFB_IMAGEBLIT···73727473config FB_OMAP_BOOTLOADER_INIT7574 bool "Check bootloader initialization"7676- depends on FB_OMAP7575+ depends on FB_OMAP || FB_OMAP27776 help7877 Say Y here if you want to enable checking if the bootloader has7978 already initialized the display controller. In this case the
···11+menuconfig FB_OMAP222+ tristate "OMAP2/3 frame buffer support (EXPERIMENTAL)"33+ depends on FB && OMAP2_DSS44+55+ select OMAP2_VRAM66+ select OMAP2_VRFB77+ select FB_CFB_FILLRECT88+ select FB_CFB_COPYAREA99+ select FB_CFB_IMAGEBLIT1010+ help1111+ Frame buffer driver for OMAP2/3 based boards.1212+1313+config FB_OMAP2_DEBUG_SUPPORT1414+ bool "Debug support for OMAP2/3 FB"1515+ default y1616+ depends on FB_OMAP21717+ help1818+ Support for debug output. You have to enable the actual printing1919+ with debug module parameter.2020+2121+config FB_OMAP2_FORCE_AUTO_UPDATE2222+ bool "Force main display to automatic update mode"2323+ depends on FB_OMAP22424+ help2525+ Forces main display to automatic update mode (if possible),2626+ and also enables tearsync (if possible). By default2727+ displays that support manual update are started in manual2828+ update mode.2929+3030+config FB_OMAP2_NUM_FBS3131+ int "Number of framebuffers"3232+ range 1 103333+ default 33434+ depends on FB_OMAP23535+ help3636+ Select the number of framebuffers created. OMAP2/3 has 3 overlays3737+ so normally this would be 3.
···11+/*22+ * linux/drivers/video/omap2/omapfb-ioctl.c33+ *44+ * Copyright (C) 2008 Nokia Corporation55+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>66+ *77+ * Some code and ideas taken from drivers/video/omap/ driver88+ * by Imre Deak.99+ *1010+ * This program is free software; you can redistribute it and/or modify it1111+ * under the terms of the GNU General Public License version 2 as published by1212+ * the Free Software Foundation.1313+ *1414+ * This program is distributed in the hope that it will be useful, but WITHOUT1515+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1616+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1717+ * more details.1818+ *1919+ * You should have received a copy of the GNU General Public License along with2020+ * this program. If not, see <http://www.gnu.org/licenses/>.2121+ */2222+2323+#include <linux/fb.h>2424+#include <linux/device.h>2525+#include <linux/uaccess.h>2626+#include <linux/platform_device.h>2727+#include <linux/mm.h>2828+#include <linux/omapfb.h>2929+#include <linux/vmalloc.h>3030+3131+#include <plat/display.h>3232+#include <plat/vrfb.h>3333+#include <plat/vram.h>3434+3535+#include "omapfb.h"3636+3737+static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)3838+{3939+ struct omapfb_info *ofbi = FB2OFB(fbi);4040+ struct omapfb2_device *fbdev = ofbi->fbdev;4141+ struct omap_overlay *ovl;4242+ struct omap_overlay_info info;4343+ int r = 0;4444+4545+ DBG("omapfb_setup_plane\n");4646+4747+ if (ofbi->num_overlays != 1) {4848+ r = -EINVAL;4949+ goto out;5050+ }5151+5252+ /* XXX uses only the first overlay */5353+ ovl = ofbi->overlays[0];5454+5555+ if (pi->enabled && !ofbi->region.size) {5656+ /*5757+ * This plane's memory was freed, can't enable it5858+ * until it's reallocated.5959+ */6060+ r = -EINVAL;6161+ goto out;6262+ }6363+6464+ ovl->get_overlay_info(ovl, &info);6565+6666+ info.pos_x = pi->pos_x;6767+ info.pos_y = pi->pos_y;6868+ info.out_width = pi->out_width;6969+ info.out_height = pi->out_height;7070+ info.enabled = pi->enabled;7171+7272+ r = ovl->set_overlay_info(ovl, &info);7373+ if (r)7474+ goto out;7575+7676+ if (ovl->manager) {7777+ r = ovl->manager->apply(ovl->manager);7878+ if (r)7979+ goto out;8080+ }8181+8282+out:8383+ if (r)8484+ dev_err(fbdev->dev, "setup_plane failed\n");8585+ return r;8686+}8787+8888+static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)8989+{9090+ struct omapfb_info *ofbi = FB2OFB(fbi);9191+9292+ if (ofbi->num_overlays != 1) {9393+ memset(pi, 0, sizeof(*pi));9494+ } else {9595+ struct omap_overlay_info *ovli;9696+ struct omap_overlay *ovl;9797+9898+ ovl = ofbi->overlays[0];9999+ ovli = &ovl->info;100100+101101+ pi->pos_x = ovli->pos_x;102102+ pi->pos_y = ovli->pos_y;103103+ pi->enabled = ovli->enabled;104104+ pi->channel_out = 0; /* xxx */105105+ pi->mirror = 0;106106+ pi->out_width = ovli->out_width;107107+ pi->out_height = ovli->out_height;108108+ }109109+110110+ return 0;111111+}112112+113113+static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)114114+{115115+ struct omapfb_info *ofbi = FB2OFB(fbi);116116+ struct omapfb2_device *fbdev = ofbi->fbdev;117117+ struct omapfb2_mem_region *rg;118118+ int r, i;119119+ size_t size;120120+121121+ if (mi->type > OMAPFB_MEMTYPE_MAX)122122+ return -EINVAL;123123+124124+ size = PAGE_ALIGN(mi->size);125125+126126+ rg = &ofbi->region;127127+128128+ for (i = 0; i < ofbi->num_overlays; i++) {129129+ if (ofbi->overlays[i]->info.enabled)130130+ return -EBUSY;131131+ }132132+133133+ if (rg->size != size || rg->type != mi->type) {134134+ r = omapfb_realloc_fbmem(fbi, size, mi->type);135135+ if (r) {136136+ dev_err(fbdev->dev, "realloc fbmem failed\n");137137+ return r;138138+ }139139+ }140140+141141+ return 0;142142+}143143+144144+static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)145145+{146146+ struct omapfb_info *ofbi = FB2OFB(fbi);147147+ struct omapfb2_mem_region *rg;148148+149149+ rg = &ofbi->region;150150+ memset(mi, 0, sizeof(*mi));151151+152152+ mi->size = rg->size;153153+ mi->type = rg->type;154154+155155+ return 0;156156+}157157+158158+static int omapfb_update_window_nolock(struct fb_info *fbi,159159+ u32 x, u32 y, u32 w, u32 h)160160+{161161+ struct omap_dss_device *display = fb2display(fbi);162162+ u16 dw, dh;163163+164164+ if (!display)165165+ return 0;166166+167167+ if (w == 0 || h == 0)168168+ return 0;169169+170170+ display->get_resolution(display, &dw, &dh);171171+172172+ if (x + w > dw || y + h > dh)173173+ return -EINVAL;174174+175175+ return display->update(display, x, y, w, h);176176+}177177+178178+/* This function is exported for SGX driver use */179179+int omapfb_update_window(struct fb_info *fbi,180180+ u32 x, u32 y, u32 w, u32 h)181181+{182182+ struct omapfb_info *ofbi = FB2OFB(fbi);183183+ struct omapfb2_device *fbdev = ofbi->fbdev;184184+ int r;185185+186186+ omapfb_lock(fbdev);187187+ lock_fb_info(fbi);188188+189189+ r = omapfb_update_window_nolock(fbi, x, y, w, h);190190+191191+ unlock_fb_info(fbi);192192+ omapfb_unlock(fbdev);193193+194194+ return r;195195+}196196+EXPORT_SYMBOL(omapfb_update_window);197197+198198+static int omapfb_set_update_mode(struct fb_info *fbi,199199+ enum omapfb_update_mode mode)200200+{201201+ struct omap_dss_device *display = fb2display(fbi);202202+ enum omap_dss_update_mode um;203203+ int r;204204+205205+ if (!display || !display->set_update_mode)206206+ return -EINVAL;207207+208208+ switch (mode) {209209+ case OMAPFB_UPDATE_DISABLED:210210+ um = OMAP_DSS_UPDATE_DISABLED;211211+ break;212212+213213+ case OMAPFB_AUTO_UPDATE:214214+ um = OMAP_DSS_UPDATE_AUTO;215215+ break;216216+217217+ case OMAPFB_MANUAL_UPDATE:218218+ um = OMAP_DSS_UPDATE_MANUAL;219219+ break;220220+221221+ default:222222+ return -EINVAL;223223+ }224224+225225+ r = display->set_update_mode(display, um);226226+227227+ return r;228228+}229229+230230+static int omapfb_get_update_mode(struct fb_info *fbi,231231+ enum omapfb_update_mode *mode)232232+{233233+ struct omap_dss_device *display = fb2display(fbi);234234+ enum omap_dss_update_mode m;235235+236236+ if (!display || !display->get_update_mode)237237+ return -EINVAL;238238+239239+ m = display->get_update_mode(display);240240+241241+ switch (m) {242242+ case OMAP_DSS_UPDATE_DISABLED:243243+ *mode = OMAPFB_UPDATE_DISABLED;244244+ break;245245+ case OMAP_DSS_UPDATE_AUTO:246246+ *mode = OMAPFB_AUTO_UPDATE;247247+ break;248248+ case OMAP_DSS_UPDATE_MANUAL:249249+ *mode = OMAPFB_MANUAL_UPDATE;250250+ break;251251+ default:252252+ BUG();253253+ }254254+255255+ return 0;256256+}257257+258258+/* XXX this color key handling is a hack... */259259+static struct omapfb_color_key omapfb_color_keys[2];260260+261261+static int _omapfb_set_color_key(struct omap_overlay_manager *mgr,262262+ struct omapfb_color_key *ck)263263+{264264+ struct omap_overlay_manager_info info;265265+ enum omap_dss_trans_key_type kt;266266+ int r;267267+268268+ mgr->get_manager_info(mgr, &info);269269+270270+ if (ck->key_type == OMAPFB_COLOR_KEY_DISABLED) {271271+ info.trans_enabled = false;272272+ omapfb_color_keys[mgr->id] = *ck;273273+274274+ r = mgr->set_manager_info(mgr, &info);275275+ if (r)276276+ return r;277277+278278+ r = mgr->apply(mgr);279279+280280+ return r;281281+ }282282+283283+ switch (ck->key_type) {284284+ case OMAPFB_COLOR_KEY_GFX_DST:285285+ kt = OMAP_DSS_COLOR_KEY_GFX_DST;286286+ break;287287+ case OMAPFB_COLOR_KEY_VID_SRC:288288+ kt = OMAP_DSS_COLOR_KEY_VID_SRC;289289+ break;290290+ default:291291+ return -EINVAL;292292+ }293293+294294+ info.default_color = ck->background;295295+ info.trans_key = ck->trans_key;296296+ info.trans_key_type = kt;297297+ info.trans_enabled = true;298298+299299+ omapfb_color_keys[mgr->id] = *ck;300300+301301+ r = mgr->set_manager_info(mgr, &info);302302+ if (r)303303+ return r;304304+305305+ r = mgr->apply(mgr);306306+307307+ return r;308308+}309309+310310+static int omapfb_set_color_key(struct fb_info *fbi,311311+ struct omapfb_color_key *ck)312312+{313313+ struct omapfb_info *ofbi = FB2OFB(fbi);314314+ struct omapfb2_device *fbdev = ofbi->fbdev;315315+ int r;316316+ int i;317317+ struct omap_overlay_manager *mgr = NULL;318318+319319+ omapfb_lock(fbdev);320320+321321+ for (i = 0; i < ofbi->num_overlays; i++) {322322+ if (ofbi->overlays[i]->manager) {323323+ mgr = ofbi->overlays[i]->manager;324324+ break;325325+ }326326+ }327327+328328+ if (!mgr) {329329+ r = -EINVAL;330330+ goto err;331331+ }332332+333333+ r = _omapfb_set_color_key(mgr, ck);334334+err:335335+ omapfb_unlock(fbdev);336336+337337+ return r;338338+}339339+340340+static int omapfb_get_color_key(struct fb_info *fbi,341341+ struct omapfb_color_key *ck)342342+{343343+ struct omapfb_info *ofbi = FB2OFB(fbi);344344+ struct omapfb2_device *fbdev = ofbi->fbdev;345345+ struct omap_overlay_manager *mgr = NULL;346346+ int r = 0;347347+ int i;348348+349349+ omapfb_lock(fbdev);350350+351351+ for (i = 0; i < ofbi->num_overlays; i++) {352352+ if (ofbi->overlays[i]->manager) {353353+ mgr = ofbi->overlays[i]->manager;354354+ break;355355+ }356356+ }357357+358358+ if (!mgr) {359359+ r = -EINVAL;360360+ goto err;361361+ }362362+363363+ *ck = omapfb_color_keys[mgr->id];364364+err:365365+ omapfb_unlock(fbdev);366366+367367+ return r;368368+}369369+370370+static int omapfb_memory_read(struct fb_info *fbi,371371+ struct omapfb_memory_read *mr)372372+{373373+ struct omap_dss_device *display = fb2display(fbi);374374+ void *buf;375375+ int r;376376+377377+ if (!display || !display->memory_read)378378+ return -ENOENT;379379+380380+ if (!access_ok(VERIFY_WRITE, mr->buffer, mr->buffer_size))381381+ return -EFAULT;382382+383383+ if (mr->w * mr->h * 3 > mr->buffer_size)384384+ return -EINVAL;385385+386386+ buf = vmalloc(mr->buffer_size);387387+ if (!buf) {388388+ DBG("vmalloc failed\n");389389+ return -ENOMEM;390390+ }391391+392392+ r = display->memory_read(display, buf, mr->buffer_size,393393+ mr->x, mr->y, mr->w, mr->h);394394+395395+ if (r > 0) {396396+ if (copy_to_user(mr->buffer, buf, mr->buffer_size))397397+ r = -EFAULT;398398+ }399399+400400+ vfree(buf);401401+402402+ return r;403403+}404404+405405+static int omapfb_get_ovl_colormode(struct omapfb2_device *fbdev,406406+ struct omapfb_ovl_colormode *mode)407407+{408408+ int ovl_idx = mode->overlay_idx;409409+ int mode_idx = mode->mode_idx;410410+ struct omap_overlay *ovl;411411+ enum omap_color_mode supported_modes;412412+ struct fb_var_screeninfo var;413413+ int i;414414+415415+ if (ovl_idx >= fbdev->num_overlays)416416+ return -ENODEV;417417+ ovl = fbdev->overlays[ovl_idx];418418+ supported_modes = ovl->supported_modes;419419+420420+ mode_idx = mode->mode_idx;421421+422422+ for (i = 0; i < sizeof(supported_modes) * 8; i++) {423423+ if (!(supported_modes & (1 << i)))424424+ continue;425425+ /*426426+ * It's possible that the FB doesn't support a mode427427+ * that is supported by the overlay, so call the428428+ * following here.429429+ */430430+ if (dss_mode_to_fb_mode(1 << i, &var) < 0)431431+ continue;432432+433433+ mode_idx--;434434+ if (mode_idx < 0)435435+ break;436436+ }437437+438438+ if (i == sizeof(supported_modes) * 8)439439+ return -ENOENT;440440+441441+ mode->bits_per_pixel = var.bits_per_pixel;442442+ mode->nonstd = var.nonstd;443443+ mode->red = var.red;444444+ mode->green = var.green;445445+ mode->blue = var.blue;446446+ mode->transp = var.transp;447447+448448+ return 0;449449+}450450+451451+static int omapfb_wait_for_go(struct fb_info *fbi)452452+{453453+ struct omapfb_info *ofbi = FB2OFB(fbi);454454+ int r = 0;455455+ int i;456456+457457+ for (i = 0; i < ofbi->num_overlays; ++i) {458458+ struct omap_overlay *ovl = ofbi->overlays[i];459459+ r = ovl->wait_for_go(ovl);460460+ if (r)461461+ break;462462+ }463463+464464+ return r;465465+}466466+467467+int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)468468+{469469+ struct omapfb_info *ofbi = FB2OFB(fbi);470470+ struct omapfb2_device *fbdev = ofbi->fbdev;471471+ struct omap_dss_device *display = fb2display(fbi);472472+473473+ union {474474+ struct omapfb_update_window_old uwnd_o;475475+ struct omapfb_update_window uwnd;476476+ struct omapfb_plane_info plane_info;477477+ struct omapfb_caps caps;478478+ struct omapfb_mem_info mem_info;479479+ struct omapfb_color_key color_key;480480+ struct omapfb_ovl_colormode ovl_colormode;481481+ enum omapfb_update_mode update_mode;482482+ int test_num;483483+ struct omapfb_memory_read memory_read;484484+ struct omapfb_vram_info vram_info;485485+ struct omapfb_tearsync_info tearsync_info;486486+ } p;487487+488488+ int r = 0;489489+490490+ switch (cmd) {491491+ case OMAPFB_SYNC_GFX:492492+ DBG("ioctl SYNC_GFX\n");493493+ if (!display || !display->sync) {494494+ /* DSS1 never returns an error here, so we neither */495495+ /*r = -EINVAL;*/496496+ break;497497+ }498498+499499+ r = display->sync(display);500500+ break;501501+502502+ case OMAPFB_UPDATE_WINDOW_OLD:503503+ DBG("ioctl UPDATE_WINDOW_OLD\n");504504+ if (!display || !display->update) {505505+ r = -EINVAL;506506+ break;507507+ }508508+509509+ if (copy_from_user(&p.uwnd_o,510510+ (void __user *)arg,511511+ sizeof(p.uwnd_o))) {512512+ r = -EFAULT;513513+ break;514514+ }515515+516516+ r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y,517517+ p.uwnd_o.width, p.uwnd_o.height);518518+ break;519519+520520+ case OMAPFB_UPDATE_WINDOW:521521+ DBG("ioctl UPDATE_WINDOW\n");522522+ if (!display || !display->update) {523523+ r = -EINVAL;524524+ break;525525+ }526526+527527+ if (copy_from_user(&p.uwnd, (void __user *)arg,528528+ sizeof(p.uwnd))) {529529+ r = -EFAULT;530530+ break;531531+ }532532+533533+ r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y,534534+ p.uwnd.width, p.uwnd.height);535535+ break;536536+537537+ case OMAPFB_SETUP_PLANE:538538+ DBG("ioctl SETUP_PLANE\n");539539+ if (copy_from_user(&p.plane_info, (void __user *)arg,540540+ sizeof(p.plane_info)))541541+ r = -EFAULT;542542+ else543543+ r = omapfb_setup_plane(fbi, &p.plane_info);544544+ break;545545+546546+ case OMAPFB_QUERY_PLANE:547547+ DBG("ioctl QUERY_PLANE\n");548548+ r = omapfb_query_plane(fbi, &p.plane_info);549549+ if (r < 0)550550+ break;551551+ if (copy_to_user((void __user *)arg, &p.plane_info,552552+ sizeof(p.plane_info)))553553+ r = -EFAULT;554554+ break;555555+556556+ case OMAPFB_SETUP_MEM:557557+ DBG("ioctl SETUP_MEM\n");558558+ if (copy_from_user(&p.mem_info, (void __user *)arg,559559+ sizeof(p.mem_info)))560560+ r = -EFAULT;561561+ else562562+ r = omapfb_setup_mem(fbi, &p.mem_info);563563+ break;564564+565565+ case OMAPFB_QUERY_MEM:566566+ DBG("ioctl QUERY_MEM\n");567567+ r = omapfb_query_mem(fbi, &p.mem_info);568568+ if (r < 0)569569+ break;570570+ if (copy_to_user((void __user *)arg, &p.mem_info,571571+ sizeof(p.mem_info)))572572+ r = -EFAULT;573573+ break;574574+575575+ case OMAPFB_GET_CAPS:576576+ DBG("ioctl GET_CAPS\n");577577+ if (!display) {578578+ r = -EINVAL;579579+ break;580580+ }581581+582582+ memset(&p.caps, 0, sizeof(p.caps));583583+ if (display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE)584584+ p.caps.ctrl |= OMAPFB_CAPS_MANUAL_UPDATE;585585+ if (display->caps & OMAP_DSS_DISPLAY_CAP_TEAR_ELIM)586586+ p.caps.ctrl |= OMAPFB_CAPS_TEARSYNC;587587+588588+ if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps)))589589+ r = -EFAULT;590590+ break;591591+592592+ case OMAPFB_GET_OVERLAY_COLORMODE:593593+ DBG("ioctl GET_OVERLAY_COLORMODE\n");594594+ if (copy_from_user(&p.ovl_colormode, (void __user *)arg,595595+ sizeof(p.ovl_colormode))) {596596+ r = -EFAULT;597597+ break;598598+ }599599+ r = omapfb_get_ovl_colormode(fbdev, &p.ovl_colormode);600600+ if (r < 0)601601+ break;602602+ if (copy_to_user((void __user *)arg, &p.ovl_colormode,603603+ sizeof(p.ovl_colormode)))604604+ r = -EFAULT;605605+ break;606606+607607+ case OMAPFB_SET_UPDATE_MODE:608608+ DBG("ioctl SET_UPDATE_MODE\n");609609+ if (get_user(p.update_mode, (int __user *)arg))610610+ r = -EFAULT;611611+ else612612+ r = omapfb_set_update_mode(fbi, p.update_mode);613613+ break;614614+615615+ case OMAPFB_GET_UPDATE_MODE:616616+ DBG("ioctl GET_UPDATE_MODE\n");617617+ r = omapfb_get_update_mode(fbi, &p.update_mode);618618+ if (r)619619+ break;620620+ if (put_user(p.update_mode,621621+ (enum omapfb_update_mode __user *)arg))622622+ r = -EFAULT;623623+ break;624624+625625+ case OMAPFB_SET_COLOR_KEY:626626+ DBG("ioctl SET_COLOR_KEY\n");627627+ if (copy_from_user(&p.color_key, (void __user *)arg,628628+ sizeof(p.color_key)))629629+ r = -EFAULT;630630+ else631631+ r = omapfb_set_color_key(fbi, &p.color_key);632632+ break;633633+634634+ case OMAPFB_GET_COLOR_KEY:635635+ DBG("ioctl GET_COLOR_KEY\n");636636+ r = omapfb_get_color_key(fbi, &p.color_key);637637+ if (r)638638+ break;639639+ if (copy_to_user((void __user *)arg, &p.color_key,640640+ sizeof(p.color_key)))641641+ r = -EFAULT;642642+ break;643643+644644+ case OMAPFB_WAITFORVSYNC:645645+ DBG("ioctl WAITFORVSYNC\n");646646+ if (!display) {647647+ r = -EINVAL;648648+ break;649649+ }650650+651651+ r = display->wait_vsync(display);652652+ break;653653+654654+ case OMAPFB_WAITFORGO:655655+ DBG("ioctl WAITFORGO\n");656656+ if (!display) {657657+ r = -EINVAL;658658+ break;659659+ }660660+661661+ r = omapfb_wait_for_go(fbi);662662+ break;663663+664664+ /* LCD and CTRL tests do the same thing for backward665665+ * compatibility */666666+ case OMAPFB_LCD_TEST:667667+ DBG("ioctl LCD_TEST\n");668668+ if (get_user(p.test_num, (int __user *)arg)) {669669+ r = -EFAULT;670670+ break;671671+ }672672+ if (!display || !display->run_test) {673673+ r = -EINVAL;674674+ break;675675+ }676676+677677+ r = display->run_test(display, p.test_num);678678+679679+ break;680680+681681+ case OMAPFB_CTRL_TEST:682682+ DBG("ioctl CTRL_TEST\n");683683+ if (get_user(p.test_num, (int __user *)arg)) {684684+ r = -EFAULT;685685+ break;686686+ }687687+ if (!display || !display->run_test) {688688+ r = -EINVAL;689689+ break;690690+ }691691+692692+ r = display->run_test(display, p.test_num);693693+694694+ break;695695+696696+ case OMAPFB_MEMORY_READ:697697+ DBG("ioctl MEMORY_READ\n");698698+699699+ if (copy_from_user(&p.memory_read, (void __user *)arg,700700+ sizeof(p.memory_read))) {701701+ r = -EFAULT;702702+ break;703703+ }704704+705705+ r = omapfb_memory_read(fbi, &p.memory_read);706706+707707+ break;708708+709709+ case OMAPFB_GET_VRAM_INFO: {710710+ unsigned long vram, free, largest;711711+712712+ DBG("ioctl GET_VRAM_INFO\n");713713+714714+ omap_vram_get_info(&vram, &free, &largest);715715+ p.vram_info.total = vram;716716+ p.vram_info.free = free;717717+ p.vram_info.largest_free_block = largest;718718+719719+ if (copy_to_user((void __user *)arg, &p.vram_info,720720+ sizeof(p.vram_info)))721721+ r = -EFAULT;722722+ break;723723+ }724724+725725+ case OMAPFB_SET_TEARSYNC: {726726+ DBG("ioctl SET_TEARSYNC\n");727727+728728+ if (copy_from_user(&p.tearsync_info, (void __user *)arg,729729+ sizeof(p.tearsync_info))) {730730+ r = -EFAULT;731731+ break;732732+ }733733+734734+ if (!display->enable_te) {735735+ r = -ENODEV;736736+ break;737737+ }738738+739739+ r = display->enable_te(display, !!p.tearsync_info.enabled);740740+741741+ break;742742+ }743743+744744+ default:745745+ dev_err(fbdev->dev, "Unknown ioctl 0x%x\n", cmd);746746+ r = -EINVAL;747747+ }748748+749749+ if (r < 0)750750+ DBG("ioctl failed: %d\n", r);751751+752752+ return r;753753+}754754+755755+
+2261
drivers/video/omap2/omapfb/omapfb-main.c
···11+/*22+ * linux/drivers/video/omap2/omapfb-main.c33+ *44+ * Copyright (C) 2008 Nokia Corporation55+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>66+ *77+ * Some code and ideas taken from drivers/video/omap/ driver88+ * by Imre Deak.99+ *1010+ * This program is free software; you can redistribute it and/or modify it1111+ * under the terms of the GNU General Public License version 2 as published by1212+ * the Free Software Foundation.1313+ *1414+ * This program is distributed in the hope that it will be useful, but WITHOUT1515+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1616+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1717+ * more details.1818+ *1919+ * You should have received a copy of the GNU General Public License along with2020+ * this program. If not, see <http://www.gnu.org/licenses/>.2121+ */2222+2323+#include <linux/module.h>2424+#include <linux/delay.h>2525+#include <linux/fb.h>2626+#include <linux/dma-mapping.h>2727+#include <linux/vmalloc.h>2828+#include <linux/device.h>2929+#include <linux/platform_device.h>3030+#include <linux/omapfb.h>3131+3232+#include <plat/display.h>3333+#include <plat/vram.h>3434+#include <plat/vrfb.h>3535+3636+#include "omapfb.h"3737+3838+#define MODULE_NAME "omapfb"3939+4040+#define OMAPFB_PLANE_XRES_MIN 84141+#define OMAPFB_PLANE_YRES_MIN 84242+4343+static char *def_mode;4444+static char *def_vram;4545+static int def_vrfb;4646+static int def_rotate;4747+static int def_mirror;4848+4949+#ifdef DEBUG5050+unsigned int omapfb_debug;5151+module_param_named(debug, omapfb_debug, bool, 0644);5252+static unsigned int omapfb_test_pattern;5353+module_param_named(test, omapfb_test_pattern, bool, 0644);5454+#endif5555+5656+static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi);5757+5858+#ifdef DEBUG5959+static void draw_pixel(struct fb_info *fbi, int x, int y, unsigned color)6060+{6161+ struct fb_var_screeninfo *var = &fbi->var;6262+ struct fb_fix_screeninfo *fix = &fbi->fix;6363+ void __iomem *addr = fbi->screen_base;6464+ const unsigned bytespp = var->bits_per_pixel >> 3;6565+ const unsigned line_len = fix->line_length / bytespp;6666+6767+ int r = (color >> 16) & 0xff;6868+ int g = (color >> 8) & 0xff;6969+ int b = (color >> 0) & 0xff;7070+7171+ if (var->bits_per_pixel == 16) {7272+ u16 __iomem *p = (u16 __iomem *)addr;7373+ p += y * line_len + x;7474+7575+ r = r * 32 / 256;7676+ g = g * 64 / 256;7777+ b = b * 32 / 256;7878+7979+ __raw_writew((r << 11) | (g << 5) | (b << 0), p);8080+ } else if (var->bits_per_pixel == 24) {8181+ u8 __iomem *p = (u8 __iomem *)addr;8282+ p += (y * line_len + x) * 3;8383+8484+ __raw_writeb(b, p + 0);8585+ __raw_writeb(g, p + 1);8686+ __raw_writeb(r, p + 2);8787+ } else if (var->bits_per_pixel == 32) {8888+ u32 __iomem *p = (u32 __iomem *)addr;8989+ p += y * line_len + x;9090+ __raw_writel(color, p);9191+ }9292+}9393+9494+static void fill_fb(struct fb_info *fbi)9595+{9696+ struct fb_var_screeninfo *var = &fbi->var;9797+ const short w = var->xres_virtual;9898+ const short h = var->yres_virtual;9999+ void __iomem *addr = fbi->screen_base;100100+ int y, x;101101+102102+ if (!addr)103103+ return;104104+105105+ DBG("fill_fb %dx%d, line_len %d bytes\n", w, h, fbi->fix.line_length);106106+107107+ for (y = 0; y < h; y++) {108108+ for (x = 0; x < w; x++) {109109+ if (x < 20 && y < 20)110110+ draw_pixel(fbi, x, y, 0xffffff);111111+ else if (x < 20 && (y > 20 && y < h - 20))112112+ draw_pixel(fbi, x, y, 0xff);113113+ else if (y < 20 && (x > 20 && x < w - 20))114114+ draw_pixel(fbi, x, y, 0xff00);115115+ else if (x > w - 20 && (y > 20 && y < h - 20))116116+ draw_pixel(fbi, x, y, 0xff0000);117117+ else if (y > h - 20 && (x > 20 && x < w - 20))118118+ draw_pixel(fbi, x, y, 0xffff00);119119+ else if (x == 20 || x == w - 20 ||120120+ y == 20 || y == h - 20)121121+ draw_pixel(fbi, x, y, 0xffffff);122122+ else if (x == y || w - x == h - y)123123+ draw_pixel(fbi, x, y, 0xff00ff);124124+ else if (w - x == y || x == h - y)125125+ draw_pixel(fbi, x, y, 0x00ffff);126126+ else if (x > 20 && y > 20 && x < w - 20 && y < h - 20) {127127+ int t = x * 3 / w;128128+ unsigned r = 0, g = 0, b = 0;129129+ unsigned c;130130+ if (var->bits_per_pixel == 16) {131131+ if (t == 0)132132+ b = (y % 32) * 256 / 32;133133+ else if (t == 1)134134+ g = (y % 64) * 256 / 64;135135+ else if (t == 2)136136+ r = (y % 32) * 256 / 32;137137+ } else {138138+ if (t == 0)139139+ b = (y % 256);140140+ else if (t == 1)141141+ g = (y % 256);142142+ else if (t == 2)143143+ r = (y % 256);144144+ }145145+ c = (r << 16) | (g << 8) | (b << 0);146146+ draw_pixel(fbi, x, y, c);147147+ } else {148148+ draw_pixel(fbi, x, y, 0);149149+ }150150+ }151151+ }152152+}153153+#endif154154+155155+static unsigned omapfb_get_vrfb_offset(struct omapfb_info *ofbi, int rot)156156+{157157+ struct vrfb *vrfb = &ofbi->region.vrfb;158158+ unsigned offset;159159+160160+ switch (rot) {161161+ case FB_ROTATE_UR:162162+ offset = 0;163163+ break;164164+ case FB_ROTATE_CW:165165+ offset = vrfb->yoffset;166166+ break;167167+ case FB_ROTATE_UD:168168+ offset = vrfb->yoffset * OMAP_VRFB_LINE_LEN + vrfb->xoffset;169169+ break;170170+ case FB_ROTATE_CCW:171171+ offset = vrfb->xoffset * OMAP_VRFB_LINE_LEN;172172+ break;173173+ default:174174+ BUG();175175+ }176176+177177+ offset *= vrfb->bytespp;178178+179179+ return offset;180180+}181181+182182+static u32 omapfb_get_region_rot_paddr(struct omapfb_info *ofbi, int rot)183183+{184184+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {185185+ return ofbi->region.vrfb.paddr[rot]186186+ + omapfb_get_vrfb_offset(ofbi, rot);187187+ } else {188188+ return ofbi->region.paddr;189189+ }190190+}191191+192192+static u32 omapfb_get_region_paddr(struct omapfb_info *ofbi)193193+{194194+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)195195+ return ofbi->region.vrfb.paddr[0];196196+ else197197+ return ofbi->region.paddr;198198+}199199+200200+static void __iomem *omapfb_get_region_vaddr(struct omapfb_info *ofbi)201201+{202202+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)203203+ return ofbi->region.vrfb.vaddr[0];204204+ else205205+ return ofbi->region.vaddr;206206+}207207+208208+static struct omapfb_colormode omapfb_colormodes[] = {209209+ {210210+ .dssmode = OMAP_DSS_COLOR_UYVY,211211+ .bits_per_pixel = 16,212212+ .nonstd = OMAPFB_COLOR_YUV422,213213+ }, {214214+ .dssmode = OMAP_DSS_COLOR_YUV2,215215+ .bits_per_pixel = 16,216216+ .nonstd = OMAPFB_COLOR_YUY422,217217+ }, {218218+ .dssmode = OMAP_DSS_COLOR_ARGB16,219219+ .bits_per_pixel = 16,220220+ .red = { .length = 4, .offset = 8, .msb_right = 0 },221221+ .green = { .length = 4, .offset = 4, .msb_right = 0 },222222+ .blue = { .length = 4, .offset = 0, .msb_right = 0 },223223+ .transp = { .length = 4, .offset = 12, .msb_right = 0 },224224+ }, {225225+ .dssmode = OMAP_DSS_COLOR_RGB16,226226+ .bits_per_pixel = 16,227227+ .red = { .length = 5, .offset = 11, .msb_right = 0 },228228+ .green = { .length = 6, .offset = 5, .msb_right = 0 },229229+ .blue = { .length = 5, .offset = 0, .msb_right = 0 },230230+ .transp = { .length = 0, .offset = 0, .msb_right = 0 },231231+ }, {232232+ .dssmode = OMAP_DSS_COLOR_RGB24P,233233+ .bits_per_pixel = 24,234234+ .red = { .length = 8, .offset = 16, .msb_right = 0 },235235+ .green = { .length = 8, .offset = 8, .msb_right = 0 },236236+ .blue = { .length = 8, .offset = 0, .msb_right = 0 },237237+ .transp = { .length = 0, .offset = 0, .msb_right = 0 },238238+ }, {239239+ .dssmode = OMAP_DSS_COLOR_RGB24U,240240+ .bits_per_pixel = 32,241241+ .red = { .length = 8, .offset = 16, .msb_right = 0 },242242+ .green = { .length = 8, .offset = 8, .msb_right = 0 },243243+ .blue = { .length = 8, .offset = 0, .msb_right = 0 },244244+ .transp = { .length = 0, .offset = 0, .msb_right = 0 },245245+ }, {246246+ .dssmode = OMAP_DSS_COLOR_ARGB32,247247+ .bits_per_pixel = 32,248248+ .red = { .length = 8, .offset = 16, .msb_right = 0 },249249+ .green = { .length = 8, .offset = 8, .msb_right = 0 },250250+ .blue = { .length = 8, .offset = 0, .msb_right = 0 },251251+ .transp = { .length = 8, .offset = 24, .msb_right = 0 },252252+ }, {253253+ .dssmode = OMAP_DSS_COLOR_RGBA32,254254+ .bits_per_pixel = 32,255255+ .red = { .length = 8, .offset = 24, .msb_right = 0 },256256+ .green = { .length = 8, .offset = 16, .msb_right = 0 },257257+ .blue = { .length = 8, .offset = 8, .msb_right = 0 },258258+ .transp = { .length = 8, .offset = 0, .msb_right = 0 },259259+ }, {260260+ .dssmode = OMAP_DSS_COLOR_RGBX32,261261+ .bits_per_pixel = 32,262262+ .red = { .length = 8, .offset = 24, .msb_right = 0 },263263+ .green = { .length = 8, .offset = 16, .msb_right = 0 },264264+ .blue = { .length = 8, .offset = 8, .msb_right = 0 },265265+ .transp = { .length = 0, .offset = 0, .msb_right = 0 },266266+ },267267+};268268+269269+static bool cmp_var_to_colormode(struct fb_var_screeninfo *var,270270+ struct omapfb_colormode *color)271271+{272272+ bool cmp_component(struct fb_bitfield *f1, struct fb_bitfield *f2)273273+ {274274+ return f1->length == f2->length &&275275+ f1->offset == f2->offset &&276276+ f1->msb_right == f2->msb_right;277277+ }278278+279279+ if (var->bits_per_pixel == 0 ||280280+ var->red.length == 0 ||281281+ var->blue.length == 0 ||282282+ var->green.length == 0)283283+ return 0;284284+285285+ return var->bits_per_pixel == color->bits_per_pixel &&286286+ cmp_component(&var->red, &color->red) &&287287+ cmp_component(&var->green, &color->green) &&288288+ cmp_component(&var->blue, &color->blue) &&289289+ cmp_component(&var->transp, &color->transp);290290+}291291+292292+static void assign_colormode_to_var(struct fb_var_screeninfo *var,293293+ struct omapfb_colormode *color)294294+{295295+ var->bits_per_pixel = color->bits_per_pixel;296296+ var->nonstd = color->nonstd;297297+ var->red = color->red;298298+ var->green = color->green;299299+ var->blue = color->blue;300300+ var->transp = color->transp;301301+}302302+303303+static int fb_mode_to_dss_mode(struct fb_var_screeninfo *var,304304+ enum omap_color_mode *mode)305305+{306306+ enum omap_color_mode dssmode;307307+ int i;308308+309309+ /* first match with nonstd field */310310+ if (var->nonstd) {311311+ for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {312312+ struct omapfb_colormode *m = &omapfb_colormodes[i];313313+ if (var->nonstd == m->nonstd) {314314+ assign_colormode_to_var(var, m);315315+ *mode = m->dssmode;316316+ return 0;317317+ }318318+ }319319+320320+ return -EINVAL;321321+ }322322+323323+ /* then try exact match of bpp and colors */324324+ for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {325325+ struct omapfb_colormode *m = &omapfb_colormodes[i];326326+ if (cmp_var_to_colormode(var, m)) {327327+ assign_colormode_to_var(var, m);328328+ *mode = m->dssmode;329329+ return 0;330330+ }331331+ }332332+333333+ /* match with bpp if user has not filled color fields334334+ * properly */335335+ switch (var->bits_per_pixel) {336336+ case 1:337337+ dssmode = OMAP_DSS_COLOR_CLUT1;338338+ break;339339+ case 2:340340+ dssmode = OMAP_DSS_COLOR_CLUT2;341341+ break;342342+ case 4:343343+ dssmode = OMAP_DSS_COLOR_CLUT4;344344+ break;345345+ case 8:346346+ dssmode = OMAP_DSS_COLOR_CLUT8;347347+ break;348348+ case 12:349349+ dssmode = OMAP_DSS_COLOR_RGB12U;350350+ break;351351+ case 16:352352+ dssmode = OMAP_DSS_COLOR_RGB16;353353+ break;354354+ case 24:355355+ dssmode = OMAP_DSS_COLOR_RGB24P;356356+ break;357357+ case 32:358358+ dssmode = OMAP_DSS_COLOR_RGB24U;359359+ break;360360+ default:361361+ return -EINVAL;362362+ }363363+364364+ for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {365365+ struct omapfb_colormode *m = &omapfb_colormodes[i];366366+ if (dssmode == m->dssmode) {367367+ assign_colormode_to_var(var, m);368368+ *mode = m->dssmode;369369+ return 0;370370+ }371371+ }372372+373373+ return -EINVAL;374374+}375375+376376+static int check_fb_res_bounds(struct fb_var_screeninfo *var)377377+{378378+ int xres_min = OMAPFB_PLANE_XRES_MIN;379379+ int xres_max = 2048;380380+ int yres_min = OMAPFB_PLANE_YRES_MIN;381381+ int yres_max = 2048;382382+383383+ /* XXX: some applications seem to set virtual res to 0. */384384+ if (var->xres_virtual == 0)385385+ var->xres_virtual = var->xres;386386+387387+ if (var->yres_virtual == 0)388388+ var->yres_virtual = var->yres;389389+390390+ if (var->xres_virtual < xres_min || var->yres_virtual < yres_min)391391+ return -EINVAL;392392+393393+ if (var->xres < xres_min)394394+ var->xres = xres_min;395395+ if (var->yres < yres_min)396396+ var->yres = yres_min;397397+ if (var->xres > xres_max)398398+ var->xres = xres_max;399399+ if (var->yres > yres_max)400400+ var->yres = yres_max;401401+402402+ if (var->xres > var->xres_virtual)403403+ var->xres = var->xres_virtual;404404+ if (var->yres > var->yres_virtual)405405+ var->yres = var->yres_virtual;406406+407407+ return 0;408408+}409409+410410+static void shrink_height(unsigned long max_frame_size,411411+ struct fb_var_screeninfo *var)412412+{413413+ DBG("can't fit FB into memory, reducing y\n");414414+ var->yres_virtual = max_frame_size /415415+ (var->xres_virtual * var->bits_per_pixel >> 3);416416+417417+ if (var->yres_virtual < OMAPFB_PLANE_YRES_MIN)418418+ var->yres_virtual = OMAPFB_PLANE_YRES_MIN;419419+420420+ if (var->yres > var->yres_virtual)421421+ var->yres = var->yres_virtual;422422+}423423+424424+static void shrink_width(unsigned long max_frame_size,425425+ struct fb_var_screeninfo *var)426426+{427427+ DBG("can't fit FB into memory, reducing x\n");428428+ var->xres_virtual = max_frame_size / var->yres_virtual /429429+ (var->bits_per_pixel >> 3);430430+431431+ if (var->xres_virtual < OMAPFB_PLANE_XRES_MIN)432432+ var->xres_virtual = OMAPFB_PLANE_XRES_MIN;433433+434434+ if (var->xres > var->xres_virtual)435435+ var->xres = var->xres_virtual;436436+}437437+438438+static int check_vrfb_fb_size(unsigned long region_size,439439+ const struct fb_var_screeninfo *var)440440+{441441+ unsigned long min_phys_size = omap_vrfb_min_phys_size(var->xres_virtual,442442+ var->yres_virtual, var->bits_per_pixel >> 3);443443+444444+ return min_phys_size > region_size ? -EINVAL : 0;445445+}446446+447447+static int check_fb_size(const struct omapfb_info *ofbi,448448+ struct fb_var_screeninfo *var)449449+{450450+ unsigned long max_frame_size = ofbi->region.size;451451+ int bytespp = var->bits_per_pixel >> 3;452452+ unsigned long line_size = var->xres_virtual * bytespp;453453+454454+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {455455+ /* One needs to check for both VRFB and OMAPFB limitations. */456456+ if (check_vrfb_fb_size(max_frame_size, var))457457+ shrink_height(omap_vrfb_max_height(458458+ max_frame_size, var->xres_virtual, bytespp) *459459+ line_size, var);460460+461461+ if (check_vrfb_fb_size(max_frame_size, var)) {462462+ DBG("cannot fit FB to memory\n");463463+ return -EINVAL;464464+ }465465+466466+ return 0;467467+ }468468+469469+ DBG("max frame size %lu, line size %lu\n", max_frame_size, line_size);470470+471471+ if (line_size * var->yres_virtual > max_frame_size)472472+ shrink_height(max_frame_size, var);473473+474474+ if (line_size * var->yres_virtual > max_frame_size) {475475+ shrink_width(max_frame_size, var);476476+ line_size = var->xres_virtual * bytespp;477477+ }478478+479479+ if (line_size * var->yres_virtual > max_frame_size) {480480+ DBG("cannot fit FB to memory\n");481481+ return -EINVAL;482482+ }483483+484484+ return 0;485485+}486486+487487+/*488488+ * Consider if VRFB assisted rotation is in use and if the virtual space for489489+ * the zero degree view needs to be mapped. The need for mapping also acts as490490+ * the trigger for setting up the hardware on the context in question. This491491+ * ensures that one does not attempt to access the virtual view before the492492+ * hardware is serving the address translations.493493+ */494494+static int setup_vrfb_rotation(struct fb_info *fbi)495495+{496496+ struct omapfb_info *ofbi = FB2OFB(fbi);497497+ struct omapfb2_mem_region *rg = &ofbi->region;498498+ struct vrfb *vrfb = &rg->vrfb;499499+ struct fb_var_screeninfo *var = &fbi->var;500500+ struct fb_fix_screeninfo *fix = &fbi->fix;501501+ unsigned bytespp;502502+ bool yuv_mode;503503+ enum omap_color_mode mode;504504+ int r;505505+ bool reconf;506506+507507+ if (!rg->size || ofbi->rotation_type != OMAP_DSS_ROT_VRFB)508508+ return 0;509509+510510+ DBG("setup_vrfb_rotation\n");511511+512512+ r = fb_mode_to_dss_mode(var, &mode);513513+ if (r)514514+ return r;515515+516516+ bytespp = var->bits_per_pixel >> 3;517517+518518+ yuv_mode = mode == OMAP_DSS_COLOR_YUV2 || mode == OMAP_DSS_COLOR_UYVY;519519+520520+ /* We need to reconfigure VRFB if the resolution changes, if yuv mode521521+ * is enabled/disabled, or if bytes per pixel changes */522522+523523+ /* XXX we shouldn't allow this when framebuffer is mmapped */524524+525525+ reconf = false;526526+527527+ if (yuv_mode != vrfb->yuv_mode)528528+ reconf = true;529529+ else if (bytespp != vrfb->bytespp)530530+ reconf = true;531531+ else if (vrfb->xres != var->xres_virtual ||532532+ vrfb->yres != var->yres_virtual)533533+ reconf = true;534534+535535+ if (vrfb->vaddr[0] && reconf) {536536+ fbi->screen_base = NULL;537537+ fix->smem_start = 0;538538+ fix->smem_len = 0;539539+ iounmap(vrfb->vaddr[0]);540540+ vrfb->vaddr[0] = NULL;541541+ DBG("setup_vrfb_rotation: reset fb\n");542542+ }543543+544544+ if (vrfb->vaddr[0])545545+ return 0;546546+547547+ omap_vrfb_setup(&rg->vrfb, rg->paddr,548548+ var->xres_virtual,549549+ var->yres_virtual,550550+ bytespp, yuv_mode);551551+552552+ /* Now one can ioremap the 0 angle view */553553+ r = omap_vrfb_map_angle(vrfb, var->yres_virtual, 0);554554+ if (r)555555+ return r;556556+557557+ /* used by open/write in fbmem.c */558558+ fbi->screen_base = ofbi->region.vrfb.vaddr[0];559559+560560+ fix->smem_start = ofbi->region.vrfb.paddr[0];561561+562562+ switch (var->nonstd) {563563+ case OMAPFB_COLOR_YUV422:564564+ case OMAPFB_COLOR_YUY422:565565+ fix->line_length =566566+ (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;567567+ break;568568+ default:569569+ fix->line_length =570570+ (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;571571+ break;572572+ }573573+574574+ fix->smem_len = var->yres_virtual * fix->line_length;575575+576576+ return 0;577577+}578578+579579+int dss_mode_to_fb_mode(enum omap_color_mode dssmode,580580+ struct fb_var_screeninfo *var)581581+{582582+ int i;583583+584584+ for (i = 0; i < ARRAY_SIZE(omapfb_colormodes); ++i) {585585+ struct omapfb_colormode *mode = &omapfb_colormodes[i];586586+ if (dssmode == mode->dssmode) {587587+ assign_colormode_to_var(var, mode);588588+ return 0;589589+ }590590+ }591591+ return -ENOENT;592592+}593593+594594+void set_fb_fix(struct fb_info *fbi)595595+{596596+ struct fb_fix_screeninfo *fix = &fbi->fix;597597+ struct fb_var_screeninfo *var = &fbi->var;598598+ struct omapfb_info *ofbi = FB2OFB(fbi);599599+ struct omapfb2_mem_region *rg = &ofbi->region;600600+601601+ DBG("set_fb_fix\n");602602+603603+ /* used by open/write in fbmem.c */604604+ fbi->screen_base = (char __iomem *)omapfb_get_region_vaddr(ofbi);605605+606606+ /* used by mmap in fbmem.c */607607+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {608608+ switch (var->nonstd) {609609+ case OMAPFB_COLOR_YUV422:610610+ case OMAPFB_COLOR_YUY422:611611+ fix->line_length =612612+ (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 2;613613+ break;614614+ default:615615+ fix->line_length =616616+ (OMAP_VRFB_LINE_LEN * var->bits_per_pixel) >> 3;617617+ break;618618+ }619619+620620+ fix->smem_len = var->yres_virtual * fix->line_length;621621+ } else {622622+ fix->line_length =623623+ (var->xres_virtual * var->bits_per_pixel) >> 3;624624+ fix->smem_len = rg->size;625625+ }626626+627627+ fix->smem_start = omapfb_get_region_paddr(ofbi);628628+629629+ fix->type = FB_TYPE_PACKED_PIXELS;630630+631631+ if (var->nonstd)632632+ fix->visual = FB_VISUAL_PSEUDOCOLOR;633633+ else {634634+ switch (var->bits_per_pixel) {635635+ case 32:636636+ case 24:637637+ case 16:638638+ case 12:639639+ fix->visual = FB_VISUAL_TRUECOLOR;640640+ /* 12bpp is stored in 16 bits */641641+ break;642642+ case 1:643643+ case 2:644644+ case 4:645645+ case 8:646646+ fix->visual = FB_VISUAL_PSEUDOCOLOR;647647+ break;648648+ }649649+ }650650+651651+ fix->accel = FB_ACCEL_NONE;652652+653653+ fix->xpanstep = 1;654654+ fix->ypanstep = 1;655655+}656656+657657+/* check new var and possibly modify it to be ok */658658+int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var)659659+{660660+ struct omapfb_info *ofbi = FB2OFB(fbi);661661+ struct omap_dss_device *display = fb2display(fbi);662662+ enum omap_color_mode mode = 0;663663+ int i;664664+ int r;665665+666666+ DBG("check_fb_var %d\n", ofbi->id);667667+668668+ if (ofbi->region.size == 0)669669+ return 0;670670+671671+ r = fb_mode_to_dss_mode(var, &mode);672672+ if (r) {673673+ DBG("cannot convert var to omap dss mode\n");674674+ return r;675675+ }676676+677677+ for (i = 0; i < ofbi->num_overlays; ++i) {678678+ if ((ofbi->overlays[i]->supported_modes & mode) == 0) {679679+ DBG("invalid mode\n");680680+ return -EINVAL;681681+ }682682+ }683683+684684+ if (var->rotate < 0 || var->rotate > 3)685685+ return -EINVAL;686686+687687+ if (check_fb_res_bounds(var))688688+ return -EINVAL;689689+690690+ if (check_fb_size(ofbi, var))691691+ return -EINVAL;692692+693693+ if (var->xres + var->xoffset > var->xres_virtual)694694+ var->xoffset = var->xres_virtual - var->xres;695695+ if (var->yres + var->yoffset > var->yres_virtual)696696+ var->yoffset = var->yres_virtual - var->yres;697697+698698+ DBG("xres = %d, yres = %d, vxres = %d, vyres = %d\n",699699+ var->xres, var->yres,700700+ var->xres_virtual, var->yres_virtual);701701+702702+ var->height = -1;703703+ var->width = -1;704704+ var->grayscale = 0;705705+706706+ if (display && display->get_timings) {707707+ struct omap_video_timings timings;708708+ display->get_timings(display, &timings);709709+710710+ /* pixclock in ps, the rest in pixclock */711711+ var->pixclock = timings.pixel_clock != 0 ?712712+ KHZ2PICOS(timings.pixel_clock) :713713+ 0;714714+ var->left_margin = timings.hfp;715715+ var->right_margin = timings.hbp;716716+ var->upper_margin = timings.vfp;717717+ var->lower_margin = timings.vbp;718718+ var->hsync_len = timings.hsw;719719+ var->vsync_len = timings.vsw;720720+ } else {721721+ var->pixclock = 0;722722+ var->left_margin = 0;723723+ var->right_margin = 0;724724+ var->upper_margin = 0;725725+ var->lower_margin = 0;726726+ var->hsync_len = 0;727727+ var->vsync_len = 0;728728+ }729729+730730+ /* TODO: get these from panel->config */731731+ var->vmode = FB_VMODE_NONINTERLACED;732732+ var->sync = 0;733733+734734+ return 0;735735+}736736+737737+/*738738+ * ---------------------------------------------------------------------------739739+ * fbdev framework callbacks740740+ * ---------------------------------------------------------------------------741741+ */742742+static int omapfb_open(struct fb_info *fbi, int user)743743+{744744+ return 0;745745+}746746+747747+static int omapfb_release(struct fb_info *fbi, int user)748748+{749749+#if 0750750+ struct omapfb_info *ofbi = FB2OFB(fbi);751751+ struct omapfb2_device *fbdev = ofbi->fbdev;752752+ struct omap_dss_device *display = fb2display(fbi);753753+754754+ DBG("Closing fb with plane index %d\n", ofbi->id);755755+756756+ omapfb_lock(fbdev);757757+758758+ if (display && display->get_update_mode && display->update) {759759+ /* XXX this update should be removed, I think. But it's760760+ * good for debugging */761761+ if (display->get_update_mode(display) ==762762+ OMAP_DSS_UPDATE_MANUAL) {763763+ u16 w, h;764764+765765+ if (display->sync)766766+ display->sync(display);767767+768768+ display->get_resolution(display, &w, &h);769769+ display->update(display, 0, 0, w, h);770770+ }771771+ }772772+773773+ if (display && display->sync)774774+ display->sync(display);775775+776776+ omapfb_unlock(fbdev);777777+#endif778778+ return 0;779779+}780780+781781+static unsigned calc_rotation_offset_dma(struct fb_var_screeninfo *var,782782+ struct fb_fix_screeninfo *fix, int rotation)783783+{784784+ unsigned offset;785785+786786+ offset = var->yoffset * fix->line_length +787787+ var->xoffset * (var->bits_per_pixel >> 3);788788+789789+ return offset;790790+}791791+792792+static unsigned calc_rotation_offset_vrfb(struct fb_var_screeninfo *var,793793+ struct fb_fix_screeninfo *fix, int rotation)794794+{795795+ unsigned offset;796796+797797+ if (rotation == FB_ROTATE_UD)798798+ offset = (var->yres_virtual - var->yres) *799799+ fix->line_length;800800+ else if (rotation == FB_ROTATE_CW)801801+ offset = (var->yres_virtual - var->yres) *802802+ (var->bits_per_pixel >> 3);803803+ else804804+ offset = 0;805805+806806+ if (rotation == FB_ROTATE_UR)807807+ offset += var->yoffset * fix->line_length +808808+ var->xoffset * (var->bits_per_pixel >> 3);809809+ else if (rotation == FB_ROTATE_UD)810810+ offset -= var->yoffset * fix->line_length +811811+ var->xoffset * (var->bits_per_pixel >> 3);812812+ else if (rotation == FB_ROTATE_CW)813813+ offset -= var->xoffset * fix->line_length +814814+ var->yoffset * (var->bits_per_pixel >> 3);815815+ else if (rotation == FB_ROTATE_CCW)816816+ offset += var->xoffset * fix->line_length +817817+ var->yoffset * (var->bits_per_pixel >> 3);818818+819819+ return offset;820820+}821821+822822+823823+/* setup overlay according to the fb */824824+static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl,825825+ u16 posx, u16 posy, u16 outw, u16 outh)826826+{827827+ int r = 0;828828+ struct omapfb_info *ofbi = FB2OFB(fbi);829829+ struct fb_var_screeninfo *var = &fbi->var;830830+ struct fb_fix_screeninfo *fix = &fbi->fix;831831+ enum omap_color_mode mode = 0;832832+ int offset;833833+ u32 data_start_p;834834+ void __iomem *data_start_v;835835+ struct omap_overlay_info info;836836+ int xres, yres;837837+ int screen_width;838838+ int mirror;839839+ int rotation = var->rotate;840840+ int i;841841+842842+ for (i = 0; i < ofbi->num_overlays; i++) {843843+ if (ovl != ofbi->overlays[i])844844+ continue;845845+846846+ rotation = (rotation + ofbi->rotation[i]) % 4;847847+ break;848848+ }849849+850850+ DBG("setup_overlay %d, posx %d, posy %d, outw %d, outh %d\n", ofbi->id,851851+ posx, posy, outw, outh);852852+853853+ if (rotation == FB_ROTATE_CW || rotation == FB_ROTATE_CCW) {854854+ xres = var->yres;855855+ yres = var->xres;856856+ } else {857857+ xres = var->xres;858858+ yres = var->yres;859859+ }860860+861861+862862+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {863863+ data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation);864864+ data_start_v = NULL;865865+ } else {866866+ data_start_p = omapfb_get_region_paddr(ofbi);867867+ data_start_v = omapfb_get_region_vaddr(ofbi);868868+ }869869+870870+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)871871+ offset = calc_rotation_offset_vrfb(var, fix, rotation);872872+ else873873+ offset = calc_rotation_offset_dma(var, fix, rotation);874874+875875+ data_start_p += offset;876876+ data_start_v += offset;877877+878878+ if (offset)879879+ DBG("offset %d, %d = %d\n",880880+ var->xoffset, var->yoffset, offset);881881+882882+ DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v);883883+884884+ r = fb_mode_to_dss_mode(var, &mode);885885+ if (r) {886886+ DBG("fb_mode_to_dss_mode failed");887887+ goto err;888888+ }889889+890890+ switch (var->nonstd) {891891+ case OMAPFB_COLOR_YUV422:892892+ case OMAPFB_COLOR_YUY422:893893+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {894894+ screen_width = fix->line_length895895+ / (var->bits_per_pixel >> 2);896896+ break;897897+ }898898+ default:899899+ screen_width = fix->line_length / (var->bits_per_pixel >> 3);900900+ break;901901+ }902902+903903+ ovl->get_overlay_info(ovl, &info);904904+905905+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB)906906+ mirror = 0;907907+ else908908+ mirror = ofbi->mirror;909909+910910+ info.paddr = data_start_p;911911+ info.vaddr = data_start_v;912912+ info.screen_width = screen_width;913913+ info.width = xres;914914+ info.height = yres;915915+ info.color_mode = mode;916916+ info.rotation_type = ofbi->rotation_type;917917+ info.rotation = rotation;918918+ info.mirror = mirror;919919+920920+ info.pos_x = posx;921921+ info.pos_y = posy;922922+ info.out_width = outw;923923+ info.out_height = outh;924924+925925+ r = ovl->set_overlay_info(ovl, &info);926926+ if (r) {927927+ DBG("ovl->setup_overlay_info failed\n");928928+ goto err;929929+ }930930+931931+ return 0;932932+933933+err:934934+ DBG("setup_overlay failed\n");935935+ return r;936936+}937937+938938+/* apply var to the overlay */939939+int omapfb_apply_changes(struct fb_info *fbi, int init)940940+{941941+ int r = 0;942942+ struct omapfb_info *ofbi = FB2OFB(fbi);943943+ struct fb_var_screeninfo *var = &fbi->var;944944+ struct omap_overlay *ovl;945945+ u16 posx, posy;946946+ u16 outw, outh;947947+ int i;948948+949949+#ifdef DEBUG950950+ if (omapfb_test_pattern)951951+ fill_fb(fbi);952952+#endif953953+954954+ for (i = 0; i < ofbi->num_overlays; i++) {955955+ ovl = ofbi->overlays[i];956956+957957+ DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id);958958+959959+ if (ofbi->region.size == 0) {960960+ /* the fb is not available. disable the overlay */961961+ omapfb_overlay_enable(ovl, 0);962962+ if (!init && ovl->manager)963963+ ovl->manager->apply(ovl->manager);964964+ continue;965965+ }966966+967967+ if (init || (ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) {968968+ int rotation = (var->rotate + ofbi->rotation[i]) % 4;969969+ if (rotation == FB_ROTATE_CW ||970970+ rotation == FB_ROTATE_CCW) {971971+ outw = var->yres;972972+ outh = var->xres;973973+ } else {974974+ outw = var->xres;975975+ outh = var->yres;976976+ }977977+ } else {978978+ outw = ovl->info.out_width;979979+ outh = ovl->info.out_height;980980+ }981981+982982+ if (init) {983983+ posx = 0;984984+ posy = 0;985985+ } else {986986+ posx = ovl->info.pos_x;987987+ posy = ovl->info.pos_y;988988+ }989989+990990+ r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh);991991+ if (r)992992+ goto err;993993+994994+ if (!init && ovl->manager)995995+ ovl->manager->apply(ovl->manager);996996+ }997997+ return 0;998998+err:999999+ DBG("apply_changes failed\n");10001000+ return r;10011001+}10021002+10031003+/* checks var and eventually tweaks it to something supported,10041004+ * DO NOT MODIFY PAR */10051005+static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi)10061006+{10071007+ int r;10081008+10091009+ DBG("check_var(%d)\n", FB2OFB(fbi)->id);10101010+10111011+ r = check_fb_var(fbi, var);10121012+10131013+ return r;10141014+}10151015+10161016+/* set the video mode according to info->var */10171017+static int omapfb_set_par(struct fb_info *fbi)10181018+{10191019+ int r;10201020+10211021+ DBG("set_par(%d)\n", FB2OFB(fbi)->id);10221022+10231023+ set_fb_fix(fbi);10241024+10251025+ r = setup_vrfb_rotation(fbi);10261026+ if (r)10271027+ return r;10281028+10291029+ r = omapfb_apply_changes(fbi, 0);10301030+10311031+ return r;10321032+}10331033+10341034+static int omapfb_pan_display(struct fb_var_screeninfo *var,10351035+ struct fb_info *fbi)10361036+{10371037+ struct fb_var_screeninfo new_var;10381038+ int r;10391039+10401040+ DBG("pan_display(%d)\n", FB2OFB(fbi)->id);10411041+10421042+ if (var->xoffset == fbi->var.xoffset &&10431043+ var->yoffset == fbi->var.yoffset)10441044+ return 0;10451045+10461046+ new_var = fbi->var;10471047+ new_var.xoffset = var->xoffset;10481048+ new_var.yoffset = var->yoffset;10491049+10501050+ fbi->var = new_var;10511051+10521052+ r = omapfb_apply_changes(fbi, 0);10531053+10541054+ return r;10551055+}10561056+10571057+static void mmap_user_open(struct vm_area_struct *vma)10581058+{10591059+ struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;10601060+10611061+ atomic_inc(&ofbi->map_count);10621062+}10631063+10641064+static void mmap_user_close(struct vm_area_struct *vma)10651065+{10661066+ struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data;10671067+10681068+ atomic_dec(&ofbi->map_count);10691069+}10701070+10711071+static struct vm_operations_struct mmap_user_ops = {10721072+ .open = mmap_user_open,10731073+ .close = mmap_user_close,10741074+};10751075+10761076+static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)10771077+{10781078+ struct omapfb_info *ofbi = FB2OFB(fbi);10791079+ struct fb_fix_screeninfo *fix = &fbi->fix;10801080+ unsigned long off;10811081+ unsigned long start;10821082+ u32 len;10831083+10841084+ if (vma->vm_end - vma->vm_start == 0)10851085+ return 0;10861086+ if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))10871087+ return -EINVAL;10881088+ off = vma->vm_pgoff << PAGE_SHIFT;10891089+10901090+ start = omapfb_get_region_paddr(ofbi);10911091+ len = fix->smem_len;10921092+ if (off >= len)10931093+ return -EINVAL;10941094+ if ((vma->vm_end - vma->vm_start + off) > len)10951095+ return -EINVAL;10961096+10971097+ off += start;10981098+10991099+ DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off);11001100+11011101+ vma->vm_pgoff = off >> PAGE_SHIFT;11021102+ vma->vm_flags |= VM_IO | VM_RESERVED;11031103+ vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);11041104+ vma->vm_ops = &mmap_user_ops;11051105+ vma->vm_private_data = ofbi;11061106+ if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,11071107+ vma->vm_end - vma->vm_start, vma->vm_page_prot))11081108+ return -EAGAIN;11091109+ /* vm_ops.open won't be called for mmap itself. */11101110+ atomic_inc(&ofbi->map_count);11111111+ return 0;11121112+}11131113+11141114+/* Store a single color palette entry into a pseudo palette or the hardware11151115+ * palette if one is available. For now we support only 16bpp and thus store11161116+ * the entry only to the pseudo palette.11171117+ */11181118+static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green,11191119+ u_int blue, u_int transp, int update_hw_pal)11201120+{11211121+ /*struct omapfb_info *ofbi = FB2OFB(fbi);*/11221122+ /*struct omapfb2_device *fbdev = ofbi->fbdev;*/11231123+ struct fb_var_screeninfo *var = &fbi->var;11241124+ int r = 0;11251125+11261126+ enum omapfb_color_format mode = OMAPFB_COLOR_RGB24U; /* XXX */11271127+11281128+ /*switch (plane->color_mode) {*/11291129+ switch (mode) {11301130+ case OMAPFB_COLOR_YUV422:11311131+ case OMAPFB_COLOR_YUV420:11321132+ case OMAPFB_COLOR_YUY422:11331133+ r = -EINVAL;11341134+ break;11351135+ case OMAPFB_COLOR_CLUT_8BPP:11361136+ case OMAPFB_COLOR_CLUT_4BPP:11371137+ case OMAPFB_COLOR_CLUT_2BPP:11381138+ case OMAPFB_COLOR_CLUT_1BPP:11391139+ /*11401140+ if (fbdev->ctrl->setcolreg)11411141+ r = fbdev->ctrl->setcolreg(regno, red, green, blue,11421142+ transp, update_hw_pal);11431143+ */11441144+ /* Fallthrough */11451145+ r = -EINVAL;11461146+ break;11471147+ case OMAPFB_COLOR_RGB565:11481148+ case OMAPFB_COLOR_RGB444:11491149+ case OMAPFB_COLOR_RGB24P:11501150+ case OMAPFB_COLOR_RGB24U:11511151+ if (r != 0)11521152+ break;11531153+11541154+ if (regno < 0) {11551155+ r = -EINVAL;11561156+ break;11571157+ }11581158+11591159+ if (regno < 16) {11601160+ u16 pal;11611161+ pal = ((red >> (16 - var->red.length)) <<11621162+ var->red.offset) |11631163+ ((green >> (16 - var->green.length)) <<11641164+ var->green.offset) |11651165+ (blue >> (16 - var->blue.length));11661166+ ((u32 *)(fbi->pseudo_palette))[regno] = pal;11671167+ }11681168+ break;11691169+ default:11701170+ BUG();11711171+ }11721172+ return r;11731173+}11741174+11751175+static int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,11761176+ u_int transp, struct fb_info *info)11771177+{11781178+ DBG("setcolreg\n");11791179+11801180+ return _setcolreg(info, regno, red, green, blue, transp, 1);11811181+}11821182+11831183+static int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info)11841184+{11851185+ int count, index, r;11861186+ u16 *red, *green, *blue, *transp;11871187+ u16 trans = 0xffff;11881188+11891189+ DBG("setcmap\n");11901190+11911191+ red = cmap->red;11921192+ green = cmap->green;11931193+ blue = cmap->blue;11941194+ transp = cmap->transp;11951195+ index = cmap->start;11961196+11971197+ for (count = 0; count < cmap->len; count++) {11981198+ if (transp)11991199+ trans = *transp++;12001200+ r = _setcolreg(info, index++, *red++, *green++, *blue++, trans,12011201+ count == cmap->len - 1);12021202+ if (r != 0)12031203+ return r;12041204+ }12051205+12061206+ return 0;12071207+}12081208+12091209+static int omapfb_blank(int blank, struct fb_info *fbi)12101210+{12111211+ struct omapfb_info *ofbi = FB2OFB(fbi);12121212+ struct omapfb2_device *fbdev = ofbi->fbdev;12131213+ struct omap_dss_device *display = fb2display(fbi);12141214+ int do_update = 0;12151215+ int r = 0;12161216+12171217+ omapfb_lock(fbdev);12181218+12191219+ switch (blank) {12201220+ case FB_BLANK_UNBLANK:12211221+ if (display->state != OMAP_DSS_DISPLAY_SUSPENDED)12221222+ goto exit;12231223+12241224+ if (display->resume)12251225+ r = display->resume(display);12261226+12271227+ if (r == 0 && display->get_update_mode &&12281228+ display->get_update_mode(display) ==12291229+ OMAP_DSS_UPDATE_MANUAL)12301230+ do_update = 1;12311231+12321232+ break;12331233+12341234+ case FB_BLANK_NORMAL:12351235+ /* FB_BLANK_NORMAL could be implemented.12361236+ * Needs DSS additions. */12371237+ case FB_BLANK_VSYNC_SUSPEND:12381238+ case FB_BLANK_HSYNC_SUSPEND:12391239+ case FB_BLANK_POWERDOWN:12401240+ if (display->state != OMAP_DSS_DISPLAY_ACTIVE)12411241+ goto exit;12421242+12431243+ if (display->suspend)12441244+ r = display->suspend(display);12451245+12461246+ break;12471247+12481248+ default:12491249+ r = -EINVAL;12501250+ }12511251+12521252+exit:12531253+ omapfb_unlock(fbdev);12541254+12551255+ if (r == 0 && do_update && display->update) {12561256+ u16 w, h;12571257+ display->get_resolution(display, &w, &h);12581258+12591259+ r = display->update(display, 0, 0, w, h);12601260+ }12611261+12621262+ return r;12631263+}12641264+12651265+#if 012661266+/* XXX fb_read and fb_write are needed for VRFB */12671267+ssize_t omapfb_write(struct fb_info *info, const char __user *buf,12681268+ size_t count, loff_t *ppos)12691269+{12701270+ DBG("omapfb_write %d, %lu\n", count, (unsigned long)*ppos);12711271+ /* XXX needed for VRFB */12721272+ return count;12731273+}12741274+#endif12751275+12761276+static struct fb_ops omapfb_ops = {12771277+ .owner = THIS_MODULE,12781278+ .fb_open = omapfb_open,12791279+ .fb_release = omapfb_release,12801280+ .fb_fillrect = cfb_fillrect,12811281+ .fb_copyarea = cfb_copyarea,12821282+ .fb_imageblit = cfb_imageblit,12831283+ .fb_blank = omapfb_blank,12841284+ .fb_ioctl = omapfb_ioctl,12851285+ .fb_check_var = omapfb_check_var,12861286+ .fb_set_par = omapfb_set_par,12871287+ .fb_pan_display = omapfb_pan_display,12881288+ .fb_mmap = omapfb_mmap,12891289+ .fb_setcolreg = omapfb_setcolreg,12901290+ .fb_setcmap = omapfb_setcmap,12911291+ /*.fb_write = omapfb_write,*/12921292+};12931293+12941294+static void omapfb_free_fbmem(struct fb_info *fbi)12951295+{12961296+ struct omapfb_info *ofbi = FB2OFB(fbi);12971297+ struct omapfb2_device *fbdev = ofbi->fbdev;12981298+ struct omapfb2_mem_region *rg;12991299+13001300+ rg = &ofbi->region;13011301+13021302+ if (rg->paddr)13031303+ if (omap_vram_free(rg->paddr, rg->size))13041304+ dev_err(fbdev->dev, "VRAM FREE failed\n");13051305+13061306+ if (rg->vaddr)13071307+ iounmap(rg->vaddr);13081308+13091309+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {13101310+ /* unmap the 0 angle rotation */13111311+ if (rg->vrfb.vaddr[0]) {13121312+ iounmap(rg->vrfb.vaddr[0]);13131313+ omap_vrfb_release_ctx(&rg->vrfb);13141314+ }13151315+ }13161316+13171317+ rg->vaddr = NULL;13181318+ rg->paddr = 0;13191319+ rg->alloc = 0;13201320+ rg->size = 0;13211321+}13221322+13231323+static void clear_fb_info(struct fb_info *fbi)13241324+{13251325+ memset(&fbi->var, 0, sizeof(fbi->var));13261326+ memset(&fbi->fix, 0, sizeof(fbi->fix));13271327+ strlcpy(fbi->fix.id, MODULE_NAME, sizeof(fbi->fix.id));13281328+}13291329+13301330+static int omapfb_free_all_fbmem(struct omapfb2_device *fbdev)13311331+{13321332+ int i;13331333+13341334+ DBG("free all fbmem\n");13351335+13361336+ for (i = 0; i < fbdev->num_fbs; i++) {13371337+ struct fb_info *fbi = fbdev->fbs[i];13381338+ omapfb_free_fbmem(fbi);13391339+ clear_fb_info(fbi);13401340+ }13411341+13421342+ return 0;13431343+}13441344+13451345+static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size,13461346+ unsigned long paddr)13471347+{13481348+ struct omapfb_info *ofbi = FB2OFB(fbi);13491349+ struct omapfb2_device *fbdev = ofbi->fbdev;13501350+ struct omapfb2_mem_region *rg;13511351+ void __iomem *vaddr;13521352+ int r;13531353+13541354+ rg = &ofbi->region;13551355+ memset(rg, 0, sizeof(*rg));13561356+13571357+ size = PAGE_ALIGN(size);13581358+13591359+ if (!paddr) {13601360+ DBG("allocating %lu bytes for fb %d\n", size, ofbi->id);13611361+ r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr);13621362+ } else {13631363+ DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr,13641364+ ofbi->id);13651365+ r = omap_vram_reserve(paddr, size);13661366+ }13671367+13681368+ if (r) {13691369+ dev_err(fbdev->dev, "failed to allocate framebuffer\n");13701370+ return -ENOMEM;13711371+ }13721372+13731373+ if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) {13741374+ vaddr = ioremap_wc(paddr, size);13751375+13761376+ if (!vaddr) {13771377+ dev_err(fbdev->dev, "failed to ioremap framebuffer\n");13781378+ omap_vram_free(paddr, size);13791379+ return -ENOMEM;13801380+ }13811381+13821382+ DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr);13831383+ } else {13841384+ r = omap_vrfb_request_ctx(&rg->vrfb);13851385+ if (r) {13861386+ dev_err(fbdev->dev, "vrfb create ctx failed\n");13871387+ return r;13881388+ }13891389+13901390+ vaddr = NULL;13911391+ }13921392+13931393+ rg->paddr = paddr;13941394+ rg->vaddr = vaddr;13951395+ rg->size = size;13961396+ rg->alloc = 1;13971397+13981398+ return 0;13991399+}14001400+14011401+/* allocate fbmem using display resolution as reference */14021402+static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size,14031403+ unsigned long paddr)14041404+{14051405+ struct omapfb_info *ofbi = FB2OFB(fbi);14061406+ struct omap_dss_device *display;14071407+ int bytespp;14081408+14091409+ display = fb2display(fbi);14101410+14111411+ if (!display)14121412+ return 0;14131413+14141414+ switch (display->get_recommended_bpp(display)) {14151415+ case 16:14161416+ bytespp = 2;14171417+ break;14181418+ case 24:14191419+ bytespp = 4;14201420+ break;14211421+ default:14221422+ bytespp = 4;14231423+ break;14241424+ }14251425+14261426+ if (!size) {14271427+ u16 w, h;14281428+14291429+ display->get_resolution(display, &w, &h);14301430+14311431+ if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) {14321432+ size = max(omap_vrfb_min_phys_size(w, h, bytespp),14331433+ omap_vrfb_min_phys_size(h, w, bytespp));14341434+14351435+ DBG("adjusting fb mem size for VRFB, %u -> %lu\n",14361436+ w * h * bytespp, size);14371437+ } else {14381438+ size = w * h * bytespp;14391439+ }14401440+ }14411441+14421442+ if (!size)14431443+ return 0;14441444+14451445+ return omapfb_alloc_fbmem(fbi, size, paddr);14461446+}14471447+14481448+static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt)14491449+{14501450+ enum omap_color_mode mode;14511451+14521452+ switch (fmt) {14531453+ case OMAPFB_COLOR_RGB565:14541454+ mode = OMAP_DSS_COLOR_RGB16;14551455+ break;14561456+ case OMAPFB_COLOR_YUV422:14571457+ mode = OMAP_DSS_COLOR_YUV2;14581458+ break;14591459+ case OMAPFB_COLOR_CLUT_8BPP:14601460+ mode = OMAP_DSS_COLOR_CLUT8;14611461+ break;14621462+ case OMAPFB_COLOR_CLUT_4BPP:14631463+ mode = OMAP_DSS_COLOR_CLUT4;14641464+ break;14651465+ case OMAPFB_COLOR_CLUT_2BPP:14661466+ mode = OMAP_DSS_COLOR_CLUT2;14671467+ break;14681468+ case OMAPFB_COLOR_CLUT_1BPP:14691469+ mode = OMAP_DSS_COLOR_CLUT1;14701470+ break;14711471+ case OMAPFB_COLOR_RGB444:14721472+ mode = OMAP_DSS_COLOR_RGB12U;14731473+ break;14741474+ case OMAPFB_COLOR_YUY422:14751475+ mode = OMAP_DSS_COLOR_UYVY;14761476+ break;14771477+ case OMAPFB_COLOR_ARGB16:14781478+ mode = OMAP_DSS_COLOR_ARGB16;14791479+ break;14801480+ case OMAPFB_COLOR_RGB24U:14811481+ mode = OMAP_DSS_COLOR_RGB24U;14821482+ break;14831483+ case OMAPFB_COLOR_RGB24P:14841484+ mode = OMAP_DSS_COLOR_RGB24P;14851485+ break;14861486+ case OMAPFB_COLOR_ARGB32:14871487+ mode = OMAP_DSS_COLOR_ARGB32;14881488+ break;14891489+ case OMAPFB_COLOR_RGBA32:14901490+ mode = OMAP_DSS_COLOR_RGBA32;14911491+ break;14921492+ case OMAPFB_COLOR_RGBX32:14931493+ mode = OMAP_DSS_COLOR_RGBX32;14941494+ break;14951495+ default:14961496+ mode = -EINVAL;14971497+ }14981498+14991499+ return mode;15001500+}15011501+15021502+static int omapfb_parse_vram_param(const char *param, int max_entries,15031503+ unsigned long *sizes, unsigned long *paddrs)15041504+{15051505+ int fbnum;15061506+ unsigned long size;15071507+ unsigned long paddr = 0;15081508+ char *p, *start;15091509+15101510+ start = (char *)param;15111511+15121512+ while (1) {15131513+ p = start;15141514+15151515+ fbnum = simple_strtoul(p, &p, 10);15161516+15171517+ if (p == param)15181518+ return -EINVAL;15191519+15201520+ if (*p != ':')15211521+ return -EINVAL;15221522+15231523+ if (fbnum >= max_entries)15241524+ return -EINVAL;15251525+15261526+ size = memparse(p + 1, &p);15271527+15281528+ if (!size)15291529+ return -EINVAL;15301530+15311531+ paddr = 0;15321532+15331533+ if (*p == '@') {15341534+ paddr = simple_strtoul(p + 1, &p, 16);15351535+15361536+ if (!paddr)15371537+ return -EINVAL;15381538+15391539+ }15401540+15411541+ paddrs[fbnum] = paddr;15421542+ sizes[fbnum] = size;15431543+15441544+ if (*p == 0)15451545+ break;15461546+15471547+ if (*p != ',')15481548+ return -EINVAL;15491549+15501550+ ++p;15511551+15521552+ start = p;15531553+ }15541554+15551555+ return 0;15561556+}15571557+15581558+static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev)15591559+{15601560+ int i, r;15611561+ unsigned long vram_sizes[10];15621562+ unsigned long vram_paddrs[10];15631563+15641564+ memset(&vram_sizes, 0, sizeof(vram_sizes));15651565+ memset(&vram_paddrs, 0, sizeof(vram_paddrs));15661566+15671567+ if (def_vram && omapfb_parse_vram_param(def_vram, 10,15681568+ vram_sizes, vram_paddrs)) {15691569+ dev_err(fbdev->dev, "failed to parse vram parameter\n");15701570+15711571+ memset(&vram_sizes, 0, sizeof(vram_sizes));15721572+ memset(&vram_paddrs, 0, sizeof(vram_paddrs));15731573+ }15741574+15751575+ if (fbdev->dev->platform_data) {15761576+ struct omapfb_platform_data *opd;15771577+ opd = fbdev->dev->platform_data;15781578+ for (i = 0; i < opd->mem_desc.region_cnt; ++i) {15791579+ if (!vram_sizes[i]) {15801580+ unsigned long size;15811581+ unsigned long paddr;15821582+15831583+ size = opd->mem_desc.region[i].size;15841584+ paddr = opd->mem_desc.region[i].paddr;15851585+15861586+ vram_sizes[i] = size;15871587+ vram_paddrs[i] = paddr;15881588+ }15891589+ }15901590+ }15911591+15921592+ for (i = 0; i < fbdev->num_fbs; i++) {15931593+ /* allocate memory automatically only for fb0, or if15941594+ * excplicitly defined with vram or plat data option */15951595+ if (i == 0 || vram_sizes[i] != 0) {15961596+ r = omapfb_alloc_fbmem_display(fbdev->fbs[i],15971597+ vram_sizes[i], vram_paddrs[i]);15981598+15991599+ if (r)16001600+ return r;16011601+ }16021602+ }16031603+16041604+ for (i = 0; i < fbdev->num_fbs; i++) {16051605+ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);16061606+ struct omapfb2_mem_region *rg;16071607+ rg = &ofbi->region;16081608+16091609+ DBG("region%d phys %08x virt %p size=%lu\n",16101610+ i,16111611+ rg->paddr,16121612+ rg->vaddr,16131613+ rg->size);16141614+ }16151615+16161616+ return 0;16171617+}16181618+16191619+int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type)16201620+{16211621+ struct omapfb_info *ofbi = FB2OFB(fbi);16221622+ struct omapfb2_device *fbdev = ofbi->fbdev;16231623+ struct omap_dss_device *display = fb2display(fbi);16241624+ struct omapfb2_mem_region *rg = &ofbi->region;16251625+ unsigned long old_size = rg->size;16261626+ unsigned long old_paddr = rg->paddr;16271627+ int old_type = rg->type;16281628+ int r;16291629+16301630+ if (type > OMAPFB_MEMTYPE_MAX)16311631+ return -EINVAL;16321632+16331633+ size = PAGE_ALIGN(size);16341634+16351635+ if (old_size == size && old_type == type)16361636+ return 0;16371637+16381638+ if (display && display->sync)16391639+ display->sync(display);16401640+16411641+ omapfb_free_fbmem(fbi);16421642+16431643+ if (size == 0) {16441644+ clear_fb_info(fbi);16451645+ return 0;16461646+ }16471647+16481648+ r = omapfb_alloc_fbmem(fbi, size, 0);16491649+16501650+ if (r) {16511651+ if (old_size)16521652+ omapfb_alloc_fbmem(fbi, old_size, old_paddr);16531653+16541654+ if (rg->size == 0)16551655+ clear_fb_info(fbi);16561656+16571657+ return r;16581658+ }16591659+16601660+ if (old_size == size)16611661+ return 0;16621662+16631663+ if (old_size == 0) {16641664+ DBG("initializing fb %d\n", ofbi->id);16651665+ r = omapfb_fb_init(fbdev, fbi);16661666+ if (r) {16671667+ DBG("omapfb_fb_init failed\n");16681668+ goto err;16691669+ }16701670+ r = omapfb_apply_changes(fbi, 1);16711671+ if (r) {16721672+ DBG("omapfb_apply_changes failed\n");16731673+ goto err;16741674+ }16751675+ } else {16761676+ struct fb_var_screeninfo new_var;16771677+ memcpy(&new_var, &fbi->var, sizeof(new_var));16781678+ r = check_fb_var(fbi, &new_var);16791679+ if (r)16801680+ goto err;16811681+ memcpy(&fbi->var, &new_var, sizeof(fbi->var));16821682+ set_fb_fix(fbi);16831683+ r = setup_vrfb_rotation(fbi);16841684+ if (r)16851685+ goto err;16861686+ }16871687+16881688+ return 0;16891689+err:16901690+ omapfb_free_fbmem(fbi);16911691+ clear_fb_info(fbi);16921692+ return r;16931693+}16941694+16951695+/* initialize fb_info, var, fix to something sane based on the display */16961696+static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)16971697+{16981698+ struct fb_var_screeninfo *var = &fbi->var;16991699+ struct omap_dss_device *display = fb2display(fbi);17001700+ struct omapfb_info *ofbi = FB2OFB(fbi);17011701+ int r = 0;17021702+17031703+ fbi->fbops = &omapfb_ops;17041704+ fbi->flags = FBINFO_FLAG_DEFAULT;17051705+ fbi->pseudo_palette = fbdev->pseudo_palette;17061706+17071707+ if (ofbi->region.size == 0) {17081708+ clear_fb_info(fbi);17091709+ return 0;17101710+ }17111711+17121712+ var->nonstd = 0;17131713+ var->bits_per_pixel = 0;17141714+17151715+ var->rotate = def_rotate;17161716+17171717+ /*17181718+ * Check if there is a default color format set in the board file,17191719+ * and use this format instead the default deducted from the17201720+ * display bpp.17211721+ */17221722+ if (fbdev->dev->platform_data) {17231723+ struct omapfb_platform_data *opd;17241724+ int id = ofbi->id;17251725+17261726+ opd = fbdev->dev->platform_data;17271727+ if (opd->mem_desc.region[id].format_used) {17281728+ enum omap_color_mode mode;17291729+ enum omapfb_color_format format;17301730+17311731+ format = opd->mem_desc.region[id].format;17321732+ mode = fb_format_to_dss_mode(format);17331733+ if (mode < 0) {17341734+ r = mode;17351735+ goto err;17361736+ }17371737+ r = dss_mode_to_fb_mode(mode, var);17381738+ if (r < 0)17391739+ goto err;17401740+ }17411741+ }17421742+17431743+ if (display) {17441744+ u16 w, h;17451745+ int rotation = (var->rotate + ofbi->rotation[0]) % 4;17461746+17471747+ display->get_resolution(display, &w, &h);17481748+17491749+ if (rotation == FB_ROTATE_CW ||17501750+ rotation == FB_ROTATE_CCW) {17511751+ var->xres = h;17521752+ var->yres = w;17531753+ } else {17541754+ var->xres = w;17551755+ var->yres = h;17561756+ }17571757+17581758+ var->xres_virtual = var->xres;17591759+ var->yres_virtual = var->yres;17601760+17611761+ if (!var->bits_per_pixel) {17621762+ switch (display->get_recommended_bpp(display)) {17631763+ case 16:17641764+ var->bits_per_pixel = 16;17651765+ break;17661766+ case 24:17671767+ var->bits_per_pixel = 32;17681768+ break;17691769+ default:17701770+ dev_err(fbdev->dev, "illegal display "17711771+ "bpp\n");17721772+ return -EINVAL;17731773+ }17741774+ }17751775+ } else {17761776+ /* if there's no display, let's just guess some basic values */17771777+ var->xres = 320;17781778+ var->yres = 240;17791779+ var->xres_virtual = var->xres;17801780+ var->yres_virtual = var->yres;17811781+ if (!var->bits_per_pixel)17821782+ var->bits_per_pixel = 16;17831783+ }17841784+17851785+ r = check_fb_var(fbi, var);17861786+ if (r)17871787+ goto err;17881788+17891789+ set_fb_fix(fbi);17901790+ r = setup_vrfb_rotation(fbi);17911791+ if (r)17921792+ goto err;17931793+17941794+ r = fb_alloc_cmap(&fbi->cmap, 256, 0);17951795+ if (r)17961796+ dev_err(fbdev->dev, "unable to allocate color map memory\n");17971797+17981798+err:17991799+ return r;18001800+}18011801+18021802+static void fbinfo_cleanup(struct omapfb2_device *fbdev, struct fb_info *fbi)18031803+{18041804+ fb_dealloc_cmap(&fbi->cmap);18051805+}18061806+18071807+18081808+static void omapfb_free_resources(struct omapfb2_device *fbdev)18091809+{18101810+ int i;18111811+18121812+ DBG("free_resources\n");18131813+18141814+ if (fbdev == NULL)18151815+ return;18161816+18171817+ for (i = 0; i < fbdev->num_fbs; i++)18181818+ unregister_framebuffer(fbdev->fbs[i]);18191819+18201820+ /* free the reserved fbmem */18211821+ omapfb_free_all_fbmem(fbdev);18221822+18231823+ for (i = 0; i < fbdev->num_fbs; i++) {18241824+ fbinfo_cleanup(fbdev, fbdev->fbs[i]);18251825+ framebuffer_release(fbdev->fbs[i]);18261826+ }18271827+18281828+ for (i = 0; i < fbdev->num_displays; i++) {18291829+ if (fbdev->displays[i]->state != OMAP_DSS_DISPLAY_DISABLED)18301830+ fbdev->displays[i]->disable(fbdev->displays[i]);18311831+18321832+ omap_dss_put_device(fbdev->displays[i]);18331833+ }18341834+18351835+ dev_set_drvdata(fbdev->dev, NULL);18361836+ kfree(fbdev);18371837+}18381838+18391839+static int omapfb_create_framebuffers(struct omapfb2_device *fbdev)18401840+{18411841+ int r, i;18421842+18431843+ fbdev->num_fbs = 0;18441844+18451845+ DBG("create %d framebuffers\n", CONFIG_FB_OMAP2_NUM_FBS);18461846+18471847+ /* allocate fb_infos */18481848+ for (i = 0; i < CONFIG_FB_OMAP2_NUM_FBS; i++) {18491849+ struct fb_info *fbi;18501850+ struct omapfb_info *ofbi;18511851+18521852+ fbi = framebuffer_alloc(sizeof(struct omapfb_info),18531853+ fbdev->dev);18541854+18551855+ if (fbi == NULL) {18561856+ dev_err(fbdev->dev,18571857+ "unable to allocate memory for plane info\n");18581858+ return -ENOMEM;18591859+ }18601860+18611861+ clear_fb_info(fbi);18621862+18631863+ fbdev->fbs[i] = fbi;18641864+18651865+ ofbi = FB2OFB(fbi);18661866+ ofbi->fbdev = fbdev;18671867+ ofbi->id = i;18681868+18691869+ /* assign these early, so that fb alloc can use them */18701870+ ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB :18711871+ OMAP_DSS_ROT_DMA;18721872+ ofbi->mirror = def_mirror;18731873+18741874+ fbdev->num_fbs++;18751875+ }18761876+18771877+ DBG("fb_infos allocated\n");18781878+18791879+ /* assign overlays for the fbs */18801880+ for (i = 0; i < min(fbdev->num_fbs, fbdev->num_overlays); i++) {18811881+ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);18821882+18831883+ ofbi->overlays[0] = fbdev->overlays[i];18841884+ ofbi->num_overlays = 1;18851885+ }18861886+18871887+ /* allocate fb memories */18881888+ r = omapfb_allocate_all_fbs(fbdev);18891889+ if (r) {18901890+ dev_err(fbdev->dev, "failed to allocate fbmem\n");18911891+ return r;18921892+ }18931893+18941894+ DBG("fbmems allocated\n");18951895+18961896+ /* setup fb_infos */18971897+ for (i = 0; i < fbdev->num_fbs; i++) {18981898+ r = omapfb_fb_init(fbdev, fbdev->fbs[i]);18991899+ if (r) {19001900+ dev_err(fbdev->dev, "failed to setup fb_info\n");19011901+ return r;19021902+ }19031903+ }19041904+19051905+ DBG("fb_infos initialized\n");19061906+19071907+ for (i = 0; i < fbdev->num_fbs; i++) {19081908+ r = register_framebuffer(fbdev->fbs[i]);19091909+ if (r != 0) {19101910+ dev_err(fbdev->dev,19111911+ "registering framebuffer %d failed\n", i);19121912+ return r;19131913+ }19141914+ }19151915+19161916+ DBG("framebuffers registered\n");19171917+19181918+ for (i = 0; i < fbdev->num_fbs; i++) {19191919+ r = omapfb_apply_changes(fbdev->fbs[i], 1);19201920+ if (r) {19211921+ dev_err(fbdev->dev, "failed to change mode\n");19221922+ return r;19231923+ }19241924+ }19251925+19261926+ DBG("create sysfs for fbs\n");19271927+ r = omapfb_create_sysfs(fbdev);19281928+ if (r) {19291929+ dev_err(fbdev->dev, "failed to create sysfs entries\n");19301930+ return r;19311931+ }19321932+19331933+ /* Enable fb0 */19341934+ if (fbdev->num_fbs > 0) {19351935+ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]);19361936+19371937+ if (ofbi->num_overlays > 0) {19381938+ struct omap_overlay *ovl = ofbi->overlays[0];19391939+19401940+ r = omapfb_overlay_enable(ovl, 1);19411941+19421942+ if (r) {19431943+ dev_err(fbdev->dev,19441944+ "failed to enable overlay\n");19451945+ return r;19461946+ }19471947+ }19481948+ }19491949+19501950+ DBG("create_framebuffers done\n");19511951+19521952+ return 0;19531953+}19541954+19551955+static int omapfb_mode_to_timings(const char *mode_str,19561956+ struct omap_video_timings *timings, u8 *bpp)19571957+{19581958+ struct fb_info fbi;19591959+ struct fb_var_screeninfo var;19601960+ struct fb_ops fbops;19611961+ int r;19621962+19631963+#ifdef CONFIG_OMAP2_DSS_VENC19641964+ if (strcmp(mode_str, "pal") == 0) {19651965+ *timings = omap_dss_pal_timings;19661966+ *bpp = 0;19671967+ return 0;19681968+ } else if (strcmp(mode_str, "ntsc") == 0) {19691969+ *timings = omap_dss_ntsc_timings;19701970+ *bpp = 0;19711971+ return 0;19721972+ }19731973+#endif19741974+19751975+ /* this is quite a hack, but I wanted to use the modedb and for19761976+ * that we need fb_info and var, so we create dummy ones */19771977+19781978+ memset(&fbi, 0, sizeof(fbi));19791979+ memset(&var, 0, sizeof(var));19801980+ memset(&fbops, 0, sizeof(fbops));19811981+ fbi.fbops = &fbops;19821982+19831983+ r = fb_find_mode(&var, &fbi, mode_str, NULL, 0, NULL, 24);19841984+19851985+ if (r != 0) {19861986+ timings->pixel_clock = PICOS2KHZ(var.pixclock);19871987+ timings->hfp = var.left_margin;19881988+ timings->hbp = var.right_margin;19891989+ timings->vfp = var.upper_margin;19901990+ timings->vbp = var.lower_margin;19911991+ timings->hsw = var.hsync_len;19921992+ timings->vsw = var.vsync_len;19931993+ timings->x_res = var.xres;19941994+ timings->y_res = var.yres;19951995+19961996+ switch (var.bits_per_pixel) {19971997+ case 16:19981998+ *bpp = 16;19991999+ break;20002000+ case 24:20012001+ case 32:20022002+ default:20032003+ *bpp = 24;20042004+ break;20052005+ }20062006+20072007+ return 0;20082008+ } else {20092009+ return -EINVAL;20102010+ }20112011+}20122012+20132013+static int omapfb_set_def_mode(struct omap_dss_device *display, char *mode_str)20142014+{20152015+ int r;20162016+ u8 bpp;20172017+ struct omap_video_timings timings;20182018+20192019+ r = omapfb_mode_to_timings(mode_str, &timings, &bpp);20202020+ if (r)20212021+ return r;20222022+20232023+ display->panel.recommended_bpp = bpp;20242024+20252025+ if (!display->check_timings || !display->set_timings)20262026+ return -EINVAL;20272027+20282028+ r = display->check_timings(display, &timings);20292029+ if (r)20302030+ return r;20312031+20322032+ display->set_timings(display, &timings);20332033+20342034+ return 0;20352035+}20362036+20372037+static int omapfb_parse_def_modes(struct omapfb2_device *fbdev)20382038+{20392039+ char *str, *options, *this_opt;20402040+ int r = 0;20412041+20422042+ str = kmalloc(strlen(def_mode) + 1, GFP_KERNEL);20432043+ strcpy(str, def_mode);20442044+ options = str;20452045+20462046+ while (!r && (this_opt = strsep(&options, ",")) != NULL) {20472047+ char *p, *display_str, *mode_str;20482048+ struct omap_dss_device *display;20492049+ int i;20502050+20512051+ p = strchr(this_opt, ':');20522052+ if (!p) {20532053+ r = -EINVAL;20542054+ break;20552055+ }20562056+20572057+ *p = 0;20582058+ display_str = this_opt;20592059+ mode_str = p + 1;20602060+20612061+ display = NULL;20622062+ for (i = 0; i < fbdev->num_displays; ++i) {20632063+ if (strcmp(fbdev->displays[i]->name,20642064+ display_str) == 0) {20652065+ display = fbdev->displays[i];20662066+ break;20672067+ }20682068+ }20692069+20702070+ if (!display) {20712071+ r = -EINVAL;20722072+ break;20732073+ }20742074+20752075+ r = omapfb_set_def_mode(display, mode_str);20762076+ if (r)20772077+ break;20782078+ }20792079+20802080+ kfree(str);20812081+20822082+ return r;20832083+}20842084+20852085+static int omapfb_probe(struct platform_device *pdev)20862086+{20872087+ struct omapfb2_device *fbdev = NULL;20882088+ int r = 0;20892089+ int i;20902090+ struct omap_overlay *ovl;20912091+ struct omap_dss_device *def_display;20922092+ struct omap_dss_device *dssdev;20932093+20942094+ DBG("omapfb_probe\n");20952095+20962096+ if (pdev->num_resources != 0) {20972097+ dev_err(&pdev->dev, "probed for an unknown device\n");20982098+ r = -ENODEV;20992099+ goto err0;21002100+ }21012101+21022102+ fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL);21032103+ if (fbdev == NULL) {21042104+ r = -ENOMEM;21052105+ goto err0;21062106+ }21072107+21082108+ mutex_init(&fbdev->mtx);21092109+21102110+ fbdev->dev = &pdev->dev;21112111+ platform_set_drvdata(pdev, fbdev);21122112+21132113+ fbdev->num_displays = 0;21142114+ dssdev = NULL;21152115+ for_each_dss_dev(dssdev) {21162116+ omap_dss_get_device(dssdev);21172117+ fbdev->displays[fbdev->num_displays++] = dssdev;21182118+ }21192119+21202120+ if (fbdev->num_displays == 0) {21212121+ dev_err(&pdev->dev, "no displays\n");21222122+ r = -EINVAL;21232123+ goto cleanup;21242124+ }21252125+21262126+ fbdev->num_overlays = omap_dss_get_num_overlays();21272127+ for (i = 0; i < fbdev->num_overlays; i++)21282128+ fbdev->overlays[i] = omap_dss_get_overlay(i);21292129+21302130+ fbdev->num_managers = omap_dss_get_num_overlay_managers();21312131+ for (i = 0; i < fbdev->num_managers; i++)21322132+ fbdev->managers[i] = omap_dss_get_overlay_manager(i);21332133+21342134+ if (def_mode && strlen(def_mode) > 0) {21352135+ if (omapfb_parse_def_modes(fbdev))21362136+ dev_warn(&pdev->dev, "cannot parse default modes\n");21372137+ }21382138+21392139+ r = omapfb_create_framebuffers(fbdev);21402140+ if (r)21412141+ goto cleanup;21422142+21432143+ for (i = 0; i < fbdev->num_managers; i++) {21442144+ struct omap_overlay_manager *mgr;21452145+ mgr = fbdev->managers[i];21462146+ r = mgr->apply(mgr);21472147+ if (r)21482148+ dev_warn(fbdev->dev, "failed to apply dispc config\n");21492149+ }21502150+21512151+ DBG("mgr->apply'ed\n");21522152+21532153+ /* gfx overlay should be the default one. find a display21542154+ * connected to that, and use it as default display */21552155+ ovl = omap_dss_get_overlay(0);21562156+ if (ovl->manager && ovl->manager->device) {21572157+ def_display = ovl->manager->device;21582158+ } else {21592159+ dev_warn(&pdev->dev, "cannot find default display\n");21602160+ def_display = NULL;21612161+ }21622162+21632163+ if (def_display) {21642164+#ifndef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE21652165+ u16 w, h;21662166+#endif21672167+ r = def_display->enable(def_display);21682168+ if (r)21692169+ dev_warn(fbdev->dev, "Failed to enable display '%s'\n",21702170+ def_display->name);21712171+21722172+ /* set the update mode */21732173+ if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {21742174+#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE21752175+ if (def_display->enable_te)21762176+ def_display->enable_te(def_display, 1);21772177+ if (def_display->set_update_mode)21782178+ def_display->set_update_mode(def_display,21792179+ OMAP_DSS_UPDATE_AUTO);21802180+#else /* MANUAL_UPDATE */21812181+ if (def_display->enable_te)21822182+ def_display->enable_te(def_display, 0);21832183+ if (def_display->set_update_mode)21842184+ def_display->set_update_mode(def_display,21852185+ OMAP_DSS_UPDATE_MANUAL);21862186+21872187+ def_display->get_resolution(def_display, &w, &h);21882188+ def_display->update(def_display, 0, 0, w, h);21892189+#endif21902190+ } else {21912191+ if (def_display->set_update_mode)21922192+ def_display->set_update_mode(def_display,21932193+ OMAP_DSS_UPDATE_AUTO);21942194+ }21952195+ }21962196+21972197+ return 0;21982198+21992199+cleanup:22002200+ omapfb_free_resources(fbdev);22012201+err0:22022202+ dev_err(&pdev->dev, "failed to setup omapfb\n");22032203+ return r;22042204+}22052205+22062206+static int omapfb_remove(struct platform_device *pdev)22072207+{22082208+ struct omapfb2_device *fbdev = platform_get_drvdata(pdev);22092209+22102210+ /* FIXME: wait till completion of pending events */22112211+22122212+ omapfb_remove_sysfs(fbdev);22132213+22142214+ omapfb_free_resources(fbdev);22152215+22162216+ return 0;22172217+}22182218+22192219+static struct platform_driver omapfb_driver = {22202220+ .probe = omapfb_probe,22212221+ .remove = omapfb_remove,22222222+ .driver = {22232223+ .name = "omapfb",22242224+ .owner = THIS_MODULE,22252225+ },22262226+};22272227+22282228+static int __init omapfb_init(void)22292229+{22302230+ DBG("omapfb_init\n");22312231+22322232+ if (platform_driver_register(&omapfb_driver)) {22332233+ printk(KERN_ERR "failed to register omapfb driver\n");22342234+ return -ENODEV;22352235+ }22362236+22372237+ return 0;22382238+}22392239+22402240+static void __exit omapfb_exit(void)22412241+{22422242+ DBG("omapfb_exit\n");22432243+ platform_driver_unregister(&omapfb_driver);22442244+}22452245+22462246+module_param_named(mode, def_mode, charp, 0);22472247+module_param_named(vram, def_vram, charp, 0);22482248+module_param_named(rotate, def_rotate, int, 0);22492249+module_param_named(vrfb, def_vrfb, bool, 0);22502250+module_param_named(mirror, def_mirror, bool, 0);22512251+22522252+/* late_initcall to let panel/ctrl drivers loaded first.22532253+ * I guess better option would be a more dynamic approach,22542254+ * so that omapfb reacts to new panels when they are loaded */22552255+late_initcall(omapfb_init);22562256+/*module_init(omapfb_init);*/22572257+module_exit(omapfb_exit);22582258+22592259+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@nokia.com>");22602260+MODULE_DESCRIPTION("OMAP2/3 Framebuffer");22612261+MODULE_LICENSE("GPL v2");
+507
drivers/video/omap2/omapfb/omapfb-sysfs.c
···11+/*22+ * linux/drivers/video/omap2/omapfb-sysfs.c33+ *44+ * Copyright (C) 2008 Nokia Corporation55+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>66+ *77+ * Some code and ideas taken from drivers/video/omap/ driver88+ * by Imre Deak.99+ *1010+ * This program is free software; you can redistribute it and/or modify it1111+ * under the terms of the GNU General Public License version 2 as published by1212+ * the Free Software Foundation.1313+ *1414+ * This program is distributed in the hope that it will be useful, but WITHOUT1515+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1616+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1717+ * more details.1818+ *1919+ * You should have received a copy of the GNU General Public License along with2020+ * this program. If not, see <http://www.gnu.org/licenses/>.2121+ */2222+2323+#include <linux/fb.h>2424+#include <linux/sysfs.h>2525+#include <linux/device.h>2626+#include <linux/uaccess.h>2727+#include <linux/platform_device.h>2828+#include <linux/kernel.h>2929+#include <linux/mm.h>3030+#include <linux/omapfb.h>3131+3232+#include <plat/display.h>3333+#include <plat/vrfb.h>3434+3535+#include "omapfb.h"3636+3737+static ssize_t show_rotate_type(struct device *dev,3838+ struct device_attribute *attr, char *buf)3939+{4040+ struct fb_info *fbi = dev_get_drvdata(dev);4141+ struct omapfb_info *ofbi = FB2OFB(fbi);4242+4343+ return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->rotation_type);4444+}4545+4646+static ssize_t store_rotate_type(struct device *dev,4747+ struct device_attribute *attr,4848+ const char *buf, size_t count)4949+{5050+ struct fb_info *fbi = dev_get_drvdata(dev);5151+ struct omapfb_info *ofbi = FB2OFB(fbi);5252+ enum omap_dss_rotation_type rot_type;5353+ int r;5454+5555+ rot_type = simple_strtoul(buf, NULL, 0);5656+5757+ if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)5858+ return -EINVAL;5959+6060+ lock_fb_info(fbi);6161+6262+ r = 0;6363+ if (rot_type == ofbi->rotation_type)6464+ goto out;6565+6666+ if (ofbi->region.size) {6767+ r = -EBUSY;6868+ goto out;6969+ }7070+7171+ ofbi->rotation_type = rot_type;7272+7373+ /*7474+ * Since the VRAM for this FB is not allocated at the moment we don't7575+ * need to do any further parameter checking at this point.7676+ */7777+out:7878+ unlock_fb_info(fbi);7979+8080+ return r ? r : count;8181+}8282+8383+8484+static ssize_t show_mirror(struct device *dev,8585+ struct device_attribute *attr, char *buf)8686+{8787+ struct fb_info *fbi = dev_get_drvdata(dev);8888+ struct omapfb_info *ofbi = FB2OFB(fbi);8989+9090+ return snprintf(buf, PAGE_SIZE, "%d\n", ofbi->mirror);9191+}9292+9393+static ssize_t store_mirror(struct device *dev,9494+ struct device_attribute *attr,9595+ const char *buf, size_t count)9696+{9797+ struct fb_info *fbi = dev_get_drvdata(dev);9898+ struct omapfb_info *ofbi = FB2OFB(fbi);9999+ bool mirror;100100+ int r;101101+ struct fb_var_screeninfo new_var;102102+103103+ mirror = simple_strtoul(buf, NULL, 0);104104+105105+ if (mirror != 0 && mirror != 1)106106+ return -EINVAL;107107+108108+ lock_fb_info(fbi);109109+110110+ ofbi->mirror = mirror;111111+112112+ memcpy(&new_var, &fbi->var, sizeof(new_var));113113+ r = check_fb_var(fbi, &new_var);114114+ if (r)115115+ goto out;116116+ memcpy(&fbi->var, &new_var, sizeof(fbi->var));117117+118118+ set_fb_fix(fbi);119119+120120+ r = omapfb_apply_changes(fbi, 0);121121+ if (r)122122+ goto out;123123+124124+ r = count;125125+out:126126+ unlock_fb_info(fbi);127127+128128+ return r;129129+}130130+131131+static ssize_t show_overlays(struct device *dev,132132+ struct device_attribute *attr, char *buf)133133+{134134+ struct fb_info *fbi = dev_get_drvdata(dev);135135+ struct omapfb_info *ofbi = FB2OFB(fbi);136136+ struct omapfb2_device *fbdev = ofbi->fbdev;137137+ ssize_t l = 0;138138+ int t;139139+140140+ omapfb_lock(fbdev);141141+ lock_fb_info(fbi);142142+143143+ for (t = 0; t < ofbi->num_overlays; t++) {144144+ struct omap_overlay *ovl = ofbi->overlays[t];145145+ int ovlnum;146146+147147+ for (ovlnum = 0; ovlnum < fbdev->num_overlays; ++ovlnum)148148+ if (ovl == fbdev->overlays[ovlnum])149149+ break;150150+151151+ l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",152152+ t == 0 ? "" : ",", ovlnum);153153+ }154154+155155+ l += snprintf(buf + l, PAGE_SIZE - l, "\n");156156+157157+ unlock_fb_info(fbi);158158+ omapfb_unlock(fbdev);159159+160160+ return l;161161+}162162+163163+static struct omapfb_info *get_overlay_fb(struct omapfb2_device *fbdev,164164+ struct omap_overlay *ovl)165165+{166166+ int i, t;167167+168168+ for (i = 0; i < fbdev->num_fbs; i++) {169169+ struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]);170170+171171+ for (t = 0; t < ofbi->num_overlays; t++) {172172+ if (ofbi->overlays[t] == ovl)173173+ return ofbi;174174+ }175175+ }176176+177177+ return NULL;178178+}179179+180180+static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,181181+ const char *buf, size_t count)182182+{183183+ struct fb_info *fbi = dev_get_drvdata(dev);184184+ struct omapfb_info *ofbi = FB2OFB(fbi);185185+ struct omapfb2_device *fbdev = ofbi->fbdev;186186+ struct omap_overlay *ovls[OMAPFB_MAX_OVL_PER_FB];187187+ struct omap_overlay *ovl;188188+ int num_ovls, r, i;189189+ int len;190190+ bool added = false;191191+192192+ num_ovls = 0;193193+194194+ len = strlen(buf);195195+ if (buf[len - 1] == '\n')196196+ len = len - 1;197197+198198+ omapfb_lock(fbdev);199199+ lock_fb_info(fbi);200200+201201+ if (len > 0) {202202+ char *p = (char *)buf;203203+ int ovlnum;204204+205205+ while (p < buf + len) {206206+ int found;207207+ if (num_ovls == OMAPFB_MAX_OVL_PER_FB) {208208+ r = -EINVAL;209209+ goto out;210210+ }211211+212212+ ovlnum = simple_strtoul(p, &p, 0);213213+ if (ovlnum > fbdev->num_overlays) {214214+ r = -EINVAL;215215+ goto out;216216+ }217217+218218+ found = 0;219219+ for (i = 0; i < num_ovls; ++i) {220220+ if (ovls[i] == fbdev->overlays[ovlnum]) {221221+ found = 1;222222+ break;223223+ }224224+ }225225+226226+ if (!found)227227+ ovls[num_ovls++] = fbdev->overlays[ovlnum];228228+229229+ p++;230230+ }231231+ }232232+233233+ for (i = 0; i < num_ovls; ++i) {234234+ struct omapfb_info *ofbi2 = get_overlay_fb(fbdev, ovls[i]);235235+ if (ofbi2 && ofbi2 != ofbi) {236236+ dev_err(fbdev->dev, "overlay already in use\n");237237+ r = -EINVAL;238238+ goto out;239239+ }240240+ }241241+242242+ /* detach unused overlays */243243+ for (i = 0; i < ofbi->num_overlays; ++i) {244244+ int t, found;245245+246246+ ovl = ofbi->overlays[i];247247+248248+ found = 0;249249+250250+ for (t = 0; t < num_ovls; ++t) {251251+ if (ovl == ovls[t]) {252252+ found = 1;253253+ break;254254+ }255255+ }256256+257257+ if (found)258258+ continue;259259+260260+ DBG("detaching %d\n", ofbi->overlays[i]->id);261261+262262+ omapfb_overlay_enable(ovl, 0);263263+264264+ if (ovl->manager)265265+ ovl->manager->apply(ovl->manager);266266+267267+ for (t = i + 1; t < ofbi->num_overlays; t++) {268268+ ofbi->rotation[t-1] = ofbi->rotation[t];269269+ ofbi->overlays[t-1] = ofbi->overlays[t];270270+ }271271+272272+ ofbi->num_overlays--;273273+ i--;274274+ }275275+276276+ for (i = 0; i < num_ovls; ++i) {277277+ int t, found;278278+279279+ ovl = ovls[i];280280+281281+ found = 0;282282+283283+ for (t = 0; t < ofbi->num_overlays; ++t) {284284+ if (ovl == ofbi->overlays[t]) {285285+ found = 1;286286+ break;287287+ }288288+ }289289+290290+ if (found)291291+ continue;292292+ ofbi->rotation[ofbi->num_overlays] = 0;293293+ ofbi->overlays[ofbi->num_overlays++] = ovl;294294+295295+ added = true;296296+ }297297+298298+ if (added) {299299+ r = omapfb_apply_changes(fbi, 0);300300+ if (r)301301+ goto out;302302+ }303303+304304+ r = count;305305+out:306306+ unlock_fb_info(fbi);307307+ omapfb_unlock(fbdev);308308+309309+ return r;310310+}311311+312312+static ssize_t show_overlays_rotate(struct device *dev,313313+ struct device_attribute *attr, char *buf)314314+{315315+ struct fb_info *fbi = dev_get_drvdata(dev);316316+ struct omapfb_info *ofbi = FB2OFB(fbi);317317+ ssize_t l = 0;318318+ int t;319319+320320+ lock_fb_info(fbi);321321+322322+ for (t = 0; t < ofbi->num_overlays; t++) {323323+ l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",324324+ t == 0 ? "" : ",", ofbi->rotation[t]);325325+ }326326+327327+ l += snprintf(buf + l, PAGE_SIZE - l, "\n");328328+329329+ unlock_fb_info(fbi);330330+331331+ return l;332332+}333333+334334+static ssize_t store_overlays_rotate(struct device *dev,335335+ struct device_attribute *attr, const char *buf, size_t count)336336+{337337+ struct fb_info *fbi = dev_get_drvdata(dev);338338+ struct omapfb_info *ofbi = FB2OFB(fbi);339339+ int num_ovls = 0, r, i;340340+ int len;341341+ bool changed = false;342342+ u8 rotation[OMAPFB_MAX_OVL_PER_FB];343343+344344+ len = strlen(buf);345345+ if (buf[len - 1] == '\n')346346+ len = len - 1;347347+348348+ lock_fb_info(fbi);349349+350350+ if (len > 0) {351351+ char *p = (char *)buf;352352+353353+ while (p < buf + len) {354354+ int rot;355355+356356+ if (num_ovls == ofbi->num_overlays) {357357+ r = -EINVAL;358358+ goto out;359359+ }360360+361361+ rot = simple_strtoul(p, &p, 0);362362+ if (rot < 0 || rot > 3) {363363+ r = -EINVAL;364364+ goto out;365365+ }366366+367367+ if (ofbi->rotation[num_ovls] != rot)368368+ changed = true;369369+370370+ rotation[num_ovls++] = rot;371371+372372+ p++;373373+ }374374+ }375375+376376+ if (num_ovls != ofbi->num_overlays) {377377+ r = -EINVAL;378378+ goto out;379379+ }380380+381381+ if (changed) {382382+ for (i = 0; i < num_ovls; ++i)383383+ ofbi->rotation[i] = rotation[i];384384+385385+ r = omapfb_apply_changes(fbi, 0);386386+ if (r)387387+ goto out;388388+389389+ /* FIXME error handling? */390390+ }391391+392392+ r = count;393393+out:394394+ unlock_fb_info(fbi);395395+396396+ return r;397397+}398398+399399+static ssize_t show_size(struct device *dev,400400+ struct device_attribute *attr, char *buf)401401+{402402+ struct fb_info *fbi = dev_get_drvdata(dev);403403+ struct omapfb_info *ofbi = FB2OFB(fbi);404404+405405+ return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size);406406+}407407+408408+static ssize_t store_size(struct device *dev, struct device_attribute *attr,409409+ const char *buf, size_t count)410410+{411411+ struct fb_info *fbi = dev_get_drvdata(dev);412412+ struct omapfb_info *ofbi = FB2OFB(fbi);413413+ unsigned long size;414414+ int r;415415+ int i;416416+417417+ size = PAGE_ALIGN(simple_strtoul(buf, NULL, 0));418418+419419+ lock_fb_info(fbi);420420+421421+ for (i = 0; i < ofbi->num_overlays; i++) {422422+ if (ofbi->overlays[i]->info.enabled) {423423+ r = -EBUSY;424424+ goto out;425425+ }426426+ }427427+428428+ if (size != ofbi->region.size) {429429+ r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type);430430+ if (r) {431431+ dev_err(dev, "realloc fbmem failed\n");432432+ goto out;433433+ }434434+ }435435+436436+ r = count;437437+out:438438+ unlock_fb_info(fbi);439439+440440+ return r;441441+}442442+443443+static ssize_t show_phys(struct device *dev,444444+ struct device_attribute *attr, char *buf)445445+{446446+ struct fb_info *fbi = dev_get_drvdata(dev);447447+ struct omapfb_info *ofbi = FB2OFB(fbi);448448+449449+ return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr);450450+}451451+452452+static ssize_t show_virt(struct device *dev,453453+ struct device_attribute *attr, char *buf)454454+{455455+ struct fb_info *fbi = dev_get_drvdata(dev);456456+ struct omapfb_info *ofbi = FB2OFB(fbi);457457+458458+ return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr);459459+}460460+461461+static struct device_attribute omapfb_attrs[] = {462462+ __ATTR(rotate_type, S_IRUGO | S_IWUSR, show_rotate_type,463463+ store_rotate_type),464464+ __ATTR(mirror, S_IRUGO | S_IWUSR, show_mirror, store_mirror),465465+ __ATTR(size, S_IRUGO | S_IWUSR, show_size, store_size),466466+ __ATTR(overlays, S_IRUGO | S_IWUSR, show_overlays, store_overlays),467467+ __ATTR(overlays_rotate, S_IRUGO | S_IWUSR, show_overlays_rotate,468468+ store_overlays_rotate),469469+ __ATTR(phys_addr, S_IRUGO, show_phys, NULL),470470+ __ATTR(virt_addr, S_IRUGO, show_virt, NULL),471471+};472472+473473+int omapfb_create_sysfs(struct omapfb2_device *fbdev)474474+{475475+ int i;476476+ int r;477477+478478+ DBG("create sysfs for fbs\n");479479+ for (i = 0; i < fbdev->num_fbs; i++) {480480+ int t;481481+ for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++) {482482+ r = device_create_file(fbdev->fbs[i]->dev,483483+ &omapfb_attrs[t]);484484+485485+ if (r) {486486+ dev_err(fbdev->dev, "failed to create sysfs "487487+ "file\n");488488+ return r;489489+ }490490+ }491491+ }492492+493493+ return 0;494494+}495495+496496+void omapfb_remove_sysfs(struct omapfb2_device *fbdev)497497+{498498+ int i, t;499499+500500+ DBG("remove sysfs for fbs\n");501501+ for (i = 0; i < fbdev->num_fbs; i++) {502502+ for (t = 0; t < ARRAY_SIZE(omapfb_attrs); t++)503503+ device_remove_file(fbdev->fbs[i]->dev,504504+ &omapfb_attrs[t]);505505+ }506506+}507507+
+146
drivers/video/omap2/omapfb/omapfb.h
···11+/*22+ * linux/drivers/video/omap2/omapfb.h33+ *44+ * Copyright (C) 2008 Nokia Corporation55+ * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>66+ *77+ * Some code and ideas taken from drivers/video/omap/ driver88+ * by Imre Deak.99+ *1010+ * This program is free software; you can redistribute it and/or modify it1111+ * under the terms of the GNU General Public License version 2 as published by1212+ * the Free Software Foundation.1313+ *1414+ * This program is distributed in the hope that it will be useful, but WITHOUT1515+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1616+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1717+ * more details.1818+ *1919+ * You should have received a copy of the GNU General Public License along with2020+ * this program. If not, see <http://www.gnu.org/licenses/>.2121+ */2222+2323+#ifndef __DRIVERS_VIDEO_OMAP2_OMAPFB_H__2424+#define __DRIVERS_VIDEO_OMAP2_OMAPFB_H__2525+2626+#ifdef CONFIG_FB_OMAP2_DEBUG_SUPPORT2727+#define DEBUG2828+#endif2929+3030+#include <plat/display.h>3131+3232+#ifdef DEBUG3333+extern unsigned int omapfb_debug;3434+#define DBG(format, ...) \3535+ if (omapfb_debug) \3636+ printk(KERN_DEBUG "OMAPFB: " format, ## __VA_ARGS__)3737+#else3838+#define DBG(format, ...)3939+#endif4040+4141+#define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))4242+4343+/* max number of overlays to which a framebuffer data can be direct */4444+#define OMAPFB_MAX_OVL_PER_FB 34545+4646+struct omapfb2_mem_region {4747+ u32 paddr;4848+ void __iomem *vaddr;4949+ struct vrfb vrfb;5050+ unsigned long size;5151+ u8 type; /* OMAPFB_PLANE_MEM_* */5252+ bool alloc; /* allocated by the driver */5353+ bool map; /* kernel mapped by the driver */5454+};5555+5656+/* appended to fb_info */5757+struct omapfb_info {5858+ int id;5959+ struct omapfb2_mem_region region;6060+ atomic_t map_count;6161+ int num_overlays;6262+ struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB];6363+ struct omapfb2_device *fbdev;6464+ enum omap_dss_rotation_type rotation_type;6565+ u8 rotation[OMAPFB_MAX_OVL_PER_FB];6666+ bool mirror;6767+};6868+6969+struct omapfb2_device {7070+ struct device *dev;7171+ struct mutex mtx;7272+7373+ u32 pseudo_palette[17];7474+7575+ int state;7676+7777+ unsigned num_fbs;7878+ struct fb_info *fbs[10];7979+8080+ unsigned num_displays;8181+ struct omap_dss_device *displays[10];8282+ unsigned num_overlays;8383+ struct omap_overlay *overlays[10];8484+ unsigned num_managers;8585+ struct omap_overlay_manager *managers[10];8686+};8787+8888+struct omapfb_colormode {8989+ enum omap_color_mode dssmode;9090+ u32 bits_per_pixel;9191+ u32 nonstd;9292+ struct fb_bitfield red;9393+ struct fb_bitfield green;9494+ struct fb_bitfield blue;9595+ struct fb_bitfield transp;9696+};9797+9898+void set_fb_fix(struct fb_info *fbi);9999+int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var);100100+int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type);101101+int omapfb_apply_changes(struct fb_info *fbi, int init);102102+103103+int omapfb_create_sysfs(struct omapfb2_device *fbdev);104104+void omapfb_remove_sysfs(struct omapfb2_device *fbdev);105105+106106+int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg);107107+108108+int dss_mode_to_fb_mode(enum omap_color_mode dssmode,109109+ struct fb_var_screeninfo *var);110110+111111+/* find the display connected to this fb, if any */112112+static inline struct omap_dss_device *fb2display(struct fb_info *fbi)113113+{114114+ struct omapfb_info *ofbi = FB2OFB(fbi);115115+ int i;116116+117117+ /* XXX: returns the display connected to first attached overlay */118118+ for (i = 0; i < ofbi->num_overlays; i++) {119119+ if (ofbi->overlays[i]->manager)120120+ return ofbi->overlays[i]->manager->device;121121+ }122122+123123+ return NULL;124124+}125125+126126+static inline void omapfb_lock(struct omapfb2_device *fbdev)127127+{128128+ mutex_lock(&fbdev->mtx);129129+}130130+131131+static inline void omapfb_unlock(struct omapfb2_device *fbdev)132132+{133133+ mutex_unlock(&fbdev->mtx);134134+}135135+136136+static inline int omapfb_overlay_enable(struct omap_overlay *ovl,137137+ int enable)138138+{139139+ struct omap_overlay_info info;140140+141141+ ovl->get_overlay_info(ovl, &info);142142+ info.enabled = enable;143143+ return ovl->set_overlay_info(ovl, &info);144144+}145145+146146+#endif