Linux Framebuffer Layer development
 help / color / mirror / Atom feed
* [PATCH 02/10] fbdev: xylon: Framebuffer driver core
From: Davor Joja @ 2015-03-11 15:27 UTC (permalink / raw)
  To: linux-kernel, linux-fbdev, tomi.valkeinen, geert; +Cc: Davor Joja
In-Reply-To: <1426087631-9952-1-git-send-email-davorjoja@logicbricks.com>

Driver core functionality.

Signed-off-by: Davor Joja <davorjoja@logicbricks.com>
---
 drivers/video/fbdev/xylon/xylonfb_core.c | 1691 ++++++++++++++++++++++++++++++
 drivers/video/fbdev/xylon/xylonfb_core.h |  252 +++++
 2 files changed, 1943 insertions(+)
 create mode 100644 drivers/video/fbdev/xylon/xylonfb_core.c
 create mode 100644 drivers/video/fbdev/xylon/xylonfb_core.h

diff --git a/drivers/video/fbdev/xylon/xylonfb_core.c b/drivers/video/fbdev/xylon/xylonfb_core.c
new file mode 100644
index 0000000..9970215
--- /dev/null
+++ b/drivers/video/fbdev/xylon/xylonfb_core.c
@@ -0,0 +1,1691 @@
+/*
+ * Xylon logiCVC frame buffer driver core functions
+ *
+ * Copyright (C) 2015 Xylon d.o.o.
+ * Author: Davor Joja <davor.joja@logicbricks.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+
+#include "xylonfb_core.h"
+#include "logicvc.h"
+
+#define LOGICVC_PIX_FMT_AYUV	v4l2_fourcc('A', 'Y', 'U', 'V')
+#define LOGICVC_PIX_FMT_AVUY	v4l2_fourcc('A', 'V', 'U', 'Y')
+#define LOGICVC_PIX_FMT_ALPHA	v4l2_fourcc('A', '8', ' ', ' ')
+
+#define XYLONFB_PSEUDO_PALETTE_SIZE	256
+#define XYLONFB_VRES_DEFAULT		1080
+
+#define LOGICVC_COLOR_RGB_BLACK		0
+#define LOGICVC_COLOR_RGB_WHITE		0xFFFFFF
+#define LOGICVC_COLOR_YUV888_BLACK	0x8080
+#define LOGICVC_COLOR_YUV888_WHITE	0xFF8080
+
+char *xylonfb_mode_option;
+
+static const struct xylonfb_vmode xylonfb_vm = {
+	.vmode = {
+		.refresh = 60,
+		.xres = 1024,
+		.yres = 768,
+		.pixclock = KHZ2PICOS(65000),
+		.left_margin = 160,
+		.right_margin = 24,
+		.upper_margin = 29,
+		.lower_margin = 3,
+		.hsync_len = 136,
+		.vsync_len = 6,
+		.vmode = FB_VMODE_NONINTERLACED
+	},
+	.name = "1024x768"
+};
+
+static int xylonfb_set_timings(struct fb_info *fbi, int bpp);
+static void xylonfb_logicvc_disp_ctrl(struct fb_info *fbi, bool enable);
+static void xylonfb_enable_logicvc_output(struct fb_info *fbi);
+static void xylonfb_disable_logicvc_output(struct fb_info *fbi);
+static void xylonfb_logicvc_layer_enable(struct fb_info *fbi, bool enable);
+static void xylonfb_fbi_update(struct fb_info *fbi);
+
+static u32 xylonfb_get_reg(void __iomem *base, unsigned int offset,
+			   struct xylonfb_layer_data *ld)
+{
+	return readl(base + offset);
+}
+
+static void xylonfb_set_reg(u32 value, void __iomem *base, unsigned int offset,
+			    struct xylonfb_layer_data *ld)
+{
+	writel(value, (base + offset));
+}
+
+static unsigned long xylonfb_get_reg_mem_addr(void __iomem *base,
+					      unsigned int offset,
+					      struct xylonfb_layer_data *ld)
+{
+	unsigned int ordinal = offset / LOGICVC_REG_STRIDE;
+
+	if ((unsigned long)base - (unsigned long)ld->data->dev_base) {
+		return (unsigned long)(&ld->regs) + (ordinal * sizeof(u32));
+	} else {
+		ordinal -= (LOGICVC_CTRL_ROFF / LOGICVC_REG_STRIDE);
+		return (unsigned long)(&ld->data->regs) +
+				       (ordinal * sizeof(u32));
+	}
+}
+
+static u32 xylonfb_get_reg_mem(void __iomem *base, unsigned int offset,
+			       struct xylonfb_layer_data *ld)
+{
+	return *((unsigned long *)xylonfb_get_reg_mem_addr(base, offset, ld));
+}
+
+static void xylonfb_set_reg_mem(u32 value, void __iomem *base,
+				unsigned int offset,
+				struct xylonfb_layer_data *ld)
+{
+	unsigned long *reg_mem_addr +		(unsigned long *)xylonfb_get_reg_mem_addr(base, offset, ld);
+	*reg_mem_addr = value;
+	writel((*reg_mem_addr), (base + offset));
+}
+
+static irqreturn_t xylonfb_isr(int irq, void *dev_id)
+{
+	struct fb_info **afbi = dev_get_drvdata(dev_id);
+	struct fb_info *fbi = afbi[0];
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	void __iomem *dev_base = data->dev_base;
+	u32 isr;
+
+	XYLONFB_DBG(CORE, "%s", __func__);
+
+	isr = readl(dev_base + LOGICVC_INT_STAT_ROFF);
+	if (isr & LOGICVC_INT_V_SYNC) {
+		writel(LOGICVC_INT_V_SYNC, dev_base + LOGICVC_INT_STAT_ROFF);
+
+		data->vsync.count++;
+
+		if (waitqueue_active(&data->vsync.wait))
+			wake_up_interruptible(&data->vsync.wait);
+
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int xylonfb_open(struct fb_info *fbi, int user)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	int ret;
+	bool enable = false;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (atomic_read(&ld->refcount) = 0) {
+		if (ld->flags & XYLONFB_FLAGS_ACTIVATE_NEXT_OPEN) {
+			ld->flags &= ~XYLONFB_FLAGS_ACTIVATE_NEXT_OPEN;
+			enable = true;
+		} else {
+			if (fbi->var.activate = FB_ACTIVATE_NOW) {
+				enable = true;
+			} else if (fbi->var.activate = FB_ACTIVATE_NXTOPEN) {
+				ld->flags |= XYLONFB_FLAGS_ACTIVATE_NEXT_OPEN;
+				return 0;
+			} else if (fbi->var.activate = FB_ACTIVATE_VBL) {
+				ret = xylonfb_vsync_wait(0, fbi);
+				if (ret > 0)
+					enable = true;
+				else
+					return ret;
+			}
+		}
+
+		if (enable) {
+			xylonfb_logicvc_layer_enable(fbi, true);
+			atomic_inc(&data->refcount);
+		}
+	}
+
+	atomic_inc(&ld->refcount);
+
+	return 0;
+}
+
+static int xylonfb_release(struct fb_info *fbi, int user)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (atomic_read(&ld->refcount) > 0) {
+		atomic_dec(&ld->refcount);
+
+		if (atomic_read(&ld->refcount) = 0) {
+			xylonfb_logicvc_layer_enable(fbi, false);
+			atomic_dec(&data->refcount);
+		}
+	}
+
+	return 0;
+}
+
+static int xylonfb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *fbi)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_layer_fix_data *fd = ld->fd;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (var->xres < LOGICVC_MIN_XRES)
+		var->xres = LOGICVC_MIN_XRES;
+	if (var->xres > LOGICVC_MAX_XRES)
+		var->xres = LOGICVC_MAX_XRES;
+	if (var->yres < LOGICVC_MIN_VRES)
+		var->yres = LOGICVC_MIN_VRES;
+	if (var->yres > LOGICVC_MAX_VRES)
+		var->yres = LOGICVC_MAX_VRES;
+
+	if (var->xres_virtual < var->xres)
+		var->xres_virtual = var->xres;
+	if (var->xres_virtual > fd->width)
+		var->xres_virtual = fd->width;
+	if (var->yres_virtual < var->yres)
+		var->yres_virtual = var->yres;
+	if (var->yres_virtual > fd->height)
+		var->yres_virtual = fd->height;
+
+	/* YUV 4:2:2 layer type can only have even layer xoffset */
+	if (fd->format = XYLONFB_FORMAT_YUYV)
+		var->xoffset &= ~((unsigned long) + 1);
+
+	if ((var->xoffset + var->xres) >= var->xres_virtual)
+		var->xoffset = var->xres_virtual - var->xres - 1;
+	if ((var->yoffset + var->yres) >= var->yres_virtual)
+		var->yoffset = var->yres_virtual - var->yres - 1;
+
+	if (var->bits_per_pixel != fbi->var.bits_per_pixel) {
+		if (var->bits_per_pixel = 24)
+			var->bits_per_pixel = 32;
+		else
+			var->bits_per_pixel = fbi->var.bits_per_pixel;
+	}
+
+	var->grayscale = fbi->var.grayscale;
+
+	var->transp.offset = fbi->var.transp.offset;
+	var->transp.length = fbi->var.transp.length;
+	var->transp.msb_right = fbi->var.transp.msb_right;
+	var->red.offset = fbi->var.red.offset;
+	var->red.length = fbi->var.red.length;
+	var->red.msb_right = fbi->var.red.msb_right;
+	var->green.offset = fbi->var.green.offset;
+	var->green.length = fbi->var.green.length;
+	var->green.msb_right = fbi->var.green.msb_right;
+	var->blue.offset = fbi->var.blue.offset;
+	var->blue.length = fbi->var.blue.length;
+	var->blue.msb_right = fbi->var.blue.msb_right;
+	var->height = fbi->var.height;
+	var->width = fbi->var.width;
+	var->sync = fbi->var.sync;
+	var->rotate = fbi->var.rotate;
+
+	return 0;
+}
+
+static int xylonfb_set_par(struct fb_info *fbi)
+{
+	struct device *dev = fbi->dev;
+	struct fb_info **afbi = NULL;
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	unsigned long f;
+	int i, bpp;
+	int ret = 0;
+	char vmode_opt[VMODE_NAME_SIZE];
+	bool resolution_change, layer_on[LOGICVC_MAX_LAYERS];
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (data->flags & XYLONFB_FLAGS_VMODE_SET)
+		return 0;
+
+	if ((fbi->var.xres = data->vm_active.vmode.xres) ||
+	    (fbi->var.yres = data->vm_active.vmode.yres))
+		resolution_change = false;
+	else
+		resolution_change = true;
+
+	if (resolution_change || (data->flags & XYLONFB_FLAGS_VMODE_INIT)) {
+		if (!(data->flags & XYLONFB_FLAGS_VMODE_INIT)) {
+			struct xylonfb_layer_data *ld;
+
+			afbi = dev_get_drvdata(fbi->device);
+			for (i = 0; i < data->layers; i++) {
+				ld = afbi[i]->par;
+				if (ld->flags & XYLONFB_FLAGS_LAYER_ENABLED)
+					layer_on[i] = true;
+				else
+					layer_on[i] = false;
+			}
+		}
+
+		xylonfb_disable_logicvc_output(fbi);
+		xylonfb_logicvc_disp_ctrl(fbi, false);
+
+		if (!(data->flags & XYLONFB_FLAGS_VMODE_INIT)) {
+			data->vm_active.vmode.refresh = 60;
+			sprintf(vmode_opt, "%dx%d%s-%d@%d%s",
+				fbi->var.xres, fbi->var.yres,
+				data->vm_active.opts_cvt,
+				fbi->var.bits_per_pixel,
+				data->vm_active.vmode.refresh,
+				data->vm_active.opts_ext);
+			if (!strcmp(data->vm.name, vmode_opt)) {
+				data->vm_active = data->vm;
+			} else {
+				bpp = fbi->var.bits_per_pixel;
+				xylonfb_mode_option = vmode_opt;
+				ret = xylonfb_set_timings(fbi, bpp);
+				xylonfb_mode_option = NULL;
+			}
+		}
+		if (!ret) {
+			f = PICOS2KHZ(data->vm_active.vmode.pixclock);
+			if (data->flags & XYLONFB_FLAGS_PIXCLK_VALID)
+				if (xylonfb_hw_pixclk_set(&data->pdev->dev,
+							  data->pixel_clock, f))
+					dev_err(dev,
+						"failed set pixel clock\n");
+
+			xylonfb_fbi_update(fbi);
+			XYLONFB_DBG(INFO, "video mode: %dx%d%s-%d@%d%s\n",
+				    fbi->var.xres, fbi->var.yres,
+				    data->vm_active.opts_cvt,
+				    fbi->var.bits_per_pixel,
+				    data->vm_active.vmode.refresh,
+				    data->vm_active.opts_ext);
+		}
+
+		xylonfb_enable_logicvc_output(fbi);
+		xylonfb_logicvc_disp_ctrl(fbi, true);
+
+		if (data->flags & XYLONFB_FLAGS_VMODE_INIT)
+			data->flags |= XYLONFB_FLAGS_VMODE_SET;
+
+		if (!(data->flags & XYLONFB_FLAGS_VMODE_SET)) {
+			if (!afbi) {
+				xylonfb_logicvc_layer_enable(fbi, true);
+				return ret;
+			}
+
+			for (i = 0; i < data->layers; i++) {
+				if (layer_on[i])
+					xylonfb_logicvc_layer_enable(afbi[i],
+								     true);
+			}
+		}
+	}
+
+	return ret;
+}
+
+static void xylonfb_set_color_hw_rgb2yuv(u16 t, u16 r, u16 g, u16 b, u32 *yuv,
+					 struct xylonfb_layer_data *ld)
+{
+	struct xylonfb_data *data = ld->data;
+	u32 y, u, v;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	y = ((data->coeff.cyr * (r & 0xFF)) + (data->coeff.cyg * (g & 0xFF)) +
+	     (data->coeff.cyb * (b & 0xFF)) + data->coeff.cy) /
+	     LOGICVC_YUV_NORM;
+	u = ((-data->coeff.cur * (r & 0xFF)) - (data->coeff.cug * (g & 0xFF)) +
+	     (data->coeff.cub * (b & 0xFF)) + LOGICVC_COEFF_U) /
+	     LOGICVC_YUV_NORM;
+	v = ((data->coeff.cvr * (r & 0xFF)) - (data->coeff.cvg * (g & 0xFF)) -
+	     (data->coeff.cvb * (b & 0xFF)) + LOGICVC_COEFF_V) /
+	     LOGICVC_YUV_NORM;
+
+	*yuv = ((t & 0xFF) << 24) | (y << 16) | (u << 8) | v;
+}
+
+static int xylonfb_set_color_hw(u16 *t, u16 *r, u16 *g, u16 *b,
+				int len, int id, struct fb_info *fbi)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_layer_fix_data *fd = ld->fd;
+	u32 pixel, pixel_clut;
+	u16 a = 0xFF;
+	int bpp, to, ro, go, bo;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	bpp = fd->bpp;
+
+	to = fbi->var.transp.offset;
+	ro = fbi->var.red.offset;
+	go = fbi->var.green.offset;
+	bo = fbi->var.blue.offset;
+
+	switch (fbi->fix.visual) {
+	case FB_VISUAL_PSEUDOCOLOR:
+		if ((id > (LOGICVC_CLUT_SIZE - 1)) || (len > LOGICVC_CLUT_SIZE))
+			return -EINVAL;
+
+		switch (fd->format_clut) {
+		case XYLONFB_FORMAT_CLUT_ARGB6565:
+			while (len > 0) {
+				if (t)
+					a = t[id];
+				pixel_clut = ((((a & 0xFC) >> 2) << to) |
+					      (((r[id] & 0xF8) >> 3) << ro) |
+					      (((g[id] & 0xFC) >> 2) << go) |
+					      (((b[id] & 0xF8) >> 3) << bo));
+				writel(pixel_clut, ld->clut_base +
+				       (id*LOGICVC_CLUT_REGISTER_SIZE));
+				len--;
+				id++;
+			}
+			break;
+		case XYLONFB_FORMAT_CLUT_ARGB8888:
+			while (len > 0) {
+				if (t)
+					a = t[id];
+				pixel_clut = (((a & 0xFF) << to) |
+					      ((r[id] & 0xFF) << ro) |
+					      ((g[id] & 0xFF) << go) |
+					      ((b[id] & 0xFF) << bo));
+				writel(pixel_clut, ld->clut_base +
+				       (id*LOGICVC_CLUT_REGISTER_SIZE));
+				len--;
+				id++;
+			}
+			break;
+		case XYLONFB_FORMAT_CLUT_AYUV8888:
+			while (len > 0) {
+				if (t)
+					a = t[id];
+				xylonfb_set_color_hw_rgb2yuv(a, r[id],
+							     g[id], b[id],
+					 		     &pixel_clut,
+					 		     ld);
+				writel(pixel_clut, ld->clut_base +
+				       (id*LOGICVC_CLUT_REGISTER_SIZE));
+				len--;
+				id++;
+			}
+			break;
+		}
+		break;
+	case FB_VISUAL_TRUECOLOR:
+		switch (fd->format) {
+		case XYLONFB_FORMAT_RGB332:
+			while (len > 0) {
+				pixel = ((((r[id] & 0xE0) >> 5) << ro) |
+					(((g[id] & 0xE0) >> 5) << go) |
+					(((b[id] & 0xC0) >> 6) << bo));
+				((u32 *)(fbi->pseudo_palette))[id] +					(pixel << 24) | (pixel << 16) |
+					(pixel << 8) | pixel;
+				len--;
+				id++;
+			}
+			break;
+		case XYLONFB_FORMAT_RGB565:
+			while (len > 0) {
+				pixel = ((((r[id] & 0xF8) >> 3) << ro) |
+					(((g[id] & 0xFC) >> 2) << go) |
+					(((b[id] & 0xF8) >> 3) << bo));
+				((u32 *)(fbi->pseudo_palette))[id] +					(pixel << 16) | pixel;
+				len--;
+				id++;
+			}
+			break;
+		case XYLONFB_FORMAT_XRGB8888:
+			while (len > 0) {
+				((u32 *)(fbi->pseudo_palette))[id] +					(((r[id] & 0xFF) << ro) |
+					((g[id] & 0xFF) << go) |
+					((b[id] & 0xFF) << bo));
+				len--;
+				id++;
+			}
+			break;
+		case XYLONFB_FORMAT_ARGB8888:
+			while (len > 0) {
+				if (t)
+					a = t[id];
+				((u32 *)(fbi->pseudo_palette))[id] +					(((a & 0xFF) << to) |
+					((r[id] & 0xFF) << ro) |
+					((g[id] & 0xFF) << go) |
+					((b[id] & 0xFF) << bo));
+				len--;
+				id++;
+			}
+			break;
+		}
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int xylonfb_set_color(unsigned regno,
+			     unsigned red, unsigned green, unsigned blue,
+			     unsigned transp, struct fb_info *fbi)
+{
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	return xylonfb_set_color_hw((u16 *)&transp,
+				    (u16 *)&red, (u16 *)&green, (u16 *)&blue,
+				    1, regno, fbi);
+}
+
+static int xylonfb_set_cmap(struct fb_cmap *cmap, struct fb_info *fbi)
+{
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	return xylonfb_set_color_hw(cmap->transp,
+				    cmap->red, cmap->green, cmap->blue,
+				    cmap->len, cmap->start, fbi);
+}
+
+static void xylonfb_set_pixels(struct fb_info *fbi,
+			       struct xylonfb_layer_data *ld,
+			       int bpp, unsigned int pix)
+{
+	u32 *vmem;
+	u8 *vmem8;
+	u16 *vmem16;
+	u32 *vmem32;
+	int x, y, pixoffset;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	vmem = ld->fb_base + (fbi->var.xoffset * (fbi->var.bits_per_pixel/4)) +
+	       (fbi->var.yoffset * fbi->var.xres_virtual *
+	       (fbi->var.bits_per_pixel/4));
+
+	switch (bpp) {
+	case 8:
+		vmem8 = (u8 *)vmem;
+		for (y = fbi->var.yoffset; y < fbi->var.yres; y++) {
+			pixoffset = (y * fbi->var.xres_virtual);
+			for (x = fbi->var.xoffset; x < fbi->var.xres; x++)
+				vmem8[pixoffset + x] = pix;
+		}
+		break;
+	case 16:
+		vmem16 = (u16 *)vmem;
+		for (y = fbi->var.yoffset; y < fbi->var.yres; y++) {
+			pixoffset = (y * fbi->var.xres_virtual);
+			for (x = fbi->var.xoffset; x < fbi->var.xres; x++)
+				vmem16[pixoffset + x] = pix;
+		}
+		break;
+	case 32:
+		vmem32 = (u32 *)vmem;
+		for (y = fbi->var.yoffset; y < fbi->var.yres; y++) {
+			pixoffset = (y * fbi->var.xres_virtual);
+			for (x = fbi->var.xoffset; x < fbi->var.xres; x++)
+				vmem32[pixoffset + x] = pix;
+		}
+		break;
+	}
+}
+
+static int xylonfb_blank(int blank_mode, struct fb_info *fbi)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	struct xylonfb_layer_fix_data *fd = ld->fd;
+	void __iomem *dev_base = data->dev_base;
+	u32 ctrl = data->reg_access.get_reg_val(dev_base,
+						LOGICVC_CTRL_ROFF,
+						ld);
+	u32 power = readl(dev_base + LOGICVC_POWER_CTRL_ROFF);
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	switch (blank_mode) {
+	case FB_BLANK_UNBLANK:
+		XYLONFB_DBG(INFO, "FB_BLANK_UNBLANK");
+		ctrl |= (LOGICVC_CTRL_HSYNC | LOGICVC_CTRL_VSYNC |
+			LOGICVC_CTRL_DATA_ENABLE);
+		data->reg_access.set_reg_val(ctrl, dev_base,
+					     LOGICVC_CTRL_ROFF, ld);
+
+		power |= LOGICVC_V_EN_MSK;
+		writel(power, dev_base + LOGICVC_POWER_CTRL_ROFF);
+
+		mdelay(50);
+		break;
+
+	case FB_BLANK_NORMAL:
+		XYLONFB_DBG(INFO, "FB_BLANK_NORMAL");
+		switch (fd->format) {
+		case XYLONFB_FORMAT_C8:
+			xylonfb_set_color(0, 0, 0, 0, 0xFF, fbi);
+			xylonfb_set_pixels(fbi, ld, 8, 0);
+			break;
+		case XYLONFB_FORMAT_RGB332:
+			xylonfb_set_pixels(fbi, ld, 8, 0x00);
+			break;
+		case XYLONFB_FORMAT_RGB565:
+			xylonfb_set_pixels(fbi, ld, 16, 0x0000);
+			break;
+		case XYLONFB_FORMAT_XRGB8888:
+		case XYLONFB_FORMAT_ARGB8888:
+			xylonfb_set_pixels(fbi, ld, 32, 0xFF000000);
+			break;
+		}
+		break;
+
+	case FB_BLANK_POWERDOWN:
+		XYLONFB_DBG(INFO, "FB_BLANK_POWERDOWN");
+		ctrl &= ~(LOGICVC_CTRL_HSYNC | LOGICVC_CTRL_VSYNC |
+			LOGICVC_CTRL_DATA_ENABLE);
+		data->reg_access.set_reg_val(ctrl, dev_base,
+					     LOGICVC_CTRL_ROFF, ld);
+
+		power &= ~LOGICVC_V_EN_MSK;
+		writel(power, dev_base + LOGICVC_POWER_CTRL_ROFF);
+
+		mdelay(50);
+		break;
+
+	case FB_BLANK_VSYNC_SUSPEND:
+		XYLONFB_DBG(INFO, "FB_BLANK_VSYNC_SUSPEND");
+		ctrl &= ~LOGICVC_CTRL_VSYNC;
+		data->reg_access.set_reg_val(ctrl, dev_base,
+					     LOGICVC_CTRL_ROFF, ld);
+		break;
+
+	case FB_BLANK_HSYNC_SUSPEND:
+		XYLONFB_DBG(INFO, "FB_BLANK_HSYNC_SUSPEND");
+		ctrl &= ~LOGICVC_CTRL_HSYNC;
+		data->reg_access.set_reg_val(ctrl, dev_base,
+					     LOGICVC_CTRL_ROFF, ld);
+		break;
+	}
+
+	return 0;
+}
+
+static int xylonfb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *fbi)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	struct xylonfb_layer_fix_data *fd = ld->fd;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (!(data->flags & XYLONFB_FLAGS_SIZE_POSITION))
+		return -EINVAL;
+
+	if ((fbi->var.xoffset = var->xoffset) &&
+	    (fbi->var.yoffset = var->yoffset))
+		return 0;
+
+	if (fbi->var.vmode & FB_VMODE_YWRAP)
+		return -EINVAL;
+
+	if (((var->xoffset + fbi->var.xres) > fbi->var.xres_virtual) ||
+	    ((var->yoffset + fbi->var.yres) > fbi->var.yres_virtual))
+		return -EINVAL;
+
+	if (fd->format = XYLONFB_FORMAT_YUYV)
+		var->xoffset &= ~((unsigned long) + 1);
+
+	fbi->var.xoffset = var->xoffset;
+	fbi->var.yoffset = var->yoffset;
+
+	if (!(data->flags & XYLONFB_FLAGS_DYNAMIC_LAYER_ADDRESS)) {
+		data->reg_access.set_reg_val(var->xoffset, ld->base,
+					     LOGICVC_LAYER_HOFF_ROFF, ld);
+		data->reg_access.set_reg_val(var->yoffset, ld->base,
+					     LOGICVC_LAYER_VOFF_ROFF, ld);
+	}
+	data->reg_access.set_reg_val((fbi->var.xres - 1), ld->base,
+				     LOGICVC_LAYER_HPOS_ROFF, ld);
+	data->reg_access.set_reg_val((fbi->var.yres - 1), ld->base,
+				     LOGICVC_LAYER_VPOS_ROFF, ld);
+	if (data->flags & XYLONFB_FLAGS_DYNAMIC_LAYER_ADDRESS) {
+		ld->fb_pbase_active = ld->fb_pbase +
+				      ((var->xoffset * (fd->bpp / 8)) +
+				      (var->yoffset * fd->width *
+				      (fd->bpp / 8)));
+		data->reg_access.set_reg_val(ld->fb_pbase_active, ld->base,
+					     LOGICVC_LAYER_ADDR_ROFF, ld);
+	}
+
+	return 0;
+}
+
+static struct fb_ops xylonfb_ops = {
+	.owner = THIS_MODULE,
+	.fb_open = xylonfb_open,
+	.fb_release = xylonfb_release,
+	.fb_check_var = xylonfb_check_var,
+	.fb_set_par = xylonfb_set_par,
+	.fb_setcolreg = xylonfb_set_color,
+	.fb_setcmap = xylonfb_set_cmap,
+	.fb_blank = xylonfb_blank,
+	.fb_pan_display = xylonfb_pan_display,
+	.fb_fillrect = cfb_fillrect,
+	.fb_copyarea = cfb_copyarea,
+	.fb_imageblit = cfb_imageblit,
+	.fb_ioctl = xylonfb_ioctl,
+};
+
+static int xylonfb_find_next_layer(struct xylonfb_data *data, int layers,
+				   int id)
+{
+	dma_addr_t address = data->fd[id]->address;
+	dma_addr_t temp_address = ((unsigned long) - 1);
+	dma_addr_t loop_address;
+	int next = -1;
+	int i;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	for (i = 0; i < layers; i++) {
+		loop_address = data->fd[i]->address;
+		if ((address < loop_address) && (loop_address < temp_address)) {
+			next = i;
+			temp_address = loop_address;
+		}
+	}
+
+	return next;
+}
+
+static void xylonfb_get_vmem_height(struct xylonfb_data *data, int layers,
+				    int id)
+{
+	struct xylonfb_layer_fix_data *fd = data->fd[id];
+	dma_addr_t vmem_start = fd->address;
+	dma_addr_t vmem_end;
+	int next;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (fd->address_range && (id < (layers - 1))) {
+		fd->height = fd->address_range / (fd->width * (fd->bpp / 8));
+		return;
+	}
+
+	vmem_start = fd->address;
+
+	next = xylonfb_find_next_layer(data, layers, id);
+	if (next = -1) {
+		if (fd->address_range) {
+			fd->height = fd->address_range /
+				     (fd->width * (fd->bpp / 8));
+		} else {
+			if (fd->buffer_offset)
+				fd->height = fd->buffer_offset *
+					     LOGICVC_MAX_LAYER_BUFFERS;
+			else
+				fd->height = XYLONFB_VRES_DEFAULT;
+		}
+	} else {
+		vmem_end = data->fd[next]->address;
+		fd->height = (vmem_end - vmem_start) /
+			     (fd->width * (fd->bpp / 8));
+	}
+
+	if (fd->height > (LOGICVC_MAX_VRES * LOGICVC_MAX_LAYER_BUFFERS))
+		fd->height = LOGICVC_MAX_VRES * LOGICVC_MAX_LAYER_BUFFERS;
+}
+
+static void xylonfb_set_fbi_var_screeninfo(struct fb_var_screeninfo *var,
+					   struct xylonfb_data *data)
+{
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	var->xres = data->vm_active.vmode.xres;
+	var->yres = data->vm_active.vmode.yres;
+	var->pixclock = data->vm_active.vmode.pixclock;
+	var->left_margin = data->vm_active.vmode.left_margin;
+	var->right_margin = data->vm_active.vmode.right_margin;
+	var->upper_margin = data->vm_active.vmode.upper_margin;
+	var->lower_margin = data->vm_active.vmode.lower_margin;
+	var->hsync_len = data->vm_active.vmode.hsync_len;
+	var->vsync_len = data->vm_active.vmode.vsync_len;
+	var->sync = data->vm_active.vmode.sync;
+	var->vmode = data->vm_active.vmode.vmode;
+}
+
+static void xylonfb_fbi_update(struct fb_info *fbi)
+{
+	struct fb_info **afbi = dev_get_drvdata(fbi->device);
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	int i, layers, id;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (!afbi)
+		return;
+
+	layers = data->layers;
+	id = ld->fd->id;
+
+	for (i = 0; i < layers; i++) {
+		if (i = id)
+			continue;
+
+		xylonfb_set_fbi_var_screeninfo(&afbi[i]->var, data);
+		afbi[i]->monspecs = afbi[id]->monspecs;
+	}
+}
+
+static void xylonfb_set_hw_specifics(struct fb_info *fbi,
+				     struct xylonfb_layer_data *ld,
+				     struct xylonfb_layer_fix_data *fd)
+{
+	struct xylonfb_data *data = ld->data;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	fbi->fix.smem_start = ld->fb_pbase;
+	fbi->fix.smem_len = ld->fb_size;
+	if (fd->type = LOGICVC_LAYER_RGB) {
+		fbi->fix.type = FB_TYPE_PACKED_PIXELS;
+	} else if (fd->type = LOGICVC_LAYER_YUV) {
+		if (fd->format = XYLONFB_FORMAT_C8)
+			fbi->fix.type = FB_TYPE_PACKED_PIXELS;
+		else
+			fbi->fix.type = FB_TYPE_FOURCC;
+	}
+	if ((fd->type = LOGICVC_LAYER_YUV) ||
+	    (fd->type = LOGICVC_LAYER_ALPHA)) {
+		if (fd->format = XYLONFB_FORMAT_C8)
+			fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+		else
+			fbi->fix.visual = FB_VISUAL_FOURCC;
+	} else if (fd->format = XYLONFB_FORMAT_C8) {
+		fbi->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	} else {
+		/*
+		 * Other logiCVC layer pixel formats:
+		 * - 8 bpp: LAYER or PIXEL alpha
+		 *   It is not true color, RGB triplet is stored in 8 bits.
+		 * - 16 bpp:
+		 *   LAYER alpha: RGB triplet is stored in 16 bits
+		 * - 32 bpp: LAYER or PIXEL alpha
+		 *   True color, RGB triplet or ARGB quadriplet
+		 *   is stored in 32 bits.
+		 */
+		fbi->fix.visual = FB_VISUAL_TRUECOLOR;
+	}
+
+	fbi->fix.xpanstep = 1;
+	fbi->fix.ypanstep = 1;
+	fbi->fix.ywrapstep = 0;
+	fbi->fix.line_length = fd->width * (fd->bpp / 8);
+	fbi->fix.mmio_start = ld->pbase;
+	fbi->fix.mmio_len = LOGICVC_LAYER_REGISTERS_RANGE;
+	fbi->fix.accel = FB_ACCEL_NONE;
+
+	fbi->var.xres_virtual = fd->width;
+	fbi->var.yres_virtual = fd->height;
+
+	fbi->var.bits_per_pixel = fd->bpp;
+
+	switch (fd->type) {
+	case LOGICVC_LAYER_ALPHA:
+		fbi->var.grayscale = LOGICVC_PIX_FMT_ALPHA;
+		break;
+	case LOGICVC_LAYER_RGB:
+		fbi->var.grayscale = 0;
+		break;
+	case LOGICVC_LAYER_YUV:
+		if (fd->format = XYLONFB_FORMAT_C8) {
+			fbi->var.grayscale = LOGICVC_PIX_FMT_AYUV;
+		} else if (fd->format = XYLONFB_FORMAT_YUYV) {
+			if (fd->component_swap)
+				fbi->var.grayscale = V4L2_PIX_FMT_VYUY;
+			else
+				fbi->var.grayscale = V4L2_PIX_FMT_YVYU;
+		} else if (fd->format = XYLONFB_FORMAT_AYUV) {
+			if (fd->component_swap)
+				fbi->var.grayscale = LOGICVC_PIX_FMT_AVUY;
+			else
+				fbi->var.grayscale = LOGICVC_PIX_FMT_AYUV;
+		}
+		break;
+	}
+
+	/*
+	 * Set values according to logiCVC layer data width configuration:
+	 * layer data width can be 1, 2, 4 bytes
+	 */
+	if (fd->transparency = LOGICVC_ALPHA_LAYER) {
+		fbi->var.transp.offset = 0;
+		fbi->var.transp.length = 0;
+	}
+
+	switch (fd->format) {
+	case XYLONFB_FORMAT_A8:
+		fbi->var.transp.offset = 0;
+		fbi->var.transp.length = 8;
+		break;
+	case XYLONFB_FORMAT_C8:
+		switch (fd->format_clut) {
+		case XYLONFB_FORMAT_CLUT_ARGB6565:
+			fbi->var.transp.offset = 24;
+			fbi->var.transp.length = 6;
+			fbi->var.red.offset = 19;
+			fbi->var.red.length = 5;
+			fbi->var.green.offset = 10;
+			fbi->var.green.length = 6;
+			fbi->var.blue.offset = 3;
+			fbi->var.blue.length = 5;
+			break;
+		case XYLONFB_FORMAT_CLUT_ARGB8888:
+			fbi->var.transp.offset = 24;
+			fbi->var.transp.length = 8;
+			fbi->var.red.offset = 16;
+			fbi->var.red.length = 8;
+			fbi->var.green.offset = 8;
+			fbi->var.green.length = 8;
+			fbi->var.blue.offset = 0;
+			fbi->var.blue.length = 8;
+			break;
+		case XYLONFB_FORMAT_CLUT_AYUV8888:
+			fbi->var.transp.offset = 24;
+			fbi->var.transp.length = 8;
+			fbi->var.red.offset = 16;
+			fbi->var.red.length = 8;
+			fbi->var.green.offset = 8;
+			fbi->var.green.length = 8;
+			fbi->var.blue.offset = 0;
+			fbi->var.blue.length = 8;
+			break;
+		}
+		break;
+	case XYLONFB_FORMAT_RGB332:
+		fbi->var.red.offset = 5;
+		fbi->var.red.length = 3;
+		fbi->var.green.offset = 2;
+		fbi->var.green.length = 3;
+		fbi->var.blue.offset = 0;
+		fbi->var.blue.length = 2;
+		break;
+	case XYLONFB_FORMAT_RGB565:
+		fbi->var.red.offset = 11;
+		fbi->var.red.length = 5;
+		fbi->var.green.offset = 5;
+		fbi->var.green.length = 6;
+		fbi->var.blue.offset = 0;
+		fbi->var.blue.length = 5;
+		break;
+	case XYLONFB_FORMAT_ARGB8888:
+	case XYLONFB_FORMAT_AYUV:
+		fbi->var.transp.offset = 24;
+		fbi->var.transp.length = 8;
+	case XYLONFB_FORMAT_XRGB8888:
+		fbi->var.red.offset = 16;
+		fbi->var.red.length = 8;
+		fbi->var.green.offset = 8;
+		fbi->var.green.length = 8;
+		fbi->var.blue.offset = 0;
+		fbi->var.blue.length = 8;
+		break;
+	}
+	fbi->var.transp.msb_right = 0;
+	fbi->var.red.msb_right = 0;
+	fbi->var.green.msb_right = 0;
+	fbi->var.blue.msb_right = 0;
+	fbi->var.activate = FB_ACTIVATE_NOW;
+	fbi->var.height = 0;
+	fbi->var.width = 0;
+	fbi->var.sync = 0;
+	if (!(data->vm_active.ctrl & LOGICVC_CTRL_HSYNC_INVERT))
+		fbi->var.sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (!(data->vm_active.ctrl & LOGICVC_CTRL_VSYNC_INVERT))
+		fbi->var.sync |= FB_SYNC_VERT_HIGH_ACT;
+	fbi->var.rotate = 0;
+}
+
+static int xylonfb_set_timings(struct fb_info *fbi, int bpp)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	struct fb_var_screeninfo fb_var;
+	struct fb_videomode *vm;
+	int rc;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if ((data->flags & XYLONFB_FLAGS_VMODE_INIT) &&
+	    (data->flags & XYLONFB_FLAGS_VMODE_CUSTOM) &&
+	    memchr(data->vm.name, 'x', 10)) {
+		data->vm_active = data->vm;
+		vm = &data->vm.vmode;
+		data->vm_active.vmode.refresh +			DIV_ROUND_CLOSEST((PICOS2KHZ(vm->pixclock) * 1000),
+					  ((vm->xres + vm->left_margin +
+					  vm->right_margin + vm->hsync_len) *
+					  (vm->yres + vm->upper_margin +
+					  vm->lower_margin + vm->vsync_len)));
+		return 0;
+	}
+
+	rc = fb_find_mode(&fb_var, fbi, xylonfb_mode_option, NULL, 0,
+			  &xylonfb_vm.vmode, bpp);
+
+	switch (rc) {
+	case 0:
+		dev_err(fbi->dev, "failed find video mode\n"
+			"using driver default mode %dx%dM-%d@%d\n",
+			xylonfb_vm.vmode.xres,
+			xylonfb_vm.vmode.yres,
+			bpp,
+			xylonfb_vm.vmode.refresh);
+		break;
+	case 1:
+		dev_dbg(fbi->dev, "video mode %s", xylonfb_mode_option);
+		break;
+	case 2:
+		dev_warn(fbi->dev, "video mode %s with ignored refresh rate\n",
+			 xylonfb_mode_option);
+		break;
+	case 3:
+		dev_warn(fbi->dev, "default video mode %dx%dM-%d@%d\n",
+			 xylonfb_vm.vmode.xres,
+			 xylonfb_vm.vmode.yres,
+			 bpp,
+			 xylonfb_vm.vmode.refresh);
+		break;
+	case 4:
+		dev_warn(fbi->dev, "video mode fallback\n");
+		break;
+	default:
+		break;
+	}
+
+	data->vm_active.ctrl = data->vm.ctrl;
+	data->vm_active.vmode.xres = fb_var.xres;
+	data->vm_active.vmode.yres = fb_var.yres;
+	data->vm_active.vmode.pixclock = fb_var.pixclock;
+	data->vm_active.vmode.left_margin = fb_var.left_margin;
+	data->vm_active.vmode.right_margin = fb_var.right_margin;
+	data->vm_active.vmode.upper_margin = fb_var.upper_margin;
+	data->vm_active.vmode.lower_margin = fb_var.lower_margin;
+	data->vm_active.vmode.hsync_len = fb_var.hsync_len;
+	data->vm_active.vmode.vsync_len = fb_var.vsync_len;
+	data->vm_active.vmode.sync = fb_var.sync;
+	data->vm_active.vmode.vmode = fb_var.vmode;
+	data->vm_active.vmode.refresh +		DIV_ROUND_CLOSEST((PICOS2KHZ(fb_var.pixclock) * 1000),
+				  ((fb_var.xres + fb_var.left_margin +
+				  fb_var.right_margin + fb_var.hsync_len) *
+				  (fb_var.yres + fb_var.upper_margin +
+				  fb_var.lower_margin + fb_var.vsync_len)));
+	strcpy(data->vm_active.opts_cvt, data->vm.opts_cvt);
+	strcpy(data->vm_active.opts_ext, data->vm.opts_ext);
+	sprintf(data->vm_active.name, "%dx%d%s-%d@%d%s",
+		fb_var.xres, fb_var.yres,
+		data->vm_active.opts_cvt,
+		fb_var.bits_per_pixel,
+		data->vm_active.vmode.refresh,
+		data->vm_active.opts_ext);
+
+	if (!memchr(data->vm.name, 'x', 10))
+		data->vm = data->vm_active;
+
+	return 0;
+}
+
+static int xylonfb_register_fb(struct fb_info *fbi,
+			       struct xylonfb_layer_data *ld, int id,
+			       int *regfb)
+{
+	struct device *dev = fbi->dev;
+	struct xylonfb_data *data = ld->data;
+	struct xylonfb_layer_fix_data *fd = ld->fd;
+	int transp;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	fbi->flags = FBINFO_DEFAULT;
+	fbi->screen_base = (char __iomem *)ld->fb_base;
+	fbi->screen_size = ld->fb_size;
+	fbi->pseudo_palette = kzalloc(sizeof(u32) * XYLONFB_PSEUDO_PALETTE_SIZE,
+				      GFP_KERNEL);
+	fbi->fbops = &xylonfb_ops;
+
+	sprintf(fbi->fix.id, "Xylon FB%d", id);
+	xylonfb_set_hw_specifics(fbi, ld, fd);
+
+	if (!(data->flags & XYLONFB_FLAGS_VMODE_DEFAULT)) {
+		if (!xylonfb_set_timings(fbi, fbi->var.bits_per_pixel))
+			data->flags |= XYLONFB_FLAGS_VMODE_DEFAULT;
+		else
+			dev_err(dev, "videomode not set\n");
+	}
+	xylonfb_set_fbi_var_screeninfo(&fbi->var, data);
+	fbi->mode = &data->vm_active.vmode;
+	fbi->mode->name = data->vm_active.name;
+
+	if (fd->transparency = LOGICVC_ALPHA_LAYER)
+		transp = 0;
+	else
+		transp = 1;
+	if (fb_alloc_cmap(&fbi->cmap, XYLONFB_PSEUDO_PALETTE_SIZE, transp))
+		return -ENOMEM;
+
+	/*
+	 * After fb driver registration, values in struct fb_info
+	 * must not be changed anywhere else in driver except in
+	 * xylonfb_set_par() function
+	 */
+	*regfb = register_framebuffer(fbi);
+	if (*regfb) {
+		dev_err(dev, "failed register fb %d\n", id);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void xylonfb_layer_initialize(struct xylonfb_layer_data *ld)
+{
+	struct xylonfb_data *data = ld->data;
+	struct xylonfb_layer_fix_data *fd = ld->fd;
+	u32 reg = ld->data->reg_access.get_reg_val(ld->base,
+						   LOGICVC_LAYER_CTRL_ROFF,
+						   ld);
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	reg |= LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_DISABLE;
+	if (fd->component_swap)
+		reg |= LOGICVC_LAYER_CTRL_PIXEL_FORMAT_ABGR;
+	ld->data->reg_access.set_reg_val(reg, ld->base,
+					 LOGICVC_LAYER_CTRL_ROFF,
+					 ld);
+
+	if (data->flags & XYLONFB_FLAGS_DYNAMIC_LAYER_ADDRESS)
+		data->reg_access.set_reg_val(ld->fb_pbase, ld->base,
+					     LOGICVC_LAYER_ADDR_ROFF,
+					     ld);
+}
+
+static int xylonfb_vmem_init(struct xylonfb_layer_data *ld, int id, bool *mmap)
+{
+	struct xylonfb_data *data = ld->data;
+	struct xylonfb_layer_fix_data *fd = ld->fd;
+	struct device *dev = &data->pdev->dev;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (fd->address) {
+		ld->fb_pbase = fd->address;
+
+		xylonfb_get_vmem_height(data, data->layers, id);
+		ld->fb_size = fd->width * (fd->bpp / 8) * fd->height;
+
+		if (*mmap) {
+			ld->fb_base = (__force void *)ioremap_wc(ld->fb_pbase,
+								 ld->fb_size);
+			if (!ld->fb_base) {
+				dev_err(dev, "failed map video memory\n");
+				return -EINVAL;
+			}
+		}
+	} else {
+		if (fd->buffer_offset)
+			fd->height = fd->buffer_offset *
+				     LOGICVC_MAX_LAYER_BUFFERS;
+		else
+			fd->height = XYLONFB_VRES_DEFAULT *
+				     LOGICVC_MAX_LAYER_BUFFERS;
+		ld->fb_size = fd->width * (fd->bpp / 8) * fd->height;
+
+		ld->fb_base = dma_alloc_coherent(&data->pdev->dev,
+						 PAGE_ALIGN(ld->fb_size),
+						 &ld->fb_pbase, GFP_KERNEL);
+		if (!ld->fb_base) {
+			dev_err(dev, "failed allocate video buffer ID%d\n", id);
+			return -ENOMEM;
+		}
+
+		data->flags |= XYLONFB_FLAGS_DMA_BUFFER;
+	}
+
+	ld->fb_pbase_active = ld->fb_pbase;
+
+	*mmap = false;
+
+	return 0;
+}
+
+static void xylonfb_logicvc_disp_ctrl(struct fb_info *fbi, bool enable)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	void __iomem *dev_base = data->dev_base;
+	u32 val;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (enable) {
+		val = LOGICVC_EN_VDD_MSK;
+		writel(val, dev_base + LOGICVC_POWER_CTRL_ROFF);
+		mdelay(data->pwr_delay);
+		val |= LOGICVC_V_EN_MSK;
+		writel(val, dev_base + LOGICVC_POWER_CTRL_ROFF);
+		mdelay(data->sig_delay);
+		val |= LOGICVC_EN_BLIGHT_MSK;
+		writel(val, dev_base + LOGICVC_POWER_CTRL_ROFF);
+	} else {
+		writel(0, dev_base + LOGICVC_POWER_CTRL_ROFF);
+	}
+}
+
+static void xylonfb_logicvc_layer_enable(struct fb_info *fbi, bool enable)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	u32 reg;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	reg = ld->data->reg_access.get_reg_val(ld->base,
+					       LOGICVC_LAYER_CTRL_ROFF,
+					       ld);
+
+	if (enable) {
+		reg |= LOGICVC_LAYER_CTRL_ENABLE;
+		ld->flags |= XYLONFB_FLAGS_LAYER_ENABLED;
+	} else {
+		reg &= ~LOGICVC_LAYER_CTRL_ENABLE;
+		ld->flags &= ~XYLONFB_FLAGS_LAYER_ENABLED;
+	}
+
+	ld->data->reg_access.set_reg_val(reg, ld->base,
+					 LOGICVC_LAYER_CTRL_ROFF,
+					 ld);
+}
+
+static void xylonfb_enable_logicvc_output(struct fb_info *fbi)
+{
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	void __iomem *dev_base = data->dev_base;
+	struct fb_videomode *vm = &data->vm_active.vmode;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	writel(vm->right_margin - 1, dev_base + LOGICVC_HSYNC_FRONT_PORCH_ROFF);
+	writel(vm->hsync_len - 1, dev_base + LOGICVC_HSYNC_ROFF);
+	writel(vm->left_margin - 1, dev_base + LOGICVC_HSYNC_BACK_PORCH_ROFF);
+	writel(vm->xres - 1, dev_base + LOGICVC_HRES_ROFF);
+	writel(vm->lower_margin - 1, dev_base + LOGICVC_VSYNC_FRONT_PORCH_ROFF);
+	writel(vm->vsync_len - 1, dev_base + LOGICVC_VSYNC_ROFF);
+	writel(vm->upper_margin - 1, dev_base + LOGICVC_VSYNC_BACK_PORCH_ROFF);
+	writel(vm->yres - 1, dev_base + LOGICVC_VRES_ROFF);
+	data->reg_access.set_reg_val(data->vm_active.ctrl, dev_base,
+				     LOGICVC_CTRL_ROFF, ld);
+
+	if (data->flags & XYLONFB_FLAGS_BACKGROUND_LAYER_YUV)
+		data->reg_access.set_reg_val(LOGICVC_COLOR_YUV888_BLACK,
+					     dev_base,
+					     LOGICVC_BACKGROUND_COLOR_ROFF,
+					     ld);
+	else
+		data->reg_access.set_reg_val(LOGICVC_COLOR_RGB_BLACK,
+					     dev_base,
+					     LOGICVC_BACKGROUND_COLOR_ROFF,
+					     ld);
+
+	writel(LOGICVC_DTYPE_REG_INIT, dev_base + LOGICVC_DTYPE_ROFF);
+
+	XYLONFB_DBG(INFO, "logiCVC HW parameters:\n" \
+		"    Horizontal Front Porch: %d pixclks\n" \
+		"    Horizontal Sync:        %d pixclks\n" \
+		"    Horizontal Back Porch:  %d pixclks\n" \
+		"    Vertical Front Porch:   %d pixclks\n" \
+		"    Vertical Sync:          %d pixclks\n" \
+		"    Vertical Back Porch:    %d pixclks\n" \
+		"    Pixel Clock:            %d ps\n" \
+		"    Horizontal Resolution:  %d pixels\n" \
+		"    Vertical Resolution:    %d lines\n", \
+		vm->right_margin, vm->hsync_len, vm->left_margin,
+		vm->lower_margin, vm->vsync_len, vm->upper_margin,
+		vm->pixclock, vm->xres, vm->yres);
+}
+
+static void xylonfb_disable_logicvc_output(struct fb_info *fbi)
+{
+	struct fb_info **afbi = dev_get_drvdata(fbi->device);
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	int i;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (afbi)
+		for (i = 0; i < data->layers; i++)
+			xylonfb_logicvc_layer_enable(afbi[i], false);
+}
+
+static void xylonfb_start(struct fb_info **afbi, int layers)
+{
+	struct fb_info *fbi = afbi[0];
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	int i;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	for (i = 0; i < layers; i++) {
+		ld = afbi[i]->par;
+		if (ld->flags & XYLONFB_FLAGS_LAYER_ENABLED)
+			continue;
+
+		xylonfb_logicvc_layer_enable(afbi[i], false);
+	}
+
+	if (data->flags & XYLONFB_FLAGS_VSYNC_IRQ) {
+		writel(LOGICVC_INT_V_SYNC,
+		       data->dev_base + LOGICVC_INT_STAT_ROFF);
+		data->reg_access.set_reg_val(~LOGICVC_INT_V_SYNC,
+					     data->dev_base,
+					     LOGICVC_INT_MASK_ROFF, ld);
+	}
+
+	for (i = 0; i < layers; i++) {
+		ld = afbi[i]->par;
+		XYLONFB_DBG(INFO, "logiCVC layer %d\n" \
+			"    Registers Base Address:     0x%lX\n" \
+			"    Layer Video Memory Address: 0x%lX\n" \
+			"    X resolution:               %d\n" \
+			"    Y resolution:               %d\n" \
+			"    X resolution (virtual):     %d\n" \
+			"    Y resolution (virtual):     %d\n" \
+			"    Line length (bytes):        %d\n" \
+			"    Bits per Pixel:             %d\n" \
+			"\n", \
+			i,
+			(unsigned long)ld->pbase,
+			(unsigned long)ld->fb_pbase,
+			afbi[i]->var.xres,
+			afbi[i]->var.yres,
+			afbi[i]->var.xres_virtual,
+			afbi[i]->var.yres_virtual,
+			afbi[i]->fix.line_length,
+			afbi[i]->var.bits_per_pixel);
+	}
+}
+
+static void xylonfb_get_vmode_opts(struct xylonfb_data *data)
+{
+	char *s, *opt, *ext, *c;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	s = data->vm.name;
+	opt = data->vm.opts_cvt;
+	ext = data->vm.opts_ext;
+
+	data->vm.vmode.vmode = 0;
+
+	c = strchr(s, 'M');
+	if (c)
+		*opt++ = *c;
+	c = strchr(s, 'R');
+	if (c)
+		*opt = *c;
+	c = strchr(s, 'i');
+	if (c) {
+		*ext++ = *c;
+		data->vm.vmode.vmode |= FB_VMODE_INTERLACED;
+	}
+	c = strchr(s, 'm');
+	if (c)
+		*ext = *c;
+}
+
+static bool xylonfb_allow_console(struct xylonfb_layer_fix_data *fd)
+{
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	switch (fd->format) {
+	case XYLONFB_FORMAT_C8:
+	case XYLONFB_FORMAT_RGB332:
+	case XYLONFB_FORMAT_RGB565:
+	case XYLONFB_FORMAT_XRGB8888:
+	case XYLONFB_FORMAT_ARGB8888:
+		return true;
+	default:
+		return false;
+	}
+}
+
+int xylonfb_init_core(struct xylonfb_data *data)
+{
+	struct device *dev = &data->pdev->dev;
+	struct fb_info **afbi, *fbi;
+	struct xylonfb_layer_data *ld;
+	void __iomem *dev_base;
+	u32 ip_ver;
+	int i, ret, layers, console_layer;
+	int regfb[LOGICVC_MAX_LAYERS];
+	size_t size;
+	unsigned short layer_base_off[] = {
+		(LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_0_OFFSET),
+		(LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_1_OFFSET),
+		(LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_2_OFFSET),
+		(LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_3_OFFSET),
+		(LOGICVC_LAYER_BASE_OFFSET + LOGICVC_LAYER_4_OFFSET)
+	};
+	unsigned short clut_base_off[] = {
+		(LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L0_CLUT_0_OFFSET),
+		(LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L1_CLUT_0_OFFSET),
+		(LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L2_CLUT_0_OFFSET),
+		(LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L3_CLUT_0_OFFSET),
+		(LOGICVC_CLUT_BASE_OFFSET + LOGICVC_CLUT_L4_CLUT_0_OFFSET),
+	};
+	bool memmap;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	dev_base = devm_ioremap_resource(dev, &data->resource_mem);
+	if (IS_ERR(dev_base)) {
+		dev_err(dev, "failed ioremap mem resource\n");
+		return PTR_ERR(dev_base);
+	}
+	data->dev_base = dev_base;
+
+	data->irq = data->resource_irq.start;
+	ret = devm_request_irq(dev, data->irq, xylonfb_isr, IRQF_TRIGGER_HIGH,
+			       XYLONFB_DEVICE_NAME, dev);
+	if (ret)
+		return ret;
+
+	ip_ver = readl(dev_base + LOGICVC_IP_VERSION_ROFF);
+	data->major = (ip_ver >> LOGICVC_MAJOR_REVISION_SHIFT) &
+		      LOGICVC_MAJOR_REVISION_MASK;
+	data->minor = (ip_ver >> LOGICVC_MINOR_REVISION_SHIFT) &
+		      LOGICVC_MINOR_REVISION_MASK;
+	data->patch = ip_ver & LOGICVC_PATCH_LEVEL_MASK;
+	dev_info(dev, "logiCVC IP core %d.%02d.%c\n",
+		 data->major, data->minor, ('a' + data->patch));
+
+	if (data->major >= 4)
+		data->flags |= XYLONFB_FLAGS_DYNAMIC_LAYER_ADDRESS;
+
+	layers = data->layers;
+	if (layers = 0) {
+		dev_err(dev, "no available layers\n");
+		return -ENODEV;
+	}
+	console_layer = data->console_layer;
+	if (console_layer >= layers) {
+		dev_err(dev, "invalid console layer ID\n");
+		console_layer = 0;
+	}
+
+	if (data->flags & XYLONFB_FLAGS_CHECK_CONSOLE_LAYER) {
+		if (!xylonfb_allow_console(data->fd[console_layer])) {
+			dev_err(dev, "invalid console layer format\n");
+			return -EINVAL;
+		}
+		data->flags &= ~XYLONFB_FLAGS_CHECK_CONSOLE_LAYER;
+	}
+
+	size = sizeof(struct fb_info *);
+	afbi = devm_kzalloc(dev, (size * layers), GFP_KERNEL);
+	if (!afbi) {
+		dev_err(dev, "failed allocate internal data\n");
+		return -ENOMEM;
+	}
+
+	if (data->flags & XYLONFB_FLAGS_READABLE_REGS) {
+		data->reg_access.get_reg_val = xylonfb_get_reg;
+		data->reg_access.set_reg_val = xylonfb_set_reg;
+	} else {
+		size = sizeof(struct xylonfb_registers);
+		data->reg_access.get_reg_val = xylonfb_get_reg_mem;
+		data->reg_access.set_reg_val = xylonfb_set_reg_mem;
+	}
+
+	data->coeff.cyr = LOGICVC_COEFF_Y_R;
+	data->coeff.cyg = LOGICVC_COEFF_Y_G;
+	data->coeff.cyb = LOGICVC_COEFF_Y_B;
+	if (data->flags & XYLONFB_FLAGS_DISPLAY_INTERFACE_ITU656) {
+		data->coeff.cy = LOGICVC_COEFF_ITU656_Y;
+		data->coeff.cur = LOGICVC_COEFF_ITU656_U_R;
+		data->coeff.cug = LOGICVC_COEFF_ITU656_U_G;
+		data->coeff.cub = LOGICVC_COEFF_ITU656_U_B;
+		data->coeff.cvr = LOGICVC_COEFF_ITU656_V_R;
+		data->coeff.cvg = LOGICVC_COEFF_ITU656_V_G;
+		data->coeff.cvb = LOGICVC_COEFF_ITU656_V_B;
+	} else {
+		data->coeff.cy = LOGICVC_COEFF_Y;
+		data->coeff.cur = LOGICVC_COEFF_U_R;
+		data->coeff.cug = LOGICVC_COEFF_U_G;
+		data->coeff.cub = LOGICVC_COEFF_U_B;
+		data->coeff.cvr = LOGICVC_COEFF_V_R;
+		data->coeff.cvg = LOGICVC_COEFF_V_G;
+		data->coeff.cvb = LOGICVC_COEFF_V_B;
+	}
+
+	atomic_set(&data->refcount, 0);
+
+	data->flags |= XYLONFB_FLAGS_VMODE_INIT;
+
+	sprintf(data->vm.name, "%s-%d@%d",
+		data->vm.name, data->fd[console_layer]->bpp,
+		data->vm.vmode.refresh);
+	if (!(data->flags & XYLONFB_FLAGS_VMODE_CUSTOM))
+		xylonfb_mode_option = data->vm.name;
+	xylonfb_get_vmode_opts(data);
+
+	if (data->pixel_clock) {
+		if (xylonfb_hw_pixclk_supported(dev, data->pixel_clock)) {
+			data->flags |= XYLONFB_FLAGS_PIXCLK_VALID;
+		} else {
+			dev_warn(dev, "pixel clock not supported\n");
+			ret = -EPROBE_DEFER;
+			goto err_probe;
+		}
+	} else {
+		dev_info(dev, "external pixel clock\n");
+	}
+
+	ld = NULL;
+
+	for (i = 0; i < layers; i++)
+		regfb[i] = -1;
+	memmap = true;
+
+	/*
+	 * /dev/fb0 will be default console layer,
+	 * no matter how logiCVC layers are sorted in memory
+	 */
+	for (i = console_layer; i < layers; i++) {
+		if (regfb[i] != -1)
+			continue;
+
+		size = sizeof(struct xylonfb_layer_data);
+		fbi = framebuffer_alloc(size, dev);
+		if (!fbi) {
+			dev_err(dev, "failed allocate fb info\n");
+			ret = -ENOMEM;
+			goto err_probe;
+		}
+		fbi->dev = dev;
+		afbi[i] = fbi;
+
+		ld = fbi->par;
+		ld->data = data;
+		ld->fd = data->fd[i];
+
+		atomic_set(&ld->refcount, 0);
+
+		ld->pbase = data->resource_mem.start + layer_base_off[i];
+		ld->base = dev_base + layer_base_off[i];
+		ld->clut_base = dev_base + clut_base_off[i];
+
+		ret = xylonfb_vmem_init(ld, i, &memmap);
+		if (ret)
+			goto err_probe;
+
+		xylonfb_layer_initialize(ld);
+
+		ret = xylonfb_register_fb(fbi, ld, i, &regfb[i]);
+		if (ret)
+			goto err_probe;
+
+		if (console_layer >= 0)
+			fbi->monspecs = afbi[console_layer]->monspecs;
+
+		mutex_init(&ld->mutex);
+
+		XYLONFB_DBG(INFO, "Layer parameters\n" \
+			    "    ID %d\n" \
+			    "    Width %d pixels\n" \
+			    "    Height %d lines\n" \
+			    "    Bits per pixel %d\n" \
+			    "    Buffer size %d bytes\n", \
+			    ld->fd->id,
+			    ld->fd->width,
+			    ld->fd->height,
+			    ld->fd->bpp,
+			    ld->fb_size);
+
+		if (console_layer > 0) {
+			i = -1;
+			console_layer = -1;
+		}
+	}
+
+	if (ld) {
+		if (!(data->flags & XYLONFB_FLAGS_READABLE_REGS))
+			data->reg_access.set_reg_val(0xFFFF, dev_base,
+						     LOGICVC_INT_MASK_ROFF,
+						     ld);
+	} else {
+		dev_warn(dev, "initialization not completed\n");
+	}
+
+	if (data->flags & XYLONFB_FLAGS_BACKGROUND_LAYER)
+		dev_info(dev, "BG layer: %s@%dbpp",
+			 data->flags & XYLONFB_FLAGS_BACKGROUND_LAYER_RGB ? \
+			 "RGB" : "YUV", data->bg_layer_bpp);
+
+	mutex_init(&data->irq_mutex);
+	init_waitqueue_head(&data->vsync.wait);
+	atomic_set(&data->refcount, 0);
+
+	dev_set_drvdata(dev, (void *)afbi);
+
+	data->flags &= ~(XYLONFB_FLAGS_VMODE_INIT |
+			 XYLONFB_FLAGS_VMODE_DEFAULT | XYLONFB_FLAGS_VMODE_SET);
+	xylonfb_mode_option = NULL;
+
+	xylonfb_start(afbi, layers);
+
+	return 0;
+
+err_probe:
+	for (i = layers - 1; i >= 0; i--) {
+		fbi = afbi[i];
+		if (!fbi)
+			continue;
+		ld = fbi->par;
+		if (regfb[i] = 0)
+			unregister_framebuffer(fbi);
+		else
+			regfb[i] = 0;
+		if (fbi->cmap.red)
+			fb_dealloc_cmap(&fbi->cmap);
+		if (ld) {
+			if (data->flags & XYLONFB_FLAGS_DMA_BUFFER) {
+				if (ld->fb_base)
+					dma_free_coherent(dev,
+						PAGE_ALIGN(ld->fb_size),
+						ld->fb_base, ld->fb_pbase);
+			} else {
+				if (ld->fb_base)
+					iounmap((void __iomem *)ld->fb_base);
+			}
+			kfree(fbi->pseudo_palette);
+			framebuffer_release(fbi);
+		}
+	}
+
+	return ret;
+}
+
+int xylonfb_deinit_core(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct fb_info **afbi = dev_get_drvdata(dev);
+	struct fb_info *fbi = afbi[0];
+	struct xylonfb_layer_data *ld = fbi->par;
+	struct xylonfb_data *data = ld->data;
+	int i;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (atomic_read(&data->refcount) != 0) {
+		dev_err(dev, "driver in use\n");
+		return -EINVAL;
+	}
+
+	xylonfb_disable_logicvc_output(fbi);
+
+	xylonfb_hw_pixclk_unload(data->pixel_clock);
+
+	for (i = data->layers - 1; i >= 0; i--) {
+		fbi = afbi[i];
+		ld = fbi->par;
+
+		unregister_framebuffer(fbi);
+		fb_dealloc_cmap(&fbi->cmap);
+		if (data->flags & XYLONFB_FLAGS_DMA_BUFFER) {
+			dma_free_coherent(dev,
+					  PAGE_ALIGN(ld->fb_size),
+					  ld->fb_base, ld->fb_pbase);
+		}
+		kfree(fbi->pseudo_palette);
+		framebuffer_release(fbi);
+	}
+
+	return 0;
+}
diff --git a/drivers/video/fbdev/xylon/xylonfb_core.h b/drivers/video/fbdev/xylon/xylonfb_core.h
new file mode 100644
index 0000000..1a3dee8
--- /dev/null
+++ b/drivers/video/fbdev/xylon/xylonfb_core.h
@@ -0,0 +1,252 @@
+/*
+ * Xylon logiCVC frame buffer driver internal data structures
+ *
+ * Copyright (C) 2015 Xylon d.o.o.
+ * Author: Davor Joja <davor.joja@logicbricks.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __XYLONFB_CORE_H__
+#define __XYLONFB_CORE_H__
+
+#include <linux/fb.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+
+#define XYLONFB_DRIVER_NAME "xylonfb"
+#define XYLONFB_DEVICE_NAME "logicvc"
+#define XYLONFB_DRIVER_DESCRIPTION "Xylon logiCVC frame buffer driver"
+#define XYLONFB_DRIVER_VERSION "3.0"
+
+#define INFO		1
+#define CORE		2
+#define DEBUG_LEVEL	CORE
+
+#ifdef DEBUG
+#define XYLONFB_DBG(level, format, ...)				\
+	do {							\
+		if (level >= DEBUG_LEVEL)			\
+			pr_info(format "\n", ## __VA_ARGS__);	\
+	} while (0)
+#else
+#define XYLONFB_DBG(format, ...) do { } while (0)
+#endif
+
+#define LOGICVC_MAX_LAYERS	5
+
+/* Xylon FB driver flags */
+#define XYLONFB_FLAGS_READABLE_REGS		(1 << 0)
+#define XYLONFB_FLAGS_SIZE_POSITION		(1 << 1)
+#define XYLONFB_FLAGS_BACKGROUND_LAYER		(1 << 2)
+#define XYLONFB_FLAGS_BACKGROUND_LAYER_RGB	(1 << 3)
+#define XYLONFB_FLAGS_BACKGROUND_LAYER_YUV	(1 << 4)
+#define XYLONFB_FLAGS_DISPLAY_INTERFACE_ITU656	(1 << 5)
+#define XYLONFB_FLAGS_DYNAMIC_LAYER_ADDRESS	(1 << 6)
+#define XYLONFB_FLAGS_CHECK_CONSOLE_LAYER	(1 << 7)
+#define XYLONFB_FLAGS_PIXCLK_VALID		(1 << 8)
+#define XYLONFB_FLAGS_DMA_BUFFER		(1 << 9)
+#define XYLONFB_FLAGS_VSYNC_IRQ			(1 << 10)
+#define XYLONFB_FLAGS_VMODE_CUSTOM		(1 << 11)
+#define XYLONFB_FLAGS_VMODE_INIT		(1 << 12)
+#define XYLONFB_FLAGS_VMODE_DEFAULT		(1 << 13)
+#define XYLONFB_FLAGS_VMODE_SET			(1 << 14)
+#define XYLONFB_FLAGS_LAYER_ENABLED		(1 << 15)
+#define XYLONFB_FLAGS_ACTIVATE_NEXT_OPEN	(1 << 16)
+
+/* Xylon FB driver color formats */
+enum xylonfb_color_format {
+	XYLONFB_FORMAT_A8,
+	XYLONFB_FORMAT_C8,
+	XYLONFB_FORMAT_RGB332,
+	XYLONFB_FORMAT_RGB565,
+	XYLONFB_FORMAT_XRGB8888,
+	XYLONFB_FORMAT_ARGB8888,
+	XYLONFB_FORMAT_YUYV,
+	XYLONFB_FORMAT_AYUV,
+	XYLONFB_FORMAT_CLUT_ARGB6565,
+	XYLONFB_FORMAT_CLUT_ARGB8888,
+	XYLONFB_FORMAT_CLUT_AYUV8888
+};
+
+struct xylonfb_layer_data;
+struct xylonfb_data;
+
+#define VMODE_NAME_SIZE	21
+#define VMODE_OPTS_SIZE	3
+
+struct xylonfb_vmode {
+	u32 ctrl;
+	struct fb_videomode vmode;
+	char name[VMODE_NAME_SIZE];
+	char opts_cvt[VMODE_OPTS_SIZE];
+	char opts_ext[VMODE_OPTS_SIZE];
+};
+
+struct xylonfb_registers {
+	u32 ctrl;
+	u32 dtype;
+	u32 bg;
+	u32 unused[3];
+	u32 int_mask;
+};
+
+union xylonfb_layer_reg_0 {
+	u32 addr;
+	u32 hoff;
+};
+
+union xylonfb_layer_reg_1 {
+	u32 unused;
+	u32 voff;
+};
+
+struct xylonfb_layer_registers {
+	union xylonfb_layer_reg_0 reg_0;
+	union xylonfb_layer_reg_1 reg_1;
+	u32 hpos;
+	u32 vpos;
+	u32 hsize;
+	u32 vsize;
+	u32 alpha;
+	u32 ctrl;
+	u32 transp;
+};
+
+struct xylonfb_register_access {
+	u32 (*get_reg_val)(void __iomem *dev_base, unsigned int offset,
+			   struct xylonfb_layer_data *layer_data);
+	void (*set_reg_val)(u32 value, void __iomem *dev_base,
+			    unsigned int offset,
+			    struct xylonfb_layer_data *layer_data);
+};
+
+struct xylonfb_layer_fix_data {
+	unsigned int id;
+	u32 address;
+	u32 address_range;
+	u32 buffer_offset;
+	u32 bpp;
+	u32 width;
+	u32 height;
+	u32 format;
+	u32 format_clut;
+	u32 transparency;
+	u32 type;
+	bool component_swap;
+};
+
+struct xylonfb_layer_data {
+	struct mutex mutex;
+
+	atomic_t refcount;
+
+	struct xylonfb_data *data;
+	struct xylonfb_layer_fix_data *fd;
+	struct xylonfb_layer_registers regs;
+
+	dma_addr_t pbase;
+	void __iomem *base;
+	void __iomem *clut_base;
+
+	dma_addr_t fb_pbase;
+	void *fb_base;
+	u32 fb_size;
+
+	dma_addr_t fb_pbase_active;
+
+	u32 flags;
+};
+
+struct xylonfb_rgb2yuv_coeff {
+	s32 cy;
+	s32 cyr;
+	s32 cyg;
+	s32 cyb;
+	s32 cur;
+	s32 cug;
+	s32 cub;
+	s32 cvr;
+	s32 cvg;
+	s32 cvb;
+};
+
+struct xylonfb_sync {
+	wait_queue_head_t wait;
+	unsigned int count;
+};
+
+struct xylonfb_data {
+	struct platform_device *pdev;
+
+	struct device_node *device;
+	struct device_node *pixel_clock;
+
+	struct resource resource_mem;
+	struct resource resource_irq;
+
+	void __iomem *dev_base;
+
+	struct mutex irq_mutex;
+
+	struct xylonfb_register_access reg_access;
+	struct xylonfb_sync vsync;
+	struct xylonfb_vmode vm;
+	struct xylonfb_vmode vm_active;
+	struct xylonfb_rgb2yuv_coeff coeff;
+
+	struct xylonfb_layer_fix_data *fd[LOGICVC_MAX_LAYERS];
+	struct xylonfb_registers regs;
+
+	u32 bg_layer_bpp;
+	u32 console_layer;
+	u32 pixel_stride;
+
+	atomic_t refcount;
+
+	u32 flags;
+	int irq;
+	u8 layers;
+	/*
+	 * Delay after applying display power and
+	 * before applying display signals
+	 */
+	u32 pwr_delay;
+	/*
+	 * Delay after applying display signal and
+	 * before applying display backlight power supply
+	 */
+	u32 sig_delay;
+	/* IP version */
+	u8 major;
+	u8 minor;
+	u8 patch;
+};
+
+/* Xylon FB video mode options */
+extern char *xylonfb_mode_option;
+
+/* Xylon FB core pixel clock interface functions */
+extern bool xylonfb_hw_pixclk_supported(struct device *dev,
+					struct device_node *dn);
+extern void xylonfb_hw_pixclk_unload(struct device_node *dn);
+extern int xylonfb_hw_pixclk_set(struct device *dev, struct device_node *dn,
+				 unsigned long pixclk_khz);
+
+/* Xylon FB core V sync wait function */
+extern int xylonfb_vsync_wait(u32 crt, struct fb_info *fbi);
+
+/* Xylon FB core interface functions */
+extern int xylonfb_init_core(struct xylonfb_data *data);
+extern int xylonfb_deinit_core(struct platform_device *pdev);
+extern int xylonfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+			 unsigned long arg);
+
+#endif /* __XYLONFB_CORE_H__ */
-- 
1.9.1


^ permalink raw reply related

* [PATCH 01/10] fbdev: Xylon framebuffer driver
From: Davor Joja @ 2015-03-11 15:27 UTC (permalink / raw)
  To: linux-kernel, linux-fbdev, tomi.valkeinen, geert; +Cc: Davor Joja
In-Reply-To: <1426087631-9952-1-git-send-email-davorjoja@logicbricks.com>

Driver registration and OF binding.

Signed-off-by: Davor Joja <davorjoja@logicbricks.com>
---
 drivers/video/fbdev/xylon/xylonfb_main.c | 528 +++++++++++++++++++++++++++++++
 1 file changed, 528 insertions(+)
 create mode 100644 drivers/video/fbdev/xylon/xylonfb_main.c

diff --git a/drivers/video/fbdev/xylon/xylonfb_main.c b/drivers/video/fbdev/xylon/xylonfb_main.c
new file mode 100644
index 0000000..3313da5
--- /dev/null
+++ b/drivers/video/fbdev/xylon/xylonfb_main.c
@@ -0,0 +1,528 @@
+/*
+ * Xylon logiCVC frame buffer Open Firmware driver
+ *
+ * Copyright (C) 2015 Xylon d.o.o.
+ * Author: Davor Joja <davor.joja@logicbricks.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/platform_device.h>
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+#include "xylonfb_core.h"
+#include "logicvc.h"
+
+static void xylonfb_init_ctrl(struct device_node *dn, enum display_flags flags,
+			      u32 *ctrl)
+{
+	u32 ctrl_reg = (LOGICVC_CTRL_HSYNC | LOGICVC_CTRL_VSYNC |
+			LOGICVC_CTRL_DATA_ENABLE);
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (of_property_read_bool(dn, "hsync-active-low") ||
+	    (flags & DISPLAY_FLAGS_HSYNC_LOW))
+		ctrl_reg |= LOGICVC_CTRL_HSYNC_INVERT;
+	if (of_property_read_bool(dn, "vsync-active-low") ||
+	    (flags & DISPLAY_FLAGS_VSYNC_LOW))
+		ctrl_reg |= LOGICVC_CTRL_VSYNC_INVERT;
+	if (of_property_read_bool(dn, "data-enable-active-low") ||
+	    (flags & DISPLAY_FLAGS_DE_LOW))
+		ctrl_reg |= LOGICVC_CTRL_DATA_ENABLE_INVERT;
+	if (of_property_read_bool(dn, "pixel-data-invert"))
+		ctrl_reg |= LOGICVC_CTRL_PIXEL_DATA_INVERT;
+	if (of_property_read_bool(dn, "pixel-data-output-trigger-high") ||
+	    (flags & DISPLAY_FLAGS_PIXDATA_POSEDGE))
+		ctrl_reg |= LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT;
+
+	*ctrl = ctrl_reg;
+}
+
+static int xylonfb_layer_set_format(struct xylonfb_layer_fix_data *fd,
+				    struct device *dev)
+{
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	switch (fd->type) {
+	case LOGICVC_LAYER_ALPHA:
+		fd->format = XYLONFB_FORMAT_A8;
+		break;
+
+	case LOGICVC_LAYER_RGB:
+		switch (fd->bpp) {
+		case 8:
+			switch (fd->transparency) {
+			case LOGICVC_ALPHA_CLUT_16BPP:
+				fd->format = XYLONFB_FORMAT_C8;
+				fd->format_clut = XYLONFB_FORMAT_CLUT_ARGB6565;
+				break;
+			case LOGICVC_ALPHA_CLUT_32BPP:
+				fd->format = XYLONFB_FORMAT_C8;
+				fd->format_clut = XYLONFB_FORMAT_CLUT_ARGB8888;
+				break;
+			case LOGICVC_ALPHA_LAYER:
+				fd->format = XYLONFB_FORMAT_RGB332;
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+		case 16:
+			if (fd->transparency != LOGICVC_ALPHA_LAYER)
+				return -EINVAL;
+
+			fd->format = XYLONFB_FORMAT_RGB565;
+			break;
+		case 32:
+			switch (fd->transparency) {
+			case LOGICVC_ALPHA_LAYER:
+				fd->format = XYLONFB_FORMAT_XRGB8888;
+				break;
+			case LOGICVC_ALPHA_PIXEL:
+				fd->format = XYLONFB_FORMAT_ARGB8888;
+				break;
+			default:
+				return -EINVAL;
+			}
+			break;
+		}
+		break;
+
+	case LOGICVC_LAYER_YUV:
+		switch (fd->bpp) {
+		case 8:
+			if (fd->transparency != LOGICVC_ALPHA_CLUT_32BPP)
+				return -EINVAL;
+
+			fd->format = XYLONFB_FORMAT_C8;
+			fd->format_clut = XYLONFB_FORMAT_CLUT_AYUV8888;
+			break;
+		case 16:
+			if (fd->transparency != LOGICVC_ALPHA_LAYER)
+				return -EINVAL;
+
+			fd->format = XYLONFB_FORMAT_YUYV;
+			break;
+		case 32:
+			if (fd->transparency != LOGICVC_ALPHA_PIXEL)
+				return -EINVAL;
+
+			fd->format = XYLONFB_FORMAT_AYUV;
+			break;
+		}
+		break;
+
+	default:
+		dev_err(dev, "unsupported layer type\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int xylonfb_parse_layer_info(struct device_node *parent_dn,
+				    struct xylonfb_data *data, int id)
+{
+	struct device *dev = &data->pdev->dev;
+	struct device_node *dn;
+	struct xylonfb_layer_fix_data *fd;
+	int ret;
+	char layer_name[10];
+	const char *string;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	snprintf(layer_name, sizeof(layer_name), "layer_%d", id);
+	dn = of_get_child_by_name(parent_dn, layer_name);
+	if (!dn)
+		return 0;
+
+	data->layers++;
+
+	fd = devm_kzalloc(&data->pdev->dev,
+			  sizeof(struct xylonfb_layer_fix_data), GFP_KERNEL);
+	if (!fd) {
+		dev_err(dev, "failed allocate layer fix data (%d)\n", id);
+		return -ENOMEM;
+	}
+
+	data->fd[id] = fd;
+
+	fd->id = id;
+
+	ret = of_property_read_u32(dn, "address", &fd->address);
+	if (ret && (ret != -EINVAL)) {
+		dev_err(dev, "failed get address\n");
+		return ret;
+	}
+	ret = of_property_read_u32_index(dn, "address", 1, &fd->address_range);
+
+	ret = of_property_read_u32(dn, "buffer-offset", &fd->buffer_offset);
+	if (ret && (ret != -EINVAL)) {
+		dev_err(dev, "failed get buffer-offset\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(dn, "bits-per-pixel", &fd->bpp);
+	if (ret) {
+		dev_err(dev, "failed get bits-per-pixel\n");
+		return ret;
+	}
+	switch (fd->bpp) {
+	case 8:
+	case 16:
+	case 32:
+		break;
+	default:
+		dev_err(dev, "invalid bits-per-pixel value\n");
+		return -EINVAL;
+	}
+
+	ret = of_property_read_string(dn, "type", &string);
+	if (ret) {
+		dev_err(dev, "failed get type\n");
+		return ret;
+	}
+	if (!strcmp(string, "alpha")) {
+		fd->type = LOGICVC_LAYER_ALPHA;
+	} else if (!strcmp(string, "rgb")) {
+		fd->type = LOGICVC_LAYER_RGB;
+	} else if (!strcmp(string, "yuv")) {
+		fd->type = LOGICVC_LAYER_YUV;
+	} else {
+		dev_err(dev, "unsupported layer type\n");
+		return -EINVAL;
+	}
+
+	if (fd->type != LOGICVC_LAYER_ALPHA) {
+		ret = of_property_read_string(dn, "transparency", &string);
+		if (ret) {
+			dev_err(dev, "failed get transparency\n");
+			return ret;
+		}
+		if (!strcmp(string, "clut16")) {
+			fd->transparency = LOGICVC_ALPHA_CLUT_16BPP;
+		} else if (!strcmp(string, "clut32")) {
+			fd->transparency = LOGICVC_ALPHA_CLUT_32BPP;
+		} else if (!strcmp(string, "layer")) {
+			fd->transparency = LOGICVC_ALPHA_LAYER;
+		} else if (!strcmp(string, "pixel")) {
+			fd->transparency = LOGICVC_ALPHA_PIXEL;
+		} else {
+			dev_err(dev, "unsupported layer transparency\n");
+			return -EINVAL;
+		}
+	}
+
+	if (of_property_read_bool(dn, "component-swap"))
+		fd->component_swap = true;
+
+	fd->width = data->pixel_stride;
+
+	ret = xylonfb_layer_set_format(fd, dev);
+	if (ret) {
+		dev_err(dev, "failed set layer format\n");
+		return ret;
+	}
+
+	of_node_put(dn);
+
+	return id + 1;
+}
+
+static int xylon_parse_hw_info(struct device_node *dn,
+			       struct xylonfb_data *data)
+{
+	struct device *dev = &data->pdev->dev;
+	int ret;
+	const char *string;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	ret = of_property_read_u32(dn, "background-layer-bits-per-pixel",
+				   &data->bg_layer_bpp);
+	if (ret && (ret != -EINVAL)) {
+		dev_err(dev, "failed get bg-layer-bits-per-pixel\n");
+		return ret;
+	} else if (ret = 0) {
+		data->flags |= XYLONFB_FLAGS_BACKGROUND_LAYER;
+
+		ret = of_property_read_string(dn, "background-layer-type",
+					      &string);
+		if (ret) {
+			dev_err(dev, "failed get bg-layer-type\n");
+			return ret;
+		}
+		if (!strcmp(string, "rgb")) {
+			data->flags |= XYLONFB_FLAGS_BACKGROUND_LAYER_RGB;
+		} else if (!strcmp(string, "yuv")) {
+			data->flags |= XYLONFB_FLAGS_BACKGROUND_LAYER_YUV;
+		} else {
+			dev_err(dev, "unsupported bg layer type\n");
+			return -EINVAL;
+		}
+	}
+
+	if (of_property_read_bool(dn, "display-interface-itu656"))
+		data->flags |= XYLONFB_FLAGS_DISPLAY_INTERFACE_ITU656;
+
+	if (of_property_read_bool(dn, "readable-regs"))
+		data->flags |= XYLONFB_FLAGS_READABLE_REGS;
+	else
+		dev_warn(dev, "logicvc registers not readable\n");
+
+	if (of_property_read_bool(dn, "size-position"))
+		data->flags |= XYLONFB_FLAGS_SIZE_POSITION;
+	else
+		dev_warn(dev, "logicvc size-position disabled\n");
+
+	ret = of_property_read_u32(dn, "pixel-stride", &data->pixel_stride);
+	if (ret) {
+		dev_err(dev, "failed get pixel-stride\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(dn, "power-delay", &data->pwr_delay);
+	if (ret && (ret != -EINVAL)) {
+		dev_err(dev, "failed get power-delay\n");
+		return ret;
+	}
+
+	ret = of_property_read_u32(dn, "signal-delay", &data->sig_delay);
+	if (ret && (ret != -EINVAL)) {
+		dev_err(dev, "failed get signal\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id logicvc_of_match[] = {
+	{ .compatible = "xylon,logicvc-3.00.a" },
+	{ .compatible = "xylon,logicvc-4.00.a" },
+	{/* end of table */}
+};
+
+static int xylonfb_get_logicvc_configuration(struct xylonfb_data *data)
+{
+	struct device *dev = &data->pdev->dev;
+	struct device_node *dn = data->device;
+	const struct of_device_id *match;
+	struct videomode vm;
+	int i, ret;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	match = of_match_node(logicvc_of_match, dn);
+	if (!match) {
+		dev_err(dev, "failed match logicvc\n");
+		return -ENODEV;
+	}
+
+	ret = of_address_to_resource(dn, 0, &data->resource_mem);
+	if (ret) {
+		dev_err(dev, "failed get mem resource\n");
+		return ret;
+	}
+	data->irq = of_irq_to_resource(dn, 0, &data->resource_irq);
+	if (data->irq = 0) {
+		dev_err(dev, "failed get irq resource\n");
+		return ret;
+	}
+
+	ret = xylon_parse_hw_info(dn, data);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < LOGICVC_MAX_LAYERS; i++) {
+		ret = xylonfb_parse_layer_info(dn, data, i);
+		if (ret < 0)
+			return ret;
+		if (ret = 0)
+			break;
+	}
+
+	if (data->flags & XYLONFB_FLAGS_BACKGROUND_LAYER &&
+	    data->layers = LOGICVC_MAX_LAYERS) {
+		data->flags &= ~XYLONFB_FLAGS_BACKGROUND_LAYER;
+		data->layers--;
+		if (data->console_layer = data->layers)
+			data->console_layer--;
+
+		dev_warn(dev, "invalid last layer configuration\n");
+	}
+
+	memset(&vm, 0, sizeof(vm));
+
+	if (data->vm.name[0] = 0) {
+		ret = of_get_videomode(dn, &vm, OF_USE_NATIVE_MODE);
+		if (!ret) {
+			fb_videomode_from_videomode(&vm, &data->vm.vmode);
+
+			sprintf(data->vm.name, "%dx%d",
+				data->vm.vmode.xres, data->vm.vmode.yres);
+
+			data->flags |= XYLONFB_FLAGS_VMODE_CUSTOM;
+		}
+	}
+
+	xylonfb_init_ctrl(dn, vm.flags, &data->vm.ctrl);
+
+	return 0;
+}
+
+static int xylonfb_get_driver_configuration(struct xylonfb_data *data)
+{
+	struct device *dev = &data->pdev->dev;
+	struct device_node *dn = data->pdev->dev.of_node;
+	int ret;
+	const char *string;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	data->device = of_parse_phandle(dn, "device", 0);
+	if (!data->device) {
+		dev_err(dev, "failed get device\n");
+		return -ENODEV;
+	}
+
+	data->pixel_clock = of_parse_phandle(dn, "clocks", 0);
+
+	ret = of_property_read_u32(dn, "console-layer", &data->console_layer);
+	if (ret && (ret != -EINVAL)) {
+			dev_err(dev, "failed get console-layer\n");
+			return ret;
+	} else {
+		data->flags |= XYLONFB_FLAGS_CHECK_CONSOLE_LAYER;
+	}
+
+	if (of_property_read_bool(dn, "vsync-irq"))
+		data->flags |= XYLONFB_FLAGS_VSYNC_IRQ;
+
+	ret = of_property_read_string(dn, "video-mode", &string);
+	if (ret && (ret != -EINVAL)) {
+		dev_err(dev, "failed get video-mode\n");
+		return ret;
+	} else if (ret = 0) {
+		strcpy(data->vm.name, string);
+		return 0;
+	}
+
+	return 0;
+}
+
+static int xylonfb_probe(struct platform_device *pdev)
+{
+	struct xylonfb_data *data;
+	int ret;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	data = devm_kzalloc(&pdev->dev, sizeof(struct xylonfb_data),
+			     GFP_KERNEL);
+	if (!data) {
+		dev_err(&pdev->dev, "failed allocate init data\n");
+		return -ENOMEM;
+	}
+
+	data->pdev = pdev;
+
+	ret = xylonfb_get_driver_configuration(data);
+	if (ret)
+		goto xylonfb_probe_error;
+
+	ret = xylonfb_get_logicvc_configuration(data);
+	if (ret)
+		goto xylonfb_probe_error;
+
+	ret = xylonfb_init_core(data);
+
+xylonfb_probe_error:
+	return ret;
+}
+
+static int xylonfb_remove(struct platform_device *pdev)
+{
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	return xylonfb_deinit_core(pdev);
+}
+
+static const struct of_device_id xylonfb_of_match[] = {
+	{ .compatible = "xylon,fb-3.00.a" },
+	{/* end of table */},
+};
+MODULE_DEVICE_TABLE(of, xylonfb_of_match);
+
+static struct platform_driver xylonfb_driver = {
+	.probe = xylonfb_probe,
+	.remove = xylonfb_remove,
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = XYLONFB_DEVICE_NAME,
+		.of_match_table = xylonfb_of_match,
+	},
+};
+
+static int xylonfb_get_params(char *options)
+{
+	char *this_opt;
+
+	XYLONFB_DBG(INFO, "%s", __func__);
+
+	if (!options || !*options)
+		return 0;
+
+	while ((this_opt = strsep(&options, ",")) != NULL) {
+		if (!*this_opt)
+			continue;
+		xylonfb_mode_option = this_opt;
+	}
+	return 0;
+}
+
+static int xylonfb_init(void)
+{
+	char *option = NULL;
+	/*
+	 *  Kernel boot options (in 'video=xxxfb:<options>' format)
+	 */
+	if (fb_get_options(XYLONFB_DRIVER_NAME, &option))
+		return -ENODEV;
+	/* Set internal module parameters */
+	xylonfb_get_params(option);
+
+	if (platform_driver_register(&xylonfb_driver)) {
+		pr_err("failed %s driver registration\n", XYLONFB_DRIVER_NAME);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static void __exit xylonfb_exit(void)
+{
+	platform_driver_unregister(&xylonfb_driver);
+}
+
+module_init(xylonfb_init);
+module_exit(xylonfb_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION(XYLONFB_DRIVER_DESCRIPTION);
+MODULE_VERSION(XYLONFB_DRIVER_VERSION);
-- 
1.9.1


^ permalink raw reply related

* Add Xylon logiCVC framebuffer driver
From: Davor Joja @ 2015-03-11 15:27 UTC (permalink / raw)
  To: linux-kernel, linux-fbdev, tomi.valkeinen, geert

Hello,

I am sending the patch series to add support for Xylon logiCVC IP core device.
logiCVC is Configurable Video Controller developed and optimized for Xilinx 
FPGA devices.
Driver has been compiled and tested with kernel 3.18 on Zynq SoC, running fb
console and other graphics on single or multiple LCDs.

Kind regards,
Davor


^ permalink raw reply

* Re: [PATCH v2 6/6] staging: sm750fb: Remove spinlock helper function
From: Lorenzo Stoakes @ 2015-03-11 15:03 UTC (permalink / raw)
  To: Sudip Mukherjee; +Cc: teddy.wang, Greg KH, linux-fbdev, devel, linux-kernel
In-Reply-To: <20150311145841.GA30040@sudip-PC>

On 11 March 2015 at 14:58, Sudip Mukherjee <sudipm.mukherjee@gmail.com> wrote:
>
> tested the whole series on hardware, looks ok.
>

Great!

> now it depends on Greg if he wants to accept patches with such big
> commit logs, and another problem he will face is to get some patches from
> this thread and some from the old thread.
> (while testing i faced this problem to maintain the sequence of
>  patches)

I am more than happy to resend the whole series as necessary if that
makes it easier for Greg or anyone else :) I have previously
resubmitted an entire patch series only for people to find the v2
resubmits of unchanged code to be confusing. I am absolutely happy to
do whatever works for Greg of course!

Best,

-- 
Lorenzo Stoakes
https:/ljs.io

^ permalink raw reply

* Re: [PATCH v2 6/6] staging: sm750fb: Remove spinlock helper function
From: Sudip Mukherjee @ 2015-03-11 14:58 UTC (permalink / raw)
  To: Lorenzo Stoakes; +Cc: teddy.wang, gregkh, linux-fbdev, devel, linux-kernel
In-Reply-To: <1426070749-32024-3-git-send-email-lstoakes@gmail.com>

On Wed, Mar 11, 2015 at 10:45:49AM +0000, Lorenzo Stoakes wrote:
> This patch removes the unnecessary spinlock helper function and instead
> calls spin_lock and spin_unlock directly.
> 
> This does *not* resolve sparse warnings about context imbalances but these are
> spurious.

tested the whole series on hardware, looks ok.

now it depends on Greg if he wants to accept patches with such big
commit logs, and another problem he will face is to get some patches from
this thread and some from the old thread.
(while testing i faced this problem to maintain the sequence of
 patches)

regards
sudip

^ permalink raw reply

* Re: [PATCH v2 4/6] staging: sm750fb: Remove unused function
From: Sudip Mukherjee @ 2015-03-11 11:16 UTC (permalink / raw)
  To: Lorenzo Stoakes; +Cc: teddy.wang, Greg KH, linux-fbdev, devel, linux-kernel
In-Reply-To: <CAA5enKa6EHFPF9ebq6T4kJhsbXX35t4JgO=t6kxtPn9Jd_D81A@mail.gmail.com>

On Wed, Mar 11, 2015 at 10:59:41AM +0000, Lorenzo Stoakes wrote:
> On 11 March 2015 at 10:57, Sudip Mukherjee <sudipm.mukherjee@gmail.com> wrote:
> > but function prototype still remains in sm750_accel.h
> 
> No it doesn't, v2 of patch 3 in the series no longer puts it there :)
oops.. i am sorry.. i still had your previous patches applied thatiswhy
i got the prototype in sm750_accel.h

regards
sudip
> 
> -- 
> Lorenzo Stoakes
> https:/ljs.io

^ permalink raw reply

* Re: [PATCH v2 4/6] staging: sm750fb: Remove unused function
From: Lorenzo Stoakes @ 2015-03-11 10:59 UTC (permalink / raw)
  To: Sudip Mukherjee; +Cc: teddy.wang, Greg KH, linux-fbdev, devel, linux-kernel
In-Reply-To: <20150311105708.GG4560@sudip-PC>

On 11 March 2015 at 10:57, Sudip Mukherjee <sudipm.mukherjee@gmail.com> wrote:
> but function prototype still remains in sm750_accel.h

No it doesn't, v2 of patch 3 in the series no longer puts it there :)

-- 
Lorenzo Stoakes
https:/ljs.io

^ permalink raw reply

* Re: [PATCH v2 4/6] staging: sm750fb: Remove unused function
From: Sudip Mukherjee @ 2015-03-11 10:57 UTC (permalink / raw)
  To: Lorenzo Stoakes; +Cc: teddy.wang, gregkh, linux-fbdev, devel, linux-kernel
In-Reply-To: <1426070749-32024-2-git-send-email-lstoakes@gmail.com>

On Wed, Mar 11, 2015 at 10:45:48AM +0000, Lorenzo Stoakes wrote:
> This patch removes the unused hw712_fillrect function. This patch fixes
> the following sparse warning:-
> 
> drivers/staging/sm750fb/sm750_accel.c:95:5: warning: symbol 'hw712_fillrect' was not declared. Should it be static?
> 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
> ---
>  drivers/staging/sm750fb/sm750_accel.c | 78 -----------------------------------
>  1 file changed, 78 deletions(-)
> 
> diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c
> index 6521c3b..c5a3726 100644
> --- a/drivers/staging/sm750fb/sm750_accel.c
> +++ b/drivers/staging/sm750fb/sm750_accel.c

but function prototype still remains in sm750_accel.h 

regards
sudip

^ permalink raw reply

* Re: [PATCH 1/6] staging: sm750fb: Use memset_io instead of memset
From: Sudip Mukherjee @ 2015-03-11 10:47 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: Dan Carpenter, teddy.wang, Greg KH, devel, linux-fbdev,
	linux-kernel
In-Reply-To: <20150311094806.GE4560@sudip-PC>

On Wed, Mar 11, 2015 at 03:18:06PM +0530, Sudip Mukherjee wrote:
> On Wed, Mar 11, 2015 at 09:11:52AM +0000, Lorenzo Stoakes wrote:
> > On 11 March 2015 at 08:54, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> > > Btw, do you have this hardware?  Are you able to test these changes?
> > 
> > Unfortunately not, I am trying to keep these changes as simple code
> > fixes that ought not to affect actual hardware behaviour as I can
> > (though of course you can never be entirely sure that's the case!)
> > 
> > I suspect that Sudip must have some real hardware, is this the case
> > Sudip? If it isn't too presumptuous of me to ask, perhaps you might be
> > able to check patches that are successfully merged into
> > staging-testing?
> yes, i have the hardware and will test on it. but your patch 5/6 and
> 6/6 is scaring me :)

i think i will better check v2 of your series on hardware, and while
you are preparing that v2 keep in mind the changelog should not exceed
72 characters. in your this series for all patches it was more than
that.

regards
sudip

> 
> regards
> sudip
> > 
> > Best,
> > 
> > -- 
> > Lorenzo Stoakes
> > https:/ljs.io

^ permalink raw reply

* [PATCH v2 6/6] staging: sm750fb: Remove spinlock helper function
From: Lorenzo Stoakes @ 2015-03-11 10:45 UTC (permalink / raw)
  To: sudipm.mukherjee, teddy.wang, gregkh
  Cc: linux-fbdev, devel, linux-kernel, Lorenzo Stoakes
In-Reply-To: <1426070749-32024-1-git-send-email-lstoakes@gmail.com>

This patch removes the unnecessary spinlock helper function and instead
calls spin_lock and spin_unlock directly.

This does *not* resolve sparse warnings about context imbalances but these are
spurious.

Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
---
 drivers/staging/sm750fb/sm750.c | 47 +++++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 23 deletions(-)

diff --git a/drivers/staging/sm750fb/sm750.c b/drivers/staging/sm750fb/sm750.c
index 3e36b6a..217795e 100644
--- a/drivers/staging/sm750fb/sm750.c
+++ b/drivers/staging/sm750fb/sm750.c
@@ -56,23 +56,6 @@ static char * g_settings = NULL;
 static int g_dualview = 0;
 static char * g_option = NULL;
 
-/* if not use spin_lock,system will die if user load driver
- * and immediatly unload driver frequently (dual)*/
-static inline void myspin_lock(spinlock_t * sl){
-	struct lynx_share * share;
-	share = container_of(sl,struct lynx_share,slock);
-	if(share->dual){
-		spin_lock(sl);
-	}
-}
-
-static inline void myspin_unlock(spinlock_t * sl){
-	struct lynx_share * share;
-	share = container_of(sl,struct lynx_share,slock);
-	if(share->dual){
-		spin_unlock(sl);
-	}
-}
 static const struct fb_videomode lynx750_ext[] = {
 	/*  	1024x600-60 VESA 	[1.71:1]	*/
 	{NULL,  60, 1024, 600, 20423, 144,  40, 18, 1, 104, 3,
@@ -209,13 +192,19 @@ static void lynxfb_ops_fillrect(struct fb_info* info,const struct fb_fillrect* r
 	color = (Bpp = 1)?region->color:((u32*)info->pseudo_palette)[region->color];
 	rop = ( region->rop != ROP_COPY ) ? HW_ROP2_XOR:HW_ROP2_COPY;
 
-	myspin_lock(&share->slock);
+	/* if not use spin_lock,system will die if user load driver
+	 * and immediatly unload driver frequently (dual)*/
+	if (share->dual)
+		spin_lock(&share->slock);
+
 	share->accel.de_fillrect(&share->accel,
 							base,pitch,Bpp,
 							region->dx,region->dy,
 							region->width,region->height,
 							color,rop);
-	myspin_unlock(&share->slock);
+
+	if (share->dual)
+		spin_unlock(&share->slock);
 }
 
 static void lynxfb_ops_copyarea(struct fb_info * info,const struct fb_copyarea * region)
@@ -233,12 +222,18 @@ static void lynxfb_ops_copyarea(struct fb_info * info,const struct fb_copyarea *
 	pitch = info->fix.line_length;
 	Bpp = info->var.bits_per_pixel >> 3;
 
-	myspin_lock(&share->slock);
+	/* if not use spin_lock,system will die if user load driver
+	 * and immediatly unload driver frequently (dual)*/
+	if (share->dual)
+		spin_lock(&share->slock);
+
 	share->accel.de_copyarea(&share->accel,
 							base,pitch,region->sx,region->sy,
 							base,pitch,Bpp,region->dx,region->dy,
 							region->width,region->height,HW_ROP2_COPY);
-	myspin_unlock(&share->slock);
+
+	if (share->dual)
+		spin_unlock(&share->slock);
 }
 
 static void lynxfb_ops_imageblit(struct fb_info*info,const struct fb_image* image)
@@ -272,14 +267,20 @@ static void lynxfb_ops_imageblit(struct fb_info*info,const struct fb_image* imag
 	}
 	return;
 _do_work:
-	myspin_lock(&share->slock);
+	/* if not use spin_lock,system will die if user load driver
+	 * and immediatly unload driver frequently (dual)*/
+	if (share->dual)
+		spin_lock(&share->slock);
+
 	share->accel.de_imageblit(&share->accel,
 					image->data,image->width>>3,0,
 					base,pitch,Bpp,
 					image->dx,image->dy,
 					image->width,image->height,
 					fgcol,bgcol,HW_ROP2_COPY);
-	myspin_unlock(&share->slock);
+
+	if (share->dual)
+		spin_unlock(&share->slock);
 }
 
 static int lynxfb_ops_pan_display(struct fb_var_screeninfo *var,
-- 
2.3.2


^ permalink raw reply related

* [PATCH v2 4/6] staging: sm750fb: Remove unused function
From: Lorenzo Stoakes @ 2015-03-11 10:45 UTC (permalink / raw)
  To: sudipm.mukherjee, teddy.wang, gregkh
  Cc: linux-fbdev, devel, linux-kernel, Lorenzo Stoakes
In-Reply-To: <1426070749-32024-1-git-send-email-lstoakes@gmail.com>

This patch removes the unused hw712_fillrect function. This patch fixes
the following sparse warning:-

drivers/staging/sm750fb/sm750_accel.c:95:5: warning: symbol 'hw712_fillrect' was not declared. Should it be static?

Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
---
 drivers/staging/sm750fb/sm750_accel.c | 78 -----------------------------------
 1 file changed, 78 deletions(-)

diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c
index 6521c3b..c5a3726 100644
--- a/drivers/staging/sm750fb/sm750_accel.c
+++ b/drivers/staging/sm750fb/sm750_accel.c
@@ -89,84 +89,6 @@ void hw_set2dformat(struct lynx_accel * accel,int fmt)
 	write_dpr(accel,DE_STRETCH_FORMAT,reg);
 }
 
-/* seems sm712 RectFill command is broken,so need use BitBlt to
- * replace it. */
-
-int hw712_fillrect(struct lynx_accel * accel,
-				u32 base,u32 pitch,u32 Bpp,
-				u32 x,u32 y,u32 width,u32 height,
-				u32 color,u32 rop)
-{
-	u32 deCtrl;
-	if(accel->de_wait() != 0)
-	{
-		/* int time wait and always busy,seems hardware
-		 * got something error */
-		pr_debug("%s:De engine always bussy\n",__func__);
-		return -1;
-	}
-	/* 24bpp 2d acceleration still not work,we already support 2d on
-	 * both 8/16/32 bpp now, so there is no harm if we disable 2d on
-	 * 24bpp for current stage. */
-#if 0
-	if(Bpp = 3){
-		width *= 3;
-		x *= 3;
-		write_dpr(accel,DE_PITCH,
-			FIELD_VALUE(0,DE_PITCH,DESTINATION,pitch)|
-			FIELD_VALUE(0,DE_PITCH,SOURCE,pitch));//dpr10
-	}
-	else
-#endif
-	{
-		write_dpr(accel,DE_PITCH,
-			FIELD_VALUE(0,DE_PITCH,DESTINATION,pitch/Bpp)|
-			FIELD_VALUE(0,DE_PITCH,SOURCE,pitch/Bpp));//dpr10
-
-	}
-
-	write_dpr(accel,DE_FOREGROUND,color);//DPR14
-	write_dpr(accel,DE_MONO_PATTERN_HIGH,~0);//DPR34
-	write_dpr(accel,DE_MONO_PATTERN_LOW,~0);//DPR38
-
-	write_dpr(accel,DE_WINDOW_SOURCE_BASE,base);//dpr44
-	write_dpr(accel,DE_WINDOW_DESTINATION_BASE,base);//dpr40
-
-
-	write_dpr(accel,DE_WINDOW_WIDTH,
-			FIELD_VALUE(0,DE_WINDOW_WIDTH,DESTINATION,pitch/Bpp)|
-			FIELD_VALUE(0,DE_WINDOW_WIDTH,SOURCE,pitch/Bpp));//dpr3c
-
-
-	write_dpr(accel,DE_DESTINATION,
-			FIELD_SET(0,DE_DESTINATION,WRAP,DISABLE)|
-			FIELD_VALUE(0,DE_DESTINATION,X,x)|
-			FIELD_VALUE(0,DE_DESTINATION,Y,y));//dpr4
-
-	write_dpr(accel,DE_DIMENSION,
-			FIELD_VALUE(0,DE_DIMENSION,X,width)|
-			FIELD_VALUE(0,DE_DIMENSION,Y_ET,height));//dpr8
-
-	deCtrl -		FIELD_SET(0,DE_CONTROL,STATUS,START)|
-		FIELD_SET(0,DE_CONTROL,COMMAND,BITBLT)|
-		FIELD_SET(0,DE_CONTROL,ROP2_SOURCE,PATTERN)|
-		FIELD_SET(0,DE_CONTROL,ROP_SELECT,ROP2)|
-		FIELD_VALUE(0,DE_CONTROL,ROP,rop);//dpr0xc
-#if 0
-		/* dump registers */
-		int i;
-		inf_msg("x,y,w,h = %d,%d,%d,%d\n",x,y,width,height);
-		for(i=0x04;i<=0x44;i+=4){
-			inf_msg("dpr%02x = %08x\n",i,read_dpr(accel,i));
-		}
-		inf_msg("deCtrl = %08x\n",deCtrl);
-#endif
-
-	write_dpr(accel,DE_CONTROL,deCtrl);
-	return 0;
-}
-
 int hw_fillrect(struct lynx_accel * accel,
 				u32 base,u32 pitch,u32 Bpp,
 				u32 x,u32 y,u32 width,u32 height,
-- 
2.3.2


^ permalink raw reply related

* [PATCH v2 3/6] staging: sm750fb: Make internal functions static
From: Lorenzo Stoakes @ 2015-03-11 10:45 UTC (permalink / raw)
  To: sudipm.mukherjee, teddy.wang, gregkh
  Cc: linux-fbdev, devel, linux-kernel, Lorenzo Stoakes

This patch declares externally unavailable functions static. This fixes
the following sparse warnings:-

drivers/staging/sm750fb/ddk750_swi2c.c:223:6: warning: symbol 'swI2CStart' was not declared. Should it be static?
drivers/staging/sm750fb/ddk750_swi2c.c:234:6: warning: symbol 'swI2CStop' was not declared. Should it be static?
drivers/staging/sm750fb/ddk750_swi2c.c:252:6: warning: symbol 'swI2CWriteByte' was not declared. Should it be static?
drivers/staging/sm750fb/ddk750_swi2c.c:320:15: warning: symbol 'swI2CReadByte' was not declared. Should it be static?
drivers/staging/sm750fb/ddk750_swi2c.c:361:6: warning: symbol 'swI2CInit_SM750LE' was not declared. Should it be static?
drivers/staging/sm750fb/ddk750_hwi2c.c:63:6: warning: symbol 'hwI2CWaitTXDone' was not declared. Should it be static?
drivers/staging/sm750fb/ddk750_hwi2c.c:93:14: warning: symbol 'hwI2CWriteData' was not declared. Should it be static?
drivers/staging/sm750fb/ddk750_hwi2c.c:160:14: warning: symbol 'hwI2CReadData' was not declared. Should it be static?

Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
---
 drivers/staging/sm750fb/ddk750_hwi2c.c |  6 +++---
 drivers/staging/sm750fb/ddk750_swi2c.c | 10 +++++-----
 drivers/staging/sm750fb/sm750_accel.c  |  2 +-
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/staging/sm750fb/ddk750_hwi2c.c b/drivers/staging/sm750fb/ddk750_hwi2c.c
index 84dfb6f..7826376 100644
--- a/drivers/staging/sm750fb/ddk750_hwi2c.c
+++ b/drivers/staging/sm750fb/ddk750_hwi2c.c
@@ -60,7 +60,7 @@ void hwI2CClose(void)
 }
 
 
-long hwI2CWaitTXDone(void)
+static long hwI2CWaitTXDone(void)
 {
     unsigned int timeout;
 
@@ -90,7 +90,7 @@ long hwI2CWaitTXDone(void)
  *  Return Value:
  *      Total number of bytes those are actually written.
  */
-unsigned int hwI2CWriteData(
+static unsigned int hwI2CWriteData(
     unsigned char deviceAddress,
     unsigned int length,
     unsigned char *pBuffer
@@ -157,7 +157,7 @@ unsigned int hwI2CWriteData(
  *  Return Value:
  *      Total number of actual bytes read from the slave device
  */
-unsigned int hwI2CReadData(
+static unsigned int hwI2CReadData(
     unsigned char deviceAddress,
     unsigned int length,
     unsigned char *pBuffer
diff --git a/drivers/staging/sm750fb/ddk750_swi2c.c b/drivers/staging/sm750fb/ddk750_swi2c.c
index 1249759..516f5bb 100644
--- a/drivers/staging/sm750fb/ddk750_swi2c.c
+++ b/drivers/staging/sm750fb/ddk750_swi2c.c
@@ -220,7 +220,7 @@ static void swI2CAck(void)
 /*
  *  This function sends the start command to the slave device
  */
-void swI2CStart(void)
+static void swI2CStart(void)
 {
     /* Start I2C */
     swI2CSDA(1);
@@ -231,7 +231,7 @@ void swI2CStart(void)
 /*
  *  This function sends the stop command to the slave device
  */
-void swI2CStop(void)
+static void swI2CStop(void)
 {
     /* Stop the I2C */
     swI2CSCL(1);
@@ -249,7 +249,7 @@ void swI2CStop(void)
  *       0   - Success
  *      -1   - Fail to write byte
  */
-long swI2CWriteByte(unsigned char data)
+static long swI2CWriteByte(unsigned char data)
 {
     unsigned char value = data;
     int i;
@@ -317,7 +317,7 @@ long swI2CWriteByte(unsigned char data)
  *  Return Value:
  *      One byte data read from the Slave device
  */
-unsigned char swI2CReadByte(unsigned char ack)
+static unsigned char swI2CReadByte(unsigned char ack)
 {
     int i;
     unsigned char data = 0;
@@ -358,7 +358,7 @@ unsigned char swI2CReadByte(unsigned char ack)
  *      -1   - Fail to initialize the i2c
  *       0   - Success
  */
-long swI2CInit_SM750LE(
+static long swI2CInit_SM750LE(
     unsigned char i2cClkGPIO,
     unsigned char i2cDataGPIO
 )
-- 
2.3.2


^ permalink raw reply related

* Re: [PATCH 1/6] staging: sm750fb: Use memset_io instead of memset
From: Lorenzo Stoakes @ 2015-03-11 10:41 UTC (permalink / raw)
  To: Sudip Mukherjee
  Cc: Dan Carpenter, teddy.wang, Greg KH, devel, linux-fbdev,
	linux-kernel
In-Reply-To: <20150311103542.GF4560@sudip-PC>

On 11 March 2015 at 10:35, Sudip Mukherjee
> i think i will better check v2 of your series on hardware

This is incoming in just a moment (though I only v2 patches in the
series I've changed which I think is the right way to make
modifications with a patch series.)

> , and while
> you are preparing that v2 keep in mind the changelog should not exceed
> 72 characters. in your this series for all patches it was more than
> that.

I will update the messages in the changed patches accordingly, I'm not
sure this is worth a resend of all previous patches for however? I do
see quite a few patches in the log that exceed this.

Additionally, I suspect it would make the patches less readable to
wrap sparse warning lines so I think those ought to sit outside of
this limit.

I am more than happy to change these though if these ought to be kept
*strictly* to a 72 character limit throughout?

Best,

-- 
Lorenzo Stoakes
https:/ljs.io

^ permalink raw reply

* Re: [PATCH 4/6] staging: sm750fb: Expose hw712_fillrect externally
From: Sudip Mukherjee @ 2015-03-11  9:49 UTC (permalink / raw)
  To: Lorenzo Stoakes; +Cc: teddy.wang, gregkh, linux-fbdev, devel, linux-kernel
In-Reply-To: <1426037325-8392-4-git-send-email-lstoakes@gmail.com>

On Wed, Mar 11, 2015 at 01:28:43AM +0000, Lorenzo Stoakes wrote:
> 
> diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c
> index 4aa763b..6521c3b 100644
> --- a/drivers/staging/sm750fb/sm750_accel.c
> +++ b/drivers/staging/sm750fb/sm750_accel.c
> @@ -92,7 +92,7 @@ void hw_set2dformat(struct lynx_accel * accel,int fmt)
>  /* seems sm712 RectFill command is broken,so need use BitBlt to
>   * replace it. */
>  
> -static int hw712_fillrect(struct lynx_accel * accel,
> +int hw712_fillrect(struct lynx_accel * accel,
>  				u32 base,u32 pitch,u32 Bpp,
>  				u32 x,u32 y,u32 width,u32 height,
>  				u32 color,u32 rop)
in your previous patch 3/6 you made it static now you are again
removing the static keyword. may i ask why you changed it in 3/6 if you
again change it back to original in this patch?
anyways, like Dan said, delete this function, its not used anywhere.
it will not be used also, i missed removing this function from the
vendor crude drver.

regards
sudip

> 

^ permalink raw reply

* Re: [PATCH 1/6] staging: sm750fb: Use memset_io instead of memset
From: Sudip Mukherjee @ 2015-03-11  9:48 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: Dan Carpenter, teddy.wang, Greg KH, devel, linux-fbdev,
	linux-kernel
In-Reply-To: <CAA5enKaWynLvLUN+GCdphOOMmqX+cAj3kA3owjKbng66CK=pqg@mail.gmail.com>

On Wed, Mar 11, 2015 at 09:11:52AM +0000, Lorenzo Stoakes wrote:
> On 11 March 2015 at 08:54, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> > Btw, do you have this hardware?  Are you able to test these changes?
> 
> Unfortunately not, I am trying to keep these changes as simple code
> fixes that ought not to affect actual hardware behaviour as I can
> (though of course you can never be entirely sure that's the case!)
> 
> I suspect that Sudip must have some real hardware, is this the case
> Sudip? If it isn't too presumptuous of me to ask, perhaps you might be
> able to check patches that are successfully merged into
> staging-testing?
yes, i have the hardware and will test on it. but your patch 5/6 and
6/6 is scaring me :)

regards
sudip
> 
> Best,
> 
> -- 
> Lorenzo Stoakes
> https:/ljs.io

^ permalink raw reply

* Re: [PATCH 3/6] staging: sm750fb: Make internal functions static
From: Sudip Mukherjee @ 2015-03-11  9:42 UTC (permalink / raw)
  To: Lorenzo Stoakes; +Cc: teddy.wang, gregkh, linux-fbdev, devel, linux-kernel
In-Reply-To: <1426037325-8392-3-git-send-email-lstoakes@gmail.com>

On Wed, Mar 11, 2015 at 01:28:42AM +0000, Lorenzo Stoakes wrote:
> This patch declares externally unavailable functions static. This fixes the
> following sparse warnings:-
<snip>
> diff --git a/drivers/staging/sm750fb/sm750_accel.c b/drivers/staging/sm750fb/sm750_accel.c
> index 6521c3b..4aa763b 100644
> --- a/drivers/staging/sm750fb/sm750_accel.c
> +++ b/drivers/staging/sm750fb/sm750_accel.c
> @@ -92,7 +92,7 @@ void hw_set2dformat(struct lynx_accel * accel,int fmt)
>  /* seems sm712 RectFill command is broken,so need use BitBlt to
>   * replace it. */
>  
> -int hw712_fillrect(struct lynx_accel * accel,
> +static int hw712_fillrect(struct lynx_accel * accel,
>  				u32 base,u32 pitch,u32 Bpp,
>  				u32 x,u32 y,u32 width,u32 height,
>  				u32 color,u32 rop)
this is introducing a build warning, better remove this from your patch
and send a separate patch to remove the function as this function is
not used anywhere.

regards
sudip

> -- 
> 2.3.2
> 

^ permalink raw reply

* Re: [PATCH 4/6] staging: sm750fb: Expose hw712_fillrect externally
From: Lorenzo Stoakes @ 2015-03-11  9:39 UTC (permalink / raw)
  To: Sudip Mukherjee; +Cc: teddy.wang, Greg KH, linux-fbdev, devel, linux-kernel
In-Reply-To: <20150311093728.GD4560@sudip-PC>

On 11 March 2015 at 09:37, Sudip Mukherjee <sudipm.mukherjee@gmail.com> wrote:
> in your previous patch 3/6 you made it static now you are again
> removing the static keyword. may i ask why you changed it in 3/6 if you
> again change it back to original in this patch?

There's no good reason, it's just a mistake :) I'll fix it shortly.

> anyways, like Dan said, delete this function, its not used anywhere.
> it will not be used also, i missed removing this function from the
> vendor crude drver.

Will do!

Best,
-- 
Lorenzo Stoakes
https:/ljs.io

^ permalink raw reply

* Re: [PATCH 3/6] staging: sm750fb: Make internal functions static
From: Lorenzo Stoakes @ 2015-03-11  9:38 UTC (permalink / raw)
  To: Sudip Mukherjee; +Cc: teddy.wang, Greg KH, linux-fbdev, devel, linux-kernel
In-Reply-To: <20150311093001.GC4560@sudip-PC>

On 11 March 2015 at 09:30, Sudip Mukherjee
> this is introducing a build warning, better remove this from your patch
> and send a separate patch to remove the function as this function is
> not used anywhere.

Hi Sudip,

I didn't realise I'd included the move to static in this patch. In a
later patch I expose this function in the header file. I'll update
this patch not to touch hw712_fillrect then remove it in a later patch
altogether.

Best,

-- 
Lorenzo Stoakes
https:/ljs.io

^ permalink raw reply

* Re: [PATCH 1/6] staging: sm750fb: Use memset_io instead of memset
From: Dan Carpenter @ 2015-03-11  9:23 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: Sudip Mukherjee, teddy.wang, Greg KH, devel, linux-fbdev,
	linux-kernel
In-Reply-To: <CAA5enKaWynLvLUN+GCdphOOMmqX+cAj3kA3owjKbng66CK=pqg@mail.gmail.com>

On Wed, Mar 11, 2015 at 09:11:52AM +0000, Lorenzo Stoakes wrote:
> On 11 March 2015 at 08:54, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> > When I see a patch like this, then I worry, "What if the Sparse
> > annotations are wrong?  The patch description doesn't say anything about
> > that."  After review then I think the annotations are correct so that's
> > fine.
> 
> How do you mean? I was careful to check what sparse was referring to,
> then investigate how memset should be used with pointers with a
> __iomem qualifier. I'd like to be able to improve my patch
> descriptions going forward as best I can :)
> 

Yes.  The patch is correct.  I wasn't asking you to redo it.  From later
patches it's actually clear that you know that this change is a bugfix
and a behavior change.  But we get a lot of patches where people just
randomly change things to please Sparse and it maybe silences a warning
but it's not correct.  I can think of a few recentish examples where
people used standard struct types which hold __iomem or __user pointers
but they used them in non-standard ways so the pointers were actually
normal kernel pointers.

I guess the rule here is that the patch should explain the effect of the
bugfix for the user.  Often you won't know the effect, but it's a
helpful thing to think about.

> > Btw, do you have this hardware?  Are you able to test these changes?
> 
> Unfortunately not, I am trying to keep these changes as simple code
> fixes that ought not to affect actual hardware behaviour as I can
> (though of course you can never be entirely sure that's the case!)

That's fine.  I was just wondering.  It affects how paranoid I am when I
review the code.

regards,
dan carpenter


^ permalink raw reply

* Re: [PATCH 1/6] staging: sm750fb: Use memset_io instead of memset
From: Lorenzo Stoakes @ 2015-03-11  9:11 UTC (permalink / raw)
  To: Dan Carpenter
  Cc: Sudip Mukherjee, teddy.wang, Greg KH, devel, linux-fbdev,
	linux-kernel
In-Reply-To: <20150311085433.GU10964@mwanda>

On 11 March 2015 at 08:54, Dan Carpenter <dan.carpenter@oracle.com> wrote:
> When I see a patch like this, then I worry, "What if the Sparse
> annotations are wrong?  The patch description doesn't say anything about
> that."  After review then I think the annotations are correct so that's
> fine.

How do you mean? I was careful to check what sparse was referring to,
then investigate how memset should be used with pointers with a
__iomem qualifier. I'd like to be able to improve my patch
descriptions going forward as best I can :)

> Btw, do you have this hardware?  Are you able to test these changes?

Unfortunately not, I am trying to keep these changes as simple code
fixes that ought not to affect actual hardware behaviour as I can
(though of course you can never be entirely sure that's the case!)

I suspect that Sudip must have some real hardware, is this the case
Sudip? If it isn't too presumptuous of me to ask, perhaps you might be
able to check patches that are successfully merged into
staging-testing?

Best,

-- 
Lorenzo Stoakes
https:/ljs.io

^ permalink raw reply

* Re: [PATCH 6/6] staging: sm750fb: Spinlock and unlock in the same block
From: Dan Carpenter @ 2015-03-11  9:09 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: sudipm.mukherjee, teddy.wang, gregkh, devel, linux-fbdev,
	linux-kernel
In-Reply-To: <1426037325-8392-6-git-send-email-lstoakes@gmail.com>

On Wed, Mar 11, 2015 at 01:28:45AM +0000, Lorenzo Stoakes wrote:
> -static inline void myspin_lock(spinlock_t * sl){
> -	struct lynx_share * share;
> -	share = container_of(sl,struct lynx_share,slock);
> -	if(share->dual){
> -		spin_lock(sl);
> -	}
> -}

Yes, good.  We all hate locking wrappers but these are worse than
normal.

> +	/* if not use spin_lock,system will die if user load driver
> +	 * and immediatly unload driver frequently (dual)*/
> +	if (share->dual) {
> +		spin_lock(&share->slock);
> +		share->accel.de_fillrect(&share->accel,
> +					base,pitch,Bpp,
> +					region->dx,region->dy,
> +					region->width,region->height,
> +					color,rop);
> +		spin_unlock(&share->slock);
> +	} else
> +		share->accel.de_fillrect(&share->accel,
> +					base,pitch,Bpp,
> +					region->dx,region->dy,
> +					region->width,region->height,
> +					color,rop);
>  }

No.  You've made the code uglier to work around Sparse stupidness.  Also
the braces are not according to kernel style.

	if (share->dual)
		spin_lock(&share->slock);

	share->accel.de_fillrect(&share->accel,
				 base,pitch,Bpp,
				 region->dx,region->dy,
				 region->width,region->height,
				 color,rop);

	if (share->dual)
		spin_unlock(&share->slock);

Sparse will still complain but no one cares.

regards,

^ permalink raw reply

* Re: [PATCH 3/3] staging: sm7xxfb: change return of sm7xx_vga_setup
From: Sudip Mukherjee @ 2015-03-11  8:59 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: Greg Kroah-Hartman, devel, linux-fbdev, linux-kernel
In-Reply-To: <20150309140414.GA11015@mwanda>

On Mon, Mar 09, 2015 at 05:04:14PM +0300, Dan Carpenter wrote:
> On Mon, Mar 09, 2015 at 07:23:43PM +0530, Sudip Mukherjee wrote:
<snip>
> > > Hm...  That's a good question.
> > > 
> > > I suspect we should just go with fb_get_mode() and do it quickly.  This
> > > driver is so new in the kernel that there are no users to get upset.
> >
> > i am afraid that is not correct. this driver was in staging from long
> > back, and Greg removed it from staging as no one was working with it.
> > But after that removal Lemote Yeeloong laptop of Steven Rostedt
> > stopped working. (https://lkml.org/lkml/2014/11/20/698) , so i guess
> > there will be many such users.
> 
> Hm...  I suspect we should still change it so it matches the other FB
> drivers but I don't know.
> 
> Perhaps Greg has an opinion?
maybe, i should make the change and then we can request Steven Rostedt
to test it on his Lemote Yeeloong. if nothing breaks, then alright,
else revert the patch.

regards
sudip

> 
> regards,
> dan carpenter
> 

^ permalink raw reply

* Re: [PATCH 6/6] staging: sm750fb: correct integer comparison
From: Sudip Mukherjee @ 2015-03-11  8:56 UTC (permalink / raw)
  To: Dan Carpenter; +Cc: Greg Kroah-Hartman, devel, linux-fbdev, linux-kernel
In-Reply-To: <20150311075743.GS10964@mwanda>

On Wed, Mar 11, 2015 at 10:57:43AM +0300, Dan Carpenter wrote:
> On Tue, Mar 10, 2015 at 10:46:57PM +0530, Sudip Mukherjee wrote:
> >  
> > -        while((opt = strsep(&src,":")) != NULL && *opt != NULL){
> > +        while((opt = strsep(&src,":")) != NULL && *opt != 0){
> 
> Use '\0' for the NUL char.
i got a doubt while making that patch, so i checked lib/string.c and
saw both 0 and '\0' are used.

regards
sudip
> 
> regards,
> dan carpenter

^ permalink raw reply

* Re: [PATCH 4/6] staging: sm750fb: Expose hw712_fillrect externally
From: Dan Carpenter @ 2015-03-11  8:56 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: sudipm.mukherjee, teddy.wang, gregkh, devel, linux-fbdev,
	linux-kernel
In-Reply-To: <1426037325-8392-4-git-send-email-lstoakes@gmail.com>

On Wed, Mar 11, 2015 at 01:28:43AM +0000, Lorenzo Stoakes wrote:
> This patch adds a reference to hw712_fillrect which is not used elsewhere in the driver,
> but appears to be an alternative to the hw_fillrect method. This patch fixes the following sparse warning:-
> 
> drivers/staging/sm750fb/sm750_accel.c:95:5: warning: symbol 'hw712_fillrect' was not declared. Should it be static?
> 

Just delete it.

regards,
dan carpenter


^ permalink raw reply

* Re: [PATCH 1/6] staging: sm750fb: Use memset_io instead of memset
From: Dan Carpenter @ 2015-03-11  8:54 UTC (permalink / raw)
  To: Lorenzo Stoakes
  Cc: sudipm.mukherjee, teddy.wang, gregkh, devel, linux-fbdev,
	linux-kernel
In-Reply-To: <1426037325-8392-1-git-send-email-lstoakes@gmail.com>

On Wed, Mar 11, 2015 at 01:28:40AM +0000, Lorenzo Stoakes wrote:
> This patch uses memset_io instead of memset when using memset on __iomem
> qualified pointers. This fixes the following sparse warnings:-
> 
> drivers/staging/sm750fb/sm750.c:489:17: warning: incorrect type in argument 1 (different address spaces)
> drivers/staging/sm750fb/sm750.c:490:17: warning: incorrect type in argument 1 (different address spaces)
> drivers/staging/sm750fb/sm750.c:501:17: warning: incorrect type in argument 1 (different address spaces)
> drivers/staging/sm750fb/sm750.c:502:17: warning: incorrect type in argument 1 (different address spaces)
> drivers/staging/sm750fb/sm750.c:833:5: warning: incorrect type in argument 1 (different address spaces)
> drivers/staging/sm750fb/sm750.c:1154:9: warning: incorrect type in argument 1 (different address spaces)
> 
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>

When I see a patch like this, then I worry, "What if the Sparse
annotations are wrong?  The patch description doesn't say anything about
that."  After review then I think the annotations are correct so that's
fine.

Btw, do you have this hardware?  Are you able to test these changes?

regards,
dan carpenter


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox