File Index
Files and directories
Sign in
FILE

ffb.c

File preview with syntax highlighting.

linux-6.19.14/drivers/video/fbdev/ffb.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/* ffb.c: Creator/Elite3D frame buffer driver
   3 *
   4 * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
   5 * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
   6 *
   7 * Driver layout based loosely on tgafb.c, see that file for credits.
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/kernel.h>
  12#include <linux/errno.h>
  13#include <linux/string.h>
  14#include <linux/delay.h>
  15#include <linux/init.h>
  16#include <linux/fb.h>
  17#include <linux/mm.h>
  18#include <linux/timer.h>
  19#include <linux/of.h>
  20#include <linux/platform_device.h>
  21
  22#include <asm/io.h>
  23#include <asm/upa.h>
  24#include <asm/fbio.h>
  25
  26#include "sbuslib.h"
  27
  28/*
  29 * Local functions.
  30 */
  31
  32static int ffb_setcolreg(unsigned, unsigned, unsigned, unsigned,
  33			 unsigned, struct fb_info *);
  34static int ffb_blank(int, struct fb_info *);
  35
  36static void ffb_imageblit(struct fb_info *, const struct fb_image *);
  37static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *);
  38static void ffb_copyarea(struct fb_info *, const struct fb_copyarea *);
  39static int ffb_sync(struct fb_info *);
  40static int ffb_pan_display(struct fb_var_screeninfo *, struct fb_info *);
  41
  42static int ffb_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
  43static int ffb_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg);
  44
  45/*
  46 *  Frame buffer operations
  47 */
  48
  49static const struct fb_ops ffb_ops = {
  50	.owner			= THIS_MODULE,
  51	__FB_DEFAULT_SBUS_OPS_RDWR(ffb),
  52	.fb_setcolreg		= ffb_setcolreg,
  53	.fb_blank		= ffb_blank,
  54	.fb_pan_display		= ffb_pan_display,
  55	.fb_fillrect		= ffb_fillrect,
  56	.fb_copyarea		= ffb_copyarea,
  57	.fb_imageblit		= ffb_imageblit,
  58	.fb_sync		= ffb_sync,
  59	__FB_DEFAULT_SBUS_OPS_IOCTL(ffb),
  60	__FB_DEFAULT_SBUS_OPS_MMAP(ffb),
  61};
  62
  63/* Register layout and definitions */
  64#define	FFB_SFB8R_VOFF		0x00000000
  65#define	FFB_SFB8G_VOFF		0x00400000
  66#define	FFB_SFB8B_VOFF		0x00800000
  67#define	FFB_SFB8X_VOFF		0x00c00000
  68#define	FFB_SFB32_VOFF		0x01000000
  69#define	FFB_SFB64_VOFF		0x02000000
  70#define	FFB_FBC_REGS_VOFF	0x04000000
  71#define	FFB_BM_FBC_REGS_VOFF	0x04002000
  72#define	FFB_DFB8R_VOFF		0x04004000
  73#define	FFB_DFB8G_VOFF		0x04404000
  74#define	FFB_DFB8B_VOFF		0x04804000
  75#define	FFB_DFB8X_VOFF		0x04c04000
  76#define	FFB_DFB24_VOFF		0x05004000
  77#define	FFB_DFB32_VOFF		0x06004000
  78#define	FFB_DFB422A_VOFF	0x07004000	/* DFB 422 mode write to A */
  79#define	FFB_DFB422AD_VOFF	0x07804000	/* DFB 422 mode with line doubling */
  80#define	FFB_DFB24B_VOFF		0x08004000	/* DFB 24bit mode write to B */
  81#define	FFB_DFB422B_VOFF	0x09004000	/* DFB 422 mode write to B */
  82#define	FFB_DFB422BD_VOFF	0x09804000	/* DFB 422 mode with line doubling */
  83#define	FFB_SFB16Z_VOFF		0x0a004000	/* 16bit mode Z planes */
  84#define	FFB_SFB8Z_VOFF		0x0a404000	/* 8bit mode Z planes */
  85#define	FFB_SFB422_VOFF		0x0ac04000	/* SFB 422 mode write to A/B */
  86#define	FFB_SFB422D_VOFF	0x0b404000	/* SFB 422 mode with line doubling */
  87#define	FFB_FBC_KREGS_VOFF	0x0bc04000
  88#define	FFB_DAC_VOFF		0x0bc06000
  89#define	FFB_PROM_VOFF		0x0bc08000
  90#define	FFB_EXP_VOFF		0x0bc18000
  91
  92#define	FFB_SFB8R_POFF		0x04000000UL
  93#define	FFB_SFB8G_POFF		0x04400000UL
  94#define	FFB_SFB8B_POFF		0x04800000UL
  95#define	FFB_SFB8X_POFF		0x04c00000UL
  96#define	FFB_SFB32_POFF		0x05000000UL
  97#define	FFB_SFB64_POFF		0x06000000UL
  98#define	FFB_FBC_REGS_POFF	0x00600000UL
  99#define	FFB_BM_FBC_REGS_POFF	0x00600000UL
 100#define	FFB_DFB8R_POFF		0x01000000UL
 101#define	FFB_DFB8G_POFF		0x01400000UL
 102#define	FFB_DFB8B_POFF		0x01800000UL
 103#define	FFB_DFB8X_POFF		0x01c00000UL
 104#define	FFB_DFB24_POFF		0x02000000UL
 105#define	FFB_DFB32_POFF		0x03000000UL
 106#define	FFB_FBC_KREGS_POFF	0x00610000UL
 107#define	FFB_DAC_POFF		0x00400000UL
 108#define	FFB_PROM_POFF		0x00000000UL
 109#define	FFB_EXP_POFF		0x00200000UL
 110#define FFB_DFB422A_POFF	0x09000000UL
 111#define FFB_DFB422AD_POFF	0x09800000UL
 112#define FFB_DFB24B_POFF		0x0a000000UL
 113#define FFB_DFB422B_POFF	0x0b000000UL
 114#define FFB_DFB422BD_POFF	0x0b800000UL
 115#define FFB_SFB16Z_POFF		0x0c800000UL
 116#define FFB_SFB8Z_POFF		0x0c000000UL
 117#define FFB_SFB422_POFF		0x0d000000UL
 118#define FFB_SFB422D_POFF	0x0d800000UL
 119
 120/* Draw operations */
 121#define FFB_DRAWOP_DOT		0x00
 122#define FFB_DRAWOP_AADOT	0x01
 123#define FFB_DRAWOP_BRLINECAP	0x02
 124#define FFB_DRAWOP_BRLINEOPEN	0x03
 125#define FFB_DRAWOP_DDLINE	0x04
 126#define FFB_DRAWOP_AALINE	0x05
 127#define FFB_DRAWOP_TRIANGLE	0x06
 128#define FFB_DRAWOP_POLYGON	0x07
 129#define FFB_DRAWOP_RECTANGLE	0x08
 130#define FFB_DRAWOP_FASTFILL	0x09
 131#define FFB_DRAWOP_BCOPY	0x0a
 132#define FFB_DRAWOP_VSCROLL	0x0b
 133
 134/* Pixel processor control */
 135/* Force WID */
 136#define FFB_PPC_FW_DISABLE	0x800000
 137#define FFB_PPC_FW_ENABLE	0xc00000
 138/* Auxiliary clip */
 139#define FFB_PPC_ACE_DISABLE	0x040000
 140#define FFB_PPC_ACE_AUX_SUB	0x080000
 141#define FFB_PPC_ACE_AUX_ADD	0x0c0000
 142/* Depth cue */
 143#define FFB_PPC_DCE_DISABLE	0x020000
 144#define FFB_PPC_DCE_ENABLE	0x030000
 145/* Alpha blend */
 146#define FFB_PPC_ABE_DISABLE	0x008000
 147#define FFB_PPC_ABE_ENABLE	0x00c000
 148/* View clip */
 149#define FFB_PPC_VCE_DISABLE	0x001000
 150#define FFB_PPC_VCE_2D		0x002000
 151#define FFB_PPC_VCE_3D		0x003000
 152/* Area pattern */
 153#define FFB_PPC_APE_DISABLE	0x000800
 154#define FFB_PPC_APE_ENABLE	0x000c00
 155/* Transparent background */
 156#define FFB_PPC_TBE_OPAQUE	0x000200
 157#define FFB_PPC_TBE_TRANSPARENT	0x000300
 158/* Z source */
 159#define FFB_PPC_ZS_VAR		0x000080
 160#define FFB_PPC_ZS_CONST	0x0000c0
 161/* Y source */
 162#define FFB_PPC_YS_VAR		0x000020
 163#define FFB_PPC_YS_CONST	0x000030
 164/* X source */
 165#define FFB_PPC_XS_WID		0x000004
 166#define FFB_PPC_XS_VAR		0x000008
 167#define FFB_PPC_XS_CONST	0x00000c
 168/* Color (BGR) source */
 169#define FFB_PPC_CS_VAR		0x000002
 170#define FFB_PPC_CS_CONST	0x000003
 171
 172#define FFB_ROP_NEW		0x83
 173#define FFB_ROP_OLD		0x85
 174#define FFB_ROP_NEW_XOR_OLD	0x86
 175
 176#define FFB_UCSR_FIFO_MASK	0x00000fff
 177#define FFB_UCSR_FB_BUSY	0x01000000
 178#define FFB_UCSR_RP_BUSY	0x02000000
 179#define FFB_UCSR_ALL_BUSY	(FFB_UCSR_RP_BUSY|FFB_UCSR_FB_BUSY)
 180#define FFB_UCSR_READ_ERR	0x40000000
 181#define FFB_UCSR_FIFO_OVFL	0x80000000
 182#define FFB_UCSR_ALL_ERRORS	(FFB_UCSR_READ_ERR|FFB_UCSR_FIFO_OVFL)
 183
 184struct ffb_fbc {
 185	/* Next vertex registers */
 186	u32	xxx1[3];
 187	u32	alpha;
 188	u32	red;
 189	u32	green;
 190	u32	blue;
 191	u32	depth;
 192	u32	y;
 193	u32	x;
 194	u32	xxx2[2];
 195	u32	ryf;
 196	u32	rxf;
 197	u32	xxx3[2];
 198
 199	u32	dmyf;
 200	u32	dmxf;
 201	u32	xxx4[2];
 202	u32	ebyi;
 203	u32	ebxi;
 204	u32	xxx5[2];
 205	u32	by;
 206	u32	bx;
 207	u32	dy;
 208	u32	dx;
 209	u32	bh;
 210	u32	bw;
 211	u32	xxx6[2];
 212
 213	u32	xxx7[32];
 214
 215	/* Setup unit vertex state register */
 216	u32	suvtx;
 217	u32	xxx8[63];
 218
 219	/* Control registers */
 220	u32	ppc;
 221	u32	wid;
 222	u32	fg;
 223	u32	bg;
 224	u32	consty;
 225	u32	constz;
 226	u32	xclip;
 227	u32	dcss;
 228	u32	vclipmin;
 229	u32	vclipmax;
 230	u32	vclipzmin;
 231	u32	vclipzmax;
 232	u32	dcsf;
 233	u32	dcsb;
 234	u32	dczf;
 235	u32	dczb;
 236
 237	u32	xxx9;
 238	u32	blendc;
 239	u32	blendc1;
 240	u32	blendc2;
 241	u32	fbramitc;
 242	u32	fbc;
 243	u32	rop;
 244	u32	cmp;
 245	u32	matchab;
 246	u32	matchc;
 247	u32	magnab;
 248	u32	magnc;
 249	u32	fbcfg0;
 250	u32	fbcfg1;
 251	u32	fbcfg2;
 252	u32	fbcfg3;
 253
 254	u32	ppcfg;
 255	u32	pick;
 256	u32	fillmode;
 257	u32	fbramwac;
 258	u32	pmask;
 259	u32	xpmask;
 260	u32	ypmask;
 261	u32	zpmask;
 262	u32	clip0min;
 263	u32	clip0max;
 264	u32	clip1min;
 265	u32	clip1max;
 266	u32	clip2min;
 267	u32	clip2max;
 268	u32	clip3min;
 269	u32	clip3max;
 270
 271	/* New 3dRAM III support regs */
 272	u32	rawblend2;
 273	u32	rawpreblend;
 274	u32	rawstencil;
 275	u32	rawstencilctl;
 276	u32	threedram1;
 277	u32	threedram2;
 278	u32	passin;
 279	u32	rawclrdepth;
 280	u32	rawpmask;
 281	u32	rawcsrc;
 282	u32	rawmatch;
 283	u32	rawmagn;
 284	u32	rawropblend;
 285	u32	rawcmp;
 286	u32	rawwac;
 287	u32	fbramid;
 288
 289	u32	drawop;
 290	u32	xxx10[2];
 291	u32	fontlpat;
 292	u32	xxx11;
 293	u32	fontxy;
 294	u32	fontw;
 295	u32	fontinc;
 296	u32	font;
 297	u32	xxx12[3];
 298	u32	blend2;
 299	u32	preblend;
 300	u32	stencil;
 301	u32	stencilctl;
 302
 303	u32	xxx13[4];
 304	u32	dcss1;
 305	u32	dcss2;
 306	u32	dcss3;
 307	u32	widpmask;
 308	u32	dcs2;
 309	u32	dcs3;
 310	u32	dcs4;
 311	u32	xxx14;
 312	u32	dcd2;
 313	u32	dcd3;
 314	u32	dcd4;
 315	u32	xxx15;
 316
 317	u32	pattern[32];
 318
 319	u32	xxx16[256];
 320
 321	u32	devid;
 322	u32	xxx17[63];
 323
 324	u32	ucsr;
 325	u32	xxx18[31];
 326
 327	u32	mer;
 328};
 329
 330struct ffb_dac {
 331	u32	type;
 332	u32	value;
 333	u32	type2;
 334	u32	value2;
 335};
 336
 337#define FFB_DAC_UCTRL		0x1001 /* User Control */
 338#define FFB_DAC_UCTRL_OVENAB	0x00000008 /* Overlay Enable */
 339#define FFB_DAC_UCTRL_WMODE	0x00000030 /* Window Mode */
 340#define FFB_DAC_UCTRL_WM_COMB	0x00000000 /* Window Mode = Combined */
 341#define FFB_DAC_UCTRL_MANREV	0x00000f00 /* 4-bit Manufacturing Revision */
 342#define FFB_DAC_UCTRL_MANREV_SHIFT 8
 343#define FFB_DAC_TGEN		0x6000 /* Timing Generator */
 344#define FFB_DAC_TGEN_VIDE	0x00000001 /* Video Enable */
 345#define FFB_DAC_DID		0x8000 /* Device Identification */
 346#define FFB_DAC_DID_PNUM	0x0ffff000 /* Device Part Number */
 347#define FFB_DAC_DID_PNUM_SHIFT	12
 348#define FFB_DAC_DID_REV		0xf0000000 /* Device Revision */
 349#define FFB_DAC_DID_REV_SHIFT	28
 350
 351#define FFB_DAC_CUR_CTRL	0x100
 352#define FFB_DAC_CUR_CTRL_P0	0x00000001
 353#define FFB_DAC_CUR_CTRL_P1	0x00000002
 354
 355struct ffb_par {
 356	spinlock_t		lock;
 357	struct ffb_fbc __iomem	*fbc;
 358	struct ffb_dac __iomem	*dac;
 359
 360	u32			flags;
 361#define FFB_FLAG_AFB		0x00000001 /* AFB m3 or m6 */
 362#define FFB_FLAG_BLANKED	0x00000002 /* screen is blanked */
 363#define FFB_FLAG_INVCURSOR	0x00000004 /* DAC has inverted cursor logic */
 364
 365	u32			fg_cache __attribute__((aligned (8)));
 366	u32			bg_cache;
 367	u32			rop_cache;
 368
 369	int			fifo_cache;
 370
 371	unsigned long		physbase;
 372	unsigned long		fbsize;
 373
 374	int			board_type;
 375
 376	u32			pseudo_palette[16];
 377};
 378
 379static void FFBFifo(struct ffb_par *par, int n)
 380{
 381	struct ffb_fbc __iomem *fbc;
 382	int cache = par->fifo_cache;
 383
 384	if (cache - n < 0) {
 385		fbc = par->fbc;
 386		do {
 387			cache = (upa_readl(&fbc->ucsr) & FFB_UCSR_FIFO_MASK);
 388			cache -= 8;
 389		} while (cache - n < 0);
 390	}
 391	par->fifo_cache = cache - n;
 392}
 393
 394static void FFBWait(struct ffb_par *par)
 395{
 396	struct ffb_fbc __iomem *fbc;
 397	int limit = 10000;
 398
 399	fbc = par->fbc;
 400	do {
 401		if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_BUSY) == 0)
 402			break;
 403		if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0) {
 404			upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
 405		}
 406		udelay(10);
 407	} while (--limit > 0);
 408}
 409
 410static int ffb_sync(struct fb_info *p)
 411{
 412	struct ffb_par *par = (struct ffb_par *)p->par;
 413
 414	FFBWait(par);
 415	return 0;
 416}
 417
 418static __inline__ void ffb_rop(struct ffb_par *par, u32 rop)
 419{
 420	if (par->rop_cache != rop) {
 421		FFBFifo(par, 1);
 422		upa_writel(rop, &par->fbc->rop);
 423		par->rop_cache = rop;
 424	}
 425}
 426
 427static void ffb_switch_from_graph(struct ffb_par *par)
 428{
 429	struct ffb_fbc __iomem *fbc = par->fbc;
 430	struct ffb_dac __iomem *dac = par->dac;
 431	unsigned long flags, uctrl;
 432
 433	spin_lock_irqsave(&par->lock, flags);
 434	FFBWait(par);
 435	par->fifo_cache = 0;
 436	FFBFifo(par, 7);
 437	upa_writel(FFB_PPC_VCE_DISABLE | FFB_PPC_TBE_OPAQUE |
 438		   FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST,
 439		   &fbc->ppc);
 440	upa_writel(0x2000707f, &fbc->fbc);
 441	upa_writel(par->rop_cache, &fbc->rop);
 442	upa_writel(0xffffffff, &fbc->pmask);
 443	upa_writel((1 << 16) | (0 << 0), &fbc->fontinc);
 444	upa_writel(par->fg_cache, &fbc->fg);
 445	upa_writel(par->bg_cache, &fbc->bg);
 446	FFBWait(par);
 447
 448	/* Disable cursor.  */
 449	upa_writel(FFB_DAC_CUR_CTRL, &dac->type2);
 450	if (par->flags & FFB_FLAG_INVCURSOR)
 451		upa_writel(0, &dac->value2);
 452	else
 453		upa_writel((FFB_DAC_CUR_CTRL_P0 |
 454			    FFB_DAC_CUR_CTRL_P1), &dac->value2);
 455
 456	/* Disable overlay and window modes. */
 457	upa_writel(FFB_DAC_UCTRL, &dac->type);
 458	uctrl = upa_readl(&dac->value);
 459	uctrl &= ~FFB_DAC_UCTRL_WMODE;
 460	uctrl |= FFB_DAC_UCTRL_WM_COMB;
 461	uctrl &= ~FFB_DAC_UCTRL_OVENAB;
 462	upa_writel(FFB_DAC_UCTRL, &dac->type);
 463	upa_writel(uctrl, &dac->value);
 464
 465	spin_unlock_irqrestore(&par->lock, flags);
 466}
 467
 468static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 469{
 470	struct ffb_par *par = (struct ffb_par *)info->par;
 471
 472	/* We just use this to catch switches out of
 473	 * graphics mode.
 474	 */
 475	ffb_switch_from_graph(par);
 476
 477	if (var->xoffset || var->yoffset || var->vmode)
 478		return -EINVAL;
 479	return 0;
 480}
 481
 482/**
 483 *	ffb_fillrect - Draws a rectangle on the screen.
 484 *
 485 *	@info: frame buffer structure that represents a single frame buffer
 486 *	@rect: structure defining the rectagle and operation.
 487 */
 488static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 489{
 490	struct ffb_par *par = (struct ffb_par *)info->par;
 491	struct ffb_fbc __iomem *fbc = par->fbc;
 492	unsigned long flags;
 493	u32 fg;
 494
 495	BUG_ON(rect->rop != ROP_COPY && rect->rop != ROP_XOR);
 496
 497	fg = ((u32 *)info->pseudo_palette)[rect->color];
 498
 499	spin_lock_irqsave(&par->lock, flags);
 500
 501	if (fg != par->fg_cache) {
 502		FFBFifo(par, 1);
 503		upa_writel(fg, &fbc->fg);
 504		par->fg_cache = fg;
 505	}
 506
 507	ffb_rop(par, rect->rop == ROP_COPY ?
 508		     FFB_ROP_NEW :
 509		     FFB_ROP_NEW_XOR_OLD);
 510
 511	FFBFifo(par, 5);
 512	upa_writel(FFB_DRAWOP_RECTANGLE, &fbc->drawop);
 513	upa_writel(rect->dy, &fbc->by);
 514	upa_writel(rect->dx, &fbc->bx);
 515	upa_writel(rect->height, &fbc->bh);
 516	upa_writel(rect->width, &fbc->bw);
 517
 518	spin_unlock_irqrestore(&par->lock, flags);
 519}
 520
 521/**
 522 *	ffb_copyarea - Copies on area of the screen to another area.
 523 *
 524 *	@info: frame buffer structure that represents a single frame buffer
 525 *	@area: structure defining the source and destination.
 526 */
 527
 528static void ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 529{
 530	struct ffb_par *par = (struct ffb_par *)info->par;
 531	struct ffb_fbc __iomem *fbc = par->fbc;
 532	unsigned long flags;
 533
 534	if (area->dx != area->sx ||
 535	    area->dy == area->sy) {
 536		cfb_copyarea(info, area);
 537		return;
 538	}
 539
 540	spin_lock_irqsave(&par->lock, flags);
 541
 542	ffb_rop(par, FFB_ROP_OLD);
 543
 544	FFBFifo(par, 7);
 545	upa_writel(FFB_DRAWOP_VSCROLL, &fbc->drawop);
 546	upa_writel(area->sy, &fbc->by);
 547	upa_writel(area->sx, &fbc->bx);
 548	upa_writel(area->dy, &fbc->dy);
 549	upa_writel(area->dx, &fbc->dx);
 550	upa_writel(area->height, &fbc->bh);
 551	upa_writel(area->width, &fbc->bw);
 552
 553	spin_unlock_irqrestore(&par->lock, flags);
 554}
 555
 556/**
 557 *	ffb_imageblit - Copies a image from system memory to the screen.
 558 *
 559 *	@info: frame buffer structure that represents a single frame buffer
 560 *	@image: structure defining the image.
 561 */
 562static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
 563{
 564	struct ffb_par *par = (struct ffb_par *)info->par;
 565	struct ffb_fbc __iomem *fbc = par->fbc;
 566	const u8 *data = image->data;
 567	unsigned long flags;
 568	u32 fg, bg, xy;
 569	u64 fgbg;
 570	int i, width, stride;
 571
 572	if (image->depth > 1) {
 573		cfb_imageblit(info, image);
 574		return;
 575	}
 576
 577	fg = ((u32 *)info->pseudo_palette)[image->fg_color];
 578	bg = ((u32 *)info->pseudo_palette)[image->bg_color];
 579	fgbg = ((u64) fg << 32) | (u64) bg;
 580	xy = (image->dy << 16) | image->dx;
 581	width = image->width;
 582	stride = ((width + 7) >> 3);
 583
 584	spin_lock_irqsave(&par->lock, flags);
 585
 586	if (fgbg != *(u64 *)&par->fg_cache) {
 587		FFBFifo(par, 2);
 588		upa_writeq(fgbg, &fbc->fg);
 589		*(u64 *)&par->fg_cache = fgbg;
 590	}
 591
 592	if (width >= 32) {
 593		FFBFifo(par, 1);
 594		upa_writel(32, &fbc->fontw);
 595	}
 596
 597	while (width >= 32) {
 598		const u8 *next_data = data + 4;
 599
 600		FFBFifo(par, 1);
 601		upa_writel(xy, &fbc->fontxy);
 602		xy += (32 << 0);
 603
 604		for (i = 0; i < image->height; i++) {
 605			u32 val = (((u32)data[0] << 24) |
 606				   ((u32)data[1] << 16) |
 607				   ((u32)data[2] <<  8) |
 608				   ((u32)data[3] <<  0));
 609			FFBFifo(par, 1);
 610			upa_writel(val, &fbc->font);
 611
 612			data += stride;
 613		}
 614
 615		data = next_data;
 616		width -= 32;
 617	}
 618
 619	if (width) {
 620		FFBFifo(par, 2);
 621		upa_writel(width, &fbc->fontw);
 622		upa_writel(xy, &fbc->fontxy);
 623
 624		for (i = 0; i < image->height; i++) {
 625			u32 val = (((u32)data[0] << 24) |
 626				   ((u32)data[1] << 16) |
 627				   ((u32)data[2] <<  8) |
 628				   ((u32)data[3] <<  0));
 629			FFBFifo(par, 1);
 630			upa_writel(val, &fbc->font);
 631
 632			data += stride;
 633		}
 634	}
 635
 636	spin_unlock_irqrestore(&par->lock, flags);
 637}
 638
 639static void ffb_fixup_var_rgb(struct fb_var_screeninfo *var)
 640{
 641	var->red.offset = 0;
 642	var->red.length = 8;
 643	var->green.offset = 8;
 644	var->green.length = 8;
 645	var->blue.offset = 16;
 646	var->blue.length = 8;
 647	var->transp.offset = 0;
 648	var->transp.length = 0;
 649}
 650
 651/**
 652 *	ffb_setcolreg - Sets a color register.
 653 *
 654 *	@regno: boolean, 0 copy local, 1 get_user() function
 655 *	@red: frame buffer colormap structure
 656 *	@green: The green value which can be up to 16 bits wide
 657 *	@blue:  The blue value which can be up to 16 bits wide.
 658 *	@transp: If supported the alpha value which can be up to 16 bits wide.
 659 *	@info: frame buffer info structure
 660 */
 661static int ffb_setcolreg(unsigned regno,
 662			 unsigned red, unsigned green, unsigned blue,
 663			 unsigned transp, struct fb_info *info)
 664{
 665	u32 value;
 666
 667	if (regno >= 16)
 668		return 1;
 669
 670	red >>= 8;
 671	green >>= 8;
 672	blue >>= 8;
 673
 674	value = (blue << 16) | (green << 8) | red;
 675	((u32 *)info->pseudo_palette)[regno] = value;
 676
 677	return 0;
 678}
 679
 680/**
 681 *	ffb_blank - Optional function.  Blanks the display.
 682 *	@blank: the blank mode we want.
 683 *	@info: frame buffer structure that represents a single frame buffer
 684 */
 685static int ffb_blank(int blank, struct fb_info *info)
 686{
 687	struct ffb_par *par = (struct ffb_par *)info->par;
 688	struct ffb_dac __iomem *dac = par->dac;
 689	unsigned long flags;
 690	u32 val;
 691	int i;
 692
 693	spin_lock_irqsave(&par->lock, flags);
 694
 695	FFBWait(par);
 696
 697	upa_writel(FFB_DAC_TGEN, &dac->type);
 698	val = upa_readl(&dac->value);
 699	switch (blank) {
 700	case FB_BLANK_UNBLANK: /* Unblanking */
 701		val |= FFB_DAC_TGEN_VIDE;
 702		par->flags &= ~FFB_FLAG_BLANKED;
 703		break;
 704
 705	case FB_BLANK_NORMAL: /* Normal blanking */
 706	case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
 707	case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
 708	case FB_BLANK_POWERDOWN: /* Poweroff */
 709		val &= ~FFB_DAC_TGEN_VIDE;
 710		par->flags |= FFB_FLAG_BLANKED;
 711		break;
 712	}
 713	upa_writel(FFB_DAC_TGEN, &dac->type);
 714	upa_writel(val, &dac->value);
 715	for (i = 0; i < 10; i++) {
 716		upa_writel(FFB_DAC_TGEN, &dac->type);
 717		upa_readl(&dac->value);
 718	}
 719
 720	spin_unlock_irqrestore(&par->lock, flags);
 721
 722	return 0;
 723}
 724
 725static const struct sbus_mmap_map ffb_mmap_map[] = {
 726	{
 727		.voff	= FFB_SFB8R_VOFF,
 728		.poff	= FFB_SFB8R_POFF,
 729		.size	= 0x0400000
 730	},
 731	{
 732		.voff	= FFB_SFB8G_VOFF,
 733		.poff	= FFB_SFB8G_POFF,
 734		.size	= 0x0400000
 735	},
 736	{
 737		.voff	= FFB_SFB8B_VOFF,
 738		.poff	= FFB_SFB8B_POFF,
 739		.size	= 0x0400000
 740	},
 741	{
 742		.voff	= FFB_SFB8X_VOFF,
 743		.poff	= FFB_SFB8X_POFF,
 744		.size	= 0x0400000
 745	},
 746	{
 747		.voff	= FFB_SFB32_VOFF,
 748		.poff	= FFB_SFB32_POFF,
 749		.size	= 0x1000000
 750	},
 751	{
 752		.voff	= FFB_SFB64_VOFF,
 753		.poff	= FFB_SFB64_POFF,
 754		.size	= 0x2000000
 755	},
 756	{
 757		.voff	= FFB_FBC_REGS_VOFF,
 758		.poff	= FFB_FBC_REGS_POFF,
 759		.size	= 0x0002000
 760	},
 761	{
 762		.voff	= FFB_BM_FBC_REGS_VOFF,
 763		.poff	= FFB_BM_FBC_REGS_POFF,
 764		.size	= 0x0002000
 765	},
 766	{
 767		.voff	= FFB_DFB8R_VOFF,
 768		.poff	= FFB_DFB8R_POFF,
 769		.size	= 0x0400000
 770	},
 771	{
 772		.voff	= FFB_DFB8G_VOFF,
 773		.poff	= FFB_DFB8G_POFF,
 774		.size	= 0x0400000
 775	},
 776	{
 777		.voff	= FFB_DFB8B_VOFF,
 778		.poff	= FFB_DFB8B_POFF,
 779		.size	= 0x0400000
 780	},
 781	{
 782		.voff	= FFB_DFB8X_VOFF,
 783		.poff	= FFB_DFB8X_POFF,
 784		.size	= 0x0400000
 785	},
 786	{
 787		.voff	= FFB_DFB24_VOFF,
 788		.poff	= FFB_DFB24_POFF,
 789		.size	= 0x1000000
 790	},
 791	{
 792		.voff	= FFB_DFB32_VOFF,
 793		.poff	= FFB_DFB32_POFF,
 794		.size	= 0x1000000
 795	},
 796	{
 797		.voff	= FFB_FBC_KREGS_VOFF,
 798		.poff	= FFB_FBC_KREGS_POFF,
 799		.size	= 0x0002000
 800	},
 801	{
 802		.voff	= FFB_DAC_VOFF,
 803		.poff	= FFB_DAC_POFF,
 804		.size	= 0x0002000
 805	},
 806	{
 807		.voff	= FFB_PROM_VOFF,
 808		.poff	= FFB_PROM_POFF,
 809		.size	= 0x0010000
 810	},
 811	{
 812		.voff	= FFB_EXP_VOFF,
 813		.poff	= FFB_EXP_POFF,
 814		.size	= 0x0002000
 815	},
 816	{
 817		.voff	= FFB_DFB422A_VOFF,
 818		.poff	= FFB_DFB422A_POFF,
 819		.size	= 0x0800000
 820	},
 821	{
 822		.voff	= FFB_DFB422AD_VOFF,
 823		.poff	= FFB_DFB422AD_POFF,
 824		.size	= 0x0800000
 825	},
 826	{
 827		.voff	= FFB_DFB24B_VOFF,
 828		.poff	= FFB_DFB24B_POFF,
 829		.size	= 0x1000000
 830	},
 831	{
 832		.voff	= FFB_DFB422B_VOFF,
 833		.poff	= FFB_DFB422B_POFF,
 834		.size	= 0x0800000
 835	},
 836	{
 837		.voff	= FFB_DFB422BD_VOFF,
 838		.poff	= FFB_DFB422BD_POFF,
 839		.size	= 0x0800000
 840	},
 841	{
 842		.voff	= FFB_SFB16Z_VOFF,
 843		.poff	= FFB_SFB16Z_POFF,
 844		.size	= 0x0800000
 845	},
 846	{
 847		.voff	= FFB_SFB8Z_VOFF,
 848		.poff	= FFB_SFB8Z_POFF,
 849		.size	= 0x0800000
 850	},
 851	{
 852		.voff	= FFB_SFB422_VOFF,
 853		.poff	= FFB_SFB422_POFF,
 854		.size	= 0x0800000
 855	},
 856	{
 857		.voff	= FFB_SFB422D_VOFF,
 858		.poff	= FFB_SFB422D_POFF,
 859		.size	= 0x0800000
 860	},
 861	{ .size = 0 }
 862};
 863
 864static int ffb_sbusfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 865{
 866	struct ffb_par *par = (struct ffb_par *)info->par;
 867
 868	return sbusfb_mmap_helper(ffb_mmap_map,
 869				  par->physbase, par->fbsize,
 870				  0, vma);
 871}
 872
 873static int ffb_sbusfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 874{
 875	struct ffb_par *par = (struct ffb_par *)info->par;
 876
 877	return sbusfb_ioctl_helper(cmd, arg, info,
 878				   FBTYPE_CREATOR, 24, par->fbsize);
 879}
 880
 881/*
 882 *  Initialisation
 883 */
 884
 885static void ffb_init_fix(struct fb_info *info)
 886{
 887	struct ffb_par *par = (struct ffb_par *)info->par;
 888	const char *ffb_type_name;
 889
 890	if (!(par->flags & FFB_FLAG_AFB)) {
 891		if ((par->board_type & 0x7) == 0x3)
 892			ffb_type_name = "Creator 3D";
 893		else
 894			ffb_type_name = "Creator";
 895	} else
 896		ffb_type_name = "Elite 3D";
 897
 898	strscpy(info->fix.id, ffb_type_name, sizeof(info->fix.id));
 899
 900	info->fix.type = FB_TYPE_PACKED_PIXELS;
 901	info->fix.visual = FB_VISUAL_TRUECOLOR;
 902
 903	/* Framebuffer length is the same regardless of resolution. */
 904	info->fix.line_length = 8192;
 905
 906	info->fix.accel = FB_ACCEL_SUN_CREATOR;
 907}
 908
 909static int ffb_probe(struct platform_device *op)
 910{
 911	struct device_node *dp = op->dev.of_node;
 912	struct ffb_fbc __iomem *fbc;
 913	struct ffb_dac __iomem *dac;
 914	struct fb_info *info;
 915	struct ffb_par *par;
 916	u32 dac_pnum, dac_rev, dac_mrev;
 917	int err;
 918
 919	info = framebuffer_alloc(sizeof(struct ffb_par), &op->dev);
 920
 921	err = -ENOMEM;
 922	if (!info)
 923		goto out_err;
 924
 925	par = info->par;
 926
 927	spin_lock_init(&par->lock);
 928	par->fbc = of_ioremap(&op->resource[2], 0,
 929			      sizeof(struct ffb_fbc), "ffb fbc");
 930	if (!par->fbc)
 931		goto out_release_fb;
 932
 933	par->dac = of_ioremap(&op->resource[1], 0,
 934			      sizeof(struct ffb_dac), "ffb dac");
 935	if (!par->dac)
 936		goto out_unmap_fbc;
 937
 938	par->rop_cache = FFB_ROP_NEW;
 939	par->physbase = op->resource[0].start;
 940
 941	/* Don't mention copyarea, so SCROLL_REDRAW is always
 942	 * used.  It is the fastest on this chip.
 943	 */
 944	info->flags = (/* FBINFO_HWACCEL_COPYAREA | */
 945		       FBINFO_HWACCEL_FILLRECT |
 946		       FBINFO_HWACCEL_IMAGEBLIT);
 947
 948	info->fbops = &ffb_ops;
 949
 950	info->screen_base = (char *) par->physbase + FFB_DFB24_POFF;
 951	info->pseudo_palette = par->pseudo_palette;
 952
 953	sbusfb_fill_var(&info->var, dp, 32);
 954	par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4);
 955	ffb_fixup_var_rgb(&info->var);
 956
 957	info->var.accel_flags = FB_ACCELF_TEXT;
 958
 959	if (of_node_name_eq(dp, "SUNW,afb"))
 960		par->flags |= FFB_FLAG_AFB;
 961
 962	par->board_type = of_getintprop_default(dp, "board_type", 0);
 963
 964	fbc = par->fbc;
 965	if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
 966		upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
 967
 968	dac = par->dac;
 969	upa_writel(FFB_DAC_DID, &dac->type);
 970	dac_pnum = upa_readl(&dac->value);
 971	dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT;
 972	dac_pnum = (dac_pnum & FFB_DAC_DID_PNUM) >> FFB_DAC_DID_PNUM_SHIFT;
 973
 974	upa_writel(FFB_DAC_UCTRL, &dac->type);
 975	dac_mrev = upa_readl(&dac->value);
 976	dac_mrev = (dac_mrev & FFB_DAC_UCTRL_MANREV) >>
 977		FFB_DAC_UCTRL_MANREV_SHIFT;
 978
 979	/* Elite3D has different DAC revision numbering, and no DAC revisions
 980	 * have the reversed meaning of cursor enable.  Otherwise, Pacifica 1
 981	 * ramdacs with manufacturing revision less than 3 have inverted
 982	 * cursor logic.  We identify Pacifica 1 as not Pacifica 2, the
 983	 * latter having a part number value of 0x236e.
 984	 */
 985	if ((par->flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
 986		par->flags &= ~FFB_FLAG_INVCURSOR;
 987	} else {
 988		if (dac_mrev < 3)
 989			par->flags |= FFB_FLAG_INVCURSOR;
 990	}
 991
 992	ffb_switch_from_graph(par);
 993
 994	/* Unblank it just to be sure.  When there are multiple
 995	 * FFB/AFB cards in the system, or it is not the OBP
 996	 * chosen console, it will have video outputs off in
 997	 * the DAC.
 998	 */
 999	ffb_blank(FB_BLANK_UNBLANK, info);
1000
1001	if (fb_alloc_cmap(&info->cmap, 256, 0))
1002		goto out_unmap_dac;
1003
1004	ffb_init_fix(info);
1005
1006	err = register_framebuffer(info);
1007	if (err < 0)
1008		goto out_dealloc_cmap;
1009
1010	dev_set_drvdata(&op->dev, info);
1011
1012	printk(KERN_INFO "%pOF: %s at %016lx, type %d, "
1013	       "DAC pnum[%x] rev[%d] manuf_rev[%d]\n",
1014	       dp,
1015	       ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
1016	       par->physbase, par->board_type,
1017	       dac_pnum, dac_rev, dac_mrev);
1018
1019	return 0;
1020
1021out_dealloc_cmap:
1022	fb_dealloc_cmap(&info->cmap);
1023
1024out_unmap_dac:
1025	of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));
1026
1027out_unmap_fbc:
1028	of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
1029
1030out_release_fb:
1031	framebuffer_release(info);
1032
1033out_err:
1034	return err;
1035}
1036
1037static void ffb_remove(struct platform_device *op)
1038{
1039	struct fb_info *info = dev_get_drvdata(&op->dev);
1040	struct ffb_par *par = info->par;
1041
1042	unregister_framebuffer(info);
1043	fb_dealloc_cmap(&info->cmap);
1044
1045	of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
1046	of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));
1047
1048	framebuffer_release(info);
1049}
1050
1051static const struct of_device_id ffb_match[] = {
1052	{
1053		.name = "SUNW,ffb",
1054	},
1055	{
1056		.name = "SUNW,afb",
1057	},
1058	{},
1059};
1060MODULE_DEVICE_TABLE(of, ffb_match);
1061
1062static struct platform_driver ffb_driver = {
1063	.driver = {
1064		.name = "ffb",
1065		.of_match_table = ffb_match,
1066	},
1067	.probe		= ffb_probe,
1068	.remove		= ffb_remove,
1069};
1070
1071static int __init ffb_init(void)
1072{
1073	if (fb_get_options("ffb", NULL))
1074		return -ENODEV;
1075
1076	return platform_driver_register(&ffb_driver);
1077}
1078
1079static void __exit ffb_exit(void)
1080{
1081	platform_driver_unregister(&ffb_driver);
1082}
1083
1084module_init(ffb_init);
1085module_exit(ffb_exit);
1086
1087MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets");
1088MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
1089MODULE_VERSION("2.0");
1090MODULE_LICENSE("GPL");
~/ Read-only file preview.