* [PATCH 08/10] fbdev: Xylon framebuffer driver to fbdev Kconfig and Makefile
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>
Adding Xylon framebuffer driver to fbdev Kconfig and Makefile.
Signed-off-by: Davor Joja <davorjoja@logicbricks.com>
---
drivers/video/fbdev/Kconfig | 1 +
drivers/video/fbdev/Makefile | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index b3dd417..3bd0693 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -2454,6 +2454,7 @@ source "drivers/video/fbdev/omap/Kconfig"
source "drivers/video/fbdev/omap2/Kconfig"
source "drivers/video/fbdev/exynos/Kconfig"
source "drivers/video/fbdev/mmp/Kconfig"
+source "drivers/video/fbdev/xylon/Kconfig"
config FB_SH_MOBILE_MERAM
tristate "SuperH Mobile MERAM read ahead support"
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile
index 1979aff..57cb259 100644
--- a/drivers/video/fbdev/Makefile
+++ b/drivers/video/fbdev/Makefile
@@ -132,6 +132,7 @@ obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o
obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o
obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o
obj-$(CONFIG_FB_OPENCORES) += ocfb.o
+obj-$(CONFIG_FB_XYLON) += xylon/
# Platform or fallback drivers go here
obj-$(CONFIG_FB_UVESA) += uvesafb.o
--
1.9.1
^ permalink raw reply related
* [PATCH 07/10] uapi: linux: Xylon framebuffer driver header file
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 header file containing structures and IOCTLs for user space
applications to be able to use advanced logiCVC hw functionality.
Signed-off-by: Davor Joja <davorjoja@logicbricks.com>
---
include/uapi/linux/xylonfb.h | 85 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 85 insertions(+)
create mode 100644 include/uapi/linux/xylonfb.h
diff --git a/include/uapi/linux/xylonfb.h b/include/uapi/linux/xylonfb.h
new file mode 100644
index 0000000..662c02f
--- /dev/null
+++ b/include/uapi/linux/xylonfb.h
@@ -0,0 +1,85 @@
+/*
+ * Xylon logiCVC frame buffer driver IOCTL parameters
+ *
+ * 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_H__
+#define __XYLONFB_H__
+
+#include <linux/types.h>
+
+struct xylonfb_hw_access {
+ __u32 offset;
+ __u32 value;
+ bool set;
+};
+
+/* Used only with logiCVC 3.x */
+struct xylonfb_layer_buffer {
+ __u8 id;
+ bool set;
+};
+
+struct xylonfb_layer_color {
+ __u32 raw_rgb;
+ __u8 use_raw;
+ __u8 r;
+ __u8 g;
+ __u8 b;
+ bool set;
+};
+
+struct xylonfb_layer_geometry {
+ __u16 x;
+ __u16 y;
+ __u16 width;
+ __u16 height;
+ __u16 x_offset;
+ __u16 y_offset;
+ bool set;
+};
+
+struct xylonfb_layer_transparency {
+ __u8 alpha;
+ bool set;
+};
+
+/* Xylon FB IOCTL's */
+#define XYLONFB_IOW(num, dtype) _IOW('x', num, dtype)
+#define XYLONFB_IOR(num, dtype) _IOR('x', num, dtype)
+#define XYLONFB_IOWR(num, dtype) _IOWR('x', num, dtype)
+#define XYLONFB_IO(num) _IO('x', num)
+
+#define XYLONFB_VSYNC_CTRL XYLONFB_IOR(30, bool)
+#define XYLONFB_LAYER_IDX XYLONFB_IOR(31, unsigned int)
+#define XYLONFB_LAYER_ALPHA \
+ XYLONFB_IOR(32, struct xylonfb_layer_transparency)
+#define XYLONFB_LAYER_COLOR_TRANSP_CTRL XYLONFB_IOW(33, bool)
+#define XYLONFB_LAYER_COLOR_TRANSP \
+ XYLONFB_IOR(34, struct xylonfb_layer_color)
+#define XYLONFB_LAYER_GEOMETRY \
+ XYLONFB_IOR(35, struct xylonfb_layer_geometry)
+#define XYLONFB_LAYER_BUFFER \
+ XYLONFB_IOR(36, struct xylonfb_layer_buffer)
+#define XYLONFB_LAYER_BUFFER_OFFSET XYLONFB_IOR(37, unsigned int)
+#define XYLONFB_BACKGROUND_COLOR \
+ XYLONFB_IOR(38, struct xylonfb_layer_color)
+#define XYLONFB_LAYER_EXT_BUFF_SWITCH XYLONFB_IOW(39, bool)
+#define XYLONFB_HW_ACCESS \
+ XYLONFB_IOR(40, struct xylonfb_hw_access)
+#define XYLONFB_IP_CORE_VERSION XYLONFB_IOR(41, __u32)
+#define XYLONFB_WAIT_EDID XYLONFB_IOW(42, unsigned int)
+#define XYLONFB_GET_EDID XYLONFB_IOR(43, char)
+
+#endif /* __XYLONFB_H__ */
--
1.9.1
^ permalink raw reply related
* [PATCH 06/10] fbdev: xylon: Framebuffer driver kernel and make configuration
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 kernel and build configuration.
Signed-off-by: Davor Joja <davorjoja@logicbricks.com>
---
drivers/video/fbdev/xylon/Kconfig | 31 +++++++++++++++++++++++++++++++
drivers/video/fbdev/xylon/Makefile | 3 +++
2 files changed, 34 insertions(+)
create mode 100644 drivers/video/fbdev/xylon/Kconfig
create mode 100644 drivers/video/fbdev/xylon/Makefile
diff --git a/drivers/video/fbdev/xylon/Kconfig b/drivers/video/fbdev/xylon/Kconfig
new file mode 100644
index 0000000..74278ad
--- /dev/null
+++ b/drivers/video/fbdev/xylon/Kconfig
@@ -0,0 +1,31 @@
+menuconfig FB_XYLON
+ tristate "Xylon logiCVC frame buffer support"
+ depends on FB
+ default n
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ select FB_MODE_HELPERS
+ select VIDEOMODE_HELPERS
+ help
+ Choose this option if you want to use the Xylon logiCVC as frame
+ buffer device. Without the support of PCI & AGP.
+
+config FB_XYLON_PIXCLK
+ bool "Xylon logiCVC pixel clock"
+ depends on FB_XYLON
+ default n
+ help
+ logiCVC pixel clock generated from:
+ - External generator not controllable by Xylon framebuffer driver
+ This is default selection.
+ - Generators controllable by Xylon framebuffer driver
+
+config FB_XYLON_PIXCLK_LOGICLK
+ bool "Xylon logiCLK pixel clock generator"
+ depends on FB_XYLON && FB_XYLON_PIXCLK
+ default n
+ select COMMON_CLK_LOGICLK
+ help
+ Support for controlling pixel clock generation from
+ Xylon logiCLK FGPA IP core.
diff --git a/drivers/video/fbdev/xylon/Makefile b/drivers/video/fbdev/xylon/Makefile
new file mode 100644
index 0000000..3baa96a
--- /dev/null
+++ b/drivers/video/fbdev/xylon/Makefile
@@ -0,0 +1,3 @@
+xylonfb-y := xylonfb_main.o xylonfb_core.o xylonfb_ioctl.o xylonfb_pixclk.o
+
+obj-$(CONFIG_FB_XYLON) += xylonfb.o
--
1.9.1
^ permalink raw reply related
* [PATCH 05/10] fbdev: xylon: logiCVC IP core definitions
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 hw parameters and definitions for logiCVC IP core.
Signed-off-by: Davor Joja <davorjoja@logicbricks.com>
---
drivers/video/fbdev/xylon/logicvc.h | 192 ++++++++++++++++++++++++++++++++++++
1 file changed, 192 insertions(+)
create mode 100644 drivers/video/fbdev/xylon/logicvc.h
diff --git a/drivers/video/fbdev/xylon/logicvc.h b/drivers/video/fbdev/xylon/logicvc.h
new file mode 100644
index 0000000..7c1266e
--- /dev/null
+++ b/drivers/video/fbdev/xylon/logicvc.h
@@ -0,0 +1,192 @@
+/*
+ * Xylon logiCVC IP core parameters
+ *
+ * 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 __LOGICVC_H__
+#define __LOGICVC_H__
+
+/*
+ * All logiCVC registers are only 32-bit accessible.
+ * All logiCVC registers are aligned to 8 byte boundary.
+ */
+#define LOGICVC_REG_STRIDE 8
+#define LOGICVC_HSYNC_FRONT_PORCH_ROFF (0 * LOGICVC_REG_STRIDE)
+#define LOGICVC_HSYNC_ROFF (1 * LOGICVC_REG_STRIDE)
+#define LOGICVC_HSYNC_BACK_PORCH_ROFF (2 * LOGICVC_REG_STRIDE)
+#define LOGICVC_HRES_ROFF (3 * LOGICVC_REG_STRIDE)
+#define LOGICVC_VSYNC_FRONT_PORCH_ROFF (4 * LOGICVC_REG_STRIDE)
+#define LOGICVC_VSYNC_ROFF (5 * LOGICVC_REG_STRIDE)
+#define LOGICVC_VSYNC_BACK_PORCH_ROFF (6 * LOGICVC_REG_STRIDE)
+#define LOGICVC_VRES_ROFF (7 * LOGICVC_REG_STRIDE)
+#define LOGICVC_CTRL_ROFF (8 * LOGICVC_REG_STRIDE)
+#define LOGICVC_DTYPE_ROFF (9 * LOGICVC_REG_STRIDE)
+#define LOGICVC_BACKGROUND_COLOR_ROFF (10 * LOGICVC_REG_STRIDE)
+#define LOGICVC_CLUT_SELECT_ROFF (12 * LOGICVC_REG_STRIDE)
+#define LOGICVC_INT_STAT_ROFF (13 * LOGICVC_REG_STRIDE)
+#define LOGICVC_INT_MASK_ROFF (14 * LOGICVC_REG_STRIDE)
+#define LOGICVC_POWER_CTRL_ROFF (15 * LOGICVC_REG_STRIDE)
+#define LOGICVC_IP_VERSION_ROFF (31 * LOGICVC_REG_STRIDE)
+/* Version 3.x */
+#define LOGICVC_VBUFF_SELECT_ROFF (11 * LOGICVC_REG_STRIDE)
+
+/*
+ * logiCVC layer registers offsets (common for each layer)
+ * Last possible logiCVC layer (No.4) implements only "Layer memory address"
+ * and "Layer control" registers.
+ */
+/* Version 3.x */
+#define LOGICVC_LAYER_HOFF_ROFF (0 * LOGICVC_REG_STRIDE)
+#define LOGICVC_LAYER_VOFF_ROFF (1 * LOGICVC_REG_STRIDE)
+/* Version 4.x */
+#define LOGICVC_LAYER_ADDR_ROFF (0 * LOGICVC_REG_STRIDE)
+/* Common */
+#define LOGICVC_LAYER_HPOS_ROFF (2 * LOGICVC_REG_STRIDE)
+#define LOGICVC_LAYER_VPOS_ROFF (3 * LOGICVC_REG_STRIDE)
+#define LOGICVC_LAYER_HSIZE_ROFF (4 * LOGICVC_REG_STRIDE)
+#define LOGICVC_LAYER_VSIZE_ROFF (5 * LOGICVC_REG_STRIDE)
+#define LOGICVC_LAYER_ALPHA_ROFF (6 * LOGICVC_REG_STRIDE)
+#define LOGICVC_LAYER_CTRL_ROFF (7 * LOGICVC_REG_STRIDE)
+#define LOGICVC_LAYER_TRANSP_COLOR_ROFF (8 * LOGICVC_REG_STRIDE)
+
+/* logiCVC interrupt bits */
+#define LOGICVC_INT_L0_UPDATED (1 << 0)
+#define LOGICVC_INT_L1_UPDATED (1 << 1)
+#define LOGICVC_INT_L2_UPDATED (1 << 2)
+#define LOGICVC_INT_L3_UPDATED (1 << 3)
+#define LOGICVC_INT_L4_UPDATED (1 << 4)
+#define LOGICVC_INT_V_SYNC (1 << 5)
+#define LOGICVC_INT_E_VIDEO_VALID (1 << 6)
+#define LOGICVC_INT_FIFO_UNDERRUN (1 << 7)
+#define LOGICVC_INT_L0_CLUT_SW (1 << 8)
+#define LOGICVC_INT_L1_CLUT_SW (1 << 9)
+#define LOGICVC_INT_L2_CLUT_SW (1 << 10)
+#define LOGICVC_INT_L3_CLUT_SW (1 << 11)
+#define LOGICVC_INT_L4_CLUT_SW (1 << 12)
+
+/* logiCVC layer base offsets */
+#define LOGICVC_LAYER_OFFSET 0x80
+#define LOGICVC_LAYER_BASE_OFFSET 0x100
+#define LOGICVC_LAYER_BASE_END 0x338
+#define LOGICVC_LAYER_0_OFFSET (0 * LOGICVC_LAYER_OFFSET)
+#define LOGICVC_LAYER_1_OFFSET (1 * LOGICVC_LAYER_OFFSET)
+#define LOGICVC_LAYER_2_OFFSET (2 * LOGICVC_LAYER_OFFSET)
+#define LOGICVC_LAYER_3_OFFSET (3 * LOGICVC_LAYER_OFFSET)
+#define LOGICVC_LAYER_4_OFFSET (4 * LOGICVC_LAYER_OFFSET)
+
+/* logiCVC layer CLUT base offsets */
+#define LOGICVC_CLUT_OFFSET 0x800
+#define LOGICVC_CLUT_BASE_OFFSET 0x1000
+#define LOGICVC_CLUT_L0_CLUT_0_OFFSET (0 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_L0_CLUT_1_OFFSET (1 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_L1_CLUT_0_OFFSET (2 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_L1_CLUT_1_OFFSET (3 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_L2_CLUT_0_OFFSET (4 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_L2_CLUT_1_OFFSET (5 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_L3_CLUT_0_OFFSET (6 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_L3_CLUT_1_OFFSET (7 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_L4_CLUT_0_OFFSET (8 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_L4_CLUT_1_OFFSET (9 * LOGICVC_CLUT_OFFSET)
+#define LOGICVC_CLUT_REGISTER_SIZE 8
+#define LOGICVC_CLUT_0_INDEX_OFFSET 2
+#define LOGICVC_CLUT_1_INDEX_OFFSET 1
+
+/* logiCVC registers range */
+#define LOGICVC_REGISTERS_RANGE 0x6000
+#define LOGICVC_LAYER_REGISTERS_RANGE 0x80
+
+/* logiCVC control register bits */
+#define LOGICVC_CTRL_HSYNC (1 << 0)
+#define LOGICVC_CTRL_HSYNC_INVERT (1 << 1)
+#define LOGICVC_CTRL_VSYNC (1 << 2)
+#define LOGICVC_CTRL_VSYNC_INVERT (1 << 3)
+#define LOGICVC_CTRL_DATA_ENABLE (1 << 4)
+#define LOGICVC_CTRL_DATA_ENABLE_INVERT (1 << 5)
+#define LOGICVC_CTRL_PIXEL_DATA_INVERT (1 << 7)
+#define LOGICVC_CTRL_PIXEL_DATA_TRIGGER_INVERT (1 << 8)
+#define LOGICVC_CTRL_DISABLE_LAYER_UPDATE (1 << 9)
+
+/* logiCVC layer control register bits */
+#define LOGICVC_LAYER_CTRL_ENABLE (1 << 0)
+#define LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_DISABLE (1 << 1)
+#define LOGICVC_LAYER_CTRL_EXTERNAL_BUFFER_SWITCH (1 << 2)
+#define LOGICVC_LAYER_CTRL_INTERLACE (1 << 3)
+#define LOGICVC_LAYER_CTRL_PIXEL_FORMAT_ABGR (1 << 4)
+
+/* logiCVC register initial values */
+#define LOGICVC_DTYPE_REG_INIT 0
+
+/* logiCVC display power signals */
+#define LOGICVC_EN_BLIGHT_MSK (1 << 0)
+#define LOGICVC_EN_VDD_MSK (1 << 1)
+#define LOGICVC_EN_VEE_MSK (1 << 2)
+#define LOGICVC_V_EN_MSK (1 << 3)
+
+/* logiCVC various definitions */
+#define LOGICVC_MAJOR_REVISION_SHIFT 11
+#define LOGICVC_MAJOR_REVISION_MASK 0x3F
+#define LOGICVC_MINOR_REVISION_SHIFT 5
+#define LOGICVC_MINOR_REVISION_MASK 0x3F
+#define LOGICVC_PATCH_LEVEL_MASK 0x1F
+
+#define LOGICVC_MAX_LAYER_BUFFERS 3
+#define LOGICVC_MIN_XRES 64
+#define LOGICVC_MIN_VRES 1
+#define LOGICVC_MAX_XRES 2048
+#define LOGICVC_MAX_VRES 2048
+#define LOGICVC_CLUT_SIZE 256
+
+#define LOGICVC_COEFF_Y_R 29900
+#define LOGICVC_COEFF_Y_G 58700
+#define LOGICVC_COEFF_Y_B 11400
+#define LOGICVC_COEFF_Y 0
+#define LOGICVC_COEFF_U 12800000
+#define LOGICVC_COEFF_V 12800000
+#define LOGICVC_COEFF_U_R 16868
+#define LOGICVC_COEFF_U_G 33107
+#define LOGICVC_COEFF_U_B 49970
+#define LOGICVC_COEFF_V_R 49980
+#define LOGICVC_COEFF_V_G 41850
+#define LOGICVC_COEFF_V_B 8128
+#define LOGICVC_COEFF_ITU656_Y 1600000
+#define LOGICVC_COEFF_ITU656_U_R 17258
+#define LOGICVC_COEFF_ITU656_U_G 33881
+#define LOGICVC_COEFF_ITU656_U_B 51140
+#define LOGICVC_COEFF_ITU656_V_R 51138
+#define LOGICVC_COEFF_ITU656_V_G 42820
+#define LOGICVC_COEFF_ITU656_V_B 8316
+#define LOGICVC_YUV_NORM 100000
+#define LOGICVC_COEFF_R_U 1402524
+#define LOGICVC_COEFF_R 179000000
+#define LOGICVC_COEFF_G_U 714403
+#define LOGICVC_COEFF_G_V 344340
+#define LOGICVC_COEFF_G 135000000
+#define LOGICVC_COEFF_B_V 1773049
+#define LOGICVC_COEFF_B 226000000
+#define LOGICVC_RGB_NORM 1000000
+
+enum xylonfb_layer_type {
+ LOGICVC_LAYER_RGB,
+ LOGICVC_LAYER_YUV,
+ LOGICVC_LAYER_ALPHA
+};
+
+enum xylonfb_alpha_type {
+ LOGICVC_ALPHA_LAYER,
+ LOGICVC_ALPHA_PIXEL,
+ LOGICVC_ALPHA_CLUT_16BPP,
+ LOGICVC_ALPHA_CLUT_32BPP
+};
+
+#endif /* __LOGICVC_H__ */
--
1.9.1
^ permalink raw reply related
* [PATCH 04/10] fbdev: xylon: Framebuffer driver pixel clock
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 pixel clock control functionality supporting optional Xylon logiCLK IP
core clock generator.
Signed-off-by: Davor Joja <davorjoja@logicbricks.com>
---
drivers/video/fbdev/xylon/xylonfb_pixclk.c | 119 +++++++++++++++++++++++++++++
1 file changed, 119 insertions(+)
create mode 100644 drivers/video/fbdev/xylon/xylonfb_pixclk.c
diff --git a/drivers/video/fbdev/xylon/xylonfb_pixclk.c b/drivers/video/fbdev/xylon/xylonfb_pixclk.c
new file mode 100644
index 0000000..d63dbeb
--- /dev/null
+++ b/drivers/video/fbdev/xylon/xylonfb_pixclk.c
@@ -0,0 +1,119 @@
+/*
+ * Xylon logiCVC frame buffer driver pixel clock control
+ *
+ * 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/clk.h>
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+
+struct xylonfb_pixclk {
+ struct device *dev;
+ struct device_node *dn;
+ struct clk *clk;
+};
+
+#if defined(CONFIG_FB_XYLON_PIXCLK_LOGICLK)
+static const struct of_device_id logiclk_of_match[] = {
+ { .compatible = "xylon,logiclk-1.02.b" },
+ {/* end of table */}
+};
+static struct xylonfb_pixclk logiclk;
+#endif
+
+bool xylonfb_hw_pixclk_supported(struct device *dev, struct device_node *dn);
+void xylonfb_hw_pixclk_unload(struct device_node *dn);
+int xylonfb_hw_pixclk_set(struct device *dev, struct device_node *dn,
+ unsigned long pixclk_khz);
+
+#if defined(CONFIG_FB_XYLON_PIXCLK)
+static int xylonfb_hw_pixclk_set_freq(struct device *dev,
+ struct device_node *dn,
+ unsigned long freq_khz)
+{
+ struct clk *clk = NULL;
+
+#if defined(CONFIG_FB_XYLON_PIXCLK_LOGICLK)
+ if (dn = logiclk.dn)
+ clk = logiclk.clk;
+#endif
+
+ if (clk && clk_set_rate(clk, (freq_khz * 1000))) {
+ dev_err(dev, "failed set pixel clock frequency\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+#endif
+
+bool xylonfb_hw_pixclk_supported(struct device *dev, struct device_node *dn)
+{
+#if defined(CONFIG_FB_XYLON_PIXCLK)
+ struct clk **clk;
+ bool clk_dev = false;
+
+#if defined(CONFIG_FB_XYLON_PIXCLK_LOGICLK)
+ if (of_match_node(logiclk_of_match, of_get_parent(dn))) {
+ clk = &logiclk.clk;
+ logiclk.dev = dev;
+ logiclk.dn = dn;
+ clk_dev = true;
+ }
+#endif
+
+ if (clk_dev) {
+ *clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(*clk)) {
+ dev_err(dev, "failed get pixel clock\n");
+ return false;
+ }
+ if (clk_prepare_enable(*clk)) {
+ dev_err(dev,
+ "failed prepare/enable pixel clock\n");
+ return false;
+ }
+
+ return true;
+ } else {
+ return false;
+ }
+#else
+ return true;
+#endif
+}
+
+void xylonfb_hw_pixclk_unload(struct device_node *dn)
+{
+ struct clk *clk = NULL;
+
+#if defined(CONFIG_FB_XYLON_PIXCLK_LOGICLK)
+ clk = logiclk.clk;
+#endif
+
+ if (clk)
+ clk_disable_unprepare(clk);
+}
+
+int xylonfb_hw_pixclk_set(struct device *dev, struct device_node *dn,
+ unsigned long pixclk_khz)
+{
+#if defined(CONFIG_FB_XYLON_PIXCLK)
+ return xylonfb_hw_pixclk_set_freq(dev, dn, pixclk_khz);
+#else
+ dev_warn(dev, "pixel clock control not supported\n");
+ return -ENODEV;
+#endif
+}
--
1.9.1
^ permalink raw reply related
* [PATCH 03/10] fbdev: xylon: Framebuffer driver ioctl
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 IOCTL providing advanced video controller functionality used by user
space applications.
Signed-off-by: Davor Joja <davorjoja@logicbricks.com>
---
drivers/video/fbdev/xylon/xylonfb_ioctl.c | 672 ++++++++++++++++++++++++++++++
1 file changed, 672 insertions(+)
create mode 100644 drivers/video/fbdev/xylon/xylonfb_ioctl.c
diff --git a/drivers/video/fbdev/xylon/xylonfb_ioctl.c b/drivers/video/fbdev/xylon/xylonfb_ioctl.c
new file mode 100644
index 0000000..131bdcf
--- /dev/null
+++ b/drivers/video/fbdev/xylon/xylonfb_ioctl.c
@@ -0,0 +1,672 @@
+/*
+ * Xylon logiCVC frame buffer driver IOCTL functionality
+ *
+ * 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/platform_device.h>
+#include <linux/uaccess.h>
+#include <uapi/linux/xylonfb.h>
+
+#include "logicvc.h"
+#include "xylonfb_core.h"
+
+static int xylonfb_get_vblank(struct fb_vblank *vblank, struct fb_info *fbi)
+{
+ vblank->flags |= FB_VBLANK_HAVE_VSYNC;
+
+ return 0;
+}
+
+static void xylonfb_vsync_ctrl(struct fb_info *fbi, bool enable)
+{
+ struct xylonfb_layer_data *ld = fbi->par;
+ struct xylonfb_data *data = ld->data;
+ u32 imr;
+
+ mutex_lock(&data->irq_mutex);
+
+ imr = data->reg_access.get_reg_val(data->dev_base,
+ LOGICVC_INT_MASK_ROFF, ld);
+ if (enable) {
+ imr &= (~LOGICVC_INT_V_SYNC);
+ writel(LOGICVC_INT_V_SYNC,
+ data->dev_base + LOGICVC_INT_STAT_ROFF);
+ } else {
+ imr |= LOGICVC_INT_V_SYNC;
+ }
+
+ data->reg_access.set_reg_val(imr, data->dev_base,
+ LOGICVC_INT_MASK_ROFF, ld);
+
+ mutex_unlock(&data->irq_mutex);
+}
+
+int xylonfb_vsync_wait(u32 crt, struct fb_info *fbi)
+{
+ struct xylonfb_layer_data *ld = fbi->par;
+ struct xylonfb_data *data = ld->data;
+ int ret, count;
+
+ mutex_lock(&data->irq_mutex);
+
+ count = data->vsync.count;
+
+ ret = wait_event_interruptible_timeout(data->vsync.wait,
+ (count != data->vsync.count),
+ HZ/10);
+
+ mutex_unlock(&data->irq_mutex);
+
+ if (ret < 0)
+ return ret;
+ else if (ret = 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static unsigned int alpha_normalized(unsigned int alpha, unsigned int used_bits,
+ bool set)
+{
+ if (set)
+ return alpha / (255 / ((1 << used_bits) - 1));
+ else
+ return (((255 << 16) / ((1 << used_bits) - 1)) * alpha) >> 16;
+}
+
+static int xylonfb_layer_alpha(struct xylonfb_layer_data *ld, u8 *alpha,
+ bool set)
+{
+ struct xylonfb_data *data = ld->data;
+ struct xylonfb_layer_fix_data *fd = ld->fd;
+ unsigned int used_bits;
+ u32 val;
+
+ if (fd->transparency != LOGICVC_ALPHA_LAYER)
+ return -EPERM;
+
+ switch (fd->type) {
+ case LOGICVC_LAYER_YUV:
+ used_bits = 8;
+ break;
+ case LOGICVC_LAYER_RGB:
+ switch (fd->bpp) {
+ case 8:
+ used_bits = 3;
+ break;
+ case 16:
+ used_bits = 6;
+ break;
+ case 32:
+ used_bits = 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!set) {
+ val = data->reg_access.get_reg_val(ld->base,
+ LOGICVC_LAYER_ALPHA_ROFF,
+ ld);
+ *alpha = (u8)(val & (0xFF >> (8 - used_bits)));
+ }
+
+ /* get/set normalized alpha value */
+ *alpha = alpha_normalized(*alpha, used_bits, set);
+
+ if (set)
+ data->reg_access.set_reg_val(*alpha, ld->base,
+ LOGICVC_LAYER_ALPHA_ROFF,
+ ld);
+
+ return 0;
+}
+
+static int xylonfb_layer_buff(struct fb_info *fbi,
+ struct xylonfb_layer_buffer *layer_buff,
+ bool set)
+{
+ struct xylonfb_layer_data *ld = fbi->par;
+ unsigned int layer_id = ld->fd->id;
+ u32 reg;
+
+ if (set) {
+ if (layer_buff->id >= LOGICVC_MAX_LAYER_BUFFERS)
+ return -EINVAL;
+
+ reg = readl(ld->data->dev_base + LOGICVC_VBUFF_SELECT_ROFF);
+ reg |= (1 << (10 + layer_id));
+ reg &= ~(0x03 << (layer_id << 1));
+ reg |= (layer_buff->id << (layer_id << 1));
+ writel(reg, ld->data->dev_base + LOGICVC_VBUFF_SELECT_ROFF);
+
+ xylonfb_vsync_wait(0, fbi);
+ } else {
+ reg = readl(ld->data->dev_base + LOGICVC_VBUFF_SELECT_ROFF);
+ reg >>= ((layer_id << 1));
+ layer_buff->id = reg & 0x03;
+ }
+
+ return 0;
+}
+
+static void xylonfb_rgb_yuv(u32 c1, u32 c2, u32 c3, u32 *pixel,
+ struct xylonfb_layer_data *ld, bool rgb2yuv)
+{
+ struct xylonfb_data *data = ld->data;
+ u32 r, g, b, y, u, v;
+
+ if (rgb2yuv) {
+ y = ((data->coeff.cyr * c1) + (data->coeff.cyg * c2) +
+ (data->coeff.cyb * c3) + data->coeff.cy) /
+ LOGICVC_YUV_NORM;
+ u = ((-data->coeff.cur * c1) - (data->coeff.cug * c2) +
+ (data->coeff.cub * c3) + LOGICVC_COEFF_U) /
+ LOGICVC_YUV_NORM;
+ v = ((data->coeff.cvr * c1) - (data->coeff.cvg * c2) -
+ (data->coeff.cvb * c3) + LOGICVC_COEFF_V) /
+ LOGICVC_YUV_NORM;
+
+ *pixel = (0xFF << 24) | (y << 16) | (u << 8) | v;
+ } else {
+ r = ((c1 * LOGICVC_RGB_NORM) + (LOGICVC_COEFF_R_U * c2) -
+ LOGICVC_COEFF_R) / LOGICVC_RGB_NORM;
+ g = ((c1 * LOGICVC_RGB_NORM) - (LOGICVC_COEFF_G_U * c2) -
+ (LOGICVC_COEFF_G_V * c3) + LOGICVC_COEFF_G) /
+ LOGICVC_RGB_NORM;
+ b = ((c1 * LOGICVC_RGB_NORM) - (LOGICVC_COEFF_B_V * c3) -
+ LOGICVC_COEFF_B) / LOGICVC_RGB_NORM;
+
+ *pixel = (0xFF << 24) | (r << 16) | (g << 8) | b;
+ }
+}
+
+static int xylonfb_layer_color_rgb(struct xylonfb_layer_data *ld,
+ struct xylonfb_layer_color *layer_color,
+ unsigned int reg_offset, bool set)
+{
+ struct xylonfb_data *data = ld->data;
+ struct xylonfb_layer_fix_data *fd = ld->fd;
+ void __iomem *base;
+ u32 r = 0, g = 0, b = 0;
+ u32 raw_rgb, y, u, v;
+ int bpp, transparency;
+
+ if (reg_offset = LOGICVC_LAYER_TRANSP_COLOR_ROFF) {
+ base = ld->base;
+ bpp = fd->bpp;
+ transparency = fd->transparency;
+ } else /* if (reg_offset = LOGICVC_BACKGROUND_COLOR_ROFF) */ {
+ base = data->dev_base;
+ bpp = data->bg_layer_bpp;
+ transparency = -1;
+ }
+
+ if (set) {
+ if (layer_color->use_raw) {
+ raw_rgb = layer_color->raw_rgb;
+ } else if (data->flags & XYLONFB_FLAGS_BACKGROUND_LAYER_YUV) {
+ r = layer_color->r;
+ g = layer_color->g;
+ b = layer_color->b;
+ xylonfb_rgb_yuv(r, g, b, &raw_rgb, ld, true);
+ } else {
+ r = layer_color->r;
+ g = layer_color->g;
+ b = layer_color->b;
+check_bpp_set:
+ switch (bpp) {
+ case 8:
+ switch (transparency) {
+ case LOGICVC_ALPHA_CLUT_16BPP:
+ bpp = 16;
+ goto check_bpp_set;
+ case LOGICVC_ALPHA_CLUT_32BPP:
+ bpp = 32;
+ goto check_bpp_set;
+ default:
+ raw_rgb = (r & 0xE0) |
+ ((g & 0xE0) >> 3) |
+ ((b & 0xC0) >> 6);
+ break;
+ }
+ break;
+ case 16:
+ raw_rgb = ((r & 0xF8) << 8) |
+ ((g & 0xFC) << 3) |
+ ((b & 0xF8) >> 3);
+ break;
+ case 32:
+ raw_rgb = (r << 16) | (g << 8) | b;
+ break;
+ default:
+ raw_rgb = 0;
+ }
+ }
+ data->reg_access.set_reg_val(raw_rgb, base, reg_offset, ld);
+ } else {
+ raw_rgb = data->reg_access.get_reg_val(base, reg_offset, ld);
+check_bpp_get:
+ if (data->flags & XYLONFB_FLAGS_BACKGROUND_LAYER_YUV) {
+ y = (raw_rgb >> 16) & 0xFF;
+ u = (raw_rgb >> 8) & 0xFF;
+ v = raw_rgb & 0xFF;
+ xylonfb_rgb_yuv(y, u, v, &raw_rgb, ld, false);
+ } else {
+ switch (bpp) {
+ case 8:
+ switch (transparency) {
+ case LOGICVC_ALPHA_CLUT_16BPP:
+ bpp = 16;
+ goto check_bpp_get;
+ case LOGICVC_ALPHA_CLUT_32BPP:
+ bpp = 32;
+ goto check_bpp_get;
+ default:
+ r = raw_rgb >> 5;
+ r = (((r << 3) | r) << 2) | (r >> 1);
+ g = (raw_rgb >> 2) & 0x07;
+ g = (((g << 3) | g) << 2) | (g >> 1);
+ b = raw_rgb & 0x03;
+ b = (b << 6) | (b << 4) | (b << 2) | b;
+ break;
+ }
+ break;
+ case 16:
+ r = raw_rgb >> 11;
+ r = (r << 3) | (r >> 2);
+ g = (raw_rgb >> 5) & 0x3F;
+ g = (g << 2) | (g >> 4);
+ b = raw_rgb & 0x1F;
+ b = (b << 3) | (b >> 2);
+ break;
+ case 32:
+ r = raw_rgb >> 16;
+ g = (raw_rgb >> 8) & 0xFF;
+ b = raw_rgb & 0xFF;
+ break;
+ default:
+ raw_rgb = r = g = b = 0;
+ }
+ }
+ layer_color->raw_rgb = raw_rgb;
+ layer_color->r = (u8)r;
+ layer_color->g = (u8)g;
+ layer_color->b = (u8)b;
+ }
+
+ return 0;
+}
+
+static int xylonfb_layer_geometry(struct fb_info *fbi,
+ struct xylonfb_layer_geometry *layer_geometry,
+ bool set)
+{
+ struct xylonfb_layer_data *ld = fbi->par;
+ struct xylonfb_data *data = ld->data;
+ struct xylonfb_layer_fix_data *fd = ld->fd;
+ u32 x, y, width, height, xoff, yoff, xres, yres;
+
+ xres = fbi->var.xres;
+ yres = fbi->var.yres;
+
+ if (set) {
+ x = layer_geometry->x;
+ y = layer_geometry->y;
+ width = layer_geometry->width;
+ height = layer_geometry->height;
+
+ if ((x > xres) || (y > yres))
+ return -EINVAL;
+
+ if ((width = 0) || (height = 0))
+ return -EINVAL;
+
+ if ((x + width) > xres) {
+ width = xres - x;
+ layer_geometry->width = width;
+ }
+ if ((y + height) > yres) {
+ height = yres - y;
+ layer_geometry->height = height;
+ }
+ /* YUV 4:2:2 layer type can only have even layer width */
+ if ((width > 2) && (fd->type = LOGICVC_LAYER_YUV) &&
+ (fd->bpp = 16))
+ width &= ~((unsigned long) + 1);
+
+ /*
+ * logiCVC 3.x registers write sequence:
+ * offset, size, position with implicit last write to
+ * LOGICVC_LAYER_VPOS_ROFF
+ * logiCVC 4.x registers write sequence:
+ * size, position with implicit last write to
+ * LOGICVC_LAYER_ADDR_ROFF
+ */
+ if (!(data->flags & XYLONFB_FLAGS_DYNAMIC_LAYER_ADDRESS)) {
+ data->reg_access.set_reg_val(layer_geometry->x_offset,
+ ld->base,
+ LOGICVC_LAYER_HOFF_ROFF,
+ ld);
+ data->reg_access.set_reg_val(layer_geometry->y_offset,
+ ld->base,
+ LOGICVC_LAYER_VOFF_ROFF,
+ ld);
+ }
+ data->reg_access.set_reg_val((width - 1), ld->base,
+ LOGICVC_LAYER_HSIZE_ROFF,
+ ld);
+ data->reg_access.set_reg_val((height - 1), ld->base,
+ LOGICVC_LAYER_VSIZE_ROFF,
+ ld);
+ data->reg_access.set_reg_val((xres - (x + 1)), ld->base,
+ LOGICVC_LAYER_HPOS_ROFF,
+ ld);
+ data->reg_access.set_reg_val((yres - (y + 1)), ld->base,
+ LOGICVC_LAYER_VPOS_ROFF,
+ ld);
+ if (data->flags & XYLONFB_FLAGS_DYNAMIC_LAYER_ADDRESS) {
+ xoff = layer_geometry->x_offset * (ld->fd->bpp / 8);
+ yoff = layer_geometry->y_offset * ld->fd->width *
+ (ld->fd->bpp / 8);
+
+ ld->fb_pbase_active = ld->fb_pbase + xoff + yoff;
+
+ data->reg_access.set_reg_val(ld->fb_pbase_active,
+ ld->base,
+ LOGICVC_LAYER_ADDR_ROFF,
+ ld);
+ }
+ } else {
+ x = data->reg_access.get_reg_val(ld->base,
+ LOGICVC_LAYER_HPOS_ROFF,
+ ld);
+ layer_geometry->x = xres - (x + 1);
+ y = data->reg_access.get_reg_val(ld->base,
+ LOGICVC_LAYER_VPOS_ROFF,
+ ld);
+ layer_geometry->y = yres - (y + 1);
+ layer_geometry->width + data->reg_access.get_reg_val(ld->base,
+ LOGICVC_LAYER_HSIZE_ROFF,
+ ld);
+ layer_geometry->width += 1;
+ layer_geometry->height + data->reg_access.get_reg_val(ld->base,
+ LOGICVC_LAYER_VSIZE_ROFF,
+ ld);
+ layer_geometry->height += 1;
+ }
+
+ return 0;
+}
+
+static int xylonfb_layer_reg_access(struct xylonfb_layer_data *ld,
+ struct xylonfb_hw_access *hw_access,
+ bool set)
+{
+ struct xylonfb_data *data = ld->data;
+ struct xylonfb_layer_fix_data *fd = ld->fd;
+ u32 offset;
+ u32 rel_offset;
+
+ if ((hw_access->offset < LOGICVC_LAYER_BASE_OFFSET) ||
+ (hw_access->offset > LOGICVC_LAYER_BASE_END))
+ return -EPERM;
+
+ if (data->flags & XYLONFB_FLAGS_READABLE_REGS) {
+ offset = hw_access->offset;
+ if (set)
+ data->reg_access.set_reg_val(hw_access->value,
+ data->dev_base,
+ offset,
+ ld);
+ else
+ hw_access->value + data->reg_access.get_reg_val(data->dev_base,
+ offset,
+ ld);
+ return 0;
+ }
+
+ rel_offset = hw_access->offset - (fd->id * 0x80) -
+ LOGICVC_LAYER_BASE_OFFSET;
+
+ if (rel_offset > LOGICVC_LAYER_BASE_END)
+ return -EINVAL;
+
+ if (set)
+ data->reg_access.set_reg_val(hw_access->value, ld->base,
+ rel_offset, ld);
+ else
+ hw_access->value = data->reg_access.get_reg_val(ld->base,
+ rel_offset, ld);
+
+ return 0;
+}
+
+int xylonfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg)
+{
+ struct xylonfb_layer_data *ld = fbi->par;
+ struct xylonfb_data *data = ld->data;
+ union {
+ struct fb_vblank vblank;
+ struct xylonfb_hw_access hw_access;
+ struct xylonfb_layer_buffer layer_buff;
+ struct xylonfb_layer_color layer_color;
+ struct xylonfb_layer_geometry layer_geometry;
+ struct xylonfb_layer_transparency layer_transp;
+ } ioctl;
+ void __user *argp = (void __user *)arg;
+ unsigned long val;
+ u32 var32;
+ int ret = 0;
+ bool flag;
+
+ switch (cmd) {
+ case FBIOGET_VBLANK:
+ if (copy_from_user(&ioctl.vblank, argp, sizeof(ioctl.vblank)))
+ return -EFAULT;
+
+ ret = xylonfb_get_vblank(&ioctl.vblank, fbi);
+ if (!ret &&
+ copy_to_user(argp, &ioctl.vblank, sizeof(ioctl.vblank)))
+ ret = -EFAULT;
+ break;
+
+ case FBIO_WAITFORVSYNC:
+ if (get_user(var32, (u32 __user *)arg))
+ return -EFAULT;
+
+ ret = xylonfb_vsync_wait(var32, fbi);
+ break;
+
+ case XYLONFB_VSYNC_CTRL:
+ if (get_user(flag, (u8 __user *)arg))
+ return -EFAULT;
+
+ xylonfb_vsync_ctrl(fbi, flag);
+ break;
+
+ case XYLONFB_LAYER_IDX:
+ var32 = ld->fd->id;
+ put_user(var32, (u32 __user *)arg);
+ break;
+
+ case XYLONFB_LAYER_ALPHA:
+ if (copy_from_user(&ioctl.layer_transp, argp,
+ sizeof(ioctl.layer_transp)))
+ return -EFAULT;
+
+ mutex_lock(&ld->mutex);
+ ret = xylonfb_layer_alpha(ld, &ioctl.layer_transp.alpha,
+ ioctl.layer_transp.set);
+ if (!ret && !ioctl.layer_transp.set)
+ if (copy_to_user(argp, &ioctl.layer_transp,
+ sizeof(ioctl.layer_transp)))
+ ret = -EFAULT;
+ mutex_unlock(&ld->mutex);
+ break;
+
+ case XYLONFB_LAYER_COLOR_TRANSP_CTRL:
+ if (get_user(flag, (u8 __user *)arg))
+ return -EFAULT;
+
+ mutex_lock(&ld->mutex);
+ var32 = data->reg_access.get_reg_val(ld->base,
+ LOGICVC_LAYER_CTRL_ROFF,
+ ld);
+ if (flag)
+ var32 |= LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_DISABLE;
+ else
+ var32 &= ~LOGICVC_LAYER_CTRL_COLOR_TRANSPARENCY_DISABLE;
+ data->reg_access.set_reg_val(var32, ld->base,
+ LOGICVC_LAYER_CTRL_ROFF,
+ ld);
+ mutex_unlock(&ld->mutex);
+ break;
+
+ case XYLONFB_LAYER_COLOR_TRANSP:
+ if (copy_from_user(&ioctl.layer_color, argp,
+ sizeof(ioctl.layer_color)))
+ return -EFAULT;
+
+ mutex_lock(&ld->mutex);
+ ret = xylonfb_layer_color_rgb(ld, &ioctl.layer_color,
+ LOGICVC_LAYER_TRANSP_COLOR_ROFF,
+ ioctl.layer_color.set);
+ if (!ret && !ioctl.layer_color.set)
+ if (copy_to_user(argp, &ioctl.layer_color,
+ sizeof(ioctl.layer_color)))
+ ret = -EFAULT;
+ mutex_unlock(&ld->mutex);
+ break;
+
+ case XYLONFB_LAYER_GEOMETRY:
+ if (!(data->flags & XYLONFB_FLAGS_SIZE_POSITION))
+ return -EINVAL;
+
+ if (copy_from_user(&ioctl.layer_geometry, argp,
+ sizeof(ioctl.layer_geometry)))
+ return -EFAULT;
+
+ mutex_lock(&ld->mutex);
+ ret = xylonfb_layer_geometry(fbi, &ioctl.layer_geometry,
+ ioctl.layer_geometry.set);
+ if (!ret && !ioctl.layer_geometry.set)
+ if (copy_to_user(argp, &ioctl.layer_geometry,
+ sizeof(ioctl.layer_geometry)))
+ ret = -EFAULT;
+ mutex_unlock(&ld->mutex);
+ break;
+
+ case XYLONFB_LAYER_BUFFER:
+ if (data->major >= 4)
+ return -EPERM;
+
+ if (copy_from_user(&ioctl.layer_buff, argp,
+ sizeof(ioctl.layer_buff)))
+ return -EFAULT;
+
+ mutex_lock(&ld->mutex);
+ ret = xylonfb_layer_buff(fbi, &ioctl.layer_buff,
+ ioctl.layer_buff.set);
+ if (!ret && !ioctl.layer_buff.set)
+ if (copy_to_user(argp, &ioctl.layer_buff,
+ sizeof(ioctl.layer_buff)))
+ ret = -EFAULT;
+ mutex_unlock(&ld->mutex);
+ break;
+
+ case XYLONFB_LAYER_BUFFER_OFFSET:
+ if (data->major < 4) {
+ var32 = readl(ld->data->dev_base +
+ LOGICVC_VBUFF_SELECT_ROFF);
+ var32 >>= (ld->fd->id << 1);
+ var32 &= 0x03;
+ val = ld->fd->buffer_offset;
+ val *= var32;
+ } else {
+ val = ld->fd->buffer_offset;
+ }
+ put_user(val, (unsigned long __user *)arg);
+ break;
+
+ case XYLONFB_BACKGROUND_COLOR:
+ if (data->bg_layer_bpp = 0)
+ return -EPERM;
+
+ if (copy_from_user(&ioctl.layer_color, argp,
+ sizeof(ioctl.layer_color)))
+ return -EFAULT;
+
+ mutex_lock(&ld->mutex);
+ ret = xylonfb_layer_color_rgb(ld, &ioctl.layer_color,
+ LOGICVC_BACKGROUND_COLOR_ROFF,
+ ioctl.layer_color.set);
+ if (!ret && !ioctl.layer_color.set)
+ if (copy_to_user(argp, &ioctl.layer_color,
+ sizeof(ioctl.layer_color)))
+ ret = -EFAULT;
+ mutex_unlock(&ld->mutex);
+ break;
+
+ case XYLONFB_LAYER_EXT_BUFF_SWITCH:
+ if (get_user(flag, (u8 __user *)arg))
+ return -EFAULT;
+
+ mutex_lock(&ld->mutex);
+ var32 = data->reg_access.get_reg_val(ld->base,
+ LOGICVC_LAYER_CTRL_ROFF,
+ ld);
+ if (flag)
+ var32 |= LOGICVC_LAYER_CTRL_EXTERNAL_BUFFER_SWITCH;
+ else
+ var32 &= ~LOGICVC_LAYER_CTRL_EXTERNAL_BUFFER_SWITCH;
+ data->reg_access.set_reg_val(var32, ld->base,
+ LOGICVC_LAYER_CTRL_ROFF,
+ ld);
+ mutex_unlock(&ld->mutex);
+ break;
+
+ case XYLONFB_HW_ACCESS:
+ if (copy_from_user(&ioctl.hw_access, argp,
+ sizeof(ioctl.hw_access)))
+ return -EFAULT;
+
+ ret = xylonfb_layer_reg_access(ld, &ioctl.hw_access,
+ ioctl.hw_access.set);
+ if (!ret && !ioctl.hw_access.set)
+ if (copy_to_user(argp, &ioctl.hw_access,
+ sizeof(ioctl.hw_access)))
+ ret = -EFAULT;
+ break;
+
+ case XYLONFB_IP_CORE_VERSION:
+ var32 = (data->major << 16) | (data->minor << 8) | data->patch;
+ if (copy_to_user(argp, &var32, sizeof(u32)))
+ ret = -EFAULT;
+ break;
+
+ default:
+ dev_err(&data->pdev->dev, "unknown ioctl");
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
--
1.9.1
^ permalink raw reply related
* [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, ®fb[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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox