1 /*
2 Program the Texas TVP3026
3 using Texas Instrument TVP3026 manual SLA098B July 1996
4
5 Authors:
6 Apsed May 2002 plus a lot of time after;
7 Rudolf Cornelissen 3/2003.
8 */
9
10 #define MODULE_BIT 0x00010000
11
12 #include <OS.h> // system_time, snooze
13 #include "mga_std.h"
14
15 #define FVCO_MIN 110.00000 // MHz
16 #define FPLL_MCLK 100.00000 // MHz
17
18 //r: ??
19 #define MGAVGA_INSTS0 0x1FC2
20
21 #define WAIT_FOR_PLL_LOCK( pll, on_error) do { \
22 bigtime_t start, now; \
23 float delay; \
24 int tmo; \
25 \
26 start = system_time(); \
27 for (tmo = 0; tmo < 100 * 1000 * 1000; tmo++) { \
28 int status = DXIR (pll ## PLLDATA); \
29 if (status & 0x40) break; \
30 /* snooze(10); */ \
31 } \
32 now = system_time(); \
33 delay = (now - start) / 1000.0; \
34 LOG(2,("mil2 %s PLL locked in %fms for %d loops\n", #pll, delay, tmo)); \
35 if (tmo == 100 * 1000 * 1000) { \
36 LOG(8,("mil2 %s PLL not locked in %fms for %d loops\n", #pll, delay, tmo)); \
37 on_error; \
38 } \
39 } while (0)
40
41 /*program the pixpll - frequency in MHz*/
mil2_dac_set_pix_pll(float f_need,int bpp)42 status_t mil2_dac_set_pix_pll (float f_need, int bpp)
43 {
44 uint8 n, m, p, q;
45 int z, k;
46 float fd;
47 status_t result;
48
49 display_mode target;
50 target.timing.pixel_clock = (f_need * 1000);
51
52 LOG(4,("mil2_dac_set_pix_pll need %fMHz, %dbpp\n", f_need, bpp));
53 result = gx00_dac_pix_pll_find(target, &fd, &m, &n, &p, 0);
54 if (result != B_OK) return result;
55
56 // follows (!strictly) Appendix C, extended mode setup
57 // 1st stop the PLLs,
58 switch (bpp) {
59 case 8: DXIW(TVP_CLOCKSEL, 0x25); break;
60 case 16: DXIW(TVP_CLOCKSEL, 0x15); break;
61 case 24: DXIW(TVP_CLOCKSEL, 0x25); break;
62 case 32: DXIW(TVP_CLOCKSEL, 0x05); break;
63 default: return B_ERROR;
64 }
65 DXIW(TVP_PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
66 DXIW(TVP_LOOPLLDATA, 0x00); // 0x2f: 2.4.1 ... stop the loop PLL
67 DXIW(TVP_PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the pixel PLL
68 VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x
69
70 // 2nd setup the pixel PLL
71 LOG(2,("mil2_dac_set_pix_pll pix PLL, nmp 0x%02x 0x%02x 0x%02x\n",
72 n, m, p));
73 DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
74 DXIW(TVP_PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
75 DXIW(TVP_PIXPLLDATA, m);
76 DXIW(TVP_PIXPLLDATA, p | 0xb0);
77 WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR); // ... wait for PLL lock
78
79 // now compute parameters for the loop PLL (24bpp not available) see 2.4.3.1
80 k = 1; // ?? external division factor between RCLK and LCLK
81 // does 32bit DAC path exists for MIL1/2? if so, do this via si->ps...
82 // n = (65 - (4 * (PIXEL_BUS_WIDTH64? 64: 32)) / bpp);
83 n = (65 - (4 * 64) / bpp);
84 m = 61;
85 z = (FVCO_MIN * (65 - n)) / (4 * fd * k);
86 q = 0;
87 if (z < 2) p = 0; // this is TRUNC (log2 (z))
88 else if (z < 4) p = 1;
89 else if (z < 8) p = 2;
90 else if (z < 16) p = 3;
91 else { // but not this
92 p = 3;
93 q = 1 + (z - 16) / 16;
94 }
95 LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
96 n, m, p, q));
97 DXIW(TVP_MEMCLKCTRL, (DXIR(TVP_MEMCLKCTRL) & 0xf8) | q | 0x20); // 0x39: 2.4.2 table 2.13
98 LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
99 n, m, p, q));
100
101 // now setup the loop PLL
102 LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
103 n, m, p, q));
104 DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
105 DXIW(TVP_LOOPLLDATA, n | 0xc0); // 0x2f: ... load n, m, p and ...
106 DXIW(TVP_LOOPLLDATA, m);
107 DXIW(TVP_LOOPLLDATA, p | 0xf0);
108 WAIT_FOR_PLL_LOCK (TVP_LOO, return B_ERROR); // ... wait for PLL lock
109
110 return B_OK;
111 }
112
113 // set MEM clock MCLK , shall be <= 100MHz
mil2_dac_set_mem_pll(float f_need,float * mclk)114 static status_t mil2_dac_set_mem_pll (float f_need, float *mclk)
115 {
116 status_t status;
117 uint8 n, m, p;
118 uint8 n_pix, m_pix, p_pix;
119 uint8 memclkctrl;
120
121 display_mode target;
122 target.timing.pixel_clock = (f_need * 1000);
123
124 LOG(4,("mil2_dac_set_sys_pll need %fMHz\n", f_need));
125 //fixme: MIL has same restrictions for pixel and system PLL, so Apsed did this:
126 status = gx00_dac_pix_pll_find(target, mclk, &m, &n, &p, 0);
127 if (status != B_OK) return status;
128
129 // follows (!strictly) TVP3026 2.4.2.1, extended mode setup
130
131 // 0) save PIXPLL nmp to restore it at end
132 DXIW(TVP_PLLADDR, 0x00);
133 n_pix = DXIR(TVP_PIXPLLDATA);
134 DXIW(TVP_PLLADDR, 0x15);
135 m_pix = DXIR(TVP_PIXPLLDATA);
136 DXIW(TVP_PLLADDR, 0x2a);
137 p_pix = DXIR(TVP_PIXPLLDATA);
138
139 // 1) disable pixel PLL, set pixel PLL at MCLK freq and poll for lock
140 DXIW(TVP_PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
141 DXIW(TVP_PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the PLL
142 DXIW(TVP_PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
143 DXIW(TVP_PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
144 DXIW(TVP_PIXPLLDATA, m);
145 DXIW(TVP_PIXPLLDATA, p | 0xb0);
146 WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR); // ... wait for PLL lock
147
148 // 2) select pixel clock as dot clock source
149 VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x
150
151 // 3) output dot clock on MCLK pin
152 memclkctrl = DXIR(TVP_MEMCLKCTRL) & 0xe7;
153 DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x00 << 3));
154 DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x01 << 3));
155
156 // 4) disable mem PLL, set mem PLL at MCLK freq and poll for lock
157 DXIW(TVP_PLLADDR, 0x2a);
158 DXIW(TVP_MEMPLLDATA, 0x00);
159 DXIW(TVP_PLLADDR, 0x00);
160 DXIW(TVP_MEMPLLDATA, n | 0xc0);
161 DXIW(TVP_MEMPLLDATA, m);
162 DXIW(TVP_MEMPLLDATA, p | 0xb0);
163 WAIT_FOR_PLL_LOCK (TVP_MEM, return B_ERROR);
164
165 // 5) output mem clock on MCLK pin
166 DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x02 << 3));
167 DXIW(TVP_MEMCLKCTRL, memclkctrl | (0x03 << 3));
168
169 // 6) restaure pixel clock as it was
170 DXIW(TVP_PLLADDR, 0x2a);
171 DXIW(TVP_PIXPLLDATA, 0x00);
172 DXIW(TVP_PLLADDR, 0x00);
173 DXIW(TVP_PIXPLLDATA, n_pix | 0xc0);
174 DXIW(TVP_PIXPLLDATA, m_pix);
175 DXIW(TVP_PIXPLLDATA, p_pix | 0xb0);
176 WAIT_FOR_PLL_LOCK (TVP_PIX, return B_ERROR);
177
178 return B_OK;
179 }
180
181 /* initialize TVP3026: memory clock PLL ... */
mil2_dac_init(void)182 status_t mil2_dac_init (void)
183 {
184 status_t status;
185 float need = 60.0; // MHz FPLL_MCLK
186 float mclk;
187 uint32 option;
188 uint32 rfhcnt, nogscale, memconfig;
189
190 LOG(4, ("mil2_dac_init MISC 0x%02x\n", VGAR(MISCR)));
191 CFGW(DEVCTRL,(2|CFGR(DEVCTRL))); // enable device response (already enabled here!)
192 VGAW_I(CRTC,0x11,0); // allow me to change CRTC
193 VGAW_I(CRTCEXT,3,0x80); // use powergraphix (+ trash other bits, they are set later)
194 VGAW(MISCW,0x08); // set MGA pixel clock in MISC - PLLSEL10 of TVP3026 is 1X
195
196 // set MEM clock MCLK following TVP3026 2.4.2.1
197 status = mil2_dac_set_mem_pll (need, &mclk); //FPLL_MCLK);
198 if (status != B_OK) return status;
199
200 // update OPTION for refresh count following page 3-18
201 // 33.2mus >= (rfhcnt31*512 + rfhcnt0*64 + 1)*gclk_period*factor
202 // rfhcnt31*512 + rfhcnt0*64 <= -1 + 33.2mus*mclk/factor
203 if (1) {
204 int mclk_p = 1;
205 int nogscale = 1;
206 int f_pll = mclk * 1000 * 333 / (10000 << mclk_p);
207 int rfhcnt = (f_pll - 128) / 256;
208 if (rfhcnt > 15) rfhcnt = 15;
209 LOG(2,("mil2_dac_init: refresh count %d nogscale %d for %fMHz\n",
210 rfhcnt, nogscale, mclk));
211 }
212 for (nogscale = 1; nogscale >= 0; nogscale--) {
213 int max = -1 + 33.2 * mclk / (nogscale? 1: 4);
214 for (rfhcnt = 15; rfhcnt > 0; rfhcnt--) {
215 int value = (rfhcnt & 0x0e) * 256 + (rfhcnt & 0x01) * 64;
216 LOG(2,("mil2_dac_init factor %d, rfhcnt %2d: %d ?<= %d\n",
217 nogscale, rfhcnt, value, max));
218 if (value <= max) goto rfhcnt_found;
219 }
220 }
221 LOG(8,("mil2_dac_init: cant get valid refresh count for %fMHz\n", mclk));
222 return B_ERROR;
223 rfhcnt_found:
224 LOG(2,("mil2_dac_init: found refresh count %d nogscale %d for %fMHz\n",
225 rfhcnt, nogscale, mclk));
226
227 memconfig = 0x01; // worst case scenario: 64 bits RAMDAC (= tvp3026m) with >2Mb RAM.
228 option = CFGR(OPTION) & 0xffd0cfff;
229 CFGW(OPTION, option | (nogscale << 21) | (rfhcnt << 16) | (memconfig << 12));
230 LOG(2,("mil2_dac_init: OPTION 0x%08x\n", CFGR(OPTION)));
231
232 //r: select indirect cursor control register and set defaults
233 DXIW(CURCTRL, 0x00);
234 return B_OK;
235 }
236