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*/ 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 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 ... */ 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