forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
/
parport_ip32.c
2239 lines (2016 loc) · 66.5 KB
/
parport_ip32.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-or-later
/* Low-level parallel port routines for built-in port on SGI IP32
*
* Author: Arnaud Giersch <[email protected]>
*
* Based on parport_pc.c by
* Phil Blundell, Tim Waugh, Jose Renau, David Campbell,
* Andrea Arcangeli, et al.
*
* Thanks to Ilya A. Volynets-Evenbakh for his help.
*
* Copyright (C) 2005, 2006 Arnaud Giersch.
*/
/* Current status:
*
* Basic SPP and PS2 modes are supported.
* Support for parallel port IRQ is present.
* Hardware SPP (a.k.a. compatibility), EPP, and ECP modes are
* supported.
* SPP/ECP FIFO can be driven in PIO or DMA mode. PIO mode can work with
* or without interrupt support.
*
* Hardware ECP mode is not fully implemented (ecp_read_data and
* ecp_write_addr are actually missing).
*
* To do:
*
* Fully implement ECP mode.
* EPP and ECP mode need to be tested. I currently do not own any
* peripheral supporting these extended mode, and cannot test them.
* If DMA mode works well, decide if support for PIO FIFO modes should be
* dropped.
* Use the io{read,write} family functions when they become available in
* the linux-mips.org tree. Note: the MIPS specific functions readsb()
* and writesb() are to be translated by ioread8_rep() and iowrite8_rep()
* respectively.
*/
/* The built-in parallel port on the SGI 02 workstation (a.k.a. IP32) is an
* IEEE 1284 parallel port driven by a Texas Instrument TL16PIR552PH chip[1].
* This chip supports SPP, bidirectional, EPP and ECP modes. It has a 16 byte
* FIFO buffer and supports DMA transfers.
*
* [1] http://focus.ti.com/docs/prod/folders/print/tl16pir552.html
*
* Theoretically, we could simply use the parport_pc module. It is however
* not so simple. The parport_pc code assumes that the parallel port
* registers are port-mapped. On the O2, they are memory-mapped.
* Furthermore, each register is replicated on 256 consecutive addresses (as
* it is for the built-in serial ports on the same chip).
*/
/*--- Some configuration defines ---------------------------------------*/
/* DEBUG_PARPORT_IP32
* 0 disable debug
* 1 standard level: pr_debug1 is enabled
* 2 parport_ip32_dump_state is enabled
* >=3 verbose level: pr_debug is enabled
*/
#if !defined(DEBUG_PARPORT_IP32)
# define DEBUG_PARPORT_IP32 0 /* 0 (disabled) for production */
#endif
/*----------------------------------------------------------------------*/
/* Setup DEBUG macros. This is done before any includes, just in case we
* activate pr_debug() with DEBUG_PARPORT_IP32 >= 3.
*/
#if DEBUG_PARPORT_IP32 == 1
# warning DEBUG_PARPORT_IP32 == 1
#elif DEBUG_PARPORT_IP32 == 2
# warning DEBUG_PARPORT_IP32 == 2
#elif DEBUG_PARPORT_IP32 >= 3
# warning DEBUG_PARPORT_IP32 >= 3
# if !defined(DEBUG)
# define DEBUG /* enable pr_debug() in kernel.h */
# endif
#endif
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/parport.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/stddef.h>
#include <linux/types.h>
#include <asm/io.h>
#include <asm/ip32/ip32_ints.h>
#include <asm/ip32/mace.h>
/*--- Global variables -------------------------------------------------*/
/* Verbose probing on by default for debugging. */
#if DEBUG_PARPORT_IP32 >= 1
# define DEFAULT_VERBOSE_PROBING 1
#else
# define DEFAULT_VERBOSE_PROBING 0
#endif
/* Default prefix for printk */
#define PPIP32 "parport_ip32: "
/*
* These are the module parameters:
* @features: bit mask of features to enable/disable
* (all enabled by default)
* @verbose_probing: log chit-chat during initialization
*/
#define PARPORT_IP32_ENABLE_IRQ (1U << 0)
#define PARPORT_IP32_ENABLE_DMA (1U << 1)
#define PARPORT_IP32_ENABLE_SPP (1U << 2)
#define PARPORT_IP32_ENABLE_EPP (1U << 3)
#define PARPORT_IP32_ENABLE_ECP (1U << 4)
static unsigned int features = ~0U;
static bool verbose_probing = DEFAULT_VERBOSE_PROBING;
/* We do not support more than one port. */
static struct parport *this_port;
/* Timing constants for FIFO modes. */
#define FIFO_NFAULT_TIMEOUT 100 /* milliseconds */
#define FIFO_POLLING_INTERVAL 50 /* microseconds */
/*--- I/O register definitions -----------------------------------------*/
/**
* struct parport_ip32_regs - virtual addresses of parallel port registers
* @data: Data Register
* @dsr: Device Status Register
* @dcr: Device Control Register
* @eppAddr: EPP Address Register
* @eppData0: EPP Data Register 0
* @eppData1: EPP Data Register 1
* @eppData2: EPP Data Register 2
* @eppData3: EPP Data Register 3
* @ecpAFifo: ECP Address FIFO
* @fifo: General FIFO register. The same address is used for:
* - cFifo, the Parallel Port DATA FIFO
* - ecpDFifo, the ECP Data FIFO
* - tFifo, the ECP Test FIFO
* @cnfgA: Configuration Register A
* @cnfgB: Configuration Register B
* @ecr: Extended Control Register
*/
struct parport_ip32_regs {
void __iomem *data;
void __iomem *dsr;
void __iomem *dcr;
void __iomem *eppAddr;
void __iomem *eppData0;
void __iomem *eppData1;
void __iomem *eppData2;
void __iomem *eppData3;
void __iomem *ecpAFifo;
void __iomem *fifo;
void __iomem *cnfgA;
void __iomem *cnfgB;
void __iomem *ecr;
};
/* Device Status Register */
#define DSR_nBUSY (1U << 7) /* PARPORT_STATUS_BUSY */
#define DSR_nACK (1U << 6) /* PARPORT_STATUS_ACK */
#define DSR_PERROR (1U << 5) /* PARPORT_STATUS_PAPEROUT */
#define DSR_SELECT (1U << 4) /* PARPORT_STATUS_SELECT */
#define DSR_nFAULT (1U << 3) /* PARPORT_STATUS_ERROR */
#define DSR_nPRINT (1U << 2) /* specific to TL16PIR552 */
/* #define DSR_reserved (1U << 1) */
#define DSR_TIMEOUT (1U << 0) /* EPP timeout */
/* Device Control Register */
/* #define DCR_reserved (1U << 7) | (1U << 6) */
#define DCR_DIR (1U << 5) /* direction */
#define DCR_IRQ (1U << 4) /* interrupt on nAck */
#define DCR_SELECT (1U << 3) /* PARPORT_CONTROL_SELECT */
#define DCR_nINIT (1U << 2) /* PARPORT_CONTROL_INIT */
#define DCR_AUTOFD (1U << 1) /* PARPORT_CONTROL_AUTOFD */
#define DCR_STROBE (1U << 0) /* PARPORT_CONTROL_STROBE */
/* ECP Configuration Register A */
#define CNFGA_IRQ (1U << 7)
#define CNFGA_ID_MASK ((1U << 6) | (1U << 5) | (1U << 4))
#define CNFGA_ID_SHIFT 4
#define CNFGA_ID_16 (00U << CNFGA_ID_SHIFT)
#define CNFGA_ID_8 (01U << CNFGA_ID_SHIFT)
#define CNFGA_ID_32 (02U << CNFGA_ID_SHIFT)
/* #define CNFGA_reserved (1U << 3) */
#define CNFGA_nBYTEINTRANS (1U << 2)
#define CNFGA_PWORDLEFT ((1U << 1) | (1U << 0))
/* ECP Configuration Register B */
#define CNFGB_COMPRESS (1U << 7)
#define CNFGB_INTRVAL (1U << 6)
#define CNFGB_IRQ_MASK ((1U << 5) | (1U << 4) | (1U << 3))
#define CNFGB_IRQ_SHIFT 3
#define CNFGB_DMA_MASK ((1U << 2) | (1U << 1) | (1U << 0))
#define CNFGB_DMA_SHIFT 0
/* Extended Control Register */
#define ECR_MODE_MASK ((1U << 7) | (1U << 6) | (1U << 5))
#define ECR_MODE_SHIFT 5
#define ECR_MODE_SPP (00U << ECR_MODE_SHIFT)
#define ECR_MODE_PS2 (01U << ECR_MODE_SHIFT)
#define ECR_MODE_PPF (02U << ECR_MODE_SHIFT)
#define ECR_MODE_ECP (03U << ECR_MODE_SHIFT)
#define ECR_MODE_EPP (04U << ECR_MODE_SHIFT)
/* #define ECR_MODE_reserved (05U << ECR_MODE_SHIFT) */
#define ECR_MODE_TST (06U << ECR_MODE_SHIFT)
#define ECR_MODE_CFG (07U << ECR_MODE_SHIFT)
#define ECR_nERRINTR (1U << 4)
#define ECR_DMAEN (1U << 3)
#define ECR_SERVINTR (1U << 2)
#define ECR_F_FULL (1U << 1)
#define ECR_F_EMPTY (1U << 0)
/*--- Private data -----------------------------------------------------*/
/**
* enum parport_ip32_irq_mode - operation mode of interrupt handler
* @PARPORT_IP32_IRQ_FWD: forward interrupt to the upper parport layer
* @PARPORT_IP32_IRQ_HERE: interrupt is handled locally
*/
enum parport_ip32_irq_mode { PARPORT_IP32_IRQ_FWD, PARPORT_IP32_IRQ_HERE };
/**
* struct parport_ip32_private - private stuff for &struct parport
* @regs: register addresses
* @dcr_cache: cached contents of DCR
* @dcr_writable: bit mask of writable DCR bits
* @pword: number of bytes per PWord
* @fifo_depth: number of PWords that FIFO will hold
* @readIntrThreshold: minimum number of PWords we can read
* if we get an interrupt
* @writeIntrThreshold: minimum number of PWords we can write
* if we get an interrupt
* @irq_mode: operation mode of interrupt handler for this port
* @irq_complete: mutex used to wait for an interrupt to occur
*/
struct parport_ip32_private {
struct parport_ip32_regs regs;
unsigned int dcr_cache;
unsigned int dcr_writable;
unsigned int pword;
unsigned int fifo_depth;
unsigned int readIntrThreshold;
unsigned int writeIntrThreshold;
enum parport_ip32_irq_mode irq_mode;
struct completion irq_complete;
};
/*--- Debug code -------------------------------------------------------*/
/*
* pr_debug1 - print debug messages
*
* This is like pr_debug(), but is defined for %DEBUG_PARPORT_IP32 >= 1
*/
#if DEBUG_PARPORT_IP32 >= 1
# define pr_debug1(...) printk(KERN_DEBUG __VA_ARGS__)
#else /* DEBUG_PARPORT_IP32 < 1 */
# define pr_debug1(...) do { } while (0)
#endif
/*
* pr_trace, pr_trace1 - trace function calls
* @p: pointer to &struct parport
* @fmt: printk format string
* @...: parameters for format string
*
* Macros used to trace function calls. The given string is formatted after
* function name. pr_trace() uses pr_debug(), and pr_trace1() uses
* pr_debug1(). __pr_trace() is the low-level macro and is not to be used
* directly.
*/
#define __pr_trace(pr, p, fmt, ...) \
pr("%s: %s" fmt "\n", \
({ const struct parport *__p = (p); \
__p ? __p->name : "parport_ip32"; }), \
__func__ , ##__VA_ARGS__)
#define pr_trace(p, fmt, ...) __pr_trace(pr_debug, p, fmt , ##__VA_ARGS__)
#define pr_trace1(p, fmt, ...) __pr_trace(pr_debug1, p, fmt , ##__VA_ARGS__)
/*
* __pr_probe, pr_probe - print message if @verbose_probing is true
* @p: pointer to &struct parport
* @fmt: printk format string
* @...: parameters for format string
*
* For new lines, use pr_probe(). Use __pr_probe() for continued lines.
*/
#define __pr_probe(...) \
do { if (verbose_probing) printk(__VA_ARGS__); } while (0)
#define pr_probe(p, fmt, ...) \
__pr_probe(KERN_INFO PPIP32 "0x%lx: " fmt, (p)->base , ##__VA_ARGS__)
/*
* parport_ip32_dump_state - print register status of parport
* @p: pointer to &struct parport
* @str: string to add in message
* @show_ecp_config: shall we dump ECP configuration registers too?
*
* This function is only here for debugging purpose, and should be used with
* care. Reading the parallel port registers may have undesired side effects.
* Especially if @show_ecp_config is true, the parallel port is resetted.
* This function is only defined if %DEBUG_PARPORT_IP32 >= 2.
*/
#if DEBUG_PARPORT_IP32 >= 2
static void parport_ip32_dump_state(struct parport *p, char *str,
unsigned int show_ecp_config)
{
struct parport_ip32_private * const priv = p->physport->private_data;
unsigned int i;
printk(KERN_DEBUG PPIP32 "%s: state (%s):\n", p->name, str);
{
static const char ecr_modes[8][4] = {"SPP", "PS2", "PPF",
"ECP", "EPP", "???",
"TST", "CFG"};
unsigned int ecr = readb(priv->regs.ecr);
printk(KERN_DEBUG PPIP32 " ecr=0x%02x", ecr);
printk(" %s",
ecr_modes[(ecr & ECR_MODE_MASK) >> ECR_MODE_SHIFT]);
if (ecr & ECR_nERRINTR)
printk(",nErrIntrEn");
if (ecr & ECR_DMAEN)
printk(",dmaEn");
if (ecr & ECR_SERVINTR)
printk(",serviceIntr");
if (ecr & ECR_F_FULL)
printk(",f_full");
if (ecr & ECR_F_EMPTY)
printk(",f_empty");
printk("\n");
}
if (show_ecp_config) {
unsigned int oecr, cnfgA, cnfgB;
oecr = readb(priv->regs.ecr);
writeb(ECR_MODE_PS2, priv->regs.ecr);
writeb(ECR_MODE_CFG, priv->regs.ecr);
cnfgA = readb(priv->regs.cnfgA);
cnfgB = readb(priv->regs.cnfgB);
writeb(ECR_MODE_PS2, priv->regs.ecr);
writeb(oecr, priv->regs.ecr);
printk(KERN_DEBUG PPIP32 " cnfgA=0x%02x", cnfgA);
printk(" ISA-%s", (cnfgA & CNFGA_IRQ) ? "Level" : "Pulses");
switch (cnfgA & CNFGA_ID_MASK) {
case CNFGA_ID_8:
printk(",8 bits");
break;
case CNFGA_ID_16:
printk(",16 bits");
break;
case CNFGA_ID_32:
printk(",32 bits");
break;
default:
printk(",unknown ID");
break;
}
if (!(cnfgA & CNFGA_nBYTEINTRANS))
printk(",ByteInTrans");
if ((cnfgA & CNFGA_ID_MASK) != CNFGA_ID_8)
printk(",%d byte%s left", cnfgA & CNFGA_PWORDLEFT,
((cnfgA & CNFGA_PWORDLEFT) > 1) ? "s" : "");
printk("\n");
printk(KERN_DEBUG PPIP32 " cnfgB=0x%02x", cnfgB);
printk(" irq=%u,dma=%u",
(cnfgB & CNFGB_IRQ_MASK) >> CNFGB_IRQ_SHIFT,
(cnfgB & CNFGB_DMA_MASK) >> CNFGB_DMA_SHIFT);
printk(",intrValue=%d", !!(cnfgB & CNFGB_INTRVAL));
if (cnfgB & CNFGB_COMPRESS)
printk(",compress");
printk("\n");
}
for (i = 0; i < 2; i++) {
unsigned int dcr = i ? priv->dcr_cache : readb(priv->regs.dcr);
printk(KERN_DEBUG PPIP32 " dcr(%s)=0x%02x",
i ? "soft" : "hard", dcr);
printk(" %s", (dcr & DCR_DIR) ? "rev" : "fwd");
if (dcr & DCR_IRQ)
printk(",ackIntEn");
if (!(dcr & DCR_SELECT))
printk(",nSelectIn");
if (dcr & DCR_nINIT)
printk(",nInit");
if (!(dcr & DCR_AUTOFD))
printk(",nAutoFD");
if (!(dcr & DCR_STROBE))
printk(",nStrobe");
printk("\n");
}
#define sep (f++ ? ',' : ' ')
{
unsigned int f = 0;
unsigned int dsr = readb(priv->regs.dsr);
printk(KERN_DEBUG PPIP32 " dsr=0x%02x", dsr);
if (!(dsr & DSR_nBUSY))
printk("%cBusy", sep);
if (dsr & DSR_nACK)
printk("%cnAck", sep);
if (dsr & DSR_PERROR)
printk("%cPError", sep);
if (dsr & DSR_SELECT)
printk("%cSelect", sep);
if (dsr & DSR_nFAULT)
printk("%cnFault", sep);
if (!(dsr & DSR_nPRINT))
printk("%c(Print)", sep);
if (dsr & DSR_TIMEOUT)
printk("%cTimeout", sep);
printk("\n");
}
#undef sep
}
#else /* DEBUG_PARPORT_IP32 < 2 */
#define parport_ip32_dump_state(...) do { } while (0)
#endif
/*
* CHECK_EXTRA_BITS - track and log extra bits
* @p: pointer to &struct parport
* @b: byte to inspect
* @m: bit mask of authorized bits
*
* This is used to track and log extra bits that should not be there in
* parport_ip32_write_control() and parport_ip32_frob_control(). It is only
* defined if %DEBUG_PARPORT_IP32 >= 1.
*/
#if DEBUG_PARPORT_IP32 >= 1
#define CHECK_EXTRA_BITS(p, b, m) \
do { \
unsigned int __b = (b), __m = (m); \
if (__b & ~__m) \
pr_debug1(PPIP32 "%s: extra bits in %s(%s): " \
"0x%02x/0x%02x\n", \
(p)->name, __func__, #b, __b, __m); \
} while (0)
#else /* DEBUG_PARPORT_IP32 < 1 */
#define CHECK_EXTRA_BITS(...) do { } while (0)
#endif
/*--- IP32 parallel port DMA operations --------------------------------*/
/**
* struct parport_ip32_dma_data - private data needed for DMA operation
* @dir: DMA direction (from or to device)
* @buf: buffer physical address
* @len: buffer length
* @next: address of next bytes to DMA transfer
* @left: number of bytes remaining
* @ctx: next context to write (0: context_a; 1: context_b)
* @irq_on: are the DMA IRQs currently enabled?
* @lock: spinlock to protect access to the structure
*/
struct parport_ip32_dma_data {
enum dma_data_direction dir;
dma_addr_t buf;
dma_addr_t next;
size_t len;
size_t left;
unsigned int ctx;
unsigned int irq_on;
spinlock_t lock;
};
static struct parport_ip32_dma_data parport_ip32_dma;
/**
* parport_ip32_dma_setup_context - setup next DMA context
* @limit: maximum data size for the context
*
* The alignment constraints must be verified in caller function, and the
* parameter @limit must be set accordingly.
*/
static void parport_ip32_dma_setup_context(unsigned int limit)
{
unsigned long flags;
spin_lock_irqsave(&parport_ip32_dma.lock, flags);
if (parport_ip32_dma.left > 0) {
/* Note: ctxreg is "volatile" here only because
* mace->perif.ctrl.parport.context_a and context_b are
* "volatile". */
volatile u64 __iomem *ctxreg = (parport_ip32_dma.ctx == 0) ?
&mace->perif.ctrl.parport.context_a :
&mace->perif.ctrl.parport.context_b;
u64 count;
u64 ctxval;
if (parport_ip32_dma.left <= limit) {
count = parport_ip32_dma.left;
ctxval = MACEPAR_CONTEXT_LASTFLAG;
} else {
count = limit;
ctxval = 0;
}
pr_trace(NULL,
"(%u): 0x%04x:0x%04x, %u -> %u%s",
limit,
(unsigned int)parport_ip32_dma.buf,
(unsigned int)parport_ip32_dma.next,
(unsigned int)count,
parport_ip32_dma.ctx, ctxval ? "*" : "");
ctxval |= parport_ip32_dma.next &
MACEPAR_CONTEXT_BASEADDR_MASK;
ctxval |= ((count - 1) << MACEPAR_CONTEXT_DATALEN_SHIFT) &
MACEPAR_CONTEXT_DATALEN_MASK;
writeq(ctxval, ctxreg);
parport_ip32_dma.next += count;
parport_ip32_dma.left -= count;
parport_ip32_dma.ctx ^= 1U;
}
/* If there is nothing more to send, disable IRQs to avoid to
* face an IRQ storm which can lock the machine. Disable them
* only once. */
if (parport_ip32_dma.left == 0 && parport_ip32_dma.irq_on) {
pr_debug(PPIP32 "IRQ off (ctx)\n");
disable_irq_nosync(MACEISA_PAR_CTXA_IRQ);
disable_irq_nosync(MACEISA_PAR_CTXB_IRQ);
parport_ip32_dma.irq_on = 0;
}
spin_unlock_irqrestore(&parport_ip32_dma.lock, flags);
}
/**
* parport_ip32_dma_interrupt - DMA interrupt handler
* @irq: interrupt number
* @dev_id: unused
*/
static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id)
{
if (parport_ip32_dma.left)
pr_trace(NULL, "(%d): ctx=%d", irq, parport_ip32_dma.ctx);
parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND);
return IRQ_HANDLED;
}
#if DEBUG_PARPORT_IP32
static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id)
{
pr_trace1(NULL, "(%d)", irq);
return IRQ_HANDLED;
}
#endif
/**
* parport_ip32_dma_start - begins a DMA transfer
* @p: partport to work on
* @dir: DMA direction: DMA_TO_DEVICE or DMA_FROM_DEVICE
* @addr: pointer to data buffer
* @count: buffer size
*
* Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be
* correctly balanced.
*/
static int parport_ip32_dma_start(struct parport *p,
enum dma_data_direction dir, void *addr, size_t count)
{
unsigned int limit;
u64 ctrl;
pr_trace(NULL, "(%d, %lu)", dir, (unsigned long)count);
/* FIXME - add support for DMA_FROM_DEVICE. In this case, buffer must
* be 64 bytes aligned. */
BUG_ON(dir != DMA_TO_DEVICE);
/* Reset DMA controller */
ctrl = MACEPAR_CTLSTAT_RESET;
writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
/* DMA IRQs should normally be enabled */
if (!parport_ip32_dma.irq_on) {
WARN_ON(1);
enable_irq(MACEISA_PAR_CTXA_IRQ);
enable_irq(MACEISA_PAR_CTXB_IRQ);
parport_ip32_dma.irq_on = 1;
}
/* Prepare DMA pointers */
parport_ip32_dma.dir = dir;
parport_ip32_dma.buf = dma_map_single(&p->bus_dev, addr, count, dir);
parport_ip32_dma.len = count;
parport_ip32_dma.next = parport_ip32_dma.buf;
parport_ip32_dma.left = parport_ip32_dma.len;
parport_ip32_dma.ctx = 0;
/* Setup DMA direction and first two contexts */
ctrl = (dir == DMA_TO_DEVICE) ? 0 : MACEPAR_CTLSTAT_DIRECTION;
writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
/* Single transfer should not cross a 4K page boundary */
limit = MACEPAR_CONTEXT_DATA_BOUND -
(parport_ip32_dma.next & (MACEPAR_CONTEXT_DATA_BOUND - 1));
parport_ip32_dma_setup_context(limit);
parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND);
/* Real start of DMA transfer */
ctrl |= MACEPAR_CTLSTAT_ENABLE;
writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
return 0;
}
/**
* parport_ip32_dma_stop - ends a running DMA transfer
* @p: partport to work on
*
* Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be
* correctly balanced.
*/
static void parport_ip32_dma_stop(struct parport *p)
{
u64 ctx_a;
u64 ctx_b;
u64 ctrl;
u64 diag;
size_t res[2]; /* {[0] = res_a, [1] = res_b} */
pr_trace(NULL, "()");
/* Disable IRQs */
spin_lock_irq(&parport_ip32_dma.lock);
if (parport_ip32_dma.irq_on) {
pr_debug(PPIP32 "IRQ off (stop)\n");
disable_irq_nosync(MACEISA_PAR_CTXA_IRQ);
disable_irq_nosync(MACEISA_PAR_CTXB_IRQ);
parport_ip32_dma.irq_on = 0;
}
spin_unlock_irq(&parport_ip32_dma.lock);
/* Force IRQ synchronization, even if the IRQs were disabled
* elsewhere. */
synchronize_irq(MACEISA_PAR_CTXA_IRQ);
synchronize_irq(MACEISA_PAR_CTXB_IRQ);
/* Stop DMA transfer */
ctrl = readq(&mace->perif.ctrl.parport.cntlstat);
ctrl &= ~MACEPAR_CTLSTAT_ENABLE;
writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
/* Adjust residue (parport_ip32_dma.left) */
ctx_a = readq(&mace->perif.ctrl.parport.context_a);
ctx_b = readq(&mace->perif.ctrl.parport.context_b);
ctrl = readq(&mace->perif.ctrl.parport.cntlstat);
diag = readq(&mace->perif.ctrl.parport.diagnostic);
res[0] = (ctrl & MACEPAR_CTLSTAT_CTXA_VALID) ?
1 + ((ctx_a & MACEPAR_CONTEXT_DATALEN_MASK) >>
MACEPAR_CONTEXT_DATALEN_SHIFT) :
0;
res[1] = (ctrl & MACEPAR_CTLSTAT_CTXB_VALID) ?
1 + ((ctx_b & MACEPAR_CONTEXT_DATALEN_MASK) >>
MACEPAR_CONTEXT_DATALEN_SHIFT) :
0;
if (diag & MACEPAR_DIAG_DMACTIVE)
res[(diag & MACEPAR_DIAG_CTXINUSE) != 0] =
1 + ((diag & MACEPAR_DIAG_CTRMASK) >>
MACEPAR_DIAG_CTRSHIFT);
parport_ip32_dma.left += res[0] + res[1];
/* Reset DMA controller, and re-enable IRQs */
ctrl = MACEPAR_CTLSTAT_RESET;
writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
pr_debug(PPIP32 "IRQ on (stop)\n");
enable_irq(MACEISA_PAR_CTXA_IRQ);
enable_irq(MACEISA_PAR_CTXB_IRQ);
parport_ip32_dma.irq_on = 1;
dma_unmap_single(&p->bus_dev, parport_ip32_dma.buf,
parport_ip32_dma.len, parport_ip32_dma.dir);
}
/**
* parport_ip32_dma_get_residue - get residue from last DMA transfer
*
* Returns the number of bytes remaining from last DMA transfer.
*/
static inline size_t parport_ip32_dma_get_residue(void)
{
return parport_ip32_dma.left;
}
/**
* parport_ip32_dma_register - initialize DMA engine
*
* Returns zero for success.
*/
static int parport_ip32_dma_register(void)
{
int err;
spin_lock_init(&parport_ip32_dma.lock);
parport_ip32_dma.irq_on = 1;
/* Reset DMA controller */
writeq(MACEPAR_CTLSTAT_RESET, &mace->perif.ctrl.parport.cntlstat);
/* Request IRQs */
err = request_irq(MACEISA_PAR_CTXA_IRQ, parport_ip32_dma_interrupt,
0, "parport_ip32", NULL);
if (err)
goto fail_a;
err = request_irq(MACEISA_PAR_CTXB_IRQ, parport_ip32_dma_interrupt,
0, "parport_ip32", NULL);
if (err)
goto fail_b;
#if DEBUG_PARPORT_IP32
/* FIXME - what is this IRQ for? */
err = request_irq(MACEISA_PAR_MERR_IRQ, parport_ip32_merr_interrupt,
0, "parport_ip32", NULL);
if (err)
goto fail_merr;
#endif
return 0;
#if DEBUG_PARPORT_IP32
fail_merr:
free_irq(MACEISA_PAR_CTXB_IRQ, NULL);
#endif
fail_b:
free_irq(MACEISA_PAR_CTXA_IRQ, NULL);
fail_a:
return err;
}
/**
* parport_ip32_dma_unregister - release and free resources for DMA engine
*/
static void parport_ip32_dma_unregister(void)
{
#if DEBUG_PARPORT_IP32
free_irq(MACEISA_PAR_MERR_IRQ, NULL);
#endif
free_irq(MACEISA_PAR_CTXB_IRQ, NULL);
free_irq(MACEISA_PAR_CTXA_IRQ, NULL);
}
/*--- Interrupt handlers and associates --------------------------------*/
/**
* parport_ip32_wakeup - wakes up code waiting for an interrupt
* @p: pointer to &struct parport
*/
static inline void parport_ip32_wakeup(struct parport *p)
{
struct parport_ip32_private * const priv = p->physport->private_data;
complete(&priv->irq_complete);
}
/**
* parport_ip32_interrupt - interrupt handler
* @irq: interrupt number
* @dev_id: pointer to &struct parport
*
* Caught interrupts are forwarded to the upper parport layer if IRQ_mode is
* %PARPORT_IP32_IRQ_FWD.
*/
static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id)
{
struct parport * const p = dev_id;
struct parport_ip32_private * const priv = p->physport->private_data;
enum parport_ip32_irq_mode irq_mode = priv->irq_mode;
switch (irq_mode) {
case PARPORT_IP32_IRQ_FWD:
return parport_irq_handler(irq, dev_id);
case PARPORT_IP32_IRQ_HERE:
parport_ip32_wakeup(p);
break;
}
return IRQ_HANDLED;
}
/*--- Some utility function to manipulate ECR register -----------------*/
/**
* parport_ip32_read_econtrol - read contents of the ECR register
* @p: pointer to &struct parport
*/
static inline unsigned int parport_ip32_read_econtrol(struct parport *p)
{
struct parport_ip32_private * const priv = p->physport->private_data;
return readb(priv->regs.ecr);
}
/**
* parport_ip32_write_econtrol - write new contents to the ECR register
* @p: pointer to &struct parport
* @c: new value to write
*/
static inline void parport_ip32_write_econtrol(struct parport *p,
unsigned int c)
{
struct parport_ip32_private * const priv = p->physport->private_data;
writeb(c, priv->regs.ecr);
}
/**
* parport_ip32_frob_econtrol - change bits from the ECR register
* @p: pointer to &struct parport
* @mask: bit mask of bits to change
* @val: new value for changed bits
*
* Read from the ECR, mask out the bits in @mask, exclusive-or with the bits
* in @val, and write the result to the ECR.
*/
static inline void parport_ip32_frob_econtrol(struct parport *p,
unsigned int mask,
unsigned int val)
{
unsigned int c;
c = (parport_ip32_read_econtrol(p) & ~mask) ^ val;
parport_ip32_write_econtrol(p, c);
}
/**
* parport_ip32_set_mode - change mode of ECP port
* @p: pointer to &struct parport
* @mode: new mode to write in ECR
*
* ECR is reset in a sane state (interrupts and DMA disabled), and placed in
* mode @mode. Go through PS2 mode if needed.
*/
static void parport_ip32_set_mode(struct parport *p, unsigned int mode)
{
unsigned int omode;
mode &= ECR_MODE_MASK;
omode = parport_ip32_read_econtrol(p) & ECR_MODE_MASK;
if (!(mode == ECR_MODE_SPP || mode == ECR_MODE_PS2
|| omode == ECR_MODE_SPP || omode == ECR_MODE_PS2)) {
/* We have to go through PS2 mode */
unsigned int ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
parport_ip32_write_econtrol(p, ecr);
}
parport_ip32_write_econtrol(p, mode | ECR_nERRINTR | ECR_SERVINTR);
}
/*--- Basic functions needed for parport -------------------------------*/
/**
* parport_ip32_read_data - return current contents of the DATA register
* @p: pointer to &struct parport
*/
static inline unsigned char parport_ip32_read_data(struct parport *p)
{
struct parport_ip32_private * const priv = p->physport->private_data;
return readb(priv->regs.data);
}
/**
* parport_ip32_write_data - set new contents for the DATA register
* @p: pointer to &struct parport
* @d: new value to write
*/
static inline void parport_ip32_write_data(struct parport *p, unsigned char d)
{
struct parport_ip32_private * const priv = p->physport->private_data;
writeb(d, priv->regs.data);
}
/**
* parport_ip32_read_status - return current contents of the DSR register
* @p: pointer to &struct parport
*/
static inline unsigned char parport_ip32_read_status(struct parport *p)
{
struct parport_ip32_private * const priv = p->physport->private_data;
return readb(priv->regs.dsr);
}
/**
* __parport_ip32_read_control - return cached contents of the DCR register
* @p: pointer to &struct parport
*/
static inline unsigned int __parport_ip32_read_control(struct parport *p)
{
struct parport_ip32_private * const priv = p->physport->private_data;
return priv->dcr_cache; /* use soft copy */
}
/**
* __parport_ip32_write_control - set new contents for the DCR register
* @p: pointer to &struct parport
* @c: new value to write
*/
static inline void __parport_ip32_write_control(struct parport *p,
unsigned int c)
{
struct parport_ip32_private * const priv = p->physport->private_data;
CHECK_EXTRA_BITS(p, c, priv->dcr_writable);
c &= priv->dcr_writable; /* only writable bits */
writeb(c, priv->regs.dcr);
priv->dcr_cache = c; /* update soft copy */
}
/**
* __parport_ip32_frob_control - change bits from the DCR register
* @p: pointer to &struct parport
* @mask: bit mask of bits to change
* @val: new value for changed bits
*
* This is equivalent to read from the DCR, mask out the bits in @mask,
* exclusive-or with the bits in @val, and write the result to the DCR.
* Actually, the cached contents of the DCR is used.
*/
static inline void __parport_ip32_frob_control(struct parport *p,
unsigned int mask,
unsigned int val)
{
unsigned int c;
c = (__parport_ip32_read_control(p) & ~mask) ^ val;
__parport_ip32_write_control(p, c);
}
/**
* parport_ip32_read_control - return cached contents of the DCR register
* @p: pointer to &struct parport
*
* The return value is masked so as to only return the value of %DCR_STROBE,
* %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
*/
static inline unsigned char parport_ip32_read_control(struct parport *p)
{
const unsigned int rm =
DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
return __parport_ip32_read_control(p) & rm;
}
/**
* parport_ip32_write_control - set new contents for the DCR register
* @p: pointer to &struct parport
* @c: new value to write
*
* The value is masked so as to only change the value of %DCR_STROBE,
* %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
*/
static inline void parport_ip32_write_control(struct parport *p,
unsigned char c)
{
const unsigned int wm =
DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
CHECK_EXTRA_BITS(p, c, wm);
__parport_ip32_frob_control(p, wm, c & wm);
}
/**
* parport_ip32_frob_control - change bits from the DCR register
* @p: pointer to &struct parport
* @mask: bit mask of bits to change
* @val: new value for changed bits
*
* This differs from __parport_ip32_frob_control() in that it only allows to
* change the value of %DCR_STROBE, %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
*/
static inline unsigned char parport_ip32_frob_control(struct parport *p,
unsigned char mask,
unsigned char val)
{
const unsigned int wm =
DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
CHECK_EXTRA_BITS(p, mask, wm);
CHECK_EXTRA_BITS(p, val, wm);
__parport_ip32_frob_control(p, mask & wm, val & wm);
return parport_ip32_read_control(p);
}
/**
* parport_ip32_disable_irq - disable interrupts on the rising edge of nACK
* @p: pointer to &struct parport
*/
static inline void parport_ip32_disable_irq(struct parport *p)
{
__parport_ip32_frob_control(p, DCR_IRQ, 0);
}
/**
* parport_ip32_enable_irq - enable interrupts on the rising edge of nACK
* @p: pointer to &struct parport
*/
static inline void parport_ip32_enable_irq(struct parport *p)
{
__parport_ip32_frob_control(p, DCR_IRQ, DCR_IRQ);
}
/**
* parport_ip32_data_forward - enable host-to-peripheral communications
* @p: pointer to &struct parport
*