xref: /netbsd/sys/arch/hpcmips/dev/mq200subr.c (revision c4a72b64)
1 /*	$NetBSD: mq200subr.c,v 1.3 2002/09/27 15:36:04 provos 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, &param);
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 			if (i != MQ200_I_PMC)
197 				panic("%s(%d): register context %d is empty",
198 				    __FILE__, __LINE__, i);
199 #endif
200 		sc->sc_regctxs[i].offset = offsets[i];
201 	}
202 }
203 
204 void
205 mq200_setup(struct mq200_softc *sc)
206 {
207 	const struct mq200_clock_setting *clock;
208 	const struct mq200_crt_param *crt;
209 
210 	clock = &sc->sc_md->md_clock_settings[sc->sc_flags & MQ200_SC_GC_MASK];
211 	crt = sc->sc_crt;
212 
213 	/* disable GC1 and GC2	*/
214 	//mq200_write(sc, MQ200_GCCR(MQ200_GC1), 0);
215 	mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC1)], 0);
216 	mq200_write(sc, MQ200_GC1CRTCR, 0);
217 	//mq200_write(sc, MQ200_GCCR(MQ200_GC2), 0);
218 	mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC2)], 0);
219 
220 	while (mq200_read(sc, MQ200_PMCR) & MQ200_PMC_SEQPROGRESS)
221 	    /* busy wait */;
222 
223 	/*
224 	 * setup around clock
225 	 */
226 	/* setup eatch PLLs	*/
227 	mq200_set_pll(sc, MQ200_CLOCK_PLL1, clock->pll1);
228 	mq200_set_pll(sc, MQ200_CLOCK_PLL2, clock->pll2);
229 	mq200_set_pll(sc, MQ200_CLOCK_PLL3, clock->pll3);
230 	if (sc->sc_flags & MQ200_SC_GC1_ENABLE)
231 		mq200_set_pll(sc, clock->gc[MQ200_GC1], crt->clock);
232 
233 	/* setup MEMORY clock */
234 	if (clock->mem == MQ200_CLOCK_PLL2)
235 		mq200_on(sc, &sc->sc_regctxs[MQ200_I_MM01],
236 		    MQ200_MM01_CLK_PLL2);
237 	else
238 		mq200_off(sc, &sc->sc_regctxs[MQ200_I_MM01],
239 		    MQ200_MM01_CLK_PLL2);
240 	DPRINTF("MEM: PLL%d\n", (clock->mem == MQ200_CLOCK_PLL2)?2:1);
241 
242 	/* setup GE clock */
243 	mq200_mod(sc, &sc->sc_regctxs[MQ200_I_PMC],
244 	    MQ200_PMC_GE_CLK_MASK | MQ200_PMC_GE_ENABLE,
245 	    (clock->ge << MQ200_PMC_GE_CLK_SHIFT) | MQ200_PMC_GE_ENABLE);
246 	DPRINTF(" GE: PLL%d\n", clock->ge);
247 
248 	/*
249 	 * setup GC1	(CRT contoller)
250 	 */
251 	if (sc->sc_flags & MQ200_SC_GC1_ENABLE) {
252 		/* GC03R	Horizontal Display Control	*/
253 		mq200_write(sc, MQ200_GCHDCR(MQ200_GC1),
254 		    (((u_int32_t)crt->hdtotal-2)<<MQ200_GC1HDC_TOTAL_SHIFT) |
255 		    ((u_int32_t)crt->width << MQ200_GCHDC_END_SHIFT));
256 
257 		/* GC03R	Vertical Display Control	*/
258 		mq200_write(sc, MQ200_GCVDCR(MQ200_GC1),
259 		    (((u_int32_t)crt->vdtotal-1)<<MQ200_GC1VDC_TOTAL_SHIFT) |
260 		    (((u_int32_t)crt->height - 1) << MQ200_GCVDC_END_SHIFT));
261 
262 		/* GC04R	Horizontal Sync Control		*/
263 		mq200_write(sc, MQ200_GCHSCR(MQ200_GC1),
264 		    ((u_int32_t)crt->hsstart << MQ200_GCHSC_START_SHIFT) |
265 		    ((u_int32_t)crt->hsend << MQ200_GCHSC_END_SHIFT));
266 
267 		/* GC05R	Vertical Sync Control		*/
268 		mq200_write(sc, MQ200_GCVSCR(MQ200_GC1),
269 		    ((u_int32_t)crt->vsstart << MQ200_GCVSC_START_SHIFT) |
270 		    ((u_int32_t)crt->vsend << MQ200_GCVSC_END_SHIFT));
271 
272 		/* GC00R	GC1 Control			*/
273 		//mq200_write(sc, MQ200_GCCR(MQ200_GC1),
274 		mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC1)],
275 		    (MQ200_GCC_ENABLE |
276 			(clock->gc[MQ200_GC1] << MQ200_GCC_RCLK_SHIFT) |
277 			MQ200_GCC_MCLK_FD_1 |
278 			(1 << MQ200_GCC_MCLK_SD_SHIFT)));
279 
280 		/* GC01R	CRT Control			*/
281 		mq200_write(sc, MQ200_GC1CRTCR,
282 		    MQ200_GC1CRTC_DACEN | crt->opt);
283 
284 		sc->sc_width[MQ200_GC1] = crt->width;
285 		sc->sc_height[MQ200_GC1] = crt->height;
286 
287 		DPRINTF("GC1: %s\n",
288 		    mq200_clknames[clock->gc[MQ200_GC1]]);
289 	}
290 
291 	while (mq200_read(sc, MQ200_PMCR) & MQ200_PMC_SEQPROGRESS)
292 	    /* busy wait */;
293 
294 	/*
295 	 * setup GC2	(FP contoller)
296 	 */
297 	if (sc->sc_flags & MQ200_SC_GC2_ENABLE) {
298 		//mq200_write(sc, MQ200_GCCR(MQ200_GC2),
299 		mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC2)],
300 		    MQ200_GCC_ENABLE |
301 		    (clock->gc[MQ200_GC2] << MQ200_GCC_RCLK_SHIFT) |
302 		    MQ200_GCC_MCLK_FD_1 | (1 << MQ200_GCC_MCLK_SD_SHIFT));
303 		DPRINTF("GC2: %s\n",
304 		    mq200_clknames[clock->gc[MQ200_GC2]]);
305 	}
306 
307 	while (mq200_read(sc, MQ200_PMCR) & MQ200_PMC_SEQPROGRESS)
308 	    /* busy wait */;
309 
310 	/*
311 	 * disable unused PLLs
312 	 */
313 	if (clock->pll1 == 0) {
314 		DPRINTF("PLL1 disable\n");
315 		mq200_off(sc, &sc->sc_regctxs[MQ200_I_DCMISC],
316 		    MQ200_DCMISC_PLL1_ENABLE);
317 	}
318 	if (clock->pll2 == 0) {
319 		DPRINTF("PLL2 disable\n");
320 		mq200_off(sc, &sc->sc_regctxs[MQ200_I_PMC],
321 		    MQ200_PMC_PLL2_ENABLE);
322 	}
323 	if (clock->pll3 == 0) {
324 		DPRINTF("PLL3 disable\n");
325 		mq200_off(sc,  &sc->sc_regctxs[MQ200_I_PMC],
326 		    MQ200_PMC_PLL3_ENABLE);
327 	}
328 }
329 
330 void
331 mq200_win_enable(struct mq200_softc *sc, int gc,
332     u_int32_t depth, u_int32_t start,
333     int width, int height, int stride)
334 {
335 
336 	DPRINTF("enable window on GC%d: %dx%d(%dx%d)\n",
337 	    gc + 1, width, height,  sc->sc_width[gc], sc->sc_height[gc]);
338 
339 	if (sc->sc_width[gc] < width) {
340 		if (mq200_depth_table[depth])
341 			start += (height - sc->sc_height[gc]) *
342 			    mq200_depth_table[depth] / 8;
343 		width = sc->sc_width[gc];
344 	}
345 
346 	if (sc->sc_height[gc] < height) {
347 		start += (height - sc->sc_height[gc]) * stride;
348 		height = sc->sc_height[gc];
349 	}
350 
351 	/* GC08R	Window Horizontal Control	*/
352 	mq200_write(sc, MQ200_GCWHCR(gc),
353 	    (((u_int32_t)width - 1) << MQ200_GCWHC_WIDTH_SHIFT) |
354 	    ((sc->sc_width[gc] - width)/2));
355 
356 	/* GC09R	Window Vertical Control		*/
357 	mq200_write(sc, MQ200_GCWVCR(gc),
358 	    (((u_int32_t)height - 1) << MQ200_GCWVC_HEIGHT_SHIFT) |
359 	    ((sc->sc_height[gc] - height)/2));
360 
361 	/* GC00R	GC Control	*/
362 	mq200_mod(sc, &sc->sc_regctxs[MQ200_I_GCC(gc)],
363 	    (MQ200_GCC_WINEN | MQ200_GCC_DEPTH_MASK),
364 	    (MQ200_GCC_WINEN | (depth << MQ200_GCC_DEPTH_SHIFT)));
365 }
366 
367 void
368 mq200_win_disable(struct mq200_softc *sc, int gc)
369 {
370 	/* GC00R	GC Control	*/
371 	mq200_off(sc, &sc->sc_regctxs[MQ200_I_GCC(gc)], MQ200_GCC_WINEN);
372 }
373