ddk750_display.c (4222B)
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}