summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libcpu/powerpc/mpc8xx/mmu/mmu.c
blob: fbf2d2eeb0bb2fe3e3557d09fbc07b84fbc17f4f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
 * mmu.c
 *
 * This file contains routines for initializing
 * and manipulating the MMU on the MPC8xx.
 *
 * Copyright (c) 1999, National Research Council of Canada
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.com/license/LICENSE.
 */

#include <rtems.h>
#include <rtems/powerpc/powerpc.h>

#include <mpc8xx.h>
#include <mpc8xx/mmu.h>

/*
 * mmu_init
 *
 * This routine sets up the virtual memory maps on an MPC8xx.
 * The MPC8xx does not support block address translation (BATs)
 * and does not have segment registers. Thus, we must set up page
 * translation. However, its MMU supports variable size pages
 * (1-, 4-, 16-, 512-Kbyte or 8-Mbyte), which simplifies the task.
 *
 * The MPC8xx has separate data and instruction 32-entry translation
 * lookaside buffers (TLB). By mapping all of DRAM as one huge page,
 * we can preload the TLBs and not have to be concerned with taking
 * TLB miss exceptions.
 *
 * We set up the virtual memory map so that virtual address of a
 * location is equal to its real address.
 */
void mmu_init( void )
{
  register uint32_t   reg1, i;

  /*
   * Initialize the TLBs
   *
   * Instruction address translation and data address translation
   * must be disabled during initialization (IR=0, DR=0 in MSR).
   * We can assume the MSR has already been set this way.
   */

  /*
   * Initialize IMMU & DMMU Control Registers (MI_CTR & MD_CTR)
   * 	GPM [0]			0b0 = PowerPC mode
   *	PPM [1]			0b0 = Page resolution of protection
   *	CIDEF [2]		0b0/0b0 = Default cache-inhibit attribute =
   *							NO for IMMU, NO for DMMU
   *                            NOTE: it is vital that data caching is ON, when
   *                            DMMU is off, otherwise valid/dirty values in
   *                            cache would be ignored during exception entry
   *	reserved/WTDEF [3]	0b0 = Default write-through attribute = not
   *	RSV4x [4]		0b0 = 4 entries not reserved
   *	reserved/TWAM [5]	0b0/0b1 = 4-Kbyte page hardware assist
   *	PPCS [6]		0b0 = Ignore user/supervisor state
   *	reserved [7-18]		0x00
   *	xTLB_INDX [19-23]	31 = 0x1F
   *	reserved [24-31]	0x00
   *
   * Note: It is important that cache-inhibit be set as the default for the
   * data cache when the DMMU is disabled in order to prevent internal memory
   * mapped registers from being cached accidentally when address translation
   * is turned off at the start of exception processing.
   */
  reg1 = M8xx_MI_CTR_ITLB_INDX(31);
  _mtspr( M8xx_MI_CTR, reg1 );
  reg1 = M8xx_MD_CTR_TWAM | M8xx_MD_CTR_DTLB_INDX(31);
  _mtspr( M8xx_MD_CTR, reg1 );
  _isync;

  /*
   * Invalidate all TLB entries in both TLBs.
   * Note: We rely on the RSV4 bit in MI_CTR and MD_CTR being 0b0, so
   *       all 32 entries are invalidated.
   */
  __asm__ volatile ("tlbia\n"::);
  _isync;

  /*
   * Set Current Address Space ID Register (M_CASID).
   * Supervisor: CASID = 0
   */
  reg1 = 0;
  _mtspr( M8xx_M_CASID, reg1 );

  /*
   * Initialize the MMU Access Protection Registers (MI_AP, MD_AP)
   * We ignore the Access Protection Group (APG) mechanism globally
   * by setting all of the Mx_AP fields to 0b01 : client access
   * permission is defined by page protection bits.
   */
  reg1 = 0x55555555;
  _mtspr( M8xx_MI_AP, reg1 );
  _mtspr( M8xx_MD_AP, reg1 );

  /*
   * Load both 32-entry TLBs with values from the MMU_TLB_table
   * which is defined in the BSP.
   * Note the _TLB_Table must have at most 32 entries. This code
   * makes no effort to enforce this restriction.
   */
  for( i = 0; i < MMU_N_TLB_Table_Entries; ++i ) {
    reg1 = MMU_TLB_table[i].mmu_epn;
    _mtspr( M8xx_MI_EPN, reg1 );
    _mtspr( M8xx_MD_EPN, reg1 );
    reg1 = MMU_TLB_table[i].mmu_twc;
    _mtspr( M8xx_MI_TWC, reg1 );
    _mtspr( M8xx_MD_TWC, reg1 );
    reg1 = MMU_TLB_table[i].mmu_rpn;	/* RPN must be written last! */
    _mtspr( M8xx_MI_RPN, reg1 );
    _mtspr( M8xx_MD_RPN, reg1 );
  }

  /*
   * Turn on address translation by setting MSR[IR] and MSR[DR].
   */
  _CPU_MSR_GET( reg1 );
  reg1 |= PPC_MSR_IR | PPC_MSR_DR;
  _CPU_MSR_SET( reg1 );
}