cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dpu_hw_intf.c (10782B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
      3 */
      4
      5#include "dpu_hwio.h"
      6#include "dpu_hw_catalog.h"
      7#include "dpu_hw_intf.h"
      8#include "dpu_kms.h"
      9
     10#define INTF_TIMING_ENGINE_EN           0x000
     11#define INTF_CONFIG                     0x004
     12#define INTF_HSYNC_CTL                  0x008
     13#define INTF_VSYNC_PERIOD_F0            0x00C
     14#define INTF_VSYNC_PERIOD_F1            0x010
     15#define INTF_VSYNC_PULSE_WIDTH_F0       0x014
     16#define INTF_VSYNC_PULSE_WIDTH_F1       0x018
     17#define INTF_DISPLAY_V_START_F0         0x01C
     18#define INTF_DISPLAY_V_START_F1         0x020
     19#define INTF_DISPLAY_V_END_F0           0x024
     20#define INTF_DISPLAY_V_END_F1           0x028
     21#define INTF_ACTIVE_V_START_F0          0x02C
     22#define INTF_ACTIVE_V_START_F1          0x030
     23#define INTF_ACTIVE_V_END_F0            0x034
     24#define INTF_ACTIVE_V_END_F1            0x038
     25#define INTF_DISPLAY_HCTL               0x03C
     26#define INTF_ACTIVE_HCTL                0x040
     27#define INTF_BORDER_COLOR               0x044
     28#define INTF_UNDERFLOW_COLOR            0x048
     29#define INTF_HSYNC_SKEW                 0x04C
     30#define INTF_POLARITY_CTL               0x050
     31#define INTF_TEST_CTL                   0x054
     32#define INTF_TP_COLOR0                  0x058
     33#define INTF_TP_COLOR1                  0x05C
     34#define INTF_CONFIG2                    0x060
     35#define INTF_DISPLAY_DATA_HCTL          0x064
     36#define INTF_ACTIVE_DATA_HCTL           0x068
     37#define INTF_FRAME_LINE_COUNT_EN        0x0A8
     38#define INTF_FRAME_COUNT                0x0AC
     39#define   INTF_LINE_COUNT               0x0B0
     40
     41#define   INTF_DEFLICKER_CONFIG         0x0F0
     42#define   INTF_DEFLICKER_STRNG_COEFF    0x0F4
     43#define   INTF_DEFLICKER_WEAK_COEFF     0x0F8
     44
     45#define   INTF_DSI_CMD_MODE_TRIGGER_EN  0x084
     46#define   INTF_PANEL_FORMAT             0x090
     47#define   INTF_TPG_ENABLE               0x100
     48#define   INTF_TPG_MAIN_CONTROL         0x104
     49#define   INTF_TPG_VIDEO_CONFIG         0x108
     50#define   INTF_TPG_COMPONENT_LIMITS     0x10C
     51#define   INTF_TPG_RECTANGLE            0x110
     52#define   INTF_TPG_INITIAL_VALUE        0x114
     53#define   INTF_TPG_BLK_WHITE_PATTERN_FRAMES   0x118
     54#define   INTF_TPG_RGB_MAPPING          0x11C
     55#define   INTF_PROG_FETCH_START         0x170
     56#define   INTF_PROG_ROT_START           0x174
     57
     58#define   INTF_FRAME_LINE_COUNT_EN      0x0A8
     59#define   INTF_FRAME_COUNT              0x0AC
     60#define   INTF_LINE_COUNT               0x0B0
     61
     62#define   INTF_MUX                      0x25C
     63
     64#define INTF_CFG_ACTIVE_H_EN	BIT(29)
     65#define INTF_CFG_ACTIVE_V_EN	BIT(30)
     66
     67#define INTF_CFG2_DATABUS_WIDEN	BIT(0)
     68#define INTF_CFG2_DATA_HCTL_EN	BIT(4)
     69
     70static const struct dpu_intf_cfg *_intf_offset(enum dpu_intf intf,
     71		const struct dpu_mdss_cfg *m,
     72		void __iomem *addr,
     73		struct dpu_hw_blk_reg_map *b)
     74{
     75	int i;
     76
     77	for (i = 0; i < m->intf_count; i++) {
     78		if ((intf == m->intf[i].id) &&
     79		(m->intf[i].type != INTF_NONE)) {
     80			b->base_off = addr;
     81			b->blk_off = m->intf[i].base;
     82			b->length = m->intf[i].len;
     83			b->hwversion = m->hwversion;
     84			b->log_mask = DPU_DBG_MASK_INTF;
     85			return &m->intf[i];
     86		}
     87	}
     88
     89	return ERR_PTR(-EINVAL);
     90}
     91
     92static void dpu_hw_intf_setup_timing_engine(struct dpu_hw_intf *ctx,
     93		const struct intf_timing_params *p,
     94		const struct dpu_format *fmt)
     95{
     96	struct dpu_hw_blk_reg_map *c = &ctx->hw;
     97	u32 hsync_period, vsync_period;
     98	u32 display_v_start, display_v_end;
     99	u32 hsync_start_x, hsync_end_x;
    100	u32 hsync_data_start_x, hsync_data_end_x;
    101	u32 active_h_start, active_h_end;
    102	u32 active_v_start, active_v_end;
    103	u32 active_hctl, display_hctl, hsync_ctl;
    104	u32 polarity_ctl, den_polarity, hsync_polarity, vsync_polarity;
    105	u32 panel_format;
    106	u32 intf_cfg, intf_cfg2 = 0;
    107	u32 display_data_hctl = 0, active_data_hctl = 0;
    108	u32 data_width;
    109	bool dp_intf = false;
    110
    111	/* read interface_cfg */
    112	intf_cfg = DPU_REG_READ(c, INTF_CONFIG);
    113
    114	if (ctx->cap->type == INTF_DP)
    115		dp_intf = true;
    116
    117	hsync_period = p->hsync_pulse_width + p->h_back_porch + p->width +
    118	p->h_front_porch;
    119	vsync_period = p->vsync_pulse_width + p->v_back_porch + p->height +
    120	p->v_front_porch;
    121
    122	display_v_start = ((p->vsync_pulse_width + p->v_back_porch) *
    123	hsync_period) + p->hsync_skew;
    124	display_v_end = ((vsync_period - p->v_front_porch) * hsync_period) +
    125	p->hsync_skew - 1;
    126
    127	hsync_start_x = p->h_back_porch + p->hsync_pulse_width;
    128	hsync_end_x = hsync_period - p->h_front_porch - 1;
    129
    130	if (p->width != p->xres) { /* border fill added */
    131		active_h_start = hsync_start_x;
    132		active_h_end = active_h_start + p->xres - 1;
    133	} else {
    134		active_h_start = 0;
    135		active_h_end = 0;
    136	}
    137
    138	if (p->height != p->yres) { /* border fill added */
    139		active_v_start = display_v_start;
    140		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
    141	} else {
    142		active_v_start = 0;
    143		active_v_end = 0;
    144	}
    145
    146	if (active_h_end) {
    147		active_hctl = (active_h_end << 16) | active_h_start;
    148		intf_cfg |= INTF_CFG_ACTIVE_H_EN;
    149	} else {
    150		active_hctl = 0;
    151	}
    152
    153	if (active_v_end)
    154		intf_cfg |= INTF_CFG_ACTIVE_V_EN;
    155
    156	hsync_ctl = (hsync_period << 16) | p->hsync_pulse_width;
    157	display_hctl = (hsync_end_x << 16) | hsync_start_x;
    158
    159	/*
    160	 * DATA_HCTL_EN controls data timing which can be different from
    161	 * video timing. It is recommended to enable it for all cases, except
    162	 * if compression is enabled in 1 pixel per clock mode
    163	 */
    164	if (p->wide_bus_en)
    165		intf_cfg2 |= INTF_CFG2_DATABUS_WIDEN | INTF_CFG2_DATA_HCTL_EN;
    166
    167	data_width = p->width;
    168
    169	hsync_data_start_x = hsync_start_x;
    170	hsync_data_end_x =  hsync_start_x + data_width - 1;
    171
    172	display_data_hctl = (hsync_data_end_x << 16) | hsync_data_start_x;
    173
    174	if (dp_intf) {
    175		/* DP timing adjustment */
    176		display_v_start += p->hsync_pulse_width + p->h_back_porch;
    177		display_v_end   -= p->h_front_porch;
    178
    179		active_h_start = hsync_start_x;
    180		active_h_end = active_h_start + p->xres - 1;
    181		active_v_start = display_v_start;
    182		active_v_end = active_v_start + (p->yres * hsync_period) - 1;
    183
    184		active_hctl = (active_h_end << 16) | active_h_start;
    185		display_hctl = active_hctl;
    186
    187		intf_cfg |= INTF_CFG_ACTIVE_H_EN | INTF_CFG_ACTIVE_V_EN;
    188	}
    189
    190	den_polarity = 0;
    191	if (ctx->cap->type == INTF_HDMI) {
    192		hsync_polarity = p->yres >= 720 ? 0 : 1;
    193		vsync_polarity = p->yres >= 720 ? 0 : 1;
    194	} else if (ctx->cap->type == INTF_DP) {
    195		hsync_polarity = p->hsync_polarity;
    196		vsync_polarity = p->vsync_polarity;
    197	} else {
    198		hsync_polarity = 0;
    199		vsync_polarity = 0;
    200	}
    201	polarity_ctl = (den_polarity << 2) | /*  DEN Polarity  */
    202		(vsync_polarity << 1) | /* VSYNC Polarity */
    203		(hsync_polarity << 0);  /* HSYNC Polarity */
    204
    205	if (!DPU_FORMAT_IS_YUV(fmt))
    206		panel_format = (fmt->bits[C0_G_Y] |
    207				(fmt->bits[C1_B_Cb] << 2) |
    208				(fmt->bits[C2_R_Cr] << 4) |
    209				(0x21 << 8));
    210	else
    211		/* Interface treats all the pixel data in RGB888 format */
    212		panel_format = (COLOR_8BIT |
    213				(COLOR_8BIT << 2) |
    214				(COLOR_8BIT << 4) |
    215				(0x21 << 8));
    216
    217	DPU_REG_WRITE(c, INTF_HSYNC_CTL, hsync_ctl);
    218	DPU_REG_WRITE(c, INTF_VSYNC_PERIOD_F0, vsync_period * hsync_period);
    219	DPU_REG_WRITE(c, INTF_VSYNC_PULSE_WIDTH_F0,
    220			p->vsync_pulse_width * hsync_period);
    221	DPU_REG_WRITE(c, INTF_DISPLAY_HCTL, display_hctl);
    222	DPU_REG_WRITE(c, INTF_DISPLAY_V_START_F0, display_v_start);
    223	DPU_REG_WRITE(c, INTF_DISPLAY_V_END_F0, display_v_end);
    224	DPU_REG_WRITE(c, INTF_ACTIVE_HCTL,  active_hctl);
    225	DPU_REG_WRITE(c, INTF_ACTIVE_V_START_F0, active_v_start);
    226	DPU_REG_WRITE(c, INTF_ACTIVE_V_END_F0, active_v_end);
    227	DPU_REG_WRITE(c, INTF_BORDER_COLOR, p->border_clr);
    228	DPU_REG_WRITE(c, INTF_UNDERFLOW_COLOR, p->underflow_clr);
    229	DPU_REG_WRITE(c, INTF_HSYNC_SKEW, p->hsync_skew);
    230	DPU_REG_WRITE(c, INTF_POLARITY_CTL, polarity_ctl);
    231	DPU_REG_WRITE(c, INTF_FRAME_LINE_COUNT_EN, 0x3);
    232	DPU_REG_WRITE(c, INTF_CONFIG, intf_cfg);
    233	DPU_REG_WRITE(c, INTF_PANEL_FORMAT, panel_format);
    234	if (ctx->cap->features & BIT(DPU_DATA_HCTL_EN)) {
    235		DPU_REG_WRITE(c, INTF_CONFIG2, intf_cfg2);
    236		DPU_REG_WRITE(c, INTF_DISPLAY_DATA_HCTL, display_data_hctl);
    237		DPU_REG_WRITE(c, INTF_ACTIVE_DATA_HCTL, active_data_hctl);
    238	}
    239}
    240
    241static void dpu_hw_intf_enable_timing_engine(
    242		struct dpu_hw_intf *intf,
    243		u8 enable)
    244{
    245	struct dpu_hw_blk_reg_map *c = &intf->hw;
    246	/* Note: Display interface select is handled in top block hw layer */
    247	DPU_REG_WRITE(c, INTF_TIMING_ENGINE_EN, enable != 0);
    248}
    249
    250static void dpu_hw_intf_setup_prg_fetch(
    251		struct dpu_hw_intf *intf,
    252		const struct intf_prog_fetch *fetch)
    253{
    254	struct dpu_hw_blk_reg_map *c = &intf->hw;
    255	int fetch_enable;
    256
    257	/*
    258	 * Fetch should always be outside the active lines. If the fetching
    259	 * is programmed within active region, hardware behavior is unknown.
    260	 */
    261
    262	fetch_enable = DPU_REG_READ(c, INTF_CONFIG);
    263	if (fetch->enable) {
    264		fetch_enable |= BIT(31);
    265		DPU_REG_WRITE(c, INTF_PROG_FETCH_START,
    266				fetch->fetch_start);
    267	} else {
    268		fetch_enable &= ~BIT(31);
    269	}
    270
    271	DPU_REG_WRITE(c, INTF_CONFIG, fetch_enable);
    272}
    273
    274static void dpu_hw_intf_bind_pingpong_blk(
    275		struct dpu_hw_intf *intf,
    276		bool enable,
    277		const enum dpu_pingpong pp)
    278{
    279	struct dpu_hw_blk_reg_map *c = &intf->hw;
    280	u32 mux_cfg;
    281
    282	mux_cfg = DPU_REG_READ(c, INTF_MUX);
    283	mux_cfg &= ~0xf;
    284
    285	if (enable)
    286		mux_cfg |= (pp - PINGPONG_0) & 0x7;
    287	else
    288		mux_cfg |= 0xf;
    289
    290	DPU_REG_WRITE(c, INTF_MUX, mux_cfg);
    291}
    292
    293static void dpu_hw_intf_get_status(
    294		struct dpu_hw_intf *intf,
    295		struct intf_status *s)
    296{
    297	struct dpu_hw_blk_reg_map *c = &intf->hw;
    298
    299	s->is_en = DPU_REG_READ(c, INTF_TIMING_ENGINE_EN);
    300	s->is_prog_fetch_en = !!(DPU_REG_READ(c, INTF_CONFIG) & BIT(31));
    301	if (s->is_en) {
    302		s->frame_count = DPU_REG_READ(c, INTF_FRAME_COUNT);
    303		s->line_count = DPU_REG_READ(c, INTF_LINE_COUNT);
    304	} else {
    305		s->line_count = 0;
    306		s->frame_count = 0;
    307	}
    308}
    309
    310static u32 dpu_hw_intf_get_line_count(struct dpu_hw_intf *intf)
    311{
    312	struct dpu_hw_blk_reg_map *c;
    313
    314	if (!intf)
    315		return 0;
    316
    317	c = &intf->hw;
    318
    319	return DPU_REG_READ(c, INTF_LINE_COUNT);
    320}
    321
    322static void _setup_intf_ops(struct dpu_hw_intf_ops *ops,
    323		unsigned long cap)
    324{
    325	ops->setup_timing_gen = dpu_hw_intf_setup_timing_engine;
    326	ops->setup_prg_fetch  = dpu_hw_intf_setup_prg_fetch;
    327	ops->get_status = dpu_hw_intf_get_status;
    328	ops->enable_timing = dpu_hw_intf_enable_timing_engine;
    329	ops->get_line_count = dpu_hw_intf_get_line_count;
    330	if (cap & BIT(DPU_INTF_INPUT_CTRL))
    331		ops->bind_pingpong_blk = dpu_hw_intf_bind_pingpong_blk;
    332}
    333
    334struct dpu_hw_intf *dpu_hw_intf_init(enum dpu_intf idx,
    335		void __iomem *addr,
    336		const struct dpu_mdss_cfg *m)
    337{
    338	struct dpu_hw_intf *c;
    339	const struct dpu_intf_cfg *cfg;
    340
    341	c = kzalloc(sizeof(*c), GFP_KERNEL);
    342	if (!c)
    343		return ERR_PTR(-ENOMEM);
    344
    345	cfg = _intf_offset(idx, m, addr, &c->hw);
    346	if (IS_ERR_OR_NULL(cfg)) {
    347		kfree(c);
    348		pr_err("failed to create dpu_hw_intf %d\n", idx);
    349		return ERR_PTR(-EINVAL);
    350	}
    351
    352	/*
    353	 * Assign ops
    354	 */
    355	c->idx = idx;
    356	c->cap = cfg;
    357	c->mdss = m;
    358	_setup_intf_ops(&c->ops, c->cap->features);
    359
    360	return c;
    361}
    362
    363void dpu_hw_intf_destroy(struct dpu_hw_intf *intf)
    364{
    365	kfree(intf);
    366}
    367