forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dbri.c
2690 lines (2294 loc) · 77.9 KB
/
dbri.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for DBRI sound chip found on Sparcs.
* Copyright (C) 2004, 2005 Martin Habets ([email protected])
*
* Converted to ring buffered version by Krzysztof Helt ([email protected])
*
* Based entirely upon drivers/sbus/audio/dbri.c which is:
* Copyright (C) 1997 Rudolf Koenig ([email protected])
* Copyright (C) 1998, 1999 Brent Baccala ([email protected])
*
* This is the low level driver for the DBRI & MMCODEC duo used for ISDN & AUDIO
* on Sun SPARCStation 10, 20, LX and Voyager models.
*
* - DBRI: AT&T T5900FX Dual Basic Rates ISDN Interface. It is a 32 channel
* data time multiplexer with ISDN support (aka T7259)
* Interfaces: SBus,ISDN NT & TE, CHI, 4 bits parallel.
* CHI: (spelled ki) Concentration Highway Interface (AT&T or Intel bus ?).
* Documentation:
* - "STP 4000SBus Dual Basic Rate ISDN (DBRI) Transceiver" from
* Sparc Technology Business (courtesy of Sun Support)
* - Data sheet of the T7903, a newer but very similar ISA bus equivalent
* available from the Lucent (formerly AT&T microelectronics) home
* page.
* - https://www.freesoft.org/Linux/DBRI/
* - MMCODEC: Crystal Semiconductor CS4215 16 bit Multimedia Audio Codec
* Interfaces: CHI, Audio In & Out, 2 bits parallel
* Documentation: from the Crystal Semiconductor home page.
*
* The DBRI is a 32 pipe machine, each pipe can transfer some bits between
* memory and a serial device (long pipes, no. 0-15) or between two serial
* devices (short pipes, no. 16-31), or simply send a fixed data to a serial
* device (short pipes).
* A timeslot defines the bit-offset and no. of bits read from a serial device.
* The timeslots are linked to 6 circular lists, one for each direction for
* each serial device (NT,TE,CHI). A timeslot is associated to 1 or 2 pipes
* (the second one is a monitor/tee pipe, valid only for serial input).
*
* The mmcodec is connected via the CHI bus and needs the data & some
* parameters (volume, output selection) time multiplexed in 8 byte
* chunks. It also has a control mode, which serves for audio format setting.
*
* Looking at the CS4215 data sheet it is easy to set up 2 or 4 codecs on
* the same CHI bus, so I thought perhaps it is possible to use the on-board
* & the speakerbox codec simultaneously, giving 2 (not very independent :-)
* audio devices. But the SUN HW group decided against it, at least on my
* LX the speakerbox connector has at least 1 pin missing and 1 wrongly
* connected.
*
* I've tried to stick to the following function naming conventions:
* snd_* ALSA stuff
* cs4215_* CS4215 codec specific stuff
* dbri_* DBRI high-level stuff
* other DBRI low-level stuff
*/
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/io.h>
#include <linux/dma-mapping.h>
#include <linux/gfp.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/info.h>
#include <sound/control.h>
#include <sound/initval.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/atomic.h>
#include <linux/module.h>
MODULE_AUTHOR("Rudolf Koenig, Brent Baccala and Martin Habets");
MODULE_DESCRIPTION("Sun DBRI");
MODULE_LICENSE("GPL");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
/* Enable this card */
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
module_param_array(index, int, NULL, 0444);
MODULE_PARM_DESC(index, "Index value for Sun DBRI soundcard.");
module_param_array(id, charp, NULL, 0444);
MODULE_PARM_DESC(id, "ID string for Sun DBRI soundcard.");
module_param_array(enable, bool, NULL, 0444);
MODULE_PARM_DESC(enable, "Enable Sun DBRI soundcard.");
#undef DBRI_DEBUG
#define D_INT (1<<0)
#define D_GEN (1<<1)
#define D_CMD (1<<2)
#define D_MM (1<<3)
#define D_USR (1<<4)
#define D_DESC (1<<5)
static int dbri_debug;
module_param(dbri_debug, int, 0644);
MODULE_PARM_DESC(dbri_debug, "Debug value for Sun DBRI soundcard.");
#ifdef DBRI_DEBUG
static const char * const cmds[] = {
"WAIT", "PAUSE", "JUMP", "IIQ", "REX", "SDP", "CDP", "DTS",
"SSP", "CHI", "NT", "TE", "CDEC", "TEST", "CDM", "RESRV"
};
#define dprintk(a, x...) if (dbri_debug & a) printk(KERN_DEBUG x)
#else
#define dprintk(a, x...) do { } while (0)
#endif /* DBRI_DEBUG */
#define DBRI_CMD(cmd, intr, value) ((cmd << 28) | \
(intr << 27) | \
value)
/***************************************************************************
CS4215 specific definitions and structures
****************************************************************************/
struct cs4215 {
__u8 data[4]; /* Data mode: Time slots 5-8 */
__u8 ctrl[4]; /* Ctrl mode: Time slots 1-4 */
__u8 onboard;
__u8 offset; /* Bit offset from frame sync to time slot 1 */
volatile __u32 status;
volatile __u32 version;
__u8 precision; /* In bits, either 8 or 16 */
__u8 channels; /* 1 or 2 */
};
/*
* Control mode first
*/
/* Time Slot 1, Status register */
#define CS4215_CLB (1<<2) /* Control Latch Bit */
#define CS4215_OLB (1<<3) /* 1: line: 2.0V, speaker 4V */
/* 0: line: 2.8V, speaker 8V */
#define CS4215_MLB (1<<4) /* 1: Microphone: 20dB gain disabled */
#define CS4215_RSRVD_1 (1<<5)
/* Time Slot 2, Data Format Register */
#define CS4215_DFR_LINEAR16 0
#define CS4215_DFR_ULAW 1
#define CS4215_DFR_ALAW 2
#define CS4215_DFR_LINEAR8 3
#define CS4215_DFR_STEREO (1<<2)
static struct {
unsigned short freq;
unsigned char xtal;
unsigned char csval;
} CS4215_FREQ[] = {
{ 8000, (1 << 4), (0 << 3) },
{ 16000, (1 << 4), (1 << 3) },
{ 27429, (1 << 4), (2 << 3) }, /* Actually 24428.57 */
{ 32000, (1 << 4), (3 << 3) },
/* { NA, (1 << 4), (4 << 3) }, */
/* { NA, (1 << 4), (5 << 3) }, */
{ 48000, (1 << 4), (6 << 3) },
{ 9600, (1 << 4), (7 << 3) },
{ 5512, (2 << 4), (0 << 3) }, /* Actually 5512.5 */
{ 11025, (2 << 4), (1 << 3) },
{ 18900, (2 << 4), (2 << 3) },
{ 22050, (2 << 4), (3 << 3) },
{ 37800, (2 << 4), (4 << 3) },
{ 44100, (2 << 4), (5 << 3) },
{ 33075, (2 << 4), (6 << 3) },
{ 6615, (2 << 4), (7 << 3) },
{ 0, 0, 0}
};
#define CS4215_HPF (1<<7) /* High Pass Filter, 1: Enabled */
#define CS4215_12_MASK 0xfcbf /* Mask off reserved bits in slot 1 & 2 */
/* Time Slot 3, Serial Port Control register */
#define CS4215_XEN (1<<0) /* 0: Enable serial output */
#define CS4215_XCLK (1<<1) /* 1: Master mode: Generate SCLK */
#define CS4215_BSEL_64 (0<<2) /* Bitrate: 64 bits per frame */
#define CS4215_BSEL_128 (1<<2)
#define CS4215_BSEL_256 (2<<2)
#define CS4215_MCK_MAST (0<<4) /* Master clock */
#define CS4215_MCK_XTL1 (1<<4) /* 24.576 MHz clock source */
#define CS4215_MCK_XTL2 (2<<4) /* 16.9344 MHz clock source */
#define CS4215_MCK_CLK1 (3<<4) /* Clockin, 256 x Fs */
#define CS4215_MCK_CLK2 (4<<4) /* Clockin, see DFR */
/* Time Slot 4, Test Register */
#define CS4215_DAD (1<<0) /* 0:Digital-Dig loop, 1:Dig-Analog-Dig loop */
#define CS4215_ENL (1<<1) /* Enable Loopback Testing */
/* Time Slot 5, Parallel Port Register */
/* Read only here and the same as the in data mode */
/* Time Slot 6, Reserved */
/* Time Slot 7, Version Register */
#define CS4215_VERSION_MASK 0xf /* Known versions 0/C, 1/D, 2/E */
/* Time Slot 8, Reserved */
/*
* Data mode
*/
/* Time Slot 1-2: Left Channel Data, 2-3: Right Channel Data */
/* Time Slot 5, Output Setting */
#define CS4215_LO(v) v /* Left Output Attenuation 0x3f: -94.5 dB */
#define CS4215_LE (1<<6) /* Line Out Enable */
#define CS4215_HE (1<<7) /* Headphone Enable */
/* Time Slot 6, Output Setting */
#define CS4215_RO(v) v /* Right Output Attenuation 0x3f: -94.5 dB */
#define CS4215_SE (1<<6) /* Speaker Enable */
#define CS4215_ADI (1<<7) /* A/D Data Invalid: Busy in calibration */
/* Time Slot 7, Input Setting */
#define CS4215_LG(v) v /* Left Gain Setting 0xf: 22.5 dB */
#define CS4215_IS (1<<4) /* Input Select: 1=Microphone, 0=Line */
#define CS4215_OVR (1<<5) /* 1: Over range condition occurred */
#define CS4215_PIO0 (1<<6) /* Parallel I/O 0 */
#define CS4215_PIO1 (1<<7)
/* Time Slot 8, Input Setting */
#define CS4215_RG(v) v /* Right Gain Setting 0xf: 22.5 dB */
#define CS4215_MA(v) (v<<4) /* Monitor Path Attenuation 0xf: mute */
/***************************************************************************
DBRI specific definitions and structures
****************************************************************************/
/* DBRI main registers */
#define REG0 0x00 /* Status and Control */
#define REG1 0x04 /* Mode and Interrupt */
#define REG2 0x08 /* Parallel IO */
#define REG3 0x0c /* Test */
#define REG8 0x20 /* Command Queue Pointer */
#define REG9 0x24 /* Interrupt Queue Pointer */
#define DBRI_NO_CMDS 64
#define DBRI_INT_BLK 64
#define DBRI_NO_DESCS 64
#define DBRI_NO_PIPES 32
#define DBRI_MAX_PIPE (DBRI_NO_PIPES - 1)
#define DBRI_REC 0
#define DBRI_PLAY 1
#define DBRI_NO_STREAMS 2
/* One transmit/receive descriptor */
/* When ba != 0 descriptor is used */
struct dbri_mem {
volatile __u32 word1;
__u32 ba; /* Transmit/Receive Buffer Address */
__u32 nda; /* Next Descriptor Address */
volatile __u32 word4;
};
/* This structure is in a DMA region where it can accessed by both
* the CPU and the DBRI
*/
struct dbri_dma {
s32 cmd[DBRI_NO_CMDS]; /* Place for commands */
volatile s32 intr[DBRI_INT_BLK]; /* Interrupt field */
struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */
};
#define dbri_dma_off(member, elem) \
((u32)(unsigned long) \
(&(((struct dbri_dma *)0)->member[elem])))
enum in_or_out { PIPEinput, PIPEoutput };
struct dbri_pipe {
u32 sdp; /* SDP command word */
int nextpipe; /* Next pipe in linked list */
int length; /* Length of timeslot (bits) */
int first_desc; /* Index of first descriptor */
int desc; /* Index of active descriptor */
volatile __u32 *recv_fixed_ptr; /* Ptr to receive fixed data */
};
/* Per stream (playback or record) information */
struct dbri_streaminfo {
struct snd_pcm_substream *substream;
u32 dvma_buffer; /* Device view of ALSA DMA buffer */
int size; /* Size of DMA buffer */
size_t offset; /* offset in user buffer */
int pipe; /* Data pipe used */
int left_gain; /* mixer elements */
int right_gain;
};
/* This structure holds the information for both chips (DBRI & CS4215) */
struct snd_dbri {
int regs_size, irq; /* Needed for unload */
struct platform_device *op; /* OF device info */
spinlock_t lock;
struct dbri_dma *dma; /* Pointer to our DMA block */
dma_addr_t dma_dvma; /* DBRI visible DMA address */
void __iomem *regs; /* dbri HW regs */
int dbri_irqp; /* intr queue pointer */
struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */
int next_desc[DBRI_NO_DESCS]; /* Index of next desc, or -1 */
spinlock_t cmdlock; /* Protects cmd queue accesses */
s32 *cmdptr; /* Pointer to the last queued cmd */
int chi_bpf;
struct cs4215 mm; /* mmcodec special info */
/* per stream (playback/record) info */
struct dbri_streaminfo stream_info[DBRI_NO_STREAMS];
};
#define DBRI_MAX_VOLUME 63 /* Output volume */
#define DBRI_MAX_GAIN 15 /* Input gain */
/* DBRI Reg0 - Status Control Register - defines. (Page 17) */
#define D_P (1<<15) /* Program command & queue pointer valid */
#define D_G (1<<14) /* Allow 4-Word SBus Burst */
#define D_S (1<<13) /* Allow 16-Word SBus Burst */
#define D_E (1<<12) /* Allow 8-Word SBus Burst */
#define D_X (1<<7) /* Sanity Timer Disable */
#define D_T (1<<6) /* Permit activation of the TE interface */
#define D_N (1<<5) /* Permit activation of the NT interface */
#define D_C (1<<4) /* Permit activation of the CHI interface */
#define D_F (1<<3) /* Force Sanity Timer Time-Out */
#define D_D (1<<2) /* Disable Master Mode */
#define D_H (1<<1) /* Halt for Analysis */
#define D_R (1<<0) /* Soft Reset */
/* DBRI Reg1 - Mode and Interrupt Register - defines. (Page 18) */
#define D_LITTLE_END (1<<8) /* Byte Order */
#define D_BIG_END (0<<8) /* Byte Order */
#define D_MRR (1<<4) /* Multiple Error Ack on SBus (read only) */
#define D_MLE (1<<3) /* Multiple Late Error on SBus (read only) */
#define D_LBG (1<<2) /* Lost Bus Grant on SBus (read only) */
#define D_MBE (1<<1) /* Burst Error on SBus (read only) */
#define D_IR (1<<0) /* Interrupt Indicator (read only) */
/* DBRI Reg2 - Parallel IO Register - defines. (Page 18) */
#define D_ENPIO3 (1<<7) /* Enable Pin 3 */
#define D_ENPIO2 (1<<6) /* Enable Pin 2 */
#define D_ENPIO1 (1<<5) /* Enable Pin 1 */
#define D_ENPIO0 (1<<4) /* Enable Pin 0 */
#define D_ENPIO (0xf0) /* Enable all the pins */
#define D_PIO3 (1<<3) /* Pin 3: 1: Data mode, 0: Ctrl mode */
#define D_PIO2 (1<<2) /* Pin 2: 1: Onboard PDN */
#define D_PIO1 (1<<1) /* Pin 1: 0: Reset */
#define D_PIO0 (1<<0) /* Pin 0: 1: Speakerbox PDN */
/* DBRI Commands (Page 20) */
#define D_WAIT 0x0 /* Stop execution */
#define D_PAUSE 0x1 /* Flush long pipes */
#define D_JUMP 0x2 /* New command queue */
#define D_IIQ 0x3 /* Initialize Interrupt Queue */
#define D_REX 0x4 /* Report command execution via interrupt */
#define D_SDP 0x5 /* Setup Data Pipe */
#define D_CDP 0x6 /* Continue Data Pipe (reread NULL Pointer) */
#define D_DTS 0x7 /* Define Time Slot */
#define D_SSP 0x8 /* Set short Data Pipe */
#define D_CHI 0x9 /* Set CHI Global Mode */
#define D_NT 0xa /* NT Command */
#define D_TE 0xb /* TE Command */
#define D_CDEC 0xc /* Codec setup */
#define D_TEST 0xd /* No comment */
#define D_CDM 0xe /* CHI Data mode command */
/* Special bits for some commands */
#define D_PIPE(v) ((v)<<0) /* Pipe No.: 0-15 long, 16-21 short */
/* Setup Data Pipe */
/* IRM */
#define D_SDP_2SAME (1<<18) /* Report 2nd time in a row value received */
#define D_SDP_CHANGE (2<<18) /* Report any changes */
#define D_SDP_EVERY (3<<18) /* Report any changes */
#define D_SDP_EOL (1<<17) /* EOL interrupt enable */
#define D_SDP_IDLE (1<<16) /* HDLC idle interrupt enable */
/* Pipe data MODE */
#define D_SDP_MEM (0<<13) /* To/from memory */
#define D_SDP_HDLC (2<<13)
#define D_SDP_HDLC_D (3<<13) /* D Channel (prio control) */
#define D_SDP_SER (4<<13) /* Serial to serial */
#define D_SDP_FIXED (6<<13) /* Short only */
#define D_SDP_MODE(v) ((v)&(7<<13))
#define D_SDP_TO_SER (1<<12) /* Direction */
#define D_SDP_FROM_SER (0<<12) /* Direction */
#define D_SDP_MSB (1<<11) /* Bit order within Byte */
#define D_SDP_LSB (0<<11) /* Bit order within Byte */
#define D_SDP_P (1<<10) /* Pointer Valid */
#define D_SDP_A (1<<8) /* Abort */
#define D_SDP_C (1<<7) /* Clear */
/* Define Time Slot */
#define D_DTS_VI (1<<17) /* Valid Input Time-Slot Descriptor */
#define D_DTS_VO (1<<16) /* Valid Output Time-Slot Descriptor */
#define D_DTS_INS (1<<15) /* Insert Time Slot */
#define D_DTS_DEL (0<<15) /* Delete Time Slot */
#define D_DTS_PRVIN(v) ((v)<<10) /* Previous In Pipe */
#define D_DTS_PRVOUT(v) ((v)<<5) /* Previous Out Pipe */
/* Time Slot defines */
#define D_TS_LEN(v) ((v)<<24) /* Number of bits in this time slot */
#define D_TS_CYCLE(v) ((v)<<14) /* Bit Count at start of TS */
#define D_TS_DI (1<<13) /* Data Invert */
#define D_TS_1CHANNEL (0<<10) /* Single Channel / Normal mode */
#define D_TS_MONITOR (2<<10) /* Monitor pipe */
#define D_TS_NONCONTIG (3<<10) /* Non contiguous mode */
#define D_TS_ANCHOR (7<<10) /* Starting short pipes */
#define D_TS_MON(v) ((v)<<5) /* Monitor Pipe */
#define D_TS_NEXT(v) ((v)<<0) /* Pipe no.: 0-15 long, 16-21 short */
/* Concentration Highway Interface Modes */
#define D_CHI_CHICM(v) ((v)<<16) /* Clock mode */
#define D_CHI_IR (1<<15) /* Immediate Interrupt Report */
#define D_CHI_EN (1<<14) /* CHIL Interrupt enabled */
#define D_CHI_OD (1<<13) /* Open Drain Enable */
#define D_CHI_FE (1<<12) /* Sample CHIFS on Rising Frame Edge */
#define D_CHI_FD (1<<11) /* Frame Drive */
#define D_CHI_BPF(v) ((v)<<0) /* Bits per Frame */
/* NT: These are here for completeness */
#define D_NT_FBIT (1<<17) /* Frame Bit */
#define D_NT_NBF (1<<16) /* Number of bad frames to loose framing */
#define D_NT_IRM_IMM (1<<15) /* Interrupt Report & Mask: Immediate */
#define D_NT_IRM_EN (1<<14) /* Interrupt Report & Mask: Enable */
#define D_NT_ISNT (1<<13) /* Configure interface as NT */
#define D_NT_FT (1<<12) /* Fixed Timing */
#define D_NT_EZ (1<<11) /* Echo Channel is Zeros */
#define D_NT_IFA (1<<10) /* Inhibit Final Activation */
#define D_NT_ACT (1<<9) /* Activate Interface */
#define D_NT_MFE (1<<8) /* Multiframe Enable */
#define D_NT_RLB(v) ((v)<<5) /* Remote Loopback */
#define D_NT_LLB(v) ((v)<<2) /* Local Loopback */
#define D_NT_FACT (1<<1) /* Force Activation */
#define D_NT_ABV (1<<0) /* Activate Bipolar Violation */
/* Codec Setup */
#define D_CDEC_CK(v) ((v)<<24) /* Clock Select */
#define D_CDEC_FED(v) ((v)<<12) /* FSCOD Falling Edge Delay */
#define D_CDEC_RED(v) ((v)<<0) /* FSCOD Rising Edge Delay */
/* Test */
#define D_TEST_RAM(v) ((v)<<16) /* RAM Pointer */
#define D_TEST_SIZE(v) ((v)<<11) /* */
#define D_TEST_ROMONOFF 0x5 /* Toggle ROM opcode monitor on/off */
#define D_TEST_PROC 0x6 /* Microprocessor test */
#define D_TEST_SER 0x7 /* Serial-Controller test */
#define D_TEST_RAMREAD 0x8 /* Copy from Ram to system memory */
#define D_TEST_RAMWRITE 0x9 /* Copy into Ram from system memory */
#define D_TEST_RAMBIST 0xa /* RAM Built-In Self Test */
#define D_TEST_MCBIST 0xb /* Microcontroller Built-In Self Test */
#define D_TEST_DUMP 0xe /* ROM Dump */
/* CHI Data Mode */
#define D_CDM_THI (1 << 8) /* Transmit Data on CHIDR Pin */
#define D_CDM_RHI (1 << 7) /* Receive Data on CHIDX Pin */
#define D_CDM_RCE (1 << 6) /* Receive on Rising Edge of CHICK */
#define D_CDM_XCE (1 << 2) /* Transmit Data on Rising Edge of CHICK */
#define D_CDM_XEN (1 << 1) /* Transmit Highway Enable */
#define D_CDM_REN (1 << 0) /* Receive Highway Enable */
/* The Interrupts */
#define D_INTR_BRDY 1 /* Buffer Ready for processing */
#define D_INTR_MINT 2 /* Marked Interrupt in RD/TD */
#define D_INTR_IBEG 3 /* Flag to idle transition detected (HDLC) */
#define D_INTR_IEND 4 /* Idle to flag transition detected (HDLC) */
#define D_INTR_EOL 5 /* End of List */
#define D_INTR_CMDI 6 /* Command has bean read */
#define D_INTR_XCMP 8 /* Transmission of frame complete */
#define D_INTR_SBRI 9 /* BRI status change info */
#define D_INTR_FXDT 10 /* Fixed data change */
#define D_INTR_CHIL 11 /* CHI lost frame sync (channel 36 only) */
#define D_INTR_COLL 11 /* Unrecoverable D-Channel collision */
#define D_INTR_DBYT 12 /* Dropped by frame slip */
#define D_INTR_RBYT 13 /* Repeated by frame slip */
#define D_INTR_LINT 14 /* Lost Interrupt */
#define D_INTR_UNDR 15 /* DMA underrun */
#define D_INTR_TE 32
#define D_INTR_NT 34
#define D_INTR_CHI 36
#define D_INTR_CMD 38
#define D_INTR_GETCHAN(v) (((v) >> 24) & 0x3f)
#define D_INTR_GETCODE(v) (((v) >> 20) & 0xf)
#define D_INTR_GETCMD(v) (((v) >> 16) & 0xf)
#define D_INTR_GETVAL(v) ((v) & 0xffff)
#define D_INTR_GETRVAL(v) ((v) & 0xfffff)
#define D_P_0 0 /* TE receive anchor */
#define D_P_1 1 /* TE transmit anchor */
#define D_P_2 2 /* NT transmit anchor */
#define D_P_3 3 /* NT receive anchor */
#define D_P_4 4 /* CHI send data */
#define D_P_5 5 /* CHI receive data */
#define D_P_6 6 /* */
#define D_P_7 7 /* */
#define D_P_8 8 /* */
#define D_P_9 9 /* */
#define D_P_10 10 /* */
#define D_P_11 11 /* */
#define D_P_12 12 /* */
#define D_P_13 13 /* */
#define D_P_14 14 /* */
#define D_P_15 15 /* */
#define D_P_16 16 /* CHI anchor pipe */
#define D_P_17 17 /* CHI send */
#define D_P_18 18 /* CHI receive */
#define D_P_19 19 /* CHI receive */
#define D_P_20 20 /* CHI receive */
#define D_P_21 21 /* */
#define D_P_22 22 /* */
#define D_P_23 23 /* */
#define D_P_24 24 /* */
#define D_P_25 25 /* */
#define D_P_26 26 /* */
#define D_P_27 27 /* */
#define D_P_28 28 /* */
#define D_P_29 29 /* */
#define D_P_30 30 /* */
#define D_P_31 31 /* */
/* Transmit descriptor defines */
#define DBRI_TD_F (1 << 31) /* End of Frame */
#define DBRI_TD_D (1 << 30) /* Do not append CRC */
#define DBRI_TD_CNT(v) ((v) << 16) /* Number of valid bytes in the buffer */
#define DBRI_TD_B (1 << 15) /* Final interrupt */
#define DBRI_TD_M (1 << 14) /* Marker interrupt */
#define DBRI_TD_I (1 << 13) /* Transmit Idle Characters */
#define DBRI_TD_FCNT(v) (v) /* Flag Count */
#define DBRI_TD_UNR (1 << 3) /* Underrun: transmitter is out of data */
#define DBRI_TD_ABT (1 << 2) /* Abort: frame aborted */
#define DBRI_TD_TBC (1 << 0) /* Transmit buffer Complete */
#define DBRI_TD_STATUS(v) ((v) & 0xff) /* Transmit status */
/* Maximum buffer size per TD: almost 8KB */
#define DBRI_TD_MAXCNT ((1 << 13) - 4)
/* Receive descriptor defines */
#define DBRI_RD_F (1 << 31) /* End of Frame */
#define DBRI_RD_C (1 << 30) /* Completed buffer */
#define DBRI_RD_B (1 << 15) /* Final interrupt */
#define DBRI_RD_M (1 << 14) /* Marker interrupt */
#define DBRI_RD_BCNT(v) (v) /* Buffer size */
#define DBRI_RD_CRC (1 << 7) /* 0: CRC is correct */
#define DBRI_RD_BBC (1 << 6) /* 1: Bad Byte received */
#define DBRI_RD_ABT (1 << 5) /* Abort: frame aborted */
#define DBRI_RD_OVRN (1 << 3) /* Overrun: data lost */
#define DBRI_RD_STATUS(v) ((v) & 0xff) /* Receive status */
#define DBRI_RD_CNT(v) (((v) >> 16) & 0x1fff) /* Valid bytes in the buffer */
/* stream_info[] access */
/* Translate the ALSA direction into the array index */
#define DBRI_STREAMNO(substream) \
(substream->stream == \
SNDRV_PCM_STREAM_PLAYBACK ? DBRI_PLAY: DBRI_REC)
/* Return a pointer to dbri_streaminfo */
#define DBRI_STREAM(dbri, substream) \
&dbri->stream_info[DBRI_STREAMNO(substream)]
/*
* Short data pipes transmit LSB first. The CS4215 receives MSB first. Grrr.
* So we have to reverse the bits. Note: not all bit lengths are supported
*/
static __u32 reverse_bytes(__u32 b, int len)
{
switch (len) {
case 32:
b = ((b & 0xffff0000) >> 16) | ((b & 0x0000ffff) << 16);
fallthrough;
case 16:
b = ((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8);
fallthrough;
case 8:
b = ((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4);
fallthrough;
case 4:
b = ((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2);
fallthrough;
case 2:
b = ((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1);
case 1:
case 0:
break;
default:
printk(KERN_ERR "DBRI reverse_bytes: unsupported length\n");
}
return b;
}
/*
****************************************************************************
************** DBRI initialization and command synchronization *************
****************************************************************************
Commands are sent to the DBRI by building a list of them in memory,
then writing the address of the first list item to DBRI register 8.
The list is terminated with a WAIT command, which generates a
CPU interrupt to signal completion.
Since the DBRI can run in parallel with the CPU, several means of
synchronization present themselves. The method implemented here uses
the dbri_cmdwait() to wait for execution of batch of sent commands.
A circular command buffer is used here. A new command is being added
while another can be executed. The scheme works by adding two WAIT commands
after each sent batch of commands. When the next batch is prepared it is
added after the WAIT commands then the WAITs are replaced with single JUMP
command to the new batch. Then the DBRI is forced to reread the last WAIT
command (replaced by the JUMP by then). If the DBRI is still executing
previous commands the request to reread the WAIT command is ignored.
Every time a routine wants to write commands to the DBRI, it must
first call dbri_cmdlock() and get pointer to a free space in
dbri->dma->cmd buffer. After this, the commands can be written to
the buffer, and dbri_cmdsend() is called with the final pointer value
to send them to the DBRI.
*/
#define MAXLOOPS 20
/*
* Wait for the current command string to execute
*/
static void dbri_cmdwait(struct snd_dbri *dbri)
{
int maxloops = MAXLOOPS;
unsigned long flags;
/* Delay if previous commands are still being processed */
spin_lock_irqsave(&dbri->lock, flags);
while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P)) {
spin_unlock_irqrestore(&dbri->lock, flags);
msleep_interruptible(1);
spin_lock_irqsave(&dbri->lock, flags);
}
spin_unlock_irqrestore(&dbri->lock, flags);
if (maxloops == 0)
printk(KERN_ERR "DBRI: Chip never completed command buffer\n");
else
dprintk(D_CMD, "Chip completed command buffer (%d)\n",
MAXLOOPS - maxloops - 1);
}
/*
* Lock the command queue and return pointer to space for len cmd words
* It locks the cmdlock spinlock.
*/
static s32 *dbri_cmdlock(struct snd_dbri *dbri, int len)
{
u32 dvma_addr = (u32)dbri->dma_dvma;
/* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */
len += 2;
spin_lock(&dbri->cmdlock);
if (dbri->cmdptr - dbri->dma->cmd + len < DBRI_NO_CMDS - 2)
return dbri->cmdptr + 2;
else if (len < sbus_readl(dbri->regs + REG8) - dvma_addr)
return dbri->dma->cmd;
else
printk(KERN_ERR "DBRI: no space for commands.");
return NULL;
}
/*
* Send prepared cmd string. It works by writing a JUMP cmd into
* the last WAIT cmd and force DBRI to reread the cmd.
* The JUMP cmd points to the new cmd string.
* It also releases the cmdlock spinlock.
*
* Lock must be held before calling this.
*/
static void dbri_cmdsend(struct snd_dbri *dbri, s32 *cmd, int len)
{
u32 dvma_addr = (u32)dbri->dma_dvma;
s32 tmp, addr;
static int wait_id;
wait_id++;
wait_id &= 0xffff; /* restrict it to a 16 bit counter. */
*(cmd) = DBRI_CMD(D_WAIT, 1, wait_id);
*(cmd+1) = DBRI_CMD(D_WAIT, 1, wait_id);
/* Replace the last command with JUMP */
addr = dvma_addr + (cmd - len - dbri->dma->cmd) * sizeof(s32);
*(dbri->cmdptr+1) = addr;
*(dbri->cmdptr) = DBRI_CMD(D_JUMP, 0, 0);
#ifdef DBRI_DEBUG
if (cmd > dbri->cmdptr) {
s32 *ptr;
for (ptr = dbri->cmdptr; ptr < cmd+2; ptr++)
dprintk(D_CMD, "cmd: %lx:%08x\n",
(unsigned long)ptr, *ptr);
} else {
s32 *ptr = dbri->cmdptr;
dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
ptr++;
dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr);
for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++)
dprintk(D_CMD, "cmd: %lx:%08x\n",
(unsigned long)ptr, *ptr);
}
#endif
/* Reread the last command */
tmp = sbus_readl(dbri->regs + REG0);
tmp |= D_P;
sbus_writel(tmp, dbri->regs + REG0);
dbri->cmdptr = cmd;
spin_unlock(&dbri->cmdlock);
}
/* Lock must be held when calling this */
static void dbri_reset(struct snd_dbri *dbri)
{
int i;
u32 tmp;
dprintk(D_GEN, "reset 0:%x 2:%x 8:%x 9:%x\n",
sbus_readl(dbri->regs + REG0),
sbus_readl(dbri->regs + REG2),
sbus_readl(dbri->regs + REG8), sbus_readl(dbri->regs + REG9));
sbus_writel(D_R, dbri->regs + REG0); /* Soft Reset */
for (i = 0; (sbus_readl(dbri->regs + REG0) & D_R) && i < 64; i++)
udelay(10);
/* A brute approach - DBRI falls back to working burst size by itself
* On SS20 D_S does not work, so do not try so high. */
tmp = sbus_readl(dbri->regs + REG0);
tmp |= D_G | D_E;
tmp &= ~D_S;
sbus_writel(tmp, dbri->regs + REG0);
}
/* Lock must not be held before calling this */
static void dbri_initialize(struct snd_dbri *dbri)
{
u32 dvma_addr = (u32)dbri->dma_dvma;
s32 *cmd;
u32 dma_addr;
unsigned long flags;
int n;
spin_lock_irqsave(&dbri->lock, flags);
dbri_reset(dbri);
/* Initialize pipes */
for (n = 0; n < DBRI_NO_PIPES; n++)
dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1;
spin_lock_init(&dbri->cmdlock);
/*
* Initialize the interrupt ring buffer.
*/
dma_addr = dvma_addr + dbri_dma_off(intr, 0);
dbri->dma->intr[0] = dma_addr;
dbri->dbri_irqp = 1;
/*
* Set up the interrupt queue
*/
spin_lock(&dbri->cmdlock);
cmd = dbri->cmdptr = dbri->dma->cmd;
*(cmd++) = DBRI_CMD(D_IIQ, 0, 0);
*(cmd++) = dma_addr;
*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
dbri->cmdptr = cmd;
*(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
*(cmd++) = DBRI_CMD(D_WAIT, 1, 0);
dma_addr = dvma_addr + dbri_dma_off(cmd, 0);
sbus_writel(dma_addr, dbri->regs + REG8);
spin_unlock(&dbri->cmdlock);
spin_unlock_irqrestore(&dbri->lock, flags);
dbri_cmdwait(dbri);
}
/*
****************************************************************************
************************** DBRI data pipe management ***********************
****************************************************************************
While DBRI control functions use the command and interrupt buffers, the
main data path takes the form of data pipes, which can be short (command
and interrupt driven), or long (attached to DMA buffers). These functions
provide a rudimentary means of setting up and managing the DBRI's pipes,
but the calling functions have to make sure they respect the pipes' linked
list ordering, among other things. The transmit and receive functions
here interface closely with the transmit and receive interrupt code.
*/
static inline int pipe_active(struct snd_dbri *dbri, int pipe)
{
return ((pipe >= 0) && (dbri->pipes[pipe].desc != -1));
}
/* reset_pipe(dbri, pipe)
*
* Called on an in-use pipe to clear anything being transmitted or received
* Lock must be held before calling this.
*/
static void reset_pipe(struct snd_dbri *dbri, int pipe)
{
int sdp;
int desc;
s32 *cmd;
if (pipe < 0 || pipe > DBRI_MAX_PIPE) {
printk(KERN_ERR "DBRI: reset_pipe called with "
"illegal pipe number\n");
return;
}
sdp = dbri->pipes[pipe].sdp;
if (sdp == 0) {
printk(KERN_ERR "DBRI: reset_pipe called "
"on uninitialized pipe\n");
return;
}
cmd = dbri_cmdlock(dbri, 3);
*(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P);
*(cmd++) = 0;
*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
dbri_cmdsend(dbri, cmd, 3);
desc = dbri->pipes[pipe].first_desc;
if (desc >= 0)
do {
dbri->dma->desc[desc].ba = 0;
dbri->dma->desc[desc].nda = 0;
desc = dbri->next_desc[desc];
} while (desc != -1 && desc != dbri->pipes[pipe].first_desc);
dbri->pipes[pipe].desc = -1;
dbri->pipes[pipe].first_desc = -1;
}
/*
* Lock must be held before calling this.
*/
static void setup_pipe(struct snd_dbri *dbri, int pipe, int sdp)
{
if (pipe < 0 || pipe > DBRI_MAX_PIPE) {
printk(KERN_ERR "DBRI: setup_pipe called "
"with illegal pipe number\n");
return;
}
if ((sdp & 0xf800) != sdp) {
printk(KERN_ERR "DBRI: setup_pipe called "
"with strange SDP value\n");
/* sdp &= 0xf800; */
}
/* If this is a fixed receive pipe, arrange for an interrupt
* every time its data changes
*/
if (D_SDP_MODE(sdp) == D_SDP_FIXED && !(sdp & D_SDP_TO_SER))
sdp |= D_SDP_CHANGE;
sdp |= D_PIPE(pipe);
dbri->pipes[pipe].sdp = sdp;
dbri->pipes[pipe].desc = -1;
dbri->pipes[pipe].first_desc = -1;
reset_pipe(dbri, pipe);
}
/*
* Lock must be held before calling this.
*/
static void link_time_slot(struct snd_dbri *dbri, int pipe,
int prevpipe, int nextpipe,
int length, int cycle)
{
s32 *cmd;
int val;
if (pipe < 0 || pipe > DBRI_MAX_PIPE
|| prevpipe < 0 || prevpipe > DBRI_MAX_PIPE
|| nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) {
printk(KERN_ERR
"DBRI: link_time_slot called with illegal pipe number\n");
return;
}
if (dbri->pipes[pipe].sdp == 0
|| dbri->pipes[prevpipe].sdp == 0
|| dbri->pipes[nextpipe].sdp == 0) {
printk(KERN_ERR "DBRI: link_time_slot called "
"on uninitialized pipe\n");
return;
}
dbri->pipes[prevpipe].nextpipe = pipe;
dbri->pipes[pipe].nextpipe = nextpipe;
dbri->pipes[pipe].length = length;
cmd = dbri_cmdlock(dbri, 4);
if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) {
/* Deal with CHI special case:
* "If transmission on edges 0 or 1 is desired, then cycle n
* (where n = # of bit times per frame...) must be used."
* - DBRI data sheet, page 11
*/
if (prevpipe == 16 && cycle == 0)
cycle = dbri->chi_bpf;
val = D_DTS_VO | D_DTS_INS | D_DTS_PRVOUT(prevpipe) | pipe;
*(cmd++) = DBRI_CMD(D_DTS, 0, val);
*(cmd++) = 0;
*(cmd++) =
D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
} else {
val = D_DTS_VI | D_DTS_INS | D_DTS_PRVIN(prevpipe) | pipe;
*(cmd++) = DBRI_CMD(D_DTS, 0, val);
*(cmd++) =
D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe);
*(cmd++) = 0;
}
*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
dbri_cmdsend(dbri, cmd, 4);
}
#if 0
/*
* Lock must be held before calling this.
*/
static void unlink_time_slot(struct snd_dbri *dbri, int pipe,
enum in_or_out direction, int prevpipe,
int nextpipe)
{
s32 *cmd;
int val;
if (pipe < 0 || pipe > DBRI_MAX_PIPE
|| prevpipe < 0 || prevpipe > DBRI_MAX_PIPE
|| nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) {
printk(KERN_ERR
"DBRI: unlink_time_slot called with illegal pipe number\n");
return;
}
cmd = dbri_cmdlock(dbri, 4);
if (direction == PIPEinput) {
val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe;
*(cmd++) = DBRI_CMD(D_DTS, 0, val);
*(cmd++) = D_TS_NEXT(nextpipe);
*(cmd++) = 0;
} else {
val = D_DTS_VO | D_DTS_DEL | D_DTS_PRVOUT(prevpipe) | pipe;
*(cmd++) = DBRI_CMD(D_DTS, 0, val);
*(cmd++) = 0;
*(cmd++) = D_TS_NEXT(nextpipe);
}
*(cmd++) = DBRI_CMD(D_PAUSE, 0, 0);
dbri_cmdsend(dbri, cmd, 4);
}
#endif
/* xmit_fixed() / recv_fixed()
*
* Transmit/receive data on a "fixed" pipe - i.e, one whose contents are not
* expected to change much, and which we don't need to buffer.
* The DBRI only interrupts us when the data changes (receive pipes),
* or only changes the data when this function is called (transmit pipes).
* Only short pipes (numbers 16-31) can be used in fixed data mode.
*
* These function operate on a 32-bit field, no matter how large
* the actual time slot is. The interrupt handler takes care of bit
* ordering and alignment. An 8-bit time slot will always end up
* in the low-order 8 bits, filled either MSB-first or LSB-first,
* depending on the settings passed to setup_pipe().
*
* Lock must not be held before calling it.
*/