龙芯软件开发(28)-- 显示卡初始化

在上一次里,已经说到初始化网络,在那里提到调用一个函数tgt_devconfig来初始化其它重要的设备。这其中就有一个重要的设备要初始化的,它就是显示卡。下面就来仔细地阅读这个函数的代码,如下:
void
tgt_devconfig()
{
#if NMOD_VGACON > 0
int rc;
#if NMOD_FRAMEBUFFER > 0
unsigned long fbaddress,ioaddress;
extern struct pci_device *vga_dev;
#endif
#endif
_pci_devinit(1); /* PCI device initialization */
上面进行PCI设备加载,让它可以工作。

#if NMOD_X86EMU_INT10 > 0
SBD_DISPLAY("VGAI", 0);
rc = vga_bios_init();
#endif
上面可以选择模拟X86的CPU功能,由于市场上的显示卡,大部份都是为X86的CPU制造的,所以显示卡里的BIOS程序,只能在X86里的CPU运行。为了使用这种显示卡,就要在龙芯里模拟一个X86的CPU,这样就可以执行显示卡的BIOS程序了。希望国产的显示卡芯片早日壮大,这样就可以直写出适用于龙芯的BIOS了。

#if (NMOD_X86EMU_INT10 == 0 && defined(RADEON7000))
SBD_DISPLAY("VGAI", 0);
rc = radeon_init();
#endif
上面使用直接初始化显示卡的方式。

#if NMOD_FRAMEBUFFER > 0
if (rc > 0) {
SBD_DISPLAY("FRBI", 0);
fbaddress =_pci_conf_read(vga_dev->pa.pa_tag,0x10);
ioaddress =_pci_conf_read(vga_dev->pa.pa_tag,0x18);

fbaddress = fbaddress &0xffffff00; //laster 8 bit
ioaddress = ioaddress &0xfffffff0; //laster 4 bit

printf("fbaddress 0x%x\tioaddress 0x%x\n",fbaddress, ioaddress);

fb_init(fbaddress, ioaddress);
printf("after fb_init\n");

} else {
printf("vga bios init failed, rc=%d\n",rc);
}
#endif
上面进行帧缓冲区(Frame buffer)初始化。

if (rc > 0)
if(!getenv("novga")) vga_available=1;
上面根据参数是否输出显示内容到显示器上。当你想输出到串口上时,就需要设置这个变量为1。

config_init();
configure();
上面初始化自动配置的结构。

#if NMOD_VGACON >0
#if !(defined(VGA_NOTEBOOK_V1) || defined(VGA_NOTEBOOK_V2))
rc=kbd_initialize();
#else
rc = 0;
#endif
printf("%s\n",kbd_error_msgs[rc]);
if(!rc){
kbd_available=1;
}
上面进行键盘初始化。

#endif
printf("devconfig done.\n");
}

上面先进行PCI设备的加载过程,然后选择合适方式来初始化显示卡,最后初始化了键盘。
下面再来仔细地看看显示卡的初始化。先看函数radeon_init的实现:
int
radeon_init (void)
{
unsigned int v;
int i;
/* BIOS Header at 0x10c
first initialization block at 0x1dd
PLL information block at 0x2ef
second initialization block at 0x25e
second initialization block at 0x3bb */

printf ("starting radeon init…\n");

radeon_init_regbase();
上面这个函数从PCI里读取显示卡的IO基地址和内存访问地址。

/* first initialization */

/* reg 0x1c0 is SEPROM_CNTL1 */
v = MMINL (0x1c0);
v = (v & 0xffffff) | 0x4000000;
MMOUTL (0x1c0, v);

/* reg 0x30 is BUS_CNTL */
OUTL (0x30, 0x5133a3b0);

MMOUTL (0xec, 0x4443);

/* reg 0x1d0 is AIC_CTRL */
v = MMINL (0x1d0);
v = (v & 0xfffffffd) | 0x2;
MMOUTL (0x1d0, v);

/* reg 0x50 is CRTC_GEN_CNTL */
OUTL (0x50, 0x4000000);

/* reg 0x58 is DAC_CNTL */
OUTL (0x58, 0xff604102);

/* reg 0x168 is PAD_CTLR_STRENGTH */
v = MMINL (0x168);
v = (v & 0xfffeffff) | 0x1200;
MMOUTL (0x168, v);

/* reg 0x178 is MEM_IO_CNTL_A0 */
MMOUTL (0x178, 0xff1f7fff);

/* reg 0x17c is MEM_IO_CNTL_A1 */
MMOUTL (0x17c, 0xfecfbfff);

/* reg 0x188 is MC_DEBUG */
v = MMINL (0x188);
v = (v & 0xffffffff) | 0x8007c00;
MMOUTL (0x188, v);

/* reg 0xd00 is DISP_MISC_CNTL */
v = MMINL (0xd00);
v = (v & 0xffffff) | 0x5b000000;
MMOUTL (0xd00, v);

/* reg 0x88c is TV_DAC_CNTL */
v = MMINL (0x88c);
v = (v & 0xf800fcef) | 0x7480000;
MMOUTL (0x88c, v);

/* reg 0xd04 is DAC_MACRO_CNTL */
v = MMINL (0xd04);
v = (v & 0xfffffff0) | 0x6;
MMOUTL (0xd04, v);

/* reg 0x284 is FP_GEN_CNTL */
v = MMINL (0x284);
v = (v & 0xffffffff) | 0x8;
MMOUTL (0x284, v);

/* reg 0x30 is BUS_CNTL */
v = MMINL (0x30);
v = (v & 0xffffffef) | 0x0;
MMOUTL (0x30, v);

linux_outb (0x0,0xa108);
linux_outb (0x5,0x3c2);
linux_outb (0x0,0x3c0);
linux_outw (0x2001,0x3c4);
上面通过设置控制寄存器,初始化Radeon 7000第一阶段,主要有DAC寄存器,由于显示卡的主要功能就是把数字化的信号变换为摸拟信号输出给显示器。

/* PLL initialization */

/* PLL reg 0xd is SCLK_CNTL */
OUTPLL (0xd, 0xfffffff8);

/* PLL reg 0x12 is MCLK_CNTL */
OUTPLL (0x12, 0xa350000);

/* PLL reg 0x8 is VCLK_ECP_CNTL */
OUTPLL (0x8, 0x0);

/* PLL reg 0x2d is PIXCLKS_CNTL */
OUTPLL (0x2d, 0x0);

linux_outb (0x0,0xa108);

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x3 is PPLL_REF_DIV */
OUTPLL (0x3, 0x3c);

/* PLL reg 0xa is M_SPLL_REF_FB_DIV */
OUTPLL (0xa, 0x14a4a0c);

/* PLL reg 0xe is MPLL_CNTL */
OUTPLL (0xe, 0x400fc33);

/* PLL reg 0xc is SPLL_CNTL */
OUTPLL (0xc, 0x400bc33);

/* PLL reg 0x2 is PPLL_CNTL */
OUTPLL (0x2, 0xa703);

/* PLL reg 0xf is MDLL_CKO */
OUTPLL (0xf, 0x53f);

/* PLL reg 0x10 is MDLL_RDCKA */
OUTPLL (0x10, 0x8830883);

/*special command 0x2 */
mdelay (150);

/* PLL reg 0xe is MPLL_CNTL */
/* AND/OR */
v = INPLL (0xe);
OUTPLL (0xe, ((v & 0xfd) | 0x0));

/*special command 0x2 */
mdelay (150);

/* PLL reg 0xe is MPLL_CNTL */
/* AND/OR */
v = INPLL (0xe);
OUTPLL (0xe, ((v & 0xfe) | 0x0));

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x12 is MCLK_CNTL */
OUTPLL (0x12, 0xa350012);

/*special command 0x2 */
mdelay (150);

/* PLL reg 0xf is MDLL_CKO */
/* AND/OR */
v = INPLL (0xf);
OUTPLL (0xf, ((v & 0xfe) | 0x0));

/*special command 0x1 */
mdelay (1500);

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x10 is MDLL_RDCKA */
/* AND/OR */
v = INPLL (0x10);
OUTPLL (0x10, ((v & 0xfe) | 0x0));

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x10 is MDLL_RDCKA */
/* AND/OR */
v = INPLL (0x10);
OUTPLL (0x10, ((v & 0xfe0000) | 0x0));

/*special command 0x1 */
mdelay (1500);

/*special command 0x2 */
mdelay (150);

/* PLL reg 0xf is MDLL_CKO */
/* AND/OR */
v = INPLL (0xf);
OUTPLL (0xf, ((v & 0xfd) | 0x0));

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x10 is MDLL_RDCKA */
/* AND/OR */
v = INPLL (0x10);
OUTPLL (0x10, ((v & 0xfd) | 0x0));

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x10 is MDLL_RDCKA */
/* AND/OR */
v = INPLL (0x10);
OUTPLL (0x10, ((v & 0xfd0000) | 0x0));

/*special command 0x2 */
mdelay (150);

/*special command 0x2 */
mdelay (150);

/* PLL reg 0xc is SPLL_CNTL */
/* AND/OR */
v = INPLL (0xc);
OUTPLL (0xc, ((v & 0xfe) | 0x0));

/*special command 0x1 */
mdelay (1500);

/*special command 0x2 */
mdelay (150);

/* PLL reg 0xc is SPLL_CNTL */
/* AND/OR */
v = INPLL (0xc);
OUTPLL (0xc, ((v & 0xfd) | 0x0));

/*special command 0x2 */
mdelay (150);

/* PLL reg 0xd is SCLK_CNTL */
OUTPLL (0xd, 0xfffffffa);

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x8 is VCLK_ECP_CNTL */
/* AND/OR */
v = INPLL (0x8);
OUTPLL (0x8, ((v & 0x3c) | 0x0));

/* PLL reg 0x2 is PPLL_CNTL */
/* AND/OR */
v = INPLL (0x2);
OUTPLL (0x2, ((v & 0xff) | 0x3));

/* PLL reg 0x4 is PPLL_DIV_0 */
OUTPLL (0x4, 0x381c0);

/* PLL reg 0x5 is PPLL_DIV_1 */
OUTPLL (0x5, 0x381f7);

/* PLL reg 0x6 is PPLL_DIV_2 */
OUTPLL (0x6, 0x381c0);

/* PLL reg 0x7 is PPLL_DIV_3 */
OUTPLL (0x7, 0x381f7);

/* PLL reg 0x2 is PPLL_CNTL */
/* AND/OR */
v = INPLL (0x2);
OUTPLL (0x2, ((v & 0xfd) | 0x0));

/*special command 0x1 */
mdelay (1500);

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x2 is PPLL_CNTL */
/* AND/OR */
v = INPLL (0x2);
OUTPLL (0x2, ((v & 0xfe) | 0x0));

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x8 is VCLK_ECP_CNTL */
/* AND/OR */
v = INPLL (0x8);
OUTPLL (0x8, ((v & 0x3c) | 0x3));

/*special command 0x2 */
mdelay (150);

/* PLL reg 0x1 is CLK_PIN_CNTL */
/* AND/OR */
v = INPLL (0x1);
OUTPLL (0x1, ((v & 0xff) | 0x10));
上面主要进行PLL设置,由于显示卡需要生成精确的行扫描频率和场扫描频率,这些电路都会使用锁相环实现的,只要设置相应的分频和倍频系数就会得到扫描频率。

/* second initialization */

/* reg 0x140 is MEM_CNTL */
v = MMINL (0x140);
v = (v & 0xffffffff) | 0x20002004;
MMOUTL (0x140, v);

/* reg 0x158 is MEM_SDRAM_MODE_REG */
v = MMINL (0x158);
v = (v & 0xf0000000) | 0x403a0000;
MMOUTL (0x158, v);

/* reg 0x144 is EXT_MEM_CNTL */
MMOUTL (0x144, 0x1405356b);

/* reg 0x14c is MC_AGP_LOCATION */
MMOUTL (0x14c, 0xffff0);

/* reg 0x148 is MC_FB_LOCATION */
MMOUTL (0x148, 0xffff0000);

/* reg 0x154 is MEM_INIT_LATENCY_TIMER */
MMOUTL (0x154, 0x77777777);

/* reg 0x18c is MEM_IO_OE_CNTL */
MMOUTL (0x18c, 0x16666);

MMOUTL (0x910, 0x4);

/* reg 0x10 is BIOS_0_SCRATCH */
v = MMINL (0x10);
v = (v & 0xfffffffb) | 0x4;
MMOUTL (0x10, v);

/* reg 0xd64 is DISP_OUTPUT_CNTL */
v = MMINL (0xd64);
v = (v & 0xfffffbff) | 0x0;
MMOUTL (0xd64, v);

/* reg 0x2a8 is TMDS_PLL_CNTL */
MMOUTL (0x2a8, 0xa1b);

/* reg 0xd64 is DISP_OUTPUT_CNTL */
v = MMINL (0xd64);
v = (v & 0xfffffbff) | 0x222;
MMOUTL (0xd64, v);

/* reg 0x800 is TV_MASTER_CNTL */
v = MMINL (0x800);
v = (v & 0xbfffffff) | 0x40000000;
MMOUTL (0x800, v);

/* reg 0xd10 is DISP_TEST_DEBUG_CNTL */
v = MMINL (0xd10);
v = (v & 0xefffffff) | 0x10000000;
MMOUTL (0xd10, v);

/* reg 0x4dc is OV0_FLAG_CNTRL */
v = MMINL (0x4dc);
v = (v & 0xfffffeff) | 0x100;
MMOUTL (0x4dc, v);

/* reg 0x34 is BUS_CNTL1 */
v = MMINL (0x34);
v = (v & 0x73ffffff) | 0x84000000;
MMOUTL (0x34, v);

/* reg 0x174 is AGP_CNTL */
v = MMINL (0x174);
v = (v & 0xffefff00) | 0x1e0000;
MMOUTL (0x174, v);
上面设置一些跟显存有关的寄存器。

/* memory controller initialization */
mc_init ();
上面清除显存,并且打开PLL,设置特定的频率输出。

MMOUTL (0xd64, 0);
/* 8bit DAC */
MMOUTL (0x058, 0xff604002);

MMOUTL (0x38, 0x00010000);
MMOUTL (0x3C, 0x00010000);

setregs(&regs);

/* install palette */
OUTL(0xb0, 0);
for (i=0;i<0xff;i++) {
OUTL(0xb4, (i«16) | (i«8) | i );
}
上面设置调色板。

radeon_init_mode();
上面初始化输出模式,在PMON是使用黑屏白字的模式。

radeon_engine_init();
上面关闭3D引擎和初始化2D引擎。

radeon_dump_regs();
上面是调试时输出寄存器的值。

printf ("radeon init done\n");

return 1;
}

没有更详细的显示卡资料,只能大概地了解它的作用。希望国产的显示卡芯片大大地加快研发进度,以便日后更容易地开发相应的软件,降低显示卡驱动程序的开发难度。在一台电脑里,显示卡是跟人们交流的窗口,有着非常重要的地位。随着3D技术的发展,显示卡越来越重要了,下一代自主开发的3D显示卡,盼望早日到来!

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License