diff options
Diffstat (limited to 'drivers/dsp/bridge/hw/hw_mmu.c')
-rw-r--r-- | drivers/dsp/bridge/hw/hw_mmu.c | 599 |
1 files changed, 599 insertions, 0 deletions
diff --git a/drivers/dsp/bridge/hw/hw_mmu.c b/drivers/dsp/bridge/hw/hw_mmu.c new file mode 100644 index 000000000000..ce9d5868d442 --- /dev/null +++ b/drivers/dsp/bridge/hw/hw_mmu.c @@ -0,0 +1,599 @@ +/* + * hw_mmu.c + * + * DSP-BIOS Bridge driver support functions for TI OMAP processors. + * + * Copyright (C) 2007 Texas Instruments, Inc. + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * ======== hw_mmu.c ======== + * Description: + * API definitions to setup MMU TLB and PTE + * + *! Revision History: + *! ================ + *! 19-Apr-2004 sb TLBAdd and TLBFlush input the page size in bytes instead + of an enum. TLBAdd inputs mapping attributes struct instead + of individual arguments. + Removed MMU.h and other cosmetic updates. + *! 08-Mar-2004 sb Added the Page Table Management APIs + *! 16 Feb 2003 sb: Initial version + */ + +#include <GlobalTypes.h> +#include <linux/io.h> +#include "MMURegAcM.h" +#include <hw_defs.h> +#include <hw_mmu.h> +#include <linux/types.h> + +#define MMU_BASE_VAL_MASK 0xFC00 +#define MMU_PAGE_MAX 3 +#define MMU_ELEMENTSIZE_MAX 3 +#define MMU_ADDR_MASK 0xFFFFF000 +#define MMU_TTB_MASK 0xFFFFC000 +#define MMU_SECTION_ADDR_MASK 0xFFF00000 +#define MMU_SSECTION_ADDR_MASK 0xFF000000 +#define MMU_PAGE_TABLE_MASK 0xFFFFFC00 +#define MMU_LARGE_PAGE_MASK 0xFFFF0000 +#define MMU_SMALL_PAGE_MASK 0xFFFFF000 + +#define MMU_LOAD_TLB 0x00000001 + +/* HW_MMUPageSize_t: Enumerated Type used to specify the MMU Page Size(SLSS) */ +enum HW_MMUPageSize_t { + HW_MMU_SECTION, + HW_MMU_LARGE_PAGE, + HW_MMU_SMALL_PAGE, + HW_MMU_SUPERSECTION +} ; + +/* +* FUNCTION : MMU_FlushEntry +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of MMU module +* +* RETURNS: +* +* Type : HW_STATUS +* Description : RET_OK -- No errors occured +* RET_BAD_NULL_PARAM -- A Pointer +* Paramater was set to NULL +* +* PURPOSE: : Flush the TLB entry pointed by the +* lock counter register +* even if this entry is set protected +* +* METHOD: : Check the Input parameter and Flush a +* single entry in the TLB. +*/ +static HW_STATUS MMU_FlushEntry(const void __iomem *baseAddress); + +/* +* FUNCTION : MMU_SetCAMEntry +* +* INPUTS: +* +* Identifier : baseAddress +* TypE : const u32 +* Description : Base Address of instance of MMU module +* +* Identifier : pageSize +* TypE : const u32 +* Description : It indicates the page size +* +* Identifier : preservedBit +* Type : const u32 +* Description : It indicates the TLB entry is preserved entry +* or not +* +* Identifier : validBit +* Type : const u32 +* Description : It indicates the TLB entry is valid entry or not +* +* +* Identifier : virtualAddrTag +* Type : const u32 +* Description : virtual Address +* +* RETURNS: +* +* Type : HW_STATUS +* Description : RET_OK -- No errors occured +* RET_BAD_NULL_PARAM -- A Pointer Paramater +* was set to NULL +* RET_PARAM_OUT_OF_RANGE -- Input Parameter out +* of Range +* +* PURPOSE: : Set MMU_CAM reg +* +* METHOD: : Check the Input parameters and set the CAM entry. +*/ +static HW_STATUS MMU_SetCAMEntry(const void __iomem *baseAddress, + const u32 pageSize, + const u32 preservedBit, + const u32 validBit, + const u32 virtualAddrTag); + +/* +* FUNCTION : MMU_SetRAMEntry +* +* INPUTS: +* +* Identifier : baseAddress +* Type : const u32 +* Description : Base Address of instance of MMU module +* +* Identifier : physicalAddr +* Type : const u32 +* Description : Physical Address to which the corresponding +* virtual Address shouldpoint +* +* Identifier : endianism +* Type : HW_Endianism_t +* Description : endianism for the given page +* +* Identifier : elementSize +* Type : HW_ElementSize_t +* Description : The element size ( 8,16, 32 or 64 bit) +* +* Identifier : mixedSize +* Type : HW_MMUMixedSize_t +* Description : Element Size to follow CPU or TLB +* +* RETURNS: +* +* Type : HW_STATUS +* Description : RET_OK -- No errors occured +* RET_BAD_NULL_PARAM -- A Pointer Paramater +* was set to NULL +* RET_PARAM_OUT_OF_RANGE -- Input Parameter +* out of Range +* +* PURPOSE: : Set MMU_CAM reg +* +* METHOD: : Check the Input parameters and set the RAM entry. +*/ +static HW_STATUS MMU_SetRAMEntry(const void __iomem *baseAddress, + const u32 physicalAddr, + enum HW_Endianism_t endianism, + enum HW_ElementSize_t elementSize, + enum HW_MMUMixedSize_t mixedSize); + +/* HW FUNCTIONS */ + +HW_STATUS HW_MMU_Enable(const void __iomem *baseAddress) +{ + HW_STATUS status = RET_OK; + + MMUMMU_CNTLMMUEnableWrite32(baseAddress, HW_SET); + + return status; +} + +HW_STATUS HW_MMU_Disable(const void __iomem *baseAddress) +{ + HW_STATUS status = RET_OK; + + MMUMMU_CNTLMMUEnableWrite32(baseAddress, HW_CLEAR); + + return status; +} + +HW_STATUS HW_MMU_NumLockedSet(const void __iomem *baseAddress, + u32 numLockedEntries) +{ + HW_STATUS status = RET_OK; + + MMUMMU_LOCKBaseValueWrite32(baseAddress, numLockedEntries); + + return status; +} + +HW_STATUS HW_MMU_VictimNumSet(const void __iomem *baseAddress, + u32 victimEntryNum) +{ + HW_STATUS status = RET_OK; + + MMUMMU_LOCKCurrentVictimWrite32(baseAddress, victimEntryNum); + + return status; +} + +HW_STATUS HW_MMU_EventAck(const void __iomem *baseAddress, u32 irqMask) +{ + HW_STATUS status = RET_OK; + + MMUMMU_IRQSTATUSWriteRegister32(baseAddress, irqMask); + + return status; +} + +HW_STATUS HW_MMU_EventDisable(const void __iomem *baseAddress, + u32 irqMask) +{ + HW_STATUS status = RET_OK; + u32 irqReg; + + irqReg = MMUMMU_IRQENABLEReadRegister32(baseAddress); + + MMUMMU_IRQENABLEWriteRegister32(baseAddress, irqReg & ~irqMask); + + return status; +} + +HW_STATUS HW_MMU_EventEnable(const void __iomem *baseAddress, u32 irqMask) +{ + HW_STATUS status = RET_OK; + u32 irqReg; + + irqReg = MMUMMU_IRQENABLEReadRegister32(baseAddress); + + MMUMMU_IRQENABLEWriteRegister32(baseAddress, irqReg | irqMask); + + return status; +} + + +HW_STATUS HW_MMU_EventStatus(const void __iomem *baseAddress, u32 *irqMask) +{ + HW_STATUS status = RET_OK; + + *irqMask = MMUMMU_IRQSTATUSReadRegister32(baseAddress); + + return status; +} + + +HW_STATUS HW_MMU_FaultAddrRead(const void __iomem *baseAddress, u32 *addr) +{ + HW_STATUS status = RET_OK; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + /* read values from register */ + *addr = MMUMMU_FAULT_ADReadRegister32(baseAddress); + + return status; +} + +HW_STATUS HW_MMU_TTBSet(const void __iomem *baseAddress, u32 TTBPhysAddr) +{ + HW_STATUS status = RET_OK; + u32 loadTTB; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + loadTTB = TTBPhysAddr & ~0x7FUL; + /* write values to register */ + MMUMMU_TTBWriteRegister32(baseAddress, loadTTB); + + return status; +} + +HW_STATUS HW_MMU_TWLEnable(const void __iomem *baseAddress) +{ + HW_STATUS status = RET_OK; + + MMUMMU_CNTLTWLEnableWrite32(baseAddress, HW_SET); + + return status; +} + +HW_STATUS HW_MMU_TWLDisable(const void __iomem *baseAddress) +{ + HW_STATUS status = RET_OK; + + MMUMMU_CNTLTWLEnableWrite32(baseAddress, HW_CLEAR); + + return status; +} + +HW_STATUS HW_MMU_TLBFlush(const void __iomem *baseAddress, u32 virtualAddr, + u32 pageSize) +{ + HW_STATUS status = RET_OK; + u32 virtualAddrTag; + enum HW_MMUPageSize_t pgSizeBits; + + switch (pageSize) { + case HW_PAGE_SIZE_4KB: + pgSizeBits = HW_MMU_SMALL_PAGE; + break; + + case HW_PAGE_SIZE_64KB: + pgSizeBits = HW_MMU_LARGE_PAGE; + break; + + case HW_PAGE_SIZE_1MB: + pgSizeBits = HW_MMU_SECTION; + break; + + case HW_PAGE_SIZE_16MB: + pgSizeBits = HW_MMU_SUPERSECTION; + break; + + default: + return RET_FAIL; + } + + /* Generate the 20-bit tag from virtual address */ + virtualAddrTag = ((virtualAddr & MMU_ADDR_MASK) >> 12); + + MMU_SetCAMEntry(baseAddress, pgSizeBits, 0, 0, virtualAddrTag); + + MMU_FlushEntry(baseAddress); + + return status; +} + +HW_STATUS HW_MMU_TLBAdd(const void __iomem *baseAddress, + u32 physicalAddr, + u32 virtualAddr, + u32 pageSize, + u32 entryNum, + struct HW_MMUMapAttrs_t *mapAttrs, + enum HW_SetClear_t preservedBit, + enum HW_SetClear_t validBit) +{ + HW_STATUS status = RET_OK; + u32 lockReg; + u32 virtualAddrTag; + enum HW_MMUPageSize_t mmuPgSize; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(pageSize, MMU_PAGE_MAX, RET_PARAM_OUT_OF_RANGE, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(mapAttrs->elementSize, MMU_ELEMENTSIZE_MAX, + RET_PARAM_OUT_OF_RANGE, RES_MMU_BASE + + RES_INVALID_INPUT_PARAM); + + switch (pageSize) { + case HW_PAGE_SIZE_4KB: + mmuPgSize = HW_MMU_SMALL_PAGE; + break; + + case HW_PAGE_SIZE_64KB: + mmuPgSize = HW_MMU_LARGE_PAGE; + break; + + case HW_PAGE_SIZE_1MB: + mmuPgSize = HW_MMU_SECTION; + break; + + case HW_PAGE_SIZE_16MB: + mmuPgSize = HW_MMU_SUPERSECTION; + break; + + default: + return RET_FAIL; + } + + lockReg = MMUMMU_LOCKReadRegister32(baseAddress); + + /* Generate the 20-bit tag from virtual address */ + virtualAddrTag = ((virtualAddr & MMU_ADDR_MASK) >> 12); + + /* Write the fields in the CAM Entry Register */ + MMU_SetCAMEntry(baseAddress, mmuPgSize, preservedBit, validBit, + virtualAddrTag); + + /* Write the different fields of the RAM Entry Register */ + /* endianism of the page,Element Size of the page (8, 16, 32, 64 bit)*/ + MMU_SetRAMEntry(baseAddress, physicalAddr, mapAttrs->endianism, + mapAttrs->elementSize, mapAttrs->mixedSize); + + /* Update the MMU Lock Register */ + /* currentVictim between lockedBaseValue and (MMU_Entries_Number - 1)*/ + MMUMMU_LOCKCurrentVictimWrite32(baseAddress, entryNum); + + /* Enable loading of an entry in TLB by writing 1 + into LD_TLB_REG register */ + MMUMMU_LD_TLBWriteRegister32(baseAddress, MMU_LOAD_TLB); + + + MMUMMU_LOCKWriteRegister32(baseAddress, lockReg); + + return status; +} + +HW_STATUS HW_MMU_PteSet(const u32 pgTblVa, + u32 physicalAddr, + u32 virtualAddr, + u32 pageSize, + struct HW_MMUMapAttrs_t *mapAttrs) +{ + HW_STATUS status = RET_OK; + u32 pteAddr, pteVal; + s32 numEntries = 1; + + switch (pageSize) { + case HW_PAGE_SIZE_4KB: + pteAddr = HW_MMU_PteAddrL2(pgTblVa, + virtualAddr & MMU_SMALL_PAGE_MASK); + pteVal = ((physicalAddr & MMU_SMALL_PAGE_MASK) | + (mapAttrs->endianism << 9) | + (mapAttrs->elementSize << 4) | + (mapAttrs->mixedSize << 11) | 2 + ); + break; + + case HW_PAGE_SIZE_64KB: + numEntries = 16; + pteAddr = HW_MMU_PteAddrL2(pgTblVa, + virtualAddr & MMU_LARGE_PAGE_MASK); + pteVal = ((physicalAddr & MMU_LARGE_PAGE_MASK) | + (mapAttrs->endianism << 9) | + (mapAttrs->elementSize << 4) | + (mapAttrs->mixedSize << 11) | 1 + ); + break; + + case HW_PAGE_SIZE_1MB: + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SECTION_ADDR_MASK); + pteVal = ((((physicalAddr & MMU_SECTION_ADDR_MASK) | + (mapAttrs->endianism << 15) | + (mapAttrs->elementSize << 10) | + (mapAttrs->mixedSize << 17)) & + ~0x40000) | 0x2 + ); + break; + + case HW_PAGE_SIZE_16MB: + numEntries = 16; + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SSECTION_ADDR_MASK); + pteVal = (((physicalAddr & MMU_SSECTION_ADDR_MASK) | + (mapAttrs->endianism << 15) | + (mapAttrs->elementSize << 10) | + (mapAttrs->mixedSize << 17) + ) | 0x40000 | 0x2 + ); + break; + + case HW_MMU_COARSE_PAGE_SIZE: + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SECTION_ADDR_MASK); + pteVal = (physicalAddr & MMU_PAGE_TABLE_MASK) | 1; + break; + + default: + return RET_FAIL; + } + + while (--numEntries >= 0) + ((u32 *)pteAddr)[numEntries] = pteVal; + + return status; +} + +HW_STATUS HW_MMU_PteClear(const u32 pgTblVa, + u32 virtualAddr, + u32 pgSize) +{ + HW_STATUS status = RET_OK; + u32 pteAddr; + s32 numEntries = 1; + + switch (pgSize) { + case HW_PAGE_SIZE_4KB: + pteAddr = HW_MMU_PteAddrL2(pgTblVa, + virtualAddr & MMU_SMALL_PAGE_MASK); + break; + + case HW_PAGE_SIZE_64KB: + numEntries = 16; + pteAddr = HW_MMU_PteAddrL2(pgTblVa, + virtualAddr & MMU_LARGE_PAGE_MASK); + break; + + case HW_PAGE_SIZE_1MB: + case HW_MMU_COARSE_PAGE_SIZE: + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SECTION_ADDR_MASK); + break; + + case HW_PAGE_SIZE_16MB: + numEntries = 16; + pteAddr = HW_MMU_PteAddrL1(pgTblVa, + virtualAddr & MMU_SSECTION_ADDR_MASK); + break; + + default: + return RET_FAIL; + } + + while (--numEntries >= 0) + ((u32 *)pteAddr)[numEntries] = 0; + + return status; +} + +/* MMU_FlushEntry */ +static HW_STATUS MMU_FlushEntry(const void __iomem *baseAddress) +{ + HW_STATUS status = RET_OK; + u32 flushEntryData = 0x1; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + /* write values to register */ + MMUMMU_FLUSH_ENTRYWriteRegister32(baseAddress, flushEntryData); + + return status; +} + +/* MMU_SetCAMEntry */ +static HW_STATUS MMU_SetCAMEntry(const void __iomem *baseAddress, + const u32 pageSize, + const u32 preservedBit, + const u32 validBit, + const u32 virtualAddrTag) +{ + HW_STATUS status = RET_OK; + u32 mmuCamReg; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + + mmuCamReg = (virtualAddrTag << 12); + mmuCamReg = (mmuCamReg) | (pageSize) | (validBit << 2) | + (preservedBit << 3) ; + + /* write values to register */ + MMUMMU_CAMWriteRegister32(baseAddress, mmuCamReg); + + return status; +} + +/* MMU_SetRAMEntry */ +static HW_STATUS MMU_SetRAMEntry(const void __iomem *baseAddress, + const u32 physicalAddr, + enum HW_Endianism_t endianism, + enum HW_ElementSize_t elementSize, + enum HW_MMUMixedSize_t mixedSize) +{ + HW_STATUS status = RET_OK; + u32 mmuRamReg; + + /*Check the input Parameters*/ + CHECK_INPUT_PARAM(baseAddress, 0, RET_BAD_NULL_PARAM, + RES_MMU_BASE + RES_INVALID_INPUT_PARAM); + CHECK_INPUT_RANGE_MIN0(elementSize, MMU_ELEMENTSIZE_MAX, + RET_PARAM_OUT_OF_RANGE, RES_MMU_BASE + + RES_INVALID_INPUT_PARAM); + + + mmuRamReg = (physicalAddr & MMU_ADDR_MASK); + mmuRamReg = (mmuRamReg) | ((endianism << 9) | (elementSize << 7) | + (mixedSize << 6)); + + /* write values to register */ + MMUMMU_RAMWriteRegister32(baseAddress, mmuRamReg); + + return status; + +} |