Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/char/mwave/3780i.c
49259 views
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
67
static void PaceMsaAccess(unsigned short usDspBaseIO)
68
{
69
cond_resched();
70
udelay(100);
71
cond_resched();
72
}
73
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
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
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
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
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
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
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
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
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
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
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
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
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
538