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