uboot/drivers/video/exynos/exynos_mipi_dsi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2012 Samsung Electronics
   4 *
   5 * Author: InKi Dae <inki.dae@samsung.com>
   6 * Author: Donghwa Lee <dh09.lee@samsung.com>
   7 */
   8
   9#include <common.h>
  10#include <malloc.h>
  11#include <fdtdec.h>
  12#include <linux/libfdt.h>
  13#include <linux/compat.h>
  14#include <linux/err.h>
  15#include <asm/arch/dsim.h>
  16#include <asm/arch/mipi_dsim.h>
  17#include <asm/arch/power.h>
  18#include <asm/arch/cpu.h>
  19#include <asm/arch/clk.h>
  20
  21#include "exynos_mipi_dsi_lowlevel.h"
  22#include "exynos_mipi_dsi_common.h"
  23
  24#define master_to_driver(a)     (a->dsim_lcd_drv)
  25#define master_to_device(a)     (a->dsim_lcd_dev)
  26
  27DECLARE_GLOBAL_DATA_PTR;
  28
  29struct mipi_dsim_ddi {
  30        int                             bus_id;
  31        struct list_head                list;
  32        struct mipi_dsim_lcd_device     *dsim_lcd_dev;
  33        struct mipi_dsim_lcd_driver     *dsim_lcd_drv;
  34};
  35
  36static LIST_HEAD(dsim_ddi_list);
  37static LIST_HEAD(dsim_lcd_dev_list);
  38
  39int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
  40{
  41        struct mipi_dsim_ddi *dsim_ddi;
  42
  43        if (!lcd_dev) {
  44                debug("mipi_dsim_lcd_device is NULL.\n");
  45                return -EFAULT;
  46        }
  47
  48        if (!lcd_dev->name) {
  49                debug("dsim_lcd_device name is NULL.\n");
  50                return -EFAULT;
  51        }
  52
  53        dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
  54        if (!dsim_ddi) {
  55                debug("failed to allocate dsim_ddi object.\n");
  56                return -EFAULT;
  57        }
  58
  59        dsim_ddi->dsim_lcd_dev = lcd_dev;
  60
  61        list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
  62
  63        return 0;
  64}
  65
  66struct mipi_dsim_ddi
  67        *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
  68{
  69        struct mipi_dsim_ddi *dsim_ddi;
  70        struct mipi_dsim_lcd_device *lcd_dev;
  71
  72        list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
  73                lcd_dev = dsim_ddi->dsim_lcd_dev;
  74                if (!lcd_dev)
  75                        continue;
  76
  77                if (lcd_drv->id >= 0) {
  78                        if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0 &&
  79                                        lcd_drv->id == lcd_dev->id) {
  80                                /**
  81                                 * bus_id would be used to identify
  82                                 * connected bus.
  83                                 */
  84                                dsim_ddi->bus_id = lcd_dev->bus_id;
  85
  86                                return dsim_ddi;
  87                        }
  88                } else {
  89                        if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
  90                                /**
  91                                 * bus_id would be used to identify
  92                                 * connected bus.
  93                                 */
  94                                dsim_ddi->bus_id = lcd_dev->bus_id;
  95
  96                                return dsim_ddi;
  97                        }
  98                }
  99
 100                kfree(dsim_ddi);
 101                list_del(&dsim_ddi_list);
 102        }
 103
 104        return NULL;
 105}
 106
 107int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
 108{
 109        struct mipi_dsim_ddi *dsim_ddi;
 110
 111        if (!lcd_drv) {
 112                debug("mipi_dsim_lcd_driver is NULL.\n");
 113                return -EFAULT;
 114        }
 115
 116        if (!lcd_drv->name) {
 117                debug("dsim_lcd_driver name is NULL.\n");
 118                return -EFAULT;
 119        }
 120
 121        dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
 122        if (!dsim_ddi) {
 123                debug("mipi_dsim_ddi object not found.\n");
 124                return -EFAULT;
 125        }
 126
 127        dsim_ddi->dsim_lcd_drv = lcd_drv;
 128
 129        debug("registered panel driver(%s) to mipi-dsi driver.\n",
 130                lcd_drv->name);
 131
 132        return 0;
 133
 134}
 135
 136struct mipi_dsim_ddi
 137        *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
 138                        const char *name)
 139{
 140        struct mipi_dsim_ddi *dsim_ddi;
 141        struct mipi_dsim_lcd_driver *lcd_drv;
 142        struct mipi_dsim_lcd_device *lcd_dev;
 143
 144        list_for_each_entry(dsim_ddi, &dsim_ddi_list, list) {
 145                lcd_drv = dsim_ddi->dsim_lcd_drv;
 146                lcd_dev = dsim_ddi->dsim_lcd_dev;
 147                if (!lcd_drv || !lcd_dev)
 148                        continue;
 149
 150                debug("lcd_drv->id = %d, lcd_dev->id = %d\n",
 151                                        lcd_drv->id, lcd_dev->id);
 152
 153                if ((strcmp(lcd_drv->name, name) == 0)) {
 154                        lcd_dev->master = dsim;
 155
 156                        dsim->dsim_lcd_dev = lcd_dev;
 157                        dsim->dsim_lcd_drv = lcd_drv;
 158
 159                        return dsim_ddi;
 160                }
 161        }
 162
 163        return NULL;
 164}
 165
 166/* define MIPI-DSI Master operations. */
 167static struct mipi_dsim_master_ops master_ops = {
 168        .cmd_write                      = exynos_mipi_dsi_wr_data,
 169        .get_dsim_frame_done            = exynos_mipi_dsi_get_frame_done_status,
 170        .clear_dsim_frame_done          = exynos_mipi_dsi_clear_frame_done,
 171};
 172
 173int exynos_mipi_dsi_init(struct exynos_platform_mipi_dsim *dsim_pd)
 174{
 175        struct mipi_dsim_device *dsim;
 176        struct mipi_dsim_config *dsim_config;
 177        struct mipi_dsim_ddi *dsim_ddi;
 178
 179        dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
 180        if (!dsim) {
 181                debug("failed to allocate dsim object.\n");
 182                return -EFAULT;
 183        }
 184
 185        /* get mipi_dsim_config. */
 186        dsim_config = dsim_pd->dsim_config;
 187        if (dsim_config == NULL) {
 188                debug("failed to get dsim config data.\n");
 189                return -EFAULT;
 190        }
 191
 192        dsim->pd = dsim_pd;
 193        dsim->dsim_config = dsim_config;
 194        dsim->master_ops = &master_ops;
 195
 196        /* bind lcd ddi matched with panel name. */
 197        dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
 198        if (!dsim_ddi) {
 199                debug("mipi_dsim_ddi object not found.\n");
 200                return -ENOSYS;
 201        }
 202        if (dsim_pd->lcd_power)
 203                dsim_pd->lcd_power();
 204
 205        if (dsim_pd->mipi_power)
 206                dsim_pd->mipi_power();
 207
 208        /* phy_enable(unsigned int dev_index, unsigned int enable) */
 209        if (dsim_pd->phy_enable)
 210                dsim_pd->phy_enable(0, 1);
 211
 212        set_mipi_clk();
 213
 214        exynos_mipi_dsi_init_dsim(dsim);
 215        exynos_mipi_dsi_init_link(dsim);
 216        exynos_mipi_dsi_set_hs_enable(dsim);
 217
 218        /* set display timing. */
 219        exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
 220
 221        /* initialize mipi-dsi client(lcd panel). */
 222        if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->mipi_panel_init) {
 223                dsim_ddi->dsim_lcd_drv->mipi_panel_init(dsim);
 224                dsim_ddi->dsim_lcd_drv->mipi_display_on(dsim);
 225        }
 226
 227        debug("mipi-dsi driver(%s mode) has been probed.\n",
 228                (dsim_config->e_interface == DSIM_COMMAND) ?
 229                        "CPU" : "RGB");
 230
 231        return 0;
 232}
 233
 234int exynos_dsim_config_parse_dt(const void *blob, struct mipi_dsim_config *dt,
 235                                struct mipi_dsim_lcd_device *lcd_dt)
 236{
 237        int node;
 238
 239        node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS_MIPI_DSI);
 240        if (node <= 0) {
 241                printf("exynos_mipi_dsi: Can't get device node for mipi dsi\n");
 242                return -ENODEV;
 243        }
 244
 245        dt->e_interface = fdtdec_get_int(blob, node,
 246                                "samsung,dsim-config-e-interface", 0);
 247
 248        dt->e_virtual_ch = fdtdec_get_int(blob, node,
 249                                "samsung,dsim-config-e-virtual-ch", 0);
 250
 251        dt->e_pixel_format = fdtdec_get_int(blob, node,
 252                                "samsung,dsim-config-e-pixel-format", 0);
 253
 254        dt->e_burst_mode = fdtdec_get_int(blob, node,
 255                                "samsung,dsim-config-e-burst-mode", 0);
 256
 257        dt->e_no_data_lane = fdtdec_get_int(blob, node,
 258                                "samsung,dsim-config-e-no-data-lane", 0);
 259
 260        dt->e_byte_clk = fdtdec_get_int(blob, node,
 261                                "samsung,dsim-config-e-byte-clk", 0);
 262
 263        dt->hfp = fdtdec_get_int(blob, node,
 264                                "samsung,dsim-config-hfp", 0);
 265
 266        dt->p = fdtdec_get_int(blob, node,
 267                                          "samsung,dsim-config-p", 0);
 268        dt->m = fdtdec_get_int(blob, node,
 269                                          "samsung,dsim-config-m", 0);
 270        dt->s = fdtdec_get_int(blob, node,
 271                                          "samsung,dsim-config-s", 0);
 272
 273        dt->pll_stable_time = fdtdec_get_int(blob, node,
 274                                "samsung,dsim-config-pll-stable-time", 0);
 275
 276        dt->esc_clk = fdtdec_get_int(blob, node,
 277                                "samsung,dsim-config-esc-clk", 0);
 278
 279        dt->stop_holding_cnt = fdtdec_get_int(blob, node,
 280                                "samsung,dsim-config-stop-holding-cnt", 0);
 281
 282        dt->bta_timeout = fdtdec_get_int(blob, node,
 283                                "samsung,dsim-config-bta-timeout", 0);
 284
 285        dt->rx_timeout = fdtdec_get_int(blob, node,
 286                                "samsung,dsim-config-rx-timeout", 0);
 287
 288        lcd_dt->name = fdtdec_get_config_string(blob,
 289                                "samsung,dsim-device-name");
 290
 291        lcd_dt->id = fdtdec_get_int(blob, node,
 292                                "samsung,dsim-device-id", 0);
 293
 294        lcd_dt->bus_id = fdtdec_get_int(blob, node,
 295                                "samsung,dsim-device-bus_id", 0);
 296
 297        lcd_dt->reverse_panel = fdtdec_get_int(blob, node,
 298                                "samsung,dsim-device-reverse-panel", 0);
 299
 300        return 0;
 301}
 302
 303void exynos_init_dsim_platform_data(vidinfo_t *vid)
 304{
 305        static struct mipi_dsim_config dsim_config_dt;
 306        static struct exynos_platform_mipi_dsim dsim_platform_data_dt;
 307        static struct mipi_dsim_lcd_device mipi_lcd_device_dt;
 308
 309        if (exynos_dsim_config_parse_dt(gd->fdt_blob, &dsim_config_dt,
 310                                        &mipi_lcd_device_dt))
 311                debug("Can't get proper dsim config.\n");
 312
 313        strcpy(dsim_platform_data_dt.lcd_panel_name, mipi_lcd_device_dt.name);
 314        dsim_platform_data_dt.dsim_config = &dsim_config_dt;
 315        dsim_platform_data_dt.mipi_power = mipi_power;
 316        dsim_platform_data_dt.phy_enable = set_mipi_phy_ctrl;
 317        dsim_platform_data_dt.lcd_panel_info = (void *)vid;
 318
 319        mipi_lcd_device_dt.platform_data = (void *)&dsim_platform_data_dt;
 320        exynos_mipi_dsi_register_lcd_device(&mipi_lcd_device_dt);
 321
 322        vid->dsim_platform_data_dt = &dsim_platform_data_dt;
 323}
 324