diff options
Diffstat (limited to 'drivers/gpu/imx/dcss/dcss-dtrc.c')
-rw-r--r-- | drivers/gpu/imx/dcss/dcss-dtrc.c | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/drivers/gpu/imx/dcss/dcss-dtrc.c b/drivers/gpu/imx/dcss/dcss-dtrc.c new file mode 100644 index 000000000000..5ce145388d6b --- /dev/null +++ b/drivers/gpu/imx/dcss/dcss-dtrc.c @@ -0,0 +1,612 @@ +/* + * Copyright (C) 2017 NXP + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#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 USE_CTXLD + +#define DTRC_F0_OFS 0x00 +#define DTRC_F1_OFS 0x60 + +#define DCSS_DTRC_DYDSADDR 0x00 +#define DCSS_DTRC_DCDSADDR 0x04 +#define DCSS_DTRC_DYTSADDR 0x08 +#define DCSS_DTRC_DCTSADDR 0x0C +#define DCSS_DTRC_SIZE 0x10 +#define FRAME_WIDTH_POS 0 +#define FRAME_WIDTH_MASK GENMASK(9, 0) +#define FRAME_HEIGHT_POS 16 +#define FRAME_HEIGHT_MASK GENMASK(25, 16) +#define DCSS_DTRC_SYSSA 0x14 +#define DCSS_DTRC_SYSEA 0x18 +#define DCSS_DTRC_SUVSSA 0x1C +#define DCSS_DTRC_SUVSEA 0x20 +#define DCSS_DTRC_CROPORIG 0x24 +#define DCSS_DTRC_CROPSIZE 0x28 +#define CROP_HEIGHT_POS 16 +#define CROP_HEIGHT_MASK GENMASK(28, 16) +#define CROP_WIDTH_POS 0 +#define CROP_WIDTH_MASK GENMASK(12, 0) +#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_DCTSADDR_EXT 0x3C +#define DCSS_DTRC_SYSSA_EXT 0x40 +#define DCSS_DTRC_SYSEA_EXT 0x44 +#define DCSS_DTRC_SUVSSA_EXT 0x48 +#define DCSS_DTRC_SUVSEA_EXT 0x4C + +#define DCSS_DTRC_INTEN 0xC0 +#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 +#define DCSS_DTRC_VER 0xD8 +#define DCSS_DTRC_PFCTRL 0xF0 +#define DCSS_DTRC_PFCR 0xF4 +#define DCSS_DTRC_TOCR 0xF8 + +#define TRACE_IRQ (1LL << 48) +#define TRACE_SWITCH_BANKS (2LL << 48) + +struct dcss_dtrc_ch { + void __iomem *base_reg; + u32 base_ofs; + + 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; + + int irq; + int ch_num; +}; + +struct dcss_dtrc_priv { + struct dcss_soc *dcss; + void __iomem *dtrc_reg; + + struct dcss_dtrc_ch ch[2]; +}; + +#ifdef CONFIG_DEBUG_FS +static struct dcss_debug_reg dtrc_frame_debug_reg[] = { + DCSS_DBG_REG(DCSS_DTRC_DYDSADDR), + DCSS_DBG_REG(DCSS_DTRC_DCDSADDR), + DCSS_DBG_REG(DCSS_DTRC_DYTSADDR), + DCSS_DBG_REG(DCSS_DTRC_DCTSADDR), + DCSS_DBG_REG(DCSS_DTRC_SIZE), + DCSS_DBG_REG(DCSS_DTRC_SYSSA), + DCSS_DBG_REG(DCSS_DTRC_SYSEA), + DCSS_DBG_REG(DCSS_DTRC_SUVSSA), + DCSS_DBG_REG(DCSS_DTRC_SUVSEA), + DCSS_DBG_REG(DCSS_DTRC_CROPORIG), + DCSS_DBG_REG(DCSS_DTRC_CROPSIZE), + DCSS_DBG_REG(DCSS_DTRC_DCTL), + DCSS_DBG_REG(DCSS_DTRC_DYDSADDR_EXT), + DCSS_DBG_REG(DCSS_DTRC_DCDSADDR_EXT), + DCSS_DBG_REG(DCSS_DTRC_DYTSADDR_EXT), + DCSS_DBG_REG(DCSS_DTRC_DCTSADDR_EXT), + DCSS_DBG_REG(DCSS_DTRC_SYSSA_EXT), + DCSS_DBG_REG(DCSS_DTRC_SYSEA_EXT), + DCSS_DBG_REG(DCSS_DTRC_SUVSSA_EXT), + DCSS_DBG_REG(DCSS_DTRC_SUVSEA_EXT), +}; + +static struct dcss_debug_reg dtrc_ctrl_debug_reg[] = { + DCSS_DBG_REG(DCSS_DTRC_INTEN), + DCSS_DBG_REG(DCSS_DTRC_FDINTR), + DCSS_DBG_REG(DCSS_DTRC_DTCTRL), + DCSS_DBG_REG(DCSS_DTRC_ARIDR), + DCSS_DBG_REG(DCSS_DTRC_DTID2DDR), + DCSS_DBG_REG(DCSS_DTRC_CONFIG), + DCSS_DBG_REG(DCSS_DTRC_VER), + DCSS_DBG_REG(DCSS_DTRC_PFCTRL), + DCSS_DBG_REG(DCSS_DTRC_PFCR), + DCSS_DBG_REG(DCSS_DTRC_TOCR), +}; + +static void dcss_dtrc_dump_frame_regs(struct seq_file *s, void *data, + int ch, int frame) +{ + struct dcss_soc *dcss = data; + int i; + + seq_printf(s, "\t>> Dumping F%d regs:\n", frame); + for (i = 0; i < ARRAY_SIZE(dtrc_frame_debug_reg); i++) + seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n", + dtrc_frame_debug_reg[i].name, + dtrc_frame_debug_reg[i].ofs + frame * DTRC_F1_OFS, + dcss_readl(dcss->dtrc_priv->ch[ch].base_reg + + dtrc_frame_debug_reg[i].ofs + + frame * DTRC_F1_OFS)); +} + +void dcss_dtrc_dump_regs(struct seq_file *s, void *data) +{ + struct dcss_soc *dcss = data; + int ch, fr, i; + + for (ch = 0; ch < 2; ch++) { + seq_printf(s, ">> Dumping DTRC for CH %d:\n", ch + 1); + for (fr = 0; fr < 2; fr++) + dcss_dtrc_dump_frame_regs(s, data, ch, fr); + + seq_printf(s, "\t>> Dumping DTRC CTRL regs for CH %d:\n", + ch + 1); + for (i = 0; i < ARRAY_SIZE(dtrc_ctrl_debug_reg); i++) + seq_printf(s, "\t%-35s(0x%04x) -> 0x%08x\n", + dtrc_ctrl_debug_reg[i].name, + dtrc_ctrl_debug_reg[i].ofs, + dcss_readl(dcss->dtrc_priv->ch[ch].base_reg + + dtrc_ctrl_debug_reg[i].ofs)); + } +} +#endif + +static irqreturn_t dcss_dtrc_irq_handler(int irq, void *data) +{ + struct dcss_dtrc_ch *ch = data; + u32 b0, b1, curr_bank; + + b0 = dcss_readl(ch->base_reg + DCSS_DTRC_DCTL) & 0x1; + b1 = dcss_readl(ch->base_reg + DTRC_F1_OFS + DCSS_DTRC_DCTL) & 0x1; + curr_bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31; + + dcss_trace_module(TRACE_DTRC, TRACE_IRQ | (ch->ch_num + 1) << 3 | + curr_bank << 2 | b0 << 0 | b1 << 1); + + dcss_update(1, 1, ch->base_reg + DCSS_DTRC_FDINTR); + + return IRQ_HANDLED; +} + +static int dcss_dtrc_irq_config(struct dcss_soc *dcss, int ch_num) +{ + struct platform_device *pdev = to_platform_device(dcss->dev); + struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv; + struct dcss_dtrc_ch *ch = &dtrc->ch[ch_num]; + char irq_name[20]; + int ret; + + sprintf(irq_name, "dtrc_ch%d", ch_num + 1); + irq_name[8] = 0; + + ch->irq = platform_get_irq_byname(pdev, irq_name); + if (ch->irq < 0) { + dev_err(dcss->dev, "dtrc: can't get DTRC irq\n"); + return ch->irq; + } + + ret = devm_request_irq(dcss->dev, ch->irq, + dcss_dtrc_irq_handler, + IRQF_TRIGGER_HIGH, + "dcss-dtrc", ch); + if (ret) { + dev_err(dcss->dev, "dtrc: irq request failed.\n"); + return ret; + } + + dcss_writel(1, ch->base_reg + DCSS_DTRC_INTEN); + + return 0; +} + +static int dcss_dtrc_ch_init_all(struct dcss_soc *dcss, unsigned long dtrc_base) +{ + struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv; + struct dcss_dtrc_ch *ch; + int i; + + for (i = 0; i < 2; i++) { + ch = &dtrc->ch[i]; + + ch->base_ofs = dtrc_base + i * 0x1000; + + ch->base_reg = devm_ioremap(dcss->dev, ch->base_ofs, SZ_4K); + if (!ch->base_reg) { + dev_err(dcss->dev, "dtrc: unable to remap ch base\n"); + return -ENOMEM; + } + + ch->ch_num = i; + + dcss_dtrc_irq_config(dcss, i); + +#if defined(USE_CTXLD) + ch->ctx_id = CTX_SB_HP; +#endif + } + + return 0; +} + +static void dcss_dtrc_write(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(dtrc->dcss, dtrc->ch[ch_num].ctx_id, + val, dtrc->ch[ch_num].base_ofs + ofs); +#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; + + dtrc = devm_kzalloc(dcss->dev, sizeof(*dtrc), GFP_KERNEL); + if (!dtrc) + return -ENOMEM; + + dcss->dtrc_priv = dtrc; + dtrc->dcss = dcss; + + return dcss_dtrc_ch_init_all(dcss, dtrc_base); +} + +void dcss_dtrc_exit(struct dcss_soc *dcss) +{ + struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv; + + /* reset the module to default */ + dcss_writel(HOT_RESET, dtrc->dtrc_reg + DCSS_DTRC_DTCTRL); +} + +void dcss_dtrc_bypass(struct dcss_soc *dcss, int ch_num) +{ + struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv; + + if (ch_num == 0) + return; + + ch_num -= 1; + + if (dtrc->ch[ch_num].bypass) + return; + + 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); + dcss_dtrc_write(dtrc, ch_num, 0x0f0e, DCSS_DTRC_DTID2DDR); + + dtrc->ch[ch_num].bypass = true; +} +EXPORT_SYMBOL(dcss_dtrc_bypass); + +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; + + if (ch_num == 0) + return; + + ch_num -= 1; + + 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); + + if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED) { + ch->y_dec_ofs = dec_table_ofs & 0xFFFFFFFF; + ch->uv_dec_ofs = dec_table_ofs >> 32; + + 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; +} +EXPORT_SYMBOL(dcss_dtrc_addr_set); + +void dcss_dtrc_set_res(struct dcss_soc *dcss, int ch_num, struct drm_rect *src, + struct drm_rect *old_src, u32 pixel_format) +{ + struct dcss_dtrc_priv *dtrc = dcss->dtrc_priv; + struct dcss_dtrc_ch *ch; + u32 frame_height, frame_width; + u32 crop_w, crop_h, crop_orig_w, crop_orig_h; + int bank; + u32 old_xres, old_yres, xres, yres; + u32 pix_depth; + u16 width_align = 0; + + if (ch_num == 0) + return; + + ch_num -= 1; + + ch = &dtrc->ch[ch_num]; + + bank = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31; + + ch->pix_format = pixel_format; + + pix_depth = ch->pix_format == DRM_FORMAT_P010 ? 10 : 8; + old_xres = old_src->x2 - old_src->x1; + old_yres = old_src->y2 - old_src->y1; + xres = src->x2 - src->x1; + yres = src->y2 - src->y1; + + frame_height = ((old_yres >> 3) << FRAME_HEIGHT_POS) & FRAME_HEIGHT_MASK; + frame_width = ((old_xres >> 3) << FRAME_WIDTH_POS) & FRAME_WIDTH_MASK; + + 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); + + /* + * Image original size is aligned: + * - 128 pixels for width (8-bit) or 256 (10-bit); + * - 8 lines for height; + */ + width_align = ch->pix_format == DRM_FORMAT_P010 ? 0xff : 0x7f; + if (xres == old_xres && !(xres & width_align) && + yres == old_yres && !(yres & 0xf)) { + ch->dctl &= ~CROPPING_EN; + goto exit; + } + + /* align the image size: down align for compressed formats */ + if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED && src->x1) + xres = xres & ~width_align; + else + xres = (xres - 1 + width_align) & ~width_align; + + if (ch->format_modifier == DRM_FORMAT_MOD_VSI_G2_TILED_COMPRESSED && src->y1) + yres = yres & ~0xf; + else + yres = (yres - 1 + 0xf) & ~0xf; + + src->x1 &= ~1; + src->x2 &= ~1; + + crop_orig_w = (src->x1 << CROP_WIDTH_POS) & CROP_WIDTH_MASK; + crop_orig_h = (src->y1 << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK; + + dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_orig_w | crop_orig_h, + DCSS_DTRC_CROPORIG); + dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_orig_w | crop_orig_h, + DTRC_F1_OFS + DCSS_DTRC_CROPORIG); + + crop_w = (xres << CROP_WIDTH_POS) & CROP_WIDTH_MASK; + crop_h = (yres << CROP_HEIGHT_POS) & CROP_HEIGHT_MASK; + + dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_w | crop_h, + DTRC_F1_OFS * bank + DCSS_DTRC_CROPSIZE); + dcss_dtrc_write(dcss->dtrc_priv, ch_num, crop_w | crop_h, + DTRC_F1_OFS * (bank ^ 1) + DCSS_DTRC_CROPSIZE); + + ch->dctl |= CROPPING_EN; + +exit: + dcss_dtrc_write(dtrc, ch_num, xres * yres * pix_depth / 8, + DCSS_DTRC_SYSEA); + dcss_dtrc_write(dtrc, ch_num, xres * yres * pix_depth / 8, + DTRC_F1_OFS + DCSS_DTRC_SYSEA); + + dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres * pix_depth / 8 / 2, + DCSS_DTRC_SUVSEA); + dcss_dtrc_write(dtrc, ch_num, 0x10000000 + xres * yres * pix_depth / 8 / 2, + DTRC_F1_OFS + DCSS_DTRC_SUVSEA); + + src->x2 = src->x1 + xres; + src->y2 = src->y1 + yres; + + if (ch->running) + return; + + dcss_dtrc_write(dtrc, ch_num, 0x0, DCSS_DTRC_SYSSA); + dcss_dtrc_write(dtrc, ch_num, 0x0, + DTRC_F1_OFS + DCSS_DTRC_SYSSA); + + dcss_dtrc_write(dtrc, ch_num, 0x10000000, DCSS_DTRC_SUVSSA); + dcss_dtrc_write(dtrc, ch_num, 0x10000000, + DTRC_F1_OFS + DCSS_DTRC_SUVSSA); +} +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 = ch->dctl & ~(PIX_DEPTH_8BIT_EN | COMPRESSION_DIS); + + fdctl |= ch->pix_format == DRM_FORMAT_P010 ? 0 : 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]; + u32 b0, b1; + + if (!ch->running) + return; + + b0 = dcss_readl(ch->base_reg + DCSS_DTRC_DCTL) & 0x1; + b1 = dcss_readl(ch->base_reg + DTRC_F1_OFS + DCSS_DTRC_DCTL) & 0x1; + + ch->curr_frame = dcss_readl(ch->base_reg + DCSS_DTRC_DTCTRL) >> 31; + + dcss_trace_module(TRACE_DTRC, TRACE_SWITCH_BANKS | + (dtrc_ch + 1) << 3 | ch->curr_frame << 2 | + b0 << 0 | b1 << 1); + + dcss_dtrc_write_irqsafe(dtrc, dtrc_ch, ch->dctl | CONFIG_READY, + (ch->curr_frame ^ 1) * 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); +} |