• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2009 Nokia Corporation
4  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
5  */
6 
7 #define DSS_SUBSYS_NAME "SDI"
8 
9 #include <linux/kernel.h>
10 #include <linux/delay.h>
11 #include <linux/err.h>
12 #include <linux/regulator/consumer.h>
13 #include <linux/export.h>
14 #include <linux/platform_device.h>
15 #include <linux/string.h>
16 #include <linux/of.h>
17 
18 #include "omapdss.h"
19 #include "dss.h"
20 
21 struct sdi_device {
22 	struct platform_device *pdev;
23 	struct dss_device *dss;
24 
25 	bool update_enabled;
26 	struct regulator *vdds_sdi_reg;
27 
28 	struct dss_lcd_mgr_config mgr_config;
29 	unsigned long pixelclock;
30 	int datapairs;
31 
32 	struct omap_dss_device output;
33 };
34 
35 #define dssdev_to_sdi(dssdev) container_of(dssdev, struct sdi_device, output)
36 
37 struct sdi_clk_calc_ctx {
38 	struct sdi_device *sdi;
39 	unsigned long pck_min, pck_max;
40 
41 	unsigned long fck;
42 	struct dispc_clock_info dispc_cinfo;
43 };
44 
dpi_calc_dispc_cb(int lckd,int pckd,unsigned long lck,unsigned long pck,void * data)45 static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
46 		unsigned long pck, void *data)
47 {
48 	struct sdi_clk_calc_ctx *ctx = data;
49 
50 	ctx->dispc_cinfo.lck_div = lckd;
51 	ctx->dispc_cinfo.pck_div = pckd;
52 	ctx->dispc_cinfo.lck = lck;
53 	ctx->dispc_cinfo.pck = pck;
54 
55 	return true;
56 }
57 
dpi_calc_dss_cb(unsigned long fck,void * data)58 static bool dpi_calc_dss_cb(unsigned long fck, void *data)
59 {
60 	struct sdi_clk_calc_ctx *ctx = data;
61 
62 	ctx->fck = fck;
63 
64 	return dispc_div_calc(ctx->sdi->dss->dispc, fck,
65 			      ctx->pck_min, ctx->pck_max,
66 			      dpi_calc_dispc_cb, ctx);
67 }
68 
sdi_calc_clock_div(struct sdi_device * sdi,unsigned long pclk,unsigned long * fck,struct dispc_clock_info * dispc_cinfo)69 static int sdi_calc_clock_div(struct sdi_device *sdi, unsigned long pclk,
70 			      unsigned long *fck,
71 			      struct dispc_clock_info *dispc_cinfo)
72 {
73 	int i;
74 	struct sdi_clk_calc_ctx ctx;
75 
76 	/*
77 	 * DSS fclk gives us very few possibilities, so finding a good pixel
78 	 * clock may not be possible. We try multiple times to find the clock,
79 	 * each time widening the pixel clock range we look for, up to
80 	 * +/- 1MHz.
81 	 */
82 
83 	for (i = 0; i < 10; ++i) {
84 		bool ok;
85 
86 		memset(&ctx, 0, sizeof(ctx));
87 
88 		ctx.sdi = sdi;
89 
90 		if (pclk > 1000 * i * i * i)
91 			ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
92 		else
93 			ctx.pck_min = 0;
94 		ctx.pck_max = pclk + 1000 * i * i * i;
95 
96 		ok = dss_div_calc(sdi->dss, pclk, ctx.pck_min,
97 				  dpi_calc_dss_cb, &ctx);
98 		if (ok) {
99 			*fck = ctx.fck;
100 			*dispc_cinfo = ctx.dispc_cinfo;
101 			return 0;
102 		}
103 	}
104 
105 	return -EINVAL;
106 }
107 
sdi_config_lcd_manager(struct sdi_device * sdi)108 static void sdi_config_lcd_manager(struct sdi_device *sdi)
109 {
110 	sdi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
111 
112 	sdi->mgr_config.stallmode = false;
113 	sdi->mgr_config.fifohandcheck = false;
114 
115 	sdi->mgr_config.video_port_width = 24;
116 	sdi->mgr_config.lcden_sig_polarity = 1;
117 
118 	dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config);
119 }
120 
sdi_display_enable(struct omap_dss_device * dssdev)121 static void sdi_display_enable(struct omap_dss_device *dssdev)
122 {
123 	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
124 	struct dispc_clock_info dispc_cinfo;
125 	unsigned long fck;
126 	int r;
127 
128 	r = regulator_enable(sdi->vdds_sdi_reg);
129 	if (r)
130 		return;
131 
132 	r = dispc_runtime_get(sdi->dss->dispc);
133 	if (r)
134 		goto err_get_dispc;
135 
136 	r = sdi_calc_clock_div(sdi, sdi->pixelclock, &fck, &dispc_cinfo);
137 	if (r)
138 		goto err_calc_clock_div;
139 
140 	sdi->mgr_config.clock_info = dispc_cinfo;
141 
142 	r = dss_set_fck_rate(sdi->dss, fck);
143 	if (r)
144 		goto err_set_dss_clock_div;
145 
146 	sdi_config_lcd_manager(sdi);
147 
148 	/*
149 	 * LCLK and PCLK divisors are located in shadow registers, and we
150 	 * normally write them to DISPC registers when enabling the output.
151 	 * However, SDI uses pck-free as source clock for its PLL, and pck-free
152 	 * is affected by the divisors. And as we need the PLL before enabling
153 	 * the output, we need to write the divisors early.
154 	 *
155 	 * It seems just writing to the DISPC register is enough, and we don't
156 	 * need to care about the shadow register mechanism for pck-free. The
157 	 * exact reason for this is unknown.
158 	 */
159 	dispc_mgr_set_clock_div(sdi->dss->dispc, sdi->output.dispc_channel,
160 				&sdi->mgr_config.clock_info);
161 
162 	dss_sdi_init(sdi->dss, sdi->datapairs);
163 	r = dss_sdi_enable(sdi->dss);
164 	if (r)
165 		goto err_sdi_enable;
166 	mdelay(2);
167 
168 	r = dss_mgr_enable(&sdi->output);
169 	if (r)
170 		goto err_mgr_enable;
171 
172 	return;
173 
174 err_mgr_enable:
175 	dss_sdi_disable(sdi->dss);
176 err_sdi_enable:
177 err_set_dss_clock_div:
178 err_calc_clock_div:
179 	dispc_runtime_put(sdi->dss->dispc);
180 err_get_dispc:
181 	regulator_disable(sdi->vdds_sdi_reg);
182 }
183 
sdi_display_disable(struct omap_dss_device * dssdev)184 static void sdi_display_disable(struct omap_dss_device *dssdev)
185 {
186 	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
187 
188 	dss_mgr_disable(&sdi->output);
189 
190 	dss_sdi_disable(sdi->dss);
191 
192 	dispc_runtime_put(sdi->dss->dispc);
193 
194 	regulator_disable(sdi->vdds_sdi_reg);
195 }
196 
sdi_set_timings(struct omap_dss_device * dssdev,const struct drm_display_mode * mode)197 static void sdi_set_timings(struct omap_dss_device *dssdev,
198 			    const struct drm_display_mode *mode)
199 {
200 	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
201 
202 	sdi->pixelclock = mode->clock * 1000;
203 }
204 
sdi_check_timings(struct omap_dss_device * dssdev,struct drm_display_mode * mode)205 static int sdi_check_timings(struct omap_dss_device *dssdev,
206 			     struct drm_display_mode *mode)
207 {
208 	struct sdi_device *sdi = dssdev_to_sdi(dssdev);
209 	struct dispc_clock_info dispc_cinfo;
210 	unsigned long pixelclock = mode->clock * 1000;
211 	unsigned long fck;
212 	unsigned long pck;
213 	int r;
214 
215 	if (pixelclock == 0)
216 		return -EINVAL;
217 
218 	r = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);
219 	if (r)
220 		return r;
221 
222 	pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
223 
224 	if (pck != pixelclock) {
225 		DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n",
226 			pixelclock, pck);
227 
228 		mode->clock = pck / 1000;
229 	}
230 
231 	return 0;
232 }
233 
sdi_connect(struct omap_dss_device * src,struct omap_dss_device * dst)234 static int sdi_connect(struct omap_dss_device *src,
235 		       struct omap_dss_device *dst)
236 {
237 	return omapdss_device_connect(dst->dss, dst, dst->next);
238 }
239 
sdi_disconnect(struct omap_dss_device * src,struct omap_dss_device * dst)240 static void sdi_disconnect(struct omap_dss_device *src,
241 			   struct omap_dss_device *dst)
242 {
243 	omapdss_device_disconnect(dst, dst->next);
244 }
245 
246 static const struct omap_dss_device_ops sdi_ops = {
247 	.connect = sdi_connect,
248 	.disconnect = sdi_disconnect,
249 
250 	.enable = sdi_display_enable,
251 	.disable = sdi_display_disable,
252 
253 	.check_timings = sdi_check_timings,
254 	.set_timings = sdi_set_timings,
255 };
256 
sdi_init_output(struct sdi_device * sdi)257 static int sdi_init_output(struct sdi_device *sdi)
258 {
259 	struct omap_dss_device *out = &sdi->output;
260 	int r;
261 
262 	out->dev = &sdi->pdev->dev;
263 	out->id = OMAP_DSS_OUTPUT_SDI;
264 	out->type = OMAP_DISPLAY_TYPE_SDI;
265 	out->name = "sdi.0";
266 	out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
267 	/* We have SDI only on OMAP3, where it's on port 1 */
268 	out->of_ports = BIT(1);
269 	out->ops = &sdi_ops;
270 	out->owner = THIS_MODULE;
271 	out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE	/* 15.5.9.1.2 */
272 		       | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
273 
274 	r = omapdss_device_init_output(out);
275 	if (r < 0)
276 		return r;
277 
278 	omapdss_device_register(out);
279 
280 	return 0;
281 }
282 
sdi_uninit_output(struct sdi_device * sdi)283 static void sdi_uninit_output(struct sdi_device *sdi)
284 {
285 	omapdss_device_unregister(&sdi->output);
286 	omapdss_device_cleanup_output(&sdi->output);
287 }
288 
sdi_init_port(struct dss_device * dss,struct platform_device * pdev,struct device_node * port)289 int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,
290 		  struct device_node *port)
291 {
292 	struct sdi_device *sdi;
293 	struct device_node *ep;
294 	u32 datapairs;
295 	int r;
296 
297 	sdi = kzalloc(sizeof(*sdi), GFP_KERNEL);
298 	if (!sdi)
299 		return -ENOMEM;
300 
301 	ep = of_get_next_child(port, NULL);
302 	if (!ep) {
303 		r = 0;
304 		goto err_free;
305 	}
306 
307 	r = of_property_read_u32(ep, "datapairs", &datapairs);
308 	of_node_put(ep);
309 	if (r) {
310 		DSSERR("failed to parse datapairs\n");
311 		goto err_free;
312 	}
313 
314 	sdi->datapairs = datapairs;
315 	sdi->dss = dss;
316 
317 	sdi->pdev = pdev;
318 	port->data = sdi;
319 
320 	sdi->vdds_sdi_reg = devm_regulator_get(&pdev->dev, "vdds_sdi");
321 	if (IS_ERR(sdi->vdds_sdi_reg)) {
322 		r = PTR_ERR(sdi->vdds_sdi_reg);
323 		if (r != -EPROBE_DEFER)
324 			DSSERR("can't get VDDS_SDI regulator\n");
325 		goto err_free;
326 	}
327 
328 	r = sdi_init_output(sdi);
329 	if (r)
330 		goto err_free;
331 
332 	return 0;
333 
334 err_free:
335 	kfree(sdi);
336 
337 	return r;
338 }
339 
sdi_uninit_port(struct device_node * port)340 void sdi_uninit_port(struct device_node *port)
341 {
342 	struct sdi_device *sdi = port->data;
343 
344 	if (!sdi)
345 		return;
346 
347 	sdi_uninit_output(sdi);
348 	kfree(sdi);
349 }
350