1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").  
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 /*
  27  * Silicon Image 3XXX controller specific processing
  28  *
  29  * This file may be expanded to take advantage of Silicon Image
  30  * additional features (if applicable to specific controller model):
  31  * 1. Virtual DMA operation
  32  * 2. Concurrent all-channel DMA
  33  * 3. Large Block Transfers
  34  * 4. Watchdog Timer
  35  * 5. Power Management
  36  * 6. Hot Plug Support
  37  */
  38 
  39 #pragma ident   "%Z%%M% %I%     %E% SMI"
  40 
  41 #include "ata_common.h"
  42 #include "sil3xxx.h"
  43 #include <sys/pci.h>
  44 
  45 int fifocntctl[] = {FIFO_CNTCTL_0, FIFO_CNTCTL_1, FIFO_CNTCTL_2, FIFO_CNTCTL_3};
  46 int sfiscfg[] = {SFISCFG_0, SFISCFG_1, SFISCFG_2, SFISCFG_3};
  47 
  48 /*
  49  * Controller specific initialization
  50  */
  51 uint_t
  52 sil3xxx_init_controller(dev_info_t *dip,
  53         /* LINTED */
  54         ushort_t vendor_id, ushort_t device_id)
  55 {
  56         ddi_acc_handle_t  pci_conf_handle; /* pci config space handle */
  57         uint8_t cache_lnsz, frrc = 0;
  58         uint32_t fifo_cnt_ctl;
  59         int ports, i;
  60 
  61 #ifdef  DEBUG
  62         /* LINTED */
  63         ushort_t sfiscfg_val;
  64 #endif
  65 
  66         /*
  67          * Sil3114, Sil3512, Sil3112
  68          * We want to perform this initialization only once per entire
  69          * pciide controller (all channels)
  70          */
  71         if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_get_parent(dip),
  72                 DDI_PROP_DONTPASS, "sil3xxx-initialized")) {
  73                 return (TRUE);
  74         }
  75 
  76         if (pci_config_setup(ddi_get_parent(dip), &pci_conf_handle) !=
  77             DDI_SUCCESS) {
  78                 cmn_err(CE_WARN,
  79                     "sil3xxx_init_controller: Can't do pci_config_setup\n");
  80                 return (FALSE);
  81         }
  82 
  83         /*
  84          * Sil3114/3512/3112 incorrectly change between MR and back to
  85          * MRM for same transaction, which violates the PCI spec and can
  86          * lead to incorrect data reads.  The workaround
  87          * is to set bits 2:0 in the FIFO count and control register so
  88          * that its value, a multiple of 32 bytes starting at 32, not 0,
  89          * is greater or equal to the cacheline size, a multiple of 4
  90          * bytes.  This will prevent any reads until the FIFO free space
  91          * is greater than a cacheline size, ensuring only MRM is issued.
  92          */
  93 
  94         cache_lnsz = pci_config_get8(pci_conf_handle, PCI_CONF_CACHE_LINESZ);
  95 
  96         /*
  97          * The cache line is specified in 32-bit words, so multiply by 4
  98          * to get bytes.  Then divide by 32 bytes, the granularity of the
  99          * FIFO control bits 2:0.  Add 1 if there is any remainder to
 100          * account for a partial 32-byte block, then subtract 1 since for
 101          * FIFO controls bits 2:0, 0 corresponds to 32, 1 corresponds to
 102          * 64, and so on.  The calculation is expanded for clarity.
 103          */
 104         if (cache_lnsz != 0) {
 105                 frrc = (cache_lnsz * 4 / 32) +
 106                         (((cache_lnsz * 4) % 32) ? 1 : 0) - 1;
 107         }
 108 
 109         if (device_id == SIL3114_DEVICE_ID) {
 110                 ports = 4;
 111         } else {
 112                 ports = 2;
 113         }
 114 
 115         /*
 116          * The following BAR5 registers are accessed via an indirect register
 117          * in the PCI configuration space rather than mapping BAR5.
 118          */
 119         for (i = 0; i < ports; i++) {
 120                 GET_BAR5_INDIRECT(pci_conf_handle, fifocntctl[i],
 121                     fifo_cnt_ctl);
 122                 fifo_cnt_ctl = (fifo_cnt_ctl & ~0x7) | (frrc & 0x7);
 123                 PUT_BAR5_INDIRECT(pci_conf_handle, fifocntctl[i],
 124                     fifo_cnt_ctl);
 125                 /*
 126                  * Correct default setting for FIS0cfg
 127                  */
 128 #ifdef  DEBUG
 129                 GET_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i],
 130                         sfiscfg_val);
 131                 ADBG_WARN(("sil3xxx_init_controller: old val SFISCfg "
 132                         "ch%d: %x\n", i, sfiscfg_val));
 133 #endif
 134                 PUT_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i],
 135                         SFISCFG_ERRATA);
 136 #ifdef  DEBUG
 137                 GET_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i],
 138                         sfiscfg_val);
 139                 ADBG_WARN(("sil3xxx_init_controller: new val SFISCfg "
 140                         "ch%d: %x\n", i, sfiscfg_val));
 141 #endif
 142         }
 143 
 144         /* Now tear down the pci config setup */
 145         pci_config_teardown(&pci_conf_handle);
 146 
 147         /* Create property indicating that initialization was done */
 148         (void) ddi_prop_update_int(DDI_DEV_T_NONE, ddi_get_parent(dip),
 149                 "sil3xxx-initialized", 1);
 150 
 151         return (TRUE);
 152 }