1 /* $NetBSD: tdvfb.c,v 1.6 2013/07/30 19:21:50 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Radoslaw Kujawa. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 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. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /* 32 * A console driver for 3Dfx Voodoo2 (CVG) and 3Dfx Voodoo Graphics (SST-1). 33 * 34 * 3Dfx Glide 2.x source code, Linux driver by Ghozlane Toumi, and 35 * "Voodoo2 Graphics Engine for 3D Game Acceleration" document were used as 36 * reference. wscons attachment code based mostly on genfb by Michael 37 * Lorenz. 38 * 39 * This driver currently only support boards with ICS GENDAC (which seems to 40 * be most popular, however at least two different DACs were used with CVG). 41 * 42 * TODO (in no particular order): 43 * - Finally fix 16-bit depth handling on big-endian machines. 44 * - Expose card to userspace through /dev/3dfx compatible device file 45 * (for Glide). 46 * - Allow mmap'ing of registers through wscons access op. 47 * - Complete wscons emul ops acceleration support. 48 * - Add support for others DACs (need hardware). 49 */ 50 51 #include <sys/cdefs.h> 52 __KERNEL_RCSID(0, "$NetBSD: tdvfb.c,v 1.6 2013/07/30 19:21:50 macallan Exp $"); 53 54 #include <sys/param.h> 55 #include <sys/systm.h> 56 #include <sys/kernel.h> 57 #include <sys/device.h> 58 #include <sys/endian.h> 59 60 #include <dev/pci/pcivar.h> 61 #include <dev/pci/pcireg.h> 62 #include <dev/pci/pcidevs.h> 63 #include <dev/pci/pciio.h> 64 65 #include <dev/pci/tdvfbreg.h> 66 #include <dev/pci/tdvfbvar.h> 67 68 #include <dev/videomode/videomode.h> 69 #include <dev/pci/wsdisplay_pci.h> 70 71 #include "opt_wsemul.h" 72 #include "opt_tdvfb.h" 73 74 #define MAXLOOP 4096 75 /* #define TDVFB_DEBUG 1 */ 76 77 static int tdvfb_match(device_t, cfdata_t, void *); 78 static void tdvfb_attach(device_t, device_t, void *); 79 80 static uint32_t tdvfb_cvg_read(struct tdvfb_softc *sc, uint32_t reg); 81 static void tdvfb_cvg_write(struct tdvfb_softc *sc, uint32_t reg, 82 uint32_t val); 83 static void tdvfb_cvg_set(struct tdvfb_softc *sc, uint32_t reg, 84 uint32_t bits); 85 static void tdvfb_cvg_unset(struct tdvfb_softc *sc, uint32_t reg, 86 uint32_t bits); 87 static uint8_t tdvfb_cvg_dac_read(struct tdvfb_softc *sc, uint32_t reg); 88 static void tdvfb_cvg_dac_write(struct tdvfb_softc *sc, uint32_t reg, 89 uint32_t val); 90 static void tdvfb_wait(struct tdvfb_softc *sc); 91 92 static bool tdvfb_init(struct tdvfb_softc *sc); 93 static void tdvfb_fbiinit_defaults(struct tdvfb_softc *sc); 94 static size_t tdvfb_mem_size(struct tdvfb_softc *sc); 95 96 static bool tdvfb_videomode_set(struct tdvfb_softc *sc); 97 static void tdvfb_videomode_dac(struct tdvfb_softc *sc); 98 99 static bool tdvfb_gendac_detect(struct tdvfb_softc *sc); 100 static struct tdvfb_dac_timing tdvfb_gendac_calc_pll(int freq); 101 static void tdvfb_gendac_set_cvg_timing(struct tdvfb_softc *sc, 102 struct tdvfb_dac_timing *timing); 103 static void tdvfb_gendac_set_vid_timing(struct tdvfb_softc *sc, 104 struct tdvfb_dac_timing *timing); 105 106 static paddr_t tdvfb_mmap(void *v, void *vs, off_t offset, int prot); 107 static int tdvfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, 108 struct lwp *l); 109 static void tdvfb_init_screen(void *cookie, struct vcons_screen *scr, 110 int existing, long *defattr); 111 static void tdvfb_init_palette(struct tdvfb_softc *sc); 112 /* blitter support */ 113 static void tdvfb_rectfill(struct tdvfb_softc *sc, int x, int y, int wi, 114 int he, uint32_t color); 115 static void tdvfb_bitblt(struct tdvfb_softc *sc, int xs, int ys, int xd, 116 int yd, int wi, int he); 117 /* accelerated raster ops */ 118 static void tdvfb_eraserows(void *cookie, int row, int nrows, 119 long fillattr); 120 static void tdvfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows); 121 122 CFATTACH_DECL_NEW(tdvfb, sizeof(struct tdvfb_softc), 123 tdvfb_match, tdvfb_attach, NULL, NULL); 124 125 struct wsdisplay_accessops tdvfb_accessops = { 126 tdvfb_ioctl, 127 tdvfb_mmap, 128 NULL, /* alloc_screen */ 129 NULL, /* free_screen */ 130 NULL, /* show_screen */ 131 NULL, /* load_font */ 132 NULL, /* pollc */ 133 NULL /* scroll */ 134 }; 135 136 static int 137 tdvfb_match(device_t parent, cfdata_t match, void *aux) 138 { 139 const struct pci_attach_args *pa = (const struct pci_attach_args *)aux; 140 141 if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3DFX) && 142 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DFX_VOODOO2)) 143 return 100; 144 if ((PCI_VENDOR(pa->pa_id) == PCI_VENDOR_3DFX) && 145 (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DFX_VOODOO)) 146 return 100; 147 148 return 0; 149 } 150 151 static void 152 tdvfb_attach(device_t parent, device_t self, void *aux) 153 { 154 struct tdvfb_softc *sc = device_private(self); 155 struct wsemuldisplaydev_attach_args ws_aa; 156 struct rasops_info *ri; 157 const struct pci_attach_args *pa = aux; 158 pcireg_t screg; 159 bool console; 160 long defattr; 161 162 #ifdef TDVFB_CONSOLE 163 console = true; 164 #else 165 console = false; 166 #endif 167 168 sc->sc_pc = pa->pa_pc; 169 sc->sc_pcitag = pa->pa_tag; 170 sc->sc_dev = self; 171 172 if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_3DFX_VOODOO2) 173 sc->sc_voodootype = TDV_VOODOO_2; 174 else 175 sc->sc_voodootype = TDV_VOODOO_1; 176 177 screg = pci_conf_read(sc->sc_pc, sc->sc_pcitag, 178 PCI_COMMAND_STATUS_REG); 179 screg |= PCI_COMMAND_MEM_ENABLE; 180 pci_conf_write(sc->sc_pc, sc->sc_pcitag, PCI_COMMAND_STATUS_REG, 181 screg); 182 183 pci_aprint_devinfo(pa, NULL); 184 185 /* map the BAR */ 186 if (pci_mapreg_map(pa, TDV_MM_BAR, PCI_MAPREG_TYPE_MEM, 187 BUS_SPACE_MAP_LINEAR, &sc->sc_cvgt, &sc->sc_cvgh, 188 &sc->sc_cvg_pa, 0) != 0 ) { 189 aprint_error_dev(sc->sc_dev, "unable to map CVG BAR"); 190 return; 191 } 192 193 /* Map the framebuffer. */ 194 if (bus_space_subregion(sc->sc_cvgt, sc->sc_cvgh, TDV_OFF_FB, 195 TDV_FB_SIZE, &sc->sc_fbh)) { 196 aprint_error_dev(sc->sc_dev, "unable to map the framebuffer"); 197 } 198 199 aprint_normal_dev(sc->sc_dev, "registers at 0x%08x, fb at 0x%08x\n", 200 (uint32_t) sc->sc_cvg_pa, (uint32_t) sc->sc_cvg_pa + TDV_OFF_FB); 201 202 /* Do the low level setup. */ 203 if (!tdvfb_init(sc)) { 204 aprint_error_dev(sc->sc_dev, "could not initialize CVG\n"); 205 return; 206 } 207 208 /* 209 * The card is alive now, let's check how much framebuffer memory 210 * do we have. 211 */ 212 sc->sc_memsize = tdvfb_mem_size(sc); 213 214 aprint_normal_dev(sc->sc_dev, "%d MB framebuffer memory present\n", 215 sc->sc_memsize / 1024 / 1024); 216 217 /* Select video mode, 800x600 32bpp 60Hz by default... */ 218 sc->sc_width = 800; 219 sc->sc_height = 600; 220 #if BYTE_ORDER == BIG_ENDIAN 221 sc->sc_bpp = 32; /* XXX: 16 would allow blitter use. */ 222 #else 223 sc->sc_bpp = 16; 224 #endif 225 sc->sc_linebytes = 1024 * (sc->sc_bpp / 8); 226 sc->sc_videomode = pick_mode_by_ref(sc->sc_width, sc->sc_height, 60); 227 228 aprint_normal_dev(sc->sc_dev, "setting %dx%d %d bpp resolution\n", 229 sc->sc_width, sc->sc_height, sc->sc_bpp); 230 231 tdvfb_videomode_set(sc); 232 233 sc->sc_defaultscreen_descr = (struct wsscreen_descr){ 234 "default", 235 0, 0, 236 NULL, 237 8, 16, 238 WSSCREEN_WSCOLORS | WSSCREEN_HILIT, 239 NULL 240 }; 241 sc->sc_screens[0] = &sc->sc_defaultscreen_descr; 242 sc->sc_screenlist = (struct wsscreen_list){1, sc->sc_screens}; 243 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 244 245 vcons_init(&sc->vd, sc, &sc->sc_defaultscreen_descr, 246 &tdvfb_accessops); 247 sc->vd.init_screen = tdvfb_init_screen; 248 249 ri = &sc->sc_console_screen.scr_ri; 250 251 tdvfb_init_palette(sc); 252 253 if (console) { 254 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 255 &defattr); 256 257 sc->sc_console_screen.scr_flags |= VCONS_SCREEN_IS_STATIC | 258 VCONS_DONT_READ; 259 vcons_redraw_screen(&sc->sc_console_screen); 260 261 sc->sc_defaultscreen_descr.textops = &ri->ri_ops; 262 sc->sc_defaultscreen_descr.capabilities = ri->ri_caps; 263 sc->sc_defaultscreen_descr.nrows = ri->ri_rows; 264 sc->sc_defaultscreen_descr.ncols = ri->ri_cols; 265 266 wsdisplay_cnattach(&sc->sc_defaultscreen_descr, ri, 0, 0, 267 defattr); 268 vcons_replay_msgbuf(&sc->sc_console_screen); 269 } else { 270 if (sc->sc_console_screen.scr_ri.ri_rows == 0) { 271 vcons_init_screen(&sc->vd, &sc->sc_console_screen, 1, 272 &defattr); 273 } else 274 (*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr); 275 } 276 277 ws_aa.console = console; 278 ws_aa.scrdata = &sc->sc_screenlist; 279 ws_aa.accessops = &tdvfb_accessops; 280 ws_aa.accesscookie = &sc->vd; 281 282 config_found(sc->sc_dev, &ws_aa, wsemuldisplaydevprint); 283 } 284 285 static void 286 tdvfb_init_palette(struct tdvfb_softc *sc) 287 { 288 int i, j; 289 290 j = 0; 291 for (i = 0; i < 256; i++) { 292 sc->sc_cmap_red[i] = rasops_cmap[j]; 293 sc->sc_cmap_green[i] = rasops_cmap[j + 1]; 294 sc->sc_cmap_blue[i] = rasops_cmap[j + 2]; 295 j += 3; 296 } 297 } 298 299 static void 300 tdvfb_init_screen(void *cookie, struct vcons_screen *scr, int existing, 301 long *defattr) 302 { 303 struct tdvfb_softc *sc = cookie; 304 struct rasops_info *ri = &scr->scr_ri; 305 306 wsfont_init(); 307 308 ri->ri_depth = sc->sc_bpp; 309 ri->ri_width = sc->sc_width; 310 ri->ri_height = sc->sc_height; 311 ri->ri_stride = sc->sc_linebytes; 312 ri->ri_flg = RI_CENTER; 313 314 #if BYTE_ORDER == BIG_ENDIAN 315 #if 0 /* XXX: not yet :( */ 316 if (sc->sc_bpp == 16) 317 ri->ri_flg |= RI_BITSWAP; 318 #endif 319 #endif 320 321 ri->ri_bits = (char *) bus_space_vaddr(sc->sc_cvgt, sc->sc_fbh); 322 #ifdef TDVFB_DEBUG 323 aprint_normal_dev(sc->sc_dev, "fb handle: %lx, ri_bits: %p\n", sc->sc_fbh, ri->ri_bits); 324 #endif /* TDVFB_DEBUG */ 325 326 scr->scr_flags |= VCONS_DONT_READ; 327 328 rasops_init(ri, 0, 0); 329 ri->ri_caps = WSSCREEN_WSCOLORS; 330 rasops_reconfig(ri, sc->sc_height / ri->ri_font->fontheight, 331 sc->sc_width / ri->ri_font->fontwidth); 332 333 ri->ri_hw = scr; 334 335 /* If we are a Voodoo2 and running in 16 bits try to use blitter. */ 336 if ((sc->sc_voodootype == TDV_VOODOO_2) && (sc->sc_bpp == 16)) { 337 aprint_normal_dev(sc->sc_dev, "using CVG blitter\n"); 338 ri->ri_ops.eraserows = tdvfb_eraserows; 339 ri->ri_ops.copyrows = tdvfb_copyrows; 340 } 341 } 342 343 static bool 344 tdvfb_videomode_set(struct tdvfb_softc *sc) 345 { 346 uint32_t fbiinit1, fbiinit5, fbiinit6, lfbmode; 347 uint16_t vbackporch, vsyncon, vsyncoff; 348 uint16_t hbackporch, hsyncon, hsyncoff; 349 uint16_t yheight, xwidth; 350 351 yheight = sc->sc_videomode->vdisplay; 352 xwidth = sc->sc_videomode->hdisplay; 353 354 vbackporch = sc->sc_videomode->vtotal - sc->sc_videomode->vsync_end; 355 hbackporch = sc->sc_videomode->htotal - sc->sc_videomode->hsync_end; 356 357 vsyncon = sc->sc_videomode->vsync_end - sc->sc_videomode->vsync_start; 358 hsyncon = sc->sc_videomode->hsync_end - sc->sc_videomode->hsync_start; 359 360 vsyncoff = sc->sc_videomode->vtotal - vsyncon; 361 hsyncoff = sc->sc_videomode->htotal - hsyncon; 362 #ifdef TDVFB_DEBUG 363 aprint_normal_dev(sc->sc_dev, 364 "xy %d %d hbp %d vbp %d, hson %d, hsoff %d, vson %d, vsoff %d\n", 365 xwidth, yheight, hbackporch, vbackporch, hsyncon, hsyncoff, 366 vsyncon, vsyncoff); 367 #endif /* TDVFB_DEBUG */ 368 369 sc->vid_timing = tdvfb_gendac_calc_pll(sc->sc_videomode->dot_clock); 370 371 if(sc->sc_voodootype == TDV_VOODOO_2) 372 sc->sc_x_tiles = (sc->sc_videomode->hdisplay + 63 ) / 64 * 2; 373 else 374 sc->sc_x_tiles = (sc->sc_videomode->hdisplay + 63 ) / 64; 375 376 tdvfb_cvg_write(sc, TDV_OFF_NOPCMD, 0); 377 tdvfb_wait(sc); 378 379 /* enable writing to fbiinit regs, reset, disable DRAM refresh */ 380 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG, 381 TDV_INITENABLE_EN_INIT); 382 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT1, TDV_FBIINIT1_VIDEO_RST); 383 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT0, TDV_FBIINIT0_FBI_RST | 384 TDV_FBIINIT0_FIFO_RST); 385 tdvfb_cvg_unset(sc, TDV_OFF_FBIINIT2, TDV_FBIINIT2_DRAM_REFR); 386 tdvfb_wait(sc); 387 388 /* program video timings into CVG/SST-1*/ 389 tdvfb_cvg_write(sc, TDV_OFF_VDIMENSIONS, yheight << 16 | (xwidth - 1)); 390 tdvfb_cvg_write(sc, TDV_OFF_BACKPORCH, vbackporch << 16 | 391 (hbackporch - 2)); 392 tdvfb_cvg_write(sc, TDV_OFF_HSYNC, hsyncoff << 16 | (hsyncon - 1)); 393 tdvfb_cvg_write(sc, TDV_OFF_VSYNC, vsyncoff << 16 | vsyncon); 394 395 tdvfb_videomode_dac(sc); 396 397 fbiinit1 = ((tdvfb_cvg_read(sc, TDV_OFF_FBIINIT1) & 398 TDV_FBIINIT1_VIDMASK) | 399 TDV_FBIINIT1_DR_DATA | 400 TDV_FBIINIT1_DR_BLANKING | 401 TDV_FBIINIT1_DR_HVSYNC | 402 TDV_FBIINIT1_DR_DCLK | 403 TDV_FBIINIT1_IN_VCLK_2X ); 404 405 if (sc->sc_voodootype == TDV_VOODOO_2) { 406 fbiinit1 |= ((sc->sc_x_tiles & 0x20) >> 5) 407 << TDV_FBIINIT1_TILES_X_MSB | ((sc->sc_x_tiles & 0x1e) >> 1) 408 << TDV_FBIINIT1_TILES_X; 409 fbiinit6 = (sc->sc_x_tiles & 0x1) << TDV_FBIINIT6_TILES_X_LSB; 410 } else 411 fbiinit1 |= sc->sc_x_tiles << TDV_FBIINIT1_TILES_X; 412 413 fbiinit1 |= TDV_FBIINIT1_VCLK_2X << TDV_FBIINIT1_VCLK_SRC; 414 415 if (sc->sc_voodootype == TDV_VOODOO_2) { 416 fbiinit5 = tdvfb_cvg_read(sc, TDV_OFF_FBIINIT5) 417 & TDV_FBIINIT5_VIDMASK; 418 if (sc->sc_videomode->flags & VID_PHSYNC) 419 fbiinit5 |= TDV_FBIINIT5_PHSYNC; 420 if (sc->sc_videomode->flags & VID_PVSYNC) 421 fbiinit5 |= TDV_FBIINIT5_PVSYNC; 422 } 423 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT1, fbiinit1); 424 if (sc->sc_voodootype == TDV_VOODOO_2) { 425 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT6, fbiinit6); 426 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT5, fbiinit5); 427 } 428 tdvfb_wait(sc); 429 430 /* unreset, enable DRAM refresh */ 431 tdvfb_cvg_unset(sc, TDV_OFF_FBIINIT1, TDV_FBIINIT1_VIDEO_RST); 432 tdvfb_cvg_unset(sc, TDV_OFF_FBIINIT0, TDV_FBIINIT0_FBI_RST | 433 TDV_FBIINIT0_FIFO_RST); 434 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT2, TDV_FBIINIT2_DRAM_REFR); 435 /* diable access to FBIINIT regs */ 436 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG, 437 TDV_INITENABLE_EN_FIFO); 438 tdvfb_wait(sc); 439 440 if (sc->sc_bpp == 16) 441 lfbmode = TDV_LFBMODE_565; 442 else if (sc->sc_bpp == 32) 443 lfbmode = TDV_LFBMODE_8888; 444 else 445 return false; 446 447 #if BYTE_ORDER == BIG_ENDIAN 448 lfbmode |= TDV_LFBMODE_BSW_WR | TDV_LFBMODE_BSW_RD; 449 #endif 450 451 tdvfb_cvg_write(sc, TDV_OFF_LFBMODE, lfbmode); 452 453 return true; 454 } 455 456 /* 457 * Update DAC parameters for selected video mode. 458 */ 459 static void 460 tdvfb_videomode_dac(struct tdvfb_softc *sc) 461 { 462 uint32_t fbiinit2, fbiinit3; 463 464 /* remember current FBIINIT settings */ 465 fbiinit2 = tdvfb_cvg_read(sc, TDV_OFF_FBIINIT2); 466 fbiinit3 = tdvfb_cvg_read(sc, TDV_OFF_FBIINIT3); 467 468 /* remap DAC */ 469 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG, 470 TDV_INITENABLE_EN_INIT | TDV_INITENABLE_REMAPDAC); 471 472 tdvfb_cvg_dac_write(sc, TDV_GENDAC_CMD, TDV_GENDAC_CMD_16BITS); 473 474 tdvfb_gendac_set_vid_timing(sc, &(sc->vid_timing)); 475 476 /* disable remapping */ 477 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG, 478 TDV_INITENABLE_EN_INIT); 479 /* restore */ 480 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT2, fbiinit2); 481 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT2, fbiinit3); 482 } 483 484 /* 485 * Check how much memory do we have. Actually, Voodoo1/2 has separate 486 * framebuffer and texture memory. This function only checks for framebuffer 487 * memory. Texture memory ramains unused. 488 */ 489 static size_t 490 tdvfb_mem_size(struct tdvfb_softc *sc) 491 { 492 size_t mem_size; 493 uint32_t vram_test4, vram_test2; 494 495 bus_space_write_4(sc->sc_cvgt, sc->sc_fbh, 0, 0x11aabbaa); 496 bus_space_write_4(sc->sc_cvgt, sc->sc_fbh, 0x100000, 0x22aabbaa); 497 bus_space_write_4(sc->sc_cvgt, sc->sc_fbh, 0x200000, 0x44aabbaa); 498 499 vram_test4 = bus_space_read_4(sc->sc_cvgt, sc->sc_fbh, 0x400000); 500 vram_test2 = bus_space_read_4(sc->sc_cvgt, sc->sc_fbh, 0x200000); 501 502 if (vram_test4 == 0x44aabbaa) 503 mem_size = 4*1024*1024; 504 else if (vram_test2 == 0x22aabbaa) { 505 mem_size = 2*1024*1024; 506 } else 507 mem_size = 1*1024*1024; 508 509 return mem_size; 510 } 511 512 /* do the low level init of Voodoo board */ 513 static bool 514 tdvfb_init(struct tdvfb_softc *sc) 515 { 516 /* undocumented - found in glide code */ 517 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_VCLK_DISABLE_REG, 0); 518 /* allow write to hardware initialization registers */ 519 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG, 520 TDV_INITENABLE_EN_INIT); 521 522 /* reset the board */ 523 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT1, TDV_FBIINIT1_VIDEO_RST); 524 tdvfb_wait(sc); 525 tdvfb_cvg_set(sc, TDV_OFF_FBIINIT0, TDV_FBIINIT0_FBI_RST | 526 TDV_FBIINIT0_FIFO_RST); 527 tdvfb_wait(sc); 528 529 /* disable video RAM refresh */ 530 tdvfb_cvg_unset(sc, TDV_OFF_FBIINIT2, TDV_FBIINIT2_DRAM_REFR); 531 tdvfb_wait(sc); 532 533 /* on voodoo1 I had to read FBIINIT2 before remapping, 534 * otherwise weird things were happening, on v2 it works just fine */ 535 /* tdvfb_cvg_read(sc, TDV_OFF_FBIINIT2); */ 536 537 /* remap DAC */ 538 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG, 539 TDV_INITENABLE_EN_INIT | TDV_INITENABLE_REMAPDAC); 540 541 /* detect supported DAC, TODO: we really should support other DACs */ 542 if(!tdvfb_gendac_detect(sc)) { 543 aprint_error_dev(sc->sc_dev, "could not detect ICS GENDAC\n"); 544 return false; 545 } 546 547 /* calculate PLL used to drive the chips (graphics clock) */ 548 if(sc->sc_voodootype == TDV_VOODOO_2) 549 sc->cvg_timing = tdvfb_gendac_calc_pll(TDV_CVG_CLK); 550 else 551 sc->cvg_timing = tdvfb_gendac_calc_pll(TDV_SST_CLK); 552 553 /* set PLL for gfx clock */ 554 tdvfb_gendac_set_cvg_timing(sc, &(sc->cvg_timing)); 555 556 /* don't remap the DAC anymore */ 557 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG, 558 TDV_INITENABLE_EN_INIT | TDV_INITENABLE_EN_FIFO); 559 560 /* set FBIINIT registers to some default values that make sense */ 561 tdvfb_fbiinit_defaults(sc); 562 563 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_INITENABLE_REG, 564 TDV_INITENABLE_EN_FIFO); 565 pci_conf_write(sc->sc_pc, sc->sc_pcitag, TDV_VCLK_ENABLE_REG, 0); 566 567 return true; 568 } 569 570 static void 571 tdvfb_fbiinit_defaults(struct tdvfb_softc *sc) 572 { 573 uint32_t fbiinit0, fbiinit1, fbiinit2, fbiinit3, fbiinit4, fbiinit6; 574 575 fbiinit0 = TDV_FBIINIT0_VGA_PASS; /* disable VGA passthrough */ 576 fbiinit1 = /*TDV_FBIINIT1_PCIWAIT |*/ /* one wait state for PCI write */ 577 TDV_FBIINIT1_LFB_EN | /* enable lfb reads */ 578 TDV_FBIINIT1_VIDEO_RST | /* video timing reset */ 579 10 << TDV_FBIINIT1_TILES_X | /* tiles x/horizontal */ 580 TDV_FBIINIT1_VCLK_2X << TDV_FBIINIT1_VCLK_SRC ; 581 582 fbiinit2 = TDV_FBIINIT2_SWB_ALG |/* swap buffer use DAC sync */ 583 TDV_FBIINIT2_FAST_RAS | /* fast RAS read */ 584 TDV_FBIINIT2_DRAM_OE | /* enable DRAM OE */ 585 TDV_FBIINIT2_DRAM_REFR | /* enable DRAM refresh */ 586 TDV_FBIINIT2_FIFO_RDA | /* FIFO read ahead */ 587 TDV_FBIINIT2_DRAM_REF16 << TDV_FBIINIT2_DRAM_REFLD; /* 16 ms */ 588 589 fbiinit3 = TDV_FBIINIT3_TREX_DIS; /* disable texture mapping */ 590 591 fbiinit4 = /*TDV_FBIINIT4_PCIWAIT|*/ /* one wait state for PCI write */ 592 TDV_FBIINIT4_LFB_RDA; /* lfb read ahead */ 593 594 fbiinit6 = 0; 595 #ifdef TDVFB_DEBUG 596 aprint_normal("fbiinit: 0 %x, 1 %x, 2 %x, 3 %x, 4 %x, 6 %x\n", 597 fbiinit0, fbiinit1, fbiinit2, fbiinit3, fbiinit4, fbiinit6); 598 #endif /* TDVFB_DEBUG */ 599 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT0, fbiinit0); 600 tdvfb_wait(sc); 601 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT1, fbiinit1); 602 tdvfb_wait(sc); 603 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT2, fbiinit2); 604 tdvfb_wait(sc); 605 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT3, fbiinit3); 606 tdvfb_wait(sc); 607 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT4, fbiinit4); 608 tdvfb_wait(sc); 609 if (sc->sc_voodootype == TDV_VOODOO_2) { 610 tdvfb_cvg_write(sc, TDV_OFF_FBIINIT6, fbiinit6); 611 tdvfb_wait(sc); 612 } 613 } 614 615 static void 616 tdvfb_gendac_set_vid_timing(struct tdvfb_softc *sc, 617 struct tdvfb_dac_timing *timing) 618 { 619 uint8_t pllreg; 620 621 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, TDV_GENDAC_PLL_CTRL); 622 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 623 624 /* write the timing for gfx clock into "slot" 0 */ 625 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLWR, TDV_GENDAC_PLL_0); 626 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, timing->m); 627 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, timing->n); 628 /* select "slot" 0 for output */ 629 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLWR, TDV_GENDAC_PLL_CTRL); 630 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, 631 (pllreg & TDV_GENDAC_VIDPLLMASK) | TDV_GENDAC_PLL_VIDCLK | 632 TDV_GENDAC_PLL_VIDCLK0); 633 tdvfb_wait(sc); 634 tdvfb_wait(sc); 635 #ifdef TDVFB_DEBUG 636 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, TDV_GENDAC_PLL_0); 637 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 638 aprint_normal("vid read again: %d\n", pllreg); 639 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 640 aprint_normal("vid read again: %d\n", pllreg); 641 #endif /* TDVFB_DEBUG */ 642 } 643 644 static void 645 tdvfb_gendac_set_cvg_timing(struct tdvfb_softc *sc, 646 struct tdvfb_dac_timing *timing) 647 { 648 uint8_t pllreg; 649 650 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, TDV_GENDAC_PLL_CTRL); 651 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 652 653 /* write the timing for gfx clock into "slot" A */ 654 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLWR, TDV_GENDAC_PLL_A); 655 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, timing->m); 656 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, timing->n); 657 /* select "slot" A for output */ 658 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLWR, TDV_GENDAC_PLL_CTRL); 659 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLDATA, 660 (pllreg & TDV_GENDAC_CVGPLLMASK) | TDV_GENDAC_PLL_CVGCLKA); 661 #ifdef TDVFB_DEBUG 662 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, TDV_GENDAC_PLL_A); 663 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 664 aprint_normal("read again: %d\n", pllreg); 665 pllreg = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 666 aprint_normal("read again: %d\n", pllreg); 667 #endif /* TDVFB_DEBUG */ 668 tdvfb_wait(sc); 669 } 670 671 static struct tdvfb_dac_timing 672 tdvfb_gendac_calc_pll(int freq) 673 { 674 int n1, n2; 675 int m, mdbl; 676 int best_m, best_n1, best_error; 677 int fout; 678 struct tdvfb_dac_timing timing; 679 680 best_m = -1; best_n1 = -1; 681 682 /* select highest possible n2, check n2 * fCLK < TDV_GENDAC_MAXVCO */ 683 for (n2 = TDV_GENDAC_MAX_N2; n2 >= TDV_GENDAC_MIN_N2; n2--) { 684 if ((freq * (1 << n2)) < TDV_GENDAC_MAXVCO) 685 break; 686 } 687 688 best_error = freq; 689 690 /* 691 * m+2 2^n2 * fOUT 692 * ---- = ----------- 693 * n1+2 fREF 694 */ 695 for (n1 = TDV_GENDAC_MIN_N1; n1 <= TDV_GENDAC_MAX_N1; n1++) { 696 /* loop mostly inspired by Linux driver */ 697 mdbl = (2 * freq * (1 << n2)*(n1 + 2)) / TDV_GENDAC_REFFREQ - 4; 698 if (mdbl % 2) 699 m = mdbl/2+1; 700 else 701 m = mdbl/2; 702 703 if(m > TDV_GENDAC_MAX_M) 704 break; 705 706 fout = (TDV_GENDAC_REFFREQ * (m + 2)) / ((1 << n2) * (n1 + 2)); 707 if ((abs(fout - freq) < best_error) && (m > 0)) { 708 best_n1 = n1; 709 best_m = m; 710 best_error = abs(fout - freq); 711 if (200*best_error < freq) break; 712 } 713 714 } 715 716 fout = (TDV_GENDAC_REFFREQ * (best_m + 2)) / ((1 << n2) * (best_n1 + 2)); 717 timing.m = best_m; 718 timing.n = (n2 << 5) | best_n1; 719 timing.fout = fout; 720 721 #ifdef TDVFB_DEBUG 722 aprint_normal("tdvfb_gendac_calc_pll ret: m %d, n %d, fout %d kHz\n", 723 timing.m, timing.n, timing.fout); 724 #endif /* TDVFB_DEBUG */ 725 726 return timing; 727 } 728 729 static bool 730 tdvfb_gendac_detect(struct tdvfb_softc *sc) 731 { 732 uint8_t m_f1, m_f7, m_fb; 733 uint8_t n_f1, n_f7, n_fb; 734 735 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, 0x1); 736 m_f1 = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 737 n_f1 = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 738 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, 0x7); 739 m_f7 = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 740 n_f7 = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 741 tdvfb_cvg_dac_write(sc, TDV_GENDAC_PLLRD, 0xB); 742 m_fb = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 743 n_fb = tdvfb_cvg_dac_read(sc, TDV_GENDAC_PLLDATA); 744 745 if( (m_f1 == TDV_GENDAC_DFLT_F1_M) && 746 (n_f1 == TDV_GENDAC_DFLT_F1_N) && 747 (m_f7 == TDV_GENDAC_DFLT_F7_M) && 748 (n_f7 == TDV_GENDAC_DFLT_F7_N) && 749 (n_fb == TDV_GENDAC_DFLT_FB_N) && 750 (n_fb == TDV_GENDAC_DFLT_FB_N) ) { 751 aprint_normal_dev(sc->sc_dev, "ICS 5342 GENDAC\n"); 752 return true; 753 } 754 755 return false; 756 } 757 758 static void 759 tdvfb_wait(struct tdvfb_softc *sc) 760 { 761 uint32_t x, cnt; 762 cnt = 0; 763 for (x = 0; x < MAXLOOP; x++) { 764 if (tdvfb_cvg_read(sc, TDV_OFF_STATUS) & TDV_STATUS_FBI_BUSY) 765 cnt = 0; 766 else 767 cnt++; 768 769 if (cnt >= 5) /* Voodoo2 specs suggest at least 3 */ 770 break; 771 } 772 773 if (x == MAXLOOP) 774 /* 775 * The console probably isn't working now anyway, so maybe 776 * let's panic... At least it will drop into ddb if some other 777 * device a console. 778 */ 779 panic("tdvfb is stuck!\n"); 780 } 781 782 static uint32_t 783 tdvfb_cvg_read(struct tdvfb_softc *sc, uint32_t reg) 784 { 785 uint32_t rv; 786 rv = bus_space_read_4(sc->sc_cvgt, sc->sc_cvgh, reg); 787 #ifdef TDVFB_DEBUG_REGS 788 aprint_normal("cvg_read val %x from reg %x\n", rv, reg); 789 #endif /* TDVFB_DEBUG_REGS */ 790 return rv; 791 } 792 793 static void 794 tdvfb_cvg_write(struct tdvfb_softc *sc, uint32_t reg, uint32_t val) 795 { 796 #ifdef TDVFB_DEBUG_REGS 797 aprint_normal("cvg_write val %x to reg %x\n", val, reg); 798 #endif /* TDVFB_DEBUG_REGS */ 799 bus_space_write_4(sc->sc_cvgt, sc->sc_cvgh, reg, val); 800 } 801 802 static void 803 tdvfb_cvg_set(struct tdvfb_softc *sc, uint32_t reg, uint32_t bits) 804 { 805 uint32_t v; 806 v = tdvfb_cvg_read(sc, reg) | bits; 807 tdvfb_cvg_write(sc, reg, v); 808 } 809 810 static void 811 tdvfb_cvg_unset(struct tdvfb_softc *sc, uint32_t reg, uint32_t bits) 812 { 813 uint32_t v; 814 v = tdvfb_cvg_read(sc, reg) & ~bits; 815 tdvfb_cvg_write(sc, reg, v); 816 } 817 818 static uint8_t 819 tdvfb_cvg_dac_read(struct tdvfb_softc *sc, uint32_t reg) 820 { 821 uint32_t rv; 822 823 tdvfb_cvg_dac_write(sc, reg, TDV_DAC_DATA_READ); 824 825 rv = tdvfb_cvg_read(sc, TDV_OFF_DAC_READ); 826 #ifdef TDVFB_DEBUG_REGS 827 aprint_normal("cvg_dac_read val %x from reg %x\n", rv, reg); 828 #endif /* TDVFB_DEBUG_REGS */ 829 return rv & 0xFF; 830 } 831 832 static void 833 tdvfb_cvg_dac_write(struct tdvfb_softc *sc, uint32_t reg, uint32_t val) 834 { 835 uint32_t wreg; 836 837 wreg = ((reg & TDV_GENDAC_ADDRMASK) << 8) | val; 838 839 #ifdef TDVFB_DEBUG_REGS 840 aprint_normal("cvg_dac_write val %x to reg %x (%x)\n", val, reg, 841 wreg); 842 #endif /* TDVFB_DEBUG_REGS */ 843 844 tdvfb_cvg_write(sc, TDV_OFF_DAC_DATA, wreg); 845 tdvfb_wait(sc); 846 } 847 848 static void 849 tdvfb_rectfill(struct tdvfb_softc *sc, int x, int y, int wi, int he, 850 uint32_t color) 851 { 852 tdvfb_cvg_write(sc, TDV_OFF_BLTSRC, 0); 853 tdvfb_cvg_write(sc, TDV_OFF_BLTDST, 0); 854 tdvfb_cvg_write(sc, TDV_OFF_BLTROP, TDV_BLTROP_COPY); 855 tdvfb_cvg_write(sc, TDV_OFF_BLTXYSTRIDE, 856 sc->sc_linebytes | (sc->sc_linebytes << 16)); 857 tdvfb_cvg_write(sc, TDV_OFF_BLTDSTXY, x | (y << 16)); 858 tdvfb_cvg_write(sc, TDV_OFF_BLTSIZE, wi | (he << 16)); 859 tdvfb_cvg_write(sc, TDV_OFF_BLTCMD, TDV_BLTCMD_RECTFILL | 860 TDV_BLTCMD_LAUNCH | TDV_BLTCMD_FMT_565 << 3 | TDV_BLTCMD_DSTTILED | 861 TDV_BLTCMD_CLIPRECT ); 862 tdvfb_wait(sc); 863 } 864 865 static void 866 tdvfb_bitblt(struct tdvfb_softc *sc, int xs, int ys, int xd, int yd, int wi, 867 int he) 868 { 869 tdvfb_cvg_write(sc, TDV_OFF_BLTSRC, 0); 870 tdvfb_cvg_write(sc, TDV_OFF_BLTDST, 0); 871 tdvfb_cvg_write(sc, TDV_OFF_BLTROP, TDV_BLTROP_COPY); 872 tdvfb_cvg_write(sc, TDV_OFF_BLTXYSTRIDE, 873 sc->sc_linebytes | (sc->sc_linebytes << 16)); 874 tdvfb_cvg_write(sc, TDV_OFF_BLTSRCXY, xs | (ys << 16)); 875 tdvfb_cvg_write(sc, TDV_OFF_BLTDSTXY, xd | (yd << 16)); 876 tdvfb_cvg_write(sc, TDV_OFF_BLTSIZE, wi | (he << 16)); 877 tdvfb_cvg_write(sc, TDV_OFF_BLTCMD, TDV_BLTCMD_SCR2SCR | 878 TDV_BLTCMD_LAUNCH | TDV_BLTCMD_FMT_565 << 3); 879 880 tdvfb_wait(sc); 881 } 882 883 static void 884 tdvfb_copyrows(void *cookie, int srcrow, int dstrow, int nrows) 885 { 886 struct tdvfb_softc *sc; 887 struct rasops_info *ri; 888 struct vcons_screen *scr; 889 int x, ys, yd, wi, he; 890 891 ri = cookie; 892 scr = ri->ri_hw; 893 sc = scr->scr_cookie; 894 895 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 896 x = ri->ri_xorigin; 897 ys = ri->ri_yorigin + ri->ri_font->fontheight * srcrow; 898 yd = ri->ri_yorigin + ri->ri_font->fontheight * dstrow; 899 wi = ri->ri_emuwidth; 900 he = ri->ri_font->fontheight * nrows; 901 tdvfb_bitblt(sc, x, ys, x, yd, wi, he); 902 } 903 } 904 905 static void 906 tdvfb_eraserows(void *cookie, int row, int nrows, long fillattr) 907 { 908 909 struct tdvfb_softc *sc; 910 struct rasops_info *ri; 911 struct vcons_screen *scr; 912 int x, y, wi, he, fg, bg, ul; 913 914 ri = cookie; 915 scr = ri->ri_hw; 916 sc = scr->scr_cookie; 917 918 if (sc->sc_mode == WSDISPLAYIO_MODE_EMUL) { 919 rasops_unpack_attr(fillattr, &fg, &bg, &ul); 920 if ((row == 0) && (nrows == ri->ri_rows)) 921 tdvfb_rectfill(sc, 0, 0, ri->ri_width, 922 ri->ri_height, ri->ri_devcmap[bg]); 923 else { 924 x = ri->ri_xorigin; 925 y = ri->ri_yorigin + ri->ri_font->fontheight * row; 926 wi = ri->ri_emuwidth; 927 he = ri->ri_font->fontheight * nrows; 928 tdvfb_rectfill(sc, x, y, wi, he, ri->ri_devcmap[bg]); 929 } 930 } 931 } 932 933 static int 934 tdvfb_ioctl(void *v, void *vs, u_long cmd, void *data, int flag, struct lwp *l) 935 { 936 struct vcons_data *vd; 937 struct tdvfb_softc *sc; 938 struct wsdisplay_fbinfo *wsfbi; 939 struct vcons_screen *ms; 940 941 vd = v; 942 sc = vd->cookie; 943 ms = vd->active; 944 945 switch (cmd) { 946 case WSDISPLAYIO_GTYPE: 947 *(u_int *)data = WSDISPLAY_TYPE_PCIMISC; 948 return 0; 949 950 case PCI_IOC_CFGREAD: 951 case PCI_IOC_CFGWRITE: 952 return pci_devioctl(sc->sc_pc, sc->sc_pcitag, 953 cmd, data, flag, l); 954 955 case WSDISPLAYIO_GET_BUSID: 956 return wsdisplayio_busid_pci(sc->sc_dev, sc->sc_pc, 957 sc->sc_pcitag, data); 958 959 case WSDISPLAYIO_GINFO: 960 if (ms == NULL) 961 return ENODEV; 962 963 wsfbi = (void*) data; 964 wsfbi->height = ms->scr_ri.ri_height; 965 wsfbi->width = ms->scr_ri.ri_width; 966 wsfbi->depth = ms->scr_ri.ri_depth; 967 wsfbi->cmsize = 256; 968 return 0; 969 970 case WSDISPLAYIO_LINEBYTES: 971 *(u_int*)data = sc->sc_linebytes; 972 return 0; 973 974 case WSDISPLAYIO_SMODE: 975 { 976 int new_mode = *(int*)data; 977 if (new_mode != sc->sc_mode) { 978 sc->sc_mode = new_mode; 979 if(new_mode == WSDISPLAYIO_MODE_EMUL) 980 vcons_redraw_screen(ms); 981 } 982 return 0; 983 } 984 case WSDISPLAYIO_GET_FBINFO: 985 { 986 struct wsdisplayio_fbinfo *fbi = data; 987 struct rasops_info *ri; 988 int ret; 989 990 ri = &sc->vd.active->scr_ri; 991 ret = wsdisplayio_get_fbinfo(ri, fbi); 992 return ret; 993 } 994 } 995 return EPASSTHROUGH; 996 } 997 998 static paddr_t 999 tdvfb_mmap(void *v, void *vs, off_t offset, int prot) 1000 { 1001 struct vcons_data *vd; 1002 struct tdvfb_softc *sc; 1003 paddr_t pa; 1004 1005 vd = v; 1006 sc = vd->cookie; 1007 1008 if (offset < sc->sc_memsize) { 1009 pa = bus_space_mmap(sc->sc_cvgt, sc->sc_fbh + offset, 0, prot, 1010 BUS_SPACE_MAP_LINEAR); 1011 return pa; 1012 } 1013 1014 return -1; 1015 } 1016 1017