xref: /linux/drivers/gpu/drm/sti/sti_dvo.c (revision e0bf6c5ca2d3281f231c5f0c9bf145e9513644de)
1 /*
2  * Copyright (C) STMicroelectronics SA 2014
3  * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
4  * License terms:  GNU General Public License (GPL), version 2
5  */
6 
7 #include <linux/clk.h>
8 #include <linux/component.h>
9 #include <linux/module.h>
10 #include <linux/of_gpio.h>
11 #include <linux/platform_device.h>
12 
13 #include <drm/drmP.h>
14 #include <drm/drm_crtc_helper.h>
15 #include <drm/drm_panel.h>
16 
17 #include "sti_awg_utils.h"
18 #include "sti_mixer.h"
19 
20 /* DVO registers */
21 #define DVO_AWG_DIGSYNC_CTRL      0x0000
22 #define DVO_DOF_CFG               0x0004
23 #define DVO_LUT_PROG_LOW          0x0008
24 #define DVO_LUT_PROG_MID          0x000C
25 #define DVO_LUT_PROG_HIGH         0x0010
26 #define DVO_DIGSYNC_INSTR_I       0x0100
27 
28 #define DVO_AWG_CTRL_EN           BIT(0)
29 #define DVO_AWG_FRAME_BASED_SYNC  BIT(2)
30 
31 #define DVO_DOF_EN_LOWBYTE        BIT(0)
32 #define DVO_DOF_EN_MIDBYTE        BIT(1)
33 #define DVO_DOF_EN_HIGHBYTE       BIT(2)
34 #define DVO_DOF_EN                BIT(6)
35 #define DVO_DOF_MOD_COUNT_SHIFT   8
36 
37 #define DVO_LUT_ZERO              0
38 #define DVO_LUT_Y_G               1
39 #define DVO_LUT_Y_G_DEL           2
40 #define DVO_LUT_CB_B              3
41 #define DVO_LUT_CB_B_DEL          4
42 #define DVO_LUT_CR_R              5
43 #define DVO_LUT_CR_R_DEL          6
44 #define DVO_LUT_HOLD              7
45 
46 struct dvo_config {
47 	u32 flags;
48 	u32 lowbyte;
49 	u32 midbyte;
50 	u32 highbyte;
51 	int (*awg_fwgen_fct)(
52 			struct awg_code_generation_params *fw_gen_params,
53 			struct awg_timing *timing);
54 };
55 
56 static struct dvo_config rgb_24bit_de_cfg = {
57 	.flags         = (0L << DVO_DOF_MOD_COUNT_SHIFT),
58 	.lowbyte       = DVO_LUT_CR_R,
59 	.midbyte       = DVO_LUT_Y_G,
60 	.highbyte      = DVO_LUT_CB_B,
61 	.awg_fwgen_fct = sti_awg_generate_code_data_enable_mode,
62 };
63 
64 /**
65  * STI digital video output structure
66  *
67  * @dev: driver device
68  * @drm_dev: pointer to drm device
69  * @mode: current display mode selected
70  * @regs: dvo registers
71  * @clk_pix: pixel clock for dvo
72  * @clk: clock for dvo
73  * @clk_main_parent: dvo parent clock if main path used
74  * @clk_aux_parent: dvo parent clock if aux path used
75  * @panel_node: panel node reference from device tree
76  * @panel: reference to the panel connected to the dvo
77  * @enabled: true if dvo is enabled else false
78  * @encoder: drm_encoder it is bound
79  */
80 struct sti_dvo {
81 	struct device dev;
82 	struct drm_device *drm_dev;
83 	struct drm_display_mode mode;
84 	void __iomem *regs;
85 	struct clk *clk_pix;
86 	struct clk *clk;
87 	struct clk *clk_main_parent;
88 	struct clk *clk_aux_parent;
89 	struct device_node *panel_node;
90 	struct drm_panel *panel;
91 	struct dvo_config *config;
92 	bool enabled;
93 	struct drm_encoder *encoder;
94 	struct drm_bridge *bridge;
95 };
96 
97 struct sti_dvo_connector {
98 	struct drm_connector drm_connector;
99 	struct drm_encoder *encoder;
100 	struct sti_dvo *dvo;
101 };
102 
103 #define to_sti_dvo_connector(x) \
104 	container_of(x, struct sti_dvo_connector, drm_connector)
105 
106 #define BLANKING_LEVEL 16
107 int dvo_awg_generate_code(struct sti_dvo *dvo, u8 *ram_size, u32 *ram_code)
108 {
109 	struct drm_display_mode *mode = &dvo->mode;
110 	struct dvo_config *config = dvo->config;
111 	struct awg_code_generation_params fw_gen_params;
112 	struct awg_timing timing;
113 
114 	fw_gen_params.ram_code = ram_code;
115 	fw_gen_params.instruction_offset = 0;
116 
117 	timing.total_lines = mode->vtotal;
118 	timing.active_lines = mode->vdisplay;
119 	timing.blanking_lines = mode->vsync_start - mode->vdisplay;
120 	timing.trailing_lines = mode->vtotal - mode->vsync_start;
121 	timing.total_pixels = mode->htotal;
122 	timing.active_pixels = mode->hdisplay;
123 	timing.blanking_pixels = mode->hsync_start - mode->hdisplay;
124 	timing.trailing_pixels = mode->htotal - mode->hsync_start;
125 	timing.blanking_level = BLANKING_LEVEL;
126 
127 	if (config->awg_fwgen_fct(&fw_gen_params, &timing)) {
128 		DRM_ERROR("AWG firmware not properly generated\n");
129 		return -EINVAL;
130 	}
131 
132 	*ram_size = fw_gen_params.instruction_offset;
133 
134 	return 0;
135 }
136 
137 /* Configure AWG, writing instructions
138  *
139  * @dvo: pointer to DVO structure
140  * @awg_ram_code: pointer to AWG instructions table
141  * @nb: nb of AWG instructions
142  */
143 static void dvo_awg_configure(struct sti_dvo *dvo, u32 *awg_ram_code, int nb)
144 {
145 	int i;
146 
147 	DRM_DEBUG_DRIVER("\n");
148 
149 	for (i = 0; i < nb; i++)
150 		writel(awg_ram_code[i],
151 		       dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4);
152 	for (i = nb; i < AWG_MAX_INST; i++)
153 		writel(0, dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4);
154 
155 	writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
156 }
157 
158 static void sti_dvo_disable(struct drm_bridge *bridge)
159 {
160 	struct sti_dvo *dvo = bridge->driver_private;
161 
162 	if (!dvo->enabled)
163 		return;
164 
165 	DRM_DEBUG_DRIVER("\n");
166 
167 	if (dvo->config->awg_fwgen_fct)
168 		writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
169 
170 	writel(0x00000000, dvo->regs + DVO_DOF_CFG);
171 
172 	if (dvo->panel)
173 		dvo->panel->funcs->disable(dvo->panel);
174 
175 	/* Disable/unprepare dvo clock */
176 	clk_disable_unprepare(dvo->clk_pix);
177 	clk_disable_unprepare(dvo->clk);
178 
179 	dvo->enabled = false;
180 }
181 
182 static void sti_dvo_pre_enable(struct drm_bridge *bridge)
183 {
184 	struct sti_dvo *dvo = bridge->driver_private;
185 	struct dvo_config *config = dvo->config;
186 	u32 val;
187 
188 	DRM_DEBUG_DRIVER("\n");
189 
190 	if (dvo->enabled)
191 		return;
192 
193 	/* Make sure DVO is disabled */
194 	writel(0x00000000, dvo->regs + DVO_DOF_CFG);
195 	writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
196 
197 	if (config->awg_fwgen_fct) {
198 		u8 nb_instr;
199 		u32 awg_ram_code[AWG_MAX_INST];
200 		/* Configure AWG */
201 		if (!dvo_awg_generate_code(dvo, &nb_instr, awg_ram_code))
202 			dvo_awg_configure(dvo, awg_ram_code, nb_instr);
203 		else
204 			return;
205 	}
206 
207 	/* Prepare/enable clocks */
208 	if (clk_prepare_enable(dvo->clk_pix))
209 		DRM_ERROR("Failed to prepare/enable dvo_pix clk\n");
210 	if (clk_prepare_enable(dvo->clk))
211 		DRM_ERROR("Failed to prepare/enable dvo clk\n");
212 
213 	if (dvo->panel)
214 		dvo->panel->funcs->enable(dvo->panel);
215 
216 	/* Set LUT */
217 	writel(config->lowbyte,  dvo->regs + DVO_LUT_PROG_LOW);
218 	writel(config->midbyte,  dvo->regs + DVO_LUT_PROG_MID);
219 	writel(config->highbyte, dvo->regs + DVO_LUT_PROG_HIGH);
220 
221 	/* Digital output formatter config */
222 	val = (config->flags | DVO_DOF_EN);
223 	writel(val, dvo->regs + DVO_DOF_CFG);
224 
225 	dvo->enabled = true;
226 }
227 
228 static void sti_dvo_set_mode(struct drm_bridge *bridge,
229 			     struct drm_display_mode *mode,
230 			     struct drm_display_mode *adjusted_mode)
231 {
232 	struct sti_dvo *dvo = bridge->driver_private;
233 	struct sti_mixer *mixer = to_sti_mixer(dvo->encoder->crtc);
234 	int rate = mode->clock * 1000;
235 	struct clk *clkp;
236 	int ret;
237 
238 	DRM_DEBUG_DRIVER("\n");
239 
240 	memcpy(&dvo->mode, mode, sizeof(struct drm_display_mode));
241 
242 	/* According to the path used (main or aux), the dvo clocks should
243 	 * have a different parent clock. */
244 	if (mixer->id == STI_MIXER_MAIN)
245 		clkp = dvo->clk_main_parent;
246 	else
247 		clkp = dvo->clk_aux_parent;
248 
249 	if (clkp) {
250 		clk_set_parent(dvo->clk_pix, clkp);
251 		clk_set_parent(dvo->clk, clkp);
252 	}
253 
254 	/* DVO clocks = compositor clock */
255 	ret = clk_set_rate(dvo->clk_pix, rate);
256 	if (ret < 0) {
257 		DRM_ERROR("Cannot set rate (%dHz) for dvo_pix clk\n", rate);
258 		return;
259 	}
260 
261 	ret = clk_set_rate(dvo->clk, rate);
262 	if (ret < 0) {
263 		DRM_ERROR("Cannot set rate (%dHz) for dvo clk\n", rate);
264 		return;
265 	}
266 
267 	/* For now, we only support 24bit data enable (DE) synchro format */
268 	dvo->config = &rgb_24bit_de_cfg;
269 }
270 
271 static void sti_dvo_bridge_nope(struct drm_bridge *bridge)
272 {
273 	/* do nothing */
274 }
275 
276 static const struct drm_bridge_funcs sti_dvo_bridge_funcs = {
277 	.pre_enable = sti_dvo_pre_enable,
278 	.enable = sti_dvo_bridge_nope,
279 	.disable = sti_dvo_disable,
280 	.post_disable = sti_dvo_bridge_nope,
281 	.mode_set = sti_dvo_set_mode,
282 };
283 
284 static int sti_dvo_connector_get_modes(struct drm_connector *connector)
285 {
286 	struct sti_dvo_connector *dvo_connector
287 		= to_sti_dvo_connector(connector);
288 	struct sti_dvo *dvo = dvo_connector->dvo;
289 
290 	if (dvo->panel)
291 		return dvo->panel->funcs->get_modes(dvo->panel);
292 
293 	return 0;
294 }
295 
296 #define CLK_TOLERANCE_HZ 50
297 
298 static int sti_dvo_connector_mode_valid(struct drm_connector *connector,
299 					struct drm_display_mode *mode)
300 {
301 	int target = mode->clock * 1000;
302 	int target_min = target - CLK_TOLERANCE_HZ;
303 	int target_max = target + CLK_TOLERANCE_HZ;
304 	int result;
305 	struct sti_dvo_connector *dvo_connector
306 		= to_sti_dvo_connector(connector);
307 	struct sti_dvo *dvo = dvo_connector->dvo;
308 
309 	result = clk_round_rate(dvo->clk_pix, target);
310 
311 	DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n",
312 			 target, result);
313 
314 	if ((result < target_min) || (result > target_max)) {
315 		DRM_DEBUG_DRIVER("dvo pixclk=%d not supported\n", target);
316 		return MODE_BAD;
317 	}
318 
319 	return MODE_OK;
320 }
321 
322 struct drm_encoder *sti_dvo_best_encoder(struct drm_connector *connector)
323 {
324 	struct sti_dvo_connector *dvo_connector
325 		= to_sti_dvo_connector(connector);
326 
327 	/* Best encoder is the one associated during connector creation */
328 	return dvo_connector->encoder;
329 }
330 
331 static struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = {
332 	.get_modes = sti_dvo_connector_get_modes,
333 	.mode_valid = sti_dvo_connector_mode_valid,
334 	.best_encoder = sti_dvo_best_encoder,
335 };
336 
337 static enum drm_connector_status
338 sti_dvo_connector_detect(struct drm_connector *connector, bool force)
339 {
340 	struct sti_dvo_connector *dvo_connector
341 		= to_sti_dvo_connector(connector);
342 	struct sti_dvo *dvo = dvo_connector->dvo;
343 
344 	DRM_DEBUG_DRIVER("\n");
345 
346 	if (!dvo->panel)
347 		dvo->panel = of_drm_find_panel(dvo->panel_node);
348 
349 	if (dvo->panel)
350 		if (!drm_panel_attach(dvo->panel, connector))
351 			return connector_status_connected;
352 
353 	return connector_status_disconnected;
354 }
355 
356 static void sti_dvo_connector_destroy(struct drm_connector *connector)
357 {
358 	struct sti_dvo_connector *dvo_connector
359 		= to_sti_dvo_connector(connector);
360 
361 	drm_connector_unregister(connector);
362 	drm_connector_cleanup(connector);
363 	kfree(dvo_connector);
364 }
365 
366 static struct drm_connector_funcs sti_dvo_connector_funcs = {
367 	.dpms = drm_helper_connector_dpms,
368 	.fill_modes = drm_helper_probe_single_connector_modes,
369 	.detect = sti_dvo_connector_detect,
370 	.destroy = sti_dvo_connector_destroy,
371 };
372 
373 static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev)
374 {
375 	struct drm_encoder *encoder;
376 
377 	list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
378 		if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
379 			return encoder;
380 	}
381 
382 	return NULL;
383 }
384 
385 static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
386 {
387 	struct sti_dvo *dvo = dev_get_drvdata(dev);
388 	struct drm_device *drm_dev = data;
389 	struct drm_encoder *encoder;
390 	struct sti_dvo_connector *connector;
391 	struct drm_connector *drm_connector;
392 	struct drm_bridge *bridge;
393 	int err;
394 
395 	/* Set the drm device handle */
396 	dvo->drm_dev = drm_dev;
397 
398 	encoder = sti_dvo_find_encoder(drm_dev);
399 	if (!encoder)
400 		return -ENOMEM;
401 
402 	connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
403 	if (!connector)
404 		return -ENOMEM;
405 
406 	connector->dvo = dvo;
407 
408 	bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
409 	if (!bridge)
410 		return -ENOMEM;
411 
412 	bridge->driver_private = dvo;
413 	bridge->funcs = &sti_dvo_bridge_funcs;
414 	bridge->of_node = dvo->dev.of_node;
415 	err = drm_bridge_add(bridge);
416 	if (err) {
417 		DRM_ERROR("Failed to add bridge\n");
418 		return err;
419 	}
420 
421 	err = drm_bridge_attach(drm_dev, bridge);
422 	if (err) {
423 		DRM_ERROR("Failed to attach bridge\n");
424 		return err;
425 	}
426 
427 	dvo->bridge = bridge;
428 	encoder->bridge = bridge;
429 	connector->encoder = encoder;
430 	dvo->encoder = encoder;
431 
432 	drm_connector = (struct drm_connector *)connector;
433 
434 	drm_connector->polled = DRM_CONNECTOR_POLL_HPD;
435 
436 	drm_connector_init(drm_dev, drm_connector,
437 			   &sti_dvo_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
438 	drm_connector_helper_add(drm_connector,
439 				 &sti_dvo_connector_helper_funcs);
440 
441 	err = drm_connector_register(drm_connector);
442 	if (err)
443 		goto err_connector;
444 
445 	err = drm_mode_connector_attach_encoder(drm_connector, encoder);
446 	if (err) {
447 		DRM_ERROR("Failed to attach a connector to a encoder\n");
448 		goto err_sysfs;
449 	}
450 
451 	return 0;
452 
453 err_sysfs:
454 	drm_connector_unregister(drm_connector);
455 err_connector:
456 	drm_bridge_remove(bridge);
457 	drm_connector_cleanup(drm_connector);
458 	return -EINVAL;
459 }
460 
461 static void sti_dvo_unbind(struct device *dev,
462 			   struct device *master, void *data)
463 {
464 	struct sti_dvo *dvo = dev_get_drvdata(dev);
465 
466 	drm_bridge_remove(dvo->bridge);
467 }
468 
469 static const struct component_ops sti_dvo_ops = {
470 	.bind = sti_dvo_bind,
471 	.unbind = sti_dvo_unbind,
472 };
473 
474 static int sti_dvo_probe(struct platform_device *pdev)
475 {
476 	struct device *dev = &pdev->dev;
477 	struct sti_dvo *dvo;
478 	struct resource *res;
479 	struct device_node *np = dev->of_node;
480 
481 	DRM_INFO("%s\n", __func__);
482 
483 	dvo = devm_kzalloc(dev, sizeof(*dvo), GFP_KERNEL);
484 	if (!dvo) {
485 		DRM_ERROR("Failed to allocate memory for DVO\n");
486 		return -ENOMEM;
487 	}
488 
489 	dvo->dev = pdev->dev;
490 
491 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvo-reg");
492 	if (!res) {
493 		DRM_ERROR("Invalid dvo resource\n");
494 		return -ENOMEM;
495 	}
496 	dvo->regs = devm_ioremap_nocache(dev, res->start,
497 			resource_size(res));
498 	if (IS_ERR(dvo->regs))
499 		return PTR_ERR(dvo->regs);
500 
501 	dvo->clk_pix = devm_clk_get(dev, "dvo_pix");
502 	if (IS_ERR(dvo->clk_pix)) {
503 		DRM_ERROR("Cannot get dvo_pix clock\n");
504 		return PTR_ERR(dvo->clk_pix);
505 	}
506 
507 	dvo->clk = devm_clk_get(dev, "dvo");
508 	if (IS_ERR(dvo->clk)) {
509 		DRM_ERROR("Cannot get dvo clock\n");
510 		return PTR_ERR(dvo->clk);
511 	}
512 
513 	dvo->clk_main_parent = devm_clk_get(dev, "main_parent");
514 	if (IS_ERR(dvo->clk_main_parent)) {
515 		DRM_DEBUG_DRIVER("Cannot get main_parent clock\n");
516 		dvo->clk_main_parent = NULL;
517 	}
518 
519 	dvo->clk_aux_parent = devm_clk_get(dev, "aux_parent");
520 	if (IS_ERR(dvo->clk_aux_parent)) {
521 		DRM_DEBUG_DRIVER("Cannot get aux_parent clock\n");
522 		dvo->clk_aux_parent = NULL;
523 	}
524 
525 	dvo->panel_node = of_parse_phandle(np, "sti,panel", 0);
526 	if (!dvo->panel_node)
527 		DRM_ERROR("No panel associated to the dvo output\n");
528 
529 	platform_set_drvdata(pdev, dvo);
530 
531 	return component_add(&pdev->dev, &sti_dvo_ops);
532 }
533 
534 static int sti_dvo_remove(struct platform_device *pdev)
535 {
536 	component_del(&pdev->dev, &sti_dvo_ops);
537 	return 0;
538 }
539 
540 static struct of_device_id dvo_of_match[] = {
541 	{ .compatible = "st,stih407-dvo", },
542 	{ /* end node */ }
543 };
544 MODULE_DEVICE_TABLE(of, dvo_of_match);
545 
546 struct platform_driver sti_dvo_driver = {
547 	.driver = {
548 		.name = "sti-dvo",
549 		.owner = THIS_MODULE,
550 		.of_match_table = dvo_of_match,
551 	},
552 	.probe = sti_dvo_probe,
553 	.remove = sti_dvo_remove,
554 };
555 
556 module_platform_driver(sti_dvo_driver);
557 
558 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
559 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
560 MODULE_LICENSE("GPL");
561