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