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(addr: 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(addr: reg, data: 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(addr: reg, data: val);
43 } while ((peek32(addr: 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(addr: reg, data: val);
57
58 val &= ~DISPLAY_CTRL_TIMING;
59 poke32(addr: reg, data: 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, data: 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, data: 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, data: 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, data: 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, data: 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, data: reg);
136 }
137
138 if (output & PRI_TP_USAGE) {
139 /* set primary timing and plane en_bit */
140 set_display_control(ctrl: 0, disp_state: (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(ctrl: 1, disp_state: (output & SEC_TP_MASK) >> SEC_TP_OFFSET);
146 }
147
148 if (output & PNL_SEQ_USAGE) {
149 /* set panel sequence */
150 sw_panel_power_sequence(disp: (output & PNL_SEQ_MASK) >>
151 PNL_SEQ_OFFSET, delay: 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(state: (output & DPMS_MASK) >> DPMS_OFFSET);
159}
160

source code of linux/drivers/staging/sm750fb/ddk750_display.c