uboot/drivers/video/nexell/s5pxx18_dp_lvds.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
   8#include <config.h>
   9#include <common.h>
  10#include <errno.h>
  11
  12#include <asm/arch/nexell.h>
  13#include <asm/arch/reset.h>
  14#include <asm/arch/display.h>
  15
  16#include "soc/s5pxx18_soc_lvds.h"
  17#include "soc/s5pxx18_soc_disptop.h"
  18#include "soc/s5pxx18_soc_disptop_clk.h"
  19
  20#define __io_address(a) (void *)(uintptr_t)(a)
  21
  22static void lvds_phy_reset(void)
  23{
  24        nx_rstcon_setrst(RESET_ID_LVDS, RSTCON_ASSERT);
  25        nx_rstcon_setrst(RESET_ID_LVDS, RSTCON_NEGATE);
  26}
  27
  28static void lvds_init(void)
  29{
  30        int clkid = DP_CLOCK_LVDS;
  31        int index = 0;
  32        void *base;
  33
  34        base = __io_address(nx_disp_top_clkgen_get_physical_address(clkid));
  35        nx_disp_top_clkgen_set_base_address(clkid, base);
  36
  37        nx_lvds_initialize();
  38
  39        for (index = 0; nx_lvds_get_number_of_module() > index; index++)
  40                nx_lvds_set_base_address(index,
  41                  (void *)__io_address(nx_lvds_get_physical_address(index)));
  42
  43        nx_disp_top_clkgen_set_clock_pclk_mode(clkid, nx_pclkmode_always);
  44}
  45
  46static void lvds_enable(int enable)
  47{
  48        int clkid = DP_CLOCK_LVDS;
  49        int on = (enable ? 1 : 0);
  50
  51        nx_disp_top_clkgen_set_clock_divisor_enable(clkid, on);
  52}
  53
  54static int lvds_setup(int module, int input,
  55                      struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
  56                      struct dp_lvds_dev *dev)
  57{
  58        unsigned int val;
  59        int clkid = DP_CLOCK_LVDS;
  60        enum dp_lvds_format format = DP_LVDS_FORMAT_JEIDA;
  61        u32 voltage = DEF_VOLTAGE_LEVEL;
  62
  63        if (dev) {
  64                format = dev->lvds_format;
  65                voltage = dev->voltage_level;
  66        }
  67
  68        printf("LVDS:  ");
  69        printf("%s, ", format == DP_LVDS_FORMAT_VESA ? "VESA" :
  70                format == DP_LVDS_FORMAT_JEIDA ? "JEIDA" : "LOC");
  71        printf("voltage LV:0x%x\n", voltage);
  72
  73        /*
  74         *-------- predefined type.
  75         * only change iTA to iTE in VESA mode
  76         * wire [34:0] loc_VideoIn =
  77         * {4'hf, 4'h0, i_VDEN, i_VSYNC, i_HSYNC, i_VD[23:0] };
  78         */
  79        u32 VSYNC = 25;
  80        u32 HSYNC = 24;
  81        u32 VDEN  = 26; /* bit position */
  82        u32 ONE   = 34;
  83        u32 ZERO  = 27;
  84
  85        /*====================================================
  86         * current not use location mode
  87         *====================================================
  88         */
  89        u32 LOC_A[7] = {ONE, ONE, ONE, ONE, ONE, ONE, ONE};
  90        u32 LOC_B[7] = {ONE, ONE, ONE, ONE, ONE, ONE, ONE};
  91        u32 LOC_C[7] = {VDEN, VSYNC, HSYNC, ONE, HSYNC, VSYNC, VDEN};
  92        u32 LOC_D[7] = {ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO};
  93        u32 LOC_E[7] = {ZERO, ZERO, ZERO, ZERO, ZERO, ZERO, ZERO};
  94
  95        switch (input) {
  96        case DP_DEVICE_DP0:
  97                input = 0;
  98                break;
  99        case DP_DEVICE_DP1:
 100                input = 1;
 101                break;
 102        case DP_DEVICE_RESCONV:
 103                input = 2;
 104                break;
 105        default:
 106                return -EINVAL;
 107        }
 108
 109        /*
 110         * select TOP MUX
 111         */
 112        nx_disp_top_clkgen_set_clock_divisor_enable(clkid, 0);
 113        nx_disp_top_clkgen_set_clock_source(clkid, 0, ctrl->clk_src_lv0);
 114        nx_disp_top_clkgen_set_clock_divisor(clkid, 0, ctrl->clk_div_lv0);
 115        nx_disp_top_clkgen_set_clock_source(clkid, 1, ctrl->clk_src_lv1);
 116        nx_disp_top_clkgen_set_clock_divisor(clkid, 1, ctrl->clk_div_lv1);
 117
 118        /*
 119         * LVDS Control Pin Setting
 120         */
 121        val = (0 << 30) |      /* CPU_I_VBLK_FLAG_SEL */
 122              (0 << 29) |      /* CPU_I_BVLK_FLAG */
 123              (1 << 28) |      /* SKINI_BST  */
 124              (1 << 27) |      /* DLYS_BST  */
 125              (0 << 26) |      /* I_AUTO_SEL */
 126              (format << 19) | /* JEiDA data packing */
 127              (0x1B << 13)   | /* I_LOCK_PPM_SET, PPM setting for PLL lock */
 128              (0x638 << 1);    /* I_DESKEW_CNT_SEL, period of de-skew region */
 129        nx_lvds_set_lvdsctrl0(0, val);
 130
 131        val = (0 << 28) |   /* I_ATE_MODE, function mode */
 132              (0 << 27) |   /* I_TEST_CON_MODE, DA (test ctrl mode) */
 133              (0 << 24) |   /* I_TX4010X_DUMMY */
 134              (0 << 15) |   /* SKCCK 0 */
 135              (0 << 12) |   /* SKC4 (TX output skew control pin at ODD ch4) */
 136              (0 << 9)  |   /* SKC3 (TX output skew control pin at ODD ch3) */
 137              (0 << 6)  |   /* SKC2 (TX output skew control pin at ODD ch2) */
 138              (0 << 3)  |   /* SKC1 (TX output skew control pin at ODD ch1) */
 139              (0 << 0);     /* SKC0 (TX output skew control pin at ODD ch0) */
 140        nx_lvds_set_lvdsctrl1(0, val);
 141
 142        val = (0 << 15)   | /* CK_POL_SEL, Input clock, bypass */
 143              (0 << 14)   | /* VSEL, VCO Freq. range. 0: Low(40MHz~90MHz),
 144                             *                        1: High(90MHz~160MHz) */
 145              (0x1 << 12) | /* S (Post-scaler) */
 146              (0xA << 6)  | /* M (Main divider) */
 147              (0xA << 0);   /* P (Pre-divider) */
 148
 149        nx_lvds_set_lvdsctrl2(0, val);
 150        val = (0x03 << 6) | /* SK_BIAS, Bias current ctrl pin */
 151              (0 << 5)    | /* SKEWINI, skew selection pin, 0: bypass,
 152                             *                              1: skew enable */
 153              (0 << 4)    | /* SKEW_EN_H, skew block power down, 0: power down,
 154                             *                                   1: operating */
 155              (1 << 3)    | /* CNTB_TDLY, delay control pin */
 156              (0 << 2)    | /* SEL_DATABF, input clock 1/2 division cont. pin */
 157              (0x3 << 0);   /* SKEW_REG_CUR, regulator bias current selection
 158                             *               in SKEW block */
 159
 160        nx_lvds_set_lvdsctrl3(0, val);
 161        val = (0 << 28)   | /* FLT_CNT, filter control pin for PLL */
 162              (0 << 27)   | /* VOD_ONLY_CNT, the pre-emphasis's pre-diriver
 163                             *               control pin (VOD only) */
 164              (0 << 26)   | /* CNNCT_MODE_SEL, connectivity mode selection,
 165                             *                 0:TX operating, 1:con check */
 166              (0 << 24)   | /* CNNCT_CNT, connectivity ctrl pin,
 167                             *            0: tx operating, 1: con check */
 168              (0 << 23)   | /* VOD_HIGH_S, VOD control pin, 1: Vod only */
 169              (0 << 22)   | /* SRC_TRH, source termination resistor sel. pin */
 170              (voltage << 14) |
 171              (0x01 << 6) | /* CNT_PEN_H, TX driver pre-emphasis level cont. */
 172              (0x4 << 3)  | /* FC_CODE, vos control pin */
 173              (0 << 2)    | /* OUTCON, TX Driver state selectioin pin, 0:Hi-z,
 174                             *                                         1:Low */
 175              (0 << 1)    | /* LOCK_CNT, Lock signal selection pin, enable */
 176              (0 << 0);     /* AUTO_DSK_SEL, auto deskew sel. pin, normal */
 177        nx_lvds_set_lvdsctrl4(0, val);
 178
 179        val = (0 << 24) |   /* I_BIST_RESETB */
 180              (0 << 23) |   /* I_BIST_EN */
 181              (0 << 21) |   /* I_BIST_PAT_SEL */
 182              (0 << 14) |   /* I_BIST_USER_PATTERN */
 183              (0 << 13) |   /* I_BIST_FORCE_ERROR */
 184              (0 << 7)  |   /* I_BIST_SKEW_CTRL */
 185              (0 << 5)  |   /* I_BIST_CLK_INV */
 186              (0 << 3)  |   /* I_BIST_DATA_INV */
 187              (0 << 0);     /* I_BIST_CH_SEL */
 188        nx_lvds_set_lvdstmode0(0, val);
 189
 190        /* user do not need to modify this codes. */
 191        val = (LOC_A[4] << 24) | (LOC_A[3] << 18) | (LOC_A[2] << 12) |
 192              (LOC_A[1] << 6)  | (LOC_A[0] << 0);
 193        nx_lvds_set_lvdsloc0(0, val);
 194
 195        val = (LOC_B[2] << 24) | (LOC_B[1] << 18) | (LOC_B[0] << 12) |
 196              (LOC_A[6] << 6)  | (LOC_A[5] << 0);
 197        nx_lvds_set_lvdsloc1(0, val);
 198
 199        val = (LOC_C[0] << 24) | (LOC_B[6] << 18) | (LOC_B[5] << 12) |
 200              (LOC_B[4] << 6)  | (LOC_B[3] << 0);
 201        nx_lvds_set_lvdsloc2(0, val);
 202
 203        val = (LOC_C[5] << 24) | (LOC_C[4] << 18) | (LOC_C[3] << 12) |
 204              (LOC_C[2] << 6)  | (LOC_C[1] << 0);
 205        nx_lvds_set_lvdsloc3(0, val);
 206
 207        val = (LOC_D[3] << 24) | (LOC_D[2] << 18) | (LOC_D[1] << 12) |
 208              (LOC_D[0] << 6)  | (LOC_C[6] << 0);
 209        nx_lvds_set_lvdsloc4(0, val);
 210
 211        val = (LOC_E[1] << 24) | (LOC_E[0] << 18) | (LOC_D[6] << 12) |
 212              (LOC_D[5] << 6)  | (LOC_D[4] << 0);
 213        nx_lvds_set_lvdsloc5(0, val);
 214
 215        val = (LOC_E[6] << 24) | (LOC_E[5] << 18) | (LOC_E[4] << 12) |
 216              (LOC_E[3] << 6)  | (LOC_E[2] << 0);
 217        nx_lvds_set_lvdsloc6(0, val);
 218
 219        nx_lvds_set_lvdslocmask0(0, 0xffffffff);
 220        nx_lvds_set_lvdslocmask1(0, 0xffffffff);
 221
 222        nx_lvds_set_lvdslocpol0(0, (0 << 19) | (0 << 18));
 223
 224        /*
 225         * select TOP MUX
 226         */
 227        nx_disp_top_set_lvdsmux(1, input);
 228
 229        /*
 230         * LVDS PHY Reset, make sure last.
 231         */
 232        lvds_phy_reset();
 233
 234        return 0;
 235}
 236
 237void nx_lvds_display(int module,
 238                     struct dp_sync_info *sync, struct dp_ctrl_info *ctrl,
 239                     struct dp_plane_top *top, struct dp_plane_info *planes,
 240                     struct dp_lvds_dev *dev)
 241{
 242        struct dp_plane_info *plane = planes;
 243        int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1;
 244        int count = top->plane_num;
 245        int i = 0;
 246
 247        printf("LVDS:  dp.%d\n", module);
 248
 249        dp_control_init(module);
 250        dp_plane_init(module);
 251
 252        lvds_init();
 253
 254        /* set plane */
 255        dp_plane_screen_setup(module, top);
 256
 257        for (i = 0; count > i; i++, plane++) {
 258                if (!plane->enable)
 259                        continue;
 260                dp_plane_layer_setup(module, plane);
 261                dp_plane_layer_enable(module, plane, 1);
 262        }
 263
 264        dp_plane_screen_enable(module, 1);
 265
 266        /* set lvds */
 267        lvds_setup(module, input, sync, ctrl, dev);
 268
 269        lvds_enable(1);
 270
 271        /* set dp control */
 272        dp_control_setup(module, sync, ctrl);
 273        dp_control_enable(module, 1);
 274}
 275