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 | |
8 | static 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 | |
63 | static 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 | |
88 | static 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 | |
114 | void 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 | |