xref: /linux/drivers/char/mwave/3780i.c (revision 83bd89291f5cc866f60d32c34e268896c7ba8a3d)
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