1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020 Antmicro <www.antmicro.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
15 #include <drm/drm_device.h>
16 #include <drm/drm_drv.h>
17 #include <drm/drm_ioctl.h>
18 #include <drm/drm_prime.h>
19 #include <linux/module.h>
21 #include <linux/wait.h>
22 #include <linux/platform_device.h>
23 #include <linux/types.h>
24 #include <linux/litex.h>
25 #include <linux/errno.h>
27 #include "litevideo.h"
30 #define DRIVER_NAME "litevideo"
35 static void litevideo_get_md(u32 pixel_clock
, u32
*best_m
, u32
*best_d
)
37 u32 ideal_m
, ideal_d
, curr_m
, curr_d
, m
, d
;
38 u32 curr_diff
, test_diff
;
40 ideal_m
= pixel_clock
;
41 ideal_d
= LITEVIDEO_IDEAL_DIV_VALUE
;
43 /* Start searching from minimum values */
48 for (d
= MMCM_MIN_D
; d
< MMCM_MAX_D
; d
++) {
49 for (m
= MMCM_MIN_M
; m
< MMCM_MAX_M
; m
++) {
51 /* Clocks cannot be set perfectly, therefore all
52 * combinations for multiplier (m) and divisor (d)
53 * are checked to find the closest possible clock value
56 curr_diff
= abs((d
* ideal_d
* curr_m
) -
57 (d
* curr_d
* ideal_m
));
58 test_diff
= abs((curr_d
* ideal_d
* m
) -
59 (d
* curr_d
* ideal_m
));
61 if (test_diff
< curr_diff
) {
72 static int litevideo_mmcm_write(struct litevideo_prv
*prv
, u32 addr
, u32 data
)
74 /* write MMCM register address */
76 litex_set_reg(prv
->base
+ LITEVIDEO_MMCM_ADDR_OFF
,
77 LITEVIDEO_MMCM_ADDR_SIZE
, addr
);
79 /* write data to send to MMCM register */
81 litex_set_reg(prv
->base
+ LITEVIDEO_MMCM_DATA_OFF
,
82 LITEVIDEO_MMCM_DATA_SIZE
, data
);
86 litex_set_reg(prv
->base
+ LITEVIDEO_MMCM_WRITE_OFF
,
87 LITEVIDEO_MMCM_WRITE_SIZE
, MMCM_WRITE
);
89 /* wait for transfer finish */
91 if (!wait_event_timeout(prv
->wq
,
92 litex_get_reg(prv
->base
+ LITEVIDEO_MMCM_READY_OFF
,
93 LITEVIDEO_MMCM_READY_SIZE
), HZ
))
99 static int litevideo_clkgen_write(struct litevideo_prv
*prv
, u32 m
, u32 d
)
105 ret
= litevideo_mmcm_write(prv
, MMCM_CLKFBOUT1
,
106 MMCM_HT_FALLING_EDGE
|
107 (m
/ 2) << MMCM_HT_SHIFT
|
108 (m
/ 2 + (m
% 2)) << MMCM_LT_SHIFT
);
116 ret
= litevideo_mmcm_write(prv
, MMCM_DIVCLK
,
117 MMCM_HT_FALLING_EDGE
);
119 ret
= litevideo_mmcm_write(prv
, MMCM_DIVCLK
,
120 (d
/ 2) << MMCM_HT_SHIFT
|
121 (d
/ 2 + (d
% 2)) << MMCM_LT_SHIFT
);
126 /* clkout0_divide = 10 */
128 ret
= litevideo_mmcm_write(prv
, MMCM_CLKOUT0
,
129 MMCM_HT_FALLING_EDGE
|
130 MMCM_CLKOUT_DIV10
<< MMCM_HT_SHIFT
|
131 MMCM_CLKOUT_DIV10
<< MMCM_LT_SHIFT
);
136 /* clkout1_divide = 2 */
138 ret
= litevideo_mmcm_write(prv
, MMCM_CLKOUT1
,
139 MMCM_HT_FALLING_EDGE
|
140 MMCM_CLKOUT_DIV2
<< MMCM_HT_SHIFT
|
141 MMCM_CLKOUT_DIV2
<< MMCM_LT_SHIFT
);
146 static int litevideo_drv_init(struct litevideo_prv
*prv
, u32 m
, u32 d
)
150 /* initialize waitqueue for timeouts in litex_mmcm_write() */
152 init_waitqueue_head(&prv
->wq
);
156 ret
= litevideo_clkgen_write(prv
, m
, d
);
160 /* timings - horizontal */
162 litex_set_reg(prv
->base
+ LITEVIDEO_CORE_HRES_OFF
,
163 LITEVIDEO_CORE_HRES_SIZE
, prv
->h_active
);
164 litex_set_reg(prv
->base
+ LITEVIDEO_CORE_HSYNC_START_OFF
,
165 LITEVIDEO_CORE_HSYNC_START_SIZE
,
166 prv
->h_active
+ prv
->h_front_porch
);
167 litex_set_reg(prv
->base
+ LITEVIDEO_CORE_HSYNC_END_OFF
,
168 LITEVIDEO_CORE_HSYNC_END_SIZE
,
169 prv
->h_active
+ prv
->h_front_porch
+ prv
->v_sync
);
170 litex_set_reg(prv
->base
+ LITEVIDEO_CORE_HSCAN_OFF
,
171 LITEVIDEO_CORE_HSCAN_SIZE
,
172 prv
->h_active
+ prv
->h_blanking
);
174 /* timings - vertical */
176 litex_set_reg(prv
->base
+ LITEVIDEO_CORE_VRES_OFF
,
177 LITEVIDEO_CORE_VRES_SIZE
, prv
->v_active
);
178 litex_set_reg(prv
->base
+ LITEVIDEO_CORE_VSYNC_START_OFF
,
179 LITEVIDEO_CORE_VSYNC_START_SIZE
,
180 prv
->v_active
+ prv
->v_front_porch
);
181 litex_set_reg(prv
->base
+ LITEVIDEO_CORE_VSYNC_END_OFF
,
182 LITEVIDEO_CORE_VSYNC_END_SIZE
,
183 prv
->v_active
+ prv
->v_front_porch
+ prv
->v_sync
);
184 litex_set_reg(prv
->base
+ LITEVIDEO_CORE_VSCAN_OFF
,
185 LITEVIDEO_CORE_VSCAN_SIZE
,
186 prv
->v_active
+ prv
->v_blanking
);
190 litex_set_reg(prv
->base
+ LITEVIDEO_DMA_ENABLE_OFF
,
191 LITEVIDEO_DMA_ENABLE_SIZE
, DMA_DISABLE
);
193 litex_set_reg(prv
->base
+ LITEVIDEO_DMA_BASE_ADDR_OFF
,
194 LITEVIDEO_DMA_BASE_ADDR_SIZE
, prv
->dma_offset
);
196 litex_set_reg(prv
->base
+ LITEVIDEO_DMA_LENGTH_OFF
,
197 LITEVIDEO_DMA_LENGTH_SIZE
, prv
->dma_length
);
199 litex_set_reg(prv
->base
+ LITEVIDEO_DMA_ENABLE_OFF
,
200 LITEVIDEO_DMA_ENABLE_SIZE
, DMA_ENABLE
);
205 static int litevideo_probe(struct platform_device
*pdev
)
207 struct device_node
*np
= pdev
->dev
.of_node
;
208 struct litevideo_prv
*prv
;
209 struct resource
*res
;
219 prv
= devm_kzalloc(&pdev
->dev
, sizeof(*prv
), GFP_KERNEL
);
225 ret
= of_property_read_u32(np
, "litevideo,pixel-clock", &val
);
228 prv
->pixel_clock
= val
;
230 /* timings - vertical */
232 ret
= of_property_read_u32(np
, "litevideo,v-active", &val
);
237 ret
= of_property_read_u32(np
, "litevideo,v-blanking", &val
);
240 prv
->v_blanking
= val
;
242 ret
= of_property_read_u32(np
, "litevideo,v-front-porch", &val
);
245 prv
->v_front_porch
= val
;
247 ret
= of_property_read_u32(np
, "litevideo,v-sync", &val
);
252 /* timings - horizontal */
254 ret
= of_property_read_u32(np
, "litevideo,h-active", &val
);
259 ret
= of_property_read_u32(np
, "litevideo,h-blanking", &val
);
262 prv
->h_blanking
= val
;
264 ret
= of_property_read_u32(np
, "litevideo,h-front-porch", &val
);
267 prv
->h_front_porch
= val
;
269 ret
= of_property_read_u32(np
, "litevideo,h-sync", &val
);
276 ret
= of_property_read_u32(np
, "litevideo,dma-offset", &val
);
279 prv
->dma_offset
= val
;
281 ret
= of_property_read_u32(np
, "litevideo,dma-length", &val
);
284 prv
->dma_length
= val
;
286 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
287 prv
->base
= devm_ioremap_resource(&pdev
->dev
, res
);
291 litevideo_get_md(prv
->pixel_clock
, &m
, &d
);
292 return litevideo_drv_init(prv
, m
, d
);
295 static const struct of_device_id litevideo_of_match
[] = {
296 { .compatible
= "litex,litevideo" },
299 MODULE_DEVICE_TABLE(of
, litevideo_of_match
);
301 static struct platform_driver litevideo_platform_driver
= {
302 .probe
= litevideo_probe
,
305 .owner
= THIS_MODULE
,
306 .of_match_table
= litevideo_of_match
,
310 module_platform_driver(litevideo_platform_driver
);
312 MODULE_LICENSE("GPL");
313 MODULE_DESCRIPTION("LiteVideo driver");
314 MODULE_AUTHOR("Antmicro <www.antmicro.com>");
315 MODULE_ALIAS("platform:" DRIVER_NAME
);