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