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_lm.h" 8 #include "dpu_hw_dspp.h" 9 #include "dpu_kms.h" 10 11 12 /* DSPP_PCC */ 13 #define PCC_EN BIT(0) 14 #define PCC_DIS 0 15 #define PCC_RED_R_OFF 0x10 16 #define PCC_RED_G_OFF 0x1C 17 #define PCC_RED_B_OFF 0x28 18 #define PCC_GREEN_R_OFF 0x14 19 #define PCC_GREEN_G_OFF 0x20 20 #define PCC_GREEN_B_OFF 0x2C 21 #define PCC_BLUE_R_OFF 0x18 22 #define PCC_BLUE_G_OFF 0x24 23 #define PCC_BLUE_B_OFF 0x30 24 25 static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx, 26 struct dpu_hw_pcc_cfg *cfg) 27 { 28 29 u32 base = ctx->cap->sblk->pcc.base; 30 31 if (!ctx || !base) { 32 DRM_ERROR("invalid ctx %pK pcc base 0x%x\n", ctx, base); 33 return; 34 } 35 36 if (!cfg) { 37 DRM_DEBUG_DRIVER("disable pcc feature\n"); 38 DPU_REG_WRITE(&ctx->hw, base, PCC_DIS); 39 return; 40 } 41 42 DPU_REG_WRITE(&ctx->hw, base + PCC_RED_R_OFF, cfg->r.r); 43 DPU_REG_WRITE(&ctx->hw, base + PCC_RED_G_OFF, cfg->r.g); 44 DPU_REG_WRITE(&ctx->hw, base + PCC_RED_B_OFF, cfg->r.b); 45 46 DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_R_OFF, cfg->g.r); 47 DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_G_OFF, cfg->g.g); 48 DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_B_OFF, cfg->g.b); 49 50 DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_R_OFF, cfg->b.r); 51 DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_G_OFF, cfg->b.g); 52 DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_B_OFF, cfg->b.b); 53 54 DPU_REG_WRITE(&ctx->hw, base, PCC_EN); 55 } 56 57 static void _setup_dspp_ops(struct dpu_hw_dspp *c, 58 unsigned long features) 59 { 60 if (test_bit(DPU_DSPP_PCC, &features) && 61 IS_SC7180_TARGET(c->hw.hwversion)) 62 c->ops.setup_pcc = dpu_setup_dspp_pcc; 63 } 64 65 static const struct dpu_dspp_cfg *_dspp_offset(enum dpu_dspp dspp, 66 const struct dpu_mdss_cfg *m, 67 void __iomem *addr, 68 struct dpu_hw_blk_reg_map *b) 69 { 70 int i; 71 72 if (!m || !addr || !b) 73 return ERR_PTR(-EINVAL); 74 75 for (i = 0; i < m->dspp_count; i++) { 76 if (dspp == m->dspp[i].id) { 77 b->base_off = addr; 78 b->blk_off = m->dspp[i].base; 79 b->length = m->dspp[i].len; 80 b->hwversion = m->hwversion; 81 b->log_mask = DPU_DBG_MASK_DSPP; 82 return &m->dspp[i]; 83 } 84 } 85 86 return ERR_PTR(-EINVAL); 87 } 88 89 static struct dpu_hw_blk_ops dpu_hw_ops; 90 91 struct dpu_hw_dspp *dpu_hw_dspp_init(enum dpu_dspp idx, 92 void __iomem *addr, 93 const struct dpu_mdss_cfg *m) 94 { 95 struct dpu_hw_dspp *c; 96 const struct dpu_dspp_cfg *cfg; 97 98 if (!addr || !m) 99 return ERR_PTR(-EINVAL); 100 101 c = kzalloc(sizeof(*c), GFP_KERNEL); 102 if (!c) 103 return ERR_PTR(-ENOMEM); 104 105 cfg = _dspp_offset(idx, m, addr, &c->hw); 106 if (IS_ERR_OR_NULL(cfg)) { 107 kfree(c); 108 return ERR_PTR(-EINVAL); 109 } 110 111 /* Assign ops */ 112 c->idx = idx; 113 c->cap = cfg; 114 _setup_dspp_ops(c, c->cap->features); 115 116 dpu_hw_blk_init(&c->base, DPU_HW_BLK_DSPP, idx, &dpu_hw_ops); 117 118 return c; 119 } 120 121 void dpu_hw_dspp_destroy(struct dpu_hw_dspp *dspp) 122 { 123 if (dspp) 124 dpu_hw_blk_destroy(&dspp->base); 125 126 kfree(dspp); 127 } 128 129 130