[Feature]Upload Modem source code

Change-Id: Id4294f30faced84d3e6fd6d5e61e1111bf287a37
diff --git a/mcu/service/mertos/include/mer_kernel_scheduler.h b/mcu/service/mertos/include/mer_kernel_scheduler.h
new file mode 100644
index 0000000..8eca4e3
--- /dev/null
+++ b/mcu/service/mertos/include/mer_kernel_scheduler.h
@@ -0,0 +1,429 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2018
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+/*****************************************************************************
+*
+* Filename:
+* ---------
+*   mer_kernel_scheduler.h
+*
+* Project:
+* --------
+*   MERTOS
+*
+* Description:
+* ------------
+*   MERTOS scheduler header
+*
+* Author:
+* -------
+ * -------
+*
+*****************************************************************************/
+#ifndef _MER_KERNEL_SCHEDULER_H_
+#define _MER_KERNEL_SCHEDULER_H_
+#include "mer_kernel_config_public.h"
+
+#if defined(__MD97__) || defined(__MD97P__)
+
+#define MER_KERNEL_SCHEDULER_WAKE_UP_STATE  0x2
+#define MER_KERNEL_SCHEDULER_BUSY_STATE     0x0
+#define MER_KERNEL_SCHEDULER_IDLE_STATE     0x1
+
+#define MER_KERNEL_SCHEDULER_CORE0_MASK     0x7
+#define MER_KERNEL_SCHEDULER_CORE1_MASK     0x38
+
+#else
+    #error "unsupport platform"
+#endif /* __MD97__ || __MD97P__ */
+
+#define MER_KERNEL_SCHEDULER_JOB_INDEX_MASK       (0xFFFFFFF)
+#define MER_KERNEL_SCHEDULER_JOB_PRIORITY_MASK    (~(MER_KERNEL_SCHEDULER_JOB_INDEX_MASK))
+
+#define MER_KERNEL_SCHEDULER_LOCK_IS_RELEASED     (0x0)
+#define MER_KERNEL_SCHEDULER_LOCK_IS_NOT_RELEASED (0x1)
+
+//#define __MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__
+
+#ifndef MER_KERNEL_IS_ASSEMBLY
+    #error "please include public header"
+#endif /* MER_KERNEL_IS_ASSEMBLY */
+
+#if !MER_KERNEL_IS_ASSEMBLY
+
+#include "mer_service_types.h"
+#include "mer_kernel_utility_target.h"
+#include "mer_kernel.h"
+#include "mer_kernel_dpc.h"
+
+///////////////////////////////////////////////////////////////////////////////
+// Internal type
+///////////////////////////////////////////////////////////////////////////////
+typedef struct {
+    mer_uint32 priority;
+    mer_uint32 affinity_mask;
+    mer_uint32 job_index;
+    mer_uint32 self_adjust;
+} mer_kernel_scheduler_job;
+
+typedef void (*mer_kernel_scheduler_job_callback)(mer_uint32);
+//typedef void (*mer_kernel_scheduler_set_job_callback)(mer_uint32);
+
+typedef enum {
+    MER_KERNEL_SCHEDULER_INSERT_TO_HEAD = 0,
+    MER_KERNEL_SCHEDULER_INSERT_TO_TAIL = 2,
+    MER_KERNEL_SCHEDULER_INSERT_TO_HEAD_AND_RETURN = 0x10,
+    MER_KERNEL_SCHEDULER_INSERT_TO_TAIL_AND_RETURN = 0x12,
+} mer_kernel_scheduler_job_insert_type;
+
+typedef enum {
+    MER_KERNEL_SCHEDULER_CONTEXT_TASK = 1,
+    MER_KERNEL_SCHEDULER_CONTEXT_DPC = 2,
+    MER_KERNEL_SCHEDULER_CONTEXT_ISR = 3,
+    MER_KERNEL_SCHEDULER_CONTEXT_NONE = 4,
+} mer_kernel_scheduler_context_type;
+
+///////////////////////////////////////////////////////////////////////////////
+// External Variable
+///////////////////////////////////////////////////////////////////////////////
+extern mer_kernel_scheduler_job mer_kernel_scheduler_running_job[MIPS_HW_VPE_NUM];
+extern mer_kernel_scheduler_job mer_kernel_scheduler_ready_job[MIPS_HW_VPE_NUM];
+extern mer_kernel_scheduler_job_callback mer_kernel_scheduler_job_insert[];
+extern mer_uint32 mer_kernel_scheduler_idle_flag_mips[MIPS_HW_VPE_NUM];
+
+extern mer_uint32 mer_kernel_dpc_info_table_begin;
+extern mer_uint32 mer_kernel_dpc_info_table_end;
+extern mer_uint32 mer_kernel_task_info_table_begin;
+extern mer_uint32 mer_kernel_task_info_table_end;
+
+///////////////////////////////////////////////////////////////////////////////
+// External Function
+///////////////////////////////////////////////////////////////////////////////
+extern void mer_kernel_scheduler_reschedule_job();
+mer_uint32 mer_kernel_scheduler_insert_job(mer_uint32 new_job_priority, 
+                                    mer_uint32 new_job_affinity_mask, 
+                                    mer_uint32 new_job_index, 
+                                    mer_kernel_scheduler_job_insert_type new_job_insert_position);
+void mer_kernel_scheduler_switch_local_job(mer_uint32 current_vpe);
+void mer_kernel_scheduler_adjust_priority(mer_uint32 current_vpe);
+
+/* Low power */
+mer_uint32 mer_kernel_scheduler_remove_vpes_from_scheduling();
+void mer_kernel_scheduler_restore_current_vpe_to_scheduling(mer_uint32 core);
+void mer_kernel_scheduler_set_slave_vpe_idle_flag();
+void mer_kernel_scheduler_remove_slave_vpe_idle_flag();
+
+void mer_kernel_scheduler_initialization();
+
+mer_kernel_scheduler_context_type mer_kernel_scheduler_get_current_context_level();
+
+///////////////////////////////////////////////////////////////////////////////
+// Static Inline Function
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * Check whether the job priority of VPE is in ISR
+ * Time complexity O(1)
+ * 
+ * @param[out] 1 if in ISR, otherwise 0 if in DPC/Task
+ * @param[in] priority
+ * 
+ */
+static inline mer_uint32 mer_kernel_scheduler_is_in_isr(mer_uint32 priority){
+    
+    mer_uint32 non_isr_mask = 0xC0000000;
+    return ((priority & non_isr_mask) == 0);
+}
+
+/**
+ * Encode DI to current running priority
+ * Time complexity O(1)
+ * 
+ * @param[out] current_vpe
+ * @param[in] N/A
+ * 
+ */
+static inline void mer_kernel_scheduler_di(mer_uint32 current_vpe){
+
+#if defined(__MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__)  
+#error "should not compile"
+#if defined(__MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__)
+    if (MER_KERNEL_GET_INTERRUPT_COUNT()){
+#else
+    if (mer_kernel_interrupt_count[current_vpe]){
+#endif /* __MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__ */
+        return;
+    }
+    
+    mer_uint32 priority = mer_kernel_scheduler_running_job[current_vpe].priority;
+    mer_uint32 level_mask = ((priority & (~MER_KERNEL_SCHEDULER_JOB_INDEX_MASK)) >> 2);
+    mer_uint32 job_mask = (priority & MER_KERNEL_SCHEDULER_JOB_INDEX_MASK);
+    
+    mer_kernel_scheduler_running_job[current_vpe].priority =  level_mask | job_mask;
+    mer_kernel_utility_coherence_sync();
+    
+#endif /* __MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__ */
+}
+
+/**
+ * Encode EI to current running priority
+ * Time complexity O(1)
+ * 
+ * @param[out] N/A
+ * @param[in] current_vpe
+ * 
+ */
+static inline void mer_kernel_scheduler_ei(mer_uint32 current_vpe){
+    
+#if defined(__MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__)    
+#error "should not compile"
+#if defined(__MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__)
+    if (MER_KERNEL_GET_INTERRUPT_COUNT()){
+#else
+    if (mer_kernel_interrupt_count[current_vpe]){
+#endif /* __MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__ */
+    
+    mer_uint32 priority = mer_kernel_scheduler_running_job[current_vpe].priority;
+    mer_uint32 level_mask = ((priority & (~MER_KERNEL_SCHEDULER_JOB_INDEX_MASK)) << 2);
+    mer_uint32 job_mask = (priority & MER_KERNEL_SCHEDULER_JOB_INDEX_MASK);
+    
+    mer_kernel_scheduler_running_job[current_vpe].priority =  level_mask | job_mask;
+    mer_kernel_utility_coherence_sync();
+    
+#endif /* __MER_KERNEL_SCHEDULER_ENCODE_DI_PRIORITY__ */    
+
+}
+
+/**
+ * Set wake up status for child VPE (VPE1 in 93/95) before it reset
+ * Time complexity O(1)
+ * 
+ * @param[out] N/A
+ * @param[in] N/A
+ * 
+ */
+static inline void mer_kernel_scheduler_notify_child_vpe(){
+
+#if defined(__MD97__) || defined(__MD97P__)
+    mer_uint32 current_vpe = mer_kernel_utility_get_current_vpe_id();
+    mer_kernel_scheduler_idle_flag_mips[current_vpe+1] = MER_KERNEL_SCHEDULER_WAKE_UP_STATE;
+    mer_kernel_scheduler_idle_flag_mips[current_vpe+2] = MER_KERNEL_SCHEDULER_WAKE_UP_STATE;
+#else
+    #error "should porting to new platform"
+#endif     
+
+}
+
+/**
+ * check if current context level is in dpc or not
+ * Time complexity O(1)
+ * 
+ * @param[out] TRUE/FALSE 
+ * @param[in] N/A
+ * 
+ */
+__attribute__((always_inline)) static inline mer_uint32 mer_kernel_scheduler_is_in_dpc(){
+    
+#if defined(__MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__)
+#if 0
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+#else
+    /* Use the type in structure instead to have a better profiling result */
+    mer_uint32 control_block = MER_KERNEL_GET_CURRENT_CONTROL_BLOCK();
+    return ((MER_KERNEL_GET_INTERRUPT_COUNT() == 0) && \
+        (control_block) && \
+        (((mer_service_dpc_cb *)(control_block))->job_type == MER_SERVICE_TYPE_DPC));
+#endif
+#else
+    #error "should porting this part"
+#endif
+}
+
+/**
+ * check if current context level is in task or not
+ * Time complexity O(1)
+ * 
+ * @param[out] TRUE/FALSE 
+ * @param[in] N/A
+ * 
+ */
+__attribute__((always_inline)) static inline mer_uint32 mer_kernel_scheduler_is_in_task(){
+    
+#if defined(__MER_KERNEL_USE_MIPS_CP0_CONTEXT_REG__)
+#if 0
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+#else
+    /* Use the type in structure instead to have a better profiling result */
+    mer_uint32 control_block = MER_KERNEL_GET_CURRENT_CONTROL_BLOCK();
+    return ((MER_KERNEL_GET_INTERRUPT_COUNT() == 0) && \
+        (control_block) && \
+        (((mer_service_dpc_cb *)(control_block))->job_type == MER_SERVICE_TYPE_TASK));
+#endif
+
+#else
+    #error "should porting this part"
+#endif
+}
+
+/**
+ * atomic read
+ * 
+ * @param[out] value
+ * @param[in] address
+ * 
+ */
+static inline mer_uint32 mer_kernel_scheduler_atmoic_read(mer_uint32 *ptr){
+    
+    mer_uint32 ret_value = 0;
+    __asm__ __volatile__(
+        "ll      %0, 0(%1) \n"          \
+        :"=d"(ret_value)                \
+        :"d"(ptr)                       \
+        :"memory"                       \
+    ); 
+
+    return ret_value;
+}
+
+/**
+ * atomic write
+ * 
+ * @param[out] result 
+ * @param[in] address
+ * 
+ */
+static inline mer_uint32 mer_kernel_scheduler_atomic_write(mer_uint32 *ptr, mer_uint32 result){
+    
+    __asm__ __volatile__(
+        "sc      %0, 0(%1) \n"          \
+        :"=d"(result)                   \
+        :"d"(ptr), "0"(result)          \
+        :"memory"                       \
+    ); 
+
+    return result;
+}
+
+/**
+ * Wipe out the VPE running priority when entering ISR
+ * 
+ * Time complexity O(1)
+ * 
+ * @param[out]  N/A
+ * @param[in]   vpe_id, job_stack_pointer
+ * 
+ */
+__attribute__((always_inline)) static inline void mer_kernel_scheduler_enter_isr(mer_uint32 vpe_id, mer_uint32 job_stack_pointer)
+{
+    /*  Note that we do not take schedule lock here since we DO NOT allow ignore 
+        ISR priority. It means, when I am in ISR, NO other VPE will send OS 
+        interrupt to me even when I am a extremely short ISR from idle.
+        By doing so, we can make sure when sending an interrupt, the target 
+        should receive OS interrupt immediately (unless it disable interrupt)
+        This reduce the chance that multiple OS interrupt send to same VPE.
+    */
+    
+
+#if defined(__MER_KERNEL_DYNAMIC_BALANCE_JOB__)    
+    mer_uint32 *job_sp = (mer_uint32 *)(MER_KERNEL_GET_CURRENT_CONTROL_BLOCK());
+    *job_sp = job_stack_pointer;
+#else
+    mer_uint32 *job_sp = (mer_uint32 *)(MER_KERNEL_GET_CURRENT_CONTROL_BLOCK());
+    *job_sp = job_stack_pointer;
+#endif
+
+    mer_uint32 result;
+
+    do {
+        //mer_kernel_utility_coherence_sync();
+
+        mer_uint32 *ptr = &mer_kernel_scheduler_running_job[vpe_id].priority;
+
+        mer_uint32 ll_value = mer_kernel_scheduler_atmoic_read(ptr);
+        
+        mer_uint32 level_mask = ((ll_value & (~MER_KERNEL_SCHEDULER_JOB_INDEX_MASK)) >> 2);
+        mer_uint32 job_mask = (ll_value & MER_KERNEL_SCHEDULER_JOB_INDEX_MASK);
+        
+        result = mer_kernel_scheduler_atomic_write(ptr, (level_mask | job_mask));
+                    
+    }while(result == 0);
+
+    //mer_kernel_utility_coherence_sync();
+    
+}
+
+/**
+ * Recover out the VPE running priority when leaving ISR
+ * 
+ * Time complexity O(1)
+ * 
+ * @param[out]  N/A
+ * @param[in]   N/A
+ * 
+ */
+__attribute__((always_inline)) static inline mer_bool mer_kernel_scheduler_recover_job_info(mer_uint32 vpe_id){
+
+    mer_uint32 result, self_reorder, ready_job = mer_kernel_scheduler_ready_job[vpe_id].priority;
+    mer_uint32 *ptr = &mer_kernel_scheduler_running_job[vpe_id].priority;
+
+    do {
+        
+        mer_uint32 ll_value = mer_kernel_scheduler_atmoic_read(ptr);
+        
+        mer_uint32 level_mask = ((ll_value & (~MER_KERNEL_SCHEDULER_JOB_INDEX_MASK)) << 2);
+        mer_uint32 job_mask = (ll_value & MER_KERNEL_SCHEDULER_JOB_INDEX_MASK);
+        mer_uint32 origin_mask = (level_mask | job_mask);
+
+        self_reorder = (ready_job < origin_mask); 
+
+        result = mer_kernel_scheduler_atomic_write(ptr, origin_mask);
+
+    }while(result == 0);
+    
+    return self_reorder;
+
+}
+
+#endif /* !MER_IS_ASSEMBLY */
+
+#endif /* _MER_KERNEL_SCHEDULER_H_ */
+