summaryrefslogtreecommitdiff
path: root/firmware/ata.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/ata.c')
-rw-r--r--firmware/ata.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/firmware/ata.c b/firmware/ata.c
new file mode 100644
index 0000000000..460808a217
--- /dev/null
+++ b/firmware/ata.c
@@ -0,0 +1,242 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "ata.h"
20#include "kernel.h"
21#include "led.h"
22
23#define ATA_DATA (*((volatile unsigned short*)0x06104100))
24#define ATA_ERROR (*((volatile unsigned char*)0x06100101))
25#define ATA_FEATURE ATA_ERROR
26#define ATA_NSECTOR (*((volatile unsigned char*)0x06100102))
27#define ATA_SECTOR (*((volatile unsigned char*)0x06100103))
28#define ATA_LCYL (*((volatile unsigned char*)0x06100104))
29#define ATA_HCYL (*((volatile unsigned char*)0x06100105))
30#define ATA_SELECT (*((volatile unsigned char*)0x06100106))
31#define ATA_COMMAND (*((volatile unsigned char*)0x06100107))
32#define ATA_STATUS ATA_COMMAND
33#define ATA_CONTROL (*((volatile unsigned char*)0x06100306))
34
35#define SELECT_LBA 0x40
36
37#define STATUS_BSY 0x80
38#define STATUS_RDY 0x40
39#define STATUS_DRQ 0x08
40#define STATUS_ERR 0x01
41
42#define CONTROL_nIEN 0x02
43#define CONTROL_SRST 0x04
44
45#define CMD_READ_SECTORS 0x20
46#define CMD_WRITE_SECTORS 0x30
47#define CMD_STANDBY_IMMEDIATE 0xE0
48#define CMD_STANDBY 0xE2
49#define CMD_SLEEP 0xE6
50#define CMD_SECURITY_FREEZE_LOCK 0xF5
51
52static int wait_for_bsy(void)
53{
54 char timeout = current_tick + HZ;
55 while (TIME_BEFORE(current_tick, timeout) && (ATA_STATUS & STATUS_BSY))
56 yield();
57
58 if (TIME_BEFORE(current_tick, timeout))
59 return 1;
60 else
61 return 0; /* timeout */
62}
63
64static int wait_for_rdy(void)
65{
66 if (!wait_for_bsy())
67 return 0;
68 return ATA_STATUS & STATUS_RDY;
69}
70
71static int wait_for_start_of_transfer(void)
72{
73 if (!wait_for_bsy())
74 return 0;
75 return (ATA_STATUS & (STATUS_RDY|STATUS_DRQ)) == (STATUS_RDY|STATUS_DRQ);
76}
77
78static int wait_for_end_of_transfer(void)
79{
80 if (!wait_for_bsy())
81 return 0;
82 return (ATA_STATUS & (STATUS_RDY|STATUS_DRQ)) == STATUS_RDY;
83}
84
85int ata_read_sectors(unsigned long start,
86 unsigned char count,
87 unsigned short* buf)
88{
89 int i;
90
91 if (!wait_for_rdy())
92 return 0;
93
94 led_turn_on();
95
96 ATA_NSECTOR = count;
97 ATA_SECTOR = start & 0xff;
98 ATA_LCYL = (start >> 8) & 0xff;
99 ATA_HCYL = (start >> 16) & 0xff;
100 ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA;
101 ATA_COMMAND = CMD_READ_SECTORS;
102
103 for (i=0; i<count; i++) {
104 int j;
105 if (!wait_for_start_of_transfer())
106 return 0;
107
108 for (j=0; j<256; j++)
109 buf[j] = SWAB16(ATA_DATA);
110 }
111
112 led_turn_off();
113
114 return wait_for_end_of_transfer();
115}
116
117int ata_write_sectors(unsigned long start,
118 unsigned char count,
119 unsigned short* buf)
120{
121 int i;
122
123 if (!wait_for_rdy())
124 return 0;
125
126 led_turn_on ();
127
128 ATA_NSECTOR = count;
129 ATA_SECTOR = start & 0xff;
130 ATA_LCYL = (start >> 8) & 0xff;
131 ATA_HCYL = (start >> 16) & 0xff;
132 ATA_SELECT = ((start >> 24) & 0xf) | SELECT_LBA;
133 ATA_COMMAND = CMD_WRITE_SECTORS;
134
135 for (i=0; i<count; i++) {
136 int j;
137 if (!wait_for_start_of_transfer())
138 return 0;
139
140 for (j=0; j<256; j++)
141 ATA_DATA = SWAB16(buf[j]);
142 }
143
144 led_turn_off ();
145
146 return wait_for_end_of_transfer();
147}
148
149static int check_registers(void)
150{
151 if ( ATA_STATUS & STATUS_BSY )
152 return 0;
153
154 ATA_NSECTOR = 0xa5;
155 ATA_SECTOR = 0x5a;
156 ATA_LCYL = 0xaa;
157 ATA_HCYL = 0x55;
158
159 if ((ATA_NSECTOR == 0xa5) &&
160 (ATA_SECTOR == 0x5a) &&
161 (ATA_LCYL == 0xaa) &&
162 (ATA_HCYL == 0x55))
163 return 1;
164 else
165 return 0;
166}
167
168static int check_harddisk(void)
169{
170 if (!wait_for_rdy())
171 return 0;
172
173 if ((ATA_NSECTOR == 1) &&
174 (ATA_SECTOR == 1) &&
175 (ATA_LCYL == 0) &&
176 (ATA_HCYL == 0) &&
177 (ATA_SELECT == 0))
178 return 1;
179 else
180 return 0;
181}
182
183static int freeze_lock(void)
184{
185 if (!wait_for_rdy())
186 return -1;
187
188 ATA_COMMAND = CMD_SECURITY_FREEZE_LOCK;
189
190 if (!wait_for_rdy())
191 return -1;
192
193 return 0;
194}
195
196int ata_hard_reset(void)
197{
198 clear_bit(1,PADR);
199 sleep(HZ/500);
200
201 set_bit(1,PADR);
202 sleep(HZ/500);
203
204 return wait_for_rdy();
205}
206
207int ata_soft_reset(void)
208{
209 ATA_SELECT = SELECT_LBA;
210 ATA_CONTROL = CONTROL_nIEN|CONTROL_SRST;
211 sleep(HZ/20000); /* >= 5us */
212
213 ATA_CONTROL = CONTROL_nIEN;
214 sleep(HZ/400); /* >2ms */
215
216 return wait_for_rdy();
217}
218
219int ata_init(void)
220{
221 led_turn_off();
222
223 /* activate ATA */
224 PADR |= 0x80;
225
226 if (!ata_hard_reset())
227 return -1;
228
229 if (!check_registers())
230 return -2;
231
232 if (!check_harddisk())
233 return -3;
234
235 if (!freeze_lock())
236 return -4;
237
238 ATA_SELECT = SELECT_LBA;
239 ATA_CONTROL = CONTROL_nIEN;
240
241 return 0;
242}