root/drivers/video/fbdev/omap2/omapfb/dss/sdi.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dpi_calc_dispc_cb
  2. dpi_calc_dss_cb
  3. sdi_calc_clock_div
  4. sdi_config_lcd_manager
  5. sdi_display_enable
  6. sdi_display_disable
  7. sdi_set_timings
  8. sdi_get_timings
  9. sdi_check_timings
  10. sdi_set_datapairs
  11. sdi_init_regulator
  12. sdi_connect
  13. sdi_disconnect
  14. sdi_init_output
  15. sdi_uninit_output
  16. sdi_bind
  17. sdi_unbind
  18. sdi_probe
  19. sdi_remove
  20. sdi_init_platform_driver
  21. sdi_uninit_platform_driver
  22. sdi_init_port
  23. sdi_uninit_port

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * linux/drivers/video/omap2/dss/sdi.c
   4  *
   5  * Copyright (C) 2009 Nokia Corporation
   6  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
   7  */
   8 
   9 #define DSS_SUBSYS_NAME "SDI"
  10 
  11 #include <linux/kernel.h>
  12 #include <linux/delay.h>
  13 #include <linux/err.h>
  14 #include <linux/regulator/consumer.h>
  15 #include <linux/export.h>
  16 #include <linux/platform_device.h>
  17 #include <linux/string.h>
  18 #include <linux/of.h>
  19 #include <linux/component.h>
  20 
  21 #include <video/omapfb_dss.h>
  22 #include "dss.h"
  23 
  24 static struct {
  25         struct platform_device *pdev;
  26 
  27         bool update_enabled;
  28         struct regulator *vdds_sdi_reg;
  29 
  30         struct dss_lcd_mgr_config mgr_config;
  31         struct omap_video_timings timings;
  32         int datapairs;
  33 
  34         struct omap_dss_device output;
  35 
  36         bool port_initialized;
  37 } sdi;
  38 
  39 struct sdi_clk_calc_ctx {
  40         unsigned long pck_min, pck_max;
  41 
  42         unsigned long fck;
  43         struct dispc_clock_info dispc_cinfo;
  44 };
  45 
  46 static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
  47                 unsigned long pck, void *data)
  48 {
  49         struct sdi_clk_calc_ctx *ctx = data;
  50 
  51         ctx->dispc_cinfo.lck_div = lckd;
  52         ctx->dispc_cinfo.pck_div = pckd;
  53         ctx->dispc_cinfo.lck = lck;
  54         ctx->dispc_cinfo.pck = pck;
  55 
  56         return true;
  57 }
  58 
  59 static bool dpi_calc_dss_cb(unsigned long fck, void *data)
  60 {
  61         struct sdi_clk_calc_ctx *ctx = data;
  62 
  63         ctx->fck = fck;
  64 
  65         return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
  66                         dpi_calc_dispc_cb, ctx);
  67 }
  68 
  69 static int sdi_calc_clock_div(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                 if (pclk > 1000 * i * i * i)
  88                         ctx.pck_min = max(pclk - 1000 * i * i * i, 0lu);
  89                 else
  90                         ctx.pck_min = 0;
  91                 ctx.pck_max = pclk + 1000 * i * i * i;
  92 
  93                 ok = dss_div_calc(pclk, ctx.pck_min, dpi_calc_dss_cb, &ctx);
  94                 if (ok) {
  95                         *fck = ctx.fck;
  96                         *dispc_cinfo = ctx.dispc_cinfo;
  97                         return 0;
  98                 }
  99         }
 100 
 101         return -EINVAL;
 102 }
 103 
 104 static void sdi_config_lcd_manager(struct omap_dss_device *dssdev)
 105 {
 106         struct omap_overlay_manager *mgr = sdi.output.manager;
 107 
 108         sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 109 
 110         sdi.mgr_config.stallmode = false;
 111         sdi.mgr_config.fifohandcheck = false;
 112 
 113         sdi.mgr_config.video_port_width = 24;
 114         sdi.mgr_config.lcden_sig_polarity = 1;
 115 
 116         dss_mgr_set_lcd_config(mgr, &sdi.mgr_config);
 117 }
 118 
 119 static int sdi_display_enable(struct omap_dss_device *dssdev)
 120 {
 121         struct omap_dss_device *out = &sdi.output;
 122         struct omap_video_timings *t = &sdi.timings;
 123         unsigned long fck;
 124         struct dispc_clock_info dispc_cinfo;
 125         unsigned long pck;
 126         int r;
 127 
 128         if (out->manager == NULL) {
 129                 DSSERR("failed to enable display: no output/manager\n");
 130                 return -ENODEV;
 131         }
 132 
 133         r = regulator_enable(sdi.vdds_sdi_reg);
 134         if (r)
 135                 goto err_reg_enable;
 136 
 137         r = dispc_runtime_get();
 138         if (r)
 139                 goto err_get_dispc;
 140 
 141         /* 15.5.9.1.2 */
 142         t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
 143         t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE;
 144 
 145         r = sdi_calc_clock_div(t->pixelclock, &fck, &dispc_cinfo);
 146         if (r)
 147                 goto err_calc_clock_div;
 148 
 149         sdi.mgr_config.clock_info = dispc_cinfo;
 150 
 151         pck = fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div;
 152 
 153         if (pck != t->pixelclock) {
 154                 DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
 155                         t->pixelclock, pck);
 156 
 157                 t->pixelclock = pck;
 158         }
 159 
 160 
 161         dss_mgr_set_timings(out->manager, t);
 162 
 163         r = dss_set_fck_rate(fck);
 164         if (r)
 165                 goto err_set_dss_clock_div;
 166 
 167         sdi_config_lcd_manager(dssdev);
 168 
 169         /*
 170          * LCLK and PCLK divisors are located in shadow registers, and we
 171          * normally write them to DISPC registers when enabling the output.
 172          * However, SDI uses pck-free as source clock for its PLL, and pck-free
 173          * is affected by the divisors. And as we need the PLL before enabling
 174          * the output, we need to write the divisors early.
 175          *
 176          * It seems just writing to the DISPC register is enough, and we don't
 177          * need to care about the shadow register mechanism for pck-free. The
 178          * exact reason for this is unknown.
 179          */
 180         dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info);
 181 
 182         dss_sdi_init(sdi.datapairs);
 183         r = dss_sdi_enable();
 184         if (r)
 185                 goto err_sdi_enable;
 186         mdelay(2);
 187 
 188         r = dss_mgr_enable(out->manager);
 189         if (r)
 190                 goto err_mgr_enable;
 191 
 192         return 0;
 193 
 194 err_mgr_enable:
 195         dss_sdi_disable();
 196 err_sdi_enable:
 197 err_set_dss_clock_div:
 198 err_calc_clock_div:
 199         dispc_runtime_put();
 200 err_get_dispc:
 201         regulator_disable(sdi.vdds_sdi_reg);
 202 err_reg_enable:
 203         return r;
 204 }
 205 
 206 static void sdi_display_disable(struct omap_dss_device *dssdev)
 207 {
 208         struct omap_overlay_manager *mgr = sdi.output.manager;
 209 
 210         dss_mgr_disable(mgr);
 211 
 212         dss_sdi_disable();
 213 
 214         dispc_runtime_put();
 215 
 216         regulator_disable(sdi.vdds_sdi_reg);
 217 }
 218 
 219 static void sdi_set_timings(struct omap_dss_device *dssdev,
 220                 struct omap_video_timings *timings)
 221 {
 222         sdi.timings = *timings;
 223 }
 224 
 225 static void sdi_get_timings(struct omap_dss_device *dssdev,
 226                 struct omap_video_timings *timings)
 227 {
 228         *timings = sdi.timings;
 229 }
 230 
 231 static int sdi_check_timings(struct omap_dss_device *dssdev,
 232                         struct omap_video_timings *timings)
 233 {
 234         struct omap_overlay_manager *mgr = sdi.output.manager;
 235 
 236         if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
 237                 return -EINVAL;
 238 
 239         if (timings->pixelclock == 0)
 240                 return -EINVAL;
 241 
 242         return 0;
 243 }
 244 
 245 static void sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs)
 246 {
 247         sdi.datapairs = datapairs;
 248 }
 249 
 250 static int sdi_init_regulator(void)
 251 {
 252         struct regulator *vdds_sdi;
 253 
 254         if (sdi.vdds_sdi_reg)
 255                 return 0;
 256 
 257         vdds_sdi = devm_regulator_get(&sdi.pdev->dev, "vdds_sdi");
 258         if (IS_ERR(vdds_sdi)) {
 259                 if (PTR_ERR(vdds_sdi) != -EPROBE_DEFER)
 260                         DSSERR("can't get VDDS_SDI regulator\n");
 261                 return PTR_ERR(vdds_sdi);
 262         }
 263 
 264         sdi.vdds_sdi_reg = vdds_sdi;
 265 
 266         return 0;
 267 }
 268 
 269 static int sdi_connect(struct omap_dss_device *dssdev,
 270                 struct omap_dss_device *dst)
 271 {
 272         struct omap_overlay_manager *mgr;
 273         int r;
 274 
 275         r = sdi_init_regulator();
 276         if (r)
 277                 return r;
 278 
 279         mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
 280         if (!mgr)
 281                 return -ENODEV;
 282 
 283         r = dss_mgr_connect(mgr, dssdev);
 284         if (r)
 285                 return r;
 286 
 287         r = omapdss_output_set_device(dssdev, dst);
 288         if (r) {
 289                 DSSERR("failed to connect output to new device: %s\n",
 290                                 dst->name);
 291                 dss_mgr_disconnect(mgr, dssdev);
 292                 return r;
 293         }
 294 
 295         return 0;
 296 }
 297 
 298 static void sdi_disconnect(struct omap_dss_device *dssdev,
 299                 struct omap_dss_device *dst)
 300 {
 301         WARN_ON(dst != dssdev->dst);
 302 
 303         if (dst != dssdev->dst)
 304                 return;
 305 
 306         omapdss_output_unset_device(dssdev);
 307 
 308         if (dssdev->manager)
 309                 dss_mgr_disconnect(dssdev->manager, dssdev);
 310 }
 311 
 312 static const struct omapdss_sdi_ops sdi_ops = {
 313         .connect = sdi_connect,
 314         .disconnect = sdi_disconnect,
 315 
 316         .enable = sdi_display_enable,
 317         .disable = sdi_display_disable,
 318 
 319         .check_timings = sdi_check_timings,
 320         .set_timings = sdi_set_timings,
 321         .get_timings = sdi_get_timings,
 322 
 323         .set_datapairs = sdi_set_datapairs,
 324 };
 325 
 326 static void sdi_init_output(struct platform_device *pdev)
 327 {
 328         struct omap_dss_device *out = &sdi.output;
 329 
 330         out->dev = &pdev->dev;
 331         out->id = OMAP_DSS_OUTPUT_SDI;
 332         out->output_type = OMAP_DISPLAY_TYPE_SDI;
 333         out->name = "sdi.0";
 334         out->dispc_channel = OMAP_DSS_CHANNEL_LCD;
 335         /* We have SDI only on OMAP3, where it's on port 1 */
 336         out->port_num = 1;
 337         out->ops.sdi = &sdi_ops;
 338         out->owner = THIS_MODULE;
 339 
 340         omapdss_register_output(out);
 341 }
 342 
 343 static void sdi_uninit_output(struct platform_device *pdev)
 344 {
 345         struct omap_dss_device *out = &sdi.output;
 346 
 347         omapdss_unregister_output(out);
 348 }
 349 
 350 static int sdi_bind(struct device *dev, struct device *master, void *data)
 351 {
 352         struct platform_device *pdev = to_platform_device(dev);
 353 
 354         sdi.pdev = pdev;
 355 
 356         sdi_init_output(pdev);
 357 
 358         return 0;
 359 }
 360 
 361 static void sdi_unbind(struct device *dev, struct device *master, void *data)
 362 {
 363         struct platform_device *pdev = to_platform_device(dev);
 364 
 365         sdi_uninit_output(pdev);
 366 }
 367 
 368 static const struct component_ops sdi_component_ops = {
 369         .bind   = sdi_bind,
 370         .unbind = sdi_unbind,
 371 };
 372 
 373 static int sdi_probe(struct platform_device *pdev)
 374 {
 375         return component_add(&pdev->dev, &sdi_component_ops);
 376 }
 377 
 378 static int sdi_remove(struct platform_device *pdev)
 379 {
 380         component_del(&pdev->dev, &sdi_component_ops);
 381         return 0;
 382 }
 383 
 384 static struct platform_driver omap_sdi_driver = {
 385         .probe          = sdi_probe,
 386         .remove         = sdi_remove,
 387         .driver         = {
 388                 .name   = "omapdss_sdi",
 389                 .suppress_bind_attrs = true,
 390         },
 391 };
 392 
 393 int __init sdi_init_platform_driver(void)
 394 {
 395         return platform_driver_register(&omap_sdi_driver);
 396 }
 397 
 398 void sdi_uninit_platform_driver(void)
 399 {
 400         platform_driver_unregister(&omap_sdi_driver);
 401 }
 402 
 403 int sdi_init_port(struct platform_device *pdev, struct device_node *port)
 404 {
 405         struct device_node *ep;
 406         u32 datapairs;
 407         int r;
 408 
 409         ep = omapdss_of_get_next_endpoint(port, NULL);
 410         if (!ep)
 411                 return 0;
 412 
 413         r = of_property_read_u32(ep, "datapairs", &datapairs);
 414         if (r) {
 415                 DSSERR("failed to parse datapairs\n");
 416                 goto err_datapairs;
 417         }
 418 
 419         sdi.datapairs = datapairs;
 420 
 421         of_node_put(ep);
 422 
 423         sdi.pdev = pdev;
 424 
 425         sdi_init_output(pdev);
 426 
 427         sdi.port_initialized = true;
 428 
 429         return 0;
 430 
 431 err_datapairs:
 432         of_node_put(ep);
 433 
 434         return r;
 435 }
 436 
 437 void sdi_uninit_port(struct device_node *port)
 438 {
 439         if (!sdi.port_initialized)
 440                 return;
 441 
 442         sdi_uninit_output(sdi.pdev);
 443 }

/* [<][>][^][v][top][bottom][index][help] */