1 /*
2 *
3 * 3780i.c -- helper routines for the 3780i DSP
4 *
5 *
6 * Written By: Mike Sullivan IBM Corporation
7 *
8 * Copyright (C) 1999 IBM Corporation
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * NO WARRANTY
21 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
22 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
23 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
24 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
25 * solely responsible for determining the appropriateness of using and
26 * distributing the Program and assumes all risks associated with its
27 * exercise of rights under this Agreement, including but not limited to
28 * the risks and costs of program errors, damage to or loss of data,
29 * programs or equipment, and unavailability or interruption of operations.
30 *
31 * DISCLAIMER OF LIABILITY
32 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
33 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
35 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
38 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
39 *
40 * You should have received a copy of the GNU General Public License
41 * along with this program; if not, write to the Free Software
42 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43 *
44 *
45 * 10/23/2000 - Alpha Release
46 * First release to the public
47 */
48
49 #define pr_fmt(fmt) "3780i: " fmt
50
51 #include <linux/kernel.h>
52 #include <linux/unistd.h>
53 #include <linux/delay.h>
54 #include <linux/ioport.h>
55 #include <linux/bitops.h>
56 #include <linux/sched.h> /* cond_resched() */
57
58 #include <asm/io.h>
59 #include <linux/uaccess.h>
60 #include <asm/irq.h>
61 #include "smapi.h"
62 #include "mwavedd.h"
63 #include "3780i.h"
64
65 static DEFINE_SPINLOCK(dsp_lock);
66
PaceMsaAccess(unsigned short usDspBaseIO)67 static void PaceMsaAccess(unsigned short usDspBaseIO)
68 {
69 cond_resched();
70 udelay(100);
71 cond_resched();
72 }
73
dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,unsigned long ulMsaAddr)74 unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
75 unsigned long ulMsaAddr)
76 {
77 unsigned long flags;
78 unsigned short val;
79
80 spin_lock_irqsave(&dsp_lock, flags);
81 OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulMsaAddr);
82 OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulMsaAddr >> 16));
83 val = InWordDsp(DSP_MsaDataDSISHigh);
84 spin_unlock_irqrestore(&dsp_lock, flags);
85
86 return val;
87 }
88
dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,unsigned long ulMsaAddr,unsigned short usValue)89 void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
90 unsigned long ulMsaAddr, unsigned short usValue)
91 {
92 unsigned long flags;
93
94 spin_lock_irqsave(&dsp_lock, flags);
95 OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulMsaAddr);
96 OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulMsaAddr >> 16));
97 OutWordDsp(DSP_MsaDataDSISHigh, usValue);
98 spin_unlock_irqrestore(&dsp_lock, flags);
99 }
100
dsp3780I_WriteGenCfg(unsigned short usDspBaseIO,unsigned uIndex,unsigned char ucValue)101 static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
102 unsigned char ucValue)
103 {
104 DSP_ISA_SLAVE_CONTROL rSlaveControl;
105 DSP_ISA_SLAVE_CONTROL rSlaveControl_Save;
106
107 MKBYTE(rSlaveControl) = InByteDsp(DSP_IsaSlaveControl);
108
109 rSlaveControl_Save = rSlaveControl;
110 rSlaveControl.ConfigMode = true;
111
112 OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl));
113 OutByteDsp(DSP_ConfigAddress, (unsigned char) uIndex);
114 OutByteDsp(DSP_ConfigData, ucValue);
115 OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl_Save));
116 }
117
dsp3780I_EnableDSP(struct dsp_3780i_config_settings * pSettings,unsigned short * pIrqMap,unsigned short * pDmaMap)118 int dsp3780I_EnableDSP(struct dsp_3780i_config_settings *pSettings,
119 unsigned short *pIrqMap,
120 unsigned short *pDmaMap)
121 {
122 unsigned long flags;
123 unsigned short usDspBaseIO = pSettings->usDspBaseIO;
124 int i;
125 DSP_UART_CFG_1 rUartCfg1;
126 DSP_UART_CFG_2 rUartCfg2;
127 DSP_HBRIDGE_CFG_1 rHBridgeCfg1;
128 DSP_HBRIDGE_CFG_2 rHBridgeCfg2;
129 DSP_BUSMASTER_CFG_1 rBusmasterCfg1;
130 DSP_BUSMASTER_CFG_2 rBusmasterCfg2;
131 DSP_ISA_PROT_CFG rIsaProtCfg;
132 DSP_POWER_MGMT_CFG rPowerMgmtCfg;
133 DSP_HBUS_TIMER_CFG rHBusTimerCfg;
134 DSP_LBUS_TIMEOUT_DISABLE rLBusTimeoutDisable;
135 DSP_CHIP_RESET rChipReset;
136 DSP_CLOCK_CONTROL_1 rClockControl1;
137 DSP_CLOCK_CONTROL_2 rClockControl2;
138 DSP_ISA_SLAVE_CONTROL rSlaveControl;
139 DSP_HBRIDGE_CONTROL rHBridgeControl;
140 unsigned short tval;
141
142 if (!pSettings->bDSPEnabled) {
143 pr_err("%s: Error: DSP not enabled. Aborting.\n", __func__);
144 return -EIO;
145 }
146
147 if (pSettings->bModemEnabled) {
148 rUartCfg1.Reserved = rUartCfg2.Reserved = 0;
149 rUartCfg1.IrqActiveLow = pSettings->bUartIrqActiveLow;
150 rUartCfg1.IrqPulse = pSettings->bUartIrqPulse;
151 rUartCfg1.Irq =
152 (unsigned char) pIrqMap[pSettings->usUartIrq];
153 switch (pSettings->usUartBaseIO) {
154 case 0x03F8:
155 rUartCfg1.BaseIO = 0;
156 break;
157 case 0x02F8:
158 rUartCfg1.BaseIO = 1;
159 break;
160 case 0x03E8:
161 rUartCfg1.BaseIO = 2;
162 break;
163 case 0x02E8:
164 rUartCfg1.BaseIO = 3;
165 break;
166 }
167 rUartCfg2.Enable = true;
168 }
169
170 rHBridgeCfg1.Reserved = rHBridgeCfg2.Reserved = 0;
171 rHBridgeCfg1.IrqActiveLow = pSettings->bDspIrqActiveLow;
172 rHBridgeCfg1.IrqPulse = pSettings->bDspIrqPulse;
173 rHBridgeCfg1.Irq = (unsigned char) pIrqMap[pSettings->usDspIrq];
174 rHBridgeCfg1.AccessMode = 1;
175 rHBridgeCfg2.Enable = true;
176
177
178 rBusmasterCfg2.Reserved = 0;
179 rBusmasterCfg1.Dma = (unsigned char) pDmaMap[pSettings->usDspDma];
180 rBusmasterCfg1.NumTransfers =
181 (unsigned char) pSettings->usNumTransfers;
182 rBusmasterCfg1.ReRequest = (unsigned char) pSettings->usReRequest;
183 rBusmasterCfg1.MEMCS16 = pSettings->bEnableMEMCS16;
184 rBusmasterCfg2.IsaMemCmdWidth =
185 (unsigned char) pSettings->usIsaMemCmdWidth;
186
187
188 rIsaProtCfg.Reserved = 0;
189 rIsaProtCfg.GateIOCHRDY = pSettings->bGateIOCHRDY;
190
191 rPowerMgmtCfg.Reserved = 0;
192 rPowerMgmtCfg.Enable = pSettings->bEnablePwrMgmt;
193
194 rHBusTimerCfg.LoadValue =
195 (unsigned char) pSettings->usHBusTimerLoadValue;
196
197 rLBusTimeoutDisable.Reserved = 0;
198 rLBusTimeoutDisable.DisableTimeout =
199 pSettings->bDisableLBusTimeout;
200
201 MKWORD(rChipReset) = ~pSettings->usChipletEnable;
202
203 rClockControl1.Reserved1 = rClockControl1.Reserved2 = 0;
204 rClockControl1.N_Divisor = pSettings->usN_Divisor;
205 rClockControl1.M_Multiplier = pSettings->usM_Multiplier;
206
207 rClockControl2.Reserved = 0;
208 rClockControl2.PllBypass = pSettings->bPllBypass;
209
210 /* Issue a soft reset to the chip */
211 /* Note: Since we may be coming in with 3780i clocks suspended, we must keep
212 * soft-reset active for 10ms.
213 */
214 rSlaveControl.ClockControl = 0;
215 rSlaveControl.SoftReset = true;
216 rSlaveControl.ConfigMode = false;
217 rSlaveControl.Reserved = 0;
218
219 spin_lock_irqsave(&dsp_lock, flags);
220 OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
221 MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl);
222
223 for (i = 0; i < 11; i++)
224 udelay(2000);
225
226 rSlaveControl.SoftReset = false;
227 OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
228
229 MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl);
230
231 /* Program our general configuration registers */
232 WriteGenCfg(DSP_HBridgeCfg1Index, MKBYTE(rHBridgeCfg1));
233 WriteGenCfg(DSP_HBridgeCfg2Index, MKBYTE(rHBridgeCfg2));
234 WriteGenCfg(DSP_BusMasterCfg1Index, MKBYTE(rBusmasterCfg1));
235 WriteGenCfg(DSP_BusMasterCfg2Index, MKBYTE(rBusmasterCfg2));
236 WriteGenCfg(DSP_IsaProtCfgIndex, MKBYTE(rIsaProtCfg));
237 WriteGenCfg(DSP_PowerMgCfgIndex, MKBYTE(rPowerMgmtCfg));
238 WriteGenCfg(DSP_HBusTimerCfgIndex, MKBYTE(rHBusTimerCfg));
239
240 if (pSettings->bModemEnabled) {
241 WriteGenCfg(DSP_UartCfg1Index, MKBYTE(rUartCfg1));
242 WriteGenCfg(DSP_UartCfg2Index, MKBYTE(rUartCfg2));
243 }
244
245
246 rHBridgeControl.EnableDspInt = false;
247 rHBridgeControl.MemAutoInc = true;
248 rHBridgeControl.IoAutoInc = false;
249 rHBridgeControl.DiagnosticMode = false;
250
251 OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
252 spin_unlock_irqrestore(&dsp_lock, flags);
253 WriteMsaCfg(DSP_LBusTimeoutDisable, MKWORD(rLBusTimeoutDisable));
254 WriteMsaCfg(DSP_ClockControl_1, MKWORD(rClockControl1));
255 WriteMsaCfg(DSP_ClockControl_2, MKWORD(rClockControl2));
256 WriteMsaCfg(DSP_ChipReset, MKWORD(rChipReset));
257
258 ReadMsaCfg(DSP_ChipID);
259
260 return 0;
261 }
262
dsp3780I_DisableDSP(struct dsp_3780i_config_settings * pSettings)263 int dsp3780I_DisableDSP(struct dsp_3780i_config_settings *pSettings)
264 {
265 unsigned long flags;
266 unsigned short usDspBaseIO = pSettings->usDspBaseIO;
267 DSP_ISA_SLAVE_CONTROL rSlaveControl;
268
269 rSlaveControl.ClockControl = 0;
270 rSlaveControl.SoftReset = true;
271 rSlaveControl.ConfigMode = false;
272 rSlaveControl.Reserved = 0;
273 spin_lock_irqsave(&dsp_lock, flags);
274 OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
275
276 udelay(5);
277
278 rSlaveControl.ClockControl = 1;
279 OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
280 spin_unlock_irqrestore(&dsp_lock, flags);
281
282 udelay(5);
283
284 return 0;
285 }
286
dsp3780I_Reset(struct dsp_3780i_config_settings * pSettings)287 int dsp3780I_Reset(struct dsp_3780i_config_settings *pSettings)
288 {
289 unsigned long flags;
290 unsigned short usDspBaseIO = pSettings->usDspBaseIO;
291 DSP_BOOT_DOMAIN rBootDomain;
292 DSP_HBRIDGE_CONTROL rHBridgeControl;
293
294 spin_lock_irqsave(&dsp_lock, flags);
295 /* Mask DSP to PC interrupt */
296 MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
297
298 rHBridgeControl.EnableDspInt = false;
299 OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
300 spin_unlock_irqrestore(&dsp_lock, flags);
301
302 /* Reset the core via the boot domain register */
303 rBootDomain.ResetCore = true;
304 rBootDomain.Halt = true;
305 rBootDomain.NMI = true;
306 rBootDomain.Reserved = 0;
307
308 WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
309
310 /* Reset all the chiplets and then reactivate them */
311 WriteMsaCfg(DSP_ChipReset, 0xFFFF);
312 udelay(5);
313 WriteMsaCfg(DSP_ChipReset,
314 (unsigned short) (~pSettings->usChipletEnable));
315
316 return 0;
317 }
318
319
dsp3780I_Run(struct dsp_3780i_config_settings * pSettings)320 int dsp3780I_Run(struct dsp_3780i_config_settings *pSettings)
321 {
322 unsigned long flags;
323 unsigned short usDspBaseIO = pSettings->usDspBaseIO;
324 DSP_BOOT_DOMAIN rBootDomain;
325 DSP_HBRIDGE_CONTROL rHBridgeControl;
326
327 /* Transition the core to a running state */
328 rBootDomain.ResetCore = true;
329 rBootDomain.Halt = false;
330 rBootDomain.NMI = true;
331 rBootDomain.Reserved = 0;
332 WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
333
334 udelay(5);
335
336 rBootDomain.ResetCore = false;
337 WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
338 udelay(5);
339
340 rBootDomain.NMI = false;
341 WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
342 udelay(5);
343
344 /* Enable DSP to PC interrupt */
345 spin_lock_irqsave(&dsp_lock, flags);
346 MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
347 rHBridgeControl.EnableDspInt = true;
348
349 OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
350 spin_unlock_irqrestore(&dsp_lock, flags);
351
352 return 0;
353 }
354
355
dsp3780I_ReadDStore(unsigned short usDspBaseIO,void __user * pvBuffer,unsigned uCount,unsigned long ulDSPAddr)356 int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
357 unsigned uCount, unsigned long ulDSPAddr)
358 {
359 unsigned long flags;
360 unsigned short __user *pusBuffer = pvBuffer;
361 unsigned short val;
362
363 /* Set the initial MSA address. No adjustments need to be made to data store addresses */
364 spin_lock_irqsave(&dsp_lock, flags);
365 OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
366 OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
367 spin_unlock_irqrestore(&dsp_lock, flags);
368
369 /* Transfer the memory block */
370 while (uCount-- != 0) {
371 spin_lock_irqsave(&dsp_lock, flags);
372 val = InWordDsp(DSP_MsaDataDSISHigh);
373 spin_unlock_irqrestore(&dsp_lock, flags);
374 if(put_user(val, pusBuffer++))
375 return -EFAULT;
376
377 PaceMsaAccess(usDspBaseIO);
378 }
379
380 return 0;
381 }
382
dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,void __user * pvBuffer,unsigned uCount,unsigned long ulDSPAddr)383 int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
384 void __user *pvBuffer, unsigned uCount,
385 unsigned long ulDSPAddr)
386 {
387 unsigned long flags;
388 unsigned short __user *pusBuffer = pvBuffer;
389 unsigned short val;
390
391 /* Set the initial MSA address. No adjustments need to be made to data store addresses */
392 spin_lock_irqsave(&dsp_lock, flags);
393 OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
394 OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
395 spin_unlock_irqrestore(&dsp_lock, flags);
396
397 /* Transfer the memory block */
398 while (uCount-- != 0) {
399 spin_lock_irqsave(&dsp_lock, flags);
400 val = InWordDsp(DSP_ReadAndClear);
401 spin_unlock_irqrestore(&dsp_lock, flags);
402 if(put_user(val, pusBuffer++))
403 return -EFAULT;
404
405 PaceMsaAccess(usDspBaseIO);
406 }
407
408 return 0;
409 }
410
411
dsp3780I_WriteDStore(unsigned short usDspBaseIO,void __user * pvBuffer,unsigned uCount,unsigned long ulDSPAddr)412 int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
413 unsigned uCount, unsigned long ulDSPAddr)
414 {
415 unsigned long flags;
416 unsigned short __user *pusBuffer = pvBuffer;
417
418 /* Set the initial MSA address. No adjustments need to be made to data store addresses */
419 spin_lock_irqsave(&dsp_lock, flags);
420 OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
421 OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
422 spin_unlock_irqrestore(&dsp_lock, flags);
423
424 /* Transfer the memory block */
425 while (uCount-- != 0) {
426 unsigned short val;
427 if(get_user(val, pusBuffer++))
428 return -EFAULT;
429 spin_lock_irqsave(&dsp_lock, flags);
430 OutWordDsp(DSP_MsaDataDSISHigh, val);
431 spin_unlock_irqrestore(&dsp_lock, flags);
432
433 PaceMsaAccess(usDspBaseIO);
434 }
435
436 return 0;
437 }
438
439
dsp3780I_ReadIStore(unsigned short usDspBaseIO,void __user * pvBuffer,unsigned uCount,unsigned long ulDSPAddr)440 int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
441 unsigned uCount, unsigned long ulDSPAddr)
442 {
443 unsigned long flags;
444 unsigned short __user *pusBuffer = pvBuffer;
445
446 /*
447 * Set the initial MSA address. To convert from an instruction store
448 * address to an MSA address
449 * shift the address two bits to the left and set bit 22
450 */
451 ulDSPAddr = (ulDSPAddr << 2) | (1 << 22);
452 spin_lock_irqsave(&dsp_lock, flags);
453 OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
454 OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
455 spin_unlock_irqrestore(&dsp_lock, flags);
456
457 /* Transfer the memory block */
458 while (uCount-- != 0) {
459 unsigned short val_lo, val_hi;
460 spin_lock_irqsave(&dsp_lock, flags);
461 val_lo = InWordDsp(DSP_MsaDataISLow);
462 val_hi = InWordDsp(DSP_MsaDataDSISHigh);
463 spin_unlock_irqrestore(&dsp_lock, flags);
464 if(put_user(val_lo, pusBuffer++))
465 return -EFAULT;
466 if(put_user(val_hi, pusBuffer++))
467 return -EFAULT;
468
469 PaceMsaAccess(usDspBaseIO);
470
471 }
472
473 return 0;
474 }
475
476
dsp3780I_WriteIStore(unsigned short usDspBaseIO,void __user * pvBuffer,unsigned uCount,unsigned long ulDSPAddr)477 int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
478 unsigned uCount, unsigned long ulDSPAddr)
479 {
480 unsigned long flags;
481 unsigned short __user *pusBuffer = pvBuffer;
482
483 /*
484 * Set the initial MSA address. To convert from an instruction store
485 * address to an MSA address
486 * shift the address two bits to the left and set bit 22
487 */
488 ulDSPAddr = (ulDSPAddr << 2) | (1 << 22);
489 spin_lock_irqsave(&dsp_lock, flags);
490 OutWordDsp(DSP_MsaAddrLow, (unsigned short) ulDSPAddr);
491 OutWordDsp(DSP_MsaAddrHigh, (unsigned short) (ulDSPAddr >> 16));
492 spin_unlock_irqrestore(&dsp_lock, flags);
493
494 /* Transfer the memory block */
495 while (uCount-- != 0) {
496 unsigned short val_lo, val_hi;
497 if(get_user(val_lo, pusBuffer++))
498 return -EFAULT;
499 if(get_user(val_hi, pusBuffer++))
500 return -EFAULT;
501 spin_lock_irqsave(&dsp_lock, flags);
502 OutWordDsp(DSP_MsaDataISLow, val_lo);
503 OutWordDsp(DSP_MsaDataDSISHigh, val_hi);
504 spin_unlock_irqrestore(&dsp_lock, flags);
505
506 PaceMsaAccess(usDspBaseIO);
507 }
508
509 return 0;
510 }
511
512
dsp3780I_GetIPCSource(unsigned short usDspBaseIO,unsigned short * pusIPCSource)513 int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
514 unsigned short *pusIPCSource)
515 {
516 unsigned long flags;
517 DSP_HBRIDGE_CONTROL rHBridgeControl;
518
519 /*
520 * Disable DSP to PC interrupts, read the interrupt register,
521 * clear the pending IPC bits, and reenable DSP to PC interrupts
522 */
523 spin_lock_irqsave(&dsp_lock, flags);
524 MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
525 rHBridgeControl.EnableDspInt = false;
526 OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
527
528 *pusIPCSource = InWordDsp(DSP_Interrupt);
529 OutWordDsp(DSP_Interrupt, (unsigned short) ~(*pusIPCSource));
530
531 rHBridgeControl.EnableDspInt = true;
532 OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
533 spin_unlock_irqrestore(&dsp_lock, flags);
534
535 return 0;
536 }
537