コード例 #1
0
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;
}
コード例 #2
0
ファイル: mxc_lcdif.c プロジェクト: AvalueAES/rev-sa01
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;
}
コード例 #3
0
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;
}
コード例 #4
0
/**
 * adf_fbdev_open - default implementation of fbdev open op
 */
int adf_fbdev_open(struct fb_info *info, int user)
{
	struct adf_fbdev *fbdev = info->par;
	int ret;

	mutex_lock(&fbdev->refcount_lock);

	if (unlikely(fbdev->refcount == UINT_MAX)) {
		ret = -EMFILE;
		goto done;
	}

	if (!fbdev->refcount) {
		struct drm_mode_modeinfo mode;
		struct fb_videomode fbmode;
		struct adf_device *dev = adf_interface_parent(fbdev->intf);

		ret = adf_device_attach(dev, fbdev->eng, fbdev->intf);
		if (ret < 0 && ret != -EALREADY)
			goto done;

		ret = adf_fb_alloc(fbdev);
		if (ret < 0)
			goto done;

		adf_interface_current_mode(fbdev->intf, &mode);
		adf_modeinfo_to_fb_videomode(&mode, &fbmode);
		fb_videomode_to_var(&fbdev->info->var, &fbmode);

		adf_fbdev_set_format(fbdev, fbdev->default_format);
		adf_fbdev_fill_modelist(fbdev);
	}

	if (!fbdev_opened_once) {
		fbdev_opened_once = true;
	} else {
		ret = adf_fbdev_post(fbdev);
		if (ret < 0) {
			if (!fbdev->refcount)
				adf_fb_destroy(fbdev);
			goto done;
		}
	}

	fbdev->refcount++;
done:
	mutex_unlock(&fbdev->refcount_lock);
	return ret;
}
コード例 #5
0
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;
}
コード例 #6
0
static void lcd_init_fb(struct fb_info *info)
{
	struct fb_var_screeninfo var;

	memset(&var, 0, sizeof(var));

	fb_videomode_to_var(&var, &mode);

	var.activate = FB_ACTIVATE_ALL;

	acquire_console_sem();
	info->flags |= FBINFO_MISC_USEREVENT;
	fb_set_var(info, &var);
	fb_blank(info, FB_BLANK_UNBLANK);
	info->flags &= ~FBINFO_MISC_USEREVENT;
	release_console_sem();
}
コード例 #7
0
static void lcd_init_fb(struct fb_info *info)
{
	struct fb_var_screeninfo var;

	memset(&var, 0, sizeof(var));

	fb_videomode_to_var(&var, &video_modes[0]);

	var.activate = FB_ACTIVATE_ALL;
	var.yres_virtual = var.yres * 3;

	acquire_console_sem();
	info->flags |= FBINFO_MISC_USEREVENT;
	fb_set_var(info, &var);
	info->flags &= ~FBINFO_MISC_USEREVENT;
	release_console_sem();
}
コード例 #8
0
static void lcd_init_fb(struct fb_info *info)
{
	struct fb_var_screeninfo var;

	memset(&var, 0, sizeof(var));

	fb_videomode_to_var(&var, &video_modes[0]);

	if (machine_is_mx31_3ds()) {
		var.upper_margin = 0;
		var.left_margin = 0;
	}

	var.activate = FB_ACTIVATE_ALL;
	var.yres_virtual = var.yres * 2;

	acquire_console_sem();
	info->flags |= FBINFO_MISC_USEREVENT;
	fb_set_var(info, &var);
	info->flags &= ~FBINFO_MISC_USEREVENT;
	release_console_sem();
}
コード例 #9
0
/**
 * adf_fbdev_open - default implementation of fbdev open op
 */
int adf_fbdev_open(struct fb_info *info, int user)
{
	struct adf_fbdev *fbdev = info->par;
	int ret;

	if (!fbdev->open) {
		struct drm_mode_modeinfo mode;
		struct fb_videomode fbmode;
		struct adf_device *dev = adf_interface_parent(fbdev->intf);

		ret = adf_device_attach(dev, fbdev->eng, fbdev->intf);
		if (ret < 0 && ret != -EALREADY)
			return ret;

		ret = adf_fb_alloc(fbdev);
		if (ret < 0)
			return ret;

		adf_interface_current_mode(fbdev->intf, &mode);
		adf_modeinfo_to_fb_videomode(&mode, &fbmode);
		fb_videomode_to_var(&fbdev->info->var, &fbmode);

		adf_fbdev_set_format(fbdev, fbdev->default_format);
		adf_fbdev_fill_modelist(fbdev);
	}

	ret = adf_fbdev_post(fbdev);
	if (ret < 0) {
		if (!fbdev->open)
			adf_fb_destroy(fbdev);
		return ret;
	}

	fbdev->open = true;
	return 0;
}
コード例 #10
0
ファイル: mxc_elcdif_fb.c プロジェクト: AvalueAES/rev-sa01
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;
}
コード例 #11
0
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__);

}
コード例 #12
0
/*
 * Probe routine for the framebuffer driver. It is called during the
 * driver binding process. The following functions are performed in
 * this routine: Framebuffer initialization, Memory allocation and
 * mapping, Framebuffer registration, IPU initialization.
 *
 * @return      Appropriate error code to the kernel common code
 */
static int mxcfb_probe(u32 interface_pix_fmt, uint8_t disp,
			struct fb_videomode const *mode)
{
	struct fb_info *fbi;
	struct mxcfb_info *mxcfbi;
	int ret = 0;

	/*
	 * Initialize FB structures
	 */
	fbi = mxcfb_init_fbinfo();
	if (!fbi) {
		ret = -ENOMEM;
		goto err0;
	}
	mxcfbi = (struct mxcfb_info *)fbi->par;

	if (!g_dp_in_use) {
		mxcfbi->ipu_ch = MEM_BG_SYNC;
		mxcfbi->blank = FB_BLANK_UNBLANK;
	} else {
		mxcfbi->ipu_ch = MEM_DC_SYNC;
		mxcfbi->blank = FB_BLANK_POWERDOWN;
	}

	mxcfbi->ipu_di = disp;

	ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
	ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
	strcpy(fbi->fix.id, "DISP3 BG");

	g_dp_in_use = 1;

	mxcfb_info[mxcfbi->ipu_di] = fbi;

	/* Need dummy values until real panel is configured */

	mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
	fb_videomode_to_var(&fbi->var, mode);
	fbi->var.bits_per_pixel = 16;
	fbi->fix.line_length = fbi->var.xres * (fbi->var.bits_per_pixel / 8);
	fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length;

	mxcfb_check_var(&fbi->var, fbi);

	/* Default Y virtual size is 2x panel size */
	fbi->var.yres_virtual = fbi->var.yres * 2;

	mxcfb_set_fix(fbi);

	/* allocate fb first */
	if (mxcfb_map_video_memory(fbi) < 0)
		return -ENOMEM;

	mxcfb_set_par(fbi);

	panel.winSizeX = mode->xres;
	panel.winSizeY = mode->yres;
	panel.plnSizeX = mode->xres;
	panel.plnSizeY = mode->yres;

	panel.frameAdrs = (u32)fbi->screen_base;
	panel.memSize = fbi->screen_size;

	panel.gdfBytesPP = 2;
	panel.gdfIndex = GDF_16BIT_565RGB;

	ipu_dump_registers();

	return 0;

err0:
	return ret;
}
コード例 #13
0
ファイル: sh_mobile_lcdcfb.c プロジェクト: CSCLOG/beaglebone
static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev)
{
	struct fb_info *info;
	struct sh_mobile_lcdc_priv *priv;
	struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data;
	struct resource *res;
	int error;
	void *buf;
	int i, j;

	if (!pdata) {
		dev_err(&pdev->dev, "no platform data defined\n");
		return -EINVAL;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	i = platform_get_irq(pdev, 0);
	if (!res || i < 0) {
		dev_err(&pdev->dev, "cannot get platform resources\n");
		return -ENOENT;
	}

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		dev_err(&pdev->dev, "cannot allocate device data\n");
		return -ENOMEM;
	}

	platform_set_drvdata(pdev, priv);

	error = request_irq(i, sh_mobile_lcdc_irq, IRQF_DISABLED,
			    dev_name(&pdev->dev), priv);
	if (error) {
		dev_err(&pdev->dev, "unable to request irq\n");
		goto err1;
	}

	priv->irq = i;
	atomic_set(&priv->hw_usecnt, -1);

	j = 0;
	for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) {
		struct sh_mobile_lcdc_chan *ch = priv->ch + j;

		ch->lcdc = priv;
		memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i]));

		error = sh_mobile_lcdc_check_interface(ch);
		if (error) {
			dev_err(&pdev->dev, "unsupported interface type\n");
			goto err1;
		}
		init_waitqueue_head(&ch->frame_end_wait);
		init_completion(&ch->vsync_completion);
		ch->pan_offset = 0;

		/* probe the backlight is there is one defined */
		if (ch->cfg.bl_info.max_brightness)
			ch->bl = sh_mobile_lcdc_bl_probe(&pdev->dev, ch);

		switch (pdata->ch[i].chan) {
		case LCDC_CHAN_MAINLCD:
			ch->enabled = 1 << 1;
			ch->reg_offs = lcdc_offs_mainlcd;
			j++;
			break;
		case LCDC_CHAN_SUBLCD:
			ch->enabled = 1 << 2;
			ch->reg_offs = lcdc_offs_sublcd;
			j++;
			break;
		}
	}

	if (!j) {
		dev_err(&pdev->dev, "no channels defined\n");
		error = -EINVAL;
		goto err1;
	}

	/* for dual channel LCDC (MAIN + SUB) force shared bpp setting */
	if (j == 2)
		priv->forced_bpp = pdata->ch[0].bpp;

	priv->base = ioremap_nocache(res->start, resource_size(res));
	if (!priv->base)
		goto err1;

	error = sh_mobile_lcdc_setup_clocks(pdev, pdata->clock_source, priv);
	if (error) {
		dev_err(&pdev->dev, "unable to setup clocks\n");
		goto err1;
	}

	priv->meram_dev = pdata->meram_dev;

	for (i = 0; i < j; i++) {
		struct fb_var_screeninfo *var;
		const struct fb_videomode *lcd_cfg, *max_cfg = NULL;
		struct sh_mobile_lcdc_chan *ch = priv->ch + i;
		struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg;
		const struct fb_videomode *mode = cfg->lcd_cfg;
		unsigned long max_size = 0;
		int k;
		int num_cfg;

		ch->info = framebuffer_alloc(0, &pdev->dev);
		if (!ch->info) {
			dev_err(&pdev->dev, "unable to allocate fb_info\n");
			error = -ENOMEM;
			break;
		}

		info = ch->info;
		var = &info->var;
		info->fbops = &sh_mobile_lcdc_ops;
		info->par = ch;

		mutex_init(&ch->open_lock);

		for (k = 0, lcd_cfg = mode;
		     k < cfg->num_cfg && lcd_cfg;
		     k++, lcd_cfg++) {
			unsigned long size = lcd_cfg->yres * lcd_cfg->xres;
			/* NV12 buffers must have even number of lines */
			if ((cfg->nonstd) && cfg->bpp == 12 &&
					(lcd_cfg->yres & 0x1)) {
				dev_err(&pdev->dev, "yres must be multiple of 2"
						" for YCbCr420 mode.\n");
				error = -EINVAL;
				goto err1;
			}

			if (size > max_size) {
				max_cfg = lcd_cfg;
				max_size = size;
			}
		}

		if (!mode)
			max_size = MAX_XRES * MAX_YRES;
		else if (max_cfg)
			dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n",
				max_cfg->xres, max_cfg->yres);

		info->fix = sh_mobile_lcdc_fix;
		info->fix.smem_len = max_size * 2 * cfg->bpp / 8;

		 /* Only pan in 2 line steps for NV12 */
		if (cfg->nonstd && cfg->bpp == 12)
			info->fix.ypanstep = 2;

		if (!mode) {
			mode = &default_720p;
			num_cfg = 1;
		} else {
			num_cfg = cfg->num_cfg;
		}

		fb_videomode_to_modelist(mode, num_cfg, &info->modelist);

		fb_videomode_to_var(var, mode);
		var->width = cfg->lcd_size_cfg.width;
		var->height = cfg->lcd_size_cfg.height;
		/* Default Y virtual resolution is 2x panel size */
		var->yres_virtual = var->yres * 2;
		var->activate = FB_ACTIVATE_NOW;

		error = sh_mobile_lcdc_set_bpp(var, cfg->bpp, cfg->nonstd);
		if (error)
			break;

		buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len,
					 &ch->dma_handle, GFP_KERNEL);
		if (!buf) {
			dev_err(&pdev->dev, "unable to allocate buffer\n");
			error = -ENOMEM;
			break;
		}

		info->pseudo_palette = &ch->pseudo_palette;
		info->flags = FBINFO_FLAG_DEFAULT;

		error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0);
		if (error < 0) {
			dev_err(&pdev->dev, "unable to allocate cmap\n");
			dma_free_coherent(&pdev->dev, info->fix.smem_len,
					  buf, ch->dma_handle);
			break;
		}

		info->fix.smem_start = ch->dma_handle;
		if (var->nonstd)
			info->fix.line_length = var->xres;
		else
			info->fix.line_length = var->xres * (cfg->bpp / 8);

		info->screen_base = buf;
		info->device = &pdev->dev;
		ch->display_var = *var;
	}

	if (error)
		goto err1;

	error = sh_mobile_lcdc_start(priv);
	if (error) {
		dev_err(&pdev->dev, "unable to start hardware\n");
		goto err1;
	}

	for (i = 0; i < j; i++) {
		struct sh_mobile_lcdc_chan *ch = priv->ch + i;

		info = ch->info;

		if (info->fbdefio) {
			ch->sglist = vmalloc(sizeof(struct scatterlist) *
					info->fix.smem_len >> PAGE_SHIFT);
			if (!ch->sglist) {
				dev_err(&pdev->dev, "cannot allocate sglist\n");
				goto err1;
			}
		}

		info->bl_dev = ch->bl;

		error = register_framebuffer(info);
		if (error < 0)
			goto err1;

		dev_info(info->dev,
			 "registered %s/%s as %dx%d %dbpp.\n",
			 pdev->name,
			 (ch->cfg.chan == LCDC_CHAN_MAINLCD) ?
			 "mainlcd" : "sublcd",
			 info->var.xres, info->var.yres,
			 ch->cfg.bpp);

		/* deferred io mode: disable clock to save power */
		if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED)
			sh_mobile_lcdc_clk_off(priv);
	}
コード例 #14
0
static int wm8505fb_probe(struct platform_device *pdev)
{
	struct wm8505fb_info	*fbi;
	struct resource	*res;
	struct display_timings *disp_timing;
	void			*addr;
	int ret;

	struct fb_videomode	mode;
	u32			bpp;
	dma_addr_t fb_mem_phys;
	unsigned long fb_mem_len;
	void *fb_mem_virt;

	fbi = devm_kzalloc(&pdev->dev, sizeof(struct wm8505fb_info) +
			sizeof(u32) * 16, GFP_KERNEL);
	if (!fbi) {
		dev_err(&pdev->dev, "Failed to initialize framebuffer device\n");
		return -ENOMEM;
	}

	strcpy(fbi->fb.fix.id, DRIVER_NAME);

	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
	fbi->fb.fix.xpanstep	= 1;
	fbi->fb.fix.ypanstep	= 1;
	fbi->fb.fix.ywrapstep	= 0;
	fbi->fb.fix.accel	= FB_ACCEL_NONE;

	fbi->fb.fbops		= &wm8505fb_ops;
	fbi->fb.flags		= FBINFO_DEFAULT
				| FBINFO_HWACCEL_COPYAREA
				| FBINFO_HWACCEL_FILLRECT
				| FBINFO_HWACCEL_XPAN
				| FBINFO_HWACCEL_YPAN
				| FBINFO_VIRTFB
				| FBINFO_PARTIAL_PAN_OK;
	fbi->fb.node		= -1;

	addr = fbi;
	addr = addr + sizeof(struct wm8505fb_info);
	fbi->fb.pseudo_palette	= addr;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	fbi->regbase = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(fbi->regbase))
		return PTR_ERR(fbi->regbase);

	disp_timing = of_get_display_timings(pdev->dev.of_node);
	if (!disp_timing)
		return -EINVAL;

	ret = of_get_fb_videomode(pdev->dev.of_node, &mode, OF_USE_NATIVE_MODE);
	if (ret)
		return ret;

	ret = of_property_read_u32(pdev->dev.of_node, "bits-per-pixel", &bpp);
	if (ret)
		return ret;

	fb_videomode_to_var(&fbi->fb.var, &mode);

	fbi->fb.var.nonstd		= 0;
	fbi->fb.var.activate		= FB_ACTIVATE_NOW;

	fbi->fb.var.height		= -1;
	fbi->fb.var.width		= -1;

	/* try allocating the framebuffer */
	fb_mem_len = mode.xres * mode.yres * 2 * (bpp / 8);
	fb_mem_virt = dmam_alloc_coherent(&pdev->dev, fb_mem_len, &fb_mem_phys,
				GFP_KERNEL);
	if (!fb_mem_virt) {
		pr_err("%s: Failed to allocate framebuffer\n", __func__);
		return -ENOMEM;
	}

	fbi->fb.var.xres_virtual	= mode.xres;
	fbi->fb.var.yres_virtual	= mode.yres * 2;
	fbi->fb.var.bits_per_pixel	= bpp;

	fbi->fb.fix.smem_start		= fb_mem_phys;
	fbi->fb.fix.smem_len		= fb_mem_len;
	fbi->fb.screen_base		= fb_mem_virt;
	fbi->fb.screen_size		= fb_mem_len;

	fbi->contrast = 0x10;
	ret = wm8505fb_set_par(&fbi->fb);
	if (ret) {
		dev_err(&pdev->dev, "Failed to set parameters\n");
		return ret;
	}

	if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) {
		dev_err(&pdev->dev, "Failed to allocate color map\n");
		return -ENOMEM;
	}

	wm8505fb_init_hw(&fbi->fb);

	platform_set_drvdata(pdev, fbi);

	ret = register_framebuffer(&fbi->fb);
	if (ret < 0) {
		dev_err(&pdev->dev,
			"Failed to register framebuffer device: %d\n", ret);
		if (fbi->fb.cmap.len)
			fb_dealloc_cmap(&fbi->fb.cmap);
		return ret;
	}

	ret = device_create_file(&pdev->dev, &dev_attr_contrast);
	if (ret < 0) {
		printk(KERN_WARNING "fb%d: failed to register attributes (%d)\n",
			fbi->fb.node, ret);
	}

	printk(KERN_INFO "fb%d: %s frame buffer at 0x%lx-0x%lx\n",
	       fbi->fb.node, fbi->fb.fix.id, fbi->fb.fix.smem_start,
	       fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1);

	return 0;
}
コード例 #15
0
/*!
 * This function is called by the driver framework to initialize the LDB
 * device.
 *
 * @param	dev	The device structure for the LDB passed in by the
 *			driver framework.
 *
 * @return      Returns 0 on success or negative error code on error
 */
static int ldb_probe(struct platform_device *pdev)
{
	int ret = 0, i, ipu_di, ipu_di_pix_fmt[2];
	bool primary = false, find_1080p = false;
	struct resource *res;
	struct ldb_platform_data *plat_data = pdev->dev.platform_data;
	mm_segment_t old_fs;
	struct clk *ldb_clk_parent;
	unsigned long ldb_clk_prate = 455000000;
	struct fb_var_screeninfo *var[2];
	uint32_t reg;
	struct device *temp;
	int mxc_ldb_major;
	const struct fb_videomode *mode;
	struct class *mxc_ldb_class;

	if (g_enable_ldb == false)
		return -ENODEV;

	spin_lock_init(&ldb_lock);

	g_ldb_dev = &pdev->dev;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (IS_ERR(res))
		return -ENODEV;

	memset(&ldb, 0, sizeof(struct ldb_data));
	enabled[0] = enabled[1] = false;
	var[0] = var[1] = NULL;
	if (g_boot_cmd) {
		ldb.chan_mode_opt = g_chan_mode_opt;
		ldb.chan_bit_map[0] = g_chan_bit_map[0];
		ldb.chan_bit_map[1] = g_chan_bit_map[1];
	}

	ldb.base_addr = res->start;
	ldb_reg = ioremap(ldb.base_addr, res->end - res->start + 1);
	ldb.control_reg = ldb_reg + 2;

	INIT_LIST_HEAD(&ldb.modelist);
	for (i = 0; i < mxcfb_ldb_modedb_sz; i++)
		fb_add_videomode(&mxcfb_ldb_modedb[i], &ldb.modelist);

	for (i = 0; i < num_registered_fb; i++) {
		if ((registered_fb[i]->var.sync & FB_SYNC_EXT) &&
		    (registered_fb[i]->var.vmode == FB_VMODE_NONINTERLACED)) {
			ldb.fbi[i] = registered_fb[i];

			mode = fb_match_mode(&ldb.fbi[i]->var, &ldb.modelist);
			if (mode) {
				dev_dbg(g_ldb_dev, "fb mode found\n");
				fb_videomode_to_var(&ldb.fbi[i]->var, mode);
			} else {
				dev_warn(g_ldb_dev,
						"can't find video mode\n");
				goto err0;
			}
			/*
			 * Default ldb mode:
			 * 1080p: DI0 split, SPWG or DI1 split, SPWG
			 * others: single, SPWG
			 */
			if (g_boot_cmd == false) {
				if (fb_mode_is_equal(mode, &mxcfb_ldb_modedb[0])) {
					if (strcmp(ldb.fbi[i]->fix.id,
					    "DISP3 BG") == 0) {
						ldb.chan_mode_opt = LDB_SPL_DI0;
						dev_warn(g_ldb_dev,
							"default di0 split mode\n");
					} else if (strcmp(ldb.fbi[i]->fix.id,
						   "DISP3 BG - DI1") == 0) {
						ldb.chan_mode_opt = LDB_SPL_DI1;
						dev_warn(g_ldb_dev,
							"default di1 split mode\n");
					}
					ldb.chan_bit_map[0] = LDB_BIT_MAP_SPWG;
					ldb.chan_bit_map[1] = LDB_BIT_MAP_SPWG;
					find_1080p = true;
				} else if (!find_1080p) {
					if (strcmp(ldb.fbi[i]->fix.id,
					    "DISP3 BG") == 0) {
						ldb.chan_mode_opt = LDB_SIN_DI0;
						ldb.chan_bit_map[0] = LDB_BIT_MAP_SPWG;
						dev_warn(g_ldb_dev,
							 "default di0 single mode\n");
					} else if (strcmp(ldb.fbi[i]->fix.id,
						   "DISP3 BG - DI1") == 0) {
						ldb.chan_mode_opt = LDB_SIN_DI1;
						ldb.chan_bit_map[1] = LDB_BIT_MAP_SPWG;
						dev_warn(g_ldb_dev,
							 "default di1 single mode\n");
					}
				}
			}

			acquire_console_sem();
			fb_blank(ldb.fbi[i], FB_BLANK_POWERDOWN);
			release_console_sem();

			if (i == 0)
				primary = true;

			if (ldb.fbi[1] != NULL)
				break;
		}
	}

	/*
	 * We cannot support two LVDS panel with different pixel clock rates
	 * except that one's pixel clock rate is two times of the others'.
	 */
	if (ldb.fbi[1] && ldb.fbi[0] != NULL) {
		if (ldb.fbi[0]->var.pixclock != ldb.fbi[1]->var.pixclock &&
		    ldb.fbi[0]->var.pixclock != 2 * ldb.fbi[1]->var.pixclock &&
		    ldb.fbi[1]->var.pixclock != 2 * ldb.fbi[0]->var.pixclock)
			return -EINVAL;
	}

	ldb.bgref_rmode = plat_data->ext_ref;
	ldb.lvds_bg_reg = regulator_get(&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);
	}

	for (i = 0; i < 2; i++) {
		if (ldb.fbi[i] != NULL) {
			if (strcmp(ldb.fbi[i]->fix.id, "DISP3 BG") == 0)
				ipu_di = 0;
			else if (strcmp(ldb.fbi[i]->fix.id, "DISP3 BG - DI1")
				 == 0)
				ipu_di = 1;
			else {
				dev_err(g_ldb_dev, "Wrong framebuffer\n");
				goto err0;
			}

			var[ipu_di] = &ldb.fbi[i]->var;
			if (ldb.fbi[i]->fbops->fb_ioctl) {
				old_fs = get_fs();
				set_fs(KERNEL_DS);
				ldb.fbi[i]->fbops->fb_ioctl(ldb.fbi[i],
						MXCFB_GET_DIFMT,
						(unsigned long)&(ipu_di_pix_fmt[ipu_di]));
				set_fs(old_fs);
			} else {
				dev_err(g_ldb_dev, "Can't get framebuffer "
						   "information\n");
				goto err0;
			}

			if (!valid_mode(ipu_di_pix_fmt[ipu_di])) {
				dev_err(g_ldb_dev, "Unsupport pixel format "
						   "for ldb input\n");
				goto err0;
			}

			reg = __raw_readl(ldb.control_reg);
			if (var[ipu_di]->sync & FB_SYNC_VERT_HIGH_ACT) {
				if (ipu_di == 0)
					__raw_writel((reg &
						~LDB_DI0_VS_POL_MASK) |
						LDB_DI0_VS_POL_ACT_HIGH,
						ldb.control_reg);
				else
					__raw_writel((reg &
						~LDB_DI1_VS_POL_MASK) |
						LDB_DI1_VS_POL_ACT_HIGH,
						ldb.control_reg);
			} else {
				if (ipu_di == 0)
					__raw_writel((reg &
						~LDB_DI0_VS_POL_MASK) |
						LDB_DI0_VS_POL_ACT_LOW,
						ldb.control_reg);
				else
					__raw_writel((reg &
						~LDB_DI1_VS_POL_MASK) |
						LDB_DI1_VS_POL_ACT_LOW,
						ldb.control_reg);
			}

			/* TODO:Set the correct pll4 rate for all situations */
			if (ipu_di == 1) {
				ldb.ldb_di_clk[1] =
					clk_get(&pdev->dev, "ldb_di1_clk");
				ldb_clk_parent =
					clk_get_parent(ldb.ldb_di_clk[1]);
				clk_set_rate(ldb_clk_parent, ldb_clk_prate);
				clk_put(ldb.ldb_di_clk[1]);
			} else {
				ldb.ldb_di_clk[0] =
					clk_get(&pdev->dev, "ldb_di0_clk");
				ldb_clk_parent =
					clk_get_parent(ldb.ldb_di_clk[0]);
				clk_set_rate(ldb_clk_parent, ldb_clk_prate);
				clk_put(ldb.ldb_di_clk[0]);
			}
		}
	}

	reg = __raw_readl(ldb.control_reg);
	if (ldb.bgref_rmode == LDB_EXT_REF)
		__raw_writel((reg & ~LDB_BGREF_RMODE_MASK) |
			      LDB_BGREF_RMODE_EXT, ldb.control_reg);
	else
		__raw_writel((reg & ~LDB_BGREF_RMODE_MASK) |
			      LDB_BGREF_RMODE_INT, ldb.control_reg);

	switch (ldb.chan_mode_opt) {
	case LDB_SIN_DI0:
		if (var[0] == NULL) {
			dev_err(g_ldb_dev, "Can't find framebuffer on DI0\n");
			break;
		}

		reg = __raw_readl(ldb.control_reg);
		if (bits_per_pixel(ipu_di_pix_fmt[0]) == 24)
			__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
				      LDB_DATA_WIDTH_CH0_24,
				      ldb.control_reg);
		else if (bits_per_pixel(ipu_di_pix_fmt[0]) == 18)
			__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
				      LDB_DATA_WIDTH_CH0_18,
				      ldb.control_reg);

		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
			__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
				      LDB_BIT_MAP_CH0_SPWG,
				      ldb.control_reg);
		else
			__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
				      LDB_BIT_MAP_CH0_JEIDA,
				      ldb.control_reg);

		ldb.ldb_di_clk[0] = clk_get(NULL, "ldb_di0_clk");
		clk_set_rate(ldb.ldb_di_clk[0], ldb_clk_prate/7);
		clk_enable(ldb.ldb_di_clk[0]);
		clk_put(ldb.ldb_di_clk[0]);

		reg = __raw_readl(ldb.control_reg);
		__raw_writel((reg & ~LDB_CH0_MODE_MASK) |
			      LDB_CH0_MODE_EN_TO_DI0, ldb.control_reg);
		ldb.ch_working[0] = true;
		break;
	case LDB_SIN_DI1:
		if (var[1] == NULL) {
			dev_err(g_ldb_dev, "Can't find framebuffer on DI1\n");
			break;
		}

		reg = __raw_readl(ldb.control_reg);
		if (bits_per_pixel(ipu_di_pix_fmt[1]) == 24)
			__raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
				      LDB_DATA_WIDTH_CH1_24,
				      ldb.control_reg);
		else if (bits_per_pixel(ipu_di_pix_fmt[1]) == 18)
			__raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
				      LDB_DATA_WIDTH_CH1_18,
				      ldb.control_reg);

		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
			__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
				      LDB_BIT_MAP_CH1_SPWG,
				      ldb.control_reg);
		else
			__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
				      LDB_BIT_MAP_CH1_JEIDA,
				      ldb.control_reg);

		ldb.ldb_di_clk[1] = clk_get(NULL, "ldb_di1_clk");
		clk_set_rate(ldb.ldb_di_clk[1], ldb_clk_prate/7);
		clk_enable(ldb.ldb_di_clk[1]);
		clk_put(ldb.ldb_di_clk[1]);

		reg = __raw_readl(ldb.control_reg);
		__raw_writel((reg & ~LDB_CH1_MODE_MASK) |
			      LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
		ldb.ch_working[1] = true;
		break;
	case LDB_SEP:
		if (var[0] == NULL || var[1] == NULL) {
			dev_err(g_ldb_dev, "Can't find framebuffers on DI0/1\n");
			break;
		}

		reg = __raw_readl(ldb.control_reg);
		if (bits_per_pixel(ipu_di_pix_fmt[0]) == 24)
			__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
				      LDB_DATA_WIDTH_CH0_24,
				      ldb.control_reg);
		else if (bits_per_pixel(ipu_di_pix_fmt[0]) == 18)
			__raw_writel((reg & ~LDB_DATA_WIDTH_CH0_MASK) |
				      LDB_DATA_WIDTH_CH0_18,
				      ldb.control_reg);
		reg = __raw_readl(ldb.control_reg);
		if (bits_per_pixel(ipu_di_pix_fmt[1]) == 24)
			__raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
				      LDB_DATA_WIDTH_CH1_24,
				      ldb.control_reg);
		else if (bits_per_pixel(ipu_di_pix_fmt[1]) == 18)
			__raw_writel((reg & ~LDB_DATA_WIDTH_CH1_MASK) |
				      LDB_DATA_WIDTH_CH1_18,
				      ldb.control_reg);

		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
			__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
				      LDB_BIT_MAP_CH0_SPWG,
				      ldb.control_reg);
		else
			__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
				      LDB_BIT_MAP_CH0_JEIDA,
				      ldb.control_reg);
		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
			__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
				      LDB_BIT_MAP_CH1_SPWG,
				      ldb.control_reg);
		else
			__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
				      LDB_BIT_MAP_CH1_JEIDA,
				      ldb.control_reg);

		ldb.ldb_di_clk[0] = clk_get(NULL, "ldb_di0_clk");
		clk_set_rate(ldb.ldb_di_clk[0], ldb_clk_prate/7);
		clk_enable(ldb.ldb_di_clk[0]);
		clk_put(ldb.ldb_di_clk[0]);
		ldb.ldb_di_clk[1] = clk_get(NULL, "ldb_di1_clk");
		clk_set_rate(ldb.ldb_di_clk[1], ldb_clk_prate/7);
		clk_enable(ldb.ldb_di_clk[1]);
		clk_put(ldb.ldb_di_clk[1]);

		reg = __raw_readl(ldb.control_reg);
		__raw_writel((reg & ~(LDB_CH0_MODE_MASK |
				      LDB_CH1_MODE_MASK)) |
			      LDB_CH0_MODE_EN_TO_DI0 |
			      LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
		ldb.ch_working[0] = true;
		ldb.ch_working[1] = true;
		break;
	case LDB_DUL_DI0:
	case LDB_SPL_DI0:
		if (var[0] == NULL) {
			dev_err(g_ldb_dev, "Can't find framebuffer on DI0\n");
			break;
		}

		reg = __raw_readl(ldb.control_reg);
		if (bits_per_pixel(ipu_di_pix_fmt[0]) == 24)
			__raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
					      LDB_DATA_WIDTH_CH1_MASK)) |
				      LDB_DATA_WIDTH_CH0_24 |
				      LDB_DATA_WIDTH_CH1_24,
				      ldb.control_reg);
		else if (bits_per_pixel(ipu_di_pix_fmt[0]) == 18)
			__raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
					      LDB_DATA_WIDTH_CH1_MASK)) |
				      LDB_DATA_WIDTH_CH0_18 |
				      LDB_DATA_WIDTH_CH1_18,
				      ldb.control_reg);

		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
			__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
				      LDB_BIT_MAP_CH0_SPWG,
				      ldb.control_reg);
		else
			__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
				      LDB_BIT_MAP_CH0_JEIDA,
				      ldb.control_reg);
		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
			__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
				      LDB_BIT_MAP_CH1_SPWG,
				      ldb.control_reg);
		else
			__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
				      LDB_BIT_MAP_CH1_JEIDA,
				      ldb.control_reg);

		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_mode_opt == LDB_SPL_DI0)
			__raw_writel(reg | LDB_SPLIT_MODE_EN,
				      ldb.control_reg);

		ldb.ldb_di_clk[0] = clk_get(NULL, "ldb_di0_clk");
		ldb.ldb_di_clk[1] = clk_get(NULL, "ldb_di1_clk");
		if (ldb.chan_mode_opt == LDB_DUL_DI0) {
			clk_set_rate(ldb.ldb_di_clk[0], ldb_clk_prate/7);
		} else {
			clk_set_rate(ldb.ldb_di_clk[0], 2*ldb_clk_prate/7);
			clk_set_rate(ldb.ldb_di_clk[1], 2*ldb_clk_prate/7);
		}
		clk_enable(ldb.ldb_di_clk[0]);
		clk_enable(ldb.ldb_di_clk[1]);
		clk_put(ldb.ldb_di_clk[0]);
		clk_put(ldb.ldb_di_clk[1]);

		reg = __raw_readl(ldb.control_reg);
		__raw_writel((reg & ~(LDB_CH0_MODE_MASK |
				      LDB_CH1_MODE_MASK)) |
			      LDB_CH0_MODE_EN_TO_DI0 |
			      LDB_CH1_MODE_EN_TO_DI0, ldb.control_reg);
		ldb.ch_working[0] = true;
		ldb.ch_working[1] = true;
		break;
	case LDB_DUL_DI1:
	case LDB_SPL_DI1:
		if (var[1] == NULL) {
			dev_err(g_ldb_dev, "Can't find framebuffer on DI1\n");
			break;
		}

		reg = __raw_readl(ldb.control_reg);
		if (bits_per_pixel(ipu_di_pix_fmt[1]) == 24)
			__raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
					      LDB_DATA_WIDTH_CH1_MASK)) |
				      LDB_DATA_WIDTH_CH0_24 |
				      LDB_DATA_WIDTH_CH1_24,
				      ldb.control_reg);
		else if (bits_per_pixel(ipu_di_pix_fmt[1]) == 18)
			__raw_writel((reg & ~(LDB_DATA_WIDTH_CH0_MASK |
					      LDB_DATA_WIDTH_CH1_MASK)) |
				      LDB_DATA_WIDTH_CH0_18 |
				      LDB_DATA_WIDTH_CH1_18,
				      ldb.control_reg);

		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_bit_map[0] == LDB_BIT_MAP_SPWG)
			__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
				      LDB_BIT_MAP_CH0_SPWG,
				      ldb.control_reg);
		else
			__raw_writel((reg & ~LDB_BIT_MAP_CH0_MASK) |
				      LDB_BIT_MAP_CH0_JEIDA,
				      ldb.control_reg);
		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_bit_map[1] == LDB_BIT_MAP_SPWG)
			__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
				      LDB_BIT_MAP_CH1_SPWG,
				      ldb.control_reg);
		else
			__raw_writel((reg & ~LDB_BIT_MAP_CH1_MASK) |
				      LDB_BIT_MAP_CH1_JEIDA,
				      ldb.control_reg);

		reg = __raw_readl(ldb.control_reg);
		if (ldb.chan_mode_opt == LDB_SPL_DI1)
			__raw_writel(reg | LDB_SPLIT_MODE_EN,
				      ldb.control_reg);

		ldb.ldb_di_clk[0] = clk_get(NULL, "ldb_di0_clk");
		ldb.ldb_di_clk[1] = clk_get(NULL, "ldb_di1_clk");
		if (ldb.chan_mode_opt == LDB_DUL_DI1) {
			clk_set_rate(ldb.ldb_di_clk[1], ldb_clk_prate/7);
		} else {
			clk_set_rate(ldb.ldb_di_clk[0], 2*ldb_clk_prate/7);
			clk_set_rate(ldb.ldb_di_clk[1], 2*ldb_clk_prate/7);
		}
		clk_enable(ldb.ldb_di_clk[0]);
		clk_enable(ldb.ldb_di_clk[1]);
		clk_put(ldb.ldb_di_clk[0]);
		clk_put(ldb.ldb_di_clk[1]);

		reg = __raw_readl(ldb.control_reg);
		__raw_writel((reg & ~(LDB_CH0_MODE_MASK |
				      LDB_CH1_MODE_MASK)) |
			      LDB_CH0_MODE_EN_TO_DI1 |
			      LDB_CH1_MODE_EN_TO_DI1, ldb.control_reg);
		ldb.ch_working[0] = true;
		ldb.ch_working[1] = true;
		break;
	default:
		break;
	}

	mxc_ldb_major = register_chrdev(0, "mxc_ldb", &mxc_ldb_fops);
	if (mxc_ldb_major < 0) {
		dev_err(g_ldb_dev, "Unable to register MXC LDB as a char "
				   "device\n");
		ret = mxc_ldb_major;
		goto err0;
	}

	mxc_ldb_class = class_create(THIS_MODULE, "mxc_ldb");
	if (IS_ERR(mxc_ldb_class)) {
		dev_err(g_ldb_dev, "Unable to create class for MXC LDB\n");
		ret = PTR_ERR(mxc_ldb_class);
		goto err1;
	}

	temp = device_create(mxc_ldb_class, NULL, MKDEV(mxc_ldb_major, 0),
			NULL, "mxc_ldb");
	if (IS_ERR(temp)) {
		dev_err(g_ldb_dev, "Unable to create class device for "
				   "MXC LDB\n");
		ret = PTR_ERR(temp);
		goto err2;
	}

	ret = fb_register_client(&nb);
	if (ret < 0)
		goto err2;

	if (primary && ldb.fbi[0] != NULL) {
		acquire_console_sem();
		fb_blank(ldb.fbi[0], FB_BLANK_UNBLANK);
		release_console_sem();
		fb_show_logo(ldb.fbi[0], 0);
	}

	return ret;
err2:
	class_destroy(mxc_ldb_class);
err1:
	unregister_chrdev(mxc_ldb_major, "mxc_ldb");
err0:
	iounmap(ldb_reg);
	return ret;
}
コード例 #16
0
static int sh_hdmi_read_edid(struct sh_hdmi *hdmi)
{
	struct fb_var_screeninfo tmpvar;
	struct fb_var_screeninfo *var = &tmpvar;
	const struct fb_videomode *mode, *found = NULL;
	struct fb_info *info = hdmi->info;
	struct fb_modelist *modelist = NULL;
	unsigned int f_width = 0, f_height = 0, f_refresh = 0;
	unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */
	bool exact_match = false;
	u8 edid[128];
	char *forced;
	int i;

	/* Read EDID */
	dev_dbg(hdmi->dev, "Read back EDID code:");
	for (i = 0; i < 128; i++) {
		edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW);
#ifdef DEBUG
		if ((i % 16) == 0) {
			printk(KERN_CONT "\n");
			printk(KERN_DEBUG "%02X | %02X", i, edid[i]);
		} else {
			printk(KERN_CONT " %02X", edid[i]);
		}
#endif
	}
#ifdef DEBUG
	printk(KERN_CONT "\n");
#endif

	fb_edid_to_monspecs(edid, &hdmi->monspec);

	fb_get_options("sh_mobile_lcdc", &forced);
	if (forced && *forced) {
		/* Only primitive parsing so far */
		i = sscanf(forced, "%ux%u@%u",
			   &f_width, &f_height, &f_refresh);
		if (i < 2) {
			f_width = 0;
			f_height = 0;
		}
		dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n",
			f_width, f_height, f_refresh);
	}

	/* Walk monitor modes to find the best or the exact match */
	for (i = 0, mode = hdmi->monspec.modedb;
	     f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match;
	     i++, mode++) {
		unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode);

		/* No interest in unmatching modes */
		if (f_width != mode->xres || f_height != mode->yres)
			continue;
		if (f_refresh == mode->refresh || (!f_refresh && !rate_error))
			/*
			 * Exact match if either the refresh rate matches or it
			 * hasn't been specified and we've found a mode, for
			 * which we can configure the clock precisely
			 */
			exact_match = true;
		else if (found && found_rate_error <= rate_error)
			/*
			 * We otherwise search for the closest matching clock
			 * rate - either if no refresh rate has been specified
			 * or we cannot find an exactly matching one
			 */
			continue;

		/* Check if supported: sufficient fb memory, supported clock-rate */
		fb_videomode_to_var(var, mode);

		if (info && info->fbops->fb_check_var &&
		    info->fbops->fb_check_var(var, info)) {
			exact_match = false;
			continue;
		}

		found = mode;
		found_rate_error = rate_error;
	}

	/*
	 * TODO 1: if no ->info is present, postpone running the config until
	 * after ->info first gets registered.
	 * TODO 2: consider registering the HDMI platform device from the LCDC
	 * driver, and passing ->info with HDMI platform data.
	 */
	if (info && !found) {
		modelist = hdmi->info->modelist.next &&
			!list_empty(&hdmi->info->modelist) ?
			list_entry(hdmi->info->modelist.next,
				   struct fb_modelist, list) :
			NULL;

		if (modelist) {
			found = &modelist->mode;
			found_rate_error = sh_hdmi_rate_error(hdmi, found);
		}
	}
コード例 #17
0
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);
}
コード例 #18
0
/*
 * Probe routine for the framebuffer driver. It is called during the
 * driver binding process.      The following functions are performed in
 * this routine: Framebuffer initialization, Memory allocation and
 * mapping, Framebuffer registration, IPU initialization.
 *
 * @return      Appropriate error code to the kernel common code
 */
static int mxcfb_probe(u32 interface_pix_fmt, struct fb_videomode *mode, int di)
{
	struct fb_info *fbi;
	struct mxcfb_info *mxcfbi;

	/*
	 * Initialize FB structures
	 */
	fbi = mxcfb_init_fbinfo();
	if (!fbi)
		return -ENOMEM;

	mxcfbi = fbi->par;

	if (!g_dp_in_use) {
		mxcfbi->ipu_ch = MEM_BG_SYNC;
		mxcfbi->blank = FB_BLANK_UNBLANK;
	} else {
		mxcfbi->ipu_ch = MEM_DC_SYNC;
		mxcfbi->blank = FB_BLANK_POWERDOWN;
	}

	mxcfbi->ipu_di = di;

	ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
	ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
	strcpy(fbi->fix.id, "DISP3 BG");

	g_dp_in_use = 1;

	mxcfb_info[mxcfbi->ipu_di] = fbi;

	/* Need dummy values until real panel is configured */
	fbi->var.xres = panel_info.vl_col;
	fbi->var.yres = panel_info.vl_row;

	mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
	fb_videomode_to_var(&fbi->var, mode);
	fbi->var.bits_per_pixel = NBITS(panel_info.vl_bpix);
	fbi->fix.line_length = fbi->var.xres * (fbi->var.bits_per_pixel / 8);
	fbi->fix.smem_len = fbi->var.yres_virtual * fbi->fix.line_length;

	mxcfb_check_var(&fbi->var, fbi);
	mxcfb_set_fix(fbi);

	/* allocate fb first */
	if (mxcfb_map_video_memory(fbi) < 0)
		return -ENOMEM;

	mxcfb_set_par(fbi);

	lcd_line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;

	debug("MXC IPUV3 configured\n"
		"XRES = %d YRES = %d BitsXpixel = %d\n",
		panel_info.vl_col,
		panel_info.vl_row,
		panel_info.vl_bpix);

	ipu_dump_registers();

	return 0;
}
コード例 #19
0
/**
 * 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;
}
コード例 #20
0
static int adv739x_disp_init(struct mxc_dispdrv_handle *disp,
	struct mxc_dispdrv_setting *setting)
{
	int ret = 0, i;
	struct adv739x_data *adv739x = mxc_dispdrv_getdata(disp);
	struct fsl_mxc_lcd_platform_data *plat = adv739x->client->dev.platform_data;
	struct fb_videomode *modedb = adv739x_modedb;
	int modedb_sz = adv739x_modedb_sz;
	static bool inited = false;

	if (inited)
		return -EBUSY;

	inited = true;

	setting->dev_id = plat->ipu_id;
	setting->disp_id = plat->disp_id;

	{
		struct clk *di_parent;
		struct clk *di;
		char di_clk[] = "ipu1_di0_clk";

		di_clk[3] += setting->dev_id;
		di_clk[7] += setting->disp_id;
		di = clk_get(NULL, di_clk);
		if (IS_ERR(di)) {
			pr_err("%s: clock %s not found\n", __func__, di_clk);
		}
		di_parent = clk_get(NULL, "pll3_pfd_540M");
		if (IS_ERR(di_parent)) {
			pr_err("%s: clock pll3_pfd_540M not found\n", __func__);
		}
		clk_set_parent(di, di_parent);
		clk_set_rate(di, 540000000/5);
		clk_enable(di_parent);
	}
	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->default_ifmt;
		adv739x->ifmt = plat->default_ifmt;
	}

	INIT_LIST_HEAD(&setting->fbi->modelist);
	for (i = 0; i < modedb_sz; i++) {
		fb_add_videomode(&modedb[i],
				&setting->fbi->modelist);
	}

	adv739x->fbi = setting->fbi;
	adv739x->enabled = 0;
	adv739x->cur_mode = ADV739X_MODE_NTSC;  //default mode

	adv739x->pdev = platform_device_register_simple("mxc_adv739x", 0, NULL, 0);
	if (IS_ERR(adv739x->pdev)) {
		dev_err(&adv739x->client->dev,
				"Unable to register adv739x as a platform device\n");
		ret = PTR_ERR(adv739x->pdev);
		goto register_pltdev_failed;
	}

	/* Claim pins */
	if (plat->get_pins)
		if (!plat->get_pins()) {
			ret = -EACCES;
			goto get_pins_failed;
		}

	adv739x->nb.notifier_call = adv739x_fb_event;
	ret = fb_register_client(&adv739x->nb);
	if (ret < 0)
		goto reg_fbclient_failed;

	return ret;

reg_fbclient_failed:
get_pins_failed:
	platform_device_unregister(adv739x->pdev);
register_pltdev_failed:
	return ret;
}
コード例 #21
0
/**
 * s3c_fb_probe_win() - register an hardware window
 * @sfb: The base resources for the hardware
 * @res: Pointer to where to place the resultant window.
 *
 * Allocate and do the basic initialisation for one of the hardware's graphics
 * windows.
 */
static int __devinit s3c_fb_probe_win(struct s3c_fb *sfb, unsigned int win_no,
				      struct s3c_fb_win **res)
{
	struct fb_var_screeninfo *var;
	struct fb_videomode *initmode;
	struct s3c_fb_pd_win *windata;
	struct s3c_fb_win *win;
	struct fb_info *fbinfo;
	int palette_size;
	int ret;

	dev_dbg(sfb->dev, "probing window %d\n", win_no);

	palette_size = s3c_fb_win_pal_size(win_no);

	fbinfo = framebuffer_alloc(sizeof(struct s3c_fb_win) +
				   palette_size * sizeof(u32), sfb->dev);
	if (!fbinfo) {
		dev_err(sfb->dev, "failed to allocate framebuffer\n");
		return -ENOENT;
	}

	windata = sfb->pdata->win[win_no];
	initmode = &windata->win_mode;

	WARN_ON(windata->max_bpp == 0);
	WARN_ON(windata->win_mode.xres == 0);
	WARN_ON(windata->win_mode.yres == 0);

	win = fbinfo->par;
	var = &fbinfo->var;
	win->fbinfo = fbinfo;
	win->parent = sfb;
	win->windata = windata;
	win->index = win_no;
	win->palette_buffer = (u32 *)(win + 1);

	ret = s3c_fb_alloc_memory(sfb, win);
	if (ret) {
		dev_err(sfb->dev, "failed to allocate display memory\n");
		return ret;
	}

	/* setup the r/b/g positions for the window's palette */
	s3c_fb_init_palette(win_no, &win->palette);

	/* setup the initial video mode from the window */
	fb_videomode_to_var(&fbinfo->var, initmode);

	fbinfo->fix.type	= FB_TYPE_PACKED_PIXELS;
	fbinfo->fix.accel	= FB_ACCEL_NONE;
	fbinfo->var.activate	= FB_ACTIVATE_NOW;
	fbinfo->var.vmode	= FB_VMODE_NONINTERLACED;
	fbinfo->var.bits_per_pixel = windata->default_bpp;
	fbinfo->fbops		= &s3c_fb_ops;
	fbinfo->flags		= FBINFO_FLAG_DEFAULT;
	fbinfo->pseudo_palette  = &win->pseudo_palette;

	/* prepare to actually start the framebuffer */

	ret = s3c_fb_check_var(&fbinfo->var, fbinfo);
	if (ret < 0) {
		dev_err(sfb->dev, "check_var failed on initial video params\n");
		return ret;
	}

	/* create initial colour map */

	ret = fb_alloc_cmap(&fbinfo->cmap, s3c_fb_win_pal_size(win_no), 1);
	if (ret == 0)
		fb_set_cmap(&fbinfo->cmap, fbinfo);
	else
		dev_err(sfb->dev, "failed to allocate fb cmap\n");

	s3c_fb_set_par(fbinfo);

	dev_dbg(sfb->dev, "about to register framebuffer\n");

	/* run the check_var and set_par on our configuration. */

	ret = register_framebuffer(fbinfo);
	if (ret < 0) {
		dev_err(sfb->dev, "failed to register framebuffer\n");
		return ret;
	}

	*res = win;
	dev_info(sfb->dev, "window %d: fb %s\n", win_no, fbinfo->fix.id);

	return 0;
}
コード例 #22
0
ファイル: mxc_ipuv3_fb.c プロジェクト: Aorjoa/bootloader
/*
 * Probe routine for the framebuffer driver. It is called during the
 * driver binding process.      The following functions are performed in
 * this routine: Framebuffer initialization, Memory allocation and
 * mapping, Framebuffer registration, IPU initialization.
 *
 * @return      Appropriate error code to the kernel common code
 */
static int mxcfb_probe(u32 interface_pix_fmt, struct fb_videomode *mode)
{
	struct fb_info *fbi;
	struct mxcfb_info *mxcfbi;
	int ret = 0;

	/*
	 * Initialize FB structures
	 */
	fbi = mxcfb_init_fbinfo();
	if (!fbi) {
		ret = -ENOMEM;
		goto err0;
	}
	mxcfbi = (struct mxcfb_info *)fbi->par;

	if (!g_dp_in_use) {
		mxcfbi->ipu_ch = MEM_BG_SYNC;
		mxcfbi->blank = FB_BLANK_UNBLANK;
	} else {
		mxcfbi->ipu_ch = MEM_DC_SYNC;
		mxcfbi->blank = FB_BLANK_POWERDOWN;
	}

	mxcfbi->ipu_di = 0;

	ipu_disp_set_global_alpha(mxcfbi->ipu_ch, 1, 0x80);
	ipu_disp_set_color_key(mxcfbi->ipu_ch, 0, 0);
	strcpy(fbi->fix.id, "DISP3 BG");

	g_dp_in_use = 1;

	mxcfb_info[mxcfbi->ipu_di] = fbi;

	/* Need dummy values until real panel is configured */
	fbi->var.xres = 640;
	fbi->var.yres = 480;
	fbi->var.bits_per_pixel = 16;

	mxcfbi->ipu_di_pix_fmt = interface_pix_fmt;
	fb_videomode_to_var(&fbi->var, mode);

	mxcfb_check_var(&fbi->var, fbi);

	/* Default Y virtual size is 2x panel size */
	fbi->var.yres_virtual = fbi->var.yres * 2;

	mxcfb_set_fix(fbi);

	/* alocate fb first */
	if (mxcfb_map_video_memory(fbi) < 0)
		return -ENOMEM;

	mxcfb_set_par(fbi);

	/* Setting panel_info for lcd */
	panel_info.cmap = NULL;
	panel_info.vl_col = fbi->var.xres;
	panel_info.vl_row = fbi->var.yres;
	panel_info.vl_bpix = LCD_BPP;

	lcd_line_length = (panel_info.vl_col * NBITS(panel_info.vl_bpix)) / 8;

	debug("MXC IPUV3 configured\n"
		"XRES = %d YRES = %d BitsXpixel = %d\n",
		panel_info.vl_col,
		panel_info.vl_row,
		panel_info.vl_bpix);

	ipu_dump_registers();

	return 0;

err0:
	return ret;
}
コード例 #23
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;
	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;
}
コード例 #24
0
static int __devinit wm8505fb_probe(struct platform_device *pdev)
{
	struct wm8505fb_info	*fbi;
	struct resource		*res;
	void			*addr;
	struct vt8500fb_platform_data *pdata;
	int ret;

	pdata = pdev->dev.platform_data;

	ret = -ENOMEM;
	fbi = NULL;

	fbi = kzalloc(sizeof(struct wm8505fb_info) + sizeof(u32) * 16,
							GFP_KERNEL);
	if (!fbi) {
		dev_err(&pdev->dev, "Failed to initialize framebuffer device\n");
		ret = -ENOMEM;
		goto failed;
	}

	strcpy(fbi->fb.fix.id, DRIVER_NAME);

	fbi->fb.fix.type	= FB_TYPE_PACKED_PIXELS;
	fbi->fb.fix.xpanstep	= 1;
	fbi->fb.fix.ypanstep	= 1;
	fbi->fb.fix.ywrapstep	= 0;
	fbi->fb.fix.accel	= FB_ACCEL_NONE;

	fbi->fb.fbops		= &wm8505fb_ops;
	fbi->fb.flags		= FBINFO_DEFAULT
				| FBINFO_HWACCEL_COPYAREA
				| FBINFO_HWACCEL_FILLRECT
				| FBINFO_HWACCEL_XPAN
				| FBINFO_HWACCEL_YPAN
				| FBINFO_VIRTFB
				| FBINFO_PARTIAL_PAN_OK;
	fbi->fb.node		= -1;

	addr = fbi;
	addr = addr + sizeof(struct wm8505fb_info);
	fbi->fb.pseudo_palette	= addr;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL) {
		dev_err(&pdev->dev, "no I/O memory resource defined\n");
		ret = -ENODEV;
		goto failed_fbi;
	}

	res = request_mem_region(res->start, resource_size(res), DRIVER_NAME);
	if (res == NULL) {
		dev_err(&pdev->dev, "failed to request I/O memory\n");
		ret = -EBUSY;
		goto failed_fbi;
	}

	fbi->regbase = ioremap(res->start, resource_size(res));
	if (fbi->regbase == NULL) {
		dev_err(&pdev->dev, "failed to map I/O memory\n");
		ret = -EBUSY;
		goto failed_free_res;
	}

	fb_videomode_to_var(&fbi->fb.var, &pdata->mode);

	fbi->fb.var.nonstd		= 0;
	fbi->fb.var.activate		= FB_ACTIVATE_NOW;

	fbi->fb.var.height		= -1;
	fbi->fb.var.width		= -1;
	fbi->fb.var.xres_virtual	= pdata->xres_virtual;
	fbi->fb.var.yres_virtual	= pdata->yres_virtual;
	fbi->fb.var.bits_per_pixel	= pdata->bpp;

	fbi->fb.fix.smem_start	= pdata->video_mem_phys;
	fbi->fb.fix.smem_len	= pdata->video_mem_len;
	fbi->fb.screen_base	= pdata->video_mem_virt;
	fbi->fb.screen_size	= pdata->video_mem_len;

	if (fb_alloc_cmap(&fbi->fb.cmap, 256, 0) < 0) {
		dev_err(&pdev->dev, "Failed to allocate color map\n");
		ret = -ENOMEM;
		goto failed_free_io;
	}

	wm8505fb_init_hw(&fbi->fb);

	fbi->contrast = 0x80;
	ret = wm8505fb_set_par(&fbi->fb);
	if (ret) {
		dev_err(&pdev->dev, "Failed to set parameters\n");
		goto failed_free_cmap;
	}

	platform_set_drvdata(pdev, fbi);

	ret = register_framebuffer(&fbi->fb);
	if (ret < 0) {
		dev_err(&pdev->dev,
			"Failed to register framebuffer device: %d\n", ret);
		goto failed_free_cmap;
	}

	ret = device_create_file(&pdev->dev, &dev_attr_contrast);
	if (ret < 0) {
		printk(KERN_WARNING "fb%d: failed to register attributes (%d)\n",
			fbi->fb.node, ret);
	}

	printk(KERN_INFO "fb%d: %s frame buffer at 0x%lx-0x%lx\n",
	       fbi->fb.node, fbi->fb.fix.id, fbi->fb.fix.smem_start,
	       fbi->fb.fix.smem_start + fbi->fb.fix.smem_len - 1);

	return 0;

failed_free_cmap:
	if (fbi->fb.cmap.len)
		fb_dealloc_cmap(&fbi->fb.cmap);
failed_free_io:
	iounmap(fbi->regbase);
failed_free_res:
	release_mem_region(res->start, resource_size(res));
failed_fbi:
	platform_set_drvdata(pdev, NULL);
	kfree(fbi);
failed:
	return ret;
}
コード例 #25
0
ファイル: ldb.c プロジェクト: AvalueAES/rev-sa01
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;
}
コード例 #26
0
static
PVRSRV_ERROR DC_FBDEV_PanelQuery(IMG_HANDLE hDeviceData,
								 IMG_UINT32 ui32PanelsArraySize,
								 IMG_UINT32 *pui32NumPanels,
								 PVRSRV_PANEL_INFO *psPanelInfo)
{
	DC_FBDEV_DEVICE *psDeviceData = hDeviceData;
	struct fb_var_screeninfo *psVar = &psDeviceData->psLINFBInfo->var;
	struct fb_var_screeninfo sVar = { .pixclock = 0 };

	if(!lock_fb_info(psDeviceData->psLINFBInfo))
		return PVRSRV_ERROR_RETRY;

	*pui32NumPanels = 1;

	psPanelInfo[0].sSurfaceInfo.sFormat.ePixFormat = psDeviceData->ePixFormat;
	psPanelInfo[0].sSurfaceInfo.sDims.ui32Width    = psVar->xres;
	psPanelInfo[0].sSurfaceInfo.sDims.ui32Height   = psVar->yres;
	psPanelInfo[0].sSurfaceInfo.sFormat.eMemLayout = PVRSRV_SURFACE_MEMLAYOUT_STRIDED;
	psPanelInfo[0].sSurfaceInfo.sFormat.u.sFBCLayout.eFBCompressionMode = FB_COMPRESSION_NONE;

	/* Conformant fbdev drivers should have `var' and mode in sync by now,
	 * but some don't (like drmfb), so try a couple of different ways to
	 * get the info before falling back to the default.
	 */
	if(psVar->xres > 0 && psVar->yres > 0 && psVar->pixclock > 0)
		sVar = *psVar;
	else if(psDeviceData->psLINFBInfo->mode)
		fb_videomode_to_var(&sVar, psDeviceData->psLINFBInfo->mode);

	/* Override the refresh rate when defined. */
#ifdef DC_FBDEV_REFRESH
	psPanelInfo[0].ui32RefreshRate = DC_FBDEV_REFRESH;
#else
	if(sVar.xres > 0 && sVar.yres > 0 && sVar.pixclock > 0)
	{
		psPanelInfo[0].ui32RefreshRate = 1000000000LU /
			((sVar.upper_margin + sVar.lower_margin +
			  sVar.yres + sVar.vsync_len) *
			 (sVar.left_margin  + sVar.right_margin +
			  sVar.xres + sVar.hsync_len) *
			 (sVar.pixclock / 1000));
	}
	else
		psPanelInfo[0].ui32RefreshRate = FALLBACK_REFRESH_RATE;
#endif

	/* MTK: fixme */
	if (psPanelInfo[0].ui32RefreshRate == 0)
		psPanelInfo[0].ui32RefreshRate = FALLBACK_REFRESH_RATE;

	psPanelInfo[0].ui32XDpi =
		((int)sVar.width > 0) ? (254000 / sVar.width * psVar->xres / 10000) : FALLBACK_DPI;

	psPanelInfo[0].ui32YDpi	=
		((int)sVar.height > 0) ? 254000 / sVar.height * psVar->yres / 10000 : FALLBACK_DPI;

	unlock_fb_info(psDeviceData->psLINFBInfo);
	return PVRSRV_OK;
}

static
PVRSRV_ERROR DC_FBDEV_FormatQuery(IMG_HANDLE hDeviceData,
								  IMG_UINT32 ui32NumFormats,
								  PVRSRV_SURFACE_FORMAT *pasFormat,
								  IMG_UINT32 *pui32Supported)
{
	DC_FBDEV_DEVICE *psDeviceData = hDeviceData;
	int i;

	for(i = 0; i < ui32NumFormats; i++)
	{
		pui32Supported[i] = 0;

		if(pasFormat[i].ePixFormat == psDeviceData->ePixFormat)
			pui32Supported[i]++;
	}

	return PVRSRV_OK;
}