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