18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Framebuffer driver for TI OMAP boards 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2004 Nokia Corporation 68c2ecf20Sopenharmony_ci * Author: Imre Deak <imre.deak@nokia.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Acknowledgements: 98c2ecf20Sopenharmony_ci * Alex McMains <aam@ridgerun.com> - Original driver 108c2ecf20Sopenharmony_ci * Juha Yrjola <juha.yrjola@nokia.com> - Original driver and improvements 118c2ecf20Sopenharmony_ci * Dirk Behme <dirk.behme@de.bosch.com> - changes for 2.6 kernel API 128c2ecf20Sopenharmony_ci * Texas Instruments - H3 support 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/mm.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <linux/omap-dma.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <mach/hardware.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "omapfb.h" 258c2ecf20Sopenharmony_ci#include "lcdc.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define MODULE_NAME "omapfb" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic unsigned int def_accel; 308c2ecf20Sopenharmony_cistatic unsigned long def_vram[OMAPFB_PLANE_NUM]; 318c2ecf20Sopenharmony_cistatic unsigned int def_vram_cnt; 328c2ecf20Sopenharmony_cistatic unsigned long def_vxres; 338c2ecf20Sopenharmony_cistatic unsigned long def_vyres; 348c2ecf20Sopenharmony_cistatic unsigned int def_rotate; 358c2ecf20Sopenharmony_cistatic unsigned int def_mirror; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic bool manual_update = IS_BUILTIN(CONFIG_FB_OMAP_MANUAL_UPDATE); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic struct platform_device *fbdev_pdev; 408c2ecf20Sopenharmony_cistatic struct lcd_panel *fbdev_panel; 418c2ecf20Sopenharmony_cistatic struct omapfb_device *omapfb_dev; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct caps_table_struct { 448c2ecf20Sopenharmony_ci unsigned long flag; 458c2ecf20Sopenharmony_ci const char *name; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic const struct caps_table_struct ctrl_caps[] = { 498c2ecf20Sopenharmony_ci { OMAPFB_CAPS_MANUAL_UPDATE, "manual update" }, 508c2ecf20Sopenharmony_ci { OMAPFB_CAPS_TEARSYNC, "tearing synchronization" }, 518c2ecf20Sopenharmony_ci { OMAPFB_CAPS_PLANE_RELOCATE_MEM, "relocate plane memory" }, 528c2ecf20Sopenharmony_ci { OMAPFB_CAPS_PLANE_SCALE, "scale plane" }, 538c2ecf20Sopenharmony_ci { OMAPFB_CAPS_WINDOW_PIXEL_DOUBLE, "pixel double window" }, 548c2ecf20Sopenharmony_ci { OMAPFB_CAPS_WINDOW_SCALE, "scale window" }, 558c2ecf20Sopenharmony_ci { OMAPFB_CAPS_WINDOW_OVERLAY, "overlay window" }, 568c2ecf20Sopenharmony_ci { OMAPFB_CAPS_WINDOW_ROTATE, "rotate window" }, 578c2ecf20Sopenharmony_ci { OMAPFB_CAPS_SET_BACKLIGHT, "backlight setting" }, 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic const struct caps_table_struct color_caps[] = { 618c2ecf20Sopenharmony_ci { 1 << OMAPFB_COLOR_RGB565, "RGB565", }, 628c2ecf20Sopenharmony_ci { 1 << OMAPFB_COLOR_YUV422, "YUV422", }, 638c2ecf20Sopenharmony_ci { 1 << OMAPFB_COLOR_YUV420, "YUV420", }, 648c2ecf20Sopenharmony_ci { 1 << OMAPFB_COLOR_CLUT_8BPP, "CLUT8", }, 658c2ecf20Sopenharmony_ci { 1 << OMAPFB_COLOR_CLUT_4BPP, "CLUT4", }, 668c2ecf20Sopenharmony_ci { 1 << OMAPFB_COLOR_CLUT_2BPP, "CLUT2", }, 678c2ecf20Sopenharmony_ci { 1 << OMAPFB_COLOR_CLUT_1BPP, "CLUT1", }, 688c2ecf20Sopenharmony_ci { 1 << OMAPFB_COLOR_RGB444, "RGB444", }, 698c2ecf20Sopenharmony_ci { 1 << OMAPFB_COLOR_YUY422, "YUY422", }, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic void omapdss_release(struct device *dev) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* dummy device for clocks */ 778c2ecf20Sopenharmony_cistatic struct platform_device omapdss_device = { 788c2ecf20Sopenharmony_ci .name = "omapdss_dss", 798c2ecf20Sopenharmony_ci .id = -1, 808c2ecf20Sopenharmony_ci .dev = { 818c2ecf20Sopenharmony_ci .release = omapdss_release, 828c2ecf20Sopenharmony_ci }, 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/* 868c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 878c2ecf20Sopenharmony_ci * LCD panel 888c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ciextern struct lcd_ctrl hwa742_ctrl; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic const struct lcd_ctrl *ctrls[] = { 938c2ecf20Sopenharmony_ci &omap1_int_ctrl, 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_OMAP_LCDC_HWA742 968c2ecf20Sopenharmony_ci &hwa742_ctrl, 978c2ecf20Sopenharmony_ci#endif 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL 1018c2ecf20Sopenharmony_ciextern struct lcd_ctrl_extif omap1_ext_if; 1028c2ecf20Sopenharmony_ci#endif 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void omapfb_rqueue_lock(struct omapfb_device *fbdev) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci mutex_lock(&fbdev->rqueue_mutex); 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic void omapfb_rqueue_unlock(struct omapfb_device *fbdev) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci mutex_unlock(&fbdev->rqueue_mutex); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* 1158c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 1168c2ecf20Sopenharmony_ci * LCD controller and LCD DMA 1178c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * Allocate resources needed for LCD controller and LCD DMA operations. Video 1218c2ecf20Sopenharmony_ci * memory is allocated from system memory according to the virtual display 1228c2ecf20Sopenharmony_ci * size, except if a bigger memory size is specified explicitly as a kernel 1238c2ecf20Sopenharmony_ci * parameter. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_cistatic int ctrl_init(struct omapfb_device *fbdev) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci int r; 1288c2ecf20Sopenharmony_ci int i; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci /* kernel/module vram parameters override boot tags/board config */ 1318c2ecf20Sopenharmony_ci if (def_vram_cnt) { 1328c2ecf20Sopenharmony_ci for (i = 0; i < def_vram_cnt; i++) 1338c2ecf20Sopenharmony_ci fbdev->mem_desc.region[i].size = 1348c2ecf20Sopenharmony_ci PAGE_ALIGN(def_vram[i]); 1358c2ecf20Sopenharmony_ci fbdev->mem_desc.region_cnt = i; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (!fbdev->mem_desc.region_cnt) { 1398c2ecf20Sopenharmony_ci struct lcd_panel *panel = fbdev->panel; 1408c2ecf20Sopenharmony_ci int def_size; 1418c2ecf20Sopenharmony_ci int bpp = panel->bpp; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* 12 bpp is packed in 16 bits */ 1448c2ecf20Sopenharmony_ci if (bpp == 12) 1458c2ecf20Sopenharmony_ci bpp = 16; 1468c2ecf20Sopenharmony_ci def_size = def_vxres * def_vyres * bpp / 8; 1478c2ecf20Sopenharmony_ci fbdev->mem_desc.region_cnt = 1; 1488c2ecf20Sopenharmony_ci fbdev->mem_desc.region[0].size = PAGE_ALIGN(def_size); 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci r = fbdev->ctrl->init(fbdev, 0, &fbdev->mem_desc); 1518c2ecf20Sopenharmony_ci if (r < 0) { 1528c2ecf20Sopenharmony_ci dev_err(fbdev->dev, "controller initialization failed (%d)\n", 1538c2ecf20Sopenharmony_ci r); 1548c2ecf20Sopenharmony_ci return r; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#ifdef DEBUG 1588c2ecf20Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 1598c2ecf20Sopenharmony_ci dev_dbg(fbdev->dev, "region%d phys %08x virt %p size=%lu\n", 1608c2ecf20Sopenharmony_ci i, 1618c2ecf20Sopenharmony_ci fbdev->mem_desc.region[i].paddr, 1628c2ecf20Sopenharmony_ci fbdev->mem_desc.region[i].vaddr, 1638c2ecf20Sopenharmony_ci fbdev->mem_desc.region[i].size); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci#endif 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic void ctrl_cleanup(struct omapfb_device *fbdev) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci fbdev->ctrl->cleanup(); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/* Must be called with fbdev->rqueue_mutex held. */ 1758c2ecf20Sopenharmony_cistatic int ctrl_change_mode(struct fb_info *fbi) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci int r; 1788c2ecf20Sopenharmony_ci unsigned long offset; 1798c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 1808c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 1818c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var = &fbi->var; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci offset = var->yoffset * fbi->fix.line_length + 1848c2ecf20Sopenharmony_ci var->xoffset * var->bits_per_pixel / 8; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (fbdev->ctrl->sync) 1878c2ecf20Sopenharmony_ci fbdev->ctrl->sync(); 1888c2ecf20Sopenharmony_ci r = fbdev->ctrl->setup_plane(plane->idx, plane->info.channel_out, 1898c2ecf20Sopenharmony_ci offset, var->xres_virtual, 1908c2ecf20Sopenharmony_ci plane->info.pos_x, plane->info.pos_y, 1918c2ecf20Sopenharmony_ci var->xres, var->yres, plane->color_mode); 1928c2ecf20Sopenharmony_ci if (r < 0) 1938c2ecf20Sopenharmony_ci return r; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (fbdev->ctrl->set_rotate != NULL) { 1968c2ecf20Sopenharmony_ci r = fbdev->ctrl->set_rotate(var->rotate); 1978c2ecf20Sopenharmony_ci if (r < 0) 1988c2ecf20Sopenharmony_ci return r; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (fbdev->ctrl->set_scale != NULL) 2028c2ecf20Sopenharmony_ci r = fbdev->ctrl->set_scale(plane->idx, 2038c2ecf20Sopenharmony_ci var->xres, var->yres, 2048c2ecf20Sopenharmony_ci plane->info.out_width, 2058c2ecf20Sopenharmony_ci plane->info.out_height); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci return r; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/* 2118c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 2128c2ecf20Sopenharmony_ci * fbdev framework callbacks and the ioctl interface 2138c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci/* Called each time the omapfb device is opened */ 2168c2ecf20Sopenharmony_cistatic int omapfb_open(struct fb_info *info, int user) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void omapfb_sync(struct fb_info *info); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* Called when the omapfb device is closed. We make sure that any pending 2248c2ecf20Sopenharmony_ci * gfx DMA operations are ended, before we return. */ 2258c2ecf20Sopenharmony_cistatic int omapfb_release(struct fb_info *info, int user) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci omapfb_sync(info); 2288c2ecf20Sopenharmony_ci return 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/* Store a single color palette entry into a pseudo palette or the hardware 2328c2ecf20Sopenharmony_ci * palette if one is available. For now we support only 16bpp and thus store 2338c2ecf20Sopenharmony_ci * the entry only to the pseudo palette. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_cistatic int _setcolreg(struct fb_info *info, u_int regno, u_int red, u_int green, 2368c2ecf20Sopenharmony_ci u_int blue, u_int transp, int update_hw_pal) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = info->par; 2398c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 2408c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var = &info->var; 2418c2ecf20Sopenharmony_ci int r = 0; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci switch (plane->color_mode) { 2448c2ecf20Sopenharmony_ci case OMAPFB_COLOR_YUV422: 2458c2ecf20Sopenharmony_ci case OMAPFB_COLOR_YUV420: 2468c2ecf20Sopenharmony_ci case OMAPFB_COLOR_YUY422: 2478c2ecf20Sopenharmony_ci r = -EINVAL; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci case OMAPFB_COLOR_CLUT_8BPP: 2508c2ecf20Sopenharmony_ci case OMAPFB_COLOR_CLUT_4BPP: 2518c2ecf20Sopenharmony_ci case OMAPFB_COLOR_CLUT_2BPP: 2528c2ecf20Sopenharmony_ci case OMAPFB_COLOR_CLUT_1BPP: 2538c2ecf20Sopenharmony_ci if (fbdev->ctrl->setcolreg) 2548c2ecf20Sopenharmony_ci r = fbdev->ctrl->setcolreg(regno, red, green, blue, 2558c2ecf20Sopenharmony_ci transp, update_hw_pal); 2568c2ecf20Sopenharmony_ci fallthrough; 2578c2ecf20Sopenharmony_ci case OMAPFB_COLOR_RGB565: 2588c2ecf20Sopenharmony_ci case OMAPFB_COLOR_RGB444: 2598c2ecf20Sopenharmony_ci if (r != 0) 2608c2ecf20Sopenharmony_ci break; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (regno < 16) { 2638c2ecf20Sopenharmony_ci u16 pal; 2648c2ecf20Sopenharmony_ci pal = ((red >> (16 - var->red.length)) << 2658c2ecf20Sopenharmony_ci var->red.offset) | 2668c2ecf20Sopenharmony_ci ((green >> (16 - var->green.length)) << 2678c2ecf20Sopenharmony_ci var->green.offset) | 2688c2ecf20Sopenharmony_ci (blue >> (16 - var->blue.length)); 2698c2ecf20Sopenharmony_ci ((u32 *)(info->pseudo_palette))[regno] = pal; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci default: 2738c2ecf20Sopenharmony_ci BUG(); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci return r; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic int omapfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, 2798c2ecf20Sopenharmony_ci u_int transp, struct fb_info *info) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci return _setcolreg(info, regno, red, green, blue, transp, 1); 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic int omapfb_setcmap(struct fb_cmap *cmap, struct fb_info *info) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci int count, index, r; 2878c2ecf20Sopenharmony_ci u16 *red, *green, *blue, *transp; 2888c2ecf20Sopenharmony_ci u16 trans = 0xffff; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci red = cmap->red; 2918c2ecf20Sopenharmony_ci green = cmap->green; 2928c2ecf20Sopenharmony_ci blue = cmap->blue; 2938c2ecf20Sopenharmony_ci transp = cmap->transp; 2948c2ecf20Sopenharmony_ci index = cmap->start; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci for (count = 0; count < cmap->len; count++) { 2978c2ecf20Sopenharmony_ci if (transp) 2988c2ecf20Sopenharmony_ci trans = *transp++; 2998c2ecf20Sopenharmony_ci r = _setcolreg(info, index++, *red++, *green++, *blue++, trans, 3008c2ecf20Sopenharmony_ci count == cmap->len - 1); 3018c2ecf20Sopenharmony_ci if (r != 0) 3028c2ecf20Sopenharmony_ci return r; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci return 0; 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic int omapfb_update_full_screen(struct fb_info *fbi); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int omapfb_blank(int blank, struct fb_info *fbi) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 3138c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 3148c2ecf20Sopenharmony_ci int do_update = 0; 3158c2ecf20Sopenharmony_ci int r = 0; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 3188c2ecf20Sopenharmony_ci switch (blank) { 3198c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: 3208c2ecf20Sopenharmony_ci if (fbdev->state == OMAPFB_SUSPENDED) { 3218c2ecf20Sopenharmony_ci if (fbdev->ctrl->resume) 3228c2ecf20Sopenharmony_ci fbdev->ctrl->resume(); 3238c2ecf20Sopenharmony_ci if (fbdev->panel->enable) 3248c2ecf20Sopenharmony_ci fbdev->panel->enable(fbdev->panel); 3258c2ecf20Sopenharmony_ci fbdev->state = OMAPFB_ACTIVE; 3268c2ecf20Sopenharmony_ci if (fbdev->ctrl->get_update_mode() == 3278c2ecf20Sopenharmony_ci OMAPFB_MANUAL_UPDATE) 3288c2ecf20Sopenharmony_ci do_update = 1; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 3328c2ecf20Sopenharmony_ci if (fbdev->state == OMAPFB_ACTIVE) { 3338c2ecf20Sopenharmony_ci if (fbdev->panel->disable) 3348c2ecf20Sopenharmony_ci fbdev->panel->disable(fbdev->panel); 3358c2ecf20Sopenharmony_ci if (fbdev->ctrl->suspend) 3368c2ecf20Sopenharmony_ci fbdev->ctrl->suspend(); 3378c2ecf20Sopenharmony_ci fbdev->state = OMAPFB_SUSPENDED; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci default: 3418c2ecf20Sopenharmony_ci r = -EINVAL; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (r == 0 && do_update) 3468c2ecf20Sopenharmony_ci r = omapfb_update_full_screen(fbi); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return r; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic void omapfb_sync(struct fb_info *fbi) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 3548c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 3578c2ecf20Sopenharmony_ci if (fbdev->ctrl->sync) 3588c2ecf20Sopenharmony_ci fbdev->ctrl->sync(); 3598c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/* 3638c2ecf20Sopenharmony_ci * Set fb_info.fix fields and also updates fbdev. 3648c2ecf20Sopenharmony_ci * When calling this fb_info.var must be set up already. 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_cistatic void set_fb_fix(struct fb_info *fbi, int from_init) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct fb_fix_screeninfo *fix = &fbi->fix; 3698c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var = &fbi->var; 3708c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 3718c2ecf20Sopenharmony_ci struct omapfb_mem_region *rg; 3728c2ecf20Sopenharmony_ci int bpp; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci rg = &plane->fbdev->mem_desc.region[plane->idx]; 3758c2ecf20Sopenharmony_ci fbi->screen_base = rg->vaddr; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (!from_init) { 3788c2ecf20Sopenharmony_ci mutex_lock(&fbi->mm_lock); 3798c2ecf20Sopenharmony_ci fix->smem_start = rg->paddr; 3808c2ecf20Sopenharmony_ci fix->smem_len = rg->size; 3818c2ecf20Sopenharmony_ci mutex_unlock(&fbi->mm_lock); 3828c2ecf20Sopenharmony_ci } else { 3838c2ecf20Sopenharmony_ci fix->smem_start = rg->paddr; 3848c2ecf20Sopenharmony_ci fix->smem_len = rg->size; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci fix->type = FB_TYPE_PACKED_PIXELS; 3888c2ecf20Sopenharmony_ci bpp = var->bits_per_pixel; 3898c2ecf20Sopenharmony_ci if (var->nonstd) 3908c2ecf20Sopenharmony_ci fix->visual = FB_VISUAL_PSEUDOCOLOR; 3918c2ecf20Sopenharmony_ci else switch (var->bits_per_pixel) { 3928c2ecf20Sopenharmony_ci case 16: 3938c2ecf20Sopenharmony_ci case 12: 3948c2ecf20Sopenharmony_ci fix->visual = FB_VISUAL_TRUECOLOR; 3958c2ecf20Sopenharmony_ci /* 12bpp is stored in 16 bits */ 3968c2ecf20Sopenharmony_ci bpp = 16; 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci case 1: 3998c2ecf20Sopenharmony_ci case 2: 4008c2ecf20Sopenharmony_ci case 4: 4018c2ecf20Sopenharmony_ci case 8: 4028c2ecf20Sopenharmony_ci fix->visual = FB_VISUAL_PSEUDOCOLOR; 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci fix->accel = FB_ACCEL_OMAP1610; 4068c2ecf20Sopenharmony_ci fix->line_length = var->xres_virtual * bpp / 8; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic int set_color_mode(struct omapfb_plane_struct *plane, 4108c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var) 4118c2ecf20Sopenharmony_ci{ 4128c2ecf20Sopenharmony_ci switch (var->nonstd) { 4138c2ecf20Sopenharmony_ci case 0: 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci case OMAPFB_COLOR_YUV422: 4168c2ecf20Sopenharmony_ci var->bits_per_pixel = 16; 4178c2ecf20Sopenharmony_ci plane->color_mode = var->nonstd; 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci case OMAPFB_COLOR_YUV420: 4208c2ecf20Sopenharmony_ci var->bits_per_pixel = 12; 4218c2ecf20Sopenharmony_ci plane->color_mode = var->nonstd; 4228c2ecf20Sopenharmony_ci return 0; 4238c2ecf20Sopenharmony_ci case OMAPFB_COLOR_YUY422: 4248c2ecf20Sopenharmony_ci var->bits_per_pixel = 16; 4258c2ecf20Sopenharmony_ci plane->color_mode = var->nonstd; 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci default: 4288c2ecf20Sopenharmony_ci return -EINVAL; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 4328c2ecf20Sopenharmony_ci case 1: 4338c2ecf20Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_CLUT_1BPP; 4348c2ecf20Sopenharmony_ci return 0; 4358c2ecf20Sopenharmony_ci case 2: 4368c2ecf20Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_CLUT_2BPP; 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci case 4: 4398c2ecf20Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_CLUT_4BPP; 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci case 8: 4428c2ecf20Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_CLUT_8BPP; 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci case 12: 4458c2ecf20Sopenharmony_ci var->bits_per_pixel = 16; 4468c2ecf20Sopenharmony_ci fallthrough; 4478c2ecf20Sopenharmony_ci case 16: 4488c2ecf20Sopenharmony_ci if (plane->fbdev->panel->bpp == 12) 4498c2ecf20Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_RGB444; 4508c2ecf20Sopenharmony_ci else 4518c2ecf20Sopenharmony_ci plane->color_mode = OMAPFB_COLOR_RGB565; 4528c2ecf20Sopenharmony_ci return 0; 4538c2ecf20Sopenharmony_ci default: 4548c2ecf20Sopenharmony_ci return -EINVAL; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci/* 4598c2ecf20Sopenharmony_ci * Check the values in var against our capabilities and in case of out of 4608c2ecf20Sopenharmony_ci * bound values try to adjust them. 4618c2ecf20Sopenharmony_ci */ 4628c2ecf20Sopenharmony_cistatic int set_fb_var(struct fb_info *fbi, 4638c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var) 4648c2ecf20Sopenharmony_ci{ 4658c2ecf20Sopenharmony_ci int bpp; 4668c2ecf20Sopenharmony_ci unsigned long max_frame_size; 4678c2ecf20Sopenharmony_ci unsigned long line_size; 4688c2ecf20Sopenharmony_ci int xres_min, xres_max; 4698c2ecf20Sopenharmony_ci int yres_min, yres_max; 4708c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 4718c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 4728c2ecf20Sopenharmony_ci struct lcd_panel *panel = fbdev->panel; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (set_color_mode(plane, var) < 0) 4758c2ecf20Sopenharmony_ci return -EINVAL; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci bpp = var->bits_per_pixel; 4788c2ecf20Sopenharmony_ci if (plane->color_mode == OMAPFB_COLOR_RGB444) 4798c2ecf20Sopenharmony_ci bpp = 16; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci switch (var->rotate) { 4828c2ecf20Sopenharmony_ci case 0: 4838c2ecf20Sopenharmony_ci case 180: 4848c2ecf20Sopenharmony_ci xres_min = OMAPFB_PLANE_XRES_MIN; 4858c2ecf20Sopenharmony_ci xres_max = panel->x_res; 4868c2ecf20Sopenharmony_ci yres_min = OMAPFB_PLANE_YRES_MIN; 4878c2ecf20Sopenharmony_ci yres_max = panel->y_res; 4888c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) { 4898c2ecf20Sopenharmony_ci var->xres = panel->x_res; 4908c2ecf20Sopenharmony_ci var->yres = panel->y_res; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case 90: 4948c2ecf20Sopenharmony_ci case 270: 4958c2ecf20Sopenharmony_ci xres_min = OMAPFB_PLANE_YRES_MIN; 4968c2ecf20Sopenharmony_ci xres_max = panel->y_res; 4978c2ecf20Sopenharmony_ci yres_min = OMAPFB_PLANE_XRES_MIN; 4988c2ecf20Sopenharmony_ci yres_max = panel->x_res; 4998c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) { 5008c2ecf20Sopenharmony_ci var->xres = panel->y_res; 5018c2ecf20Sopenharmony_ci var->yres = panel->x_res; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci break; 5048c2ecf20Sopenharmony_ci default: 5058c2ecf20Sopenharmony_ci return -EINVAL; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (var->xres < xres_min) 5098c2ecf20Sopenharmony_ci var->xres = xres_min; 5108c2ecf20Sopenharmony_ci if (var->yres < yres_min) 5118c2ecf20Sopenharmony_ci var->yres = yres_min; 5128c2ecf20Sopenharmony_ci if (var->xres > xres_max) 5138c2ecf20Sopenharmony_ci var->xres = xres_max; 5148c2ecf20Sopenharmony_ci if (var->yres > yres_max) 5158c2ecf20Sopenharmony_ci var->yres = yres_max; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (var->xres_virtual < var->xres) 5188c2ecf20Sopenharmony_ci var->xres_virtual = var->xres; 5198c2ecf20Sopenharmony_ci if (var->yres_virtual < var->yres) 5208c2ecf20Sopenharmony_ci var->yres_virtual = var->yres; 5218c2ecf20Sopenharmony_ci max_frame_size = fbdev->mem_desc.region[plane->idx].size; 5228c2ecf20Sopenharmony_ci line_size = var->xres_virtual * bpp / 8; 5238c2ecf20Sopenharmony_ci if (line_size * var->yres_virtual > max_frame_size) { 5248c2ecf20Sopenharmony_ci /* Try to keep yres_virtual first */ 5258c2ecf20Sopenharmony_ci line_size = max_frame_size / var->yres_virtual; 5268c2ecf20Sopenharmony_ci var->xres_virtual = line_size * 8 / bpp; 5278c2ecf20Sopenharmony_ci if (var->xres_virtual < var->xres) { 5288c2ecf20Sopenharmony_ci /* Still doesn't fit. Shrink yres_virtual too */ 5298c2ecf20Sopenharmony_ci var->xres_virtual = var->xres; 5308c2ecf20Sopenharmony_ci line_size = var->xres * bpp / 8; 5318c2ecf20Sopenharmony_ci var->yres_virtual = max_frame_size / line_size; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci /* Recheck this, as the virtual size changed. */ 5348c2ecf20Sopenharmony_ci if (var->xres_virtual < var->xres) 5358c2ecf20Sopenharmony_ci var->xres = var->xres_virtual; 5368c2ecf20Sopenharmony_ci if (var->yres_virtual < var->yres) 5378c2ecf20Sopenharmony_ci var->yres = var->yres_virtual; 5388c2ecf20Sopenharmony_ci if (var->xres < xres_min || var->yres < yres_min) 5398c2ecf20Sopenharmony_ci return -EINVAL; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci if (var->xres + var->xoffset > var->xres_virtual) 5428c2ecf20Sopenharmony_ci var->xoffset = var->xres_virtual - var->xres; 5438c2ecf20Sopenharmony_ci if (var->yres + var->yoffset > var->yres_virtual) 5448c2ecf20Sopenharmony_ci var->yoffset = var->yres_virtual - var->yres; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (plane->color_mode == OMAPFB_COLOR_RGB444) { 5478c2ecf20Sopenharmony_ci var->red.offset = 8; var->red.length = 4; 5488c2ecf20Sopenharmony_ci var->red.msb_right = 0; 5498c2ecf20Sopenharmony_ci var->green.offset = 4; var->green.length = 4; 5508c2ecf20Sopenharmony_ci var->green.msb_right = 0; 5518c2ecf20Sopenharmony_ci var->blue.offset = 0; var->blue.length = 4; 5528c2ecf20Sopenharmony_ci var->blue.msb_right = 0; 5538c2ecf20Sopenharmony_ci } else { 5548c2ecf20Sopenharmony_ci var->red.offset = 11; var->red.length = 5; 5558c2ecf20Sopenharmony_ci var->red.msb_right = 0; 5568c2ecf20Sopenharmony_ci var->green.offset = 5; var->green.length = 6; 5578c2ecf20Sopenharmony_ci var->green.msb_right = 0; 5588c2ecf20Sopenharmony_ci var->blue.offset = 0; var->blue.length = 5; 5598c2ecf20Sopenharmony_ci var->blue.msb_right = 0; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci var->height = -1; 5638c2ecf20Sopenharmony_ci var->width = -1; 5648c2ecf20Sopenharmony_ci var->grayscale = 0; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* pixclock in ps, the rest in pixclock */ 5678c2ecf20Sopenharmony_ci var->pixclock = 10000000 / (panel->pixel_clock / 100); 5688c2ecf20Sopenharmony_ci var->left_margin = panel->hfp; 5698c2ecf20Sopenharmony_ci var->right_margin = panel->hbp; 5708c2ecf20Sopenharmony_ci var->upper_margin = panel->vfp; 5718c2ecf20Sopenharmony_ci var->lower_margin = panel->vbp; 5728c2ecf20Sopenharmony_ci var->hsync_len = panel->hsw; 5738c2ecf20Sopenharmony_ci var->vsync_len = panel->vsw; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci /* TODO: get these from panel->config */ 5768c2ecf20Sopenharmony_ci var->vmode = FB_VMODE_NONINTERLACED; 5778c2ecf20Sopenharmony_ci var->sync = 0; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci return 0; 5808c2ecf20Sopenharmony_ci} 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci/* 5848c2ecf20Sopenharmony_ci * Set new x,y offsets in the virtual display for the visible area and switch 5858c2ecf20Sopenharmony_ci * to the new mode. 5868c2ecf20Sopenharmony_ci */ 5878c2ecf20Sopenharmony_cistatic int omapfb_pan_display(struct fb_var_screeninfo *var, 5888c2ecf20Sopenharmony_ci struct fb_info *fbi) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 5918c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 5928c2ecf20Sopenharmony_ci int r = 0; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 5958c2ecf20Sopenharmony_ci if (var->xoffset != fbi->var.xoffset || 5968c2ecf20Sopenharmony_ci var->yoffset != fbi->var.yoffset) { 5978c2ecf20Sopenharmony_ci struct fb_var_screeninfo *new_var = &fbdev->new_var; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci memcpy(new_var, &fbi->var, sizeof(*new_var)); 6008c2ecf20Sopenharmony_ci new_var->xoffset = var->xoffset; 6018c2ecf20Sopenharmony_ci new_var->yoffset = var->yoffset; 6028c2ecf20Sopenharmony_ci if (set_fb_var(fbi, new_var)) 6038c2ecf20Sopenharmony_ci r = -EINVAL; 6048c2ecf20Sopenharmony_ci else { 6058c2ecf20Sopenharmony_ci memcpy(&fbi->var, new_var, sizeof(*new_var)); 6068c2ecf20Sopenharmony_ci ctrl_change_mode(fbi); 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci return r; 6128c2ecf20Sopenharmony_ci} 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci/* Set mirror to vertical axis and switch to the new mode. */ 6158c2ecf20Sopenharmony_cistatic int omapfb_mirror(struct fb_info *fbi, int mirror) 6168c2ecf20Sopenharmony_ci{ 6178c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 6188c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 6198c2ecf20Sopenharmony_ci int r = 0; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 6228c2ecf20Sopenharmony_ci mirror = mirror ? 1 : 0; 6238c2ecf20Sopenharmony_ci if (cpu_is_omap15xx()) 6248c2ecf20Sopenharmony_ci r = -EINVAL; 6258c2ecf20Sopenharmony_ci else if (mirror != plane->info.mirror) { 6268c2ecf20Sopenharmony_ci plane->info.mirror = mirror; 6278c2ecf20Sopenharmony_ci r = ctrl_change_mode(fbi); 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return r; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci/* 6358c2ecf20Sopenharmony_ci * Check values in var, try to adjust them in case of out of bound values if 6368c2ecf20Sopenharmony_ci * possible, or return error. 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_cistatic int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 6418c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 6428c2ecf20Sopenharmony_ci int r; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 6458c2ecf20Sopenharmony_ci if (fbdev->ctrl->sync != NULL) 6468c2ecf20Sopenharmony_ci fbdev->ctrl->sync(); 6478c2ecf20Sopenharmony_ci r = set_fb_var(fbi, var); 6488c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci return r; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci/* 6548c2ecf20Sopenharmony_ci * Switch to a new mode. The parameters for it has been check already by 6558c2ecf20Sopenharmony_ci * omapfb_check_var. 6568c2ecf20Sopenharmony_ci */ 6578c2ecf20Sopenharmony_cistatic int omapfb_set_par(struct fb_info *fbi) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 6608c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 6618c2ecf20Sopenharmony_ci int r = 0; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 6648c2ecf20Sopenharmony_ci set_fb_fix(fbi, 0); 6658c2ecf20Sopenharmony_ci r = ctrl_change_mode(fbi); 6668c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci return r; 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ciint omapfb_update_window_async(struct fb_info *fbi, 6728c2ecf20Sopenharmony_ci struct omapfb_update_window *win, 6738c2ecf20Sopenharmony_ci void (*callback)(void *), 6748c2ecf20Sopenharmony_ci void *callback_data) 6758c2ecf20Sopenharmony_ci{ 6768c2ecf20Sopenharmony_ci int xres, yres; 6778c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 6788c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 6798c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var = &fbi->var; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci switch (var->rotate) { 6828c2ecf20Sopenharmony_ci case 0: 6838c2ecf20Sopenharmony_ci case 180: 6848c2ecf20Sopenharmony_ci xres = fbdev->panel->x_res; 6858c2ecf20Sopenharmony_ci yres = fbdev->panel->y_res; 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci case 90: 6888c2ecf20Sopenharmony_ci case 270: 6898c2ecf20Sopenharmony_ci xres = fbdev->panel->y_res; 6908c2ecf20Sopenharmony_ci yres = fbdev->panel->x_res; 6918c2ecf20Sopenharmony_ci break; 6928c2ecf20Sopenharmony_ci default: 6938c2ecf20Sopenharmony_ci return -EINVAL; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (win->x >= xres || win->y >= yres || 6978c2ecf20Sopenharmony_ci win->out_x > xres || win->out_y > yres) 6988c2ecf20Sopenharmony_ci return -EINVAL; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (!fbdev->ctrl->update_window || 7018c2ecf20Sopenharmony_ci fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) 7028c2ecf20Sopenharmony_ci return -ENODEV; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (win->x + win->width > xres) 7058c2ecf20Sopenharmony_ci win->width = xres - win->x; 7068c2ecf20Sopenharmony_ci if (win->y + win->height > yres) 7078c2ecf20Sopenharmony_ci win->height = yres - win->y; 7088c2ecf20Sopenharmony_ci if (win->out_x + win->out_width > xres) 7098c2ecf20Sopenharmony_ci win->out_width = xres - win->out_x; 7108c2ecf20Sopenharmony_ci if (win->out_y + win->out_height > yres) 7118c2ecf20Sopenharmony_ci win->out_height = yres - win->out_y; 7128c2ecf20Sopenharmony_ci if (!win->width || !win->height || !win->out_width || !win->out_height) 7138c2ecf20Sopenharmony_ci return 0; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci return fbdev->ctrl->update_window(fbi, win, callback, callback_data); 7168c2ecf20Sopenharmony_ci} 7178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omapfb_update_window_async); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic int omapfb_update_win(struct fb_info *fbi, 7208c2ecf20Sopenharmony_ci struct omapfb_update_window *win) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 7238c2ecf20Sopenharmony_ci int ret; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci omapfb_rqueue_lock(plane->fbdev); 7268c2ecf20Sopenharmony_ci ret = omapfb_update_window_async(fbi, win, NULL, NULL); 7278c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(plane->fbdev); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return ret; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_cistatic int omapfb_update_full_screen(struct fb_info *fbi) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 7358c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 7368c2ecf20Sopenharmony_ci struct omapfb_update_window win; 7378c2ecf20Sopenharmony_ci int r; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (!fbdev->ctrl->update_window || 7408c2ecf20Sopenharmony_ci fbdev->ctrl->get_update_mode() != OMAPFB_MANUAL_UPDATE) 7418c2ecf20Sopenharmony_ci return -ENODEV; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci win.x = 0; 7448c2ecf20Sopenharmony_ci win.y = 0; 7458c2ecf20Sopenharmony_ci win.width = fbi->var.xres; 7468c2ecf20Sopenharmony_ci win.height = fbi->var.yres; 7478c2ecf20Sopenharmony_ci win.out_x = 0; 7488c2ecf20Sopenharmony_ci win.out_y = 0; 7498c2ecf20Sopenharmony_ci win.out_width = fbi->var.xres; 7508c2ecf20Sopenharmony_ci win.out_height = fbi->var.yres; 7518c2ecf20Sopenharmony_ci win.format = 0; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 7548c2ecf20Sopenharmony_ci r = fbdev->ctrl->update_window(fbi, &win, NULL, NULL); 7558c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci return r; 7588c2ecf20Sopenharmony_ci} 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_cistatic int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) 7618c2ecf20Sopenharmony_ci{ 7628c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 7638c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 7648c2ecf20Sopenharmony_ci struct lcd_panel *panel = fbdev->panel; 7658c2ecf20Sopenharmony_ci struct omapfb_plane_info old_info; 7668c2ecf20Sopenharmony_ci int r = 0; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci if (pi->pos_x + pi->out_width > panel->x_res || 7698c2ecf20Sopenharmony_ci pi->pos_y + pi->out_height > panel->y_res) 7708c2ecf20Sopenharmony_ci return -EINVAL; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 7738c2ecf20Sopenharmony_ci if (pi->enabled && !fbdev->mem_desc.region[plane->idx].size) { 7748c2ecf20Sopenharmony_ci /* 7758c2ecf20Sopenharmony_ci * This plane's memory was freed, can't enable it 7768c2ecf20Sopenharmony_ci * until it's reallocated. 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_ci r = -EINVAL; 7798c2ecf20Sopenharmony_ci goto out; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci old_info = plane->info; 7828c2ecf20Sopenharmony_ci plane->info = *pi; 7838c2ecf20Sopenharmony_ci if (pi->enabled) { 7848c2ecf20Sopenharmony_ci r = ctrl_change_mode(fbi); 7858c2ecf20Sopenharmony_ci if (r < 0) { 7868c2ecf20Sopenharmony_ci plane->info = old_info; 7878c2ecf20Sopenharmony_ci goto out; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci r = fbdev->ctrl->enable_plane(plane->idx, pi->enabled); 7918c2ecf20Sopenharmony_ci if (r < 0) { 7928c2ecf20Sopenharmony_ci plane->info = old_info; 7938c2ecf20Sopenharmony_ci goto out; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ciout: 7968c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 7978c2ecf20Sopenharmony_ci return r; 7988c2ecf20Sopenharmony_ci} 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_cistatic int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) 8018c2ecf20Sopenharmony_ci{ 8028c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci *pi = plane->info; 8058c2ecf20Sopenharmony_ci return 0; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 8118c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 8128c2ecf20Sopenharmony_ci struct omapfb_mem_region *rg = &fbdev->mem_desc.region[plane->idx]; 8138c2ecf20Sopenharmony_ci size_t size; 8148c2ecf20Sopenharmony_ci int r = 0; 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci if (fbdev->ctrl->setup_mem == NULL) 8178c2ecf20Sopenharmony_ci return -ENODEV; 8188c2ecf20Sopenharmony_ci if (mi->type != OMAPFB_MEMTYPE_SDRAM) 8198c2ecf20Sopenharmony_ci return -EINVAL; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci size = PAGE_ALIGN(mi->size); 8228c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 8238c2ecf20Sopenharmony_ci if (plane->info.enabled) { 8248c2ecf20Sopenharmony_ci r = -EBUSY; 8258c2ecf20Sopenharmony_ci goto out; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci if (rg->size != size || rg->type != mi->type) { 8288c2ecf20Sopenharmony_ci struct fb_var_screeninfo *new_var = &fbdev->new_var; 8298c2ecf20Sopenharmony_ci unsigned long old_size = rg->size; 8308c2ecf20Sopenharmony_ci u8 old_type = rg->type; 8318c2ecf20Sopenharmony_ci unsigned long paddr; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci rg->size = size; 8348c2ecf20Sopenharmony_ci rg->type = mi->type; 8358c2ecf20Sopenharmony_ci /* 8368c2ecf20Sopenharmony_ci * size == 0 is a special case, for which we 8378c2ecf20Sopenharmony_ci * don't check / adjust the screen parameters. 8388c2ecf20Sopenharmony_ci * This isn't a problem since the plane can't 8398c2ecf20Sopenharmony_ci * be reenabled unless its size is > 0. 8408c2ecf20Sopenharmony_ci */ 8418c2ecf20Sopenharmony_ci if (old_size != size && size) { 8428c2ecf20Sopenharmony_ci if (size) { 8438c2ecf20Sopenharmony_ci memcpy(new_var, &fbi->var, sizeof(*new_var)); 8448c2ecf20Sopenharmony_ci r = set_fb_var(fbi, new_var); 8458c2ecf20Sopenharmony_ci if (r < 0) 8468c2ecf20Sopenharmony_ci goto out; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci } 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (fbdev->ctrl->sync) 8518c2ecf20Sopenharmony_ci fbdev->ctrl->sync(); 8528c2ecf20Sopenharmony_ci r = fbdev->ctrl->setup_mem(plane->idx, size, mi->type, &paddr); 8538c2ecf20Sopenharmony_ci if (r < 0) { 8548c2ecf20Sopenharmony_ci /* Revert changes. */ 8558c2ecf20Sopenharmony_ci rg->size = old_size; 8568c2ecf20Sopenharmony_ci rg->type = old_type; 8578c2ecf20Sopenharmony_ci goto out; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci rg->paddr = paddr; 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci if (old_size != size) { 8628c2ecf20Sopenharmony_ci if (size) { 8638c2ecf20Sopenharmony_ci memcpy(&fbi->var, new_var, sizeof(fbi->var)); 8648c2ecf20Sopenharmony_ci set_fb_fix(fbi, 0); 8658c2ecf20Sopenharmony_ci } else { 8668c2ecf20Sopenharmony_ci /* 8678c2ecf20Sopenharmony_ci * Set these explicitly to indicate that the 8688c2ecf20Sopenharmony_ci * plane memory is dealloce'd, the other 8698c2ecf20Sopenharmony_ci * screen parameters in var / fix are invalid. 8708c2ecf20Sopenharmony_ci */ 8718c2ecf20Sopenharmony_ci mutex_lock(&fbi->mm_lock); 8728c2ecf20Sopenharmony_ci fbi->fix.smem_start = 0; 8738c2ecf20Sopenharmony_ci fbi->fix.smem_len = 0; 8748c2ecf20Sopenharmony_ci mutex_unlock(&fbi->mm_lock); 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci } 8788c2ecf20Sopenharmony_ciout: 8798c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci return r; 8828c2ecf20Sopenharmony_ci} 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_cistatic int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 8878c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 8888c2ecf20Sopenharmony_ci struct omapfb_mem_region *rg; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci rg = &fbdev->mem_desc.region[plane->idx]; 8918c2ecf20Sopenharmony_ci memset(mi, 0, sizeof(*mi)); 8928c2ecf20Sopenharmony_ci mi->size = rg->size; 8938c2ecf20Sopenharmony_ci mi->type = rg->type; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return 0; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic int omapfb_set_color_key(struct omapfb_device *fbdev, 8998c2ecf20Sopenharmony_ci struct omapfb_color_key *ck) 9008c2ecf20Sopenharmony_ci{ 9018c2ecf20Sopenharmony_ci int r; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (!fbdev->ctrl->set_color_key) 9048c2ecf20Sopenharmony_ci return -ENODEV; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 9078c2ecf20Sopenharmony_ci r = fbdev->ctrl->set_color_key(ck); 9088c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci return r; 9118c2ecf20Sopenharmony_ci} 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_cistatic int omapfb_get_color_key(struct omapfb_device *fbdev, 9148c2ecf20Sopenharmony_ci struct omapfb_color_key *ck) 9158c2ecf20Sopenharmony_ci{ 9168c2ecf20Sopenharmony_ci int r; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (!fbdev->ctrl->get_color_key) 9198c2ecf20Sopenharmony_ci return -ENODEV; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 9228c2ecf20Sopenharmony_ci r = fbdev->ctrl->get_color_key(ck); 9238c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return r; 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic struct blocking_notifier_head omapfb_client_list[OMAPFB_PLANE_NUM]; 9298c2ecf20Sopenharmony_cistatic int notifier_inited; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic void omapfb_init_notifier(void) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci int i; 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci for (i = 0; i < OMAPFB_PLANE_NUM; i++) 9368c2ecf20Sopenharmony_ci BLOCKING_INIT_NOTIFIER_HEAD(&omapfb_client_list[i]); 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ciint omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, 9408c2ecf20Sopenharmony_ci omapfb_notifier_callback_t callback, 9418c2ecf20Sopenharmony_ci void *callback_data) 9428c2ecf20Sopenharmony_ci{ 9438c2ecf20Sopenharmony_ci int r; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM) 9468c2ecf20Sopenharmony_ci return -EINVAL; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci if (!notifier_inited) { 9498c2ecf20Sopenharmony_ci omapfb_init_notifier(); 9508c2ecf20Sopenharmony_ci notifier_inited = 1; 9518c2ecf20Sopenharmony_ci } 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci omapfb_nb->nb.notifier_call = (int (*)(struct notifier_block *, 9548c2ecf20Sopenharmony_ci unsigned long, void *))callback; 9558c2ecf20Sopenharmony_ci omapfb_nb->data = callback_data; 9568c2ecf20Sopenharmony_ci r = blocking_notifier_chain_register( 9578c2ecf20Sopenharmony_ci &omapfb_client_list[omapfb_nb->plane_idx], 9588c2ecf20Sopenharmony_ci &omapfb_nb->nb); 9598c2ecf20Sopenharmony_ci if (r) 9608c2ecf20Sopenharmony_ci return r; 9618c2ecf20Sopenharmony_ci if (omapfb_dev != NULL && 9628c2ecf20Sopenharmony_ci omapfb_dev->ctrl && omapfb_dev->ctrl->bind_client) { 9638c2ecf20Sopenharmony_ci omapfb_dev->ctrl->bind_client(omapfb_nb); 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci return 0; 9678c2ecf20Sopenharmony_ci} 9688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omapfb_register_client); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ciint omapfb_unregister_client(struct omapfb_notifier_block *omapfb_nb) 9718c2ecf20Sopenharmony_ci{ 9728c2ecf20Sopenharmony_ci return blocking_notifier_chain_unregister( 9738c2ecf20Sopenharmony_ci &omapfb_client_list[omapfb_nb->plane_idx], &omapfb_nb->nb); 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omapfb_unregister_client); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_civoid omapfb_notify_clients(struct omapfb_device *fbdev, unsigned long event) 9788c2ecf20Sopenharmony_ci{ 9798c2ecf20Sopenharmony_ci int i; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci if (!notifier_inited) 9828c2ecf20Sopenharmony_ci /* no client registered yet */ 9838c2ecf20Sopenharmony_ci return; 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci for (i = 0; i < OMAPFB_PLANE_NUM; i++) 9868c2ecf20Sopenharmony_ci blocking_notifier_call_chain(&omapfb_client_list[i], event, 9878c2ecf20Sopenharmony_ci fbdev->fb_info[i]); 9888c2ecf20Sopenharmony_ci} 9898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omapfb_notify_clients); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic int omapfb_set_update_mode(struct omapfb_device *fbdev, 9928c2ecf20Sopenharmony_ci enum omapfb_update_mode mode) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci int r; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 9978c2ecf20Sopenharmony_ci r = fbdev->ctrl->set_update_mode(mode); 9988c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci return r; 10018c2ecf20Sopenharmony_ci} 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_cistatic enum omapfb_update_mode omapfb_get_update_mode(struct omapfb_device *fbdev) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci int r; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 10088c2ecf20Sopenharmony_ci r = fbdev->ctrl->get_update_mode(); 10098c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci return r; 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_cistatic void omapfb_get_caps(struct omapfb_device *fbdev, int plane, 10158c2ecf20Sopenharmony_ci struct omapfb_caps *caps) 10168c2ecf20Sopenharmony_ci{ 10178c2ecf20Sopenharmony_ci memset(caps, 0, sizeof(*caps)); 10188c2ecf20Sopenharmony_ci fbdev->ctrl->get_caps(plane, caps); 10198c2ecf20Sopenharmony_ci if (fbdev->panel->get_caps) 10208c2ecf20Sopenharmony_ci caps->ctrl |= fbdev->panel->get_caps(fbdev->panel); 10218c2ecf20Sopenharmony_ci} 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci/* For lcd testing */ 10248c2ecf20Sopenharmony_civoid omapfb_write_first_pixel(struct omapfb_device *fbdev, u16 pixval) 10258c2ecf20Sopenharmony_ci{ 10268c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 10278c2ecf20Sopenharmony_ci *(u16 *)fbdev->mem_desc.region[0].vaddr = pixval; 10288c2ecf20Sopenharmony_ci if (fbdev->ctrl->get_update_mode() == OMAPFB_MANUAL_UPDATE) { 10298c2ecf20Sopenharmony_ci struct omapfb_update_window win; 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci memset(&win, 0, sizeof(win)); 10328c2ecf20Sopenharmony_ci win.width = 2; 10338c2ecf20Sopenharmony_ci win.height = 2; 10348c2ecf20Sopenharmony_ci win.out_width = 2; 10358c2ecf20Sopenharmony_ci win.out_height = 2; 10368c2ecf20Sopenharmony_ci fbdev->ctrl->update_window(fbdev->fb_info[0], &win, NULL, NULL); 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 10398c2ecf20Sopenharmony_ci} 10408c2ecf20Sopenharmony_ciEXPORT_SYMBOL(omapfb_write_first_pixel); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci/* 10438c2ecf20Sopenharmony_ci * Ioctl interface. Part of the kernel mode frame buffer API is duplicated 10448c2ecf20Sopenharmony_ci * here to be accessible by user mode code. 10458c2ecf20Sopenharmony_ci */ 10468c2ecf20Sopenharmony_cistatic int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, 10478c2ecf20Sopenharmony_ci unsigned long arg) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = fbi->par; 10508c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 10518c2ecf20Sopenharmony_ci const struct fb_ops *ops = fbi->fbops; 10528c2ecf20Sopenharmony_ci union { 10538c2ecf20Sopenharmony_ci struct omapfb_update_window update_window; 10548c2ecf20Sopenharmony_ci struct omapfb_plane_info plane_info; 10558c2ecf20Sopenharmony_ci struct omapfb_mem_info mem_info; 10568c2ecf20Sopenharmony_ci struct omapfb_color_key color_key; 10578c2ecf20Sopenharmony_ci enum omapfb_update_mode update_mode; 10588c2ecf20Sopenharmony_ci struct omapfb_caps caps; 10598c2ecf20Sopenharmony_ci unsigned int mirror; 10608c2ecf20Sopenharmony_ci int plane_out; 10618c2ecf20Sopenharmony_ci int enable_plane; 10628c2ecf20Sopenharmony_ci } p; 10638c2ecf20Sopenharmony_ci int r = 0; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci BUG_ON(!ops); 10668c2ecf20Sopenharmony_ci switch (cmd) { 10678c2ecf20Sopenharmony_ci case OMAPFB_MIRROR: 10688c2ecf20Sopenharmony_ci if (get_user(p.mirror, (int __user *)arg)) 10698c2ecf20Sopenharmony_ci r = -EFAULT; 10708c2ecf20Sopenharmony_ci else 10718c2ecf20Sopenharmony_ci omapfb_mirror(fbi, p.mirror); 10728c2ecf20Sopenharmony_ci break; 10738c2ecf20Sopenharmony_ci case OMAPFB_SYNC_GFX: 10748c2ecf20Sopenharmony_ci omapfb_sync(fbi); 10758c2ecf20Sopenharmony_ci break; 10768c2ecf20Sopenharmony_ci case OMAPFB_VSYNC: 10778c2ecf20Sopenharmony_ci break; 10788c2ecf20Sopenharmony_ci case OMAPFB_SET_UPDATE_MODE: 10798c2ecf20Sopenharmony_ci if (get_user(p.update_mode, (int __user *)arg)) 10808c2ecf20Sopenharmony_ci r = -EFAULT; 10818c2ecf20Sopenharmony_ci else 10828c2ecf20Sopenharmony_ci r = omapfb_set_update_mode(fbdev, p.update_mode); 10838c2ecf20Sopenharmony_ci break; 10848c2ecf20Sopenharmony_ci case OMAPFB_GET_UPDATE_MODE: 10858c2ecf20Sopenharmony_ci p.update_mode = omapfb_get_update_mode(fbdev); 10868c2ecf20Sopenharmony_ci if (put_user(p.update_mode, 10878c2ecf20Sopenharmony_ci (enum omapfb_update_mode __user *)arg)) 10888c2ecf20Sopenharmony_ci r = -EFAULT; 10898c2ecf20Sopenharmony_ci break; 10908c2ecf20Sopenharmony_ci case OMAPFB_UPDATE_WINDOW_OLD: 10918c2ecf20Sopenharmony_ci if (copy_from_user(&p.update_window, (void __user *)arg, 10928c2ecf20Sopenharmony_ci sizeof(struct omapfb_update_window_old))) 10938c2ecf20Sopenharmony_ci r = -EFAULT; 10948c2ecf20Sopenharmony_ci else { 10958c2ecf20Sopenharmony_ci struct omapfb_update_window *u = &p.update_window; 10968c2ecf20Sopenharmony_ci u->out_x = u->x; 10978c2ecf20Sopenharmony_ci u->out_y = u->y; 10988c2ecf20Sopenharmony_ci u->out_width = u->width; 10998c2ecf20Sopenharmony_ci u->out_height = u->height; 11008c2ecf20Sopenharmony_ci memset(u->reserved, 0, sizeof(u->reserved)); 11018c2ecf20Sopenharmony_ci r = omapfb_update_win(fbi, u); 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci break; 11048c2ecf20Sopenharmony_ci case OMAPFB_UPDATE_WINDOW: 11058c2ecf20Sopenharmony_ci if (copy_from_user(&p.update_window, (void __user *)arg, 11068c2ecf20Sopenharmony_ci sizeof(p.update_window))) 11078c2ecf20Sopenharmony_ci r = -EFAULT; 11088c2ecf20Sopenharmony_ci else 11098c2ecf20Sopenharmony_ci r = omapfb_update_win(fbi, &p.update_window); 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci case OMAPFB_SETUP_PLANE: 11128c2ecf20Sopenharmony_ci if (copy_from_user(&p.plane_info, (void __user *)arg, 11138c2ecf20Sopenharmony_ci sizeof(p.plane_info))) 11148c2ecf20Sopenharmony_ci r = -EFAULT; 11158c2ecf20Sopenharmony_ci else 11168c2ecf20Sopenharmony_ci r = omapfb_setup_plane(fbi, &p.plane_info); 11178c2ecf20Sopenharmony_ci break; 11188c2ecf20Sopenharmony_ci case OMAPFB_QUERY_PLANE: 11198c2ecf20Sopenharmony_ci if ((r = omapfb_query_plane(fbi, &p.plane_info)) < 0) 11208c2ecf20Sopenharmony_ci break; 11218c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)arg, &p.plane_info, 11228c2ecf20Sopenharmony_ci sizeof(p.plane_info))) 11238c2ecf20Sopenharmony_ci r = -EFAULT; 11248c2ecf20Sopenharmony_ci break; 11258c2ecf20Sopenharmony_ci case OMAPFB_SETUP_MEM: 11268c2ecf20Sopenharmony_ci if (copy_from_user(&p.mem_info, (void __user *)arg, 11278c2ecf20Sopenharmony_ci sizeof(p.mem_info))) 11288c2ecf20Sopenharmony_ci r = -EFAULT; 11298c2ecf20Sopenharmony_ci else 11308c2ecf20Sopenharmony_ci r = omapfb_setup_mem(fbi, &p.mem_info); 11318c2ecf20Sopenharmony_ci break; 11328c2ecf20Sopenharmony_ci case OMAPFB_QUERY_MEM: 11338c2ecf20Sopenharmony_ci if ((r = omapfb_query_mem(fbi, &p.mem_info)) < 0) 11348c2ecf20Sopenharmony_ci break; 11358c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)arg, &p.mem_info, 11368c2ecf20Sopenharmony_ci sizeof(p.mem_info))) 11378c2ecf20Sopenharmony_ci r = -EFAULT; 11388c2ecf20Sopenharmony_ci break; 11398c2ecf20Sopenharmony_ci case OMAPFB_SET_COLOR_KEY: 11408c2ecf20Sopenharmony_ci if (copy_from_user(&p.color_key, (void __user *)arg, 11418c2ecf20Sopenharmony_ci sizeof(p.color_key))) 11428c2ecf20Sopenharmony_ci r = -EFAULT; 11438c2ecf20Sopenharmony_ci else 11448c2ecf20Sopenharmony_ci r = omapfb_set_color_key(fbdev, &p.color_key); 11458c2ecf20Sopenharmony_ci break; 11468c2ecf20Sopenharmony_ci case OMAPFB_GET_COLOR_KEY: 11478c2ecf20Sopenharmony_ci if ((r = omapfb_get_color_key(fbdev, &p.color_key)) < 0) 11488c2ecf20Sopenharmony_ci break; 11498c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)arg, &p.color_key, 11508c2ecf20Sopenharmony_ci sizeof(p.color_key))) 11518c2ecf20Sopenharmony_ci r = -EFAULT; 11528c2ecf20Sopenharmony_ci break; 11538c2ecf20Sopenharmony_ci case OMAPFB_GET_CAPS: 11548c2ecf20Sopenharmony_ci omapfb_get_caps(fbdev, plane->idx, &p.caps); 11558c2ecf20Sopenharmony_ci if (copy_to_user((void __user *)arg, &p.caps, sizeof(p.caps))) 11568c2ecf20Sopenharmony_ci r = -EFAULT; 11578c2ecf20Sopenharmony_ci break; 11588c2ecf20Sopenharmony_ci case OMAPFB_LCD_TEST: 11598c2ecf20Sopenharmony_ci { 11608c2ecf20Sopenharmony_ci int test_num; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (get_user(test_num, (int __user *)arg)) { 11638c2ecf20Sopenharmony_ci r = -EFAULT; 11648c2ecf20Sopenharmony_ci break; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci if (!fbdev->panel->run_test) { 11678c2ecf20Sopenharmony_ci r = -EINVAL; 11688c2ecf20Sopenharmony_ci break; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci r = fbdev->panel->run_test(fbdev->panel, test_num); 11718c2ecf20Sopenharmony_ci break; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci case OMAPFB_CTRL_TEST: 11748c2ecf20Sopenharmony_ci { 11758c2ecf20Sopenharmony_ci int test_num; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci if (get_user(test_num, (int __user *)arg)) { 11788c2ecf20Sopenharmony_ci r = -EFAULT; 11798c2ecf20Sopenharmony_ci break; 11808c2ecf20Sopenharmony_ci } 11818c2ecf20Sopenharmony_ci if (!fbdev->ctrl->run_test) { 11828c2ecf20Sopenharmony_ci r = -EINVAL; 11838c2ecf20Sopenharmony_ci break; 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci r = fbdev->ctrl->run_test(test_num); 11868c2ecf20Sopenharmony_ci break; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci default: 11898c2ecf20Sopenharmony_ci r = -EINVAL; 11908c2ecf20Sopenharmony_ci } 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci return r; 11938c2ecf20Sopenharmony_ci} 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_cistatic int omapfb_mmap(struct fb_info *info, struct vm_area_struct *vma) 11968c2ecf20Sopenharmony_ci{ 11978c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane = info->par; 11988c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = plane->fbdev; 11998c2ecf20Sopenharmony_ci int r; 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci omapfb_rqueue_lock(fbdev); 12028c2ecf20Sopenharmony_ci r = fbdev->ctrl->mmap(info, vma); 12038c2ecf20Sopenharmony_ci omapfb_rqueue_unlock(fbdev); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci return r; 12068c2ecf20Sopenharmony_ci} 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci/* 12098c2ecf20Sopenharmony_ci * Callback table for the frame buffer framework. Some of these pointers 12108c2ecf20Sopenharmony_ci * will be changed according to the current setting of fb_info->accel_flags. 12118c2ecf20Sopenharmony_ci */ 12128c2ecf20Sopenharmony_cistatic struct fb_ops omapfb_ops = { 12138c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12148c2ecf20Sopenharmony_ci .fb_open = omapfb_open, 12158c2ecf20Sopenharmony_ci .fb_release = omapfb_release, 12168c2ecf20Sopenharmony_ci .fb_setcolreg = omapfb_setcolreg, 12178c2ecf20Sopenharmony_ci .fb_setcmap = omapfb_setcmap, 12188c2ecf20Sopenharmony_ci .fb_fillrect = cfb_fillrect, 12198c2ecf20Sopenharmony_ci .fb_copyarea = cfb_copyarea, 12208c2ecf20Sopenharmony_ci .fb_imageblit = cfb_imageblit, 12218c2ecf20Sopenharmony_ci .fb_blank = omapfb_blank, 12228c2ecf20Sopenharmony_ci .fb_ioctl = omapfb_ioctl, 12238c2ecf20Sopenharmony_ci .fb_check_var = omapfb_check_var, 12248c2ecf20Sopenharmony_ci .fb_set_par = omapfb_set_par, 12258c2ecf20Sopenharmony_ci .fb_pan_display = omapfb_pan_display, 12268c2ecf20Sopenharmony_ci}; 12278c2ecf20Sopenharmony_ci 12288c2ecf20Sopenharmony_ci/* 12298c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 12308c2ecf20Sopenharmony_ci * Sysfs interface 12318c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 12328c2ecf20Sopenharmony_ci */ 12338c2ecf20Sopenharmony_ci/* omapfbX sysfs entries */ 12348c2ecf20Sopenharmony_cistatic ssize_t omapfb_show_caps_num(struct device *dev, 12358c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 12388c2ecf20Sopenharmony_ci int plane; 12398c2ecf20Sopenharmony_ci size_t size; 12408c2ecf20Sopenharmony_ci struct omapfb_caps caps; 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci plane = 0; 12438c2ecf20Sopenharmony_ci size = 0; 12448c2ecf20Sopenharmony_ci while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { 12458c2ecf20Sopenharmony_ci omapfb_get_caps(fbdev, plane, &caps); 12468c2ecf20Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 12478c2ecf20Sopenharmony_ci "plane#%d %#010x %#010x %#010x\n", 12488c2ecf20Sopenharmony_ci plane, caps.ctrl, caps.plane_color, caps.wnd_color); 12498c2ecf20Sopenharmony_ci plane++; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci return size; 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic ssize_t omapfb_show_caps_text(struct device *dev, 12558c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 12568c2ecf20Sopenharmony_ci{ 12578c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 12588c2ecf20Sopenharmony_ci int i; 12598c2ecf20Sopenharmony_ci struct omapfb_caps caps; 12608c2ecf20Sopenharmony_ci int plane; 12618c2ecf20Sopenharmony_ci size_t size; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci plane = 0; 12648c2ecf20Sopenharmony_ci size = 0; 12658c2ecf20Sopenharmony_ci while (size < PAGE_SIZE && plane < OMAPFB_PLANE_NUM) { 12668c2ecf20Sopenharmony_ci omapfb_get_caps(fbdev, plane, &caps); 12678c2ecf20Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 12688c2ecf20Sopenharmony_ci "plane#%d:\n", plane); 12698c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ctrl_caps) && 12708c2ecf20Sopenharmony_ci size < PAGE_SIZE; i++) { 12718c2ecf20Sopenharmony_ci if (ctrl_caps[i].flag & caps.ctrl) 12728c2ecf20Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 12738c2ecf20Sopenharmony_ci " %s\n", ctrl_caps[i].name); 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 12768c2ecf20Sopenharmony_ci " plane colors:\n"); 12778c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(color_caps) && 12788c2ecf20Sopenharmony_ci size < PAGE_SIZE; i++) { 12798c2ecf20Sopenharmony_ci if (color_caps[i].flag & caps.plane_color) 12808c2ecf20Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 12818c2ecf20Sopenharmony_ci " %s\n", color_caps[i].name); 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 12848c2ecf20Sopenharmony_ci " window colors:\n"); 12858c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(color_caps) && 12868c2ecf20Sopenharmony_ci size < PAGE_SIZE; i++) { 12878c2ecf20Sopenharmony_ci if (color_caps[i].flag & caps.wnd_color) 12888c2ecf20Sopenharmony_ci size += scnprintf(&buf[size], PAGE_SIZE - size, 12898c2ecf20Sopenharmony_ci " %s\n", color_caps[i].name); 12908c2ecf20Sopenharmony_ci } 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci plane++; 12938c2ecf20Sopenharmony_ci } 12948c2ecf20Sopenharmony_ci return size; 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_cistatic DEVICE_ATTR(caps_num, 0444, omapfb_show_caps_num, NULL); 12988c2ecf20Sopenharmony_cistatic DEVICE_ATTR(caps_text, 0444, omapfb_show_caps_text, NULL); 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci/* panel sysfs entries */ 13018c2ecf20Sopenharmony_cistatic ssize_t omapfb_show_panel_name(struct device *dev, 13028c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13038c2ecf20Sopenharmony_ci{ 13048c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->panel->name); 13078c2ecf20Sopenharmony_ci} 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_cistatic ssize_t omapfb_show_bklight_level(struct device *dev, 13108c2ecf20Sopenharmony_ci struct device_attribute *attr, 13118c2ecf20Sopenharmony_ci char *buf) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 13148c2ecf20Sopenharmony_ci int r; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci if (fbdev->panel->get_bklight_level) { 13178c2ecf20Sopenharmony_ci r = snprintf(buf, PAGE_SIZE, "%d\n", 13188c2ecf20Sopenharmony_ci fbdev->panel->get_bklight_level(fbdev->panel)); 13198c2ecf20Sopenharmony_ci } else 13208c2ecf20Sopenharmony_ci r = -ENODEV; 13218c2ecf20Sopenharmony_ci return r; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic ssize_t omapfb_store_bklight_level(struct device *dev, 13258c2ecf20Sopenharmony_ci struct device_attribute *attr, 13268c2ecf20Sopenharmony_ci const char *buf, size_t size) 13278c2ecf20Sopenharmony_ci{ 13288c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 13298c2ecf20Sopenharmony_ci int r; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci if (fbdev->panel->set_bklight_level) { 13328c2ecf20Sopenharmony_ci unsigned int level; 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci if (sscanf(buf, "%10d", &level) == 1) { 13358c2ecf20Sopenharmony_ci r = fbdev->panel->set_bklight_level(fbdev->panel, 13368c2ecf20Sopenharmony_ci level); 13378c2ecf20Sopenharmony_ci } else 13388c2ecf20Sopenharmony_ci r = -EINVAL; 13398c2ecf20Sopenharmony_ci } else 13408c2ecf20Sopenharmony_ci r = -ENODEV; 13418c2ecf20Sopenharmony_ci return r ? r : size; 13428c2ecf20Sopenharmony_ci} 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_cistatic ssize_t omapfb_show_bklight_max(struct device *dev, 13458c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 13488c2ecf20Sopenharmony_ci int r; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci if (fbdev->panel->get_bklight_level) { 13518c2ecf20Sopenharmony_ci r = snprintf(buf, PAGE_SIZE, "%d\n", 13528c2ecf20Sopenharmony_ci fbdev->panel->get_bklight_max(fbdev->panel)); 13538c2ecf20Sopenharmony_ci } else 13548c2ecf20Sopenharmony_ci r = -ENODEV; 13558c2ecf20Sopenharmony_ci return r; 13568c2ecf20Sopenharmony_ci} 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_panel_name = 13598c2ecf20Sopenharmony_ci __ATTR(name, 0444, omapfb_show_panel_name, NULL); 13608c2ecf20Sopenharmony_cistatic DEVICE_ATTR(backlight_level, 0664, 13618c2ecf20Sopenharmony_ci omapfb_show_bklight_level, omapfb_store_bklight_level); 13628c2ecf20Sopenharmony_cistatic DEVICE_ATTR(backlight_max, 0444, omapfb_show_bklight_max, NULL); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cistatic struct attribute *panel_attrs[] = { 13658c2ecf20Sopenharmony_ci &dev_attr_panel_name.attr, 13668c2ecf20Sopenharmony_ci &dev_attr_backlight_level.attr, 13678c2ecf20Sopenharmony_ci &dev_attr_backlight_max.attr, 13688c2ecf20Sopenharmony_ci NULL, 13698c2ecf20Sopenharmony_ci}; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_cistatic const struct attribute_group panel_attr_grp = { 13728c2ecf20Sopenharmony_ci .name = "panel", 13738c2ecf20Sopenharmony_ci .attrs = panel_attrs, 13748c2ecf20Sopenharmony_ci}; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci/* ctrl sysfs entries */ 13778c2ecf20Sopenharmony_cistatic ssize_t omapfb_show_ctrl_name(struct device *dev, 13788c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 13798c2ecf20Sopenharmony_ci{ 13808c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = dev_get_drvdata(dev); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci return snprintf(buf, PAGE_SIZE, "%s\n", fbdev->ctrl->name); 13838c2ecf20Sopenharmony_ci} 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_cistatic struct device_attribute dev_attr_ctrl_name = 13868c2ecf20Sopenharmony_ci __ATTR(name, 0444, omapfb_show_ctrl_name, NULL); 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_cistatic struct attribute *ctrl_attrs[] = { 13898c2ecf20Sopenharmony_ci &dev_attr_ctrl_name.attr, 13908c2ecf20Sopenharmony_ci NULL, 13918c2ecf20Sopenharmony_ci}; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_cistatic const struct attribute_group ctrl_attr_grp = { 13948c2ecf20Sopenharmony_ci .name = "ctrl", 13958c2ecf20Sopenharmony_ci .attrs = ctrl_attrs, 13968c2ecf20Sopenharmony_ci}; 13978c2ecf20Sopenharmony_ci 13988c2ecf20Sopenharmony_cistatic int omapfb_register_sysfs(struct omapfb_device *fbdev) 13998c2ecf20Sopenharmony_ci{ 14008c2ecf20Sopenharmony_ci int r; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci if ((r = device_create_file(fbdev->dev, &dev_attr_caps_num))) 14038c2ecf20Sopenharmony_ci goto fail0; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci if ((r = device_create_file(fbdev->dev, &dev_attr_caps_text))) 14068c2ecf20Sopenharmony_ci goto fail1; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci if ((r = sysfs_create_group(&fbdev->dev->kobj, &panel_attr_grp))) 14098c2ecf20Sopenharmony_ci goto fail2; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci if ((r = sysfs_create_group(&fbdev->dev->kobj, &ctrl_attr_grp))) 14128c2ecf20Sopenharmony_ci goto fail3; 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci return 0; 14158c2ecf20Sopenharmony_cifail3: 14168c2ecf20Sopenharmony_ci sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); 14178c2ecf20Sopenharmony_cifail2: 14188c2ecf20Sopenharmony_ci device_remove_file(fbdev->dev, &dev_attr_caps_text); 14198c2ecf20Sopenharmony_cifail1: 14208c2ecf20Sopenharmony_ci device_remove_file(fbdev->dev, &dev_attr_caps_num); 14218c2ecf20Sopenharmony_cifail0: 14228c2ecf20Sopenharmony_ci dev_err(fbdev->dev, "unable to register sysfs interface\n"); 14238c2ecf20Sopenharmony_ci return r; 14248c2ecf20Sopenharmony_ci} 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_cistatic void omapfb_unregister_sysfs(struct omapfb_device *fbdev) 14278c2ecf20Sopenharmony_ci{ 14288c2ecf20Sopenharmony_ci sysfs_remove_group(&fbdev->dev->kobj, &ctrl_attr_grp); 14298c2ecf20Sopenharmony_ci sysfs_remove_group(&fbdev->dev->kobj, &panel_attr_grp); 14308c2ecf20Sopenharmony_ci device_remove_file(fbdev->dev, &dev_attr_caps_num); 14318c2ecf20Sopenharmony_ci device_remove_file(fbdev->dev, &dev_attr_caps_text); 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci/* 14358c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 14368c2ecf20Sopenharmony_ci * LDM callbacks 14378c2ecf20Sopenharmony_ci * --------------------------------------------------------------------------- 14388c2ecf20Sopenharmony_ci */ 14398c2ecf20Sopenharmony_ci/* Initialize system fb_info object and set the default video mode. 14408c2ecf20Sopenharmony_ci * The frame buffer memory already allocated by lcddma_init 14418c2ecf20Sopenharmony_ci */ 14428c2ecf20Sopenharmony_cistatic int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info) 14438c2ecf20Sopenharmony_ci{ 14448c2ecf20Sopenharmony_ci struct fb_var_screeninfo *var = &info->var; 14458c2ecf20Sopenharmony_ci struct fb_fix_screeninfo *fix = &info->fix; 14468c2ecf20Sopenharmony_ci int r = 0; 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci info->fbops = &omapfb_ops; 14498c2ecf20Sopenharmony_ci info->flags = FBINFO_FLAG_DEFAULT; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci strncpy(fix->id, MODULE_NAME, sizeof(fix->id)); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci info->pseudo_palette = fbdev->pseudo_palette; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci var->accel_flags = def_accel ? FB_ACCELF_TEXT : 0; 14568c2ecf20Sopenharmony_ci var->xres = def_vxres; 14578c2ecf20Sopenharmony_ci var->yres = def_vyres; 14588c2ecf20Sopenharmony_ci var->xres_virtual = def_vxres; 14598c2ecf20Sopenharmony_ci var->yres_virtual = def_vyres; 14608c2ecf20Sopenharmony_ci var->rotate = def_rotate; 14618c2ecf20Sopenharmony_ci var->bits_per_pixel = fbdev->panel->bpp; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci set_fb_var(info, var); 14648c2ecf20Sopenharmony_ci set_fb_fix(info, 1); 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci r = fb_alloc_cmap(&info->cmap, 16, 0); 14678c2ecf20Sopenharmony_ci if (r != 0) 14688c2ecf20Sopenharmony_ci dev_err(fbdev->dev, "unable to allocate color map memory\n"); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci return r; 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci/* Release the fb_info object */ 14748c2ecf20Sopenharmony_cistatic void fbinfo_cleanup(struct omapfb_device *fbdev, struct fb_info *fbi) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci fb_dealloc_cmap(&fbi->cmap); 14778c2ecf20Sopenharmony_ci} 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic void planes_cleanup(struct omapfb_device *fbdev) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci int i; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 14848c2ecf20Sopenharmony_ci if (fbdev->fb_info[i] == NULL) 14858c2ecf20Sopenharmony_ci break; 14868c2ecf20Sopenharmony_ci fbinfo_cleanup(fbdev, fbdev->fb_info[i]); 14878c2ecf20Sopenharmony_ci framebuffer_release(fbdev->fb_info[i]); 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci} 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_cistatic int planes_init(struct omapfb_device *fbdev) 14928c2ecf20Sopenharmony_ci{ 14938c2ecf20Sopenharmony_ci struct fb_info *fbi; 14948c2ecf20Sopenharmony_ci int i; 14958c2ecf20Sopenharmony_ci int r; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 14988c2ecf20Sopenharmony_ci struct omapfb_plane_struct *plane; 14998c2ecf20Sopenharmony_ci fbi = framebuffer_alloc(sizeof(struct omapfb_plane_struct), 15008c2ecf20Sopenharmony_ci fbdev->dev); 15018c2ecf20Sopenharmony_ci if (fbi == NULL) { 15028c2ecf20Sopenharmony_ci planes_cleanup(fbdev); 15038c2ecf20Sopenharmony_ci return -ENOMEM; 15048c2ecf20Sopenharmony_ci } 15058c2ecf20Sopenharmony_ci plane = fbi->par; 15068c2ecf20Sopenharmony_ci plane->idx = i; 15078c2ecf20Sopenharmony_ci plane->fbdev = fbdev; 15088c2ecf20Sopenharmony_ci plane->info.mirror = def_mirror; 15098c2ecf20Sopenharmony_ci fbdev->fb_info[i] = fbi; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci if ((r = fbinfo_init(fbdev, fbi)) < 0) { 15128c2ecf20Sopenharmony_ci framebuffer_release(fbi); 15138c2ecf20Sopenharmony_ci planes_cleanup(fbdev); 15148c2ecf20Sopenharmony_ci return r; 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci plane->info.out_width = fbi->var.xres; 15178c2ecf20Sopenharmony_ci plane->info.out_height = fbi->var.yres; 15188c2ecf20Sopenharmony_ci } 15198c2ecf20Sopenharmony_ci return 0; 15208c2ecf20Sopenharmony_ci} 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci/* 15238c2ecf20Sopenharmony_ci * Free driver resources. Can be called to rollback an aborted initialization 15248c2ecf20Sopenharmony_ci * sequence. 15258c2ecf20Sopenharmony_ci */ 15268c2ecf20Sopenharmony_cistatic void omapfb_free_resources(struct omapfb_device *fbdev, int state) 15278c2ecf20Sopenharmony_ci{ 15288c2ecf20Sopenharmony_ci int i; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci switch (state) { 15318c2ecf20Sopenharmony_ci case OMAPFB_ACTIVE: 15328c2ecf20Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) 15338c2ecf20Sopenharmony_ci unregister_framebuffer(fbdev->fb_info[i]); 15348c2ecf20Sopenharmony_ci fallthrough; 15358c2ecf20Sopenharmony_ci case 7: 15368c2ecf20Sopenharmony_ci omapfb_unregister_sysfs(fbdev); 15378c2ecf20Sopenharmony_ci fallthrough; 15388c2ecf20Sopenharmony_ci case 6: 15398c2ecf20Sopenharmony_ci if (fbdev->panel->disable) 15408c2ecf20Sopenharmony_ci fbdev->panel->disable(fbdev->panel); 15418c2ecf20Sopenharmony_ci fallthrough; 15428c2ecf20Sopenharmony_ci case 5: 15438c2ecf20Sopenharmony_ci omapfb_set_update_mode(fbdev, OMAPFB_UPDATE_DISABLED); 15448c2ecf20Sopenharmony_ci fallthrough; 15458c2ecf20Sopenharmony_ci case 4: 15468c2ecf20Sopenharmony_ci planes_cleanup(fbdev); 15478c2ecf20Sopenharmony_ci fallthrough; 15488c2ecf20Sopenharmony_ci case 3: 15498c2ecf20Sopenharmony_ci ctrl_cleanup(fbdev); 15508c2ecf20Sopenharmony_ci fallthrough; 15518c2ecf20Sopenharmony_ci case 2: 15528c2ecf20Sopenharmony_ci if (fbdev->panel->cleanup) 15538c2ecf20Sopenharmony_ci fbdev->panel->cleanup(fbdev->panel); 15548c2ecf20Sopenharmony_ci fallthrough; 15558c2ecf20Sopenharmony_ci case 1: 15568c2ecf20Sopenharmony_ci dev_set_drvdata(fbdev->dev, NULL); 15578c2ecf20Sopenharmony_ci kfree(fbdev); 15588c2ecf20Sopenharmony_ci case 0: 15598c2ecf20Sopenharmony_ci /* nothing to free */ 15608c2ecf20Sopenharmony_ci break; 15618c2ecf20Sopenharmony_ci default: 15628c2ecf20Sopenharmony_ci BUG(); 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci} 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_cistatic int omapfb_find_ctrl(struct omapfb_device *fbdev) 15678c2ecf20Sopenharmony_ci{ 15688c2ecf20Sopenharmony_ci struct omapfb_platform_data *conf; 15698c2ecf20Sopenharmony_ci char name[17]; 15708c2ecf20Sopenharmony_ci int i; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci conf = dev_get_platdata(fbdev->dev); 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci fbdev->ctrl = NULL; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci strncpy(name, conf->lcd.ctrl_name, sizeof(name) - 1); 15778c2ecf20Sopenharmony_ci name[sizeof(name) - 1] = '\0'; 15788c2ecf20Sopenharmony_ci 15798c2ecf20Sopenharmony_ci if (strcmp(name, "internal") == 0) { 15808c2ecf20Sopenharmony_ci fbdev->ctrl = fbdev->int_ctrl; 15818c2ecf20Sopenharmony_ci return 0; 15828c2ecf20Sopenharmony_ci } 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ctrls); i++) { 15858c2ecf20Sopenharmony_ci dev_dbg(fbdev->dev, "ctrl %s\n", ctrls[i]->name); 15868c2ecf20Sopenharmony_ci if (strcmp(ctrls[i]->name, name) == 0) { 15878c2ecf20Sopenharmony_ci fbdev->ctrl = ctrls[i]; 15888c2ecf20Sopenharmony_ci break; 15898c2ecf20Sopenharmony_ci } 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci if (fbdev->ctrl == NULL) { 15938c2ecf20Sopenharmony_ci dev_dbg(fbdev->dev, "ctrl %s not supported\n", name); 15948c2ecf20Sopenharmony_ci return -1; 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci return 0; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci/* 16018c2ecf20Sopenharmony_ci * Called by LDM binding to probe and attach a new device. 16028c2ecf20Sopenharmony_ci * Initialization sequence: 16038c2ecf20Sopenharmony_ci * 1. allocate system omapfb_device structure 16048c2ecf20Sopenharmony_ci * 2. select controller type according to platform configuration 16058c2ecf20Sopenharmony_ci * init LCD panel 16068c2ecf20Sopenharmony_ci * 3. init LCD controller and LCD DMA 16078c2ecf20Sopenharmony_ci * 4. init system fb_info structure for all planes 16088c2ecf20Sopenharmony_ci * 5. setup video mode for first plane and enable it 16098c2ecf20Sopenharmony_ci * 6. enable LCD panel 16108c2ecf20Sopenharmony_ci * 7. register sysfs attributes 16118c2ecf20Sopenharmony_ci * OMAPFB_ACTIVE: register system fb_info structure for all planes 16128c2ecf20Sopenharmony_ci */ 16138c2ecf20Sopenharmony_cistatic int omapfb_do_probe(struct platform_device *pdev, 16148c2ecf20Sopenharmony_ci struct lcd_panel *panel) 16158c2ecf20Sopenharmony_ci{ 16168c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = NULL; 16178c2ecf20Sopenharmony_ci int init_state; 16188c2ecf20Sopenharmony_ci unsigned long phz, hhz, vhz; 16198c2ecf20Sopenharmony_ci unsigned long vram; 16208c2ecf20Sopenharmony_ci int i; 16218c2ecf20Sopenharmony_ci int r = 0; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci init_state = 0; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci if (pdev->num_resources != 0) { 16268c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "probed for an unknown device\n"); 16278c2ecf20Sopenharmony_ci r = -ENODEV; 16288c2ecf20Sopenharmony_ci goto cleanup; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (dev_get_platdata(&pdev->dev) == NULL) { 16328c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "missing platform data\n"); 16338c2ecf20Sopenharmony_ci r = -ENOENT; 16348c2ecf20Sopenharmony_ci goto cleanup; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); 16388c2ecf20Sopenharmony_ci if (fbdev == NULL) { 16398c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 16408c2ecf20Sopenharmony_ci "unable to allocate memory for device info\n"); 16418c2ecf20Sopenharmony_ci r = -ENOMEM; 16428c2ecf20Sopenharmony_ci goto cleanup; 16438c2ecf20Sopenharmony_ci } 16448c2ecf20Sopenharmony_ci init_state++; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci fbdev->dev = &pdev->dev; 16478c2ecf20Sopenharmony_ci fbdev->panel = panel; 16488c2ecf20Sopenharmony_ci fbdev->dssdev = &omapdss_device; 16498c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, fbdev); 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci mutex_init(&fbdev->rqueue_mutex); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci fbdev->int_ctrl = &omap1_int_ctrl; 16548c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_OMAP_LCDC_EXTERNAL 16558c2ecf20Sopenharmony_ci fbdev->ext_if = &omap1_ext_if; 16568c2ecf20Sopenharmony_ci#endif 16578c2ecf20Sopenharmony_ci if (omapfb_find_ctrl(fbdev) < 0) { 16588c2ecf20Sopenharmony_ci dev_err(fbdev->dev, 16598c2ecf20Sopenharmony_ci "LCD controller not found, board not supported\n"); 16608c2ecf20Sopenharmony_ci r = -ENODEV; 16618c2ecf20Sopenharmony_ci goto cleanup; 16628c2ecf20Sopenharmony_ci } 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci if (fbdev->panel->init) { 16658c2ecf20Sopenharmony_ci r = fbdev->panel->init(fbdev->panel, fbdev); 16668c2ecf20Sopenharmony_ci if (r) 16678c2ecf20Sopenharmony_ci goto cleanup; 16688c2ecf20Sopenharmony_ci } 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci pr_info("omapfb: configured for panel %s\n", fbdev->panel->name); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci def_vxres = def_vxres ? def_vxres : fbdev->panel->x_res; 16738c2ecf20Sopenharmony_ci def_vyres = def_vyres ? def_vyres : fbdev->panel->y_res; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci init_state++; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci r = ctrl_init(fbdev); 16788c2ecf20Sopenharmony_ci if (r) 16798c2ecf20Sopenharmony_ci goto cleanup; 16808c2ecf20Sopenharmony_ci if (fbdev->ctrl->mmap != NULL) 16818c2ecf20Sopenharmony_ci omapfb_ops.fb_mmap = omapfb_mmap; 16828c2ecf20Sopenharmony_ci init_state++; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci r = planes_init(fbdev); 16858c2ecf20Sopenharmony_ci if (r) 16868c2ecf20Sopenharmony_ci goto cleanup; 16878c2ecf20Sopenharmony_ci init_state++; 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci#ifdef CONFIG_FB_OMAP_DMA_TUNE 16908c2ecf20Sopenharmony_ci /* Set DMA priority for EMIFF access to highest */ 16918c2ecf20Sopenharmony_ci omap_set_dma_priority(0, OMAP_DMA_PORT_EMIFF, 15); 16928c2ecf20Sopenharmony_ci#endif 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci r = ctrl_change_mode(fbdev->fb_info[0]); 16958c2ecf20Sopenharmony_ci if (r) { 16968c2ecf20Sopenharmony_ci dev_err(fbdev->dev, "mode setting failed\n"); 16978c2ecf20Sopenharmony_ci goto cleanup; 16988c2ecf20Sopenharmony_ci } 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci /* GFX plane is enabled by default */ 17018c2ecf20Sopenharmony_ci r = fbdev->ctrl->enable_plane(OMAPFB_PLANE_GFX, 1); 17028c2ecf20Sopenharmony_ci if (r) 17038c2ecf20Sopenharmony_ci goto cleanup; 17048c2ecf20Sopenharmony_ci 17058c2ecf20Sopenharmony_ci omapfb_set_update_mode(fbdev, manual_update ? 17068c2ecf20Sopenharmony_ci OMAPFB_MANUAL_UPDATE : OMAPFB_AUTO_UPDATE); 17078c2ecf20Sopenharmony_ci init_state++; 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (fbdev->panel->enable) { 17108c2ecf20Sopenharmony_ci r = fbdev->panel->enable(fbdev->panel); 17118c2ecf20Sopenharmony_ci if (r) 17128c2ecf20Sopenharmony_ci goto cleanup; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci init_state++; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci r = omapfb_register_sysfs(fbdev); 17178c2ecf20Sopenharmony_ci if (r) 17188c2ecf20Sopenharmony_ci goto cleanup; 17198c2ecf20Sopenharmony_ci init_state++; 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci vram = 0; 17228c2ecf20Sopenharmony_ci for (i = 0; i < fbdev->mem_desc.region_cnt; i++) { 17238c2ecf20Sopenharmony_ci r = register_framebuffer(fbdev->fb_info[i]); 17248c2ecf20Sopenharmony_ci if (r != 0) { 17258c2ecf20Sopenharmony_ci dev_err(fbdev->dev, 17268c2ecf20Sopenharmony_ci "registering framebuffer %d failed\n", i); 17278c2ecf20Sopenharmony_ci goto cleanup; 17288c2ecf20Sopenharmony_ci } 17298c2ecf20Sopenharmony_ci vram += fbdev->mem_desc.region[i].size; 17308c2ecf20Sopenharmony_ci } 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci fbdev->state = OMAPFB_ACTIVE; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci panel = fbdev->panel; 17358c2ecf20Sopenharmony_ci phz = panel->pixel_clock * 1000; 17368c2ecf20Sopenharmony_ci hhz = phz * 10 / (panel->hfp + panel->x_res + panel->hbp + panel->hsw); 17378c2ecf20Sopenharmony_ci vhz = hhz / (panel->vfp + panel->y_res + panel->vbp + panel->vsw); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci omapfb_dev = fbdev; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci pr_info("omapfb: Framebuffer initialized. Total vram %lu planes %d\n", 17428c2ecf20Sopenharmony_ci vram, fbdev->mem_desc.region_cnt); 17438c2ecf20Sopenharmony_ci pr_info("omapfb: Pixclock %lu kHz hfreq %lu.%lu kHz " 17448c2ecf20Sopenharmony_ci "vfreq %lu.%lu Hz\n", 17458c2ecf20Sopenharmony_ci phz / 1000, hhz / 10000, hhz % 10, vhz / 10, vhz % 10); 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci return 0; 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_cicleanup: 17508c2ecf20Sopenharmony_ci omapfb_free_resources(fbdev, init_state); 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_ci return r; 17538c2ecf20Sopenharmony_ci} 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_cistatic int omapfb_probe(struct platform_device *pdev) 17568c2ecf20Sopenharmony_ci{ 17578c2ecf20Sopenharmony_ci int r; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci BUG_ON(fbdev_pdev != NULL); 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci r = platform_device_register(&omapdss_device); 17628c2ecf20Sopenharmony_ci if (r) { 17638c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "can't register omapdss device\n"); 17648c2ecf20Sopenharmony_ci return r; 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci /* Delay actual initialization until the LCD is registered */ 17688c2ecf20Sopenharmony_ci fbdev_pdev = pdev; 17698c2ecf20Sopenharmony_ci if (fbdev_panel != NULL) 17708c2ecf20Sopenharmony_ci omapfb_do_probe(fbdev_pdev, fbdev_panel); 17718c2ecf20Sopenharmony_ci return 0; 17728c2ecf20Sopenharmony_ci} 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_civoid omapfb_register_panel(struct lcd_panel *panel) 17758c2ecf20Sopenharmony_ci{ 17768c2ecf20Sopenharmony_ci BUG_ON(fbdev_panel != NULL); 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci fbdev_panel = panel; 17798c2ecf20Sopenharmony_ci if (fbdev_pdev != NULL) 17808c2ecf20Sopenharmony_ci omapfb_do_probe(fbdev_pdev, fbdev_panel); 17818c2ecf20Sopenharmony_ci} 17828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(omapfb_register_panel); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci/* Called when the device is being detached from the driver */ 17858c2ecf20Sopenharmony_cistatic int omapfb_remove(struct platform_device *pdev) 17868c2ecf20Sopenharmony_ci{ 17878c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = platform_get_drvdata(pdev); 17888c2ecf20Sopenharmony_ci enum omapfb_state saved_state = fbdev->state; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci /* FIXME: wait till completion of pending events */ 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci fbdev->state = OMAPFB_DISABLED; 17938c2ecf20Sopenharmony_ci omapfb_free_resources(fbdev, saved_state); 17948c2ecf20Sopenharmony_ci 17958c2ecf20Sopenharmony_ci platform_device_unregister(&omapdss_device); 17968c2ecf20Sopenharmony_ci fbdev->dssdev = NULL; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci return 0; 17998c2ecf20Sopenharmony_ci} 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci/* PM suspend */ 18028c2ecf20Sopenharmony_cistatic int omapfb_suspend(struct platform_device *pdev, pm_message_t mesg) 18038c2ecf20Sopenharmony_ci{ 18048c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = platform_get_drvdata(pdev); 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci if (fbdev != NULL) 18078c2ecf20Sopenharmony_ci omapfb_blank(FB_BLANK_POWERDOWN, fbdev->fb_info[0]); 18088c2ecf20Sopenharmony_ci return 0; 18098c2ecf20Sopenharmony_ci} 18108c2ecf20Sopenharmony_ci 18118c2ecf20Sopenharmony_ci/* PM resume */ 18128c2ecf20Sopenharmony_cistatic int omapfb_resume(struct platform_device *pdev) 18138c2ecf20Sopenharmony_ci{ 18148c2ecf20Sopenharmony_ci struct omapfb_device *fbdev = platform_get_drvdata(pdev); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if (fbdev != NULL) 18178c2ecf20Sopenharmony_ci omapfb_blank(FB_BLANK_UNBLANK, fbdev->fb_info[0]); 18188c2ecf20Sopenharmony_ci return 0; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_cistatic struct platform_driver omapfb_driver = { 18228c2ecf20Sopenharmony_ci .probe = omapfb_probe, 18238c2ecf20Sopenharmony_ci .remove = omapfb_remove, 18248c2ecf20Sopenharmony_ci .suspend = omapfb_suspend, 18258c2ecf20Sopenharmony_ci .resume = omapfb_resume, 18268c2ecf20Sopenharmony_ci .driver = { 18278c2ecf20Sopenharmony_ci .name = MODULE_NAME, 18288c2ecf20Sopenharmony_ci }, 18298c2ecf20Sopenharmony_ci}; 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci#ifndef MODULE 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci/* Process kernel command line parameters */ 18348c2ecf20Sopenharmony_cistatic int __init omapfb_setup(char *options) 18358c2ecf20Sopenharmony_ci{ 18368c2ecf20Sopenharmony_ci char *this_opt = NULL; 18378c2ecf20Sopenharmony_ci int r = 0; 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci pr_debug("omapfb: options %s\n", options); 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (!options || !*options) 18428c2ecf20Sopenharmony_ci return 0; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci while (!r && (this_opt = strsep(&options, ",")) != NULL) { 18458c2ecf20Sopenharmony_ci if (!strncmp(this_opt, "accel", 5)) 18468c2ecf20Sopenharmony_ci def_accel = 1; 18478c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "vram:", 5)) { 18488c2ecf20Sopenharmony_ci char *suffix; 18498c2ecf20Sopenharmony_ci unsigned long vram; 18508c2ecf20Sopenharmony_ci vram = (simple_strtoul(this_opt + 5, &suffix, 0)); 18518c2ecf20Sopenharmony_ci switch (suffix[0]) { 18528c2ecf20Sopenharmony_ci case '\0': 18538c2ecf20Sopenharmony_ci break; 18548c2ecf20Sopenharmony_ci case 'm': 18558c2ecf20Sopenharmony_ci case 'M': 18568c2ecf20Sopenharmony_ci vram *= 1024; 18578c2ecf20Sopenharmony_ci fallthrough; 18588c2ecf20Sopenharmony_ci case 'k': 18598c2ecf20Sopenharmony_ci case 'K': 18608c2ecf20Sopenharmony_ci vram *= 1024; 18618c2ecf20Sopenharmony_ci break; 18628c2ecf20Sopenharmony_ci default: 18638c2ecf20Sopenharmony_ci pr_debug("omapfb: invalid vram suffix %c\n", 18648c2ecf20Sopenharmony_ci suffix[0]); 18658c2ecf20Sopenharmony_ci r = -1; 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci def_vram[def_vram_cnt++] = vram; 18688c2ecf20Sopenharmony_ci } 18698c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "vxres:", 6)) 18708c2ecf20Sopenharmony_ci def_vxres = simple_strtoul(this_opt + 6, NULL, 0); 18718c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "vyres:", 6)) 18728c2ecf20Sopenharmony_ci def_vyres = simple_strtoul(this_opt + 6, NULL, 0); 18738c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "rotate:", 7)) 18748c2ecf20Sopenharmony_ci def_rotate = (simple_strtoul(this_opt + 7, NULL, 0)); 18758c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "mirror:", 7)) 18768c2ecf20Sopenharmony_ci def_mirror = (simple_strtoul(this_opt + 7, NULL, 0)); 18778c2ecf20Sopenharmony_ci else if (!strncmp(this_opt, "manual_update", 13)) 18788c2ecf20Sopenharmony_ci manual_update = 1; 18798c2ecf20Sopenharmony_ci else { 18808c2ecf20Sopenharmony_ci pr_debug("omapfb: invalid option\n"); 18818c2ecf20Sopenharmony_ci r = -1; 18828c2ecf20Sopenharmony_ci } 18838c2ecf20Sopenharmony_ci } 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci return r; 18868c2ecf20Sopenharmony_ci} 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_ci#endif 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci/* Register both the driver and the device */ 18918c2ecf20Sopenharmony_cistatic int __init omapfb_init(void) 18928c2ecf20Sopenharmony_ci{ 18938c2ecf20Sopenharmony_ci#ifndef MODULE 18948c2ecf20Sopenharmony_ci char *option; 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci if (fb_get_options("omapfb", &option)) 18978c2ecf20Sopenharmony_ci return -ENODEV; 18988c2ecf20Sopenharmony_ci omapfb_setup(option); 18998c2ecf20Sopenharmony_ci#endif 19008c2ecf20Sopenharmony_ci /* Register the driver with LDM */ 19018c2ecf20Sopenharmony_ci if (platform_driver_register(&omapfb_driver)) { 19028c2ecf20Sopenharmony_ci pr_debug("failed to register omapfb driver\n"); 19038c2ecf20Sopenharmony_ci return -ENODEV; 19048c2ecf20Sopenharmony_ci } 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_ci return 0; 19078c2ecf20Sopenharmony_ci} 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_cistatic void __exit omapfb_cleanup(void) 19108c2ecf20Sopenharmony_ci{ 19118c2ecf20Sopenharmony_ci platform_driver_unregister(&omapfb_driver); 19128c2ecf20Sopenharmony_ci} 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_cimodule_param_named(accel, def_accel, uint, 0664); 19158c2ecf20Sopenharmony_cimodule_param_array_named(vram, def_vram, ulong, &def_vram_cnt, 0664); 19168c2ecf20Sopenharmony_cimodule_param_named(vxres, def_vxres, long, 0664); 19178c2ecf20Sopenharmony_cimodule_param_named(vyres, def_vyres, long, 0664); 19188c2ecf20Sopenharmony_cimodule_param_named(rotate, def_rotate, uint, 0664); 19198c2ecf20Sopenharmony_cimodule_param_named(mirror, def_mirror, uint, 0664); 19208c2ecf20Sopenharmony_cimodule_param_named(manual_update, manual_update, bool, 0664); 19218c2ecf20Sopenharmony_ci 19228c2ecf20Sopenharmony_cimodule_init(omapfb_init); 19238c2ecf20Sopenharmony_cimodule_exit(omapfb_cleanup); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("TI OMAP framebuffer driver"); 19268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Imre Deak <imre.deak@nokia.com>"); 19278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1928