[FL-1945] Firmware, Scripts, Cli: add OTPv2, alternative displays support and 2-step OTP programming. #764
This commit is contained in:
		
							parent
							
								
									63428609b7
								
							
						
					
					
						commit
						0e14545d48
					
				| @ -57,10 +57,6 @@ static const uint8_t enclave_signature_expected[ENCLAVE_SIGNATURE_KEY_SLOTS][ENC | |||||||
| void cli_command_device_info(Cli* cli, string_t args, void* context) { | void cli_command_device_info(Cli* cli, string_t args, void* context) { | ||||||
|     // Model name
 |     // Model name
 | ||||||
|     printf("hardware_model      : %s\r\n", furi_hal_version_get_model_name()); |     printf("hardware_model      : %s\r\n", furi_hal_version_get_model_name()); | ||||||
|     const char* name = furi_hal_version_get_name_ptr(); |  | ||||||
|     if(name) { |  | ||||||
|         printf("hardware_name       : %s\r\n", name); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     // Unique ID
 |     // Unique ID
 | ||||||
|     printf("hardware_uid        : "); |     printf("hardware_uid        : "); | ||||||
| @ -70,16 +66,24 @@ void cli_command_device_info(Cli* cli, string_t args, void* context) { | |||||||
|     } |     } | ||||||
|     printf("\r\n"); |     printf("\r\n"); | ||||||
| 
 | 
 | ||||||
|  |     // OTP Revision
 | ||||||
|  |     printf("hardware_otp_ver    : %d\r\n", furi_hal_version_get_otp_version()); | ||||||
|  |     printf("hardware_timestamp  : %lu\r\n", furi_hal_version_get_hw_timestamp()); | ||||||
|  | 
 | ||||||
|     // Board Revision
 |     // Board Revision
 | ||||||
|     printf("hardware_ver        : %d\r\n", furi_hal_version_get_hw_version()); |     printf("hardware_ver        : %d\r\n", furi_hal_version_get_hw_version()); | ||||||
|     printf("hardware_target     : %d\r\n", furi_hal_version_get_hw_target()); |     printf("hardware_target     : %d\r\n", furi_hal_version_get_hw_target()); | ||||||
|     printf("hardware_body       : %d\r\n", furi_hal_version_get_hw_body()); |     printf("hardware_body       : %d\r\n", furi_hal_version_get_hw_body()); | ||||||
|     printf("hardware_connect    : %d\r\n", furi_hal_version_get_hw_connect()); |     printf("hardware_connect    : %d\r\n", furi_hal_version_get_hw_connect()); | ||||||
|     printf("hardware_timestamp  : %lu\r\n", furi_hal_version_get_hw_timestamp()); |     printf("hardware_display    : %d\r\n", furi_hal_version_get_hw_display()); | ||||||
| 
 | 
 | ||||||
|     // Color and Region
 |     // Board Personification
 | ||||||
|     printf("hardware_color      : %d\r\n", furi_hal_version_get_hw_color()); |     printf("hardware_color      : %d\r\n", furi_hal_version_get_hw_color()); | ||||||
|     printf("hardware_region     : %d\r\n", furi_hal_version_get_hw_region()); |     printf("hardware_region     : %d\r\n", furi_hal_version_get_hw_region()); | ||||||
|  |     const char* name = furi_hal_version_get_name_ptr(); | ||||||
|  |     if(name) { | ||||||
|  |         printf("hardware_name       : %s\r\n", name); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     // Bootloader Version
 |     // Bootloader Version
 | ||||||
|     const Version* boot_version = furi_hal_version_get_boot_version(); |     const Version* boot_version = furi_hal_version_get_boot_version(); | ||||||
|  | |||||||
| @ -10,13 +10,6 @@ | |||||||
| #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | ||||||
| #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | ||||||
| 
 | 
 | ||||||
| /** OTP Versions enum */ |  | ||||||
| typedef enum { |  | ||||||
|     FuriHalVersionOtpVersion0=0x00, |  | ||||||
|     FuriHalVersionOtpVersion1=0x01, |  | ||||||
|     FuriHalVersionOtpVersionEmpty=0xFFFFFFFE, |  | ||||||
|     FuriHalVersionOtpVersionUnknown=0xFFFFFFFF, |  | ||||||
| } FuriHalVersionOtpVersion; |  | ||||||
| 
 | 
 | ||||||
| /** OTP V0 Structure: prototypes and early EVT */ | /** OTP V0 Structure: prototypes and early EVT */ | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -28,7 +21,7 @@ typedef struct { | |||||||
|     char name[FURI_HAL_VERSION_NAME_LENGTH]; |     char name[FURI_HAL_VERSION_NAME_LENGTH]; | ||||||
| } FuriHalVersionOTPv0; | } FuriHalVersionOTPv0; | ||||||
| 
 | 
 | ||||||
| /** OTP V1 Structure: late EVT, DVT, PVT, Production */ | /** OTP V1 Structure: late EVT, DVT */ | ||||||
| typedef struct { | typedef struct { | ||||||
|     /* First 64 bits: header */ |     /* First 64 bits: header */ | ||||||
|     uint16_t header_magic; |     uint16_t header_magic; | ||||||
| @ -49,10 +42,35 @@ typedef struct { | |||||||
|     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ |     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||||
| } FuriHalVersionOTPv1; | } FuriHalVersionOTPv1; | ||||||
| 
 | 
 | ||||||
|  | /** OTP V2 Structure: DVT2, PVT, Production */ | ||||||
|  | typedef struct { | ||||||
|  |     /* Early First 64 bits: header */ | ||||||
|  |     uint16_t header_magic; | ||||||
|  |     uint8_t header_version; | ||||||
|  |     uint8_t header_reserved; | ||||||
|  |     uint32_t header_timestamp; | ||||||
|  | 
 | ||||||
|  |     /* Early Second 64 bits: board info */ | ||||||
|  |     uint8_t board_version; /** Board version */ | ||||||
|  |     uint8_t board_target; /** Board target firmware */ | ||||||
|  |     uint8_t board_body; /** Board body */ | ||||||
|  |     uint8_t board_connect; /** Board interconnect */ | ||||||
|  |     uint8_t board_display; /** Board display */ | ||||||
|  |     uint8_t board_reserved2_0; /** Reserved for future use, 0x00 */ | ||||||
|  |     uint16_t board_reserved2_1; /** Reserved for future use, 0x0000 */ | ||||||
|  | 
 | ||||||
|  |     /* Late Third 64 bits: device info */ | ||||||
|  |     uint8_t board_color; /** Board color */ | ||||||
|  |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint16_t board_reserved3_0; /** Reserved for future use, 0x0000 */ | ||||||
|  |     uint32_t board_reserved3_1; /** Reserved for future use, 0x00000000 */ | ||||||
|  | 
 | ||||||
|  |     /* Late Fourth 64 bits: Unique Device Name */ | ||||||
|  |     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||||
|  | } FuriHalVersionOTPv2; | ||||||
|  | 
 | ||||||
| /** Represenation Model: */ | /** Represenation Model: */ | ||||||
| typedef struct { | typedef struct { | ||||||
|     FuriHalVersionOtpVersion otp_version; |  | ||||||
| 
 |  | ||||||
|     uint32_t timestamp; |     uint32_t timestamp; | ||||||
| 
 | 
 | ||||||
|     uint8_t board_version; /** Board version */ |     uint8_t board_version; /** Board version */ | ||||||
| @ -61,6 +79,7 @@ typedef struct { | |||||||
|     uint8_t board_connect; /** Board interconnect */ |     uint8_t board_connect; /** Board interconnect */ | ||||||
|     uint8_t board_color; /** Board color */ |     uint8_t board_color; /** Board color */ | ||||||
|     uint8_t board_region; /** Board region */ |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint8_t board_display; /** Board display */ | ||||||
| 
 | 
 | ||||||
|     char name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; /** \0 terminated name */ |     char name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; /** \0 terminated name */ | ||||||
|     char device_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH];  /** device name for special needs */ |     char device_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH];  /** device name for special needs */ | ||||||
| @ -69,20 +88,6 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| static FuriHalVersion furi_hal_version = {0}; | static FuriHalVersion furi_hal_version = {0}; | ||||||
| 
 | 
 | ||||||
| static FuriHalVersionOtpVersion furi_hal_version_get_otp_version() { |  | ||||||
|     if (*(uint64_t*)FURI_HAL_VERSION_OTP_ADDRESS == 0xFFFFFFFF) { |  | ||||||
|         return FuriHalVersionOtpVersionEmpty; |  | ||||||
|     } else { |  | ||||||
|         if (((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_magic == FURI_HAL_VERSION_OTP_HEADER_MAGIC) { |  | ||||||
|             return FuriHalVersionOtpVersion1; |  | ||||||
|         } else if (((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { |  | ||||||
|             return FuriHalVersionOtpVersion0; |  | ||||||
|         } else { |  | ||||||
|             return FuriHalVersionOtpVersionUnknown; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void furi_hal_version_set_name(const char* name) { | static void furi_hal_version_set_name(const char* name) { | ||||||
|     if(name != NULL) { |     if(name != NULL) { | ||||||
|         strlcpy(furi_hal_version.name, name, FURI_HAL_VERSION_ARRAY_NAME_LENGTH); |         strlcpy(furi_hal_version.name, name, FURI_HAL_VERSION_ARRAY_NAME_LENGTH); | ||||||
| @ -124,8 +129,6 @@ static void furi_hal_version_load_otp_v0() { | |||||||
|     furi_hal_version.board_target = otp->board_target; |     furi_hal_version.board_target = otp->board_target; | ||||||
|     furi_hal_version.board_body = otp->board_body; |     furi_hal_version.board_body = otp->board_body; | ||||||
|     furi_hal_version.board_connect = otp->board_connect; |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|     furi_hal_version.board_color = 0; |  | ||||||
|     furi_hal_version.board_region = 0; |  | ||||||
| 
 | 
 | ||||||
|     furi_hal_version_set_name(otp->name); |     furi_hal_version_set_name(otp->name); | ||||||
| } | } | ||||||
| @ -144,9 +147,33 @@ static void furi_hal_version_load_otp_v1() { | |||||||
|     furi_hal_version_set_name(otp->name); |     furi_hal_version_set_name(otp->name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void furi_hal_version_load_otp_v2() { | ||||||
|  |     const FuriHalVersionOTPv2* otp = (FuriHalVersionOTPv2*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||||
|  | 
 | ||||||
|  |     // 1st block, programmed afer baking
 | ||||||
|  |     furi_hal_version.timestamp = otp->header_timestamp; | ||||||
|  | 
 | ||||||
|  |     // 2nd block, programmed afer baking
 | ||||||
|  |     furi_hal_version.board_version = otp->board_version; | ||||||
|  |     furi_hal_version.board_target = otp->board_target; | ||||||
|  |     furi_hal_version.board_body = otp->board_body; | ||||||
|  |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|  |     furi_hal_version.board_display = otp->board_display; | ||||||
|  | 
 | ||||||
|  |     // 3rd and 4th blocks, programmed on FATP stage
 | ||||||
|  |     if (otp->board_color != 0xFF) { | ||||||
|  |         furi_hal_version.board_color = otp->board_color; | ||||||
|  |         furi_hal_version.board_region = otp->board_region; | ||||||
|  |         furi_hal_version_set_name(otp->name); | ||||||
|  |     } else { | ||||||
|  |         furi_hal_version.board_color = 0; | ||||||
|  |         furi_hal_version.board_region = 0; | ||||||
|  |         furi_hal_version_set_name(NULL); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void furi_hal_version_init() { | void furi_hal_version_init() { | ||||||
|     furi_hal_version.otp_version = furi_hal_version_get_otp_version(); |     switch(furi_hal_version_get_otp_version()) { | ||||||
|     switch(furi_hal_version.otp_version) { |  | ||||||
|         case FuriHalVersionOtpVersionUnknown: |         case FuriHalVersionOtpVersionUnknown: | ||||||
|             furi_hal_version_load_otp_default(); |             furi_hal_version_load_otp_default(); | ||||||
|         break; |         break; | ||||||
| @ -159,6 +186,9 @@ void furi_hal_version_init() { | |||||||
|         case FuriHalVersionOtpVersion1: |         case FuriHalVersionOtpVersion1: | ||||||
|             furi_hal_version_load_otp_v1(); |             furi_hal_version_load_otp_v1(); | ||||||
|         break; |         break; | ||||||
|  |         case FuriHalVersionOtpVersion2: | ||||||
|  |             furi_hal_version_load_otp_v2(); | ||||||
|  |         break; | ||||||
|         default: furi_crash(NULL); |         default: furi_crash(NULL); | ||||||
|     } |     } | ||||||
|     FURI_LOG_I("FuriHalVersion", "Init OK"); |     FURI_LOG_I("FuriHalVersion", "Init OK"); | ||||||
| @ -172,6 +202,28 @@ const char* furi_hal_version_get_model_name() { | |||||||
|     return "Flipper Zero"; |     return "Flipper Zero"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const FuriHalVersionOtpVersion furi_hal_version_get_otp_version() { | ||||||
|  |     if (*(uint64_t*)FURI_HAL_VERSION_OTP_ADDRESS == 0xFFFFFFFF) { | ||||||
|  |         return FuriHalVersionOtpVersionEmpty; | ||||||
|  |     } else { | ||||||
|  |         if (((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_magic == FURI_HAL_VERSION_OTP_HEADER_MAGIC) { | ||||||
|  |             // Version 1+
 | ||||||
|  |             uint8_t version = ((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_version; | ||||||
|  |             if (version >= FuriHalVersionOtpVersion1 && version <= FuriHalVersionOtpVersion2) { | ||||||
|  |                 return version; | ||||||
|  |             } else { | ||||||
|  |                 return FuriHalVersionOtpVersionUnknown; | ||||||
|  |             } | ||||||
|  |         } else if (((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { | ||||||
|  |             // Version 0
 | ||||||
|  |             return FuriHalVersionOtpVersion0; | ||||||
|  |         } else { | ||||||
|  |             // Version Unknown
 | ||||||
|  |             return FuriHalVersionOtpVersionUnknown; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const uint8_t furi_hal_version_get_hw_version() { | const uint8_t furi_hal_version_get_hw_version() { | ||||||
|     return furi_hal_version.board_version; |     return furi_hal_version.board_version; | ||||||
| } | } | ||||||
| @ -196,6 +248,10 @@ const FuriHalVersionRegion furi_hal_version_get_hw_region() { | |||||||
|     return furi_hal_version.board_region; |     return furi_hal_version.board_region; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const FuriHalVersionDisplay furi_hal_version_get_hw_display() { | ||||||
|  |     return furi_hal_version.board_display; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const uint32_t furi_hal_version_get_hw_timestamp() { | const uint32_t furi_hal_version_get_hw_timestamp() { | ||||||
|     return furi_hal_version.timestamp; |     return furi_hal_version.timestamp; | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,13 +10,6 @@ | |||||||
| #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | ||||||
| #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | ||||||
| 
 | 
 | ||||||
| /** OTP Versions enum */ |  | ||||||
| typedef enum { |  | ||||||
|     FuriHalVersionOtpVersion0=0x00, |  | ||||||
|     FuriHalVersionOtpVersion1=0x01, |  | ||||||
|     FuriHalVersionOtpVersionEmpty=0xFFFFFFFE, |  | ||||||
|     FuriHalVersionOtpVersionUnknown=0xFFFFFFFF, |  | ||||||
| } FuriHalVersionOtpVersion; |  | ||||||
| 
 | 
 | ||||||
| /** OTP V0 Structure: prototypes and early EVT */ | /** OTP V0 Structure: prototypes and early EVT */ | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -28,7 +21,7 @@ typedef struct { | |||||||
|     char name[FURI_HAL_VERSION_NAME_LENGTH]; |     char name[FURI_HAL_VERSION_NAME_LENGTH]; | ||||||
| } FuriHalVersionOTPv0; | } FuriHalVersionOTPv0; | ||||||
| 
 | 
 | ||||||
| /** OTP V1 Structure: late EVT, DVT, PVT, Production */ | /** OTP V1 Structure: late EVT, DVT */ | ||||||
| typedef struct { | typedef struct { | ||||||
|     /* First 64 bits: header */ |     /* First 64 bits: header */ | ||||||
|     uint16_t header_magic; |     uint16_t header_magic; | ||||||
| @ -49,10 +42,35 @@ typedef struct { | |||||||
|     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ |     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||||
| } FuriHalVersionOTPv1; | } FuriHalVersionOTPv1; | ||||||
| 
 | 
 | ||||||
|  | /** OTP V2 Structure: DVT2, PVT, Production */ | ||||||
|  | typedef struct { | ||||||
|  |     /* Early First 64 bits: header */ | ||||||
|  |     uint16_t header_magic; | ||||||
|  |     uint8_t header_version; | ||||||
|  |     uint8_t header_reserved; | ||||||
|  |     uint32_t header_timestamp; | ||||||
|  | 
 | ||||||
|  |     /* Early Second 64 bits: board info */ | ||||||
|  |     uint8_t board_version; /** Board version */ | ||||||
|  |     uint8_t board_target; /** Board target firmware */ | ||||||
|  |     uint8_t board_body; /** Board body */ | ||||||
|  |     uint8_t board_connect; /** Board interconnect */ | ||||||
|  |     uint8_t board_display; /** Board display */ | ||||||
|  |     uint8_t board_reserved2_0; /** Reserved for future use, 0x00 */ | ||||||
|  |     uint16_t board_reserved2_1; /** Reserved for future use, 0x0000 */ | ||||||
|  | 
 | ||||||
|  |     /* Late Third 64 bits: device info */ | ||||||
|  |     uint8_t board_color; /** Board color */ | ||||||
|  |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint16_t board_reserved3_0; /** Reserved for future use, 0x0000 */ | ||||||
|  |     uint32_t board_reserved3_1; /** Reserved for future use, 0x00000000 */ | ||||||
|  | 
 | ||||||
|  |     /* Late Fourth 64 bits: Unique Device Name */ | ||||||
|  |     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||||
|  | } FuriHalVersionOTPv2; | ||||||
|  | 
 | ||||||
| /** Represenation Model: */ | /** Represenation Model: */ | ||||||
| typedef struct { | typedef struct { | ||||||
|     FuriHalVersionOtpVersion otp_version; |  | ||||||
| 
 |  | ||||||
|     uint32_t timestamp; |     uint32_t timestamp; | ||||||
| 
 | 
 | ||||||
|     uint8_t board_version; /** Board version */ |     uint8_t board_version; /** Board version */ | ||||||
| @ -61,6 +79,7 @@ typedef struct { | |||||||
|     uint8_t board_connect; /** Board interconnect */ |     uint8_t board_connect; /** Board interconnect */ | ||||||
|     uint8_t board_color; /** Board color */ |     uint8_t board_color; /** Board color */ | ||||||
|     uint8_t board_region; /** Board region */ |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint8_t board_display; /** Board display */ | ||||||
| 
 | 
 | ||||||
|     char name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; /** \0 terminated name */ |     char name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; /** \0 terminated name */ | ||||||
|     char device_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH];  /** device name for special needs */ |     char device_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH];  /** device name for special needs */ | ||||||
| @ -69,20 +88,6 @@ typedef struct { | |||||||
| 
 | 
 | ||||||
| static FuriHalVersion furi_hal_version = {0}; | static FuriHalVersion furi_hal_version = {0}; | ||||||
| 
 | 
 | ||||||
| static FuriHalVersionOtpVersion furi_hal_version_get_otp_version() { |  | ||||||
|     if (*(uint64_t*)FURI_HAL_VERSION_OTP_ADDRESS == 0xFFFFFFFF) { |  | ||||||
|         return FuriHalVersionOtpVersionEmpty; |  | ||||||
|     } else { |  | ||||||
|         if (((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_magic == FURI_HAL_VERSION_OTP_HEADER_MAGIC) { |  | ||||||
|             return FuriHalVersionOtpVersion1; |  | ||||||
|         } else if (((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { |  | ||||||
|             return FuriHalVersionOtpVersion0; |  | ||||||
|         } else { |  | ||||||
|             return FuriHalVersionOtpVersionUnknown; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void furi_hal_version_set_name(const char* name) { | static void furi_hal_version_set_name(const char* name) { | ||||||
|     if(name != NULL) { |     if(name != NULL) { | ||||||
|         strlcpy(furi_hal_version.name, name, FURI_HAL_VERSION_ARRAY_NAME_LENGTH); |         strlcpy(furi_hal_version.name, name, FURI_HAL_VERSION_ARRAY_NAME_LENGTH); | ||||||
| @ -124,8 +129,6 @@ static void furi_hal_version_load_otp_v0() { | |||||||
|     furi_hal_version.board_target = otp->board_target; |     furi_hal_version.board_target = otp->board_target; | ||||||
|     furi_hal_version.board_body = otp->board_body; |     furi_hal_version.board_body = otp->board_body; | ||||||
|     furi_hal_version.board_connect = otp->board_connect; |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|     furi_hal_version.board_color = 0; |  | ||||||
|     furi_hal_version.board_region = 0; |  | ||||||
| 
 | 
 | ||||||
|     furi_hal_version_set_name(otp->name); |     furi_hal_version_set_name(otp->name); | ||||||
| } | } | ||||||
| @ -144,9 +147,33 @@ static void furi_hal_version_load_otp_v1() { | |||||||
|     furi_hal_version_set_name(otp->name); |     furi_hal_version_set_name(otp->name); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void furi_hal_version_load_otp_v2() { | ||||||
|  |     const FuriHalVersionOTPv2* otp = (FuriHalVersionOTPv2*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||||
|  | 
 | ||||||
|  |     // 1st block, programmed afer baking
 | ||||||
|  |     furi_hal_version.timestamp = otp->header_timestamp; | ||||||
|  | 
 | ||||||
|  |     // 2nd block, programmed afer baking
 | ||||||
|  |     furi_hal_version.board_version = otp->board_version; | ||||||
|  |     furi_hal_version.board_target = otp->board_target; | ||||||
|  |     furi_hal_version.board_body = otp->board_body; | ||||||
|  |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|  |     furi_hal_version.board_display = otp->board_display; | ||||||
|  | 
 | ||||||
|  |     // 3rd and 4th blocks, programmed on FATP stage
 | ||||||
|  |     if (otp->board_color != 0xFF) { | ||||||
|  |         furi_hal_version.board_color = otp->board_color; | ||||||
|  |         furi_hal_version.board_region = otp->board_region; | ||||||
|  |         furi_hal_version_set_name(otp->name); | ||||||
|  |     } else { | ||||||
|  |         furi_hal_version.board_color = 0; | ||||||
|  |         furi_hal_version.board_region = 0; | ||||||
|  |         furi_hal_version_set_name(NULL); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void furi_hal_version_init() { | void furi_hal_version_init() { | ||||||
|     furi_hal_version.otp_version = furi_hal_version_get_otp_version(); |     switch(furi_hal_version_get_otp_version()) { | ||||||
|     switch(furi_hal_version.otp_version) { |  | ||||||
|         case FuriHalVersionOtpVersionUnknown: |         case FuriHalVersionOtpVersionUnknown: | ||||||
|             furi_hal_version_load_otp_default(); |             furi_hal_version_load_otp_default(); | ||||||
|         break; |         break; | ||||||
| @ -159,6 +186,9 @@ void furi_hal_version_init() { | |||||||
|         case FuriHalVersionOtpVersion1: |         case FuriHalVersionOtpVersion1: | ||||||
|             furi_hal_version_load_otp_v1(); |             furi_hal_version_load_otp_v1(); | ||||||
|         break; |         break; | ||||||
|  |         case FuriHalVersionOtpVersion2: | ||||||
|  |             furi_hal_version_load_otp_v2(); | ||||||
|  |         break; | ||||||
|         default: furi_crash(NULL); |         default: furi_crash(NULL); | ||||||
|     } |     } | ||||||
|     FURI_LOG_I("FuriHalVersion", "Init OK"); |     FURI_LOG_I("FuriHalVersion", "Init OK"); | ||||||
| @ -172,6 +202,28 @@ const char* furi_hal_version_get_model_name() { | |||||||
|     return "Flipper Zero"; |     return "Flipper Zero"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const FuriHalVersionOtpVersion furi_hal_version_get_otp_version() { | ||||||
|  |     if (*(uint64_t*)FURI_HAL_VERSION_OTP_ADDRESS == 0xFFFFFFFF) { | ||||||
|  |         return FuriHalVersionOtpVersionEmpty; | ||||||
|  |     } else { | ||||||
|  |         if (((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_magic == FURI_HAL_VERSION_OTP_HEADER_MAGIC) { | ||||||
|  |             // Version 1+
 | ||||||
|  |             uint8_t version = ((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_version; | ||||||
|  |             if (version >= FuriHalVersionOtpVersion1 && version <= FuriHalVersionOtpVersion2) { | ||||||
|  |                 return version; | ||||||
|  |             } else { | ||||||
|  |                 return FuriHalVersionOtpVersionUnknown; | ||||||
|  |             } | ||||||
|  |         } else if (((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { | ||||||
|  |             // Version 0
 | ||||||
|  |             return FuriHalVersionOtpVersion0; | ||||||
|  |         } else { | ||||||
|  |             // Version Unknown
 | ||||||
|  |             return FuriHalVersionOtpVersionUnknown; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const uint8_t furi_hal_version_get_hw_version() { | const uint8_t furi_hal_version_get_hw_version() { | ||||||
|     return furi_hal_version.board_version; |     return furi_hal_version.board_version; | ||||||
| } | } | ||||||
| @ -196,6 +248,10 @@ const FuriHalVersionRegion furi_hal_version_get_hw_region() { | |||||||
|     return furi_hal_version.board_region; |     return furi_hal_version.board_region; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | const FuriHalVersionDisplay furi_hal_version_get_hw_display() { | ||||||
|  |     return furi_hal_version.board_display; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const uint32_t furi_hal_version_get_hw_timestamp() { | const uint32_t furi_hal_version_get_hw_timestamp() { | ||||||
|     return furi_hal_version.timestamp; |     return furi_hal_version.timestamp; | ||||||
| } | } | ||||||
|  | |||||||
| @ -19,6 +19,15 @@ extern "C" { | |||||||
| /** BLE symbol + "Flipper " + name */ | /** BLE symbol + "Flipper " + name */ | ||||||
| #define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + 8 + FURI_HAL_VERSION_ARRAY_NAME_LENGTH) | #define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + 8 + FURI_HAL_VERSION_ARRAY_NAME_LENGTH) | ||||||
| 
 | 
 | ||||||
|  | /** OTP Versions enum */ | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalVersionOtpVersion0=0x00, | ||||||
|  |     FuriHalVersionOtpVersion1=0x01, | ||||||
|  |     FuriHalVersionOtpVersion2=0x02, | ||||||
|  |     FuriHalVersionOtpVersionEmpty=0xFFFFFFFE, | ||||||
|  |     FuriHalVersionOtpVersionUnknown=0xFFFFFFFF, | ||||||
|  | } FuriHalVersionOtpVersion; | ||||||
|  | 
 | ||||||
| /** Device Colors */ | /** Device Colors */ | ||||||
| typedef enum { | typedef enum { | ||||||
|     FuriHalVersionColorUnknown=0x00, |     FuriHalVersionColorUnknown=0x00, | ||||||
| @ -34,6 +43,13 @@ typedef enum { | |||||||
|     FuriHalVersionRegionJp=0x03, |     FuriHalVersionRegionJp=0x03, | ||||||
| } FuriHalVersionRegion; | } FuriHalVersionRegion; | ||||||
| 
 | 
 | ||||||
|  | /** Device Display */ | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalVersionDisplayUnknown=0x00, | ||||||
|  |     FuriHalVersionDisplayErc=0x01, | ||||||
|  |     FuriHalVersionDisplayMgg=0x02, | ||||||
|  | } FuriHalVersionDisplay; | ||||||
|  | 
 | ||||||
| /** Init flipper version
 | /** Init flipper version
 | ||||||
|  */ |  */ | ||||||
| void furi_hal_version_init(); | void furi_hal_version_init(); | ||||||
| @ -50,6 +66,12 @@ bool furi_hal_version_do_i_belong_here(); | |||||||
|  */ |  */ | ||||||
| const char* furi_hal_version_get_model_name(); | const char* furi_hal_version_get_model_name(); | ||||||
| 
 | 
 | ||||||
|  | /** Get OTP version
 | ||||||
|  |  * | ||||||
|  |  * @return     OTP Version | ||||||
|  |  */ | ||||||
|  | const FuriHalVersionOtpVersion furi_hal_version_get_otp_version(); | ||||||
|  | 
 | ||||||
| /** Get hardware version
 | /** Get hardware version
 | ||||||
|  * |  * | ||||||
|  * @return     Hardware Version |  * @return     Hardware Version | ||||||
| @ -86,6 +108,12 @@ const uint8_t furi_hal_version_get_hw_connect(); | |||||||
|  */ |  */ | ||||||
| const FuriHalVersionRegion furi_hal_version_get_hw_region(); | const FuriHalVersionRegion furi_hal_version_get_hw_region(); | ||||||
| 
 | 
 | ||||||
|  | /** Get hardware display id
 | ||||||
|  |  * | ||||||
|  |  * @return     Display id | ||||||
|  |  */ | ||||||
|  | const FuriHalVersionDisplay furi_hal_version_get_hw_display(); | ||||||
|  | 
 | ||||||
| /** Get hardware timestamp
 | /** Get hardware timestamp
 | ||||||
|  * |  * | ||||||
|  * @return     Hardware Manufacture timestamp |  * @return     Hardware Manufacture timestamp | ||||||
|  | |||||||
							
								
								
									
										152
									
								
								scripts/otp.py
									
									
									
									
									
								
							
							
						
						
									
										152
									
								
								scripts/otp.py
									
									
									
									
									
								
							| @ -10,7 +10,7 @@ import struct | |||||||
| import datetime | import datetime | ||||||
| 
 | 
 | ||||||
| OTP_MAGIC = 0xBABE | OTP_MAGIC = 0xBABE | ||||||
| OTP_VERSION = 0x01 | OTP_VERSION = 0x02 | ||||||
| OTP_RESERVED = 0x00 | OTP_RESERVED = 0x00 | ||||||
| 
 | 
 | ||||||
| OTP_COLORS = { | OTP_COLORS = { | ||||||
| @ -18,6 +18,7 @@ OTP_COLORS = { | |||||||
|     "black": 0x01, |     "black": 0x01, | ||||||
|     "white": 0x02, |     "white": 0x02, | ||||||
| } | } | ||||||
|  | 
 | ||||||
| OTP_REGIONS = { | OTP_REGIONS = { | ||||||
|     "unknown": 0x00, |     "unknown": 0x00, | ||||||
|     "eu_ru": 0x01, |     "eu_ru": 0x01, | ||||||
| @ -25,7 +26,11 @@ OTP_REGIONS = { | |||||||
|     "jp": 0x03, |     "jp": 0x03, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| BOARD_RESERVED = 0x0000 | OTP_DISPLAYS = { | ||||||
|  |     "unknown": 0x00, | ||||||
|  |     "erc": 0x01, | ||||||
|  |     "mgg": 0x02, | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| class Main: | class Main: | ||||||
| @ -34,22 +39,36 @@ class Main: | |||||||
|         self.parser = argparse.ArgumentParser() |         self.parser = argparse.ArgumentParser() | ||||||
|         self.parser.add_argument("-d", "--debug", action="store_true", help="Debug") |         self.parser.add_argument("-d", "--debug", action="store_true", help="Debug") | ||||||
|         self.subparsers = self.parser.add_subparsers(help="sub-command help") |         self.subparsers = self.parser.add_subparsers(help="sub-command help") | ||||||
|         # Generate |         # Generate All | ||||||
|         self.parser_generate = self.subparsers.add_parser( |         self.parser_generate_all = self.subparsers.add_parser( | ||||||
|             "generate", help="Generate OTP binary" |             "generate", help="Generate OTP binary" | ||||||
|         ) |         ) | ||||||
|         self._add_args(self.parser_generate) |         self._add_first_args(self.parser_generate_all) | ||||||
|         self.parser_generate.add_argument("file", help="Output file") |         self._add_second_args(self.parser_generate_all) | ||||||
|         self.parser_generate.set_defaults(func=self.generate) |         self.parser_generate_all.add_argument("file", help="Output file") | ||||||
|         # Flash |         self.parser_generate_all.set_defaults(func=self.generate_all) | ||||||
|         self.parser_flash = self.subparsers.add_parser( |         # Flash First | ||||||
|             "flash", help="Flash OTP to device" |         self.parser_flash_first = self.subparsers.add_parser( | ||||||
|  |             "flash_first", help="Flash first block of OTP to device" | ||||||
|         ) |         ) | ||||||
|         self._add_args(self.parser_flash) |         self._add_swd_args(self.parser_flash_first) | ||||||
|         self.parser_flash.add_argument( |         self._add_first_args(self.parser_flash_first) | ||||||
|             "--port", type=str, help="Port to connect: swd or usb1", default="swd" |         self.parser_flash_first.set_defaults(func=self.flash_first) | ||||||
|  |         # Flash Second | ||||||
|  |         self.parser_flash_second = self.subparsers.add_parser( | ||||||
|  |             "flash_second", help="Flash second block of OTP to device" | ||||||
|         ) |         ) | ||||||
|         self.parser_flash.set_defaults(func=self.flash) |         self._add_swd_args(self.parser_flash_second) | ||||||
|  |         self._add_second_args(self.parser_flash_second) | ||||||
|  |         self.parser_flash_second.set_defaults(func=self.flash_second) | ||||||
|  |         # Flash All | ||||||
|  |         self.parser_flash_all = self.subparsers.add_parser( | ||||||
|  |             "flash_all", help="Flash OTP to device" | ||||||
|  |         ) | ||||||
|  |         self._add_swd_args(self.parser_flash_all) | ||||||
|  |         self._add_first_args(self.parser_flash_all) | ||||||
|  |         self._add_second_args(self.parser_flash_all) | ||||||
|  |         self.parser_flash_all.set_defaults(func=self.flash_all) | ||||||
|         # logging |         # logging | ||||||
|         self.logger = logging.getLogger() |         self.logger = logging.getLogger() | ||||||
|         self.timestamp = datetime.datetime.now().timestamp() |         self.timestamp = datetime.datetime.now().timestamp() | ||||||
| @ -69,16 +88,29 @@ class Main: | |||||||
|         # execute requested function |         # execute requested function | ||||||
|         self.args.func() |         self.args.func() | ||||||
| 
 | 
 | ||||||
|     def _add_args(self, parser): |     def _add_swd_args(self, parser): | ||||||
|         parser.add_argument("--version", type=int, help="Version", default=11) |         parser.add_argument( | ||||||
|         parser.add_argument("--firmware", type=int, help="Firmware", default=7) |             "--port", type=str, help="Port to connect: swd or usb1", default="swd" | ||||||
|         parser.add_argument("--body", type=int, help="Body", default=9) |         ) | ||||||
|         parser.add_argument("--connect", type=int, help="Connect", default=6) | 
 | ||||||
|         parser.add_argument("--color", type=str, help="Color", default="unknown") |     def _add_first_args(self, parser): | ||||||
|         parser.add_argument("--region", type=str, help="Region", default="unknown") |         parser.add_argument("--version", type=int, help="Version", required=True) | ||||||
|  |         parser.add_argument("--firmware", type=int, help="Firmware", required=True) | ||||||
|  |         parser.add_argument("--body", type=int, help="Body", required=True) | ||||||
|  |         parser.add_argument("--connect", type=int, help="Connect", required=True) | ||||||
|  |         parser.add_argument("--display", type=str, help="Display", required=True) | ||||||
|  | 
 | ||||||
|  |     def _add_second_args(self, parser): | ||||||
|  |         parser.add_argument("--color", type=str, help="Color", required=True) | ||||||
|  |         parser.add_argument("--region", type=str, help="Region", required=True) | ||||||
|         parser.add_argument("--name", type=str, help="Name", required=True) |         parser.add_argument("--name", type=str, help="Name", required=True) | ||||||
| 
 | 
 | ||||||
|     def _process_args(self): |     def _process_first_args(self): | ||||||
|  |         if self.args.display not in OTP_DISPLAYS: | ||||||
|  |             self.parser.error(f"Invalid display. Use one of {OTP_DISPLAYS.keys()}") | ||||||
|  |         self.args.display = OTP_DISPLAYS[self.args.display] | ||||||
|  | 
 | ||||||
|  |     def _process_second_args(self): | ||||||
|         if self.args.color not in OTP_COLORS: |         if self.args.color not in OTP_COLORS: | ||||||
|             self.parser.error(f"Invalid color. Use one of {OTP_COLORS.keys()}") |             self.parser.error(f"Invalid color. Use one of {OTP_COLORS.keys()}") | ||||||
|         self.args.color = OTP_COLORS[self.args.color] |         self.args.color = OTP_COLORS[self.args.color] | ||||||
| @ -94,9 +126,9 @@ class Main: | |||||||
|                 "Name contains incorrect symbols. Only a-zA-Z0-9 allowed." |                 "Name contains incorrect symbols. Only a-zA-Z0-9 allowed." | ||||||
|             ) |             ) | ||||||
| 
 | 
 | ||||||
|     def _pack_struct(self): |     def _pack_first(self): | ||||||
|         return struct.pack( |         return struct.pack( | ||||||
|             "<" "HBBL" "BBBBBBH" "8s", |             "<" "HBBL" "BBBBBBH", | ||||||
|             OTP_MAGIC, |             OTP_MAGIC, | ||||||
|             OTP_VERSION, |             OTP_VERSION, | ||||||
|             OTP_RESERVED, |             OTP_RESERVED, | ||||||
| @ -105,25 +137,74 @@ class Main: | |||||||
|             self.args.firmware, |             self.args.firmware, | ||||||
|             self.args.body, |             self.args.body, | ||||||
|             self.args.connect, |             self.args.connect, | ||||||
|  |             self.args.display, | ||||||
|  |             OTP_RESERVED, | ||||||
|  |             OTP_RESERVED, | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def _pack_second(self): | ||||||
|  |         return struct.pack( | ||||||
|  |             "<" "BBHL" "8s", | ||||||
|             self.args.color, |             self.args.color, | ||||||
|             self.args.region, |             self.args.region, | ||||||
|             BOARD_RESERVED, |             OTP_RESERVED, | ||||||
|  |             OTP_RESERVED, | ||||||
|             self.args.name.encode("ascii"), |             self.args.name.encode("ascii"), | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def generate(self): |     def generate_all(self): | ||||||
|         self.logger.debug(f"Generating OTP") |         self.logger.debug(f"Generating OTP") | ||||||
|         self._process_args() |         self._process_first_args() | ||||||
|         data = self._pack_struct() |         self._process_second_args() | ||||||
|         open(self.args.file, "wb").write(data) |         open(f"{self.args.file}_first.bin", "wb").write(self._pack_first()) | ||||||
|  |         open(f"{self.args.file}_second.bin", "wb").write(self._pack_second()) | ||||||
| 
 | 
 | ||||||
|     def flash(self): |     def flash_first(self): | ||||||
|  |         self.logger.debug(f"Flashing first block of OTP") | ||||||
|  | 
 | ||||||
|  |         self._process_first_args() | ||||||
|  | 
 | ||||||
|  |         filename = f"otp_unknown_first_{self.timestamp}.bin" | ||||||
|  |         file = open(filename, "wb") | ||||||
|  |         file.write(self._pack_first()) | ||||||
|  |         file.close() | ||||||
|  | 
 | ||||||
|  |         self._flash_bin("0x1FFF7000", filename) | ||||||
|  | 
 | ||||||
|  |         os.remove(filename) | ||||||
|  | 
 | ||||||
|  |     def flash_second(self): | ||||||
|  |         self.logger.debug(f"Flashing second block of OTP") | ||||||
|  | 
 | ||||||
|  |         self._process_second_args() | ||||||
|  | 
 | ||||||
|  |         filename = f"otp_{self.args.name}_second_{self.timestamp}.bin" | ||||||
|  |         file = open(filename, "wb") | ||||||
|  |         file.write(self._pack_second()) | ||||||
|  |         file.close() | ||||||
|  | 
 | ||||||
|  |         self._flash_bin("0x1FFF7010", filename) | ||||||
|  | 
 | ||||||
|  |         os.remove(filename) | ||||||
|  | 
 | ||||||
|  |     def flash_all(self): | ||||||
|         self.logger.debug(f"Flashing OTP") |         self.logger.debug(f"Flashing OTP") | ||||||
|         self._process_args() |  | ||||||
|         data = self._pack_struct() |  | ||||||
|         filename = f"otp_{self.args.name}_{self.timestamp}.bin" |  | ||||||
|         open(filename, "wb").write(data) |  | ||||||
| 
 | 
 | ||||||
|  |         self._process_first_args() | ||||||
|  |         self._process_second_args() | ||||||
|  | 
 | ||||||
|  |         filename = f"otp_{self.args.name}_whole_{self.timestamp}.bin" | ||||||
|  |         file = open(filename, "wb") | ||||||
|  |         file.write(self._pack_first()) | ||||||
|  |         file.write(self._pack_second()) | ||||||
|  |         file.close() | ||||||
|  | 
 | ||||||
|  |         self._flash_bin("0x1FFF7000", filename) | ||||||
|  | 
 | ||||||
|  |         os.remove(filename) | ||||||
|  | 
 | ||||||
|  |     def _flash_bin(self, address, filename): | ||||||
|  |         self.logger.debug(f"Programming {filename} at {address}") | ||||||
|         try: |         try: | ||||||
|             output = subprocess.check_output( |             output = subprocess.check_output( | ||||||
|                 [ |                 [ | ||||||
| @ -133,7 +214,7 @@ class Main: | |||||||
|                     f"port={self.args.port}", |                     f"port={self.args.port}", | ||||||
|                     "-d", |                     "-d", | ||||||
|                     filename, |                     filename, | ||||||
|                     "0x1FFF7000", |                     f"{address}", | ||||||
|                 ] |                 ] | ||||||
|             ) |             ) | ||||||
|             assert output |             assert output | ||||||
| @ -155,7 +236,6 @@ class Main: | |||||||
|                 f"port={self.args.port}", |                 f"port={self.args.port}", | ||||||
|             ] |             ] | ||||||
|         ) |         ) | ||||||
|         os.remove(filename) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく