#include <linux/device.h>
#include <linux/bitops.h>
#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
#include <drm/drm_fourcc.h>
+#include <linux/delay.h>
#include <video/imx-dcss.h>
#include "dcss-prv.h"
#define DCSS_DTRC_CROPORIG 0x24
#define DCSS_DTRC_CROPSIZE 0x28
#define DCSS_DTRC_DCTL 0x2C
+#define CROPPING_EN BIT(18)
+#define COMPRESSION_DIS BIT(17)
+#define PIX_DEPTH_8BIT_EN BIT(1)
+#define CONFIG_READY BIT(0)
#define DCSS_DTRC_DYDSADDR_EXT 0x30
#define DCSS_DTRC_DCDSADDR_EXT 0x34
#define DCSS_DTRC_DYTSADDR_EXT 0x38
#define DCSS_DTRC_FDINTR 0xC4
#define DCSS_DTRC_DTCTRL 0xC8
#define CURRENT_FRAME BIT(31)
+#define ADDRESS_ID_ENABLE BIT(30)
+#define ENDIANNESS_10BIT BIT(29)
+#define MERGE_ARID_ENABLE BIT(28)
+#define NON_G1_2_SWAP_MODE_POS 24
+#define NON_G1_2_SWAP_MODE_MASK GENMASK(27, 24)
+#define TABLE_DATA_SWAP_POS 20
+#define TABLE_DATA_SWAP_MASK GENMASK(23, 20)
+#define TILED_SWAP_POS 16
+#define TILED_SWAP_MASK GENMASK(19, 16)
+#define RASTER_SWAP_POS 12
+#define RASTER_SWAP_MASK GENMASK(15, 12)
+#define BURST_LENGTH_POS 4
+#define BURST_LENGTH_MASK GENMASK(11, 4)
+#define G1_TILED_DATA_EN BIT(3)
#define HOT_RESET BIT(2)
+#define ARIDR_MODE_DETILE 0
+#define ARIDR_MODE_BYPASS 2
#define DCSS_DTRC_ARIDR 0xCC
#define DCSS_DTRC_DTID2DDR 0xD0
#define DCSS_DTRC_CONFIG 0xD4
u32 xres;
u32 yres;
u32 pix_format;
+ u64 format_modifier;
+ u32 y_dec_ofs;
+ u32 uv_dec_ofs;
+
+ int curr_frame;
+
+ u32 dctl;
u32 ctx_id;
bool bypass;
+ bool running;
};
struct dcss_dtrc_priv {
dev_err(dcss->dev, "dtrc: unable to remap ch base\n");
return -ENOMEM;
}
+
+#if defined(USE_CTXLD)
+ ch->ctx_id = CTX_SB_HP;
+#endif
}
return 0;
#endif
}
+static void dcss_dtrc_write_irqsafe(struct dcss_dtrc_priv *dtrc, int ch_num,
+ u32 val, u32 ofs)
+{
+#if !defined(USE_CTXLD)
+ dcss_writel(val, dtrc->ch[ch_num].base_reg + ofs);
+#else
+ dcss_ctxld_write_irqsafe(dtrc->dcss, dtrc->ch[ch_num].ctx_id,
+ val, dtrc->ch[ch_num].base_ofs + ofs);
+#endif
+}
+
int dcss_dtrc_init(struct dcss_soc *dcss, unsigned long dtrc_base)
{
struct dcss_dtrc_priv *dtrc;
if (dtrc->ch[ch_num].bypass)
return;
- dcss_dtrc_write(dtrc, ch_num, 2, DCSS_DTRC_DTCTRL);
+ dcss_dtrc_write(dtrc, ch_num, ARIDR_MODE_BYPASS, DCSS_DTRC_DTCTRL);
dcss_dtrc_write(dtrc, ch_num, 0, DCSS_DTRC_DYTSADDR);
dcss_dtrc_write(dtrc, ch_num, 0, DCSS_DTRC_DCTSADDR);
dcss_dtrc_write(dtrc, ch_num, 0x0f0e0100, DCSS_DTRC_ARIDR);
}
EXPORT_SYMBOL(dcss_dtrc_bypass);
-void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba)
+void dcss_dtrc_addr_set(struct dcss_soc *dcss, int ch_num, u32 p1_ba, u32 p2_ba,
+ uint64_t dec_table_ofs)
{
struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
- struct dcss_dtrc_ch *ch = &dtrc->ch[ch_num];
- int curr_frame;
+ struct dcss_dtrc_ch *ch;
if (ch_num == 0)
return;
ch_num -= 1;
- curr_frame = dcss_readl(dtrc->ch[ch_num].base_reg + DCSS_DTRC_DTCTRL);
- curr_frame = (curr_frame & CURRENT_FRAME) >> 31;
+ ch = &dtrc->ch[ch_num];
dcss_dtrc_write(dtrc, ch_num, p1_ba, DCSS_DTRC_DYDSADDR);
dcss_dtrc_write(dtrc, ch_num, p2_ba, DCSS_DTRC_DCDSADDR);
dcss_dtrc_write(dtrc, ch_num, p1_ba, DTRC_F1_OFS + DCSS_DTRC_DYDSADDR);
dcss_dtrc_write(dtrc, ch_num, p2_ba, DTRC_F1_OFS + DCSS_DTRC_DCDSADDR);
- dcss_dtrc_write(dtrc, ch_num, p1_ba, DCSS_DTRC_SYSSA);
- dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->xres * ch->yres,
- DCSS_DTRC_SYSEA);
+ if (!ch->running) {
+ dcss_dtrc_write(dtrc, ch_num, p1_ba, DCSS_DTRC_SYSSA);
+ dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->xres * ch->yres,
+ DCSS_DTRC_SYSEA);
- dcss_dtrc_write(dtrc, ch_num, p1_ba, DTRC_F1_OFS + DCSS_DTRC_SYSSA);
- dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->xres * ch->yres,
- DTRC_F1_OFS + DCSS_DTRC_SYSEA);
+ dcss_dtrc_write(dtrc, ch_num, p2_ba, DCSS_DTRC_SUVSSA);
+ dcss_dtrc_write(dtrc, ch_num, p2_ba + ch->xres * ch->yres / 2,
+ DCSS_DTRC_SUVSEA);
- dcss_dtrc_write(dtrc, ch_num, p2_ba, DCSS_DTRC_SUVSSA);
- dcss_dtrc_write(dtrc, ch_num, p2_ba + ch->xres * ch->yres / 4,
- DCSS_DTRC_SUVSEA);
+ dcss_dtrc_write(dtrc, ch_num, p1_ba,
+ DTRC_F1_OFS + DCSS_DTRC_SYSSA);
+ dcss_dtrc_write(dtrc, ch_num, p1_ba + ch->xres * ch->yres,
+ DTRC_F1_OFS + DCSS_DTRC_SYSEA);
- dcss_dtrc_write(dtrc, ch_num, p2_ba, DTRC_F1_OFS + DCSS_DTRC_SUVSSA);
- dcss_dtrc_write(dtrc, ch_num, p2_ba + ch->xres * ch->yres / 4,
- DTRC_F1_OFS + DCSS_DTRC_SUVSEA);
+ dcss_dtrc_write(dtrc, ch_num, p2_ba,
+ DTRC_F1_OFS + DCSS_DTRC_SUVSSA);
+ dcss_dtrc_write(dtrc, ch_num, p2_ba + ch->xres * ch->yres / 2,
+ DTRC_F1_OFS + DCSS_DTRC_SUVSEA);
- dcss_dtrc_write(dcss->dtrc_priv, ch_num - 1, 0x0f0e0100,
- DCSS_DTRC_ARIDR);
- dcss_dtrc_write(dcss->dtrc_priv, ch_num - 1, 0x0f0e,
- DCSS_DTRC_DTID2DDR);
+ ch->y_dec_ofs = dec_table_ofs & 0xFFFFFFFF;
+ ch->uv_dec_ofs = dec_table_ofs >> 32;
+ }
- dcss_dtrc_write(dtrc, ch_num, 0x50f00108, DCSS_DTRC_DTCTRL);
-
- /* TODO: hardcoded this for testing purposes. */
- dcss_dtrc_write(dtrc, ch_num, 0x20002,
- (curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
- dcss_dtrc_write(dtrc, ch_num, 0x20003,
- curr_frame * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+ dcss_dtrc_write(dtrc, ch_num,
+ p1_ba + ch->y_dec_ofs, DCSS_DTRC_DYTSADDR);
+ dcss_dtrc_write(dtrc, ch_num,
+ p1_ba + ch->uv_dec_ofs, DCSS_DTRC_DCTSADDR);
+ dcss_dtrc_write(dtrc, ch_num,
+ p1_ba + ch->y_dec_ofs, DTRC_F1_OFS + DCSS_DTRC_DYTSADDR);
+ dcss_dtrc_write(dtrc, ch_num,
+ p1_ba + ch->uv_dec_ofs, DTRC_F1_OFS + DCSS_DTRC_DCTSADDR);
dtrc->ch[ch_num].bypass = false;
}
void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, u32 xres, u32 yres)
{
struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
u32 frame_height, frame_width;
+ int bank;
if (ch_num == 0)
return;
- dtrc->ch[ch_num].xres = xres;
- dtrc->ch[ch_num].yres = yres;
+ ch_num -= 1;
+
+ ch = &dtrc->ch[ch_num];
+ bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ ch->xres = xres;
+ ch->yres = yres;
frame_height = ((yres >> 3) << FRAME_HEIGHT_POS) & FRAME_HEIGHT_MASK;
frame_width = ((xres >> 3) << FRAME_WIDTH_POS) & FRAME_WIDTH_MASK;
- dcss_dtrc_write(dcss->dtrc_priv, ch_num - 1, frame_height | frame_width,
- DTRC_F0_OFS + DCSS_DTRC_SIZE);
- dcss_dtrc_write(dcss->dtrc_priv, ch_num - 1, frame_height | frame_width,
- DTRC_F1_OFS + DCSS_DTRC_SIZE);
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, frame_height | frame_width,
+ DTRC_F1_OFS * bank + DCSS_DTRC_SIZE);
+
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, frame_height | frame_width,
+ DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_SIZE);
}
EXPORT_SYMBOL(dcss_dtrc_set_res);
+
+void dcss_dtrc_enable(struct dcss_soc *dcss, int ch_num, bool enable)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
+ int curr_frame;
+ u32 fdctl, dtctrl;
+
+ if (ch_num == 0)
+ return;
+
+ ch_num -= 1;
+
+ ch = &dtrc->ch[ch_num];
+
+ if (ch->bypass)
+ return;
+
+ if (!enable) {
+ ch->running = false;
+ return;
+ }
+
+ if (ch->running)
+ return;
+
+ dcss_update(HOT_RESET, HOT_RESET, ch->base_reg + DCSS_DTRC_DTCTRL);
+ while (dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) & HOT_RESET)
+ usleep_range(100, 200);
+
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, 0x0f0e0100,
+ DCSS_DTRC_ARIDR);
+ dcss_dtrc_write(dcss->dtrc_priv, ch_num, 0x0f0e,
+ DCSS_DTRC_DTID2DDR);
+
+ dtctrl = ADDRESS_ID_ENABLE | MERGE_ARID_ENABLE |
+ ((0xF << TABLE_DATA_SWAP_POS) & TABLE_DATA_SWAP_MASK) |
+ ((0x10 << BURST_LENGTH_POS) & BURST_LENGTH_MASK);
+
+ if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G1_TILED)
+ dtctrl |= G1_TILED_DATA_EN;
+
+ dcss_dtrc_write(dtrc, ch_num, dtctrl, DCSS_DTRC_DTCTRL);
+
+ curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31;
+
+ fdctl = PIX_DEPTH_8BIT_EN;
+
+ if (ch->format_modifier != DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED)
+ fdctl |= COMPRESSION_DIS;
+
+ dcss_dtrc_write(dtrc, ch_num, fdctl,
+ (curr_frame ^ 1) * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+ dcss_dtrc_write(dtrc, ch_num, fdctl | (enable ? CONFIG_READY : 0),
+ curr_frame * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+
+ ch->curr_frame = curr_frame;
+ ch->dctl = fdctl;
+ ch->running = true;
+}
+EXPORT_SYMBOL(dcss_dtrc_enable);
+
+bool dcss_dtrc_is_running(struct dcss_soc *dcss, int ch_num)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
+
+ if (!ch_num)
+ return false;
+
+ ch_num -= 1;
+
+ ch = &dtrc->ch[ch_num];
+
+ return ch->running;
+}
+
+void dcss_dtrc_set_format_mod(struct dcss_soc *dcss, int ch_num, u64 modifier)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+ struct dcss_dtrc_ch *ch;
+
+ if (!ch_num)
+ return;
+
+ ch_num -= 1;
+
+ ch = &dtrc->ch[ch_num];
+
+ ch->format_modifier = modifier;
+}
+EXPORT_SYMBOL(dcss_dtrc_set_format_mod);
+
+static void dcss_dtrc_ch_switch_banks(struct dcss_dtrc_priv *dtrc, int dtrc_ch)
+{
+ struct dcss_dtrc_ch *ch = &dtrc->ch[dtrc_ch];
+
+ if (!ch->running)
+ return;
+
+ ch->curr_frame ^= 1;
+
+ dcss_dtrc_write_irqsafe(dtrc, dtrc_ch, ch->dctl | CONFIG_READY,
+ ch->curr_frame * DTRC_F1_OFS + DCSS_DTRC_DCTL);
+}
+
+void dcss_dtrc_switch_banks(struct dcss_soc *dcss)
+{
+ struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv;
+
+ dcss_dtrc_ch_switch_banks(dtrc, 0);
+ dcss_dtrc_ch_switch_banks(dtrc, 1);
+}