1507c3241Smlf /*
2507c3241Smlf  * CDDL HEADER START
3507c3241Smlf  *
4507c3241Smlf  * The contents of this file are subject to the terms of the
57d0b359cSToomas Soome  * Common Development and Distribution License (the "License").
6507c3241Smlf  * You may not use this file except in compliance with the License.
7507c3241Smlf  *
8507c3241Smlf  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9507c3241Smlf  * or http://www.opensolaris.org/os/licensing.
10507c3241Smlf  * See the License for the specific language governing permissions
11507c3241Smlf  * and limitations under the License.
12507c3241Smlf  *
13507c3241Smlf  * When distributing Covered Code, include this CDDL HEADER in each
14507c3241Smlf  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15507c3241Smlf  * If applicable, add the following below this CDDL HEADER, with the
16507c3241Smlf  * fields enclosed by brackets "[]" replaced with your own identifying
17507c3241Smlf  * information: Portions Copyright [yyyy] [name of copyright owner]
18507c3241Smlf  *
19507c3241Smlf  * CDDL HEADER END
20507c3241Smlf  */
21507c3241Smlf 
22507c3241Smlf /*
23507c3241Smlf  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24507c3241Smlf  * Use is subject to license terms.
25*6e6c7d67SAndrew Stormont  *
26*6e6c7d67SAndrew Stormont  * Copyright 2018 RackTop Systems.
27507c3241Smlf  */
28507c3241Smlf /*
29507c3241Smlf  * Silicon Image 3XXX controller specific processing
30507c3241Smlf  *
31507c3241Smlf  * This file may be expanded to take advantage of Silicon Image
32507c3241Smlf  * additional features (if applicable to specific controller model):
33507c3241Smlf  * 1. Virtual DMA operation
34507c3241Smlf  * 2. Concurrent all-channel DMA
35507c3241Smlf  * 3. Large Block Transfers
36507c3241Smlf  * 4. Watchdog Timer
37507c3241Smlf  * 5. Power Management
38507c3241Smlf  * 6. Hot Plug Support
39507c3241Smlf  */
40507c3241Smlf 
41507c3241Smlf #include "ata_common.h"
42507c3241Smlf #include "sil3xxx.h"
43507c3241Smlf #include <sys/pci.h>
44507c3241Smlf 
45507c3241Smlf int fifocntctl[] = {FIFO_CNTCTL_0, FIFO_CNTCTL_1, FIFO_CNTCTL_2, FIFO_CNTCTL_3};
46507c3241Smlf int sfiscfg[] = {SFISCFG_0, SFISCFG_1, SFISCFG_2, SFISCFG_3};
47507c3241Smlf 
48507c3241Smlf /*
49507c3241Smlf  * Controller specific initialization
50507c3241Smlf  */
517d0b359cSToomas Soome /* ARGSUSED */
52507c3241Smlf uint_t
sil3xxx_init_controller(dev_info_t * dip,ushort_t vendor_id,ushort_t device_id)537d0b359cSToomas Soome sil3xxx_init_controller(dev_info_t *dip, ushort_t vendor_id, ushort_t device_id)
54507c3241Smlf {
55507c3241Smlf 	ddi_acc_handle_t  pci_conf_handle; /* pci config space handle */
56507c3241Smlf 	uint8_t cache_lnsz, frrc = 0;
57507c3241Smlf 	uint32_t fifo_cnt_ctl;
58507c3241Smlf 	int ports, i;
59507c3241Smlf 
60*6e6c7d67SAndrew Stormont #ifdef	ATA_DEBUG
617d0b359cSToomas Soome 	ushort_t sfiscfg_val __unused;
62507c3241Smlf #endif
63507c3241Smlf 
64507c3241Smlf 	/*
65507c3241Smlf 	 * Sil3114, Sil3512, Sil3112
66507c3241Smlf 	 * We want to perform this initialization only once per entire
67507c3241Smlf 	 * pciide controller (all channels)
68507c3241Smlf 	 */
69507c3241Smlf 	if (ddi_prop_exists(DDI_DEV_T_ANY, ddi_get_parent(dip),
707d0b359cSToomas Soome 	    DDI_PROP_DONTPASS, "sil3xxx-initialized")) {
71507c3241Smlf 		return (TRUE);
72507c3241Smlf 	}
73507c3241Smlf 
74507c3241Smlf 	if (pci_config_setup(ddi_get_parent(dip), &pci_conf_handle) !=
75507c3241Smlf 	    DDI_SUCCESS) {
76507c3241Smlf 		cmn_err(CE_WARN,
77507c3241Smlf 		    "sil3xxx_init_controller: Can't do pci_config_setup\n");
78507c3241Smlf 		return (FALSE);
79507c3241Smlf 	}
80507c3241Smlf 
81507c3241Smlf 	/*
82507c3241Smlf 	 * Sil3114/3512/3112 incorrectly change between MR and back to
83507c3241Smlf 	 * MRM for same transaction, which violates the PCI spec and can
84507c3241Smlf 	 * lead to incorrect data reads.  The workaround
85507c3241Smlf 	 * is to set bits 2:0 in the FIFO count and control register so
86507c3241Smlf 	 * that its value, a multiple of 32 bytes starting at 32, not 0,
87507c3241Smlf 	 * is greater or equal to the cacheline size, a multiple of 4
88507c3241Smlf 	 * bytes.  This will prevent any reads until the FIFO free space
89507c3241Smlf 	 * is greater than a cacheline size, ensuring only MRM is issued.
90507c3241Smlf 	 */
91507c3241Smlf 
92507c3241Smlf 	cache_lnsz = pci_config_get8(pci_conf_handle, PCI_CONF_CACHE_LINESZ);
93507c3241Smlf 
94507c3241Smlf 	/*
95507c3241Smlf 	 * The cache line is specified in 32-bit words, so multiply by 4
96507c3241Smlf 	 * to get bytes.  Then divide by 32 bytes, the granularity of the
97507c3241Smlf 	 * FIFO control bits 2:0.  Add 1 if there is any remainder to
98507c3241Smlf 	 * account for a partial 32-byte block, then subtract 1 since for
99507c3241Smlf 	 * FIFO controls bits 2:0, 0 corresponds to 32, 1 corresponds to
100507c3241Smlf 	 * 64, and so on.  The calculation is expanded for clarity.
101507c3241Smlf 	 */
102507c3241Smlf 	if (cache_lnsz != 0) {
103507c3241Smlf 		frrc = (cache_lnsz * 4 / 32) +
1047d0b359cSToomas Soome 		    (((cache_lnsz * 4) % 32) ? 1 : 0) - 1;
105507c3241Smlf 	}
106507c3241Smlf 
107507c3241Smlf 	if (device_id == SIL3114_DEVICE_ID) {
108507c3241Smlf 		ports = 4;
109507c3241Smlf 	} else {
110507c3241Smlf 		ports = 2;
111507c3241Smlf 	}
112507c3241Smlf 
113507c3241Smlf 	/*
114507c3241Smlf 	 * The following BAR5 registers are accessed via an indirect register
115507c3241Smlf 	 * in the PCI configuration space rather than mapping BAR5.
116507c3241Smlf 	 */
117507c3241Smlf 	for (i = 0; i < ports; i++) {
118507c3241Smlf 		GET_BAR5_INDIRECT(pci_conf_handle, fifocntctl[i],
119507c3241Smlf 		    fifo_cnt_ctl);
120507c3241Smlf 		fifo_cnt_ctl = (fifo_cnt_ctl & ~0x7) | (frrc & 0x7);
121507c3241Smlf 		PUT_BAR5_INDIRECT(pci_conf_handle, fifocntctl[i],
122507c3241Smlf 		    fifo_cnt_ctl);
123507c3241Smlf 		/*
124507c3241Smlf 		 * Correct default setting for FIS0cfg
125507c3241Smlf 		 */
126*6e6c7d67SAndrew Stormont #ifdef	ATA_DEBUG
127507c3241Smlf 		GET_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i],
1287d0b359cSToomas Soome 		    sfiscfg_val);
129507c3241Smlf 		ADBG_WARN(("sil3xxx_init_controller: old val SFISCfg "
1307d0b359cSToomas Soome 		    "ch%d: %x\n", i, sfiscfg_val));
131507c3241Smlf #endif
132507c3241Smlf 		PUT_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i],
1337d0b359cSToomas Soome 		    SFISCFG_ERRATA);
134*6e6c7d67SAndrew Stormont #ifdef	ATA_DEBUG
135507c3241Smlf 		GET_BAR5_INDIRECT(pci_conf_handle, sfiscfg[i],
1367d0b359cSToomas Soome 		    sfiscfg_val);
137507c3241Smlf 		ADBG_WARN(("sil3xxx_init_controller: new val SFISCfg "
1387d0b359cSToomas Soome 		    "ch%d: %x\n", i, sfiscfg_val));
139507c3241Smlf #endif
140507c3241Smlf 	}
141507c3241Smlf 
142507c3241Smlf 	/* Now tear down the pci config setup */
143507c3241Smlf 	pci_config_teardown(&pci_conf_handle);
144507c3241Smlf 
145507c3241Smlf 	/* Create property indicating that initialization was done */
146507c3241Smlf 	(void) ddi_prop_update_int(DDI_DEV_T_NONE, ddi_get_parent(dip),
1477d0b359cSToomas Soome 	    "sil3xxx-initialized", 1);
148507c3241Smlf 
149507c3241Smlf 	return (TRUE);
150507c3241Smlf }
151