kernel_samsung_a34x-permissive/drivers/gpu/drm/mediatek/mtk_disp_wdma.c
2024-04-28 15:49:01 +02:00

1684 lines
53 KiB
C
Executable file

/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include <drm/drmP.h>
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
#include "mtk_drm_crtc.h"
#include "mtk_drm_ddp_comp.h"
#include "mtk_dump.h"
#include "mtk_drm_mmp.h"
#include "mtk_drm_gem.h"
#include "mtk_drm_fb.h"
#include "mtk_drm_trace.h"
#include "mtk_drm_drv.h"
#include "cmdq-sec.h"
#define DISP_REG_WDMA_INTEN 0x0000
#define INTEN_FLD_FME_CPL_INTEN REG_FLD_MSB_LSB(0, 0)
#define INTEN_FLD_FME_UND_INTEN REG_FLD_MSB_LSB(1, 1)
#define DISP_REG_WDMA_INTSTA 0x0004
#define DISP_REG_WDMA_EN 0x0008
#define WDMA_EN BIT(0)
#define DISP_REG_WDMA_RST 0x000c
#define DISP_REG_WDMA_SMI_CON 0x0010
#define SMI_CON_FLD_THRESHOLD REG_FLD_MSB_LSB(3, 0)
#define SMI_CON_FLD_SLOW_ENABLE REG_FLD_MSB_LSB(4, 4)
#define SMI_CON_FLD_SLOW_LEVEL REG_FLD_MSB_LSB(7, 5)
#define SMI_CON_FLD_SLOW_COUNT REG_FLD_MSB_LSB(15, 8)
#define SMI_CON_FLD_SMI_Y_REPEAT_NUM REG_FLD_MSB_LSB(19, 16)
#define SMI_CON_FLD_SMI_U_REPEAT_NUM REG_FLD_MSB_LSB(23, 20)
#define SMI_CON_FLD_SMI_V_REPEAT_NUM REG_FLD_MSB_LSB(27, 24)
#define SMI_CON_FLD_SMI_OBUF_FULL_REQ REG_FLD_MSB_LSB(28, 28)
#define DISP_REG_WDMA_CFG 0x0014
#define CFG_FLD_UFO_DCP_ENABLE REG_FLD_MSB_LSB(18, 18)
#define WDMA_OUT_FMT (0xf << 4)
#define WDMA_CT_EN BIT(11)
#define WDMA_CON_SWAP BIT(16)
#define WDMA_UFO_DCP_ENABLE BIT(18)
#define WDMA_INT_MTX_SEL (0xf << 24)
#define DISP_REG_WDMA_SRC_SIZE 0x0018
#define DISP_REG_WDMA_CLIP_SIZE 0x001c
#define DISP_REG_WDMA_CLIP_COORD 0x0020
#define DISP_REG_WDMA_SHADOW_CTRL 0x0024
#define WDMA_BYPASS_SHADOW BIT(1)
#define WDMA_READ_WRK_REG BIT(2)
#define DISP_REG_WDMA_DST_WIN_BYTE 0x0028
#define DISP_REG_WDMA_ALPHA 0x002C
#define DISP_REG_WDMA_DST_UV_PITCH 0x0078
#define DISP_REG_WDMA_DST_ADDR_OFFSET0 0x0080
#define DISP_REG_WDMA_DST_ADDR_OFFSET1 0x0084
#define DISP_REG_WDMA_DST_ADDR_OFFSET2 0x0088
#define DISP_REG_WDMA_FLOW_CTRL_DBG 0x00A0
#define FLOW_CTRL_DBG_FLD_WDMA_STA_FLOW_CTRL REG_FLD_MSB_LSB(9, 0)
#define FLOW_CTRL_DBG_FLD_WDMA_IN_READY REG_FLD_MSB_LSB(14, 14)
#define FLOW_CTRL_DBG_FLD_WDMA_IN_VALID REG_FLD_MSB_LSB(15, 15)
#define DISP_REG_WDMA_EXEC_DBG 0x000A4
#define EXEC_DBG_FLD_WDMA_STA_EXEC REG_FLD_MSB_LSB(31, 0)
#define DISP_REG_WDMA_INPUT_CNT_DBG 0x000A8
#define DISP_REG_WDMA_DEBUG 0x000B8
#define DISP_REG_WDMA_BUF_CON3 0x0104
#define BUF_CON3_FLD_ISSUE_REQ_TH_Y REG_FLD_MSB_LSB(8, 0)
#define BUF_CON3_FLD_ISSUE_REQ_TH_U REG_FLD_MSB_LSB(24, 16)
#define DISP_REG_WDMA_BUF_CON4 0x0108
#define BUF_CON4_FLD_ISSUE_REQ_TH_V REG_FLD_MSB_LSB(8, 0)
#define DISP_REG_WDMA_BUF_CON1 0x0038
#define BUF_CON1_FLD_FIFO_PSEUDO_SIZE REG_FLD_MSB_LSB(9, 0)
#define BUF_CON1_FLD_FIFO_PSEUDO_SIZE_UV REG_FLD_MSB_LSB(18, 10)
#define BUF_CON1_FLD_URGENT_EN REG_FLD_MSB_LSB(26, 26)
#define BUF_CON1_FLD_ALPHA_MASK_EN REG_FLD_MSB_LSB(27, 27)
#define BUF_CON1_FLD_FRAME_END_ULTRA REG_FLD_MSB_LSB(28, 28)
#define BUF_CON1_FLD_GCLAST_EN REG_FLD_MSB_LSB(29, 29)
#define BUF_CON1_FLD_PRE_ULTRA_ENABLE REG_FLD_MSB_LSB(30, 30)
#define BUF_CON1_FLD_ULTRA_ENABLE REG_FLD_MSB_LSB(31, 31)
#define DISP_REG_WDMA_BUF_CON5 0x0200
#define DISP_REG_WDMA_BUF_CON6 0x0204
#define DISP_REG_WDMA_BUF_CON7 0x0208
#define DISP_REG_WDMA_BUF_CON8 0x020C
#define DISP_REG_WDMA_BUF_CON9 0x0210
#define DISP_REG_WDMA_BUF_CON10 0x0214
#define DISP_REG_WDMA_BUF_CON11 0x0218
#define DISP_REG_WDMA_BUF_CON12 0x021C
#define DISP_REG_WDMA_BUF_CON13 0x0220
#define DISP_REG_WDMA_BUF_CON14 0x0224
#define DISP_REG_WDMA_BUF_CON15 0x0228
#define BUF_CON_FLD_PRE_ULTRA_LOW REG_FLD_MSB_LSB(9, 0)
#define BUF_CON_FLD_ULTRA_LOW REG_FLD_MSB_LSB(25, 16)
#define DISP_REG_WDMA_BUF_CON16 0x022C
#define BUF_CON_FLD_PRE_ULTRA_HIGH REG_FLD_MSB_LSB(9, 0)
#define BUF_CON_FLD_ULTRA_HIGH REG_FLD_MSB_LSB(25, 16)
#define DISP_REG_WDMA_BUF_CON17 0x0230
#define BUF_CON17_FLD_WDMA_DVFS_EN REG_FLD_MSB_LSB(0, 0)
#define BUF_CON17_FLD_DVFS_TH_Y REG_FLD_MSB_LSB(25, 16)
#define DISP_REG_WDMA_BUF_CON18 0x0234
#define BUF_CON18_FLD_DVFS_TH_U REG_FLD_MSB_LSB(9, 0)
#define BUF_CON18_FLD_DVFS_TH_V REG_FLD_MSB_LSB(25, 16)
#define DISP_REG_WDMA_DRS_CON0 0x0250
#define DISP_REG_WDMA_DRS_CON1 0x0254
#define DISP_REG_WDMA_DRS_CON2 0x0258
#define DISP_REG_WDMA_DRS_CON3 0x025C
#define DISP_REG_WDMA_URGENT_CON0 0x0260
#define FLD_WDMA_URGENT_LOW_Y REG_FLD_MSB_LSB(9, 0)
#define FLD_WDMA_URGENT_HIGH_Y REG_FLD_MSB_LSB(25, 16)
#define DISP_REG_WDMA_URGENT_CON1 0x0264
#define FLD_WDMA_URGENT_LOW_U REG_FLD_MSB_LSB(9, 0)
#define FLD_WDMA_URGENT_HIGH_U REG_FLD_MSB_LSB(25, 16)
#define DISP_REG_WDMA_URGENT_CON2 0x0268
#define FLD_WDMA_URGENT_LOW_V REG_FLD_MSB_LSB(9, 0)
#define FLD_WDMA_URGENT_HIGH_V REG_FLD_MSB_LSB(25, 16)
#define DISP_REG_WDMA_DST_ADDR0 0x0f00
#define DISP_REG_WDMA_DST_ADDR1 0x0f04
#define DISP_REG_WDMA_DST_ADDR2 0x0f08
#define DISP_REG_WDMA_RGB888 0x10
#define MEM_MODE_INPUT_FORMAT_RGB565 0x0U
#define MEM_MODE_INPUT_FORMAT_RGB888 (0x001U << 4)
#define MEM_MODE_INPUT_FORMAT_RGBA8888 (0x002U << 4)
#define MEM_MODE_INPUT_FORMAT_ARGB8888 (0x003U << 4)
#define MEM_MODE_INPUT_FORMAT_UYVY (0x004U << 4)
#define MEM_MODE_INPUT_FORMAT_YUYV (0x005U << 4)
#define MEM_MODE_INPUT_FORMAT_IYUV (0x008U << 4)
#define MEM_MODE_INPUT_SWAP BIT(16)
enum GS_WDMA_FLD {
GS_WDMA_SMI_CON = 0, /* whole reg */
GS_WDMA_BUF_CON1, /* whole reg */
GS_WDMA_PRE_ULTRA_LOW_Y,
GS_WDMA_ULTRA_LOW_Y,
GS_WDMA_PRE_ULTRA_HIGH_Y,
GS_WDMA_ULTRA_HIGH_Y,
GS_WDMA_PRE_ULTRA_LOW_U,
GS_WDMA_ULTRA_LOW_U,
GS_WDMA_PRE_ULTRA_HIGH_U,
GS_WDMA_ULTRA_HIGH_U,
GS_WDMA_PRE_ULTRA_LOW_V,
GS_WDMA_ULTRA_LOW_V,
GS_WDMA_PRE_ULTRA_HIGH_V,
GS_WDMA_ULTRA_HIGH_V,
GS_WDMA_PRE_ULTRA_LOW_Y_DVFS,
GS_WDMA_ULTRA_LOW_Y_DVFS,
GS_WDMA_PRE_ULTRA_HIGH_Y_DVFS,
GS_WDMA_ULTRA_HIGH_Y_DVFS,
GS_WDMA_PRE_ULTRA_LOW_U_DVFS,
GS_WDMA_ULTRA_LOW_U_DVFS,
GS_WDMA_PRE_ULTRA_HIGH_U_DVFS,
GS_WDMA_ULTRA_HIGH_U_DVFS,
GS_WDMA_PRE_ULTRA_LOW_V_DVFS,
GS_WDMA_ULTRA_LOW_V_DVFS,
GS_WDMA_PRE_ULTRA_HIGH_V_DVFS,
GS_WDMA_ULTRA_HIGH_V_DVFS,
GS_WDMA_DVFS_EN,
GS_WDMA_DVFS_TH_Y,
GS_WDMA_DVFS_TH_U,
GS_WDMA_DVFS_TH_V,
GS_WDMA_URGENT_LOW_Y,
GS_WDMA_URGENT_HIGH_Y,
GS_WDMA_URGENT_LOW_U,
GS_WDMA_URGENT_HIGH_U,
GS_WDMA_URGENT_LOW_V,
GS_WDMA_URGENT_HIGH_V,
GS_WDMA_ISSUE_REG_TH_Y,
GS_WDMA_ISSUE_REG_TH_U,
GS_WDMA_ISSUE_REG_TH_V,
GS_WDMA_FLD_NUM,
};
struct mtk_disp_wdma_data {
void (*sodi_config)(struct drm_device *drm, enum mtk_ddp_comp_id id,
struct cmdq_pkt *handle, void *data);
bool support_shadow;
};
struct mtk_wdma_cfg_info {
unsigned int addr;
unsigned int width;
unsigned int height;
unsigned int fmt;
};
/**
* struct mtk_disp_wdma - DISP_RDMA driver structure
* @ddp_comp - structure containing type enum and hardware resources
* @crtc - associated crtc to report irq events to
*/
struct mtk_disp_wdma {
struct mtk_ddp_comp ddp_comp;
const struct mtk_disp_wdma_data *data;
struct mtk_wdma_cfg_info cfg_info;
};
static irqreturn_t mtk_wdma_irq_handler(int irq, void *dev_id)
{
struct mtk_disp_wdma *priv = dev_id;
struct mtk_ddp_comp *wdma = &priv->ddp_comp;
struct mtk_cwb_info *cwb_info;
struct mtk_drm_private *drm_priv;
unsigned int buf_idx;
unsigned int val = 0;
unsigned int ret = 0;
if (mtk_drm_top_clk_isr_get("wdma_irq") == false) {
DDPIRQ("%s, top clk off\n", __func__);
return IRQ_NONE;
}
val = readl(wdma->regs + DISP_REG_WDMA_INTSTA);
if (!val) {
ret = IRQ_NONE;
goto out;
}
DRM_MMP_MARK(IRQ, irq, val);
if (wdma->id == DDP_COMPONENT_WDMA0)
DRM_MMP_MARK(wdma0, val, 0);
if (val & 0x2)
DRM_MMP_MARK(abnormal_irq, val, wdma->id);
DDPIRQ("%s irq, val:0x%x\n", mtk_dump_comp_str(wdma), val);
writel(~val, wdma->regs + DISP_REG_WDMA_INTSTA);
if (val & (1 << 0)) {
struct mtk_drm_crtc *mtk_crtc = wdma->mtk_crtc;
DDPIRQ("[IRQ] %s: frame complete!\n",
mtk_dump_comp_str(wdma));
drm_priv = mtk_crtc->base.dev->dev_private;
cwb_info = mtk_crtc->cwb_info;
if (cwb_info && cwb_info->enable &&
cwb_info->comp->id == wdma->id &&
!drm_priv->cwb_is_preempted) {
buf_idx = cwb_info->buf_idx;
cwb_info->buffer[buf_idx].timestamp = 100;
atomic_set(&mtk_crtc->cwb_task_active, 1);
wake_up_interruptible(&mtk_crtc->cwb_wq);
}
if (mtk_crtc->dc_main_path_commit_task) {
atomic_set(
&mtk_crtc->dc_main_path_commit_event, 1);
wake_up_interruptible(
&mtk_crtc->dc_main_path_commit_wq);
}
MMPathTraceDRM(wdma);
}
if (val & (1 << 1))
DDPPR_ERR("[IRQ] %s: frame underrun!\n",
mtk_dump_comp_str(wdma));
ret = IRQ_HANDLED;
out:
mtk_drm_top_clk_isr_put("wdma_irq");
return ret;
}
static inline struct mtk_disp_wdma *comp_to_wdma(struct mtk_ddp_comp *comp)
{
return container_of(comp, struct mtk_disp_wdma, ddp_comp);
}
static void mtk_wdma_start(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle)
{
struct mtk_disp_wdma *wdma = comp_to_wdma(comp);
const struct mtk_disp_wdma_data *data = wdma->data;
unsigned int inten;
bool en = 1;
inten = REG_FLD_VAL(INTEN_FLD_FME_CPL_INTEN, 1) |
REG_FLD_VAL(INTEN_FLD_FME_UND_INTEN, 1);
mtk_ddp_write(comp, WDMA_EN, DISP_REG_WDMA_EN, handle);
mtk_ddp_write(comp, inten, DISP_REG_WDMA_INTEN, handle);
if (data && data->sodi_config)
data->sodi_config(comp->mtk_crtc->base.dev, comp->id, handle,
&en);
}
static void mtk_wdma_stop(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle)
{
struct mtk_disp_wdma *wdma = comp_to_wdma(comp);
const struct mtk_disp_wdma_data *data = wdma->data;
bool en = 0;
mtk_ddp_write(comp, 0x0, DISP_REG_WDMA_INTEN, handle);
mtk_ddp_write(comp, 0x0, DISP_REG_WDMA_EN, handle);
mtk_ddp_write(comp, 0x0, DISP_REG_WDMA_INTSTA, handle);
if (data && data->sodi_config)
data->sodi_config(comp->mtk_crtc->base.dev,
comp->id, handle, &en);
mtk_ddp_write(comp, 0x01, DISP_REG_WDMA_RST, handle);
mtk_ddp_write(comp, 0x00, DISP_REG_WDMA_RST, handle);
}
static int mtk_wdma_is_busy(struct mtk_ddp_comp *comp)
{
int ret, tmp;
tmp = readl(comp->regs + DISP_REG_WDMA_FLOW_CTRL_DBG);
ret = ((tmp & REG_FLD_MASK(FLOW_CTRL_DBG_FLD_WDMA_STA_FLOW_CTRL)) != 0x1) ? 1 : 0;
DDPINFO("%s:%d is:%d regs:0x%x\n", __func__, __LINE__, ret, tmp);
return ret;
}
static void mtk_wdma_prepare(struct mtk_ddp_comp *comp)
{
#if defined(CONFIG_DRM_MTK_SHADOW_REGISTER_SUPPORT)
struct mtk_disp_wdma *wdma = comp_to_wdma(comp);
#endif
mtk_ddp_comp_clk_prepare(comp);
#if defined(CONFIG_DRM_MTK_SHADOW_REGISTER_SUPPORT)
if (wdma->data->support_shadow) {
/* Enable shadow register and read shadow register */
mtk_ddp_write_mask_cpu(comp, 0x0,
DISP_REG_WDMA_SHADOW_CTRL, WDMA_BYPASS_SHADOW);
} else {
/* Bypass shadow register and read shadow register */
mtk_ddp_write_mask_cpu(comp, WDMA_BYPASS_SHADOW,
DISP_REG_WDMA_SHADOW_CTRL, WDMA_BYPASS_SHADOW);
}
#else
#if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \
|| defined(CONFIG_MACH_MT6833) \
|| defined(CONFIG_MACH_MT6877) \
|| defined(CONFIG_MACH_MT6781)
/* Bypass shadow register and read shadow register */
mtk_ddp_write_mask_cpu(comp, WDMA_BYPASS_SHADOW,
DISP_REG_WDMA_SHADOW_CTRL, WDMA_BYPASS_SHADOW);
#endif
#endif
}
static void mtk_wdma_unprepare(struct mtk_ddp_comp *comp)
{
mtk_ddp_comp_clk_unprepare(comp);
}
static void mtk_wdma_calc_golden_setting(struct golden_setting_context *gsc,
unsigned int format,
unsigned int is_primary_flag,
unsigned int *gs)
{
unsigned int preultra_low_us = 7, preultra_high_us = 6;
unsigned int ultra_low_us = 6, ultra_high_us = 4;
unsigned int dvfs_offset = 2;
unsigned int urgent_low_offset = 4, urgent_high_offset = 3;
unsigned int Bpp = 3;
unsigned int FP = 100;
unsigned int res = 0;
unsigned int frame_rate = 0;
unsigned long long consume_rate = 0;
#if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6893)
unsigned int fifo_size = 325;
unsigned int fifo_size_uv = 31;
#endif
#if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \
|| defined(CONFIG_MACH_MT6833) \
|| defined(CONFIG_MACH_MT6877)
unsigned int fifo_size = 578;
unsigned int fifo_size_uv = 29;
#endif
#if defined(CONFIG_MACH_MT6781)
unsigned int fifo_size = 410;
unsigned int fifo_size_uv = 200;
#endif
unsigned int fifo;
unsigned int factor1 = 4;
unsigned int factor2 = 4;
unsigned int tmp;
frame_rate = 60;
res = gsc->dst_width * gsc->dst_height;
consume_rate = res * frame_rate;
do_div(consume_rate, 1000);
consume_rate *= 125; /* PF = 100 */
do_div(consume_rate, 16 * 1000);
/* WDMA_SMI_CON */
if (format == DRM_FORMAT_YVU420 || format == DRM_FORMAT_YUV420)
gs[GS_WDMA_SMI_CON] = 0x11140007;
else
gs[GS_WDMA_SMI_CON] = 0x12240007;
/* WDMA_BUF_CON1 */
if (!gsc->is_dc)
gs[GS_WDMA_BUF_CON1] = 0xD4000000;
else
gs[GS_WDMA_BUF_CON1] = 0x40000000;
switch (format) {
case DRM_FORMAT_YVU420:
case DRM_FORMAT_YUV420:
/* 3 plane */
#if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6893)
fifo_size = 228;
fifo_size_uv = 50;
#endif
#if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \
|| defined(CONFIG_MACH_MT6833) || defined(CONFIG_MACH_MT6877) \
|| defined(CONFIG_MACH_MT6781)
fifo_size = 402;
fifo_size_uv = 99;
#endif
fifo = fifo_size_uv;
factor1 = 4;
factor2 = 4;
Bpp = 1;
break;
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
/* 2 plane */
#if defined(CONFIG_MACH_MT6885) || defined(CONFIG_MACH_MT6893)
fifo_size = 228;
fifo_size_uv = 109;
#endif
#if defined(CONFIG_MACH_MT6873) || defined(CONFIG_MACH_MT6853) \
|| defined(CONFIG_MACH_MT6833) || defined(CONFIG_MACH_MT6877) \
|| defined(CONFIG_MACH_MT6781)
fifo_size = 402;
fifo_size_uv = 201;
#endif
fifo = fifo_size_uv;
factor1 = 2;
factor2 = 4;
Bpp = 1;
break;
default:
/* 1 plane */
/* fifo_size keep default */
/* Bpp keep default */
factor1 = 4;
factor2 = 4;
fifo = fifo_size / 4;
break;
}
gs[GS_WDMA_BUF_CON1] += (fifo_size_uv << 10) + fifo_size;
#if BITS_PER_LONG == 64
/* WDMA_BUF_CON5 */
tmp = DIV_ROUND_UP(consume_rate * Bpp * preultra_low_us, FP);
gs[GS_WDMA_PRE_ULTRA_LOW_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * Bpp * ultra_low_us, FP);
gs[GS_WDMA_ULTRA_LOW_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA_BUF_CON6 */
tmp = DIV_ROUND_UP(consume_rate * Bpp * preultra_high_us, FP);
gs[GS_WDMA_PRE_ULTRA_HIGH_Y] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * Bpp * ultra_high_us, FP);
gs[GS_WDMA_ULTRA_HIGH_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA_BUF_CON7 */
tmp = DIV_ROUND_UP(consume_rate * preultra_low_us, FP * factor1);
gs[GS_WDMA_PRE_ULTRA_LOW_U] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * ultra_low_us, FP * factor1);
gs[GS_WDMA_ULTRA_LOW_U] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON8 */
tmp = DIV_ROUND_UP(consume_rate * preultra_high_us, FP * factor1);
gs[GS_WDMA_PRE_ULTRA_HIGH_U] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * ultra_high_us, FP * factor1);
gs[GS_WDMA_ULTRA_HIGH_U] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON9 */
tmp = DIV_ROUND_UP(consume_rate * preultra_low_us, FP * factor2);
gs[GS_WDMA_PRE_ULTRA_LOW_V] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * ultra_low_us, FP * factor2);
gs[GS_WDMA_ULTRA_LOW_V] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON10 */
tmp = DIV_ROUND_UP(consume_rate * preultra_high_us, FP * factor2);
gs[GS_WDMA_PRE_ULTRA_HIGH_V] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * ultra_high_us, FP * factor2);
gs[GS_WDMA_ULTRA_HIGH_V] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON11 */
tmp = DIV_ROUND_UP(consume_rate * Bpp * (preultra_low_us + dvfs_offset),
FP);
gs[GS_WDMA_PRE_ULTRA_LOW_Y_DVFS] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * Bpp * (ultra_low_us + dvfs_offset),
FP);
gs[GS_WDMA_ULTRA_LOW_Y_DVFS] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA_BUF_CON12 */
tmp = DIV_ROUND_UP(
consume_rate * Bpp * (preultra_high_us + dvfs_offset), FP);
gs[GS_WDMA_PRE_ULTRA_HIGH_Y_DVFS] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * Bpp * (ultra_high_us + dvfs_offset),
FP);
gs[GS_WDMA_ULTRA_HIGH_Y_DVFS] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA_BUF_CON13 */
tmp = DIV_ROUND_UP(consume_rate * (preultra_low_us + dvfs_offset),
FP * factor1);
gs[GS_WDMA_PRE_ULTRA_LOW_U_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * (ultra_low_us + dvfs_offset),
FP * factor1);
gs[GS_WDMA_ULTRA_LOW_U_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON14 */
tmp = DIV_ROUND_UP(consume_rate * (preultra_high_us + dvfs_offset),
FP * factor1);
gs[GS_WDMA_PRE_ULTRA_HIGH_U_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * (ultra_high_us + dvfs_offset),
FP * factor1);
gs[GS_WDMA_ULTRA_HIGH_U_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON15 */
tmp = DIV_ROUND_UP(consume_rate * (preultra_low_us + dvfs_offset),
FP * factor2);
gs[GS_WDMA_PRE_ULTRA_LOW_V_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * (ultra_low_us + dvfs_offset),
FP * factor2);
gs[GS_WDMA_ULTRA_LOW_V_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON16 */
tmp = DIV_ROUND_UP(consume_rate * (preultra_high_us + dvfs_offset),
FP * factor2);
gs[GS_WDMA_PRE_ULTRA_HIGH_V_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * (ultra_high_us + dvfs_offset),
FP * factor2);
gs[GS_WDMA_ULTRA_HIGH_V_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON17 */
gs[GS_WDMA_DVFS_EN] = 1;
gs[GS_WDMA_DVFS_TH_Y] = gs[GS_WDMA_ULTRA_HIGH_Y_DVFS];
/* WDMA_BUF_CON18 */
gs[GS_WDMA_DVFS_TH_U] = gs[GS_WDMA_ULTRA_HIGH_U_DVFS];
gs[GS_WDMA_DVFS_TH_V] = gs[GS_WDMA_ULTRA_HIGH_V_DVFS];
/* WDMA URGENT CONTROL 0 */
tmp = DIV_ROUND_UP(consume_rate * Bpp * urgent_low_offset, FP);
gs[GS_WDMA_URGENT_LOW_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * Bpp * urgent_high_offset, FP);
gs[GS_WDMA_URGENT_HIGH_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA URGENT CONTROL 1 */
tmp = DIV_ROUND_UP(consume_rate * urgent_low_offset, FP * factor1);
gs[GS_WDMA_URGENT_LOW_U] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * urgent_high_offset, FP * factor1);
gs[GS_WDMA_URGENT_HIGH_U] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA URGENT CONTROL 2 */
tmp = DIV_ROUND_UP(consume_rate * urgent_low_offset, FP * factor2);
gs[GS_WDMA_URGENT_LOW_V] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV_ROUND_UP(consume_rate * urgent_high_offset, FP * factor2);
gs[GS_WDMA_URGENT_HIGH_V] = (fifo > tmp) ? (fifo - tmp) : 1;
#elif BITS_PER_LONG == 32
/* WDMA_BUF_CON5 */
tmp = DIV64_U64_ROUND_UP(consume_rate * Bpp * preultra_low_us, FP);
gs[GS_WDMA_PRE_ULTRA_LOW_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * Bpp * ultra_low_us, FP);
gs[GS_WDMA_ULTRA_LOW_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA_BUF_CON6 */
tmp = DIV64_U64_ROUND_UP(consume_rate * Bpp * preultra_high_us, FP);
gs[GS_WDMA_PRE_ULTRA_HIGH_Y] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * Bpp * ultra_high_us, FP);
gs[GS_WDMA_ULTRA_HIGH_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA_BUF_CON7 */
tmp = DIV64_U64_ROUND_UP(consume_rate * preultra_low_us, FP * factor1);
gs[GS_WDMA_PRE_ULTRA_LOW_U] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * ultra_low_us, FP * factor1);
gs[GS_WDMA_ULTRA_LOW_U] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON8 */
tmp = DIV64_U64_ROUND_UP(consume_rate * preultra_high_us, FP * factor1);
gs[GS_WDMA_PRE_ULTRA_HIGH_U] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * ultra_high_us, FP * factor1);
gs[GS_WDMA_ULTRA_HIGH_U] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON9 */
tmp = DIV64_U64_ROUND_UP(consume_rate * preultra_low_us, FP * factor2);
gs[GS_WDMA_PRE_ULTRA_LOW_V] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * ultra_low_us, FP * factor2);
gs[GS_WDMA_ULTRA_LOW_V] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON10 */
tmp = DIV64_U64_ROUND_UP(consume_rate * preultra_high_us, FP * factor2);
gs[GS_WDMA_PRE_ULTRA_HIGH_V] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * ultra_high_us, FP * factor2);
gs[GS_WDMA_ULTRA_HIGH_V] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON11 */
tmp = DIV64_U64_ROUND_UP(consume_rate * Bpp * (preultra_low_us + dvfs_offset),
FP);
gs[GS_WDMA_PRE_ULTRA_LOW_Y_DVFS] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * Bpp * (ultra_low_us + dvfs_offset),
FP);
gs[GS_WDMA_ULTRA_LOW_Y_DVFS] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA_BUF_CON12 */
tmp = DIV64_U64_ROUND_UP(
consume_rate * Bpp * (preultra_high_us + dvfs_offset), FP);
gs[GS_WDMA_PRE_ULTRA_HIGH_Y_DVFS] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * Bpp * (ultra_high_us + dvfs_offset),
FP);
gs[GS_WDMA_ULTRA_HIGH_Y_DVFS] =
(fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA_BUF_CON13 */
tmp = DIV64_U64_ROUND_UP(consume_rate * (preultra_low_us + dvfs_offset),
FP * factor1);
gs[GS_WDMA_PRE_ULTRA_LOW_U_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * (ultra_low_us + dvfs_offset),
FP * factor1);
gs[GS_WDMA_ULTRA_LOW_U_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON14 */
tmp = DIV64_U64_ROUND_UP(consume_rate * (preultra_high_us + dvfs_offset),
FP * factor1);
gs[GS_WDMA_PRE_ULTRA_HIGH_U_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * (ultra_high_us + dvfs_offset),
FP * factor1);
gs[GS_WDMA_ULTRA_HIGH_U_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON15 */
tmp = DIV64_U64_ROUND_UP(consume_rate * (preultra_low_us + dvfs_offset),
FP * factor2);
gs[GS_WDMA_PRE_ULTRA_LOW_V_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * (ultra_low_us + dvfs_offset),
FP * factor2);
gs[GS_WDMA_ULTRA_LOW_V_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON16 */
tmp = DIV64_U64_ROUND_UP(consume_rate * (preultra_high_us + dvfs_offset),
FP * factor2);
gs[GS_WDMA_PRE_ULTRA_HIGH_V_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * (ultra_high_us + dvfs_offset),
FP * factor2);
gs[GS_WDMA_ULTRA_HIGH_V_DVFS] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA_BUF_CON17 */
gs[GS_WDMA_DVFS_EN] = 1;
gs[GS_WDMA_DVFS_TH_Y] = gs[GS_WDMA_ULTRA_HIGH_Y_DVFS];
/* WDMA_BUF_CON18 */
gs[GS_WDMA_DVFS_TH_U] = gs[GS_WDMA_ULTRA_HIGH_U_DVFS];
gs[GS_WDMA_DVFS_TH_V] = gs[GS_WDMA_ULTRA_HIGH_V_DVFS];
/* WDMA URGENT CONTROL 0 */
tmp = DIV64_U64_ROUND_UP(consume_rate * Bpp * urgent_low_offset, FP);
gs[GS_WDMA_URGENT_LOW_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * Bpp * urgent_high_offset, FP);
gs[GS_WDMA_URGENT_HIGH_Y] = (fifo_size > tmp) ? (fifo_size - tmp) : 1;
/* WDMA URGENT CONTROL 1 */
tmp = DIV64_U64_ROUND_UP(consume_rate * urgent_low_offset, FP * factor1);
gs[GS_WDMA_URGENT_LOW_U] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * urgent_high_offset, FP * factor1);
gs[GS_WDMA_URGENT_HIGH_U] = (fifo > tmp) ? (fifo - tmp) : 1;
/* WDMA URGENT CONTROL 2 */
tmp = DIV64_U64_ROUND_UP(consume_rate * urgent_low_offset, FP * factor2);
gs[GS_WDMA_URGENT_LOW_V] = (fifo > tmp) ? (fifo - tmp) : 1;
tmp = DIV64_U64_ROUND_UP(consume_rate * urgent_high_offset, FP * factor2);
gs[GS_WDMA_URGENT_HIGH_V] = (fifo > tmp) ? (fifo - tmp) : 1;
#else
#error "check for api use for this architeacture"
#endif
/* WDMA Buf Constant 3 */
gs[GS_WDMA_ISSUE_REG_TH_Y] = 16;
gs[GS_WDMA_ISSUE_REG_TH_U] = 16;
/* WDMA Buf Constant 4 */
gs[GS_WDMA_ISSUE_REG_TH_V] = 16;
}
static void mtk_wdma_golden_setting(struct mtk_ddp_comp *comp,
struct golden_setting_context *gsc,
struct cmdq_pkt *handle)
{
unsigned int gs[GS_WDMA_FLD_NUM];
unsigned int value = 0;
if (!gsc) {
DDPPR_ERR("golden setting is null, %s,%d\n", __FILE__,
__LINE__);
return;
}
mtk_wdma_calc_golden_setting(gsc, comp->fb->format->format, true, gs);
#if 0
mtk_ddp_write(comp, 0x800000ff, 0x2C, handle);
mtk_ddp_write(comp, 0xd4000529, 0x38, handle);
mtk_ddp_write(comp, 0x00640043, 0x200, handle);
mtk_ddp_write(comp, 0x00a50064, 0x204, handle);
mtk_ddp_write(comp, 0x00390036, 0x208, handle);
mtk_ddp_write(comp, 0x003f0039, 0x20C, handle);
mtk_ddp_write(comp, 0x00390036, 0x210, handle);
mtk_ddp_write(comp, 0x003f0039, 0x214, handle);
mtk_ddp_write(comp, 0x00220001, 0x218, handle);
mtk_ddp_write(comp, 0x00640022, 0x21C, handle);
mtk_ddp_write(comp, 0x00340031, 0x220, handle);
mtk_ddp_write(comp, 0x00390034, 0x224, handle);
mtk_ddp_write(comp, 0x00340031, 0x228, handle);
mtk_ddp_write(comp, 0x00390034, 0x22C, handle);
mtk_ddp_write(comp, 0x00640001, 0x230, handle);
mtk_ddp_write(comp, 0x00390039, 0x234, handle);
mtk_ddp_write(comp, 0x00300000, 0x250, handle);
mtk_ddp_write(comp, 0x00300030, 0x254, handle);
mtk_ddp_write(comp, 0x00300000, 0x258, handle);
mtk_ddp_write(comp, 0x00300030, 0x25C, handle);
mtk_ddp_write(comp, 165 | (198 << 16), 0x260, handle);
mtk_ddp_write(comp, 63 | (65 << 16), 0x264, handle);
mtk_ddp_write(comp, 63 | (65 << 16), 0x268, handle);
#else
/* WDMA_SMI_CON */
value = gs[GS_WDMA_SMI_CON];
mtk_ddp_write(comp, value, DISP_REG_WDMA_SMI_CON, handle);
// DISP_REG_SET(cmdq, offset + DISP_REG_WDMA_SMI_CON, value);
/* WDMA_BUF_CON1 */
value = gs[GS_WDMA_BUF_CON1];
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON1, handle);
// DISP_REG_SET(cmdq, offset + DISP_REG_WDMA_BUF_CON1, value);
/* WDMA BUF CONST 5 */
value = gs[GS_WDMA_PRE_ULTRA_LOW_Y] + (gs[GS_WDMA_ULTRA_LOW_Y] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON5, handle);
// DISP_REG_SET(cmdq, offset + DISP_REG_WDMA_BUF_CON5, value);
/* WDMA BUF CONST 6 */
value = gs[GS_WDMA_PRE_ULTRA_HIGH_Y] + (gs[GS_WDMA_ULTRA_HIGH_Y] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON6, handle);
// DISP_REG_SET(cmdq, offset + DISP_REG_WDMA_BUF_CON6, value);
/* WDMA BUF CONST 7 */
value = gs[GS_WDMA_PRE_ULTRA_LOW_U] + (gs[GS_WDMA_ULTRA_LOW_U] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON7, handle);
// DISP_REG_SET(cmdq, offset + DISP_REG_WDMA_BUF_CON7, value);
/* WDMA BUF CONST 8 */
value = gs[GS_WDMA_PRE_ULTRA_HIGH_U] + (gs[GS_WDMA_ULTRA_HIGH_U] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON8, handle);
// DISP_REG_SET(cmdq, offset + DISP_REG_WDMA_BUF_CON8, value);
/* WDMA BUF CONST 9 */
value = gs[GS_WDMA_PRE_ULTRA_LOW_V] + (gs[GS_WDMA_ULTRA_LOW_V] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON9, handle);
// DISP_REG_SET(cmdq, offset + DISP_REG_WDMA_BUF_CON9, value);
/* WDMA BUF CONST 10 */
value = gs[GS_WDMA_PRE_ULTRA_HIGH_V] + (gs[GS_WDMA_ULTRA_HIGH_V] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON10, handle);
/* WDMA BUF CONST 11 */
value = gs[GS_WDMA_PRE_ULTRA_LOW_Y_DVFS] +
(gs[GS_WDMA_ULTRA_LOW_Y_DVFS] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON11, handle);
/* WDMA BUF CONST 12 */
value = gs[GS_WDMA_PRE_ULTRA_HIGH_Y_DVFS] +
(gs[GS_WDMA_ULTRA_HIGH_Y_DVFS] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON12, handle);
/* WDMA BUF CONST 13 */
value = gs[GS_WDMA_PRE_ULTRA_LOW_U_DVFS] +
(gs[GS_WDMA_ULTRA_LOW_U_DVFS] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON13, handle);
/* WDMA BUF CONST 14 */
value = gs[GS_WDMA_PRE_ULTRA_HIGH_U_DVFS] +
(gs[GS_WDMA_ULTRA_HIGH_U_DVFS] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON14, handle);
/* WDMA BUF CONST 15 */
value = gs[GS_WDMA_PRE_ULTRA_LOW_V_DVFS] +
(gs[GS_WDMA_ULTRA_LOW_V_DVFS] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON15, handle);
/* WDMA BUF CONST 16 */
value = gs[GS_WDMA_PRE_ULTRA_HIGH_V_DVFS] +
(gs[GS_WDMA_ULTRA_HIGH_V_DVFS] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON16, handle);
/* WDMA BUF CONST 17 */
value = gs[GS_WDMA_DVFS_EN] + (gs[GS_WDMA_DVFS_TH_Y] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON17, handle);
/* WDMA BUF CONST 18 */
value = gs[GS_WDMA_DVFS_TH_U] + (gs[GS_WDMA_DVFS_TH_V] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON18, handle);
/* WDMA URGENT CON0 */
value = gs[GS_WDMA_URGENT_LOW_Y] + (gs[GS_WDMA_URGENT_HIGH_Y] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_URGENT_CON0, handle);
/* WDMA URGENT CON1 */
value = gs[GS_WDMA_URGENT_LOW_U] + (gs[GS_WDMA_URGENT_HIGH_U] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_URGENT_CON1, handle);
/* WDMA URGENT CON2 */
value = gs[GS_WDMA_URGENT_LOW_V] + (gs[GS_WDMA_URGENT_HIGH_V] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_URGENT_CON2, handle);
/* WDMA_BUF_CON3 */
value = gs[GS_WDMA_ISSUE_REG_TH_Y] + (gs[GS_WDMA_ISSUE_REG_TH_U] << 16);
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON3, handle);
/* WDMA_BUF_CON4 */
value = gs[GS_WDMA_ISSUE_REG_TH_V];
mtk_ddp_write(comp, value, DISP_REG_WDMA_BUF_CON4, handle);
#endif
}
static unsigned int wdma_fmt_convert(unsigned int fmt)
{
switch (fmt) {
default:
case DRM_FORMAT_RGB565:
return MEM_MODE_INPUT_FORMAT_RGB565;
case DRM_FORMAT_BGR565:
return MEM_MODE_INPUT_FORMAT_RGB565 | MEM_MODE_INPUT_SWAP;
case DRM_FORMAT_RGB888:
return MEM_MODE_INPUT_FORMAT_RGB888;
case DRM_FORMAT_BGR888:
return MEM_MODE_INPUT_FORMAT_RGB888 | MEM_MODE_INPUT_SWAP;
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_RGBA8888:
return MEM_MODE_INPUT_FORMAT_ARGB8888;
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_BGRA8888:
return MEM_MODE_INPUT_FORMAT_ARGB8888 | MEM_MODE_INPUT_SWAP;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
return MEM_MODE_INPUT_FORMAT_RGBA8888;
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
return MEM_MODE_INPUT_FORMAT_RGBA8888 | MEM_MODE_INPUT_SWAP;
case DRM_FORMAT_UYVY:
return MEM_MODE_INPUT_FORMAT_UYVY;
case DRM_FORMAT_YUYV:
return MEM_MODE_INPUT_FORMAT_YUYV;
case DRM_FORMAT_YUV420:
return MEM_MODE_INPUT_FORMAT_IYUV;
case DRM_FORMAT_YVU420:
return MEM_MODE_INPUT_FORMAT_IYUV | MEM_MODE_INPUT_SWAP;
}
}
static int wdma_config_yuv420(struct mtk_ddp_comp *comp,
uint32_t fmt, unsigned int dstPitch,
unsigned int Height, unsigned long dstAddress,
uint32_t sec, void *handle, int sec_id)
{
/* size_t size; */
unsigned int u_off = 0;
unsigned int v_off = 0;
unsigned int u_stride = 0;
unsigned int y_size = 0;
unsigned int u_size = 0;
/* unsigned int v_size = 0; */
unsigned int stride = dstPitch;
int has_v = 1;
if (fmt != DRM_FORMAT_YUV420 && fmt != DRM_FORMAT_YVU420 &&
fmt != DRM_FORMAT_NV12 && fmt != DRM_FORMAT_NV21)
return 0;
if (fmt == DRM_FORMAT_YUV420 || fmt == DRM_FORMAT_YVU420) {
y_size = stride * Height;
u_stride = ALIGN_TO(stride / 2, 16);
u_size = u_stride * Height / 2;
u_off = y_size;
v_off = y_size + u_size;
} else if (fmt == DRM_FORMAT_NV12 || fmt == DRM_FORMAT_NV21) {
y_size = stride * Height;
u_stride = stride / 2;
u_size = u_stride * Height / 2;
u_off = y_size;
has_v = 0;
}
if (!sec) {
mtk_ddp_write(comp, dstAddress + u_off,
DISP_REG_WDMA_DST_ADDR1, handle);
if (has_v)
mtk_ddp_write(comp, dstAddress + v_off,
DISP_REG_WDMA_DST_ADDR2, handle);
} else {
#if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT)
cmdq_sec_pkt_write_reg(handle,
comp->regs_pa + DISP_REG_WDMA_DST_ADDR1,
dstAddress, CMDQ_IWC_H_2_MVA,
u_off, u_size, 0, sec_id);
if (has_v)
cmdq_sec_pkt_write_reg(handle,
comp->regs_pa + DISP_REG_WDMA_DST_ADDR2,
dstAddress, CMDQ_IWC_H_2_MVA,
v_off, u_size, 0, sec_id);
#endif
}
mtk_ddp_write_mask(comp, u_stride,
DISP_REG_WDMA_DST_UV_PITCH, 0xFFFF, handle);
return 0;
}
static bool is_yuv(uint32_t format)
{
switch (format) {
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
case DRM_FORMAT_YUYV:
case DRM_FORMAT_YVYU:
case DRM_FORMAT_UYVY:
case DRM_FORMAT_VYUY:
return true;
default:
break;
}
return false;
}
static void mtk_wdma_config(struct mtk_ddp_comp *comp,
struct mtk_ddp_config *cfg, struct cmdq_pkt *handle)
{
unsigned int size = 0;
unsigned int con = 0;
unsigned int addr = 0;
struct mtk_disp_wdma *wdma = comp_to_wdma(comp);
struct mtk_wdma_cfg_info *cfg_info = &wdma->cfg_info;
int crtc_idx = drm_crtc_index(&comp->mtk_crtc->base);
int clip_w, clip_h;
struct golden_setting_context *gsc;
u32 sec, buffer_size;
int sec_id;
if (!comp->fb) {
if (crtc_idx != 2)
DDPPR_ERR("%s fb is empty, CRTC%d\n",
__func__, crtc_idx);
return;
}
addr = (u32)mtk_fb_get_dma(comp->fb);
if (!addr) {
DDPPR_ERR("%s:%d C%d no dma_buf\n",
__func__, __LINE__,
crtc_idx);
return;
}
sec = mtk_drm_fb_is_secure(comp->fb);
sec_id = mtk_fb_get_sec_id(comp->fb);
addr += comp->fb->offsets[0];
if (!(comp->fb->format &&
comp->fb->format->format)) {
DDPPR_ERR("%s fb format is NULL, CRTC%d\n",
__func__, crtc_idx);
return;
}
con = wdma_fmt_convert(comp->fb->format->format);
DDPINFO("%s fmt:0x%x, con:0x%x addr %x\n", __func__,
comp->fb->format->format, con, addr);
if (!addr) {
DDPPR_ERR("%s wdma dst addr is zero\n", __func__);
return;
}
clip_w = cfg->w;
clip_h = cfg->h;
if (is_yuv(comp->fb->format->format)) {
if ((cfg->x + cfg->w) % 2)
clip_w -= 1;
if ((cfg->y + cfg->h) % 2)
clip_h -= 1;
}
size = (cfg->w & 0x3FFFU) + ((cfg->h << 16U) & 0x3FFF0000U);
mtk_ddp_write(comp, size, DISP_REG_WDMA_SRC_SIZE, handle);
mtk_ddp_write(comp, (cfg->y << 16) | cfg->x,
DISP_REG_WDMA_CLIP_COORD, handle);
mtk_ddp_write(comp, (clip_h << 16) | clip_w,
DISP_REG_WDMA_CLIP_SIZE, handle);
mtk_ddp_write_mask(comp, con, DISP_REG_WDMA_CFG,
WDMA_OUT_FMT | WDMA_CON_SWAP, handle);
if (is_yuv(comp->fb->format->format)) {
wdma_config_yuv420(comp, comp->fb->format->format,
comp->fb->pitches[0], cfg->h,
addr, sec, handle, sec_id);
mtk_ddp_write_mask(comp, 0,
DISP_REG_WDMA_CFG, WDMA_UFO_DCP_ENABLE, handle);
mtk_ddp_write_mask(comp, WDMA_CT_EN,
DISP_REG_WDMA_CFG, WDMA_CT_EN, handle);
mtk_ddp_write_mask(comp, 0x02000000,
DISP_REG_WDMA_CFG, WDMA_INT_MTX_SEL, handle);
} else {
mtk_ddp_write_mask(comp, 0,
DISP_REG_WDMA_CFG, WDMA_UFO_DCP_ENABLE, handle);
mtk_ddp_write_mask(comp, 0,
DISP_REG_WDMA_CFG, WDMA_CT_EN, handle);
}
mtk_ddp_write(comp, comp->fb->pitches[0],
DISP_REG_WDMA_DST_WIN_BYTE, handle);
if (!sec) {
mtk_ddp_write(comp, addr & 0xFFFFFFFFU,
DISP_REG_WDMA_DST_ADDR0, handle);
} else {
buffer_size = clip_w * comp->fb->pitches[0];
#if defined(CONFIG_MTK_SEC_VIDEO_PATH_SUPPORT)
cmdq_sec_pkt_write_reg(handle,
comp->regs_pa + DISP_REG_WDMA_DST_ADDR0,
addr & 0xFFFFFFFFU, CMDQ_IWC_H_2_MVA,
0, buffer_size, 0, sec_id);
#endif
}
gsc = cfg->p_golden_setting_context;
mtk_wdma_golden_setting(comp, gsc, handle);
cfg_info->addr = addr;
cfg_info->width = cfg->w;
cfg_info->height = cfg->h;
cfg_info->fmt = comp->fb->format->format;
}
static void mtk_wdma_addon_config(struct mtk_ddp_comp *comp,
enum mtk_ddp_comp_id prev,
enum mtk_ddp_comp_id next,
union mtk_addon_config *addon_config,
struct cmdq_pkt *handle)
{
unsigned int size = 0;
unsigned int con = 0;
unsigned int addr = 0;
struct mtk_disp_wdma *wdma = comp_to_wdma(comp);
struct mtk_wdma_cfg_info *cfg_info = &wdma->cfg_info;
int crtc_idx = drm_crtc_index(&comp->mtk_crtc->base);
int src_w, src_h, clip_w, clip_h, clip_x, clip_y;
struct golden_setting_context *gsc;
comp->fb = addon_config->addon_wdma_config.fb;
if (!comp->fb) {
DDPPR_ERR("%s fb is empty, CRTC%d\n", __func__, crtc_idx);
return;
}
con = wdma_fmt_convert(comp->fb->format->format);
addr = addon_config->addon_wdma_config.addr;
if (!addr) {
DDPPR_ERR("%s:%d C%d no dma_buf\n", __func__,
__LINE__, crtc_idx);
return;
}
cfg_info->addr = addr;
mtk_ddp_write(comp, addr & 0xFFFFFFFFU,
DISP_REG_WDMA_DST_ADDR0, handle);
src_w = addon_config->addon_wdma_config.wdma_src_roi.width;
src_h = addon_config->addon_wdma_config.wdma_src_roi.height;
clip_w = addon_config->addon_wdma_config.wdma_dst_roi.width;
clip_h = addon_config->addon_wdma_config.wdma_dst_roi.height;
clip_x = addon_config->addon_wdma_config.wdma_dst_roi.x;
clip_y = addon_config->addon_wdma_config.wdma_dst_roi.y;
size = (src_w & 0x3FFFU) + ((src_h << 16U) & 0x3FFF0000U);
mtk_ddp_write(comp, size, DISP_REG_WDMA_SRC_SIZE, handle);
mtk_ddp_write(comp, (clip_y << 16) | clip_x,
DISP_REG_WDMA_CLIP_COORD, handle);
mtk_ddp_write(comp, (clip_h << 16) | clip_w,
DISP_REG_WDMA_CLIP_SIZE, handle);
mtk_ddp_write_mask(comp, con, DISP_REG_WDMA_CFG,
WDMA_OUT_FMT | WDMA_CON_SWAP, handle);
mtk_ddp_write_mask(comp, 0,
DISP_REG_WDMA_CFG, WDMA_UFO_DCP_ENABLE, handle);
mtk_ddp_write_mask(comp, 0,
DISP_REG_WDMA_CFG, WDMA_CT_EN, handle);
mtk_ddp_write(comp, clip_w * 3,
DISP_REG_WDMA_DST_WIN_BYTE, handle);
gsc = addon_config->addon_wdma_config.p_golden_setting_context;
mtk_wdma_golden_setting(comp, gsc, handle);
DDPMSG("[capture] config addr:0x%x, roi:(%d,%d,%d,%d)\n",
addr, clip_x, clip_y, clip_w, clip_h);
cfg_info->width = clip_w;
cfg_info->height = clip_h;
cfg_info->fmt = comp->fb->format->format;
}
void mtk_wdma_dump_golden_setting(struct mtk_ddp_comp *comp)
{
void __iomem *baddr = comp->regs;
unsigned int value;
int i;
DDPDUMP("-- %s Golden Setting --\n", mtk_dump_comp_str(comp));
if (comp->mtk_crtc && comp->mtk_crtc->sec_on) {
DDPDUMP("Skip dump secure wdma!\n");
return;
}
DDPDUMP("0x%03x:0x%08x 0x%03x:0x%08x\n",
0x10, readl(DISP_REG_WDMA_SMI_CON + baddr),
0x38, readl(DISP_REG_WDMA_BUF_CON1 + baddr));
for (i = 0; i < 3; i++)
DDPDUMP("0x%03x:0x%08x 0x%08x 0x%08x 0x%08x\n",
0x200 + i * 0x10,
readl(DISP_REG_WDMA_BUF_CON5 +
baddr + i * 0x10),
readl(DISP_REG_WDMA_BUF_CON6 +
baddr + i * 0x10),
readl(DISP_REG_WDMA_BUF_CON7 +
baddr + i * 0x10),
readl(DISP_REG_WDMA_BUF_CON8 +
baddr + i * 0x10));
DDPDUMP("0x%03x:0x%08x 0x%08x\n",
0x230, readl(DISP_REG_WDMA_BUF_CON17 + baddr),
readl(DISP_REG_WDMA_BUF_CON18 + baddr));
DDPDUMP("0x%03x:0x%08x 0x%08x 0x%08x 0x%08x\n",
0x250, readl(DISP_REG_WDMA_DRS_CON0 + baddr),
readl(DISP_REG_WDMA_DRS_CON1 + baddr),
readl(DISP_REG_WDMA_DRS_CON2 + baddr),
readl(DISP_REG_WDMA_DRS_CON3 + baddr));
DDPDUMP("0x%03x:0x%08x 0x%08x\n",
0x104, readl(DISP_REG_WDMA_BUF_CON3 + baddr),
readl(DISP_REG_WDMA_BUF_CON4 + baddr));
value = readl(DISP_REG_WDMA_SMI_CON + baddr);
DDPDUMP("WDMA_SMI_CON:[3:0]:%x [4:4]:%x [7:5]:%x [15:8]:%x\n",
REG_FLD_VAL_GET(SMI_CON_FLD_THRESHOLD, value),
REG_FLD_VAL_GET(SMI_CON_FLD_SLOW_ENABLE, value),
REG_FLD_VAL_GET(SMI_CON_FLD_SLOW_LEVEL, value),
REG_FLD_VAL_GET(SMI_CON_FLD_SLOW_COUNT, value));
DDPDUMP("WDMA_SMI_CON:[19:16]:%u [23:20]:%u [27:24]:%u [28]:%u\n",
REG_FLD_VAL_GET(SMI_CON_FLD_SMI_Y_REPEAT_NUM, value),
REG_FLD_VAL_GET(SMI_CON_FLD_SMI_U_REPEAT_NUM, value),
REG_FLD_VAL_GET(SMI_CON_FLD_SMI_V_REPEAT_NUM, value),
REG_FLD_VAL_GET(SMI_CON_FLD_SMI_OBUF_FULL_REQ, value));
value = readl(DISP_REG_WDMA_BUF_CON1 + baddr);
DDPDUMP("WDMA_BUF_CON1:[31]:%x [30]:%x [28]:%x [26]%d\n",
REG_FLD_VAL_GET(BUF_CON1_FLD_ULTRA_ENABLE, value),
REG_FLD_VAL_GET(BUF_CON1_FLD_PRE_ULTRA_ENABLE, value),
REG_FLD_VAL_GET(BUF_CON1_FLD_FRAME_END_ULTRA, value),
REG_FLD_VAL_GET(BUF_CON1_FLD_URGENT_EN, value));
DDPDUMP("WDMA_BUF_CON1:[18:10]:%d [9:0]:%d\n",
REG_FLD_VAL_GET(BUF_CON1_FLD_FIFO_PSEUDO_SIZE_UV, value),
REG_FLD_VAL_GET(BUF_CON1_FLD_FIFO_PSEUDO_SIZE, value));
value = readl(DISP_REG_WDMA_BUF_CON5 + baddr);
DDPDUMP("WDMA_BUF_CON5:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_LOW, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_LOW, value));
value = readl(DISP_REG_WDMA_BUF_CON6 + baddr);
DDPDUMP("WDMA_BUF_CON6:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_HIGH, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_HIGH, value));
value = readl(DISP_REG_WDMA_BUF_CON7 + baddr);
DDPDUMP("WDMA_BUF_CON7:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_LOW, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_LOW, value));
value = readl(DISP_REG_WDMA_BUF_CON8 + baddr);
DDPDUMP("WDMA_BUF_CON8:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_HIGH, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_HIGH, value));
value = readl(DISP_REG_WDMA_BUF_CON9 + baddr);
DDPDUMP("WDMA_BUF_CON9:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_LOW, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_LOW, value));
value = readl(DISP_REG_WDMA_BUF_CON10 + baddr);
DDPDUMP("WDMA_BUF_CON10:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_HIGH, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_HIGH, value));
value = readl(DISP_REG_WDMA_BUF_CON11 + baddr);
DDPDUMP("WDMA_BUF_CON11:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_LOW, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_LOW, value));
value = readl(DISP_REG_WDMA_BUF_CON12 + baddr);
DDPDUMP("WDMA_BUF_CON12:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_HIGH, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_HIGH, value));
value = readl(DISP_REG_WDMA_BUF_CON13 + baddr);
DDPDUMP("WDMA_BUF_CON13:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_LOW, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_LOW, value));
value = readl(DISP_REG_WDMA_BUF_CON14 + baddr);
DDPDUMP("WDMA_BUF_CON14:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_HIGH, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_HIGH, value));
value = readl(DISP_REG_WDMA_BUF_CON15 + baddr);
DDPDUMP("WDMA_BUF_CON15:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_LOW, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_LOW, value));
value = readl(DISP_REG_WDMA_BUF_CON16 + baddr);
DDPDUMP("WDMA_BUF_CON16:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON_FLD_PRE_ULTRA_HIGH, value),
REG_FLD_VAL_GET(BUF_CON_FLD_ULTRA_HIGH, value));
value = readl(DISP_REG_WDMA_BUF_CON17 + baddr);
DDPDUMP("WDMA_BUF_CON17:[0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON17_FLD_WDMA_DVFS_EN, value),
REG_FLD_VAL_GET(BUF_CON17_FLD_DVFS_TH_Y, value));
value = readl(DISP_REG_WDMA_BUF_CON18 + baddr);
DDPDUMP("WDMA_BUF_CON18:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON18_FLD_DVFS_TH_U, value),
REG_FLD_VAL_GET(BUF_CON18_FLD_DVFS_TH_V, value));
value = readl(DISP_REG_WDMA_URGENT_CON0 + baddr);
DDPDUMP("WDMA_URGENT_CON0:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(FLD_WDMA_URGENT_LOW_Y, value),
REG_FLD_VAL_GET(FLD_WDMA_URGENT_HIGH_Y, value));
value = readl(DISP_REG_WDMA_URGENT_CON1 + baddr);
DDPDUMP("WDMA_URGENT_CON1:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(FLD_WDMA_URGENT_LOW_U, value),
REG_FLD_VAL_GET(FLD_WDMA_URGENT_HIGH_U, value));
value = readl(DISP_REG_WDMA_URGENT_CON2 + baddr);
DDPDUMP("WDMA_URGENT_CON2:[9:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(FLD_WDMA_URGENT_LOW_V, value),
REG_FLD_VAL_GET(FLD_WDMA_URGENT_HIGH_V, value));
value = readl(DISP_REG_WDMA_BUF_CON3 + baddr);
DDPDUMP("WDMA_BUF_CON3:[8:0]:%d [25:16]:%d\n",
REG_FLD_VAL_GET(BUF_CON3_FLD_ISSUE_REQ_TH_Y, value),
REG_FLD_VAL_GET(BUF_CON3_FLD_ISSUE_REQ_TH_U, value));
value = readl(DISP_REG_WDMA_BUF_CON4 + baddr);
DDPDUMP("WDMA_BUF_CON4:[8:0]:%d\n",
REG_FLD_VAL_GET(BUF_CON4_FLD_ISSUE_REQ_TH_V, value));
}
int mtk_wdma_dump(struct mtk_ddp_comp *comp)
{
void __iomem *baddr = comp->regs;
DDPDUMP("== %s REGS ==\n", mtk_dump_comp_str(comp));
if (comp->mtk_crtc && comp->mtk_crtc->sec_on) {
DDPDUMP("Skip dump secure wdma!\n");
return 0;
}
if (mtk_ddp_comp_helper_get_opt(comp,
MTK_DRM_OPT_REG_PARSER_RAW_DUMP)) {
unsigned int i = 0;
for (i = 0; i < 0x300; i += 0x10)
mtk_serial_dump_reg(baddr, i, 4);
} else {
DDPDUMP("0x000:0x%08x 0x%08x 0x%08x 0x%08x\n",
readl(DISP_REG_WDMA_INTEN + baddr),
readl(DISP_REG_WDMA_INTSTA + baddr),
readl(DISP_REG_WDMA_EN + baddr),
readl(DISP_REG_WDMA_RST + baddr));
DDPDUMP("0x010:0x%08x 0x%08x 0x%08x 0x%08x\n",
readl(DISP_REG_WDMA_SMI_CON + baddr),
readl(DISP_REG_WDMA_CFG + baddr),
readl(DISP_REG_WDMA_SRC_SIZE + baddr),
readl(DISP_REG_WDMA_CLIP_SIZE + baddr));
DDPDUMP("0x020:0x%08x 0x%08x 0x%08x 0x%08x\n",
readl(DISP_REG_WDMA_CLIP_COORD + baddr),
readl(DISP_REG_WDMA_SHADOW_CTRL + baddr),
readl(DISP_REG_WDMA_DST_WIN_BYTE + baddr),
readl(DISP_REG_WDMA_ALPHA + baddr));
DDPDUMP("0x038:0x%08x 0x078:0x%08x\n",
readl(DISP_REG_WDMA_BUF_CON1 + baddr),
readl(DISP_REG_WDMA_DST_UV_PITCH + baddr));
DDPDUMP("0x080:0x%08x 0x%08x 0x%08x\n",
readl(DISP_REG_WDMA_DST_ADDR_OFFSET0 + baddr),
readl(DISP_REG_WDMA_DST_ADDR_OFFSET1 + baddr),
readl(DISP_REG_WDMA_DST_ADDR_OFFSET2 + baddr));
DDPDUMP("0x0a0:0x%08x 0x%08x 0x%08x 0x0b8:0x%08x\n",
readl(DISP_REG_WDMA_FLOW_CTRL_DBG + baddr),
readl(DISP_REG_WDMA_EXEC_DBG + baddr),
readl(DISP_REG_WDMA_INPUT_CNT_DBG + baddr),
readl(DISP_REG_WDMA_DEBUG + baddr));
DDPDUMP("0xf00:0x%08x 0x%08x 0x%08x\n",
readl(DISP_REG_WDMA_DST_ADDR0 + baddr),
readl(DISP_REG_WDMA_DST_ADDR1 + baddr),
readl(DISP_REG_WDMA_DST_ADDR2 + baddr));
}
mtk_wdma_dump_golden_setting(comp);
return 0;
}
static char *wdma_get_state(unsigned int status)
{
switch (status) {
case 0x1:
return "idle";
case 0x2:
return "clear";
case 0x4:
return "prepare1";
case 0x8:
return "prepare2";
case 0x10:
return "data_transmit";
case 0x20:
return "eof_wait";
case 0x40:
return "soft_reset_wait";
case 0x80:
return "eof_done";
case 0x100:
return "soft_reset_done";
case 0x200:
return "frame_complete";
}
return "unknown-state";
}
int mtk_wdma_analysis(struct mtk_ddp_comp *comp)
{
void __iomem *baddr = comp->regs;
DDPDUMP("== DISP %s ANALYSIS ==\n", mtk_dump_comp_str(comp));
if (comp->mtk_crtc && comp->mtk_crtc->sec_on) {
DDPDUMP("Skip dump secure wdma!\n");
return 0;
}
DDPDUMP("en=%d,src(%dx%d),clip=(%d,%d,%dx%d)\n",
readl(baddr + DISP_REG_WDMA_EN) & 0x01,
readl(baddr + DISP_REG_WDMA_SRC_SIZE) & 0x3fff,
(readl(baddr + DISP_REG_WDMA_SRC_SIZE) >> 16) & 0x3fff,
readl(baddr + DISP_REG_WDMA_CLIP_COORD) & 0x3fff,
(readl(baddr + DISP_REG_WDMA_CLIP_COORD) >> 16) & 0x3fff,
readl(baddr + DISP_REG_WDMA_CLIP_SIZE) & 0x3fff,
(readl(baddr + DISP_REG_WDMA_CLIP_SIZE) >> 16) & 0x3fff);
DDPDUMP("pitch=(W=%d,UV=%d),addr=(0x%08x,0x%08x,0x%08x),cfg=0x%x\n",
readl(baddr + DISP_REG_WDMA_DST_WIN_BYTE),
readl(baddr + DISP_REG_WDMA_DST_UV_PITCH),
readl(baddr + DISP_REG_WDMA_DST_ADDR0),
readl(baddr + DISP_REG_WDMA_DST_ADDR1),
readl(baddr + DISP_REG_WDMA_DST_ADDR2),
readl(baddr + DISP_REG_WDMA_CFG));
DDPDUMP("state=%s,in_req=%d(prev sent data)\n",
wdma_get_state(DISP_REG_GET_FIELD(
FLOW_CTRL_DBG_FLD_WDMA_STA_FLOW_CTRL,
baddr + DISP_REG_WDMA_FLOW_CTRL_DBG)),
REG_FLD_VAL_GET(FLOW_CTRL_DBG_FLD_WDMA_IN_VALID,
readl(baddr + DISP_REG_WDMA_FLOW_CTRL_DBG)));
DDPDUMP("in_ack=%d(ask data to prev),start=%d,end=%d,pos:in(%d,%d)\n",
REG_FLD_VAL_GET(FLOW_CTRL_DBG_FLD_WDMA_IN_READY,
readl(baddr + DISP_REG_WDMA_FLOW_CTRL_DBG)),
readl(baddr + DISP_REG_WDMA_EXEC_DBG) & 0x3f,
readl(baddr + DISP_REG_WDMA_EXEC_DBG) >> 16 & 0x3f,
readl(baddr + DISP_REG_WDMA_INPUT_CNT_DBG) & 0x3fff,
(readl(baddr + DISP_REG_WDMA_INPUT_CNT_DBG) >> 16) & 0x3fff);
return 0;
}
int MMPathTraceWDMA(struct mtk_ddp_comp *ddp_comp, char *str,
unsigned int strlen, unsigned int n)
{
struct mtk_disp_wdma *wdma = comp_to_wdma(ddp_comp);
struct mtk_wdma_cfg_info *cfg_info = &wdma->cfg_info;
n += scnprintf(str + n, strlen - n,
"out=0x%x, out_width=%d, out_height=%d, out_fmt=%s, out_bpp=%d",
cfg_info->addr,
cfg_info->width,
cfg_info->height,
mtk_get_format_name(cfg_info->fmt),
mtk_get_format_bpp(cfg_info->fmt));
return n;
}
static int mtk_wdma_io_cmd(struct mtk_ddp_comp *comp, struct cmdq_pkt *handle,
enum mtk_ddp_io_cmd cmd, void *params)
{
struct mtk_disp_wdma *wdma = container_of(comp, struct mtk_disp_wdma, ddp_comp);
switch (cmd) {
case WDMA_WRITE_DST_ADDR0:
{
unsigned int addr = *(unsigned int *)params;
mtk_ddp_write(comp, addr & 0xFFFFFFFFU,
DISP_REG_WDMA_DST_ADDR0, handle);
DDPMSG("[capture] update addr:0x%x\n", addr);
wdma->cfg_info.addr = addr;
}
break;
case WDMA_READ_DST_SIZE:
{
unsigned int val, w, h;
struct mtk_cwb_info *cwb_info = (struct mtk_cwb_info *)params;
val = readl(comp->regs + DISP_REG_WDMA_CLIP_SIZE);
w = val & 0x3fff;
h = (val >> 16) & 0x3fff;
cwb_info->copy_w = w;
cwb_info->copy_h = h;
DDPDBG("[capture] sof get (w,h)=(%d,%d)\n", w, h);
}
break;
case IRQ_LEVEL_IDLE: {
mtk_ddp_write(comp, 0x0, DISP_REG_WDMA_INTEN, handle);
break;
}
case IRQ_LEVEL_ALL: {
unsigned int inten;
inten = REG_FLD_VAL(INTEN_FLD_FME_CPL_INTEN, 1) |
REG_FLD_VAL(INTEN_FLD_FME_UND_INTEN, 1);
mtk_ddp_write(comp, inten, DISP_REG_WDMA_INTEN, handle);
break;
}
default:
break;
}
return 0;
}
static const struct mtk_ddp_comp_funcs mtk_disp_wdma_funcs = {
.config = mtk_wdma_config,
.addon_config = mtk_wdma_addon_config,
.start = mtk_wdma_start,
.stop = mtk_wdma_stop,
.prepare = mtk_wdma_prepare,
.unprepare = mtk_wdma_unprepare,
.is_busy = mtk_wdma_is_busy,
.io_cmd = mtk_wdma_io_cmd,
};
static int mtk_disp_wdma_bind(struct device *dev, struct device *master,
void *data)
{
struct mtk_disp_wdma *priv = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
int ret;
DDPINFO("%s\n", __func__);
ret = mtk_ddp_comp_register(drm_dev, &priv->ddp_comp);
if (ret < 0) {
dev_err(dev, "Failed to register component %s: %d\n",
dev->of_node->full_name, ret);
return ret;
}
return 0;
}
static void mtk_disp_wdma_unbind(struct device *dev, struct device *master,
void *data)
{
struct mtk_disp_wdma *priv = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
mtk_ddp_comp_unregister(drm_dev, &priv->ddp_comp);
}
static const struct component_ops mtk_disp_wdma_component_ops = {
.bind = mtk_disp_wdma_bind, .unbind = mtk_disp_wdma_unbind,
};
static int mtk_disp_wdma_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct mtk_disp_wdma *priv;
enum mtk_ddp_comp_id comp_id;
int irq;
int ret;
DDPMSG("%s+\n", __func__);
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DISP_WDMA);
if ((int)comp_id < 0) {
dev_err(dev, "Failed to identify by alias: %d\n", comp_id);
return comp_id;
}
ret = mtk_ddp_comp_init(dev, dev->of_node, &priv->ddp_comp, comp_id,
&mtk_disp_wdma_funcs);
if (ret) {
dev_err(dev, "Failed to initialize component: %d\n", ret);
return ret;
}
platform_set_drvdata(pdev, priv);
ret = devm_request_irq(dev, irq, mtk_wdma_irq_handler,
IRQF_TRIGGER_NONE | IRQF_SHARED, dev_name(dev),
priv);
if (ret < 0) {
DDPAEE("%s:%d, failed to request irq:%d ret:%d comp_id:%d\n",
__func__, __LINE__,
irq, ret, comp_id);
return ret;
}
priv->data = of_device_get_match_data(dev);
pm_runtime_enable(dev);
ret = component_add(dev, &mtk_disp_wdma_component_ops);
if (ret != 0) {
dev_err(dev, "Failed to add component: %d\n", ret);
pm_runtime_disable(dev);
}
DDPMSG("%s-\n", __func__);
return ret;
}
static int mtk_disp_wdma_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &mtk_disp_wdma_component_ops);
pm_runtime_disable(&pdev->dev);
return 0;
}
static const struct mtk_disp_wdma_data mt6779_wdma_driver_data = {
.sodi_config = mt6779_mtk_sodi_config,
.support_shadow = false,
};
static const struct mtk_disp_wdma_data mt6885_wdma_driver_data = {
.sodi_config = mt6885_mtk_sodi_config,
.support_shadow = false,
};
static const struct mtk_disp_wdma_data mt6873_wdma_driver_data = {
.sodi_config = mt6873_mtk_sodi_config,
.support_shadow = false,
};
static const struct mtk_disp_wdma_data mt6853_wdma_driver_data = {
.sodi_config = mt6853_mtk_sodi_config,
.support_shadow = false,
};
static const struct mtk_disp_wdma_data mt6877_wdma_driver_data = {
.sodi_config = mt6877_mtk_sodi_config,
.support_shadow = false,
};
static const struct mtk_disp_wdma_data mt6833_wdma_driver_data = {
.sodi_config = mt6833_mtk_sodi_config,
.support_shadow = false,
};
static const struct mtk_disp_wdma_data mt6781_wdma_driver_data = {
.sodi_config = mt6781_mtk_sodi_config,
.support_shadow = false,
};
static const struct of_device_id mtk_disp_wdma_driver_dt_match[] = {
{.compatible = "mediatek,mt2701-disp-wdma"},
{.compatible = "mediatek,mt6779-disp-wdma",
.data = &mt6779_wdma_driver_data},
{.compatible = "mediatek,mt8173-disp-wdma"},
{.compatible = "mediatek,mt6885-disp-wdma",
.data = &mt6885_wdma_driver_data},
{.compatible = "mediatek,mt6873-disp-wdma",
.data = &mt6873_wdma_driver_data},
{.compatible = "mediatek,mt6853-disp-wdma",
.data = &mt6853_wdma_driver_data},
{.compatible = "mediatek,mt6877-disp-wdma",
.data = &mt6877_wdma_driver_data},
{.compatible = "mediatek,mt6833-disp-wdma",
.data = &mt6833_wdma_driver_data},
{.compatible = "mediatek,mt6781-disp-wdma",
.data = &mt6781_wdma_driver_data},
{},
};
MODULE_DEVICE_TABLE(of, mtk_disp_wdma_driver_dt_match);
struct platform_driver mtk_disp_wdma_driver = {
.probe = mtk_disp_wdma_probe,
.remove = mtk_disp_wdma_remove,
.driver = {
.name = "mediatek-disp-wdma",
.owner = THIS_MODULE,
.of_match_table = mtk_disp_wdma_driver_dt_match,
},
};