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_top.c (9128B)


      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_top.h"
      8#include "dpu_kms.h"
      9
     10#define SSPP_SPARE                        0x28
     11
     12#define FLD_SPLIT_DISPLAY_CMD             BIT(1)
     13#define FLD_SMART_PANEL_FREE_RUN          BIT(2)
     14#define FLD_INTF_1_SW_TRG_MUX             BIT(4)
     15#define FLD_INTF_2_SW_TRG_MUX             BIT(8)
     16#define FLD_TE_LINE_INTER_WATERLEVEL_MASK 0xFFFF
     17
     18#define DANGER_STATUS                     0x360
     19#define SAFE_STATUS                       0x364
     20
     21#define TE_LINE_INTERVAL                  0x3F4
     22
     23#define TRAFFIC_SHAPER_EN                 BIT(31)
     24#define TRAFFIC_SHAPER_RD_CLIENT(num)     (0x030 + (num * 4))
     25#define TRAFFIC_SHAPER_WR_CLIENT(num)     (0x060 + (num * 4))
     26#define TRAFFIC_SHAPER_FIXPOINT_FACTOR    4
     27
     28#define MDP_WD_TIMER_0_CTL                0x380
     29#define MDP_WD_TIMER_0_CTL2               0x384
     30#define MDP_WD_TIMER_0_LOAD_VALUE         0x388
     31#define MDP_WD_TIMER_1_CTL                0x390
     32#define MDP_WD_TIMER_1_CTL2               0x394
     33#define MDP_WD_TIMER_1_LOAD_VALUE         0x398
     34#define MDP_WD_TIMER_2_CTL                0x420
     35#define MDP_WD_TIMER_2_CTL2               0x424
     36#define MDP_WD_TIMER_2_LOAD_VALUE         0x428
     37#define MDP_WD_TIMER_3_CTL                0x430
     38#define MDP_WD_TIMER_3_CTL2               0x434
     39#define MDP_WD_TIMER_3_LOAD_VALUE         0x438
     40#define MDP_WD_TIMER_4_CTL                0x440
     41#define MDP_WD_TIMER_4_CTL2               0x444
     42#define MDP_WD_TIMER_4_LOAD_VALUE         0x448
     43
     44#define MDP_TICK_COUNT                    16
     45#define XO_CLK_RATE                       19200
     46#define MS_TICKS_IN_SEC                   1000
     47
     48#define CALCULATE_WD_LOAD_VALUE(fps) \
     49	((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps)))
     50
     51#define DCE_SEL                           0x450
     52
     53static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp,
     54		struct split_pipe_cfg *cfg)
     55{
     56	struct dpu_hw_blk_reg_map *c;
     57	u32 upper_pipe = 0;
     58	u32 lower_pipe = 0;
     59
     60	if (!mdp || !cfg)
     61		return;
     62
     63	c = &mdp->hw;
     64
     65	if (cfg->en) {
     66		if (cfg->mode == INTF_MODE_CMD) {
     67			lower_pipe = FLD_SPLIT_DISPLAY_CMD;
     68			/* interface controlling sw trigger */
     69			if (cfg->intf == INTF_2)
     70				lower_pipe |= FLD_INTF_1_SW_TRG_MUX;
     71			else
     72				lower_pipe |= FLD_INTF_2_SW_TRG_MUX;
     73			upper_pipe = lower_pipe;
     74		} else {
     75			if (cfg->intf == INTF_2) {
     76				lower_pipe = FLD_INTF_1_SW_TRG_MUX;
     77				upper_pipe = FLD_INTF_2_SW_TRG_MUX;
     78			} else {
     79				lower_pipe = FLD_INTF_2_SW_TRG_MUX;
     80				upper_pipe = FLD_INTF_1_SW_TRG_MUX;
     81			}
     82		}
     83	}
     84
     85	DPU_REG_WRITE(c, SSPP_SPARE, cfg->split_flush_en ? 0x1 : 0x0);
     86	DPU_REG_WRITE(c, SPLIT_DISPLAY_LOWER_PIPE_CTRL, lower_pipe);
     87	DPU_REG_WRITE(c, SPLIT_DISPLAY_UPPER_PIPE_CTRL, upper_pipe);
     88	DPU_REG_WRITE(c, SPLIT_DISPLAY_EN, cfg->en & 0x1);
     89}
     90
     91static bool dpu_hw_setup_clk_force_ctrl(struct dpu_hw_mdp *mdp,
     92		enum dpu_clk_ctrl_type clk_ctrl, bool enable)
     93{
     94	struct dpu_hw_blk_reg_map *c;
     95	u32 reg_off, bit_off;
     96	u32 reg_val, new_val;
     97	bool clk_forced_on;
     98
     99	if (!mdp)
    100		return false;
    101
    102	c = &mdp->hw;
    103
    104	if (clk_ctrl <= DPU_CLK_CTRL_NONE || clk_ctrl >= DPU_CLK_CTRL_MAX)
    105		return false;
    106
    107	reg_off = mdp->caps->clk_ctrls[clk_ctrl].reg_off;
    108	bit_off = mdp->caps->clk_ctrls[clk_ctrl].bit_off;
    109
    110	reg_val = DPU_REG_READ(c, reg_off);
    111
    112	if (enable)
    113		new_val = reg_val | BIT(bit_off);
    114	else
    115		new_val = reg_val & ~BIT(bit_off);
    116
    117	DPU_REG_WRITE(c, reg_off, new_val);
    118
    119	clk_forced_on = !(reg_val & BIT(bit_off));
    120
    121	return clk_forced_on;
    122}
    123
    124
    125static void dpu_hw_get_danger_status(struct dpu_hw_mdp *mdp,
    126		struct dpu_danger_safe_status *status)
    127{
    128	struct dpu_hw_blk_reg_map *c;
    129	u32 value;
    130
    131	if (!mdp || !status)
    132		return;
    133
    134	c = &mdp->hw;
    135
    136	value = DPU_REG_READ(c, DANGER_STATUS);
    137	status->mdp = (value >> 0) & 0x3;
    138	status->sspp[SSPP_VIG0] = (value >> 4) & 0x3;
    139	status->sspp[SSPP_VIG1] = (value >> 6) & 0x3;
    140	status->sspp[SSPP_VIG2] = (value >> 8) & 0x3;
    141	status->sspp[SSPP_VIG3] = (value >> 10) & 0x3;
    142	status->sspp[SSPP_RGB0] = (value >> 12) & 0x3;
    143	status->sspp[SSPP_RGB1] = (value >> 14) & 0x3;
    144	status->sspp[SSPP_RGB2] = (value >> 16) & 0x3;
    145	status->sspp[SSPP_RGB3] = (value >> 18) & 0x3;
    146	status->sspp[SSPP_DMA0] = (value >> 20) & 0x3;
    147	status->sspp[SSPP_DMA1] = (value >> 22) & 0x3;
    148	status->sspp[SSPP_DMA2] = (value >> 28) & 0x3;
    149	status->sspp[SSPP_DMA3] = (value >> 30) & 0x3;
    150	status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x3;
    151	status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x3;
    152}
    153
    154static void dpu_hw_setup_vsync_source(struct dpu_hw_mdp *mdp,
    155		struct dpu_vsync_source_cfg *cfg)
    156{
    157	struct dpu_hw_blk_reg_map *c;
    158	u32 reg, wd_load_value, wd_ctl, wd_ctl2, i;
    159	static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18};
    160
    161	if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber)))
    162		return;
    163
    164	c = &mdp->hw;
    165	reg = DPU_REG_READ(c, MDP_VSYNC_SEL);
    166	for (i = 0; i < cfg->pp_count; i++) {
    167		int pp_idx = cfg->ppnumber[i] - PINGPONG_0;
    168
    169		if (pp_idx >= ARRAY_SIZE(pp_offset))
    170			continue;
    171
    172		reg &= ~(0xf << pp_offset[pp_idx]);
    173		reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx];
    174	}
    175	DPU_REG_WRITE(c, MDP_VSYNC_SEL, reg);
    176
    177	if (cfg->vsync_source >= DPU_VSYNC_SOURCE_WD_TIMER_4 &&
    178			cfg->vsync_source <= DPU_VSYNC_SOURCE_WD_TIMER_0) {
    179		switch (cfg->vsync_source) {
    180		case DPU_VSYNC_SOURCE_WD_TIMER_4:
    181			wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE;
    182			wd_ctl = MDP_WD_TIMER_4_CTL;
    183			wd_ctl2 = MDP_WD_TIMER_4_CTL2;
    184			break;
    185		case DPU_VSYNC_SOURCE_WD_TIMER_3:
    186			wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE;
    187			wd_ctl = MDP_WD_TIMER_3_CTL;
    188			wd_ctl2 = MDP_WD_TIMER_3_CTL2;
    189			break;
    190		case DPU_VSYNC_SOURCE_WD_TIMER_2:
    191			wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE;
    192			wd_ctl = MDP_WD_TIMER_2_CTL;
    193			wd_ctl2 = MDP_WD_TIMER_2_CTL2;
    194			break;
    195		case DPU_VSYNC_SOURCE_WD_TIMER_1:
    196			wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE;
    197			wd_ctl = MDP_WD_TIMER_1_CTL;
    198			wd_ctl2 = MDP_WD_TIMER_1_CTL2;
    199			break;
    200		case DPU_VSYNC_SOURCE_WD_TIMER_0:
    201		default:
    202			wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE;
    203			wd_ctl = MDP_WD_TIMER_0_CTL;
    204			wd_ctl2 = MDP_WD_TIMER_0_CTL2;
    205			break;
    206		}
    207
    208		DPU_REG_WRITE(c, wd_load_value,
    209			CALCULATE_WD_LOAD_VALUE(cfg->frame_rate));
    210
    211		DPU_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */
    212		reg = DPU_REG_READ(c, wd_ctl2);
    213		reg |= BIT(8);		/* enable heartbeat timer */
    214		reg |= BIT(0);		/* enable WD timer */
    215		DPU_REG_WRITE(c, wd_ctl2, reg);
    216
    217		/* make sure that timers are enabled/disabled for vsync state */
    218		wmb();
    219	}
    220}
    221
    222static void dpu_hw_get_safe_status(struct dpu_hw_mdp *mdp,
    223		struct dpu_danger_safe_status *status)
    224{
    225	struct dpu_hw_blk_reg_map *c;
    226	u32 value;
    227
    228	if (!mdp || !status)
    229		return;
    230
    231	c = &mdp->hw;
    232
    233	value = DPU_REG_READ(c, SAFE_STATUS);
    234	status->mdp = (value >> 0) & 0x1;
    235	status->sspp[SSPP_VIG0] = (value >> 4) & 0x1;
    236	status->sspp[SSPP_VIG1] = (value >> 6) & 0x1;
    237	status->sspp[SSPP_VIG2] = (value >> 8) & 0x1;
    238	status->sspp[SSPP_VIG3] = (value >> 10) & 0x1;
    239	status->sspp[SSPP_RGB0] = (value >> 12) & 0x1;
    240	status->sspp[SSPP_RGB1] = (value >> 14) & 0x1;
    241	status->sspp[SSPP_RGB2] = (value >> 16) & 0x1;
    242	status->sspp[SSPP_RGB3] = (value >> 18) & 0x1;
    243	status->sspp[SSPP_DMA0] = (value >> 20) & 0x1;
    244	status->sspp[SSPP_DMA1] = (value >> 22) & 0x1;
    245	status->sspp[SSPP_DMA2] = (value >> 28) & 0x1;
    246	status->sspp[SSPP_DMA3] = (value >> 30) & 0x1;
    247	status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x1;
    248	status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x1;
    249}
    250
    251static void dpu_hw_intf_audio_select(struct dpu_hw_mdp *mdp)
    252{
    253	struct dpu_hw_blk_reg_map *c;
    254
    255	if (!mdp)
    256		return;
    257
    258	c = &mdp->hw;
    259
    260	DPU_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1);
    261}
    262
    263static void _setup_mdp_ops(struct dpu_hw_mdp_ops *ops,
    264		unsigned long cap)
    265{
    266	ops->setup_split_pipe = dpu_hw_setup_split_pipe;
    267	ops->setup_clk_force_ctrl = dpu_hw_setup_clk_force_ctrl;
    268	ops->get_danger_status = dpu_hw_get_danger_status;
    269	ops->setup_vsync_source = dpu_hw_setup_vsync_source;
    270	ops->get_safe_status = dpu_hw_get_safe_status;
    271
    272	if (cap & BIT(DPU_MDP_AUDIO_SELECT))
    273		ops->intf_audio_select = dpu_hw_intf_audio_select;
    274}
    275
    276static const struct dpu_mdp_cfg *_top_offset(enum dpu_mdp mdp,
    277		const struct dpu_mdss_cfg *m,
    278		void __iomem *addr,
    279		struct dpu_hw_blk_reg_map *b)
    280{
    281	int i;
    282
    283	if (!m || !addr || !b)
    284		return ERR_PTR(-EINVAL);
    285
    286	for (i = 0; i < m->mdp_count; i++) {
    287		if (mdp == m->mdp[i].id) {
    288			b->base_off = addr;
    289			b->blk_off = m->mdp[i].base;
    290			b->length = m->mdp[i].len;
    291			b->hwversion = m->hwversion;
    292			b->log_mask = DPU_DBG_MASK_TOP;
    293			return &m->mdp[i];
    294		}
    295	}
    296
    297	return ERR_PTR(-EINVAL);
    298}
    299
    300struct dpu_hw_mdp *dpu_hw_mdptop_init(enum dpu_mdp idx,
    301		void __iomem *addr,
    302		const struct dpu_mdss_cfg *m)
    303{
    304	struct dpu_hw_mdp *mdp;
    305	const struct dpu_mdp_cfg *cfg;
    306
    307	if (!addr || !m)
    308		return ERR_PTR(-EINVAL);
    309
    310	mdp = kzalloc(sizeof(*mdp), GFP_KERNEL);
    311	if (!mdp)
    312		return ERR_PTR(-ENOMEM);
    313
    314	cfg = _top_offset(idx, m, addr, &mdp->hw);
    315	if (IS_ERR_OR_NULL(cfg)) {
    316		kfree(mdp);
    317		return ERR_PTR(-EINVAL);
    318	}
    319
    320	/*
    321	 * Assign ops
    322	 */
    323	mdp->idx = idx;
    324	mdp->caps = cfg;
    325	_setup_mdp_ops(&mdp->ops, mdp->caps->features);
    326
    327	return mdp;
    328}
    329
    330void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp)
    331{
    332	kfree(mdp);
    333}
    334