📄 epson1356fb.c
字号:
static inte1356_calc_pixclock(const struct fb_info_e1356 *info, pixclock_info_t* ipclk){ int src_sel=-1, flicker_mult=0; pixclock_info_t test, ret; if (ipclk->pixclk > info->max_pixclock) return -ENXIO; test.pixclk_d = ipclk->pixclk_d; ret.error = 100; if (IS_TV(info->fix.disp_type) && (info->fix.tv_filt & TV_FILT_FLICKER)) flicker_mult = 0x80; test.clksrc = info->fix.busclk; if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 && abs(test.error) < abs(ret.error)) { ret = test; src_sel = 0x01; } test.clksrc = info->fix.mclk; if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 && abs(test.error) < abs(ret.error)) { ret = test; src_sel = 0x03; } test.clksrc = info->fix.clki; if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 && abs(test.error) < abs(ret.error)) { ret = test; src_sel = 0x00; } test.clksrc = info->fix.clki2; if (get_nearest_pixclk_div(&test, flicker_mult != 0) == 0 && abs(test.error) < abs(ret.error)) { ret = test; src_sel = 0x02; } if (ret.error > MAX_PCLK_ERROR_LOWER || ret.error < MAX_PCLK_ERROR_HIGHER) return -ENXIO; ret.pixclk_bits = flicker_mult | ((ret.divisor-1)<<4) | src_sel; *ipclk = ret; return 0;}static inline inte1356_engine_wait_complete(reg_bitblt_t* bltreg){ return e1356_wait_bitclr(&bltreg->ctrl0, 0x80, 5000);}static inline inte1356_engine_wait_busy(reg_bitblt_t* bltreg){ return e1356_wait_bitset(&bltreg->ctrl0, 0x80, 5000);}static voide1356fb_engine_init(const struct e1356fb_par* par, struct fb_info_e1356* info){ reg_bitblt_t* bltreg = info->reg.bitblt; e1356_engine_wait_complete(bltreg); writeb(0, &bltreg->ctrl0); writeb(0, &bltreg->ctrl1); writeb(0, &bltreg->rop_code); writeb(0, &bltreg->operation); writeb(0, &bltreg->src_start_addr0); writeb(0, &bltreg->src_start_addr1); writeb(0, &bltreg->src_start_addr2); writeb(0, &bltreg->dest_start_addr0); writeb(0, &bltreg->dest_start_addr1); writeb(0, &bltreg->dest_start_addr2); writew(0, &bltreg->mem_addr_offset0); writew(0, &bltreg->width0); writew(0, &bltreg->height0); writew(0, &bltreg->bg_color0); writew(0, &bltreg->fg_color0);}static void doBlt_Write(const struct e1356fb_par* par, struct fb_info_e1356* info, blt_info_t* blt){ reg_bitblt_t* bltreg = info->reg.bitblt; int nWords, nTotalWords; u32 srcphase, dstAddr; u16* w16; u32 stride = par->width_virt * par->Bpp; dstAddr = blt->dst_x * par->Bpp + blt->dst_y * stride; srcphase = (u32)blt->src & 1; if (blt->attribute & BLT_ATTR_TRANSPARENT) writew(blt->bg_color, &bltreg->bg_color0); else writeb(blt->rop, &bltreg->rop_code); writeb(blt->operation, &bltreg->operation); writeb((u8)srcphase, &bltreg->src_start_addr0); writew(stride/2, &bltreg->mem_addr_offset0); writeb(dstAddr, &bltreg->dest_start_addr0); writeb(dstAddr>>8, &bltreg->dest_start_addr1); writeb(dstAddr>>16, &bltreg->dest_start_addr2); writew(blt->dst_width-1, &bltreg->width0); writew(blt->dst_height-1, &bltreg->height0); // program color format operation writeb(par->bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1); // start it up writeb(0x80, &bltreg->ctrl0); // wait for it to actually start e1356_engine_wait_busy(bltreg); // calculate the number of 16 bit words per one blt line nWords = srcphase + ((blt->dst_width - srcphase)*par->Bpp + 1) / 2; nTotalWords = nWords*blt->dst_height; w16 = (u16*)((u32)blt->src & 0xfffffffe); // Word aligned while (nTotalWords > 0) { int j, nFIFO; u8 ctrl0; // read the FIFO status ctrl0 = readb(&bltreg->ctrl0); if ((ctrl0 & 0x30) == 0x20) // FIFO is at least half full, but not full nFIFO = 1; else if ((ctrl0 & 0x40) == 0) // FIFO is empty nFIFO = 16; else // FIFO is full continue; for (j = 0; j < nFIFO && nTotalWords > 0; j++,nTotalWords--) writew(*w16++, info->reg.bitblt_data); } e1356_engine_wait_complete(bltreg);}static voiddoBlt_SolidFill(const struct e1356fb_par* par, struct fb_info_e1356* info, blt_info_t* blt){ reg_bitblt_t* bltreg = info->reg.bitblt; u32 width = blt->dst_width, height = blt->dst_height; u32 stride = par->width_virt * par->Bpp; u32 dest_addr = (blt->dst_y * stride) + (blt->dst_x * par->Bpp); if (width == 0 || height == 0) return; // program dest address writeb(dest_addr & 0x00ff, &bltreg->dest_start_addr0); writeb((dest_addr>>8) & 0x00ff, &bltreg->dest_start_addr1); writeb((dest_addr>>16) & 0x00ff, &bltreg->dest_start_addr2); // program width and height of solid-fill blit writew(width-1, &bltreg->width0); writew(height-1, &bltreg->height0); // program color of fill writew(blt->fg_color, &bltreg->fg_color0); // select solid-fill BLIT writeb(BLT_SOLID_FILL, &bltreg->operation); // program color format operation writeb(par->bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1); // program BLIT memory offset writew(stride/2, &bltreg->mem_addr_offset0); // start it up (self completes) writeb(0x80, &bltreg->ctrl0); e1356_engine_wait_complete(bltreg);}static voiddoBlt_Move(const struct e1356fb_par* par, struct fb_info_e1356* info, blt_info_t* blt){ reg_bitblt_t* bltreg = info->reg.bitblt; int neg_dir=0; u32 dest_addr, src_addr; u32 bpp = par->bpp; u32 stride = par->width_virt * par->Bpp; // virt line length in bytes u32 srcx = blt->src_x, srcy = blt->src_y; u32 dstx = blt->dst_x, dsty = blt->dst_y; u32 width = blt->dst_width, height = blt->dst_height; if (width == 0 || height == 0) return; src_addr = srcx*par->Bpp + srcy*stride; dest_addr = dstx*par->Bpp + dsty*stride; /* * See if regions overlap and dest region is beyond source region. * If so, we need to do a move BLT in negative direction. Only applies * if the BLT is not transparent. */ if (!(blt->attribute & BLT_ATTR_TRANSPARENT)) { if ((srcx + width > dstx) && (srcx < dstx + width) && (srcy + height > dsty) && (srcy < dsty + height) && (dest_addr > src_addr)) { neg_dir = 1; // negative direction : get the coords of lower right corner src_addr += stride * (height-1) + par->Bpp * (width-1); dest_addr += stride * (height-1) + par->Bpp * (width-1); } } // program BLIT memory offset writew(stride/2, &bltreg->mem_addr_offset0); // program src and dest addresses writeb(src_addr & 0x00ff, &bltreg->src_start_addr0); writeb((src_addr>>8) & 0x00ff, &bltreg->src_start_addr1); writeb((src_addr>>16) & 0x00ff, &bltreg->src_start_addr2); writeb(dest_addr & 0x00ff, &bltreg->dest_start_addr0); writeb((dest_addr>>8) & 0x00ff, &bltreg->dest_start_addr1); writeb((dest_addr>>16) & 0x00ff, &bltreg->dest_start_addr2); // program width and height of blit writew(width-1, &bltreg->width0); writew(height-1, &bltreg->height0); // program color format operation writeb(bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1); // set the blt type if (blt->attribute & BLT_ATTR_TRANSPARENT) { writew(blt->bg_color, &bltreg->bg_color0); writeb(BLT_MOVE_POS_TRANSP, &bltreg->operation); } else { writeb(blt->rop, &bltreg->rop_code); // select pos/neg move BLIT writeb(neg_dir ? BLT_MOVE_NEG_ROP : BLT_MOVE_POS_ROP, &bltreg->operation); } // start it up (self completes) writeb(0x80, &bltreg->ctrl0); e1356_engine_wait_complete(bltreg);}static void doBlt_ColorExpand(const struct e1356fb_par* par, struct fb_info_e1356* info, blt_info_t* blt){ reg_bitblt_t* bltreg = info->reg.bitblt; int i, j, nWords, Sx, Sy; u32 dstAddr; u16* wpt, *wpt1; u32 stride = par->width_virt * par->Bpp; if (blt->dst_width == 0 || blt->dst_height == 0) return; Sx = blt->src_x; Sy = blt->src_y; writeb((7 - Sx%8), &bltreg->rop_code); writeb(blt->operation, &bltreg->operation); writeb((u8)(Sx & 1), &bltreg->src_start_addr0); dstAddr = blt->dst_x*par->Bpp + blt->dst_y * stride; writeb(dstAddr, &bltreg->dest_start_addr0); writeb(dstAddr>>8, &bltreg->dest_start_addr1); writeb(dstAddr>>16, &bltreg->dest_start_addr2); // program color format operation writeb(par->bpp == 8 ? 0x00 : 0x01, &bltreg->ctrl1); writew(stride/2, &bltreg->mem_addr_offset0); writew(blt->dst_width-1, &bltreg->width0); writew(blt->dst_height-1, &bltreg->height0); writew(blt->bg_color, &bltreg->bg_color0); writew(blt->fg_color, &bltreg->fg_color0); // start it up writeb(0x80, &bltreg->ctrl0); // wait for it to actually start e1356_engine_wait_busy(bltreg); // calculate the number of 16 bit words per one blt line nWords = (Sx%16 + blt->dst_width + 15)/16; wpt = blt->src + (Sy*blt->srcstride + Sx/16)/2; for (i = 0; i < blt->dst_height; i++) { wpt1 = wpt; for (j = 0; j < nWords; j++) { // loop until FIFO becomes empty... e1356_wait_bitclr(&bltreg->ctrl0, 0x40, 10000); writew(*wpt1++, info->reg.bitblt_data); } wpt += blt->srcstride/2; } e1356_engine_wait_complete(bltreg);}/* * The BitBLT operation dispatcher */static intdoBlt(const struct e1356fb_par* par, struct fb_info_e1356* info, blt_info_t* blt){ /* * Make sure we're not reentering in the middle of an * active BitBLT operation. ALWAYS call this dispatcher * and not one of the above BLT routines directly, or you * run the risk of overlapping BLT operations, which can * cause complete system hangs. */ if (readb(&info->reg.bitblt->ctrl0) & 0x80) return -ENXIO; switch (blt->operation) { case BLT_MOVE_POS_ROP: case BLT_MOVE_NEG_ROP: case BLT_MOVE_POS_TRANSP: doBlt_Move(par, info, blt); break; case BLT_COLOR_EXP: case BLT_COLOR_EXP_TRANSP: doBlt_ColorExpand(par, info, blt); break; case BLT_SOLID_FILL: doBlt_SolidFill(par, info, blt); break; case BLT_WRITE_ROP: case BLT_WRITE_TRANSP: doBlt_Write(par, info, blt); break; case BLT_READ: case BLT_PAT_FILL_ROP: case BLT_PAT_FILL_TRANSP: case BLT_MOVE_COLOR_EXP: case BLT_MOVE_COLOR_EXP_TRANSP: DPRINTK("BitBLT operation 0x%02x not implemented yet\n", blt->operation); return -ENXIO; default: DPRINTK("Unknown BitBLT operation 0x%02x\n", blt->operation); return -ENXIO; } return 0;}// Initializes blt->src and blt->srcstridestatic void fill_putcs_buffer(struct display *p, blt_info_t* blt, const unsigned short* str, int count){ int row, i, j; u8* b1, *b2; u32 fw = fontwidth(p); u32 fwb = (fw + 7) >> 3; u32 fh = fontheight(p); int bytesPerChar = fwb * fh; if (count*bytesPerChar > PAGE_SIZE) { // Truncate the string if it overflows putcs_buffer, which is // one page in size. count = PAGE_SIZE/bytesPerChar - 1; } blt->srcstride = (fwb*count + 1) & ~1; //round up to be even b1 = (u8*)blt->src; for (row = 0; row < fh; row++) { b2 = b1; for (i = 0; i < count; i++) { for (j=0; j<fwb; j++) *b2++ = p->fontdata[(str[i] & p->charmask) * bytesPerChar + row*fwb + j]; } b1 += blt->srcstride; }}/* * Set the color of a palette entry in 8bpp mode */static inline voiddo_setpalentry(reg_lut_t* lut, unsigned regno, u8 r, u8 g, u8 b){ writeb(0x00, &lut->mode); writeb((u8)regno, &lut->addr); writeb(r&0xf0, &lut->data); writeb(g&0xf0, &lut->data); writeb(b&0xf0, &lut->data);} static voiddo_pan_var(struct fb_var_screeninfo* var, struct fb_info_e1356* info){ u32 pixel_start, start_addr; u8 pixel_pan; struct e1356fb_par* par = &info->current_par; reg_misc_t* misc = info->reg.misc; reg_dispmode_t* dispmode = (IS_PANEL(info->fix.disp_type)) ? info->reg.lcd_mode : info->reg.crttv_mode; pixel_start = var->yoffset * par->width_virt + var->xoffset; start_addr = (pixel_start * par->Bpp) / 2; pixel_pan = (par->bpp == 8) ? (u8)(pixel_start & 1) : 0; if (readb(&misc->disp_mode) != 0) { reg_dispcfg_t* dispcfg = (IS_PANEL(info->fix.disp_type)) ? info->reg.lcd_cfg : info->reg.crttv_cfg; // wait for the end of the current VNDP e1356_wait_bitclr(&dispcfg->vndp, 0x80, 5000); // now wait for the start of a new VNDP e1356_wait_bitset(&dispcfg->vndp, 0x80, 5000); } writeb((u8)(start_addr & 0xff), &dispmode->start_addr0); writeb((u8)((start_addr>>8) & 0xff), &dispmode->start_addr1); writeb((u8)((start_addr>>16) & 0xff), &dispmode->start_addr2); writeb(pixel_pan, &dispmode->pixel_panning);}/* * Invert the hardware cursor image (timerfunc) */static voiddo_flashcursor(unsigned long ptr){ u8 curs_ctrl; struct fb_info_e1356* info = (struct fb_info_e1356 *)ptr; reg_inkcurs_t* inkcurs = (IS_PANEL(info->fix.disp_type)) ? info->reg.lcd_inkcurs : info->reg.crttv_inkcurs; spin_lock(&info->cursor.lock); // toggle cursor enable bit curs_ctrl = readb(&inkcurs->ctrl); writeb((curs_ctrl ^ 0x01) & 0x01, &inkcurs->ctrl); info->cursor.timer.expires = jiffies+HZ/2; add_timer(&info->cursor.timer); spin_unlock(&info->cursor.lock);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -