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>
26#include <linux/delay.h>
27#include <linux/export.h>
28#include <linux/err.h>
29#include <linux/errno.h>
30#include <linux/platform_device.h>
31#include <linux/regulator/consumer.h>
32#include <linux/string.h>
33#include <linux/of.h>
34
35#include <video/omapdss.h>
36
37#include "dss.h"
38#include "dss_features.h"
39
40static struct {
41	struct platform_device *pdev;
42
43	struct regulator *vdds_dsi_reg;
44	struct platform_device *dsidev;
45
46	struct mutex lock;
47
48	struct omap_video_timings timings;
49	struct dss_lcd_mgr_config mgr_config;
50	int data_lines;
51
52	struct omap_dss_device output;
53
54	bool port_initialized;
55} dpi;
56
57static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
58{
59	/*
60	 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
61	 * would also be used for DISPC fclk. Meaning, when the DPI output is
62	 * disabled, DISPC clock will be disabled, and TV out will stop.
63	 */
64	switch (omapdss_get_version()) {
65	case OMAPDSS_VER_OMAP24xx:
66	case OMAPDSS_VER_OMAP34xx_ES1:
67	case OMAPDSS_VER_OMAP34xx_ES3:
68	case OMAPDSS_VER_OMAP3630:
69	case OMAPDSS_VER_AM35xx:
70	case OMAPDSS_VER_AM43xx:
71		return NULL;
72
73	case OMAPDSS_VER_OMAP4430_ES1:
74	case OMAPDSS_VER_OMAP4430_ES2:
75	case OMAPDSS_VER_OMAP4:
76		switch (channel) {
77		case OMAP_DSS_CHANNEL_LCD:
78			return dsi_get_dsidev_from_id(0);
79		case OMAP_DSS_CHANNEL_LCD2:
80			return dsi_get_dsidev_from_id(1);
81		default:
82			return NULL;
83		}
84
85	case OMAPDSS_VER_OMAP5:
86		switch (channel) {
87		case OMAP_DSS_CHANNEL_LCD:
88			return dsi_get_dsidev_from_id(0);
89		case OMAP_DSS_CHANNEL_LCD3:
90			return dsi_get_dsidev_from_id(1);
91		default:
92			return NULL;
93		}
94
95	default:
96		return NULL;
97	}
98}
99
100static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
101{
102	switch (channel) {
103	case OMAP_DSS_CHANNEL_LCD:
104		return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
105	case OMAP_DSS_CHANNEL_LCD2:
106		return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
107	case OMAP_DSS_CHANNEL_LCD3:
108		return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
109	default:
110		/* this shouldn't happen */
111		WARN_ON(1);
112		return OMAP_DSS_CLK_SRC_FCK;
113	}
114}
115
116struct dpi_clk_calc_ctx {
117	struct platform_device *dsidev;
118
119	/* inputs */
120
121	unsigned long pck_min, pck_max;
122
123	/* outputs */
124
125	struct dsi_clock_info dsi_cinfo;
126	unsigned long fck;
127	struct dispc_clock_info dispc_cinfo;
128};
129
130static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
131		unsigned long pck, void *data)
132{
133	struct dpi_clk_calc_ctx *ctx = data;
134
135	/*
136	 * Odd dividers give us uneven duty cycle, causing problem when level
137	 * shifted. So skip all odd dividers when the pixel clock is on the
138	 * higher side.
139	 */
140	if (ctx->pck_min >= 100000000) {
141		if (lckd > 1 && lckd % 2 != 0)
142			return false;
143
144		if (pckd > 1 && pckd % 2 != 0)
145			return false;
146	}
147
148	ctx->dispc_cinfo.lck_div = lckd;
149	ctx->dispc_cinfo.pck_div = pckd;
150	ctx->dispc_cinfo.lck = lck;
151	ctx->dispc_cinfo.pck = pck;
152
153	return true;
154}
155
156
157static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
158		void *data)
159{
160	struct dpi_clk_calc_ctx *ctx = data;
161
162	/*
163	 * Odd dividers give us uneven duty cycle, causing problem when level
164	 * shifted. So skip all odd dividers when the pixel clock is on the
165	 * higher side.
166	 */
167	if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000)
168		return false;
169
170	ctx->dsi_cinfo.regm_dispc = regm_dispc;
171	ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
172
173	return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
174			dpi_calc_dispc_cb, ctx);
175}
176
177
178static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
179		unsigned long pll,
180		void *data)
181{
182	struct dpi_clk_calc_ctx *ctx = data;
183
184	ctx->dsi_cinfo.regn = regn;
185	ctx->dsi_cinfo.regm = regm;
186	ctx->dsi_cinfo.fint = fint;
187	ctx->dsi_cinfo.clkin4ddr = pll;
188
189	return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
190			dpi_calc_hsdiv_cb, ctx);
191}
192
193static bool dpi_calc_dss_cb(unsigned long fck, void *data)
194{
195	struct dpi_clk_calc_ctx *ctx = data;
196
197	ctx->fck = fck;
198
199	return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
200			dpi_calc_dispc_cb, ctx);
201}
202
203static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
204{
205	unsigned long clkin;
206	unsigned long pll_min, pll_max;
207
208	clkin = dsi_get_pll_clkin(dpi.dsidev);
209
210	memset(ctx, 0, sizeof(*ctx));
211	ctx->dsidev = dpi.dsidev;
212	ctx->pck_min = pck - 1000;
213	ctx->pck_max = pck + 1000;
214	ctx->dsi_cinfo.clkin = clkin;
215
216	pll_min = 0;
217	pll_max = 0;
218
219	return dsi_pll_calc(dpi.dsidev, clkin,
220			pll_min, pll_max,
221			dpi_calc_pll_cb, ctx);
222}
223
224static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
225{
226	int i;
227
228	/*
229	 * DSS fck gives us very few possibilities, so finding a good pixel
230	 * clock may not be possible. We try multiple times to find the clock,
231	 * each time widening the pixel clock range we look for, up to
232	 * +/- ~15MHz.
233	 */
234
235	for (i = 0; i < 25; ++i) {
236		bool ok;
237
238		memset(ctx, 0, sizeof(*ctx));
239		if (pck > 1000 * i * i * i)
240			ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
241		else
242			ctx->pck_min = 0;
243		ctx->pck_max = pck + 1000 * i * i * i;
244
245		ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx);
246		if (ok)
247			return ok;
248	}
249
250	return false;
251}
252
253
254
255static int dpi_set_dsi_clk(enum omap_channel channel,
256		unsigned long pck_req, unsigned long *fck, int *lck_div,
257		int *pck_div)
258{
259	struct dpi_clk_calc_ctx ctx;
260	int r;
261	bool ok;
262
263	ok = dpi_dsi_clk_calc(pck_req, &ctx);
264	if (!ok)
265		return -EINVAL;
266
267	r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
268	if (r)
269		return r;
270
271	dss_select_lcd_clk_source(channel,
272			dpi_get_alt_clk_src(channel));
273
274	dpi.mgr_config.clock_info = ctx.dispc_cinfo;
275
276	*fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
277	*lck_div = ctx.dispc_cinfo.lck_div;
278	*pck_div = ctx.dispc_cinfo.pck_div;
279
280	return 0;
281}
282
283static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
284		int *lck_div, int *pck_div)
285{
286	struct dpi_clk_calc_ctx ctx;
287	int r;
288	bool ok;
289
290	ok = dpi_dss_clk_calc(pck_req, &ctx);
291	if (!ok)
292		return -EINVAL;
293
294	r = dss_set_fck_rate(ctx.fck);
295	if (r)
296		return r;
297
298	dpi.mgr_config.clock_info = ctx.dispc_cinfo;
299
300	*fck = ctx.fck;
301	*lck_div = ctx.dispc_cinfo.lck_div;
302	*pck_div = ctx.dispc_cinfo.pck_div;
303
304	return 0;
305}
306
307static int dpi_set_mode(struct omap_overlay_manager *mgr)
308{
309	struct omap_video_timings *t = &dpi.timings;
310	int lck_div = 0, pck_div = 0;
311	unsigned long fck = 0;
312	unsigned long pck;
313	int r = 0;
314
315	if (dpi.dsidev)
316		r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck,
317				&lck_div, &pck_div);
318	else
319		r = dpi_set_dispc_clk(t->pixelclock, &fck,
320				&lck_div, &pck_div);
321	if (r)
322		return r;
323
324	pck = fck / lck_div / pck_div;
325
326	if (pck != t->pixelclock) {
327		DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
328			t->pixelclock, pck);
329
330		t->pixelclock = pck;
331	}
332
333	dss_mgr_set_timings(mgr, t);
334
335	return 0;
336}
337
338static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
339{
340	dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
341
342	dpi.mgr_config.stallmode = false;
343	dpi.mgr_config.fifohandcheck = false;
344
345	dpi.mgr_config.video_port_width = dpi.data_lines;
346
347	dpi.mgr_config.lcden_sig_polarity = 0;
348
349	dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
350}
351
352static int dpi_display_enable(struct omap_dss_device *dssdev)
353{
354	struct omap_dss_device *out = &dpi.output;
355	int r;
356
357	mutex_lock(&dpi.lock);
358
359	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
360		DSSERR("no VDSS_DSI regulator\n");
361		r = -ENODEV;
362		goto err_no_reg;
363	}
364
365	if (out == NULL || out->manager == NULL) {
366		DSSERR("failed to enable display: no output/manager\n");
367		r = -ENODEV;
368		goto err_no_out_mgr;
369	}
370
371	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
372		r = regulator_enable(dpi.vdds_dsi_reg);
373		if (r)
374			goto err_reg_enable;
375	}
376
377	r = dispc_runtime_get();
378	if (r)
379		goto err_get_dispc;
380
381	r = dss_dpi_select_source(out->manager->id);
382	if (r)
383		goto err_src_sel;
384
385	if (dpi.dsidev) {
386		r = dsi_runtime_get(dpi.dsidev);
387		if (r)
388			goto err_get_dsi;
389
390		r = dsi_pll_init(dpi.dsidev, 0, 1);
391		if (r)
392			goto err_dsi_pll_init;
393	}
394
395	r = dpi_set_mode(out->manager);
396	if (r)
397		goto err_set_mode;
398
399	dpi_config_lcd_manager(out->manager);
400
401	mdelay(2);
402
403	r = dss_mgr_enable(out->manager);
404	if (r)
405		goto err_mgr_enable;
406
407	mutex_unlock(&dpi.lock);
408
409	return 0;
410
411err_mgr_enable:
412err_set_mode:
413	if (dpi.dsidev)
414		dsi_pll_uninit(dpi.dsidev, true);
415err_dsi_pll_init:
416	if (dpi.dsidev)
417		dsi_runtime_put(dpi.dsidev);
418err_get_dsi:
419err_src_sel:
420	dispc_runtime_put();
421err_get_dispc:
422	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
423		regulator_disable(dpi.vdds_dsi_reg);
424err_reg_enable:
425err_no_out_mgr:
426err_no_reg:
427	mutex_unlock(&dpi.lock);
428	return r;
429}
430
431static void dpi_display_disable(struct omap_dss_device *dssdev)
432{
433	struct omap_overlay_manager *mgr = dpi.output.manager;
434
435	mutex_lock(&dpi.lock);
436
437	dss_mgr_disable(mgr);
438
439	if (dpi.dsidev) {
440		dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
441		dsi_pll_uninit(dpi.dsidev, true);
442		dsi_runtime_put(dpi.dsidev);
443	}
444
445	dispc_runtime_put();
446
447	if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
448		regulator_disable(dpi.vdds_dsi_reg);
449
450	mutex_unlock(&dpi.lock);
451}
452
453static void dpi_set_timings(struct omap_dss_device *dssdev,
454		struct omap_video_timings *timings)
455{
456	DSSDBG("dpi_set_timings\n");
457
458	mutex_lock(&dpi.lock);
459
460	dpi.timings = *timings;
461
462	mutex_unlock(&dpi.lock);
463}
464
465static void dpi_get_timings(struct omap_dss_device *dssdev,
466		struct omap_video_timings *timings)
467{
468	mutex_lock(&dpi.lock);
469
470	*timings = dpi.timings;
471
472	mutex_unlock(&dpi.lock);
473}
474
475static int dpi_check_timings(struct omap_dss_device *dssdev,
476			struct omap_video_timings *timings)
477{
478	struct omap_overlay_manager *mgr = dpi.output.manager;
479	int lck_div, pck_div;
480	unsigned long fck;
481	unsigned long pck;
482	struct dpi_clk_calc_ctx ctx;
483	bool ok;
484
485	if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
486		return -EINVAL;
487
488	if (timings->pixelclock == 0)
489		return -EINVAL;
490
491	if (dpi.dsidev) {
492		ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx);
493		if (!ok)
494			return -EINVAL;
495
496		fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
497	} else {
498		ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
499		if (!ok)
500			return -EINVAL;
501
502		fck = ctx.fck;
503	}
504
505	lck_div = ctx.dispc_cinfo.lck_div;
506	pck_div = ctx.dispc_cinfo.pck_div;
507
508	pck = fck / lck_div / pck_div;
509
510	timings->pixelclock = pck;
511
512	return 0;
513}
514
515static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
516{
517	mutex_lock(&dpi.lock);
518
519	dpi.data_lines = data_lines;
520
521	mutex_unlock(&dpi.lock);
522}
523
524static int dpi_verify_dsi_pll(struct platform_device *dsidev)
525{
526	int r;
527
528	/* do initial setup with the PLL to see if it is operational */
529
530	r = dsi_runtime_get(dsidev);
531	if (r)
532		return r;
533
534	r = dsi_pll_init(dsidev, 0, 1);
535	if (r) {
536		dsi_runtime_put(dsidev);
537		return r;
538	}
539
540	dsi_pll_uninit(dsidev, true);
541	dsi_runtime_put(dsidev);
542
543	return 0;
544}
545
546static int dpi_init_regulator(void)
547{
548	struct regulator *vdds_dsi;
549
550	if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
551		return 0;
552
553	if (dpi.vdds_dsi_reg)
554		return 0;
555
556	vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi");
557	if (IS_ERR(vdds_dsi)) {
558		if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
559			DSSERR("can't get VDDS_DSI regulator\n");
560		return PTR_ERR(vdds_dsi);
561	}
562
563	dpi.vdds_dsi_reg = vdds_dsi;
564
565	return 0;
566}
567
568static void dpi_init_pll(void)
569{
570	struct platform_device *dsidev;
571
572	if (dpi.dsidev)
573		return;
574
575	dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
576	if (!dsidev)
577		return;
578
579	if (dpi_verify_dsi_pll(dsidev)) {
580		DSSWARN("DSI PLL not operational\n");
581		return;
582	}
583
584	dpi.dsidev = dsidev;
585}
586
587/*
588 * Return a hardcoded channel for the DPI output. This should work for
589 * current use cases, but this can be later expanded to either resolve
590 * the channel in some more dynamic manner, or get the channel as a user
591 * parameter.
592 */
593static enum omap_channel dpi_get_channel(void)
594{
595	switch (omapdss_get_version()) {
596	case OMAPDSS_VER_OMAP24xx:
597	case OMAPDSS_VER_OMAP34xx_ES1:
598	case OMAPDSS_VER_OMAP34xx_ES3:
599	case OMAPDSS_VER_OMAP3630:
600	case OMAPDSS_VER_AM35xx:
601	case OMAPDSS_VER_AM43xx:
602		return OMAP_DSS_CHANNEL_LCD;
603
604	case OMAPDSS_VER_OMAP4430_ES1:
605	case OMAPDSS_VER_OMAP4430_ES2:
606	case OMAPDSS_VER_OMAP4:
607		return OMAP_DSS_CHANNEL_LCD2;
608
609	case OMAPDSS_VER_OMAP5:
610		return OMAP_DSS_CHANNEL_LCD3;
611
612	default:
613		DSSWARN("unsupported DSS version\n");
614		return OMAP_DSS_CHANNEL_LCD;
615	}
616}
617
618static int dpi_connect(struct omap_dss_device *dssdev,
619		struct omap_dss_device *dst)
620{
621	struct omap_overlay_manager *mgr;
622	int r;
623
624	r = dpi_init_regulator();
625	if (r)
626		return r;
627
628	dpi_init_pll();
629
630	mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
631	if (!mgr)
632		return -ENODEV;
633
634	r = dss_mgr_connect(mgr, dssdev);
635	if (r)
636		return r;
637
638	r = omapdss_output_set_device(dssdev, dst);
639	if (r) {
640		DSSERR("failed to connect output to new device: %s\n",
641				dst->name);
642		dss_mgr_disconnect(mgr, dssdev);
643		return r;
644	}
645
646	return 0;
647}
648
649static void dpi_disconnect(struct omap_dss_device *dssdev,
650		struct omap_dss_device *dst)
651{
652	WARN_ON(dst != dssdev->dst);
653
654	if (dst != dssdev->dst)
655		return;
656
657	omapdss_output_unset_device(dssdev);
658
659	if (dssdev->manager)
660		dss_mgr_disconnect(dssdev->manager, dssdev);
661}
662
663static const struct omapdss_dpi_ops dpi_ops = {
664	.connect = dpi_connect,
665	.disconnect = dpi_disconnect,
666
667	.enable = dpi_display_enable,
668	.disable = dpi_display_disable,
669
670	.check_timings = dpi_check_timings,
671	.set_timings = dpi_set_timings,
672	.get_timings = dpi_get_timings,
673
674	.set_data_lines = dpi_set_data_lines,
675};
676
677static void dpi_init_output(struct platform_device *pdev)
678{
679	struct omap_dss_device *out = &dpi.output;
680
681	out->dev = &pdev->dev;
682	out->id = OMAP_DSS_OUTPUT_DPI;
683	out->output_type = OMAP_DISPLAY_TYPE_DPI;
684	out->name = "dpi.0";
685	out->dispc_channel = dpi_get_channel();
686	out->ops.dpi = &dpi_ops;
687	out->owner = THIS_MODULE;
688
689	omapdss_register_output(out);
690}
691
692static void __exit dpi_uninit_output(struct platform_device *pdev)
693{
694	struct omap_dss_device *out = &dpi.output;
695
696	omapdss_unregister_output(out);
697}
698
699static int omap_dpi_probe(struct platform_device *pdev)
700{
701	dpi.pdev = pdev;
702
703	mutex_init(&dpi.lock);
704
705	dpi_init_output(pdev);
706
707	return 0;
708}
709
710static int __exit omap_dpi_remove(struct platform_device *pdev)
711{
712	dpi_uninit_output(pdev);
713
714	return 0;
715}
716
717static struct platform_driver omap_dpi_driver = {
718	.probe		= omap_dpi_probe,
719	.remove         = __exit_p(omap_dpi_remove),
720	.driver         = {
721		.name   = "omapdss_dpi",
722		.owner  = THIS_MODULE,
723		.suppress_bind_attrs = true,
724	},
725};
726
727int __init dpi_init_platform_driver(void)
728{
729	return platform_driver_register(&omap_dpi_driver);
730}
731
732void __exit dpi_uninit_platform_driver(void)
733{
734	platform_driver_unregister(&omap_dpi_driver);
735}
736
737int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
738{
739	struct device_node *ep;
740	u32 datalines;
741	int r;
742
743	ep = omapdss_of_get_next_endpoint(port, NULL);
744	if (!ep)
745		return 0;
746
747	r = of_property_read_u32(ep, "data-lines", &datalines);
748	if (r) {
749		DSSERR("failed to parse datalines\n");
750		goto err_datalines;
751	}
752
753	dpi.data_lines = datalines;
754
755	of_node_put(ep);
756
757	dpi.pdev = pdev;
758
759	mutex_init(&dpi.lock);
760
761	dpi_init_output(pdev);
762
763	dpi.port_initialized = true;
764
765	return 0;
766
767err_datalines:
768	of_node_put(ep);
769
770	return r;
771}
772
773void __exit dpi_uninit_port(void)
774{
775	if (!dpi.port_initialized)
776		return;
777
778	dpi_uninit_output(dpi.pdev);
779}
780