162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Framebuffer driver for TI OMAP boards 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004 Nokia Corporation 662306a36Sopenharmony_ci * Author: Imre Deak <imre.deak@nokia.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Acknowledgements: 962306a36Sopenharmony_ci * Alex McMains <aam@ridgerun.com> - Original driver 1062306a36Sopenharmony_ci * Juha Yrjola <juha.yrjola@nokia.com> - Original driver and improvements 1162306a36Sopenharmony_ci * Dirk Behme <dirk.behme@de.bosch.com> - changes for 2.6 kernel API 1262306a36Sopenharmony_ci * Texas Instruments - H3 support 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/mm.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/uaccess.h> 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/sysfs.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/omap-dma.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/soc/ti/omap1-soc.h> 2462306a36Sopenharmony_ci#include "omapfb.h" 2562306a36Sopenharmony_ci#include "lcdc.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define MODULE_NAME "omapfb" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic unsigned int def_accel; 3062306a36Sopenharmony_cistatic unsigned long def_vram[OMAPFB_PLANE_NUM]; 3162306a36Sopenharmony_cistatic unsigned int def_vram_cnt; 3262306a36Sopenharmony_cistatic unsigned long def_vxres; 3362306a36Sopenharmony_cistatic unsigned long def_vyres; 3462306a36Sopenharmony_cistatic unsigned int def_rotate; 3562306a36Sopenharmony_cistatic unsigned int def_mirror; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic bool manual_update = IS_BUILTIN(CONFIG_FB_OMAP_MANUAL_UPDATE); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic struct platform_device *fbdev_pdev; 4062306a36Sopenharmony_cistatic struct lcd_panel *fbdev_panel; 4162306a36Sopenharmony_cistatic struct omapfb_device *omapfb_dev; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct caps_table_struct { 4462306a36Sopenharmony_ci unsigned long flag; 4562306a36Sopenharmony_ci const char *name; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic const struct caps_table_struct ctrl_caps[] = { 4962306a36Sopenharmony_ci { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" }, 5062306a36Sopenharmony_ci { OMAPFB_CAPS_TEARSYNC, "tearing synchronization" }, 5162306a36Sopenharmony_ci { OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" }, 5262306a36Sopenharmony_ci { OMAPFB_CAPS_PLANE_SCALE, "scale plane" }, 5362306a36Sopenharmony_ci { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" }, 5462306a36Sopenharmony_ci { OMAPFB_CAPS_WINDOW_SCALE, "scale window" }, 5562306a36Sopenharmony_ci { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" }, 5662306a36Sopenharmony_ci { OMAPFB_CAPS_WINDOW_ROTATE, "rotate window" }, 5762306a36Sopenharmony_ci { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" }, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic const struct caps_table_struct color_caps[] = { 6162306a36Sopenharmony_ci { 1 << OMAPFB_COLOR_RGB565, "RGB565", }, 6262306a36Sopenharmony_ci { 1 << OMAPFB_COLOR_YUV422, "YUV422", }, 6362306a36Sopenharmony_ci { 1 << OMAPFB_COLOR_YUV420, "YUV420", }, 6462306a36Sopenharmony_ci { 1 << OMAPFB_COLOR_CLUT_8BPP, "CLUT8", }, 6562306a36Sopenharmony_ci { 1 << OMAPFB_COLOR_CLUT_4BPP, "CLUT4", }, 6662306a36Sopenharmony_ci { 1 << OMAPFB_COLOR_CLUT_2BPP, "CLUT2", }, 6762306a36Sopenharmony_ci { 1 << OMAPFB_COLOR_CLUT_1BPP, "CLUT1", }, 6862306a36Sopenharmony_ci { 1 << OMAPFB_COLOR_RGB444, "RGB444", }, 6962306a36Sopenharmony_ci { 1 << OMAPFB_COLOR_YUY422, "YUY422", }, 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void omapdss_release(struct device *dev) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* dummy device for clocks */ 7762306a36Sopenharmony_cistatic struct platform_device omapdss_device = { 7862306a36Sopenharmony_ci .name = "omapdss_dss", 7962306a36Sopenharmony_ci .id = -1, 8062306a36Sopenharmony_ci .dev = { 8162306a36Sopenharmony_ci .release = omapdss_release, 8262306a36Sopenharmony_ci }, 8362306a36Sopenharmony_ci}; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * --------------------------------------------------------------------------- 8762306a36Sopenharmony_ci * LCD panel 8862306a36Sopenharmony_ci * --------------------------------------------------------------------------- 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ciextern struct lcd_ctrl hwa742_ctrl; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic const struct lcd_ctrl *ctrls[] = { 9362306a36Sopenharmony_ci &omap1_int_ctrl, 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#ifdef CONFIG_FB_OMAP_LCDC_HWA742 9662306a36Sopenharmony_ci &hwa742_ctrl, 9762306a36Sopenharmony_ci#endif 9862306a36Sopenharmony_ci}; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL 10162306a36Sopenharmony_ciextern struct lcd_ctrl_extif omap1_ext_if; 10262306a36Sopenharmony_ci#endif 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic void omapfb_rqueue_lock(struct omapfb_device *fbdev) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci mutex_lock(&fbdev->rqueue_mutex); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_cistatic void omapfb_rqueue_unlock(struct omapfb_device *fbdev) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci mutex_unlock(&fbdev->rqueue_mutex); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* 11562306a36Sopenharmony_ci * --------------------------------------------------------------------------- 11662306a36Sopenharmony_ci * LCD controller and LCD DMA 11762306a36Sopenharmony_ci * --------------------------------------------------------------------------- 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci/* 12062306a36Sopenharmony_ci * Allocate resources needed for LCD controller and LCD DMA operations. Video 12162306a36Sopenharmony_ci * memory is allocated from system memory according to the virtual display 12262306a36Sopenharmony_ci * size, except if a bigger memory size is specified explicitly as a kernel 12362306a36Sopenharmony_ci * parameter. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_cistatic int ctrl_init(struct omapfb_device *fbdev) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci int r; 12862306a36Sopenharmony_ci int i; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci /* kernel/module vram parameters override boot tags/board config */ 13162306a36Sopenharmony_ci if (def_vram_cnt) { 13262306a36Sopenharmony_ci for (i = 0; i < def_vram_cnt; i++) 13362306a36Sopenharmony_ci fbdev->mem_desc.region[i].size = 13462306a36Sopenharmony_ci PAGE_ALIGN(def_vram[i]); 13562306a36Sopenharmony_ci fbdev->mem_desc.region_cnt = i; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci if (!fbdev->mem_desc.region_cnt) { 13962306a36Sopenharmony_ci struct lcd_panel *panel = fbdev->panel; 14062306a36Sopenharmony_ci int def_size; 14162306a36Sopenharmony_ci int bpp = panel->bpp; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci /* 12 bpp is packed in 16 bits */ 14462306a36Sopenharmony_ci if (bpp == 12) 14562306a36Sopenharmony_ci bpp = 16; 14662306a36Sopenharmony_ci def_size = def_vxres * def_vyres * bpp / 8; 14762306a36Sopenharmony_ci fbdev->mem_desc.region_cnt = 1; 14862306a36Sopenharmony_ci fbdev->mem_desc.region[0].size = PAGE_ALIGN(def_size); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc); 15162306a36Sopenharmony_ci if (r < 0) { 15262306a36Sopenharmony_ci dev_err(fbdev->dev, "controller initialization failed (%d)\n", 15362306a36Sopenharmony_ci r); 15462306a36Sopenharmony_ci return r; 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci#ifdef DEBUG 15862306a36Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 15962306a36Sopenharmony_ci dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n", 16062306a36Sopenharmony_ci i, 16162306a36Sopenharmony_ci fbdev->mem_desc.region[i].paddr, 16262306a36Sopenharmony_ci fbdev->mem_desc.region[i].vaddr, 16362306a36Sopenharmony_ci fbdev->mem_desc.region[i].size); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci#endif 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic void ctrl_cleanup(struct omapfb_device *fbdev) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci fbdev->ctrl->cleanup(); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* Must be called with fbdev->rqueue_mutex held. */ 17562306a36Sopenharmony_cistatic int ctrl_change_mode(struct fb_info *fbi) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci int r; 17862306a36Sopenharmony_ci unsigned long offset; 17962306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 18062306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 18162306a36Sopenharmony_ci struct fb_var_screeninfo *var = &fbi->var; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci offset = var->yoffset * fbi->fix.line_length + 18462306a36Sopenharmony_ci var->xoffset * var->bits_per_pixel / 8; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (fbdev->ctrl->sync) 18762306a36Sopenharmony_ci fbdev->ctrl->sync(); 18862306a36Sopenharmony_ci r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out, 18962306a36Sopenharmony_ci offset, var->xres_virtual, 19062306a36Sopenharmony_ci plane->info.pos_x, plane->info.pos_y, 19162306a36Sopenharmony_ci var->xres, var->yres, plane->color_mode); 19262306a36Sopenharmony_ci if (r < 0) 19362306a36Sopenharmony_ci return r; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (fbdev->ctrl->set_rotate != NULL) { 19662306a36Sopenharmony_ci r = fbdev->ctrl->set_rotate(var->rotate); 19762306a36Sopenharmony_ci if (r < 0) 19862306a36Sopenharmony_ci return r; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (fbdev->ctrl->set_scale != NULL) 20262306a36Sopenharmony_ci r = fbdev->ctrl->set_scale(plane->idx, 20362306a36Sopenharmony_ci var->xres, var->yres, 20462306a36Sopenharmony_ci plane->info.out_width, 20562306a36Sopenharmony_ci plane->info.out_height); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return r; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* 21162306a36Sopenharmony_ci * --------------------------------------------------------------------------- 21262306a36Sopenharmony_ci * fbdev framework callbacks and the ioctl interface 21362306a36Sopenharmony_ci * --------------------------------------------------------------------------- 21462306a36Sopenharmony_ci */ 21562306a36Sopenharmony_ci/* Called each time the omapfb device is opened */ 21662306a36Sopenharmony_cistatic int omapfb_open(struct fb_info *info, int user) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic void omapfb_sync(struct fb_info *info); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* Called when the omapfb device is closed. We make sure that any pending 22462306a36Sopenharmony_ci * gfx DMA operations are ended, before we return. */ 22562306a36Sopenharmony_cistatic int omapfb_release(struct fb_info *info, int user) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci omapfb_sync(info); 22862306a36Sopenharmony_ci return 0; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* Store a single color palette entry into a pseudo palette or the hardware 23262306a36Sopenharmony_ci * palette if one is available. For now we support only 16bpp and thus store 23362306a36Sopenharmony_ci * the entry only to the pseudo palette. 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_cistatic int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green, 23662306a36Sopenharmony_ci u_int blue, u_int transp, int update_hw_pal) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct omapfb_plane_struct *plane = info->par; 23962306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 24062306a36Sopenharmony_ci struct fb_var_screeninfo *var = &info->var; 24162306a36Sopenharmony_ci int r = 0; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci switch (plane->color_mode) { 24462306a36Sopenharmony_ci case OMAPFB_COLOR_YUV422: 24562306a36Sopenharmony_ci case OMAPFB_COLOR_YUV420: 24662306a36Sopenharmony_ci case OMAPFB_COLOR_YUY422: 24762306a36Sopenharmony_ci r = -EINVAL; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci case OMAPFB_COLOR_CLUT_8BPP: 25062306a36Sopenharmony_ci case OMAPFB_COLOR_CLUT_4BPP: 25162306a36Sopenharmony_ci case OMAPFB_COLOR_CLUT_2BPP: 25262306a36Sopenharmony_ci case OMAPFB_COLOR_CLUT_1BPP: 25362306a36Sopenharmony_ci if (fbdev->ctrl->setcolreg) 25462306a36Sopenharmony_ci r = fbdev->ctrl->setcolreg(regno, red, green, blue, 25562306a36Sopenharmony_ci transp, update_hw_pal); 25662306a36Sopenharmony_ci fallthrough; 25762306a36Sopenharmony_ci case OMAPFB_COLOR_RGB565: 25862306a36Sopenharmony_ci case OMAPFB_COLOR_RGB444: 25962306a36Sopenharmony_ci if (r != 0) 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (regno < 16) { 26362306a36Sopenharmony_ci u16 pal; 26462306a36Sopenharmony_ci pal = ((red >> (16 - var->red.length)) << 26562306a36Sopenharmony_ci var->red.offset) | 26662306a36Sopenharmony_ci ((green >> (16 - var->green.length)) << 26762306a36Sopenharmony_ci var->green.offset) | 26862306a36Sopenharmony_ci (blue >> (16 - var->blue.length)); 26962306a36Sopenharmony_ci ((u32 *)(info->pseudo_palette))[regno] = pal; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci default: 27362306a36Sopenharmony_ci BUG(); 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci return r; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 27962306a36Sopenharmony_ci u_int transp, struct fb_info *info) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci return _setcolreg(info, regno, red, green, blue, transp, 1); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_cistatic int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int count, index, r; 28762306a36Sopenharmony_ci u16 *red, *green, *blue, *transp; 28862306a36Sopenharmony_ci u16 trans = 0xffff; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci red = cmap->red; 29162306a36Sopenharmony_ci green = cmap->green; 29262306a36Sopenharmony_ci blue = cmap->blue; 29362306a36Sopenharmony_ci transp = cmap->transp; 29462306a36Sopenharmony_ci index = cmap->start; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci for (count = 0; count < cmap->len; count++) { 29762306a36Sopenharmony_ci if (transp) 29862306a36Sopenharmony_ci trans = *transp++; 29962306a36Sopenharmony_ci r = _setcolreg(info, index++, *red++, *green++, *blue++, trans, 30062306a36Sopenharmony_ci count == cmap->len - 1); 30162306a36Sopenharmony_ci if (r != 0) 30262306a36Sopenharmony_ci return r; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return 0; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int omapfb_update_full_screen(struct fb_info *fbi); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic int omapfb_blank(int blank, struct fb_info *fbi) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 31362306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 31462306a36Sopenharmony_ci int do_update = 0; 31562306a36Sopenharmony_ci int r = 0; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 31862306a36Sopenharmony_ci switch (blank) { 31962306a36Sopenharmony_ci case FB_BLANK_UNBLANK: 32062306a36Sopenharmony_ci if (fbdev->state == OMAPFB_SUSPENDED) { 32162306a36Sopenharmony_ci if (fbdev->ctrl->resume) 32262306a36Sopenharmony_ci fbdev->ctrl->resume(); 32362306a36Sopenharmony_ci if (fbdev->panel->enable) 32462306a36Sopenharmony_ci fbdev->panel->enable(fbdev->panel); 32562306a36Sopenharmony_ci fbdev->state = OMAPFB_ACTIVE; 32662306a36Sopenharmony_ci if (fbdev->ctrl->get_update_mode() == 32762306a36Sopenharmony_ci OMAPFB_MANUAL_UPDATE) 32862306a36Sopenharmony_ci do_update = 1; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: 33262306a36Sopenharmony_ci if (fbdev->state == OMAPFB_ACTIVE) { 33362306a36Sopenharmony_ci if (fbdev->panel->disable) 33462306a36Sopenharmony_ci fbdev->panel->disable(fbdev->panel); 33562306a36Sopenharmony_ci if (fbdev->ctrl->suspend) 33662306a36Sopenharmony_ci fbdev->ctrl->suspend(); 33762306a36Sopenharmony_ci fbdev->state = OMAPFB_SUSPENDED; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci break; 34062306a36Sopenharmony_ci default: 34162306a36Sopenharmony_ci r = -EINVAL; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci if (r == 0 && do_update) 34662306a36Sopenharmony_ci r = omapfb_update_full_screen(fbi); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return r; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void omapfb_sync(struct fb_info *fbi) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 35462306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 35762306a36Sopenharmony_ci if (fbdev->ctrl->sync) 35862306a36Sopenharmony_ci fbdev->ctrl->sync(); 35962306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/* 36362306a36Sopenharmony_ci * Set fb_info.fix fields and also updates fbdev. 36462306a36Sopenharmony_ci * When calling this fb_info.var must be set up already. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_cistatic void set_fb_fix(struct fb_info *fbi, int from_init) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct fb_fix_screeninfo *fix = &fbi->fix; 36962306a36Sopenharmony_ci struct fb_var_screeninfo *var = &fbi->var; 37062306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 37162306a36Sopenharmony_ci struct omapfb_mem_region *rg; 37262306a36Sopenharmony_ci int bpp; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci rg = &plane->fbdev->mem_desc.region[plane->idx]; 37562306a36Sopenharmony_ci fbi->screen_base = rg->vaddr; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci if (!from_init) { 37862306a36Sopenharmony_ci mutex_lock(&fbi->mm_lock); 37962306a36Sopenharmony_ci fix->smem_start = rg->paddr; 38062306a36Sopenharmony_ci fix->smem_len = rg->size; 38162306a36Sopenharmony_ci mutex_unlock(&fbi->mm_lock); 38262306a36Sopenharmony_ci } else { 38362306a36Sopenharmony_ci fix->smem_start = rg->paddr; 38462306a36Sopenharmony_ci fix->smem_len = rg->size; 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci fix->type = FB_TYPE_PACKED_PIXELS; 38862306a36Sopenharmony_ci bpp = var->bits_per_pixel; 38962306a36Sopenharmony_ci if (var->nonstd) 39062306a36Sopenharmony_ci fix->visual = FB_VISUAL_PSEUDOCOLOR; 39162306a36Sopenharmony_ci else switch (var->bits_per_pixel) { 39262306a36Sopenharmony_ci case 16: 39362306a36Sopenharmony_ci case 12: 39462306a36Sopenharmony_ci fix->visual = FB_VISUAL_TRUECOLOR; 39562306a36Sopenharmony_ci /* 12bpp is stored in 16 bits */ 39662306a36Sopenharmony_ci bpp = 16; 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci case 1: 39962306a36Sopenharmony_ci case 2: 40062306a36Sopenharmony_ci case 4: 40162306a36Sopenharmony_ci case 8: 40262306a36Sopenharmony_ci fix->visual = FB_VISUAL_PSEUDOCOLOR; 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci fix->accel = FB_ACCEL_OMAP1610; 40662306a36Sopenharmony_ci fix->line_length = var->xres_virtual * bpp / 8; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_cistatic int set_color_mode(struct omapfb_plane_struct *plane, 41062306a36Sopenharmony_ci struct fb_var_screeninfo *var) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci switch (var->nonstd) { 41362306a36Sopenharmony_ci case 0: 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci case OMAPFB_COLOR_YUV422: 41662306a36Sopenharmony_ci var->bits_per_pixel = 16; 41762306a36Sopenharmony_ci plane->color_mode = var->nonstd; 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci case OMAPFB_COLOR_YUV420: 42062306a36Sopenharmony_ci var->bits_per_pixel = 12; 42162306a36Sopenharmony_ci plane->color_mode = var->nonstd; 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci case OMAPFB_COLOR_YUY422: 42462306a36Sopenharmony_ci var->bits_per_pixel = 16; 42562306a36Sopenharmony_ci plane->color_mode = var->nonstd; 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci default: 42862306a36Sopenharmony_ci return -EINVAL; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci switch (var->bits_per_pixel) { 43262306a36Sopenharmony_ci case 1: 43362306a36Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_CLUT_1BPP; 43462306a36Sopenharmony_ci return 0; 43562306a36Sopenharmony_ci case 2: 43662306a36Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_CLUT_2BPP; 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci case 4: 43962306a36Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_CLUT_4BPP; 44062306a36Sopenharmony_ci return 0; 44162306a36Sopenharmony_ci case 8: 44262306a36Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_CLUT_8BPP; 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci case 12: 44562306a36Sopenharmony_ci var->bits_per_pixel = 16; 44662306a36Sopenharmony_ci fallthrough; 44762306a36Sopenharmony_ci case 16: 44862306a36Sopenharmony_ci if (plane->fbdev->panel->bpp == 12) 44962306a36Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_RGB444; 45062306a36Sopenharmony_ci else 45162306a36Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_RGB565; 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci default: 45462306a36Sopenharmony_ci return -EINVAL; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci/* 45962306a36Sopenharmony_ci * Check the values in var against our capabilities and in case of out of 46062306a36Sopenharmony_ci * bound values try to adjust them. 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_cistatic int set_fb_var(struct fb_info *fbi, 46362306a36Sopenharmony_ci struct fb_var_screeninfo *var) 46462306a36Sopenharmony_ci{ 46562306a36Sopenharmony_ci int bpp; 46662306a36Sopenharmony_ci unsigned long max_frame_size; 46762306a36Sopenharmony_ci unsigned long line_size; 46862306a36Sopenharmony_ci int xres_min, xres_max; 46962306a36Sopenharmony_ci int yres_min, yres_max; 47062306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 47162306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 47262306a36Sopenharmony_ci struct lcd_panel *panel = fbdev->panel; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (set_color_mode(plane, var) < 0) 47562306a36Sopenharmony_ci return -EINVAL; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci bpp = var->bits_per_pixel; 47862306a36Sopenharmony_ci if (plane->color_mode == OMAPFB_COLOR_RGB444) 47962306a36Sopenharmony_ci bpp = 16; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci switch (var->rotate) { 48262306a36Sopenharmony_ci case 0: 48362306a36Sopenharmony_ci case 180: 48462306a36Sopenharmony_ci xres_min = OMAPFB_PLANE_XRES_MIN; 48562306a36Sopenharmony_ci xres_max = panel->x_res; 48662306a36Sopenharmony_ci yres_min = OMAPFB_PLANE_YRES_MIN; 48762306a36Sopenharmony_ci yres_max = panel->y_res; 48862306a36Sopenharmony_ci if (cpu_is_omap15xx()) { 48962306a36Sopenharmony_ci var->xres = panel->x_res; 49062306a36Sopenharmony_ci var->yres = panel->y_res; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci break; 49362306a36Sopenharmony_ci case 90: 49462306a36Sopenharmony_ci case 270: 49562306a36Sopenharmony_ci xres_min = OMAPFB_PLANE_YRES_MIN; 49662306a36Sopenharmony_ci xres_max = panel->y_res; 49762306a36Sopenharmony_ci yres_min = OMAPFB_PLANE_XRES_MIN; 49862306a36Sopenharmony_ci yres_max = panel->x_res; 49962306a36Sopenharmony_ci if (cpu_is_omap15xx()) { 50062306a36Sopenharmony_ci var->xres = panel->y_res; 50162306a36Sopenharmony_ci var->yres = panel->x_res; 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci break; 50462306a36Sopenharmony_ci default: 50562306a36Sopenharmony_ci return -EINVAL; 50662306a36Sopenharmony_ci } 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (var->xres < xres_min) 50962306a36Sopenharmony_ci var->xres = xres_min; 51062306a36Sopenharmony_ci if (var->yres < yres_min) 51162306a36Sopenharmony_ci var->yres = yres_min; 51262306a36Sopenharmony_ci if (var->xres > xres_max) 51362306a36Sopenharmony_ci var->xres = xres_max; 51462306a36Sopenharmony_ci if (var->yres > yres_max) 51562306a36Sopenharmony_ci var->yres = yres_max; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (var->xres_virtual < var->xres) 51862306a36Sopenharmony_ci var->xres_virtual = var->xres; 51962306a36Sopenharmony_ci if (var->yres_virtual < var->yres) 52062306a36Sopenharmony_ci var->yres_virtual = var->yres; 52162306a36Sopenharmony_ci max_frame_size = fbdev->mem_desc.region[plane->idx].size; 52262306a36Sopenharmony_ci line_size = var->xres_virtual * bpp / 8; 52362306a36Sopenharmony_ci if (line_size * var->yres_virtual > max_frame_size) { 52462306a36Sopenharmony_ci /* Try to keep yres_virtual first */ 52562306a36Sopenharmony_ci line_size = max_frame_size / var->yres_virtual; 52662306a36Sopenharmony_ci var->xres_virtual = line_size * 8 / bpp; 52762306a36Sopenharmony_ci if (var->xres_virtual < var->xres) { 52862306a36Sopenharmony_ci /* Still doesn't fit. Shrink yres_virtual too */ 52962306a36Sopenharmony_ci var->xres_virtual = var->xres; 53062306a36Sopenharmony_ci line_size = var->xres * bpp / 8; 53162306a36Sopenharmony_ci var->yres_virtual = max_frame_size / line_size; 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci /* Recheck this, as the virtual size changed. */ 53462306a36Sopenharmony_ci if (var->xres_virtual < var->xres) 53562306a36Sopenharmony_ci var->xres = var->xres_virtual; 53662306a36Sopenharmony_ci if (var->yres_virtual < var->yres) 53762306a36Sopenharmony_ci var->yres = var->yres_virtual; 53862306a36Sopenharmony_ci if (var->xres < xres_min || var->yres < yres_min) 53962306a36Sopenharmony_ci return -EINVAL; 54062306a36Sopenharmony_ci } 54162306a36Sopenharmony_ci if (var->xres + var->xoffset > var->xres_virtual) 54262306a36Sopenharmony_ci var->xoffset = var->xres_virtual - var->xres; 54362306a36Sopenharmony_ci if (var->yres + var->yoffset > var->yres_virtual) 54462306a36Sopenharmony_ci var->yoffset = var->yres_virtual - var->yres; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (plane->color_mode == OMAPFB_COLOR_RGB444) { 54762306a36Sopenharmony_ci var->red.offset = 8; 54862306a36Sopenharmony_ci var->red.length = 4; 54962306a36Sopenharmony_ci var->red.msb_right = 0; 55062306a36Sopenharmony_ci var->green.offset = 4; 55162306a36Sopenharmony_ci var->green.length = 4; 55262306a36Sopenharmony_ci var->green.msb_right = 0; 55362306a36Sopenharmony_ci var->blue.offset = 0; 55462306a36Sopenharmony_ci var->blue.length = 4; 55562306a36Sopenharmony_ci var->blue.msb_right = 0; 55662306a36Sopenharmony_ci } else { 55762306a36Sopenharmony_ci var->red.offset = 11; 55862306a36Sopenharmony_ci var->red.length = 5; 55962306a36Sopenharmony_ci var->red.msb_right = 0; 56062306a36Sopenharmony_ci var->green.offset = 5; 56162306a36Sopenharmony_ci var->green.length = 6; 56262306a36Sopenharmony_ci var->green.msb_right = 0; 56362306a36Sopenharmony_ci var->blue.offset = 0; 56462306a36Sopenharmony_ci var->blue.length = 5; 56562306a36Sopenharmony_ci var->blue.msb_right = 0; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci var->height = -1; 56962306a36Sopenharmony_ci var->width = -1; 57062306a36Sopenharmony_ci var->grayscale = 0; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci /* pixclock in ps, the rest in pixclock */ 57362306a36Sopenharmony_ci var->pixclock = 10000000 / (panel->pixel_clock / 100); 57462306a36Sopenharmony_ci var->left_margin = panel->hfp; 57562306a36Sopenharmony_ci var->right_margin = panel->hbp; 57662306a36Sopenharmony_ci var->upper_margin = panel->vfp; 57762306a36Sopenharmony_ci var->lower_margin = panel->vbp; 57862306a36Sopenharmony_ci var->hsync_len = panel->hsw; 57962306a36Sopenharmony_ci var->vsync_len = panel->vsw; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* TODO: get these from panel->config */ 58262306a36Sopenharmony_ci var->vmode = FB_VMODE_NONINTERLACED; 58362306a36Sopenharmony_ci var->sync = 0; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return 0; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci/* 59062306a36Sopenharmony_ci * Set new x,y offsets in the virtual display for the visible area and switch 59162306a36Sopenharmony_ci * to the new mode. 59262306a36Sopenharmony_ci */ 59362306a36Sopenharmony_cistatic int omapfb_pan_display(struct fb_var_screeninfo *var, 59462306a36Sopenharmony_ci struct fb_info *fbi) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 59762306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 59862306a36Sopenharmony_ci int r = 0; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 60162306a36Sopenharmony_ci if (var->xoffset != fbi->var.xoffset || 60262306a36Sopenharmony_ci var->yoffset != fbi->var.yoffset) { 60362306a36Sopenharmony_ci struct fb_var_screeninfo *new_var = &fbdev->new_var; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci memcpy(new_var, &fbi->var, sizeof(*new_var)); 60662306a36Sopenharmony_ci new_var->xoffset = var->xoffset; 60762306a36Sopenharmony_ci new_var->yoffset = var->yoffset; 60862306a36Sopenharmony_ci if (set_fb_var(fbi, new_var)) 60962306a36Sopenharmony_ci r = -EINVAL; 61062306a36Sopenharmony_ci else { 61162306a36Sopenharmony_ci memcpy(&fbi->var, new_var, sizeof(*new_var)); 61262306a36Sopenharmony_ci ctrl_change_mode(fbi); 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci return r; 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci/* Set mirror to vertical axis and switch to the new mode. */ 62162306a36Sopenharmony_cistatic int omapfb_mirror(struct fb_info *fbi, int mirror) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 62462306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 62562306a36Sopenharmony_ci int r = 0; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 62862306a36Sopenharmony_ci mirror = mirror ? 1 : 0; 62962306a36Sopenharmony_ci if (cpu_is_omap15xx()) 63062306a36Sopenharmony_ci r = -EINVAL; 63162306a36Sopenharmony_ci else if (mirror != plane->info.mirror) { 63262306a36Sopenharmony_ci plane->info.mirror = mirror; 63362306a36Sopenharmony_ci r = ctrl_change_mode(fbi); 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci return r; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci/* 64162306a36Sopenharmony_ci * Check values in var, try to adjust them in case of out of bound values if 64262306a36Sopenharmony_ci * possible, or return error. 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_cistatic int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 64762306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 64862306a36Sopenharmony_ci int r; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 65162306a36Sopenharmony_ci if (fbdev->ctrl->sync != NULL) 65262306a36Sopenharmony_ci fbdev->ctrl->sync(); 65362306a36Sopenharmony_ci r = set_fb_var(fbi, var); 65462306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci return r; 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci/* 66062306a36Sopenharmony_ci * Switch to a new mode. The parameters for it has been check already by 66162306a36Sopenharmony_ci * omapfb_check_var. 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_cistatic int omapfb_set_par(struct fb_info *fbi) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 66662306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 66762306a36Sopenharmony_ci int r = 0; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 67062306a36Sopenharmony_ci set_fb_fix(fbi, 0); 67162306a36Sopenharmony_ci r = ctrl_change_mode(fbi); 67262306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci return r; 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic int omapfb_update_window_async(struct fb_info *fbi, 67862306a36Sopenharmony_ci struct omapfb_update_window *win, 67962306a36Sopenharmony_ci void (*callback)(void *), 68062306a36Sopenharmony_ci void *callback_data) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci int xres, yres; 68362306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 68462306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 68562306a36Sopenharmony_ci struct fb_var_screeninfo *var = &fbi->var; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci switch (var->rotate) { 68862306a36Sopenharmony_ci case 0: 68962306a36Sopenharmony_ci case 180: 69062306a36Sopenharmony_ci xres = fbdev->panel->x_res; 69162306a36Sopenharmony_ci yres = fbdev->panel->y_res; 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci case 90: 69462306a36Sopenharmony_ci case 270: 69562306a36Sopenharmony_ci xres = fbdev->panel->y_res; 69662306a36Sopenharmony_ci yres = fbdev->panel->x_res; 69762306a36Sopenharmony_ci break; 69862306a36Sopenharmony_ci default: 69962306a36Sopenharmony_ci return -EINVAL; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (win->x >= xres || win->y >= yres || 70362306a36Sopenharmony_ci win->out_x > xres || win->out_y > yres) 70462306a36Sopenharmony_ci return -EINVAL; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci if (!fbdev->ctrl->update_window || 70762306a36Sopenharmony_ci fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) 70862306a36Sopenharmony_ci return -ENODEV; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (win->x + win->width > xres) 71162306a36Sopenharmony_ci win->width = xres - win->x; 71262306a36Sopenharmony_ci if (win->y + win->height > yres) 71362306a36Sopenharmony_ci win->height = yres - win->y; 71462306a36Sopenharmony_ci if (win->out_x + win->out_width > xres) 71562306a36Sopenharmony_ci win->out_width = xres - win->out_x; 71662306a36Sopenharmony_ci if (win->out_y + win->out_height > yres) 71762306a36Sopenharmony_ci win->out_height = yres - win->out_y; 71862306a36Sopenharmony_ci if (!win->width || !win->height || !win->out_width || !win->out_height) 71962306a36Sopenharmony_ci return 0; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return fbdev->ctrl->update_window(fbi, win, callback, callback_data); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_cistatic int omapfb_update_win(struct fb_info *fbi, 72562306a36Sopenharmony_ci struct omapfb_update_window *win) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 72862306a36Sopenharmony_ci int ret; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci omapfb_rqueue_lock(plane->fbdev); 73162306a36Sopenharmony_ci ret = omapfb_update_window_async(fbi, win, NULL, NULL); 73262306a36Sopenharmony_ci omapfb_rqueue_unlock(plane->fbdev); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci return ret; 73562306a36Sopenharmony_ci} 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_cistatic int omapfb_update_full_screen(struct fb_info *fbi) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 74062306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 74162306a36Sopenharmony_ci struct omapfb_update_window win; 74262306a36Sopenharmony_ci int r; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci if (!fbdev->ctrl->update_window || 74562306a36Sopenharmony_ci fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) 74662306a36Sopenharmony_ci return -ENODEV; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci win.x = 0; 74962306a36Sopenharmony_ci win.y = 0; 75062306a36Sopenharmony_ci win.width = fbi->var.xres; 75162306a36Sopenharmony_ci win.height = fbi->var.yres; 75262306a36Sopenharmony_ci win.out_x = 0; 75362306a36Sopenharmony_ci win.out_y = 0; 75462306a36Sopenharmony_ci win.out_width = fbi->var.xres; 75562306a36Sopenharmony_ci win.out_height = fbi->var.yres; 75662306a36Sopenharmony_ci win.format = 0; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 75962306a36Sopenharmony_ci r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL); 76062306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci return r; 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_cistatic int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) 76662306a36Sopenharmony_ci{ 76762306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 76862306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 76962306a36Sopenharmony_ci struct lcd_panel *panel = fbdev->panel; 77062306a36Sopenharmony_ci struct omapfb_plane_info old_info; 77162306a36Sopenharmony_ci int r = 0; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci if (pi->pos_x + pi->out_width > panel->x_res || 77462306a36Sopenharmony_ci pi->pos_y + pi->out_height > panel->y_res) 77562306a36Sopenharmony_ci return -EINVAL; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 77862306a36Sopenharmony_ci if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) { 77962306a36Sopenharmony_ci /* 78062306a36Sopenharmony_ci * This plane's memory was freed, can't enable it 78162306a36Sopenharmony_ci * until it's reallocated. 78262306a36Sopenharmony_ci */ 78362306a36Sopenharmony_ci r = -EINVAL; 78462306a36Sopenharmony_ci goto out; 78562306a36Sopenharmony_ci } 78662306a36Sopenharmony_ci old_info = plane->info; 78762306a36Sopenharmony_ci plane->info = *pi; 78862306a36Sopenharmony_ci if (pi->enabled) { 78962306a36Sopenharmony_ci r = ctrl_change_mode(fbi); 79062306a36Sopenharmony_ci if (r < 0) { 79162306a36Sopenharmony_ci plane->info = old_info; 79262306a36Sopenharmony_ci goto out; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled); 79662306a36Sopenharmony_ci if (r < 0) { 79762306a36Sopenharmony_ci plane->info = old_info; 79862306a36Sopenharmony_ci goto out; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ciout: 80162306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 80262306a36Sopenharmony_ci return r; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci *pi = plane->info; 81062306a36Sopenharmony_ci return 0; 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistatic int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 81662306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 81762306a36Sopenharmony_ci struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx]; 81862306a36Sopenharmony_ci size_t size; 81962306a36Sopenharmony_ci int r = 0; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (fbdev->ctrl->setup_mem == NULL) 82262306a36Sopenharmony_ci return -ENODEV; 82362306a36Sopenharmony_ci if (mi->type != OMAPFB_MEMTYPE_SDRAM) 82462306a36Sopenharmony_ci return -EINVAL; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci size = PAGE_ALIGN(mi->size); 82762306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 82862306a36Sopenharmony_ci if (plane->info.enabled) { 82962306a36Sopenharmony_ci r = -EBUSY; 83062306a36Sopenharmony_ci goto out; 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci if (rg->size != size || rg->type != mi->type) { 83362306a36Sopenharmony_ci struct fb_var_screeninfo *new_var = &fbdev->new_var; 83462306a36Sopenharmony_ci unsigned long old_size = rg->size; 83562306a36Sopenharmony_ci u8 old_type = rg->type; 83662306a36Sopenharmony_ci unsigned long paddr; 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci rg->size = size; 83962306a36Sopenharmony_ci rg->type = mi->type; 84062306a36Sopenharmony_ci /* 84162306a36Sopenharmony_ci * size == 0 is a special case, for which we 84262306a36Sopenharmony_ci * don't check / adjust the screen parameters. 84362306a36Sopenharmony_ci * This isn't a problem since the plane can't 84462306a36Sopenharmony_ci * be reenabled unless its size is > 0. 84562306a36Sopenharmony_ci */ 84662306a36Sopenharmony_ci if (old_size != size && size) { 84762306a36Sopenharmony_ci if (size) { 84862306a36Sopenharmony_ci memcpy(new_var, &fbi->var, sizeof(*new_var)); 84962306a36Sopenharmony_ci r = set_fb_var(fbi, new_var); 85062306a36Sopenharmony_ci if (r < 0) 85162306a36Sopenharmony_ci goto out; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci if (fbdev->ctrl->sync) 85662306a36Sopenharmony_ci fbdev->ctrl->sync(); 85762306a36Sopenharmony_ci r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr); 85862306a36Sopenharmony_ci if (r < 0) { 85962306a36Sopenharmony_ci /* Revert changes. */ 86062306a36Sopenharmony_ci rg->size = old_size; 86162306a36Sopenharmony_ci rg->type = old_type; 86262306a36Sopenharmony_ci goto out; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci rg->paddr = paddr; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci if (old_size != size) { 86762306a36Sopenharmony_ci if (size) { 86862306a36Sopenharmony_ci memcpy(&fbi->var, new_var, sizeof(fbi->var)); 86962306a36Sopenharmony_ci set_fb_fix(fbi, 0); 87062306a36Sopenharmony_ci } else { 87162306a36Sopenharmony_ci /* 87262306a36Sopenharmony_ci * Set these explicitly to indicate that the 87362306a36Sopenharmony_ci * plane memory is dealloce'd, the other 87462306a36Sopenharmony_ci * screen parameters in var / fix are invalid. 87562306a36Sopenharmony_ci */ 87662306a36Sopenharmony_ci mutex_lock(&fbi->mm_lock); 87762306a36Sopenharmony_ci fbi->fix.smem_start = 0; 87862306a36Sopenharmony_ci fbi->fix.smem_len = 0; 87962306a36Sopenharmony_ci mutex_unlock(&fbi->mm_lock); 88062306a36Sopenharmony_ci } 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ciout: 88462306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci return r; 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_cistatic int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) 89062306a36Sopenharmony_ci{ 89162306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 89262306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 89362306a36Sopenharmony_ci struct omapfb_mem_region *rg; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci rg = &fbdev->mem_desc.region[plane->idx]; 89662306a36Sopenharmony_ci memset(mi, 0, sizeof(*mi)); 89762306a36Sopenharmony_ci mi->size = rg->size; 89862306a36Sopenharmony_ci mi->type = rg->type; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return 0; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic int omapfb_set_color_key(struct omapfb_device *fbdev, 90462306a36Sopenharmony_ci struct omapfb_color_key *ck) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci int r; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (!fbdev->ctrl->set_color_key) 90962306a36Sopenharmony_ci return -ENODEV; 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 91262306a36Sopenharmony_ci r = fbdev->ctrl->set_color_key(ck); 91362306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return r; 91662306a36Sopenharmony_ci} 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_cistatic int omapfb_get_color_key(struct omapfb_device *fbdev, 91962306a36Sopenharmony_ci struct omapfb_color_key *ck) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci int r; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (!fbdev->ctrl->get_color_key) 92462306a36Sopenharmony_ci return -ENODEV; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 92762306a36Sopenharmony_ci r = fbdev->ctrl->get_color_key(ck); 92862306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci return r; 93162306a36Sopenharmony_ci} 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM]; 93462306a36Sopenharmony_cistatic int notifier_inited; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic void omapfb_init_notifier(void) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci int i; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci for (i = 0; i < OMAPFB_PLANE_NUM; i++) 94162306a36Sopenharmony_ci BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]); 94262306a36Sopenharmony_ci} 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ciint omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, 94562306a36Sopenharmony_ci omapfb_notifier_callback_t callback, 94662306a36Sopenharmony_ci void *callback_data) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci int r; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM) 95162306a36Sopenharmony_ci return -EINVAL; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (!notifier_inited) { 95462306a36Sopenharmony_ci omapfb_init_notifier(); 95562306a36Sopenharmony_ci notifier_inited = 1; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *, 95962306a36Sopenharmony_ci unsigned long, void *))callback; 96062306a36Sopenharmony_ci omapfb_nb->data = callback_data; 96162306a36Sopenharmony_ci r = blocking_notifier_chain_register( 96262306a36Sopenharmony_ci &omapfb_client_list[omapfb_nb->plane_idx], 96362306a36Sopenharmony_ci &omapfb_nb->nb); 96462306a36Sopenharmony_ci if (r) 96562306a36Sopenharmony_ci return r; 96662306a36Sopenharmony_ci if (omapfb_dev != NULL && 96762306a36Sopenharmony_ci omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) { 96862306a36Sopenharmony_ci omapfb_dev->ctrl->bind_client(omapfb_nb); 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci return 0; 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ciEXPORT_SYMBOL(omapfb_register_client); 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ciint omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci return blocking_notifier_chain_unregister( 97862306a36Sopenharmony_ci &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb); 97962306a36Sopenharmony_ci} 98062306a36Sopenharmony_ciEXPORT_SYMBOL(omapfb_unregister_client); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_civoid omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event) 98362306a36Sopenharmony_ci{ 98462306a36Sopenharmony_ci int i; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci if (!notifier_inited) 98762306a36Sopenharmony_ci /* no client registered yet */ 98862306a36Sopenharmony_ci return; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci for (i = 0; i < OMAPFB_PLANE_NUM; i++) 99162306a36Sopenharmony_ci blocking_notifier_call_chain(&omapfb_client_list[i], event, 99262306a36Sopenharmony_ci fbdev->fb_info[i]); 99362306a36Sopenharmony_ci} 99462306a36Sopenharmony_ciEXPORT_SYMBOL(omapfb_notify_clients); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic int omapfb_set_update_mode(struct omapfb_device *fbdev, 99762306a36Sopenharmony_ci enum omapfb_update_mode mode) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci int r; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 100262306a36Sopenharmony_ci r = fbdev->ctrl->set_update_mode(mode); 100362306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci return r; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev) 100962306a36Sopenharmony_ci{ 101062306a36Sopenharmony_ci int r; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 101362306a36Sopenharmony_ci r = fbdev->ctrl->get_update_mode(); 101462306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci return r; 101762306a36Sopenharmony_ci} 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_cistatic void omapfb_get_caps(struct omapfb_device *fbdev, int plane, 102062306a36Sopenharmony_ci struct omapfb_caps *caps) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci memset(caps, 0, sizeof(*caps)); 102362306a36Sopenharmony_ci fbdev->ctrl->get_caps(plane, caps); 102462306a36Sopenharmony_ci if (fbdev->panel->get_caps) 102562306a36Sopenharmony_ci caps->ctrl |= fbdev->panel->get_caps(fbdev->panel); 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci/* For lcd testing */ 102962306a36Sopenharmony_civoid omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 103262306a36Sopenharmony_ci *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval; 103362306a36Sopenharmony_ci if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) { 103462306a36Sopenharmony_ci struct omapfb_update_window win; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci memset(&win, 0, sizeof(win)); 103762306a36Sopenharmony_ci win.width = 2; 103862306a36Sopenharmony_ci win.height = 2; 103962306a36Sopenharmony_ci win.out_width = 2; 104062306a36Sopenharmony_ci win.out_height = 2; 104162306a36Sopenharmony_ci fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, NULL); 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ciEXPORT_SYMBOL(omapfb_write_first_pixel); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci/* 104862306a36Sopenharmony_ci * Ioctl interface. Part of the kernel mode frame buffer API is duplicated 104962306a36Sopenharmony_ci * here to be accessible by user mode code. 105062306a36Sopenharmony_ci */ 105162306a36Sopenharmony_cistatic int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, 105262306a36Sopenharmony_ci unsigned long arg) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 105562306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 105662306a36Sopenharmony_ci const struct fb_ops *ops = fbi->fbops; 105762306a36Sopenharmony_ci union { 105862306a36Sopenharmony_ci struct omapfb_update_window update_window; 105962306a36Sopenharmony_ci struct omapfb_plane_info plane_info; 106062306a36Sopenharmony_ci struct omapfb_mem_info mem_info; 106162306a36Sopenharmony_ci struct omapfb_color_key color_key; 106262306a36Sopenharmony_ci enum omapfb_update_mode update_mode; 106362306a36Sopenharmony_ci struct omapfb_caps caps; 106462306a36Sopenharmony_ci unsigned int mirror; 106562306a36Sopenharmony_ci int plane_out; 106662306a36Sopenharmony_ci int enable_plane; 106762306a36Sopenharmony_ci } p; 106862306a36Sopenharmony_ci int r = 0; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci BUG_ON(!ops); 107162306a36Sopenharmony_ci switch (cmd) { 107262306a36Sopenharmony_ci case OMAPFB_MIRROR: 107362306a36Sopenharmony_ci if (get_user(p.mirror, (int __user *)arg)) 107462306a36Sopenharmony_ci r = -EFAULT; 107562306a36Sopenharmony_ci else 107662306a36Sopenharmony_ci omapfb_mirror(fbi, p.mirror); 107762306a36Sopenharmony_ci break; 107862306a36Sopenharmony_ci case OMAPFB_SYNC_GFX: 107962306a36Sopenharmony_ci omapfb_sync(fbi); 108062306a36Sopenharmony_ci break; 108162306a36Sopenharmony_ci case OMAPFB_VSYNC: 108262306a36Sopenharmony_ci break; 108362306a36Sopenharmony_ci case OMAPFB_SET_UPDATE_MODE: 108462306a36Sopenharmony_ci if (get_user(p.update_mode, (int __user *)arg)) 108562306a36Sopenharmony_ci r = -EFAULT; 108662306a36Sopenharmony_ci else 108762306a36Sopenharmony_ci r = omapfb_set_update_mode(fbdev, p.update_mode); 108862306a36Sopenharmony_ci break; 108962306a36Sopenharmony_ci case OMAPFB_GET_UPDATE_MODE: 109062306a36Sopenharmony_ci p.update_mode = omapfb_get_update_mode(fbdev); 109162306a36Sopenharmony_ci if (put_user(p.update_mode, 109262306a36Sopenharmony_ci (enum omapfb_update_mode __user *)arg)) 109362306a36Sopenharmony_ci r = -EFAULT; 109462306a36Sopenharmony_ci break; 109562306a36Sopenharmony_ci case OMAPFB_UPDATE_WINDOW_OLD: 109662306a36Sopenharmony_ci if (copy_from_user(&p.update_window, (void __user *)arg, 109762306a36Sopenharmony_ci sizeof(struct omapfb_update_window_old))) 109862306a36Sopenharmony_ci r = -EFAULT; 109962306a36Sopenharmony_ci else { 110062306a36Sopenharmony_ci struct omapfb_update_window *u = &p.update_window; 110162306a36Sopenharmony_ci u->out_x = u->x; 110262306a36Sopenharmony_ci u->out_y = u->y; 110362306a36Sopenharmony_ci u->out_width = u->width; 110462306a36Sopenharmony_ci u->out_height = u->height; 110562306a36Sopenharmony_ci memset(u->reserved, 0, sizeof(u->reserved)); 110662306a36Sopenharmony_ci r = omapfb_update_win(fbi, u); 110762306a36Sopenharmony_ci } 110862306a36Sopenharmony_ci break; 110962306a36Sopenharmony_ci case OMAPFB_UPDATE_WINDOW: 111062306a36Sopenharmony_ci if (copy_from_user(&p.update_window, (void __user *)arg, 111162306a36Sopenharmony_ci sizeof(p.update_window))) 111262306a36Sopenharmony_ci r = -EFAULT; 111362306a36Sopenharmony_ci else 111462306a36Sopenharmony_ci r = omapfb_update_win(fbi, &p.update_window); 111562306a36Sopenharmony_ci break; 111662306a36Sopenharmony_ci case OMAPFB_SETUP_PLANE: 111762306a36Sopenharmony_ci if (copy_from_user(&p.plane_info, (void __user *)arg, 111862306a36Sopenharmony_ci sizeof(p.plane_info))) 111962306a36Sopenharmony_ci r = -EFAULT; 112062306a36Sopenharmony_ci else 112162306a36Sopenharmony_ci r = omapfb_setup_plane(fbi, &p.plane_info); 112262306a36Sopenharmony_ci break; 112362306a36Sopenharmony_ci case OMAPFB_QUERY_PLANE: 112462306a36Sopenharmony_ci if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0) 112562306a36Sopenharmony_ci break; 112662306a36Sopenharmony_ci if (copy_to_user((void __user *)arg, &p.plane_info, 112762306a36Sopenharmony_ci sizeof(p.plane_info))) 112862306a36Sopenharmony_ci r = -EFAULT; 112962306a36Sopenharmony_ci break; 113062306a36Sopenharmony_ci case OMAPFB_SETUP_MEM: 113162306a36Sopenharmony_ci if (copy_from_user(&p.mem_info, (void __user *)arg, 113262306a36Sopenharmony_ci sizeof(p.mem_info))) 113362306a36Sopenharmony_ci r = -EFAULT; 113462306a36Sopenharmony_ci else 113562306a36Sopenharmony_ci r = omapfb_setup_mem(fbi, &p.mem_info); 113662306a36Sopenharmony_ci break; 113762306a36Sopenharmony_ci case OMAPFB_QUERY_MEM: 113862306a36Sopenharmony_ci if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0) 113962306a36Sopenharmony_ci break; 114062306a36Sopenharmony_ci if (copy_to_user((void __user *)arg, &p.mem_info, 114162306a36Sopenharmony_ci sizeof(p.mem_info))) 114262306a36Sopenharmony_ci r = -EFAULT; 114362306a36Sopenharmony_ci break; 114462306a36Sopenharmony_ci case OMAPFB_SET_COLOR_KEY: 114562306a36Sopenharmony_ci if (copy_from_user(&p.color_key, (void __user *)arg, 114662306a36Sopenharmony_ci sizeof(p.color_key))) 114762306a36Sopenharmony_ci r = -EFAULT; 114862306a36Sopenharmony_ci else 114962306a36Sopenharmony_ci r = omapfb_set_color_key(fbdev, &p.color_key); 115062306a36Sopenharmony_ci break; 115162306a36Sopenharmony_ci case OMAPFB_GET_COLOR_KEY: 115262306a36Sopenharmony_ci if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0) 115362306a36Sopenharmony_ci break; 115462306a36Sopenharmony_ci if (copy_to_user((void __user *)arg, &p.color_key, 115562306a36Sopenharmony_ci sizeof(p.color_key))) 115662306a36Sopenharmony_ci r = -EFAULT; 115762306a36Sopenharmony_ci break; 115862306a36Sopenharmony_ci case OMAPFB_GET_CAPS: 115962306a36Sopenharmony_ci omapfb_get_caps(fbdev, plane->idx, &p.caps); 116062306a36Sopenharmony_ci if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) 116162306a36Sopenharmony_ci r = -EFAULT; 116262306a36Sopenharmony_ci break; 116362306a36Sopenharmony_ci case OMAPFB_LCD_TEST: 116462306a36Sopenharmony_ci { 116562306a36Sopenharmony_ci int test_num; 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (get_user(test_num, (int __user *)arg)) { 116862306a36Sopenharmony_ci r = -EFAULT; 116962306a36Sopenharmony_ci break; 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci if (!fbdev->panel->run_test) { 117262306a36Sopenharmony_ci r = -EINVAL; 117362306a36Sopenharmony_ci break; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci r = fbdev->panel->run_test(fbdev->panel, test_num); 117662306a36Sopenharmony_ci break; 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci case OMAPFB_CTRL_TEST: 117962306a36Sopenharmony_ci { 118062306a36Sopenharmony_ci int test_num; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (get_user(test_num, (int __user *)arg)) { 118362306a36Sopenharmony_ci r = -EFAULT; 118462306a36Sopenharmony_ci break; 118562306a36Sopenharmony_ci } 118662306a36Sopenharmony_ci if (!fbdev->ctrl->run_test) { 118762306a36Sopenharmony_ci r = -EINVAL; 118862306a36Sopenharmony_ci break; 118962306a36Sopenharmony_ci } 119062306a36Sopenharmony_ci r = fbdev->ctrl->run_test(test_num); 119162306a36Sopenharmony_ci break; 119262306a36Sopenharmony_ci } 119362306a36Sopenharmony_ci default: 119462306a36Sopenharmony_ci r = -EINVAL; 119562306a36Sopenharmony_ci } 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_ci return r; 119862306a36Sopenharmony_ci} 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_cistatic int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci struct omapfb_plane_struct *plane = info->par; 120362306a36Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 120462306a36Sopenharmony_ci int r; 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci omapfb_rqueue_lock(fbdev); 120762306a36Sopenharmony_ci r = fbdev->ctrl->mmap(info, vma); 120862306a36Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci return r; 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci/* 121462306a36Sopenharmony_ci * Callback table for the frame buffer framework. Some of these pointers 121562306a36Sopenharmony_ci * will be changed according to the current setting of fb_info->accel_flags. 121662306a36Sopenharmony_ci */ 121762306a36Sopenharmony_cistatic struct fb_ops omapfb_ops = { 121862306a36Sopenharmony_ci .owner = THIS_MODULE, 121962306a36Sopenharmony_ci FB_DEFAULT_IOMEM_OPS, 122062306a36Sopenharmony_ci .fb_open = omapfb_open, 122162306a36Sopenharmony_ci .fb_release = omapfb_release, 122262306a36Sopenharmony_ci .fb_setcolreg = omapfb_setcolreg, 122362306a36Sopenharmony_ci .fb_setcmap = omapfb_setcmap, 122462306a36Sopenharmony_ci .fb_blank = omapfb_blank, 122562306a36Sopenharmony_ci .fb_ioctl = omapfb_ioctl, 122662306a36Sopenharmony_ci .fb_check_var = omapfb_check_var, 122762306a36Sopenharmony_ci .fb_set_par = omapfb_set_par, 122862306a36Sopenharmony_ci .fb_pan_display = omapfb_pan_display, 122962306a36Sopenharmony_ci}; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci/* 123262306a36Sopenharmony_ci * --------------------------------------------------------------------------- 123362306a36Sopenharmony_ci * Sysfs interface 123462306a36Sopenharmony_ci * --------------------------------------------------------------------------- 123562306a36Sopenharmony_ci */ 123662306a36Sopenharmony_ci/* omapfbX sysfs entries */ 123762306a36Sopenharmony_cistatic ssize_t omapfb_show_caps_num(struct device *dev, 123862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 124162306a36Sopenharmony_ci int plane; 124262306a36Sopenharmony_ci size_t size; 124362306a36Sopenharmony_ci struct omapfb_caps caps; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci plane = 0; 124662306a36Sopenharmony_ci size = 0; 124762306a36Sopenharmony_ci while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { 124862306a36Sopenharmony_ci omapfb_get_caps(fbdev, plane, &caps); 124962306a36Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 125062306a36Sopenharmony_ci "plane#%d %#010x %#010x %#010x\n", 125162306a36Sopenharmony_ci plane, caps.ctrl, caps.plane_color, caps.wnd_color); 125262306a36Sopenharmony_ci plane++; 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci return size; 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_cistatic ssize_t omapfb_show_caps_text(struct device *dev, 125862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 126162306a36Sopenharmony_ci int i; 126262306a36Sopenharmony_ci struct omapfb_caps caps; 126362306a36Sopenharmony_ci int plane; 126462306a36Sopenharmony_ci size_t size; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci plane = 0; 126762306a36Sopenharmony_ci size = 0; 126862306a36Sopenharmony_ci while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { 126962306a36Sopenharmony_ci omapfb_get_caps(fbdev, plane, &caps); 127062306a36Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 127162306a36Sopenharmony_ci "plane#%d:\n", plane); 127262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ctrl_caps) && 127362306a36Sopenharmony_ci size < PAGE_SIZE; i++) { 127462306a36Sopenharmony_ci if (ctrl_caps[i].flag & caps.ctrl) 127562306a36Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 127662306a36Sopenharmony_ci " %s\n", ctrl_caps[i].name); 127762306a36Sopenharmony_ci } 127862306a36Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 127962306a36Sopenharmony_ci " plane colors:\n"); 128062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(color_caps) && 128162306a36Sopenharmony_ci size < PAGE_SIZE; i++) { 128262306a36Sopenharmony_ci if (color_caps[i].flag & caps.plane_color) 128362306a36Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 128462306a36Sopenharmony_ci " %s\n", color_caps[i].name); 128562306a36Sopenharmony_ci } 128662306a36Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 128762306a36Sopenharmony_ci " window colors:\n"); 128862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(color_caps) && 128962306a36Sopenharmony_ci size < PAGE_SIZE; i++) { 129062306a36Sopenharmony_ci if (color_caps[i].flag & caps.wnd_color) 129162306a36Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 129262306a36Sopenharmony_ci " %s\n", color_caps[i].name); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci plane++; 129662306a36Sopenharmony_ci } 129762306a36Sopenharmony_ci return size; 129862306a36Sopenharmony_ci} 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_cistatic DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL); 130162306a36Sopenharmony_cistatic DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci/* panel sysfs entries */ 130462306a36Sopenharmony_cistatic ssize_t omapfb_show_panel_name(struct device *dev, 130562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 130662306a36Sopenharmony_ci{ 130762306a36Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", fbdev->panel->name); 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_cistatic ssize_t omapfb_show_bklight_level(struct device *dev, 131362306a36Sopenharmony_ci struct device_attribute *attr, 131462306a36Sopenharmony_ci char *buf) 131562306a36Sopenharmony_ci{ 131662306a36Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 131762306a36Sopenharmony_ci int r; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci if (fbdev->panel->get_bklight_level) { 132062306a36Sopenharmony_ci r = sysfs_emit(buf, "%d\n", 132162306a36Sopenharmony_ci fbdev->panel->get_bklight_level(fbdev->panel)); 132262306a36Sopenharmony_ci } else 132362306a36Sopenharmony_ci r = -ENODEV; 132462306a36Sopenharmony_ci return r; 132562306a36Sopenharmony_ci} 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_cistatic ssize_t omapfb_store_bklight_level(struct device *dev, 132862306a36Sopenharmony_ci struct device_attribute *attr, 132962306a36Sopenharmony_ci const char *buf, size_t size) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 133262306a36Sopenharmony_ci int r; 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci if (fbdev->panel->set_bklight_level) { 133562306a36Sopenharmony_ci unsigned int level; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci if (sscanf(buf, "%10d", &level) == 1) { 133862306a36Sopenharmony_ci r = fbdev->panel->set_bklight_level(fbdev->panel, 133962306a36Sopenharmony_ci level); 134062306a36Sopenharmony_ci } else 134162306a36Sopenharmony_ci r = -EINVAL; 134262306a36Sopenharmony_ci } else 134362306a36Sopenharmony_ci r = -ENODEV; 134462306a36Sopenharmony_ci return r ? r : size; 134562306a36Sopenharmony_ci} 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_cistatic ssize_t omapfb_show_bklight_max(struct device *dev, 134862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 134962306a36Sopenharmony_ci{ 135062306a36Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 135162306a36Sopenharmony_ci int r; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (fbdev->panel->get_bklight_level) { 135462306a36Sopenharmony_ci r = sysfs_emit(buf, "%d\n", 135562306a36Sopenharmony_ci fbdev->panel->get_bklight_max(fbdev->panel)); 135662306a36Sopenharmony_ci } else 135762306a36Sopenharmony_ci r = -ENODEV; 135862306a36Sopenharmony_ci return r; 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_cistatic struct device_attribute dev_attr_panel_name = 136262306a36Sopenharmony_ci __ATTR(name, 0444, omapfb_show_panel_name, NULL); 136362306a36Sopenharmony_cistatic DEVICE_ATTR(backlight_level, 0664, 136462306a36Sopenharmony_ci omapfb_show_bklight_level, omapfb_store_bklight_level); 136562306a36Sopenharmony_cistatic DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_cistatic struct attribute *panel_attrs[] = { 136862306a36Sopenharmony_ci &dev_attr_panel_name.attr, 136962306a36Sopenharmony_ci &dev_attr_backlight_level.attr, 137062306a36Sopenharmony_ci &dev_attr_backlight_max.attr, 137162306a36Sopenharmony_ci NULL, 137262306a36Sopenharmony_ci}; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_cistatic const struct attribute_group panel_attr_grp = { 137562306a36Sopenharmony_ci .name = "panel", 137662306a36Sopenharmony_ci .attrs = panel_attrs, 137762306a36Sopenharmony_ci}; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci/* ctrl sysfs entries */ 138062306a36Sopenharmony_cistatic ssize_t omapfb_show_ctrl_name(struct device *dev, 138162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 138262306a36Sopenharmony_ci{ 138362306a36Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", fbdev->ctrl->name); 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_cistatic struct device_attribute dev_attr_ctrl_name = 138962306a36Sopenharmony_ci __ATTR(name, 0444, omapfb_show_ctrl_name, NULL); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistatic struct attribute *ctrl_attrs[] = { 139262306a36Sopenharmony_ci &dev_attr_ctrl_name.attr, 139362306a36Sopenharmony_ci NULL, 139462306a36Sopenharmony_ci}; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cistatic const struct attribute_group ctrl_attr_grp = { 139762306a36Sopenharmony_ci .name = "ctrl", 139862306a36Sopenharmony_ci .attrs = ctrl_attrs, 139962306a36Sopenharmony_ci}; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_cistatic int omapfb_register_sysfs(struct omapfb_device *fbdev) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci int r; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num))) 140662306a36Sopenharmony_ci goto fail0; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text))) 140962306a36Sopenharmony_ci goto fail1; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp))) 141262306a36Sopenharmony_ci goto fail2; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp))) 141562306a36Sopenharmony_ci goto fail3; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci return 0; 141862306a36Sopenharmony_cifail3: 141962306a36Sopenharmony_ci sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); 142062306a36Sopenharmony_cifail2: 142162306a36Sopenharmony_ci device_remove_file(fbdev->dev, &dev_attr_caps_text); 142262306a36Sopenharmony_cifail1: 142362306a36Sopenharmony_ci device_remove_file(fbdev->dev, &dev_attr_caps_num); 142462306a36Sopenharmony_cifail0: 142562306a36Sopenharmony_ci dev_err(fbdev->dev, "unable to register sysfs interface\n"); 142662306a36Sopenharmony_ci return r; 142762306a36Sopenharmony_ci} 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_cistatic void omapfb_unregister_sysfs(struct omapfb_device *fbdev) 143062306a36Sopenharmony_ci{ 143162306a36Sopenharmony_ci sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp); 143262306a36Sopenharmony_ci sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); 143362306a36Sopenharmony_ci device_remove_file(fbdev->dev, &dev_attr_caps_num); 143462306a36Sopenharmony_ci device_remove_file(fbdev->dev, &dev_attr_caps_text); 143562306a36Sopenharmony_ci} 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci/* 143862306a36Sopenharmony_ci * --------------------------------------------------------------------------- 143962306a36Sopenharmony_ci * LDM callbacks 144062306a36Sopenharmony_ci * --------------------------------------------------------------------------- 144162306a36Sopenharmony_ci */ 144262306a36Sopenharmony_ci/* Initialize system fb_info object and set the default video mode. 144362306a36Sopenharmony_ci * The frame buffer memory already allocated by lcddma_init 144462306a36Sopenharmony_ci */ 144562306a36Sopenharmony_cistatic int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci struct fb_var_screeninfo *var = &info->var; 144862306a36Sopenharmony_ci struct fb_fix_screeninfo *fix = &info->fix; 144962306a36Sopenharmony_ci int r = 0; 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci info->fbops = &omapfb_ops; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci strscpy(fix->id, MODULE_NAME, sizeof(fix->id)); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci info->pseudo_palette = fbdev->pseudo_palette; 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0; 145862306a36Sopenharmony_ci var->xres = def_vxres; 145962306a36Sopenharmony_ci var->yres = def_vyres; 146062306a36Sopenharmony_ci var->xres_virtual = def_vxres; 146162306a36Sopenharmony_ci var->yres_virtual = def_vyres; 146262306a36Sopenharmony_ci var->rotate = def_rotate; 146362306a36Sopenharmony_ci var->bits_per_pixel = fbdev->panel->bpp; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci set_fb_var(info, var); 146662306a36Sopenharmony_ci set_fb_fix(info, 1); 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci r = fb_alloc_cmap(&info->cmap, 16, 0); 146962306a36Sopenharmony_ci if (r != 0) 147062306a36Sopenharmony_ci dev_err(fbdev->dev, "unable to allocate color map memory\n"); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci return r; 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_ci/* Release the fb_info object */ 147662306a36Sopenharmony_cistatic void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci fb_dealloc_cmap(&fbi->cmap); 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_cistatic void planes_cleanup(struct omapfb_device *fbdev) 148262306a36Sopenharmony_ci{ 148362306a36Sopenharmony_ci int i; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 148662306a36Sopenharmony_ci if (fbdev->fb_info[i] == NULL) 148762306a36Sopenharmony_ci break; 148862306a36Sopenharmony_ci fbinfo_cleanup(fbdev, fbdev->fb_info[i]); 148962306a36Sopenharmony_ci framebuffer_release(fbdev->fb_info[i]); 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci} 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_cistatic int planes_init(struct omapfb_device *fbdev) 149462306a36Sopenharmony_ci{ 149562306a36Sopenharmony_ci struct fb_info *fbi; 149662306a36Sopenharmony_ci int i; 149762306a36Sopenharmony_ci int r; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 150062306a36Sopenharmony_ci struct omapfb_plane_struct *plane; 150162306a36Sopenharmony_ci fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct), 150262306a36Sopenharmony_ci fbdev->dev); 150362306a36Sopenharmony_ci if (fbi == NULL) { 150462306a36Sopenharmony_ci planes_cleanup(fbdev); 150562306a36Sopenharmony_ci return -ENOMEM; 150662306a36Sopenharmony_ci } 150762306a36Sopenharmony_ci plane = fbi->par; 150862306a36Sopenharmony_ci plane->idx = i; 150962306a36Sopenharmony_ci plane->fbdev = fbdev; 151062306a36Sopenharmony_ci plane->info.mirror = def_mirror; 151162306a36Sopenharmony_ci fbdev->fb_info[i] = fbi; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci if ((r = fbinfo_init(fbdev, fbi)) < 0) { 151462306a36Sopenharmony_ci framebuffer_release(fbi); 151562306a36Sopenharmony_ci planes_cleanup(fbdev); 151662306a36Sopenharmony_ci return r; 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci plane->info.out_width = fbi->var.xres; 151962306a36Sopenharmony_ci plane->info.out_height = fbi->var.yres; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci return 0; 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci/* 152562306a36Sopenharmony_ci * Free driver resources. Can be called to rollback an aborted initialization 152662306a36Sopenharmony_ci * sequence. 152762306a36Sopenharmony_ci */ 152862306a36Sopenharmony_cistatic void omapfb_free_resources(struct omapfb_device *fbdev, int state) 152962306a36Sopenharmony_ci{ 153062306a36Sopenharmony_ci int i; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci switch (state) { 153362306a36Sopenharmony_ci case OMAPFB_ACTIVE: 153462306a36Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) 153562306a36Sopenharmony_ci unregister_framebuffer(fbdev->fb_info[i]); 153662306a36Sopenharmony_ci fallthrough; 153762306a36Sopenharmony_ci case 7: 153862306a36Sopenharmony_ci omapfb_unregister_sysfs(fbdev); 153962306a36Sopenharmony_ci fallthrough; 154062306a36Sopenharmony_ci case 6: 154162306a36Sopenharmony_ci if (fbdev->panel->disable) 154262306a36Sopenharmony_ci fbdev->panel->disable(fbdev->panel); 154362306a36Sopenharmony_ci fallthrough; 154462306a36Sopenharmony_ci case 5: 154562306a36Sopenharmony_ci omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED); 154662306a36Sopenharmony_ci fallthrough; 154762306a36Sopenharmony_ci case 4: 154862306a36Sopenharmony_ci planes_cleanup(fbdev); 154962306a36Sopenharmony_ci fallthrough; 155062306a36Sopenharmony_ci case 3: 155162306a36Sopenharmony_ci ctrl_cleanup(fbdev); 155262306a36Sopenharmony_ci fallthrough; 155362306a36Sopenharmony_ci case 2: 155462306a36Sopenharmony_ci if (fbdev->panel->cleanup) 155562306a36Sopenharmony_ci fbdev->panel->cleanup(fbdev->panel); 155662306a36Sopenharmony_ci fallthrough; 155762306a36Sopenharmony_ci case 1: 155862306a36Sopenharmony_ci dev_set_drvdata(fbdev->dev, NULL); 155962306a36Sopenharmony_ci kfree(fbdev); 156062306a36Sopenharmony_ci break; 156162306a36Sopenharmony_ci case 0: 156262306a36Sopenharmony_ci /* nothing to free */ 156362306a36Sopenharmony_ci break; 156462306a36Sopenharmony_ci default: 156562306a36Sopenharmony_ci BUG(); 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic int omapfb_find_ctrl(struct omapfb_device *fbdev) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci struct omapfb_platform_data *conf; 157262306a36Sopenharmony_ci char name[17]; 157362306a36Sopenharmony_ci int i; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci conf = dev_get_platdata(fbdev->dev); 157662306a36Sopenharmony_ci 157762306a36Sopenharmony_ci fbdev->ctrl = NULL; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci strscpy(name, conf->lcd.ctrl_name, sizeof(name)); 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci if (strcmp(name, "internal") == 0) { 158262306a36Sopenharmony_ci fbdev->ctrl = fbdev->int_ctrl; 158362306a36Sopenharmony_ci return 0; 158462306a36Sopenharmony_ci } 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ctrls); i++) { 158762306a36Sopenharmony_ci dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name); 158862306a36Sopenharmony_ci if (strcmp(ctrls[i]->name, name) == 0) { 158962306a36Sopenharmony_ci fbdev->ctrl = ctrls[i]; 159062306a36Sopenharmony_ci break; 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci } 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_ci if (fbdev->ctrl == NULL) { 159562306a36Sopenharmony_ci dev_dbg(fbdev->dev, "ctrl %s not supported\n", name); 159662306a36Sopenharmony_ci return -1; 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci return 0; 160062306a36Sopenharmony_ci} 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci/* 160362306a36Sopenharmony_ci * Called by LDM binding to probe and attach a new device. 160462306a36Sopenharmony_ci * Initialization sequence: 160562306a36Sopenharmony_ci * 1. allocate system omapfb_device structure 160662306a36Sopenharmony_ci * 2. select controller type according to platform configuration 160762306a36Sopenharmony_ci * init LCD panel 160862306a36Sopenharmony_ci * 3. init LCD controller and LCD DMA 160962306a36Sopenharmony_ci * 4. init system fb_info structure for all planes 161062306a36Sopenharmony_ci * 5. setup video mode for first plane and enable it 161162306a36Sopenharmony_ci * 6. enable LCD panel 161262306a36Sopenharmony_ci * 7. register sysfs attributes 161362306a36Sopenharmony_ci * OMAPFB_ACTIVE: register system fb_info structure for all planes 161462306a36Sopenharmony_ci */ 161562306a36Sopenharmony_cistatic int omapfb_do_probe(struct platform_device *pdev, 161662306a36Sopenharmony_ci struct lcd_panel *panel) 161762306a36Sopenharmony_ci{ 161862306a36Sopenharmony_ci struct omapfb_device *fbdev = NULL; 161962306a36Sopenharmony_ci int init_state; 162062306a36Sopenharmony_ci unsigned long phz, hhz, vhz; 162162306a36Sopenharmony_ci unsigned long vram; 162262306a36Sopenharmony_ci int i; 162362306a36Sopenharmony_ci int r = 0; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci init_state = 0; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci if (pdev->num_resources != 2) { 162862306a36Sopenharmony_ci dev_err(&pdev->dev, "probed for an unknown device\n"); 162962306a36Sopenharmony_ci r = -ENODEV; 163062306a36Sopenharmony_ci goto cleanup; 163162306a36Sopenharmony_ci } 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci if (dev_get_platdata(&pdev->dev) == NULL) { 163462306a36Sopenharmony_ci dev_err(&pdev->dev, "missing platform data\n"); 163562306a36Sopenharmony_ci r = -ENOENT; 163662306a36Sopenharmony_ci goto cleanup; 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); 164062306a36Sopenharmony_ci if (fbdev == NULL) { 164162306a36Sopenharmony_ci dev_err(&pdev->dev, 164262306a36Sopenharmony_ci "unable to allocate memory for device info\n"); 164362306a36Sopenharmony_ci r = -ENOMEM; 164462306a36Sopenharmony_ci goto cleanup; 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci fbdev->int_irq = platform_get_irq(pdev, 0); 164762306a36Sopenharmony_ci if (fbdev->int_irq < 0) { 164862306a36Sopenharmony_ci r = -ENXIO; 164962306a36Sopenharmony_ci goto cleanup; 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci fbdev->ext_irq = platform_get_irq(pdev, 1); 165362306a36Sopenharmony_ci if (fbdev->ext_irq < 0) { 165462306a36Sopenharmony_ci r = -ENXIO; 165562306a36Sopenharmony_ci goto cleanup; 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci init_state++; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci fbdev->dev = &pdev->dev; 166162306a36Sopenharmony_ci fbdev->panel = panel; 166262306a36Sopenharmony_ci fbdev->dssdev = &omapdss_device; 166362306a36Sopenharmony_ci platform_set_drvdata(pdev, fbdev); 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci mutex_init(&fbdev->rqueue_mutex); 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci fbdev->int_ctrl = &omap1_int_ctrl; 166862306a36Sopenharmony_ci#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL 166962306a36Sopenharmony_ci fbdev->ext_if = &omap1_ext_if; 167062306a36Sopenharmony_ci#endif 167162306a36Sopenharmony_ci if (omapfb_find_ctrl(fbdev) < 0) { 167262306a36Sopenharmony_ci dev_err(fbdev->dev, 167362306a36Sopenharmony_ci "LCD controller not found, board not supported\n"); 167462306a36Sopenharmony_ci r = -ENODEV; 167562306a36Sopenharmony_ci goto cleanup; 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci if (fbdev->panel->init) { 167962306a36Sopenharmony_ci r = fbdev->panel->init(fbdev->panel, fbdev); 168062306a36Sopenharmony_ci if (r) 168162306a36Sopenharmony_ci goto cleanup; 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci pr_info("omapfb: configured for panel %s\n", fbdev->panel->name); 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci def_vxres = def_vxres ? def_vxres : fbdev->panel->x_res; 168762306a36Sopenharmony_ci def_vyres = def_vyres ? def_vyres : fbdev->panel->y_res; 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci init_state++; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci r = ctrl_init(fbdev); 169262306a36Sopenharmony_ci if (r) 169362306a36Sopenharmony_ci goto cleanup; 169462306a36Sopenharmony_ci if (fbdev->ctrl->mmap != NULL) 169562306a36Sopenharmony_ci omapfb_ops.fb_mmap = omapfb_mmap; 169662306a36Sopenharmony_ci init_state++; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci r = planes_init(fbdev); 169962306a36Sopenharmony_ci if (r) 170062306a36Sopenharmony_ci goto cleanup; 170162306a36Sopenharmony_ci init_state++; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci#ifdef CONFIG_FB_OMAP_DMA_TUNE 170462306a36Sopenharmony_ci /* Set DMA priority for EMIFF access to highest */ 170562306a36Sopenharmony_ci omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15); 170662306a36Sopenharmony_ci#endif 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci r = ctrl_change_mode(fbdev->fb_info[0]); 170962306a36Sopenharmony_ci if (r) { 171062306a36Sopenharmony_ci dev_err(fbdev->dev, "mode setting failed\n"); 171162306a36Sopenharmony_ci goto cleanup; 171262306a36Sopenharmony_ci } 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci /* GFX plane is enabled by default */ 171562306a36Sopenharmony_ci r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); 171662306a36Sopenharmony_ci if (r) 171762306a36Sopenharmony_ci goto cleanup; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci omapfb_set_update_mode(fbdev, manual_update ? 172062306a36Sopenharmony_ci OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE); 172162306a36Sopenharmony_ci init_state++; 172262306a36Sopenharmony_ci 172362306a36Sopenharmony_ci if (fbdev->panel->enable) { 172462306a36Sopenharmony_ci r = fbdev->panel->enable(fbdev->panel); 172562306a36Sopenharmony_ci if (r) 172662306a36Sopenharmony_ci goto cleanup; 172762306a36Sopenharmony_ci } 172862306a36Sopenharmony_ci init_state++; 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci r = omapfb_register_sysfs(fbdev); 173162306a36Sopenharmony_ci if (r) 173262306a36Sopenharmony_ci goto cleanup; 173362306a36Sopenharmony_ci init_state++; 173462306a36Sopenharmony_ci 173562306a36Sopenharmony_ci vram = 0; 173662306a36Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 173762306a36Sopenharmony_ci r = register_framebuffer(fbdev->fb_info[i]); 173862306a36Sopenharmony_ci if (r != 0) { 173962306a36Sopenharmony_ci dev_err(fbdev->dev, 174062306a36Sopenharmony_ci "registering framebuffer %d failed\n", i); 174162306a36Sopenharmony_ci goto cleanup; 174262306a36Sopenharmony_ci } 174362306a36Sopenharmony_ci vram += fbdev->mem_desc.region[i].size; 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci fbdev->state = OMAPFB_ACTIVE; 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci panel = fbdev->panel; 174962306a36Sopenharmony_ci phz = panel->pixel_clock * 1000; 175062306a36Sopenharmony_ci hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw); 175162306a36Sopenharmony_ci vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw); 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci omapfb_dev = fbdev; 175462306a36Sopenharmony_ci 175562306a36Sopenharmony_ci pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n", 175662306a36Sopenharmony_ci vram, fbdev->mem_desc.region_cnt); 175762306a36Sopenharmony_ci pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz " 175862306a36Sopenharmony_ci "vfreq %lu.%lu Hz\n", 175962306a36Sopenharmony_ci phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10); 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci return 0; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_cicleanup: 176462306a36Sopenharmony_ci omapfb_free_resources(fbdev, init_state); 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci return r; 176762306a36Sopenharmony_ci} 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_cistatic int omapfb_probe(struct platform_device *pdev) 177062306a36Sopenharmony_ci{ 177162306a36Sopenharmony_ci int r; 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci BUG_ON(fbdev_pdev != NULL); 177462306a36Sopenharmony_ci 177562306a36Sopenharmony_ci r = platform_device_register(&omapdss_device); 177662306a36Sopenharmony_ci if (r) { 177762306a36Sopenharmony_ci dev_err(&pdev->dev, "can't register omapdss device\n"); 177862306a36Sopenharmony_ci return r; 177962306a36Sopenharmony_ci } 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci /* Delay actual initialization until the LCD is registered */ 178262306a36Sopenharmony_ci fbdev_pdev = pdev; 178362306a36Sopenharmony_ci if (fbdev_panel != NULL) 178462306a36Sopenharmony_ci omapfb_do_probe(fbdev_pdev, fbdev_panel); 178562306a36Sopenharmony_ci return 0; 178662306a36Sopenharmony_ci} 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_civoid omapfb_register_panel(struct lcd_panel *panel) 178962306a36Sopenharmony_ci{ 179062306a36Sopenharmony_ci BUG_ON(fbdev_panel != NULL); 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci fbdev_panel = panel; 179362306a36Sopenharmony_ci if (fbdev_pdev != NULL) 179462306a36Sopenharmony_ci omapfb_do_probe(fbdev_pdev, fbdev_panel); 179562306a36Sopenharmony_ci} 179662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(omapfb_register_panel); 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci/* Called when the device is being detached from the driver */ 179962306a36Sopenharmony_cistatic void omapfb_remove(struct platform_device *pdev) 180062306a36Sopenharmony_ci{ 180162306a36Sopenharmony_ci struct omapfb_device *fbdev = platform_get_drvdata(pdev); 180262306a36Sopenharmony_ci enum omapfb_state saved_state = fbdev->state; 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci /* FIXME: wait till completion of pending events */ 180562306a36Sopenharmony_ci 180662306a36Sopenharmony_ci fbdev->state = OMAPFB_DISABLED; 180762306a36Sopenharmony_ci omapfb_free_resources(fbdev, saved_state); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci platform_device_unregister(&omapdss_device); 181062306a36Sopenharmony_ci fbdev->dssdev = NULL; 181162306a36Sopenharmony_ci} 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci/* PM suspend */ 181462306a36Sopenharmony_cistatic int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg) 181562306a36Sopenharmony_ci{ 181662306a36Sopenharmony_ci struct omapfb_device *fbdev = platform_get_drvdata(pdev); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci if (fbdev != NULL) 181962306a36Sopenharmony_ci omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]); 182062306a36Sopenharmony_ci return 0; 182162306a36Sopenharmony_ci} 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci/* PM resume */ 182462306a36Sopenharmony_cistatic int omapfb_resume(struct platform_device *pdev) 182562306a36Sopenharmony_ci{ 182662306a36Sopenharmony_ci struct omapfb_device *fbdev = platform_get_drvdata(pdev); 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci if (fbdev != NULL) 182962306a36Sopenharmony_ci omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]); 183062306a36Sopenharmony_ci return 0; 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_cistatic struct platform_driver omapfb_driver = { 183462306a36Sopenharmony_ci .probe = omapfb_probe, 183562306a36Sopenharmony_ci .remove_new = omapfb_remove, 183662306a36Sopenharmony_ci .suspend = omapfb_suspend, 183762306a36Sopenharmony_ci .resume = omapfb_resume, 183862306a36Sopenharmony_ci .driver = { 183962306a36Sopenharmony_ci .name = MODULE_NAME, 184062306a36Sopenharmony_ci }, 184162306a36Sopenharmony_ci}; 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci#ifndef MODULE 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci/* Process kernel command line parameters */ 184662306a36Sopenharmony_cistatic int __init omapfb_setup(char *options) 184762306a36Sopenharmony_ci{ 184862306a36Sopenharmony_ci char *this_opt = NULL; 184962306a36Sopenharmony_ci int r = 0; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci pr_debug("omapfb: options %s\n", options); 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci if (!options || !*options) 185462306a36Sopenharmony_ci return 0; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci while (!r && (this_opt = strsep(&options, ",")) != NULL) { 185762306a36Sopenharmony_ci if (!strncmp(this_opt, "accel", 5)) 185862306a36Sopenharmony_ci def_accel = 1; 185962306a36Sopenharmony_ci else if (!strncmp(this_opt, "vram:", 5)) { 186062306a36Sopenharmony_ci char *suffix; 186162306a36Sopenharmony_ci unsigned long vram; 186262306a36Sopenharmony_ci vram = (simple_strtoul(this_opt + 5, &suffix, 0)); 186362306a36Sopenharmony_ci switch (suffix[0]) { 186462306a36Sopenharmony_ci case '\0': 186562306a36Sopenharmony_ci break; 186662306a36Sopenharmony_ci case 'm': 186762306a36Sopenharmony_ci case 'M': 186862306a36Sopenharmony_ci vram *= 1024; 186962306a36Sopenharmony_ci fallthrough; 187062306a36Sopenharmony_ci case 'k': 187162306a36Sopenharmony_ci case 'K': 187262306a36Sopenharmony_ci vram *= 1024; 187362306a36Sopenharmony_ci break; 187462306a36Sopenharmony_ci default: 187562306a36Sopenharmony_ci pr_debug("omapfb: invalid vram suffix %c\n", 187662306a36Sopenharmony_ci suffix[0]); 187762306a36Sopenharmony_ci r = -1; 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci def_vram[def_vram_cnt++] = vram; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci else if (!strncmp(this_opt, "vxres:", 6)) 188262306a36Sopenharmony_ci def_vxres = simple_strtoul(this_opt + 6, NULL, 0); 188362306a36Sopenharmony_ci else if (!strncmp(this_opt, "vyres:", 6)) 188462306a36Sopenharmony_ci def_vyres = simple_strtoul(this_opt + 6, NULL, 0); 188562306a36Sopenharmony_ci else if (!strncmp(this_opt, "rotate:", 7)) 188662306a36Sopenharmony_ci def_rotate = (simple_strtoul(this_opt + 7, NULL, 0)); 188762306a36Sopenharmony_ci else if (!strncmp(this_opt, "mirror:", 7)) 188862306a36Sopenharmony_ci def_mirror = (simple_strtoul(this_opt + 7, NULL, 0)); 188962306a36Sopenharmony_ci else if (!strncmp(this_opt, "manual_update", 13)) 189062306a36Sopenharmony_ci manual_update = 1; 189162306a36Sopenharmony_ci else { 189262306a36Sopenharmony_ci pr_debug("omapfb: invalid option\n"); 189362306a36Sopenharmony_ci r = -1; 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci return r; 189862306a36Sopenharmony_ci} 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci#endif 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci/* Register both the driver and the device */ 190362306a36Sopenharmony_cistatic int __init omapfb_init(void) 190462306a36Sopenharmony_ci{ 190562306a36Sopenharmony_ci#ifndef MODULE 190662306a36Sopenharmony_ci char *option; 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci if (fb_get_options("omapfb", &option)) 190962306a36Sopenharmony_ci return -ENODEV; 191062306a36Sopenharmony_ci omapfb_setup(option); 191162306a36Sopenharmony_ci#endif 191262306a36Sopenharmony_ci /* Register the driver with LDM */ 191362306a36Sopenharmony_ci if (platform_driver_register(&omapfb_driver)) { 191462306a36Sopenharmony_ci pr_debug("failed to register omapfb driver\n"); 191562306a36Sopenharmony_ci return -ENODEV; 191662306a36Sopenharmony_ci } 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci return 0; 191962306a36Sopenharmony_ci} 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_cistatic void __exit omapfb_cleanup(void) 192262306a36Sopenharmony_ci{ 192362306a36Sopenharmony_ci platform_driver_unregister(&omapfb_driver); 192462306a36Sopenharmony_ci} 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_cimodule_param_named(accel, def_accel, uint, 0664); 192762306a36Sopenharmony_cimodule_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664); 192862306a36Sopenharmony_cimodule_param_named(vxres, def_vxres, long, 0664); 192962306a36Sopenharmony_cimodule_param_named(vyres, def_vyres, long, 0664); 193062306a36Sopenharmony_cimodule_param_named(rotate, def_rotate, uint, 0664); 193162306a36Sopenharmony_cimodule_param_named(mirror, def_mirror, uint, 0664); 193262306a36Sopenharmony_cimodule_param_named(manual_update, manual_update, bool, 0664); 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_cimodule_init(omapfb_init); 193562306a36Sopenharmony_cimodule_exit(omapfb_cleanup); 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ciMODULE_DESCRIPTION("TI OMAP framebuffer driver"); 193862306a36Sopenharmony_ciMODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>"); 193962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1940