📄 intelfbhw.c
字号:
/* Enable sync */ tmp = INREG(ADPA); tmp &= ~ADPA_DPMS_CONTROL_MASK; tmp |= ADPA_DPMS_D0; OUTREG(ADPA, tmp); /* setup display plane */ 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;}static intwait_ring(struct intelfb_info *dinfo, int n){ int i = 0; unsigned long end; u32 last_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK;#if 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 = dinfo->ring_head - (dinfo->ring_tail + RING_MIN_FREE); if (dinfo->ring_space < 0) dinfo->ring_space += dinfo->ring_size; if (dinfo->ring_head != last_head) { end = jiffies + (HZ * 3); last_head = dinfo->ring_head; } i++; if (time_before(end, jiffies)) { WRN_MSG("space: %d wanted %d\n", dinfo->ring_space, n); WRN_MSG("lockup\n"); break; } udelay(1); } return i;}voidintelfbhw_do_sync(struct intelfb_info *dinfo){#if USE_SYNC_PAGE u32 newval;#endif u32 tmp; int i = 0;#if VERBOSE > 0 DBG_MSG("intelfbhw_do_sync\n");#endif#if USE_SYNC_PAGE /* * Although doing MI_STORE_DWORD_IMM after the MI_FLUSH is supposed * to make sure everything is synchronised, there is still some * mis-ordering of operations when mixing 2D with direct CPU * writes to the framebuffer. */ newval = readl(dinfo->syncpage_virt); newval++;#if VERBOSE > 0 DBG_MSG("intelfbhw_do_sync: %d\n", newval);#endif START_RING(6); OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE); OUT_RING(MI_NOOP); OUT_RING(MI_STORE_DWORD_IMM); OUT_RING(dinfo->syncpage_phys); OUT_RING(newval); OUT_RING(MI_NOOP); ADVANCE_RING(); while ((tmp = readl(dinfo->syncpage_virt)) != newval && i < 10000) { i++; udelay(10); } if (tmp != newval) { DBG_MSG("intelfbhw_do_sync: STORE_DWORD_IMM returns %d " "instead of %d\n", tmp, newval); } else {#if VERBOSE > 1 DBG_MSG("intelfbhw_do_sync: done in %d iterations\n", i);#endif }#else /* * 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). */ START_RING(2); OUT_RING(MI_FLUSH | MI_WRITE_DIRTY_STATE); OUT_RING(MI_NOOP); ADVANCE_RING(); wait_ring(dinfo, dinfo->ring_size - RING_MIN_FREE); dinfo->ring_space = dinfo->ring_size - RING_MIN_FREE;#endif}static voidrefresh_ring(struct intelfb_info *dinfo){ DBG_MSG("refresh_ring\n"); dinfo->ring_head = INREG(PRI_RING_HEAD) & RING_HEAD_MASK; dinfo->ring_tail = INREG(PRI_RING_TAIL) & RING_TAIL_MASK; dinfo->ring_space = dinfo->ring_head - (dinfo->ring_tail + RING_MIN_FREE); if (dinfo->ring_space < 0) dinfo->ring_space += dinfo->ring_size;}static voidreset_state(struct intelfb_info *dinfo){ int i; u32 tmp; DBG_MSG("reset_state\n"); for (i = 0; i < FENCE_NUM; i++) OUTREG(FENCE + (i << 2), 0); /* Flush the ring buffer if it's enabled. */ tmp = INREG(PRI_RING_LENGTH); if (tmp & RING_ENABLE) { DBG_MSG("reset_state: ring was enabled\n"); refresh_ring(dinfo); intelfbhw_do_sync(dinfo); DO_RING_IDLE(); } OUTREG(PRI_RING_LENGTH, 0); OUTREG(PRI_RING_HEAD, 0); OUTREG(PRI_RING_TAIL, 0); OUTREG(PRI_RING_START, 0);}/* Stop the 2D engine, and turn off the ring buffer. */voidintelfbhw_2d_stop(struct intelfb_info *dinfo){ DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel, dinfo->ring_active); if (!dinfo->accel) return; dinfo->ring_active = 0; reset_state(dinfo);}/* * Enable the ring buffer, and initialise the 2D engine. * It is assumed that the graphics engine has been stopped by previously * calling intelfb_2d_stop(). */voidintelfbhw_2d_start(struct intelfb_info *dinfo){ DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n", dinfo->accel, dinfo->ring_active); if (!dinfo->accel) return; /* Initialise the primary ring buffer. */ OUTREG(PRI_RING_LENGTH, 0); OUTREG(PRI_RING_TAIL, 0); OUTREG(PRI_RING_HEAD, 0); OUTREG(PRI_RING_START, dinfo->ring_base_phys & RING_START_MASK); OUTREG(PRI_RING_LENGTH, ((dinfo->ring_size - GTT_PAGE_SIZE) & RING_LENGTH_MASK) | RING_NO_REPORT | RING_ENABLE); refresh_ring(dinfo); dinfo->ring_active = 1; DBG_MSG("INSTPM was 0x%08x, setting to 0x%08x\n", INREG(INSTPM), 0x1f << 16); OUTREG(INSTPM, 0x1f << 16); OUTREG(INSTPM, 0x1f << 16);}/* 2D fillrect (solid fill or invert) */voidintelfbhw_do_fillrect(struct intelfb_info *dinfo, u32 x, u32 y, u32 w, u32 h, u32 color, u32 pitch, u32 bpp, u32 rop){ u32 br00, br09, br13, br14, br16;#if VERBOSE > 1 DBG_MSG("intelfbhw_do_fillrect: (%d,%d) %dx%d, c 0x%06x, p %d bpp %d, " "rop 0x%02x\n", x, y, w, h, color, pitch, bpp, rop);#endif br00 = COLOR_BLT_CMD; br09 = dinfo->fb_offset + (y * pitch + x * (bpp / 8)); br13 = (rop << ROP_SHIFT) | pitch; br14 = (h << HEIGHT_SHIFT) | ((w * bpp / 8) << WIDTH_SHIFT); br16 = color; switch (bpp) { case 8: br13 |= COLOR_DEPTH_8; break; case 16: br13 |= COLOR_DEPTH_16; break; case 32: br13 |= COLOR_DEPTH_32; br00 |= WRITE_ALPHA | WRITE_RGB; break; } START_RING(6); OUT_RING(br00); OUT_RING(br13); OUT_RING(br14); OUT_RING(br09); OUT_RING(br16); OUT_RING(MI_NOOP); ADVANCE_RING();}voidintelfbhw_do_bitblt(struct intelfb_info *dinfo, u32 curx, u32 cury, u32 dstx, u32 dsty, u32 w, u32 h, u32 pitch, u32 bpp){ u32 br00, br09, br11, br12, br13, br22, br23, br26;#if VERBOSE > 0 DBG_MSG("intelfbhw_do_bitblt: (%d,%d)->(%d,%d) %dx%d, p %d bpp %d\n", curx, cury, dstx, dsty, w, h, pitch, bpp);#endif br00 = XY_SRC_COPY_BLT_CMD; br09 = dinfo->fb_offset; br11 = (pitch << PITCH_SHIFT); br12 = dinfo->fb_offset; br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT); br22 = (dstx << WIDTH_SHIFT) | (dsty << HEIGHT_SHIFT); br23 = ((dstx + w) << WIDTH_SHIFT) | ((dsty + h) << HEIGHT_SHIFT); br26 = (curx << WIDTH_SHIFT) | (cury << HEIGHT_SHIFT); switch (bpp) { case 8: br13 |= COLOR_DEPTH_8; break; case 16: br13 |= COLOR_DEPTH_16; break; case 32: br13 |= COLOR_DEPTH_32; br00 |= WRITE_ALPHA | WRITE_RGB; break; } START_RING(8); OUT_RING(br00); OUT_RING(br13); OUT_RING(br22); OUT_RING(br23); OUT_RING(br09); OUT_RING(br26); OUT_RING(br11); OUT_RING(br12); ADVANCE_RING();}intintelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, u32 h, u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp){ int i, n = 0, fw_bytes, bytes_per_src_line; int nbytes, ndwords, pad, tmp; u16 *wcdat; u32 *dwcdat; u32 br00, br09, br13, br18, br19, br22, br23;#if 0 DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h);#endif /* Support fonts up to 32 pixels wide. */ if (w > 32) return 0; /* Number of bytes required for each cdat scanline. */ fw_bytes = ROUND_UP_TO(w, 8) / 8; /* Src scanlines are word (16-bit) padded. */ bytes_per_src_line = ROUND_UP_TO(fw_bytes, 2); /* Total bytes of padded scanline data to write out. */ nbytes = h * bytes_per_src_line; /* * Check if the glyph data exceeds the immediate mode limit. * It would take a large font (1K pixels) to hit this limit. */ if (nbytes > MAX_MONO_IMM_SIZE) return 0; /* Src data is packaged a dword (32-bit) at a time. */ ndwords = ROUND_UP_TO(nbytes, 4) / 4; /* Ring has to be padded to a quad word. */ pad = ndwords % 2; /* For easy reference of the glyph data in different sized chunks. */ wcdat = (u16 *)cdat; dwcdat = (u32 *)cdat; tmp = (XY_MONO_SRC_IMM_BLT_CMD & DW_LENGTH_MASK) + ndwords; br00 = (XY_MONO_SRC_IMM_BLT_CMD & ~DW_LENGTH_MASK) | tmp; br09 = dinfo->fb_offset; br13 = (SRC_ROP_GXCOPY << ROP_SHIFT) | (pitch << PITCH_SHIFT); br18 = bg; br19 = fg; br22 = (x << WIDTH_SHIFT) | (y << HEIGHT_SHIFT); br23 = ((x + w) << WIDTH_SHIFT) | ((y + h) << HEIGHT_SHIFT); switch (bpp) { case 8: br13 |= COLOR_DEPTH_8; break; case 16: br13 |= COLOR_DEPTH_16; break; case 32: br13 |= COLOR_DEPTH_32; br00 |= WRITE_ALPHA | WRITE_RGB; break; }#if 0 DBG_MSG("ndwords + pad is %d, pad is %d\n", ndwords + pad, pad);#endif START_RING(ndwords + pad); OUT_RING(br00); OUT_RING(br13); OUT_RING(br22); OUT_RING(br23); OUT_RING(br09); OUT_RING(br18); OUT_RING(br19); i = h; switch (fw_bytes) { case 1: while (i >= 2) { OUT_RING(cdat[0] | cdat[1] << 16); cdat +=2; i -= 2; n++; } if (i) { OUT_RING(cdat[0]); n++; } break; case 2: while (i >= 2) { OUT_RING(wcdat[0] | wcdat[1] << 16); wcdat += 2; i -= 2; n++; } if (i) { OUT_RING(wcdat[0]); n++; } break; case 3: while (i) { OUT_RING(wcdat[0] | cdat[3] << 16); wcdat += 2; cdat += 4; i--; n++; } break; case 4: while(i) { OUT_RING(dwcdat[0]); i--; n++; } } if (pad) { OUT_RING(MI_NOOP); n++; }#if 0 DBG_MSG("%d immediate bytes + pad\n", n);#endif ADVANCE_RING(); return 1;}/* HW cursor functions. */voidintelfbhw_cursor_init(struct intelfb_info *dinfo){ u32 tmp; DBG_MSG("intelfbhw_cursor_init\n"); if (!dinfo->cursor_base) return; if (dinfo->mobile) { if (!dinfo->cursor_base_real) return; tmp = INREG(CURSOR_A_CONTROL); tmp &= ~(CURSOR_MODE_MASK | CURSOR_MOBILE_GAMMA_ENABLE | CURSOR_MEM_TYPE_LOCAL | (1 << CURSOR_PIPE_SELECT_SHIFT)); tmp |= CURSOR_MODE_DISABLE; OUTREG(CURSOR_A_CONTROL, tmp); OUTREG(CURSOR_A_BASEADDR, dinfo->cursor_base_real); } else {#if 0 tmp = INREG(CURSOR_CONTROL); tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE | CURSOR_ENABLE | CURSOR_STRIDE_MASK);#endif tmp = CURSOR_FORMAT_3C; OUTREG(CURSOR_CONTROL, tmp); OUTREG(CURSOR_A_BASEADDR, dinfo->cursor_offset); tmp = (64 << CURSOR_SIZE_H_SHIFT) | (64 << CURSOR_SIZE_V_SHIFT); OUTREG(CURSOR_SIZE, tmp); }}voidintelfbhw_cursor_hide(struct intelfb_info *dinfo){ u32 tmp;#if VERBOSE > 1 DBG_MSG("intelfbhw_cursor_hide\n");#endif if (!dinfo->cursor_base) return; dinfo->cursor.enabled = 0; dinfo->cursor.on = 0; if (dinfo->mobile) { if (!dinfo->cursor_base_real) return; tmp = INREG(CURSOR_A_CONTROL); tmp &= ~CURSOR_MODE_MASK; tmp |= CURSOR_MODE_DISABLE; OUTREG(CURSOR_A_CONTROL, tmp); /* Flush changes */ OUTREG(CURSOR_A_BASEADDR, dinfo->cursor_base_real); } else { tmp = INREG(CURSOR_CONTROL); tmp &= ~CURSOR_ENABLE; OUTREG(CURSOR_CONTROL, tmp); }}voidintelfbhw_cursor_show(struct intelfb_info *dinfo){ u32 tmp;#if VERBOSE > 1 DBG_MSG("intelfbhw_cursor_show\n");#endif if (!dinfo->cursor_base) return; dinfo->cursor.on = 1; dinfo->cursor.enabled = 1; if (dinfo->cursor.blanked) return; if (dinfo->mobile) { if (!dinfo->cursor_base_real) return; tmp = INREG(CURSOR_A_CONTROL); tmp &= ~CURSOR_MODE_MASK; tmp |= CURSOR_MODE_64_4C_AX; OUTREG(CURSOR_A_CONTROL, tmp); /* Flush changes */ OUTREG(CURSOR_A_BASEADDR, dinfo->cursor_base_real); } else { tmp = INREG(CURSOR_CONTROL); tmp |= CURSOR_ENABLE; OUTREG(CURSOR_CONTROL, tmp); }}voidintelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y){ u32 tmp;#if VERBOSE > 1 DBG_MSG("intelfbhw_cursor_setpos: (%d, %d)\n", x, y);#endif /* * Sets the position. The coordinates are assumed to already * have any offset adjusted. Assume that the cursor is never * completely off-screen, and that x, y are always >= 0. */ if (!dinfo->cursor_base) return; tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); OUTREG(CURSOR_A_POSITION, tmp);}voidintelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg){#if VERBOSE > 1 DBG_MSG("intelfbhw_cursor_setcolor\n");#endif if (!dinfo->cursor_base) return; OUTREG(CURSOR_A_PALETTE0, bg & CURSOR_PALETTE_MASK); OUTREG(CURSOR_A_PALETTE1, fg & CURSOR_PALETTE_MASK); OUTREG(CURSOR_A_PALETTE2, fg & CURSOR_PALETTE_MASK); OUTREG(CURSOR_A_PALETTE3, bg & CURSOR_PALETTE_MASK);}voidintelfbhw_cursor_load(struct intelfb_info *dinfo, struct display *disp){ u32 xline, mline; int i; DBG_MSG("intelfbhw_cursor_load\n"); if (!dinfo->cursor_base) return; intelfb_create_cursor_shape(dinfo, disp); xline = (1 << dinfo->cursor.w) - 1; mline = ~xline; for (i = 0; i < dinfo->cursor.u; i++) { writel(~0, dinfo->cursor_base + i * 16); writel(~0, dinfo->cursor_base + i * 16 + 4); writel(0, dinfo->cursor_base + i * 16 + 8); writel(0, dinfo->cursor_base + i * 16 + 12); } for (; i < dinfo->cursor.d; i++) { writel(mline, dinfo->cursor_base + i * 16); writel(~0, dinfo->cursor_base + i * 16 + 4); writel(xline, dinfo->cursor_base + i * 16 + 8); writel(0, dinfo->cursor_base + i * 16 + 12); } for (; i < 64; i++) { writel(~0, dinfo->cursor_base + i * 16); writel(~0, dinfo->cursor_base + i * 16 + 4); writel(0, dinfo->cursor_base + i * 16 + 8); writel(0, dinfo->cursor_base + i * 16 + 12); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -