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/amba-clcd.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Copyright (C) 2001 ARM Limited, by David A Rusling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Updated to 2.5, Deep Blue Solutions Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * License.  See the file COPYING in the main directory of this archive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *  ARM PrimeCell PL110 Color LCD Controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/amba/bus.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/amba/clcd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/backlight.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/clk.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/delay.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/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/mm.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/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/of_graph.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #include <video/display_timing.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) #include <video/of_display_timing.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #include <video/videomode.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #define to_clcd(info)	container_of(info, struct clcd_fb, fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) /* This is limited to 16 characters when displayed by X startup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) static const char *clcd_name = "CLCD FB";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)  * Unfortunately, the enable/disable functions may be called either from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)  * process or IRQ context, and we _need_ to delay.  This is _not_ good.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) static inline void clcdfb_sleep(unsigned int ms)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	if (in_atomic()) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) 		mdelay(ms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 		msleep(ms);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) static inline void clcdfb_set_start(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	unsigned long ustart = fb->fb.fix.smem_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	unsigned long lstart;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	ustart += fb->fb.var.yoffset * fb->fb.fix.line_length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	lstart = ustart + fb->fb.var.yres * fb->fb.fix.line_length / 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	writel(ustart, fb->regs + CLCD_UBAS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	writel(lstart, fb->regs + CLCD_LBAS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) static void clcdfb_disable(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 	u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	if (fb->board->disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		fb->board->disable(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	if (fb->panel->backlight) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 		fb->panel->backlight->props.power = FB_BLANK_POWERDOWN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		backlight_update_status(fb->panel->backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	val = readl(fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	if (val & CNTL_LCDPWR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		val &= ~CNTL_LCDPWR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		writel(val, fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		clcdfb_sleep(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	if (val & CNTL_LCDEN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 		val &= ~CNTL_LCDEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 		writel(val, fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	 * Disable CLCD clock source.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	if (fb->clk_enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 		fb->clk_enabled = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		clk_disable(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) static void clcdfb_enable(struct clcd_fb *fb, u32 cntl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	 * Enable the CLCD clock source.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	if (!fb->clk_enabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 		fb->clk_enabled = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		clk_enable(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	 * Bring up by first enabling..
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	cntl |= CNTL_LCDEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	writel(cntl, fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	clcdfb_sleep(20);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	 * and now apply power.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	cntl |= CNTL_LCDPWR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	writel(cntl, fb->regs + fb->off_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	 * Turn on backlight
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	if (fb->panel->backlight) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 		fb->panel->backlight->props.power = FB_BLANK_UNBLANK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		backlight_update_status(fb->panel->backlight);
^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) 	 * finally, enable the interface.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	if (fb->board->enable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		fb->board->enable(fb);
^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) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) clcdfb_set_bitfields(struct clcd_fb *fb, struct fb_var_screeninfo *var)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	u32 caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	if (fb->panel->caps && fb->board->caps)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 		caps = fb->panel->caps & fb->board->caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 		/* Old way of specifying what can be used */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 		caps = fb->panel->cntl & CNTL_BGR ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 			CLCD_CAP_BGR : CLCD_CAP_RGB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 		/* But mask out 444 modes as they weren't supported */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 		caps &= ~CLCD_CAP_444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	/* Only TFT panels can do RGB888/BGR888 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	if (!(fb->panel->cntl & CNTL_LCDTFT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 		caps &= ~CLCD_CAP_888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	memset(&var->transp, 0, sizeof(var->transp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 	var->red.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	var->green.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	var->blue.msb_right = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	switch (var->bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 	case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		/* If we can't do 5551, reject */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		caps &= CLCD_CAP_5551;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 		if (!caps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 			ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 		var->red.length		= var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		var->red.offset		= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		var->green.length	= var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		var->green.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 		var->blue.length	= var->bits_per_pixel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		var->blue.offset	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 		/* If we can't do 444, 5551 or 565, reject */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 		if (!(caps & (CLCD_CAP_444 | CLCD_CAP_5551 | CLCD_CAP_565))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 			ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		 * Green length can be 4, 5 or 6 depending whether
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 		 * we're operating in 444, 5551 or 565 mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		if (var->green.length == 4 && caps & CLCD_CAP_444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 			caps &= CLCD_CAP_444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		if (var->green.length == 5 && caps & CLCD_CAP_5551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 			caps &= CLCD_CAP_5551;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 		else if (var->green.length == 6 && caps & CLCD_CAP_565)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 			caps &= CLCD_CAP_565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 		else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 			 * PL110 officially only supports RGB555,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 			 * but may be wired up to allow RGB565.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 			if (caps & CLCD_CAP_565) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 				var->green.length = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 				caps &= CLCD_CAP_565;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 			} else if (caps & CLCD_CAP_5551) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 				var->green.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 				caps &= CLCD_CAP_5551;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 			} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 				var->green.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 				caps &= CLCD_CAP_444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 			}
^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) 		if (var->green.length >= 5) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 			var->red.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 			var->blue.length = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 			var->red.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 			var->blue.length = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 	case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 		/* If we can't do 888, reject */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 		caps &= CLCD_CAP_888;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 		if (!caps) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 			ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		var->red.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		var->green.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 		var->blue.length = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	 * >= 16bpp displays have separate colour component bitfields
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	 * encoded in the pixel data.  Calculate their position from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 	 * the bitfield length defined above.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	if (ret == 0 && var->bits_per_pixel >= 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 		bool bgr, rgb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 		bgr = caps & CLCD_CAP_BGR && var->blue.offset == 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		rgb = caps & CLCD_CAP_RGB && var->red.offset == 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 		if (!bgr && !rgb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 			/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 			 * The requested format was not possible, try just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 			 * our capabilities.  One of BGR or RGB must be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 			 * supported.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 			 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 			bgr = caps & CLCD_CAP_BGR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 		if (bgr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 			var->blue.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 			var->green.offset = var->blue.offset + var->blue.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 			var->red.offset = var->green.offset + var->green.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 			var->red.offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 			var->green.offset = var->red.offset + var->red.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 			var->blue.offset = var->green.offset + var->green.length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 		}
^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) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) static int clcdfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 	struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	if (fb->board->check)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		ret = fb->board->check(fb, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 	if (ret == 0 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 	    var->xres_virtual * var->bits_per_pixel / 8 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 	    var->yres_virtual > fb->fb.fix.smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 		ret = clcdfb_set_bitfields(fb, var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) static int clcdfb_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 	struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 	struct clcd_regs regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 	fb->fb.fix.line_length = fb->fb.var.xres_virtual *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 				 fb->fb.var.bits_per_pixel / 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 	if (fb->fb.var.bits_per_pixel <= 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 		fb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 		fb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	fb->board->decode(fb, &regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	clcdfb_disable(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	writel(regs.tim0, fb->regs + CLCD_TIM0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 	writel(regs.tim1, fb->regs + CLCD_TIM1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 	writel(regs.tim2, fb->regs + CLCD_TIM2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	writel(regs.tim3, fb->regs + CLCD_TIM3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 	clcdfb_set_start(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	clk_set_rate(fb->clk, (1000000000 / regs.pixclock) * 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 	fb->clcd_cntl = regs.cntl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	clcdfb_enable(fb, regs.cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) #ifdef DEBUG
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	printk(KERN_INFO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	       "CLCD: Registers set to\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 	       "  %08x %08x %08x %08x\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 	       "  %08x %08x %08x %08x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 		readl(fb->regs + CLCD_TIM0), readl(fb->regs + CLCD_TIM1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 		readl(fb->regs + CLCD_TIM2), readl(fb->regs + CLCD_TIM3),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 		readl(fb->regs + CLCD_UBAS), readl(fb->regs + CLCD_LBAS),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 		readl(fb->regs + fb->off_ienb), readl(fb->regs + fb->off_cntl));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) static inline u32 convert_bitfield(int val, struct fb_bitfield *bf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	unsigned int mask = (1 << bf->length) - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 	return (val >> (16 - bf->length) & mask) << bf->offset;
^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) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)  *  Set a single color register. The values supplied have a 16 bit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)  *  magnitude.  Return != 0 for invalid regno.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) clcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 		 unsigned int blue, unsigned int transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	if (regno < 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		fb->cmap[regno] = convert_bitfield(transp, &fb->fb.var.transp) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 				  convert_bitfield(blue, &fb->fb.var.blue) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 				  convert_bitfield(green, &fb->fb.var.green) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 				  convert_bitfield(red, &fb->fb.var.red);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	if (fb->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR && regno < 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 		int hw_reg = CLCD_PALETTE + ((regno * 2) & ~3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 		u32 val, mask, newval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 		newval  = (red >> 11)  & 0x001f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 		newval |= (green >> 6) & 0x03e0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		newval |= (blue >> 1)  & 0x7c00;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		 * 3.2.11: if we're configured for big endian
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 		 * byte order, the palette entries are swapped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 		if (fb->clcd_cntl & CNTL_BEBO)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 			regno ^= 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 		if (regno & 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) 			newval <<= 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) 			mask = 0x0000ffff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 		} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 			mask = 0xffff0000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 		val = readl(fb->regs + hw_reg) & mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 		writel(val | newval, fb->regs + hw_reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 	return regno > 255;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)  *  Blank the screen if blank_mode != 0, else unblank. If blank == NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)  *  then the caller blanks by setting the CLUT (Color Look Up Table) to all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)  *  black. Return 0 if blanking succeeded, != 0 if un-/blanking failed due
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392)  *  to e.g. a video mode which doesn't support it. Implements VESA suspend
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)  *  and powerdown modes on hardware that supports disabling hsync/vsync:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394)  *    blank_mode == 2: suspend vsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395)  *    blank_mode == 3: suspend hsync
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)  *    blank_mode == 4: powerdown
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) static int clcdfb_blank(int blank_mode, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 	if (blank_mode != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 		clcdfb_disable(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 		clcdfb_enable(fb, fb->clcd_cntl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) static int clcdfb_mmap(struct fb_info *info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 		       struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 	struct clcd_fb *fb = to_clcd(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	unsigned long len, off = vma->vm_pgoff << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 	int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 	len = info->fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 	if (off <= len && vma->vm_end - vma->vm_start <= len - off &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 	    fb->board->mmap)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 		ret = fb->board->mmap(fb, vma);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) static const struct fb_ops clcdfb_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 	.owner		= THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 	.fb_check_var	= clcdfb_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) 	.fb_set_par	= clcdfb_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) 	.fb_setcolreg	= clcdfb_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) 	.fb_blank	= clcdfb_blank,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 	.fb_fillrect	= cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 	.fb_copyarea	= cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 	.fb_imageblit	= cfb_imageblit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 	.fb_mmap	= clcdfb_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) static int clcdfb_register(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 	 * ARM PL111 always has IENB at 0x1c; it's only PL110
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 	 * which is reversed on some platforms.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 	if (amba_manf(fb->dev) == 0x41 && amba_part(fb->dev) == 0x111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 		fb->off_ienb = CLCD_PL111_IENB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 		fb->off_cntl = CLCD_PL111_CNTL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 		fb->off_ienb = CLCD_PL110_IENB;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 		fb->off_cntl = CLCD_PL110_CNTL;
^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) 	fb->clk = clk_get(&fb->dev->dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 	if (IS_ERR(fb->clk)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 		ret = PTR_ERR(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 		goto out;
^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) 	ret = clk_prepare(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 		goto free_clk;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 	fb->fb.device		= &fb->dev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	fb->fb.fix.mmio_start	= fb->dev->res.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 	fb->fb.fix.mmio_len	= resource_size(&fb->dev->res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	fb->regs = ioremap(fb->fb.fix.mmio_start, fb->fb.fix.mmio_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	if (!fb->regs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 		printk(KERN_ERR "CLCD: unable to remap registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 		ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 		goto clk_unprep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 	fb->fb.fbops		= &clcdfb_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 	fb->fb.flags		= FBINFO_FLAG_DEFAULT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 	fb->fb.pseudo_palette	= fb->cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	strncpy(fb->fb.fix.id, clcd_name, sizeof(fb->fb.fix.id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 	fb->fb.fix.type		= FB_TYPE_PACKED_PIXELS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 	fb->fb.fix.type_aux	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 	fb->fb.fix.xpanstep	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 	fb->fb.fix.ypanstep	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	fb->fb.fix.ywrapstep	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	fb->fb.fix.accel	= FB_ACCEL_NONE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 	fb->fb.var.xres		= fb->panel->mode.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	fb->fb.var.yres		= fb->panel->mode.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 	fb->fb.var.xres_virtual	= fb->panel->mode.xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) 	fb->fb.var.yres_virtual	= fb->panel->mode.yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 	fb->fb.var.bits_per_pixel = fb->panel->bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 	fb->fb.var.grayscale	= fb->panel->grayscale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	fb->fb.var.pixclock	= fb->panel->mode.pixclock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 	fb->fb.var.left_margin	= fb->panel->mode.left_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) 	fb->fb.var.right_margin	= fb->panel->mode.right_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	fb->fb.var.upper_margin	= fb->panel->mode.upper_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) 	fb->fb.var.lower_margin	= fb->panel->mode.lower_margin;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	fb->fb.var.hsync_len	= fb->panel->mode.hsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 	fb->fb.var.vsync_len	= fb->panel->mode.vsync_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) 	fb->fb.var.sync		= fb->panel->mode.sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	fb->fb.var.vmode	= fb->panel->mode.vmode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 	fb->fb.var.activate	= FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	fb->fb.var.nonstd	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) 	fb->fb.var.height	= fb->panel->height;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 	fb->fb.var.width	= fb->panel->width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) 	fb->fb.var.accel_flags	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 	fb->fb.monspecs.hfmin	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 	fb->fb.monspecs.hfmax   = 100000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 	fb->fb.monspecs.vfmin	= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 	fb->fb.monspecs.vfmax	= 400;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 	fb->fb.monspecs.dclkmin = 1000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 	fb->fb.monspecs.dclkmax	= 100000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 	 * Make sure that the bitfields are set appropriately.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 	clcdfb_set_bitfields(fb, &fb->fb.var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 	 * Allocate colourmap.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 	ret = fb_alloc_cmap(&fb->fb.cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 		goto unmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) 	 * Ensure interrupts are disabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) 	writel(0, fb->regs + fb->off_ienb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 	fb_set_var(&fb->fb, &fb->fb.var);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 	dev_info(&fb->dev->dev, "%s hardware, %s display\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 	         fb->board->name, fb->panel->mode.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) 	ret = register_framebuffer(&fb->fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) 	if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) 	printk(KERN_ERR "CLCD: cannot register framebuffer (%d)\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 	fb_dealloc_cmap(&fb->fb.cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545)  unmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	iounmap(fb->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)  clk_unprep:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	clk_unprepare(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)  free_clk:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 	clk_put(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)  out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) #ifdef CONFIG_OF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) static int clcdfb_of_get_dpi_panel_mode(struct device_node *node,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) 		struct clcd_panel *clcd_panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) 	struct display_timing timing;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) 	struct videomode video;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) 	err = of_get_display_timing(node, "panel-timing", &timing);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) 	if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) 		pr_err("%pOF: problems parsing panel-timing (%d)\n", node, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) 	videomode_from_timing(&timing, &video);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) 	err = fb_videomode_from_videomode(&video, &clcd_panel->mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) 	/* Set up some inversion flags */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) 	if (timing.flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) 		clcd_panel->tim2 |= TIM2_IPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) 	else if (!(timing.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) 		 * To preserve backwards compatibility, the IPC (inverted
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) 		 * pixel clock) flag needs to be set on any display that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) 		 * doesn't explicitly specify that the pixel clock is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) 		 * active on the negative or positive edge.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) 		clcd_panel->tim2 |= TIM2_IPC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) 	if (timing.flags & DISPLAY_FLAGS_HSYNC_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) 		clcd_panel->tim2 |= TIM2_IHS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) 	if (timing.flags & DISPLAY_FLAGS_VSYNC_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) 		clcd_panel->tim2 |= TIM2_IVS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) 	if (timing.flags & DISPLAY_FLAGS_DE_LOW)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) 		clcd_panel->tim2 |= TIM2_IOE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) 	return 0;
^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) static int clcdfb_snprintf_mode(char *buf, int size, struct fb_videomode *mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) 	return snprintf(buf, size, "%ux%u@%u", mode->xres, mode->yres,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) 			mode->refresh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) static int clcdfb_of_get_backlight(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) 				   struct clcd_panel *clcd_panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) 	struct backlight_device *backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) 	/* Look up the optional backlight device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) 	backlight = devm_of_find_backlight(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) 	if (IS_ERR(backlight))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) 		return PTR_ERR(backlight);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) 	clcd_panel->backlight = backlight;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) static int clcdfb_of_get_mode(struct device *dev, struct device_node *panel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) 			      struct clcd_panel *clcd_panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) 	struct fb_videomode *mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) 	char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) 	int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) 	/* Only directly connected DPI panels supported for now */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) 	if (of_device_is_compatible(panel, "panel-dpi"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) 		err = clcdfb_of_get_dpi_panel_mode(panel, clcd_panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) 		err = -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) 	mode = &clcd_panel->mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) 	len = clcdfb_snprintf_mode(NULL, 0, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) 	name = devm_kzalloc(dev, len + 1, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) 	if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) 	clcdfb_snprintf_mode(name, len + 1, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) 	mode->name = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) static int clcdfb_of_init_tft_panel(struct clcd_fb *fb, u32 r0, u32 g0, u32 b0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) 	static struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) 		unsigned int part;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) 		u32 r0, g0, b0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) 		u32 caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) 	} panels[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) 		{ 0x110, 1,  7, 13, CLCD_CAP_5551 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) 		{ 0x110, 0,  8, 16, CLCD_CAP_888 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) 		{ 0x110, 16, 8, 0,  CLCD_CAP_888 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) 		{ 0x111, 4, 14, 20, CLCD_CAP_444 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) 		{ 0x111, 3, 11, 19, CLCD_CAP_444 | CLCD_CAP_5551 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) 		{ 0x111, 3, 10, 19, CLCD_CAP_444 | CLCD_CAP_5551 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) 				    CLCD_CAP_565 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) 		{ 0x111, 0,  8, 16, CLCD_CAP_444 | CLCD_CAP_5551 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) 				    CLCD_CAP_565 | CLCD_CAP_888 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) 	};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) 	/* Bypass pixel clock divider */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) 	fb->panel->tim2 |= TIM2_BCD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) 	/* TFT display, vert. comp. interrupt at the start of the back porch */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) 	fb->panel->cntl |= CNTL_LCDTFT | CNTL_LCDVCOMP(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) 	fb->panel->caps = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) 	/* Match the setup with known variants */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) 	for (i = 0; i < ARRAY_SIZE(panels) && !fb->panel->caps; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) 		if (amba_part(fb->dev) != panels[i].part)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) 		if (g0 != panels[i].g0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) 		if (r0 == panels[i].r0 && b0 == panels[i].b0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) 			fb->panel->caps = panels[i].caps;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) 	 * If we actually physically connected the R lines to B and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) 	 * vice versa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) 	if (r0 != 0 && b0 == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) 		fb->panel->bgr_connection = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) 	return fb->panel->caps ? 0 : -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) static int clcdfb_of_init_display(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) 	struct device_node *endpoint, *panel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) 	unsigned int bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) 	u32 max_bandwidth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) 	u32 tft_r0b0g0[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) 	fb->panel = devm_kzalloc(&fb->dev->dev, sizeof(*fb->panel), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) 	if (!fb->panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 	 * Fetch the panel endpoint.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) 	endpoint = of_graph_get_next_endpoint(fb->dev->dev.of_node, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) 	if (!endpoint)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) 	panel = of_graph_get_remote_port_parent(endpoint);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) 	if (!panel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) 	err = clcdfb_of_get_backlight(&fb->dev->dev, fb->panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) 	err = clcdfb_of_get_mode(&fb->dev->dev, panel, fb->panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) 	err = of_property_read_u32(fb->dev->dev.of_node, "max-memory-bandwidth",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) 			&max_bandwidth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) 	if (!err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) 		/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) 		 * max_bandwidth is in bytes per second and pixclock in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) 		 * pico-seconds, so the maximum allowed bits per pixel is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) 		 *   8 * max_bandwidth / (PICOS2KHZ(pixclock) * 1000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) 		 * Rearrange this calculation to avoid overflow and then ensure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) 		 * result is a valid format.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) 		bpp = max_bandwidth / (1000 / 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) 			/ PICOS2KHZ(fb->panel->mode.pixclock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) 		bpp = rounddown_pow_of_two(bpp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) 		if (bpp > 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) 			bpp = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) 	} else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) 		bpp = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) 	fb->panel->bpp = bpp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) #ifdef CONFIG_CPU_BIG_ENDIAN
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) 	fb->panel->cntl |= CNTL_BEBO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) 	fb->panel->width = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) 	fb->panel->height = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) 	if (of_property_read_u32_array(endpoint,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) 			"arm,pl11x,tft-r0g0b0-pads",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) 			tft_r0b0g0, ARRAY_SIZE(tft_r0b0g0)) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) 		return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) 	return clcdfb_of_init_tft_panel(fb, tft_r0b0g0[0],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) 					tft_r0b0g0[1],  tft_r0b0g0[2]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) static int clcdfb_of_vram_setup(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) 	struct device_node *memory;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) 	u64 size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) 	err = clcdfb_of_init_display(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) 	memory = of_parse_phandle(fb->dev->dev.of_node, "memory-region", 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) 	if (!memory)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) 	fb->fb.screen_base = of_iomap(memory, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) 	if (!fb->fb.screen_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) 	fb->fb.fix.smem_start = of_translate_address(memory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) 			of_get_address(memory, 0, &size, NULL));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) 	fb->fb.fix.smem_len = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) static int clcdfb_of_vram_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) 	unsigned long off, user_size, kernel_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) 	off = vma->vm_pgoff << PAGE_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) 	user_size = vma->vm_end - vma->vm_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) 	kernel_size = fb->fb.fix.smem_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) 	if (off >= kernel_size || user_size > (kernel_size - off))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) 		return -ENXIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) 	return remap_pfn_range(vma, vma->vm_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) 			__phys_to_pfn(fb->fb.fix.smem_start) + vma->vm_pgoff,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) 			user_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) 			pgprot_writecombine(vma->vm_page_prot));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) static void clcdfb_of_vram_remove(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) 	iounmap(fb->fb.screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) static int clcdfb_of_dma_setup(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) 	unsigned long framesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) 	dma_addr_t dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) 	int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) 	err = clcdfb_of_init_display(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) 	if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) 		return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) 	framesize = PAGE_ALIGN(fb->panel->mode.xres * fb->panel->mode.yres *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) 			fb->panel->bpp / 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) 	fb->fb.screen_base = dma_alloc_coherent(&fb->dev->dev, framesize,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) 			&dma, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) 	if (!fb->fb.screen_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) 	fb->fb.fix.smem_start = dma;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) 	fb->fb.fix.smem_len = framesize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) static int clcdfb_of_dma_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) 	return dma_mmap_wc(&fb->dev->dev, vma, fb->fb.screen_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) 			   fb->fb.fix.smem_start, fb->fb.fix.smem_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) static void clcdfb_of_dma_remove(struct clcd_fb *fb)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) 	dma_free_coherent(&fb->dev->dev, fb->fb.fix.smem_len,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) 			fb->fb.screen_base, fb->fb.fix.smem_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) 	struct clcd_board *board = devm_kzalloc(&dev->dev, sizeof(*board),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) 			GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) 	struct device_node *node = dev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) 	if (!board)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) 	board->name = of_node_full_name(node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) 	board->caps = CLCD_CAP_ALL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) 	board->check = clcdfb_check;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) 	board->decode = clcdfb_decode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) 	if (of_find_property(node, "memory-region", NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) 		board->setup = clcdfb_of_vram_setup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) 		board->mmap = clcdfb_of_vram_mmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) 		board->remove = clcdfb_of_vram_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) 		board->setup = clcdfb_of_dma_setup;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) 		board->mmap = clcdfb_of_dma_mmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) 		board->remove = clcdfb_of_dma_remove;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) 	return board;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) static struct clcd_board *clcdfb_of_get_board(struct amba_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) 	return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) 	struct clcd_board *board = dev_get_platdata(&dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) 	struct clcd_fb *fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) 	if (!board)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) 		board = clcdfb_of_get_board(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) 	if (!board)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) 	ret = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) 	ret = amba_request_regions(dev, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) 		printk(KERN_ERR "CLCD: unable to reserve regs region\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) 	fb = kzalloc(sizeof(*fb), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) 	if (!fb) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) 		ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) 		goto free_region;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) 	fb->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) 	fb->board = board;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) 	dev_info(&fb->dev->dev, "PL%03x designer %02x rev%u at 0x%08llx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) 		amba_part(dev), amba_manf(dev), amba_rev(dev),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) 		(unsigned long long)dev->res.start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) 	ret = fb->board->setup(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) 		goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) 	ret = clcdfb_register(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) 	if (ret == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) 		amba_set_drvdata(dev, fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) 		goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) 	fb->board->remove(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920)  free_fb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) 	kfree(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922)  free_region:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) 	amba_release_regions(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924)  out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) static void clcdfb_remove(struct amba_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) 	struct clcd_fb *fb = amba_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) 	clcdfb_disable(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) 	unregister_framebuffer(&fb->fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) 	if (fb->fb.cmap.len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) 		fb_dealloc_cmap(&fb->fb.cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) 	iounmap(fb->regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) 	clk_unprepare(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) 	clk_put(fb->clk);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) 	fb->board->remove(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) 	kfree(fb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) 	amba_release_regions(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) static const struct amba_id clcdfb_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) 		.id	= 0x00041110,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) 		.mask	= 0x000ffffe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) 	{ 0, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) MODULE_DEVICE_TABLE(amba, clcdfb_id_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) static struct amba_driver clcd_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) 	.drv 		= {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) 		.name	= "clcd-pl11x",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) 	.probe		= clcdfb_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) 	.remove		= clcdfb_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) 	.id_table	= clcdfb_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) static int __init amba_clcdfb_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) 	if (fb_get_options("ambafb", NULL))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) 	return amba_driver_register(&clcd_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) module_init(amba_clcdfb_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) static void __exit amba_clcdfb_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) 	amba_driver_unregister(&clcd_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) module_exit(amba_clcdfb_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) MODULE_DESCRIPTION("ARM PrimeCell PL110 CLCD core driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) MODULE_LICENSE("GPL");