linux/drivers/gpu/drm/omapdrm/dss/sdi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2009 Nokia Corporation
   4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
   5 */
   6
   7#define DSS_SUBSYS_NAME "SDI"
   8
   9#include <linux/kernel.h>
  10#include <linux/delay.h>
  11#include <linux/err.h>
  12#include <linux/regulator/consumer.h>
  13#include <linux/export.h>
  14#include <linux/platform_device.h>
  15#include <linux/string.h>
  16#include <linux/of.h>
  17
  18#include "omapdss.h"
  19#include "dss.h"
  20
  21struct sdi_device {
  22        struct platform_device *pdev;
  23        struct dss_device *dss;
  24
  25        bool update_enabled;
  26        struct regulator *vdds_sdi_reg;
  27
  28        struct dss_lcd_mgr_config mgr_config;
  29        unsigned long pixelclock;
  30        int datapairs;
  31
  32        struct omap_dss_device output;
  33};
  34
  35#define dssdev_to_sdi(dssdev) container_of(dssdev, struct sdi_device, output)
  36
  37struct sdi_clk_calc_ctx {
  38        struct sdi_device *sdi;
  39        unsigned long pck_min, pck_max;
  40
  41        unsigned long fck;
  42        struct dispc_clock_info dispc_cinfo;
  43};
  44
  45static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
  46                unsigned long pck, void *data)
  47{
  48        struct sdi_clk_calc_ctx *ctx = data;
  49
  50        ctx->dispc_cinfo.lck_div = lckd;
  51        ctx->dispc_cinfo.pck_div = pckd;
  52        ctx->dispc_cinfo.lck = lck;
  53        ctx->dispc_cinfo.pck = pck;
  54
  55        return true;
  56}
  57
  58static bool dpi_calc_dss_cb(unsigned long fck, void *data)
  59{
  60        struct sdi_clk_calc_ctx *ctx = data;
  61
  62        ctx->fck = fck;
  63
  64        return dispc_div_calc(ctx->sdi->dss->dispc, fck,
  65                              ctx->pck_min, ctx->pck_max,
  66                              dpi_calc_dispc_cb, ctx);
  67}
  68
  69static int sdi_calc_clock_div(struct sdi_device *sdi, unsigned long pclk,
  70                              unsigned long *fck,
  71                              struct dispc_clock_info *dispc_cinfo)
  72{
  73        int i;
  74        struct sdi_clk_calc_ctx ctx;
  75
  76        /*
  77         * DSS fclk gives us very few possibilities, so finding a good pixel
  78         * clock may not be possible. We try multiple times to find the clock,
  79         * each time widening the pixel clock range we look for, up to
  80         * +/- 1MHz.
  81         */
  82
  83        for (i = 0; i < 10; ++i) {
  84                bool ok;
  85
  86                memset(&ctx, 0, sizeof(ctx));
  87
  88                ctx.sdi = sdi;
  89
  90                if (pclk > 1000 * i * i * i)
  91                        ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
  92                else
  93                        ctx.pck_min = 0;
  94                ctx.pck_max = pclk + 1000 * i * i * i;
  95
  96                ok = dss_div_calc(sdi->dss, pclk, ctx.pck_min,
  97                                  dpi_calc_dss_cb, &ctx);
  98                if (ok) {
  99                        *fck = ctx.fck;
 100                        *dispc_cinfo = ctx.dispc_cinfo;
 101                        return 0;
 102                }
 103        }
 104
 105        return -EINVAL;
 106}
 107
 108static void sdi_config_lcd_manager(struct sdi_device *sdi)
 109{
 110        sdi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 111
 112        sdi->mgr_config.stallmode = false;
 113        sdi->mgr_config.fifohandcheck = false;
 114
 115        sdi->mgr_config.video_port_width = 24;
 116        sdi->mgr_config.lcden_sig_polarity = 1;
 117
 118        dss_mgr_set_lcd_config(&sdi->output, &sdi->mgr_config);
 119}
 120
 121static void sdi_display_enable(struct omap_dss_device *dssdev)
 122{
 123        struct sdi_device *sdi = dssdev_to_sdi(dssdev);
 124        struct dispc_clock_info dispc_cinfo;
 125        unsigned long fck;
 126        int r;
 127
 128        r = regulator_enable(sdi->vdds_sdi_reg);
 129        if (r)
 130                return;
 131
 132        r = dispc_runtime_get(sdi->dss->dispc);
 133        if (r)
 134                goto err_get_dispc;
 135
 136        r = sdi_calc_clock_div(sdi, sdi->pixelclock, &fck, &dispc_cinfo);
 137        if (r)
 138                goto err_calc_clock_div;
 139
 140        sdi->mgr_config.clock_info = dispc_cinfo;
 141
 142        r = dss_set_fck_rate(sdi->dss, fck);
 143        if (r)
 144                goto err_set_dss_clock_div;
 145
 146        sdi_config_lcd_manager(sdi);
 147
 148        /*
 149         * LCLK and PCLK divisors are located in shadow registers, and we
 150         * normally write them to DISPC registers when enabling the output.
 151         * However, SDI uses pck-free as source clock for its PLL, and pck-free
 152         * is affected by the divisors. And as we need the PLL before enabling
 153         * the output, we need to write the divisors early.
 154         *
 155         * It seems just writing to the DISPC register is enough, and we don't
 156         * need to care about the shadow register mechanism for pck-free. The
 157         * exact reason for this is unknown.
 158         */
 159        dispc_mgr_set_clock_div(sdi->dss->dispc, sdi->output.dispc_channel,
 160                                &sdi->mgr_config.clock_info);
 161
 162        dss_sdi_init(sdi->dss, sdi->datapairs);
 163        r = dss_sdi_enable(sdi->dss);
 164        if (r)
 165                goto err_sdi_enable;
 166        mdelay(2);
 167
 168        r = dss_mgr_enable(&sdi->output);
 169        if (r)
 170                goto err_mgr_enable;
 171
 172        return;
 173
 174err_mgr_enable:
 175        dss_sdi_disable(sdi->dss);
 176err_sdi_enable:
 177err_set_dss_clock_div:
 178err_calc_clock_div:
 179        dispc_runtime_put(sdi->dss->dispc);
 180err_get_dispc:
 181        regulator_disable(sdi->vdds_sdi_reg);
 182}
 183
 184static void sdi_display_disable(struct omap_dss_device *dssdev)
 185{
 186        struct sdi_device *sdi = dssdev_to_sdi(dssdev);
 187
 188        dss_mgr_disable(&sdi->output);
 189
 190        dss_sdi_disable(sdi->dss);
 191
 192        dispc_runtime_put(sdi->dss->dispc);
 193
 194        regulator_disable(sdi->vdds_sdi_reg);
 195}
 196
 197static void sdi_set_timings(struct omap_dss_device *dssdev,
 198                            const struct drm_display_mode *mode)
 199{
 200        struct sdi_device *sdi = dssdev_to_sdi(dssdev);
 201
 202        sdi->pixelclock = mode->clock * 1000;
 203}
 204
 205static int sdi_check_timings(struct omap_dss_device *dssdev,
 206                             struct drm_display_mode *mode)
 207{
 208        struct sdi_device *sdi = dssdev_to_sdi(dssdev);
 209        struct dispc_clock_info dispc_cinfo;
 210        unsigned long pixelclock = mode->clock * 1000;
 211        unsigned long fck;
 212        unsigned long pck;
 213        int r;
 214
 215        if (pixelclock == 0)
 216                return -EINVAL;
 217
 218        r = sdi_calc_clock_div(sdi, pixelclock, &fck, &dispc_cinfo);
 219        if (r)
 220                return r;
 221
 222        pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
 223
 224        if (pck != pixelclock) {
 225                DSSWARN("Pixel clock adjusted from %lu Hz to %lu Hz\n",
 226                        pixelclock, pck);
 227
 228                mode->clock = pck / 1000;
 229        }
 230
 231        return 0;
 232}
 233
 234static int sdi_connect(struct omap_dss_device *src,
 235                       struct omap_dss_device *dst)
 236{
 237        return omapdss_device_connect(dst->dss, dst, dst->next);
 238}
 239
 240static void sdi_disconnect(struct omap_dss_device *src,
 241                           struct omap_dss_device *dst)
 242{
 243        omapdss_device_disconnect(dst, dst->next);
 244}
 245
 246static const struct omap_dss_device_ops sdi_ops = {
 247        .connect = sdi_connect,
 248        .disconnect = sdi_disconnect,
 249
 250        .enable = sdi_display_enable,
 251        .disable = sdi_display_disable,
 252
 253        .check_timings = sdi_check_timings,
 254        .set_timings = sdi_set_timings,
 255};
 256
 257static int sdi_init_output(struct sdi_device *sdi)
 258{
 259        struct omap_dss_device *out = &sdi->output;
 260        int r;
 261
 262        out->dev = &sdi->pdev->dev;
 263        out->id = OMAP_DSS_OUTPUT_SDI;
 264        out->type = OMAP_DISPLAY_TYPE_SDI;
 265        out->name = "sdi.0";
 266        out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
 267        /* We have SDI only on OMAP3, where it's on port 1 */
 268        out->of_ports = BIT(1);
 269        out->ops = &sdi_ops;
 270        out->owner = THIS_MODULE;
 271        out->bus_flags = DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE     /* 15.5.9.1.2 */
 272                       | DRM_BUS_FLAG_SYNC_DRIVE_POSEDGE;
 273
 274        r = omapdss_device_init_output(out);
 275        if (r < 0)
 276                return r;
 277
 278        omapdss_device_register(out);
 279
 280        return 0;
 281}
 282
 283static void sdi_uninit_output(struct sdi_device *sdi)
 284{
 285        omapdss_device_unregister(&sdi->output);
 286        omapdss_device_cleanup_output(&sdi->output);
 287}
 288
 289int sdi_init_port(struct dss_device *dss, struct platform_device *pdev,
 290                  struct device_node *port)
 291{
 292        struct sdi_device *sdi;
 293        struct device_node *ep;
 294        u32 datapairs;
 295        int r;
 296
 297        sdi = kzalloc(sizeof(*sdi), GFP_KERNEL);
 298        if (!sdi)
 299                return -ENOMEM;
 300
 301        ep = of_get_next_child(port, NULL);
 302        if (!ep) {
 303                r = 0;
 304                goto err_free;
 305        }
 306
 307        r = of_property_read_u32(ep, "datapairs", &datapairs);
 308        of_node_put(ep);
 309        if (r) {
 310                DSSERR("failed to parse datapairs\n");
 311                goto err_free;
 312        }
 313
 314        sdi->datapairs = datapairs;
 315        sdi->dss = dss;
 316
 317        sdi->pdev = pdev;
 318        port->data = sdi;
 319
 320        sdi->vdds_sdi_reg = devm_regulator_get(&pdev->dev, "vdds_sdi");
 321        if (IS_ERR(sdi->vdds_sdi_reg)) {
 322                r = PTR_ERR(sdi->vdds_sdi_reg);
 323                if (r != -EPROBE_DEFER)
 324                        DSSERR("can't get VDDS_SDI regulator\n");
 325                goto err_free;
 326        }
 327
 328        r = sdi_init_output(sdi);
 329        if (r)
 330                goto err_free;
 331
 332        return 0;
 333
 334err_free:
 335        kfree(sdi);
 336
 337        return r;
 338}
 339
 340void sdi_uninit_port(struct device_node *port)
 341{
 342        struct sdi_device *sdi = port->data;
 343
 344        if (!sdi)
 345                return;
 346
 347        sdi_uninit_output(sdi);
 348        kfree(sdi);
 349}
 350