atyfb.c

来自「讲述linux的初始化过程」· C语言 代码 · 共 2,436 行 · 第 1/5 页

C
2,436
字号
	    break;	case 16:	    i = 1;	    break;	case 32:	    i = 2;	    break;    }    aty_st_514(0x90, 0x00, info);		/* VRAM Mask Low */    aty_st_514(0x04, tab[i].pixel_dly, info);	/* Horizontal Sync Control */    aty_st_514(0x05, 0x00, info);		/* Power Management */    aty_st_514(0x02, 0x01, info);		/* Misc Clock Control */    aty_st_514(0x71, tab[i].misc2_cntl, info);	/* Misc Control 2 */    aty_st_514(0x0a, tab[i].pixel_rep, info);	/* Pixel Format */    aty_st_514(tab[i].pixel_cntl_index, tab[i].pixel_cntl_v1, info);			/* Misc Control 2 / 16 BPP Control / 32 BPP Control */}static int aty_crtc_to_var(const struct crtc *crtc,			   struct fb_var_screeninfo *var){    u32 xres, yres, bpp, left, right, upper, lower, hslen, vslen, sync;    u32 h_total, h_disp, h_sync_strt, h_sync_dly, h_sync_wid, h_sync_pol;    u32 v_total, v_disp, v_sync_strt, v_sync_wid, v_sync_pol, c_sync;    u32 pix_width;    /* input */    h_total = crtc->h_tot_disp & 0x1ff;    h_disp = (crtc->h_tot_disp>>16) & 0xff;    h_sync_strt = (crtc->h_sync_strt_wid & 0xff) |		  ((crtc->h_sync_strt_wid>>4) & 0x100);    h_sync_dly = (crtc->h_sync_strt_wid>>8) & 0x7;    h_sync_wid = (crtc->h_sync_strt_wid>>16) & 0x1f;    h_sync_pol = (crtc->h_sync_strt_wid>>21) & 0x1;    v_total = crtc->v_tot_disp & 0x7ff;    v_disp = (crtc->v_tot_disp>>16) & 0x7ff;    v_sync_strt = crtc->v_sync_strt_wid & 0x7ff;    v_sync_wid = (crtc->v_sync_strt_wid>>16) & 0x1f;    v_sync_pol = (crtc->v_sync_strt_wid>>21) & 0x1;    c_sync = crtc->gen_cntl & CRTC_CSYNC_EN ? 1 : 0;    pix_width = crtc->gen_cntl & CRTC_PIX_WIDTH_MASK;    /* convert */    xres = (h_disp+1)*8;    yres = v_disp+1;    left = (h_total-h_sync_strt-h_sync_wid)*8-h_sync_dly;    right = (h_sync_strt-h_disp)*8+h_sync_dly;    hslen = h_sync_wid*8;    upper = v_total-v_sync_strt-v_sync_wid;    lower = v_sync_strt-v_disp;    vslen = v_sync_wid;    sync = (h_sync_pol ? 0 : FB_SYNC_HOR_HIGH_ACT) |	   (v_sync_pol ? 0 : FB_SYNC_VERT_HIGH_ACT) |	   (c_sync ? FB_SYNC_COMP_HIGH_ACT : 0);    switch (pix_width) {#if 0	case CRTC_PIX_WIDTH_4BPP:	    bpp = 4;	    var->red.offset = 0;	    var->red.length = 8;	    var->green.offset = 0;	    var->green.length = 8;	    var->blue.offset = 0;	    var->blue.length = 8;	    var->transp.offset = 0;	    var->transp.length = 0;	    break;#endif	case CRTC_PIX_WIDTH_8BPP:	    bpp = 8;	    var->red.offset = 0;	    var->red.length = 8;	    var->green.offset = 0;	    var->green.length = 8;	    var->blue.offset = 0;	    var->blue.length = 8;	    var->transp.offset = 0;	    var->transp.length = 0;	    break;	case CRTC_PIX_WIDTH_15BPP:	/* RGB 555 */	    bpp = 16;	    var->red.offset = 10;	    var->red.length = 5;	    var->green.offset = 5;	    var->green.length = 5;	    var->blue.offset = 0;	    var->blue.length = 5;	    var->transp.offset = 0;	    var->transp.length = 0;	    break;#if 0	case CRTC_PIX_WIDTH_16BPP:	/* RGB 565 */	    bpp = 16;	    var->red.offset = 11;	    var->red.length = 5;	    var->green.offset = 5;	    var->green.length = 6;	    var->blue.offset = 0;	    var->blue.length = 5;	    var->transp.offset = 0;	    var->transp.length = 0;	    break;#endif	case CRTC_PIX_WIDTH_24BPP:	/* RGB 888 */	    bpp = 24;	    var->red.offset = 16;	    var->red.length = 8;	    var->green.offset = 8;	    var->green.length = 8;	    var->blue.offset = 0;	    var->blue.length = 8;	    var->transp.offset = 0;	    var->transp.length = 0;	    break;	case CRTC_PIX_WIDTH_32BPP:	/* ARGB 8888 */	    bpp = 32;	    var->red.offset = 16;	    var->red.length = 8;	    var->green.offset = 8;	    var->green.length = 8;	    var->blue.offset = 0;	    var->blue.length = 8;	    var->transp.offset = 24;	    var->transp.length = 8;	    break;	default:	    FAIL("Invalid pixel width");    }    /* output */    var->xres = xres;    var->yres = yres;    var->xres_virtual = crtc->vxres;    var->yres_virtual = crtc->vyres;    var->bits_per_pixel = bpp;    var->xoffset = crtc->xoffset;    var->yoffset = crtc->yoffset;    var->left_margin = left;    var->right_margin = right;    var->upper_margin = upper;    var->lower_margin = lower;    var->hsync_len = hslen;    var->vsync_len = vslen;    var->sync = sync;    var->vmode = FB_VMODE_NONINTERLACED;    return 0;}/* ------------------------------------------------------------------------- */    /*     *  PLL programming (Mach64 GX family)     *     *  FIXME: use function pointer tables instead of switch statements     */static void aty_set_pll_gx(const struct fb_info_aty *info,			   const struct pll_gx *pll){    switch (info->clk_type) {	case CLK_ATI18818_1:	    aty_st_8(CLOCK_CNTL, pll->m, info);	    break;	case CLK_IBMRGB514:	    aty_st_514(0x06, 0x02, info);	/* DAC Operation */	    aty_st_514(0x10, 0x01, info);	/* PLL Control 1 */	    aty_st_514(0x70, 0x01, info);	/* Misc Control 1 */	    aty_st_514(0x8f, 0x1f, info);	/* PLL Ref. Divider Input */	    aty_st_514(0x03, 0x00, info);	/* Sync Control */	    aty_st_514(0x05, 0x00, info);	/* Power Management */	    aty_st_514(0x20, pll->m, info);	/* F0 / M0 */	    aty_st_514(0x21, pll->n, info);	/* F1 / N0 */	    break;    }}static int aty_var_to_pll_18818(u32 period_in_ps, struct pll_18818 *pll){    u32 MHz100;		/* in 0.01 MHz */    u32 program_bits;    u32 post_divider;    /* Calculate the programming word */    MHz100 = 100000000 / period_in_ps;    program_bits = -1;    post_divider = 1;    if (MHz100 > MAX_FREQ_2595) {	MHz100 = MAX_FREQ_2595;	return -EINVAL;    } else if (MHz100 < ABS_MIN_FREQ_2595) {	program_bits = 0;	/* MHz100 = 257 */	return -EINVAL;    } else {	while (MHz100 < MIN_FREQ_2595) {	    MHz100 *= 2;	    post_divider *= 2;	}    }    MHz100 *= 1000;    MHz100 = (REF_DIV_2595 * MHz100) / REF_FREQ_2595;    MHz100 += 500;    /* + 0.5 round */    MHz100 /= 1000;    if (program_bits == -1) {	program_bits = MHz100 - N_ADJ_2595;	switch (post_divider) {	    case 1:		program_bits |= 0x0600;		break;	    case 2:		program_bits |= 0x0400;		break;	    case 4:		program_bits |= 0x0200;		break;	    case 8:	    default:		break;	}    }    program_bits |= STOP_BITS_2595;    pll->program_bits = program_bits;    pll->locationAddr = 0;    pll->post_divider = post_divider;    pll->period_in_ps = period_in_ps;    return 0;}static u32 aty_pll_18818_to_var(const struct pll_18818 *pll){    return(pll->period_in_ps);  /* default for now */}static void aty_set_pll18818(const struct fb_info_aty *info,			     const struct pll_18818 *pll){    u32 program_bits;    u32 locationAddr;    u32 i;    u8 old_clock_cntl;    u8 old_crtc_ext_disp;    old_clock_cntl = aty_ld_8(CLOCK_CNTL, info);    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),	     info);    mdelay(15); /* delay for 50 (15) ms */    program_bits = pll->program_bits;    locationAddr = pll->locationAddr;    /* Program the clock chip */    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 0, info);  /* Strobe = 0 */    aty_StrobeClock(info);    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, 1, info);  /* Strobe = 0 */    aty_StrobeClock(info);    aty_ICS2595_put1bit(1, info);    /* Send start bits */    aty_ICS2595_put1bit(0, info);    /* Start bit */    aty_ICS2595_put1bit(0, info);    /* Read / ~Write */    for (i = 0; i < 5; i++) {	/* Location 0..4 */	aty_ICS2595_put1bit(locationAddr & 1, info);	locationAddr >>= 1;    }    for (i = 0; i < 8 + 1 + 2 + 2; i++) {	aty_ICS2595_put1bit(program_bits & 1, info);	program_bits >>= 1;    }    udelay(1000); /* delay for 1 ms */    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);    aty_st_8(CLOCK_CNTL + info->clk_wr_offset, old_clock_cntl | CLOCK_STROBE,	     info);    mdelay(50); /* delay for 50 (15) ms */    aty_st_8(CLOCK_CNTL + info->clk_wr_offset,	     ((pll->locationAddr & 0x0F) | CLOCK_STROBE), info);    return;}static int aty_var_to_pll_408(u32 period_in_ps, struct pll_18818 *pll){    u32 mhz100;		/* in 0.01 MHz */    u32 program_bits;    /* u32 post_divider; */    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;    u32 temp, tempB;    u16 remainder, preRemainder;    short divider = 0, tempA;    /* Calculate the programming word */    mhz100 = 100000000 / period_in_ps;    mach64MinFreq = MIN_FREQ_2595;    mach64MaxFreq = MAX_FREQ_2595;    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */    /* Calculate program word */    if (mhz100 == 0)	program_bits = 0xFF;    else {	if (mhz100 < mach64MinFreq)	    mhz100 = mach64MinFreq;	if (mhz100 > mach64MaxFreq)	    mhz100 = mach64MaxFreq;	while (mhz100 < (mach64MinFreq << 3)) {	    mhz100 <<= 1;	    divider += 0x40;	}	temp = (unsigned int)mhz100;	temp = (unsigned int)(temp * (MIN_N_408 + 2));	temp -= ((short)(mach64RefFreq << 1));	tempA = MIN_N_408;	preRemainder = 0xFFFF;	do {	    tempB = temp;	    remainder = tempB % mach64RefFreq;	    tempB = tempB / mach64RefFreq;	    if (((tempB & 0xFFFF) <= 255) && (remainder <= preRemainder)) {		preRemainder = remainder;		divider &= ~0x3f;		divider |= tempA;		divider = (divider & 0x00FF) + ((tempB & 0xFF) << 8);	    }	    temp += mhz100;	    tempA++;	} while(tempA <= 32);	program_bits = divider;    }    pll->program_bits = program_bits;    pll->locationAddr = 0;    pll->post_divider = divider;	/* fuer nix */    pll->period_in_ps = period_in_ps;    return 0;}static u32 aty_pll_408_to_var(const struct pll_18818 *pll){    return(pll->period_in_ps);  /* default for now */}static void aty_set_pll_408(const struct fb_info_aty *info,			    const struct pll_18818 *pll){    u32 program_bits;    u32 locationAddr;    u8 tmpA, tmpB, tmpC;    char old_crtc_ext_disp;    old_crtc_ext_disp = aty_ld_8(CRTC_GEN_CNTL + 3, info);    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp | (CRTC_EXT_DISP_EN >> 24),	     info);    program_bits = pll->program_bits;    locationAddr = pll->locationAddr;    /* Program clock */    aty_dac_waste4(info);    tmpB = aty_ld_8(DAC_REGS + 2, info) | 1;    aty_dac_waste4(info);    aty_st_8(DAC_REGS + 2, tmpB, info);    tmpA = tmpB;    tmpC = tmpA;    tmpA |= 8;    tmpB = 1;    aty_st_8(DAC_REGS, tmpB, info);    aty_st_8(DAC_REGS + 2, tmpA, info);    udelay(400); /* delay for 400 us */    locationAddr = (locationAddr << 2) + 0x40;    tmpB = locationAddr;    tmpA = program_bits >> 8;    aty_st_8(DAC_REGS, tmpB, info);    aty_st_8(DAC_REGS + 2, tmpA, info);    tmpB = locationAddr + 1;    tmpA = (u8)program_bits;    aty_st_8(DAC_REGS, tmpB, info);    aty_st_8(DAC_REGS + 2, tmpA, info);    tmpB = locationAddr + 2;    tmpA = 0x77;    aty_st_8(DAC_REGS, tmpB, info);    aty_st_8(DAC_REGS + 2, tmpA, info);    udelay(400); /* delay for 400 us */    tmpA = tmpC & (~(1 | 8));    tmpB = 1;    aty_st_8(DAC_REGS, tmpB, info);    aty_st_8(DAC_REGS + 2, tmpA, info);    (void)aty_ld_8(DAC_REGS, info); /* Clear DAC Counter */    aty_st_8(CRTC_GEN_CNTL + 3, old_crtc_ext_disp, info);    return;}static int aty_var_to_pll_1703(u32 period_in_ps, struct pll_18818 *pll){    u32 mhz100;			/* in 0.01 MHz */    u32 program_bits;    /* u32 post_divider; */    u32 mach64MinFreq, mach64MaxFreq, mach64RefFreq;    u32 temp, tempB;    u16 remainder, preRemainder;    short divider = 0, tempA;    /* Calculate the programming word */    mhz100 = 100000000 / period_in_ps;    mach64MinFreq = MIN_FREQ_2595;    mach64MaxFreq = MAX_FREQ_2595;    mach64RefFreq = REF_FREQ_2595;	/* 14.32 MHz */    /* Calculate program word */    if (mhz100 == 0)	program_bits = 0xE0;    else {	if (mhz100 < mach64MinFreq)	    mhz100 = mach64MinFreq;	if (mhz100 > mach64MaxFreq)	    mhz100 = mach64MaxFreq;	divider = 0;	while (mhz100 < (mach64MinFreq << 3)) {	    mhz100 <<= 1;	    divider += 0x20;	}	temp = (unsigned int)(mhz100);	temp = (unsigned int)(temp * (MIN_N_1703 + 2));	temp -= (short)(mach64RefFreq << 1);	tempA = MIN_N_1703;	preRemainder = 0xffff;	do {	    tempB = temp;	    remainder = tempB % mach64RefFreq;	    tempB = tempB / mach64RefFreq;	    if ((tempB & 0xffff) <= 127 && (remainder <= preRemainder)) {		preRemainder = remainder;		divider &= ~0x1f;		divider |= tempA;		divider = (divider & 0x00ff) + ((tempB & 0xff) << 8);	    }	    temp += mhz100;	    tempA++;	} while (tempA <= (MIN_N_1703 << 1));	program_bits = divider;    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?