summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/hallx3/alpha/flash8k.c
blob: 193b2b9fcb72b880cf641e7250a261e30bd4a051 (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
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
/*++

Copyright (c) 1994  Digital Equipment Corporation

Module Name:

    flash8k.c

Abstract:

    This module implements the flash-specific, device-independent routines 
    necessary to Read and Write the flash ROM containing the system environment
    variables. The routines implemented here are:

	HalpReadNVRamBuffer()		- copy data from Flash into memory
	HalpWriteNVRamBuffer()		- write memory data to Flash
	HalpCopyNVRamBuffer()		- stubbed for compatibility with NVRAM

Author:

    Steve Brooks  5-Oct 93
	

Revision History:

    Wim Colgate   1-May-1995

    Added LX3 specfic code for Bankset 8 mumbo-jumbo for the LX3 specific
    'Flash Bus'. 


--*/


#include "halp.h"
#include "pflash.h"
#include "flash8k.h"

#include "arccodes.h"

//
// To access the flash bus, one needs to enable the bankset 8 in 
// the APECS chipset.
//

#define BANKSET8_CONFIGURATION_REGISTER HAL_MAKE_QVA( 0x180000B00 )
#define BANKSET8_ENABLE 0x1

#define STALL_VALUE 16

//
// This variable tells us which bank of 8K 'nvram' are we using
// The LX3 nvram is actually two separate 8K sections of the FLASH ROM.
// One living at 0x4000, the other at 0x8000.
//
// This 'base' is not a QVA as in other platforms -- rather it is a base
// index off of the FLASH ROM device (0-512K).

extern ULONG Am29F400NVRAMBase;

//
// Variables:
//
//  PFLASH_DRIVER HalpFlashDriver
//      Pointer to the device-specific flash driver.
//

PFLASH_DRIVER HalpFlashDriver = NULL;

//
// Flash Drivers
//
// Each platform which uses this module must define FlashDriverList as an
// array of pointers to the initialize functions of any flash drivers for
// which the flash device might be used for the environment in the system.
//

extern PFLASH_DRIVER (*FlashDriverList[])(ULONG);

//
// Local function prototypes.
//

ARC_STATUS
HalpReadNVRamBuffer (
    OUT PCHAR DataPtr,
    IN  PCHAR NvRamOffset,
    IN  ULONG Length
    );

ARC_STATUS
HalpWriteNVRamBuffer (
    IN  PCHAR NvRamOffset,
    IN  PCHAR DataPtr,
    IN  ULONG Length
    );

ARC_STATUS
HalpCopyNVRamBuffer (
    IN  PCHAR NvDestPtr,
    IN  PCHAR NvSrcPtr,
    IN  ULONG Length
    );

PFLASH_DRIVER 
HalpInitializeFlashDriver(
    IN ULONG NvRamOffset
    );

#ifdef AXP_FIRMWARE

#pragma alloc_text(DISTEXT, HalpReadNVRamBuffer )
#pragma alloc_text(DISTEXT, HalpWriteNVRamBuffer )
#pragma alloc_text(DISTEXT, HalpCopyNVRamBuffer )
#pragma alloc_text(DISTEXT, HalpInitializeFlashDriver )

#endif

ARC_STATUS HalpReadNVRamBuffer (
    OUT PCHAR DataPtr,
    IN  PCHAR NvRamOffset,
    IN  ULONG Length )

/*++

Routine Description:

    This routine Reads data from the NVRam into main memory

Arguments:

    DataPtr	- Pointer to memory location to receive data
    NvRamOffset- NVRam offset to read data from
    Length	- Number of bytes of data to transfer

Return Value:

    ESUCCESS if the operation succeeds.
    ENODEV if no flash driver is loaded
    E2BIG if we attempt to read beyond the end of the NVRAM location

--*/
{
    ULONG CsrMask;

#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
    DbgPrint("HalpReadNVRamBuffer(%08x, %08x, %d)\r\n",(ULONG)DataPtr,
             NvRamOffset, Length);
#endif

    //
    // If there is no flash driver, return an error.
    //

    if ((HalpFlashDriver == NULL) && 
        ((HalpFlashDriver = 
                HalpInitializeFlashDriver((ULONG)NvRamOffset)) == NULL)) {

        return ENODEV;
    }

    //
    // Check to see if we will read beyond the bounds...
    // (normalize offset - base + length)
    //

    if (NvRamOffset - Am29F400NVRAMBase + Length > (PUCHAR)NVRAM1_SECTOR_SIZE) {
        return E2BIG;
    }

    //
    // Adjust the offset by the NVRAM Base -- The NVRAM Offset is going
    // to be 0-8K. The Base is where in the FLASH ROM the NVRAM is located.
    // Since these routines are going to call the lower FLASH ROM routines,
    // (which spans 0-512K), we need to adjust the NVRAM offset appropriately.
    //

    //
    // Enable Bankset 8
    //

    CsrMask = READ_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER );
    WRITE_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER,
                             CsrMask | BANKSET8_ENABLE );

    //
    // Read from the flash.
    //

    HalpFlash8kSetReadMode(NvRamOffset);
    while(Length--) {
        *DataPtr = HalpFlash8kReadByte(NvRamOffset);
        DataPtr++;
        NvRamOffset++;
    }

    //
    // Disable Bankset 8 (Restore original state)
    //

    WRITE_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER, CsrMask );

    return ESUCCESS;
}

ARC_STATUS 
HalpWriteNVRamBuffer (
    IN  PCHAR NvRamOffset,
    IN  PCHAR DataPtr,
    IN  ULONG Length )

/*++

Routine Description:

    This routine Writes data from memory into the NVRam

Arguments:

    NvRamOffset- NVRam Offset to write data into
    DataPtr	- Pointer to memory location of data to be written
    Length	- Number of bytes of data to transfer

Return Value:

    ESUCCESS if the operation succeeds.
    ENODEV if no flash driver is loaded
    EIO if a device error was detected
    E2BIG if we attempt to write beyond the end of the NVRAM location

--*/
{
    ARC_STATUS ReturnStatus = ESUCCESS;
    UCHAR NeedToErase = FALSE;
    UCHAR Byte;
    ULONG Index;
    ULONG Offset;
    ULONG CsrMask;
    PUCHAR FlashBuffer;

    ULONG SectorSize;
    ULONG SectorBase;
 
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
    DbgPrint("HalpWriteNVRamBuffer(%08x, %08x, %d)\r\n", NvRamOffset,
             (ULONG)DataPtr, Length);
#endif

    //
    // If there is no flash driver, return an error.
    //

    if ((HalpFlashDriver == NULL) && 
        ((HalpFlashDriver = 
                HalpInitializeFlashDriver((ULONG)NvRamOffset)) == NULL)) {

        return ENODEV;
    }

    //
    // Check to see if we will write beyond the bounds...
    // (normalize offset - base + length)
    //

    if (NvRamOffset - Am29F400NVRAMBase + Length > (PUCHAR)NVRAM1_SECTOR_SIZE) {
        return E2BIG;
    }

    //
    // Enable Bankset 8
    //
    
    CsrMask = READ_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER );
    WRITE_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER,
                             CsrMask | BANKSET8_ENABLE );

    //
    // Read the whole bloody Physical NVRAM into a temporary buffer for
    // comparisons
    //

    SectorBase = (ULONG)HalpFlash8kSectorAlign(NvRamOffset);
    SectorSize = HalpFlash8kSectorSize(SectorBase);

    FlashBuffer = ExAllocatePool(NonPagedPool, SectorSize);
    if (FlashBuffer == NULL) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
            DbgPrint("HalpWriteNVRamBuffer: Could not allocate shadow\r\n");
#endif
        return ENOMEM;
    }

    ReturnStatus = HalpReadNVRamBuffer(FlashBuffer, 
                                       (PUCHAR)SectorBase, 
                                       SectorSize);

    //
    // Check to see if we can write the data as is. Since we're dealing with 
    // a flash ROM device, we can only program 1-->1 and 1-->0, but not 0-->1.
    //

    Offset = (ULONG)NvRamOffset;
    for (Index = 0; (Index < Length) && !NeedToErase; Index++, Offset++) {

        Byte = FlashBuffer[Offset - SectorBase];

        if (!HalpFlash8kOverwriteCheck(Byte, (UCHAR)DataPtr[Index])) {
            NeedToErase = TRUE;

#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
            DbgPrint("Need to erase flash because byte at %08x (%02x) ",
                         Offset, Byte);
            DbgPrint("Cannot be written with %02x\r\n", (UCHAR)DataPtr[Index]);
#endif

        }

    }

    //
    // We can either program directly, or we must erase first.
    // split this path here.
    //

    if (!NeedToErase) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
        DbgPrint("Don't need to erase -- simple overwrite\n");
#endif
        Offset = (ULONG)NvRamOffset;
        for (Index = 0; Index < Length; Index++, Offset++) {

            //
            // if byte is the same - don't bother writing
            //

            Byte = FlashBuffer[Offset - SectorBase];

            if (Byte != (UCHAR)DataPtr[Index]) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
                DbgPrint("Writing %02x at %x\n", (UCHAR)DataPtr[Index], Offset);
#endif
                HalpStallExecution(STALL_VALUE);
                ReturnStatus = HalpFlash8kWriteByte(Offset,DataPtr[Index]);
                if (ReturnStatus != ESUCCESS) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
                    DbgPrint("Failed to write %02x (was %02x) at %x status %x (Retrying...)\n", 
                        (UCHAR)DataPtr[Index], Byte, Offset, ReturnStatus);
#endif
                    //
                    // Retry
                    //

                    Index--; Offset--;
                }
            }
        }
    } else {

        //
        // We need to erase the flash block in order to write some of the 
        // requested data.
        //

    
        //
        // Merge our data with the existing FLASH ROM data.
        //

        for(Index = 0; Index < Length; Index++) {
            FlashBuffer[(ULONG)NvRamOffset - SectorBase + Index] = 
                   DataPtr[Index];
        }

#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
        DbgPrint("Erasing sector\n");
#endif

        //
        // Erase the sector
        //

        ReturnStatus = HalpFlash8kEraseSector(SectorBase);

#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
            DbgPrint("Returned from erase: %x\n", ReturnStatus);
            DbgPrint("Writing %x bytes to %x\n", SectorSize, SectorBase);
#endif
    
        for (Index = 0; Index < SectorSize; Index++, Offset++) {

            if (FlashBuffer[Index] != HalpFlashDriver->ErasedData) {

                HalpStallExecution(STALL_VALUE);

                ReturnStatus = HalpFlash8kWriteByte(SectorBase + Index,
                                                        FlashBuffer[Index]);
                if (ReturnStatus != ESUCCESS) {
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
                    DbgPrint("Failed to write %02x at %x status %x (Retrying...)\n", 
                    (UCHAR)FlashBuffer[Index], SectorBase + Index, ReturnStatus);
#endif
                    //
                    // Retry
                    //

                    Index--; Offset--;
                }
            }
        }

#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
            DbgPrint("\nReturned from write: %x\n", ReturnStatus);
            DbgPrint("Wrote %x bytes\n", Index);
#endif

    }

    //
    // Disable Bankset 8 (Restore original state)
    //

    WRITE_COMANCHE_REGISTER( BANKSET8_CONFIGURATION_REGISTER, CsrMask );
    
    HalpFlash8kSetReadMode(NvRamOffset);

    ExFreePool(FlashBuffer);

    return ReturnStatus;
}

//
//
//
ARC_STATUS HalpCopyNVRamBuffer (
    IN  PCHAR NvDestPtr,
    IN  PCHAR NvSrcPtr,
    IN  ULONG Length )
/*++

Routine Description:

    This routine is not supported.

Arguments:

    NvDestPtr- NVRam Offset to write data into
    NvSrcPtr - NVRam Offset of data to copy
    Length	 - Number of bytes of data to transfer

Return Value:

    ENODEV if no flash driver is loaded
    EIO if a flash driver is loaded

--*/

{
#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
    DbgPrint("HalpCopyNVRamBuffer()\r\n");
#endif

    //
    // If there is no flash driver, return an error.
    //
    if (HalpFlashDriver == NULL) {
        return ENODEV;
    }

    return EIO;
}

PFLASH_DRIVER 
HalpInitializeFlashDriver(
    IN ULONG NvRamOffset
    )
/*++

Routine Description:

    This routine attempts to recognize the flash device present in the
    system by calling each known flash driver's Initialize() function
    with the address passed in.  The Initialize() functions will each 
    return NULL if they do not recognize the flash device at the specified
    address and a pointer to a FLASH_DRIVER structure if the device is
    recognized.  This routine looks until it either recognizes a flash device
    or runs out of known flash devices.

Arguments:

    NvRamOffset - an Offset within the flash device

Return Value:

    A pointer to the FLASH_DRIVER structure of the driver which corresponds
    to the flash device in the system.  NULL if no known flash device was
    recognized.

--*/
{
    PFLASH_DRIVER FlashDriver = NULL;
    ULONG DriverNumber;

    for(DriverNumber=0; FlashDriverList[DriverNumber] != NULL; DriverNumber++) {
        FlashDriver = FlashDriverList[DriverNumber](NvRamOffset);
        if (FlashDriver != NULL) {
            break;
        }
    }

#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
    if (FlashDriver == NULL) {
        DbgPrint("ERROR: No flash device found at %08x\r\n", NvRamOffset);
    }
#endif

    return FlashDriver;
}