This is an automated email from Gerrit. "ahmed BOUDJELIDA <aboudjel...@nanoxplore.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7702
-- gerrit commit 264bf39788c9c1f5008e7c91b37632fa93fe6b15 Author: Ahmed BOUDJELIDA <aboudjel...@nanoxplore.com> Date: Sat Jun 17 01:11:15 2023 +0200 jtag/drivers: Add new driver for ANGIE USB-JTAG Adapter This is a driver code for NanoXplore's ANGIE USB-JTAG Adapter. The driver and firmware are based on the openULINK project. Since the ANGIE Adapter has a Spartan-6 FPGA in addition to the FX2 microcontroller, the driver adds a function "angie_load_bitstream" that programs this FPGA. Change-Id: Id17111c74073da01450d43d466e11b0cc086691f Signed-off-by: Ahmed BOUDJELIDA <aboudjel...@nanoxplore.com> diff --git a/configure.ac b/configure.ac index ac2808e1f5..ecf8384bf8 100644 --- a/configure.ac +++ b/configure.ac @@ -118,6 +118,7 @@ m4_define([USB1_ADAPTERS], [[stlink], [ST-Link Programmer], [HLADAPTER_STLINK]], [[ti_icdi], [TI ICDI JTAG Programmer], [HLADAPTER_ICDI]], [[ulink], [Keil ULINK JTAG Programmer], [ULINK]], + [[angie], [ANGIE Adapter], [ANGIE]], [[usb_blaster_2], [Altera USB-Blaster II Compatible], [USB_BLASTER_2]], [[ft232r], [Bitbang mode of FT232R based devices], [FT232R]], [[vsllink], [Versaloon-Link JTAG Programmer], [VSLLINK]], diff --git a/doc/openocd.texi b/doc/openocd.texi index 832047f0ea..c902c7029c 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -514,6 +514,9 @@ debuggers to ARM Cortex based targets @url{http://www.keil.com/support/man/docs/ @item @b{Keil ULINK v1} @* Link: @url{http://www.keil.com/ulink1/} +@item @b{angie} +@* Link: @url{https://nanoxplore.org/} + @item @b{TI XDS110 Debug Probe} @* Link: @url{https://software-dl.ti.com/ccs/esd/documents/xdsdebugprobes/emu_xds110.html} @* Link: @url{https://software-dl.ti.com/ccs/esd/documents/xdsdebugprobes/emu_xds_software_package_download.html#xds110-support-utilities} @@ -3241,6 +3244,14 @@ opendous-jtag is a freely programmable USB adapter. This is the Keil ULINK v1 JTAG debugger. @end deffn +@deffn {Interface Driver} {angie} +This is the NanoXplore's ANGIE USB-JTAG Adapter. + +@deffn {Command} {angie download_firmware} +Downloads ANGIE's firmware image (.hex) to the Cypress FX2 microcontroller. +@end deffn +@end deffn + @deffn {Interface Driver} {xds110} The XDS110 is included as the embedded debug probe on many Texas Instruments LaunchPad evaluation boards. The XDS110 is also available as a stand-alone USB diff --git a/src/jtag/drivers/ANGIE/README b/src/jtag/drivers/ANGIE/README new file mode 100644 index 0000000000..e30b931789 --- /dev/null +++ b/src/jtag/drivers/ANGIE/README @@ -0,0 +1,2 @@ +This folder contain only the files needed by ANGIE's driver. +You will find the complete ANGIE's firmware folder in contrib/firmware. diff --git a/src/jtag/drivers/ANGIE/angie_bitstream.bit b/src/jtag/drivers/ANGIE/angie_bitstream.bit new file mode 100644 index 0000000000..5718d15032 Binary files /dev/null and b/src/jtag/drivers/ANGIE/angie_bitstream.bit differ diff --git a/src/jtag/drivers/ANGIE/angie_firmware.hex b/src/jtag/drivers/ANGIE/angie_firmware.hex new file mode 100644 index 0000000000..252d0c4905 --- /dev/null +++ b/src/jtag/drivers/ANGIE/angie_firmware.hex @@ -0,0 +1,611 @@ +:040000000200713257 +:01000B0032C2 +:0100130032BA +:01001B0032B2 +:0100230032AA +:01002B0032A2 +:01003300329A +:01003B003292 +:01004300328A +:01004B003282 +:01005300327A +:01005B003272 +:01006300326A +:03006B0002010887 +:0300CA0002006EC3 +:03006E000200CDC0 +:1000CD0090E600E054E74412F090E100E4F5F01200 +:1000DD0016E11207191217DF1207C41207F090E686 +:1000ED0080E043E00AF09000FA1216B790E680E047 +:1000FD0053E0F7F0120C4A90000022C020C0E0C07F +:10010D00F0C082C083C007C006C005C004C003C0D4 +:10011D0002C001C000C0D075D0005391EF90E65DD4 +:10012D007401F090E6A0E043E080F012064CD0D0D0 +:10013D00D000D001D002D003D004D005D006D00716 +:10014D00D083D082D0F0D0E0D02032323232323271 +:10015D0032323232C0E0C082C0837509015391EF53 +:10016D0090E65F7404F0D083D082D0E032C0E0C05E +:10017D0082C0837508015391EF90E65F7408F0D04B +:10018D0083D082D0E03275080032323232323232D0 +:10019D003232323232323232323232323232323232 +:1001AD0032323232323232AF82747F5FFE24F750F8 +:1001BD0003020208EE240A83F582EE240D83F583F3 +:1001CD00E473E1E5F808FC080008040101010201EF +:1001DD000202020290E6A022EF30E7067EA27FE641 +:1001ED0080047EA17FE68E828F832290E6A32290EB +:1001FD00E6A42290E6A52290E6A62290000022AF6A +:10020D00828F05530580E4C423CDC423541F6DCDC7 +:10021D00541FCD6DCD30E40244E0740F5F90E68342 +:10022D002DF0E043E020F02290E6B8E0FFBF800221 +:10023D00800DBF81028029BF820280450202D390CA +:10024D00E740E4F090E741F090E68AF07582031202 +:10025D00165F90E68B7402F075820312165F806A4A +:10026D0090E740E4F090E741F090E68AF075820364 +:10027D0012165F90E68B7402F075820312165F8082 +:10028D004990E6BCE0F5821201B4AE82AF837D00E9 +:10029D008E828F838DF01222A830E00890E7407493 +:1002AD0001F0800590E740E4F090E741E4F090E63E +:1002BD008AF075820312165F90E68B7402F07582D8 +:1002CD000312165F8004758200227582012290E66A +:1002DD00B8E0FFFEBE00028005BF0244800A90E632 +:1002ED00A0E043E001F0803890E6BAE0FEA3E0FF25 +:1002FD004E702590E6BCE0F5821201B4AE82AF835C +:10030D00EE4F7003F582228E828F83E0FD5305FE42 +:10031D008E828F83EDF0800890E6A0E043E001F03F +:10032D007582012290E6B8E0FFFEBE00028005BF97 +:10033D000247801290E6BAE0FEA3E0FFBE023ABF8C +:10034D0000377582012290E6BAE0FEA3E04E7025DB +:10035D0090E6BCE0F5821201B4AE82AF83EE4F7031 +:10036D0003F582228E828F83E0FD4305018E828FFD +:10037D0083EDF08004758200227582012290E6BA29 +:10038D00E0A3E0FF90E6BAE0FEBF0102800DBF02E0 +:10039D0002801ABF030280260204357DC87F229099 +:1003AD00E6B3EFF090E6B474C8F00204397DDA7F5D +:1003BD002290E6B3EFF090E6B474DAF0806E90E63A +:1003CD00BCE0FDA3E04D70117D167F2390E6B3EFE9 +:1003DD00F090E6B47416F0805390E6BCE0FDA3E017 +:1003ED00FFBD0940BF043D1EC2D575F002EE30E7DA +:1003FD0004B2D5F404A430D50AF42401C5F0F434C4 +:10040D0000C5F02480F582742335F0F583E493FE66 +:10041D00A3E493FF8E048F0590E6B3EDF090E6B460 +:10042D00EEF080087582002275820022758201220D +:10043D0075828412020C75820212020C90E6A2746F +:10044D0002F090E6A1E4F090E68DF07582030216BD +:10045D005FAC82AD83AEF0FF90E6CEF0758203C047 +:10046D0007C006C005C00412165FD004D005D00623 +:10047D0090E6CFEEF0758203C006C005C0041216DB +:10048D005FD004D00590E6D0EDF0758203C005C0B5 +:10049D000412165FD004D005D006D00790E6D1EC3B +:1004AD00F022750C40750DE790E6BEE0F50EA3E069 +:1004BD00F50F90E6B8E0FF30E733AE0EAF0FC37423 +:1004CD00409EE49F50067E407F008004AE0EAF0F2D +:1004DD008E0B750A00C3E50A950B5011E50A250C24 +:1004ED00F582E4350DF583E4F0050A80E890E6B970 +:1004FD00E0FFBFB0028009BFB1030205E802064468 +:10050D0090E68AE4F090E68BF090E6A0E020E1F929 +:10051D00850C82850D83E0FC7F007E007D00850CBF +:10052D0082850D83A3E0F8790089038802E4F942FE +:10053D0007E94206EA4205EB4204850C82850D83EC +:10054D00A3A3E0F879007A008A0389028801E442C6 +:10055D0007E94206EA4205EB4204850C82850D83CC +:10056D00A3A3A3E0F879007A007B00903C00E84F4C +:10057D00F0E94EA3F0EA4DA3F0EB4CA3F090E6BAF0 +:10058D00E0FEA3E05306C07F00BE0005BF00028061 +:10059D0003020648C28590E6C074F2F0758203121C +:1005AD00165F90E6187410F075820312165FD285EF +:1005BD0090000A1216B7903C00E0FCA3E0FDA3E00A +:1005CD00FEA3E08C828D838EF012045EC282C28304 +:1005DD0075BB0075820312165F8060750A0AE5BB54 +:1005ED0020E726AF0A150AEF70177488C0E0742350 +:1005FD00C0E07480C0E01219C51581158115818088 +:10060D00089000011216B780D590E6BAE0FEA3E07F +:10061D005306C07F00BE000FBF000CD283D2829064 +:10062D00E601E053E0FCF090E68AE4F090E6BEE0EF +:10063D00FF90E68BF0800475820122758200229076 +:10064D00E6B9E0FF24F35003020709EF240A83F50E +:10065D0082EF241183F583E4738091A2ABA218C4B9 +:10066D00BBD418ED0618060606060607060606078D +:10067D00060707120235E58260012290E6A0E043ED +:10068D00E001F0221202DBE58260012290E6A0E09B +:10069D0043E001F02290E6A0E043E001F0221203D6 +:1006AD0031E582706690E6A0E043E001F02290E62D +:1006BD00A0E043E001F02212038AE582704D90E63E +:1006CD00A0E043E001F0229022DFE49390E740F0B8 +:1006DD0090E68AE4F090E68B04F075820302165FD3 +:1006ED009022E5E49390E740F090E68AE4F090E6FE +:1006FD008B04F075820302165F02043D1204AFE510 +:10070D0082600890E6A0E043E001F02290E61174CB +:10071D00A0F075820312165F90E61074A0F075823A +:10072D000312165F90E61274A0F075820312165F25 +:10073D0090E613E4F075820312165F90E614E4F070 +:10074D0075820312165F90E615E4F075820312169A +:10075D005F90E68DE4F075820312165F90E68DE4EE +:10076D00F075820312165F90E68FE4F07582031226 +:10077D00165F90E68FE4F075820312165F90E60423 +:10078D007480F075820312165F90E6047402F075A2 +:10079D00820312165F90E604E4F075820312165F71 +:1007AD0090E618E4F075820312165F90E618741047 +:1007BD00F075820302165FD2AFD2E843D82090E6DF +:1007CD0068E043E009F090E65EE043E00CF090E66F +:1007DD005F740CF090E65CE043E001F090E65D7430 +:1007ED0001F02290E6707401F075B2EF7580FFD2C2 +:1007FD0082D283D28575B3EF7590FFD290C291C22C +:10080D0092C293D29590E671E4F075B4EF75A0FFA6 +:01081D0022B8 +:1022C80012010002FFFFFF404E584E42000001027B +:1022D80003010902270001010480320904000003F8 +:1022E800FFFFFF00070501024000000705810240CB +:1022F8000000070502020002000705840200020030 +:102308000705060200020007050802000200040390 +:10231800090422034E0061006E006F00580070002F +:102328006C006F00720065002C0020005300410013 +:1023380053002E001C0341004E0047004900450091 +:1023480020004100640061007000740065007200A4 +:102358000E033000300030003000300031001A0326 +:102368004A00540041004700200041006400610019 +:1023780070007400650072001A233C2358236623FA +:102388004750494620646F6E652074696D65206FFB +:0423980075740A004E +:10081E007F00E5102480F582E434E7F583E0FE6086 +:10082E005DBE010302098DBE02030208B8BE0303BA +:10083E000209B9BE04030208E1BE05030209E2BEC5 +:10084E00200302090EBE2103020A0FBE2203020973 +:10085E004ABE2303020A4BBE2403020A8EBE2503A0 +:10086E00020AD1BE2603020B14BE2703020B4DBE95 +:10087E002803020B89BE2A03020C07020C0B7E050D +:10088E00AD100DED3395E0FCED2480F582EC34E7F0 +:10089E00F583E0FFE51004F582851126C007C0063A +:1008AE00120C92D006D007020C0DAD100DED339543 +:1008BE00E0FCED2480F582EC34E7F583E02405FEC0 +:1008CE00E51004F582C007C006120F46D006D00709 +:1008DE00020C0DAD100DED3395E0FCED2480F5828C +:1008EE00EC34E7F583E0FF2405FEE51004F5828580 +:1008FE00113DC007C00612120DD006D007020C0D16 +:10090E007E02AD100DED3395E0FCED2480F582EC0A +:10091E0034E7F583E0FDAC100C0CEC3395E0FBEC0A +:10092E002480F582EB34E7F583E0F5188D82C0075D +:10093E00C0061215B9D006D007020C0D7E02AD10FE +:10094E000DED3395E0FCED2480F582EC34E7F58374 +:10095E00E0FD7C00AB100B0BEB3395E0FAEB248043 +:10096E00F582EA34E7F583E0FAE44DF582EA4CF5D8 +:10097E0083C007C00612155DD006D007020C0D7E8F +:10098E0005AD100DED3395E0FCED2480F582EC34D1 +:10099E00E7F583E0FFE51004F58285112CC007C052 +:1009AE0006120DD6D006D007020C0DAD100DED338C +:1009BE0095E0FCED2480F582EC34E7F583E0240528 +:1009CE00FEE51004F582C007C006121094D006D0C2 +:1009DE0007020C0DAD100DED3395E0FCED2480F506 +:1009EE0082EC34E7F583E0FF2405FEE51004F58282 +:1009FE00851144C007C0061213A3D006D007020CFF +:100A0E000D7E02AD100DED3395E0FCED2480F582E8 +:100A1E00EC34E7F583E0FDAC100C0CEC3395E0FB09 +:100A2E00EC2480F582EB34E7F583E0F5188D82C077 +:100A3E0007C0061215E5D006D007020C0D7E02ADDA +:100A4E00100DED3395E0FCED2480F582EC34E7F5E6 +:100A5E0083E0FD7C00AB100B0BEB3395E0FAEB243F +:100A6E0080F582EA34E7F583E0FAE44DF582EA4C4C +:100A7E00F583C007C006121580D006D007020C0DF4 +:100A8E007E02AD100DED3395E0FCED2480F582EC89 +:100A9E0034E7F583E0FD7C00AB100B0BEB3395E0F8 +:100AAE00FAEB2480F582EA34E7F583E0FAE44DF5BB +:100ABE0082EA4CF583C007C006121684D006D00712 +:100ACE00020C0D7E02AD100DED3395E0FCED248091 +:100ADE00F582EC34E7F583E0FD7C00AB100B0BEBFD +:100AEE003395E0FAEB2480F582EA34E7F583E0FAF9 +:100AFE00E44DF582EA4CF583C007C0061216B7D056 +:100B0E0006D007020C0D7E007F02C007C00612162B +:100B1E0027AC82AD83D006D007E51124C0F582E460 +:100B2E0034E7F5838D03EBF0AB110BEB3395E0FA65 +:100B3E00EB24C0F582EA34E7F583ECF0020C0D7E6F +:100B4E0002AD100DED3395E0FCED2480F582EC3412 +:100B5E00E7F583E0FDAC100C0CEC3395E0FBEC24D8 +:100B6E0080F582EB34E7F583E0F5188D82C007C07F +:100B7E0006121641D006D007020C0D7E05AD100DE3 +:100B8E00ED3395E0FCED2480F582EC34E7F583E05F +:100B9E00FDAC100C0CEC3395E0FBEC2480F582EBF5 +:100BAE0034E7F583E0F518AC100C0C0CEC3395E043 +:100BBE00FBEC2480F582EB34E7F583E0F519E510C4 +:100BCE002404FC3395E0FBEC2480F582EB34E7F54E +:100BDE0083E0F51AAC10EE2CFC3395E0FBEC248090 +:100BEE00F582EB34E7F583E0F51B8D82C007C00676 +:100BFE0012164FD006D00780067E0180027E00EFCF +:100C0E002511F511AD107F008E037C00EB2DFDEC50 +:100C1E003FFF0DBD00010F90E68DE0FC7B00C3EDA4 +:100C2E009CEF64808BF063F08095F0400475820138 +:100C3E00220EAF10EE2FF510758200227510007582 +:100C4E001100E50860FC7508007F00EF70071208C0 +:100C5E001EAF8280F6E511601390E68FE511F075F8 +:100C6E00820312165FE50960FC75090090E68DE4BB +:100C7E00F075820312165F90E68DE4F07582031212 +:100C8E00165F80B8E582FF2480F582E434E7F583B1 +:100C9E00E0F527EF04FD3395E0FCED2480F582ECC2 +:100CAE0034E7F583E0F52874022FFC3395E0FBEC76 +:100CBE002480F582EB34E7F583E0C4540FFA530237 +:100CCE000FEC2480F582EB34E7F583E0FC740F5CC7 +:100CDE00F52974032FF93395E0FBE92480F582EBB7 +:100CEE0034E7F583E0FBEF2404F93395E0FFE924C4 +:100CFE0080F582EF34E7F583E0F52AEA60078B187A +:100D0E008A821215B974F15590FB7A00A8277900E2 +:100D1E0018B8FF01198A047E00C3EC98EE6480892E +:100D2E00F063F08095F0502C7E007C008B90EEC32B +:100D3E0013FE74044BF5903094034306800CBC08EC +:100D4E000040E9E5262A24C0F582E434E7F583EE77 +:100D5E00F00A80B88A06752B00AA297900C3E99596 +:100D6E00285038A8287F0018B8FF011F89047D007D +:100D7E00ECB50011EDB5070DEA600A4303021AE562 +:100D8E002AC313F52A8B90E52BC313F52B74044B52 +:100D9E00F590309403432B800980C27408C39528C4 +:100DAE00F5F005F0E52B8002C313D5F0FBFFE52629 +:100DBE002E24C0F582E434E7F583EFF0EA6008856F +:100DCE002A188A820215B922E582FF2480F582E470 +:100DDE0034E7F583E0F52DEF04FD3395E0FCED24CB +:100DEE0080F582EC34E7F583E0F52E74022FFC33A8 +:100DFE0095E0FBEC2480F582EB34E7F583E0C454F8 +:100E0E000FFA53020FEC2480F582EB34E7F583E002 +:100E1E00FC740F5CF52F74032FF93395E0FBE92476 +:100E2E0080F582EB34E7F583E0FBEF2404F933958C +:100E3E00E0FFE92480F582EF34E7F583E0F530EA50 +:100E4E0060078B188A821215E574F15590FB7A00B3 +:100E5E00A82D790018B8FF01198A047E00C3EC98FA +:100E6E00EE648089F063F08095F050427E007C0045 +:100E7E008B907900C3E9952150030980F7EEC313D7 +:100E8E00FE74044BF5907900C3E995215003098057 +:100E9E00F73094034306800CBC080040D3E52C2A9F +:100EAE0024C0F582E434E7F583EEF00A80A28A06C8 +:100EBE00753100AA2F7900C3E9952E504EA82E7FCA +:100ECE000018B8FF011F89047D00ECB50011EDB5C7 +:100EDE00070DEA600A4303021AE530C313F5308B9F +:100EEE00907F00C3EF952150030F80F7E531C313B8 +:100EFE00F53174044BF5907F00C3EF952150030F2D +:100F0E0080F73094034331800980AC7408C3952E6A +:100F1E00F5F005F0E5318002C313D5F0FBFFE52CAB +:100F2E002E24C0F582E434E7F583EFF0EA600885FD +:100F3E0030188A820215E522E582FF2480F582E4CC +:100F4E0034E7F583E0F5328F05ED04FC3395E0FBD5 +:100F5E00EC2480F582EB34E7F583E0FC74022DFB84 +:100F6E003395E0FAEB2480F582EA34E7F583E0C4AA +:100F7E00540FF953010FEB2480F582EA34E7F58321 +:100F8E00E0FB740F5BF53374032DF83395E0FAE84C +:100F9E002480F582EA34E7F583E0FAED2404F83391 +:100FAE0095E0FDE82480F582ED34E7F583E0F53435 +:100FBE00E9600F8A188982C007C0041215B9D004DF +:100FCE00D00774F95590FA7900A8327B0018B8FF53 +:100FDE00011B89057E00C3ED98EE64808BF063F0F3 +:100FEE008095F05037EF292405FE3395E0FDEE2471 +:100FFE0080F582ED34E7F583E0FE7D00EE30E0050E +:10100E0043020880035302F78A90EEC313FE740462 +:10101E004AF5900DBD080040E30980ADEF29240587 +:10102E00FF3395E0FEEF2480F582EE34E7F583E0A2 +:10103E00F535AE337D00C3ED9C503FE53530E00510 +:10104E0043020880035302F78C017B0019B9FF019C +:10105E001B8D007F00E8B50111EFB5030DEE600AA0 +:10106E004302021EE534C313F5348A90E535C313EB +:10107E00F53574044AF5900D80BCEE600885341881 +:10108E008E820215B922E582F5362480F582E4348B +:10109E00E7F583E0F537E536FD04FC3395E0FBEC30 +:1010AE002480F582EB34E7F583E0FC74022DFB33EC +:1010BE0095E0FAEB2480F582EA34E7F583E0C45438 +:1010CE000FF953010FEB2480F582EA34E7F583E044 +:1010DE00FB740F5BF53874032DF83395E0FAE824B2 +:1010EE0080F582EA34E7F583E0FAED2404F83395CF +:1010FE00E0FDE82480F582ED34E7F583E0F539E98B +:10110E00600B8A188982C0041215E5D00474F95553 +:10111E0090FA7900A8377B0018B8FF011B89067F6B +:10112E0000C3EE98EF64808BF063F08095F0504E24 +:10113E00E536292405FF3395E0FEEF2480F582EE97 +:10114E0034E7F583E0FF7E00EF30E00543020880D0 +:10115E00035302F78A907B00C3EB952250030B805A +:10116E00F7EFC313FF74044AF5907B00C3EB95228F +:10117E0050030B80F70EBE080040CD098096E53671 +:10118E00292405F93395E0FFE92480F582EF34E751 +:10119E00F583E0F53AAE387B00C3EB9C5055E53A4B +:1011AE0030E00543020880035302F78C00790018E3 +:1011BE00B8FF01198B057F00EDB50011EFB5010DDC +:1011CE00EE600A4302021EE539C313F5398A907F99 +:1011DE0000C3EF952250030F80F7E53AC313F53A9B +:1011EE0074044AF5907F00C3EF952250030F80F7E9 +:1011FE000B80A6EE60088539188E820215E522AFA7 +:10120E0082053BE4B53B02053CEF2480F582E434D5 +:10121E00E7F583E0F53E8F05ED04FC3395E0FBEC3E +:10122E002480F582EB34E7F583E0F53F74022DFB65 +:10123E003395E0FAEB2480F582EA34E7F583E0C4D7 +:10124E00540FF953010FEB2480F582EA34E7F5834E +:10125E00E0FB740F5BF54074032DF83395E0FAE86C +:10126E002480F582EA34E7F583E0FAED2404F833BE +:10127E0095E0FDE82480F582ED34E7F583E0F54155 +:10128E00E9600B8A188982C0071215B9D00774F964 +:10129E005590FA7900A83E7B0018B8FF011B89050E +:1012AE007E00C3ED98EE64808BF063F08095F05075 +:1012BE004CEF292405FE3395E0FDEE2480F582EDFA +:1012CE0034E7F583E0FE7D007B00EE30E00543025F +:1012DE000880035302F78A90EEC313FE74044AF596 +:1012EE0090EDA29413FD0BBB080040DEE53D2924D2 +:1012FE00C0F582E434E7F583EDF00980988906EFB6 +:10130E00292405FF3395E0FDEF2480F582ED34E7C7 +:10131E00F583E0F542754300AB407900C3E9953F94 +:10132E005046E54230E00543020880035302F7A819 +:10133E003F7F0018B8FF011F89047D00ECB5001136 +:10134E00EDB5070DEB600A4302021BE541C313F531 +:10135E00418A90E542C313F54274044AF590E54381 +:10136E00A29413F5430980B47408C3953FF5F005B4 +:10137E00F0E5438002C313D5F0FBFFE53D2E24C0FC +:10138E00F582E434E7F583EFF0EB60088541188BC6 +:10139E00820215B922E582F5452480F582E434E710 +:1013AE00F583E0F546E545FD04FC3395E0FBEC24C2 +:1013BE0080F582EB34E7F583E0F54774022DFB33BD +:1013CE0095E0FAEB2480F582EA34E7F583E0C45425 +:1013DE000FF953010FEB2480F582EA34E7F583E031 +:1013EE00FB740F5BF54874032DF83395E0FAE8248F +:1013FE0080F582EA34E7F583E0FAED2404F83395BC +:10140E00E0FDE82480F582ED34E7F583E0F549E967 +:10141E0060078A1889821215E574F95590FA7900D9 +:10142E00A8467B0018B8FF011B89067F00C3EE9803 +:10143E00EF64808BF063F08095F05064E5452924CD +:10144E0005FF3395E0FEEF2480F582EE34E7F58359 +:10145E00E0FF7E007B00EF30E0054302088003537F +:10146E0002F78A907800C3E8952350030880F7EFBF +:10147E00C313FF74044AF5907800C3E89523500314 +:10148E000880F7EEA29413FE0BBB080040C8E5449B +:10149E002924C0F582E434E7F583EEF00902142E18 +:1014AE008907E545292405F93395E0FEE92480F501 +:1014BE0082EE34E7F583E0F54A754B00A9487800D3 +:1014CE00C3E89547505CE54A30E0054302088003C7 +:1014DE005302F7AD477E001DBDFF011E88037C0041 +:1014EE00EBB50511ECB5060DE9600A43020219E5EC +:1014FE0049C313F5498A907E00C3EE952350030E1F +:10150E0080F7E54AC313F54A74044AF5907E00C38A +:10151E00EE952350030E80F7E54BA29413F54B087E +:10152E00809E7408C39547F5F005F0E54B8002C325 +:10153E0013D5F0FBFEE5442F24C0F582E434E7F525 +:10154E0083EEF0E9600885491889820215E522AE1E +:10155E0082AF8374FB5590FD7B007C00C3EB9EEC49 +:10156E009F500E8D9074044DF5900BBB00EE0C80C9 +:10157E00EB22AE82AF8374FB5590FD7B007C00C3E3 +:10158E00EB9EEC9F50248D907A00C3EA9524500375 +:10159E000A80F774044DF5907A00C3EA952450033F +:1015AE000A80F70BBB00D80C80D522AF8274FB5596 +:1015BE0090FE7D00C3ED9F501DE51830E0054306FB +:1015CE000280035306FD8E90E518C313F5187404BC +:1015DE004EF5900D80DE22AF8274FB5590FE7D009D +:1015EE00C3ED9F5033E51830E005430602800353E8 +:1015FE0006FD8E907C00C3EC952550030C80F7E51C +:10160E0018C313F51874044EF5907C00C3EC9525A1 +:10161E0050030C80F70D80C8227F003094027F01AA +:10162E00742F5590FE8F05E4FFFCEE4FF582EC4DC6 +:10163E00F58322E582542FF45290742F5518429060 +:10164E0022858221851822851923851A24851B253A +:10165E0022AF827E00C3EE9F5004000E80F7220060 +:10166E00227E567F02EE24FFFCEF34FFFD8C068DAA +:10167E0007EC4D70F0227518057519001218A1AE01 +:10168E0082AF837C007D00C3EC9EED9F501AC00795 +:10169E00C006C005C00412166DD004D005D006D009 +:1016AE00070CBC00E20D80DF22AE82AF837C007D92 +:1016BE0000C3EC9EED9F501AC007C006C005C004C3 +:1016CE0012166FD004D005D006D0070CBC00E20D68 +:0316DE0080DF2288 +:03004300023E007A +:103E000002010800020158000201590002015A0093 +:103E100002015B0002015C0002015D0002015E0024 +:103E200002015F00020160000201610002017A00EC +:103E3000020193000201970002019800020199001B +:103E400002019A0002015E0002019B0002019C0037 +:103E500002019D0002019E0002019F000201A000DC +:103E60000201A10002015E0002015E0002015E008B +:103E70000201A2000201A3000201A4000201A500A8 +:103E80000201A6000201A7000201A8000201A90088 +:103E90000201AA000201AB000201AC000201AD0068 +:103EA0000201AE000201AF000201B0000201B10048 +:083EB0000201B2000201B3009F +:1016E100D310AF01C3C0D085821285831385F01456 +:1016F100F51590E600E05418C423541F70057A01D3 +:10170100FB801C90E600E05418C423541FF9B90172 +:10171100067802790080047804790088028903D26E +:10172100CDD2CC8A18751900751A00751B009071FD +:10173100B075F00BE4C00212192F85121885131928 +:1017410085141A85151B1218CAAC82AD83AEF0FF41 +:10175100D0020CBC00090DBD00050EBE00010FEF4B +:10176100C313EE13ED13FDEC13FC74FFC39CFC7467 +:10177100FF9DFD8DCBEA60067E017F0080047E0027 +:101781007F00EE2CF5CAD2CAC29FD29EC29DD29CC6 +:10179100438780D299D0D092AF223098FDAF99C2C1 +:1017A100987E008F828E8322AF8210990280FB8FF8 +:1017B1009922AF82BF0A0A75820DC0071217A9D0FC +:1017C100078F82C0071217A9D007BF0D0A75820AB9 +:1017D100C0071217A9D0077E008F828E832290E660 +:1017E1000174EEF090E6F574FFF0902440E49390DC +:1017F100E6F3F0902441E49390E6C3F0902442E4B0 +:101801009390E6C1F0902443E49390E6C2F09024D3 +:1018110045E49390E6C0F0902446E49390E6F4F01A +:1018210075AF077E9C7F238F9A759B9C759DE47590 +:101831009E007F0090E67BE090E67CF00FBF800089 +:1018410040F275820312165F90E6C4E4F0758203DC +:1018510012165F90E6C5E4F090241C9390E6C6F062 +:1018610090241DE49390E6C7F090241EE49390E643 +:10187100C8F090241FE49390E6C9F0902420E493EB +:1018810090E6CAF0902421E49390E6CBF0902422D4 +:10189100E49390E6CCF0902423E49390E6CDF022FB +:10239C00013F0101010101070207020202020200D2 +:1023AC000407070707070707000900000000003FA4 +:1023BC0088013F0101010107010205000000000036 +:1023CC000705070707070707090009000000003F7A +:1023DC0001010101010101070000000000000000E3 +:1023EC000707070707070707000000000000003F6A +:1023FC0001010101010101070000000000000000C3 +:10240C000707070707070707000000000000003F49 +:10241C0000000000000000000000000000000000B0 +:10242C0000000000000000000000000000000000A0 +:0B243C0000000000E0000007EEF200CE +:1018A1007A10E4FBFCE58225E0F582E58333F583DC +:1018B100EB33FBEC33FCEB9518F5F0EC9519400696 +:1018C100FCABF0438201DADD22FB7A20E4FCFDFE71 +:1018D100FFE5822582F582E58333F583E5F033F573 +:1018E100F0EB33FB4017DAE98042E5822582F5828D +:1018F100E58333F583E5F033F5F0EB33FBEC33FCB3 +:10190100ED33FDEE33FEEF33FFEC9518ED9519EE57 +:10191100951AEF951B4013EC9518FCED9519FDEE0A +:0E192100951AFEEF951BFF438201DABEEB2202 +:0600A000E478FFF6D8FD34 +:10007E007900E94400601B7A00902452780475A040 +:10008E003CE493F2A308B8000205A0D9F4DAF275A5 +:02009E00A0FFC1 +:10192F00AAF0FBE5828518F0A4FCADF0E5838518DD +:10193F00F0A42DFDE435F0FEE5828519F0A42DFD10 +:10194F00E5F03EFEE433FFEA8518F0A42EFEE5F045 +:10195F003FFFE5838519F0A42EFEE5F03FFFE582FA +:10196F00851AF0A42EFEE5F03FFFEB8518F0A42FAB +:10197F00FFEA8519F0A42FFFE583851AF0A42FFF46 +:0E198F00E582851BF0A42F8EF08D838C8222C2 +:1000A6007800E84400600A790075A03CE4F309D8BA +:1000B600FC7804E84400600C7901903C00E4F0A36D +:0400C600D8FCD9FA8F +:10199D00C0178581177E008E831217B3D01722854D +:1019AD00825C85835D85F05EE4F559F55AF55B85BE +:1019BD00165F90199D021A8BC017E581F51724FB50 +:1019CD00FF8F5FE4F559F55AF55BE51724FBF886B3 +:1019DD005C08865D08865E90199D121A8BD01722C1 +:1019ED00AF82C04FC050C0511219FA8007C04DC010 +:1019FD004E8F82221581158115810557E4B5570249 +:101A0D00055822AF8274302FFF24C6500B74072F58 +:101A1D00FFE54C60034307208F820219EDE582FF3D +:101A2D00C4540FF582C007121A10D007740F5FF55A +:101A3D0082021A10858218AB52AC53AD54AE55AA22 +:101A4D0056751A208A07EF2FF519EE235401451903 +:101A5D00FAEB2BFBEC33FCED33FDEE33FEC3EA95D5 +:101A6D00184008EAC39518FA430301E51A14FF8FCD +:101A7D001A70D18B528C538D548E558A5622858275 +:101A8D004D85834E85594F855A50855B51E4F557E9 +:101A9D00F558AD5CAE5DAF5E8D828E838FF01222F8 +:101AAD00A8FC74012DF55CE43EF55D8F5EECFF70D6 +:101ABD000302226CBF250280030222647E007D009A +:101ACD008E608E617A007B008E627C008E63E4F501 +:101ADD006BF56C7564FF7565FF855C6D855D6E8559 +:101AED005E6F856D82856E83856FF01222A8F5700D +:101AFD00A385826D85836E856D5C856E5D856F5E5C +:101B0D007425B570088570821219ED808574D02505 +:101B1D00704003021BCDE57024C65003021BCD742B +:101B2D00FFB56455B56552856B18856C1990000A23 +:101B3D00C006C005C004C003C00212228B8582718D +:101B4D00858372D002D003D004D005D00685707382 +:101B5D00757400E5732571F573E5743572F574E5EB +:101B6D007324D0F56BE57434FFF56CE56B456C6053 +:101B7D0003021AEF7D01021AEF856418856519902D +:101B8D00000AC006C005C004C003C00212228B8526 +:101B9D008273858374D002D003D004D005D006851E +:101BAD007071757200E5712573F573E5723574F515 +:101BBD0074E57324D0F564E57434FFF565021AEF0E +:101BCD00742EB5701574FFB56405B56502800302FA +:101BDD001AEFE4F564F565021AEF749F2570500E47 +:101BED00E570248540085370DF754C018003754CFA +:101BFD00007420B57003021C99742BB57003021C80 +:101C0D0093742DB5700280797442B57003021C9FD8 +:101C1D007443B57003021CAA7444B57003021EF719 +:101C2D007446B57003021F0D7448B57003021AEFA8 +:101C3D007449B57003021EF7744AB57003021AEFAA +:101C4D00744CB570028050744FB57003021EFE7453 +:101C5D0050B57003021E427453B5700280767454F1 +:101C6D00B57003021AEF7455B57003021F03745853 +:101C7D00B57003021F08745AB57003021AEF021FE4 +:101C8D00117E01021AEF756001021AEF75610102F2 +:101C9D001AEF7B01021AEF756201021AEFEB600A6F +:101CAD00E55F14F9895F8773800DE55F24FEF5719B +:101CBD0085715FA9718773857382C006C005C004E5 +:101CCD00C003C0021219EDD002D003D004D005D04C +:101CDD0006021F33E55F24FDF57385735FA97387D6 +:101CED006D09876E09876F1919856D52856E53853C +:101CFD006F54856D82856E83856FF0C006C005C0FB +:101D0D0004C003C002122273858273858374D002CE +:101D1D00D003D004D005D00674FFB56409B56506AF +:101D2D00857364857465EE704FC3E573956BE574CB +:101D3D00956C5044E56BC39573F571E56C9574F531 +:101D4D007285716D85726E157174FFB571021572A4 +:101D5D00E56D456E601C758220C006C005C004C0CF +:101D6D0003C0021219EDD002D003D004D005D00665 +:101D7D0080CF85716B85726C8564718565728552B6 +:101D8D00828553838554F01222A8F56D856D6860A8 +:101D9D004FC3E4957174808572F063F08095F050B7 +:101DAD003F157174FFB571021572856882C006C04A +:101DBD0005C004C003C0021219EDD002D003D00437 +:101DCD00D005D00685526D85536E85546F056DE433 +:101DDD00B56D02056E856D52856E53856F54809E6F +:101DED00EE7003021F33C3E573956BE574956C407C +:101DFD0003021F33E56BC39573F573E56C9574F5AD +:101E0D0074857371857472157374FFB573021574CF +:101E1D00E57145727003021F2D758220C006C00545 +:101E2D00C004C003C0021219EDD002D003D004D0FB +:101E3D0005D00680CCE55F24FDF57185715FA97134 +:101E4D00876D09876E09876F1919856D52856E53D8 +:101E5D00856F54855469748025695005757143806B +:101E6D001974A025695005757150800E74C02569CF +:101E7D0050057571498003757158857182C006C012 +:101E8D0005C004C003C0021219ED75823A1219ED96 +:101E9D007582301219ED7582781219EDD002D003CA +:101EAD00D004D005D0067449B5710280217450B5A7 +:101EBD007102801A855382C006C005C004C003C0DC +:101ECD0002121A2AD002D003D004D005D0068552B2 +:101EDD0082C006C005C004C003C002121A2AD00277 +:101EED00D003D004D005D006803C7A0175630A80FA +:101EFD0035756308803075630A802B7563108026F5 +:101F0D007C018022857082C006C005C004C003C05C +:101F1D00021219EDD002D003D004D005D0068006F0 +:101F2D0085736B85746CEC6068E55F24FCFC8C5FDD +:101F3D008C018775098776098777098778191919AB +:101F4D0085755285765385775485785575524775C5 +:101F5D005324755480855275855376855477740155 +:101F6D002575F56DE43576F56E85776F856D528542 +:101F7D006E53856F548575828576838577F0122231 +:101F8D00A8FC8C757003021A9F8575821219ED805D +:101F9D00C4E5637003021A9FEB603FE55F14F98996 +:101FAD005F87048C7575760075770075780085757B +:101FBD0052857653857754857855EA600302205013 +:101FCD008552757576007577007578008575528523 +:101FDD0076538577548578558069E5626025E55F90 +:101FED0024FCFC8C5F8C018775098776098777093E +:101FFD0087781919198575528576538577548578A3 +:10200D00558040E55F24FEFC8C5F8C0187030987BA +:10201D0004198B75ECF5763395E0F577F5788575C4 +:10202D0052857653857754857855EA7016855275A5 +:10203D00855376F577F57885755285765385775482 +:10204D00857855EA602AE55530E723C3E49552F5C6 +:10205D0075E49553F576E49554F577E49555F57853 +:10206D0085755285765385775485785580027A002B +:10207D007C01797EE4F575F576755600856382C031 +:10208D0006C005C004C002C001121A41D001D00221 +:10209D00D004D005D006EC700DE556C4F573E7FB02 +:1020AD004573F7198002A7560575E4B575020576D7 +:1020BD00ECB40100E433FCE55245534554455570ED +:1020CD00B8896A857566857667E56B456C700575AB +:1020DD006B01F56CED7043EE7040856B75856C761C +:1020ED00AB660B8B73757400C3E5739575E57495CD +:1020FD00765021758220C006C005C004C002121999 +:10210D00EDD002D004D005D006157574FFB575025B +:10211D00157680CC85756B85766CEA601D75822D84 +:10212D00C006C005C0041219EDD004D005D00615A7 +:10213D006B74FFB56B02156C8046E56645676040B4 +:10214D00E560601D75822BC006C005C0041219ED37 +:10215D00D004D005D006156B74FFB56B02156C80DD +:10216D001FE561601B758220C006C005C0041219F1 +:10217D00EDD004D005D006156B74FFB56B02156C50 +:10218D00EE703C856B75856C76AA75AB761575749E +:10219D00FFB575021576C3E5669AE5679B5041ED6F +:1021AD0060067A307B0080047A207B008A82C0062C +:1021BD00C005C0041219EDD004D005D00680CAC3E5 +:1021CD00E566956BE567956C500FE56BC39566F508 +:1021DD0073E56C9567F574800DE4F573F574800601 +:1021ED00857573857674A96A856675856776AA7512 +:1021FD00AD76157574FFB575021576EA4D602EEC4A +:10220D00B40100E433FC700A09E7C4540FFD8D5688 +:10221D0080078705740F5DF556855682C006C0048C +:10222D00C001121A10D001D004D00680C1EE700387 +:10223D00021A9FAD73AE748D038E041DBDFF011E7A +:10224D00EB4C7003021A9F758220C006C00512194F +:10225D00EDD005D00680E08F821219ED021A9F8510 +:06226D0057828558832210 +:0B2447003C4E4F20464C4F41543E00DD +:10227300AA82AB831222A86003A380F8C3E5829AE3 +:10228300F582E5839BF58322E5828518F0A4C58258 +:10229300C0F08519F0A4D0F025F0C5838518F0A40B +:0522A3002583F58322F4 +:0D00710075817E1222C4E582600302006EDC +:1022A80020F71430F6148883A88220F507E6A8835F +:1022B80075830022E280F7E49322E02275820022EF +:00000001FF diff --git a/src/jtag/drivers/ANGIE/include/msgtypes.h b/src/jtag/drivers/ANGIE/include/msgtypes.h new file mode 100644 index 0000000000..fb045e98c3 --- /dev/null +++ b/src/jtag/drivers/ANGIE/include/msgtypes.h @@ -0,0 +1,172 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + +**************************************************************************** + File : msgtypes.h * + Contents : Definition of the commands supported by NanoXplore * + USB-JTAG ANGIE adapter hardware. * + Based on openULINK project code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + <aboudjel...@nanoxplore.com> * + <ahmederrachedb...@gmail.com> * +*****************************************************************************/ + +/** + * @file + * Definition of the commands supported by the ANGIE firmware. + * + * Basically, two types of commands can be distinguished: + * - Commands with fixed payload size + * - Commands with variable payload size + * + * SCAN commands (in all variations) carry payloads of variable size, all + * other commands carry payloads of fixed size. + * + * In the case of SCAN commands, the payload size (n) is calculated by + * dividing the scan_size_bits variable by 8, rounding up the result. + * + * Offset zero always contains the command ID. + * + **************************************************************************** + * CMD_SCAN_IN, CMD_SLOW_SCAN_IN: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_SCAN_OUT, CMD_SLOW_SCAN_OUT: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + **************************************************************************** + * CMD_SCAN_IO, CMD_SLOW_SCAN_IO: * + * * + * OUT: * + * offset 1: scan_size_bytes * + * offset 2: bits_last_byte * + * offset 3: tms_count_start + tms_count_end * + * offset 4: tms_sequence_start * + * offset 5: tms_sequence_end * + * offset 6..x: TDI data * + * * + * IN: * + * offset 0..n: TDO data * + **************************************************************************** + * CMD_CLOCK_TMS, CMD_SLOW_CLOCK_TMS: * + * * + * OUT: * + * offset 1: tms_count * + * offset 2: tms_sequence * + **************************************************************************** + * CMD_CLOCK_TCK, CMD_SLOW_CLOCK_TCK: * + * * + * OUT: * + * offset 1: low byte of tck_count * + * offset 2: high byte of tck_count * + **************************************************************************** + * CMD_CLOCK_SLEEP_US: * + * * + * OUT: * + * offset 1: low byte of sleep_us * + * offset 2: high byte of sleep_us * + **************************************************************************** + * CMD_CLOCK_SLEEP_MS: * + * * + * OUT: * + * offset 1: low byte of sleep_ms * + * offset 2: high byte of sleep_ms * + **************************************************************************** + * CMD_GET_SIGNALS: * + * * + * IN: * + * offset 0: current state of input signals * + * offset 1: current state of output signals * + **************************************************************************** + * CMD_SET_SIGNALS: * + * * + * OUT: * + * offset 1: signals that should be de-asserted * + * offset 2: signals that should be asserted * + **************************************************************************** + * CMD_CONFIGURE_TCK_FREQ: * + * * + * OUT: * + * offset 1: delay value for scan_in function * + * offset 2: delay value for scan_out function * + * offset 3: delay value for scan_io function * + * offset 4: delay value for clock_tck function * + * offset 5: delay value for clock_tms function * + **************************************************************************** + * CMD_SET_LEDS: * + * * + * OUT: * + * offset 1: LED states: * + * Bit 0: turn COM LED on * + * Bit 1: turn RUN LED on * + * Bit 2: turn COM LED off * + * Bit 3: turn RUN LED off * + * Bits 7..4: Reserved * + **************************************************************************** + * CMD_TEST: * + * * + * OUT: * + * offset 1: unused dummy value * + **************************************************************************** + */ + +#ifndef __MSGTYPES_H +#define __MSGTYPES_H + +/* + * Command IDs: + * + * Bits 7..6: Reserved, should always be zero + * Bits 5..0: Command ID. There are 62 usable IDs. Of this 63 available IDs, + * the IDs 0x00..0x1F are commands with variable payload size, + * the IDs 0x20..0x3F are commands with fixed payload size. + */ + +#define CMD_ID_MASK 0x3F + +/* Commands with variable payload size */ +#define CMD_SCAN_IN 0x00 +#define CMD_SLOW_SCAN_IN 0x01 +#define CMD_SCAN_OUT 0x02 +#define CMD_SLOW_SCAN_OUT 0x03 +#define CMD_SCAN_IO 0x04 +#define CMD_SLOW_SCAN_IO 0x05 + +/* Commands with fixed payload size */ +#define CMD_CLOCK_TMS 0x20 +#define CMD_SLOW_CLOCK_TMS 0x21 +#define CMD_CLOCK_TCK 0x22 +#define CMD_SLOW_CLOCK_TCK 0x23 +#define CMD_SLEEP_US 0x24 +#define CMD_SLEEP_MS 0x25 +#define CMD_GET_SIGNALS 0x26 +#define CMD_SET_SIGNALS 0x27 +#define CMD_CONFIGURE_TCK_FREQ 0x28 +#define CMD_SET_LEDS 0x29 +#define CMD_TEST 0x2A + +/* JTAG signal definition for jtag_get_signals() -- Input signals! */ +#define SIGNAL_TDO 1 + +/* JTAG signal definition for jtag_get_signals() -- Output signals! */ +#define SIGNAL_TDI 8 +#define SIGNAL_TMS 2 +#define SIGNAL_TCK 4 +#define SIGNAL_TRST 1 +#define SIGNAL_SRST 32 + +#endif diff --git a/src/jtag/drivers/Makefile.am b/src/jtag/drivers/Makefile.am index 6410f37545..91a6ea6d81 100644 --- a/src/jtag/drivers/Makefile.am +++ b/src/jtag/drivers/Makefile.am @@ -10,8 +10,10 @@ noinst_LTLIBRARIES += %D%/libocdjtagdrivers.la %C%_libocdjtagdrivers_la_CPPFLAGS = $(AM_CPPFLAGS) ULINK_FIRMWARE = %D%/OpenULINK +ANGIE_FILES = %D%/ANGIE EXTRA_DIST += $(ULINK_FIRMWARE) \ + $(ANGIE_FILES) \ %D%/usb_blaster/README.CheapClone \ %D%/Makefile.rlink \ %D%/rlink_call.m4 \ @@ -123,6 +125,12 @@ ulinkdir = $(pkgdatadir)/OpenULINK dist_ulink_DATA = $(ULINK_FIRMWARE)/ulink_firmware.hex %C%_libocdjtagdrivers_la_LIBADD += -lm endif +if ANGIE +DRIVERFILES += %D%/angie.c +angiedir = $(pkgdatadir)/ANGIE +dist_angie_DATA = $(ANGIE_FILES)/angie_firmware.hex $(ANGIE_FILES)/angie_bitstream.bit +%C%_libocdjtagdrivers_la_LIBADD += -lm +endif if VSLLINK DRIVERFILES += %D%/versaloon/usbtoxxx/usbtogpio.c DRIVERFILES += %D%/versaloon/usbtoxxx/usbtojtagraw.c diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c new file mode 100644 index 0000000000..24654c5691 --- /dev/null +++ b/src/jtag/drivers/angie.c @@ -0,0 +1,2342 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/*************************************************************************** + File : angie.c * + Contents : OpenOCD driver code for NanoXplore USB-JTAG ANGIE * + adapter hardware. * + Based on openULINK driver code by: Martin Schmoelzer. * + Copyright 2023, Ahmed Errached BOUDJELIDA, NanoXplore SAS. * + <aboudjel...@nanoxplore.com> * + <ahmederrachedb...@gmail.com> * + ***************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include "helper/system.h" +#include <jtag/interface.h> +#include <jtag/commands.h> +#include <target/image.h> +#include <libusb.h> +#include "libusb_helper.h" +#include "ANGIE/include/msgtypes.h" + +/** USB Vendor ID of ANGIE device in unconfigured state (no firmware loaded + * yet) or with its firmware. */ +#define ANGIE_VID 0x584e + +/** USB Product ID of ANGIE device in unconfigured state (no firmware loaded + * yet) or with its firmware. */ +#define ANGIE_PID 0x424e + +/** Address of EZ-USB ANGIE CPU Control & Status register. This register can be + * written by issuing a Control EP0 vendor request. */ +#define CPUCS_REG 0xE600 + +/** USB Control EP0 bRequest: "Firmware Load". */ +#define REQUEST_FIRMWARE_LOAD 0xA0 + +/** Value to write into CPUCS to put EZ-USB ANGIE into reset. */ +#define CPU_RESET 0x01 + +/** Value to write into CPUCS to put EZ-USB ANGIE out of reset. */ +#define CPU_START 0x00 + +/** Base address of firmware in EZ-USB ANGIE code space. */ +#define FIRMWARE_ADDR 0x0000 + +/** USB interface number */ +#define USB_INTERFACE 0 + +/** Delay (in microseconds) to wait while EZ-USB performs ReNumeration. */ +#define ANGIE_RENUMERATION_DELAY 1500000 + +/** Default location of ANGIE firmware image. */ +#define ANGIE_FIRMWARE_FILE PKGDATADIR "/ANGIE/angie_firmware.hex" + +/** Default location of ANGIE firmware image. */ +#define ANGIE_BITSTREAM_FILE PKGDATADIR "/ANGIE/angie_bitstream.bit" + +/** Maximum size of a single firmware section. Entire EZ-USB ANGIE code space = 16kB */ +#define SECTION_BUFFERSIZE 16384 + +/** Tuning of OpenOCD SCAN commands split into multiple ANGIE commands. */ +#define SPLIT_SCAN_THRESHOLD 10 + +/** ANGIE hardware type */ +enum angie_type { + ANGIE, +}; + +enum angie_payload_direction { + PAYLOAD_DIRECTION_OUT, + PAYLOAD_DIRECTION_IN +}; + +enum angie_delay_type { + DELAY_CLOCK_TCK, + DELAY_CLOCK_TMS, + DELAY_SCAN_IN, + DELAY_SCAN_OUT, + DELAY_SCAN_IO +}; + +/** + * ANGIE command (ANGIE command queue element). + * + * For the OUT direction payload, things are quite easy: Payload is stored + * in a rather small array (up to 63 bytes), the payload is always allocated + * by the function generating the command and freed by angie_clear_queue(). + * + * For the IN direction payload, things get a little bit more complicated: + * The maximum IN payload size for a single command is 64 bytes. Assume that + * a single OpenOCD command needs to scan 256 bytes. This results in the + * generation of four ANGIE commands. The function generating these + * commands shall allocate an uint8_t[256] array. Each command's #payload_in + * pointer shall point to the corresponding offset where IN data shall be + * placed, while #payload_in_start shall point to the first element of the 256 + * byte array. + * - first command: #payload_in_start + 0 + * - second command: #payload_in_start + 64 + * - third command: #payload_in_start + 128 + * - fourth command: #payload_in_start + 192 + * + * The last command sets #needs_postprocessing to true. + */ +struct angie_cmd { + uint8_t id; /**< ANGIE command ID */ + + uint8_t *payload_out; /**< Pointer where OUT payload shall be stored */ + uint8_t payload_out_size; /**< OUT direction payload size for this command */ + + uint8_t *payload_in_start; /**< Pointer to first element of IN payload array */ + uint8_t *payload_in; /**< Pointer where IN payload shall be stored */ + uint8_t payload_in_size; /**< IN direction payload size for this command */ + + /** Indicates if this command needs post-processing */ + bool needs_postprocessing; + + /** Indicates if angie_clear_queue() should free payload_in_start */ + bool free_payload_in_start; + + /** Pointer to corresponding OpenOCD command for post-processing */ + struct jtag_command *cmd_origin; + + struct angie_cmd *next; /**< Pointer to next command (linked list) */ +}; + +/** Describes one driver instance */ +struct angie { + struct libusb_context *libusb_ctx; + struct libusb_device_handle *usb_device_handle; + enum angie_type type; + + unsigned int ep_in; /**< IN endpoint number */ + unsigned int ep_out; /**< OUT endpoint number */ + + int delay_scan_in; /**< Delay value for SCAN_IN commands */ + int delay_scan_out; /**< Delay value for SCAN_OUT commands */ + int delay_scan_io; /**< Delay value for SCAN_IO commands */ + int delay_clock_tck; /**< Delay value for CLOCK_TMS commands */ + int delay_clock_tms; /**< Delay value for CLOCK_TCK commands */ + + int commands_in_queue; /**< Number of commands in queue */ + struct angie_cmd *queue_start; /**< Pointer to first command in queue */ + struct angie_cmd *queue_end; /**< Pointer to last command in queue */ +}; + +/**************************** Function Prototypes *****************************/ + +/* USB helper functions */ +static int angie_usb_open(struct angie **device); +static int angie_usb_close(struct angie **device); + +/* ANGIE MCU (Cypress EZ-USB) specific functions */ +static int angie_cpu_reset(struct angie *device, char reset_bit); +static int angie_load_firmware_and_renumerate(struct angie **device, const char *filename, + uint32_t delay); +static int angie_load_firmware(struct angie *device, const char *filename); +static int angie_load_bitstream(struct angie *device, const char *filename); + +static int angie_write_firmware_section(struct angie *device, + struct image *firmware_image, int section_index); + +/* Generic helper functions */ +static void angie_print_signal_states(uint8_t input_signals, uint8_t output_signals); + +/* ANGIE command generation helper functions */ +static int angie_allocate_payload(struct angie_cmd *angie_cmd, int size, + enum angie_payload_direction direction); + +/* ANGIE command queue helper functions */ +static int angie_get_queue_size(struct angie *device, + enum angie_payload_direction direction); +static void angie_clear_queue(struct angie *device); +static int angie_append_queue(struct angie *device, struct angie_cmd *angie_cmd); +static int angie_execute_queued_commands(struct angie *device, int timeout); + +static void angie_print_queue(struct angie *device); + +static int angie_append_scan_cmd(struct angie *device, + enum scan_type scan_type, + int scan_size_bits, + uint8_t *tdi, + uint8_t *tdo_start, + uint8_t *tdo, + uint8_t tms_count_start, + uint8_t tms_sequence_start, + uint8_t tms_count_end, + uint8_t tms_sequence_end, + struct jtag_command *origin, + bool postprocess); +static int angie_append_clock_tms_cmd(struct angie *device, uint8_t count, + uint8_t sequence); +static int angie_append_clock_tck_cmd(struct angie *device, uint16_t count); +static int angie_append_get_signals_cmd(struct angie *device); +static int angie_append_set_signals_cmd(struct angie *device, uint8_t low, + uint8_t high); +static int angie_append_sleep_cmd(struct angie *device, uint32_t us); +static int angie_append_configure_tck_cmd(struct angie *device, + int delay_scan_in, + int delay_scan_out, + int delay_scan_io, + int delay_tck, + int delay_tms); +static int angie_append_test_cmd(struct angie *device); + +/* ANGIE TCK frequency helper functions */ +static int angie_calculate_delay(enum angie_delay_type type, long f, int *delay); + +/* Interface between ANGIE and OpenOCD */ +static void angie_set_end_state(tap_state_t endstate); +static int angie_queue_statemove(struct angie *device); + +static int angie_queue_scan(struct angie *device, struct jtag_command *cmd); +static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd); +static int angie_queue_runtest(struct angie *device, struct jtag_command *cmd); +static int angie_queue_reset(struct angie *device, struct jtag_command *cmd); +static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd); +static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd); +static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd); + +static int angie_post_process_scan(struct angie_cmd *angie_cmd); +static int angie_post_process_queue(struct angie *device); + +/* adapter driver functions */ +static int angie_execute_queue(void); +static int angie_khz(int khz, int *jtag_speed); +static int angie_speed(int speed); +static int angie_speed_div(int speed, int *khz); +static int angie_init(void); +static int angie_quit(void); + +/****************************** Global Variables ******************************/ + +static struct angie *angie_handle; + +/**************************** USB helper functions ****************************/ + +/** + * Opens the ANGIE device + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_usb_open(struct angie **device) +{ + ssize_t num_devices, i; + bool found; + struct libusb_device **usb_devices; + struct libusb_device_descriptor usb_desc; + struct libusb_device_handle *usb_device_handle; + + num_devices = libusb_get_device_list((*device)->libusb_ctx, &usb_devices); + + if (num_devices <= 0) + return ERROR_FAIL; + + found = false; + for (i = 0; i < num_devices; i++) { + if (libusb_get_device_descriptor(usb_devices[i], &usb_desc) != 0) { + continue; + } else if (usb_desc.idVendor == ANGIE_VID && usb_desc.idProduct == ANGIE_PID) { + found = true; + break; + } + } + + if (!found) + return ERROR_FAIL; + + if (libusb_open(usb_devices[i], &usb_device_handle) != 0) + return ERROR_FAIL; + libusb_free_device_list(usb_devices, 1); + + (*device)->usb_device_handle = usb_device_handle; + (*device)->type = ANGIE; + + return ERROR_OK; +} + +/** + * Releases the ANGIE interface and closes the USB device handle. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_usb_close(struct angie **device) +{ + if (libusb_release_interface((*device)->usb_device_handle, 0) != 0) + return ERROR_FAIL; + + libusb_close((*device)->usb_device_handle); + + (*device)->usb_device_handle = NULL; + + return ERROR_OK; +} + +/******************* ANGIE CPU (EZ-USB) specific functions ********************/ + +/** + * Writes '0' or '1' to the CPUCS register, putting the EZ-USB CPU into reset + * or out of reset. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param reset_bit 0 to put CPU into reset, 1 to put CPU out of reset. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_cpu_reset(struct angie *device, char reset_bit) +{ + int ret; + + ret = jtag_libusb_control_transfer(device->usb_device_handle, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), + REQUEST_FIRMWARE_LOAD, CPUCS_REG, 0, &reset_bit, 1, LIBUSB_TIMEOUT_MS); + + /* usb_control_msg() returns the number of bytes transferred during the + * DATA stage of the control transfer - must be exactly 1 in this case! */ + if (ret != 1) + return ERROR_FAIL; + return ERROR_OK; +} + +/** + * Puts the ANGIE's EZ-USB microcontroller into reset state, downloads + * the firmware image, resumes the microcontroller and re-enumerates + * USB devices. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * The usb_handle member will be modified during re-enumeration. + * @param filename path to the Intel HEX file containing the firmware image. + * @param delay the delay to wait for the device to re-enumerate. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_load_firmware_and_renumerate(struct angie **device, + const char *filename, uint32_t delay) +{ + int ret; + + /* Basic process: After downloading the firmware, the ANGIE will disconnect + * itself and re-connect after a short amount of time so we have to close + * the handle and re-enumerate USB devices */ + + ret = angie_load_firmware(*device, filename); + if (ret != ERROR_OK) + return ret; + + ret = angie_usb_close(device); + if (ret != ERROR_OK) + return ret; + + usleep(delay); + + ret = angie_usb_open(device); + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +/** + * Downloads a firmware image to the ANGIE's EZ-USB microcontroller + * over the USB bus. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param filename an absolute or relative path to the Intel HEX file + * containing the firmware image. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_load_firmware(struct angie *device, const char *filename) +{ + struct image angie_firmware_image; + int ret; + + ret = angie_cpu_reset(device, CPU_RESET); + if (ret != ERROR_OK) { + LOG_ERROR("Could not halt ANGIE CPU"); + return ret; + } + + angie_firmware_image.base_address = 0; + angie_firmware_image.base_address_set = false; + + ret = image_open(&angie_firmware_image, filename, "ihex"); + if (ret != ERROR_OK) { + LOG_ERROR("Could not load firmware image"); + return ret; + } + + /* Download all sections in the image to ANGIE */ + for (unsigned int i = 0; i < angie_firmware_image.num_sections; i++) { + ret = angie_write_firmware_section(device, &angie_firmware_image, i); + if (ret != ERROR_OK) + return ret; + } + + image_close(&angie_firmware_image); + + ret = angie_cpu_reset(device, CPU_START); + if (ret != ERROR_OK) { + LOG_ERROR("Could not restart ANGIE CPU"); + return ret; + } + + return ERROR_OK; +} + +/** + * Downloads a bitstream file to the ANGIE's FPGA through the EZ-USB microcontroller + * over the USB bus. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param filename an absolute or relative path to the Xilinx .bit file + * containing the bitstream data. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_load_bitstream(struct angie *device, const char *filename) +{ + int ret; + const char *bitstream_file_path = filename; + FILE *bitstream_file = NULL; + char *bitstream_data = NULL; + size_t bitstream_size = 0; + + /* CFGopen */ + ret = jtag_libusb_control_transfer(device->usb_device_handle, + 0x00, 0xB0, 0, 0, 0, 0, LIBUSB_TIMEOUT_MS); + if (ret != ERROR_OK) { + LOG_ERROR("Failed opencfg"); + /* Abort if libusb sent less data than requested */ + return ERROR_FAIL; + } + + /* Open the bitstream file */ + bitstream_file = fopen(bitstream_file_path, "rb"); + if (!bitstream_file) { + LOG_ERROR("Failed to open bitstream file: %s\n", bitstream_file_path); + return ERROR_FAIL; + } + + /* Get the size of the bitstream file */ + fseek(bitstream_file, 0, SEEK_END); + bitstream_size = ftell(bitstream_file); + fseek(bitstream_file, 0, SEEK_SET); + + /* Allocate memory for the bitstream data */ + bitstream_data = (char *)malloc(bitstream_size); + if (!bitstream_data) { + LOG_ERROR("Failed to allocate memory for bitstream data."); + fclose(bitstream_file); + return ERROR_FAIL; + } + + /* Read the bitstream data from the file */ + if (fread(bitstream_data, 1, bitstream_size, bitstream_file) != bitstream_size) { + LOG_ERROR("Failed to read bitstream data."); + free(bitstream_data); + fclose(bitstream_file); + return ERROR_FAIL; + } + + /* Send the bitstream data to the microcontroller */ + int actual_length = 0; + ret = jtag_libusb_bulk_write(device->usb_device_handle, 0x02, bitstream_data, bitstream_size, 1000, &actual_length); + if (ret != LIBUSB_SUCCESS) { + LOG_ERROR("Failed to send bitstream data: %s", libusb_strerror(ret)); + free(bitstream_data); + fclose(bitstream_file); + return ERROR_FAIL; + actual_length = 0; + } else { + LOG_INFO("Bitstream sent successfully."); + } + + /* Clean up */ + free(bitstream_data); + fclose(bitstream_file); + + /* CFGopen */ + ret = jtag_libusb_control_transfer(device->usb_device_handle, + 0x00, 0xB1, 0, 0, 0, 0, LIBUSB_TIMEOUT_MS); + if (ret != ERROR_OK) { + LOG_INFO("error cfgclose"); + /* Abort if libusb sent less data than requested */ + return ERROR_FAIL; + } + + return ERROR_OK; +} + +/** + * Send one contiguous firmware section to the ANGIE's EZ-USB microcontroller + * over the USB bus. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param firmware_image pointer to the firmware image that contains the section + * which should be sent to the ANGIE's EZ-USB microcontroller. + * @param section_index index of the section within the firmware image. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_write_firmware_section(struct angie *device, + struct image *firmware_image, int section_index) +{ + uint16_t addr, size, bytes_remaining, chunk_size; + uint8_t data[SECTION_BUFFERSIZE]; + uint8_t *data_ptr = data; + size_t size_read; + int ret; + + size = (uint16_t)firmware_image->sections[section_index].size; + addr = (uint16_t)firmware_image->sections[section_index].base_address; + + LOG_DEBUG("section %02i at addr 0x%04x (size 0x%04x)", section_index, addr, + size); + + /* Copy section contents to local buffer */ + ret = image_read_section(firmware_image, section_index, 0, size, data, + &size_read); + + if (ret != ERROR_OK || size_read != size) { + /* Propagating the return code would return '0' (misleadingly indicating + * successful execution of the function) if only the size check fails. */ + return ERROR_FAIL; + } + + bytes_remaining = size; + + /* Send section data in chunks of up to 64 bytes to ANGIE */ + while (bytes_remaining > 0) { + if (bytes_remaining > 64) + chunk_size = 64; + else + chunk_size = bytes_remaining; + + ret = jtag_libusb_control_transfer(device->usb_device_handle, + (LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE), + REQUEST_FIRMWARE_LOAD, addr, FIRMWARE_ADDR, (char *)data_ptr, + chunk_size, LIBUSB_TIMEOUT_MS); + + if (ret != (int)chunk_size) { + /* Abort if libusb sent less data than requested */ + return ERROR_FAIL; + } + + bytes_remaining -= chunk_size; + addr += chunk_size; + data_ptr += chunk_size; + } + + return ERROR_OK; +} + +/************************** Generic helper functions **************************/ + +/** + * Print state of interesting signals via LOG_INFO(). + * + * @param input_signals input signal states as returned by CMD_GET_SIGNALS + * @param output_signals output signal states as returned by CMD_GET_SIGNALS + */ +static void angie_print_signal_states(uint8_t input_signals, uint8_t output_signals) +{ + LOG_INFO("ANGIE signal states: TDI: %i, TDO: %i, TMS: %i, TCK: %i, TRST: %i " + "SRST: %i", + (output_signals & SIGNAL_TDI ? 1 : 0), + (input_signals & SIGNAL_TDO ? 1 : 0), + (output_signals & SIGNAL_TMS ? 1 : 0), + (output_signals & SIGNAL_TCK ? 1 : 0), + (output_signals & SIGNAL_TRST ? 1 : 0), + (output_signals & SIGNAL_SRST ? 1 : 0)); +} + +/**************** ANGIE command generation helper functions ***************/ + +/** + * Allocate and initialize space in memory for ANGIE command payload. + * + * @param angie_cmd pointer to command whose payload should be allocated. + * @param size the amount of memory to allocate (bytes). + * @param direction which payload to allocate. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_allocate_payload(struct angie_cmd *angie_cmd, int size, + enum angie_payload_direction direction) +{ + uint8_t *payload; + + payload = calloc(size, sizeof(uint8_t)); + + if (!payload) { + LOG_ERROR("Could not allocate ANGIE command payload: out of memory"); + return ERROR_FAIL; + } + + switch (direction) { + case PAYLOAD_DIRECTION_OUT: + if (angie_cmd->payload_out) { + LOG_ERROR("BUG: Duplicate payload allocation for ANGIE command"); + free(payload); + return ERROR_FAIL; + } else { + angie_cmd->payload_out = payload; + angie_cmd->payload_out_size = size; + } + break; + case PAYLOAD_DIRECTION_IN: + if (angie_cmd->payload_in_start) { + LOG_ERROR("BUG: Duplicate payload allocation for ANGIE command"); + free(payload); + return ERROR_FAIL; + } else { + angie_cmd->payload_in_start = payload; + angie_cmd->payload_in = payload; + angie_cmd->payload_in_size = size; + + /* By default, free payload_in_start in angie_clear_queue(). Commands + * that do not want this behavior (e. g. split scans) must turn it off + * separately! */ + angie_cmd->free_payload_in_start = true; + } + break; + } + + return ERROR_OK; +} + +/****************** ANGIE command queue helper functions ******************/ + +/** + * Get the current number of bytes in the queue, including command IDs. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param direction the transfer direction for which to get byte count. + * @return the number of bytes currently stored in the queue for the specified + * direction. + */ +static int angie_get_queue_size(struct angie *device, + enum angie_payload_direction direction) +{ + struct angie_cmd *current = device->queue_start; + int sum = 0; + + while (current) { + switch (direction) { + case PAYLOAD_DIRECTION_OUT: + sum += current->payload_out_size + 1; /* + 1 byte for Command ID */ + break; + case PAYLOAD_DIRECTION_IN: + sum += current->payload_in_size; + break; + } + + current = current->next; + } + + return sum; +} + +/** + * Clear the ANGIE command queue. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + */ +static void angie_clear_queue(struct angie *device) +{ + struct angie_cmd *current = device->queue_start; + struct angie_cmd *next = NULL; + + while (current) { + /* Save pointer to next element */ + next = current->next; + + /* Free payloads: OUT payload can be freed immediately */ + free(current->payload_out); + current->payload_out = NULL; + + /* IN payload MUST be freed ONLY if no other commands use the + * payload_in_start buffer */ + if (current->free_payload_in_start) { + free(current->payload_in_start); + current->payload_in_start = NULL; + current->payload_in = NULL; + } + + /* Free queue element */ + free(current); + + /* Proceed with next element */ + current = next; + } + + device->commands_in_queue = 0; + device->queue_start = NULL; + device->queue_end = NULL; +} + +/** + * Add a command to the ANGIE command queue. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param angie_cmd pointer to command that shall be appended to the ANGIE + * command queue. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_queue(struct angie *device, struct angie_cmd *angie_cmd) +{ + int newsize_out, newsize_in; + int ret = ERROR_OK; + + newsize_out = angie_get_queue_size(device, PAYLOAD_DIRECTION_OUT) + 1 + + angie_cmd->payload_out_size; + + newsize_in = angie_get_queue_size(device, PAYLOAD_DIRECTION_IN) + + angie_cmd->payload_in_size; + + /* Check if the current command can be appended to the queue */ + if (newsize_out > 64 || newsize_in > 64) { + /* New command does not fit. Execute all commands in queue before starting + * new queue with the current command as first entry. */ + ret = angie_execute_queued_commands(device, LIBUSB_TIMEOUT_MS); + + if (ret == ERROR_OK) + ret = angie_post_process_queue(device); + + if (ret == ERROR_OK) + angie_clear_queue(device); + } + + if (!device->queue_start) { + /* Queue was empty */ + device->commands_in_queue = 1; + + device->queue_start = angie_cmd; + device->queue_end = angie_cmd; + } else { + /* There are already commands in the queue */ + device->commands_in_queue++; + + device->queue_end->next = angie_cmd; + device->queue_end = angie_cmd; + } + + if (ret != ERROR_OK) + angie_clear_queue(device); + + return ret; +} + +/** + * Sends all queued ANGIE commands to the ANGIE for execution. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param timeout + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_execute_queued_commands(struct angie *device, int timeout) +{ + struct angie_cmd *current; + int ret, i, index_out, index_in, count_out, count_in, transferred; + uint8_t buffer[64]; + + if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) + angie_print_queue(device); + + index_out = 0; + count_out = 0; + count_in = 0; + + for (current = device->queue_start; current; current = current->next) { + /* Add command to packet */ + buffer[index_out] = current->id; + index_out++; + count_out++; + + for (i = 0; i < current->payload_out_size; i++) + buffer[index_out + i] = current->payload_out[i]; + index_out += current->payload_out_size; + count_in += current->payload_in_size; + count_out += current->payload_out_size; + } + + /* Send packet to ANGIE */ + ret = jtag_libusb_bulk_write(device->usb_device_handle, device->ep_out, + (char *)buffer, count_out, timeout, &transferred); + if (ret != 0) + return ERROR_FAIL; + if (transferred != count_out) + return ERROR_FAIL; + + /* Wait for response if commands contain IN payload data */ + if (count_in > 0) { + ret = jtag_libusb_bulk_write(device->usb_device_handle, device->ep_in, + (char *)buffer, count_in, timeout, &transferred); + if (ret != 0) + return ERROR_FAIL; + if (transferred != count_in) + return ERROR_FAIL; + + /* Write back IN payload data */ + index_in = 0; + for (current = device->queue_start; current; current = current->next) { + for (i = 0; i < current->payload_in_size; i++) { + current->payload_in[i] = buffer[index_in]; + index_in++; + } + } + } + + return ERROR_OK; +} + +/** + * Convert an ANGIE command ID (\a id) to a human-readable string. + * + * @param id the ANGIE command ID. + * @return the corresponding human-readable string. + */ +static const char *angie_cmd_id_string(uint8_t id) +{ + switch (id) { + case CMD_SCAN_IN: + return "CMD_SCAN_IN"; + case CMD_SLOW_SCAN_IN: + return "CMD_SLOW_SCAN_IN"; + case CMD_SCAN_OUT: + return "CMD_SCAN_OUT"; + case CMD_SLOW_SCAN_OUT: + return "CMD_SLOW_SCAN_OUT"; + case CMD_SCAN_IO: + return "CMD_SCAN_IO"; + case CMD_SLOW_SCAN_IO: + return "CMD_SLOW_SCAN_IO"; + case CMD_CLOCK_TMS: + return "CMD_CLOCK_TMS"; + case CMD_SLOW_CLOCK_TMS: + return "CMD_SLOW_CLOCK_TMS"; + case CMD_CLOCK_TCK: + return "CMD_CLOCK_TCK"; + case CMD_SLOW_CLOCK_TCK: + return "CMD_SLOW_CLOCK_TCK"; + case CMD_SLEEP_US: + return "CMD_SLEEP_US"; + case CMD_SLEEP_MS: + return "CMD_SLEEP_MS"; + case CMD_GET_SIGNALS: + return "CMD_GET_SIGNALS"; + case CMD_SET_SIGNALS: + return "CMD_SET_SIGNALS"; + case CMD_CONFIGURE_TCK_FREQ: + return "CMD_CONFIGURE_TCK_FREQ"; + case CMD_SET_LEDS: + return "CMD_SET_LEDS"; + case CMD_TEST: + return "CMD_TEST"; + default: + return "CMD_UNKNOWN"; + } +} + +/** + * Print one ANGIE command to stdout. + * + * @param angie_cmd pointer to ANGIE command. + */ +static void angie_print_command(struct angie_cmd *angie_cmd) +{ + int i; + + printf(" %-22s | OUT size = %i, bytes = 0x", + angie_cmd_id_string(angie_cmd->id), angie_cmd->payload_out_size); + + for (i = 0; i < angie_cmd->payload_out_size; i++) + printf("%02X ", angie_cmd->payload_out[i]); + printf("\n | IN size = %i\n", + angie_cmd->payload_in_size); +} + +/** + * Print the ANGIE command queue to stdout. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + */ +static void angie_print_queue(struct angie *device) +{ + struct angie_cmd *current; + + printf("ANGIE command queue:\n"); + + for (current = device->queue_start; current; current = current->next) + angie_print_command(current); +} + +/** + * Perform JTAG scan + * + * Creates and appends a JTAG scan command to the ANGIE command queue. + * A JTAG scan consists of three steps: + * - Move to the desired SHIFT state, depending on scan type (IR/DR scan). + * - Shift TDI data into the JTAG chain, optionally reading the TDO pin. + * - Move to the desired end state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param scan_type the type of the scan (IN, OUT, IO (bidirectional)). + * @param scan_size_bits number of bits to shift into the JTAG chain. + * @param tdi pointer to array containing TDI data. + * @param tdo_start pointer to first element of array where TDO data shall be + * stored. See #angie_cmd for details. + * @param tdo pointer to array where TDO data shall be stored + * @param tms_count_start number of TMS state transitions to perform BEFORE + * shifting data into the JTAG chain. + * @param tms_sequence_start sequence of TMS state transitions that will be + * performed BEFORE shifting data into the JTAG chain. + * @param tms_count_end number of TMS state transitions to perform AFTER + * shifting data into the JTAG chain. + * @param tms_sequence_end sequence of TMS state transitions that will be + * performed AFTER shifting data into the JTAG chain. + * @param origin pointer to OpenOCD command that generated this scan command. + * @param postprocess whether this command needs to be post-processed after + * execution. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_scan_cmd(struct angie *device, enum scan_type scan_type, + int scan_size_bits, uint8_t *tdi, uint8_t *tdo_start, uint8_t *tdo, + uint8_t tms_count_start, uint8_t tms_sequence_start, uint8_t tms_count_end, + uint8_t tms_sequence_end, struct jtag_command *origin, bool postprocess) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret, i, scan_size_bytes; + uint8_t bits_last_byte; + + if (!cmd) + return ERROR_FAIL; + + /* Check size of command. USB buffer can hold 64 bytes, 1 byte is command ID, + * 5 bytes are setup data -> 58 remaining payload bytes for TDI data */ + if (scan_size_bits > (58 * 8)) { + LOG_ERROR("BUG: Tried to create CMD_SCAN_IO ANGIE command with too" + " large payload"); + free(cmd); + return ERROR_FAIL; + } + + scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); + + bits_last_byte = scan_size_bits % 8; + if (bits_last_byte == 0) + bits_last_byte = 8; + + /* Allocate out_payload depending on scan type */ + switch (scan_type) { + case SCAN_IN: + if (device->delay_scan_in < 0) + cmd->id = CMD_SCAN_IN; + else + cmd->id = CMD_SLOW_SCAN_IN; + ret = angie_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_IN); + break; + case SCAN_OUT: + if (device->delay_scan_out < 0) + cmd->id = CMD_SCAN_OUT; + else + cmd->id = CMD_SLOW_SCAN_OUT; + ret = angie_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); + break; + case SCAN_IO: + if (device->delay_scan_io < 0) + cmd->id = CMD_SCAN_IO; + else + cmd->id = CMD_SLOW_SCAN_IO; + ret = angie_allocate_payload(cmd, scan_size_bytes + 5, PAYLOAD_DIRECTION_OUT); + break; + default: + LOG_ERROR("BUG: 'append scan cmd' encountered an unknown scan type"); + ret = ERROR_FAIL; + break; + } + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + /* Build payload_out that is common to all scan types */ + cmd->payload_out[0] = scan_size_bytes & 0xFF; + cmd->payload_out[1] = bits_last_byte & 0xFF; + cmd->payload_out[2] = ((tms_count_start & 0x0F) << 4) | (tms_count_end & 0x0F); + cmd->payload_out[3] = tms_sequence_start; + cmd->payload_out[4] = tms_sequence_end; + + /* Setup payload_out for types with OUT transfer */ + if (scan_type == SCAN_OUT || scan_type == SCAN_IO) { + for (i = 0; i < scan_size_bytes; i++) + cmd->payload_out[i + 5] = tdi[i]; + } + + /* Setup payload_in pointers for types with IN transfer */ + if (scan_type == SCAN_IN || scan_type == SCAN_IO) { + cmd->payload_in_start = tdo_start; + cmd->payload_in = tdo; + cmd->payload_in_size = scan_size_bytes; + } + + cmd->needs_postprocessing = postprocess; + cmd->cmd_origin = origin; + + /* For scan commands, we free payload_in_start only when the command is + * the last in a series of split commands or a stand-alone command */ + cmd->free_payload_in_start = postprocess; + + return angie_append_queue(device, cmd); +} + +/** + * Perform TAP state transitions + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param count defines the number of TCK clock cycles generated (up to 8). + * @param sequence defines the TMS pin levels for each state transition. The + * Least-Significant Bit is read first. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_clock_tms_cmd(struct angie *device, uint8_t count, + uint8_t sequence) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) + return ERROR_FAIL; + + if (device->delay_clock_tms < 0) + cmd->id = CMD_CLOCK_TMS; + else + cmd->id = CMD_SLOW_CLOCK_TMS; + + /* CMD_CLOCK_TMS has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = count; + cmd->payload_out[1] = sequence; + + return angie_append_queue(device, cmd); +} + +/** + * Generate a defined amount of TCK clock cycles + * + * All other JTAG signals are left unchanged. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param count the number of TCK clock cycles to generate. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_clock_tck_cmd(struct angie *device, uint16_t count) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) + return ERROR_FAIL; + + if (device->delay_clock_tck < 0) + cmd->id = CMD_CLOCK_TCK; + else + cmd->id = CMD_SLOW_CLOCK_TCK; + + /* CMD_CLOCK_TCK has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = count & 0xff; + cmd->payload_out[1] = (count >> 8) & 0xff; + + return angie_append_queue(device, cmd); +} + +/** + * Read JTAG signals. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_get_signals_cmd(struct angie *device) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) + return ERROR_FAIL; + + cmd->id = CMD_GET_SIGNALS; + cmd->needs_postprocessing = true; + + /* CMD_GET_SIGNALS has two IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_IN); + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + return angie_append_queue(device, cmd); +} + +/** + * Arbitrarily set JTAG output signals. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param low defines which signals will be de-asserted. Each bit corresponds + * to a JTAG signal: + * - SIGNAL_TDI + * - SIGNAL_TMS + * - SIGNAL_TCK + * - SIGNAL_TRST + * - SIGNAL_BRKIN + * - SIGNAL_RESET + * - SIGNAL_OCDSE + * @param high defines which signals will be asserted. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_set_signals_cmd(struct angie *device, uint8_t low, + uint8_t high) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) + return ERROR_FAIL; + + cmd->id = CMD_SET_SIGNALS; + + /* CMD_SET_SIGNALS has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = low; + cmd->payload_out[1] = high; + + return angie_append_queue(device, cmd); +} + +/** + * Sleep for a pre-defined number of microseconds + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param us the number microseconds to sleep. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_sleep_cmd(struct angie *device, uint32_t us) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) + return ERROR_FAIL; + + cmd->id = CMD_SLEEP_US; + + /* CMD_SLEEP_US has two OUT payload bytes and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 2, PAYLOAD_DIRECTION_OUT); + + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = us & 0x00ff; + cmd->payload_out[1] = (us >> 8) & 0x00ff; + + return angie_append_queue(device, cmd); +} + +/** + * Set TCK delay counters + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param delay_scan_in delay count top value in jtag_slow_scan_in() function. + * @param delay_scan_out delay count top value in jtag_slow_scan_out() function. + * @param delay_scan_io delay count top value in jtag_slow_scan_io() function. + * @param delay_tck delay count top value in jtag_clock_tck() function. + * @param delay_tms delay count top value in jtag_slow_clock_tms() function. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_configure_tck_cmd(struct angie *device, int delay_scan_in, + int delay_scan_out, int delay_scan_io, int delay_tck, int delay_tms) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) + return ERROR_FAIL; + + cmd->id = CMD_CONFIGURE_TCK_FREQ; + + /* CMD_CONFIGURE_TCK_FREQ has five OUT payload bytes and zero + * IN payload bytes */ + ret = angie_allocate_payload(cmd, 5, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + if (delay_scan_in < 0) + cmd->payload_out[0] = 0; + else + cmd->payload_out[0] = (uint8_t)delay_scan_in; + + if (delay_scan_out < 0) + cmd->payload_out[1] = 0; + else + cmd->payload_out[1] = (uint8_t)delay_scan_out; + + if (delay_scan_io < 0) + cmd->payload_out[2] = 0; + else + cmd->payload_out[2] = (uint8_t)delay_scan_io; + + if (delay_tck < 0) + cmd->payload_out[3] = 0; + else + cmd->payload_out[3] = (uint8_t)delay_tck; + + if (delay_tms < 0) + cmd->payload_out[4] = 0; + else + cmd->payload_out[4] = (uint8_t)delay_tms; + + return angie_append_queue(device, cmd); +} + +/** + * Test command. Used to check if the ANGIE device is ready to accept new + * commands. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_append_test_cmd(struct angie *device) +{ + struct angie_cmd *cmd = calloc(1, sizeof(struct angie_cmd)); + int ret; + + if (!cmd) + return ERROR_FAIL; + + cmd->id = CMD_TEST; + + /* CMD_TEST has one OUT payload byte and zero IN payload bytes */ + ret = angie_allocate_payload(cmd, 1, PAYLOAD_DIRECTION_OUT); + if (ret != ERROR_OK) { + free(cmd); + return ret; + } + + cmd->payload_out[0] = 0xAA; + + return angie_append_queue(device, cmd); +} + +/****************** ANGIE TCK frequency helper functions ******************/ + +/** + * Calculate delay values for a given TCK frequency. + * + * The ANGIE firmware uses five different speed values for different + * commands. These speed values are calculated in these functions. + * + * The five different commands which support variable TCK frequency are + * implemented twice in the firmware: + * 1. Maximum possible frequency without any artificial delay + * 2. Variable frequency with artificial linear delay loop + * + * To set the ANGIE to maximum frequency, it is only necessary to use the + * corresponding command IDs. To set the ANGIE to a lower frequency, the + * delay loop top values have to be calculated first. Then, a + * CMD_CONFIGURE_TCK_FREQ command needs to be sent to the ANGIE device. + * + * The delay values are described by linear equations: + * t = k * x + d + * (t = period, k = constant, x = delay value, d = constant) + * + * Thus, the delay can be calculated as in the following equation: + * x = (t - d) / k + * + * The constants in these equations have been determined and validated by + * measuring the frequency resulting from different delay values. + * + * @param type for which command to calculate the delay value. + * @param f TCK frequency for which to calculate the delay value in Hz. + * @param delay where to store resulting delay value. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_calculate_delay(enum angie_delay_type type, long f, int *delay) +{ + float t, x, x_ceil; + + /* Calculate period of requested TCK frequency */ + t = 1.0 / (float)(f); + + switch (type) { + case DELAY_CLOCK_TCK: + x = (t - (float)(6 / 1000000)) / (float)(4 / 1000000); + break; + case DELAY_CLOCK_TMS: + x = (t - (float)(8.5 / 1000000)) / (float)(4 / 1000000); + break; + case DELAY_SCAN_IN: + x = (t - (float)(8.8308 / 1000000)) / (float)(4 / 1000000); + break; + case DELAY_SCAN_OUT: + x = (t - (float)(1.0527 / 100000)) / (float)(4 / 1000000); + break; + case DELAY_SCAN_IO: + x = (t - (float)(1.3132 / 100000)) / (float)(4 / 1000000); + break; + default: + return ERROR_FAIL; + break; + } + + /* Check if the delay value is negative. This happens when a frequency is + * requested that is too high for the delay loop implementation. In this + * case, set delay value to zero. */ + if (x < 0) + x = 0; + + /* We need to convert the exact delay value to an integer. Therefore, we + * round the exact value UP to ensure that the resulting frequency is NOT + * higher than the requested frequency. */ + x_ceil = ceilf(x); + + /* Check if the value is within limits */ + if (x_ceil > 255) + return ERROR_FAIL; + + *delay = (int)x_ceil; + + return ERROR_OK; +} + +/** + * Calculate frequency for a given delay value. + * + * Similar to the #angie_calculate_delay function, this function calculates the + * TCK frequency for a given delay value by using linear equations of the form: + * t = k * x + d + * (t = period, k = constant, x = delay value, d = constant) + * + * @param type for which command to calculate the delay value. + * @param delay value for which to calculate the resulting TCK frequency. + * @return the resulting TCK frequency + */ +static long angie_calculate_frequency(enum angie_delay_type type, int delay) +{ + float t, f_float; + + if (delay > 255) + return 0; + + switch (type) { + case DELAY_CLOCK_TCK: + if (delay < 0) + t = (float)(2.666 / 1000000); + else + t = (float)(4 / 1000000) * (float)(delay) + (float)(6 / 1000000); + break; + case DELAY_CLOCK_TMS: + if (delay < 0) + t = (float)(5.666 / 1000000); + else + t = (float)(4 / 1000000) * (float)(delay) + (float)(8.5 / 1000000); + break; + case DELAY_SCAN_IN: + if (delay < 0) + t = (float)(5.5 / 1000000); + else + t = (float)(4 / 1000000) * (float)(delay) + (float)(8.8308 / 1000000); + break; + case DELAY_SCAN_OUT: + if (delay < 0) + t = (float)(7.0 / 1000000); + else + t = (float)(4 / 1000000) * (float)(delay) + (float)(1.0527 / 100000); + break; + case DELAY_SCAN_IO: + if (delay < 0) + t = (float)(9.926 / 1000000); + else + t = (float)(4 / 1000000) * (float)(delay) + (float)(1.3132 / 100000); + break; + default: + return 0; + } + + f_float = 1.0 / t; + return roundf(f_float); +} + +/******************* Interface between ANGIE and OpenOCD ******************/ + +/** + * Sets the end state follower (see interface.h) if \a endstate is a stable + * state. + * + * @param endstate the state the end state follower should be set to. + */ +static void angie_set_end_state(tap_state_t endstate) +{ + if (tap_is_state_stable(endstate)) { + tap_set_end_state(endstate); + } else { + LOG_ERROR("BUG: %s is not a valid end state", tap_state_name(endstate)); + exit(EXIT_FAILURE); + } +} + +/** + * Move from the current TAP state to the current TAP end state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_statemove(struct angie *device) +{ + uint8_t tms_sequence, tms_count; + int ret; + + if (tap_get_state() == tap_get_end_state()) { + /* Do nothing if we are already there */ + return ERROR_OK; + } + + tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + + ret = angie_append_clock_tms_cmd(device, tms_count, tms_sequence); + + if (ret == ERROR_OK) + tap_set_state(tap_get_end_state()); + + return ret; +} + +/** + * Perform a scan operation on a JTAG register. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_scan(struct angie *device, struct jtag_command *cmd) +{ + uint32_t scan_size_bits, scan_size_bytes, bits_last_scan; + uint32_t scans_max_payload, bytecount; + uint8_t *tdi_buffer_start = NULL, *tdi_buffer = NULL; + uint8_t *tdo_buffer_start = NULL, *tdo_buffer = NULL; + + uint8_t first_tms_count, first_tms_sequence; + uint8_t last_tms_count, last_tms_sequence; + + uint8_t tms_count_pause, tms_sequence_pause; + uint8_t tms_count_resume, tms_sequence_resume; + + uint8_t tms_count_start, tms_sequence_start; + uint8_t tms_count_end, tms_sequence_end; + + enum scan_type type; + int ret; + + /* Determine scan size */ + scan_size_bits = jtag_scan_size(cmd->cmd.scan); + scan_size_bytes = DIV_ROUND_UP(scan_size_bits, 8); + + /* Determine scan type (IN/OUT/IO) */ + type = jtag_scan_type(cmd->cmd.scan); + + /* Determine number of scan commands with maximum payload */ + scans_max_payload = scan_size_bytes / 58; + + /* Determine size of last shift command */ + bits_last_scan = scan_size_bits - (scans_max_payload * 58 * 8); + + /* Allocate TDO buffer if required */ + if (type == SCAN_IN || type == SCAN_IO) { + tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes); + + if (!tdo_buffer_start) + return ERROR_FAIL; + + tdo_buffer = tdo_buffer_start; + } + + /* Fill TDI buffer if required */ + if (type == SCAN_OUT || type == SCAN_IO) { + jtag_build_buffer(cmd->cmd.scan, &tdi_buffer_start); + tdi_buffer = tdi_buffer_start; + } + + /* Get TAP state transitions */ + if (cmd->cmd.scan->ir_scan) { + angie_set_end_state(TAP_IRSHIFT); + first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + tap_set_state(TAP_IRSHIFT); + tap_set_end_state(cmd->cmd.scan->end_state); + last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + /* TAP state transitions for split scans */ + tms_count_pause = tap_get_tms_path_len(TAP_IRSHIFT, TAP_IRPAUSE); + tms_sequence_pause = tap_get_tms_path(TAP_IRSHIFT, TAP_IRPAUSE); + tms_count_resume = tap_get_tms_path_len(TAP_IRPAUSE, TAP_IRSHIFT); + tms_sequence_resume = tap_get_tms_path(TAP_IRPAUSE, TAP_IRSHIFT); + } else { + angie_set_end_state(TAP_DRSHIFT); + first_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + first_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + tap_set_state(TAP_DRSHIFT); + tap_set_end_state(cmd->cmd.scan->end_state); + last_tms_count = tap_get_tms_path_len(tap_get_state(), tap_get_end_state()); + last_tms_sequence = tap_get_tms_path(tap_get_state(), tap_get_end_state()); + + /* TAP state transitions for split scans */ + tms_count_pause = tap_get_tms_path_len(TAP_DRSHIFT, TAP_DRPAUSE); + tms_sequence_pause = tap_get_tms_path(TAP_DRSHIFT, TAP_DRPAUSE); + tms_count_resume = tap_get_tms_path_len(TAP_DRPAUSE, TAP_DRSHIFT); + tms_sequence_resume = tap_get_tms_path(TAP_DRPAUSE, TAP_DRSHIFT); + } + + /* Generate scan commands */ + bytecount = scan_size_bytes; + while (bytecount > 0) { + if (bytecount == scan_size_bytes) { + /* This is the first scan */ + tms_count_start = first_tms_count; + tms_sequence_start = first_tms_sequence; + } else { + /* Resume from previous scan */ + tms_count_start = tms_count_resume; + tms_sequence_start = tms_sequence_resume; + } + + if (bytecount > 58) { /* Full scan, at least one scan will follow */ + tms_count_end = tms_count_pause; + tms_sequence_end = tms_sequence_pause; + + ret = angie_append_scan_cmd(device, + type, + 58 * 8, + tdi_buffer, + tdo_buffer_start, + tdo_buffer, + tms_count_start, + tms_sequence_start, + tms_count_end, + tms_sequence_end, + cmd, + false); + + bytecount -= 58; + + /* Update TDI and TDO buffer pointers */ + if (tdi_buffer_start) + tdi_buffer += 58; + if (tdo_buffer_start) + tdo_buffer += 58; + } else if (bytecount == 58) { /* Full scan, no further scans */ + tms_count_end = last_tms_count; + tms_sequence_end = last_tms_sequence; + + ret = angie_append_scan_cmd(device, + type, + 58 * 8, + tdi_buffer, + tdo_buffer_start, + tdo_buffer, + tms_count_start, + tms_sequence_start, + tms_count_end, + tms_sequence_end, + cmd, + true); + + bytecount = 0; + } else {/* Scan with less than maximum payload, no further scans */ + tms_count_end = last_tms_count; + tms_sequence_end = last_tms_sequence; + + ret = angie_append_scan_cmd(device, + type, + bits_last_scan, + tdi_buffer, + tdo_buffer_start, + tdo_buffer, + tms_count_start, + tms_sequence_start, + tms_count_end, + tms_sequence_end, + cmd, + true); + + bytecount = 0; + } + + if (ret != ERROR_OK) { + free(tdi_buffer_start); + free(tdo_buffer_start); + return ret; + } + } + + free(tdi_buffer_start); + + /* Set current state to the end state requested by the command */ + tap_set_state(cmd->cmd.scan->end_state); + + return ERROR_OK; +} + +/** + * Move the TAP into the Test Logic Reset state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_tlr_reset(struct angie *device, struct jtag_command *cmd) +{ + int ret; + + ret = angie_append_clock_tms_cmd(device, 5, 0xff); + + if (ret == ERROR_OK) + tap_set_state(TAP_RESET); + + return ret; +} + +/** + * Run Test. + * + * Generate TCK clock cycles while remaining + * in the Run-Test/Idle state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_runtest(struct angie *device, struct jtag_command *cmd) +{ + int ret; + + /* Only perform statemove if the TAP currently isn't in the TAP_IDLE state */ + if (tap_get_state() != TAP_IDLE) { + angie_set_end_state(TAP_IDLE); + angie_queue_statemove(device); + } + + /* Generate the clock cycles */ + ret = angie_append_clock_tck_cmd(device, cmd->cmd.runtest->num_cycles); + if (ret != ERROR_OK) + return ret; + + /* Move to end state specified in command */ + if (cmd->cmd.runtest->end_state != tap_get_state()) { + tap_set_end_state(cmd->cmd.runtest->end_state); + angie_queue_statemove(device); + } + + return ERROR_OK; +} + +/** + * Execute a JTAG_RESET command + * + * @param device + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_reset(struct angie *device, struct jtag_command *cmd) +{ + uint8_t low = 0, high = 0; + + if (cmd->cmd.reset->trst) { + tap_set_state(TAP_RESET); + low |= SIGNAL_TRST; + } else { + high |= SIGNAL_TRST; + } + + if (cmd->cmd.reset->srst) + low |= SIGNAL_SRST; + else + high |= SIGNAL_SRST; + + + return angie_append_set_signals_cmd(device, low, high); +} + +/** + * Move to one TAP state or several states in succession. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_pathmove(struct angie *device, struct jtag_command *cmd) +{ + int ret, i, num_states, batch_size, state_count; + tap_state_t *path; + uint8_t tms_sequence; + + num_states = cmd->cmd.pathmove->num_states; + path = cmd->cmd.pathmove->path; + state_count = 0; + + while (num_states > 0) { + tms_sequence = 0; + + /* Determine batch size */ + if (num_states >= 8) + batch_size = 8; + else + batch_size = num_states; + + for (i = 0; i < batch_size; i++) { + if (tap_state_transition(tap_get_state(), false) == path[state_count]) { + /* Append '0' transition: clear bit 'i' in tms_sequence */ + buf_set_u32(&tms_sequence, i, 1, 0x0); + } else if (tap_state_transition(tap_get_state(), true) + == path[state_count]) { + /* Append '1' transition: set bit 'i' in tms_sequence */ + buf_set_u32(&tms_sequence, i, 1, 0x1); + } else { + /* Invalid state transition */ + LOG_ERROR("BUG: %s -> %s isn't a valid TAP state transition", + tap_state_name(tap_get_state()), + tap_state_name(path[state_count])); + return ERROR_FAIL; + } + + tap_set_state(path[state_count]); + state_count++; + num_states--; + } + + /* Append CLOCK_TMS command to ANGIE command queue */ + LOG_INFO("pathmove batch: count = %i, sequence = 0x%x", batch_size, tms_sequence); + ret = angie_append_clock_tms_cmd(angie_handle, batch_size, tms_sequence); + if (ret != ERROR_OK) + return ret; + } + + return ERROR_OK; +} + +/** + * Sleep for a specific amount of time. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_queue_sleep(struct angie *device, struct jtag_command *cmd) +{ + /* IMPORTANT! Due to the time offset in command execution introduced by + * command queueing, this needs to be implemented in the ANGIE device */ + return angie_append_sleep_cmd(device, cmd->cmd.sleep->us); +} + +/** + * Generate TCK cycles while remaining in a stable state. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @param cmd pointer to the command that shall be executed. + */ +static int angie_queue_stableclocks(struct angie *device, struct jtag_command *cmd) +{ + int ret; + unsigned int num_cycles; + + if (!tap_is_state_stable(tap_get_state())) { + LOG_ERROR("JTAG_STABLECLOCKS: state not stable"); + return ERROR_FAIL; + } + + num_cycles = cmd->cmd.stableclocks->num_cycles; + + /* TMS stays either high (Test Logic Reset state) or low (all other states) */ + if (tap_get_state() == TAP_RESET) + ret = angie_append_set_signals_cmd(device, 0, SIGNAL_TMS); + else + ret = angie_append_set_signals_cmd(device, SIGNAL_TMS, 0); + + if (ret != ERROR_OK) + return ret; + + while (num_cycles > 0) { + if (num_cycles > 0xFFFF) { + /* ANGIE CMD_CLOCK_TCK can generate up to 0xFFFF (uint16_t) cycles */ + ret = angie_append_clock_tck_cmd(device, 0xFFFF); + num_cycles -= 0xFFFF; + } else { + ret = angie_append_clock_tck_cmd(device, num_cycles); + num_cycles = 0; + } + + if (ret != ERROR_OK) + return ret; + } + + return ERROR_OK; +} + +/** + * Post-process JTAG_SCAN command + * + * @param angie_cmd pointer to ANGIE command that shall be processed. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_post_process_scan(struct angie_cmd *angie_cmd) +{ + struct jtag_command *cmd = angie_cmd->cmd_origin; + int ret; + + switch (jtag_scan_type(cmd->cmd.scan)) { + case SCAN_IN: + case SCAN_IO: + ret = jtag_read_buffer(angie_cmd->payload_in_start, cmd->cmd.scan); + break; + case SCAN_OUT: + /* Nothing to do for OUT scans */ + ret = ERROR_OK; + break; + default: + LOG_ERROR("BUG: angie post process scan encountered an unknown" + " JTAG scan type"); + ret = ERROR_FAIL; + break; + } + + return ret; +} + +/** + * Perform post-processing of commands after ANGIE queue has been executed. + * + * @param device pointer to struct angie identifying ANGIE driver instance. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_post_process_queue(struct angie *device) +{ + struct angie_cmd *current; + struct jtag_command *openocd_cmd; + int ret; + + current = device->queue_start; + + while (current) { + openocd_cmd = current->cmd_origin; + + /* Check if a corresponding OpenOCD command is stored for this + * ANGIE command */ + if (current->needs_postprocessing && openocd_cmd) { + switch (openocd_cmd->type) { + case JTAG_SCAN: + ret = angie_post_process_scan(current); + break; + case JTAG_TLR_RESET: + case JTAG_RUNTEST: + case JTAG_RESET: + case JTAG_PATHMOVE: + case JTAG_SLEEP: + case JTAG_STABLECLOCKS: + /* Nothing to do for these commands */ + ret = ERROR_OK; + break; + default: + ret = ERROR_FAIL; + LOG_ERROR("BUG: angie post process queue encountered unknown JTAG " + "command type"); + break; + } + + if (ret != ERROR_OK) + return ret; + } + + current = current->next; + } + + return ERROR_OK; +} + +/**************************** JTAG driver functions ***************************/ + +/** + * Executes the JTAG Command Queue. + * + * This is done in three stages: First, all OpenOCD commands are processed into + * queued ANGIE commands. Next, the ANGIE command queue is sent to the + * ANGIE device and data received from the ANGIE device is cached. Finally, + * the post-processing function writes back data to the corresponding OpenOCD + * commands. + * + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_execute_queue(void) +{ + struct jtag_command *cmd = jtag_command_queue; + int ret; + + while (cmd) { + switch (cmd->type) { + case JTAG_SCAN: + ret = angie_queue_scan(angie_handle, cmd); + break; + case JTAG_TLR_RESET: + ret = angie_queue_tlr_reset(angie_handle, cmd); + break; + case JTAG_RUNTEST: + ret = angie_queue_runtest(angie_handle, cmd); + break; + case JTAG_RESET: + ret = angie_queue_reset(angie_handle, cmd); + break; + case JTAG_PATHMOVE: + ret = angie_queue_pathmove(angie_handle, cmd); + break; + case JTAG_SLEEP: + ret = angie_queue_sleep(angie_handle, cmd); + break; + case JTAG_STABLECLOCKS: + ret = angie_queue_stableclocks(angie_handle, cmd); + break; + default: + ret = ERROR_FAIL; + LOG_ERROR("BUG: encountered unknown JTAG command type"); + break; + } + + if (ret != ERROR_OK) + return ret; + + cmd = cmd->next; + } + + if (angie_handle->commands_in_queue > 0) { + ret = angie_execute_queued_commands(angie_handle, LIBUSB_TIMEOUT_MS); + if (ret != ERROR_OK) + return ret; + + ret = angie_post_process_queue(angie_handle); + if (ret != ERROR_OK) + return ret; + + angie_clear_queue(angie_handle); + } + + return ERROR_OK; +} + +/** + * Set the TCK frequency of the ANGIE adapter. + * + * @param khz desired JTAG TCK frequency. + * @param jtag_speed where to store corresponding adapter-specific speed value. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_khz(int khz, int *jtag_speed) +{ + int ret; + + if (khz == 0) { + LOG_ERROR("RCLK not supported"); + return ERROR_FAIL; + } + + /* CLOCK_TCK commands are decoupled from others. Therefore, the frequency + * setting can be done independently from all other commands. */ + if (khz >= 375) { + angie_handle->delay_clock_tck = -1; + } else { + ret = angie_calculate_delay(DELAY_CLOCK_TCK, khz * 1000, + &angie_handle->delay_clock_tck); + if (ret != ERROR_OK) + return ret; + } + + /* SCAN_{IN,OUT,IO} commands invoke CLOCK_TMS commands. Therefore, if the + * requested frequency goes below the maximum frequency for SLOW_CLOCK_TMS + * commands, all SCAN commands MUST also use the variable frequency + * implementation! */ + if (khz >= 176) { + angie_handle->delay_clock_tms = -1; + angie_handle->delay_scan_in = -1; + angie_handle->delay_scan_out = -1; + angie_handle->delay_scan_io = -1; + } else { + ret = angie_calculate_delay(DELAY_CLOCK_TMS, khz * 1000, + &angie_handle->delay_clock_tms); + if (ret != ERROR_OK) + return ret; + + ret = angie_calculate_delay(DELAY_SCAN_IN, khz * 1000, + &angie_handle->delay_scan_in); + if (ret != ERROR_OK) + return ret; + + ret = angie_calculate_delay(DELAY_SCAN_OUT, khz * 1000, + &angie_handle->delay_scan_out); + if (ret != ERROR_OK) + return ret; + + ret = angie_calculate_delay(DELAY_SCAN_IO, khz * 1000, + &angie_handle->delay_scan_io); + if (ret != ERROR_OK) + return ret; + } + + LOG_DEBUG_IO("ANGIE TCK setup: delay_tck = %i (%li Hz),", + angie_handle->delay_clock_tck, + angie_calculate_frequency(DELAY_CLOCK_TCK, angie_handle->delay_clock_tck)); + LOG_DEBUG_IO(" delay_tms = %i (%li Hz),", + angie_handle->delay_clock_tms, + angie_calculate_frequency(DELAY_CLOCK_TMS, angie_handle->delay_clock_tms)); + LOG_DEBUG_IO(" delay_scan_in = %i (%li Hz),", + angie_handle->delay_scan_in, + angie_calculate_frequency(DELAY_SCAN_IN, angie_handle->delay_scan_in)); + LOG_DEBUG_IO(" delay_scan_out = %i (%li Hz),", + angie_handle->delay_scan_out, + angie_calculate_frequency(DELAY_SCAN_OUT, angie_handle->delay_scan_out)); + LOG_DEBUG_IO(" delay_scan_io = %i (%li Hz),", + angie_handle->delay_scan_io, + angie_calculate_frequency(DELAY_SCAN_IO, angie_handle->delay_scan_io)); + + /* Configure the ANGIE device with the new delay values */ + ret = angie_append_configure_tck_cmd(angie_handle, + angie_handle->delay_scan_in, + angie_handle->delay_scan_out, + angie_handle->delay_scan_io, + angie_handle->delay_clock_tck, + angie_handle->delay_clock_tms); + + if (ret != ERROR_OK) + return ret; + + *jtag_speed = khz; + + return ERROR_OK; +} + +/** + * Set the TCK frequency of the ANGIE adapter. + * + * Because of the way the TCK frequency is set up in the ANGIE firmware, + * there are five different speed settings. To simplify things, the + * adapter-specific speed setting value is identical to the TCK frequency in + * khz. + * + * @param speed desired adapter-specific speed value. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_speed(int speed) +{ + int dummy; + + return angie_khz(speed, &dummy); +} + +/** + * Convert adapter-specific speed value to corresponding TCK frequency in kHz. + * + * Because of the way the TCK frequency is set up in the ANGIE firmware, + * there are five different speed settings. To simplify things, the + * adapter-specific speed setting value is identical to the TCK frequency in + * khz. + * + * @param speed adapter-specific speed value. + * @param khz where to store corresponding TCK frequency in kHz. + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_speed_div(int speed, int *khz) +{ + *khz = speed; + + return ERROR_OK; +} + +/** + * Initiates the firmware download to the ANGIE adapter and prepares + * the USB handle. + * + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_init(void) +{ + int ret, transferred; + char str_manufacturer[20]; + bool download_firmware = false; + char *dummy; + uint8_t input_signals, output_signals; + + angie_handle = calloc(1, sizeof(struct angie)); + if (!angie_handle) + return ERROR_FAIL; + + libusb_init(&angie_handle->libusb_ctx); + + ret = angie_usb_open(&angie_handle); + if (ret != ERROR_OK) { + LOG_ERROR("Could not open ANGIE device"); + free(angie_handle); + angie_handle = NULL; + return ret; + } + + /* Get String Descriptor to determine if firmware needs to be loaded */ + ret = libusb_get_string_descriptor_ascii(angie_handle->usb_device_handle, 1, (unsigned char *)str_manufacturer, 20); + if (ret < 0) { + /* Could not get descriptor -> Unconfigured or original Keil firmware */ + download_firmware = true; + } else { + /* We got a String Descriptor, check if it is the correct one */ + if (strncmp(str_manufacturer, "NanoXplore, SAS.", 16) != 0) { + LOG_ERROR("A different Firmware is loaded, please unplug and reconnect ANGIE."); + return ERROR_FAIL; + } + download_firmware = false; + } + + if (download_firmware) { + LOG_INFO("Loading ANGIE firmware. This is reversible by power-cycling" + " ANGIE device."); + + ret = libusb_claim_interface(angie_handle->usb_device_handle, 0); + if (ret != ERROR_OK) + LOG_ERROR("Could not claim interface"); + + ret = angie_load_firmware_and_renumerate(&angie_handle, + ANGIE_FIRMWARE_FILE, ANGIE_RENUMERATION_DELAY); + if (ret != ERROR_OK) { + LOG_ERROR("Could not download firmware and re-numerate ANGIE"); + free(angie_handle); + angie_handle = NULL; + return ret; + } + ret = angie_load_bitstream(angie_handle, ANGIE_BITSTREAM_FILE); + if (ret != ERROR_OK) { + LOG_ERROR("Could not download bitstream"); + free(angie_handle); + angie_handle = NULL; + return ret; + } + } else { + LOG_INFO("ANGIE device is already running ANGIE firmware"); + } + + /* Get ANGIE USB IN/OUT endpoints and claim the interface */ + ret = jtag_libusb_choose_interface(angie_handle->usb_device_handle, + &angie_handle->ep_in, &angie_handle->ep_out, -1, -1, -1, -1); + if (ret != ERROR_OK) + return ret; + + /* Initialize ANGIE command queue */ + angie_clear_queue(angie_handle); + + /* Issue one test command with short timeout */ + ret = angie_append_test_cmd(angie_handle); + if (ret != ERROR_OK) + return ret; + + ret = angie_execute_queued_commands(angie_handle, 200); + if (ret != ERROR_OK) { + /* Sending test command failed. The ANGIE device may be forever waiting for + * the host to fetch an USB Bulk IN packet (e. g. OpenOCD crashed or was + * shut down by the user via Ctrl-C. Try to retrieve this Bulk IN packet. */ + dummy = calloc(64, sizeof(uint8_t)); + + ret = jtag_libusb_bulk_write(angie_handle->usb_device_handle, angie_handle->ep_in, + dummy, 64, 200, &transferred); + + free(dummy); + + if (ret != 0 || transferred == 0) { + /* Bulk IN transfer failed -> unrecoverable error condition */ + LOG_ERROR("Cannot communicate with ANGIE device. Disconnect ANGIE from " + "the USB port and re-connect, then re-run OpenOCD"); + free(angie_handle); + angie_handle = NULL; + return ERROR_FAIL; + angie_handle = NULL; + } else { + /* Successfully received Bulk IN packet -> continue */ + LOG_INFO("Recovered from lost Bulk IN packet"); + } + } + angie_clear_queue(angie_handle); + + ret = angie_append_get_signals_cmd(angie_handle); + if (ret == ERROR_OK) + ret = angie_execute_queued_commands(angie_handle, 200); + + if (ret == ERROR_OK) { + /* Post-process the single CMD_GET_SIGNALS command */ + input_signals = angie_handle->queue_start->payload_in[0]; + output_signals = angie_handle->queue_start->payload_in[1]; + + angie_print_signal_states(input_signals, output_signals); + } + + angie_clear_queue(angie_handle); + + return ERROR_OK; +} + +/** + * Closes the USB handle for the ANGIE device. + * + * @return on success: ERROR_OK + * @return on failure: ERROR_FAIL + */ +static int angie_quit(void) +{ + int ret; + + ret = angie_usb_close(&angie_handle); + free(angie_handle); + + return ret; +} + +/** + * Set a custom path to ANGIE firmware image and force downloading to ANGIE. + */ +COMMAND_HANDLER(angie_download_firmware_handler) +{ + int ret; + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + + LOG_INFO("Downloading ANGIE firmware image %s", CMD_ARGV[0]); + + /* Download firmware image in CMD_ARGV[0] */ + ret = angie_load_firmware_and_renumerate(&angie_handle, CMD_ARGV[0], + ANGIE_RENUMERATION_DELAY); + + return ret; +} + +/*************************** Command Registration **************************/ + +static const struct command_registration angie_subcommand_handlers[] = { + { + .name = "download_firmware", + .handler = &angie_download_firmware_handler, + .mode = COMMAND_EXEC, + .help = "download firmware image to ANGIE device", + .usage = "path/to/angie_firmware.hex", + }, + COMMAND_REGISTRATION_DONE, +}; + +static const struct command_registration angie_command_handlers[] = { + { + .name = "angie", + .mode = COMMAND_ANY, + .help = "perform angie management", + .chain = angie_subcommand_handlers, + .usage = "", + }, + COMMAND_REGISTRATION_DONE +}; + +static struct jtag_interface angie_interface = { + .execute_queue = angie_execute_queue, +}; + +struct adapter_driver angie_adapter_driver = { + .name = "angie", + .transports = jtag_only, + .commands = angie_command_handlers, + + .init = angie_init, + .quit = angie_quit, + .speed = angie_speed, + .khz = angie_khz, + .speed_div = angie_speed_div, + + .jtag_ops = &angie_interface, +}; diff --git a/src/jtag/interface.h b/src/jtag/interface.h index 50044935bd..ec737b4588 100644 --- a/src/jtag/interface.h +++ b/src/jtag/interface.h @@ -393,6 +393,7 @@ extern struct adapter_driver rshim_dap_adapter_driver; extern struct adapter_driver stlink_dap_adapter_driver; extern struct adapter_driver sysfsgpio_adapter_driver; extern struct adapter_driver ulink_adapter_driver; +extern struct adapter_driver angie_adapter_driver; extern struct adapter_driver usb_blaster_adapter_driver; extern struct adapter_driver usbprog_adapter_driver; extern struct adapter_driver vdebug_adapter_driver; diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c index 48a194fd56..aa0ad3ade1 100644 --- a/src/jtag/interfaces.c +++ b/src/jtag/interfaces.c @@ -96,6 +96,9 @@ struct adapter_driver *adapter_drivers[] = { #if BUILD_ULINK == 1 &ulink_adapter_driver, #endif +#if BUILD_ANGIE == 1 + &angie_adapter_driver, +#endif #if BUILD_ARMJTAGEW == 1 &armjtagew_adapter_driver, #endif diff --git a/src/jtag/startup.tcl b/src/jtag/startup.tcl index b74775a747..0017e634b6 100644 --- a/src/jtag/startup.tcl +++ b/src/jtag/startup.tcl @@ -419,6 +419,12 @@ proc ulink_download_firmware args { eval ulink download_firmware $args } +lappend _telnet_autocomplete_skip angie_download_firmware +proc angie_download_firmware args { + echo "DEPRECATED! use 'angie download_firmware' not 'angie_download_firmware'" + eval angie download_firmware $args +} + lappend _telnet_autocomplete_skip vsllink_usb_vid proc vsllink_usb_vid args { echo "DEPRECATED! use 'vsllink usb_vid' not 'vsllink_usb_vid'" diff --git a/tcl/interface/angie.cfg b/tcl/interface/angie.cfg new file mode 100644 index 0000000000..77fda3ccba --- /dev/null +++ b/tcl/interface/angie.cfg @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (C) 2023 by NanoXplore, France - all rights reserved +# +# configuration file for ANGIE Adapter from NanoXplore. +# + +adapter driver angie +adapter speed 10000 +reset_config trst_and_srst trst_push_pull srst_open_drain \ No newline at end of file --