1// SPDX-License-Identifier: GPL-2.0 2 3#include "ddk750_reg.h" 4#include "ddk750_mode.h" 5#include "ddk750_chip.h" 6 7/* 8 * SM750LE only: 9 * This function takes care extra registers and bit fields required to set 10 * up a mode in SM750LE 11 * 12 * Explanation about Display Control register: 13 * HW only supports 7 predefined pixel clocks, and clock select is 14 * in bit 29:27 of Display Control register. 15 */ 16static unsigned long 17display_control_adjust_SM750LE(struct mode_parameter *mode_param, 18 unsigned long disp_control) 19{ 20 unsigned long x, y; 21 22 x = mode_param->horizontal_display_end; 23 y = mode_param->vertical_display_end; 24 25 /* 26 * SM750LE has to set up the top-left and bottom-right 27 * registers as well. 28 * Note that normal SM750/SM718 only use those two register for 29 * auto-centering mode. 30 */ 31 poke32(CRT_AUTO_CENTERING_TL, 0); 32 33 poke32(CRT_AUTO_CENTERING_BR, 34 (((y - 1) << CRT_AUTO_CENTERING_BR_BOTTOM_SHIFT) & 35 CRT_AUTO_CENTERING_BR_BOTTOM_MASK) | 36 ((x - 1) & CRT_AUTO_CENTERING_BR_RIGHT_MASK)); 37 38 /* 39 * Assume common fields in disp_control have been properly set before 40 * calling this function. 41 * This function only sets the extra fields in disp_control. 42 */ 43 44 /* Clear bit 29:27 of display control register */ 45 disp_control &= ~CRT_DISPLAY_CTRL_CLK_MASK; 46 47 /* Set bit 29:27 of display control register for the right clock */ 48 /* Note that SM750LE only need to supported 7 resolutions. */ 49 if (x == 800 && y == 600) 50 disp_control |= CRT_DISPLAY_CTRL_CLK_PLL41; 51 else if (x == 1024 && y == 768) 52 disp_control |= CRT_DISPLAY_CTRL_CLK_PLL65; 53 else if (x == 1152 && y == 864) 54 disp_control |= CRT_DISPLAY_CTRL_CLK_PLL80; 55 else if (x == 1280 && y == 768) 56 disp_control |= CRT_DISPLAY_CTRL_CLK_PLL80; 57 else if (x == 1280 && y == 720) 58 disp_control |= CRT_DISPLAY_CTRL_CLK_PLL74; 59 else if (x == 1280 && y == 960) 60 disp_control |= CRT_DISPLAY_CTRL_CLK_PLL108; 61 else if (x == 1280 && y == 1024) 62 disp_control |= CRT_DISPLAY_CTRL_CLK_PLL108; 63 else /* default to VGA clock */ 64 disp_control |= CRT_DISPLAY_CTRL_CLK_PLL25; 65 66 /* Set bit 25:24 of display controller */ 67 disp_control |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT); 68 69 /* Set bit 14 of display controller */ 70 disp_control |= DISPLAY_CTRL_CLOCK_PHASE; 71 72 poke32(CRT_DISPLAY_CTRL, disp_control); 73 74 return disp_control; 75} 76 77/* only timing related registers will be programed */ 78static void program_mode_registers(struct mode_parameter *mode_param, 79 struct pll_value *pll) 80{ 81 int cnt = 0; 82 unsigned int tmp, reg; 83 84 if (pll->clock_type == SECONDARY_PLL) { 85 /* programe secondary pixel clock */ 86 poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll)); 87 88 tmp = ((mode_param->horizontal_total - 1) << 89 CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) & 90 CRT_HORIZONTAL_TOTAL_TOTAL_MASK; 91 tmp |= (mode_param->horizontal_display_end - 1) & 92 CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK; 93 94 poke32(CRT_HORIZONTAL_TOTAL, tmp); 95 96 tmp = (mode_param->horizontal_sync_width << 97 CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) & 98 CRT_HORIZONTAL_SYNC_WIDTH_MASK; 99 tmp |= (mode_param->horizontal_sync_start - 1) & 100 CRT_HORIZONTAL_SYNC_START_MASK; 101 102 poke32(CRT_HORIZONTAL_SYNC, tmp); 103 104 tmp = ((mode_param->vertical_total - 1) << 105 CRT_VERTICAL_TOTAL_TOTAL_SHIFT) & 106 CRT_VERTICAL_TOTAL_TOTAL_MASK; 107 tmp |= (mode_param->vertical_display_end - 1) & 108 CRT_VERTICAL_TOTAL_DISPLAY_END_MASK; 109 110 poke32(CRT_VERTICAL_TOTAL, tmp); 111 112 tmp = ((mode_param->vertical_sync_height << 113 CRT_VERTICAL_SYNC_HEIGHT_SHIFT)) & 114 CRT_VERTICAL_SYNC_HEIGHT_MASK; 115 tmp |= (mode_param->vertical_sync_start - 1) & 116 CRT_VERTICAL_SYNC_START_MASK; 117 118 poke32(CRT_VERTICAL_SYNC, tmp); 119 120 tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE; 121 if (mode_param->vertical_sync_polarity) 122 tmp |= DISPLAY_CTRL_VSYNC_PHASE; 123 if (mode_param->horizontal_sync_polarity) 124 tmp |= DISPLAY_CTRL_HSYNC_PHASE; 125 126 if (sm750_get_chip_type() == SM750LE) { 127 display_control_adjust_SM750LE(mode_param, tmp); 128 } else { 129 reg = peek32(CRT_DISPLAY_CTRL) & 130 ~(DISPLAY_CTRL_VSYNC_PHASE | 131 DISPLAY_CTRL_HSYNC_PHASE | 132 DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE); 133 134 poke32(CRT_DISPLAY_CTRL, tmp | reg); 135 } 136 137 } else if (pll->clock_type == PRIMARY_PLL) { 138 unsigned int reserved; 139 140 poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll)); 141 142 reg = ((mode_param->horizontal_total - 1) << 143 PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) & 144 PANEL_HORIZONTAL_TOTAL_TOTAL_MASK; 145 reg |= ((mode_param->horizontal_display_end - 1) & 146 PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK); 147 poke32(PANEL_HORIZONTAL_TOTAL, reg); 148 149 poke32(PANEL_HORIZONTAL_SYNC, 150 ((mode_param->horizontal_sync_width << 151 PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) & 152 PANEL_HORIZONTAL_SYNC_WIDTH_MASK) | 153 ((mode_param->horizontal_sync_start - 1) & 154 PANEL_HORIZONTAL_SYNC_START_MASK)); 155 156 poke32(PANEL_VERTICAL_TOTAL, 157 (((mode_param->vertical_total - 1) << 158 PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) & 159 PANEL_VERTICAL_TOTAL_TOTAL_MASK) | 160 ((mode_param->vertical_display_end - 1) & 161 PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK)); 162 163 poke32(PANEL_VERTICAL_SYNC, 164 ((mode_param->vertical_sync_height << 165 PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) & 166 PANEL_VERTICAL_SYNC_HEIGHT_MASK) | 167 ((mode_param->vertical_sync_start - 1) & 168 PANEL_VERTICAL_SYNC_START_MASK)); 169 170 tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE; 171 if (mode_param->vertical_sync_polarity) 172 tmp |= DISPLAY_CTRL_VSYNC_PHASE; 173 if (mode_param->horizontal_sync_polarity) 174 tmp |= DISPLAY_CTRL_HSYNC_PHASE; 175 if (mode_param->clock_phase_polarity) 176 tmp |= DISPLAY_CTRL_CLOCK_PHASE; 177 178 reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK | 179 PANEL_DISPLAY_CTRL_VSYNC; 180 181 reg = (peek32(PANEL_DISPLAY_CTRL) & ~reserved) & 182 ~(DISPLAY_CTRL_CLOCK_PHASE | DISPLAY_CTRL_VSYNC_PHASE | 183 DISPLAY_CTRL_HSYNC_PHASE | DISPLAY_CTRL_TIMING | 184 DISPLAY_CTRL_PLANE); 185 186 /* 187 * May a hardware bug or just my test chip (not confirmed). 188 * PANEL_DISPLAY_CTRL register seems requiring few writes 189 * before a value can be successfully written in. 190 * Added some masks to mask out the reserved bits. 191 * Note: This problem happens by design. The hardware will wait 192 * for the next vertical sync to turn on/off the plane. 193 */ 194 poke32(PANEL_DISPLAY_CTRL, tmp | reg); 195 196 while ((peek32(PANEL_DISPLAY_CTRL) & ~reserved) != 197 (tmp | reg)) { 198 cnt++; 199 if (cnt > 1000) 200 break; 201 poke32(PANEL_DISPLAY_CTRL, tmp | reg); 202 } 203 } 204} 205 206int ddk750_set_mode_timing(struct mode_parameter *parm, enum clock_type clock) 207{ 208 struct pll_value pll; 209 210 pll.input_freq = DEFAULT_INPUT_CLOCK; 211 pll.clock_type = clock; 212 213 sm750_calc_pll_value(parm->pixel_clock, &pll); 214 if (sm750_get_chip_type() == SM750LE) { 215 /* set graphic mode via IO method */ 216 outb_p(0x88, 0x3d4); 217 outb_p(0x06, 0x3d5); 218 } 219 program_mode_registers(parm, &pll); 220 return 0; 221} 222