/* program the DAC */ /* Author: Rudolf Cornelissen 4/2003-4/2004 */ #define MODULE_BIT 0x00010000 #include "nm_std.h" /*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/ status_t nm_dac_mode(int mode,float brightness) { uint8 *r, *g, *b, t[256]; uint16 i; /*set colour arrays to point to space reserved in shared info*/ r = si->color_data; g = r + 256; b = g + 256; LOG(4,("DAC: Setting screen mode %d brightness %f\n", mode, brightness)); /*init a basic palette for brightness specified*/ for (i = 0; i < 256; i++) { int ri = i * brightness; if (ri > 255) ri = 255; t[i] = ri; } /*modify the palette for the specified mode (&validate mode)*/ /* Note: the Neomagic chips have a 6 bit wide Palette RAM! */ switch(mode) { case BPP8: LOG(8,("DAC: 8bit mode is indexed by OS, aborting brightness setup.\n")); return B_OK; break; case BPP24: LOG(8,("DAC: 24bit mode is a direct mode, aborting brightness setup.\n")); return B_OK; //fixme: unnessesary? direct mode (6bits PAL RAM is insufficient here!) /* for (i = 0; i < 256; i++) { b[i] = g[i] = r[i] = t[i]; } */ break; case BPP16: for (i = 0; i < 32; i++) { /* blue and red have only the 5 most significant bits */ b[i] = r[i] = t[i << 3]; } for (i = 0; i < 64; i++) { /* the green component has 6 bits */ g[i] = t[i << 2]; } break; case BPP15: for (i = 0; i < 32; i++) { /* all color components have 5 bits */ g[i] = r[i] = b[i] = t[i << 3]; } break; default: LOG(8,("DAC: Invalid colordepth requested, aborting!\n")); return B_ERROR; break; } if (nm_dac_palette(r, g, b, i) != B_OK) return B_ERROR; /*set the mode - also sets VCLK dividor*/ // DXIW(MULCTRL, mode); // LOG(2,("DAC: mulctrl 0x%02x\n", DXIR(MULCTRL))); /* disable palette RAM adressing mask */ ISAWB(PALMASK, 0xff); LOG(2,("DAC: PAL pixrdmsk readback $%02x\n", ISARB(PALMASK))); return B_OK; } /* program the DAC palette using the given r,g,b values */ status_t nm_dac_palette(uint8 r[256],uint8 g[256],uint8 b[256], uint16 cnt) { int i; LOG(4,("DAC: setting palette\n")); /* select first PAL adress before starting programming */ ISAWB(PALINDW, 0x00); /* loop through all 256 to program DAC */ for (i = 0; i < cnt; i++) { /* the 6 implemented bits are on b0-b5 of the bus */ ISAWB(PALDATA, (r[i] >> 2)); ISAWB(PALDATA, (g[i] >> 2)); ISAWB(PALDATA, (b[i] >> 2)); } if (ISARB(PALINDW) != (cnt & 0x00ff)) { LOG(8,("DAC: PAL write index incorrect after programming\n")); return B_ERROR; } if (1) {//reread LUT uint8 R, G, B; /* select first PAL adress to read (modulo 3 counter) */ ISAWB(PALINDR, 0x00); for (i = 0; i < cnt; i++) { /* the 6 implemented bits are on b0-b5 of the bus */ R = (ISARB(PALDATA) << 2); G = (ISARB(PALDATA) << 2); B = (ISARB(PALDATA) << 2); /* only compare the most significant 6 bits */ if (((r[i] & 0xfc) != R) || ((g[i] & 0xfc) != G) || ((b[i] & 0xfc) != B)) 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 } } return B_OK; } /*program the pixpll - frequency in kHz*/ /* important note: * PIXPLLC is used - others should be kept as is */ status_t nm_dac_set_pix_pll(display_mode target) { uint8 m=0,n=0,p=0; uint8 temp; // uint time = 0; float pix_setting, req_pclk; status_t result; req_pclk = (target.timing.pixel_clock)/1000.0; LOG(4,("DAC: Setting PIX PLL for pixelclock %f\n", req_pclk)); result = nm_dac_pix_pll_find(target,&pix_setting,&m,&n,&p); if (result != B_OK) { return result; } /*reprogram (disable,select,wait for stability,enable)*/ //unknown on Neomagic?: // DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0F)|0x04); /*disable the PIXPLL*/ // DXIW(PIXCLKCTRL,(DXIR(PIXCLKCTRL)&0x0C)|0x01); /*select the PIXPLL*/ /* select PixelPLL registerset C */ temp = (ISARB(MISCR) | 0x0c); /* we need to wait a bit or the card will mess-up it's register values.. */ snooze(10); ISAWB(MISCW, temp); /*set VCO divider (lsb) */ ISAGRPHW(PLLC_NL, n); /*set VCO divider (msb) if it exists */ if (si->ps.card_type >= NM2200) { temp = (ISAGRPHR(PLLC_NH) & 0x0f); /* we need to wait a bit or the card will mess-up it's register values.. */ snooze(10); ISAGRPHW(PLLC_NH, (temp | (p & 0xf0))); } /*set main reference frequency divider */ ISAGRPHW(PLLC_M, m); /* Wait for the PIXPLL frequency to lock until timeout occurs */ //unknown on Neomagic?: /* while((!(DXIR(PIXPLLSTAT)&0x40)) & (time <= 2000)) { time++; snooze(1); } if (time > 2000) LOG(2,("DAC: PIX PLL frequency not locked!\n")); else LOG(2,("DAC: PIX PLL frequency locked\n")); DXIW(PIXCLKCTRL,DXIR(PIXCLKCTRL)&0x0B); //enable the PIXPLL */ //for now: /* Give the PIXPLL frequency some time to lock... */ snooze(1000); LOG(4,("DAC: PLLSEL $%02x\n", ISARB(MISCR))); LOG(4,("DAC: PLLN $%02x\n", ISAGRPHR(PLLC_NL))); LOG(4,("DAC: PLLM $%02x\n", ISAGRPHR(PLLC_M))); LOG(2,("DAC: PIX PLL frequency should be locked now...\n")); return B_OK; } /* find nearest valid pix pll */ status_t nm_dac_pix_pll_find (display_mode target,float * calc_pclk,uint8 * m_result,uint8 * n_result,uint8 * p_result) { int m = 0, n = 0, p = 0, n_max, m_max; float error, error_best = 999999999; int best[2] = { 0, 0 }; float f_vco, max_pclk; float req_pclk = target.timing.pixel_clock/1000.0; /* determine the max. scaler settings for the current card */ switch (si->ps.card_type) { case NM2070: LOG(4,("DAC: NM2070 restrictions apply\n")); m_max = 32; n_max = 128; break; case NM2090: case NM2093: case NM2097: case NM2160: LOG(4,("DAC: NM2090/93/97/NM2160 restrictions apply\n")); m_max = 64; n_max = 128; break; default: LOG(4,("DAC: NM22xx/NM23xx restrictions apply\n")); m_max = 64; n_max = 2048; break; } /* determine the max. pixelclock for the current videomode */ switch (target.space) { case B_CMAP8: max_pclk = si->ps.max_dac1_clock_8; break; case B_RGB15_LITTLE: case B_RGB16_LITTLE: max_pclk = si->ps.max_dac1_clock_16; break; case B_RGB24_LITTLE: max_pclk = si->ps.max_dac1_clock_24; break; default: /* use fail-safe value */ max_pclk = si->ps.max_dac1_clock_24; break; } /* Make sure the requested pixelclock is within the PLL's operational limits */ /* lower limit is min_pixel_vco (PLL postscaler does not exist in NM cards) */ if (req_pclk < si->ps.min_pixel_vco) { LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", req_pclk, (float)si->ps.min_pixel_vco)); req_pclk = si->ps.min_pixel_vco; } /* upper limit is given by pins in combination with current active mode */ if (req_pclk > max_pclk) { LOG(4,("DAC: clamping pixclock: requested %fMHz, set to %fMHz\n", req_pclk, (float)max_pclk)); req_pclk = max_pclk; } /* calculate the needed VCO frequency for this postscaler setting * (NM cards have no PLL postscaler) */ f_vco = req_pclk; /* iterate trough all valid reference-frequency postscaler settings */ for (m = 1; m <= m_max; m++) { /* only even reference postscaler settings are supported beyond half the range */ if ((m > (m_max / 2)) && ((m / 2.0) != 0.0)) continue; /* calculate VCO postscaler setting for current setup.. */ n = (int)(((f_vco * m) / si->ps.f_ref) + 0.5); /* ..and check for validity */ if ((n < 1) || (n > n_max)) continue; /* find error in frequency this setting gives */ error = fabs(req_pclk - ((si->ps.f_ref / m) * n)); /* note the setting if best yet */ if (error < error_best) { error_best = error; best[0] = m; best[1] = n; } } /* setup the scalers programming values for found optimum setting */ n = best[1] - 1; /* the reference frequency postscaler are actually two postscalers: * p can divide by 1 or 2, and m can divide by 1-32 (1-16 for NM2070). */ if (best[0] <= (m_max / 2)) { m = best[0] - 1; p = (0 << 7); } else { m = (best[0] / 2) - 1; p = (1 << 7); } /* display and return the results */ *calc_pclk = (si->ps.f_ref / best[0]) * best[1]; *m_result = m; if (si->ps.card_type < NM2200) { *n_result = ((n & 0x07f) | p); *p_result = 0; LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, nm $%02x $%02x\n", req_pclk, *calc_pclk, *n_result, *m_result)); } else { *n_result = (n & 0x0ff); *p_result = (((n & 0x700) >> 4) | p); LOG(2,("DAC: pix PLL check: requested %fMHz got %fMHz, pnm $%02x $%02x $%02x\n", req_pclk, *calc_pclk, *p_result, *n_result, *m_result)); } return B_OK; }