66b2fdd04a36e4df00675edd10213fe4c2eec49d
[goodfet] / firmware / apps / slc2 / slc2.c
1 /*! \file slc2.c
2    \author Alexey Borisenko <abori021@uottawa.ca>
3    \brief Silicon Labs C2 Debug interface
4  */
5
6 #include "command.h"
7
8 #ifdef __MSPGCC__
9 #include <msp430.h>
10 #else
11 #include <signal.h>
12 #include <io.h>
13 #include <iomacros.h>
14 #endif
15
16 #include "slc2.h"
17
18 #include "platform.h"
19
20
21 //-----------------------------------------------------------------------------------
22 // Global VARIABLES
23 //-----------------------------------------------------------------------------------
24 unsigned char NUM_BYTES;
25 unsigned int FLASH_ADDR;
26 unsigned char *C2_PTR;
27
28 //! Handles a monitor command.
29 void slc2_handle_fn( uint8_t const app,
30                      uint8_t const verb,
31                      uint32_t const len);
32
33 // define the spi app's app_t
34 app_t const slc2_app = {
35
36         /* app number */
37         SLC2,
38
39         /* handle fn */
40         slc2_handle_fn,
41
42         /* name */
43         "Silicon Labs C2",
44
45         /* desc */
46         "\tThis app handles Silicon Lab's C2 debugging protocol.\n"
47 };
48
49 //-----------------------------------------------------------------------------------
50 // FLASH Programming Routines (High Level)
51 //-----------------------------------------------------------------------------------
52 //
53 // These high-level routines perform the FLASH Programming Interface (FPI)
54 // command sequences.
55 //-----------------------------------------------------------------------------------
56 // C2_Init()
57 //-----------------------------------------------------------------------------------
58 // - Initializes the C2 Interface for FLASH programming
59 //
60 void C2_Init()
61 {
62         C2CKOUTPUT;
63         C2D_DriverOff;
64         C2_Reset(); // Reset the target device
65         delay_us(2); // Delay for at least 2us
66         C2_WriteAR(FPCTL); // Target the C2 FLASH Programming
67 // Control register (FPCTL) for C2 Data
68 // register accesses
69         C2_WriteDR(0x02); // Write the first key code to enable
70 // C2 FLASH programming
71         C2_WriteDR(0x01); // Write the second key code to enable
72 // C2 FLASH programming
73         delay_us(20000); // Delay for at least 20ms to ensure the
74 // target is ready for C2 FLASH programming
75 }
76 //-----------------------------------------------------------------------------------
77 // C2_GetDevID()
78 //-----------------------------------------------------------------------------------
79 // - Reads the target Devcie ID register and Revision ID register
80 //
81 unsigned char C2_GetDevID()
82 {
83         C2_WriteAR(DEVICEID); // Select DeviceID regsiter for C2 Data
84 // register accesses
85         return C2_ReadDR(); // Read and return the DeviceID register
86 }
87
88 //-----------------------------------------------------------------------------------
89 // C2_GetDevID()
90 //-----------------------------------------------------------------------------------
91 // - Reads the target Devcie ID register and Revision ID register
92 //
93 unsigned char C2_GetRevID()
94 {
95         C2_WriteAR(REVID); // Select DeviceID regsiter for C2 Data
96 // register accesses
97         return C2_ReadDR(); // Read and return the DeviceID register
98 }
99
100 //-----------------------------------------------------------------------------------
101 // C2_BlockRead()
102 //-----------------------------------------------------------------------------------
103 // - Reads a block of FLASH memory starting at <FLASH_ADDR>
104 // - The size of the block is defined by <NUM_BYTES>
105 // - Stores the read data at the location targeted by the pointer <C2_PTR>
106 // - Assumes that FLASH accesses via C2 have been enabled prior to the function call
107 // - Function call returns a ‘1’ if successful; returns a ‘0’ if unsuccessful
108 //
109 char C2_BlockRead()
110 {
111         unsigned char i; // Counter
112         unsigned char status; // FPI status information holder
113         C2_WriteAR(FPDAT); // Select the FLASH Programming Data register
114 // for C2 Data register accesses
115         C2_WriteDR(BLOCK_READ); // Send FLASH block read command
116         Poll_InBusy; // Wait for input acknowledge
117 // Check status before starting FLASH access sequence
118         Poll_OutReady; // Wait for status information
119         status = C2_ReadDR(); // Read FLASH programming interface status
120         if (status != COMMAND_OK)
121                 return 0;  // Exit and indicate error
122         C2_WriteDR(FLASH_ADDR >> 8); // Send address high byte to FPDAT
123         Poll_InBusy; // Wait for input acknowledge
124         C2_WriteDR(FLASH_ADDR & 0x00FF); // Send address low byte to FPDAT
125         Poll_InBusy; // Wait for input acknowledge
126         C2_WriteDR(NUM_BYTES); // Send block size
127         Poll_InBusy; // Wait for input acknowledge
128 // Check status before reading FLASH block
129         Poll_OutReady; // Wait for status information
130         status = C2_ReadDR(); // Read FLASH programming interface status
131         if (status != COMMAND_OK)
132                 return 0;  // Exit and indicate error
133 // Read FLASH block
134         for (i=0; i<NUM_BYTES; i++)
135         {
136                 Poll_OutReady; // Wait for data ready indicator
137                 *C2_PTR++ = C2_ReadDR(); // Read data from the FPDAT register
138         }
139         return 1; // Exit and indicate success
140 }
141 //-----------------------------------------------------------------------------------
142 // C2_BlockWrite()
143 //-----------------------------------------------------------------------------------
144 // - Writes a block of FLASH memory starting at <FLASH_ADDR>
145 // - The size of the block is defined by <NUM_BYTES>
146 // - Writes the block stored at the location targetted by <C2_PTR>
147 // - Assumes that FLASH accesses via C2 have been enabled prior to the function call
148 // - Function call returns a ‘1’ if successful; returns a ‘0’ if unsuccessful
149 //
150 char C2_BlockWrite()
151 {
152         unsigned char i; // Counter
153         unsigned char status; // FPI status information holder
154         C2_WriteAR(FPDAT); // Select the FLASH Programming Data register
155 // for C2 Data register accesses
156         C2_WriteDR(BLOCK_WRITE); // Send FLASH block write command
157         Poll_InBusy; // Wait for input acknowledge
158 // Check status before starting FLASH access sequence
159         Poll_OutReady; // Wait for status information
160         status = C2_ReadDR(); // Read FLASH programming interface status
161         if (status != COMMAND_OK)
162                 return 0;  // Exit and indicate error
163         C2_WriteDR(FLASH_ADDR >> 8); // Send address high byte to FPDAT
164         Poll_InBusy; // Wait for input acknowledge
165         C2_WriteDR(FLASH_ADDR & 0x00FF); // Send address low byte to FPDAT
166         Poll_InBusy; // Wait for input acknowledge
167         C2_WriteDR(NUM_BYTES); // Send block size
168         Poll_InBusy; // Wait for input acknolwedge
169
170 // Check status before starting FLASH access sequence
171         Poll_OutReady; // Wait for status information
172         status = C2_ReadDR(); // Read FLASH programming interface status
173         if (status != COMMAND_OK)
174                 return 0;  // Exit and indicate error
175         C2_WriteDR(FLASH_ADDR >> 8); // Send address high byte to FPDAT
176         Poll_InBusy; // Wait for input acknowledge
177         C2_WriteDR(FLASH_ADDR & 0x00FF); // Send address low byte to FPDAT
178         Poll_InBusy; // Wait for input acknowledge
179         C2_WriteDR(NUM_BYTES); // Send block size
180         Poll_InBusy; // Wait for input acknolwedge
181 // Check status before writing FLASH block
182         Poll_OutReady; // Wait for status information
183         status = C2_ReadDR(); // Read FLASH programming interface status
184         if (status != COMMAND_OK)
185                 return 0;  // Exit and indicate error
186 // Write FLASH block
187         for (i=0; i<NUM_BYTES; i++)
188         {
189                 C2_WriteDR(*C2_PTR++); // Write data to the FPDAT register
190                 Poll_InBusy; // Wait for input acknowledge
191         }
192         Poll_OutReady; // Wait for last FLASH write to complete
193         return 1; // Exit and indicate success
194 }
195 //-----------------------------------------------------------------------------------
196 // C2_PageErase()
197 //-----------------------------------------------------------------------------------
198 // - Erases a 512-byte FLASH page
199 // - Targets the FLASH page containing the address <FLASH_ADDR>
200 // - Assumes that FLASH accesses via C2 have been enabled prior to the function call
201 // - Function call returns a ‘1’ if successful; returns a ‘0’ if unsuccessful
202 //
203 char C2_PageErase()
204 {
205         unsigned char page; // Target FLASH page
206         unsigned char status; // FPI status information holder
207
208         page = (unsigned char)(FLASH_ADDR >> 9);
209 // <page> is the 512-byte sector containing
210 // the target <FLASH_ADDR>.
211         if (page >= NUM_PAGES - 1) // Check that target page is within range
212 // (NUM_PAGES minus 1 for reserved area)
213                 return 0;  // Indicate error if out of range
214         C2_WriteAR(FPDAT); // Select the FLASH Programming Data register
215 // for C2 Data register accesses
216         C2_WriteDR(PAGE_ERASE); // Send FLASH page erase command
217         Poll_InBusy; // Wait for input acknowledge
218 // Check status before starting FLASH access sequence
219         Poll_OutReady; // Wait for status information
220         status = C2_ReadDR(); // Read FLASH programming interface status
221         if (status != COMMAND_OK)
222                 return 0;  // Exit and indicate error
223         C2_WriteDR(page); // Send FLASH page number
224         Poll_InBusy; // Wait for input acknowledge
225         Poll_OutReady; // Wait for ready indicator
226         status = C2_ReadDR(); // Read FLASH programming interface status
227         if (status != COMMAND_OK)
228                 return 0;  // Exit and indicate error
229         C2_WriteDR(0x00); // Dummy write to initiate erase
230         Poll_InBusy; // Wait for input acknowledge
231         Poll_OutReady; // Wait for erase operation to complete
232         return 1; // Exit and indicate success
233 }
234 //-----------------------------------------------------------------------------------
235 // C2_Device_Erase()
236 //-----------------------------------------------------------------------------------
237 // - Erases the entire FLASH memory space
238 // - Assumes that FLASH accesses via C2 have been enabled prior to the function call
239 // - Function call returns a ‘1’ if successful; returns a ‘0’ if unsuccessful
240 //
241 char C2_DeviceErase()
242 {
243         unsigned char status; // FPI status information holder
244         C2_WriteAR(FPDAT); // Select the FLASH Programming Data register
245 // for C2 Data register accesses
246         C2_WriteDR(DEVICE_ERASE); // Send Device Erase command
247         Poll_InBusy; // Wait for input acknowledge
248 // Check status before starting FLASH access sequence
249         Poll_OutReady; // Wait for status information
250         status = C2_ReadDR(); // Read FLASH programming interface status
251         if (status != COMMAND_OK)
252                 return 0;  // Exit and indicate error
253 // Send a three-byte arming sequence to enable the device erase. If the sequence
254 // is not received correctly, the command will be ignored.
255 // Sequence: 0xDE, 0xAD, 0xA5.
256
257         C2_WriteDR(0xDE); // Arming sequence command 1
258         Poll_InBusy; // Wait for input acknowledge
259         C2_WriteDR(0xAD); // Arming sequence command 2
260         Poll_InBusy; // Wait for input acknowledge
261         C2_WriteDR(0xA5); // Arming sequence command 3
262         Poll_InBusy; // Wait for input acknowledge
263         Poll_OutReady; // Wait for erase operation to complete
264         return 1; // Exit and indicate success
265 }
266 //-----------------------------------------------------------------------------------
267 // Primitive C2 Command Routines
268 //-----------------------------------------------------------------------------------
269 //
270 // These routines perform the low-level C2 commands:
271 // 1. Address Read
272 // 2. Address Write
273 // 3. Data Read
274 // 4. Data Write
275 // 5. Device Reset
276 //-----------------------------------------------------------------------------------
277 // C2_ReadAR()
278 //-----------------------------------------------------------------------------------
279 // - Performs a C2 Address register read
280 // - Returns the 8-bit register content
281 //
282 unsigned char C2_ReadAR()
283 {
284         unsigned char i; // Bit counter
285         unsigned char addr; // Address register read content
286 // START field
287         StrobeC2CK; // Strobe C2CK with C2D driver disabled
288 // INS field (10b, LSB first)
289         CLRC2D;
290         C2D_DriverOn; // Enable C2D driver (output)
291         StrobeC2CK;
292         SETC2D;
293         StrobeC2CK;
294         C2D_DriverOff; // Disable C2D driver (input)
295 // ADDRESS field
296         addr = 0;
297         for (i=0; i<8; i++) // Shift in 8 bit ADDRESS field
298         { // LSB-first
299                 addr >>= 1;
300                 StrobeC2CK;
301                 if (READC2D)
302                         addr |= 0x80;
303         }
304 // STOP field
305         StrobeC2CK; // Strobe C2CK with C2D driver disabled
306
307         return addr; // Return Address register read value
308 }
309 //-----------------------------------------------------------------------------------
310 // C2_WriteAR()
311 //-----------------------------------------------------------------------------------
312 // - Performs a C2 Address register write (writes the <addr> input
313 // to Address register)
314 //
315 void C2_WriteAR(unsigned char addr)
316 {
317         unsigned char i; // Bit counter
318 // START field
319         StrobeC2CK; // Strobe C2CK with C2D driver disabled
320 // INS field (11b, LSB first)
321         SETC2D;
322         C2D_DriverOn; // Enable C2D driver (output)
323         StrobeC2CK;
324         SETC2D;
325         StrobeC2CK;
326 // ADDRESS field
327         for(i=0; i<8; i++) // Shift out 8-bit ADDRESS field
328         {
329                 if(addr & 0x01)
330                         SETC2D;
331                 else
332                         CLRC2D;
333                 StrobeC2CK;
334                 addr >>= 1;
335         }
336 // STOP field
337         C2D_DriverOff; // Disable C2D driver
338         StrobeC2CK; // Strobe C2CK with C2D driver disabled
339         return;
340 }
341 //-----------------------------------------------------------------------------------
342 // C2_ReadDR()
343 //-----------------------------------------------------------------------------------
344 // - Performs a C2 Data register read
345 // - Returns the 8-bit register content
346 //
347 unsigned char C2_ReadDR()
348 {
349         unsigned char i; // Bit counter
350         unsigned char dat; // Data register read content
351 // START field
352         StrobeC2CK; // Strobe C2CK with C2D driver disabled
353 // INS field (00b, LSB first)
354         CLRC2D;
355         C2D_DriverOn; // Enable C2D driver (output)
356         StrobeC2CK;
357         CLRC2D;
358         StrobeC2CK;
359
360 // LENGTH field (00b -> 1 byte)
361         CLRC2D;
362         StrobeC2CK;
363         CLRC2D;
364         StrobeC2CK;
365 // WAIT field
366         C2D_DriverOff; // Disable C2D driver for input
367         do
368         {
369                 StrobeC2CK;
370         }
371         while (!READC2D); // Strobe C2CK until target transmits a ‘1’
372 // DATA field
373         dat = 0;
374         for (i=0; i<8; i++) // Shift in 8-bit DATA field
375         { // LSB-first
376                 dat >>= 1;
377                 StrobeC2CK;
378                 if (READC2D)
379                         dat |= 0x80;
380         }
381 // STOP field
382         StrobeC2CK; // Strobe C2CK with C2D driver disabled
383         return dat;
384 }
385
386 //-----------------------------------------------------------------------------------
387 // C2_WriteDR()
388 //-----------------------------------------------------------------------------------
389 // - Performs a C2 Data register write (writes <dat> input to data register)
390 //
391 void C2_WriteDR(unsigned char dat)
392 {
393         unsigned char i; // Bit counter
394 // START field
395         StrobeC2CK; // Strobe C2CK with C2D driver disabled
396 // INS field (01b, LSB first)
397         SETC2D;
398         C2D_DriverOn; // Enable C2D driver
399         StrobeC2CK;
400         CLRC2D;
401         StrobeC2CK;
402 // LENGTH field (00b -> 1 byte)
403         CLRC2D;
404         StrobeC2CK;
405         CLRC2D;
406         StrobeC2CK;
407 // DATA field
408         for (i=0; i<8; i++) // Shift out 8-bit DATA field
409         { // LSB-first
410                 if(dat & 0x01)
411                         SETC2D;
412                 else
413                         CLRC2D;
414                 StrobeC2CK;
415                 dat >>= 1;
416         }
417 // WAIT field
418         C2D_DriverOff; // Disable C2D driver for input
419         do
420         {
421                 StrobeC2CK; // Strobe C2CK until target transmits a ‘1’
422         }
423         while (!READC2D);
424 // STOP field
425         StrobeC2CK; // Strobe C2CK with C2D driver disabled
426         return;
427 }
428
429 //-----------------------------------------------------------------------------------
430 // C2_Reset()
431 //-----------------------------------------------------------------------------------
432 // - Performs a target device reset by pulling the C2CK pin low for >20us
433 //
434 void C2_Reset()
435 {
436         CLRC2CK; // Put target device in reset state by pulling
437         delay_us(20); // C2CK low for >20us
438         SETC2CK; // Release target device from reset
439 }
440
441
442
443 //! Handles a monitor command.
444 void slc2_handle_fn( uint8_t const app,
445                      uint8_t const verb,
446                      uint32_t const len)
447 {
448         prep_timer();
449         unsigned char dev_id = 0;
450         unsigned char rev_id = 0;
451         switch(verb)
452         {
453         case PEEK:
454                 //C2_Reset();
455                 //C2_Init();
456                 NUM_BYTES = 2;
457                 FLASH_ADDR = (cmddata[1] << 8) + cmddata[0];
458                 C2_PTR = cmddata; //cmddata + 2;
459                 //slc2_init();////
460                 if(C2_BlockRead()) {
461                         txdata(app, verb, 2);
462                 }else{
463                         txdata(app, NOK, 0);
464                 }
465                 break;
466
467         case POKE:
468                 NUM_BYTES = len;
469                 FLASH_ADDR = (cmddata[1] << 8) + cmddata[0];
470                 C2_PTR = cmddata + 2;
471                 if(C2_BlockWrite()) {
472                         txhead(app, OK, 0);
473                 }else{
474                         txhead(app, NOK, 0);
475                 }
476                 break;
477
478         case SETUP:
479                 C2_Reset();
480                 C2_Init();
481                 txdata(app,verb,0);
482                 break;
483
484         case GETDEVID:
485                 dev_id =  C2_GetDevID();
486                 cmddata[0] = dev_id;
487                 txdata(app, verb, 1);
488                 break;
489
490         case GETREVID:
491                 rev_id =  C2_GetRevID();
492                 cmddata[0] = rev_id;
493                 txdata(app, verb, 1);
494                 break;
495
496         case PERASE:
497                 FLASH_ADDR = (cmddata[1] << 8) + cmddata[0];
498                 if(C2_PageErase()) {
499                         txhead(app, OK, 0);
500                 }else{
501                         txhead(app, NOK, 0);
502                 }
503                 break;
504
505         case DERASE:
506                 if(C2_DeviceErase()) {
507                         txhead(app, OK, 0);
508                 }else{
509                         txhead(app, NOK, 0);
510                 }
511                 break;
512         case VRESET:
513                 C2_Reset();
514                 txdata(app,verb,0);
515                 break;
516         default:
517                 txdata(app, NOK, 0);
518                 break;
519         }
520 }