Home | History | Annotate | Line # | Download | only in dev
mq200subr.c revision 1.4
      1 /*	$NetBSD: mq200subr.c,v 1.4 2003/07/15 02:29:30 lukem 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/cdefs.h>
     34 __KERNEL_RCSID(0, "$NetBSD: mq200subr.c,v 1.4 2003/07/15 02:29:30 lukem Exp $");
     35 
     36 #include <sys/param.h>
     37 #include <sys/kernel.h>
     38 #include <sys/systm.h>
     39 #include <sys/device.h>
     40 #else
     41 #include <stdio.h>
     42 #endif
     43 #include <sys/types.h>
     44 
     45 #include <machine/platid.h>
     46 #include <machine/platid_mask.h>
     47 
     48 #include "opt_mq200.h"
     49 #include "mq200var.h"
     50 #include "mq200reg.h"
     51 #include "mq200priv.h"
     52 
     53 #define ABS(a)	((a) < 0 ? -(a) : (a))
     54 
     55 int mq200_depth_table[] = {
     56 	[MQ200_GCC_1BPP] =		1,
     57 	[MQ200_GCC_2BPP] =		2,
     58 	[MQ200_GCC_4BPP] =		4,
     59 	[MQ200_GCC_8BPP] =		8,
     60 	[MQ200_GCC_16BPP] =		16,
     61 	[MQ200_GCC_24BPP] =		32,
     62 	[MQ200_GCC_ARGB888] =		32,
     63 	[MQ200_GCC_ABGR888] =		32,
     64 	[MQ200_GCC_16BPP_DIRECT] =	16,
     65 	[MQ200_GCC_24BPP_DIRECT] =	32,
     66 	[MQ200_GCC_ARGB888_DIRECT] =	32,
     67 	[MQ200_GCC_ABGR888_DIRECT] =	32,
     68 };
     69 
     70 struct mq200_crt_param mq200_crt_params[] = {
     71 	[MQ200_CRT_640x480_60Hz] =
     72 	{	640, 480, 25175,	/* width, height, dot clock */
     73 		800,			/* HD Total */
     74 		525,			/* VD Total */
     75 		656, 752,		/* HS Start, HS End */
     76 		490, 492,		/* VS Start, VS End */
     77 		(MQ200_GC1CRTC_HSYNC_ACTVLOW |
     78 		    MQ200_GC1CRTC_VSYNC_ACTVLOW |
     79 		    MQ200_GC1CRTC_BLANK_PEDESTAL_EN),
     80 	},
     81 	[MQ200_CRT_800x600_60Hz] =
     82 	{	800, 600, 40000,	/* width, height, dot clock */
     83 		1054,			/* HD Total */
     84 		628,			/* VD Total */
     85 		839, 967,		/* HS Start, HS End */
     86 		601, 605,		/* VS Start, VS End */
     87 		MQ200_GC1CRTC_BLANK_PEDESTAL_EN,
     88 	},
     89 	[MQ200_CRT_1024x768_60Hz] =
     90 	{	1024, 768, 65000,	/* width, height, dot clock */
     91 		1344,			/* HD Total */
     92 		806,			/* VD Total */
     93 		1048,	1184,		/* HS Start, HS End */
     94 		771,	777,		/* VS Start, VS End */
     95 		(MQ200_GC1CRTC_HSYNC_ACTVLOW |
     96 		    MQ200_GC1CRTC_VSYNC_ACTVLOW |
     97 		    MQ200_GC1CRTC_BLANK_PEDESTAL_EN),
     98 	},
     99 };
    100 
    101 int mq200_crt_nparams = sizeof(mq200_crt_params)/sizeof(*mq200_crt_params);
    102 
    103 /*
    104  * get PLL setting register value for given frequency
    105  */
    106 void
    107 mq200_pllparam(int reqout, u_int32_t *res)
    108 {
    109 	int n, m, p, out;
    110 	int ref = 12288;
    111 	int bn, bm, bp, e;
    112 
    113 	e = ref;
    114 	for (p = 0; p <= 4; p++) {
    115 		for (n = 0; n < (1<<5); n++) {
    116 			m = (reqout * ((n + 1) << p)) / ref - 1;
    117 			out = ref * (m + 1) / ((n + 1) << p);
    118 			if (0xff < m)
    119 				break;
    120 			if (40 <= m &&
    121 			    1000 <= ref/(n + 1) &&
    122 			    170000 <= ref*(m+1)/(n+1) &&
    123 			    ref*(m+1)/(n+1) <= 340000 &&
    124 			    ABS(reqout - out) <= e) {
    125 				e = ABS(reqout - out);
    126 				bn = n;
    127 				bm = m;
    128 				bp = p;
    129 			}
    130 		}
    131 	}
    132 
    133 #if 0
    134 	out = ref * (bm + 1) / ((bn + 1) << bp);
    135 	printf("PLL: %d.%03d x (%d+1) / (%d+1) / %d = %d.%03d\n",
    136 	    ref / 1000, ref % 1000, bm, bn, (1<<bp),
    137 	    out / 1000, out % 1000);
    138 #endif
    139 	*res = ((bm << MQ200_PLL_M_SHIFT) |
    140 		(bn << MQ200_PLL_N_SHIFT) |
    141 		(bp << MQ200_PLL_P_SHIFT));
    142 }
    143 
    144 void
    145 mq200_set_pll(struct mq200_softc *sc, int pll, int clock)
    146 {
    147 	struct mq200_regctx *paramreg, *enreg;
    148 	u_int32_t param, enbit;
    149 
    150 	switch (pll) {
    151 	case MQ200_CLOCK_PLL1:
    152 		paramreg = &sc->sc_regctxs[MQ200_I_PLL(1)];
    153 		enreg = &sc->sc_regctxs[MQ200_I_DCMISC];
    154 		enbit = MQ200_DCMISC_PLL1_ENABLE;
    155 		break;
    156 	case MQ200_CLOCK_PLL2:
    157 		paramreg = &sc->sc_regctxs[MQ200_I_PLL(2)];
    158 		enreg = &sc->sc_regctxs[MQ200_I_PMC];
    159 		enbit = MQ200_PMC_PLL2_ENABLE;
    160 		break;
    161 	case MQ200_CLOCK_PLL3:
    162 		paramreg = &sc->sc_regctxs[MQ200_I_PLL(3)];
    163 		enreg = &sc->sc_regctxs[MQ200_I_PMC];
    164 		enbit = MQ200_PMC_PLL3_ENABLE;
    165 		break;
    166 	default:
    167 		printf("mq200: invalid PLL: %d\n", pll);
    168 		return;
    169 	}
    170 	if (clock != 0 && clock != -1) {
    171 		/* PLL Programming	*/
    172 		mq200_pllparam(clock, &param);
    173 		mq200_mod(sc, paramreg, MQ200_PLL_PARAM_MASK, param);
    174 		/* enable PLL	*/
    175 		mq200_on(sc, enreg, enbit);
    176 	}
    177 
    178 	DPRINTF("%s %d.%03dMHz\n",
    179 	    mq200_clknames[pll], clock/1000, clock%1000);
    180 }
    181 
    182 void
    183 mq200_setup_regctx(struct mq200_softc *sc)
    184 {
    185 	int i;
    186 	static int offsets[MQ200_I_MAX] = {
    187 		[MQ200_I_DCMISC] =		MQ200_DCMISCR,
    188 		[MQ200_I_PLL(2)] =		MQ200_PLL2R,
    189 		[MQ200_I_PLL(3)] =		MQ200_PLL3R,
    190 		[MQ200_I_PMC] =			MQ200_PMCR,
    191 		[MQ200_I_MM01] =		MQ200_MMR(1),
    192 		[MQ200_I_GCC(MQ200_GC1)] =	MQ200_GCCR(MQ200_GC1),
    193 		[MQ200_I_GCC(MQ200_GC2)] =	MQ200_GCCR(MQ200_GC2),
    194 	};
    195 
    196 	for (i = 0; i < sizeof(offsets)/sizeof(*offsets); i++) {
    197 		if (offsets[i] == 0)
    198 #ifdef MQ200_DEBUG
    199 			if (i != MQ200_I_PMC)
    200 				panic("%s(%d): register context %d is empty",
    201 				    __FILE__, __LINE__, i);
    202 #endif
    203 		sc->sc_regctxs[i].offset = offsets[i];
    204 	}
    205 }
    206 
    207 void
    208 mq200_setup(struct mq200_softc *sc)
    209 {
    210 	const struct mq200_clock_setting *clock;
    211 	const struct mq200_crt_param *crt;
    212 
    213 	clock = &sc->sc_md->md_clock_settings[sc->sc_flags & MQ200_SC_GC_MASK];
    214 	crt = sc->sc_crt;
    215 
    216 	/* disable GC1 and GC2	*/
    217 	//mq200_write(sc, MQ200_GCCR(MQ200_GC1), 0);
    218 	mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC1)], 0);
    219 	mq200_write(sc, MQ200_GC1CRTCR, 0);
    220 	//mq200_write(sc, MQ200_GCCR(MQ200_GC2), 0);
    221 	mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC2)], 0);
    222 
    223 	while (mq200_read(sc, MQ200_PMCR) & MQ200_PMC_SEQPROGRESS)
    224 	    /* busy wait */;
    225 
    226 	/*
    227 	 * setup around clock
    228 	 */
    229 	/* setup eatch PLLs	*/
    230 	mq200_set_pll(sc, MQ200_CLOCK_PLL1, clock->pll1);
    231 	mq200_set_pll(sc, MQ200_CLOCK_PLL2, clock->pll2);
    232 	mq200_set_pll(sc, MQ200_CLOCK_PLL3, clock->pll3);
    233 	if (sc->sc_flags & MQ200_SC_GC1_ENABLE)
    234 		mq200_set_pll(sc, clock->gc[MQ200_GC1], crt->clock);
    235 
    236 	/* setup MEMORY clock */
    237 	if (clock->mem == MQ200_CLOCK_PLL2)
    238 		mq200_on(sc, &sc->sc_regctxs[MQ200_I_MM01],
    239 		    MQ200_MM01_CLK_PLL2);
    240 	else
    241 		mq200_off(sc, &sc->sc_regctxs[MQ200_I_MM01],
    242 		    MQ200_MM01_CLK_PLL2);
    243 	DPRINTF("MEM: PLL%d\n", (clock->mem == MQ200_CLOCK_PLL2)?2:1);
    244 
    245 	/* setup GE clock */
    246 	mq200_mod(sc, &sc->sc_regctxs[MQ200_I_PMC],
    247 	    MQ200_PMC_GE_CLK_MASK | MQ200_PMC_GE_ENABLE,
    248 	    (clock->ge << MQ200_PMC_GE_CLK_SHIFT) | MQ200_PMC_GE_ENABLE);
    249 	DPRINTF(" GE: PLL%d\n", clock->ge);
    250 
    251 	/*
    252 	 * setup GC1	(CRT contoller)
    253 	 */
    254 	if (sc->sc_flags & MQ200_SC_GC1_ENABLE) {
    255 		/* GC03R	Horizontal Display Control	*/
    256 		mq200_write(sc, MQ200_GCHDCR(MQ200_GC1),
    257 		    (((u_int32_t)crt->hdtotal-2)<<MQ200_GC1HDC_TOTAL_SHIFT) |
    258 		    ((u_int32_t)crt->width << MQ200_GCHDC_END_SHIFT));
    259 
    260 		/* GC03R	Vertical Display Control	*/
    261 		mq200_write(sc, MQ200_GCVDCR(MQ200_GC1),
    262 		    (((u_int32_t)crt->vdtotal-1)<<MQ200_GC1VDC_TOTAL_SHIFT) |
    263 		    (((u_int32_t)crt->height - 1) << MQ200_GCVDC_END_SHIFT));
    264 
    265 		/* GC04R	Horizontal Sync Control		*/
    266 		mq200_write(sc, MQ200_GCHSCR(MQ200_GC1),
    267 		    ((u_int32_t)crt->hsstart << MQ200_GCHSC_START_SHIFT) |
    268 		    ((u_int32_t)crt->hsend << MQ200_GCHSC_END_SHIFT));
    269 
    270 		/* GC05R	Vertical Sync Control		*/
    271 		mq200_write(sc, MQ200_GCVSCR(MQ200_GC1),
    272 		    ((u_int32_t)crt->vsstart << MQ200_GCVSC_START_SHIFT) |
    273 		    ((u_int32_t)crt->vsend << MQ200_GCVSC_END_SHIFT));
    274 
    275 		/* GC00R	GC1 Control			*/
    276 		//mq200_write(sc, MQ200_GCCR(MQ200_GC1),
    277 		mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC1)],
    278 		    (MQ200_GCC_ENABLE |
    279 			(clock->gc[MQ200_GC1] << MQ200_GCC_RCLK_SHIFT) |
    280 			MQ200_GCC_MCLK_FD_1 |
    281 			(1 << MQ200_GCC_MCLK_SD_SHIFT)));
    282 
    283 		/* GC01R	CRT Control			*/
    284 		mq200_write(sc, MQ200_GC1CRTCR,
    285 		    MQ200_GC1CRTC_DACEN | crt->opt);
    286 
    287 		sc->sc_width[MQ200_GC1] = crt->width;
    288 		sc->sc_height[MQ200_GC1] = crt->height;
    289 
    290 		DPRINTF("GC1: %s\n",
    291 		    mq200_clknames[clock->gc[MQ200_GC1]]);
    292 	}
    293 
    294 	while (mq200_read(sc, MQ200_PMCR) & MQ200_PMC_SEQPROGRESS)
    295 	    /* busy wait */;
    296 
    297 	/*
    298 	 * setup GC2	(FP contoller)
    299 	 */
    300 	if (sc->sc_flags & MQ200_SC_GC2_ENABLE) {
    301 		//mq200_write(sc, MQ200_GCCR(MQ200_GC2),
    302 		mq200_write2(sc, &sc->sc_regctxs[MQ200_I_GCC(MQ200_GC2)],
    303 		    MQ200_GCC_ENABLE |
    304 		    (clock->gc[MQ200_GC2] << MQ200_GCC_RCLK_SHIFT) |
    305 		    MQ200_GCC_MCLK_FD_1 | (1 << MQ200_GCC_MCLK_SD_SHIFT));
    306 		DPRINTF("GC2: %s\n",
    307 		    mq200_clknames[clock->gc[MQ200_GC2]]);
    308 	}
    309 
    310 	while (mq200_read(sc, MQ200_PMCR) & MQ200_PMC_SEQPROGRESS)
    311 	    /* busy wait */;
    312 
    313 	/*
    314 	 * disable unused PLLs
    315 	 */
    316 	if (clock->pll1 == 0) {
    317 		DPRINTF("PLL1 disable\n");
    318 		mq200_off(sc, &sc->sc_regctxs[MQ200_I_DCMISC],
    319 		    MQ200_DCMISC_PLL1_ENABLE);
    320 	}
    321 	if (clock->pll2 == 0) {
    322 		DPRINTF("PLL2 disable\n");
    323 		mq200_off(sc, &sc->sc_regctxs[MQ200_I_PMC],
    324 		    MQ200_PMC_PLL2_ENABLE);
    325 	}
    326 	if (clock->pll3 == 0) {
    327 		DPRINTF("PLL3 disable\n");
    328 		mq200_off(sc,  &sc->sc_regctxs[MQ200_I_PMC],
    329 		    MQ200_PMC_PLL3_ENABLE);
    330 	}
    331 }
    332 
    333 void
    334 mq200_win_enable(struct mq200_softc *sc, int gc,
    335     u_int32_t depth, u_int32_t start,
    336     int width, int height, int stride)
    337 {
    338 
    339 	DPRINTF("enable window on GC%d: %dx%d(%dx%d)\n",
    340 	    gc + 1, width, height,  sc->sc_width[gc], sc->sc_height[gc]);
    341 
    342 	if (sc->sc_width[gc] < width) {
    343 		if (mq200_depth_table[depth])
    344 			start += (height - sc->sc_height[gc]) *
    345 			    mq200_depth_table[depth] / 8;
    346 		width = sc->sc_width[gc];
    347 	}
    348 
    349 	if (sc->sc_height[gc] < height) {
    350 		start += (height - sc->sc_height[gc]) * stride;
    351 		height = sc->sc_height[gc];
    352 	}
    353 
    354 	/* GC08R	Window Horizontal Control	*/
    355 	mq200_write(sc, MQ200_GCWHCR(gc),
    356 	    (((u_int32_t)width - 1) << MQ200_GCWHC_WIDTH_SHIFT) |
    357 	    ((sc->sc_width[gc] - width)/2));
    358 
    359 	/* GC09R	Window Vertical Control		*/
    360 	mq200_write(sc, MQ200_GCWVCR(gc),
    361 	    (((u_int32_t)height - 1) << MQ200_GCWVC_HEIGHT_SHIFT) |
    362 	    ((sc->sc_height[gc] - height)/2));
    363 
    364 	/* GC00R	GC Control	*/
    365 	mq200_mod(sc, &sc->sc_regctxs[MQ200_I_GCC(gc)],
    366 	    (MQ200_GCC_WINEN | MQ200_GCC_DEPTH_MASK),
    367 	    (MQ200_GCC_WINEN | (depth << MQ200_GCC_DEPTH_SHIFT)));
    368 }
    369 
    370 void
    371 mq200_win_disable(struct mq200_softc *sc, int gc)
    372 {
    373 	/* GC00R	GC Control	*/
    374 	mq200_off(sc, &sc->sc_regctxs[MQ200_I_GCC(gc)], MQ200_GCC_WINEN);
    375 }
    376