18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * drivers/mb862xx/mb862xxfb.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Fujitsu Carmine/Coral-P(A)/Lime framebuffer driver 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * (C) 2008 Anatolij Gustschin <agust@denx.de> 88c2ecf20Sopenharmony_ci * DENX Software Engineering 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#undef DEBUG 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/fb.h> 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#if defined(CONFIG_OF) 218c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 228c2ecf20Sopenharmony_ci#endif 238c2ecf20Sopenharmony_ci#include "mb862xxfb.h" 248c2ecf20Sopenharmony_ci#include "mb862xx_reg.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define NR_PALETTE 256 278c2ecf20Sopenharmony_ci#define MB862XX_MEM_SIZE 0x1000000 288c2ecf20Sopenharmony_ci#define CORALP_MEM_SIZE 0x2000000 298c2ecf20Sopenharmony_ci#define CARMINE_MEM_SIZE 0x8000000 308c2ecf20Sopenharmony_ci#define DRV_NAME "mb862xxfb" 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#if defined(CONFIG_SOCRATES) 338c2ecf20Sopenharmony_cistatic struct mb862xx_gc_mode socrates_gc_mode = { 348c2ecf20Sopenharmony_ci /* Mode for Prime View PM070WL4 TFT LCD Panel */ 358c2ecf20Sopenharmony_ci { "800x480", 45, 800, 480, 40000, 86, 42, 33, 10, 128, 2, 0, 0, 0 }, 368c2ecf20Sopenharmony_ci /* 16 bits/pixel, 16MB, 133MHz, SDRAM memory mode value */ 378c2ecf20Sopenharmony_ci 16, 0x1000000, GC_CCF_COT_133, 0x4157ba63 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci#endif 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci/* Helpers */ 428c2ecf20Sopenharmony_cistatic inline int h_total(struct fb_var_screeninfo *var) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci return var->xres + var->left_margin + 458c2ecf20Sopenharmony_ci var->right_margin + var->hsync_len; 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic inline int v_total(struct fb_var_screeninfo *var) 498c2ecf20Sopenharmony_ci{ 508c2ecf20Sopenharmony_ci return var->yres + var->upper_margin + 518c2ecf20Sopenharmony_ci var->lower_margin + var->vsync_len; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic inline int hsp(struct fb_var_screeninfo *var) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci return var->xres + var->right_margin - 1; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic inline int vsp(struct fb_var_screeninfo *var) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci return var->yres + var->lower_margin - 1; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic inline int d_pitch(struct fb_var_screeninfo *var) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci return var->xres * var->bits_per_pixel / 8; 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic inline unsigned int chan_to_field(unsigned int chan, 708c2ecf20Sopenharmony_ci struct fb_bitfield *bf) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci chan &= 0xffff; 738c2ecf20Sopenharmony_ci chan >>= 16 - bf->length; 748c2ecf20Sopenharmony_ci return chan << bf->offset; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic int mb862xxfb_setcolreg(unsigned regno, 788c2ecf20Sopenharmony_ci unsigned red, unsigned green, unsigned blue, 798c2ecf20Sopenharmony_ci unsigned transp, struct fb_info *info) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = info->par; 828c2ecf20Sopenharmony_ci unsigned int val; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci switch (info->fix.visual) { 858c2ecf20Sopenharmony_ci case FB_VISUAL_TRUECOLOR: 868c2ecf20Sopenharmony_ci if (regno < 16) { 878c2ecf20Sopenharmony_ci val = chan_to_field(red, &info->var.red); 888c2ecf20Sopenharmony_ci val |= chan_to_field(green, &info->var.green); 898c2ecf20Sopenharmony_ci val |= chan_to_field(blue, &info->var.blue); 908c2ecf20Sopenharmony_ci par->pseudo_palette[regno] = val; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci break; 938c2ecf20Sopenharmony_ci case FB_VISUAL_PSEUDOCOLOR: 948c2ecf20Sopenharmony_ci if (regno < 256) { 958c2ecf20Sopenharmony_ci val = (red >> 8) << 16; 968c2ecf20Sopenharmony_ci val |= (green >> 8) << 8; 978c2ecf20Sopenharmony_ci val |= blue >> 8; 988c2ecf20Sopenharmony_ci outreg(disp, GC_L0PAL0 + (regno * 4), val); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci default: 1028c2ecf20Sopenharmony_ci return 1; /* unsupported type */ 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci return 0; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int mb862xxfb_check_var(struct fb_var_screeninfo *var, 1088c2ecf20Sopenharmony_ci struct fb_info *fbi) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci unsigned long tmp; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (fbi->dev) 1138c2ecf20Sopenharmony_ci dev_dbg(fbi->dev, "%s\n", __func__); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* check if these values fit into the registers */ 1168c2ecf20Sopenharmony_ci if (var->hsync_len > 255 || var->vsync_len > 255) 1178c2ecf20Sopenharmony_ci return -EINVAL; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci if ((var->xres + var->right_margin) >= 4096) 1208c2ecf20Sopenharmony_ci return -EINVAL; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci if ((var->yres + var->lower_margin) > 4096) 1238c2ecf20Sopenharmony_ci return -EINVAL; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci if (h_total(var) > 4096 || v_total(var) > 4096) 1268c2ecf20Sopenharmony_ci return -EINVAL; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci if (var->xres_virtual > 4096 || var->yres_virtual > 4096) 1298c2ecf20Sopenharmony_ci return -EINVAL; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (var->bits_per_pixel <= 8) 1328c2ecf20Sopenharmony_ci var->bits_per_pixel = 8; 1338c2ecf20Sopenharmony_ci else if (var->bits_per_pixel <= 16) 1348c2ecf20Sopenharmony_ci var->bits_per_pixel = 16; 1358c2ecf20Sopenharmony_ci else if (var->bits_per_pixel <= 32) 1368c2ecf20Sopenharmony_ci var->bits_per_pixel = 32; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * can cope with 8,16 or 24/32bpp if resulting 1408c2ecf20Sopenharmony_ci * pitch is divisible by 64 without remainder 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci if (d_pitch(&fbi->var) % GC_L0M_L0W_UNIT) { 1438c2ecf20Sopenharmony_ci int r; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci var->bits_per_pixel = 0; 1468c2ecf20Sopenharmony_ci do { 1478c2ecf20Sopenharmony_ci var->bits_per_pixel += 8; 1488c2ecf20Sopenharmony_ci r = d_pitch(&fbi->var) % GC_L0M_L0W_UNIT; 1498c2ecf20Sopenharmony_ci } while (r && var->bits_per_pixel <= 32); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (d_pitch(&fbi->var) % GC_L0M_L0W_UNIT) 1528c2ecf20Sopenharmony_ci return -EINVAL; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* line length is going to be 128 bit aligned */ 1568c2ecf20Sopenharmony_ci tmp = (var->xres * var->bits_per_pixel) / 8; 1578c2ecf20Sopenharmony_ci if ((tmp & 15) != 0) 1588c2ecf20Sopenharmony_ci return -EINVAL; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* set r/g/b positions and validate bpp */ 1618c2ecf20Sopenharmony_ci switch (var->bits_per_pixel) { 1628c2ecf20Sopenharmony_ci case 8: 1638c2ecf20Sopenharmony_ci var->red.length = var->bits_per_pixel; 1648c2ecf20Sopenharmony_ci var->green.length = var->bits_per_pixel; 1658c2ecf20Sopenharmony_ci var->blue.length = var->bits_per_pixel; 1668c2ecf20Sopenharmony_ci var->red.offset = 0; 1678c2ecf20Sopenharmony_ci var->green.offset = 0; 1688c2ecf20Sopenharmony_ci var->blue.offset = 0; 1698c2ecf20Sopenharmony_ci var->transp.length = 0; 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci case 16: 1728c2ecf20Sopenharmony_ci var->red.length = 5; 1738c2ecf20Sopenharmony_ci var->green.length = 5; 1748c2ecf20Sopenharmony_ci var->blue.length = 5; 1758c2ecf20Sopenharmony_ci var->red.offset = 10; 1768c2ecf20Sopenharmony_ci var->green.offset = 5; 1778c2ecf20Sopenharmony_ci var->blue.offset = 0; 1788c2ecf20Sopenharmony_ci var->transp.length = 0; 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci case 24: 1818c2ecf20Sopenharmony_ci case 32: 1828c2ecf20Sopenharmony_ci var->transp.length = 8; 1838c2ecf20Sopenharmony_ci var->red.length = 8; 1848c2ecf20Sopenharmony_ci var->green.length = 8; 1858c2ecf20Sopenharmony_ci var->blue.length = 8; 1868c2ecf20Sopenharmony_ci var->transp.offset = 24; 1878c2ecf20Sopenharmony_ci var->red.offset = 16; 1888c2ecf20Sopenharmony_ci var->green.offset = 8; 1898c2ecf20Sopenharmony_ci var->blue.offset = 0; 1908c2ecf20Sopenharmony_ci break; 1918c2ecf20Sopenharmony_ci default: 1928c2ecf20Sopenharmony_ci return -EINVAL; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic struct fb_ops mb862xxfb_ops; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* 2008c2ecf20Sopenharmony_ci * set display parameters 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_cistatic int mb862xxfb_set_par(struct fb_info *fbi) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = fbi->par; 2058c2ecf20Sopenharmony_ci unsigned long reg, sc; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci dev_dbg(par->dev, "%s\n", __func__); 2088c2ecf20Sopenharmony_ci if (par->type == BT_CORALP) 2098c2ecf20Sopenharmony_ci mb862xxfb_init_accel(fbi, &mb862xxfb_ops, fbi->var.xres); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (par->pre_init) 2128c2ecf20Sopenharmony_ci return 0; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* disp off */ 2158c2ecf20Sopenharmony_ci reg = inreg(disp, GC_DCM1); 2168c2ecf20Sopenharmony_ci reg &= ~GC_DCM01_DEN; 2178c2ecf20Sopenharmony_ci outreg(disp, GC_DCM1, reg); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* set display reference clock div. */ 2208c2ecf20Sopenharmony_ci sc = par->refclk / (1000000 / fbi->var.pixclock) - 1; 2218c2ecf20Sopenharmony_ci reg = inreg(disp, GC_DCM1); 2228c2ecf20Sopenharmony_ci reg &= ~(GC_DCM01_CKS | GC_DCM01_RESV | GC_DCM01_SC); 2238c2ecf20Sopenharmony_ci reg |= sc << 8; 2248c2ecf20Sopenharmony_ci outreg(disp, GC_DCM1, reg); 2258c2ecf20Sopenharmony_ci dev_dbg(par->dev, "SC 0x%lx\n", sc); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* disp dimension, format */ 2288c2ecf20Sopenharmony_ci reg = pack(d_pitch(&fbi->var) / GC_L0M_L0W_UNIT, 2298c2ecf20Sopenharmony_ci (fbi->var.yres - 1)); 2308c2ecf20Sopenharmony_ci if (fbi->var.bits_per_pixel == 16) 2318c2ecf20Sopenharmony_ci reg |= GC_L0M_L0C_16; 2328c2ecf20Sopenharmony_ci outreg(disp, GC_L0M, reg); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (fbi->var.bits_per_pixel == 32) { 2358c2ecf20Sopenharmony_ci reg = inreg(disp, GC_L0EM); 2368c2ecf20Sopenharmony_ci outreg(disp, GC_L0EM, reg | GC_L0EM_L0EC_24); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci outreg(disp, GC_WY_WX, 0); 2398c2ecf20Sopenharmony_ci reg = pack(fbi->var.yres - 1, fbi->var.xres); 2408c2ecf20Sopenharmony_ci outreg(disp, GC_WH_WW, reg); 2418c2ecf20Sopenharmony_ci outreg(disp, GC_L0OA0, 0); 2428c2ecf20Sopenharmony_ci outreg(disp, GC_L0DA0, 0); 2438c2ecf20Sopenharmony_ci outreg(disp, GC_L0DY_L0DX, 0); 2448c2ecf20Sopenharmony_ci outreg(disp, GC_L0WY_L0WX, 0); 2458c2ecf20Sopenharmony_ci outreg(disp, GC_L0WH_L0WW, reg); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* both HW-cursors off */ 2488c2ecf20Sopenharmony_ci reg = inreg(disp, GC_CPM_CUTC); 2498c2ecf20Sopenharmony_ci reg &= ~(GC_CPM_CEN0 | GC_CPM_CEN1); 2508c2ecf20Sopenharmony_ci outreg(disp, GC_CPM_CUTC, reg); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci /* timings */ 2538c2ecf20Sopenharmony_ci reg = pack(fbi->var.xres - 1, fbi->var.xres - 1); 2548c2ecf20Sopenharmony_ci outreg(disp, GC_HDB_HDP, reg); 2558c2ecf20Sopenharmony_ci reg = pack((fbi->var.yres - 1), vsp(&fbi->var)); 2568c2ecf20Sopenharmony_ci outreg(disp, GC_VDP_VSP, reg); 2578c2ecf20Sopenharmony_ci reg = ((fbi->var.vsync_len - 1) << 24) | 2588c2ecf20Sopenharmony_ci pack((fbi->var.hsync_len - 1), hsp(&fbi->var)); 2598c2ecf20Sopenharmony_ci outreg(disp, GC_VSW_HSW_HSP, reg); 2608c2ecf20Sopenharmony_ci outreg(disp, GC_HTP, pack(h_total(&fbi->var) - 1, 0)); 2618c2ecf20Sopenharmony_ci outreg(disp, GC_VTR, pack(v_total(&fbi->var) - 1, 0)); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* display on */ 2648c2ecf20Sopenharmony_ci reg = inreg(disp, GC_DCM1); 2658c2ecf20Sopenharmony_ci reg |= GC_DCM01_DEN | GC_DCM01_L0E; 2668c2ecf20Sopenharmony_ci reg &= ~GC_DCM01_ESY; 2678c2ecf20Sopenharmony_ci outreg(disp, GC_DCM1, reg); 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int mb862xxfb_pan(struct fb_var_screeninfo *var, 2728c2ecf20Sopenharmony_ci struct fb_info *info) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = info->par; 2758c2ecf20Sopenharmony_ci unsigned long reg; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci reg = pack(var->yoffset, var->xoffset); 2788c2ecf20Sopenharmony_ci outreg(disp, GC_L0WY_L0WX, reg); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci reg = pack(info->var.yres_virtual, info->var.xres_virtual); 2818c2ecf20Sopenharmony_ci outreg(disp, GC_L0WH_L0WW, reg); 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_cistatic int mb862xxfb_blank(int mode, struct fb_info *fbi) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = fbi->par; 2888c2ecf20Sopenharmony_ci unsigned long reg; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci dev_dbg(fbi->dev, "blank mode=%d\n", mode); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci switch (mode) { 2938c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: 2948c2ecf20Sopenharmony_ci reg = inreg(disp, GC_DCM1); 2958c2ecf20Sopenharmony_ci reg &= ~GC_DCM01_DEN; 2968c2ecf20Sopenharmony_ci outreg(disp, GC_DCM1, reg); 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: 2998c2ecf20Sopenharmony_ci reg = inreg(disp, GC_DCM1); 3008c2ecf20Sopenharmony_ci reg |= GC_DCM01_DEN; 3018c2ecf20Sopenharmony_ci outreg(disp, GC_DCM1, reg); 3028c2ecf20Sopenharmony_ci break; 3038c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: 3048c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: 3058c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: 3068c2ecf20Sopenharmony_ci default: 3078c2ecf20Sopenharmony_ci return 1; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci return 0; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int mb862xxfb_ioctl(struct fb_info *fbi, unsigned int cmd, 3138c2ecf20Sopenharmony_ci unsigned long arg) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = fbi->par; 3168c2ecf20Sopenharmony_ci struct mb862xx_l1_cfg *l1_cfg = &par->l1_cfg; 3178c2ecf20Sopenharmony_ci void __user *argp = (void __user *)arg; 3188c2ecf20Sopenharmony_ci int *enable; 3198c2ecf20Sopenharmony_ci u32 l1em = 0; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci switch (cmd) { 3228c2ecf20Sopenharmony_ci case MB862XX_L1_GET_CFG: 3238c2ecf20Sopenharmony_ci if (copy_to_user(argp, l1_cfg, sizeof(*l1_cfg))) 3248c2ecf20Sopenharmony_ci return -EFAULT; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case MB862XX_L1_SET_CFG: 3278c2ecf20Sopenharmony_ci if (copy_from_user(l1_cfg, argp, sizeof(*l1_cfg))) 3288c2ecf20Sopenharmony_ci return -EFAULT; 3298c2ecf20Sopenharmony_ci if (l1_cfg->dh == 0 || l1_cfg->dw == 0) 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci if ((l1_cfg->sw >= l1_cfg->dw) && (l1_cfg->sh >= l1_cfg->dh)) { 3328c2ecf20Sopenharmony_ci /* downscaling */ 3338c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_CSC, 3348c2ecf20Sopenharmony_ci pack((l1_cfg->sh << 11) / l1_cfg->dh, 3358c2ecf20Sopenharmony_ci (l1_cfg->sw << 11) / l1_cfg->dw)); 3368c2ecf20Sopenharmony_ci l1em = inreg(disp, GC_L1EM); 3378c2ecf20Sopenharmony_ci l1em &= ~GC_L1EM_DM; 3388c2ecf20Sopenharmony_ci } else if ((l1_cfg->sw <= l1_cfg->dw) && 3398c2ecf20Sopenharmony_ci (l1_cfg->sh <= l1_cfg->dh)) { 3408c2ecf20Sopenharmony_ci /* upscaling */ 3418c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_CSC, 3428c2ecf20Sopenharmony_ci pack((l1_cfg->sh << 11) / l1_cfg->dh, 3438c2ecf20Sopenharmony_ci (l1_cfg->sw << 11) / l1_cfg->dw)); 3448c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_CMSS, 3458c2ecf20Sopenharmony_ci pack(l1_cfg->sw >> 1, l1_cfg->sh)); 3468c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_CMDS, 3478c2ecf20Sopenharmony_ci pack(l1_cfg->dw >> 1, l1_cfg->dh)); 3488c2ecf20Sopenharmony_ci l1em = inreg(disp, GC_L1EM); 3498c2ecf20Sopenharmony_ci l1em |= GC_L1EM_DM; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (l1_cfg->mirror) { 3538c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_CBM, 3548c2ecf20Sopenharmony_ci inreg(cap, GC_CAP_CBM) | GC_CBM_HRV); 3558c2ecf20Sopenharmony_ci l1em |= l1_cfg->dw * 2 - 8; 3568c2ecf20Sopenharmony_ci } else { 3578c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_CBM, 3588c2ecf20Sopenharmony_ci inreg(cap, GC_CAP_CBM) & ~GC_CBM_HRV); 3598c2ecf20Sopenharmony_ci l1em &= 0xffff0000; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci outreg(disp, GC_L1EM, l1em); 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci case MB862XX_L1_ENABLE: 3648c2ecf20Sopenharmony_ci enable = (int *)arg; 3658c2ecf20Sopenharmony_ci if (*enable) { 3668c2ecf20Sopenharmony_ci outreg(disp, GC_L1DA, par->cap_buf); 3678c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_IMG_START, 3688c2ecf20Sopenharmony_ci pack(l1_cfg->sy >> 1, l1_cfg->sx)); 3698c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_IMG_END, 3708c2ecf20Sopenharmony_ci pack(l1_cfg->sh, l1_cfg->sw)); 3718c2ecf20Sopenharmony_ci outreg(disp, GC_L1M, GC_L1M_16 | GC_L1M_YC | GC_L1M_CS | 3728c2ecf20Sopenharmony_ci (par->l1_stride << 16)); 3738c2ecf20Sopenharmony_ci outreg(disp, GC_L1WY_L1WX, 3748c2ecf20Sopenharmony_ci pack(l1_cfg->dy, l1_cfg->dx)); 3758c2ecf20Sopenharmony_ci outreg(disp, GC_L1WH_L1WW, 3768c2ecf20Sopenharmony_ci pack(l1_cfg->dh - 1, l1_cfg->dw)); 3778c2ecf20Sopenharmony_ci outreg(disp, GC_DLS, 1); 3788c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_VCM, 3798c2ecf20Sopenharmony_ci GC_VCM_VIE | GC_VCM_CM | GC_VCM_VS_PAL); 3808c2ecf20Sopenharmony_ci outreg(disp, GC_DCM1, inreg(disp, GC_DCM1) | 3818c2ecf20Sopenharmony_ci GC_DCM1_DEN | GC_DCM1_L1E); 3828c2ecf20Sopenharmony_ci } else { 3838c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_VCM, 3848c2ecf20Sopenharmony_ci inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE); 3858c2ecf20Sopenharmony_ci outreg(disp, GC_DCM1, 3868c2ecf20Sopenharmony_ci inreg(disp, GC_DCM1) & ~GC_DCM1_L1E); 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci case MB862XX_L1_CAP_CTL: 3908c2ecf20Sopenharmony_ci enable = (int *)arg; 3918c2ecf20Sopenharmony_ci if (*enable) { 3928c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_VCM, 3938c2ecf20Sopenharmony_ci inreg(cap, GC_CAP_VCM) | GC_VCM_VIE); 3948c2ecf20Sopenharmony_ci } else { 3958c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_VCM, 3968c2ecf20Sopenharmony_ci inreg(cap, GC_CAP_VCM) & ~GC_VCM_VIE); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci default: 4008c2ecf20Sopenharmony_ci return -EINVAL; 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci/* framebuffer ops */ 4068c2ecf20Sopenharmony_cistatic struct fb_ops mb862xxfb_ops = { 4078c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4088c2ecf20Sopenharmony_ci .fb_check_var = mb862xxfb_check_var, 4098c2ecf20Sopenharmony_ci .fb_set_par = mb862xxfb_set_par, 4108c2ecf20Sopenharmony_ci .fb_setcolreg = mb862xxfb_setcolreg, 4118c2ecf20Sopenharmony_ci .fb_blank = mb862xxfb_blank, 4128c2ecf20Sopenharmony_ci .fb_pan_display = mb862xxfb_pan, 4138c2ecf20Sopenharmony_ci .fb_fillrect = cfb_fillrect, 4148c2ecf20Sopenharmony_ci .fb_copyarea = cfb_copyarea, 4158c2ecf20Sopenharmony_ci .fb_imageblit = cfb_imageblit, 4168c2ecf20Sopenharmony_ci .fb_ioctl = mb862xxfb_ioctl, 4178c2ecf20Sopenharmony_ci}; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci/* initialize fb_info data */ 4208c2ecf20Sopenharmony_cistatic int mb862xxfb_init_fbinfo(struct fb_info *fbi) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = fbi->par; 4238c2ecf20Sopenharmony_ci struct mb862xx_gc_mode *mode = par->gc_mode; 4248c2ecf20Sopenharmony_ci unsigned long reg; 4258c2ecf20Sopenharmony_ci int stride; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci fbi->fbops = &mb862xxfb_ops; 4288c2ecf20Sopenharmony_ci fbi->pseudo_palette = par->pseudo_palette; 4298c2ecf20Sopenharmony_ci fbi->screen_base = par->fb_base; 4308c2ecf20Sopenharmony_ci fbi->screen_size = par->mapped_vram; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci strcpy(fbi->fix.id, DRV_NAME); 4338c2ecf20Sopenharmony_ci fbi->fix.smem_start = (unsigned long)par->fb_base_phys; 4348c2ecf20Sopenharmony_ci fbi->fix.mmio_start = (unsigned long)par->mmio_base_phys; 4358c2ecf20Sopenharmony_ci fbi->fix.mmio_len = par->mmio_len; 4368c2ecf20Sopenharmony_ci fbi->fix.accel = FB_ACCEL_NONE; 4378c2ecf20Sopenharmony_ci fbi->fix.type = FB_TYPE_PACKED_PIXELS; 4388c2ecf20Sopenharmony_ci fbi->fix.type_aux = 0; 4398c2ecf20Sopenharmony_ci fbi->fix.xpanstep = 1; 4408c2ecf20Sopenharmony_ci fbi->fix.ypanstep = 1; 4418c2ecf20Sopenharmony_ci fbi->fix.ywrapstep = 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci reg = inreg(disp, GC_DCM1); 4448c2ecf20Sopenharmony_ci if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E) { 4458c2ecf20Sopenharmony_ci /* get the disp mode from active display cfg */ 4468c2ecf20Sopenharmony_ci unsigned long sc = ((reg & GC_DCM01_SC) >> 8) + 1; 4478c2ecf20Sopenharmony_ci unsigned long hsp, vsp, ht, vt; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci dev_dbg(par->dev, "using bootloader's disp. mode\n"); 4508c2ecf20Sopenharmony_ci fbi->var.pixclock = (sc * 1000000) / par->refclk; 4518c2ecf20Sopenharmony_ci fbi->var.xres = (inreg(disp, GC_HDB_HDP) & 0x0fff) + 1; 4528c2ecf20Sopenharmony_ci reg = inreg(disp, GC_VDP_VSP); 4538c2ecf20Sopenharmony_ci fbi->var.yres = ((reg >> 16) & 0x0fff) + 1; 4548c2ecf20Sopenharmony_ci vsp = (reg & 0x0fff) + 1; 4558c2ecf20Sopenharmony_ci fbi->var.xres_virtual = fbi->var.xres; 4568c2ecf20Sopenharmony_ci fbi->var.yres_virtual = fbi->var.yres; 4578c2ecf20Sopenharmony_ci reg = inreg(disp, GC_L0EM); 4588c2ecf20Sopenharmony_ci if (reg & GC_L0EM_L0EC_24) { 4598c2ecf20Sopenharmony_ci fbi->var.bits_per_pixel = 32; 4608c2ecf20Sopenharmony_ci } else { 4618c2ecf20Sopenharmony_ci reg = inreg(disp, GC_L0M); 4628c2ecf20Sopenharmony_ci if (reg & GC_L0M_L0C_16) 4638c2ecf20Sopenharmony_ci fbi->var.bits_per_pixel = 16; 4648c2ecf20Sopenharmony_ci else 4658c2ecf20Sopenharmony_ci fbi->var.bits_per_pixel = 8; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci reg = inreg(disp, GC_VSW_HSW_HSP); 4688c2ecf20Sopenharmony_ci fbi->var.hsync_len = ((reg & 0xff0000) >> 16) + 1; 4698c2ecf20Sopenharmony_ci fbi->var.vsync_len = ((reg & 0x3f000000) >> 24) + 1; 4708c2ecf20Sopenharmony_ci hsp = (reg & 0xffff) + 1; 4718c2ecf20Sopenharmony_ci ht = ((inreg(disp, GC_HTP) & 0xfff0000) >> 16) + 1; 4728c2ecf20Sopenharmony_ci fbi->var.right_margin = hsp - fbi->var.xres; 4738c2ecf20Sopenharmony_ci fbi->var.left_margin = ht - hsp - fbi->var.hsync_len; 4748c2ecf20Sopenharmony_ci vt = ((inreg(disp, GC_VTR) & 0xfff0000) >> 16) + 1; 4758c2ecf20Sopenharmony_ci fbi->var.lower_margin = vsp - fbi->var.yres; 4768c2ecf20Sopenharmony_ci fbi->var.upper_margin = vt - vsp - fbi->var.vsync_len; 4778c2ecf20Sopenharmony_ci } else if (mode) { 4788c2ecf20Sopenharmony_ci dev_dbg(par->dev, "using supplied mode\n"); 4798c2ecf20Sopenharmony_ci fb_videomode_to_var(&fbi->var, (struct fb_videomode *)mode); 4808c2ecf20Sopenharmony_ci fbi->var.bits_per_pixel = mode->def_bpp ? mode->def_bpp : 8; 4818c2ecf20Sopenharmony_ci } else { 4828c2ecf20Sopenharmony_ci int ret; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci ret = fb_find_mode(&fbi->var, fbi, "640x480-16@60", 4858c2ecf20Sopenharmony_ci NULL, 0, NULL, 16); 4868c2ecf20Sopenharmony_ci if (ret == 0 || ret == 4) { 4878c2ecf20Sopenharmony_ci dev_err(par->dev, 4888c2ecf20Sopenharmony_ci "failed to get initial mode\n"); 4898c2ecf20Sopenharmony_ci return -EINVAL; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci fbi->var.xoffset = 0; 4948c2ecf20Sopenharmony_ci fbi->var.yoffset = 0; 4958c2ecf20Sopenharmony_ci fbi->var.grayscale = 0; 4968c2ecf20Sopenharmony_ci fbi->var.nonstd = 0; 4978c2ecf20Sopenharmony_ci fbi->var.height = -1; 4988c2ecf20Sopenharmony_ci fbi->var.width = -1; 4998c2ecf20Sopenharmony_ci fbi->var.accel_flags = 0; 5008c2ecf20Sopenharmony_ci fbi->var.vmode = FB_VMODE_NONINTERLACED; 5018c2ecf20Sopenharmony_ci fbi->var.activate = FB_ACTIVATE_NOW; 5028c2ecf20Sopenharmony_ci fbi->flags = FBINFO_DEFAULT | 5038c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 5048c2ecf20Sopenharmony_ci FBINFO_FOREIGN_ENDIAN | 5058c2ecf20Sopenharmony_ci#endif 5068c2ecf20Sopenharmony_ci FBINFO_HWACCEL_XPAN | 5078c2ecf20Sopenharmony_ci FBINFO_HWACCEL_YPAN; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci /* check and possibly fix bpp */ 5108c2ecf20Sopenharmony_ci if ((fbi->fbops->fb_check_var)(&fbi->var, fbi)) 5118c2ecf20Sopenharmony_ci dev_err(par->dev, "check_var() failed on initial setup?\n"); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci fbi->fix.visual = fbi->var.bits_per_pixel == 8 ? 5148c2ecf20Sopenharmony_ci FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; 5158c2ecf20Sopenharmony_ci fbi->fix.line_length = (fbi->var.xres_virtual * 5168c2ecf20Sopenharmony_ci fbi->var.bits_per_pixel) / 8; 5178c2ecf20Sopenharmony_ci fbi->fix.smem_len = fbi->fix.line_length * fbi->var.yres_virtual; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* 5208c2ecf20Sopenharmony_ci * reserve space for capture buffers and two cursors 5218c2ecf20Sopenharmony_ci * at the end of vram: 720x576 * 2 * 2.2 + 64x64 * 16. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_ci par->cap_buf = par->mapped_vram - 0x1bd800 - 0x10000; 5248c2ecf20Sopenharmony_ci par->cap_len = 0x1bd800; 5258c2ecf20Sopenharmony_ci par->l1_cfg.sx = 0; 5268c2ecf20Sopenharmony_ci par->l1_cfg.sy = 0; 5278c2ecf20Sopenharmony_ci par->l1_cfg.sw = 720; 5288c2ecf20Sopenharmony_ci par->l1_cfg.sh = 576; 5298c2ecf20Sopenharmony_ci par->l1_cfg.dx = 0; 5308c2ecf20Sopenharmony_ci par->l1_cfg.dy = 0; 5318c2ecf20Sopenharmony_ci par->l1_cfg.dw = 720; 5328c2ecf20Sopenharmony_ci par->l1_cfg.dh = 576; 5338c2ecf20Sopenharmony_ci stride = par->l1_cfg.sw * (fbi->var.bits_per_pixel / 8); 5348c2ecf20Sopenharmony_ci par->l1_stride = stride / 64 + ((stride % 64) ? 1 : 0); 5358c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_CBM, GC_CBM_OO | GC_CBM_CBST | 5368c2ecf20Sopenharmony_ci (par->l1_stride << 16)); 5378c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_CBOA, par->cap_buf); 5388c2ecf20Sopenharmony_ci outreg(cap, GC_CAP_CBLA, par->cap_buf + par->cap_len); 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci/* 5438c2ecf20Sopenharmony_ci * show some display controller and cursor registers 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_cistatic ssize_t mb862xxfb_show_dispregs(struct device *dev, 5468c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(dev); 5498c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = fbi->par; 5508c2ecf20Sopenharmony_ci char *ptr = buf; 5518c2ecf20Sopenharmony_ci unsigned int reg; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci for (reg = GC_DCM0; reg <= GC_L0DY_L0DX; reg += 4) 5548c2ecf20Sopenharmony_ci ptr += sprintf(ptr, "%08x = %08x\n", 5558c2ecf20Sopenharmony_ci reg, inreg(disp, reg)); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci for (reg = GC_CPM_CUTC; reg <= GC_CUY1_CUX1; reg += 4) 5588c2ecf20Sopenharmony_ci ptr += sprintf(ptr, "%08x = %08x\n", 5598c2ecf20Sopenharmony_ci reg, inreg(disp, reg)); 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci for (reg = GC_DCM1; reg <= GC_L0WH_L0WW; reg += 4) 5628c2ecf20Sopenharmony_ci ptr += sprintf(ptr, "%08x = %08x\n", 5638c2ecf20Sopenharmony_ci reg, inreg(disp, reg)); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci for (reg = 0x400; reg <= 0x410; reg += 4) 5668c2ecf20Sopenharmony_ci ptr += sprintf(ptr, "geo %08x = %08x\n", 5678c2ecf20Sopenharmony_ci reg, inreg(geo, reg)); 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci for (reg = 0x400; reg <= 0x410; reg += 4) 5708c2ecf20Sopenharmony_ci ptr += sprintf(ptr, "draw %08x = %08x\n", 5718c2ecf20Sopenharmony_ci reg, inreg(draw, reg)); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci for (reg = 0x440; reg <= 0x450; reg += 4) 5748c2ecf20Sopenharmony_ci ptr += sprintf(ptr, "draw %08x = %08x\n", 5758c2ecf20Sopenharmony_ci reg, inreg(draw, reg)); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci return ptr - buf; 5788c2ecf20Sopenharmony_ci} 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_cistatic DEVICE_ATTR(dispregs, 0444, mb862xxfb_show_dispregs, NULL); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_cistatic irqreturn_t mb862xx_intr(int irq, void *dev_id) 5838c2ecf20Sopenharmony_ci{ 5848c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = (struct mb862xxfb_par *) dev_id; 5858c2ecf20Sopenharmony_ci unsigned long reg_ist, mask; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci if (!par) 5888c2ecf20Sopenharmony_ci return IRQ_NONE; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (par->type == BT_CARMINE) { 5918c2ecf20Sopenharmony_ci /* Get Interrupt Status */ 5928c2ecf20Sopenharmony_ci reg_ist = inreg(ctrl, GC_CTRL_STATUS); 5938c2ecf20Sopenharmony_ci mask = inreg(ctrl, GC_CTRL_INT_MASK); 5948c2ecf20Sopenharmony_ci if (reg_ist == 0) 5958c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci reg_ist &= mask; 5988c2ecf20Sopenharmony_ci if (reg_ist == 0) 5998c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci /* Clear interrupt status */ 6028c2ecf20Sopenharmony_ci outreg(ctrl, 0x0, reg_ist); 6038c2ecf20Sopenharmony_ci } else { 6048c2ecf20Sopenharmony_ci /* Get status */ 6058c2ecf20Sopenharmony_ci reg_ist = inreg(host, GC_IST); 6068c2ecf20Sopenharmony_ci mask = inreg(host, GC_IMASK); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci reg_ist &= mask; 6098c2ecf20Sopenharmony_ci if (reg_ist == 0) 6108c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci /* Clear status */ 6138c2ecf20Sopenharmony_ci outreg(host, GC_IST, ~reg_ist); 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci return IRQ_HANDLED; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_MB862XX_LIME) 6198c2ecf20Sopenharmony_ci/* 6208c2ecf20Sopenharmony_ci * GDC (Lime, Coral(B/Q), Mint, ...) on host bus 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_cistatic int mb862xx_gdc_init(struct mb862xxfb_par *par) 6238c2ecf20Sopenharmony_ci{ 6248c2ecf20Sopenharmony_ci unsigned long ccf, mmr; 6258c2ecf20Sopenharmony_ci unsigned long ver, rev; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci if (!par) 6288c2ecf20Sopenharmony_ci return -ENODEV; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_PRE_INIT_FB) 6318c2ecf20Sopenharmony_ci par->pre_init = 1; 6328c2ecf20Sopenharmony_ci#endif 6338c2ecf20Sopenharmony_ci par->host = par->mmio_base; 6348c2ecf20Sopenharmony_ci par->i2c = par->mmio_base + MB862XX_I2C_BASE; 6358c2ecf20Sopenharmony_ci par->disp = par->mmio_base + MB862XX_DISP_BASE; 6368c2ecf20Sopenharmony_ci par->cap = par->mmio_base + MB862XX_CAP_BASE; 6378c2ecf20Sopenharmony_ci par->draw = par->mmio_base + MB862XX_DRAW_BASE; 6388c2ecf20Sopenharmony_ci par->geo = par->mmio_base + MB862XX_GEO_BASE; 6398c2ecf20Sopenharmony_ci par->pio = par->mmio_base + MB862XX_PIO_BASE; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci par->refclk = GC_DISP_REFCLK_400; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci ver = inreg(host, GC_CID); 6448c2ecf20Sopenharmony_ci rev = inreg(pio, GC_REVISION); 6458c2ecf20Sopenharmony_ci if ((ver == 0x303) && (rev & 0xffffff00) == 0x20050100) { 6468c2ecf20Sopenharmony_ci dev_info(par->dev, "Fujitsu Lime v1.%d found\n", 6478c2ecf20Sopenharmony_ci (int)rev & 0xff); 6488c2ecf20Sopenharmony_ci par->type = BT_LIME; 6498c2ecf20Sopenharmony_ci ccf = par->gc_mode ? par->gc_mode->ccf : GC_CCF_COT_100; 6508c2ecf20Sopenharmony_ci mmr = par->gc_mode ? par->gc_mode->mmr : 0x414fb7f2; 6518c2ecf20Sopenharmony_ci } else { 6528c2ecf20Sopenharmony_ci dev_info(par->dev, "? GDC, CID/Rev.: 0x%lx/0x%lx \n", ver, rev); 6538c2ecf20Sopenharmony_ci return -ENODEV; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (!par->pre_init) { 6578c2ecf20Sopenharmony_ci outreg(host, GC_CCF, ccf); 6588c2ecf20Sopenharmony_ci udelay(200); 6598c2ecf20Sopenharmony_ci outreg(host, GC_MMR, mmr); 6608c2ecf20Sopenharmony_ci udelay(10); 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* interrupt status */ 6648c2ecf20Sopenharmony_ci outreg(host, GC_IST, 0); 6658c2ecf20Sopenharmony_ci outreg(host, GC_IMASK, GC_INT_EN); 6668c2ecf20Sopenharmony_ci return 0; 6678c2ecf20Sopenharmony_ci} 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_cistatic int of_platform_mb862xx_probe(struct platform_device *ofdev) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct device_node *np = ofdev->dev.of_node; 6728c2ecf20Sopenharmony_ci struct device *dev = &ofdev->dev; 6738c2ecf20Sopenharmony_ci struct mb862xxfb_par *par; 6748c2ecf20Sopenharmony_ci struct fb_info *info; 6758c2ecf20Sopenharmony_ci struct resource res; 6768c2ecf20Sopenharmony_ci resource_size_t res_size; 6778c2ecf20Sopenharmony_ci unsigned long ret = -ENODEV; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (of_address_to_resource(np, 0, &res)) { 6808c2ecf20Sopenharmony_ci dev_err(dev, "Invalid address\n"); 6818c2ecf20Sopenharmony_ci return -ENXIO; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev); 6858c2ecf20Sopenharmony_ci if (!info) 6868c2ecf20Sopenharmony_ci return -ENOMEM; 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci par = info->par; 6898c2ecf20Sopenharmony_ci par->info = info; 6908c2ecf20Sopenharmony_ci par->dev = dev; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci par->irq = irq_of_parse_and_map(np, 0); 6938c2ecf20Sopenharmony_ci if (par->irq == NO_IRQ) { 6948c2ecf20Sopenharmony_ci dev_err(dev, "failed to map irq\n"); 6958c2ecf20Sopenharmony_ci ret = -ENODEV; 6968c2ecf20Sopenharmony_ci goto fbrel; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci res_size = resource_size(&res); 7008c2ecf20Sopenharmony_ci par->res = request_mem_region(res.start, res_size, DRV_NAME); 7018c2ecf20Sopenharmony_ci if (par->res == NULL) { 7028c2ecf20Sopenharmony_ci dev_err(dev, "Cannot claim framebuffer/mmio\n"); 7038c2ecf20Sopenharmony_ci ret = -ENXIO; 7048c2ecf20Sopenharmony_ci goto irqdisp; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci#if defined(CONFIG_SOCRATES) 7088c2ecf20Sopenharmony_ci par->gc_mode = &socrates_gc_mode; 7098c2ecf20Sopenharmony_ci#endif 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci par->fb_base_phys = res.start; 7128c2ecf20Sopenharmony_ci par->mmio_base_phys = res.start + MB862XX_MMIO_BASE; 7138c2ecf20Sopenharmony_ci par->mmio_len = MB862XX_MMIO_SIZE; 7148c2ecf20Sopenharmony_ci if (par->gc_mode) 7158c2ecf20Sopenharmony_ci par->mapped_vram = par->gc_mode->max_vram; 7168c2ecf20Sopenharmony_ci else 7178c2ecf20Sopenharmony_ci par->mapped_vram = MB862XX_MEM_SIZE; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram); 7208c2ecf20Sopenharmony_ci if (par->fb_base == NULL) { 7218c2ecf20Sopenharmony_ci dev_err(dev, "Cannot map framebuffer\n"); 7228c2ecf20Sopenharmony_ci goto rel_reg; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci par->mmio_base = ioremap(par->mmio_base_phys, par->mmio_len); 7268c2ecf20Sopenharmony_ci if (par->mmio_base == NULL) { 7278c2ecf20Sopenharmony_ci dev_err(dev, "Cannot map registers\n"); 7288c2ecf20Sopenharmony_ci goto fb_unmap; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci dev_dbg(dev, "fb phys 0x%llx 0x%lx\n", 7328c2ecf20Sopenharmony_ci (u64)par->fb_base_phys, (ulong)par->mapped_vram); 7338c2ecf20Sopenharmony_ci dev_dbg(dev, "mmio phys 0x%llx 0x%lx, (irq = %d)\n", 7348c2ecf20Sopenharmony_ci (u64)par->mmio_base_phys, (ulong)par->mmio_len, par->irq); 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (mb862xx_gdc_init(par)) 7378c2ecf20Sopenharmony_ci goto io_unmap; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (request_irq(par->irq, mb862xx_intr, 0, 7408c2ecf20Sopenharmony_ci DRV_NAME, (void *)par)) { 7418c2ecf20Sopenharmony_ci dev_err(dev, "Cannot request irq\n"); 7428c2ecf20Sopenharmony_ci goto io_unmap; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci mb862xxfb_init_fbinfo(info); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0) < 0) { 7488c2ecf20Sopenharmony_ci dev_err(dev, "Could not allocate cmap for fb_info.\n"); 7498c2ecf20Sopenharmony_ci goto free_irq; 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if ((info->fbops->fb_set_par)(info)) 7538c2ecf20Sopenharmony_ci dev_err(dev, "set_var() failed on initial setup?\n"); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci if (register_framebuffer(info)) { 7568c2ecf20Sopenharmony_ci dev_err(dev, "failed to register framebuffer\n"); 7578c2ecf20Sopenharmony_ci goto rel_cmap; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci dev_set_drvdata(dev, info); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci if (device_create_file(dev, &dev_attr_dispregs)) 7638c2ecf20Sopenharmony_ci dev_err(dev, "Can't create sysfs regdump file\n"); 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cirel_cmap: 7678c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 7688c2ecf20Sopenharmony_cifree_irq: 7698c2ecf20Sopenharmony_ci outreg(host, GC_IMASK, 0); 7708c2ecf20Sopenharmony_ci free_irq(par->irq, (void *)par); 7718c2ecf20Sopenharmony_ciio_unmap: 7728c2ecf20Sopenharmony_ci iounmap(par->mmio_base); 7738c2ecf20Sopenharmony_cifb_unmap: 7748c2ecf20Sopenharmony_ci iounmap(par->fb_base); 7758c2ecf20Sopenharmony_cirel_reg: 7768c2ecf20Sopenharmony_ci release_mem_region(res.start, res_size); 7778c2ecf20Sopenharmony_ciirqdisp: 7788c2ecf20Sopenharmony_ci irq_dispose_mapping(par->irq); 7798c2ecf20Sopenharmony_cifbrel: 7808c2ecf20Sopenharmony_ci framebuffer_release(info); 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic int of_platform_mb862xx_remove(struct platform_device *ofdev) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct fb_info *fbi = dev_get_drvdata(&ofdev->dev); 7878c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = fbi->par; 7888c2ecf20Sopenharmony_ci resource_size_t res_size = resource_size(par->res); 7898c2ecf20Sopenharmony_ci unsigned long reg; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci dev_dbg(fbi->dev, "%s release\n", fbi->fix.id); 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci /* display off */ 7948c2ecf20Sopenharmony_ci reg = inreg(disp, GC_DCM1); 7958c2ecf20Sopenharmony_ci reg &= ~(GC_DCM01_DEN | GC_DCM01_L0E); 7968c2ecf20Sopenharmony_ci outreg(disp, GC_DCM1, reg); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci /* disable interrupts */ 7998c2ecf20Sopenharmony_ci outreg(host, GC_IMASK, 0); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci free_irq(par->irq, (void *)par); 8028c2ecf20Sopenharmony_ci irq_dispose_mapping(par->irq); 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci device_remove_file(&ofdev->dev, &dev_attr_dispregs); 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci unregister_framebuffer(fbi); 8078c2ecf20Sopenharmony_ci fb_dealloc_cmap(&fbi->cmap); 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci iounmap(par->mmio_base); 8108c2ecf20Sopenharmony_ci iounmap(par->fb_base); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci release_mem_region(par->res->start, res_size); 8138c2ecf20Sopenharmony_ci framebuffer_release(fbi); 8148c2ecf20Sopenharmony_ci return 0; 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci/* 8188c2ecf20Sopenharmony_ci * common types 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_cistatic struct of_device_id of_platform_mb862xx_tbl[] = { 8218c2ecf20Sopenharmony_ci { .compatible = "fujitsu,MB86276", }, 8228c2ecf20Sopenharmony_ci { .compatible = "fujitsu,lime", }, 8238c2ecf20Sopenharmony_ci { .compatible = "fujitsu,MB86277", }, 8248c2ecf20Sopenharmony_ci { .compatible = "fujitsu,mint", }, 8258c2ecf20Sopenharmony_ci { .compatible = "fujitsu,MB86293", }, 8268c2ecf20Sopenharmony_ci { .compatible = "fujitsu,MB86294", }, 8278c2ecf20Sopenharmony_ci { .compatible = "fujitsu,coral", }, 8288c2ecf20Sopenharmony_ci { /* end */ } 8298c2ecf20Sopenharmony_ci}; 8308c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_platform_mb862xx_tbl); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistatic struct platform_driver of_platform_mb862xxfb_driver = { 8338c2ecf20Sopenharmony_ci .driver = { 8348c2ecf20Sopenharmony_ci .name = DRV_NAME, 8358c2ecf20Sopenharmony_ci .of_match_table = of_platform_mb862xx_tbl, 8368c2ecf20Sopenharmony_ci }, 8378c2ecf20Sopenharmony_ci .probe = of_platform_mb862xx_probe, 8388c2ecf20Sopenharmony_ci .remove = of_platform_mb862xx_remove, 8398c2ecf20Sopenharmony_ci}; 8408c2ecf20Sopenharmony_ci#endif 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_MB862XX_PCI_GDC) 8438c2ecf20Sopenharmony_cistatic int coralp_init(struct mb862xxfb_par *par) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci int cn, ver; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci par->host = par->mmio_base; 8488c2ecf20Sopenharmony_ci par->i2c = par->mmio_base + MB862XX_I2C_BASE; 8498c2ecf20Sopenharmony_ci par->disp = par->mmio_base + MB862XX_DISP_BASE; 8508c2ecf20Sopenharmony_ci par->cap = par->mmio_base + MB862XX_CAP_BASE; 8518c2ecf20Sopenharmony_ci par->draw = par->mmio_base + MB862XX_DRAW_BASE; 8528c2ecf20Sopenharmony_ci par->geo = par->mmio_base + MB862XX_GEO_BASE; 8538c2ecf20Sopenharmony_ci par->pio = par->mmio_base + MB862XX_PIO_BASE; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci par->refclk = GC_DISP_REFCLK_400; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci if (par->mapped_vram >= 0x2000000) { 8588c2ecf20Sopenharmony_ci /* relocate gdc registers space */ 8598c2ecf20Sopenharmony_ci writel(1, par->fb_base + MB862XX_MMIO_BASE + GC_RSW); 8608c2ecf20Sopenharmony_ci udelay(1); /* wait at least 20 bus cycles */ 8618c2ecf20Sopenharmony_ci } 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci ver = inreg(host, GC_CID); 8648c2ecf20Sopenharmony_ci cn = (ver & GC_CID_CNAME_MSK) >> 8; 8658c2ecf20Sopenharmony_ci ver = ver & GC_CID_VERSION_MSK; 8668c2ecf20Sopenharmony_ci if (cn == 3) { 8678c2ecf20Sopenharmony_ci unsigned long reg; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci dev_info(par->dev, "Fujitsu Coral-%s GDC Rev.%d found\n",\ 8708c2ecf20Sopenharmony_ci (ver == 6) ? "P" : (ver == 8) ? "PA" : "?", 8718c2ecf20Sopenharmony_ci par->pdev->revision); 8728c2ecf20Sopenharmony_ci reg = inreg(disp, GC_DCM1); 8738c2ecf20Sopenharmony_ci if (reg & GC_DCM01_DEN && reg & GC_DCM01_L0E) 8748c2ecf20Sopenharmony_ci par->pre_init = 1; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (!par->pre_init) { 8778c2ecf20Sopenharmony_ci outreg(host, GC_CCF, GC_CCF_CGE_166 | GC_CCF_COT_133); 8788c2ecf20Sopenharmony_ci udelay(200); 8798c2ecf20Sopenharmony_ci outreg(host, GC_MMR, GC_MMR_CORALP_EVB_VAL); 8808c2ecf20Sopenharmony_ci udelay(10); 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci /* Clear interrupt status */ 8838c2ecf20Sopenharmony_ci outreg(host, GC_IST, 0); 8848c2ecf20Sopenharmony_ci } else { 8858c2ecf20Sopenharmony_ci return -ENODEV; 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci mb862xx_i2c_init(par); 8898c2ecf20Sopenharmony_ci return 0; 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic int init_dram_ctrl(struct mb862xxfb_par *par) 8938c2ecf20Sopenharmony_ci{ 8948c2ecf20Sopenharmony_ci unsigned long i = 0; 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci /* 8978c2ecf20Sopenharmony_ci * Set io mode first! Spec. says IC may be destroyed 8988c2ecf20Sopenharmony_ci * if not set to SSTL2/LVCMOS before init. 8998c2ecf20Sopenharmony_ci */ 9008c2ecf20Sopenharmony_ci outreg(dram_ctrl, GC_DCTL_IOCONT1_IOCONT0, GC_EVB_DCTL_IOCONT1_IOCONT0); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci /* DRAM init */ 9038c2ecf20Sopenharmony_ci outreg(dram_ctrl, GC_DCTL_MODE_ADD, GC_EVB_DCTL_MODE_ADD); 9048c2ecf20Sopenharmony_ci outreg(dram_ctrl, GC_DCTL_SETTIME1_EMODE, GC_EVB_DCTL_SETTIME1_EMODE); 9058c2ecf20Sopenharmony_ci outreg(dram_ctrl, GC_DCTL_REFRESH_SETTIME2, 9068c2ecf20Sopenharmony_ci GC_EVB_DCTL_REFRESH_SETTIME2); 9078c2ecf20Sopenharmony_ci outreg(dram_ctrl, GC_DCTL_RSV2_RSV1, GC_EVB_DCTL_RSV2_RSV1); 9088c2ecf20Sopenharmony_ci outreg(dram_ctrl, GC_DCTL_DDRIF2_DDRIF1, GC_EVB_DCTL_DDRIF2_DDRIF1); 9098c2ecf20Sopenharmony_ci outreg(dram_ctrl, GC_DCTL_RSV0_STATES, GC_EVB_DCTL_RSV0_STATES); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci /* DLL reset done? */ 9128c2ecf20Sopenharmony_ci while ((inreg(dram_ctrl, GC_DCTL_RSV0_STATES) & GC_DCTL_STATES_MSK)) { 9138c2ecf20Sopenharmony_ci udelay(GC_DCTL_INIT_WAIT_INTERVAL); 9148c2ecf20Sopenharmony_ci if (i++ > GC_DCTL_INIT_WAIT_CNT) { 9158c2ecf20Sopenharmony_ci dev_err(par->dev, "VRAM init failed.\n"); 9168c2ecf20Sopenharmony_ci return -EINVAL; 9178c2ecf20Sopenharmony_ci } 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci outreg(dram_ctrl, GC_DCTL_MODE_ADD, GC_EVB_DCTL_MODE_ADD_AFT_RST); 9208c2ecf20Sopenharmony_ci outreg(dram_ctrl, GC_DCTL_RSV0_STATES, GC_EVB_DCTL_RSV0_STATES_AFT_RST); 9218c2ecf20Sopenharmony_ci return 0; 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_cistatic int carmine_init(struct mb862xxfb_par *par) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci unsigned long reg; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci par->ctrl = par->mmio_base + MB86297_CTRL_BASE; 9298c2ecf20Sopenharmony_ci par->i2c = par->mmio_base + MB86297_I2C_BASE; 9308c2ecf20Sopenharmony_ci par->disp = par->mmio_base + MB86297_DISP0_BASE; 9318c2ecf20Sopenharmony_ci par->disp1 = par->mmio_base + MB86297_DISP1_BASE; 9328c2ecf20Sopenharmony_ci par->cap = par->mmio_base + MB86297_CAP0_BASE; 9338c2ecf20Sopenharmony_ci par->cap1 = par->mmio_base + MB86297_CAP1_BASE; 9348c2ecf20Sopenharmony_ci par->draw = par->mmio_base + MB86297_DRAW_BASE; 9358c2ecf20Sopenharmony_ci par->dram_ctrl = par->mmio_base + MB86297_DRAMCTRL_BASE; 9368c2ecf20Sopenharmony_ci par->wrback = par->mmio_base + MB86297_WRBACK_BASE; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci par->refclk = GC_DISP_REFCLK_533; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci /* warm up */ 9418c2ecf20Sopenharmony_ci reg = GC_CTRL_CLK_EN_DRAM | GC_CTRL_CLK_EN_2D3D | GC_CTRL_CLK_EN_DISP0; 9428c2ecf20Sopenharmony_ci outreg(ctrl, GC_CTRL_CLK_ENABLE, reg); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci /* check for engine module revision */ 9458c2ecf20Sopenharmony_ci if (inreg(draw, GC_2D3D_REV) == GC_RE_REVISION) 9468c2ecf20Sopenharmony_ci dev_info(par->dev, "Fujitsu Carmine GDC Rev.%d found\n", 9478c2ecf20Sopenharmony_ci par->pdev->revision); 9488c2ecf20Sopenharmony_ci else 9498c2ecf20Sopenharmony_ci goto err_init; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci reg &= ~GC_CTRL_CLK_EN_2D3D; 9528c2ecf20Sopenharmony_ci outreg(ctrl, GC_CTRL_CLK_ENABLE, reg); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci /* set up vram */ 9558c2ecf20Sopenharmony_ci if (init_dram_ctrl(par) < 0) 9568c2ecf20Sopenharmony_ci goto err_init; 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci outreg(ctrl, GC_CTRL_INT_MASK, 0); 9598c2ecf20Sopenharmony_ci return 0; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_cierr_init: 9628c2ecf20Sopenharmony_ci outreg(ctrl, GC_CTRL_CLK_ENABLE, 0); 9638c2ecf20Sopenharmony_ci return -EINVAL; 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_cistatic inline int mb862xx_pci_gdc_init(struct mb862xxfb_par *par) 9678c2ecf20Sopenharmony_ci{ 9688c2ecf20Sopenharmony_ci switch (par->type) { 9698c2ecf20Sopenharmony_ci case BT_CORALP: 9708c2ecf20Sopenharmony_ci return coralp_init(par); 9718c2ecf20Sopenharmony_ci case BT_CARMINE: 9728c2ecf20Sopenharmony_ci return carmine_init(par); 9738c2ecf20Sopenharmony_ci default: 9748c2ecf20Sopenharmony_ci return -ENODEV; 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci#define CHIP_ID(id) \ 9798c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_FUJITSU_LIMITED, id) } 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic const struct pci_device_id mb862xx_pci_tbl[] = { 9828c2ecf20Sopenharmony_ci /* MB86295/MB86296 */ 9838c2ecf20Sopenharmony_ci CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALP), 9848c2ecf20Sopenharmony_ci CHIP_ID(PCI_DEVICE_ID_FUJITSU_CORALPA), 9858c2ecf20Sopenharmony_ci /* MB86297 */ 9868c2ecf20Sopenharmony_ci CHIP_ID(PCI_DEVICE_ID_FUJITSU_CARMINE), 9878c2ecf20Sopenharmony_ci { 0, } 9888c2ecf20Sopenharmony_ci}; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mb862xx_pci_tbl); 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_cistatic int mb862xx_pci_probe(struct pci_dev *pdev, 9938c2ecf20Sopenharmony_ci const struct pci_device_id *ent) 9948c2ecf20Sopenharmony_ci{ 9958c2ecf20Sopenharmony_ci struct mb862xxfb_par *par; 9968c2ecf20Sopenharmony_ci struct fb_info *info; 9978c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 9988c2ecf20Sopenharmony_ci int ret; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci ret = pci_enable_device(pdev); 10018c2ecf20Sopenharmony_ci if (ret < 0) { 10028c2ecf20Sopenharmony_ci dev_err(dev, "Cannot enable PCI device\n"); 10038c2ecf20Sopenharmony_ci goto out; 10048c2ecf20Sopenharmony_ci } 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct mb862xxfb_par), dev); 10078c2ecf20Sopenharmony_ci if (!info) { 10088c2ecf20Sopenharmony_ci ret = -ENOMEM; 10098c2ecf20Sopenharmony_ci goto dis_dev; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci par = info->par; 10138c2ecf20Sopenharmony_ci par->info = info; 10148c2ecf20Sopenharmony_ci par->dev = dev; 10158c2ecf20Sopenharmony_ci par->pdev = pdev; 10168c2ecf20Sopenharmony_ci par->irq = pdev->irq; 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci ret = pci_request_regions(pdev, DRV_NAME); 10198c2ecf20Sopenharmony_ci if (ret < 0) { 10208c2ecf20Sopenharmony_ci dev_err(dev, "Cannot reserve region(s) for PCI device\n"); 10218c2ecf20Sopenharmony_ci goto rel_fb; 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci switch (pdev->device) { 10258c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_FUJITSU_CORALP: 10268c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_FUJITSU_CORALPA: 10278c2ecf20Sopenharmony_ci par->fb_base_phys = pci_resource_start(par->pdev, 0); 10288c2ecf20Sopenharmony_ci par->mapped_vram = CORALP_MEM_SIZE; 10298c2ecf20Sopenharmony_ci if (par->mapped_vram >= 0x2000000) { 10308c2ecf20Sopenharmony_ci par->mmio_base_phys = par->fb_base_phys + 10318c2ecf20Sopenharmony_ci MB862XX_MMIO_HIGH_BASE; 10328c2ecf20Sopenharmony_ci } else { 10338c2ecf20Sopenharmony_ci par->mmio_base_phys = par->fb_base_phys + 10348c2ecf20Sopenharmony_ci MB862XX_MMIO_BASE; 10358c2ecf20Sopenharmony_ci } 10368c2ecf20Sopenharmony_ci par->mmio_len = MB862XX_MMIO_SIZE; 10378c2ecf20Sopenharmony_ci par->type = BT_CORALP; 10388c2ecf20Sopenharmony_ci break; 10398c2ecf20Sopenharmony_ci case PCI_DEVICE_ID_FUJITSU_CARMINE: 10408c2ecf20Sopenharmony_ci par->fb_base_phys = pci_resource_start(par->pdev, 2); 10418c2ecf20Sopenharmony_ci par->mmio_base_phys = pci_resource_start(par->pdev, 3); 10428c2ecf20Sopenharmony_ci par->mmio_len = pci_resource_len(par->pdev, 3); 10438c2ecf20Sopenharmony_ci par->mapped_vram = CARMINE_MEM_SIZE; 10448c2ecf20Sopenharmony_ci par->type = BT_CARMINE; 10458c2ecf20Sopenharmony_ci break; 10468c2ecf20Sopenharmony_ci default: 10478c2ecf20Sopenharmony_ci /* should never occur */ 10488c2ecf20Sopenharmony_ci ret = -EIO; 10498c2ecf20Sopenharmony_ci goto rel_reg; 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci par->fb_base = ioremap(par->fb_base_phys, par->mapped_vram); 10538c2ecf20Sopenharmony_ci if (par->fb_base == NULL) { 10548c2ecf20Sopenharmony_ci dev_err(dev, "Cannot map framebuffer\n"); 10558c2ecf20Sopenharmony_ci ret = -EIO; 10568c2ecf20Sopenharmony_ci goto rel_reg; 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci par->mmio_base = ioremap(par->mmio_base_phys, par->mmio_len); 10608c2ecf20Sopenharmony_ci if (par->mmio_base == NULL) { 10618c2ecf20Sopenharmony_ci dev_err(dev, "Cannot map registers\n"); 10628c2ecf20Sopenharmony_ci ret = -EIO; 10638c2ecf20Sopenharmony_ci goto fb_unmap; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci 10668c2ecf20Sopenharmony_ci dev_dbg(dev, "fb phys 0x%llx 0x%lx\n", 10678c2ecf20Sopenharmony_ci (unsigned long long)par->fb_base_phys, (ulong)par->mapped_vram); 10688c2ecf20Sopenharmony_ci dev_dbg(dev, "mmio phys 0x%llx 0x%lx\n", 10698c2ecf20Sopenharmony_ci (unsigned long long)par->mmio_base_phys, (ulong)par->mmio_len); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci ret = mb862xx_pci_gdc_init(par); 10728c2ecf20Sopenharmony_ci if (ret) 10738c2ecf20Sopenharmony_ci goto io_unmap; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci ret = request_irq(par->irq, mb862xx_intr, IRQF_SHARED, 10768c2ecf20Sopenharmony_ci DRV_NAME, (void *)par); 10778c2ecf20Sopenharmony_ci if (ret) { 10788c2ecf20Sopenharmony_ci dev_err(dev, "Cannot request irq\n"); 10798c2ecf20Sopenharmony_ci goto io_unmap; 10808c2ecf20Sopenharmony_ci } 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci mb862xxfb_init_fbinfo(info); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (fb_alloc_cmap(&info->cmap, NR_PALETTE, 0) < 0) { 10858c2ecf20Sopenharmony_ci dev_err(dev, "Could not allocate cmap for fb_info.\n"); 10868c2ecf20Sopenharmony_ci ret = -ENOMEM; 10878c2ecf20Sopenharmony_ci goto free_irq; 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci if ((info->fbops->fb_set_par)(info)) 10918c2ecf20Sopenharmony_ci dev_err(dev, "set_var() failed on initial setup?\n"); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci ret = register_framebuffer(info); 10948c2ecf20Sopenharmony_ci if (ret < 0) { 10958c2ecf20Sopenharmony_ci dev_err(dev, "failed to register framebuffer\n"); 10968c2ecf20Sopenharmony_ci goto rel_cmap; 10978c2ecf20Sopenharmony_ci } 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, info); 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (device_create_file(dev, &dev_attr_dispregs)) 11028c2ecf20Sopenharmony_ci dev_err(dev, "Can't create sysfs regdump file\n"); 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci if (par->type == BT_CARMINE) 11058c2ecf20Sopenharmony_ci outreg(ctrl, GC_CTRL_INT_MASK, GC_CARMINE_INT_EN); 11068c2ecf20Sopenharmony_ci else 11078c2ecf20Sopenharmony_ci outreg(host, GC_IMASK, GC_INT_EN); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci return 0; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_cirel_cmap: 11128c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 11138c2ecf20Sopenharmony_cifree_irq: 11148c2ecf20Sopenharmony_ci free_irq(par->irq, (void *)par); 11158c2ecf20Sopenharmony_ciio_unmap: 11168c2ecf20Sopenharmony_ci iounmap(par->mmio_base); 11178c2ecf20Sopenharmony_cifb_unmap: 11188c2ecf20Sopenharmony_ci iounmap(par->fb_base); 11198c2ecf20Sopenharmony_cirel_reg: 11208c2ecf20Sopenharmony_ci pci_release_regions(pdev); 11218c2ecf20Sopenharmony_cirel_fb: 11228c2ecf20Sopenharmony_ci framebuffer_release(info); 11238c2ecf20Sopenharmony_cidis_dev: 11248c2ecf20Sopenharmony_ci pci_disable_device(pdev); 11258c2ecf20Sopenharmony_ciout: 11268c2ecf20Sopenharmony_ci return ret; 11278c2ecf20Sopenharmony_ci} 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_cistatic void mb862xx_pci_remove(struct pci_dev *pdev) 11308c2ecf20Sopenharmony_ci{ 11318c2ecf20Sopenharmony_ci struct fb_info *fbi = pci_get_drvdata(pdev); 11328c2ecf20Sopenharmony_ci struct mb862xxfb_par *par = fbi->par; 11338c2ecf20Sopenharmony_ci unsigned long reg; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci dev_dbg(fbi->dev, "%s release\n", fbi->fix.id); 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci /* display off */ 11388c2ecf20Sopenharmony_ci reg = inreg(disp, GC_DCM1); 11398c2ecf20Sopenharmony_ci reg &= ~(GC_DCM01_DEN | GC_DCM01_L0E); 11408c2ecf20Sopenharmony_ci outreg(disp, GC_DCM1, reg); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci if (par->type == BT_CARMINE) { 11438c2ecf20Sopenharmony_ci outreg(ctrl, GC_CTRL_INT_MASK, 0); 11448c2ecf20Sopenharmony_ci outreg(ctrl, GC_CTRL_CLK_ENABLE, 0); 11458c2ecf20Sopenharmony_ci } else { 11468c2ecf20Sopenharmony_ci outreg(host, GC_IMASK, 0); 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci mb862xx_i2c_exit(par); 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci device_remove_file(&pdev->dev, &dev_attr_dispregs); 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci unregister_framebuffer(fbi); 11548c2ecf20Sopenharmony_ci fb_dealloc_cmap(&fbi->cmap); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci free_irq(par->irq, (void *)par); 11578c2ecf20Sopenharmony_ci iounmap(par->mmio_base); 11588c2ecf20Sopenharmony_ci iounmap(par->fb_base); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci pci_release_regions(pdev); 11618c2ecf20Sopenharmony_ci framebuffer_release(fbi); 11628c2ecf20Sopenharmony_ci pci_disable_device(pdev); 11638c2ecf20Sopenharmony_ci} 11648c2ecf20Sopenharmony_ci 11658c2ecf20Sopenharmony_cistatic struct pci_driver mb862xxfb_pci_driver = { 11668c2ecf20Sopenharmony_ci .name = DRV_NAME, 11678c2ecf20Sopenharmony_ci .id_table = mb862xx_pci_tbl, 11688c2ecf20Sopenharmony_ci .probe = mb862xx_pci_probe, 11698c2ecf20Sopenharmony_ci .remove = mb862xx_pci_remove, 11708c2ecf20Sopenharmony_ci}; 11718c2ecf20Sopenharmony_ci#endif 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_cistatic int mb862xxfb_init(void) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci int ret = -ENODEV; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_MB862XX_LIME) 11788c2ecf20Sopenharmony_ci ret = platform_driver_register(&of_platform_mb862xxfb_driver); 11798c2ecf20Sopenharmony_ci#endif 11808c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_MB862XX_PCI_GDC) 11818c2ecf20Sopenharmony_ci ret = pci_register_driver(&mb862xxfb_pci_driver); 11828c2ecf20Sopenharmony_ci#endif 11838c2ecf20Sopenharmony_ci return ret; 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_cistatic void __exit mb862xxfb_exit(void) 11878c2ecf20Sopenharmony_ci{ 11888c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_MB862XX_LIME) 11898c2ecf20Sopenharmony_ci platform_driver_unregister(&of_platform_mb862xxfb_driver); 11908c2ecf20Sopenharmony_ci#endif 11918c2ecf20Sopenharmony_ci#if defined(CONFIG_FB_MB862XX_PCI_GDC) 11928c2ecf20Sopenharmony_ci pci_unregister_driver(&mb862xxfb_pci_driver); 11938c2ecf20Sopenharmony_ci#endif 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cimodule_init(mb862xxfb_init); 11978c2ecf20Sopenharmony_cimodule_exit(mb862xxfb_exit); 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Fujitsu MB862xx Framebuffer driver"); 12008c2ecf20Sopenharmony_ciMODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>"); 12018c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1202