leo hendrickson / Mbed OS example-Ethernet-mbed-Cloud-connect
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers arm_uc_pal_realtek_rtl8195am.c Source File

arm_uc_pal_realtek_rtl8195am.c

00001 // ----------------------------------------------------------------------------
00002 // Copyright 2016-2017 ARM Ltd.
00003 //
00004 // SPDX-License-Identifier: Apache-2.0
00005 //
00006 // Licensed under the Apache License, Version 2.0 (the "License");
00007 // you may not use this file except in compliance with the License.
00008 // You may obtain a copy of the License at
00009 //
00010 //     http://www.apache.org/licenses/LICENSE-2.0
00011 //
00012 // Unless required by applicable law or agreed to in writing, software
00013 // distributed under the License is distributed on an "AS IS" BASIS,
00014 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015 // See the License for the specific language governing permissions and
00016 // limitations under the License.
00017 // ----------------------------------------------------------------------------
00018 
00019 #include "arm_uc_config.h"
00020 #if defined(ARM_UC_FEATURE_PAL_RTL8195AM) && (ARM_UC_FEATURE_PAL_RTL8195AM == 1)
00021 #if defined(TARGET_REALTEK_RTL8195AM)
00022 
00023 #include "update-client-paal/arm_uc_paal_update_api.h"
00024 #include "update-client-pal-flashiap/arm_uc_pal_flashiap_platform.h"
00025 
00026 #include "update-client-metadata-header/arm_uc_metadata_header_v2.h"
00027 
00028 
00029 #include "ota_api.h"
00030 #include "flash_ext.h"
00031 
00032 #define HEADER_SIZE     (OTA_CRC32_OFS + 4)
00033 
00034 typedef enum {
00035     BASE_ADDRESS_RUNNING,
00036     BASE_ADDRESS_SPARE
00037 } base_address_t;
00038 
00039 typedef enum {
00040     BASE_SLOT_0 = 0,
00041     BASE_SLOT_1 = 1,
00042     BASE_SLOT_INVALID
00043 } base_slot_t;
00044 
00045 /**
00046  * Base slot, for caching between operations.
00047  */
00048 static base_slot_t arm_uc_base_slot = BASE_SLOT_INVALID;
00049 
00050 static const uint32_t arm_uc_address_header[2] = { OTA_REGION1_HEADER, OTA_REGION2_HEADER };
00051 static const uint32_t arm_uc_address_firmware[2] = { OTA_REGION1_BASE, OTA_REGION2_BASE };
00052 
00053 /**
00054  * Callback handler.
00055  */
00056 static void (*arm_uc_pal_rtl8195am_callback)(uint32_t) = NULL;
00057 
00058 /**
00059  * @brief      Signal external event handler with NULL pointer check.
00060  *
00061  * @param[in]  event  The event
00062  */
00063 static void arm_uc_pal_rtl8195am_signal_internal(uint32_t event)
00064 {
00065     if (arm_uc_pal_rtl8195am_callback) {
00066         arm_uc_pal_rtl8195am_callback(event);
00067     }
00068 }
00069 
00070 /**
00071  * @brief      Create header compatible with the RTL8195AM bootloader
00072  *
00073  * @param[in]  details  Update client firmware details struct.
00074  * @param      buffer   Scratch buffer for creating the header.
00075  *
00076  * @return     ERR_NONE on success. ERR_INVALID_PARAMETER on failure.
00077  */
00078 static arm_uc_error_t arm_uc_pal_create_realtek_header(const arm_uc_firmware_details_t *details,
00079                                                        arm_uc_buffer_t *buffer)
00080 {
00081     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00082 
00083     if (details && buffer && buffer->ptr && (buffer->size_max >= HEADER_SIZE)) {
00084         /* set tag */
00085         buffer->ptr[OTA_TAG_OFS    ] =  OTA_TAG_ID        & 0xFF;
00086         buffer->ptr[OTA_TAG_OFS + 1] = (OTA_TAG_ID >>  8) & 0xFF;
00087         buffer->ptr[OTA_TAG_OFS + 2] = (OTA_TAG_ID >> 16) & 0xFF;
00088         buffer->ptr[OTA_TAG_OFS + 3] = (OTA_TAG_ID >> 24) & 0xFF;
00089 
00090         /* set version tag */
00091         buffer->ptr[OTA_VER_OFS    ] =  OTA_VER_ID        & 0xFF;
00092         buffer->ptr[OTA_VER_OFS + 1] = (OTA_VER_ID >>  8) & 0xFF;
00093         buffer->ptr[OTA_VER_OFS + 2] = (OTA_VER_ID >> 16) & 0xFF;
00094         buffer->ptr[OTA_VER_OFS + 3] = (OTA_VER_ID >> 24) & 0xFF;
00095 
00096         /* set timestamp */
00097         buffer->ptr[OTA_EPOCH_OFS    ] =  details->version        & 0xFF;
00098         buffer->ptr[OTA_EPOCH_OFS + 1] = (details->version >>  8) & 0xFF;
00099         buffer->ptr[OTA_EPOCH_OFS + 2] = (details->version >> 16) & 0xFF;
00100         buffer->ptr[OTA_EPOCH_OFS + 3] = (details->version >> 24) & 0xFF;
00101         buffer->ptr[OTA_EPOCH_OFS + 4] = (details->version >> 32) & 0xFF;
00102         buffer->ptr[OTA_EPOCH_OFS + 5] = (details->version >> 40) & 0xFF;
00103         buffer->ptr[OTA_EPOCH_OFS + 6] = (details->version >> 48) & 0xFF;
00104         buffer->ptr[OTA_EPOCH_OFS + 7] = (details->version >> 56) & 0xFF;
00105 
00106         /* set size */
00107         uint32_t size_with_header = details->size + HEADER_SIZE;
00108 
00109         buffer->ptr[OTA_SIZE_OFS    ] =  size_with_header        & 0xFF;
00110         buffer->ptr[OTA_SIZE_OFS + 1] = (size_with_header >>  8) & 0xFF;
00111         buffer->ptr[OTA_SIZE_OFS + 2] = (size_with_header >> 16) & 0xFF;
00112         buffer->ptr[OTA_SIZE_OFS + 3] = (size_with_header >> 24) & 0xFF;
00113 
00114         /* copy hash */
00115         for (size_t index = 0; index < ARM_UC_SHA256_SIZE; index++) {
00116             buffer->ptr[OTA_HASH_OFS + index] = details->hash[index];
00117         }
00118 
00119         /* copy campaign */
00120         for (size_t index = 0; index < ARM_UC_GUID_SIZE; index++) {
00121             buffer->ptr[OTA_CAMPAIGN_OFS + index] = details->campaign[index];
00122         }
00123 
00124         /* set buffer size minus CRC */
00125         buffer->size = HEADER_SIZE - 4;
00126 
00127         result.code = ERR_NONE;
00128     }
00129 
00130     return result;
00131 }
00132 
00133 /**
00134  * @brief      Read header for the image located at the base address.
00135  *
00136  * @param[in]  base_slot     Header slot.
00137  * @param      details       Update client details struct.
00138  *
00139  * @return     ERR_NONE on success, ERR_INVALID_PARAMETER on failure.
00140  */
00141 static arm_uc_error_t arm_uc_pal_get_realtek_header(base_slot_t base_slot,
00142                                                     arm_uc_firmware_details_t *details)
00143 {
00144     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00145 
00146     if ((base_slot != BASE_SLOT_INVALID) && details) {
00147         uint8_t buffer[HEADER_SIZE] = { 0 };
00148 
00149         int rc = arm_uc_flashiap_read(buffer, arm_uc_address_header[base_slot], sizeof(buffer));
00150 
00151         if (rc == 0) {
00152 #if 0
00153             printf("debug: \r\n");
00154             for (size_t index = 0; index < sizeof(buffer); index++) {
00155                 printf("%02X", buffer[index]);
00156             }
00157             printf("\r\n");
00158 #endif
00159 
00160             /* parse tag */
00161             uint32_t tag = buffer[OTA_TAG_OFS + 3];
00162             tag = (tag << 8) | buffer[OTA_TAG_OFS + 2];
00163             tag = (tag << 8) | buffer[OTA_TAG_OFS + 1];
00164             tag = (tag << 8) | buffer[OTA_TAG_OFS + 0];
00165 
00166             /* parse version tag */
00167             uint32_t version_tag = buffer[OTA_VER_OFS + 3];
00168             version_tag = (version_tag << 8) | buffer[OTA_VER_OFS + 2];
00169             version_tag = (version_tag << 8) | buffer[OTA_VER_OFS + 1];
00170             version_tag = (version_tag << 8) | buffer[OTA_VER_OFS + 0];
00171 
00172             UC_PAAL_TRACE("tag: %" PRIX32, tag);
00173             UC_PAAL_TRACE("version_tag: %" PRIX32, version_tag);
00174 
00175             /* check tags */
00176             if ((tag == OTA_TAG_ID) && (version_tag == OTA_VER_ID)) {
00177                 /* parse CRC */
00178                 uint32_t crc_header = buffer[OTA_CRC32_OFS + 3];
00179                 crc_header = (crc_header << 8) | buffer[OTA_CRC32_OFS + 2];
00180                 crc_header = (crc_header << 8) | buffer[OTA_CRC32_OFS + 1];
00181                 crc_header = (crc_header << 8) | buffer[OTA_CRC32_OFS + 0];
00182 
00183                 /* calculate crc */
00184                 uint32_t crc_calculated = arm_uc_crc32(buffer, OTA_CRC32_OFS);
00185 
00186                 UC_PAAL_TRACE("CRC header:     %" PRIX32, crc_header);
00187                 UC_PAAL_TRACE("CRC calculated: %" PRIX32, crc_calculated);
00188 
00189                 /* check crc before proceeding */
00190                 if (crc_header == crc_calculated) {
00191                     /* parse size */
00192                     uint32_t size = buffer[OTA_SIZE_OFS + 3];
00193                     size = (size << 8) | buffer[OTA_SIZE_OFS + 2];
00194                     size = (size << 8) | buffer[OTA_SIZE_OFS + 1];
00195                     size = (size << 8) | buffer[OTA_SIZE_OFS + 0];
00196 
00197                     /* parse version */
00198                     uint64_t version = buffer[OTA_EPOCH_OFS + 7];
00199                     version = (version << 8) | buffer[OTA_EPOCH_OFS + 6];
00200                     version = (version << 8) | buffer[OTA_EPOCH_OFS + 5];
00201                     version = (version << 8) | buffer[OTA_EPOCH_OFS + 4];
00202                     version = (version << 8) | buffer[OTA_EPOCH_OFS + 3];
00203                     version = (version << 8) | buffer[OTA_EPOCH_OFS + 2];
00204                     version = (version << 8) | buffer[OTA_EPOCH_OFS + 1];
00205                     version = (version << 8) | buffer[OTA_EPOCH_OFS + 0];
00206 
00207                     /* copy hash */
00208                     for (size_t index = 0; index < ARM_UC_SHA256_SIZE; index++) {
00209                         details->hash[index] = buffer[OTA_HASH_OFS + index];
00210                     }
00211 
00212                     details->size = size - HEADER_SIZE;
00213                     details->version = version;
00214 
00215                     UC_PAAL_TRACE("size: %" PRIu64, details->size);
00216                     UC_PAAL_TRACE("version: %" PRIu64, details->version);
00217 
00218 #if 0
00219                     printf("hash: ");
00220                     for (size_t index = 0; index < ARM_UC_SHA256_SIZE; index++) {
00221                         printf("%02X", details->hash[index]);
00222                     }
00223                     printf("\r\n");
00224 #endif
00225 
00226                     result.code = ERR_NONE;
00227                 } else {
00228                     UC_PAAL_ERR_MSG("header crc check failed");
00229                 }
00230             } else {
00231                 UC_PAAL_ERR_MSG("invalid header");
00232             }
00233         } else {
00234             UC_PAAL_ERR_MSG("error reading from flash");
00235         }
00236     }
00237 
00238     return result;
00239 }
00240 
00241 /**
00242  * @brief      Find base address of either running or spare firmare slot.
00243  *
00244  * @param[in]  find  Enum specifying what to find (running or spare slot).
00245  *
00246  * @return     Base slot.
00247  */
00248 static base_slot_t arm_uc_pal_find_base_slot(base_address_t find)
00249 {
00250     base_slot_t base_slot = BASE_SLOT_0;
00251 
00252     arm_uc_firmware_details_t slot_0 = { 0 };
00253     arm_uc_firmware_details_t slot_1 = { 0 };
00254 
00255     /* read header from both slots */
00256     arm_uc_error_t result_0 = arm_uc_pal_get_realtek_header(BASE_SLOT_0, &slot_0);
00257     arm_uc_error_t result_1 = arm_uc_pal_get_realtek_header(BASE_SLOT_1, &slot_1);
00258 
00259     /* both headers are valid */
00260     if ((result_0.error == ERR_NONE) && (result_1.error == ERR_NONE)) {
00261         /* running firmware has the highest version number */
00262         if (find == BASE_ADDRESS_RUNNING) {
00263             base_slot = (slot_0.version >= slot_1.version) ? BASE_SLOT_0 : BASE_SLOT_1;
00264         }
00265         /* spare firmware has the lowest version number */
00266         else {
00267             /* same test, swap result */
00268             base_slot = (slot_0.version >= slot_1.version) ? BASE_SLOT_1 : BASE_SLOT_0;
00269         }
00270     }
00271     /* only slot0 has a valid header */
00272     else if (result_0.error == ERR_NONE) {
00273         if (find == BASE_ADDRESS_RUNNING) {
00274             /* only valid header must be the running one */
00275             base_slot = BASE_SLOT_0;
00276         } else {
00277             /* slot with invalid header can be used as spare */
00278             base_slot = BASE_SLOT_1;
00279         }
00280     }
00281     /* only slot1 has a valid header */
00282     else if (result_1.error == ERR_NONE) {
00283         if (find == BASE_ADDRESS_RUNNING) {
00284             /* only valid header must be the running one */
00285             base_slot = BASE_SLOT_1;
00286         } else {
00287             /* slot with invalid header can be used as spare */
00288             base_slot = BASE_SLOT_0;
00289         }
00290     }
00291 
00292     /* if both headers are invalid return 0 */
00293 
00294     return base_slot;
00295 }
00296 
00297 /*****************************************************************************/
00298 
00299 arm_uc_error_t ARM_UC_PAL_RTL8195AM_Initialize(void (*callback)(uint32_t))
00300 {
00301     arm_uc_error_t result = { .code = ERR_NONE };
00302 
00303     arm_uc_flashiap_init();
00304     arm_uc_pal_rtl8195am_callback = callback;
00305 
00306     return result;
00307 }
00308 
00309 /**
00310  * @brief Get maximum number of supported storage locations.
00311  *
00312  * @return Number of storage locations.
00313  */
00314 uint32_t ARM_UC_PAL_RTL8195AM_GetMaxID(void)
00315 {
00316     return 2;
00317 }
00318 
00319 /**
00320  * @brief Prepare the storage layer for a new firmware image.
00321  * @details The storage location is set up to receive an image with
00322  *          the details passed in the details struct.
00323  *
00324  * @param location Storage location ID.
00325  * @param details Pointer to a struct with firmware details.
00326  * @param buffer Temporary buffer for formatting and storing metadata.
00327  * @return Returns ERR_NONE on accept, and signals the event handler with
00328  *         either DONE or ERROR when complete.
00329  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00330  */
00331 arm_uc_error_t ARM_UC_PAL_RTL8195AM_Prepare(uint32_t location,
00332                                             const arm_uc_firmware_details_t *details,
00333                                             arm_uc_buffer_t *buffer)
00334 {
00335     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00336 
00337     if (details && buffer && buffer->ptr) {
00338         UC_PAAL_TRACE("Prepare: %" PRIX32 " %" PRIX64 " %" PRIu64,
00339                       location,
00340                       details->size,
00341                       details->version);
00342 
00343         /* find location for the spare slot */
00344         arm_uc_base_slot = arm_uc_pal_find_base_slot(BASE_ADDRESS_SPARE);
00345 
00346         UC_PAAL_TRACE("spare base slot: %d", arm_uc_base_slot);
00347 
00348         /* check that the firmware can fit the spare slot */
00349         if (((arm_uc_base_slot == BASE_SLOT_0) &&
00350                 (details->size < (OTA_REGION1_SIZE - FLASH_SECTOR_SIZE))) ||
00351                 ((arm_uc_base_slot == BASE_SLOT_1) &&
00352                  (details->size < (OTA_REGION2_SIZE - FLASH_SECTOR_SIZE)))) {
00353             /* encode firmware details in buffer */
00354             result  = arm_uc_pal_create_realtek_header(details, buffer);
00355 
00356             /* make space for new firmware */
00357             if (result.error == ERR_NONE) {
00358                 /* erase header */
00359                 uint32_t erase_address = arm_uc_address_header[arm_uc_base_slot];
00360                 uint32_t end_address = erase_address + HEADER_SIZE;
00361 
00362                 /* erase */
00363                 while (erase_address < end_address) {
00364                     uint32_t sector_size = arm_uc_flashiap_get_sector_size(erase_address);
00365                     int status = arm_uc_flashiap_erase(erase_address, sector_size);
00366 
00367                     UC_PAAL_TRACE("erase: %" PRIX32 " %" PRIX32 " %d",
00368                                   erase_address,
00369                                   sector_size,
00370                                   status);
00371 
00372                     if (status == 0) {
00373                         erase_address += sector_size;
00374                     } else {
00375                         result.code = ERR_INVALID_PARAMETER;
00376                         break;
00377                     }
00378                 }
00379 
00380                 /* erase firmware */
00381                 if (result.error == ERR_NONE) {
00382                     /* find end address */
00383                     erase_address = arm_uc_address_firmware[arm_uc_base_slot];
00384                     end_address = erase_address + details->size;
00385 
00386                     /* erase */
00387                     while (erase_address < end_address) {
00388                         uint32_t sector_size = arm_uc_flashiap_get_sector_size(erase_address);
00389                         int status = arm_uc_flashiap_erase(erase_address, sector_size);
00390 
00391                         UC_PAAL_TRACE("erase: %" PRIX32 " %" PRIX32 " %d",
00392                                       erase_address,
00393                                       sector_size,
00394                                       status);
00395 
00396                         if (status == 0) {
00397                             erase_address += sector_size;
00398                         } else {
00399                             result.code = ERR_INVALID_PARAMETER;
00400                             break;
00401                         }
00402                     }
00403 
00404                     /* write header */
00405                     if (result.error == ERR_NONE) {
00406                         UC_PAAL_TRACE("program: %u %" PRIu32,
00407                                       arm_uc_address_header[arm_uc_base_slot],
00408                                       buffer->size);
00409 
00410                         /* set default return code */
00411                         result.code = ERR_NONE;
00412 
00413                         /* write header without CRC */
00414                         int status = arm_uc_flashiap_program(buffer->ptr,
00415                                                              arm_uc_address_header[arm_uc_base_slot],
00416                                                              buffer->size);
00417 
00418                         if (status != 0) {
00419                             /* set return code */
00420                             result.code = ERR_INVALID_PARAMETER;
00421                         }
00422 
00423                         if (result.error == ERR_NONE) {
00424                             /* signal done */
00425                             arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_PREPARE_DONE);
00426                         } else {
00427                             UC_PAAL_ERR_MSG("flash program failed");
00428                         }
00429                     } else {
00430                         UC_PAAL_ERR_MSG("flash erase failed");
00431                     }
00432                 } else {
00433                     UC_PAAL_ERR_MSG("erase header failed");
00434                 }
00435             } else {
00436                 UC_PAAL_ERR_MSG("create header failed");
00437             }
00438         } else {
00439             UC_PAAL_ERR_MSG("firmware larger than slot");
00440             result.code = PAAL_ERR_FIRMWARE_TOO_LARGE;
00441         }
00442     }
00443 
00444     return result;
00445 }
00446 
00447 /**
00448  * @brief Write a fragment to the indicated storage location.
00449  * @details The storage location must have been allocated using the Prepare
00450  *          call. The call is expected to write the entire fragment before
00451  *          signaling completion.
00452  *
00453  * @param location Storage location ID.
00454  * @param offset Offset in bytes to where the fragment should be written.
00455  * @param buffer Pointer to buffer struct with fragment.
00456  * @return Returns ERR_NONE on accept, and signals the event handler with
00457  *         either DONE or ERROR when complete.
00458  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00459  */
00460 arm_uc_error_t ARM_UC_PAL_RTL8195AM_Write(uint32_t location,
00461                                           uint32_t offset,
00462                                           const arm_uc_buffer_t *buffer)
00463 {
00464     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00465 
00466     if (buffer && buffer->ptr && (arm_uc_base_slot != BASE_SLOT_INVALID)) {
00467         /* find location address */
00468         uint32_t physical_address = arm_uc_address_firmware[arm_uc_base_slot] + offset;
00469 
00470         UC_PAAL_TRACE("Write: %p %" PRIX32 " %" PRIX32 " %" PRIX32,
00471                       buffer->ptr,
00472                       buffer->size,
00473                       offset,
00474                       physical_address);
00475 
00476         /* set default return code */
00477         result.code = ERR_NONE;
00478 
00479         for (size_t index = 0; index < buffer->size;) {
00480             /* write aligned */
00481             size_t modulo = (physical_address + index) % FLASH_PAGE_SIZE;
00482             size_t remaining = buffer->size - index;
00483             size_t write_size = 0;
00484 
00485             /* fill remaining flash page */
00486             if (modulo > 0) {
00487                 write_size = modulo;
00488             }
00489             /* write last page */
00490             else if (remaining < FLASH_PAGE_SIZE) {
00491                 write_size = remaining;
00492             }
00493             /* write full page */
00494             else {
00495                 write_size = FLASH_PAGE_SIZE;
00496             }
00497 
00498             int status = arm_uc_flashiap_program(&buffer->ptr[index],
00499                                                  physical_address + index,
00500                                                  write_size);
00501 
00502             if (status != 0) {
00503                 /* set return code */
00504                 result.code = ERR_INVALID_PARAMETER;
00505                 break;
00506             }
00507 
00508             index += write_size;
00509         }
00510 
00511         if (result.error == ERR_NONE) {
00512             /* signal done */
00513             arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_WRITE_DONE);
00514         } else {
00515             UC_PAAL_ERR_MSG("flash program failed");
00516         }
00517     }
00518 
00519     return result;
00520 }
00521 
00522 /**
00523  * @brief Close storage location for writing and flush pending data.
00524  *
00525  * @param location Storage location ID.
00526  * @return Returns ERR_NONE on accept, and signals the event handler with
00527  *         either DONE or ERROR when complete.
00528  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00529  */
00530 arm_uc_error_t ARM_UC_PAL_RTL8195AM_Finalize(uint32_t location)
00531 {
00532     arm_uc_error_t result = { .code = ERR_NONE };
00533 
00534     UC_PAAL_TRACE("Finalize");
00535 
00536     arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_FINALIZE_DONE);
00537 
00538     return result;
00539 }
00540 
00541 /**
00542  * @brief Read a fragment from the indicated storage location.
00543  * @details The function will read until the buffer is full or the end of
00544  *          the storage location has been reached. The actual amount of
00545  *          bytes read is set in the buffer struct.
00546  *
00547  * @param location Storage location ID.
00548  * @param offset Offset in bytes to read from.
00549  * @param buffer Pointer to buffer struct to store fragment. buffer->size
00550  *        contains the intended read size.
00551  * @return Returns ERR_NONE on accept, and signals the event handler with
00552  *         either DONE or ERROR when complete.
00553  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00554  *         buffer->size contains actual bytes read on return.
00555  */
00556 arm_uc_error_t ARM_UC_PAL_RTL8195AM_Read(uint32_t location,
00557                                          uint32_t offset,
00558                                          arm_uc_buffer_t *buffer)
00559 {
00560     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00561 
00562     if (buffer && buffer->ptr) {
00563         /* find the base address for the spare slot if not already set */
00564         if (arm_uc_base_slot == BASE_SLOT_INVALID) {
00565             arm_uc_base_slot = arm_uc_pal_find_base_slot(BASE_ADDRESS_SPARE);
00566         }
00567 
00568         /* calculate actual physical address */
00569         uint32_t physical_address = arm_uc_address_firmware[arm_uc_base_slot] + offset;
00570 
00571         UC_PAAL_TRACE("Read: %" PRIX32 " %" PRIX32 " %" PRIX32,
00572                       physical_address,
00573                       offset,
00574                       buffer->size);
00575 
00576         uint32_t read_size = buffer->size;
00577 
00578         int status = arm_uc_flashiap_read(buffer->ptr, physical_address, read_size);
00579 
00580         if (status == 0) {
00581             /* set buffer size */
00582             buffer->size = read_size;
00583 
00584             /* set return code */
00585             result.code = ERR_NONE;
00586 
00587             /* signal done */
00588             arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_READ_DONE);
00589         } else {
00590             UC_PAAL_ERR_MSG("flash read failed");
00591         }
00592     }
00593 
00594     return result;
00595 }
00596 
00597 /**
00598  * @brief Set the firmware image in the slot to be the new active image.
00599  * @details This call is responsible for initiating the process for
00600  *          applying a new/different image. Depending on the platform this
00601  *          could be:
00602  *           * An empty call, if the installer can deduce which slot to
00603  *             choose from based on the firmware details.
00604  *           * Setting a flag to indicate which slot to use next.
00605  *           * Decompressing/decrypting/installing the firmware image on
00606  *             top of another.
00607  *
00608  * @param location Storage location ID.
00609  * @return Returns ERR_NONE on accept, and signals the event handler with
00610  *         either DONE or ERROR when complete.
00611  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00612  */
00613 arm_uc_error_t ARM_UC_PAL_RTL8195AM_Activate(uint32_t location)
00614 {
00615     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00616 
00617     UC_PAAL_TRACE("Activate");
00618 
00619     if (arm_uc_base_slot != BASE_SLOT_INVALID) {
00620         uint8_t buffer[HEADER_SIZE] = { 0 };
00621 
00622         int status = arm_uc_flashiap_read(buffer, arm_uc_address_header[arm_uc_base_slot], sizeof(buffer));
00623 
00624         if (status == 0) {
00625             /* calculate CRC */
00626             uint32_t crc = arm_uc_crc32(buffer, OTA_CRC32_OFS);
00627 
00628             buffer[0] =  crc        & 0xFF;
00629             buffer[1] = (crc >>  8) & 0xFF;
00630             buffer[2] = (crc >> 16) & 0xFF;
00631             buffer[3] = (crc >> 24) & 0xFF;
00632 
00633             /* set crc in header to signal the bootloader that the image is ready */
00634             status = arm_uc_flashiap_program(buffer, arm_uc_address_header[arm_uc_base_slot] + OTA_CRC32_OFS, 4);
00635 
00636             if (status == 0) {
00637                 /* set return code */
00638                 result.code = ERR_NONE;
00639 
00640                 /* signal done */
00641                 arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_ACTIVATE_DONE);
00642             }
00643         }
00644     }
00645 
00646     return result;
00647 }
00648 
00649 /**
00650  * @brief Get firmware details for the firmware image in the slot passed.
00651  * @details This call populates the passed details struct with information
00652  *          about the firmware image in the slot passed. Only the fields
00653  *          marked as supported in the capabilities bitmap will have valid
00654  *          values.
00655  *
00656  * @param details Pointer to firmware details struct to be populated.
00657  * @return Returns ERR_NONE on accept, and signals the event handler with
00658  *         either DONE or ERROR when complete.
00659  *         Returns ERR_INVALID_PARAMETER on reject, and no signal is sent.
00660  */
00661 arm_uc_error_t ARM_UC_PAL_RTL8195AM_GetFirmwareDetails(
00662     uint32_t location,
00663     arm_uc_firmware_details_t *details)
00664 {
00665     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00666 
00667     /* this function is only used by the mbed Bootloader */
00668 
00669     return result;
00670 }
00671 
00672 /*****************************************************************************/
00673 
00674 arm_uc_error_t ARM_UC_PAL_RTL8195AM_GetActiveDetails(arm_uc_firmware_details_t *details)
00675 {
00676     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00677 
00678     if (details) {
00679         UC_PAAL_TRACE("GetActiveDetails");
00680 
00681         /* find running slot */
00682         base_slot_t base_slot = arm_uc_pal_find_base_slot(BASE_ADDRESS_RUNNING);
00683 
00684         UC_PAAL_TRACE("active base: %d", base_slot);
00685 
00686         result = arm_uc_pal_get_realtek_header(base_slot, details);
00687 
00688         /* signal event if operation was successful */
00689         if (result.error == ERR_NONE) {
00690             arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_GET_ACTIVE_FIRMWARE_DETAILS_DONE);
00691         }
00692     }
00693 
00694     return result;
00695 }
00696 
00697 arm_uc_error_t ARM_UC_PAL_RTL8195AM_GetInstallerDetails(arm_uc_installer_details_t *details)
00698 {
00699     arm_uc_error_t result = { .code = ERR_INVALID_PARAMETER };
00700 
00701     if (details) {
00702         /* reset installer details struct */
00703         memset(&details->arm_hash, 0, ARM_UC_SHA256_SIZE);
00704         memset(&details->oem_hash, 0, ARM_UC_SHA256_SIZE);
00705         details->layout = 0;
00706 
00707         /* the magic tag identifies the bootloader it is compatible with */
00708         details->oem_hash[0] = (OTA_TAG_ID >> 24) & 0xFF;
00709         details->oem_hash[1] = (OTA_TAG_ID >> 16) & 0xFF;
00710         details->oem_hash[2] = (OTA_TAG_ID >>  8) & 0xFF;
00711         details->oem_hash[3] =  OTA_TAG_ID        & 0xFF;
00712 
00713         details->oem_hash[4] = (OTA_VER_ID >> 24) & 0xFF;
00714         details->oem_hash[5] = (OTA_VER_ID >> 16) & 0xFF;
00715         details->oem_hash[6] = (OTA_VER_ID >>  8) & 0xFF;
00716         details->oem_hash[7] =  OTA_VER_ID        & 0xFF;
00717 
00718         result.code = ERR_NONE;
00719 
00720         arm_uc_pal_rtl8195am_signal_internal(ARM_UC_PAAL_EVENT_GET_INSTALLER_DETAILS_DONE);
00721     }
00722 
00723     return result;
00724 }
00725 
00726 ARM_UC_PAAL_UPDATE_CAPABILITIES ARM_UC_PAL_RTL8195AM_GetCapabilities(void)
00727 {
00728     ARM_UC_PAAL_UPDATE_CAPABILITIES result = {
00729         .installer_arm_hash = 0,
00730         .installer_oem_hash = 0,
00731         .installer_layout   = 0,
00732         .firmware_hash      = 1,
00733         .firmware_hmac      = 0,
00734         .firmware_campaign  = 0,
00735         .firmware_version   = 1,
00736         .firmware_size      = 1
00737     };
00738 
00739     return result;
00740 }
00741 
00742 const ARM_UC_PAAL_UPDATE ARM_UCP_REALTEK_RTL8195AM = {
00743     .Initialize                 = ARM_UC_PAL_RTL8195AM_Initialize,
00744     .GetCapabilities            = ARM_UC_PAL_RTL8195AM_GetCapabilities,
00745     .GetMaxID                   = ARM_UC_PAL_RTL8195AM_GetMaxID,
00746     .Prepare                    = ARM_UC_PAL_RTL8195AM_Prepare,
00747     .Write                      = ARM_UC_PAL_RTL8195AM_Write,
00748     .Finalize                   = ARM_UC_PAL_RTL8195AM_Finalize,
00749     .Read                       = ARM_UC_PAL_RTL8195AM_Read,
00750     .Activate                   = ARM_UC_PAL_RTL8195AM_Activate,
00751     .GetActiveFirmwareDetails   = ARM_UC_PAL_RTL8195AM_GetActiveDetails,
00752     .GetFirmwareDetails         = ARM_UC_PAL_RTL8195AM_GetFirmwareDetails,
00753     .GetInstallerDetails        = ARM_UC_PAL_RTL8195AM_GetInstallerDetails
00754 };
00755 
00756 #endif
00757 #endif /* ARM_UC_FEATURE_PAL_RTL8195AM */