blob: 41cedfc98cae9db1e350b25fe13fcbd33240be70 [file] [log] [blame]
/* 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, &regs->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, &regs->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), &regs->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, &regs->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 , &regs->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(&regs->pxp_ctrl_reg);
/* output buffer */
if (pxp_conf->out_param.pixel_fmt == FMT_RGB888)
writel(BV_PXP_OUT_CTRL_FORMAT__RGB888, &regs->pxp_out_ctrl);
else
writel(BV_PXP_OUT_CTRL_FORMAT__RGB565, &regs->pxp_out_ctrl);
writel((u32)pxp_conf->out_param.paddr, &regs->pxp_out_buf);
writel(pxp_conf->out_param.stride, &regs->pxp_out_pitch);
writel((pxp_conf->out_param.width - 1) << 16 |
(pxp_conf->out_param.height - 1),
&regs->pxp_out_lrc);
/* scale needed */
writel(0, &regs->pxp_out_ps_ulc);
writel((pxp_conf->out_param.width - 1) << 16 |
(pxp_conf->out_param.height - 1),
&regs->pxp_out_ps_lrc);
pxp_set_scaling(pxp_conf);
writel(0, &regs->pxp_out_as_ulc);
writel(0, &regs->pxp_out_as_lrc);
/* input buffer */
if (pxp_conf->s0_param.pixel_fmt == FMT_YUV444)
writel(BV_PXP_PS_CTRL_FORMAT__YUV1P444, &regs->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),
&regs->pxp_ps_ctrl);
else if (pxp_conf->s0_param.pixel_fmt == FMT_UYVY)
writel(BV_PXP_PS_CTRL_FORMAT__UYVY1P422, &regs->pxp_ps_ctrl);
else
printf("%s, unsupport fmt\n", __func__);
writel((u32)pxp_conf->s0_param.paddr, &regs->pxp_ps_buf);
writel(pxp_conf->s0_param.stride, &regs->pxp_ps_pitch);
writel(0, &regs->pxp_ps_background);
writel(0x84ab01f0, &regs->pxp_csc1_coef0);
writel(0x01980204, &regs->pxp_csc1_coef1);
writel(0x0730079c, &regs->pxp_csc1_coef2);
/* pxp start */
writel(BM_PXP_CTRL_IRQ_ENABLE | BM_PXP_CTRL_ENABLE, &regs->pxp_ctrl);
}