18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  linux/arch/arm/mach-rpc/dma.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci *  Copyright (C) 1998 Russell King
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci *  DMA functions specific to RiscPC architecture
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/mman.h>
108c2ecf20Sopenharmony_ci#include <linux/init.h>
118c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
128c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <asm/page.h>
168c2ecf20Sopenharmony_ci#include <asm/dma.h>
178c2ecf20Sopenharmony_ci#include <asm/fiq.h>
188c2ecf20Sopenharmony_ci#include <asm/irq.h>
198c2ecf20Sopenharmony_ci#include <mach/hardware.h>
208c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <asm/mach/dma.h>
238c2ecf20Sopenharmony_ci#include <asm/hardware/iomd.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct iomd_dma {
268c2ecf20Sopenharmony_ci	struct dma_struct	dma;
278c2ecf20Sopenharmony_ci	void __iomem		*base;		/* Controller base address */
288c2ecf20Sopenharmony_ci	int			irq;		/* Controller IRQ */
298c2ecf20Sopenharmony_ci	unsigned int		state;
308c2ecf20Sopenharmony_ci	dma_addr_t		cur_addr;
318c2ecf20Sopenharmony_ci	unsigned int		cur_len;
328c2ecf20Sopenharmony_ci	dma_addr_t		dma_addr;
338c2ecf20Sopenharmony_ci	unsigned int		dma_len;
348c2ecf20Sopenharmony_ci};
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci#if 0
378c2ecf20Sopenharmony_citypedef enum {
388c2ecf20Sopenharmony_ci	dma_size_8	= 1,
398c2ecf20Sopenharmony_ci	dma_size_16	= 2,
408c2ecf20Sopenharmony_ci	dma_size_32	= 4,
418c2ecf20Sopenharmony_ci	dma_size_128	= 16
428c2ecf20Sopenharmony_ci} dma_size_t;
438c2ecf20Sopenharmony_ci#endif
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define TRANSFER_SIZE	2
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define CURA	(0)
488c2ecf20Sopenharmony_ci#define ENDA	(IOMD_IO0ENDA - IOMD_IO0CURA)
498c2ecf20Sopenharmony_ci#define CURB	(IOMD_IO0CURB - IOMD_IO0CURA)
508c2ecf20Sopenharmony_ci#define ENDB	(IOMD_IO0ENDB - IOMD_IO0CURA)
518c2ecf20Sopenharmony_ci#define CR	(IOMD_IO0CR - IOMD_IO0CURA)
528c2ecf20Sopenharmony_ci#define ST	(IOMD_IO0ST - IOMD_IO0CURA)
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic void iomd_get_next_sg(struct iomd_dma *idma)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	unsigned long end, offset, flags = 0;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (idma->dma.sg) {
598c2ecf20Sopenharmony_ci		idma->cur_addr = idma->dma_addr;
608c2ecf20Sopenharmony_ci		offset = idma->cur_addr & ~PAGE_MASK;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci		end = offset + idma->dma_len;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci		if (end > PAGE_SIZE)
658c2ecf20Sopenharmony_ci			end = PAGE_SIZE;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci		if (offset + TRANSFER_SIZE >= end)
688c2ecf20Sopenharmony_ci			flags |= DMA_END_L;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		idma->cur_len = end - TRANSFER_SIZE;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci		idma->dma_len -= end - offset;
738c2ecf20Sopenharmony_ci		idma->dma_addr += end - offset;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		if (idma->dma_len == 0) {
768c2ecf20Sopenharmony_ci			if (idma->dma.sgcount > 1) {
778c2ecf20Sopenharmony_ci				idma->dma.sg = sg_next(idma->dma.sg);
788c2ecf20Sopenharmony_ci				idma->dma_addr = idma->dma.sg->dma_address;
798c2ecf20Sopenharmony_ci				idma->dma_len = idma->dma.sg->length;
808c2ecf20Sopenharmony_ci				idma->dma.sgcount--;
818c2ecf20Sopenharmony_ci			} else {
828c2ecf20Sopenharmony_ci				idma->dma.sg = NULL;
838c2ecf20Sopenharmony_ci				flags |= DMA_END_S;
848c2ecf20Sopenharmony_ci			}
858c2ecf20Sopenharmony_ci		}
868c2ecf20Sopenharmony_ci	} else {
878c2ecf20Sopenharmony_ci		flags = DMA_END_S | DMA_END_L;
888c2ecf20Sopenharmony_ci		idma->cur_addr = 0;
898c2ecf20Sopenharmony_ci		idma->cur_len = 0;
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	idma->cur_len |= flags;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic irqreturn_t iomd_dma_handle(int irq, void *dev_id)
968c2ecf20Sopenharmony_ci{
978c2ecf20Sopenharmony_ci	struct iomd_dma *idma = dev_id;
988c2ecf20Sopenharmony_ci	void __iomem *base = idma->base;
998c2ecf20Sopenharmony_ci	unsigned int state = idma->state;
1008c2ecf20Sopenharmony_ci	unsigned int status, cur, end;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	do {
1038c2ecf20Sopenharmony_ci		status = readb(base + ST);
1048c2ecf20Sopenharmony_ci		if (!(status & DMA_ST_INT))
1058c2ecf20Sopenharmony_ci			goto out;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci		if ((state ^ status) & DMA_ST_AB)
1088c2ecf20Sopenharmony_ci			iomd_get_next_sg(idma);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci		// This efficiently implements state = OFL != AB ? AB : 0
1118c2ecf20Sopenharmony_ci		state = ((status >> 2) ^ status) & DMA_ST_AB;
1128c2ecf20Sopenharmony_ci		if (state) {
1138c2ecf20Sopenharmony_ci			cur = CURA;
1148c2ecf20Sopenharmony_ci			end = ENDA;
1158c2ecf20Sopenharmony_ci		} else {
1168c2ecf20Sopenharmony_ci			cur = CURB;
1178c2ecf20Sopenharmony_ci			end = ENDB;
1188c2ecf20Sopenharmony_ci		}
1198c2ecf20Sopenharmony_ci		writel(idma->cur_addr, base + cur);
1208c2ecf20Sopenharmony_ci		writel(idma->cur_len, base + end);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci		if (status & DMA_ST_OFL &&
1238c2ecf20Sopenharmony_ci		    idma->cur_len == (DMA_END_S|DMA_END_L))
1248c2ecf20Sopenharmony_ci			break;
1258c2ecf20Sopenharmony_ci	} while (1);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	state = ~DMA_ST_AB;
1288c2ecf20Sopenharmony_ci	disable_irq_nosync(irq);
1298c2ecf20Sopenharmony_ciout:
1308c2ecf20Sopenharmony_ci	idma->state = state;
1318c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_cistatic int iomd_request_dma(unsigned int chan, dma_t *dma)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	return request_irq(idma->irq, iomd_dma_handle,
1398c2ecf20Sopenharmony_ci			   0, idma->dma.device_id, idma);
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic void iomd_free_dma(unsigned int chan, dma_t *dma)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	free_irq(idma->irq, idma);
1478c2ecf20Sopenharmony_ci}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic struct device isa_dma_dev = {
1508c2ecf20Sopenharmony_ci	.init_name		= "fallback device",
1518c2ecf20Sopenharmony_ci	.coherent_dma_mask	= ~(dma_addr_t)0,
1528c2ecf20Sopenharmony_ci	.dma_mask		= &isa_dma_dev.coherent_dma_mask,
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic void iomd_enable_dma(unsigned int chan, dma_t *dma)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
1588c2ecf20Sopenharmony_ci	void __iomem *base = idma->base;
1598c2ecf20Sopenharmony_ci	unsigned int ctrl = TRANSFER_SIZE | DMA_CR_E;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (idma->dma.invalid) {
1628c2ecf20Sopenharmony_ci		idma->dma.invalid = 0;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci		/*
1658c2ecf20Sopenharmony_ci		 * Cope with ISA-style drivers which expect cache
1668c2ecf20Sopenharmony_ci		 * coherence.
1678c2ecf20Sopenharmony_ci		 */
1688c2ecf20Sopenharmony_ci		if (!idma->dma.sg) {
1698c2ecf20Sopenharmony_ci			idma->dma.sg = &idma->dma.buf;
1708c2ecf20Sopenharmony_ci			idma->dma.sgcount = 1;
1718c2ecf20Sopenharmony_ci			idma->dma.buf.length = idma->dma.count;
1728c2ecf20Sopenharmony_ci			idma->dma.buf.dma_address = dma_map_single(&isa_dma_dev,
1738c2ecf20Sopenharmony_ci				idma->dma.addr, idma->dma.count,
1748c2ecf20Sopenharmony_ci				idma->dma.dma_mode == DMA_MODE_READ ?
1758c2ecf20Sopenharmony_ci				DMA_FROM_DEVICE : DMA_TO_DEVICE);
1768c2ecf20Sopenharmony_ci		}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci		idma->dma_addr = idma->dma.sg->dma_address;
1798c2ecf20Sopenharmony_ci		idma->dma_len = idma->dma.sg->length;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci		writeb(DMA_CR_C, base + CR);
1828c2ecf20Sopenharmony_ci		idma->state = DMA_ST_AB;
1838c2ecf20Sopenharmony_ci	}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (idma->dma.dma_mode == DMA_MODE_READ)
1868c2ecf20Sopenharmony_ci		ctrl |= DMA_CR_D;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	writeb(ctrl, base + CR);
1898c2ecf20Sopenharmony_ci	enable_irq(idma->irq);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic void iomd_disable_dma(unsigned int chan, dma_t *dma)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	struct iomd_dma *idma = container_of(dma, struct iomd_dma, dma);
1958c2ecf20Sopenharmony_ci	void __iomem *base = idma->base;
1968c2ecf20Sopenharmony_ci	unsigned long flags;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	local_irq_save(flags);
1998c2ecf20Sopenharmony_ci	if (idma->state != ~DMA_ST_AB)
2008c2ecf20Sopenharmony_ci		disable_irq(idma->irq);
2018c2ecf20Sopenharmony_ci	writeb(0, base + CR);
2028c2ecf20Sopenharmony_ci	local_irq_restore(flags);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic int iomd_set_dma_speed(unsigned int chan, dma_t *dma, int cycle)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	int tcr, speed;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	if (cycle < 188)
2108c2ecf20Sopenharmony_ci		speed = 3;
2118c2ecf20Sopenharmony_ci	else if (cycle <= 250)
2128c2ecf20Sopenharmony_ci		speed = 2;
2138c2ecf20Sopenharmony_ci	else if (cycle < 438)
2148c2ecf20Sopenharmony_ci		speed = 1;
2158c2ecf20Sopenharmony_ci	else
2168c2ecf20Sopenharmony_ci		speed = 0;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	tcr = iomd_readb(IOMD_DMATCR);
2198c2ecf20Sopenharmony_ci	speed &= 3;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	switch (chan) {
2228c2ecf20Sopenharmony_ci	case DMA_0:
2238c2ecf20Sopenharmony_ci		tcr = (tcr & ~0x03) | speed;
2248c2ecf20Sopenharmony_ci		break;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	case DMA_1:
2278c2ecf20Sopenharmony_ci		tcr = (tcr & ~0x0c) | (speed << 2);
2288c2ecf20Sopenharmony_ci		break;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	case DMA_2:
2318c2ecf20Sopenharmony_ci		tcr = (tcr & ~0x30) | (speed << 4);
2328c2ecf20Sopenharmony_ci		break;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	case DMA_3:
2358c2ecf20Sopenharmony_ci		tcr = (tcr & ~0xc0) | (speed << 6);
2368c2ecf20Sopenharmony_ci		break;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	default:
2398c2ecf20Sopenharmony_ci		break;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	iomd_writeb(tcr, IOMD_DMATCR);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	return speed;
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic struct dma_ops iomd_dma_ops = {
2488c2ecf20Sopenharmony_ci	.type		= "IOMD",
2498c2ecf20Sopenharmony_ci	.request	= iomd_request_dma,
2508c2ecf20Sopenharmony_ci	.free		= iomd_free_dma,
2518c2ecf20Sopenharmony_ci	.enable		= iomd_enable_dma,
2528c2ecf20Sopenharmony_ci	.disable	= iomd_disable_dma,
2538c2ecf20Sopenharmony_ci	.setspeed	= iomd_set_dma_speed,
2548c2ecf20Sopenharmony_ci};
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic struct fiq_handler fh = {
2578c2ecf20Sopenharmony_ci	.name	= "floppydma"
2588c2ecf20Sopenharmony_ci};
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistruct floppy_dma {
2618c2ecf20Sopenharmony_ci	struct dma_struct	dma;
2628c2ecf20Sopenharmony_ci	unsigned int		fiq;
2638c2ecf20Sopenharmony_ci};
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic void floppy_enable_dma(unsigned int chan, dma_t *dma)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
2688c2ecf20Sopenharmony_ci	void *fiqhandler_start;
2698c2ecf20Sopenharmony_ci	unsigned int fiqhandler_length;
2708c2ecf20Sopenharmony_ci	struct pt_regs regs;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (fdma->dma.sg)
2738c2ecf20Sopenharmony_ci		BUG();
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	if (fdma->dma.dma_mode == DMA_MODE_READ) {
2768c2ecf20Sopenharmony_ci		extern unsigned char floppy_fiqin_start, floppy_fiqin_end;
2778c2ecf20Sopenharmony_ci		fiqhandler_start = &floppy_fiqin_start;
2788c2ecf20Sopenharmony_ci		fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start;
2798c2ecf20Sopenharmony_ci	} else {
2808c2ecf20Sopenharmony_ci		extern unsigned char floppy_fiqout_start, floppy_fiqout_end;
2818c2ecf20Sopenharmony_ci		fiqhandler_start = &floppy_fiqout_start;
2828c2ecf20Sopenharmony_ci		fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start;
2838c2ecf20Sopenharmony_ci	}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	regs.ARM_r9  = fdma->dma.count;
2868c2ecf20Sopenharmony_ci	regs.ARM_r10 = (unsigned long)fdma->dma.addr;
2878c2ecf20Sopenharmony_ci	regs.ARM_fp  = (unsigned long)FLOPPYDMA_BASE;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if (claim_fiq(&fh)) {
2908c2ecf20Sopenharmony_ci		printk("floppydma: couldn't claim FIQ.\n");
2918c2ecf20Sopenharmony_ci		return;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	set_fiq_handler(fiqhandler_start, fiqhandler_length);
2958c2ecf20Sopenharmony_ci	set_fiq_regs(&regs);
2968c2ecf20Sopenharmony_ci	enable_fiq(fdma->fiq);
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_cistatic void floppy_disable_dma(unsigned int chan, dma_t *dma)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct floppy_dma *fdma = container_of(dma, struct floppy_dma, dma);
3028c2ecf20Sopenharmony_ci	disable_fiq(fdma->fiq);
3038c2ecf20Sopenharmony_ci	release_fiq(&fh);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic int floppy_get_residue(unsigned int chan, dma_t *dma)
3078c2ecf20Sopenharmony_ci{
3088c2ecf20Sopenharmony_ci	struct pt_regs regs;
3098c2ecf20Sopenharmony_ci	get_fiq_regs(&regs);
3108c2ecf20Sopenharmony_ci	return regs.ARM_r9;
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic struct dma_ops floppy_dma_ops = {
3148c2ecf20Sopenharmony_ci	.type		= "FIQDMA",
3158c2ecf20Sopenharmony_ci	.enable		= floppy_enable_dma,
3168c2ecf20Sopenharmony_ci	.disable	= floppy_disable_dma,
3178c2ecf20Sopenharmony_ci	.residue	= floppy_get_residue,
3188c2ecf20Sopenharmony_ci};
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci/*
3218c2ecf20Sopenharmony_ci * This is virtual DMA - we don't need anything here.
3228c2ecf20Sopenharmony_ci */
3238c2ecf20Sopenharmony_cistatic void sound_enable_disable_dma(unsigned int chan, dma_t *dma)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_cistatic struct dma_ops sound_dma_ops = {
3288c2ecf20Sopenharmony_ci	.type		= "VIRTUAL",
3298c2ecf20Sopenharmony_ci	.enable		= sound_enable_disable_dma,
3308c2ecf20Sopenharmony_ci	.disable	= sound_enable_disable_dma,
3318c2ecf20Sopenharmony_ci};
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic struct iomd_dma iomd_dma[6];
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic struct floppy_dma floppy_dma = {
3368c2ecf20Sopenharmony_ci	.dma		= {
3378c2ecf20Sopenharmony_ci		.d_ops	= &floppy_dma_ops,
3388c2ecf20Sopenharmony_ci	},
3398c2ecf20Sopenharmony_ci	.fiq		= FIQ_FLOPPYDATA,
3408c2ecf20Sopenharmony_ci};
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic dma_t sound_dma = {
3438c2ecf20Sopenharmony_ci	.d_ops		= &sound_dma_ops,
3448c2ecf20Sopenharmony_ci};
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic int __init rpc_dma_init(void)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	unsigned int i;
3498c2ecf20Sopenharmony_ci	int ret;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	iomd_writeb(0, IOMD_IO0CR);
3528c2ecf20Sopenharmony_ci	iomd_writeb(0, IOMD_IO1CR);
3538c2ecf20Sopenharmony_ci	iomd_writeb(0, IOMD_IO2CR);
3548c2ecf20Sopenharmony_ci	iomd_writeb(0, IOMD_IO3CR);
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	iomd_writeb(0xa0, IOMD_DMATCR);
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/*
3598c2ecf20Sopenharmony_ci	 * Setup DMA channels 2,3 to be for podules
3608c2ecf20Sopenharmony_ci	 * and channels 0,1 for internal devices
3618c2ecf20Sopenharmony_ci	 */
3628c2ecf20Sopenharmony_ci	iomd_writeb(DMA_EXT_IO3|DMA_EXT_IO2, IOMD_DMAEXT);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	iomd_dma[DMA_0].base	= IOMD_BASE + IOMD_IO0CURA;
3658c2ecf20Sopenharmony_ci	iomd_dma[DMA_0].irq	= IRQ_DMA0;
3668c2ecf20Sopenharmony_ci	iomd_dma[DMA_1].base	= IOMD_BASE + IOMD_IO1CURA;
3678c2ecf20Sopenharmony_ci	iomd_dma[DMA_1].irq	= IRQ_DMA1;
3688c2ecf20Sopenharmony_ci	iomd_dma[DMA_2].base	= IOMD_BASE + IOMD_IO2CURA;
3698c2ecf20Sopenharmony_ci	iomd_dma[DMA_2].irq	= IRQ_DMA2;
3708c2ecf20Sopenharmony_ci	iomd_dma[DMA_3].base	= IOMD_BASE + IOMD_IO3CURA;
3718c2ecf20Sopenharmony_ci	iomd_dma[DMA_3].irq	= IRQ_DMA3;
3728c2ecf20Sopenharmony_ci	iomd_dma[DMA_S0].base	= IOMD_BASE + IOMD_SD0CURA;
3738c2ecf20Sopenharmony_ci	iomd_dma[DMA_S0].irq	= IRQ_DMAS0;
3748c2ecf20Sopenharmony_ci	iomd_dma[DMA_S1].base	= IOMD_BASE + IOMD_SD1CURA;
3758c2ecf20Sopenharmony_ci	iomd_dma[DMA_S1].irq	= IRQ_DMAS1;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	for (i = DMA_0; i <= DMA_S1; i++) {
3788c2ecf20Sopenharmony_ci		iomd_dma[i].dma.d_ops = &iomd_dma_ops;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci		ret = isa_dma_add(i, &iomd_dma[i].dma);
3818c2ecf20Sopenharmony_ci		if (ret)
3828c2ecf20Sopenharmony_ci			printk("IOMDDMA%u: unable to register: %d\n", i, ret);
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	ret = isa_dma_add(DMA_VIRTUAL_FLOPPY, &floppy_dma.dma);
3868c2ecf20Sopenharmony_ci	if (ret)
3878c2ecf20Sopenharmony_ci		printk("IOMDFLOPPY: unable to register: %d\n", ret);
3888c2ecf20Sopenharmony_ci	ret = isa_dma_add(DMA_VIRTUAL_SOUND, &sound_dma);
3898c2ecf20Sopenharmony_ci	if (ret)
3908c2ecf20Sopenharmony_ci		printk("IOMDSOUND: unable to register: %d\n", ret);
3918c2ecf20Sopenharmony_ci	return 0;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_cicore_initcall(rpc_dma_init);
394