| /* |
| L2CR functions |
| Copyright © 1997-1998 by PowerLogix R & D, Inc. |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| */ |
| /* |
| Thur, Dec. 12, 1998. |
| - First public release, contributed by PowerLogix. |
| *********** |
| Sat, Aug. 7, 1999. |
| - Terry: Made sure code disabled interrupts before running. (Previously |
| it was assumed interrupts were already disabled). |
| - Terry: Updated for tentative G4 support. 4MB of memory is now flushed |
| instead of 2MB. (Prob. only 3 is necessary). |
| - Terry: Updated for workaround to HID0[DPM] processor bug |
| during global invalidates. |
| *********** |
| Thu, July 13, 2000. |
| - Terry: Added isync to correct for an errata. |
| |
| 22 August 2001. |
| - DanM: Finally added the 7450 patch I've had for the past |
| several months. The L2CR is similar, but I'm going |
| to assume the user of this functions knows what they |
| are doing. |
| |
| Author: Terry Greeniaus (tgree@phys.ualberta.ca) |
| Please e-mail updates to this file to me, thanks! |
| */ |
| #include <linux/config.h> |
| #include <asm/processor.h> |
| #include <asm/cputable.h> |
| #include <asm/ppc_asm.h> |
| #include <asm/cache.h> |
| #include <asm/page.h> |
| |
| /* Usage: |
| |
| When setting the L2CR register, you must do a few special |
| things. If you are enabling the cache, you must perform a |
| global invalidate. If you are disabling the cache, you must |
| flush the cache contents first. This routine takes care of |
| doing these things. When first enabling the cache, make sure |
| you pass in the L2CR you want, as well as passing in the |
| global invalidate bit set. A global invalidate will only be |
| performed if the L2I bit is set in applyThis. When enabling |
| the cache, you should also set the L2E bit in applyThis. If |
| you want to modify the L2CR contents after the cache has been |
| enabled, the recommended procedure is to first call |
| __setL2CR(0) to disable the cache and then call it again with |
| the new values for L2CR. Examples: |
| |
| _setL2CR(0) - disables the cache |
| _setL2CR(0xB3A04000) - enables my G3 upgrade card: |
| - L2E set to turn on the cache |
| - L2SIZ set to 1MB |
| - L2CLK set to 1:1 |
| - L2RAM set to pipelined synchronous late-write |
| - L2I set to perform a global invalidation |
| - L2OH set to 0.5 nS |
| - L2DF set because this upgrade card |
| requires it |
| |
| A similar call should work for your card. You need to know |
| the correct setting for your card and then place them in the |
| fields I have outlined above. Other fields support optional |
| features, such as L2DO which caches only data, or L2TS which |
| causes cache pushes from the L1 cache to go to the L2 cache |
| instead of to main memory. |
| |
| IMPORTANT: |
| Starting with the 7450, the bits in this register have moved |
| or behave differently. The Enable, Parity Enable, Size, |
| and L2 Invalidate are the only bits that have not moved. |
| The size is read-only for these processors with internal L2 |
| cache, and the invalidate is a control as well as status. |
| -- Dan |
| |
| */ |
| /* |
| * Summary: this procedure ignores the L2I bit in the value passed in, |
| * flushes the cache if it was already enabled, always invalidates the |
| * cache, then enables the cache if the L2E bit is set in the value |
| * passed in. |
| * -- paulus. |
| */ |
| _GLOBAL(_set_L2CR) |
| /* Make sure this is a 750 or 7400 chip */ |
| BEGIN_FTR_SECTION |
| li r3,-1 |
| blr |
| END_FTR_SECTION_IFCLR(CPU_FTR_L2CR) |
| |
| mflr r9 |
| |
| /* Stop DST streams */ |
| BEGIN_FTR_SECTION |
| DSSALL |
| sync |
| END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
| |
| /* Turn off interrupts and data relocation. */ |
| mfmsr r7 /* Save MSR in r7 */ |
| rlwinm r4,r7,0,17,15 |
| rlwinm r4,r4,0,28,26 /* Turn off DR bit */ |
| sync |
| mtmsr r4 |
| isync |
| |
| /* Before we perform the global invalidation, we must disable dynamic |
| * power management via HID0[DPM] to work around a processor bug where |
| * DPM can possibly interfere with the state machine in the processor |
| * that invalidates the L2 cache tags. |
| */ |
| mfspr r8,SPRN_HID0 /* Save HID0 in r8 */ |
| rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */ |
| sync |
| mtspr SPRN_HID0,r4 /* Disable DPM */ |
| sync |
| |
| /* Get the current enable bit of the L2CR into r4 */ |
| mfspr r4,SPRN_L2CR |
| |
| /* Tweak some bits */ |
| rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */ |
| rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */ |
| rlwinm r3,r3,0,1,31 /* Turn off the enable bit */ |
| |
| /* Check to see if we need to flush */ |
| rlwinm. r4,r4,0,0,0 |
| beq 2f |
| |
| /* Flush the cache. First, read the first 4MB of memory (physical) to |
| * put new data in the cache. (Actually we only need |
| * the size of the L2 cache plus the size of the L1 cache, but 4MB will |
| * cover everything just to be safe). |
| */ |
| |
| /**** Might be a good idea to set L2DO here - to prevent instructions |
| from getting into the cache. But since we invalidate |
| the next time we enable the cache it doesn't really matter. |
| Don't do this unless you accomodate all processor variations. |
| The bit moved on the 7450..... |
| ****/ |
| |
| /* TODO: use HW flush assist when available */ |
| |
| lis r4,0x0002 |
| mtctr r4 |
| li r4,0 |
| 1: |
| lwzx r0,r0,r4 |
| addi r4,r4,32 /* Go to start of next cache line */ |
| bdnz 1b |
| isync |
| |
| /* Now, flush the first 4MB of memory */ |
| lis r4,0x0002 |
| mtctr r4 |
| li r4,0 |
| sync |
| 1: |
| dcbf 0,r4 |
| addi r4,r4,32 /* Go to start of next cache line */ |
| bdnz 1b |
| |
| 2: |
| /* Set up the L2CR configuration bits (and switch L2 off) */ |
| /* CPU errata: Make sure the mtspr below is already in the |
| * L1 icache |
| */ |
| b 20f |
| .balign L1_CACHE_LINE_SIZE |
| 22: |
| sync |
| mtspr SPRN_L2CR,r3 |
| sync |
| b 23f |
| 20: |
| b 21f |
| 21: sync |
| isync |
| b 22b |
| |
| 23: |
| /* Perform a global invalidation */ |
| oris r3,r3,0x0020 |
| sync |
| mtspr SPRN_L2CR,r3 |
| sync |
| isync /* For errata */ |
| |
| BEGIN_FTR_SECTION |
| /* On the 7450, we wait for the L2I bit to clear...... |
| */ |
| 10: mfspr r3,SPRN_L2CR |
| andis. r4,r3,0x0020 |
| bne 10b |
| b 11f |
| END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450) |
| |
| /* Wait for the invalidation to complete */ |
| 3: mfspr r3,SPRN_L2CR |
| rlwinm. r4,r3,0,31,31 |
| bne 3b |
| |
| 11: rlwinm r3,r3,0,11,9 /* Turn off the L2I bit */ |
| sync |
| mtspr SPRN_L2CR,r3 |
| sync |
| |
| /* See if we need to enable the cache */ |
| cmplwi r5,0 |
| beq 4f |
| |
| /* Enable the cache */ |
| oris r3,r3,0x8000 |
| mtspr SPRN_L2CR,r3 |
| sync |
| |
| 4: |
| |
| /* Restore HID0[DPM] to whatever it was before */ |
| sync |
| mtspr 1008,r8 |
| sync |
| |
| /* Restore MSR (restores EE and DR bits to original state) */ |
| SYNC |
| mtmsr r7 |
| isync |
| |
| mtlr r9 |
| blr |
| |
| _GLOBAL(_get_L2CR) |
| /* Return the L2CR contents */ |
| li r3,0 |
| BEGIN_FTR_SECTION |
| mfspr r3,SPRN_L2CR |
| END_FTR_SECTION_IFSET(CPU_FTR_L2CR) |
| blr |
| |
| |
| /* |
| * Here is a similar routine for dealing with the L3 cache |
| * on the 745x family of chips |
| */ |
| |
| _GLOBAL(_set_L3CR) |
| /* Make sure this is a 745x chip */ |
| BEGIN_FTR_SECTION |
| li r3,-1 |
| blr |
| END_FTR_SECTION_IFCLR(CPU_FTR_L3CR) |
| |
| /* Turn off interrupts and data relocation. */ |
| mfmsr r7 /* Save MSR in r7 */ |
| rlwinm r4,r7,0,17,15 |
| rlwinm r4,r4,0,28,26 /* Turn off DR bit */ |
| sync |
| mtmsr r4 |
| isync |
| |
| /* Stop DST streams */ |
| DSSALL |
| sync |
| |
| /* Get the current enable bit of the L3CR into r4 */ |
| mfspr r4,SPRN_L3CR |
| |
| /* Tweak some bits */ |
| rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */ |
| rlwinm r3,r3,0,22,20 /* Turn off the invalidate bit */ |
| rlwinm r3,r3,0,2,31 /* Turn off the enable & PE bits */ |
| rlwinm r3,r3,0,5,3 /* Turn off the clken bit */ |
| /* Check to see if we need to flush */ |
| rlwinm. r4,r4,0,0,0 |
| beq 2f |
| |
| /* Flush the cache. |
| */ |
| |
| /* TODO: use HW flush assist */ |
| |
| lis r4,0x0008 |
| mtctr r4 |
| li r4,0 |
| 1: |
| lwzx r0,r0,r4 |
| dcbf 0,r4 |
| addi r4,r4,32 /* Go to start of next cache line */ |
| bdnz 1b |
| |
| 2: |
| /* Set up the L3CR configuration bits (and switch L3 off) */ |
| sync |
| mtspr SPRN_L3CR,r3 |
| sync |
| |
| oris r3,r3,L3CR_L3RES@h /* Set reserved bit 5 */ |
| mtspr SPRN_L3CR,r3 |
| sync |
| oris r3,r3,L3CR_L3CLKEN@h /* Set clken */ |
| mtspr SPRN_L3CR,r3 |
| sync |
| |
| /* Wait for stabilize */ |
| li r0,256 |
| mtctr r0 |
| 1: bdnz 1b |
| |
| /* Perform a global invalidation */ |
| ori r3,r3,0x0400 |
| sync |
| mtspr SPRN_L3CR,r3 |
| sync |
| isync |
| |
| /* We wait for the L3I bit to clear...... */ |
| 10: mfspr r3,SPRN_L3CR |
| andi. r4,r3,0x0400 |
| bne 10b |
| |
| /* Clear CLKEN */ |
| rlwinm r3,r3,0,5,3 /* Turn off the clken bit */ |
| mtspr SPRN_L3CR,r3 |
| sync |
| |
| /* Wait for stabilize */ |
| li r0,256 |
| mtctr r0 |
| 1: bdnz 1b |
| |
| /* See if we need to enable the cache */ |
| cmplwi r5,0 |
| beq 4f |
| |
| /* Enable the cache */ |
| oris r3,r3,(L3CR_L3E | L3CR_L3CLKEN)@h |
| mtspr SPRN_L3CR,r3 |
| sync |
| |
| /* Wait for stabilize */ |
| li r0,256 |
| mtctr r0 |
| 1: bdnz 1b |
| |
| /* Restore MSR (restores EE and DR bits to original state) */ |
| 4: SYNC |
| mtmsr r7 |
| isync |
| blr |
| |
| _GLOBAL(_get_L3CR) |
| /* Return the L3CR contents */ |
| li r3,0 |
| BEGIN_FTR_SECTION |
| mfspr r3,SPRN_L3CR |
| END_FTR_SECTION_IFSET(CPU_FTR_L3CR) |
| blr |
| |
| /* --- End of PowerLogix code --- |
| */ |
| |
| |
| /* flush_disable_L1() - Flush and disable L1 cache |
| * |
| * clobbers r0, r3, ctr, cr0 |
| * Must be called with interrupts disabled and MMU enabled. |
| */ |
| _GLOBAL(__flush_disable_L1) |
| /* Stop pending alitvec streams and memory accesses */ |
| BEGIN_FTR_SECTION |
| DSSALL |
| END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
| sync |
| |
| /* Load counter to 0x4000 cache lines (512k) and |
| * load cache with datas |
| */ |
| li r3,0x4000 /* 512kB / 32B */ |
| mtctr r3 |
| lis r3,KERNELBASE@h |
| 1: |
| lwz r0,0(r3) |
| addi r3,r3,0x0020 /* Go to start of next cache line */ |
| bdnz 1b |
| isync |
| sync |
| |
| /* Now flush those cache lines */ |
| li r3,0x4000 /* 512kB / 32B */ |
| mtctr r3 |
| lis r3,KERNELBASE@h |
| 1: |
| dcbf 0,r3 |
| addi r3,r3,0x0020 /* Go to start of next cache line */ |
| bdnz 1b |
| sync |
| |
| /* We can now disable the L1 cache (HID0:DCE, HID0:ICE) */ |
| mfspr r3,SPRN_HID0 |
| rlwinm r3,r3,0,18,15 |
| mtspr SPRN_HID0,r3 |
| sync |
| isync |
| blr |
| |
| /* inval_enable_L1 - Invalidate and enable L1 cache |
| * |
| * Assumes L1 is already disabled and MSR:EE is off |
| * |
| * clobbers r3 |
| */ |
| _GLOBAL(__inval_enable_L1) |
| /* Enable and then Flash inval the instruction & data cache */ |
| mfspr r3,SPRN_HID0 |
| ori r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI |
| sync |
| isync |
| mtspr SPRN_HID0,r3 |
| xori r3,r3, HID0_ICFI|HID0_DCI |
| mtspr SPRN_HID0,r3 |
| sync |
| |
| blr |
| |
| |