Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2015-2016, 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 "sde_hw_mdss.h" |
| 14 | #include "sde_hwio.h" |
| 15 | #include "sde_hw_catalog.h" |
| 16 | #include "sde_hw_cdm.h" |
| 17 | |
| 18 | #define CDM_CSC_10_OPMODE 0x000 |
| 19 | #define CDM_CSC_10_BASE 0x004 |
| 20 | |
| 21 | #define CDM_CDWN2_OP_MODE 0x100 |
| 22 | #define CDM_CDWN2_CLAMP_OUT 0x104 |
| 23 | #define CDM_CDWN2_PARAMS_3D_0 0x108 |
| 24 | #define CDM_CDWN2_PARAMS_3D_1 0x10C |
| 25 | #define CDM_CDWN2_COEFF_COSITE_H_0 0x110 |
| 26 | #define CDM_CDWN2_COEFF_COSITE_H_1 0x114 |
| 27 | #define CDM_CDWN2_COEFF_COSITE_H_2 0x118 |
| 28 | #define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C |
| 29 | #define CDM_CDWN2_COEFF_OFFSITE_H_1 0x120 |
| 30 | #define CDM_CDWN2_COEFF_OFFSITE_H_2 0x124 |
| 31 | #define CDM_CDWN2_COEFF_COSITE_V 0x128 |
| 32 | #define CDM_CDWN2_COEFF_OFFSITE_V 0x12C |
| 33 | #define CDM_CDWN2_OUT_SIZE 0x130 |
| 34 | |
| 35 | #define CDM_HDMI_PACK_OP_MODE 0x200 |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 36 | #define CDM_CSC_10_MATRIX_COEFF_0 0x004 |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 37 | |
| 38 | /** |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 39 | * Horizontal coefficients for cosite chroma downscale |
| 40 | * s13 representation of coefficients |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 41 | */ |
| 42 | static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e}; |
| 43 | |
| 44 | /** |
| 45 | * Horizontal coefficients for offsite chroma downscale |
| 46 | */ |
| 47 | static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; |
| 48 | |
| 49 | /** |
| 50 | * Vertical coefficients for cosite chroma downscale |
| 51 | */ |
| 52 | static u32 cosite_v_coeff[] = {0x00080004}; |
| 53 | /** |
| 54 | * Vertical coefficients for offsite chroma downscale |
| 55 | */ |
| 56 | static u32 offsite_v_coeff[] = {0x00060002}; |
| 57 | |
| 58 | /* Limited Range rgb2yuv coeff with clamp and bias values for CSC 10 module */ |
| 59 | static struct sde_csc_cfg rgb2yuv_cfg = { |
| 60 | { |
| 61 | 0x0083, 0x0102, 0x0032, |
| 62 | 0x1fb5, 0x1f6c, 0x00e1, |
| 63 | 0x00e1, 0x1f45, 0x1fdc |
| 64 | }, |
| 65 | { 0x00, 0x00, 0x00 }, |
| 66 | { 0x0040, 0x0200, 0x0200 }, |
| 67 | { 0x000, 0x3ff, 0x000, 0x3ff, 0x000, 0x3ff }, |
| 68 | { 0x040, 0x3ac, 0x040, 0x3c0, 0x040, 0x3c0 }, |
| 69 | }; |
| 70 | |
| 71 | static struct sde_cdm_cfg *_cdm_offset(enum sde_cdm cdm, |
| 72 | struct sde_mdss_cfg *m, |
| 73 | void __iomem *addr, |
| 74 | struct sde_hw_blk_reg_map *b) |
| 75 | { |
| 76 | int i; |
| 77 | |
| 78 | for (i = 0; i < m->cdm_count; i++) { |
| 79 | if (cdm == m->cdm[i].id) { |
| 80 | b->base_off = addr; |
| 81 | b->blk_off = m->cdm[i].base; |
| 82 | b->hwversion = m->hwversion; |
Clarence Ip | 4ce5932 | 2016-06-26 22:27:51 -0400 | [diff] [blame] | 83 | b->log_mask = SDE_DBG_MASK_CDM; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 84 | return &m->cdm[i]; |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | return ERR_PTR(-EINVAL); |
| 89 | } |
| 90 | |
| 91 | static void sde_hw_cdm_setup_csc_10bit(struct sde_hw_cdm *ctx, |
| 92 | struct sde_csc_cfg *data) |
| 93 | { |
| 94 | struct sde_hw_blk_reg_map *c = &ctx->hw; |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 95 | u32 csc_reg_off = CDM_CSC_10_MATRIX_COEFF_0; |
| 96 | u32 val; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 97 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 98 | /* matrix coeff */ |
| 99 | val = data->csc_mv[0] | (data->csc_mv[1] << 16); |
| 100 | SDE_REG_WRITE(c, csc_reg_off, val); |
| 101 | val = data->csc_mv[2] | (data->csc_mv[3] << 16); |
| 102 | SDE_REG_WRITE(c, csc_reg_off + 0x4, val); |
| 103 | val = data->csc_mv[4] | (data->csc_mv[5] << 16); |
| 104 | SDE_REG_WRITE(c, csc_reg_off + 0x8, val); |
| 105 | val = data->csc_mv[6] | (data->csc_mv[7] << 16); |
| 106 | SDE_REG_WRITE(c, csc_reg_off + 0xc, val); |
| 107 | val = data->csc_mv[8]; |
| 108 | SDE_REG_WRITE(c, csc_reg_off + 0x10, val); |
| 109 | |
| 110 | /* Pre clamp */ |
| 111 | val = (data->csc_pre_lv[0] << 16) | data->csc_pre_lv[1]; |
| 112 | SDE_REG_WRITE(c, csc_reg_off + 0x14, val); |
| 113 | val = (data->csc_pre_lv[2] << 16) | data->csc_pre_lv[3]; |
| 114 | SDE_REG_WRITE(c, csc_reg_off + 0x18, val); |
| 115 | val = (data->csc_pre_lv[4] << 16) | data->csc_pre_lv[5]; |
| 116 | SDE_REG_WRITE(c, csc_reg_off + 0x1c, val); |
| 117 | |
| 118 | /* Post clamp */ |
| 119 | val = (data->csc_post_lv[0] << 16) | data->csc_post_lv[1]; |
| 120 | SDE_REG_WRITE(c, csc_reg_off + 0x20, val); |
| 121 | val = (data->csc_post_lv[2] << 16) | data->csc_post_lv[3]; |
| 122 | SDE_REG_WRITE(c, csc_reg_off + 0x24, val); |
| 123 | val = (data->csc_post_lv[4] << 16) | data->csc_post_lv[5]; |
| 124 | SDE_REG_WRITE(c, csc_reg_off + 0x28, val); |
| 125 | |
| 126 | /* Pre-Bias */ |
| 127 | SDE_REG_WRITE(c, csc_reg_off + 0x2c, data->csc_pre_bv[0]); |
| 128 | SDE_REG_WRITE(c, csc_reg_off + 0x30, data->csc_pre_bv[1]); |
| 129 | SDE_REG_WRITE(c, csc_reg_off + 0x34, data->csc_pre_bv[2]); |
| 130 | |
| 131 | /* Post-Bias */ |
| 132 | SDE_REG_WRITE(c, csc_reg_off + 0x38, data->csc_post_bv[0]); |
| 133 | SDE_REG_WRITE(c, csc_reg_off + 0x3c, data->csc_post_bv[1]); |
| 134 | SDE_REG_WRITE(c, csc_reg_off + 0x40, data->csc_post_bv[2]); |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 135 | } |
| 136 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 137 | static int sde_hw_cdm_setup_cdwn(struct sde_hw_cdm *ctx, |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 138 | struct sde_hw_cdm_cfg *cfg) |
| 139 | { |
| 140 | struct sde_hw_blk_reg_map *c = &ctx->hw; |
| 141 | u32 opmode = 0; |
| 142 | u32 out_size = 0; |
| 143 | |
| 144 | if (cfg->output_bit_depth == CDM_CDWN_OUTPUT_10BIT) |
| 145 | opmode &= ~BIT(7); |
| 146 | else |
| 147 | opmode |= BIT(7); |
| 148 | |
| 149 | /* ENABLE DWNS_H bit */ |
| 150 | opmode |= BIT(1); |
| 151 | |
| 152 | switch (cfg->h_cdwn_type) { |
| 153 | case CDM_CDWN_DISABLE: |
| 154 | /* CLEAR METHOD_H field */ |
| 155 | opmode &= ~(0x18); |
| 156 | /* CLEAR DWNS_H bit */ |
| 157 | opmode &= ~BIT(1); |
| 158 | break; |
| 159 | case CDM_CDWN_PIXEL_DROP: |
| 160 | /* Clear METHOD_H field (pixel drop is 0) */ |
| 161 | opmode &= ~(0x18); |
| 162 | break; |
| 163 | case CDM_CDWN_AVG: |
| 164 | /* Clear METHOD_H field (Average is 0x1) */ |
| 165 | opmode &= ~(0x18); |
| 166 | opmode |= (0x1 << 0x3); |
| 167 | break; |
| 168 | case CDM_CDWN_COSITE: |
| 169 | /* Clear METHOD_H field (Average is 0x2) */ |
| 170 | opmode &= ~(0x18); |
| 171 | opmode |= (0x2 << 0x3); |
| 172 | /* Co-site horizontal coefficients */ |
| 173 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0, |
| 174 | cosite_h_coeff[0]); |
| 175 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1, |
| 176 | cosite_h_coeff[1]); |
| 177 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2, |
| 178 | cosite_h_coeff[2]); |
| 179 | break; |
| 180 | case CDM_CDWN_OFFSITE: |
| 181 | /* Clear METHOD_H field (Average is 0x3) */ |
| 182 | opmode &= ~(0x18); |
| 183 | opmode |= (0x3 << 0x3); |
| 184 | |
| 185 | /* Off-site horizontal coefficients */ |
| 186 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0, |
| 187 | offsite_h_coeff[0]); |
| 188 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1, |
| 189 | offsite_h_coeff[1]); |
| 190 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2, |
| 191 | offsite_h_coeff[2]); |
| 192 | break; |
| 193 | default: |
| 194 | pr_err("%s invalid horz down sampling type\n", __func__); |
| 195 | return -EINVAL; |
| 196 | } |
| 197 | |
| 198 | /* ENABLE DWNS_V bit */ |
| 199 | opmode |= BIT(2); |
| 200 | |
| 201 | switch (cfg->v_cdwn_type) { |
| 202 | case CDM_CDWN_DISABLE: |
| 203 | /* CLEAR METHOD_V field */ |
| 204 | opmode &= ~(0x60); |
| 205 | /* CLEAR DWNS_V bit */ |
| 206 | opmode &= ~BIT(2); |
| 207 | break; |
| 208 | case CDM_CDWN_PIXEL_DROP: |
| 209 | /* Clear METHOD_V field (pixel drop is 0) */ |
| 210 | opmode &= ~(0x60); |
| 211 | break; |
| 212 | case CDM_CDWN_AVG: |
| 213 | /* Clear METHOD_V field (Average is 0x1) */ |
| 214 | opmode &= ~(0x60); |
| 215 | opmode |= (0x1 << 0x5); |
| 216 | break; |
| 217 | case CDM_CDWN_COSITE: |
| 218 | /* Clear METHOD_V field (Average is 0x2) */ |
| 219 | opmode &= ~(0x60); |
| 220 | opmode |= (0x2 << 0x5); |
| 221 | /* Co-site vertical coefficients */ |
| 222 | SDE_REG_WRITE(c, |
| 223 | CDM_CDWN2_COEFF_COSITE_V, |
| 224 | cosite_v_coeff[0]); |
| 225 | break; |
| 226 | case CDM_CDWN_OFFSITE: |
| 227 | /* Clear METHOD_V field (Average is 0x3) */ |
| 228 | opmode &= ~(0x60); |
| 229 | opmode |= (0x3 << 0x5); |
| 230 | |
| 231 | /* Off-site vertical coefficients */ |
| 232 | SDE_REG_WRITE(c, |
| 233 | CDM_CDWN2_COEFF_OFFSITE_V, |
| 234 | offsite_v_coeff[0]); |
| 235 | break; |
| 236 | default: |
| 237 | return -EINVAL; |
| 238 | } |
| 239 | |
| 240 | if (cfg->v_cdwn_type || cfg->h_cdwn_type) |
| 241 | opmode |= BIT(0); /* EN CDWN module */ |
| 242 | else |
| 243 | opmode &= ~BIT(0); |
| 244 | |
| 245 | out_size = (cfg->output_width & 0xFFFF) | |
| 246 | ((cfg->output_height & 0xFFFF) << 16); |
| 247 | SDE_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size); |
| 248 | SDE_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode); |
| 249 | SDE_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT, |
| 250 | ((0x3FF << 16) | 0x0)); |
| 251 | |
| 252 | return 0; |
| 253 | } |
| 254 | |
| 255 | int sde_hw_cdm_enable(struct sde_hw_cdm *ctx, |
| 256 | struct sde_hw_cdm_cfg *cdm) |
| 257 | { |
| 258 | struct sde_hw_blk_reg_map *c = &ctx->hw; |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 259 | const struct sde_format *fmt = cdm->output_fmt; |
| 260 | struct cdm_output_cfg cdm_cfg = { 0 }; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 261 | u32 opmode = 0; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 262 | u32 csc = 0; |
| 263 | |
Lloyd Atkinson | fa2489c | 2016-05-25 15:16:03 -0400 | [diff] [blame] | 264 | if (!SDE_FORMAT_IS_YUV(fmt)) |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 265 | return -EINVAL; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 266 | |
| 267 | if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { |
Lloyd Atkinson | 9a67349 | 2016-07-05 11:41:57 -0400 | [diff] [blame] | 268 | if (fmt->chroma_sample != SDE_CHROMA_H1V2) |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 269 | return -EINVAL; /*unsupported format */ |
| 270 | opmode = BIT(0); |
| 271 | opmode |= (fmt->chroma_sample << 1); |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 272 | cdm_cfg.intf_en = true; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 273 | } else { |
| 274 | opmode = 0; |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 275 | cdm_cfg.wb_en = true; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 276 | } |
| 277 | |
| 278 | csc |= BIT(2); |
| 279 | csc &= ~BIT(1); |
| 280 | csc |= BIT(0); |
| 281 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 282 | if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) |
| 283 | ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 284 | |
| 285 | SDE_REG_WRITE(c, CDM_CSC_10_OPMODE, csc); |
| 286 | SDE_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode); |
| 287 | return 0; |
| 288 | } |
| 289 | |
| 290 | void sde_hw_cdm_disable(struct sde_hw_cdm *ctx) |
| 291 | { |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 292 | struct cdm_output_cfg cdm_cfg = { 0 }; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 293 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 294 | if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) |
| 295 | ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 296 | } |
| 297 | |
| 298 | static void _setup_cdm_ops(struct sde_hw_cdm_ops *ops, |
| 299 | unsigned long features) |
| 300 | { |
| 301 | ops->setup_csc_data = sde_hw_cdm_setup_csc_10bit; |
| 302 | ops->setup_cdwn = sde_hw_cdm_setup_cdwn; |
| 303 | ops->enable = sde_hw_cdm_enable; |
| 304 | ops->disable = sde_hw_cdm_disable; |
| 305 | } |
| 306 | |
| 307 | struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx, |
| 308 | void __iomem *addr, |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 309 | struct sde_mdss_cfg *m, |
| 310 | struct sde_hw_mdp *hw_mdp) |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 311 | { |
| 312 | struct sde_hw_cdm *c; |
| 313 | struct sde_cdm_cfg *cfg; |
| 314 | |
| 315 | c = kzalloc(sizeof(*c), GFP_KERNEL); |
| 316 | if (!c) |
| 317 | return ERR_PTR(-ENOMEM); |
| 318 | |
| 319 | cfg = _cdm_offset(idx, m, addr, &c->hw); |
| 320 | if (IS_ERR_OR_NULL(cfg)) { |
| 321 | kfree(c); |
| 322 | return ERR_PTR(-EINVAL); |
| 323 | } |
| 324 | |
| 325 | c->idx = idx; |
| 326 | c->cdm_hw_cap = cfg; |
| 327 | _setup_cdm_ops(&c->ops, c->cdm_hw_cap->features); |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 328 | c->hw_mdp = hw_mdp; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 329 | |
| 330 | /* |
| 331 | * Perform any default initialization for the chroma down module |
| 332 | * @setup default csc coefficients |
| 333 | */ |
| 334 | sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg); |
| 335 | |
| 336 | return c; |
| 337 | } |
Lloyd Atkinson | 6b3b9dd | 2016-08-10 18:45:31 -0400 | [diff] [blame] | 338 | |
| 339 | void sde_hw_cdm_destroy(struct sde_hw_cdm *cdm) |
| 340 | { |
| 341 | kfree(cdm); |
| 342 | } |