|
@@ -114,3 +114,169 @@
|
|
|
# define MAX_ISA_DMA_ADDRESS ALPHA_SABLE_MAX_ISA_DMA_ADDRESS
|
|
|
# elif defined(CONFIG_ALPHA_ALCOR)
|
|
|
# define MAX_ISA_DMA_ADDRESS ALPHA_ALCOR_MAX_ISA_DMA_ADDRESS
|
|
|
+# else
|
|
|
+# define MAX_ISA_DMA_ADDRESS ALPHA_MAX_ISA_DMA_ADDRESS
|
|
|
+# endif
|
|
|
+#endif
|
|
|
+
|
|
|
+/* If we have the iommu, we don't have any address limitations on DMA.
|
|
|
+ Otherwise (Nautilus, RX164), we have to have 0-16 Mb DMA zone
|
|
|
+ like i386. */
|
|
|
+#define MAX_DMA_ADDRESS (alpha_mv.mv_pci_tbi ? \
|
|
|
+ ~0UL : IDENT_ADDR + 0x01000000)
|
|
|
+
|
|
|
+/* 8237 DMA controllers */
|
|
|
+#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
|
|
|
+#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
|
|
|
+
|
|
|
+/* DMA controller registers */
|
|
|
+#define DMA1_CMD_REG 0x08 /* command register (w) */
|
|
|
+#define DMA1_STAT_REG 0x08 /* status register (r) */
|
|
|
+#define DMA1_REQ_REG 0x09 /* request register (w) */
|
|
|
+#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
|
|
|
+#define DMA1_MODE_REG 0x0B /* mode register (w) */
|
|
|
+#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
|
|
|
+#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
|
|
|
+#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
|
|
|
+#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
|
|
|
+#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
|
|
|
+#define DMA1_EXT_MODE_REG (0x400 | DMA1_MODE_REG)
|
|
|
+
|
|
|
+#define DMA2_CMD_REG 0xD0 /* command register (w) */
|
|
|
+#define DMA2_STAT_REG 0xD0 /* status register (r) */
|
|
|
+#define DMA2_REQ_REG 0xD2 /* request register (w) */
|
|
|
+#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
|
|
|
+#define DMA2_MODE_REG 0xD6 /* mode register (w) */
|
|
|
+#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
|
|
|
+#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
|
|
|
+#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
|
|
|
+#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
|
|
|
+#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
|
|
|
+#define DMA2_EXT_MODE_REG (0x400 | DMA2_MODE_REG)
|
|
|
+
|
|
|
+#define DMA_ADDR_0 0x00 /* DMA address registers */
|
|
|
+#define DMA_ADDR_1 0x02
|
|
|
+#define DMA_ADDR_2 0x04
|
|
|
+#define DMA_ADDR_3 0x06
|
|
|
+#define DMA_ADDR_4 0xC0
|
|
|
+#define DMA_ADDR_5 0xC4
|
|
|
+#define DMA_ADDR_6 0xC8
|
|
|
+#define DMA_ADDR_7 0xCC
|
|
|
+
|
|
|
+#define DMA_CNT_0 0x01 /* DMA count registers */
|
|
|
+#define DMA_CNT_1 0x03
|
|
|
+#define DMA_CNT_2 0x05
|
|
|
+#define DMA_CNT_3 0x07
|
|
|
+#define DMA_CNT_4 0xC2
|
|
|
+#define DMA_CNT_5 0xC6
|
|
|
+#define DMA_CNT_6 0xCA
|
|
|
+#define DMA_CNT_7 0xCE
|
|
|
+
|
|
|
+#define DMA_PAGE_0 0x87 /* DMA page registers */
|
|
|
+#define DMA_PAGE_1 0x83
|
|
|
+#define DMA_PAGE_2 0x81
|
|
|
+#define DMA_PAGE_3 0x82
|
|
|
+#define DMA_PAGE_5 0x8B
|
|
|
+#define DMA_PAGE_6 0x89
|
|
|
+#define DMA_PAGE_7 0x8A
|
|
|
+
|
|
|
+#define DMA_HIPAGE_0 (0x400 | DMA_PAGE_0)
|
|
|
+#define DMA_HIPAGE_1 (0x400 | DMA_PAGE_1)
|
|
|
+#define DMA_HIPAGE_2 (0x400 | DMA_PAGE_2)
|
|
|
+#define DMA_HIPAGE_3 (0x400 | DMA_PAGE_3)
|
|
|
+#define DMA_HIPAGE_4 (0x400 | DMA_PAGE_4)
|
|
|
+#define DMA_HIPAGE_5 (0x400 | DMA_PAGE_5)
|
|
|
+#define DMA_HIPAGE_6 (0x400 | DMA_PAGE_6)
|
|
|
+#define DMA_HIPAGE_7 (0x400 | DMA_PAGE_7)
|
|
|
+
|
|
|
+#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
|
|
|
+#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
|
|
|
+#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */
|
|
|
+
|
|
|
+#define DMA_AUTOINIT 0x10
|
|
|
+
|
|
|
+extern spinlock_t dma_spin_lock;
|
|
|
+
|
|
|
+static __inline__ unsigned long claim_dma_lock(void)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ spin_lock_irqsave(&dma_spin_lock, flags);
|
|
|
+ return flags;
|
|
|
+}
|
|
|
+
|
|
|
+static __inline__ void release_dma_lock(unsigned long flags)
|
|
|
+{
|
|
|
+ spin_unlock_irqrestore(&dma_spin_lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+/* enable/disable a specific DMA channel */
|
|
|
+static __inline__ void enable_dma(unsigned int dmanr)
|
|
|
+{
|
|
|
+ if (dmanr<=3)
|
|
|
+ dma_outb(dmanr, DMA1_MASK_REG);
|
|
|
+ else
|
|
|
+ dma_outb(dmanr & 3, DMA2_MASK_REG);
|
|
|
+}
|
|
|
+
|
|
|
+static __inline__ void disable_dma(unsigned int dmanr)
|
|
|
+{
|
|
|
+ if (dmanr<=3)
|
|
|
+ dma_outb(dmanr | 4, DMA1_MASK_REG);
|
|
|
+ else
|
|
|
+ dma_outb((dmanr & 3) | 4, DMA2_MASK_REG);
|
|
|
+}
|
|
|
+
|
|
|
+/* Clear the 'DMA Pointer Flip Flop'.
|
|
|
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
|
|
|
+ * Use this once to initialize the FF to a known state.
|
|
|
+ * After that, keep track of it. :-)
|
|
|
+ * --- In order to do that, the DMA routines below should ---
|
|
|
+ * --- only be used while interrupts are disabled! ---
|
|
|
+ */
|
|
|
+static __inline__ void clear_dma_ff(unsigned int dmanr)
|
|
|
+{
|
|
|
+ if (dmanr<=3)
|
|
|
+ dma_outb(0, DMA1_CLEAR_FF_REG);
|
|
|
+ else
|
|
|
+ dma_outb(0, DMA2_CLEAR_FF_REG);
|
|
|
+}
|
|
|
+
|
|
|
+/* set mode (above) for a specific DMA channel */
|
|
|
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
|
|
|
+{
|
|
|
+ if (dmanr<=3)
|
|
|
+ dma_outb(mode | dmanr, DMA1_MODE_REG);
|
|
|
+ else
|
|
|
+ dma_outb(mode | (dmanr&3), DMA2_MODE_REG);
|
|
|
+}
|
|
|
+
|
|
|
+/* set extended mode for a specific DMA channel */
|
|
|
+static __inline__ void set_dma_ext_mode(unsigned int dmanr, char ext_mode)
|
|
|
+{
|
|
|
+ if (dmanr<=3)
|
|
|
+ dma_outb(ext_mode | dmanr, DMA1_EXT_MODE_REG);
|
|
|
+ else
|
|
|
+ dma_outb(ext_mode | (dmanr&3), DMA2_EXT_MODE_REG);
|
|
|
+}
|
|
|
+
|
|
|
+/* Set only the page register bits of the transfer address.
|
|
|
+ * This is used for successive transfers when we know the contents of
|
|
|
+ * the lower 16 bits of the DMA current address register.
|
|
|
+ */
|
|
|
+static __inline__ void set_dma_page(unsigned int dmanr, unsigned int pagenr)
|
|
|
+{
|
|
|
+ switch(dmanr) {
|
|
|
+ case 0:
|
|
|
+ dma_outb(pagenr, DMA_PAGE_0);
|
|
|
+ dma_outb((pagenr >> 8), DMA_HIPAGE_0);
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ dma_outb(pagenr, DMA_PAGE_1);
|
|
|
+ dma_outb((pagenr >> 8), DMA_HIPAGE_1);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ dma_outb(pagenr, DMA_PAGE_2);
|
|
|
+ dma_outb((pagenr >> 8), DMA_HIPAGE_2);
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ dma_outb(pagenr, DMA_PAGE_3);
|