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

bw2.c (9312B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* bw2.c: BWTWO frame buffer driver
      3 *
      4 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
      5 * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz)
      6 * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
      7 * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
      8 *
      9 * Driver layout based loosely on tgafb.c, see that file for credits.
     10 */
     11
     12#include <linux/module.h>
     13#include <linux/kernel.h>
     14#include <linux/errno.h>
     15#include <linux/string.h>
     16#include <linux/delay.h>
     17#include <linux/init.h>
     18#include <linux/fb.h>
     19#include <linux/mm.h>
     20#include <linux/of_device.h>
     21
     22#include <asm/io.h>
     23#include <asm/fbio.h>
     24
     25#include "sbuslib.h"
     26
     27/*
     28 * Local functions.
     29 */
     30
     31static int bw2_blank(int, struct fb_info *);
     32
     33static int bw2_mmap(struct fb_info *, struct vm_area_struct *);
     34static int bw2_ioctl(struct fb_info *, unsigned int, unsigned long);
     35
     36/*
     37 *  Frame buffer operations
     38 */
     39
     40static const struct fb_ops bw2_ops = {
     41	.owner			= THIS_MODULE,
     42	.fb_blank		= bw2_blank,
     43	.fb_fillrect		= cfb_fillrect,
     44	.fb_copyarea		= cfb_copyarea,
     45	.fb_imageblit		= cfb_imageblit,
     46	.fb_mmap		= bw2_mmap,
     47	.fb_ioctl		= bw2_ioctl,
     48#ifdef CONFIG_COMPAT
     49	.fb_compat_ioctl	= sbusfb_compat_ioctl,
     50#endif
     51};
     52
     53/* OBio addresses for the bwtwo registers */
     54#define BWTWO_REGISTER_OFFSET 0x400000
     55
     56struct bt_regs {
     57	u32 addr;
     58	u32 color_map;
     59	u32 control;
     60	u32 cursor;
     61};
     62
     63struct bw2_regs {
     64	struct bt_regs	cmap;
     65	u8	control;
     66	u8	status;
     67	u8	cursor_start;
     68	u8	cursor_end;
     69	u8	h_blank_start;
     70	u8	h_blank_end;
     71	u8	h_sync_start;
     72	u8	h_sync_end;
     73	u8	comp_sync_end;
     74	u8	v_blank_start_high;
     75	u8	v_blank_start_low;
     76	u8	v_blank_end;
     77	u8	v_sync_start;
     78	u8	v_sync_end;
     79	u8	xfer_holdoff_start;
     80	u8	xfer_holdoff_end;
     81};
     82
     83/* Status Register Constants */
     84#define BWTWO_SR_RES_MASK	0x70
     85#define BWTWO_SR_1600_1280	0x50
     86#define BWTWO_SR_1152_900_76_A	0x40
     87#define BWTWO_SR_1152_900_76_B	0x60
     88#define BWTWO_SR_ID_MASK	0x0f
     89#define BWTWO_SR_ID_MONO	0x02
     90#define BWTWO_SR_ID_MONO_ECL	0x03
     91#define BWTWO_SR_ID_MSYNC	0x04
     92#define BWTWO_SR_ID_NOCONN	0x0a
     93
     94/* Control Register Constants */
     95#define BWTWO_CTL_ENABLE_INTS   0x80
     96#define BWTWO_CTL_ENABLE_VIDEO  0x40
     97#define BWTWO_CTL_ENABLE_TIMING 0x20
     98#define BWTWO_CTL_ENABLE_CURCMP 0x10
     99#define BWTWO_CTL_XTAL_MASK     0x0C
    100#define BWTWO_CTL_DIVISOR_MASK  0x03
    101
    102/* Status Register Constants */
    103#define BWTWO_STAT_PENDING_INT  0x80
    104#define BWTWO_STAT_MSENSE_MASK  0x70
    105#define BWTWO_STAT_ID_MASK      0x0f
    106
    107struct bw2_par {
    108	spinlock_t		lock;
    109	struct bw2_regs		__iomem *regs;
    110
    111	u32			flags;
    112#define BW2_FLAG_BLANKED	0x00000001
    113
    114	unsigned long		which_io;
    115};
    116
    117/**
    118 *      bw2_blank - Optional function.  Blanks the display.
    119 *      @blank: the blank mode we want.
    120 *      @info: frame buffer structure that represents a single frame buffer
    121 */
    122static int
    123bw2_blank(int blank, struct fb_info *info)
    124{
    125	struct bw2_par *par = (struct bw2_par *) info->par;
    126	struct bw2_regs __iomem *regs = par->regs;
    127	unsigned long flags;
    128	u8 val;
    129
    130	spin_lock_irqsave(&par->lock, flags);
    131
    132	switch (blank) {
    133	case FB_BLANK_UNBLANK: /* Unblanking */
    134		val = sbus_readb(&regs->control);
    135		val |= BWTWO_CTL_ENABLE_VIDEO;
    136		sbus_writeb(val, &regs->control);
    137		par->flags &= ~BW2_FLAG_BLANKED;
    138		break;
    139
    140	case FB_BLANK_NORMAL: /* Normal blanking */
    141	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
    142	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
    143	case FB_BLANK_POWERDOWN: /* Poweroff */
    144		val = sbus_readb(&regs->control);
    145		val &= ~BWTWO_CTL_ENABLE_VIDEO;
    146		sbus_writeb(val, &regs->control);
    147		par->flags |= BW2_FLAG_BLANKED;
    148		break;
    149	}
    150
    151	spin_unlock_irqrestore(&par->lock, flags);
    152
    153	return 0;
    154}
    155
    156static struct sbus_mmap_map bw2_mmap_map[] = {
    157	{
    158		.size = SBUS_MMAP_FBSIZE(1)
    159	},
    160	{ .size = 0 }
    161};
    162
    163static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma)
    164{
    165	struct bw2_par *par = (struct bw2_par *)info->par;
    166
    167	return sbusfb_mmap_helper(bw2_mmap_map,
    168				  info->fix.smem_start, info->fix.smem_len,
    169				  par->which_io,
    170				  vma);
    171}
    172
    173static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
    174{
    175	return sbusfb_ioctl_helper(cmd, arg, info,
    176				   FBTYPE_SUN2BW, 1, info->fix.smem_len);
    177}
    178
    179/*
    180 *  Initialisation
    181 */
    182
    183static void bw2_init_fix(struct fb_info *info, int linebytes)
    184{
    185	strlcpy(info->fix.id, "bwtwo", sizeof(info->fix.id));
    186
    187	info->fix.type = FB_TYPE_PACKED_PIXELS;
    188	info->fix.visual = FB_VISUAL_MONO01;
    189
    190	info->fix.line_length = linebytes;
    191
    192	info->fix.accel = FB_ACCEL_SUN_BWTWO;
    193}
    194
    195static u8 bw2regs_1600[] = {
    196	0x14, 0x8b,	0x15, 0x28,	0x16, 0x03,	0x17, 0x13,
    197	0x18, 0x7b,	0x19, 0x05,	0x1a, 0x34,	0x1b, 0x2e,
    198	0x1c, 0x00,	0x1d, 0x0a,	0x1e, 0xff,	0x1f, 0x01,
    199	0x10, 0x21,	0
    200};
    201
    202static u8 bw2regs_ecl[] = {
    203	0x14, 0x65,	0x15, 0x1e,	0x16, 0x04,	0x17, 0x0c,
    204	0x18, 0x5e,	0x19, 0x03,	0x1a, 0xa7,	0x1b, 0x23,
    205	0x1c, 0x00,	0x1d, 0x08,	0x1e, 0xff,	0x1f, 0x01,
    206	0x10, 0x20,	0
    207};
    208
    209static u8 bw2regs_analog[] = {
    210	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x03,	0x17, 0x13,
    211	0x18, 0xb0,	0x19, 0x03,	0x1a, 0xa6,	0x1b, 0x22,
    212	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
    213	0x10, 0x20,	0
    214};
    215
    216static u8 bw2regs_76hz[] = {
    217	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,
    218	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,
    219	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,
    220	0x10, 0x24,	0
    221};
    222
    223static u8 bw2regs_66hz[] = {
    224	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,
    225	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,
    226	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,
    227	0x10, 0x20,	0
    228};
    229
    230static int bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,
    231			       int *linebytes)
    232{
    233	u8 status, mon;
    234	u8 *p;
    235
    236	status = sbus_readb(&par->regs->status);
    237	mon = status & BWTWO_SR_RES_MASK;
    238	switch (status & BWTWO_SR_ID_MASK) {
    239	case BWTWO_SR_ID_MONO_ECL:
    240		if (mon == BWTWO_SR_1600_1280) {
    241			p = bw2regs_1600;
    242			info->var.xres = info->var.xres_virtual = 1600;
    243			info->var.yres = info->var.yres_virtual = 1280;
    244			*linebytes = 1600 / 8;
    245		} else
    246			p = bw2regs_ecl;
    247		break;
    248
    249	case BWTWO_SR_ID_MONO:
    250		p = bw2regs_analog;
    251		break;
    252
    253	case BWTWO_SR_ID_MSYNC:
    254		if (mon == BWTWO_SR_1152_900_76_A ||
    255		    mon == BWTWO_SR_1152_900_76_B)
    256			p = bw2regs_76hz;
    257		else
    258			p = bw2regs_66hz;
    259		break;
    260
    261	case BWTWO_SR_ID_NOCONN:
    262		return 0;
    263
    264	default:
    265		printk(KERN_ERR "bw2: can't handle SR %02x\n",
    266		       status);
    267		return -EINVAL;
    268	}
    269	for ( ; *p; p += 2) {
    270		u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];
    271		sbus_writeb(p[1], regp);
    272	}
    273	return 0;
    274}
    275
    276static int bw2_probe(struct platform_device *op)
    277{
    278	struct device_node *dp = op->dev.of_node;
    279	struct fb_info *info;
    280	struct bw2_par *par;
    281	int linebytes, err;
    282
    283	info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev);
    284
    285	err = -ENOMEM;
    286	if (!info)
    287		goto out_err;
    288	par = info->par;
    289
    290	spin_lock_init(&par->lock);
    291
    292	info->fix.smem_start = op->resource[0].start;
    293	par->which_io = op->resource[0].flags & IORESOURCE_BITS;
    294
    295	sbusfb_fill_var(&info->var, dp, 1);
    296	linebytes = of_getintprop_default(dp, "linebytes",
    297					  info->var.xres);
    298
    299	info->var.red.length = info->var.green.length =
    300		info->var.blue.length = info->var.bits_per_pixel;
    301	info->var.red.offset = info->var.green.offset =
    302		info->var.blue.offset = 0;
    303
    304	par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,
    305			       sizeof(struct bw2_regs), "bw2 regs");
    306	if (!par->regs)
    307		goto out_release_fb;
    308
    309	if (!of_find_property(dp, "width", NULL)) {
    310		err = bw2_do_default_mode(par, info, &linebytes);
    311		if (err)
    312			goto out_unmap_regs;
    313	}
    314
    315	info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);
    316
    317	info->flags = FBINFO_DEFAULT;
    318	info->fbops = &bw2_ops;
    319
    320	info->screen_base = of_ioremap(&op->resource[0], 0,
    321				       info->fix.smem_len, "bw2 ram");
    322	if (!info->screen_base) {
    323		err = -ENOMEM;
    324		goto out_unmap_regs;
    325	}
    326
    327	bw2_blank(FB_BLANK_UNBLANK, info);
    328
    329	bw2_init_fix(info, linebytes);
    330
    331	err = register_framebuffer(info);
    332	if (err < 0)
    333		goto out_unmap_screen;
    334
    335	dev_set_drvdata(&op->dev, info);
    336
    337	printk(KERN_INFO "%pOF: bwtwo at %lx:%lx\n",
    338	       dp, par->which_io, info->fix.smem_start);
    339
    340	return 0;
    341
    342out_unmap_screen:
    343	of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
    344
    345out_unmap_regs:
    346	of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
    347
    348out_release_fb:
    349	framebuffer_release(info);
    350
    351out_err:
    352	return err;
    353}
    354
    355static int bw2_remove(struct platform_device *op)
    356{
    357	struct fb_info *info = dev_get_drvdata(&op->dev);
    358	struct bw2_par *par = info->par;
    359
    360	unregister_framebuffer(info);
    361
    362	of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));
    363	of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);
    364
    365	framebuffer_release(info);
    366
    367	return 0;
    368}
    369
    370static const struct of_device_id bw2_match[] = {
    371	{
    372		.name = "bwtwo",
    373	},
    374	{},
    375};
    376MODULE_DEVICE_TABLE(of, bw2_match);
    377
    378static struct platform_driver bw2_driver = {
    379	.driver = {
    380		.name = "bw2",
    381		.of_match_table = bw2_match,
    382	},
    383	.probe		= bw2_probe,
    384	.remove		= bw2_remove,
    385};
    386
    387static int __init bw2_init(void)
    388{
    389	if (fb_get_options("bw2fb", NULL))
    390		return -ENODEV;
    391
    392	return platform_driver_register(&bw2_driver);
    393}
    394
    395static void __exit bw2_exit(void)
    396{
    397	platform_driver_unregister(&bw2_driver);
    398}
    399
    400module_init(bw2_init);
    401module_exit(bw2_exit);
    402
    403MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");
    404MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
    405MODULE_VERSION("2.0");
    406MODULE_LICENSE("GPL");