18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/video/hitfb.c -- Hitachi LCD frame buffer device 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * (C) 1999 Mihai Spatar 58c2ecf20Sopenharmony_ci * (C) 2000 YAEGASHI Takeshi 68c2ecf20Sopenharmony_ci * (C) 2003, 2004 Paul Mundt 78c2ecf20Sopenharmony_ci * (C) 2003, 2004, 2006 Andriy Skulysh 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 108c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 118c2ecf20Sopenharmony_ci * more details. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/errno.h> 178c2ecf20Sopenharmony_ci#include <linux/string.h> 188c2ecf20Sopenharmony_ci#include <linux/mm.h> 198c2ecf20Sopenharmony_ci#include <linux/delay.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci#include <linux/fb.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <asm/machvec.h> 258c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 268c2ecf20Sopenharmony_ci#include <asm/io.h> 278c2ecf20Sopenharmony_ci#include <asm/hd64461.h> 288c2ecf20Sopenharmony_ci#include <cpu/dac.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define WIDTH 640 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic struct fb_var_screeninfo hitfb_var = { 338c2ecf20Sopenharmony_ci .activate = FB_ACTIVATE_NOW, 348c2ecf20Sopenharmony_ci .height = -1, 358c2ecf20Sopenharmony_ci .width = -1, 368c2ecf20Sopenharmony_ci .vmode = FB_VMODE_NONINTERLACED, 378c2ecf20Sopenharmony_ci}; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic struct fb_fix_screeninfo hitfb_fix = { 408c2ecf20Sopenharmony_ci .id = "Hitachi HD64461", 418c2ecf20Sopenharmony_ci .type = FB_TYPE_PACKED_PIXELS, 428c2ecf20Sopenharmony_ci .accel = FB_ACCEL_NONE, 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic inline void hitfb_accel_wait(void) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci while (fb_readw(HD64461_GRCFGR) & HD64461_GRCFGR_ACCSTATUS) ; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline void hitfb_accel_start(int truecolor) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci if (truecolor) { 538c2ecf20Sopenharmony_ci fb_writew(6, HD64461_GRCFGR); 548c2ecf20Sopenharmony_ci } else { 558c2ecf20Sopenharmony_ci fb_writew(7, HD64461_GRCFGR); 568c2ecf20Sopenharmony_ci } 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy, 608c2ecf20Sopenharmony_ci u16 width, u16 height) 618c2ecf20Sopenharmony_ci{ 628c2ecf20Sopenharmony_ci u32 saddr = WIDTH * dy + dx; 638c2ecf20Sopenharmony_ci if (truecolor) 648c2ecf20Sopenharmony_ci saddr <<= 1; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci fb_writew(width-1, HD64461_BBTDWR); 678c2ecf20Sopenharmony_ci fb_writew(height-1, HD64461_BBTDHR); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci fb_writew(saddr & 0xffff, HD64461_BBTDSARL); 708c2ecf20Sopenharmony_ci fb_writew(saddr >> 16, HD64461_BBTDSARH); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx, 758c2ecf20Sopenharmony_ci u16 dy, u16 width, u16 height, u16 rop, 768c2ecf20Sopenharmony_ci u32 mask_addr) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci u32 saddr, daddr; 798c2ecf20Sopenharmony_ci u32 maddr = 0; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci height--; 828c2ecf20Sopenharmony_ci width--; 838c2ecf20Sopenharmony_ci fb_writew(rop, HD64461_BBTROPR); 848c2ecf20Sopenharmony_ci if ((sy < dy) || ((sy == dy) && (sx <= dx))) { 858c2ecf20Sopenharmony_ci saddr = WIDTH * (sy + height) + sx + width; 868c2ecf20Sopenharmony_ci daddr = WIDTH * (dy + height) + dx + width; 878c2ecf20Sopenharmony_ci if (mask_addr) { 888c2ecf20Sopenharmony_ci if (truecolor) 898c2ecf20Sopenharmony_ci maddr = ((width >> 3) + 1) * (height + 1) - 1; 908c2ecf20Sopenharmony_ci else 918c2ecf20Sopenharmony_ci maddr = 928c2ecf20Sopenharmony_ci (((width >> 4) + 1) * (height + 1) - 1) * 2; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci fb_writew((1 << 5) | 1, HD64461_BBTMDR); 958c2ecf20Sopenharmony_ci } else 968c2ecf20Sopenharmony_ci fb_writew(1, HD64461_BBTMDR); 978c2ecf20Sopenharmony_ci } else { 988c2ecf20Sopenharmony_ci saddr = WIDTH * sy + sx; 998c2ecf20Sopenharmony_ci daddr = WIDTH * dy + dx; 1008c2ecf20Sopenharmony_ci if (mask_addr) { 1018c2ecf20Sopenharmony_ci fb_writew((1 << 5), HD64461_BBTMDR); 1028c2ecf20Sopenharmony_ci } else { 1038c2ecf20Sopenharmony_ci fb_writew(0, HD64461_BBTMDR); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci if (truecolor) { 1078c2ecf20Sopenharmony_ci saddr <<= 1; 1088c2ecf20Sopenharmony_ci daddr <<= 1; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci fb_writew(width, HD64461_BBTDWR); 1118c2ecf20Sopenharmony_ci fb_writew(height, HD64461_BBTDHR); 1128c2ecf20Sopenharmony_ci fb_writew(saddr & 0xffff, HD64461_BBTSSARL); 1138c2ecf20Sopenharmony_ci fb_writew(saddr >> 16, HD64461_BBTSSARH); 1148c2ecf20Sopenharmony_ci fb_writew(daddr & 0xffff, HD64461_BBTDSARL); 1158c2ecf20Sopenharmony_ci fb_writew(daddr >> 16, HD64461_BBTDSARH); 1168c2ecf20Sopenharmony_ci if (mask_addr) { 1178c2ecf20Sopenharmony_ci maddr += mask_addr; 1188c2ecf20Sopenharmony_ci fb_writew(maddr & 0xffff, HD64461_BBTMARL); 1198c2ecf20Sopenharmony_ci fb_writew(maddr >> 16, HD64461_BBTMARH); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci hitfb_accel_start(truecolor); 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci if (rect->rop != ROP_COPY) 1278c2ecf20Sopenharmony_ci cfb_fillrect(p, rect); 1288c2ecf20Sopenharmony_ci else { 1298c2ecf20Sopenharmony_ci hitfb_accel_wait(); 1308c2ecf20Sopenharmony_ci fb_writew(0x00f0, HD64461_BBTROPR); 1318c2ecf20Sopenharmony_ci fb_writew(16, HD64461_BBTMDR); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (p->var.bits_per_pixel == 16) { 1348c2ecf20Sopenharmony_ci fb_writew(((u32 *) (p->pseudo_palette))[rect->color], 1358c2ecf20Sopenharmony_ci HD64461_GRSCR); 1368c2ecf20Sopenharmony_ci hitfb_accel_set_dest(1, rect->dx, rect->dy, rect->width, 1378c2ecf20Sopenharmony_ci rect->height); 1388c2ecf20Sopenharmony_ci hitfb_accel_start(1); 1398c2ecf20Sopenharmony_ci } else { 1408c2ecf20Sopenharmony_ci fb_writew(rect->color, HD64461_GRSCR); 1418c2ecf20Sopenharmony_ci hitfb_accel_set_dest(0, rect->dx, rect->dy, rect->width, 1428c2ecf20Sopenharmony_ci rect->height); 1438c2ecf20Sopenharmony_ci hitfb_accel_start(0); 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci hitfb_accel_wait(); 1518c2ecf20Sopenharmony_ci hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy, 1528c2ecf20Sopenharmony_ci area->dx, area->dy, area->width, area->height, 1538c2ecf20Sopenharmony_ci 0x00cc, 0); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic int hitfb_pan_display(struct fb_var_screeninfo *var, 1578c2ecf20Sopenharmony_ci struct fb_info *info) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci int xoffset = var->xoffset; 1608c2ecf20Sopenharmony_ci int yoffset = var->yoffset; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (xoffset != 0) 1638c2ecf20Sopenharmony_ci return -EINVAL; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci fb_writew((yoffset*info->fix.line_length)>>10, HD64461_LCDCBAR); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return 0; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciint hitfb_blank(int blank_mode, struct fb_info *info) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci unsigned short v; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (blank_mode) { 1758c2ecf20Sopenharmony_ci v = fb_readw(HD64461_LDR1); 1768c2ecf20Sopenharmony_ci v &= ~HD64461_LDR1_DON; 1778c2ecf20Sopenharmony_ci fb_writew(v, HD64461_LDR1); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci v = fb_readw(HD64461_LCDCCR); 1808c2ecf20Sopenharmony_ci v |= HD64461_LCDCCR_MOFF; 1818c2ecf20Sopenharmony_ci fb_writew(v, HD64461_LCDCCR); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci v = fb_readw(HD64461_STBCR); 1848c2ecf20Sopenharmony_ci v |= HD64461_STBCR_SLCDST; 1858c2ecf20Sopenharmony_ci fb_writew(v, HD64461_STBCR); 1868c2ecf20Sopenharmony_ci } else { 1878c2ecf20Sopenharmony_ci v = fb_readw(HD64461_STBCR); 1888c2ecf20Sopenharmony_ci v &= ~HD64461_STBCR_SLCDST; 1898c2ecf20Sopenharmony_ci fb_writew(v, HD64461_STBCR); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci v = fb_readw(HD64461_LCDCCR); 1928c2ecf20Sopenharmony_ci v &= ~(HD64461_LCDCCR_MOFF | HD64461_LCDCCR_STREQ); 1938c2ecf20Sopenharmony_ci fb_writew(v, HD64461_LCDCCR); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci do { 1968c2ecf20Sopenharmony_ci v = fb_readw(HD64461_LCDCCR); 1978c2ecf20Sopenharmony_ci } while(v&HD64461_LCDCCR_STBACK); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci v = fb_readw(HD64461_LDR1); 2008c2ecf20Sopenharmony_ci v |= HD64461_LDR1_DON; 2018c2ecf20Sopenharmony_ci fb_writew(v, HD64461_LDR1); 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green, 2078c2ecf20Sopenharmony_ci unsigned blue, unsigned transp, struct fb_info *info) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci if (regno >= 256) 2108c2ecf20Sopenharmony_ci return 1; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci switch (info->var.bits_per_pixel) { 2138c2ecf20Sopenharmony_ci case 8: 2148c2ecf20Sopenharmony_ci fb_writew(regno << 8, HD64461_CPTWAR); 2158c2ecf20Sopenharmony_ci fb_writew(red >> 10, HD64461_CPTWDR); 2168c2ecf20Sopenharmony_ci fb_writew(green >> 10, HD64461_CPTWDR); 2178c2ecf20Sopenharmony_ci fb_writew(blue >> 10, HD64461_CPTWDR); 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci case 16: 2208c2ecf20Sopenharmony_ci if (regno >= 16) 2218c2ecf20Sopenharmony_ci return 1; 2228c2ecf20Sopenharmony_ci ((u32 *) (info->pseudo_palette))[regno] = 2238c2ecf20Sopenharmony_ci ((red & 0xf800)) | 2248c2ecf20Sopenharmony_ci ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11); 2258c2ecf20Sopenharmony_ci break; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci return 0; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int hitfb_sync(struct fb_info *info) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci hitfb_accel_wait(); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci int maxy; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci var->xres = info->var.xres; 2428c2ecf20Sopenharmony_ci var->xres_virtual = info->var.xres; 2438c2ecf20Sopenharmony_ci var->yres = info->var.yres; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16)) 2468c2ecf20Sopenharmony_ci var->bits_per_pixel = info->var.bits_per_pixel; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (var->yres_virtual < var->yres) 2498c2ecf20Sopenharmony_ci var->yres_virtual = var->yres; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci maxy = info->fix.smem_len / var->xres; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (var->bits_per_pixel == 16) 2548c2ecf20Sopenharmony_ci maxy /= 2; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (var->yres_virtual > maxy) 2578c2ecf20Sopenharmony_ci var->yres_virtual = maxy; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci var->xoffset = 0; 2608c2ecf20Sopenharmony_ci var->yoffset = 0; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 2638c2ecf20Sopenharmony_ci case 8: 2648c2ecf20Sopenharmony_ci var->red.offset = 0; 2658c2ecf20Sopenharmony_ci var->red.length = 8; 2668c2ecf20Sopenharmony_ci var->green.offset = 0; 2678c2ecf20Sopenharmony_ci var->green.length = 8; 2688c2ecf20Sopenharmony_ci var->blue.offset = 0; 2698c2ecf20Sopenharmony_ci var->blue.length = 8; 2708c2ecf20Sopenharmony_ci var->transp.offset = 0; 2718c2ecf20Sopenharmony_ci var->transp.length = 0; 2728c2ecf20Sopenharmony_ci break; 2738c2ecf20Sopenharmony_ci case 16: /* RGB 565 */ 2748c2ecf20Sopenharmony_ci var->red.offset = 11; 2758c2ecf20Sopenharmony_ci var->red.length = 5; 2768c2ecf20Sopenharmony_ci var->green.offset = 5; 2778c2ecf20Sopenharmony_ci var->green.length = 6; 2788c2ecf20Sopenharmony_ci var->blue.offset = 0; 2798c2ecf20Sopenharmony_ci var->blue.length = 5; 2808c2ecf20Sopenharmony_ci var->transp.offset = 0; 2818c2ecf20Sopenharmony_ci var->transp.length = 0; 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci return 0; 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic int hitfb_set_par(struct fb_info *info) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci unsigned short ldr3; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci switch (info->var.bits_per_pixel) { 2938c2ecf20Sopenharmony_ci case 8: 2948c2ecf20Sopenharmony_ci info->fix.line_length = info->var.xres; 2958c2ecf20Sopenharmony_ci info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 2968c2ecf20Sopenharmony_ci info->fix.ypanstep = 16; 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci case 16: 2998c2ecf20Sopenharmony_ci info->fix.line_length = info->var.xres*2; 3008c2ecf20Sopenharmony_ci info->fix.visual = FB_VISUAL_TRUECOLOR; 3018c2ecf20Sopenharmony_ci info->fix.ypanstep = 8; 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci fb_writew(info->fix.line_length, HD64461_LCDCLOR); 3068c2ecf20Sopenharmony_ci ldr3 = fb_readw(HD64461_LDR3); 3078c2ecf20Sopenharmony_ci ldr3 &= ~15; 3088c2ecf20Sopenharmony_ci ldr3 |= (info->var.bits_per_pixel == 8) ? 4 : 8; 3098c2ecf20Sopenharmony_ci fb_writew(ldr3, HD64461_LDR3); 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic const struct fb_ops hitfb_ops = { 3148c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3158c2ecf20Sopenharmony_ci .fb_check_var = hitfb_check_var, 3168c2ecf20Sopenharmony_ci .fb_set_par = hitfb_set_par, 3178c2ecf20Sopenharmony_ci .fb_setcolreg = hitfb_setcolreg, 3188c2ecf20Sopenharmony_ci .fb_blank = hitfb_blank, 3198c2ecf20Sopenharmony_ci .fb_sync = hitfb_sync, 3208c2ecf20Sopenharmony_ci .fb_pan_display = hitfb_pan_display, 3218c2ecf20Sopenharmony_ci .fb_fillrect = hitfb_fillrect, 3228c2ecf20Sopenharmony_ci .fb_copyarea = hitfb_copyarea, 3238c2ecf20Sopenharmony_ci .fb_imageblit = cfb_imageblit, 3248c2ecf20Sopenharmony_ci}; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic int hitfb_probe(struct platform_device *dev) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci unsigned short lcdclor, ldr3, ldvndr; 3298c2ecf20Sopenharmony_ci struct fb_info *info; 3308c2ecf20Sopenharmony_ci int ret; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci if (fb_get_options("hitfb", NULL)) 3338c2ecf20Sopenharmony_ci return -ENODEV; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci hitfb_fix.mmio_start = HD64461_IO_OFFSET(0x1000); 3368c2ecf20Sopenharmony_ci hitfb_fix.mmio_len = 0x1000; 3378c2ecf20Sopenharmony_ci hitfb_fix.smem_start = HD64461_IO_OFFSET(0x02000000); 3388c2ecf20Sopenharmony_ci hitfb_fix.smem_len = 512 * 1024; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci lcdclor = fb_readw(HD64461_LCDCLOR); 3418c2ecf20Sopenharmony_ci ldvndr = fb_readw(HD64461_LDVNDR); 3428c2ecf20Sopenharmony_ci ldr3 = fb_readw(HD64461_LDR3); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci switch (ldr3 & 15) { 3458c2ecf20Sopenharmony_ci default: 3468c2ecf20Sopenharmony_ci case 4: 3478c2ecf20Sopenharmony_ci hitfb_var.bits_per_pixel = 8; 3488c2ecf20Sopenharmony_ci hitfb_var.xres = lcdclor; 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci case 8: 3518c2ecf20Sopenharmony_ci hitfb_var.bits_per_pixel = 16; 3528c2ecf20Sopenharmony_ci hitfb_var.xres = lcdclor / 2; 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci hitfb_fix.line_length = lcdclor; 3568c2ecf20Sopenharmony_ci hitfb_fix.visual = (hitfb_var.bits_per_pixel == 8) ? 3578c2ecf20Sopenharmony_ci FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 3588c2ecf20Sopenharmony_ci hitfb_var.yres = ldvndr + 1; 3598c2ecf20Sopenharmony_ci hitfb_var.xres_virtual = hitfb_var.xres; 3608c2ecf20Sopenharmony_ci hitfb_var.yres_virtual = hitfb_fix.smem_len / lcdclor; 3618c2ecf20Sopenharmony_ci switch (hitfb_var.bits_per_pixel) { 3628c2ecf20Sopenharmony_ci case 8: 3638c2ecf20Sopenharmony_ci hitfb_var.red.offset = 0; 3648c2ecf20Sopenharmony_ci hitfb_var.red.length = 8; 3658c2ecf20Sopenharmony_ci hitfb_var.green.offset = 0; 3668c2ecf20Sopenharmony_ci hitfb_var.green.length = 8; 3678c2ecf20Sopenharmony_ci hitfb_var.blue.offset = 0; 3688c2ecf20Sopenharmony_ci hitfb_var.blue.length = 8; 3698c2ecf20Sopenharmony_ci hitfb_var.transp.offset = 0; 3708c2ecf20Sopenharmony_ci hitfb_var.transp.length = 0; 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci case 16: /* RGB 565 */ 3738c2ecf20Sopenharmony_ci hitfb_var.red.offset = 11; 3748c2ecf20Sopenharmony_ci hitfb_var.red.length = 5; 3758c2ecf20Sopenharmony_ci hitfb_var.green.offset = 5; 3768c2ecf20Sopenharmony_ci hitfb_var.green.length = 6; 3778c2ecf20Sopenharmony_ci hitfb_var.blue.offset = 0; 3788c2ecf20Sopenharmony_ci hitfb_var.blue.length = 5; 3798c2ecf20Sopenharmony_ci hitfb_var.transp.offset = 0; 3808c2ecf20Sopenharmony_ci hitfb_var.transp.length = 0; 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(u32) * 16, &dev->dev); 3858c2ecf20Sopenharmony_ci if (unlikely(!info)) 3868c2ecf20Sopenharmony_ci return -ENOMEM; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci info->fbops = &hitfb_ops; 3898c2ecf20Sopenharmony_ci info->var = hitfb_var; 3908c2ecf20Sopenharmony_ci info->fix = hitfb_fix; 3918c2ecf20Sopenharmony_ci info->pseudo_palette = info->par; 3928c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN | 3938c2ecf20Sopenharmony_ci FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci info->screen_base = (void *)hitfb_fix.smem_start; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci ret = fb_alloc_cmap(&info->cmap, 256, 0); 3988c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 3998c2ecf20Sopenharmony_ci goto err_fb; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci ret = register_framebuffer(info); 4028c2ecf20Sopenharmony_ci if (unlikely(ret < 0)) 4038c2ecf20Sopenharmony_ci goto err; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci platform_set_drvdata(dev, info); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci fb_info(info, "%s frame buffer device\n", info->fix.id); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return 0; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cierr: 4128c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 4138c2ecf20Sopenharmony_cierr_fb: 4148c2ecf20Sopenharmony_ci framebuffer_release(info); 4158c2ecf20Sopenharmony_ci return ret; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic int hitfb_remove(struct platform_device *dev) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct fb_info *info = platform_get_drvdata(dev); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci unregister_framebuffer(info); 4238c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 4248c2ecf20Sopenharmony_ci framebuffer_release(info); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci return 0; 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic int hitfb_suspend(struct device *dev) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci u16 v; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci hitfb_blank(1,0); 4348c2ecf20Sopenharmony_ci v = fb_readw(HD64461_STBCR); 4358c2ecf20Sopenharmony_ci v |= HD64461_STBCR_SLCKE_IST; 4368c2ecf20Sopenharmony_ci fb_writew(v, HD64461_STBCR); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci return 0; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic int hitfb_resume(struct device *dev) 4428c2ecf20Sopenharmony_ci{ 4438c2ecf20Sopenharmony_ci u16 v; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci v = fb_readw(HD64461_STBCR); 4468c2ecf20Sopenharmony_ci v &= ~HD64461_STBCR_SLCKE_OST; 4478c2ecf20Sopenharmony_ci msleep(100); 4488c2ecf20Sopenharmony_ci v = fb_readw(HD64461_STBCR); 4498c2ecf20Sopenharmony_ci v &= ~HD64461_STBCR_SLCKE_IST; 4508c2ecf20Sopenharmony_ci fb_writew(v, HD64461_STBCR); 4518c2ecf20Sopenharmony_ci hitfb_blank(0,0); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic const struct dev_pm_ops hitfb_dev_pm_ops = { 4578c2ecf20Sopenharmony_ci .suspend = hitfb_suspend, 4588c2ecf20Sopenharmony_ci .resume = hitfb_resume, 4598c2ecf20Sopenharmony_ci}; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic struct platform_driver hitfb_driver = { 4628c2ecf20Sopenharmony_ci .probe = hitfb_probe, 4638c2ecf20Sopenharmony_ci .remove = hitfb_remove, 4648c2ecf20Sopenharmony_ci .driver = { 4658c2ecf20Sopenharmony_ci .name = "hitfb", 4668c2ecf20Sopenharmony_ci .pm = &hitfb_dev_pm_ops, 4678c2ecf20Sopenharmony_ci }, 4688c2ecf20Sopenharmony_ci}; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_cistatic struct platform_device hitfb_device = { 4718c2ecf20Sopenharmony_ci .name = "hitfb", 4728c2ecf20Sopenharmony_ci .id = -1, 4738c2ecf20Sopenharmony_ci}; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_cistatic int __init hitfb_init(void) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci int ret; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci ret = platform_driver_register(&hitfb_driver); 4808c2ecf20Sopenharmony_ci if (!ret) { 4818c2ecf20Sopenharmony_ci ret = platform_device_register(&hitfb_device); 4828c2ecf20Sopenharmony_ci if (ret) 4838c2ecf20Sopenharmony_ci platform_driver_unregister(&hitfb_driver); 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci return ret; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic void __exit hitfb_exit(void) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci platform_device_unregister(&hitfb_device); 4928c2ecf20Sopenharmony_ci platform_driver_unregister(&hitfb_driver); 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cimodule_init(hitfb_init); 4968c2ecf20Sopenharmony_cimodule_exit(hitfb_exit); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 499