linux/drivers/staging/sm750fb/ddk750_display.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include "ddk750_reg.h"
   3#include "ddk750_chip.h"
   4#include "ddk750_display.h"
   5#include "ddk750_power.h"
   6#include "ddk750_dvi.h"
   7
   8static void set_display_control(int ctrl, int disp_state)
   9{
  10        /* state != 0 means turn on both timing & plane en_bit */
  11        unsigned long reg, val, reserved;
  12        int cnt = 0;
  13
  14        if (!ctrl) {
  15                reg = PANEL_DISPLAY_CTRL;
  16                reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK;
  17        } else {
  18                reg = CRT_DISPLAY_CTRL;
  19                reserved = CRT_DISPLAY_CTRL_RESERVED_MASK;
  20        }
  21
  22        val = peek32(reg);
  23        if (disp_state) {
  24                /*
  25                 * Timing should be enabled first before enabling the
  26                 * plane because changing at the same time does not
  27                 * guarantee that the plane will also enabled or
  28                 * disabled.
  29                 */
  30                val |= DISPLAY_CTRL_TIMING;
  31                poke32(reg, val);
  32
  33                val |= DISPLAY_CTRL_PLANE;
  34
  35                /*
  36                 * Somehow the register value on the plane is not set
  37                 * until a few delay. Need to write and read it a
  38                 * couple times
  39                 */
  40                do {
  41                        cnt++;
  42                        poke32(reg, val);
  43                } while ((peek32(reg) & ~reserved) != (val & ~reserved));
  44                pr_debug("Set Plane enbit:after tried %d times\n", cnt);
  45        } else {
  46                /*
  47                 * When turning off, there is no rule on the
  48                 * programming sequence since whenever the clock is
  49                 * off, then it does not matter whether the plane is
  50                 * enabled or disabled.  Note: Modifying the plane bit
  51                 * will take effect on the next vertical sync. Need to
  52                 * find out if it is necessary to wait for 1 vsync
  53                 * before modifying the timing enable bit.
  54                 */
  55                val &= ~DISPLAY_CTRL_PLANE;
  56                poke32(reg, val);
  57
  58                val &= ~DISPLAY_CTRL_TIMING;
  59                poke32(reg, val);
  60        }
  61}
  62
  63static void primary_wait_vertical_sync(int delay)
  64{
  65        unsigned int status;
  66
  67        /*
  68         * Do not wait when the Primary PLL is off or display control is
  69         * already off. This will prevent the software to wait forever.
  70         */
  71        if (!(peek32(PANEL_PLL_CTRL) & PLL_CTRL_POWER) ||
  72            !(peek32(PANEL_DISPLAY_CTRL) & DISPLAY_CTRL_TIMING))
  73                return;
  74
  75        while (delay-- > 0) {
  76                /* Wait for end of vsync. */
  77                do {
  78                        status = peek32(SYSTEM_CTRL);
  79                } while (status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE);
  80
  81                /* Wait for start of vsync. */
  82                do {
  83                        status = peek32(SYSTEM_CTRL);
  84                } while (!(status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE));
  85        }
  86}
  87
  88static void sw_panel_power_sequence(int disp, int delay)
  89{
  90        unsigned int reg;
  91
  92        /* disp should be 1 to open sequence */
  93        reg = peek32(PANEL_DISPLAY_CTRL);
  94        reg |= (disp ? PANEL_DISPLAY_CTRL_FPEN : 0);
  95        poke32(PANEL_DISPLAY_CTRL, reg);
  96        primary_wait_vertical_sync(delay);
  97
  98        reg = peek32(PANEL_DISPLAY_CTRL);
  99        reg |= (disp ? PANEL_DISPLAY_CTRL_DATA : 0);
 100        poke32(PANEL_DISPLAY_CTRL, reg);
 101        primary_wait_vertical_sync(delay);
 102
 103        reg = peek32(PANEL_DISPLAY_CTRL);
 104        reg |= (disp ? PANEL_DISPLAY_CTRL_VBIASEN : 0);
 105        poke32(PANEL_DISPLAY_CTRL, reg);
 106        primary_wait_vertical_sync(delay);
 107
 108        reg = peek32(PANEL_DISPLAY_CTRL);
 109        reg |= (disp ? PANEL_DISPLAY_CTRL_FPEN : 0);
 110        poke32(PANEL_DISPLAY_CTRL, reg);
 111        primary_wait_vertical_sync(delay);
 112}
 113
 114void ddk750_set_logical_disp_out(enum disp_output output)
 115{
 116        unsigned int reg;
 117
 118        if (output & PNL_2_USAGE) {
 119                /* set panel path controller select */
 120                reg = peek32(PANEL_DISPLAY_CTRL);
 121                reg &= ~PANEL_DISPLAY_CTRL_SELECT_MASK;
 122                reg |= (((output & PNL_2_MASK) >> PNL_2_OFFSET) <<
 123                        PANEL_DISPLAY_CTRL_SELECT_SHIFT);
 124                poke32(PANEL_DISPLAY_CTRL, reg);
 125        }
 126
 127        if (output & CRT_2_USAGE) {
 128                /* set crt path controller select */
 129                reg = peek32(CRT_DISPLAY_CTRL);
 130                reg &= ~CRT_DISPLAY_CTRL_SELECT_MASK;
 131                reg |= (((output & CRT_2_MASK) >> CRT_2_OFFSET) <<
 132                        CRT_DISPLAY_CTRL_SELECT_SHIFT);
 133                /*se blank off */
 134                reg &= ~CRT_DISPLAY_CTRL_BLANK;
 135                poke32(CRT_DISPLAY_CTRL, reg);
 136        }
 137
 138        if (output & PRI_TP_USAGE) {
 139                /* set primary timing and plane en_bit */
 140                set_display_control(0, (output & PRI_TP_MASK) >> PRI_TP_OFFSET);
 141        }
 142
 143        if (output & SEC_TP_USAGE) {
 144                /* set secondary timing and plane en_bit*/
 145                set_display_control(1, (output & SEC_TP_MASK) >> SEC_TP_OFFSET);
 146        }
 147
 148        if (output & PNL_SEQ_USAGE) {
 149                /* set  panel sequence */
 150                sw_panel_power_sequence((output & PNL_SEQ_MASK) >>
 151                                        PNL_SEQ_OFFSET, 4);
 152        }
 153
 154        if (output & DAC_USAGE)
 155                set_DAC((output & DAC_MASK) >> DAC_OFFSET);
 156
 157        if (output & DPMS_USAGE)
 158                ddk750_set_dpms((output & DPMS_MASK) >> DPMS_OFFSET);
 159}
 160