1/* 2 * $Id: io.c,v 1.1.1.1 2007/08/03 18:52:15 Exp $ 3 * by Greg Banks <gbanks@pocketpenguins.com> 4 * (c) 2000 PocketPenguins Inc 5 * 6 * Derived from io_hd64461.c, which bore the message: 7 * Copyright (C) 2000 YAEGASHI Takeshi 8 * 9 * Typical I/O routines for HD64465 system. 10 */ 11 12#include <linux/kernel.h> 13#include <linux/module.h> 14#include <asm/io.h> 15#include <asm/hd64465/hd64465.h> 16 17 18#define HD64465_DEBUG 0 19 20#if HD64465_DEBUG 21#define DPRINTK(args...) printk(args) 22#define DIPRINTK(n, args...) if (hd64465_io_debug>(n)) printk(args) 23#else 24#define DPRINTK(args...) 25#define DIPRINTK(n, args...) 26#endif 27 28 29 30/* This is a hack suitable only for debugging IO port problems */ 31int hd64465_io_debug; 32EXPORT_SYMBOL(hd64465_io_debug); 33 34/* Low iomap maps port 0-1K to addresses in 8byte chunks */ 35#define HD64465_IOMAP_LO_THRESH 0x400 36#define HD64465_IOMAP_LO_SHIFT 3 37#define HD64465_IOMAP_LO_MASK ((1<<HD64465_IOMAP_LO_SHIFT)-1) 38#define HD64465_IOMAP_LO_NMAP (HD64465_IOMAP_LO_THRESH>>HD64465_IOMAP_LO_SHIFT) 39static unsigned long hd64465_iomap_lo[HD64465_IOMAP_LO_NMAP]; 40static unsigned char hd64465_iomap_lo_shift[HD64465_IOMAP_LO_NMAP]; 41 42/* High iomap maps port 1K-64K to addresses in 1K chunks */ 43#define HD64465_IOMAP_HI_THRESH 0x10000 44#define HD64465_IOMAP_HI_SHIFT 10 45#define HD64465_IOMAP_HI_MASK ((1<<HD64465_IOMAP_HI_SHIFT)-1) 46#define HD64465_IOMAP_HI_NMAP (HD64465_IOMAP_HI_THRESH>>HD64465_IOMAP_HI_SHIFT) 47static unsigned long hd64465_iomap_hi[HD64465_IOMAP_HI_NMAP]; 48static unsigned char hd64465_iomap_hi_shift[HD64465_IOMAP_HI_NMAP]; 49 50#define PORT2ADDR(x) (sh_mv.mv_isa_port2addr(x)) 51 52void hd64465_port_map(unsigned short baseport, unsigned int nports, 53 unsigned long addr, unsigned char shift) 54{ 55 unsigned int port, endport = baseport + nports; 56 57 DPRINTK("hd64465_port_map(base=0x%04hx, n=0x%04hx, addr=0x%08lx,endport=0x%04x)\n", 58 baseport, nports, addr,endport); 59 60 for (port = baseport ; 61 port < endport && port < HD64465_IOMAP_LO_THRESH ; 62 port += (1<<HD64465_IOMAP_LO_SHIFT)) { 63 DPRINTK(" maplo[0x%x] = 0x%08lx\n", port, addr); 64 hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = addr; 65 hd64465_iomap_lo_shift[port>>HD64465_IOMAP_LO_SHIFT] = shift; 66 addr += (1<<(HD64465_IOMAP_LO_SHIFT)); 67 } 68 69 for (port = max_t(unsigned int, baseport, HD64465_IOMAP_LO_THRESH); 70 port < endport && port < HD64465_IOMAP_HI_THRESH ; 71 port += (1<<HD64465_IOMAP_HI_SHIFT)) { 72 DPRINTK(" maphi[0x%x] = 0x%08lx\n", port, addr); 73 hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = addr; 74 hd64465_iomap_hi_shift[port>>HD64465_IOMAP_HI_SHIFT] = shift; 75 addr += (1<<(HD64465_IOMAP_HI_SHIFT)); 76 } 77} 78EXPORT_SYMBOL(hd64465_port_map); 79 80void hd64465_port_unmap(unsigned short baseport, unsigned int nports) 81{ 82 unsigned int port, endport = baseport + nports; 83 84 DPRINTK("hd64465_port_unmap(base=0x%04hx, n=0x%04hx)\n", 85 baseport, nports); 86 87 for (port = baseport ; 88 port < endport && port < HD64465_IOMAP_LO_THRESH ; 89 port += (1<<HD64465_IOMAP_LO_SHIFT)) { 90 hd64465_iomap_lo[port>>HD64465_IOMAP_LO_SHIFT] = 0; 91 } 92 93 for (port = max_t(unsigned int, baseport, HD64465_IOMAP_LO_THRESH); 94 port < endport && port < HD64465_IOMAP_HI_THRESH ; 95 port += (1<<HD64465_IOMAP_HI_SHIFT)) { 96 hd64465_iomap_hi[port>>HD64465_IOMAP_HI_SHIFT] = 0; 97 } 98} 99EXPORT_SYMBOL(hd64465_port_unmap); 100 101unsigned long hd64465_isa_port2addr(unsigned long port) 102{ 103 unsigned long addr = 0; 104 unsigned char shift; 105 106 /* handle remapping of low IO ports */ 107 if (port < HD64465_IOMAP_LO_THRESH) { 108 addr = hd64465_iomap_lo[port >> HD64465_IOMAP_LO_SHIFT]; 109 shift = hd64465_iomap_lo_shift[port >> HD64465_IOMAP_LO_SHIFT]; 110 if (addr != 0) 111 addr += (port & HD64465_IOMAP_LO_MASK) << shift; 112 else 113 printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port); 114 } else if (port < HD64465_IOMAP_HI_THRESH) { 115 addr = hd64465_iomap_hi[port >> HD64465_IOMAP_HI_SHIFT]; 116 shift = hd64465_iomap_hi_shift[port >> HD64465_IOMAP_HI_SHIFT]; 117 if (addr != 0) 118 addr += (port & HD64465_IOMAP_HI_MASK) << shift; 119 else 120 printk(KERN_NOTICE "io_hd64465: access to un-mapped port %lx\n", port); 121 } 122 123 /* HD64465 internal devices (0xb0000000) */ 124 else if (port < 0x20000) 125 addr = CONFIG_HD64465_IOBASE + port - 0x10000; 126 127 /* Whole physical address space (0xa0000000) */ 128 else 129 addr = P2SEGADDR(port); 130 131 DIPRINTK(2, "PORT2ADDR(0x%08lx) = 0x%08lx\n", port, addr); 132 133 return addr; 134} 135 136static inline void delay(void) 137{ 138 ctrl_inw(0xa0000000); 139} 140 141unsigned char hd64465_inb(unsigned long port) 142{ 143 unsigned long addr = PORT2ADDR(port); 144 unsigned long b = (addr == 0 ? 0 : *(volatile unsigned char*)addr); 145 146 DIPRINTK(0, "inb(%08lx) = %02x\n", addr, (unsigned)b); 147 return b; 148} 149 150unsigned char hd64465_inb_p(unsigned long port) 151{ 152 unsigned long v; 153 unsigned long addr = PORT2ADDR(port); 154 155 v = (addr == 0 ? 0 : *(volatile unsigned char*)addr); 156 delay(); 157 DIPRINTK(0, "inb_p(%08lx) = %02x\n", addr, (unsigned)v); 158 return v; 159} 160 161unsigned short hd64465_inw(unsigned long port) 162{ 163 unsigned long addr = PORT2ADDR(port); 164 unsigned long b = (addr == 0 ? 0 : *(volatile unsigned short*)addr); 165 DIPRINTK(0, "inw(%08lx) = %04lx\n", addr, b); 166 return b; 167} 168 169unsigned int hd64465_inl(unsigned long port) 170{ 171 unsigned long addr = PORT2ADDR(port); 172 unsigned int b = (addr == 0 ? 0 : *(volatile unsigned long*)addr); 173 DIPRINTK(0, "inl(%08lx) = %08x\n", addr, b); 174 return b; 175} 176 177void hd64465_outb(unsigned char b, unsigned long port) 178{ 179 unsigned long addr = PORT2ADDR(port); 180 181 DIPRINTK(0, "outb(%02x, %08lx)\n", (unsigned)b, addr); 182 if (addr != 0) 183 *(volatile unsigned char*)addr = b; 184} 185 186void hd64465_outb_p(unsigned char b, unsigned long port) 187{ 188 unsigned long addr = PORT2ADDR(port); 189 190 DIPRINTK(0, "outb_p(%02x, %08lx)\n", (unsigned)b, addr); 191 if (addr != 0) 192 *(volatile unsigned char*)addr = b; 193 delay(); 194} 195 196void hd64465_outw(unsigned short b, unsigned long port) 197{ 198 unsigned long addr = PORT2ADDR(port); 199 DIPRINTK(0, "outw(%04x, %08lx)\n", (unsigned)b, addr); 200 if (addr != 0) 201 *(volatile unsigned short*)addr = b; 202} 203 204void hd64465_outl(unsigned int b, unsigned long port) 205{ 206 unsigned long addr = PORT2ADDR(port); 207 DIPRINTK(0, "outl(%08x, %08lx)\n", b, addr); 208 if (addr != 0) 209 *(volatile unsigned long*)addr = b; 210} 211