📄 mx3fb.c
字号:
{ struct mx3fb_data *drv_data = platform_get_drvdata(pdev); struct mx3fb_info *mx3_fbi = drv_data->fbi->par; if (mx3_fbi->blank == FB_BLANK_UNBLANK) { sdc_enable_channel(mx3_fbi); sdc_set_brightness(mx3fb, drv_data->backlight_level); } acquire_console_sem(); fb_set_suspend(drv_data->fbi, 0); release_console_sem(); return 0;}#else#define mx3fb_suspend NULL#define mx3fb_resume NULL#endif/* * Main framebuffer functions *//** * mx3fb_map_video_memory() - allocates the DRAM memory for the frame buffer. * @fbi: framebuffer information pointer * @return: Error code indicating success or failure * * This buffer is remapped into a non-cached, non-buffered, memory region to * allow palette and pixel writes to occur without flushing the cache. Once this * area is remapped, all virtual memory access to the video memory should occur * at the new region. */static int mx3fb_map_video_memory(struct fb_info *fbi){ int retval = 0; dma_addr_t addr; fbi->screen_base = dma_alloc_writecombine(fbi->device, fbi->fix.smem_len, &addr, GFP_DMA); if (!fbi->screen_base) { dev_err(fbi->device, "Cannot allocate %u bytes framebuffer memory\n", fbi->fix.smem_len); retval = -EBUSY; goto err0; } fbi->fix.smem_start = addr; dev_dbg(fbi->device, "allocated fb @ p=0x%08x, v=0x%p, size=%d.\n", (uint32_t) fbi->fix.smem_start, fbi->screen_base, fbi->fix.smem_len); fbi->screen_size = fbi->fix.smem_len; /* Clear the screen */ memset((char *)fbi->screen_base, 0, fbi->fix.smem_len); return 0;err0: fbi->fix.smem_len = 0; fbi->fix.smem_start = 0; fbi->screen_base = NULL; return retval;}/** * mx3fb_unmap_video_memory() - de-allocate frame buffer memory. * @fbi: framebuffer information pointer * @return: error code indicating success or failure */static int mx3fb_unmap_video_memory(struct fb_info *fbi){ dma_free_writecombine(fbi->device, fbi->fix.smem_len, fbi->screen_base, fbi->fix.smem_start); fbi->screen_base = 0; fbi->fix.smem_start = 0; fbi->fix.smem_len = 0; return 0;}/** * mx3fb_init_fbinfo() - initialize framebuffer information object. * @return: initialized framebuffer structure. */static struct fb_info *mx3fb_init_fbinfo(struct device *dev, struct fb_ops *ops){ struct fb_info *fbi; struct mx3fb_info *mx3fbi; int ret; /* Allocate sufficient memory for the fb structure */ fbi = framebuffer_alloc(sizeof(struct mx3fb_info), dev); if (!fbi) return NULL; mx3fbi = fbi->par; mx3fbi->cookie = -EINVAL; mx3fbi->cur_ipu_buf = 0; fbi->var.activate = FB_ACTIVATE_NOW; fbi->fbops = ops; fbi->flags = FBINFO_FLAG_DEFAULT; fbi->pseudo_palette = mx3fbi->pseudo_palette; mutex_init(&mx3fbi->mutex); /* Allocate colormap */ ret = fb_alloc_cmap(&fbi->cmap, 16, 0); if (ret < 0) { framebuffer_release(fbi); return NULL; } return fbi;}static int init_fb_chan(struct mx3fb_data *mx3fb, struct idmac_channel *ichan){ struct device *dev = mx3fb->dev; struct mx3fb_platform_data *mx3fb_pdata = dev->platform_data; const char *name = mx3fb_pdata->name; unsigned int irq; struct fb_info *fbi; struct mx3fb_info *mx3fbi; const struct fb_videomode *mode; int ret, num_modes; ichan->client = mx3fb; irq = ichan->eof_irq; if (ichan->dma_chan.chan_id != IDMAC_SDC_0) return -EINVAL; fbi = mx3fb_init_fbinfo(dev, &mx3fb_ops); if (!fbi) return -ENOMEM; if (!fb_mode) fb_mode = name; if (!fb_mode) { ret = -EINVAL; goto emode; } if (mx3fb_pdata->mode && mx3fb_pdata->num_modes) { mode = mx3fb_pdata->mode; num_modes = mx3fb_pdata->num_modes; } else { mode = mx3fb_modedb; num_modes = ARRAY_SIZE(mx3fb_modedb); } if (!fb_find_mode(&fbi->var, fbi, fb_mode, mode, num_modes, NULL, default_bpp)) { ret = -EBUSY; goto emode; } fb_videomode_to_modelist(mode, num_modes, &fbi->modelist); /* Default Y virtual size is 2x panel size */ fbi->var.yres_virtual = fbi->var.yres * 2; mx3fb->fbi = fbi; /* set Display Interface clock period */ mx3fb_write_reg(mx3fb, 0x00100010L, DI_HSP_CLK_PER); /* Might need to trigger HSP clock change - see 44.3.3.8.5 */ sdc_set_brightness(mx3fb, 255); sdc_set_global_alpha(mx3fb, true, 0xFF); sdc_set_color_key(mx3fb, IDMAC_SDC_0, false, 0); mx3fbi = fbi->par; mx3fbi->idmac_channel = ichan; mx3fbi->ipu_ch = ichan->dma_chan.chan_id; mx3fbi->mx3fb = mx3fb; mx3fbi->blank = FB_BLANK_NORMAL; init_completion(&mx3fbi->flip_cmpl); disable_irq(ichan->eof_irq); dev_dbg(mx3fb->dev, "disabling irq %d\n", ichan->eof_irq); ret = mx3fb_set_par(fbi); if (ret < 0) goto esetpar; mx3fb_blank(FB_BLANK_UNBLANK, fbi); dev_info(dev, "mx3fb: fb registered, using mode %s\n", fb_mode); ret = register_framebuffer(fbi); if (ret < 0) goto erfb; return 0;erfb:esetpar:emode: fb_dealloc_cmap(&fbi->cmap); framebuffer_release(fbi); return ret;}static bool chan_filter(struct dma_chan *chan, void *arg){ struct dma_chan_request *rq = arg; struct device *dev; struct mx3fb_platform_data *mx3fb_pdata; if (!rq) return false; dev = rq->mx3fb->dev; mx3fb_pdata = dev->platform_data; return rq->id == chan->chan_id && mx3fb_pdata->dma_dev == chan->device->dev;}static void release_fbi(struct fb_info *fbi){ mx3fb_unmap_video_memory(fbi); fb_dealloc_cmap(&fbi->cmap); unregister_framebuffer(fbi); framebuffer_release(fbi);}static int mx3fb_probe(struct platform_device *pdev){ struct device *dev = &pdev->dev; int ret; struct resource *sdc_reg; struct mx3fb_data *mx3fb; dma_cap_mask_t mask; struct dma_chan *chan; struct dma_chan_request rq; /* * Display Interface (DI) and Synchronous Display Controller (SDC) * registers */ sdc_reg = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!sdc_reg) return -EINVAL; mx3fb = kzalloc(sizeof(*mx3fb), GFP_KERNEL); if (!mx3fb) return -ENOMEM; spin_lock_init(&mx3fb->lock); mx3fb->reg_base = ioremap(sdc_reg->start, resource_size(sdc_reg)); if (!mx3fb->reg_base) { ret = -ENOMEM; goto eremap; } pr_debug("Remapped %x to %x at %p\n", sdc_reg->start, sdc_reg->end, mx3fb->reg_base); /* IDMAC interface */ dmaengine_get(); mx3fb->dev = dev; platform_set_drvdata(pdev, mx3fb); rq.mx3fb = mx3fb; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); dma_cap_set(DMA_PRIVATE, mask); rq.id = IDMAC_SDC_0; chan = dma_request_channel(mask, chan_filter, &rq); if (!chan) { ret = -EBUSY; goto ersdc0; } ret = init_fb_chan(mx3fb, to_idmac_chan(chan)); if (ret < 0) goto eisdc0; mx3fb->backlight_level = 255; return 0;eisdc0: dma_release_channel(chan);ersdc0: dmaengine_put(); iounmap(mx3fb->reg_base);eremap: kfree(mx3fb); dev_err(dev, "mx3fb: failed to register fb\n"); return ret;}static int mx3fb_remove(struct platform_device *dev){ struct mx3fb_data *mx3fb = platform_get_drvdata(dev); struct fb_info *fbi = mx3fb->fbi; struct mx3fb_info *mx3_fbi = fbi->par; struct dma_chan *chan; chan = &mx3_fbi->idmac_channel->dma_chan; release_fbi(fbi); dma_release_channel(chan); dmaengine_put(); iounmap(mx3fb->reg_base); kfree(mx3fb); return 0;}static struct platform_driver mx3fb_driver = { .driver = { .name = MX3FB_NAME, }, .probe = mx3fb_probe, .remove = mx3fb_remove, .suspend = mx3fb_suspend, .resume = mx3fb_resume,};/* * Parse user specified options (`video=mx3fb:') * example: * video=mx3fb:bpp=16 */static int mx3fb_setup(void){#ifndef MODULE char *opt, *options = NULL; if (fb_get_options("mx3fb", &options)) return -ENODEV; if (!options || !*options) return 0; while ((opt = strsep(&options, ",")) != NULL) { if (!*opt) continue; if (!strncmp(opt, "bpp=", 4)) default_bpp = simple_strtoul(opt + 4, NULL, 0); else fb_mode = opt; }#endif return 0;}static int __init mx3fb_init(void){ int ret = mx3fb_setup(); if (ret < 0) return ret; ret = platform_driver_register(&mx3fb_driver); return ret;}static void __exit mx3fb_exit(void){ platform_driver_unregister(&mx3fb_driver);}module_init(mx3fb_init);module_exit(mx3fb_exit);MODULE_AUTHOR("Freescale Semiconductor, Inc.");MODULE_DESCRIPTION("MX3 framebuffer driver");MODULE_ALIAS("platform:" MX3FB_NAME);MODULE_LICENSE("GPL v2");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -