linux/drivers/gpu/drm/sti/sti_vtg.c
<<
>>
Prefs
   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
  72LIST_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 */
  86struct 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
  98static void vtg_register(struct sti_vtg *vtg)
  99{
 100        list_add_tail(&vtg->link, &vtg_lookup);
 101}
 102
 103struct 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}
 113EXPORT_SYMBOL(of_vtg_find);
 114
 115static 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
 124static 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
 198static 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
 206void 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}
 220EXPORT_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 */
 234u32 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}
 243EXPORT_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 */
 255u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x)
 256{
 257        return mode.htotal - mode.hsync_start + x;
 258}
 259EXPORT_SYMBOL(sti_vtg_get_pixel_number);
 260
 261int 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}
 270EXPORT_SYMBOL(sti_vtg_register_client);
 271
 272int 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}
 279EXPORT_SYMBOL(sti_vtg_unregister_client);
 280
 281static 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
 294static 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
 308static 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
 366static int vtg_remove(struct platform_device *pdev)
 367{
 368        return 0;
 369}
 370
 371static const struct of_device_id vtg_of_match[] = {
 372        { .compatible = "st,vtg", },
 373        { /* sentinel */ }
 374};
 375MODULE_DEVICE_TABLE(of, vtg_of_match);
 376
 377struct 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
 387module_platform_driver(sti_vtg_driver);
 388
 389MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
 390MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
 391MODULE_LICENSE("GPL");
 392