/**HEADER********************************************************************
* 
* Copyright (c) 2012 Freescale Semiconductor;
* All Rights Reserved
*
*************************************************************************** 
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR 
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: bsp_util.c$
* $Version : 1.0.0.0$
* $Date    : Feb-7-2012$
*
* Comments:
*
*   This file contains bsp utility functions.
*
*END************************************************************************/

#include <mqx.h>
#include <bsp.h>
#include <mqx_inc.h>
#include "lwmem.h"
#include "lwmemprv.h"
#include <mem_prv.h>
#include <mqx_prv.h>



/*!
 * @brief Calls ROM for services
 *
 *  This function enables the ROM functions described in the hardware manual to be called from
 *  user code. The function locates the address of the ROM code handler by reading the value from
 *  the ROM exception table, and then jumps to it. When the ROM code handler completes it will
 *  return directly to the user code that called this trap.
 *  
 *  @param func_id  -   (in) Specifies which ROM functions to execute.
 *  
 *  @param *addr    -   (in) Address of parameter block used for ROM function.
 *  
 *  @return Data block from the ROM function that was called.
 */

__declspec(register_abi) asm void* asm_rom_handler(    
    rmf_func_t          func_id,    /**< Specifies which of the ROM functions to execute         */
    void               *addr)       /**< Address of the parameter block used for the ROM function*/
{
    move.w  #0x2700, sr                     // Raise priority level to prevent re-entrancy

    move.l  #(0x300000 + INT_OFFSET_Vtrap0), a1 // Get the address of the ROM trap handler
    move.l  (a1), a1                        // and jump to it
    jmp     (a1)
}



__declspec(register_abi) uint_32 device_info_get(
    uint_32         length,      //!< - maximum number of bytes to copy to the destination
    uint_16         *id_ptr)     //!< - address of the device_info_t structure
{

    // The ROM device info contains the following types of information:
    //
    // typedef struct {
    //  uint_32              device_id;   /**< ROM: Pseudo random part identification value           */
    //  uint_16              rom_version; /**< ROM: ROM version code: major.minor                     */
    //  uint_16              fw_version;  /**< FW:  Firmware version code: major.minor                */
    //  uint_16              hw_version;  /**< ROM: Hardware version code: major.minor                */
    //  uint_16              build_code;  /**< FW:  Firmware build number and date code. The value is
    //                                    *        encoded in the following bit fields:
    //                                    *        - [15:12] daily build number, 0 to 15
    //                                    *        - [11: 8] build month, 1 to 12
    //                                    *        - [ 7: 3] build day, 1 to 31
    //                                    *        - [ 2: 0] build year, 2010 to 2017                */
    //  uint_16              part_number; /**< FW:  BCD encoded part number, e.g. 0x500x              */
    //  uint_8               reset_cause; /**< FW:  Lower 5 bits from the RCSR reports reset source   */
    //  uint_8               secure_mode; /**< FW:  Lower 2 bits of FOPT report the security mode of
    //                                    *        the device: 2 = secure, otherwise not secure      */
    //} device_info_t;
  
    uint_16 *rom_id_code_ptr;
    uint_8  *src_ptr;
    uint_8  *dst_ptr;
    int_32  ctr;

    // Read device info from the ROM
    src_ptr = (uint_8*)fxlc9500x_rom_command(RMF_DEV_INFO, (void*)0);
    
    // Skip first 6 bytes as they contain chip specific data.  
    // First 4 byte is device ID, next 2 byte is ROM version.
    rom_id_code_ptr = (uint_16*)&(src_ptr[6]);

    // Replace / add the firmware and build values
#if 0
    *(rom_id_code_ptr++) = FW_VERSION; // rom_id_code[3]
#else
    // This is firmware version, 16bit. Caller can insert its own
    // firmware version.
    rom_id_code_ptr++;
#endif
    
    // Hardware version
    rom_id_code_ptr++;
    
#if 0
    *(rom_id_code_ptr++) = ((BUILD_NUMBER << 12) & 0x7000) |// rom_id_code[5]
                           ((BUILD_MONTH  <<  8) & 0x0F00) |
                           ((BUILD_DAY    <<  3) & 0x00F8) |
                           ((BUILD_YEAR - 2010)  & 0x0007);
#else
    // This is reserved/unused 16bit location.  Caller can insert build
    // time stamp here.
    rom_id_code_ptr++;    
#endif
    
#if 0
    *(rom_id_code_ptr++) = PART_NUMBER; // rom_id_code[6]
#else
    // This is part number, 16bit location.  Caller can insert its own
    // part number if desired.
    rom_id_code_ptr++;        
#endif
    
    // Save the reset cause.
    *(rom_id_code_ptr++) = (uint_16)(((RCSR & 0x1F) << 8) | (FOPT & 3)); // rom_id_code[7]

    // Limit the number of bytes to copy to the length of the id code structure
    if (length > ROM_DEVICE_INFO_MAX_BYTES)
        length = ROM_DEVICE_INFO_MAX_BYTES;
    

    // Copy values into the user supplied RAM
    dst_ptr = (uint_8*)id_ptr;
    ctr     = (int_32)length;
    while (--ctr >= 0)
        *(dst_ptr++) = *(src_ptr++); // copy modified ROM device info

    return length;
}



uint_32 get_kernel_free_mem
   (
      void
   )
{ /* Body */

   uint_32                    size = 0;

#if MQX_USE_LWMEM_ALLOCATOR
   KERNEL_DATA_STRUCT_PTR       kernel_data;
   LWMEM_BLOCK_STRUCT_PTR       block_ptr;
   LWMEM_POOL_STRUCT_PTR        pool_ptr;

   _GET_KERNEL_DATA(kernel_data);

   /* initialize the memory alloc_info_struct */
   pool_ptr = kernel_data->KERNEL_LWMEM_POOL;
   block_ptr = pool_ptr->POOL_FREE_LIST_PTR;

   while (block_ptr != NULL) {      
      size += block_ptr->BLOCKSIZE;
      block_ptr = block_ptr->U.NEXTBLOCK;
   } /* Endwhile */
#if MQX_ENABLE_USER_MODE // User mode applies only to ARM. hht
   pool_ptr = kernel_data->KD_USER_POOL;
   block_ptr = pool_ptr->POOL_FREE_LIST_PTR;

   while (block_ptr != NULL) {      
      size += block_ptr->BLOCKSIZE;
      block_ptr = block_ptr->U.NEXTBLOCK;
   } /* Endwhile */
#endif


#else
   KERNEL_DATA_STRUCT_PTR kernel_data;
   STOREBLOCK_STRUCT_PTR  block_ptr;
   MEMPOOL_STRUCT_PTR     mem_pool_ptr;

   _GET_KERNEL_DATA(kernel_data);
   mem_pool_ptr = &kernel_data->KD_POOL;

   block_ptr = mem_pool_ptr->POOL_FREE_LIST_PTR;
   
   while ( block_ptr ) {      
      size += block_ptr->BLOCKSIZE;
      block_ptr = (STOREBLOCK_STRUCT_PTR)NEXT_FREE(block_ptr);
   } /* Endwhile */
#endif

   return size;
} /* Endbody */


