void sc_hwset_blend(struct sc_dev *sc, enum sc_blend_op bl_op, bool pre_multi, unsigned char g_alpha) { unsigned int cfg = readl(sc->regs + SCALER_CFG); int idx = bl_op - 1; cfg |= SCALER_CFG_BLEND_EN; writel(cfg, sc->regs + SCALER_CFG); cfg = readl(sc->regs + SCALER_SRC_BLEND_COLOR); get_blend_value(&cfg, sc_bl_op_tbl[idx].src_color, pre_multi); if (g_alpha < 0xff) cfg |= (SRC_GA << SCALER_OP_SEL_SHIFT); writel(cfg, sc->regs + SCALER_SRC_BLEND_COLOR); sc_dbg("src_blend_color is 0x%x, %d\n", cfg, pre_multi); cfg = readl(sc->regs + SCALER_SRC_BLEND_ALPHA); get_blend_value(&cfg, sc_bl_op_tbl[idx].src_alpha, 1); if (g_alpha < 0xff) cfg |= (SRC_GA << SCALER_OP_SEL_SHIFT) | (g_alpha << 0); writel(cfg, sc->regs + SCALER_SRC_BLEND_ALPHA); sc_dbg("src_blend_alpha is 0x%x\n", cfg); cfg = readl(sc->regs + SCALER_DST_BLEND_COLOR); get_blend_value(&cfg, sc_bl_op_tbl[idx].dst_color, pre_multi); if (g_alpha < 0xff) cfg |= ((INV_SAGA & 0xf) << SCALER_OP_SEL_SHIFT); writel(cfg, sc->regs + SCALER_DST_BLEND_COLOR); sc_dbg("dst_blend_color is 0x%x\n", cfg); cfg = readl(sc->regs + SCALER_DST_BLEND_ALPHA); get_blend_value(&cfg, sc_bl_op_tbl[idx].dst_alpha, 1); if (g_alpha < 0xff) cfg |= ((INV_SAGA & 0xf) << SCALER_OP_SEL_SHIFT); writel(cfg, sc->regs + SCALER_DST_BLEND_ALPHA); sc_dbg("dst_blend_alpha is 0x%x\n", cfg); /* * If dst format is non-premultiplied format * and blending operation is enabled, * result image should be divided by alpha value * because the result is always pre-multiplied. */ if (!pre_multi) { cfg = readl(sc->regs + SCALER_CFG); cfg |= SCALER_CFG_BL_DIV_ALPHA_EN; writel(cfg, sc->regs + SCALER_CFG); } }
void sc_hwset_flip_rotation(struct sc_dev *sc, u32 direction, int degree) { unsigned long cfg = readl(sc->regs + SCALER_ROT_CFG); sc_dbg("flip %d rotation %d\n", direction, degree); cfg &= ~SCALER_FLIP_MASK; if (direction & SC_VFLIP) cfg |= SCALER_FLIP_X_EN; if (direction & SC_HFLIP) cfg |= SCALER_FLIP_Y_EN; /* * we expect that the direction of rotation is clockwise * but the Scaler does in counter clockwise. * Since the GScaler doest that in clockwise, * the following makes the direction of rotation by the Scaler * clockwise. */ cfg &= ~SCALER_ROT_MASK; if (degree == 270) cfg |= SCALER_ROT_90; else if (degree == 180) cfg |= SCALER_ROT_180; else if (degree == 90) cfg |= SCALER_ROT_270; writel(cfg, sc->regs + SCALER_ROT_CFG); }
int sc_hwget_version(struct sc_dev *sc) { unsigned long cfg = readl(sc->regs + SCALER_VER); sc_dbg("This scaler version is 0x%x\n", (unsigned int)cfg); return cfg & 0xffff; }
void sc_hwset_csc_coef(struct sc_dev *sc, enum sc_csc_idx idx, struct sc_csc *csc) { unsigned int i, j, tmp; unsigned long cfg; int *csc_eq_val; if (idx == NO_CSC) { csc_eq_val = sc_csc_list[idx]->narrow_601; } else { if (csc->csc_eq == V4L2_COLORSPACE_REC709) { if (csc->csc_range == SC_CSC_NARROW) csc_eq_val = sc_csc_list[idx]->narrow_709; else csc_eq_val = sc_csc_list[idx]->wide_709; } else if (csc->csc_eq == V4L2_COLORSPACE_BT2020) { if (csc->csc_range == SC_CSC_NARROW) csc_eq_val = sc_csc_list[idx]->narrow_2020; else csc_eq_val = sc_csc_list[idx]->wide_2020; } else if (csc->csc_eq == V4L2_COLORSPACE_DCI_P3) { if (csc->csc_range == SC_CSC_NARROW) csc_eq_val = sc_csc_list[idx]->narrow_p3; else csc_eq_val = sc_csc_list[idx]->wide_p3; } else { if (csc->csc_range == SC_CSC_NARROW) csc_eq_val = sc_csc_list[idx]->narrow_601; else csc_eq_val = sc_csc_list[idx]->wide_601; } } tmp = SCALER_CSC_COEF22 - SCALER_CSC_COEF00; for (i = 0, j = 0; i < 9; i++, j += 4) { cfg = readl(sc->regs + SCALER_CSC_COEF00 + j); cfg &= ~SCALER_CSC_COEF_MASK; cfg |= csc_eq_val[i]; writel(cfg, sc->regs + SCALER_CSC_COEF00 + j); sc_dbg("csc value %d - %d\n", i, csc_eq_val[i]); } /* set CSC_Y_OFFSET_EN */ cfg = readl(sc->regs + SCALER_CFG); if (idx == CSC_Y2R) { if (csc->csc_range == SC_CSC_WIDE) cfg &= ~SCALER_CFG_CSC_Y_OFFSET_SRC; else cfg |= SCALER_CFG_CSC_Y_OFFSET_SRC; } else if (idx == CSC_R2Y) { if (csc->csc_range == SC_CSC_WIDE) cfg &= ~SCALER_CFG_CSC_Y_OFFSET_DST; else cfg |= SCALER_CFG_CSC_Y_OFFSET_DST; } writel(cfg, sc->regs + SCALER_CFG); }
void sc_hwset_vratio(struct sc_dev *sc, u32 ratio) { unsigned long cfg = readl(sc->regs + SCALER_V_RATIO); sc_dbg("v-ratio is %d\n", ratio); cfg &= ~SCALER_RATIO_MASK; cfg |= ratio; writel(cfg, sc->regs + SCALER_V_RATIO); }
void sc_hwset_color_fill(struct sc_dev *sc, unsigned int val) { unsigned int cfg = readl(sc->regs + SCALER_CFG); cfg |= SCALER_CFG_FILL_EN; writel(cfg, sc->regs + SCALER_CFG); cfg = readl(sc->regs + SCALER_FILL_COLOR); cfg = val; writel(cfg, sc->regs + SCALER_FILL_COLOR); sc_dbg("color filled is 0x%08x\n", val); }
void sc_hwset_soft_reset(struct sc_dev *sc) { unsigned long cfg = readl(sc->regs + SCALER_CFG); cfg |= SCALER_CFG_SOFT_RST; cfg &= ~((1 << 10) | (1 << 9)); writel(cfg, sc->regs + SCALER_CFG); sc_dbg("done soft reset\n"); /* * TODO: check the reset completion * 1. wait until it becomes '0' * 2. backup the SCALER_INT_EN value * 3. write 0x1 to SCALER_INT_EN and re-read * 4. if re-read is 0x1, successfully complete * 5. restore the SCALER_INT_EN register */ }
void sc_hwset_flip_rotation(struct sc_dev *sc, u32 direction, int degree) { unsigned long cfg = readl(sc->regs + SCALER_ROT_CFG); sc_dbg("flip %d rotation %d\n", direction, degree); cfg &= ~SCALER_FLIP_MASK; if (direction & SC_VFLIP) cfg |= SCALER_FLIP_X_EN; if (direction & SC_HFLIP) cfg |= SCALER_FLIP_Y_EN; cfg &= ~SCALER_ROT_MASK; if (degree == 90) cfg |= SCALER_ROT_90; else if (degree == 180) cfg |= SCALER_ROT_180; else if (degree == 270) cfg |= SCALER_ROT_270; writel(cfg, sc->regs + SCALER_ROT_CFG); }
void sc_hwset_blend(struct sc_dev *sc, enum sc_blend_op bl_op, bool pre_multi, unsigned char g_alpha, struct sc_src_blend_cfg *src_blend_cfg) { unsigned int cfg = __raw_readl(sc->regs + SCALER_CFG); int idx = bl_op - 1; cfg |= SCALER_CFG_BLEND_EN; __raw_writel(cfg, sc->regs + SCALER_CFG); cfg = __raw_readl(sc->regs + SCALER_SRC_BLEND_COLOR); get_blend_value(&cfg, sc_bl_op_tbl[idx].src_color, pre_multi); if (g_alpha < 0xff) cfg |= (SRC_GA << SCALER_OP_SEL_SHIFT); __raw_writel(cfg, sc->regs + SCALER_SRC_BLEND_COLOR); sc_dbg("src_blend_color is 0x%x, %d\n", cfg, pre_multi); cfg = __raw_readl(sc->regs + SCALER_SRC_BLEND_ALPHA); get_blend_value(&cfg, sc_bl_op_tbl[idx].src_alpha, 1); if (g_alpha < 0xff) cfg |= (SRC_GA << SCALER_OP_SEL_SHIFT) | (g_alpha << 0); __raw_writel(cfg, sc->regs + SCALER_SRC_BLEND_ALPHA); sc_dbg("src_blend_alpha is 0x%x\n", cfg); cfg = __raw_readl(sc->regs + SCALER_DST_BLEND_COLOR); get_blend_value(&cfg, sc_bl_op_tbl[idx].dst_color, pre_multi); if (g_alpha < 0xff) cfg |= ((INV_SAGA & 0xf) << SCALER_OP_SEL_SHIFT); __raw_writel(cfg, sc->regs + SCALER_DST_BLEND_COLOR); sc_dbg("dst_blend_color is 0x%x\n", cfg); cfg = __raw_readl(sc->regs + SCALER_DST_BLEND_ALPHA); get_blend_value(&cfg, sc_bl_op_tbl[idx].dst_alpha, 1); if (g_alpha < 0xff) cfg |= ((INV_SAGA & 0xf) << SCALER_OP_SEL_SHIFT); __raw_writel(cfg, sc->regs + SCALER_DST_BLEND_ALPHA); sc_dbg("dst_blend_alpha is 0x%x\n", cfg); /* * If dst format is non-premultiplied format * and blending operation is enabled, * result image should be divided by alpha value * because the result is always pre-multiplied. */ if (!pre_multi && sc->version != SCALER_VERSION(2, 2, 0)) { cfg = readl(sc->regs + SCALER_CFG); cfg |= SCALER_CFG_BL_DIV_ALPHA_EN; __raw_writel(cfg, sc->regs + SCALER_CFG); } /* Set source blending configuration */ if (sc->version == SCALER_VERSION(2, 2, 0)) { sc_set_blendsrc_cfg(sc, pre_multi, src_blend_cfg); /* span in the units of pixels */ sc_set_blend_src_span(sc, src_blend_cfg->blend_src_stride); sc_blend_src_pos(sc, src_blend_cfg->blend_src_h_pos, src_blend_cfg->blend_src_v_pos); sc_blend_src_wh(sc, src_blend_cfg->blend_src_crop_width, src_blend_cfg->blend_src_crop_height); } }