18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/* floppy.h: Sparc specific parts of the Floppy driver.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 1996, 2007, 2008 David S. Miller (davem@davemloft.net)
58c2ecf20Sopenharmony_ci * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Ultra/PCI support added: Sep 1997  Eddie C. Dost  (ecd@skynet.be)
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#ifndef __ASM_SPARC64_FLOPPY_H
118c2ecf20Sopenharmony_ci#define __ASM_SPARC64_FLOPPY_H
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/of.h>
148c2ecf20Sopenharmony_ci#include <linux/of_device.h>
158c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <asm/auxio.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * Define this to enable exchanging drive 0 and 1 if only drive 1 is
218c2ecf20Sopenharmony_ci * probed on PCI machines.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ci#undef PCI_FDC_SWAP_DRIVES
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* References:
278c2ecf20Sopenharmony_ci * 1) Netbsd Sun floppy driver.
288c2ecf20Sopenharmony_ci * 2) NCR 82077 controller manual
298c2ecf20Sopenharmony_ci * 3) Intel 82077 controller manual
308c2ecf20Sopenharmony_ci */
318c2ecf20Sopenharmony_cistruct sun_flpy_controller {
328c2ecf20Sopenharmony_ci	volatile unsigned char status1_82077; /* Auxiliary Status reg. 1 */
338c2ecf20Sopenharmony_ci	volatile unsigned char status2_82077; /* Auxiliary Status reg. 2 */
348c2ecf20Sopenharmony_ci	volatile unsigned char dor_82077;     /* Digital Output reg. */
358c2ecf20Sopenharmony_ci	volatile unsigned char tapectl_82077; /* Tape Control reg */
368c2ecf20Sopenharmony_ci	volatile unsigned char status_82077;  /* Main Status Register. */
378c2ecf20Sopenharmony_ci#define drs_82077              status_82077   /* Digital Rate Select reg. */
388c2ecf20Sopenharmony_ci	volatile unsigned char data_82077;    /* Data fifo. */
398c2ecf20Sopenharmony_ci	volatile unsigned char ___unused;
408c2ecf20Sopenharmony_ci	volatile unsigned char dir_82077;     /* Digital Input reg. */
418c2ecf20Sopenharmony_ci#define dcr_82077              dir_82077      /* Config Control reg. */
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* You'll only ever find one controller on an Ultra anyways. */
458c2ecf20Sopenharmony_cistatic struct sun_flpy_controller *sun_fdc = (struct sun_flpy_controller *)-1;
468c2ecf20Sopenharmony_ciunsigned long fdc_status;
478c2ecf20Sopenharmony_cistatic struct platform_device *floppy_op = NULL;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistruct sun_floppy_ops {
508c2ecf20Sopenharmony_ci	unsigned char	(*fd_inb) (unsigned long port, unsigned int reg);
518c2ecf20Sopenharmony_ci	void		(*fd_outb) (unsigned char value, unsigned long base,
528c2ecf20Sopenharmony_ci				    unsigned int reg);
538c2ecf20Sopenharmony_ci	void		(*fd_enable_dma) (void);
548c2ecf20Sopenharmony_ci	void		(*fd_disable_dma) (void);
558c2ecf20Sopenharmony_ci	void		(*fd_set_dma_mode) (int);
568c2ecf20Sopenharmony_ci	void		(*fd_set_dma_addr) (char *);
578c2ecf20Sopenharmony_ci	void		(*fd_set_dma_count) (int);
588c2ecf20Sopenharmony_ci	unsigned int	(*get_dma_residue) (void);
598c2ecf20Sopenharmony_ci	int		(*fd_request_irq) (void);
608c2ecf20Sopenharmony_ci	void		(*fd_free_irq) (void);
618c2ecf20Sopenharmony_ci	int		(*fd_eject) (int);
628c2ecf20Sopenharmony_ci};
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistatic struct sun_floppy_ops sun_fdops;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci#define fd_inb(base, reg)         sun_fdops.fd_inb(base, reg)
678c2ecf20Sopenharmony_ci#define fd_outb(value, base, reg) sun_fdops.fd_outb(value, base, reg)
688c2ecf20Sopenharmony_ci#define fd_enable_dma()           sun_fdops.fd_enable_dma()
698c2ecf20Sopenharmony_ci#define fd_disable_dma()          sun_fdops.fd_disable_dma()
708c2ecf20Sopenharmony_ci#define fd_request_dma()          (0) /* nothing... */
718c2ecf20Sopenharmony_ci#define fd_free_dma()             /* nothing... */
728c2ecf20Sopenharmony_ci#define fd_clear_dma_ff()         /* nothing... */
738c2ecf20Sopenharmony_ci#define fd_set_dma_mode(mode)     sun_fdops.fd_set_dma_mode(mode)
748c2ecf20Sopenharmony_ci#define fd_set_dma_addr(addr)     sun_fdops.fd_set_dma_addr(addr)
758c2ecf20Sopenharmony_ci#define fd_set_dma_count(count)   sun_fdops.fd_set_dma_count(count)
768c2ecf20Sopenharmony_ci#define get_dma_residue(x)        sun_fdops.get_dma_residue()
778c2ecf20Sopenharmony_ci#define fd_request_irq()          sun_fdops.fd_request_irq()
788c2ecf20Sopenharmony_ci#define fd_free_irq()             sun_fdops.fd_free_irq()
798c2ecf20Sopenharmony_ci#define fd_eject(drive)           sun_fdops.fd_eject(drive)
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/* Super paranoid... */
828c2ecf20Sopenharmony_ci#undef HAVE_DISABLE_HLT
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic int sun_floppy_types[2] = { 0, 0 };
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci/* Here is where we catch the floppy driver trying to initialize,
878c2ecf20Sopenharmony_ci * therefore this is where we call the PROM device tree probing
888c2ecf20Sopenharmony_ci * routine etc. on the Sparc.
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_ci#define FLOPPY0_TYPE		sun_floppy_init()
918c2ecf20Sopenharmony_ci#define FLOPPY1_TYPE		sun_floppy_types[1]
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci#define FDC1			((unsigned long)sun_fdc)
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci#define N_FDC    1
968c2ecf20Sopenharmony_ci#define N_DRIVE  8
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/* No 64k boundary crossing problems on the Sparc. */
998c2ecf20Sopenharmony_ci#define CROSS_64KB(a,s) (0)
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic unsigned char sun_82077_fd_inb(unsigned long base, unsigned int reg)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	udelay(5);
1048c2ecf20Sopenharmony_ci	switch (reg) {
1058c2ecf20Sopenharmony_ci	default:
1068c2ecf20Sopenharmony_ci		printk("floppy: Asked to read unknown port %x\n", reg);
1078c2ecf20Sopenharmony_ci		panic("floppy: Port bolixed.");
1088c2ecf20Sopenharmony_ci	case FD_STATUS:
1098c2ecf20Sopenharmony_ci		return sbus_readb(&sun_fdc->status_82077) & ~STATUS_DMA;
1108c2ecf20Sopenharmony_ci	case FD_DATA:
1118c2ecf20Sopenharmony_ci		return sbus_readb(&sun_fdc->data_82077);
1128c2ecf20Sopenharmony_ci	case FD_DIR:
1138c2ecf20Sopenharmony_ci		/* XXX: Is DCL on 0x80 in sun4m? */
1148c2ecf20Sopenharmony_ci		return sbus_readb(&sun_fdc->dir_82077);
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci	panic("sun_82072_fd_inb: How did I get here?");
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic void sun_82077_fd_outb(unsigned char value, unsigned long base,
1208c2ecf20Sopenharmony_ci			      unsigned int reg)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	udelay(5);
1238c2ecf20Sopenharmony_ci	switch (reg) {
1248c2ecf20Sopenharmony_ci	default:
1258c2ecf20Sopenharmony_ci		printk("floppy: Asked to write to unknown port %x\n", reg);
1268c2ecf20Sopenharmony_ci		panic("floppy: Port bolixed.");
1278c2ecf20Sopenharmony_ci	case FD_DOR:
1288c2ecf20Sopenharmony_ci		/* Happily, the 82077 has a real DOR register. */
1298c2ecf20Sopenharmony_ci		sbus_writeb(value, &sun_fdc->dor_82077);
1308c2ecf20Sopenharmony_ci		break;
1318c2ecf20Sopenharmony_ci	case FD_DATA:
1328c2ecf20Sopenharmony_ci		sbus_writeb(value, &sun_fdc->data_82077);
1338c2ecf20Sopenharmony_ci		break;
1348c2ecf20Sopenharmony_ci	case FD_DCR:
1358c2ecf20Sopenharmony_ci		sbus_writeb(value, &sun_fdc->dcr_82077);
1368c2ecf20Sopenharmony_ci		break;
1378c2ecf20Sopenharmony_ci	case FD_DSR:
1388c2ecf20Sopenharmony_ci		sbus_writeb(value, &sun_fdc->status_82077);
1398c2ecf20Sopenharmony_ci		break;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci	return;
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/* For pseudo-dma (Sun floppy drives have no real DMA available to
1458c2ecf20Sopenharmony_ci * them so we must eat the data fifo bytes directly ourselves) we have
1468c2ecf20Sopenharmony_ci * three state variables.  doing_pdma tells our inline low-level
1478c2ecf20Sopenharmony_ci * assembly floppy interrupt entry point whether it should sit and eat
1488c2ecf20Sopenharmony_ci * bytes from the fifo or just transfer control up to the higher level
1498c2ecf20Sopenharmony_ci * floppy interrupt c-code.  I tried very hard but I could not get the
1508c2ecf20Sopenharmony_ci * pseudo-dma to work in c-code without getting many overruns and
1518c2ecf20Sopenharmony_ci * underruns.  If non-zero, doing_pdma encodes the direction of
1528c2ecf20Sopenharmony_ci * the transfer for debugging.  1=read 2=write
1538c2ecf20Sopenharmony_ci */
1548c2ecf20Sopenharmony_ciunsigned char *pdma_vaddr;
1558c2ecf20Sopenharmony_ciunsigned long pdma_size;
1568c2ecf20Sopenharmony_civolatile int doing_pdma = 0;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci/* This is software state */
1598c2ecf20Sopenharmony_cichar *pdma_base = NULL;
1608c2ecf20Sopenharmony_ciunsigned long pdma_areasize;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci/* Common routines to all controller types on the Sparc. */
1638c2ecf20Sopenharmony_cistatic void sun_fd_disable_dma(void)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	doing_pdma = 0;
1668c2ecf20Sopenharmony_ci	pdma_base = NULL;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic void sun_fd_set_dma_mode(int mode)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	switch(mode) {
1728c2ecf20Sopenharmony_ci	case DMA_MODE_READ:
1738c2ecf20Sopenharmony_ci		doing_pdma = 1;
1748c2ecf20Sopenharmony_ci		break;
1758c2ecf20Sopenharmony_ci	case DMA_MODE_WRITE:
1768c2ecf20Sopenharmony_ci		doing_pdma = 2;
1778c2ecf20Sopenharmony_ci		break;
1788c2ecf20Sopenharmony_ci	default:
1798c2ecf20Sopenharmony_ci		printk("Unknown dma mode %d\n", mode);
1808c2ecf20Sopenharmony_ci		panic("floppy: Giving up...");
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic void sun_fd_set_dma_addr(char *buffer)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	pdma_vaddr = buffer;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic void sun_fd_set_dma_count(int length)
1908c2ecf20Sopenharmony_ci{
1918c2ecf20Sopenharmony_ci	pdma_size = length;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic void sun_fd_enable_dma(void)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	pdma_base = pdma_vaddr;
1978c2ecf20Sopenharmony_ci	pdma_areasize = pdma_size;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ciirqreturn_t sparc_floppy_irq(int irq, void *dev_cookie)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	if (likely(doing_pdma)) {
2038c2ecf20Sopenharmony_ci		void __iomem *stat = (void __iomem *) fdc_status;
2048c2ecf20Sopenharmony_ci		unsigned char *vaddr = pdma_vaddr;
2058c2ecf20Sopenharmony_ci		unsigned long size = pdma_size;
2068c2ecf20Sopenharmony_ci		u8 val;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci		while (size) {
2098c2ecf20Sopenharmony_ci			val = readb(stat);
2108c2ecf20Sopenharmony_ci			if (unlikely(!(val & 0x80))) {
2118c2ecf20Sopenharmony_ci				pdma_vaddr = vaddr;
2128c2ecf20Sopenharmony_ci				pdma_size = size;
2138c2ecf20Sopenharmony_ci				return IRQ_HANDLED;
2148c2ecf20Sopenharmony_ci			}
2158c2ecf20Sopenharmony_ci			if (unlikely(!(val & 0x20))) {
2168c2ecf20Sopenharmony_ci				pdma_vaddr = vaddr;
2178c2ecf20Sopenharmony_ci				pdma_size = size;
2188c2ecf20Sopenharmony_ci				doing_pdma = 0;
2198c2ecf20Sopenharmony_ci				goto main_interrupt;
2208c2ecf20Sopenharmony_ci			}
2218c2ecf20Sopenharmony_ci			if (val & 0x40) {
2228c2ecf20Sopenharmony_ci				/* read */
2238c2ecf20Sopenharmony_ci				*vaddr++ = readb(stat + 1);
2248c2ecf20Sopenharmony_ci			} else {
2258c2ecf20Sopenharmony_ci				unsigned char data = *vaddr++;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci				/* write */
2288c2ecf20Sopenharmony_ci				writeb(data, stat + 1);
2298c2ecf20Sopenharmony_ci			}
2308c2ecf20Sopenharmony_ci			size--;
2318c2ecf20Sopenharmony_ci		}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci		pdma_vaddr = vaddr;
2348c2ecf20Sopenharmony_ci		pdma_size = size;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci		/* Send Terminal Count pulse to floppy controller. */
2378c2ecf20Sopenharmony_ci		val = readb(auxio_register);
2388c2ecf20Sopenharmony_ci		val |= AUXIO_AUX1_FTCNT;
2398c2ecf20Sopenharmony_ci		writeb(val, auxio_register);
2408c2ecf20Sopenharmony_ci		val &= ~AUXIO_AUX1_FTCNT;
2418c2ecf20Sopenharmony_ci		writeb(val, auxio_register);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci		doing_pdma = 0;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_cimain_interrupt:
2478c2ecf20Sopenharmony_ci	return floppy_interrupt(irq, dev_cookie);
2488c2ecf20Sopenharmony_ci}
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic int sun_fd_request_irq(void)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	static int once = 0;
2538c2ecf20Sopenharmony_ci	int error;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	if(!once) {
2568c2ecf20Sopenharmony_ci		once = 1;
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci		error = request_irq(FLOPPY_IRQ, sparc_floppy_irq,
2598c2ecf20Sopenharmony_ci				    0, "floppy", NULL);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci		return ((error == 0) ? 0 : -1);
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci	return 0;
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic void sun_fd_free_irq(void)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic unsigned int sun_get_dma_residue(void)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	/* XXX This isn't really correct. XXX */
2738c2ecf20Sopenharmony_ci	return 0;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_cistatic int sun_fd_eject(int drive)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	set_dor(0x00, 0xff, 0x90);
2798c2ecf20Sopenharmony_ci	udelay(500);
2808c2ecf20Sopenharmony_ci	set_dor(0x00, 0x6f, 0x00);
2818c2ecf20Sopenharmony_ci	udelay(500);
2828c2ecf20Sopenharmony_ci	return 0;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci#include <asm/ebus_dma.h>
2868c2ecf20Sopenharmony_ci#include <asm/ns87303.h>
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic struct ebus_dma_info sun_pci_fd_ebus_dma;
2898c2ecf20Sopenharmony_cistatic struct device *sun_floppy_dev;
2908c2ecf20Sopenharmony_cistatic int sun_pci_broken_drive = -1;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_cistruct sun_pci_dma_op {
2938c2ecf20Sopenharmony_ci	unsigned int 	addr;
2948c2ecf20Sopenharmony_ci	int		len;
2958c2ecf20Sopenharmony_ci	int		direction;
2968c2ecf20Sopenharmony_ci	char		*buf;
2978c2ecf20Sopenharmony_ci};
2988c2ecf20Sopenharmony_cistatic struct sun_pci_dma_op sun_pci_dma_current = { -1U, 0, 0, NULL};
2998c2ecf20Sopenharmony_cistatic struct sun_pci_dma_op sun_pci_dma_pending = { -1U, 0, 0, NULL};
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ciirqreturn_t floppy_interrupt(int irq, void *dev_id);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic unsigned char sun_pci_fd_inb(unsigned long base, unsigned int reg)
3048c2ecf20Sopenharmony_ci{
3058c2ecf20Sopenharmony_ci	udelay(5);
3068c2ecf20Sopenharmony_ci	return inb(base + reg);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic void sun_pci_fd_outb(unsigned char val, unsigned long base,
3108c2ecf20Sopenharmony_ci			    unsigned int reg)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	udelay(5);
3138c2ecf20Sopenharmony_ci	outb(val, base + reg);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic void sun_pci_fd_broken_outb(unsigned char val, unsigned long base,
3178c2ecf20Sopenharmony_ci				   unsigned int reg)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	udelay(5);
3208c2ecf20Sopenharmony_ci	/*
3218c2ecf20Sopenharmony_ci	 * XXX: Due to SUN's broken floppy connector on AX and AXi
3228c2ecf20Sopenharmony_ci	 *      we need to turn on MOTOR_0 also, if the floppy is
3238c2ecf20Sopenharmony_ci	 *      jumpered to DS1 (like most PC floppies are). I hope
3248c2ecf20Sopenharmony_ci	 *      this does not hurt correct hardware like the AXmp.
3258c2ecf20Sopenharmony_ci	 *      (Eddie, Sep 12 1998).
3268c2ecf20Sopenharmony_ci	 */
3278c2ecf20Sopenharmony_ci	if (reg == FD_DOR) {
3288c2ecf20Sopenharmony_ci		if (((val & 0x03) == sun_pci_broken_drive) && (val & 0x20)) {
3298c2ecf20Sopenharmony_ci			val |= 0x10;
3308c2ecf20Sopenharmony_ci		}
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci	outb(val, base + reg);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci#ifdef PCI_FDC_SWAP_DRIVES
3368c2ecf20Sopenharmony_cistatic void sun_pci_fd_lde_broken_outb(unsigned char val, unsigned long base,
3378c2ecf20Sopenharmony_ci				       unsigned int reg)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	udelay(5);
3408c2ecf20Sopenharmony_ci	/*
3418c2ecf20Sopenharmony_ci	 * XXX: Due to SUN's broken floppy connector on AX and AXi
3428c2ecf20Sopenharmony_ci	 *      we need to turn on MOTOR_0 also, if the floppy is
3438c2ecf20Sopenharmony_ci	 *      jumpered to DS1 (like most PC floppies are). I hope
3448c2ecf20Sopenharmony_ci	 *      this does not hurt correct hardware like the AXmp.
3458c2ecf20Sopenharmony_ci	 *      (Eddie, Sep 12 1998).
3468c2ecf20Sopenharmony_ci	 */
3478c2ecf20Sopenharmony_ci	if (reg == FD_DOR) {
3488c2ecf20Sopenharmony_ci		if (((val & 0x03) == sun_pci_broken_drive) && (val & 0x10)) {
3498c2ecf20Sopenharmony_ci			val &= ~(0x03);
3508c2ecf20Sopenharmony_ci			val |= 0x21;
3518c2ecf20Sopenharmony_ci		}
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci	outb(val, base + reg);
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci#endif /* PCI_FDC_SWAP_DRIVES */
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic void sun_pci_fd_enable_dma(void)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	BUG_ON((NULL == sun_pci_dma_pending.buf) 	||
3608c2ecf20Sopenharmony_ci	    (0	  == sun_pci_dma_pending.len) 	||
3618c2ecf20Sopenharmony_ci	    (0	  == sun_pci_dma_pending.direction));
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	sun_pci_dma_current.buf = sun_pci_dma_pending.buf;
3648c2ecf20Sopenharmony_ci	sun_pci_dma_current.len = sun_pci_dma_pending.len;
3658c2ecf20Sopenharmony_ci	sun_pci_dma_current.direction = sun_pci_dma_pending.direction;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	sun_pci_dma_pending.buf  = NULL;
3688c2ecf20Sopenharmony_ci	sun_pci_dma_pending.len  = 0;
3698c2ecf20Sopenharmony_ci	sun_pci_dma_pending.direction = 0;
3708c2ecf20Sopenharmony_ci	sun_pci_dma_pending.addr = -1U;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	sun_pci_dma_current.addr =
3738c2ecf20Sopenharmony_ci		dma_map_single(sun_floppy_dev,
3748c2ecf20Sopenharmony_ci			       sun_pci_dma_current.buf,
3758c2ecf20Sopenharmony_ci			       sun_pci_dma_current.len,
3768c2ecf20Sopenharmony_ci			       sun_pci_dma_current.direction);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	ebus_dma_enable(&sun_pci_fd_ebus_dma, 1);
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	if (ebus_dma_request(&sun_pci_fd_ebus_dma,
3818c2ecf20Sopenharmony_ci			     sun_pci_dma_current.addr,
3828c2ecf20Sopenharmony_ci			     sun_pci_dma_current.len))
3838c2ecf20Sopenharmony_ci		BUG();
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic void sun_pci_fd_disable_dma(void)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	ebus_dma_enable(&sun_pci_fd_ebus_dma, 0);
3898c2ecf20Sopenharmony_ci	if (sun_pci_dma_current.addr != -1U)
3908c2ecf20Sopenharmony_ci		dma_unmap_single(sun_floppy_dev,
3918c2ecf20Sopenharmony_ci				 sun_pci_dma_current.addr,
3928c2ecf20Sopenharmony_ci				 sun_pci_dma_current.len,
3938c2ecf20Sopenharmony_ci				 sun_pci_dma_current.direction);
3948c2ecf20Sopenharmony_ci	sun_pci_dma_current.addr = -1U;
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic void sun_pci_fd_set_dma_mode(int mode)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	if (mode == DMA_MODE_WRITE)
4008c2ecf20Sopenharmony_ci		sun_pci_dma_pending.direction = DMA_TO_DEVICE;
4018c2ecf20Sopenharmony_ci	else
4028c2ecf20Sopenharmony_ci		sun_pci_dma_pending.direction = DMA_FROM_DEVICE;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	ebus_dma_prepare(&sun_pci_fd_ebus_dma, mode != DMA_MODE_WRITE);
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic void sun_pci_fd_set_dma_count(int length)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	sun_pci_dma_pending.len = length;
4108c2ecf20Sopenharmony_ci}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic void sun_pci_fd_set_dma_addr(char *buffer)
4138c2ecf20Sopenharmony_ci{
4148c2ecf20Sopenharmony_ci	sun_pci_dma_pending.buf = buffer;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic unsigned int sun_pci_get_dma_residue(void)
4188c2ecf20Sopenharmony_ci{
4198c2ecf20Sopenharmony_ci	return ebus_dma_residue(&sun_pci_fd_ebus_dma);
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_cistatic int sun_pci_fd_request_irq(void)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	return ebus_dma_irq_enable(&sun_pci_fd_ebus_dma, 1);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_cistatic void sun_pci_fd_free_irq(void)
4288c2ecf20Sopenharmony_ci{
4298c2ecf20Sopenharmony_ci	ebus_dma_irq_enable(&sun_pci_fd_ebus_dma, 0);
4308c2ecf20Sopenharmony_ci}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int sun_pci_fd_eject(int drive)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	return -EINVAL;
4358c2ecf20Sopenharmony_ci}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_civoid sun_pci_fd_dma_callback(struct ebus_dma_info *p, int event, void *cookie)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	floppy_interrupt(0, NULL);
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci/*
4438c2ecf20Sopenharmony_ci * Floppy probing, we'd like to use /dev/fd0 for a single Floppy on PCI,
4448c2ecf20Sopenharmony_ci * even if this is configured using DS1, thus looks like /dev/fd1 with
4458c2ecf20Sopenharmony_ci * the cabling used in Ultras.
4468c2ecf20Sopenharmony_ci */
4478c2ecf20Sopenharmony_ci#define DOR	(port + 2)
4488c2ecf20Sopenharmony_ci#define MSR	(port + 4)
4498c2ecf20Sopenharmony_ci#define FIFO	(port + 5)
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic void sun_pci_fd_out_byte(unsigned long port, unsigned char val,
4528c2ecf20Sopenharmony_ci			        unsigned long reg)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	unsigned char status;
4558c2ecf20Sopenharmony_ci	int timeout = 1000;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	while (!((status = inb(MSR)) & 0x80) && --timeout)
4588c2ecf20Sopenharmony_ci		udelay(100);
4598c2ecf20Sopenharmony_ci	outb(val, reg);
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic unsigned char sun_pci_fd_sensei(unsigned long port)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	unsigned char result[2] = { 0x70, 0x00 };
4658c2ecf20Sopenharmony_ci	unsigned char status;
4668c2ecf20Sopenharmony_ci	int i = 0;
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	sun_pci_fd_out_byte(port, 0x08, FIFO);
4698c2ecf20Sopenharmony_ci	do {
4708c2ecf20Sopenharmony_ci		int timeout = 1000;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_ci		while (!((status = inb(MSR)) & 0x80) && --timeout)
4738c2ecf20Sopenharmony_ci			udelay(100);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		if (!timeout)
4768c2ecf20Sopenharmony_ci			break;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci		if ((status & 0xf0) == 0xd0)
4798c2ecf20Sopenharmony_ci			result[i++] = inb(FIFO);
4808c2ecf20Sopenharmony_ci		else
4818c2ecf20Sopenharmony_ci			break;
4828c2ecf20Sopenharmony_ci	} while (i < 2);
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	return result[0];
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic void sun_pci_fd_reset(unsigned long port)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	unsigned char mask = 0x00;
4908c2ecf20Sopenharmony_ci	unsigned char status;
4918c2ecf20Sopenharmony_ci	int timeout = 10000;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	outb(0x80, MSR);
4948c2ecf20Sopenharmony_ci	do {
4958c2ecf20Sopenharmony_ci		status = sun_pci_fd_sensei(port);
4968c2ecf20Sopenharmony_ci		if ((status & 0xc0) == 0xc0)
4978c2ecf20Sopenharmony_ci			mask |= 1 << (status & 0x03);
4988c2ecf20Sopenharmony_ci		else
4998c2ecf20Sopenharmony_ci			udelay(100);
5008c2ecf20Sopenharmony_ci	} while ((mask != 0x0f) && --timeout);
5018c2ecf20Sopenharmony_ci}
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_cistatic int sun_pci_fd_test_drive(unsigned long port, int drive)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	unsigned char status, data;
5068c2ecf20Sopenharmony_ci	int timeout = 1000;
5078c2ecf20Sopenharmony_ci	int ready;
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	sun_pci_fd_reset(port);
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	data = (0x10 << drive) | 0x0c | drive;
5128c2ecf20Sopenharmony_ci	sun_pci_fd_out_byte(port, data, DOR);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	sun_pci_fd_out_byte(port, 0x07, FIFO);
5158c2ecf20Sopenharmony_ci	sun_pci_fd_out_byte(port, drive & 0x03, FIFO);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	do {
5188c2ecf20Sopenharmony_ci		udelay(100);
5198c2ecf20Sopenharmony_ci		status = sun_pci_fd_sensei(port);
5208c2ecf20Sopenharmony_ci	} while (((status & 0xc0) == 0x80) && --timeout);
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (!timeout)
5238c2ecf20Sopenharmony_ci		ready = 0;
5248c2ecf20Sopenharmony_ci	else
5258c2ecf20Sopenharmony_ci		ready = (status & 0x10) ? 0 : 1;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	sun_pci_fd_reset(port);
5288c2ecf20Sopenharmony_ci	return ready;
5298c2ecf20Sopenharmony_ci}
5308c2ecf20Sopenharmony_ci#undef FIFO
5318c2ecf20Sopenharmony_ci#undef MSR
5328c2ecf20Sopenharmony_ci#undef DOR
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_cistatic int __init ebus_fdthree_p(struct device_node *dp)
5358c2ecf20Sopenharmony_ci{
5368c2ecf20Sopenharmony_ci	if (of_node_name_eq(dp, "fdthree"))
5378c2ecf20Sopenharmony_ci		return 1;
5388c2ecf20Sopenharmony_ci	if (of_node_name_eq(dp, "floppy")) {
5398c2ecf20Sopenharmony_ci		const char *compat;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci		compat = of_get_property(dp, "compatible", NULL);
5428c2ecf20Sopenharmony_ci		if (compat && !strcmp(compat, "fdthree"))
5438c2ecf20Sopenharmony_ci			return 1;
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci	return 0;
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_cistatic unsigned long __init sun_floppy_init(void)
5498c2ecf20Sopenharmony_ci{
5508c2ecf20Sopenharmony_ci	static int initialized = 0;
5518c2ecf20Sopenharmony_ci	struct device_node *dp;
5528c2ecf20Sopenharmony_ci	struct platform_device *op;
5538c2ecf20Sopenharmony_ci	const char *prop;
5548c2ecf20Sopenharmony_ci	char state[128];
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	if (initialized)
5578c2ecf20Sopenharmony_ci		return sun_floppy_types[0];
5588c2ecf20Sopenharmony_ci	initialized = 1;
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_ci	op = NULL;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	for_each_node_by_name(dp, "SUNW,fdtwo") {
5638c2ecf20Sopenharmony_ci		if (!of_node_name_eq(dp->parent, "sbus"))
5648c2ecf20Sopenharmony_ci			continue;
5658c2ecf20Sopenharmony_ci		op = of_find_device_by_node(dp);
5668c2ecf20Sopenharmony_ci		if (op)
5678c2ecf20Sopenharmony_ci			break;
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci	if (op) {
5708c2ecf20Sopenharmony_ci		floppy_op = op;
5718c2ecf20Sopenharmony_ci		FLOPPY_IRQ = op->archdata.irqs[0];
5728c2ecf20Sopenharmony_ci	} else {
5738c2ecf20Sopenharmony_ci		struct device_node *ebus_dp;
5748c2ecf20Sopenharmony_ci		void __iomem *auxio_reg;
5758c2ecf20Sopenharmony_ci		const char *state_prop;
5768c2ecf20Sopenharmony_ci		unsigned long config;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci		dp = NULL;
5798c2ecf20Sopenharmony_ci		for_each_node_by_name(ebus_dp, "ebus") {
5808c2ecf20Sopenharmony_ci			for (dp = ebus_dp->child; dp; dp = dp->sibling) {
5818c2ecf20Sopenharmony_ci				if (ebus_fdthree_p(dp))
5828c2ecf20Sopenharmony_ci					goto found_fdthree;
5838c2ecf20Sopenharmony_ci			}
5848c2ecf20Sopenharmony_ci		}
5858c2ecf20Sopenharmony_ci	found_fdthree:
5868c2ecf20Sopenharmony_ci		if (!dp)
5878c2ecf20Sopenharmony_ci			return 0;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci		op = of_find_device_by_node(dp);
5908c2ecf20Sopenharmony_ci		if (!op)
5918c2ecf20Sopenharmony_ci			return 0;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci		state_prop = of_get_property(op->dev.of_node, "status", NULL);
5948c2ecf20Sopenharmony_ci		if (state_prop && !strncmp(state_prop, "disabled", 8))
5958c2ecf20Sopenharmony_ci			return 0;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci		FLOPPY_IRQ = op->archdata.irqs[0];
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_ci		/* Make sure the high density bit is set, some systems
6008c2ecf20Sopenharmony_ci		 * (most notably Ultra5/Ultra10) come up with it clear.
6018c2ecf20Sopenharmony_ci		 */
6028c2ecf20Sopenharmony_ci		auxio_reg = (void __iomem *) op->resource[2].start;
6038c2ecf20Sopenharmony_ci		writel(readl(auxio_reg)|0x2, auxio_reg);
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci		sun_floppy_dev = &op->dev;
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci		spin_lock_init(&sun_pci_fd_ebus_dma.lock);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci		/* XXX ioremap */
6108c2ecf20Sopenharmony_ci		sun_pci_fd_ebus_dma.regs = (void __iomem *)
6118c2ecf20Sopenharmony_ci			op->resource[1].start;
6128c2ecf20Sopenharmony_ci		if (!sun_pci_fd_ebus_dma.regs)
6138c2ecf20Sopenharmony_ci			return 0;
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci		sun_pci_fd_ebus_dma.flags = (EBUS_DMA_FLAG_USE_EBDMA_HANDLER |
6168c2ecf20Sopenharmony_ci					     EBUS_DMA_FLAG_TCI_DISABLE);
6178c2ecf20Sopenharmony_ci		sun_pci_fd_ebus_dma.callback = sun_pci_fd_dma_callback;
6188c2ecf20Sopenharmony_ci		sun_pci_fd_ebus_dma.client_cookie = NULL;
6198c2ecf20Sopenharmony_ci		sun_pci_fd_ebus_dma.irq = FLOPPY_IRQ;
6208c2ecf20Sopenharmony_ci		strcpy(sun_pci_fd_ebus_dma.name, "floppy");
6218c2ecf20Sopenharmony_ci		if (ebus_dma_register(&sun_pci_fd_ebus_dma))
6228c2ecf20Sopenharmony_ci			return 0;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci		/* XXX ioremap */
6258c2ecf20Sopenharmony_ci		sun_fdc = (struct sun_flpy_controller *) op->resource[0].start;
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		sun_fdops.fd_inb = sun_pci_fd_inb;
6288c2ecf20Sopenharmony_ci		sun_fdops.fd_outb = sun_pci_fd_outb;
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci		can_use_virtual_dma = use_virtual_dma = 0;
6318c2ecf20Sopenharmony_ci		sun_fdops.fd_enable_dma = sun_pci_fd_enable_dma;
6328c2ecf20Sopenharmony_ci		sun_fdops.fd_disable_dma = sun_pci_fd_disable_dma;
6338c2ecf20Sopenharmony_ci		sun_fdops.fd_set_dma_mode = sun_pci_fd_set_dma_mode;
6348c2ecf20Sopenharmony_ci		sun_fdops.fd_set_dma_addr = sun_pci_fd_set_dma_addr;
6358c2ecf20Sopenharmony_ci		sun_fdops.fd_set_dma_count = sun_pci_fd_set_dma_count;
6368c2ecf20Sopenharmony_ci		sun_fdops.get_dma_residue = sun_pci_get_dma_residue;
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci		sun_fdops.fd_request_irq = sun_pci_fd_request_irq;
6398c2ecf20Sopenharmony_ci		sun_fdops.fd_free_irq = sun_pci_fd_free_irq;
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci		sun_fdops.fd_eject = sun_pci_fd_eject;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci		fdc_status = (unsigned long) &sun_fdc->status_82077;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		/*
6468c2ecf20Sopenharmony_ci		 * XXX: Find out on which machines this is really needed.
6478c2ecf20Sopenharmony_ci		 */
6488c2ecf20Sopenharmony_ci		if (1) {
6498c2ecf20Sopenharmony_ci			sun_pci_broken_drive = 1;
6508c2ecf20Sopenharmony_ci			sun_fdops.fd_outb = sun_pci_fd_broken_outb;
6518c2ecf20Sopenharmony_ci		}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci		allowed_drive_mask = 0;
6548c2ecf20Sopenharmony_ci		if (sun_pci_fd_test_drive((unsigned long)sun_fdc, 0))
6558c2ecf20Sopenharmony_ci			sun_floppy_types[0] = 4;
6568c2ecf20Sopenharmony_ci		if (sun_pci_fd_test_drive((unsigned long)sun_fdc, 1))
6578c2ecf20Sopenharmony_ci			sun_floppy_types[1] = 4;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		/*
6608c2ecf20Sopenharmony_ci		 * Find NS87303 SuperIO config registers (through ecpp).
6618c2ecf20Sopenharmony_ci		 */
6628c2ecf20Sopenharmony_ci		config = 0;
6638c2ecf20Sopenharmony_ci		for (dp = ebus_dp->child; dp; dp = dp->sibling) {
6648c2ecf20Sopenharmony_ci			if (of_node_name_eq(dp, "ecpp")) {
6658c2ecf20Sopenharmony_ci				struct platform_device *ecpp_op;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci				ecpp_op = of_find_device_by_node(dp);
6688c2ecf20Sopenharmony_ci				if (ecpp_op)
6698c2ecf20Sopenharmony_ci					config = ecpp_op->resource[1].start;
6708c2ecf20Sopenharmony_ci				goto config_done;
6718c2ecf20Sopenharmony_ci			}
6728c2ecf20Sopenharmony_ci		}
6738c2ecf20Sopenharmony_ci	config_done:
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci		/*
6768c2ecf20Sopenharmony_ci		 * Sanity check, is this really the NS87303?
6778c2ecf20Sopenharmony_ci		 */
6788c2ecf20Sopenharmony_ci		switch (config & 0x3ff) {
6798c2ecf20Sopenharmony_ci		case 0x02e:
6808c2ecf20Sopenharmony_ci		case 0x15c:
6818c2ecf20Sopenharmony_ci		case 0x26e:
6828c2ecf20Sopenharmony_ci		case 0x398:
6838c2ecf20Sopenharmony_ci			break;
6848c2ecf20Sopenharmony_ci		default:
6858c2ecf20Sopenharmony_ci			config = 0;
6868c2ecf20Sopenharmony_ci		}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci		if (!config)
6898c2ecf20Sopenharmony_ci			return sun_floppy_types[0];
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci		/* Enable PC-AT mode. */
6928c2ecf20Sopenharmony_ci		ns87303_modify(config, ASC, 0, 0xc0);
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci#ifdef PCI_FDC_SWAP_DRIVES
6958c2ecf20Sopenharmony_ci		/*
6968c2ecf20Sopenharmony_ci		 * If only Floppy 1 is present, swap drives.
6978c2ecf20Sopenharmony_ci		 */
6988c2ecf20Sopenharmony_ci		if (!sun_floppy_types[0] && sun_floppy_types[1]) {
6998c2ecf20Sopenharmony_ci			/*
7008c2ecf20Sopenharmony_ci			 * Set the drive exchange bit in FCR on NS87303,
7018c2ecf20Sopenharmony_ci			 * make sure other bits are sane before doing so.
7028c2ecf20Sopenharmony_ci			 */
7038c2ecf20Sopenharmony_ci			ns87303_modify(config, FER, FER_EDM, 0);
7048c2ecf20Sopenharmony_ci			ns87303_modify(config, ASC, ASC_DRV2_SEL, 0);
7058c2ecf20Sopenharmony_ci			ns87303_modify(config, FCR, 0, FCR_LDE);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci			config = sun_floppy_types[0];
7088c2ecf20Sopenharmony_ci			sun_floppy_types[0] = sun_floppy_types[1];
7098c2ecf20Sopenharmony_ci			sun_floppy_types[1] = config;
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci			if (sun_pci_broken_drive != -1) {
7128c2ecf20Sopenharmony_ci				sun_pci_broken_drive = 1 - sun_pci_broken_drive;
7138c2ecf20Sopenharmony_ci				sun_fdops.fd_outb = sun_pci_fd_lde_broken_outb;
7148c2ecf20Sopenharmony_ci			}
7158c2ecf20Sopenharmony_ci		}
7168c2ecf20Sopenharmony_ci#endif /* PCI_FDC_SWAP_DRIVES */
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci		return sun_floppy_types[0];
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci	prop = of_get_property(op->dev.of_node, "status", NULL);
7218c2ecf20Sopenharmony_ci	if (prop && !strncmp(state, "disabled", 8))
7228c2ecf20Sopenharmony_ci		return 0;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	/*
7258c2ecf20Sopenharmony_ci	 * We cannot do of_ioremap here: it does request_region,
7268c2ecf20Sopenharmony_ci	 * which the generic floppy driver tries to do once again.
7278c2ecf20Sopenharmony_ci	 * But we must use the sdev resource values as they have
7288c2ecf20Sopenharmony_ci	 * had parent ranges applied.
7298c2ecf20Sopenharmony_ci	 */
7308c2ecf20Sopenharmony_ci	sun_fdc = (struct sun_flpy_controller *)
7318c2ecf20Sopenharmony_ci		(op->resource[0].start +
7328c2ecf20Sopenharmony_ci		 ((op->resource[0].flags & 0x1ffUL) << 32UL));
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	/* Last minute sanity check... */
7358c2ecf20Sopenharmony_ci	if (sbus_readb(&sun_fdc->status1_82077) == 0xff) {
7368c2ecf20Sopenharmony_ci		sun_fdc = (struct sun_flpy_controller *)-1;
7378c2ecf20Sopenharmony_ci		return 0;
7388c2ecf20Sopenharmony_ci	}
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci        sun_fdops.fd_inb = sun_82077_fd_inb;
7418c2ecf20Sopenharmony_ci        sun_fdops.fd_outb = sun_82077_fd_outb;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	can_use_virtual_dma = use_virtual_dma = 1;
7448c2ecf20Sopenharmony_ci	sun_fdops.fd_enable_dma = sun_fd_enable_dma;
7458c2ecf20Sopenharmony_ci	sun_fdops.fd_disable_dma = sun_fd_disable_dma;
7468c2ecf20Sopenharmony_ci	sun_fdops.fd_set_dma_mode = sun_fd_set_dma_mode;
7478c2ecf20Sopenharmony_ci	sun_fdops.fd_set_dma_addr = sun_fd_set_dma_addr;
7488c2ecf20Sopenharmony_ci	sun_fdops.fd_set_dma_count = sun_fd_set_dma_count;
7498c2ecf20Sopenharmony_ci	sun_fdops.get_dma_residue = sun_get_dma_residue;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	sun_fdops.fd_request_irq = sun_fd_request_irq;
7528c2ecf20Sopenharmony_ci	sun_fdops.fd_free_irq = sun_fd_free_irq;
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci	sun_fdops.fd_eject = sun_fd_eject;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci        fdc_status = (unsigned long) &sun_fdc->status_82077;
7578c2ecf20Sopenharmony_ci
7588c2ecf20Sopenharmony_ci	/* Success... */
7598c2ecf20Sopenharmony_ci	allowed_drive_mask = 0x01;
7608c2ecf20Sopenharmony_ci	sun_floppy_types[0] = 4;
7618c2ecf20Sopenharmony_ci	sun_floppy_types[1] = 0;
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci	return sun_floppy_types[0];
7648c2ecf20Sopenharmony_ci}
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci#define EXTRA_FLOPPY_PARAMS
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(dma_spin_lock);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci#define claim_dma_lock() \
7718c2ecf20Sopenharmony_ci({	unsigned long flags; \
7728c2ecf20Sopenharmony_ci	spin_lock_irqsave(&dma_spin_lock, flags); \
7738c2ecf20Sopenharmony_ci	flags; \
7748c2ecf20Sopenharmony_ci})
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci#define release_dma_lock(__flags) \
7778c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&dma_spin_lock, __flags);
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci#endif /* !(__ASM_SPARC64_FLOPPY_H) */
780