Dhaval Patel | 6fe7f67 | 2017-02-10 12:40:46 -0800 | [diff] [blame] | 1 | /* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved. |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 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" |
Lloyd Atkinson | 113aefd | 2016-10-23 13:15:18 -0400 | [diff] [blame] | 17 | #include "sde_dbg.h" |
Lloyd Atkinson | 652e59b | 2017-05-03 11:20:30 -0400 | [diff] [blame] | 18 | #include "sde_kms.h" |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 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 |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 38 | #define CDM_CSC_10_MATRIX_COEFF_0 0x004 |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 39 | |
| 40 | /** |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 41 | * Horizontal coefficients for cosite chroma downscale |
| 42 | * s13 representation of coefficients |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 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 | |
Dhaval Patel | 8873933 | 2017-04-11 11:08:04 -0700 | [diff] [blame] | 60 | /* Limited Range rgb2yuv coeff with clamp and bias values for CSC 10 module */ |
| 61 | static struct sde_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 | |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 73 | static struct sde_cdm_cfg *_cdm_offset(enum sde_cdm cdm, |
| 74 | struct sde_mdss_cfg *m, |
| 75 | void __iomem *addr, |
| 76 | struct sde_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; |
Lloyd Atkinson | 4995592 | 2017-09-27 16:46:58 -0400 | [diff] [blame] | 84 | b->length = m->cdm[i].len; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 85 | b->hwversion = m->hwversion; |
Clarence Ip | 4ce5932 | 2016-06-26 22:27:51 -0400 | [diff] [blame] | 86 | b->log_mask = SDE_DBG_MASK_CDM; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 87 | return &m->cdm[i]; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | return ERR_PTR(-EINVAL); |
| 92 | } |
| 93 | |
Alan Kwong | d6a3860 | 2017-03-11 22:26:25 -0800 | [diff] [blame] | 94 | static int sde_hw_cdm_setup_csc_10bit(struct sde_hw_cdm *ctx, |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 95 | struct sde_csc_cfg *data) |
| 96 | { |
Alan Kwong | d6a3860 | 2017-03-11 22:26:25 -0800 | [diff] [blame] | 97 | sde_hw_csc_setup(&ctx->hw, CDM_CSC_10_MATRIX_COEFF_0, data, true); |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 98 | |
Alan Kwong | d6a3860 | 2017-03-11 22:26:25 -0800 | [diff] [blame] | 99 | return 0; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 100 | } |
| 101 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 102 | static int sde_hw_cdm_setup_cdwn(struct sde_hw_cdm *ctx, |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 103 | struct sde_hw_cdm_cfg *cfg) |
| 104 | { |
| 105 | struct sde_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 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0, |
| 139 | cosite_h_coeff[0]); |
| 140 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1, |
| 141 | cosite_h_coeff[1]); |
| 142 | SDE_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 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0, |
| 152 | offsite_h_coeff[0]); |
| 153 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1, |
| 154 | offsite_h_coeff[1]); |
| 155 | SDE_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 | SDE_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 | SDE_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 | SDE_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size); |
| 213 | SDE_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode); |
| 214 | SDE_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT, |
| 215 | ((0x3FF << 16) | 0x0)); |
| 216 | |
| 217 | return 0; |
| 218 | } |
| 219 | |
| 220 | int sde_hw_cdm_enable(struct sde_hw_cdm *ctx, |
| 221 | struct sde_hw_cdm_cfg *cdm) |
| 222 | { |
| 223 | struct sde_hw_blk_reg_map *c = &ctx->hw; |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 224 | const struct sde_format *fmt = cdm->output_fmt; |
| 225 | struct cdm_output_cfg cdm_cfg = { 0 }; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 226 | u32 opmode = 0; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 227 | u32 csc = 0; |
| 228 | |
Lloyd Atkinson | fa2489c | 2016-05-25 15:16:03 -0400 | [diff] [blame] | 229 | if (!SDE_FORMAT_IS_YUV(fmt)) |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 230 | return -EINVAL; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 231 | |
| 232 | if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { |
Lloyd Atkinson | 9a67349 | 2016-07-05 11:41:57 -0400 | [diff] [blame] | 233 | if (fmt->chroma_sample != SDE_CHROMA_H1V2) |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 234 | return -EINVAL; /*unsupported format */ |
| 235 | opmode = BIT(0); |
| 236 | opmode |= (fmt->chroma_sample << 1); |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 237 | cdm_cfg.intf_en = true; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 238 | } else { |
| 239 | opmode = 0; |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 240 | cdm_cfg.wb_en = true; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 241 | } |
| 242 | |
| 243 | csc |= BIT(2); |
| 244 | csc &= ~BIT(1); |
| 245 | csc |= BIT(0); |
| 246 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 247 | if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) |
| 248 | ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 249 | |
| 250 | SDE_REG_WRITE(c, CDM_CSC_10_OPMODE, csc); |
| 251 | SDE_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode); |
| 252 | return 0; |
| 253 | } |
| 254 | |
| 255 | void sde_hw_cdm_disable(struct sde_hw_cdm *ctx) |
| 256 | { |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 257 | struct cdm_output_cfg cdm_cfg = { 0 }; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 258 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 259 | if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) |
| 260 | ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 261 | } |
| 262 | |
| 263 | static void _setup_cdm_ops(struct sde_hw_cdm_ops *ops, |
| 264 | unsigned long features) |
| 265 | { |
| 266 | ops->setup_csc_data = sde_hw_cdm_setup_csc_10bit; |
| 267 | ops->setup_cdwn = sde_hw_cdm_setup_cdwn; |
| 268 | ops->enable = sde_hw_cdm_enable; |
| 269 | ops->disable = sde_hw_cdm_disable; |
| 270 | } |
| 271 | |
Lloyd Atkinson | 652e59b | 2017-05-03 11:20:30 -0400 | [diff] [blame] | 272 | static struct sde_hw_blk_ops sde_hw_ops = { |
| 273 | .start = NULL, |
| 274 | .stop = NULL, |
| 275 | }; |
| 276 | |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 277 | struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx, |
| 278 | void __iomem *addr, |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 279 | struct sde_mdss_cfg *m, |
| 280 | struct sde_hw_mdp *hw_mdp) |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 281 | { |
| 282 | struct sde_hw_cdm *c; |
| 283 | struct sde_cdm_cfg *cfg; |
Lloyd Atkinson | 652e59b | 2017-05-03 11:20:30 -0400 | [diff] [blame] | 284 | int rc; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 285 | |
| 286 | c = kzalloc(sizeof(*c), GFP_KERNEL); |
| 287 | if (!c) |
| 288 | return ERR_PTR(-ENOMEM); |
| 289 | |
| 290 | cfg = _cdm_offset(idx, m, addr, &c->hw); |
| 291 | if (IS_ERR_OR_NULL(cfg)) { |
| 292 | kfree(c); |
| 293 | return ERR_PTR(-EINVAL); |
| 294 | } |
| 295 | |
| 296 | c->idx = idx; |
Lloyd Atkinson | 4a752fc | 2017-05-19 16:09:17 -0400 | [diff] [blame] | 297 | c->caps = cfg; |
| 298 | _setup_cdm_ops(&c->ops, c->caps->features); |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 299 | c->hw_mdp = hw_mdp; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 300 | |
Lloyd Atkinson | 652e59b | 2017-05-03 11:20:30 -0400 | [diff] [blame] | 301 | rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_CDM, idx, &sde_hw_ops); |
| 302 | if (rc) { |
| 303 | SDE_ERROR("failed to init hw blk %d\n", rc); |
| 304 | goto blk_init_error; |
| 305 | } |
| 306 | |
Lloyd Atkinson | 113aefd | 2016-10-23 13:15:18 -0400 | [diff] [blame] | 307 | sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, |
| 308 | c->hw.blk_off + c->hw.length, c->hw.xin_id); |
Lloyd Atkinson | 652e59b | 2017-05-03 11:20:30 -0400 | [diff] [blame] | 309 | |
Dhaval Patel | 8873933 | 2017-04-11 11:08:04 -0700 | [diff] [blame] | 310 | /* |
| 311 | * Perform any default initialization for the chroma down module |
| 312 | * @setup default csc coefficients |
| 313 | */ |
| 314 | sde_hw_cdm_setup_csc_10bit(c, &rgb2yuv_cfg); |
Lloyd Atkinson | 113aefd | 2016-10-23 13:15:18 -0400 | [diff] [blame] | 315 | |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 316 | return c; |
Lloyd Atkinson | 652e59b | 2017-05-03 11:20:30 -0400 | [diff] [blame] | 317 | |
| 318 | blk_init_error: |
| 319 | kzfree(c); |
| 320 | |
| 321 | return ERR_PTR(rc); |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 322 | } |
Lloyd Atkinson | 6b3b9dd | 2016-08-10 18:45:31 -0400 | [diff] [blame] | 323 | |
| 324 | void sde_hw_cdm_destroy(struct sde_hw_cdm *cdm) |
| 325 | { |
Lloyd Atkinson | 652e59b | 2017-05-03 11:20:30 -0400 | [diff] [blame] | 326 | if (cdm) |
| 327 | sde_hw_blk_destroy(&cdm->base); |
Lloyd Atkinson | 6b3b9dd | 2016-08-10 18:45:31 -0400 | [diff] [blame] | 328 | kfree(cdm); |
| 329 | } |