Add first draft of the TPI NVM commands for reading, writing and erasing a target...
[pub/lufa.git] / Projects / AVRISP-MKII / Lib / XPROG / XPROGProtocol.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 /** \file
32 *
33 * XPROG Protocol handler, to process V2 Protocol wrapped XPROG commands used in Atmel programmer devices.
34 */
35
36 #define INCLUDE_FROM_XPROGPROTOCOL_C
37 #include "XPROGProtocol.h"
38
39 #if defined(ENABLE_XPROG_PROTOCOL) || defined(__DOXYGEN__)
40 /** Base absolute address for the target's NVM controller for PDI programming */
41 uint32_t XPROG_Param_NVMBase = 0x010001C0;
42
43 /** Size in bytes of the target's EEPROM page */
44 uint16_t XPROG_Param_EEPageSize;
45
46 /** Address of the TPI device's NVMCMD register for TPI programming */
47 uint8_t XPROG_Param_NVMCMDRegAddr;
48
49 /** Address of the TPI device's NVMCSR register for TPI programming */
50 uint8_t XPROG_Param_NVMCSRRegAddr;
51
52 /** Currently selected XPROG programming protocol */
53 uint8_t XPROG_SelectedProtocol = XPRG_PROTOCOL_PDI;
54
55 /** Handler for the CMD_XPROG_SETMODE command, which sets the programmer-to-target protocol used for PDI/TPI
56 * programming.
57 */
58 void XPROGProtocol_SetMode(void)
59 {
60 struct
61 {
62 uint8_t Protocol;
63 } SetMode_XPROG_Params;
64
65 Endpoint_Read_Stream_LE(&SetMode_XPROG_Params, sizeof(SetMode_XPROG_Params));
66
67 Endpoint_ClearOUT();
68 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
69
70 XPROG_SelectedProtocol = SetMode_XPROG_Params.Protocol;
71
72 Endpoint_Write_Byte(CMD_XPROG_SETMODE);
73 Endpoint_Write_Byte((SetMode_XPROG_Params.Protocol != XPRG_PROTOCOL_JTAG) ? STATUS_CMD_OK : STATUS_CMD_FAILED);
74 Endpoint_ClearIN();
75 }
76
77 /** Handler for the CMD_XPROG command, which wraps up XPROG commands in a V2 wrapper which need to be
78 * removed and processed so that the underlying XPROG command can be handled.
79 */
80 void XPROGProtocol_Command(void)
81 {
82 uint8_t XPROGCommand = Endpoint_Read_Byte();
83
84 switch (XPROGCommand)
85 {
86 case XPRG_CMD_ENTER_PROGMODE:
87 XPROGProtocol_EnterXPROGMode();
88 break;
89 case XPRG_CMD_LEAVE_PROGMODE:
90 XPROGProtocol_LeaveXPROGMode();
91 break;
92 case XPRG_CMD_ERASE:
93 XPROGProtocol_Erase();
94 break;
95 case XPRG_CMD_WRITE_MEM:
96 XPROGProtocol_WriteMemory();
97 break;
98 case XPRG_CMD_READ_MEM:
99 XPROGProtocol_ReadMemory();
100 break;
101 case XPRG_CMD_CRC:
102 XPROGProtocol_ReadCRC();
103 break;
104 case XPRG_CMD_SET_PARAM:
105 XPROGProtocol_SetParam();
106 break;
107 }
108 }
109
110 /** Handler for the XPROG ENTER_PROGMODE command to establish a connection with the attached device. */
111 static void XPROGProtocol_EnterXPROGMode(void)
112 {
113 Endpoint_ClearOUT();
114 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
115
116 bool NVMBusEnabled;
117
118 if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
119 {
120 /* Enable PDI programming mode with the attached target */
121 XPROGTarget_EnableTargetPDI();
122
123 /* Store the RESET key into the RESET PDI register to keep the XMEGA in reset */
124 XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
125 XPROGTarget_SendByte(PDI_RESET_KEY);
126
127 /* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
128 XPROGTarget_SendByte(PDI_CMD_KEY);
129 for (uint8_t i = sizeof(PDI_NVMENABLE_KEY); i > 0; i--)
130 XPROGTarget_SendByte(PDI_NVMENABLE_KEY[i - 1]);
131
132 /* Wait until the NVM bus becomes active */
133 NVMBusEnabled = XMEGANVM_WaitWhileNVMBusBusy();
134 }
135 else
136 {
137 /* Enable TPI programming mode with the attached target */
138 XPROGTarget_EnableTargetTPI();
139
140 /* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
141 XPROGTarget_SendByte(TPI_CMD_SKEY);
142 for (uint8_t i = sizeof(TPI_NVMENABLE_KEY); i > 0; i--)
143 XPROGTarget_SendByte(TPI_NVMENABLE_KEY[i - 1]);
144
145 /* Wait until the NVM bus becomes active */
146 NVMBusEnabled = TINYNVM_WaitWhileNVMBusBusy();
147 }
148
149 Endpoint_Write_Byte(CMD_XPROG);
150 Endpoint_Write_Byte(XPRG_CMD_ENTER_PROGMODE);
151 Endpoint_Write_Byte(NVMBusEnabled ? XPRG_ERR_OK : XPRG_ERR_FAILED);
152 Endpoint_ClearIN();
153 }
154
155 /** Handler for the XPROG LEAVE_PROGMODE command to terminate the PDI programming connection with
156 * the attached device.
157 */
158 static void XPROGProtocol_LeaveXPROGMode(void)
159 {
160 Endpoint_ClearOUT();
161 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
162
163 if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
164 {
165 /* Clear the RESET key in the RESET PDI register to allow the XMEGA to run */
166 XPROGTarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);
167 XPROGTarget_SendByte(0x00);
168
169 XPROGTarget_DisableTargetPDI();
170 }
171 else
172 {
173 /* Clear the NVMEN bit in the TPI CONTROL register to disable TPI mode */
174 XPROGTarget_SendByte(TPI_CMD_SSTCS | TPI_CTRL_REG);
175 XPROGTarget_SendByte(0x00);
176
177 XPROGTarget_DisableTargetTPI();
178 }
179
180 Endpoint_Write_Byte(CMD_XPROG);
181 Endpoint_Write_Byte(XPRG_CMD_LEAVE_PROGMODE);
182 Endpoint_Write_Byte(XPRG_ERR_OK);
183 Endpoint_ClearIN();
184 }
185
186 /** Handler for the XPRG ERASE command to erase a specific memory address space in the attached device. */
187 static void XPROGProtocol_Erase(void)
188 {
189 uint8_t ReturnStatus = XPRG_ERR_OK;
190
191 struct
192 {
193 uint8_t MemoryType;
194 uint32_t Address;
195 } Erase_XPROG_Params;
196
197 Endpoint_Read_Stream_LE(&Erase_XPROG_Params, sizeof(Erase_XPROG_Params));
198 Erase_XPROG_Params.Address = SwapEndian_32(Erase_XPROG_Params.Address);
199
200 Endpoint_ClearOUT();
201 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
202
203 uint8_t EraseCommand = XMEGA_NVM_CMD_NOOP;
204
205 if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
206 {
207 /* Determine which NVM command to send to the device depending on the memory to erase */
208 if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_CHIP)
209 EraseCommand = XMEGA_NVM_CMD_CHIPERASE;
210 else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_APP)
211 EraseCommand = XMEGA_NVM_CMD_ERASEAPPSEC;
212 else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_BOOT)
213 EraseCommand = XMEGA_NVM_CMD_ERASEBOOTSEC;
214 else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_EEPROM)
215 EraseCommand = XMEGA_NVM_CMD_ERASEEEPROM;
216 else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_APP_PAGE)
217 EraseCommand = XMEGA_NVM_CMD_ERASEAPPSECPAGE;
218 else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_BOOT_PAGE)
219 EraseCommand = XMEGA_NVM_CMD_ERASEBOOTSECPAGE;
220 else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_EEPROM_PAGE)
221 EraseCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGE;
222 else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_USERSIG)
223 EraseCommand = XMEGA_NVM_CMD_ERASEUSERSIG;
224
225 /* Erase the target memory, indicate timeout if ocurred */
226 if (!(XMEGANVM_EraseMemory(EraseCommand, Erase_XPROG_Params.Address)))
227 ReturnStatus = XPRG_ERR_TIMEOUT;
228 }
229 else
230 {
231 /* Erase the target memory, indicate timeout if ocurred */
232 if (!(TINYNVM_EraseMemory()))
233 ReturnStatus = XPRG_ERR_TIMEOUT;
234 }
235
236 Endpoint_Write_Byte(CMD_XPROG);
237 Endpoint_Write_Byte(XPRG_CMD_ERASE);
238 Endpoint_Write_Byte(ReturnStatus);
239 Endpoint_ClearIN();
240 }
241
242 /** Handler for the XPROG WRITE_MEMORY command to write to a specific memory space within the attached device. */
243 static void XPROGProtocol_WriteMemory(void)
244 {
245 uint8_t ReturnStatus = XPRG_ERR_OK;
246
247 struct
248 {
249 uint8_t MemoryType;
250 uint8_t PageMode;
251 uint32_t Address;
252 uint16_t Length;
253 uint8_t ProgData[256];
254 } WriteMemory_XPROG_Params;
255
256 Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params, (sizeof(WriteMemory_XPROG_Params) -
257 sizeof(WriteMemory_XPROG_Params).ProgData));
258 WriteMemory_XPROG_Params.Address = SwapEndian_32(WriteMemory_XPROG_Params.Address);
259 WriteMemory_XPROG_Params.Length = SwapEndian_16(WriteMemory_XPROG_Params.Length);
260 Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length);
261
262 Endpoint_ClearOUT();
263 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
264
265 /* Assume FLASH page programming by default, as it is the common case */
266 uint8_t WriteCommand = XMEGA_NVM_CMD_WRITEFLASHPAGE;
267 uint8_t WriteBuffCommand = XMEGA_NVM_CMD_LOADFLASHPAGEBUFF;
268 uint8_t EraseBuffCommand = XMEGA_NVM_CMD_ERASEFLASHPAGEBUFF;
269 bool PagedMemory = true;
270
271 if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
272 {
273 if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_APPL)
274 {
275 WriteCommand = XMEGA_NVM_CMD_WRITEAPPSECPAGE;
276 }
277 else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_BOOT)
278 {
279 WriteCommand = XMEGA_NVM_CMD_WRITEBOOTSECPAGE;
280 }
281 else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_EEPROM)
282 {
283 WriteCommand = XMEGA_NVM_CMD_WRITEEEPROMPAGE;
284 WriteBuffCommand = XMEGA_NVM_CMD_LOADEEPROMPAGEBUFF;
285 EraseBuffCommand = XMEGA_NVM_CMD_ERASEEEPROMPAGEBUFF;
286 }
287 else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_USERSIG)
288 {
289 /* User signature is paged, but needs us to manually indicate the mode bits since the host doesn't set them */
290 WriteMemory_XPROG_Params.PageMode = (XPRG_PAGEMODE_ERASE | XPRG_PAGEMODE_WRITE);
291 WriteCommand = XMEGA_NVM_CMD_WRITEUSERSIG;
292 }
293 else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_FUSE)
294 {
295 WriteCommand = XMEGA_NVM_CMD_WRITEFUSE;
296 PagedMemory = false;
297 }
298 else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_LOCKBITS)
299 {
300 WriteCommand = XMEGA_NVM_CMD_WRITELOCK;
301 PagedMemory = false;
302 }
303
304 /* Send the appropriate memory write commands to the device, indicate timeout if occurred */
305 if ((PagedMemory && !(XMEGANVM_WritePageMemory(WriteBuffCommand, EraseBuffCommand, WriteCommand,
306 WriteMemory_XPROG_Params.PageMode, WriteMemory_XPROG_Params.Address,
307 WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length))) ||
308 (!PagedMemory && !(XMEGANVM_WriteByteMemory(WriteCommand, WriteMemory_XPROG_Params.Address,
309 WriteMemory_XPROG_Params.ProgData[0]))))
310 {
311 ReturnStatus = XPRG_ERR_TIMEOUT;
312 }
313 }
314 else
315 {
316 /* Send write command to the TPI device, indicate timeout if occurred */
317 if (!(TINYNVM_WriteMemory(WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData[0])))
318 ReturnStatus = XPRG_ERR_TIMEOUT;
319 }
320
321 Endpoint_Write_Byte(CMD_XPROG);
322 Endpoint_Write_Byte(XPRG_CMD_WRITE_MEM);
323 Endpoint_Write_Byte(ReturnStatus);
324 Endpoint_ClearIN();
325 }
326
327 /** Handler for the XPROG READ_MEMORY command to read data from a specific address space within the
328 * attached device.
329 */
330 static void XPROGProtocol_ReadMemory(void)
331 {
332 uint8_t ReturnStatus = XPRG_ERR_OK;
333
334 struct
335 {
336 uint8_t MemoryType;
337 uint32_t Address;
338 uint16_t Length;
339 } ReadMemory_XPROG_Params;
340
341 Endpoint_Read_Stream_LE(&ReadMemory_XPROG_Params, sizeof(ReadMemory_XPROG_Params));
342 ReadMemory_XPROG_Params.Address = SwapEndian_32(ReadMemory_XPROG_Params.Address);
343 ReadMemory_XPROG_Params.Length = SwapEndian_16(ReadMemory_XPROG_Params.Length);
344
345 Endpoint_ClearOUT();
346 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
347
348 uint8_t ReadBuffer[256];
349
350 if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
351 {
352 /* Read the PDI target's memory, indicate timeout if occurred */
353 if (!(XMEGANVM_ReadMemory(ReadMemory_XPROG_Params.Address, ReadBuffer, ReadMemory_XPROG_Params.Length)))
354 ReturnStatus = XPRG_ERR_TIMEOUT;
355 }
356 else
357 {
358 /* Read the TPI target's memory, indicate timeout if occurred */
359 if (!(TINYNVM_ReadMemory(ReadMemory_XPROG_Params.Address, ReadBuffer, ReadMemory_XPROG_Params.Length)))
360 ReturnStatus = XPRG_ERR_TIMEOUT;
361 }
362
363 Endpoint_Write_Byte(CMD_XPROG);
364 Endpoint_Write_Byte(XPRG_CMD_READ_MEM);
365 Endpoint_Write_Byte(ReturnStatus);
366
367 if (ReturnStatus == XPRG_ERR_OK)
368 Endpoint_Write_Stream_LE(ReadBuffer, ReadMemory_XPROG_Params.Length);
369
370 Endpoint_ClearIN();
371 }
372
373 /** Handler for the XPROG CRC command to read a specific memory space's CRC value for comparison between the
374 * attached device's memory and a data set on the host.
375 */
376 static void XPROGProtocol_ReadCRC(void)
377 {
378 uint8_t ReturnStatus = XPRG_ERR_OK;
379
380 struct
381 {
382 uint8_t CRCType;
383 } ReadCRC_XPROG_Params;
384
385 Endpoint_Read_Stream_LE(&ReadCRC_XPROG_Params, sizeof(ReadCRC_XPROG_Params));
386 Endpoint_ClearOUT();
387 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
388
389 uint8_t CRCCommand = XMEGA_NVM_CMD_NOOP;
390 uint32_t MemoryCRC;
391
392 if (XPROG_SelectedProtocol == XPRG_PROTOCOL_PDI)
393 {
394 /* Determine which NVM command to send to the device depending on the memory to CRC */
395 if (ReadCRC_XPROG_Params.CRCType == XPRG_CRC_APP)
396 CRCCommand = XMEGA_NVM_CMD_APPCRC;
397 else if (ReadCRC_XPROG_Params.CRCType == XPRG_CRC_BOOT)
398 CRCCommand = XMEGA_NVM_CMD_BOOTCRC;
399 else
400 CRCCommand = XMEGA_NVM_CMD_FLASHCRC;
401
402 /* Perform and retrieve the memory CRC, indicate timeout if occurred */
403 if (!(XMEGANVM_GetMemoryCRC(CRCCommand, &MemoryCRC)))
404 ReturnStatus = XPRG_ERR_TIMEOUT;
405 }
406 else
407 {
408 /* TPI does not support memory CRC */
409 ReturnStatus = XPRG_ERR_FAILED;
410 }
411
412 Endpoint_Write_Byte(CMD_XPROG);
413 Endpoint_Write_Byte(XPRG_CMD_CRC);
414 Endpoint_Write_Byte(ReturnStatus);
415
416 if (ReturnStatus == XPRG_ERR_OK)
417 {
418 Endpoint_Write_Byte(MemoryCRC >> 16);
419 Endpoint_Write_Word_LE(MemoryCRC & 0xFFFF);
420 }
421
422 Endpoint_ClearIN();
423 }
424
425 /** Handler for the XPROG SET_PARAM command to set a XPROG parameter for use when communicating with the
426 * attached device.
427 */
428 static void XPROGProtocol_SetParam(void)
429 {
430 uint8_t ReturnStatus = XPRG_ERR_OK;
431
432 uint8_t XPROGParam = Endpoint_Read_Byte();
433
434 /* Determine which parameter is being set, store the new parameter value */
435 switch (XPROGParam)
436 {
437 case XPRG_PARAM_NVMBASE:
438 XPROG_Param_NVMBase = Endpoint_Read_DWord_BE();
439 break;
440 case XPRG_PARAM_EEPPAGESIZE:
441 XPROG_Param_EEPageSize = Endpoint_Read_Word_BE();
442 break;
443 case XPRG_PARAM_NVMCMD:
444 XPROG_Param_NVMCMDRegAddr = Endpoint_Read_Byte();
445 break;
446 case XPRG_PARAM_NVMCSR:
447 XPROG_Param_NVMCSRRegAddr = Endpoint_Read_Byte();
448 break;
449 default:
450 ReturnStatus = XPRG_ERR_FAILED;
451 break;
452 }
453
454 Endpoint_ClearOUT();
455 Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
456
457 Endpoint_Write_Byte(CMD_XPROG);
458 Endpoint_Write_Byte(XPRG_CMD_SET_PARAM);
459 Endpoint_Write_Byte(ReturnStatus);
460 Endpoint_ClearIN();
461 }
462
463 #endif