openBeOS_Matrox_V0.13beta1_src
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5533 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,668 @@
|
||||
/*
|
||||
Program the Texas TVP3026
|
||||
using Texas Instrument TVP3026 manual SLA098B July 1996
|
||||
|
||||
Author:
|
||||
Apsed May 2002 a lot of time after ...
|
||||
|
||||
NB BPP24 and BPP32DIR not tested
|
||||
*/
|
||||
|
||||
#define MODULE_BIT 0x00010000
|
||||
|
||||
#include <OS.h> // system_time, snooze
|
||||
#include "mga_std.h"
|
||||
|
||||
#define PIXEL_BUS_WIDTH64 0 // if 0: 32 bits width, else 64
|
||||
#define PIXEL_BUS_WIDTH64 1 // if 0: 32 bits width, else 64
|
||||
|
||||
#define FPLL_REF 14.31818 // MHz
|
||||
#define FVCO_MAX 220.00000 // MHz, may be 220 or 250, see 3.5
|
||||
#define FVCO_MIN 110.00000 // MHz
|
||||
#define FPLL_MCLK 100.00000 // MHz
|
||||
|
||||
#define MGAVGA_INSTS0 0x1FC2
|
||||
|
||||
// access the TVP3026, this is near G200 DAC but ...
|
||||
|
||||
/* direct registers */
|
||||
#define TVP_PALWTADD 0x3c00
|
||||
#define TVP_PALDATA 0x3c01
|
||||
#define TVP_PIXRDMSK 0x3c02
|
||||
#define TVP_PALRDADD 0x3c03
|
||||
#define TVP_CUROVRWTADD 0x3c04
|
||||
#define TVP_CUROVRDATA 0x3c05
|
||||
#define TVP_CUROVRRDADD 0x3c07
|
||||
#define TVP_DIRCURCTRL 0x3c09
|
||||
#define TVP_X_DATAREG 0x3c0a
|
||||
#define TVP_CURRAMDATA 0x3c0b
|
||||
#define TVP_CURPOSXL 0x3c0c
|
||||
#define TVP_CURPOSXH 0x3c0d
|
||||
#define TVP_CURPOSYL 0x3c0e
|
||||
#define TVP_CURPOSYH 0x3c0f
|
||||
|
||||
/* indirect registers */
|
||||
#define TVPI_SILICONREV 0x01
|
||||
#define TVPI_INDCURCTRL 0x06
|
||||
#define TVPI_LATCHCTRL 0x0f
|
||||
#define TVPI_TCOLCTRL 0x18
|
||||
#define TVPI_MULCTRL 0x19
|
||||
#define TVPI_CLOCKSEL 0x1a
|
||||
#define TVPI_PALPAGE 0x1c
|
||||
#define TVPI_GENCTRL 0x1d
|
||||
#define TVPI_MISCCTRL 0x1e
|
||||
#define TVPI_GENIOCTRL 0x2a
|
||||
#define TVPI_GENIODATA 0x2b
|
||||
#define TVPI_PLLADDR 0x2c
|
||||
#define TVPI_PIXPLLDATA 0x2d
|
||||
#define TVPI_MEMPLLDATA 0x2e
|
||||
#define TVPI_LOOPLLDATA 0x2f
|
||||
#define TVPI_COLKEYOL 0x30
|
||||
#define TVPI_COLKEYOH 0x31
|
||||
#define TVPI_COLKEYRL 0x32
|
||||
#define TVPI_COLKEYRH 0x33
|
||||
#define TVPI_COLKEYGL 0x34
|
||||
#define TVPI_COLKEYGH 0x35
|
||||
#define TVPI_COLKEYBL 0x36
|
||||
#define TVPI_COLKEYBH 0x37
|
||||
#define TVPI_COLKEYCTRL 0x38
|
||||
#define TVPI_MEMCLKCTRL 0x39
|
||||
#define TVPI_SENSETEST 0x3a
|
||||
#define TVPI_TESTMODEDATA 0x3b
|
||||
#define TVPI_CRCREML 0x3c
|
||||
#define TVPI_CRCREMH 0x3d
|
||||
#define TVPI_CRCBITSEL 0x3e
|
||||
#define TVPI_ID 0x3f
|
||||
#define TVPI_RESET 0xff
|
||||
|
||||
/*read and write from the TVP3026 registers*/
|
||||
#define TVPR(A) (MGA_REG8(TVP_##A))
|
||||
#define TVPW(A,B) (MGA_REG8(TVP_##A)=B)
|
||||
|
||||
/*read and write from the TVP3026 indirect register*/
|
||||
#define TVPIR(A) (TVPW(PALWTADD,TVPI_##A),TVPR(X_DATAREG))
|
||||
#define TVPIW(A,B) (TVPW(PALWTADD,TVPI_##A),TVPW(X_DATAREG,B))
|
||||
|
||||
#define WAIT_FOR_PLL_LOCK( pll, on_error) do { \
|
||||
bigtime_t start, now; \
|
||||
float delay; \
|
||||
int tmo; \
|
||||
\
|
||||
start = system_time(); \
|
||||
for (tmo = 0; tmo < 100 * 1000 * 1000; tmo++) { \
|
||||
int status = TVPIR (pll ## PLLDATA); \
|
||||
if (status & 0x40) break; \
|
||||
/* snooze(10); */ \
|
||||
} \
|
||||
now = system_time(); \
|
||||
delay = (now - start) / 1000.0; \
|
||||
LOG(2,("mil2 %s PLL locked in %fms for %d loops\n", #pll, delay, tmo)); \
|
||||
if (tmo == 100 * 1000 * 1000) { \
|
||||
LOG(8,("mil2 %s PLL not locked in %fms for %d loops\n", #pll, delay, tmo)); \
|
||||
on_error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define REREAD_PLL( pll) do { \
|
||||
uint8 n, m, p; \
|
||||
float f, vco; \
|
||||
\
|
||||
TVPIW(PLLADDR, 0x00); \
|
||||
n = TVPIR(pll ## PLLDATA); \
|
||||
TVPIW(PLLADDR, 0x15); \
|
||||
m = TVPIR(pll ## PLLDATA); \
|
||||
TVPIW(PLLADDR, 0x2a); \
|
||||
p = TVPIR(pll ## PLLDATA); \
|
||||
vco = 8 * FPLL_REF * (65 - (m & 0x3f)) / (65 - (n & 0x3f)); \
|
||||
f = vco / (1 << (p & 0x03)); \
|
||||
LOG(2,("mil2 reread %s PLL, nmp 0x%02x 0x%02x 0x%02x, %fMHz, vco %fMHz\n", \
|
||||
#pll, n, m, p, f, vco)); \
|
||||
} while (0)
|
||||
|
||||
#define DUMP_CFG(reg) MSG(( \
|
||||
"PCI CONFIG register 0x%04x %20s 0x%08x\n", MGACFG_##reg, #reg, CFGR(reg)))
|
||||
#define DUMP_VGA(reg) MSG(( \
|
||||
"MGA VGA register 0x%04x %20s 0x%02x\n", MGAVGA_##reg, #reg, VGAR(reg)))
|
||||
#define DUMP_VGA_ATTR(reg) MSG(( \
|
||||
"MGA VGA ATTR register 0x%04x %20s 0x%02x\n", 0x##reg, "ATTR" #reg, VGAR_I(ATTR, 0x##reg)))
|
||||
#define DUMP_VGA_SEQ(reg) MSG(( \
|
||||
"MGA VGA SEQ register 0x%04x %20s 0x%02x\n", 0x##reg, "SEQ" #reg, VGAR_I(SEQ, 0x##reg)))
|
||||
#define DUMP_VGA_GCTL(reg) MSG(( \
|
||||
"MGA VGA GCTL register 0x%04x %20s 0x%02x\n", 0x##reg, "GCTL" #reg, VGAR_I(GCTL, 0x##reg)))
|
||||
#define DUMP_VGA_CRTC(reg) MSG(( \
|
||||
"MGA VGA CRTC register 0x%04x %20s 0x%02x\n", 0x##reg, "CRTC" #reg, VGAR_I(CRTC, 0x##reg)))
|
||||
#define DUMP_VGA_CRTCEXT(reg) MSG(( \
|
||||
"MGA VGA CRTCEXT register 0x%04x %20s 0x%02x\n", 0x##reg, "CRTCEXT" #reg, VGAR_I(CRTCEXT, 0x##reg)))
|
||||
#define DUMP_TVP(reg) MSG(( \
|
||||
"TVP3028 register 0x%04x %20s 0x%02x\n", TVP_##reg, #reg, TVPR(reg)))
|
||||
#define DUMP_TVPI(reg) MSG(( \
|
||||
"TVP3028 INDIRECT register 0x%04x %20s 0x%02x\n", TVPI_##reg, #reg, TVPIR(reg)))
|
||||
#define DUMP_MGA(reg) MSG(( \
|
||||
"MGA register 0x%04x %20s 0x%08x\n", MGAACC_##reg, #reg, ACCR(reg)))
|
||||
|
||||
static void dump_tvp3026 (void)
|
||||
{
|
||||
/* TVP3026 DAC direct registers */
|
||||
// DUMP_TVP (PALWTADD);
|
||||
// DUMP_TVP (PALDATA );
|
||||
DUMP_TVP (PIXRDMSK);
|
||||
// DUMP_TVP (PALRDADD);
|
||||
DUMP_TVP (CUROVRWTADD);
|
||||
DUMP_TVP (CUROVRDATA);
|
||||
DUMP_TVP (CUROVRRDADD);
|
||||
DUMP_TVP (DIRCURCTRL);
|
||||
// DUMP_TVP (X_DATAREG);
|
||||
DUMP_TVP (CURRAMDATA);
|
||||
DUMP_TVP (CURPOSXL);
|
||||
DUMP_TVP (CURPOSXH);
|
||||
DUMP_TVP (CURPOSYL);
|
||||
DUMP_TVP (CURPOSYH);
|
||||
|
||||
/* TVP3026 DAC indirect registers */
|
||||
DUMP_TVPI (SILICONREV);
|
||||
DUMP_TVPI (INDCURCTRL);
|
||||
DUMP_TVPI (LATCHCTRL);
|
||||
DUMP_TVPI (TCOLCTRL);
|
||||
DUMP_TVPI (MULCTRL);
|
||||
DUMP_TVPI (CLOCKSEL);
|
||||
DUMP_TVPI (PALPAGE);
|
||||
DUMP_TVPI (GENCTRL);
|
||||
DUMP_TVPI (MISCCTRL);
|
||||
DUMP_TVPI (GENIOCTRL);
|
||||
DUMP_TVPI (GENIODATA);
|
||||
// DUMP_TVPI (PLLADDR);
|
||||
// DUMP_TVPI (PIXPLLDATA);
|
||||
// DUMP_TVPI (MEMPLLDATA);
|
||||
// DUMP_TVPI (LOOPLLDATA);
|
||||
REREAD_PLL (PIX);
|
||||
REREAD_PLL (MEM);
|
||||
REREAD_PLL (LOO);
|
||||
DUMP_TVPI (COLKEYOL);
|
||||
DUMP_TVPI (COLKEYOH);
|
||||
DUMP_TVPI (COLKEYRL);
|
||||
DUMP_TVPI (COLKEYRH);
|
||||
DUMP_TVPI (COLKEYGL);
|
||||
DUMP_TVPI (COLKEYGH);
|
||||
DUMP_TVPI (COLKEYBL);
|
||||
DUMP_TVPI (COLKEYBH);
|
||||
DUMP_TVPI (COLKEYCTRL);
|
||||
DUMP_TVPI (MEMCLKCTRL);
|
||||
DUMP_TVPI (SENSETEST);
|
||||
DUMP_TVPI (TESTMODEDATA);
|
||||
DUMP_TVPI (CRCREML);
|
||||
DUMP_TVPI (CRCREMH);
|
||||
// DUMP_TVPI (CRCBITSEL); // WO
|
||||
DUMP_TVPI (ID);
|
||||
// DUMP_TVPI (RESET); // WO
|
||||
}
|
||||
|
||||
static void dump_mil2 (void)
|
||||
{
|
||||
/* PCI_config_space */
|
||||
DUMP_CFG (DEVID);
|
||||
DUMP_CFG (DEVCTRL);
|
||||
DUMP_CFG (CLASS);
|
||||
DUMP_CFG (HEADER);
|
||||
DUMP_CFG (MGABASE2);
|
||||
DUMP_CFG (MGABASE1);
|
||||
DUMP_CFG (MGABASE3);
|
||||
DUMP_CFG (SUBSYSIDR);
|
||||
DUMP_CFG (ROMBASE);
|
||||
DUMP_CFG (CAP_PTR);
|
||||
DUMP_CFG (INTCTRL);
|
||||
DUMP_CFG (OPTION);
|
||||
DUMP_CFG (MGA_INDEX);
|
||||
DUMP_CFG (MGA_DATA);
|
||||
DUMP_CFG (SUBSYSIDW);
|
||||
DUMP_CFG (AGP_IDENT);
|
||||
DUMP_CFG (AGP_STS);
|
||||
DUMP_CFG (AGP_CMD);
|
||||
|
||||
/*VGA registers - these are byte wide*/
|
||||
// DUMP_VGA (ATTR_I);
|
||||
// DUMP_VGA (ATTR_D);
|
||||
DUMP_VGA_ATTR (0);
|
||||
DUMP_VGA_ATTR (1);
|
||||
DUMP_VGA_ATTR (3);
|
||||
DUMP_VGA_ATTR (3);
|
||||
DUMP_VGA_ATTR (4);
|
||||
DUMP_VGA_ATTR (5);
|
||||
DUMP_VGA_ATTR (6);
|
||||
DUMP_VGA_ATTR (7);
|
||||
DUMP_VGA_ATTR (8);
|
||||
DUMP_VGA_ATTR (9);
|
||||
DUMP_VGA_ATTR (A);
|
||||
DUMP_VGA_ATTR (B);
|
||||
DUMP_VGA_ATTR (C);
|
||||
DUMP_VGA_ATTR (D);
|
||||
DUMP_VGA_ATTR (E);
|
||||
DUMP_VGA_ATTR (F);
|
||||
DUMP_VGA_ATTR (10);
|
||||
DUMP_VGA_ATTR (11);
|
||||
DUMP_VGA_ATTR (12);
|
||||
DUMP_VGA_ATTR (13);
|
||||
DUMP_VGA_ATTR (14);
|
||||
// DUMP_VGA (CRTC_I);
|
||||
// DUMP_VGA (CRTC_D);
|
||||
DUMP_VGA_CRTC (0);
|
||||
DUMP_VGA_CRTC (1);
|
||||
DUMP_VGA_CRTC (2);
|
||||
DUMP_VGA_CRTC (3);
|
||||
DUMP_VGA_CRTC (4);
|
||||
DUMP_VGA_CRTC (5);
|
||||
DUMP_VGA_CRTC (6);
|
||||
DUMP_VGA_CRTC (7);
|
||||
DUMP_VGA_CRTC (8);
|
||||
DUMP_VGA_CRTC (9);
|
||||
DUMP_VGA_CRTC (A);
|
||||
DUMP_VGA_CRTC (B);
|
||||
DUMP_VGA_CRTC (C);
|
||||
DUMP_VGA_CRTC (D);
|
||||
DUMP_VGA_CRTC (E);
|
||||
DUMP_VGA_CRTC (F);
|
||||
DUMP_VGA_CRTC (10);
|
||||
DUMP_VGA_CRTC (11);
|
||||
DUMP_VGA_CRTC (12);
|
||||
DUMP_VGA_CRTC (13);
|
||||
DUMP_VGA_CRTC (14);
|
||||
DUMP_VGA_CRTC (15);
|
||||
DUMP_VGA_CRTC (16);
|
||||
DUMP_VGA_CRTC (17);
|
||||
DUMP_VGA_CRTC (18);
|
||||
DUMP_VGA_CRTC (22);
|
||||
DUMP_VGA_CRTC (24);
|
||||
DUMP_VGA_CRTC (26);
|
||||
// DUMP_VGA (CRTCEXT_I);
|
||||
// DUMP_VGA (CRTCEXT_D);
|
||||
DUMP_VGA_CRTCEXT (0);
|
||||
DUMP_VGA_CRTCEXT (1);
|
||||
DUMP_VGA_CRTCEXT (2);
|
||||
DUMP_VGA_CRTCEXT (3);
|
||||
DUMP_VGA_CRTCEXT (4);
|
||||
DUMP_VGA_CRTCEXT (5);
|
||||
DUMP_VGA (DACSTAT);
|
||||
// DUMP_VGA (FEATW);
|
||||
DUMP_VGA (FEATR);
|
||||
// DUMP_VGA (GCTL_I);
|
||||
// DUMP_VGA (GCTL_D);
|
||||
DUMP_VGA_GCTL (0);
|
||||
DUMP_VGA_GCTL (1);
|
||||
DUMP_VGA_GCTL (2);
|
||||
DUMP_VGA_GCTL (3);
|
||||
DUMP_VGA_GCTL (4);
|
||||
DUMP_VGA_GCTL (5);
|
||||
DUMP_VGA_GCTL (6);
|
||||
DUMP_VGA_GCTL (7);
|
||||
DUMP_VGA_GCTL (8);
|
||||
DUMP_VGA (INSTS0);
|
||||
DUMP_VGA (INSTS1);
|
||||
DUMP_VGA (MISCR);
|
||||
DUMP_VGA (MISCW);
|
||||
// DUMP_VGA (SEQ_I);
|
||||
// DUMP_VGA (SEQ_D);
|
||||
DUMP_VGA_SEQ (0);
|
||||
DUMP_VGA_SEQ (1);
|
||||
DUMP_VGA_SEQ (2);
|
||||
DUMP_VGA_SEQ (3);
|
||||
DUMP_VGA_SEQ (4);
|
||||
|
||||
/* MGA registers, only the readable*/
|
||||
DUMP_MGA (IEN);
|
||||
DUMP_MGA (RST);
|
||||
DUMP_MGA (OPMODE);
|
||||
DUMP_MGA (STATUS);
|
||||
|
||||
/* TVP3026 registers */
|
||||
dump_tvp3026();
|
||||
}
|
||||
|
||||
/*set the mode, brightness is a value from 0->2 (where 1 is equivalent to direct)*/
|
||||
status_t mil2_dac_mode (int mode, float brightness, int hsync_pos, int vsync_pos, int sync_green)
|
||||
{
|
||||
uint8 *r, *g, *b, t[64];
|
||||
int i;
|
||||
uint8 miscctrl = 0, latchctrl = 0;
|
||||
uint8 tcolctrl = 0, mulctrl = 0;
|
||||
|
||||
LOG(4,("TVP:Setting screen mode %d brightness %f\n", mode, brightness));
|
||||
if (si->settings.logmask & 0x80000000) dump_tvp3026();
|
||||
|
||||
/*set colour arrays to point to space reserved in shared info*/
|
||||
r = si->color_data;
|
||||
g = r + 256;
|
||||
b = g + 256;
|
||||
|
||||
/*init a basic palette for brightness specified*/
|
||||
brightness = 2.0; // TODO
|
||||
for (i=0;i<256;i++) {
|
||||
int ri = i*brightness;
|
||||
if (ri > 255) ri = 255;
|
||||
r[i]=ri;
|
||||
}
|
||||
|
||||
/*modify the palette for the specified mode (&validate mode)*/
|
||||
switch(mode) {
|
||||
case BPP8:
|
||||
case BPP24:case BPP32:
|
||||
for (i=0;i<256;i++) b[i]=g[i]=r[i];
|
||||
break;
|
||||
case BPP16:
|
||||
for (i=0;i<64;i++) t[i]=r[i<<2];
|
||||
for (i=0;i<64;i++) g[i]=t[i];
|
||||
for (i=0;i<32;i++) b[i]=r[i]=t[i<<1];
|
||||
break;
|
||||
case BPP15:
|
||||
for (i=0;i<32;i++) t[i]=r[i<<3];
|
||||
for (i=0;i<32;i++) g[i]=r[i]=b[i]=t[i];
|
||||
break;
|
||||
case BPP32DIR:
|
||||
break;
|
||||
default:
|
||||
LOG(8,("TVP:Invalid bit depth requested\n"));
|
||||
return B_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (mil2_dac_palette (r, g, b) != B_OK) return B_ERROR;
|
||||
|
||||
// set the mode
|
||||
switch (mode) { // mulctrl for PIXEL_BUS_WIDTH 32
|
||||
case BPP8: miscctrl=0x0c; latchctrl=0x06; tcolctrl=0x80; mulctrl=0x4b; break;
|
||||
case BPP15: miscctrl=0x20; latchctrl=0x06; tcolctrl=0x04; mulctrl=0x53; break;
|
||||
case BPP16: miscctrl=0x20; latchctrl=0x06; tcolctrl=0x05; mulctrl=0x53; break;
|
||||
case BPP24: miscctrl=0x20; latchctrl=0x06; tcolctrl=0x1f; mulctrl=0x5b; break;
|
||||
case BPP32: miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b; break;
|
||||
case BPP32DIR: miscctrl=0x20; latchctrl=0x07; tcolctrl=0x06; mulctrl=0x5b; break;
|
||||
}
|
||||
if (PIXEL_BUS_WIDTH64) mulctrl += 1;
|
||||
TVPIW(MISCCTRL,(TVPIR(MISCCTRL) & 0xd3) | miscctrl);
|
||||
TVPIW(LATCHCTRL, latchctrl);
|
||||
TVPIW(TCOLCTRL, tcolctrl);
|
||||
TVPIW(MULCTRL, mulctrl);
|
||||
|
||||
// synchros
|
||||
TVPIW (GENCTRL, (TVPIR (GENCTRL) & 0xdc)
|
||||
| (sync_green? 0x00:0x20) // apsed TODO ?
|
||||
| (vsync_pos? 0x00:0x02)
|
||||
| (hsync_pos? 0x00:0x01));
|
||||
|
||||
//VGAW (MISCW, VGAR(MISCR) & 0x3f); // TODO
|
||||
//TVPIW (GENCTRL, TVPIR (GENCTRL) & 0xdf); // TODO
|
||||
|
||||
LOG(2,("TVP: clocksel 0x%02x, miscctrl 0x%02x\n",
|
||||
TVPIR(CLOCKSEL), TVPIR(MISCCTRL)));
|
||||
LOG(2,("TVP: tcolctrl 0x%02x, mulctrl 0x%02x, pixrdmsk 0x%02x, genctrl 0x%02x\n",
|
||||
TVPIR(TCOLCTRL), TVPIR(MULCTRL), TVPR(PIXRDMSK), TVPIR (GENCTRL)));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// program the palette using the given r,g,b values
|
||||
status_t mil2_dac_palette (uint8 r[256], uint8 g[256], uint8 b[256])
|
||||
{
|
||||
int i;
|
||||
|
||||
LOG(4,("TVP: setting palette\n"));
|
||||
|
||||
/*clear palwtadd to start programming*/
|
||||
TVPW(PALWTADD,0);
|
||||
|
||||
/*loop through all 256 to program LUT*/
|
||||
for (i=0;i<256;i++) {
|
||||
TVPW(PALDATA,r[i]);
|
||||
TVPW(PALDATA,g[i]);
|
||||
TVPW(PALDATA,b[i]);
|
||||
}
|
||||
if (TVPR(PALWTADD)!=0) {
|
||||
LOG(8,("TVP: PALWTADD is not 0 after programming\n"));
|
||||
return B_ERROR;
|
||||
}
|
||||
if (0) { // apsed: reread LUT
|
||||
uint8 R, G, B;
|
||||
TVPW(PALRDADD,0);
|
||||
for (i=0;i<256;i++) {
|
||||
R = TVPR(PALDATA);
|
||||
G = TVPR(PALDATA);
|
||||
B = TVPR(PALDATA);
|
||||
if ((r[i] != R) || (g[i] != G) || (b[i] != B)) {
|
||||
LOG(8,("TVP: palette 0x%02x: w %02x %02x %02x, r %02x %02x %02x\n",
|
||||
i, r[i], g[i], b[i], R, G, B));
|
||||
}
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// find nearest valid pll parameters, TVP3026 2.4.1
|
||||
status_t mil2_dac_pix_pll_find (float f_need, float *f_result, uint8 *m_result, uint8 *n_result, uint8 *p_result)
|
||||
{
|
||||
int m, n, p;
|
||||
float error, best, best_vco;
|
||||
float f_vco, f_pll;
|
||||
|
||||
LOG(0,("mil2_dac_pix_pll_find for %fMHz\n", f_need));
|
||||
best = 999999999;
|
||||
// stupid implementation of 2.4.1 and 2.4.2
|
||||
for (m = 1; m <= 62; m++) {
|
||||
for (n = 40; n <= 62; n++) {
|
||||
f_vco = (8.0 * FPLL_REF * (65 - m)) / (65 - n);
|
||||
if ((f_vco < FVCO_MIN) || (f_vco >= FVCO_MAX)) continue;
|
||||
for (p = 0; p <= 3; p++) {
|
||||
f_pll = f_vco / (float)(1 << p);
|
||||
error = fabs (f_need - f_pll) / f_need;
|
||||
if (error > best) continue;
|
||||
best = error;
|
||||
best_vco = f_vco;
|
||||
*f_result = f_pll;
|
||||
*m_result = m;
|
||||
*n_result = n;
|
||||
*p_result = p;
|
||||
LOG (0,("mil2_dac_pix_pll_find nmp %fMHz %fMHz 0x%02x 0x%02x 0x%02x\n",
|
||||
f_pll, f_vco, *n_result, *m_result, *p_result));
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG(0,("mil2_dac_pix_pll_find requested %fMHz got %fMHz, vco %fMHz, nmp 0x%02x 0x%02x 0x%02x\n",
|
||||
f_need, *f_result, best_vco, *n_result, *m_result, *p_result));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*program the pixpll - frequency in MHz*/
|
||||
status_t mil2_dac_set_pix_pll (float f_need, int bpp)
|
||||
{
|
||||
uint8 n, m, p, q;
|
||||
int z, k;
|
||||
float fd;
|
||||
status_t result;
|
||||
|
||||
LOG(4,("mil2_dac_set_pix_pll need %fMHz, %dbpp\n", f_need, bpp));
|
||||
result = mil2_dac_pix_pll_find(f_need,&fd,&m,&n,&p);
|
||||
if (result != B_OK) return result;
|
||||
LOG(2,("mil2_dac_set_pix_pll need %fMHz got %fMHz, nmp 0x%02x 0x%02x 0x%02x\n",
|
||||
f_need, fd, n, m, p));
|
||||
|
||||
// follows (!strictly) Appendix C, extended mode setup
|
||||
// 1st stop the PLLs,
|
||||
switch (bpp) {
|
||||
case 8: TVPIW(CLOCKSEL, 0x25); break;
|
||||
case 16: TVPIW(CLOCKSEL, 0x15); break;
|
||||
case 24: TVPIW(CLOCKSEL, 0x25); break;
|
||||
case 32: TVPIW(CLOCKSEL, 0x05); break;
|
||||
default: return B_ERROR;
|
||||
}
|
||||
TVPIW(PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
|
||||
TVPIW(LOOPLLDATA, 0x00); // 0x2f: 2.4.1 ... stop the loop PLL
|
||||
TVPIW(PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the pixel PLL
|
||||
VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x
|
||||
|
||||
// 2nd setup the pixel PLL
|
||||
LOG(2,("mil2_dac_set_pix_pll pix PLL, nmp 0x%02x 0x%02x 0x%02x\n",
|
||||
n, m, p));
|
||||
TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
|
||||
TVPIW(PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
|
||||
TVPIW(PIXPLLDATA, m);
|
||||
TVPIW(PIXPLLDATA, p | 0xb0);
|
||||
WAIT_FOR_PLL_LOCK (PIX, return B_ERROR); // ... wait for PLL lock
|
||||
if (1) REREAD_PLL (PIX);
|
||||
|
||||
// now compute parameters for the loop PLL (24bpp not available) see 2.4.3.1
|
||||
k = 1; // ?? external division factor between RCLK and LCLK
|
||||
n = (65 - (4 * (PIXEL_BUS_WIDTH64? 64: 32)) / bpp);
|
||||
m = 61;
|
||||
z = (FVCO_MIN * (65 - n)) / (4 * fd * k);
|
||||
q = 0;
|
||||
if (z < 2) p = 0; // this is TRUNC (log2 (z))
|
||||
else if (z < 4) p = 1;
|
||||
else if (z < 8) p = 2;
|
||||
else if (z < 16) p = 3;
|
||||
else { // but not this
|
||||
p = 3;
|
||||
q = 1 + (z - 16) / 16;
|
||||
}
|
||||
LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||
n, m, p, q));
|
||||
TVPIW(MEMCLKCTRL, (TVPIR(MEMCLKCTRL) & 0xf8) | q | 0x20); // 0x39: 2.4.2 table 2.13
|
||||
LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||
n, m, p, q));
|
||||
|
||||
// now setup the loop PLL
|
||||
LOG(2,("mil2_dac_set_pix_pll loop PLL, nmpq 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
||||
n, m, p, q));
|
||||
TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
|
||||
TVPIW(LOOPLLDATA, n | 0xc0); // 0x2f: ... load n, m, p and ...
|
||||
TVPIW(LOOPLLDATA, m);
|
||||
TVPIW(LOOPLLDATA, p | 0xf0);
|
||||
WAIT_FOR_PLL_LOCK (LOO, return B_ERROR); // ... wait for PLL lock
|
||||
if (1) REREAD_PLL (LOO);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// set MEM clock MCLK , shall be <= 100MHz
|
||||
static status_t mil2_dac_set_mem_pll (float f_need, float *mclk)
|
||||
{
|
||||
status_t status;
|
||||
uint8 n, m, p;
|
||||
uint8 n_pix, m_pix, p_pix;
|
||||
uint8 memclkctrl;
|
||||
|
||||
status = mil2_dac_pix_pll_find (f_need, mclk, &m, &n, &p);
|
||||
if (status != B_OK) return status;
|
||||
LOG(2,("mil2_dac_set_mem_pll need %fMHz got %fMHz, nmp 0x%02x 0x%02x 0x%02x\n",
|
||||
f_need, *mclk, n, m, p));
|
||||
|
||||
// follows (!strictly) TVP3026 2.4.2.1, extended mode setup
|
||||
|
||||
// 0) save PIXPLL nmp to restore it at end
|
||||
TVPIW(PLLADDR, 0x00);
|
||||
n_pix = TVPIR(PIXPLLDATA);
|
||||
TVPIW(PLLADDR, 0x15);
|
||||
m_pix = TVPIR(PIXPLLDATA);
|
||||
TVPIW(PLLADDR, 0x2a);
|
||||
p_pix = TVPIR(PIXPLLDATA);
|
||||
if (1) REREAD_PLL (PIX);
|
||||
|
||||
// 1) disable pixel PLL, set pixel PLL at MCLK freq and poll for lock
|
||||
TVPIW(PLLADDR, 0x2a); // 0x2c: 2.4 select P to ...
|
||||
TVPIW(PIXPLLDATA, 0x00); // 0x2d: 2.4.1 ... stop the PLL
|
||||
TVPIW(PLLADDR, 0x00); // 0x2c: 2.4 select N to ...
|
||||
TVPIW(PIXPLLDATA, n | 0xc0); // 0x2d: ... load n, m, p and ...
|
||||
TVPIW(PIXPLLDATA, m);
|
||||
TVPIW(PIXPLLDATA, p | 0xb0);
|
||||
WAIT_FOR_PLL_LOCK (PIX, return B_ERROR); // ... wait for PLL lock
|
||||
if (1) REREAD_PLL (PIX);
|
||||
|
||||
// 2) select pixel clock as dot clock source
|
||||
VGAW (MISCW, VGAR(MISCR) | 0x0c); // PLLSEL(1,0) set to 1x
|
||||
|
||||
// 3) output dot clock on MCLK pin
|
||||
memclkctrl = TVPIR(MEMCLKCTRL) & 0xe7;
|
||||
TVPIW(MEMCLKCTRL, memclkctrl | (0x00 << 3));
|
||||
TVPIW(MEMCLKCTRL, memclkctrl | (0x01 << 3));
|
||||
|
||||
// 4) disable mem PLL, set mem PLL at MCLK freq and poll for lock
|
||||
if (1) REREAD_PLL (MEM);
|
||||
TVPIW(PLLADDR, 0x2a);
|
||||
TVPIW(MEMPLLDATA, 0x00);
|
||||
TVPIW(PLLADDR, 0x00);
|
||||
TVPIW(MEMPLLDATA, n | 0xc0);
|
||||
TVPIW(MEMPLLDATA, m);
|
||||
TVPIW(MEMPLLDATA, p | 0xb0);
|
||||
WAIT_FOR_PLL_LOCK (MEM, return B_ERROR);
|
||||
if (1) REREAD_PLL (MEM);
|
||||
|
||||
// 5) output mem clock on MCLK pin
|
||||
TVPIW(MEMCLKCTRL, memclkctrl | (0x02 << 3));
|
||||
TVPIW(MEMCLKCTRL, memclkctrl | (0x03 << 3));
|
||||
|
||||
// 6) restaure pixel clock as it was
|
||||
TVPIW(PLLADDR, 0x2a);
|
||||
TVPIW(PIXPLLDATA, 0x00);
|
||||
TVPIW(PLLADDR, 0x00);
|
||||
// TVPIW(PIXPLLDATA, n_pix);
|
||||
// TVPIW(PIXPLLDATA, m_pix);
|
||||
// TVPIW(PIXPLLDATA, p_pix);
|
||||
TVPIW(PIXPLLDATA, n_pix | 0xc0);
|
||||
TVPIW(PIXPLLDATA, m_pix);
|
||||
TVPIW(PIXPLLDATA, p_pix | 0xb0);
|
||||
WAIT_FOR_PLL_LOCK (PIX, return B_ERROR);
|
||||
if (1) REREAD_PLL (PIX);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/* initialize TVP3026: memory clock PLL ... */
|
||||
status_t mil2_dac_init (void)
|
||||
{
|
||||
status_t status;
|
||||
float need = 60.0; // MHz FPLL_MCLK
|
||||
float mclk;
|
||||
uint32 option;
|
||||
uint32 rfhcnt, nogscale, memconfig;
|
||||
|
||||
dump_mil2();
|
||||
|
||||
LOG(4, ("mil2_dac_init MISC 0x%02x\n", VGAR(MISCR)));
|
||||
CFGW(DEVCTRL,(2|CFGR(DEVCTRL))); // enable device response (already enabled here!)
|
||||
VGAW_I(CRTC,0x11,0); // allow me to change CRTC
|
||||
VGAW_I(CRTCEXT,3,0x80); // use powergraphix (+ trash other bits, they are set later)
|
||||
VGAW(MISCW,0x08); // set MGA pixel clock in MISC - PLLSEL10 of TVP3026 is 1X
|
||||
|
||||
// set MEM clock MCLK following TVP3026 2.4.2.1
|
||||
status = mil2_dac_set_mem_pll (need, &mclk); //FPLL_MCLK);
|
||||
if (status != B_OK) return status;
|
||||
|
||||
// update OPTION for refresh count following page 3-18
|
||||
// 33.2mus >= (rfhcnt31*512 + rfhcnt0*64 + 1)*gclk_period*factor
|
||||
// rfhcnt31*512 + rfhcnt0*64 <= -1 + 33.2mus*mclk/factor
|
||||
if (1) {
|
||||
int mclk_p = 1;
|
||||
int nogscale = 1;
|
||||
int f_pll = mclk * 1000 * 333 / (10000 << mclk_p);
|
||||
int rfhcnt = (f_pll - 128) / 256;
|
||||
if (rfhcnt > 15) rfhcnt = 15;
|
||||
LOG(2,("mil2_dac_init: refresh count %d nogscale %d for %fMHz\n",
|
||||
rfhcnt, nogscale, mclk));
|
||||
}
|
||||
for (nogscale = 1; nogscale >= 0; nogscale--) {
|
||||
int max = -1 + 33.2 * mclk / (nogscale? 1: 4);
|
||||
for (rfhcnt = 15; rfhcnt > 0; rfhcnt--) {
|
||||
int value = (rfhcnt & 0x0e) * 256 + (rfhcnt & 0x01) * 64;
|
||||
LOG(2,("mil2_dac_init factor %d, rfhcnt %2d: %d ?<= %d\n",
|
||||
nogscale, rfhcnt, value, max));
|
||||
if (value <= max) goto rfhcnt_found;
|
||||
}
|
||||
}
|
||||
LOG(8,("mil2_dac_init: cant get valid refresh count for %fMHz\n", mclk));
|
||||
return B_ERROR;
|
||||
rfhcnt_found:
|
||||
LOG(2,("mil2_dac_init: found refresh count %d nogscale %d for %fMHz\n",
|
||||
rfhcnt, nogscale, mclk));
|
||||
|
||||
memconfig = 0x00; // 32 bits RAMDAC
|
||||
memconfig = 0x01; // 64 bits RAMDAC
|
||||
option = CFGR(OPTION) & 0xffd0cfff;
|
||||
CFGW(OPTION, option | (nogscale << 21) | (rfhcnt << 16) | (memconfig << 12));
|
||||
LOG(2,("mil2_dac_init: OPTION 0x%08x\n", CFGR(OPTION)));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
Reference in New Issue
Block a user