ddk750_mode.c (6877B)
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 17displayControlAdjust_SM750LE(struct mode_parameter *pModeParam, 18 unsigned long dispControl) 19{ 20 unsigned long x, y; 21 22 x = pModeParam->horizontal_display_end; 23 y = pModeParam->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 dispControl have been properly set before 40 * calling this function. 41 * This function only sets the extra fields in dispControl. 42 */ 43 44 /* Clear bit 29:27 of display control register */ 45 dispControl &= ~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 dispControl |= CRT_DISPLAY_CTRL_CLK_PLL41; 51 else if (x == 1024 && y == 768) 52 dispControl |= CRT_DISPLAY_CTRL_CLK_PLL65; 53 else if (x == 1152 && y == 864) 54 dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80; 55 else if (x == 1280 && y == 768) 56 dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80; 57 else if (x == 1280 && y == 720) 58 dispControl |= CRT_DISPLAY_CTRL_CLK_PLL74; 59 else if (x == 1280 && y == 960) 60 dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108; 61 else if (x == 1280 && y == 1024) 62 dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108; 63 else /* default to VGA clock */ 64 dispControl |= CRT_DISPLAY_CTRL_CLK_PLL25; 65 66 /* Set bit 25:24 of display controller */ 67 dispControl |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT); 68 69 /* Set bit 14 of display controller */ 70 dispControl |= DISPLAY_CTRL_CLOCK_PHASE; 71 72 poke32(CRT_DISPLAY_CTRL, dispControl); 73 74 return dispControl; 75} 76 77/* only timing related registers will be programed */ 78static int programModeRegisters(struct mode_parameter *pModeParam, 79 struct pll_value *pll) 80{ 81 int ret = 0; 82 int cnt = 0; 83 unsigned int tmp, reg; 84 85 if (pll->clock_type == SECONDARY_PLL) { 86 /* programe secondary pixel clock */ 87 poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll)); 88 89 tmp = ((pModeParam->horizontal_total - 1) << 90 CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) & 91 CRT_HORIZONTAL_TOTAL_TOTAL_MASK; 92 tmp |= (pModeParam->horizontal_display_end - 1) & 93 CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK; 94 95 poke32(CRT_HORIZONTAL_TOTAL, tmp); 96 97 tmp = (pModeParam->horizontal_sync_width << 98 CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) & 99 CRT_HORIZONTAL_SYNC_WIDTH_MASK; 100 tmp |= (pModeParam->horizontal_sync_start - 1) & 101 CRT_HORIZONTAL_SYNC_START_MASK; 102 103 poke32(CRT_HORIZONTAL_SYNC, tmp); 104 105 tmp = ((pModeParam->vertical_total - 1) << 106 CRT_VERTICAL_TOTAL_TOTAL_SHIFT) & 107 CRT_VERTICAL_TOTAL_TOTAL_MASK; 108 tmp |= (pModeParam->vertical_display_end - 1) & 109 CRT_VERTICAL_TOTAL_DISPLAY_END_MASK; 110 111 poke32(CRT_VERTICAL_TOTAL, tmp); 112 113 tmp = ((pModeParam->vertical_sync_height << 114 CRT_VERTICAL_SYNC_HEIGHT_SHIFT)) & 115 CRT_VERTICAL_SYNC_HEIGHT_MASK; 116 tmp |= (pModeParam->vertical_sync_start - 1) & 117 CRT_VERTICAL_SYNC_START_MASK; 118 119 poke32(CRT_VERTICAL_SYNC, tmp); 120 121 tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE; 122 if (pModeParam->vertical_sync_polarity) 123 tmp |= DISPLAY_CTRL_VSYNC_PHASE; 124 if (pModeParam->horizontal_sync_polarity) 125 tmp |= DISPLAY_CTRL_HSYNC_PHASE; 126 127 if (sm750_get_chip_type() == SM750LE) { 128 displayControlAdjust_SM750LE(pModeParam, tmp); 129 } else { 130 reg = peek32(CRT_DISPLAY_CTRL) & 131 ~(DISPLAY_CTRL_VSYNC_PHASE | 132 DISPLAY_CTRL_HSYNC_PHASE | 133 DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE); 134 135 poke32(CRT_DISPLAY_CTRL, tmp | reg); 136 } 137 138 } else if (pll->clock_type == PRIMARY_PLL) { 139 unsigned int reserved; 140 141 poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll)); 142 143 reg = ((pModeParam->horizontal_total - 1) << 144 PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) & 145 PANEL_HORIZONTAL_TOTAL_TOTAL_MASK; 146 reg |= ((pModeParam->horizontal_display_end - 1) & 147 PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK); 148 poke32(PANEL_HORIZONTAL_TOTAL, reg); 149 150 poke32(PANEL_HORIZONTAL_SYNC, 151 ((pModeParam->horizontal_sync_width << 152 PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) & 153 PANEL_HORIZONTAL_SYNC_WIDTH_MASK) | 154 ((pModeParam->horizontal_sync_start - 1) & 155 PANEL_HORIZONTAL_SYNC_START_MASK)); 156 157 poke32(PANEL_VERTICAL_TOTAL, 158 (((pModeParam->vertical_total - 1) << 159 PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) & 160 PANEL_VERTICAL_TOTAL_TOTAL_MASK) | 161 ((pModeParam->vertical_display_end - 1) & 162 PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK)); 163 164 poke32(PANEL_VERTICAL_SYNC, 165 ((pModeParam->vertical_sync_height << 166 PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) & 167 PANEL_VERTICAL_SYNC_HEIGHT_MASK) | 168 ((pModeParam->vertical_sync_start - 1) & 169 PANEL_VERTICAL_SYNC_START_MASK)); 170 171 tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE; 172 if (pModeParam->vertical_sync_polarity) 173 tmp |= DISPLAY_CTRL_VSYNC_PHASE; 174 if (pModeParam->horizontal_sync_polarity) 175 tmp |= DISPLAY_CTRL_HSYNC_PHASE; 176 if (pModeParam->clock_phase_polarity) 177 tmp |= DISPLAY_CTRL_CLOCK_PHASE; 178 179 reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK | 180 PANEL_DISPLAY_CTRL_VSYNC; 181 182 reg = (peek32(PANEL_DISPLAY_CTRL) & ~reserved) & 183 ~(DISPLAY_CTRL_CLOCK_PHASE | DISPLAY_CTRL_VSYNC_PHASE | 184 DISPLAY_CTRL_HSYNC_PHASE | DISPLAY_CTRL_TIMING | 185 DISPLAY_CTRL_PLANE); 186 187 /* 188 * May a hardware bug or just my test chip (not confirmed). 189 * PANEL_DISPLAY_CTRL register seems requiring few writes 190 * before a value can be successfully written in. 191 * Added some masks to mask out the reserved bits. 192 * Note: This problem happens by design. The hardware will wait 193 * for the next vertical sync to turn on/off the plane. 194 */ 195 poke32(PANEL_DISPLAY_CTRL, tmp | reg); 196 197 while ((peek32(PANEL_DISPLAY_CTRL) & ~reserved) != 198 (tmp | reg)) { 199 cnt++; 200 if (cnt > 1000) 201 break; 202 poke32(PANEL_DISPLAY_CTRL, tmp | reg); 203 } 204 } else { 205 ret = -1; 206 } 207 return ret; 208} 209 210int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock) 211{ 212 struct pll_value pll; 213 214 pll.input_freq = DEFAULT_INPUT_CLOCK; 215 pll.clock_type = clock; 216 217 sm750_calc_pll_value(parm->pixel_clock, &pll); 218 if (sm750_get_chip_type() == SM750LE) { 219 /* set graphic mode via IO method */ 220 outb_p(0x88, 0x3d4); 221 outb_p(0x06, 0x3d5); 222 } 223 programModeRegisters(parm, &pll); 224 return 0; 225}