Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 1 | /* |
Ray Zhang | a8a5dfe | 2018-01-22 10:29:01 +0800 | [diff] [blame] | 2 | * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 and |
| 6 | * only version 2 as published by the Free Software Foundation. |
| 7 | * |
| 8 | * This program is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * GNU General Public License for more details. |
| 12 | * |
| 13 | */ |
| 14 | |
| 15 | |
| 16 | #define pr_fmt(fmt) "dsi-drm:[%s] " fmt, __func__ |
| 17 | #include <drm/drm_atomic_helper.h> |
| 18 | #include <drm/drm_atomic.h> |
| 19 | |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 20 | #include "msm_kms.h" |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 21 | #include "sde_connector.h" |
| 22 | #include "dsi_drm.h" |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 23 | #include "sde_trace.h" |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 24 | |
| 25 | #define to_dsi_bridge(x) container_of((x), struct dsi_bridge, base) |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 26 | #define to_dsi_state(x) container_of((x), struct dsi_connector_state, base) |
| 27 | |
| 28 | static void convert_to_dsi_mode(const struct drm_display_mode *drm_mode, |
| 29 | struct dsi_display_mode *dsi_mode) |
| 30 | { |
Ajay Singh Parmar | 1181d27 | 2016-07-21 11:12:23 -0700 | [diff] [blame] | 31 | memset(dsi_mode, 0, sizeof(*dsi_mode)); |
| 32 | |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 33 | dsi_mode->timing.h_active = drm_mode->hdisplay; |
| 34 | dsi_mode->timing.h_back_porch = drm_mode->htotal - drm_mode->hsync_end; |
| 35 | dsi_mode->timing.h_sync_width = drm_mode->htotal - |
| 36 | (drm_mode->hsync_start + dsi_mode->timing.h_back_porch); |
| 37 | dsi_mode->timing.h_front_porch = drm_mode->hsync_start - |
| 38 | drm_mode->hdisplay; |
| 39 | dsi_mode->timing.h_skew = drm_mode->hskew; |
| 40 | |
| 41 | dsi_mode->timing.v_active = drm_mode->vdisplay; |
| 42 | dsi_mode->timing.v_back_porch = drm_mode->vtotal - drm_mode->vsync_end; |
| 43 | dsi_mode->timing.v_sync_width = drm_mode->vtotal - |
| 44 | (drm_mode->vsync_start + dsi_mode->timing.v_back_porch); |
| 45 | |
| 46 | dsi_mode->timing.v_front_porch = drm_mode->vsync_start - |
| 47 | drm_mode->vdisplay; |
| 48 | |
| 49 | dsi_mode->timing.refresh_rate = drm_mode->vrefresh; |
| 50 | |
| 51 | dsi_mode->pixel_clk_khz = drm_mode->clock; |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 52 | |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 53 | dsi_mode->priv_info = |
| 54 | (struct dsi_display_mode_priv_info *)drm_mode->private; |
Jeykumar Sankaran | 6b345ac | 2017-03-15 19:17:19 -0700 | [diff] [blame] | 55 | |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 56 | if (msm_is_mode_seamless(drm_mode)) |
Lloyd Atkinson | 7d12ce0 | 2016-12-13 11:32:57 -0500 | [diff] [blame] | 57 | dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_SEAMLESS; |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 58 | if (msm_is_mode_dynamic_fps(drm_mode)) |
Lloyd Atkinson | 7d12ce0 | 2016-12-13 11:32:57 -0500 | [diff] [blame] | 59 | dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DFPS; |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 60 | if (msm_needs_vblank_pre_modeset(drm_mode)) |
Lloyd Atkinson | 7d12ce0 | 2016-12-13 11:32:57 -0500 | [diff] [blame] | 61 | dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VBLANK_PRE_MODESET; |
Jeykumar Sankaran | a7c7bbe | 2017-05-31 18:12:05 -0700 | [diff] [blame] | 62 | if (msm_is_mode_seamless_dms(drm_mode)) |
| 63 | dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_DMS; |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 64 | if (msm_is_mode_seamless_vrr(drm_mode)) |
| 65 | dsi_mode->dsi_mode_flags |= DSI_MODE_FLAG_VRR; |
Ray Zhang | a8a5dfe | 2018-01-22 10:29:01 +0800 | [diff] [blame] | 66 | |
| 67 | dsi_mode->timing.h_sync_polarity = |
| 68 | !!(drm_mode->flags & DRM_MODE_FLAG_PHSYNC); |
| 69 | dsi_mode->timing.v_sync_polarity = |
| 70 | !!(drm_mode->flags & DRM_MODE_FLAG_PVSYNC); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 71 | } |
| 72 | |
Chandan Uddaraju | 3f2cf42 | 2017-06-15 15:37:39 -0700 | [diff] [blame] | 73 | void dsi_convert_to_drm_mode(const struct dsi_display_mode *dsi_mode, |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 74 | struct drm_display_mode *drm_mode) |
| 75 | { |
Ajay Singh Parmar | 1181d27 | 2016-07-21 11:12:23 -0700 | [diff] [blame] | 76 | memset(drm_mode, 0, sizeof(*drm_mode)); |
| 77 | |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 78 | drm_mode->hdisplay = dsi_mode->timing.h_active; |
| 79 | drm_mode->hsync_start = drm_mode->hdisplay + |
| 80 | dsi_mode->timing.h_front_porch; |
| 81 | drm_mode->hsync_end = drm_mode->hsync_start + |
| 82 | dsi_mode->timing.h_sync_width; |
| 83 | drm_mode->htotal = drm_mode->hsync_end + dsi_mode->timing.h_back_porch; |
| 84 | drm_mode->hskew = dsi_mode->timing.h_skew; |
| 85 | |
| 86 | drm_mode->vdisplay = dsi_mode->timing.v_active; |
| 87 | drm_mode->vsync_start = drm_mode->vdisplay + |
| 88 | dsi_mode->timing.v_front_porch; |
| 89 | drm_mode->vsync_end = drm_mode->vsync_start + |
| 90 | dsi_mode->timing.v_sync_width; |
| 91 | drm_mode->vtotal = drm_mode->vsync_end + dsi_mode->timing.v_back_porch; |
| 92 | |
| 93 | drm_mode->vrefresh = dsi_mode->timing.refresh_rate; |
| 94 | drm_mode->clock = dsi_mode->pixel_clk_khz; |
| 95 | |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 96 | drm_mode->private = (int *)dsi_mode->priv_info; |
Jeykumar Sankaran | 6b345ac | 2017-03-15 19:17:19 -0700 | [diff] [blame] | 97 | |
Lloyd Atkinson | 7d12ce0 | 2016-12-13 11:32:57 -0500 | [diff] [blame] | 98 | if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_SEAMLESS) |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 99 | drm_mode->flags |= DRM_MODE_FLAG_SEAMLESS; |
Lloyd Atkinson | 7d12ce0 | 2016-12-13 11:32:57 -0500 | [diff] [blame] | 100 | if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DFPS) |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 101 | drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DYNAMIC_FPS; |
Lloyd Atkinson | 7d12ce0 | 2016-12-13 11:32:57 -0500 | [diff] [blame] | 102 | if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VBLANK_PRE_MODESET) |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 103 | drm_mode->private_flags |= MSM_MODE_FLAG_VBLANK_PRE_MODESET; |
Jeykumar Sankaran | a7c7bbe | 2017-05-31 18:12:05 -0700 | [diff] [blame] | 104 | if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_DMS) |
| 105 | drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_DMS; |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 106 | if (dsi_mode->dsi_mode_flags & DSI_MODE_FLAG_VRR) |
| 107 | drm_mode->private_flags |= MSM_MODE_FLAG_SEAMLESS_VRR; |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 108 | |
Ray Zhang | a8a5dfe | 2018-01-22 10:29:01 +0800 | [diff] [blame] | 109 | if (dsi_mode->timing.h_sync_polarity) |
| 110 | drm_mode->flags |= DRM_MODE_FLAG_PHSYNC; |
| 111 | if (dsi_mode->timing.v_sync_polarity) |
| 112 | drm_mode->flags |= DRM_MODE_FLAG_PVSYNC; |
| 113 | |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 114 | drm_mode_set_name(drm_mode); |
| 115 | } |
| 116 | |
| 117 | static int dsi_bridge_attach(struct drm_bridge *bridge) |
| 118 | { |
| 119 | struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); |
| 120 | |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 121 | if (!bridge) { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 122 | pr_err("Invalid params\n"); |
| 123 | return -EINVAL; |
| 124 | } |
| 125 | |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 126 | pr_debug("[%d] attached\n", c_bridge->id); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 127 | |
| 128 | return 0; |
| 129 | |
| 130 | } |
| 131 | |
| 132 | static void dsi_bridge_pre_enable(struct drm_bridge *bridge) |
| 133 | { |
| 134 | int rc = 0; |
| 135 | struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); |
| 136 | |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 137 | if (!bridge) { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 138 | pr_err("Invalid params\n"); |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 139 | return; |
| 140 | } |
| 141 | |
Shashank Babu Chinta Venkata | 7d60873 | 2017-05-31 14:10:26 -0700 | [diff] [blame] | 142 | if (!c_bridge || !c_bridge->display) |
| 143 | pr_err("Incorrect bridge details\n"); |
| 144 | |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 145 | /* By this point mode should have been validated through mode_fixup */ |
| 146 | rc = dsi_display_set_mode(c_bridge->display, |
| 147 | &(c_bridge->dsi_mode), 0x0); |
| 148 | if (rc) { |
| 149 | pr_err("[%d] failed to perform a mode set, rc=%d\n", |
| 150 | c_bridge->id, rc); |
| 151 | return; |
| 152 | } |
| 153 | |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 154 | if (c_bridge->dsi_mode.dsi_mode_flags & |
| 155 | (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) { |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 156 | pr_debug("[%d] seamless pre-enable\n", c_bridge->id); |
| 157 | return; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 158 | } |
| 159 | |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 160 | SDE_ATRACE_BEGIN("dsi_bridge_pre_enable"); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 161 | rc = dsi_display_prepare(c_bridge->display); |
| 162 | if (rc) { |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 163 | pr_err("[%d] DSI display prepare failed, rc=%d\n", |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 164 | c_bridge->id, rc); |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 165 | SDE_ATRACE_END("dsi_bridge_pre_enable"); |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 166 | return; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 167 | } |
| 168 | |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 169 | SDE_ATRACE_BEGIN("dsi_display_enable"); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 170 | rc = dsi_display_enable(c_bridge->display); |
| 171 | if (rc) { |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 172 | pr_err("[%d] DSI display enable failed, rc=%d\n", |
Shashank Babu Chinta Venkata | 7d60873 | 2017-05-31 14:10:26 -0700 | [diff] [blame] | 173 | c_bridge->id, rc); |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 174 | (void)dsi_display_unprepare(c_bridge->display); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 175 | } |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 176 | SDE_ATRACE_END("dsi_display_enable"); |
| 177 | SDE_ATRACE_END("dsi_bridge_pre_enable"); |
Shashank Babu Chinta Venkata | 7d60873 | 2017-05-31 14:10:26 -0700 | [diff] [blame] | 178 | |
| 179 | rc = dsi_display_splash_res_cleanup(c_bridge->display); |
| 180 | if (rc) |
| 181 | pr_err("Continuous splash pipeline cleanup failed, rc=%d\n", |
| 182 | rc); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 183 | } |
| 184 | |
| 185 | static void dsi_bridge_enable(struct drm_bridge *bridge) |
| 186 | { |
| 187 | int rc = 0; |
| 188 | struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); |
| 189 | |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 190 | if (!bridge) { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 191 | pr_err("Invalid params\n"); |
| 192 | return; |
| 193 | } |
| 194 | |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 195 | if (c_bridge->dsi_mode.dsi_mode_flags & |
| 196 | (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR)) { |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 197 | pr_debug("[%d] seamless enable\n", c_bridge->id); |
| 198 | return; |
| 199 | } |
| 200 | |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 201 | rc = dsi_display_post_enable(c_bridge->display); |
| 202 | if (rc) |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 203 | pr_err("[%d] DSI display post enabled failed, rc=%d\n", |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 204 | c_bridge->id, rc); |
| 205 | } |
| 206 | |
| 207 | static void dsi_bridge_disable(struct drm_bridge *bridge) |
| 208 | { |
| 209 | int rc = 0; |
Clarence Ip | 458a5d0 | 2017-11-27 18:15:16 -0500 | [diff] [blame] | 210 | struct dsi_display *display; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 211 | struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); |
| 212 | |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 213 | if (!bridge) { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 214 | pr_err("Invalid params\n"); |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 215 | return; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 216 | } |
Clarence Ip | 458a5d0 | 2017-11-27 18:15:16 -0500 | [diff] [blame] | 217 | display = c_bridge->display; |
| 218 | |
| 219 | if (display && display->drm_conn) |
| 220 | sde_connector_helper_bridge_disable(display->drm_conn); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 221 | |
| 222 | rc = dsi_display_pre_disable(c_bridge->display); |
| 223 | if (rc) { |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 224 | pr_err("[%d] DSI display pre disable failed, rc=%d\n", |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 225 | c_bridge->id, rc); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 226 | } |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 227 | } |
| 228 | |
| 229 | static void dsi_bridge_post_disable(struct drm_bridge *bridge) |
| 230 | { |
| 231 | int rc = 0; |
| 232 | struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); |
| 233 | |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 234 | if (!bridge) { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 235 | pr_err("Invalid params\n"); |
| 236 | return; |
| 237 | } |
| 238 | |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 239 | SDE_ATRACE_BEGIN("dsi_bridge_post_disable"); |
| 240 | SDE_ATRACE_BEGIN("dsi_display_disable"); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 241 | rc = dsi_display_disable(c_bridge->display); |
| 242 | if (rc) { |
| 243 | pr_err("[%d] DSI display disable failed, rc=%d\n", |
| 244 | c_bridge->id, rc); |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 245 | SDE_ATRACE_END("dsi_display_disable"); |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 246 | return; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 247 | } |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 248 | SDE_ATRACE_END("dsi_display_disable"); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 249 | |
| 250 | rc = dsi_display_unprepare(c_bridge->display); |
| 251 | if (rc) { |
| 252 | pr_err("[%d] DSI display unprepare failed, rc=%d\n", |
| 253 | c_bridge->id, rc); |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 254 | SDE_ATRACE_END("dsi_bridge_post_disable"); |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 255 | return; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 256 | } |
Narendra Muppalla | 77b3293 | 2017-05-10 13:53:11 -0700 | [diff] [blame] | 257 | SDE_ATRACE_END("dsi_bridge_post_disable"); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 258 | } |
| 259 | |
| 260 | static void dsi_bridge_mode_set(struct drm_bridge *bridge, |
| 261 | struct drm_display_mode *mode, |
| 262 | struct drm_display_mode *adjusted_mode) |
| 263 | { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 264 | struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 265 | |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 266 | if (!bridge || !mode || !adjusted_mode) { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 267 | pr_err("Invalid params\n"); |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 268 | return; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 269 | } |
| 270 | |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 271 | memset(&(c_bridge->dsi_mode), 0x0, sizeof(struct dsi_display_mode)); |
| 272 | convert_to_dsi_mode(adjusted_mode, &(c_bridge->dsi_mode)); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 273 | } |
| 274 | |
| 275 | static bool dsi_bridge_mode_fixup(struct drm_bridge *bridge, |
| 276 | const struct drm_display_mode *mode, |
| 277 | struct drm_display_mode *adjusted_mode) |
| 278 | { |
| 279 | int rc = 0; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 280 | struct dsi_bridge *c_bridge = to_dsi_bridge(bridge); |
Lloyd Atkinson | 560785e | 2017-11-16 14:04:15 -0500 | [diff] [blame] | 281 | struct dsi_display *display; |
| 282 | struct dsi_display_mode dsi_mode, cur_dsi_mode, *panel_dsi_mode; |
Jeykumar Sankaran | a7c7bbe | 2017-05-31 18:12:05 -0700 | [diff] [blame] | 283 | struct drm_display_mode cur_mode; |
Raviteja Tamatam | d7174ec | 2017-11-17 18:48:56 +0530 | [diff] [blame] | 284 | struct drm_crtc_state *crtc_state; |
| 285 | |
| 286 | crtc_state = container_of(mode, struct drm_crtc_state, mode); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 287 | |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 288 | if (!bridge || !mode || !adjusted_mode) { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 289 | pr_err("Invalid params\n"); |
| 290 | return false; |
| 291 | } |
| 292 | |
Lloyd Atkinson | 560785e | 2017-11-16 14:04:15 -0500 | [diff] [blame] | 293 | display = c_bridge->display; |
| 294 | if (!display) { |
| 295 | pr_err("Invalid params\n"); |
| 296 | return false; |
| 297 | } |
| 298 | |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 299 | convert_to_dsi_mode(mode, &dsi_mode); |
| 300 | |
Ray Zhang | a8a5dfe | 2018-01-22 10:29:01 +0800 | [diff] [blame] | 301 | /* external bridge doesn't use priv_info and dsi_mode_flags */ |
| 302 | if (!dsi_display_has_ext_bridge(display)) { |
| 303 | /* |
| 304 | * retrieve dsi mode from dsi driver's cache since not safe to |
| 305 | * take the drm mode config mutex in all paths |
| 306 | */ |
| 307 | rc = dsi_display_find_mode(display, &dsi_mode, &panel_dsi_mode); |
| 308 | if (rc) |
| 309 | return rc; |
Lloyd Atkinson | 560785e | 2017-11-16 14:04:15 -0500 | [diff] [blame] | 310 | |
Ray Zhang | a8a5dfe | 2018-01-22 10:29:01 +0800 | [diff] [blame] | 311 | /* |
| 312 | * propagate the private info to the adjusted_mode derived dsi |
| 313 | * mode |
| 314 | */ |
| 315 | dsi_mode.priv_info = panel_dsi_mode->priv_info; |
| 316 | dsi_mode.dsi_mode_flags = panel_dsi_mode->dsi_mode_flags; |
| 317 | } |
Lloyd Atkinson | 560785e | 2017-11-16 14:04:15 -0500 | [diff] [blame] | 318 | |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 319 | rc = dsi_display_validate_mode(c_bridge->display, &dsi_mode, |
| 320 | DSI_VALIDATE_FLAG_ALLOW_ADJUST); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 321 | if (rc) { |
Ajay Singh Parmar | 35c1e9f | 2016-06-10 23:25:13 -0700 | [diff] [blame] | 322 | pr_err("[%d] mode is not valid, rc=%d\n", c_bridge->id, rc); |
Jeykumar Sankaran | a7c7bbe | 2017-05-31 18:12:05 -0700 | [diff] [blame] | 323 | return false; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 324 | } |
| 325 | |
Raviteja Tamatam | d7174ec | 2017-11-17 18:48:56 +0530 | [diff] [blame] | 326 | if (bridge->encoder && bridge->encoder->crtc && |
| 327 | crtc_state->crtc) { |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 328 | |
Raviteja Tamatam | d7174ec | 2017-11-17 18:48:56 +0530 | [diff] [blame] | 329 | convert_to_dsi_mode(&crtc_state->crtc->state->mode, |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 330 | &cur_dsi_mode); |
| 331 | rc = dsi_display_validate_mode_vrr(c_bridge->display, |
| 332 | &cur_dsi_mode, &dsi_mode); |
| 333 | if (rc) |
| 334 | pr_debug("[%s] vrr mode mismatch failure rc=%d\n", |
| 335 | c_bridge->display->name, rc); |
| 336 | |
Raviteja Tamatam | d7174ec | 2017-11-17 18:48:56 +0530 | [diff] [blame] | 337 | cur_mode = crtc_state->crtc->mode; |
Jeykumar Sankaran | a7c7bbe | 2017-05-31 18:12:05 -0700 | [diff] [blame] | 338 | |
Jeykumar Sankaran | 2e12270 | 2017-12-14 16:36:15 -0800 | [diff] [blame] | 339 | /* No DMS/VRR when drm pipeline is changing */ |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 340 | if (!drm_mode_equal(&cur_mode, adjusted_mode) && |
Jeykumar Sankaran | 2e12270 | 2017-12-14 16:36:15 -0800 | [diff] [blame] | 341 | (!(dsi_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR)) && |
| 342 | (!crtc_state->active_changed || |
| 343 | display->is_cont_splash_enabled)) |
Jeykumar Sankaran | a7c7bbe | 2017-05-31 18:12:05 -0700 | [diff] [blame] | 344 | dsi_mode.dsi_mode_flags |= DSI_MODE_FLAG_DMS; |
| 345 | } |
| 346 | |
Lloyd Atkinson | 560785e | 2017-11-16 14:04:15 -0500 | [diff] [blame] | 347 | /* convert back to drm mode, propagating the private info & flags */ |
Chandan Uddaraju | 3f2cf42 | 2017-06-15 15:37:39 -0700 | [diff] [blame] | 348 | dsi_convert_to_drm_mode(&dsi_mode, adjusted_mode); |
Jeykumar Sankaran | a7c7bbe | 2017-05-31 18:12:05 -0700 | [diff] [blame] | 349 | |
| 350 | return true; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 351 | } |
| 352 | |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 353 | int dsi_conn_get_mode_info(const struct drm_display_mode *drm_mode, |
| 354 | struct msm_mode_info *mode_info, |
Alan Kwong | b1bca60 | 2017-09-18 17:28:45 -0400 | [diff] [blame] | 355 | u32 max_mixer_width, void *display) |
Jeykumar Sankaran | 6b345ac | 2017-03-15 19:17:19 -0700 | [diff] [blame] | 356 | { |
| 357 | struct dsi_display_mode dsi_mode; |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 358 | struct dsi_mode_info *timing; |
Jeykumar Sankaran | 6b345ac | 2017-03-15 19:17:19 -0700 | [diff] [blame] | 359 | |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 360 | if (!drm_mode || !mode_info) |
Jeykumar Sankaran | 6b345ac | 2017-03-15 19:17:19 -0700 | [diff] [blame] | 361 | return -EINVAL; |
| 362 | |
| 363 | convert_to_dsi_mode(drm_mode, &dsi_mode); |
| 364 | |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 365 | if (!dsi_mode.priv_info) |
Jeykumar Sankaran | 6b345ac | 2017-03-15 19:17:19 -0700 | [diff] [blame] | 366 | return -EINVAL; |
| 367 | |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 368 | memset(mode_info, 0, sizeof(*mode_info)); |
| 369 | |
| 370 | timing = &dsi_mode.timing; |
| 371 | mode_info->frame_rate = dsi_mode.timing.refresh_rate; |
| 372 | mode_info->vtotal = DSI_V_TOTAL(timing); |
| 373 | mode_info->prefill_lines = dsi_mode.priv_info->panel_prefill_lines; |
| 374 | mode_info->jitter_numer = dsi_mode.priv_info->panel_jitter_numer; |
| 375 | mode_info->jitter_denom = dsi_mode.priv_info->panel_jitter_denom; |
Vara Reddy | 812bd72 | 2017-09-20 07:19:19 -0700 | [diff] [blame] | 376 | mode_info->clk_rate = dsi_mode.priv_info->clk_rate_hz; |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 377 | |
| 378 | memcpy(&mode_info->topology, &dsi_mode.priv_info->topology, |
Jeykumar Sankaran | 6b345ac | 2017-03-15 19:17:19 -0700 | [diff] [blame] | 379 | sizeof(struct msm_display_topology)); |
| 380 | |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 381 | mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; |
| 382 | if (dsi_mode.priv_info->dsc_enabled) { |
| 383 | mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_DSC; |
| 384 | memcpy(&mode_info->comp_info.dsc_info, &dsi_mode.priv_info->dsc, |
| 385 | sizeof(dsi_mode.priv_info->dsc)); |
| 386 | } |
| 387 | |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 388 | if (dsi_mode.priv_info->roi_caps.enabled) { |
| 389 | memcpy(&mode_info->roi_caps, &dsi_mode.priv_info->roi_caps, |
| 390 | sizeof(dsi_mode.priv_info->roi_caps)); |
| 391 | } |
| 392 | |
Jeykumar Sankaran | 6b345ac | 2017-03-15 19:17:19 -0700 | [diff] [blame] | 393 | return 0; |
| 394 | } |
| 395 | |
Ray Zhang | a8a5dfe | 2018-01-22 10:29:01 +0800 | [diff] [blame] | 396 | int dsi_conn_ext_bridge_get_mode_info(const struct drm_display_mode *drm_mode, |
| 397 | struct msm_mode_info *mode_info, |
| 398 | u32 max_mixer_width, void *display) |
| 399 | { |
| 400 | struct msm_display_topology *topology; |
| 401 | struct dsi_display_mode dsi_mode; |
| 402 | struct dsi_mode_info *timing; |
| 403 | |
| 404 | if (!drm_mode || !mode_info) |
| 405 | return -EINVAL; |
| 406 | |
| 407 | convert_to_dsi_mode(drm_mode, &dsi_mode); |
| 408 | |
| 409 | memset(mode_info, 0, sizeof(*mode_info)); |
| 410 | |
| 411 | timing = &dsi_mode.timing; |
| 412 | mode_info->frame_rate = dsi_mode.timing.refresh_rate; |
| 413 | mode_info->vtotal = DSI_V_TOTAL(timing); |
| 414 | |
| 415 | topology = &mode_info->topology; |
| 416 | topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ? 2 : 1; |
| 417 | topology->num_enc = 0; |
| 418 | topology->num_intf = topology->num_lm; |
| 419 | |
| 420 | mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; |
| 421 | |
| 422 | return 0; |
| 423 | } |
| 424 | |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 425 | static const struct drm_bridge_funcs dsi_bridge_ops = { |
| 426 | .attach = dsi_bridge_attach, |
| 427 | .mode_fixup = dsi_bridge_mode_fixup, |
| 428 | .pre_enable = dsi_bridge_pre_enable, |
| 429 | .enable = dsi_bridge_enable, |
| 430 | .disable = dsi_bridge_disable, |
| 431 | .post_disable = dsi_bridge_post_disable, |
| 432 | .mode_set = dsi_bridge_mode_set, |
| 433 | }; |
| 434 | |
Alan Kwong | 769fba9 | 2017-11-13 16:50:36 -0500 | [diff] [blame] | 435 | int dsi_conn_set_info_blob(struct drm_connector *connector, |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 436 | void *info, void *display, struct msm_mode_info *mode_info) |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 437 | { |
Dhaval Patel | 4e57484 | 2016-08-23 15:11:37 -0700 | [diff] [blame] | 438 | struct dsi_display *dsi_display = display; |
| 439 | struct dsi_panel *panel; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 440 | |
Dhaval Patel | 4e57484 | 2016-08-23 15:11:37 -0700 | [diff] [blame] | 441 | if (!info || !dsi_display) |
| 442 | return -EINVAL; |
| 443 | |
Clarence Ip | 458a5d0 | 2017-11-27 18:15:16 -0500 | [diff] [blame] | 444 | dsi_display->drm_conn = connector; |
| 445 | |
Dhaval Patel | 4e57484 | 2016-08-23 15:11:37 -0700 | [diff] [blame] | 446 | sde_kms_info_add_keystr(info, |
| 447 | "display type", dsi_display->display_type); |
| 448 | |
| 449 | switch (dsi_display->type) { |
| 450 | case DSI_DISPLAY_SINGLE: |
| 451 | sde_kms_info_add_keystr(info, "display config", |
| 452 | "single display"); |
| 453 | break; |
| 454 | case DSI_DISPLAY_EXT_BRIDGE: |
| 455 | sde_kms_info_add_keystr(info, "display config", "ext bridge"); |
| 456 | break; |
| 457 | case DSI_DISPLAY_SPLIT: |
| 458 | sde_kms_info_add_keystr(info, "display config", |
| 459 | "split display"); |
| 460 | break; |
| 461 | case DSI_DISPLAY_SPLIT_EXT_BRIDGE: |
| 462 | sde_kms_info_add_keystr(info, "display config", |
| 463 | "split ext bridge"); |
| 464 | break; |
| 465 | default: |
| 466 | pr_debug("invalid display type:%d\n", dsi_display->type); |
| 467 | break; |
| 468 | } |
| 469 | |
| 470 | if (!dsi_display->panel) { |
| 471 | pr_debug("invalid panel data\n"); |
| 472 | goto end; |
| 473 | } |
| 474 | |
| 475 | panel = dsi_display->panel; |
| 476 | sde_kms_info_add_keystr(info, "panel name", panel->name); |
| 477 | |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 478 | switch (panel->panel_mode) { |
Dhaval Patel | 4e57484 | 2016-08-23 15:11:37 -0700 | [diff] [blame] | 479 | case DSI_OP_VIDEO_MODE: |
| 480 | sde_kms_info_add_keystr(info, "panel mode", "video"); |
| 481 | break; |
| 482 | case DSI_OP_CMD_MODE: |
| 483 | sde_kms_info_add_keystr(info, "panel mode", "command"); |
Alan Kwong | 9aa061c | 2016-11-06 21:17:12 -0500 | [diff] [blame] | 484 | sde_kms_info_add_keyint(info, "mdp_transfer_time_us", |
| 485 | panel->cmd_config.mdp_transfer_time_us); |
Dhaval Patel | 4e57484 | 2016-08-23 15:11:37 -0700 | [diff] [blame] | 486 | break; |
| 487 | default: |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 488 | pr_debug("invalid panel type:%d\n", panel->panel_mode); |
Dhaval Patel | 4e57484 | 2016-08-23 15:11:37 -0700 | [diff] [blame] | 489 | break; |
| 490 | } |
| 491 | sde_kms_info_add_keystr(info, "dfps support", |
| 492 | panel->dfps_caps.dfps_support ? "true" : "false"); |
| 493 | |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 494 | if (panel->dfps_caps.dfps_support) { |
| 495 | sde_kms_info_add_keyint(info, "min_fps", |
| 496 | panel->dfps_caps.min_refresh_rate); |
| 497 | sde_kms_info_add_keyint(info, "max_fps", |
| 498 | panel->dfps_caps.max_refresh_rate); |
| 499 | } |
| 500 | |
Dhaval Patel | 4e57484 | 2016-08-23 15:11:37 -0700 | [diff] [blame] | 501 | switch (panel->phy_props.rotation) { |
| 502 | case DSI_PANEL_ROTATE_NONE: |
| 503 | sde_kms_info_add_keystr(info, "panel orientation", "none"); |
| 504 | break; |
| 505 | case DSI_PANEL_ROTATE_H_FLIP: |
| 506 | sde_kms_info_add_keystr(info, "panel orientation", "horz flip"); |
| 507 | break; |
| 508 | case DSI_PANEL_ROTATE_V_FLIP: |
| 509 | sde_kms_info_add_keystr(info, "panel orientation", "vert flip"); |
| 510 | break; |
Dhaval Patel | 9b349aa | 2017-05-17 17:06:15 -0700 | [diff] [blame] | 511 | case DSI_PANEL_ROTATE_HV_FLIP: |
| 512 | sde_kms_info_add_keystr(info, "panel orientation", |
| 513 | "horz & vert flip"); |
| 514 | break; |
Dhaval Patel | 4e57484 | 2016-08-23 15:11:37 -0700 | [diff] [blame] | 515 | default: |
| 516 | pr_debug("invalid panel rotation:%d\n", |
| 517 | panel->phy_props.rotation); |
| 518 | break; |
| 519 | } |
| 520 | |
| 521 | switch (panel->bl_config.type) { |
| 522 | case DSI_BACKLIGHT_PWM: |
| 523 | sde_kms_info_add_keystr(info, "backlight type", "pwm"); |
| 524 | break; |
| 525 | case DSI_BACKLIGHT_WLED: |
| 526 | sde_kms_info_add_keystr(info, "backlight type", "wled"); |
| 527 | break; |
| 528 | case DSI_BACKLIGHT_DCS: |
| 529 | sde_kms_info_add_keystr(info, "backlight type", "dcs"); |
| 530 | break; |
| 531 | default: |
| 532 | pr_debug("invalid panel backlight type:%d\n", |
| 533 | panel->bl_config.type); |
| 534 | break; |
| 535 | } |
| 536 | |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 537 | if (mode_info && mode_info->roi_caps.enabled) { |
Lloyd Atkinson | e53b737 | 2017-03-22 17:16:47 -0400 | [diff] [blame] | 538 | sde_kms_info_add_keyint(info, "partial_update_num_roi", |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 539 | mode_info->roi_caps.num_roi); |
Lloyd Atkinson | e53b737 | 2017-03-22 17:16:47 -0400 | [diff] [blame] | 540 | sde_kms_info_add_keyint(info, "partial_update_xstart", |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 541 | mode_info->roi_caps.align.xstart_pix_align); |
Lloyd Atkinson | e53b737 | 2017-03-22 17:16:47 -0400 | [diff] [blame] | 542 | sde_kms_info_add_keyint(info, "partial_update_walign", |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 543 | mode_info->roi_caps.align.width_pix_align); |
Lloyd Atkinson | e53b737 | 2017-03-22 17:16:47 -0400 | [diff] [blame] | 544 | sde_kms_info_add_keyint(info, "partial_update_wmin", |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 545 | mode_info->roi_caps.align.min_width); |
Lloyd Atkinson | e53b737 | 2017-03-22 17:16:47 -0400 | [diff] [blame] | 546 | sde_kms_info_add_keyint(info, "partial_update_ystart", |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 547 | mode_info->roi_caps.align.ystart_pix_align); |
Lloyd Atkinson | e53b737 | 2017-03-22 17:16:47 -0400 | [diff] [blame] | 548 | sde_kms_info_add_keyint(info, "partial_update_halign", |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 549 | mode_info->roi_caps.align.height_pix_align); |
Lloyd Atkinson | e53b737 | 2017-03-22 17:16:47 -0400 | [diff] [blame] | 550 | sde_kms_info_add_keyint(info, "partial_update_hmin", |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 551 | mode_info->roi_caps.align.min_height); |
Lloyd Atkinson | e53b737 | 2017-03-22 17:16:47 -0400 | [diff] [blame] | 552 | sde_kms_info_add_keyint(info, "partial_update_roimerge", |
Jeykumar Sankaran | 736d79d | 2017-10-05 17:44:24 -0700 | [diff] [blame] | 553 | mode_info->roi_caps.merge_rois); |
Lloyd Atkinson | e53b737 | 2017-03-22 17:16:47 -0400 | [diff] [blame] | 554 | } |
| 555 | |
Dhaval Patel | 4e57484 | 2016-08-23 15:11:37 -0700 | [diff] [blame] | 556 | end: |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 557 | return 0; |
| 558 | } |
| 559 | |
| 560 | enum drm_connector_status dsi_conn_detect(struct drm_connector *conn, |
| 561 | bool force, |
| 562 | void *display) |
| 563 | { |
| 564 | enum drm_connector_status status = connector_status_unknown; |
Clarence Ip | a403932 | 2016-07-15 16:23:59 -0400 | [diff] [blame] | 565 | struct msm_display_info info; |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 566 | int rc; |
| 567 | |
| 568 | if (!conn || !display) |
| 569 | return status; |
| 570 | |
| 571 | /* get display dsi_info */ |
Clarence Ip | a403932 | 2016-07-15 16:23:59 -0400 | [diff] [blame] | 572 | memset(&info, 0x0, sizeof(info)); |
| 573 | rc = dsi_display_get_info(&info, display); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 574 | if (rc) { |
Clarence Ip | a403932 | 2016-07-15 16:23:59 -0400 | [diff] [blame] | 575 | pr_err("failed to get display info, rc=%d\n", rc); |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 576 | return connector_status_disconnected; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 577 | } |
| 578 | |
Clarence Ip | a403932 | 2016-07-15 16:23:59 -0400 | [diff] [blame] | 579 | if (info.capabilities & MSM_DISPLAY_CAP_HOT_PLUG) |
| 580 | status = (info.is_connected ? connector_status_connected : |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 581 | connector_status_disconnected); |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 582 | else |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 583 | status = connector_status_connected; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 584 | |
Clarence Ip | a403932 | 2016-07-15 16:23:59 -0400 | [diff] [blame] | 585 | conn->display_info.width_mm = info.width_mm; |
| 586 | conn->display_info.height_mm = info.height_mm; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 587 | |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 588 | return status; |
| 589 | } |
| 590 | |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 591 | void dsi_connector_put_modes(struct drm_connector *connector, |
| 592 | void *display) |
| 593 | { |
| 594 | struct drm_display_mode *drm_mode; |
| 595 | struct dsi_display_mode dsi_mode; |
| 596 | |
| 597 | if (!connector || !display) |
| 598 | return; |
| 599 | |
| 600 | list_for_each_entry(drm_mode, &connector->modes, head) { |
| 601 | convert_to_dsi_mode(drm_mode, &dsi_mode); |
| 602 | dsi_display_put_mode(display, &dsi_mode); |
| 603 | } |
| 604 | } |
| 605 | |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 606 | int dsi_connector_get_modes(struct drm_connector *connector, |
| 607 | void *display) |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 608 | { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 609 | u32 count = 0; |
Channagoud Kadabi | 075db3b | 2017-03-16 14:26:17 -0700 | [diff] [blame] | 610 | struct dsi_display_mode *modes = NULL; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 611 | struct drm_display_mode drm_mode; |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 612 | int rc, i; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 613 | |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 614 | if (sde_connector_get_panel(connector)) { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 615 | /* |
| 616 | * TODO: If drm_panel is attached, query modes from the panel. |
| 617 | * This is complicated in split dsi cases because panel is not |
| 618 | * attached to both connectors. |
| 619 | */ |
| 620 | goto end; |
| 621 | } |
Jeykumar Sankaran | 446a5f1 | 2017-05-09 20:30:39 -0700 | [diff] [blame] | 622 | rc = dsi_display_get_mode_count(display, &count); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 623 | if (rc) { |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 624 | pr_err("failed to get num of modes, rc=%d\n", rc); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 625 | goto end; |
| 626 | } |
| 627 | |
Lloyd Atkinson | 560785e | 2017-11-16 14:04:15 -0500 | [diff] [blame] | 628 | rc = dsi_display_get_modes(display, &modes); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 629 | if (rc) { |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 630 | pr_err("failed to get modes, rc=%d\n", rc); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 631 | count = 0; |
Lloyd Atkinson | 560785e | 2017-11-16 14:04:15 -0500 | [diff] [blame] | 632 | goto end; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 633 | } |
| 634 | |
| 635 | for (i = 0; i < count; i++) { |
| 636 | struct drm_display_mode *m; |
| 637 | |
| 638 | memset(&drm_mode, 0x0, sizeof(drm_mode)); |
Chandan Uddaraju | 3f2cf42 | 2017-06-15 15:37:39 -0700 | [diff] [blame] | 639 | dsi_convert_to_drm_mode(&modes[i], &drm_mode); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 640 | m = drm_mode_duplicate(connector->dev, &drm_mode); |
| 641 | if (!m) { |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 642 | pr_err("failed to add mode %ux%u\n", |
| 643 | drm_mode.hdisplay, |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 644 | drm_mode.vdisplay); |
| 645 | count = -ENOMEM; |
Lloyd Atkinson | 560785e | 2017-11-16 14:04:15 -0500 | [diff] [blame] | 646 | goto end; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 647 | } |
| 648 | m->width_mm = connector->display_info.width_mm; |
| 649 | m->height_mm = connector->display_info.height_mm; |
| 650 | drm_mode_probed_add(connector, m); |
| 651 | } |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 652 | end: |
| 653 | pr_debug("MODE COUNT =%d\n\n", count); |
| 654 | return count; |
| 655 | } |
| 656 | |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 657 | enum drm_mode_status dsi_conn_mode_valid(struct drm_connector *connector, |
| 658 | struct drm_display_mode *mode, |
| 659 | void *display) |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 660 | { |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 661 | struct dsi_display_mode dsi_mode; |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 662 | int rc; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 663 | |
| 664 | if (!connector || !mode) { |
| 665 | pr_err("Invalid params\n"); |
| 666 | return MODE_ERROR; |
| 667 | } |
| 668 | |
| 669 | convert_to_dsi_mode(mode, &dsi_mode); |
| 670 | |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 671 | rc = dsi_display_validate_mode(display, &dsi_mode, |
Ajay Singh Parmar | 62f795b | 2016-06-10 23:20:23 -0700 | [diff] [blame] | 672 | DSI_VALIDATE_FLAG_ALLOW_ADJUST); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 673 | if (rc) { |
Clarence Ip | 40d7d59 | 2016-07-15 16:02:26 -0400 | [diff] [blame] | 674 | pr_err("mode not supported, rc=%d\n", rc); |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 675 | return MODE_BAD; |
| 676 | } |
| 677 | |
| 678 | return MODE_OK; |
| 679 | } |
| 680 | |
Lloyd Atkinson | 05d7551 | 2017-01-17 14:45:51 -0500 | [diff] [blame] | 681 | int dsi_conn_pre_kickoff(struct drm_connector *connector, |
| 682 | void *display, |
| 683 | struct msm_display_kickoff_params *params) |
| 684 | { |
| 685 | if (!connector || !display || !params) { |
| 686 | pr_err("Invalid params\n"); |
| 687 | return -EINVAL; |
| 688 | } |
| 689 | |
| 690 | return dsi_display_pre_kickoff(display, params); |
| 691 | } |
| 692 | |
Clarence Ip | 80ada7f | 2017-05-04 09:55:21 -0700 | [diff] [blame] | 693 | void dsi_conn_enable_event(struct drm_connector *connector, |
| 694 | uint32_t event_idx, bool enable, void *display) |
| 695 | { |
| 696 | struct dsi_event_cb_info event_info; |
| 697 | |
| 698 | memset(&event_info, 0, sizeof(event_info)); |
| 699 | |
| 700 | event_info.event_cb = sde_connector_trigger_event; |
| 701 | event_info.event_usr_ptr = connector; |
| 702 | |
| 703 | dsi_display_enable_event(display, event_idx, &event_info, enable); |
| 704 | } |
| 705 | |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 706 | int dsi_conn_post_kickoff(struct drm_connector *connector) |
| 707 | { |
| 708 | struct drm_encoder *encoder; |
| 709 | struct dsi_bridge *c_bridge; |
| 710 | struct dsi_display_mode adj_mode; |
| 711 | struct dsi_display *display; |
| 712 | struct dsi_display_ctrl *m_ctrl, *ctrl; |
| 713 | int i, rc = 0; |
| 714 | |
Dhaval Patel | badfefd | 2017-09-26 13:58:02 -0700 | [diff] [blame] | 715 | if (!connector || !connector->state) { |
| 716 | pr_err("invalid connector or connector state"); |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 717 | return -EINVAL; |
Dhaval Patel | badfefd | 2017-09-26 13:58:02 -0700 | [diff] [blame] | 718 | } |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 719 | |
| 720 | encoder = connector->state->best_encoder; |
Dhaval Patel | badfefd | 2017-09-26 13:58:02 -0700 | [diff] [blame] | 721 | if (!encoder) { |
| 722 | pr_debug("best encoder is not available"); |
| 723 | return 0; |
| 724 | } |
| 725 | |
Raviteja Tamatam | 68892de | 2017-06-20 04:47:19 +0530 | [diff] [blame] | 726 | c_bridge = to_dsi_bridge(encoder->bridge); |
| 727 | adj_mode = c_bridge->dsi_mode; |
| 728 | display = c_bridge->display; |
| 729 | |
| 730 | if (adj_mode.dsi_mode_flags & DSI_MODE_FLAG_VRR) { |
| 731 | m_ctrl = &display->ctrl[display->clk_master_idx]; |
| 732 | rc = dsi_ctrl_timing_db_update(m_ctrl->ctrl, false); |
| 733 | if (rc) { |
| 734 | pr_err("[%s] failed to dfps update rc=%d\n", |
| 735 | display->name, rc); |
| 736 | return -EINVAL; |
| 737 | } |
| 738 | |
| 739 | /* Update the rest of the controllers */ |
| 740 | for (i = 0; i < display->ctrl_count; i++) { |
| 741 | ctrl = &display->ctrl[i]; |
| 742 | if (!ctrl->ctrl || (ctrl == m_ctrl)) |
| 743 | continue; |
| 744 | |
| 745 | rc = dsi_ctrl_timing_db_update(ctrl->ctrl, false); |
| 746 | if (rc) { |
| 747 | pr_err("[%s] failed to dfps update rc=%d\n", |
| 748 | display->name, rc); |
| 749 | return -EINVAL; |
| 750 | } |
| 751 | } |
| 752 | |
| 753 | c_bridge->dsi_mode.dsi_mode_flags &= ~DSI_MODE_FLAG_VRR; |
| 754 | } |
| 755 | |
| 756 | return 0; |
| 757 | } |
| 758 | |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 759 | struct dsi_bridge *dsi_drm_bridge_init(struct dsi_display *display, |
| 760 | struct drm_device *dev, |
| 761 | struct drm_encoder *encoder) |
| 762 | { |
| 763 | int rc = 0; |
| 764 | struct dsi_bridge *bridge; |
| 765 | |
| 766 | bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); |
| 767 | if (!bridge) { |
| 768 | rc = -ENOMEM; |
| 769 | goto error; |
| 770 | } |
| 771 | |
| 772 | bridge->display = display; |
| 773 | bridge->base.funcs = &dsi_bridge_ops; |
| 774 | bridge->base.encoder = encoder; |
| 775 | |
| 776 | rc = drm_bridge_attach(dev, &bridge->base); |
| 777 | if (rc) { |
| 778 | pr_err("failed to attach bridge, rc=%d\n", rc); |
| 779 | goto error_free_bridge; |
| 780 | } |
| 781 | |
| 782 | encoder->bridge = &bridge->base; |
| 783 | return bridge; |
| 784 | error_free_bridge: |
| 785 | kfree(bridge); |
| 786 | error: |
| 787 | return ERR_PTR(rc); |
| 788 | } |
| 789 | |
| 790 | void dsi_drm_bridge_cleanup(struct dsi_bridge *bridge) |
| 791 | { |
Lloyd Atkinson | e404caf | 2016-07-13 17:26:45 -0400 | [diff] [blame] | 792 | if (bridge && bridge->base.encoder) |
| 793 | bridge->base.encoder->bridge = NULL; |
Ajay Singh Parmar | 6bccfec | 2016-05-16 17:56:30 -0700 | [diff] [blame] | 794 | |
| 795 | kfree(bridge); |
| 796 | } |