162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* sun3xflop.h: Sun3/80 specific parts of the floppy driver. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Derived partially from asm-sparc/floppy.h, which is: 562306a36Sopenharmony_ci * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Sun3x version 2/4/2000 Sam Creasey (sammy@sammy.net) 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#ifndef __ASM_SUN3X_FLOPPY_H 1162306a36Sopenharmony_ci#define __ASM_SUN3X_FLOPPY_H 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/pgtable.h> 1462306a36Sopenharmony_ci#include <asm/page.h> 1562306a36Sopenharmony_ci#include <asm/irq.h> 1662306a36Sopenharmony_ci#include <asm/sun3x.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/* default interrupt vector */ 1962306a36Sopenharmony_ci#define SUN3X_FDC_IRQ 0x40 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* some constants */ 2262306a36Sopenharmony_ci#define FCR_TC 0x1 2362306a36Sopenharmony_ci#define FCR_EJECT 0x2 2462306a36Sopenharmony_ci#define FCR_MTRON 0x4 2562306a36Sopenharmony_ci#define FCR_DSEL1 0x8 2662306a36Sopenharmony_ci#define FCR_DSEL0 0x10 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* We don't need no stinkin' I/O port allocation crap. */ 2962306a36Sopenharmony_ci#undef release_region 3062306a36Sopenharmony_ci#undef request_region 3162306a36Sopenharmony_ci#define release_region(X, Y) do { } while(0) 3262306a36Sopenharmony_ci#define request_region(X, Y, Z) (1) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistruct sun3xflop_private { 3562306a36Sopenharmony_ci volatile unsigned char *status_r; 3662306a36Sopenharmony_ci volatile unsigned char *data_r; 3762306a36Sopenharmony_ci volatile unsigned char *fcr_r; 3862306a36Sopenharmony_ci volatile unsigned char *fvr_r; 3962306a36Sopenharmony_ci unsigned char fcr; 4062306a36Sopenharmony_ci} sun3x_fdc; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Super paranoid... */ 4362306a36Sopenharmony_ci#undef HAVE_DISABLE_HLT 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* Routines unique to each controller type on a Sun. */ 4662306a36Sopenharmony_cistatic unsigned char sun3x_82072_fd_inb(int port) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci static int once = 0; 4962306a36Sopenharmony_ci// udelay(5); 5062306a36Sopenharmony_ci switch(port & 7) { 5162306a36Sopenharmony_ci default: 5262306a36Sopenharmony_ci pr_crit("floppy: Asked to read unknown port %d\n", port); 5362306a36Sopenharmony_ci panic("floppy: Port bolixed."); 5462306a36Sopenharmony_ci case 4: /* FD_STATUS */ 5562306a36Sopenharmony_ci return (*sun3x_fdc.status_r) & ~STATUS_DMA; 5662306a36Sopenharmony_ci case 5: /* FD_DATA */ 5762306a36Sopenharmony_ci return (*sun3x_fdc.data_r); 5862306a36Sopenharmony_ci case 7: /* FD_DIR */ 5962306a36Sopenharmony_ci /* ugly hack, I can't find a way to actually detect the disk */ 6062306a36Sopenharmony_ci if(!once) { 6162306a36Sopenharmony_ci once = 1; 6262306a36Sopenharmony_ci return 0x80; 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci }; 6662306a36Sopenharmony_ci panic("sun_82072_fd_inb: How did I get here?"); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic void sun3x_82072_fd_outb(unsigned char value, int port) 7062306a36Sopenharmony_ci{ 7162306a36Sopenharmony_ci// udelay(5); 7262306a36Sopenharmony_ci switch(port & 7) { 7362306a36Sopenharmony_ci default: 7462306a36Sopenharmony_ci pr_crit("floppy: Asked to write to unknown port %d\n", port); 7562306a36Sopenharmony_ci panic("floppy: Port bolixed."); 7662306a36Sopenharmony_ci case 2: /* FD_DOR */ 7762306a36Sopenharmony_ci /* Oh geese, 82072 on the Sun has no DOR register, 7862306a36Sopenharmony_ci * so we make do with taunting the FCR. 7962306a36Sopenharmony_ci * 8062306a36Sopenharmony_ci * ASSUMPTIONS: There will only ever be one floppy 8162306a36Sopenharmony_ci * drive attached to a Sun controller 8262306a36Sopenharmony_ci * and it will be at drive zero. 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci { 8662306a36Sopenharmony_ci unsigned char fcr = sun3x_fdc.fcr; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if(value & 0x10) { 8962306a36Sopenharmony_ci fcr |= (FCR_DSEL0 | FCR_MTRON); 9062306a36Sopenharmony_ci } else 9162306a36Sopenharmony_ci fcr &= ~(FCR_DSEL0 | FCR_MTRON); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if(fcr != sun3x_fdc.fcr) { 9562306a36Sopenharmony_ci *(sun3x_fdc.fcr_r) = fcr; 9662306a36Sopenharmony_ci sun3x_fdc.fcr = fcr; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci case 5: /* FD_DATA */ 10162306a36Sopenharmony_ci *(sun3x_fdc.data_r) = value; 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci case 7: /* FD_DCR */ 10462306a36Sopenharmony_ci *(sun3x_fdc.status_r) = value; 10562306a36Sopenharmony_ci break; 10662306a36Sopenharmony_ci case 4: /* FD_STATUS */ 10762306a36Sopenharmony_ci *(sun3x_fdc.status_r) = value; 10862306a36Sopenharmony_ci break; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci return; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciasmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci register unsigned char st; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci#undef TRACE_FLPY_INT 11962306a36Sopenharmony_ci#define NO_FLOPPY_ASSEMBLER 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#ifdef TRACE_FLPY_INT 12262306a36Sopenharmony_ci static int calls=0; 12362306a36Sopenharmony_ci static int bytes=0; 12462306a36Sopenharmony_ci static int dma_wait=0; 12562306a36Sopenharmony_ci#endif 12662306a36Sopenharmony_ci if(!doing_pdma) { 12762306a36Sopenharmony_ci floppy_interrupt(irq, dev_id); 12862306a36Sopenharmony_ci return IRQ_HANDLED; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci// pr_info("doing pdma\n");// st %x\n", sun_fdc->status_82072); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci#ifdef TRACE_FLPY_INT 13462306a36Sopenharmony_ci if(!calls) 13562306a36Sopenharmony_ci bytes = virtual_dma_count; 13662306a36Sopenharmony_ci#endif 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci { 13962306a36Sopenharmony_ci register int lcount; 14062306a36Sopenharmony_ci register char *lptr; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci for(lcount=virtual_dma_count, lptr=virtual_dma_addr; 14362306a36Sopenharmony_ci lcount; lcount--, lptr++) { 14462306a36Sopenharmony_ci/* st=fd_inb(virtual_dma_port+4) & 0x80 ; */ 14562306a36Sopenharmony_ci st = *(sun3x_fdc.status_r); 14662306a36Sopenharmony_ci/* if(st != 0xa0) */ 14762306a36Sopenharmony_ci/* break; */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if((st & 0x80) == 0) { 15062306a36Sopenharmony_ci virtual_dma_count = lcount; 15162306a36Sopenharmony_ci virtual_dma_addr = lptr; 15262306a36Sopenharmony_ci return IRQ_HANDLED; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if((st & 0x20) == 0) 15662306a36Sopenharmony_ci break; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci if(virtual_dma_mode) 15962306a36Sopenharmony_ci/* fd_outb(*lptr, virtual_dma_port+5); */ 16062306a36Sopenharmony_ci *(sun3x_fdc.data_r) = *lptr; 16162306a36Sopenharmony_ci else 16262306a36Sopenharmony_ci/* *lptr = fd_inb(virtual_dma_port+5); */ 16362306a36Sopenharmony_ci *lptr = *(sun3x_fdc.data_r); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci virtual_dma_count = lcount; 16762306a36Sopenharmony_ci virtual_dma_addr = lptr; 16862306a36Sopenharmony_ci/* st = fd_inb(virtual_dma_port+4); */ 16962306a36Sopenharmony_ci st = *(sun3x_fdc.status_r); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci#ifdef TRACE_FLPY_INT 17362306a36Sopenharmony_ci calls++; 17462306a36Sopenharmony_ci#endif 17562306a36Sopenharmony_ci// pr_info("st=%02x\n", st); 17662306a36Sopenharmony_ci if(st == 0x20) 17762306a36Sopenharmony_ci return IRQ_HANDLED; 17862306a36Sopenharmony_ci if(!(st & 0x20)) { 17962306a36Sopenharmony_ci virtual_dma_residue += virtual_dma_count; 18062306a36Sopenharmony_ci virtual_dma_count=0; 18162306a36Sopenharmony_ci doing_pdma = 0; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci#ifdef TRACE_FLPY_INT 18462306a36Sopenharmony_ci pr_info("count=%x, residue=%x calls=%d bytes=%x dma_wait=%d\n", 18562306a36Sopenharmony_ci virtual_dma_count, virtual_dma_residue, calls, bytes, 18662306a36Sopenharmony_ci dma_wait); 18762306a36Sopenharmony_ci calls = 0; 18862306a36Sopenharmony_ci dma_wait=0; 18962306a36Sopenharmony_ci#endif 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci floppy_interrupt(irq, dev_id); 19262306a36Sopenharmony_ci return IRQ_HANDLED; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci#ifdef TRACE_FLPY_INT 19762306a36Sopenharmony_ci if(!virtual_dma_count) 19862306a36Sopenharmony_ci dma_wait++; 19962306a36Sopenharmony_ci#endif 20062306a36Sopenharmony_ci return IRQ_HANDLED; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic int sun3xflop_request_irq(void) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci static int once = 0; 20662306a36Sopenharmony_ci int error; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if(!once) { 20962306a36Sopenharmony_ci once = 1; 21062306a36Sopenharmony_ci error = request_irq(FLOPPY_IRQ, sun3xflop_hardint, 21162306a36Sopenharmony_ci 0, "floppy", NULL); 21262306a36Sopenharmony_ci return ((error == 0) ? 0 : -1); 21362306a36Sopenharmony_ci } else return 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic void __init floppy_set_flags(int *ints,int param, int param2); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_cistatic int sun3xflop_init(void) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci if(FLOPPY_IRQ < 0x40) 22162306a36Sopenharmony_ci FLOPPY_IRQ = SUN3X_FDC_IRQ; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci sun3x_fdc.status_r = (volatile unsigned char *)SUN3X_FDC; 22462306a36Sopenharmony_ci sun3x_fdc.data_r = (volatile unsigned char *)(SUN3X_FDC+1); 22562306a36Sopenharmony_ci sun3x_fdc.fcr_r = (volatile unsigned char *)SUN3X_FDC_FCR; 22662306a36Sopenharmony_ci sun3x_fdc.fvr_r = (volatile unsigned char *)SUN3X_FDC_FVR; 22762306a36Sopenharmony_ci sun3x_fdc.fcr = 0; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* Last minute sanity check... */ 23062306a36Sopenharmony_ci if(*sun3x_fdc.status_r == 0xff) { 23162306a36Sopenharmony_ci return -1; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci *sun3x_fdc.fvr_r = FLOPPY_IRQ; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci *sun3x_fdc.fcr_r = FCR_TC; 23762306a36Sopenharmony_ci udelay(10); 23862306a36Sopenharmony_ci *sun3x_fdc.fcr_r = 0; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Success... */ 24162306a36Sopenharmony_ci floppy_set_flags(NULL, 1, FD_BROKEN_DCL); // I don't know how to detect this. 24262306a36Sopenharmony_ci allowed_drive_mask = 0x01; 24362306a36Sopenharmony_ci return (int) SUN3X_FDC; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* I'm not precisely sure this eject routine works */ 24762306a36Sopenharmony_cistatic int sun3x_eject(void) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci if(MACH_IS_SUN3X) { 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci sun3x_fdc.fcr |= (FCR_DSEL0 | FCR_EJECT); 25262306a36Sopenharmony_ci *(sun3x_fdc.fcr_r) = sun3x_fdc.fcr; 25362306a36Sopenharmony_ci udelay(10); 25462306a36Sopenharmony_ci sun3x_fdc.fcr &= ~(FCR_DSEL0 | FCR_EJECT); 25562306a36Sopenharmony_ci *(sun3x_fdc.fcr_r) = sun3x_fdc.fcr; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci#define fd_eject(drive) sun3x_eject() 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci#endif /* !(__ASM_SUN3X_FLOPPY_H) */ 264