| /* |
| * $Id: io.c,v 1.4 2003/08/03 03:05:10 lethal Exp $ |
| * by Greg Banks <gbanks@pocketpenguins.com> |
| * (c) 2000 PocketPenguins Inc |
| * |
| * Derived from io_hd64461.c, which bore the message: |
| * Copyright (C) 2000 YAEGASHI Takeshi |
| * |
| * Typical I/O routines for HD64465 system. |
| */ |
| |
| #include <linux/config.h> |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <asm/io.h> |
| #include <asm/hd64465/hd64465.h> |
| |
| |
| #define HD64465_DEBUG 0 |
| |
| #if HD64465_DEBUG |
| #define DPRINTK(args...) printk(args) |
| #define DIPRINTK(n, args...) if (hd64465_io_debug>(n)) printk(args) |
| #else |
| #define DPRINTK(args...) |
| #define DIPRINTK(n, args...) |
| #endif |
| |
| |
| |
| /* This is a hack suitable only for debugging IO port problems */ |
| int hd64465_io_debug; |
| EXPORT_SYMBOL(hd64465_io_debug); |
| |
| /* Low iomap maps port 0-1K to addresses in 8byte chunks */ |
| #define HD64465_IOMAP_LO_THRESH 0x400 |
| #define HD64465_IOMAP_LO_SHIFT 3 |
| #define HD64465_IOMAP_LO_MASK ((1<<HD64465_IOMAP_LO_SHIFT)-1) |
| #define HD64465_IOMAP_LO_NMAP (HD64465_IOMAP_LO_THRESH>>HD64465_IOMAP_LO_SHIFT) |
| static unsigned long hd64465_iomap_lo[HD64465_IOMAP_LO_NMAP]; |
| static unsigned char hd64465_iomap_lo_shift[HD64465_IOMAP_LO_NMAP]; |
| |
| /* High iomap maps port 1K-64K to addresses in 1K chunks */ |
| #define HD64465_IOMAP_HI_THRESH 0x10000 |
| #define HD64465_IOMAP_HI_SHIFT 10 |
| #define HD64465_IOMAP_HI_MASK ((1<<HD64465_IOMAP_HI_SHIFT)-1) |
| #define HD64465_IOMAP_HI_NMAP (HD64465_IOMAP_HI_THRESH>>HD64465_IOMAP_HI_SHIFT) |
| static unsigned long hd64465_iomap_hi[HD64465_IOMAP_HI_NMAP]; |
| static unsigned char hd64465_iomap_hi_shift[HD64465_IOMAP_HI_NMAP]; |
| |
| #ifndef MAX |
| #define MAX(a,b) ((a)>(b)?(a):(b)) |
| #endif |
| |
| #define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x)) |
| |
| void hd64465_port_map(unsigned short baseport, unsigned int nports, |
| unsigned long addr, unsigned char shift) |
| { |
| unsigned int port, endport = baseport + nports; |
| |
| DPRINTK("hd64465_port_map(base=0x%04hx, n=0x%04hx, addr=0x%08lx,endport=0x%04x)\n", |
| baseport, nports, addr,endport); |
| |
| for (port = baseport ; |
| port < endport && port < HD64465_IOMAP_LO_THRESH ; |
| port += (1<<HD64465_IOMAP_LO_SHIFT)) { |
| DPRINTK(" maplo[0x%x] = 0x%08lx\n", port, addr); |
| hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = addr; |
| hd64465_iomap_lo_shift[port>>HD64465_IOMAP_LO_SHIFT] = shift; |
| addr += (1<<(HD64465_IOMAP_LO_SHIFT)); |
| } |
| |
| for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ; |
| port < endport && port < HD64465_IOMAP_HI_THRESH ; |
| port += (1<<HD64465_IOMAP_HI_SHIFT)) { |
| DPRINTK(" maphi[0x%x] = 0x%08lx\n", port, addr); |
| hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = addr; |
| hd64465_iomap_hi_shift[port>>HD64465_IOMAP_HI_SHIFT] = shift; |
| addr += (1<<(HD64465_IOMAP_HI_SHIFT)); |
| } |
| } |
| EXPORT_SYMBOL(hd64465_port_map); |
| |
| void hd64465_port_unmap(unsigned short baseport, unsigned int nports) |
| { |
| unsigned int port, endport = baseport + nports; |
| |
| DPRINTK("hd64465_port_unmap(base=0x%04hx, n=0x%04hx)\n", |
| baseport, nports); |
| |
| for (port = baseport ; |
| port < endport && port < HD64465_IOMAP_LO_THRESH ; |
| port += (1<<HD64465_IOMAP_LO_SHIFT)) { |
| hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = 0; |
| } |
| |
| for (port = MAX(baseport, HD64465_IOMAP_LO_THRESH) ; |
| port < endport && port < HD64465_IOMAP_HI_THRESH ; |
| port += (1<<HD64465_IOMAP_HI_SHIFT)) { |
| hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = 0; |
| } |
| } |
| EXPORT_SYMBOL(hd64465_port_unmap); |
| |
| unsigned long hd64465_isa_port2addr(unsigned long port) |
| { |
| unsigned long addr = 0; |
| unsigned char shift; |
| |
| /* handle remapping of low IO ports */ |
| if (port < HD64465_IOMAP_LO_THRESH) { |
| addr = hd64465_iomap_lo[port >> HD64465_IOMAP_LO_SHIFT]; |
| shift = hd64465_iomap_lo_shift[port >> HD64465_IOMAP_LO_SHIFT]; |
| if (addr != 0) |
| addr += (port & HD64465_IOMAP_LO_MASK) << shift; |
| else |
| printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port); |
| } else if (port < HD64465_IOMAP_HI_THRESH) { |
| addr = hd64465_iomap_hi[port >> HD64465_IOMAP_HI_SHIFT]; |
| shift = hd64465_iomap_hi_shift[port >> HD64465_IOMAP_HI_SHIFT]; |
| if (addr != 0) |
| addr += (port & HD64465_IOMAP_HI_MASK) << shift; |
| else |
| printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port); |
| } |
| |
| /* HD64465 internal devices (0xb0000000) */ |
| else if (port < 0x20000) |
| addr = CONFIG_HD64465_IOBASE + port - 0x10000; |
| |
| /* Whole physical address space (0xa0000000) */ |
| else |
| addr = P2SEGADDR(port); |
| |
| DIPRINTK(2, "PORT2ADDR(0x%08lx) = 0x%08lx\n", port, addr); |
| |
| return addr; |
| } |
| |
| static inline void delay(void) |
| { |
| ctrl_inw(0xa0000000); |
| } |
| |
| unsigned char hd64465_inb(unsigned long port) |
| { |
| unsigned long addr = PORT2ADDR(port); |
| unsigned long b = (addr == 0 ? 0 : *(volatile unsigned char*)addr); |
| |
| DIPRINTK(0, "inb(%08lx) = %02x\n", addr, (unsigned)b); |
| return b; |
| } |
| |
| unsigned char hd64465_inb_p(unsigned long port) |
| { |
| unsigned long v; |
| unsigned long addr = PORT2ADDR(port); |
| |
| v = (addr == 0 ? 0 : *(volatile unsigned char*)addr); |
| delay(); |
| DIPRINTK(0, "inb_p(%08lx) = %02x\n", addr, (unsigned)v); |
| return v; |
| } |
| |
| unsigned short hd64465_inw(unsigned long port) |
| { |
| unsigned long addr = PORT2ADDR(port); |
| unsigned long b = (addr == 0 ? 0 : *(volatile unsigned short*)addr); |
| DIPRINTK(0, "inw(%08lx) = %04lx\n", addr, b); |
| return b; |
| } |
| |
| unsigned int hd64465_inl(unsigned long port) |
| { |
| unsigned long addr = PORT2ADDR(port); |
| unsigned int b = (addr == 0 ? 0 : *(volatile unsigned long*)addr); |
| DIPRINTK(0, "inl(%08lx) = %08x\n", addr, b); |
| return b; |
| } |
| |
| void hd64465_outb(unsigned char b, unsigned long port) |
| { |
| unsigned long addr = PORT2ADDR(port); |
| |
| DIPRINTK(0, "outb(%02x, %08lx)\n", (unsigned)b, addr); |
| if (addr != 0) |
| *(volatile unsigned char*)addr = b; |
| } |
| |
| void hd64465_outb_p(unsigned char b, unsigned long port) |
| { |
| unsigned long addr = PORT2ADDR(port); |
| |
| DIPRINTK(0, "outb_p(%02x, %08lx)\n", (unsigned)b, addr); |
| if (addr != 0) |
| *(volatile unsigned char*)addr = b; |
| delay(); |
| } |
| |
| void hd64465_outw(unsigned short b, unsigned long port) |
| { |
| unsigned long addr = PORT2ADDR(port); |
| DIPRINTK(0, "outw(%04x, %08lx)\n", (unsigned)b, addr); |
| if (addr != 0) |
| *(volatile unsigned short*)addr = b; |
| } |
| |
| void hd64465_outl(unsigned int b, unsigned long port) |
| { |
| unsigned long addr = PORT2ADDR(port); |
| DIPRINTK(0, "outl(%08x, %08lx)\n", b, addr); |
| if (addr != 0) |
| *(volatile unsigned long*)addr = b; |
| } |
| |