blob: 592c490620b292134162711d02d33f9f00524f11 [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
13#include "sde_hw_catalog.h"
14#include "sde_hwio.h"
15#include "sde_hw_lm.h"
16#include "sde_hw_mdss.h"
17
18#define LM_OP_MODE 0x00
19#define LM_OUT_SIZE 0x04
20#define LM_BORDER_COLOR_0 0x08
21#define LM_BORDER_COLOR_1 0x010
22
23/* These register are offset to mixer base + stage base */
24#define LM_BLEND0_OP 0x00
abeykunb85a5e32016-08-24 13:51:40 -040025#define LM_BLEND0_CONST_ALPHA 0x04
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070026#define LM_BLEND0_FG_ALPHA 0x04
27#define LM_BLEND0_BG_ALPHA 0x08
28
29static struct sde_lm_cfg *_lm_offset(enum sde_lm mixer,
30 struct sde_mdss_cfg *m,
31 void __iomem *addr,
32 struct sde_hw_blk_reg_map *b)
33{
34 int i;
35
36 for (i = 0; i < m->mixer_count; i++) {
37 if (mixer == m->mixer[i].id) {
38 b->base_off = addr;
39 b->blk_off = m->mixer[i].base;
40 b->hwversion = m->hwversion;
Clarence Ip4ce59322016-06-26 22:27:51 -040041 b->log_mask = SDE_DBG_MASK_LM;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070042 return &m->mixer[i];
43 }
44 }
45
46 return ERR_PTR(-ENOMEM);
47}
48
49/**
50 * _stage_offset(): returns the relative offset of the blend registers
51 * for the stage to be setup
52 * @c: mixer ctx contains the mixer to be programmed
53 * @stage: stage index to setup
54 */
55static inline int _stage_offset(struct sde_hw_mixer *ctx, enum sde_stage stage)
56{
57 const struct sde_lm_sub_blks *sblk = ctx->cap->sblk;
Dhaval Patel73d9a312016-08-25 17:02:23 -070058 int rc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070059
Dhaval Patel73d9a312016-08-25 17:02:23 -070060 if (stage == SDE_STAGE_BASE)
61 rc = -EINVAL;
62 else if (stage <= sblk->maxblendstages)
63 rc = sblk->blendstage_base[stage - 1];
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070064 else
Dhaval Patel73d9a312016-08-25 17:02:23 -070065 rc = -EINVAL;
66
67 return rc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070068}
69
70static void sde_hw_lm_setup_out(struct sde_hw_mixer *ctx,
71 struct sde_hw_mixer_cfg *mixer)
72{
73 struct sde_hw_blk_reg_map *c = &ctx->hw;
74 u32 outsize;
Clarence Ip4411a6d2016-10-20 14:59:54 -040075 u32 op_mode;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070076
Clarence Ip4411a6d2016-10-20 14:59:54 -040077 op_mode = SDE_REG_READ(c, LM_OP_MODE);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070078
79 outsize = mixer->out_height << 16 | mixer->out_width;
80 SDE_REG_WRITE(c, LM_OUT_SIZE, outsize);
81
82 /* SPLIT_LEFT_RIGHT */
Clarence Ip4411a6d2016-10-20 14:59:54 -040083 if (mixer->right_mixer)
84 op_mode |= BIT(31);
85 else
86 op_mode &= ~BIT(31);
87 SDE_REG_WRITE(c, LM_OP_MODE, op_mode);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -070088}
89
90static void sde_hw_lm_setup_border_color(struct sde_hw_mixer *ctx,
91 struct sde_mdss_color *color,
92 u8 border_en)
93{
94 struct sde_hw_blk_reg_map *c = &ctx->hw;
95
96 if (border_en) {
97 SDE_REG_WRITE(c, LM_BORDER_COLOR_0,
98 (color->color_0 & 0xFFF) |
99 ((color->color_1 & 0xFFF) << 0x10));
100 SDE_REG_WRITE(c, LM_BORDER_COLOR_1,
101 (color->color_2 & 0xFFF) |
102 ((color->color_3 & 0xFFF) << 0x10));
103 }
104}
105
abeykunb85a5e32016-08-24 13:51:40 -0400106static void sde_hw_lm_setup_blend_config_msmskunk(struct sde_hw_mixer *ctx,
107 u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op)
108{
109 struct sde_hw_blk_reg_map *c = &ctx->hw;
110 int stage_off;
111 u32 const_alpha;
112
113 if (stage == SDE_STAGE_BASE)
114 return;
115
116 stage_off = _stage_offset(ctx, stage);
117 if (WARN_ON(stage_off < 0))
118 return;
119
120 const_alpha = (bg_alpha & 0xFF) | ((fg_alpha & 0xFF) << 16);
121 SDE_REG_WRITE(c, LM_BLEND0_CONST_ALPHA + stage_off, const_alpha);
122 SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op);
123}
124
Dhaval Patel48c76022016-09-01 17:51:23 -0700125static void sde_hw_lm_setup_blend_config(struct sde_hw_mixer *ctx,
126 u32 stage, u32 fg_alpha, u32 bg_alpha, u32 blend_op)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700127{
128 struct sde_hw_blk_reg_map *c = &ctx->hw;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700129 int stage_off;
130
Dhaval Patel73d9a312016-08-25 17:02:23 -0700131 if (stage == SDE_STAGE_BASE)
132 return;
133
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700134 stage_off = _stage_offset(ctx, stage);
135 if (WARN_ON(stage_off < 0))
136 return;
137
Dhaval Patel48c76022016-09-01 17:51:23 -0700138 SDE_REG_WRITE(c, LM_BLEND0_FG_ALPHA + stage_off, fg_alpha);
139 SDE_REG_WRITE(c, LM_BLEND0_BG_ALPHA + stage_off, bg_alpha);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400140 SDE_REG_WRITE(c, LM_BLEND0_OP + stage_off, blend_op);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700141}
142
143static void sde_hw_lm_setup_color3(struct sde_hw_mixer *ctx,
Dhaval Patel48c76022016-09-01 17:51:23 -0700144 uint32_t mixer_op_mode)
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700145{
146 struct sde_hw_blk_reg_map *c = &ctx->hw;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700147 int op_mode;
148
149 /* read the existing op_mode configuration */
150 op_mode = SDE_REG_READ(c, LM_OP_MODE);
151
Clarence Ip4411a6d2016-10-20 14:59:54 -0400152 op_mode = (op_mode & (BIT(31) | BIT(30))) | mixer_op_mode;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700153
154 SDE_REG_WRITE(c, LM_OP_MODE, op_mode);
155}
156
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700157static void sde_hw_lm_gc(struct sde_hw_mixer *mixer,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700158 void *cfg)
159{
160}
161
abeykunb85a5e32016-08-24 13:51:40 -0400162static void _setup_mixer_ops(struct sde_mdss_cfg *m,
163 struct sde_hw_lm_ops *ops,
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700164 unsigned long cap)
165{
166 ops->setup_mixer_out = sde_hw_lm_setup_out;
abeykunb85a5e32016-08-24 13:51:40 -0400167 if (IS_MSMSKUNK_TARGET(m->hwversion))
168 ops->setup_blend_config = sde_hw_lm_setup_blend_config_msmskunk;
169 else
170 ops->setup_blend_config = sde_hw_lm_setup_blend_config;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700171 ops->setup_alpha_out = sde_hw_lm_setup_color3;
172 ops->setup_border_color = sde_hw_lm_setup_border_color;
Gopikrishnaiah Anandane0e5e0c2016-05-25 11:05:33 -0700173 ops->setup_gc = sde_hw_lm_gc;
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700174};
175
176struct sde_hw_mixer *sde_hw_lm_init(enum sde_lm idx,
177 void __iomem *addr,
178 struct sde_mdss_cfg *m)
179{
180 struct sde_hw_mixer *c;
181 struct sde_lm_cfg *cfg;
182
183 c = kzalloc(sizeof(*c), GFP_KERNEL);
184 if (!c)
185 return ERR_PTR(-ENOMEM);
186
187 cfg = _lm_offset(idx, m, addr, &c->hw);
188 if (IS_ERR_OR_NULL(cfg)) {
189 kfree(c);
190 return ERR_PTR(-EINVAL);
191 }
192
193 /* Assign ops */
194 c->idx = idx;
195 c->cap = cfg;
abeykunb85a5e32016-08-24 13:51:40 -0400196 _setup_mixer_ops(m, &c->ops, c->cap->features);
Narendra Muppalla1b0b3352015-09-29 10:16:51 -0700197
198 /*
199 * Perform any default initialization for the sspp blocks
200 */
201 return c;
202}
Lloyd Atkinson6b3b9dd2016-08-10 18:45:31 -0400203
204void sde_hw_lm_destroy(struct sde_hw_mixer *lm)
205{
206 kfree(lm);
207}