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