18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* Architecture specific parts of the Floppy driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Linux/PA-RISC Project (http://www.parisc-linux.org/) 58c2ecf20Sopenharmony_ci * Copyright (C) 2000 Matthew Wilcox (willy a debian . org) 68c2ecf20Sopenharmony_ci * Copyright (C) 2000 Dave Kennedy 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#ifndef __ASM_PARISC_FLOPPY_H 98c2ecf20Sopenharmony_ci#define __ASM_PARISC_FLOPPY_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * The DMA channel used by the floppy controller cannot access data at 168c2ecf20Sopenharmony_ci * addresses >= 16MB 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * Went back to the 1MB limit, as some people had problems with the floppy 198c2ecf20Sopenharmony_ci * driver otherwise. It doesn't matter much for performance anyway, as most 208c2ecf20Sopenharmony_ci * floppy accesses go through the track buffer. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci#define _CROSS_64KB(a,s,vdma) \ 238c2ecf20Sopenharmony_ci(!(vdma) && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64)) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define CROSS_64KB(a,s) _CROSS_64KB(a,s,use_virtual_dma & 1) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define SW fd_routine[use_virtual_dma&1] 298c2ecf20Sopenharmony_ci#define CSW fd_routine[can_use_virtual_dma & 1] 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define fd_inb(base, reg) readb((base) + (reg)) 338c2ecf20Sopenharmony_ci#define fd_outb(value, base, reg) writeb(value, (base) + (reg)) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define fd_request_dma() CSW._request_dma(FLOPPY_DMA,"floppy") 368c2ecf20Sopenharmony_ci#define fd_free_dma() CSW._free_dma(FLOPPY_DMA) 378c2ecf20Sopenharmony_ci#define fd_enable_irq() enable_irq(FLOPPY_IRQ) 388c2ecf20Sopenharmony_ci#define fd_disable_irq() disable_irq(FLOPPY_IRQ) 398c2ecf20Sopenharmony_ci#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL) 408c2ecf20Sopenharmony_ci#define fd_get_dma_residue() SW._get_dma_residue(FLOPPY_DMA) 418c2ecf20Sopenharmony_ci#define fd_dma_mem_alloc(size) SW._dma_mem_alloc(size) 428c2ecf20Sopenharmony_ci#define fd_dma_setup(addr, size, mode, io) SW._dma_setup(addr, size, mode, io) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define FLOPPY_CAN_FALLBACK_ON_NODMA 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic int virtual_dma_count=0; 478c2ecf20Sopenharmony_cistatic int virtual_dma_residue=0; 488c2ecf20Sopenharmony_cistatic char *virtual_dma_addr=0; 498c2ecf20Sopenharmony_cistatic int virtual_dma_mode=0; 508c2ecf20Sopenharmony_cistatic int doing_pdma=0; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci register unsigned char st; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#undef TRACE_FLPY_INT 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 598c2ecf20Sopenharmony_ci static int calls=0; 608c2ecf20Sopenharmony_ci static int bytes=0; 618c2ecf20Sopenharmony_ci static int dma_wait=0; 628c2ecf20Sopenharmony_ci#endif 638c2ecf20Sopenharmony_ci if (!doing_pdma) { 648c2ecf20Sopenharmony_ci floppy_interrupt(irq, dev_id, regs); 658c2ecf20Sopenharmony_ci return; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 698c2ecf20Sopenharmony_ci if(!calls) 708c2ecf20Sopenharmony_ci bytes = virtual_dma_count; 718c2ecf20Sopenharmony_ci#endif 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci { 748c2ecf20Sopenharmony_ci register int lcount; 758c2ecf20Sopenharmony_ci register char *lptr = virtual_dma_addr; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci for (lcount = virtual_dma_count; lcount; lcount--) { 788c2ecf20Sopenharmony_ci st = fd_inb(virtual_dma_port, FD_STATUS); 798c2ecf20Sopenharmony_ci st &= STATUS_DMA | STATUS_READY; 808c2ecf20Sopenharmony_ci if (st != (STATUS_DMA | STATUS_READY)) 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci if (virtual_dma_mode) { 838c2ecf20Sopenharmony_ci fd_outb(*lptr, virtual_dma_port, FD_DATA); 848c2ecf20Sopenharmony_ci } else { 858c2ecf20Sopenharmony_ci *lptr = fd_inb(virtual_dma_port, FD_DATA); 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci lptr++; 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci virtual_dma_count = lcount; 908c2ecf20Sopenharmony_ci virtual_dma_addr = lptr; 918c2ecf20Sopenharmony_ci st = fd_inb(virtual_dma_port, FD_STATUS); 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 958c2ecf20Sopenharmony_ci calls++; 968c2ecf20Sopenharmony_ci#endif 978c2ecf20Sopenharmony_ci if (st == STATUS_DMA) 988c2ecf20Sopenharmony_ci return; 998c2ecf20Sopenharmony_ci if (!(st & STATUS_DMA)) { 1008c2ecf20Sopenharmony_ci virtual_dma_residue += virtual_dma_count; 1018c2ecf20Sopenharmony_ci virtual_dma_count = 0; 1028c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 1038c2ecf20Sopenharmony_ci printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n", 1048c2ecf20Sopenharmony_ci virtual_dma_count, virtual_dma_residue, calls, bytes, 1058c2ecf20Sopenharmony_ci dma_wait); 1068c2ecf20Sopenharmony_ci calls = 0; 1078c2ecf20Sopenharmony_ci dma_wait=0; 1088c2ecf20Sopenharmony_ci#endif 1098c2ecf20Sopenharmony_ci doing_pdma = 0; 1108c2ecf20Sopenharmony_ci floppy_interrupt(irq, dev_id, regs); 1118c2ecf20Sopenharmony_ci return; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci#ifdef TRACE_FLPY_INT 1148c2ecf20Sopenharmony_ci if (!virtual_dma_count) 1158c2ecf20Sopenharmony_ci dma_wait++; 1168c2ecf20Sopenharmony_ci#endif 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic void fd_disable_dma(void) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci if(! (can_use_virtual_dma & 1)) 1228c2ecf20Sopenharmony_ci disable_dma(FLOPPY_DMA); 1238c2ecf20Sopenharmony_ci doing_pdma = 0; 1248c2ecf20Sopenharmony_ci virtual_dma_residue += virtual_dma_count; 1258c2ecf20Sopenharmony_ci virtual_dma_count=0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic int vdma_request_dma(unsigned int dmanr, const char * device_id) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci return 0; 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic void vdma_nop(unsigned int dummy) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int vdma_get_dma_residue(unsigned int dummy) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci return virtual_dma_count + virtual_dma_residue; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int fd_request_irq(void) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci if(can_use_virtual_dma) 1478c2ecf20Sopenharmony_ci return request_irq(FLOPPY_IRQ, floppy_hardint, 1488c2ecf20Sopenharmony_ci 0, "floppy", NULL); 1498c2ecf20Sopenharmony_ci else 1508c2ecf20Sopenharmony_ci return request_irq(FLOPPY_IRQ, floppy_interrupt, 1518c2ecf20Sopenharmony_ci 0, "floppy", NULL); 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic unsigned long dma_mem_alloc(unsigned long size) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci return __get_dma_pages(GFP_KERNEL, get_order(size)); 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic unsigned long vdma_mem_alloc(unsigned long size) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci return (unsigned long) vmalloc(size); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define nodma_mem_alloc(size) vdma_mem_alloc(size) 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic void _fd_dma_mem_free(unsigned long addr, unsigned long size) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci if((unsigned int) addr >= (unsigned int) high_memory) 1718c2ecf20Sopenharmony_ci return vfree((void *)addr); 1728c2ecf20Sopenharmony_ci else 1738c2ecf20Sopenharmony_ci free_pages(addr, get_order(size)); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci#define fd_dma_mem_free(addr, size) _fd_dma_mem_free(addr, size) 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic void _fd_chose_dma_mode(char *addr, unsigned long size) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci if(can_use_virtual_dma == 2) { 1818c2ecf20Sopenharmony_ci if((unsigned int) addr >= (unsigned int) high_memory || 1828c2ecf20Sopenharmony_ci virt_to_bus(addr) >= 0x1000000 || 1838c2ecf20Sopenharmony_ci _CROSS_64KB(addr, size, 0)) 1848c2ecf20Sopenharmony_ci use_virtual_dma = 1; 1858c2ecf20Sopenharmony_ci else 1868c2ecf20Sopenharmony_ci use_virtual_dma = 0; 1878c2ecf20Sopenharmony_ci } else { 1888c2ecf20Sopenharmony_ci use_virtual_dma = can_use_virtual_dma & 1; 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci#define fd_chose_dma_mode(addr, size) _fd_chose_dma_mode(addr, size) 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic int vdma_dma_setup(char *addr, unsigned long size, int mode, int io) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci doing_pdma = 1; 1988c2ecf20Sopenharmony_ci virtual_dma_port = io; 1998c2ecf20Sopenharmony_ci virtual_dma_mode = (mode == DMA_MODE_WRITE); 2008c2ecf20Sopenharmony_ci virtual_dma_addr = addr; 2018c2ecf20Sopenharmony_ci virtual_dma_count = size; 2028c2ecf20Sopenharmony_ci virtual_dma_residue = 0; 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic int hard_dma_setup(char *addr, unsigned long size, int mode, int io) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci#ifdef FLOPPY_SANITY_CHECK 2098c2ecf20Sopenharmony_ci if (CROSS_64KB(addr, size)) { 2108c2ecf20Sopenharmony_ci printk("DMA crossing 64-K boundary %p-%p\n", addr, addr+size); 2118c2ecf20Sopenharmony_ci return -1; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci#endif 2148c2ecf20Sopenharmony_ci /* actual, physical DMA */ 2158c2ecf20Sopenharmony_ci doing_pdma = 0; 2168c2ecf20Sopenharmony_ci clear_dma_ff(FLOPPY_DMA); 2178c2ecf20Sopenharmony_ci set_dma_mode(FLOPPY_DMA,mode); 2188c2ecf20Sopenharmony_ci set_dma_addr(FLOPPY_DMA,virt_to_bus(addr)); 2198c2ecf20Sopenharmony_ci set_dma_count(FLOPPY_DMA,size); 2208c2ecf20Sopenharmony_ci enable_dma(FLOPPY_DMA); 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic struct fd_routine_l { 2258c2ecf20Sopenharmony_ci int (*_request_dma)(unsigned int dmanr, const char * device_id); 2268c2ecf20Sopenharmony_ci void (*_free_dma)(unsigned int dmanr); 2278c2ecf20Sopenharmony_ci int (*_get_dma_residue)(unsigned int dummy); 2288c2ecf20Sopenharmony_ci unsigned long (*_dma_mem_alloc) (unsigned long size); 2298c2ecf20Sopenharmony_ci int (*_dma_setup)(char *addr, unsigned long size, int mode, int io); 2308c2ecf20Sopenharmony_ci} fd_routine[] = { 2318c2ecf20Sopenharmony_ci { 2328c2ecf20Sopenharmony_ci request_dma, 2338c2ecf20Sopenharmony_ci free_dma, 2348c2ecf20Sopenharmony_ci get_dma_residue, 2358c2ecf20Sopenharmony_ci dma_mem_alloc, 2368c2ecf20Sopenharmony_ci hard_dma_setup 2378c2ecf20Sopenharmony_ci }, 2388c2ecf20Sopenharmony_ci { 2398c2ecf20Sopenharmony_ci vdma_request_dma, 2408c2ecf20Sopenharmony_ci vdma_nop, 2418c2ecf20Sopenharmony_ci vdma_get_dma_residue, 2428c2ecf20Sopenharmony_ci vdma_mem_alloc, 2438c2ecf20Sopenharmony_ci vdma_dma_setup 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci}; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic int FDC1 = 0x3f0; /* Lies. Floppy controller is memory mapped, not io mapped */ 2498c2ecf20Sopenharmony_cistatic int FDC2 = -1; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci#define FLOPPY0_TYPE 0 2528c2ecf20Sopenharmony_ci#define FLOPPY1_TYPE 0 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#define N_FDC 1 2558c2ecf20Sopenharmony_ci#define N_DRIVE 8 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci#define EXTRA_FLOPPY_PARAMS 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci#endif /* __ASM_PARISC_FLOPPY_H */ 260