whiterose

linux unikernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/whiterose

p9100.c (9117B)


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