linux/drivers/media/platform/xilinx/xilinx-vtc.c
<<
>>
Prefs
   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");
 378