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

p9100.c (9159B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* p9100.c: P9100 frame buffer driver
      3 *
      4 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
      5 * Copyright 1999 Derrick J Brashear (shadow@dementia.org)
      6 *
      7 * Driver layout based loosely on tgafb.c, see that file for credits.
      8 */
      9
     10#include <linux/module.h>
     11#include <linux/kernel.h>
     12#include <linux/errno.h>
     13#include <linux/string.h>
     14#include <linux/delay.h>
     15#include <linux/init.h>
     16#include <linux/fb.h>
     17#include <linux/mm.h>
     18#include <linux/of_device.h>
     19
     20#include <asm/io.h>
     21#include <asm/fbio.h>
     22
     23#include "sbuslib.h"
     24
     25/*
     26 * Local functions.
     27 */
     28
     29static int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned,
     30			   unsigned, struct fb_info *);
     31static int p9100_blank(int, struct fb_info *);
     32
     33static int p9100_mmap(struct fb_info *, struct vm_area_struct *);
     34static int p9100_ioctl(struct fb_info *, unsigned int, unsigned long);
     35
     36/*
     37 *  Frame buffer operations
     38 */
     39
     40static const struct fb_ops p9100_ops = {
     41	.owner			= THIS_MODULE,
     42	.fb_setcolreg		= p9100_setcolreg,
     43	.fb_blank		= p9100_blank,
     44	.fb_fillrect		= cfb_fillrect,
     45	.fb_copyarea		= cfb_copyarea,
     46	.fb_imageblit		= cfb_imageblit,
     47	.fb_mmap		= p9100_mmap,
     48	.fb_ioctl		= p9100_ioctl,
     49#ifdef CONFIG_COMPAT
     50	.fb_compat_ioctl	= sbusfb_compat_ioctl,
     51#endif
     52};
     53
     54/* P9100 control registers */
     55#define P9100_SYSCTL_OFF	0x0UL
     56#define P9100_VIDEOCTL_OFF	0x100UL
     57#define P9100_VRAMCTL_OFF 	0x180UL
     58#define P9100_RAMDAC_OFF 	0x200UL
     59#define P9100_VIDEOCOPROC_OFF 	0x400UL
     60
     61/* P9100 command registers */
     62#define P9100_CMD_OFF 0x0UL
     63
     64/* P9100 framebuffer memory */
     65#define P9100_FB_OFF 0x0UL
     66
     67/* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */
     68#define SYS_CONFIG_PIXELSIZE_SHIFT 26 
     69
     70#define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */
     71
     72struct p9100_regs {
     73	/* Registers for the system control */
     74	u32 sys_base;
     75	u32 sys_config;
     76	u32 sys_intr;
     77	u32 sys_int_ena;
     78	u32 sys_alt_rd;
     79	u32 sys_alt_wr;
     80	u32 sys_xxx[58];
     81
     82	/* Registers for the video control */
     83	u32 vid_base;
     84	u32 vid_hcnt;
     85	u32 vid_htotal;
     86	u32 vid_hsync_rise;
     87	u32 vid_hblank_rise;
     88	u32 vid_hblank_fall;
     89	u32 vid_hcnt_preload;
     90	u32 vid_vcnt;
     91	u32 vid_vlen;
     92	u32 vid_vsync_rise;
     93	u32 vid_vblank_rise;
     94	u32 vid_vblank_fall;
     95	u32 vid_vcnt_preload;
     96	u32 vid_screenpaint_addr;
     97	u32 vid_screenpaint_timectl1;
     98	u32 vid_screenpaint_qsfcnt;
     99	u32 vid_screenpaint_timectl2;
    100	u32 vid_xxx[15];
    101
    102	/* Registers for the video control */
    103	u32 vram_base;
    104	u32 vram_memcfg;
    105	u32 vram_refresh_pd;
    106	u32 vram_refresh_cnt;
    107	u32 vram_raslo_max;
    108	u32 vram_raslo_cur;
    109	u32 pwrup_cfg;
    110	u32 vram_xxx[25];
    111
    112	/* Registers for IBM RGB528 Palette */
    113	u32 ramdac_cmap_wridx; 
    114	u32 ramdac_palette_data;
    115	u32 ramdac_pixel_mask;
    116	u32 ramdac_palette_rdaddr;
    117	u32 ramdac_idx_lo;
    118	u32 ramdac_idx_hi;
    119	u32 ramdac_idx_data;
    120	u32 ramdac_idx_ctl;
    121	u32 ramdac_xxx[1784];
    122};
    123
    124struct p9100_cmd_parameng {
    125	u32 parameng_status;
    126	u32 parameng_bltcmd;
    127	u32 parameng_quadcmd;
    128};
    129
    130struct p9100_par {
    131	spinlock_t		lock;
    132	struct p9100_regs	__iomem *regs;
    133
    134	u32			flags;
    135#define P9100_FLAG_BLANKED	0x00000001
    136
    137	unsigned long		which_io;
    138};
    139
    140/**
    141 *      p9100_setcolreg - Optional function. Sets a color register.
    142 *      @regno: boolean, 0 copy local, 1 get_user() function
    143 *      @red: frame buffer colormap structure
    144 *      @green: The green value which can be up to 16 bits wide
    145 *      @blue:  The blue value which can be up to 16 bits wide.
    146 *      @transp: If supported the alpha value which can be up to 16 bits wide.
    147 *      @info: frame buffer info structure
    148 */
    149static int p9100_setcolreg(unsigned regno,
    150			   unsigned red, unsigned green, unsigned blue,
    151			   unsigned transp, struct fb_info *info)
    152{
    153	struct p9100_par *par = (struct p9100_par *) info->par;
    154	struct p9100_regs __iomem *regs = par->regs;
    155	unsigned long flags;
    156
    157	if (regno >= 256)
    158		return 1;
    159
    160	red >>= 8;
    161	green >>= 8;
    162	blue >>= 8;
    163
    164	spin_lock_irqsave(&par->lock, flags);
    165
    166	sbus_writel((regno << 16), &regs->ramdac_cmap_wridx);
    167	sbus_writel((red << 16), &regs->ramdac_palette_data);
    168	sbus_writel((green << 16), &regs->ramdac_palette_data);
    169	sbus_writel((blue << 16), &regs->ramdac_palette_data);
    170
    171	spin_unlock_irqrestore(&par->lock, flags);
    172
    173	return 0;
    174}
    175
    176/**
    177 *      p9100_blank - Optional function.  Blanks the display.
    178 *      @blank: the blank mode we want.
    179 *      @info: frame buffer structure that represents a single frame buffer
    180 */
    181static int
    182p9100_blank(int blank, struct fb_info *info)
    183{
    184	struct p9100_par *par = (struct p9100_par *) info->par;
    185	struct p9100_regs __iomem *regs = par->regs;
    186	unsigned long flags;
    187	u32 val;
    188
    189	spin_lock_irqsave(&par->lock, flags);
    190
    191	switch (blank) {
    192	case FB_BLANK_UNBLANK: /* Unblanking */
    193		val = sbus_readl(&regs->vid_screenpaint_timectl1);
    194		val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
    195		sbus_writel(val, &regs->vid_screenpaint_timectl1);
    196		par->flags &= ~P9100_FLAG_BLANKED;
    197		break;
    198
    199	case FB_BLANK_NORMAL: /* Normal blanking */
    200	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
    201	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
    202	case FB_BLANK_POWERDOWN: /* Poweroff */
    203		val = sbus_readl(&regs->vid_screenpaint_timectl1);
    204		val &= ~SCREENPAINT_TIMECTL1_ENABLE_VIDEO;
    205		sbus_writel(val, &regs->vid_screenpaint_timectl1);
    206		par->flags |= P9100_FLAG_BLANKED;
    207		break;
    208	}
    209
    210	spin_unlock_irqrestore(&par->lock, flags);
    211
    212	return 0;
    213}
    214
    215static struct sbus_mmap_map p9100_mmap_map[] = {
    216	{ CG3_MMAP_OFFSET,	0,		SBUS_MMAP_FBSIZE(1) },
    217	{ 0,			0,		0		    }
    218};
    219
    220static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma)
    221{
    222	struct p9100_par *par = (struct p9100_par *)info->par;
    223
    224	return sbusfb_mmap_helper(p9100_mmap_map,
    225				  info->fix.smem_start, info->fix.smem_len,
    226				  par->which_io, vma);
    227}
    228
    229static int p9100_ioctl(struct fb_info *info, unsigned int cmd,
    230		       unsigned long arg)
    231{
    232	/* Make it look like a cg3. */
    233	return sbusfb_ioctl_helper(cmd, arg, info,
    234				   FBTYPE_SUN3COLOR, 8, info->fix.smem_len);
    235}
    236
    237/*
    238 *  Initialisation
    239 */
    240
    241static void p9100_init_fix(struct fb_info *info, int linebytes, struct device_node *dp)
    242{
    243	snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp);
    244
    245	info->fix.type = FB_TYPE_PACKED_PIXELS;
    246	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
    247
    248	info->fix.line_length = linebytes;
    249
    250	info->fix.accel = FB_ACCEL_SUN_CGTHREE;
    251}
    252
    253static int p9100_probe(struct platform_device *op)
    254{
    255	struct device_node *dp = op->dev.of_node;
    256	struct fb_info *info;
    257	struct p9100_par *par;
    258	int linebytes, err;
    259
    260	info = framebuffer_alloc(sizeof(struct p9100_par), &op->dev);
    261
    262	err = -ENOMEM;
    263	if (!info)
    264		goto out_err;
    265	par = info->par;
    266
    267	spin_lock_init(&par->lock);
    268
    269	/* This is the framebuffer and the only resource apps can mmap.  */
    270	info->fix.smem_start = op->resource[2].start;
    271	par->which_io = op->resource[2].flags & IORESOURCE_BITS;
    272
    273	sbusfb_fill_var(&info->var, dp, 8);
    274	info->var.red.length = 8;
    275	info->var.green.length = 8;
    276	info->var.blue.length = 8;
    277
    278	linebytes = of_getintprop_default(dp, "linebytes", info->var.xres);
    279	info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
    280
    281	par->regs = of_ioremap(&op->resource[0], 0,
    282			       sizeof(struct p9100_regs), "p9100 regs");
    283	if (!par->regs)
    284		goto out_release_fb;
    285
    286	info->flags = FBINFO_DEFAULT;
    287	info->fbops = &p9100_ops;
    288	info->screen_base = of_ioremap(&op->resource[2], 0,
    289				       info->fix.smem_len, "p9100 ram");
    290	if (!info->screen_base)
    291		goto out_unmap_regs;
    292
    293	p9100_blank(FB_BLANK_UNBLANK, info);
    294
    295	if (fb_alloc_cmap(&info->cmap, 256, 0))
    296		goto out_unmap_screen;
    297
    298	p9100_init_fix(info, linebytes, dp);
    299
    300	err = register_framebuffer(info);
    301	if (err < 0)
    302		goto out_dealloc_cmap;
    303
    304	fb_set_cmap(&info->cmap, info);
    305
    306	dev_set_drvdata(&op->dev, info);
    307
    308	printk(KERN_INFO "%pOF: p9100 at %lx:%lx\n",
    309	       dp,
    310	       par->which_io, info->fix.smem_start);
    311
    312	return 0;
    313
    314out_dealloc_cmap:
    315	fb_dealloc_cmap(&info->cmap);
    316
    317out_unmap_screen:
    318	of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len);
    319
    320out_unmap_regs:
    321	of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
    322
    323out_release_fb:
    324	framebuffer_release(info);
    325
    326out_err:
    327	return err;
    328}
    329
    330static int p9100_remove(struct platform_device *op)
    331{
    332	struct fb_info *info = dev_get_drvdata(&op->dev);
    333	struct p9100_par *par = info->par;
    334
    335	unregister_framebuffer(info);
    336	fb_dealloc_cmap(&info->cmap);
    337
    338	of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs));
    339	of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len);
    340
    341	framebuffer_release(info);
    342
    343	return 0;
    344}
    345
    346static const struct of_device_id p9100_match[] = {
    347	{
    348		.name = "p9100",
    349	},
    350	{},
    351};
    352MODULE_DEVICE_TABLE(of, p9100_match);
    353
    354static struct platform_driver p9100_driver = {
    355	.driver = {
    356		.name = "p9100",
    357		.of_match_table = p9100_match,
    358	},
    359	.probe		= p9100_probe,
    360	.remove		= p9100_remove,
    361};
    362
    363static int __init p9100_init(void)
    364{
    365	if (fb_get_options("p9100fb", NULL))
    366		return -ENODEV;
    367
    368	return platform_driver_register(&p9100_driver);
    369}
    370
    371static void __exit p9100_exit(void)
    372{
    373	platform_driver_unregister(&p9100_driver);
    374}
    375
    376module_init(p9100_init);
    377module_exit(p9100_exit);
    378
    379MODULE_DESCRIPTION("framebuffer driver for P9100 chipsets");
    380MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
    381MODULE_VERSION("2.0");
    382MODULE_LICENSE("GPL");