Commit | Line | Data |
---|---|---|
026abc33 KS |
1 | /* |
2 | * Copyright © 2010 Intel Corporation | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a | |
5 | * copy of this software and associated documentation files (the "Software"), | |
6 | * to deal in the Software without restriction, including without limitation | |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
8 | * and/or sell copies of the Software, and to permit persons to whom the | |
9 | * Software is furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice (including the next | |
12 | * paragraph) shall be included in all copies or substantial portions of the | |
13 | * Software. | |
14 | * | |
15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
21 | * DEALINGS IN THE SOFTWARE. | |
22 | * | |
23 | * Authors: | |
24 | * jim liu <jim.liu@intel.com> | |
25 | * Jackie Li<yaodong.li@intel.com> | |
26 | */ | |
27 | ||
28 | #include <linux/module.h> | |
29 | ||
30 | #include "mdfld_dsi_output.h" | |
31 | #include "mdfld_dsi_dpi.h" | |
32 | #include "mdfld_output.h" | |
33 | #include "mdfld_dsi_pkg_sender.h" | |
34 | #include "tc35876x-dsi-lvds.h" | |
35 | #include <linux/pm_runtime.h> | |
36 | #include <asm/intel_scu_ipc.h> | |
37 | ||
38 | /* get the LABC from command line. */ | |
39 | static int LABC_control = 1; | |
40 | ||
41 | #ifdef MODULE | |
42 | module_param(LABC_control, int, 0644); | |
43 | #else | |
44 | ||
45 | static int __init parse_LABC_control(char *arg) | |
46 | { | |
47 | /* LABC control can be passed in as a cmdline parameter */ | |
48 | /* to enable this feature add LABC=1 to cmdline */ | |
49 | /* to disable this feature add LABC=0 to cmdline */ | |
50 | if (!arg) | |
51 | return -EINVAL; | |
52 | ||
53 | if (!strcasecmp(arg, "0")) | |
54 | LABC_control = 0; | |
55 | else if (!strcasecmp(arg, "1")) | |
56 | LABC_control = 1; | |
57 | ||
58 | return 0; | |
59 | } | |
60 | early_param("LABC", parse_LABC_control); | |
61 | #endif | |
62 | ||
63 | /** | |
64 | * Check and see if the generic control or data buffer is empty and ready. | |
65 | */ | |
66 | void mdfld_dsi_gen_fifo_ready(struct drm_device *dev, u32 gen_fifo_stat_reg, | |
67 | u32 fifo_stat) | |
68 | { | |
69 | u32 GEN_BF_time_out_count; | |
70 | ||
71 | /* Check MIPI Adatper command registers */ | |
72 | for (GEN_BF_time_out_count = 0; | |
73 | GEN_BF_time_out_count < GEN_FB_TIME_OUT; | |
74 | GEN_BF_time_out_count++) { | |
75 | if ((REG_READ(gen_fifo_stat_reg) & fifo_stat) == fifo_stat) | |
76 | break; | |
77 | udelay(100); | |
78 | } | |
79 | ||
80 | if (GEN_BF_time_out_count == GEN_FB_TIME_OUT) | |
81 | DRM_ERROR("mdfld_dsi_gen_fifo_ready, Timeout. gen_fifo_stat_reg = 0x%x.\n", | |
82 | gen_fifo_stat_reg); | |
83 | } | |
84 | ||
85 | /** | |
86 | * Manage the DSI MIPI keyboard and display brightness. | |
87 | * FIXME: this is exported to OSPM code. should work out an specific | |
88 | * display interface to OSPM. | |
89 | */ | |
90 | ||
91 | void mdfld_dsi_brightness_init(struct mdfld_dsi_config *dsi_config, int pipe) | |
92 | { | |
93 | struct mdfld_dsi_pkg_sender *sender = | |
94 | mdfld_dsi_get_pkg_sender(dsi_config); | |
22ccb2a1 SS |
95 | struct drm_device *dev; |
96 | struct drm_psb_private *dev_priv; | |
026abc33 KS |
97 | u32 gen_ctrl_val; |
98 | ||
99 | if (!sender) { | |
100 | DRM_ERROR("No sender found\n"); | |
101 | return; | |
102 | } | |
103 | ||
22ccb2a1 SS |
104 | dev = sender->dev; |
105 | dev_priv = dev->dev_private; | |
106 | ||
026abc33 KS |
107 | /* Set default display backlight value to 85% (0xd8)*/ |
108 | mdfld_dsi_send_mcs_short(sender, write_display_brightness, 0xd8, 1, | |
109 | true); | |
110 | ||
111 | /* Set minimum brightness setting of CABC function to 20% (0x33)*/ | |
112 | mdfld_dsi_send_mcs_short(sender, write_cabc_min_bright, 0x33, 1, true); | |
113 | ||
114 | /* Enable backlight or/and LABC */ | |
115 | gen_ctrl_val = BRIGHT_CNTL_BLOCK_ON | DISPLAY_DIMMING_ON | | |
116 | BACKLIGHT_ON; | |
117 | if (LABC_control == 1) | |
118 | gen_ctrl_val |= DISPLAY_DIMMING_ON | DISPLAY_BRIGHTNESS_AUTO | |
119 | | GAMMA_AUTO; | |
120 | ||
121 | if (LABC_control == 1) | |
122 | gen_ctrl_val |= AMBIENT_LIGHT_SENSE_ON; | |
123 | ||
124 | dev_priv->mipi_ctrl_display = gen_ctrl_val; | |
125 | ||
126 | mdfld_dsi_send_mcs_short(sender, write_ctrl_display, (u8)gen_ctrl_val, | |
127 | 1, true); | |
128 | ||
129 | mdfld_dsi_send_mcs_short(sender, write_ctrl_cabc, UI_IMAGE, 1, true); | |
130 | } | |
131 | ||
132 | void mdfld_dsi_brightness_control(struct drm_device *dev, int pipe, int level) | |
133 | { | |
134 | struct mdfld_dsi_pkg_sender *sender; | |
135 | struct drm_psb_private *dev_priv; | |
136 | struct mdfld_dsi_config *dsi_config; | |
137 | u32 gen_ctrl_val = 0; | |
138 | int p_type = TMD_VID; | |
139 | ||
140 | if (!dev || (pipe != 0 && pipe != 2)) { | |
141 | DRM_ERROR("Invalid parameter\n"); | |
142 | return; | |
143 | } | |
144 | ||
145 | p_type = mdfld_get_panel_type(dev, 0); | |
146 | ||
147 | dev_priv = dev->dev_private; | |
148 | ||
149 | if (pipe) | |
150 | dsi_config = dev_priv->dsi_configs[1]; | |
151 | else | |
152 | dsi_config = dev_priv->dsi_configs[0]; | |
153 | ||
154 | sender = mdfld_dsi_get_pkg_sender(dsi_config); | |
155 | ||
156 | if (!sender) { | |
157 | DRM_ERROR("No sender found\n"); | |
158 | return; | |
159 | } | |
160 | ||
161 | gen_ctrl_val = (level * 0xff / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL) & 0xff; | |
162 | ||
163 | dev_dbg(sender->dev->dev, "pipe = %d, gen_ctrl_val = %d.\n", | |
164 | pipe, gen_ctrl_val); | |
165 | ||
166 | if (p_type == TMD_VID) { | |
167 | /* Set display backlight value */ | |
168 | mdfld_dsi_send_mcs_short(sender, tmd_write_display_brightness, | |
169 | (u8)gen_ctrl_val, 1, true); | |
170 | } else { | |
171 | /* Set display backlight value */ | |
172 | mdfld_dsi_send_mcs_short(sender, write_display_brightness, | |
173 | (u8)gen_ctrl_val, 1, true); | |
174 | ||
175 | /* Enable backlight control */ | |
176 | if (level == 0) | |
177 | gen_ctrl_val = 0; | |
178 | else | |
179 | gen_ctrl_val = dev_priv->mipi_ctrl_display; | |
180 | ||
181 | mdfld_dsi_send_mcs_short(sender, write_ctrl_display, | |
182 | (u8)gen_ctrl_val, 1, true); | |
183 | } | |
184 | } | |
185 | ||
186 | static int mdfld_dsi_get_panel_status(struct mdfld_dsi_config *dsi_config, | |
187 | u8 dcs, u32 *data, bool hs) | |
188 | { | |
189 | struct mdfld_dsi_pkg_sender *sender | |
190 | = mdfld_dsi_get_pkg_sender(dsi_config); | |
191 | ||
192 | if (!sender || !data) { | |
193 | DRM_ERROR("Invalid parameter\n"); | |
194 | return -EINVAL; | |
195 | } | |
196 | ||
197 | return mdfld_dsi_read_mcs(sender, dcs, data, 1, hs); | |
198 | } | |
199 | ||
200 | int mdfld_dsi_get_power_mode(struct mdfld_dsi_config *dsi_config, u32 *mode, | |
201 | bool hs) | |
202 | { | |
203 | if (!dsi_config || !mode) { | |
204 | DRM_ERROR("Invalid parameter\n"); | |
205 | return -EINVAL; | |
206 | } | |
207 | ||
208 | return mdfld_dsi_get_panel_status(dsi_config, 0x0a, mode, hs); | |
209 | } | |
210 | ||
026abc33 KS |
211 | /* |
212 | * NOTE: this function was used by OSPM. | |
213 | * TODO: will be removed later, should work out display interfaces for OSPM | |
214 | */ | |
215 | void mdfld_dsi_controller_init(struct mdfld_dsi_config *dsi_config, int pipe) | |
216 | { | |
217 | if (!dsi_config || ((pipe != 0) && (pipe != 2))) { | |
218 | DRM_ERROR("Invalid parameters\n"); | |
219 | return; | |
220 | } | |
221 | ||
222 | mdfld_dsi_dpi_controller_init(dsi_config, pipe); | |
223 | } | |
224 | ||
225 | static void mdfld_dsi_connector_save(struct drm_connector *connector) | |
226 | { | |
227 | } | |
228 | ||
229 | static void mdfld_dsi_connector_restore(struct drm_connector *connector) | |
230 | { | |
231 | } | |
232 | ||
233 | /* FIXME: start using the force parameter */ | |
234 | static enum drm_connector_status | |
235 | mdfld_dsi_connector_detect(struct drm_connector *connector, bool force) | |
236 | { | |
237 | struct mdfld_dsi_connector *dsi_connector | |
238 | = mdfld_dsi_connector(connector); | |
239 | ||
240 | dsi_connector->status = connector_status_connected; | |
241 | ||
242 | return dsi_connector->status; | |
243 | } | |
244 | ||
245 | static int mdfld_dsi_connector_set_property(struct drm_connector *connector, | |
246 | struct drm_property *property, | |
247 | uint64_t value) | |
248 | { | |
249 | struct drm_encoder *encoder = connector->encoder; | |
026abc33 KS |
250 | |
251 | if (!strcmp(property->name, "scaling mode") && encoder) { | |
6306865d | 252 | struct gma_crtc *gma_crtc = to_gma_crtc(encoder->crtc); |
026abc33 KS |
253 | bool centerechange; |
254 | uint64_t val; | |
255 | ||
6306865d | 256 | if (!gma_crtc) |
026abc33 KS |
257 | goto set_prop_error; |
258 | ||
259 | switch (value) { | |
260 | case DRM_MODE_SCALE_FULLSCREEN: | |
261 | break; | |
262 | case DRM_MODE_SCALE_NO_SCALE: | |
263 | break; | |
264 | case DRM_MODE_SCALE_ASPECT: | |
265 | break; | |
266 | default: | |
267 | goto set_prop_error; | |
268 | } | |
269 | ||
a69ac9ea | 270 | if (drm_object_property_get_value(&connector->base, property, &val)) |
026abc33 KS |
271 | goto set_prop_error; |
272 | ||
273 | if (val == value) | |
274 | goto set_prop_done; | |
275 | ||
a69ac9ea | 276 | if (drm_object_property_set_value(&connector->base, |
026abc33 KS |
277 | property, value)) |
278 | goto set_prop_error; | |
279 | ||
280 | centerechange = (val == DRM_MODE_SCALE_NO_SCALE) || | |
281 | (value == DRM_MODE_SCALE_NO_SCALE); | |
282 | ||
6306865d PJ |
283 | if (gma_crtc->saved_mode.hdisplay != 0 && |
284 | gma_crtc->saved_mode.vdisplay != 0) { | |
026abc33 KS |
285 | if (centerechange) { |
286 | if (!drm_crtc_helper_set_mode(encoder->crtc, | |
6306865d | 287 | &gma_crtc->saved_mode, |
026abc33 KS |
288 | encoder->crtc->x, |
289 | encoder->crtc->y, | |
f4510a27 | 290 | encoder->crtc->primary->fb)) |
026abc33 KS |
291 | goto set_prop_error; |
292 | } else { | |
45fe734c | 293 | const struct drm_encoder_helper_funcs *funcs = |
026abc33 KS |
294 | encoder->helper_private; |
295 | funcs->mode_set(encoder, | |
6306865d PJ |
296 | &gma_crtc->saved_mode, |
297 | &gma_crtc->saved_adjusted_mode); | |
026abc33 KS |
298 | } |
299 | } | |
300 | } else if (!strcmp(property->name, "backlight") && encoder) { | |
a69ac9ea | 301 | if (drm_object_property_set_value(&connector->base, property, |
026abc33 KS |
302 | value)) |
303 | goto set_prop_error; | |
d112a816 ZY |
304 | else |
305 | gma_backlight_set(encoder->dev, value); | |
026abc33 KS |
306 | } |
307 | set_prop_done: | |
308 | return 0; | |
309 | set_prop_error: | |
310 | return -1; | |
311 | } | |
312 | ||
313 | static void mdfld_dsi_connector_destroy(struct drm_connector *connector) | |
314 | { | |
315 | struct mdfld_dsi_connector *dsi_connector = | |
316 | mdfld_dsi_connector(connector); | |
317 | struct mdfld_dsi_pkg_sender *sender; | |
318 | ||
319 | if (!dsi_connector) | |
320 | return; | |
34ea3d38 | 321 | drm_connector_unregister(connector); |
026abc33 KS |
322 | drm_connector_cleanup(connector); |
323 | sender = dsi_connector->pkg_sender; | |
324 | mdfld_dsi_pkg_sender_destroy(sender); | |
325 | kfree(dsi_connector); | |
326 | } | |
327 | ||
328 | static int mdfld_dsi_connector_get_modes(struct drm_connector *connector) | |
329 | { | |
330 | struct mdfld_dsi_connector *dsi_connector = | |
331 | mdfld_dsi_connector(connector); | |
332 | struct mdfld_dsi_config *dsi_config = | |
333 | mdfld_dsi_get_config(dsi_connector); | |
334 | struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; | |
335 | struct drm_display_mode *dup_mode = NULL; | |
336 | struct drm_device *dev = connector->dev; | |
337 | ||
338 | connector->display_info.min_vfreq = 0; | |
339 | connector->display_info.max_vfreq = 200; | |
340 | connector->display_info.min_hfreq = 0; | |
341 | connector->display_info.max_hfreq = 200; | |
342 | ||
343 | if (fixed_mode) { | |
344 | dev_dbg(dev->dev, "fixed_mode %dx%d\n", | |
345 | fixed_mode->hdisplay, fixed_mode->vdisplay); | |
346 | dup_mode = drm_mode_duplicate(dev, fixed_mode); | |
347 | drm_mode_probed_add(connector, dup_mode); | |
348 | return 1; | |
349 | } | |
350 | DRM_ERROR("Didn't get any modes!\n"); | |
351 | return 0; | |
352 | } | |
353 | ||
354 | static int mdfld_dsi_connector_mode_valid(struct drm_connector *connector, | |
355 | struct drm_display_mode *mode) | |
356 | { | |
357 | struct mdfld_dsi_connector *dsi_connector = | |
358 | mdfld_dsi_connector(connector); | |
359 | struct mdfld_dsi_config *dsi_config = | |
360 | mdfld_dsi_get_config(dsi_connector); | |
361 | struct drm_display_mode *fixed_mode = dsi_config->fixed_mode; | |
362 | ||
363 | if (mode->flags & DRM_MODE_FLAG_DBLSCAN) | |
364 | return MODE_NO_DBLESCAN; | |
365 | ||
366 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | |
367 | return MODE_NO_INTERLACE; | |
368 | ||
369 | /** | |
370 | * FIXME: current DC has no fitting unit, reject any mode setting | |
371 | * request | |
372 | * Will figure out a way to do up-scaling(pannel fitting) later. | |
373 | **/ | |
374 | if (fixed_mode) { | |
375 | if (mode->hdisplay != fixed_mode->hdisplay) | |
376 | return MODE_PANEL; | |
377 | ||
378 | if (mode->vdisplay != fixed_mode->vdisplay) | |
379 | return MODE_PANEL; | |
380 | } | |
381 | ||
382 | return MODE_OK; | |
383 | } | |
384 | ||
385 | static void mdfld_dsi_connector_dpms(struct drm_connector *connector, int mode) | |
386 | { | |
387 | if (mode == connector->dpms) | |
388 | return; | |
389 | ||
390 | /*first, execute dpms*/ | |
391 | ||
392 | drm_helper_connector_dpms(connector, mode); | |
393 | } | |
394 | ||
395 | static struct drm_encoder *mdfld_dsi_connector_best_encoder( | |
396 | struct drm_connector *connector) | |
397 | { | |
398 | struct mdfld_dsi_connector *dsi_connector = | |
399 | mdfld_dsi_connector(connector); | |
400 | struct mdfld_dsi_config *dsi_config = | |
401 | mdfld_dsi_get_config(dsi_connector); | |
402 | return &dsi_config->encoder->base.base; | |
403 | } | |
404 | ||
405 | /*DSI connector funcs*/ | |
406 | static const struct drm_connector_funcs mdfld_dsi_connector_funcs = { | |
407 | .dpms = /*drm_helper_connector_dpms*/mdfld_dsi_connector_dpms, | |
026abc33 KS |
408 | .detect = mdfld_dsi_connector_detect, |
409 | .fill_modes = drm_helper_probe_single_connector_modes, | |
410 | .set_property = mdfld_dsi_connector_set_property, | |
411 | .destroy = mdfld_dsi_connector_destroy, | |
412 | }; | |
413 | ||
414 | /*DSI connector helper funcs*/ | |
415 | static const struct drm_connector_helper_funcs | |
416 | mdfld_dsi_connector_helper_funcs = { | |
417 | .get_modes = mdfld_dsi_connector_get_modes, | |
418 | .mode_valid = mdfld_dsi_connector_mode_valid, | |
419 | .best_encoder = mdfld_dsi_connector_best_encoder, | |
420 | }; | |
421 | ||
422 | static int mdfld_dsi_get_default_config(struct drm_device *dev, | |
423 | struct mdfld_dsi_config *config, int pipe) | |
424 | { | |
425 | if (!dev || !config) { | |
426 | DRM_ERROR("Invalid parameters"); | |
427 | return -EINVAL; | |
428 | } | |
429 | ||
430 | config->bpp = 24; | |
431 | if (mdfld_get_panel_type(dev, pipe) == TC35876X) | |
432 | config->lane_count = 4; | |
433 | else | |
434 | config->lane_count = 2; | |
435 | config->channel_num = 0; | |
436 | ||
437 | if (mdfld_get_panel_type(dev, pipe) == TMD_VID) | |
438 | config->video_mode = MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_PULSE; | |
439 | else if (mdfld_get_panel_type(dev, pipe) == TC35876X) | |
440 | config->video_mode = | |
441 | MDFLD_DSI_VIDEO_NON_BURST_MODE_SYNC_EVENTS; | |
442 | else | |
443 | config->video_mode = MDFLD_DSI_VIDEO_BURST_MODE; | |
444 | ||
445 | return 0; | |
446 | } | |
447 | ||
448 | int mdfld_dsi_panel_reset(int pipe) | |
449 | { | |
450 | unsigned gpio; | |
451 | int ret = 0; | |
452 | ||
453 | switch (pipe) { | |
454 | case 0: | |
455 | gpio = 128; | |
456 | break; | |
457 | case 2: | |
458 | gpio = 34; | |
459 | break; | |
460 | default: | |
461 | DRM_ERROR("Invalid output\n"); | |
462 | return -EINVAL; | |
463 | } | |
464 | ||
465 | ret = gpio_request(gpio, "gfx"); | |
466 | if (ret) { | |
467 | DRM_ERROR("gpio_rqueset failed\n"); | |
468 | return ret; | |
469 | } | |
470 | ||
471 | ret = gpio_direction_output(gpio, 1); | |
472 | if (ret) { | |
473 | DRM_ERROR("gpio_direction_output failed\n"); | |
474 | goto gpio_error; | |
475 | } | |
476 | ||
477 | gpio_get_value(128); | |
478 | ||
479 | gpio_error: | |
480 | if (gpio_is_valid(gpio)) | |
481 | gpio_free(gpio); | |
482 | ||
483 | return ret; | |
484 | } | |
485 | ||
486 | /* | |
487 | * MIPI output init | |
488 | * @dev drm device | |
489 | * @pipe pipe number. 0 or 2 | |
490 | * @config | |
491 | * | |
492 | * Do the initialization of a MIPI output, including create DRM mode objects | |
493 | * initialization of DSI output on @pipe | |
494 | */ | |
495 | void mdfld_dsi_output_init(struct drm_device *dev, | |
496 | int pipe, | |
026abc33 KS |
497 | const struct panel_funcs *p_vid_funcs) |
498 | { | |
499 | struct mdfld_dsi_config *dsi_config; | |
500 | struct mdfld_dsi_connector *dsi_connector; | |
501 | struct drm_connector *connector; | |
502 | struct mdfld_dsi_encoder *encoder; | |
503 | struct drm_psb_private *dev_priv = dev->dev_private; | |
504 | struct panel_info dsi_panel_info; | |
505 | u32 width_mm, height_mm; | |
506 | ||
507 | dev_dbg(dev->dev, "init DSI output on pipe %d\n", pipe); | |
508 | ||
6380813c | 509 | if (pipe != 0 && pipe != 2) { |
026abc33 KS |
510 | DRM_ERROR("Invalid parameter\n"); |
511 | return; | |
512 | } | |
513 | ||
514 | /*create a new connetor*/ | |
515 | dsi_connector = kzalloc(sizeof(struct mdfld_dsi_connector), GFP_KERNEL); | |
516 | if (!dsi_connector) { | |
517 | DRM_ERROR("No memory"); | |
518 | return; | |
519 | } | |
520 | ||
521 | dsi_connector->pipe = pipe; | |
522 | ||
fda95c2e KS |
523 | dsi_config = kzalloc(sizeof(struct mdfld_dsi_config), |
524 | GFP_KERNEL); | |
525 | if (!dsi_config) { | |
526 | DRM_ERROR("cannot allocate memory for DSI config\n"); | |
527 | goto dsi_init_err0; | |
026abc33 | 528 | } |
fda95c2e | 529 | mdfld_dsi_get_default_config(dev, dsi_config, pipe); |
026abc33 KS |
530 | |
531 | dsi_connector->private = dsi_config; | |
532 | ||
533 | dsi_config->changed = 1; | |
534 | dsi_config->dev = dev; | |
535 | ||
536 | dsi_config->fixed_mode = p_vid_funcs->get_config_mode(dev); | |
537 | if (p_vid_funcs->get_panel_info(dev, pipe, &dsi_panel_info)) | |
538 | goto dsi_init_err0; | |
539 | ||
540 | width_mm = dsi_panel_info.width_mm; | |
541 | height_mm = dsi_panel_info.height_mm; | |
542 | ||
543 | dsi_config->mode = dsi_config->fixed_mode; | |
544 | dsi_config->connector = dsi_connector; | |
545 | ||
546 | if (!dsi_config->fixed_mode) { | |
547 | DRM_ERROR("No pannel fixed mode was found\n"); | |
548 | goto dsi_init_err0; | |
549 | } | |
550 | ||
551 | if (pipe && dev_priv->dsi_configs[0]) { | |
552 | dsi_config->dvr_ic_inited = 0; | |
553 | dev_priv->dsi_configs[1] = dsi_config; | |
554 | } else if (pipe == 0) { | |
555 | dsi_config->dvr_ic_inited = 1; | |
556 | dev_priv->dsi_configs[0] = dsi_config; | |
557 | } else { | |
558 | DRM_ERROR("Trying to init MIPI1 before MIPI0\n"); | |
559 | goto dsi_init_err0; | |
560 | } | |
561 | ||
562 | ||
563 | connector = &dsi_connector->base.base; | |
d56f57ac DV |
564 | dsi_connector->base.save = mdfld_dsi_connector_save; |
565 | dsi_connector->base.restore = mdfld_dsi_connector_restore; | |
566 | ||
026abc33 KS |
567 | drm_connector_init(dev, connector, &mdfld_dsi_connector_funcs, |
568 | DRM_MODE_CONNECTOR_LVDS); | |
569 | drm_connector_helper_add(connector, &mdfld_dsi_connector_helper_funcs); | |
570 | ||
571 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | |
572 | connector->display_info.width_mm = width_mm; | |
573 | connector->display_info.height_mm = height_mm; | |
574 | connector->interlace_allowed = false; | |
575 | connector->doublescan_allowed = false; | |
576 | ||
577 | /*attach properties*/ | |
a69ac9ea | 578 | drm_object_attach_property(&connector->base, |
026abc33 KS |
579 | dev->mode_config.scaling_mode_property, |
580 | DRM_MODE_SCALE_FULLSCREEN); | |
a69ac9ea | 581 | drm_object_attach_property(&connector->base, |
026abc33 KS |
582 | dev_priv->backlight_property, |
583 | MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); | |
584 | ||
585 | /*init DSI package sender on this output*/ | |
586 | if (mdfld_dsi_pkg_sender_init(dsi_connector, pipe)) { | |
587 | DRM_ERROR("Package Sender initialization failed on pipe %d\n", | |
588 | pipe); | |
589 | goto dsi_init_err0; | |
590 | } | |
591 | ||
592 | encoder = mdfld_dsi_dpi_init(dev, dsi_connector, p_vid_funcs); | |
593 | if (!encoder) { | |
594 | DRM_ERROR("Create DPI encoder failed\n"); | |
595 | goto dsi_init_err1; | |
596 | } | |
597 | encoder->private = dsi_config; | |
598 | dsi_config->encoder = encoder; | |
599 | encoder->base.type = (pipe == 0) ? INTEL_OUTPUT_MIPI : | |
600 | INTEL_OUTPUT_MIPI2; | |
34ea3d38 | 601 | drm_connector_register(connector); |
026abc33 KS |
602 | return; |
603 | ||
604 | /*TODO: add code to destroy outputs on error*/ | |
605 | dsi_init_err1: | |
606 | /*destroy sender*/ | |
607 | mdfld_dsi_pkg_sender_destroy(dsi_connector->pkg_sender); | |
608 | ||
609 | drm_connector_cleanup(connector); | |
610 | ||
611 | kfree(dsi_config->fixed_mode); | |
612 | kfree(dsi_config); | |
613 | dsi_init_err0: | |
614 | kfree(dsi_connector); | |
615 | } |