1--
2-- Copyright 2014, General Dynamics C4 Systems
3--
4-- This software may be distributed and modified according to the terms of
5-- the GNU General Public License version 2. Note that NO WARRANTY is provided.
6-- See "LICENSE_GPLv2.txt" for details.
7--
8-- @TAG(GD_GPL)
9--
10
11{-# LANGUAGE EmptyDataDecls, ForeignFunctionInterface, GeneralizedNewtypeDeriving #-}
12
13module SEL4.Machine.Hardware.ARM.KZM where
14
15import Prelude hiding (Word)
16import SEL4.Machine.RegisterSet
17import Foreign.Ptr
18import Data.Bits
19import Data.Word(Word8)
20import Data.Ix
21import SEL4.Machine.Hardware.ARM.Callbacks
22
23
24newtype IRQ = IRQ Word8
25    deriving (Enum, Ord, Ix, Eq, Show)
26
27instance Bounded IRQ where
28    minBound = IRQ 0
29    maxBound = IRQ 31
30
31kernelBase :: VPtr
32kernelBase = VPtr 0xf0000000
33
34physBase = 0x80000000
35physMappingOffset = 0xf0000000 - physBase
36
37ptrFromPAddr :: PAddr -> PPtr a
38ptrFromPAddr (PAddr addr) = PPtr $ addr + physMappingOffset
39
40addrFromPPtr :: PPtr a -> PAddr
41addrFromPPtr (PPtr ptr) = PAddr $ ptr - physMappingOffset
42
43pageColourBits :: Int
44pageColourBits = 0 -- qemu has no cache
45
46getMemoryRegions :: Ptr CallbackData -> IO [(PAddr, PAddr)]
47getMemoryRegions _ = return [(0x80000000, 0x80000000 + (0x8 `shiftL` 24))]
48
49getDeviceRegions :: Ptr CallbackData -> IO [(PAddr, PAddr)]
50getDeviceRegions _ = return devices
51    where devices = [
52            (0x53f98000, 0x53f99000) -- second SP804; kernel uses first
53            ]
54
55timerPPtr = PPtr 0xfff00000
56timerAddr = PAddr 0x53f94000
57timerIRQ = IRQ 28
58
59avicPPtr = PPtr 0xfff01000
60avicAddr = PAddr 0x68000000
61
62getKernelDevices :: Ptr CallbackData -> IO [(PAddr, PPtr Word)]
63getKernelDevices _ = return devices
64    where devices = [
65            (timerAddr, timerPPtr), -- kernel timer
66            (avicAddr, avicPPtr) -- interrupt controller
67            ]
68
69maskInterrupt :: Ptr CallbackData -> Bool -> IRQ -> IO ()
70maskInterrupt env mask (IRQ irq) = do
71    let value = fromIntegral irq
72    offset <- return $ if (mask == True) then 0xc else 0x8
73    storeWordCallback env (avicAddr + offset) value
74
75-- We don't need to acknowledge interrupts explicitly because we don't use
76-- the vectored interrupt controller.
77ackInterrupt :: Ptr CallbackData -> IRQ -> IO ()
78ackInterrupt _ _ = return ()
79
80foreign import ccall unsafe "qemu_run_devices"
81    runDevicesCallback :: Ptr CallbackData -> IO ()
82
83interruptCallback :: Ptr CallbackData -> IO (Maybe IRQ)
84interruptCallback env = do
85    -- No need to call back to the simulator here; we just check the PIC's
86    -- active interrupt register. This will probably work for real ARMs too,
87    -- as long as we're not using vectored interrupts
88    active <- loadWordCallback env (avicAddr + 64)
89    return $ if active == 0xFFFF0000
90        then Nothing
91        else (Just $ IRQ $ fromIntegral (active `shiftR` 16))
92
93getActiveIRQ :: Ptr CallbackData -> IO (Maybe IRQ)
94getActiveIRQ env = do
95    runDevicesCallback env
96    interruptCallback env
97
98-- 1kHz tick; qemu's SP804s always run at 1MHz
99timerFreq :: Word
100timerFreq = 100
101
102timerLimit :: Word
103timerLimit = 1000000 `div` timerFreq
104
105configureTimer :: Ptr CallbackData -> IO IRQ
106configureTimer env = do
107    -- enabled, periodic, interrupts enabled
108    storeWordCallback env timerAddr 0
109    let timerCtrl = bit 24 .|. bit 17 .|. bit 3 .|. bit 2 .|. bit 1
110    storeWordCallback env timerAddr timerCtrl
111    storeWordCallback env (timerAddr+0x8) (100 * 1000 * 1000)
112    storeWordCallback env (timerAddr+0xc) 0
113    storeWordCallback env (timerAddr+0x4) 1
114    let timerCtrl2 = timerCtrl .|. 1
115    storeWordCallback env timerAddr timerCtrl2
116    return timerIRQ
117
118initIRQController :: Ptr CallbackData -> IO ()
119initIRQController env = runDevicesCallback env
120
121resetTimer :: Ptr CallbackData -> IO ()
122resetTimer env = storeWordCallback env (timerAddr+0x4) 1
123
124isbCallback :: Ptr CallbackData -> IO ()
125isbCallback _ = return ()
126
127dsbCallback :: Ptr CallbackData -> IO ()
128dsbCallback _ = return ()
129
130dmbCallback :: Ptr CallbackData -> IO ()
131dmbCallback _ = return ()
132
133cacheCleanByVACallback :: Ptr CallbackData -> VPtr -> PAddr -> IO ()
134cacheCleanByVACallback _cptr _mva _pa = return ()
135
136cacheCleanByVA_PoUCallback :: Ptr CallbackData -> VPtr -> PAddr -> IO ()
137cacheCleanByVA_PoUCallback _cptr _mva _pa = return ()
138
139cacheInvalidateByVACallback :: Ptr CallbackData -> VPtr -> PAddr -> IO ()
140cacheInvalidateByVACallback _cptr _mva _pa = return ()
141
142cacheInvalidateByVA_ICallback :: Ptr CallbackData -> VPtr -> PAddr -> IO ()
143cacheInvalidateByVA_ICallback _cptr _mva _pa = return ()
144
145cacheInvalidate_I_PoUCallback :: Ptr CallbackData -> IO ()
146cacheInvalidate_I_PoUCallback _ = return ()
147
148cacheCleanInvalidateByVACallback ::
149    Ptr CallbackData -> VPtr -> PAddr -> IO ()
150cacheCleanInvalidateByVACallback _cptr _mva _pa = return ()
151
152branchFlushCallback :: Ptr CallbackData -> VPtr -> PAddr -> IO ()
153branchFlushCallback _cptr _mva _pa = return ()
154
155cacheClean_D_PoUCallback :: Ptr CallbackData -> IO ()
156cacheClean_D_PoUCallback _ = return ()
157
158cacheCleanInvalidate_D_PoCCallback :: Ptr CallbackData -> IO ()
159cacheCleanInvalidate_D_PoCCallback _ = return ()
160
161cacheCleanInvalidate_D_PoUCallback :: Ptr CallbackData -> IO ()
162cacheCleanInvalidate_D_PoUCallback _ = return ()
163
164cacheCleanInvalidateL2RangeCallback ::
165    Ptr CallbackData -> PAddr -> PAddr -> IO ()
166cacheCleanInvalidateL2RangeCallback _ _ _ = return ()
167
168cacheInvalidateL2RangeCallback :: Ptr CallbackData -> PAddr -> PAddr -> IO ()
169cacheInvalidateL2RangeCallback _ _ _ = return ()
170
171cacheCleanL2RangeCallback :: Ptr CallbackData -> PAddr -> PAddr -> IO ()
172cacheCleanL2RangeCallback _ _ _ = return ()
173
174-- For the ARM1136
175cacheLine :: Int
176cacheLine = 32
177
178cacheLineBits :: Int
179cacheLineBits = 5
180