1 /* $NetBSD: mq200subr.c,v 1.3.6.3 2004/09/21 13:16:04 skrll Exp $ */
4 * Copyright (c) 2001 TAKEMURA Shin
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: mq200subr.c,v 1.3.6.3 2004/09/21 13:16:04 skrll Exp $");
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
43 #include <sys/types.h>
45 #include <machine/platid.h>
46 #include <machine/platid_mask.h>
48 #include "opt_mq200.h"
51 #include "mq200priv.h"
53 #define ABS(a) ((a) < 0 ? -(a) : (a))
55 int mq200_depth_table
[] = {
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,
70 struct mq200_crt_param mq200_crt_params
[] = {
71 [MQ200_CRT_640x480_60Hz
] =
72 { 640, 480, 25175, /* width, height, dot clock */
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
),
81 [MQ200_CRT_800x600_60Hz
] =
82 { 800, 600, 40000, /* width, height, dot clock */
85 839, 967, /* HS Start, HS End */
86 601, 605, /* VS Start, VS End */
87 MQ200_GC1CRTC_BLANK_PEDESTAL_EN
,
89 [MQ200_CRT_1024x768_60Hz
] =
90 { 1024, 768, 65000, /* width, height, dot clock */
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
),
101 int mq200_crt_nparams
= sizeof(mq200_crt_params
)/sizeof(*mq200_crt_params
);
104 * get PLL setting register value for given frequency
107 mq200_pllparam(int reqout
, u_int32_t
*res
)
114 bn
= 0; bp
= 0; bm
= 0;
115 for (p
= 0; p
<= 4; p
++) {
116 for (n
= 0; n
< (1<<5); n
++) {
117 m
= (reqout
* ((n
+ 1) << p
)) / ref
- 1;
118 out
= ref
* (m
+ 1) / ((n
+ 1) << p
);
122 1000 <= ref
/(n
+ 1) &&
123 170000 <= ref
*(m
+1)/(n
+1) &&
124 ref
*(m
+1)/(n
+1) <= 340000 &&
125 ABS(reqout
- out
) <= e
) {
126 e
= ABS(reqout
- out
);
137 out
= ref
* (bm
+ 1) / ((bn
+ 1) << bp
);
138 printf("PLL: %d.%03d x (%d+1) / (%d+1) / %d = %d.%03d\n",
139 ref
/ 1000, ref
% 1000, bm
, bn
, (1<<bp
),
140 out
/ 1000, out
% 1000);
142 *res
= ((bm
<< MQ200_PLL_M_SHIFT
) |
143 (bn
<< MQ200_PLL_N_SHIFT
) |
144 (bp
<< MQ200_PLL_P_SHIFT
));
150 mq200_set_pll(struct mq200_softc
*sc
, int pll
, int clock
)
152 struct mq200_regctx
*paramreg
, *enreg
;
153 u_int32_t param
, enbit
;
156 case MQ200_CLOCK_PLL1
:
157 paramreg
= &sc
->sc_regctxs
[MQ200_I_PLL(1)];
158 enreg
= &sc
->sc_regctxs
[MQ200_I_DCMISC
];
159 enbit
= MQ200_DCMISC_PLL1_ENABLE
;
161 case MQ200_CLOCK_PLL2
:
162 paramreg
= &sc
->sc_regctxs
[MQ200_I_PLL(2)];
163 enreg
= &sc
->sc_regctxs
[MQ200_I_PMC
];
164 enbit
= MQ200_PMC_PLL2_ENABLE
;
166 case MQ200_CLOCK_PLL3
:
167 paramreg
= &sc
->sc_regctxs
[MQ200_I_PLL(3)];
168 enreg
= &sc
->sc_regctxs
[MQ200_I_PMC
];
169 enbit
= MQ200_PMC_PLL3_ENABLE
;
172 printf("mq200: invalid PLL: %d\n", pll
);
175 if (clock
!= 0 && clock
!= -1) {
176 /* PLL Programming */
177 if (mq200_pllparam(clock
, ¶m
) != 0) {
178 printf("mq200: invalid clock rate: %s %d.%03dMHz\n",
179 mq200_clknames
[pll
], clock
/1000, clock
%1000);
182 mq200_mod(sc
, paramreg
, MQ200_PLL_PARAM_MASK
, param
);
184 mq200_on(sc
, enreg
, enbit
);
187 DPRINTF("%s %d.%03dMHz\n",
188 mq200_clknames
[pll
], clock
/1000, clock
%1000);
192 mq200_setup_regctx(struct mq200_softc
*sc
)
195 static int offsets
[MQ200_I_MAX
] = {
196 [MQ200_I_DCMISC
] = MQ200_DCMISCR
,
197 [MQ200_I_PLL(2)] = MQ200_PLL2R
,
198 [MQ200_I_PLL(3)] = MQ200_PLL3R
,
199 [MQ200_I_PMC
] = MQ200_PMCR
,
200 [MQ200_I_MM01
] = MQ200_MMR(1),
201 [MQ200_I_GCC(MQ200_GC1
)] = MQ200_GCCR(MQ200_GC1
),
202 [MQ200_I_GCC(MQ200_GC2
)] = MQ200_GCCR(MQ200_GC2
),
205 for (i
= 0; i
< sizeof(offsets
)/sizeof(*offsets
); i
++) {
208 if (i
!= MQ200_I_PMC
)
209 panic("%s(%d): register context %d is empty",
210 __FILE__
, __LINE__
, i
);
212 sc
->sc_regctxs
[i
].offset
= offsets
[i
];
217 mq200_setup(struct mq200_softc
*sc
)
219 const struct mq200_clock_setting
*clock
;
220 const struct mq200_crt_param
*crt
;
222 clock
= &sc
->sc_md
->md_clock_settings
[sc
->sc_flags
& MQ200_SC_GC_MASK
];
225 /* disable GC1 and GC2 */
226 //mq200_write(sc, MQ200_GCCR(MQ200_GC1), 0);
227 mq200_write2(sc
, &sc
->sc_regctxs
[MQ200_I_GCC(MQ200_GC1
)], 0);
228 mq200_write(sc
, MQ200_GC1CRTCR
, 0);
229 //mq200_write(sc, MQ200_GCCR(MQ200_GC2), 0);
230 mq200_write2(sc
, &sc
->sc_regctxs
[MQ200_I_GCC(MQ200_GC2
)], 0);
232 while (mq200_read(sc
, MQ200_PMCR
) & MQ200_PMC_SEQPROGRESS
)
238 /* setup eatch PLLs */
239 mq200_set_pll(sc
, MQ200_CLOCK_PLL1
, clock
->pll1
);
240 mq200_set_pll(sc
, MQ200_CLOCK_PLL2
, clock
->pll2
);
241 mq200_set_pll(sc
, MQ200_CLOCK_PLL3
, clock
->pll3
);
242 if (sc
->sc_flags
& MQ200_SC_GC1_ENABLE
)
243 mq200_set_pll(sc
, clock
->gc
[MQ200_GC1
], crt
->clock
);
245 /* setup MEMORY clock */
246 if (clock
->mem
== MQ200_CLOCK_PLL2
)
247 mq200_on(sc
, &sc
->sc_regctxs
[MQ200_I_MM01
],
248 MQ200_MM01_CLK_PLL2
);
250 mq200_off(sc
, &sc
->sc_regctxs
[MQ200_I_MM01
],
251 MQ200_MM01_CLK_PLL2
);
252 DPRINTF("MEM: PLL%d\n", (clock
->mem
== MQ200_CLOCK_PLL2
)?2:1);
255 mq200_mod(sc
, &sc
->sc_regctxs
[MQ200_I_PMC
],
256 MQ200_PMC_GE_CLK_MASK
| MQ200_PMC_GE_ENABLE
,
257 (clock
->ge
<< MQ200_PMC_GE_CLK_SHIFT
) | MQ200_PMC_GE_ENABLE
);
258 DPRINTF(" GE: PLL%d\n", clock
->ge
);
261 * setup GC1 (CRT contoller)
263 if (sc
->sc_flags
& MQ200_SC_GC1_ENABLE
) {
264 /* GC03R Horizontal Display Control */
265 mq200_write(sc
, MQ200_GCHDCR(MQ200_GC1
),
266 (((u_int32_t
)crt
->hdtotal
-2)<<MQ200_GC1HDC_TOTAL_SHIFT
) |
267 ((u_int32_t
)crt
->width
<< MQ200_GCHDC_END_SHIFT
));
269 /* GC03R Vertical Display Control */
270 mq200_write(sc
, MQ200_GCVDCR(MQ200_GC1
),
271 (((u_int32_t
)crt
->vdtotal
-1)<<MQ200_GC1VDC_TOTAL_SHIFT
) |
272 (((u_int32_t
)crt
->height
- 1) << MQ200_GCVDC_END_SHIFT
));
274 /* GC04R Horizontal Sync Control */
275 mq200_write(sc
, MQ200_GCHSCR(MQ200_GC1
),
276 ((u_int32_t
)crt
->hsstart
<< MQ200_GCHSC_START_SHIFT
) |
277 ((u_int32_t
)crt
->hsend
<< MQ200_GCHSC_END_SHIFT
));
279 /* GC05R Vertical Sync Control */
280 mq200_write(sc
, MQ200_GCVSCR(MQ200_GC1
),
281 ((u_int32_t
)crt
->vsstart
<< MQ200_GCVSC_START_SHIFT
) |
282 ((u_int32_t
)crt
->vsend
<< MQ200_GCVSC_END_SHIFT
));
284 /* GC00R GC1 Control */
285 //mq200_write(sc, MQ200_GCCR(MQ200_GC1),
286 mq200_write2(sc
, &sc
->sc_regctxs
[MQ200_I_GCC(MQ200_GC1
)],
288 (clock
->gc
[MQ200_GC1
] << MQ200_GCC_RCLK_SHIFT
) |
289 MQ200_GCC_MCLK_FD_1
|
290 (1 << MQ200_GCC_MCLK_SD_SHIFT
)));
292 /* GC01R CRT Control */
293 mq200_write(sc
, MQ200_GC1CRTCR
,
294 MQ200_GC1CRTC_DACEN
| crt
->opt
);
296 sc
->sc_width
[MQ200_GC1
] = crt
->width
;
297 sc
->sc_height
[MQ200_GC1
] = crt
->height
;
300 mq200_clknames
[clock
->gc
[MQ200_GC1
]]);
303 while (mq200_read(sc
, MQ200_PMCR
) & MQ200_PMC_SEQPROGRESS
)
307 * setup GC2 (FP contoller)
309 if (sc
->sc_flags
& MQ200_SC_GC2_ENABLE
) {
310 //mq200_write(sc, MQ200_GCCR(MQ200_GC2),
311 mq200_write2(sc
, &sc
->sc_regctxs
[MQ200_I_GCC(MQ200_GC2
)],
313 (clock
->gc
[MQ200_GC2
] << MQ200_GCC_RCLK_SHIFT
) |
314 MQ200_GCC_MCLK_FD_1
| (1 << MQ200_GCC_MCLK_SD_SHIFT
));
316 mq200_clknames
[clock
->gc
[MQ200_GC2
]]);
319 while (mq200_read(sc
, MQ200_PMCR
) & MQ200_PMC_SEQPROGRESS
)
323 * disable unused PLLs
325 if (clock
->pll1
== 0) {
326 DPRINTF("PLL1 disable\n");
327 mq200_off(sc
, &sc
->sc_regctxs
[MQ200_I_DCMISC
],
328 MQ200_DCMISC_PLL1_ENABLE
);
330 if (clock
->pll2
== 0) {
331 DPRINTF("PLL2 disable\n");
332 mq200_off(sc
, &sc
->sc_regctxs
[MQ200_I_PMC
],
333 MQ200_PMC_PLL2_ENABLE
);
335 if (clock
->pll3
== 0) {
336 DPRINTF("PLL3 disable\n");
337 mq200_off(sc
, &sc
->sc_regctxs
[MQ200_I_PMC
],
338 MQ200_PMC_PLL3_ENABLE
);
343 mq200_win_enable(struct mq200_softc
*sc
, int gc
,
344 u_int32_t depth
, u_int32_t start
,
345 int width
, int height
, int stride
)
348 DPRINTF("enable window on GC%d: %dx%d(%dx%d)\n",
349 gc
+ 1, width
, height
, sc
->sc_width
[gc
], sc
->sc_height
[gc
]);
351 if (sc
->sc_width
[gc
] < width
) {
352 if (mq200_depth_table
[depth
])
353 start
+= (height
- sc
->sc_height
[gc
]) *
354 mq200_depth_table
[depth
] / 8;
355 width
= sc
->sc_width
[gc
];
358 if (sc
->sc_height
[gc
] < height
) {
359 start
+= (height
- sc
->sc_height
[gc
]) * stride
;
360 height
= sc
->sc_height
[gc
];
363 /* GC08R Window Horizontal Control */
364 mq200_write(sc
, MQ200_GCWHCR(gc
),
365 (((u_int32_t
)width
- 1) << MQ200_GCWHC_WIDTH_SHIFT
) |
366 ((sc
->sc_width
[gc
] - width
)/2));
368 /* GC09R Window Vertical Control */
369 mq200_write(sc
, MQ200_GCWVCR(gc
),
370 (((u_int32_t
)height
- 1) << MQ200_GCWVC_HEIGHT_SHIFT
) |
371 ((sc
->sc_height
[gc
] - height
)/2));
373 /* GC00R GC Control */
374 mq200_mod(sc
, &sc
->sc_regctxs
[MQ200_I_GCC(gc
)],
375 (MQ200_GCC_WINEN
| MQ200_GCC_DEPTH_MASK
),
376 (MQ200_GCC_WINEN
| (depth
<< MQ200_GCC_DEPTH_SHIFT
)));
380 mq200_win_disable(struct mq200_softc
*sc
, int gc
)
382 /* GC00R GC Control */
383 mq200_off(sc
, &sc
->sc_regctxs
[MQ200_I_GCC(gc
)], MQ200_GCC_WINEN
);