⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mach64xx.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include "pci.h"#include "vga.h"/* * ATI Mach64 family. */enum {	HTotalDisp,	HSyncStrtWid,	VTotalDisp,	VSyncStrtWid,	VlineCrntVline,	OffPitch,	IntCntl,	CrtcGenCntl,	OvrClr,	OvrWidLR,	OvrWidTB,	CurClr0,	CurClr1,	CurOffset,	CurHVposn,	CurHVoff,	ScratchReg0,	ScratchReg1,	/* Scratch Register (BIOS info) */	ClockCntl,	BusCntl,	MemCntl,	ExtMemCntl,	MemVgaWpSel,	MemVgaRpSel,	DacRegs,	DacCntl,	GenTestCntl,	ConfigCntl,	/* Configuration control */	ConfigChipId,	ConfigStat0,	/* Configuration status 0 */	ConfigStat1,	/* Configuration status 1 */	ConfigStat2,	DspConfig,	/* Rage */	DspOnOff,	/* Rage */	DpBkgdClr,	DpChainMsk,	DpFrgdClr,	DpMix,	DpPixWidth,	DpSrc,	DpWriteMsk,	LcdIndex,	LcdData,	Nreg,	TvIndex = 0x1D,	TvData = 0x27,	LCD_ConfigPanel = 0,	LCD_GenCtrl,	LCD_DstnCntl,	LCD_HfbPitchAddr,	LCD_HorzStretch,	LCD_VertStretch,	LCD_ExtVertStretch,	LCD_LtGio,	LCD_PowerMngmnt,	LCD_ZvgPio,	Nlcd,};static char* iorname[Nreg] = {	"HTotalDisp",	"HSyncStrtWid",	"VTotalDisp",	"VSyncStrtWid",	"VlineCrntVline",	"OffPitch",	"IntCntl",	"CrtcGenCntl",	"OvrClr",	"OvrWidLR",	"OvrWidTB",	"CurClr0",	"CurClr1",	"CurOffset",	"CurHVposn",	"CurHVoff",	"ScratchReg0",	"ScratchReg1",	"ClockCntl",	"BusCntl",	"MemCntl",	"ExtMemCntl",	"MemVgaWpSel",	"MemVgaRpSel",	"DacRegs",	"DacCntl",	"GenTestCntl",	"ConfigCntl",	"ConfigChipId",	"ConfigStat0",	"ConfigStat1",	"ConfigStat2",	"DspConfig",	"DspOnOff",	"DpBkgdClr",	"DpChainMsk",	"DpFrgdClr",	"DpMix",	"DpPixWidth",	"DpSrc",	"DpWriteMsk",	"LcdIndex",	"LcdData",	};static char* lcdname[Nlcd] = {	"LCD ConfigPanel",	"LCD GenCntl",	"LCD DstnCntl",	"LCD HfbPitchAddr",	"LCD HorzStretch",	"LCD VertStretch",	"LCD ExtVertStretch",	"LCD LtGio",	"LCD PowerMngmnt",	"LCD ZvgPio"};/* * Crummy hack: all io register offsets * here get IOREG or'ed in, so that we can * tell the difference between an uninitialized * array entry and HTotalDisp. */enum {	IOREG = 0x10000,};static ushort ioregs[Nreg] = { [HTotalDisp]		IOREG|0x0000, [HSyncStrtWid]	IOREG|0x0100, [VTotalDisp]		IOREG|0x0200, [VSyncStrtWid]		IOREG|0x0300, [VlineCrntVline]	IOREG|0x0400, [OffPitch]			IOREG|0x0500, [IntCntl]			IOREG|0x0600, [CrtcGenCntl]		IOREG|0x0700, [OvrClr]			IOREG|0x0800, [OvrWidLR]		IOREG|0x0900, [OvrWidTB]		IOREG|0x0A00, [CurClr0]			IOREG|0x0B00, [CurClr1]			IOREG|0x0C00, [CurOffset]		IOREG|0x0D00, [CurHVposn]		IOREG|0x0E00, [CurHVoff]		IOREG|0x0F00, [ScratchReg0]		IOREG|0x1000, [ScratchReg1]		IOREG|0x1100, [ClockCntl]		IOREG|0x1200, [BusCntl]			IOREG|0x1300, [MemCntl]		IOREG|0x1400, [MemVgaWpSel]	IOREG|0x1500, [MemVgaRpSel]	IOREG|0x1600, [DacRegs]		IOREG|0x1700, [DacCntl]			IOREG|0x1800, [GenTestCntl]		IOREG|0x1900, [ConfigCntl]		IOREG|0x1A00, [ConfigChipId]		IOREG|0x1B00, [ConfigStat0]		IOREG|0x1C00, [ConfigStat1]		IOREG|0x1D00,/* [GpIo]				IOREG|0x1E00, *//* [HTotalDisp]			IOREG|0x1F00, 	duplicate, says XFree86 */};static ushort pciregs[Nreg] = {  [HTotalDisp]		0x00,  [HSyncStrtWid]	0x01,  [VTotalDisp]		0x02,  [VSyncStrtWid]        0x03,  [VlineCrntVline]      0x04,  [OffPitch]		0x05,  [IntCntl]		0x06,  [CrtcGenCntl]		0x07,  [DspConfig]		0x08,  [DspOnOff]		0x09,  [OvrClr]		0x10,  [OvrWidLR]		0x11,  [OvrWidTB]		0x12,  [CurClr0]		0x18,  [CurClr1]		0x19,  [CurOffset]		0x1A,  [CurHVposn]		0x1B,  [CurHVoff]		0x1C,  [ScratchReg0]		0x20,  [ScratchReg1]		0x21,  [ClockCntl]		0x24,  [BusCntl]		0x28,  [LcdIndex]		0x29,  [LcdData]		0x2A,  [ExtMemCntl]		0x2B,  [MemCntl]		0x2C,  [MemVgaWpSel]		0x2D,  [MemVgaRpSel]		0x2E,  [DacRegs]		0x30,  [DacCntl]		0x31,  [GenTestCntl]		0x34,  [ConfigCntl]		0x37,  [ConfigChipId]	0x38,  [ConfigStat0]		0x39,  [ConfigStat1]		0x25,	/* rsc: was 0x3A, but that's not what the LT manual says */  [ConfigStat2]		0x26,  [DpBkgdClr]		0xB0,  [DpChainMsk]		0xB3,  [DpFrgdClr]		0xB1,  [DpMix]		0xB5,  [DpPixWidth]		0xB4,  [DpSrc]		0xB6,  [DpWriteMsk]		0xB2,};enum {	PLLm		= 0x02,	PLLp		= 0x06,	PLLn0		= 0x07,	PLLn1		= 0x08,	PLLn2		= 0x09,	PLLn3		= 0x0A,	PLLx            = 0x0B,         /* external divisor (Rage) */	Npll		= 32,	Ntv		= 1,		/* actually 256, but not used */};typedef struct Mach64xx	Mach64xx;struct Mach64xx {	ulong	io;	Pcidev*	pci;	int	bigmem;	int	lcdon;	int	lcdpanelid;	ulong	reg[Nreg];	ulong	lcd[Nlcd];	ulong	tv[Ntv];	uchar	pll[Npll];	ulong	(*ior32)(Mach64xx*, int);	void	(*iow32)(Mach64xx*, int, ulong);};static ulongportior32(Mach64xx* mp, int r){	if((ioregs[r] & IOREG) == 0)		return ~0;	return inportl(((ioregs[r] & ~IOREG)<<2)+mp->io);}static voidportiow32(Mach64xx* mp, int r, ulong l){	if((ioregs[r] & IOREG) == 0)		return;	outportl(((ioregs[r] & ~IOREG)<<2)+mp->io, l);}static ulongpciior32(Mach64xx* mp, int r){	return inportl((pciregs[r]<<2)+mp->io);}static voidpciiow32(Mach64xx* mp, int r, ulong l){	outportl((pciregs[r]<<2)+mp->io, l);}static ucharpllr(Mach64xx* mp, int r){	int io;	if(mp->ior32 == portior32)		io = ((ioregs[ClockCntl]&~IOREG)<<2)+mp->io;	else		io = (pciregs[ClockCntl]<<2)+mp->io;	outportb(io+1, r<<2);	return inportb(io+2);}static voidpllw(Mach64xx* mp, int r, uchar b){	int io;	if(mp->ior32 == portior32)		io = ((ioregs[ClockCntl]&~IOREG)<<2)+mp->io;	else		io = (pciregs[ClockCntl]<<2)+mp->io;	outportb(io+1, (r<<2)|0x02);	outportb(io+2, b);}static ulonglcdr32(Mach64xx *mp, ulong r){	ulong or;	or = mp->ior32(mp, LcdIndex);	mp->iow32(mp, LcdIndex, (or&~0x0F) | (r&0x0F));	return mp->ior32(mp, LcdData);}static voidlcdw32(Mach64xx *mp, ulong r, ulong v){	ulong or;	or = mp->ior32(mp, LcdIndex);	mp->iow32(mp, LcdIndex, (or&~0x0F) | (r&0x0F));	mp->iow32(mp, LcdData, v);}static ulongtvr32(Mach64xx *mp, ulong r){	outportb(mp->io+(TvIndex<<2), r&0x0F);	return inportl(mp->io+(TvData<<2));}static voidtvw32(Mach64xx *mp, ulong r, ulong v){	outportb(mp->io+(TvIndex<<2), r&0x0F);	outportl(mp->io+(TvData<<2), v);}static int smallmem[] = {	   512*1024,	  1024*1024,	 2*1024*1024,	 4*1024*1024,	6*1024*1024,	8*1024*1024,	12*1024*1024,	16*1024*1024,};static int bigmem[] = {	    512*1024,	  2*512*1024,	  3*512*1024,	  4*512*1024,	  5*512*1024,	  6*512*1024,	  7*512*1024,	  8*512*1024,	 5*1024*1024,	 6*1024*1024,	 7*1024*1024,	 8*1024*1024,	10*1024*1024,	12*1024*1024,	14*1024*1024,	16*1024*1024,};static voidsnarf(Vga* vga, Ctlr* ctlr){	Mach64xx *mp;	int i;	ulong v;	if(vga->private == nil){		vga->private = alloc(sizeof(Mach64xx));		mp = vga->private;		mp->io = 0x2EC;		mp->ior32 = portior32;		mp->iow32 = portiow32;		mp->pci = pcimatch(0, 0x1002, 0);		if (mp->pci) {			if(v = mp->pci->mem[1].bar & ~0x3) {				mp->io = v;				mp->ior32 = pciior32;				mp->iow32 = pciiow32;			}		}	}	mp = vga->private;	for(i = 0; i < Nreg; i++)		mp->reg[i] = mp->ior32(mp, i);	for(i = 0; i < Npll; i++)		mp->pll[i] = pllr(mp, i);	switch(mp->reg[ConfigChipId] & 0xFFFF){	default:		mp->lcdpanelid = 0;		break;	case ('L'<<8)|'B':		/* 4C42: Rage LTPro AGP */	case ('L'<<8)|'I':		/* 4C49: Rage 3D LTPro */	case ('L'<<8)|'M':		/* 4C4D: Rage Mobility */	case ('L'<<8)|'P':		/* 4C50: Rage 3D LTPro */		for(i = 0; i < Nlcd; i++)			mp->lcd[i] = lcdr32(mp, i);		if(mp->lcd[LCD_GenCtrl] & 0x02)			mp->lcdon = 1;		mp->lcdpanelid = ((mp->reg[ConfigStat2]>>14) & 0x1F);		break;	}	/*	 * Check which memory size map we are using.	 */	mp->bigmem = 0;	switch(mp->reg[ConfigChipId] & 0xFFFF){		case ('G'<<8)|'B':	/* 4742: 264GT PRO */		case ('G'<<8)|'D':	/* 4744: 264GT PRO */		case ('G'<<8)|'I':	/* 4749: 264GT PRO */		case ('G'<<8)|'M':	/* 474D: Rage XL */		case ('G'<<8)|'P':	/* 4750: 264GT PRO */		case ('G'<<8)|'Q':	/* 4751: 264GT PRO */		case ('G'<<8)|'R':	/* 4752: */		case ('G'<<8)|'U':	/* 4755: 264GT DVD */		case ('G'<<8)|'V':	/* 4756: Rage2C */		case ('G'<<8)|'Z':	/* 475A: Rage2C */		case ('V'<<8)|'U':	/* 5655: 264VT3 */		case ('V'<<8)|'V':	/* 5656: 264VT4 */		case ('L'<<8)|'B':	/* 4C42: Rage LTPro AGP */		case ('L'<<8)|'I':	/* 4C49: Rage 3D LTPro */		case ('L'<<8)|'M':	/* 4C4D: Rage Mobility */		case ('L'<<8)|'P':	/* 4C50: Rage 3D LTPro */			mp->bigmem = 1;			break;		case ('G'<<8)|'T':	/* 4754: 264GT[B] */		case ('V'<<8)|'T':	/* 5654: 264VT/GT/VTB */			/*			 * Only the VTB and GTB use the new memory encoding,			 * and they are identified by a nonzero ChipVersion,			 * apparently.			 */			if((mp->reg[ConfigChipId] >> 24) & 0x7)				mp->bigmem = 1;			break;	}	/*	 * Memory size and aperture. It's recommended	 * to use an 8Mb aperture on a 16Mb boundary.	 */	if(mp->bigmem)		vga->vmz = bigmem[mp->reg[MemCntl] & 0x0F];	else		vga->vmz = smallmem[mp->reg[MemCntl] & 0x07];	vga->vma = 16*1024*1024;	switch(mp->reg[ConfigCntl]&0x3){	case 0:		vga->apz = 16*1024*1024;	/* empirical -rsc */		break;	case 1:		vga->apz = 4*1024*1024;		break;	case 2:		vga->apz = 8*1024*1024;		break;	case 3:		vga->apz = 2*1024*1024;	/* empirical: mach64GX -rsc */		break;	}	ctlr->flag |= Fsnarf;}static voidoptions(Vga*, Ctlr* ctlr){	ctlr->flag |= Hlinear|Foptions;}static voidclock(Vga* vga, Ctlr* ctlr){	int clk, m, n, p;	double f, q;	Mach64xx *mp;	mp = vga->private;	/*	 * Don't compute clock timings for LCD panels.	 * Just use what's already there.  We can't just use	 * the frequency in the vgadb for this because 	 * the frequency being programmed into the PLLs	 * is not the frequency being used to compute the DSP	 * settings.  The DSP-relevant frequency is the one	 * we keep in /lib/vgadb.	 */	if(mp->lcdon){		clk = mp->reg[ClockCntl] & 0x03;		n = mp->pll[7+clk];		p = (mp->pll[6]>>(clk*2)) & 0x03;		p |= (mp->pll[11]>>(2+clk)) & 0x04;		switch(p){		case 0:		case 1:		case 2:		case 3:			p = 1<<p;			break;		case 4+0:			p = 3;			break;		case 4+2:			p = 6;			break;		case 4+3:			p = 12;			break;		default:		case 4+1:			p = -1;			break;		}		m = mp->pll[PLLm];		f = (2.0*RefFreq*n)/(m*p) + 0.5;		vga->m[0] = m;		vga->p[0] = p;		vga->n[0] = n;		vga->f[0] = f;		return;	}	if(vga->f[0] == 0)		vga->f[0] = vga->mode->frequency;	f = vga->f[0];	/*	 * To generate a specific output frequency, the reference (m),	 * feedback (n), and post dividers (p) must be loaded with the	 * appropriate divide-down ratios. In the following r is the	 * XTALIN frequency (usually RefFreq) and t is the target frequency	 * (vga->f).	 *	 * Use the maximum reference divider left by the BIOS for now,	 * otherwise MCLK might be a concern. It can be calculated as	 * follows:	 * 			    Upper Limit of PLL Lock Range	 *	Minimum PLLREFCLK = -----------------------------	 *				      (2*255)	 *	 *				       XTALIN	 *			m = Floor[-----------------]	 *				  Minimum PLLREFCLK	 *	 * For an upper limit of 135MHz and XTALIN of 14.318MHz m	 * would be 54.	 */	m = mp->pll[PLLm];	vga->m[0] = m;	/*	 * The post divider may be 1, 2, 4 or 8 and is determined by	 * calculating	 *		 t*m	 *	    q = -----	 *		(2*r)	 * and using the result to look-up p.	 */	q = (f*m)/(2*RefFreq);	if(ctlr->flag&Uenhanced){	  if(q > 255 || q < 10.6666666667)		error("%s: vclk %lud out of range\n", ctlr->name, vga->f[0]);	  if(q > 127.5)		p = 1;	  else if(q > 85)		p = 2;	  else if(q > 63.75)		p = 3;	  else if(q > 42.5)		p = 4;	  else if(q > 31.875)		p = 6;	  else if(q > 21.25)		p = 8;	  else		p = 12;	}else{	  if(q > 255 || q < 16)		error("%s: vclk %lud out of range\n", ctlr->name, vga->f[0]);	  if(q >= 127.5)		p = 1;	  else if(q >= 63.5)		p = 2;	  else if(q >= 31.5)		p = 4;	  else		p = 8;	}	vga->p[0] = p;	/*	 * The feedback divider should be kept in the range 0x80 to 0xFF	 * and is found from	 *	n = q*p	 * rounded to the nearest whole number.	 */	vga->n[0] = (q*p)+0.5;}typedef struct Meminfo	Meminfo;struct Meminfo {	int latency;	int latch;	int trp;		/* filled in from card */	int trcd;		/* filled in from card */	int tcrd;		/* filled in from card */	int tras;		/* filled in from card */};enum {	Mdram,	Medo,		Msdram,	Mwram,};/* * The manuals and documentation are silent on which settings * to use for Mwdram, or how to tell which to use. */static Meminfo meminfo[] = {[Mdram]		{ 1, 0 },[Medo]		{ 1, 2 },[Msdram]	{ 3, 1 },[Mwram]		{ 1, 3 },	/* non TYPE_A */};static ushort looplatencytab[2][2] = {	{ 8, 6 },		/* DRAM: ≤1M, > 1M */	{ 9, 8 },		/* SDRAM: ≤1M, > 1M */};static ushort cyclesperqwordtab[2][2] = {	{ 3, 2 },		/* DRAM: ≤1M, > 1M */	{ 2, 1 },		/* SDRAM: ≤1M, > 1M */};static int memtype[] = {	-1,			/* disable memory access */	Mdram,			/* basic DRAM */	Medo,			/* EDO */	Medo,			/* hyper page DRAM or EDO */	Msdram,			/* SDRAM */	Msdram,			/* SGRAM */	Mwram,	Mwram};/* * Calculate various memory parameters so that the card * fetches the right bytes at the right time.  I don't claim to * understand the actual calculations very well. * * This is remarkably useful on laptops, since knowledge of * x lets us find the frequency that the screen is really running * at, which is not necessarily in the VCLKs. */static voidsetdsp(Vga* vga, Ctlr*){	Mach64xx *mp;	Meminfo *mem;	ushort table, memclk, memtyp;	int i, prec, xprec, fprec;	ulong t;	double pw, x, fifosz, fifoon, fifooff;	ushort dspon, dspoff;	int afifosz, lat, ncycle, pfc, rcc;	mp = vga->private;	/*	 * Get video ram configuration from BIOS and chip	 */	table = *(ushort*)readbios(sizeof table, 0xc0048);	trace("rom table offset %uX\n", table);	table = *(ushort*)readbios(sizeof table, 0xc0000+table+16);	trace("freq table offset %uX\n", table);	memclk = *(ushort*)readbios(sizeof memclk, 0xc0000+table+18);	trace("memclk %ud\n", memclk);	memtyp = memtype[mp->reg[ConfigStat0]&07];	mem = &meminfo[memtyp];	/*	 * First we need to calculate x, the number of 	 * XCLKs that one QWORD occupies in the display FIFO.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -