]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/gpu/drm/omapdrm/dss/dpi.c
drm/omap: support type B PLL for DPI
[mirror_ubuntu-bionic-kernel.git] / drivers / gpu / drm / omapdrm / dss / dpi.c
CommitLineData
553c48cf
TV
1/*
2 * linux/drivers/video/omap2/dss/dpi.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DPI"
24
25#include <linux/kernel.h>
553c48cf 26#include <linux/delay.h>
a8a35931 27#include <linux/export.h>
8a2cfea8 28#include <linux/err.h>
553c48cf 29#include <linux/errno.h>
8a2cfea8
TV
30#include <linux/platform_device.h>
31#include <linux/regulator/consumer.h>
13b1ba7d 32#include <linux/string.h>
2ecef246 33#include <linux/of.h>
2daea7af 34#include <linux/clk.h>
736e60dd 35#include <linux/component.h>
553c48cf 36
a0b38cc4 37#include <video/omapdss.h>
553c48cf
TV
38
39#include "dss.h"
195e672a 40#include "dss_features.h"
553c48cf 41
630d2d0d 42struct dpi_data {
00df43b8
TV
43 struct platform_device *pdev;
44
8a2cfea8 45 struct regulator *vdds_dsi_reg;
331e6078 46 enum dss_clk_source clk_src;
2daea7af 47 struct dss_pll *pll;
5cf9a264 48
c8a5e4e8
AT
49 struct mutex lock;
50
c499144c 51 struct omap_video_timings timings;
5cf9a264 52 struct dss_lcd_mgr_config mgr_config;
c6b393d4 53 int data_lines;
81b87f51 54
1f68d9c4 55 struct omap_dss_device output;
2ecef246
TV
56
57 bool port_initialized;
630d2d0d
AT
58};
59
2ac6a1aa
AT
60static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
61{
62 return container_of(dssdev, struct dpi_data, output);
63}
64
80eb6751 65/* only used in non-DT mode */
2ac6a1aa
AT
66static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
67{
68 return dev_get_drvdata(&pdev->dev);
69}
553c48cf 70
331e6078 71static enum dss_clk_source dpi_get_clk_src(enum omap_channel channel)
a72b64b9 72{
bd0f5cc3
TV
73 /*
74 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
75 * would also be used for DISPC fclk. Meaning, when the DPI output is
76 * disabled, DISPC clock will be disabled, and TV out will stop.
77 */
78 switch (omapdss_get_version()) {
79 case OMAPDSS_VER_OMAP24xx:
80 case OMAPDSS_VER_OMAP34xx_ES1:
81 case OMAPDSS_VER_OMAP34xx_ES3:
82 case OMAPDSS_VER_OMAP3630:
83 case OMAPDSS_VER_AM35xx:
d6279d4a 84 case OMAPDSS_VER_AM43xx:
331e6078 85 return DSS_CLK_SRC_FCK;
bd0f5cc3 86
f8ad984c
TV
87 case OMAPDSS_VER_OMAP4430_ES1:
88 case OMAPDSS_VER_OMAP4430_ES2:
89 case OMAPDSS_VER_OMAP4:
90 switch (channel) {
91 case OMAP_DSS_CHANNEL_LCD:
331e6078 92 return DSS_CLK_SRC_PLL1_1;
f8ad984c 93 case OMAP_DSS_CHANNEL_LCD2:
331e6078 94 return DSS_CLK_SRC_PLL2_1;
f8ad984c 95 default:
331e6078 96 return DSS_CLK_SRC_FCK;
f8ad984c
TV
97 }
98
99 case OMAPDSS_VER_OMAP5:
100 switch (channel) {
101 case OMAP_DSS_CHANNEL_LCD:
331e6078 102 return DSS_CLK_SRC_PLL1_1;
f8ad984c 103 case OMAP_DSS_CHANNEL_LCD3:
331e6078
TV
104 return DSS_CLK_SRC_PLL2_1;
105 case OMAP_DSS_CHANNEL_LCD2:
f8ad984c 106 default:
331e6078 107 return DSS_CLK_SRC_FCK;
f8ad984c
TV
108 }
109
a2408154
TV
110 case OMAPDSS_VER_DRA7xx:
111 switch (channel) {
112 case OMAP_DSS_CHANNEL_LCD:
331e6078 113 return DSS_CLK_SRC_PLL1_1;
a2408154 114 case OMAP_DSS_CHANNEL_LCD2:
331e6078 115 return DSS_CLK_SRC_PLL1_3;
a2408154 116 case OMAP_DSS_CHANNEL_LCD3:
331e6078 117 return DSS_CLK_SRC_PLL2_1;
a2408154 118 default:
331e6078 119 return DSS_CLK_SRC_FCK;
a2408154
TV
120 }
121
0e8276ef 122 default:
3b63ca75 123 return DSS_CLK_SRC_FCK;
0e8276ef 124 }
7636b3b4
AT
125}
126
100c8262 127struct dpi_clk_calc_ctx {
2daea7af 128 struct dss_pll *pll;
13ece4d3 129 unsigned clkout_idx;
100c8262
TV
130
131 /* inputs */
132
133 unsigned long pck_min, pck_max;
134
135 /* outputs */
136
2daea7af 137 struct dss_pll_clock_info dsi_cinfo;
c56812fc 138 unsigned long fck;
100c8262
TV
139 struct dispc_clock_info dispc_cinfo;
140};
141
142static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
143 unsigned long pck, void *data)
144{
145 struct dpi_clk_calc_ctx *ctx = data;
146
147 /*
148 * Odd dividers give us uneven duty cycle, causing problem when level
149 * shifted. So skip all odd dividers when the pixel clock is on the
150 * higher side.
151 */
72e5512a 152 if (ctx->pck_min >= 100000000) {
100c8262
TV
153 if (lckd > 1 && lckd % 2 != 0)
154 return false;
155
156 if (pckd > 1 && pckd % 2 != 0)
157 return false;
158 }
159
160 ctx->dispc_cinfo.lck_div = lckd;
161 ctx->dispc_cinfo.pck_div = pckd;
162 ctx->dispc_cinfo.lck = lck;
163 ctx->dispc_cinfo.pck = pck;
164
165 return true;
166}
167
168
2daea7af 169static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
100c8262
TV
170 void *data)
171{
172 struct dpi_clk_calc_ctx *ctx = data;
173
174 /*
175 * Odd dividers give us uneven duty cycle, causing problem when level
176 * shifted. So skip all odd dividers when the pixel clock is on the
177 * higher side.
178 */
2daea7af 179 if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000)
100c8262
TV
180 return false;
181
13ece4d3
TV
182 ctx->dsi_cinfo.mX[ctx->clkout_idx] = m_dispc;
183 ctx->dsi_cinfo.clkout[ctx->clkout_idx] = dispc;
100c8262
TV
184
185 return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
186 dpi_calc_dispc_cb, ctx);
187}
188
189
2daea7af
TV
190static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
191 unsigned long clkdco,
100c8262
TV
192 void *data)
193{
194 struct dpi_clk_calc_ctx *ctx = data;
195
2daea7af
TV
196 ctx->dsi_cinfo.n = n;
197 ctx->dsi_cinfo.m = m;
100c8262 198 ctx->dsi_cinfo.fint = fint;
2daea7af 199 ctx->dsi_cinfo.clkdco = clkdco;
100c8262 200
cd0715ff 201 return dss_pll_hsdiv_calc_a(ctx->pll, clkdco,
2daea7af
TV
202 ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
203 dpi_calc_hsdiv_cb, ctx);
100c8262
TV
204}
205
d0f58bd3 206static bool dpi_calc_dss_cb(unsigned long fck, void *data)
100c8262
TV
207{
208 struct dpi_clk_calc_ctx *ctx = data;
209
d0f58bd3 210 ctx->fck = fck;
100c8262
TV
211
212 return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
213 dpi_calc_dispc_cb, ctx);
214}
215
630d2d0d
AT
216static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck,
217 struct dpi_clk_calc_ctx *ctx)
100c8262
TV
218{
219 unsigned long clkin;
100c8262 220
100c8262 221 memset(ctx, 0, sizeof(*ctx));
2daea7af 222 ctx->pll = dpi->pll;
13ece4d3 223 ctx->clkout_idx = dss_pll_get_clkout_idx_for_src(dpi->clk_src);
100c8262 224
683cd866 225 clkin = clk_get_rate(dpi->pll->clkin);
100c8262 226
683cd866
TV
227 if (dpi->pll->hw->type == DSS_PLL_TYPE_A) {
228 unsigned long pll_min, pll_max;
2daea7af 229
683cd866
TV
230 ctx->pck_min = pck - 1000;
231 ctx->pck_max = pck + 1000;
232
233 pll_min = 0;
234 pll_max = 0;
235
236 return dss_pll_calc_a(ctx->pll, clkin,
237 pll_min, pll_max,
238 dpi_calc_pll_cb, ctx);
239 } else { /* DSS_PLL_TYPE_B */
240 dss_pll_calc_b(dpi->pll, clkin, pck, &ctx->dsi_cinfo);
241
242 ctx->dispc_cinfo.lck_div = 1;
243 ctx->dispc_cinfo.pck_div = 1;
244 ctx->dispc_cinfo.lck = ctx->dsi_cinfo.clkout[0];
245 ctx->dispc_cinfo.pck = ctx->dispc_cinfo.lck;
246
247 return true;
248 }
100c8262
TV
249}
250
251static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
252{
253 int i;
254
255 /*
256 * DSS fck gives us very few possibilities, so finding a good pixel
257 * clock may not be possible. We try multiple times to find the clock,
258 * each time widening the pixel clock range we look for, up to
2c6360fb 259 * +/- ~15MHz.
100c8262
TV
260 */
261
2c6360fb 262 for (i = 0; i < 25; ++i) {
100c8262
TV
263 bool ok;
264
265 memset(ctx, 0, sizeof(*ctx));
266 if (pck > 1000 * i * i * i)
267 ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
268 else
269 ctx->pck_min = 0;
270 ctx->pck_max = pck + 1000 * i * i * i;
271
688af02d 272 ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx);
100c8262
TV
273 if (ok)
274 return ok;
275 }
276
277 return false;
278}
279
280
281
630d2d0d 282static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel,
ff1b2cde
SS
283 unsigned long pck_req, unsigned long *fck, int *lck_div,
284 int *pck_div)
553c48cf 285{
100c8262 286 struct dpi_clk_calc_ctx ctx;
553c48cf 287 int r;
100c8262 288 bool ok;
553c48cf 289
630d2d0d 290 ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
100c8262
TV
291 if (!ok)
292 return -EINVAL;
553c48cf 293
2daea7af 294 r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo);
553c48cf
TV
295 if (r)
296 return r;
297
331e6078 298 dss_select_lcd_clk_source(channel, dpi->clk_src);
553c48cf 299
630d2d0d 300 dpi->mgr_config.clock_info = ctx.dispc_cinfo;
553c48cf 301
13ece4d3 302 *fck = ctx.dsi_cinfo.clkout[ctx.clkout_idx];
100c8262
TV
303 *lck_div = ctx.dispc_cinfo.lck_div;
304 *pck_div = ctx.dispc_cinfo.pck_div;
553c48cf
TV
305
306 return 0;
307}
7636b3b4 308
630d2d0d
AT
309static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
310 unsigned long *fck, int *lck_div, int *pck_div)
553c48cf 311{
100c8262 312 struct dpi_clk_calc_ctx ctx;
553c48cf 313 int r;
100c8262 314 bool ok;
553c48cf 315
100c8262
TV
316 ok = dpi_dss_clk_calc(pck_req, &ctx);
317 if (!ok)
318 return -EINVAL;
553c48cf 319
d0f58bd3 320 r = dss_set_fck_rate(ctx.fck);
553c48cf
TV
321 if (r)
322 return r;
323
630d2d0d 324 dpi->mgr_config.clock_info = ctx.dispc_cinfo;
553c48cf 325
d0f58bd3 326 *fck = ctx.fck;
100c8262
TV
327 *lck_div = ctx.dispc_cinfo.lck_div;
328 *pck_div = ctx.dispc_cinfo.pck_div;
553c48cf
TV
329
330 return 0;
331}
553c48cf 332
630d2d0d 333static int dpi_set_mode(struct dpi_data *dpi)
553c48cf 334{
630d2d0d 335 struct omap_dss_device *out = &dpi->output;
a070ba6c 336 enum omap_channel channel = out->dispc_channel;
630d2d0d 337 struct omap_video_timings *t = &dpi->timings;
7636b3b4
AT
338 int lck_div = 0, pck_div = 0;
339 unsigned long fck = 0;
553c48cf 340 unsigned long pck;
553c48cf
TV
341 int r = 0;
342
2daea7af 343 if (dpi->pll)
a070ba6c 344 r = dpi_set_dsi_clk(dpi, channel, t->pixelclock, &fck,
6d523e7b 345 &lck_div, &pck_div);
7636b3b4 346 else
630d2d0d 347 r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
6d523e7b 348 &lck_div, &pck_div);
553c48cf 349 if (r)
4fbafaf3 350 return r;
553c48cf 351
d8d78941 352 pck = fck / lck_div / pck_div;
553c48cf 353
d8d78941
TV
354 if (pck != t->pixelclock) {
355 DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
356 t->pixelclock, pck);
553c48cf 357
d8d78941 358 t->pixelclock = pck;
553c48cf
TV
359 }
360
a070ba6c 361 dss_mgr_set_timings(channel, t);
553c48cf 362
4fbafaf3 363 return 0;
553c48cf
TV
364}
365
630d2d0d 366static void dpi_config_lcd_manager(struct dpi_data *dpi)
553c48cf 367{
630d2d0d 368 struct omap_dss_device *out = &dpi->output;
a070ba6c 369 enum omap_channel channel = out->dispc_channel;
630d2d0d
AT
370
371 dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
569969d6 372
630d2d0d
AT
373 dpi->mgr_config.stallmode = false;
374 dpi->mgr_config.fifohandcheck = false;
5cf9a264 375
630d2d0d 376 dpi->mgr_config.video_port_width = dpi->data_lines;
5cf9a264 377
630d2d0d 378 dpi->mgr_config.lcden_sig_polarity = 0;
5cf9a264 379
a070ba6c 380 dss_mgr_set_lcd_config(channel, &dpi->mgr_config);
553c48cf
TV
381}
382
86a3efe1 383static int dpi_display_enable(struct omap_dss_device *dssdev)
553c48cf 384{
2ac6a1aa 385 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
630d2d0d 386 struct omap_dss_device *out = &dpi->output;
a070ba6c 387 enum omap_channel channel = out->dispc_channel;
553c48cf
TV
388 int r;
389
630d2d0d 390 mutex_lock(&dpi->lock);
c8a5e4e8 391
630d2d0d 392 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
40410715 393 DSSERR("no VDSS_DSI regulator\n");
c8a5e4e8
AT
394 r = -ENODEV;
395 goto err_no_reg;
40410715
RK
396 }
397
f1504ad0 398 if (!out->dispc_channel_connected) {
5d512fcd 399 DSSERR("failed to enable display: no output/manager\n");
c8a5e4e8 400 r = -ENODEV;
5d512fcd 401 goto err_no_out_mgr;
05e1d606
TV
402 }
403
195e672a 404 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
630d2d0d 405 r = regulator_enable(dpi->vdds_dsi_reg);
8a2cfea8 406 if (r)
4fbafaf3 407 goto err_reg_enable;
8a2cfea8
TV
408 }
409
4fbafaf3 410 r = dispc_runtime_get();
553c48cf 411 if (r)
4fbafaf3
TV
412 goto err_get_dispc;
413
a070ba6c 414 r = dss_dpi_select_source(out->port_num, channel);
de09e455
TV
415 if (r)
416 goto err_src_sel;
417
2daea7af
TV
418 if (dpi->pll) {
419 r = dss_pll_enable(dpi->pll);
7636b3b4 420 if (r)
4fbafaf3 421 goto err_dsi_pll_init;
7636b3b4
AT
422 }
423
630d2d0d 424 r = dpi_set_mode(dpi);
553c48cf 425 if (r)
4fbafaf3 426 goto err_set_mode;
553c48cf 427
630d2d0d 428 dpi_config_lcd_manager(dpi);
5cf9a264 429
553c48cf
TV
430 mdelay(2);
431
a070ba6c 432 r = dss_mgr_enable(channel);
33ca237f
TV
433 if (r)
434 goto err_mgr_enable;
553c48cf 435
630d2d0d 436 mutex_unlock(&dpi->lock);
c8a5e4e8 437
553c48cf
TV
438 return 0;
439
33ca237f 440err_mgr_enable:
4fbafaf3 441err_set_mode:
2daea7af
TV
442 if (dpi->pll)
443 dss_pll_disable(dpi->pll);
4fbafaf3 444err_dsi_pll_init:
de09e455 445err_src_sel:
4fbafaf3
TV
446 dispc_runtime_put();
447err_get_dispc:
195e672a 448 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
630d2d0d 449 regulator_disable(dpi->vdds_dsi_reg);
4fbafaf3 450err_reg_enable:
5d512fcd 451err_no_out_mgr:
c8a5e4e8 452err_no_reg:
630d2d0d 453 mutex_unlock(&dpi->lock);
553c48cf
TV
454 return r;
455}
456
86a3efe1 457static void dpi_display_disable(struct omap_dss_device *dssdev)
553c48cf 458{
2ac6a1aa 459 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
a070ba6c 460 enum omap_channel channel = dpi->output.dispc_channel;
5d512fcd 461
630d2d0d 462 mutex_lock(&dpi->lock);
c8a5e4e8 463
a070ba6c 464 dss_mgr_disable(channel);
553c48cf 465
2daea7af 466 if (dpi->pll) {
3b63ca75 467 dss_select_lcd_clk_source(channel, DSS_CLK_SRC_FCK);
2daea7af 468 dss_pll_disable(dpi->pll);
7636b3b4 469 }
553c48cf 470
4fbafaf3 471 dispc_runtime_put();
553c48cf 472
195e672a 473 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
630d2d0d 474 regulator_disable(dpi->vdds_dsi_reg);
8a2cfea8 475
630d2d0d 476 mutex_unlock(&dpi->lock);
553c48cf 477}
553c48cf 478
86a3efe1 479static void dpi_set_timings(struct omap_dss_device *dssdev,
c499144c 480 struct omap_video_timings *timings)
553c48cf 481{
2ac6a1aa 482 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
630d2d0d 483
553c48cf 484 DSSDBG("dpi_set_timings\n");
c8a5e4e8 485
630d2d0d 486 mutex_lock(&dpi->lock);
c8a5e4e8 487
630d2d0d 488 dpi->timings = *timings;
c499144c 489
630d2d0d 490 mutex_unlock(&dpi->lock);
553c48cf
TV
491}
492
0b24edb1
TV
493static void dpi_get_timings(struct omap_dss_device *dssdev,
494 struct omap_video_timings *timings)
495{
2ac6a1aa 496 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
630d2d0d
AT
497
498 mutex_lock(&dpi->lock);
0b24edb1 499
630d2d0d 500 *timings = dpi->timings;
0b24edb1 501
630d2d0d 502 mutex_unlock(&dpi->lock);
0b24edb1
TV
503}
504
86a3efe1 505static int dpi_check_timings(struct omap_dss_device *dssdev,
553c48cf
TV
506 struct omap_video_timings *timings)
507{
2ac6a1aa 508 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
a070ba6c 509 enum omap_channel channel = dpi->output.dispc_channel;
553c48cf
TV
510 int lck_div, pck_div;
511 unsigned long fck;
512 unsigned long pck;
100c8262
TV
513 struct dpi_clk_calc_ctx ctx;
514 bool ok;
553c48cf 515
2158f2c7
TV
516 if (timings->x_res % 8 != 0)
517 return -EINVAL;
518
a070ba6c 519 if (!dispc_mgr_timings_ok(channel, timings))
553c48cf
TV
520 return -EINVAL;
521
d8d78941 522 if (timings->pixelclock == 0)
553c48cf
TV
523 return -EINVAL;
524
2daea7af 525 if (dpi->pll) {
630d2d0d 526 ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
100c8262
TV
527 if (!ok)
528 return -EINVAL;
553c48cf 529
13ece4d3 530 fck = ctx.dsi_cinfo.clkout[ctx.clkout_idx];
7636b3b4 531 } else {
d8d78941 532 ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
100c8262
TV
533 if (!ok)
534 return -EINVAL;
553c48cf 535
d0f58bd3 536 fck = ctx.fck;
553c48cf 537 }
7636b3b4 538
100c8262
TV
539 lck_div = ctx.dispc_cinfo.lck_div;
540 pck_div = ctx.dispc_cinfo.pck_div;
553c48cf 541
d8d78941 542 pck = fck / lck_div / pck_div;
553c48cf 543
d8d78941 544 timings->pixelclock = pck;
553c48cf
TV
545
546 return 0;
547}
553c48cf 548
86a3efe1 549static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
c6b393d4 550{
2ac6a1aa 551 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
c6b393d4 552
630d2d0d 553 mutex_lock(&dpi->lock);
c6b393d4 554
630d2d0d
AT
555 dpi->data_lines = data_lines;
556
557 mutex_unlock(&dpi->lock);
c6b393d4 558}
c6b393d4 559
2daea7af 560static int dpi_verify_dsi_pll(struct dss_pll *pll)
6061675b
TV
561{
562 int r;
563
564 /* do initial setup with the PLL to see if it is operational */
565
2daea7af 566 r = dss_pll_enable(pll);
f76b178a 567 if (r)
6061675b 568 return r;
6061675b 569
2daea7af 570 dss_pll_disable(pll);
6061675b
TV
571
572 return 0;
573}
574
630d2d0d 575static int dpi_init_regulator(struct dpi_data *dpi)
2795f646
TV
576{
577 struct regulator *vdds_dsi;
578
579 if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
580 return 0;
581
630d2d0d 582 if (dpi->vdds_dsi_reg)
2795f646
TV
583 return 0;
584
630d2d0d 585 vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
2795f646 586 if (IS_ERR(vdds_dsi)) {
40359a9b
TV
587 if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
588 DSSERR("can't get VDDS_DSI regulator\n");
4123de21 589 return PTR_ERR(vdds_dsi);
2795f646
TV
590 }
591
630d2d0d 592 dpi->vdds_dsi_reg = vdds_dsi;
2795f646
TV
593
594 return 0;
595}
596
630d2d0d 597static void dpi_init_pll(struct dpi_data *dpi)
2795f646 598{
2daea7af 599 struct dss_pll *pll;
2795f646 600
2daea7af 601 if (dpi->pll)
2795f646
TV
602 return;
603
331e6078
TV
604 dpi->clk_src = dpi_get_clk_src(dpi->output.dispc_channel);
605
606 pll = dss_pll_find_by_src(dpi->clk_src);
2daea7af 607 if (!pll)
2795f646
TV
608 return;
609
2daea7af 610 if (dpi_verify_dsi_pll(pll)) {
2795f646
TV
611 DSSWARN("DSI PLL not operational\n");
612 return;
613 }
614
2daea7af 615 dpi->pll = pll;
2795f646
TV
616}
617
2eea5ae6
TV
618/*
619 * Return a hardcoded channel for the DPI output. This should work for
620 * current use cases, but this can be later expanded to either resolve
621 * the channel in some more dynamic manner, or get the channel as a user
622 * parameter.
623 */
f7e38fe9 624static enum omap_channel dpi_get_channel(int port_num)
2eea5ae6
TV
625{
626 switch (omapdss_get_version()) {
627 case OMAPDSS_VER_OMAP24xx:
628 case OMAPDSS_VER_OMAP34xx_ES1:
629 case OMAPDSS_VER_OMAP34xx_ES3:
630 case OMAPDSS_VER_OMAP3630:
631 case OMAPDSS_VER_AM35xx:
d6279d4a 632 case OMAPDSS_VER_AM43xx:
2eea5ae6
TV
633 return OMAP_DSS_CHANNEL_LCD;
634
a2408154
TV
635 case OMAPDSS_VER_DRA7xx:
636 switch (port_num) {
637 case 2:
638 return OMAP_DSS_CHANNEL_LCD3;
639 case 1:
640 return OMAP_DSS_CHANNEL_LCD2;
641 case 0:
642 default:
643 return OMAP_DSS_CHANNEL_LCD;
644 }
645
2eea5ae6
TV
646 case OMAPDSS_VER_OMAP4430_ES1:
647 case OMAPDSS_VER_OMAP4430_ES2:
648 case OMAPDSS_VER_OMAP4:
649 return OMAP_DSS_CHANNEL_LCD2;
650
651 case OMAPDSS_VER_OMAP5:
652 return OMAP_DSS_CHANNEL_LCD3;
653
654 default:
655 DSSWARN("unsupported DSS version\n");
656 return OMAP_DSS_CHANNEL_LCD;
657 }
658}
659
0b24edb1
TV
660static int dpi_connect(struct omap_dss_device *dssdev,
661 struct omap_dss_device *dst)
662{
2ac6a1aa 663 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
a070ba6c 664 enum omap_channel channel = dpi->output.dispc_channel;
0b24edb1
TV
665 int r;
666
630d2d0d 667 r = dpi_init_regulator(dpi);
0b24edb1
TV
668 if (r)
669 return r;
670
630d2d0d 671 dpi_init_pll(dpi);
0b24edb1 672
a070ba6c 673 r = dss_mgr_connect(channel, dssdev);
0b24edb1
TV
674 if (r)
675 return r;
676
677 r = omapdss_output_set_device(dssdev, dst);
678 if (r) {
679 DSSERR("failed to connect output to new device: %s\n",
680 dst->name);
a070ba6c 681 dss_mgr_disconnect(channel, dssdev);
0b24edb1
TV
682 return r;
683 }
684
685 return 0;
686}
687
688static void dpi_disconnect(struct omap_dss_device *dssdev,
689 struct omap_dss_device *dst)
690{
a070ba6c
TV
691 struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
692 enum omap_channel channel = dpi->output.dispc_channel;
693
9560dc10 694 WARN_ON(dst != dssdev->dst);
0b24edb1 695
9560dc10 696 if (dst != dssdev->dst)
0b24edb1
TV
697 return;
698
699 omapdss_output_unset_device(dssdev);
700
a070ba6c 701 dss_mgr_disconnect(channel, dssdev);
0b24edb1
TV
702}
703
704static const struct omapdss_dpi_ops dpi_ops = {
705 .connect = dpi_connect,
706 .disconnect = dpi_disconnect,
707
86a3efe1
TV
708 .enable = dpi_display_enable,
709 .disable = dpi_display_disable,
0b24edb1
TV
710
711 .check_timings = dpi_check_timings,
86a3efe1 712 .set_timings = dpi_set_timings,
0b24edb1
TV
713 .get_timings = dpi_get_timings,
714
86a3efe1 715 .set_data_lines = dpi_set_data_lines,
0b24edb1
TV
716};
717
94cf394b 718static void dpi_init_output(struct platform_device *pdev)
81b87f51 719{
2ac6a1aa 720 struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
630d2d0d 721 struct omap_dss_device *out = &dpi->output;
81b87f51 722
1f68d9c4 723 out->dev = &pdev->dev;
81b87f51 724 out->id = OMAP_DSS_OUTPUT_DPI;
1f68d9c4 725 out->output_type = OMAP_DISPLAY_TYPE_DPI;
7286a08f 726 out->name = "dpi.0";
f7e38fe9 727 out->dispc_channel = dpi_get_channel(0);
0b24edb1 728 out->ops.dpi = &dpi_ops;
b7328e14 729 out->owner = THIS_MODULE;
81b87f51 730
5d47dbc8 731 omapdss_register_output(out);
81b87f51
AT
732}
733
ede92695 734static void dpi_uninit_output(struct platform_device *pdev)
81b87f51 735{
2ac6a1aa 736 struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
630d2d0d 737 struct omap_dss_device *out = &dpi->output;
81b87f51 738
5d47dbc8 739 omapdss_unregister_output(out);
81b87f51
AT
740}
741
80eb6751
AT
742static void dpi_init_output_port(struct platform_device *pdev,
743 struct device_node *port)
744{
745 struct dpi_data *dpi = port->data;
746 struct omap_dss_device *out = &dpi->output;
f7e38fe9
AT
747 int r;
748 u32 port_num;
749
750 r = of_property_read_u32(port, "reg", &port_num);
751 if (r)
752 port_num = 0;
753
754 switch (port_num) {
755 case 2:
756 out->name = "dpi.2";
757 break;
758 case 1:
759 out->name = "dpi.1";
760 break;
761 case 0:
762 default:
763 out->name = "dpi.0";
764 break;
765 }
80eb6751
AT
766
767 out->dev = &pdev->dev;
768 out->id = OMAP_DSS_OUTPUT_DPI;
769 out->output_type = OMAP_DISPLAY_TYPE_DPI;
f7e38fe9
AT
770 out->dispc_channel = dpi_get_channel(port_num);
771 out->port_num = port_num;
80eb6751
AT
772 out->ops.dpi = &dpi_ops;
773 out->owner = THIS_MODULE;
774
775 omapdss_register_output(out);
776}
777
ede92695 778static void dpi_uninit_output_port(struct device_node *port)
80eb6751
AT
779{
780 struct dpi_data *dpi = port->data;
781 struct omap_dss_device *out = &dpi->output;
782
783 omapdss_unregister_output(out);
784}
785
736e60dd 786static int dpi_bind(struct device *dev, struct device *master, void *data)
38f3daf6 787{
736e60dd 788 struct platform_device *pdev = to_platform_device(dev);
2ac6a1aa
AT
789 struct dpi_data *dpi;
790
791 dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
792 if (!dpi)
793 return -ENOMEM;
630d2d0d
AT
794
795 dpi->pdev = pdev;
00df43b8 796
630d2d0d
AT
797 dev_set_drvdata(&pdev->dev, dpi);
798
799 mutex_init(&dpi->lock);
c8a5e4e8 800
81b87f51
AT
801 dpi_init_output(pdev);
802
5f42f2ce
TV
803 return 0;
804}
805
736e60dd 806static void dpi_unbind(struct device *dev, struct device *master, void *data)
553c48cf 807{
736e60dd
TV
808 struct platform_device *pdev = to_platform_device(dev);
809
81b87f51 810 dpi_uninit_output(pdev);
736e60dd
TV
811}
812
813static const struct component_ops dpi_component_ops = {
814 .bind = dpi_bind,
815 .unbind = dpi_unbind,
816};
81b87f51 817
736e60dd
TV
818static int dpi_probe(struct platform_device *pdev)
819{
820 return component_add(&pdev->dev, &dpi_component_ops);
821}
822
823static int dpi_remove(struct platform_device *pdev)
824{
825 component_del(&pdev->dev, &dpi_component_ops);
a57dd4fe 826 return 0;
553c48cf
TV
827}
828
a57dd4fe 829static struct platform_driver omap_dpi_driver = {
736e60dd
TV
830 .probe = dpi_probe,
831 .remove = dpi_remove,
a57dd4fe
TV
832 .driver = {
833 .name = "omapdss_dpi",
422ccbd5 834 .suppress_bind_attrs = true,
a57dd4fe
TV
835 },
836};
837
6e7e8f06 838int __init dpi_init_platform_driver(void)
a57dd4fe 839{
94cf394b 840 return platform_driver_register(&omap_dpi_driver);
a57dd4fe
TV
841}
842
ede92695 843void dpi_uninit_platform_driver(void)
a57dd4fe
TV
844{
845 platform_driver_unregister(&omap_dpi_driver);
846}
2ecef246 847
ede92695 848int dpi_init_port(struct platform_device *pdev, struct device_node *port)
2ecef246 849{
2ac6a1aa 850 struct dpi_data *dpi;
2ecef246
TV
851 struct device_node *ep;
852 u32 datalines;
853 int r;
854
2ac6a1aa
AT
855 dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
856 if (!dpi)
857 return -ENOMEM;
858
2ecef246
TV
859 ep = omapdss_of_get_next_endpoint(port, NULL);
860 if (!ep)
861 return 0;
862
863 r = of_property_read_u32(ep, "data-lines", &datalines);
864 if (r) {
865 DSSERR("failed to parse datalines\n");
866 goto err_datalines;
867 }
868
630d2d0d 869 dpi->data_lines = datalines;
2ecef246
TV
870
871 of_node_put(ep);
872
630d2d0d 873 dpi->pdev = pdev;
80eb6751 874 port->data = dpi;
2ecef246 875
630d2d0d 876 mutex_init(&dpi->lock);
2ecef246 877
80eb6751 878 dpi_init_output_port(pdev, port);
2ecef246 879
630d2d0d 880 dpi->port_initialized = true;
2ecef246
TV
881
882 return 0;
883
884err_datalines:
885 of_node_put(ep);
886
887 return r;
888}
889
ede92695 890void dpi_uninit_port(struct device_node *port)
2ecef246 891{
80eb6751 892 struct dpi_data *dpi = port->data;
630d2d0d
AT
893
894 if (!dpi->port_initialized)
2ecef246
TV
895 return;
896
80eb6751 897 dpi_uninit_output_port(port);
2ecef246 898}