comparison src/cs/drivers/drv_app/ffs/board/amdsbdrv.c @ 0:4e78acac3d88

src/{condat,cs,gpf,nucleus}: import from Selenite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 06:23:26 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4e78acac3d88
1 /******************************************************************************
2 * Flash File System (ffs)
3 * Idea, design and coding by Mads Meisner-Jensen, mmj@ti.com
4 *
5 * FFS AMD single bank low level flash driver RAM code
6 *
7 * $Id: amdsbdrv.c 1.5.1.3 Tue, 06 Jan 2004 10:57:45 +0100 tsj $
8 *
9 ******************************************************************************/
10
11 #include "ffs.cfg"
12
13 #include "ffs/ffs.h"
14 #include "ffs/board/drv.h"
15 #include "ffs/board/ffstrace.h"
16
17
18 // Due to long branches, we disable all tracing and led function calls.
19 #undef tlw
20 #define tlw(contents)
21 #undef ttw
22 #define ttw(contents)
23
24
25 #ifdef __GNUC__
26 asm(".globl ffsdrv_ram_amd_begin");
27 asm("ffsdrv_ram_amd_begin:");
28 #else
29 asm(" .label _ffsdrv_ram_amd_begin");
30 asm(" .def _ffsdrv_ram_amd_begin");
31 #endif
32
33
34 // IMPORTANT! Apparently, placing the int_disable/enable() function code
35 // here instead of at the bottom of the file, makes the code crash or
36 // freeze. Reason is as of yet unknown.
37
38 uint32 amd_int_disable(void);
39 void amd_int_enable(uint32 tmp);
40
41
42 /******************************************************************************
43 * AMD Single Bank Driver Functions
44 ******************************************************************************/
45
46 void ffsdrv_ram_amd_sb_write_halfword(volatile uint16 *addr, uint16 value)
47 {
48 volatile char *flash = dev.base;
49 uint32 cpsr;
50
51 ttw(ttr(TTrDrv, "wh(%x,%x)" NL, addr, value));
52
53 if (~*addr & value) {
54 ttw(ttr(TTrFatal, "wh(%x,%x->%x) fatal" NL, addr, *addr, value));
55 return;
56 }
57
58 cpsr = amd_int_disable();
59 tlw(led_on(LED_WRITE));
60
61 flash[0xAAAA] = 0xAA; // AMD unlock cycle 1
62 flash[0x5555] = 0x55; // AMD unlock cycle 2
63 flash[0xAAAA] = 0xA0;
64 *addr = value;
65
66 while ((*addr ^ value) & 0x80)
67 ;
68
69 tlw(led_off(LED_WRITE));
70 amd_int_enable(cpsr);
71 }
72
73 // This VERY simple way of erase suspension only works because we run under
74 // a pre-emptive operating system, so whenever an interrupt occurs, another
75 // task takes the CPU, and at the end of the interrupt, FFS gets the CPU
76 // again.
77 void ffsdrv_ram_amd_sb_erase(uint8 block)
78 {
79 volatile char *flash = dev.base;
80 volatile char *addr;
81 uint32 cpsr;
82 uint16 flashpoll;
83
84 addr = block2addr(block);
85
86 ttw(ttr(TTrDrvEra, "e(%d)" NL, block));
87
88 cpsr = amd_int_disable();
89 tlw(led_on(LED_ERASE));
90
91 flash[0xAAAA] = 0xAA; // AMD unlock cycle 1
92 flash[0x5555] = 0x55; // AMD unlock cycle 2
93 flash[0xAAAA] = 0x80;
94 flash[0xAAAA] = 0xAA; // AMD unlock cycle 1
95 flash[0x5555] = 0x55; // AMD unlock cycle 2
96 *addr = 0x30; // AMD erase sector command
97
98 // Wait for erase to finish.
99 while ((*addr & 0x80) == 0) {
100 tlw(led_toggle(LED_ERASE));
101 // Poll interrupts, taking interrupt mask into account.
102 if (INT_REQUESTED)
103 {
104 // 1. suspend erase
105 // 2. enable interrupts
106 // .. now the interrupt code executes
107 // 3. disable interrupts
108 // 4. resume erase
109
110 tlw(led_on(LED_ERASE_SUSPEND));
111 *addr = 0xB0;
112
113 // wait for erase suspend to finish
114 while ((*addr & 0x80) == 0)
115 ;
116
117 tlw(led_off(LED_ERASE_SUSPEND));
118 amd_int_enable(cpsr);
119
120 // Other interrupts and tasks run now...
121
122 cpsr = amd_int_disable();
123 tlw(led_on(LED_ERASE_SUSPEND));
124
125 // Before resuming erase we must? check if the erase is really
126 // suspended or if it did finish
127 flashpoll = *addr;
128 *addr = 0x30;
129
130 tlw(led_off(LED_ERASE_SUSPEND));
131 }
132 }
133
134 tlw(led_on(LED_ERASE));
135 tlw(led_off(LED_ERASE));
136 amd_int_enable(cpsr);
137 }
138
139
140 /******************************************************************************
141 * Interrupt Enable/Disable
142 ******************************************************************************/
143
144 #ifdef __GNUC__
145 #define NOINLINE __attribute__ ((noinline))
146 #else
147 #define NOINLINE
148 #endif
149
150 uint32 NOINLINE amd_int_disable(void)
151 {
152 #ifdef __GNUC__
153 asm(" .code 16");
154 #else
155 asm(" .state16");
156 #endif
157 asm(" mov A1, #0xC0");
158 asm(" ldr A2, tct_amd_disable");
159 asm(" bx A2 ");
160
161 #ifdef __GNUC__
162 asm(".balign 4");
163 asm("tct_amd_disable:");
164 asm(" .word TCT_Control_Interrupts");
165 #else
166 asm("tct_amd_disable .field _TCT_Control_Interrupts+0,32");
167 asm(" .global _TCT_Control_Interrupts");
168 #endif
169 }
170
171 void NOINLINE amd_int_enable(uint32 cpsr)
172 {
173 #ifdef __GNUC__
174 asm(" .code 16");
175 #else
176 asm(" .state16");
177 #endif
178 asm(" ldr A2, tct_amd_enable");
179 asm(" bx A2 ");
180
181 #ifdef __GNUC__
182 asm(".balign 4");
183 asm("tct_amd_enable:");
184 asm(" .word TCT_Control_Interrupts");
185 #else
186 asm("tct_amd_enable .field _TCT_Control_Interrupts+0,32");
187 asm(" .global _TCT_Control_Interrupts");
188 #endif
189 }
190
191 // Even though we have this end label, we cannot determine the number of
192 // constant/PC-relative data following the code!
193 #ifdef __GNUC__
194 asm(".globl ffsdrv_ram_amd_end");
195 asm("ffsdrv_ram_amd_end:");
196 #else
197 asm(" .state32");
198 asm(" .label _ffsdrv_ram_amd_end");
199 asm(" .def _ffsdrv_ram_amd_end");
200 #endif