| /* SPDX-License-Identifier: GPL-2.0+ */ |
| /* |
| * Copyright (C) 2014 Freescale Semiconductor, Inc. All Rights Reserved. |
| * |
| */ |
| |
| #include <common.h> |
| |
| #include <asm/arch/imx-regs.h> |
| #include <asm/arch/sys_proto.h> |
| #include <linux/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; |
| break; |
| 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); |
| } |