xref: /linux/drivers/staging/sm750fb/ddk750_display.c (revision 307797159ac25fe5a2048bf5c6a5718298edca57)
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 setDisplayControl(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 
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 swPanelPowerSequence(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 
114 void ddk750_setLogicalDispOut(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 		setDisplayControl(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 		setDisplayControl(1, (output & SEC_TP_MASK) >> SEC_TP_OFFSET);
146 	}
147 
148 	if (output & PNL_SEQ_USAGE) {
149 		/* set  panel sequence */
150 		swPanelPowerSequence((output & PNL_SEQ_MASK) >> PNL_SEQ_OFFSET,
151 				     4);
152 	}
153 
154 	if (output & DAC_USAGE)
155 		setDAC((output & DAC_MASK) >> DAC_OFFSET);
156 
157 	if (output & DPMS_USAGE)
158 		ddk750_set_dpms((output & DPMS_MASK) >> DPMS_OFFSET);
159 }
160