Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/intl/locales/et/hyphenation/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 34 kB image not shown  

SSL dcss-dtg.c   Sprache: unbekannt

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright 2019 NXP.
 */


#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>

#include "dcss-dev.h"

#define DCSS_DTG_TC_CONTROL_STATUS   0x00
#define   CH3_EN     BIT(0)
#define   CH2_EN     BIT(1)
#define   CH1_EN     BIT(2)
#define   OVL_DATA_MODE     BIT(3)
#define   BLENDER_VIDEO_ALPHA_SEL   BIT(7)
#define   DTG_START     BIT(8)
#define   DBY_MODE_EN     BIT(9)
#define   CH1_ALPHA_SEL     BIT(10)
#define   CSS_PIX_COMP_SWAP_POS    12
#define   CSS_PIX_COMP_SWAP_MASK   GENMASK(14, 12)
#define   DEFAULT_FG_ALPHA_POS    24
#define   DEFAULT_FG_ALPHA_MASK    GENMASK(31, 24)
#define DCSS_DTG_TC_DTG     0x04
#define DCSS_DTG_TC_DISP_TOP    0x08
#define DCSS_DTG_TC_DISP_BOT    0x0C
#define DCSS_DTG_TC_CH1_TOP    0x10
#define DCSS_DTG_TC_CH1_BOT    0x14
#define DCSS_DTG_TC_CH2_TOP    0x18
#define DCSS_DTG_TC_CH2_BOT    0x1C
#define DCSS_DTG_TC_CH3_TOP    0x20
#define DCSS_DTG_TC_CH3_BOT    0x24
#define   TC_X_POS     0
#define   TC_X_MASK     GENMASK(12, 0)
#define   TC_Y_POS     16
#define   TC_Y_MASK     GENMASK(28, 16)
#define DCSS_DTG_TC_CTXLD    0x28
#define   TC_CTXLD_DB_Y_POS    0
#define   TC_CTXLD_DB_Y_MASK    GENMASK(12, 0)
#define   TC_CTXLD_SB_Y_POS    16
#define   TC_CTXLD_SB_Y_MASK    GENMASK(28, 16)
#define DCSS_DTG_TC_CH1_BKRND    0x2C
#define DCSS_DTG_TC_CH2_BKRND    0x30
#define   BKRND_R_Y_COMP_POS    20
#define   BKRND_R_Y_COMP_MASK    GENMASK(29, 20)
#define   BKRND_G_U_COMP_POS    10
#define   BKRND_G_U_COMP_MASK    GENMASK(19, 10)
#define   BKRND_B_V_COMP_POS    0
#define   BKRND_B_V_COMP_MASK    GENMASK(9, 0)
#define DCSS_DTG_BLENDER_DBY_RANGEINV   0x38
#define DCSS_DTG_BLENDER_DBY_RANGEMIN   0x3C
#define DCSS_DTG_BLENDER_DBY_BDP   0x40
#define DCSS_DTG_BLENDER_BKRND_I   0x44
#define DCSS_DTG_BLENDER_BKRND_P   0x48
#define DCSS_DTG_BLENDER_BKRND_T   0x4C
#define DCSS_DTG_LINE0_INT    0x50
#define DCSS_DTG_LINE1_INT    0x54
#define DCSS_DTG_BG_ALPHA_DEFAULT   0x58
#define DCSS_DTG_INT_STATUS    0x5C
#define DCSS_DTG_INT_CONTROL    0x60
#define DCSS_DTG_TC_CH3_BKRND    0x64
#define DCSS_DTG_INT_MASK    0x68
#define   LINE0_IRQ     BIT(0)
#define   LINE1_IRQ     BIT(1)
#define   LINE2_IRQ     BIT(2)
#define   LINE3_IRQ     BIT(3)
#define DCSS_DTG_LINE2_INT    0x6C
#define DCSS_DTG_LINE3_INT    0x70
#define DCSS_DTG_DBY_OL     0x74
#define DCSS_DTG_DBY_BL     0x78
#define DCSS_DTG_DBY_EL     0x7C

struct dcss_dtg {
 struct device *dev;
 struct dcss_ctxld *ctxld;
 void __iomem *base_reg;
 u32 base_ofs;

 u32 ctx_id;

 bool in_use;

 u32 dis_ulc_x;
 u32 dis_ulc_y;

 u32 control_status;
 u32 alpha;
 u32 alpha_cfg;

 int ctxld_kick_irq;
 bool ctxld_kick_irq_en;
};

static void dcss_dtg_write(struct dcss_dtg *dtg, u32 val, u32 ofs)
{
 if (!dtg->in_use)
  dcss_writel(val, dtg->base_reg + ofs);

 dcss_ctxld_write(dtg->ctxld, dtg->ctx_id,
    val, dtg->base_ofs + ofs);
}

static irqreturn_t dcss_dtg_irq_handler(int irq, void *data)
{
 struct dcss_dtg *dtg = data;
 u32 status;

 status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);

 if (!(status & LINE0_IRQ))
  return IRQ_NONE;

 dcss_ctxld_kick(dtg->ctxld);

 dcss_writel(status & LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);

 return IRQ_HANDLED;
}

static int dcss_dtg_irq_config(struct dcss_dtg *dtg,
          struct platform_device *pdev)
{
 int ret;

 dtg->ctxld_kick_irq = platform_get_irq_byname(pdev, "ctxld_kick");
 if (dtg->ctxld_kick_irq < 0)
  return dtg->ctxld_kick_irq;

 dcss_update(0, LINE0_IRQ | LINE1_IRQ,
      dtg->base_reg + DCSS_DTG_INT_MASK);

 ret = request_irq(dtg->ctxld_kick_irq, dcss_dtg_irq_handler,
     IRQF_NO_AUTOEN, "dcss_ctxld_kick", dtg);
 if (ret) {
  dev_err(dtg->dev, "dtg: irq request failed.\n");
  return ret;
 }

 dtg->ctxld_kick_irq_en = false;

 return 0;
}

int dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base)
{
 int ret = 0;
 struct dcss_dtg *dtg;

 dtg = devm_kzalloc(dcss->dev, sizeof(*dtg), GFP_KERNEL);
 if (!dtg)
  return -ENOMEM;

 dcss->dtg = dtg;
 dtg->dev = dcss->dev;
 dtg->ctxld = dcss->ctxld;

 dtg->base_reg = devm_ioremap(dtg->dev, dtg_base, SZ_4K);
 if (!dtg->base_reg) {
  dev_err(dtg->dev, "dtg: unable to remap dtg base\n");
  return -ENOMEM;
 }

 dtg->base_ofs = dtg_base;
 dtg->ctx_id = CTX_DB;

 dtg->alpha = 255;

 dtg->control_status |= OVL_DATA_MODE | BLENDER_VIDEO_ALPHA_SEL |
  ((dtg->alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK);

 ret = dcss_dtg_irq_config(dtg, to_platform_device(dtg->dev));

 return ret;
}

void dcss_dtg_exit(struct dcss_dtg *dtg)
{
 free_irq(dtg->ctxld_kick_irq, dtg);
}

void dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm)
{
 struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dtg->dev);
 u16 dtg_lrc_x, dtg_lrc_y;
 u16 dis_ulc_x, dis_ulc_y;
 u16 dis_lrc_x, dis_lrc_y;
 u32 sb_ctxld_trig, db_ctxld_trig;
 u32 pixclock = vm->pixelclock;
 u32 actual_clk;

 dtg_lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
      vm->hactive - 1;
 dtg_lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
      vm->vactive - 1;
 dis_ulc_x = vm->hsync_len + vm->hback_porch - 1;
 dis_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch - 1;
 dis_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
 dis_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
      vm->vactive - 1;

 clk_disable_unprepare(dcss->pix_clk);
 clk_set_rate(dcss->pix_clk, vm->pixelclock);
 clk_prepare_enable(dcss->pix_clk);

 actual_clk = clk_get_rate(dcss->pix_clk);
 if (pixclock != actual_clk) {
  dev_info(dtg->dev,
    "Pixel clock set to %u kHz instead of %u kHz.\n",
    (actual_clk / 1000), (pixclock / 1000));
 }

 dcss_dtg_write(dtg, ((dtg_lrc_y << TC_Y_POS) | dtg_lrc_x),
         DCSS_DTG_TC_DTG);
 dcss_dtg_write(dtg, ((dis_ulc_y << TC_Y_POS) | dis_ulc_x),
         DCSS_DTG_TC_DISP_TOP);
 dcss_dtg_write(dtg, ((dis_lrc_y << TC_Y_POS) | dis_lrc_x),
         DCSS_DTG_TC_DISP_BOT);

 dtg->dis_ulc_x = dis_ulc_x;
 dtg->dis_ulc_y = dis_ulc_y;

 sb_ctxld_trig = ((0 * dis_lrc_y / 100) << TC_CTXLD_SB_Y_POS) &
       TC_CTXLD_SB_Y_MASK;
 db_ctxld_trig = ((99 * dis_lrc_y / 100) << TC_CTXLD_DB_Y_POS) &
       TC_CTXLD_DB_Y_MASK;

 dcss_dtg_write(dtg, sb_ctxld_trig | db_ctxld_trig, DCSS_DTG_TC_CTXLD);

 /* vblank trigger */
 dcss_dtg_write(dtg, 0, DCSS_DTG_LINE1_INT);

 /* CTXLD trigger */
 dcss_dtg_write(dtg, ((90 * dis_lrc_y) / 100) << 16, DCSS_DTG_LINE0_INT);
}

void dcss_dtg_plane_pos_set(struct dcss_dtg *dtg, int ch_num,
       int px, int py, int pw, int ph)
{
 u16 p_ulc_x, p_ulc_y;
 u16 p_lrc_x, p_lrc_y;

 p_ulc_x = dtg->dis_ulc_x + px;
 p_ulc_y = dtg->dis_ulc_y + py;
 p_lrc_x = p_ulc_x + pw;
 p_lrc_y = p_ulc_y + ph;

 if (!px && !py && !pw && !ph) {
  dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
  dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
 } else {
  dcss_dtg_write(dtg, ((p_ulc_y << TC_Y_POS) | p_ulc_x),
          DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
  dcss_dtg_write(dtg, ((p_lrc_y << TC_Y_POS) | p_lrc_x),
          DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
 }
}

bool dcss_dtg_global_alpha_changed(struct dcss_dtg *dtg, int ch_num, int alpha)
{
 if (ch_num)
  return false;

 return alpha != dtg->alpha;
}

void dcss_dtg_plane_alpha_set(struct dcss_dtg *dtg, int ch_num,
         const struct drm_format_info *format, int alpha)
{
 /* we care about alpha only when channel 0 is concerned */
 if (ch_num)
  return;

 /*
 * Use global alpha if pixel format does not have alpha channel or the
 * user explicitly chose to use global alpha (i.e. alpha is not OPAQUE).
 */

 if (!format->has_alpha || alpha != 255)
  dtg->alpha_cfg = (alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK;
 else /* use per-pixel alpha otherwise */
  dtg->alpha_cfg = CH1_ALPHA_SEL;

 dtg->alpha = alpha;
}

void dcss_dtg_css_set(struct dcss_dtg *dtg)
{
 dtg->control_status |=
   (0x5 << CSS_PIX_COMP_SWAP_POS) & CSS_PIX_COMP_SWAP_MASK;
}

void dcss_dtg_enable(struct dcss_dtg *dtg)
{
 dtg->control_status |= DTG_START;

 dtg->control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
 dtg->control_status |= dtg->alpha_cfg;

 dcss_dtg_write(dtg, dtg->control_status, DCSS_DTG_TC_CONTROL_STATUS);

 dtg->in_use = true;
}

void dcss_dtg_shutoff(struct dcss_dtg *dtg)
{
 dtg->control_status &= ~DTG_START;

 dcss_writel(dtg->control_status,
      dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);

 dtg->in_use = false;
}

bool dcss_dtg_is_enabled(struct dcss_dtg *dtg)
{
 return dtg->in_use;
}

void dcss_dtg_ch_enable(struct dcss_dtg *dtg, int ch_num, bool en)
{
 u32 ch_en_map[] = {CH1_EN, CH2_EN, CH3_EN};
 u32 control_status;

 control_status = dtg->control_status & ~ch_en_map[ch_num];
 control_status |= en ? ch_en_map[ch_num] : 0;

 control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
 control_status |= dtg->alpha_cfg;

 if (dtg->control_status != control_status)
  dcss_dtg_write(dtg, control_status, DCSS_DTG_TC_CONTROL_STATUS);

 dtg->control_status = control_status;
}

void dcss_dtg_vblank_irq_enable(struct dcss_dtg *dtg, bool en)
{
 u32 status;
 u32 mask = en ? LINE1_IRQ : 0;

 if (en) {
  status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
  dcss_writel(status & LINE1_IRQ,
       dtg->base_reg + DCSS_DTG_INT_CONTROL);
 }

 dcss_update(mask, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
}

void dcss_dtg_ctxld_kick_irq_enable(struct dcss_dtg *dtg, bool en)
{
 u32 status;
 u32 mask = en ? LINE0_IRQ : 0;

 if (en) {
  status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);

  if (!dtg->ctxld_kick_irq_en) {
   dcss_writel(status & LINE0_IRQ,
        dtg->base_reg + DCSS_DTG_INT_CONTROL);
   enable_irq(dtg->ctxld_kick_irq);
   dtg->ctxld_kick_irq_en = true;
   dcss_update(mask, LINE0_IRQ,
        dtg->base_reg + DCSS_DTG_INT_MASK);
  }

  return;
 }

 if (!dtg->ctxld_kick_irq_en)
  return;

 disable_irq_nosync(dtg->ctxld_kick_irq);
 dtg->ctxld_kick_irq_en = false;

 dcss_update(mask, LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
}

void dcss_dtg_vblank_irq_clear(struct dcss_dtg *dtg)
{
 dcss_update(LINE1_IRQ, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
}

bool dcss_dtg_vblank_irq_valid(struct dcss_dtg *dtg)
{
 return !!(dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS) & LINE1_IRQ);
}


Messung V0.5
C=96 H=95 G=95

[ Verzeichnis aufwärts0.12unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]