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" |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 18 | |
| 19 | #define CDM_CSC_10_OPMODE 0x000 |
| 20 | #define CDM_CSC_10_BASE 0x004 |
| 21 | |
| 22 | #define CDM_CDWN2_OP_MODE 0x100 |
| 23 | #define CDM_CDWN2_CLAMP_OUT 0x104 |
| 24 | #define CDM_CDWN2_PARAMS_3D_0 0x108 |
| 25 | #define CDM_CDWN2_PARAMS_3D_1 0x10C |
| 26 | #define CDM_CDWN2_COEFF_COSITE_H_0 0x110 |
| 27 | #define CDM_CDWN2_COEFF_COSITE_H_1 0x114 |
| 28 | #define CDM_CDWN2_COEFF_COSITE_H_2 0x118 |
| 29 | #define CDM_CDWN2_COEFF_OFFSITE_H_0 0x11C |
| 30 | #define CDM_CDWN2_COEFF_OFFSITE_H_1 0x120 |
| 31 | #define CDM_CDWN2_COEFF_OFFSITE_H_2 0x124 |
| 32 | #define CDM_CDWN2_COEFF_COSITE_V 0x128 |
| 33 | #define CDM_CDWN2_COEFF_OFFSITE_V 0x12C |
| 34 | #define CDM_CDWN2_OUT_SIZE 0x130 |
| 35 | |
| 36 | #define CDM_HDMI_PACK_OP_MODE 0x200 |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 37 | #define CDM_CSC_10_MATRIX_COEFF_0 0x004 |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 38 | |
| 39 | /** |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 40 | * Horizontal coefficients for cosite chroma downscale |
| 41 | * s13 representation of coefficients |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 42 | */ |
| 43 | static u32 cosite_h_coeff[] = {0x00000016, 0x000001cc, 0x0100009e}; |
| 44 | |
| 45 | /** |
| 46 | * Horizontal coefficients for offsite chroma downscale |
| 47 | */ |
| 48 | static u32 offsite_h_coeff[] = {0x000b0005, 0x01db01eb, 0x00e40046}; |
| 49 | |
| 50 | /** |
| 51 | * Vertical coefficients for cosite chroma downscale |
| 52 | */ |
| 53 | static u32 cosite_v_coeff[] = {0x00080004}; |
| 54 | /** |
| 55 | * Vertical coefficients for offsite chroma downscale |
| 56 | */ |
| 57 | static u32 offsite_v_coeff[] = {0x00060002}; |
| 58 | |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 59 | static struct sde_cdm_cfg *_cdm_offset(enum sde_cdm cdm, |
| 60 | struct sde_mdss_cfg *m, |
| 61 | void __iomem *addr, |
| 62 | struct sde_hw_blk_reg_map *b) |
| 63 | { |
| 64 | int i; |
| 65 | |
| 66 | for (i = 0; i < m->cdm_count; i++) { |
| 67 | if (cdm == m->cdm[i].id) { |
| 68 | b->base_off = addr; |
| 69 | b->blk_off = m->cdm[i].base; |
| 70 | b->hwversion = m->hwversion; |
Clarence Ip | 4ce5932 | 2016-06-26 22:27:51 -0400 | [diff] [blame] | 71 | b->log_mask = SDE_DBG_MASK_CDM; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 72 | return &m->cdm[i]; |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | return ERR_PTR(-EINVAL); |
| 77 | } |
| 78 | |
Alan Kwong | d6a3860 | 2017-03-11 22:26:25 -0800 | [diff] [blame] | 79 | 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] | 80 | struct sde_csc_cfg *data) |
| 81 | { |
Alan Kwong | d6a3860 | 2017-03-11 22:26:25 -0800 | [diff] [blame] | 82 | 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] | 83 | |
Alan Kwong | d6a3860 | 2017-03-11 22:26:25 -0800 | [diff] [blame] | 84 | return 0; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 85 | } |
| 86 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 87 | static int sde_hw_cdm_setup_cdwn(struct sde_hw_cdm *ctx, |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 88 | struct sde_hw_cdm_cfg *cfg) |
| 89 | { |
| 90 | struct sde_hw_blk_reg_map *c = &ctx->hw; |
| 91 | u32 opmode = 0; |
| 92 | u32 out_size = 0; |
| 93 | |
| 94 | if (cfg->output_bit_depth == CDM_CDWN_OUTPUT_10BIT) |
| 95 | opmode &= ~BIT(7); |
| 96 | else |
| 97 | opmode |= BIT(7); |
| 98 | |
| 99 | /* ENABLE DWNS_H bit */ |
| 100 | opmode |= BIT(1); |
| 101 | |
| 102 | switch (cfg->h_cdwn_type) { |
| 103 | case CDM_CDWN_DISABLE: |
| 104 | /* CLEAR METHOD_H field */ |
| 105 | opmode &= ~(0x18); |
| 106 | /* CLEAR DWNS_H bit */ |
| 107 | opmode &= ~BIT(1); |
| 108 | break; |
| 109 | case CDM_CDWN_PIXEL_DROP: |
| 110 | /* Clear METHOD_H field (pixel drop is 0) */ |
| 111 | opmode &= ~(0x18); |
| 112 | break; |
| 113 | case CDM_CDWN_AVG: |
| 114 | /* Clear METHOD_H field (Average is 0x1) */ |
| 115 | opmode &= ~(0x18); |
| 116 | opmode |= (0x1 << 0x3); |
| 117 | break; |
| 118 | case CDM_CDWN_COSITE: |
| 119 | /* Clear METHOD_H field (Average is 0x2) */ |
| 120 | opmode &= ~(0x18); |
| 121 | opmode |= (0x2 << 0x3); |
| 122 | /* Co-site horizontal coefficients */ |
| 123 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_0, |
| 124 | cosite_h_coeff[0]); |
| 125 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_1, |
| 126 | cosite_h_coeff[1]); |
| 127 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_COSITE_H_2, |
| 128 | cosite_h_coeff[2]); |
| 129 | break; |
| 130 | case CDM_CDWN_OFFSITE: |
| 131 | /* Clear METHOD_H field (Average is 0x3) */ |
| 132 | opmode &= ~(0x18); |
| 133 | opmode |= (0x3 << 0x3); |
| 134 | |
| 135 | /* Off-site horizontal coefficients */ |
| 136 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_0, |
| 137 | offsite_h_coeff[0]); |
| 138 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_1, |
| 139 | offsite_h_coeff[1]); |
| 140 | SDE_REG_WRITE(c, CDM_CDWN2_COEFF_OFFSITE_H_2, |
| 141 | offsite_h_coeff[2]); |
| 142 | break; |
| 143 | default: |
| 144 | pr_err("%s invalid horz down sampling type\n", __func__); |
| 145 | return -EINVAL; |
| 146 | } |
| 147 | |
| 148 | /* ENABLE DWNS_V bit */ |
| 149 | opmode |= BIT(2); |
| 150 | |
| 151 | switch (cfg->v_cdwn_type) { |
| 152 | case CDM_CDWN_DISABLE: |
| 153 | /* CLEAR METHOD_V field */ |
| 154 | opmode &= ~(0x60); |
| 155 | /* CLEAR DWNS_V bit */ |
| 156 | opmode &= ~BIT(2); |
| 157 | break; |
| 158 | case CDM_CDWN_PIXEL_DROP: |
| 159 | /* Clear METHOD_V field (pixel drop is 0) */ |
| 160 | opmode &= ~(0x60); |
| 161 | break; |
| 162 | case CDM_CDWN_AVG: |
| 163 | /* Clear METHOD_V field (Average is 0x1) */ |
| 164 | opmode &= ~(0x60); |
| 165 | opmode |= (0x1 << 0x5); |
| 166 | break; |
| 167 | case CDM_CDWN_COSITE: |
| 168 | /* Clear METHOD_V field (Average is 0x2) */ |
| 169 | opmode &= ~(0x60); |
| 170 | opmode |= (0x2 << 0x5); |
| 171 | /* Co-site vertical coefficients */ |
| 172 | SDE_REG_WRITE(c, |
| 173 | CDM_CDWN2_COEFF_COSITE_V, |
| 174 | cosite_v_coeff[0]); |
| 175 | break; |
| 176 | case CDM_CDWN_OFFSITE: |
| 177 | /* Clear METHOD_V field (Average is 0x3) */ |
| 178 | opmode &= ~(0x60); |
| 179 | opmode |= (0x3 << 0x5); |
| 180 | |
| 181 | /* Off-site vertical coefficients */ |
| 182 | SDE_REG_WRITE(c, |
| 183 | CDM_CDWN2_COEFF_OFFSITE_V, |
| 184 | offsite_v_coeff[0]); |
| 185 | break; |
| 186 | default: |
| 187 | return -EINVAL; |
| 188 | } |
| 189 | |
| 190 | if (cfg->v_cdwn_type || cfg->h_cdwn_type) |
| 191 | opmode |= BIT(0); /* EN CDWN module */ |
| 192 | else |
| 193 | opmode &= ~BIT(0); |
| 194 | |
| 195 | out_size = (cfg->output_width & 0xFFFF) | |
| 196 | ((cfg->output_height & 0xFFFF) << 16); |
| 197 | SDE_REG_WRITE(c, CDM_CDWN2_OUT_SIZE, out_size); |
| 198 | SDE_REG_WRITE(c, CDM_CDWN2_OP_MODE, opmode); |
| 199 | SDE_REG_WRITE(c, CDM_CDWN2_CLAMP_OUT, |
| 200 | ((0x3FF << 16) | 0x0)); |
| 201 | |
| 202 | return 0; |
| 203 | } |
| 204 | |
| 205 | int sde_hw_cdm_enable(struct sde_hw_cdm *ctx, |
| 206 | struct sde_hw_cdm_cfg *cdm) |
| 207 | { |
| 208 | struct sde_hw_blk_reg_map *c = &ctx->hw; |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 209 | const struct sde_format *fmt = cdm->output_fmt; |
| 210 | struct cdm_output_cfg cdm_cfg = { 0 }; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 211 | u32 opmode = 0; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 212 | u32 csc = 0; |
| 213 | |
Lloyd Atkinson | fa2489c | 2016-05-25 15:16:03 -0400 | [diff] [blame] | 214 | if (!SDE_FORMAT_IS_YUV(fmt)) |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 215 | return -EINVAL; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 216 | |
| 217 | if (cdm->output_type == CDM_CDWN_OUTPUT_HDMI) { |
Lloyd Atkinson | 9a67349 | 2016-07-05 11:41:57 -0400 | [diff] [blame] | 218 | if (fmt->chroma_sample != SDE_CHROMA_H1V2) |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 219 | return -EINVAL; /*unsupported format */ |
| 220 | opmode = BIT(0); |
| 221 | opmode |= (fmt->chroma_sample << 1); |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 222 | cdm_cfg.intf_en = true; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 223 | } else { |
| 224 | opmode = 0; |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 225 | cdm_cfg.wb_en = true; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 226 | } |
| 227 | |
| 228 | csc |= BIT(2); |
| 229 | csc &= ~BIT(1); |
| 230 | csc |= BIT(0); |
| 231 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 232 | if (ctx->hw_mdp && ctx->hw_mdp->ops.setup_cdm_output) |
| 233 | ctx->hw_mdp->ops.setup_cdm_output(ctx->hw_mdp, &cdm_cfg); |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 234 | |
| 235 | SDE_REG_WRITE(c, CDM_CSC_10_OPMODE, csc); |
| 236 | SDE_REG_WRITE(c, CDM_HDMI_PACK_OP_MODE, opmode); |
| 237 | return 0; |
| 238 | } |
| 239 | |
| 240 | void sde_hw_cdm_disable(struct sde_hw_cdm *ctx) |
| 241 | { |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 242 | struct cdm_output_cfg cdm_cfg = { 0 }; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 243 | |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 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); |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 246 | } |
| 247 | |
| 248 | static void _setup_cdm_ops(struct sde_hw_cdm_ops *ops, |
| 249 | unsigned long features) |
| 250 | { |
| 251 | ops->setup_csc_data = sde_hw_cdm_setup_csc_10bit; |
| 252 | ops->setup_cdwn = sde_hw_cdm_setup_cdwn; |
| 253 | ops->enable = sde_hw_cdm_enable; |
| 254 | ops->disable = sde_hw_cdm_disable; |
| 255 | } |
| 256 | |
| 257 | struct sde_hw_cdm *sde_hw_cdm_init(enum sde_cdm idx, |
| 258 | void __iomem *addr, |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 259 | struct sde_mdss_cfg *m, |
| 260 | struct sde_hw_mdp *hw_mdp) |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 261 | { |
| 262 | struct sde_hw_cdm *c; |
| 263 | struct sde_cdm_cfg *cfg; |
| 264 | |
| 265 | c = kzalloc(sizeof(*c), GFP_KERNEL); |
| 266 | if (!c) |
| 267 | return ERR_PTR(-ENOMEM); |
| 268 | |
| 269 | cfg = _cdm_offset(idx, m, addr, &c->hw); |
| 270 | if (IS_ERR_OR_NULL(cfg)) { |
| 271 | kfree(c); |
| 272 | return ERR_PTR(-EINVAL); |
| 273 | } |
| 274 | |
| 275 | c->idx = idx; |
| 276 | c->cdm_hw_cap = cfg; |
| 277 | _setup_cdm_ops(&c->ops, c->cdm_hw_cap->features); |
Alan Kwong | dcc96ff | 2016-07-29 03:06:44 -0400 | [diff] [blame] | 278 | c->hw_mdp = hw_mdp; |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 279 | |
Lloyd Atkinson | 113aefd | 2016-10-23 13:15:18 -0400 | [diff] [blame] | 280 | sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off, |
| 281 | c->hw.blk_off + c->hw.length, c->hw.xin_id); |
| 282 | |
Narendra Muppalla | 1b0b335 | 2015-09-29 10:16:51 -0700 | [diff] [blame] | 283 | return c; |
| 284 | } |
Lloyd Atkinson | 6b3b9dd | 2016-08-10 18:45:31 -0400 | [diff] [blame] | 285 | |
| 286 | void sde_hw_cdm_destroy(struct sde_hw_cdm *cdm) |
| 287 | { |
| 288 | kfree(cdm); |
| 289 | } |