File Index
Files and directories
Sign in
FILE

3780i.c

File preview with syntax highlighting.

linux-6.19.14/drivers/char/mwave/3780i.c C
  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
 65static DEFINE_SPINLOCK(dsp_lock);
 66
 67static void PaceMsaAccess(unsigned short usDspBaseIO)
 68{
 69	cond_resched();
 70	udelay(100);
 71	cond_resched();
 72}
 73
 74unsigned 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
 89void 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
101static 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
118int 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
263int 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
287int 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
320int 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
356int 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
383int 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
412int 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
440int 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
477int 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
513int 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}
~/ Read-only file preview.