ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / arm / mach-lh7a40x / ide-lpd7a40x.c
1 /* arch/arm/mach-lh7a40x/ide-lpd7a40x.c
2  *
3  *  Copyright (C) 2004 Logic Product Development
4  *
5  *  This program is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU General Public License
7  *  version 2 as published by the Free Software Foundation.
8  *
9  */
10
11
12 #include <linux/config.h>
13 #include <linux/ide.h>
14
15 #include <asm/io.h>
16
17 #define IOBARRIER_READ          readl (IOBARRIER_VIRT)
18
19 static u8 lpd7a40x_ide_inb (unsigned long port)
20 {
21         u16 v = (u16) readw (port & ~0x1);
22         IOBARRIER_READ;
23         if (port & 0x1)
24                 v >>= 8;
25         return v & 0xff;
26 }
27
28 static u16 lpd7a40x_ide_inw (unsigned long port)
29 {
30         u16 v = (u16) readw (port);
31         IOBARRIER_READ;
32         return v;
33 }
34
35 static void lpd7a40x_ide_insw (unsigned long port, void *addr, u32 count)
36 {
37         while (count--) {
38                 *((u16*) addr)++ = (u16) readw (port);
39                 IOBARRIER_READ;
40         }
41 }
42
43 static u32 lpd7a40x_ide_inl (unsigned long port)
44 {
45         u32 v = (u16) readw (port);
46         IOBARRIER_READ;
47         v |= (u16) readw (port + 2);
48         IOBARRIER_READ;
49
50         return v;
51 }
52
53 static void lpd7a40x_ide_insl (unsigned long port, void *addr, u32 count)
54 {
55         while (count--) {
56                 *((u16*) addr)++ = (u16) readw (port);
57                 IOBARRIER_READ;
58                 *((u16*) addr)++ = (u16) readw (port + 2);
59                 IOBARRIER_READ;
60         }
61 }
62
63 /* lpd7a40x_ide_outb -- this function is complicated by the fact that
64  * the user wants to be able to do byte IO and the hardware cannot.
65  * In order to write the high byte, we need to write a short.  So, we
66  * read before writing in order to maintain the register values that
67  * shouldn't change.  This isn't a good idea for the data IO registers
68  * since reading from them will not return the current value.  We
69  * expect that this function handles the control register adequately.
70 */
71
72 static void lpd7a40x_ide_outb (u8 valueUser, unsigned long port)
73 {
74         /* Block writes to SELECT register.  Draconian, but the only
75          * way to cope with this hardware configuration without
76          * modifying the SELECT_DRIVE call in the ide driver. */
77         if ((port & 0xf) == 0x6)
78                 return;
79
80         if (port & 0x1) {       /* Perform read before write.  Only
81                                  * the COMMAND register needs
82                                  * this.  */
83                 u16 value = (u16) readw (port & ~0x1);
84                 IOBARRIER_READ;
85                 value = (value & 0x00ff) | (valueUser << 8);
86                 writew (value, port & ~0x1);
87                 IOBARRIER_READ;
88         }
89         else {                  /* Allow low-byte writes which seem to
90                                  * be OK. */
91                 writeb (valueUser, port);
92                 IOBARRIER_READ;
93         }
94 }
95
96 static void lpd7a40x_ide_outbsync (ide_drive_t *drive, u8 value,
97                                    unsigned long port)
98 {
99         lpd7a40x_ide_outb (value, port);
100 }
101
102 static void lpd7a40x_ide_outw (u16 value, unsigned long port)
103 {
104         writew (value, port);
105         IOBARRIER_READ;
106 }
107
108 static void lpd7a40x_ide_outsw (unsigned long port, void *addr, u32 count)
109 {
110         while (count-- > 0) {
111                 writew (*((u16*) addr)++, port);
112                 IOBARRIER_READ;
113         }
114 }
115
116 static void lpd7a40x_ide_outl (u32 value, unsigned long port)
117 {
118         writel (value, port);
119         IOBARRIER_READ;
120 }
121
122 static void lpd7a40x_ide_outsl (unsigned long port, void *addr, u32 count)
123 {
124         while (count-- > 0) {
125                 writel (*((u32*) addr)++, port);
126                 IOBARRIER_READ;
127         }
128 }
129
130 void lpd7a40x_SELECT_DRIVE (ide_drive_t *drive)
131 {
132         unsigned jifStart = jiffies;
133 #define WAIT_TIME       (30*HZ/1000)
134
135         /* Check for readiness. */
136         while ((HWIF(drive)->INB(IDE_STATUS_REG) & 0x40) == 0)
137                 if (jifStart <= jiffies + WAIT_TIME)
138                         return;
139
140         /* Only allow one drive.
141            For more information, see Documentation/arm/Sharp-LH/ */
142         if (drive->select.all & (1<<4))
143                 return;
144
145         /* OUTW so that the IDLE_IMMEDIATE (and not NOP) command is sent. */
146         HWIF(drive)->OUTW(drive->select.all | 0xe100, IDE_SELECT_REG);
147 }
148
149 void lpd7a40x_hwif_ioops (ide_hwif_t *hwif)
150 {
151         hwif->mmio      = 2;    /* Just for show */
152         hwif->irq       = IDE_NO_IRQ;   /* Stop this probing */
153
154         hwif->OUTB      = lpd7a40x_ide_outb;
155         hwif->OUTBSYNC  = lpd7a40x_ide_outbsync;
156         hwif->OUTW      = lpd7a40x_ide_outw;
157         hwif->OUTL      = lpd7a40x_ide_outl;
158         hwif->OUTSW     = lpd7a40x_ide_outsw;
159         hwif->OUTSL     = lpd7a40x_ide_outsl;
160         hwif->INB       = lpd7a40x_ide_inb;
161         hwif->INW       = lpd7a40x_ide_inw;
162         hwif->INL       = lpd7a40x_ide_inl;
163         hwif->INSW      = lpd7a40x_ide_insw;
164         hwif->INSL      = lpd7a40x_ide_insl;
165         hwif->selectproc = lpd7a40x_SELECT_DRIVE;
166 }