18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* sun3xflop.h: Sun3/80 specific parts of the floppy driver. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Derived partially from asm-sparc/floppy.h, which is: 58c2ecf20Sopenharmony_ci * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Sun3x version 2/4/2000 Sam Creasey (sammy@sammy.net) 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#ifndef __ASM_SUN3X_FLOPPY_H 118c2ecf20Sopenharmony_ci#define __ASM_SUN3X_FLOPPY_H 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/pgtable.h> 148c2ecf20Sopenharmony_ci#include <asm/page.h> 158c2ecf20Sopenharmony_ci#include <asm/irq.h> 168c2ecf20Sopenharmony_ci#include <asm/sun3x.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* default interrupt vector */ 198c2ecf20Sopenharmony_ci#define SUN3X_FDC_IRQ 0x40 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* some constants */ 228c2ecf20Sopenharmony_ci#define FCR_TC 0x1 238c2ecf20Sopenharmony_ci#define FCR_EJECT 0x2 248c2ecf20Sopenharmony_ci#define FCR_MTRON 0x4 258c2ecf20Sopenharmony_ci#define FCR_DSEL1 0x8 268c2ecf20Sopenharmony_ci#define FCR_DSEL0 0x10 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* We don't need no stinkin' I/O port allocation crap. */ 298c2ecf20Sopenharmony_ci#undef release_region 308c2ecf20Sopenharmony_ci#undef request_region 318c2ecf20Sopenharmony_ci#define release_region(X, Y) do { } while(0) 328c2ecf20Sopenharmony_ci#define request_region(X, Y, Z) (1) 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistruct sun3xflop_private { 358c2ecf20Sopenharmony_ci volatile unsigned char *status_r; 368c2ecf20Sopenharmony_ci volatile unsigned char *data_r; 378c2ecf20Sopenharmony_ci volatile unsigned char *fcr_r; 388c2ecf20Sopenharmony_ci volatile unsigned char *fvr_r; 398c2ecf20Sopenharmony_ci unsigned char fcr; 408c2ecf20Sopenharmony_ci} sun3x_fdc; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* Super paranoid... */ 438c2ecf20Sopenharmony_ci#undef HAVE_DISABLE_HLT 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* Routines unique to each controller type on a Sun. */ 468c2ecf20Sopenharmony_cistatic unsigned char sun3x_82072_fd_inb(int port) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci static int once = 0; 498c2ecf20Sopenharmony_ci// udelay(5); 508c2ecf20Sopenharmony_ci switch(port & 7) { 518c2ecf20Sopenharmony_ci default: 528c2ecf20Sopenharmony_ci pr_crit("floppy: Asked to read unknown port %d\n", port); 538c2ecf20Sopenharmony_ci panic("floppy: Port bolixed."); 548c2ecf20Sopenharmony_ci case 4: /* FD_STATUS */ 558c2ecf20Sopenharmony_ci return (*sun3x_fdc.status_r) & ~STATUS_DMA; 568c2ecf20Sopenharmony_ci case 5: /* FD_DATA */ 578c2ecf20Sopenharmony_ci return (*sun3x_fdc.data_r); 588c2ecf20Sopenharmony_ci case 7: /* FD_DIR */ 598c2ecf20Sopenharmony_ci /* ugly hack, I can't find a way to actually detect the disk */ 608c2ecf20Sopenharmony_ci if(!once) { 618c2ecf20Sopenharmony_ci once = 1; 628c2ecf20Sopenharmony_ci return 0x80; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci return 0; 658c2ecf20Sopenharmony_ci }; 668c2ecf20Sopenharmony_ci panic("sun_82072_fd_inb: How did I get here?"); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void sun3x_82072_fd_outb(unsigned char value, int port) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci// udelay(5); 728c2ecf20Sopenharmony_ci switch(port & 7) { 738c2ecf20Sopenharmony_ci default: 748c2ecf20Sopenharmony_ci pr_crit("floppy: Asked to write to unknown port %d\n", port); 758c2ecf20Sopenharmony_ci panic("floppy: Port bolixed."); 768c2ecf20Sopenharmony_ci case 2: /* FD_DOR */ 778c2ecf20Sopenharmony_ci /* Oh geese, 82072 on the Sun has no DOR register, 788c2ecf20Sopenharmony_ci * so we make do with taunting the FCR. 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * ASSUMPTIONS: There will only ever be one floppy 818c2ecf20Sopenharmony_ci * drive attached to a Sun controller 828c2ecf20Sopenharmony_ci * and it will be at drive zero. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci { 868c2ecf20Sopenharmony_ci unsigned char fcr = sun3x_fdc.fcr; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if(value & 0x10) { 898c2ecf20Sopenharmony_ci fcr |= (FCR_DSEL0 | FCR_MTRON); 908c2ecf20Sopenharmony_ci } else 918c2ecf20Sopenharmony_ci fcr &= ~(FCR_DSEL0 | FCR_MTRON); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if(fcr != sun3x_fdc.fcr) { 958c2ecf20Sopenharmony_ci *(sun3x_fdc.fcr_r) = fcr; 968c2ecf20Sopenharmony_ci sun3x_fdc.fcr = fcr; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case 5: /* FD_DATA */ 1018c2ecf20Sopenharmony_ci *(sun3x_fdc.data_r) = value; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci case 7: /* FD_DCR */ 1048c2ecf20Sopenharmony_ci *(sun3x_fdc.status_r) = value; 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci case 4: /* FD_STATUS */ 1078c2ecf20Sopenharmony_ci *(sun3x_fdc.status_r) = value; 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci }; 1108c2ecf20Sopenharmony_ci return; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ciasmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci register unsigned char st; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci#undef TRACE_FLPY_INT 1198c2ecf20Sopenharmony_ci#define NO_FLOPPY_ASSEMBLER 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 1228c2ecf20Sopenharmony_ci static int calls=0; 1238c2ecf20Sopenharmony_ci static int bytes=0; 1248c2ecf20Sopenharmony_ci static int dma_wait=0; 1258c2ecf20Sopenharmony_ci#endif 1268c2ecf20Sopenharmony_ci if(!doing_pdma) { 1278c2ecf20Sopenharmony_ci floppy_interrupt(irq, dev_id); 1288c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci// pr_info("doing pdma\n");// st %x\n", sun_fdc->status_82072); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 1348c2ecf20Sopenharmony_ci if(!calls) 1358c2ecf20Sopenharmony_ci bytes = virtual_dma_count; 1368c2ecf20Sopenharmony_ci#endif 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci { 1398c2ecf20Sopenharmony_ci register int lcount; 1408c2ecf20Sopenharmony_ci register char *lptr; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci for(lcount=virtual_dma_count, lptr=virtual_dma_addr; 1438c2ecf20Sopenharmony_ci lcount; lcount--, lptr++) { 1448c2ecf20Sopenharmony_ci/* st=fd_inb(virtual_dma_port+4) & 0x80 ; */ 1458c2ecf20Sopenharmony_ci st = *(sun3x_fdc.status_r); 1468c2ecf20Sopenharmony_ci/* if(st != 0xa0) */ 1478c2ecf20Sopenharmony_ci/* break; */ 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if((st & 0x80) == 0) { 1508c2ecf20Sopenharmony_ci virtual_dma_count = lcount; 1518c2ecf20Sopenharmony_ci virtual_dma_addr = lptr; 1528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if((st & 0x20) == 0) 1568c2ecf20Sopenharmony_ci break; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if(virtual_dma_mode) 1598c2ecf20Sopenharmony_ci/* fd_outb(*lptr, virtual_dma_port+5); */ 1608c2ecf20Sopenharmony_ci *(sun3x_fdc.data_r) = *lptr; 1618c2ecf20Sopenharmony_ci else 1628c2ecf20Sopenharmony_ci/* *lptr = fd_inb(virtual_dma_port+5); */ 1638c2ecf20Sopenharmony_ci *lptr = *(sun3x_fdc.data_r); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci virtual_dma_count = lcount; 1678c2ecf20Sopenharmony_ci virtual_dma_addr = lptr; 1688c2ecf20Sopenharmony_ci/* st = fd_inb(virtual_dma_port+4); */ 1698c2ecf20Sopenharmony_ci st = *(sun3x_fdc.status_r); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 1738c2ecf20Sopenharmony_ci calls++; 1748c2ecf20Sopenharmony_ci#endif 1758c2ecf20Sopenharmony_ci// pr_info("st=%02x\n", st); 1768c2ecf20Sopenharmony_ci if(st == 0x20) 1778c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1788c2ecf20Sopenharmony_ci if(!(st & 0x20)) { 1798c2ecf20Sopenharmony_ci virtual_dma_residue += virtual_dma_count; 1808c2ecf20Sopenharmony_ci virtual_dma_count=0; 1818c2ecf20Sopenharmony_ci doing_pdma = 0; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 1848c2ecf20Sopenharmony_ci pr_info("count=%x, residue=%x calls=%d bytes=%x dma_wait=%d\n", 1858c2ecf20Sopenharmony_ci virtual_dma_count, virtual_dma_residue, calls, bytes, 1868c2ecf20Sopenharmony_ci dma_wait); 1878c2ecf20Sopenharmony_ci calls = 0; 1888c2ecf20Sopenharmony_ci dma_wait=0; 1898c2ecf20Sopenharmony_ci#endif 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci floppy_interrupt(irq, dev_id); 1928c2ecf20Sopenharmony_ci return IRQ_HANDLED; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 1978c2ecf20Sopenharmony_ci if(!virtual_dma_count) 1988c2ecf20Sopenharmony_ci dma_wait++; 1998c2ecf20Sopenharmony_ci#endif 2008c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int sun3xflop_request_irq(void) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci static int once = 0; 2068c2ecf20Sopenharmony_ci int error; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if(!once) { 2098c2ecf20Sopenharmony_ci once = 1; 2108c2ecf20Sopenharmony_ci error = request_irq(FLOPPY_IRQ, sun3xflop_hardint, 2118c2ecf20Sopenharmony_ci 0, "floppy", NULL); 2128c2ecf20Sopenharmony_ci return ((error == 0) ? 0 : -1); 2138c2ecf20Sopenharmony_ci } else return 0; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic void __init floppy_set_flags(int *ints,int param, int param2); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int sun3xflop_init(void) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci if(FLOPPY_IRQ < 0x40) 2218c2ecf20Sopenharmony_ci FLOPPY_IRQ = SUN3X_FDC_IRQ; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci sun3x_fdc.status_r = (volatile unsigned char *)SUN3X_FDC; 2248c2ecf20Sopenharmony_ci sun3x_fdc.data_r = (volatile unsigned char *)(SUN3X_FDC+1); 2258c2ecf20Sopenharmony_ci sun3x_fdc.fcr_r = (volatile unsigned char *)SUN3X_FDC_FCR; 2268c2ecf20Sopenharmony_ci sun3x_fdc.fvr_r = (volatile unsigned char *)SUN3X_FDC_FVR; 2278c2ecf20Sopenharmony_ci sun3x_fdc.fcr = 0; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Last minute sanity check... */ 2308c2ecf20Sopenharmony_ci if(*sun3x_fdc.status_r == 0xff) { 2318c2ecf20Sopenharmony_ci return -1; 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci *sun3x_fdc.fvr_r = FLOPPY_IRQ; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci *sun3x_fdc.fcr_r = FCR_TC; 2378c2ecf20Sopenharmony_ci udelay(10); 2388c2ecf20Sopenharmony_ci *sun3x_fdc.fcr_r = 0; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Success... */ 2418c2ecf20Sopenharmony_ci floppy_set_flags(NULL, 1, FD_BROKEN_DCL); // I don't know how to detect this. 2428c2ecf20Sopenharmony_ci allowed_drive_mask = 0x01; 2438c2ecf20Sopenharmony_ci return (int) SUN3X_FDC; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci/* I'm not precisely sure this eject routine works */ 2478c2ecf20Sopenharmony_cistatic int sun3x_eject(void) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci if(MACH_IS_SUN3X) { 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci sun3x_fdc.fcr |= (FCR_DSEL0 | FCR_EJECT); 2528c2ecf20Sopenharmony_ci *(sun3x_fdc.fcr_r) = sun3x_fdc.fcr; 2538c2ecf20Sopenharmony_ci udelay(10); 2548c2ecf20Sopenharmony_ci sun3x_fdc.fcr &= ~(FCR_DSEL0 | FCR_EJECT); 2558c2ecf20Sopenharmony_ci *(sun3x_fdc.fcr_r) = sun3x_fdc.fcr; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return 0; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci#define fd_eject(drive) sun3x_eject() 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci#endif /* !(__ASM_SUN3X_FLOPPY_H) */ 264