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

gx1fb_core.c (12214B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * drivers/video/geode/gx1fb_core.c
      4 *   -- Geode GX1 framebuffer driver
      5 *
      6 * Copyright (C) 2005 Arcom Control Systems Ltd.
      7 */
      8
      9#include <linux/module.h>
     10#include <linux/kernel.h>
     11#include <linux/errno.h>
     12#include <linux/string.h>
     13#include <linux/mm.h>
     14#include <linux/delay.h>
     15#include <linux/fb.h>
     16#include <linux/init.h>
     17#include <linux/pci.h>
     18
     19#include "geodefb.h"
     20#include "display_gx1.h"
     21#include "video_cs5530.h"
     22
     23static char mode_option[32] = "640x480-16@60";
     24static int  crt_option = 1;
     25static char panel_option[32] = "";
     26
     27/* Modes relevant to the GX1 (taken from modedb.c) */
     28static const struct fb_videomode gx1_modedb[] = {
     29	/* 640x480-60 VESA */
     30	{ NULL, 60, 640, 480, 39682,  48, 16, 33, 10, 96, 2,
     31	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     32	/* 640x480-75 VESA */
     33	{ NULL, 75, 640, 480, 31746, 120, 16, 16, 01, 64, 3,
     34	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     35	/* 640x480-85 VESA */
     36	{ NULL, 85, 640, 480, 27777, 80, 56, 25, 01, 56, 3,
     37	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     38	/* 800x600-60 VESA */
     39	{ NULL, 60, 800, 600, 25000, 88, 40, 23, 01, 128, 4,
     40	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     41	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     42	/* 800x600-75 VESA */
     43	{ NULL, 75, 800, 600, 20202, 160, 16, 21, 01, 80, 3,
     44	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     45	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     46	/* 800x600-85 VESA */
     47	{ NULL, 85, 800, 600, 17761, 152, 32, 27, 01, 64, 3,
     48	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     49	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     50	/* 1024x768-60 VESA */
     51	{ NULL, 60, 1024, 768, 15384, 160, 24, 29, 3, 136, 6,
     52	  0, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     53	/* 1024x768-75 VESA */
     54	{ NULL, 75, 1024, 768, 12690, 176, 16, 28, 1, 96, 3,
     55	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     56	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     57	/* 1024x768-85 VESA */
     58	{ NULL, 85, 1024, 768, 10582, 208, 48, 36, 1, 96, 3,
     59	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     60	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     61	/* 1280x960-60 VESA */
     62	{ NULL, 60, 1280, 960, 9259, 312, 96, 36, 1, 112, 3,
     63	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     64	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     65	/* 1280x960-85 VESA */
     66	{ NULL, 85, 1280, 960, 6734, 224, 64, 47, 1, 160, 3,
     67	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     68	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     69	/* 1280x1024-60 VESA */
     70	{ NULL, 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3,
     71	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     72	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     73	/* 1280x1024-75 VESA */
     74	{ NULL, 75, 1280, 1024, 7407, 248, 16, 38, 1, 144, 3,
     75	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     76	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     77	/* 1280x1024-85 VESA */
     78	{ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3,
     79	  FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
     80	  FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
     81};
     82
     83static int gx1_line_delta(int xres, int bpp)
     84{
     85	int line_delta = xres * (bpp >> 3);
     86
     87	if (line_delta > 2048)
     88		line_delta = 4096;
     89	else if (line_delta > 1024)
     90		line_delta = 2048;
     91	else
     92		line_delta = 1024;
     93	return line_delta;
     94}
     95
     96static int gx1fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
     97{
     98	struct geodefb_par *par = info->par;
     99
    100	/* Maximum resolution is 1280x1024. */
    101	if (var->xres > 1280 || var->yres > 1024)
    102		return -EINVAL;
    103
    104	if (par->panel_x && (var->xres > par->panel_x || var->yres > par->panel_y))
    105		return -EINVAL;
    106
    107	/* Only 16 bpp and 8 bpp is supported by the hardware. */
    108	if (var->bits_per_pixel == 16) {
    109		var->red.offset   = 11; var->red.length   = 5;
    110		var->green.offset =  5; var->green.length = 6;
    111		var->blue.offset  =  0; var->blue.length  = 5;
    112		var->transp.offset = 0; var->transp.length = 0;
    113	} else if (var->bits_per_pixel == 8) {
    114		var->red.offset   = 0; var->red.length   = 8;
    115		var->green.offset = 0; var->green.length = 8;
    116		var->blue.offset  = 0; var->blue.length  = 8;
    117		var->transp.offset = 0; var->transp.length = 0;
    118	} else
    119		return -EINVAL;
    120
    121	/* Enough video memory? */
    122	if (gx1_line_delta(var->xres, var->bits_per_pixel) * var->yres > info->fix.smem_len)
    123		return -EINVAL;
    124
    125	/* FIXME: Check timing parameters here? */
    126
    127	return 0;
    128}
    129
    130static int gx1fb_set_par(struct fb_info *info)
    131{
    132	struct geodefb_par *par = info->par;
    133
    134	if (info->var.bits_per_pixel == 16)
    135		info->fix.visual = FB_VISUAL_TRUECOLOR;
    136	else
    137		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
    138
    139	info->fix.line_length = gx1_line_delta(info->var.xres, info->var.bits_per_pixel);
    140
    141	par->dc_ops->set_mode(info);
    142
    143	return 0;
    144}
    145
    146static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
    147{
    148	chan &= 0xffff;
    149	chan >>= 16 - bf->length;
    150	return chan << bf->offset;
    151}
    152
    153static int gx1fb_setcolreg(unsigned regno, unsigned red, unsigned green,
    154			   unsigned blue, unsigned transp,
    155			   struct fb_info *info)
    156{
    157	struct geodefb_par *par = info->par;
    158
    159	if (info->var.grayscale) {
    160		/* grayscale = 0.30*R + 0.59*G + 0.11*B */
    161		red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
    162	}
    163
    164	/* Truecolor has hardware independent palette */
    165	if (info->fix.visual == FB_VISUAL_TRUECOLOR) {
    166		u32 *pal = info->pseudo_palette;
    167		u32 v;
    168
    169		if (regno >= 16)
    170			return -EINVAL;
    171
    172		v  = chan_to_field(red, &info->var.red);
    173		v |= chan_to_field(green, &info->var.green);
    174		v |= chan_to_field(blue, &info->var.blue);
    175
    176		pal[regno] = v;
    177	} else {
    178		if (regno >= 256)
    179			return -EINVAL;
    180
    181		par->dc_ops->set_palette_reg(info, regno, red, green, blue);
    182	}
    183
    184	return 0;
    185}
    186
    187static int gx1fb_blank(int blank_mode, struct fb_info *info)
    188{
    189	struct geodefb_par *par = info->par;
    190
    191	return par->vid_ops->blank_display(info, blank_mode);
    192}
    193
    194static int gx1fb_map_video_memory(struct fb_info *info, struct pci_dev *dev)
    195{
    196	struct geodefb_par *par = info->par;
    197	unsigned gx_base;
    198	int fb_len;
    199	int ret;
    200
    201	gx_base = gx1_gx_base();
    202	if (!gx_base)
    203		return -ENODEV;
    204
    205	ret = pci_enable_device(dev);
    206	if (ret < 0)
    207		return ret;
    208
    209	ret = pci_request_region(dev, 0, "gx1fb (video)");
    210	if (ret < 0)
    211		return ret;
    212	par->vid_regs = pci_ioremap_bar(dev, 0);
    213	if (!par->vid_regs)
    214		return -ENOMEM;
    215
    216	if (!request_mem_region(gx_base + 0x8300, 0x100, "gx1fb (display controller)"))
    217		return -EBUSY;
    218	par->dc_regs = ioremap(gx_base + 0x8300, 0x100);
    219	if (!par->dc_regs)
    220		return -ENOMEM;
    221
    222	if ((fb_len = gx1_frame_buffer_size()) < 0)
    223		return -ENOMEM;
    224	info->fix.smem_start = gx_base + 0x800000;
    225	info->fix.smem_len = fb_len;
    226	info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len);
    227	if (!info->screen_base)
    228		return -ENOMEM;
    229
    230	dev_info(&dev->dev, "%d Kibyte of video memory at 0x%lx\n",
    231		 info->fix.smem_len / 1024, info->fix.smem_start);
    232
    233	return 0;
    234}
    235
    236static int parse_panel_option(struct fb_info *info)
    237{
    238	struct geodefb_par *par = info->par;
    239
    240	if (strcmp(panel_option, "") != 0) {
    241		int x, y;
    242		char *s;
    243		x = simple_strtol(panel_option, &s, 10);
    244		if (!x)
    245			return -EINVAL;
    246		y = simple_strtol(s + 1, NULL, 10);
    247		if (!y)
    248			return -EINVAL;
    249		par->panel_x = x;
    250		par->panel_y = y;
    251	}
    252	return 0;
    253}
    254
    255static const struct fb_ops gx1fb_ops = {
    256	.owner		= THIS_MODULE,
    257	.fb_check_var	= gx1fb_check_var,
    258	.fb_set_par	= gx1fb_set_par,
    259	.fb_setcolreg	= gx1fb_setcolreg,
    260	.fb_blank       = gx1fb_blank,
    261	/* No HW acceleration for now. */
    262	.fb_fillrect	= cfb_fillrect,
    263	.fb_copyarea	= cfb_copyarea,
    264	.fb_imageblit	= cfb_imageblit,
    265};
    266
    267static struct fb_info *gx1fb_init_fbinfo(struct device *dev)
    268{
    269	struct geodefb_par *par;
    270	struct fb_info *info;
    271
    272	/* Alloc enough space for the pseudo palette. */
    273	info = framebuffer_alloc(sizeof(struct geodefb_par) + sizeof(u32) * 16, dev);
    274	if (!info)
    275		return NULL;
    276
    277	par = info->par;
    278
    279	strcpy(info->fix.id, "GX1");
    280
    281	info->fix.type		= FB_TYPE_PACKED_PIXELS;
    282	info->fix.type_aux	= 0;
    283	info->fix.xpanstep	= 0;
    284	info->fix.ypanstep	= 0;
    285	info->fix.ywrapstep	= 0;
    286	info->fix.accel		= FB_ACCEL_NONE;
    287
    288	info->var.nonstd	= 0;
    289	info->var.activate	= FB_ACTIVATE_NOW;
    290	info->var.height	= -1;
    291	info->var.width	= -1;
    292	info->var.accel_flags = 0;
    293	info->var.vmode	= FB_VMODE_NONINTERLACED;
    294
    295	info->fbops		= &gx1fb_ops;
    296	info->flags		= FBINFO_DEFAULT;
    297	info->node		= -1;
    298
    299	info->pseudo_palette	= (void *)par + sizeof(struct geodefb_par);
    300
    301	info->var.grayscale	= 0;
    302
    303	/* CRT and panel options */
    304	par->enable_crt = crt_option;
    305	if (parse_panel_option(info) < 0)
    306		printk(KERN_WARNING "gx1fb: invalid 'panel' option -- disabling flat panel\n");
    307	if (!par->panel_x)
    308		par->enable_crt = 1; /* fall back to CRT if no panel is specified */
    309
    310	if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
    311		framebuffer_release(info);
    312		return NULL;
    313	}
    314	return info;
    315}
    316
    317static int gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
    318{
    319	struct geodefb_par *par;
    320	struct fb_info *info;
    321	int ret;
    322
    323	info = gx1fb_init_fbinfo(&pdev->dev);
    324	if (!info)
    325		return -ENOMEM;
    326	par = info->par;
    327
    328	/* GX1 display controller and CS5530 video device */
    329	par->dc_ops  = &gx1_dc_ops;
    330	par->vid_ops = &cs5530_vid_ops;
    331
    332	if ((ret = gx1fb_map_video_memory(info, pdev)) < 0) {
    333		dev_err(&pdev->dev, "failed to map frame buffer or controller registers\n");
    334		goto err;
    335	}
    336
    337	ret = fb_find_mode(&info->var, info, mode_option,
    338			   gx1_modedb, ARRAY_SIZE(gx1_modedb), NULL, 16);
    339	if (ret == 0 || ret == 4) {
    340		dev_err(&pdev->dev, "could not find valid video mode\n");
    341		ret = -EINVAL;
    342		goto err;
    343	}
    344
    345        /* Clear the frame buffer of garbage. */
    346        memset_io(info->screen_base, 0, info->fix.smem_len);
    347
    348	gx1fb_check_var(&info->var, info);
    349	gx1fb_set_par(info);
    350
    351	if (register_framebuffer(info) < 0) {
    352		ret = -EINVAL;
    353		goto err;
    354	}
    355	pci_set_drvdata(pdev, info);
    356	fb_info(info, "%s frame buffer device\n", info->fix.id);
    357	return 0;
    358
    359  err:
    360	if (info->screen_base) {
    361		iounmap(info->screen_base);
    362		pci_release_region(pdev, 0);
    363	}
    364	if (par->vid_regs) {
    365		iounmap(par->vid_regs);
    366		pci_release_region(pdev, 1);
    367	}
    368	if (par->dc_regs) {
    369		iounmap(par->dc_regs);
    370		release_mem_region(gx1_gx_base() + 0x8300, 0x100);
    371	}
    372
    373	fb_dealloc_cmap(&info->cmap);
    374	framebuffer_release(info);
    375
    376	return ret;
    377}
    378
    379static void gx1fb_remove(struct pci_dev *pdev)
    380{
    381	struct fb_info *info = pci_get_drvdata(pdev);
    382	struct geodefb_par *par = info->par;
    383
    384	unregister_framebuffer(info);
    385
    386	iounmap((void __iomem *)info->screen_base);
    387	pci_release_region(pdev, 0);
    388
    389	iounmap(par->vid_regs);
    390	pci_release_region(pdev, 1);
    391
    392	iounmap(par->dc_regs);
    393	release_mem_region(gx1_gx_base() + 0x8300, 0x100);
    394
    395	fb_dealloc_cmap(&info->cmap);
    396
    397	framebuffer_release(info);
    398}
    399
    400#ifndef MODULE
    401static void __init gx1fb_setup(char *options)
    402{
    403	char *this_opt;
    404
    405	if (!options || !*options)
    406		return;
    407
    408	while ((this_opt = strsep(&options, ","))) {
    409		if (!*this_opt)
    410			continue;
    411
    412		if (!strncmp(this_opt, "mode:", 5))
    413			strlcpy(mode_option, this_opt + 5, sizeof(mode_option));
    414		else if (!strncmp(this_opt, "crt:", 4))
    415			crt_option = !!simple_strtoul(this_opt + 4, NULL, 0);
    416		else if (!strncmp(this_opt, "panel:", 6))
    417			strlcpy(panel_option, this_opt + 6, sizeof(panel_option));
    418		else
    419			strlcpy(mode_option, this_opt, sizeof(mode_option));
    420	}
    421}
    422#endif
    423
    424static struct pci_device_id gx1fb_id_table[] = {
    425	{ PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_VIDEO,
    426	  PCI_ANY_ID, PCI_ANY_ID, PCI_BASE_CLASS_DISPLAY << 16,
    427	  0xff0000, 0 },
    428	{ 0, }
    429};
    430
    431MODULE_DEVICE_TABLE(pci, gx1fb_id_table);
    432
    433static struct pci_driver gx1fb_driver = {
    434	.name		= "gx1fb",
    435	.id_table	= gx1fb_id_table,
    436	.probe		= gx1fb_probe,
    437	.remove		= gx1fb_remove,
    438};
    439
    440static int __init gx1fb_init(void)
    441{
    442#ifndef MODULE
    443	char *option = NULL;
    444
    445	if (fb_get_options("gx1fb", &option))
    446		return -ENODEV;
    447	gx1fb_setup(option);
    448#endif
    449	return pci_register_driver(&gx1fb_driver);
    450}
    451
    452static void gx1fb_cleanup(void)
    453{
    454	pci_unregister_driver(&gx1fb_driver);
    455}
    456
    457module_init(gx1fb_init);
    458module_exit(gx1fb_cleanup);
    459
    460module_param_string(mode, mode_option, sizeof(mode_option), 0444);
    461MODULE_PARM_DESC(mode, "video mode (<x>x<y>[-<bpp>][@<refr>])");
    462
    463module_param_named(crt, crt_option, int, 0444);
    464MODULE_PARM_DESC(crt, "enable CRT output. 0 = off, 1 = on (default)");
    465
    466module_param_string(panel, panel_option, sizeof(panel_option), 0444);
    467MODULE_PARM_DESC(panel, "size of attached flat panel (<x>x<y>)");
    468
    469MODULE_DESCRIPTION("framebuffer driver for the AMD Geode GX1");
    470MODULE_LICENSE("GPL");