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