125fdd593SJeykumar Sankaran /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. 225fdd593SJeykumar Sankaran * 325fdd593SJeykumar Sankaran * This program is free software; you can redistribute it and/or modify 425fdd593SJeykumar Sankaran * it under the terms of the GNU General Public License version 2 and 525fdd593SJeykumar Sankaran * only version 2 as published by the Free Software Foundation. 625fdd593SJeykumar Sankaran * 725fdd593SJeykumar Sankaran * This program is distributed in the hope that it will be useful, 825fdd593SJeykumar Sankaran * but WITHOUT ANY WARRANTY; without even the implied warranty of 925fdd593SJeykumar Sankaran * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1025fdd593SJeykumar Sankaran * GNU General Public License for more details. 1125fdd593SJeykumar Sankaran */ 1225fdd593SJeykumar Sankaran 1325fdd593SJeykumar Sankaran #include <linux/delay.h> 1425fdd593SJeykumar Sankaran #include "dpu_hwio.h" 1525fdd593SJeykumar Sankaran #include "dpu_hw_ctl.h" 1625fdd593SJeykumar Sankaran #include "dpu_kms.h" 17812eeeb6SSean Paul #include "dpu_trace.h" 1825fdd593SJeykumar Sankaran 1925fdd593SJeykumar Sankaran #define CTL_LAYER(lm) \ 2025fdd593SJeykumar Sankaran (((lm) == LM_5) ? (0x024) : (((lm) - LM_0) * 0x004)) 2125fdd593SJeykumar Sankaran #define CTL_LAYER_EXT(lm) \ 2225fdd593SJeykumar Sankaran (0x40 + (((lm) - LM_0) * 0x004)) 2325fdd593SJeykumar Sankaran #define CTL_LAYER_EXT2(lm) \ 2425fdd593SJeykumar Sankaran (0x70 + (((lm) - LM_0) * 0x004)) 2525fdd593SJeykumar Sankaran #define CTL_LAYER_EXT3(lm) \ 2625fdd593SJeykumar Sankaran (0xA0 + (((lm) - LM_0) * 0x004)) 2725fdd593SJeykumar Sankaran #define CTL_TOP 0x014 2825fdd593SJeykumar Sankaran #define CTL_FLUSH 0x018 2925fdd593SJeykumar Sankaran #define CTL_START 0x01C 3025fdd593SJeykumar Sankaran #define CTL_PREPARE 0x0d0 3125fdd593SJeykumar Sankaran #define CTL_SW_RESET 0x030 3225fdd593SJeykumar Sankaran #define CTL_LAYER_EXTN_OFFSET 0x40 3325fdd593SJeykumar Sankaran 3425fdd593SJeykumar Sankaran #define CTL_MIXER_BORDER_OUT BIT(24) 3525fdd593SJeykumar Sankaran #define CTL_FLUSH_MASK_CTL BIT(17) 3625fdd593SJeykumar Sankaran 3725fdd593SJeykumar Sankaran #define DPU_REG_RESET_TIMEOUT_US 2000 3825fdd593SJeykumar Sankaran 3925fdd593SJeykumar Sankaran static struct dpu_ctl_cfg *_ctl_offset(enum dpu_ctl ctl, 4025fdd593SJeykumar Sankaran struct dpu_mdss_cfg *m, 4125fdd593SJeykumar Sankaran void __iomem *addr, 4225fdd593SJeykumar Sankaran struct dpu_hw_blk_reg_map *b) 4325fdd593SJeykumar Sankaran { 4425fdd593SJeykumar Sankaran int i; 4525fdd593SJeykumar Sankaran 4625fdd593SJeykumar Sankaran for (i = 0; i < m->ctl_count; i++) { 4725fdd593SJeykumar Sankaran if (ctl == m->ctl[i].id) { 4825fdd593SJeykumar Sankaran b->base_off = addr; 4925fdd593SJeykumar Sankaran b->blk_off = m->ctl[i].base; 5025fdd593SJeykumar Sankaran b->length = m->ctl[i].len; 5125fdd593SJeykumar Sankaran b->hwversion = m->hwversion; 5225fdd593SJeykumar Sankaran b->log_mask = DPU_DBG_MASK_CTL; 5325fdd593SJeykumar Sankaran return &m->ctl[i]; 5425fdd593SJeykumar Sankaran } 5525fdd593SJeykumar Sankaran } 5625fdd593SJeykumar Sankaran return ERR_PTR(-ENOMEM); 5725fdd593SJeykumar Sankaran } 5825fdd593SJeykumar Sankaran 5925fdd593SJeykumar Sankaran static int _mixer_stages(const struct dpu_lm_cfg *mixer, int count, 6025fdd593SJeykumar Sankaran enum dpu_lm lm) 6125fdd593SJeykumar Sankaran { 6225fdd593SJeykumar Sankaran int i; 6325fdd593SJeykumar Sankaran int stages = -EINVAL; 6425fdd593SJeykumar Sankaran 6525fdd593SJeykumar Sankaran for (i = 0; i < count; i++) { 6625fdd593SJeykumar Sankaran if (lm == mixer[i].id) { 6725fdd593SJeykumar Sankaran stages = mixer[i].sblk->maxblendstages; 6825fdd593SJeykumar Sankaran break; 6925fdd593SJeykumar Sankaran } 7025fdd593SJeykumar Sankaran } 7125fdd593SJeykumar Sankaran 7225fdd593SJeykumar Sankaran return stages; 7325fdd593SJeykumar Sankaran } 7425fdd593SJeykumar Sankaran 75812eeeb6SSean Paul static inline u32 dpu_hw_ctl_get_flush_register(struct dpu_hw_ctl *ctx) 76812eeeb6SSean Paul { 77812eeeb6SSean Paul struct dpu_hw_blk_reg_map *c = &ctx->hw; 78812eeeb6SSean Paul 79812eeeb6SSean Paul return DPU_REG_READ(c, CTL_FLUSH); 80812eeeb6SSean Paul } 81812eeeb6SSean Paul 8225fdd593SJeykumar Sankaran static inline void dpu_hw_ctl_trigger_start(struct dpu_hw_ctl *ctx) 8325fdd593SJeykumar Sankaran { 84812eeeb6SSean Paul trace_dpu_hw_ctl_trigger_start(ctx->pending_flush_mask, 85812eeeb6SSean Paul dpu_hw_ctl_get_flush_register(ctx)); 8625fdd593SJeykumar Sankaran DPU_REG_WRITE(&ctx->hw, CTL_START, 0x1); 8725fdd593SJeykumar Sankaran } 8825fdd593SJeykumar Sankaran 8925fdd593SJeykumar Sankaran static inline void dpu_hw_ctl_trigger_pending(struct dpu_hw_ctl *ctx) 9025fdd593SJeykumar Sankaran { 91812eeeb6SSean Paul trace_dpu_hw_ctl_trigger_prepare(ctx->pending_flush_mask, 92812eeeb6SSean Paul dpu_hw_ctl_get_flush_register(ctx)); 9325fdd593SJeykumar Sankaran DPU_REG_WRITE(&ctx->hw, CTL_PREPARE, 0x1); 9425fdd593SJeykumar Sankaran } 9525fdd593SJeykumar Sankaran 9625fdd593SJeykumar Sankaran static inline void dpu_hw_ctl_clear_pending_flush(struct dpu_hw_ctl *ctx) 9725fdd593SJeykumar Sankaran { 98812eeeb6SSean Paul trace_dpu_hw_ctl_clear_pending_flush(ctx->pending_flush_mask, 99812eeeb6SSean Paul dpu_hw_ctl_get_flush_register(ctx)); 10025fdd593SJeykumar Sankaran ctx->pending_flush_mask = 0x0; 10125fdd593SJeykumar Sankaran } 10225fdd593SJeykumar Sankaran 10325fdd593SJeykumar Sankaran static inline void dpu_hw_ctl_update_pending_flush(struct dpu_hw_ctl *ctx, 10425fdd593SJeykumar Sankaran u32 flushbits) 10525fdd593SJeykumar Sankaran { 106812eeeb6SSean Paul trace_dpu_hw_ctl_update_pending_flush(flushbits, 107812eeeb6SSean Paul ctx->pending_flush_mask); 10825fdd593SJeykumar Sankaran ctx->pending_flush_mask |= flushbits; 10925fdd593SJeykumar Sankaran } 11025fdd593SJeykumar Sankaran 11125fdd593SJeykumar Sankaran static u32 dpu_hw_ctl_get_pending_flush(struct dpu_hw_ctl *ctx) 11225fdd593SJeykumar Sankaran { 11325fdd593SJeykumar Sankaran if (!ctx) 11425fdd593SJeykumar Sankaran return 0x0; 11525fdd593SJeykumar Sankaran 11625fdd593SJeykumar Sankaran return ctx->pending_flush_mask; 11725fdd593SJeykumar Sankaran } 11825fdd593SJeykumar Sankaran 11925fdd593SJeykumar Sankaran static inline void dpu_hw_ctl_trigger_flush(struct dpu_hw_ctl *ctx) 12025fdd593SJeykumar Sankaran { 121812eeeb6SSean Paul trace_dpu_hw_ctl_trigger_pending_flush(ctx->pending_flush_mask, 122812eeeb6SSean Paul dpu_hw_ctl_get_flush_register(ctx)); 12325fdd593SJeykumar Sankaran DPU_REG_WRITE(&ctx->hw, CTL_FLUSH, ctx->pending_flush_mask); 12425fdd593SJeykumar Sankaran } 12525fdd593SJeykumar Sankaran 12658fba464SSean Paul static uint32_t dpu_hw_ctl_get_bitmask_sspp(struct dpu_hw_ctl *ctx, 12725fdd593SJeykumar Sankaran enum dpu_sspp sspp) 12825fdd593SJeykumar Sankaran { 12925fdd593SJeykumar Sankaran uint32_t flushbits = 0; 13025fdd593SJeykumar Sankaran 13125fdd593SJeykumar Sankaran switch (sspp) { 13225fdd593SJeykumar Sankaran case SSPP_VIG0: 13325fdd593SJeykumar Sankaran flushbits = BIT(0); 13425fdd593SJeykumar Sankaran break; 13525fdd593SJeykumar Sankaran case SSPP_VIG1: 13625fdd593SJeykumar Sankaran flushbits = BIT(1); 13725fdd593SJeykumar Sankaran break; 13825fdd593SJeykumar Sankaran case SSPP_VIG2: 13925fdd593SJeykumar Sankaran flushbits = BIT(2); 14025fdd593SJeykumar Sankaran break; 14125fdd593SJeykumar Sankaran case SSPP_VIG3: 14225fdd593SJeykumar Sankaran flushbits = BIT(18); 14325fdd593SJeykumar Sankaran break; 14425fdd593SJeykumar Sankaran case SSPP_RGB0: 14525fdd593SJeykumar Sankaran flushbits = BIT(3); 14625fdd593SJeykumar Sankaran break; 14725fdd593SJeykumar Sankaran case SSPP_RGB1: 14825fdd593SJeykumar Sankaran flushbits = BIT(4); 14925fdd593SJeykumar Sankaran break; 15025fdd593SJeykumar Sankaran case SSPP_RGB2: 15125fdd593SJeykumar Sankaran flushbits = BIT(5); 15225fdd593SJeykumar Sankaran break; 15325fdd593SJeykumar Sankaran case SSPP_RGB3: 15425fdd593SJeykumar Sankaran flushbits = BIT(19); 15525fdd593SJeykumar Sankaran break; 15625fdd593SJeykumar Sankaran case SSPP_DMA0: 15725fdd593SJeykumar Sankaran flushbits = BIT(11); 15825fdd593SJeykumar Sankaran break; 15925fdd593SJeykumar Sankaran case SSPP_DMA1: 16025fdd593SJeykumar Sankaran flushbits = BIT(12); 16125fdd593SJeykumar Sankaran break; 16225fdd593SJeykumar Sankaran case SSPP_DMA2: 16325fdd593SJeykumar Sankaran flushbits = BIT(24); 16425fdd593SJeykumar Sankaran break; 16525fdd593SJeykumar Sankaran case SSPP_DMA3: 16625fdd593SJeykumar Sankaran flushbits = BIT(25); 16725fdd593SJeykumar Sankaran break; 16825fdd593SJeykumar Sankaran case SSPP_CURSOR0: 16925fdd593SJeykumar Sankaran flushbits = BIT(22); 17025fdd593SJeykumar Sankaran break; 17125fdd593SJeykumar Sankaran case SSPP_CURSOR1: 17225fdd593SJeykumar Sankaran flushbits = BIT(23); 17325fdd593SJeykumar Sankaran break; 17425fdd593SJeykumar Sankaran default: 17525fdd593SJeykumar Sankaran break; 17625fdd593SJeykumar Sankaran } 17725fdd593SJeykumar Sankaran 17825fdd593SJeykumar Sankaran return flushbits; 17925fdd593SJeykumar Sankaran } 18025fdd593SJeykumar Sankaran 18158fba464SSean Paul static uint32_t dpu_hw_ctl_get_bitmask_mixer(struct dpu_hw_ctl *ctx, 18225fdd593SJeykumar Sankaran enum dpu_lm lm) 18325fdd593SJeykumar Sankaran { 18425fdd593SJeykumar Sankaran uint32_t flushbits = 0; 18525fdd593SJeykumar Sankaran 18625fdd593SJeykumar Sankaran switch (lm) { 18725fdd593SJeykumar Sankaran case LM_0: 18825fdd593SJeykumar Sankaran flushbits = BIT(6); 18925fdd593SJeykumar Sankaran break; 19025fdd593SJeykumar Sankaran case LM_1: 19125fdd593SJeykumar Sankaran flushbits = BIT(7); 19225fdd593SJeykumar Sankaran break; 19325fdd593SJeykumar Sankaran case LM_2: 19425fdd593SJeykumar Sankaran flushbits = BIT(8); 19525fdd593SJeykumar Sankaran break; 19625fdd593SJeykumar Sankaran case LM_3: 19725fdd593SJeykumar Sankaran flushbits = BIT(9); 19825fdd593SJeykumar Sankaran break; 19925fdd593SJeykumar Sankaran case LM_4: 20025fdd593SJeykumar Sankaran flushbits = BIT(10); 20125fdd593SJeykumar Sankaran break; 20225fdd593SJeykumar Sankaran case LM_5: 20325fdd593SJeykumar Sankaran flushbits = BIT(20); 20425fdd593SJeykumar Sankaran break; 20525fdd593SJeykumar Sankaran default: 20625fdd593SJeykumar Sankaran return -EINVAL; 20725fdd593SJeykumar Sankaran } 20825fdd593SJeykumar Sankaran 20925fdd593SJeykumar Sankaran flushbits |= CTL_FLUSH_MASK_CTL; 21025fdd593SJeykumar Sankaran 21125fdd593SJeykumar Sankaran return flushbits; 21225fdd593SJeykumar Sankaran } 21325fdd593SJeykumar Sankaran 21458fba464SSean Paul static int dpu_hw_ctl_get_bitmask_intf(struct dpu_hw_ctl *ctx, 21525fdd593SJeykumar Sankaran u32 *flushbits, enum dpu_intf intf) 21625fdd593SJeykumar Sankaran { 21725fdd593SJeykumar Sankaran switch (intf) { 21825fdd593SJeykumar Sankaran case INTF_0: 21925fdd593SJeykumar Sankaran *flushbits |= BIT(31); 22025fdd593SJeykumar Sankaran break; 22125fdd593SJeykumar Sankaran case INTF_1: 22225fdd593SJeykumar Sankaran *flushbits |= BIT(30); 22325fdd593SJeykumar Sankaran break; 22425fdd593SJeykumar Sankaran case INTF_2: 22525fdd593SJeykumar Sankaran *flushbits |= BIT(29); 22625fdd593SJeykumar Sankaran break; 22725fdd593SJeykumar Sankaran case INTF_3: 22825fdd593SJeykumar Sankaran *flushbits |= BIT(28); 22925fdd593SJeykumar Sankaran break; 23025fdd593SJeykumar Sankaran default: 23125fdd593SJeykumar Sankaran return -EINVAL; 23225fdd593SJeykumar Sankaran } 23325fdd593SJeykumar Sankaran return 0; 23425fdd593SJeykumar Sankaran } 23525fdd593SJeykumar Sankaran 23625fdd593SJeykumar Sankaran static u32 dpu_hw_ctl_poll_reset_status(struct dpu_hw_ctl *ctx, u32 timeout_us) 23725fdd593SJeykumar Sankaran { 23825fdd593SJeykumar Sankaran struct dpu_hw_blk_reg_map *c = &ctx->hw; 23925fdd593SJeykumar Sankaran ktime_t timeout; 24025fdd593SJeykumar Sankaran u32 status; 24125fdd593SJeykumar Sankaran 24225fdd593SJeykumar Sankaran timeout = ktime_add_us(ktime_get(), timeout_us); 24325fdd593SJeykumar Sankaran 24425fdd593SJeykumar Sankaran /* 24525fdd593SJeykumar Sankaran * it takes around 30us to have mdp finish resetting its ctl path 24625fdd593SJeykumar Sankaran * poll every 50us so that reset should be completed at 1st poll 24725fdd593SJeykumar Sankaran */ 24825fdd593SJeykumar Sankaran do { 24925fdd593SJeykumar Sankaran status = DPU_REG_READ(c, CTL_SW_RESET); 25025fdd593SJeykumar Sankaran status &= 0x1; 25125fdd593SJeykumar Sankaran if (status) 25225fdd593SJeykumar Sankaran usleep_range(20, 50); 25325fdd593SJeykumar Sankaran } while (status && ktime_compare_safe(ktime_get(), timeout) < 0); 25425fdd593SJeykumar Sankaran 25525fdd593SJeykumar Sankaran return status; 25625fdd593SJeykumar Sankaran } 25725fdd593SJeykumar Sankaran 25825fdd593SJeykumar Sankaran static int dpu_hw_ctl_reset_control(struct dpu_hw_ctl *ctx) 25925fdd593SJeykumar Sankaran { 26025fdd593SJeykumar Sankaran struct dpu_hw_blk_reg_map *c = &ctx->hw; 26125fdd593SJeykumar Sankaran 26225fdd593SJeykumar Sankaran pr_debug("issuing hw ctl reset for ctl:%d\n", ctx->idx); 26325fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_SW_RESET, 0x1); 26425fdd593SJeykumar Sankaran if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US)) 26525fdd593SJeykumar Sankaran return -EINVAL; 26625fdd593SJeykumar Sankaran 26725fdd593SJeykumar Sankaran return 0; 26825fdd593SJeykumar Sankaran } 26925fdd593SJeykumar Sankaran 27025fdd593SJeykumar Sankaran static int dpu_hw_ctl_wait_reset_status(struct dpu_hw_ctl *ctx) 27125fdd593SJeykumar Sankaran { 27225fdd593SJeykumar Sankaran struct dpu_hw_blk_reg_map *c = &ctx->hw; 27325fdd593SJeykumar Sankaran u32 status; 27425fdd593SJeykumar Sankaran 27525fdd593SJeykumar Sankaran status = DPU_REG_READ(c, CTL_SW_RESET); 27625fdd593SJeykumar Sankaran status &= 0x01; 27725fdd593SJeykumar Sankaran if (!status) 27825fdd593SJeykumar Sankaran return 0; 27925fdd593SJeykumar Sankaran 28025fdd593SJeykumar Sankaran pr_debug("hw ctl reset is set for ctl:%d\n", ctx->idx); 28125fdd593SJeykumar Sankaran if (dpu_hw_ctl_poll_reset_status(ctx, DPU_REG_RESET_TIMEOUT_US)) { 28225fdd593SJeykumar Sankaran pr_err("hw recovery is not complete for ctl:%d\n", ctx->idx); 28325fdd593SJeykumar Sankaran return -EINVAL; 28425fdd593SJeykumar Sankaran } 28525fdd593SJeykumar Sankaran 28625fdd593SJeykumar Sankaran return 0; 28725fdd593SJeykumar Sankaran } 28825fdd593SJeykumar Sankaran 28925fdd593SJeykumar Sankaran static void dpu_hw_ctl_clear_all_blendstages(struct dpu_hw_ctl *ctx) 29025fdd593SJeykumar Sankaran { 29125fdd593SJeykumar Sankaran struct dpu_hw_blk_reg_map *c = &ctx->hw; 29225fdd593SJeykumar Sankaran int i; 29325fdd593SJeykumar Sankaran 29425fdd593SJeykumar Sankaran for (i = 0; i < ctx->mixer_count; i++) { 29525fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_LAYER(LM_0 + i), 0); 29625fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_LAYER_EXT(LM_0 + i), 0); 29725fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_LAYER_EXT2(LM_0 + i), 0); 29825fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_LAYER_EXT3(LM_0 + i), 0); 29925fdd593SJeykumar Sankaran } 30025fdd593SJeykumar Sankaran } 30125fdd593SJeykumar Sankaran 30225fdd593SJeykumar Sankaran static void dpu_hw_ctl_setup_blendstage(struct dpu_hw_ctl *ctx, 30325fdd593SJeykumar Sankaran enum dpu_lm lm, struct dpu_hw_stage_cfg *stage_cfg) 30425fdd593SJeykumar Sankaran { 30525fdd593SJeykumar Sankaran struct dpu_hw_blk_reg_map *c = &ctx->hw; 30625fdd593SJeykumar Sankaran u32 mixercfg = 0, mixercfg_ext = 0, mix, ext; 30725fdd593SJeykumar Sankaran u32 mixercfg_ext2 = 0, mixercfg_ext3 = 0; 30825fdd593SJeykumar Sankaran int i, j; 309dfdb3be4SColin Ian King int stages; 31025fdd593SJeykumar Sankaran int pipes_per_stage; 31125fdd593SJeykumar Sankaran 31225fdd593SJeykumar Sankaran stages = _mixer_stages(ctx->mixer_hw_caps, ctx->mixer_count, lm); 31325fdd593SJeykumar Sankaran if (stages < 0) 31425fdd593SJeykumar Sankaran return; 31525fdd593SJeykumar Sankaran 31625fdd593SJeykumar Sankaran if (test_bit(DPU_MIXER_SOURCESPLIT, 31725fdd593SJeykumar Sankaran &ctx->mixer_hw_caps->features)) 31825fdd593SJeykumar Sankaran pipes_per_stage = PIPES_PER_STAGE; 31925fdd593SJeykumar Sankaran else 32025fdd593SJeykumar Sankaran pipes_per_stage = 1; 32125fdd593SJeykumar Sankaran 32225fdd593SJeykumar Sankaran mixercfg = CTL_MIXER_BORDER_OUT; /* always set BORDER_OUT */ 32325fdd593SJeykumar Sankaran 32425fdd593SJeykumar Sankaran if (!stage_cfg) 32525fdd593SJeykumar Sankaran goto exit; 32625fdd593SJeykumar Sankaran 32725fdd593SJeykumar Sankaran for (i = 0; i <= stages; i++) { 32825fdd593SJeykumar Sankaran /* overflow to ext register if 'i + 1 > 7' */ 32925fdd593SJeykumar Sankaran mix = (i + 1) & 0x7; 33025fdd593SJeykumar Sankaran ext = i >= 7; 33125fdd593SJeykumar Sankaran 33225fdd593SJeykumar Sankaran for (j = 0 ; j < pipes_per_stage; j++) { 33325fdd593SJeykumar Sankaran enum dpu_sspp_multirect_index rect_index = 33425fdd593SJeykumar Sankaran stage_cfg->multirect_index[i][j]; 33525fdd593SJeykumar Sankaran 33625fdd593SJeykumar Sankaran switch (stage_cfg->stage[i][j]) { 33725fdd593SJeykumar Sankaran case SSPP_VIG0: 33825fdd593SJeykumar Sankaran if (rect_index == DPU_SSPP_RECT_1) { 33925fdd593SJeykumar Sankaran mixercfg_ext3 |= ((i + 1) & 0xF) << 0; 34025fdd593SJeykumar Sankaran } else { 34125fdd593SJeykumar Sankaran mixercfg |= mix << 0; 34225fdd593SJeykumar Sankaran mixercfg_ext |= ext << 0; 34325fdd593SJeykumar Sankaran } 34425fdd593SJeykumar Sankaran break; 34525fdd593SJeykumar Sankaran case SSPP_VIG1: 34625fdd593SJeykumar Sankaran if (rect_index == DPU_SSPP_RECT_1) { 34725fdd593SJeykumar Sankaran mixercfg_ext3 |= ((i + 1) & 0xF) << 4; 34825fdd593SJeykumar Sankaran } else { 34925fdd593SJeykumar Sankaran mixercfg |= mix << 3; 35025fdd593SJeykumar Sankaran mixercfg_ext |= ext << 2; 35125fdd593SJeykumar Sankaran } 35225fdd593SJeykumar Sankaran break; 35325fdd593SJeykumar Sankaran case SSPP_VIG2: 35425fdd593SJeykumar Sankaran if (rect_index == DPU_SSPP_RECT_1) { 35525fdd593SJeykumar Sankaran mixercfg_ext3 |= ((i + 1) & 0xF) << 8; 35625fdd593SJeykumar Sankaran } else { 35725fdd593SJeykumar Sankaran mixercfg |= mix << 6; 35825fdd593SJeykumar Sankaran mixercfg_ext |= ext << 4; 35925fdd593SJeykumar Sankaran } 36025fdd593SJeykumar Sankaran break; 36125fdd593SJeykumar Sankaran case SSPP_VIG3: 36225fdd593SJeykumar Sankaran if (rect_index == DPU_SSPP_RECT_1) { 36325fdd593SJeykumar Sankaran mixercfg_ext3 |= ((i + 1) & 0xF) << 12; 36425fdd593SJeykumar Sankaran } else { 36525fdd593SJeykumar Sankaran mixercfg |= mix << 26; 36625fdd593SJeykumar Sankaran mixercfg_ext |= ext << 6; 36725fdd593SJeykumar Sankaran } 36825fdd593SJeykumar Sankaran break; 36925fdd593SJeykumar Sankaran case SSPP_RGB0: 37025fdd593SJeykumar Sankaran mixercfg |= mix << 9; 37125fdd593SJeykumar Sankaran mixercfg_ext |= ext << 8; 37225fdd593SJeykumar Sankaran break; 37325fdd593SJeykumar Sankaran case SSPP_RGB1: 37425fdd593SJeykumar Sankaran mixercfg |= mix << 12; 37525fdd593SJeykumar Sankaran mixercfg_ext |= ext << 10; 37625fdd593SJeykumar Sankaran break; 37725fdd593SJeykumar Sankaran case SSPP_RGB2: 37825fdd593SJeykumar Sankaran mixercfg |= mix << 15; 37925fdd593SJeykumar Sankaran mixercfg_ext |= ext << 12; 38025fdd593SJeykumar Sankaran break; 38125fdd593SJeykumar Sankaran case SSPP_RGB3: 38225fdd593SJeykumar Sankaran mixercfg |= mix << 29; 38325fdd593SJeykumar Sankaran mixercfg_ext |= ext << 14; 38425fdd593SJeykumar Sankaran break; 38525fdd593SJeykumar Sankaran case SSPP_DMA0: 38625fdd593SJeykumar Sankaran if (rect_index == DPU_SSPP_RECT_1) { 38725fdd593SJeykumar Sankaran mixercfg_ext2 |= ((i + 1) & 0xF) << 8; 38825fdd593SJeykumar Sankaran } else { 38925fdd593SJeykumar Sankaran mixercfg |= mix << 18; 39025fdd593SJeykumar Sankaran mixercfg_ext |= ext << 16; 39125fdd593SJeykumar Sankaran } 39225fdd593SJeykumar Sankaran break; 39325fdd593SJeykumar Sankaran case SSPP_DMA1: 39425fdd593SJeykumar Sankaran if (rect_index == DPU_SSPP_RECT_1) { 39525fdd593SJeykumar Sankaran mixercfg_ext2 |= ((i + 1) & 0xF) << 12; 39625fdd593SJeykumar Sankaran } else { 39725fdd593SJeykumar Sankaran mixercfg |= mix << 21; 39825fdd593SJeykumar Sankaran mixercfg_ext |= ext << 18; 39925fdd593SJeykumar Sankaran } 40025fdd593SJeykumar Sankaran break; 40125fdd593SJeykumar Sankaran case SSPP_DMA2: 40225fdd593SJeykumar Sankaran if (rect_index == DPU_SSPP_RECT_1) { 40325fdd593SJeykumar Sankaran mixercfg_ext2 |= ((i + 1) & 0xF) << 16; 40425fdd593SJeykumar Sankaran } else { 40525fdd593SJeykumar Sankaran mix |= (i + 1) & 0xF; 40625fdd593SJeykumar Sankaran mixercfg_ext2 |= mix << 0; 40725fdd593SJeykumar Sankaran } 40825fdd593SJeykumar Sankaran break; 40925fdd593SJeykumar Sankaran case SSPP_DMA3: 41025fdd593SJeykumar Sankaran if (rect_index == DPU_SSPP_RECT_1) { 41125fdd593SJeykumar Sankaran mixercfg_ext2 |= ((i + 1) & 0xF) << 20; 41225fdd593SJeykumar Sankaran } else { 41325fdd593SJeykumar Sankaran mix |= (i + 1) & 0xF; 41425fdd593SJeykumar Sankaran mixercfg_ext2 |= mix << 4; 41525fdd593SJeykumar Sankaran } 41625fdd593SJeykumar Sankaran break; 41725fdd593SJeykumar Sankaran case SSPP_CURSOR0: 41825fdd593SJeykumar Sankaran mixercfg_ext |= ((i + 1) & 0xF) << 20; 41925fdd593SJeykumar Sankaran break; 42025fdd593SJeykumar Sankaran case SSPP_CURSOR1: 42125fdd593SJeykumar Sankaran mixercfg_ext |= ((i + 1) & 0xF) << 26; 42225fdd593SJeykumar Sankaran break; 42325fdd593SJeykumar Sankaran default: 42425fdd593SJeykumar Sankaran break; 42525fdd593SJeykumar Sankaran } 42625fdd593SJeykumar Sankaran } 42725fdd593SJeykumar Sankaran } 42825fdd593SJeykumar Sankaran 42925fdd593SJeykumar Sankaran exit: 43025fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_LAYER(lm), mixercfg); 43125fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_LAYER_EXT(lm), mixercfg_ext); 43225fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_LAYER_EXT2(lm), mixercfg_ext2); 43325fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_LAYER_EXT3(lm), mixercfg_ext3); 43425fdd593SJeykumar Sankaran } 43525fdd593SJeykumar Sankaran 43625fdd593SJeykumar Sankaran static void dpu_hw_ctl_intf_cfg(struct dpu_hw_ctl *ctx, 43725fdd593SJeykumar Sankaran struct dpu_hw_intf_cfg *cfg) 43825fdd593SJeykumar Sankaran { 43925fdd593SJeykumar Sankaran struct dpu_hw_blk_reg_map *c = &ctx->hw; 44025fdd593SJeykumar Sankaran u32 intf_cfg = 0; 44125fdd593SJeykumar Sankaran 44225fdd593SJeykumar Sankaran intf_cfg |= (cfg->intf & 0xF) << 4; 44325fdd593SJeykumar Sankaran 44425fdd593SJeykumar Sankaran if (cfg->mode_3d) { 44525fdd593SJeykumar Sankaran intf_cfg |= BIT(19); 44625fdd593SJeykumar Sankaran intf_cfg |= (cfg->mode_3d - 0x1) << 20; 44725fdd593SJeykumar Sankaran } 44825fdd593SJeykumar Sankaran 44925fdd593SJeykumar Sankaran switch (cfg->intf_mode_sel) { 45025fdd593SJeykumar Sankaran case DPU_CTL_MODE_SEL_VID: 45125fdd593SJeykumar Sankaran intf_cfg &= ~BIT(17); 45225fdd593SJeykumar Sankaran intf_cfg &= ~(0x3 << 15); 45325fdd593SJeykumar Sankaran break; 45425fdd593SJeykumar Sankaran case DPU_CTL_MODE_SEL_CMD: 45525fdd593SJeykumar Sankaran intf_cfg |= BIT(17); 45625fdd593SJeykumar Sankaran intf_cfg |= ((cfg->stream_sel & 0x3) << 15); 45725fdd593SJeykumar Sankaran break; 45825fdd593SJeykumar Sankaran default: 45925fdd593SJeykumar Sankaran pr_err("unknown interface type %d\n", cfg->intf_mode_sel); 46025fdd593SJeykumar Sankaran return; 46125fdd593SJeykumar Sankaran } 46225fdd593SJeykumar Sankaran 46325fdd593SJeykumar Sankaran DPU_REG_WRITE(c, CTL_TOP, intf_cfg); 46425fdd593SJeykumar Sankaran } 46525fdd593SJeykumar Sankaran 46625fdd593SJeykumar Sankaran static void _setup_ctl_ops(struct dpu_hw_ctl_ops *ops, 46725fdd593SJeykumar Sankaran unsigned long cap) 46825fdd593SJeykumar Sankaran { 46925fdd593SJeykumar Sankaran ops->clear_pending_flush = dpu_hw_ctl_clear_pending_flush; 47025fdd593SJeykumar Sankaran ops->update_pending_flush = dpu_hw_ctl_update_pending_flush; 47125fdd593SJeykumar Sankaran ops->get_pending_flush = dpu_hw_ctl_get_pending_flush; 47225fdd593SJeykumar Sankaran ops->trigger_flush = dpu_hw_ctl_trigger_flush; 47325fdd593SJeykumar Sankaran ops->get_flush_register = dpu_hw_ctl_get_flush_register; 47425fdd593SJeykumar Sankaran ops->trigger_start = dpu_hw_ctl_trigger_start; 47525fdd593SJeykumar Sankaran ops->trigger_pending = dpu_hw_ctl_trigger_pending; 47625fdd593SJeykumar Sankaran ops->setup_intf_cfg = dpu_hw_ctl_intf_cfg; 47725fdd593SJeykumar Sankaran ops->reset = dpu_hw_ctl_reset_control; 47825fdd593SJeykumar Sankaran ops->wait_reset_status = dpu_hw_ctl_wait_reset_status; 47925fdd593SJeykumar Sankaran ops->clear_all_blendstages = dpu_hw_ctl_clear_all_blendstages; 48025fdd593SJeykumar Sankaran ops->setup_blendstage = dpu_hw_ctl_setup_blendstage; 48125fdd593SJeykumar Sankaran ops->get_bitmask_sspp = dpu_hw_ctl_get_bitmask_sspp; 48225fdd593SJeykumar Sankaran ops->get_bitmask_mixer = dpu_hw_ctl_get_bitmask_mixer; 48325fdd593SJeykumar Sankaran ops->get_bitmask_intf = dpu_hw_ctl_get_bitmask_intf; 48425fdd593SJeykumar Sankaran }; 48525fdd593SJeykumar Sankaran 48653edf462SJordan Crouse static struct dpu_hw_blk_ops dpu_hw_ops; 48725fdd593SJeykumar Sankaran 48825fdd593SJeykumar Sankaran struct dpu_hw_ctl *dpu_hw_ctl_init(enum dpu_ctl idx, 48925fdd593SJeykumar Sankaran void __iomem *addr, 49025fdd593SJeykumar Sankaran struct dpu_mdss_cfg *m) 49125fdd593SJeykumar Sankaran { 49225fdd593SJeykumar Sankaran struct dpu_hw_ctl *c; 49325fdd593SJeykumar Sankaran struct dpu_ctl_cfg *cfg; 49425fdd593SJeykumar Sankaran 49525fdd593SJeykumar Sankaran c = kzalloc(sizeof(*c), GFP_KERNEL); 49625fdd593SJeykumar Sankaran if (!c) 49725fdd593SJeykumar Sankaran return ERR_PTR(-ENOMEM); 49825fdd593SJeykumar Sankaran 49925fdd593SJeykumar Sankaran cfg = _ctl_offset(idx, m, addr, &c->hw); 50025fdd593SJeykumar Sankaran if (IS_ERR_OR_NULL(cfg)) { 50125fdd593SJeykumar Sankaran kfree(c); 50225fdd593SJeykumar Sankaran pr_err("failed to create dpu_hw_ctl %d\n", idx); 50325fdd593SJeykumar Sankaran return ERR_PTR(-EINVAL); 50425fdd593SJeykumar Sankaran } 50525fdd593SJeykumar Sankaran 50625fdd593SJeykumar Sankaran c->caps = cfg; 50725fdd593SJeykumar Sankaran _setup_ctl_ops(&c->ops, c->caps->features); 50825fdd593SJeykumar Sankaran c->idx = idx; 50925fdd593SJeykumar Sankaran c->mixer_count = m->mixer_count; 51025fdd593SJeykumar Sankaran c->mixer_hw_caps = m->mixer; 51125fdd593SJeykumar Sankaran 51253edf462SJordan Crouse dpu_hw_blk_init(&c->base, DPU_HW_BLK_CTL, idx, &dpu_hw_ops); 51325fdd593SJeykumar Sankaran 51425fdd593SJeykumar Sankaran return c; 51525fdd593SJeykumar Sankaran } 51625fdd593SJeykumar Sankaran 51725fdd593SJeykumar Sankaran void dpu_hw_ctl_destroy(struct dpu_hw_ctl *ctx) 51825fdd593SJeykumar Sankaran { 51925fdd593SJeykumar Sankaran if (ctx) 52025fdd593SJeykumar Sankaran dpu_hw_blk_destroy(&ctx->base); 52125fdd593SJeykumar Sankaran kfree(ctx); 52225fdd593SJeykumar Sankaran } 523