Add the mem_native library for native memory access
This library is used by the new FPGA-TIO driver. It uses C library
to direct access the memory, instead of using the memtool.
BUG=chromium:374103
TEST=Pending test, to wait for all the stuffs ready for the FPGA-TIO driver.
Change-Id: Ibfbaad0cdc13c30c08ceead502b31cc6a91f1020
Reviewed-on: https://chromium-review.googlesource.com/200213
Reviewed-by: Dean Liao <deanliao@chromium.org>
Commit-Queue: Wai-Hong Tam <waihong@chromium.org>
Tested-by: Wai-Hong Tam <waihong@chromium.org>
diff --git a/chameleond/utils/mem_native.py b/chameleond/utils/mem_native.py
new file mode 100644
index 0000000..6f07441
--- /dev/null
+++ b/chameleond/utils/mem_native.py
@@ -0,0 +1,117 @@
+# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Memory module for accessing the memory for IO.
+
+This module uses C library to direct access the memory.
+
+Usage:
+ import mem_native
+ value = mem_native.Memory.Read(address)
+"""
+
+import ctypes
+import time
+
+
+class _Memory(object):
+ """A class to abstract the memory access for IO."""
+
+ # Address space for memory-mapped I/O.
+ _MMAP_START = 0xff210000
+ _MMAP_SIZE = 0x10000
+ # mmap end address (exclusive)
+ _MMAP_END = _MMAP_START + _MMAP_SIZE
+
+ _REG_SET_DELAY = 0.001
+
+ def __init__(self):
+ """Constructs a _Memory object.
+
+ Raises:
+ IOError if failed to open /dev/mem.
+ """
+ libc = ctypes.cdll.LoadLibrary('libc.so.6')
+ O_RDWR = 00000002
+ O_SYNC = 04000000 | 00010000
+ fd = libc.open('/dev/mem', O_RDWR | O_SYNC)
+ if fd == -1:
+ raise IOError('Failed to open /dev/mem')
+ PROT_READ = 0x1
+ PROT_WRITE = 0x2
+ MAP_SHARED = 0x01
+ self._memory = libc.mmap(0, self._MMAP_SIZE, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, self._MMAP_START)
+ if self._memory == -1:
+ raise IOError('Failed to call mmap()')
+
+ def _GetLocalAddress(self, address):
+ """Gets the local mmapped address for a given memory address.
+
+ Args:
+ address: The memory address.
+
+ Returns:
+ A local mmapped address.
+ """
+ assert self._memory != -1
+ assert self._MMAP_START <= address < self._MMAP_END
+ return self._memory + (address & 0xffff)
+
+ def Read(self, address):
+ """Reads the 32-bit integer from the given memory address.
+
+ Args:
+ address: The memory address.
+
+ Returns:
+ An integer.
+ """
+ local_addr = self._GetLocalAddress(address)
+ return ctypes.c_uint.from_address(local_addr).value # pylint: disable=E1101
+
+ def Write(self, address, data):
+ """Writes the given 32-bit integer to the given memory address.
+
+ Args:
+ address: The memory address.
+ data: The 32-bit integer to write.
+ """
+ local_addr = self._GetLocalAddress(address)
+ ctypes.c_uint.from_address(local_addr).value = data # pylint: disable=E1101
+
+ def SetMask(self, address, mask):
+ """Sets the mask on the given memory address.
+
+ Args:
+ address: The memory address.
+ mask: The bitwise mask.
+ """
+ self.Write(address, self.Read(address) | mask)
+
+ def ClearMask(self, address, mask):
+ """Clears the mask on the given memory address.
+
+ Args:
+ address: The memory address.
+ mask: The bitwise mask.
+ """
+ self.Write(address, self.Read(address) & ~mask)
+
+ def SetAndClearMask(self, address, mask, delay_secs=_REG_SET_DELAY):
+ """Sets and then clears the mask on the given memory address.
+
+ It is a blocking call for at least delay_secs seconds.
+
+ Args:
+ address: The memory address.
+ mask: The bitwise mask.
+ delay_secs: The time between set and clear. Default: _REG_SET_DELAY
+ """
+ self.SetMask(address, mask)
+ time.sleep(delay_secs)
+ self.ClearMask(address, mask)
+
+
+# Singleton
+Memory = _Memory()