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-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Driver for Aeroflex Gaisler SVGACTRL framebuffer device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * 2011 (c) Aeroflex Gaisler AB
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Full documentation of the core can be found here:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * https://www.gaisler.com/products/grlib/grip.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * Contributors: Kristoffer Glembo <kristoffer@gaisler.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/dma-mapping.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/of_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/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/tty.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/fb.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) struct grvga_regs {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	u32 status; 		/* 0x00 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 	u32 video_length; 	/* 0x04 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 	u32 front_porch;	/* 0x08 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	u32 sync_length;	/* 0x0C */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	u32 line_length;	/* 0x10 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 	u32 fb_pos;		/* 0x14 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 	u32 clk_vector[4];	/* 0x18 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	u32 clut;	        /* 0x20 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) struct grvga_par {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	struct grvga_regs *regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	u32 color_palette[16];  /* 16 entry pseudo palette used by fbcon in true color mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 	int clk_sel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 	int fb_alloced;         /* = 1 if framebuffer is allocated in main memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) static const struct fb_videomode grvga_modedb[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49)     {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	/* 640x480 @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 	NULL, 60, 640, 480, 40000, 48, 16, 39, 11, 96, 2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	0, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53)     }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	/* 800x600 @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	0, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57)     }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	/* 800x600 @ 72 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 	NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	0, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61)     }, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	/* 1024x768 @ 60 Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	NULL, 60, 1024, 768, 15385, 160, 24, 29, 3, 136, 6,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	0, FB_VMODE_NONINTERLACED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65)     }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66)  };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) static const struct fb_fix_screeninfo grvga_fix = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	.id =		"AG SVGACTRL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	.type =		FB_TYPE_PACKED_PIXELS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	.visual =       FB_VISUAL_PSEUDOCOLOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	.xpanstep =	0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	.ypanstep =	1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	.ywrapstep =	0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	.accel =	FB_ACCEL_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) static int grvga_check_var(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 			   struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	struct grvga_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	if (!var->xres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 		var->xres = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	if (!var->yres)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 		var->yres = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	if (var->bits_per_pixel <= 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 		var->bits_per_pixel = 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	else if (var->bits_per_pixel <= 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 		var->bits_per_pixel = 16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	else if (var->bits_per_pixel <= 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 		var->bits_per_pixel = 24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	else if (var->bits_per_pixel <= 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		var->bits_per_pixel = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	var->xres_virtual = var->xres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	var->yres_virtual = 2*var->yres;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	if (info->fix.smem_len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		if ((var->yres_virtual*var->xres_virtual*var->bits_per_pixel/8) > info->fix.smem_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 			return -ENOMEM;
^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) 	/* Which clocks that are available can be read out in these registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	for (i = 0; i <= 3 ; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 		if (var->pixclock == par->regs->clk_vector[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	if (i <= 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		par->clk_sel = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 		var->red   = (struct fb_bitfield) {0, 8, 0};      /* offset, length, msb-right */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 		var->green = (struct fb_bitfield) {0, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		var->blue  = (struct fb_bitfield) {0, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 		var->transp = (struct fb_bitfield) {0, 0, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 		var->red   = (struct fb_bitfield) {11, 5, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 		var->green = (struct fb_bitfield) {5, 6, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		var->blue  = (struct fb_bitfield) {0, 5, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		var->transp = (struct fb_bitfield) {0, 0, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 		var->red   = (struct fb_bitfield) {16, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		var->green = (struct fb_bitfield) {8, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 		var->blue  = (struct fb_bitfield) {0, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		var->transp = (struct fb_bitfield) {24, 8, 0};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 		return -EINVAL;
^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) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static int grvga_set_par(struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	u32 func = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	struct grvga_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	__raw_writel(((info->var.yres - 1) << 16) | (info->var.xres - 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 		     &par->regs->video_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	__raw_writel((info->var.lower_margin << 16) | (info->var.right_margin),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		     &par->regs->front_porch);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	__raw_writel((info->var.vsync_len << 16) | (info->var.hsync_len),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		     &par->regs->sync_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	__raw_writel(((info->var.yres + info->var.lower_margin + info->var.upper_margin + info->var.vsync_len - 1) << 16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 		     (info->var.xres + info->var.right_margin + info->var.left_margin + info->var.hsync_len - 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		     &par->regs->line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	switch (info->var.bits_per_pixel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		func = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	case 16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 		info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 		func = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	case 24:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	case 32:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 		info->fix.visual = FB_VISUAL_TRUECOLOR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 		func = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	__raw_writel((par->clk_sel << 6) | (func << 4) | 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 		     &par->regs->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	info->fix.line_length = (info->var.xres_virtual*info->var.bits_per_pixel)/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	return 0;
^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) static int grvga_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	struct grvga_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	if (regno >= 256)	/* Size of CLUT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	if (info->var.grayscale) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	red    = CNVT_TOHW(red,   info->var.red.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	green  = CNVT_TOHW(green, info->var.green.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	blue   = CNVT_TOHW(blue,  info->var.blue.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	transp = CNVT_TOHW(transp, info->var.transp.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) #undef CNVT_TOHW
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	/* In PSEUDOCOLOR we use the hardware CLUT */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 		__raw_writel((regno << 24) | (red << 16) | (green << 8) | blue,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 			     &par->regs->clut);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 	/* Truecolor uses the pseudo palette */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 	else if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 		u32 v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 		if (regno >= 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) 			return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 		v =     (red    << info->var.red.offset)   |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 			(green  << info->var.green.offset) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 			(blue   << info->var.blue.offset)  |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 			(transp << info->var.transp.offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 		((u32 *) (info->pseudo_palette))[regno] = v;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) static int grvga_pan_display(struct fb_var_screeninfo *var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 			     struct fb_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	struct grvga_par *par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	struct fb_fix_screeninfo *fix = &info->fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 	u32 base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 	if (var->xoffset != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	base_addr = fix->smem_start + (var->yoffset * fix->line_length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 	base_addr &= ~3UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	/* Set framebuffer base address  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	__raw_writel(base_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		     &par->regs->fb_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) static const struct fb_ops grvga_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	.owner          = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	.fb_check_var   = grvga_check_var,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	.fb_set_par	= grvga_set_par,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	.fb_setcolreg   = grvga_setcolreg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 	.fb_pan_display = grvga_pan_display,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	.fb_fillrect	= cfb_fillrect,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	.fb_copyarea	= cfb_copyarea,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 	.fb_imageblit	= cfb_imageblit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static int grvga_parse_custom(char *options,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 			      struct fb_var_screeninfo *screendata)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	char *this_opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 	while ((this_opt = strsep(&options, " ")) != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 		if (!*this_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 			continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 		switch (count) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 		case 0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 			screendata->pixclock = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		case 1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 			screendata->xres = screendata->xres_virtual = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 		case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 			screendata->right_margin = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 		case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 			screendata->hsync_len = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 		case 4:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 			screendata->left_margin = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 		case 5:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 			screendata->yres = screendata->yres_virtual = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 		case 6:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 			screendata->lower_margin = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 		case 7:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 			screendata->vsync_len = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		case 8:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 			screendata->upper_margin = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 		case 9:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 			screendata->bits_per_pixel = simple_strtoul(this_opt, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 			count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 		default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 			return -1;
^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) 	screendata->activate  = FB_ACTIVATE_NOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 	screendata->vmode     = FB_VMODE_NONINTERLACED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) static int grvga_probe(struct platform_device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	struct fb_info *info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	int retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	unsigned long virtual_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	unsigned long grvga_fix_addr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	unsigned long physical_start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	unsigned long grvga_mem_size = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 	struct grvga_par *par = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	char *options = NULL, *mode_opt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	info = framebuffer_alloc(sizeof(struct grvga_par), &dev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	if (!info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	/* Expecting: "grvga: modestring, [addr:<framebuffer physical address>], [size:<framebuffer size>]
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	 * If modestring is custom:<custom mode string> we parse the string which then contains all videoparameters
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	 * If address is left out, we allocate memory,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	 * if size is left out we only allocate enough to support the given mode.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	if (fb_get_options("grvga", &options)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 		retval = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 		goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	if (!options || !*options)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		options =  "640x480-8@60";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 		char *this_opt = strsep(&options, ",");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 		if (!this_opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 		if (!strncmp(this_opt, "custom", 6)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 			if (grvga_parse_custom(this_opt, &info->var) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 				dev_err(&dev->dev, "Failed to parse custom mode (%s).\n", this_opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 				retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 				goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 			}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 		} else if (!strncmp(this_opt, "addr", 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 			grvga_fix_addr = simple_strtoul(this_opt + 5, NULL, 16);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 		else if (!strncmp(this_opt, "size", 4))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 			grvga_mem_size = simple_strtoul(this_opt + 5, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) 			mode_opt = this_opt;
^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) 	par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	info->fbops = &grvga_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) 	info->fix = grvga_fix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) 	info->pseudo_palette = par->color_palette;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) 	info->flags = FBINFO_DEFAULT | FBINFO_PARTIAL_PAN_OK | FBINFO_HWACCEL_YPAN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) 	info->fix.smem_len = grvga_mem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 	if (!devm_request_mem_region(&dev->dev, dev->resource[0].start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) 		    resource_size(&dev->resource[0]), "grlib-svgactrl regs")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) 		dev_err(&dev->dev, "registers already mapped\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) 		retval = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) 		goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) 	par->regs = of_ioremap(&dev->resource[0], 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) 			       resource_size(&dev->resource[0]),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 			       "grlib-svgactrl regs");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) 	if (!par->regs) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) 		dev_err(&dev->dev, "failed to map registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) 		retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) 		goto free_fb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) 	retval = fb_alloc_cmap(&info->cmap, 256, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) 	if (retval < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) 		dev_err(&dev->dev, "failed to allocate mem with fb_alloc_cmap\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) 		retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) 		goto unmap_regs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) 	if (mode_opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) 		retval = fb_find_mode(&info->var, info, mode_opt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) 				      grvga_modedb, sizeof(grvga_modedb), &grvga_modedb[0], 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) 		if (!retval || retval == 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) 			retval = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) 			goto dealloc_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) 	if (!grvga_mem_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) 		grvga_mem_size = info->var.xres_virtual * info->var.yres_virtual * info->var.bits_per_pixel/8;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) 	if (grvga_fix_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) 		/* Got framebuffer base address from argument list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) 		physical_start = grvga_fix_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) 		if (!devm_request_mem_region(&dev->dev, physical_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) 					     grvga_mem_size, dev->name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) 			dev_err(&dev->dev, "failed to request memory region\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) 			retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) 			goto dealloc_cmap;
^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) 		virtual_start = (unsigned long) ioremap(physical_start, grvga_mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) 		if (!virtual_start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) 			dev_err(&dev->dev, "error mapping framebuffer memory\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) 			retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) 			goto dealloc_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) 	} else {	/* Allocate frambuffer memory */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) 		unsigned long page;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) 		virtual_start = (unsigned long) __get_free_pages(GFP_DMA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) 								 get_order(grvga_mem_size));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) 		if (!virtual_start) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) 			dev_err(&dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) 				"unable to allocate framebuffer memory (%lu bytes)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) 				grvga_mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) 			retval = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) 			goto dealloc_cmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) 		physical_start = dma_map_single(&dev->dev, (void *)virtual_start, grvga_mem_size, DMA_TO_DEVICE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) 		/* Set page reserved so that mmap will work. This is necessary
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) 		 * since we'll be remapping normal memory.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) 		 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) 		for (page = virtual_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) 		     page < PAGE_ALIGN(virtual_start + grvga_mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) 		     page += PAGE_SIZE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) 			SetPageReserved(virt_to_page(page));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) 		par->fb_alloced = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) 	memset((unsigned long *) virtual_start, 0, grvga_mem_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) 	info->screen_base = (char __iomem *) virtual_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) 	info->fix.smem_start = physical_start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) 	info->fix.smem_len   = grvga_mem_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) 	dev_set_drvdata(&dev->dev, info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) 	dev_info(&dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) 		 "Aeroflex Gaisler framebuffer device (fb%d), %dx%d-%d, using %luK of video memory @ %p\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) 		 info->node, info->var.xres, info->var.yres, info->var.bits_per_pixel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) 		 grvga_mem_size >> 10, info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) 	retval = register_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) 	if (retval < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) 		dev_err(&dev->dev, "failed to register framebuffer\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) 		goto free_mem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) 	__raw_writel(physical_start, &par->regs->fb_pos);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) 	__raw_writel(__raw_readl(&par->regs->status) | 1,  /* Enable framebuffer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) 		     &par->regs->status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) free_mem:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) 	if (grvga_fix_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) 		iounmap((void *)virtual_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) 		kfree((void *)virtual_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) dealloc_cmap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) 	fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) unmap_regs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) 	of_iounmap(&dev->resource[0], par->regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) 		   resource_size(&dev->resource[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) free_fb:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) 	framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) 	return retval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) static int grvga_remove(struct platform_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) 	struct fb_info *info = dev_get_drvdata(&device->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) 	struct grvga_par *par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) 	if (info) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) 		par = info->par;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) 		unregister_framebuffer(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) 		fb_dealloc_cmap(&info->cmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) 		of_iounmap(&device->resource[0], par->regs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) 			   resource_size(&device->resource[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) 		if (!par->fb_alloced)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) 			iounmap(info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) 			kfree((void *)info->screen_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) 		framebuffer_release(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static struct of_device_id svgactrl_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) 		.name = "GAISLER_SVGACTRL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) 	{
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) 		.name = "01_063",
^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) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) MODULE_DEVICE_TABLE(of, svgactrl_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) static struct platform_driver grvga_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) 		.name = "grlib-svgactrl",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) 		.of_match_table = svgactrl_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) 	.probe		= grvga_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) 	.remove		= grvga_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) module_platform_driver(grvga_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) MODULE_AUTHOR("Aeroflex Gaisler");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) MODULE_DESCRIPTION("Aeroflex Gaisler framebuffer device driver");