1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4
5 #include "pci.h"
6 #include "vga.h"
7
8 /*
9 * Brooktree Bt485 Monolithic True-Color RAMDAC.
10 * Assumes hooked up to an S3 86C928.
11 *
12 * There are only 16 directly addressable registers,
13 * Cmd3 is accessed indirectly and overlays the
14 * status register. We make this register index 0x1A.
15 * Cmd4 is an artifact of the Tvp3025 in Bt485
16 * emulation mode.
17 */
18 enum {
19 AddrW = 0x00, /* Address register; palette/cursor RAM write */
20 Palette = 0x01, /* 6/8-bit color palette data */
21 Pmask = 0x02, /* Pixel mask register */
22 AddrR = 0x03, /* Address register; palette/cursor RAM read */
23 ColorW = 0x04, /* Address register; cursor/overscan color write */
24 Color = 0x05, /* Cursor/overscan color data */
25 Cmd0 = 0x06, /* Command register 0 */
26 ColorR = 0x07, /* Address register; cursor/overscan color read */
27 Cmd1 = 0x08, /* Command register 1 */
28 Cmd2 = 0x09, /* Command register 2 */
29 Status = 0x0A, /* Status */
30 Cram = 0x0B, /* Cursor RAM array data */
31 Cxlr = 0x0C, /* Cursor x-low register */
32 Cxhr = 0x0D, /* Cursor x-high register */
33 Cylr = 0x0E, /* Cursor y-low register */
34 Cyhr = 0x0F, /* Cursor y-high register */
35
36 Nreg = 0x10,
37
38 Cmd3 = 0x1A, /* Command register 3 */
39 Cmd4 = 0x2A, /* Command register 4 */
40 };
41
42 static uchar
bt485io(uchar reg)43 bt485io(uchar reg)
44 {
45 uchar crt55, cr0;
46
47 if(reg >= Nreg && (reg & 0x0F) != Status)
48 error("%s: bad reg - 0x%X\n", bt485.name, reg);
49
50 crt55 = vgaxi(Crtx, 0x55) & 0xFC;
51 if((reg & 0x0F) == Status){
52 /*
53 * 1,2: Set indirect addressing for Status or
54 * Cmd[34] - set bit7 of Cr0.
55 */
56 vgaxo(Crtx, 0x55, crt55|((Cmd0>>2) & 0x03));
57 cr0 = vgai(dacxreg[Cmd0 & 0x03])|0x80;
58 vgao(dacxreg[Cmd0 & 0x03], cr0);
59
60 /*
61 * 3,4: Set the index into the Write register,
62 * index == 0x00 for Status, 0x01 for Cmd3,
63 * 0x02 for Cmd4.
64 */
65 vgaxo(Crtx, 0x55, crt55|((AddrW>>2) & 0x03));
66 vgao(dacxreg[AddrW & 0x03], (reg>>4) & 0x0F);
67
68 /*
69 * 5,6: Get the contents of the appropriate
70 * register at 0x0A.
71 */
72 }
73
74 return crt55;
75 }
76
77 uchar
bt485i(uchar reg)78 bt485i(uchar reg)
79 {
80 uchar crt55, r;
81
82 crt55 = bt485io(reg);
83 vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
84 r = vgai(dacxreg[reg & 0x03]);
85 vgaxo(Crtx, 0x55, crt55);
86
87 return r;
88 }
89
90 void
bt485o(uchar reg,uchar data)91 bt485o(uchar reg, uchar data)
92 {
93 uchar crt55;
94
95 crt55 = bt485io(reg);
96 vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
97 vgao(dacxreg[reg & 0x03], data);
98 vgaxo(Crtx, 0x55, crt55);
99 }
100
101 static void
options(Vga *,Ctlr * ctlr)102 options(Vga*, Ctlr* ctlr)
103 {
104 ctlr->flag |= Hsid32|Hclk2|Hextsid|Henhanced|Foptions;
105 }
106
107 static void
init(Vga * vga,Ctlr * ctlr)108 init(Vga* vga, Ctlr* ctlr)
109 {
110 ulong grade;
111 char *p;
112
113 /*
114 * Work out the part speed-grade from name. Name can have,
115 * e.g. '-135' on the end for 135MHz part.
116 */
117 grade = 110000000;
118 if(p = strrchr(ctlr->name, '-'))
119 grade = strtoul(p+1, 0, 0) * 1000000;
120
121 /*
122 * If we don't already have a desired pclk,
123 * take it from the mode.
124 * Check it's within range.
125 */
126 if(vga->f[0] == 0)
127 vga->f[0] = vga->mode->frequency;
128 if(vga->f[0] > grade)
129 error("%s: invalid pclk - %ld\n", ctlr->name, vga->f[0]);
130
131 /*
132 * Determine whether to use clock-doubler or not.
133 */
134 if((ctlr->flag & Uclk2) == 0 && vga->f[0] > 67500000){
135 vga->f[0] /= 2;
136 resyncinit(vga, ctlr, Uclk2, 0);
137 }
138
139 ctlr->flag |= Finit;
140 }
141
142 static void
load(Vga *,Ctlr * ctlr)143 load(Vga*, Ctlr* ctlr)
144 {
145 uchar x;
146
147 /*
148 * Put the chip to sleep before (possibly) changing the clock-source
149 * to ensure the integrity of the palette.
150 */
151 x = bt485i(Cmd0);
152 bt485o(Cmd0, x|0x01); /* sleep mode */
153
154 /*
155 * Set the clock-source, clock-doubler and frequency
156 * appropriately:
157 * if using the pixel-port, use Pclock1;
158 * use the doubler if fvco > 67.5MHz.
159 * set the frequency.
160 */
161 x = bt485i(Cmd2);
162 if(ctlr->flag & Uenhanced)
163 x |= 0x10; /* Pclock1 */
164 else
165 x &= ~0x10;
166 bt485o(Cmd2, x);
167
168 x = bt485i(Cmd3);
169 if(ctlr->flag & Uclk2)
170 x |= 0x08; /* clock-doubler */
171 else
172 x &= ~0x08;
173 bt485o(Cmd3, x);
174
175 /*
176 * Set 4:1 multiplex and portselect bits on the
177 * Bt485 appropriately for using the pixel-port.
178 */
179 x = bt485i(Cmd2);
180 if(ctlr->flag & Uenhanced){
181 bt485o(Cmd1, 0x40); /* 4:1 multiplex */
182 x |= 0x20; /* portselect */
183 }
184 else{
185 bt485o(Cmd1, 0x00);
186 x &= ~0x20;
187 }
188 bt485o(Cmd2, x);
189
190 x = bt485i(Cmd4);
191 if(ctlr->flag & Uenhanced)
192 x |= 0x01;
193 else
194 x &= ~0x01;
195 bt485o(Cmd4, x);
196
197 /*
198 * All done, wake the chip back up.
199 * Set 6/8-bit colour as appropriate.
200 */
201 x = bt485i(Cmd0) & ~0x01;
202 /*if(vga->mode.z == 8)
203 x |= 0x02;
204 else*/
205 x &= ~0x02;
206 bt485o(Cmd0, x);
207
208 ctlr->flag |= Fload;
209 }
210
211 static void
dump(Vga *,Ctlr * ctlr)212 dump(Vga*, Ctlr* ctlr)
213 {
214 int i;
215
216 printitem(ctlr->name, "direct");
217 for(i = 0; i < 0x10; i++)
218 printreg(bt485i(i));
219 printitem(ctlr->name, "indirect");
220 printreg(bt485i(Cmd3));
221 printreg(bt485i(Cmd4));
222 }
223
224 Ctlr bt485 = {
225 "bt485", /* name */
226 0, /* snarf */
227 options, /* options */
228 init, /* init */
229 load, /* load */
230 dump, /* dump */
231 };
232