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