Exemple #1
0
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? */
}
Exemple #2
0
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;
}
Exemple #4
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);
}
Exemple #10
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);
}
Exemple #12
0
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;
}
Exemple #13
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
	{
Exemple #14
0
	/* 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;
}
Exemple #15
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_CONTRAST_VAL);
}
Exemple #16
0
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;
}
Exemple #18
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;
}
Exemple #19
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(&regs->lcdc_lcddis, LCDC_LCDDIS_DISPDIS);
	while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS))
		udelay(1);
	/* Disable synchronization */
	lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_SYNCDIS);
	while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS))
		udelay(1);
	/* Disable pixel clock */
	lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_CLKDIS);
	while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS))
		udelay(1);
	/* Disable PWM */
	lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_PWMDIS);
	while ((lcdc_readl(&regs->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(&regs->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(&regs->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(&regs->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(&regs->lcdc_lcdcfg1, value);

	value = LCDC_LCDCFG2_VBPW(panel_info.vl_lower_margin);
	value |= LCDC_LCDCFG2_VFPW(panel_info.vl_upper_margin - 1);
	lcdc_writel(&regs->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(&regs->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(&regs->lcdc_lcdcfg4, value);

	lcdc_writel(&regs->lcdc_basecfg0,
			LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);

	switch (NBITS(panel_info.vl_bpix)) {
	case 16:
		lcdc_writel(&regs->lcdc_basecfg1,
			LCDC_BASECFG1_RGBMODE_16BPP_RGB_565);
		break;
	default:
		BUG();
		break;
	}

	lcdc_writel(&regs->lcdc_basecfg2, LCDC_BASECFG2_XSTRIDE(0));
	lcdc_writel(&regs->lcdc_basecfg3, 0);
	lcdc_writel(&regs->lcdc_basecfg4, LCDC_BASECFG4_DMA);

	/* Disable all interrupts */
	lcdc_writel(&regs->lcdc_lcdidr, ~0UL);
	lcdc_writel(&regs->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(&regs->lcdc_baseaddr, desc->address);
	lcdc_writel(&regs->lcdc_basectrl, desc->control);
	lcdc_writel(&regs->lcdc_basenext, desc->next);
	lcdc_writel(&regs->lcdc_basecher, LCDC_BASECHER_CHEN |
					  LCDC_BASECHER_UPDATEEN);

	/* Enable LCD */
	value = lcdc_readl(&regs->lcdc_lcden);
	lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_CLKEN);
	while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS))
		udelay(1);
	value = lcdc_readl(&regs->lcdc_lcden);
	lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_SYNCEN);
	while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS))
		udelay(1);
	value = lcdc_readl(&regs->lcdc_lcden);
	lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_DISPEN);
	while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS))
		udelay(1);
	value = lcdc_readl(&regs->lcdc_lcden);
	lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_PWMEN);
	while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS))
		udelay(1);
}
Exemple #20
0
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;
}