]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/sm750fb/ddk750_mode.c
f81e0532387543a965fa7994236b799e73ab9ef4
[karo-tx-linux.git] / drivers / staging / sm750fb / ddk750_mode.c
1
2 #include "ddk750_help.h"
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 */
16 static unsigned long displayControlAdjust_SM750LE(mode_parameter_t *pModeParam, unsigned long dispControl)
17 {
18         unsigned long x, y;
19
20         x = pModeParam->horizontal_display_end;
21         y = pModeParam->vertical_display_end;
22
23         /* SM750LE has to set up the top-left and bottom-right
24            registers as well.
25            Note that normal SM750/SM718 only use those two register for
26            auto-centering mode.
27          */
28         POKE32(CRT_AUTO_CENTERING_TL,
29         FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, TOP, 0)
30         | FIELD_VALUE(0, CRT_AUTO_CENTERING_TL, LEFT, 0));
31
32         POKE32(CRT_AUTO_CENTERING_BR,
33         FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, BOTTOM, y - 1)
34         | FIELD_VALUE(0, CRT_AUTO_CENTERING_BR, RIGHT, x - 1));
35
36         /* Assume common fields in dispControl have been properly set before
37            calling this function.
38            This function only sets the extra fields in dispControl.
39          */
40
41         /* Clear bit 29:27 of display control register */
42         dispControl &= FIELD_CLEAR(CRT_DISPLAY_CTRL, CLK);
43
44         /* Set bit 29:27 of display control register for the right clock */
45         /* Note that SM750LE only need to supported 7 resolutions. */
46         if (x == 800 && y == 600)
47                 dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL41);
48         else if (x == 1024 && y == 768)
49                 dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL65);
50         else if (x == 1152 && y == 864)
51                 dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL80);
52         else if (x == 1280 && y == 768)
53                 dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL80);
54         else if (x == 1280 && y == 720)
55                 dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL74);
56         else if (x == 1280 && y == 960)
57                 dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL108);
58         else if (x == 1280 && y == 1024)
59                 dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL108);
60         else /* default to VGA clock */
61         dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CLK, PLL25);
62
63         /* Set bit 25:24 of display controller */
64         dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, CRTSELECT, CRT);
65         dispControl = FIELD_SET(dispControl, CRT_DISPLAY_CTRL, RGBBIT, 24BIT);
66
67         /* Set bit 14 of display controller */
68         dispControl = FIELD_SET(dispControl, DISPLAY_CTRL, CLOCK_PHASE,
69                                 ACTIVE_LOW);
70
71         POKE32(CRT_DISPLAY_CTRL, dispControl);
72
73         return dispControl;
74 }
75
76
77
78 /* only timing related registers will be  programed */
79 static int programModeRegisters(mode_parameter_t *pModeParam, pll_value_t *pll)
80 {
81         int ret = 0;
82         int cnt = 0;
83         unsigned int tmp, reg;
84
85         if (pll->clockType == SECONDARY_PLL) {
86                 /* programe secondary pixel clock */
87                 POKE32(CRT_PLL_CTRL, formatPllReg(pll));
88                 POKE32(CRT_HORIZONTAL_TOTAL,
89                 FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1)
90                 | FIELD_VALUE(0, CRT_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1));
91
92                 POKE32(CRT_HORIZONTAL_SYNC,
93                 FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width)
94                 | FIELD_VALUE(0, CRT_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1));
95
96                 POKE32(CRT_VERTICAL_TOTAL,
97                 FIELD_VALUE(0, CRT_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1)
98                 | FIELD_VALUE(0, CRT_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1));
99
100                 POKE32(CRT_VERTICAL_SYNC,
101                 FIELD_VALUE(0, CRT_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height)
102                 | FIELD_VALUE(0, CRT_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1));
103
104
105                 tmp = FIELD_VALUE(0, DISPLAY_CTRL, VSYNC_PHASE,
106                                   pModeParam->vertical_sync_polarity) |
107                         FIELD_VALUE(0, DISPLAY_CTRL, HSYNC_PHASE,
108                                     pModeParam->horizontal_sync_polarity) |
109                         FIELD_SET(0, DISPLAY_CTRL, TIMING, ENABLE) |
110                         FIELD_SET(0, DISPLAY_CTRL, PLANE, ENABLE);
111
112
113                 if (getChipType() == SM750LE) {
114                         displayControlAdjust_SM750LE(pModeParam, tmp);
115                 } else {
116                         reg = PEEK32(CRT_DISPLAY_CTRL)
117                                 & FIELD_CLEAR(DISPLAY_CTRL, VSYNC_PHASE)
118                                 & FIELD_CLEAR(DISPLAY_CTRL, HSYNC_PHASE)
119                                 & FIELD_CLEAR(DISPLAY_CTRL, TIMING)
120                                 & FIELD_CLEAR(DISPLAY_CTRL, PLANE);
121
122                          POKE32(CRT_DISPLAY_CTRL, tmp | reg);
123                 }
124
125         } else if (pll->clockType == PRIMARY_PLL) {
126                 unsigned int reserved;
127
128                 POKE32(PANEL_PLL_CTRL, formatPllReg(pll));
129
130                 POKE32(PANEL_HORIZONTAL_TOTAL,
131                 FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, TOTAL, pModeParam->horizontal_total - 1)
132                 | FIELD_VALUE(0, PANEL_HORIZONTAL_TOTAL, DISPLAY_END, pModeParam->horizontal_display_end - 1));
133
134                 POKE32(PANEL_HORIZONTAL_SYNC,
135                 FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, WIDTH, pModeParam->horizontal_sync_width)
136                 | FIELD_VALUE(0, PANEL_HORIZONTAL_SYNC, START, pModeParam->horizontal_sync_start - 1));
137
138                 POKE32(PANEL_VERTICAL_TOTAL,
139                 FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, TOTAL, pModeParam->vertical_total - 1)
140                         | FIELD_VALUE(0, PANEL_VERTICAL_TOTAL, DISPLAY_END, pModeParam->vertical_display_end - 1));
141
142                 POKE32(PANEL_VERTICAL_SYNC,
143                 FIELD_VALUE(0, PANEL_VERTICAL_SYNC, HEIGHT, pModeParam->vertical_sync_height)
144                 | FIELD_VALUE(0, PANEL_VERTICAL_SYNC, START, pModeParam->vertical_sync_start - 1));
145
146                 tmp = FIELD_VALUE(0, DISPLAY_CTRL, VSYNC_PHASE,
147                                   pModeParam->vertical_sync_polarity) |
148                         FIELD_VALUE(0, DISPLAY_CTRL, HSYNC_PHASE,
149                                     pModeParam->horizontal_sync_polarity) |
150                         FIELD_VALUE(0, DISPLAY_CTRL, CLOCK_PHASE,
151                                      pModeParam->clock_phase_polarity) |
152                         FIELD_SET(0, DISPLAY_CTRL, TIMING, ENABLE) |
153                         FIELD_SET(0, DISPLAY_CTRL, PLANE, ENABLE);
154
155                 reserved = FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_1_MASK,
156                                      ENABLE) |
157                                  FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_2_MASK, ENABLE) |
158                                  FIELD_SET(0, PANEL_DISPLAY_CTRL, RESERVED_3_MASK, ENABLE) |
159                                  FIELD_SET(0, PANEL_DISPLAY_CTRL, VSYNC, ACTIVE_LOW);
160
161                 reg = (PEEK32(PANEL_DISPLAY_CTRL) & ~reserved)
162                         & FIELD_CLEAR(DISPLAY_CTRL, CLOCK_PHASE)
163                         & FIELD_CLEAR(DISPLAY_CTRL, VSYNC_PHASE)
164                         & FIELD_CLEAR(DISPLAY_CTRL, HSYNC_PHASE)
165                         & FIELD_CLEAR(DISPLAY_CTRL, TIMING)
166                         & FIELD_CLEAR(DISPLAY_CTRL, PLANE);
167
168
169                 /* May a hardware bug or just my test chip (not confirmed).
170                 * PANEL_DISPLAY_CTRL register seems requiring few writes
171                 * before a value can be successfully written in.
172                 * Added some masks to mask out the reserved bits.
173                 * Note: This problem happens by design. The hardware will wait for the
174                 *       next vertical sync to turn on/off the plane.
175                 */
176
177                 POKE32(PANEL_DISPLAY_CTRL, tmp | reg);
178
179                 while ((PEEK32(PANEL_DISPLAY_CTRL) & ~reserved) !=
180                         (tmp | reg)) {
181                         cnt++;
182                         if (cnt > 1000)
183                                 break;
184                         POKE32(PANEL_DISPLAY_CTRL, tmp | reg);
185                 }
186         } else {
187                 ret = -1;
188         }
189         return ret;
190 }
191
192 int ddk750_setModeTiming(mode_parameter_t *parm, clock_type_t clock)
193 {
194         pll_value_t pll;
195         unsigned int uiActualPixelClk;
196
197         pll.inputFreq = DEFAULT_INPUT_CLOCK;
198         pll.clockType = clock;
199
200         uiActualPixelClk = calcPllValue(parm->pixel_clock, &pll);
201         if (getChipType() == SM750LE) {
202                 /* set graphic mode via IO method */
203                 outb_p(0x88, 0x3d4);
204                 outb_p(0x06, 0x3d5);
205         }
206         programModeRegisters(parm, &pll);
207         return 0;
208 }
209
210