blob: 4e677c2a326ee6a83ebb9ff45ea9b78a1a46e9bb [file] [log] [blame]
abeykunb85a5e32016-08-24 13:51:40 -04001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Narendra Muppalla1b0b3352015-09-29 10:16:51 -07002 *
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
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -080013#include "sde_kms.h"
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070014#include "sde_hw_catalog.h"
15#include "sde_hwio.h"
16#include "sde_hw_lm.h"
17#include "sde_hw_mdss.h"
Lloyd Atkinson113aefd2016-10-23 13:15:18 -040018#include "sde_dbg.h"
Lloyd Atkinson652e59b2017-05-03 11:20:30 -040019#include "sde_kms.h"
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070020
21#define LM_OP_MODE 0x00
22#define LM_OUT_SIZE 0x04
23#define LM_BORDER_COLOR_0 0x08
24#define LM_BORDER_COLOR_1 0x010
25
26/* These register are offset to mixer base + stage base */
27#define LM_BLEND0_OP 0x00
abeykunb85a5e32016-08-24 13:51:40 -040028#define LM_BLEND0_CONST_ALPHA 0x04
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -080029#define LM_FG_COLOR_FILL_COLOR_0 0x08
30#define LM_FG_COLOR_FILL_COLOR_1 0x0C
31#define LM_FG_COLOR_FILL_SIZE 0x10
32#define LM_FG_COLOR_FILL_XY 0x14
33
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070034#define LM_BLEND0_FG_ALPHA 0x04
35#define LM_BLEND0_BG_ALPHA 0x08
36
Dhaval Patelf9245d62017-03-28 16:24:00 -070037#define LM_MISR_CTRL 0x310
38#define LM_MISR_SIGNATURE 0x314
39
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070040static struct sde_lm_cfg *_lm_offset(enum sde_lm mixer,
41 struct sde_mdss_cfg *m,
42 void __iomem *addr,
43 struct sde_hw_blk_reg_map *b)
44{
45 int i;
46
47 for (i = 0; i < m->mixer_count; i++) {
48 if (mixer == m->mixer[i].id) {
49 b->base_off = addr;
50 b->blk_off = m->mixer[i].base;
Lloyd Atkinson77158732016-10-23 13:02:00 -040051 b->length = m->mixer[i].len;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070052 b->hwversion = m->hwversion;
Clarence Ip4ce59322016-06-26 22:27:51 -040053 b->log_mask = SDE_DBG_MASK_LM;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070054 return &m->mixer[i];
55 }
56 }
57
58 return ERR_PTR(-ENOMEM);
59}
60
61/**
62 * _stage_offset(): returns the relative offset of the blend registers
63 * for the stage to be setup
64 * @c: mixer ctx contains the mixer to be programmed
65 * @stage: stage index to setup
66 */
67static inline int _stage_offset(struct sde_hw_mixer *ctx, enum sde_stage stage)
68{
69 const struct sde_lm_sub_blks *sblk = ctx->cap->sblk;
Dhaval Patel73d9a312016-08-25 17:02:23 -070070 int rc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070071
Dhaval Patel73d9a312016-08-25 17:02:23 -070072 if (stage == SDE_STAGE_BASE)
73 rc = -EINVAL;
74 else if (stage <= sblk->maxblendstages)
Dhaval Patelf56a73a2017-05-12 15:42:10 -070075 rc = sblk->blendstage_base[stage - SDE_STAGE_0];
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070076 else
Dhaval Patel73d9a312016-08-25 17:02:23 -070077 rc = -EINVAL;
78
79 return rc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070080}
81
82static void sde_hw_lm_setup_out(struct sde_hw_mixer *ctx,
83 struct sde_hw_mixer_cfg *mixer)
84{
85 struct sde_hw_blk_reg_map *c = &ctx->hw;
86 u32 outsize;
Clarence Ip4411a6d2016-10-20 14:59:54 -040087 u32 op_mode;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070088
Clarence Ip4411a6d2016-10-20 14:59:54 -040089 op_mode = SDE_REG_READ(c, LM_OP_MODE);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070090
91 outsize = mixer->out_height << 16 | mixer->out_width;
92 SDE_REG_WRITE(c, LM_OUT_SIZE, outsize);
93
94 /* SPLIT_LEFT_RIGHT */
Clarence Ip4411a6d2016-10-20 14:59:54 -040095 if (mixer->right_mixer)
96 op_mode |= BIT(31);
97 else
98 op_mode &= ~BIT(31);
99 SDE_REG_WRITE(c, LM_OP_MODE, op_mode);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700100}
101
102static void sde_hw_lm_setup_border_color(struct sde_hw_mixer *ctx,
103 struct sde_mdss_color *color,
104 u8 border_en)
105{
106 struct sde_hw_blk_reg_map *c = &ctx->hw;
107
108 if (border_en) {
109 SDE_REG_WRITE(c, LM_BORDER_COLOR_0,
110 (color->color_0 & 0xFFF) |
111 ((color->color_1 & 0xFFF) << 0x10));
112 SDE_REG_WRITE(c, LM_BORDER_COLOR_1,
113 (color->color_2 & 0xFFF) |
114 ((color->color_3 & 0xFFF) << 0x10));
115 }
116}
117
Kyle Yan6a20fae2017-02-14 13:34:41 -0800118static void sde_hw_lm_setup_blend_config_sdm845(struct sde_hw_mixer *ctx,
abeykunb85a5e32016-08-24 13:51:40 -0400119 u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op)
120{
121 struct sde_hw_blk_reg_map *c = &ctx->hw;
122 int stage_off;
123 u32 const_alpha;
124
125 if (stage == SDE_STAGE_BASE)
126 return;
127
128 stage_off = _stage_offset(ctx, stage);
129 if (WARN_ON(stage_off < 0))
130 return;
131
132 const_alpha = (bg_alpha & 0xFF) | ((fg_alpha & 0xFF) << 16);
133 SDE_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, const_alpha);
134 SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op);
135}
136
Dhaval Patel48c76022016-09-01 17:51:23 -0700137static void sde_hw_lm_setup_blend_config(struct sde_hw_mixer *ctx,
138 u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700139{
140 struct sde_hw_blk_reg_map *c = &ctx->hw;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700141 int stage_off;
142
Dhaval Patel73d9a312016-08-25 17:02:23 -0700143 if (stage == SDE_STAGE_BASE)
144 return;
145
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700146 stage_off = _stage_offset(ctx, stage);
147 if (WARN_ON(stage_off < 0))
148 return;
149
Dhaval Patel48c76022016-09-01 17:51:23 -0700150 SDE_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha);
151 SDE_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400152 SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700153}
154
155static void sde_hw_lm_setup_color3(struct sde_hw_mixer *ctx,
Dhaval Patel48c76022016-09-01 17:51:23 -0700156 uint32_t mixer_op_mode)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700157{
158 struct sde_hw_blk_reg_map *c = &ctx->hw;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700159 int op_mode;
160
161 /* read the existing op_mode configuration */
162 op_mode = SDE_REG_READ(c, LM_OP_MODE);
163
Clarence Ip4411a6d2016-10-20 14:59:54 -0400164 op_mode = (op_mode & (BIT(31) | BIT(30))) | mixer_op_mode;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700165
166 SDE_REG_WRITE(c, LM_OP_MODE, op_mode);
167}
168
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700169static void sde_hw_lm_gc(struct sde_hw_mixer *mixer,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700170 void *cfg)
171{
172}
173
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -0800174static void sde_hw_lm_clear_dim_layer(struct sde_hw_mixer *ctx)
175{
176 struct sde_hw_blk_reg_map *c = &ctx->hw;
177 const struct sde_lm_sub_blks *sblk = ctx->cap->sblk;
178 int stage_off, i;
179 u32 reset = BIT(16), val;
180
181 reset = ~reset;
182 for (i = SDE_STAGE_0; i < sblk->maxblendstages; i++) {
183 stage_off = _stage_offset(ctx, i);
184 if (WARN_ON(stage_off < 0))
185 return;
186
187 /*
188 * read the existing blendn_op register and clear only DIM layer
189 * bit (color_fill bit)
190 */
191 val = SDE_REG_READ(c, LM_BLEND0_OP + stage_off);
192 val &= reset;
193 SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, val);
194 }
195}
196
197static void sde_hw_lm_setup_dim_layer(struct sde_hw_mixer *ctx,
198 struct sde_hw_dim_layer *dim_layer)
199{
200 struct sde_hw_blk_reg_map *c = &ctx->hw;
201 int stage_off;
Dhaval Patelf56a73a2017-05-12 15:42:10 -0700202 u32 val = 0, alpha = 0;
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -0800203
204 stage_off = _stage_offset(ctx, dim_layer->stage);
205 if (stage_off < 0) {
206 SDE_ERROR("invalid stage_off:%d for dim layer\n", stage_off);
207 return;
208 }
209
Dhaval Patelf56a73a2017-05-12 15:42:10 -0700210 alpha = dim_layer->color_fill.color_3 & 0xFF;
211 val = ((dim_layer->color_fill.color_1 << 2) & 0xFFF) << 16 |
212 ((dim_layer->color_fill.color_0 << 2) & 0xFFF);
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -0800213 SDE_REG_WRITE(c, LM_FG_COLOR_FILL_COLOR_0 + stage_off, val);
214
Dhaval Patelf56a73a2017-05-12 15:42:10 -0700215 val = (alpha << 4) << 16 |
216 ((dim_layer->color_fill.color_2 << 2) & 0xFFF);
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -0800217 SDE_REG_WRITE(c, LM_FG_COLOR_FILL_COLOR_1 + stage_off, val);
218
219 val = dim_layer->rect.h << 16 | dim_layer->rect.w;
220 SDE_REG_WRITE(c, LM_FG_COLOR_FILL_SIZE + stage_off, val);
221
222 val = dim_layer->rect.y << 16 | dim_layer->rect.x;
223 SDE_REG_WRITE(c, LM_FG_COLOR_FILL_XY + stage_off, val);
224
225 val = BIT(16); /* enable dim layer */
Dhaval Patelf56a73a2017-05-12 15:42:10 -0700226 val |= SDE_BLEND_FG_ALPHA_FG_CONST | SDE_BLEND_BG_ALPHA_BG_CONST;
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -0800227 if (dim_layer->flags & SDE_DRM_DIM_LAYER_EXCLUSIVE)
228 val |= BIT(17);
Dhaval Patelf56a73a2017-05-12 15:42:10 -0700229 else
230 val &= ~BIT(17);
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -0800231 SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, val);
Dhaval Patelf56a73a2017-05-12 15:42:10 -0700232 val = (alpha << 16) | (0xff - alpha);
233 SDE_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, val);
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -0800234}
235
Dhaval Patelf9245d62017-03-28 16:24:00 -0700236static void sde_hw_lm_setup_misr(struct sde_hw_mixer *ctx,
237 bool enable, u32 frame_count)
238{
239 struct sde_hw_blk_reg_map *c = &ctx->hw;
240 u32 config = 0;
241
242 SDE_REG_WRITE(c, LM_MISR_CTRL, MISR_CTRL_STATUS_CLEAR);
243 /* clear misr data */
244 wmb();
245
246 if (enable)
247 config = (frame_count & MISR_FRAME_COUNT_MASK) |
248 MISR_CTRL_ENABLE | INTF_MISR_CTRL_FREE_RUN_MASK;
249
250 SDE_REG_WRITE(c, LM_MISR_CTRL, config);
251}
252
253static u32 sde_hw_lm_collect_misr(struct sde_hw_mixer *ctx)
254{
255 struct sde_hw_blk_reg_map *c = &ctx->hw;
256
257 return SDE_REG_READ(c, LM_MISR_SIGNATURE);
258}
259
abeykunb85a5e32016-08-24 13:51:40 -0400260static void _setup_mixer_ops(struct sde_mdss_cfg *m,
261 struct sde_hw_lm_ops *ops,
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -0800262 unsigned long features)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700263{
264 ops->setup_mixer_out = sde_hw_lm_setup_out;
Jayant Shekhar2b72ce22017-09-12 11:26:44 +0530265 if (IS_SDM845_TARGET(m->hwversion) || IS_SDM670_TARGET(m->hwversion))
Kyle Yan6a20fae2017-02-14 13:34:41 -0800266 ops->setup_blend_config = sde_hw_lm_setup_blend_config_sdm845;
abeykunb85a5e32016-08-24 13:51:40 -0400267 else
268 ops->setup_blend_config = sde_hw_lm_setup_blend_config;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700269 ops->setup_alpha_out = sde_hw_lm_setup_color3;
270 ops->setup_border_color = sde_hw_lm_setup_border_color;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700271 ops->setup_gc = sde_hw_lm_gc;
Dhaval Patelf9245d62017-03-28 16:24:00 -0700272 ops->setup_misr = sde_hw_lm_setup_misr;
273 ops->collect_misr = sde_hw_lm_collect_misr;
Veera Sundaram Sankaran3171ff82017-01-04 14:34:47 -0800274
275 if (test_bit(SDE_DIM_LAYER, &features)) {
276 ops->setup_dim_layer = sde_hw_lm_setup_dim_layer;
277 ops->clear_dim_layer = sde_hw_lm_clear_dim_layer;
278 }
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700279};
280
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400281static struct sde_hw_blk_ops sde_hw_ops = {
282 .start = NULL,
283 .stop = NULL,
284};
285
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700286struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx,
287 void __iomem *addr,
288 struct sde_mdss_cfg *m)
289{
290 struct sde_hw_mixer *c;
291 struct sde_lm_cfg *cfg;
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400292 int rc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700293
294 c = kzalloc(sizeof(*c), GFP_KERNEL);
295 if (!c)
296 return ERR_PTR(-ENOMEM);
297
298 cfg = _lm_offset(idx, m, addr, &c->hw);
299 if (IS_ERR_OR_NULL(cfg)) {
300 kfree(c);
301 return ERR_PTR(-EINVAL);
302 }
303
304 /* Assign ops */
305 c->idx = idx;
306 c->cap = cfg;
abeykunb85a5e32016-08-24 13:51:40 -0400307 _setup_mixer_ops(m, &c->ops, c->cap->features);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700308
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400309 rc = sde_hw_blk_init(&c->base, SDE_HW_BLK_LM, idx, &sde_hw_ops);
310 if (rc) {
311 SDE_ERROR("failed to init hw blk %d\n", rc);
312 goto blk_init_error;
313 }
314
Lloyd Atkinson113aefd2016-10-23 13:15:18 -0400315 sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name, c->hw.blk_off,
316 c->hw.blk_off + c->hw.length, c->hw.xin_id);
317
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700318 return c;
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400319
320blk_init_error:
321 kzfree(c);
322
323 return ERR_PTR(rc);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700324}
Lloyd Atkinson6b3b9dd2016-08-10 18:45:31 -0400325
326void sde_hw_lm_destroy(struct sde_hw_mixer *lm)
327{
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400328 if (lm)
329 sde_hw_blk_destroy(&lm->base);
Lloyd Atkinson6b3b9dd2016-08-10 18:45:31 -0400330 kfree(lm);
331}