diff options
Diffstat (limited to 'drivers/video/mxc_pxp.c')
-rw-r--r-- | drivers/video/mxc_pxp.c | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/drivers/video/mxc_pxp.c b/drivers/video/mxc_pxp.c new file mode 100644 index 0000000..ea70bdd --- /dev/null +++ b/drivers/video/mxc_pxp.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> + +#include <asm/arch/imx-regs.h> +#include <asm/arch/sys_proto.h> +#include <asm/errno.h> +#include <asm/io.h> + +#include <linux/string.h> +#include <linux/list.h> +#include <gis.h> + +#include "mxc_pxp.h" + +#define BV_PXP_OUT_CTRL_FORMAT__RGB888 0x4 +#define BV_PXP_OUT_CTRL_FORMAT__RGB555 0xC +#define BV_PXP_OUT_CTRL_FORMAT__RGB444 0xD +#define BV_PXP_OUT_CTRL_FORMAT__RGB565 0xE +#define BV_PXP_OUT_CTRL_FORMAT__YUV1P444 0x10 +#define BV_PXP_OUT_CTRL_FORMAT__UYVY1P422 0x12 +#define BV_PXP_OUT_CTRL_FORMAT__VYUY1P422 0x13 + +#define BV_PXP_PS_CTRL_FORMAT__RGB888 0x4 +#define BV_PXP_PS_CTRL_FORMAT__RGB565 0xE +#define BV_PXP_PS_CTRL_FORMAT__YUV1P444 0x10 +#define BV_PXP_PS_CTRL_FORMAT__UYVY1P422 0x12 +#define BV_PXP_PS_CTRL_FORMAT__VYUY1P422 0x13 + +#define BP_PXP_PS_CTRL_SWAP 5 +#define BM_PXP_PS_CTRL_SWAP 0x000000E0 +#define BF_PXP_PS_CTRL_SWAP(v) \ + (((v) << 5) & BM_PXP_PS_CTRL_SWAP) + +#define PXP_DOWNSCALE_THRESHOLD 0x4000 + +static void pxp_set_ctrl(struct pxp_config_data *pxp_conf) +{ + u32 ctrl; + u32 fmt_ctrl; + int need_swap = 0; /* to support YUYV and YVYU formats */ + struct mxs_pxp_regs *regs = (struct mxs_pxp_regs *)PXP_BASE_ADDR; + + /* Configure S0 input format */ + switch (pxp_conf->s0_param.pixel_fmt) { + case FMT_YUV444: + fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__YUV1P444; + break; + case FMT_UYVY: + fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422; + break; + case FMT_YUYV: + fmt_ctrl = BV_PXP_PS_CTRL_FORMAT__UYVY1P422; + need_swap = 1; + default: + fmt_ctrl = 0; + } + + ctrl = BF_PXP_PS_CTRL_FORMAT(fmt_ctrl) | BF_PXP_PS_CTRL_SWAP(need_swap); + writel(ctrl, ®s->pxp_ps_ctrl); + + /* Configure output format based on out_channel format */ + switch (pxp_conf->out_param.pixel_fmt) { + case FMT_RGB565: + fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB565; + break; + case FMT_RGB888: + fmt_ctrl = BV_PXP_OUT_CTRL_FORMAT__RGB888; + break; + default: + fmt_ctrl = 0; + } + + ctrl = BF_PXP_OUT_CTRL_FORMAT(fmt_ctrl); + writel(ctrl, ®s->pxp_out_ctrl); +} + +static int pxp_set_scaling(struct pxp_config_data *pxp_conf) +{ + int ret = 0; + u32 xscale, yscale, s0scale; + u32 decx, decy, xdec = 0, ydec = 0; + struct pxp_layer_param *s0_params = &pxp_conf->s0_param; + struct pxp_layer_param *out_params = &pxp_conf->out_param; + struct mxs_pxp_regs *regs = (struct mxs_pxp_regs *)PXP_BASE_ADDR; + + decx = s0_params->width / out_params->width; + decy = s0_params->height / out_params->height; + if (decx > 1) { + if (decx >= 2 && decx < 4) { + decx = 2; + xdec = 1; + } else if (decx >= 4 && decx < 8) { + decx = 4; + xdec = 2; + } else if (decx >= 8) { + decx = 8; + xdec = 3; + } + xscale = s0_params->width * 0x1000 / + (out_params->width * decx); + } else { + if ((s0_params->pixel_fmt == FMT_YUYV) || + (s0_params->pixel_fmt == FMT_UYVY) || + (s0_params->pixel_fmt == FMT_YUV444)) + xscale = (s0_params->width - 1) * 0x1000 / + (out_params->width - 1); + else + xscale = (s0_params->width - 2) * 0x1000 / + (out_params->width - 1); + } + if (decy > 1) { + if (decy >= 2 && decy < 4) { + decy = 2; + ydec = 1; + } else if (decy >= 4 && decy < 8) { + decy = 4; + ydec = 2; + } else if (decy >= 8) { + decy = 8; + ydec = 3; + } + yscale = s0_params->height * 0x1000 / + (out_params->height * decy); + } else + yscale = (s0_params->height - 1) * 0x1000 / + (out_params->height - 1); + + writel((xdec << 10) | (ydec << 8), ®s->pxp_ps_ctrl); + + if (xscale > PXP_DOWNSCALE_THRESHOLD) + xscale = PXP_DOWNSCALE_THRESHOLD; + if (yscale > PXP_DOWNSCALE_THRESHOLD) + yscale = PXP_DOWNSCALE_THRESHOLD; + s0scale = BF_PXP_PS_SCALE_YSCALE(yscale) | + BF_PXP_PS_SCALE_XSCALE(xscale); + writel(s0scale, ®s->pxp_ps_scale); + + pxp_set_ctrl(pxp_conf); + + return ret; +} + +void pxp_power_down(void) +{ + struct mxs_pxp_regs *regs = (struct mxs_pxp_regs *)PXP_BASE_ADDR; + u32 val; + + val = BM_PXP_CTRL_SFTRST | BM_PXP_CTRL_CLKGATE; + writel(val , ®s->pxp_ctrl); +} + +void pxp_config(struct pxp_config_data *pxp_conf) +{ + struct mxs_pxp_regs *regs = (struct mxs_pxp_regs *)PXP_BASE_ADDR; + + /* reset */ + mxs_reset_block(®s->pxp_ctrl_reg); + + /* output buffer */ + if (pxp_conf->out_param.pixel_fmt == FMT_RGB888) + writel(BV_PXP_OUT_CTRL_FORMAT__RGB888, ®s->pxp_out_ctrl); + else + writel(BV_PXP_OUT_CTRL_FORMAT__RGB565, ®s->pxp_out_ctrl); + + writel((u32)pxp_conf->out_param.paddr, ®s->pxp_out_buf); + + writel(pxp_conf->out_param.stride, ®s->pxp_out_pitch); + writel((pxp_conf->out_param.width - 1) << 16 | + (pxp_conf->out_param.height - 1), + ®s->pxp_out_lrc); + + /* scale needed */ + writel(0, ®s->pxp_out_ps_ulc); + writel((pxp_conf->out_param.width - 1) << 16 | + (pxp_conf->out_param.height - 1), + ®s->pxp_out_ps_lrc); + pxp_set_scaling(pxp_conf); + + writel(0, ®s->pxp_out_as_ulc); + writel(0, ®s->pxp_out_as_lrc); + + /* input buffer */ + if (pxp_conf->s0_param.pixel_fmt == FMT_YUV444) + writel(BV_PXP_PS_CTRL_FORMAT__YUV1P444, ®s->pxp_ps_ctrl); + else if (pxp_conf->s0_param.pixel_fmt == FMT_YUYV) + writel(BV_PXP_PS_CTRL_FORMAT__UYVY1P422 | BF_PXP_PS_CTRL_SWAP(1), + ®s->pxp_ps_ctrl); + else if (pxp_conf->s0_param.pixel_fmt == FMT_UYVY) + writel(BV_PXP_PS_CTRL_FORMAT__UYVY1P422, ®s->pxp_ps_ctrl); + else + printf("%s, unsupport fmt\n", __func__); + + writel((u32)pxp_conf->s0_param.paddr, ®s->pxp_ps_buf); + writel(pxp_conf->s0_param.stride, ®s->pxp_ps_pitch); + writel(0, ®s->pxp_ps_background); + writel(0x84ab01f0, ®s->pxp_csc1_coef0); + writel(0x01980204, ®s->pxp_csc1_coef1); + writel(0x0730079c, ®s->pxp_csc1_coef2); + + /* pxp start */ + writel(BM_PXP_CTRL_IRQ_ENABLE | BM_PXP_CTRL_ENABLE, ®s->pxp_ctrl); +} |