📄 intelfbhw.c
字号:
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 + -