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