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; }
static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) { lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon); lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); }
/* 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_hlcdfb_update_dma_ovl(struct fb_info *info, struct fb_var_screeninfo *var) { struct atmel_lcdfb_info *sinfo = info->par; struct fb_fix_screeninfo *fix = &info->fix; unsigned long dma_addr; struct atmel_hlcd_dma_desc *desc; dma_addr = (fix->smem_start + var->yoffset * fix->line_length + var->xoffset * var->bits_per_pixel / 8); dma_addr &= ~3UL; /* Setup the DMA descriptor, this descriptor will loop to itself */ desc = sinfo->dma_desc; desc->address = dma_addr; /* Disable DMA transfer interrupt & descriptor loaded interrupt. */ desc->control = LCDC_OVRCTRL_ADDIEN | LCDC_OVRCTRL_DSCRIEN | LCDC_OVRCTRL_DMAIEN | LCDC_OVRCTRL_DFETCH; desc->next = sinfo->dma_desc_phys; lcdc_writel(sinfo, ATMEL_LCDC_OVRADDR, dma_addr); lcdc_writel(sinfo, ATMEL_LCDC_OVRCTRL, desc->control); lcdc_writel(sinfo, ATMEL_LCDC_OVRNEXT, sinfo->dma_desc_phys); lcdc_writel(sinfo, ATMEL_LCDC_OVRCHER, LCDC_OVRCHER_CHEN | LCDC_OVRCHER_UPDATEEN); }
static int win0_display(struct rk3188_lcdc_device *lcdc_dev,struct layer_par *par ) { u32 y_addr; u32 uv_addr; y_addr = par->smem_start + par->y_offset; uv_addr = par->cbr_start + par->c_offset; DBG(2,"lcdc%d>>%s:y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr); spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { lcdc_writel(lcdc_dev, WIN0_YRGB_MST0, y_addr); lcdc_writel(lcdc_dev, WIN0_CBR_MST0, uv_addr); // #if defined(CONFIG_RK_HDMI) // #if defined(CONFIG_DUAL_LCDC_DUAL_DISP_IN_KERNEL) // if(lcdc_dev->driver.screen_ctr_info->prop == EXTEND) // { // if(hdmi_get_hotplug() == HDMI_HPD_ACTIVED) // { lcdc_cfg_done(lcdc_dev); // } // } // #endif // #endif } spin_unlock(&lcdc_dev->reg_lock); return 0; }
int rk30_lcdc_ioctl(struct rk_lcdc_device_driver * dev_drv,unsigned int cmd, unsigned long arg,int layer_id) { struct rk30_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk30_lcdc_device,driver); u32 panel_size[2]; void __user *argp = (void __user *)arg; int ret = 0; struct color_key_cfg clr_key_cfg; switch(cmd) { case RK_FBIOGET_PANEL_SIZE: //get panel size panel_size[0] = dev_drv->screen0->x_res; panel_size[1] = dev_drv->screen0->y_res; if(copy_to_user(argp, panel_size, 8)) return -EFAULT; break; case RK_FBIOPUT_COLOR_KEY_CFG: if(copy_from_user(&clr_key_cfg,argp,sizeof(struct color_key_cfg ))) return -EFAULT; lcdc_writel(lcdc_dev,WIN0_COLOR_KEY_CTRL,clr_key_cfg.win0_color_key_cfg); lcdc_writel(lcdc_dev,WIN1_COLOR_KEY_CTRL,clr_key_cfg.win1_color_key_cfg); lcdc_writel(lcdc_dev,WIN2_COLOR_KEY_CTRL,clr_key_cfg.win2_color_key_cfg); break; default: break; } return ret; }
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 init_contrast(struct atmel_lcdfb_info *sinfo) { /* have some default contrast/backlight settings */ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); if (sinfo->lcdcon_is_backlight) init_backlight(sinfo); }
static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) { struct atmel_lcdfb_platform_data *pdata = sinfo->pdata; lcdc_writel(sinfo, ATMEL_LCDC_DMACON, pdata->default_dmacon); lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, (pdata->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); }
static void atmel_lcdfb_init_contrast(struct atmel_lcdfb_info *sinfo) { /* contrast pwm can be 'inverted' */ if (sinfo->lcdcon_pol_negative) contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); /* have some default contrast/backlight settings */ lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); }
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_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); }
/** * atmel_lcdfb_setcolreg - Optional function. Sets a color register. * @regno: Which register in the CLUT we are programming * @red: The red value which can be up to 16 bits wide * @green: The green value which can be up to 16 bits wide * @blue: The blue value which can be up to 16 bits wide. * @transp: If supported the alpha value which can be up to 16 bits wide. * @info: frame buffer info structure * * Set a single color register. The values supplied have a 16 bit * magnitude which needs to be scaled in this function for the hardware. * Things to take into consideration are how many color registers, if * any, are supported with the current color visual. With truecolor mode * no color palettes are supported. Here a psuedo palette is created * which we store the value in pseudo_palette in struct fb_info. For * pseudocolor mode we have a limited color palette. To deal with this * we can program what color is displayed for a particular pixel value. * DirectColor is similar in that we can program each color field. If * we have a static colormap we don't need to implement this function. * * Returns negative errno on error, or zero on success. In an * ideal world, this would have been the case, but as it turns * out, the other drivers return 1 on failure, so that's what * we're going to do. */ static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info) { struct atmel_lcdfb_info *sinfo = info->par; unsigned int val; u32 *pal; int ret = 1; if (info->var.grayscale) red = green = blue = (19595 * red + 38470 * green + 7471 * blue) >> 16; switch (info->fix.visual) { case FB_VISUAL_TRUECOLOR: if (regno < 16) { pal = info->pseudo_palette; val = chan_to_field(red, &info->var.red); val |= chan_to_field(green, &info->var.green); val |= chan_to_field(blue, &info->var.blue); pal[regno] = val; ret = 0; } break; case FB_VISUAL_PSEUDOCOLOR: if (regno < 256) { val = ((red >> 11) & 0x001f); val |= ((green >> 6) & 0x03e0); val |= ((blue >> 1) & 0x7c00); /* * TODO: intensity bit. Maybe something like * ~(red[10] ^ green[10] ^ blue[10]) & 1 */ lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); ret = 0; } break; case FB_VISUAL_MONO01: if (regno < 2) { val = (regno == 0) ? 0x00 : 0x1F; lcdc_writel(sinfo, ATMEL_LCDC_LUT(regno), val); ret = 0; } break; }
static void init_contrast(struct atmel_lcdfb_info *sinfo) { if (sinfo->lcdcon_pol_negative) contrast_ctr &= ~(ATMEL_LCDC_POL_POSITIVE); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); if (sinfo->lcdcon_is_backlight) init_backlight(sinfo); }
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); }
/* * the CLUT register map as following * RCLUT(24 ~ 16), GCLUT(15 ~ 8), BCLUT(7 ~ 0) */ void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) { lcdc_writel(((red << LCDC_BASECLUT_RCLUT_Pos) & LCDC_BASECLUT_RCLUT_Msk) | ((green << LCDC_BASECLUT_GCLUT_Pos) & LCDC_BASECLUT_GCLUT_Msk) | ((blue << LCDC_BASECLUT_BCLUT_Pos) & LCDC_BASECLUT_BCLUT_Msk), panel_info.mmio + ATMEL_LCDC_LUT(regno)); }
static int win2_open(struct rk30_lcdc_device *lcdc_dev,bool open) { spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { if(open) { if(!lcdc_dev->atv_layer_cnt) { printk(KERN_INFO "lcdc%d wakeup from standby!",lcdc_dev->id); lcdc_msk_reg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(0)); } lcdc_dev->atv_layer_cnt++; } else if((lcdc_dev->atv_layer_cnt > 0) && (!open)) { lcdc_dev->atv_layer_cnt--; } lcdc_dev->driver.layer_par[1]->state = open; lcdc_msk_reg(lcdc_dev, SYS_CTRL1, m_W2_EN, v_W2_EN(open)); if(!lcdc_dev->atv_layer_cnt) //if no layer used,disable lcdc { printk(KERN_INFO "no layer of lcdc%d is used,go to standby!",lcdc_dev->id); lcdc_msk_reg(lcdc_dev, SYS_CTRL0,m_LCDC_STANDBY,v_LCDC_STANDBY(1)); } lcdc_writel(lcdc_dev, REG_CFG_DONE, 0x01); lcdc_dev->driver.layer_par[1]->state = open; } spin_unlock(&lcdc_dev->reg_lock); return 0; }
/*********************************** overlay manager swap:1 win0 on the top of win1 0 win1 on the top of win0 set : 1 set overlay 0 get overlay state ************************************/ static int rk30_lcdc_ovl_mgr(struct rk_lcdc_device_driver *dev_drv,int swap,bool set) { struct rk30_lcdc_device *lcdc_dev = container_of(dev_drv,struct rk30_lcdc_device,driver); int ovl; spin_lock(&lcdc_dev->reg_lock); if(lcdc_dev->clk_on) { if(set) //set overlay { lcdc_msk_reg(lcdc_dev,DSP_CTRL0,m_W0W1_POSITION_SWAP,v_W0W1_POSITION_SWAP(swap)); lcdc_writel(lcdc_dev, REG_CFG_DONE, 0x01); lcdc_cfg_done(lcdc_dev); ovl = swap; } else //get overlay { ovl = lcdc_read_bit(lcdc_dev,DSP_CTRL0,m_W0W1_POSITION_SWAP); } } else { ovl = -EPERM; } spin_unlock(&lcdc_dev->reg_lock); return ovl; }
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_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 int win2_display(struct rk30_lcdc_device *lcdc_dev,struct layer_par *par ) { u32 y_addr; u32 uv_addr; y_addr = par->smem_start + par->y_offset; uv_addr = par->cbr_start + par->c_offset; DBG(2,KERN_INFO "lcdc%d>>%s>>y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr); spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { lcdc_writel(lcdc_dev, WIN2_MST, y_addr); lcdc_writel(lcdc_dev, REG_CFG_DONE, 0x01); } spin_unlock(&lcdc_dev->reg_lock); return 0; }
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 win0_display(struct rk30_lcdc_device *lcdc_dev,struct layer_par *par ) { u32 y_addr; u32 uv_addr; y_addr = par->smem_start + par->y_offset; uv_addr = par->cbr_start + par->c_offset; DBG(2,KERN_INFO "lcdc%d>>%s:y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr); spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { lcdc_writel(lcdc_dev, WIN0_YRGB_MST0, y_addr); lcdc_writel(lcdc_dev, WIN0_CBR_MST0, uv_addr); lcdc_cfg_done(lcdc_dev); } spin_unlock(&lcdc_dev->reg_lock); return 0; }
static void atmel_lcdfb_update_dma(struct fb_info *info) { struct atmel_lcdfb_info *sinfo = info->priv; unsigned long dma_addr; dma_addr = (unsigned long)info->screen_base; dma_addr &= ~3UL; /* Set framebuffer DMA base address and pixel offset */ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); }
void rk_lcdc_set_par(struct fb_dsp_info *fb_info, vidinfo_t *vid) { struct lcdc_device *lcdc_dev = &rk32_lcdc; fb_info->layer_id = lcdc_dev->dft_win; switch (fb_info->layer_id) { case WIN0: win0_set_par(lcdc_dev, fb_info, vid); break; case WIN1: printf("%s --->WIN1 not support\n", __func__); break; default: printf("%s --->unknow lay_id \n", __func__); break; } lcdc_writel(lcdc_dev, BCSH_BCS, 0xd0010000); lcdc_writel(lcdc_dev, BCSH_H, 0x01000000); lcdc_writel(lcdc_dev, BCSH_COLOR_BAR, 1); lcdc_cfg_done(lcdc_dev); }
static void atmel_hlcdfb_update_dma(struct fb_info *info) { struct atmel_lcdfb_info *sinfo = info->priv; unsigned long dma_addr; struct atmel_hlcd_dma_desc *desc; dma_addr = (u32)info->screen_base; dma_addr &= ~3UL; /* Setup the DMA descriptor, this descriptor will loop to itself */ desc = sinfo->dma_desc; desc->address = dma_addr; /* 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(sinfo, ATMEL_LCDC_BASEADDR, desc->address); lcdc_writel(sinfo, ATMEL_LCDC_BASECTRL, desc->control); lcdc_writel(sinfo, ATMEL_LCDC_BASENEXT, desc->next); lcdc_writel(sinfo, ATMEL_LCDC_BASECHER, LCDC_BASECHER_CHEN | LCDC_BASECHER_UPDATEEN); }
static void atmel_lcdfb_update_dma(struct fb_info *info, struct fb_var_screeninfo *var) { struct atmel_lcdfb_info *sinfo = info->par; struct fb_fix_screeninfo *fix = &info->fix; unsigned long dma_addr; dma_addr = (fix->smem_start + var->yoffset * fix->line_length + var->xoffset * var->bits_per_pixel / 8); dma_addr &= ~3UL; /* Set framebuffer DMA base address and pixel offset */ lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr); atmel_lcdfb_update_dma2d(sinfo, var); }
/** * 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; }
static int win1_set_par(struct rk3188_lcdc_device *lcdc_dev,rk_screen *screen, struct layer_par *par ) { u32 xact, yact, xvir, yvir, xpos, ypos; u8 fmt_cfg; xact = par->xact; yact = par->yact; xvir = par->xvir; yvir = par->yvir; xpos = par->xpos+screen->left_margin + screen->hsync_len; ypos = par->ypos+screen->upper_margin + screen->vsync_len; DBG(1,"lcdc%d>>%s>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", lcdc_dev->id,__func__,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,xpos,ypos); spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { lcdc_writel(lcdc_dev, WIN1_DSP_INFO,v_DSP_WIDTH(par->xsize) | v_DSP_HEIGHT(par->ysize)); lcdc_writel(lcdc_dev, WIN1_DSP_ST,v_DSP_STX(xpos) | v_DSP_STY(ypos)); // disable win1 color key and set the color to black(rgb=0) lcdc_msk_reg(lcdc_dev, WIN1_COLOR_KEY,m_COLOR_KEY_EN,v_COLOR_KEY_EN(0)); switch(par->format) { case XBGR888: fmt_cfg = 0; lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_ARGB888_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN1_ALPHA_EN,v_WIN1_ALPHA_EN(0)); lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN1_RB_SWAP,v_WIN1_RB_SWAP(1)); break; case ABGR888: fmt_cfg = 0; lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_ARGB888_VIRWIDTH(xvir)); lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN1_ALPHA_EN,v_WIN1_ALPHA_EN(1)); lcdc_msk_reg(lcdc_dev,DSP_CTRL0,m_WIN1_ALPHA_MODE | m_ALPHA_MODE_SEL0, v_WIN1_ALPHA_MODE(1) | v_ALPHA_MODE_SEL0(1));//default set to per-pixel alpha lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN1_RB_SWAP,v_WIN1_RB_SWAP(1)); break; case ARGB888: fmt_cfg = 0; lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_ARGB888_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN1_ALPHA_EN,v_WIN1_ALPHA_EN(1)); //lcdc_msk_reg(lcdc_dev,DSP_CTRL0,m_WIN1_ALPHA_MODE | m_ALPHA_MODE_SEL0, // v_WIN1_ALPHA_MODE(1) | v_ALPHA_MODE_SEL0(1));//default set to per-pixel alpha lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN1_RB_SWAP,v_WIN1_RB_SWAP(0)); break; case RGB888: //rgb888 fmt_cfg = 1; lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_RGB888_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN1_ALPHA_EN,v_WIN1_ALPHA_EN(0)); lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN1_RB_SWAP,v_WIN1_RB_SWAP(0)); //lcdc_msk_reg(lcdc_dev,SYS_CTRL1,m_W1_RGB_RB_SWAP,v_W1_RGB_RB_SWAP(1)); break; case RGB565: //rgb565 fmt_cfg = 2; lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN1_VIR,v_WIN1_RGB565_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN1_ALPHA_EN,v_WIN1_ALPHA_EN(0)); lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN1_RB_SWAP,v_WIN1_RB_SWAP(0)); break; default: dev_err(lcdc_dev->driver.dev,"%s:un supported format!\n",__func__); break; } lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN1_FORMAT, v_WIN1_FORMAT(fmt_cfg)); } spin_unlock(&lcdc_dev->reg_lock); return 0; }
static int win0_set_par(struct rk3188_lcdc_device *lcdc_dev,rk_screen *screen, struct layer_par *par ) { u32 xact, yact, xvir, yvir, xpos, ypos; u32 ScaleYrgbX = 0x1000; u32 ScaleYrgbY = 0x1000; u32 ScaleCbrX = 0x1000; u32 ScaleCbrY = 0x1000; u8 fmt_cfg =0 ; //data format register config value xact = par->xact; //active (origin) picture window width/height yact = par->yact; xvir = par->xvir; // virtual resolution yvir = par->yvir; xpos = par->xpos+screen->left_margin + screen->hsync_len; ypos = par->ypos+screen->upper_margin + screen->vsync_len; ScaleYrgbX = CalScale(xact, par->xsize); //both RGB and yuv need this two factor ScaleYrgbY = CalScale(yact, par->ysize); switch (par->format) { case ARGB888: case XBGR888: case ABGR888: fmt_cfg = 0; break; case RGB888: fmt_cfg = 1; break; case RGB565: fmt_cfg = 2; break; case YUV422:// yuv422 fmt_cfg = 5; ScaleCbrX = CalScale((xact/2), par->xsize); ScaleCbrY = CalScale(yact, par->ysize); break; case YUV420: // yuv420 fmt_cfg = 4; ScaleCbrX = CalScale(xact/2, par->xsize); ScaleCbrY = CalScale(yact/2, par->ysize); break; case YUV444:// yuv444 fmt_cfg = 6; ScaleCbrX = CalScale(xact, par->xsize); ScaleCbrY = CalScale(yact, par->ysize); break; default: dev_err(lcdc_dev->driver.dev,"%s:un supported format!\n",__func__); break; } DBG(1,"lcdc%d>>%s>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>xpos:%d>>ypos:%d>>\n", lcdc_dev->id,__func__,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,xpos,ypos); spin_lock(&lcdc_dev->reg_lock); if(likely(lcdc_dev->clk_on)) { lcdc_writel(lcdc_dev,WIN0_SCL_FACTOR_YRGB,v_X_SCL_FACTOR(ScaleYrgbX) | v_Y_SCL_FACTOR(ScaleYrgbY)); lcdc_writel(lcdc_dev,WIN0_SCL_FACTOR_CBR,v_X_SCL_FACTOR(ScaleCbrX) | v_Y_SCL_FACTOR(ScaleCbrY)); lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN0_FORMAT,v_WIN0_FORMAT(fmt_cfg)); //(inf->video_mode==0) lcdc_writel(lcdc_dev,WIN0_ACT_INFO,v_ACT_WIDTH(xact) | v_ACT_HEIGHT(yact)); lcdc_writel(lcdc_dev,WIN0_DSP_ST,v_DSP_STX(xpos) | v_DSP_STY(ypos)); lcdc_writel(lcdc_dev,WIN0_DSP_INFO,v_DSP_WIDTH(par->xsize) | v_DSP_HEIGHT(par->ysize)); lcdc_msk_reg(lcdc_dev,WIN0_COLOR_KEY,m_COLOR_KEY_EN,v_COLOR_KEY_EN(0)); switch(par->format) { case XBGR888: lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_ARGB888_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN0_ALPHA_EN,v_WIN0_ALPHA_EN(0)); lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN0_RB_SWAP,v_WIN0_RB_SWAP(1)); break; case ABGR888: lcdc_msk_reg(lcdc_dev,WIN_VIR,m_WIN0_VIR,v_ARGB888_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN0_ALPHA_EN,v_WIN0_ALPHA_EN(1)); //lcdc_msk_reg(lcdc_dev,DSP_CTRL0,m_WIN0_ALPHA_MODE | m_ALPHA_MODE_SEL0 | // m_ALPHA_MODE_SEL1,v_WIN0_ALPHA_MODE(1) | v_ALPHA_MODE_SEL0(1) | // v_ALPHA_MODE_SEL1(0));//default set to per-pixel alpha lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN0_RB_SWAP,v_WIN0_RB_SWAP(1)); break; case ARGB888: lcdc_msk_reg(lcdc_dev,WIN_VIR,m_WIN0_VIR,v_ARGB888_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN0_ALPHA_EN,v_WIN0_ALPHA_EN(1)); //lcdc_msk_reg(lcdc_dev,DSP_CTRL0,m_WIN0_ALPHA_MODE | m_ALPHA_MODE_SEL0, // v_WIN0_ALPHA_MODE(1) | v_ALPHA_MODE_SEL0(1));//default set to per-pixel alpha lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN0_RB_SWAP,v_WIN0_RB_SWAP(0)); break; case RGB888: //rgb888 lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_RGB888_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN0_ALPHA_EN,v_WIN0_ALPHA_EN(0)); lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN0_RB_SWAP,v_WIN0_RB_SWAP(0)); break; case RGB565: //rgb565 lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_RGB565_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN0_ALPHA_EN,v_WIN0_ALPHA_EN(0)); lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN0_RB_SWAP,v_WIN0_RB_SWAP(0)); break; case YUV422: case YUV420: case YUV444: lcdc_msk_reg(lcdc_dev, WIN_VIR,m_WIN0_VIR,v_YUV_VIRWIDTH(xvir)); //lcdc_msk_reg(lcdc_dev,ALPHA_CTRL,m_WIN0_ALPHA_EN,v_WIN0_ALPHA_EN(0)); lcdc_msk_reg(lcdc_dev,SYS_CTRL,m_WIN0_RB_SWAP,v_WIN0_RB_SWAP(0)); break; default: dev_err(lcdc_dev->driver.dev,"%s:un supported format!\n",__func__); break; } lcdc_cfg_done(lcdc_dev); } spin_unlock(&lcdc_dev->reg_lock); return 0; }