]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
Xilinx: ARM: video: adding framebuffer support
authorPallav Joshi <pallav.joshi@xilinx.com>
Tue, 29 Nov 2011 20:33:28 +0000 (02:03 +0530)
committerJohn Linn <john.linn@xilinx.com>
Fri, 2 Dec 2011 18:13:13 +0000 (10:13 -0800)
Frame buffer driver support added for Xylon IP.

Signed-off-by: Pallav Joshi <pallav.joshi@xilinx.com>
arch/arm/boot/dts/zynq-ep107-xylon.dts [new file with mode: 0755]
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/xylonfb.c [new file with mode: 0755]
drivers/video/xylonfb.h [new file with mode: 0755]

diff --git a/arch/arm/boot/dts/zynq-ep107-xylon.dts b/arch/arm/boot/dts/zynq-ep107-xylon.dts
new file mode 100755 (executable)
index 0000000..fcd11aa
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ *  Copyright (C) 2011 Xilinx
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "Xilinx Zynq EP107";
+       compatible = "xlnx,zynq-ep107";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       interrupt-parent = <&intc>;
+
+       memory {
+               device_type = "memory";
+               reg = <0x0 0xF000000>;
+       };
+
+       chosen {
+               bootargs = "console=ttyPS0,115200 root=/dev/ram rw initrd=0x800000,8M earlyprintk ip=:::::eth0:dhcp";
+               linux,stdout-path = "/amba@0/uart@E0000000";
+       };
+
+       amba: amba@0 {
+               compatible = "simple-bus";
+               #address-cells = <1>;
+               #size-cells = <1>;
+               ranges;
+
+               intc: intc@f8f01000 {
+                       interrupt-controller;
+                       compatible = "arm,gic";
+                       reg = <0xF8F01000 0x1000>;
+                       #interrupt-cells = <2>;
+               };
+
+               slcr: slcr@f8000000 {
+                       compatible = "xlnx,ps7-slcr-1.00.a";
+                       reg = <0xF8000000 0x1000>;
+               };
+
+               wdt0: swdt@f8005000 {
+                       device_type = "watchdog";
+                       compatible = "xlnx,ps7-wdt-1.00.a";
+                       reg = <0xF8005000 0x100>;
+               };
+
+               wdt1: scuwdt@f8f00620 {
+                       device_type = "watchdog";
+                       compatible = "xlnx,ps7-scuwdt-1.00.a";
+                       reg = <0xF8F00620 0x20>;
+               };
+       
+               uart0: uart@e0000000 {
+                       compatible = "xlnx,ps7-uart-1.00.a";
+                       reg = <0xE0000000 0x1000>;
+                       interrupts = <59 0>;
+                       clock = <50000000>;
+               };
+       
+               uart1: uart@e0001000 {
+                       compatible = "xlnx,ps7-uart-1.00.a";
+                       reg = <0xE0001000 0x1000>;
+                       interrupts = <82 0>;
+                       clock = <50000000>;
+               };
+       
+               spi0: spi@e0006000 {
+                       compatible = "xlnx,ps7-spi-1.00.a";
+                       reg = <0xE0006000 0x1000>;
+                       interrupts = <58 0>;
+                       speed-hz = <50000000>;
+                       bus-num = <0>;
+                       num-chip-select = <4>;
+               };
+
+               spi1: spi@e0007000 {
+                       compatible = "xlnx,ps7-spi-1.00.a";
+                       reg = <0xE0007000 0x1000>;
+                       interrupts = <81 0>;
+                       speed-hz = <50000000>;
+                       bus-num = <1>;
+                       num-chip-select = <4>;
+               };
+
+               qspi0: spi@e000d000 {
+                       compatible = "xlnx,ps7-qspi-1.00.a";
+                       reg = <0xE000D000 0x1000>;
+                       interrupts = <51 0>;
+                       speed-hz = <100000000>;
+                       bus-num = <2>;
+                       num-chip-select = <1>;
+                       is-dual = <0>;
+               };
+
+               i2c0: i2c@e0004000 {
+                       compatible = "xlnx,ps7-i2c-1.00.a";
+                       reg = <0xE0004000 0x1000>;
+                       interrupts = <57 0>;
+                       bus-id = <0>;
+                       input-clk = <50000000>;
+                       i2c-clk = <100000>;
+                       
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       m24c02_eeprom@50 {
+                               compatible = "at,24c02";
+                               reg = <0x50>;
+                       };
+
+                       rtc8564@51 {
+                               compatible = "rtc8564";
+                               reg = <0x51>;
+                       };
+               };
+
+               i2c1: i2c@e0005000 {
+                       compatible = "xlnx,ps7-i2c-1.00.a";
+                       reg = <0xE0005000 0x1000>;
+                       interrupts = <80 0>;
+                       bus-id = <1>;
+                       input-clk = <50000000>;
+                       i2c-clk = <100000>;
+
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       m24c02_eeprom@55 {
+                               compatible = "at,24c02";
+                               reg = <0x55>;
+                       };
+               };
+
+               gpio0: gpio@e000a000 {
+                       compatible = "xlnx,ps7-gpio-1.00.a";
+                       reg = <0xE000A000 0x1000>;
+                       interrupts = <52 0>;
+               };
+
+               sdhci0: sdhci@e0100000 {
+                       compatible = "generic-sdhci";
+                       reg = <0xE0100000 0x1000>;
+                       interrupts = <56 0>;
+               };
+
+               sdhci1: sdhci@e0101000 {
+                       compatible = "generic-sdhci";
+                       reg = <0xE0101000 0x1000>;
+                       interrupts = <79 0>;
+               };
+
+               nor: nor@e2000000 {
+                       compatible = "cfi-flash";
+                       bank-width = <1>;
+                       reg = <0xE2000000 0x2000000>;           /* 32MB */
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       partition@0 {
+                               label = "nor-fsbl";
+                               reg = <0x00000000 0x80000>;     /* 512K */
+                       };
+                       partition@1 {
+                               label = "nor-u-boot";
+                               reg = <0x80000 0x80000>;        /* 512K */
+                       };
+                       partition@2 {
+                               label = "nor-linux";
+                               reg = <0x100000 0x500000>;      /* 5 MB */
+                       };
+                       partition@3 {
+                               label = "nor-device-tree";
+                               reg = <0x600000 0x20000>;       /* 128K */
+                       };
+                       partition@4{
+                               label = "nor-user";
+                               reg = <0x620000 0x8E0000>;      /* 8875K */
+                       };
+                       partition@5{
+                               label = "nor-scratch";
+                               reg = <0xF00000 0x100000>;      /* 1 MB */
+                       };
+                       partition@6{
+                               label = "nor-rootfs";
+                               reg = <0x1000000 0x1000000>;    /* 16 MB */
+                       };
+                };
+
+               devcfg: devcfg@f8007000 {
+                       compatible = "xlnx,ps7-dev-cfg-1.00.a";
+                       reg = <0xF8007000 0x1000>;
+                       interrupts = <40 0>;
+               };
+               eth0: eth@e000b000 {
+                       compatible = "xlnx,ps7-ethernet-1.00.a";
+                       reg = <0xE000B000 0x1000>;
+                       interrupts = <54 0>;
+                       phy-handle = <&phy0>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       phy0: phy@23 {
+                               compatible = "marvell,88e1111";
+                               device_type = "ethernet-phy";
+                               reg = <23>;
+                       } ;
+               };
+
+               eth1: eth@e000c000 {
+                       compatible = "xlnx,ps7-ethernet-1.00.a";
+                       reg = <0xE000C000 0x1000>;
+                       interrupts = <77 0>;
+                       phy-handle = <&phy1>;
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       phy1: phy@16 {
+                               compatible = "marvell,88e1111";
+                               device_type = "ethernet-phy";
+                               reg = <16>;
+                       } ;
+               };
+
+               nand: nand@e1000000 {
+                       compatible = "xlnx,ps7-nand-1.00.a";
+                       reg = <0xE1000000 0x1000000 0xE000E000 0x1000>;
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       partition@0 {
+                               label = "nand-fsbl";
+                               reg = <0x00000000 0x100000>;    /* 1 MB */
+                       };
+                       partition@1 {
+                               label = "nand-u-boot";
+                               reg = <0x100000 0x100000>;      /* 1 MB */
+                       };
+                       partition@2 {
+                               label = "nand-linux";
+                               reg = <0x200000 0x500000>;      /* 5 MB */
+                       };
+                       partition@3 {
+                               label = "nand-device-tree";
+                               reg = <0x700000 0x20000>;       /* 128 KB */
+                       };
+                       partition@4 {
+                               label = "nand-user";
+                               reg = <0x720000 0xE0000>;       /* 896 KB */
+                       };
+                       partition@5 {
+                               label = "nand-scratch";
+                               reg = <0x800000 0x100000>;      /* 1 MB */
+                       };
+                       partition@6 {
+                               label = "nand-rootfs";
+                               reg = <0x900000 0x8000000>;     /* 128 MB */
+                       };
+                       partition@7 {
+                               label = "nand-bitstreams";
+                               reg = <0x8900000 0x7700000>;    /* 119 MB */
+                       };
+               };
+
+               usb@e0002000 {
+                       compatible = "xlnx,ps7-usb-1.00.a";
+                       reg = <0xe0002000 0x1000>;
+                       interrupts = <53 0>;
+                       dr_mode = "peripheral";
+                       phy_type = "ulpi";
+               };
+
+               usb@e0003000 {
+                       compatible = "xlnx,ps7-usb-1.00.a";
+                       reg = <0xe0003000 0x1000>;
+                       interrupts = <76 0>;
+                       dr_mode = "host";
+                       phy_type = "ulpi";
+               };
+               
+               logicvc_0: logicvc@40030000 {
+                       compatible = "xylon,logicvc-1.06.c";
+
+                       device-id = < 0 >;
+
+                       video-memory = < 0x0f000000 0xfffff >;
+                       reg = < 0x40030000 0xffff >;
+                       row-stride = < 1024 >;
+                       layers = < 4 >;
+                       use-background = < 1 >;
+                       readable-regs = < 1 >;
+                       use-size-position = < 1 >;
+                       display-type-no = < 7 >;
+
+                       layer_0: layer@0 {
+                               data-width = < 8 > ;
+                               alpha-mode = < 3 > ;
+                               offset = < 0 >;
+                               buffer-offset = < 512 >;
+                       };
+                       layer_1: layer@1 {
+                               data-width = < 16 > ;
+                               alpha-mode = < 0 > ;
+                               offset = < 512 >;
+                               buffer-offset = < 512 >;
+                       };
+                       layer_2: layer@2 {
+                               data-width = < 24 > ;
+                               alpha-mode = < 1 > ;
+                               offset = < 1024 >;
+                               buffer-offset = < 512 >;
+                       };
+                       layer_3: layer@3 {
+                               data-width = < 24 > ;
+                               alpha-mode = < 0 > ;
+                               offset = < 1024 >;
+                               buffer-offset = < 1024 >;
+                       };      
+               };
+               
+               logibitblt_0: logibitblt@40040000 {
+                       compatible = "xylon,logibitblt-3.00.a";
+
+                       reg = < 0x40040000 0xffff >;
+                       video-memory = < 0x0f000000 0x00ffffff >;
+
+                       use-move-neg = < 1 >;
+                       use-expand = < 1 >;
+                       use-patt-fill = < 1 >;
+                       use-rle = < 1 >;
+                       use-porter-duff = < 1 >;
+                       use-aa-font-expand = < 1 >;
+                       use-global-alpha = < 1 >;
+               };              
+       };
+};
index 894ba3c425bf3f784b374cbc72af8c1216f9c575..3f74fce868ecc3594d3b36cba45630ad50a23615 100644 (file)
@@ -2383,6 +2383,18 @@ config FB_PUV3_UNIGFX
          Choose this option if you want to use the Unigfx device as a
          framebuffer device. Without the support of PCI & AGP.
 
+
+config FB_XYLON
+       tristate "Xylon logiCVC framebuffer support"
+       depends on FB
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+       help
+         Choose this option if you want to use the Xylon logiCVC device as a
+         framebuffer device. Without the support of PCI & AGP.
+
+
 source "drivers/video/omap/Kconfig"
 source "drivers/video/omap2/Kconfig"
 
index 8b83129e209ca0f943a3d624e29930a679aec110..9c9c6ae778ed83d4e10cec39c41fc53f4b329e2a 100644 (file)
@@ -141,6 +141,7 @@ obj-$(CONFIG_FB_MSM)              += msm/
 obj-$(CONFIG_FB_NUC900)           += nuc900fb.o
 obj-$(CONFIG_FB_JZ4740)                  += jz4740_fb.o
 obj-$(CONFIG_FB_PUV3_UNIGFX)      += fb-puv3.o
+obj-$(CONFIG_FB_XYLON)            += xylonfb.o
 
 # Platform or fallback drivers go here
 obj-$(CONFIG_FB_UVESA)            += uvesafb.o
diff --git a/drivers/video/xylonfb.c b/drivers/video/xylonfb.c
new file mode 100755 (executable)
index 0000000..c28f01e
--- /dev/null
@@ -0,0 +1,1517 @@
+/*
+ * XYLON logiCVC frame buffer driver
+ *
+ * Author: Xylon d.o.o.
+ *
+ * 2002-2007 (c) MontaVista Software, Inc.
+ * 2007 (c) Secret Lab Technologies, Ltd.
+ * 2009 (c) Xilinx Inc.
+ * 2011 (c) Xylon d.o.o.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/*
+ * This driver was based on skeletonfb.c and other various fb video drivers.
+ */
+
+/*
+ * logiCVC frame buffer driver supports tripple buffering system per video layer.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/irq.h>
+#include <linux/ioctl.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/console.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/vt.h>
+#include <linux/fs.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <linux/stat.h>
+#include "xylonfb.h"
+
+
+/* DJ: will be removed (used only for development on non-PEP platform) */
+//#define ARM8_BOARD
+#define dbg(...) //printk(KERN_ERR __VA_ARGS__)
+
+#define DRIVER_NAME "xylonfb"
+#define DRIVER_DESCRIPTION "Xylon logiCVC frame buffer driver"
+
+#define LOGICVC_USER_CONFIGURATION 0xFFFF
+
+
+#define TRANSP_COLOR_8BPP_CLUT_16 0xF813
+#define TRANSP_COLOR_8BPP_CLUT_24 0x00FF009C
+#define TRANSP_COLOR_16BPP 0xF813
+#define TRANSP_COLOR_24BPP 0x00FF009C
+#define BACKGROUND_COLOR_24BPP 0x00000000
+
+/* All logiCVC registers are 32 bit registers, at distance of 64 bit */
+#define CVC_REG_DIST_USED      8                       /*  All logicvc registers are spaced at 8 bytes */
+#define CVC_SHSY_FP_ROFF      (0  * CVC_REG_DIST_USED) /* R_HSY_FP */
+#define CVC_SHSY_ROFF         (1  * CVC_REG_DIST_USED) /* R_HSY */
+#define CVC_SHSY_BP_ROFF      (2  * CVC_REG_DIST_USED) /* R_HSY_BP */
+#define CVC_SHSY_RES_ROFF     (3  * CVC_REG_DIST_USED) /* R_HSY_RES */
+#define CVC_SVSY_FP_ROFF      (4  * CVC_REG_DIST_USED) /* R_VSY_FP */
+#define CVC_SVSY_ROFF         (5  * CVC_REG_DIST_USED) /* R_VSY */
+#define CVC_SVSY_BP_ROFF      (6  * CVC_REG_DIST_USED) /* R_VSY_BP */
+#define CVC_SVSY_RES_ROFF     (7  * CVC_REG_DIST_USED) /* R_VSY_RES */
+#define CVC_SCTRL_ROFF        (8  * CVC_REG_DIST_USED) /* R_CTRL */
+#define CVC_SDTYPE_ROFF       (9  * CVC_REG_DIST_USED) /* R_DTYPE */
+#define CVC_BACKCOL_ROFF      (10 * CVC_REG_DIST_USED) /* R_BACKGROUND */
+#define CVC_DOUBLE_VBUFF_ROFF (11 * CVC_REG_DIST_USED) /* R_DOUBLE_VBUFF */
+#define CVC_DOUBLE_CLUT_ROFF  (12 * CVC_REG_DIST_USED) /* R_DOUBLE_CLUT */
+#define CVC_INT_ROFF          (13 * CVC_REG_DIST_USED) /* R_INT */
+#define CVC_INT_MASK_ROFF     (14 * CVC_REG_DIST_USED) /* R_INT_MASK */
+#define CVC_SPWRCTRL_ROFF     (15 * CVC_REG_DIST_USED) /* R_PWRCTRL */
+
+/* CVC layer registers base and distance between the layers */
+//#define CVC_LAYER_DISTANCE   (16  * CVC_REG_DIST_USED)                       /* distance between groups of layer registers */
+//#define CVC_LAYER0_BASE_ROFF (32  * CVC_REG_DIST_USED)                       /* offset to the beginning of layer 0 registers */
+//#define CVC_LAYER1_BASE_ROFF (CVC_LAYER0_BASE_ROFF + CVC_LAYER_DISTANCE * 1) /* offset to the beginning of layer 1 registers */
+//#define CVC_LAYER2_BASE_ROFF (CVC_LAYER0_BASE_ROFF + CVC_LAYER_DISTANCE * 2) /* offset to the beginning of layer 2 registers */
+//#define CVC_LAYER3_BASE_ROFF (CVC_LAYER0_BASE_ROFF + CVC_LAYER_DISTANCE * 3) /* offset to the beginning of layer 3 registers */
+//#define CVC_LAYER4_BASE_ROFF (CVC_LAYER0_BASE_ROFF + CVC_LAYER_DISTANCE * 4) /* offset to the beginning of layer 4 registers */
+/* CVC layer registers offsets (common for each layer) */
+#define CVC_LAYER_HOR_OFF_ROFF (0 * CVC_REG_DIST_USED) /*  LH_OFFSET   */
+#define CVC_LAYER_VER_OFF_ROFF (1 * CVC_REG_DIST_USED) /*  LV_OFFSET   */
+#define CVC_LAYER_HOR_POS_ROFF (2 * CVC_REG_DIST_USED) /*  LH_POSITION */
+#define CVC_LAYER_VER_POS_ROFF (3 * CVC_REG_DIST_USED) /*  LV_POSITION */
+#define CVC_LAYER_WIDTH_ROFF   (4 * CVC_REG_DIST_USED) /*  LH_WIDTH    */
+#define CVC_LAYER_HEIGHT_ROFF  (5 * CVC_REG_DIST_USED) /*  LV_HEIGHT   */
+#define CVC_LAYER_ALPHA_ROFF   (6 * CVC_REG_DIST_USED) /*  ALPHA       */
+#define CVC_LAYER_CTRL_ROFF    (7 * CVC_REG_DIST_USED) /*  CTRL        */
+#define CVC_LAYER_TRANSP_ROFF  (8 * CVC_REG_DIST_USED) /*  TRANSPARENT */
+
+/* CVC interrupt bits */
+#define CVC_L0_VBUFF_SW_INT   0x01
+#define CVC_L1_VBUFF_SW_INT   0x02
+#define CVC_L2_VBUFF_SW_INT   0x04
+#define CVC_L3_VBUFF_SW_INT   0x08
+#define CVC_L4_VBUFF_SW_INT   0x10
+#define CVC_V_SYNC_INT        0x20
+#define CVC_E_VIDEO_VALID_INT 0x40
+#define CVC_L0_CLUT_SW_INT    0x100
+#define CVC_L1_CLUT_SW_INT    0x200
+#define CVC_L2_CLUT_SW_INT    0x400
+#define CVC_L3_CLUT_SW_INT    0x800
+#define CVC_L4_CLUT_SW_INT    0x1000
+
+/* CVC layer base offsets */
+#define CVC_LAYER_BASE_OFFSET 0x100
+#define CVC_LAYER_0_OFFSET    0
+#define CVC_LAYER_1_OFFSET    0x80
+#define CVC_LAYER_2_OFFSET    0x100
+#define CVC_LAYER_3_OFFSET    0x180
+#define CVC_LAYER_4_OFFSET    0x200
+
+/* CVC layer CLUT base offsets */
+#define CVC_CLUT_BASE_OFFSET      0x1000
+#define CVC_CLUT_L0_CLUT_0_OFFSET 0
+#define CVC_CLUT_L0_CLUT_1_OFFSET 0x800
+#define CVC_CLUT_L1_CLUT_0_OFFSET 0x1000
+#define CVC_CLUT_L1_CLUT_1_OFFSET 0x1800
+#define CVC_CLUT_L2_CLUT_0_OFFSET 0x2000
+#define CVC_CLUT_L2_CLUT_1_OFFSET 0x2800
+#define CVC_CLUT_L3_CLUT_0_OFFSET 0x3000
+#define CVC_CLUT_L3_CLUT_1_OFFSET 0x3800
+#define CVC_CLUT_L4_CLUT_0_OFFSET 0x4000
+#define CVC_CLUT_L4_CLUT_1_OFFSET 0x4800
+#define CVC_CLUT_REGISTER_SIZE    4
+
+/* CVC register and CLUT base offsets */
+#define CVC_GENERAL_REGISTERS_RANGE 0x100
+#define CVC_REGISTERS_RANGE         0x6000
+
+/* CVC register initial values */
+#define CTRL_REG_INIT 0x001F
+#define TYPE_REG_INIT 0x001F
+
+/* CVC display power signals */
+#define CVC_EN_BLIGHT_MSK 0x01
+#define CVC_EN_VDD_MSK    0x02
+#define CVC_EN_VEE_MSK    0x04
+#define CVC_V_EN_MSK      0x08
+
+/* FB driver flags */
+#define FB_DMA_BUFFER 0x01
+#define FB_VSYNC_INT  0x02
+
+
+
+
+struct xylonfb_vsync {
+       wait_queue_head_t wait;
+       unsigned int cnt;
+};
+
+struct xylonfb_layer_data {
+       struct xylonfb_vsync vsync;     /* FB driver V-sync structure */
+       dma_addr_t reg_base_phys;       /* Physical base address of the logiCVC registers */
+       void *reg_base_virt;            /* Virtual base address of the logiCVC registers */
+       unsigned long reg_range;        /* Size of the logiCVC registers area */
+       dma_addr_t fb_phys;             /* Physical base address of the frame buffer video memory */
+       void *fb_virt;                          /* Virtual base address of the frame buffer video memory */
+       unsigned long fb_size;          /* Size of the frame buffer video memory */
+       void *layer_reg_base_virt;      /* Virtual base address of the logiCVC layer registers */
+       void *layer_clut_base_virt;     /* Virtual base address of the logiCVC layer CLUT registers */
+       unsigned char layer_byte_pp;/* logiCVC layer bytes per pixel */
+       unsigned char layer_id;         /* logiCVC layer ID */
+       unsigned char layers;           /* logiCVC number of layers */
+       unsigned char fb_flags;         /* FB driver flags */
+};
+
+static unsigned short cvc_layer_reg_offset[] = {
+       (CVC_LAYER_BASE_OFFSET + CVC_LAYER_0_OFFSET),
+       (CVC_LAYER_BASE_OFFSET + CVC_LAYER_1_OFFSET),
+       (CVC_LAYER_BASE_OFFSET + CVC_LAYER_2_OFFSET),
+       (CVC_LAYER_BASE_OFFSET + CVC_LAYER_3_OFFSET),
+       (CVC_LAYER_BASE_OFFSET + CVC_LAYER_4_OFFSET)
+};
+static unsigned short cvc_clut_reg_offset[] = {
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L0_CLUT_0_OFFSET),
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L0_CLUT_1_OFFSET),
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L1_CLUT_0_OFFSET),
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L1_CLUT_1_OFFSET),
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L2_CLUT_0_OFFSET),
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L2_CLUT_1_OFFSET),
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L3_CLUT_0_OFFSET),
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L3_CLUT_1_OFFSET),
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L4_CLUT_0_OFFSET),
+       (CVC_CLUT_BASE_OFFSET + CVC_CLUT_L4_CLUT_1_OFFSET)
+};
+
+
+/* Framebuffer driver platform data struct */
+struct xylonfb_hw_platform_data
+{
+       unsigned long regs_baseaddr;    /* Physical address of the logiCVC hardware registers */
+       unsigned long vmem_baseaddr;    /* Physical address of the layer framebuffer */
+       unsigned long xres;                             /* Layer resolution of screen in pixels */
+       unsigned long yres;
+       unsigned long xvirt;                    /* Layer resolution of memory buffer in pixels */
+       unsigned long yvirt;
+       unsigned long row_stride;               /* Layer row stride in virtual memory. (Should be the same as xvirt) */
+       unsigned char bpp;                              /* Layer bits per pixel */
+};
+
+/* Default logiCVC HW platform configuration */
+#ifdef ARM8_BOARD
+static struct xylonfb_hw_platform_data logiCVC_platform_data[] = {
+       {
+               .regs_baseaddr = 0x18008000,
+               .vmem_baseaddr = 0x10000000,
+               .xres = 0,
+               .yres = 0,
+               .xvirt = 1024,
+               .yvirt = 2048,
+               .row_stride = 1024,
+               .bpp = 8,
+       },
+       {
+               .regs_baseaddr = 0x18008000,
+               .vmem_baseaddr = 0x10200000,
+               .xres = 0,
+               .yres = 0,
+               .xvirt = 1024,
+               .yvirt = 3072,
+               .row_stride = 1024,
+               .bpp = 16,
+       },
+       {
+               .regs_baseaddr = 0x18008000,
+               .vmem_baseaddr = 0x10800000,
+               .xres = 0,
+               .yres = 0,
+               .xvirt = 1024,
+               .yvirt = 3072,
+               .row_stride = 1024,
+               .bpp = 32,
+       },
+};
+#else /* #ifdef ARM8_BOARD (PEP HW) */
+static struct xylonfb_hw_platform_data logiCVC_platform_data[] = {
+       {
+               .regs_baseaddr = 0x40030000,
+               .vmem_baseaddr = 0x0F000000,
+               .xres = 0,
+               .yres = 0,
+               .xvirt = 1024,
+               .yvirt = 1024,
+               .row_stride = 1024,
+               .bpp = 8,
+       },
+       {
+               .regs_baseaddr = 0x40030000,
+               .vmem_baseaddr = 0x0F100000,
+               .xres = 0,
+               .yres = 0,
+               .xvirt = 1024,
+               .yvirt = 1536,
+               .row_stride = 1024,
+               .bpp = 16,
+       },
+       {
+               .regs_baseaddr = 0x40030000,
+               .vmem_baseaddr = 0x0F400000,
+               .xres = 0,
+               .yres = 0,
+               .xvirt = 1024,
+               .yvirt = 1536,
+               .row_stride = 1024,
+               .bpp = 32,
+       },
+};
+#endif /* #ifdef ARM8_BOARD */
+
+
+/* Supported_video_modes */
+#define VESA_640_480 "640x480@60"
+#define VESA_800_600 "800x600@60"
+#define VESA_1024_768 "1024x768@60"
+#define VESA_1280_1024 "1280x1024@60"
+
+/**
+ * Structure that contains detailed data about the particular display or standard VGA resolution type. 
+ */
+static struct fb_videomode videomode_640x480 = {
+       .refresh      = 60,
+       .xres         = 640,
+       .yres         = 480,
+       .pixclock     = KHZ2PICOS(25152),
+       .left_margin  = 48,
+       .right_margin = 16,
+       .upper_margin = 31,
+       .lower_margin = 11,
+       .hsync_len    = 96,
+       .vsync_len    = 2,
+       .sync         = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       .vmode        = FB_VMODE_NONINTERLACED
+};
+
+/* Xenarc 800x480 60Hz VGA monitor (used on logiTAP, running PetaLinux) */
+//static struct fb_videomode videomode_800x480 = {
+//     .xres           = 800,
+//     .yres           = 480,
+//     .pixclock       = KHZ2PICOS(31500),
+//     .left_margin    = 56,
+//     .right_margin   = 64,
+//     .upper_margin   = 14,
+//     .lower_margin   = 28,
+//     .hsync_len      = 80,
+//     .vsync_len      = 3,
+//     .sync           = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+//     .vmode          = FB_VMODE_NONINTERLACED
+//};
+
+static struct fb_videomode videomode_800x600 = {
+       .refresh      = 60,
+       .xres         = 800,
+       .yres         = 600,
+       .pixclock     = KHZ2PICOS(39790),
+       .left_margin  = 88,
+       .right_margin = 40,
+       .upper_margin = 23,
+       .lower_margin = 1,
+       .hsync_len    = 128,
+       .vsync_len    = 4,
+       .sync         = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       .vmode        = FB_VMODE_NONINTERLACED
+};
+
+static struct fb_videomode videomode_1024x768 = {
+       .refresh      = 60,
+       .xres         = 1024,
+       .yres         = 768,
+       .pixclock     = KHZ2PICOS(65076),
+       .left_margin  = 160,
+       .right_margin = 24,
+       .upper_margin = 29,
+       .lower_margin = 3,
+       .hsync_len    = 136,
+       .vsync_len    = 6,
+       .sync         = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       .vmode        = FB_VMODE_NONINTERLACED
+};
+
+static struct fb_videomode videomode_1280x1024 = {
+       .refresh      = 60,
+       .xres         = 1024,
+       .yres         = 768,
+       .pixclock     = KHZ2PICOS(108065),
+       .left_margin  = 160,
+       .right_margin = 24,
+       .upper_margin = 29,
+       .lower_margin = 3,
+       .hsync_len    = 136,
+       .vsync_len    = 6,
+       .sync         = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+       .vmode        = FB_VMODE_NONINTERLACED
+};
+
+
+struct video_mode_parameters
+{
+       unsigned int VESA_code; /* VESA code. 0 if display isn't in VESA standard */
+       unsigned int bpp; /* Bits per pixel(8, 16, 24 supported) */
+       struct fb_videomode *vmode_data; /* Video mode parameters */
+};
+
+struct active_video_mode_parameters
+{
+       unsigned int bpp; /* Bits per pixel(8, 16, 24 supported) */
+       unsigned int power_on_delay; /* Delay after applying display power and before applying display signals */
+       unsigned int signal_on_delay; /* Delay after applying display signal and before applying display backlight power supply */
+       struct fb_videomode vmode_data; /* Video mode parameters */
+};
+
+enum supported_video_modes {
+       VESA_640_480_8 = 0,
+       VESA_640_480_16,
+       VESA_640_480_32,
+       VESA_800_600_8,
+       VESA_800_600_16,
+       VESA_800_600_32,
+       VESA_1024_768_8,
+       VESA_1024_768_16,
+       VESA_1024_768_32,
+       VESA_1280_1024_8,
+       VESA_1280_1024_16,
+       VESA_1280_1024_32,
+       NUM_OF_VIDEO_MODES,
+       DEFAULT_VIDEO_MODE = VESA_640_480_32
+};
+
+static struct video_mode_parameters const video_modes[] = {
+       /* 640 x 480 @ 60Hz */
+       {
+               XYLONFB_VM_VESA_640_480_8,
+               8,
+               &videomode_640x480,
+       },
+       {
+               XYLONFB_VM_VESA_640_480_16,
+               16,
+               &videomode_640x480,
+       },
+       {
+               XYLONFB_VM_VESA_640_480_32,
+               32,
+               &videomode_640x480,
+       },
+       /* 800 x 600 @ 60Hz */
+       {
+               XYLONFB_VM_VESA_800_600_8,
+               8,
+               &videomode_800x600,
+       },
+       {
+               XYLONFB_VM_VESA_800_600_16,
+               16,
+               &videomode_800x600,
+       },
+       {
+               XYLONFB_VM_VESA_800_600_32,
+               32,
+               &videomode_800x600,
+       },
+       /* 1024 x 768 @ 60Hz */
+       {
+               XYLONFB_VM_VESA_1024_768_8,
+               8,
+               &videomode_1024x768,
+       },
+       {
+               XYLONFB_VM_VESA_1024_768_16,
+               16,
+               &videomode_1024x768,
+       },
+       {
+               XYLONFB_VM_VESA_1024_768_32,
+               32,
+               &videomode_1024x768,
+       },
+       /* 1280 x 1024 @ 60Hz */
+       {
+               XYLONFB_VM_VESA_1280_1024_8,
+               8,
+               &videomode_1280x1024,
+       },
+       {
+               XYLONFB_VM_VESA_1280_1024_16,
+               16,
+               &videomode_1280x1024,
+       },
+       {
+               XYLONFB_VM_VESA_1280_1024_32,
+               32,
+               &videomode_1280x1024,
+       }
+};
+
+
+/* Active video mode (parameters are changeable) */
+static struct active_video_mode_parameters active_video_mode;
+
+/* Platform init input parameters */
+static unsigned long regs_baseaddr;
+static unsigned long vmem_baseaddr;
+static unsigned long virt_hres;
+static unsigned long virt_vres;
+static unsigned long row_stride;
+/* Video mode init input parameters */
+static unsigned long video_mode_code;
+static unsigned long hfp;
+static unsigned long hsync;
+static unsigned long hbp;
+static unsigned long hres;
+static unsigned long vfp;
+static unsigned long vsync;
+static unsigned long vbp;
+static unsigned long vres;
+static unsigned long pix_clk;
+static unsigned long bpp;
+static unsigned long power_on_delay;
+static unsigned long signal_on_delay;
+static unsigned long startup_layer;
+
+/* Xylon platform parameters */
+module_param(regs_baseaddr, ulong, S_IRUGO | S_IWUSR);
+module_param(vmem_baseaddr, ulong, S_IRUGO | S_IWUSR);
+module_param(virt_hres, ulong, S_IRUGO | S_IWUSR);
+module_param(virt_vres, ulong, S_IRUGO | S_IWUSR);
+module_param(row_stride, ulong, S_IRUGO | S_IWUSR);
+/* Video mode parameters */
+module_param(video_mode_code, ulong, S_IRUGO | S_IWUSR);
+module_param(hfp, ulong, S_IRUGO | S_IWUSR);
+module_param(hsync, ulong, S_IRUGO | S_IWUSR);
+module_param(hbp, ulong, S_IRUGO | S_IWUSR);
+module_param(hres, ulong, S_IRUGO | S_IWUSR);
+module_param(vfp, ulong, S_IRUGO | S_IWUSR);
+module_param(vsync, ulong, S_IRUGO | S_IWUSR);
+module_param(vbp, ulong, S_IRUGO | S_IWUSR);
+module_param(vres, ulong, S_IRUGO | S_IWUSR);
+module_param(pix_clk, ulong, S_IRUGO | S_IWUSR);
+module_param(bpp, ulong, S_IRUGO | S_IWUSR);
+module_param(power_on_delay, ulong, S_IRUGO | S_IWUSR);
+module_param(signal_on_delay, ulong, S_IRUGO | S_IWUSR);
+module_param(startup_layer, ulong, S_IRUGO | S_IWUSR);
+
+static u32 xylonfb_pseudo_palette[16];
+atomic_t xylonfb_use_ref;
+
+
+
+//static irqreturn_t xylonfb_irq(int irq, void *dev_id)
+//{
+//     struct fb_info *fbi = (struct fb_info *)dev_id;
+//     struct xylonfb_layer_data *layer_data = fbi->par;
+//     u32 isr;
+//
+//     isr = readl(layer_data->reg_base_virt + CVC_INT_ROFF);
+//
+//     if (isr & CVC_V_SYNC_INT) {
+//             writel(layer_data->reg_base_virt + CVC_INT_ROFF, CVC_V_SYNC_INT);
+//             layer_data->vsync.cnt++;
+//             layer_data->fb_flags |= FB_VSYNC_INT;
+//             wake_up_interruptible(&layer_data->vsync.wait);
+//     }
+//
+//     return IRQ_HANDLED;
+//}
+
+
+static int xylonfb_open(struct fb_info *fbi, int user)
+{
+       dbg("%s", __func__);
+
+       atomic_inc(&xylonfb_use_ref);
+
+       return 0;
+}
+
+static int xylonfb_release(struct fb_info *fbi, int user)
+{
+       dbg("%s", __func__);
+
+       atomic_dec(&xylonfb_use_ref);
+
+       return 0;
+}
+
+static int xylonfb_set_color_reg(unsigned regno, unsigned red, unsigned green,
+                       unsigned blue, unsigned transp, struct fb_info *fbi)
+{
+       struct xylonfb_layer_data *layer_data = fbi->par;
+       u32 clut_value = 0;
+
+       dbg("%s", __func__);
+
+       if (fbi->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
+               if (regno >= 256)
+                       return -EINVAL;
+
+               /* for now supported only 32bpp CLUT */
+               if (fbi->var.bits_per_pixel == 8)
+                       clut_value =
+                               (((u8)transp<<24) | ((u8)red<<16) | ((u8)green<<8) | (u8)blue);
+               /* logiCVC supports 16bpp CLUT also */
+               else if (fbi->var.bits_per_pixel == 16)
+                       clut_value =
+                               (((u8)(transp&0x3F)<<24) | ((u8)(red&0xF8)<<16) |
+                               ((u8)(green&0xFC)<<8) | (u8)(blue&0xF8));
+               writel(clut_value,
+                       layer_data->layer_clut_base_virt +
+                               (regno * CVC_CLUT_REGISTER_SIZE));
+       } else {
+               if (regno >= 16)
+                       return -EINVAL;
+
+               ((u32 *)(fbi->pseudo_palette))[regno] =
+                       (red & 0xf800) | ((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
+       }
+
+       return 0;
+}
+
+static int xylonfb_set_cmap(struct fb_cmap *cmap, struct fb_info *fbi)
+{
+       struct xylonfb_layer_data *layer_data = fbi->par;
+       u32 clut_value;
+       int i;
+
+       dbg("%s", __func__);
+
+       if (fbi->fix.visual == FB_VISUAL_PSEUDOCOLOR) {
+               if (cmap->start >= 256 || cmap->len >= 256)
+                       return -EINVAL;
+
+               if (fbi->var.bits_per_pixel == 8) {
+                       /* for now supported only 32bpp CLUT */
+                       for (i = cmap->start; i < cmap->len; i++) {
+                               clut_value =
+                                       (((u8)cmap->transp[i]<<24) | ((u8)cmap->red[i]<<16) |
+                                       ((u8)cmap->green[i]<<8) | (u8)cmap->blue[i]);
+                               writel(clut_value,
+                                       layer_data->layer_clut_base_virt + (i * CVC_CLUT_REGISTER_SIZE));
+                       }
+               } else if (fbi->var.bits_per_pixel == 16) {
+                       /* logiCVC supports 16bpp CLUT also */
+                       for (i = cmap->start; i < cmap->len; i++) {
+                               clut_value = (((u8)(cmap->transp[i]&0x3F)<<24) |
+                                       ((u8)(cmap->red[i]&0xF8)<<16) |
+                                       ((u8)(cmap->green[i]&0xFC)<<8) |
+                                       (u8)(cmap->blue[i]&0xF8));
+                               writel(clut_value,
+                                       layer_data->layer_clut_base_virt + (i*CVC_CLUT_REGISTER_SIZE));
+                       }
+               }
+       } else {
+               if (cmap->start > 16 || cmap->len > 16)
+                       return -EINVAL;
+
+               for (i = cmap->start; i < cmap->len; i++) {
+                       ((u32 *)(fbi->pseudo_palette))[i] =     
+                               0xFF000000 | 
+                               ((cmap->red[i] & 0x00FF) << 16) | 
+                               ((cmap->green[i] & 0x00FF) << 8) | 
+                               ((cmap->blue[i] & 0x00FF));
+               }
+       }
+
+       return 0;
+}
+
+static int xylonfb_blank(int blank_mode, struct fb_info *fbi)
+{
+       dbg("%s", __func__);
+
+       switch (blank_mode) {
+       case FB_BLANK_UNBLANK:
+       case FB_BLANK_NORMAL:
+//             memset_io((void __iomem *)fbi->screen_base, 0, fbi->screen_size);
+               break;
+       case FB_BLANK_VSYNC_SUSPEND:
+       case FB_BLANK_HSYNC_SUSPEND:
+       case FB_BLANK_POWERDOWN:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       /* let fbcon do a soft blank for us */
+       return (blank_mode == FB_BLANK_NORMAL) ? 1 : 0;
+}
+
+static int xylonfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi)
+{
+       struct xylonfb_layer_data *layer_data = fbi->par;
+
+       dbg("%s", __func__);
+
+       if (fbi->var.xoffset == var->xoffset && fbi->var.yoffset == var->yoffset)
+               return 0;
+
+       if (var->vmode & FB_VMODE_YWRAP) {
+               if (var->yoffset < 0 ||
+                       var->yoffset >= fbi->var.yres_virtual ||
+                       var->xoffset)
+                       return -EINVAL;
+       } else {
+               if (var->xoffset + var->xres > fbi->var.xres_virtual ||
+                       var->yoffset + var->yres > fbi->var.yres_virtual)
+                       return -EINVAL;
+       }
+       fbi->var.xoffset = var->xoffset;
+       fbi->var.yoffset = var->yoffset;
+       if (var->vmode & FB_VMODE_YWRAP)
+               fbi->var.vmode |= FB_VMODE_YWRAP;
+       else
+               fbi->var.vmode &= ~FB_VMODE_YWRAP;
+       /* set HW memory X offset */
+       writel(var->xoffset, (layer_data->layer_reg_base_virt + CVC_LAYER_HOR_OFF_ROFF));
+       /* set HW memory Y offset */
+       writel(var->yoffset, (layer_data->layer_reg_base_virt + CVC_LAYER_VER_OFF_ROFF));
+       /* Apply changes */
+       writel((var->yres-1), (layer_data->layer_reg_base_virt + CVC_LAYER_VER_POS_ROFF));
+
+       return 0;
+}
+
+static int xylonfb_get_vblank(struct fb_vblank *vblank, struct fb_info *fbi)
+{
+       struct xylonfb_layer_data *layer_data = fbi->par;
+       u32 isr;
+
+       dbg("%s", __func__);
+
+       isr = readl(layer_data->reg_base_virt + CVC_INT_ROFF);
+       if (isr & CVC_V_SYNC_INT)
+               vblank->flags |= (FB_VBLANK_VSYNCING | FB_VBLANK_HAVE_VSYNC);
+       else
+               vblank->flags |= FB_VBLANK_HAVE_VSYNC;
+
+       return 0;
+}
+
+static int xylonfb_wait_for_vsync(u32 crt, struct fb_info *fbi)
+{
+       struct xylonfb_layer_data *layer_data = fbi->par;
+       u32 imr;
+       int ret;
+
+       dbg("%s", __func__);
+
+       /* enable CVC V-sync interrupt */
+       imr = readl(layer_data->reg_base_virt + CVC_INT_MASK_ROFF);
+       imr &= (~CVC_V_SYNC_INT);
+       writel(layer_data->reg_base_virt + CVC_INT_MASK_ROFF, imr);
+
+       ret = wait_event_interruptible_timeout(layer_data->vsync.wait,
+                       (layer_data->fb_flags & FB_VSYNC_INT), HZ/10);
+
+       /* disable CVC V-sync interrupt */
+       imr |= CVC_V_SYNC_INT;
+       writel(layer_data->reg_base_virt + CVC_INT_MASK_ROFF, imr);
+
+       if (ret < 0)
+               return ret;
+       else if (ret == 0) {
+               return -ETIMEDOUT;
+       } else
+               layer_data->fb_flags &= (~FB_VSYNC_INT);
+
+       return 0;
+}
+
+static int xylonfb_ioctl(struct fb_info *fbi, unsigned int cmd,
+                       unsigned long arg)
+{
+       struct fb_var_screeninfo var;
+       struct fb_fix_screeninfo fix;
+       struct fb_vblank vblank;
+       struct fb_con2fbmap con2fb;
+       struct fb_cmap cmap_from;
+       struct fb_cmap cmap;
+       struct fb_event event;
+       void __user *argp = (void __user *)arg;
+       u32 crt;
+       long ret = 0;
+
+       dbg("%s", __func__);
+
+       switch (cmd) {
+       case FBIOGET_VSCREENINFO:
+               dbg("FBIOGET_VSCREENINFO\n");
+               if (!lock_fb_info(fbi))
+                       return -ENODEV;
+               var = fbi->var;
+               unlock_fb_info(fbi);
+
+               ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;
+               break;
+
+       case FBIOPUT_VSCREENINFO:
+               dbg("FBIOPUT_VSCREENINFO\n");
+               if (copy_from_user(&var, argp, sizeof(var)))
+                       return -EFAULT;
+               if (!lock_fb_info(fbi))
+                       return -ENODEV;
+               console_lock();
+               fbi->flags |= FBINFO_MISC_USEREVENT;
+               ret = fb_set_var(fbi, &var);
+               fbi->flags &= ~FBINFO_MISC_USEREVENT;
+               console_unlock();
+               unlock_fb_info(fbi);
+               if (!ret && copy_to_user(argp, &var, sizeof(var)))
+                       ret = -EFAULT;
+               break;
+
+       case FBIOGET_FSCREENINFO:
+               dbg("FBIOGET_FSCREENINFO\n");
+               if (!lock_fb_info(fbi))
+                       return -ENODEV;
+               fix = fbi->fix;
+               unlock_fb_info(fbi);
+
+               ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;
+               break;
+
+       case FBIOPUTCMAP:
+               dbg("FBIOPUTCMAP\n");
+               if (fbi->var.bits_per_pixel != 8)
+                       return -EINVAL;
+
+               if (copy_from_user(&cmap, argp, sizeof(cmap)))
+                       return -EFAULT;
+               ret = fb_set_cmap(&cmap, fbi);
+               break;
+
+       case FBIOGETCMAP:
+               dbg("FBIOGETCMAP\n");
+               if (fbi->var.bits_per_pixel != 8)
+                       return -EINVAL;
+
+               if (copy_from_user(&cmap, argp, sizeof(cmap)))
+                       return -EFAULT;
+               if (!lock_fb_info(fbi))
+                       return -ENODEV;
+               cmap_from = fbi->cmap;
+               unlock_fb_info(fbi);
+               ret = fb_copy_cmap(&cmap_from, &cmap);
+               break;
+
+       case FBIOPAN_DISPLAY:
+               dbg("FBIOPAN_DISPLAY\n");
+               if (copy_from_user(&var, argp, sizeof(var)))
+                       return -EFAULT;
+               if (!lock_fb_info(fbi))
+                       return -ENODEV;
+               console_lock();
+               ret = fb_pan_display(fbi, &var);
+               console_unlock();
+               unlock_fb_info(fbi);
+               if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
+                       return -EFAULT;
+               break;
+
+       case FBIO_CURSOR:
+               ret = -EINVAL;
+               break;
+
+       case FBIOGET_CON2FBMAP:
+               dbg("FBIOGET_CON2FBMAP\n");
+               if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
+                       return -EFAULT;
+               if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
+                       return -EINVAL;
+               con2fb.framebuffer = -1;
+               event.data = &con2fb;
+               if (!lock_fb_info(fbi))
+                       return -ENODEV;
+               event.info = fbi;
+               fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
+               unlock_fb_info(fbi);
+               ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
+               break;
+
+       case FBIOPUT_CON2FBMAP:
+               dbg("FBIOPUT_CON2FBMAP\n");
+               if (copy_from_user(&con2fb, argp, sizeof(con2fb)))
+                       return -EFAULT;
+               if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
+                       return -EINVAL;
+               if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
+                       return -EINVAL;
+               if (!registered_fb[con2fb.framebuffer])
+                       request_module("fb%d", con2fb.framebuffer);
+               if (!registered_fb[con2fb.framebuffer]) {
+                       ret = -EINVAL;
+                       break;
+               }
+               event.data = &con2fb;
+               if (!lock_fb_info(fbi))
+                       return -ENODEV;
+               event.info = fbi;
+               ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
+               unlock_fb_info(fbi);
+               break;
+
+       case FBIOBLANK:
+               dbg("FBIOBLANK\n");
+               if (!lock_fb_info(fbi))
+                       return -ENODEV;
+               console_lock();
+               fbi->flags |= FBINFO_MISC_USEREVENT;
+               ret = fb_blank(fbi, arg);
+               fbi->flags &= ~FBINFO_MISC_USEREVENT;
+               console_unlock();
+               unlock_fb_info(fbi);
+               break;
+
+       case FBIOGET_VBLANK:
+               if (copy_from_user(&vblank, argp, sizeof(vblank)))
+                       return -EFAULT;
+               ret = xylonfb_get_vblank(&vblank, fbi);
+               if (!ret)
+                       if (copy_to_user(argp, &vblank, sizeof(vblank)))
+                               ret = -EFAULT;
+               break;
+
+       case FBIO_WAITFORVSYNC:
+               dbg("FBIO_WAITFORVSYNC\n");
+               if (get_user(crt, (u32 __user *) arg))
+                       break;
+               ret = xylonfb_wait_for_vsync(crt, fbi);
+               break;
+
+       default:
+               dbg("FBIO_DEFAULT\n");
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+/*
+ * Framebuffer operations structure.
+ */
+static struct fb_ops xylonfb_ops = {
+       .owner = THIS_MODULE,
+       .fb_open = xylonfb_open,
+       .fb_release = xylonfb_release,
+       .fb_check_var = NULL,
+       .fb_set_par = NULL,
+       .fb_setcolreg = xylonfb_set_color_reg,
+       .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_cursor = NULL,
+       .fb_rotate = NULL,
+       .fb_sync = NULL,
+       .fb_ioctl = xylonfb_ioctl,
+       .fb_mmap = NULL,
+       .fb_get_caps = NULL,
+       .fb_destroy = NULL,
+};
+
+
+static void xylonfb_hw_start(struct fb_info *fbi)
+{
+       struct xylonfb_layer_data *layer_data = fbi->par;
+       u32 val;
+       int i;
+
+       dbg("%s", __func__);
+
+       writel(active_video_mode.vmode_data.right_margin-1,
+               layer_data->reg_base_virt + CVC_SHSY_FP_ROFF);
+       writel(active_video_mode.vmode_data.hsync_len-1,
+               layer_data->reg_base_virt + CVC_SHSY_ROFF);
+       writel(active_video_mode.vmode_data.left_margin-1,
+               layer_data->reg_base_virt + CVC_SHSY_BP_ROFF);
+       writel(active_video_mode.vmode_data.xres-1,
+               layer_data->reg_base_virt + CVC_SHSY_RES_ROFF);
+       writel(active_video_mode.vmode_data.lower_margin-1,
+               layer_data->reg_base_virt + CVC_SVSY_FP_ROFF);
+       writel(active_video_mode.vmode_data.vsync_len-1,
+               layer_data->reg_base_virt + CVC_SVSY_ROFF);
+       writel(active_video_mode.vmode_data.upper_margin-1,
+               layer_data->reg_base_virt + CVC_SVSY_BP_ROFF);
+       writel(active_video_mode.vmode_data.yres-1,
+               layer_data->reg_base_virt + CVC_SVSY_RES_ROFF);
+#ifdef ARM8_BOARD
+       val = readl(layer_data->reg_base_virt + CVC_SCTRL_ROFF);
+       val |= CTRL_REG_INIT;
+       writel(val, layer_data->reg_base_virt + CVC_SCTRL_ROFF);
+#else /* #ifdef ARM8_BOARD */
+       writel(CTRL_REG_INIT, layer_data->reg_base_virt + CVC_SCTRL_ROFF);
+#endif /* #ifdef ARM8_BOARD */
+       writel(TYPE_REG_INIT, layer_data->reg_base_virt + CVC_SDTYPE_ROFF);
+       writel(0xFFFFFFFF, layer_data->reg_base_virt + CVC_BACKCOL_ROFF);
+//     writel(0x00, layer_data->reg_base_virt + CVC_DOUBLE_VBUFF_ROFF);
+//     writel(0x00, layer_data->reg_base_virt + CVC_DOUBLE_CLUT_ROFF);
+       writel(0xFFFF, layer_data->reg_base_virt + CVC_INT_ROFF);
+       writel(0xFFFF, layer_data->reg_base_virt + CVC_INT_MASK_ROFF);
+       writel(TRANSP_COLOR_24BPP,
+               (layer_data->layer_reg_base_virt + CVC_LAYER_TRANSP_ROFF));
+       /* Display power control */
+       val = CVC_EN_VDD_MSK;
+       writel(val, layer_data->reg_base_virt + CVC_SPWRCTRL_ROFF);
+       mdelay(active_video_mode.power_on_delay);
+       val |= CVC_V_EN_MSK;
+       writel(val, layer_data->reg_base_virt + CVC_SPWRCTRL_ROFF);
+       mdelay(active_video_mode.signal_on_delay);
+       val |= CVC_EN_BLIGHT_MSK;
+       writel(val, layer_data->reg_base_virt + CVC_SPWRCTRL_ROFF);
+       /* Turn logiCVC ON - make layer visible on screen */
+       writel(1, (layer_data->layer_reg_base_virt + CVC_LAYER_CTRL_ROFF));
+
+       printk(KERN_INFO "logiCVC HW parameters:\n");
+       printk(KERN_INFO "    Horizontal Front Porch: %d pixclks\n",
+               active_video_mode.vmode_data.right_margin);
+       printk(KERN_INFO "    Horizontal Sync:        %d pixclks\n",
+               active_video_mode.vmode_data.hsync_len);
+       printk(KERN_INFO "    Horizontal Back Porch:  %d pixclks\n",
+               active_video_mode.vmode_data.left_margin);
+       printk(KERN_INFO "    Vertical Front Porch:   %d pixclks\n",
+               active_video_mode.vmode_data.lower_margin);
+       printk(KERN_INFO "    Vertical Sync:          %d pixclks\n",
+               active_video_mode.vmode_data.vsync_len);
+       printk(KERN_INFO "    Vertical Back Porch:    %d pixclks\n",
+               active_video_mode.vmode_data.upper_margin);
+       printk(KERN_INFO "    Pixel Clock:            %d\n",
+               active_video_mode.vmode_data.pixclock);
+       printk(KERN_INFO "    Bits per Pixel:         %d\n",
+               active_video_mode.bpp);
+       printk(KERN_INFO "    Horizontal Res:         %d\n",
+               active_video_mode.vmode_data.xres);
+       printk(KERN_INFO "    Vertical Res:           %d\n",
+               active_video_mode.vmode_data.yres);
+       printk(KERN_INFO "\n");
+       printk(KERN_INFO "logiCVC layer parameters:\n");
+       for (i = 0; i < ARRAY_SIZE(logiCVC_platform_data); i++) {
+               printk(KERN_INFO "logiCVC layer %d\n", i);
+               printk(KERN_INFO "    Registers Base Address:     0x%X\n",
+                       (unsigned int)logiCVC_platform_data[i].regs_baseaddr);
+               printk(KERN_INFO "    Layer Video Memory Address: 0x%X\n",
+                       (unsigned int)logiCVC_platform_data[i].vmem_baseaddr);
+               printk(KERN_INFO "    X resolution:               %ld\n",
+                       logiCVC_platform_data[i].xres);
+               printk(KERN_INFO "    Y resolution:               %ld\n",
+                       logiCVC_platform_data[i].yres);
+               printk(KERN_INFO "    X resolution (virtual):     %ld\n",
+                       logiCVC_platform_data[i].xvirt);
+               printk(KERN_INFO "    Y resolution (virtual):     %ld\n",
+                       logiCVC_platform_data[i].yvirt);
+               printk(KERN_INFO "    Row stride:                 %ld\n",
+                       logiCVC_platform_data[i].row_stride);
+               printk(KERN_INFO "    Bits per Pixel:             %d\n",
+                       logiCVC_platform_data[i].bpp);
+               printk(KERN_INFO "\n");
+       }
+}
+
+static int xylonfb_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct xylonfb_hw_platform_data *pdata;
+       struct fb_info **afbi;
+       struct fb_info *fbi;
+       struct xylonfb_layer_data *layer_data;
+       int layers;
+       int i, rc, regfb, on;
+
+       dbg("%s", __func__);
+
+       layers = ARRAY_SIZE(logiCVC_platform_data);
+
+       afbi = kzalloc(sizeof(struct fb_info *) * layers, GFP_KERNEL);
+       if (!afbi) {
+               dev_err(dev, "Error allocate xylonfb internals\n");
+               return -ENOMEM;
+       }
+
+       layer_data = NULL;
+
+       for (i = layers-1; i >= 0; i--) {
+               /* set register flag to invalid value */
+               regfb = -1;
+
+               fbi = framebuffer_alloc(sizeof(struct xylonfb_layer_data), dev);
+               if (!fbi) {
+                       dev_err(dev, "Error allocate xylonfb info\n");
+                       rc = -ENOMEM;
+                       goto err_fb;
+               }
+               afbi[i] = fbi;
+               layer_data = fbi->par;
+
+               if (pdev->dev.platform_data)
+                       pdata = pdev->dev.platform_data;
+               else
+                       pdata = &logiCVC_platform_data[i];
+
+               /* logiCVC register mapping */
+               layer_data->reg_base_phys = pdata->regs_baseaddr;
+               layer_data->reg_range = CVC_REGISTERS_RANGE;
+               layer_data->reg_base_virt =
+                       ioremap_nocache(layer_data->reg_base_phys, layer_data->reg_range);
+               /* VMEM mapping */
+               layer_data->fb_phys = pdata->vmem_baseaddr;
+               layer_data->fb_size = pdata->xvirt * (pdata->bpp / 8) * pdata->yvirt;
+               if (layer_data->fb_flags & FB_DMA_BUFFER) {
+                       /* NOT USED FOR NOW! */
+                       layer_data->fb_virt = dma_alloc_writecombine(dev,
+                               PAGE_ALIGN(layer_data->fb_size),
+                               &layer_data->fb_phys, GFP_KERNEL);
+               } else {
+                       layer_data->fb_virt =
+                               ioremap_wc(layer_data->fb_phys, layer_data->fb_size);
+               }
+               /* check IO mappings */
+               if (!layer_data->reg_base_virt || !layer_data->fb_virt) {
+                       dev_err(dev, "Error xylonfb ioremap REGS 0x%X FB 0x%X\n",
+                               (unsigned int)layer_data->reg_base_virt,
+                               (unsigned int)layer_data->fb_virt);
+                       rc = -ENOMEM;
+                       goto err_fb;
+               }
+//             memset_io((void __iomem *)layer_data->fb_virt, 0, layer_data->fb_size);
+               layer_data->layer_reg_base_virt =
+                       layer_data->reg_base_virt + cvc_layer_reg_offset[i];
+               layer_data->layer_clut_base_virt =
+                       layer_data->reg_base_virt + cvc_clut_reg_offset[i];
+               layer_data->layer_byte_pp = pdata->bpp / 8;
+               layer_data->layer_id = i;
+               layer_data->layers = layers;
+
+               printk(KERN_INFO \
+                       "Registers base address 0x%X\n" \
+                       "Registers range 0x%X\n" \
+                       "Layer registers base address 0x%X\n" \
+                       "Layer CLUT registers base address 0x%X\n" \
+                       "Layer bytes per Pixel %d\n" \
+                       "Layer ID %d\n" \
+                       "FB address 0x%X\n" \
+                       "FB size %ld\n", \
+                       (unsigned int)layer_data->reg_base_virt, (unsigned int)layer_data->reg_range,
+                       (unsigned int)layer_data->layer_reg_base_virt, (unsigned int)layer_data->layer_clut_base_virt,
+                       layer_data->layer_byte_pp, layer_data->layer_id,
+                       (unsigned int)layer_data->fb_virt, layer_data->fb_size);
+
+               fbi->flags = FBINFO_DEFAULT;
+               fbi->screen_base = (char __iomem *)layer_data->fb_virt;
+               fbi->screen_size = layer_data->fb_size;
+               fbi->pseudo_palette = xylonfb_pseudo_palette;
+               fbi->fbops = &xylonfb_ops;
+
+               sprintf(fbi->fix.id, "Xylon FB%d", i);
+               fbi->fix.smem_start = layer_data->fb_phys;
+               fbi->fix.smem_len = layer_data->fb_size;
+               fbi->fix.type = FB_TYPE_TEXT;
+               if (pdata->bpp == 8 || pdata->bpp == 16)
+                       fbi->fix.visual = FB_VISUAL_DIRECTCOLOR;
+               else
+                       fbi->fix.visual = FB_VISUAL_TRUECOLOR;
+               fbi->fix.xpanstep = 1;
+               fbi->fix.ypanstep = 1;
+               fbi->fix.ywrapstep = 2048;
+               fbi->fix.line_length = pdata->xvirt * (pdata->bpp / 8);
+               fbi->fix.mmio_start = layer_data->reg_base_phys;
+               fbi->fix.mmio_len = CVC_REGISTERS_RANGE;
+               fbi->fix.accel = FB_ACCEL_NONE;
+
+               fbi->var.xres = pdata->xres;
+               fbi->var.yres = pdata->yres;
+               fbi->var.xres_virtual = pdata->xvirt;
+               fbi->var.yres_virtual = pdata->yvirt;
+               fbi->var.bits_per_pixel = pdata->bpp;
+               fbi->var.transp.offset = 24;
+               fbi->var.transp.length = 8;
+               fbi->var.transp.msb_right = 0;
+               fbi->var.red.offset = 16;
+               fbi->var.red.length = 8;
+               fbi->var.red.msb_right = 0;
+               fbi->var.green.offset = 8;
+               fbi->var.green.length = 8;
+               fbi->var.green.msb_right = 0;
+               fbi->var.blue.offset = 0;
+               fbi->var.blue.length = 8;
+               fbi->var.blue.msb_right = 0;
+               fbi->var.activate = FB_ACTIVATE_NOW;
+               fbi->var.height = 0;
+               fbi->var.width = 0;
+               fbi->var.pixclock = active_video_mode.vmode_data.pixclock;
+               fbi->var.left_margin = active_video_mode.vmode_data.left_margin;
+               fbi->var.right_margin = active_video_mode.vmode_data.right_margin;
+               fbi->var.upper_margin = active_video_mode.vmode_data.upper_margin;
+               fbi->var.lower_margin = active_video_mode.vmode_data.lower_margin;
+               fbi->var.hsync_len = active_video_mode.vmode_data.hsync_len;
+               fbi->var.vsync_len = active_video_mode.vmode_data.vsync_len;
+               fbi->var.sync = 0;
+               fbi->var.vmode = FB_VMODE_NONINTERLACED;
+               fbi->var.rotate = 0;
+
+               if (fb_alloc_cmap(&fbi->cmap, 256, 1)) {
+                       rc = -ENOMEM;
+                       goto err_fb;
+               }
+
+               regfb = register_framebuffer(fbi);
+               if (regfb) {
+                       printk(KERN_ERR "Error registering xylonfb %d\n", i);
+                       goto err_fb;
+               } else
+                       printk(KERN_INFO "xylonfb %d registered\n", i);
+
+               init_waitqueue_head(&layer_data->vsync.wait);
+       }
+
+//     if (request_irq(irq, xylonfb_irq, IRQF_SHARED, "xylonfb", fbi))
+//             goto err_fb;
+
+       atomic_set(&xylonfb_use_ref, 0);
+       dev_set_drvdata(dev, (void *)afbi);
+
+       /* start logiCVC HW */
+       if (startup_layer == 0) {
+               for (i = 0; i < layers; i++)
+                       if (afbi[i]->fix.visual == FB_VISUAL_TRUECOLOR)
+                               break;
+       } else {
+               i = startup_layer - 1;
+       }
+       if (i < layers) {
+               /* start 32-bit layer */
+               xylonfb_hw_start(afbi[i]);
+               /* Turn OFF unused layers */
+               on = i;
+               for (i = 0; i < layers; i++) {
+                       if (i == on)
+                               continue;
+                       fbi = afbi[i];
+                       layer_data = (struct xylonfb_layer_data *)fbi->par;
+                       writel(0, (layer_data->layer_reg_base_virt + CVC_LAYER_CTRL_ROFF));
+               }
+       } else
+               printk(KERN_ERR "No 32-bit logiCVC layer found!\nxylonfb disabled\n");
+
+       return 0;
+
+err_fb:
+       for (; i < layers; i++) {
+               fbi = afbi[i];
+               if (fbi)
+                       layer_data = fbi->par;
+
+               if (regfb == 0)
+                       unregister_framebuffer(fbi);
+               else
+                       regfb = 0;
+               if (fbi->cmap.red)
+                       fb_dealloc_cmap(&fbi->cmap);
+               if (layer_data) {
+                       if (layer_data->fb_flags & FB_DMA_BUFFER) {
+                               /* NOT USED FOR NOW! */
+                               dma_free_coherent(dev, PAGE_ALIGN(fbi->fix.smem_len),
+                                       layer_data->fb_virt, layer_data->fb_phys);
+                       } else {
+                               if (layer_data->fb_virt)
+                                       iounmap(layer_data->fb_virt);
+                       }
+                       if (layer_data->reg_base_virt)
+                               iounmap(layer_data->reg_base_virt);
+                       framebuffer_release(fbi);
+               }
+       }
+
+       dev_set_drvdata(dev, NULL);
+
+       return rc;
+}
+
+static int xylonfb_remove(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct fb_info **afbi = (struct fb_info **)dev_get_drvdata(dev);
+       struct fb_info *fbi;
+       struct xylonfb_layer_data *layer_data;
+       int i, use;
+       bool cvc_off = 0;
+
+       dbg("%s", __func__);
+
+       use = atomic_read(&xylonfb_use_ref);
+       if (use) {
+               printk(KERN_ERR "xylonfb driver is in use\n");
+               return -EINVAL;
+       }
+
+       for (i = ARRAY_SIZE(logiCVC_platform_data)-1; i >= 0; i--) {
+               fbi = afbi[i];
+               layer_data = fbi->par;
+               if (!cvc_off) {
+                       /* disable logiCVC */
+                       writel(0, layer_data->reg_base_virt + CVC_SCTRL_ROFF);
+                       cvc_off = 1;
+               }
+               unregister_framebuffer(fbi);
+               fb_dealloc_cmap(&fbi->cmap);
+               if (layer_data->fb_flags & FB_DMA_BUFFER) {
+                       dma_free_coherent(dev, PAGE_ALIGN(fbi->fix.smem_len),
+                               layer_data->fb_virt, layer_data->fb_phys);
+               } else {
+                       iounmap(layer_data->fb_virt);
+               }
+               iounmap(layer_data->reg_base_virt);
+               framebuffer_release(fbi);
+       }
+
+       dev_set_drvdata(dev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver xylonfb_driver = {
+       .probe = xylonfb_probe,
+       .remove = xylonfb_remove,
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = DRIVER_NAME,
+       },
+};
+
+
+static struct platform_device xylonfb_device = {
+       .name = DRIVER_NAME,
+       .id = -1,
+};
+
+
+/* Set initial display parameters.
+   First check if video mode (input parameter) is set, if it's not, then set it to default mode.
+   After the video mode is set, check if any of the input parameters is set and change that parameter
+   in already selected mode. This alows us to set new mode without need to set all parameters for it,
+   just choose similar mode and change parameters that needs to be changed to get desired mode.  
+*/
+static void __init xylonfb_set_params(void)
+{
+       int i;
+       bool video_mode_set = 0;
+
+       dbg("%s", __func__);
+
+       /* Set video mode */
+       if (0 != video_mode_code) {
+               for (i = 0; i < ARRAY_SIZE(video_modes); i++) {
+                       if (video_modes[i].VESA_code == video_mode_code) {
+                               active_video_mode.bpp = video_modes[i].bpp;
+                               active_video_mode.vmode_data = *video_modes[i].vmode_data;
+                               video_mode_set = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (0 == video_mode_set) {
+               if (0 == video_mode_code) {
+                       /* Set default video mode */
+                       active_video_mode.bpp = video_modes[DEFAULT_VIDEO_MODE].bpp;
+                       active_video_mode.vmode_data =
+                               *video_modes[DEFAULT_VIDEO_MODE].vmode_data;
+               } else if (LOGICVC_USER_CONFIGURATION == video_mode_code) {
+                       /* Set video mode with input parameters */
+                       if(0 != hfp)
+                               active_video_mode.vmode_data.right_margin = hfp;
+                       if(0 != hsync)
+                               active_video_mode.vmode_data.hsync_len = hsync;
+                       if(0 != hbp)
+                               active_video_mode.vmode_data.left_margin = hbp;
+                       if(0 != hres)
+                               active_video_mode.vmode_data.xres = hres;
+                       if(0 != vfp)
+                               active_video_mode.vmode_data.lower_margin = vfp;
+                       if(0 != vsync)
+                               active_video_mode.vmode_data.vsync_len = vsync;
+                       if(0 != vbp)
+                               active_video_mode.vmode_data.upper_margin = vbp;
+                       if(0 != vres)
+                               active_video_mode.vmode_data.yres = vres;
+                       if(0 != pix_clk)
+                               active_video_mode.vmode_data.pixclock = pix_clk;
+                       if(0 != bpp)
+                               active_video_mode.bpp = bpp;
+               }
+       }
+
+       /* Set logiCVC HW platform parameters */
+       for (i = 0; i < ARRAY_SIZE(logiCVC_platform_data); i++) {
+               if(0 != hres)
+                       logiCVC_platform_data[i].xres = hres;
+               else
+                       logiCVC_platform_data[i].xres = active_video_mode.vmode_data.xres;
+               if(0 != vres)
+                       logiCVC_platform_data[i].yres = vres;
+               else
+                       logiCVC_platform_data[i].yres = active_video_mode.vmode_data.yres;
+               if(0 != virt_hres)
+                       logiCVC_platform_data[i].xvirt = virt_hres;
+               if(0 != virt_vres)
+                       logiCVC_platform_data[i].yvirt = virt_vres;
+               if(0 != row_stride)
+                       logiCVC_platform_data[i].row_stride = row_stride;
+               if(0 != regs_baseaddr)
+                       logiCVC_platform_data[i].regs_baseaddr = regs_baseaddr;
+               if(0 != vmem_baseaddr)
+                       logiCVC_platform_data[i].vmem_baseaddr = vmem_baseaddr;
+       }
+}
+
+#ifdef ARM8_BOARD
+static void __init config_clk(void)
+{
+#define CLOCK_REGISTERS_BASEADDR 0x18007000
+#define CLOCK_REGISTERS_RANGE 0x18
+#define GPOUT_REG_OFF 0x10
+#define PWM_REG_OFF 0x14
+#define PWR_REG_DISPLAY_POWER_MSK 1
+#define PWR_REG_BACKLIGHT_POWER_MSK 2
+#define BACKLIGHT_MAX_VALUE 255
+       void *clk_reg_base_virt;
+       void *cvc_reg_base_virt;
+       u32 val;
+
+       dbg("%s", __func__);
+
+       clk_reg_base_virt =
+               ioremap_nocache(CLOCK_REGISTERS_BASEADDR, CLOCK_REGISTERS_RANGE);
+       cvc_reg_base_virt =
+               ioremap_nocache(logiCVC_platform_data[0].regs_baseaddr, CVC_GENERAL_REGISTERS_RANGE);
+
+       /*
+               Available display resolutions:
+               0x0000 - 640x480
+               0x2000 - 800x600
+               0x4000 - 1024x768
+               0x6000 - 1280x1024
+       */
+       /* reset FPGA */
+       writel(0x01000000, clk_reg_base_virt + GPOUT_REG_OFF);
+       udelay(100);
+       /* set logiCVC input clock divider */
+       writel(0x2000, cvc_reg_base_virt + CVC_SCTRL_ROFF);
+       udelay(100);
+       val = readl(cvc_reg_base_virt + CVC_SCTRL_ROFF);
+       val |= 0x8000;
+       /* set VCLKSEL2 bit */
+       writel(val, cvc_reg_base_virt + CVC_SCTRL_ROFF);
+       val &= ~0x8000;
+       /* set video PLL reset */
+       writel(0x01000000, clk_reg_base_virt);
+       udelay(10);
+       /* clear VCLKSEL2 bit */
+       writel(val, cvc_reg_base_virt + CVC_SCTRL_ROFF);
+       udelay(10);
+       /* release video PLL reset */
+       writel(0, clk_reg_base_virt);
+       udelay(10);
+
+       writel(PWR_REG_DISPLAY_POWER_MSK, clk_reg_base_virt + GPOUT_REG_OFF);
+
+       val = readl(clk_reg_base_virt + GPOUT_REG_OFF);
+       writel((val | PWR_REG_BACKLIGHT_POWER_MSK),
+               clk_reg_base_virt + GPOUT_REG_OFF);
+       writel((BACKLIGHT_MAX_VALUE / 2), clk_reg_base_virt + PWM_REG_OFF);
+
+       iounmap(cvc_reg_base_virt);
+       iounmap(clk_reg_base_virt);
+}
+#endif /* #ifdef ARM8_BOARD */
+
+static int __init xylonfb_setup(char *options)
+{
+       char *this_opt;
+
+       dbg("%s", __func__);
+
+       if (!options || !*options)
+               return 0;
+
+       while ((this_opt = strsep(&options, ",")) != NULL) {
+               if (!*this_opt)
+                       continue;
+       }
+
+       return 0;
+}
+
+static void xylonfb_dev_release(struct device *dev)
+{
+       dbg("%s", __func__);
+}
+
+static int __init xylonfb_init(void)
+{
+       char *option = NULL;
+       int ret;
+
+       dbg("%s", __func__);
+
+       /*
+        *  For kernel boot options (in 'video=xxxfb:<options>' format)
+        */
+       if (fb_get_options(DRIVER_NAME, &option))
+               return -ENODEV;
+
+       /* Set internal module parameters */
+       xylonfb_setup(option);
+       /* Check input parameters */
+       xylonfb_set_params();
+
+#ifdef ARM8_BOARD
+       config_clk();
+#endif
+
+       ret = platform_driver_register(&xylonfb_driver);
+       if (!ret) {
+               xylonfb_device.dev.release = xylonfb_dev_release;
+               ret = platform_device_register(&xylonfb_device);
+               if (ret) {
+                       platform_driver_unregister(&xylonfb_driver);
+                       printk(KERN_ERR "xylonfb device registration failed\n");
+               }
+       }
+
+       return ret;
+}
+
+static void __exit xylonfb_exit(void)
+{
+       dbg("%s", __func__);
+
+       platform_device_unregister(&xylonfb_device);
+       platform_driver_unregister(&xylonfb_driver);
+}
+
+
+module_init(xylonfb_init);
+module_exit(xylonfb_exit);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
diff --git a/drivers/video/xylonfb.h b/drivers/video/xylonfb.h
new file mode 100755 (executable)
index 0000000..ba7bc6e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * XYLON logiCVC frame buffer driver
+ *
+ * Author: Xylon d.o.o.
+ *
+ * 2002-2007 (c) MontaVista Software, Inc.
+ * 2007 (c) Secret Lab Technologies, Ltd.
+ * 2009 (c) Xilinx Inc.
+ * 2011 (c) Xylon d.o.o.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2.  This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef        __XYLON_FB_H__
+#define __XYLON_FB_H__
+
+#define XYLONFB_IOC_MAGIC   'x'
+#define XYLONFB_IOC_GETVRAM _IO(XYLONFB_IOC_MAGIC, 0)
+
+/* Supported video modes. */
+#define XYLONFB_VM_VESA_640_480_8  0x101
+#define XYLONFB_VM_VESA_640_480_16 0x111
+#define XYLONFB_VM_VESA_640_480_32 0x112
+
+#define XYLONFB_VM_VESA_800_600_8  0x103
+#define XYLONFB_VM_VESA_800_600_16 0x114
+#define XYLONFB_VM_VESA_800_600_32 0x115
+
+#define XYLONFB_VM_VESA_1024_768_8  0x105
+#define XYLONFB_VM_VESA_1024_768_16 0x117
+#define XYLONFB_VM_VESA_1024_768_32 0x118
+
+#define XYLONFB_VM_VESA_1280_1024_8  0x107
+#define XYLONFB_VM_VESA_1280_1024_16 0x11A
+#define XYLONFB_VM_VESA_1280_1024_32 0x11B
+
+#endif // __XYLON_FB_H__