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