Skip to content

Instantly share code, notes, and snippets.

@eyip002
Created July 9, 2022 19:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eyip002/82ce41ebe88273103b70780b4e8a5614 to your computer and use it in GitHub Desktop.
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
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