1 /* $NetBSD: ibm561.c,v 1.8 2008/04/28 20:23:50 martin Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Roland C. Dowdeswell of Ponte, Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: ibm561.c,v 1.8 2008/04/28 20:23:50 martin Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
42 #include <uvm/uvm_extern.h>
44 #include <dev/pci/pcivar.h>
45 #include <dev/ic/ibm561reg.h>
46 #include <dev/ic/ibm561var.h>
47 #include <dev/ic/ramdac.h>
49 #include <dev/wscons/wsconsio.h>
52 * Functions exported via the RAMDAC configuration table.
54 void ibm561_init(struct ramdac_cookie
*);
55 int ibm561_set_cmap(struct ramdac_cookie
*, struct wsdisplay_cmap
*);
56 int ibm561_get_cmap(struct ramdac_cookie
*, struct wsdisplay_cmap
*);
57 int ibm561_set_cursor(struct ramdac_cookie
*, struct wsdisplay_cursor
*);
58 int ibm561_get_cursor(struct ramdac_cookie
*, struct wsdisplay_cursor
*);
59 int ibm561_set_curpos(struct ramdac_cookie
*, struct wsdisplay_curpos
*);
60 int ibm561_get_curpos(struct ramdac_cookie
*, struct wsdisplay_curpos
*);
61 int ibm561_get_curmax(struct ramdac_cookie
*, struct wsdisplay_curpos
*);
62 int ibm561_set_dotclock(struct ramdac_cookie
*, unsigned);
65 struct ramdac_funcs ibm561_funcsstruct
= {
76 NULL
, /* check_curcmap; not needed */
77 NULL
, /* set_curcmap; not needed */
78 NULL
, /* get_curcmap; not needed */
88 int (*ramdac_sched_update
)(void *, void (*)(void *));
89 void (*ramdac_wr
)(void *, u_int
, u_int8_t
);
90 u_int8_t (*ramdac_rd
)(void *, u_int
);
92 #define CHANGED_CURCMAP 0x0001 /* cursor cmap */
93 #define CHANGED_CMAP 0x0002 /* color map */
94 #define CHANGED_WTYPE 0x0004 /* window types */
95 #define CHANGED_DOTCLOCK 0x0008 /* dot clock */
96 #define CHANGED_ALL 0x000f /* or of all above */
99 /* dotclock parameters */
102 u_int8_t div_dotclock
;
104 /* colormaps et al. */
105 u_int8_t curcmap_r
[2];
106 u_int8_t curcmap_g
[2];
107 u_int8_t curcmap_b
[2];
109 u_int8_t cmap_r
[IBM561_NCMAP_ENTRIES
];
110 u_int8_t cmap_g
[IBM561_NCMAP_ENTRIES
];
111 u_int8_t cmap_b
[IBM561_NCMAP_ENTRIES
];
113 u_int16_t gamma_r
[IBM561_NGAMMA_ENTRIES
];
114 u_int16_t gamma_g
[IBM561_NGAMMA_ENTRIES
];
115 u_int16_t gamma_b
[IBM561_NGAMMA_ENTRIES
];
117 u_int16_t wtype
[IBM561_NWTYPES
];
123 void ibm561_update(void *);
124 static void ibm561_load_cmap(struct ibm561data
*);
125 static void ibm561_load_dotclock(struct ibm561data
*);
126 static void ibm561_regbegin(struct ibm561data
*, u_int16_t
);
127 static void ibm561_regcont(struct ibm561data
*, u_int16_t
, u_int8_t
);
128 static void ibm561_regcont10bit(struct ibm561data
*, u_int16_t
, u_int16_t
);
129 static void ibm561_regwr(struct ibm561data
*, u_int16_t
, u_int8_t
);
131 struct ramdac_funcs
*
134 return &ibm561_funcsstruct
;
137 struct ramdac_cookie
*
138 ibm561_register(v
, sched_update
, wr
, rd
)
140 int (*sched_update
)(void *, void (*)(void *));
141 void (*wr
)(void *, u_int
, u_int8_t
);
142 u_int8_t (*rd
)(void *, u_int
);
144 struct ibm561data
*data
;
146 data
= malloc(sizeof *data
, M_DEVBUF
, M_WAITOK
|M_ZERO
);
148 data
->ramdac_sched_update
= sched_update
;
149 data
->ramdac_wr
= wr
;
150 data
->ramdac_rd
= rd
;
151 return (struct ramdac_cookie
*)data
;
155 * This function exists solely to provide a means to init
156 * the RAMDAC without first registering. It is useful for
157 * initializing the console early on.
160 struct ibm561data
*saved_console_data
;
163 ibm561_cninit(v
, sched_update
, wr
, rd
, dotclock
)
165 int (*sched_update
)(void *, void (*)(void *));
166 void (*wr
)(void *, u_int
, u_int8_t
);
167 u_int8_t (*rd
)(void *, u_int
);
170 struct ibm561data tmp
, *data
= &tmp
;
171 memset(data
, 0x0, sizeof *data
);
173 data
->ramdac_sched_update
= sched_update
;
174 data
->ramdac_wr
= wr
;
175 data
->ramdac_rd
= rd
;
176 ibm561_set_dotclock((struct ramdac_cookie
*)data
, dotclock
);
177 saved_console_data
= data
;
178 ibm561_init((struct ramdac_cookie
*)data
);
179 saved_console_data
= NULL
;
183 ibm561_init(struct ramdac_cookie
*rc
)
185 struct ibm561data
*data
= (struct ibm561data
*)rc
;
188 /* XXX this is _essential_ */
190 ibm561_load_dotclock(data
);
192 /* XXXrcd: bunch of magic of which I have no current clue */
193 ibm561_regwr(data
, IBM561_CONFIG_REG1
, 0x2a);
194 ibm561_regwr(data
, IBM561_CONFIG_REG3
, 0x41);
195 ibm561_regwr(data
, IBM561_CONFIG_REG4
, 0x20);
197 /* initialize the card a bit */
198 ibm561_regwr(data
, IBM561_SYNC_CNTL
, 0x1);
199 ibm561_regwr(data
, IBM561_CONFIG_REG2
, 0x19);
201 ibm561_regwr(data
, IBM561_CONFIG_REG1
, 0x2a);
202 ibm561_regwr(data
, IBM561_CONFIG_REG4
, 0x20);
204 ibm561_regbegin(data
, IBM561_WAT_SEG_REG
);
205 ibm561_regcont(data
, IBM561_CMD
, 0x00);
206 ibm561_regcont(data
, IBM561_CMD
, 0x00);
207 ibm561_regcont(data
, IBM561_CMD
, 0x00);
208 ibm561_regcont(data
, IBM561_CMD
, 0x00);
209 ibm561_regbegin(data
, IBM561_CHROMAKEY0
);
210 ibm561_regcont(data
, IBM561_CMD
, 0x00);
211 ibm561_regcont(data
, IBM561_CMD
, 0x00);
212 ibm561_regcont(data
, IBM561_CMD
, 0x00);
213 ibm561_regcont(data
, IBM561_CMD
, 0x00);
215 ibm561_regwr(data
, IBM561_CURS_CNTL_REG
, 0x00); /* XXX off? */
217 /* cursor `hot spot' registers */
218 ibm561_regbegin(data
, IBM561_HOTSPOT_REG
);
219 ibm561_regcont(data
, IBM561_CMD
, 0x00);
220 ibm561_regcont(data
, IBM561_CMD
, 0x00);
221 ibm561_regcont(data
, IBM561_CMD
, 0xff);
222 ibm561_regcont(data
, IBM561_CMD
, 0x00);
223 ibm561_regcont(data
, IBM561_CMD
, 0xff);
224 ibm561_regcont(data
, IBM561_CMD
, 0x00);
226 /* VRAM Mask Registers (diagnostics) */
227 ibm561_regbegin(data
, IBM561_VRAM_MASK_REG
);
228 ibm561_regcont(data
, IBM561_CMD
, 0xff);
229 ibm561_regcont(data
, IBM561_CMD
, 0xff);
230 ibm561_regcont(data
, IBM561_CMD
, 0xff);
231 ibm561_regcont(data
, IBM561_CMD
, 0xff);
232 ibm561_regcont(data
, IBM561_CMD
, 0xff);
233 ibm561_regcont(data
, IBM561_CMD
, 0xff);
234 ibm561_regcont(data
, IBM561_CMD
, 0xff);
236 /* let's set up some decent default colour maps and gammas */
237 for (i
=0; i
< IBM561_NCMAP_ENTRIES
; i
++)
238 data
->cmap_r
[i
] = data
->cmap_g
[i
] = data
->cmap_b
[i
] = 0xff;
239 data
->cmap_r
[0] = data
->cmap_g
[0] = data
->cmap_b
[0] = 0x00;
240 data
->cmap_r
[256] = data
->cmap_g
[256] = data
->cmap_b
[256] = 0x00;
241 data
->cmap_r
[512] = data
->cmap_g
[512] = data
->cmap_b
[512] = 0x00;
242 data
->cmap_r
[768] = data
->cmap_g
[768] = data
->cmap_b
[768] = 0x00;
244 data
->gamma_r
[0] = data
->gamma_g
[0] = data
->gamma_b
[0] = 0x00;
245 for (i
=0; i
< IBM561_NGAMMA_ENTRIES
; i
++)
246 data
->gamma_r
[i
] = data
->gamma_g
[i
] = data
->gamma_b
[i
] = 0xff;
248 for (i
=0; i
< IBM561_NWTYPES
; i
++)
249 data
->wtype
[i
] = 0x0036;
250 data
->wtype
[1] = 0x0028;
253 data
->changed
= CHANGED_ALL
;
254 data
->ramdac_sched_update(data
->cookie
, ibm561_update
);
258 ibm561_set_cmap(struct ramdac_cookie
*rc
, struct wsdisplay_cmap
*cmapp
)
260 struct ibm561data
*data
= (struct ibm561data
*)rc
;
262 uint8_t r
[IBM561_NCMAP_ENTRIES
];
263 uint8_t g
[IBM561_NCMAP_ENTRIES
];
264 uint8_t b
[IBM561_NCMAP_ENTRIES
];
267 if (cmapp
->index
>= IBM561_NCMAP_ENTRIES
||
268 cmapp
->count
> IBM561_NCMAP_ENTRIES
- cmapp
->index
)
271 index
= cmapp
->index
;
272 count
= cmapp
->count
;
273 error
= copyin(cmapp
->red
, &r
[index
], count
);
276 error
= copyin(cmapp
->green
, &g
[index
], count
);
279 error
= copyin(cmapp
->blue
, &b
[index
], count
);
283 memcpy(&data
->cmap_r
[index
], &r
[index
], count
);
284 memcpy(&data
->cmap_g
[index
], &g
[index
], count
);
285 memcpy(&data
->cmap_b
[index
], &b
[index
], count
);
286 data
->changed
|= CHANGED_CMAP
;
287 data
->ramdac_sched_update(data
->cookie
, ibm561_update
);
293 ibm561_get_cmap(struct ramdac_cookie
*rc
, struct wsdisplay_cmap
*cmapp
)
295 struct ibm561data
*data
= (struct ibm561data
*)rc
;
299 if (cmapp
->index
>= IBM561_NCMAP_ENTRIES
||
300 cmapp
->count
> IBM561_NCMAP_ENTRIES
- cmapp
->index
)
302 count
= cmapp
->count
;
303 index
= cmapp
->index
;
304 error
= copyout(&data
->cmap_r
[index
], cmapp
->red
, count
);
307 error
= copyout(&data
->cmap_g
[index
], cmapp
->green
, count
);
310 error
= copyout(&data
->cmap_b
[index
], cmapp
->blue
, count
);
316 * I am leaving these functions returning EINVAL, as they are
317 * not strictly necessary for the correct functioning of the
318 * card and in fact are not used on the other TGA variants, except
319 * they are exported via ioctl(2) to userland, which does not in
324 ibm561_set_cursor(struct ramdac_cookie
*rc
, struct wsdisplay_cursor
*cursorp
)
330 ibm561_get_cursor(struct ramdac_cookie
*rc
, struct wsdisplay_cursor
*cursorp
)
336 ibm561_set_curpos(struct ramdac_cookie
*rc
, struct wsdisplay_curpos
*curposp
)
342 ibm561_get_curpos(struct ramdac_cookie
*rc
, struct wsdisplay_curpos
*curposp
)
348 ibm561_get_curmax(struct ramdac_cookie
*rc
, struct wsdisplay_curpos
*curposp
)
354 ibm561_set_dotclock(struct ramdac_cookie
*rc
, unsigned dotclock
)
356 struct ibm561data
*data
= (struct ibm561data
*)rc
;
358 /* XXXrcd: a couple of these are a little hazy, vis a vis
359 * check 175MHz and 202MHz, which are wrong...
362 case 25175000: data
->vco_div
= 0x3e; data
->pll_ref
= 0x09; break;
363 case 31500000: data
->vco_div
= 0x17; data
->pll_ref
= 0x05; break;
364 case 40000000: data
->vco_div
= 0x42; data
->pll_ref
= 0x06; break;
365 case 50000000: data
->vco_div
= 0x45; data
->pll_ref
= 0x05; break;
366 case 65000000: data
->vco_div
= 0xac; data
->pll_ref
= 0x0c; break;
367 case 69000000: data
->vco_div
= 0xa9; data
->pll_ref
= 0x0b; break;
368 case 74000000: data
->vco_div
= 0x9c; data
->pll_ref
= 0x09; break;
369 case 75000000: data
->vco_div
= 0x93; data
->pll_ref
= 0x08; break;
370 case 103994000: data
->vco_div
= 0x96; data
->pll_ref
= 0x06; break;
371 case 108180000: data
->vco_div
= 0xb8; data
->pll_ref
= 0x08; break;
372 case 110000000: data
->vco_div
= 0xba; data
->pll_ref
= 0x08; break;
373 case 119840000: data
->vco_div
= 0x82; data
->pll_ref
= 0x04; break;
374 case 130808000: data
->vco_div
= 0xc8; data
->pll_ref
= 0x08; break;
375 case 135000000: data
->vco_div
= 0xc1; data
->pll_ref
= 0x07; break;
376 case 175000000: data
->vco_div
= 0xe2; data
->pll_ref
= 0x07; break;
377 case 202500000: data
->vco_div
= 0xe2; data
->pll_ref
= 0x07; break;
382 data
->div_dotclock
= 0xb0;
383 data
->changed
|= CHANGED_DOTCLOCK
;
392 ibm561_update(void *vp
)
394 struct ibm561data
*data
= (struct ibm561data
*)vp
;
397 /* XXX see comment above ibm561_cninit() */
399 data
= saved_console_data
;
401 if (data
->changed
& CHANGED_WTYPE
) {
402 ibm561_regbegin(data
, IBM561_FB_WINTYPE
);
403 for (i
=0; i
< IBM561_NWTYPES
; i
++)
404 ibm561_regcont10bit(data
, IBM561_CMD_FB_WAT
, data
->wtype
[i
]);
406 /* XXXrcd: quick hack here for AUX FB table */
407 ibm561_regbegin(data
, IBM561_AUXFB_WINTYPE
);
408 for (i
=0; i
< IBM561_NWTYPES
; i
++)
409 ibm561_regcont(data
, IBM561_CMD
, 0x04);
411 /* XXXrcd: quick hack here for OL WAT table */
412 ibm561_regbegin(data
, IBM561_OL_WINTYPE
);
413 for (i
=0; i
< IBM561_NWTYPES
; i
++)
414 ibm561_regcont10bit(data
, IBM561_CMD_FB_WAT
, 0x0231);
416 /* XXXrcd: quick hack here for AUX OL WAT table */
417 ibm561_regbegin(data
, IBM561_AUXOL_WINTYPE
);
418 for (i
=0; i
< IBM561_NWTYPES
; i
++)
419 ibm561_regcont(data
, IBM561_CMD
, 0x0c);
422 if (data
->changed
& CHANGED_CMAP
)
423 ibm561_load_cmap(data
);
425 /* XXX: I am not sure in what situations it is safe to
426 * change the dotclock---hope this is good.
428 if (data
->changed
& CHANGED_DOTCLOCK
)
429 ibm561_load_dotclock(data
);
433 ibm561_load_cmap(struct ibm561data
*data
)
437 ibm561_regbegin(data
, IBM561_CMAP_TABLE
);
438 for (i
=0; i
< IBM561_NCMAP_ENTRIES
; i
++) {
439 ibm561_regcont(data
, IBM561_CMD_CMAP
, data
->cmap_r
[i
]);
440 ibm561_regcont(data
, IBM561_CMD_CMAP
, data
->cmap_g
[i
]);
441 ibm561_regcont(data
, IBM561_CMD_CMAP
, data
->cmap_b
[i
]);
444 ibm561_regbegin(data
, IBM561_RED_GAMMA_TABLE
);
445 for (i
=0; i
< 256; i
++)
446 ibm561_regcont10bit(data
, IBM561_CMD_GAMMA
, data
->gamma_r
[i
]);
448 ibm561_regbegin(data
, IBM561_GREEN_GAMMA_TABLE
);
449 for (i
=1; i
< 256; i
++)
450 ibm561_regcont10bit(data
, IBM561_CMD_GAMMA
, data
->gamma_g
[i
]);
452 ibm561_regbegin(data
, IBM561_BLUE_GAMMA_TABLE
);
453 for (i
=1; i
< 256; i
++)
454 ibm561_regcont10bit(data
, IBM561_CMD_GAMMA
, data
->gamma_b
[i
]);
459 ibm561_load_dotclock(struct ibm561data
*data
)
462 * we should probably be more pro-active here, but it shouldn't
465 if (!data
->vco_div
|| !data
->pll_ref
|| ! data
->div_dotclock
) {
466 panic("ibm561_load_dotclock: called uninitialized");
469 ibm561_regwr(data
, IBM561_PLL_VCO_DIV
, data
->vco_div
);
470 ibm561_regwr(data
, IBM561_PLL_REF_REG
, data
->pll_ref
);
471 ibm561_regwr(data
, IBM561_DIV_DOTCLCK
, data
->div_dotclock
);
475 ibm561_regcont10bit(struct ibm561data
*data
, u_int16_t reg
, u_int16_t val
)
477 data
->ramdac_wr(data
->cookie
, IBM561_CMD_GAMMA
, (val
>> 2) & 0xff);
478 data
->ramdac_wr(data
->cookie
, IBM561_CMD_GAMMA
, (val
& 0x3) << 6);
482 ibm561_regbegin(struct ibm561data
*data
, u_int16_t reg
)
484 data
->ramdac_wr(data
->cookie
, IBM561_ADDR_LOW
, reg
& 0xff);
485 data
->ramdac_wr(data
->cookie
, IBM561_ADDR_HIGH
, (reg
>> 8) & 0xff);
489 ibm561_regcont(struct ibm561data
*data
, u_int16_t reg
, u_int8_t val
)
491 data
->ramdac_wr(data
->cookie
, reg
, val
);
495 ibm561_regwr(struct ibm561data
*data
, u_int16_t reg
, u_int8_t val
)
497 ibm561_regbegin(data
, reg
);
498 ibm561_regcont(data
, IBM561_CMD
, val
);