1*5dda7945SStefano Babic /* 2*5dda7945SStefano Babic * Porting to u-boot: 3*5dda7945SStefano Babic * 4*5dda7945SStefano Babic * (C) Copyright 2010 5*5dda7945SStefano Babic * Stefano Babic, DENX Software Engineering, sbabic@denx.de 6*5dda7945SStefano Babic * 7*5dda7945SStefano Babic * MX51 Linux framebuffer: 8*5dda7945SStefano Babic * 9*5dda7945SStefano Babic * (C) Copyright 2004-2010 Freescale Semiconductor, Inc. 10*5dda7945SStefano Babic * 11*5dda7945SStefano Babic * See file CREDITS for list of people who contributed to this 12*5dda7945SStefano Babic * project. 13*5dda7945SStefano Babic * 14*5dda7945SStefano Babic * This program is free software; you can redistribute it and/or 15*5dda7945SStefano Babic * modify it under the terms of the GNU General Public License as 16*5dda7945SStefano Babic * published by the Free Software Foundation; either version 2 of 17*5dda7945SStefano Babic * the License, or (at your option) any later version. 18*5dda7945SStefano Babic * 19*5dda7945SStefano Babic * This program is distributed in the hope that it will be useful, 20*5dda7945SStefano Babic * but WITHOUT ANY WARRANTY; without even the implied warranty of 21*5dda7945SStefano Babic * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22*5dda7945SStefano Babic * GNU General Public License for more details. 23*5dda7945SStefano Babic * 24*5dda7945SStefano Babic * You should have received a copy of the GNU General Public License 25*5dda7945SStefano Babic * along with this program; if not, write to the Free Software 26*5dda7945SStefano Babic * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 27*5dda7945SStefano Babic * MA 02111-1307 USA 28*5dda7945SStefano Babic */ 29*5dda7945SStefano Babic 30*5dda7945SStefano Babic /* #define DEBUG */ 31*5dda7945SStefano Babic #include <common.h> 32*5dda7945SStefano Babic #include <asm/errno.h> 33*5dda7945SStefano Babic #include <linux/string.h> 34*5dda7945SStefano Babic #include <linux/list.h> 35*5dda7945SStefano Babic #include <linux/fb.h> 36*5dda7945SStefano Babic #include <asm/io.h> 37*5dda7945SStefano Babic #include <malloc.h> 38*5dda7945SStefano Babic #include <lcd.h> 39*5dda7945SStefano Babic #include "videomodes.h" 40*5dda7945SStefano Babic #include "ipu.h" 41*5dda7945SStefano Babic #include "mxcfb.h" 42*5dda7945SStefano Babic 43*5dda7945SStefano Babic DECLARE_GLOBAL_DATA_PTR; 44*5dda7945SStefano Babic 45*5dda7945SStefano Babic void *lcd_base; /* Start of framebuffer memory */ 46*5dda7945SStefano Babic void *lcd_console_address; /* Start of console buffer */ 47*5dda7945SStefano Babic 48*5dda7945SStefano Babic int lcd_line_length; 49*5dda7945SStefano Babic int lcd_color_fg; 50*5dda7945SStefano Babic int lcd_color_bg; 51*5dda7945SStefano Babic 52*5dda7945SStefano Babic short console_col; 53*5dda7945SStefano Babic short console_row; 54*5dda7945SStefano Babic 55*5dda7945SStefano Babic vidinfo_t panel_info; 56*5dda7945SStefano Babic 57*5dda7945SStefano Babic static int mxcfb_map_video_memory(struct fb_info *fbi); 58*5dda7945SStefano Babic static int mxcfb_unmap_video_memory(struct fb_info *fbi); 59*5dda7945SStefano Babic 60*5dda7945SStefano Babic void lcd_initcolregs(void) 61*5dda7945SStefano Babic { 62*5dda7945SStefano Babic } 63*5dda7945SStefano Babic 64*5dda7945SStefano Babic void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue) 65*5dda7945SStefano Babic { 66*5dda7945SStefano Babic } 67*5dda7945SStefano Babic 68*5dda7945SStefano Babic void lcd_disable(void) 69*5dda7945SStefano Babic { 70*5dda7945SStefano Babic } 71*5dda7945SStefano Babic 72*5dda7945SStefano Babic void lcd_panel_disable(void) 73*5dda7945SStefano Babic { 74*5dda7945SStefano Babic } 75*5dda7945SStefano Babic 76*5dda7945SStefano Babic void fb_videomode_to_var(struct fb_var_screeninfo *var, 77*5dda7945SStefano Babic const struct fb_videomode *mode) 78*5dda7945SStefano Babic { 79*5dda7945SStefano Babic var->xres = mode->xres; 80*5dda7945SStefano Babic var->yres = mode->yres; 81*5dda7945SStefano Babic var->xres_virtual = mode->xres; 82*5dda7945SStefano Babic var->yres_virtual = mode->yres; 83*5dda7945SStefano Babic var->xoffset = 0; 84*5dda7945SStefano Babic var->yoffset = 0; 85*5dda7945SStefano Babic var->pixclock = mode->pixclock; 86*5dda7945SStefano Babic var->left_margin = mode->left_margin; 87*5dda7945SStefano Babic var->right_margin = mode->right_margin; 88*5dda7945SStefano Babic var->upper_margin = mode->upper_margin; 89*5dda7945SStefano Babic var->lower_margin = mode->lower_margin; 90*5dda7945SStefano Babic var->hsync_len = mode->hsync_len; 91*5dda7945SStefano Babic var->vsync_len = mode->vsync_len; 92*5dda7945SStefano Babic var->sync = mode->sync; 93*5dda7945SStefano Babic var->vmode = mode->vmode & FB_VMODE_MASK; 94*5dda7945SStefano Babic } 95*5dda7945SStefano Babic 96*5dda7945SStefano Babic /* 97*5dda7945SStefano Babic * Structure containing the MXC specific framebuffer information. 98*5dda7945SStefano Babic */ 99*5dda7945SStefano Babic struct mxcfb_info { 100*5dda7945SStefano Babic int blank; 101*5dda7945SStefano Babic ipu_channel_t ipu_ch; 102*5dda7945SStefano Babic int ipu_di; 103*5dda7945SStefano Babic u32 ipu_di_pix_fmt; 104*5dda7945SStefano Babic unsigned char overlay; 105*5dda7945SStefano Babic unsigned char alpha_chan_en; 106*5dda7945SStefano Babic dma_addr_t alpha_phy_addr0; 107*5dda7945SStefano Babic dma_addr_t alpha_phy_addr1; 108*5dda7945SStefano Babic void *alpha_virt_addr0; 109*5dda7945SStefano Babic void *alpha_virt_addr1; 110*5dda7945SStefano Babic uint32_t alpha_mem_len; 111*5dda7945SStefano Babic uint32_t cur_ipu_buf; 112*5dda7945SStefano Babic uint32_t cur_ipu_alpha_buf; 113*5dda7945SStefano Babic 114*5dda7945SStefano Babic u32 pseudo_palette[16]; 115*5dda7945SStefano Babic }; 116*5dda7945SStefano Babic 117*5dda7945SStefano Babic enum { 118*5dda7945SStefano Babic BOTH_ON, 119*5dda7945SStefano Babic SRC_ON, 120*5dda7945SStefano Babic TGT_ON, 121*5dda7945SStefano Babic BOTH_OFF 122*5dda7945SStefano Babic }; 123*5dda7945SStefano Babic 124*5dda7945SStefano Babic static unsigned long default_bpp = 16; 125*5dda7945SStefano Babic static unsigned char g_dp_in_use; 126*5dda7945SStefano Babic static struct fb_info *mxcfb_info[3]; 127*5dda7945SStefano Babic static int ext_clk_used; 128*5dda7945SStefano Babic 129*5dda7945SStefano Babic static uint32_t bpp_to_pixfmt(struct fb_info *fbi) 130*5dda7945SStefano Babic { 131*5dda7945SStefano Babic uint32_t pixfmt = 0; 132*5dda7945SStefano Babic 133*5dda7945SStefano Babic debug("bpp_to_pixfmt: %d\n", fbi->var.bits_per_pixel); 134*5dda7945SStefano Babic 135*5dda7945SStefano Babic if (fbi->var.nonstd) 136*5dda7945SStefano Babic return fbi->var.nonstd; 137*5dda7945SStefano Babic 138*5dda7945SStefano Babic switch (fbi->var.bits_per_pixel) { 139*5dda7945SStefano Babic case 24: 140*5dda7945SStefano Babic pixfmt = IPU_PIX_FMT_BGR24; 141*5dda7945SStefano Babic break; 142*5dda7945SStefano Babic case 32: 143*5dda7945SStefano Babic pixfmt = IPU_PIX_FMT_BGR32; 144*5dda7945SStefano Babic break; 145*5dda7945SStefano Babic case 16: 146*5dda7945SStefano Babic pixfmt = IPU_PIX_FMT_RGB565; 147*5dda7945SStefano Babic break; 148*5dda7945SStefano Babic } 149*5dda7945SStefano Babic return pixfmt; 150*5dda7945SStefano Babic } 151*5dda7945SStefano Babic 152*5dda7945SStefano Babic /* 153*5dda7945SStefano Babic * Set fixed framebuffer parameters based on variable settings. 154*5dda7945SStefano Babic * 155*5dda7945SStefano Babic * @param info framebuffer information pointer 156*5dda7945SStefano Babic */ 157*5dda7945SStefano Babic static int mxcfb_set_fix(struct fb_info *info) 158*5dda7945SStefano Babic { 159*5dda7945SStefano Babic struct fb_fix_screeninfo *fix = &info->fix; 160*5dda7945SStefano Babic struct fb_var_screeninfo *var = &info->var; 161*5dda7945SStefano Babic 162*5dda7945SStefano Babic fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; 163*5dda7945SStefano Babic 164*5dda7945SStefano Babic fix->type = FB_TYPE_PACKED_PIXELS; 165*5dda7945SStefano Babic fix->accel = FB_ACCEL_NONE; 166*5dda7945SStefano Babic fix->visual = FB_VISUAL_TRUECOLOR; 167*5dda7945SStefano Babic fix->xpanstep = 1; 168*5dda7945SStefano Babic fix->ypanstep = 1; 169*5dda7945SStefano Babic 170*5dda7945SStefano Babic return 0; 171*5dda7945SStefano Babic } 172*5dda7945SStefano Babic 173*5dda7945SStefano Babic static int setup_disp_channel1(struct fb_info *fbi) 174*5dda7945SStefano Babic { 175*5dda7945SStefano Babic ipu_channel_params_t params; 176*5dda7945SStefano Babic struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; 177*5dda7945SStefano Babic 178*5dda7945SStefano Babic memset(¶ms, 0, sizeof(params)); 179*5dda7945SStefano Babic params.mem_dp_bg_sync.di = mxc_fbi->ipu_di; 180*5dda7945SStefano Babic 181*5dda7945SStefano Babic debug("%s called\n", __func__); 182*5dda7945SStefano Babic /* 183*5dda7945SStefano Babic * Assuming interlaced means yuv output, below setting also 184*5dda7945SStefano Babic * valid for mem_dc_sync. FG should have the same vmode as BG. 185*5dda7945SStefano Babic */ 186*5dda7945SStefano Babic if (fbi->var.vmode & FB_VMODE_INTERLACED) { 187*5dda7945SStefano Babic params.mem_dp_bg_sync.interlaced = 1; 188*5dda7945SStefano Babic params.mem_dp_bg_sync.out_pixel_fmt = 189*5dda7945SStefano Babic IPU_PIX_FMT_YUV444; 190*5dda7945SStefano Babic } else { 191*5dda7945SStefano Babic if (mxc_fbi->ipu_di_pix_fmt) { 192*5dda7945SStefano Babic params.mem_dp_bg_sync.out_pixel_fmt = 193*5dda7945SStefano Babic mxc_fbi->ipu_di_pix_fmt; 194*5dda7945SStefano Babic } else { 195*5dda7945SStefano Babic params.mem_dp_bg_sync.out_pixel_fmt = 196*5dda7945SStefano Babic IPU_PIX_FMT_RGB666; 197*5dda7945SStefano Babic } 198*5dda7945SStefano Babic } 199*5dda7945SStefano Babic params.mem_dp_bg_sync.in_pixel_fmt = bpp_to_pixfmt(fbi); 200*5dda7945SStefano Babic if (mxc_fbi->alpha_chan_en) 201*5dda7945SStefano Babic params.mem_dp_bg_sync.alpha_chan_en = 1; 202*5dda7945SStefano Babic 203*5dda7945SStefano Babic ipu_init_channel(mxc_fbi->ipu_ch, ¶ms); 204*5dda7945SStefano Babic 205*5dda7945SStefano Babic return 0; 206*5dda7945SStefano Babic } 207*5dda7945SStefano Babic 208*5dda7945SStefano Babic static int setup_disp_channel2(struct fb_info *fbi) 209*5dda7945SStefano Babic { 210*5dda7945SStefano Babic int retval = 0; 211*5dda7945SStefano Babic struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; 212*5dda7945SStefano Babic 213*5dda7945SStefano Babic mxc_fbi->cur_ipu_buf = 1; 214*5dda7945SStefano Babic if (mxc_fbi->alpha_chan_en) 215*5dda7945SStefano Babic mxc_fbi->cur_ipu_alpha_buf = 1; 216*5dda7945SStefano Babic 217*5dda7945SStefano Babic fbi->var.xoffset = fbi->var.yoffset = 0; 218*5dda7945SStefano Babic 219*5dda7945SStefano Babic debug("%s: %x %d %d %d %lx %lx\n", 220*5dda7945SStefano Babic __func__, 221*5dda7945SStefano Babic mxc_fbi->ipu_ch, 222*5dda7945SStefano Babic fbi->var.xres, 223*5dda7945SStefano Babic fbi->var.yres, 224*5dda7945SStefano Babic fbi->fix.line_length, 225*5dda7945SStefano Babic fbi->fix.smem_start, 226*5dda7945SStefano Babic fbi->fix.smem_start + 227*5dda7945SStefano Babic (fbi->fix.line_length * fbi->var.yres)); 228*5dda7945SStefano Babic 229*5dda7945SStefano Babic retval = ipu_init_channel_buffer(mxc_fbi->ipu_ch, IPU_INPUT_BUFFER, 230*5dda7945SStefano Babic bpp_to_pixfmt(fbi), 231*5dda7945SStefano Babic fbi->var.xres, fbi->var.yres, 232*5dda7945SStefano Babic fbi->fix.line_length, 233*5dda7945SStefano Babic fbi->fix.smem_start + 234*5dda7945SStefano Babic (fbi->fix.line_length * fbi->var.yres), 235*5dda7945SStefano Babic fbi->fix.smem_start, 236*5dda7945SStefano Babic 0, 0); 237*5dda7945SStefano Babic if (retval) 238*5dda7945SStefano Babic printf("ipu_init_channel_buffer error %d\n", retval); 239*5dda7945SStefano Babic 240*5dda7945SStefano Babic return retval; 241*5dda7945SStefano Babic } 242*5dda7945SStefano Babic 243*5dda7945SStefano Babic /* 244*5dda7945SStefano Babic * Set framebuffer parameters and change the operating mode. 245*5dda7945SStefano Babic * 246*5dda7945SStefano Babic * @param info framebuffer information pointer 247*5dda7945SStefano Babic */ 248*5dda7945SStefano Babic static int mxcfb_set_par(struct fb_info *fbi) 249*5dda7945SStefano Babic { 250*5dda7945SStefano Babic int retval = 0; 251*5dda7945SStefano Babic u32 mem_len; 252*5dda7945SStefano Babic ipu_di_signal_cfg_t sig_cfg; 253*5dda7945SStefano Babic struct mxcfb_info *mxc_fbi = (struct mxcfb_info *)fbi->par; 254*5dda7945SStefano Babic uint32_t out_pixel_fmt; 255*5dda7945SStefano Babic 256*5dda7945SStefano Babic ipu_disable_channel(mxc_fbi->ipu_ch); 257*5dda7945SStefano Babic ipu_uninit_channel(mxc_fbi->ipu_ch); 258*5dda7945SStefano Babic mxcfb_set_fix(fbi); 259*5dda7945SStefano Babic 260*5dda7945SStefano Babic mem_len = fbi->var.yres_virtual * fbi->fix.line_length; 261*5dda7945SStefano Babic if (!fbi->fix.smem_start || (mem_len > fbi->fix.smem_len)) { 262*5dda7945SStefano Babic if (fbi->fix.smem_start) 263*5dda7945SStefano Babic mxcfb_unmap_video_memory(fbi); 264*5dda7945SStefano Babic 265*5dda7945SStefano Babic if (mxcfb_map_video_memory(fbi) < 0) 266*5dda7945SStefano Babic return -ENOMEM; 267*5dda7945SStefano Babic } 268*5dda7945SStefano Babic 269*5dda7945SStefano Babic setup_disp_channel1(fbi); 270*5dda7945SStefano Babic 271*5dda7945SStefano Babic memset(&sig_cfg, 0, sizeof(sig_cfg)); 272*5dda7945SStefano Babic if (fbi->var.vmode & FB_VMODE_INTERLACED) { 273*5dda7945SStefano Babic sig_cfg.interlaced = 1; 274*5dda7945SStefano Babic out_pixel_fmt = IPU_PIX_FMT_YUV444; 275*5dda7945SStefano Babic } else { 276*5dda7945SStefano Babic if (mxc_fbi->ipu_di_pix_fmt) 277*5dda7945SStefano Babic out_pixel_fmt = mxc_fbi->ipu_di_pix_fmt; 278*5dda7945SStefano Babic else 279*5dda7945SStefano Babic out_pixel_fmt = IPU_PIX_FMT_RGB666; 280*5dda7945SStefano Babic } 281*5dda7945SStefano Babic if (fbi->var.vmode & FB_VMODE_ODD_FLD_FIRST) /* PAL */ 282*5dda7945SStefano Babic sig_cfg.odd_field_first = 1; 283*5dda7945SStefano Babic if ((fbi->var.sync & FB_SYNC_EXT) || ext_clk_used) 284*5dda7945SStefano Babic sig_cfg.ext_clk = 1; 285*5dda7945SStefano Babic if (fbi->var.sync & FB_SYNC_HOR_HIGH_ACT) 286*5dda7945SStefano Babic sig_cfg.Hsync_pol = 1; 287*5dda7945SStefano Babic if (fbi->var.sync & FB_SYNC_VERT_HIGH_ACT) 288*5dda7945SStefano Babic sig_cfg.Vsync_pol = 1; 289*5dda7945SStefano Babic if (!(fbi->var.sync & FB_SYNC_CLK_LAT_FALL)) 290*5dda7945SStefano Babic sig_cfg.clk_pol = 1; 291*5dda7945SStefano Babic if (fbi->var.sync & FB_SYNC_DATA_INVERT) 292*5dda7945SStefano Babic sig_cfg.data_pol = 1; 293*5dda7945SStefano Babic if (!(fbi->var.sync & FB_SYNC_OE_LOW_ACT)) 294*5dda7945SStefano Babic sig_cfg.enable_pol = 1; 295*5dda7945SStefano Babic if (fbi->var.sync & FB_SYNC_CLK_IDLE_EN) 296*5dda7945SStefano Babic sig_cfg.clkidle_en = 1; 297*5dda7945SStefano Babic 298*5dda7945SStefano Babic debug("pixclock = %ul Hz\n", 299*5dda7945SStefano Babic (u32) (PICOS2KHZ(fbi->var.pixclock) * 1000UL)); 300*5dda7945SStefano Babic 301*5dda7945SStefano Babic if (ipu_init_sync_panel(mxc_fbi->ipu_di, 302*5dda7945SStefano Babic (PICOS2KHZ(fbi->var.pixclock)) * 1000UL, 303*5dda7945SStefano Babic fbi->var.xres, fbi->var.yres, 304*5dda7945SStefano Babic out_pixel_fmt, 305*5dda7945SStefano Babic fbi->var.left_margin, 306*5dda7945SStefano Babic fbi->var.hsync_len, 307*5dda7945SStefano Babic fbi->var.right_margin, 308*5dda7945SStefano Babic fbi->var.upper_margin, 309*5dda7945SStefano Babic fbi->var.vsync_len, 310*5dda7945SStefano Babic fbi->var.lower_margin, 311*5dda7945SStefano Babic 0, sig_cfg) != 0) { 312*5dda7945SStefano Babic puts("mxcfb: Error initializing panel.\n"); 313*5dda7945SStefano Babic return -EINVAL; 314*5dda7945SStefano Babic } 315*5dda7945SStefano Babic 316*5dda7945SStefano Babic retval = setup_disp_channel2(fbi); 317*5dda7945SStefano Babic if (retval) 318*5dda7945SStefano Babic return retval; 319*5dda7945SStefano Babic 320*5dda7945SStefano Babic if (mxc_fbi->blank == FB_BLANK_UNBLANK) 321*5dda7945SStefano Babic ipu_enable_channel(mxc_fbi->ipu_ch); 322*5dda7945SStefano Babic 323*5dda7945SStefano Babic return retval; 324*5dda7945SStefano Babic } 325*5dda7945SStefano Babic 326*5dda7945SStefano Babic /* 327*5dda7945SStefano Babic * Check framebuffer variable parameters and adjust to valid values. 328*5dda7945SStefano Babic * 329*5dda7945SStefano Babic * @param var framebuffer variable parameters 330*5dda7945SStefano Babic * 331*5dda7945SStefano Babic * @param info framebuffer information pointer 332*5dda7945SStefano Babic */ 333*5dda7945SStefano Babic static int mxcfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 334*5dda7945SStefano Babic { 335*5dda7945SStefano Babic u32 vtotal; 336*5dda7945SStefano Babic u32 htotal; 337*5dda7945SStefano Babic 338*5dda7945SStefano Babic if (var->xres_virtual < var->xres) 339*5dda7945SStefano Babic var->xres_virtual = var->xres; 340*5dda7945SStefano Babic if (var->yres_virtual < var->yres) 341*5dda7945SStefano Babic var->yres_virtual = var->yres; 342*5dda7945SStefano Babic 343*5dda7945SStefano Babic if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && 344*5dda7945SStefano Babic (var->bits_per_pixel != 16) && (var->bits_per_pixel != 8)) 345*5dda7945SStefano Babic var->bits_per_pixel = default_bpp; 346*5dda7945SStefano Babic 347*5dda7945SStefano Babic switch (var->bits_per_pixel) { 348*5dda7945SStefano Babic case 8: 349*5dda7945SStefano Babic var->red.length = 3; 350*5dda7945SStefano Babic var->red.offset = 5; 351*5dda7945SStefano Babic var->red.msb_right = 0; 352*5dda7945SStefano Babic 353*5dda7945SStefano Babic var->green.length = 3; 354*5dda7945SStefano Babic var->green.offset = 2; 355*5dda7945SStefano Babic var->green.msb_right = 0; 356*5dda7945SStefano Babic 357*5dda7945SStefano Babic var->blue.length = 2; 358*5dda7945SStefano Babic var->blue.offset = 0; 359*5dda7945SStefano Babic var->blue.msb_right = 0; 360*5dda7945SStefano Babic 361*5dda7945SStefano Babic var->transp.length = 0; 362*5dda7945SStefano Babic var->transp.offset = 0; 363*5dda7945SStefano Babic var->transp.msb_right = 0; 364*5dda7945SStefano Babic break; 365*5dda7945SStefano Babic case 16: 366*5dda7945SStefano Babic var->red.length = 5; 367*5dda7945SStefano Babic var->red.offset = 11; 368*5dda7945SStefano Babic var->red.msb_right = 0; 369*5dda7945SStefano Babic 370*5dda7945SStefano Babic var->green.length = 6; 371*5dda7945SStefano Babic var->green.offset = 5; 372*5dda7945SStefano Babic var->green.msb_right = 0; 373*5dda7945SStefano Babic 374*5dda7945SStefano Babic var->blue.length = 5; 375*5dda7945SStefano Babic var->blue.offset = 0; 376*5dda7945SStefano Babic var->blue.msb_right = 0; 377*5dda7945SStefano Babic 378*5dda7945SStefano Babic var->transp.length = 0; 379*5dda7945SStefano Babic var->transp.offset = 0; 380*5dda7945SStefano Babic var->transp.msb_right = 0; 381*5dda7945SStefano Babic break; 382*5dda7945SStefano Babic case 24: 383*5dda7945SStefano Babic var->red.length = 8; 384*5dda7945SStefano Babic var->red.offset = 16; 385*5dda7945SStefano Babic var->red.msb_right = 0; 386*5dda7945SStefano Babic 387*5dda7945SStefano Babic var->green.length = 8; 388*5dda7945SStefano Babic var->green.offset = 8; 389*5dda7945SStefano Babic var->green.msb_right = 0; 390*5dda7945SStefano Babic 391*5dda7945SStefano Babic var->blue.length = 8; 392*5dda7945SStefano Babic var->blue.offset = 0; 393*5dda7945SStefano Babic var->blue.msb_right = 0; 394*5dda7945SStefano Babic 395*5dda7945SStefano Babic var->transp.length = 0; 396*5dda7945SStefano Babic var->transp.offset = 0; 397*5dda7945SStefano Babic var->transp.msb_right = 0; 398*5dda7945SStefano Babic break; 399*5dda7945SStefano Babic case 32: 400*5dda7945SStefano Babic var->red.length = 8; 401*5dda7945SStefano Babic var->red.offset = 16; 402*5dda7945SStefano Babic var->red.msb_right = 0; 403*5dda7945SStefano Babic 404*5dda7945SStefano Babic var->green.length = 8; 405*5dda7945SStefano Babic var->green.offset = 8; 406*5dda7945SStefano Babic var->green.msb_right = 0; 407*5dda7945SStefano Babic 408*5dda7945SStefano Babic var->blue.length = 8; 409*5dda7945SStefano Babic var->blue.offset = 0; 410*5dda7945SStefano Babic var->blue.msb_right = 0; 411*5dda7945SStefano Babic 412*5dda7945SStefano Babic var->transp.length = 8; 413*5dda7945SStefano Babic var->transp.offset = 24; 414*5dda7945SStefano Babic var->transp.msb_right = 0; 415*5dda7945SStefano Babic break; 416*5dda7945SStefano Babic } 417*5dda7945SStefano Babic 418*5dda7945SStefano Babic if (var->pixclock < 1000) { 419*5dda7945SStefano Babic htotal = var->xres + var->right_margin + var->hsync_len + 420*5dda7945SStefano Babic var->left_margin; 421*5dda7945SStefano Babic vtotal = var->yres + var->lower_margin + var->vsync_len + 422*5dda7945SStefano Babic var->upper_margin; 423*5dda7945SStefano Babic var->pixclock = (vtotal * htotal * 6UL) / 100UL; 424*5dda7945SStefano Babic var->pixclock = KHZ2PICOS(var->pixclock); 425*5dda7945SStefano Babic printf("pixclock set for 60Hz refresh = %u ps\n", 426*5dda7945SStefano Babic var->pixclock); 427*5dda7945SStefano Babic } 428*5dda7945SStefano Babic 429*5dda7945SStefano Babic var->height = -1; 430*5dda7945SStefano Babic var->width = -1; 431*5dda7945SStefano Babic var->grayscale = 0; 432*5dda7945SStefano Babic 433*5dda7945SStefano Babic return 0; 434*5dda7945SStefano Babic } 435*5dda7945SStefano Babic 436*5dda7945SStefano Babic static int mxcfb_map_video_memory(struct fb_info *fbi) 437*5dda7945SStefano Babic { 438*5dda7945SStefano Babic if (fbi->fix.smem_len < fbi->var.yres_virtual * fbi->fix.line_length) { 439*5dda7945SStefano Babic fbi->fix.smem_len = fbi->var.yres_virtual * 440*5dda7945SStefano Babic fbi->fix.line_length; 441*5dda7945SStefano Babic } 442*5dda7945SStefano Babic 443*5dda7945SStefano Babic fbi->screen_base = (char *)lcd_base; 444*5dda7945SStefano Babic fbi->fix.smem_start = (unsigned long)lcd_base; 445*5dda7945SStefano Babic if (fbi->screen_base == 0) { 446*5dda7945SStefano Babic puts("Unable to allocate framebuffer memory\n"); 447*5dda7945SStefano Babic fbi->fix.smem_len = 0; 448*5dda7945SStefano Babic fbi->fix.smem_start = 0; 449*5dda7945SStefano Babic return -EBUSY; 450*5dda7945SStefano Babic } 451*5dda7945SStefano Babic 452*5dda7945SStefano Babic debug("allocated fb @ paddr=0x%08X, size=%d.\n", 453*5dda7945SStefano Babic (uint32_t) fbi->fix.smem_start, fbi->fix.smem_len); 454*5dda7945SStefano Babic 455*5dda7945SStefano Babic fbi->screen_size = fbi->fix.smem_len; 456*5dda7945SStefano Babic 457*5dda7945SStefano Babic /* Clear the screen */ 458*5dda7945SStefano Babic memset((char *)fbi->screen_base, 0, fbi->fix.smem_len); 459*5dda7945SStefano Babic 460*5dda7945SStefano Babic return 0; 461*5dda7945SStefano Babic } 462*5dda7945SStefano Babic 463*5dda7945SStefano Babic static int mxcfb_unmap_video_memory(struct fb_info *fbi) 464*5dda7945SStefano Babic { 465*5dda7945SStefano Babic fbi->screen_base = 0; 466*5dda7945SStefano Babic fbi->fix.smem_start = 0; 467*5dda7945SStefano Babic fbi->fix.smem_len = 0; 468*5dda7945SStefano Babic return 0; 469*5dda7945SStefano Babic } 470*5dda7945SStefano Babic 471*5dda7945SStefano Babic /* 472*5dda7945SStefano Babic * Initializes the framebuffer information pointer. After allocating 473*5dda7945SStefano Babic * sufficient memory for the framebuffer structure, the fields are 474*5dda7945SStefano Babic * filled with custom information passed in from the configurable 475*5dda7945SStefano Babic * structures. This includes information such as bits per pixel, 476*5dda7945SStefano Babic * color maps, screen width/height and RGBA offsets. 477*5dda7945SStefano Babic * 478*5dda7945SStefano Babic * @return Framebuffer structure initialized with our information 479*5dda7945SStefano Babic */ 480*5dda7945SStefano Babic static struct fb_info *mxcfb_init_fbinfo(void) 481*5dda7945SStefano Babic { 482*5dda7945SStefano Babic #define BYTES_PER_LONG 4 483*5dda7945SStefano Babic #define PADDING (BYTES_PER_LONG - (sizeof(struct fb_info) % BYTES_PER_LONG)) 484*5dda7945SStefano Babic struct fb_info *fbi; 485*5dda7945SStefano Babic struct mxcfb_info *mxcfbi; 486*5dda7945SStefano Babic char *p; 487*5dda7945SStefano Babic int size = sizeof(struct mxcfb_info) + PADDING + 488*5dda7945SStefano Babic sizeof(struct fb_info); 489*5dda7945SStefano Babic 490*5dda7945SStefano Babic debug("%s: %d %d %d %d\n", 491*5dda7945SStefano Babic __func__, 492*5dda7945SStefano Babic PADDING, 493*5dda7945SStefano Babic size, 494*5dda7945SStefano Babic sizeof(struct mxcfb_info), 495*5dda7945SStefano Babic sizeof(struct fb_info)); 496*5dda7945SStefano Babic /* 497*5dda7945SStefano Babic * Allocate sufficient memory for the fb structure 498*5dda7945SStefano Babic */ 499*5dda7945SStefano Babic 500*5dda7945SStefano Babic p = malloc(size); 501*5dda7945SStefano Babic if (!p) 502*5dda7945SStefano Babic return NULL; 503*5dda7945SStefano Babic 504*5dda7945SStefano Babic memset(p, 0, size); 505*5dda7945SStefano Babic 506*5dda7945SStefano Babic fbi = (struct fb_info *)p; 507*5dda7945SStefano Babic fbi->par = p + sizeof(struct fb_info) + PADDING; 508*5dda7945SStefano Babic 509*5dda7945SStefano Babic mxcfbi = (struct mxcfb_info *)fbi->par; 510*5dda7945SStefano Babic debug("Framebuffer structures at: fbi=0x%x mxcfbi=0x%x\n", 511*5dda7945SStefano Babic (unsigned int)fbi, (unsigned int)mxcfbi); 512*5dda7945SStefano Babic 513*5dda7945SStefano Babic fbi->var.activate = FB_ACTIVATE_NOW; 514*5dda7945SStefano Babic 515*5dda7945SStefano Babic fbi->flags = FBINFO_FLAG_DEFAULT; 516*5dda7945SStefano Babic fbi->pseudo_palette = mxcfbi->pseudo_palette; 517*5dda7945SStefano Babic 518*5dda7945SStefano Babic return fbi; 519*5dda7945SStefano Babic } 520*5dda7945SStefano Babic 521*5dda7945SStefano Babic /* 522*5dda7945SStefano Babic * Probe routine for the framebuffer driver. It is called during the 523*5dda7945SStefano Babic * driver binding process. The following functions are performed in 524*5dda7945SStefano Babic * this routine: Framebuffer initialization, Memory allocation and 525*5dda7945SStefano Babic * mapping, Framebuffer registration, IPU initialization. 526*5dda7945SStefano Babic * 527*5dda7945SStefano Babic * @return Appropriate error code to the kernel common code 528*5dda7945SStefano Babic */ 529*5dda7945SStefano Babic static int mxcfb_probe(u32 interface_pix_fmt, struct fb_videomode *mode) 530*5dda7945SStefano Babic { 531*5dda7945SStefano Babic struct fb_info *fbi; 532*5dda7945SStefano Babic struct mxcfb_info *mxcfbi; 533*5dda7945SStefano Babic int ret = 0; 534*5dda7945SStefano Babic 535*5dda7945SStefano Babic /* 536*5dda7945SStefano Babic * Initialize FB structures 537*5dda7945SStefano Babic */ 538*5dda7945SStefano Babic fbi = mxcfb_init_fbinfo(); 539*5dda7945SStefano Babic if (!fbi) { 540*5dda7945SStefano Babic ret = -ENOMEM; 541*5dda7945SStefano Babic goto err0; 542*5dda7945SStefano Babic } 543*5dda7945SStefano Babic mxcfbi = (struct mxcfb_info *)fbi->par; 544*5dda7945SStefano Babic 545*5dda7945SStefano Babic if (!g_dp_in_use) { 546*5dda7945SStefano Babic mxcfbi->ipu_ch = MEM_BG_SYNC; 547*5dda7945SStefano Babic mxcfbi->blank = FB_BLANK_UNBLANK; 548*5dda7945SStefano Babic } else { 549*5dda7945SStefano Babic mxcfbi->ipu_ch = MEM_DC_SYNC; 550*5dda7945SStefano Babic mxcfbi->blank = FB_BLANK_POWERDOWN; 551*5dda7945SStefano Babic } 552*5dda7945SStefano Babic 553*5dda7945SStefano Babic mxcfbi->ipu_di = 0; 554*5dda7945SStefano Babic 555*5dda7945SStefano Babic ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80); 556*5dda7945SStefano Babic ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0); 557*5dda7945SStefano Babic strcpy(fbi->fix.id, "DISP3 BG"); 558*5dda7945SStefano Babic 559*5dda7945SStefano Babic g_dp_in_use = 1; 560*5dda7945SStefano Babic 561*5dda7945SStefano Babic mxcfb_info[mxcfbi->ipu_di] = fbi; 562*5dda7945SStefano Babic 563*5dda7945SStefano Babic /* Need dummy values until real panel is configured */ 564*5dda7945SStefano Babic fbi->var.xres = 640; 565*5dda7945SStefano Babic fbi->var.yres = 480; 566*5dda7945SStefano Babic fbi->var.bits_per_pixel = 16; 567*5dda7945SStefano Babic 568*5dda7945SStefano Babic mxcfbi->ipu_di_pix_fmt = interface_pix_fmt; 569*5dda7945SStefano Babic fb_videomode_to_var(&fbi->var, mode); 570*5dda7945SStefano Babic 571*5dda7945SStefano Babic mxcfb_check_var(&fbi->var, fbi); 572*5dda7945SStefano Babic 573*5dda7945SStefano Babic /* Default Y virtual size is 2x panel size */ 574*5dda7945SStefano Babic fbi->var.yres_virtual = fbi->var.yres * 2; 575*5dda7945SStefano Babic 576*5dda7945SStefano Babic mxcfb_set_fix(fbi); 577*5dda7945SStefano Babic 578*5dda7945SStefano Babic /* alocate fb first */ 579*5dda7945SStefano Babic if (mxcfb_map_video_memory(fbi) < 0) 580*5dda7945SStefano Babic return -ENOMEM; 581*5dda7945SStefano Babic 582*5dda7945SStefano Babic mxcfb_set_par(fbi); 583*5dda7945SStefano Babic 584*5dda7945SStefano Babic /* Setting panel_info for lcd */ 585*5dda7945SStefano Babic panel_info.cmap = NULL; 586*5dda7945SStefano Babic panel_info.vl_col = fbi->var.xres; 587*5dda7945SStefano Babic panel_info.vl_row = fbi->var.yres; 588*5dda7945SStefano Babic panel_info.vl_bpix = LCD_BPP; 589*5dda7945SStefano Babic 590*5dda7945SStefano Babic lcd_line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8; 591*5dda7945SStefano Babic 592*5dda7945SStefano Babic debug("MXC IPUV3 configured\n" 593*5dda7945SStefano Babic "XRES = %d YRES = %d BitsXpixel = %d\n", 594*5dda7945SStefano Babic panel_info.vl_col, 595*5dda7945SStefano Babic panel_info.vl_row, 596*5dda7945SStefano Babic panel_info.vl_bpix); 597*5dda7945SStefano Babic 598*5dda7945SStefano Babic ipu_dump_registers(); 599*5dda7945SStefano Babic 600*5dda7945SStefano Babic return 0; 601*5dda7945SStefano Babic 602*5dda7945SStefano Babic err0: 603*5dda7945SStefano Babic return ret; 604*5dda7945SStefano Babic } 605*5dda7945SStefano Babic 606*5dda7945SStefano Babic int overwrite_console(void) 607*5dda7945SStefano Babic { 608*5dda7945SStefano Babic /* Keep stdout / stderr on serial, our LCD is for splashscreen only */ 609*5dda7945SStefano Babic return 1; 610*5dda7945SStefano Babic } 611*5dda7945SStefano Babic 612*5dda7945SStefano Babic void lcd_ctrl_init(void *lcdbase) 613*5dda7945SStefano Babic { 614*5dda7945SStefano Babic u32 mem_len = panel_info.vl_col * 615*5dda7945SStefano Babic panel_info.vl_row * 616*5dda7945SStefano Babic NBITS(panel_info.vl_bpix) / 8; 617*5dda7945SStefano Babic 618*5dda7945SStefano Babic /* 619*5dda7945SStefano Babic * We rely on lcdbase being a physical address, i.e., either MMU off, 620*5dda7945SStefano Babic * or 1-to-1 mapping. Might want to add some virt2phys here. 621*5dda7945SStefano Babic */ 622*5dda7945SStefano Babic if (!lcdbase) 623*5dda7945SStefano Babic return; 624*5dda7945SStefano Babic 625*5dda7945SStefano Babic memset(lcdbase, 0, mem_len); 626*5dda7945SStefano Babic } 627*5dda7945SStefano Babic 628*5dda7945SStefano Babic int mx51_fb_init(struct fb_videomode *mode) 629*5dda7945SStefano Babic { 630*5dda7945SStefano Babic int ret; 631*5dda7945SStefano Babic 632*5dda7945SStefano Babic ret = ipu_probe(); 633*5dda7945SStefano Babic if (ret) 634*5dda7945SStefano Babic puts("Error initializing IPU\n"); 635*5dda7945SStefano Babic 636*5dda7945SStefano Babic lcd_base += 56; 637*5dda7945SStefano Babic 638*5dda7945SStefano Babic debug("Framebuffer at 0x%x\n", (unsigned int)lcd_base); 639*5dda7945SStefano Babic ret = mxcfb_probe(IPU_PIX_FMT_RGB666, mode); 640*5dda7945SStefano Babic 641*5dda7945SStefano Babic return ret; 642*5dda7945SStefano Babic } 643