xref: /plan9-contrib/sys/src/9/pc/vgai81x.c (revision 74f16c8187aab477889167f2422d0597b1b7d0ff)
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8 
9 #define	Image	IMAGE
10 #include <draw.h>
11 #include <memdraw.h>
12 #include <cursor.h>
13 #include "screen.h"
14 
15 typedef struct
16 {
17 	ushort	ctl;
18 	ushort	pad;
19 	ulong	base;
20 	ulong	pos;
21 } CursorI81x;
22 
23 enum {
24 	Fbsize		= 8*MB,
25 
26 	hwCur		= 0x70080,
27 	SRX		= 0x3c4,
28 	DPMSsync	= 0x5002,
29 };
30 
31 static void
i81xblank(VGAscr * scr,int blank)32 i81xblank(VGAscr *scr, int blank)
33 {
34 	char *srx, *srxd, *dpms;
35 	char sr01, mode;
36 
37 	srx = (char *)scr->mmio+SRX;
38 	srxd = srx+1;
39 	dpms = (char *)scr->mmio+DPMSsync;
40 
41 	*srx = 0x01;
42 	sr01 = *srxd & ~0x20;
43 	mode = *dpms & 0xf0;
44 
45 	if(blank) {
46 		sr01 |= 0x20;
47 		mode |= 0x0a;
48 	}
49 	*srxd = sr01;
50 	*dpms = mode;
51 }
52 
53 static Pcidev *
i81xpcimatch(void)54 i81xpcimatch(void)
55 {
56 	Pcidev *p;
57 
58 	p = nil;
59 	while((p = pcimatch(p, 0x8086, 0)) != nil){
60 		switch(p->did){
61 		default:
62 			continue;
63 		case 0x7121:
64 		case 0x7123:
65 		case 0x7125:
66 		case 0x1102:
67 		case 0x1112:
68 		case 0x1132:
69 		case 0x3577:	/* IBM R31 uses intel 830M chipset */
70 			return p;
71 		}
72 	}
73 	return nil;
74 }
75 
76 static void
i81xenable(VGAscr * scr)77 i81xenable(VGAscr* scr)
78 {
79 	Pcidev *p;
80 	int size;
81 	Mach *mach0;
82 	ulong *pgtbl, *rp, cursor, *pte, fbuf, fbend;
83 
84 	if(scr->mmio)
85 		return;
86 	p = i81xpcimatch();
87 	if(p == nil)
88 		return;
89 	scr->mmio = vmap(p->mem[1].bar & ~0x0F, p->mem[1].size);
90 	if(scr->mmio == 0)
91 		return;
92 	addvgaseg("i81xmmio", p->mem[1].bar&~0x0F, p->mem[1].size);
93 
94 	/* allocate page table */
95 	pgtbl = xspanalloc(64*1024, BY2PG, 0);
96 	scr->mmio[0x2020/4] = PADDR(pgtbl) | 1;
97 
98 	size = p->mem[0].size;
99 	if(size > 0)
100 		size = Fbsize;
101 	vgalinearaddr(scr, p->mem[0].bar&~0xF, size);
102 	addvgaseg("i81xscreen", p->mem[0].bar&~0xF, size);
103 
104 	/*
105 	 * allocate backing store for frame buffer
106 	 * and populate device page tables.
107 	 */
108 	fbuf = PADDR(xspanalloc(size, BY2PG, 0));
109 	fbend = PGROUND(fbuf+size);
110 	rp = scr->mmio+0x10000/4;
111 	while(fbuf < fbend) {
112 		*rp++ = fbuf | 1;
113 		fbuf += BY2PG;
114 	}
115 
116 	/*
117 	 * allocate space for the cursor data in system memory.
118 	 * must be uncached.
119 	 */
120 	cursor = (ulong)xspanalloc(BY2PG, BY2PG, 0);
121 	mach0 = MACHP(0);
122 	pte = mmuwalk(mach0->pdb, cursor, 2, 0);
123 	if(pte == nil)
124 		panic("i81x cursor mmuwalk");
125 	*pte |= PTEUNCACHED;
126 	scr->storage = cursor;
127 
128 	scr->blank = i81xblank;
129 	hwblank = 1;
130 }
131 
132 static void
i81xcurdisable(VGAscr * scr)133 i81xcurdisable(VGAscr* scr)
134 {
135 	CursorI81x *hwcurs;
136 
137 	if(scr->mmio == 0)
138 		return;
139 	hwcurs = (void*)((uchar*)scr->mmio+hwCur);
140 	hwcurs->ctl = (1<<4);
141 }
142 
143 static void
i81xcurload(VGAscr * scr,Cursor * curs)144 i81xcurload(VGAscr* scr, Cursor* curs)
145 {
146 	int y;
147 	uchar *p;
148 	CursorI81x *hwcurs;
149 
150 	if(scr->mmio == 0)
151 		return;
152 	hwcurs = (void*)((uchar*)scr->mmio+hwCur);
153 
154 	/*
155 	 * Disable the cursor then load the new image in
156 	 * the top-left of the 32x32 array.
157 	 * Unused portions of the image have been initialised to be
158 	 * transparent.
159 	 */
160 	hwcurs->ctl = (1<<4);
161 	p = (uchar*)scr->storage;
162 	for(y = 0; y < 16; y += 2) {
163 		*p++ = ~(curs->clr[2*y]|curs->set[2*y]);
164 		*p++ = ~(curs->clr[2*y+1]|curs->set[2*y+1]);
165 		p += 2;
166 		*p++ = ~(curs->clr[2*y+2]|curs->set[2*y+2]);
167 		*p++ = ~(curs->clr[2*y+3]|curs->set[2*y+3]);
168 		p += 2;
169 		*p++ = curs->set[2*y];
170 		*p++ = curs->set[2*y+1];
171 		p += 2;
172 		*p++ = curs->set[2*y+2];
173 		*p++ = curs->set[2*y+3];
174 		p += 2;
175 	}
176 
177 	/*
178 	 * Save the cursor hotpoint and enable the cursor.
179 	 * The 0,0 cursor point is top-left.
180 	 */
181 	scr->offset.x = curs->offset.x;
182 	scr->offset.y = curs->offset.y;
183 	hwcurs->ctl = (1<<4)|1;
184 }
185 
186 static int
i81xcurmove(VGAscr * scr,Point p)187 i81xcurmove(VGAscr* scr, Point p)
188 {
189 	int x, y;
190 	ulong pos;
191 	CursorI81x *hwcurs;
192 
193 	if(scr->mmio == 0)
194 		return 1;
195 	hwcurs = (void*)((uchar*)scr->mmio+hwCur);
196 
197 	x = p.x+scr->offset.x;
198 	y = p.y+scr->offset.y;
199 	pos = 0;
200 	if(x < 0) {
201 		pos |= (1<<15);
202 		x = -x;
203 	}
204 	if(y < 0) {
205 		pos |= (1<<31);
206 		y = -y;
207 	}
208 	pos |= ((y&0x7ff)<<16)|(x&0x7ff);
209 	hwcurs->pos = pos;
210 
211 	return 0;
212 }
213 
214 static void
i81xcurenable(VGAscr * scr)215 i81xcurenable(VGAscr* scr)
216 {
217 	int i;
218 	uchar *p;
219 	CursorI81x *hwcurs;
220 
221 	i81xenable(scr);
222 	if(scr->mmio == 0)
223 		return;
224 	hwcurs = (void*)((uchar*)scr->mmio+hwCur);
225 
226 	/*
227 	 * Initialise the 32x32 cursor to be transparent in 2bpp mode.
228 	 */
229 	hwcurs->base = PADDR(scr->storage);
230 	p = (uchar*)scr->storage;
231 	for(i = 0; i < 32/2; i++) {
232 		memset(p, 0xff, 8);
233 		memset(p+8, 0, 8);
234 		p += 16;
235 	}
236 	/*
237 	 * Load, locate and enable the 32x32 cursor in 2bpp mode.
238 	 */
239 	i81xcurload(scr, &arrow);
240 	i81xcurmove(scr, ZP);
241 }
242 
243 VGAdev vgai81xdev = {
244 	"i81x",
245 
246 	i81xenable,
247 	nil,
248 	nil,
249 	nil,
250 };
251 
252 VGAcur vgai81xcur = {
253 	"i81xhwgc",
254 
255 	i81xcurenable,
256 	i81xcurdisable,
257 	i81xcurload,
258 	i81xcurmove,
259 };
260