blob: 3ba7a5122ddc9cfa3f0724bd6cdcf366e5515308 [file] [log] [blame]
Lloyd Atkinson77158732016-10-23 13:02:00 -04001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
Abhijit Kulkarni94954d52016-06-24 18:27:48 -04002 *
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_hwio.h"
14#include "sde_hw_catalog.h"
Clarence Ipc475b082016-06-26 09:27:23 -040015#include "sde_hw_top.h"
Lloyd Atkinson113aefd2016-10-23 13:15:18 -040016#include "sde_dbg.h"
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040017
Clarence Ip110d15c2016-08-16 14:44:41 -040018#define SSPP_SPARE 0x28
Clarence Ip32bcb002017-03-13 12:26:44 -070019#define UBWC_STATIC 0x144
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040020
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040021#define FLD_SPLIT_DISPLAY_CMD BIT(1)
22#define FLD_SMART_PANEL_FREE_RUN BIT(2)
23#define FLD_INTF_1_SW_TRG_MUX BIT(4)
24#define FLD_INTF_2_SW_TRG_MUX BIT(8)
25#define FLD_TE_LINE_INTER_WATERLEVEL_MASK 0xFFFF
26
Alan Kwongf0fd8512016-10-24 21:39:26 -040027#define DANGER_STATUS 0x360
28#define SAFE_STATUS 0x364
29
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040030#define TE_LINE_INTERVAL 0x3F4
31
Alan Kwong3232ca52016-07-29 02:27:47 -040032#define TRAFFIC_SHAPER_EN BIT(31)
33#define TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4))
34#define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4))
35#define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4
36
Jeykumar Sankaran5c2f0702017-03-09 18:03:15 -080037#define DCE_SEL 0x450
38
Clarence Ip8e69ad02016-12-09 09:43:57 -050039static void sde_hw_setup_split_pipe(struct sde_hw_mdp *mdp,
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040040 struct split_pipe_cfg *cfg)
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040041{
42 struct sde_hw_blk_reg_map *c = &mdp->hw;
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040043 u32 upper_pipe = 0;
44 u32 lower_pipe = 0;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040045
Clarence Ip8e69ad02016-12-09 09:43:57 -050046 if (!mdp || !cfg)
47 return;
48
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040049 if (cfg->en) {
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040050 if (cfg->mode == INTF_MODE_CMD) {
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040051 lower_pipe = FLD_SPLIT_DISPLAY_CMD;
52 /* interface controlling sw trigger */
53 if (cfg->intf == INTF_2)
54 lower_pipe |= FLD_INTF_1_SW_TRG_MUX;
55 else
56 lower_pipe |= FLD_INTF_2_SW_TRG_MUX;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040057
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040058 /* free run */
Clarence Ip8e69ad02016-12-09 09:43:57 -050059 if (cfg->pp_split_slave != INTF_MAX)
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040060 lower_pipe = FLD_SMART_PANEL_FREE_RUN;
61
62 upper_pipe = lower_pipe;
63 } else {
64 if (cfg->intf == INTF_2) {
65 lower_pipe = FLD_INTF_1_SW_TRG_MUX;
66 upper_pipe = FLD_INTF_2_SW_TRG_MUX;
67 } else {
68 lower_pipe = FLD_INTF_2_SW_TRG_MUX;
69 upper_pipe = FLD_INTF_1_SW_TRG_MUX;
70 }
71 }
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040072 }
73
Clarence Ip8e69ad02016-12-09 09:43:57 -050074 SDE_REG_WRITE(c, SSPP_SPARE, cfg->split_flush_en ? 0x1 : 0x0);
Clarence Ip110d15c2016-08-16 14:44:41 -040075 SDE_REG_WRITE(c, SPLIT_DISPLAY_LOWER_PIPE_CTRL, lower_pipe);
76 SDE_REG_WRITE(c, SPLIT_DISPLAY_UPPER_PIPE_CTRL, upper_pipe);
77 SDE_REG_WRITE(c, SPLIT_DISPLAY_EN, cfg->en & 0x1);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040078}
79
Clarence Ip8e69ad02016-12-09 09:43:57 -050080static void sde_hw_setup_pp_split(struct sde_hw_mdp *mdp,
81 struct split_pipe_cfg *cfg)
82{
83 u32 ppb_config = 0x0;
84 u32 ppb_control = 0x0;
85
86 if (!mdp || !cfg)
87 return;
88
89 if (cfg->en && cfg->pp_split_slave != INTF_MAX) {
90 ppb_config |= (cfg->pp_split_slave - INTF_0 + 1) << 20;
91 ppb_config |= BIT(16); /* split enable */
92 ppb_control = BIT(5); /* horz split*/
93 }
94 if (cfg->pp_split_index) {
95 SDE_REG_WRITE(&mdp->hw, PPB0_CONFIG, 0x0);
96 SDE_REG_WRITE(&mdp->hw, PPB0_CNTL, 0x0);
97 SDE_REG_WRITE(&mdp->hw, PPB1_CONFIG, ppb_config);
98 SDE_REG_WRITE(&mdp->hw, PPB1_CNTL, ppb_control);
99 } else {
100 SDE_REG_WRITE(&mdp->hw, PPB0_CONFIG, ppb_config);
101 SDE_REG_WRITE(&mdp->hw, PPB0_CNTL, ppb_control);
102 SDE_REG_WRITE(&mdp->hw, PPB1_CONFIG, 0x0);
103 SDE_REG_WRITE(&mdp->hw, PPB1_CNTL, 0x0);
104 }
105}
106
Alan Kwongdcc96ff2016-07-29 03:06:44 -0400107static void sde_hw_setup_cdm_output(struct sde_hw_mdp *mdp,
108 struct cdm_output_cfg *cfg)
109{
110 struct sde_hw_blk_reg_map *c = &mdp->hw;
111 u32 out_ctl = 0;
112
113 if (cfg->wb_en)
114 out_ctl |= BIT(24);
115 else if (cfg->intf_en)
116 out_ctl |= BIT(19);
117
118 SDE_REG_WRITE(c, MDP_OUT_CTL_0, out_ctl);
119}
120
Alan Kwong5d324e42016-07-28 22:56:18 -0400121static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp,
122 enum sde_clk_ctrl_type clk_ctrl, bool enable)
123{
124 struct sde_hw_blk_reg_map *c = &mdp->hw;
125 u32 reg_off, bit_off;
126 u32 reg_val, new_val;
127 bool clk_forced_on;
128
129 if (clk_ctrl <= SDE_CLK_CTRL_NONE || clk_ctrl >= SDE_CLK_CTRL_MAX)
130 return false;
131
132 reg_off = mdp->cap->clk_ctrls[clk_ctrl].reg_off;
133 bit_off = mdp->cap->clk_ctrls[clk_ctrl].bit_off;
134
135 reg_val = SDE_REG_READ(c, reg_off);
136
137 if (enable)
138 new_val = reg_val | BIT(bit_off);
139 else
140 new_val = reg_val & ~BIT(bit_off);
141
142 SDE_REG_WRITE(c, reg_off, new_val);
143
144 clk_forced_on = !(reg_val & BIT(bit_off));
145
146 return clk_forced_on;
147}
148
Alan Kwongf0fd8512016-10-24 21:39:26 -0400149
150static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp,
151 struct sde_danger_safe_status *status)
152{
153 struct sde_hw_blk_reg_map *c = &mdp->hw;
154 u32 value;
155
156 value = SDE_REG_READ(c, DANGER_STATUS);
157 status->mdp = (value >> 0) & 0x3;
158 status->sspp[SSPP_VIG0] = (value >> 4) & 0x3;
159 status->sspp[SSPP_VIG1] = (value >> 6) & 0x3;
160 status->sspp[SSPP_VIG2] = (value >> 8) & 0x3;
161 status->sspp[SSPP_VIG3] = (value >> 10) & 0x3;
162 status->sspp[SSPP_RGB0] = (value >> 12) & 0x3;
163 status->sspp[SSPP_RGB1] = (value >> 14) & 0x3;
164 status->sspp[SSPP_RGB2] = (value >> 16) & 0x3;
165 status->sspp[SSPP_RGB3] = (value >> 18) & 0x3;
166 status->sspp[SSPP_DMA0] = (value >> 20) & 0x3;
167 status->sspp[SSPP_DMA1] = (value >> 22) & 0x3;
168 status->sspp[SSPP_DMA2] = (value >> 28) & 0x3;
169 status->sspp[SSPP_DMA3] = (value >> 30) & 0x3;
170 status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x3;
171 status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x3;
172 status->wb[WB_0] = 0;
173 status->wb[WB_1] = 0;
174 status->wb[WB_2] = (value >> 2) & 0x3;
175 status->wb[WB_3] = 0;
176}
177
178static void sde_hw_get_safe_status(struct sde_hw_mdp *mdp,
179 struct sde_danger_safe_status *status)
180{
181 struct sde_hw_blk_reg_map *c = &mdp->hw;
182 u32 value;
183
184 value = SDE_REG_READ(c, SAFE_STATUS);
185 status->mdp = (value >> 0) & 0x1;
186 status->sspp[SSPP_VIG0] = (value >> 4) & 0x1;
187 status->sspp[SSPP_VIG1] = (value >> 6) & 0x1;
188 status->sspp[SSPP_VIG2] = (value >> 8) & 0x1;
189 status->sspp[SSPP_VIG3] = (value >> 10) & 0x1;
190 status->sspp[SSPP_RGB0] = (value >> 12) & 0x1;
191 status->sspp[SSPP_RGB1] = (value >> 14) & 0x1;
192 status->sspp[SSPP_RGB2] = (value >> 16) & 0x1;
193 status->sspp[SSPP_RGB3] = (value >> 18) & 0x1;
194 status->sspp[SSPP_DMA0] = (value >> 20) & 0x1;
195 status->sspp[SSPP_DMA1] = (value >> 22) & 0x1;
196 status->sspp[SSPP_DMA2] = (value >> 28) & 0x1;
197 status->sspp[SSPP_DMA3] = (value >> 30) & 0x1;
198 status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x1;
199 status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x1;
200 status->wb[WB_0] = 0;
201 status->wb[WB_1] = 0;
202 status->wb[WB_2] = (value >> 2) & 0x1;
203 status->wb[WB_3] = 0;
204}
205
Jeykumar Sankaran5c2f0702017-03-09 18:03:15 -0800206static void sde_hw_setup_dce(struct sde_hw_mdp *mdp, u32 dce_sel)
207{
208 struct sde_hw_blk_reg_map *c = &mdp->hw;
209
210 SDE_REG_WRITE(c, DCE_SEL, dce_sel);
211}
212
Clarence Ip35348262017-04-28 16:10:46 -0700213void sde_hw_reset_ubwc(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m)
214{
215 struct sde_hw_blk_reg_map c;
216
217 if (!mdp || !m)
218 return;
219
220 if (!IS_UBWC_20_SUPPORTED(m->ubwc_version))
221 return;
222
223 /* force blk offset to zero to access beginning of register region */
224 c = mdp->hw;
225 c.blk_off = 0x0;
226 SDE_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static);
227}
228
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400229static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
230 unsigned long cap)
231{
Clarence Ip8e69ad02016-12-09 09:43:57 -0500232 ops->setup_split_pipe = sde_hw_setup_split_pipe;
233 ops->setup_pp_split = sde_hw_setup_pp_split;
Alan Kwongdcc96ff2016-07-29 03:06:44 -0400234 ops->setup_cdm_output = sde_hw_setup_cdm_output;
Alan Kwong5d324e42016-07-28 22:56:18 -0400235 ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
Alan Kwongf0fd8512016-10-24 21:39:26 -0400236 ops->get_danger_status = sde_hw_get_danger_status;
237 ops->get_safe_status = sde_hw_get_safe_status;
Jeykumar Sankaran5c2f0702017-03-09 18:03:15 -0800238 ops->setup_dce = sde_hw_setup_dce;
Clarence Ip35348262017-04-28 16:10:46 -0700239 ops->reset_ubwc = sde_hw_reset_ubwc;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400240}
241
242static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
243 const struct sde_mdss_cfg *m,
244 void __iomem *addr,
245 struct sde_hw_blk_reg_map *b)
246{
247 int i;
248
249 for (i = 0; i < m->mdp_count; i++) {
250 if (mdp == m->mdp[i].id) {
251 b->base_off = addr;
252 b->blk_off = m->mdp[i].base;
Lloyd Atkinson77158732016-10-23 13:02:00 -0400253 b->length = m->mdp[i].len;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400254 b->hwversion = m->hwversion;
Lloyd Atkinsonbb87b5b2016-06-13 18:31:15 -0400255 b->log_mask = SDE_DBG_MASK_TOP;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400256 return &m->mdp[i];
257 }
258 }
259
260 return ERR_PTR(-EINVAL);
261}
262
263struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
264 void __iomem *addr,
265 const struct sde_mdss_cfg *m)
266{
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400267 struct sde_hw_mdp *mdp;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400268 const struct sde_mdp_cfg *cfg;
269
Clarence Ip32bcb002017-03-13 12:26:44 -0700270 if (!addr || !m)
271 return ERR_PTR(-EINVAL);
272
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400273 mdp = kzalloc(sizeof(*mdp), GFP_KERNEL);
274 if (!mdp)
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400275 return ERR_PTR(-ENOMEM);
276
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400277 cfg = _top_offset(idx, m, addr, &mdp->hw);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400278 if (IS_ERR_OR_NULL(cfg)) {
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400279 kfree(mdp);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400280 return ERR_PTR(-EINVAL);
281 }
282
283 /*
284 * Assign ops
285 */
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400286 mdp->idx = idx;
287 mdp->cap = cfg;
288 _setup_mdp_ops(&mdp->ops, mdp->cap->features);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400289
Lloyd Atkinson113aefd2016-10-23 13:15:18 -0400290 sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
291 mdp->hw.blk_off, mdp->hw.blk_off + mdp->hw.length,
292 mdp->hw.xin_id);
Lloyd Atkinsonac4b6e02017-03-23 11:43:48 -0700293 sde_dbg_set_sde_top_offset(mdp->hw.blk_off);
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400294
295 return mdp;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400296}
297
298void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp)
299{
Lloyd Atkinsone5c2c0b2016-07-05 12:23:29 -0400300 kfree(mdp);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400301}
302