/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*

                  ARM Memory Management Unit

GENERAL DESCRIPTION
        This module provides some methods for populating the mmu pagetable.

EXTERNALIZED FUNCTIONS

INITIALIZATION AND SEQUENCING REQUIREMENTS

Copyright (c) 2000 by QUALCOMM Incorporated. All Rights Reserved.
*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*/


/*===========================================================================

                           EDIT HISTORY FOR FILE
  This section contains comments describing changes made to the module.
  Notice that changes are listed in reverse chronological order.

  $log$

===========================================================================*/


/*===========================================================================

                     INCLUDE FILES FOR MODULE

===========================================================================*/
#include "customer.h"
#include "comdef.h"
#include "armmmu.h"
#include "boothw.h"
#ifdef VHDL_VERIFICATION
  #include "memory_map_small.h"
#else
  #include "memory_map_full.h"
#endif
/*
   traverses the page table and clears out any existing entries
   all table entries are mapped as invalid.
*/

#define LAST_64K_PAGE_INDEX (15)
#define ACCESS_PERMISSION_RW  (3)
#define ACCESS_PERMISSION_RO  (3)
#define DOMAIN0   (0)
#define DOMAIN1   (1)


extern byte* Image__SCATTER_U_RO_1_CODERO__Base;
extern byte* Image__SCATTER_U_RW_1_RW__Base;
extern byte* Image__SCATTER_U_RW_2_ZI__ZI__Base;       


/* page table size is 4096 */
extern unsigned long mmu_pagetable[MMU_PT_SIZE];
extern unsigned long mmu_pagetables2[256];
extern unsigned long mmu_pagetables3[256];

/*=============================================================================
Memory Map Structure
  The memory map structure is an array of mem blocks defined above.  It is used
  my the function create_pagetable to create the mmu pagetable.  By
  modifying the structure one can change the memory map of the mmu page table.
  Each entry represents a memory block and consists of a base address, size in
  megabytes, access type and domain permisions.

  By default bootstrap creates a pagetable using the flat memory map.  Meaning
  that anyone has has access to any memory block and that all access to these
  areas of memory are unbufferable and and uncacheable.  If the symbol
  MMU_CUST_MEM_MAP is defined the customized map will be used.
  Ideally memory access should be bufferable and cacheable and all IO
  operations should be be neither.
=============================================================================*/
#define MMU_LAST_ADDRESS 0xffffffff

const mem_block cust_mem_map[] =
{
  /* CHIP SELECTS 0-3 */
  {MSM6100_MEMORY_0_A_BASE,MSM6100_MEMORY_0_A_SIZE,MMU_PT_MEM_ACCESS,MMU_PT_DEF_DOMAIN},
  #if defined( BOOT_MODE_NOR) && !defined (SHADOW_MODE)
  {MSM6100_MEMORY_0_B_BASE,MSM6100_MEMORY_0_B_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},
  #else
  {MSM6100_MEMORY_0_B_BASE,MSM6100_MEMORY_0_B_SIZE,MMU_PT_MEM_ACCESS,MMU_PT_DEF_DOMAIN},
  #endif
  {MSM6100_MEMORY_0_C_BASE,MSM6100_MEMORY_0_C_SIZE,MMU_PT_MEM_ACCESS,MMU_PT_DEF_DOMAIN},
  {MSM6100_MEMORY_1_BASE,MSM6100_MEMORY_1_SIZE,MMU_PT_MEM_ACCESS,MMU_PT_DEF_DOMAIN},
  {MSM6100_MEMORY_2_BASE,MSM6100_MEMORY_2_SIZE,MMU_PT_MEM_ACCESS,MMU_PT_DEF_DOMAIN},
  {MSM6100_MEMORY_3_BASE,MSM6100_MEMORY_3_SIZE,MMU_PT_MEM_ACCESS,MMU_PT_DEF_DOMAIN},

  /* GP_0,GP_1 */
  {MSM6100_GP_0_BASE,MSM6100_GP_0_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},
  {MSM6100_GP_1_BASE,MSM6100_GP_1_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  /* LCD */
  {MSM6100_LCD_BASE,MSM6100_LCD_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  /* ROM2*/
  {MSM6100_ROM_2_BASE,MSM6100_ROM_2_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  /* RAM2*/
  {MSM6100_RAM_2_BASE,MSM6100_RAM_2_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  /* MDSP*/
  {MSM6100_MDSP_BASE,MSM6100_MDSP_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  /* ADSP*/
  {MSM6100_ADSP_BASE,MSM6100_ADSP_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  /* GPIO_2*/
  {MSM6100_GPIO_2_BASE,MSM6100_GPIO_2_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  /* FPB*/
  {MSM6100_FPB_BASE,MSM6100_FPB_SIZE,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  /* Reserved */
  {MSM6100_RESERVED_1_BASE ,MSM6100_RESERVED_1_SIZE ,MMU_PT_MEM_ACCESS,MMU_PT_DEF_DOMAIN},

  /* Reserved (EDRAM)*/
  {MSM6100_RESERVED_EDRAM_BASE ,MSM6100_RESERVED_EDRAM_SIZE ,MMU_PT_MEM_ACCESS,MMU_PT_DEF_DOMAIN},

  /* Reserved (IMEM)*/
  {MSM6100_RESERVED_IMEM_BASE ,MSM6100_RESERVED_IMEM_SIZE ,MMU_PT_MEM_ACCESS,MMU_PT_DEF_DOMAIN},

  /*MSM CORE*/
  {MSM6100_MODEM_BASE ,MSM6100_MODEM_SIZE ,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  /*MSM6100_BOOT_REGION*/
  {MSM6100_BOOT_REGION_BASE ,MSM6100_BOOT_REGION_SIZE ,MMU_PT_IO_ACCESS,MMU_PT_DEF_DOMAIN},

  { MMU_LAST_ADDRESS,0,0,0 }
};

/*=============================================================================
FUNCTION INVALIDATE_PAGETABLE

DESCRIPTION
  Zeros out all entries in the mmu page table.  Having an entry of type 0
  raises an exception.

DEPENDENCIES
  mmu_pagetable must be allocated

RETURN VALUE
  NONE

SIDE EFFECT
  All entries in the pagetable are invalidated.  If the mmu is enabled this
  will raise an section translation exception each time memory access is tried

=============================================================================*/
void invalidate_pagetable(void)
{
  int i;
  unsigned long *p = mmu_pagetable;
  for (i = 0; i < MMU_PT_SIZE; i++) {
    *p++ = 0;
  }

}

void map_block_as_protected_sections_and_pages( const mem_block * block )
{
   unsigned long i, mappedi;
   unsigned int limit;
   unsigned int orFactor = 0;
  
   unsigned long unprotectedBrewRO = (unsigned long)Image__SCATTER_U_RO_1_CODERO__Base;
   unsigned long unprotectedBrewRW = (unsigned long)Image__SCATTER_U_RW_1_RW__Base;
   unsigned long unprotectedBrewZI2 = (unsigned long)Image__SCATTER_U_RW_2_ZI__ZI__Base;
   unsigned long unprotectedBrewZI2End = (unsigned long) T_RAM_BASE + T_RAM_SIZE;
   unsigned long page2base  = (unsigned long) mmu_pagetables2;
   
   unsigned long temp =0;
   unsigned long k=0,j=0;
 
   unprotectedBrewRO >>= 20 ;//assuming 1 mb boundary
   unprotectedBrewRW >>= 20;//assuming 1 mb boundary
   unprotectedBrewZI2 >>= 20;//assuming 1 mb boundary
   unprotectedBrewZI2End >>= 20;

   /* Convert our base address into an index into the page table */
   i = block->base_address >> 20;
   /* only map size sections */
   limit = i + (block->size);

   for (; i < limit  ; i++)
   {
      /*
        ________________________________________________________________________
        |                                                                       |
        |31-------------20 |19--------12 |11--10 |8----5|4|3------2 |1-0        |
        | Phys Address base| Should be 0 |Access |DOMAIN|1|Cach/Buff|EntryType  |
        |_______________________________________________________________________|
        must write U_BIT, bit 4 as a 1 for backward compatability.
        as stated by ARM.
        Note* The access parameter contains an absolute value for bits
        [11-10] and bits [3-2]. No further shifting is required.
      */
      mappedi = i;
      if( (i>=unprotectedBrewZI2) && (i<unprotectedBrewZI2End) )//this is actually ZI section
      {
            mmu_pagetable[i] =     (MMU_PT_ALL_ACCESS) |MMU_PT_C |
            (DOMAIN0 << 5 )  |
            (mappedi << 20)       |
            MMU_PT_BIT_4        |
            MMU_PT_SECTION ;
      }
      else if(i == unprotectedBrewRW)
      {
         page2base  = (unsigned long) mmu_pagetables2;
         mmu_pagetable[i] =  page2base | 0x01 | (1<<5);

         for(j=0;j<=LAST_64K_PAGE_INDEX;j++)
         {
            temp = (mappedi << 20) + (j << 16);
            temp |= 0x01;
            
            if(j<LAST_64K_PAGE_INDEX)
               {
               temp |= (ACCESS_PERMISSION_RW << 4) |
                  (ACCESS_PERMISSION_RW << 6) | 
                  (ACCESS_PERMISSION_RW << 8) | 
                  (ACCESS_PERMISSION_RW << 10);
               }
            else
               {
               temp |= (ACCESS_PERMISSION_RO << 4) |
                  (ACCESS_PERMISSION_RO << 6) | 
                  (ACCESS_PERMISSION_RO << 8) | 
                  (ACCESS_PERMISSION_RO << 10);
               }

            temp |= MMU_PT_C;
            for(k=0;k<=15;k++)
            {
               mmu_pagetables2[(j << 4) + k] = temp; 
            }
         }


      }
      else if((i == unprotectedBrewRO)||(i== unprotectedBrewRO+1))//brew code, ap = 01
	   {
         mmu_pagetable[i] =     (MMU_PT_AP_NO_USR_W) | MMU_PT_C |
            (DOMAIN1 << 5 )  |
            (mappedi << 20)       |
            MMU_PT_BIT_4        |
            MMU_PT_SECTION ;
	   }
	   else
	   {
         if(block->access == MMU_PT_MEM_ACCESS)
            orFactor = MMU_PT_C;
         else
            orFactor = 0;
	    	mmu_pagetable[i] =     (MMU_PT_AP_SVC_RW) |orFactor |
            (DOMAIN1 << 5 )  |
            (mappedi << 20)       |
            MMU_PT_BIT_4        |
            MMU_PT_SECTION ;
	   } 
	   
	}
}


/*=============================================================================
FUNCTION MAP_BLOCK_AS_SECTIONS

DESCRIPTION
  Maps a block descriptor into the page table as sections

DEPENDENCIES
  mmu_pagetable must be allocated

RETURN VALUE
  NONE

SIDE EFFECT
  Existing entries in the pagetable will be replaced.
=============================================================================*/
void map_block_as_sections( const mem_block * block )
{
  unsigned int i;
  unsigned int limit;

  /* Convert our base address into an index into the page table */
  i = block->base_address >> 20;
  /* only map size sections */
  limit = i + (block->size);

  for (; i < limit  ; i++)
  {
/*
 ________________________________________________________________________
|                                                                       |
|31-------------20 |19--------12 |11--10 |8----5|4|3------2 |1-0        |
| Phys Address base| Should be 0 |Access |DOMAIN|1|Cach/Buff|EntryType  |
|_______________________________________________________________________|
  must write U_BIT, bit 4 as a 1 for backward compatability.
  as stated by ARM.
  Note* The access parameter contains an absolute value for bits
  [11-10] and bits [3-2]. No further shifting is required.
*/

    mmu_pagetable[i] =     (block->access ) |
                             (block->domain << 5 )  |
                             (i << 20)       |
                             MMU_PT_BIT_4        |
                             MMU_PT_SECTION ;
  }
}


/*=============================================================================
FUNCTION POPULATE_PAGETABLE

DESCRIPTION
  Populates a pagetable with the content of a memory map.

DEPENDENCIES
  The memory Map must contain all needed memory

RETURN VALUE
  NONE

SIDE EFFECT
  Existing entries in the pagetable will be replaced.
=============================================================================*/
void populate_pagetable( const mem_block  * map )
{
  while ( map->base_address != MMU_LAST_ADDRESS )
  {
    BOOTHW_KICK_WATCHDOG();
    map_block_as_protected_sections_and_pages(map++);
   // map_block_as_sections(map++);
  }
}


/*=============================================================================
FUNCTION create_pagetable

DESCRIPTION
  Populates a pagetable with the content of a memory map.

DEPENDENCIES
  The memory Map must contain all needed memory
  If MMU_CUST_MEM_MAP is defined then the custom memory map will be
  mapped instead of the flat memory map which gets mapped by default

RETURN VALUE
  NONE

SIDE EFFECT
  Existing entries in the pagetable will be replaced.
=============================================================================*/
void create_pagetable(void)
{
/* Remove the following line if the code is not used for VHDL verification */

#ifndef VHDL_VERIFICATION

   invalidate_pagetable();

#endif

   populate_pagetable((mem_block  * )cust_mem_map);

   BOOTHW_KICK_WATCHDOG();

}

