1 /* program the DAC */ 2 /* Author: 3 Rudolf Cornelissen 4/2003-4/2004 4 */ 5 6 #define MODULE_BIT 0x00010000 7 8 #include "nm_std.h" 9 10 /*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ 11 status_t nm_dac_mode(int mode,float brightness) 12 { 13 uint8 *r, *g, *b, t[256]; 14 uint16 i; 15 16 /*set colour arrays to point to space reserved in shared info*/ 17 r = si->color_data; 18 g = r + 256; 19 b = g + 256; 20 21 LOG(4,("DAC: Setting screen mode %d brightness %f\n", mode, brightness)); 22 /*init a basic palette for brightness specified*/ 23 for (i = 0; i < 256; i++) 24 { 25 int ri = i * brightness; 26 if (ri > 255) ri = 255; 27 t[i] = ri; 28 } 29 30 /*modify the palette for the specified mode (&validate mode)*/ 31 /* Note: the Neomagic chips have a 6 bit wide Palette RAM! */ 32 switch(mode) 33 { 34 case BPP8: 35 LOG(8,("DAC: 8bit mode is indexed by OS, aborting brightness setup.\n")); 36 return B_OK; 37 break; 38 case BPP24: 39 LOG(8,("DAC: 24bit mode is a direct mode, aborting brightness setup.\n")); 40 return B_OK; 41 //fixme: unnessesary? direct mode (6bits PAL RAM is insufficient here!) 42 /* for (i = 0; i < 256; i++) 43 { 44 b[i] = g[i] = r[i] = t[i]; 45 } 46 */ break; 47 case BPP16: 48 for (i = 0; i < 32; i++) 49 { 50 /* blue and red have only the 5 most significant bits */ 51 b[i] = r[i] = t[i << 3]; 52 } 53 for (i = 0; i < 64; i++) 54 { 55 /* the green component has 6 bits */ 56 g[i] = t[i << 2]; 57 } 58 break; 59 case BPP15: 60 for (i = 0; i < 32; i++) 61 { 62 /* all color components have 5 bits */ 63 g[i] = r[i] = b[i] = t[i << 3]; 64 } 65 break; 66 default: 67 LOG(8,("DAC: Invalid colordepth requested, aborting!\n")); 68 return B_ERROR; 69 break; 70 } 71 72 if (nm_dac_palette(r, g, b, i) != B_OK) return B_ERROR; 73 74 /*set the mode - also sets VCLK dividor*/ 75 // DXIW(MULCTRL, mode); 76 // LOG(2,("DAC: mulctrl 0x%02x\n", DXIR(MULCTRL))); 77 78 /* disable palette RAM adressing mask */ 79 ISAWB(PALMASK, 0xff); 80 LOG(2,("DAC: PAL pixrdmsk readback $%02x\n", ISARB(PALMASK))); 81 82 return B_OK; 83 } 84 85 /* program the DAC palette using the given r,g,b values */ 86 status_t nm_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256], uint16 cnt) 87 { 88 int i; 89 90 LOG(4,("DAC: setting palette\n")); 91 92 /* select first PAL adress before starting programming */ 93 ISAWB(PALINDW, 0x00); 94 95 /* loop through all 256 to program DAC */ 96 for (i = 0; i < cnt; i++) 97 { 98 /* the 6 implemented bits are on b0-b5 of the bus */ 99 ISAWB(PALDATA, (r[i] >> 2)); 100 ISAWB(PALDATA, (g[i] >> 2)); 101 ISAWB(PALDATA, (b[i] >> 2)); 102 } 103 if (ISARB(PALINDW) != (cnt & 0x00ff)) 104 { 105 LOG(8,("DAC: PAL write index incorrect after programming\n")); 106 return B_ERROR; 107 } 108 if (1) 109 {//reread LUT 110 uint8 R, G, B; 111 112 /* select first PAL adress to read (modulo 3 counter) */ 113 ISAWB(PALINDR, 0x00); 114 for (i = 0; i < cnt; i++) 115 { 116 /* the 6 implemented bits are on b0-b5 of the bus */ 117 R = (ISARB(PALDATA) << 2); 118 G = (ISARB(PALDATA) << 2); 119 B = (ISARB(PALDATA) << 2); 120 /* only compare the most significant 6 bits */ 121 if (((r[i] & 0xfc) != R) || ((g[i] & 0xfc) != G) || ((b[i] & 0xfc) != B)) 122 LOG(1,("DAC palette %d: w %x %x %x, r %x %x %x\n", i, r[i], g[i], b[i], R, G, B)); // apsed 123 } 124 } 125 126 return B_OK; 127 } 128 129 /*program the pixpll - frequency in kHz*/ 130 /* important note: 131 * PIXPLLC is used - others should be kept as is 132 */ 133 status_t nm_dac_set_pix_pll(display_mode target) 134 { 135 uint8 m=0,n=0,p=0; 136 uint8 temp; 137 // uint time = 0; 138 139 float pix_setting, req_pclk; 140 status_t result; 141 142 req_pclk = (target.timing.pixel_clock)/1000.0; 143 LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk)); 144 145 result = nm_dac_pix_pll_find(target,&pix_setting,&m,&n,&p); 146 if (result != B_OK) 147 { 148 return result; 149 } 150 151 /*reprogram (disable,select,wait for stability,enable)*/ 152 //unknown on Neomagic?: 153 // DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/ 154 // DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/ 155 156 /* select PixelPLL registerset C */ 157 temp = (ISARB(MISCR) | 0x0c); 158 /* we need to wait a bit or the card will mess-up it's register values.. */ 159 snooze(10); 160 ISAWB(MISCW, temp); 161 162 /*set VCO divider (lsb) */ 163 ISAGRPHW(PLLC_NL, n); 164 /*set VCO divider (msb) if it exists */ 165 if (si->ps.card_type >= NM2200) 166 { 167 temp = (ISAGRPHR(PLLC_NH) & 0x0f); 168 /* we need to wait a bit or the card will mess-up it's register values.. */ 169 snooze(10); 170 ISAGRPHW(PLLC_NH, (temp | (p & 0xf0))); 171 } 172 /*set main reference frequency divider */ 173 ISAGRPHW(PLLC_M, m); 174 175 /* Wait for the PIXPLL frequency to lock until timeout occurs */ 176 //unknown on Neomagic?: 177 /* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000)) 178 { 179 time++; 180 snooze(1); 181 } 182 183 if (time > 2000) 184 LOG(2,("DAC: PIX PLL frequency not locked!\n")); 185 else 186 LOG(2,("DAC: PIX PLL frequency locked\n")); 187 DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL 188 */ 189 190 //for now: 191 /* Give the PIXPLL frequency some time to lock... */ 192 snooze(1000); 193 LOG(4,("DAC: PLLSEL $%02x\n", ISARB(MISCR))); 194 LOG(4,("DAC: PLLN $%02x\n", ISAGRPHR(PLLC_NL))); 195 LOG(4,("DAC: PLLM $%02x\n", ISAGRPHR(PLLC_M))); 196 197 LOG(2,("DAC: PIX PLL frequency should be locked now...\n")); 198 199 return B_OK; 200 } 201 202 /* find nearest valid pix pll */ 203 status_t nm_dac_pix_pll_find 204 (display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result) 205 { 206 int m = 0, n = 0, p = 0, n_max, m_max; 207 float error, error_best = 999999999; 208 int best[2] = { 0, 0 }; 209 float f_vco, max_pclk; 210 float req_pclk = target.timing.pixel_clock/1000.0; 211 212 /* determine the max. scaler settings for the current card */ 213 switch (si->ps.card_type) 214 { 215 case NM2070: 216 LOG(4,("DAC: NM2070 restrictions apply\n")); 217 m_max = 32; 218 n_max = 128; 219 break; 220 case NM2090: 221 case NM2093: 222 case NM2097: 223 case NM2160: 224 LOG(4,("DAC: NM2090/93/97/NM2160 restrictions apply\n")); 225 m_max = 64; 226 n_max = 128; 227 break; 228 default: 229 LOG(4,("DAC: NM22xx/NM23xx restrictions apply\n")); 230 m_max = 64; 231 n_max = 2048; 232 break; 233 } 234 235 /* determine the max. pixelclock for the current videomode */ 236 switch (target.space) 237 { 238 case B_CMAP8: 239 max_pclk = si->ps.max_dac1_clock_8; 240 break; 241 case B_RGB15_LITTLE: 242 case B_RGB16_LITTLE: 243 max_pclk = si->ps.max_dac1_clock_16; 244 break; 245 case B_RGB24_LITTLE: 246 max_pclk = si->ps.max_dac1_clock_24; 247 break; 248 default: 249 /* use fail-safe value */ 250 max_pclk = si->ps.max_dac1_clock_24; 251 break; 252 } 253 254 /* Make sure the requested pixelclock is within the PLL's operational limits */ 255 /* lower limit is min_pixel_vco (PLL postscaler does not exist in NM cards) */ 256 if (req_pclk < si->ps.min_pixel_vco) 257 { 258 LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", 259 req_pclk, (float)si->ps.min_pixel_vco)); 260 req_pclk = si->ps.min_pixel_vco; 261 } 262 /* upper limit is given by pins in combination with current active mode */ 263 if (req_pclk > max_pclk) 264 { 265 LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", 266 req_pclk, (float)max_pclk)); 267 req_pclk = max_pclk; 268 } 269 270 /* calculate the needed VCO frequency for this postscaler setting 271 * (NM cards have no PLL postscaler) */ 272 f_vco = req_pclk; 273 274 /* iterate trough all valid reference-frequency postscaler settings */ 275 for (m = 1; m <= m_max; m++) 276 { 277 /* only even reference postscaler settings are supported beyond half the range */ 278 if ((m > (m_max / 2)) && ((m / 2.0) != 0.0)) continue; 279 /* calculate VCO postscaler setting for current setup.. */ 280 n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); 281 /* ..and check for validity */ 282 if ((n < 1) || (n > n_max)) continue; 283 284 /* find error in frequency this setting gives */ 285 error = fabs(req_pclk - ((si->ps.f_ref / m) * n)); 286 287 /* note the setting if best yet */ 288 if (error < error_best) 289 { 290 error_best = error; 291 best[0] = m; 292 best[1] = n; 293 } 294 } 295 296 /* setup the scalers programming values for found optimum setting */ 297 n = best[1] - 1; 298 /* the reference frequency postscaler are actually two postscalers: 299 * p can divide by 1 or 2, and m can divide by 1-32 (1-16 for NM2070). */ 300 if (best[0] <= (m_max / 2)) 301 { 302 m = best[0] - 1; 303 p = (0 << 7); 304 } 305 else 306 { 307 m = (best[0] / 2) - 1; 308 p = (1 << 7); 309 } 310 311 /* display and return the results */ 312 *calc_pclk = (si->ps.f_ref / best[0]) * best[1]; 313 *m_result = m; 314 if (si->ps.card_type < NM2200) 315 { 316 *n_result = ((n & 0x07f) | p); 317 *p_result = 0; 318 LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, nm $%02x $%02x\n", 319 req_pclk, *calc_pclk, *n_result, *m_result)); 320 } 321 else 322 { 323 *n_result = (n & 0x0ff); 324 *p_result = (((n & 0x700) >> 4) | p); 325 LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, pnm $%02x $%02x $%02x\n", 326 req_pclk, *calc_pclk, *p_result, *n_result, *m_result)); 327 } 328 329 return B_OK; 330 } 331