Exemplo n.º 1
0
static int xylonfb_of_probe(struct platform_device *pdev)
{
	struct xylonfb_init_data init_data;
	int i, rc;

	driver_devel("%s\n", __func__);

	memset(&init_data, 0, sizeof(struct xylonfb_init_data));

	init_data.pdev = pdev;

	rc = xylonfb_parse_hw_info(pdev->dev.of_node, &init_data);
	if (rc)
		return rc;
	rc = xylonfb_parse_vram_info(pdev->dev.of_node,
		&init_data.vmem_base_addr, &init_data.vmem_high_addr);
	if (rc)
		return rc;
	rc = xylonfb_parse_layer_info(pdev->dev.of_node, &init_data);
	if (rc)
		return rc;
	/* if Device-Tree contains video mode options do not use
	   kernel command line video mode options */
	xylonfb_parse_vmode_info(pdev->dev.of_node, &init_data);

	for (i = 0; i < init_data.layers; i++) {
		rc = xylonfb_parse_layer_params(pdev->dev.of_node, i,
			&init_data.lfdata[i]);
		if (rc)
			return rc;
	}

	return xylonfb_init_driver(&init_data);
}
Exemplo n.º 2
0
static void xylonfb_adv7511_set_v4l2_timings(struct v4l2_subdev *sd,
	struct fb_var_screeninfo *var)
{
	struct v4l2_dv_timings dv_timings;

	driver_devel("%s\n", __func__);

	dv_timings.type = V4L2_DV_BT_656_1120;

	dv_timings.bt.width = var->xres;
	dv_timings.bt.height = var->yres;
	dv_timings.bt.interlaced = 0;
	dv_timings.bt.polarities = 0;
	if (var->sync & FB_SYNC_VERT_HIGH_ACT)
		dv_timings.bt.polarities |= V4L2_DV_VSYNC_POS_POL;
	if (var->sync & FB_SYNC_HOR_HIGH_ACT)
		dv_timings.bt.polarities |= V4L2_DV_HSYNC_POS_POL;
	dv_timings.bt.pixelclock = (__u64)PICOS2KHZ(var->pixclock) * 1000;
	dv_timings.bt.hfrontporch = var->right_margin;
	dv_timings.bt.hsync = var->hsync_len;
	dv_timings.bt.hbackporch = var->left_margin;
	dv_timings.bt.vfrontporch = var->lower_margin;
	dv_timings.bt.vsync = var->vsync_len;
	dv_timings.bt.vbackporch = var->upper_margin;
	dv_timings.bt.il_vfrontporch = 0;
	dv_timings.bt.il_vsync = 0;
	dv_timings.bt.il_vbackporch = 0;
	dv_timings.bt.standards = 0;
	dv_timings.bt.standards = V4L2_DV_BT_STD_DMT | V4L2_DV_BT_STD_CEA861;
	dv_timings.bt.flags = 0;

	sd->ops->video->s_dv_timings(sd, &dv_timings);
}
Exemplo n.º 3
0
void xylonfb_adv7511_unregister(struct fb_info *fbi)
{
	struct i2c_client *client = v4l2_get_subdevdata(xfb_adv7511->sd);
	struct xylonfb_layer_data *ld = fbi->par;
	struct xylonfb_common_data *cd = ld->xylonfb_cd;
	struct xylonfb_misc_data *misc_data = cd->xylonfb_misc;

	driver_devel("%s\n", __func__);

	if (!xfb_adv7511)
		return;

	free_irq(client->irq, xfb_adv7511);
	flush_work(&xfb_adv7511->irq_work);
	flush_workqueue(xfb_adv7511->irq_work_queue);
	destroy_workqueue(xfb_adv7511->irq_work_queue);

	kfree(xfb_adv7511->monspecs);
	kfree(xfb_adv7511->var_screeninfo);
	misc_data->monspecs = NULL;
	misc_data->var_screeninfo = NULL;

	v4l2_device_unregister(&xfb_adv7511->v4l2_dev);

	kfree(xfb_adv7511);
	xfb_adv7511 = NULL;
}
Exemplo n.º 4
0
static int xylonfb_parse_hw_info(struct device_node *np,
	struct xylonfb_init_data *init_data)
{
	u32 const *prop;
	int size;

	driver_devel("%s\n", __func__);

	prop = of_get_property(np, "xlnx,display-interface", &size);
	if (!prop) {
		pr_err("Error xylonfb getting display interface\n");
		return -EINVAL;
	}
	init_data->display_interface_type = be32_to_cpup(prop) << 4;

	prop = of_get_property(np, "xlnx,display-color-space", &size);
	if (!prop) {
		pr_err("Error xylonfb getting display color space\n");
		return -EINVAL;
	}
	init_data->display_interface_type |= be32_to_cpup(prop);

	prop = of_get_property(np, "xlnx,readable-regs", &size);
	if (!prop) {
		pr_warn("xylonfb registers not readable\n");
	} else {
		if (be32_to_cpup(prop))
			init_data->flags |= LOGICVC_READABLE_REGS;
	}

	return 0;
}
Exemplo n.º 5
0
static int xylonfb_adv7511_update(struct fb_info *fbi)
{
	struct xylonfb_layer_data *ld = fbi->par;
	struct xylonfb_misc_data *misc_data =
		ld->xylonfb_cd->xylonfb_misc;
	int ret;

	driver_devel("%s\n", __func__);

	fbi->monspecs = *(misc_data->monspecs);

	console_lock();
	misc_data->var_screeninfo->xres_virtual = fbi->var.xres_virtual;
	misc_data->var_screeninfo->yres_virtual = fbi->var.yres_virtual;
	misc_data->var_screeninfo->xoffset = fbi->var.xoffset;
	misc_data->var_screeninfo->yoffset = fbi->var.yoffset;
	misc_data->var_screeninfo->bits_per_pixel = fbi->var.bits_per_pixel;
	fbi->flags |= FBINFO_MISC_USEREVENT;
	misc_data->var_screeninfo->activate |= FB_ACTIVATE_ALL;
	ret = fb_set_var(fbi, misc_data->var_screeninfo);
	misc_data->var_screeninfo->activate &= ~FB_ACTIVATE_ALL;
	console_unlock();

	return ret;
}
Exemplo n.º 6
0
static void xylonfb_misc_adv7511(struct fb_info *fbi, bool init)
{
	struct xylonfb_layer_data *ld = fbi->par;
	struct xylonfb_common_data *cd = ld->xylonfb_cd;
	struct xylonfb_misc_data *misc_data = cd->xylonfb_misc;

	driver_devel("%s\n", __func__);

	if (cd->xylonfb_flags & XYLONFB_FLAG_ADV7511_SKIP)
		return;

	if (init) {
		if (cd->xylonfb_flags & XYLONFB_FLAG_MISC_ADV7511)
			return;

		if (!xylonfb_adv7511_register(fbi)) {
			fbi->monspecs = *(misc_data->monspecs);
			cd->xylonfb_flags |= XYLONFB_FLAG_MISC_ADV7511;
		} else {
			pr_warn("Warning xylonfb ADV7511 already initialized\n");
		}
	} else {
		xylonfb_adv7511_unregister(fbi);
		cd->xylonfb_flags &= ~XYLONFB_FLAG_MISC_ADV7511;
	}
}
Exemplo n.º 7
0
static void xylonfb_misc_init_wait(struct fb_info *fbi)
{
	struct xylonfb_layer_data *ld = fbi->par;

	driver_devel("%s\n", __func__);

	init_waitqueue_head(&ld->xylonfb_cd->xylonfb_misc->wait);
}
Exemplo n.º 8
0
static irqreturn_t xylonfb_adv7511_isr(int irq, void *dev_id)
{
	struct xylonfb_adv7511 *xfb_adv7511 = dev_id;

	driver_devel("%s\n", __func__);

	queue_work(xfb_adv7511->irq_work_queue, &xfb_adv7511->irq_work);

	return IRQ_HANDLED;
}
Exemplo n.º 9
0
static void xylonfb_adv7511_handler(struct work_struct *work)
{
	struct xylonfb_adv7511 *xfb_adv7511 =
		container_of(work, struct xylonfb_adv7511, irq_work);

	driver_devel("%s\n", __func__);

	xfb_adv7511->sd->ops->core->interrupt_service_routine(
		xfb_adv7511->sd, 0, NULL);
}
Exemplo n.º 10
0
static int xylonfb_parse_layer_info(struct device_node *np,
	struct xylonfb_init_data *init_data)
{
	u32 const *prop;
	unsigned int layers, bg_bpp, bg_alpha_mode;
	int size;
	char bg_layer_name[25];

	driver_devel("%s\n", __func__);

	prop = of_get_property(np, "xlnx,num-of-layers", &size);
	if (!prop) {
		pr_err("Error getting number of layers\n");
		return -EINVAL;
	}
	layers = be32_to_cpup(prop);

	bg_bpp = 0;
	bg_alpha_mode = 0;
	prop = of_get_property(np, "xlnx,use-background", &size);
	if (!prop) {
		pr_warn("xylonfb no BG layer\n");
	} else {
		if (be32_to_cpup(prop) == 1) {
			layers--;

			sprintf(bg_layer_name, "xlnx,layer-%d-data-width", layers);
			prop = of_get_property(np, bg_layer_name, &size);
			if (!prop)
				bg_bpp = 16;
			else
				bg_bpp = be32_to_cpup(prop);
			if (bg_bpp == 24)
				bg_bpp = 32;

			sprintf(bg_layer_name, "xlnx,layer-%d-alpha-mode", layers);
			prop = of_get_property(np, bg_layer_name, &size);
			if (!prop)
				bg_alpha_mode = LOGICVC_LAYER_ALPHA;
			else
				bg_alpha_mode = be32_to_cpup(prop);
		} else {
			pr_debug("xylonfb no BG layer\n");
		}
	}

	init_data->layers = (unsigned char)layers;
	init_data->bg_layer_bpp = (unsigned char)bg_bpp;
	init_data->bg_layer_alpha_mode = (unsigned char)bg_alpha_mode;

	return 0;
}
Exemplo n.º 11
0
static void xylonfb_set_ctrl_reg(struct xylonfb_init_data *init_data,
	unsigned long pix_data_invert, unsigned long pix_clk_act_high)
{
	u32 sync = init_data->vmode_data.fb_vmode.sync;
	u32 ctrl = CTRL_REG_INIT;

	driver_devel("%s\n", __func__);

	/* FB_SYNC_HOR_HIGH_ACT */
	if (!(sync & (1<<0)))
		ctrl &= (~(1<<1));
	/* FB_SYNC_VERT_HIGH_ACT */
	if (!(sync & (1<<1)))
		ctrl &= (~(1<<3));
	if (pix_data_invert)
		ctrl |= LOGICVC_PIX_DATA_INVERT;
	if (pix_clk_act_high)
		ctrl |= LOGICVC_PIX_ACT_HIGH;

	init_data->vmode_data.ctrl_reg = ctrl;
}
Exemplo n.º 12
0
static int xylonfb_parse_vram_info(struct device_node *np,
	unsigned long *vmem_base_addr, unsigned long *vmem_high_addr)
{
	u32 const *prop;
	int size;

	driver_devel("%s\n", __func__);

	prop = of_get_property(np, "xlnx,vmem-baseaddr", &size);
	if (!prop) {
		pr_err("Error xylonfb getting VRAM address begin\n");
		return -EINVAL;
	}
	*vmem_base_addr = be32_to_cpup(prop);

	prop = of_get_property(np, "xlnx,vmem-highaddr", &size);
	if (!prop) {
		pr_err("Error xylonfb getting VRAM address end\n");
		return -EINVAL;
	}
	*vmem_high_addr = be32_to_cpup(prop);

	return 0;
}
Exemplo n.º 13
0
static void xylonfb_adv7511_get_monspecs(u8 *edid,
	struct fb_monspecs *monspecs, struct fb_var_screeninfo *var)
{
	driver_devel("%s\n", __func__);

	fb_edid_to_monspecs(edid, monspecs);

	if (*(xfb_adv7511->xfb_flags) & XYLONFB_FLAG_EDID_PRINT) {
		pr_info("========================================\n");
		pr_info("Display Information (EDID)\n");
		pr_info("========================================\n");
		pr_info("EDID Version %d.%d\n",
			(int)monspecs->version,
			(int)monspecs->revision);
		pr_info("Manufacturer: %s\n", monspecs->manufacturer);
		pr_info("Model: %x\n", monspecs->model);
		pr_info("Serial Number: %u\n", monspecs->serial);
		pr_info("Year: %u Week %u\n",
			monspecs->year, monspecs->week);
		pr_info("Display Characteristics:\n");
		pr_info("   Monitor Operating Limits from EDID\n");
		pr_info("   H: %d-%dKHz V: %d-%dHz DCLK: %dMHz\n",
			monspecs->hfmin/1000, monspecs->hfmax/1000,
			monspecs->vfmin, monspecs->vfmax,
			monspecs->dclkmax/1000000);
		if (monspecs->input & FB_DISP_DDI) {
			pr_info("   Digital Display Input\n");
		} else {
			pr_info("   Analog Display Input:\n");
			pr_info("   Input Voltage:\n");
			if (monspecs->input & FB_DISP_ANA_700_300)
				pr_info("      0.700V/0.300V");
			else if (monspecs->input & FB_DISP_ANA_714_286)
				pr_info("      0.714V/0.286V");
			else if (monspecs->input & FB_DISP_ANA_1000_400)
				pr_info("      1.000V/0.400V");
			else if (monspecs->input & FB_DISP_ANA_700_000)
				pr_info("      0.700V/0.000V");
		}
		if (monspecs->signal) {
			pr_info("   Synchronization:\n");
			if (monspecs->signal & FB_SIGNAL_BLANK_BLANK)
				pr_info("      Blank to Blank\n");
			if (monspecs->signal & FB_SIGNAL_SEPARATE)
				pr_info("      Separate\n");
			if (monspecs->signal & FB_SIGNAL_COMPOSITE)
				pr_info("      Composite\n");
			if (monspecs->signal & FB_SIGNAL_SYNC_ON_GREEN)
				pr_info("      Sync on Green\n");
			if (monspecs->signal & FB_SIGNAL_SERRATION_ON)
				pr_info("      Serration on\n");
		}
		if (monspecs->max_x)
			pr_info("   Max H-size %dcm\n", monspecs->max_x);
		else
			pr_info("   Variable H-size\n");
		if (monspecs->max_y)
			pr_info("   Max V-size %dcm\n", monspecs->max_y);
		else
			pr_info("   Variable V-size\n");
		pr_info("   Display Gamma %d.%d\n",
			monspecs->gamma/100, monspecs->gamma % 100);
		pr_info("   DPMS: Active %s, Suspend %s, Standby %s\n",
			(monspecs->dpms & FB_DPMS_ACTIVE_OFF) ? "yes" : "no",
			(monspecs->dpms & FB_DPMS_SUSPEND)    ? "yes" : "no",
			(monspecs->dpms & FB_DPMS_STANDBY)    ? "yes" : "no");
		if (monspecs->input & FB_DISP_MONO)
			pr_info("   Monochrome/Grayscale\n");
		else if (monspecs->input & FB_DISP_RGB)
			pr_info("   RGB Color Display\n");
		else if (monspecs->input & FB_DISP_MULTI)
			pr_info("   Non-RGB Multicolor Display\n");
		else if (monspecs->input & FB_DISP_UNKNOWN)
			pr_info("   Unknown\n");
		pr_info("   Chromaticity coordinates:\n");
		pr_info("      RedX:   0.%03d\n", monspecs->chroma.redx);
		pr_info("      RedY:   0.%03d\n", monspecs->chroma.redy);
		pr_info("      GreenX: 0.%03d\n", monspecs->chroma.greenx);
		pr_info("      GreenY: 0.%03d\n", monspecs->chroma.greeny);
		pr_info("      BlueX:  0.%03d\n", monspecs->chroma.bluex);
		pr_info("      BlueY:  0.%03d\n", monspecs->chroma.bluey);
		pr_info("      WhiteX: 0.%03d\n", monspecs->chroma.whitex);
		pr_info("      WhiteY: 0.%03d\n", monspecs->chroma.whitey);
		if (monspecs->misc) {
			if (monspecs->misc & FB_MISC_PRIM_COLOR)
				pr_info("   Default color format is primary\n");
			if (monspecs->misc & FB_MISC_1ST_DETAIL)
				pr_info("   First DETAILED Timing is preferred\n");
			if (monspecs->gtf == 1)
				pr_info("   Display is GTF capable\n");
		}
		pr_info("Monitor Timings\n");
		pr_info("   Resolution %dx%d\n", var->xres, var->yres);
		pr_info("   Pixel Clock %d MHz ",
			(int)PICOS2KHZ(var->pixclock)/1000);
		pr_info("   H sync:\n");
		pr_info("      Front porch %d Length %d Back porch %d\n",
			var->right_margin, var->hsync_len, var->left_margin);
		pr_info("   V sync:\n");
		pr_info("      Front porch %d Length %d Back porch %d\n",
			var->lower_margin, var->vsync_len, var->upper_margin);
		pr_info("   %sHSync %sVSync\n",
			(var->sync & FB_SYNC_HOR_HIGH_ACT) ? "+" : "-",
			(var->sync & FB_SYNC_VERT_HIGH_ACT) ? "+" : "-");
		pr_info("========================================\n");
	}
}
Exemplo n.º 14
0
static int xylonfb_parse_vmode_info(struct device_node *np,
	struct xylonfb_init_data *init_data)
{
	struct device_node *dn, *vmode_np;
	u32 const *prop;
	char *c;
	unsigned long pix_data_invert, pix_clk_act_high;
	int size, tmp;

	driver_devel("%s\n", __func__);

	vmode_np = NULL;
	init_data->vmode_data.fb_vmode.refresh = 60;
	init_data->active_layer = 0;
	init_data->vmode_params_set = false;

	prop = of_get_property(np, "pixel-clock-source", &size);
	if (!prop) {
		pr_info("No pixel clock source\n");
		init_data->pixclk_src_id = 0;
	} else {
		tmp = be32_to_cpup(prop);
		init_data->pixclk_src_id = (u16)tmp;
	}
	pix_data_invert = 0;
	prop = of_get_property(np, "pixel-data-invert", &size);
	if (!prop)
		pr_err("Error getting pixel data invert\n");
	else
		pix_data_invert = be32_to_cpup(prop);
	pix_clk_act_high = 0;
	prop = of_get_property(np, "pixel-clock-active-high", &size);
	if (!prop)
		pr_err("Error getting pixel active edge\n");
	else
		pix_clk_act_high = be32_to_cpup(prop);

	prop = of_get_property(np, "pixel-component-format", &size);
	if (prop) {
		if (!strcmp("ABGR", (char *)prop)) {
			prop = of_get_property(np, "pixel-component-layer", &size);
			if (prop) {
				while (size > 0) {
					tmp = be32_to_cpup(prop);
					init_data->layer_ctrl_flags[tmp] = LOGICVC_SWAP_RB;
					prop++;
					size -= sizeof(prop);
				}
			}
		}
	}

	prop = of_get_property(np, "active-layer", &size);
	if (prop) {
		tmp = be32_to_cpup(prop);
		init_data->active_layer = (unsigned char)tmp;
	} else {
		pr_info("xylonfb setting default layer to %d\n",
			init_data->active_layer);
	}

	dn = of_get_child_by_name(np, "edid");
	if (dn) {
		prop = of_get_property(dn, "preffered-videomode", &size);
		if (prop) {
			tmp = be32_to_cpup(prop);
			if (tmp)
				init_data->flags |= XYLONFB_FLAG_EDID_VMODE;
		}
		prop = of_get_property(dn, "display-data", &size);
		if (prop) {
			tmp = be32_to_cpup(prop);
			if (tmp)
				init_data->flags |= XYLONFB_FLAG_EDID_PRINT;
		}
	} else {
		init_data->flags |= XYLONFB_FLAG_ADV7511_SKIP;
	}
	of_node_put(dn);

	prop = of_get_property(np, "videomode", &size);
	if (prop) {
		if (strlen((char *)prop) <= VMODE_NAME_SZ) {
			dn = NULL;
			dn = of_find_node_by_name(NULL, "xylon-video-params");
			if (dn) {
				strcpy(init_data->vmode_data.fb_vmode_name,
					(char *)prop);
				vmode_np = of_find_node_by_name(dn,
					init_data->vmode_data.fb_vmode_name);
				c = strchr((char *)prop, '_');
				if (c)
					*c = 0;
				strcpy(init_data->vmode_data.fb_vmode_name, (char *)prop);
			} else {
				strcpy(init_data->vmode_data.fb_vmode_name, (char *)prop);
			}
			of_node_put(dn);
		} else {
			pr_err("Error videomode name to long\n");
		}
		if (vmode_np) {
			prop = of_get_property(vmode_np, "refresh", &size);
			if (!prop)
				pr_err("Error getting refresh rate\n");
			else
				init_data->vmode_data.fb_vmode.refresh =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "xres", &size);
			if (!prop)
				pr_err("Error getting xres\n");
			else
				init_data->vmode_data.fb_vmode.xres =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "yres", &size);
			if (!prop)
				pr_err("Error getting yres\n");
			else
				init_data->vmode_data.fb_vmode.yres =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "pixclock-khz", &size);
			if (!prop)
				pr_err("Error getting pixclock-khz\n");
			else
				init_data->vmode_data.fb_vmode.pixclock =
					KHZ2PICOS(be32_to_cpup(prop));

			prop = of_get_property(vmode_np, "left-margin", &size);
			if (!prop)
				pr_err("Error getting left-margin\n");
			else
				init_data->vmode_data.fb_vmode.left_margin =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "right-margin", &size);
			if (!prop)
				pr_err("Error getting right-margin\n");
			else
				init_data->vmode_data.fb_vmode.right_margin =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "upper-margin", &size);
			if (!prop)
				pr_err("Error getting upper-margin\n");
			else
				init_data->vmode_data.fb_vmode.upper_margin =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "lower-margin", &size);
			if (!prop)
				pr_err("Error getting lower-margin\n");
			else
				init_data->vmode_data.fb_vmode.lower_margin =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "hsync-len", &size);
			if (!prop)
				pr_err("Error getting hsync-len\n");
			else
				init_data->vmode_data.fb_vmode.hsync_len =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "vsync-len", &size);
			if (!prop)
				pr_err("Error getting vsync-len\n");
			else
				init_data->vmode_data.fb_vmode.vsync_len =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "sync", &size);
			if (!prop)
				pr_err("Error getting sync\n");
			else
				init_data->vmode_data.fb_vmode.sync =
					be32_to_cpup(prop);

			prop = of_get_property(vmode_np, "vmode", &size);
			if (!prop)
				pr_err("Error getting vmode\n");
			else
				init_data->vmode_data.fb_vmode.vmode =
					be32_to_cpup(prop);

			init_data->vmode_params_set = true;
		}
	} else {
		pr_info("xylonfb using default driver video mode\n");
	}

	xylonfb_set_ctrl_reg(init_data, pix_data_invert, pix_clk_act_high);

	return 0;
}
Exemplo n.º 15
0
int xylonfb_adv7511_register(struct fb_info *fbi)
{
	struct v4l2_subdev *sd;
	struct i2c_client *client;
	struct xylonfb_layer_data *ld = fbi->par;
	struct xylonfb_common_data *cd = ld->xylonfb_cd;
	struct xylonfb_misc_data *misc_data = cd->xylonfb_misc;
	int ret;

	driver_devel("%s\n", __func__);

	if (xfb_adv7511)
		return 0;

	xfb_adv7511 = kzalloc(sizeof(struct xylonfb_adv7511), GFP_KERNEL);
	if (!xfb_adv7511) {
		pr_err("xylonfb ADV7511 error allocating data\n");
		return -ENOMEM;
	}

	strlcpy(xfb_adv7511->v4l2_dev.name, DRIVER_NAME,
		sizeof(xfb_adv7511->v4l2_dev.name));
	ret = v4l2_device_register(NULL, &xfb_adv7511->v4l2_dev);
	if (ret) {
		pr_err("xylonfb ADV7511 registering V4L2 device error\n");
		return ret;
	}

	xfb_adv7511->flags |= ADV7511_FLAG_INIT;
	xfb_adv7511->v4l2_dev.notify = xylonfb_adv7511_notify;

	init_completion(&xfb_adv7511->edid_done);

	xfb_adv7511->var_screeninfo =
		kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL);
	xfb_adv7511->monspecs =
		kzalloc(sizeof(struct fb_monspecs), GFP_KERNEL);
	xfb_adv7511->xfb_flags = &cd->xylonfb_flags;
	xfb_adv7511->fbi = fbi;

	misc_data->var_screeninfo = xfb_adv7511->var_screeninfo;
	misc_data->monspecs = xfb_adv7511->monspecs;

	sd = adv7511_subdev(NULL);
	if (!sd) {
		pr_err("xylonfb ADV7511 getting V4L2 subdevice error %s\n",
			ADV7511_NAME);
		ret = -ENODEV;
		goto error_subdev;
	}
	sd->v4l2_dev = &xfb_adv7511->v4l2_dev;
	xfb_adv7511->sd = sd;

	client = v4l2_get_subdevdata(sd);
	if (!client) {
		pr_err("xylonfb ADV7511 getting V4L2 subdevice client error\n");
		ret = -ENODEV;
		goto error_subdev;
	}

	xfb_adv7511->irq_work_queue =
		create_singlethread_workqueue(ADV7511_NAME);
	if (xfb_adv7511->irq_work_queue == NULL) {
		pr_err("xylonfb ADV7511 workqueue error\n");
		goto error_subdev;
	}
	INIT_WORK(&xfb_adv7511->irq_work, xylonfb_adv7511_handler);

	if (client->irq > 0) {
		ret = request_irq(client->irq, xylonfb_adv7511_isr,
			IRQF_TRIGGER_RISING, ADV7511_NAME, xfb_adv7511);
		if (ret) {
			pr_err("xylonfb ADV7511 registering interrupt error %d at %d\n",
				ret, client->irq);
			goto error_irq;
		}
	} else {
		pr_err("xylonfb ADV7511 error no IRQ registered\n");
	}

	sd->ops->core->interrupt_service_routine(sd, 0, NULL);

	if (xfb_adv7511->timeout) {
		ret = wait_for_completion_timeout(&xfb_adv7511->edid_done,
			xfb_adv7511->timeout);
	} else {
		ret = 0;
	}
	xfb_adv7511->flags &= ~ADV7511_FLAG_INIT;
	if (ret == 0) {
		if (xfb_adv7511->timeout) {
			pr_err("xylonfb ADV7511 EDID error\n");
			return -ETIMEDOUT;
		} else {
			return -ENODEV;
		}
	}

	return 0;

error_irq:
	flush_work(&xfb_adv7511->irq_work);
	flush_workqueue(xfb_adv7511->irq_work_queue);
	destroy_workqueue(xfb_adv7511->irq_work_queue);
error_subdev:
	v4l2_device_unregister(&xfb_adv7511->v4l2_dev);

	kfree(xfb_adv7511);

	return ret;
}
Exemplo n.º 16
0
static void xylonfb_adv7511_notify(struct v4l2_subdev *sd,
	unsigned int notification, void *arg)
{
	union notify_data {
		struct adv7511_monitor_detect *md;
		struct adv7511_edid_detect *ed;
	} nd;
	struct v4l2_subdev_edid sd_edid;
	int ret;
	u8 edid[256];

	driver_devel("%s\n", __func__);

	switch (notification) {
	case ADV7511_MONITOR_DETECT:
		nd.md = arg;
		driver_devel("ADV7511 monitor%sdetected\n",
			nd.md->present ? " " : " not ");
		if (nd.md->present) {
			xfb_adv7511->timeout = HZ;
		} else {
			xfb_adv7511->timeout = 0;
			*(xfb_adv7511->xfb_flags) &= ~XYLONFB_FLAG_EDID_RDY;
			atomic_set(&xfb_adv7511->edid_lock, 0);
		}
		break;
	case ADV7511_EDID_DETECT:
		if ((*(xfb_adv7511->xfb_flags) & XYLONFB_FLAG_EDID_VMODE) &&
			!atomic_read(&xfb_adv7511->edid_lock)) {
			nd.ed = arg;
			driver_devel("ADV7511 EDID%sread\n",
				nd.ed->present ? " " : " not ");
			if (nd.ed->present) {
				atomic_set(&xfb_adv7511->edid_lock, 1);
				pr_debug("EDID segment: %d\n", nd.ed->segment);

				memset(edid, 0, sizeof(edid));

				sd_edid.pad = 0;
				sd_edid.start_block = 0;
				sd_edid.blocks = 1;
				sd_edid.edid = edid;
				ret = xfb_adv7511->sd->ops->core->ioctl(sd,
					VIDIOC_SUBDEV_G_EDID,
					(void *)&sd_edid);
				if (ret) {
					pr_warn("xylonfb ADV7511 IOCTL error %d\n",
						ret);
					break;
				}

				fb_parse_edid(edid,
					xfb_adv7511->var_screeninfo);
				xylonfb_adv7511_get_monspecs(edid,
					xfb_adv7511->monspecs,
					xfb_adv7511->var_screeninfo);
				xylonfb_adv7511_set_v4l2_timings(
					xfb_adv7511->sd,
					xfb_adv7511->var_screeninfo);

				*(xfb_adv7511->xfb_flags) |=
					XYLONFB_FLAG_EDID_RDY;

				if (xfb_adv7511->flags & ADV7511_FLAG_INIT)
					complete(&xfb_adv7511->edid_done);
				else
					xylonfb_adv7511_update(
						xfb_adv7511->fbi);
			}
		}
		break;
	default:
		pr_warn("xylonfb ADV7511 false notify (%d)\n", notification);
		break;
	}
}
Exemplo n.º 17
0
static int xylonfb_parse_layer_params(struct device_node *np,
	int id, struct xylonfb_layer_fix_data *lfdata)
{
	u32 const *prop;
	int size;
	char layer_property_name[25];

	driver_devel("%s\n", __func__);

	sprintf(layer_property_name, "xlnx,layer-%d-offset", id);
	prop = of_get_property(np, layer_property_name, &size);
	if (!prop) {
		pr_err("Error getting layer offset\n");
		return -EINVAL;
	} else {
		lfdata->offset = be32_to_cpup(prop);
	}

	sprintf(layer_property_name, "xlnx,buffer-%d-offset", id);
	prop = of_get_property(np, layer_property_name, &size);
	if (!prop) {
		pr_err("Error getting buffer offset\n");
		return -EINVAL;
	} else {
		lfdata->buffer_offset = be32_to_cpup(prop);
	}

	prop = of_get_property(np, "xlnx,row-stride", &size);
	if (!prop)
		lfdata->width = 1024;
	else
		lfdata->width = be32_to_cpup(prop);

	sprintf(layer_property_name, "xlnx,layer-%d-type", id);
	prop = of_get_property(np, layer_property_name, &size);
	if (!prop) {
		pr_err("Error getting layer type\n");
		return -EINVAL;
	} else {
		lfdata->layer_type = be32_to_cpup(prop);
	}

	sprintf(layer_property_name, "xlnx,layer-%d-alpha-mode", id);
	prop = of_get_property(np, layer_property_name, &size);
	if (!prop) {
		pr_err("Error getting layer alpha mode\n");
		return -EINVAL;
	} else {
		lfdata->alpha_mode = be32_to_cpup(prop);
		/* If logiCVC layer is Alpha layer, override DT value */
		if (lfdata->layer_type == LOGICVC_ALPHA_LAYER)
			lfdata->alpha_mode = LOGICVC_LAYER_ALPHA;
	}

	sprintf(layer_property_name, "xlnx,layer-%d-data-width", id);
	prop = of_get_property(np, layer_property_name, &size);
	if (!prop)
		lfdata->bpp = 16;
	else
		lfdata->bpp = be32_to_cpup(prop);
	if (lfdata->bpp == 24)
		lfdata->bpp = 32;

	lfdata->bpp_virt = lfdata->bpp;

	switch (lfdata->bpp) {
	case 8:
		if (lfdata->alpha_mode == LOGICVC_PIXEL_ALPHA)
			lfdata->bpp = 16;
		break;
	case 16:
		if (lfdata->alpha_mode == LOGICVC_PIXEL_ALPHA)
			lfdata->bpp = 32;
		break;
	}

	lfdata->layer_fix_info = id;

	return 0;
}
Exemplo n.º 18
0
static int xylonfb_of_remove(struct platform_device *pdev)
{
	driver_devel("%s\n", __func__);

	return xylonfb_deinit_driver(pdev);
}