uboot/drivers/video/nexell_display.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (C) 2016  Nexell Co., Ltd.
   4 *
   5 * Author: junghyun, kim <jhkim@nexell.co.kr>
   6 *
   7 * Copyright (C) 2020  Stefan Bosch <stefan_b@posteo.net>
   8 */
   9
  10#include <config.h>
  11#include <common.h>
  12#include <command.h>
  13#include <dm.h>
  14#include <mapmem.h>
  15#include <malloc.h>
  16#include <linux/compat.h>
  17#include <linux/err.h>
  18#include <video.h>              /* For struct video_uc_plat */
  19#include <lcd.h>
  20#include <asm/global_data.h>
  21#include <asm/io.h>
  22#include <asm/arch/display.h>
  23#include <asm/arch/display_dev.h>
  24#include "videomodes.h"
  25
  26DECLARE_GLOBAL_DATA_PTR;
  27
  28#if !defined(CONFIG_DM) && !defined(CONFIG_OF_CONTROL)
  29static struct nx_display_dev *dp_dev;
  30#endif
  31
  32static char *const dp_dev_str[] = {
  33        [DP_DEVICE_RESCONV] = "RESCONV",
  34        [DP_DEVICE_RGBLCD] = "LCD",
  35        [DP_DEVICE_HDMI] = "HDMI",
  36        [DP_DEVICE_MIPI] = "MiPi",
  37        [DP_DEVICE_LVDS] = "LVDS",
  38        [DP_DEVICE_CVBS] = "TVOUT",
  39        [DP_DEVICE_DP0] = "DP0",
  40        [DP_DEVICE_DP1] = "DP1",
  41};
  42
  43#if CONFIG_IS_ENABLED(OF_CONTROL)
  44static void nx_display_parse_dp_sync(ofnode node, struct dp_sync_info *sync)
  45{
  46        sync->h_active_len = ofnode_read_s32_default(node, "h_active_len", 0);
  47        sync->h_sync_width = ofnode_read_s32_default(node, "h_sync_width", 0);
  48        sync->h_back_porch = ofnode_read_s32_default(node, "h_back_porch", 0);
  49        sync->h_front_porch = ofnode_read_s32_default(node, "h_front_porch", 0);
  50        sync->h_sync_invert = ofnode_read_s32_default(node, "h_sync_invert", 0);
  51        sync->v_active_len = ofnode_read_s32_default(node, "v_active_len", 0);
  52        sync->v_sync_width = ofnode_read_s32_default(node, "v_sync_width", 0);
  53        sync->v_back_porch = ofnode_read_s32_default(node, "v_back_porch", 0);
  54        sync->v_front_porch = ofnode_read_s32_default(node, "v_front_porch", 0);
  55        sync->v_sync_invert = ofnode_read_s32_default(node, "v_sync_invert", 0);
  56        sync->pixel_clock_hz = ofnode_read_s32_default(node, "pixel_clock_hz", 0);
  57
  58        debug("DP: sync ->\n");
  59        debug("ha:%d, hs:%d, hb:%d, hf:%d, hi:%d\n",
  60              sync->h_active_len, sync->h_sync_width,
  61              sync->h_back_porch, sync->h_front_porch, sync->h_sync_invert);
  62        debug("va:%d, vs:%d, vb:%d, vf:%d, vi:%d\n",
  63              sync->v_active_len, sync->v_sync_width,
  64              sync->v_back_porch, sync->v_front_porch, sync->v_sync_invert);
  65}
  66
  67static void nx_display_parse_dp_ctrl(ofnode node, struct dp_ctrl_info *ctrl)
  68{
  69        /* clock gen */
  70        ctrl->clk_src_lv0 = ofnode_read_s32_default(node, "clk_src_lv0", 0);
  71        ctrl->clk_div_lv0 = ofnode_read_s32_default(node, "clk_div_lv0", 0);
  72        ctrl->clk_src_lv1 = ofnode_read_s32_default(node, "clk_src_lv1", 0);
  73        ctrl->clk_div_lv1 = ofnode_read_s32_default(node, "clk_div_lv1", 0);
  74
  75        /* scan format */
  76        ctrl->interlace = ofnode_read_s32_default(node, "interlace", 0);
  77
  78        /* syncgen format */
  79        ctrl->out_format = ofnode_read_s32_default(node, "out_format", 0);
  80        ctrl->invert_field = ofnode_read_s32_default(node, "invert_field", 0);
  81        ctrl->swap_RB = ofnode_read_s32_default(node, "swap_RB", 0);
  82        ctrl->yc_order = ofnode_read_s32_default(node, "yc_order", 0);
  83
  84        /* extern sync delay */
  85        ctrl->delay_mask = ofnode_read_s32_default(node, "delay_mask", 0);
  86        ctrl->d_rgb_pvd = ofnode_read_s32_default(node, "d_rgb_pvd", 0);
  87        ctrl->d_hsync_cp1 = ofnode_read_s32_default(node, "d_hsync_cp1", 0);
  88        ctrl->d_vsync_fram = ofnode_read_s32_default(node, "d_vsync_fram", 0);
  89        ctrl->d_de_cp2 = ofnode_read_s32_default(node, "d_de_cp2", 0);
  90
  91        /* extern sync delay */
  92        ctrl->vs_start_offset =
  93            ofnode_read_s32_default(node, "vs_start_offset", 0);
  94        ctrl->vs_end_offset = ofnode_read_s32_default(node, "vs_end_offset", 0);
  95        ctrl->ev_start_offset =
  96            ofnode_read_s32_default(node, "ev_start_offset", 0);
  97        ctrl->ev_end_offset = ofnode_read_s32_default(node, "ev_end_offset", 0);
  98
  99        /* pad clock seletor */
 100        ctrl->vck_select = ofnode_read_s32_default(node, "vck_select", 0);
 101        ctrl->clk_inv_lv0 = ofnode_read_s32_default(node, "clk_inv_lv0", 0);
 102        ctrl->clk_delay_lv0 = ofnode_read_s32_default(node, "clk_delay_lv0", 0);
 103        ctrl->clk_inv_lv1 = ofnode_read_s32_default(node, "clk_inv_lv1", 0);
 104        ctrl->clk_delay_lv1 = ofnode_read_s32_default(node, "clk_delay_lv1", 0);
 105        ctrl->clk_sel_div1 = ofnode_read_s32_default(node, "clk_sel_div1", 0);
 106
 107        debug("DP: ctrl [%s] ->\n",
 108              ctrl->interlace ? "Interlace" : " Progressive");
 109        debug("cs0:%d, cd0:%d, cs1:%d, cd1:%d\n",
 110              ctrl->clk_src_lv0, ctrl->clk_div_lv0,
 111              ctrl->clk_src_lv1, ctrl->clk_div_lv1);
 112        debug("fmt:0x%x, inv:%d, swap:%d, yb:0x%x\n",
 113              ctrl->out_format, ctrl->invert_field,
 114              ctrl->swap_RB, ctrl->yc_order);
 115        debug("dm:0x%x, drp:%d, dhs:%d, dvs:%d, dde:0x%x\n",
 116              ctrl->delay_mask, ctrl->d_rgb_pvd,
 117              ctrl->d_hsync_cp1, ctrl->d_vsync_fram, ctrl->d_de_cp2);
 118        debug("vss:%d, vse:%d, evs:%d, eve:%d\n",
 119              ctrl->vs_start_offset, ctrl->vs_end_offset,
 120              ctrl->ev_start_offset, ctrl->ev_end_offset);
 121        debug("sel:%d, i0:%d, d0:%d, i1:%d, d1:%d, s1:%d\n",
 122              ctrl->vck_select, ctrl->clk_inv_lv0, ctrl->clk_delay_lv0,
 123              ctrl->clk_inv_lv1, ctrl->clk_delay_lv1, ctrl->clk_sel_div1);
 124}
 125
 126static void nx_display_parse_dp_top_layer(ofnode node, struct dp_plane_top *top)
 127{
 128        top->screen_width = ofnode_read_s32_default(node, "screen_width", 0);
 129        top->screen_height = ofnode_read_s32_default(node, "screen_height", 0);
 130        top->video_prior = ofnode_read_s32_default(node, "video_prior", 0);
 131        top->interlace = ofnode_read_s32_default(node, "interlace", 0);
 132        top->back_color = ofnode_read_s32_default(node, "back_color", 0);
 133        top->plane_num = DP_PLANS_NUM;
 134
 135        debug("DP: top [%s] ->\n",
 136              top->interlace ? "Interlace" : " Progressive");
 137        debug("w:%d, h:%d, prior:%d, bg:0x%x\n",
 138              top->screen_width, top->screen_height,
 139              top->video_prior, top->back_color);
 140}
 141
 142static void nx_display_parse_dp_layer(ofnode node, struct dp_plane_info *plane)
 143{
 144        plane->left = ofnode_read_s32_default(node, "left", 0);
 145        plane->width = ofnode_read_s32_default(node, "width", 0);
 146        plane->top = ofnode_read_s32_default(node, "top", 0);
 147        plane->height = ofnode_read_s32_default(node, "height", 0);
 148        plane->pixel_byte = ofnode_read_s32_default(node, "pixel_byte", 0);
 149        plane->format = ofnode_read_s32_default(node, "format", 0);
 150        plane->alpha_on = ofnode_read_s32_default(node, "alpha_on", 0);
 151        plane->alpha_depth = ofnode_read_s32_default(node, "alpha", 0);
 152        plane->tp_on = ofnode_read_s32_default(node, "tp_on", 0);
 153        plane->tp_color = ofnode_read_s32_default(node, "tp_color", 0);
 154
 155        /* enable layer */
 156        if (plane->fb_base)
 157                plane->enable = 1;
 158        else
 159                plane->enable = 0;
 160
 161        if (plane->fb_base == 0) {
 162                printf("fail : dp plane.%d invalid fb base [0x%x] ->\n",
 163                       plane->layer, plane->fb_base);
 164                return;
 165        }
 166
 167        debug("DP: plane.%d [0x%x] ->\n", plane->layer, plane->fb_base);
 168        debug("f:0x%x, l:%d, t:%d, %d * %d, bpp:%d, a:%d(%d), t:%d(0x%x)\n",
 169              plane->format, plane->left, plane->top, plane->width,
 170              plane->height, plane->pixel_byte, plane->alpha_on,
 171              plane->alpha_depth, plane->tp_on, plane->tp_color);
 172}
 173
 174static void nx_display_parse_dp_planes(ofnode node,
 175                                       struct nx_display_dev *dp,
 176                                       struct video_uc_plat *plat)
 177{
 178        const char *name;
 179        ofnode subnode;
 180
 181        ofnode_for_each_subnode(subnode, node) {
 182                name = ofnode_get_name(subnode);
 183
 184                if (strcmp(name, "layer_top") == 0)
 185                        nx_display_parse_dp_top_layer(subnode, &dp->top);
 186
 187                /*
 188                 * TODO: Is it sure that only one layer is used? Otherwise
 189                 * fb_base must be different?
 190                 */
 191                if (strcmp(name, "layer_0") == 0) {
 192                        dp->planes[0].fb_base =
 193                              (uint)map_sysmem(plat->base, plat->size);
 194                        debug("%s(): dp->planes[0].fb_base == 0x%x\n", __func__,
 195                              (uint)dp->planes[0].fb_base);
 196                        nx_display_parse_dp_layer(subnode, &dp->planes[0]);
 197                }
 198
 199                if (strcmp(name, "layer_1") == 0) {
 200                        dp->planes[1].fb_base =
 201                              (uint)map_sysmem(plat->base, plat->size);
 202                        debug("%s(): dp->planes[1].fb_base == 0x%x\n", __func__,
 203                              (uint)dp->planes[1].fb_base);
 204                        nx_display_parse_dp_layer(subnode, &dp->planes[1]);
 205                }
 206
 207                if (strcmp(name, "layer_2") == 0) {
 208                        dp->planes[2].fb_base =
 209                              (uint)map_sysmem(plat->base, plat->size);
 210                        debug("%s(): dp->planes[2].fb_base == 0x%x\n", __func__,
 211                              (uint)dp->planes[2].fb_base);
 212                        nx_display_parse_dp_layer(subnode, &dp->planes[2]);
 213                }
 214        }
 215}
 216
 217static int nx_display_parse_dp_lvds(ofnode node, struct nx_display_dev *dp)
 218{
 219        struct dp_lvds_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 220
 221        if (!dev) {
 222                printf("failed to allocate display LVDS object.\n");
 223                return -ENOMEM;
 224        }
 225
 226        dp->device = dev;
 227
 228        dev->lvds_format = ofnode_read_s32_default(node, "format", 0);
 229        dev->pol_inv_hs = ofnode_read_s32_default(node, "pol_inv_hs", 0);
 230        dev->pol_inv_vs = ofnode_read_s32_default(node, "pol_inv_vs", 0);
 231        dev->pol_inv_de = ofnode_read_s32_default(node, "pol_inv_de", 0);
 232        dev->pol_inv_ck = ofnode_read_s32_default(node, "pol_inv_ck", 0);
 233        dev->voltage_level = ofnode_read_s32_default(node, "voltage_level", 0);
 234
 235        if (!dev->voltage_level)
 236                dev->voltage_level = DEF_VOLTAGE_LEVEL;
 237
 238        debug("DP: LVDS -> %s, voltage LV:0x%x\n",
 239              dev->lvds_format == DP_LVDS_FORMAT_VESA ? "VESA" :
 240              dev->lvds_format == DP_LVDS_FORMAT_JEIDA ? "JEIDA" : "LOC",
 241              dev->voltage_level);
 242        debug("pol inv hs:%d, vs:%d, de:%d, ck:%d\n",
 243              dev->pol_inv_hs, dev->pol_inv_vs,
 244              dev->pol_inv_de, dev->pol_inv_ck);
 245
 246        return 0;
 247}
 248
 249static int nx_display_parse_dp_rgb(ofnode node, struct nx_display_dev *dp)
 250{
 251        struct dp_rgb_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 252
 253        if (!dev) {
 254                printf("failed to allocate display RGB LCD object.\n");
 255                return -ENOMEM;
 256        }
 257        dp->device = dev;
 258
 259        dev->lcd_mpu_type = ofnode_read_s32_default(node, "lcd_mpu_type", 0);
 260
 261        debug("DP: RGB -> MPU[%s]\n", dev->lcd_mpu_type ? "O" : "X");
 262        return 0;
 263}
 264
 265static int nx_display_parse_dp_mipi(ofnode node, struct nx_display_dev *dp)
 266{
 267        struct dp_mipi_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 268
 269        if (!dev) {
 270                printf("failed to allocate display MiPi object.\n");
 271                return -ENOMEM;
 272        }
 273        dp->device = dev;
 274
 275        dev->lp_bitrate = ofnode_read_s32_default(node, "lp_bitrate", 0);
 276        dev->hs_bitrate = ofnode_read_s32_default(node, "hs_bitrate", 0);
 277        dev->lpm_trans = 1;
 278        dev->command_mode = 0;
 279
 280        debug("DP: MIPI ->\n");
 281        debug("lp:%dmhz, hs:%dmhz\n", dev->lp_bitrate, dev->hs_bitrate);
 282
 283        return 0;
 284}
 285
 286static int nx_display_parse_dp_hdmi(ofnode node, struct nx_display_dev *dp)
 287{
 288        struct dp_hdmi_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 289
 290        if (!dev) {
 291                printf("failed to allocate display HDMI object.\n");
 292                return -ENOMEM;
 293        }
 294        dp->device = dev;
 295
 296        dev->preset = ofnode_read_s32_default(node, "preset", 0);
 297
 298        debug("DP: HDMI -> %d\n", dev->preset);
 299
 300        return 0;
 301}
 302
 303static int nx_display_parse_dp_lcds(ofnode node, const char *type,
 304                                    struct nx_display_dev *dp)
 305{
 306        if (strcmp(type, "lvds") == 0) {
 307                dp->dev_type = DP_DEVICE_LVDS;
 308                return nx_display_parse_dp_lvds(node, dp);
 309        } else if (strcmp(type, "rgb") == 0) {
 310                dp->dev_type = DP_DEVICE_RGBLCD;
 311                return nx_display_parse_dp_rgb(node, dp);
 312        } else if (strcmp(type, "mipi") == 0) {
 313                dp->dev_type = DP_DEVICE_MIPI;
 314                return nx_display_parse_dp_mipi(node, dp);
 315        } else if (strcmp(type, "hdmi") == 0) {
 316                dp->dev_type = DP_DEVICE_HDMI;
 317                return nx_display_parse_dp_hdmi(node, dp);
 318        }
 319
 320        printf("%s: node %s unknown display type\n", __func__,
 321               ofnode_get_name(node));
 322        return -EINVAL;
 323
 324        return 0;
 325}
 326
 327#define DT_SYNC         (1 << 0)
 328#define DT_CTRL         (1 << 1)
 329#define DT_PLANES       (1 << 2)
 330#define DT_DEVICE       (1 << 3)
 331
 332static int nx_display_parse_dt(struct udevice *dev,
 333                               struct nx_display_dev *dp,
 334                               struct video_uc_plat *plat)
 335{
 336        const char *name, *dtype;
 337        int ret = 0;
 338        unsigned int dt_status = 0;
 339        ofnode subnode;
 340
 341        if (!dev)
 342                return -ENODEV;
 343
 344        dp->module = dev_read_s32_default(dev, "module", -1);
 345        if (dp->module == -1)
 346                dp->module = dev_read_s32_default(dev, "index", 0);
 347
 348        dtype = dev_read_string(dev, "lcd-type");
 349
 350        ofnode_for_each_subnode(subnode, dev_ofnode(dev)) {
 351                name = ofnode_get_name(subnode);
 352
 353                if (strcmp("dp-sync", name) == 0) {
 354                        dt_status |= DT_SYNC;
 355                        nx_display_parse_dp_sync(subnode, &dp->sync);
 356                }
 357
 358                if (strcmp("dp-ctrl", name) == 0) {
 359                        dt_status |= DT_CTRL;
 360                        nx_display_parse_dp_ctrl(subnode, &dp->ctrl);
 361                }
 362
 363                if (strcmp("dp-planes", name) == 0) {
 364                        dt_status |= DT_PLANES;
 365                        nx_display_parse_dp_planes(subnode, dp, plat);
 366                }
 367
 368                if (strcmp("dp-device", name) == 0) {
 369                        dt_status |= DT_DEVICE;
 370                        ret = nx_display_parse_dp_lcds(subnode, dtype, dp);
 371                }
 372        }
 373
 374        if (dt_status != (DT_SYNC | DT_CTRL | DT_PLANES | DT_DEVICE)) {
 375                printf("Not enough DT config for display [0x%x]\n", dt_status);
 376                return -ENODEV;
 377        }
 378
 379        return ret;
 380}
 381#endif
 382
 383__weak int nx_display_fixup_dp(struct nx_display_dev *dp)
 384{
 385        return 0;
 386}
 387
 388static struct nx_display_dev *nx_display_setup(void)
 389{
 390        struct nx_display_dev *dp;
 391        int i, ret;
 392        int node = 0;
 393        struct video_uc_plat *plat = NULL;
 394
 395        struct udevice *dev;
 396
 397        /* call driver probe */
 398        debug("DT: uclass device call...\n");
 399
 400        ret = uclass_get_device(UCLASS_VIDEO, 0, &dev);
 401        if (ret) {
 402                debug("%s(): uclass_get_device(UCLASS_VIDEO, 0, &dev) != 0 --> return NULL\n",
 403                      __func__);
 404                return NULL;
 405        }
 406        plat = dev_get_uclass_plat(dev);
 407        if (!dev) {
 408                debug("%s(): dev_get_uclass_plat(dev) == NULL --> return NULL\n",
 409                      __func__);
 410                return NULL;
 411        }
 412        dp = dev_get_priv(dev);
 413        if (!dp) {
 414                debug("%s(): dev_get_priv(dev) == NULL --> return NULL\n",
 415                      __func__);
 416                return NULL;
 417        }
 418        node = dev_ofnode(dev).of_offset;
 419
 420        if (CONFIG_IS_ENABLED(OF_CONTROL)) {
 421                ret = nx_display_parse_dt(dev, dp, plat);
 422                if (ret)
 423                        goto err_setup;
 424        }
 425
 426        nx_display_fixup_dp(dp);
 427
 428        for (i = 0; dp->top.plane_num > i; i++) {
 429                dp->planes[i].layer = i;
 430                if (dp->planes[i].enable && !dp->fb_plane) {
 431                        dp->fb_plane = &dp->planes[i];
 432                        dp->fb_addr = dp->fb_plane->fb_base;
 433                        dp->depth = dp->fb_plane->pixel_byte;
 434                }
 435        }
 436
 437        switch (dp->dev_type) {
 438#ifdef CONFIG_VIDEO_NX_RGB
 439        case DP_DEVICE_RGBLCD:
 440                nx_rgb_display(dp->module,
 441                               &dp->sync, &dp->ctrl, &dp->top,
 442                               dp->planes, (struct dp_rgb_dev *)dp->device);
 443                break;
 444#endif
 445#ifdef CONFIG_VIDEO_NX_LVDS
 446        case DP_DEVICE_LVDS:
 447                nx_lvds_display(dp->module,
 448                                &dp->sync, &dp->ctrl, &dp->top,
 449                                dp->planes, (struct dp_lvds_dev *)dp->device);
 450                break;
 451#endif
 452#ifdef CONFIG_VIDEO_NX_MIPI
 453        case DP_DEVICE_MIPI:
 454                nx_mipi_display(dp->module,
 455                                &dp->sync, &dp->ctrl, &dp->top,
 456                                dp->planes, (struct dp_mipi_dev *)dp->device);
 457                break;
 458#endif
 459#ifdef CONFIG_VIDEO_NX_HDMI
 460        case DP_DEVICE_HDMI:
 461                nx_hdmi_display(dp->module,
 462                                &dp->sync, &dp->ctrl, &dp->top,
 463                                dp->planes, (struct dp_hdmi_dev *)dp->device);
 464                break;
 465#endif
 466        default:
 467                printf("fail : not support lcd type %d !!!\n", dp->dev_type);
 468                goto err_setup;
 469        };
 470
 471        printf("LCD:   [%s] dp.%d.%d %dx%d %dbpp FB:0x%08x\n",
 472               dp_dev_str[dp->dev_type], dp->module, dp->fb_plane->layer,
 473               dp->fb_plane->width, dp->fb_plane->height, dp->depth * 8,
 474               dp->fb_addr);
 475
 476        return dp;
 477
 478err_setup:
 479        kfree(dp);
 480
 481        return NULL;
 482}
 483
 484#if defined CONFIG_LCD
 485
 486/* default lcd */
 487struct vidinfo panel_info = {
 488        .vl_col = 320, .vl_row = 240, .vl_bpix = 32,
 489};
 490
 491void lcd_ctrl_init(void *lcdbase)
 492{
 493        vidinfo_t *pi = &panel_info;
 494        struct nx_display_dev *dp;
 495        int bpix;
 496
 497        dp = nx_display_setup();
 498        if (!dp)
 499                return NULL;
 500
 501        switch (dp->depth) {
 502        case 2:
 503                bpix = LCD_COLOR16;
 504                break;
 505        case 3:
 506        case 4:
 507                bpix = LCD_COLOR32;
 508                break;
 509        default:
 510                printf("fail : not support LCD bit per pixel %d\n",
 511                       dp->depth * 8);
 512                return NULL;
 513        }
 514
 515        dp->panel_info = pi;
 516
 517        /* set resolution with config */
 518        pi->vl_bpix = bpix;
 519        pi->vl_col = dp->fb_plane->width;
 520        pi->vl_row = dp->fb_plane->height;
 521        pi->priv = dp;
 522        gd->fb_base = dp->fb_addr;
 523}
 524
 525void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
 526{
 527}
 528
 529__weak void lcd_enable(void)
 530{
 531}
 532#endif
 533
 534static int nx_display_probe(struct udevice *dev)
 535{
 536        struct video_uc_plat *uc_plat = dev_get_uclass_plat(dev);
 537        struct video_priv *uc_priv = dev_get_uclass_priv(dev);
 538        struct nx_display_plat *plat = dev_get_plat(dev);
 539        char addr[64];
 540
 541        debug("%s()\n", __func__);
 542
 543        if (!dev)
 544                return -EINVAL;
 545
 546        if (!uc_plat) {
 547                debug("%s(): video_uc_plat *plat == NULL --> return -EINVAL\n",
 548                      __func__);
 549                return -EINVAL;
 550        }
 551
 552        if (!uc_priv) {
 553                debug("%s(): video_priv *uc_priv == NULL --> return -EINVAL\n",
 554                      __func__);
 555                return -EINVAL;
 556        }
 557
 558        if (!plat) {
 559                debug("%s(): nx_display_plat *plat == NULL --> return -EINVAL\n",
 560                      __func__);
 561                return -EINVAL;
 562        }
 563
 564        struct nx_display_dev *dp;
 565
 566        dp = nx_display_setup();
 567        if (!dp) {
 568                debug("%s(): nx_display_setup() == 0 --> return -EINVAL\n",
 569                      __func__);
 570                return -EINVAL;
 571        }
 572
 573        switch (dp->depth) {
 574        case 2:
 575                uc_priv->bpix = VIDEO_BPP16;
 576                break;
 577        case 3:
 578                /* There is no VIDEO_BPP24 because these values are of
 579                 * type video_log2_bpp
 580                 */
 581        case 4:
 582                uc_priv->bpix = VIDEO_BPP32;
 583                break;
 584        default:
 585                printf("fail : not support LCD bit per pixel %d\n",
 586                       dp->depth * 8);
 587                return -EINVAL;
 588        }
 589
 590        uc_priv->xsize = dp->fb_plane->width;
 591        uc_priv->ysize = dp->fb_plane->height;
 592        uc_priv->rot = 0;
 593
 594        /*
 595         * set environment variable "fb_addr" (frame buffer address), required
 596         * for splash image, which is not set if CONFIG_DM_VIDEO is enabled).
 597         */
 598        sprintf(addr, "0x%x", dp->fb_addr);
 599        debug("%s(): env_set(\"fb_addr\", %s) ...\n", __func__, addr);
 600        env_set("fb_addr", addr);
 601
 602        return 0;
 603}
 604
 605static int nx_display_bind(struct udevice *dev)
 606{
 607        struct video_uc_plat *plat = dev_get_uclass_plat(dev);
 608
 609        debug("%s()\n", __func__);
 610
 611        /* Datasheet S5p4418:
 612         *   Resolution up to 2048 x 1280, up to 12 Bit per color (HDMI)
 613         * Actual (max.) size is 0x1000000 because in U-Boot nanopi2-2016.01
 614         * "#define CONFIG_FB_ADDR  0x77000000" and next address is
 615         * "#define BMP_LOAD_ADDR  0x78000000"
 616         */
 617        plat->size = 0x1000000;
 618
 619        return 0;
 620}
 621
 622static const struct udevice_id nx_display_ids[] = {
 623        {.compatible = "nexell,nexell-display", },
 624        {}
 625};
 626
 627U_BOOT_DRIVER(nexell_display) = {
 628        .name = "nexell-display",
 629        .id = UCLASS_VIDEO,
 630        .of_match = nx_display_ids,
 631        .plat_auto      = sizeof(struct nx_display_plat),
 632        .bind = nx_display_bind,
 633        .probe = nx_display_probe,
 634        .priv_auto      = sizeof(struct nx_display_dev),
 635};
 636