static void sh_mobile_fb_reconfig(struct fb_info *info) { struct sh_mobile_lcdc_chan *ch = info->par; struct fb_videomode mode1, mode2; struct fb_event event; int evnt = FB_EVENT_MODE_CHANGE_ALL; if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) /* More framebuffer users are active */ return; fb_var_to_videomode(&mode1, &ch->display_var); fb_var_to_videomode(&mode2, &info->var); if (fb_mode_is_equal(&mode1, &mode2)) return; /* Display has been re-plugged, framebuffer is free now, reconfigure */ if (fb_set_var(info, &ch->display_var) < 0) /* Couldn't reconfigure, hopefully, can continue as before */ return; info->fix.line_length = mode1.xres * (ch->cfg.bpp / 8); /* * fb_set_var() calls the notifier change internally, only if * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a * user event, we have to call the chain ourselves. */ event.info = info; event.data = &mode1; fb_notifier_call_chain(evnt, &event); }
static int tegra_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct tegra_fb_info *tegra_fb = info->par; struct tegra_dc *dc = tegra_fb->win->dc; struct tegra_dc_out_ops *ops = dc->out_ops; struct fb_videomode mode; if ((var->yres * var->xres * var->bits_per_pixel / 8 * 2) > info->screen_size) return -EINVAL; /* Apply mode filter for HDMI only -LVDS supports only fix mode */ if (ops && ops->mode_filter) { fb_var_to_videomode(&mode, var); if (!ops->mode_filter(dc, &mode)) return -EINVAL; /* Mode filter may have modified the mode */ fb_videomode_to_var(var, &mode); } /* Double yres_virtual to allow double buffering through pan_display */ var->yres_virtual = var->yres * 2; return 0; }
static int lcdif_init(struct mxc_dispdrv_handle *disp, struct mxc_dispdrv_setting *setting) { int ret, i; struct mxc_lcdif_data *lcdif = mxc_dispdrv_getdata(disp); struct fsl_mxc_lcd_platform_data *plat_data = lcdif->pdev->dev.platform_data; struct fb_videomode *modedb = lcdif_modedb; int modedb_sz = lcdif_modedb_sz; /* use platform defined ipu/di */ setting->dev_id = plat_data->ipu_id; setting->disp_id = plat_data->disp_id; ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str, modedb, modedb_sz, NULL, setting->default_bpp); if (!ret) { fb_videomode_to_var(&setting->fbi->var, &modedb[0]); setting->if_fmt = plat_data->default_ifmt; } INIT_LIST_HEAD(&setting->fbi->modelist); for (i = 0; i < modedb_sz; i++) { struct fb_videomode m; fb_var_to_videomode(&m, &setting->fbi->var); if (fb_mode_is_equal(&m, &modedb[i])) { fb_add_videomode(&modedb[i], &setting->fbi->modelist); break; } } return ret; }
static const struct fb_videomode *atmel_lcdfb_choose_mode(struct fb_var_screeninfo *var, struct fb_info *info) { struct fb_videomode varfbmode; const struct fb_videomode *fbmode = NULL; fb_var_to_videomode(&varfbmode, var); fbmode = fb_find_nearest_mode(&varfbmode, &info->modelist); if (fbmode) fb_videomode_to_var(var, fbmode); return fbmode; }
static int mipi_dsi_lcd_init(struct mipi_dsi_info *mipi_dsi, struct mxc_dispdrv_setting *setting) { int i, size, err; struct fb_videomode *mipi_lcd_modedb; struct fb_videomode mode; struct device *dev = &mipi_dsi->pdev->dev; for (i = 0; i < ARRAY_SIZE(mipi_dsi_lcd_db); i++) { if (!strcmp(mipi_dsi->lcd_panel, mipi_dsi_lcd_db[i].lcd_panel)) { mipi_dsi->lcd_callback = &mipi_dsi_lcd_db[i].lcd_callback; break; } } if (i == ARRAY_SIZE(mipi_dsi_lcd_db)) { dev_err(dev, "failed to find supported lcd panel.\n"); return -EINVAL; } mipi_dsi->lcd_callback->get_mipi_lcd_videomode(&mipi_lcd_modedb, &size, &mipi_dsi->lcd_config); err = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str, mipi_lcd_modedb, size, NULL, setting->default_bpp); if (err != 1) fb_videomode_to_var(&setting->fbi->var, mipi_lcd_modedb); INIT_LIST_HEAD(&setting->fbi->modelist); for (i = 0; i < size; i++) { fb_var_to_videomode(&mode, &setting->fbi->var); if (fb_mode_is_equal(&mode, mipi_lcd_modedb + i)) { err = fb_add_videomode(mipi_lcd_modedb + i, &setting->fbi->modelist); mipi_dsi->mode = mipi_lcd_modedb + i; break; } } if ((err < 0) || (size == i)) { dev_err(dev, "failed to add videomode.\n"); return err; } return 0; }
/** * adf_fbdev_set_par - default implementation of fbdev set_par op */ int adf_fbdev_set_par(struct fb_info *info) { struct adf_fbdev *fbdev = info->par; struct adf_interface *intf = fbdev->intf; struct fb_videomode vmode; struct drm_mode_modeinfo mode; int ret; u32 format = drm_fourcc_from_fb_var(&info->var); fb_var_to_videomode(&vmode, &info->var); adf_modeinfo_from_fb_videomode(&vmode, &mode); ret = adf_interface_set_mode(intf, &mode); if (ret < 0) return ret; ret = adf_fbdev_post(fbdev); if (ret < 0) return ret; if (format != fbdev->format) adf_fbdev_set_format(fbdev, format); return 0; }
static int ldb_disp_init(struct mxc_dispdrv_handle *disp, struct mxc_dispdrv_setting *setting) { int ret = 0, i; struct ldb_data *ldb = mxc_dispdrv_getdata(disp); struct fsl_mxc_ldb_platform_data *plat_data = ldb->pdev->dev.platform_data; struct resource *res; uint32_t base_addr; uint32_t reg, setting_idx; uint32_t ch_mask = 0, ch_val = 0; uint32_t ipu_id, disp_id; /* if input format not valid, make RGB666 as default*/ if (!valid_mode(setting->if_fmt)) { dev_warn(&ldb->pdev->dev, "Input pixel format not valid" " use default RGB666\n"); setting->if_fmt = IPU_PIX_FMT_RGB666; } if (!ldb->inited) { char di_clk[] = "ipu1_di0_clk"; char ldb_clk[] = "ldb_di0_clk"; int lvds_channel = 0; setting_idx = 0; res = platform_get_resource(ldb->pdev, IORESOURCE_MEM, 0); if (IS_ERR(res)) return -ENOMEM; base_addr = res->start; ldb->reg = ioremap(base_addr, res->end - res->start + 1); ldb->control_reg = ldb->reg + 2; ldb->gpr3_reg = ldb->reg + 3; ldb->lvds_bg_reg = regulator_get(&ldb->pdev->dev, plat_data->lvds_bg_reg); if (!IS_ERR(ldb->lvds_bg_reg)) { regulator_set_voltage(ldb->lvds_bg_reg, 2500000, 2500000); regulator_enable(ldb->lvds_bg_reg); } /* ipu selected by platform data setting */ setting->dev_id = plat_data->ipu_id; reg = readl(ldb->control_reg); /* refrence resistor select */ reg &= ~LDB_BGREF_RMODE_MASK; if (plat_data->ext_ref) reg |= LDB_BGREF_RMODE_EXT; else reg |= LDB_BGREF_RMODE_INT; /* TODO: now only use SPWG data mapping for both channel */ reg &= ~(LDB_BIT_MAP_CH0_MASK | LDB_BIT_MAP_CH1_MASK); reg |= LDB_BIT_MAP_CH0_SPWG | LDB_BIT_MAP_CH1_SPWG; /* channel mode setting */ reg &= ~(LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK); reg &= ~(LDB_DATA_WIDTH_CH0_MASK | LDB_DATA_WIDTH_CH1_MASK); if (bits_per_pixel(setting->if_fmt) == 24) reg |= LDB_DATA_WIDTH_CH0_24 | LDB_DATA_WIDTH_CH1_24; else reg |= LDB_DATA_WIDTH_CH0_18 | LDB_DATA_WIDTH_CH1_18; if (g_ldb_mode) ldb->mode = g_ldb_mode; else ldb->mode = plat_data->mode; if ((ldb->mode == LDB_SIN0) || (ldb->mode == LDB_SIN1)) { ret = ldb->mode - LDB_SIN0; if (plat_data->disp_id != ret) { dev_warn(&ldb->pdev->dev, "change IPU DI%d to IPU DI%d for LDB " "channel%d.\n", plat_data->disp_id, ret, ret); plat_data->disp_id = ret; } } else if (((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1)) && (cpu_is_mx6q() || cpu_is_mx6dl())) { if (plat_data->disp_id == plat_data->sec_disp_id) { dev_err(&ldb->pdev->dev, "For LVDS separate mode," "two DIs should be different!\n"); return -EINVAL; } if (((!plat_data->disp_id) && (ldb->mode == LDB_SEP1)) || ((plat_data->disp_id) && (ldb->mode == LDB_SEP0))) { dev_dbg(&ldb->pdev->dev, "LVDS separate mode:" "swap DI configuration!\n"); ipu_id = plat_data->ipu_id; disp_id = plat_data->disp_id; plat_data->ipu_id = plat_data->sec_ipu_id; plat_data->disp_id = plat_data->sec_disp_id; plat_data->sec_ipu_id = ipu_id; plat_data->sec_disp_id = disp_id; } } if (ldb->mode == LDB_SPL_DI0) { reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI0; setting->disp_id = 0; } else if (ldb->mode == LDB_SPL_DI1) { reg |= LDB_SPLIT_MODE_EN | LDB_CH0_MODE_EN_TO_DI1 | LDB_CH1_MODE_EN_TO_DI1; setting->disp_id = 1; } else if (ldb->mode == LDB_DUL_DI0) { reg &= ~LDB_SPLIT_MODE_EN; reg |= LDB_CH0_MODE_EN_TO_DI0 | LDB_CH1_MODE_EN_TO_DI0; setting->disp_id = 0; } else if (ldb->mode == LDB_DUL_DI1) { reg &= ~LDB_SPLIT_MODE_EN; reg |= LDB_CH0_MODE_EN_TO_DI1 | LDB_CH1_MODE_EN_TO_DI1; setting->disp_id = 1; } else if (ldb->mode == LDB_SIN0) { reg &= ~LDB_SPLIT_MODE_EN; setting->disp_id = plat_data->disp_id; if (setting->disp_id == 0) reg |= LDB_CH0_MODE_EN_TO_DI0; else reg |= LDB_CH0_MODE_EN_TO_DI1; ch_mask = LDB_CH0_MODE_MASK; ch_val = reg & LDB_CH0_MODE_MASK; } else if (ldb->mode == LDB_SIN1) { reg &= ~LDB_SPLIT_MODE_EN; setting->disp_id = plat_data->disp_id; if (setting->disp_id == 0) reg |= LDB_CH1_MODE_EN_TO_DI0; else reg |= LDB_CH1_MODE_EN_TO_DI1; ch_mask = LDB_CH1_MODE_MASK; ch_val = reg & LDB_CH1_MODE_MASK; } else { /* separate mode*/ setting->disp_id = plat_data->disp_id; /* first output is LVDS0 or LVDS1 */ if (ldb->mode == LDB_SEP0) lvds_channel = 0; else lvds_channel = 1; reg &= ~LDB_SPLIT_MODE_EN; if ((lvds_channel == 0) && (setting->disp_id == 0)) reg |= LDB_CH0_MODE_EN_TO_DI0; else if ((lvds_channel == 0) && (setting->disp_id == 1)) reg |= LDB_CH0_MODE_EN_TO_DI1; else if ((lvds_channel == 1) && (setting->disp_id == 0)) reg |= LDB_CH1_MODE_EN_TO_DI0; else reg |= LDB_CH1_MODE_EN_TO_DI1; ch_mask = lvds_channel ? LDB_CH1_MODE_MASK : LDB_CH0_MODE_MASK; ch_val = reg & ch_mask; if (bits_per_pixel(setting->if_fmt) == 24) { if (lvds_channel == 0) reg &= ~LDB_DATA_WIDTH_CH1_24; else reg &= ~LDB_DATA_WIDTH_CH0_24; } else { if (lvds_channel == 0) reg &= ~LDB_DATA_WIDTH_CH1_18; else reg &= ~LDB_DATA_WIDTH_CH0_18; } } writel(reg, ldb->control_reg); if (ldb->mode < LDB_SIN0) { ch_mask = LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK; ch_val = reg & (LDB_CH0_MODE_MASK | LDB_CH1_MODE_MASK); } /* clock setting */ if ((cpu_is_mx6q() || cpu_is_mx6dl()) && ((ldb->mode == LDB_SEP0) || (ldb->mode == LDB_SEP1))) ldb_clk[6] += lvds_channel; else ldb_clk[6] += setting->disp_id; ldb->setting[setting_idx].ldb_di_clk = clk_get(&ldb->pdev->dev, ldb_clk); if (IS_ERR(ldb->setting[setting_idx].ldb_di_clk)) { dev_err(&ldb->pdev->dev, "get ldb clk0 failed\n"); iounmap(ldb->reg); return PTR_ERR(ldb->setting[setting_idx].ldb_di_clk); } di_clk[3] += setting->dev_id; di_clk[7] += setting->disp_id; ldb->setting[setting_idx].di_clk = clk_get(&ldb->pdev->dev, di_clk); if (IS_ERR(ldb->setting[setting_idx].di_clk)) { dev_err(&ldb->pdev->dev, "get di clk0 failed\n"); iounmap(ldb->reg); return PTR_ERR(ldb->setting[setting_idx].di_clk); } dev_dbg(&ldb->pdev->dev, "ldb_clk to di clk: %s -> %s\n", ldb_clk, di_clk); /* fb notifier for clk setting */ ldb->nb.notifier_call = ldb_fb_event, ret = fb_register_client(&ldb->nb); if (ret < 0) { iounmap(ldb->reg); return ret; } ldb->inited = true; } else { /* second time for separate mode */ char di_clk[] = "ipu1_di0_clk"; char ldb_clk[] = "ldb_di0_clk"; int lvds_channel; if ((ldb->mode == LDB_SPL_DI0) || (ldb->mode == LDB_SPL_DI1) || (ldb->mode == LDB_DUL_DI0) || (ldb->mode == LDB_DUL_DI1) || (ldb->mode == LDB_SIN0) || (ldb->mode == LDB_SIN1)) { dev_err(&ldb->pdev->dev, "for second ldb disp" "ldb mode should in separate mode\n"); return -EINVAL; } setting_idx = 1; if (cpu_is_mx6q() || cpu_is_mx6dl()) { setting->dev_id = plat_data->sec_ipu_id; setting->disp_id = plat_data->sec_disp_id; } else { setting->dev_id = plat_data->ipu_id; setting->disp_id = !plat_data->disp_id; } if (setting->disp_id == ldb->setting[0].di) { dev_err(&ldb->pdev->dev, "Err: for second ldb disp in" "separate mode, DI should be different!\n"); return -EINVAL; } /* second output is LVDS0 or LVDS1 */ if (ldb->mode == LDB_SEP0) lvds_channel = 1; else lvds_channel = 0; reg = readl(ldb->control_reg); if ((lvds_channel == 0) && (setting->disp_id == 0)) reg |= LDB_CH0_MODE_EN_TO_DI0; else if ((lvds_channel == 0) && (setting->disp_id == 1)) reg |= LDB_CH0_MODE_EN_TO_DI1; else if ((lvds_channel == 1) && (setting->disp_id == 0)) reg |= LDB_CH1_MODE_EN_TO_DI0; else reg |= LDB_CH1_MODE_EN_TO_DI1; ch_mask = lvds_channel ? LDB_CH1_MODE_MASK : LDB_CH0_MODE_MASK; ch_val = reg & ch_mask; if (bits_per_pixel(setting->if_fmt) == 24) { if (lvds_channel == 0) reg |= LDB_DATA_WIDTH_CH0_24; else reg |= LDB_DATA_WIDTH_CH1_24; } else { if (lvds_channel == 0) reg |= LDB_DATA_WIDTH_CH0_18; else reg |= LDB_DATA_WIDTH_CH1_18; } writel(reg, ldb->control_reg); /* clock setting */ if (cpu_is_mx6q() || cpu_is_mx6dl()) ldb_clk[6] += lvds_channel; else ldb_clk[6] += setting->disp_id; ldb->setting[setting_idx].ldb_di_clk = clk_get(&ldb->pdev->dev, ldb_clk); if (IS_ERR(ldb->setting[setting_idx].ldb_di_clk)) { dev_err(&ldb->pdev->dev, "get ldb clk1 failed\n"); return PTR_ERR(ldb->setting[setting_idx].ldb_di_clk); } di_clk[3] += setting->dev_id; di_clk[7] += setting->disp_id; ldb->setting[setting_idx].di_clk = clk_get(&ldb->pdev->dev, di_clk); if (IS_ERR(ldb->setting[setting_idx].di_clk)) { dev_err(&ldb->pdev->dev, "get di clk1 failed\n"); return PTR_ERR(ldb->setting[setting_idx].di_clk); } dev_dbg(&ldb->pdev->dev, "ldb_clk to di clk: %s -> %s\n", ldb_clk, di_clk); } ldb->setting[setting_idx].ch_mask = ch_mask; ldb->setting[setting_idx].ch_val = ch_val; if (cpu_is_mx6q() || cpu_is_mx6dl()) ldb_ipu_ldb_route(setting->dev_id, setting->disp_id, ldb); /* * ldb_di0_clk -> ipux_di0_clk * ldb_di1_clk -> ipux_di1_clk */ clk_set_parent(ldb->setting[setting_idx].di_clk, ldb->setting[setting_idx].ldb_di_clk); /* must use spec video mode defined by driver */ ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str, ldb_modedb, ldb_modedb_sz, NULL, setting->default_bpp); if (ret != 1) fb_videomode_to_var(&setting->fbi->var, &ldb_modedb[0]); INIT_LIST_HEAD(&setting->fbi->modelist); for (i = 0; i < ldb_modedb_sz; i++) { struct fb_videomode m; fb_var_to_videomode(&m, &setting->fbi->var); if (fb_mode_is_equal(&m, &ldb_modedb[i])) { fb_add_videomode(&ldb_modedb[i], &setting->fbi->modelist); break; } } /* save current ldb setting for fb notifier */ ldb->setting[setting_idx].active = true; ldb->setting[setting_idx].ipu = setting->dev_id; ldb->setting[setting_idx].di = setting->disp_id; return ret; }
static int handle_edid(int *pixclk) { #if 0 int err = 0; int dvi = 0; int fb0 = 0; int fb1 = 1; struct fb_var_screeninfo screeninfo; struct i2c_adapter *adp; memset(&screeninfo, 0, sizeof(screeninfo)); adp = i2c_get_adapter(1); if (cpu_is_mx51_rev(CHIP_REV_3_0) > 0) { gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI2_HSYNC), 1); msleep(1); } err = read_edid(adp, &screeninfo, &dvi); if (cpu_is_mx51_rev(CHIP_REV_3_0) > 0) gpio_set_value(IOMUX_TO_GPIO(MX51_PIN_CSI2_HSYNC), 0); if (!err) { printk(KERN_INFO " EDID read\n"); if (!dvi) { enable_vga = 1; fb0 = 1; /* fb0 will be VGA */ fb1 = 0; /* fb1 will be DVI or TV */ } /* Handle TV modes */ /* This logic is fairly complex yet still doesn't handle all possibilities. Once a customer knows the platform configuration, this should be simplified to what is desired. */ if (screeninfo.xres == 1920 && screeninfo.yres != 1200) { /* MX51 can't handle clock speeds for anything larger.*/ if (!enable_tv) enable_tv = 1; if (enable_vga || enable_wvga || enable_tv == 2) enable_tv = 2; fb_data[0].mode = &(video_modes[0]); if (!enable_wvga) fb_data[1].mode_str = "800x600M-16@60"; } else if (screeninfo.xres > 1280 && screeninfo.yres > 1024) { if (!enable_wvga) { fb_data[fb0].mode_str = "1280x1024M-16@60"; fb_data[fb1].mode_str = NULL; } else { /* WVGA is preset so the DVI can't be > this. */ fb_data[0].mode_str = "1024x768M-16@60"; } } else if (screeninfo.xres > 0 && screeninfo.yres > 0) { if (!enable_wvga) { fb_data[fb0].mode = kzalloc(sizeof(struct fb_videomode), GFP_KERNEL); fb_var_to_videomode(fb_data[fb0].mode, &screeninfo); fb_data[fb0].mode_str = NULL; if (screeninfo.xres >= 1280 && screeninfo.yres > 720) fb_data[fb1].mode_str = NULL; else if (screeninfo.xres > 1024 && screeninfo.yres > 768) fb_data[fb1].mode_str = "800x600M-16@60"; else if (screeninfo.xres > 800 && screeninfo.yres > 600) fb_data[fb1].mode_str = "1024x768M-16@60"; } else { /* A WVGA panel was specified and an EDID was read thus there is a DVI monitor attached. */ if (screeninfo.xres >= 1024) fb_data[0].mode_str = "1024x768M-16@60"; else if (screeninfo.xres >= 800) fb_data[0].mode_str = "800x600M-16@60"; else fb_data[0].mode_str = "640x480M-16@60"; } } } #endif return 0; }
static int tegra_fb_set_par(struct fb_info *info) { struct tegra_fb_info *tegra_fb = info->par; struct fb_var_screeninfo *var = &info->var; struct tegra_dc *dc = tegra_fb->win->dc; if (var->bits_per_pixel) { /* we only support RGB ordering for now */ switch (var->bits_per_pixel) { case 32: var->red.offset = 0; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 16; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8; break; case 16: var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5; break; default: return -EINVAL; } /* if line_length unset, then pad the stride */ if (!info->fix.line_length) { info->fix.line_length = var->xres * var->bits_per_pixel / 8; info->fix.line_length = round_up(info->fix.line_length, TEGRA_LINEAR_PITCH_ALIGNMENT); } tegra_fb->win->stride = info->fix.line_length; tegra_fb->win->stride_uv = 0; tegra_fb->win->phys_addr_u = 0; tegra_fb->win->phys_addr_v = 0; } if (var->pixclock) { bool stereo; unsigned old_len = 0; struct fb_videomode m; struct fb_videomode *old_mode = NULL; fb_var_to_videomode(&m, var); /* Load framebuffer info with new mode details*/ old_mode = info->mode; old_len = info->fix.line_length; info->mode = (struct fb_videomode *) fb_find_nearest_mode(&m, &info->modelist); if (!info->mode) { dev_warn(&tegra_fb->ndev->dev, "can't match video mode\n"); info->mode = old_mode; return -EINVAL; } /* Update fix line_length and window stride as per new mode */ info->fix.line_length = var->xres * var->bits_per_pixel / 8; info->fix.line_length = round_up(info->fix.line_length, TEGRA_LINEAR_PITCH_ALIGNMENT); tegra_fb->win->stride = info->fix.line_length; /* * only enable stereo if the mode supports it and * client requests it */ stereo = !!(var->vmode & info->mode->vmode & #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT FB_VMODE_STEREO_FRAME_PACK); #else FB_VMODE_STEREO_LEFT_RIGHT); #endif /* Configure DC with new mode */ if (tegra_dc_set_fb_mode(dc, info->mode, stereo)) { /* Error while configuring DC, fallback to old mode */ dev_warn(&tegra_fb->ndev->dev, "can't configure dc with mode %ux%u\n", info->mode->xres, info->mode->yres); info->mode = old_mode; info->fix.line_length = old_len; tegra_fb->win->stride = old_len; return -EINVAL; } tegra_fb->win->w.full = dfixed_const(info->mode->xres); tegra_fb->win->h.full = dfixed_const(info->mode->yres); tegra_fb->win->out_w = info->mode->xres; tegra_fb->win->out_h = info->mode->yres; }
static int tegra_fb_set_par(struct fb_info *info) { struct tegra_fb_info *tegra_fb = info->par; struct fb_var_screeninfo *var = &info->var; if (var->bits_per_pixel) { /* we only support RGB ordering for now */ switch (var->bits_per_pixel) { case 32: var->red.offset = 0; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 16; var->blue.length = 8; var->transp.offset = 24; var->transp.length = 8; tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8; break; case 16: var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5; break; default: return -EINVAL; } /* if line_length unset, then pad the stride */ if (!info->fix.line_length) { info->fix.line_length = var->xres * var->bits_per_pixel / 8; info->fix.line_length = round_up(info->fix.line_length, TEGRA_LINEAR_PITCH_ALIGNMENT); } tegra_fb->win->stride = info->fix.line_length; tegra_fb->win->stride_uv = 0; tegra_fb->win->phys_addr_u = 0; tegra_fb->win->phys_addr_v = 0; } if (var->pixclock) { bool stereo; struct fb_videomode m; fb_var_to_videomode(&m, var); info->mode = (struct fb_videomode *) fb_find_nearest_mode(&m, &info->modelist); if (!info->mode) { dev_warn(&tegra_fb->ndev->dev, "can't match video mode\n"); return -EINVAL; } /* * only enable stereo if the mode supports it and * client requests it */ stereo = !!(var->vmode & info->mode->vmode & #ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT FB_VMODE_STEREO_FRAME_PACK); #else FB_VMODE_STEREO_LEFT_RIGHT); #endif tegra_dc_set_fb_mode(tegra_fb->win->dc, info->mode, stereo); tegra_fb->win->w.full = dfixed_const(info->mode->xres); tegra_fb->win->h.full = dfixed_const(info->mode->yres); tegra_fb->win->out_w = info->mode->xres; tegra_fb->win->out_h = info->mode->yres; }
static void det_worker(struct work_struct *work) { BYTE HPD, HPDChange ; char event_string[16]; char *envp[] = { event_string, NULL }; CheckHDMITX(&HPD, &HPDChange); if (HPDChange) { /* cable connection changes */ if (HPD) { ite661x.cable_plugin = 1; sprintf(event_string, "EVENT=plugin"); /* make sure fb is powerdown */ acquire_console_sem(); fb_blank(ite661x.fbi, FB_BLANK_POWERDOWN); release_console_sem(); if (ite661x_read_edid(ite661x.fbi) < 0) dev_err(&ite661x.client->dev, "ite661x: read edid fail\n"); else { ParseEDID(ite661x.edid + 128); if (ite661x.fbi->monspecs.modedb_len > 0) { int i; const struct fb_videomode *mode; struct fb_videomode m; fb_destroy_modelist(&ite661x.fbi->modelist); for (i = 0; i < ite661x.fbi->monspecs.modedb_len; i++) { /*FIXME now we do not support interlaced mode */ if (!(ite661x.fbi->monspecs.modedb[i].vmode & FB_VMODE_INTERLACED)) fb_add_videomode(&ite661x.fbi->monspecs.modedb[i], &ite661x.fbi->modelist); } fb_var_to_videomode(&m, &ite661x.fbi->var); mode = fb_find_nearest_mode(&m, &ite661x.fbi->modelist); fb_videomode_to_var(&ite661x.fbi->var, mode); ite661x.fbi->var.activate |= FB_ACTIVATE_FORCE; acquire_console_sem(); ite661x.fbi->flags |= FBINFO_MISC_USEREVENT; fb_set_var(ite661x.fbi, &ite661x.fbi->var); ite661x.fbi->flags &= ~FBINFO_MISC_USEREVENT; release_console_sem(); } acquire_console_sem(); fb_blank(ite661x.fbi, FB_BLANK_UNBLANK); release_console_sem(); HDMITX_SetOutput(); } } else { ite661x.cable_plugin = 0; sprintf(event_string, "EVENT=plugout"); acquire_console_sem(); fb_blank(ite661x.fbi, FB_BLANK_POWERDOWN); release_console_sem(); DisableAudioOutput(); DisableVideoOutput(); } kobject_uevent_env(&ite661x.pdev->dev.kobj, KOBJ_CHANGE, envp); } enable_irq(ite661x.client->irq); }
static void det_worker(struct work_struct *work) { int dat; char event_string[16]; char *envp[] = { event_string, NULL }; dev_dbg(&sii902x.pdev->dev, "%s\n", __func__); dat = i2c_smbus_read_byte_data(sii902x.client, 0x3D); if (dat & 0x1) { /* cable connection changes */ if (dat & 0x4) { sii902x.cable_plugin = 1; dev_dbg(&sii902x.pdev->dev, "EVENT=plugin\n"); sprintf(event_string, "EVENT=plugin"); if (sii902x_read_edid(sii902x.fbi) < 0) dev_err(&sii902x.client->dev, "Sii902x: read edid fail\n"); else { if (sii902x.fbi->monspecs.modedb_len > 0) { int i; const struct fb_videomode *mode; struct fb_videomode m; fb_destroy_modelist(&sii902x.fbi->modelist); for (i = 0; i < sii902x.fbi->monspecs.modedb_len; i++) { /*FIXME now we do not support interlaced mode */ mode = &sii902x.fbi->monspecs.modedb[i]; if (!(mode->vmode & FB_VMODE_INTERLACED)) { dev_dbg(&sii902x.pdev->dev, "Added mode %d:", i); dev_dbg(&sii902x.pdev->dev, "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n", mode->xres, mode->yres, mode->refresh, mode->vmode, mode->flag); fb_add_videomode(mode, &sii902x.fbi->modelist); } } fb_var_to_videomode(&m, &sii902x.fbi->var); dump_fb_videomode(&m); mode = fb_find_nearest_mode(&m, &sii902x.fbi->modelist); fb_videomode_to_var(&sii902x.fbi->var, mode); sii902x.fbi->var.activate |= FB_ACTIVATE_FORCE; console_lock(); sii902x.fbi->flags |= FBINFO_MISC_USEREVENT; fb_set_var(sii902x.fbi, &sii902x.fbi->var); sii902x.fbi->flags &= ~FBINFO_MISC_USEREVENT; console_unlock(); } /* Power on sii902x */ sii902x_poweron(); } } else { sii902x.cable_plugin = 0; dev_dbg(&sii902x.pdev->dev, "EVENT=plugout\n"); sprintf(event_string, "EVENT=plugout"); /* Power off sii902x */ sii902x_poweroff(); } kobject_uevent_env(&sii902x.pdev->dev.kobj, KOBJ_CHANGE, envp); } i2c_smbus_write_byte_data(sii902x.client, 0x3D, dat); dev_dbg(&sii902x.pdev->dev, "exit %s\n", __func__); }
static int lcdif_init(struct mxc_dispdrv_handle *disp, struct mxc_dispdrv_setting *setting) { int ret, i; struct mxc_lcdif_data *lcdif = mxc_dispdrv_getdata(disp); struct fsl_mxc_lcd_platform_data *plat_data = lcdif->pdev->dev.platform_data; struct fb_videomode *modedb = lcdif_modedb; int modedb_sz = lcdif_modedb_sz; struct fsl_video_timing *custom_timing; /* use platform defined ipu/di */ setting->dev_id = plat_data->ipu_id; setting->disp_id = plat_data->disp_id; if (plat_data->lcd0_timing != NULL) { custom_timing = plat_data->lcd0_timing; lcdif_modedb[0].pixclock = PICOS2KHZ(custom_timing->pixclock); lcdif_modedb[0].xres = custom_timing->hres; lcdif_modedb[0].left_margin = custom_timing->hfp; lcdif_modedb[0].right_margin = custom_timing->hbp; lcdif_modedb[0].hsync_len = custom_timing->hsw; lcdif_modedb[0].yres = custom_timing->vres; lcdif_modedb[0].upper_margin = custom_timing->vfp; lcdif_modedb[0].lower_margin = custom_timing->vbp; lcdif_modedb[0].vsync_len = custom_timing->vsw; } if (plat_data->lcd1_timing != NULL) { custom_timing = plat_data->lcd1_timing; lcdif_modedb[1].pixclock = PICOS2KHZ(custom_timing->pixclock); lcdif_modedb[1].xres = custom_timing->hres; lcdif_modedb[1].left_margin = custom_timing->hfp; lcdif_modedb[1].right_margin = custom_timing->hbp; lcdif_modedb[1].hsync_len = custom_timing->hsw; lcdif_modedb[1].yres = custom_timing->vres; lcdif_modedb[1].upper_margin = custom_timing->vfp; lcdif_modedb[1].lower_margin = custom_timing->vbp; lcdif_modedb[1].vsync_len = custom_timing->vsw; } ret = fb_find_mode(&setting->fbi->var, setting->fbi, setting->dft_mode_str, modedb, modedb_sz, NULL, setting->default_bpp); if (!ret) { fb_videomode_to_var(&setting->fbi->var, &modedb[0]); setting->if_fmt = plat_data->default_ifmt; } INIT_LIST_HEAD(&setting->fbi->modelist); for (i = 0; i < modedb_sz; i++) { struct fb_videomode m; fb_var_to_videomode(&m, &setting->fbi->var); if (fb_mode_is_equal(&m, &modedb[i])) { fb_add_videomode(&modedb[i], &setting->fbi->modelist); break; } } return ret; }
/** * adf_fbdev_check_var - default implementation of fbdev check_var op */ int adf_fbdev_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct adf_fbdev *fbdev = info->par; bool valid_format = true; u32 format = drm_fourcc_from_fb_var(var); u32 pitch = var->xres_virtual * var->bits_per_pixel / 8; if (!format) { dev_dbg(info->dev, "%s: unrecognized format\n", __func__); valid_format = false; } if (valid_format && var->grayscale) { dev_dbg(info->dev, "%s: grayscale modes not supported\n", __func__); valid_format = false; } if (valid_format && var->nonstd) { dev_dbg(info->dev, "%s: nonstandard formats not supported\n", __func__); valid_format = false; } if (valid_format && !adf_overlay_engine_supports_format(fbdev->eng, format)) { char format_str[ADF_FORMAT_STR_SIZE]; adf_format_str(format, format_str); dev_dbg(info->dev, "%s: format %s not supported by overlay engine %s\n", __func__, format_str, fbdev->eng->base.name); valid_format = false; } if (valid_format && pitch > fbdev->pitch) { dev_dbg(info->dev, "%s: fb pitch too small for var (pitch = %u, xres_virtual = %u, bits_per_pixel = %u)\n", __func__, fbdev->pitch, var->xres_virtual, var->bits_per_pixel); valid_format = false; } if (valid_format && var->yres_virtual > fbdev->default_yres_virtual) { dev_dbg(info->dev, "%s: fb height too small for var (h = %u, yres_virtual = %u)\n", __func__, fbdev->default_yres_virtual, var->yres_virtual); valid_format = false; } if (valid_format) { var->activate = info->var.activate; var->height = info->var.height; var->width = info->var.width; var->accel_flags = info->var.accel_flags; var->rotate = info->var.rotate; var->colorspace = info->var.colorspace; /* userspace can't change these */ } else { /* if any part of the format is invalid then fixing it up is impractical, so save just the modesetting bits and overwrite everything else */ struct fb_videomode mode; fb_var_to_videomode(&mode, var); memcpy(var, &info->var, sizeof(*var)); fb_videomode_to_var(var, &mode); } return 0; }
static int mxc_elcdif_fb_probe(struct platform_device *pdev) { int ret = 0; struct mxc_elcdif_fb_data *data; struct resource *res; struct fb_info *fbi; struct mxc_fb_platform_data *pdata = pdev->dev.platform_data; const struct fb_videomode *mode; struct fb_videomode m; int num; fbi = framebuffer_alloc(sizeof(struct mxc_elcdif_fb_data), &pdev->dev); if (fbi == NULL) { ret = -ENOMEM; goto out; } data = (struct mxc_elcdif_fb_data *)fbi->par; data->cur_blank = data->next_blank = FB_BLANK_UNBLANK; fbi->var.activate = FB_ACTIVATE_NOW; fbi->fbops = &mxc_elcdif_fb_ops; fbi->flags = FBINFO_FLAG_DEFAULT; fbi->pseudo_palette = data->pseudo_palette; ret = fb_alloc_cmap(&fbi->cmap, 16, 0); if (ret) goto out; g_elcdif_dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { dev_err(&pdev->dev, "cannot get IRQ resource\n"); ret = -ENODEV; goto err0; } data->dma_irq = res->start; ret = request_irq(data->dma_irq, lcd_irq_handler, 0, "mxc_elcdif_fb", data); if (ret) { dev_err(&pdev->dev, "request_irq (%d) failed with error %d\n", data->dma_irq, ret); goto err0; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { ret = -ENODEV; goto err1; } elcdif_base = ioremap(res->start, SZ_4K); res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) { fbi->fix.smem_len = res->end - res->start + 1; fbi->fix.smem_start = res->start; fbi->screen_base = ioremap(fbi->fix.smem_start, fbi->fix.smem_len); } strcpy(fbi->fix.id, "mxc_elcdif_fb"); fbi->var.xres = 800; fbi->var.yres = 480; if (pdata && !data->output_pix_fmt) data->output_pix_fmt = pdata->interface_pix_fmt; INIT_LIST_HEAD(&fbi->modelist); if (pdata && pdata->mode && pdata->num_modes) fb_videomode_to_modelist(pdata->mode, pdata->num_modes, &fbi->modelist); if (mxc_disp_mode.num_modes) { int i; mode = mxc_disp_mode.mode; num = mxc_disp_mode.num_modes; for (i = 0; i < num; i++) { /* * FIXME now we do not support interlaced * mode for ddc mode */ if ((mxc_disp_mode.dev_mode & MXC_DISP_DDC_DEV) && (mode[i].vmode & FB_VMODE_INTERLACED)) continue; else { dev_dbg(&pdev->dev, "Added mode %d:", i); dev_dbg(&pdev->dev, "xres = %d, yres = %d, freq = %d, vmode = %d, flag = %d\n", mode[i].xres, mode[i].yres, mode[i].refresh, mode[i].vmode, mode[i].flag); fb_add_videomode(&mode[i], &fbi->modelist); } } } if (!fb_mode && pdata && pdata->mode_str) fb_mode = pdata->mode_str; if (fb_mode) { dev_dbg(&pdev->dev, "default video mode %s\n", fb_mode); ret = fb_find_mode(&fbi->var, fbi, fb_mode, NULL, 0, NULL, default_bpp); if ((ret == 1) || (ret == 2)) { fb_var_to_videomode(&m, &fbi->var); dump_fb_videomode(&m); mode = fb_find_nearest_mode(&m, &fbi->modelist); fb_videomode_to_var(&fbi->var, mode); } else if (pdata && pdata->mode && pdata->num_modes) { ret = fb_find_mode(&fbi->var, fbi, fb_mode, pdata->mode, pdata->num_modes, NULL, default_bpp); if (!ret) { dev_err(fbi->device, "No valid video mode found"); goto err2; } } else { dev_err(fbi->device, "No valid video mode found"); goto err2; } } mxc_elcdif_fb_check_var(&fbi->var, fbi); fbi->var.xres_virtual = fbi->var.xres; fbi->var.yres_virtual = fbi->var.yres * 3; mxc_elcdif_fb_set_fix(fbi); if (!res || !res->end) if (mxc_elcdif_fb_map_video_memory(fbi) < 0) { ret = -ENOMEM; goto err2; } g_elcdif_axi_clk = clk_get(g_elcdif_dev, "elcdif_axi"); if (g_elcdif_axi_clk == NULL) { dev_err(&pdev->dev, "can't get ELCDIF axi clk\n"); ret = -ENODEV; goto err3; } g_elcdif_pix_clk = clk_get(g_elcdif_dev, "elcdif_pix"); if (g_elcdif_pix_clk == NULL) { dev_err(&pdev->dev, "can't get ELCDIF pix clk\n"); ret = -ENODEV; goto err3; } /* * Set an appropriate pixel clk rate first, so that we can * access ELCDIF registers. */ clk_set_rate(g_elcdif_pix_clk, 25000000); fbi->var.activate |= FB_ACTIVATE_FORCE; console_lock(); fbi->flags |= FBINFO_MISC_USEREVENT; ret = fb_set_var(fbi, &fbi->var); fbi->flags &= ~FBINFO_MISC_USEREVENT; console_unlock(); if (data->cur_blank == FB_BLANK_UNBLANK) { console_lock(); fb_blank(fbi, FB_BLANK_UNBLANK); console_unlock(); } ret = register_framebuffer(fbi); if (ret) goto err3; platform_set_drvdata(pdev, fbi); return 0; err3: mxc_elcdif_fb_unmap_video_memory(fbi); err2: iounmap(elcdif_base); err1: free_irq(data->dma_irq, data); err0: fb_dealloc_cmap(&fbi->cmap); framebuffer_release(fbi); out: return ret; }