brintos

brintos / linux-shallow public Read only

0
0
Text · 8.9 KiB · e757462 Raw
398 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* bw2.c: BWTWO frame buffer driver3 *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.h>21#include <linux/platform_device.h>22 23#include <asm/io.h>24#include <asm/fbio.h>25 26#include "sbuslib.h"27 28/*29 * Local functions.30 */31 32static int bw2_blank(int, struct fb_info *);33 34static int bw2_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma);35static int bw2_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);36 37/*38 *  Frame buffer operations39 */40 41static const struct fb_ops bw2_ops = {42	.owner			= THIS_MODULE,43	FB_DEFAULT_SBUS_OPS(bw2),44	.fb_blank		= bw2_blank,45};46 47/* OBio addresses for the bwtwo registers */48#define BWTWO_REGISTER_OFFSET 0x40000049 50struct bt_regs {51	u32 addr;52	u32 color_map;53	u32 control;54	u32 cursor;55};56 57struct bw2_regs {58	struct bt_regs	cmap;59	u8	control;60	u8	status;61	u8	cursor_start;62	u8	cursor_end;63	u8	h_blank_start;64	u8	h_blank_end;65	u8	h_sync_start;66	u8	h_sync_end;67	u8	comp_sync_end;68	u8	v_blank_start_high;69	u8	v_blank_start_low;70	u8	v_blank_end;71	u8	v_sync_start;72	u8	v_sync_end;73	u8	xfer_holdoff_start;74	u8	xfer_holdoff_end;75};76 77/* Status Register Constants */78#define BWTWO_SR_RES_MASK	0x7079#define BWTWO_SR_1600_1280	0x5080#define BWTWO_SR_1152_900_76_A	0x4081#define BWTWO_SR_1152_900_76_B	0x6082#define BWTWO_SR_ID_MASK	0x0f83#define BWTWO_SR_ID_MONO	0x0284#define BWTWO_SR_ID_MONO_ECL	0x0385#define BWTWO_SR_ID_MSYNC	0x0486#define BWTWO_SR_ID_NOCONN	0x0a87 88/* Control Register Constants */89#define BWTWO_CTL_ENABLE_INTS   0x8090#define BWTWO_CTL_ENABLE_VIDEO  0x4091#define BWTWO_CTL_ENABLE_TIMING 0x2092#define BWTWO_CTL_ENABLE_CURCMP 0x1093#define BWTWO_CTL_XTAL_MASK     0x0C94#define BWTWO_CTL_DIVISOR_MASK  0x0395 96/* Status Register Constants */97#define BWTWO_STAT_PENDING_INT  0x8098#define BWTWO_STAT_MSENSE_MASK  0x7099#define BWTWO_STAT_ID_MASK      0x0f100 101struct bw2_par {102	spinlock_t		lock;103	struct bw2_regs		__iomem *regs;104 105	u32			flags;106#define BW2_FLAG_BLANKED	0x00000001107 108	unsigned long		which_io;109};110 111/**112 *      bw2_blank - Optional function.  Blanks the display.113 *      @blank: the blank mode we want.114 *      @info: frame buffer structure that represents a single frame buffer115 */116static int117bw2_blank(int blank, struct fb_info *info)118{119	struct bw2_par *par = (struct bw2_par *) info->par;120	struct bw2_regs __iomem *regs = par->regs;121	unsigned long flags;122	u8 val;123 124	spin_lock_irqsave(&par->lock, flags);125 126	switch (blank) {127	case FB_BLANK_UNBLANK: /* Unblanking */128		val = sbus_readb(&regs->control);129		val |= BWTWO_CTL_ENABLE_VIDEO;130		sbus_writeb(val, &regs->control);131		par->flags &= ~BW2_FLAG_BLANKED;132		break;133 134	case FB_BLANK_NORMAL: /* Normal blanking */135	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */136	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */137	case FB_BLANK_POWERDOWN: /* Poweroff */138		val = sbus_readb(&regs->control);139		val &= ~BWTWO_CTL_ENABLE_VIDEO;140		sbus_writeb(val, &regs->control);141		par->flags |= BW2_FLAG_BLANKED;142		break;143	}144 145	spin_unlock_irqrestore(&par->lock, flags);146 147	return 0;148}149 150static const struct sbus_mmap_map bw2_mmap_map[] = {151	{152		.size = SBUS_MMAP_FBSIZE(1)153	},154	{ .size = 0 }155};156 157static int bw2_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma)158{159	struct bw2_par *par = (struct bw2_par *)info->par;160 161	return sbusfb_mmap_helper(bw2_mmap_map,162				  info->fix.smem_start, info->fix.smem_len,163				  par->which_io,164				  vma);165}166 167static int bw2_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)168{169	return sbusfb_ioctl_helper(cmd, arg, info,170				   FBTYPE_SUN2BW, 1, info->fix.smem_len);171}172 173/*174 *  Initialisation175 */176 177static void bw2_init_fix(struct fb_info *info, int linebytes)178{179	strscpy(info->fix.id, "bwtwo", sizeof(info->fix.id));180 181	info->fix.type = FB_TYPE_PACKED_PIXELS;182	info->fix.visual = FB_VISUAL_MONO01;183 184	info->fix.line_length = linebytes;185 186	info->fix.accel = FB_ACCEL_SUN_BWTWO;187}188 189static u8 bw2regs_1600[] = {190	0x14, 0x8b,	0x15, 0x28,	0x16, 0x03,	0x17, 0x13,191	0x18, 0x7b,	0x19, 0x05,	0x1a, 0x34,	0x1b, 0x2e,192	0x1c, 0x00,	0x1d, 0x0a,	0x1e, 0xff,	0x1f, 0x01,193	0x10, 0x21,	0194};195 196static u8 bw2regs_ecl[] = {197	0x14, 0x65,	0x15, 0x1e,	0x16, 0x04,	0x17, 0x0c,198	0x18, 0x5e,	0x19, 0x03,	0x1a, 0xa7,	0x1b, 0x23,199	0x1c, 0x00,	0x1d, 0x08,	0x1e, 0xff,	0x1f, 0x01,200	0x10, 0x20,	0201};202 203static u8 bw2regs_analog[] = {204	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x03,	0x17, 0x13,205	0x18, 0xb0,	0x19, 0x03,	0x1a, 0xa6,	0x1b, 0x22,206	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,207	0x10, 0x20,	0208};209 210static u8 bw2regs_76hz[] = {211	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,212	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,213	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,214	0x10, 0x24,	0215};216 217static u8 bw2regs_66hz[] = {218	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,219	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,220	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,221	0x10, 0x20,	0222};223 224static int bw2_do_default_mode(struct bw2_par *par, struct fb_info *info,225			       int *linebytes)226{227	u8 status, mon;228	u8 *p;229 230	status = sbus_readb(&par->regs->status);231	mon = status & BWTWO_SR_RES_MASK;232	switch (status & BWTWO_SR_ID_MASK) {233	case BWTWO_SR_ID_MONO_ECL:234		if (mon == BWTWO_SR_1600_1280) {235			p = bw2regs_1600;236			info->var.xres = info->var.xres_virtual = 1600;237			info->var.yres = info->var.yres_virtual = 1280;238			*linebytes = 1600 / 8;239		} else240			p = bw2regs_ecl;241		break;242 243	case BWTWO_SR_ID_MONO:244		p = bw2regs_analog;245		break;246 247	case BWTWO_SR_ID_MSYNC:248		if (mon == BWTWO_SR_1152_900_76_A ||249		    mon == BWTWO_SR_1152_900_76_B)250			p = bw2regs_76hz;251		else252			p = bw2regs_66hz;253		break;254 255	case BWTWO_SR_ID_NOCONN:256		return 0;257 258	default:259		printk(KERN_ERR "bw2: can't handle SR %02x\n",260		       status);261		return -EINVAL;262	}263	for ( ; *p; p += 2) {264		u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];265		sbus_writeb(p[1], regp);266	}267	return 0;268}269 270static int bw2_probe(struct platform_device *op)271{272	struct device_node *dp = op->dev.of_node;273	struct fb_info *info;274	struct bw2_par *par;275	int linebytes, err;276 277	info = framebuffer_alloc(sizeof(struct bw2_par), &op->dev);278 279	err = -ENOMEM;280	if (!info)281		goto out_err;282	par = info->par;283 284	spin_lock_init(&par->lock);285 286	info->fix.smem_start = op->resource[0].start;287	par->which_io = op->resource[0].flags & IORESOURCE_BITS;288 289	sbusfb_fill_var(&info->var, dp, 1);290	linebytes = of_getintprop_default(dp, "linebytes",291					  info->var.xres);292 293	info->var.red.length = info->var.green.length =294		info->var.blue.length = info->var.bits_per_pixel;295	info->var.red.offset = info->var.green.offset =296		info->var.blue.offset = 0;297 298	par->regs = of_ioremap(&op->resource[0], BWTWO_REGISTER_OFFSET,299			       sizeof(struct bw2_regs), "bw2 regs");300	if (!par->regs)301		goto out_release_fb;302 303	if (!of_property_present(dp, "width")) {304		err = bw2_do_default_mode(par, info, &linebytes);305		if (err)306			goto out_unmap_regs;307	}308 309	info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);310 311	info->fbops = &bw2_ops;312 313	info->screen_base = of_ioremap(&op->resource[0], 0,314				       info->fix.smem_len, "bw2 ram");315	if (!info->screen_base) {316		err = -ENOMEM;317		goto out_unmap_regs;318	}319 320	bw2_blank(FB_BLANK_UNBLANK, info);321 322	bw2_init_fix(info, linebytes);323 324	err = register_framebuffer(info);325	if (err < 0)326		goto out_unmap_screen;327 328	dev_set_drvdata(&op->dev, info);329 330	printk(KERN_INFO "%pOF: bwtwo at %lx:%lx\n",331	       dp, par->which_io, info->fix.smem_start);332 333	return 0;334 335out_unmap_screen:336	of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);337 338out_unmap_regs:339	of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));340 341out_release_fb:342	framebuffer_release(info);343 344out_err:345	return err;346}347 348static void bw2_remove(struct platform_device *op)349{350	struct fb_info *info = dev_get_drvdata(&op->dev);351	struct bw2_par *par = info->par;352 353	unregister_framebuffer(info);354 355	of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs));356	of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);357 358	framebuffer_release(info);359}360 361static const struct of_device_id bw2_match[] = {362	{363		.name = "bwtwo",364	},365	{},366};367MODULE_DEVICE_TABLE(of, bw2_match);368 369static struct platform_driver bw2_driver = {370	.driver = {371		.name = "bw2",372		.of_match_table = bw2_match,373	},374	.probe		= bw2_probe,375	.remove		= bw2_remove,376};377 378static int __init bw2_init(void)379{380	if (fb_get_options("bw2fb", NULL))381		return -ENODEV;382 383	return platform_driver_register(&bw2_driver);384}385 386static void __exit bw2_exit(void)387{388	platform_driver_unregister(&bw2_driver);389}390 391module_init(bw2_init);392module_exit(bw2_exit);393 394MODULE_DESCRIPTION("framebuffer driver for BWTWO chipsets");395MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");396MODULE_VERSION("2.0");397MODULE_LICENSE("GPL");398