mq200subr.c revision 1.1 1 /* $NetBSD: mq200subr.c,v 1.1 2001/03/25 13:06:53 takemura Exp $ */
2
3 /*-
4 * Copyright (c) 2001 TAKEMURA Shin
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 */
31
32 #ifdef _KERNEL
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #else
38 #include <stdio.h>
39 #endif
40 #include <sys/types.h>
41
42 #include <machine/platid.h>
43 #include <machine/platid_mask.h>
44
45 #include "opt_mq200.h"
46 #include "mq200var.h"
47 #include "mq200reg.h"
48 #include "mq200priv.h"
49
50 #define ABS(a) ((a) < 0 ? -(a) : (a))
51
52 int mq200_depth_table[] = {
53 [MQ200_GCC_1BPP] = 1,
54 [MQ200_GCC_2BPP] = 2,
55 [MQ200_GCC_4BPP] = 4,
56 [MQ200_GCC_8BPP] = 8,
57 [MQ200_GCC_16BPP] = 16,
58 [MQ200_GCC_24BPP] = 32,
59 [MQ200_GCC_ARGB888] = 32,
60 [MQ200_GCC_ABGR888] = 32,
61 [MQ200_GCC_16BPP_DIRECT] = 16,
62 [MQ200_GCC_24BPP_DIRECT] = 32,
63 [MQ200_GCC_ARGB888_DIRECT] = 32,
64 [MQ200_GCC_ABGR888_DIRECT] = 32,
65 };
66
67 struct mq200_crt_param mq200_crt_params[] = {
68 [MQ200_CRT_640x480_60Hz] =
69 { 640, 480, 25175, /* width, height, dot clock */
70 800, /* HD Total */
71 525, /* VD Total */
72 656, 752, /* HS Start, HS End */
73 490, 492, /* VS Start, VS End */
74 (MQ200_GC1CRTC_HSYNC_ACTVLOW |
75 MQ200_GC1CRTC_VSYNC_ACTVLOW |
76 MQ200_GC1CRTC_BLANK_PEDESTAL_EN),
77 },
78 [MQ200_CRT_800x600_60Hz] =
79 { 800, 600, 40000, /* width, height, dot clock */
80 1054, /* HD Total */
81 628, /* VD Total */
82 839, 967, /* HS Start, HS End */
83 601, 605, /* VS Start, VS End */
84 MQ200_GC1CRTC_BLANK_PEDESTAL_EN,
85 },
86 [MQ200_CRT_1024x768_60Hz] =
87 { 1024, 768, 65000, /* width, height, dot clock */
88 1344, /* HD Total */
89 806, /* VD Total */
90 1048, 1184, /* HS Start, HS End */
91 771, 777, /* VS Start, VS End */
92 (MQ200_GC1CRTC_HSYNC_ACTVLOW |
93 MQ200_GC1CRTC_VSYNC_ACTVLOW |
94 MQ200_GC1CRTC_BLANK_PEDESTAL_EN),
95 },
96 };
97
98 int mq200_crt_nparams = sizeof(mq200_crt_params)/sizeof(*mq200_crt_params);
99
100 /*
101 * get PLL setting register value for given frequency
102 */
103 void
104 mq200_pllparam(int reqout, u_int32_t *res)
105 {
106 int n, m, p, out;
107 int ref = 12288;
108 int bn, bm, bp, e;
109
110 e = ref;
111 for (p = 0; p <= 4; p++) {
112 for (n = 0; n < (1<<5); n++) {
113 m = (reqout * ((n + 1) << p)) / ref - 1;
114 out = ref * (m + 1) / ((n + 1) << p);
115 if (0xff < m)
116 break;
117 if (40 <= m &&
118 1000 <= ref/(n + 1) &&
119 170000 <= ref*(m+1)/(n+1) &&
120 ref*(m+1)/(n+1) <= 340000 &&
121 ABS(reqout - out) <= e) {
122 e = ABS(reqout - out);
123 bn = n;
124 bm = m;
125 bp = p;
126 }
127 }
128 }
129
130 #if 0
131 out = ref * (bm + 1) / ((bn + 1) << bp);
132 printf("PLL: %d.%03d x (%d+1) / (%d+1) / %d = %d.%03d\n",
133 ref / 1000, ref % 1000, bm, bn, (1<<bp),
134 out / 1000, out % 1000);
135 #endif
136 *res = ((bm << MQ200_PLL_M_SHIFT) |
137 (bn << MQ200_PLL_N_SHIFT) |
138 (bp << MQ200_PLL_P_SHIFT));
139 }
140
141 void
142 mq200_set_pll(struct mq200_softc *sc, int pll, int clock)
143 {
144 struct mq200_regctx *paramreg, *enreg;
145 u_int32_t param, enbit;
146
147 switch (pll) {
148 case MQ200_CLOCK_PLL1:
149 paramreg = &sc->sc_regctxs[MQ200_I_PLL(1)];
150 enreg = &sc->sc_regctxs[MQ200_I_DCMISC];
151 enbit = MQ200_DCMISC_PLL1_ENABLE;
152 break;
153 case MQ200_CLOCK_PLL2:
154 paramreg = &sc->sc_regctxs[MQ200_I_PLL(2)];
155 enreg = &sc->sc_regctxs[MQ200_I_PMC];
156 enbit = MQ200_PMC_PLL2_ENABLE;
157 break;
158 case MQ200_CLOCK_PLL3:
159 paramreg = &sc->sc_regctxs[MQ200_I_PLL(3)];
160 enreg = &sc->sc_regctxs[MQ200_I_PMC];
161 enbit = MQ200_PMC_PLL3_ENABLE;
162 break;
163 default:
164 printf("mq200: invalid PLL: %d\n", pll);
165 return;
166 }
167 if (clock != 0 && clock != -1) {
168 /* PLL Programming */
169 mq200_pllparam(clock, ¶m);
170 mq200_mod(sc, paramreg, MQ200_PLL_PARAM_MASK, param);
171 /* enable PLL */
172 mq200_on(sc, enreg, enbit);
173 }
174
175 DPRINTF("%s %d.%03dMHz\n",
176 mq200_clknames[pll], clock/1000, clock%1000);
177 }
178
179 void
180 mq200_setup_regctx(struct mq200_softc *sc)
181 {
182 int i;
183 static int offsets[MQ200_I_MAX] = {
184 [MQ200_I_DCMISC] = MQ200_DCMISCR,
185 [MQ200_I_PLL(2)] = MQ200_PLL2R,
186 [MQ200_I_PLL(3)] = MQ200_PLL3R,
187 [MQ200_I_PMC] = MQ200_PMCR,
188 [MQ200_I_MM01] = MQ200_MMR(1),
189 [MQ200_I_GCC(MQ200_GC1)] = MQ200_GCCR(MQ200_GC1),
190 [MQ200_I_GCC(MQ200_GC2)] = MQ200_GCCR(MQ200_GC2),
191 };
192
193 for (i = 0; i < sizeof(offsets)/sizeof(*offsets); i++) {
194 if (offsets[i] == 0)
195 #ifdef MQ200_DEBUG
196 panic("%s(%d): register context %d is empty\n",
197 __FILE__, __LINE__, i);
198 #endif
199 sc->sc_regctxs[i].offset = offsets[i];
200 }
201 }
202
203 void
204 mq200_setup(struct mq200_softc *sc)
205 {
206 const struct mq200_clock_setting *clock;
207 const struct mq200_crt_param *crt;
208
209 clock = &sc->sc_md->md_clock_settings[sc->sc_flags & MQ200_SC_GC_MASK];
210 crt = sc->sc_crt;
211
212 /* disable GC1 and GC2 */
213 //mq200_write(sc, MQ200_GCCR(MQ200_GC1), 0);
214 mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC1)], 0);
215 mq200_write(sc, MQ200_GC1CRTCR, 0);
216 //mq200_write(sc, MQ200_GCCR(MQ200_GC2), 0);
217 mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC2)], 0);
218
219 while (mq200_read(sc, MQ200_PMCR) & MQ200_PMC_SEQPROGRESS)
220 /* busy wait */;
221
222 /*
223 * setup around clock
224 */
225 /* setup eatch PLLs */
226 mq200_set_pll(sc, MQ200_CLOCK_PLL1, clock->pll1);
227 mq200_set_pll(sc, MQ200_CLOCK_PLL2, clock->pll2);
228 mq200_set_pll(sc, MQ200_CLOCK_PLL3, clock->pll3);
229 if (sc->sc_flags & MQ200_SC_GC1_ENABLE)
230 mq200_set_pll(sc, clock->gc[MQ200_GC1], crt->clock);
231
232 /* setup MEMORY clock */
233 if (clock->mem == MQ200_CLOCK_PLL2)
234 mq200_on(sc, &sc->sc_regctxs[MQ200_I_MM01],
235 MQ200_MM01_CLK_PLL2);
236 else
237 mq200_off(sc, &sc->sc_regctxs[MQ200_I_MM01],
238 MQ200_MM01_CLK_PLL2);
239 DPRINTF("MEM: PLL%d\n", (clock->mem == MQ200_CLOCK_PLL2)?2:1);
240
241 /* setup GE clock */
242 mq200_mod(sc, &sc->sc_regctxs[MQ200_I_PMC],
243 MQ200_PMC_GE_CLK_MASK | MQ200_PMC_GE_ENABLE,
244 (clock->ge << MQ200_PMC_GE_CLK_SHIFT) | MQ200_PMC_GE_ENABLE);
245 DPRINTF(" GE: PLL%d\n", clock->ge);
246
247 /*
248 * setup GC1 (CRT contoller)
249 */
250 if (sc->sc_flags & MQ200_SC_GC1_ENABLE) {
251 /* GC03R Horizontal Display Control */
252 mq200_write(sc, MQ200_GCHDCR(MQ200_GC1),
253 (((u_int32_t)crt->hdtotal-2)<<MQ200_GC1HDC_TOTAL_SHIFT) |
254 ((u_int32_t)crt->width << MQ200_GCHDC_END_SHIFT));
255
256 /* GC03R Vertical Display Control */
257 mq200_write(sc, MQ200_GCVDCR(MQ200_GC1),
258 (((u_int32_t)crt->vdtotal-1)<<MQ200_GC1VDC_TOTAL_SHIFT) |
259 (((u_int32_t)crt->height - 1) << MQ200_GCVDC_END_SHIFT));
260
261 /* GC04R Horizontal Sync Control */
262 mq200_write(sc, MQ200_GCHSCR(MQ200_GC1),
263 ((u_int32_t)crt->hsstart << MQ200_GCHSC_START_SHIFT) |
264 ((u_int32_t)crt->hsend << MQ200_GCHSC_END_SHIFT));
265
266 /* GC05R Vertical Sync Control */
267 mq200_write(sc, MQ200_GCVSCR(MQ200_GC1),
268 ((u_int32_t)crt->vsstart << MQ200_GCVSC_START_SHIFT) |
269 ((u_int32_t)crt->vsend << MQ200_GCVSC_END_SHIFT));
270
271 /* GC00R GC1 Control */
272 //mq200_write(sc, MQ200_GCCR(MQ200_GC1),
273 mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC1)],
274 (MQ200_GCC_ENABLE |
275 (clock->gc[MQ200_GC1] << MQ200_GCC_RCLK_SHIFT) |
276 MQ200_GCC_MCLK_FD_1 |
277 (1 << MQ200_GCC_MCLK_SD_SHIFT)));
278
279 /* GC01R CRT Control */
280 mq200_write(sc, MQ200_GC1CRTCR,
281 MQ200_GC1CRTC_DACEN | crt->opt);
282
283 sc->sc_width[MQ200_GC1] = crt->width;
284 sc->sc_height[MQ200_GC1] = crt->height;
285
286 DPRINTF("GC1: %s\n",
287 mq200_clknames[clock->gc[MQ200_GC1]]);
288 }
289
290 while (mq200_read(sc, MQ200_PMCR) & MQ200_PMC_SEQPROGRESS)
291 /* busy wait */;
292
293 /*
294 * setup GC2 (FP contoller)
295 */
296 if (sc->sc_flags & MQ200_SC_GC2_ENABLE) {
297 //mq200_write(sc, MQ200_GCCR(MQ200_GC2),
298 mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC2)],
299 MQ200_GCC_ENABLE |
300 (clock->gc[MQ200_GC2] << MQ200_GCC_RCLK_SHIFT) |
301 MQ200_GCC_MCLK_FD_1 | (1 << MQ200_GCC_MCLK_SD_SHIFT));
302 DPRINTF("GC2: %s\n",
303 mq200_clknames[clock->gc[MQ200_GC2]]);
304 }
305
306 while (mq200_read(sc, MQ200_PMCR) & MQ200_PMC_SEQPROGRESS)
307 /* busy wait */;
308
309 /*
310 * disable unused PLLs
311 */
312 if (clock->pll1 == 0) {
313 DPRINTF("PLL1 disable\n");
314 mq200_off(sc, &sc->sc_regctxs[MQ200_I_DCMISC],
315 MQ200_DCMISC_PLL1_ENABLE);
316 }
317 if (clock->pll2 == 0) {
318 DPRINTF("PLL2 disable\n");
319 mq200_off(sc, &sc->sc_regctxs[MQ200_I_PMC],
320 MQ200_PMC_PLL2_ENABLE);
321 }
322 if (clock->pll3 == 0) {
323 DPRINTF("PLL3 disable\n");
324 mq200_off(sc, &sc->sc_regctxs[MQ200_I_PMC],
325 MQ200_PMC_PLL3_ENABLE);
326 }
327 }
328
329 void
330 mq200_win_enable(struct mq200_softc *sc, int gc,
331 u_int32_t depth, u_int32_t start,
332 int width, int height, int stride)
333 {
334
335 DPRINTF("enable window on GC%d: %dx%d(%dx%d)\n",
336 gc + 1, width, height, sc->sc_width[gc], sc->sc_height[gc]);
337
338 if (sc->sc_width[gc] < width) {
339 if (mq200_depth_table[depth])
340 start += (height - sc->sc_height[gc]) *
341 mq200_depth_table[depth] / 8;
342 width = sc->sc_width[gc];
343 }
344
345 if (sc->sc_height[gc] < height) {
346 start += (height - sc->sc_height[gc]) * stride;
347 height = sc->sc_height[gc];
348 }
349
350 /* GC08R Window Horizontal Control */
351 mq200_write(sc, MQ200_GCWHCR(gc),
352 (((u_int32_t)width - 1) << MQ200_GCWHC_WIDTH_SHIFT) |
353 ((sc->sc_width[gc] - width)/2));
354
355 /* GC09R Window Vertical Control */
356 mq200_write(sc, MQ200_GCWVCR(gc),
357 (((u_int32_t)height - 1) << MQ200_GCWVC_HEIGHT_SHIFT) |
358 ((sc->sc_height[gc] - height)/2));
359
360 /* GC00R GC Control */
361 mq200_mod(sc, &sc->sc_regctxs[MQ200_I_GCC(gc)],
362 (MQ200_GCC_WINEN | MQ200_GCC_DEPTH_MASK),
363 (MQ200_GCC_WINEN | (depth << MQ200_GCC_DEPTH_SHIFT)));
364 }
365
366 void
367 mq200_win_disable(struct mq200_softc *sc, int gc)
368 {
369 /* GC00R GC Control */
370 mq200_off(sc, &sc->sc_regctxs[MQ200_I_GCC(gc)], MQ200_GCC_WINEN);
371 }
372