1 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. 2 * 3 * This program is free software; you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License version 2 and 5 * only version 2 as published by the Free Software Foundation. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 */ 12 13 #include "dpu_hwio.h" 14 #include "dpu_hw_catalog.h" 15 #include "dpu_hw_top.h" 16 #include "dpu_dbg.h" 17 #include "dpu_kms.h" 18 19 #define SSPP_SPARE 0x28 20 #define UBWC_STATIC 0x144 21 22 #define FLD_SPLIT_DISPLAY_CMD BIT(1) 23 #define FLD_SMART_PANEL_FREE_RUN BIT(2) 24 #define FLD_INTF_1_SW_TRG_MUX BIT(4) 25 #define FLD_INTF_2_SW_TRG_MUX BIT(8) 26 #define FLD_TE_LINE_INTER_WATERLEVEL_MASK 0xFFFF 27 28 #define DANGER_STATUS 0x360 29 #define SAFE_STATUS 0x364 30 31 #define TE_LINE_INTERVAL 0x3F4 32 33 #define TRAFFIC_SHAPER_EN BIT(31) 34 #define TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4)) 35 #define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4)) 36 #define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4 37 38 #define MDP_WD_TIMER_0_CTL 0x380 39 #define MDP_WD_TIMER_0_CTL2 0x384 40 #define MDP_WD_TIMER_0_LOAD_VALUE 0x388 41 #define MDP_WD_TIMER_1_CTL 0x390 42 #define MDP_WD_TIMER_1_CTL2 0x394 43 #define MDP_WD_TIMER_1_LOAD_VALUE 0x398 44 #define MDP_WD_TIMER_2_CTL 0x420 45 #define MDP_WD_TIMER_2_CTL2 0x424 46 #define MDP_WD_TIMER_2_LOAD_VALUE 0x428 47 #define MDP_WD_TIMER_3_CTL 0x430 48 #define MDP_WD_TIMER_3_CTL2 0x434 49 #define MDP_WD_TIMER_3_LOAD_VALUE 0x438 50 #define MDP_WD_TIMER_4_CTL 0x440 51 #define MDP_WD_TIMER_4_CTL2 0x444 52 #define MDP_WD_TIMER_4_LOAD_VALUE 0x448 53 54 #define MDP_TICK_COUNT 16 55 #define XO_CLK_RATE 19200 56 #define MS_TICKS_IN_SEC 1000 57 58 #define CALCULATE_WD_LOAD_VALUE(fps) \ 59 ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps))) 60 61 #define DCE_SEL 0x450 62 63 static void dpu_hw_setup_split_pipe(struct dpu_hw_mdp *mdp, 64 struct split_pipe_cfg *cfg) 65 { 66 struct dpu_hw_blk_reg_map *c; 67 u32 upper_pipe = 0; 68 u32 lower_pipe = 0; 69 70 if (!mdp || !cfg) 71 return; 72 73 c = &mdp->hw; 74 75 if (cfg->en) { 76 if (cfg->mode == INTF_MODE_CMD) { 77 lower_pipe = FLD_SPLIT_DISPLAY_CMD; 78 /* interface controlling sw trigger */ 79 if (cfg->intf == INTF_2) 80 lower_pipe |= FLD_INTF_1_SW_TRG_MUX; 81 else 82 lower_pipe |= FLD_INTF_2_SW_TRG_MUX; 83 upper_pipe = lower_pipe; 84 } else { 85 if (cfg->intf == INTF_2) { 86 lower_pipe = FLD_INTF_1_SW_TRG_MUX; 87 upper_pipe = FLD_INTF_2_SW_TRG_MUX; 88 } else { 89 lower_pipe = FLD_INTF_2_SW_TRG_MUX; 90 upper_pipe = FLD_INTF_1_SW_TRG_MUX; 91 } 92 } 93 } 94 95 DPU_REG_WRITE(c, SSPP_SPARE, cfg->split_flush_en ? 0x1 : 0x0); 96 DPU_REG_WRITE(c, SPLIT_DISPLAY_LOWER_PIPE_CTRL, lower_pipe); 97 DPU_REG_WRITE(c, SPLIT_DISPLAY_UPPER_PIPE_CTRL, upper_pipe); 98 DPU_REG_WRITE(c, SPLIT_DISPLAY_EN, cfg->en & 0x1); 99 } 100 101 static void dpu_hw_setup_cdm_output(struct dpu_hw_mdp *mdp, 102 struct cdm_output_cfg *cfg) 103 { 104 struct dpu_hw_blk_reg_map *c; 105 u32 out_ctl = 0; 106 107 if (!mdp || !cfg) 108 return; 109 110 c = &mdp->hw; 111 112 if (cfg->intf_en) 113 out_ctl |= BIT(19); 114 115 DPU_REG_WRITE(c, MDP_OUT_CTL_0, out_ctl); 116 } 117 118 static bool dpu_hw_setup_clk_force_ctrl(struct dpu_hw_mdp *mdp, 119 enum dpu_clk_ctrl_type clk_ctrl, bool enable) 120 { 121 struct dpu_hw_blk_reg_map *c; 122 u32 reg_off, bit_off; 123 u32 reg_val, new_val; 124 bool clk_forced_on; 125 126 if (!mdp) 127 return false; 128 129 c = &mdp->hw; 130 131 if (clk_ctrl <= DPU_CLK_CTRL_NONE || clk_ctrl >= DPU_CLK_CTRL_MAX) 132 return false; 133 134 reg_off = mdp->caps->clk_ctrls[clk_ctrl].reg_off; 135 bit_off = mdp->caps->clk_ctrls[clk_ctrl].bit_off; 136 137 reg_val = DPU_REG_READ(c, reg_off); 138 139 if (enable) 140 new_val = reg_val | BIT(bit_off); 141 else 142 new_val = reg_val & ~BIT(bit_off); 143 144 DPU_REG_WRITE(c, reg_off, new_val); 145 146 clk_forced_on = !(reg_val & BIT(bit_off)); 147 148 return clk_forced_on; 149 } 150 151 152 static void dpu_hw_get_danger_status(struct dpu_hw_mdp *mdp, 153 struct dpu_danger_safe_status *status) 154 { 155 struct dpu_hw_blk_reg_map *c; 156 u32 value; 157 158 if (!mdp || !status) 159 return; 160 161 c = &mdp->hw; 162 163 value = DPU_REG_READ(c, DANGER_STATUS); 164 status->mdp = (value >> 0) & 0x3; 165 status->sspp[SSPP_VIG0] = (value >> 4) & 0x3; 166 status->sspp[SSPP_VIG1] = (value >> 6) & 0x3; 167 status->sspp[SSPP_VIG2] = (value >> 8) & 0x3; 168 status->sspp[SSPP_VIG3] = (value >> 10) & 0x3; 169 status->sspp[SSPP_RGB0] = (value >> 12) & 0x3; 170 status->sspp[SSPP_RGB1] = (value >> 14) & 0x3; 171 status->sspp[SSPP_RGB2] = (value >> 16) & 0x3; 172 status->sspp[SSPP_RGB3] = (value >> 18) & 0x3; 173 status->sspp[SSPP_DMA0] = (value >> 20) & 0x3; 174 status->sspp[SSPP_DMA1] = (value >> 22) & 0x3; 175 status->sspp[SSPP_DMA2] = (value >> 28) & 0x3; 176 status->sspp[SSPP_DMA3] = (value >> 30) & 0x3; 177 status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x3; 178 status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x3; 179 } 180 181 static void dpu_hw_setup_vsync_source(struct dpu_hw_mdp *mdp, 182 struct dpu_vsync_source_cfg *cfg) 183 { 184 struct dpu_hw_blk_reg_map *c; 185 u32 reg, wd_load_value, wd_ctl, wd_ctl2, i; 186 static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18}; 187 188 if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber))) 189 return; 190 191 c = &mdp->hw; 192 reg = DPU_REG_READ(c, MDP_VSYNC_SEL); 193 for (i = 0; i < cfg->pp_count; i++) { 194 int pp_idx = cfg->ppnumber[i] - PINGPONG_0; 195 196 if (pp_idx >= ARRAY_SIZE(pp_offset)) 197 continue; 198 199 reg &= ~(0xf << pp_offset[pp_idx]); 200 reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx]; 201 } 202 DPU_REG_WRITE(c, MDP_VSYNC_SEL, reg); 203 204 if (cfg->vsync_source >= DPU_VSYNC_SOURCE_WD_TIMER_4 && 205 cfg->vsync_source <= DPU_VSYNC_SOURCE_WD_TIMER_0) { 206 switch (cfg->vsync_source) { 207 case DPU_VSYNC_SOURCE_WD_TIMER_4: 208 wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE; 209 wd_ctl = MDP_WD_TIMER_4_CTL; 210 wd_ctl2 = MDP_WD_TIMER_4_CTL2; 211 break; 212 case DPU_VSYNC_SOURCE_WD_TIMER_3: 213 wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE; 214 wd_ctl = MDP_WD_TIMER_3_CTL; 215 wd_ctl2 = MDP_WD_TIMER_3_CTL2; 216 break; 217 case DPU_VSYNC_SOURCE_WD_TIMER_2: 218 wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE; 219 wd_ctl = MDP_WD_TIMER_2_CTL; 220 wd_ctl2 = MDP_WD_TIMER_2_CTL2; 221 break; 222 case DPU_VSYNC_SOURCE_WD_TIMER_1: 223 wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE; 224 wd_ctl = MDP_WD_TIMER_1_CTL; 225 wd_ctl2 = MDP_WD_TIMER_1_CTL2; 226 break; 227 case DPU_VSYNC_SOURCE_WD_TIMER_0: 228 default: 229 wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE; 230 wd_ctl = MDP_WD_TIMER_0_CTL; 231 wd_ctl2 = MDP_WD_TIMER_0_CTL2; 232 break; 233 } 234 235 DPU_REG_WRITE(c, wd_load_value, 236 CALCULATE_WD_LOAD_VALUE(cfg->frame_rate)); 237 238 DPU_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */ 239 reg = DPU_REG_READ(c, wd_ctl2); 240 reg |= BIT(8); /* enable heartbeat timer */ 241 reg |= BIT(0); /* enable WD timer */ 242 DPU_REG_WRITE(c, wd_ctl2, reg); 243 244 /* make sure that timers are enabled/disabled for vsync state */ 245 wmb(); 246 } 247 } 248 249 static void dpu_hw_get_safe_status(struct dpu_hw_mdp *mdp, 250 struct dpu_danger_safe_status *status) 251 { 252 struct dpu_hw_blk_reg_map *c; 253 u32 value; 254 255 if (!mdp || !status) 256 return; 257 258 c = &mdp->hw; 259 260 value = DPU_REG_READ(c, SAFE_STATUS); 261 status->mdp = (value >> 0) & 0x1; 262 status->sspp[SSPP_VIG0] = (value >> 4) & 0x1; 263 status->sspp[SSPP_VIG1] = (value >> 6) & 0x1; 264 status->sspp[SSPP_VIG2] = (value >> 8) & 0x1; 265 status->sspp[SSPP_VIG3] = (value >> 10) & 0x1; 266 status->sspp[SSPP_RGB0] = (value >> 12) & 0x1; 267 status->sspp[SSPP_RGB1] = (value >> 14) & 0x1; 268 status->sspp[SSPP_RGB2] = (value >> 16) & 0x1; 269 status->sspp[SSPP_RGB3] = (value >> 18) & 0x1; 270 status->sspp[SSPP_DMA0] = (value >> 20) & 0x1; 271 status->sspp[SSPP_DMA1] = (value >> 22) & 0x1; 272 status->sspp[SSPP_DMA2] = (value >> 28) & 0x1; 273 status->sspp[SSPP_DMA3] = (value >> 30) & 0x1; 274 status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x1; 275 status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x1; 276 } 277 278 static void dpu_hw_reset_ubwc(struct dpu_hw_mdp *mdp, struct dpu_mdss_cfg *m) 279 { 280 struct dpu_hw_blk_reg_map c; 281 282 if (!mdp || !m) 283 return; 284 285 if (!IS_UBWC_20_SUPPORTED(m->caps->ubwc_version)) 286 return; 287 288 /* force blk offset to zero to access beginning of register region */ 289 c = mdp->hw; 290 c.blk_off = 0x0; 291 DPU_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static); 292 } 293 294 static void dpu_hw_intf_audio_select(struct dpu_hw_mdp *mdp) 295 { 296 struct dpu_hw_blk_reg_map *c; 297 298 if (!mdp) 299 return; 300 301 c = &mdp->hw; 302 303 DPU_REG_WRITE(c, HDMI_DP_CORE_SELECT, 0x1); 304 } 305 306 static void _setup_mdp_ops(struct dpu_hw_mdp_ops *ops, 307 unsigned long cap) 308 { 309 ops->setup_split_pipe = dpu_hw_setup_split_pipe; 310 ops->setup_cdm_output = dpu_hw_setup_cdm_output; 311 ops->setup_clk_force_ctrl = dpu_hw_setup_clk_force_ctrl; 312 ops->get_danger_status = dpu_hw_get_danger_status; 313 ops->setup_vsync_source = dpu_hw_setup_vsync_source; 314 ops->get_safe_status = dpu_hw_get_safe_status; 315 ops->reset_ubwc = dpu_hw_reset_ubwc; 316 ops->intf_audio_select = dpu_hw_intf_audio_select; 317 } 318 319 static const struct dpu_mdp_cfg *_top_offset(enum dpu_mdp mdp, 320 const struct dpu_mdss_cfg *m, 321 void __iomem *addr, 322 struct dpu_hw_blk_reg_map *b) 323 { 324 int i; 325 326 if (!m || !addr || !b) 327 return ERR_PTR(-EINVAL); 328 329 for (i = 0; i < m->mdp_count; i++) { 330 if (mdp == m->mdp[i].id) { 331 b->base_off = addr; 332 b->blk_off = m->mdp[i].base; 333 b->length = m->mdp[i].len; 334 b->hwversion = m->hwversion; 335 b->log_mask = DPU_DBG_MASK_TOP; 336 return &m->mdp[i]; 337 } 338 } 339 340 return ERR_PTR(-EINVAL); 341 } 342 343 static struct dpu_hw_blk_ops dpu_hw_ops = { 344 .start = NULL, 345 .stop = NULL, 346 }; 347 348 struct dpu_hw_mdp *dpu_hw_mdptop_init(enum dpu_mdp idx, 349 void __iomem *addr, 350 const struct dpu_mdss_cfg *m) 351 { 352 struct dpu_hw_mdp *mdp; 353 const struct dpu_mdp_cfg *cfg; 354 int rc; 355 356 if (!addr || !m) 357 return ERR_PTR(-EINVAL); 358 359 mdp = kzalloc(sizeof(*mdp), GFP_KERNEL); 360 if (!mdp) 361 return ERR_PTR(-ENOMEM); 362 363 cfg = _top_offset(idx, m, addr, &mdp->hw); 364 if (IS_ERR_OR_NULL(cfg)) { 365 kfree(mdp); 366 return ERR_PTR(-EINVAL); 367 } 368 369 /* 370 * Assign ops 371 */ 372 mdp->idx = idx; 373 mdp->caps = cfg; 374 _setup_mdp_ops(&mdp->ops, mdp->caps->features); 375 376 rc = dpu_hw_blk_init(&mdp->base, DPU_HW_BLK_TOP, idx, &dpu_hw_ops); 377 if (rc) { 378 DPU_ERROR("failed to init hw blk %d\n", rc); 379 goto blk_init_error; 380 } 381 382 dpu_dbg_set_dpu_top_offset(mdp->hw.blk_off); 383 384 return mdp; 385 386 blk_init_error: 387 kzfree(mdp); 388 389 return ERR_PTR(rc); 390 } 391 392 void dpu_hw_mdp_destroy(struct dpu_hw_mdp *mdp) 393 { 394 if (mdp) 395 dpu_hw_blk_destroy(&mdp->base); 396 kfree(mdp); 397 } 398 399