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_hw_mdss.h" 14 #include "dpu_hwio.h" 15 #include "dpu_hw_catalog.h" 16 #include "dpu_hw_cdm.h" 17 #include "dpu_dbg.h" 18 #include "dpu_kms.h" 19 20 #define CDM_CSC_10_OPMODE 0x000 21 #define CDM_CSC_10_BASE 0x004 22 23 #define CDM_CDWN2_OP_MODE 0x100 24 #define CDM_CDWN2_CLAMP_OUT 0x104 25 #define CDM_CDWN2_PARAMS_3D_0 0x108 26 #define CDM_CDWN2_PARAMS_3D_1 0x10C 27 #define CDM_CDWN2_COEFF_COSITE_H_0 0x110 28 #define CDM_CDWN2_COEFF_COSITE_H_1 0x114 29 #define CDM_CDWN2_COEFF_COSITE_H_2 0x118 30 #define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C 31 #define CDM_CDWN2_COEFF_OFFSITE_H_1 0x120 32 #define CDM_CDWN2_COEFF_OFFSITE_H_2 0x124 33 #define CDM_CDWN2_COEFF_COSITE_V 0x128 34 #define CDM_CDWN2_COEFF_OFFSITE_V 0x12C 35 #define CDM_CDWN2_OUT_SIZE 0x130 36 37 #define CDM_HDMI_PACK_OP_MODE 0x200 38 #define CDM_CSC_10_MATRIX_COEFF_0 0x004 39 40 /** 41 * Horizontal coefficients for cosite chroma downscale 42 * s13 representation of coefficients 43 */ 44 static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e}; 45 46 /** 47 * Horizontal coefficients for offsite chroma downscale 48 */ 49 static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; 50 51 /** 52 * Vertical coefficients for cosite chroma downscale 53 */ 54 static u32 cosite_v_coeff[] = {0x00080004}; 55 /** 56 * Vertical coefficients for offsite chroma downscale 57 */ 58 static u32 offsite_v_coeff[] = {0x00060002}; 59 60 /* Limited Range rgb2yuv coeff with clamp and bias values for CSC 10 module */ 61 static struct dpu_csc_cfg rgb2yuv_cfg = { 62 { 63 0x0083, 0x0102, 0x0032, 64 0x1fb5, 0x1f6c, 0x00e1, 65 0x00e1, 0x1f45, 0x1fdc 66 }, 67 { 0x00, 0x00, 0x00 }, 68 { 0x0040, 0x0200, 0x0200 }, 69 { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff }, 70 { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 }, 71 }; 72 73 static struct dpu_cdm_cfg *_cdm_offset(enum dpu_cdm cdm, 74 struct dpu_mdss_cfg *m, 75 void __iomem *addr, 76 struct dpu_hw_blk_reg_map *b) 77 { 78 int i; 79 80 for (i = 0; i < m->cdm_count; i++) { 81 if (cdm == m->cdm[i].id) { 82 b->base_off = addr; 83 b->blk_off = m->cdm[i].base; 84 b->length = m->cdm[i].len; 85 b->hwversion = m->hwversion; 86 b->log_mask = DPU_DBG_MASK_CDM; 87 return &m->cdm[i]; 88 } 89 } 90 91 return ERR_PTR(-EINVAL); 92 } 93 94 static int dpu_hw_cdm_setup_csc_10bit(struct dpu_hw_cdm *ctx, 95 struct dpu_csc_cfg *data) 96 { 97 dpu_hw_csc_setup(&ctx->hw, CDM_CSC_10_MATRIX_COEFF_0, data, true); 98 99 return 0; 100 } 101 102 static int dpu_hw_cdm_setup_cdwn(struct dpu_hw_cdm *ctx, 103 struct dpu_hw_cdm_cfg *cfg) 104 { 105 struct dpu_hw_blk_reg_map *c = &ctx->hw; 106 u32 opmode = 0; 107 u32 out_size = 0; 108 109 if (cfg->output_bit_depth == CDM_CDWN_OUTPUT_10BIT) 110 opmode &= ~BIT(7); 111 else 112 opmode |= BIT(7); 113 114 /* ENABLE DWNS_H bit */ 115 opmode |= BIT(1); 116 117 switch (cfg->h_cdwn_type) { 118 case CDM_CDWN_DISABLE: 119 /* CLEAR METHOD_H field */ 120 opmode &= ~(0x18); 121 /* CLEAR DWNS_H bit */ 122 opmode &= ~BIT(1); 123 break; 124 case CDM_CDWN_PIXEL_DROP: 125 /* Clear METHOD_H field (pixel drop is 0) */ 126 opmode &= ~(0x18); 127 break; 128 case CDM_CDWN_AVG: 129 /* Clear METHOD_H field (Average is 0x1) */ 130 opmode &= ~(0x18); 131 opmode |= (0x1 << 0x3); 132 break; 133 case CDM_CDWN_COSITE: 134 /* Clear METHOD_H field (Average is 0x2) */ 135 opmode &= ~(0x18); 136 opmode |= (0x2 << 0x3); 137 /* Co-site horizontal coefficients */ 138 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0, 139 cosite_h_coeff[0]); 140 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1, 141 cosite_h_coeff[1]); 142 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2, 143 cosite_h_coeff[2]); 144 break; 145 case CDM_CDWN_OFFSITE: 146 /* Clear METHOD_H field (Average is 0x3) */ 147 opmode &= ~(0x18); 148 opmode |= (0x3 << 0x3); 149 150 /* Off-site horizontal coefficients */ 151 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0, 152 offsite_h_coeff[0]); 153 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1, 154 offsite_h_coeff[1]); 155 DPU_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2, 156 offsite_h_coeff[2]); 157 break; 158 default: 159 pr_err("%s invalid horz down sampling type\n", __func__); 160 return -EINVAL; 161 } 162 163 /* ENABLE DWNS_V bit */ 164 opmode |= BIT(2); 165 166 switch (cfg->v_cdwn_type) { 167 case CDM_CDWN_DISABLE: 168 /* CLEAR METHOD_V field */ 169 opmode &= ~(0x60); 170 /* CLEAR DWNS_V bit */ 171 opmode &= ~BIT(2); 172 break; 173 case CDM_CDWN_PIXEL_DROP: 174 /* Clear METHOD_V field (pixel drop is 0) */ 175 opmode &= ~(0x60); 176 break; 177 case CDM_CDWN_AVG: 178 /* Clear METHOD_V field (Average is 0x1) */ 179 opmode &= ~(0x60); 180 opmode |= (0x1 << 0x5); 181 break; 182 case CDM_CDWN_COSITE: 183 /* Clear METHOD_V field (Average is 0x2) */ 184 opmode &= ~(0x60); 185 opmode |= (0x2 << 0x5); 186 /* Co-site vertical coefficients */ 187 DPU_REG_WRITE(c, 188 CDM_CDWN2_COEFF_COSITE_V, 189 cosite_v_coeff[0]); 190 break; 191 case CDM_CDWN_OFFSITE: 192 /* Clear METHOD_V field (Average is 0x3) */ 193 opmode &= ~(0x60); 194 opmode |= (0x3 << 0x5); 195 196 /* Off-site vertical coefficients */ 197 DPU_REG_WRITE(c, 198 CDM_CDWN2_COEFF_OFFSITE_V, 199 offsite_v_coeff[0]); 200 break; 201 default: 202 return -EINVAL; 203 } 204 205 if (cfg->v_cdwn_type || cfg->h_cdwn_type) 206 opmode |= BIT(0); /* EN CDWN module */ 207 else 208 opmode &= ~BIT(0); 209 210 out_size = (cfg->output_width & 0xFFFF) | 211 ((cfg->output_height & 0xFFFF) << 16); 212 DPU_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size); 213 DPU_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode); 214 DPU_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT, 215 ((0x3FF << 16) | 0x0)); 216 217 return 0; 218 } 219 220 static int dpu_hw_cdm_enable(struct dpu_hw_cdm *ctx, 221 struct dpu_hw_cdm_cfg *cdm) 222 { 223 struct dpu_hw_blk_reg_map *c = &ctx->hw; 224 const struct dpu_format *fmt = cdm->output_fmt; 225 struct cdm_output_cfg cdm_cfg = { 0 }; 226 u32 opmode = 0; 227 u32 csc = 0; 228 229 if (!DPU_FORMAT_IS_YUV(fmt)) 230 return -EINVAL; 231 232 if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { 233 if (fmt->chroma_sample != DPU_CHROMA_H1V2) 234 return -EINVAL; /*unsupported format */ 235 opmode = BIT(0); 236 opmode |= (fmt->chroma_sample << 1); 237 cdm_cfg.intf_en = true; 238 } 239 240 csc |= BIT(2); 241 csc &= ~BIT(1); 242 csc |= BIT(0); 243 244 if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) 245 ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); 246 247 DPU_REG_WRITE(c, CDM_CSC_10_OPMODE, csc); 248 DPU_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode); 249 return 0; 250 } 251 252 static void dpu_hw_cdm_disable(struct dpu_hw_cdm *ctx) 253 { 254 struct cdm_output_cfg cdm_cfg = { 0 }; 255 256 if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) 257 ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); 258 } 259 260 static void _setup_cdm_ops(struct dpu_hw_cdm_ops *ops, 261 unsigned long features) 262 { 263 ops->setup_csc_data = dpu_hw_cdm_setup_csc_10bit; 264 ops->setup_cdwn = dpu_hw_cdm_setup_cdwn; 265 ops->enable = dpu_hw_cdm_enable; 266 ops->disable = dpu_hw_cdm_disable; 267 } 268 269 static struct dpu_hw_blk_ops dpu_hw_ops = { 270 .start = NULL, 271 .stop = NULL, 272 }; 273 274 struct dpu_hw_cdm *dpu_hw_cdm_init(enum dpu_cdm idx, 275 void __iomem *addr, 276 struct dpu_mdss_cfg *m, 277 struct dpu_hw_mdp *hw_mdp) 278 { 279 struct dpu_hw_cdm *c; 280 struct dpu_cdm_cfg *cfg; 281 int rc; 282 283 c = kzalloc(sizeof(*c), GFP_KERNEL); 284 if (!c) 285 return ERR_PTR(-ENOMEM); 286 287 cfg = _cdm_offset(idx, m, addr, &c->hw); 288 if (IS_ERR_OR_NULL(cfg)) { 289 kfree(c); 290 return ERR_PTR(-EINVAL); 291 } 292 293 c->idx = idx; 294 c->caps = cfg; 295 _setup_cdm_ops(&c->ops, c->caps->features); 296 c->hw_mdp = hw_mdp; 297 298 rc = dpu_hw_blk_init(&c->base, DPU_HW_BLK_CDM, idx, &dpu_hw_ops); 299 if (rc) { 300 DPU_ERROR("failed to init hw blk %d\n", rc); 301 goto blk_init_error; 302 } 303 304 /* 305 * Perform any default initialization for the chroma down module 306 * @setup default csc coefficients 307 */ 308 dpu_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg); 309 310 return c; 311 312 blk_init_error: 313 kzfree(c); 314 315 return ERR_PTR(rc); 316 } 317 318 void dpu_hw_cdm_destroy(struct dpu_hw_cdm *cdm) 319 { 320 if (cdm) 321 dpu_hw_blk_destroy(&cdm->base); 322 kfree(cdm); 323 } 324