root/dev/pci/sti_pci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sti_pci_match
  2. sti_pci_attach
  3. sti_check_rom
  4. sti_readbar
  5. sti_pci_enable_rom
  6. sti_pci_disable_rom

    1 /*      $OpenBSD: sti_pci.c,v 1.6 2007/06/17 12:07:10 miod Exp $        */
    2 
    3 /*
    4  * Copyright (c) 2006, 2007 Miodrag Vallat.
    5  *
    6  * Permission to use, copy, modify, and distribute this software for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice, this permission notice, and the disclaimer below
    9  * appear in all copies.
   10  *
   11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   18  */
   19 
   20 #include <sys/param.h>
   21 #include <sys/systm.h>
   22 #include <sys/device.h>
   23 
   24 #include <dev/pci/pcireg.h>
   25 #include <dev/pci/pcivar.h>
   26 #include <dev/pci/pcidevs.h>
   27 
   28 #include <dev/wscons/wsdisplayvar.h>
   29 
   30 #include <dev/ic/stireg.h>
   31 #include <dev/ic/stivar.h>
   32 
   33 int     sti_pci_match(struct device *, void *, void *);
   34 void    sti_pci_attach(struct device *, struct device *, void *);
   35 
   36 struct  sti_pci_softc {
   37         struct sti_softc        sc_base;
   38 
   39         pci_chipset_tag_t       sc_pc;
   40         pcitag_t                sc_tag;
   41 };
   42 
   43 struct cfattach sti_pci_ca = {
   44         sizeof(struct sti_pci_softc), sti_pci_match, sti_pci_attach
   45 };
   46 
   47 const struct pci_matchid sti_pci_devices[] = {
   48         { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_EG },
   49         { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX2 },
   50         { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX4 },
   51         { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FX6 },
   52         { PCI_VENDOR_HP, PCI_PRODUCT_HP_VISUALIZE_FXE },
   53 };
   54 
   55 int     sti_readbar(struct sti_softc *, struct pci_attach_args *, u_int, int);
   56 int     sti_check_rom(struct sti_pci_softc *, struct pci_attach_args *);
   57 void    sti_pci_enable_rom(struct sti_softc *);
   58 void    sti_pci_disable_rom(struct sti_softc *);
   59 
   60 int     sti_pci_is_console(struct pci_attach_args *, bus_addr_t *);
   61 
   62 int
   63 sti_pci_match(struct device *parent, void *cf, void *aux)
   64 {
   65         struct pci_attach_args *paa = aux;
   66 
   67         return (pci_matchbyid(paa, sti_pci_devices,
   68             sizeof(sti_pci_devices) / sizeof(sti_pci_devices[0])));
   69 }
   70 
   71 void
   72 sti_pci_attach(struct device *parent, struct device *self, void *aux)
   73 {
   74         struct sti_pci_softc *spc = (void *)self;
   75         struct pci_attach_args *paa = aux;
   76 
   77         spc->sc_pc = paa->pa_pc;
   78         spc->sc_tag = paa->pa_tag;
   79         spc->sc_base.sc_enable_rom = sti_pci_enable_rom;
   80         spc->sc_base.sc_disable_rom = sti_pci_disable_rom;
   81 
   82         printf("\n");
   83 
   84         if (sti_check_rom(spc, paa) != 0)
   85                 return;
   86 
   87         printf("%s", self->dv_xname);
   88         if (sti_attach_common(&spc->sc_base, STI_CODEBASE_MAIN) == 0) {
   89                 if (sti_pci_is_console(paa, spc->sc_base.bases) != 0)
   90                         spc->sc_base.sc_flags |= STI_CONSOLE;
   91                 startuphook_establish(sti_end_attach, spc);
   92         }
   93 }
   94 
   95 /*
   96  * Grovel the STI ROM image.
   97  */
   98 int
   99 sti_check_rom(struct sti_pci_softc *spc, struct pci_attach_args *pa)
  100 {
  101         struct sti_softc *sc = &spc->sc_base;
  102         pcireg_t address, mask;
  103         bus_space_handle_t romh;
  104         bus_size_t romsize, subsize, stiromsize;
  105         bus_addr_t selected, offs, suboffs;
  106         u_int32_t tmp;
  107         int i;
  108         int rc;
  109 
  110         /* sort of inline sti_pci_enable_rom(sc) */
  111         address = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
  112         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, ~PCI_ROM_ENABLE);
  113         mask = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_ROM_REG);
  114         address |= PCI_ROM_ENABLE;
  115         pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_ROM_REG, address);
  116         sc->sc_flags |= STI_ROM_ENABLED;
  117 
  118         /*
  119          * Map the complete ROM for now.
  120          */
  121 
  122         romsize = PCI_ROM_SIZE(mask);
  123         rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address), romsize,
  124             0, &romh);
  125         sti_pci_disable_rom(sc);
  126         if (rc != 0) {
  127                 printf("%s: can't map PCI ROM (%d)\n",
  128                     sc->sc_dev.dv_xname, rc);
  129                 goto fail2;
  130         }
  131 
  132         /*
  133          * Iterate over the ROM images, pick the best candidate.
  134          */
  135 
  136         selected = (bus_addr_t)-1;
  137         for (offs = 0; offs < romsize; offs += subsize) {
  138                 sti_pci_enable_rom(sc);
  139                 /*
  140                  * Check for a valid ROM header.
  141                  */
  142                 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 0);
  143                 tmp = letoh32(tmp);
  144                 if (tmp != 0x55aa0000) {
  145                         sti_pci_disable_rom(sc);
  146                         if (offs == 0) {
  147                                 printf("%s: invalid PCI ROM header signature"
  148                                     " (%08x)\n",
  149                                     sc->sc_dev.dv_xname, tmp);
  150                                 rc = EINVAL;
  151                         }
  152                         break;
  153                 }
  154 
  155                 /*
  156                  * Check ROM type.
  157                  */
  158                 tmp = bus_space_read_4(pa->pa_memt, romh, offs + 4);
  159                 tmp = letoh32(tmp);
  160                 if (tmp != 0x00000001) {        /* 1 == STI ROM */
  161                         sti_pci_disable_rom(sc);
  162                         if (offs == 0) {
  163                                 printf("%s: invalid PCI ROM type (%08x)\n",
  164                                     sc->sc_dev.dv_xname, tmp);
  165                                 rc = EINVAL;
  166                         }
  167                         break;
  168                 }
  169 
  170                 subsize = (bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
  171                     offs + 0x0c);
  172                 subsize <<= 9;
  173 
  174 #ifdef STIDEBUG
  175                 sti_pci_disable_rom(sc);
  176                 printf("ROM offset %08x size %08x type %08x",
  177                     offs, subsize, tmp);
  178                 sti_pci_enable_rom(sc);
  179 #endif
  180 
  181                 /*
  182                  * Check for a valid ROM data structure.
  183                  * We do not need it except to know what architecture the ROM
  184                  * code is for.
  185                  */
  186 
  187                 suboffs = offs +(bus_addr_t)bus_space_read_2(pa->pa_memt, romh,
  188                     offs + 0x18);
  189                 tmp = bus_space_read_4(pa->pa_memt, romh, suboffs + 0);
  190                 tmp = letoh32(tmp);
  191                 if (tmp != 0x50434952) {        /* PCIR */
  192                         sti_pci_disable_rom(sc);
  193                         if (offs == 0) {
  194                                 printf("%s: invalid PCI data signature"
  195                                     " (%08x)\n",
  196                                     sc->sc_dev.dv_xname, tmp);
  197                                 rc = EINVAL;
  198                         } else {
  199 #ifdef STIDEBUG
  200                                 printf(" invalid PCI data signature %08x\n",
  201                                     tmp);
  202 #endif
  203                                 continue;
  204                         }
  205                 }
  206 
  207                 tmp = bus_space_read_1(pa->pa_memt, romh, suboffs + 0x14);
  208                 sti_pci_disable_rom(sc);
  209 #ifdef STIDEBUG
  210                 printf(" code %02x", tmp);
  211 #endif
  212 
  213                 switch (tmp) {
  214 #ifdef __hppa__
  215                 case 0x10:
  216                         if (selected == (bus_addr_t)-1)
  217                                 selected = offs;
  218                         break;
  219 #endif
  220 #ifdef __i386__
  221                 case 0x00:
  222                         if (selected == (bus_addr_t)-1)
  223                                 selected = offs;
  224                         break;
  225 #endif
  226                 default:
  227 #ifdef STIDEBUG
  228                         printf(" (wrong architecture)");
  229 #endif
  230                         break;
  231                 }
  232 
  233 #ifdef STIDEBUG
  234                 if (selected == offs)
  235                         printf(" -> SELECTED");
  236                 printf("\n");
  237 #endif
  238         }
  239 
  240         if (selected == (bus_addr_t)-1) {
  241                 if (rc == 0) {
  242                         printf("%s: found no ROM with correct microcode"
  243                             " architecture\n", sc->sc_dev.dv_xname);
  244                         rc = ENOEXEC;
  245                 }
  246                 goto fail;
  247         }
  248 
  249         /*
  250          * Read the STI region BAR assignments.
  251          */
  252 
  253         sti_pci_enable_rom(sc);
  254         offs = selected +
  255             (bus_addr_t)bus_space_read_2(pa->pa_memt, romh, selected + 0x0e);
  256         for (i = 0; i < STI_REGION_MAX; i++) {
  257                 rc = sti_readbar(sc, pa, i,
  258                     bus_space_read_1(pa->pa_memt, romh, offs + i));
  259                 if (rc != 0)
  260                         goto fail;
  261         }
  262 
  263         /*
  264          * Find out where the STI ROM itself lies, and its size.
  265          */
  266 
  267         offs = selected +
  268             (bus_addr_t)bus_space_read_4(pa->pa_memt, romh, selected + 0x08);
  269         stiromsize = (bus_addr_t)bus_space_read_4(pa->pa_memt, romh,
  270             offs + 0x18);
  271         stiromsize = letoh32(stiromsize);
  272         sti_pci_disable_rom(sc);
  273 
  274         /*
  275          * Replace our mapping with a smaller mapping of only the area
  276          * we are interested in.
  277          */
  278 
  279         bus_space_unmap(pa->pa_memt, romh, romsize);
  280         rc = bus_space_map(pa->pa_memt, PCI_ROM_ADDR(address) + offs,
  281             stiromsize, 0, &sc->romh);
  282         if (rc != 0) {
  283                 printf("%s: can't map STI ROM (%d)\n",
  284                     sc->sc_dev.dv_xname, rc);
  285                 goto fail2;
  286         }
  287         sc->memt = pa->pa_memt;
  288 
  289         return (0);
  290 
  291 fail:
  292         bus_space_unmap(pa->pa_memt, romh, romsize);
  293 fail2:
  294         sti_pci_disable_rom(sc);
  295 
  296         return (rc);
  297 }
  298 
  299 /*
  300  * Decode a BAR register.
  301  */
  302 int
  303 sti_readbar(struct sti_softc *sc, struct pci_attach_args *pa, u_int region,
  304     int bar)
  305 {
  306         bus_addr_t addr;
  307         bus_size_t size;
  308         u_int32_t cf;
  309         int rc;
  310 
  311         if (bar == 0) {
  312                 sc->bases[region] = 0;
  313                 return (0);
  314         }
  315 
  316 #ifdef DIAGNOSTIC
  317         if (bar < PCI_MAPREG_START || bar > PCI_MAPREG_PPB_END) {
  318                 sti_pci_disable_rom(sc);
  319                 printf("%s: unexpected bar %02x for region %d\n",
  320                     sc->sc_dev.dv_xname, bar, region);
  321                 sti_pci_enable_rom(sc);
  322         }
  323 #endif
  324 
  325         cf = pci_conf_read(pa->pa_pc, pa->pa_tag, bar);
  326 
  327         if (PCI_MAPREG_TYPE(cf) == PCI_MAPREG_TYPE_IO)
  328                 rc = pci_io_find(pa->pa_pc, pa->pa_tag, bar, &addr, &size);
  329         else
  330                 rc = pci_mem_find(pa->pa_pc, pa->pa_tag, bar, &addr, &size,
  331                     NULL);
  332 
  333         if (rc != 0) {
  334                 sti_pci_disable_rom(sc);
  335                 printf("%s: invalid bar %02x for region %d\n",
  336                     sc->sc_dev.dv_xname, bar, region);
  337                 sti_pci_enable_rom(sc);
  338                 return (rc);
  339         }
  340 
  341         sc->bases[region] = addr;
  342         return (0);
  343 }
  344 
  345 /*
  346  * Enable PCI ROM.
  347  */
  348 void
  349 sti_pci_enable_rom(struct sti_softc *sc)
  350 {
  351         struct sti_pci_softc *spc = (struct sti_pci_softc *)sc;
  352         pcireg_t address;
  353 
  354         if (!ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
  355                 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_ROM_REG);
  356                 address |= PCI_ROM_ENABLE;
  357                 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_ROM_REG, address);
  358                 SET(sc->sc_flags, STI_ROM_ENABLED);
  359         }
  360 }
  361 
  362 /*
  363  * Disable PCI ROM.
  364  */
  365 void
  366 sti_pci_disable_rom(struct sti_softc *sc)
  367 {
  368         struct sti_pci_softc *spc = (struct sti_pci_softc *)sc;
  369         pcireg_t address;
  370 
  371         if (ISSET(sc->sc_flags, STI_ROM_ENABLED)) {
  372                 address = pci_conf_read(spc->sc_pc, spc->sc_tag, PCI_ROM_REG);
  373                 address &= ~PCI_ROM_ENABLE;
  374                 pci_conf_write(spc->sc_pc, spc->sc_tag, PCI_ROM_REG, address);
  375 
  376                 CLR(sc->sc_flags, STI_ROM_ENABLED);
  377         }
  378 }

/* [<][>][^][v][top][bottom][index][help] */