PDIProtocol.c 12.2 KB
Newer Older
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
/*
             LUFA Library
     Copyright (C) Dean Camera, 2009.
              
  dean [at] fourwalledcubicle [dot] com
      www.fourwalledcubicle.com
*/

/*
  Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, and distribute this software
  and its documentation for any purpose and without fee is hereby
  granted, provided that the above copyright notice appear in all
  copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

/** \file
 *
 *  PDI Protocol handler, to process V2 Protocol wrapped PDI commands used in Atmel programmer devices.
 */

36
#define  INCLUDE_FROM_PDIPROTOCOL_C
37
38
#include "PDIProtocol.h"

39
#if defined(ENABLE_PDI_PROTOCOL) || defined(__DOXYGEN__)
40
#warning PDI Programming Protocol support is incomplete and not currently suitable for general use.
41

42
/** Base absolute address for the target's NVM controller */
43
uint32_t XPROG_Param_NVMBase;
44
45

/** Size in bytes of the target's EEPROM page */
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
uint32_t XPROG_Param_EEPageSize;

/** Handler for the CMD_XPROG_SETMODE command, which sets the programmer-to-target protocol used for PDI
 *  XMEGA programming (either PDI or JTAG). Only PDI programming is supported.
 */
void PDIProtocol_XPROG_SetMode(void)
{
	struct
	{
		uint8_t Protocol;
	} SetMode_XPROG_Params;
	
	Endpoint_Read_Stream_LE(&SetMode_XPROG_Params, sizeof(SetMode_XPROG_Params));

	Endpoint_ClearOUT();
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
	
	Endpoint_Write_Byte(CMD_XPROG_SETMODE);
64
	Endpoint_Write_Byte((SetMode_XPROG_Params.Protocol == XPRG_PROTOCOL_PDI) ? STATUS_CMD_OK : STATUS_CMD_FAILED);
65
66
67
	Endpoint_ClearIN();	
}

68
69
70
/** Handler for the CMD_XPROG command, which wraps up XPROG commands in a V2 wrapper which need to be
 *  removed and processed so that the underlying XPROG command can be handled.
 */
71
72
73
74
75
76
77
78
79
80
81
82
83
void PDIProtocol_XPROG_Command(void)
{
	uint8_t XPROGCommand = Endpoint_Read_Byte();

	switch (XPROGCommand)
	{
		case XPRG_CMD_ENTER_PROGMODE:
			PDIProtocol_EnterXPROGMode();
			break;
		case XPRG_CMD_LEAVE_PROGMODE:
			PDIProtocol_LeaveXPROGMode();
			break;
		case XPRG_CMD_ERASE:
84
			PDIProtocol_Erase();
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
			break;
		case XPRG_CMD_WRITE_MEM:
			PDIProtocol_WriteMemory();
			break;
		case XPRG_CMD_READ_MEM:
			PDIProtocol_ReadMemory();
			break;
		case XPRG_CMD_CRC:
			PDIProtocol_ReadCRC();
			break;
		case XPRG_CMD_SET_PARAM:
			PDIProtocol_SetParam();
			break;
	}
}

101
/** Handler for the XPROG ENTER_PROGMODE command to establish a PDI connection with the attached device. */
102
103
104
105
106
static void PDIProtocol_EnterXPROGMode(void)
{
	Endpoint_ClearOUT();
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
	
107
108
	/* Enable PDI programming mode with the attached target */
	PDITarget_EnableTargetPDI();
109
	
110
	/* Store the RESET key into the RESET PDI register to keep the XMEGA in reset */
111
	PDITarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);	
112
113
	PDITarget_SendByte(PDI_RESET_KEY);

114
	/* Enable access to the XPROG NVM bus by sending the documented NVM access key to the device */
115
	PDITarget_SendByte(PDI_CMD_KEY);	
116
117
	for (uint8_t i = sizeof(PDI_NVMENABLE_KEY); i > 0; i--)
	  PDITarget_SendByte(PDI_NVMENABLE_KEY[i - 1]);
118

119
	/* Wait until the NVM bus becomes active */
120
	bool NVMBusEnabled = PDITarget_WaitWhileNVMBusBusy();
121
122
123
	
	Endpoint_Write_Byte(CMD_XPROG);
	Endpoint_Write_Byte(XPRG_CMD_ENTER_PROGMODE);
124
	Endpoint_Write_Byte(NVMBusEnabled ? XPRG_ERR_OK : XPRG_ERR_FAILED);
125
126
127
	Endpoint_ClearIN();
}

128
129
130
/** Handler for the XPROG LEAVE_PROGMODE command to terminate the PDI programming connection with
 *  the attached device.
 */
131
132
133
134
135
static void PDIProtocol_LeaveXPROGMode(void)
{
	Endpoint_ClearOUT();
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
	
136
	/* Clear the RESET key in the RESET PDI register to allow the XMEGA to run */
137
	PDITarget_SendByte(PDI_CMD_STCS | PDI_RESET_REG);	
138
139
	PDITarget_SendByte(0x00);

140
141
	PDITarget_DisableTargetPDI();

142
143
144
145
146
147
	Endpoint_Write_Byte(CMD_XPROG);
	Endpoint_Write_Byte(XPRG_CMD_LEAVE_PROGMODE);
	Endpoint_Write_Byte(XPRG_ERR_OK);
	Endpoint_ClearIN();
}

148
149
/** Handler for the XPRG ERASE command to erase a specific memory address space in the attached device. */
static void PDIProtocol_Erase(void)
150
151
152
153
154
155
156
157
158
159
{
	uint8_t ReturnStatus = XPRG_ERR_OK;

	struct
	{
		uint8_t  MemoryType;
		uint32_t Address;
	} Erase_XPROG_Params;

	Endpoint_Read_Stream_LE(&Erase_XPROG_Params, sizeof(Erase_XPROG_Params));
160
	Erase_XPROG_Params.Address = SwapEndian_32(Erase_XPROG_Params.Address);
161
162
163
164

	Endpoint_ClearOUT();
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
	
165
	uint8_t EraseCommand = NVM_CMD_NOOP;
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
	
	if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_CHIP)
	  EraseCommand = NVM_CMD_CHIPERASE;
	else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_APP)
	  EraseCommand = NVM_CMD_ERASEAPPSEC;
	else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_BOOT)
	  EraseCommand = NVM_CMD_ERASEBOOTSEC;
	else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_EEPROM)
	  EraseCommand = NVM_CMD_ERASEEEPROM;
	else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_APP_PAGE)
	  EraseCommand = NVM_CMD_ERASEAPPSECPAGE;
	else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_BOOT_PAGE)
	  EraseCommand = NVM_CMD_ERASEBOOTSECPAGE;
	else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_EEPROM_PAGE)
	  EraseCommand = NVM_CMD_ERASEEEPROMPAGE;
	else if (Erase_XPROG_Params.MemoryType == XPRG_ERASE_USERSIG)
	  EraseCommand = NVM_CMD_ERASEUSERSIG;
	
184
185
	if (!(NVMTarget_EraseMemory(EraseCommand, Erase_XPROG_Params.Address)))
	  ReturnStatus = XPRG_ERR_TIMEOUT;
186
187
188
189
190
191
192
	
	Endpoint_Write_Byte(CMD_XPROG);
	Endpoint_Write_Byte(XPRG_CMD_ERASE);
	Endpoint_Write_Byte(ReturnStatus);
	Endpoint_ClearIN();	
}

193
/** Handler for the XPROG WRITE_MEMORY command to write to a specific memory space within the attached device. */
194
195
196
197
198
199
200
static void PDIProtocol_WriteMemory(void)
{
	uint8_t ReturnStatus = XPRG_ERR_OK;

	struct
	{
		uint8_t  MemoryType;
201
		uint8_t  PageMode;
202
203
		uint32_t Address;
		uint16_t Length;
204
		uint8_t  ProgData[256];
205
206
207
208
209
210
211
212
213
214
	} WriteMemory_XPROG_Params;
	
	Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params, (sizeof(WriteMemory_XPROG_Params) -
	                                                    sizeof(WriteMemory_XPROG_Params).ProgData));
	WriteMemory_XPROG_Params.Address = SwapEndian_32(WriteMemory_XPROG_Params.Address);
	WriteMemory_XPROG_Params.Length  = SwapEndian_16(WriteMemory_XPROG_Params.Length);
	Endpoint_Read_Stream_LE(&WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length);

	Endpoint_ClearOUT();
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
215
216
217


	uint8_t WriteCommand     = NVM_CMD_NOOP;
218
219
	uint8_t WriteBuffCommand = NVM_CMD_NOOP;
	uint8_t EraseBuffCommand = NVM_CMD_NOOP;
220
221
222
223
	bool    PagedMemory      = false;
	
	if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_APPL)
	{
224
225
226
227
		WriteCommand     = NVM_CMD_ERASEWRITEFLASH;
		WriteBuffCommand = NVM_CMD_LOADFLASHPAGEBUFF;
		EraseBuffCommand = NVM_CMD_ERASEFLASHPAGEBUFF;
		PagedMemory      = true;
228
229
230
	}
	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_BOOT)
	{
231
232
233
234
		WriteCommand     = NVM_CMD_ERASEWRITEFLASH;
		WriteBuffCommand = NVM_CMD_LOADFLASHPAGEBUFF;
		EraseBuffCommand = NVM_CMD_ERASEFLASHPAGEBUFF;
		PagedMemory      = true;
235
236
237
	}
	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_EEPROM)
	{
238
239
240
241
		WriteCommand     = NVM_CMD_ERASEWRITEEEPROMPAGE;
		WriteBuffCommand = NVM_CMD_LOADEEPROMPAGEBUFF;
		EraseBuffCommand = NVM_CMD_ERASEEEPROMPAGEBUFF;
		PagedMemory      = true;
242
243
244
	}
	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_USERSIG)
	{
245
246
247
248
		WriteCommand     = NVM_CMD_WRITEUSERSIG;
		WriteBuffCommand = NVM_CMD_LOADFLASHPAGEBUFF;
		EraseBuffCommand = NVM_CMD_ERASEFLASHPAGEBUFF;
		PagedMemory      = true;
249
250
251
252
253
254
255
256
257
	}
	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_FUSE)
	{
		WriteCommand = NVM_CMD_WRITEFUSE;
	}
	else if (WriteMemory_XPROG_Params.MemoryType == XPRG_MEM_TYPE_LOCKBITS)
	{
		WriteCommand = NVM_CMD_WRITELOCK;
	}
258
	
259
260
	if (PagedMemory)
	{
261
262
263
264
265
266
		if (!(NVMTarget_WritePageMemory(WriteBuffCommand, EraseBuffCommand, WriteCommand, 
		                                WriteMemory_XPROG_Params.PageMode, WriteMemory_XPROG_Params.Address,
		                                WriteMemory_XPROG_Params.ProgData, WriteMemory_XPROG_Params.Length)))
		{
			ReturnStatus = XPRG_ERR_TIMEOUT;
		}
267
268
269
270
271
272
273
274
275
	}
	else
	{
		if (!(NVMTarget_WriteByteMemory(WriteCommand, WriteMemory_XPROG_Params.Address, WriteMemory_XPROG_Params.ProgData,
										WriteMemory_XPROG_Params.Length)))
		{
			ReturnStatus = XPRG_ERR_TIMEOUT;
		}
	}
276
277
	
	Endpoint_Write_Byte(CMD_XPROG);
278
	Endpoint_Write_Byte(XPRG_CMD_WRITE_MEM);
279
280
281
282
	Endpoint_Write_Byte(ReturnStatus);	
	Endpoint_ClearIN();
}

283
284
285
/** Handler for the XPROG READ_MEMORY command to read data from a specific address space within the
 *  attached device.
 */
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
static void PDIProtocol_ReadMemory(void)
{
	uint8_t ReturnStatus = XPRG_ERR_OK;

	struct
	{
		uint8_t  MemoryType;
		uint32_t Address;
		uint16_t Length;
	} ReadMemory_XPROG_Params;
	
	Endpoint_Read_Stream_LE(&ReadMemory_XPROG_Params, sizeof(ReadMemory_XPROG_Params));
	ReadMemory_XPROG_Params.Address = SwapEndian_32(ReadMemory_XPROG_Params.Address);
	ReadMemory_XPROG_Params.Length  = SwapEndian_16(ReadMemory_XPROG_Params.Length);

	Endpoint_ClearOUT();
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
303

304
	uint8_t ReadBuffer[ReadMemory_XPROG_Params.Length];
305
306
307
	
	if (!(NVMTarget_ReadMemory(ReadMemory_XPROG_Params.Address, ReadBuffer, ReadMemory_XPROG_Params.Length)))
	  ReturnStatus = XPRG_ERR_TIMEOUT;
308

309
310
311
312
	Endpoint_Write_Byte(CMD_XPROG);
	Endpoint_Write_Byte(XPRG_CMD_READ_MEM);
	Endpoint_Write_Byte(ReturnStatus);
	
313
314
315
	if (ReturnStatus == XPRG_ERR_OK)
	  Endpoint_Write_Stream_LE(ReadBuffer, ReadMemory_XPROG_Params.Length);
	
316
317
318
	Endpoint_ClearIN();
}

319
320
321
/** Handler for the XPROG CRC command to read a specific memory space's CRC value for comparison between the
 *  attached device's memory and a data set on the host.
 */
322
323
324
325
static void PDIProtocol_ReadCRC(void)
{
	uint8_t ReturnStatus = XPRG_ERR_OK;
	
326
327
328
329
330
331
	struct
	{
		uint8_t CRCType;
	} ReadCRC_XPROG_Params;
	
	Endpoint_Read_Stream_LE(&ReadCRC_XPROG_Params, sizeof(ReadCRC_XPROG_Params));
332
333
334
	Endpoint_ClearOUT();
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
	
335
	uint8_t  CRCCommand = NVM_CMD_NOOP;
336
	uint32_t MemoryCRC;
337
338

	if (ReadCRC_XPROG_Params.CRCType == XPRG_CRC_APP)
339
	  CRCCommand = NVM_CMD_APPCRC;
340
	else if (ReadCRC_XPROG_Params.CRCType == XPRG_CRC_BOOT)
341
	  CRCCommand = NVM_CMD_BOOTCRC;
342
	else
343
344
	  CRCCommand = NVM_CMD_FLASHCRC;
	
345
346
	if (!(NVMTarget_GetMemoryCRC(CRCCommand, &MemoryCRC)))
	  ReturnStatus = XPRG_ERR_TIMEOUT;
347
348
349
350
351
352
353
354
355
356
357
358
359
360
	
	Endpoint_Write_Byte(CMD_XPROG);
	Endpoint_Write_Byte(XPRG_CMD_CRC);
	Endpoint_Write_Byte(ReturnStatus);
	
	if (ReturnStatus == XPRG_ERR_OK)
	{
		Endpoint_Write_Byte(MemoryCRC >> 16);
		Endpoint_Write_Word_LE(MemoryCRC & 0xFFFF);		
	}
	
	Endpoint_ClearIN();	
}

361
362
363
/** Handler for the XPROG SET_PARAM command to set a PDI parameter for use when communicating with the
 *  attached device.
 */
364
365
366
367
368
369
370
static void PDIProtocol_SetParam(void)
{
	uint8_t ReturnStatus = XPRG_ERR_OK;

	uint8_t XPROGParam = Endpoint_Read_Byte();
	
	if (XPROGParam == XPRG_PARAM_NVMBASE)
371
	  XPROG_Param_NVMBase = Endpoint_Read_DWord_BE();
372
	else if (XPROGParam == XPRG_PARAM_EEPPAGESIZE)
373
	  XPROG_Param_EEPageSize = Endpoint_Read_Word_BE();
374
375
376
377
378
379
380
381
382
383
384
385
386
	else
	  ReturnStatus = XPRG_ERR_FAILED;
	
	Endpoint_ClearOUT();
	Endpoint_SetEndpointDirection(ENDPOINT_DIR_IN);
		  
	Endpoint_Write_Byte(CMD_XPROG);
	Endpoint_Write_Byte(XPRG_CMD_SET_PARAM);
	Endpoint_Write_Byte(ReturnStatus);
	Endpoint_ClearIN();
}

#endif