xref: /openbmc/linux/drivers/gpu/drm/sti/sti_vtg.c (revision 7f2d479c)
1 /*
2  * Copyright (C) STMicroelectronics SA 2014
3  * Authors: Benjamin Gaignard <benjamin.gaignard@st.com>
4  *          Fabien Dessenne <fabien.dessenne@st.com>
5  *          Vincent Abriou <vincent.abriou@st.com>
6  *          for STMicroelectronics.
7  * License terms:  GNU General Public License (GPL), version 2
8  */
9 
10 #include <linux/module.h>
11 #include <linux/notifier.h>
12 #include <linux/platform_device.h>
13 
14 #include <drm/drmP.h>
15 
16 #include "sti_vtg.h"
17 
18 #define VTG_TYPE_MASTER         0
19 #define VTG_TYPE_SLAVE_BY_EXT0  1
20 
21 /* registers offset */
22 #define VTG_MODE            0x0000
23 #define VTG_CLKLN           0x0008
24 #define VTG_HLFLN           0x000C
25 #define VTG_DRST_AUTOC      0x0010
26 #define VTG_VID_TFO         0x0040
27 #define VTG_VID_TFS         0x0044
28 #define VTG_VID_BFO         0x0048
29 #define VTG_VID_BFS         0x004C
30 
31 #define VTG_HOST_ITS        0x0078
32 #define VTG_HOST_ITS_BCLR   0x007C
33 #define VTG_HOST_ITM_BCLR   0x0088
34 #define VTG_HOST_ITM_BSET   0x008C
35 
36 #define VTG_H_HD_1          0x00C0
37 #define VTG_TOP_V_VD_1      0x00C4
38 #define VTG_BOT_V_VD_1      0x00C8
39 #define VTG_TOP_V_HD_1      0x00CC
40 #define VTG_BOT_V_HD_1      0x00D0
41 
42 #define VTG_H_HD_2          0x00E0
43 #define VTG_TOP_V_VD_2      0x00E4
44 #define VTG_BOT_V_VD_2      0x00E8
45 #define VTG_TOP_V_HD_2      0x00EC
46 #define VTG_BOT_V_HD_2      0x00F0
47 
48 #define VTG_H_HD_3          0x0100
49 #define VTG_TOP_V_VD_3      0x0104
50 #define VTG_BOT_V_VD_3      0x0108
51 #define VTG_TOP_V_HD_3      0x010C
52 #define VTG_BOT_V_HD_3      0x0110
53 
54 #define VTG_H_HD_4          0x0120
55 #define VTG_TOP_V_VD_4      0x0124
56 #define VTG_BOT_V_VD_4      0x0128
57 #define VTG_TOP_V_HD_4      0x012c
58 #define VTG_BOT_V_HD_4      0x0130
59 
60 #define VTG_IRQ_BOTTOM      BIT(0)
61 #define VTG_IRQ_TOP         BIT(1)
62 #define VTG_IRQ_MASK        (VTG_IRQ_TOP | VTG_IRQ_BOTTOM)
63 
64 /* Delay introduced by the HDMI in nb of pixel */
65 #define HDMI_DELAY          (6)
66 
67 /* delay introduced by the Arbitrary Waveform Generator in nb of pixels */
68 #define AWG_DELAY_HD        (-9)
69 #define AWG_DELAY_ED        (-8)
70 #define AWG_DELAY_SD        (-7)
71 
72 LIST_HEAD(vtg_lookup);
73 
74 /**
75  * STI VTG structure
76  *
77  * @dev: pointer to device driver
78  * @data: data associated to the device
79  * @irq: VTG irq
80  * @type: VTG type (main or aux)
81  * @notifier_list: notifier callback
82  * @crtc_id: the crtc id for vblank event
83  * @slave: slave vtg
84  * @link: List node to link the structure in lookup list
85  */
86 struct sti_vtg {
87 	struct device *dev;
88 	struct device_node *np;
89 	void __iomem *regs;
90 	int irq;
91 	u32 irq_status;
92 	struct raw_notifier_head notifier_list;
93 	int crtc_id;
94 	struct sti_vtg *slave;
95 	struct list_head link;
96 };
97 
98 static void vtg_register(struct sti_vtg *vtg)
99 {
100 	list_add_tail(&vtg->link, &vtg_lookup);
101 }
102 
103 struct sti_vtg *of_vtg_find(struct device_node *np)
104 {
105 	struct sti_vtg *vtg;
106 
107 	list_for_each_entry(vtg, &vtg_lookup, link) {
108 		if (vtg->np == np)
109 			return vtg;
110 	}
111 	return NULL;
112 }
113 EXPORT_SYMBOL(of_vtg_find);
114 
115 static void vtg_reset(struct sti_vtg *vtg)
116 {
117 	/* reset slave and then master */
118 	if (vtg->slave)
119 		vtg_reset(vtg->slave);
120 
121 	writel(1, vtg->regs + VTG_DRST_AUTOC);
122 }
123 
124 static void vtg_set_mode(struct sti_vtg *vtg,
125 			 int type, const struct drm_display_mode *mode)
126 {
127 	u32 tmp;
128 
129 	if (vtg->slave)
130 		vtg_set_mode(vtg->slave, VTG_TYPE_SLAVE_BY_EXT0, mode);
131 
132 	writel(mode->htotal, vtg->regs + VTG_CLKLN);
133 	writel(mode->vtotal * 2, vtg->regs + VTG_HLFLN);
134 
135 	tmp = (mode->vtotal - mode->vsync_start + 1) << 16;
136 	tmp |= mode->htotal - mode->hsync_start;
137 	writel(tmp, vtg->regs + VTG_VID_TFO);
138 	writel(tmp, vtg->regs + VTG_VID_BFO);
139 
140 	tmp = (mode->vdisplay + mode->vtotal - mode->vsync_start + 1) << 16;
141 	tmp |= mode->hdisplay + mode->htotal - mode->hsync_start;
142 	writel(tmp, vtg->regs + VTG_VID_TFS);
143 	writel(tmp, vtg->regs + VTG_VID_BFS);
144 
145 	/* prepare VTG set 1 for HDMI */
146 	tmp = (mode->hsync_end - mode->hsync_start + HDMI_DELAY) << 16;
147 	tmp |= HDMI_DELAY;
148 	writel(tmp, vtg->regs + VTG_H_HD_1);
149 
150 	tmp = (mode->vsync_end - mode->vsync_start + 1) << 16;
151 	tmp |= 1;
152 	writel(tmp, vtg->regs + VTG_TOP_V_VD_1);
153 	writel(tmp, vtg->regs + VTG_BOT_V_VD_1);
154 	writel(0, vtg->regs + VTG_TOP_V_HD_1);
155 	writel(0, vtg->regs + VTG_BOT_V_HD_1);
156 
157 	/* prepare VTG set 2 for for HD DCS */
158 	tmp = (mode->hsync_end - mode->hsync_start) << 16;
159 	writel(tmp, vtg->regs + VTG_H_HD_2);
160 
161 	tmp = (mode->vsync_end - mode->vsync_start + 1) << 16;
162 	tmp |= 1;
163 	writel(tmp, vtg->regs + VTG_TOP_V_VD_2);
164 	writel(tmp, vtg->regs + VTG_BOT_V_VD_2);
165 	writel(0, vtg->regs + VTG_TOP_V_HD_2);
166 	writel(0, vtg->regs + VTG_BOT_V_HD_2);
167 
168 	/* prepare VTG set 3 for HD Analog in HD mode */
169 	tmp = (mode->hsync_end - mode->hsync_start + AWG_DELAY_HD) << 16;
170 	tmp |= mode->htotal + AWG_DELAY_HD;
171 	writel(tmp, vtg->regs + VTG_H_HD_3);
172 
173 	tmp = (mode->vsync_end - mode->vsync_start) << 16;
174 	tmp |= mode->vtotal;
175 	writel(tmp, vtg->regs + VTG_TOP_V_VD_3);
176 	writel(tmp, vtg->regs + VTG_BOT_V_VD_3);
177 
178 	tmp = (mode->htotal + AWG_DELAY_HD) << 16;
179 	tmp |= mode->htotal + AWG_DELAY_HD;
180 	writel(tmp, vtg->regs + VTG_TOP_V_HD_3);
181 	writel(tmp, vtg->regs + VTG_BOT_V_HD_3);
182 
183 	/* Prepare VTG set 4 for DVO */
184 	tmp = (mode->hsync_end - mode->hsync_start) << 16;
185 	writel(tmp, vtg->regs + VTG_H_HD_4);
186 
187 	tmp = (mode->vsync_end - mode->vsync_start + 1) << 16;
188 	tmp |= 1;
189 	writel(tmp, vtg->regs + VTG_TOP_V_VD_4);
190 	writel(tmp, vtg->regs + VTG_BOT_V_VD_4);
191 	writel(0, vtg->regs + VTG_TOP_V_HD_4);
192 	writel(0, vtg->regs + VTG_BOT_V_HD_4);
193 
194 	/* mode */
195 	writel(type, vtg->regs + VTG_MODE);
196 }
197 
198 static void vtg_enable_irq(struct sti_vtg *vtg)
199 {
200 	/* clear interrupt status and mask */
201 	writel(0xFFFF, vtg->regs + VTG_HOST_ITS_BCLR);
202 	writel(0xFFFF, vtg->regs + VTG_HOST_ITM_BCLR);
203 	writel(VTG_IRQ_MASK, vtg->regs + VTG_HOST_ITM_BSET);
204 }
205 
206 void sti_vtg_set_config(struct sti_vtg *vtg,
207 		const struct drm_display_mode *mode)
208 {
209 	/* write configuration */
210 	vtg_set_mode(vtg, VTG_TYPE_MASTER, mode);
211 
212 	vtg_reset(vtg);
213 
214 	/* enable irq for the vtg vblank synchro */
215 	if (vtg->slave)
216 		vtg_enable_irq(vtg->slave);
217 	else
218 		vtg_enable_irq(vtg);
219 }
220 EXPORT_SYMBOL(sti_vtg_set_config);
221 
222 /**
223  * sti_vtg_get_line_number
224  *
225  * @mode: display mode to be used
226  * @y:    line
227  *
228  * Return the line number according to the display mode taking
229  * into account the Sync and Back Porch information.
230  * Video frame line numbers start at 1, y starts at 0.
231  * In interlaced modes the start line is the field line number of the odd
232  * field, but y is still defined as a progressive frame.
233  */
234 u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y)
235 {
236 	u32 start_line = mode.vtotal - mode.vsync_start + 1;
237 
238 	if (mode.flags & DRM_MODE_FLAG_INTERLACE)
239 		start_line *= 2;
240 
241 	return start_line + y;
242 }
243 EXPORT_SYMBOL(sti_vtg_get_line_number);
244 
245 /**
246  * sti_vtg_get_pixel_number
247  *
248  * @mode: display mode to be used
249  * @x:    row
250  *
251  * Return the pixel number according to the display mode taking
252  * into account the Sync and Back Porch information.
253  * Pixels are counted from 0.
254  */
255 u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x)
256 {
257 	return mode.htotal - mode.hsync_start + x;
258 }
259 EXPORT_SYMBOL(sti_vtg_get_pixel_number);
260 
261 int sti_vtg_register_client(struct sti_vtg *vtg,
262 		struct notifier_block *nb, int crtc_id)
263 {
264 	if (vtg->slave)
265 		return sti_vtg_register_client(vtg->slave, nb, crtc_id);
266 
267 	vtg->crtc_id = crtc_id;
268 	return raw_notifier_chain_register(&vtg->notifier_list, nb);
269 }
270 EXPORT_SYMBOL(sti_vtg_register_client);
271 
272 int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb)
273 {
274 	if (vtg->slave)
275 		return sti_vtg_unregister_client(vtg->slave, nb);
276 
277 	return raw_notifier_chain_unregister(&vtg->notifier_list, nb);
278 }
279 EXPORT_SYMBOL(sti_vtg_unregister_client);
280 
281 static irqreturn_t vtg_irq_thread(int irq, void *arg)
282 {
283 	struct sti_vtg *vtg = arg;
284 	u32 event;
285 
286 	event = (vtg->irq_status & VTG_IRQ_TOP) ?
287 		VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT;
288 
289 	raw_notifier_call_chain(&vtg->notifier_list, event, &vtg->crtc_id);
290 
291 	return IRQ_HANDLED;
292 }
293 
294 static irqreturn_t vtg_irq(int irq, void *arg)
295 {
296 	struct sti_vtg *vtg = arg;
297 
298 	vtg->irq_status = readl(vtg->regs + VTG_HOST_ITS);
299 
300 	writel(vtg->irq_status, vtg->regs + VTG_HOST_ITS_BCLR);
301 
302 	/* force sync bus write */
303 	readl(vtg->regs + VTG_HOST_ITS);
304 
305 	return IRQ_WAKE_THREAD;
306 }
307 
308 static int vtg_probe(struct platform_device *pdev)
309 {
310 	struct device *dev = &pdev->dev;
311 	struct device_node *np;
312 	struct sti_vtg *vtg;
313 	struct resource *res;
314 	char irq_name[32];
315 	int ret;
316 
317 	vtg = devm_kzalloc(dev, sizeof(*vtg), GFP_KERNEL);
318 	if (!vtg)
319 		return -ENOMEM;
320 
321 	vtg->dev = dev;
322 	vtg->np = pdev->dev.of_node;
323 
324 	/* Get Memory ressources */
325 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
326 	if (!res) {
327 		DRM_ERROR("Get memory resource failed\n");
328 		return -ENOMEM;
329 	}
330 	vtg->regs = devm_ioremap_nocache(dev, res->start, resource_size(res));
331 
332 	np = of_parse_phandle(pdev->dev.of_node, "st,slave", 0);
333 	if (np) {
334 		vtg->slave = of_vtg_find(np);
335 
336 		if (!vtg->slave)
337 			return -EPROBE_DEFER;
338 	} else {
339 		vtg->irq = platform_get_irq(pdev, 0);
340 		if (IS_ERR_VALUE(vtg->irq)) {
341 			DRM_ERROR("Failed to get VTG interrupt\n");
342 			return vtg->irq;
343 		}
344 
345 		snprintf(irq_name, sizeof(irq_name), "vsync-%s",
346 				dev_name(vtg->dev));
347 
348 		RAW_INIT_NOTIFIER_HEAD(&vtg->notifier_list);
349 
350 		ret = devm_request_threaded_irq(dev, vtg->irq, vtg_irq,
351 				vtg_irq_thread, IRQF_ONESHOT, irq_name, vtg);
352 		if (IS_ERR_VALUE(ret)) {
353 			DRM_ERROR("Failed to register VTG interrupt\n");
354 			return ret;
355 		}
356 	}
357 
358 	vtg_register(vtg);
359 	platform_set_drvdata(pdev, vtg);
360 
361 	DRM_INFO("%s %s\n", __func__, dev_name(vtg->dev));
362 
363 	return 0;
364 }
365 
366 static int vtg_remove(struct platform_device *pdev)
367 {
368 	return 0;
369 }
370 
371 static const struct of_device_id vtg_of_match[] = {
372 	{ .compatible = "st,vtg", },
373 	{ /* sentinel */ }
374 };
375 MODULE_DEVICE_TABLE(of, vtg_of_match);
376 
377 struct platform_driver sti_vtg_driver = {
378 	.driver = {
379 		.name = "sti-vtg",
380 		.owner = THIS_MODULE,
381 		.of_match_table = vtg_of_match,
382 	},
383 	.probe	= vtg_probe,
384 	.remove = vtg_remove,
385 };
386 
387 module_platform_driver(sti_vtg_driver);
388 
389 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
390 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
391 MODULE_LICENSE("GPL");
392