162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* p9100.c: P9100 frame buffer driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) 562306a36Sopenharmony_ci * Copyright 1999 Derrick J Brashear (shadow@dementia.org) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Driver layout based loosely on tgafb.c, see that file for credits. 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/errno.h> 1362306a36Sopenharmony_ci#include <linux/string.h> 1462306a36Sopenharmony_ci#include <linux/delay.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/fb.h> 1762306a36Sopenharmony_ci#include <linux/mm.h> 1862306a36Sopenharmony_ci#include <linux/of.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <asm/io.h> 2262306a36Sopenharmony_ci#include <asm/fbio.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "sbuslib.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Local functions. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic int p9100_setcolreg(unsigned, unsigned, unsigned, unsigned, 3162306a36Sopenharmony_ci unsigned, struct fb_info *); 3262306a36Sopenharmony_cistatic int p9100_blank(int, struct fb_info *); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int p9100_mmap(struct fb_info *, struct vm_area_struct *); 3562306a36Sopenharmony_cistatic int p9100_ioctl(struct fb_info *, unsigned int, unsigned long); 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * Frame buffer operations 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic const struct fb_ops p9100_ops = { 4262306a36Sopenharmony_ci .owner = THIS_MODULE, 4362306a36Sopenharmony_ci .fb_setcolreg = p9100_setcolreg, 4462306a36Sopenharmony_ci .fb_blank = p9100_blank, 4562306a36Sopenharmony_ci .fb_fillrect = cfb_fillrect, 4662306a36Sopenharmony_ci .fb_copyarea = cfb_copyarea, 4762306a36Sopenharmony_ci .fb_imageblit = cfb_imageblit, 4862306a36Sopenharmony_ci .fb_mmap = p9100_mmap, 4962306a36Sopenharmony_ci .fb_ioctl = p9100_ioctl, 5062306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 5162306a36Sopenharmony_ci .fb_compat_ioctl = sbusfb_compat_ioctl, 5262306a36Sopenharmony_ci#endif 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* P9100 control registers */ 5662306a36Sopenharmony_ci#define P9100_SYSCTL_OFF 0x0UL 5762306a36Sopenharmony_ci#define P9100_VIDEOCTL_OFF 0x100UL 5862306a36Sopenharmony_ci#define P9100_VRAMCTL_OFF 0x180UL 5962306a36Sopenharmony_ci#define P9100_RAMDAC_OFF 0x200UL 6062306a36Sopenharmony_ci#define P9100_VIDEOCOPROC_OFF 0x400UL 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* P9100 command registers */ 6362306a36Sopenharmony_ci#define P9100_CMD_OFF 0x0UL 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* P9100 framebuffer memory */ 6662306a36Sopenharmony_ci#define P9100_FB_OFF 0x0UL 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* 3 bits: 2=8bpp 3=16bpp 5=32bpp 7=24bpp */ 6962306a36Sopenharmony_ci#define SYS_CONFIG_PIXELSIZE_SHIFT 26 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define SCREENPAINT_TIMECTL1_ENABLE_VIDEO 0x20 /* 0 = off, 1 = on */ 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistruct p9100_regs { 7462306a36Sopenharmony_ci /* Registers for the system control */ 7562306a36Sopenharmony_ci u32 sys_base; 7662306a36Sopenharmony_ci u32 sys_config; 7762306a36Sopenharmony_ci u32 sys_intr; 7862306a36Sopenharmony_ci u32 sys_int_ena; 7962306a36Sopenharmony_ci u32 sys_alt_rd; 8062306a36Sopenharmony_ci u32 sys_alt_wr; 8162306a36Sopenharmony_ci u32 sys_xxx[58]; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* Registers for the video control */ 8462306a36Sopenharmony_ci u32 vid_base; 8562306a36Sopenharmony_ci u32 vid_hcnt; 8662306a36Sopenharmony_ci u32 vid_htotal; 8762306a36Sopenharmony_ci u32 vid_hsync_rise; 8862306a36Sopenharmony_ci u32 vid_hblank_rise; 8962306a36Sopenharmony_ci u32 vid_hblank_fall; 9062306a36Sopenharmony_ci u32 vid_hcnt_preload; 9162306a36Sopenharmony_ci u32 vid_vcnt; 9262306a36Sopenharmony_ci u32 vid_vlen; 9362306a36Sopenharmony_ci u32 vid_vsync_rise; 9462306a36Sopenharmony_ci u32 vid_vblank_rise; 9562306a36Sopenharmony_ci u32 vid_vblank_fall; 9662306a36Sopenharmony_ci u32 vid_vcnt_preload; 9762306a36Sopenharmony_ci u32 vid_screenpaint_addr; 9862306a36Sopenharmony_ci u32 vid_screenpaint_timectl1; 9962306a36Sopenharmony_ci u32 vid_screenpaint_qsfcnt; 10062306a36Sopenharmony_ci u32 vid_screenpaint_timectl2; 10162306a36Sopenharmony_ci u32 vid_xxx[15]; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Registers for the video control */ 10462306a36Sopenharmony_ci u32 vram_base; 10562306a36Sopenharmony_ci u32 vram_memcfg; 10662306a36Sopenharmony_ci u32 vram_refresh_pd; 10762306a36Sopenharmony_ci u32 vram_refresh_cnt; 10862306a36Sopenharmony_ci u32 vram_raslo_max; 10962306a36Sopenharmony_ci u32 vram_raslo_cur; 11062306a36Sopenharmony_ci u32 pwrup_cfg; 11162306a36Sopenharmony_ci u32 vram_xxx[25]; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* Registers for IBM RGB528 Palette */ 11462306a36Sopenharmony_ci u32 ramdac_cmap_wridx; 11562306a36Sopenharmony_ci u32 ramdac_palette_data; 11662306a36Sopenharmony_ci u32 ramdac_pixel_mask; 11762306a36Sopenharmony_ci u32 ramdac_palette_rdaddr; 11862306a36Sopenharmony_ci u32 ramdac_idx_lo; 11962306a36Sopenharmony_ci u32 ramdac_idx_hi; 12062306a36Sopenharmony_ci u32 ramdac_idx_data; 12162306a36Sopenharmony_ci u32 ramdac_idx_ctl; 12262306a36Sopenharmony_ci u32 ramdac_xxx[1784]; 12362306a36Sopenharmony_ci}; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistruct p9100_cmd_parameng { 12662306a36Sopenharmony_ci u32 parameng_status; 12762306a36Sopenharmony_ci u32 parameng_bltcmd; 12862306a36Sopenharmony_ci u32 parameng_quadcmd; 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct p9100_par { 13262306a36Sopenharmony_ci spinlock_t lock; 13362306a36Sopenharmony_ci struct p9100_regs __iomem *regs; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci u32 flags; 13662306a36Sopenharmony_ci#define P9100_FLAG_BLANKED 0x00000001 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci unsigned long which_io; 13962306a36Sopenharmony_ci}; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/** 14262306a36Sopenharmony_ci * p9100_setcolreg - Optional function. Sets a color register. 14362306a36Sopenharmony_ci * @regno: boolean, 0 copy local, 1 get_user() function 14462306a36Sopenharmony_ci * @red: frame buffer colormap structure 14562306a36Sopenharmony_ci * @green: The green value which can be up to 16 bits wide 14662306a36Sopenharmony_ci * @blue: The blue value which can be up to 16 bits wide. 14762306a36Sopenharmony_ci * @transp: If supported the alpha value which can be up to 16 bits wide. 14862306a36Sopenharmony_ci * @info: frame buffer info structure 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_cistatic int p9100_setcolreg(unsigned regno, 15162306a36Sopenharmony_ci unsigned red, unsigned green, unsigned blue, 15262306a36Sopenharmony_ci unsigned transp, struct fb_info *info) 15362306a36Sopenharmony_ci{ 15462306a36Sopenharmony_ci struct p9100_par *par = (struct p9100_par *) info->par; 15562306a36Sopenharmony_ci struct p9100_regs __iomem *regs = par->regs; 15662306a36Sopenharmony_ci unsigned long flags; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if (regno >= 256) 15962306a36Sopenharmony_ci return 1; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci red >>= 8; 16262306a36Sopenharmony_ci green >>= 8; 16362306a36Sopenharmony_ci blue >>= 8; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci spin_lock_irqsave(&par->lock, flags); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci sbus_writel((regno << 16), ®s->ramdac_cmap_wridx); 16862306a36Sopenharmony_ci sbus_writel((red << 16), ®s->ramdac_palette_data); 16962306a36Sopenharmony_ci sbus_writel((green << 16), ®s->ramdac_palette_data); 17062306a36Sopenharmony_ci sbus_writel((blue << 16), ®s->ramdac_palette_data); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci spin_unlock_irqrestore(&par->lock, flags); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/** 17862306a36Sopenharmony_ci * p9100_blank - Optional function. Blanks the display. 17962306a36Sopenharmony_ci * @blank: the blank mode we want. 18062306a36Sopenharmony_ci * @info: frame buffer structure that represents a single frame buffer 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_cistatic int 18362306a36Sopenharmony_cip9100_blank(int blank, struct fb_info *info) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct p9100_par *par = (struct p9100_par *) info->par; 18662306a36Sopenharmony_ci struct p9100_regs __iomem *regs = par->regs; 18762306a36Sopenharmony_ci unsigned long flags; 18862306a36Sopenharmony_ci u32 val; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci spin_lock_irqsave(&par->lock, flags); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci switch (blank) { 19362306a36Sopenharmony_ci case FB_BLANK_UNBLANK: /* Unblanking */ 19462306a36Sopenharmony_ci val = sbus_readl(®s->vid_screenpaint_timectl1); 19562306a36Sopenharmony_ci val |= SCREENPAINT_TIMECTL1_ENABLE_VIDEO; 19662306a36Sopenharmony_ci sbus_writel(val, ®s->vid_screenpaint_timectl1); 19762306a36Sopenharmony_ci par->flags &= ~P9100_FLAG_BLANKED; 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci case FB_BLANK_NORMAL: /* Normal blanking */ 20162306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ 20262306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ 20362306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: /* Poweroff */ 20462306a36Sopenharmony_ci val = sbus_readl(®s->vid_screenpaint_timectl1); 20562306a36Sopenharmony_ci val &= ~SCREENPAINT_TIMECTL1_ENABLE_VIDEO; 20662306a36Sopenharmony_ci sbus_writel(val, ®s->vid_screenpaint_timectl1); 20762306a36Sopenharmony_ci par->flags |= P9100_FLAG_BLANKED; 20862306a36Sopenharmony_ci break; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci spin_unlock_irqrestore(&par->lock, flags); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic struct sbus_mmap_map p9100_mmap_map[] = { 21762306a36Sopenharmony_ci { CG3_MMAP_OFFSET, 0, SBUS_MMAP_FBSIZE(1) }, 21862306a36Sopenharmony_ci { 0, 0, 0 } 21962306a36Sopenharmony_ci}; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct p9100_par *par = (struct p9100_par *)info->par; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return sbusfb_mmap_helper(p9100_mmap_map, 22662306a36Sopenharmony_ci info->fix.smem_start, info->fix.smem_len, 22762306a36Sopenharmony_ci par->which_io, vma); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int p9100_ioctl(struct fb_info *info, unsigned int cmd, 23162306a36Sopenharmony_ci unsigned long arg) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci /* Make it look like a cg3. */ 23462306a36Sopenharmony_ci return sbusfb_ioctl_helper(cmd, arg, info, 23562306a36Sopenharmony_ci FBTYPE_SUN3COLOR, 8, info->fix.smem_len); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci/* 23962306a36Sopenharmony_ci * Initialisation 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void p9100_init_fix(struct fb_info *info, int linebytes, struct device_node *dp) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci info->fix.type = FB_TYPE_PACKED_PIXELS; 24762306a36Sopenharmony_ci info->fix.visual = FB_VISUAL_PSEUDOCOLOR; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci info->fix.line_length = linebytes; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci info->fix.accel = FB_ACCEL_SUN_CGTHREE; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int p9100_probe(struct platform_device *op) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct device_node *dp = op->dev.of_node; 25762306a36Sopenharmony_ci struct fb_info *info; 25862306a36Sopenharmony_ci struct p9100_par *par; 25962306a36Sopenharmony_ci int linebytes, err; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci info = framebuffer_alloc(sizeof(struct p9100_par), &op->dev); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci err = -ENOMEM; 26462306a36Sopenharmony_ci if (!info) 26562306a36Sopenharmony_ci goto out_err; 26662306a36Sopenharmony_ci par = info->par; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci spin_lock_init(&par->lock); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* This is the framebuffer and the only resource apps can mmap. */ 27162306a36Sopenharmony_ci info->fix.smem_start = op->resource[2].start; 27262306a36Sopenharmony_ci par->which_io = op->resource[2].flags & IORESOURCE_BITS; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci sbusfb_fill_var(&info->var, dp, 8); 27562306a36Sopenharmony_ci info->var.red.length = 8; 27662306a36Sopenharmony_ci info->var.green.length = 8; 27762306a36Sopenharmony_ci info->var.blue.length = 8; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); 28062306a36Sopenharmony_ci info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci par->regs = of_ioremap(&op->resource[0], 0, 28362306a36Sopenharmony_ci sizeof(struct p9100_regs), "p9100 regs"); 28462306a36Sopenharmony_ci if (!par->regs) 28562306a36Sopenharmony_ci goto out_release_fb; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci info->fbops = &p9100_ops; 28862306a36Sopenharmony_ci info->screen_base = of_ioremap(&op->resource[2], 0, 28962306a36Sopenharmony_ci info->fix.smem_len, "p9100 ram"); 29062306a36Sopenharmony_ci if (!info->screen_base) 29162306a36Sopenharmony_ci goto out_unmap_regs; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci p9100_blank(FB_BLANK_UNBLANK, info); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci if (fb_alloc_cmap(&info->cmap, 256, 0)) 29662306a36Sopenharmony_ci goto out_unmap_screen; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci p9100_init_fix(info, linebytes, dp); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci err = register_framebuffer(info); 30162306a36Sopenharmony_ci if (err < 0) 30262306a36Sopenharmony_ci goto out_dealloc_cmap; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci fb_set_cmap(&info->cmap, info); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci dev_set_drvdata(&op->dev, info); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci printk(KERN_INFO "%pOF: p9100 at %lx:%lx\n", 30962306a36Sopenharmony_ci dp, 31062306a36Sopenharmony_ci par->which_io, info->fix.smem_start); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ciout_dealloc_cmap: 31562306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ciout_unmap_screen: 31862306a36Sopenharmony_ci of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ciout_unmap_regs: 32162306a36Sopenharmony_ci of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ciout_release_fb: 32462306a36Sopenharmony_ci framebuffer_release(info); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ciout_err: 32762306a36Sopenharmony_ci return err; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic void p9100_remove(struct platform_device *op) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci struct fb_info *info = dev_get_drvdata(&op->dev); 33362306a36Sopenharmony_ci struct p9100_par *par = info->par; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci unregister_framebuffer(info); 33662306a36Sopenharmony_ci fb_dealloc_cmap(&info->cmap); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); 33962306a36Sopenharmony_ci of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci framebuffer_release(info); 34262306a36Sopenharmony_ci} 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_cistatic const struct of_device_id p9100_match[] = { 34562306a36Sopenharmony_ci { 34662306a36Sopenharmony_ci .name = "p9100", 34762306a36Sopenharmony_ci }, 34862306a36Sopenharmony_ci {}, 34962306a36Sopenharmony_ci}; 35062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, p9100_match); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic struct platform_driver p9100_driver = { 35362306a36Sopenharmony_ci .driver = { 35462306a36Sopenharmony_ci .name = "p9100", 35562306a36Sopenharmony_ci .of_match_table = p9100_match, 35662306a36Sopenharmony_ci }, 35762306a36Sopenharmony_ci .probe = p9100_probe, 35862306a36Sopenharmony_ci .remove_new = p9100_remove, 35962306a36Sopenharmony_ci}; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_cistatic int __init p9100_init(void) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci if (fb_get_options("p9100fb", NULL)) 36462306a36Sopenharmony_ci return -ENODEV; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci return platform_driver_register(&p9100_driver); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_cistatic void __exit p9100_exit(void) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci platform_driver_unregister(&p9100_driver); 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cimodule_init(p9100_init); 37562306a36Sopenharmony_cimodule_exit(p9100_exit); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciMODULE_DESCRIPTION("framebuffer driver for P9100 chipsets"); 37862306a36Sopenharmony_ciMODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 37962306a36Sopenharmony_ciMODULE_VERSION("2.0"); 38062306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 381