Created
July 9, 2022 19:23
-
-
Save eyip002/82ce41ebe88273103b70780b4e8a5614 to your computer and use it in GitHub Desktop.
Altera Video Image Processing (VIP) Frame Reader: Patching back into linux-socfpga v5.15.30
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Documentation/devicetree/bindings/video/altvipfb.txt b/Documentation/devicetree/bindings/video/altvipfb.txt | |
new file mode 100644 | |
index 000000000..e646f24a0 | |
--- /dev/null | |
+++ b/Documentation/devicetree/bindings/video/altvipfb.txt | |
@@ -0,0 +1,22 @@ | |
+Altera Video and Image Processing (VIP) Frame Reader bindings | |
+ | |
+Required properties: | |
+- compatible: "altr,vip-frame-reader-9.1" or "altr,vip-frame-reader-1.0" | |
+- reg: Physical base address and length of the framebuffer controller's | |
+ registers. | |
+- max-width: The width of the framebuffer in pixels. | |
+- max-height: The height of the framebuffer in pixels. | |
+- bits-per-color: only "8" is currently supported | |
+- mem-word-width = the bus width of the avalon master port on the frame reader | |
+ | |
+Example: | |
+ | |
+alt_vip_vfr_0: vip@0xff260000 { | |
+ compatible = "altr,vip-frame-reader-1.0"; | |
+ reg = <0xff260000 0x00000080>; | |
+ max-width = <1024>; | |
+ max-height = <768>; | |
+ bits-per-color = <8>; | |
+ mem-word-width = <128>; | |
+}; | |
+ | |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig | |
index 427a993c7..65f92d51d 100644 | |
--- a/drivers/video/Kconfig | |
+++ b/drivers/video/Kconfig | |
@@ -35,6 +35,16 @@ config VIDEOMODE_HELPERS | |
config HDMI | |
bool | |
+config FB_ALTERA_VIP | |
+ tristate "Altera VIP Frame Reader framebuffer support" | |
+ depends on FB | |
+ select FB_CFB_FILLRECT | |
+ select FB_CFB_COPYAREA | |
+ select FB_CFB_IMAGEBLIT | |
+ help | |
+ This driver supports the Altera Video and Image Processing(VIP) | |
+ Frame Reader | |
+ | |
endif # HAS_IOMEM | |
if VT | |
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig | |
index b0603ba6d..431cad887 100644 | |
--- a/drivers/video/fbdev/Kconfig | |
+++ b/drivers/video/fbdev/Kconfig | |
@@ -219,6 +219,16 @@ config FB_TILEBLITTING | |
comment "Frame buffer hardware drivers" | |
depends on FB | |
+config FB_ALTERA_VIP | |
+ tristate "Altera VIP Frame Reader framebuffer support" | |
+ depends on FB | |
+ select FB_CFB_FILLRECT | |
+ select FB_CFB_COPYAREA | |
+ select FB_CFB_IMAGEBLIT | |
+ help | |
+ This driver supports the Altera Video and Image Processing (VIP) | |
+ Frame Reader | |
+ | |
config FB_ALTERA_VIP_FB2 | |
tristate "Altera VIP Frame Buffer II framebuffer support" | |
depends on FB | |
diff --git a/drivers/video/fbdev/Makefile b/drivers/video/fbdev/Makefile | |
index cae7c6db0..60763c655 100644 | |
--- a/drivers/video/fbdev/Makefile | |
+++ b/drivers/video/fbdev/Makefile | |
@@ -11,6 +11,7 @@ obj-$(CONFIG_FB_MACMODES) += macmodes.o | |
obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o | |
# Hardware specific drivers go first | |
+obj-$(CONFIG_FB_ALTERA_VIP) += altvipfb.o | |
obj-$(CONFIG_FB_ALTERA_VIP_FB2) += altvipfb2.o | |
obj-$(CONFIG_FB_ALTERA_VIP_FB2_PLAT) += altvipfb2_drv.o | |
altvipfb2_drv-objs := altvipfb2-plat.o altvipfb2.o | |
diff --git a/drivers/video/fbdev/altvipfb.c b/drivers/video/fbdev/altvipfb.c | |
new file mode 100644 | |
index 000000000..ef29d3e70 | |
--- /dev/null | |
+++ b/drivers/video/fbdev/altvipfb.c | |
@@ -0,0 +1,295 @@ | |
+/* | |
+ * altvipfb.c -- Altera Video and Image Processing (VIP) Frame Reader driver | |
+ * | |
+ * This is based on a driver made by Thomas Chou <thomas@wytron.com.tw> and | |
+ * Walter Goossens <waltergoossens@home.nl> This driver supports the Altera VIP | |
+ * Frame Reader component. More info on the hardware can be found in | |
+ * the Altera Video and Image Processing Suite User Guide at this address | |
+ * http://www.altera.com/literature/ug/ug_vip.pdf. | |
+ * | |
+ * This program is free software; you can redistribute it and/or modify it | |
+ * under the terms and conditions of the GNU General Public License, | |
+ * version 2, as published by the Free Software Foundation. | |
+ * | |
+ * This program is distributed in the hope 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/dma-mapping.h> | |
+#include <linux/fb.h> | |
+#include <linux/init.h> | |
+#include <linux/kernel.h> | |
+#include <linux/module.h> | |
+#include <linux/platform_device.h> | |
+ | |
+#define PALETTE_SIZE 256 | |
+#define DRIVER_NAME "altvipfb" | |
+ | |
+/* control registers */ | |
+#define ALTVIPFB_CONTROL 0 | |
+#define ALTVIPFB_FRAME_SELECT 12 | |
+#define ALTVIPFB_FRAME0_BASE_ADDRESS 16 | |
+#define ALTVIPFB_FRAME0_NUM_WORDS 20 | |
+#define ALTVIPFB_FRAME0_SAMPLES 24 | |
+#define ALTVIPFB_FRAME0_WIDTH 32 | |
+#define ALTVIPFB_FRAME0_HEIGHT 36 | |
+#define ALTVIPFB_FRAME0_INTERLACED 40 | |
+ | |
+struct altvipfb_type; | |
+ | |
+struct altvipfb_dev { | |
+ struct platform_device *pdev; | |
+ struct fb_info info; | |
+ struct resource *reg_res; | |
+ void __iomem *base; | |
+ int mem_word_width; | |
+ u32 pseudo_palette[PALETTE_SIZE]; | |
+}; | |
+ | |
+static int altvipfb_setcolreg(unsigned regno, unsigned red, unsigned green, | |
+ unsigned blue, unsigned transp, struct fb_info *info) | |
+{ | |
+ /* | |
+ * Set a single color register. The values supplied have a 32 bit | |
+ * magnitude. | |
+ * Return != 0 for invalid regno. | |
+ */ | |
+ | |
+ if (regno > 255) | |
+ return 1; | |
+ | |
+ red >>= 8; | |
+ green >>= 8; | |
+ blue >>= 8; | |
+ | |
+ if (regno < 255) { | |
+ ((u32 *)info->pseudo_palette)[regno] = | |
+ ((red & 255) << 16) | ((green & 255) << 8) | (blue & 255); | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+static struct fb_ops altvipfb_ops = { | |
+ .owner = THIS_MODULE, | |
+ .fb_fillrect = cfb_fillrect, | |
+ .fb_copyarea = cfb_copyarea, | |
+ .fb_imageblit = cfb_imageblit, | |
+ .fb_setcolreg = altvipfb_setcolreg, | |
+}; | |
+ | |
+static void altvipfb_start_hw(struct altvipfb_dev *fbdev) | |
+{ | |
+ writel(fbdev->info.fix.smem_start, fbdev->base + | |
+ ALTVIPFB_FRAME0_BASE_ADDRESS); | |
+ writel(fbdev->info.var.xres * fbdev->info.var.yres / | |
+ (fbdev->mem_word_width/32), | |
+ fbdev->base + ALTVIPFB_FRAME0_NUM_WORDS); | |
+ writel(fbdev->info.var.xres * fbdev->info.var.yres, | |
+ fbdev->base + ALTVIPFB_FRAME0_SAMPLES); | |
+ writel(fbdev->info.var.xres, fbdev->base + ALTVIPFB_FRAME0_WIDTH); | |
+ writel(fbdev->info.var.yres, fbdev->base + ALTVIPFB_FRAME0_HEIGHT); | |
+ writel(3, fbdev->base + ALTVIPFB_FRAME0_INTERLACED); | |
+ writel(0, fbdev->base + ALTVIPFB_FRAME_SELECT); | |
+ | |
+ /* Finally set the control register to 1 to start streaming */ | |
+ writel(1, fbdev->base + ALTVIPFB_CONTROL); | |
+} | |
+ | |
+static void altvipfb_disable_hw(struct altvipfb_dev *fbdev) | |
+{ | |
+ /* set the control register to 0 to stop streaming */ | |
+ writel(0, fbdev->base + ALTVIPFB_CONTROL); | |
+} | |
+ | |
+static int altvipfb_of_setup(struct altvipfb_dev *fbdev) | |
+{ | |
+ struct device_node *np = fbdev->pdev->dev.of_node; | |
+ int ret; | |
+ u32 bits_per_color; | |
+ | |
+ ret = of_property_read_u32(np, "max-width", &fbdev->info.var.xres); | |
+ if (ret) { | |
+ dev_err(&fbdev->pdev->dev, | |
+ "Missing required parameter 'max-width'"); | |
+ return ret; | |
+ } | |
+ fbdev->info.var.xres_virtual = fbdev->info.var.xres, | |
+ | |
+ ret = of_property_read_u32(np, "max-height", &fbdev->info.var.yres); | |
+ if (ret) { | |
+ dev_err(&fbdev->pdev->dev, | |
+ "Missing required parameter 'max-height'"); | |
+ return ret; | |
+ } | |
+ fbdev->info.var.yres_virtual = fbdev->info.var.yres; | |
+ | |
+ ret = of_property_read_u32(np, "bits-per-color", &bits_per_color); | |
+ if (ret) { | |
+ dev_err(&fbdev->pdev->dev, | |
+ "Missing required parameter 'bits-per-color'"); | |
+ return ret; | |
+ } | |
+ if (bits_per_color != 8) { | |
+ dev_err(&fbdev->pdev->dev, | |
+ "bits-per-color is set to %i. Curently only 8 is supported.", | |
+ bits_per_color); | |
+ return -ENODEV; | |
+ } | |
+ fbdev->info.var.bits_per_pixel = 32; | |
+ | |
+ ret = of_property_read_u32(np, "mem-word-width", | |
+ &fbdev->mem_word_width); | |
+ if (ret) { | |
+ dev_err(&fbdev->pdev->dev, | |
+ "Missing required parameter 'mem-word-width'"); | |
+ return ret; | |
+ } | |
+ if (!(fbdev->mem_word_width >= 32 && fbdev->mem_word_width % 32 == 0)) { | |
+ dev_err(&fbdev->pdev->dev, | |
+ "mem-word-width is set to %i. must be >= 32 and multiple of 32.", | |
+ fbdev->mem_word_width); | |
+ return -ENODEV; | |
+ } | |
+ | |
+ fbdev->info.fix.line_length = (fbdev->info.var.xres * | |
+ (fbdev->info.var.bits_per_pixel >> 3)); | |
+ fbdev->info.fix.smem_len = | |
+ fbdev->info.fix.line_length * fbdev->info.var.yres; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static void altvipfb_setup_fb_info(struct altvipfb_dev *fbdev) | |
+{ | |
+ struct fb_info *info = &fbdev->info; | |
+ | |
+ strcpy(info->fix.id, DRIVER_NAME); | |
+ info->fix.type = FB_TYPE_PACKED_PIXELS; | |
+ info->fix.visual = FB_VISUAL_TRUECOLOR; | |
+ info->fix.accel = FB_ACCEL_NONE; | |
+ | |
+ info->fbops = &altvipfb_ops; | |
+ info->var.activate = FB_ACTIVATE_NOW; | |
+ info->var.height = -1; | |
+ info->var.width = -1; | |
+ info->var.vmode = FB_VMODE_NONINTERLACED; | |
+ | |
+ /* settings for 32bit pixels */ | |
+ info->var.red.offset = 16; | |
+ info->var.red.length = 8; | |
+ info->var.red.msb_right = 0; | |
+ info->var.green.offset = 8; | |
+ info->var.green.length = 8; | |
+ info->var.green.msb_right = 0; | |
+ info->var.blue.offset = 0; | |
+ info->var.blue.length = 8; | |
+ info->var.blue.msb_right = 0; | |
+ info->pseudo_palette = fbdev->pseudo_palette; | |
+ | |
+ info->flags = FBINFO_FLAG_DEFAULT; | |
+} | |
+ | |
+static int altvipfb_probe(struct platform_device *pdev) | |
+{ | |
+ int retval; | |
+ void *fbmem_virt; | |
+ struct altvipfb_dev *fbdev; | |
+ | |
+ fbdev = devm_kzalloc(&pdev->dev, sizeof(*fbdev), GFP_KERNEL); | |
+ if (!fbdev) { | |
+ dev_err(&pdev->dev, | |
+ "altvipfb: unable to allocate %d Bytes fb memory\n", | |
+ sizeof(*fbdev)); | |
+ return -ENOMEM; | |
+ } | |
+ | |
+ fbdev->pdev = pdev; | |
+ fbdev->reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
+ if (!fbdev->reg_res) | |
+ return -ENODEV; | |
+ | |
+ fbdev->base = devm_ioremap_resource(&pdev->dev, fbdev->reg_res); | |
+ if (IS_ERR(fbdev->base)) { | |
+ dev_err(&pdev->dev, "devm_ioremap_resource failed\n"); | |
+ retval = PTR_ERR(fbdev->base); | |
+ return -ENOMEM; | |
+ } | |
+ | |
+ altvipfb_of_setup(fbdev); | |
+ | |
+ platform_set_drvdata(pdev, fbdev); | |
+ | |
+ fbmem_virt = dma_alloc_coherent(&pdev->dev, | |
+ fbdev->info.fix.smem_len, | |
+ (void *)&(fbdev->info.fix.smem_start), | |
+ GFP_KERNEL); | |
+ if (!fbmem_virt) { | |
+ dev_err(&pdev->dev, | |
+ "altvipfb: unable to allocate %d Bytes fb memory\n", | |
+ fbdev->info.fix.smem_len); | |
+ return -ENOMEM; | |
+ } | |
+ | |
+ fbdev->info.screen_base = fbmem_virt; | |
+ | |
+ retval = fb_alloc_cmap(&fbdev->info.cmap, PALETTE_SIZE, 0); | |
+ if (retval < 0) | |
+ goto err_dma_free; | |
+ | |
+ altvipfb_setup_fb_info(fbdev); | |
+ | |
+ altvipfb_start_hw(fbdev); | |
+ | |
+ dev_info(&pdev->dev, "fb%d: %s frame buffer device at 0x%x+0x%x\n", | |
+ fbdev->info.node, fbdev->info.fix.id, | |
+ (unsigned)fbdev->info.fix.smem_start, | |
+ fbdev->info.fix.smem_len); | |
+ | |
+ return register_framebuffer(&fbdev->info); | |
+ | |
+err_dma_free: | |
+ fb_dealloc_cmap(&fbdev->info.cmap); | |
+ dma_free_coherent(&pdev->dev, fbdev->info.fix.smem_len, fbmem_virt, | |
+ fbdev->info.fix.smem_start); | |
+ return retval; | |
+} | |
+ | |
+static int altvipfb_remove(struct platform_device *dev) | |
+{ | |
+ struct altvipfb_dev *fbdev = platform_get_drvdata(dev); | |
+ | |
+ if (fbdev) { | |
+ altvipfb_disable_hw(fbdev); | |
+ dma_free_coherent(&fbdev->pdev->dev, fbdev->info.fix.smem_len, | |
+ fbdev->info.screen_base, | |
+ fbdev->info.fix.smem_start); | |
+ unregister_framebuffer(&fbdev->info); | |
+ } | |
+ return 0; | |
+} | |
+ | |
+static struct of_device_id altvipfb_match[] = { | |
+ { .compatible = "altr,vip-frame-reader-1.0" }, | |
+ { .compatible = "altr,vip-frame-reader-9.1" }, | |
+ {}, | |
+}; | |
+MODULE_DEVICE_TABLE(of, altvipfb_match); | |
+ | |
+static struct platform_driver altvipfb_driver = { | |
+ .probe = altvipfb_probe, | |
+ .remove = altvipfb_remove, | |
+ .driver = { | |
+ .owner = THIS_MODULE, | |
+ .name = DRIVER_NAME, | |
+ .of_match_table = altvipfb_match, | |
+ }, | |
+}; | |
+module_platform_driver(altvipfb_driver); | |
+ | |
+MODULE_AUTHOR("Chris Rauer <crauer@altera.com> and modified by Eugene Yip <kinchee87@hotmail.com>"); | |
+MODULE_DESCRIPTION("Altera VIP Frame Reader framebuffer driver"); | |
+MODULE_LICENSE("GPL v2"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment