cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

grvga.c (14055B)


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