blob: 21a23e214cf4874001bee53f298079f90b41953f [file] [log] [blame]
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001/*
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302 * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07003 *
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.
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -070012 */
13
14#define pr_fmt(fmt) "dsi-ctrl:[%s] " fmt, __func__
15
16#include <linux/of_device.h>
17#include <linux/err.h>
18#include <linux/regulator/consumer.h>
19#include <linux/clk.h>
20#include <linux/msm-bus.h>
21#include <linux/of_irq.h>
22#include <video/mipi_display.h>
23
24#include "msm_drv.h"
25#include "msm_kms.h"
26#include "msm_gpu.h"
Jordan Croused8e96522017-02-13 10:14:16 -070027#include "msm_mmu.h"
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -070028#include "dsi_ctrl.h"
29#include "dsi_ctrl_hw.h"
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +053030#include "dsi_clk.h"
31#include "dsi_pwr.h"
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -070032#include "dsi_catalog.h"
33
Dhaval Patela2430842017-06-15 14:32:36 -070034#include "sde_dbg.h"
35
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -070036#define DSI_CTRL_DEFAULT_LABEL "MDSS DSI CTRL"
37
38#define DSI_CTRL_TX_TO_MS 200
39
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -070040#define TO_ON_OFF(x) ((x) ? "ON" : "OFF")
Sandeep Panda5c51ea62017-08-02 13:50:15 +053041
42#define CEIL(x, y) (((x) + ((y)-1)) / (y))
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -070043/**
44 * enum dsi_ctrl_driver_ops - controller driver ops
45 */
46enum dsi_ctrl_driver_ops {
47 DSI_CTRL_OP_POWER_STATE_CHANGE,
48 DSI_CTRL_OP_CMD_ENGINE,
49 DSI_CTRL_OP_VID_ENGINE,
50 DSI_CTRL_OP_HOST_ENGINE,
51 DSI_CTRL_OP_CMD_TX,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -070052 DSI_CTRL_OP_HOST_INIT,
53 DSI_CTRL_OP_TPG,
54 DSI_CTRL_OP_PHY_SW_RESET,
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -070055 DSI_CTRL_OP_ASYNC_TIMING,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -070056 DSI_CTRL_OP_MAX
57};
58
59struct dsi_ctrl_list_item {
60 struct dsi_ctrl *ctrl;
61 struct list_head list;
62};
63
64static LIST_HEAD(dsi_ctrl_list);
65static DEFINE_MUTEX(dsi_ctrl_list_lock);
66
67static const enum dsi_ctrl_version dsi_ctrl_v1_4 = DSI_CTRL_VERSION_1_4;
68static const enum dsi_ctrl_version dsi_ctrl_v2_0 = DSI_CTRL_VERSION_2_0;
Shashank Babu Chinta Venkataafef8202017-04-21 13:49:56 -070069static const enum dsi_ctrl_version dsi_ctrl_v2_2 = DSI_CTRL_VERSION_2_2;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -070070
71static const struct of_device_id msm_dsi_of_match[] = {
72 {
73 .compatible = "qcom,dsi-ctrl-hw-v1.4",
74 .data = &dsi_ctrl_v1_4,
75 },
76 {
77 .compatible = "qcom,dsi-ctrl-hw-v2.0",
78 .data = &dsi_ctrl_v2_0,
79 },
Shashank Babu Chinta Venkataafef8202017-04-21 13:49:56 -070080 {
81 .compatible = "qcom,dsi-ctrl-hw-v2.2",
82 .data = &dsi_ctrl_v2_2,
83 },
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -070084 {}
85};
86
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -070087static ssize_t debugfs_state_info_read(struct file *file,
88 char __user *buff,
89 size_t count,
90 loff_t *ppos)
91{
92 struct dsi_ctrl *dsi_ctrl = file->private_data;
93 char *buf;
94 u32 len = 0;
95
96 if (!dsi_ctrl)
97 return -ENODEV;
98
99 if (*ppos)
100 return 0;
101
102 buf = kzalloc(SZ_4K, GFP_KERNEL);
103 if (!buf)
104 return -ENOMEM;
105
106 /* Dump current state */
107 len += snprintf((buf + len), (SZ_4K - len), "Current State:\n");
108 len += snprintf((buf + len), (SZ_4K - len),
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530109 "\tCTRL_ENGINE = %s\n",
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700110 TO_ON_OFF(dsi_ctrl->current_state.controller_state));
111 len += snprintf((buf + len), (SZ_4K - len),
112 "\tVIDEO_ENGINE = %s\n\tCOMMAND_ENGINE = %s\n",
113 TO_ON_OFF(dsi_ctrl->current_state.vid_engine_state),
114 TO_ON_OFF(dsi_ctrl->current_state.cmd_engine_state));
115
116 /* Dump clock information */
117 len += snprintf((buf + len), (SZ_4K - len), "\nClock Info:\n");
118 len += snprintf((buf + len), (SZ_4K - len),
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530119 "\tBYTE_CLK = %u, PIXEL_CLK = %u, ESC_CLK = %u\n",
120 dsi_ctrl->clk_freq.byte_clk_rate,
121 dsi_ctrl->clk_freq.pix_clk_rate,
122 dsi_ctrl->clk_freq.esc_clk_rate);
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700123
124 /* TODO: make sure that this does not exceed 4K */
125 if (copy_to_user(buff, buf, len)) {
126 kfree(buf);
127 return -EFAULT;
128 }
129
130 *ppos += len;
131 kfree(buf);
132 return len;
133}
134
135static ssize_t debugfs_reg_dump_read(struct file *file,
136 char __user *buff,
137 size_t count,
138 loff_t *ppos)
139{
140 struct dsi_ctrl *dsi_ctrl = file->private_data;
141 char *buf;
142 u32 len = 0;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530143 struct dsi_clk_ctrl_info clk_info;
144 int rc = 0;
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700145
146 if (!dsi_ctrl)
147 return -ENODEV;
148
149 if (*ppos)
150 return 0;
151
152 buf = kzalloc(SZ_4K, GFP_KERNEL);
153 if (!buf)
154 return -ENOMEM;
155
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530156 clk_info.client = DSI_CLK_REQ_DSI_CLIENT;
157 clk_info.clk_type = DSI_CORE_CLK;
158 clk_info.clk_state = DSI_CLK_ON;
159
160 rc = dsi_ctrl->clk_cb.dsi_clk_cb(dsi_ctrl->clk_cb.priv, clk_info);
161 if (rc) {
162 pr_err("failed to enable DSI core clocks\n");
163 kfree(buf);
164 return rc;
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700165 }
166
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530167 if (dsi_ctrl->hw.ops.reg_dump_to_buffer)
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530168 len = dsi_ctrl->hw.ops.reg_dump_to_buffer(&dsi_ctrl->hw,
169 buf, SZ_4K);
170
171 clk_info.clk_state = DSI_CLK_OFF;
172 rc = dsi_ctrl->clk_cb.dsi_clk_cb(dsi_ctrl->clk_cb.priv, clk_info);
173 if (rc) {
174 pr_err("failed to disable DSI core clocks\n");
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +0530175 kfree(buf);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530176 return rc;
177 }
178
179
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700180 /* TODO: make sure that this does not exceed 4K */
181 if (copy_to_user(buff, buf, len)) {
182 kfree(buf);
183 return -EFAULT;
184 }
185
186 *ppos += len;
187 kfree(buf);
188 return len;
189}
190
191static const struct file_operations state_info_fops = {
192 .open = simple_open,
193 .read = debugfs_state_info_read,
194};
195
196static const struct file_operations reg_dump_fops = {
197 .open = simple_open,
198 .read = debugfs_reg_dump_read,
199};
200
201static int dsi_ctrl_debugfs_init(struct dsi_ctrl *dsi_ctrl,
202 struct dentry *parent)
203{
204 int rc = 0;
205 struct dentry *dir, *state_file, *reg_dump;
Dhaval Patela2430842017-06-15 14:32:36 -0700206 char dbg_name[DSI_DEBUG_NAME_LEN];
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700207
208 dir = debugfs_create_dir(dsi_ctrl->name, parent);
209 if (IS_ERR_OR_NULL(dir)) {
210 rc = PTR_ERR(dir);
211 pr_err("[DSI_%d] debugfs create dir failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500212 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700213 goto error;
214 }
215
216 state_file = debugfs_create_file("state_info",
217 0444,
218 dir,
219 dsi_ctrl,
220 &state_info_fops);
221 if (IS_ERR_OR_NULL(state_file)) {
222 rc = PTR_ERR(state_file);
223 pr_err("[DSI_%d] state file failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500224 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700225 goto error_remove_dir;
226 }
227
228 reg_dump = debugfs_create_file("reg_dump",
229 0444,
230 dir,
231 dsi_ctrl,
232 &reg_dump_fops);
233 if (IS_ERR_OR_NULL(reg_dump)) {
234 rc = PTR_ERR(reg_dump);
235 pr_err("[DSI_%d] reg dump file failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500236 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700237 goto error_remove_dir;
238 }
239
240 dsi_ctrl->debugfs_root = dir;
Dhaval Patela2430842017-06-15 14:32:36 -0700241
242 snprintf(dbg_name, DSI_DEBUG_NAME_LEN, "dsi%d_ctrl",
243 dsi_ctrl->cell_index);
244 sde_dbg_reg_register_base(dbg_name, dsi_ctrl->hw.base,
245 msm_iomap_size(dsi_ctrl->pdev, "dsi_ctrl"));
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -0700246error_remove_dir:
247 debugfs_remove(dir);
248error:
249 return rc;
250}
251
252static int dsi_ctrl_debugfs_deinit(struct dsi_ctrl *dsi_ctrl)
253{
254 debugfs_remove(dsi_ctrl->debugfs_root);
255 return 0;
256}
257
Jordan Croused8e96522017-02-13 10:14:16 -0700258static inline struct msm_gem_address_space*
259dsi_ctrl_get_aspace(struct dsi_ctrl *dsi_ctrl,
260 int domain)
261{
262 if (!dsi_ctrl || !dsi_ctrl->drm_dev)
263 return NULL;
264
265 return msm_gem_smmu_address_space_get(dsi_ctrl->drm_dev, domain);
266}
267
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700268static int dsi_ctrl_check_state(struct dsi_ctrl *dsi_ctrl,
269 enum dsi_ctrl_driver_ops op,
270 u32 op_state)
271{
272 int rc = 0;
273 struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state;
274
275 switch (op) {
276 case DSI_CTRL_OP_POWER_STATE_CHANGE:
277 if (state->power_state == op_state) {
278 pr_debug("[%d] No change in state, pwr_state=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500279 dsi_ctrl->cell_index, op_state);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700280 rc = -EINVAL;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530281 } else if (state->power_state == DSI_CTRL_POWER_VREG_ON) {
Veera Sundaram Sankaran4e109162017-04-21 10:36:46 -0700282 if (state->vid_engine_state == DSI_CTRL_ENGINE_ON) {
283 pr_debug("[%d]State error: op=%d: %d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500284 dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700285 op_state,
Veera Sundaram Sankaran4e109162017-04-21 10:36:46 -0700286 state->vid_engine_state);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700287 rc = -EINVAL;
288 }
289 }
290 break;
291 case DSI_CTRL_OP_CMD_ENGINE:
292 if (state->cmd_engine_state == op_state) {
293 pr_debug("[%d] No change in state, cmd_state=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500294 dsi_ctrl->cell_index, op_state);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700295 rc = -EINVAL;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530296 } else if ((state->power_state != DSI_CTRL_POWER_VREG_ON) ||
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700297 (state->controller_state != DSI_CTRL_ENGINE_ON)) {
298 pr_debug("[%d]State error: op=%d: %d, %d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500299 dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700300 op,
301 state->power_state,
302 state->controller_state);
303 rc = -EINVAL;
304 }
305 break;
306 case DSI_CTRL_OP_VID_ENGINE:
307 if (state->vid_engine_state == op_state) {
308 pr_debug("[%d] No change in state, cmd_state=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500309 dsi_ctrl->cell_index, op_state);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700310 rc = -EINVAL;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530311 } else if ((state->power_state != DSI_CTRL_POWER_VREG_ON) ||
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700312 (state->controller_state != DSI_CTRL_ENGINE_ON)) {
313 pr_debug("[%d]State error: op=%d: %d, %d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500314 dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700315 op,
316 state->power_state,
317 state->controller_state);
318 rc = -EINVAL;
319 }
320 break;
321 case DSI_CTRL_OP_HOST_ENGINE:
322 if (state->controller_state == op_state) {
323 pr_debug("[%d] No change in state, ctrl_state=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500324 dsi_ctrl->cell_index, op_state);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700325 rc = -EINVAL;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530326 } else if (state->power_state != DSI_CTRL_POWER_VREG_ON) {
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700327 pr_debug("[%d]State error (link is off): op=%d:, %d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500328 dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700329 op_state,
330 state->power_state);
331 rc = -EINVAL;
332 } else if ((op_state == DSI_CTRL_ENGINE_OFF) &&
333 ((state->cmd_engine_state != DSI_CTRL_ENGINE_OFF) ||
334 (state->vid_engine_state != DSI_CTRL_ENGINE_OFF))) {
335 pr_debug("[%d]State error (eng on): op=%d: %d, %d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500336 dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700337 op_state,
338 state->cmd_engine_state,
339 state->vid_engine_state);
340 rc = -EINVAL;
341 }
342 break;
343 case DSI_CTRL_OP_CMD_TX:
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530344 if ((state->power_state != DSI_CTRL_POWER_VREG_ON) ||
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700345 (state->host_initialized != true) ||
346 (state->cmd_engine_state != DSI_CTRL_ENGINE_ON)) {
347 pr_debug("[%d]State error: op=%d: %d, %d, %d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500348 dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700349 op,
350 state->power_state,
351 state->host_initialized,
352 state->cmd_engine_state);
353 rc = -EINVAL;
354 }
355 break;
356 case DSI_CTRL_OP_HOST_INIT:
357 if (state->host_initialized == op_state) {
358 pr_debug("[%d] No change in state, host_init=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500359 dsi_ctrl->cell_index, op_state);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700360 rc = -EINVAL;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530361 } else if (state->power_state != DSI_CTRL_POWER_VREG_ON) {
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700362 pr_debug("[%d]State error: op=%d: %d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500363 dsi_ctrl->cell_index, op, state->power_state);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700364 rc = -EINVAL;
365 }
366 break;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700367 case DSI_CTRL_OP_TPG:
368 if (state->tpg_enabled == op_state) {
369 pr_debug("[%d] No change in state, tpg_enabled=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500370 dsi_ctrl->cell_index, op_state);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700371 rc = -EINVAL;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530372 } else if ((state->power_state != DSI_CTRL_POWER_VREG_ON) ||
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700373 (state->controller_state != DSI_CTRL_ENGINE_ON)) {
374 pr_debug("[%d]State error: op=%d: %d, %d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500375 dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700376 op,
377 state->power_state,
378 state->controller_state);
379 rc = -EINVAL;
380 }
381 break;
382 case DSI_CTRL_OP_PHY_SW_RESET:
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530383 if (state->power_state != DSI_CTRL_POWER_VREG_ON) {
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700384 pr_debug("[%d]State error: op=%d: %d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500385 dsi_ctrl->cell_index, op, state->power_state);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700386 rc = -EINVAL;
387 }
388 break;
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -0700389 case DSI_CTRL_OP_ASYNC_TIMING:
390 if (state->vid_engine_state != op_state) {
391 pr_err("[%d] Unexpected engine state vid_state=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -0500392 dsi_ctrl->cell_index, op_state);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -0700393 rc = -EINVAL;
394 }
395 break;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700396 default:
397 rc = -ENOTSUPP;
398 break;
399 }
400
401 return rc;
402}
403
404static void dsi_ctrl_update_state(struct dsi_ctrl *dsi_ctrl,
405 enum dsi_ctrl_driver_ops op,
406 u32 op_state)
407{
408 struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state;
409
410 switch (op) {
411 case DSI_CTRL_OP_POWER_STATE_CHANGE:
412 state->power_state = op_state;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700413 break;
414 case DSI_CTRL_OP_CMD_ENGINE:
415 state->cmd_engine_state = op_state;
416 break;
417 case DSI_CTRL_OP_VID_ENGINE:
418 state->vid_engine_state = op_state;
419 break;
420 case DSI_CTRL_OP_HOST_ENGINE:
421 state->controller_state = op_state;
422 break;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700423 case DSI_CTRL_OP_HOST_INIT:
424 state->host_initialized = (op_state == 1) ? true : false;
425 break;
426 case DSI_CTRL_OP_TPG:
427 state->tpg_enabled = (op_state == 1) ? true : false;
428 break;
429 case DSI_CTRL_OP_CMD_TX:
430 case DSI_CTRL_OP_PHY_SW_RESET:
431 default:
432 break;
433 }
434}
435
436static int dsi_ctrl_init_regmap(struct platform_device *pdev,
437 struct dsi_ctrl *ctrl)
438{
439 int rc = 0;
440 void __iomem *ptr;
441
442 ptr = msm_ioremap(pdev, "dsi_ctrl", ctrl->name);
443 if (IS_ERR(ptr)) {
444 rc = PTR_ERR(ptr);
445 return rc;
446 }
447
448 ctrl->hw.base = ptr;
449 pr_debug("[%s] map dsi_ctrl registers to %p\n", ctrl->name,
450 ctrl->hw.base);
451
Shashank Babu Chinta Venkataafef8202017-04-21 13:49:56 -0700452 switch (ctrl->version) {
453 case DSI_CTRL_VERSION_1_4:
454 case DSI_CTRL_VERSION_2_0:
455 ptr = msm_ioremap(pdev, "mmss_misc", ctrl->name);
456 if (IS_ERR(ptr)) {
457 pr_err("mmss_misc base address not found for [%s]\n",
458 ctrl->name);
459 rc = PTR_ERR(ptr);
460 return rc;
461 }
462 ctrl->hw.mmss_misc_base = ptr;
463 ctrl->hw.disp_cc_base = NULL;
464 break;
465 case DSI_CTRL_VERSION_2_2:
466 ptr = msm_ioremap(pdev, "disp_cc_base", ctrl->name);
467 if (IS_ERR(ptr)) {
468 pr_err("disp_cc base address not found for [%s]\n",
469 ctrl->name);
470 rc = PTR_ERR(ptr);
471 return rc;
472 }
473 ctrl->hw.disp_cc_base = ptr;
474 ctrl->hw.mmss_misc_base = NULL;
475 break;
476 default:
477 break;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700478 }
479
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700480 return rc;
481}
482
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700483static int dsi_ctrl_clocks_deinit(struct dsi_ctrl *ctrl)
484{
485 struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks;
486 struct dsi_link_clk_info *link = &ctrl->clk_info.link_clks;
487 struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks;
488
489 if (core->mdp_core_clk)
490 devm_clk_put(&ctrl->pdev->dev, core->mdp_core_clk);
491 if (core->iface_clk)
492 devm_clk_put(&ctrl->pdev->dev, core->iface_clk);
493 if (core->core_mmss_clk)
494 devm_clk_put(&ctrl->pdev->dev, core->core_mmss_clk);
495 if (core->bus_clk)
496 devm_clk_put(&ctrl->pdev->dev, core->bus_clk);
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530497 if (core->mnoc_clk)
498 devm_clk_put(&ctrl->pdev->dev, core->mnoc_clk);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700499
500 memset(core, 0x0, sizeof(*core));
501
502 if (link->byte_clk)
503 devm_clk_put(&ctrl->pdev->dev, link->byte_clk);
504 if (link->pixel_clk)
505 devm_clk_put(&ctrl->pdev->dev, link->pixel_clk);
506 if (link->esc_clk)
507 devm_clk_put(&ctrl->pdev->dev, link->esc_clk);
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530508 if (link->byte_intf_clk)
509 devm_clk_put(&ctrl->pdev->dev, link->byte_intf_clk);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700510
511 memset(link, 0x0, sizeof(*link));
512
513 if (rcg->byte_clk)
514 devm_clk_put(&ctrl->pdev->dev, rcg->byte_clk);
515 if (rcg->pixel_clk)
516 devm_clk_put(&ctrl->pdev->dev, rcg->pixel_clk);
517
518 memset(rcg, 0x0, sizeof(*rcg));
519
520 return 0;
521}
522
523static int dsi_ctrl_clocks_init(struct platform_device *pdev,
524 struct dsi_ctrl *ctrl)
525{
526 int rc = 0;
527 struct dsi_core_clk_info *core = &ctrl->clk_info.core_clks;
528 struct dsi_link_clk_info *link = &ctrl->clk_info.link_clks;
529 struct dsi_clk_link_set *rcg = &ctrl->clk_info.rcg_clks;
530
531 core->mdp_core_clk = devm_clk_get(&pdev->dev, "mdp_core_clk");
532 if (IS_ERR(core->mdp_core_clk)) {
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800533 core->mdp_core_clk = NULL;
534 pr_debug("failed to get mdp_core_clk, rc=%d\n", rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700535 }
536
537 core->iface_clk = devm_clk_get(&pdev->dev, "iface_clk");
538 if (IS_ERR(core->iface_clk)) {
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800539 core->iface_clk = NULL;
540 pr_debug("failed to get iface_clk, rc=%d\n", rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700541 }
542
543 core->core_mmss_clk = devm_clk_get(&pdev->dev, "core_mmss_clk");
544 if (IS_ERR(core->core_mmss_clk)) {
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800545 core->core_mmss_clk = NULL;
546 pr_debug("failed to get core_mmss_clk, rc=%d\n", rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700547 }
548
549 core->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
550 if (IS_ERR(core->bus_clk)) {
Shashank Babu Chinta Venkata74a03f12017-02-28 11:24:51 -0800551 core->bus_clk = NULL;
552 pr_debug("failed to get bus_clk, rc=%d\n", rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700553 }
554
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530555 core->mnoc_clk = devm_clk_get(&pdev->dev, "mnoc_clk");
556 if (IS_ERR(core->mnoc_clk)) {
557 core->mnoc_clk = NULL;
558 pr_debug("can't get mnoc clock, rc=%d\n", rc);
559 }
560
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700561 link->byte_clk = devm_clk_get(&pdev->dev, "byte_clk");
562 if (IS_ERR(link->byte_clk)) {
563 rc = PTR_ERR(link->byte_clk);
564 pr_err("failed to get byte_clk, rc=%d\n", rc);
565 goto fail;
566 }
567
568 link->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk");
569 if (IS_ERR(link->pixel_clk)) {
570 rc = PTR_ERR(link->pixel_clk);
571 pr_err("failed to get pixel_clk, rc=%d\n", rc);
572 goto fail;
573 }
574
Shashank Babu Chinta Venkata2f24e982017-04-21 14:57:53 -0700575 link->esc_clk = devm_clk_get(&pdev->dev, "esc_clk");
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700576 if (IS_ERR(link->esc_clk)) {
577 rc = PTR_ERR(link->esc_clk);
578 pr_err("failed to get esc_clk, rc=%d\n", rc);
579 goto fail;
580 }
581
Padmanabhan Komanduru2dd6ff62016-12-19 12:31:36 +0530582 link->byte_intf_clk = devm_clk_get(&pdev->dev, "byte_intf_clk");
583 if (IS_ERR(link->byte_intf_clk)) {
584 link->byte_intf_clk = NULL;
585 pr_debug("can't find byte intf clk, rc=%d\n", rc);
586 }
587
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700588 rcg->byte_clk = devm_clk_get(&pdev->dev, "byte_clk_rcg");
589 if (IS_ERR(rcg->byte_clk)) {
590 rc = PTR_ERR(rcg->byte_clk);
591 pr_err("failed to get byte_clk_rcg, rc=%d\n", rc);
592 goto fail;
593 }
594
595 rcg->pixel_clk = devm_clk_get(&pdev->dev, "pixel_clk_rcg");
596 if (IS_ERR(rcg->pixel_clk)) {
597 rc = PTR_ERR(rcg->pixel_clk);
598 pr_err("failed to get pixel_clk_rcg, rc=%d\n", rc);
599 goto fail;
600 }
601
602 return 0;
603fail:
604 dsi_ctrl_clocks_deinit(ctrl);
605 return rc;
606}
607
608static int dsi_ctrl_supplies_deinit(struct dsi_ctrl *ctrl)
609{
610 int i = 0;
611 int rc = 0;
612 struct dsi_regulator_info *regs;
613
614 regs = &ctrl->pwr_info.digital;
615 for (i = 0; i < regs->count; i++) {
616 if (!regs->vregs[i].vreg)
617 pr_err("vreg is NULL, should not reach here\n");
618 else
619 devm_regulator_put(regs->vregs[i].vreg);
620 }
621
622 regs = &ctrl->pwr_info.host_pwr;
623 for (i = 0; i < regs->count; i++) {
624 if (!regs->vregs[i].vreg)
625 pr_err("vreg is NULL, should not reach here\n");
626 else
627 devm_regulator_put(regs->vregs[i].vreg);
628 }
629
630 if (!ctrl->pwr_info.host_pwr.vregs) {
631 devm_kfree(&ctrl->pdev->dev, ctrl->pwr_info.host_pwr.vregs);
632 ctrl->pwr_info.host_pwr.vregs = NULL;
633 ctrl->pwr_info.host_pwr.count = 0;
634 }
635
636 if (!ctrl->pwr_info.digital.vregs) {
637 devm_kfree(&ctrl->pdev->dev, ctrl->pwr_info.digital.vregs);
638 ctrl->pwr_info.digital.vregs = NULL;
639 ctrl->pwr_info.digital.count = 0;
640 }
641
642 return rc;
643}
644
645static int dsi_ctrl_supplies_init(struct platform_device *pdev,
646 struct dsi_ctrl *ctrl)
647{
648 int rc = 0;
649 int i = 0;
650 struct dsi_regulator_info *regs;
651 struct regulator *vreg = NULL;
652
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530653 rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700654 &ctrl->pwr_info.digital,
655 "qcom,core-supply-entries");
Shashank Babu Chinta Venkata9a5a7b92017-04-24 18:22:41 -0700656 if (rc)
657 pr_debug("failed to get digital supply, rc = %d\n", rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700658
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530659 rc = dsi_pwr_get_dt_vreg_data(&pdev->dev,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700660 &ctrl->pwr_info.host_pwr,
661 "qcom,ctrl-supply-entries");
662 if (rc) {
663 pr_err("failed to get host power supplies, rc = %d\n", rc);
664 goto error_digital;
665 }
666
667 regs = &ctrl->pwr_info.digital;
668 for (i = 0; i < regs->count; i++) {
669 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
670 if (IS_ERR(vreg)) {
671 pr_err("failed to get %s regulator\n",
672 regs->vregs[i].vreg_name);
673 rc = PTR_ERR(vreg);
674 goto error_host_pwr;
675 }
676 regs->vregs[i].vreg = vreg;
677 }
678
679 regs = &ctrl->pwr_info.host_pwr;
680 for (i = 0; i < regs->count; i++) {
681 vreg = devm_regulator_get(&pdev->dev, regs->vregs[i].vreg_name);
682 if (IS_ERR(vreg)) {
683 pr_err("failed to get %s regulator\n",
684 regs->vregs[i].vreg_name);
685 for (--i; i >= 0; i--)
686 devm_regulator_put(regs->vregs[i].vreg);
687 rc = PTR_ERR(vreg);
688 goto error_digital_put;
689 }
690 regs->vregs[i].vreg = vreg;
691 }
692
693 return rc;
694
695error_digital_put:
696 regs = &ctrl->pwr_info.digital;
697 for (i = 0; i < regs->count; i++)
698 devm_regulator_put(regs->vregs[i].vreg);
699error_host_pwr:
700 devm_kfree(&pdev->dev, ctrl->pwr_info.host_pwr.vregs);
701 ctrl->pwr_info.host_pwr.vregs = NULL;
702 ctrl->pwr_info.host_pwr.count = 0;
703error_digital:
Shashank Babu Chinta Venkata9a5a7b92017-04-24 18:22:41 -0700704 if (ctrl->pwr_info.digital.vregs)
705 devm_kfree(&pdev->dev, ctrl->pwr_info.digital.vregs);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700706 ctrl->pwr_info.digital.vregs = NULL;
707 ctrl->pwr_info.digital.count = 0;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700708 return rc;
709}
710
711static int dsi_ctrl_axi_bus_client_init(struct platform_device *pdev,
712 struct dsi_ctrl *ctrl)
713{
714 int rc = 0;
715 struct dsi_ctrl_bus_scale_info *bus = &ctrl->axi_bus_info;
716
717 bus->bus_scale_table = msm_bus_cl_get_pdata(pdev);
718 if (IS_ERR_OR_NULL(bus->bus_scale_table)) {
719 rc = PTR_ERR(bus->bus_scale_table);
Shashank Babu Chinta Venkatacf411332017-05-10 17:30:08 -0700720 pr_debug("msm_bus_cl_get_pdata() failed, rc = %d\n", rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700721 bus->bus_scale_table = NULL;
722 return rc;
723 }
724
725 bus->bus_handle = msm_bus_scale_register_client(bus->bus_scale_table);
726 if (!bus->bus_handle) {
727 rc = -EINVAL;
728 pr_err("failed to register axi bus client\n");
729 }
730
731 return rc;
732}
733
734static int dsi_ctrl_axi_bus_client_deinit(struct dsi_ctrl *ctrl)
735{
736 struct dsi_ctrl_bus_scale_info *bus = &ctrl->axi_bus_info;
737
738 if (bus->bus_handle) {
739 msm_bus_scale_unregister_client(bus->bus_handle);
740
741 bus->bus_handle = 0;
742 }
743
744 return 0;
745}
746
747static int dsi_ctrl_validate_panel_info(struct dsi_ctrl *dsi_ctrl,
748 struct dsi_host_config *config)
749{
750 int rc = 0;
751 struct dsi_host_common_cfg *host_cfg = &config->common_config;
752
753 if (config->panel_mode >= DSI_OP_MODE_MAX) {
754 pr_err("Invalid dsi operation mode (%d)\n", config->panel_mode);
755 rc = -EINVAL;
756 goto err;
757 }
758
759 if ((host_cfg->data_lanes & (DSI_CLOCK_LANE - 1)) == 0) {
760 pr_err("No data lanes are enabled\n");
761 rc = -EINVAL;
762 goto err;
763 }
764err:
765 return rc;
766}
767
768static int dsi_ctrl_update_link_freqs(struct dsi_ctrl *dsi_ctrl,
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530769 struct dsi_host_config *config, void *clk_handle)
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700770{
771 int rc = 0;
772 u32 num_of_lanes = 0;
773 u32 bpp = 3;
774 u64 h_period, v_period, bit_rate, pclk_rate, bit_rate_per_lane,
775 byte_clk_rate;
776 struct dsi_host_common_cfg *host_cfg = &config->common_config;
777 struct dsi_mode_info *timing = &config->video_timing;
778
779 if (host_cfg->data_lanes & DSI_DATA_LANE_0)
780 num_of_lanes++;
781 if (host_cfg->data_lanes & DSI_DATA_LANE_1)
782 num_of_lanes++;
783 if (host_cfg->data_lanes & DSI_DATA_LANE_2)
784 num_of_lanes++;
785 if (host_cfg->data_lanes & DSI_DATA_LANE_3)
786 num_of_lanes++;
787
Vara Reddy812bd722017-09-20 07:19:19 -0700788 if (config->bit_clk_rate_hz == 0) {
789 h_period = DSI_H_TOTAL_DSC(timing);
790 v_period = DSI_V_TOTAL(timing);
791 bit_rate = h_period * v_period * timing->refresh_rate * bpp * 8;
792 } else {
793 bit_rate = config->bit_clk_rate_hz * num_of_lanes;
794 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700795
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700796 bit_rate_per_lane = bit_rate;
797 do_div(bit_rate_per_lane, num_of_lanes);
798 pclk_rate = bit_rate;
799 do_div(pclk_rate, (8 * bpp));
800 byte_clk_rate = bit_rate_per_lane;
801 do_div(byte_clk_rate, 8);
802 pr_debug("bit_clk_rate = %llu, bit_clk_rate_per_lane = %llu\n",
803 bit_rate, bit_rate_per_lane);
804 pr_debug("byte_clk_rate = %llu, pclk_rate = %llu\n",
805 byte_clk_rate, pclk_rate);
806
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530807 dsi_ctrl->clk_freq.byte_clk_rate = byte_clk_rate;
808 dsi_ctrl->clk_freq.pix_clk_rate = pclk_rate;
809 dsi_ctrl->clk_freq.esc_clk_rate = config->esc_clk_rate_hz;
810
811 rc = dsi_clk_set_link_frequencies(clk_handle, dsi_ctrl->clk_freq,
Alexander Beykun32a6a182017-02-27 17:46:51 -0500812 dsi_ctrl->cell_index);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700813 if (rc)
814 pr_err("Failed to update link frequencies\n");
815
816 return rc;
817}
818
819static int dsi_ctrl_enable_supplies(struct dsi_ctrl *dsi_ctrl, bool enable)
820{
821 int rc = 0;
822
823 if (enable) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530824 if (!dsi_ctrl->current_state.host_initialized) {
825 rc = dsi_pwr_enable_regulator(
826 &dsi_ctrl->pwr_info.host_pwr, true);
827 if (rc) {
828 pr_err("failed to enable host power regs\n");
829 goto error;
830 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700831 }
832
833 rc = dsi_pwr_enable_regulator(&dsi_ctrl->pwr_info.digital,
834 true);
835 if (rc) {
836 pr_err("failed to enable gdsc, rc=%d\n", rc);
837 (void)dsi_pwr_enable_regulator(
838 &dsi_ctrl->pwr_info.host_pwr,
839 false
840 );
841 goto error;
842 }
843 } else {
844 rc = dsi_pwr_enable_regulator(&dsi_ctrl->pwr_info.digital,
845 false);
846 if (rc) {
847 pr_err("failed to disable gdsc, rc=%d\n", rc);
848 goto error;
849 }
850
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +0530851 if (!dsi_ctrl->current_state.host_initialized) {
852 rc = dsi_pwr_enable_regulator(
853 &dsi_ctrl->pwr_info.host_pwr, false);
854 if (rc) {
855 pr_err("failed to disable host power regs\n");
856 goto error;
857 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700858 }
859 }
860error:
861 return rc;
862}
863
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700864static int dsi_ctrl_copy_and_pad_cmd(struct dsi_ctrl *dsi_ctrl,
865 const struct mipi_dsi_packet *packet,
866 u8 **buffer,
867 u32 *size)
868{
869 int rc = 0;
870 u8 *buf = NULL;
871 u32 len, i;
872
873 len = packet->size;
874 len += 0x3; len &= ~0x03; /* Align to 32 bits */
875
876 buf = devm_kzalloc(&dsi_ctrl->pdev->dev, len * sizeof(u8), GFP_KERNEL);
877 if (!buf)
878 return -ENOMEM;
879
880 for (i = 0; i < len; i++) {
881 if (i >= packet->size)
882 buf[i] = 0xFF;
883 else if (i < sizeof(packet->header))
884 buf[i] = packet->header[i];
885 else
886 buf[i] = packet->payload[i - sizeof(packet->header)];
887 }
888
889 if (packet->payload_length > 0)
890 buf[3] |= BIT(6);
891
892 buf[3] |= BIT(7);
Sandeep Panda79450002017-05-08 17:14:24 +0530893
894 /* send embedded BTA for read commands */
895 if ((buf[2] & 0x3f) == MIPI_DSI_DCS_READ)
896 buf[3] |= BIT(5);
897
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700898 *buffer = buf;
899 *size = len;
900
901 return rc;
902}
903
Sandeep Panda5c51ea62017-08-02 13:50:15 +0530904static void dsi_ctrl_wait_for_video_done(struct dsi_ctrl *dsi_ctrl)
905{
906 u32 v_total = 0, v_blank = 0, sleep_ms = 0, fps = 0, ret;
907 struct dsi_mode_info *timing;
908
909 if (dsi_ctrl->host_config.panel_mode != DSI_OP_VIDEO_MODE)
910 return;
911
912 dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw,
913 DSI_VIDEO_MODE_FRAME_DONE);
914
915 dsi_ctrl_enable_status_interrupt(dsi_ctrl,
916 DSI_SINT_VIDEO_MODE_FRAME_DONE, NULL);
917 reinit_completion(&dsi_ctrl->irq_info.vid_frame_done);
918 ret = wait_for_completion_timeout(
919 &dsi_ctrl->irq_info.vid_frame_done,
920 msecs_to_jiffies(DSI_CTRL_TX_TO_MS));
921 if (ret <= 0)
922 pr_debug("wait for video done failed\n");
923 dsi_ctrl_disable_status_interrupt(dsi_ctrl,
924 DSI_SINT_VIDEO_MODE_FRAME_DONE);
925
926 timing = &(dsi_ctrl->host_config.video_timing);
927 v_total = timing->v_sync_width + timing->v_back_porch +
928 timing->v_front_porch + timing->v_active;
929 v_blank = timing->v_sync_width + timing->v_back_porch;
930 fps = timing->refresh_rate;
931
932 sleep_ms = CEIL((v_blank * 1000), (v_total * fps)) + 1;
933 udelay(sleep_ms * 1000);
934}
935
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700936static int dsi_message_tx(struct dsi_ctrl *dsi_ctrl,
937 const struct mipi_dsi_msg *msg,
938 u32 flags)
939{
Clarence Ip80ada7f2017-05-04 09:55:21 -0700940 int rc = 0, ret = 0;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700941 struct mipi_dsi_packet packet;
942 struct dsi_ctrl_cmd_dma_fifo_info cmd;
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -0700943 struct dsi_ctrl_cmd_dma_info cmd_mem;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700944 u32 hw_flags = 0;
945 u32 length = 0;
946 u8 *buffer = NULL;
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -0700947 u32 cnt = 0;
948 u8 *cmdbuf;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700949
950 rc = mipi_dsi_create_packet(&packet, msg);
951 if (rc) {
952 pr_err("Failed to create message packet, rc=%d\n", rc);
953 goto error;
954 }
955
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -0700956 if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
957 rc = dsi_ctrl_copy_and_pad_cmd(dsi_ctrl,
958 &packet,
959 &buffer,
960 &length);
961
962 if (rc) {
963 pr_err("[%s] failed to copy message, rc=%d\n",
964 dsi_ctrl->name, rc);
965 goto error;
966 }
967
968 cmd_mem.offset = dsi_ctrl->cmd_buffer_iova;
969 cmd_mem.length = length;
970 cmd_mem.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ?
971 true : false;
972 cmd_mem.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
973 true : false;
974 cmd_mem.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
975 true : false;
976
977 cmdbuf = (u8 *)(dsi_ctrl->vaddr);
978 for (cnt = 0; cnt < length; cnt++)
979 cmdbuf[cnt] = buffer[cnt];
980
981 } else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -0700982 rc = dsi_ctrl_copy_and_pad_cmd(dsi_ctrl,
983 &packet,
984 &buffer,
985 &length);
986 if (rc) {
987 pr_err("[%s] failed to copy message, rc=%d\n",
988 dsi_ctrl->name, rc);
989 goto error;
990 }
991 cmd.command = (u32 *)buffer;
992 cmd.size = length;
993 cmd.en_broadcast = (flags & DSI_CTRL_CMD_BROADCAST) ?
994 true : false;
995 cmd.is_master = (flags & DSI_CTRL_CMD_BROADCAST_MASTER) ?
996 true : false;
997 cmd.use_lpm = (msg->flags & MIPI_DSI_MSG_USE_LPM) ?
998 true : false;
999 }
1000
1001 hw_flags |= (flags & DSI_CTRL_CMD_DEFER_TRIGGER) ?
1002 DSI_CTRL_HW_CMD_WAIT_FOR_TRIGGER : 0;
1003
Clarence Ip80ada7f2017-05-04 09:55:21 -07001004 if (flags & DSI_CTRL_CMD_DEFER_TRIGGER) {
1005 if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
1006 dsi_ctrl->hw.ops.kickoff_command(&dsi_ctrl->hw,
1007 &cmd_mem,
1008 hw_flags);
1009 } else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
1010 dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw,
1011 &cmd,
1012 hw_flags);
1013 }
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07001014 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001015
1016 if (!(flags & DSI_CTRL_CMD_DEFER_TRIGGER)) {
Sandeep Panda5c51ea62017-08-02 13:50:15 +05301017 dsi_ctrl_wait_for_video_done(dsi_ctrl);
Clarence Ip80ada7f2017-05-04 09:55:21 -07001018 dsi_ctrl_enable_status_interrupt(dsi_ctrl,
1019 DSI_SINT_CMD_MODE_DMA_DONE, NULL);
1020 reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001021
Clarence Ip80ada7f2017-05-04 09:55:21 -07001022 if (flags & DSI_CTRL_CMD_FETCH_MEMORY) {
1023 dsi_ctrl->hw.ops.kickoff_command(&dsi_ctrl->hw,
1024 &cmd_mem,
1025 hw_flags);
1026 } else if (flags & DSI_CTRL_CMD_FIFO_STORE) {
1027 dsi_ctrl->hw.ops.kickoff_fifo_command(&dsi_ctrl->hw,
1028 &cmd,
1029 hw_flags);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001030 }
Clarence Ip80ada7f2017-05-04 09:55:21 -07001031
1032 ret = wait_for_completion_timeout(
1033 &dsi_ctrl->irq_info.cmd_dma_done,
1034 msecs_to_jiffies(DSI_CTRL_TX_TO_MS));
1035
1036 if (ret == 0) {
1037 u32 status = 0;
1038 u32 mask = DSI_CMD_MODE_DMA_DONE;
1039
1040 if (status & mask) {
1041 status |= (DSI_CMD_MODE_DMA_DONE |
1042 DSI_BTA_DONE);
1043 dsi_ctrl->hw.ops.clear_interrupt_status(
1044 &dsi_ctrl->hw,
1045 status);
1046 dsi_ctrl_disable_status_interrupt(dsi_ctrl,
1047 DSI_SINT_CMD_MODE_DMA_DONE);
1048 complete_all(&dsi_ctrl->irq_info.cmd_dma_done);
1049 pr_warn("dma_tx done but irq not triggered\n");
1050 } else {
1051 rc = -ETIMEDOUT;
1052 dsi_ctrl_disable_status_interrupt(dsi_ctrl,
1053 DSI_SINT_CMD_MODE_DMA_DONE);
1054 pr_err("[DSI_%d]Command transfer failed\n",
1055 dsi_ctrl->cell_index);
1056 }
1057 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001058
1059 dsi_ctrl->hw.ops.reset_cmd_fifo(&dsi_ctrl->hw);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001060 }
1061error:
1062 if (buffer)
1063 devm_kfree(&dsi_ctrl->pdev->dev, buffer);
1064 return rc;
1065}
1066
1067static int dsi_set_max_return_size(struct dsi_ctrl *dsi_ctrl,
1068 const struct mipi_dsi_msg *rx_msg,
1069 u32 size)
1070{
1071 int rc = 0;
1072 u8 tx[2] = { (u8)(size & 0xFF), (u8)(size >> 8) };
Sandeep Panda79450002017-05-08 17:14:24 +05301073 u32 flags = DSI_CTRL_CMD_FETCH_MEMORY;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001074 struct mipi_dsi_msg msg = {
1075 .channel = rx_msg->channel,
1076 .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
1077 .tx_len = 2,
1078 .tx_buf = tx,
1079 };
1080
Sandeep Panda79450002017-05-08 17:14:24 +05301081 rc = dsi_message_tx(dsi_ctrl, &msg, flags);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001082 if (rc)
1083 pr_err("failed to send max return size packet, rc=%d\n", rc);
1084
1085 return rc;
1086}
1087
Sandeep Panda79450002017-05-08 17:14:24 +05301088/* Helper functions to support DCS read operation */
1089static int dsi_parse_short_read1_resp(const struct mipi_dsi_msg *msg,
1090 unsigned char *buff)
1091{
1092 u8 *data = msg->rx_buf;
1093 int read_len = 1;
1094
1095 if (!data)
1096 return 0;
1097
1098 /* remove dcs type */
1099 if (msg->rx_len >= 1)
1100 data[0] = buff[1];
1101 else
1102 read_len = 0;
1103
1104 return read_len;
1105}
1106
1107static int dsi_parse_short_read2_resp(const struct mipi_dsi_msg *msg,
1108 unsigned char *buff)
1109{
1110 u8 *data = msg->rx_buf;
1111 int read_len = 2;
1112
1113 if (!data)
1114 return 0;
1115
1116 /* remove dcs type */
1117 if (msg->rx_len >= 2) {
1118 data[0] = buff[1];
1119 data[1] = buff[2];
1120 } else {
1121 read_len = 0;
1122 }
1123
1124 return read_len;
1125}
1126
1127static int dsi_parse_long_read_resp(const struct mipi_dsi_msg *msg,
1128 unsigned char *buff)
1129{
1130 if (!msg->rx_buf)
1131 return 0;
1132
1133 /* remove dcs type */
1134 if (msg->rx_buf && msg->rx_len)
1135 memcpy(msg->rx_buf, buff + 4, msg->rx_len);
1136
1137 return msg->rx_len;
1138}
1139
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001140static int dsi_message_rx(struct dsi_ctrl *dsi_ctrl,
1141 const struct mipi_dsi_msg *msg,
1142 u32 flags)
1143{
1144 int rc = 0;
Sandeep Panda79450002017-05-08 17:14:24 +05301145 u32 rd_pkt_size, total_read_len, hw_read_cnt;
1146 u32 current_read_len = 0, total_bytes_read = 0;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001147 bool short_resp = false;
1148 bool read_done = false;
Sandeep Panda79450002017-05-08 17:14:24 +05301149 u32 dlen, diff, rlen = msg->rx_len;
1150 unsigned char *buff;
1151 char cmd;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001152
1153 if (msg->rx_len <= 2) {
1154 short_resp = true;
1155 rd_pkt_size = msg->rx_len;
1156 total_read_len = 4;
1157 } else {
1158 short_resp = false;
1159 current_read_len = 10;
1160 if (msg->rx_len < current_read_len)
1161 rd_pkt_size = msg->rx_len;
1162 else
1163 rd_pkt_size = current_read_len;
1164
1165 total_read_len = current_read_len + 6;
1166 }
Sandeep Panda79450002017-05-08 17:14:24 +05301167 buff = msg->rx_buf;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001168
1169 while (!read_done) {
1170 rc = dsi_set_max_return_size(dsi_ctrl, msg, rd_pkt_size);
1171 if (rc) {
1172 pr_err("Failed to set max return packet size, rc=%d\n",
1173 rc);
1174 goto error;
1175 }
1176
Sandeep Panda79450002017-05-08 17:14:24 +05301177 /* clear RDBK_DATA registers before proceeding */
1178 dsi_ctrl->hw.ops.clear_rdbk_register(&dsi_ctrl->hw);
1179
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001180 rc = dsi_message_tx(dsi_ctrl, msg, flags);
1181 if (rc) {
1182 pr_err("Message transmission failed, rc=%d\n", rc);
1183 goto error;
1184 }
1185
Sandeep Panda79450002017-05-08 17:14:24 +05301186 dlen = dsi_ctrl->hw.ops.get_cmd_read_data(&dsi_ctrl->hw,
1187 buff, total_bytes_read,
1188 total_read_len, rd_pkt_size,
1189 &hw_read_cnt);
1190 if (!dlen)
1191 goto error;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001192
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001193 if (short_resp)
Sandeep Panda79450002017-05-08 17:14:24 +05301194 break;
1195
1196 if (rlen <= current_read_len) {
1197 diff = current_read_len - rlen;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001198 read_done = true;
Sandeep Panda79450002017-05-08 17:14:24 +05301199 } else {
1200 diff = 0;
1201 rlen -= current_read_len;
1202 }
1203
1204 dlen -= 2; /* 2 bytes of CRC */
1205 dlen -= diff;
1206 buff += dlen;
1207 total_bytes_read += dlen;
1208 if (!read_done) {
1209 current_read_len = 14; /* Not first read */
1210 if (rlen < current_read_len)
1211 rd_pkt_size += rlen;
1212 else
1213 rd_pkt_size += current_read_len;
1214 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001215 }
Sandeep Panda79450002017-05-08 17:14:24 +05301216
1217 if (hw_read_cnt < 16 && !short_resp)
1218 buff = msg->rx_buf + (16 - hw_read_cnt);
1219 else
1220 buff = msg->rx_buf;
1221
1222 /* parse the data read from panel */
1223 cmd = buff[0];
1224 switch (cmd) {
1225 case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
1226 pr_err("Rx ACK_ERROR\n");
1227 rc = 0;
1228 break;
1229 case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
1230 case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
1231 rc = dsi_parse_short_read1_resp(msg, buff);
1232 break;
1233 case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
1234 case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
1235 rc = dsi_parse_short_read2_resp(msg, buff);
1236 break;
1237 case MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE:
1238 case MIPI_DSI_RX_DCS_LONG_READ_RESPONSE:
1239 rc = dsi_parse_long_read_resp(msg, buff);
1240 break;
1241 default:
1242 pr_warn("Invalid response\n");
1243 rc = 0;
1244 }
1245
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001246error:
1247 return rc;
1248}
1249
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001250static int dsi_enable_ulps(struct dsi_ctrl *dsi_ctrl)
1251{
1252 int rc = 0;
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301253 u32 lanes = 0;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001254 u32 ulps_lanes;
1255
1256 if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE)
1257 lanes = dsi_ctrl->host_config.common_config.data_lanes;
1258
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05301259 rc = dsi_ctrl->hw.ops.wait_for_lane_idle(&dsi_ctrl->hw, lanes);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301260 if (rc) {
1261 pr_err("lanes not entering idle, skip ULPS\n");
1262 return rc;
1263 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001264
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05301265 if (!dsi_ctrl->hw.ops.ulps_ops.ulps_request ||
1266 !dsi_ctrl->hw.ops.ulps_ops.ulps_exit) {
1267 pr_debug("DSI controller ULPS ops not present\n");
1268 return 0;
1269 }
1270
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301271 lanes |= DSI_CLOCK_LANE;
1272 dsi_ctrl->hw.ops.ulps_ops.ulps_request(&dsi_ctrl->hw, lanes);
1273
1274 ulps_lanes = dsi_ctrl->hw.ops.ulps_ops.get_lanes_in_ulps(&dsi_ctrl->hw);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001275
1276 if ((lanes & ulps_lanes) != lanes) {
1277 pr_err("Failed to enter ULPS, request=0x%x, actual=0x%x\n",
1278 lanes, ulps_lanes);
1279 rc = -EIO;
1280 }
1281
1282 return rc;
1283}
1284
1285static int dsi_disable_ulps(struct dsi_ctrl *dsi_ctrl)
1286{
1287 int rc = 0;
1288 u32 ulps_lanes, lanes = 0;
1289
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05301290 dsi_ctrl->hw.ops.clear_phy0_ln_err(&dsi_ctrl->hw);
1291
1292 if (!dsi_ctrl->hw.ops.ulps_ops.ulps_request ||
1293 !dsi_ctrl->hw.ops.ulps_ops.ulps_exit) {
1294 pr_debug("DSI controller ULPS ops not present\n");
1295 return 0;
1296 }
1297
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001298 if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE)
1299 lanes = dsi_ctrl->host_config.common_config.data_lanes;
1300
1301 lanes |= DSI_CLOCK_LANE;
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05301302
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301303 ulps_lanes = dsi_ctrl->hw.ops.ulps_ops.get_lanes_in_ulps(&dsi_ctrl->hw);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001304
1305 if ((lanes & ulps_lanes) != lanes)
1306 pr_err("Mismatch between lanes in ULPS\n");
1307
1308 lanes &= ulps_lanes;
1309
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301310 dsi_ctrl->hw.ops.ulps_ops.ulps_exit(&dsi_ctrl->hw, lanes);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001311
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301312 ulps_lanes = dsi_ctrl->hw.ops.ulps_ops.get_lanes_in_ulps(&dsi_ctrl->hw);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001313 if (ulps_lanes & lanes) {
1314 pr_err("Lanes (0x%x) stuck in ULPS\n", ulps_lanes);
1315 rc = -EIO;
1316 }
1317
1318 return rc;
1319}
1320
1321static int dsi_ctrl_drv_state_init(struct dsi_ctrl *dsi_ctrl)
1322{
1323 int rc = 0;
1324 bool splash_enabled = false;
1325 struct dsi_ctrl_state_info *state = &dsi_ctrl->current_state;
1326
1327 if (!splash_enabled) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301328 state->power_state = DSI_CTRL_POWER_VREG_OFF;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001329 state->cmd_engine_state = DSI_CTRL_ENGINE_OFF;
1330 state->vid_engine_state = DSI_CTRL_ENGINE_OFF;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001331 }
1332
1333 return rc;
1334}
1335
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001336static int dsi_ctrl_buffer_deinit(struct dsi_ctrl *dsi_ctrl)
1337{
Jordan Croused8e96522017-02-13 10:14:16 -07001338 struct msm_gem_address_space *aspace = NULL;
1339
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001340 if (dsi_ctrl->tx_cmd_buf) {
Jordan Croused8e96522017-02-13 10:14:16 -07001341 aspace = dsi_ctrl_get_aspace(dsi_ctrl,
1342 MSM_SMMU_DOMAIN_UNSECURE);
1343 if (!aspace) {
1344 pr_err("failed to get address space\n");
1345 return -ENOMEM;
1346 }
1347
1348 msm_gem_put_iova(dsi_ctrl->tx_cmd_buf, aspace);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001349
Lloyd Atkinsonbc0f5cb2017-09-13 09:29:10 -04001350 mutex_lock(&dsi_ctrl->drm_dev->struct_mutex);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001351 msm_gem_free_object(dsi_ctrl->tx_cmd_buf);
Lloyd Atkinsonbc0f5cb2017-09-13 09:29:10 -04001352 mutex_unlock(&dsi_ctrl->drm_dev->struct_mutex);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001353 dsi_ctrl->tx_cmd_buf = NULL;
1354 }
1355
1356 return 0;
1357}
1358
1359int dsi_ctrl_buffer_init(struct dsi_ctrl *dsi_ctrl)
1360{
1361 int rc = 0;
1362 u32 iova = 0;
Jordan Croused8e96522017-02-13 10:14:16 -07001363 struct msm_gem_address_space *aspace = NULL;
1364
1365 aspace = dsi_ctrl_get_aspace(dsi_ctrl, MSM_SMMU_DOMAIN_UNSECURE);
1366 if (!aspace) {
1367 pr_err("failed to get address space\n");
1368 return -ENOMEM;
1369 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001370
1371 dsi_ctrl->tx_cmd_buf = msm_gem_new(dsi_ctrl->drm_dev,
1372 SZ_4K,
1373 MSM_BO_UNCACHED);
1374
1375 if (IS_ERR(dsi_ctrl->tx_cmd_buf)) {
1376 rc = PTR_ERR(dsi_ctrl->tx_cmd_buf);
1377 pr_err("failed to allocate gem, rc=%d\n", rc);
1378 dsi_ctrl->tx_cmd_buf = NULL;
1379 goto error;
1380 }
1381
1382 dsi_ctrl->cmd_buffer_size = SZ_4K;
1383
Jordan Croused8e96522017-02-13 10:14:16 -07001384 rc = msm_gem_get_iova(dsi_ctrl->tx_cmd_buf, aspace, &iova);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001385 if (rc) {
1386 pr_err("failed to get iova, rc=%d\n", rc);
1387 (void)dsi_ctrl_buffer_deinit(dsi_ctrl);
1388 goto error;
1389 }
1390
1391 if (iova & 0x07) {
1392 pr_err("Tx command buffer is not 8 byte aligned\n");
1393 rc = -ENOTSUPP;
1394 (void)dsi_ctrl_buffer_deinit(dsi_ctrl);
1395 goto error;
1396 }
1397error:
1398 return rc;
1399}
1400
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301401static int dsi_enable_io_clamp(struct dsi_ctrl *dsi_ctrl,
1402 bool enable, bool ulps_enabled)
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001403{
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001404 u32 lanes = 0;
1405
1406 if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE)
1407 lanes = dsi_ctrl->host_config.common_config.data_lanes;
1408
1409 lanes |= DSI_CLOCK_LANE;
1410
1411 if (enable)
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301412 dsi_ctrl->hw.ops.clamp_enable(&dsi_ctrl->hw,
1413 lanes, ulps_enabled);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001414 else
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301415 dsi_ctrl->hw.ops.clamp_disable(&dsi_ctrl->hw,
1416 lanes, ulps_enabled);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001417
1418 return 0;
1419}
1420
Dhaval Patelabfaa082017-07-28 12:41:10 -07001421static int dsi_ctrl_dts_parse(struct dsi_ctrl *dsi_ctrl,
1422 struct device_node *of_node)
1423{
1424 u32 index = 0;
1425 int rc = 0;
1426
1427 if (!dsi_ctrl || !of_node) {
1428 pr_err("invalid dsi_ctrl:%d or of_node:%d\n",
1429 dsi_ctrl != NULL, of_node != NULL);
1430 return -EINVAL;
1431 }
1432
1433 rc = of_property_read_u32(of_node, "cell-index", &index);
1434 if (rc) {
1435 pr_debug("cell index not set, default to 0\n");
1436 index = 0;
1437 }
1438
1439 dsi_ctrl->cell_index = index;
1440 dsi_ctrl->name = of_get_property(of_node, "label", NULL);
1441 if (!dsi_ctrl->name)
1442 dsi_ctrl->name = DSI_CTRL_DEFAULT_LABEL;
1443
1444 dsi_ctrl->phy_isolation_enabled = of_property_read_bool(of_node,
1445 "qcom,dsi-phy-isolation-enabled");
1446
1447 return 0;
1448}
1449
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001450static int dsi_ctrl_dev_probe(struct platform_device *pdev)
1451{
1452 struct dsi_ctrl *dsi_ctrl;
1453 struct dsi_ctrl_list_item *item;
1454 const struct of_device_id *id;
1455 enum dsi_ctrl_version version;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001456 int rc = 0;
1457
1458 id = of_match_node(msm_dsi_of_match, pdev->dev.of_node);
1459 if (!id)
1460 return -ENODEV;
1461
1462 version = *(enum dsi_ctrl_version *)id->data;
1463
1464 item = devm_kzalloc(&pdev->dev, sizeof(*item), GFP_KERNEL);
1465 if (!item)
1466 return -ENOMEM;
1467
1468 dsi_ctrl = devm_kzalloc(&pdev->dev, sizeof(*dsi_ctrl), GFP_KERNEL);
1469 if (!dsi_ctrl)
1470 return -ENOMEM;
1471
Shashank Babu Chinta Venkataafef8202017-04-21 13:49:56 -07001472 dsi_ctrl->version = version;
Clarence Ip80ada7f2017-05-04 09:55:21 -07001473 dsi_ctrl->irq_info.irq_num = -1;
1474 dsi_ctrl->irq_info.irq_stat_mask = 0x0;
1475
1476 spin_lock_init(&dsi_ctrl->irq_info.irq_lock);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001477
Dhaval Patelabfaa082017-07-28 12:41:10 -07001478 rc = dsi_ctrl_dts_parse(dsi_ctrl, pdev->dev.of_node);
1479 if (rc) {
1480 pr_err("ctrl:%d dts parse failed, rc = %d\n",
1481 dsi_ctrl->cell_index, rc);
1482 goto fail;
1483 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001484
1485 rc = dsi_ctrl_init_regmap(pdev, dsi_ctrl);
1486 if (rc) {
1487 pr_err("Failed to parse register information, rc = %d\n", rc);
1488 goto fail;
1489 }
1490
1491 rc = dsi_ctrl_clocks_init(pdev, dsi_ctrl);
1492 if (rc) {
1493 pr_err("Failed to parse clock information, rc = %d\n", rc);
1494 goto fail;
1495 }
1496
1497 rc = dsi_ctrl_supplies_init(pdev, dsi_ctrl);
1498 if (rc) {
1499 pr_err("Failed to parse voltage supplies, rc = %d\n", rc);
1500 goto fail_clks;
1501 }
1502
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001503 rc = dsi_catalog_ctrl_setup(&dsi_ctrl->hw, dsi_ctrl->version,
Dhaval Patelabfaa082017-07-28 12:41:10 -07001504 dsi_ctrl->cell_index, dsi_ctrl->phy_isolation_enabled);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001505 if (rc) {
1506 pr_err("Catalog does not support version (%d)\n",
1507 dsi_ctrl->version);
1508 goto fail_supplies;
1509 }
1510
1511 rc = dsi_ctrl_axi_bus_client_init(pdev, dsi_ctrl);
1512 if (rc)
Shashank Babu Chinta Venkatacf411332017-05-10 17:30:08 -07001513 pr_debug("failed to init axi bus client, rc = %d\n", rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001514
1515 item->ctrl = dsi_ctrl;
1516
1517 mutex_lock(&dsi_ctrl_list_lock);
1518 list_add(&item->list, &dsi_ctrl_list);
1519 mutex_unlock(&dsi_ctrl_list_lock);
1520
1521 mutex_init(&dsi_ctrl->ctrl_lock);
1522
1523 dsi_ctrl->pdev = pdev;
1524 platform_set_drvdata(pdev, dsi_ctrl);
Dhaval Patela2430842017-06-15 14:32:36 -07001525 pr_info("Probe successful for %s\n", dsi_ctrl->name);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001526
1527 return 0;
1528
1529fail_supplies:
1530 (void)dsi_ctrl_supplies_deinit(dsi_ctrl);
1531fail_clks:
1532 (void)dsi_ctrl_clocks_deinit(dsi_ctrl);
1533fail:
1534 return rc;
1535}
1536
1537static int dsi_ctrl_dev_remove(struct platform_device *pdev)
1538{
1539 int rc = 0;
1540 struct dsi_ctrl *dsi_ctrl;
1541 struct list_head *pos, *tmp;
1542
1543 dsi_ctrl = platform_get_drvdata(pdev);
1544
1545 mutex_lock(&dsi_ctrl_list_lock);
1546 list_for_each_safe(pos, tmp, &dsi_ctrl_list) {
1547 struct dsi_ctrl_list_item *n = list_entry(pos,
1548 struct dsi_ctrl_list_item,
1549 list);
1550 if (n->ctrl == dsi_ctrl) {
1551 list_del(&n->list);
1552 break;
1553 }
1554 }
1555 mutex_unlock(&dsi_ctrl_list_lock);
1556
1557 mutex_lock(&dsi_ctrl->ctrl_lock);
1558 rc = dsi_ctrl_axi_bus_client_deinit(dsi_ctrl);
1559 if (rc)
1560 pr_err("failed to deinitialize axi bus client, rc = %d\n", rc);
1561
1562 rc = dsi_ctrl_supplies_deinit(dsi_ctrl);
1563 if (rc)
1564 pr_err("failed to deinitialize voltage supplies, rc=%d\n", rc);
1565
1566 rc = dsi_ctrl_clocks_deinit(dsi_ctrl);
1567 if (rc)
1568 pr_err("failed to deinitialize clocks, rc=%d\n", rc);
1569
1570 mutex_unlock(&dsi_ctrl->ctrl_lock);
1571
1572 mutex_destroy(&dsi_ctrl->ctrl_lock);
1573 devm_kfree(&pdev->dev, dsi_ctrl);
1574
1575 platform_set_drvdata(pdev, NULL);
1576 return 0;
1577}
1578
1579static struct platform_driver dsi_ctrl_driver = {
1580 .probe = dsi_ctrl_dev_probe,
1581 .remove = dsi_ctrl_dev_remove,
1582 .driver = {
Ajay Singh Parmar485f7362016-07-19 10:43:24 -07001583 .name = "drm_dsi_ctrl",
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001584 .of_match_table = msm_dsi_of_match,
1585 },
1586};
1587
Dhaval Patelf9f3ffe2017-08-16 16:03:10 -07001588#if defined(CONFIG_DEBUG_FS)
1589
1590void dsi_ctrl_debug_dump(void)
1591{
1592 struct list_head *pos, *tmp;
1593 struct dsi_ctrl *ctrl = NULL;
1594
1595 mutex_lock(&dsi_ctrl_list_lock);
1596 list_for_each_safe(pos, tmp, &dsi_ctrl_list) {
1597 struct dsi_ctrl_list_item *n;
1598
1599 n = list_entry(pos, struct dsi_ctrl_list_item, list);
1600 ctrl = n->ctrl;
1601 pr_err("dsi ctrl:%d\n", ctrl->cell_index);
1602 ctrl->hw.ops.debug_bus(&ctrl->hw);
1603 }
1604 mutex_unlock(&dsi_ctrl_list_lock);
1605}
1606
1607#endif
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001608/**
1609 * dsi_ctrl_get() - get a dsi_ctrl handle from an of_node
1610 * @of_node: of_node of the DSI controller.
1611 *
1612 * Gets the DSI controller handle for the corresponding of_node. The ref count
1613 * is incremented to one and all subsequent gets will fail until the original
1614 * clients calls a put.
1615 *
1616 * Return: DSI Controller handle.
1617 */
1618struct dsi_ctrl *dsi_ctrl_get(struct device_node *of_node)
1619{
1620 struct list_head *pos, *tmp;
1621 struct dsi_ctrl *ctrl = NULL;
1622
1623 mutex_lock(&dsi_ctrl_list_lock);
1624 list_for_each_safe(pos, tmp, &dsi_ctrl_list) {
1625 struct dsi_ctrl_list_item *n;
1626
1627 n = list_entry(pos, struct dsi_ctrl_list_item, list);
1628 if (n->ctrl->pdev->dev.of_node == of_node) {
1629 ctrl = n->ctrl;
1630 break;
1631 }
1632 }
1633 mutex_unlock(&dsi_ctrl_list_lock);
1634
1635 if (!ctrl) {
1636 pr_err("Device with of node not found\n");
1637 ctrl = ERR_PTR(-EPROBE_DEFER);
1638 return ctrl;
1639 }
1640
1641 mutex_lock(&ctrl->ctrl_lock);
1642 if (ctrl->refcount == 1) {
1643 pr_err("[%s] Device in use\n", ctrl->name);
1644 ctrl = ERR_PTR(-EBUSY);
1645 } else {
1646 ctrl->refcount++;
1647 }
1648 mutex_unlock(&ctrl->ctrl_lock);
1649 return ctrl;
1650}
1651
1652/**
1653 * dsi_ctrl_put() - releases a dsi controller handle.
1654 * @dsi_ctrl: DSI controller handle.
1655 *
1656 * Releases the DSI controller. Driver will clean up all resources and puts back
1657 * the DSI controller into reset state.
1658 */
1659void dsi_ctrl_put(struct dsi_ctrl *dsi_ctrl)
1660{
1661 mutex_lock(&dsi_ctrl->ctrl_lock);
1662
1663 if (dsi_ctrl->refcount == 0)
1664 pr_err("Unbalanced dsi_ctrl_put call\n");
1665 else
1666 dsi_ctrl->refcount--;
1667
1668 mutex_unlock(&dsi_ctrl->ctrl_lock);
1669}
1670
1671/**
1672 * dsi_ctrl_drv_init() - initialize dsi controller driver.
1673 * @dsi_ctrl: DSI controller handle.
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -07001674 * @parent: Parent directory for debug fs.
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001675 *
1676 * Initializes DSI controller driver. Driver should be initialized after
1677 * dsi_ctrl_get() succeeds.
1678 *
1679 * Return: error code.
1680 */
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -07001681int dsi_ctrl_drv_init(struct dsi_ctrl *dsi_ctrl, struct dentry *parent)
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001682{
1683 int rc = 0;
1684
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -07001685 if (!dsi_ctrl || !parent) {
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001686 pr_err("Invalid params\n");
1687 return -EINVAL;
1688 }
1689
1690 mutex_lock(&dsi_ctrl->ctrl_lock);
1691 rc = dsi_ctrl_drv_state_init(dsi_ctrl);
1692 if (rc) {
1693 pr_err("Failed to initialize driver state, rc=%d\n", rc);
1694 goto error;
1695 }
1696
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -07001697 rc = dsi_ctrl_debugfs_init(dsi_ctrl, parent);
1698 if (rc) {
1699 pr_err("[DSI_%d] failed to init debug fs, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05001700 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -07001701 goto error;
1702 }
1703
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001704error:
1705 mutex_unlock(&dsi_ctrl->ctrl_lock);
1706 return rc;
1707}
1708
1709/**
1710 * dsi_ctrl_drv_deinit() - de-initializes dsi controller driver
1711 * @dsi_ctrl: DSI controller handle.
1712 *
1713 * Releases all resources acquired by dsi_ctrl_drv_init().
1714 *
1715 * Return: error code.
1716 */
1717int dsi_ctrl_drv_deinit(struct dsi_ctrl *dsi_ctrl)
1718{
1719 int rc = 0;
1720
1721 if (!dsi_ctrl) {
1722 pr_err("Invalid params\n");
1723 return -EINVAL;
1724 }
1725
1726 mutex_lock(&dsi_ctrl->ctrl_lock);
Ajay Singh Parmar48ea4272016-06-27 11:44:34 -07001727
1728 rc = dsi_ctrl_debugfs_deinit(dsi_ctrl);
1729 if (rc)
1730 pr_err("failed to release debugfs root, rc=%d\n", rc);
1731
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001732 rc = dsi_ctrl_buffer_deinit(dsi_ctrl);
1733 if (rc)
1734 pr_err("Failed to free cmd buffers, rc=%d\n", rc);
1735
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001736 mutex_unlock(&dsi_ctrl->ctrl_lock);
1737 return rc;
1738}
1739
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301740int dsi_ctrl_clk_cb_register(struct dsi_ctrl *dsi_ctrl,
1741 struct clk_ctrl_cb *clk_cb)
1742{
1743 if (!dsi_ctrl || !clk_cb) {
1744 pr_err("Invalid params\n");
1745 return -EINVAL;
1746 }
1747
1748 dsi_ctrl->clk_cb.priv = clk_cb->priv;
1749 dsi_ctrl->clk_cb.dsi_clk_cb = clk_cb->dsi_clk_cb;
1750 return 0;
1751}
1752
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001753/**
1754 * dsi_ctrl_phy_sw_reset() - perform a PHY software reset
1755 * @dsi_ctrl: DSI controller handle.
1756 *
1757 * Performs a PHY software reset on the DSI controller. Reset should be done
1758 * when the controller power state is DSI_CTRL_POWER_CORE_CLK_ON and the PHY is
1759 * not enabled.
1760 *
1761 * This function will fail if driver is in any other state.
1762 *
1763 * Return: error code.
1764 */
1765int dsi_ctrl_phy_sw_reset(struct dsi_ctrl *dsi_ctrl)
1766{
1767 int rc = 0;
1768
1769 if (!dsi_ctrl) {
1770 pr_err("Invalid params\n");
1771 return -EINVAL;
1772 }
1773
1774 mutex_lock(&dsi_ctrl->ctrl_lock);
1775 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_PHY_SW_RESET, 0x0);
1776 if (rc) {
1777 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05001778 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001779 goto error;
1780 }
1781
1782 dsi_ctrl->hw.ops.phy_sw_reset(&dsi_ctrl->hw);
1783
Alexander Beykun32a6a182017-02-27 17:46:51 -05001784 pr_debug("[DSI_%d] PHY soft reset done\n", dsi_ctrl->cell_index);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07001785 dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_PHY_SW_RESET, 0x0);
1786error:
1787 mutex_unlock(&dsi_ctrl->ctrl_lock);
1788 return rc;
1789}
1790
1791/**
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07001792 * dsi_ctrl_seamless_timing_update() - update only controller timing
1793 * @dsi_ctrl: DSI controller handle.
1794 * @timing: New DSI timing info
1795 *
1796 * Updates host timing values to conduct a seamless transition to new timing
1797 * For example, to update the porch values in a dynamic fps switch.
1798 *
1799 * Return: error code.
1800 */
1801int dsi_ctrl_async_timing_update(struct dsi_ctrl *dsi_ctrl,
1802 struct dsi_mode_info *timing)
1803{
1804 struct dsi_mode_info *host_mode;
1805 int rc = 0;
1806
1807 if (!dsi_ctrl || !timing) {
1808 pr_err("Invalid params\n");
1809 return -EINVAL;
1810 }
1811
1812 mutex_lock(&dsi_ctrl->ctrl_lock);
1813
1814 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_ASYNC_TIMING,
1815 DSI_CTRL_ENGINE_ON);
1816 if (rc) {
1817 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05001818 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07001819 goto exit;
1820 }
1821
1822 host_mode = &dsi_ctrl->host_config.video_timing;
1823 memcpy(host_mode, timing, sizeof(*host_mode));
Raviteja Tamatam68892de2017-06-20 04:47:19 +05301824 dsi_ctrl->hw.ops.set_timing_db(&dsi_ctrl->hw, true);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07001825 dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw, host_mode);
1826
1827exit:
1828 mutex_unlock(&dsi_ctrl->ctrl_lock);
1829 return rc;
1830}
1831
Raviteja Tamatam68892de2017-06-20 04:47:19 +05301832/**
1833 * dsi_ctrl_timing_db_update() - update only controller Timing DB
1834 * @dsi_ctrl: DSI controller handle.
1835 * @enable: Enable/disable Timing DB register
1836 *
1837 * Update timing db register value during dfps usecases
1838 *
1839 * Return: error code.
1840 */
1841int dsi_ctrl_timing_db_update(struct dsi_ctrl *dsi_ctrl,
1842 bool enable)
1843{
1844 int rc = 0;
1845
1846 if (!dsi_ctrl) {
1847 pr_err("Invalid dsi_ctrl\n");
1848 return -EINVAL;
1849 }
1850
1851 mutex_lock(&dsi_ctrl->ctrl_lock);
1852
1853 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_ASYNC_TIMING,
1854 DSI_CTRL_ENGINE_ON);
1855 if (rc) {
1856 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
1857 dsi_ctrl->cell_index, rc);
1858 goto exit;
1859 }
1860
1861 /*
1862 * Add HW recommended delay for dfps feature.
1863 * When prefetch is enabled, MDSS HW works on 2 vsync
1864 * boundaries i.e. mdp_vsync and panel_vsync.
1865 * In the current implementation we are only waiting
1866 * for mdp_vsync. We need to make sure that interface
1867 * flush is after panel_vsync. So, added the recommended
1868 * delays after dfps update.
1869 */
1870 usleep_range(2000, 2010);
1871
1872 dsi_ctrl->hw.ops.set_timing_db(&dsi_ctrl->hw, enable);
1873
1874exit:
1875 mutex_unlock(&dsi_ctrl->ctrl_lock);
1876 return rc;
1877}
1878
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301879int dsi_ctrl_setup(struct dsi_ctrl *dsi_ctrl)
1880{
1881 int rc = 0;
1882
1883 if (!dsi_ctrl) {
1884 pr_err("Invalid params\n");
1885 return -EINVAL;
1886 }
1887
1888 mutex_lock(&dsi_ctrl->ctrl_lock);
1889
1890 dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw,
1891 &dsi_ctrl->host_config.lane_map);
1892
1893 dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw,
1894 &dsi_ctrl->host_config.common_config);
1895
1896 if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) {
1897 dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw,
1898 &dsi_ctrl->host_config.common_config,
1899 &dsi_ctrl->host_config.u.cmd_engine);
1900
1901 dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
Lloyd Atkinson16e96de2017-04-19 11:18:14 -04001902 &dsi_ctrl->host_config.video_timing,
1903 dsi_ctrl->host_config.video_timing.h_active * 3,
1904 0x0,
1905 &dsi_ctrl->roi);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301906 dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true);
1907 } else {
1908 dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
1909 &dsi_ctrl->host_config.common_config,
1910 &dsi_ctrl->host_config.u.video_engine);
1911 dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw,
1912 &dsi_ctrl->host_config.video_timing);
1913 dsi_ctrl->hw.ops.video_engine_en(&dsi_ctrl->hw, true);
1914 }
1915
1916 dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0);
1917 dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0);
1918 dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true);
1919
1920 mutex_unlock(&dsi_ctrl->ctrl_lock);
1921 return rc;
1922}
1923
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04001924int dsi_ctrl_set_roi(struct dsi_ctrl *dsi_ctrl, struct dsi_rect *roi,
1925 bool *changed)
1926{
1927 int rc = 0;
1928
1929 if (!dsi_ctrl || !roi || !changed) {
1930 pr_err("Invalid params\n");
1931 return -EINVAL;
1932 }
1933
1934 mutex_lock(&dsi_ctrl->ctrl_lock);
1935 if (!dsi_rect_is_equal(&dsi_ctrl->roi, roi)) {
1936 *changed = true;
1937 memcpy(&dsi_ctrl->roi, roi, sizeof(dsi_ctrl->roi));
1938 } else
1939 *changed = false;
1940 mutex_unlock(&dsi_ctrl->ctrl_lock);
1941 return rc;
1942}
1943
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05301944/**
1945 * dsi_ctrl_phy_reset_config() - Mask/unmask propagation of ahb reset signal
1946 * to DSI PHY hardware.
1947 * @dsi_ctrl: DSI controller handle.
1948 * @enable: Mask/unmask the PHY reset signal.
1949 *
1950 * Return: error code.
1951 */
1952int dsi_ctrl_phy_reset_config(struct dsi_ctrl *dsi_ctrl, bool enable)
1953{
1954 if (!dsi_ctrl) {
1955 pr_err("Invalid params\n");
1956 return -EINVAL;
1957 }
1958
1959 if (dsi_ctrl->hw.ops.phy_reset_config)
1960 dsi_ctrl->hw.ops.phy_reset_config(&dsi_ctrl->hw, enable);
1961
1962 return 0;
1963}
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05301964
Clarence Ip80ada7f2017-05-04 09:55:21 -07001965static void dsi_ctrl_handle_error_status(struct dsi_ctrl *dsi_ctrl,
1966 unsigned long int error)
1967{
1968 pr_err("%s: %lu\n", __func__, error);
1969
1970 /* DTLN PHY error */
1971 if (error & 0x3000e00)
1972 if (dsi_ctrl->hw.ops.clear_error_status)
1973 dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
1974 0x3000e00);
1975
1976 /* DSI FIFO OVERFLOW error */
1977 if (error & 0xf0000) {
1978 if (dsi_ctrl->hw.ops.clear_error_status)
1979 dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
1980 0xf0000);
1981 }
1982
1983 /* DSI FIFO UNDERFLOW error */
1984 if (error & 0xf00000) {
1985 if (dsi_ctrl->hw.ops.clear_error_status)
1986 dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
1987 0xf00000);
1988 }
1989
1990 /* DSI PLL UNLOCK error */
1991 if (error & BIT(8))
1992 if (dsi_ctrl->hw.ops.clear_error_status)
1993 dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
1994 BIT(8));
1995}
1996
1997/**
1998 * dsi_ctrl_isr - interrupt service routine for DSI CTRL component
1999 * @irq: Incoming IRQ number
2000 * @ptr: Pointer to user data structure (struct dsi_ctrl)
2001 * Returns: IRQ_HANDLED if no further action required
2002 */
2003static irqreturn_t dsi_ctrl_isr(int irq, void *ptr)
2004{
2005 struct dsi_ctrl *dsi_ctrl;
2006 struct dsi_event_cb_info cb_info;
2007 unsigned long flags;
2008 uint32_t cell_index, status, i;
2009 uint64_t errors;
2010
2011 if (!ptr)
2012 return IRQ_NONE;
2013 dsi_ctrl = ptr;
2014
2015 /* clear status interrupts */
2016 if (dsi_ctrl->hw.ops.get_interrupt_status)
2017 status = dsi_ctrl->hw.ops.get_interrupt_status(&dsi_ctrl->hw);
2018 else
2019 status = 0x0;
2020
2021 if (dsi_ctrl->hw.ops.clear_interrupt_status)
2022 dsi_ctrl->hw.ops.clear_interrupt_status(&dsi_ctrl->hw, status);
2023
2024 spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags);
2025 cell_index = dsi_ctrl->cell_index;
2026 spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags);
2027
2028 /* clear error interrupts */
2029 if (dsi_ctrl->hw.ops.get_error_status)
2030 errors = dsi_ctrl->hw.ops.get_error_status(&dsi_ctrl->hw);
2031 else
2032 errors = 0x0;
2033
2034 if (errors) {
2035 /* handle DSI error recovery */
2036 dsi_ctrl_handle_error_status(dsi_ctrl, errors);
2037 if (dsi_ctrl->hw.ops.clear_error_status)
2038 dsi_ctrl->hw.ops.clear_error_status(&dsi_ctrl->hw,
2039 errors);
2040 }
2041
2042 if (status & DSI_CMD_MODE_DMA_DONE) {
2043 dsi_ctrl_disable_status_interrupt(dsi_ctrl,
2044 DSI_SINT_CMD_MODE_DMA_DONE);
2045 complete_all(&dsi_ctrl->irq_info.cmd_dma_done);
2046 }
2047
2048 if (status & DSI_CMD_FRAME_DONE) {
2049 dsi_ctrl_disable_status_interrupt(dsi_ctrl,
2050 DSI_SINT_CMD_FRAME_DONE);
2051 complete_all(&dsi_ctrl->irq_info.cmd_frame_done);
2052 }
2053
2054 if (status & DSI_VIDEO_MODE_FRAME_DONE) {
2055 dsi_ctrl_disable_status_interrupt(dsi_ctrl,
2056 DSI_SINT_VIDEO_MODE_FRAME_DONE);
2057 complete_all(&dsi_ctrl->irq_info.vid_frame_done);
2058 }
2059
2060 if (status & DSI_BTA_DONE) {
2061 dsi_ctrl_disable_status_interrupt(dsi_ctrl,
2062 DSI_SINT_BTA_DONE);
2063 complete_all(&dsi_ctrl->irq_info.bta_done);
2064 }
2065
2066 for (i = 0; status && i < DSI_STATUS_INTERRUPT_COUNT; ++i) {
2067 if (status & 0x1) {
2068 spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags);
2069 cb_info = dsi_ctrl->irq_info.irq_stat_cb[i];
2070 spin_unlock_irqrestore(
2071 &dsi_ctrl->irq_info.irq_lock, flags);
2072
2073 if (cb_info.event_cb)
2074 (void)cb_info.event_cb(cb_info.event_usr_ptr,
2075 cb_info.event_idx,
2076 cell_index, irq, 0, 0, 0);
2077 }
2078 status >>= 1;
2079 }
2080
2081 return IRQ_HANDLED;
2082}
2083
2084/**
2085 * _dsi_ctrl_setup_isr - register ISR handler
2086 * @dsi_ctrl: Pointer to associated dsi_ctrl structure
2087 * Returns: Zero on success
2088 */
2089static int dsi_ctrl_setup_isr(struct dsi_ctrl *dsi_ctrl)
2090{
2091 int irq_num, rc;
2092
2093 if (!dsi_ctrl)
2094 return -EINVAL;
2095 if (dsi_ctrl->irq_info.irq_num != -1)
2096 return 0;
2097
2098 init_completion(&dsi_ctrl->irq_info.cmd_dma_done);
2099 init_completion(&dsi_ctrl->irq_info.vid_frame_done);
2100 init_completion(&dsi_ctrl->irq_info.cmd_frame_done);
2101 init_completion(&dsi_ctrl->irq_info.bta_done);
2102
2103 irq_num = platform_get_irq(dsi_ctrl->pdev, 0);
2104 if (irq_num < 0) {
2105 pr_err("[DSI_%d] Failed to get IRQ number, %d\n",
2106 dsi_ctrl->cell_index, irq_num);
2107 rc = irq_num;
2108 } else {
2109 rc = devm_request_threaded_irq(&dsi_ctrl->pdev->dev, irq_num,
2110 dsi_ctrl_isr, NULL, 0, "dsi_ctrl", dsi_ctrl);
2111 if (rc) {
2112 pr_err("[DSI_%d] Failed to request IRQ, %d\n",
2113 dsi_ctrl->cell_index, rc);
2114 } else {
2115 dsi_ctrl->irq_info.irq_num = irq_num;
2116 disable_irq_nosync(irq_num);
2117
2118 pr_info("[DSI_%d] IRQ %d registered\n",
2119 dsi_ctrl->cell_index, irq_num);
2120 }
2121 }
2122 return rc;
2123}
2124
2125/**
2126 * _dsi_ctrl_destroy_isr - unregister ISR handler
2127 * @dsi_ctrl: Pointer to associated dsi_ctrl structure
2128 */
2129static void _dsi_ctrl_destroy_isr(struct dsi_ctrl *dsi_ctrl)
2130{
2131 if (!dsi_ctrl || !dsi_ctrl->pdev || dsi_ctrl->irq_info.irq_num < 0)
2132 return;
2133
2134 if (dsi_ctrl->irq_info.irq_num != -1) {
2135 devm_free_irq(&dsi_ctrl->pdev->dev,
2136 dsi_ctrl->irq_info.irq_num, dsi_ctrl);
2137 dsi_ctrl->irq_info.irq_num = -1;
2138 }
2139}
2140
2141void dsi_ctrl_enable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
2142 uint32_t intr_idx, struct dsi_event_cb_info *event_info)
2143{
2144 unsigned long flags;
2145
2146 if (!dsi_ctrl || dsi_ctrl->irq_info.irq_num == -1 ||
2147 intr_idx >= DSI_STATUS_INTERRUPT_COUNT)
2148 return;
2149
2150 spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags);
2151
2152 if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx] == 0) {
2153 /* enable irq on first request */
2154 if (dsi_ctrl->irq_info.irq_stat_mask == 0)
2155 enable_irq(dsi_ctrl->irq_info.irq_num);
2156
2157 /* update hardware mask */
2158 dsi_ctrl->irq_info.irq_stat_mask |= BIT(intr_idx);
2159 dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw,
2160 dsi_ctrl->irq_info.irq_stat_mask);
2161 }
2162 ++(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]);
2163
2164 if (event_info)
2165 dsi_ctrl->irq_info.irq_stat_cb[intr_idx] = *event_info;
2166
2167 spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags);
2168}
2169
2170void dsi_ctrl_disable_status_interrupt(struct dsi_ctrl *dsi_ctrl,
2171 uint32_t intr_idx)
2172{
2173 unsigned long flags;
2174
2175 if (!dsi_ctrl || dsi_ctrl->irq_info.irq_num == -1 ||
2176 intr_idx >= DSI_STATUS_INTERRUPT_COUNT)
2177 return;
2178
2179 spin_lock_irqsave(&dsi_ctrl->irq_info.irq_lock, flags);
2180
2181 if (dsi_ctrl->irq_info.irq_stat_refcount[intr_idx])
2182 if (--(dsi_ctrl->irq_info.irq_stat_refcount[intr_idx]) == 0) {
2183 dsi_ctrl->irq_info.irq_stat_mask &= ~BIT(intr_idx);
2184 dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw,
2185 dsi_ctrl->irq_info.irq_stat_mask);
2186
2187 /* don't need irq if no lines are enabled */
2188 if (dsi_ctrl->irq_info.irq_stat_mask == 0)
2189 disable_irq_nosync(dsi_ctrl->irq_info.irq_num);
2190 }
2191
2192 spin_unlock_irqrestore(&dsi_ctrl->irq_info.irq_lock, flags);
2193}
2194
Jeykumar Sankarana7c7bbe2017-05-31 18:12:05 -07002195int dsi_ctrl_host_timing_update(struct dsi_ctrl *dsi_ctrl)
2196{
2197 if (!dsi_ctrl) {
2198 pr_err("Invalid params\n");
2199 return -EINVAL;
2200 }
2201
2202 if (dsi_ctrl->hw.ops.host_setup)
2203 dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw,
2204 &dsi_ctrl->host_config.common_config);
2205
2206 if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) {
2207 if (dsi_ctrl->hw.ops.cmd_engine_setup)
2208 dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw,
2209 &dsi_ctrl->host_config.common_config,
2210 &dsi_ctrl->host_config.u.cmd_engine);
2211
2212 if (dsi_ctrl->hw.ops.setup_cmd_stream)
2213 dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
2214 &dsi_ctrl->host_config.video_timing,
2215 dsi_ctrl->host_config.video_timing.h_active * 3,
2216 0x0, NULL);
2217 } else {
2218 pr_err("invalid panel mode for resolution switch\n");
2219 return -EINVAL;
2220 }
2221
2222 return 0;
2223}
2224
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302225/**
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002226 * dsi_ctrl_host_init() - Initialize DSI host hardware.
2227 * @dsi_ctrl: DSI controller handle.
2228 *
2229 * Initializes DSI controller hardware with host configuration provided by
2230 * dsi_ctrl_update_host_config(). Initialization can be performed only during
2231 * DSI_CTRL_POWER_CORE_CLK_ON state and after the PHY SW reset has been
2232 * performed.
2233 *
2234 * Return: error code.
2235 */
2236int dsi_ctrl_host_init(struct dsi_ctrl *dsi_ctrl)
2237{
2238 int rc = 0;
2239
2240 if (!dsi_ctrl) {
2241 pr_err("Invalid params\n");
2242 return -EINVAL;
2243 }
2244
2245 mutex_lock(&dsi_ctrl->ctrl_lock);
2246 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x1);
2247 if (rc) {
2248 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002249 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002250 goto error;
2251 }
2252
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002253 dsi_ctrl->hw.ops.setup_lane_map(&dsi_ctrl->hw,
2254 &dsi_ctrl->host_config.lane_map);
2255
2256 dsi_ctrl->hw.ops.host_setup(&dsi_ctrl->hw,
2257 &dsi_ctrl->host_config.common_config);
2258
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07002259 if (dsi_ctrl->host_config.panel_mode == DSI_OP_CMD_MODE) {
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002260 dsi_ctrl->hw.ops.cmd_engine_setup(&dsi_ctrl->hw,
2261 &dsi_ctrl->host_config.common_config,
2262 &dsi_ctrl->host_config.u.cmd_engine);
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07002263
2264 dsi_ctrl->hw.ops.setup_cmd_stream(&dsi_ctrl->hw,
Alexander Beykunac182352017-02-27 17:46:51 -05002265 &dsi_ctrl->host_config.video_timing,
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07002266 dsi_ctrl->host_config.video_timing.h_active * 3,
Lloyd Atkinson16e96de2017-04-19 11:18:14 -04002267 0x0,
2268 NULL);
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07002269 } else {
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002270 dsi_ctrl->hw.ops.video_engine_setup(&dsi_ctrl->hw,
2271 &dsi_ctrl->host_config.common_config,
2272 &dsi_ctrl->host_config.u.video_engine);
Ajay Singh Parmaraa9152d2016-05-16 18:02:07 -07002273 dsi_ctrl->hw.ops.set_video_timing(&dsi_ctrl->hw,
2274 &dsi_ctrl->host_config.video_timing);
2275 }
2276
Clarence Ip80ada7f2017-05-04 09:55:21 -07002277 dsi_ctrl_setup_isr(dsi_ctrl);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002278
2279 dsi_ctrl->hw.ops.enable_status_interrupts(&dsi_ctrl->hw, 0x0);
2280 dsi_ctrl->hw.ops.enable_error_interrupts(&dsi_ctrl->hw, 0x0);
2281
Alexander Beykun32a6a182017-02-27 17:46:51 -05002282 pr_debug("[DSI_%d]Host initialization complete\n",
2283 dsi_ctrl->cell_index);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002284 dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x1);
2285error:
2286 mutex_unlock(&dsi_ctrl->ctrl_lock);
2287 return rc;
2288}
2289
Lloyd Atkinson8c49c582016-11-18 14:23:54 -05002290int dsi_ctrl_soft_reset(struct dsi_ctrl *dsi_ctrl)
2291{
2292 if (!dsi_ctrl)
2293 return -EINVAL;
2294
2295 mutex_lock(&dsi_ctrl->ctrl_lock);
2296 dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw);
2297 mutex_unlock(&dsi_ctrl->ctrl_lock);
2298
Alexander Beykun32a6a182017-02-27 17:46:51 -05002299 pr_debug("[DSI_%d]Soft reset complete\n", dsi_ctrl->cell_index);
Lloyd Atkinson8c49c582016-11-18 14:23:54 -05002300 return 0;
2301}
2302
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002303/**
2304 * dsi_ctrl_host_deinit() - De-Initialize DSI host hardware.
2305 * @dsi_ctrl: DSI controller handle.
2306 *
2307 * De-initializes DSI controller hardware. It can be performed only during
2308 * DSI_CTRL_POWER_CORE_CLK_ON state after LINK clocks have been turned off.
2309 *
2310 * Return: error code.
2311 */
2312int dsi_ctrl_host_deinit(struct dsi_ctrl *dsi_ctrl)
2313{
2314 int rc = 0;
2315
2316 if (!dsi_ctrl) {
2317 pr_err("Invalid params\n");
2318 return -EINVAL;
2319 }
2320
2321 mutex_lock(&dsi_ctrl->ctrl_lock);
2322
Clarence Ip80ada7f2017-05-04 09:55:21 -07002323 _dsi_ctrl_destroy_isr(dsi_ctrl);
2324
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002325 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x0);
2326 if (rc) {
2327 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002328 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002329 pr_err("driver state check failed, rc=%d\n", rc);
2330 goto error;
2331 }
2332
Alexander Beykun32a6a182017-02-27 17:46:51 -05002333 pr_debug("[DSI_%d] Host deinitization complete\n",
2334 dsi_ctrl->cell_index);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002335 dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_INIT, 0x0);
2336error:
2337 mutex_unlock(&dsi_ctrl->ctrl_lock);
2338 return rc;
2339}
2340
2341/**
2342 * dsi_ctrl_update_host_config() - update dsi host configuration
2343 * @dsi_ctrl: DSI controller handle.
2344 * @config: DSI host configuration.
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002345 * @flags: dsi_mode_flags modifying the behavior
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002346 *
2347 * Updates driver with new Host configuration to use for host initialization.
2348 * This function call will only update the software context. The stored
2349 * configuration information will be used when the host is initialized.
2350 *
2351 * Return: error code.
2352 */
2353int dsi_ctrl_update_host_config(struct dsi_ctrl *ctrl,
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002354 struct dsi_host_config *config,
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302355 int flags, void *clk_handle)
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002356{
2357 int rc = 0;
2358
2359 if (!ctrl || !config) {
2360 pr_err("Invalid params\n");
2361 return -EINVAL;
2362 }
2363
2364 mutex_lock(&ctrl->ctrl_lock);
2365
2366 rc = dsi_ctrl_validate_panel_info(ctrl, config);
2367 if (rc) {
2368 pr_err("panel validation failed, rc=%d\n", rc);
2369 goto error;
2370 }
2371
Raviteja Tamatam68892de2017-06-20 04:47:19 +05302372 if (!(flags & (DSI_MODE_FLAG_SEAMLESS | DSI_MODE_FLAG_VRR))) {
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302373 rc = dsi_ctrl_update_link_freqs(ctrl, config, clk_handle);
Ajay Singh Parmar62f795b2016-06-10 23:20:23 -07002374 if (rc) {
2375 pr_err("[%s] failed to update link frequencies, rc=%d\n",
2376 ctrl->name, rc);
2377 goto error;
2378 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002379 }
2380
Alexander Beykun32a6a182017-02-27 17:46:51 -05002381 pr_debug("[DSI_%d]Host config updated\n", ctrl->cell_index);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002382 memcpy(&ctrl->host_config, config, sizeof(ctrl->host_config));
Lloyd Atkinsone53b7372017-03-22 17:16:47 -04002383 ctrl->mode_bounds.x = ctrl->host_config.video_timing.h_active *
2384 ctrl->horiz_index;
2385 ctrl->mode_bounds.y = 0;
2386 ctrl->mode_bounds.w = ctrl->host_config.video_timing.h_active;
2387 ctrl->mode_bounds.h = ctrl->host_config.video_timing.v_active;
2388 memcpy(&ctrl->roi, &ctrl->mode_bounds, sizeof(ctrl->mode_bounds));
2389 ctrl->roi.x = 0;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002390error:
2391 mutex_unlock(&ctrl->ctrl_lock);
2392 return rc;
2393}
2394
2395/**
2396 * dsi_ctrl_validate_timing() - validate a video timing configuration
2397 * @dsi_ctrl: DSI controller handle.
2398 * @timing: Pointer to timing data.
2399 *
2400 * Driver will validate if the timing configuration is supported on the
2401 * controller hardware.
2402 *
2403 * Return: error code if timing is not supported.
2404 */
2405int dsi_ctrl_validate_timing(struct dsi_ctrl *dsi_ctrl,
2406 struct dsi_mode_info *mode)
2407{
2408 int rc = 0;
2409
2410 if (!dsi_ctrl || !mode) {
2411 pr_err("Invalid params\n");
2412 return -EINVAL;
2413 }
2414
2415 mutex_lock(&dsi_ctrl->ctrl_lock);
2416 mutex_unlock(&dsi_ctrl->ctrl_lock);
2417
2418 return rc;
2419}
2420
2421/**
2422 * dsi_ctrl_cmd_transfer() - Transfer commands on DSI link
2423 * @dsi_ctrl: DSI controller handle.
2424 * @msg: Message to transfer on DSI link.
2425 * @flags: Modifiers for message transfer.
2426 *
2427 * Command transfer can be done only when command engine is enabled. The
2428 * transfer API will block until either the command transfer finishes or
2429 * the timeout value is reached. If the trigger is deferred, it will return
2430 * without triggering the transfer. Command parameters are programmed to
2431 * hardware.
2432 *
2433 * Return: error code.
2434 */
2435int dsi_ctrl_cmd_transfer(struct dsi_ctrl *dsi_ctrl,
2436 const struct mipi_dsi_msg *msg,
2437 u32 flags)
2438{
2439 int rc = 0;
2440
2441 if (!dsi_ctrl || !msg) {
2442 pr_err("Invalid params\n");
2443 return -EINVAL;
2444 }
2445
2446 mutex_lock(&dsi_ctrl->ctrl_lock);
2447
2448 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_CMD_TX, 0x0);
2449 if (rc) {
2450 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002451 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002452 goto error;
2453 }
2454
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002455 if (flags & DSI_CTRL_CMD_READ) {
2456 rc = dsi_message_rx(dsi_ctrl, msg, flags);
Sandeep Panda79450002017-05-08 17:14:24 +05302457 if (rc <= 0)
2458 pr_err("read message failed read length, rc=%d\n", rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002459 } else {
2460 rc = dsi_message_tx(dsi_ctrl, msg, flags);
2461 if (rc)
2462 pr_err("command msg transfer failed, rc = %d\n", rc);
2463 }
2464
2465 dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_CMD_TX, 0x0);
Ajay Singh Parmar651406a2016-07-20 17:17:49 -07002466
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002467error:
2468 mutex_unlock(&dsi_ctrl->ctrl_lock);
2469 return rc;
2470}
2471
2472/**
2473 * dsi_ctrl_cmd_tx_trigger() - Trigger a deferred command.
2474 * @dsi_ctrl: DSI controller handle.
2475 * @flags: Modifiers.
2476 *
2477 * Return: error code.
2478 */
2479int dsi_ctrl_cmd_tx_trigger(struct dsi_ctrl *dsi_ctrl, u32 flags)
2480{
Clarence Ip80ada7f2017-05-04 09:55:21 -07002481 int rc = 0, ret = 0;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002482 u32 status = 0;
2483 u32 mask = (DSI_CMD_MODE_DMA_DONE);
2484
2485 if (!dsi_ctrl) {
2486 pr_err("Invalid params\n");
2487 return -EINVAL;
2488 }
2489
2490 mutex_lock(&dsi_ctrl->ctrl_lock);
2491
Clarence Ip80ada7f2017-05-04 09:55:21 -07002492 if (!(flags & DSI_CTRL_CMD_BROADCAST_MASTER))
2493 dsi_ctrl->hw.ops.trigger_command_dma(&dsi_ctrl->hw);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002494
2495 if ((flags & DSI_CTRL_CMD_BROADCAST) &&
Clarence Ip80ada7f2017-05-04 09:55:21 -07002496 (flags & DSI_CTRL_CMD_BROADCAST_MASTER)) {
2497 dsi_ctrl_enable_status_interrupt(dsi_ctrl,
2498 DSI_SINT_CMD_MODE_DMA_DONE, NULL);
2499 reinit_completion(&dsi_ctrl->irq_info.cmd_dma_done);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002500
Clarence Ip80ada7f2017-05-04 09:55:21 -07002501 /* trigger command */
2502 dsi_ctrl->hw.ops.trigger_command_dma(&dsi_ctrl->hw);
2503
2504 ret = wait_for_completion_timeout(
2505 &dsi_ctrl->irq_info.cmd_dma_done,
2506 msecs_to_jiffies(DSI_CTRL_TX_TO_MS));
2507
2508 if (ret == 0) {
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002509 status = dsi_ctrl->hw.ops.get_interrupt_status(
2510 &dsi_ctrl->hw);
Clarence Ip80ada7f2017-05-04 09:55:21 -07002511 if (status & mask) {
2512 status |= (DSI_CMD_MODE_DMA_DONE |
2513 DSI_BTA_DONE);
2514 dsi_ctrl->hw.ops.clear_interrupt_status(
2515 &dsi_ctrl->hw,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002516 status);
Clarence Ip80ada7f2017-05-04 09:55:21 -07002517 dsi_ctrl_disable_status_interrupt(dsi_ctrl,
2518 DSI_SINT_CMD_MODE_DMA_DONE);
2519 complete_all(&dsi_ctrl->irq_info.cmd_dma_done);
2520 pr_warn("dma_tx done but irq not triggered\n");
2521 } else {
2522 rc = -ETIMEDOUT;
2523 dsi_ctrl_disable_status_interrupt(dsi_ctrl,
2524 DSI_SINT_CMD_MODE_DMA_DONE);
2525 pr_err("[DSI_%d]Command transfer failed\n",
2526 dsi_ctrl->cell_index);
2527 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002528 }
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002529 }
2530
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002531 mutex_unlock(&dsi_ctrl->ctrl_lock);
2532 return rc;
2533}
2534
2535/**
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -04002536 * _dsi_ctrl_cache_misr - Cache frame MISR value
2537 * @dsi_ctrl: Pointer to associated dsi_ctrl structure
2538 */
2539static void _dsi_ctrl_cache_misr(struct dsi_ctrl *dsi_ctrl)
2540{
2541 u32 misr;
2542
2543 if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr)
2544 return;
2545
2546 misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw,
2547 dsi_ctrl->host_config.panel_mode);
2548
2549 if (misr)
2550 dsi_ctrl->misr_cache = misr;
2551
2552 pr_debug("DSI_%d misr_cache = %x\n", dsi_ctrl->cell_index,
2553 dsi_ctrl->misr_cache);
2554
2555}
2556
2557/**
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002558 * dsi_ctrl_set_power_state() - set power state for dsi controller
2559 * @dsi_ctrl: DSI controller handle.
2560 * @state: Power state.
2561 *
2562 * Set power state for DSI controller. Power state can be changed only when
2563 * Controller, Video and Command engines are turned off.
2564 *
2565 * Return: error code.
2566 */
2567int dsi_ctrl_set_power_state(struct dsi_ctrl *dsi_ctrl,
2568 enum dsi_power_state state)
2569{
2570 int rc = 0;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002571
2572 if (!dsi_ctrl || (state >= DSI_CTRL_POWER_MAX)) {
2573 pr_err("Invalid Params\n");
2574 return -EINVAL;
2575 }
2576
2577 mutex_lock(&dsi_ctrl->ctrl_lock);
2578
2579 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_POWER_STATE_CHANGE,
2580 state);
2581 if (rc) {
2582 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002583 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002584 goto error;
2585 }
2586
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302587 if (state == DSI_CTRL_POWER_VREG_ON) {
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002588 rc = dsi_ctrl_enable_supplies(dsi_ctrl, true);
2589 if (rc) {
2590 pr_err("[%d]failed to enable voltage supplies, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002591 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002592 goto error;
2593 }
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302594 } else if (state == DSI_CTRL_POWER_VREG_OFF) {
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -04002595 if (dsi_ctrl->misr_enable)
2596 _dsi_ctrl_cache_misr(dsi_ctrl);
2597
Dhaval Patel4fc756b62016-08-10 11:25:48 -07002598 rc = dsi_ctrl_enable_supplies(dsi_ctrl, false);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002599 if (rc) {
2600 pr_err("[%d]failed to disable vreg supplies, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002601 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002602 goto error;
2603 }
2604 }
2605
Alexander Beykun32a6a182017-02-27 17:46:51 -05002606 pr_debug("[DSI_%d] Power state updated to %d\n", dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002607 state);
2608 dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_POWER_STATE_CHANGE, state);
2609error:
2610 mutex_unlock(&dsi_ctrl->ctrl_lock);
2611 return rc;
2612}
2613
2614/**
2615 * dsi_ctrl_set_tpg_state() - enable/disable test pattern on the controller
2616 * @dsi_ctrl: DSI controller handle.
2617 * @on: enable/disable test pattern.
2618 *
2619 * Test pattern can be enabled only after Video engine (for video mode panels)
2620 * or command engine (for cmd mode panels) is enabled.
2621 *
2622 * Return: error code.
2623 */
2624int dsi_ctrl_set_tpg_state(struct dsi_ctrl *dsi_ctrl, bool on)
2625{
2626 int rc = 0;
2627
2628 if (!dsi_ctrl) {
2629 pr_err("Invalid params\n");
2630 return -EINVAL;
2631 }
2632
2633 mutex_lock(&dsi_ctrl->ctrl_lock);
2634
2635 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_TPG, on);
2636 if (rc) {
2637 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002638 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002639 goto error;
2640 }
2641
2642 if (on) {
2643 if (dsi_ctrl->host_config.panel_mode == DSI_OP_VIDEO_MODE) {
2644 dsi_ctrl->hw.ops.video_test_pattern_setup(&dsi_ctrl->hw,
2645 DSI_TEST_PATTERN_INC,
2646 0xFFFF);
2647 } else {
2648 dsi_ctrl->hw.ops.cmd_test_pattern_setup(
2649 &dsi_ctrl->hw,
2650 DSI_TEST_PATTERN_INC,
2651 0xFFFF,
2652 0x0);
2653 }
2654 }
2655 dsi_ctrl->hw.ops.test_pattern_enable(&dsi_ctrl->hw, on);
2656
Alexander Beykun32a6a182017-02-27 17:46:51 -05002657 pr_debug("[DSI_%d]Set test pattern state=%d\n",
2658 dsi_ctrl->cell_index, on);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002659 dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_TPG, on);
2660error:
2661 mutex_unlock(&dsi_ctrl->ctrl_lock);
2662 return rc;
2663}
2664
2665/**
2666 * dsi_ctrl_set_host_engine_state() - set host engine state
2667 * @dsi_ctrl: DSI Controller handle.
2668 * @state: Engine state.
2669 *
2670 * Host engine state can be modified only when DSI controller power state is
2671 * set to DSI_CTRL_POWER_LINK_CLK_ON and cmd, video engines are disabled.
2672 *
2673 * Return: error code.
2674 */
2675int dsi_ctrl_set_host_engine_state(struct dsi_ctrl *dsi_ctrl,
2676 enum dsi_engine_state state)
2677{
2678 int rc = 0;
2679
2680 if (!dsi_ctrl || (state >= DSI_CTRL_ENGINE_MAX)) {
2681 pr_err("Invalid params\n");
2682 return -EINVAL;
2683 }
2684
2685 mutex_lock(&dsi_ctrl->ctrl_lock);
2686
2687 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state);
2688 if (rc) {
2689 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002690 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002691 goto error;
2692 }
2693
2694 if (state == DSI_CTRL_ENGINE_ON)
2695 dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, true);
2696 else
2697 dsi_ctrl->hw.ops.ctrl_en(&dsi_ctrl->hw, false);
2698
Alexander Beykun32a6a182017-02-27 17:46:51 -05002699 pr_debug("[DSI_%d] Set host engine state = %d\n", dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002700 state);
2701 dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_HOST_ENGINE, state);
2702error:
2703 mutex_unlock(&dsi_ctrl->ctrl_lock);
2704 return rc;
2705}
2706
2707/**
2708 * dsi_ctrl_set_cmd_engine_state() - set command engine state
2709 * @dsi_ctrl: DSI Controller handle.
2710 * @state: Engine state.
2711 *
2712 * Command engine state can be modified only when DSI controller power state is
2713 * set to DSI_CTRL_POWER_LINK_CLK_ON.
2714 *
2715 * Return: error code.
2716 */
2717int dsi_ctrl_set_cmd_engine_state(struct dsi_ctrl *dsi_ctrl,
2718 enum dsi_engine_state state)
2719{
2720 int rc = 0;
2721
2722 if (!dsi_ctrl || (state >= DSI_CTRL_ENGINE_MAX)) {
2723 pr_err("Invalid params\n");
2724 return -EINVAL;
2725 }
2726
2727 mutex_lock(&dsi_ctrl->ctrl_lock);
2728
2729 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_CMD_ENGINE, state);
2730 if (rc) {
2731 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002732 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002733 goto error;
2734 }
2735
2736 if (state == DSI_CTRL_ENGINE_ON)
2737 dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, true);
2738 else
2739 dsi_ctrl->hw.ops.cmd_engine_en(&dsi_ctrl->hw, false);
2740
Alexander Beykun32a6a182017-02-27 17:46:51 -05002741 pr_debug("[DSI_%d] Set cmd engine state = %d\n", dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002742 state);
2743 dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_CMD_ENGINE, state);
2744error:
2745 mutex_unlock(&dsi_ctrl->ctrl_lock);
2746 return rc;
2747}
2748
2749/**
2750 * dsi_ctrl_set_vid_engine_state() - set video engine state
2751 * @dsi_ctrl: DSI Controller handle.
2752 * @state: Engine state.
2753 *
2754 * Video engine state can be modified only when DSI controller power state is
2755 * set to DSI_CTRL_POWER_LINK_CLK_ON.
2756 *
2757 * Return: error code.
2758 */
2759int dsi_ctrl_set_vid_engine_state(struct dsi_ctrl *dsi_ctrl,
2760 enum dsi_engine_state state)
2761{
2762 int rc = 0;
2763 bool on;
2764
2765 if (!dsi_ctrl || (state >= DSI_CTRL_ENGINE_MAX)) {
2766 pr_err("Invalid params\n");
2767 return -EINVAL;
2768 }
2769
2770 mutex_lock(&dsi_ctrl->ctrl_lock);
2771
2772 rc = dsi_ctrl_check_state(dsi_ctrl, DSI_CTRL_OP_VID_ENGINE, state);
2773 if (rc) {
2774 pr_err("[DSI_%d] Controller state check failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002775 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002776 goto error;
2777 }
2778
2779 on = (state == DSI_CTRL_ENGINE_ON) ? true : false;
2780 dsi_ctrl->hw.ops.video_engine_en(&dsi_ctrl->hw, on);
2781
2782 /* perform a reset when turning off video engine */
2783 if (!on)
2784 dsi_ctrl->hw.ops.soft_reset(&dsi_ctrl->hw);
2785
Alexander Beykun32a6a182017-02-27 17:46:51 -05002786 pr_debug("[DSI_%d] Set video engine state = %d\n", dsi_ctrl->cell_index,
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002787 state);
2788 dsi_ctrl_update_state(dsi_ctrl, DSI_CTRL_OP_VID_ENGINE, state);
2789error:
2790 mutex_unlock(&dsi_ctrl->ctrl_lock);
2791 return rc;
2792}
2793
2794/**
Shashank Babu Chinta Venkata82109522017-05-09 18:59:21 -07002795 * dsi_ctrl_set_ulps() - set ULPS state for DSI lanes.
2796 * @dsi_ctrl: DSI controller handle.
2797 * @enable: enable/disable ULPS.
2798 *
2799 * ULPS can be enabled/disabled after DSI host engine is turned on.
2800 *
2801 * Return: error code.
2802 */
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002803int dsi_ctrl_set_ulps(struct dsi_ctrl *dsi_ctrl, bool enable)
2804{
2805 int rc = 0;
2806
2807 if (!dsi_ctrl) {
2808 pr_err("Invalid params\n");
2809 return -EINVAL;
2810 }
2811
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302812 mutex_lock(&dsi_ctrl->ctrl_lock);
2813
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002814 if (enable)
2815 rc = dsi_enable_ulps(dsi_ctrl);
2816 else
2817 rc = dsi_disable_ulps(dsi_ctrl);
2818
2819 if (rc) {
2820 pr_err("[DSI_%d] Ulps state change(%d) failed, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002821 dsi_ctrl->cell_index, enable, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002822 goto error;
2823 }
Alexander Beykun32a6a182017-02-27 17:46:51 -05002824 pr_debug("[DSI_%d] ULPS state = %d\n", dsi_ctrl->cell_index, enable);
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302825
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002826error:
2827 mutex_unlock(&dsi_ctrl->ctrl_lock);
2828 return rc;
2829}
2830
2831/**
2832 * dsi_ctrl_set_clamp_state() - set clamp state for DSI phy
2833 * @dsi_ctrl: DSI controller handle.
2834 * @enable: enable/disable clamping.
2835 *
2836 * Clamps can be enabled/disabled while DSI contoller is still turned on.
2837 *
2838 * Return: error code.
2839 */
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302840int dsi_ctrl_set_clamp_state(struct dsi_ctrl *dsi_ctrl,
2841 bool enable, bool ulps_enabled)
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002842{
2843 int rc = 0;
2844
2845 if (!dsi_ctrl) {
2846 pr_err("Invalid params\n");
2847 return -EINVAL;
2848 }
2849
Padmanabhan Komanduru8ee8ee52016-12-19 12:10:51 +05302850 if (!dsi_ctrl->hw.ops.clamp_enable ||
2851 !dsi_ctrl->hw.ops.clamp_disable) {
2852 pr_debug("No clamp control for DSI controller\n");
2853 return 0;
2854 }
2855
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002856 mutex_lock(&dsi_ctrl->ctrl_lock);
2857
Padmanabhan Komandurudbd2fb02016-12-02 15:18:49 +05302858 rc = dsi_enable_io_clamp(dsi_ctrl, enable, ulps_enabled);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002859 if (rc) {
Alexander Beykun32a6a182017-02-27 17:46:51 -05002860 pr_err("[DSI_%d] Failed to enable IO clamp\n",
2861 dsi_ctrl->cell_index);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002862 goto error;
2863 }
2864
Alexander Beykun32a6a182017-02-27 17:46:51 -05002865 pr_debug("[DSI_%d] Clamp state = %d\n", dsi_ctrl->cell_index, enable);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002866error:
2867 mutex_unlock(&dsi_ctrl->ctrl_lock);
2868 return rc;
2869}
2870
2871/**
2872 * dsi_ctrl_set_clock_source() - set clock source fpr dsi link clocks
2873 * @dsi_ctrl: DSI controller handle.
2874 * @source_clks: Source clocks for DSI link clocks.
2875 *
2876 * Clock source should be changed while link clocks are disabled.
2877 *
2878 * Return: error code.
2879 */
2880int dsi_ctrl_set_clock_source(struct dsi_ctrl *dsi_ctrl,
2881 struct dsi_clk_link_set *source_clks)
2882{
2883 int rc = 0;
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002884
2885 if (!dsi_ctrl || !source_clks) {
2886 pr_err("Invalid params\n");
2887 return -EINVAL;
2888 }
2889
2890 mutex_lock(&dsi_ctrl->ctrl_lock);
2891
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002892 rc = dsi_clk_update_parent(source_clks, &dsi_ctrl->clk_info.rcg_clks);
2893 if (rc) {
2894 pr_err("[DSI_%d]Failed to update link clk parent, rc=%d\n",
Alexander Beykun32a6a182017-02-27 17:46:51 -05002895 dsi_ctrl->cell_index, rc);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002896 (void)dsi_clk_update_parent(&dsi_ctrl->clk_info.pll_op_clks,
2897 &dsi_ctrl->clk_info.rcg_clks);
2898 goto error;
2899 }
2900
2901 dsi_ctrl->clk_info.pll_op_clks.byte_clk = source_clks->byte_clk;
2902 dsi_ctrl->clk_info.pll_op_clks.pixel_clk = source_clks->pixel_clk;
2903
Alexander Beykun32a6a182017-02-27 17:46:51 -05002904 pr_debug("[DSI_%d] Source clocks are updated\n", dsi_ctrl->cell_index);
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002905
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002906error:
2907 mutex_unlock(&dsi_ctrl->ctrl_lock);
2908 return rc;
2909}
2910
2911/**
Rajkumar Subbiah01e6dd642017-07-05 14:47:47 -04002912 * dsi_ctrl_setup_misr() - Setup frame MISR
2913 * @dsi_ctrl: DSI controller handle.
2914 * @enable: enable/disable MISR.
2915 * @frame_count: Number of frames to accumulate MISR.
2916 *
2917 * Return: error code.
2918 */
2919int dsi_ctrl_setup_misr(struct dsi_ctrl *dsi_ctrl,
2920 bool enable,
2921 u32 frame_count)
2922{
2923 if (!dsi_ctrl) {
2924 pr_err("Invalid params\n");
2925 return -EINVAL;
2926 }
2927
2928 if (!dsi_ctrl->hw.ops.setup_misr)
2929 return 0;
2930
2931 mutex_lock(&dsi_ctrl->ctrl_lock);
2932 dsi_ctrl->misr_enable = enable;
2933 dsi_ctrl->hw.ops.setup_misr(&dsi_ctrl->hw,
2934 dsi_ctrl->host_config.panel_mode,
2935 enable, frame_count);
2936 mutex_unlock(&dsi_ctrl->ctrl_lock);
2937 return 0;
2938}
2939
2940/**
2941 * dsi_ctrl_collect_misr() - Read frame MISR
2942 * @dsi_ctrl: DSI controller handle.
2943 *
2944 * Return: MISR value.
2945 */
2946u32 dsi_ctrl_collect_misr(struct dsi_ctrl *dsi_ctrl)
2947{
2948 u32 misr;
2949
2950 if (!dsi_ctrl || !dsi_ctrl->hw.ops.collect_misr)
2951 return 0;
2952
2953 misr = dsi_ctrl->hw.ops.collect_misr(&dsi_ctrl->hw,
2954 dsi_ctrl->host_config.panel_mode);
2955 if (!misr)
2956 misr = dsi_ctrl->misr_cache;
2957
2958 pr_debug("DSI_%d cached misr = %x, final = %x\n",
2959 dsi_ctrl->cell_index, dsi_ctrl->misr_cache, misr);
2960
2961 return misr;
2962}
2963
2964/**
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002965 * dsi_ctrl_drv_register() - register platform driver for dsi controller
2966 */
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07002967void dsi_ctrl_drv_register(void)
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002968{
2969 platform_driver_register(&dsi_ctrl_driver);
2970}
2971
2972/**
2973 * dsi_ctrl_drv_unregister() - unregister platform driver
2974 */
Ajay Singh Parmar64c19192016-06-10 16:44:56 -07002975void dsi_ctrl_drv_unregister(void)
Ajay Singh Parmar5c6b4862016-06-22 17:31:21 -07002976{
2977 platform_driver_unregister(&dsi_ctrl_driver);
2978}