1 | /* $ZEL: sis1100_init.c,v 1.5 2004/05/27 23:10:20 wuestner Exp $ */
|
---|
2 |
|
---|
3 | /*
|
---|
4 | * Copyright (c) 2001-2004
|
---|
5 | * Peter Wuestner. All rights reserved.
|
---|
6 | *
|
---|
7 | * Redistribution and use in source and binary forms, with or without
|
---|
8 | * modification, are permitted provided that the following conditions
|
---|
9 | * are met:
|
---|
10 | * 1. Redistributions of source code must retain the above copyright
|
---|
11 | * notice, this list of conditions, and the following disclaimer.
|
---|
12 | * 2. Redistributions in binary form must reproduce the above copyright
|
---|
13 | * notice, this list of conditions and the following disclaimer in the
|
---|
14 | * documentation and/or other materials provided with the distribution.
|
---|
15 | *
|
---|
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
|
---|
17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
---|
20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
---|
21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
---|
22 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
---|
23 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
---|
24 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
---|
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
---|
26 | * SUCH DAMAGE.
|
---|
27 | */
|
---|
28 |
|
---|
29 | #include "sis1100_sc.h"
|
---|
30 |
|
---|
31 | void
|
---|
32 | sis1100_dump_glink_status(struct sis1100_softc* sc, char* text, int locked)
|
---|
33 | {
|
---|
34 | u_int32_t v;
|
---|
35 | if (!locked) SEM_LOCK(sc->sem_hw);
|
---|
36 | pINFO(sc, "%s:", text);
|
---|
37 | pINFO(sc, " ident =%08x", sis1100readreg(sc, ident));
|
---|
38 | pINFO(sc, " sr =%08x", sis1100readreg(sc, sr));
|
---|
39 | pINFO(sc, " cr =%08x", sis1100readreg(sc, cr));
|
---|
40 | pINFO(sc, " t_hdr =%08x", sis1100readreg(sc, t_hdr));
|
---|
41 | pINFO(sc, " t_am =%08x", sis1100readreg(sc, t_am));
|
---|
42 | pINFO(sc, " t_adl =%08x", sis1100readreg(sc, t_adl));
|
---|
43 | pINFO(sc, " t_dal =%08x", sis1100readreg(sc, t_dal));
|
---|
44 | pINFO(sc, " tc_hdr =%08x", sis1100readreg(sc, tc_hdr));
|
---|
45 | pINFO(sc, " tc_dal =%08x", sis1100readreg(sc, tc_dal));
|
---|
46 | pINFO(sc, " p_balance =%08x", sis1100readreg(sc, p_balance));
|
---|
47 | pINFO(sc, " prot_error =%08x", sis1100readreg(sc, prot_error));
|
---|
48 | pINFO(sc, " d0_bc =%08x", sis1100readreg(sc, d0_bc));
|
---|
49 | pINFO(sc, " d0_bc_buf =%08x", sis1100readreg(sc, d0_bc_buf));
|
---|
50 | pINFO(sc, " d0_bc_blen =%08x", sis1100readreg(sc, d0_bc_blen));
|
---|
51 | pINFO(sc, " d_hdr =%08x", sis1100readreg(sc, d_hdr));
|
---|
52 | pINFO(sc, " d_am =%08x", sis1100readreg(sc, d_am));
|
---|
53 | pINFO(sc, " d_adl =%08x", sis1100readreg(sc, d_adl));
|
---|
54 | pINFO(sc, " d_bc =%08x", sis1100readreg(sc, d_bc));
|
---|
55 | pINFO(sc, " rd_pipe_buf =%08x", sis1100readreg(sc, rd_pipe_buf));
|
---|
56 | pINFO(sc, " rd_pipe_blen=%08x", sis1100readreg(sc, rd_pipe_blen));
|
---|
57 | pINFO(sc, "");
|
---|
58 | v=sis1100readreg(sc, opt_csr);
|
---|
59 | pINFO(sc, " opt_csr =%08x", v);
|
---|
60 | sis1100writereg(sc, opt_csr, v&0xc0f50000);
|
---|
61 | pINFO(sc, " opt_csr =%08x", sis1100readreg(sc, opt_csr));
|
---|
62 | if (!locked) SEM_UNLOCK(sc->sem_hw);
|
---|
63 | }
|
---|
64 |
|
---|
65 | int
|
---|
66 | sis1100_flush_fifo(struct sis1100_softc* sc, const char* text, int silent)
|
---|
67 | {
|
---|
68 | u_int32_t sr, special, data;
|
---|
69 | int count=0;
|
---|
70 |
|
---|
71 | sis1100writereg(sc, cr, cr_transparent);
|
---|
72 | mb_reg();
|
---|
73 | sr=sis1100readreg(sc, sr);
|
---|
74 | while (sr&(sr_tp_special|sr_tp_data)) {
|
---|
75 | while (sr&sr_tp_data) {
|
---|
76 | data=sis1100readreg(sc, tp_data);
|
---|
77 | if (!silent) pINFO(sc, "data = 0x%08x\n", data);
|
---|
78 | sr=sis1100readreg(sc, sr);
|
---|
79 | count++;
|
---|
80 | if (count>100) {
|
---|
81 | sis1100writereg(sc, cr, cr_transparent<<16);
|
---|
82 | pINFO(sc, "too many data in fifo; giving up");
|
---|
83 | return -1;
|
---|
84 | }
|
---|
85 | }
|
---|
86 | while ((sr&(sr_tp_special|sr_tp_data))==sr_tp_special) {
|
---|
87 | special=sis1100readreg(sc, tp_special);
|
---|
88 | if (!silent) pINFO(sc, "special=0x%08x\n", special);
|
---|
89 | sr=sis1100readreg(sc, sr);
|
---|
90 | count++;
|
---|
91 | if (count>100) {
|
---|
92 | sis1100writereg(sc, cr, cr_transparent<<16);
|
---|
93 | pINFO(sc, "too many data in fifo; giving up");
|
---|
94 | return -1;
|
---|
95 | }
|
---|
96 | }
|
---|
97 | if ((!silent) && (count>100)) {
|
---|
98 | pINFO(sc, "too many data in fifo; switching to 'silent'");
|
---|
99 | silent=1;
|
---|
100 | }
|
---|
101 | if (count>10000) {
|
---|
102 | sis1100writereg(sc, cr, cr_transparent<<16);
|
---|
103 | pINFO(sc, "too many data in fifo; giving up");
|
---|
104 | return -1;
|
---|
105 | }
|
---|
106 | }
|
---|
107 | sis1100writereg(sc, cr, cr_transparent<<16);
|
---|
108 | if (count && silent)
|
---|
109 | pINFO(sc, "flushed %d words from fifo", count);
|
---|
110 | return 0;
|
---|
111 | }
|
---|
112 |
|
---|
113 | static void
|
---|
114 | sis1100_set_swapping(struct sis1100_softc* sc, int swap)
|
---|
115 | {
|
---|
116 | u_int32_t tmp;
|
---|
117 |
|
---|
118 | /*pINFO(sc, "set swap to %d", swap);*/
|
---|
119 | tmp=plxreadreg(sc, BIGEND_LMISC_PROT_AREA);
|
---|
120 | if (swap) {
|
---|
121 | sis1100writereg(sc, cr, 0x8);
|
---|
122 | plxwritereg(sc, BIGEND_LMISC_PROT_AREA, tmp|(3<<6));
|
---|
123 | } else {
|
---|
124 | sis1100writereg(sc, cr, 0x80000);
|
---|
125 | plxwritereg(sc, BIGEND_LMISC_PROT_AREA, tmp&~(3<<6));
|
---|
126 | }
|
---|
127 | }
|
---|
128 |
|
---|
129 | void
|
---|
130 | sis1100_update_swapping(struct sis1100_softc* sc, const char* caller)
|
---|
131 | {
|
---|
132 | int swap;
|
---|
133 | #if defined(__LITTLE_ENDIAN)
|
---|
134 | int local_endian=0;
|
---|
135 | #elif defined(__BIG_ENDIAN)
|
---|
136 | int local_endian=1;
|
---|
137 | #else
|
---|
138 | # error UNKNOWN ENDIAN
|
---|
139 | #endif
|
---|
140 |
|
---|
141 | /*
|
---|
142 | pINFO(sc, "local endian is %s; remote endian is %s; user swap is %d "
|
---|
143 | "(called from %s)",
|
---|
144 | local_endian?"big":"little",
|
---|
145 | sc->remote_endian?"big":"little",
|
---|
146 | sc->user_wants_swap,
|
---|
147 | caller);
|
---|
148 | */
|
---|
149 |
|
---|
150 | swap=0;
|
---|
151 | if (local_endian) swap=!swap;
|
---|
152 | if (sc->remote_endian) swap=!swap;
|
---|
153 | if (sc->user_wants_swap) swap=!swap;
|
---|
154 | sis1100_set_swapping(sc, swap);
|
---|
155 | }
|
---|
156 |
|
---|
157 | int
|
---|
158 | sis1100_init(struct sis1100_softc* sc)
|
---|
159 | {
|
---|
160 | #define MIN_FV 5
|
---|
161 | #define MAX_FV 7
|
---|
162 |
|
---|
163 | u_int32_t typ, hv, fk, fv;
|
---|
164 | int res, i;
|
---|
165 |
|
---|
166 | sc->local_ident=sis1100readreg(sc, ident);
|
---|
167 | typ=sc->local_ident&0xff;
|
---|
168 | hv=(sc->local_ident>>8)&0xff;
|
---|
169 | fk=(sc->local_ident>>16)&0xff;
|
---|
170 | fv=(sc->local_ident>>24)&0xff;
|
---|
171 |
|
---|
172 | if (typ!=1) {
|
---|
173 | pERROR(sc, "ident=08x%x; claims not to be a PCI Device", typ);
|
---|
174 | res=ENXIO;
|
---|
175 | goto raus;
|
---|
176 | }
|
---|
177 | pINFO(sc, "HW version %d; FW code %d; FW version %d", hv, fk, fv);
|
---|
178 | /*pINFO(sc, "LAS1RR=0x%08x LAS1BA=0x%08x LBRD1=0x%08x\n",
|
---|
179 | plxreadreg(sc, LAS1RR), plxreadreg(sc, LAS1BA),
|
---|
180 | plxreadreg(sc, LBRD1));*/
|
---|
181 | switch (sc->local_ident&0xffff00) { /* HW version and FW code */
|
---|
182 | case 0x010100: {
|
---|
183 | if (fv<MIN_FV) {
|
---|
184 | pERROR(sc, "Firmware version too old;"
|
---|
185 | " at least version %d is required.",
|
---|
186 | MIN_FV);
|
---|
187 | res=ENXIO;
|
---|
188 | goto raus;
|
---|
189 | }
|
---|
190 | if (fv>MAX_FV)
|
---|
191 | pINFO(sc, "Driver not tested with"
|
---|
192 | " firmware versions greater than %d.",
|
---|
193 | MAX_FV);
|
---|
194 | if (sc->reg_size!=0x1000) {
|
---|
195 | pERROR(sc, "wrong size of space 0: 0x%lx instead of 0x1000",
|
---|
196 | (unsigned long)sc->reg_size);
|
---|
197 | res=ENXIO;
|
---|
198 | goto raus;
|
---|
199 | }
|
---|
200 | pINFO(sc, "size of space 1: 0x%lx (%ld MByte)",
|
---|
201 | (u_long)sc->rem_size, (u_long)sc->rem_size>>20);
|
---|
202 | } break;
|
---|
203 | default:
|
---|
204 | pERROR(sc, "Hard- or Firmware not known");
|
---|
205 | res=ENXIO;
|
---|
206 | goto raus;
|
---|
207 | }
|
---|
208 |
|
---|
209 | /* reset all we can */
|
---|
210 | sis1100writereg(sc, cr, cr_reset); /* master reset */
|
---|
211 | sis1100writereg(sc, cr, cr_rem_reset); /* reset remote, ignore wether it exists */
|
---|
212 | if (sis1100_flush_fifo(sc, "init", 0)) { /* clear local fifo */
|
---|
213 | res=EIO;
|
---|
214 | goto raus;
|
---|
215 | }
|
---|
216 | sis1100writereg(sc, cr, cr_reset); /* master reset again */
|
---|
217 | sis1100_reset_plx(sc); /* reset PLX */
|
---|
218 | sis1100writereg(sc, p_balance, 0);
|
---|
219 | sis1100readreg(sc, prot_error);
|
---|
220 |
|
---|
221 | /* sis1100_dump_glink_status(sc, "INITIAL DUMP"); */
|
---|
222 |
|
---|
223 | /* enable PCI Initiator-to-PCI Memory */
|
---|
224 | plxwritereg(sc, DMRR, 0);
|
---|
225 | plxwritereg(sc, DMLBAM, 0);
|
---|
226 | plxwritereg(sc, DMPBAM, 1);
|
---|
227 |
|
---|
228 | sis1100writereg(sc, cr, 8); /* big endian */
|
---|
229 |
|
---|
230 | sc->got_irqs=0;
|
---|
231 | for (i=0; i<=7; i++) sc->irq_vects[i].valid=0;
|
---|
232 | sc->pending_irqs=0;
|
---|
233 | sc->doorbell=0;
|
---|
234 | sc->lemo_status=0;
|
---|
235 |
|
---|
236 | /* enable IRQs */
|
---|
237 | sis1100_disable_irq(sc, 0xffffffff, 0xffffffff);
|
---|
238 | sis1100_enable_irq(sc, plxirq_pci|plxirq_mbox|plxirq_doorbell|plxirq_local,
|
---|
239 | irq_synch_chg|irq_inh_chg|irq_sema_chg|
|
---|
240 | irq_rec_violation|irq_reset_req);
|
---|
241 |
|
---|
242 | sc->user_wants_swap=0;
|
---|
243 | sc->dsp_present=0;
|
---|
244 | sc->ram_size=0;
|
---|
245 | sc->remote_ident=0;
|
---|
246 | sc->old_remote_hw=sis1100_hw_invalid;
|
---|
247 | sc->remote_hw=sis1100_hw_invalid;
|
---|
248 | sc->remote_endian=1;
|
---|
249 |
|
---|
250 | if ((sis1100readreg(sc, sr)&sr_synch)==sr_synch) {
|
---|
251 | sis1100_init_remote(sc);
|
---|
252 | } else {
|
---|
253 | pINFO(sc, "init: remote interface not reachable");
|
---|
254 | }
|
---|
255 | res=0;
|
---|
256 |
|
---|
257 | raus:
|
---|
258 | return res;
|
---|
259 | #undef MIN_FV
|
---|
260 | #undef MAX_FV
|
---|
261 | }
|
---|
262 |
|
---|
263 | void
|
---|
264 | sis1100_done(struct sis1100_softc* sc)
|
---|
265 | {
|
---|
266 | /* DMA Ch. 0/1: not enabled */
|
---|
267 | plxwritereg(sc, DMACSR0_DMACSR1, 0);
|
---|
268 | /* disable interrupts */
|
---|
269 | plxwritereg(sc, INTCSR, 0);
|
---|
270 | }
|
---|