static void atmel_hlcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags) { /* Disable DISP signal */ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_DISPDIS); while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS)) mdelay(1); /* Disable synchronization */ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_SYNCDIS); while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS)) mdelay(1); /* Disable pixel clock */ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_CLKDIS); while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS)) mdelay(1); /* Disable PWM */ lcdc_writel(sinfo, ATMEL_LCDC_LCDDIS, LCDC_LCDDIS_PWMDIS); while ((lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS)) mdelay(1); if (!(flags & ATMEL_LCDC_STOP_NOWAIT)) /* Wait for the end of DMA transfer */ while (!(lcdc_readl(sinfo, ATMEL_LCDC_BASEISR) & LCDC_BASEISR_DMA)) mdelay(10); /*FIXME: OVL DMA? */ }
static void atmel_hlcdfb_start(struct atmel_lcdfb_info *sinfo) { lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, LCDC_LCDEN_CLKEN); while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_CLKSTS)) mdelay(1); lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, LCDC_LCDEN_SYNCEN); while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_LCDSTS)) mdelay(1); lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, LCDC_LCDEN_DISPEN); while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_DISPSTS)) mdelay(1); lcdc_writel(sinfo, ATMEL_LCDC_LCDEN, LCDC_LCDEN_PWMEN); while (!(lcdc_readl(sinfo, ATMEL_LCDC_LCDSR) & LCDC_LCDSR_PWMSTS)) mdelay(1); }
static int atmel_bl_update_status(struct backlight_device *bl) { struct atmel_lcdfb_info *sinfo = bl_get_data(bl); int power = sinfo->bl_power; int brightness = bl->props.brightness; if (bl->props.fb_blank != sinfo->bl_power) power = bl->props.fb_blank; else if (bl->props.power != sinfo->bl_power) power = bl->props.power; if (brightness < 0 && power == FB_BLANK_UNBLANK) brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); else if (power != FB_BLANK_UNBLANK) brightness = 0; lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); if (contrast_ctr & ATMEL_LCDC_POL_POSITIVE) lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, brightness ? contrast_ctr : 0); else lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; return 0; }
/* some bl->props field just changed */ static int atmel_bl_update_status(struct backlight_device *bl) { struct atmel_lcdfb_info *sinfo = bl_get_data(bl); int power = sinfo->bl_power; int brightness = bl->props.brightness; /* REVISIT there may be a meaningful difference between * fb_blank and power ... there seem to be some cases * this doesn't handle correctly. */ if (bl->props.fb_blank != sinfo->bl_power) power = bl->props.fb_blank; else if (bl->props.power != sinfo->bl_power) power = bl->props.power; if (brightness < 0 && power == FB_BLANK_UNBLANK) brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); else if (power != FB_BLANK_UNBLANK) brightness = 0; lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, brightness ? contrast_ctr : 0); bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; return 0; }
static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags) { /* Turn off the LCD controller and the DMA controller */ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); /* Wait for the LCDC core to become idle */ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) msleep(10); lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); if (!(flags & ATMEL_LCDC_STOP_NOWAIT)) /* Wait for DMA engine to become idle... */ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) msleep(10); }
static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo) { atmel_lcdfb_stop_nowait(sinfo); while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) msleep(10); }
static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo) { atmel_lcdfb_stop_nowait(sinfo); /* Wait for DMA engine to become idle... */ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) msleep(10); }
static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo) { /* Turn off the LCD controller and the DMA controller */ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); /* Wait for the LCDC core to become idle */ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) msleep(10); lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); }
static void atmel_lcdfb_stop_nowait(struct atmel_lcdfb_info *sinfo) { lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) msleep(10); lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); }
static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, struct fb_var_screeninfo *var) { u32 dma2dcfg; u32 pixeloff; pixeloff = (var->xoffset * var->bits_per_pixel) & 0x1f; dma2dcfg = ((var->xres_virtual - var->xres) * var->bits_per_pixel) / 8; dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET; lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg); /* Update configuration */ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, lcdc_readl(sinfo, ATMEL_LCDC_DMACON) | ATMEL_LCDC_DMAUPDT); }
static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, struct fb_var_screeninfo *var, struct fb_info *info) { u32 dma2dcfg; u32 pixeloff; pixeloff = (var->xoffset * info->var.bits_per_pixel) & 0x1f; dma2dcfg = (info->var.xres_virtual - info->var.xres) * info->var.bits_per_pixel / 8; dma2dcfg |= pixeloff << ATMEL_LCDC_PIXELOFF_OFFSET; lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg); lcdc_writel(sinfo, ATMEL_LCDC_DMACON, lcdc_readl(sinfo, ATMEL_LCDC_DMACON) | ATMEL_LCDC_DMAUPDT); }
static int rk30_lcdc_read_reg_defalut_cfg(struct rk30_lcdc_device *lcdc_dev) { int reg = 0; spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { for(reg=SYS_CTRL0;reg<=DSP_VACT_ST_END_F1; reg +=4) { lcdc_readl(lcdc_dev,reg); } spin_unlock(&lcdc_dev->reg_lock); } else //clk already disabled { spin_unlock(&lcdc_dev->reg_lock); } return 0; }
static ssize_t rk3188_lcdc_get_disp_info(struct rk_lcdc_device_driver *dev_drv,char *buf,int layer_id) { struct rk3188_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk3188_lcdc_device,driver); char format_w0[9]= "NULL"; char format_w1[9]= "NULL"; char status_w0[9]= "NULL"; char status_w1[9]= "NULL"; u32 fmt_id = lcdc_readl(lcdc_dev,SYS_CTRL); u32 act_info,dsp_info,dsp_st,factor; u16 xvir_w0,x_act_w0,y_act_w0,x_dsp_w0,y_dsp_w0,x_st_w0,y_st_w0,x_factor,y_factor; u16 xvir_w1,x_dsp_w1,y_dsp_w1,x_st_w1,y_st_w1; u16 x_scale,y_scale; switch((fmt_id&m_WIN0_FORMAT)>>3) { case 0: strcpy(format_w0,"ARGB888"); break; case 1: strcpy(format_w0,"RGB888"); break; case 2: strcpy(format_w0,"RGB565"); break; case 4: strcpy(format_w0,"YCbCr420"); break; case 5: strcpy(format_w0,"YCbCr422"); break; case 6: strcpy(format_w0,"YCbCr444"); break; default: strcpy(format_w0,"invalid\n"); break; } switch((fmt_id&m_WIN1_FORMAT)>>6) { case 0: strcpy(format_w1,"ARGB888"); break; case 1: strcpy(format_w1,"RGB888"); break; case 2: strcpy(format_w1,"RGB565"); break; case 4: strcpy(format_w1,"8bpp"); break; case 5: strcpy(format_w1,"4bpp"); break; case 6: strcpy(format_w1,"2bpp"); break; case 7: strcpy(format_w1,"1bpp"); break; default: strcpy(format_w1,"invalid\n"); break; } if(fmt_id&m_WIN0_EN) { strcpy(status_w0,"enabled"); } else { strcpy(status_w0,"disabled"); } if((fmt_id&m_WIN1_EN)>>1) { strcpy(status_w1,"enabled"); } else {
/* REVISIT there may be a meaningful difference between * fb_blank and power ... there seem to be some cases * this doesn't handle correctly. */ if (bl->props.fb_blank != sinfo->bl_power) power = bl->props.fb_blank; else if (bl->props.power != sinfo->bl_power) power = bl->props.power; if (brightness < 0 && power == FB_BLANK_UNBLANK) brightness = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET; else if (power != FB_BLANK_UNBLANK) brightness = 0; reg = lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) & ~LCDC_LCDCFG6_PWMCVAL; reg |= brightness << LCDC_LCDCFG6_PWMCVAL_OFFSET; lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG6, reg); bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; return 0; } static int atmel_bl_get_brightness(struct backlight_device *bl) { struct atmel_lcdfb_info *sinfo = bl_get_data(bl); return lcdc_readl(sinfo, ATMEL_LCDC_LCDCFG6) >> LCDC_LCDCFG6_PWMCVAL_OFFSET; }
static int atmel_bl_get_brightness(struct backlight_device *bl) { struct atmel_lcdfb_info *sinfo = bl_get_data(bl); return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); }
static ssize_t rk30_lcdc_get_disp_info(struct rk_lcdc_device_driver *dev_drv,char *buf,int layer_id) { struct rk30_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk30_lcdc_device,driver); char format_w0[9]= "NULL"; char format_w1[9]= "NULL"; char format_w2[9]= "NULL"; char status_w0[9]= "NULL"; char status_w1[9]= "NULL"; char status_w2[9]= "NULL"; u32 fmt_id = lcdc_readl(lcdc_dev,SYS_CTRL1); u32 act_info,dsp_info,dsp_st,factor; u16 xvir_w0,x_act_w0,y_act_w0,x_dsp_w0,y_dsp_w0,x_st_w0,y_st_w0; u16 xvir_w1,x_act_w1,y_act_w1,x_dsp_w1,y_dsp_w1,x_st_w1,y_st_w1; u16 xvir_w2,x_dsp_w2,y_dsp_w2,x_st_w2,y_st_w2; u16 x_scale_w0,y_scale_w0,x_scale_w1,y_scale_w1; int ovl = lcdc_read_bit(lcdc_dev,DSP_CTRL0,m_W0W1_POSITION_SWAP); switch((fmt_id&m_W0_FORMAT)>>4) { case 0: strcpy(format_w0,"ARGB888"); break; case 1: strcpy(format_w0,"RGB888"); break; case 2: strcpy(format_w0,"RGB565"); break; case 4: strcpy(format_w0,"YCbCr420"); break; case 5: strcpy(format_w0,"YCbCr422"); break; case 6: strcpy(format_w0,"YCbCr444"); break; default: strcpy(format_w0,"inval\n"); break; } switch((fmt_id&m_W1_FORMAT)>>7) { case 0: strcpy(format_w1,"ARGB888"); break; case 1: strcpy(format_w1,"RGB888"); break; case 2: strcpy(format_w1,"RGB565"); break; case 4: strcpy(format_w1,"YCbCr420"); break; case 5: strcpy(format_w1,"YCbCr422"); break; case 6: strcpy(format_w1,"YCbCr444"); break; default: strcpy(format_w1,"inval\n"); break; } switch((fmt_id&m_W2_FORMAT)>>10) { case 0: strcpy(format_w2,"ARGB888"); break; case 1: strcpy(format_w2,"RGB888"); break; case 2: strcpy(format_w2,"RGB565"); break; case 4: strcpy(format_w2,"8bpp"); break; case 5: strcpy(format_w2,"4bpp"); break; case 6: strcpy(format_w2,"2bpp"); break; case 7: strcpy(format_w2,"1bpp"); break; default: strcpy(format_w2,"inval\n"); break; } if(fmt_id&m_W0_EN) { strcpy(status_w0,"enabled"); } else { strcpy(status_w0,"disabled"); } if((fmt_id&m_W1_EN)>>1) { strcpy(status_w1,"enabled"); } else {
static int atmel_lcdfb_set_par(struct fb_info *info) { struct atmel_lcdfb_info *sinfo = info->par; unsigned long hozval_linesz; unsigned long value; unsigned long clk_value_khz; unsigned long bits_per_line; unsigned long pix_factor = 2; might_sleep(); dev_dbg(info->device, "%s:\n", __func__); dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", info->var.xres, info->var.yres, info->var.xres_virtual, info->var.yres_virtual); atmel_lcdfb_stop_nowait(sinfo); if (info->var.bits_per_pixel == 1) info->fix.visual = FB_VISUAL_MONO01; else if (info->var.bits_per_pixel <= 8) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else info->fix.visual = FB_VISUAL_TRUECOLOR; bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel; info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8); dev_dbg(info->device, " * update DMA engine\n"); atmel_lcdfb_update_dma(info, &info->var); value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) pix_factor = 1; clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); if (value < pix_factor) { dev_notice(info->device, "Bypassing pixel clock divider\n"); lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); } else { value = (value / pix_factor) - 1; dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET); info->var.pixclock = KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1))); dev_dbg(info->device, " updated pixclk: %lu KHz\n", PICOS2KHZ(info->var.pixclock)); } value = sinfo->default_lcdcon2; if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) value |= ATMEL_LCDC_INVLINE_INVERTED; if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) value |= ATMEL_LCDC_INVFRAME_INVERTED; switch (info->var.bits_per_pixel) { case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break; case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break; case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break; case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break; case 15: case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break; case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break; case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break; default: BUG(); break; } dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; value |= info->var.lower_margin; dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; value |= (info->var.left_margin - 1); dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); hozval_linesz = compute_hozval(info->var.xres, lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; value |= info->var.yres - 1; dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) msleep(10); atmel_lcdfb_start(sinfo); dev_dbg(info->device, " * DONE\n"); return 0; }
/** * atmel_lcdfb_set_par - Alters the hardware state. * @info: frame buffer structure that represents a single frame buffer * * Using the fb_var_screeninfo in fb_info we set the resolution * of the this particular framebuffer. This function alters the * par AND the fb_fix_screeninfo stored in fb_info. It doesn't * not alter var in fb_info since we are using that data. This * means we depend on the data in var inside fb_info to be * supported by the hardware. atmel_lcdfb_check_var is always called * before atmel_lcdfb_set_par to ensure this. Again if you can't * change the resolution you don't need this function. * */ static int atmel_lcdfb_set_par(struct fb_info *info) { struct atmel_lcdfb_info *sinfo = info->par; unsigned long hozval_linesz; unsigned long value; unsigned long clk_value_khz; unsigned long bits_per_line; dev_dbg(info->device, "%s:\n", __func__); dev_dbg(info->device, " * resolution: %ux%u (%ux%u virtual)\n", info->var.xres, info->var.yres, info->var.xres_virtual, info->var.yres_virtual); /* Turn off the LCD controller and the DMA controller */ lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET); /* Wait for the LCDC core to become idle */ while (lcdc_readl(sinfo, ATMEL_LCDC_PWRCON) & ATMEL_LCDC_BUSY) msleep(10); lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0); if (info->var.bits_per_pixel == 1) info->fix.visual = FB_VISUAL_MONO01; else if (info->var.bits_per_pixel <= 8) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else info->fix.visual = FB_VISUAL_TRUECOLOR; bits_per_line = info->var.xres_virtual * info->var.bits_per_pixel; info->fix.line_length = DIV_ROUND_UP(bits_per_line, 8); /* Re-initialize the DMA engine... */ dev_dbg(info->device, " * update DMA engine\n"); atmel_lcdfb_update_dma(info, &info->var); /* ...set frame size and burst length = 8 words (?) */ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); /* Now, the LCDC core... */ /* Set pixel clock */ clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); value = (value / 2) - 1; dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", value); if (value <= 0) { dev_notice(info->device, "Bypassing pixel clock divider\n"); lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); } else { lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET); info->var.pixclock = KHZ2PICOS(clk_value_khz / (2 * (value + 1))); dev_dbg(info->device, " updated pixclk: %lu KHz\n", PICOS2KHZ(info->var.pixclock)); } /* Initialize control register 2 */ value = sinfo->default_lcdcon2; if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) value |= ATMEL_LCDC_INVLINE_INVERTED; if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) value |= ATMEL_LCDC_INVFRAME_INVERTED; switch (info->var.bits_per_pixel) { case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break; case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break; case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break; case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break; case 15: /* fall through */ case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break; case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break; case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break; default: BUG(); break; } dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); /* Vertical timing */ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; value |= info->var.lower_margin; dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); /* Horizontal timing */ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; value |= (info->var.left_margin - 1); dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); /* Horizontal value (aka line size) */ hozval_linesz = compute_hozval(info->var.xres, lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); /* Display size */ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; value |= info->var.yres - 1; dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); /* FIFO Threshold: Use formula from data sheet */ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); /* Toggle LCD_MODE every frame */ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); /* Disable all interrupts */ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); /* Set contrast */ value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE; lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); /* ...wait for DMA engine to become idle... */ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) msleep(10); dev_dbg(info->device, " * re-enable DMA engine\n"); /* ...and enable it with updated configuration */ lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); dev_dbg(info->device, " * re-enable LCDC core\n"); lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); dev_dbg(info->device, " * DONE\n"); return 0; }
void lcd_ctrl_init(void *lcdbase) { unsigned long value; struct lcd_dma_desc *desc; struct atmel_hlcd_regs *regs; if (!has_lcdc()) return; /* No lcdc */ regs = (struct atmel_hlcd_regs *)panel_info.mmio; /* Disable DISP signal */ lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_DISPDIS); while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS)) udelay(1); /* Disable synchronization */ lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_SYNCDIS); while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS)) udelay(1); /* Disable pixel clock */ lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_CLKDIS); while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS)) udelay(1); /* Disable PWM */ lcdc_writel(®s->lcdc_lcddis, LCDC_LCDDIS_PWMDIS); while ((lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS)) udelay(1); /* Set pixel clock */ value = get_lcdc_clk_rate(0) / panel_info.vl_clk; if (get_lcdc_clk_rate(0) % panel_info.vl_clk) value++; if (value < 1) { /* Using system clock as pixel clock */ lcdc_writel(®s->lcdc_lcdcfg0, LCDC_LCDCFG0_CLKDIV(0) | LCDC_LCDCFG0_CGDISHCR | LCDC_LCDCFG0_CGDISHEO | LCDC_LCDCFG0_CGDISOVR1 | LCDC_LCDCFG0_CGDISBASE | panel_info.vl_clk_pol | LCDC_LCDCFG0_CLKSEL); } else { lcdc_writel(®s->lcdc_lcdcfg0, LCDC_LCDCFG0_CLKDIV(value - 2) | LCDC_LCDCFG0_CGDISHCR | LCDC_LCDCFG0_CGDISHEO | LCDC_LCDCFG0_CGDISOVR1 | LCDC_LCDCFG0_CGDISBASE | panel_info.vl_clk_pol); } /* Initialize control register 5 */ value = 0; value |= panel_info.vl_sync; #ifndef LCD_OUTPUT_BPP /* Output is 24bpp */ value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; #else switch (LCD_OUTPUT_BPP) { case 12: value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP; break; case 16: value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP; break; case 18: value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP; break; case 24: value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP; break; default: BUG(); break; } #endif value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME); value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS); lcdc_writel(®s->lcdc_lcdcfg5, value); /* Vertical & Horizontal Timing */ value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1); value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1); lcdc_writel(®s->lcdc_lcdcfg1, value); value = LCDC_LCDCFG2_VBPW(panel_info.vl_lower_margin); value |= LCDC_LCDCFG2_VFPW(panel_info.vl_upper_margin - 1); lcdc_writel(®s->lcdc_lcdcfg2, value); value = LCDC_LCDCFG3_HBPW(panel_info.vl_right_margin - 1); value |= LCDC_LCDCFG3_HFPW(panel_info.vl_left_margin - 1); lcdc_writel(®s->lcdc_lcdcfg3, value); /* Display size */ value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1); value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1); lcdc_writel(®s->lcdc_lcdcfg4, value); lcdc_writel(®s->lcdc_basecfg0, LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO); switch (NBITS(panel_info.vl_bpix)) { case 16: lcdc_writel(®s->lcdc_basecfg1, LCDC_BASECFG1_RGBMODE_16BPP_RGB_565); break; default: BUG(); break; } lcdc_writel(®s->lcdc_basecfg2, LCDC_BASECFG2_XSTRIDE(0)); lcdc_writel(®s->lcdc_basecfg3, 0); lcdc_writel(®s->lcdc_basecfg4, LCDC_BASECFG4_DMA); /* Disable all interrupts */ lcdc_writel(®s->lcdc_lcdidr, ~0UL); lcdc_writel(®s->lcdc_baseidr, ~0UL); /* Setup the DMA descriptor, this descriptor will loop to itself */ desc = (struct lcd_dma_desc *)(lcdbase - 16); desc->address = (u32)lcdbase; /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN | LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH; desc->next = (u32)desc; lcdc_writel(®s->lcdc_baseaddr, desc->address); lcdc_writel(®s->lcdc_basectrl, desc->control); lcdc_writel(®s->lcdc_basenext, desc->next); lcdc_writel(®s->lcdc_basecher, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN); /* Enable LCD */ value = lcdc_readl(®s->lcdc_lcden); lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_CLKEN); while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS)) udelay(1); value = lcdc_readl(®s->lcdc_lcden); lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_SYNCEN); while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS)) udelay(1); value = lcdc_readl(®s->lcdc_lcden); lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_DISPEN); while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS)) udelay(1); value = lcdc_readl(®s->lcdc_lcden); lcdc_writel(®s->lcdc_lcden, value | LCDC_LCDEN_PWMEN); while (!(lcdc_readl(®s->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS)) udelay(1); }
static int atmel_lcdfb_setup_core(struct fb_info *info) { struct atmel_lcdfb_info *sinfo = info->par; unsigned long hozval_linesz; unsigned long value; unsigned long clk_value_khz; unsigned long pix_factor = 2; /* ...set frame size and burst length = 8 words (?) */ value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32; value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET); lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value); /* Set pixel clock */ if (cpu_is_at91sam9g45() && !cpu_is_at91sam9g45es()) pix_factor = 1; clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000; value = DIV_ROUND_UP(clk_value_khz, PICOS2KHZ(info->var.pixclock)); if (value < pix_factor) { dev_notice(info->device, "Bypassing pixel clock divider\n"); lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS); } else { value = (value / pix_factor) - 1; dev_dbg(info->device, " * programming CLKVAL = 0x%08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET); info->var.pixclock = KHZ2PICOS(clk_value_khz / (pix_factor * (value + 1))); dev_dbg(info->device, " updated pixclk: %lu KHz\n", PICOS2KHZ(info->var.pixclock)); } /* Initialize control register 2 */ value = sinfo->default_lcdcon2; if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT)) value |= ATMEL_LCDC_INVLINE_INVERTED; if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT)) value |= ATMEL_LCDC_INVFRAME_INVERTED; switch (info->var.bits_per_pixel) { case 1: value |= ATMEL_LCDC_PIXELSIZE_1; break; case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break; case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break; case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break; case 15: /* fall through */ case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break; case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break; case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break; default: BUG(); break; } dev_dbg(info->device, " * LCDCON2 = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value); /* Vertical timing */ value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET; value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET; value |= info->var.lower_margin; dev_dbg(info->device, " * LCDTIM1 = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value); /* Horizontal timing */ value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET; value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET; value |= (info->var.left_margin - 1); dev_dbg(info->device, " * LCDTIM2 = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value); /* Horizontal value (aka line size) */ hozval_linesz = compute_hozval(info->var.xres, lcdc_readl(sinfo, ATMEL_LCDC_LCDCON2)); /* Display size */ value = (hozval_linesz - 1) << ATMEL_LCDC_HOZVAL_OFFSET; value |= info->var.yres - 1; dev_dbg(info->device, " * LCDFRMCFG = %08lx\n", value); lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value); /* FIFO Threshold: Use formula from data sheet */ value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3); lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value); /* Toggle LCD_MODE every frame */ lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0); /* Disable all interrupts */ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); /* Enable FIFO & DMA errors */ lcdc_writel(sinfo, ATMEL_LCDC_IER, ATMEL_LCDC_UFLWI | ATMEL_LCDC_OWRI | ATMEL_LCDC_MERI); /* ...wait for DMA engine to become idle... */ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) msleep(10); return 0; }