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);
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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);
}
Esempio n. 7
0
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
	 */
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
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);
	}
}