summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halalpha/28f008sa.c
blob: 487a908d8f7c995be1fe2bff7ad65333698fbed5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
#include "halp.h"
#include "arccodes.h"
#include "flash8k.h"

#define I28F008SA_DEVICE_SIZE   0x100000

#define SET_READ_ARRAY      0xff
#define SET_BYTE_WRITE      0x40
#define SET_ERASE_BLOCK     0x20
#define CONFIRM_ERASE_BLOCK 0xd0
#define READ_STATUS         0x70
#define RESET_STATUS        0x50
#define ID_REQUEST          0x90

#define MANUFACTURER_ID     0x89
#define DEVICE_ID           0xa2

#define BLOCK_SIZE          0x10000
#define BLANK_DATA          0xff

#define TIMEOUT_VALUE      5000000

#define STATUS_READY        0x80
#define STATUS_ERASE_SUSP   0x40
#define STATUS_ERASE_ERR    0x20
#define STATUS_WRITE_ERR    0x10
#define STATUS_VPP_LOW      0x08
#define STATUS_CMD_SEQ_ERR  (STATUS_WRITE_ERR | STATUS_READ_ERR)

//
// Local function prototypes
//
PFLASH_DRIVER
I28F008SA_Initialize(
    IN PUCHAR NvRamPtr
    );

ARC_STATUS
I28F008SA_SetReadMode(
    IN PUCHAR Address
    );

ARC_STATUS
I28F008SA_WriteByte(
    IN PUCHAR Address,
    IN UCHAR Data
    );

ARC_STATUS
I28F008SA_EraseBlock(
    IN PUCHAR Address
    );

ARC_STATUS
I28F008SA_CheckStatus(
    IN PUCHAR Address,
    FLASH_OPERATIONS Operation
    );

PUCHAR
I28F008SA_BlockAlign(
    IN PUCHAR Address
    );

UCHAR
I28F008SA_ReadByte(
    IN PUCHAR Address
    );

BOOLEAN
I28F008SA_OverwriteCheck(
    IN UCHAR OldData,
    IN UCHAR NewData
    );

ULONG
I28F008SA_BlockSize(
    IN PUCHAR Address
    );

ULONG
I28F008SA_GetLastError(
    VOID
    );

static 
VOID
I28F008SA_SetLastError(
    ULONG FlashStatus
    );

FLASH_DRIVER I28F008SA_DriverInformation = {
    "Intel 28F008SA",
    I28F008SA_SetReadMode,      // SetReadModeFunction
    I28F008SA_WriteByte,        // WriteByteFunction
    I28F008SA_EraseBlock,       // EraseBlockFunction
    I28F008SA_BlockAlign,       // AlignBlockFunction
    I28F008SA_ReadByte,         // ReadByteFunction
    I28F008SA_OverwriteCheck,   // OverwriteCheckFunction
    I28F008SA_BlockSize,        // BlockSizeFunction
    I28F008SA_GetLastError,     // GetLastErrorFunction
    I28F008SA_DEVICE_SIZE,      // DeviceSize
    BLANK_DATA                  // ErasedData
    };

static ULONG I28F008SA_LastError;

PFLASH_DRIVER
I28F008SA_Initialize(
    IN PUCHAR NvRamPtr
    )
{
    PFLASH_DRIVER ReturnDriver = NULL;
    UCHAR ManufacturerID;
    UCHAR DeviceID;

    NvRamPtr = I28F008SA_BlockAlign(NvRamPtr);

    WRITE_CONFIG_RAM_DATA(NvRamPtr, ID_REQUEST);

    ManufacturerID = READ_CONFIG_RAM_DATA(NvRamPtr);
    DeviceID = READ_CONFIG_RAM_DATA((PUCHAR)((ULONG)NvRamPtr + 1));

    if ((ManufacturerID == MANUFACTURER_ID) && (DeviceID == DEVICE_ID)) {
        I28F008SA_LastError = 0;
        I28F008SA_SetReadMode(NvRamPtr);
        ReturnDriver = &I28F008SA_DriverInformation;
    }

    return ReturnDriver;
}

ARC_STATUS
I28F008SA_SetReadMode(
    IN PUCHAR NvRamPtr
    )
{
    WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_READ_ARRAY);
    HalpMb();

    return ESUCCESS;
}

ARC_STATUS
I28F008SA_WriteByte(
    IN PUCHAR NvRamPtr, 
    IN UCHAR Data
    )
{
    ARC_STATUS ReturnStatus;

    I28F008SA_SetReadMode(NvRamPtr);

    WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_BYTE_WRITE);
    WRITE_CONFIG_RAM_DATA(NvRamPtr, Data);

    ReturnStatus = I28F008SA_CheckStatus(NvRamPtr, FlashByteWrite);

    I28F008SA_SetReadMode(NvRamPtr);

    return ReturnStatus;
}

ARC_STATUS
I28F008SA_EraseBlock (
    IN PUCHAR NvRamPtr
    )
{
    ARC_STATUS ReturnStatus;

    WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_ERASE_BLOCK);
    WRITE_CONFIG_RAM_DATA(NvRamPtr, CONFIRM_ERASE_BLOCK);

    ReturnStatus = I28F008SA_CheckStatus(NvRamPtr, FlashEraseBlock);
   
    I28F008SA_SetReadMode(NvRamPtr);

    return ReturnStatus;
}

ARC_STATUS
I28F008SA_CheckStatus (
    IN PUCHAR NvRamPtr,
    IN FLASH_OPERATIONS Operation
    )
{
    ARC_STATUS ReturnStatus = EIO;
    ULONG Timeout;
    UCHAR FlashStatus;

    //
    // Keep reading the status until the device is done with its
    // current operation.
    //
    Timeout = TIMEOUT_VALUE;
    do {
        WRITE_CONFIG_RAM_DATA(NvRamPtr, READ_STATUS);
        FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr);
        KeStallExecutionProcessor(1);
        Timeout--;
    } while (((FlashStatus & 0x80) == 0) && (Timeout > 0));

    //
    // Check the status for the operation requested.
    //
    switch(Operation) {
    case FlashByteWrite:
        if ((FlashStatus & 0x18) == 0) {
            ReturnStatus = ESUCCESS;
        } else {
            I28F008SA_SetLastError(FlashStatus & 0x18);
        }
        break;
    case FlashEraseBlock:
        if (((FlashStatus & 0x28) == 0) && ((FlashStatus & 0x30) != 0x30)) {
            ReturnStatus = ESUCCESS;
        } else {
            I28F008SA_SetLastError(FlashStatus & 0x28);
        }
        break;
    }
    if ((FlashStatus & 0x80) == 0) {
        ReturnStatus = EIO;
        I28F008SA_SetLastError(0);
    }

    //
    // Clear the flash status register
    // This is a silent operation.  The status that gets returned is the
    // status of the real operation as determined above.
    //
    WRITE_CONFIG_RAM_DATA(NvRamPtr, RESET_STATUS);
    Timeout = TIMEOUT_VALUE;
    do {
        WRITE_CONFIG_RAM_DATA(NvRamPtr, READ_STATUS);
        FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr);
        KeStallExecutionProcessor(1);
        Timeout--;
    } while (((FlashStatus & 0x80) == 0) && (Timeout > 0));

    return ReturnStatus;
}

PUCHAR
I28F008SA_BlockAlign(
    IN PUCHAR Address
    )
{
    return (PUCHAR)((ULONG)Address & ~(BLOCK_SIZE-1));
}

UCHAR
I28F008SA_ReadByte(
    IN PUCHAR Address
    )
{
    return READ_CONFIG_RAM_DATA(Address);
}

BOOLEAN
I28F008SA_OverwriteCheck(
    IN UCHAR OldData,
    IN UCHAR NewData
    )
/*++

Return Value:

    Zero if OldData can be overwritten with NewData.
    Non-zero if device must be erased to write NewData.

--*/
{
    return (~OldData & NewData) ? FALSE : TRUE;
}

ULONG
I28F008SA_BlockSize(
    IN PUCHAR Address
    )
/*++

Return Value:

    The block size of the device.  This is a constant because all
    blocks in the 28f008sa are the same size.

--*/
{
    return BLOCK_SIZE;
}

ULONG
I28F008SA_GetLastError(
    VOID
    )
{
    return I28F008SA_LastError;
}

static 
VOID
I28F008SA_SetLastError(
    ULONG FlashStatus
    )
{
    I28F008SA_LastError = ERROR_UNKNOWN;
    if (FlashStatus == 0) 
        I28F008SA_LastError = ERROR_TIMEOUT;
    if (FlashStatus & STATUS_WRITE_ERR)
        I28F008SA_LastError = ERROR_WRITE_ERROR;
    if (FlashStatus & STATUS_ERASE_ERR)
        I28F008SA_LastError = ERROR_ERASE_ERROR;
    if (FlashStatus & STATUS_VPP_LOW)
        I28F008SA_LastError = ERROR_VPP_LOW;
}