Merge git://git.infradead.org/mtd-2.6
[pandora-kernel.git] / arch / parisc / lib / io.c
1 /*
2  * arch/parisc/lib/io.c
3  *
4  * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
5  * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
6  *
7  * IO accessing functions which shouldn't be inlined because they're too big
8  */
9
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <asm/io.h>
13
14 /* Copies a block of memory to a device in an efficient manner.
15  * Assumes the device can cope with 32-bit transfers.  If it can't,
16  * don't use this function.
17  */
18 void memcpy_toio(volatile void __iomem *dst, const void *src, int count)
19 {
20         if (((unsigned long)dst & 3) != ((unsigned long)src & 3))
21                 goto bytecopy;
22         while ((unsigned long)dst & 3) {
23                 writeb(*(char *)src, dst++);
24                 src++;
25                 count--;
26         }
27         while (count > 3) {
28                 __raw_writel(*(u32 *)src, dst);
29                 src += 4;
30                 dst += 4;
31                 count -= 4;
32         }
33  bytecopy:
34         while (count--) {
35                 writeb(*(char *)src, dst++);
36                 src++;
37         }
38 }
39
40 /*
41 ** Copies a block of memory from a device in an efficient manner.
42 ** Assumes the device can cope with 32-bit transfers.  If it can't,
43 ** don't use this function.
44 **
45 ** CR16 counts on C3000 reading 256 bytes from Symbios 896 RAM:
46 **      27341/64    = 427 cyc per int
47 **      61311/128   = 478 cyc per short
48 **      122637/256  = 479 cyc per byte
49 ** Ergo bus latencies dominant (not transfer size).
50 **      Minimize total number of transfers at cost of CPU cycles.
51 **      TODO: only look at src alignment and adjust the stores to dest.
52 */
53 void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
54 {
55         /* first compare alignment of src/dst */ 
56         if ( (((unsigned long)dst ^ (unsigned long)src) & 1) || (count < 2) )
57                 goto bytecopy;
58
59         if ( (((unsigned long)dst ^ (unsigned long)src) & 2) || (count < 4) )
60                 goto shortcopy;
61
62         /* Then check for misaligned start address */
63         if ((unsigned long)src & 1) {
64                 *(u8 *)dst = readb(src);
65                 src++;
66                 dst++;
67                 count--;
68                 if (count < 2) goto bytecopy;
69         }
70
71         if ((unsigned long)src & 2) {
72                 *(u16 *)dst = __raw_readw(src);
73                 src += 2;
74                 dst += 2;
75                 count -= 2;
76         }
77
78         while (count > 3) {
79                 *(u32 *)dst = __raw_readl(src);
80                 dst += 4;
81                 src += 4;
82                 count -= 4;
83         }
84
85  shortcopy:
86         while (count > 1) {
87                 *(u16 *)dst = __raw_readw(src);
88                 src += 2;
89                 dst += 2;
90                 count -= 2;
91         }
92
93  bytecopy:
94         while (count--) {
95                 *(char *)dst = readb(src);
96                 src++;
97                 dst++;
98         }
99 }
100
101 /* Sets a block of memory on a device to a given value.
102  * Assumes the device can cope with 32-bit transfers.  If it can't,
103  * don't use this function.
104  */
105 void memset_io(volatile void __iomem *addr, unsigned char val, int count)
106 {
107         u32 val32 = (val << 24) | (val << 16) | (val << 8) | val;
108         while ((unsigned long)addr & 3) {
109                 writeb(val, addr++);
110                 count--;
111         }
112         while (count > 3) {
113                 __raw_writel(val32, addr);
114                 addr += 4;
115                 count -= 4;
116         }
117         while (count--) {
118                 writeb(val, addr++);
119         }
120 }
121
122 /*
123  * Read COUNT 8-bit bytes from port PORT into memory starting at
124  * SRC.
125  */
126 void insb (unsigned long port, void *dst, unsigned long count)
127 {
128         unsigned char *p;
129
130         p = (unsigned char *)dst;
131
132         while (((unsigned long)p) & 0x3) {
133                 if (!count)
134                         return;
135                 count--;
136                 *p = inb(port);
137                 p++;
138         }
139
140         while (count >= 4) {
141                 unsigned int w;
142                 count -= 4;
143                 w = inb(port) << 24;
144                 w |= inb(port) << 16;
145                 w |= inb(port) << 8;
146                 w |= inb(port);
147                 *(unsigned int *) p = w;
148                 p += 4;
149         }
150
151         while (count) {
152                 --count;
153                 *p = inb(port);
154                 p++;
155         }
156 }
157
158
159 /*
160  * Read COUNT 16-bit words from port PORT into memory starting at
161  * SRC.  SRC must be at least short aligned.  This is used by the
162  * IDE driver to read disk sectors.  Performance is important, but
163  * the interfaces seems to be slow: just using the inlined version
164  * of the inw() breaks things.
165  */
166 void insw (unsigned long port, void *dst, unsigned long count)
167 {
168         unsigned int l = 0, l2;
169         unsigned char *p;
170
171         p = (unsigned char *)dst;
172         
173         if (!count)
174                 return;
175         
176         switch (((unsigned long)p) & 0x3)
177         {
178          case 0x00:                     /* Buffer 32-bit aligned */
179                 while (count>=2) {
180                         
181                         count -= 2;
182                         l = cpu_to_le16(inw(port)) << 16;
183                         l |= cpu_to_le16(inw(port));
184                         *(unsigned int *)p = l;
185                         p += 4;
186                 }
187                 if (count) {
188                         *(unsigned short *)p = cpu_to_le16(inw(port));
189                 }
190                 break;
191         
192          case 0x02:                     /* Buffer 16-bit aligned */
193                 *(unsigned short *)p = cpu_to_le16(inw(port));
194                 p += 2;
195                 count--;
196                 while (count>=2) {
197                         
198                         count -= 2;
199                         l = cpu_to_le16(inw(port)) << 16;
200                         l |= cpu_to_le16(inw(port));
201                         *(unsigned int *)p = l;
202                         p += 4;
203                 }
204                 if (count) {
205                         *(unsigned short *)p = cpu_to_le16(inw(port));
206                 }
207                 break;
208                 
209          case 0x01:                     /* Buffer 8-bit aligned */
210          case 0x03:
211                 /* I don't bother with 32bit transfers
212                  * in this case, 16bit will have to do -- DE */
213                 --count;
214                 
215                 l = cpu_to_le16(inw(port));
216                 *p = l >> 8;
217                 p++;
218                 while (count--)
219                 {
220                         l2 = cpu_to_le16(inw(port));
221                         *(unsigned short *)p = (l & 0xff) << 8 | (l2 >> 8);
222                         p += 2;
223                         l = l2;
224                 }
225                 *p = l & 0xff;
226                 break;
227         }
228 }
229
230
231
232 /*
233  * Read COUNT 32-bit words from port PORT into memory starting at
234  * SRC. Now works with any alignment in SRC. Performance is important,
235  * but the interfaces seems to be slow: just using the inlined version
236  * of the inl() breaks things.
237  */
238 void insl (unsigned long port, void *dst, unsigned long count)
239 {
240         unsigned int l = 0, l2;
241         unsigned char *p;
242
243         p = (unsigned char *)dst;
244         
245         if (!count)
246                 return;
247         
248         switch (((unsigned long) dst) & 0x3)
249         {
250          case 0x00:                     /* Buffer 32-bit aligned */
251                 while (count--)
252                 {
253                         *(unsigned int *)p = cpu_to_le32(inl(port));
254                         p += 4;
255                 }
256                 break;
257         
258          case 0x02:                     /* Buffer 16-bit aligned */
259                 --count;
260                 
261                 l = cpu_to_le32(inl(port));
262                 *(unsigned short *)p = l >> 16;
263                 p += 2;
264                 
265                 while (count--)
266                 {
267                         l2 = cpu_to_le32(inl(port));
268                         *(unsigned int *)p = (l & 0xffff) << 16 | (l2 >> 16);
269                         p += 4;
270                         l = l2;
271                 }
272                 *(unsigned short *)p = l & 0xffff;
273                 break;
274          case 0x01:                     /* Buffer 8-bit aligned */
275                 --count;
276                 
277                 l = cpu_to_le32(inl(port));
278                 *(unsigned char *)p = l >> 24;
279                 p++;
280                 *(unsigned short *)p = (l >> 8) & 0xffff;
281                 p += 2;
282                 while (count--)
283                 {
284                         l2 = cpu_to_le32(inl(port));
285                         *(unsigned int *)p = (l & 0xff) << 24 | (l2 >> 8);
286                         p += 4;
287                         l = l2;
288                 }
289                 *p = l & 0xff;
290                 break;
291          case 0x03:                     /* Buffer 8-bit aligned */
292                 --count;
293                 
294                 l = cpu_to_le32(inl(port));
295                 *p = l >> 24;
296                 p++;
297                 while (count--)
298                 {
299                         l2 = cpu_to_le32(inl(port));
300                         *(unsigned int *)p = (l & 0xffffff) << 8 | l2 >> 24;
301                         p += 4;
302                         l = l2;
303                 }
304                 *(unsigned short *)p = (l >> 8) & 0xffff;
305                 p += 2;
306                 *p = l & 0xff;
307                 break;
308         }
309 }
310
311
312 /*
313  * Like insb but in the opposite direction.
314  * Don't worry as much about doing aligned memory transfers:
315  * doing byte reads the "slow" way isn't nearly as slow as
316  * doing byte writes the slow way (no r-m-w cycle).
317  */
318 void outsb(unsigned long port, const void * src, unsigned long count)
319 {
320         const unsigned char *p;
321
322         p = (const unsigned char *)src;
323         while (count) {
324                 count--;
325                 outb(*p, port);
326                 p++;
327         }
328 }
329
330 /*
331  * Like insw but in the opposite direction.  This is used by the IDE
332  * driver to write disk sectors.  Performance is important, but the
333  * interfaces seems to be slow: just using the inlined version of the
334  * outw() breaks things.
335  */
336 void outsw (unsigned long port, const void *src, unsigned long count)
337 {
338         unsigned int l = 0, l2;
339         const unsigned char *p;
340
341         p = (const unsigned char *)src;
342         
343         if (!count)
344                 return;
345         
346         switch (((unsigned long)p) & 0x3)
347         {
348          case 0x00:                     /* Buffer 32-bit aligned */
349                 while (count>=2) {
350                         count -= 2;
351                         l = *(unsigned int *)p;
352                         p += 4;
353                         outw(le16_to_cpu(l >> 16), port);
354                         outw(le16_to_cpu(l & 0xffff), port);
355                 }
356                 if (count) {
357                         outw(le16_to_cpu(*(unsigned short*)p), port);
358                 }
359                 break;
360         
361          case 0x02:                     /* Buffer 16-bit aligned */
362                 
363                 outw(le16_to_cpu(*(unsigned short*)p), port);
364                 p += 2;
365                 count--;
366                 
367                 while (count>=2) {
368                         count -= 2;
369                         l = *(unsigned int *)p;
370                         p += 4;
371                         outw(le16_to_cpu(l >> 16), port);
372                         outw(le16_to_cpu(l & 0xffff), port);
373                 }
374                 if (count) {
375                         outw(le16_to_cpu(*(unsigned short *)p), port);
376                 }
377                 break;
378                 
379          case 0x01:                     /* Buffer 8-bit aligned */      
380                 /* I don't bother with 32bit transfers
381                  * in this case, 16bit will have to do -- DE */
382                 
383                 l  = *p << 8;
384                 p++;
385                 count--;
386                 while (count)
387                 {
388                         count--;
389                         l2 = *(unsigned short *)p;
390                         p += 2;
391                         outw(le16_to_cpu(l | l2 >> 8), port);
392                         l = l2 << 8;
393                 }
394                 l2 = *(unsigned char *)p;
395                 outw (le16_to_cpu(l | l2>>8), port);
396                 break;
397         
398         }
399 }
400
401
402 /*
403  * Like insl but in the opposite direction.  This is used by the IDE
404  * driver to write disk sectors.  Works with any alignment in SRC.
405  *  Performance is important, but the interfaces seems to be slow:
406  * just using the inlined version of the outl() breaks things.
407  */
408 void outsl (unsigned long port, const void *src, unsigned long count)
409 {
410         unsigned int l = 0, l2;
411         const unsigned char *p;
412
413         p = (const unsigned char *)src;
414         
415         if (!count)
416                 return;
417         
418         switch (((unsigned long)p) & 0x3)
419         {
420          case 0x00:                     /* Buffer 32-bit aligned */
421                 while (count--)
422                 {
423                         outl(le32_to_cpu(*(unsigned int *)p), port);
424                         p += 4;
425                 }
426                 break;
427         
428          case 0x02:                     /* Buffer 16-bit aligned */
429                 --count;
430                 
431                 l = *(unsigned short *)p;
432                 p += 2;
433                 
434                 while (count--)
435                 {
436                         l2 = *(unsigned int *)p;
437                         p += 4;
438                         outl (le32_to_cpu(l << 16 | l2 >> 16), port);
439                         l = l2;
440                 }
441                 l2 = *(unsigned short *)p;
442                 outl (le32_to_cpu(l << 16 | l2), port);
443                 break;
444          case 0x01:                     /* Buffer 8-bit aligned */
445                 --count;
446
447                 l = *p << 24;
448                 p++;
449                 l |= *(unsigned short *)p << 8;
450                 p += 2;
451
452                 while (count--)
453                 {
454                         l2 = *(unsigned int *)p;
455                         p += 4;
456                         outl (le32_to_cpu(l | l2 >> 24), port);
457                         l = l2 << 8;
458                 }
459                 l2 = *p;
460                 outl (le32_to_cpu(l | l2), port);
461                 break;
462          case 0x03:                     /* Buffer 8-bit aligned */
463                 --count;
464                 
465                 l = *p << 24;
466                 p++;
467
468                 while (count--)
469                 {
470                         l2 = *(unsigned int *)p;
471                         p += 4;
472                         outl (le32_to_cpu(l | l2 >> 8), port);
473                         l = l2 << 24;
474                 }
475                 l2 = *(unsigned short *)p << 16;
476                 p += 2;
477                 l2 |= *p;
478                 outl (le32_to_cpu(l | l2), port);
479                 break;
480         }
481 }
482
483 EXPORT_SYMBOL(insb);
484 EXPORT_SYMBOL(insw);
485 EXPORT_SYMBOL(insl);
486 EXPORT_SYMBOL(outsb);
487 EXPORT_SYMBOL(outsw);
488 EXPORT_SYMBOL(outsl);