18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* leo.c: LEO frame buffer driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) 58c2ecf20Sopenharmony_ci * Copyright (C) 1996-1999 Jakub Jelinek (jj@ultra.linux.cz) 68c2ecf20Sopenharmony_ci * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Driver layout based loosely on tgafb.c, see that file for credits. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/errno.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/delay.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/fb.h> 188c2ecf20Sopenharmony_ci#include <linux/mm.h> 198c2ecf20Sopenharmony_ci#include <linux/of_device.h> 208c2ecf20Sopenharmony_ci#include <linux/io.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <asm/fbio.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "sbuslib.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * Local functions. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int leo_setcolreg(unsigned, unsigned, unsigned, unsigned, 318c2ecf20Sopenharmony_ci unsigned, struct fb_info *); 328c2ecf20Sopenharmony_cistatic int leo_blank(int, struct fb_info *); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic int leo_mmap(struct fb_info *, struct vm_area_struct *); 358c2ecf20Sopenharmony_cistatic int leo_ioctl(struct fb_info *, unsigned int, unsigned long); 368c2ecf20Sopenharmony_cistatic int leo_pan_display(struct fb_var_screeninfo *, struct fb_info *); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * Frame buffer operations 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const struct fb_ops leo_ops = { 438c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 448c2ecf20Sopenharmony_ci .fb_setcolreg = leo_setcolreg, 458c2ecf20Sopenharmony_ci .fb_blank = leo_blank, 468c2ecf20Sopenharmony_ci .fb_pan_display = leo_pan_display, 478c2ecf20Sopenharmony_ci .fb_fillrect = cfb_fillrect, 488c2ecf20Sopenharmony_ci .fb_copyarea = cfb_copyarea, 498c2ecf20Sopenharmony_ci .fb_imageblit = cfb_imageblit, 508c2ecf20Sopenharmony_ci .fb_mmap = leo_mmap, 518c2ecf20Sopenharmony_ci .fb_ioctl = leo_ioctl, 528c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 538c2ecf20Sopenharmony_ci .fb_compat_ioctl = sbusfb_compat_ioctl, 548c2ecf20Sopenharmony_ci#endif 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define LEO_OFF_LC_SS0_KRN 0x00200000UL 588c2ecf20Sopenharmony_ci#define LEO_OFF_LC_SS0_USR 0x00201000UL 598c2ecf20Sopenharmony_ci#define LEO_OFF_LC_SS1_KRN 0x01200000UL 608c2ecf20Sopenharmony_ci#define LEO_OFF_LC_SS1_USR 0x01201000UL 618c2ecf20Sopenharmony_ci#define LEO_OFF_LD_SS0 0x00400000UL 628c2ecf20Sopenharmony_ci#define LEO_OFF_LD_SS1 0x01400000UL 638c2ecf20Sopenharmony_ci#define LEO_OFF_LD_GBL 0x00401000UL 648c2ecf20Sopenharmony_ci#define LEO_OFF_LX_KRN 0x00600000UL 658c2ecf20Sopenharmony_ci#define LEO_OFF_LX_CURSOR 0x00601000UL 668c2ecf20Sopenharmony_ci#define LEO_OFF_SS0 0x00800000UL 678c2ecf20Sopenharmony_ci#define LEO_OFF_SS1 0x01800000UL 688c2ecf20Sopenharmony_ci#define LEO_OFF_UNK 0x00602000UL 698c2ecf20Sopenharmony_ci#define LEO_OFF_UNK2 0x00000000UL 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define LEO_CUR_ENABLE 0x00000080 728c2ecf20Sopenharmony_ci#define LEO_CUR_UPDATE 0x00000030 738c2ecf20Sopenharmony_ci#define LEO_CUR_PROGRESS 0x00000006 748c2ecf20Sopenharmony_ci#define LEO_CUR_UPDATECMAP 0x00000003 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define LEO_CUR_TYPE_MASK 0x00000000 778c2ecf20Sopenharmony_ci#define LEO_CUR_TYPE_IMAGE 0x00000020 788c2ecf20Sopenharmony_ci#define LEO_CUR_TYPE_CMAP 0x00000050 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistruct leo_cursor { 818c2ecf20Sopenharmony_ci u8 xxx0[16]; 828c2ecf20Sopenharmony_ci u32 cur_type; 838c2ecf20Sopenharmony_ci u32 cur_misc; 848c2ecf20Sopenharmony_ci u32 cur_cursxy; 858c2ecf20Sopenharmony_ci u32 cur_data; 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define LEO_KRN_TYPE_CLUT0 0x00001000 898c2ecf20Sopenharmony_ci#define LEO_KRN_TYPE_CLUT1 0x00001001 908c2ecf20Sopenharmony_ci#define LEO_KRN_TYPE_CLUT2 0x00001002 918c2ecf20Sopenharmony_ci#define LEO_KRN_TYPE_WID 0x00001003 928c2ecf20Sopenharmony_ci#define LEO_KRN_TYPE_UNK 0x00001006 938c2ecf20Sopenharmony_ci#define LEO_KRN_TYPE_VIDEO 0x00002003 948c2ecf20Sopenharmony_ci#define LEO_KRN_TYPE_CLUTDATA 0x00004000 958c2ecf20Sopenharmony_ci#define LEO_KRN_CSR_ENABLE 0x00000008 968c2ecf20Sopenharmony_ci#define LEO_KRN_CSR_PROGRESS 0x00000004 978c2ecf20Sopenharmony_ci#define LEO_KRN_CSR_UNK 0x00000002 988c2ecf20Sopenharmony_ci#define LEO_KRN_CSR_UNK2 0x00000001 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistruct leo_lx_krn { 1018c2ecf20Sopenharmony_ci u32 krn_type; 1028c2ecf20Sopenharmony_ci u32 krn_csr; 1038c2ecf20Sopenharmony_ci u32 krn_value; 1048c2ecf20Sopenharmony_ci}; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistruct leo_lc_ss0_krn { 1078c2ecf20Sopenharmony_ci u32 misc; 1088c2ecf20Sopenharmony_ci u8 xxx0[0x800-4]; 1098c2ecf20Sopenharmony_ci u32 rev; 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistruct leo_lc_ss0_usr { 1138c2ecf20Sopenharmony_ci u32 csr; 1148c2ecf20Sopenharmony_ci u32 addrspace; 1158c2ecf20Sopenharmony_ci u32 fontmsk; 1168c2ecf20Sopenharmony_ci u32 fontt; 1178c2ecf20Sopenharmony_ci u32 extent; 1188c2ecf20Sopenharmony_ci u32 src; 1198c2ecf20Sopenharmony_ci u32 dst; 1208c2ecf20Sopenharmony_ci u32 copy; 1218c2ecf20Sopenharmony_ci u32 fill; 1228c2ecf20Sopenharmony_ci}; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistruct leo_lc_ss1_krn { 1258c2ecf20Sopenharmony_ci u8 unknown; 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistruct leo_lc_ss1_usr { 1298c2ecf20Sopenharmony_ci u8 unknown; 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistruct leo_ld_ss0 { 1338c2ecf20Sopenharmony_ci u8 xxx0[0xe00]; 1348c2ecf20Sopenharmony_ci u32 csr; 1358c2ecf20Sopenharmony_ci u32 wid; 1368c2ecf20Sopenharmony_ci u32 wmask; 1378c2ecf20Sopenharmony_ci u32 widclip; 1388c2ecf20Sopenharmony_ci u32 vclipmin; 1398c2ecf20Sopenharmony_ci u32 vclipmax; 1408c2ecf20Sopenharmony_ci u32 pickmin; /* SS1 only */ 1418c2ecf20Sopenharmony_ci u32 pickmax; /* SS1 only */ 1428c2ecf20Sopenharmony_ci u32 fg; 1438c2ecf20Sopenharmony_ci u32 bg; 1448c2ecf20Sopenharmony_ci u32 src; /* Copy/Scroll (SS0 only) */ 1458c2ecf20Sopenharmony_ci u32 dst; /* Copy/Scroll/Fill (SS0 only) */ 1468c2ecf20Sopenharmony_ci u32 extent; /* Copy/Scroll/Fill size (SS0 only) */ 1478c2ecf20Sopenharmony_ci u32 xxx1[3]; 1488c2ecf20Sopenharmony_ci u32 setsem; /* SS1 only */ 1498c2ecf20Sopenharmony_ci u32 clrsem; /* SS1 only */ 1508c2ecf20Sopenharmony_ci u32 clrpick; /* SS1 only */ 1518c2ecf20Sopenharmony_ci u32 clrdat; /* SS1 only */ 1528c2ecf20Sopenharmony_ci u32 alpha; /* SS1 only */ 1538c2ecf20Sopenharmony_ci u8 xxx2[0x2c]; 1548c2ecf20Sopenharmony_ci u32 winbg; 1558c2ecf20Sopenharmony_ci u32 planemask; 1568c2ecf20Sopenharmony_ci u32 rop; 1578c2ecf20Sopenharmony_ci u32 z; 1588c2ecf20Sopenharmony_ci u32 dczf; /* SS1 only */ 1598c2ecf20Sopenharmony_ci u32 dczb; /* SS1 only */ 1608c2ecf20Sopenharmony_ci u32 dcs; /* SS1 only */ 1618c2ecf20Sopenharmony_ci u32 dczs; /* SS1 only */ 1628c2ecf20Sopenharmony_ci u32 pickfb; /* SS1 only */ 1638c2ecf20Sopenharmony_ci u32 pickbb; /* SS1 only */ 1648c2ecf20Sopenharmony_ci u32 dcfc; /* SS1 only */ 1658c2ecf20Sopenharmony_ci u32 forcecol; /* SS1 only */ 1668c2ecf20Sopenharmony_ci u32 door[8]; /* SS1 only */ 1678c2ecf20Sopenharmony_ci u32 pick[5]; /* SS1 only */ 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#define LEO_SS1_MISC_ENABLE 0x00000001 1718c2ecf20Sopenharmony_ci#define LEO_SS1_MISC_STEREO 0x00000002 1728c2ecf20Sopenharmony_cistruct leo_ld_ss1 { 1738c2ecf20Sopenharmony_ci u8 xxx0[0xef4]; 1748c2ecf20Sopenharmony_ci u32 ss1_misc; 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistruct leo_ld_gbl { 1788c2ecf20Sopenharmony_ci u8 unknown; 1798c2ecf20Sopenharmony_ci}; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistruct leo_par { 1828c2ecf20Sopenharmony_ci spinlock_t lock; 1838c2ecf20Sopenharmony_ci struct leo_lx_krn __iomem *lx_krn; 1848c2ecf20Sopenharmony_ci struct leo_lc_ss0_usr __iomem *lc_ss0_usr; 1858c2ecf20Sopenharmony_ci struct leo_ld_ss0 __iomem *ld_ss0; 1868c2ecf20Sopenharmony_ci struct leo_ld_ss1 __iomem *ld_ss1; 1878c2ecf20Sopenharmony_ci struct leo_cursor __iomem *cursor; 1888c2ecf20Sopenharmony_ci u32 extent; 1898c2ecf20Sopenharmony_ci u32 clut_data[256]; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci u32 flags; 1928c2ecf20Sopenharmony_ci#define LEO_FLAG_BLANKED 0x00000001 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci unsigned long which_io; 1958c2ecf20Sopenharmony_ci}; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic void leo_wait(struct leo_lx_krn __iomem *lx_krn) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int i; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci for (i = 0; 2028c2ecf20Sopenharmony_ci (sbus_readl(&lx_krn->krn_csr) & LEO_KRN_CSR_PROGRESS) && 2038c2ecf20Sopenharmony_ci i < 300000; 2048c2ecf20Sopenharmony_ci i++) 2058c2ecf20Sopenharmony_ci udelay(1); /* Busy wait at most 0.3 sec */ 2068c2ecf20Sopenharmony_ci return; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void leo_switch_from_graph(struct fb_info *info) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct leo_par *par = (struct leo_par *) info->par; 2128c2ecf20Sopenharmony_ci struct leo_ld_ss0 __iomem *ss = par->ld_ss0; 2138c2ecf20Sopenharmony_ci struct leo_cursor __iomem *cursor = par->cursor; 2148c2ecf20Sopenharmony_ci unsigned long flags; 2158c2ecf20Sopenharmony_ci u32 val; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci spin_lock_irqsave(&par->lock, flags); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci par->extent = ((info->var.xres - 1) | 2208c2ecf20Sopenharmony_ci ((info->var.yres - 1) << 16)); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci sbus_writel(0xffffffff, &ss->wid); 2238c2ecf20Sopenharmony_ci sbus_writel(0xffff, &ss->wmask); 2248c2ecf20Sopenharmony_ci sbus_writel(0, &ss->vclipmin); 2258c2ecf20Sopenharmony_ci sbus_writel(par->extent, &ss->vclipmax); 2268c2ecf20Sopenharmony_ci sbus_writel(0, &ss->fg); 2278c2ecf20Sopenharmony_ci sbus_writel(0xff000000, &ss->planemask); 2288c2ecf20Sopenharmony_ci sbus_writel(0x310850, &ss->rop); 2298c2ecf20Sopenharmony_ci sbus_writel(0, &ss->widclip); 2308c2ecf20Sopenharmony_ci sbus_writel((info->var.xres-1) | ((info->var.yres-1) << 11), 2318c2ecf20Sopenharmony_ci &par->lc_ss0_usr->extent); 2328c2ecf20Sopenharmony_ci sbus_writel(4, &par->lc_ss0_usr->addrspace); 2338c2ecf20Sopenharmony_ci sbus_writel(0x80000000, &par->lc_ss0_usr->fill); 2348c2ecf20Sopenharmony_ci sbus_writel(0, &par->lc_ss0_usr->fontt); 2358c2ecf20Sopenharmony_ci do { 2368c2ecf20Sopenharmony_ci val = sbus_readl(&par->lc_ss0_usr->csr); 2378c2ecf20Sopenharmony_ci } while (val & 0x20000000); 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* setup screen buffer for cfb_* functions */ 2408c2ecf20Sopenharmony_ci sbus_writel(1, &ss->wid); 2418c2ecf20Sopenharmony_ci sbus_writel(0x00ffffff, &ss->planemask); 2428c2ecf20Sopenharmony_ci sbus_writel(0x310b90, &ss->rop); 2438c2ecf20Sopenharmony_ci sbus_writel(0, &par->lc_ss0_usr->addrspace); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* hide cursor */ 2468c2ecf20Sopenharmony_ci sbus_writel(sbus_readl(&cursor->cur_misc) & ~LEO_CUR_ENABLE, &cursor->cur_misc); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&par->lock, flags); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistatic int leo_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci /* We just use this to catch switches out of 2548c2ecf20Sopenharmony_ci * graphics mode. 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_ci leo_switch_from_graph(info); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (var->xoffset || var->yoffset || var->vmode) 2598c2ecf20Sopenharmony_ci return -EINVAL; 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/** 2648c2ecf20Sopenharmony_ci * leo_setcolreg - Optional function. Sets a color register. 2658c2ecf20Sopenharmony_ci * @regno: boolean, 0 copy local, 1 get_user() function 2668c2ecf20Sopenharmony_ci * @red: frame buffer colormap structure 2678c2ecf20Sopenharmony_ci * @green: The green value which can be up to 16 bits wide 2688c2ecf20Sopenharmony_ci * @blue: The blue value which can be up to 16 bits wide. 2698c2ecf20Sopenharmony_ci * @transp: If supported the alpha value which can be up to 16 bits wide. 2708c2ecf20Sopenharmony_ci * @info: frame buffer info structure 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_cistatic int leo_setcolreg(unsigned regno, 2738c2ecf20Sopenharmony_ci unsigned red, unsigned green, unsigned blue, 2748c2ecf20Sopenharmony_ci unsigned transp, struct fb_info *info) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct leo_par *par = (struct leo_par *) info->par; 2778c2ecf20Sopenharmony_ci struct leo_lx_krn __iomem *lx_krn = par->lx_krn; 2788c2ecf20Sopenharmony_ci unsigned long flags; 2798c2ecf20Sopenharmony_ci u32 val; 2808c2ecf20Sopenharmony_ci int i; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (regno >= 256) 2838c2ecf20Sopenharmony_ci return 1; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci red >>= 8; 2868c2ecf20Sopenharmony_ci green >>= 8; 2878c2ecf20Sopenharmony_ci blue >>= 8; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci par->clut_data[regno] = red | (green << 8) | (blue << 16); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci spin_lock_irqsave(&par->lock, flags); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci leo_wait(lx_krn); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci sbus_writel(LEO_KRN_TYPE_CLUTDATA, &lx_krn->krn_type); 2968c2ecf20Sopenharmony_ci for (i = 0; i < 256; i++) 2978c2ecf20Sopenharmony_ci sbus_writel(par->clut_data[i], &lx_krn->krn_value); 2988c2ecf20Sopenharmony_ci sbus_writel(LEO_KRN_TYPE_CLUT0, &lx_krn->krn_type); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci val = sbus_readl(&lx_krn->krn_csr); 3018c2ecf20Sopenharmony_ci val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2); 3028c2ecf20Sopenharmony_ci sbus_writel(val, &lx_krn->krn_csr); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&par->lock, flags); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/** 3108c2ecf20Sopenharmony_ci * leo_blank - Optional function. Blanks the display. 3118c2ecf20Sopenharmony_ci * @blank_mode: the blank mode we want. 3128c2ecf20Sopenharmony_ci * @info: frame buffer structure that represents a single frame buffer 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_cistatic int leo_blank(int blank, struct fb_info *info) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct leo_par *par = (struct leo_par *) info->par; 3178c2ecf20Sopenharmony_ci struct leo_lx_krn __iomem *lx_krn = par->lx_krn; 3188c2ecf20Sopenharmony_ci unsigned long flags; 3198c2ecf20Sopenharmony_ci u32 val; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci spin_lock_irqsave(&par->lock, flags); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci switch (blank) { 3248c2ecf20Sopenharmony_ci case FB_BLANK_UNBLANK: /* Unblanking */ 3258c2ecf20Sopenharmony_ci val = sbus_readl(&lx_krn->krn_csr); 3268c2ecf20Sopenharmony_ci val |= LEO_KRN_CSR_ENABLE; 3278c2ecf20Sopenharmony_ci sbus_writel(val, &lx_krn->krn_csr); 3288c2ecf20Sopenharmony_ci par->flags &= ~LEO_FLAG_BLANKED; 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci case FB_BLANK_NORMAL: /* Normal blanking */ 3328c2ecf20Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ 3338c2ecf20Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ 3348c2ecf20Sopenharmony_ci case FB_BLANK_POWERDOWN: /* Poweroff */ 3358c2ecf20Sopenharmony_ci val = sbus_readl(&lx_krn->krn_csr); 3368c2ecf20Sopenharmony_ci val &= ~LEO_KRN_CSR_ENABLE; 3378c2ecf20Sopenharmony_ci sbus_writel(val, &lx_krn->krn_csr); 3388c2ecf20Sopenharmony_ci par->flags |= LEO_FLAG_BLANKED; 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&par->lock, flags); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci return 0; 3458c2ecf20Sopenharmony_ci} 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic struct sbus_mmap_map leo_mmap_map[] = { 3488c2ecf20Sopenharmony_ci { 3498c2ecf20Sopenharmony_ci .voff = LEO_SS0_MAP, 3508c2ecf20Sopenharmony_ci .poff = LEO_OFF_SS0, 3518c2ecf20Sopenharmony_ci .size = 0x800000 3528c2ecf20Sopenharmony_ci }, 3538c2ecf20Sopenharmony_ci { 3548c2ecf20Sopenharmony_ci .voff = LEO_LC_SS0_USR_MAP, 3558c2ecf20Sopenharmony_ci .poff = LEO_OFF_LC_SS0_USR, 3568c2ecf20Sopenharmony_ci .size = 0x1000 3578c2ecf20Sopenharmony_ci }, 3588c2ecf20Sopenharmony_ci { 3598c2ecf20Sopenharmony_ci .voff = LEO_LD_SS0_MAP, 3608c2ecf20Sopenharmony_ci .poff = LEO_OFF_LD_SS0, 3618c2ecf20Sopenharmony_ci .size = 0x1000 3628c2ecf20Sopenharmony_ci }, 3638c2ecf20Sopenharmony_ci { 3648c2ecf20Sopenharmony_ci .voff = LEO_LX_CURSOR_MAP, 3658c2ecf20Sopenharmony_ci .poff = LEO_OFF_LX_CURSOR, 3668c2ecf20Sopenharmony_ci .size = 0x1000 3678c2ecf20Sopenharmony_ci }, 3688c2ecf20Sopenharmony_ci { 3698c2ecf20Sopenharmony_ci .voff = LEO_SS1_MAP, 3708c2ecf20Sopenharmony_ci .poff = LEO_OFF_SS1, 3718c2ecf20Sopenharmony_ci .size = 0x800000 3728c2ecf20Sopenharmony_ci }, 3738c2ecf20Sopenharmony_ci { 3748c2ecf20Sopenharmony_ci .voff = LEO_LC_SS1_USR_MAP, 3758c2ecf20Sopenharmony_ci .poff = LEO_OFF_LC_SS1_USR, 3768c2ecf20Sopenharmony_ci .size = 0x1000 3778c2ecf20Sopenharmony_ci }, 3788c2ecf20Sopenharmony_ci { 3798c2ecf20Sopenharmony_ci .voff = LEO_LD_SS1_MAP, 3808c2ecf20Sopenharmony_ci .poff = LEO_OFF_LD_SS1, 3818c2ecf20Sopenharmony_ci .size = 0x1000 3828c2ecf20Sopenharmony_ci }, 3838c2ecf20Sopenharmony_ci { 3848c2ecf20Sopenharmony_ci .voff = LEO_UNK_MAP, 3858c2ecf20Sopenharmony_ci .poff = LEO_OFF_UNK, 3868c2ecf20Sopenharmony_ci .size = 0x1000 3878c2ecf20Sopenharmony_ci }, 3888c2ecf20Sopenharmony_ci { 3898c2ecf20Sopenharmony_ci .voff = LEO_LX_KRN_MAP, 3908c2ecf20Sopenharmony_ci .poff = LEO_OFF_LX_KRN, 3918c2ecf20Sopenharmony_ci .size = 0x1000 3928c2ecf20Sopenharmony_ci }, 3938c2ecf20Sopenharmony_ci { 3948c2ecf20Sopenharmony_ci .voff = LEO_LC_SS0_KRN_MAP, 3958c2ecf20Sopenharmony_ci .poff = LEO_OFF_LC_SS0_KRN, 3968c2ecf20Sopenharmony_ci .size = 0x1000 3978c2ecf20Sopenharmony_ci }, 3988c2ecf20Sopenharmony_ci { 3998c2ecf20Sopenharmony_ci .voff = LEO_LC_SS1_KRN_MAP, 4008c2ecf20Sopenharmony_ci .poff = LEO_OFF_LC_SS1_KRN, 4018c2ecf20Sopenharmony_ci .size = 0x1000 4028c2ecf20Sopenharmony_ci }, 4038c2ecf20Sopenharmony_ci { 4048c2ecf20Sopenharmony_ci .voff = LEO_LD_GBL_MAP, 4058c2ecf20Sopenharmony_ci .poff = LEO_OFF_LD_GBL, 4068c2ecf20Sopenharmony_ci .size = 0x1000 4078c2ecf20Sopenharmony_ci }, 4088c2ecf20Sopenharmony_ci { 4098c2ecf20Sopenharmony_ci .voff = LEO_UNK2_MAP, 4108c2ecf20Sopenharmony_ci .poff = LEO_OFF_UNK2, 4118c2ecf20Sopenharmony_ci .size = 0x100000 4128c2ecf20Sopenharmony_ci }, 4138c2ecf20Sopenharmony_ci { .size = 0 } 4148c2ecf20Sopenharmony_ci}; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct leo_par *par = (struct leo_par *)info->par; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return sbusfb_mmap_helper(leo_mmap_map, 4218c2ecf20Sopenharmony_ci info->fix.smem_start, info->fix.smem_len, 4228c2ecf20Sopenharmony_ci par->which_io, vma); 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci return sbusfb_ioctl_helper(cmd, arg, info, 4288c2ecf20Sopenharmony_ci FBTYPE_SUNLEO, 32, info->fix.smem_len); 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci/* 4328c2ecf20Sopenharmony_ci * Initialisation 4338c2ecf20Sopenharmony_ci */ 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic void 4368c2ecf20Sopenharmony_cileo_init_fix(struct fb_info *info, struct device_node *dp) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci info->fix.type = FB_TYPE_PACKED_PIXELS; 4418c2ecf20Sopenharmony_ci info->fix.visual = FB_VISUAL_TRUECOLOR; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci info->fix.line_length = 8192; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci info->fix.accel = FB_ACCEL_SUN_LEO; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic void leo_wid_put(struct fb_info *info, struct fb_wid_list *wl) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci struct leo_par *par = (struct leo_par *) info->par; 4518c2ecf20Sopenharmony_ci struct leo_lx_krn __iomem *lx_krn = par->lx_krn; 4528c2ecf20Sopenharmony_ci struct fb_wid_item *wi; 4538c2ecf20Sopenharmony_ci unsigned long flags; 4548c2ecf20Sopenharmony_ci u32 val; 4558c2ecf20Sopenharmony_ci int i, j; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci spin_lock_irqsave(&par->lock, flags); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci leo_wait(lx_krn); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci for (i = 0, wi = wl->wl_list; i < wl->wl_count; i++, wi++) { 4628c2ecf20Sopenharmony_ci switch (wi->wi_type) { 4638c2ecf20Sopenharmony_ci case FB_WID_DBL_8: 4648c2ecf20Sopenharmony_ci j = (wi->wi_index & 0xf) + 0x40; 4658c2ecf20Sopenharmony_ci break; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci case FB_WID_DBL_24: 4688c2ecf20Sopenharmony_ci j = wi->wi_index & 0x3f; 4698c2ecf20Sopenharmony_ci break; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci default: 4728c2ecf20Sopenharmony_ci continue; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci sbus_writel(0x5800 + j, &lx_krn->krn_type); 4758c2ecf20Sopenharmony_ci sbus_writel(wi->wi_values[0], &lx_krn->krn_value); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci sbus_writel(LEO_KRN_TYPE_WID, &lx_krn->krn_type); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci val = sbus_readl(&lx_krn->krn_csr); 4808c2ecf20Sopenharmony_ci val |= (LEO_KRN_CSR_UNK | LEO_KRN_CSR_UNK2); 4818c2ecf20Sopenharmony_ci sbus_writel(val, &lx_krn->krn_csr); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&par->lock, flags); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic void leo_init_wids(struct fb_info *info) 4878c2ecf20Sopenharmony_ci{ 4888c2ecf20Sopenharmony_ci struct fb_wid_item wi; 4898c2ecf20Sopenharmony_ci struct fb_wid_list wl; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci wl.wl_count = 1; 4928c2ecf20Sopenharmony_ci wl.wl_list = &wi; 4938c2ecf20Sopenharmony_ci wi.wi_type = FB_WID_DBL_8; 4948c2ecf20Sopenharmony_ci wi.wi_index = 0; 4958c2ecf20Sopenharmony_ci wi.wi_values [0] = 0x2c0; 4968c2ecf20Sopenharmony_ci leo_wid_put(info, &wl); 4978c2ecf20Sopenharmony_ci wi.wi_index = 1; 4988c2ecf20Sopenharmony_ci wi.wi_values [0] = 0x30; 4998c2ecf20Sopenharmony_ci leo_wid_put(info, &wl); 5008c2ecf20Sopenharmony_ci wi.wi_index = 2; 5018c2ecf20Sopenharmony_ci wi.wi_values [0] = 0x20; 5028c2ecf20Sopenharmony_ci leo_wid_put(info, &wl); 5038c2ecf20Sopenharmony_ci wi.wi_type = FB_WID_DBL_24; 5048c2ecf20Sopenharmony_ci wi.wi_index = 1; 5058c2ecf20Sopenharmony_ci wi.wi_values [0] = 0x30; 5068c2ecf20Sopenharmony_ci leo_wid_put(info, &wl); 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_cistatic void leo_init_hw(struct fb_info *info) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci struct leo_par *par = (struct leo_par *) info->par; 5128c2ecf20Sopenharmony_ci u32 val; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci val = sbus_readl(&par->ld_ss1->ss1_misc); 5158c2ecf20Sopenharmony_ci val |= LEO_SS1_MISC_ENABLE; 5168c2ecf20Sopenharmony_ci sbus_writel(val, &par->ld_ss1->ss1_misc); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci leo_switch_from_graph(info); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic void leo_fixup_var_rgb(struct fb_var_screeninfo *var) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci var->red.offset = 0; 5248c2ecf20Sopenharmony_ci var->red.length = 8; 5258c2ecf20Sopenharmony_ci var->green.offset = 8; 5268c2ecf20Sopenharmony_ci var->green.length = 8; 5278c2ecf20Sopenharmony_ci var->blue.offset = 16; 5288c2ecf20Sopenharmony_ci var->blue.length = 8; 5298c2ecf20Sopenharmony_ci var->transp.offset = 0; 5308c2ecf20Sopenharmony_ci var->transp.length = 0; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic void leo_unmap_regs(struct platform_device *op, struct fb_info *info, 5348c2ecf20Sopenharmony_ci struct leo_par *par) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci if (par->lc_ss0_usr) 5378c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], par->lc_ss0_usr, 0x1000); 5388c2ecf20Sopenharmony_ci if (par->ld_ss0) 5398c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], par->ld_ss0, 0x1000); 5408c2ecf20Sopenharmony_ci if (par->ld_ss1) 5418c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], par->ld_ss1, 0x1000); 5428c2ecf20Sopenharmony_ci if (par->lx_krn) 5438c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], par->lx_krn, 0x1000); 5448c2ecf20Sopenharmony_ci if (par->cursor) 5458c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], 5468c2ecf20Sopenharmony_ci par->cursor, sizeof(struct leo_cursor)); 5478c2ecf20Sopenharmony_ci if (info->screen_base) 5488c2ecf20Sopenharmony_ci of_iounmap(&op->resource[0], info->screen_base, 0x800000); 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int leo_probe(struct platform_device *op) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct device_node *dp = op->dev.of_node; 5548c2ecf20Sopenharmony_ci struct fb_info *info; 5558c2ecf20Sopenharmony_ci struct leo_par *par; 5568c2ecf20Sopenharmony_ci int linebytes, err; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci info = framebuffer_alloc(sizeof(struct leo_par), &op->dev); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci err = -ENOMEM; 5618c2ecf20Sopenharmony_ci if (!info) 5628c2ecf20Sopenharmony_ci goto out_err; 5638c2ecf20Sopenharmony_ci par = info->par; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci spin_lock_init(&par->lock); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci info->fix.smem_start = op->resource[0].start; 5688c2ecf20Sopenharmony_ci par->which_io = op->resource[0].flags & IORESOURCE_BITS; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci sbusfb_fill_var(&info->var, dp, 32); 5718c2ecf20Sopenharmony_ci leo_fixup_var_rgb(&info->var); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci linebytes = of_getintprop_default(dp, "linebytes", 5748c2ecf20Sopenharmony_ci info->var.xres); 5758c2ecf20Sopenharmony_ci info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci par->lc_ss0_usr = 5788c2ecf20Sopenharmony_ci of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, 5798c2ecf20Sopenharmony_ci 0x1000, "leolc ss0usr"); 5808c2ecf20Sopenharmony_ci par->ld_ss0 = 5818c2ecf20Sopenharmony_ci of_ioremap(&op->resource[0], LEO_OFF_LD_SS0, 5828c2ecf20Sopenharmony_ci 0x1000, "leold ss0"); 5838c2ecf20Sopenharmony_ci par->ld_ss1 = 5848c2ecf20Sopenharmony_ci of_ioremap(&op->resource[0], LEO_OFF_LD_SS1, 5858c2ecf20Sopenharmony_ci 0x1000, "leold ss1"); 5868c2ecf20Sopenharmony_ci par->lx_krn = 5878c2ecf20Sopenharmony_ci of_ioremap(&op->resource[0], LEO_OFF_LX_KRN, 5888c2ecf20Sopenharmony_ci 0x1000, "leolx krn"); 5898c2ecf20Sopenharmony_ci par->cursor = 5908c2ecf20Sopenharmony_ci of_ioremap(&op->resource[0], LEO_OFF_LX_CURSOR, 5918c2ecf20Sopenharmony_ci sizeof(struct leo_cursor), "leolx cursor"); 5928c2ecf20Sopenharmony_ci info->screen_base = 5938c2ecf20Sopenharmony_ci of_ioremap(&op->resource[0], LEO_OFF_SS0, 5948c2ecf20Sopenharmony_ci 0x800000, "leo ram"); 5958c2ecf20Sopenharmony_ci if (!par->lc_ss0_usr || 5968c2ecf20Sopenharmony_ci !par->ld_ss0 || 5978c2ecf20Sopenharmony_ci !par->ld_ss1 || 5988c2ecf20Sopenharmony_ci !par->lx_krn || 5998c2ecf20Sopenharmony_ci !par->cursor || 6008c2ecf20Sopenharmony_ci !info->screen_base) 6018c2ecf20Sopenharmony_ci goto out_unmap_regs; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci info->flags = FBINFO_DEFAULT; 6048c2ecf20Sopenharmony_ci info->fbops = &leo_ops; 6058c2ecf20Sopenharmony_ci info->pseudo_palette = par->clut_data; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci leo_init_wids(info); 6088c2ecf20Sopenharmony_ci leo_init_hw(info); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci leo_blank(FB_BLANK_UNBLANK, info); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (fb_alloc_cmap(&info->cmap, 256, 0)) 6138c2ecf20Sopenharmony_ci goto out_unmap_regs; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci leo_init_fix(info, dp); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci err = register_framebuffer(info); 6188c2ecf20Sopenharmony_ci if (err < 0) 6198c2ecf20Sopenharmony_ci goto out_dealloc_cmap; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci dev_set_drvdata(&op->dev, info); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci printk(KERN_INFO "%pOF: leo at %lx:%lx\n", 6248c2ecf20Sopenharmony_ci dp, 6258c2ecf20Sopenharmony_ci par->which_io, info->fix.smem_start); 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ciout_dealloc_cmap: 6308c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ciout_unmap_regs: 6338c2ecf20Sopenharmony_ci leo_unmap_regs(op, info, par); 6348c2ecf20Sopenharmony_ci framebuffer_release(info); 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ciout_err: 6378c2ecf20Sopenharmony_ci return err; 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic int leo_remove(struct platform_device *op) 6418c2ecf20Sopenharmony_ci{ 6428c2ecf20Sopenharmony_ci struct fb_info *info = dev_get_drvdata(&op->dev); 6438c2ecf20Sopenharmony_ci struct leo_par *par = info->par; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci unregister_framebuffer(info); 6468c2ecf20Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci leo_unmap_regs(op, info, par); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci framebuffer_release(info); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic const struct of_device_id leo_match[] = { 6568c2ecf20Sopenharmony_ci { 6578c2ecf20Sopenharmony_ci .name = "SUNW,leo", 6588c2ecf20Sopenharmony_ci }, 6598c2ecf20Sopenharmony_ci {}, 6608c2ecf20Sopenharmony_ci}; 6618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, leo_match); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic struct platform_driver leo_driver = { 6648c2ecf20Sopenharmony_ci .driver = { 6658c2ecf20Sopenharmony_ci .name = "leo", 6668c2ecf20Sopenharmony_ci .of_match_table = leo_match, 6678c2ecf20Sopenharmony_ci }, 6688c2ecf20Sopenharmony_ci .probe = leo_probe, 6698c2ecf20Sopenharmony_ci .remove = leo_remove, 6708c2ecf20Sopenharmony_ci}; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic int __init leo_init(void) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci if (fb_get_options("leofb", NULL)) 6758c2ecf20Sopenharmony_ci return -ENODEV; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return platform_driver_register(&leo_driver); 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic void __exit leo_exit(void) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci platform_driver_unregister(&leo_driver); 6838c2ecf20Sopenharmony_ci} 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_cimodule_init(leo_init); 6868c2ecf20Sopenharmony_cimodule_exit(leo_exit); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("framebuffer driver for LEO chipsets"); 6898c2ecf20Sopenharmony_ciMODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 6908c2ecf20Sopenharmony_ciMODULE_VERSION("2.0"); 6918c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 692