From 8e4bff4cab0ddac6060645b0715210484d02ff40 Mon Sep 17 00:00:00 2001 From: Yuval Adam <_@yuv.al> Date: Wed, 30 Aug 2017 08:25:59 +0000 Subject: Initial file dump from open source release --- drivers/video/sprdfb/sprdfb_main.c | 888 +++++++++++++++++++++++++++++++++++++ 1 file changed, 888 insertions(+) create mode 100644 drivers/video/sprdfb/sprdfb_main.c (limited to 'drivers/video/sprdfb/sprdfb_main.c') diff --git a/drivers/video/sprdfb/sprdfb_main.c b/drivers/video/sprdfb/sprdfb_main.c new file mode 100644 index 00000000..176715a9 --- /dev/null +++ b/drivers/video/sprdfb/sprdfb_main.c @@ -0,0 +1,888 @@ +/* + * Copyright (C) 2012 Spreadtrum Communications Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define pr_fmt(fmt) "sprdfb: " fmt + +#include +#include +#ifdef CONFIG_HAS_EARLYSUSPEND +#include +#endif +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OF +#include +#include +#include +#endif + +#include +#include "sprdfb_chip_common.h" +#include "sprdfb.h" +#include "sprdfb_panel.h" + +#include + +#ifdef CONFIG_FB_MMAP_CACHED +#include +#include +#endif + +enum{ + SPRD_IN_DATA_TYPE_ABGR888 = 0, + SPRD_IN_DATA_TYPE_BGR565, +/* + SPRD_IN_DATA_TYPE_RGB666, + SPRD_IN_DATA_TYPE_RGB555, + SPRD_IN_DATA_TYPE_PACKET, +*/ /*not support*/ + SPRD_IN_DATA_TYPE_LIMIT +}; + +#define SPRDFB_IN_DATA_TYPE SPRD_IN_DATA_TYPE_ABGR888 + +#ifdef CONFIG_FB_TRIPLE_FRAMEBUFFER +#define FRAMEBUFFER_NR (3) +#else +#define FRAMEBUFFER_NR (2) +#endif + +#define SPRDFB_FRAMES_TO_SKIP (1) + +#define SPRDFB_DEFAULT_FPS (60) + +#define SPRDFB_ESD_TIME_OUT_CMD (2000) + +#define SPRDFB_ESD_TIME_OUT_VIDEO (1000) + +extern bool sprdfb_panel_get(struct sprdfb_device *dev); +extern int sprdfb_panel_probe(struct sprdfb_device *dev); +extern void sprdfb_panel_remove(struct sprdfb_device *dev); + +extern struct display_ctrl sprdfb_dispc_ctrl ; + +#ifdef CONFIG_OF +extern unsigned long g_dispc_base_addr; +#endif + +static unsigned PP[16]; +static int frame_count = 0; + +static int sprdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fb); +static int sprdfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb); +static int sprdfb_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); +#ifdef CONFIG_COMPAT +static long sprdfb_compat_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg); +#endif +#ifdef CONFIG_FB_MMAP_CACHED +static int sprdfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +#endif + +static struct fb_ops sprdfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = sprdfb_check_var, + .fb_pan_display = sprdfb_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_ioctl = sprdfb_ioctl, +#ifdef CONFIG_COMPAT + .fb_compat_ioctl = sprdfb_compat_ioctl, +#endif +#ifdef CONFIG_FB_MMAP_CACHED + .fb_mmap = sprdfb_mmap, +#endif +}; + +#ifdef CONFIG_FB_MMAP_CACHED +static int sprdfb_mmap(struct fb_info *info,struct vm_area_struct *vma) +{ + struct sprdfb_device *dev = NULL; + if(NULL == info){ + printk(KERN_ERR "sprdfb: sprdfb_ioctl error. (Invalid Parameter)"); + return -1; + } + + dev = info->par; + printk("sprdfb: sprdfb_mmap,vma=0x%x\n",vma); + vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); + dev->ctrl->set_vma(vma); + + return vm_iomap_memory(vma, info->fix.smem_start, info->fix.smem_len); +} +#endif + +extern uint32_t lcd_id_from_uboot; + +static struct proc_dir_entry *lcd_user = NULL; + +ssize_t DrvLcdNameRead(struct file *pFile, char __user *pBuffer, size_t nCount, loff_t *pPos) +{ + u32 nLength; + + if (*pPos != 0) + { + return 0; + } + + nLength = sprintf(pBuffer, "%x\n", lcd_id_from_uboot); + + *pPos += nLength; + + return nLength; +} + +ssize_t DrvLcdNameWrite(struct file *pFile, const char __user *pBuffer, size_t nCount, loff_t *pPos) +{ + return nCount; +} + +static const struct file_operations _gProclcdName = { + .read = DrvLcdNameRead, + .write = DrvLcdNameWrite, +}; + + + +static int setup_fb_mem(struct sprdfb_device *dev, struct platform_device *pdev) +{ + uint32_t len; + void *addr; + bool use_reserve_mem; + uint32_t reserve_mem[2]; + int ret; + +#ifdef CONFIG_FB_LOW_RES_SIMU + if ((0!= dev->display_width) && (0 != dev->display_height)) + len = dev->display_width * dev->display_height * (dev->bpp / 8) * FRAMEBUFFER_NR; + else +#endif + len = dev->panel->width * dev->panel->height * (dev->bpp / 8) * FRAMEBUFFER_NR; + +#ifdef CONFIG_OF + use_reserve_mem = of_property_read_bool(pdev->dev.of_node, "sprd,fb_use_reservemem"); + if(use_reserve_mem) { + ret = of_property_read_u32_array(pdev->dev.of_node, "sprd,fb_mem", + reserve_mem, 2); + if(0 != ret) + printk(KERN_ERR "sprdfb: Failed to got framebuffer memory from dt file\n"); + } +#else +#ifdef CONFIG_FB_LCD_RESERVE_MEM + use_reserve_mem = true; + reserve_mem[0] = SPRD_FB_MEM_BASE; + reserve_mem[1] = SPRD_FB_MEM_SIZE; +#else + use_reserve_mem = false; +#endif +#endif + + if(!use_reserve_mem) { + addr = (void*)__get_free_pages(GFP_ATOMIC | __GFP_ZERO, get_order(len)); + if (NULL == addr) { + printk(KERN_ERR "sprdfb: Failed to allocate framebuffer memory\n"); + return -ENOMEM; + } + printk(KERN_INFO "sprdfb: got %d bytes mem at 0x%p\n", len, addr); + + dev->fb->fix.smem_start = __pa(addr); + dev->fb->fix.smem_len = len; + dev->fb->screen_base = (char*)addr; + }else{ + dev->fb->fix.smem_start = reserve_mem[0]; + printk("sprdfb: setup_fb_mem--smem_start:%lx,len:%d,reserved len:%d\n", + dev->fb->fix.smem_start, len, reserve_mem[1]); + addr = ioremap(dev->fb->fix.smem_start, len); + if (NULL == addr) { + printk(KERN_ERR "sprdfb: Unable to map framebuffer base: 0x%p\n", addr); + return -ENOMEM; + } + dev->fb->fix.smem_len = len; + dev->fb->screen_base = (char*)addr; + } + return 0; +} + +static void setup_fb_info(struct sprdfb_device *dev) +{ + struct fb_info *fb = dev->fb; + struct panel_spec *panel = dev->panel; + int r; + + fb->fbops = &sprdfb_ops; + fb->flags = FBINFO_DEFAULT; + + /* finish setting up the fb_info struct */ + strncpy(fb->fix.id, "sprdfb", 16); + fb->fix.ypanstep = 1; + fb->fix.type = FB_TYPE_PACKED_PIXELS; + fb->fix.visual = FB_VISUAL_TRUECOLOR; +#ifdef CONFIG_FB_LOW_RES_SIMU + if((0 != dev->display_width) && (0 != dev->display_height)){ + fb->fix.line_length = dev->display_width * dev->bpp / 8; + + fb->var.xres = dev->display_width; + fb->var.yres = dev->display_height; + fb->var.width = dev->display_width; + fb->var.height = dev->display_height; + + fb->var.xres_virtual = dev->display_width; + fb->var.yres_virtual = dev->display_height * FRAMEBUFFER_NR; + }else +#endif + { + fb->fix.line_length = panel->width * dev->bpp / 8; + + fb->var.xres = panel->width; + fb->var.yres = panel->height; + fb->var.width = panel->width; + fb->var.height = panel->height; + + fb->var.xres_virtual = panel->width; + fb->var.yres_virtual = panel->height * FRAMEBUFFER_NR; + } + fb->var.bits_per_pixel = dev->bpp; +#ifdef CONFIG_FB_LOW_RES_SIMU + if((0 != dev->display_width) && (0 != dev->display_height)){ + if(0 != dev->panel->fps){ + fb->var.pixclock = ((1000000000 /dev->display_width) * 1000) / (dev->panel->fps * dev->display_height); + }else{ + fb->var.pixclock = ((1000000000 /dev->display_width) * 1000) / (SPRDFB_DEFAULT_FPS * dev->display_height); + } + }else +#endif + { + if(0 != dev->panel->fps){ + fb->var.pixclock = ((1000000000 /panel->width) * 1000) / (dev->panel->fps * panel->height); + }else{ + fb->var.pixclock = ((1000000000 /panel->width) * 1000) / (SPRDFB_DEFAULT_FPS * panel->height); + } + } + + fb->var.accel_flags = 0; + fb->var.yoffset = 0; + + /* only support two pixel format */ + if (dev->bpp == 32) { /* ABGR */ + fb->var.red.offset = 16; + fb->var.red.length = 8; + fb->var.red.msb_right = 0; + fb->var.green.offset = 8; + fb->var.green.length = 8; + fb->var.green.msb_right = 0; + fb->var.blue.offset = 0; + fb->var.blue.length = 8; + fb->var.blue.msb_right = 0; + } else { /*BGR*/ + fb->var.red.offset = 11; + fb->var.red.length = 5; + fb->var.red.msb_right = 0; + fb->var.green.offset = 5; + fb->var.green.length = 6; + fb->var.green.msb_right = 0; + fb->var.blue.offset = 0; + fb->var.blue.length = 5; + fb->var.blue.msb_right = 0; + } + r = fb_alloc_cmap(&fb->cmap, 16, 0); + fb->pseudo_palette = PP; + + PP[0] = 0; + for (r = 1; r < 16; r++){ + PP[r] = 0xffffffff; + } +} + +static void fb_free_resources(struct sprdfb_device *dev) +{ + if (dev == NULL) + return; + + if (&dev->fb->cmap != NULL) { + fb_dealloc_cmap(&dev->fb->cmap); + } + if (dev->fb->screen_base) { + free_pages((unsigned long)dev->fb->screen_base, + get_order(dev->fb->fix.smem_len)); + } + unregister_framebuffer(dev->fb); + framebuffer_release(dev->fb); +} + +static int sprdfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fb) +{ + int32_t ret; + struct sprdfb_device *dev = fb->par; + + pr_debug("sprdfb: [%s]\n", __FUNCTION__); + + if(frame_count < SPRDFB_FRAMES_TO_SKIP) { + frame_count++; + return 0; + } + + if(0 == dev->enable){ + printk(KERN_ERR "sprdfb: [%s]: Invalid Device status %d", __FUNCTION__, dev->enable); + return -1; + } + + ret = dev->ctrl->refresh(dev); + if (ret) { + printk(KERN_ERR "sprdfb: failed to refresh !!!!\n"); + return -1; + } + + return 0; +} + +#include