brintos

brintos / linux-shallow public Read only

0
0
Text · 11.1 KiB · a58a483 Raw
484 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/* cg3.c: CGTHREE 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 cg3_setcolreg(unsigned, unsigned, unsigned, unsigned,33			 unsigned, struct fb_info *);34static int cg3_blank(int, struct fb_info *);35 36static int cg3_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma);37static int cg3_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);38 39/*40 *  Frame buffer operations41 */42 43static const struct fb_ops cg3_ops = {44	.owner			= THIS_MODULE,45	FB_DEFAULT_SBUS_OPS(cg3),46	.fb_setcolreg		= cg3_setcolreg,47	.fb_blank		= cg3_blank,48};49 50 51/* Control Register Constants */52#define CG3_CR_ENABLE_INTS      0x8053#define CG3_CR_ENABLE_VIDEO     0x4054#define CG3_CR_ENABLE_TIMING    0x2055#define CG3_CR_ENABLE_CURCMP    0x1056#define CG3_CR_XTAL_MASK        0x0c57#define CG3_CR_DIVISOR_MASK     0x0358 59/* Status Register Constants */60#define CG3_SR_PENDING_INT      0x8061#define CG3_SR_RES_MASK         0x7062#define CG3_SR_1152_900_76_A    0x4063#define CG3_SR_1152_900_76_B    0x6064#define CG3_SR_ID_MASK          0x0f65#define CG3_SR_ID_COLOR         0x0166#define CG3_SR_ID_MONO          0x0267#define CG3_SR_ID_MONO_ECL      0x0368 69enum cg3_type {70	CG3_AT_66HZ = 0,71	CG3_AT_76HZ,72	CG3_RDI73};74 75struct bt_regs {76	u32 addr;77	u32 color_map;78	u32 control;79	u32 cursor;80};81 82struct cg3_regs {83	struct bt_regs	cmap;84	u8	control;85	u8	status;86	u8	cursor_start;87	u8	cursor_end;88	u8	h_blank_start;89	u8	h_blank_end;90	u8	h_sync_start;91	u8	h_sync_end;92	u8	comp_sync_end;93	u8	v_blank_start_high;94	u8	v_blank_start_low;95	u8	v_blank_end;96	u8	v_sync_start;97	u8	v_sync_end;98	u8	xfer_holdoff_start;99	u8	xfer_holdoff_end;100};101 102/* Offset of interesting structures in the OBIO space */103#define CG3_REGS_OFFSET	     0x400000UL104#define CG3_RAM_OFFSET	     0x800000UL105 106struct cg3_par {107	spinlock_t		lock;108	struct cg3_regs		__iomem *regs;109	u32			sw_cmap[((256 * 3) + 3) / 4];110 111	u32			flags;112#define CG3_FLAG_BLANKED	0x00000001113#define CG3_FLAG_RDI		0x00000002114 115	unsigned long		which_io;116};117 118/**119 *      cg3_setcolreg - Optional function. Sets a color register.120 *      @regno: boolean, 0 copy local, 1 get_user() function121 *      @red: frame buffer colormap structure122 *      @green: The green value which can be up to 16 bits wide123 *      @blue:  The blue value which can be up to 16 bits wide.124 *      @transp: If supported the alpha value which can be up to 16 bits wide.125 *      @info: frame buffer info structure126 *127 * The cg3 palette is loaded with 4 color values at each time128 * so you end up with: (rgb)(r), (gb)(rg), (b)(rgb), and so on.129 * We keep a sw copy of the hw cmap to assist us in this esoteric130 * loading procedure.131 */132static int cg3_setcolreg(unsigned regno,133			 unsigned red, unsigned green, unsigned blue,134			 unsigned transp, struct fb_info *info)135{136	struct cg3_par *par = (struct cg3_par *) info->par;137	struct bt_regs __iomem *bt = &par->regs->cmap;138	unsigned long flags;139	u32 *p32;140	u8 *p8;141	int count;142 143	if (regno >= 256)144		return 1;145 146	red >>= 8;147	green >>= 8;148	blue >>= 8;149 150	spin_lock_irqsave(&par->lock, flags);151 152	p8 = (u8 *)par->sw_cmap + (regno * 3);153	p8[0] = red;154	p8[1] = green;155	p8[2] = blue;156 157#define D4M3(x) ((((x)>>2)<<1) + ((x)>>2))      /* (x/4)*3 */158#define D4M4(x) ((x)&~0x3)                      /* (x/4)*4 */159 160	count = 3;161	p32 = &par->sw_cmap[D4M3(regno)];162	sbus_writel(D4M4(regno), &bt->addr);163	while (count--)164		sbus_writel(*p32++, &bt->color_map);165 166#undef D4M3167#undef D4M4168 169	spin_unlock_irqrestore(&par->lock, flags);170 171	return 0;172}173 174/**175 *      cg3_blank - Optional function.  Blanks the display.176 *      @blank: the blank mode we want.177 *      @info: frame buffer structure that represents a single frame buffer178 */179static int cg3_blank(int blank, struct fb_info *info)180{181	struct cg3_par *par = (struct cg3_par *) info->par;182	struct cg3_regs __iomem *regs = par->regs;183	unsigned long flags;184	u8 val;185 186	spin_lock_irqsave(&par->lock, flags);187 188	switch (blank) {189	case FB_BLANK_UNBLANK: /* Unblanking */190		val = sbus_readb(&regs->control);191		val |= CG3_CR_ENABLE_VIDEO;192		sbus_writeb(val, &regs->control);193		par->flags &= ~CG3_FLAG_BLANKED;194		break;195 196	case FB_BLANK_NORMAL: /* Normal blanking */197	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */198	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */199	case FB_BLANK_POWERDOWN: /* Poweroff */200		val = sbus_readb(&regs->control);201		val &= ~CG3_CR_ENABLE_VIDEO;202		sbus_writeb(val, &regs->control);203		par->flags |= CG3_FLAG_BLANKED;204		break;205	}206 207	spin_unlock_irqrestore(&par->lock, flags);208 209	return 0;210}211 212static const struct sbus_mmap_map cg3_mmap_map[] = {213	{214		.voff	= CG3_MMAP_OFFSET,215		.poff	= CG3_RAM_OFFSET,216		.size	= SBUS_MMAP_FBSIZE(1)217	},218	{ .size = 0 }219};220 221static int cg3_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma)222{223	struct cg3_par *par = (struct cg3_par *)info->par;224 225	return sbusfb_mmap_helper(cg3_mmap_map,226				  info->fix.smem_start, info->fix.smem_len,227				  par->which_io,228				  vma);229}230 231static int cg3_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)232{233	return sbusfb_ioctl_helper(cmd, arg, info,234				   FBTYPE_SUN3COLOR, 8, info->fix.smem_len);235}236 237/*238 *  Initialisation239 */240 241static void cg3_init_fix(struct fb_info *info, int linebytes,242			 struct device_node *dp)243{244	snprintf(info->fix.id, sizeof(info->fix.id), "%pOFn", dp);245 246	info->fix.type = FB_TYPE_PACKED_PIXELS;247	info->fix.visual = FB_VISUAL_PSEUDOCOLOR;248 249	info->fix.line_length = linebytes;250 251	info->fix.accel = FB_ACCEL_SUN_CGTHREE;252}253 254static void cg3_rdi_maybe_fixup_var(struct fb_var_screeninfo *var,255				    struct device_node *dp)256{257	const char *params;258	char *p;259	int ww, hh;260 261	params = of_get_property(dp, "params", NULL);262	if (params) {263		ww = simple_strtoul(params, &p, 10);264		if (ww && *p == 'x') {265			hh = simple_strtoul(p + 1, &p, 10);266			if (hh && *p == '-') {267				if (var->xres != ww ||268				    var->yres != hh) {269					var->xres = var->xres_virtual = ww;270					var->yres = var->yres_virtual = hh;271				}272			}273		}274	}275}276 277static u8 cg3regvals_66hz[] = {	/* 1152 x 900, 66 Hz */278	0x14, 0xbb,	0x15, 0x2b,	0x16, 0x04,	0x17, 0x14,279	0x18, 0xae,	0x19, 0x03,	0x1a, 0xa8,	0x1b, 0x24,280	0x1c, 0x01,	0x1d, 0x05,	0x1e, 0xff,	0x1f, 0x01,281	0x10, 0x20,	0282};283 284static u8 cg3regvals_76hz[] = {	/* 1152 x 900, 76 Hz */285	0x14, 0xb7,	0x15, 0x27,	0x16, 0x03,	0x17, 0x0f,286	0x18, 0xae,	0x19, 0x03,	0x1a, 0xae,	0x1b, 0x2a,287	0x1c, 0x01,	0x1d, 0x09,	0x1e, 0xff,	0x1f, 0x01,288	0x10, 0x24,	0289};290 291static u8 cg3regvals_rdi[] = {	/* 640 x 480, cgRDI */292	0x14, 0x70,	0x15, 0x20,	0x16, 0x08,	0x17, 0x10,293	0x18, 0x06,	0x19, 0x02,	0x1a, 0x31,	0x1b, 0x51,294	0x1c, 0x06,	0x1d, 0x0c,	0x1e, 0xff,	0x1f, 0x01,295	0x10, 0x22,	0296};297 298static u8 *cg3_regvals[] = {299	cg3regvals_66hz, cg3regvals_76hz, cg3regvals_rdi300};301 302static u_char cg3_dacvals[] = {303	4, 0xff,	5, 0x00,	6, 0x70,	7, 0x00,	0304};305 306static int cg3_do_default_mode(struct cg3_par *par)307{308	enum cg3_type type;309	u8 *p;310 311	if (par->flags & CG3_FLAG_RDI)312		type = CG3_RDI;313	else {314		u8 status = sbus_readb(&par->regs->status), mon;315		if ((status & CG3_SR_ID_MASK) == CG3_SR_ID_COLOR) {316			mon = status & CG3_SR_RES_MASK;317			if (mon == CG3_SR_1152_900_76_A ||318			    mon == CG3_SR_1152_900_76_B)319				type = CG3_AT_76HZ;320			else321				type = CG3_AT_66HZ;322		} else {323			printk(KERN_ERR "cgthree: can't handle SR %02x\n",324			       status);325			return -EINVAL;326		}327	}328 329	for (p = cg3_regvals[type]; *p; p += 2) {330		u8 __iomem *regp = &((u8 __iomem *)par->regs)[p[0]];331		sbus_writeb(p[1], regp);332	}333	for (p = cg3_dacvals; *p; p += 2) {334		u8 __iomem *regp;335 336		regp = (u8 __iomem *)&par->regs->cmap.addr;337		sbus_writeb(p[0], regp);338		regp = (u8 __iomem *)&par->regs->cmap.control;339		sbus_writeb(p[1], regp);340	}341	return 0;342}343 344static int cg3_probe(struct platform_device *op)345{346	struct device_node *dp = op->dev.of_node;347	struct fb_info *info;348	struct cg3_par *par;349	int linebytes, err;350 351	info = framebuffer_alloc(sizeof(struct cg3_par), &op->dev);352 353	err = -ENOMEM;354	if (!info)355		goto out_err;356	par = info->par;357 358	spin_lock_init(&par->lock);359 360	info->fix.smem_start = op->resource[0].start;361	par->which_io = op->resource[0].flags & IORESOURCE_BITS;362 363	sbusfb_fill_var(&info->var, dp, 8);364	info->var.red.length = 8;365	info->var.green.length = 8;366	info->var.blue.length = 8;367	if (of_node_name_eq(dp, "cgRDI"))368		par->flags |= CG3_FLAG_RDI;369	if (par->flags & CG3_FLAG_RDI)370		cg3_rdi_maybe_fixup_var(&info->var, dp);371 372	linebytes = of_getintprop_default(dp, "linebytes",373					  info->var.xres);374	info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres);375 376	par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET,377			       sizeof(struct cg3_regs), "cg3 regs");378	if (!par->regs)379		goto out_release_fb;380 381	info->fbops = &cg3_ops;382	info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET,383				       info->fix.smem_len, "cg3 ram");384	if (!info->screen_base)385		goto out_unmap_regs;386 387	cg3_blank(FB_BLANK_UNBLANK, info);388 389	if (!of_property_present(dp, "width")) {390		err = cg3_do_default_mode(par);391		if (err)392			goto out_unmap_screen;393	}394 395	err = fb_alloc_cmap(&info->cmap, 256, 0);396	if (err)397		goto out_unmap_screen;398 399	fb_set_cmap(&info->cmap, info);400 401	cg3_init_fix(info, linebytes, dp);402 403	err = register_framebuffer(info);404	if (err < 0)405		goto out_dealloc_cmap;406 407	dev_set_drvdata(&op->dev, info);408 409	printk(KERN_INFO "%pOF: cg3 at %lx:%lx\n",410	       dp, par->which_io, info->fix.smem_start);411 412	return 0;413 414out_dealloc_cmap:415	fb_dealloc_cmap(&info->cmap);416 417out_unmap_screen:418	of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);419 420out_unmap_regs:421	of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));422 423out_release_fb:424	framebuffer_release(info);425 426out_err:427	return err;428}429 430static void cg3_remove(struct platform_device *op)431{432	struct fb_info *info = dev_get_drvdata(&op->dev);433	struct cg3_par *par = info->par;434 435	unregister_framebuffer(info);436	fb_dealloc_cmap(&info->cmap);437 438	of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs));439	of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len);440 441	framebuffer_release(info);442}443 444static const struct of_device_id cg3_match[] = {445	{446		.name = "cgthree",447	},448	{449		.name = "cgRDI",450	},451	{},452};453MODULE_DEVICE_TABLE(of, cg3_match);454 455static struct platform_driver cg3_driver = {456	.driver = {457		.name = "cg3",458		.of_match_table = cg3_match,459	},460	.probe		= cg3_probe,461	.remove		= cg3_remove,462};463 464static int __init cg3_init(void)465{466	if (fb_get_options("cg3fb", NULL))467		return -ENODEV;468 469	return platform_driver_register(&cg3_driver);470}471 472static void __exit cg3_exit(void)473{474	platform_driver_unregister(&cg3_driver);475}476 477module_init(cg3_init);478module_exit(cg3_exit);479 480MODULE_DESCRIPTION("framebuffer driver for CGthree chipsets");481MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");482MODULE_VERSION("2.0");483MODULE_LICENSE("GPL");484