📄 mx3fb.c
字号:
if (sdc_init_panel(mx3fb, mode, (PICOS2KHZ(fbi->var.pixclock)) * 1000UL, fbi->var.xres, fbi->var.yres, (fbi->var.sync & FB_SYNC_SWAP_RGB) ? IPU_PIX_FMT_BGR666 : IPU_PIX_FMT_RGB666, fbi->var.left_margin, fbi->var.hsync_len, fbi->var.right_margin + fbi->var.hsync_len, fbi->var.upper_margin, fbi->var.vsync_len, fbi->var.lower_margin + fbi->var.vsync_len, sig_cfg) != 0) { mutex_unlock(&mx3_fbi->mutex); dev_err(fbi->device, "mx3fb: Error initializing panel.\n"); return -EINVAL; } } sdc_set_window_pos(mx3fb, mx3_fbi->ipu_ch, 0, 0); mx3_fbi->cur_ipu_buf = 0; video->out_pixel_fmt = bpp_to_pixfmt(fbi->var.bits_per_pixel); video->out_width = fbi->var.xres; video->out_height = fbi->var.yres; video->out_stride = fbi->var.xres_virtual; if (mx3_fbi->blank == FB_BLANK_UNBLANK) sdc_enable_channel(mx3_fbi); mutex_unlock(&mx3_fbi->mutex); return 0;}/** * mx3fb_check_var() - check and adjust framebuffer variable parameters. * @var: framebuffer variable parameters * @fbi: framebuffer information pointer */static int mx3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi){ struct mx3fb_info *mx3_fbi = fbi->par; u32 vtotal; u32 htotal; dev_dbg(fbi->device, "%s\n", __func__); if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && (var->bits_per_pixel != 16)) var->bits_per_pixel = default_bpp; switch (var->bits_per_pixel) { case 16: var->red.length = 5; var->red.offset = 11; var->red.msb_right = 0; var->green.length = 6; var->green.offset = 5; var->green.msb_right = 0; var->blue.length = 5; var->blue.offset = 0; var->blue.msb_right = 0; var->transp.length = 0; var->transp.offset = 0; var->transp.msb_right = 0; break; case 24: var->red.length = 8; var->red.offset = 16; var->red.msb_right = 0; var->green.length = 8; var->green.offset = 8; var->green.msb_right = 0; var->blue.length = 8; var->blue.offset = 0; var->blue.msb_right = 0; var->transp.length = 0; var->transp.offset = 0; var->transp.msb_right = 0; break; case 32: var->red.length = 8; var->red.offset = 16; var->red.msb_right = 0; var->green.length = 8; var->green.offset = 8; var->green.msb_right = 0; var->blue.length = 8; var->blue.offset = 0; var->blue.msb_right = 0; var->transp.length = 8; var->transp.offset = 24; var->transp.msb_right = 0; break; } if (var->pixclock < 1000) { htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin; vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin; var->pixclock = (vtotal * htotal * 6UL) / 100UL; var->pixclock = KHZ2PICOS(var->pixclock); dev_dbg(fbi->device, "pixclock set for 60Hz refresh = %u ps\n", var->pixclock); } var->height = -1; var->width = -1; var->grayscale = 0; /* Preserve sync flags */ var->sync |= mx3_fbi->sync; mx3_fbi->sync |= var->sync; return 0;}static u32 chan_to_field(unsigned int chan, struct fb_bitfield *bf){ chan &= 0xffff; chan >>= 16 - bf->length; return chan << bf->offset;}static int mx3fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int trans, struct fb_info *fbi){ struct mx3fb_info *mx3_fbi = fbi->par; u32 val; int ret = 1; dev_dbg(fbi->device, "%s\n", __func__); mutex_lock(&mx3_fbi->mutex); /* * If greyscale is true, then we convert the RGB value * to greyscale no matter what visual we are using. */ if (fbi->var.grayscale) red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16; switch (fbi->fix.visual) { case FB_VISUAL_TRUECOLOR: /* * 16-bit True Colour. We encode the RGB value * according to the RGB bitfield information. */ if (regno < 16) { u32 *pal = fbi->pseudo_palette; val = chan_to_field(red, &fbi->var.red); val |= chan_to_field(green, &fbi->var.green); val |= chan_to_field(blue, &fbi->var.blue); pal[regno] = val; ret = 0; } break; case FB_VISUAL_STATIC_PSEUDOCOLOR: case FB_VISUAL_PSEUDOCOLOR: break; } mutex_unlock(&mx3_fbi->mutex); return ret;}/** * mx3fb_blank() - blank the display. */static int mx3fb_blank(int blank, struct fb_info *fbi){ struct mx3fb_info *mx3_fbi = fbi->par; struct mx3fb_data *mx3fb = mx3_fbi->mx3fb; dev_dbg(fbi->device, "%s\n", __func__); dev_dbg(fbi->device, "blank = %d\n", blank); if (mx3_fbi->blank == blank) return 0; mutex_lock(&mx3_fbi->mutex); mx3_fbi->blank = blank; switch (blank) { case FB_BLANK_POWERDOWN: case FB_BLANK_VSYNC_SUSPEND: case FB_BLANK_HSYNC_SUSPEND: case FB_BLANK_NORMAL: sdc_disable_channel(mx3_fbi); sdc_set_brightness(mx3fb, 0); break; case FB_BLANK_UNBLANK: sdc_enable_channel(mx3_fbi); sdc_set_brightness(mx3fb, mx3fb->backlight_level); break; } mutex_unlock(&mx3_fbi->mutex); return 0;}/** * mx3fb_pan_display() - pan or wrap the display * @var: variable screen buffer information. * @info: framebuffer information pointer. * * We look only at xoffset, yoffset and the FB_VMODE_YWRAP flag */static int mx3fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi){ struct mx3fb_info *mx3_fbi = fbi->par; u32 y_bottom; unsigned long base; off_t offset; dma_cookie_t cookie; struct scatterlist *sg = mx3_fbi->sg; struct dma_chan *dma_chan = &mx3_fbi->idmac_channel->dma_chan; struct dma_async_tx_descriptor *txd; int ret; dev_dbg(fbi->device, "%s [%c]\n", __func__, list_empty(&mx3_fbi->idmac_channel->queue) ? '-' : '+'); if (var->xoffset > 0) { dev_dbg(fbi->device, "x panning not supported\n"); return -EINVAL; } if (fbi->var.xoffset == var->xoffset && fbi->var.yoffset == var->yoffset) return 0; /* No change, do nothing */ y_bottom = var->yoffset; if (!(var->vmode & FB_VMODE_YWRAP)) y_bottom += var->yres; if (y_bottom > fbi->var.yres_virtual) return -EINVAL; mutex_lock(&mx3_fbi->mutex); offset = (var->yoffset * var->xres_virtual + var->xoffset) * (var->bits_per_pixel / 8); base = fbi->fix.smem_start + offset; dev_dbg(fbi->device, "Updating SDC BG buf %d address=0x%08lX\n", mx3_fbi->cur_ipu_buf, base); /* * We enable the End of Frame interrupt, which will free a tx-descriptor, * which we will need for the next device_prep_slave_sg(). The * IRQ-handler will disable the IRQ again. */ init_completion(&mx3_fbi->flip_cmpl); enable_irq(mx3_fbi->idmac_channel->eof_irq); ret = wait_for_completion_timeout(&mx3_fbi->flip_cmpl, HZ / 10); if (ret <= 0) { mutex_unlock(&mx3_fbi->mutex); dev_info(fbi->device, "Panning failed due to %s\n", ret < 0 ? "user interrupt" : "timeout"); return ret ? : -ETIMEDOUT; } mx3_fbi->cur_ipu_buf = !mx3_fbi->cur_ipu_buf; sg_dma_address(&sg[mx3_fbi->cur_ipu_buf]) = base; sg_set_page(&sg[mx3_fbi->cur_ipu_buf], virt_to_page(fbi->screen_base + offset), fbi->fix.smem_len, offset_in_page(fbi->screen_base + offset)); txd = dma_chan->device->device_prep_slave_sg(dma_chan, sg + mx3_fbi->cur_ipu_buf, 1, DMA_TO_DEVICE, DMA_PREP_INTERRUPT); if (!txd) { dev_err(fbi->device, "Error preparing a DMA transaction descriptor.\n"); mutex_unlock(&mx3_fbi->mutex); return -EIO; } txd->callback_param = txd; txd->callback = mx3fb_dma_done; /* * Emulate original mx3fb behaviour: each new call to idmac_tx_submit() * should switch to another buffer */ cookie = txd->tx_submit(txd); dev_dbg(fbi->device, "%d: Submit %p #%d\n", __LINE__, txd, cookie); if (cookie < 0) { dev_err(fbi->device, "Error updating SDC buf %d to address=0x%08lX\n", mx3_fbi->cur_ipu_buf, base); mutex_unlock(&mx3_fbi->mutex); return -EIO; } if (mx3_fbi->txd) async_tx_ack(mx3_fbi->txd); mx3_fbi->txd = txd; fbi->var.xoffset = var->xoffset; fbi->var.yoffset = var->yoffset; if (var->vmode & FB_VMODE_YWRAP) fbi->var.vmode |= FB_VMODE_YWRAP; else fbi->var.vmode &= ~FB_VMODE_YWRAP; mutex_unlock(&mx3_fbi->mutex); dev_dbg(fbi->device, "Update complete\n"); return 0;}/* * This structure contains the pointers to the control functions that are * invoked by the core framebuffer driver to perform operations like * blitting, rectangle filling, copy regions and cursor definition. */static struct fb_ops mx3fb_ops = { .owner = THIS_MODULE, .fb_set_par = mx3fb_set_par, .fb_check_var = mx3fb_check_var, .fb_setcolreg = mx3fb_setcolreg, .fb_pan_display = mx3fb_pan_display, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, .fb_blank = mx3fb_blank,};#ifdef CONFIG_PM/* * Power management hooks. Note that we won't be called from IRQ context, * unlike the blank functions above, so we may sleep. *//* * Suspends the framebuffer and blanks the screen. Power management support */static int mx3fb_suspend(struct platform_device *pdev, pm_message_t state){ struct mx3fb_data *drv_data = platform_get_drvdata(pdev); struct mx3fb_info *mx3_fbi = drv_data->fbi->par; acquire_console_sem(); fb_set_suspend(drv_data->fbi, 1); release_console_sem(); if (mx3_fbi->blank == FB_BLANK_UNBLANK) { sdc_disable_channel(mx3_fbi); sdc_set_brightness(mx3fb, 0); } return 0;}/* * Resumes the framebuffer and unblanks the screen. Power management support */static int mx3fb_resume(struct platform_device *pdev)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -