blob: 613ac536037986f8ca2ec1d1f206f12c31629390 [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"
Lloyd Atkinson652e59b2017-05-03 11:20:30 -040017#include "sde_kms.h"
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040018
Clarence Ip110d15c2016-08-16 14:44:41 -040019#define SSPP_SPARE 0x28
Clarence Ip32bcb002017-03-13 12:26:44 -070020#define UBWC_STATIC 0x144
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040021
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040022#define FLD_SPLIT_DISPLAY_CMD BIT(1)
23#define FLD_SMART_PANEL_FREE_RUN BIT(2)
24#define FLD_INTF_1_SW_TRG_MUX BIT(4)
25#define FLD_INTF_2_SW_TRG_MUX BIT(8)
26#define FLD_TE_LINE_INTER_WATERLEVEL_MASK 0xFFFF
27
Alan Kwongf0fd8512016-10-24 21:39:26 -040028#define DANGER_STATUS 0x360
29#define SAFE_STATUS 0x364
30
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040031#define TE_LINE_INTERVAL 0x3F4
32
Alan Kwong3232ca52016-07-29 02:27:47 -040033#define TRAFFIC_SHAPER_EN BIT(31)
34#define TRAFFIC_SHAPER_RD_CLIENT(num) (0x030 + (num * 4))
35#define TRAFFIC_SHAPER_WR_CLIENT(num) (0x060 + (num * 4))
36#define TRAFFIC_SHAPER_FIXPOINT_FACTOR 4
37
Narendra Muppallad4081e12017-04-20 19:24:08 -070038#define MDP_WD_TIMER_0_CTL 0x380
39#define MDP_WD_TIMER_0_CTL2 0x384
40#define MDP_WD_TIMER_0_LOAD_VALUE 0x388
Dhaval Patelaab9b522017-07-20 12:38:46 -070041#define MDP_WD_TIMER_1_CTL 0x390
42#define MDP_WD_TIMER_1_CTL2 0x394
43#define MDP_WD_TIMER_1_LOAD_VALUE 0x398
44#define MDP_WD_TIMER_2_CTL 0x420
45#define MDP_WD_TIMER_2_CTL2 0x424
46#define MDP_WD_TIMER_2_LOAD_VALUE 0x428
47#define MDP_WD_TIMER_3_CTL 0x430
48#define MDP_WD_TIMER_3_CTL2 0x434
49#define MDP_WD_TIMER_3_LOAD_VALUE 0x438
50#define MDP_WD_TIMER_4_CTL 0x440
51#define MDP_WD_TIMER_4_CTL2 0x444
52#define MDP_WD_TIMER_4_LOAD_VALUE 0x448
Narendra Muppallad4081e12017-04-20 19:24:08 -070053
54#define MDP_TICK_COUNT 16
55#define XO_CLK_RATE 19200
56#define MS_TICKS_IN_SEC 1000
57
58#define CALCULATE_WD_LOAD_VALUE(fps) \
59 ((uint32_t)((MS_TICKS_IN_SEC * XO_CLK_RATE)/(MDP_TICK_COUNT * fps)))
60
Jeykumar Sankaran5c2f0702017-03-09 18:03:15 -080061#define DCE_SEL 0x450
62
Clarence Ip8e69ad02016-12-09 09:43:57 -050063static void sde_hw_setup_split_pipe(struct sde_hw_mdp *mdp,
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040064 struct split_pipe_cfg *cfg)
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040065{
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -070066 struct sde_hw_blk_reg_map *c;
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040067 u32 upper_pipe = 0;
68 u32 lower_pipe = 0;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040069
Clarence Ip8e69ad02016-12-09 09:43:57 -050070 if (!mdp || !cfg)
71 return;
72
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -070073 c = &mdp->hw;
74
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040075 if (cfg->en) {
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040076 if (cfg->mode == INTF_MODE_CMD) {
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040077 lower_pipe = FLD_SPLIT_DISPLAY_CMD;
78 /* interface controlling sw trigger */
79 if (cfg->intf == INTF_2)
80 lower_pipe |= FLD_INTF_1_SW_TRG_MUX;
81 else
82 lower_pipe |= FLD_INTF_2_SW_TRG_MUX;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040083
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040084 /* free run */
Clarence Ip8e69ad02016-12-09 09:43:57 -050085 if (cfg->pp_split_slave != INTF_MAX)
Abhijit Kulkarni43eafcc2016-06-28 17:48:41 -040086 lower_pipe = FLD_SMART_PANEL_FREE_RUN;
87
88 upper_pipe = lower_pipe;
89 } else {
90 if (cfg->intf == INTF_2) {
91 lower_pipe = FLD_INTF_1_SW_TRG_MUX;
92 upper_pipe = FLD_INTF_2_SW_TRG_MUX;
93 } else {
94 lower_pipe = FLD_INTF_2_SW_TRG_MUX;
95 upper_pipe = FLD_INTF_1_SW_TRG_MUX;
96 }
97 }
Abhijit Kulkarni94954d52016-06-24 18:27:48 -040098 }
99
Clarence Ip8e69ad02016-12-09 09:43:57 -0500100 SDE_REG_WRITE(c, SSPP_SPARE, cfg->split_flush_en ? 0x1 : 0x0);
Clarence Ip110d15c2016-08-16 14:44:41 -0400101 SDE_REG_WRITE(c, SPLIT_DISPLAY_LOWER_PIPE_CTRL, lower_pipe);
102 SDE_REG_WRITE(c, SPLIT_DISPLAY_UPPER_PIPE_CTRL, upper_pipe);
103 SDE_REG_WRITE(c, SPLIT_DISPLAY_EN, cfg->en & 0x1);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400104}
105
Clarence Ip8e69ad02016-12-09 09:43:57 -0500106static void sde_hw_setup_pp_split(struct sde_hw_mdp *mdp,
107 struct split_pipe_cfg *cfg)
108{
109 u32 ppb_config = 0x0;
110 u32 ppb_control = 0x0;
111
112 if (!mdp || !cfg)
113 return;
114
115 if (cfg->en && cfg->pp_split_slave != INTF_MAX) {
116 ppb_config |= (cfg->pp_split_slave - INTF_0 + 1) << 20;
117 ppb_config |= BIT(16); /* split enable */
118 ppb_control = BIT(5); /* horz split*/
119 }
120 if (cfg->pp_split_index) {
121 SDE_REG_WRITE(&mdp->hw, PPB0_CONFIG, 0x0);
122 SDE_REG_WRITE(&mdp->hw, PPB0_CNTL, 0x0);
123 SDE_REG_WRITE(&mdp->hw, PPB1_CONFIG, ppb_config);
124 SDE_REG_WRITE(&mdp->hw, PPB1_CNTL, ppb_control);
125 } else {
126 SDE_REG_WRITE(&mdp->hw, PPB0_CONFIG, ppb_config);
127 SDE_REG_WRITE(&mdp->hw, PPB0_CNTL, ppb_control);
128 SDE_REG_WRITE(&mdp->hw, PPB1_CONFIG, 0x0);
129 SDE_REG_WRITE(&mdp->hw, PPB1_CNTL, 0x0);
130 }
131}
132
Alan Kwongdcc96ff2016-07-29 03:06:44 -0400133static void sde_hw_setup_cdm_output(struct sde_hw_mdp *mdp,
134 struct cdm_output_cfg *cfg)
135{
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700136 struct sde_hw_blk_reg_map *c;
Alan Kwongdcc96ff2016-07-29 03:06:44 -0400137 u32 out_ctl = 0;
138
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700139 if (!mdp || !cfg)
140 return;
141
142 c = &mdp->hw;
143
Alan Kwongdcc96ff2016-07-29 03:06:44 -0400144 if (cfg->wb_en)
145 out_ctl |= BIT(24);
146 else if (cfg->intf_en)
147 out_ctl |= BIT(19);
148
149 SDE_REG_WRITE(c, MDP_OUT_CTL_0, out_ctl);
150}
151
Alan Kwong5d324e42016-07-28 22:56:18 -0400152static bool sde_hw_setup_clk_force_ctrl(struct sde_hw_mdp *mdp,
153 enum sde_clk_ctrl_type clk_ctrl, bool enable)
154{
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700155 struct sde_hw_blk_reg_map *c;
Alan Kwong5d324e42016-07-28 22:56:18 -0400156 u32 reg_off, bit_off;
157 u32 reg_val, new_val;
158 bool clk_forced_on;
159
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700160 if (!mdp)
161 return false;
162
163 c = &mdp->hw;
164
Alan Kwong5d324e42016-07-28 22:56:18 -0400165 if (clk_ctrl <= SDE_CLK_CTRL_NONE || clk_ctrl >= SDE_CLK_CTRL_MAX)
166 return false;
167
Lloyd Atkinson4a752fc2017-05-19 16:09:17 -0400168 reg_off = mdp->caps->clk_ctrls[clk_ctrl].reg_off;
169 bit_off = mdp->caps->clk_ctrls[clk_ctrl].bit_off;
Alan Kwong5d324e42016-07-28 22:56:18 -0400170
171 reg_val = SDE_REG_READ(c, reg_off);
172
173 if (enable)
174 new_val = reg_val | BIT(bit_off);
175 else
176 new_val = reg_val & ~BIT(bit_off);
177
178 SDE_REG_WRITE(c, reg_off, new_val);
179
180 clk_forced_on = !(reg_val & BIT(bit_off));
181
182 return clk_forced_on;
183}
184
Alan Kwongf0fd8512016-10-24 21:39:26 -0400185
186static void sde_hw_get_danger_status(struct sde_hw_mdp *mdp,
187 struct sde_danger_safe_status *status)
188{
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700189 struct sde_hw_blk_reg_map *c;
Alan Kwongf0fd8512016-10-24 21:39:26 -0400190 u32 value;
191
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700192 if (!mdp || !status)
193 return;
194
195 c = &mdp->hw;
196
Alan Kwongf0fd8512016-10-24 21:39:26 -0400197 value = SDE_REG_READ(c, DANGER_STATUS);
198 status->mdp = (value >> 0) & 0x3;
199 status->sspp[SSPP_VIG0] = (value >> 4) & 0x3;
200 status->sspp[SSPP_VIG1] = (value >> 6) & 0x3;
201 status->sspp[SSPP_VIG2] = (value >> 8) & 0x3;
202 status->sspp[SSPP_VIG3] = (value >> 10) & 0x3;
203 status->sspp[SSPP_RGB0] = (value >> 12) & 0x3;
204 status->sspp[SSPP_RGB1] = (value >> 14) & 0x3;
205 status->sspp[SSPP_RGB2] = (value >> 16) & 0x3;
206 status->sspp[SSPP_RGB3] = (value >> 18) & 0x3;
207 status->sspp[SSPP_DMA0] = (value >> 20) & 0x3;
208 status->sspp[SSPP_DMA1] = (value >> 22) & 0x3;
209 status->sspp[SSPP_DMA2] = (value >> 28) & 0x3;
210 status->sspp[SSPP_DMA3] = (value >> 30) & 0x3;
211 status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x3;
212 status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x3;
213 status->wb[WB_0] = 0;
214 status->wb[WB_1] = 0;
215 status->wb[WB_2] = (value >> 2) & 0x3;
216 status->wb[WB_3] = 0;
217}
218
Dhaval Patelaab9b522017-07-20 12:38:46 -0700219static void sde_hw_setup_vsync_source(struct sde_hw_mdp *mdp,
220 struct sde_vsync_source_cfg *cfg)
Narendra Muppallad4081e12017-04-20 19:24:08 -0700221{
Dhaval Patelaab9b522017-07-20 12:38:46 -0700222 struct sde_hw_blk_reg_map *c;
223 u32 reg, wd_load_value, wd_ctl, wd_ctl2, i;
224 static const u32 pp_offset[PINGPONG_MAX] = {0xC, 0x8, 0x4, 0x13, 0x18};
Narendra Muppallad4081e12017-04-20 19:24:08 -0700225
Alan Kwong095c7132017-07-04 11:35:43 -0400226 if (!mdp || !cfg || (cfg->pp_count > ARRAY_SIZE(cfg->ppnumber)))
Narendra Muppallad4081e12017-04-20 19:24:08 -0700227 return;
228
Dhaval Patelaab9b522017-07-20 12:38:46 -0700229 c = &mdp->hw;
Narendra Muppallad4081e12017-04-20 19:24:08 -0700230 reg = SDE_REG_READ(c, MDP_VSYNC_SEL);
231 for (i = 0; i < cfg->pp_count; i++) {
Lloyd Atkinson8413f9a2017-05-26 15:47:25 -0400232 int pp_idx = cfg->ppnumber[i] - PINGPONG_0;
Dhaval Patelaab9b522017-07-20 12:38:46 -0700233 if (pp_idx >= ARRAY_SIZE(pp_offset))
234 continue;
Lloyd Atkinson8413f9a2017-05-26 15:47:25 -0400235
Dhaval Patelaab9b522017-07-20 12:38:46 -0700236 reg &= ~(0xf << pp_offset[pp_idx]);
237 reg |= (cfg->vsync_source & 0xf) << pp_offset[pp_idx];
Narendra Muppallad4081e12017-04-20 19:24:08 -0700238 }
Narendra Muppallad4081e12017-04-20 19:24:08 -0700239 SDE_REG_WRITE(c, MDP_VSYNC_SEL, reg);
240
Dhaval Patelaab9b522017-07-20 12:38:46 -0700241 if (cfg->vsync_source >= SDE_VSYNC_SOURCE_WD_TIMER_4 &&
242 cfg->vsync_source <= SDE_VSYNC_SOURCE_WD_TIMER_0) {
243 switch (cfg->vsync_source) {
244 case SDE_VSYNC_SOURCE_WD_TIMER_4:
245 wd_load_value = MDP_WD_TIMER_4_LOAD_VALUE;
246 wd_ctl = MDP_WD_TIMER_4_CTL;
247 wd_ctl2 = MDP_WD_TIMER_4_CTL2;
248 break;
249 case SDE_VSYNC_SOURCE_WD_TIMER_3:
250 wd_load_value = MDP_WD_TIMER_3_LOAD_VALUE;
251 wd_ctl = MDP_WD_TIMER_3_CTL;
252 wd_ctl2 = MDP_WD_TIMER_3_CTL2;
253 break;
254 case SDE_VSYNC_SOURCE_WD_TIMER_2:
255 wd_load_value = MDP_WD_TIMER_2_LOAD_VALUE;
256 wd_ctl = MDP_WD_TIMER_2_CTL;
257 wd_ctl2 = MDP_WD_TIMER_2_CTL2;
258 break;
259 case SDE_VSYNC_SOURCE_WD_TIMER_1:
260 wd_load_value = MDP_WD_TIMER_1_LOAD_VALUE;
261 wd_ctl = MDP_WD_TIMER_1_CTL;
262 wd_ctl2 = MDP_WD_TIMER_1_CTL2;
263 break;
264 case SDE_VSYNC_SOURCE_WD_TIMER_0:
265 default:
266 wd_load_value = MDP_WD_TIMER_0_LOAD_VALUE;
267 wd_ctl = MDP_WD_TIMER_0_CTL;
268 wd_ctl2 = MDP_WD_TIMER_0_CTL2;
269 break;
270 }
271
272 if (cfg->is_dummy) {
273 SDE_REG_WRITE(c, wd_ctl2, 0x0);
274 } else {
275 SDE_REG_WRITE(c, wd_load_value,
Narendra Muppallad4081e12017-04-20 19:24:08 -0700276 CALCULATE_WD_LOAD_VALUE(cfg->frame_rate));
277
Dhaval Patelaab9b522017-07-20 12:38:46 -0700278 SDE_REG_WRITE(c, wd_ctl, BIT(0)); /* clear timer */
279 reg = SDE_REG_READ(c, wd_ctl2);
280 reg |= BIT(8); /* enable heartbeat timer */
281 reg |= BIT(0); /* enable WD timer */
282 SDE_REG_WRITE(c, wd_ctl2, reg);
283 }
284
285 /* make sure that timers are enabled/disabled for vsync state */
286 wmb();
Narendra Muppallad4081e12017-04-20 19:24:08 -0700287 }
288}
289
Alan Kwongf0fd8512016-10-24 21:39:26 -0400290static void sde_hw_get_safe_status(struct sde_hw_mdp *mdp,
291 struct sde_danger_safe_status *status)
292{
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700293 struct sde_hw_blk_reg_map *c;
Alan Kwongf0fd8512016-10-24 21:39:26 -0400294 u32 value;
295
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700296 if (!mdp || !status)
297 return;
298
299 c = &mdp->hw;
300
Alan Kwongf0fd8512016-10-24 21:39:26 -0400301 value = SDE_REG_READ(c, SAFE_STATUS);
302 status->mdp = (value >> 0) & 0x1;
303 status->sspp[SSPP_VIG0] = (value >> 4) & 0x1;
304 status->sspp[SSPP_VIG1] = (value >> 6) & 0x1;
305 status->sspp[SSPP_VIG2] = (value >> 8) & 0x1;
306 status->sspp[SSPP_VIG3] = (value >> 10) & 0x1;
307 status->sspp[SSPP_RGB0] = (value >> 12) & 0x1;
308 status->sspp[SSPP_RGB1] = (value >> 14) & 0x1;
309 status->sspp[SSPP_RGB2] = (value >> 16) & 0x1;
310 status->sspp[SSPP_RGB3] = (value >> 18) & 0x1;
311 status->sspp[SSPP_DMA0] = (value >> 20) & 0x1;
312 status->sspp[SSPP_DMA1] = (value >> 22) & 0x1;
313 status->sspp[SSPP_DMA2] = (value >> 28) & 0x1;
314 status->sspp[SSPP_DMA3] = (value >> 30) & 0x1;
315 status->sspp[SSPP_CURSOR0] = (value >> 24) & 0x1;
316 status->sspp[SSPP_CURSOR1] = (value >> 26) & 0x1;
317 status->wb[WB_0] = 0;
318 status->wb[WB_1] = 0;
319 status->wb[WB_2] = (value >> 2) & 0x1;
320 status->wb[WB_3] = 0;
321}
322
Jeykumar Sankaran5c2f0702017-03-09 18:03:15 -0800323static void sde_hw_setup_dce(struct sde_hw_mdp *mdp, u32 dce_sel)
324{
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700325 struct sde_hw_blk_reg_map *c;
326
327 if (!mdp)
328 return;
329
330 c = &mdp->hw;
Jeykumar Sankaran5c2f0702017-03-09 18:03:15 -0800331
332 SDE_REG_WRITE(c, DCE_SEL, dce_sel);
333}
334
Clarence Ip35348262017-04-28 16:10:46 -0700335void sde_hw_reset_ubwc(struct sde_hw_mdp *mdp, struct sde_mdss_cfg *m)
336{
337 struct sde_hw_blk_reg_map c;
338
339 if (!mdp || !m)
340 return;
341
342 if (!IS_UBWC_20_SUPPORTED(m->ubwc_version))
343 return;
344
345 /* force blk offset to zero to access beginning of register region */
346 c = mdp->hw;
347 c.blk_off = 0x0;
348 SDE_REG_WRITE(&c, UBWC_STATIC, m->mdp[0].ubwc_static);
349}
350
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400351static void _setup_mdp_ops(struct sde_hw_mdp_ops *ops,
352 unsigned long cap)
353{
Clarence Ip8e69ad02016-12-09 09:43:57 -0500354 ops->setup_split_pipe = sde_hw_setup_split_pipe;
355 ops->setup_pp_split = sde_hw_setup_pp_split;
Alan Kwongdcc96ff2016-07-29 03:06:44 -0400356 ops->setup_cdm_output = sde_hw_setup_cdm_output;
Alan Kwong5d324e42016-07-28 22:56:18 -0400357 ops->setup_clk_force_ctrl = sde_hw_setup_clk_force_ctrl;
Alan Kwongf0fd8512016-10-24 21:39:26 -0400358 ops->get_danger_status = sde_hw_get_danger_status;
Dhaval Patelaab9b522017-07-20 12:38:46 -0700359 ops->setup_vsync_source = sde_hw_setup_vsync_source;
Alan Kwongf0fd8512016-10-24 21:39:26 -0400360 ops->get_safe_status = sde_hw_get_safe_status;
Jeykumar Sankaran5c2f0702017-03-09 18:03:15 -0800361 ops->setup_dce = sde_hw_setup_dce;
Clarence Ip35348262017-04-28 16:10:46 -0700362 ops->reset_ubwc = sde_hw_reset_ubwc;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400363}
364
365static const struct sde_mdp_cfg *_top_offset(enum sde_mdp mdp,
366 const struct sde_mdss_cfg *m,
367 void __iomem *addr,
368 struct sde_hw_blk_reg_map *b)
369{
370 int i;
371
Lloyd Atkinson20c9ecd2017-04-18 10:33:47 -0700372 if (!m || !addr || !b)
373 return ERR_PTR(-EINVAL);
374
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400375 for (i = 0; i < m->mdp_count; i++) {
376 if (mdp == m->mdp[i].id) {
377 b->base_off = addr;
378 b->blk_off = m->mdp[i].base;
Lloyd Atkinson77158732016-10-23 13:02:00 -0400379 b->length = m->mdp[i].len;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400380 b->hwversion = m->hwversion;
Lloyd Atkinsonbb87b5b2016-06-13 18:31:15 -0400381 b->log_mask = SDE_DBG_MASK_TOP;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400382 return &m->mdp[i];
383 }
384 }
385
386 return ERR_PTR(-EINVAL);
387}
388
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400389static struct sde_hw_blk_ops sde_hw_ops = {
390 .start = NULL,
391 .stop = NULL,
392};
393
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400394struct sde_hw_mdp *sde_hw_mdptop_init(enum sde_mdp idx,
395 void __iomem *addr,
396 const struct sde_mdss_cfg *m)
397{
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400398 struct sde_hw_mdp *mdp;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400399 const struct sde_mdp_cfg *cfg;
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400400 int rc;
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400401
Clarence Ip32bcb002017-03-13 12:26:44 -0700402 if (!addr || !m)
403 return ERR_PTR(-EINVAL);
404
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400405 mdp = kzalloc(sizeof(*mdp), GFP_KERNEL);
406 if (!mdp)
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400407 return ERR_PTR(-ENOMEM);
408
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400409 cfg = _top_offset(idx, m, addr, &mdp->hw);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400410 if (IS_ERR_OR_NULL(cfg)) {
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400411 kfree(mdp);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400412 return ERR_PTR(-EINVAL);
413 }
414
415 /*
416 * Assign ops
417 */
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400418 mdp->idx = idx;
Lloyd Atkinson4a752fc2017-05-19 16:09:17 -0400419 mdp->caps = cfg;
420 _setup_mdp_ops(&mdp->ops, mdp->caps->features);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400421
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400422 rc = sde_hw_blk_init(&mdp->base, SDE_HW_BLK_TOP, idx, &sde_hw_ops);
423 if (rc) {
424 SDE_ERROR("failed to init hw blk %d\n", rc);
425 goto blk_init_error;
426 }
427
Lloyd Atkinson113aefd2016-10-23 13:15:18 -0400428 sde_dbg_reg_register_dump_range(SDE_DBG_NAME, cfg->name,
429 mdp->hw.blk_off, mdp->hw.blk_off + mdp->hw.length,
430 mdp->hw.xin_id);
Lloyd Atkinsonac4b6e02017-03-23 11:43:48 -0700431 sde_dbg_set_sde_top_offset(mdp->hw.blk_off);
Lloyd Atkinson85ef3fe2016-10-04 09:47:46 -0400432
433 return mdp;
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400434
435blk_init_error:
436 kzfree(mdp);
437
438 return ERR_PTR(rc);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400439}
440
441void sde_hw_mdp_destroy(struct sde_hw_mdp *mdp)
442{
Lloyd Atkinson652e59b2017-05-03 11:20:30 -0400443 if (mdp)
444 sde_hw_blk_destroy(&mdp->base);
Lloyd Atkinsone5c2c0b2016-07-05 12:23:29 -0400445 kfree(mdp);
Abhijit Kulkarni94954d52016-06-24 18:27:48 -0400446}
447