Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2)  *	linux/drivers/video/pmag-ba-fb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *	PMAG-BA TURBOchannel Color Frame Buffer (CFB) card support,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *	derived from:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *	"HP300 Topcat framebuffer support (derived from macfb of all things)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  *	Phil Blundell <philb@gnu.org> 1998", the original code can be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *	found in the file hpfb.c in the same directory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *	Based on digital document:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * 	"PMAG-BA TURBOchannel Color Frame Buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  *	 Functional Specification", Revision 1.2, August 27, 1990
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  *	DECstation related code Copyright (C) 1999, 2000, 2001 by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  *	Michael Engel <engel@unix-ag.org>,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  *	Karsten Merker <merker@linuxtag.org> and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  *	Harald Koerfgen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  *	Copyright (c) 2005, 2006  Maciej W. Rozycki
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  *	Copyright (c) 2005  James Simmons
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  *	This file is subject to the terms and conditions of the GNU General
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  *	Public License.  See the file COPYING in the main directory of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  *	archive for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/compiler.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #include <linux/tc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #include <video/pmag-ba-fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) struct pmagbafb_par {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	volatile void __iomem *mmio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	volatile u32 __iomem *dac;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) static const struct fb_var_screeninfo pmagbafb_defined = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	.xres		= 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	.yres		= 864,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	.xres_virtual	= 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	.yres_virtual	= 864,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	.bits_per_pixel	= 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	.red.length	= 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	.green.length	= 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	.blue.length	= 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	.activate	= FB_ACTIVATE_NOW,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	.height		= -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	.width		= -1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	.accel_flags	= FB_ACCEL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	.pixclock	= 14452,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	.left_margin	= 116,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 	.right_margin	= 12,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	.upper_margin	= 34,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	.lower_margin	= 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	.hsync_len	= 128,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	.vsync_len	= 3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 	.sync		= FB_SYNC_ON_GREEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	.vmode		= FB_VMODE_NONINTERLACED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) static const struct fb_fix_screeninfo pmagbafb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	.id		= "PMAG-BA",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	.smem_len	= (1024 * 1024),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	.type		= FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	.visual		= FB_VISUAL_PSEUDOCOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	.line_length	= 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	.mmio_len	= PMAG_BA_SIZE - PMAG_BA_BT459,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) static inline void dac_write(struct pmagbafb_par *par, unsigned int reg, u8 v)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	writeb(v, par->dac + reg / 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) static inline u8 dac_read(struct pmagbafb_par *par, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	return readb(par->dac + reg / 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92)  * Set the palette.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) static int pmagbafb_setcolreg(unsigned int regno, unsigned int red,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 			      unsigned int green, unsigned int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 			      unsigned int transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	struct pmagbafb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	if (regno >= info->cmap.len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 		return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	red   >>= 8;	/* The cmap fields are 16 bits    */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	green >>= 8;	/* wide, but the hardware colormap */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	blue  >>= 8;	/* registers are only 8 bits wide */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	dac_write(par, BT459_ADDR_LO, regno);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	dac_write(par, BT459_ADDR_HI, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	dac_write(par, BT459_CMAP, red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	dac_write(par, BT459_CMAP, green);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	dac_write(par, BT459_CMAP, blue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) static const struct fb_ops pmagbafb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	.owner		= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	.fb_setcolreg	= pmagbafb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	.fb_fillrect	= cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	.fb_copyarea	= cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	.fb_imageblit	= cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)  * Turn the hardware cursor off.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static void pmagbafb_erase_cursor(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	struct pmagbafb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	dac_write(par, BT459_ADDR_LO, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	dac_write(par, BT459_ADDR_HI, 0x03);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	wmb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	dac_write(par, BT459_DATA, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int pmagbafb_probe(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	struct tc_dev *tdev = to_tc_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	resource_size_t start, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	struct pmagbafb_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	info = framebuffer_alloc(sizeof(struct pmagbafb_par), dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	dev_set_drvdata(dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 		printk(KERN_ERR "%s: Cannot allocate color map\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		       dev_name(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		goto err_alloc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	info->fbops = &pmagbafb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	info->fix = pmagbafb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	info->var = pmagbafb_defined;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	info->flags = FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	/* Request the I/O MEM resource.  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	start = tdev->resource.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	len = tdev->resource.end - start + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	if (!request_mem_region(start, len, dev_name(dev))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		printk(KERN_ERR "%s: Cannot reserve FB region\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		       dev_name(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		goto err_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	/* MMIO mapping setup.  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	info->fix.mmio_start = start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 	par->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	if (!par->mmio) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 		printk(KERN_ERR "%s: Cannot map MMIO\n", dev_name(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		goto err_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	par->dac = par->mmio + PMAG_BA_BT459;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	/* Frame buffer mapping setup.  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	info->fix.smem_start = start + PMAG_BA_FBMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	info->screen_base = ioremap(info->fix.smem_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 					    info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	if (!info->screen_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 		printk(KERN_ERR "%s: Cannot map FB\n", dev_name(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		err = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 		goto err_mmio_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	info->screen_size = info->fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	pmagbafb_erase_cursor(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 	err = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	if (err < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 		printk(KERN_ERR "%s: Cannot register framebuffer\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		       dev_name(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		goto err_smem_map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	get_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	fb_info(info, "%s frame buffer device at %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		info->fix.id, dev_name(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) err_smem_map:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	iounmap(info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) err_mmio_map:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	iounmap(par->mmio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) err_resource:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	release_mem_region(start, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) err_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) err_alloc:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static int pmagbafb_remove(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	struct tc_dev *tdev = to_tc_dev(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	struct fb_info *info = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	struct pmagbafb_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	resource_size_t start, len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	put_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	iounmap(info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	iounmap(par->mmio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	start = tdev->resource.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	len = tdev->resource.end - start + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 	release_mem_region(start, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)  * Initialize the framebuffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) static const struct tc_device_id pmagbafb_tc_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	{ "DEC     ", "PMAG-BA " },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	{ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) MODULE_DEVICE_TABLE(tc, pmagbafb_tc_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static struct tc_driver pmagbafb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	.id_table	= pmagbafb_tc_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	.driver		= {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 		.name	= "pmagbafb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 		.bus	= &tc_bus_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 		.probe	= pmagbafb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 		.remove	= pmagbafb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) static int __init pmagbafb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) #ifndef MODULE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	if (fb_get_options("pmagbafb", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	return tc_register_driver(&pmagbafb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) static void __exit pmagbafb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	tc_unregister_driver(&pmagbafb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) module_init(pmagbafb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) module_exit(pmagbafb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) MODULE_LICENSE("GPL");