xilinx-vtc.c (11050B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Xilinx Video Timing Controller 4 * 5 * Copyright (C) 2013-2015 Ideas on Board 6 * Copyright (C) 2013-2015 Xilinx, Inc. 7 * 8 * Contacts: Hyun Kwon <hyun.kwon@xilinx.com> 9 * Laurent Pinchart <laurent.pinchart@ideasonboard.com> 10 */ 11 12#include <linux/clk.h> 13#include <linux/module.h> 14#include <linux/of.h> 15#include <linux/platform_device.h> 16#include <linux/slab.h> 17 18#include "xilinx-vip.h" 19#include "xilinx-vtc.h" 20 21#define XVTC_CONTROL_FIELD_ID_POL_SRC (1 << 26) 22#define XVTC_CONTROL_ACTIVE_CHROMA_POL_SRC (1 << 25) 23#define XVTC_CONTROL_ACTIVE_VIDEO_POL_SRC (1 << 24) 24#define XVTC_CONTROL_HSYNC_POL_SRC (1 << 23) 25#define XVTC_CONTROL_VSYNC_POL_SRC (1 << 22) 26#define XVTC_CONTROL_HBLANK_POL_SRC (1 << 21) 27#define XVTC_CONTROL_VBLANK_POL_SRC (1 << 20) 28#define XVTC_CONTROL_CHROMA_SRC (1 << 18) 29#define XVTC_CONTROL_VBLANK_HOFF_SRC (1 << 17) 30#define XVTC_CONTROL_VSYNC_END_SRC (1 << 16) 31#define XVTC_CONTROL_VSYNC_START_SRC (1 << 15) 32#define XVTC_CONTROL_ACTIVE_VSIZE_SRC (1 << 14) 33#define XVTC_CONTROL_FRAME_VSIZE_SRC (1 << 13) 34#define XVTC_CONTROL_HSYNC_END_SRC (1 << 11) 35#define XVTC_CONTROL_HSYNC_START_SRC (1 << 10) 36#define XVTC_CONTROL_ACTIVE_HSIZE_SRC (1 << 9) 37#define XVTC_CONTROL_FRAME_HSIZE_SRC (1 << 8) 38#define XVTC_CONTROL_SYNC_ENABLE (1 << 5) 39#define XVTC_CONTROL_DET_ENABLE (1 << 3) 40#define XVTC_CONTROL_GEN_ENABLE (1 << 2) 41 42#define XVTC_STATUS_FSYNC(n) ((n) << 16) 43#define XVTC_STATUS_GEN_ACTIVE_VIDEO (1 << 13) 44#define XVTC_STATUS_GEN_VBLANK (1 << 12) 45#define XVTC_STATUS_DET_ACTIVE_VIDEO (1 << 11) 46#define XVTC_STATUS_DET_VBLANK (1 << 10) 47#define XVTC_STATUS_LOCK_LOSS (1 << 9) 48#define XVTC_STATUS_LOCK (1 << 8) 49 50#define XVTC_ERROR_ACTIVE_CHROMA_LOCK (1 << 21) 51#define XVTC_ERROR_ACTIVE_VIDEO_LOCK (1 << 20) 52#define XVTC_ERROR_HSYNC_LOCK (1 << 19) 53#define XVTC_ERROR_VSYNC_LOCK (1 << 18) 54#define XVTC_ERROR_HBLANK_LOCK (1 << 17) 55#define XVTC_ERROR_VBLANK_LOCK (1 << 16) 56 57#define XVTC_IRQ_ENABLE_FSYNC(n) ((n) << 16) 58#define XVTC_IRQ_ENABLE_GEN_ACTIVE_VIDEO (1 << 13) 59#define XVTC_IRQ_ENABLE_GEN_VBLANK (1 << 12) 60#define XVTC_IRQ_ENABLE_DET_ACTIVE_VIDEO (1 << 11) 61#define XVTC_IRQ_ENABLE_DET_VBLANK (1 << 10) 62#define XVTC_IRQ_ENABLE_LOCK_LOSS (1 << 9) 63#define XVTC_IRQ_ENABLE_LOCK (1 << 8) 64 65/* 66 * The following registers exist in two blocks, one at 0x0020 for the detector 67 * and one at 0x0060 for the generator. 68 */ 69 70#define XVTC_DETECTOR_OFFSET 0x0020 71#define XVTC_GENERATOR_OFFSET 0x0060 72 73#define XVTC_ACTIVE_SIZE 0x0000 74#define XVTC_ACTIVE_VSIZE_SHIFT 16 75#define XVTC_ACTIVE_VSIZE_MASK (0x1fff << 16) 76#define XVTC_ACTIVE_HSIZE_SHIFT 0 77#define XVTC_ACTIVE_HSIZE_MASK (0x1fff << 0) 78 79#define XVTC_TIMING_STATUS 0x0004 80#define XVTC_TIMING_STATUS_ACTIVE_VIDEO (1 << 2) 81#define XVTC_TIMING_STATUS_VBLANK (1 << 1) 82#define XVTC_TIMING_STATUS_LOCKED (1 << 0) 83 84#define XVTC_ENCODING 0x0008 85#define XVTC_ENCODING_CHROMA_PARITY_SHIFT 8 86#define XVTC_ENCODING_CHROMA_PARITY_MASK (3 << 8) 87#define XVTC_ENCODING_CHROMA_PARITY_EVEN_ALL (0 << 8) 88#define XVTC_ENCODING_CHROMA_PARITY_ODD_ALL (1 << 8) 89#define XVTC_ENCODING_CHROMA_PARITY_EVEN_EVEN (2 << 8) 90#define XVTC_ENCODING_CHROMA_PARITY_ODD_EVEN (3 << 8) 91#define XVTC_ENCODING_VIDEO_FORMAT_SHIFT 0 92#define XVTC_ENCODING_VIDEO_FORMAT_MASK (0xf << 0) 93#define XVTC_ENCODING_VIDEO_FORMAT_YUV422 (0 << 0) 94#define XVTC_ENCODING_VIDEO_FORMAT_YUV444 (1 << 0) 95#define XVTC_ENCODING_VIDEO_FORMAT_RGB (2 << 0) 96#define XVTC_ENCODING_VIDEO_FORMAT_YUV420 (3 << 0) 97 98#define XVTC_POLARITY 0x000c 99#define XVTC_POLARITY_ACTIVE_CHROMA_POL (1 << 5) 100#define XVTC_POLARITY_ACTIVE_VIDEO_POL (1 << 4) 101#define XVTC_POLARITY_HSYNC_POL (1 << 3) 102#define XVTC_POLARITY_VSYNC_POL (1 << 2) 103#define XVTC_POLARITY_HBLANK_POL (1 << 1) 104#define XVTC_POLARITY_VBLANK_POL (1 << 0) 105 106#define XVTC_HSIZE 0x0010 107#define XVTC_HSIZE_MASK (0x1fff << 0) 108 109#define XVTC_VSIZE 0x0014 110#define XVTC_VSIZE_MASK (0x1fff << 0) 111 112#define XVTC_HSYNC 0x0018 113#define XVTC_HSYNC_END_SHIFT 16 114#define XVTC_HSYNC_END_MASK (0x1fff << 16) 115#define XVTC_HSYNC_START_SHIFT 0 116#define XVTC_HSYNC_START_MASK (0x1fff << 0) 117 118#define XVTC_F0_VBLANK_H 0x001c 119#define XVTC_F0_VBLANK_HEND_SHIFT 16 120#define XVTC_F0_VBLANK_HEND_MASK (0x1fff << 16) 121#define XVTC_F0_VBLANK_HSTART_SHIFT 0 122#define XVTC_F0_VBLANK_HSTART_MASK (0x1fff << 0) 123 124#define XVTC_F0_VSYNC_V 0x0020 125#define XVTC_F0_VSYNC_VEND_SHIFT 16 126#define XVTC_F0_VSYNC_VEND_MASK (0x1fff << 16) 127#define XVTC_F0_VSYNC_VSTART_SHIFT 0 128#define XVTC_F0_VSYNC_VSTART_MASK (0x1fff << 0) 129 130#define XVTC_F0_VSYNC_H 0x0024 131#define XVTC_F0_VSYNC_HEND_SHIFT 16 132#define XVTC_F0_VSYNC_HEND_MASK (0x1fff << 16) 133#define XVTC_F0_VSYNC_HSTART_SHIFT 0 134#define XVTC_F0_VSYNC_HSTART_MASK (0x1fff << 0) 135 136#define XVTC_FRAME_SYNC_CONFIG(n) (0x0100 + 4 * (n)) 137#define XVTC_FRAME_SYNC_V_START_SHIFT 16 138#define XVTC_FRAME_SYNC_V_START_MASK (0x1fff << 16) 139#define XVTC_FRAME_SYNC_H_START_SHIFT 0 140#define XVTC_FRAME_SYNC_H_START_MASK (0x1fff << 0) 141 142#define XVTC_GENERATOR_GLOBAL_DELAY 0x0104 143 144/** 145 * struct xvtc_device - Xilinx Video Timing Controller device structure 146 * @xvip: Xilinx Video IP device 147 * @list: entry in the global VTC list 148 * @has_detector: the VTC has a timing detector 149 * @has_generator: the VTC has a timing generator 150 * @config: generator timings configuration 151 */ 152struct xvtc_device { 153 struct xvip_device xvip; 154 struct list_head list; 155 156 bool has_detector; 157 bool has_generator; 158 159 struct xvtc_config config; 160}; 161 162static LIST_HEAD(xvtc_list); 163static DEFINE_MUTEX(xvtc_lock); 164 165static inline void xvtc_gen_write(struct xvtc_device *xvtc, u32 addr, u32 value) 166{ 167 xvip_write(&xvtc->xvip, XVTC_GENERATOR_OFFSET + addr, value); 168} 169 170/* ----------------------------------------------------------------------------- 171 * Generator Operations 172 */ 173 174int xvtc_generator_start(struct xvtc_device *xvtc, 175 const struct xvtc_config *config) 176{ 177 int ret; 178 179 if (!xvtc->has_generator) 180 return -ENXIO; 181 182 ret = clk_prepare_enable(xvtc->xvip.clk); 183 if (ret < 0) 184 return ret; 185 186 /* We don't care about the chroma active signal, encoding parameters are 187 * not important for now. 188 */ 189 xvtc_gen_write(xvtc, XVTC_POLARITY, 190 XVTC_POLARITY_ACTIVE_CHROMA_POL | 191 XVTC_POLARITY_ACTIVE_VIDEO_POL | 192 XVTC_POLARITY_HSYNC_POL | XVTC_POLARITY_VSYNC_POL | 193 XVTC_POLARITY_HBLANK_POL | XVTC_POLARITY_VBLANK_POL); 194 195 /* Hardcode the polarity to active high, as required by the video in to 196 * AXI4-stream core. 197 */ 198 xvtc_gen_write(xvtc, XVTC_ENCODING, 0); 199 200 /* Configure the timings. The VBLANK and VSYNC signals assertion and 201 * deassertion are hardcoded to the first pixel of the line. 202 */ 203 xvtc_gen_write(xvtc, XVTC_ACTIVE_SIZE, 204 (config->vblank_start << XVTC_ACTIVE_VSIZE_SHIFT) | 205 (config->hblank_start << XVTC_ACTIVE_HSIZE_SHIFT)); 206 xvtc_gen_write(xvtc, XVTC_HSIZE, config->hsize); 207 xvtc_gen_write(xvtc, XVTC_VSIZE, config->vsize); 208 xvtc_gen_write(xvtc, XVTC_HSYNC, 209 (config->hsync_end << XVTC_HSYNC_END_SHIFT) | 210 (config->hsync_start << XVTC_HSYNC_START_SHIFT)); 211 xvtc_gen_write(xvtc, XVTC_F0_VBLANK_H, 0); 212 xvtc_gen_write(xvtc, XVTC_F0_VSYNC_V, 213 (config->vsync_end << XVTC_F0_VSYNC_VEND_SHIFT) | 214 (config->vsync_start << XVTC_F0_VSYNC_VSTART_SHIFT)); 215 xvtc_gen_write(xvtc, XVTC_F0_VSYNC_H, 0); 216 217 /* Enable the generator. Set the source of all generator parameters to 218 * generator registers. 219 */ 220 xvip_write(&xvtc->xvip, XVIP_CTRL_CONTROL, 221 XVTC_CONTROL_ACTIVE_CHROMA_POL_SRC | 222 XVTC_CONTROL_ACTIVE_VIDEO_POL_SRC | 223 XVTC_CONTROL_HSYNC_POL_SRC | XVTC_CONTROL_VSYNC_POL_SRC | 224 XVTC_CONTROL_HBLANK_POL_SRC | XVTC_CONTROL_VBLANK_POL_SRC | 225 XVTC_CONTROL_CHROMA_SRC | XVTC_CONTROL_VBLANK_HOFF_SRC | 226 XVTC_CONTROL_VSYNC_END_SRC | XVTC_CONTROL_VSYNC_START_SRC | 227 XVTC_CONTROL_ACTIVE_VSIZE_SRC | 228 XVTC_CONTROL_FRAME_VSIZE_SRC | XVTC_CONTROL_HSYNC_END_SRC | 229 XVTC_CONTROL_HSYNC_START_SRC | 230 XVTC_CONTROL_ACTIVE_HSIZE_SRC | 231 XVTC_CONTROL_FRAME_HSIZE_SRC | XVTC_CONTROL_GEN_ENABLE | 232 XVIP_CTRL_CONTROL_REG_UPDATE); 233 234 return 0; 235} 236EXPORT_SYMBOL_GPL(xvtc_generator_start); 237 238int xvtc_generator_stop(struct xvtc_device *xvtc) 239{ 240 if (!xvtc->has_generator) 241 return -ENXIO; 242 243 xvip_write(&xvtc->xvip, XVIP_CTRL_CONTROL, 0); 244 245 clk_disable_unprepare(xvtc->xvip.clk); 246 247 return 0; 248} 249EXPORT_SYMBOL_GPL(xvtc_generator_stop); 250 251struct xvtc_device *xvtc_of_get(struct device_node *np) 252{ 253 struct device_node *xvtc_node; 254 struct xvtc_device *found = NULL; 255 struct xvtc_device *xvtc; 256 257 if (!of_find_property(np, "xlnx,vtc", NULL)) 258 return NULL; 259 260 xvtc_node = of_parse_phandle(np, "xlnx,vtc", 0); 261 if (xvtc_node == NULL) 262 return ERR_PTR(-EINVAL); 263 264 mutex_lock(&xvtc_lock); 265 list_for_each_entry(xvtc, &xvtc_list, list) { 266 if (xvtc->xvip.dev->of_node == xvtc_node) { 267 found = xvtc; 268 break; 269 } 270 } 271 mutex_unlock(&xvtc_lock); 272 273 of_node_put(xvtc_node); 274 275 if (!found) 276 return ERR_PTR(-EPROBE_DEFER); 277 278 return found; 279} 280EXPORT_SYMBOL_GPL(xvtc_of_get); 281 282void xvtc_put(struct xvtc_device *xvtc) 283{ 284} 285EXPORT_SYMBOL_GPL(xvtc_put); 286 287/* ----------------------------------------------------------------------------- 288 * Registration and Unregistration 289 */ 290 291static void xvtc_register_device(struct xvtc_device *xvtc) 292{ 293 mutex_lock(&xvtc_lock); 294 list_add_tail(&xvtc->list, &xvtc_list); 295 mutex_unlock(&xvtc_lock); 296} 297 298static void xvtc_unregister_device(struct xvtc_device *xvtc) 299{ 300 mutex_lock(&xvtc_lock); 301 list_del(&xvtc->list); 302 mutex_unlock(&xvtc_lock); 303} 304 305/* ----------------------------------------------------------------------------- 306 * Platform Device Driver 307 */ 308 309static int xvtc_parse_of(struct xvtc_device *xvtc) 310{ 311 struct device_node *node = xvtc->xvip.dev->of_node; 312 313 xvtc->has_detector = of_property_read_bool(node, "xlnx,detector"); 314 xvtc->has_generator = of_property_read_bool(node, "xlnx,generator"); 315 316 return 0; 317} 318 319static int xvtc_probe(struct platform_device *pdev) 320{ 321 struct xvtc_device *xvtc; 322 int ret; 323 324 xvtc = devm_kzalloc(&pdev->dev, sizeof(*xvtc), GFP_KERNEL); 325 if (!xvtc) 326 return -ENOMEM; 327 328 xvtc->xvip.dev = &pdev->dev; 329 330 ret = xvtc_parse_of(xvtc); 331 if (ret < 0) 332 return ret; 333 334 ret = xvip_init_resources(&xvtc->xvip); 335 if (ret < 0) 336 return ret; 337 338 platform_set_drvdata(pdev, xvtc); 339 340 xvip_print_version(&xvtc->xvip); 341 342 xvtc_register_device(xvtc); 343 344 return 0; 345} 346 347static int xvtc_remove(struct platform_device *pdev) 348{ 349 struct xvtc_device *xvtc = platform_get_drvdata(pdev); 350 351 xvtc_unregister_device(xvtc); 352 353 xvip_cleanup_resources(&xvtc->xvip); 354 355 return 0; 356} 357 358static const struct of_device_id xvtc_of_id_table[] = { 359 { .compatible = "xlnx,v-tc-6.1" }, 360 { } 361}; 362MODULE_DEVICE_TABLE(of, xvtc_of_id_table); 363 364static struct platform_driver xvtc_driver = { 365 .driver = { 366 .name = "xilinx-vtc", 367 .of_match_table = xvtc_of_id_table, 368 }, 369 .probe = xvtc_probe, 370 .remove = xvtc_remove, 371}; 372 373module_platform_driver(xvtc_driver); 374 375MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>"); 376MODULE_DESCRIPTION("Xilinx Video Timing Controller Driver"); 377MODULE_LICENSE("GPL v2");