xref: /linux/drivers/staging/sm750fb/ddk750_display.c (revision a100922a3855eb35ecd465f1d558546b1e144445)
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 
set_display_control(int ctrl,int disp_state)7 static void set_display_control(int ctrl, int disp_state)
8 {
9 	/* state != 0 means turn on both timing & plane en_bit */
10 	unsigned long reg, val, reserved;
11 	int cnt = 0;
12 
13 	if (!ctrl) {
14 		reg = PANEL_DISPLAY_CTRL;
15 		reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK;
16 	} else {
17 		reg = CRT_DISPLAY_CTRL;
18 		reserved = CRT_DISPLAY_CTRL_RESERVED_MASK;
19 	}
20 
21 	val = peek32(reg);
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 		 */
29 		val |= DISPLAY_CTRL_TIMING;
30 		poke32(reg, val);
31 
32 		val |= DISPLAY_CTRL_PLANE;
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++;
41 			poke32(reg, val);
42 		} while ((peek32(reg) & ~reserved) != (val & ~reserved));
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 		 */
54 		val &= ~DISPLAY_CTRL_PLANE;
55 		poke32(reg, val);
56 
57 		val &= ~DISPLAY_CTRL_TIMING;
58 		poke32(reg, val);
59 	}
60 }
61 
primary_wait_vertical_sync(int delay)62 static void primary_wait_vertical_sync(int delay)
63 {
64 	unsigned int status;
65 
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 	 */
70 	if (!(peek32(PANEL_PLL_CTRL) & PLL_CTRL_POWER) ||
71 	    !(peek32(PANEL_DISPLAY_CTRL) & DISPLAY_CTRL_TIMING))
72 		return;
73 
74 	while (delay-- > 0) {
75 		/* Wait for end of vsync. */
76 		do {
77 			status = peek32(SYSTEM_CTRL);
78 		} while (status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE);
79 
80 		/* Wait for start of vsync. */
81 		do {
82 			status = peek32(SYSTEM_CTRL);
83 		} while (!(status & SYSTEM_CTRL_PANEL_VSYNC_ACTIVE));
84 	}
85 }
86 
sw_panel_power_sequence(int disp,int delay)87 static void sw_panel_power_sequence(int disp, int delay)
88 {
89 	unsigned int reg;
90 
91 	/* disp should be 1 to open sequence */
92 	reg = peek32(PANEL_DISPLAY_CTRL);
93 	reg |= (disp ? PANEL_DISPLAY_CTRL_FPEN : 0);
94 	poke32(PANEL_DISPLAY_CTRL, reg);
95 	primary_wait_vertical_sync(delay);
96 
97 	reg = peek32(PANEL_DISPLAY_CTRL);
98 	reg |= (disp ? PANEL_DISPLAY_CTRL_DATA : 0);
99 	poke32(PANEL_DISPLAY_CTRL, reg);
100 	primary_wait_vertical_sync(delay);
101 
102 	reg = peek32(PANEL_DISPLAY_CTRL);
103 	reg |= (disp ? PANEL_DISPLAY_CTRL_VBIASEN : 0);
104 	poke32(PANEL_DISPLAY_CTRL, reg);
105 	primary_wait_vertical_sync(delay);
106 
107 	reg = peek32(PANEL_DISPLAY_CTRL);
108 	reg |= (disp ? PANEL_DISPLAY_CTRL_FPEN : 0);
109 	poke32(PANEL_DISPLAY_CTRL, reg);
110 	primary_wait_vertical_sync(delay);
111 }
112 
ddk750_set_logical_disp_out(enum disp_output output)113 void ddk750_set_logical_disp_out(enum disp_output output)
114 {
115 	unsigned int reg;
116 
117 	if (output & PNL_2_USAGE) {
118 		/* set panel path controller select */
119 		reg = peek32(PANEL_DISPLAY_CTRL);
120 		reg &= ~PANEL_DISPLAY_CTRL_SELECT_MASK;
121 		reg |= (((output & PNL_2_MASK) >> PNL_2_OFFSET) <<
122 			PANEL_DISPLAY_CTRL_SELECT_SHIFT);
123 		poke32(PANEL_DISPLAY_CTRL, reg);
124 	}
125 
126 	if (output & CRT_2_USAGE) {
127 		/* set crt path controller select */
128 		reg = peek32(CRT_DISPLAY_CTRL);
129 		reg &= ~CRT_DISPLAY_CTRL_SELECT_MASK;
130 		reg |= (((output & CRT_2_MASK) >> CRT_2_OFFSET) <<
131 			CRT_DISPLAY_CTRL_SELECT_SHIFT);
132 		/*se blank off */
133 		reg &= ~CRT_DISPLAY_CTRL_BLANK;
134 		poke32(CRT_DISPLAY_CTRL, reg);
135 	}
136 
137 	if (output & PRI_TP_USAGE) {
138 		/* set primary timing and plane en_bit */
139 		set_display_control(0, (output & PRI_TP_MASK) >> PRI_TP_OFFSET);
140 	}
141 
142 	if (output & SEC_TP_USAGE) {
143 		/* set secondary timing and plane en_bit*/
144 		set_display_control(1, (output & SEC_TP_MASK) >> SEC_TP_OFFSET);
145 	}
146 
147 	if (output & PNL_SEQ_USAGE) {
148 		/* set  panel sequence */
149 		sw_panel_power_sequence((output & PNL_SEQ_MASK) >>
150 					PNL_SEQ_OFFSET, 4);
151 	}
152 
153 	if (output & DAC_USAGE)
154 		set_DAC((output & DAC_MASK) >> DAC_OFFSET);
155 
156 	if (output & DPMS_USAGE)
157 		ddk750_set_dpms((output & DPMS_MASK) >> DPMS_OFFSET);
158 }
159