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) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * linux/drivers/video/ep93xx-fb.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Framebuffer support for the EP93xx series.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Copyright (C) 2007 Bluewater Systems Ltd
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * Author: Ryan Mallon
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * Copyright (c) 2009 H Hartley Sweeten <hsweeten@visionengravers.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * Based on the Cirrus Logic ep93xxfb driver, and various other ep93xxfb
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * drivers.
^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) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/platform_data/video-ep93xx.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) /* Vertical Frame Timing Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #define EP93XXFB_VLINES_TOTAL			0x0000	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #define EP93XXFB_VSYNC				0x0004	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #define EP93XXFB_VACTIVE			0x0008	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #define EP93XXFB_VBLANK				0x0228	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #define EP93XXFB_VCLK				0x000c	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) /* Horizontal Frame Timing Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #define EP93XXFB_HCLKS_TOTAL			0x0010	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #define EP93XXFB_HSYNC				0x0014	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) #define EP93XXFB_HACTIVE			0x0018	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #define EP93XXFB_HBLANK				0x022c	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) #define EP93XXFB_HCLK				0x001c	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) /* Frame Buffer Memory Configuration Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) #define EP93XXFB_SCREEN_PAGE			0x0028
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) #define EP93XXFB_SCREEN_HPAGE			0x002c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) #define EP93XXFB_SCREEN_LINES			0x0030
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) #define EP93XXFB_LINE_LENGTH			0x0034
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) #define EP93XXFB_VLINE_STEP			0x0038
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) #define EP93XXFB_LINE_CARRY			0x003c	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) #define EP93XXFB_EOL_OFFSET			0x0230
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) /* Other Video Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) #define EP93XXFB_BRIGHTNESS			0x0020
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) #define EP93XXFB_ATTRIBS			0x0024	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) #define EP93XXFB_SWLOCK				0x007c	/* SW locked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) #define EP93XXFB_AC_RATE			0x0214
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) #define EP93XXFB_FIFO_LEVEL			0x0234
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) #define EP93XXFB_PIXELMODE			0x0054
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) #define EP93XXFB_PIXELMODE_32BPP		(0x7 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) #define EP93XXFB_PIXELMODE_24BPP		(0x6 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) #define EP93XXFB_PIXELMODE_16BPP		(0x4 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) #define EP93XXFB_PIXELMODE_8BPP			(0x2 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) #define EP93XXFB_PIXELMODE_SHIFT_1P_24B		(0x0 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) #define EP93XXFB_PIXELMODE_SHIFT_1P_18B		(0x1 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) #define EP93XXFB_PIXELMODE_COLOR_LUT		(0x0 << 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) #define EP93XXFB_PIXELMODE_COLOR_888		(0x4 << 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) #define EP93XXFB_PIXELMODE_COLOR_555		(0x5 << 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) #define EP93XXFB_PARL_IF_OUT			0x0058
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) #define EP93XXFB_PARL_IF_IN			0x005c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) /* Blink Control Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) #define EP93XXFB_BLINK_RATE			0x0040
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) #define EP93XXFB_BLINK_MASK			0x0044
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) #define EP93XXFB_BLINK_PATTRN			0x0048
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) #define EP93XXFB_PATTRN_MASK			0x004c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) #define EP93XXFB_BKGRND_OFFSET			0x0050
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) /* Hardware Cursor Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) #define EP93XXFB_CURSOR_ADR_START		0x0060
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) #define EP93XXFB_CURSOR_ADR_RESET		0x0064
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) #define EP93XXFB_CURSOR_SIZE			0x0068
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) #define EP93XXFB_CURSOR_COLOR1			0x006c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) #define EP93XXFB_CURSOR_COLOR2			0x0070
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) #define EP93XXFB_CURSOR_BLINK_COLOR1		0x021c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) #define EP93XXFB_CURSOR_BLINK_COLOR2		0x0220
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) #define EP93XXFB_CURSOR_XY_LOC			0x0074
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) #define EP93XXFB_CURSOR_DSCAN_HY_LOC		0x0078
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) #define EP93XXFB_CURSOR_BLINK_RATE_CTRL		0x0224
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) /* LUT Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) #define EP93XXFB_GRY_SCL_LUTR			0x0080
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) #define EP93XXFB_GRY_SCL_LUTG			0x0280
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) #define EP93XXFB_GRY_SCL_LUTB			0x0300
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) #define EP93XXFB_LUT_SW_CONTROL			0x0218
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) #define EP93XXFB_LUT_SW_CONTROL_SWTCH		(1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) #define EP93XXFB_LUT_SW_CONTROL_SSTAT		(1 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) #define EP93XXFB_COLOR_LUT			0x0400
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) /* Video Signature Registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) #define EP93XXFB_VID_SIG_RSLT_VAL		0x0200
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) #define EP93XXFB_VID_SIG_CTRL			0x0204
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) #define EP93XXFB_VSIG				0x0208
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) #define EP93XXFB_HSIG				0x020c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) #define EP93XXFB_SIG_CLR_STR			0x0210
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) /* Minimum / Maximum resolutions supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) #define EP93XXFB_MIN_XRES			64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) #define EP93XXFB_MIN_YRES			64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) #define EP93XXFB_MAX_XRES			1024
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) #define EP93XXFB_MAX_YRES			768
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) struct ep93xx_fbi {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	struct ep93xxfb_mach_info	*mach_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	struct clk			*clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	struct resource			*res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	void __iomem			*mmio_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	unsigned int			pseudo_palette[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static int check_screenpage_bug = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) module_param(check_screenpage_bug, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) MODULE_PARM_DESC(check_screenpage_bug,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		 "Check for bit 27 screen page bug. Default = 1");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static inline unsigned int ep93xxfb_readl(struct ep93xx_fbi *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 					  unsigned int off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	return __raw_readl(fbi->mmio_base + off);
^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) static inline void ep93xxfb_writel(struct ep93xx_fbi *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 				   unsigned int val, unsigned int off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	__raw_writel(val, fbi->mmio_base + off);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)  * Write to one of the locked raster registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) static inline void ep93xxfb_out_locked(struct ep93xx_fbi *fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 				       unsigned int val, unsigned int reg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	 * We don't need a lock or delay here since the raster register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	 * block will remain unlocked until the next access.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	ep93xxfb_writel(fbi, 0xaa, EP93XXFB_SWLOCK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	ep93xxfb_writel(fbi, val, reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static void ep93xxfb_set_video_attribs(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	unsigned int attribs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	attribs = EP93XXFB_ENABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	attribs |= fbi->mach_info->flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	ep93xxfb_out_locked(fbi, attribs, EP93XXFB_ATTRIBS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) static int ep93xxfb_set_pixelmode(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	unsigned int val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	info->var.transp.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	info->var.transp.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		val = EP93XXFB_PIXELMODE_8BPP | EP93XXFB_PIXELMODE_COLOR_LUT |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 			EP93XXFB_PIXELMODE_SHIFT_1P_18B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		info->var.red.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		info->var.red.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		info->var.green.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		info->var.green.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		info->var.blue.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		info->var.blue.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		info->fix.visual 	= FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 		val = EP93XXFB_PIXELMODE_16BPP | EP93XXFB_PIXELMODE_COLOR_555 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 			EP93XXFB_PIXELMODE_SHIFT_1P_18B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 		info->var.red.offset	= 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 		info->var.red.length	= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		info->var.green.offset	= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		info->var.green.length	= 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		info->var.blue.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		info->var.blue.length	= 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		info->fix.visual 	= FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		val = EP93XXFB_PIXELMODE_24BPP | EP93XXFB_PIXELMODE_COLOR_888 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 			EP93XXFB_PIXELMODE_SHIFT_1P_24B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		info->var.red.offset	= 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 		info->var.red.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 		info->var.green.offset	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 		info->var.green.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 		info->var.blue.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 		info->var.blue.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 		info->fix.visual 	= FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 		val = EP93XXFB_PIXELMODE_32BPP | EP93XXFB_PIXELMODE_COLOR_888 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 			EP93XXFB_PIXELMODE_SHIFT_1P_24B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 		info->var.red.offset	= 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 		info->var.red.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 		info->var.green.offset	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 		info->var.green.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		info->var.blue.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		info->var.blue.length	= 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 		info->fix.visual 	= FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	ep93xxfb_writel(fbi, val, EP93XXFB_PIXELMODE);
^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 void ep93xxfb_set_timing(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 	struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	unsigned int vlines_total, hclks_total, start, stop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	vlines_total = info->var.yres + info->var.upper_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		info->var.lower_margin + info->var.vsync_len - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	hclks_total = info->var.xres + info->var.left_margin +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		info->var.right_margin + info->var.hsync_len - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	ep93xxfb_out_locked(fbi, vlines_total, EP93XXFB_VLINES_TOTAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	ep93xxfb_out_locked(fbi, hclks_total, EP93XXFB_HCLKS_TOTAL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	start = vlines_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	stop = vlines_total - info->var.vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VSYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	start = vlines_total - info->var.vsync_len - info->var.upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	stop = info->var.lower_margin - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	start = vlines_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	stop = vlines_total + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_VCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	start = hclks_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	stop = hclks_total - info->var.hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HSYNC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	start = hclks_total - info->var.hsync_len - info->var.left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	stop = info->var.right_margin - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HBLANK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	start = hclks_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	stop = hclks_total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	ep93xxfb_out_locked(fbi, start | (stop << 16), EP93XXFB_HCLK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	ep93xxfb_out_locked(fbi, 0x0, EP93XXFB_LINE_CARRY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) static int ep93xxfb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	clk_set_rate(fbi->clk, 1000 * PICOS2KHZ(info->var.pixclock));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	ep93xxfb_set_timing(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	info->fix.line_length = info->var.xres_virtual *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		info->var.bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	ep93xxfb_writel(fbi, info->fix.smem_start, EP93XXFB_SCREEN_PAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	ep93xxfb_writel(fbi, info->var.yres - 1, EP93XXFB_SCREEN_LINES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	ep93xxfb_writel(fbi, ((info->var.xres * info->var.bits_per_pixel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 			      / 32) - 1, EP93XXFB_LINE_LENGTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 	ep93xxfb_writel(fbi, info->fix.line_length / 4, EP93XXFB_VLINE_STEP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	ep93xxfb_set_video_attribs(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	return 0;
^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) static int ep93xxfb_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 			      struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 	err = ep93xxfb_set_pixelmode(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	var->xres = max_t(unsigned int, var->xres, EP93XXFB_MIN_XRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	var->xres = min_t(unsigned int, var->xres, EP93XXFB_MAX_XRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	var->xres_virtual = max(var->xres_virtual, var->xres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	var->yres = max_t(unsigned int, var->yres, EP93XXFB_MIN_YRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	var->yres = min_t(unsigned int, var->yres, EP93XXFB_MAX_YRES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	var->yres_virtual = max(var->yres_virtual, var->yres);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	return 0;
^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) static int ep93xxfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	unsigned int offset = vma->vm_pgoff << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	if (offset < info->fix.smem_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 		return dma_mmap_wc(info->dev, vma, info->screen_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 				   info->fix.smem_start, info->fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) static int ep93xxfb_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	unsigned int attribs = ep93xxfb_readl(fbi, EP93XXFB_ATTRIBS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 	if (blank_mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 		if (fbi->mach_info->blank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 			fbi->mach_info->blank(blank_mode, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 		ep93xxfb_out_locked(fbi, attribs & ~EP93XXFB_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 				    EP93XXFB_ATTRIBS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 		clk_disable(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 		clk_enable(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 		ep93xxfb_out_locked(fbi, attribs | EP93XXFB_ENABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 				    EP93XXFB_ATTRIBS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 		if (fbi->mach_info->blank)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 			fbi->mach_info->blank(blank_mode, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static inline int ep93xxfb_convert_color(int val, int width)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	return ((val << width) + 0x7fff - val) >> 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) static int ep93xxfb_setcolreg(unsigned int regno, unsigned int red,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 			      unsigned int green, unsigned int blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 			      unsigned int transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	unsigned int *pal = info->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 	unsigned int ctrl, i, rgb, lut_current, lut_stat;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 	switch (info->fix.visual) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	case FB_VISUAL_PSEUDOCOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 		if (regno > 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 		rgb = ((red & 0xff00) << 8) | (green & 0xff00) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 			((blue & 0xff00) >> 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 		pal[regno] = rgb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		ep93xxfb_writel(fbi, rgb, (EP93XXFB_COLOR_LUT + (regno << 2)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		ctrl = ep93xxfb_readl(fbi, EP93XXFB_LUT_SW_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 		lut_stat = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SSTAT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		lut_current = !!(ctrl & EP93XXFB_LUT_SW_CONTROL_SWTCH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 		if (lut_stat == lut_current) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 			for (i = 0; i < 256; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 				ep93xxfb_writel(fbi, pal[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 					EP93XXFB_COLOR_LUT + (i << 2));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 			ep93xxfb_writel(fbi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 					ctrl ^ EP93XXFB_LUT_SW_CONTROL_SWTCH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 					EP93XXFB_LUT_SW_CONTROL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 	case FB_VISUAL_TRUECOLOR:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 		if (regno > 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 			return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 		red = ep93xxfb_convert_color(red, info->var.red.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 		green = ep93xxfb_convert_color(green, info->var.green.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 		blue = ep93xxfb_convert_color(blue, info->var.blue.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 		transp = ep93xxfb_convert_color(transp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 						info->var.transp.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 		pal[regno] = (red << info->var.red.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 			(green << info->var.green.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 			(blue << info->var.blue.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 			(transp << info->var.transp.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 		return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) static const struct fb_ops ep93xxfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	.owner		= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	.fb_check_var	= ep93xxfb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 	.fb_set_par	= ep93xxfb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 	.fb_blank	= ep93xxfb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 	.fb_fillrect	= cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 	.fb_copyarea	= cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 	.fb_imageblit	= cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	.fb_setcolreg	= ep93xxfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	.fb_mmap	= ep93xxfb_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) static int ep93xxfb_alloc_videomem(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 	char __iomem *virt_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 	dma_addr_t phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 	unsigned int fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	/* Maximum 16bpp -> used memory is maximum x*y*2 bytes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 	fb_size = EP93XXFB_MAX_XRES * EP93XXFB_MAX_YRES * 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 	virt_addr = dma_alloc_wc(info->dev, fb_size, &phys_addr, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	if (!virt_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 	 * There is a bug in the ep93xx framebuffer which causes problems
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 	 * if bit 27 of the physical address is set.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	 * See: https://marc.info/?l=linux-arm-kernel&m=110061245502000&w=2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 	 * There does not seem to be any official errata for this, but I
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 	 * have confirmed the problem exists on my hardware (ep9315) at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 	 * least.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 	if (check_screenpage_bug && phys_addr & (1 << 27)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 		dev_err(info->dev, "ep93xx framebuffer bug. phys addr (0x%x) "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 			"has bit 27 set: cannot init framebuffer\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 			phys_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 		dma_free_coherent(info->dev, fb_size, virt_addr, phys_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 	info->fix.smem_start = phys_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 	info->fix.smem_len = fb_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	info->screen_base = virt_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static void ep93xxfb_dealloc_videomem(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 	if (info->screen_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 		dma_free_coherent(info->dev, info->fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 				  info->screen_base, info->fix.smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) static int ep93xxfb_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 	struct ep93xxfb_mach_info *mach_info = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 	struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 	struct ep93xx_fbi *fbi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	char *video_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	if (!mach_info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 	info = framebuffer_alloc(sizeof(struct ep93xx_fbi), &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 	info->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	platform_set_drvdata(pdev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	fbi->mach_info = mach_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 	err = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 		goto failed_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	err = ep93xxfb_alloc_videomem(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 		goto failed_videomem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 	if (!res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 		err = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 		goto failed_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	 * FIXME - We don't do a request_mem_region here because we are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 	 * sharing the register space with the backlight driver (see
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	 * drivers/video/backlight/ep93xx_bl.c) and doing so will cause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 	 * the second loaded driver to return -EBUSY.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	 * NOTE: No locking is required; the backlight does not touch
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 	 * any of the framebuffer registers.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 	fbi->res = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 	fbi->mmio_base = devm_ioremap(&pdev->dev, res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 				      resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 	if (!fbi->mmio_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 		err = -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 		goto failed_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 	strcpy(info->fix.id, pdev->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 	info->fbops		= &ep93xxfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 	info->fix.type		= FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 	info->fix.accel		= FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 	info->var.activate	= FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 	info->var.vmode		= FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 	info->flags		= FBINFO_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 	info->node		= -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	info->state		= FBINFO_STATE_RUNNING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	info->pseudo_palette	= &fbi->pseudo_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 	fb_get_options("ep93xx-fb", &video_mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	err = fb_find_mode(&info->var, info, video_mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 			   NULL, 0, NULL, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 	if (err == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 		dev_err(info->dev, "No suitable video mode found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 		err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 		goto failed_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 	if (mach_info->setup) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 		err = mach_info->setup(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 		if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 			goto failed_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	err = ep93xxfb_check_var(&info->var, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 		goto failed_check;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 	fbi->clk = devm_clk_get(&pdev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 	if (IS_ERR(fbi->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 		err = PTR_ERR(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 		fbi->clk = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 		goto failed_check;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 	ep93xxfb_set_par(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) 	clk_enable(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) 	err = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) 		goto failed_check;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 	dev_info(info->dev, "registered. Mode = %dx%d-%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) 		 info->var.xres, info->var.yres, info->var.bits_per_pixel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) failed_check:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 	if (fbi->mach_info->teardown)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 		fbi->mach_info->teardown(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) failed_resource:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 	ep93xxfb_dealloc_videomem(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) failed_videomem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 	fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) failed_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 	kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 	return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) static int ep93xxfb_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 	struct fb_info *info = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 	struct ep93xx_fbi *fbi = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 	unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 	clk_disable(fbi->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 	ep93xxfb_dealloc_videomem(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 	fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 	if (fbi->mach_info->teardown)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 		fbi->mach_info->teardown(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 	kfree(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) static struct platform_driver ep93xxfb_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 	.probe		= ep93xxfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 	.remove		= ep93xxfb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 		.name	= "ep93xx-fb",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) module_platform_driver(ep93xxfb_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) MODULE_DESCRIPTION("EP93XX Framebuffer Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) MODULE_ALIAS("platform:ep93xx-fb");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) MODULE_AUTHOR("Ryan Mallon, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 	      "H Hartley Sweeten <hsweeten@visionengravers.com");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) MODULE_LICENSE("GPL");