📄 intelfbhw.c
字号:
/* Flush the ring buffer if it's enabled. */ tmp = INREG(PRI_RING_LENGTH); if (tmp & RING_ENABLE) {#if VERBOSE > 0 DBG_MSG("reset_state: ring was enabled\n");#endif 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. */void intelfbhw_2d_stop(struct intelfb_info *dinfo){#if VERBOSE > 0 DBG_MSG("intelfbhw_2d_stop: accel: %d, ring_active: %d\n", dinfo->accel, dinfo->ring_active);#endif 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(). */void intelfbhw_2d_start(struct intelfb_info *dinfo){#if VERBOSE > 0 DBG_MSG("intelfbhw_2d_start: accel: %d, ring_active: %d\n", dinfo->accel, dinfo->ring_active);#endif 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.physical & 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;}/* 2D fillrect (solid fill or invert) */void intelfbhw_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 > 0 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_start + (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();#if VERBOSE > 0 DBG_MSG("ring = 0x%08x, 0x%08x (%d)\n", dinfo->ring_head, dinfo->ring_tail, dinfo->ring_space);#endif}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_start; br11 = (pitch << PITCH_SHIFT); br12 = dinfo->fb_start; 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();}int intelfbhw_do_drawglyph(struct intelfb_info *dinfo, u32 fg, u32 bg, u32 w, u32 h, const u8* cdat, u32 x, u32 y, u32 pitch, u32 bpp){ int nbytes, ndwords, pad, tmp; u32 br00, br09, br13, br18, br19, br22, br23; int dat, ix, iy, iw; int i, j;#if VERBOSE > 0 DBG_MSG("intelfbhw_do_drawglyph: (%d,%d) %dx%d\n", x, y, w, h);#endif /* size in bytes of a padded scanline */ nbytes = ROUND_UP_TO(w, 16) / 8; /* Total bytes of padded scanline data to write out. */ nbytes = nbytes * h; /* * 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. But because the command starts with 7 bytes, pad only if there is an even number of ndwords */ pad = !(ndwords % 2); 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_start; 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; } START_RING(8 + ndwords); OUT_RING(br00); OUT_RING(br13); OUT_RING(br22); OUT_RING(br23); OUT_RING(br09); OUT_RING(br18); OUT_RING(br19); ix = iy = 0; iw = ROUND_UP_TO(w, 8) / 8; while (ndwords--) { dat = 0; for (j = 0; j < 2; ++j) { for (i = 0; i < 2; ++i) { if (ix != iw || i == 0) dat |= cdat[iy*iw + ix++] << (i+j*2)*8; } if (ix == iw && iy != (h-1)) { ix = 0; ++iy; } } OUT_RING(dat); } if (pad) OUT_RING(MI_NOOP); ADVANCE_RING(); return 1;}/* HW cursor functions. */void intelfbhw_cursor_init(struct intelfb_info *dinfo){ u32 tmp;#if VERBOSE > 0 DBG_MSG("intelfbhw_cursor_init\n");#endif if (dinfo->mobile || IS_I9XX(dinfo)) { if (!dinfo->cursor.physical) 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.physical); } else { tmp = INREG(CURSOR_CONTROL); tmp &= ~(CURSOR_FORMAT_MASK | CURSOR_GAMMA_ENABLE | CURSOR_ENABLE | CURSOR_STRIDE_MASK); tmp = CURSOR_FORMAT_3C; OUTREG(CURSOR_CONTROL, tmp); OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.offset << 12); tmp = (64 << CURSOR_SIZE_H_SHIFT) | (64 << CURSOR_SIZE_V_SHIFT); OUTREG(CURSOR_SIZE, tmp); }}void intelfbhw_cursor_hide(struct intelfb_info *dinfo){ u32 tmp;#if VERBOSE > 0 DBG_MSG("intelfbhw_cursor_hide\n");#endif dinfo->cursor_on = 0; if (dinfo->mobile || IS_I9XX(dinfo)) { if (!dinfo->cursor.physical) 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.physical); } else { tmp = INREG(CURSOR_CONTROL); tmp &= ~CURSOR_ENABLE; OUTREG(CURSOR_CONTROL, tmp); }}void intelfbhw_cursor_show(struct intelfb_info *dinfo){ u32 tmp;#if VERBOSE > 0 DBG_MSG("intelfbhw_cursor_show\n");#endif dinfo->cursor_on = 1; if (dinfo->cursor_blanked) return; if (dinfo->mobile || IS_I9XX(dinfo)) { if (!dinfo->cursor.physical) 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.physical); } else { tmp = INREG(CURSOR_CONTROL); tmp |= CURSOR_ENABLE; OUTREG(CURSOR_CONTROL, tmp); }}void intelfbhw_cursor_setpos(struct intelfb_info *dinfo, int x, int y){ u32 tmp;#if VERBOSE > 0 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. */ tmp = ((x & CURSOR_POS_MASK) << CURSOR_X_SHIFT) | ((y & CURSOR_POS_MASK) << CURSOR_Y_SHIFT); OUTREG(CURSOR_A_POSITION, tmp); if (IS_I9XX(dinfo)) OUTREG(CURSOR_A_BASEADDR, dinfo->cursor.physical);}void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg, u32 fg){#if VERBOSE > 0 DBG_MSG("intelfbhw_cursor_setcolor\n");#endif 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);}void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width, int height, u8 *data){ u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; int i, j, w = width / 8; int mod = width % 8, t_mask, d_mask;#if VERBOSE > 0 DBG_MSG("intelfbhw_cursor_load\n");#endif if (!dinfo->cursor.virtual) return; t_mask = 0xff >> mod; d_mask = ~(0xff >> mod); for (i = height; i--; ) { for (j = 0; j < w; j++) { writeb(0x00, addr + j); writeb(*(data++), addr + j+8); } if (mod) { writeb(t_mask, addr + j); writeb(*(data++) & d_mask, addr + j+8); } addr += 16; }}void intelfbhw_cursor_reset(struct intelfb_info *dinfo){ u8 __iomem *addr = (u8 __iomem *)dinfo->cursor.virtual; int i, j;#if VERBOSE > 0 DBG_MSG("intelfbhw_cursor_reset\n");#endif if (!dinfo->cursor.virtual) return; for (i = 64; i--; ) { for (j = 0; j < 8; j++) { writeb(0xff, addr + j+0); writeb(0x00, addr + j+8); } addr += 16; }}static irqreturn_t intelfbhw_irq(int irq, void *dev_id){ u16 tmp; struct intelfb_info *dinfo = dev_id; spin_lock(&dinfo->int_lock); tmp = INREG16(IIR); if (dinfo->info->var.vmode & FB_VMODE_INTERLACED) tmp &= PIPE_A_EVENT_INTERRUPT; else tmp &= VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */ if (tmp == 0) { spin_unlock(&dinfo->int_lock); return IRQ_RETVAL(0); /* not us */ } /* clear status bits 0-15 ASAP and don't touch bits 16-31 */ OUTREG(PIPEASTAT, INREG(PIPEASTAT)); OUTREG16(IIR, tmp); if (dinfo->vsync.pan_display) { dinfo->vsync.pan_display = 0; OUTREG(DSPABASE, dinfo->vsync.pan_offset); } dinfo->vsync.count++; wake_up_interruptible(&dinfo->vsync.wait); spin_unlock(&dinfo->int_lock); return IRQ_RETVAL(1);}int intelfbhw_enable_irq(struct intelfb_info *dinfo){ u16 tmp; if (!test_and_set_bit(0, &dinfo->irq_flags)) { if (request_irq(dinfo->pdev->irq, intelfbhw_irq, IRQF_SHARED, "intelfb", dinfo)) { clear_bit(0, &dinfo->irq_flags); return -EINVAL; } spin_lock_irq(&dinfo->int_lock); OUTREG16(HWSTAM, 0xfffe); /* i830 DRM uses ffff */ OUTREG16(IMR, 0); } else spin_lock_irq(&dinfo->int_lock); if (dinfo->info->var.vmode & FB_VMODE_INTERLACED) tmp = PIPE_A_EVENT_INTERRUPT; else tmp = VSYNC_PIPE_A_INTERRUPT; /* non-interlaced */ if (tmp != INREG16(IER)) { DBG_MSG("changing IER to 0x%X\n", tmp); OUTREG16(IER, tmp); } spin_unlock_irq(&dinfo->int_lock); return 0;}void intelfbhw_disable_irq(struct intelfb_info *dinfo){ if (test_and_clear_bit(0, &dinfo->irq_flags)) { if (dinfo->vsync.pan_display) { dinfo->vsync.pan_display = 0; OUTREG(DSPABASE, dinfo->vsync.pan_offset); } spin_lock_irq(&dinfo->int_lock); OUTREG16(HWSTAM, 0xffff); OUTREG16(IMR, 0xffff); OUTREG16(IER, 0x0); OUTREG16(IIR, INREG16(IIR)); /* clear IRQ requests */ spin_unlock_irq(&dinfo->int_lock); free_irq(dinfo->pdev->irq, dinfo); }}int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe){ struct intelfb_vsync *vsync; unsigned int count; int ret; switch (pipe) { case 0: vsync = &dinfo->vsync; break; default: return -ENODEV; } ret = intelfbhw_enable_irq(dinfo); if (ret) return ret; count = vsync->count; ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ / 10); if (ret < 0) return ret; if (ret == 0) { DBG_MSG("wait_for_vsync timed out!\n"); return -ETIMEDOUT; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -