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 } 153