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