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