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)  * Xilinx TFT frame buffer driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Author: MontaVista Software, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *         source@mvista.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * 2002-2007 (c) MontaVista Software, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * 2007 (c) Secret Lab Technologies, Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * 2009 (c) Xilinx Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * This file is licensed under the terms of the GNU General Public License
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * version 2.  This program is licensed "as is" without any warranty of any
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * kind, whether express or implied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  * This driver was based on au1100fb.c by MontaVista rewritten for 2.6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  * by Embedded Alley Solutions <source@embeddedalley.com>, which in turn
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  * was based on skeletonfb.c, Skeleton for a frame buffer device by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  * Geert Uytterhoeven.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) #include <asm/dcr.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) #define DRIVER_NAME		"xilinxfb"
^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)  * Xilinx calls it "TFT LCD Controller" though it can also be used for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  * the VGA port on the Xilinx ML40x board. This is a hardware display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)  * controller for a 640x480 resolution TFT or VGA screen.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49)  * The interface to the framebuffer is nice and simple.  There are two
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50)  * control registers.  The first tells the LCD interface where in memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51)  * the frame buffer is (only the 11 most significant bits are used, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52)  * don't start thinking about scrolling).  The second allows the LCD to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53)  * be turned on or off as well as rotated 180 degrees.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55)  * In case of direct BUS access the second control register will be at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56)  * an offset of 4 as compared to the DCR access where the offset is 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57)  * i.e. REG_CTRL. So this is taken care in the function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58)  * xilinx_fb_out32 where it left shifts the offset 2 times in case of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59)  * direct BUS access.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) #define NUM_REGS	2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) #define REG_FB_ADDR	0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) #define REG_CTRL	1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) #define REG_CTRL_ENABLE	 0x0001
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) #define REG_CTRL_ROTATE	 0x0002
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68)  * The hardware only handles a single mode: 640x480 24 bit true
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69)  * color. Each pixel gets a word (32 bits) of memory.  Within each word,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70)  * the 8 most significant bits are ignored, the next 8 bits are the red
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71)  * level, the next 8 bits are the green level and the 8 least
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72)  * significant bits are the blue level.  Each row of the LCD uses 1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73)  * words, but only the first 640 pixels are displayed with the other 384
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74)  * words being ignored.  There are 480 rows.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) #define BYTES_PER_PIXEL	4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) #define BITS_PER_PIXEL	(BYTES_PER_PIXEL * 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) #define RED_SHIFT	16
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) #define GREEN_SHIFT	8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) #define BLUE_SHIFT	0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) #define PALETTE_ENTRIES_NO	16	/* passed to fb_alloc_cmap() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) /* ML300/403 reference design framebuffer driver platform data struct */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) struct xilinxfb_platform_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	u32 rotate_screen;      /* Flag to rotate display 180 degrees */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	u32 screen_height_mm;   /* Physical dimensions of screen in mm */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	u32 screen_width_mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	u32 xres, yres;         /* resolution of screen in pixels */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	u32 xvirt, yvirt;       /* resolution of memory buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	/* Physical address of framebuffer memory; If non-zero, driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	 * will use provided memory address instead of allocating one from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	 * the consistent pool.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	u32 fb_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)  * Default xilinxfb configuration
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static const struct xilinxfb_platform_data xilinx_fb_default_pdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	.xres = 640,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	.yres = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	.xvirt = 1024,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	.yvirt = 480,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)  * Here are the default fb_fix_screeninfo and fb_var_screeninfo structures
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) static const struct fb_fix_screeninfo xilinx_fb_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	.id =		"Xilinx",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	.type =		FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	.visual =	FB_VISUAL_TRUECOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	.accel =	FB_ACCEL_NONE
^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_var_screeninfo xilinx_fb_var = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	.bits_per_pixel =	BITS_PER_PIXEL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	.red =		{ RED_SHIFT, 8, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	.green =	{ GREEN_SHIFT, 8, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	.blue =		{ BLUE_SHIFT, 8, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	.transp =	{ 0, 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	.activate =	FB_ACTIVATE_NOW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) #define BUS_ACCESS_FLAG		0x1 /* 1 = BUS, 0 = DCR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) #define LITTLE_ENDIAN_ACCESS	0x2 /* LITTLE ENDIAN IO functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct xilinxfb_drvdata {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	struct fb_info	info;		/* FB driver info record */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	phys_addr_t	regs_phys;	/* phys. address of the control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 					 * registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 					 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	void __iomem	*regs;		/* virt. address of the control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 					 * registers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 					 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	dcr_host_t      dcr_host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	unsigned int    dcr_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	void		*fb_virt;	/* virt. address of the frame buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	dma_addr_t	fb_phys;	/* phys. address of the frame buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	int		fb_alloced;	/* Flag, was the fb memory alloced? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	u8		flags;		/* features of the driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	u32		reg_ctrl_default;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	u32		pseudo_palette[PALETTE_ENTRIES_NO];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 					/* Fake palette of 16 colors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) #define to_xilinxfb_drvdata(_info) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	container_of(_info, struct xilinxfb_drvdata, info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)  * The XPS TFT Controller can be accessed through BUS or DCR interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)  * To perform the read/write on the registers we need to check on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)  * which bus its connected and call the appropriate write API.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static void xilinx_fb_out32(struct xilinxfb_drvdata *drvdata, u32 offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 			    u32 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	if (drvdata->flags & BUS_ACCESS_FLAG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 			iowrite32(val, drvdata->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 			iowrite32be(val, drvdata->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		dcr_write(drvdata->dcr_host, offset, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static u32 xilinx_fb_in32(struct xilinxfb_drvdata *drvdata, u32 offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	if (drvdata->flags & BUS_ACCESS_FLAG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 		if (drvdata->flags & LITTLE_ENDIAN_ACCESS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 			return ioread32(drvdata->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 			return ioread32be(drvdata->regs + (offset << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		return dcr_read(drvdata->dcr_host, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) xilinx_fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 		    unsigned int blue, unsigned int transp, struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	u32 *palette = fbi->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	if (regno >= PALETTE_ENTRIES_NO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	if (fbi->var.grayscale) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		/* Convert color to grayscale.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 		 * grayscale = 0.30*R + 0.59*G + 0.11*B
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		blue = (red * 77 + green * 151 + blue * 28 + 127) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 		green = blue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 		red = green;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	/* fbi->fix.visual is always FB_VISUAL_TRUECOLOR */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	/* We only handle 8 bits of each color. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	red >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	green >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	blue >>= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	palette[regno] = (red << RED_SHIFT) | (green << GREEN_SHIFT) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 			 (blue << BLUE_SHIFT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) xilinx_fb_blank(int blank_mode, struct fb_info *fbi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	struct xilinxfb_drvdata *drvdata = to_xilinxfb_drvdata(fbi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	switch (blank_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	case FB_BLANK_UNBLANK:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		/* turn on panel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 		xilinx_fb_out32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	case FB_BLANK_NORMAL:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	case FB_BLANK_VSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	case FB_BLANK_HSYNC_SUSPEND:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	case FB_BLANK_POWERDOWN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 		/* turn off panel */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		xilinx_fb_out32(drvdata, REG_CTRL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	return 0; /* success */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) static const struct fb_ops xilinxfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	.owner			= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	.fb_setcolreg		= xilinx_fb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 	.fb_blank		= xilinx_fb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	.fb_fillrect		= cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	.fb_copyarea		= cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	.fb_imageblit		= cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) /* ---------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)  * Bus independent setup/teardown
^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) static int xilinxfb_assign(struct platform_device *pdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 			   struct xilinxfb_drvdata *drvdata,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 			   struct xilinxfb_platform_data *pdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	if (drvdata->flags & BUS_ACCESS_FLAG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 		struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 		drvdata->regs = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 		if (IS_ERR(drvdata->regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 			return PTR_ERR(drvdata->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		drvdata->regs_phys = res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	/* Allocate the framebuffer memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	if (pdata->fb_phys) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		drvdata->fb_phys = pdata->fb_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 		drvdata->fb_virt = ioremap(pdata->fb_phys, fbsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		drvdata->fb_alloced = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		drvdata->fb_virt = dma_alloc_coherent(dev, PAGE_ALIGN(fbsize),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 						      &drvdata->fb_phys,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 						      GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	if (!drvdata->fb_virt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 		dev_err(dev, "Could not allocate frame buffer memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	/* Clear (turn to black) the framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	memset_io((void __iomem *)drvdata->fb_virt, 0, fbsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	/* Tell the hardware where the frame buffer is */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	rc = xilinx_fb_in32(drvdata, REG_FB_ADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	/* Endianness detection */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	if (rc != drvdata->fb_phys) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 		drvdata->flags |= LITTLE_ENDIAN_ACCESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 		xilinx_fb_out32(drvdata, REG_FB_ADDR, drvdata->fb_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	/* Turn on the display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 	drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	if (pdata->rotate_screen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 		drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	xilinx_fb_out32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	/* Fill struct fb_info */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 	drvdata->info.device = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	drvdata->info.screen_base = (void __iomem *)drvdata->fb_virt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	drvdata->info.fbops = &xilinxfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	drvdata->info.fix = xilinx_fb_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	drvdata->info.fix.smem_start = drvdata->fb_phys;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 	drvdata->info.fix.smem_len = fbsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	drvdata->info.fix.line_length = pdata->xvirt * BYTES_PER_PIXEL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	drvdata->info.pseudo_palette = drvdata->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	drvdata->info.flags = FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 	drvdata->info.var = xilinx_fb_var;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 	drvdata->info.var.height = pdata->screen_height_mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	drvdata->info.var.width = pdata->screen_width_mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	drvdata->info.var.xres = pdata->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	drvdata->info.var.yres = pdata->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	drvdata->info.var.xres_virtual = pdata->xvirt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	drvdata->info.var.yres_virtual = pdata->yvirt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	/* Allocate a colour map */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	rc = fb_alloc_cmap(&drvdata->info.cmap, PALETTE_ENTRIES_NO, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 		dev_err(dev, "Fail to allocate colormap (%d entries)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 			PALETTE_ENTRIES_NO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 		goto err_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	/* Register new frame buffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	rc = register_framebuffer(&drvdata->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 		dev_err(dev, "Could not register frame buffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 		goto err_regfb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	if (drvdata->flags & BUS_ACCESS_FLAG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 		/* Put a banner in the log (for DEBUG) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 		dev_dbg(dev, "regs: phys=%pa, virt=%p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 			&drvdata->regs_phys, drvdata->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 	/* Put a banner in the log (for DEBUG) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		(unsigned long long)drvdata->fb_phys, drvdata->fb_virt, fbsize);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	return 0;	/* success */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) err_regfb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 	fb_dealloc_cmap(&drvdata->info.cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) err_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 	if (drvdata->fb_alloced)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 				  drvdata->fb_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 		iounmap(drvdata->fb_virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 	/* Turn off the display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 	xilinx_fb_out32(drvdata, REG_CTRL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) static int xilinxfb_release(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	struct xilinxfb_drvdata *drvdata = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	xilinx_fb_blank(VESA_POWERDOWN, &drvdata->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	unregister_framebuffer(&drvdata->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 	fb_dealloc_cmap(&drvdata->info.cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 	if (drvdata->fb_alloced)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 		dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 				  drvdata->fb_virt, drvdata->fb_phys);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 		iounmap(drvdata->fb_virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 	/* Turn off the display */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 	xilinx_fb_out32(drvdata, REG_CTRL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 	/* Release the resources, as allocated based on interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	if (!(drvdata->flags & BUS_ACCESS_FLAG))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 		dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) /* ---------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)  * OF bus binding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) static int xilinxfb_of_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	const u32 *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	u32 tft_access = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	struct xilinxfb_platform_data pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 	int size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	struct xilinxfb_drvdata *drvdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 	/* Copy with the default pdata (not a ptr reference!) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 	pdata = xilinx_fb_default_pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 	/* Allocate the driver data region */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 	if (!drvdata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 	 * To check whether the core is connected directly to DCR or BUS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 	 * interface and initialize the tft_access accordingly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 	of_property_read_u32(pdev->dev.of_node, "xlnx,dcr-splb-slave-if",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 			     &tft_access);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 	 * Fill the resource structure if its direct BUS interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	 * otherwise fill the dcr_host structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 	if (tft_access)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 		drvdata->flags |= BUS_ACCESS_FLAG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) #ifdef CONFIG_PPC_DCR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 	else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 		int start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 		start = dcr_resource_start(pdev->dev.of_node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 		drvdata->dcr_len = dcr_resource_len(pdev->dev.of_node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 		drvdata->dcr_host = dcr_map(pdev->dev.of_node, start, drvdata->dcr_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 		if (!DCR_MAP_OK(drvdata->dcr_host)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 			dev_err(&pdev->dev, "invalid DCR address\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 			return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 	prop = of_get_property(pdev->dev.of_node, "phys-size", &size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	if ((prop) && (size >= sizeof(u32) * 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 		pdata.screen_width_mm = prop[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 		pdata.screen_height_mm = prop[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 	prop = of_get_property(pdev->dev.of_node, "resolution", &size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	if ((prop) && (size >= sizeof(u32) * 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 		pdata.xres = prop[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 		pdata.yres = prop[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	prop = of_get_property(pdev->dev.of_node, "virtual-resolution", &size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	if ((prop) && (size >= sizeof(u32) * 2)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 		pdata.xvirt = prop[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 		pdata.yvirt = prop[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	if (of_find_property(pdev->dev.of_node, "rotate-display", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 		pdata.rotate_screen = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 	dev_set_drvdata(&pdev->dev, drvdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	return xilinxfb_assign(pdev, drvdata, &pdata);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) static int xilinxfb_of_remove(struct platform_device *op)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	return xilinxfb_release(&op->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) /* Match table for of_platform binding */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) static const struct of_device_id xilinxfb_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	{ .compatible = "xlnx,xps-tft-1.00.a", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	{ .compatible = "xlnx,xps-tft-2.00.a", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 	{ .compatible = "xlnx,xps-tft-2.01.a", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	{ .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	{ .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 	{},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) static struct platform_driver xilinxfb_of_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 	.probe = xilinxfb_of_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	.remove = xilinxfb_of_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 		.name = DRIVER_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 		.of_match_table = xilinxfb_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) module_platform_driver(xilinxfb_of_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) MODULE_LICENSE("GPL");