summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev/starfive/starfive_vpp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/fbdev/starfive/starfive_vpp.c')
-rw-r--r--drivers/video/fbdev/starfive/starfive_vpp.c588
1 files changed, 588 insertions, 0 deletions
diff --git a/drivers/video/fbdev/starfive/starfive_vpp.c b/drivers/video/fbdev/starfive/starfive_vpp.c
new file mode 100644
index 000000000000..3a7b76af3115
--- /dev/null
+++ b/drivers/video/fbdev/starfive/starfive_vpp.c
@@ -0,0 +1,588 @@
+/* driver/video/starfive/starfive_vpp.c
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License version 2 as
+** published by the Free Software Foundation.
+**
+** Copyright (C) 2020 StarFive, Inc.
+**
+** PURPOSE: This files contains the driver of VPP.
+**
+** CHANGE HISTORY:
+** Version Date Author Description
+** 0.1.0 2020-10-09 starfive created
+**
+*/
+
+#include <linux/module.h>
+
+#include "starfive_fb.h"
+#include "starfive_vpp.h"
+
+//#define SF_PP_DEBUG 1
+#ifdef SF_PP_DEBUG
+ #define PP_PRT(format, args...) printk(KERN_DEBUG "[pp]: " format, ## args)
+ #define PP_INFO(format, args...) printk(KERN_INFO "[pp]: " format, ## args)
+ #define PP_ERR(format, args...) printk(KERN_ERR "[pp]: " format, ## args)
+#else
+ #define PP_PRT(x...) do{} while(0)
+ #define PP_INFO(x...) do{} while(0)
+ #define PP_ERR(x...) do{} while(0)
+#endif
+
+static u32 sf_fb_sysread32(struct sf_fb_data *sf_dev, u32 reg)
+{
+ return ioread32(sf_dev->base_syscfg + reg);
+}
+
+static void sf_fb_syswrite32(struct sf_fb_data *sf_dev, u32 reg, u32 val)
+{
+ iowrite32(val, sf_dev->base_syscfg + reg);
+}
+
+static u32 sf_fb_vppread32(struct sf_fb_data *sf_dev, int ppNum, u32 reg)
+{
+ void __iomem *base_vpp = 0;
+ switch(ppNum) {
+ case 0 : {base_vpp = sf_dev->base_vpp0; break;}
+ case 1 : {base_vpp = sf_dev->base_vpp1; break;}
+ case 2 : {base_vpp = sf_dev->base_vpp2; break;}
+ default: {PP_ERR("Err:invalid vpp Number!\n"); break;}
+ }
+ return ioread32(base_vpp + reg);
+}
+
+static void sf_fb_vppwrite32(struct sf_fb_data *sf_dev, int ppNum, u32 reg, u32 val)
+{
+ void __iomem *base_vpp = 0;
+ switch(ppNum) {
+ case 0 : {base_vpp = sf_dev->base_vpp0; break;}
+ case 1 : {base_vpp = sf_dev->base_vpp1; break;}
+ case 2 : {base_vpp = sf_dev->base_vpp2; break;}
+ default: {PP_ERR("Err:invalid vpp Number!\n"); break;}
+ }
+ iowrite32(val, base_vpp + reg);
+}
+
+void mapconv_pp0_sel(struct sf_fb_data *sf_dev, int sel)
+{
+ u32 temp;
+ temp = sf_fb_sysread32(sf_dev, SYS_MAP_CONV);
+ temp &= ~(0x1);
+ temp |= (sel & 0x1);
+ sf_fb_syswrite32(sf_dev, SYS_MAP_CONV, temp);
+}
+EXPORT_SYMBOL(mapconv_pp0_sel);
+
+void pp_output_cfg(struct sf_fb_data *sf_dev, int ppNum, int outSel, int progInter, int desformat, int ptMode)
+{
+ int cfg = outSel | progInter << PP_INTERLACE
+ | desformat << PP_DES_FORMAT
+ | ptMode << PP_POINTER_MODE;
+
+ int preCfg = 0xffff8f0 & sf_fb_vppread32(sf_dev, ppNum, PP_CTRL1);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_CTRL1, cfg | preCfg);
+ PP_PRT("PP%d outSel: %d, outFormat: 0x%x, Out Interlace: %d, ptMode: %d\n",
+ ppNum, outSel, desformat, progInter, ptMode);
+}
+
+void pp_srcfmt_cfg(struct sf_fb_data *sf_dev, int ppNum, int srcformat, int yuv420Inter, int yuv422_mode,
+ int yuv420_mode, int argbOrd)
+{
+ int cfg = srcformat << PP_SRC_FORMAT_N | yuv420Inter << PP_420_ITLC
+ | yuv422_mode << PP_SRC_422_YUV_POS
+ | yuv420_mode << PP_SRC_420_YUV_POS
+ | argbOrd << PP_SRC_ARGB_ORDER;
+
+ int preCfg = 0x83ffff0f & sf_fb_vppread32(sf_dev, ppNum, PP_CTRL1);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_CTRL1, cfg | preCfg);
+ PP_PRT("PP%d Src Format: 0x%x, YUV420 Interlace: %d, YUV422: %d, YUV420: %d, ARGB Order: %d\n",
+ ppNum, srcformat,yuv420Inter,yuv422_mode,yuv420_mode, argbOrd);
+}
+
+void pp_r2yscal_bypass(struct sf_fb_data *sf_dev, int ppNum, int r2yByp, int scalByp, int y2rByp)
+{
+ int bypass = (r2yByp | scalByp<<1 | y2rByp<<2) << PP_R2Y_BPS;
+ int preCfg = 0xffff8fff & sf_fb_vppread32(sf_dev, ppNum, PP_CTRL1);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_CTRL1, bypass | preCfg);
+ PP_PRT("PP%d Bypass R2Y: %d, Y2R: %d, MainSacle: %d\n", ppNum, r2yByp, y2rByp, scalByp);
+}
+
+void pp_argb_alpha(struct sf_fb_data *sf_dev, int ppNum, int alpha)
+{
+ int preCfg = 0xff00ffff & sf_fb_vppread32(sf_dev, ppNum, PP_CTRL1);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_CTRL1, alpha << PP_ARGB_ALPHA | preCfg);
+ PP_PRT("PP%d Alpha: 0x%4x\n", ppNum, alpha);
+}
+
+//rgbNum: 1-3
+void pp_r2y_coeff(struct sf_fb_data *sf_dev, int ppNum, int coefNum, int rcoef, int gcoef, int bcoef, int off)
+{
+ int rgcoeff = rcoef | gcoef << PP_COEF_G1;
+ int bcoefoff = bcoef| off << PP_OFFSET_1;
+ u32 addr1 = (coefNum - 1) * 0x8 + PP_R2Y_COEF1;
+ u32 addr2 = (coefNum - 1) * 0x8 + PP_R2Y_COEF2;
+ sf_fb_vppwrite32(sf_dev, ppNum, addr1, rgcoeff);
+ sf_fb_vppwrite32(sf_dev, ppNum, addr2, bcoefoff);
+ PP_PRT("PP%d coefNum: %d, rCoef: 0x%4x, gCoef: 0x%4x, bCoef: 0x%4x, off: 0x%4x\n",
+ ppNum, coefNum, rcoef, gcoef, bcoef, off);
+}
+
+void pp_output_fmt_cfg(struct sf_fb_data *sf_dev, int ppNum, int yuv420Inter, int yuv422_mode)
+{
+ int preCfg = 0xfffffffe & sf_fb_vppread32(sf_dev, ppNum, PP_CTRL2);
+ preCfg = preCfg | yuv420Inter << PP_DES_420_ORDER
+ | yuv422_mode << PP_DES_422_ORDER;
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_CTRL2, preCfg);
+ PP_PRT("PP%d Lock Transfer: %d\n", ppNum, yuv422_mode);
+}
+
+void pp_lockTrans_cfg(struct sf_fb_data *sf_dev, int ppNum, int lockTrans)
+{
+ int preCfg = 0xfffffffe & sf_fb_vppread32(sf_dev, ppNum, PP_CTRL2);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_CTRL2, lockTrans | preCfg);
+ PP_PRT("PP%d Lock Transfer: %d\n", ppNum, lockTrans);
+}
+
+void pp_int_interval_cfg(struct sf_fb_data *sf_dev, int ppNum, int interval)
+{
+ int preCfg = 0xffff00ff & sf_fb_vppread32(sf_dev, ppNum, PP_CTRL2);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_CTRL2, interval << PP_INT_INTERVAL | preCfg);
+ PP_PRT("PP%d Frame Interrupt interval: %d Frames\n", ppNum, interval);
+}
+
+void pp_srcSize_cfg(struct sf_fb_data *sf_dev, int ppNum, int hsize, int vsize)
+{
+ int size = hsize | vsize << PP_SRC_VSIZE;
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_SRC_SIZE, size);
+ PP_PRT("PP%d HSize: %d, VSize: %d\n", ppNum, hsize, vsize);
+}
+
+//0-no drop, 1-1/2, 2-1/4, down to 1/32
+void pp_drop_cfg(struct sf_fb_data *sf_dev, int ppNum, int hdrop, int vdrop)
+{
+ int drop = hdrop | vdrop << PP_DROP_VRATION;
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_DROP_CTRL, drop);
+ PP_PRT("PP%d HDrop: %d, VDrop: %d\n", ppNum, hdrop, vdrop);
+}
+
+
+void pp_desSize_cfg(struct sf_fb_data *sf_dev, int ppNum, int hsize, int vsize)
+{
+ int size = hsize | vsize << PP_DES_VSIZE;
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_DES_SIZE, size);
+ PP_PRT("PP%d HSize: %d, VSize: %d\n", ppNum, hsize, vsize);
+}
+
+void pp_desAddr_cfg(struct sf_fb_data *sf_dev, int ppNum, int yaddr, int uaddr, int vaddr)
+{
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_DES_Y_SA, yaddr);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_DES_U_SA, uaddr);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_DES_V_SA, vaddr);
+ PP_PRT("PP%d des-Addr Y: 0x%8x, U: 0x%8x, V: 0x%8x\n", ppNum, yaddr, uaddr, vaddr);
+}
+
+void pp_desOffset_cfg(struct sf_fb_data *sf_dev, int ppNum, int yoff, int uoff, int voff)
+{
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_DES_Y_OFS, yoff);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_DES_U_OFS, uoff);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_DES_V_OFS, voff);
+ PP_PRT("PP%d des-Offset Y: 0x%4x, U: 0x%4x, V: 0x%4x\n", ppNum, yoff, uoff, voff);
+}
+
+
+void pp_intcfg(struct sf_fb_data *sf_dev, int ppNum, int intMask)
+{
+ int intcfg = ~(0x1<<0);
+
+ if(intMask)
+ intcfg = 0xf;
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_INT_MASK, intcfg);
+}
+EXPORT_SYMBOL(pp_intcfg);
+
+//next source frame Y/RGB start address, ?
+void pp_srcAddr_next(struct sf_fb_data *sf_dev, int ppNum, int ysa, int usa, int vsa)
+{
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_SRC_Y_SA_NXT, ysa);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_SRC_U_SA_NXT, usa);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_SRC_V_SA_NXT, vsa);
+ PP_PRT("PP%d next Y startAddr: 0x%8x, U startAddr: 0x%8x, V startAddr: 0x%8x\n", ppNum, ysa, usa, vsa);
+}
+EXPORT_SYMBOL(pp_srcAddr_next);
+
+void pp_srcOffset_cfg(struct sf_fb_data *sf_dev, int ppNum, int yoff, int uoff, int voff)
+{
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_SRC_Y_OFS, yoff);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_SRC_U_OFS, uoff);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_SRC_V_OFS, voff);
+ PP_PRT("PP%d src-Offset Y: 0x%4x, U: 0x%4x, V: 0x%4x\n", ppNum, yoff, uoff, voff);
+}
+EXPORT_SYMBOL(pp_srcOffset_cfg);
+
+void pp_nxtAddr_load(struct sf_fb_data *sf_dev, int ppNum, int nxtPar, int nxtPos)
+{
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_LOAD_NXT_PAR, nxtPar | nxtPos);
+ PP_PRT("PP%d next addrPointer: %d, %d set Regs\n", ppNum, nxtPar, nxtPos);
+}
+EXPORT_SYMBOL(pp_nxtAddr_load);
+
+void pp_run(struct sf_fb_data *sf_dev, int ppNum, int start)
+{
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_SWITCH, start);
+ //if(start)
+ // PP_PRT("Now start the PP%d\n\n", ppNum);
+}
+EXPORT_SYMBOL(pp_run);
+
+void pp1_enable_intr(struct sf_fb_data *sf_dev)
+{
+ sf_fb_vppwrite32(sf_dev, 1, PP_INT_MASK, 0x0);
+}
+EXPORT_SYMBOL(pp1_enable_intr);
+
+void pp_enable_intr(struct sf_fb_data *sf_dev, int ppNum)
+{
+ u32 cfg = 0xfffe;
+
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_INT_MASK, cfg);
+}
+EXPORT_SYMBOL(pp_enable_intr);
+
+void pp_disable_intr(struct sf_fb_data *sf_dev, int ppNum)
+{
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_INT_MASK, 0xf);
+ sf_fb_vppwrite32(sf_dev, ppNum, PP_INT_CLR, 0xf);
+}
+EXPORT_SYMBOL(pp_disable_intr);
+
+static void pp_srcfmt_set(struct sf_fb_data *sf_dev, int ppNum, struct pp_video_mode *src)
+{
+ switch(src->format)
+ {
+ case COLOR_YUV422_YVYU:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_YUV422, 0x0, COLOR_YUV422_YVYU, 0x0, 0x0);
+ break;
+ case COLOR_YUV422_VYUY:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_YUV422, 0x0, COLOR_YUV422_VYUY, 0x0, 0x0);
+ break;
+ case COLOR_YUV422_YUYV:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_YUV422, 0x0, COLOR_YUV422_YUYV, 0x0, 0x0);
+ break;
+ case COLOR_YUV422_UYVY:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_YUV422, 0x0, COLOR_YUV422_UYVY, 0x0, 0x0);
+ break;
+ case COLOR_YUV420P:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_YUV420P, 0x0, 0, 0x0, 0x0);
+ break;
+ case COLOR_YUV420_NV21:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_YUV420I, 0x1, 0, COLOR_YUV420_NV21-COLOR_YUV420_NV21, 0x0);
+ break;
+ case COLOR_YUV420_NV12:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_YUV420I, 0x1, 0, COLOR_YUV420_NV12-COLOR_YUV420_NV21, 0x0);
+ break;
+ case COLOR_RGB888_ARGB:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_GRB888, 0x0, 0x0, 0x0, COLOR_RGB888_ARGB-COLOR_RGB888_ARGB);//0x0);
+ break;
+ case COLOR_RGB888_ABGR:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_GRB888, 0x0, 0x0, 0x0, COLOR_RGB888_ABGR-COLOR_RGB888_ARGB);//0x1);
+ break;
+ case COLOR_RGB888_RGBA:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_GRB888, 0x0, 0x0, 0x0, COLOR_RGB888_RGBA-COLOR_RGB888_ARGB);//0x2);
+ break;
+ case COLOR_RGB888_BGRA:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_GRB888, 0x0, 0x0, 0x0, COLOR_RGB888_BGRA-COLOR_RGB888_ARGB);//0x3);
+ break;
+ case COLOR_RGB565:
+ pp_srcfmt_cfg(sf_dev, ppNum, PP_SRC_RGB565, 0x0, 0x0, 0x0, 0x0);
+ break;
+ }
+}
+
+static void pp_dstfmt_set(struct sf_fb_data *sf_dev, int ppNum, struct pp_video_mode *dst)
+{
+ unsigned int outsel = 1;
+ if(dst->addr)
+ {
+ outsel = 0;
+ }
+
+ switch(dst->format) {
+ case COLOR_YUV422_YVYU:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_YUV422, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, 0, COLOR_YUV422_UYVY - COLOR_YUV422_YVYU);
+ break;
+ case COLOR_YUV422_VYUY:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_YUV422, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, 0, COLOR_YUV422_UYVY - COLOR_YUV422_VYUY);
+ break;
+ case COLOR_YUV422_YUYV:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_YUV422, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, 0, COLOR_YUV422_UYVY - COLOR_YUV422_YUYV);
+ break;
+ case COLOR_YUV422_UYVY:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_YUV422, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, 0, COLOR_YUV422_UYVY - COLOR_YUV422_YVYU);
+ break;
+ case COLOR_YUV420P:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_YUV420P, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, 0, 0);
+ break;
+ case COLOR_YUV420_NV21:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_YUV420I, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, COLOR_YUV420_NV21 - COLOR_YUV420_NV21, 0);
+ break;
+ case COLOR_YUV420_NV12:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_YUV420I, 0x0);///0x2, 0x0);
+ //pp_output_fmt_cfg(ppNum, COLOR_YUV420_NV12 - COLOR_YUV420_NV21, 0);
+ break;
+ case COLOR_RGB888_ARGB:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_ARGB888, 0x0);
+ //pp_output_fmt_cfg(ppNum, 0, 0);
+ break;
+ case COLOR_RGB888_ABGR:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_ABGR888, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, 0, 0);
+ break;
+ case COLOR_RGB888_RGBA:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_RGBA888, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, 0, 0);
+ break;
+ case COLOR_RGB888_BGRA:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_BGRA888, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, 0, 0);
+ break;
+ case COLOR_RGB565:
+ pp_output_cfg(sf_dev, ppNum, outsel, 0x0, PP_DST_RGB565, 0x0);
+ pp_output_fmt_cfg(sf_dev, ppNum, 0, 0);
+ break;
+ }
+}
+
+
+void pp_format_set(struct sf_fb_data *sf_dev, int ppNum, struct pp_video_mode *src, struct pp_video_mode *dst)
+{
+
+ /* 1:bypass, 0:not bypass */
+ unsigned int scale_byp = 1;
+
+ pp_srcfmt_set(sf_dev, ppNum, src);
+ pp_dstfmt_set(sf_dev, ppNum, dst);
+
+ if((src->height != dst->height) || (src->width != dst->width)) {
+ scale_byp = 0;
+ }
+
+ if((src->format >= COLOR_RGB888_ARGB) && (dst->format <= COLOR_YUV420_NV12)) {
+ /* rgb -> yuv-420 */
+ pp_r2yscal_bypass(sf_dev, ppNum, NOT_BYPASS, scale_byp, BYPASS);
+ pp_r2y_coeff(sf_dev, ppNum, 1, R2Y_COEF_R1, R2Y_COEF_G1, R2Y_COEF_B1, R2Y_OFFSET1);
+ pp_r2y_coeff(sf_dev, ppNum, 2, R2Y_COEF_R2, R2Y_COEF_G2, R2Y_COEF_B2, R2Y_OFFSET2);
+ pp_r2y_coeff(sf_dev, ppNum, 3, R2Y_COEF_R3, R2Y_COEF_G3, R2Y_COEF_B3, R2Y_OFFSET3);
+ } else if ((src->format <= COLOR_YUV420_NV12) && (dst->format >= COLOR_RGB888_ARGB)) {
+ /* yuv-420 -> rgb */
+ pp_r2yscal_bypass(sf_dev, ppNum, BYPASS, scale_byp, NOT_BYPASS);
+ } else if ((src->format <= COLOR_YUV422_YVYU) && (dst->format <= COLOR_YUV420_NV12)) {
+ /* yuv422 -> yuv420 */
+ pp_r2yscal_bypass(sf_dev, ppNum, BYPASS, scale_byp, BYPASS);
+ } else {
+ /* rgb565->argb888 */
+ pp_r2yscal_bypass(sf_dev, ppNum, BYPASS, scale_byp, BYPASS);
+ } //else if((src->format >= COLOR_RGB888_ARGB) && (dst->format >= COLOR_RGB888_ARGB))
+ {
+ /* rgb -> rgb */
+ // pp_r2yscal_bypass(ppNum, BYPASS, scale_byp, BYPASS);
+ }
+ pp_argb_alpha(sf_dev, ppNum, 0xff);
+
+ if(dst->addr) {
+ pp_lockTrans_cfg(sf_dev, ppNum, SYS_BUS_OUTPUT);
+ } else {
+ pp_lockTrans_cfg(sf_dev, ppNum, FIFO_OUTPUT);
+ }
+
+ pp_int_interval_cfg(sf_dev, ppNum, 0x1);
+
+}
+
+void pp_size_set(struct sf_fb_data *sf_dev, int ppNum, struct pp_video_mode *src, struct pp_video_mode *dst)
+{
+ uint32_t srcAddr, dstaddr;
+ unsigned int size, y_rgb_ofst, uofst;
+ unsigned int v_uvofst = 0, next_y_rgb_addr = 0, next_u_addr = 0, next_v_addr = 0;
+ unsigned int i = 0;
+
+ pp_srcSize_cfg(sf_dev, ppNum, src->width - 1, src->height - 1);
+ pp_drop_cfg(sf_dev, ppNum, 0x0, 0x0);///0:no drop
+ pp_desSize_cfg(sf_dev, ppNum, dst->width - 1, dst->height - 1);
+
+ srcAddr = src->addr + (i<<30);///PP_SRC_BASE_ADDR + (i<<30);
+ size = src->width * src->height;
+
+ if(src->format >= COLOR_RGB888_ARGB) {
+ next_y_rgb_addr = srcAddr;
+ next_u_addr = 0;
+ next_v_addr = 0;
+
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+
+ //pp_srcAddr_next(ppNum, srcAddr, 0, 0);
+ //pp_srcOffset_cfg(ppNum, 0x0, 0x0, 0x0);
+
+ } else {
+ //if((src->format == COLOR_YUV420_NV21) || (src->format == COLOR_YUV420_NV12)){
+ if(src->format == COLOR_YUV420_NV21) { //ok
+ next_y_rgb_addr = srcAddr;
+ next_u_addr = srcAddr+size+1;
+ next_v_addr = srcAddr+size;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = size;
+ } else if (src->format == COLOR_YUV420_NV12) {
+ next_y_rgb_addr = srcAddr;
+ next_u_addr = srcAddr+size;
+ next_v_addr = srcAddr+size+1;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = size;
+ } else if (src->format == COLOR_YUV420P) {
+ next_y_rgb_addr = srcAddr;
+ next_u_addr = srcAddr+size;
+ next_v_addr = srcAddr+size*5/4;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else if (src->format == COLOR_YUV422_YVYU) { //ok
+ next_y_rgb_addr = srcAddr;
+ next_u_addr = srcAddr+1;
+ next_v_addr = srcAddr+3;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else if (src->format == COLOR_YUV422_VYUY) { //ok
+ next_y_rgb_addr = srcAddr+1;
+ next_u_addr = srcAddr+2;
+ next_v_addr = srcAddr;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else if(src->format == COLOR_YUV422_YUYV) { //ok
+ next_y_rgb_addr = srcAddr;
+ next_u_addr = srcAddr+1;
+ next_v_addr = srcAddr+2;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else if(src->format == COLOR_YUV422_UYVY) { //ok
+ next_y_rgb_addr = srcAddr+1;
+ next_u_addr = srcAddr;
+ next_v_addr = srcAddr+2;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ }
+ }
+ pp_srcAddr_next(sf_dev, ppNum, next_y_rgb_addr, next_u_addr, next_v_addr);
+ pp_srcOffset_cfg(sf_dev, ppNum, y_rgb_ofst, uofst, v_uvofst);
+ /* source addr not change */
+ pp_nxtAddr_load(sf_dev, ppNum, 0x1, (i & 0x1));
+
+ if(dst->addr) {
+ dstaddr = dst->addr;
+ size = dst->height*dst->width;
+ if(dst->format >= COLOR_RGB888_ARGB) {
+ next_y_rgb_addr = dstaddr;
+ next_u_addr = 0;
+ next_v_addr = 0;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else {
+ if(dst->format == COLOR_YUV420_NV21) {
+ /* yyyyvuvuvu */
+ next_y_rgb_addr = dstaddr;
+ next_u_addr = dstaddr+size;
+ next_v_addr = 0;//dstaddr+size;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else if (dst->format == COLOR_YUV420_NV12){
+ /* yyyyuvuvuv */
+ next_y_rgb_addr = dstaddr;
+ next_u_addr = dstaddr+size;
+ next_v_addr = dstaddr+size+1;
+ y_rgb_ofst = 0;
+ uofst = size;
+ v_uvofst = 0;
+ } else if(dst->format == COLOR_YUV420P) {
+ next_y_rgb_addr = dstaddr;
+ next_u_addr = dstaddr+size;
+ next_v_addr = dstaddr+size*5/4;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else if (dst->format == COLOR_YUV422_YVYU) {
+ next_y_rgb_addr = dstaddr;
+ next_u_addr = dstaddr+1;
+ next_v_addr = dstaddr+3;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else if(dst->format == COLOR_YUV422_VYUY) {
+ next_y_rgb_addr = dstaddr+1;
+ next_u_addr = dstaddr+2;
+ next_v_addr = dstaddr;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else if(dst->format == COLOR_YUV422_YUYV) {
+ next_y_rgb_addr = dstaddr;
+ next_u_addr = dstaddr+1;
+ next_v_addr = dstaddr+2;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ } else if(dst->format == COLOR_YUV422_UYVY) {
+ next_y_rgb_addr = dstaddr+1;
+ next_u_addr = dstaddr;
+ next_v_addr = dstaddr+2;
+ y_rgb_ofst = 0;
+ uofst = 0;
+ v_uvofst = 0;
+ }
+ }
+ pp_desAddr_cfg(sf_dev, ppNum, next_y_rgb_addr, next_u_addr, next_v_addr);
+ pp_desOffset_cfg(sf_dev, ppNum, y_rgb_ofst, uofst, v_uvofst);
+ }
+
+}
+
+
+void pp_config(struct sf_fb_data *sf_dev, int ppNum, struct pp_video_mode *src, struct pp_video_mode *dst)
+{
+ //pp_disable_intr(sf_dev, ppNum);
+ pp_format_set(sf_dev, ppNum, src, dst);
+ pp_size_set(sf_dev, ppNum, src, dst);
+}
+EXPORT_SYMBOL(pp_config);
+
+irqreturn_t vpp1_isr_handler(int this_irq, void *dev_id)
+{
+ struct sf_fb_data *sf_dev = (struct sf_fb_data *)dev_id;
+ static int count = 0;
+ sf_fb_vppwrite32(sf_dev, 1, PP_INT_CLR, 0xf);
+
+ count ++;
+ if(0 == count % 60)
+ PP_PRT("=");
+ //printk("=");
+
+ return IRQ_HANDLED;
+}
+EXPORT_SYMBOL(vpp1_isr_handler);
+
+MODULE_AUTHOR("StarFive Technology Co., Ltd.");
+MODULE_DESCRIPTION("loadable VPP driver for StarFive");
+MODULE_LICENSE("GPL");