Deleted Added
full compact
1/*-
2 * Copyright (c) 2000 Alcove - Nicolas Souchu <nsouch@freebsd.org>
3 * All rights reserved.
4 *
5 * Code based on Peter Horton <pdh@colonel-panic.com> patch.
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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/dev/fb/s3_pci.c 201223 2009-12-29 21:51:28Z rnoland $");
30__FBSDID("$FreeBSD: head/sys/dev/fb/s3_pci.c 234362 2012-04-16 23:29:12Z jkim $");
31
32/* Enable LFB on S3 cards that has only VESA 1.2 BIOS */
33
34#include <sys/param.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <machine/bus.h>
38
39#include <vm/vm.h>
40#include <vm/vm_extern.h>
41#include <vm/vm_kern.h>
42#include <vm/pmap.h>
43
44#include <sys/uio.h>
45#include <sys/module.h>
46#include <sys/bus.h>
47#include <sys/rman.h>
48#include <machine/resource.h>
49
50#include <sys/malloc.h>
51#include <sys/fbio.h>
52
53#include <dev/pci/pcireg.h>
54#include <dev/pci/pcivar.h>
55
56#include <machine/md_var.h>
57#include <machine/pc/bios.h>
58#include <dev/fb/vesa.h>
59
60#include <dev/fb/fbreg.h>
61#include <dev/fb/vgareg.h>
62
63#define S3PCI_DEBUG 1
64
65#define PCI_S3_VENDOR_ID 0x5333
66
67#define S3_CONFIG_IO 0x3c0 /* VGA standard config io ports */
68#define S3_CONFIG_IO_SIZE 0x20
69
70#define S3_ENHANCED_IO 0x4ae8 /* Extended config register */
71#define S3_ENHANCED_IO_SIZE 1
72
73#define S3_CRTC_ADDR 0x14
74#define S3_CRTC_VALUE 0x15
75
76#define PCI_BASE_MEMORY 0x10
77
78#define outb_p(value, offset) bus_space_write_1(sc->st, sc->sh, offset, value)
79#define inb_p(offset) (bus_space_read_1(sc->st, sc->sh, offset))
80#define outb_enh(value, offset) bus_space_write_1(sc->enh_st, sc->enh_sh, \
81 offset, value)
82#define inb_enh(offset) (bus_space_read_1(sc->enh_st, sc->enh_sh, offset))
83
84struct s3pci_softc {
85 bus_space_tag_t st;
86 bus_space_handle_t sh;
87 bus_space_tag_t enh_st;
88 bus_space_handle_t enh_sh;
89 struct resource *port_res;
90 struct resource *enh_res;
91 struct resource *mem_res;
92 u_long mem_base;
93 u_long mem_size;
94};
95
96static int s3lfb_error(void);
97static vi_probe_t s3lfb_probe;
98static vi_init_t s3lfb_init;
99static vi_get_info_t s3lfb_get_info;
100static vi_query_mode_t s3lfb_query_mode;
101static vi_set_mode_t s3lfb_set_mode;
102static vi_save_font_t s3lfb_save_font;
103static vi_load_font_t s3lfb_load_font;
104static vi_show_font_t s3lfb_show_font;
105static vi_save_palette_t s3lfb_save_palette;
106static vi_load_palette_t s3lfb_load_palette;
107static vi_set_border_t s3lfb_set_border;
108static vi_save_state_t s3lfb_save_state;
109static vi_load_state_t s3lfb_load_state;
110static vi_set_win_org_t s3lfb_set_origin;
111static vi_read_hw_cursor_t s3lfb_read_hw_cursor;
112static vi_set_hw_cursor_t s3lfb_set_hw_cursor;
113static vi_set_hw_cursor_shape_t s3lfb_set_hw_cursor_shape;
114static vi_blank_display_t s3lfb_blank_display;
115static vi_mmap_t s3lfb_mmap;
116static vi_ioctl_t s3lfb_ioctl;
117static vi_clear_t s3lfb_clear;
118static vi_fill_rect_t s3lfb_fill_rect;
119static vi_bitblt_t s3lfb_bitblt;
120static vi_diag_t s3lfb_diag;
121
122static video_switch_t s3lfbvidsw = {
123 s3lfb_probe,
124 s3lfb_init,
125 s3lfb_get_info,
126 s3lfb_query_mode,
127 s3lfb_set_mode,
128 s3lfb_save_font,
129 s3lfb_load_font,
130 s3lfb_show_font,
131 s3lfb_save_palette,
132 s3lfb_load_palette,
133 s3lfb_set_border,
134 s3lfb_save_state,
135 s3lfb_load_state,
136 s3lfb_set_origin,
137 s3lfb_read_hw_cursor,
138 s3lfb_set_hw_cursor,
139 s3lfb_set_hw_cursor_shape,
140 s3lfb_blank_display,
141 s3lfb_mmap,
142 s3lfb_ioctl,
143 s3lfb_clear,
144 s3lfb_fill_rect,
145 s3lfb_bitblt,
146 s3lfb_error,
147 s3lfb_error,
148 s3lfb_diag,
149};
150
151static video_switch_t *prevvidsw;
152static device_t s3pci_dev = NULL;
153
154static int
155s3lfb_probe(int unit, video_adapter_t **adpp, void *arg, int flags)
156{
157 return (*prevvidsw->probe)(unit, adpp, arg, flags);
158}
159
160static int
161s3lfb_init(int unit, video_adapter_t *adp, int flags)
162{
163 return (*prevvidsw->init)(unit, adp, flags);
164}
165
166static int
167s3lfb_get_info(video_adapter_t *adp, int mode, video_info_t *info)
168{
169#if 0
170 device_t dev = s3pci_dev; /* XXX */
171 struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
172#endif
173 int error;
174
175 if ((error = (*prevvidsw->get_info)(adp, mode, info)))
176 return error;
177
178#if 0
179 /* Don't use linear addressing with text modes
180 */
181 if ((mode > M_VESA_BASE) &&
182 (info->vi_flags & V_INFO_GRAPHICS) &&
183 !(info->vi_flags & V_INFO_LINEAR)) {
184
185 info->vi_flags |= V_INFO_LINEAR;
186 info->vi_buffer = sc->mem_base;
187
188 } else {
189 info->vi_buffer = 0;
190 }
191#endif
192
193 return 0;
194}
195
196static int
197s3lfb_query_mode(video_adapter_t *adp, video_info_t *info)
198{
199 return (*prevvidsw->query_mode)(adp, info);
200}
201
202static vm_offset_t
203s3lfb_map_buffer(u_int paddr, size_t size)
204{
205 vm_offset_t vaddr;
206 u_int off;
207
208 off = paddr - trunc_page(paddr);
209 vaddr = (vm_offset_t)pmap_mapdev(paddr - off, size + off);
210
211 return (vaddr + off);
212}
213
214static int
215s3lfb_set_mode(video_adapter_t *adp, int mode)
216{
217 device_t dev = s3pci_dev; /* XXX */
218 struct s3pci_softc *sc = (struct s3pci_softc *)device_get_softc(dev);
219#if 0
220 unsigned char tmp;
221#endif
222 int error;
223
224 /* First, set the mode as if it was a classic VESA card
225 */
226 if ((error = (*prevvidsw->set_mode)(adp, mode)))
227 return error;
228
229 /* If not in a linear mode (according to s3lfb_get_info() called
230 * by vesa_set_mode in the (*vidsw[adp->va_index]->get_info)...
231 * sequence, return with no error
232 */
233#if 0
234 if (!(adp->va_info.vi_flags & V_INFO_LINEAR))
235 return 0;
236#endif
237
238 if ((mode <= M_VESA_BASE) ||
239 !(adp->va_info.vi_flags & V_INFO_GRAPHICS) ||
240 (adp->va_info.vi_flags & V_INFO_LINEAR))
241 return 0;
242
243 /* Ok, now apply the configuration to the card */
244
245 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x48, S3_CRTC_VALUE);
246 outb_p(0x39, S3_CRTC_ADDR); outb_p(0xa5, S3_CRTC_VALUE);
247
248 /* check that CR47 is read/write */
249
250#if 0
251 outb_p(0x47, S3_CRTC_ADDR); outb_p(0xff, S3_CRTC_VALUE);
252 tmp = inb_p(S3_CRTC_VALUE);
253 outb_p(0x00, S3_CRTC_VALUE);
254 if ((tmp != 0xff) || (inb_p(S3_CRTC_VALUE)))
255 {
256 /* lock S3 registers */
257
258 outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
259 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
260
261 return ENXIO;
262 }
263#endif
264
265 /* enable enhanced register access */
266
267 outb_p(0x40, S3_CRTC_ADDR);
268 outb_p(inb_p(S3_CRTC_VALUE) | 1, S3_CRTC_VALUE);
269
270 /* enable enhanced functions */
271
272 outb_enh(inb_enh(0) | 1, 0x0);
273
274 /* enable enhanced mode memory mapping */
275
276 outb_p(0x31, S3_CRTC_ADDR);
277 outb_p(inb_p(S3_CRTC_VALUE) | 8, S3_CRTC_VALUE);
278
279 /* enable linear frame buffer and set address window to max */
280
281 outb_p(0x58, S3_CRTC_ADDR);
282 outb_p(inb_p(S3_CRTC_VALUE) | 0x13, S3_CRTC_VALUE);
283
284 /* disabled enhanced register access */
285
286 outb_p(0x40, S3_CRTC_ADDR);
287 outb_p(inb_p(S3_CRTC_VALUE) & ~1, S3_CRTC_VALUE);
288
289 /* lock S3 registers */
290
291 outb_p(0x39, S3_CRTC_ADDR); outb_p(0x5a, S3_CRTC_VALUE);
292 outb_p(0x38, S3_CRTC_ADDR); outb_p(0x00, S3_CRTC_VALUE);
293
294 adp->va_info.vi_flags |= V_INFO_LINEAR;
295 adp->va_info.vi_buffer = sc->mem_base;
296 adp->va_buffer = s3lfb_map_buffer(adp->va_info.vi_buffer,
297 adp->va_info.vi_buffer_size);
298 adp->va_buffer_size = adp->va_info.vi_buffer_size;
299 adp->va_window = adp->va_buffer;
300 adp->va_window_size = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
301 adp->va_window_gran = adp->va_info.vi_buffer_size/adp->va_info.vi_planes;
302
303 return 0;
304}
305
306static int
307s3lfb_save_font(video_adapter_t *adp, int page, int fontsize, int fontwidth,
308 u_char *data, int ch, int count)
309{
310 return (*prevvidsw->save_font)(adp, page, fontsize, fontwidth, data,
311 ch, count);
312}
313
314static int
315s3lfb_load_font(video_adapter_t *adp, int page, int fontsize, int fontwidth,
316 u_char *data, int ch, int count)
317{
318 return (*prevvidsw->load_font)(adp, page, fontsize, fontwidth, data,
319 ch, count);
320}
321
322static int
323s3lfb_show_font(video_adapter_t *adp, int page)
324{
325 return (*prevvidsw->show_font)(adp, page);
326}
327
328static int
329s3lfb_save_palette(video_adapter_t *adp, u_char *palette)
330{
331 return (*prevvidsw->save_palette)(adp, palette);
332}
333
334static int
335s3lfb_load_palette(video_adapter_t *adp, u_char *palette)
336{
337 return (*prevvidsw->load_palette)(adp, palette);
338}
339
340static int
341s3lfb_set_border(video_adapter_t *adp, int color)
342{
343 return (*prevvidsw->set_border)(adp, color);
344}
345
346static int
347s3lfb_save_state(video_adapter_t *adp, void *p, size_t size)
348{
349 return (*prevvidsw->save_state)(adp, p, size);
350}
351
352static int
353s3lfb_load_state(video_adapter_t *adp, void *p)
354{
355 return (*prevvidsw->load_state)(adp, p);
356}
357
358static int
359s3lfb_set_origin(video_adapter_t *adp, off_t offset)
360{
361 return (*prevvidsw->set_win_org)(adp, offset);
362}
363
364static int
365s3lfb_read_hw_cursor(video_adapter_t *adp, int *col, int *row)
366{
367 return (*prevvidsw->read_hw_cursor)(adp, col, row);
368}
369
370static int
371s3lfb_set_hw_cursor(video_adapter_t *adp, int col, int row)
372{
373 return (*prevvidsw->set_hw_cursor)(adp, col, row);
374}
375
376static int
377s3lfb_set_hw_cursor_shape(video_adapter_t *adp, int base, int height,
378 int celsize, int blink)
379{
380 return (*prevvidsw->set_hw_cursor_shape)(adp, base, height,
381 celsize, blink);
382}
383
384static int
385s3lfb_blank_display(video_adapter_t *adp, int mode)
386{
387 return (*prevvidsw->blank_display)(adp, mode);
388}
389
390static int
391s3lfb_mmap(video_adapter_t *adp, vm_ooffset_t offset, vm_paddr_t *paddr,
392 int prot, vm_memattr_t *memattr)
393{
394 return (*prevvidsw->mmap)(adp, offset, paddr, prot, memattr);
395}
396
397static int
398s3lfb_clear(video_adapter_t *adp)
399{
400 return (*prevvidsw->clear)(adp);
401}
402
403static int
404s3lfb_fill_rect(video_adapter_t *adp, int val, int x, int y, int cx, int cy)
405{
406 return (*prevvidsw->fill_rect)(adp, val, x, y, cx, cy);
407}
408
409static int
410s3lfb_bitblt(video_adapter_t *adp,...)
411{
412 return (*prevvidsw->bitblt)(adp); /* XXX */
413}
414
415static int
416s3lfb_ioctl(video_adapter_t *adp, u_long cmd, caddr_t arg)
417{
418 return (*prevvidsw->ioctl)(adp, cmd, arg);
419}
420
421static int
422s3lfb_diag(video_adapter_t *adp, int level)
423{
424 return (*prevvidsw->diag)(adp, level);
425}
426
427static int
428s3lfb_error(void)
429{
430 return 1;
431}
432
433/***********************************/
434/* PCI detection/attachement stuff */
435/***********************************/
436
437static int
438s3pci_probe(device_t dev)
439{
440 u_int32_t vendor, class, subclass, device_id;
441
442 device_id = pci_get_devid(dev);
443 vendor = device_id & 0xffff;
444 class = pci_get_class(dev);
445 subclass = pci_get_subclass(dev);
446
447 if ((class != PCIC_DISPLAY) || (subclass != PCIS_DISPLAY_VGA) ||
448 (vendor != PCI_S3_VENDOR_ID))
449 return ENXIO;
450
451 device_set_desc(dev, "S3 graphic card");
452
453 bus_set_resource(dev, SYS_RES_IOPORT, 0,
454 S3_CONFIG_IO, S3_CONFIG_IO_SIZE);
455 bus_set_resource(dev, SYS_RES_IOPORT, 1,
456 S3_ENHANCED_IO, S3_ENHANCED_IO_SIZE);
457
458 return BUS_PROBE_DEFAULT;
459
460};
461
462static int
463s3pci_attach(device_t dev)
464{
465 struct s3pci_softc* sc = (struct s3pci_softc*)device_get_softc(dev);
466 video_adapter_t *adp;
467
468#if 0
469 unsigned char tmp;
470#endif
471 int rid, i;
472
473 if (s3pci_dev) {
474 printf("%s: driver already attached!\n", __func__);
475 goto error;
476 }
477
478 /* Allocate resources
479 */
480 rid = 0;
481 if (!(sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
482 0ul, ~0ul, 0, RF_ACTIVE | RF_SHAREABLE))) {
483 printf("%s: port resource allocation failed!\n", __func__);
484 goto error;
485 }
486 sc->st = rman_get_bustag(sc->port_res);
487 sc->sh = rman_get_bushandle(sc->port_res);
488
489 rid = 1;
490 if (!(sc->enh_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid,
491 0ul, ~0ul, 0, RF_ACTIVE | RF_SHAREABLE))) {
492 printf("%s: enhanced port resource allocation failed!\n",
493 __func__);
494 goto error;
495 }
496 sc->enh_st = rman_get_bustag(sc->enh_res);
497 sc->enh_sh = rman_get_bushandle(sc->enh_res);
498
499 rid = PCI_BASE_MEMORY;
500 if (!(sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
501 RF_ACTIVE))) {
502
503 printf("%s: mem resource allocation failed!\n", __func__);
504 goto error;
505 }
506
507 /* The memory base address will be our LFB base address
508 */
509 /* sc->mem_base = (u_long)rman_get_virtual(sc->mem_res); */
510 sc->mem_base = bus_get_resource_start(dev, SYS_RES_MEMORY, rid);
511 sc->mem_size = bus_get_resource_count(dev, SYS_RES_MEMORY, rid);
512
513 /* Attach the driver to the VGA/VESA framework
514 */
515 for (i = 0; (adp = vid_get_adapter(i)) != NULL; ++i) {
516 if ((adp->va_type == KD_VGA))
516 if (adp->va_type == KD_VGA)
517 break;
518 }
519
520 /* If the VESA module hasn't been loaded, or VGA doesn't
521 * exist, abort
522 */
523 if ((adp == NULL) || !(adp->va_flags & V_ADP_VESA)) {
524 printf("%s: VGA adapter not found or VESA module not loaded!\n",
525 __func__);
526 goto error;
527 }
528
529 /* Replace the VESA video switch by owers
530 */
531 prevvidsw = vidsw[adp->va_index];
532 vidsw[adp->va_index] = &s3lfbvidsw;
533
534 /* Remember who we are on the bus */
535 s3pci_dev = (void *)dev; /* XXX */
536
537 return 0;
538
539error:
540 if (sc->mem_res)
541 bus_release_resource(dev, SYS_RES_MEMORY, PCI_BASE_MEMORY, sc->mem_res);
542
543 if (sc->enh_res)
544 bus_release_resource(dev, SYS_RES_IOPORT, 1, sc->enh_res);
545
546 if (sc->port_res)
547 bus_release_resource(dev, SYS_RES_IOPORT, 0, sc->port_res);
548
549 return ENXIO;
550};
551
552static device_method_t s3pci_methods[] = {
553
554 DEVMETHOD(device_probe, s3pci_probe),
555 DEVMETHOD(device_attach, s3pci_attach),
556 {0,0}
557};
558
559static driver_t s3pci_driver = {
560 "s3pci",
561 s3pci_methods,
562 sizeof(struct s3pci_softc),
563};
564
565static devclass_t s3pci_devclass;
566
567DRIVER_MODULE(s3pci, pci, s3pci_driver, s3pci_devclass, 0, 0);