linux/drivers/gpu/drm/xilinx/xilinx_drm_dsi.c
<<
>>
Prefs
   1/*
   2 * Xilinx FPGA MIPI DSI Tx Controller driver.
   3 *
   4 * Copyright (c) 2017 Xilinx Pvt., Ltd
   5 *
   6 * Contacts: Siva Rajesh J <siva.rajesh.jarugula@xilinx.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <drm/drm_crtc_helper.h>
  14#include <drm/drm_mipi_dsi.h>
  15#include <drm/drm_panel.h>
  16#include <drm/drmP.h>
  17#include <linux/component.h>
  18#include <linux/device.h>
  19#include <linux/of_device.h>
  20#include <linux/of_graph.h>
  21#include <linux/phy/phy.h>
  22#include <video/mipi_display.h>
  23#include <video/videomode.h>
  24
  25/* DSI Tx IP registers */
  26#define XDSI_CCR                        0x00
  27#define XDSI_CCR_COREENB                BIT(0)
  28#define XDSI_CCR_CRREADY                BIT(2)
  29#define XDSI_PCR                        0x04
  30#define XDSI_PCR_VIDEOMODE(x)           (((x) & 0x3) << 3)
  31#define XDSI_PCR_VIDEOMODE_MASK         (0x3 << 3)
  32#define XDSI_PCR_VIDEOMODE_SHIFT        3
  33#define XDSI_PCR_BLLPTYPE(x)            ((x) << 5)
  34#define XDSI_PCR_BLLPMODE(x)            ((x) << 6)
  35#define XDSI_PCR_EOTPENABLE(x)          ((x) << 13)
  36#define XDSI_GIER                       0x20
  37#define XDSI_ISR                        0x24
  38#define XDSI_IER                        0x28
  39#define XDSI_CMD                        0x30
  40#define XDSI_CMD_QUEUE_PACKET(x)        (((x) & 0xffffff) << 0)
  41#define XDSI_TIME1                      0x50
  42#define XDSI_TIME1_BLLP_BURST(x)        (((x) & 0xffff) << 0)
  43#define XDSI_TIME1_HSA(x)               (((x) & 0xffff) << 16)
  44#define XDSI_TIME2                      0x54
  45#define XDSI_TIME2_VACT(x)              (((x) & 0xffff) << 0)
  46#define XDSI_TIME2_HACT(x)              (((x) & 0xffff) << 16)
  47#define XDSI_TIME3                      0x58
  48#define XDSI_TIME3_HFP(x)               (((x) & 0xffff) << 0)
  49#define XDSI_TIME3_HBP(x)               (((x) & 0xffff) << 16)
  50#define XDSI_TIME4                      0x5c
  51#define XDSI_TIME4_VFP(x)               (((x) & 0xff) << 0)
  52#define XDSI_TIME4_VBP(x)               (((x) & 0xff) << 8)
  53#define XDSI_TIME4_VSA(x)               (((x) & 0xff) << 16)
  54#define XDSI_LTIME                      0x60
  55#define XDSI_BLLP_TIME                  0x64
  56#define XDSI_NUM_DATA_TYPES             5
  57#define XDSI_NUM_PIXELS_PER_BEAT        3
  58#define XDSI_VIDEO_MODE_SYNC_PULSE      0x0
  59#define XDSI_VIDEO_MODE_SYNC_EVENT      0x1
  60#define XDSI_VIDEO_MODE_BURST           0x2
  61
  62/**
  63 * used as a multiplication factor for HACT based on used
  64 * DSI data type and pixels per beat.
  65 * e.g. for RGB666_L with 2 pixels per beat, (6+6+6)*2 = 36.
  66 * To make it multiples of 8, 36+4 = 40.
  67 * So, multiplication factor is = 40/8 which gives 5
  68 */
  69int xdsi_mul_factor[XDSI_NUM_DATA_TYPES][XDSI_NUM_PIXELS_PER_BEAT] = {
  70        { 3, 6, 12 }, /* RGB888 = {1ppb, 2ppb, 4ppb} */
  71        { 3, 5, 9 }, /* RGB666_L = {1ppb, 2ppb, 4ppb} */
  72        { 3, 5, 9 }, /* RGB666_P = {1ppb, 2ppb, 4ppb} */
  73        { 2, 4, 8 }  /* RGB565 = {1ppb, 2ppb, 4ppb} */
  74};
  75
  76/*
  77 * struct xilinx_dsi - Core configuration DSI Tx subsystem device structure
  78 * @drm_encoder: DRM encoder structure
  79 * @dsi_host: DSI host device
  80 * @connector: DRM connector structure
  81 * @panel_node: MIPI DSI device panel node
  82 * @panel:  DRM panel structure
  83 * @dev: device structure
  84 * @iomem: Base address of DSI subsystem
  85 * @lanes: number of active data lanes supported by DSI controller
  86 * @mode_flags: DSI operation mode related flags
  87 * @format: pixel format for video mode of DSI controller
  88 * @vm: videomode data structure
  89 * @mul_factor: multiplication factor for HACT timing parameter
  90 * @eotp_prop: configurable EoTP DSI parameter
  91 * @bllp_mode_prop: configurable BLLP mode DSI parameter
  92 * @bllp_type_prop: configurable BLLP type DSI parameter
  93 * @video_mode_prop: configurable Video mode DSI parameter
  94 * @bllp_burst_time_prop: Configurable BLLP time for burst mode
  95 * @cmd_queue_prop: configurable command queue
  96 * @eotp_prop_val: configurable EoTP DSI parameter value
  97 * @bllp_mode_prop_val: configurable BLLP mode DSI parameter value
  98 * @bllp_type_prop_val: configurable BLLP type DSI parameter value
  99 * @video_mode_prop_val: configurable Video mode DSI parameter value
 100 * @bllp_burst_time_prop_val: Configurable BLLP time for burst mode value
 101 * @cmd_queue_prop_val: configurable command queue value
 102 */
 103struct xilinx_dsi {
 104        struct drm_encoder encoder;
 105        struct mipi_dsi_host dsi_host;
 106        struct drm_connector connector;
 107        struct device_node *panel_node;
 108        struct drm_panel *panel;
 109        struct device *dev;
 110        void __iomem *iomem;
 111        u32 lanes;
 112        u32 mode_flags;
 113        enum mipi_dsi_pixel_format format;
 114        struct videomode vm;
 115        u32 mul_factor;
 116        struct drm_property *eotp_prop;
 117        struct drm_property *bllp_mode_prop;
 118        struct drm_property *bllp_type_prop;
 119        struct drm_property *video_mode_prop;
 120        struct drm_property *bllp_burst_time_prop;
 121        struct drm_property *cmd_queue_prop;
 122        bool eotp_prop_val;
 123        bool bllp_mode_prop_val;
 124        bool bllp_type_prop_val;
 125        u32 video_mode_prop_val;
 126        u32 bllp_burst_time_prop_val;
 127        u32 cmd_queue_prop_val;
 128};
 129
 130#define host_to_dsi(host) container_of(host, struct xilinx_dsi, dsi_host)
 131#define connector_to_dsi(c) container_of(c, struct xilinx_dsi, connector)
 132#define encoder_to_dsi(e) container_of(e, struct xilinx_dsi, encoder)
 133
 134static inline void xilinx_dsi_writel(void __iomem *base, int offset, u32 val)
 135{
 136        writel(val, base + offset);
 137}
 138
 139static inline u32 xilinx_dsi_readl(void __iomem *base, int offset)
 140{
 141        return readl(base + offset);
 142}
 143
 144/**
 145 * xilinx_dsi_set_default_drm_properties - Configure DSI DRM
 146 * properties with their default values
 147 * @dsi: DSI structure having the updated user parameters
 148 */
 149static void
 150xilinx_dsi_set_default_drm_properties(struct xilinx_dsi *dsi)
 151{
 152        drm_object_property_set_value(&dsi->connector.base, dsi->eotp_prop, 1);
 153        drm_object_property_set_value(&dsi->connector.base,
 154                        dsi->bllp_mode_prop, 0);
 155        drm_object_property_set_value(&dsi->connector.base,
 156                        dsi->bllp_type_prop, 0);
 157        drm_object_property_set_value(&dsi->connector.base,
 158                        dsi->video_mode_prop, 0);
 159        drm_object_property_set_value(&dsi->connector.base,
 160                        dsi->bllp_burst_time_prop, 0);
 161        drm_object_property_set_value(&dsi->connector.base,
 162                        dsi->cmd_queue_prop, 0);
 163}
 164
 165/**
 166 * xilinx_dsi_set_config_parameters - Configure DSI Tx registers with parameters
 167 * given from user application.
 168 * @dsi: DSI structure having the updated user parameters
 169 *
 170 * This function takes the DSI structure having drm_property parameters
 171 * configured from  user application and writes them into DSI IP registers.
 172 */
 173static void xilinx_dsi_set_config_parameters(struct xilinx_dsi *dsi)
 174{
 175        u32 reg = 0;
 176
 177        reg |= XDSI_PCR_EOTPENABLE(dsi->eotp_prop_val);
 178        reg |= XDSI_PCR_VIDEOMODE(dsi->video_mode_prop_val);
 179        reg |= XDSI_PCR_BLLPTYPE(dsi->bllp_type_prop_val);
 180        reg |= XDSI_PCR_BLLPMODE(dsi->bllp_mode_prop_val);
 181
 182        xilinx_dsi_writel(dsi->iomem, XDSI_PCR, reg);
 183
 184        /* Configure the burst time if video mode is burst.
 185         * HSA of TIME1 register is ignored in this mode.
 186         */
 187        if (dsi->video_mode_prop_val == XDSI_VIDEO_MODE_BURST) {
 188                reg = XDSI_TIME1_BLLP_BURST(dsi->bllp_burst_time_prop_val);
 189                xilinx_dsi_writel(dsi->iomem, XDSI_TIME1, reg);
 190        }
 191
 192        reg = XDSI_CMD_QUEUE_PACKET(dsi->cmd_queue_prop_val);
 193        xilinx_dsi_writel(dsi->iomem, XDSI_CMD, reg);
 194
 195        dev_dbg(dsi->dev, "PCR register value is = %x\n",
 196                        xilinx_dsi_readl(dsi->iomem, XDSI_PCR));
 197}
 198
 199/**
 200 * xilinx_dsi_set_display_mode - Configure DSI timing registers
 201 * @dsi: DSI structure having the updated user parameters
 202 *
 203 * This function writes the timing parameters of DSI IP which are
 204 * retrieved from panel timing values.
 205 */
 206static void xilinx_dsi_set_display_mode(struct xilinx_dsi *dsi)
 207{
 208        struct videomode *vm = &dsi->vm;
 209        u32 reg, video_mode;
 210
 211        reg = xilinx_dsi_readl(dsi->iomem, XDSI_PCR);
 212        video_mode = ((reg & XDSI_PCR_VIDEOMODE_MASK) >>
 213                                XDSI_PCR_VIDEOMODE_SHIFT);
 214
 215        /* configure the HSA value only if non_burst_sync_pluse video mode */
 216        if ((!video_mode) &
 217                (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)) {
 218                reg = XDSI_TIME1_HSA(vm->hsync_len);
 219                xilinx_dsi_writel(dsi->iomem, XDSI_TIME1, reg);
 220        }
 221
 222        reg = XDSI_TIME4_VFP(vm->vfront_porch) |
 223                XDSI_TIME4_VBP(vm->vback_porch) |
 224                XDSI_TIME4_VSA(vm->vsync_len);
 225        xilinx_dsi_writel(dsi->iomem, XDSI_TIME4, reg);
 226
 227        reg = XDSI_TIME3_HFP(vm->hfront_porch) |
 228                XDSI_TIME3_HBP(vm->hback_porch);
 229        xilinx_dsi_writel(dsi->iomem, XDSI_TIME3, reg);
 230
 231        dev_dbg(dsi->dev, "mul factor for parsed datatype is = %d\n",
 232                        dsi->mul_factor);
 233
 234        reg = XDSI_TIME2_HACT((vm->hactive) * dsi->mul_factor) |
 235                XDSI_TIME2_VACT(vm->vactive);
 236        xilinx_dsi_writel(dsi->iomem, XDSI_TIME2, reg);
 237
 238        dev_dbg(dsi->dev, "LCD size = %dx%d\n", vm->hactive, vm->vactive);
 239}
 240
 241/**
 242 * xilinx_dsi_set_display_enable - Enables the DSI Tx IP core enable
 243 * register bit
 244 * @dsi: DSI structure having the updated user parameters
 245 *
 246 * This function takes the DSI strucure and enables the core enable bit
 247 * of core configuration register.
 248 */
 249static void xilinx_dsi_set_display_enable(struct xilinx_dsi *dsi)
 250{
 251        u32 reg;
 252
 253        reg = xilinx_dsi_readl(dsi->iomem, XDSI_CCR);
 254        reg |= XDSI_CCR_COREENB;
 255
 256        xilinx_dsi_writel(dsi->iomem, XDSI_CCR, reg);
 257        dev_dbg(dsi->dev, "MIPI DSI Tx controller is enabled.\n");
 258}
 259
 260/**
 261 * xilinx_dsi_set_display_disable - Disable the DSI Tx IP core enable
 262 * register bit
 263 * @dsi: DSI structure having the updated user parameters
 264 *
 265 * This function takes the DSI strucure and disables the core enable bit
 266 * of core configuration register.
 267 */
 268static void xilinx_dsi_set_display_disable(struct xilinx_dsi *dsi)
 269{
 270        u32 reg;
 271
 272        reg = xilinx_dsi_readl(dsi->iomem, XDSI_CCR);
 273        reg &= ~XDSI_CCR_COREENB;
 274
 275        xilinx_dsi_writel(dsi->iomem, XDSI_CCR, reg);
 276        dev_dbg(dsi->dev, "DSI Tx is disabled. reset regs to default values\n");
 277}
 278
 279
 280static void xilinx_dsi_encoder_dpms(struct drm_encoder *encoder,
 281                                        int mode)
 282{
 283        struct xilinx_dsi *dsi = encoder_to_dsi(encoder);
 284
 285        dev_dbg(dsi->dev, "encoder dpms state: %d\n", mode);
 286
 287        switch (mode) {
 288        case DRM_MODE_DPMS_ON:
 289                xilinx_dsi_set_display_enable(dsi);
 290                break;
 291        default:
 292                xilinx_dsi_set_display_disable(dsi);
 293                xilinx_dsi_set_default_drm_properties(dsi);
 294                break;
 295        }
 296}
 297
 298/**
 299 * xilinx_dsi_connector_set_property - implementation of drm_connector_funcs
 300 * set_property invoked by IOCTL call to DRM_IOCTL_MODE_OBJ_SETPROPERTY
 301 *
 302 * @base_connector: pointer Xilinx DSI connector
 303 * @property: pointer to the drm_property structure
 304 * @value: DSI parameter value that is configured from user application
 305 *
 306 * This function takes a drm_property name and value given from user application
 307 * and update the DSI structure property varabiles with the values.
 308 * These values are later used to configure the DSI Rx IP.
 309 *
 310 * Return: 0 on success OR -EINVAL if setting property fails
 311 */
 312static int
 313xilinx_dsi_connector_set_property(struct drm_connector *base_connector,
 314                                        struct drm_property *property,
 315                                        u64 value)
 316{
 317        struct xilinx_dsi *dsi = connector_to_dsi(base_connector);
 318
 319        dev_dbg(dsi->dev, "property name = %s, value = %lld\n",
 320                        property->name, value);
 321
 322        if (property == dsi->eotp_prop)
 323                dsi->eotp_prop_val = !!value;
 324        else if (property == dsi->bllp_mode_prop)
 325                dsi->bllp_mode_prop_val = !!value;
 326        else if (property == dsi->bllp_type_prop)
 327                dsi->bllp_type_prop_val = !!value;
 328        else if (property == dsi->video_mode_prop)
 329                dsi->video_mode_prop_val = (unsigned int)value;
 330        else if (property == dsi->bllp_burst_time_prop)
 331                dsi->bllp_burst_time_prop_val = (unsigned int)value;
 332        else if (property == dsi->cmd_queue_prop)
 333                dsi->cmd_queue_prop_val = (unsigned int)value;
 334        else
 335                return -EINVAL;
 336
 337        xilinx_dsi_set_config_parameters(dsi);
 338
 339        return 0;
 340}
 341
 342static int xilinx_dsi_host_attach(struct mipi_dsi_host *host,
 343                                        struct mipi_dsi_device *device)
 344{
 345        u32 panel_lanes;
 346        struct xilinx_dsi *dsi = host_to_dsi(host);
 347
 348        panel_lanes = device->lanes;
 349        dsi->mode_flags = device->mode_flags;
 350        dsi->panel_node = device->dev.of_node;
 351
 352        if (panel_lanes != dsi->lanes) {
 353                dev_err(dsi->dev, "Mismatch of lanes. panel = %d, DSI = %d\n",
 354                        panel_lanes, dsi->lanes);
 355                return -EINVAL;
 356        }
 357
 358        if ((dsi->lanes > 4) || (dsi->lanes < 1)) {
 359                dev_err(dsi->dev, "%d lanes : invalid xlnx,dsi-num-lanes\n",
 360                                dsi->lanes);
 361                return -EINVAL;
 362        }
 363
 364        if (device->format != dsi->format) {
 365                dev_err(dsi->dev, "Mismatch of format. panel = %d, DSI = %d\n",
 366                                device->format, dsi->format);
 367                return -EINVAL;
 368        }
 369
 370        if (dsi->connector.dev)
 371                drm_helper_hpd_irq_event(dsi->connector.dev);
 372
 373        return 0;
 374}
 375
 376static int xilinx_dsi_host_detach(struct mipi_dsi_host *host,
 377                                        struct mipi_dsi_device *device)
 378{
 379        struct xilinx_dsi *dsi = host_to_dsi(host);
 380
 381        dsi->panel_node = NULL;
 382
 383        if (dsi->connector.dev)
 384                drm_helper_hpd_irq_event(dsi->connector.dev);
 385
 386        return 0;
 387}
 388
 389static const struct mipi_dsi_host_ops xilinx_dsi_ops = {
 390        .attach = xilinx_dsi_host_attach,
 391        .detach = xilinx_dsi_host_detach,
 392};
 393
 394static int xilinx_dsi_connector_dpms(struct drm_connector *connector,
 395                                        int mode)
 396{
 397        struct xilinx_dsi *dsi = connector_to_dsi(connector);
 398        int ret;
 399        bool panel_on = 0;
 400
 401        dev_dbg(dsi->dev, "connector dpms state: %d\n", mode);
 402
 403        switch (mode) {
 404        case DRM_MODE_DPMS_ON:
 405                ret = drm_panel_prepare(dsi->panel);
 406                if (ret < 0)
 407                        return ret;
 408
 409                ret = drm_panel_enable(dsi->panel);
 410                if (ret < 0) {
 411                        drm_panel_unprepare(dsi->panel);
 412                        dev_err(dsi->dev, "DRM panel not enabled. power off DSI\n");
 413                        return ret;
 414                }
 415                break;
 416        default:
 417                drm_panel_disable(dsi->panel);
 418                drm_panel_unprepare(dsi->panel);
 419                break;
 420        }
 421
 422        return drm_helper_connector_dpms(connector, mode);
 423}
 424
 425static enum drm_connector_status
 426xilinx_dsi_detect(struct drm_connector *connector, bool force)
 427{
 428        struct xilinx_dsi *dsi = connector_to_dsi(connector);
 429
 430        if (!dsi->panel) {
 431                dsi->panel = of_drm_find_panel(dsi->panel_node);
 432                if (dsi->panel)
 433                        drm_panel_attach(dsi->panel, &dsi->connector);
 434        } else if (!dsi->panel_node) {
 435                xilinx_dsi_connector_dpms(connector, DRM_MODE_DPMS_OFF);
 436                drm_panel_detach(dsi->panel);
 437                dsi->panel = NULL;
 438        }
 439
 440        if (dsi->panel)
 441                return connector_status_connected;
 442
 443        return connector_status_disconnected;
 444}
 445
 446static void xilinx_dsi_connector_destroy(struct drm_connector *connector)
 447{
 448        drm_connector_unregister(connector);
 449        drm_connector_cleanup(connector);
 450        connector->dev = NULL;
 451}
 452
 453static struct drm_connector_funcs xilinx_dsi_connector_funcs = {
 454        .dpms = xilinx_dsi_connector_dpms,
 455        .detect = xilinx_dsi_detect,
 456        .fill_modes = drm_helper_probe_single_connector_modes,
 457        .destroy = xilinx_dsi_connector_destroy,
 458        .set_property = xilinx_dsi_connector_set_property,
 459};
 460
 461static int xilinx_dsi_get_modes(struct drm_connector *connector)
 462{
 463        struct xilinx_dsi *dsi = connector_to_dsi(connector);
 464
 465        if (dsi->panel)
 466                return dsi->panel->funcs->get_modes(dsi->panel);
 467
 468        return 0;
 469}
 470
 471static struct drm_encoder *
 472xilinx_dsi_best_encoder(struct drm_connector *connector)
 473{
 474        return &(connector_to_dsi(connector)->encoder);
 475}
 476
 477static struct drm_connector_helper_funcs xilinx_dsi_connector_helper_funcs = {
 478        .get_modes = xilinx_dsi_get_modes,
 479        .best_encoder = xilinx_dsi_best_encoder,
 480};
 481
 482/**
 483 * xilinx_drm_dsi_connector_create_property -  create DSI connector properties
 484 *
 485 * @base_connector: pointer to Xilinx DSI connector
 486 *
 487 * This function takes the xilinx DSI connector component and defines
 488 * the drm_property variables with their default values.
 489 */
 490static void
 491xilinx_drm_dsi_connector_create_property(struct drm_connector *base_connector)
 492{
 493        struct drm_device *dev = base_connector->dev;
 494        struct xilinx_dsi *dsi  = connector_to_dsi(base_connector);
 495
 496        dsi->eotp_prop = drm_property_create_bool(dev, 1, "eotp");
 497        dsi->video_mode_prop = drm_property_create_range(dev, 0,
 498                        "video_mode", 0, 2);
 499        dsi->bllp_mode_prop = drm_property_create_bool(dev, 0, "bllp_mode");
 500        dsi->bllp_type_prop = drm_property_create_bool(dev, 0, "bllp_type");
 501        dsi->bllp_burst_time_prop = drm_property_create_range(dev, 0,
 502                        "bllp_burst_time", 0, 0xFFFF);
 503        dsi->cmd_queue_prop = drm_property_create_range(dev, 0,
 504                        "cmd_queue", 0, 0xFFFFFF);
 505}
 506
 507/**
 508 * xilinx_drm_dsi_connector_attach_property -  attach DSI connector
 509 * properties
 510 *
 511 * @base_connector: pointer to Xilinx DSI connector
 512 */
 513static void
 514xilinx_drm_dsi_connector_attach_property(struct drm_connector *base_connector)
 515{
 516        struct xilinx_dsi *dsi = connector_to_dsi(base_connector);
 517        struct drm_mode_object *obj = &base_connector->base;
 518
 519        if (dsi->eotp_prop)
 520                drm_object_attach_property(obj, dsi->eotp_prop, 1);
 521
 522        if (dsi->video_mode_prop)
 523                drm_object_attach_property(obj, dsi->video_mode_prop, 0);
 524
 525        if (dsi->bllp_burst_time_prop)
 526                drm_object_attach_property(&base_connector->base,
 527                                        dsi->bllp_burst_time_prop, 0);
 528
 529        if (dsi->bllp_mode_prop)
 530                drm_object_attach_property(&base_connector->base,
 531                                        dsi->bllp_mode_prop, 0);
 532
 533        if (dsi->bllp_type_prop)
 534                drm_object_attach_property(&base_connector->base,
 535                                        dsi->bllp_type_prop, 0);
 536
 537        if (dsi->cmd_queue_prop)
 538                drm_object_attach_property(&base_connector->base,
 539                                dsi->cmd_queue_prop, 0);
 540}
 541
 542static int xilinx_dsi_create_connector(struct drm_encoder *encoder)
 543{
 544        struct xilinx_dsi *dsi = encoder_to_dsi(encoder);
 545        struct drm_connector *connector = &dsi->connector;
 546        int ret;
 547
 548        connector->polled = DRM_CONNECTOR_POLL_HPD;
 549
 550        ret = drm_connector_init(encoder->dev, connector,
 551                                 &xilinx_dsi_connector_funcs,
 552                                 DRM_MODE_CONNECTOR_DSI);
 553        if (ret) {
 554                dev_err(dsi->dev, "Failed to initialize connector with drm\n");
 555                return ret;
 556        }
 557
 558        drm_connector_helper_add(connector, &xilinx_dsi_connector_helper_funcs);
 559        drm_connector_register(connector);
 560        drm_mode_connector_attach_encoder(connector, encoder);
 561        xilinx_drm_dsi_connector_create_property(connector);
 562        xilinx_drm_dsi_connector_attach_property(connector);
 563
 564        return 0;
 565}
 566
 567static bool xilinx_dsi_mode_fixup(struct drm_encoder *encoder,
 568                                        const struct drm_display_mode *mode,
 569                                        struct drm_display_mode *adjusted_mode)
 570{
 571        return true;
 572}
 573
 574/**
 575 * xilinx_dsi_mode_set -  derive the DSI timing parameters
 576 *
 577 * @encoder: pointer to Xilinx DRM encoder
 578 * @mode: DRM kernel-internal display mode structure
 579 * @adjusted_mode: DSI panel timing parameters
 580 *
 581 * This function derives the DSI IP timing parameters from the timing
 582 * values given in the attached panel driver.
 583 */
 584static void xilinx_dsi_mode_set(struct drm_encoder *encoder,
 585                                struct drm_display_mode *mode,
 586                                struct drm_display_mode *adjusted_mode)
 587{
 588        struct xilinx_dsi *dsi = encoder_to_dsi(encoder);
 589        struct videomode *vm = &dsi->vm;
 590        struct drm_display_mode *m = adjusted_mode;
 591
 592        vm->hactive = m->hdisplay;
 593        vm->vactive = m->vdisplay;
 594        vm->vfront_porch = m->vsync_start - m->vdisplay;
 595        vm->vback_porch = m->vtotal - m->vsync_end;
 596        vm->vsync_len = m->vsync_end - m->vsync_start;
 597        vm->hfront_porch = m->hsync_start - m->hdisplay;
 598        vm->hback_porch = m->htotal - m->hsync_end;
 599        vm->hsync_len = m->hsync_end - m->hsync_start;
 600        xilinx_dsi_set_display_mode(dsi);
 601}
 602
 603static void xilinx_dsi_prepare(struct drm_encoder *encoder)
 604{
 605        struct xilinx_dsi *dsi = encoder_to_dsi(encoder);
 606
 607        dev_dbg(dsi->dev, "%s %d\n", __func__, __LINE__);
 608        xilinx_dsi_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 609}
 610
 611static void xilinx_dsi_commit(struct drm_encoder *encoder)
 612{
 613        struct xilinx_dsi *dsi = encoder_to_dsi(encoder);
 614
 615        dev_dbg(dsi->dev, "config and enable the DSI: %s %d\n",
 616                         __func__, __LINE__);
 617
 618        xilinx_dsi_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
 619}
 620
 621static struct drm_encoder_helper_funcs xilinx_dsi_encoder_helper_funcs = {
 622        .dpms = xilinx_dsi_encoder_dpms,
 623        .mode_fixup = xilinx_dsi_mode_fixup,
 624        .mode_set = xilinx_dsi_mode_set,
 625        .prepare = xilinx_dsi_prepare,
 626        .commit = xilinx_dsi_commit,
 627};
 628
 629static struct drm_encoder_funcs xilinx_dsi_encoder_funcs = {
 630        .destroy = drm_encoder_cleanup,
 631};
 632
 633static int xilinx_dsi_parse_dt(struct xilinx_dsi *dsi)
 634{
 635        struct device *dev = dsi->dev;
 636        struct device_node *node = dev->of_node;
 637        int ret;
 638        u32 pixels_per_beat, datatype;
 639
 640        ret = of_property_read_u32(node, "xlnx,dsi-num-lanes",
 641                                &dsi->lanes);
 642        if (ret < 0) {
 643                dev_err(dsi->dev, "missing xlnx,dsi-num-lanes property\n");
 644                return ret;
 645        }
 646
 647        if ((dsi->lanes > 4) || (dsi->lanes < 1)) {
 648                dev_err(dsi->dev, "%d lanes : invalid xlnx,dsi-num-lanes\n",
 649                        dsi->lanes);
 650                return -EINVAL;
 651        }
 652
 653        ret = of_property_read_u32(node, "xlnx,dsi-pixels-perbeat",
 654                                        &pixels_per_beat);
 655        if (ret < 0) {
 656                dev_err(dsi->dev, "missing xlnx,dsi-pixels-perbeat property\n");
 657                return ret;
 658        }
 659
 660        if ((pixels_per_beat != 1) &&
 661                (pixels_per_beat != 2) &&
 662                (pixels_per_beat != 4)) {
 663                dev_err(dsi->dev, "Wrong dts val xlnx,dsi-pixels-perbeat\n");
 664                return -EINVAL;
 665        }
 666
 667        ret = of_property_read_u32(node, "xlnx,dsi-data-type", &datatype);
 668
 669        if (ret < 0) {
 670                dev_err(dsi->dev, "missing xlnx,dsi-data-type property\n");
 671                return ret;
 672        }
 673
 674        dsi->format = datatype;
 675
 676        if ((datatype > MIPI_DSI_FMT_RGB565) ||
 677                (datatype < MIPI_DSI_FMT_RGB888)) {
 678                dev_err(dsi->dev, "Invalid xlnx,dsi-data-type string\n");
 679                return -EINVAL;
 680        }
 681
 682        dsi->mul_factor = xdsi_mul_factor[datatype][pixels_per_beat >> 1];
 683
 684        dev_dbg(dsi->dev, "DSI controller num lanes = %d,pixels per beat = %d",
 685                                dsi->lanes, pixels_per_beat);
 686
 687        dev_dbg(dsi->dev, "DSI controller datatype = %d\n", datatype);
 688
 689        return 0;
 690}
 691
 692static int xilinx_dsi_bind(struct device *dev, struct device *master,
 693                                void *data)
 694{
 695        struct xilinx_dsi *dsi = dev_get_drvdata(dev);
 696        struct drm_encoder *encoder = &dsi->encoder;
 697        struct drm_device *drm_dev = data;
 698        int ret;
 699
 700        /*
 701         * TODO: The possible CRTCs are 1 now as per current implementation of
 702         * DSI tx drivers. DRM framework can support more than one CRTCs and
 703         * DSI driver can be enhanced for that.
 704         */
 705        encoder->possible_crtcs = 1;
 706
 707        drm_encoder_init(drm_dev, encoder, &xilinx_dsi_encoder_funcs,
 708                         DRM_MODE_ENCODER_DSI, NULL);
 709
 710        drm_encoder_helper_add(encoder, &xilinx_dsi_encoder_helper_funcs);
 711
 712        ret = xilinx_dsi_create_connector(encoder);
 713        if (ret) {
 714                dev_err(dsi->dev, "fail creating connector, ret = %d\n", ret);
 715                drm_encoder_cleanup(encoder);
 716                return ret;
 717        }
 718
 719        ret = mipi_dsi_host_register(&dsi->dsi_host);
 720        if (ret) {
 721                xilinx_dsi_connector_destroy(&dsi->connector);
 722                drm_encoder_cleanup(encoder);
 723                return ret;
 724        }
 725
 726        return ret;
 727}
 728
 729static void xilinx_dsi_unbind(struct device *dev, struct device *master,
 730                                void *data)
 731{
 732        struct xilinx_dsi *dsi = dev_get_drvdata(dev);
 733
 734        xilinx_dsi_encoder_dpms(&dsi->encoder, DRM_MODE_DPMS_OFF);
 735        mipi_dsi_host_unregister(&dsi->dsi_host);
 736}
 737
 738static const struct component_ops xilinx_dsi_component_ops = {
 739        .bind   = xilinx_dsi_bind,
 740        .unbind = xilinx_dsi_unbind,
 741};
 742
 743static int xilinx_dsi_probe(struct platform_device *pdev)
 744{
 745        struct device *dev = &pdev->dev;
 746        struct resource *res;
 747        struct xilinx_dsi *dsi;
 748        int ret;
 749
 750        dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
 751        if (!dsi)
 752                return -ENOMEM;
 753
 754        dsi->dsi_host.ops = &xilinx_dsi_ops;
 755        dsi->dsi_host.dev = dev;
 756        dsi->dev = dev;
 757
 758        ret = xilinx_dsi_parse_dt(dsi);
 759        if (ret)
 760                return ret;
 761
 762        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 763        dsi->iomem = devm_ioremap_resource(dev, res);
 764        dev_dbg(dsi->dev, "dsi virtual address = %p %s %d\n",
 765                        dsi->iomem, __func__, __LINE__);
 766
 767        if (IS_ERR(dsi->iomem)) {
 768                dev_err(dev, "failed to remap io region\n");
 769                return PTR_ERR(dsi->iomem);
 770        }
 771
 772        platform_set_drvdata(pdev, dsi);
 773
 774        return component_add(dev, &xilinx_dsi_component_ops);
 775}
 776
 777static int xilinx_dsi_remove(struct platform_device *pdev)
 778{
 779        component_del(&pdev->dev, &xilinx_dsi_component_ops);
 780
 781        return 0;
 782}
 783
 784static const struct of_device_id xilinx_dsi_of_match[] = {
 785        { .compatible = "xlnx,mipi-dsi-tx-subsystem"},
 786        { }
 787};
 788MODULE_DEVICE_TABLE(of, xilinx_dsi_of_match);
 789
 790struct platform_driver dsi_driver = {
 791        .probe = xilinx_dsi_probe,
 792        .remove = xilinx_dsi_remove,
 793        .driver = {
 794                .name = "xilinx-mipi-dsi",
 795                .owner = THIS_MODULE,
 796                .of_match_table = xilinx_dsi_of_match,
 797        },
 798};
 799
 800module_platform_driver(dsi_driver);
 801
 802MODULE_AUTHOR("Siva Rajesh <sivaraj@xilinx.com>");
 803MODULE_DESCRIPTION("Xilinx FPGA MIPI DSI Tx Driver");
 804MODULE_LICENSE("GPL v2");
 805