/** * s3c_fb_set_par() - framebuffer request to set new framebuffer state. * @info: The framebuffer to change. * * Framebuffer layer request to set a new mode for the specified framebuffer */ static int s3c_fb_set_par(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; void __iomem *regs = sfb->regs; int win_no = win->index; u32 osdc_data = 0; u32 data; u32 pagewidth; int clkdiv; dev_dbg(sfb->dev, "setting framebuffer parameters\n"); switch (var->bits_per_pixel) { case 32: case 24: case 16: case 12: info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 8: if (s3c_fb_win_has_palette(win_no, 8)) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 1: info->fix.visual = FB_VISUAL_MONO01; break; default: info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; } info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; /* disable the window whilst we update it */ writel(0, regs + WINCON(win_no)); /* use window 0 as the basis for the lcd output timings */ if (win_no == 0) { clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock); data = sfb->pdata->vidcon0; data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); if (clkdiv > 1) data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; else data &= ~VIDCON0_CLKDIR; /* 1:1 clock */ /* write the timing data to the panel */ data |= VIDCON0_ENVID | VIDCON0_ENVID_F; writel(data, regs + VIDCON0); data = VIDTCON0_VBPD(var->upper_margin - 1) | VIDTCON0_VFPD(var->lower_margin - 1) | VIDTCON0_VSPW(var->vsync_len - 1); writel(data, regs + VIDTCON0); data = VIDTCON1_HBPD(var->left_margin - 1) | VIDTCON1_HFPD(var->right_margin - 1) | VIDTCON1_HSPW(var->hsync_len - 1); writel(data, regs + VIDTCON1); data = VIDTCON2_LINEVAL(var->yres - 1) | VIDTCON2_HOZVAL(var->xres - 1); writel(data, regs + VIDTCON2); } /* write the buffer address */ writel(info->fix.smem_start, regs + VIDW_BUF_START(win_no)); data = info->fix.smem_start + info->fix.line_length * var->yres; writel(data, regs + VIDW_BUF_END(win_no)); pagewidth = (var->xres * var->bits_per_pixel) >> 3; data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | VIDW_BUF_SIZE_PAGEWIDTH(pagewidth); writel(data, regs + VIDW_BUF_SIZE(win_no)); /* write 'OSD' registers to control position of framebuffer */ data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0); writel(data, regs + VIDOSD_A(win_no)); data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, var->xres - 1)) | VIDOSDxB_BOTRIGHT_Y(var->yres - 1); writel(data, regs + VIDOSD_B(win_no)); data = var->xres * var->yres; osdc_data = VIDISD14C_ALPHA1_R(0xf) | VIDISD14C_ALPHA1_G(0xf) | VIDISD14C_ALPHA1_B(0xf); if (s3c_fb_has_osd_d(win_no)) { writel(data, regs + VIDOSD_D(win_no)); writel(osdc_data, regs + VIDOSD_C(win_no)); } else writel(data, regs + VIDOSD_C(win_no)); data = WINCONx_ENWIN; /* note, since we have to round up the bits-per-pixel, we end up * relying on the bitfield information for r/g/b/a to work out * exactly which mode of operation is intended. */ switch (var->bits_per_pixel) { case 1: data |= WINCON0_BPPMODE_1BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_4WORD; break; case 2: data |= WINCON0_BPPMODE_2BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_8WORD; break; case 4: data |= WINCON0_BPPMODE_4BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_8WORD; break; case 8: if (var->transp.length != 0) data |= WINCON1_BPPMODE_8BPP_1232; else data |= WINCON0_BPPMODE_8BPP_PALETTE; data |= WINCONx_BURSTLEN_8WORD; data |= WINCONx_BYTSWP; break; case 16: if (var->transp.length != 0) data |= WINCON1_BPPMODE_16BPP_A1555; else data |= WINCON0_BPPMODE_16BPP_565; data |= WINCONx_HAWSWP; data |= WINCONx_BURSTLEN_16WORD; break; case 24: case 32: if (var->red.length == 6) { if (var->transp.length != 0) data |= WINCON1_BPPMODE_19BPP_A1666; else data |= WINCON1_BPPMODE_18BPP_666; } else if (var->transp.length == 1) data |= WINCON1_BPPMODE_25BPP_A1888 | WINCON1_BLD_PIX; else if (var->transp.length == 4) data |= WINCON1_BPPMODE_28BPP_A4888 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; else data |= WINCON0_BPPMODE_24BPP_888; data |= WINCONx_BURSTLEN_16WORD; break; } /* It has no color key control register for window0 */ if (win_no > 0) { u32 keycon0_data = 0, keycon1_data = 0; keycon0_data = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F | WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0); keycon1_data = WxKEYCON1_COLVAL(0xffffff); writel(keycon0_data, regs + WxKEYCONy(win_no-1, 0)); writel(keycon1_data, regs + WxKEYCONy(win_no-1, 1)); } writel(data, regs + WINCON(win_no)); writel(0x0, regs + WINxMAP(win_no)); return 0; }
/** * s3c_fb_set_par() - framebuffer request to set new framebuffer state. * @info: The framebuffer to change. * * Framebuffer layer request to set a new mode for the specified framebuffer */ static int s3c_fb_set_par(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; void __iomem *regs = sfb->regs; void __iomem *buf = regs; int win_no = win->index; u32 alpha = 0; u32 data; u32 pagewidth; dev_dbg(sfb->dev, "setting framebuffer parameters\n"); pm_runtime_get_sync(sfb->dev); shadow_protect_win(win, 1); switch (var->bits_per_pixel) { case 32: case 24: case 16: case 12: info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 8: if (win->variant.palette_sz >= 256) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 1: info->fix.visual = FB_VISUAL_MONO01; break; default: info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; } info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; /* disable the window whilst we update it */ writel(0, regs + WINCON(win_no)); if (!sfb->output_on) s3c_fb_enable(sfb, 1); /* write the buffer address */ /* start and end registers stride is 8 */ buf = regs + win_no * 8; writel(info->fix.smem_start, buf + sfb->variant.buf_start); data = info->fix.smem_start + info->fix.line_length * var->yres; writel(data, buf + sfb->variant.buf_end); pagewidth = (var->xres * var->bits_per_pixel) >> 3; data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) | VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) | VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth); writel(data, regs + sfb->variant.buf_size + (win_no * 4)); /* write 'OSD' registers to control position of framebuffer */ data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) | VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0); writel(data, regs + VIDOSD_A(win_no, sfb->variant)); data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, var->xres - 1)) | VIDOSDxB_BOTRIGHT_Y(var->yres - 1) | VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel, var->xres - 1)) | VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1); writel(data, regs + VIDOSD_B(win_no, sfb->variant)); data = var->xres * var->yres; alpha = VIDISD14C_ALPHA1_R(0xf) | VIDISD14C_ALPHA1_G(0xf) | VIDISD14C_ALPHA1_B(0xf); vidosd_set_alpha(win, alpha); vidosd_set_size(win, data); /* Enable DMA channel for this window */ if (sfb->variant.has_shadowcon) { data = readl(sfb->regs + SHADOWCON); data |= SHADOWCON_CHx_ENABLE(win_no); writel(data, sfb->regs + SHADOWCON); } data = WINCONx_ENWIN; sfb->enabled |= (1 << win->index); /* note, since we have to round up the bits-per-pixel, we end up * relying on the bitfield information for r/g/b/a to work out * exactly which mode of operation is intended. */ switch (var->bits_p
/** * s3c_fb_set_par() - framebuffer request to set new framebuffer state. * @info: The framebuffer to change. * * Framebuffer layer request to set a new mode for the specified framebuffer */ static int s3c_fb_set_par(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; void __iomem *regs = sfb->regs; void __iomem *buf = regs; int win_no = win->index; u32 alpha = 0; u32 data; u32 pagewidth; int clkdiv; dev_dbg(sfb->dev, "setting framebuffer parameters\n"); shadow_protect_win(win, 1); switch (var->bits_per_pixel) { case 32: case 24: case 16: case 12: info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 8: if (win->variant.palette_sz >= 256) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 1: info->fix.visual = FB_VISUAL_MONO01; break; default: info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; } info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; /* disable the window whilst we update it */ writel(0, regs + WINCON(win_no)); /* use platform specified window as the basis for the lcd timings */ if (win_no == sfb->pdata->default_win) { clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock); data = sfb->pdata->vidcon0; data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); if (clkdiv > 1) data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; else data &= ~VIDCON0_CLKDIR; /* 1:1 clock */ /* write the timing data to the panel */ if (sfb->variant.is_2443) data |= (1 << 5); data |= VIDCON0_ENVID | VIDCON0_ENVID_F; writel(data, regs + VIDCON0); data = VIDTCON0_VBPD(var->upper_margin - 1) | VIDTCON0_VFPD(var->lower_margin - 1) | VIDTCON0_VSPW(var->vsync_len - 1); writel(data, regs + sfb->variant.vidtcon); data = VIDTCON1_HBPD(var->left_margin - 1) | VIDTCON1_HFPD(var->right_margin - 1) | VIDTCON1_HSPW(var->hsync_len - 1); /* VIDTCON1 */ writel(data, regs + sfb->variant.vidtcon + 4); data = VIDTCON2_LINEVAL(var->yres - 1) | VIDTCON2_HOZVAL(var->xres - 1); writel(data, regs +sfb->variant.vidtcon + 8 ); } /* write the buffer address */ /* start and end registers stride is 8 */ buf = regs + win_no * 8; writel(info->fix.smem_start, buf + sfb->variant.buf_start); data = info->fix.smem_start + info->fix.line_length * var->yres; writel(data, buf + sfb->variant.buf_end); pagewidth = (var->xres * var->bits_per_pixel) >> 3; data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | VIDW_BUF_SIZE_PAGEWIDTH(pagewidth); writel(data, regs + sfb->variant.buf_size + (win_no * 4)); /* write 'OSD' registers to control position of framebuffer */ data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0); writel(data, regs + VIDOSD_A(win_no, sfb->variant)); data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, var->xres - 1)) | VIDOSDxB_BOTRIGHT_Y(var->yres - 1); writel(data, regs + VIDOSD_B(win_no, sfb->variant)); data = var->xres * var->yres; alpha = VIDISD14C_ALPHA1_R(0xf) | VIDISD14C_ALPHA1_G(0xf) | VIDISD14C_ALPHA1_B(0xf); vidosd_set_alpha(win, alpha); vidosd_set_size(win, data); data = WINCONx_ENWIN; /* note, since we have to round up the bits-per-pixel, we end up * relying on the bitfield information for r/g/b/a to work out * exactly which mode of operation is intended. */ switch (var->bits_per_pixel) { case 1: data |= WINCON0_BPPMODE_1BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_4WORD; break; case 2: data |= WINCON0_BPPMODE_2BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_8WORD; break; case 4: data |= WINCON0_BPPMODE_4BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_8WORD; break; case 8: if (var->transp.length != 0) data |= WINCON1_BPPMODE_8BPP_1232; else data |= WINCON0_BPPMODE_8BPP_PALETTE; data |= WINCONx_BURSTLEN_8WORD; data |= WINCONx_BYTSWP; break; case 16: if (var->transp.length != 0) data |= WINCON1_BPPMODE_16BPP_A1555; else data |= WINCON0_BPPMODE_16BPP_565; data |= WINCONx_HAWSWP; data |= WINCONx_BURSTLEN_16WORD; break; case 24: case 32: if (var->red.length == 6) { if (var->transp.length != 0) data |= WINCON1_BPPMODE_19BPP_A1666; else data |= WINCON1_BPPMODE_18BPP_666; } else if (var->transp.length == 1) data |= WINCON1_BPPMODE_25BPP_A1888 | WINCON1_BLD_PIX; else if (var->transp.length == 4) data |= WINCON1_BPPMODE_28BPP_A4888 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; else data |= WINCON0_BPPMODE_24BPP_888; data |= WINCONx_WSWP; data |= WINCONx_BURSTLEN_16WORD; break; } /* Enable the colour keying for the window below this one */ if (win_no > 0) { u32 keycon0_data = 0, keycon1_data = 0; void __iomem *keycon = regs + sfb->variant.keycon; keycon0_data = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F | WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0); keycon1_data = WxKEYCON1_COLVAL(0xffffff); keycon += (win_no - 1) * 8; writel(keycon0_data, keycon + WKEYCON0); writel(keycon1_data, keycon + WKEYCON1); } writel(data, regs + sfb->variant.wincon + (win_no * 4)); writel(0x0, regs + sfb->variant.winmap + (win_no * 4)); /* Enable DMA channel for this window */ if (sfb->variant.has_shadowcon) { data = readl(sfb->regs + SHADOWCON); data |= SHADOWCON_CHx_ENABLE(win_no); writel(data, sfb->regs + SHADOWCON); } shadow_protect_win(win, 0); return 0; }
static int s3c_fb_set_par(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; void __iomem *regs = sfb->regs; void __iomem *buf = regs; int win_no = win->index; u32 alpha = 0; u32 data; u32 pagewidth; int clkdiv; dev_dbg(sfb->dev, "setting framebuffer parameters\n"); pm_runtime_get_sync(sfb->dev); shadow_protect_win(win, 1); switch (var->bits_per_pixel) { case 32: case 24: case 16: case 12: info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 8: if (win->variant.palette_sz >= 256) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 1: info->fix.visual = FB_VISUAL_MONO01; break; default: info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; } info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; writel(0, regs + WINCON(win_no)); if (win_no == sfb->pdata->default_win) { clkdiv = s3c_fb_calc_pixclk(sfb, var->pixclock); data = sfb->pdata->vidcon0; data &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); if (clkdiv > 1) data |= VIDCON0_CLKVAL_F(clkdiv-1) | VIDCON0_CLKDIR; else data &= ~VIDCON0_CLKDIR; if (sfb->variant.is_2443) data |= (1 << 5); writel(data, regs + VIDCON0); s3c_fb_enable(sfb, 1); data = VIDTCON0_VBPD(var->upper_margin - 1) | VIDTCON0_VFPD(var->lower_margin - 1) | VIDTCON0_VSPW(var->vsync_len - 1); writel(data, regs + sfb->variant.vidtcon); data = VIDTCON1_HBPD(var->left_margin - 1) | VIDTCON1_HFPD(var->right_margin - 1) | VIDTCON1_HSPW(var->hsync_len - 1); writel(data, regs + sfb->variant.vidtcon + 4); data = VIDTCON2_LINEVAL(var->yres - 1) | VIDTCON2_HOZVAL(var->xres - 1) | VIDTCON2_LINEVAL_E(var->yres - 1) | VIDTCON2_HOZVAL_E(var->xres - 1); writel(data, regs + sfb->variant.vidtcon + 8); } buf = regs + win_no * 8; writel(info->fix.smem_start, buf + sfb->variant.buf_start); data = info->fix.smem_start + info->fix.line_length * var->yres; writel(data, buf + sfb->variant.buf_end); pagewidth = (var->xres * var->bits_per_pixel) >> 3; data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) | VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) | VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth); writel(data, regs + sfb->variant.buf_size + (win_no * 4)); data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) | VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0); writel(data, regs + VIDOSD_A(win_no, sfb->variant)); data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, var->xres - 1)) | VIDOSDxB_BOTRIGHT_Y(var->yres - 1) | VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel, var->xres - 1)) | VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1); writel(data, regs + VIDOSD_B(win_no, sfb->variant)); data = var->xres * var->yres; alpha = VIDISD14C_ALPHA1_R(0xf) | VIDISD14C_ALPHA1_G(0xf) | VIDISD14C_ALPHA1_B(0xf); vidosd_set_alpha(win, alpha); vidosd_set_size(win, data); if (sfb->variant.has_shadowcon) { data = readl(sfb->regs + SHADOWCON); data |= SHADOWCON_CHx_ENABLE(win_no); writel(data, sfb->regs + SHADOWCON); } data = WINCONx_ENWIN; sfb->enabled |= (1 << win->index); switch (var->bits_per_pixel) { case 1: data |= WINCON0_BPPMODE_1BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_4WORD; break; case 2: data |= WINCON0_BPPMODE_2BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_8WORD; break; case 4: data |= WINCON0_BPPMODE_4BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_8WORD; break; case 8: if (var->transp.length != 0) data |= WINCON1_BPPMODE_8BPP_1232; else data |= WINCON0_BPPMODE_8BPP_PALETTE; data |= WINCONx_BURSTLEN_8WORD; data |= WINCONx_BYTSWP; break; case 16: if (var->transp.length != 0) data |= WINCON1_BPPMODE_16BPP_A1555; else data |= WINCON0_BPPMODE_16BPP_565; data |= WINCONx_HAWSWP; data |= WINCONx_BURSTLEN_16WORD; break; case 24: case 32: if (var->red.length == 6) { if (var->transp.length != 0) data |= WINCON1_BPPMODE_19BPP_A1666; else data |= WINCON1_BPPMODE_18BPP_666; } else if (var->transp.length == 1) data |= WINCON1_BPPMODE_25BPP_A1888 | WINCON1_BLD_PIX; else if ((var->transp.length == 4) || (var->transp.length == 8)) data |= WINCON1_BPPMODE_28BPP_A4888 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; else data |= WINCON0_BPPMODE_24BPP_888; data |= WINCONx_WSWP; data |= WINCONx_BURSTLEN_16WORD; break; } if (win_no > 0) { u32 keycon0_data = 0, keycon1_data = 0; void __iomem *keycon = regs + sfb->variant.keycon; keycon0_data = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F | WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0); keycon1_data = WxKEYCON1_COLVAL(0xffffff); keycon += (win_no - 1) * 8; writel(keycon0_data, keycon + WKEYCON0); writel(keycon1_data, keycon + WKEYCON1); } writel(data, regs + sfb->variant.wincon + (win_no * 4)); writel(0x0, regs + sfb->variant.winmap + (win_no * 4)); if (sfb->variant.has_blendcon) { data = readl(sfb->regs + BLENDCON); data &= ~BLENDCON_NEW_MASK; if (var->transp.length > 4) data |= BLENDCON_NEW_8BIT_ALPHA_VALUE; else data |= BLENDCON_NEW_4BIT_ALPHA_VALUE; writel(data, sfb->regs + BLENDCON); } shadow_protect_win(win, 0); pm_runtime_put_sync(sfb->dev); return 0; }
/** * s3c_fb_set_par() - framebuffer request to set new framebuffer state. * @info: The framebuffer to change. * * Framebuffer layer request to set a new mode for the specified framebuffer */ static int s3c_fb_set_par(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; struct s3c_fb_win *win = info->par; struct s3c_fb *sfb = win->parent; void __iomem *regs = sfb->regs; void __iomem *buf = regs; int win_no = win->index; u32 alpha = 0; u32 data; u32 pagewidth; dev_dbg(sfb->dev, "setting framebuffer parameters\n"); pm_runtime_get_sync(sfb->dev); shadow_protect_win(win, 1); switch (var->bits_per_pixel) { case 32: case 24: case 16: case 12: info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 8: if (win->variant.palette_sz >= 256) info->fix.visual = FB_VISUAL_PSEUDOCOLOR; else info->fix.visual = FB_VISUAL_TRUECOLOR; break; case 1: info->fix.visual = FB_VISUAL_MONO01; break; default: info->fix.visual = FB_VISUAL_PSEUDOCOLOR; break; } info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8; info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; /* disable the window whilst we update it */ writel(0, regs + WINCON(win_no)); if (!sfb->output_on) s3c_fb_enable(sfb, 1); /* write the buffer address */ /* start and end registers stride is 8 */ buf = regs + win_no * 8; writel(info->fix.smem_start, buf + sfb->variant.buf_start); data = info->fix.smem_start + info->fix.line_length * var->yres; writel(data, buf + sfb->variant.buf_end); pagewidth = (var->xres * var->bits_per_pixel) >> 3; data = VIDW_BUF_SIZE_OFFSET(info->fix.line_length - pagewidth) | VIDW_BUF_SIZE_PAGEWIDTH(pagewidth) | VIDW_BUF_SIZE_OFFSET_E(info->fix.line_length - pagewidth) | VIDW_BUF_SIZE_PAGEWIDTH_E(pagewidth); writel(data, regs + sfb->variant.buf_size + (win_no * 4)); /* write 'OSD' registers to control position of framebuffer */ data = VIDOSDxA_TOPLEFT_X(0) | VIDOSDxA_TOPLEFT_Y(0) | VIDOSDxA_TOPLEFT_X_E(0) | VIDOSDxA_TOPLEFT_Y_E(0); writel(data, regs + VIDOSD_A(win_no, sfb->variant)); data = VIDOSDxB_BOTRIGHT_X(s3c_fb_align_word(var->bits_per_pixel, var->xres - 1)) | VIDOSDxB_BOTRIGHT_Y(var->yres - 1) | VIDOSDxB_BOTRIGHT_X_E(s3c_fb_align_word(var->bits_per_pixel, var->xres - 1)) | VIDOSDxB_BOTRIGHT_Y_E(var->yres - 1); writel(data, regs + VIDOSD_B(win_no, sfb->variant)); data = var->xres * var->yres; alpha = VIDISD14C_ALPHA1_R(0xf) | VIDISD14C_ALPHA1_G(0xf) | VIDISD14C_ALPHA1_B(0xf); vidosd_set_alpha(win, alpha); vidosd_set_size(win, data); /* Enable DMA channel for this window */ if (sfb->variant.has_shadowcon) { data = readl(sfb->regs + SHADOWCON); data |= SHADOWCON_CHx_ENABLE(win_no); writel(data, sfb->regs + SHADOWCON); } data = WINCONx_ENWIN; sfb->enabled |= (1 << win->index); /* note, since we have to round up the bits-per-pixel, we end up * relying on the bitfield information for r/g/b/a to work out * exactly which mode of operation is intended. */ switch (var->bits_per_pixel) { case 1: data |= WINCON0_BPPMODE_1BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_4WORD; break; case 2: data |= WINCON0_BPPMODE_2BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_8WORD; break; case 4: data |= WINCON0_BPPMODE_4BPP; data |= WINCONx_BITSWP; data |= WINCONx_BURSTLEN_8WORD; break; case 8: if (var->transp.length != 0) data |= WINCON1_BPPMODE_8BPP_1232; else data |= WINCON0_BPPMODE_8BPP_PALETTE; data |= WINCONx_BURSTLEN_8WORD; data |= WINCONx_BYTSWP; break; case 16: if (var->transp.length != 0) data |= WINCON1_BPPMODE_16BPP_A1555; else data |= WINCON0_BPPMODE_16BPP_565; data |= WINCONx_HAWSWP; data |= WINCONx_BURSTLEN_16WORD; break; case 24: case 32: if (var->red.length == 6) { if (var->transp.length != 0) data |= WINCON1_BPPMODE_19BPP_A1666; else data |= WINCON1_BPPMODE_18BPP_666; } else if (var->transp.length == 1) data |= WINCON1_BPPMODE_25BPP_A1888 | WINCON1_BLD_PIX; else if ((var->transp.length == 4) || (var->transp.length == 8)) data |= WINCON1_BPPMODE_28BPP_A4888 | WINCON1_BLD_PIX | WINCON1_ALPHA_SEL; else data |= WINCON0_BPPMODE_24BPP_888; data |= WINCONx_WSWP; data |= WINCONx_BURSTLEN_16WORD; break; } /* Enable the colour keying for the window below this one */ if (win_no > 0) { u32 keycon0_data = 0, keycon1_data = 0; void __iomem *keycon = regs + sfb->variant.keycon; keycon0_data = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F | WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0); keycon1_data = WxKEYCON1_COLVAL(0xffffff); keycon += (win_no - 1) * 8; writel(keycon0_data, keycon + WKEYCON0); writel(keycon1_data, keycon + WKEYCON1); } writel(data, regs + sfb->variant.wincon + (win_no * 4)); writel(0x0, regs + sfb->variant.winmap + (win_no * 4)); /* Set alpha value width */ if (sfb->variant.has_blendcon) { data = readl(sfb->regs + BLENDCON); data &= ~BLENDCON_NEW_MASK; if (var->transp.length > 4) data |= BLENDCON_NEW_8BIT_ALPHA_VALUE; else data |= BLENDCON_NEW_4BIT_ALPHA_VALUE; writel(data, sfb->regs + BLENDCON); } shadow_protect_win(win, 0); pm_runtime_put_sync(sfb->dev); return 0; }