linux/drivers/video/sh_mipi_dsi.c
<<
>>
Prefs
   1/*
   2 * Renesas SH-mobile MIPI DSI support
   3 *
   4 * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
   5 *
   6 * This is free software; you can redistribute it and/or modify
   7 * it under the terms of version 2 of the GNU General Public License as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/bitmap.h>
  12#include <linux/clk.h>
  13#include <linux/delay.h>
  14#include <linux/init.h>
  15#include <linux/io.h>
  16#include <linux/platform_device.h>
  17#include <linux/pm_runtime.h>
  18#include <linux/slab.h>
  19#include <linux/string.h>
  20#include <linux/types.h>
  21#include <linux/module.h>
  22
  23#include <video/mipi_display.h>
  24#include <video/sh_mipi_dsi.h>
  25#include <video/sh_mobile_lcdc.h>
  26
  27#include "sh_mobile_lcdcfb.h"
  28
  29#define SYSCTRL         0x0000
  30#define SYSCONF         0x0004
  31#define TIMSET          0x0008
  32#define RESREQSET0      0x0018
  33#define RESREQSET1      0x001c
  34#define HSTTOVSET       0x0020
  35#define LPRTOVSET       0x0024
  36#define TATOVSET        0x0028
  37#define PRTOVSET        0x002c
  38#define DSICTRL         0x0030
  39#define DSIINTE         0x0060
  40#define PHYCTRL         0x0070
  41
  42/* relative to linkbase */
  43#define DTCTR           0x0000
  44#define VMCTR1          0x0020
  45#define VMCTR2          0x0024
  46#define VMLEN1          0x0028
  47#define VMLEN2          0x002c
  48#define CMTSRTREQ       0x0070
  49#define CMTSRTCTR       0x00d0
  50
  51/* E.g., sh7372 has 2 MIPI-DSIs - one for each LCDC */
  52#define MAX_SH_MIPI_DSI 2
  53
  54struct sh_mipi {
  55        struct sh_mobile_lcdc_entity entity;
  56
  57        void __iomem    *base;
  58        void __iomem    *linkbase;
  59        struct clk      *dsit_clk;
  60        struct platform_device *pdev;
  61};
  62
  63#define to_sh_mipi(e)   container_of(e, struct sh_mipi, entity)
  64
  65static struct sh_mipi *mipi_dsi[MAX_SH_MIPI_DSI];
  66
  67/* Protect the above array */
  68static DEFINE_MUTEX(array_lock);
  69
  70static struct sh_mipi *sh_mipi_by_handle(int handle)
  71{
  72        if (handle >= ARRAY_SIZE(mipi_dsi) || handle < 0)
  73                return NULL;
  74
  75        return mipi_dsi[handle];
  76}
  77
  78static int sh_mipi_send_short(struct sh_mipi *mipi, u8 dsi_cmd,
  79                              u8 cmd, u8 param)
  80{
  81        u32 data = (dsi_cmd << 24) | (cmd << 16) | (param << 8);
  82        int cnt = 100;
  83
  84        /* transmit a short packet to LCD panel */
  85        iowrite32(1 | data, mipi->linkbase + CMTSRTCTR);
  86        iowrite32(1, mipi->linkbase + CMTSRTREQ);
  87
  88        while ((ioread32(mipi->linkbase + CMTSRTREQ) & 1) && --cnt)
  89                udelay(1);
  90
  91        return cnt ? 0 : -ETIMEDOUT;
  92}
  93
  94#define LCD_CHAN2MIPI(c) ((c) < LCDC_CHAN_MAINLCD || (c) > LCDC_CHAN_SUBLCD ? \
  95                                -EINVAL : (c) - 1)
  96
  97static int sh_mipi_dcs(int handle, u8 cmd)
  98{
  99        struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
 100        if (!mipi)
 101                return -ENODEV;
 102        return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE, cmd, 0);
 103}
 104
 105static int sh_mipi_dcs_param(int handle, u8 cmd, u8 param)
 106{
 107        struct sh_mipi *mipi = sh_mipi_by_handle(LCD_CHAN2MIPI(handle));
 108        if (!mipi)
 109                return -ENODEV;
 110        return sh_mipi_send_short(mipi, MIPI_DSI_DCS_SHORT_WRITE_PARAM, cmd,
 111                                  param);
 112}
 113
 114static void sh_mipi_dsi_enable(struct sh_mipi *mipi, bool enable)
 115{
 116        /*
 117         * enable LCDC data tx, transition to LPS after completion of each HS
 118         * packet
 119         */
 120        iowrite32(0x00000002 | enable, mipi->linkbase + DTCTR);
 121}
 122
 123static void sh_mipi_shutdown(struct platform_device *pdev)
 124{
 125        struct sh_mipi *mipi = to_sh_mipi(platform_get_drvdata(pdev));
 126
 127        sh_mipi_dsi_enable(mipi, false);
 128}
 129
 130static int sh_mipi_setup(struct sh_mipi *mipi, const struct fb_videomode *mode)
 131{
 132        void __iomem *base = mipi->base;
 133        struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data;
 134        u32 pctype, datatype, pixfmt, linelength, vmctr2;
 135        u32 tmp, top, bottom, delay, div;
 136        int bpp;
 137
 138        /*
 139         * Select data format. MIPI DSI is not hot-pluggable, so, we just use
 140         * the default videomode. If this ever becomes a problem, We'll have to
 141         * move this to mipi_display_on() above and use info->var.xres
 142         */
 143        switch (pdata->data_format) {
 144        case MIPI_RGB888:
 145                pctype = 0;
 146                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
 147                pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
 148                linelength = mode->xres * 3;
 149                break;
 150        case MIPI_RGB565:
 151                pctype = 1;
 152                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
 153                pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
 154                linelength = mode->xres * 2;
 155                break;
 156        case MIPI_RGB666_LP:
 157                pctype = 2;
 158                datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
 159                pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
 160                linelength = mode->xres * 3;
 161                break;
 162        case MIPI_RGB666:
 163                pctype = 3;
 164                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
 165                pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
 166                linelength = (mode->xres * 18 + 7) / 8;
 167                break;
 168        case MIPI_BGR888:
 169                pctype = 8;
 170                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24;
 171                pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
 172                linelength = mode->xres * 3;
 173                break;
 174        case MIPI_BGR565:
 175                pctype = 9;
 176                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16;
 177                pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
 178                linelength = mode->xres * 2;
 179                break;
 180        case MIPI_BGR666_LP:
 181                pctype = 0xa;
 182                datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18;
 183                pixfmt = MIPI_DCS_PIXEL_FMT_24BIT;
 184                linelength = mode->xres * 3;
 185                break;
 186        case MIPI_BGR666:
 187                pctype = 0xb;
 188                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18;
 189                pixfmt = MIPI_DCS_PIXEL_FMT_18BIT;
 190                linelength = (mode->xres * 18 + 7) / 8;
 191                break;
 192        case MIPI_YUYV:
 193                pctype = 4;
 194                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
 195                pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
 196                linelength = mode->xres * 2;
 197                break;
 198        case MIPI_UYVY:
 199                pctype = 5;
 200                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16;
 201                pixfmt = MIPI_DCS_PIXEL_FMT_16BIT;
 202                linelength = mode->xres * 2;
 203                break;
 204        case MIPI_YUV420_L:
 205                pctype = 6;
 206                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
 207                pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
 208                linelength = (mode->xres * 12 + 7) / 8;
 209                break;
 210        case MIPI_YUV420:
 211                pctype = 7;
 212                datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12;
 213                pixfmt = MIPI_DCS_PIXEL_FMT_12BIT;
 214                /* Length of U/V line */
 215                linelength = (mode->xres + 1) / 2;
 216                break;
 217        default:
 218                return -EINVAL;
 219        }
 220
 221        if (!pdata->lane)
 222                return -EINVAL;
 223
 224        /* reset DSI link */
 225        iowrite32(0x00000001, base + SYSCTRL);
 226        /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */
 227        udelay(50);
 228        iowrite32(0x00000000, base + SYSCTRL);
 229
 230        /* setup DSI link */
 231
 232        /*
 233         * T_wakeup = 0x7000
 234         * T_hs-trail = 3
 235         * T_hs-prepare = 3
 236         * T_clk-trail = 3
 237         * T_clk-prepare = 2
 238         */
 239        iowrite32(0x70003332, base + TIMSET);
 240        /* no responses requested */
 241        iowrite32(0x00000000, base + RESREQSET0);
 242        /* request response to packets of type 0x28 */
 243        iowrite32(0x00000100, base + RESREQSET1);
 244        /* High-speed transmission timeout, default 0xffffffff */
 245        iowrite32(0x0fffffff, base + HSTTOVSET);
 246        /* LP reception timeout, default 0xffffffff */
 247        iowrite32(0x0fffffff, base + LPRTOVSET);
 248        /* Turn-around timeout, default 0xffffffff */
 249        iowrite32(0x0fffffff, base + TATOVSET);
 250        /* Peripheral reset timeout, default 0xffffffff */
 251        iowrite32(0x0fffffff, base + PRTOVSET);
 252        /* Interrupts not used, disable all */
 253        iowrite32(0, base + DSIINTE);
 254        /* DSI-Tx bias on */
 255        iowrite32(0x00000001, base + PHYCTRL);
 256        udelay(200);
 257        /* Deassert resets, power on */
 258        iowrite32(0x03070001 | pdata->phyctrl, base + PHYCTRL);
 259
 260        /*
 261         * Default = ULPS enable |
 262         *      Contention detection enabled |
 263         *      EoT packet transmission enable |
 264         *      CRC check enable |
 265         *      ECC check enable
 266         */
 267        bitmap_fill((unsigned long *)&tmp, pdata->lane);
 268        tmp |= 0x00003700;
 269        iowrite32(tmp, base + SYSCONF);
 270
 271        /* setup l-bridge */
 272
 273        /*
 274         * Enable transmission of all packets,
 275         * transmit LPS after each HS packet completion
 276         */
 277        iowrite32(0x00000006, mipi->linkbase + DTCTR);
 278        /* VSYNC width = 2 (<< 17) */
 279        iowrite32((mode->vsync_len << pdata->vsynw_offset) |
 280                  (pdata->clksrc << 16) | (pctype << 12) | datatype,
 281                  mipi->linkbase + VMCTR1);
 282
 283        /*
 284         * Non-burst mode with sync pulses: VSE and HSE are output,
 285         * HSA period allowed, no commands in LP
 286         */
 287        vmctr2 = 0;
 288        if (pdata->flags & SH_MIPI_DSI_VSEE)
 289                vmctr2 |= 1 << 23;
 290        if (pdata->flags & SH_MIPI_DSI_HSEE)
 291                vmctr2 |= 1 << 22;
 292        if (pdata->flags & SH_MIPI_DSI_HSAE)
 293                vmctr2 |= 1 << 21;
 294        if (pdata->flags & SH_MIPI_DSI_BL2E)
 295                vmctr2 |= 1 << 17;
 296        if (pdata->flags & SH_MIPI_DSI_HSABM)
 297                vmctr2 |= 1 << 5;
 298        if (pdata->flags & SH_MIPI_DSI_HBPBM)
 299                vmctr2 |= 1 << 4;
 300        if (pdata->flags & SH_MIPI_DSI_HFPBM)
 301                vmctr2 |= 1 << 3;
 302        iowrite32(vmctr2, mipi->linkbase + VMCTR2);
 303
 304        /*
 305         * VMLEN1 = RGBLEN | HSALEN
 306         *
 307         * see
 308         *  Video mode - Blanking Packet setting
 309         */
 310        top = linelength << 16; /* RGBLEN */
 311        bottom = 0x00000001;
 312        if (pdata->flags & SH_MIPI_DSI_HSABM) /* HSALEN */
 313                bottom = (pdata->lane * mode->hsync_len) - 10;
 314        iowrite32(top | bottom , mipi->linkbase + VMLEN1);
 315
 316        /*
 317         * VMLEN2 = HBPLEN | HFPLEN
 318         *
 319         * see
 320         *  Video mode - Blanking Packet setting
 321         */
 322        top     = 0x00010000;
 323        bottom  = 0x00000001;
 324        delay   = 0;
 325
 326        div = 1;        /* HSbyteCLK is calculation base
 327                         * HS4divCLK = HSbyteCLK/2
 328                         * HS6divCLK is not supported for now */
 329        if (pdata->flags & SH_MIPI_DSI_HS4divCLK)
 330                div = 2;
 331
 332        if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */
 333                top = mode->hsync_len + mode->left_margin;
 334                top = ((pdata->lane * top / div) - 10) << 16;
 335        }
 336        if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */
 337                bottom = mode->right_margin;
 338                bottom = (pdata->lane * bottom / div) - 12;
 339        }
 340
 341        bpp = linelength / mode->xres; /* byte / pixel */
 342        if ((pdata->lane / div) > bpp) {
 343                tmp = mode->xres / bpp; /* output cycle */
 344                tmp = mode->xres - tmp; /* (input - output) cycle */
 345                delay = (pdata->lane * tmp);
 346        }
 347
 348        iowrite32(top | (bottom + delay) , mipi->linkbase + VMLEN2);
 349
 350        msleep(5);
 351
 352        /* setup LCD panel */
 353
 354        /* cf. drivers/video/omap/lcd_mipid.c */
 355        sh_mipi_dcs(pdata->channel, MIPI_DCS_EXIT_SLEEP_MODE);
 356        msleep(120);
 357        /*
 358         * [7] - Page Address Mode
 359         * [6] - Column Address Mode
 360         * [5] - Page / Column Address Mode
 361         * [4] - Display Device Line Refresh Order
 362         * [3] - RGB/BGR Order
 363         * [2] - Display Data Latch Data Order
 364         * [1] - Flip Horizontal
 365         * [0] - Flip Vertical
 366         */
 367        sh_mipi_dcs_param(pdata->channel, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
 368        /* cf. set_data_lines() */
 369        sh_mipi_dcs_param(pdata->channel, MIPI_DCS_SET_PIXEL_FORMAT,
 370                          pixfmt << 4);
 371        sh_mipi_dcs(pdata->channel, MIPI_DCS_SET_DISPLAY_ON);
 372
 373        /* Enable timeout counters */
 374        iowrite32(0x00000f00, base + DSICTRL);
 375
 376        return 0;
 377}
 378
 379static int mipi_display_on(struct sh_mobile_lcdc_entity *entity)
 380{
 381        struct sh_mipi *mipi = to_sh_mipi(entity);
 382        struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data;
 383        int ret;
 384
 385        pm_runtime_get_sync(&mipi->pdev->dev);
 386
 387        ret = pdata->set_dot_clock(mipi->pdev, mipi->base, 1);
 388        if (ret < 0)
 389                goto mipi_display_on_fail1;
 390
 391        ret = sh_mipi_setup(mipi, &entity->def_mode);
 392        if (ret < 0)
 393                goto mipi_display_on_fail2;
 394
 395        sh_mipi_dsi_enable(mipi, true);
 396
 397        return SH_MOBILE_LCDC_DISPLAY_CONNECTED;
 398
 399mipi_display_on_fail1:
 400        pm_runtime_put_sync(&mipi->pdev->dev);
 401mipi_display_on_fail2:
 402        pdata->set_dot_clock(mipi->pdev, mipi->base, 0);
 403
 404        return ret;
 405}
 406
 407static void mipi_display_off(struct sh_mobile_lcdc_entity *entity)
 408{
 409        struct sh_mipi *mipi = to_sh_mipi(entity);
 410        struct sh_mipi_dsi_info *pdata = mipi->pdev->dev.platform_data;
 411
 412        sh_mipi_dsi_enable(mipi, false);
 413
 414        pdata->set_dot_clock(mipi->pdev, mipi->base, 0);
 415
 416        pm_runtime_put_sync(&mipi->pdev->dev);
 417}
 418
 419static const struct sh_mobile_lcdc_entity_ops mipi_ops = {
 420        .display_on = mipi_display_on,
 421        .display_off = mipi_display_off,
 422};
 423
 424static int __init sh_mipi_probe(struct platform_device *pdev)
 425{
 426        struct sh_mipi *mipi;
 427        struct sh_mipi_dsi_info *pdata = pdev->dev.platform_data;
 428        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 429        struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 430        unsigned long rate, f_current;
 431        int idx = pdev->id, ret;
 432
 433        if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata)
 434                return -ENODEV;
 435
 436        if (!pdata->set_dot_clock)
 437                return -EINVAL;
 438
 439        mutex_lock(&array_lock);
 440        if (idx < 0)
 441                for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++)
 442                        ;
 443
 444        if (idx == ARRAY_SIZE(mipi_dsi)) {
 445                ret = -EBUSY;
 446                goto efindslot;
 447        }
 448
 449        mipi = kzalloc(sizeof(*mipi), GFP_KERNEL);
 450        if (!mipi) {
 451                ret = -ENOMEM;
 452                goto ealloc;
 453        }
 454
 455        mipi->entity.owner = THIS_MODULE;
 456        mipi->entity.ops = &mipi_ops;
 457
 458        if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
 459                dev_err(&pdev->dev, "MIPI register region already claimed\n");
 460                ret = -EBUSY;
 461                goto ereqreg;
 462        }
 463
 464        mipi->base = ioremap(res->start, resource_size(res));
 465        if (!mipi->base) {
 466                ret = -ENOMEM;
 467                goto emap;
 468        }
 469
 470        if (!request_mem_region(res2->start, resource_size(res2), pdev->name)) {
 471                dev_err(&pdev->dev, "MIPI register region 2 already claimed\n");
 472                ret = -EBUSY;
 473                goto ereqreg2;
 474        }
 475
 476        mipi->linkbase = ioremap(res2->start, resource_size(res2));
 477        if (!mipi->linkbase) {
 478                ret = -ENOMEM;
 479                goto emap2;
 480        }
 481
 482        mipi->pdev = pdev;
 483
 484        mipi->dsit_clk = clk_get(&pdev->dev, "dsit_clk");
 485        if (IS_ERR(mipi->dsit_clk)) {
 486                ret = PTR_ERR(mipi->dsit_clk);
 487                goto eclktget;
 488        }
 489
 490        f_current = clk_get_rate(mipi->dsit_clk);
 491        /* 80MHz required by the datasheet */
 492        rate = clk_round_rate(mipi->dsit_clk, 80000000);
 493        if (rate > 0 && rate != f_current)
 494                ret = clk_set_rate(mipi->dsit_clk, rate);
 495        else
 496                ret = rate;
 497        if (ret < 0)
 498                goto esettrate;
 499
 500        dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate);
 501
 502        ret = clk_enable(mipi->dsit_clk);
 503        if (ret < 0)
 504                goto eclkton;
 505
 506        mipi_dsi[idx] = mipi;
 507
 508        pm_runtime_enable(&pdev->dev);
 509        pm_runtime_resume(&pdev->dev);
 510
 511        mutex_unlock(&array_lock);
 512        platform_set_drvdata(pdev, &mipi->entity);
 513
 514        return 0;
 515
 516eclkton:
 517esettrate:
 518        clk_put(mipi->dsit_clk);
 519eclktget:
 520        iounmap(mipi->linkbase);
 521emap2:
 522        release_mem_region(res2->start, resource_size(res2));
 523ereqreg2:
 524        iounmap(mipi->base);
 525emap:
 526        release_mem_region(res->start, resource_size(res));
 527ereqreg:
 528        kfree(mipi);
 529ealloc:
 530efindslot:
 531        mutex_unlock(&array_lock);
 532
 533        return ret;
 534}
 535
 536static int sh_mipi_remove(struct platform_device *pdev)
 537{
 538        struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 539        struct resource *res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 540        struct sh_mipi *mipi = to_sh_mipi(platform_get_drvdata(pdev));
 541        int i, ret;
 542
 543        mutex_lock(&array_lock);
 544
 545        for (i = 0; i < ARRAY_SIZE(mipi_dsi) && mipi_dsi[i] != mipi; i++)
 546                ;
 547
 548        if (i == ARRAY_SIZE(mipi_dsi)) {
 549                ret = -EINVAL;
 550        } else {
 551                ret = 0;
 552                mipi_dsi[i] = NULL;
 553        }
 554
 555        mutex_unlock(&array_lock);
 556
 557        if (ret < 0)
 558                return ret;
 559
 560        pm_runtime_disable(&pdev->dev);
 561        clk_disable(mipi->dsit_clk);
 562        clk_put(mipi->dsit_clk);
 563
 564        iounmap(mipi->linkbase);
 565        if (res2)
 566                release_mem_region(res2->start, resource_size(res2));
 567        iounmap(mipi->base);
 568        if (res)
 569                release_mem_region(res->start, resource_size(res));
 570        platform_set_drvdata(pdev, NULL);
 571        kfree(mipi);
 572
 573        return 0;
 574}
 575
 576static struct platform_driver sh_mipi_driver = {
 577        .remove         = sh_mipi_remove,
 578        .shutdown       = sh_mipi_shutdown,
 579        .driver = {
 580                .name   = "sh-mipi-dsi",
 581        },
 582};
 583
 584static int __init sh_mipi_init(void)
 585{
 586        return platform_driver_probe(&sh_mipi_driver, sh_mipi_probe);
 587}
 588module_init(sh_mipi_init);
 589
 590static void __exit sh_mipi_exit(void)
 591{
 592        platform_driver_unregister(&sh_mipi_driver);
 593}
 594module_exit(sh_mipi_exit);
 595
 596MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
 597MODULE_DESCRIPTION("SuperH / ARM-shmobile MIPI DSI driver");
 598MODULE_LICENSE("GPL v2");
 599
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.