l = omap_readl(OMAP_LCDC_CONTROL);
mask = OMAP_LCDC_CTRL_LCD_EN | OMAP_LCDC_IRQ_MASK; /* * Preserve the DONE mask, since we still want to get the * final DONE irq. It will be disabled in the IRQ handler.
*/
mask &= ~OMAP_LCDC_IRQ_DONE;
l &= ~mask;
omap_writel(l, OMAP_LCDC_CONTROL);
}
staticvoid disable_controller(void)
{
init_completion(&lcdc.last_frame_complete);
disable_controller_async(); if (!wait_for_completion_timeout(&lcdc.last_frame_complete,
msecs_to_jiffies(500)))
dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n");
}
/* * YUV support is only for external mode when we have the * YUV window embedded in a 16bpp frame buffer.
*/ if (lcdc.color_mode == OMAPFB_COLOR_YUV420)
bpp = 16; /* Set virtual xres elem size */
omap_set_lcd_dma_b1_vxres(
lcdc.screen_width * bpp / 8 / esize); /* Setup transformations */
omap_set_lcd_dma_b1_rotation(var->rotate);
omap_set_lcd_dma_b1_mirror(plane->info.mirror);
}
omap_setup_lcd_dma();
}
if (status & (OMAP_LCDC_STAT_FUF | OMAP_LCDC_STAT_SYNC_LOST))
reset_controller(status); else { if (status & OMAP_LCDC_STAT_DONE) {
u32 l;
/* * Disable IRQ_DONE. The status bit will be cleared * only when the controller is reenabled and we don't * want to get more interrupts.
*/
l = omap_readl(OMAP_LCDC_CONTROL);
l &= ~OMAP_LCDC_IRQ_DONE;
omap_writel(l, OMAP_LCDC_CONTROL);
complete(&lcdc.last_frame_complete);
} if (status & OMAP_LCDC_STAT_LOADED_PALETTE) {
disable_controller_async();
complete(&lcdc.palette_load_complete);
}
}
/* * Clear these interrupt status bits. * Sync_lost, FUF bits were cleared by disabling the LCD controller * LOADED_PALETTE can be cleared this way only in palette only * load mode. In other load modes it's cleared by disabling the * controller.
*/
status &= ~(OMAP_LCDC_STAT_VSYNC |
OMAP_LCDC_STAT_LOADED_PALETTE |
OMAP_LCDC_STAT_ABC |
OMAP_LCDC_STAT_LINE_INT);
omap_writel(status, OMAP_LCDC_STATUS); return IRQ_HANDLED;
}
/* * Change to a new video mode. We defer this to a later time to avoid any * flicker and not to mess up the current LCD DMA context. For this we disable * the LCD controller, which will generate a DONE irq after the last frame has * been transferred. Then it'll be safe to reconfigure both the LCD controller * as well as the LCD DMA.
*/ staticint omap_lcdc_setup_plane(int plane, int channel_out, unsignedlong offset, int screen_width, int pos_x, int pos_y, int width, int height, int color_mode)
{ struct fb_var_screeninfo *var = &lcdc.fbdev->fb_info[0]->var; struct lcd_panel *panel = lcdc.fbdev->panel; int rot_x, rot_y;
/* * Configure the LCD DMA for a palette load operation and do the palette * downloading synchronously. We don't use the frame+palette load mode of * the controller, since the palette can always be downloaded separately.
*/ staticvoid load_palette(void)
{
u16 *palette;
init_completion(&lcdc.palette_load_complete);
enable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
set_load_mode(OMAP_LCDC_LOAD_PALETTE);
enable_controller(); if (!wait_for_completion_timeout(&lcdc.palette_load_complete,
msecs_to_jiffies(500)))
dev_err(lcdc.fbdev->dev, "timeout waiting for FRAME DONE\n"); /* The controller gets disabled in the irq handler */
disable_irqs(OMAP_LCDC_IRQ_LOADED_PALETTE);
omap_stop_lcd_dma();
if (update_hw_pal) {
disable_controller();
omap_stop_lcd_dma();
load_palette();
setup_lcd_dma();
set_load_mode(OMAP_LCDC_LOAD_FRAME);
enable_controller();
}
return 0;
}
staticvoid calc_ck_div(int is_tft, int pck, int *pck_div)
{ unsignedlong lck;
pck = max(1, pck);
lck = clk_get_rate(lcdc.lcd_ck);
*pck_div = (lck + pck - 1) / pck; if (is_tft)
*pck_div = max(2, *pck_div); else
*pck_div = max(3, *pck_div); if (*pck_div > 255) { /* FIXME: try to adjust logic clock divider as well */
*pck_div = 255;
dev_warn(lcdc.fbdev->dev, "pixclock %d kHz too low.\n",
pck / 1000);
}
}
staticinlinevoid setup_regs(void)
{
u32 l; struct lcd_panel *panel = lcdc.fbdev->panel; int is_tft = panel->config & OMAP_LCDC_PANEL_TFT; unsignedlong lck; int pcd;
l = omap_readl(OMAP_LCDC_CONTROL);
l &= ~OMAP_LCDC_CTRL_LCD_TFT;
l |= is_tft ? OMAP_LCDC_CTRL_LCD_TFT : 0; #ifdef CONFIG_MACH_OMAP_PALMTE /* FIXME:if (machine_is_omap_palmte()) { */ /* PalmTE uses alternate TFT setting in 8BPP mode */
l |= (is_tft && panel->bpp == 8) ? 0x810000 : 0; /* } */ #endif
omap_writel(l, OMAP_LCDC_CONTROL);
l = omap_readl(OMAP_LCDC_TIMING2);
l &= ~(((1 << 6) - 1) << 20);
l |= (panel->config & OMAP_LCDC_SIGNAL_MASK) << 20;
omap_writel(l, OMAP_LCDC_TIMING2);
l = panel->x_res - 1;
l |= (panel->hsw - 1) << 10;
l |= (panel->hfp - 1) << 16;
l |= (panel->hbp - 1) << 24;
omap_writel(l, OMAP_LCDC_TIMING0);
l = panel->y_res - 1;
l |= (panel->vsw - 1) << 10;
l |= panel->vfp << 16;
l |= panel->vbp << 24;
omap_writel(l, OMAP_LCDC_TIMING1);
l = omap_readl(OMAP_LCDC_TIMING2);
l &= ~0xff;
lck = clk_get_rate(lcdc.lcd_ck);
if (!panel->pcd)
calc_ck_div(is_tft, panel->pixel_clock * 1000, &pcd); else {
dev_warn(lcdc.fbdev->dev, "Pixel clock divider value is obsolete.\n" "Try to set pixel_clock to %lu and pcd to 0 " "in drivers/video/omap/lcd_%s.c and submit a patch.\n",
lck / panel->pcd / 1000, panel->name);
pcd = panel->pcd;
}
l |= pcd & 0xff;
l |= panel->acb << 8;
omap_writel(l, OMAP_LCDC_TIMING2);
/* update panel info with the exact clock */
panel->pixel_clock = lck / pcd / 1000;
}
/* * Configure the LCD controller, download the color palette and start a looped * DMA transfer of the frame image data. Called only in internal * controller mode.
*/ staticint omap_lcdc_set_update_mode(enum omapfb_update_mode mode)
{ int r = 0;
if (mode != lcdc.update_mode) { switch (mode) { case OMAPFB_AUTO_UPDATE:
setup_regs();
load_palette();
/* Setup and start LCD DMA */
setup_lcd_dma();
set_load_mode(OMAP_LCDC_LOAD_FRAME);
enable_irqs(OMAP_LCDC_IRQ_DONE); /* This will start the actual DMA transfer */
enable_controller();
lcdc.update_mode = mode; break; case OMAPFB_UPDATE_DISABLED:
disable_controller();
omap_stop_lcd_dma();
lcdc.update_mode = mode; break; default:
r = -EINVAL;
}
}
staticint setup_fbmem(struct omapfb_mem_desc *req_md)
{ if (!req_md->region_cnt) {
dev_err(lcdc.fbdev->dev, "no memory regions defined\n"); return -EINVAL;
}
if (req_md->region_cnt > 1) {
dev_err(lcdc.fbdev->dev, "only one plane is supported\n");
req_md->region_cnt = 1;
}
return alloc_fbmem(&req_md->region[0]);
}
staticint omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode, struct omapfb_mem_desc *req_vram)
{ int r;
u32 l; int rate; struct clk *tc_ck;
lcdc.irq_mask = 0;
lcdc.fbdev = fbdev;
lcdc.ext_mode = ext_mode;
l = 0;
omap_writel(l, OMAP_LCDC_CONTROL);
/* FIXME: * According to errata some platforms have a clock rate limitiation
*/
lcdc.lcd_ck = clk_get(fbdev->dev, "lcd_ck"); if (IS_ERR(lcdc.lcd_ck)) {
dev_err(fbdev->dev, "unable to access LCD clock\n");
r = PTR_ERR(lcdc.lcd_ck); goto fail0;
}
tc_ck = clk_get(fbdev->dev, "tc_ck"); if (IS_ERR(tc_ck)) {
dev_err(fbdev->dev, "unable to access TC clock\n");
r = PTR_ERR(tc_ck); goto fail1;
}
rate = clk_get_rate(tc_ck);
clk_put(tc_ck);
if (machine_is_ams_delta())
rate /= 4;
r = clk_set_rate(lcdc.lcd_ck, rate); if (r) {
dev_err(fbdev->dev, "failed to adjust LCD rate\n"); goto fail1;
}
clk_prepare_enable(lcdc.lcd_ck);
r = request_irq(fbdev->int_irq, lcdc_irq_handler, 0, MODULE_NAME, fbdev); if (r) {
dev_err(fbdev->dev, "unable to get IRQ\n"); goto fail2;
}
r = omap_request_lcd_dma(lcdc_dma_handler, NULL); if (r) {
dev_err(fbdev->dev, "unable to get LCD DMA\n"); goto fail3;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.