📄 intelfbhw.c
字号:
printk(" SRC_SIZE_A: 0x%08x\n", hw->src_size_a); printk(" BCLRPAT_A: 0x%08x\n", hw->bclrpat_a); printk(" HTOTAL_B: 0x%08x\n", hw->htotal_b); printk(" HBLANK_B: 0x%08x\n", hw->hblank_b); printk(" HSYNC_B: 0x%08x\n", hw->hsync_b); printk(" VTOTAL_B: 0x%08x\n", hw->vtotal_b); printk(" VBLANK_B: 0x%08x\n", hw->vblank_b); printk(" VSYNC_B: 0x%08x\n", hw->vsync_b); printk(" SRC_SIZE_B: 0x%08x\n", hw->src_size_b); printk(" BCLRPAT_B: 0x%08x\n", hw->bclrpat_b); printk(" ADPA: 0x%08x\n", hw->adpa); printk(" DVOA: 0x%08x\n", hw->dvoa); printk(" DVOB: 0x%08x\n", hw->dvob); printk(" DVOC: 0x%08x\n", hw->dvoc); printk(" DVOA_SRCDIM: 0x%08x\n", hw->dvoa_srcdim); printk(" DVOB_SRCDIM: 0x%08x\n", hw->dvob_srcdim); printk(" DVOC_SRCDIM: 0x%08x\n", hw->dvoc_srcdim); printk(" LVDS: 0x%08x\n", hw->lvds); printk(" PIPEACONF: 0x%08x\n", hw->pipe_a_conf); printk(" PIPEBCONF: 0x%08x\n", hw->pipe_b_conf); printk(" DISPARB: 0x%08x\n", hw->disp_arb); printk(" CURSOR_A_CONTROL: 0x%08x\n", hw->cursor_a_control); printk(" CURSOR_B_CONTROL: 0x%08x\n", hw->cursor_b_control); printk(" CURSOR_A_BASEADDR: 0x%08x\n", hw->cursor_a_base); printk(" CURSOR_B_BASEADDR: 0x%08x\n", hw->cursor_b_base); printk(" CURSOR_A_PALETTE: "); for (i = 0; i < 4; i++) { printk("0x%08x", hw->cursor_a_palette[i]); if (i < 3) printk(", "); } printk("\n"); printk(" CURSOR_B_PALETTE: "); for (i = 0; i < 4; i++) { printk("0x%08x", hw->cursor_b_palette[i]); if (i < 3) printk(", "); } printk("\n"); printk(" CURSOR_SIZE: 0x%08x\n", hw->cursor_size); printk(" DSPACNTR: 0x%08x\n", hw->disp_a_ctrl); printk(" DSPBCNTR: 0x%08x\n", hw->disp_b_ctrl); printk(" DSPABASE: 0x%08x\n", hw->disp_a_base); printk(" DSPBBASE: 0x%08x\n", hw->disp_b_base); printk(" DSPASTRIDE: 0x%08x\n", hw->disp_a_stride); printk(" DSPBSTRIDE: 0x%08x\n", hw->disp_b_stride); printk(" VGACNTRL: 0x%08x\n", hw->vgacntrl); printk(" ADD_ID: 0x%08x\n", hw->add_id); for (i = 0; i < 7; i++) { printk(" SWF0%d 0x%08x\n", i, hw->swf0x[i]); } for (i = 0; i < 7; i++) { printk(" SWF1%d 0x%08x\n", i, hw->swf1x[i]); } for (i = 0; i < 3; i++) { printk(" SWF3%d 0x%08x\n", i, hw->swf3x[i]); } for (i = 0; i < 8; i++) printk(" FENCE%d 0x%08x\n", i, hw->fence[i]); printk(" INSTPM 0x%08x\n", hw->instpm); printk(" MEM_MODE 0x%08x\n", hw->mem_mode); printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0); printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1); printk("hw state dump end\n");#endif}/* Split the M parameter into M1 and M2. */static intsplitm(unsigned int m, unsigned int *retm1, unsigned int *retm2){ int m1, m2; m1 = (m - 2 - (MIN_M2 + MAX_M2) / 2) / 5 - 2; if (m1 < MIN_M1) m1 = MIN_M1; if (m1 > MAX_M1) m1 = MAX_M1; m2 = m - 5 * (m1 + 2) - 2; if (m2 < MIN_M2 || m2 > MAX_M2 || m2 >= m1) { return 1; } else { *retm1 = (unsigned int)m1; *retm2 = (unsigned int)m2; return 0; }}/* Split the P parameter into P1 and P2. */static intsplitp(unsigned int p, unsigned int *retp1, unsigned int *retp2){ int p1, p2; if (p % 4 == 0) p2 = 1; else p2 = 0; p1 = (p / (1 << (p2 + 1))) - 2; if (p % 4 == 0 && p1 < MIN_P1) { p2 = 0; p1 = (p / (1 << (p2 + 1))) - 2; } if (p1 < MIN_P1 || p1 > MAX_P1 || (p1 + 2) * (1 << (p2 + 1)) != p) { return 1; } else { *retp1 = (unsigned int)p1; *retp2 = (unsigned int)p2; return 0; }}static intcalc_pll_params(int clock, u32 *retm1, u32 *retm2, u32 *retn, u32 *retp1, u32 *retp2, u32 *retclock){ u32 m1, m2, n, p1, p2, n1; u32 f_vco, p, p_best = 0, m, f_out; u32 err_max, err_target, err_best = 10000000; u32 n_best = 0, m_best = 0, f_best, f_err; u32 p_min, p_max, p_inc, div_min, div_max; /* Accept 0.5% difference, but aim for 0.1% */ err_max = 5 * clock / 1000; err_target = clock / 1000; DBG_MSG("Clock is %d\n", clock); div_max = MAX_VCO_FREQ / clock; div_min = ROUND_UP_TO(MIN_VCO_FREQ, clock) / clock; if (clock <= P_TRANSITION_CLOCK) p_inc = 4; else p_inc = 2; p_min = ROUND_UP_TO(div_min, p_inc); p_max = ROUND_DOWN_TO(div_max, p_inc); if (p_min < MIN_P) p_min = 4; if (p_max > MAX_P) p_max = 128; DBG_MSG("p range is %d-%d (%d)\n", p_min, p_max, p_inc); p = p_min; do { if (splitp(p, &p1, &p2)) { WRN_MSG("cannot split p = %d\n", p); p += p_inc; continue; } n = MIN_N; f_vco = clock * p; do { m = ROUND_UP_TO(f_vco * n, PLL_REFCLK) / PLL_REFCLK; if (m < MIN_M) m = MIN_M; if (m > MAX_M) m = MAX_M; f_out = CALC_VCLOCK3(m, n, p); if (splitm(m, &m1, &m2)) { WRN_MSG("cannot split m = %d\n", m); n++; continue; } if (clock > f_out) f_err = clock - f_out; else f_err = f_out - clock; if (f_err < err_best) { m_best = m; n_best = n; p_best = p; f_best = f_out; err_best = f_err; } n++; } while ((n <= MAX_N) && (f_out >= clock)); p += p_inc; } while ((p <= p_max)); if (!m_best) { WRN_MSG("cannot find parameters for clock %d\n", clock); return 1; } m = m_best; n = n_best; p = p_best; splitm(m, &m1, &m2); splitp(p, &p1, &p2); n1 = n - 2; DBG_MSG("m, n, p: %d (%d,%d), %d (%d), %d (%d,%d), " "f: %d (%d), VCO: %d\n", m, m1, m2, n, n1, p, p1, p2, CALC_VCLOCK3(m, n, p), CALC_VCLOCK(m1, m2, n1, p1, p2), CALC_VCLOCK3(m, n, p) * p); *retm1 = m1; *retm2 = m2; *retn = n1; *retp1 = p1; *retp2 = p2; *retclock = CALC_VCLOCK(m1, m2, n1, p1, p2); return 0;}static __inline__ intcheck_overflow(u32 value, u32 limit, const char *description){ if (value > limit) { WRN_MSG("%s value %d exceeds limit %d\n", description, value, limit); return 1; } return 0;}/* It is assumed that hw is filled in with the initial state information. */intintelfbhw_mode_to_hw(struct intelfb_info *dinfo, struct intelfb_hwstate *hw, struct fb_var_screeninfo *var){ int pipe = PIPE_A; u32 *dpll, *fp0, *fp1; u32 m1, m2, n, p1, p2, clock_target, clock; u32 hsync_start, hsync_end, hblank_start, hblank_end, htotal, hactive; u32 vsync_start, vsync_end, vblank_start, vblank_end, vtotal, vactive; u32 vsync_pol, hsync_pol; u32 *vs, *vb, *vt, *hs, *hb, *ht, *ss, *pipe_conf; struct display *disp; DBG_MSG("intelfbhw_mode_to_hw\n"); disp = GET_DISP(&dinfo->info, dinfo->currcon); /* Disable VGA */ hw->vgacntrl |= VGA_DISABLE; /* 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; /* Set which pipe's registers will be set. */ if (pipe == PIPE_B) { dpll = &hw->dpll_b; fp0 = &hw->fpb0; fp1 = &hw->fpb1; 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; pipe_conf = &hw->pipe_b_conf; } else { dpll = &hw->dpll_a; fp0 = &hw->fpa0; fp1 = &hw->fpa1; 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; 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; *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(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)); *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; /* Make sure DVOB and DVOC are disabled for now. */ 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; 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); /* Start address and stride. */ if (dinfo->pitch) hw->disp_a_stride = dinfo->pitch; else hw->disp_a_stride = var->xres_virtual * var->bits_per_pixel / 8; 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; /* Check 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; return 0;}/* Program a (non-VGA) video mode. */intintelfbhw_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; u32 hsync_reg, htotal_reg, hblank_reg; u32 vsync_reg, vtotal_reg, vblank_reg; u32 src_size_reg; /* Assume single pipe, display plane A, analog CRT. */ DBG_MSG("intelfbhw_program_mode\n"); /* 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; 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; 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; } /* 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); /* Disable Sync */ tmp = INREG(ADPA); tmp &= ~ADPA_DPMS_CONTROL_MASK; tmp |= ADPA_DPMS_D3; OUTREG(ADPA, tmp); /* turn off pipe */ tmp = INREG(pipe_conf_reg); tmp &= ~PIPECONF_ENABLE; OUTREG(pipe_conf_reg, tmp); /* turn off PLL */ tmp = INREG(dpll_reg); dpll_reg &= ~DPLL_VCO_ENABLE; OUTREG(dpll_reg, tmp); /* Set PLL parameters */ OUTREG(dpll_reg, *dpll & ~DPLL_VCO_ENABLE); OUTREG(fp0_reg, *fp0); OUTREG(fp1_reg, *fp1); /* 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); /* Set ADPA */ OUTREG(ADPA, (hw->adpa & ~(ADPA_DPMS_CONTROL_MASK)) | ADPA_DPMS_D3); /* Enable PLL */ tmp = INREG(dpll_reg); tmp |= DPLL_VCO_ENABLE; OUTREG(dpll_reg, tmp); /* Enable pipe */ OUTREG(pipe_conf_reg, *pipe_conf | PIPECONF_ENABLE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -