2021-02-19 23:55:17 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2006-2021, RT-Thread Development Team
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*
|
|
|
|
* Change Logs:
|
|
|
|
*/
|
2017-08-17 23:31:52 +08:00
|
|
|
#ifndef _DMA_H
|
|
|
|
#define _DMA_H
|
|
|
|
|
|
|
|
|
|
|
|
#define MAX_DMA_CHANNELS 8
|
|
|
|
|
|
|
|
/* 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 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 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_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 */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 启用指定的DMA通道
|
|
|
|
*/
|
|
|
|
static __inline__ void EnableDma(unsigned int dmanr)
|
|
|
|
{
|
|
|
|
if (dmanr<=3)
|
|
|
|
OUTB(dmanr, DMA1_MASK_REG);
|
|
|
|
else
|
|
|
|
OUTB(dmanr & 3, DMA2_MASK_REG);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 禁用指定的DMA通道
|
|
|
|
*/
|
|
|
|
static __inline__ void DisableDma(unsigned int dmanr)
|
|
|
|
{
|
|
|
|
if (dmanr<=3)
|
|
|
|
OUTB(dmanr | 4, DMA1_MASK_REG);
|
|
|
|
else
|
|
|
|
OUTB((dmanr & 3) | 4, DMA2_MASK_REG);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 清空DMA 晶体计数器
|
|
|
|
*/
|
|
|
|
static __inline__ void ClearDmaFF(unsigned int dmanr)
|
|
|
|
{
|
|
|
|
if (dmanr<=3)
|
|
|
|
OUTB(0, DMA1_CLEAR_FF_REG);
|
|
|
|
else
|
|
|
|
OUTB(0, DMA2_CLEAR_FF_REG);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 清空DMA 晶体计数器
|
|
|
|
*/
|
|
|
|
static __inline__ void SetDmaMode(unsigned int dmanr, char mode)
|
|
|
|
{
|
|
|
|
if (dmanr<=3)
|
|
|
|
OUTB(mode | dmanr, DMA1_MODE_REG);
|
|
|
|
else
|
|
|
|
OUTB(mode | (dmanr&3), DMA2_MODE_REG);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 设定DMA 页面寄存器
|
|
|
|
*/
|
|
|
|
static __inline__ void SetDmaPage(unsigned int dmanr, char pagenr)
|
|
|
|
{
|
|
|
|
switch(dmanr) {
|
|
|
|
case 0:
|
|
|
|
OUTB(pagenr, DMA_PAGE_0);
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
OUTB(pagenr, DMA_PAGE_1);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
OUTB(pagenr, DMA_PAGE_2);
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
OUTB(pagenr, DMA_PAGE_3);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
OUTB(pagenr & 0xfe, DMA_PAGE_5);
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
OUTB(pagenr & 0xfe, DMA_PAGE_6);
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
OUTB(pagenr & 0xfe, DMA_PAGE_7);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 设定DMA 传输高速缓冲区地址
|
|
|
|
*/
|
|
|
|
static __inline__ void SetDmaAddr(unsigned int dmanr, unsigned int a)
|
|
|
|
{
|
|
|
|
SetDmaPage(dmanr, a>>16);
|
|
|
|
if (dmanr <= 3) {
|
|
|
|
OUTB( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
|
|
|
|
OUTB( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE );
|
|
|
|
} else {
|
|
|
|
OUTB( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
|
|
|
|
OUTB( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 设定DMA 传输块数
|
|
|
|
*/
|
|
|
|
static __inline__ void SetDmaCount(unsigned int dmanr, unsigned int count)
|
|
|
|
{
|
|
|
|
count--;
|
|
|
|
if (dmanr <= 3) {
|
|
|
|
OUTB( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
|
|
|
|
OUTB( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE );
|
|
|
|
} else {
|
|
|
|
OUTB( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
|
|
|
|
OUTB( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 获得DMA 传输剩余块数
|
|
|
|
*/
|
|
|
|
static __inline__ int GetDmaResidue(unsigned int dmanr)
|
|
|
|
{
|
|
|
|
unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
|
|
|
|
: ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
|
|
|
|
|
|
|
|
/* using short to get 16-bit wrap around */
|
|
|
|
unsigned short count;
|
|
|
|
count = 1 + inb(io_port);
|
|
|
|
count += inb(io_port) << 8;
|
|
|
|
return (dmanr<=3)? count : (count<<1);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|