162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* bw2.c: BWTWO frame buffer driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net) 562306a36Sopenharmony_ci * Copyright (C) 1996,1998 Jakub Jelinek (jj@ultra.linux.cz) 662306a36Sopenharmony_ci * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) 762306a36Sopenharmony_ci * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Driver layout based loosely on tgafb.c, see that file for credits. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/errno.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/delay.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/fb.h> 1962306a36Sopenharmony_ci#include <linux/mm.h> 2062306a36Sopenharmony_ci#include <linux/of.h> 2162306a36Sopenharmony_ci#include <linux/platform_device.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <asm/io.h> 2462306a36Sopenharmony_ci#include <asm/fbio.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "sbuslib.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* 2962306a36Sopenharmony_ci * Local functions. 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic int bw2_blank(int, struct fb_info *); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic int bw2_mmap(struct fb_info *, struct vm_area_struct *); 3562306a36Sopenharmony_cistatic int bw2_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 bw2_ops = { 4262306a36Sopenharmony_ci .owner = THIS_MODULE, 4362306a36Sopenharmony_ci .fb_blank = bw2_blank, 4462306a36Sopenharmony_ci .fb_fillrect = cfb_fillrect, 4562306a36Sopenharmony_ci .fb_copyarea = cfb_copyarea, 4662306a36Sopenharmony_ci .fb_imageblit = cfb_imageblit, 4762306a36Sopenharmony_ci .fb_mmap = bw2_mmap, 4862306a36Sopenharmony_ci .fb_ioctl = bw2_ioctl, 4962306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 5062306a36Sopenharmony_ci .fb_compat_ioctl = sbusfb_compat_ioctl, 5162306a36Sopenharmony_ci#endif 5262306a36Sopenharmony_ci}; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* OBio addresses for the bwtwo registers */ 5562306a36Sopenharmony_ci#define BWTWO_REGISTER_OFFSET 0x400000 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct bt_regs { 5862306a36Sopenharmony_ci u32 addr; 5962306a36Sopenharmony_ci u32 color_map; 6062306a36Sopenharmony_ci u32 control; 6162306a36Sopenharmony_ci u32 cursor; 6262306a36Sopenharmony_ci}; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistruct bw2_regs { 6562306a36Sopenharmony_ci struct bt_regs cmap; 6662306a36Sopenharmony_ci u8 control; 6762306a36Sopenharmony_ci u8 status; 6862306a36Sopenharmony_ci u8 cursor_start; 6962306a36Sopenharmony_ci u8 cursor_end; 7062306a36Sopenharmony_ci u8 h_blank_start; 7162306a36Sopenharmony_ci u8 h_blank_end; 7262306a36Sopenharmony_ci u8 h_sync_start; 7362306a36Sopenharmony_ci u8 h_sync_end; 7462306a36Sopenharmony_ci u8 comp_sync_end; 7562306a36Sopenharmony_ci u8 v_blank_start_high; 7662306a36Sopenharmony_ci u8 v_blank_start_low; 7762306a36Sopenharmony_ci u8 v_blank_end; 7862306a36Sopenharmony_ci u8 v_sync_start; 7962306a36Sopenharmony_ci u8 v_sync_end; 8062306a36Sopenharmony_ci u8 xfer_holdoff_start; 8162306a36Sopenharmony_ci u8 xfer_holdoff_end; 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* Status Register Constants */ 8562306a36Sopenharmony_ci#define BWTWO_SR_RES_MASK 0x70 8662306a36Sopenharmony_ci#define BWTWO_SR_1600_1280 0x50 8762306a36Sopenharmony_ci#define BWTWO_SR_1152_900_76_A 0x40 8862306a36Sopenharmony_ci#define BWTWO_SR_1152_900_76_B 0x60 8962306a36Sopenharmony_ci#define BWTWO_SR_ID_MASK 0x0f 9062306a36Sopenharmony_ci#define BWTWO_SR_ID_MONO 0x02 9162306a36Sopenharmony_ci#define BWTWO_SR_ID_MONO_ECL 0x03 9262306a36Sopenharmony_ci#define BWTWO_SR_ID_MSYNC 0x04 9362306a36Sopenharmony_ci#define BWTWO_SR_ID_NOCONN 0x0a 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* Control Register Constants */ 9662306a36Sopenharmony_ci#define BWTWO_CTL_ENABLE_INTS 0x80 9762306a36Sopenharmony_ci#define BWTWO_CTL_ENABLE_VIDEO 0x40 9862306a36Sopenharmony_ci#define BWTWO_CTL_ENABLE_TIMING 0x20 9962306a36Sopenharmony_ci#define BWTWO_CTL_ENABLE_CURCMP 0x10 10062306a36Sopenharmony_ci#define BWTWO_CTL_XTAL_MASK 0x0C 10162306a36Sopenharmony_ci#define BWTWO_CTL_DIVISOR_MASK 0x03 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* Status Register Constants */ 10462306a36Sopenharmony_ci#define BWTWO_STAT_PENDING_INT 0x80 10562306a36Sopenharmony_ci#define BWTWO_STAT_MSENSE_MASK 0x70 10662306a36Sopenharmony_ci#define BWTWO_STAT_ID_MASK 0x0f 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistruct bw2_par { 10962306a36Sopenharmony_ci spinlock_t lock; 11062306a36Sopenharmony_ci struct bw2_regs __iomem *regs; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci u32 flags; 11362306a36Sopenharmony_ci#define BW2_FLAG_BLANKED 0x00000001 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci unsigned long which_io; 11662306a36Sopenharmony_ci}; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/** 11962306a36Sopenharmony_ci * bw2_blank - Optional function. Blanks the display. 12062306a36Sopenharmony_ci * @blank: the blank mode we want. 12162306a36Sopenharmony_ci * @info: frame buffer structure that represents a single frame buffer 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_cistatic int 12462306a36Sopenharmony_cibw2_blank(int blank, struct fb_info *info) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci struct bw2_par *par = (struct bw2_par *) info->par; 12762306a36Sopenharmony_ci struct bw2_regs __iomem *regs = par->regs; 12862306a36Sopenharmony_ci unsigned long flags; 12962306a36Sopenharmony_ci u8 val; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci spin_lock_irqsave(&par->lock, flags); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci switch (blank) { 13462306a36Sopenharmony_ci case FB_BLANK_UNBLANK: /* Unblanking */ 13562306a36Sopenharmony_ci val = sbus_readb(®s->control); 13662306a36Sopenharmony_ci val |= BWTWO_CTL_ENABLE_VIDEO; 13762306a36Sopenharmony_ci sbus_writeb(val, ®s->control); 13862306a36Sopenharmony_ci par->flags &= ~BW2_FLAG_BLANKED; 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci case FB_BLANK_NORMAL: /* Normal blanking */ 14262306a36Sopenharmony_ci case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ 14362306a36Sopenharmony_ci case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ 14462306a36Sopenharmony_ci case FB_BLANK_POWERDOWN: /* Poweroff */ 14562306a36Sopenharmony_ci val = sbus_readb(®s->control); 14662306a36Sopenharmony_ci val &= ~BWTWO_CTL_ENABLE_VIDEO; 14762306a36Sopenharmony_ci sbus_writeb(val, ®s->control); 14862306a36Sopenharmony_ci par->flags |= BW2_FLAG_BLANKED; 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci spin_unlock_irqrestore(&par->lock, flags); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci} 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistatic struct sbus_mmap_map bw2_mmap_map[] = { 15862306a36Sopenharmony_ci { 15962306a36Sopenharmony_ci .size = SBUS_MMAP_FBSIZE(1) 16062306a36Sopenharmony_ci }, 16162306a36Sopenharmony_ci { .size = 0 } 16262306a36Sopenharmony_ci}; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct bw2_par *par = (struct bw2_par *)info->par; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return sbusfb_mmap_helper(bw2_mmap_map, 16962306a36Sopenharmony_ci info->fix.smem_start, info->fix.smem_len, 17062306a36Sopenharmony_ci par->which_io, 17162306a36Sopenharmony_ci vma); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistatic int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci return sbusfb_ioctl_helper(cmd, arg, info, 17762306a36Sopenharmony_ci FBTYPE_SUN2BW, 1, info->fix.smem_len); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/* 18162306a36Sopenharmony_ci * Initialisation 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic void bw2_init_fix(struct fb_info *info, int linebytes) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci strscpy(info->fix.id, "bwtwo", sizeof(info->fix.id)); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci info->fix.type = FB_TYPE_PACKED_PIXELS; 18962306a36Sopenharmony_ci info->fix.visual = FB_VISUAL_MONO01; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci info->fix.line_length = linebytes; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci info->fix.accel = FB_ACCEL_SUN_BWTWO; 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic u8 bw2regs_1600[] = { 19762306a36Sopenharmony_ci 0x14, 0x8b, 0x15, 0x28, 0x16, 0x03, 0x17, 0x13, 19862306a36Sopenharmony_ci 0x18, 0x7b, 0x19, 0x05, 0x1a, 0x34, 0x1b, 0x2e, 19962306a36Sopenharmony_ci 0x1c, 0x00, 0x1d, 0x0a, 0x1e, 0xff, 0x1f, 0x01, 20062306a36Sopenharmony_ci 0x10, 0x21, 0 20162306a36Sopenharmony_ci}; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic u8 bw2regs_ecl[] = { 20462306a36Sopenharmony_ci 0x14, 0x65, 0x15, 0x1e, 0x16, 0x04, 0x17, 0x0c, 20562306a36Sopenharmony_ci 0x18, 0x5e, 0x19, 0x03, 0x1a, 0xa7, 0x1b, 0x23, 20662306a36Sopenharmony_ci 0x1c, 0x00, 0x1d, 0x08, 0x1e, 0xff, 0x1f, 0x01, 20762306a36Sopenharmony_ci 0x10, 0x20, 0 20862306a36Sopenharmony_ci}; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic u8 bw2regs_analog[] = { 21162306a36Sopenharmony_ci 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x03, 0x17, 0x13, 21262306a36Sopenharmony_ci 0x18, 0xb0, 0x19, 0x03, 0x1a, 0xa6, 0x1b, 0x22, 21362306a36Sopenharmony_ci 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, 21462306a36Sopenharmony_ci 0x10, 0x20, 0 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic u8 bw2regs_76hz[] = { 21862306a36Sopenharmony_ci 0x14, 0xb7, 0x15, 0x27, 0x16, 0x03, 0x17, 0x0f, 21962306a36Sopenharmony_ci 0x18, 0xae, 0x19, 0x03, 0x1a, 0xae, 0x1b, 0x2a, 22062306a36Sopenharmony_ci 0x1c, 0x01, 0x1d, 0x09, 0x1e, 0xff, 0x1f, 0x01, 22162306a36Sopenharmony_ci 0x10, 0x24, 0 22262306a36Sopenharmony_ci}; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_cistatic u8 bw2regs_66hz[] = { 22562306a36Sopenharmony_ci 0x14, 0xbb, 0x15, 0x2b, 0x16, 0x04, 0x17, 0x14, 22662306a36Sopenharmony_ci 0x18, 0xae, 0x19, 0x03, 0x1a, 0xa8, 0x1b, 0x24, 22762306a36Sopenharmony_ci 0x1c, 0x01, 0x1d, 0x05, 0x1e, 0xff, 0x1f, 0x01, 22862306a36Sopenharmony_ci 0x10, 0x20, 0 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic int bw2_do_default_mode(struct bw2_par *par, struct fb_info *info, 23262306a36Sopenharmony_ci int *linebytes) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci u8 status, mon; 23562306a36Sopenharmony_ci u8 *p; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci status = sbus_readb(&par->regs->status); 23862306a36Sopenharmony_ci mon = status & BWTWO_SR_RES_MASK; 23962306a36Sopenharmony_ci switch (status & BWTWO_SR_ID_MASK) { 24062306a36Sopenharmony_ci case BWTWO_SR_ID_MONO_ECL: 24162306a36Sopenharmony_ci if (mon == BWTWO_SR_1600_1280) { 24262306a36Sopenharmony_ci p = bw2regs_1600; 24362306a36Sopenharmony_ci info->var.xres = info->var.xres_virtual = 1600; 24462306a36Sopenharmony_ci info->var.yres = info->var.yres_virtual = 1280; 24562306a36Sopenharmony_ci *linebytes = 1600 / 8; 24662306a36Sopenharmony_ci } else 24762306a36Sopenharmony_ci p = bw2regs_ecl; 24862306a36Sopenharmony_ci break; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci case BWTWO_SR_ID_MONO: 25162306a36Sopenharmony_ci p = bw2regs_analog; 25262306a36Sopenharmony_ci break; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci case BWTWO_SR_ID_MSYNC: 25562306a36Sopenharmony_ci if (mon == BWTWO_SR_1152_900_76_A || 25662306a36Sopenharmony_ci mon == BWTWO_SR_1152_900_76_B) 25762306a36Sopenharmony_ci p = bw2regs_76hz; 25862306a36Sopenharmony_ci else 25962306a36Sopenharmony_ci p = bw2regs_66hz; 26062306a36Sopenharmony_ci break; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci case BWTWO_SR_ID_NOCONN: 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci default: 26662306a36Sopenharmony_ci printk(KERN_ERR "bw2: can't handle SR %02x\n", 26762306a36Sopenharmony_ci status); 26862306a36Sopenharmony_ci return -EINVAL; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci for ( ; *p; p += 2) { 27162306a36Sopenharmony_ci u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]]; 27262306a36Sopenharmony_ci sbus_writeb(p[1], regp); 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci return 0; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic int bw2_probe(struct platform_device *op) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct device_node *dp = op->dev.of_node; 28062306a36Sopenharmony_ci struct fb_info *info; 28162306a36Sopenharmony_ci struct bw2_par *par; 28262306a36Sopenharmony_ci int linebytes, err; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci err = -ENOMEM; 28762306a36Sopenharmony_ci if (!info) 28862306a36Sopenharmony_ci goto out_err; 28962306a36Sopenharmony_ci par = info->par; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci spin_lock_init(&par->lock); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci info->fix.smem_start = op->resource[0].start; 29462306a36Sopenharmony_ci par->which_io = op->resource[0].flags & IORESOURCE_BITS; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci sbusfb_fill_var(&info->var, dp, 1); 29762306a36Sopenharmony_ci linebytes = of_getintprop_default(dp, "linebytes", 29862306a36Sopenharmony_ci info->var.xres); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci info->var.red.length = info->var.green.length = 30162306a36Sopenharmony_ci info->var.blue.length = info->var.bits_per_pixel; 30262306a36Sopenharmony_ci info->var.red.offset = info->var.green.offset = 30362306a36Sopenharmony_ci info->var.blue.offset = 0; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET, 30662306a36Sopenharmony_ci sizeof(struct bw2_regs), "bw2 regs"); 30762306a36Sopenharmony_ci if (!par->regs) 30862306a36Sopenharmony_ci goto out_release_fb; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (!of_property_present(dp, "width")) { 31162306a36Sopenharmony_ci err = bw2_do_default_mode(par, info, &linebytes); 31262306a36Sopenharmony_ci if (err) 31362306a36Sopenharmony_ci goto out_unmap_regs; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci info->fbops = &bw2_ops; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci info->screen_base = of_ioremap(&op->resource[0], 0, 32162306a36Sopenharmony_ci info->fix.smem_len, "bw2 ram"); 32262306a36Sopenharmony_ci if (!info->screen_base) { 32362306a36Sopenharmony_ci err = -ENOMEM; 32462306a36Sopenharmony_ci goto out_unmap_regs; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci bw2_blank(FB_BLANK_UNBLANK, info); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci bw2_init_fix(info, linebytes); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci err = register_framebuffer(info); 33262306a36Sopenharmony_ci if (err < 0) 33362306a36Sopenharmony_ci goto out_unmap_screen; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci dev_set_drvdata(&op->dev, info); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci printk(KERN_INFO "%pOF: bwtwo at %lx:%lx\n", 33862306a36Sopenharmony_ci dp, par->which_io, info->fix.smem_start); 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci return 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ciout_unmap_screen: 34362306a36Sopenharmony_ci of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ciout_unmap_regs: 34662306a36Sopenharmony_ci of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ciout_release_fb: 34962306a36Sopenharmony_ci framebuffer_release(info); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ciout_err: 35262306a36Sopenharmony_ci return err; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic void bw2_remove(struct platform_device *op) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct fb_info *info = dev_get_drvdata(&op->dev); 35862306a36Sopenharmony_ci struct bw2_par *par = info->par; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci unregister_framebuffer(info); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); 36362306a36Sopenharmony_ci of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci framebuffer_release(info); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic const struct of_device_id bw2_match[] = { 36962306a36Sopenharmony_ci { 37062306a36Sopenharmony_ci .name = "bwtwo", 37162306a36Sopenharmony_ci }, 37262306a36Sopenharmony_ci {}, 37362306a36Sopenharmony_ci}; 37462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, bw2_match); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic struct platform_driver bw2_driver = { 37762306a36Sopenharmony_ci .driver = { 37862306a36Sopenharmony_ci .name = "bw2", 37962306a36Sopenharmony_ci .of_match_table = bw2_match, 38062306a36Sopenharmony_ci }, 38162306a36Sopenharmony_ci .probe = bw2_probe, 38262306a36Sopenharmony_ci .remove_new = bw2_remove, 38362306a36Sopenharmony_ci}; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_cistatic int __init bw2_init(void) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci if (fb_get_options("bw2fb", NULL)) 38862306a36Sopenharmony_ci return -ENODEV; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci return platform_driver_register(&bw2_driver); 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic void __exit bw2_exit(void) 39462306a36Sopenharmony_ci{ 39562306a36Sopenharmony_ci platform_driver_unregister(&bw2_driver); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cimodule_init(bw2_init); 39962306a36Sopenharmony_cimodule_exit(bw2_exit); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ciMODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets"); 40262306a36Sopenharmony_ciMODULE_AUTHOR("David S. Miller <davem@davemloft.net>"); 40362306a36Sopenharmony_ciMODULE_VERSION("2.0"); 40462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 405