⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 intelfbhw.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		hb = &hw->hblank_a;		ht = &hw->htotal_a;		vs = &hw->vsync_a;		vb = &hw->vblank_a;		vt = &hw->vtotal_a;		ss = &hw->src_size_a;		pipe_conf = &hw->pipe_a_conf;	}	/* Use ADPA register for sync control. */	hw->adpa &= ~ADPA_USE_VGA_HVPOLARITY;	/* sync polarity */	hsync_pol = (var->sync & FB_SYNC_HOR_HIGH_ACT) ?			ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;	vsync_pol = (var->sync & FB_SYNC_VERT_HIGH_ACT) ?			ADPA_SYNC_ACTIVE_HIGH : ADPA_SYNC_ACTIVE_LOW;	hw->adpa &= ~((ADPA_SYNC_ACTIVE_MASK << ADPA_VSYNC_ACTIVE_SHIFT) |		      (ADPA_SYNC_ACTIVE_MASK << ADPA_HSYNC_ACTIVE_SHIFT));	hw->adpa |= (hsync_pol << ADPA_HSYNC_ACTIVE_SHIFT) |		    (vsync_pol << ADPA_VSYNC_ACTIVE_SHIFT);	/* Connect correct pipe to the analog port DAC */	hw->adpa &= ~(PIPE_MASK << ADPA_PIPE_SELECT_SHIFT);	hw->adpa |= (pipe << ADPA_PIPE_SELECT_SHIFT);	/* Set DPMS state to D0 (on) */	hw->adpa &= ~ADPA_DPMS_CONTROL_MASK;	hw->adpa |= ADPA_DPMS_D0;	hw->adpa |= ADPA_DAC_ENABLE;	*dpll |= (DPLL_VCO_ENABLE | DPLL_VGA_MODE_DISABLE);	*dpll &= ~(DPLL_RATE_SELECT_MASK | DPLL_REFERENCE_SELECT_MASK);	*dpll |= (DPLL_REFERENCE_DEFAULT | DPLL_RATE_SELECT_FP0);	/* Desired clock in kHz */	clock_target = 1000000000 / var->pixclock;	if (calc_pll_params(dinfo->pll_index, clock_target, &m1, &m2,			    &n, &p1, &p2, &clock)) {		WRN_MSG("calc_pll_params failed\n");		return 1;	}	/* Check for overflow. */	if (check_overflow(p1, DPLL_P1_MASK, "PLL P1 parameter"))		return 1;	if (check_overflow(p2, DPLL_P2_MASK, "PLL P2 parameter"))		return 1;	if (check_overflow(m1, FP_DIVISOR_MASK, "PLL M1 parameter"))		return 1;	if (check_overflow(m2, FP_DIVISOR_MASK, "PLL M2 parameter"))		return 1;	if (check_overflow(n, FP_DIVISOR_MASK, "PLL N parameter"))		return 1;	*dpll &= ~DPLL_P1_FORCE_DIV2;	*dpll &= ~((DPLL_P2_MASK << DPLL_P2_SHIFT) |		   (DPLL_P1_MASK << DPLL_P1_SHIFT));	if (IS_I9XX(dinfo)) {		*dpll |= (p2 << DPLL_I9XX_P2_SHIFT);		*dpll |= (1 << (p1 - 1)) << DPLL_P1_SHIFT;	} else		*dpll |= (p2 << DPLL_P2_SHIFT) | (p1 << DPLL_P1_SHIFT);	*fp0 = (n << FP_N_DIVISOR_SHIFT) |	       (m1 << FP_M1_DIVISOR_SHIFT) |	       (m2 << FP_M2_DIVISOR_SHIFT);	*fp1 = *fp0;	hw->dvob &= ~PORT_ENABLE;	hw->dvoc &= ~PORT_ENABLE;	/* Use display plane A. */	hw->disp_a_ctrl |= DISPPLANE_PLANE_ENABLE;	hw->disp_a_ctrl &= ~DISPPLANE_GAMMA_ENABLE;	hw->disp_a_ctrl &= ~DISPPLANE_PIXFORMAT_MASK;	switch (intelfb_var_to_depth(var)) {	case 8:		hw->disp_a_ctrl |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE;		break;	case 15:		hw->disp_a_ctrl |= DISPPLANE_15_16BPP;		break;	case 16:		hw->disp_a_ctrl |= DISPPLANE_16BPP;		break;	case 24:		hw->disp_a_ctrl |= DISPPLANE_32BPP_NO_ALPHA;		break;	}	hw->disp_a_ctrl &= ~(PIPE_MASK << DISPPLANE_SEL_PIPE_SHIFT);	hw->disp_a_ctrl |= (pipe << DISPPLANE_SEL_PIPE_SHIFT);	/* Set CRTC registers. */	hactive = var->xres;	hsync_start = hactive + var->right_margin;	hsync_end = hsync_start + var->hsync_len;	htotal = hsync_end + var->left_margin;	hblank_start = hactive;	hblank_end = htotal;	DBG_MSG("H: act %d, ss %d, se %d, tot %d bs %d, be %d\n",		hactive, hsync_start, hsync_end, htotal, hblank_start,		hblank_end);	vactive = var->yres;	if (var->vmode & FB_VMODE_INTERLACED)		vactive--; /* the chip adds 2 halflines automatically */	vsync_start = vactive + var->lower_margin;	vsync_end = vsync_start + var->vsync_len;	vtotal = vsync_end + var->upper_margin;	vblank_start = vactive;	vblank_end = vtotal;	vblank_end = vsync_end + 1;	DBG_MSG("V: act %d, ss %d, se %d, tot %d bs %d, be %d\n",		vactive, vsync_start, vsync_end, vtotal, vblank_start,		vblank_end);	/* Adjust for register values, and check for overflow. */	hactive--;	if (check_overflow(hactive, HACTIVE_MASK, "CRTC hactive"))		return 1;	hsync_start--;	if (check_overflow(hsync_start, HSYNCSTART_MASK, "CRTC hsync_start"))		return 1;	hsync_end--;	if (check_overflow(hsync_end, HSYNCEND_MASK, "CRTC hsync_end"))		return 1;	htotal--;	if (check_overflow(htotal, HTOTAL_MASK, "CRTC htotal"))		return 1;	hblank_start--;	if (check_overflow(hblank_start, HBLANKSTART_MASK, "CRTC hblank_start"))		return 1;	hblank_end--;	if (check_overflow(hblank_end, HBLANKEND_MASK, "CRTC hblank_end"))		return 1;	vactive--;	if (check_overflow(vactive, VACTIVE_MASK, "CRTC vactive"))		return 1;	vsync_start--;	if (check_overflow(vsync_start, VSYNCSTART_MASK, "CRTC vsync_start"))		return 1;	vsync_end--;	if (check_overflow(vsync_end, VSYNCEND_MASK, "CRTC vsync_end"))		return 1;	vtotal--;	if (check_overflow(vtotal, VTOTAL_MASK, "CRTC vtotal"))		return 1;	vblank_start--;	if (check_overflow(vblank_start, VBLANKSTART_MASK, "CRTC vblank_start"))		return 1;	vblank_end--;	if (check_overflow(vblank_end, VBLANKEND_MASK, "CRTC vblank_end"))		return 1;	*ht = (htotal << HTOTAL_SHIFT) | (hactive << HACTIVE_SHIFT);	*hb = (hblank_start << HBLANKSTART_SHIFT) |	      (hblank_end << HSYNCEND_SHIFT);	*hs = (hsync_start << HSYNCSTART_SHIFT) | (hsync_end << HSYNCEND_SHIFT);	*vt = (vtotal << VTOTAL_SHIFT) | (vactive << VACTIVE_SHIFT);	*vb = (vblank_start << VBLANKSTART_SHIFT) |	      (vblank_end << VSYNCEND_SHIFT);	*vs = (vsync_start << VSYNCSTART_SHIFT) | (vsync_end << VSYNCEND_SHIFT);	*ss = (hactive << SRC_SIZE_HORIZ_SHIFT) |	      (vactive << SRC_SIZE_VERT_SHIFT);	hw->disp_a_stride = dinfo->pitch;	DBG_MSG("pitch is %d\n", hw->disp_a_stride);	hw->disp_a_base = hw->disp_a_stride * var->yoffset +			  var->xoffset * var->bits_per_pixel / 8;	hw->disp_a_base += dinfo->fb.offset << 12;	/* Check stride alignment. */	stride_alignment = IS_I9XX(dinfo) ? STRIDE_ALIGNMENT_I9XX :					    STRIDE_ALIGNMENT;	if (hw->disp_a_stride % stride_alignment != 0) {		WRN_MSG("display stride %d has bad alignment %d\n",			hw->disp_a_stride, stride_alignment);		return 1;	}	/* Set the palette to 8-bit mode. */	*pipe_conf &= ~PIPECONF_GAMMA;	if (var->vmode & FB_VMODE_INTERLACED)		*pipe_conf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;	else		*pipe_conf &= ~PIPECONF_INTERLACE_MASK;	return 0;}/* Program a (non-VGA) video mode. */int intelfbhw_program_mode(struct intelfb_info *dinfo,			   const struct intelfb_hwstate *hw, int blank){	int pipe = PIPE_A;	u32 tmp;	const u32 *dpll, *fp0, *fp1, *pipe_conf;	const u32 *hs, *ht, *hb, *vs, *vt, *vb, *ss;	u32 dpll_reg, fp0_reg, fp1_reg, pipe_conf_reg, pipe_stat_reg;	u32 hsync_reg, htotal_reg, hblank_reg;	u32 vsync_reg, vtotal_reg, vblank_reg;	u32 src_size_reg;	u32 count, tmp_val[3];	/* Assume single pipe, display plane A, analog CRT. */#if VERBOSE > 0	DBG_MSG("intelfbhw_program_mode\n");#endif	/* Disable VGA */	tmp = INREG(VGACNTRL);	tmp |= VGA_DISABLE;	OUTREG(VGACNTRL, tmp);	/* Check whether pipe A or pipe B is enabled. */	if (hw->pipe_a_conf & PIPECONF_ENABLE)		pipe = PIPE_A;	else if (hw->pipe_b_conf & PIPECONF_ENABLE)		pipe = PIPE_B;	dinfo->pipe = pipe;	if (pipe == PIPE_B) {		dpll = &hw->dpll_b;		fp0 = &hw->fpb0;		fp1 = &hw->fpb1;		pipe_conf = &hw->pipe_b_conf;		hs = &hw->hsync_b;		hb = &hw->hblank_b;		ht = &hw->htotal_b;		vs = &hw->vsync_b;		vb = &hw->vblank_b;		vt = &hw->vtotal_b;		ss = &hw->src_size_b;		dpll_reg = DPLL_B;		fp0_reg = FPB0;		fp1_reg = FPB1;		pipe_conf_reg = PIPEBCONF;		pipe_stat_reg = PIPEBSTAT;		hsync_reg = HSYNC_B;		htotal_reg = HTOTAL_B;		hblank_reg = HBLANK_B;		vsync_reg = VSYNC_B;		vtotal_reg = VTOTAL_B;		vblank_reg = VBLANK_B;		src_size_reg = SRC_SIZE_B;	} else {		dpll = &hw->dpll_a;		fp0 = &hw->fpa0;		fp1 = &hw->fpa1;		pipe_conf = &hw->pipe_a_conf;		hs = &hw->hsync_a;		hb = &hw->hblank_a;		ht = &hw->htotal_a;		vs = &hw->vsync_a;		vb = &hw->vblank_a;		vt = &hw->vtotal_a;		ss = &hw->src_size_a;		dpll_reg = DPLL_A;		fp0_reg = FPA0;		fp1_reg = FPA1;		pipe_conf_reg = PIPEACONF;		pipe_stat_reg = PIPEASTAT;		hsync_reg = HSYNC_A;		htotal_reg = HTOTAL_A;		hblank_reg = HBLANK_A;		vsync_reg = VSYNC_A;		vtotal_reg = VTOTAL_A;		vblank_reg = VBLANK_A;		src_size_reg = SRC_SIZE_A;	}	/* turn off pipe */	tmp = INREG(pipe_conf_reg);	tmp &= ~PIPECONF_ENABLE;	OUTREG(pipe_conf_reg, tmp);	count = 0;	do {		tmp_val[count % 3] = INREG(PIPEA_DSL);		if ((tmp_val[0] == tmp_val[1]) && (tmp_val[1] == tmp_val[2]))			break;		count++;		udelay(1);		if (count % 200 == 0) {			tmp = INREG(pipe_conf_reg);			tmp &= ~PIPECONF_ENABLE;			OUTREG(pipe_conf_reg, tmp);		}	} while (count < 2000);	OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);	/* Disable planes A and B. */	tmp = INREG(DSPACNTR);	tmp &= ~DISPPLANE_PLANE_ENABLE;	OUTREG(DSPACNTR, tmp);	tmp = INREG(DSPBCNTR);	tmp &= ~DISPPLANE_PLANE_ENABLE;	OUTREG(DSPBCNTR, tmp);	/* Wait for vblank. For now, just wait for a 50Hz cycle (20ms)) */	mdelay(20);	OUTREG(DVOB, INREG(DVOB) & ~PORT_ENABLE);	OUTREG(DVOC, INREG(DVOC) & ~PORT_ENABLE);	OUTREG(ADPA, INREG(ADPA) & ~ADPA_DAC_ENABLE);	/* Disable Sync */	tmp = INREG(ADPA);	tmp &= ~ADPA_DPMS_CONTROL_MASK;	tmp |= ADPA_DPMS_D3;	OUTREG(ADPA, tmp);	/* do some funky magic - xyzzy */	OUTREG(0x61204, 0xabcd0000);	/* turn off PLL */	tmp = INREG(dpll_reg);	tmp &= ~DPLL_VCO_ENABLE;	OUTREG(dpll_reg, tmp);	/* Set PLL parameters */	OUTREG(fp0_reg, *fp0);	OUTREG(fp1_reg, *fp1);	/* Enable PLL */	OUTREG(dpll_reg, *dpll);	/* Set DVOs B/C */	OUTREG(DVOB, hw->dvob);	OUTREG(DVOC, hw->dvoc);	/* undo funky magic */	OUTREG(0x61204, 0x00000000);	/* Set ADPA */	OUTREG(ADPA, INREG(ADPA) | ADPA_DAC_ENABLE);	OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3);	/* Set pipe parameters */	OUTREG(hsync_reg, *hs);	OUTREG(hblank_reg, *hb);	OUTREG(htotal_reg, *ht);	OUTREG(vsync_reg, *vs);	OUTREG(vblank_reg, *vb);	OUTREG(vtotal_reg, *vt);	OUTREG(src_size_reg, *ss);	switch (dinfo->info->var.vmode & (FB_VMODE_INTERLACED |					  FB_VMODE_ODD_FLD_FIRST)) {	case FB_VMODE_INTERLACED | FB_VMODE_ODD_FLD_FIRST:		OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_ODD_EN);		break;	case FB_VMODE_INTERLACED: /* even lines first */		OUTREG(pipe_stat_reg, 0xFFFF | PIPESTAT_FLD_EVT_EVEN_EN);		break;	default:		/* non-interlaced */		OUTREG(pipe_stat_reg, 0xFFFF); /* clear all status bits only */	}	/* Enable pipe */	OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);	/* Enable sync */	tmp = INREG(ADPA);	tmp &= ~ADPA_DPMS_CONTROL_MASK;	tmp |= ADPA_DPMS_D0;	OUTREG(ADPA, tmp);	/* setup display plane */	if (dinfo->pdev->device == PCI_DEVICE_ID_INTEL_830M) {		/*		 *      i830M errata: the display plane must be enabled		 *      to allow writes to the other bits in the plane		 *      control register.		 */		tmp = INREG(DSPACNTR);		if ((tmp & DISPPLANE_PLANE_ENABLE) != DISPPLANE_PLANE_ENABLE) {			tmp |= DISPPLANE_PLANE_ENABLE;			OUTREG(DSPACNTR, tmp);			OUTREG(DSPACNTR,			       hw->disp_a_ctrl|DISPPLANE_PLANE_ENABLE);			mdelay(1);		}	}	OUTREG(DSPACNTR, hw->disp_a_ctrl & ~DISPPLANE_PLANE_ENABLE);	OUTREG(DSPASTRIDE, hw->disp_a_stride);	OUTREG(DSPABASE, hw->disp_a_base);	/* Enable plane */	if (!blank) {		tmp = INREG(DSPACNTR);		tmp |= DISPPLANE_PLANE_ENABLE;		OUTREG(DSPACNTR, tmp);		OUTREG(DSPABASE, hw->disp_a_base);	}	return 0;}/* forward declarations */static void refresh_ring(struct intelfb_info *dinfo);static void reset_state(struct intelfb_info *dinfo);static void do_flush(struct intelfb_info *dinfo);static  u32 get_ring_space(struct intelfb_info *dinfo){	u32 ring_space;	if (dinfo->ring_tail >= dinfo->ring_head)		ring_space = dinfo->ring.size -			(dinfo->ring_tail - dinfo->ring_head);	else		ring_space = dinfo->ring_head - dinfo->ring_tail;	if (ring_space > RING_MIN_FREE)		ring_space -= RING_MIN_FREE;	else		ring_space = 0;	return ring_space;}static int wait_ring(struct intelfb_info *dinfo, int n){	int i = 0;	unsigned long end;	u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;#if VERBOSE > 0	DBG_MSG("wait_ring: %d\n", n);#endif	end = jiffies + (HZ * 3);	while (dinfo->ring_space < n) {		dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;		dinfo->ring_space = get_ring_space(dinfo);		if (dinfo->ring_head != last_head) {			end = jiffies + (HZ * 3);			last_head = dinfo->ring_head;		}		i++;		if (time_before(end, jiffies)) {			if (!i) {				/* Try again */				reset_state(dinfo);				refresh_ring(dinfo);				do_flush(dinfo);				end = jiffies + (HZ * 3);				i = 1;			} else {				WRN_MSG("ring buffer : space: %d wanted %d\n",					dinfo->ring_space, n);				WRN_MSG("lockup - turning off hardware "					"acceleration\n");				dinfo->ring_lockup = 1;				break;			}		}		udelay(1);	}	return i;}static void do_flush(struct intelfb_info *dinfo){	START_RING(2);	OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE | MI_INVALIDATE_MAP_CACHE);	OUT_RING(MI_NOOP);	ADVANCE_RING();}void intelfbhw_do_sync(struct intelfb_info *dinfo){#if VERBOSE > 0	DBG_MSG("intelfbhw_do_sync\n");#endif	if (!dinfo->accel)		return;	/*	 * Send a flush, then wait until the ring is empty.  This is what	 * the XFree86 driver does, and actually it doesn't seem a lot worse	 * than the recommended method (both have problems).	 */	do_flush(dinfo);	wait_ring(dinfo, dinfo->ring.size - RING_MIN_FREE);	dinfo->ring_space = dinfo->ring.size - RING_MIN_FREE;}static void refresh_ring(struct intelfb_info *dinfo){#if VERBOSE > 0	DBG_MSG("refresh_ring\n");#endif	dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;	dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK;	dinfo->ring_space = get_ring_space(dinfo);}static void reset_state(struct intelfb_info *dinfo){	int i;	u32 tmp;#if VERBOSE > 0	DBG_MSG("reset_state\n");#endif	for (i = 0; i < FENCE_NUM; i++)		OUTREG(FENCE + (i << 2), 0);

⌨️ 快捷键说明

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