1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. 3 */ 4 5 #include <drm/drm_managed.h> 6 7 #include "dpu_hwio.h" 8 #include "dpu_hw_catalog.h" 9 #include "dpu_hw_lm.h" 10 #include "dpu_hw_dspp.h" 11 #include "dpu_kms.h" 12 13 14 /* DSPP_PCC */ 15 #define PCC_EN BIT(0) 16 #define PCC_DIS 0 17 #define PCC_RED_R_OFF 0x10 18 #define PCC_RED_G_OFF 0x1C 19 #define PCC_RED_B_OFF 0x28 20 #define PCC_GREEN_R_OFF 0x14 21 #define PCC_GREEN_G_OFF 0x20 22 #define PCC_GREEN_B_OFF 0x2C 23 #define PCC_BLUE_R_OFF 0x18 24 #define PCC_BLUE_G_OFF 0x24 25 #define PCC_BLUE_B_OFF 0x30 26 27 /* DSPP_GC */ 28 #define GC_EN BIT(0) 29 #define GC_DIS 0 30 #define GC_8B_ROUND_EN BIT(1) 31 #define GC_LUT_SWAP_OFF 0x1c 32 #define GC_C0_OFF 0x4 33 #define GC_C1_OFF 0xc 34 #define GC_C2_OFF 0x14 35 #define GC_C0_INDEX_OFF 0x8 36 #define GC_C1_INDEX_OFF 0x10 37 #define GC_C2_INDEX_OFF 0x18 38 39 static void dpu_setup_dspp_pcc(struct dpu_hw_dspp *ctx, 40 struct dpu_hw_pcc_cfg *cfg) 41 { 42 43 u32 base; 44 45 if (!ctx) { 46 DRM_ERROR("invalid ctx %p\n", ctx); 47 return; 48 } 49 50 base = ctx->cap->sblk->pcc.base; 51 52 if (!base) { 53 DRM_ERROR("invalid ctx %p pcc base 0x%x\n", ctx, base); 54 return; 55 } 56 57 if (!cfg) { 58 DRM_DEBUG_DRIVER("disable pcc feature\n"); 59 DPU_REG_WRITE(&ctx->hw, base, PCC_DIS); 60 return; 61 } 62 63 DPU_REG_WRITE(&ctx->hw, base + PCC_RED_R_OFF, cfg->r.r); 64 DPU_REG_WRITE(&ctx->hw, base + PCC_RED_G_OFF, cfg->r.g); 65 DPU_REG_WRITE(&ctx->hw, base + PCC_RED_B_OFF, cfg->r.b); 66 67 DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_R_OFF, cfg->g.r); 68 DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_G_OFF, cfg->g.g); 69 DPU_REG_WRITE(&ctx->hw, base + PCC_GREEN_B_OFF, cfg->g.b); 70 71 DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_R_OFF, cfg->b.r); 72 DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_G_OFF, cfg->b.g); 73 DPU_REG_WRITE(&ctx->hw, base + PCC_BLUE_B_OFF, cfg->b.b); 74 75 DPU_REG_WRITE(&ctx->hw, base, PCC_EN); 76 } 77 78 static void dpu_setup_dspp_gc(struct dpu_hw_dspp *ctx, 79 struct dpu_hw_gc_lut *gc_lut) 80 { 81 int i = 0; 82 u32 base, reg; 83 84 if (!ctx) { 85 DRM_ERROR("invalid ctx\n"); 86 return; 87 } 88 89 base = ctx->cap->sblk->gc.base; 90 91 if (!base) { 92 DRM_ERROR("invalid ctx %pK gc base\n", ctx); 93 return; 94 } 95 96 if (!gc_lut) { 97 DRM_DEBUG_DRIVER("disable gc feature\n"); 98 DPU_REG_WRITE(&ctx->hw, base, GC_DIS); 99 return; 100 } 101 102 DPU_REG_WRITE(&ctx->hw, base + GC_C0_INDEX_OFF, 0); 103 DPU_REG_WRITE(&ctx->hw, base + GC_C1_INDEX_OFF, 0); 104 DPU_REG_WRITE(&ctx->hw, base + GC_C2_INDEX_OFF, 0); 105 106 for (i = 0; i < PGC_TBL_LEN; i++) { 107 DPU_REG_WRITE(&ctx->hw, base + GC_C0_OFF, gc_lut->c0[i]); 108 DPU_REG_WRITE(&ctx->hw, base + GC_C1_OFF, gc_lut->c1[i]); 109 DPU_REG_WRITE(&ctx->hw, base + GC_C2_OFF, gc_lut->c2[i]); 110 } 111 112 DPU_REG_WRITE(&ctx->hw, base + GC_LUT_SWAP_OFF, BIT(0)); 113 114 reg = GC_EN | ((gc_lut->flags & PGC_8B_ROUND) ? GC_8B_ROUND_EN : 0); 115 DPU_REG_WRITE(&ctx->hw, base, reg); 116 } 117 118 /** 119 * dpu_hw_dspp_init() - Initializes the DSPP hw driver object. 120 * should be called once before accessing every DSPP. 121 * @dev: Corresponding device for devres management 122 * @cfg: DSPP catalog entry for which driver object is required 123 * @addr: Mapped register io address of MDP 124 * Return: pointer to structure or ERR_PTR 125 */ 126 struct dpu_hw_dspp *dpu_hw_dspp_init(struct drm_device *dev, 127 const struct dpu_dspp_cfg *cfg, 128 void __iomem *addr) 129 { 130 struct dpu_hw_dspp *c; 131 132 if (!addr) 133 return ERR_PTR(-EINVAL); 134 135 c = drmm_kzalloc(dev, sizeof(*c), GFP_KERNEL); 136 if (!c) 137 return ERR_PTR(-ENOMEM); 138 139 c->hw.blk_addr = addr + cfg->base; 140 c->hw.log_mask = DPU_DBG_MASK_DSPP; 141 142 /* Assign ops */ 143 c->idx = cfg->id; 144 c->cap = cfg; 145 if (c->cap->sblk->pcc.base) 146 c->ops.setup_pcc = dpu_setup_dspp_pcc; 147 if (c->cap->sblk->gc.base) 148 c->ops.setup_gc = dpu_setup_dspp_gc; 149 150 return c; 151 } 152