diff options
Diffstat (limited to 'drivers/gpu/drm/starfive/starfive_drm_vpp.c')
-rw-r--r-- | drivers/gpu/drm/starfive/starfive_drm_vpp.c | 766 |
1 files changed, 766 insertions, 0 deletions
diff --git a/drivers/gpu/drm/starfive/starfive_drm_vpp.c b/drivers/gpu/drm/starfive/starfive_drm_vpp.c new file mode 100644 index 000000000000..7a118222bd93 --- /dev/null +++ b/drivers/gpu/drm/starfive/starfive_drm_vpp.c @@ -0,0 +1,766 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/reset.h> +#include <linux/delay.h> +#include "starfive_drm_vpp.h" +#include "starfive_drm_crtc.h" +#include <soc/sifive/sifive_ccache.h> + +static inline void sf_set_clear(void __iomem *addr, u32 reg, u32 set, u32 clear) +{ + u32 value = ioread32(addr + reg); + + value &= ~clear; + value |= set; + iowrite32(value, addr + reg); +} + +static u32 sf_fb_sysread32(struct starfive_crtc *sf_crtc, u32 reg) +{ + return ioread32(sf_crtc->base_syscfg + reg); +} + +static void sf_fb_syswrite32(struct starfive_crtc *sf_crtc, u32 reg, u32 val) +{ + iowrite32(val, sf_crtc->base_syscfg + reg); +} + +static u32 sf_fb_vppread32(struct starfive_crtc *sf_crtc, int pp_num, u32 reg) +{ + void __iomem *base_vpp; + + switch (pp_num) { + case 0: + base_vpp = sf_crtc->base_vpp0; + break; + case 1: + base_vpp = sf_crtc->base_vpp1; + break; + case 2: + base_vpp = sf_crtc->base_vpp2; + break; + default: + dev_err(sf_crtc->dev, "Err:invalid vpp Number!\n"); + return 0; + } + + return ioread32(base_vpp + reg); +} + +static void sf_fb_vppwrite32(struct starfive_crtc *sf_crtc, int pp_num, u32 reg, u32 val) +{ + void __iomem *base_vpp; + + switch (pp_num) { + case 0: + base_vpp = sf_crtc->base_vpp0; + break; + case 1: + base_vpp = sf_crtc->base_vpp1; + break; + case 2: + base_vpp = sf_crtc->base_vpp2; + break; + default: + dev_err(sf_crtc->dev, "Err:invalid vpp Number!\n"); + return; + } + iowrite32(val, base_vpp + reg); +} + +void mapconv_pp0_sel(struct starfive_crtc *sf_crtc, int sel) +{ + u32 temp; + + temp = sf_fb_sysread32(sf_crtc, SYS_MAP_CONV); + temp &= ~(0x1); + temp |= (sel & 0x1); + sf_fb_syswrite32(sf_crtc, SYS_MAP_CONV, temp); +} + +static void pp_output_cfg(struct starfive_crtc *sf_crtc, + int pp_num, int out_sel, int prog_inter, int desformat, + int pt_mode) +{ + int cfg = out_sel | prog_inter << PP_INTERLACE | + desformat << PP_DES_FORMAT | + pt_mode << PP_POINTER_MODE; + int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL1) & 0xffff8f0U; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL1, cfg | pre_cfg); + dev_dbg(sf_crtc->dev, "PP%d out_sel: %d, outFormat: 0x%x, Out Interlace: %d, pt_mode: %d\n", + pp_num, out_sel, desformat, prog_inter, pt_mode); +} + +static void pp_srcfmt_cfg(struct starfive_crtc *sf_crtc, int pp_num, int srcformat, + int yuv420_inter, int yuv422_mode, int yuv420_mode, int argb_ord) +{ + int cfg = srcformat << PP_SRC_FORMAT_N | + yuv420_inter << PP_420_ITLC | + yuv422_mode << PP_SRC_422_YUV_POS | + yuv420_mode << PP_SRC_420_YUV_POS | + argb_ord << PP_SRC_ARGB_ORDER; + int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL1) & 0x83ffff0fU; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL1, cfg | pre_cfg); + dev_dbg(sf_crtc->dev, "PP%d Src Format: 0x%x, YUV420 Interlace: %d, YUV422: %d, YUV420: %d, ARGB Order: %d\n", + pp_num, srcformat, yuv420_inter, yuv422_mode, yuv420_mode, argb_ord); +} + +static void pp_r2yscal_bypass(struct starfive_crtc *sf_crtc, + int pp_num, int r2y_byp, int scal_byp, int y2r_byp) +{ + int bypass = (r2y_byp | scal_byp << 1 | y2r_byp << 2) << PP_R2Y_BPS; + int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL1) & 0xffff8fffU; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL1, bypass | pre_cfg); + dev_dbg(sf_crtc->dev, "PP%d Bypass R2Y: %d, Y2R: %d, MainSacle: %d\n", + pp_num, r2y_byp, y2r_byp, scal_byp); +} + +static void pp_argb_alpha(struct starfive_crtc *sf_crtc, int pp_num, int alpha) +{ + int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL1) & 0xff00ffffU; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL1, alpha << PP_ARGB_ALPHA | pre_cfg); + dev_dbg(sf_crtc->dev, "PP%d Alpha: 0x%4x\n", pp_num, alpha); +} + +//rgbNum: 1-3 +static void pp_r2y_coeff(struct starfive_crtc *sf_crtc, + int pp_num, int coef_num, int rcoef, int gcoef, int bcoef, int off) +{ + int rgcoeff = rcoef | gcoef << PP_COEF_G1; + int bcoefoff = bcoef | off << PP_OFFSET_1; + u32 addr1 = (coef_num - 1) * 0x8 + PP_R2Y_COEF1; + u32 addr2 = (coef_num - 1) * 0x8 + PP_R2Y_COEF2; + + sf_fb_vppwrite32(sf_crtc, pp_num, addr1, rgcoeff); + sf_fb_vppwrite32(sf_crtc, pp_num, addr2, bcoefoff); + dev_dbg(sf_crtc->dev, "PP%d coef_num: %d, rCoef: 0x%4x, gCoef: 0x%4x, bCoef: 0x%4x, off: 0x%4x\n", + pp_num, coef_num, rcoef, gcoef, bcoef, off); +} + +static void pp_output_fmt_cfg(struct starfive_crtc *sf_crtc, + int pp_num, int yuv420_inter, int yuv422_mode) +{ + int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL2) & 0xfffffffeU; + + pre_cfg = pre_cfg | + yuv420_inter << PP_DES_420_ORDER | + yuv422_mode << PP_DES_422_ORDER; + sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL2, pre_cfg); + dev_dbg(sf_crtc->dev, "PP%d Lock Transfer: %d\n", pp_num, yuv422_mode); +} + +static void pp_lock_trans_cfg(struct starfive_crtc *sf_crtc, int pp_num, int lock_trans) +{ + int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL2) & 0xfffffffeU; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL2, lock_trans | pre_cfg); + dev_dbg(sf_crtc->dev, "PP%d Lock Transfer: %d\n", pp_num, lock_trans); +} + +static void pp_int_interval_cfg(struct starfive_crtc *sf_crtc, int pp_num, int interval) +{ + int pre_cfg = sf_fb_vppread32(sf_crtc, pp_num, PP_CTRL2) & 0xffff00ffU; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_CTRL2, interval << PP_INT_INTERVAL | pre_cfg); + dev_dbg(sf_crtc->dev, "PP%d Frame Interrupt interval: %d Frames\n", pp_num, interval); +} + +static void pp_src_size_cfg(struct starfive_crtc *sf_crtc, int pp_num, int hsize, int vsize) +{ + int size = hsize | vsize << PP_SRC_VSIZE; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_SIZE, size); + dev_dbg(sf_crtc->dev, "PP%d HSize: %d, VSize: %d\n", pp_num, hsize, vsize); +} + +//0-no drop, 1-1/2, 2-1/4, down to 1/32 +static void pp_drop_cfg(struct starfive_crtc *sf_crtc, int pp_num, int hdrop, int vdrop) +{ + int drop = hdrop | vdrop << PP_DROP_VRATION; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_DROP_CTRL, drop); + dev_dbg(sf_crtc->dev, "PP%d HDrop: %d, VDrop: %d\n", pp_num, hdrop, vdrop); +} + +static void pp_des_size_cfg(struct starfive_crtc *sf_crtc, int pp_num, int hsize, int vsize) +{ + int size = hsize | vsize << PP_DES_VSIZE; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_SIZE, size); + dev_dbg(sf_crtc->dev, "PP%d HSize: %d, VSize: %d\n", pp_num, hsize, vsize); +} + +static void pp_des_addr_cfg(struct starfive_crtc *sf_crtc, + int pp_num, int yaddr, int uaddr, int vaddr) +{ + sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_Y_SA, yaddr); + sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_U_SA, uaddr); + sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_V_SA, vaddr); + dev_dbg(sf_crtc->dev, "PP%d des-Addr Y: 0x%8x, U: 0x%8x, V: 0x%8x\n", + pp_num, yaddr, uaddr, vaddr); +} + +static void pp_des_offset_cfg(struct starfive_crtc *sf_crtc, + int pp_num, int yoff, int uoff, int voff) +{ + sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_Y_OFS, yoff); + sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_U_OFS, uoff); + sf_fb_vppwrite32(sf_crtc, pp_num, PP_DES_V_OFS, voff); + dev_dbg(sf_crtc->dev, "PP%d des-Offset Y: 0x%4x, U: 0x%4x, V: 0x%4x\n", + pp_num, yoff, uoff, voff); +} + +void pp_intcfg(struct starfive_crtc *sf_crtc, int pp_num, int int_mask) +{ + int intcfg = ~(0x1 << 0); + + if (int_mask) + intcfg = 0xf; + sf_fb_vppwrite32(sf_crtc, pp_num, PP_INT_MASK, intcfg); +} + +//next source frame Y/RGB start address, ? +void pp_src_addr_next(struct starfive_crtc *sf_crtc, int pp_num, int ysa, int usa, int vsa) +{ + sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_Y_SA_NXT, ysa); + sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_U_SA_NXT, usa); + sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_V_SA_NXT, vsa); + dev_dbg(sf_crtc->dev, + "PP%d next Y startAddr: 0x%8x, U startAddr: 0x%8x, V startAddr: 0x%8x\n", + pp_num, ysa, usa, vsa); +} + +void pp_src_offset_cfg(struct starfive_crtc *sf_crtc, int pp_num, int yoff, int uoff, int voff) +{ + sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_Y_OFS, yoff); + sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_U_OFS, uoff); + sf_fb_vppwrite32(sf_crtc, pp_num, PP_SRC_V_OFS, voff); + dev_dbg(sf_crtc->dev, "PP%d src-Offset Y: 0x%4x, U: 0x%4x, V: 0x%4x\n", + pp_num, yoff, uoff, voff); +} + +void pp_nxt_addr_load(struct starfive_crtc *sf_crtc, int pp_num, int nxt_par, int nxt_pos) +{ + sf_fb_vppwrite32(sf_crtc, pp_num, PP_LOAD_NXT_PAR, nxt_par | nxt_pos); + dev_dbg(sf_crtc->dev, "PP%d next addrPointer: %d, %d set Regs\n", pp_num, nxt_par, nxt_pos); +} + +void pp_run(struct starfive_crtc *sf_crtc, int pp_num, int start) +{ + sf_fb_vppwrite32(sf_crtc, pp_num, PP_SWITCH, start); + //if (start) + // dev_dbg(sf_crtc->dev, "Now start the PP%d\n\n", pp_num); +} + +void pp1_enable_intr(struct starfive_crtc *sf_crtc) +{ + sf_fb_vppwrite32(sf_crtc, 1, PP_INT_MASK, 0x0); +} + +void pp_enable_intr(struct starfive_crtc *sf_crtc, int pp_num) +{ + u32 cfg = 0xfffe; + + sf_fb_vppwrite32(sf_crtc, pp_num, PP_INT_MASK, cfg); +} + +void pp_disable_intr(struct starfive_crtc *sf_crtc, int pp_num) +{ + sf_fb_vppwrite32(sf_crtc, pp_num, PP_INT_MASK, 0xf); + sf_fb_vppwrite32(sf_crtc, pp_num, PP_INT_CLR, 0xf); +} + +static void pp_srcfmt_set(struct starfive_crtc *sf_crtc, int pp_num, struct pp_video_mode *src) +{ + switch (src->format) { + case COLOR_YUV422_YVYU: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV422, 0x0, COLOR_YUV422_YVYU, 0x0, 0x0); + break; + case COLOR_YUV422_VYUY: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV422, 0x0, COLOR_YUV422_VYUY, 0x0, 0x0); + break; + case COLOR_YUV422_YUYV: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV422, 0x0, COLOR_YUV422_YUYV, 0x0, 0x0); + break; + case COLOR_YUV422_UYVY: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV422, 0x0, COLOR_YUV422_UYVY, 0x0, 0x0); + break; + case COLOR_YUV420P: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV420P, 0x0, 0, 0x0, 0x0); + break; + case COLOR_YUV420_NV21: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV420I, 0x1, 0, + COLOR_YUV420_NV21 - COLOR_YUV420_NV21, 0x0); + break; + case COLOR_YUV420_NV12: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_YUV420I, 0x1, 0, + COLOR_YUV420_NV12 - COLOR_YUV420_NV21, 0x0); + break; + case COLOR_RGB888_ARGB: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_GRB888, 0x0, 0x0, + 0x0, COLOR_RGB888_ARGB - COLOR_RGB888_ARGB); + break; + case COLOR_RGB888_ABGR: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_GRB888, 0x0, 0x0, + 0x0, COLOR_RGB888_ABGR - COLOR_RGB888_ARGB); + break; + case COLOR_RGB888_RGBA: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_GRB888, 0x0, 0x0, + 0x0, COLOR_RGB888_RGBA - COLOR_RGB888_ARGB); + break; + case COLOR_RGB888_BGRA: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_GRB888, 0x0, 0x0, + 0x0, COLOR_RGB888_BGRA - COLOR_RGB888_ARGB); + break; + case COLOR_RGB565: + pp_srcfmt_cfg(sf_crtc, pp_num, PP_SRC_RGB565, 0x0, 0x0, 0x0, 0x0); + break; + } +} + +static void pp_dstfmt_set(struct starfive_crtc *sf_crtc, int pp_num, 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_crtc, pp_num, outsel, 0x0, PP_DST_YUV422, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, 0, COLOR_YUV422_UYVY - COLOR_YUV422_YVYU); + break; + case COLOR_YUV422_VYUY: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV422, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, 0, COLOR_YUV422_UYVY - COLOR_YUV422_VYUY); + break; + case COLOR_YUV422_YUYV: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV422, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, 0, COLOR_YUV422_UYVY - COLOR_YUV422_YUYV); + break; + case COLOR_YUV422_UYVY: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV422, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, 0, COLOR_YUV422_UYVY - COLOR_YUV422_YVYU); + break; + case COLOR_YUV420P: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV420P, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0); + break; + case COLOR_YUV420_NV21: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV420I, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, COLOR_YUV420_NV21 - COLOR_YUV420_NV21, 0); + break; + case COLOR_YUV420_NV12: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_YUV420I, 0x0);///0x2, 0x0); + //pp_output_fmt_cfg(pp_num, COLOR_YUV420_NV12 - COLOR_YUV420_NV21, 0); + break; + case COLOR_RGB888_ARGB: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_ARGB888, 0x0); + //pp_output_fmt_cfg(pp_num, 0, 0); + break; + case COLOR_RGB888_ABGR: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_ABGR888, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0); + break; + case COLOR_RGB888_RGBA: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_RGBA888, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0); + break; + case COLOR_RGB888_BGRA: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_BGRA888, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0); + break; + case COLOR_RGB565: + pp_output_cfg(sf_crtc, pp_num, outsel, 0x0, PP_DST_RGB565, 0x0); + pp_output_fmt_cfg(sf_crtc, pp_num, 0, 0); + break; + } +} + +static void pp_format_set(struct starfive_crtc *sf_crtc, int pp_num, + struct pp_video_mode *src, struct pp_video_mode *dst) +{ + /* 1:bypass, 0:not bypass */ + unsigned int scale_byp = 1; + + pp_srcfmt_set(sf_crtc, pp_num, src); + pp_dstfmt_set(sf_crtc, pp_num, 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_crtc, pp_num, NOT_BYPASS, scale_byp, BYPASS); + pp_r2y_coeff(sf_crtc, pp_num, 1, R2Y_COEF_R1, R2Y_COEF_G1, + R2Y_COEF_B1, R2Y_OFFSET1); + pp_r2y_coeff(sf_crtc, pp_num, 2, R2Y_COEF_R2, R2Y_COEF_G2, + R2Y_COEF_B2, R2Y_OFFSET2); + pp_r2y_coeff(sf_crtc, pp_num, 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_crtc, pp_num, BYPASS, scale_byp, NOT_BYPASS); + } else if (src->format <= COLOR_YUV422_YVYU && dst->format <= COLOR_YUV420_NV12) { + /* yuv422 -> yuv420 */ + pp_r2yscal_bypass(sf_crtc, pp_num, BYPASS, scale_byp, BYPASS); + } else { + /* rgb565->argb888 */ + pp_r2yscal_bypass(sf_crtc, pp_num, BYPASS, scale_byp, BYPASS); + } //else if ((src->format >= COLOR_RGB888_ARGB) && (dst->format >= COLOR_RGB888_ARGB)) { + /* rgb -> rgb */ + // pp_r2yscal_bypass(pp_num, BYPASS, scale_byp, BYPASS); + //} + pp_argb_alpha(sf_crtc, pp_num, 0xff); + + if (dst->addr) + pp_lock_trans_cfg(sf_crtc, pp_num, SYS_BUS_OUTPUT); + else + pp_lock_trans_cfg(sf_crtc, pp_num, FIFO_OUTPUT); + + pp_int_interval_cfg(sf_crtc, pp_num, 0x1); +} + +static void pp_size_set(struct starfive_crtc *sf_crtc, int pp_num, + struct pp_video_mode *src, struct pp_video_mode *dst) +{ + u32 src_addr, dstaddr; + unsigned int y_rgb_ofst = 0, uofst = 0, v_uvofst = 0; + unsigned int next_y_rgb_addr = 0, next_u_addr = 0, next_v_addr = 0; + unsigned int i = 0; + unsigned int size; + + pp_src_size_cfg(sf_crtc, pp_num, src->width - 1, src->height - 1); + pp_drop_cfg(sf_crtc, pp_num, 0x0, 0x0);///0:no drop + pp_des_size_cfg(sf_crtc, pp_num, dst->width - 1, dst->height - 1); + + src_addr = 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 = src_addr; + next_u_addr = 0; + next_v_addr = 0; + + //pp_src_addr_next(pp_num, src_addr, 0, 0); + //pp_src_offset_cfg(pp_num, 0x0, 0x0, 0x0); + } else { + if (src->format == COLOR_YUV420_NV21) { //ok + next_y_rgb_addr = src_addr; + next_u_addr = src_addr + size + 1; + next_v_addr = src_addr + size; + v_uvofst = size; + } else if (src->format == COLOR_YUV420_NV12) { + next_y_rgb_addr = src_addr; + next_u_addr = src_addr + size; + next_v_addr = src_addr + size + 1; + v_uvofst = size; + } else if (src->format == COLOR_YUV420P) { + next_y_rgb_addr = src_addr; + next_u_addr = src_addr + size; + next_v_addr = src_addr + size * 5 / 4; + } else if (src->format == COLOR_YUV422_YVYU) { //ok + next_y_rgb_addr = src_addr; + next_u_addr = src_addr + 1; + next_v_addr = src_addr + 3; + } else if (src->format == COLOR_YUV422_VYUY) { //ok + next_y_rgb_addr = src_addr + 1; + next_u_addr = src_addr + 2; + next_v_addr = src_addr; + } else if (src->format == COLOR_YUV422_YUYV) { //ok + next_y_rgb_addr = src_addr; + next_u_addr = src_addr + 1; + next_v_addr = src_addr + 2; + } else if (src->format == COLOR_YUV422_UYVY) { //ok + next_y_rgb_addr = src_addr + 1; + next_u_addr = src_addr; + next_v_addr = src_addr + 2; + } + } + pp_src_addr_next(sf_crtc, pp_num, next_y_rgb_addr, next_u_addr, next_v_addr); + pp_src_offset_cfg(sf_crtc, pp_num, y_rgb_ofst, uofst, v_uvofst); + /* source addr not change */ + pp_nxt_addr_load(sf_crtc, pp_num, 0x1, (i & 0x1)); + + if (dst->addr) { + dstaddr = dst->addr; + size = dst->height * dst->width; + y_rgb_ofst = 0; + uofst = 0; + v_uvofst = 0; + + if (dst->format >= COLOR_RGB888_ARGB) { + next_y_rgb_addr = dstaddr; + next_u_addr = 0; + next_v_addr = 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; + } else if (dst->format == COLOR_YUV420_NV12) { + /* yyyyuvuvuv */ + next_y_rgb_addr = dstaddr; + next_u_addr = dstaddr + size; + next_v_addr = dstaddr + size + 1; + uofst = size; + } else if (dst->format == COLOR_YUV420P) { + next_y_rgb_addr = dstaddr; + next_u_addr = dstaddr + size; + next_v_addr = dstaddr + size * 5 / 4; + } else if (dst->format == COLOR_YUV422_YVYU) { + next_y_rgb_addr = dstaddr; + next_u_addr = dstaddr + 1; + next_v_addr = dstaddr + 3; + } else if (dst->format == COLOR_YUV422_VYUY) { + next_y_rgb_addr = dstaddr + 1; + next_u_addr = dstaddr + 2; + next_v_addr = dstaddr; + } else if (dst->format == COLOR_YUV422_YUYV) { + next_y_rgb_addr = dstaddr; + next_u_addr = dstaddr + 1; + next_v_addr = dstaddr + 2; + } else if (dst->format == COLOR_YUV422_UYVY) { + next_y_rgb_addr = dstaddr + 1; + next_u_addr = dstaddr; + next_v_addr = dstaddr + 2; + } + } + pp_des_addr_cfg(sf_crtc, pp_num, next_y_rgb_addr, next_u_addr, next_v_addr); + pp_des_offset_cfg(sf_crtc, pp_num, y_rgb_ofst, uofst, v_uvofst); + } +} + +static void pp_config(struct starfive_crtc *sf_crtc, int pp_num, + struct pp_video_mode *src, struct pp_video_mode *dst) +{ + //pp_disable_intr(sf_dev, pp_num); + pp_format_set(sf_crtc, pp_num, src, dst); + pp_size_set(sf_crtc, pp_num, src, dst); +} + +irqreturn_t vpp1_isr_handler(int this_irq, void *dev_id) +{ + struct starfive_crtc *sf_crtc = dev_id; + + sf_fb_vppread32(sf_crtc, 1, PP_INT_STATUS); + sf_fb_vppwrite32(sf_crtc, 1, PP_INT_CLR, 0xf); + sifive_ccache_flush_range(sf_crtc->dma_addr, sf_crtc->size); + + return IRQ_HANDLED; +} + +static void starfive_pp_enable_intr(struct starfive_crtc *sf_crtc, int enable) +{ + int pp_id; + + for (pp_id = 0; pp_id < PP_NUM; pp_id++) { + if (sf_crtc->pp[pp_id].inited == 1) { + if (enable) + pp_enable_intr(sf_crtc, pp_id); + else + pp_disable_intr(sf_crtc, pp_id); + } + } +} + +static int starfive_pp_video_mode_init(struct starfive_crtc *sf_crtc, + struct pp_video_mode *src, + struct pp_video_mode *dst, + int pp_id) +{ + if (!src || !dst) { + dev_err(sf_crtc->dev, "Invalid argument!\n"); + return -EINVAL; + } + + if (pp_id < PP_NUM && pp_id >= 0) { + src->format = sf_crtc->vpp_format; + src->width = sf_crtc->crtc.state->adjusted_mode.hdisplay; + src->height = sf_crtc->crtc.state->adjusted_mode.vdisplay; + src->addr = sf_crtc->dma_addr; + //src->addr = 0xa0000000; + dst->format = sf_crtc->pp[pp_id].dst.format; + dst->width = sf_crtc->crtc.state->adjusted_mode.hdisplay; + dst->height = sf_crtc->crtc.state->adjusted_mode.vdisplay; + if (sf_crtc->pp[pp_id].bus_out) /*out to ddr*/ + dst->addr = 0xfc000000; + else if (sf_crtc->pp[pp_id].fifo_out) /*out to lcdc*/ + dst->addr = 0; + } else { + dev_err(sf_crtc->dev, "pp_id %d is not support\n", pp_id); + return -EINVAL; + } + + return 0; +} + +static int starfive_pp_init(struct starfive_crtc *sf_crtc) +{ + int pp_id; + int ret = 0; + struct pp_video_mode src, dst; + + for (pp_id = 0; pp_id < PP_NUM; pp_id++) { + if (sf_crtc->pp[pp_id].inited == 1) { + ret = starfive_pp_video_mode_init(sf_crtc, &src, &dst, pp_id); + if (!ret) + pp_config(sf_crtc, pp_id, &src, &dst); + } + } + + return ret; +} + +static int starfive_pp_run(struct starfive_crtc *sf_crtc) +{ + int pp_id; + int ret = 0; + + for (pp_id = 0; pp_id < PP_NUM; pp_id++) { + if (sf_crtc->pp[pp_id].inited == 1) + pp_run(sf_crtc, pp_id, PP_RUN); + } + + return ret; +} + +int starfive_pp_enable(struct starfive_crtc *sf_crtc) +{ + starfive_pp_enable_intr(sf_crtc, PP_INTR_DISABLE); + + if (starfive_pp_init(sf_crtc)) + return -ENODEV; + + starfive_pp_run(sf_crtc); + starfive_pp_enable_intr(sf_crtc, PP_INTR_ENABLE); + + return 0; +} + +int starfive_pp_update(struct starfive_crtc *sf_crtc) +{ + int pp_id; + int ret = 0; + struct pp_video_mode src, dst; + + for (pp_id = 0; pp_id < PP_NUM; pp_id++) { + if (sf_crtc->pp[pp_id].inited == 1) { + ret = starfive_pp_video_mode_init(sf_crtc, &src, &dst, pp_id); + if (!ret) { + if (sf_crtc->ddr_format_change) + pp_format_set(sf_crtc, pp_id, &src, &dst); + + if (sf_crtc->dma_addr_change) + pp_size_set(sf_crtc, pp_id, &src, &dst); + } + } + } + + return 0; +} + +int starfive_pp_get_2lcdc_id(struct starfive_crtc *sf_crtc) +{ + int pp_id; + + for (pp_id = 0; pp_id < PP_NUM; pp_id++) { + if (sf_crtc->pp[pp_id].inited == 1) { + if (sf_crtc->pp[pp_id].fifo_out == 1 && !sf_crtc->pp[pp_id].bus_out) + return pp_id; + } + } + + if (pp_id == PP_NUM - 1) + dev_warn(sf_crtc->dev, "NO pp connect to LCDC\n"); + + return -ENODEV; +} + +void dsitx_vout_init(struct starfive_crtc *sf_crtc) +{ + u32 temp; + + reset_control_assert(sf_crtc->rst_vout_src); + reset_control_assert(sf_crtc->rst_disp_axi); + clk_prepare_enable(sf_crtc->clk_disp_axi); + clk_prepare_enable(sf_crtc->clk_vout_src); + reset_control_deassert(sf_crtc->rst_vout_src); + reset_control_deassert(sf_crtc->rst_disp_axi); + + sf_set_clear(sf_crtc->base_clk, clk_disp0_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_disp1_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_lcdc_oclk_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_lcdc_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_vpp0_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_vpp1_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_vpp2_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_ppi_tx_esc_clk_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_dsi_apb_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_dsi_sys_clk_ctrl_REG, BIT(31), BIT(31)); + + sf_set_clear(sf_crtc->base_rst, vout_rstgen_assert0_REG, ~0x1981ec, 0x1981ec); + + do { + temp = ioread32(sf_crtc->base_rst + vout_rstgen_status0_REG); + temp &= 0x1981ec; + } while (temp != 0x1981ec); +} + +void vout_reset(struct starfive_crtc *sf_crtc) +{ + u32 temp; + + iowrite32(0xFFFFFFFF, sf_crtc->base_rst); + + clk_prepare_enable(sf_crtc->clk_disp_axi); + clk_prepare_enable(sf_crtc->clk_vout_src); + reset_control_deassert(sf_crtc->rst_vout_src); + reset_control_deassert(sf_crtc->rst_disp_axi); + + sf_set_clear(sf_crtc->base_clk, clk_disp0_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_disp1_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_lcdc_oclk_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_lcdc_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_vpp0_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_vpp1_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_vpp2_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_mapconv_apb_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_mapconv_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_pixrawout_apb_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_pixrawout_axi_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_csi2tx_strm0_apb_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_csi2tx_strm0_pixclk_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_ppi_tx_esc_clk_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_dsi_apb_ctrl_REG, BIT(31), BIT(31)); + sf_set_clear(sf_crtc->base_clk, clk_dsi_sys_clk_ctrl_REG, BIT(31), BIT(31)); + + sf_set_clear(sf_crtc->base_rst, vout_rstgen_assert0_REG, ~0x19bfff, 0x19bfff); + do { + temp = ioread32(sf_crtc->base_rst + vout_rstgen_status0_REG); + temp &= 0x19bfff; + } while (temp != 0x19bfff); +} + +void vout_disable(struct starfive_crtc *sf_crtc) +{ + iowrite32(0xFFFFFFFF, sf_crtc->base_rst); + + clk_disable_unprepare(sf_crtc->clk_disp_axi); + clk_disable_unprepare(sf_crtc->clk_vout_src); + reset_control_assert(sf_crtc->rst_vout_src); + reset_control_assert(sf_crtc->rst_disp_axi); +} + +MODULE_AUTHOR("StarFive Technology Co., Ltd."); +MODULE_DESCRIPTION("loadable VPP driver for StarFive"); +MODULE_LICENSE("GPL"); |