Skip to content

Instantly share code, notes, and snippets.

@kylemanna
Created June 22, 2012 20:16
Show Gist options
  • Save kylemanna/2974939 to your computer and use it in GitHub Desktop.
Save kylemanna/2974939 to your computer and use it in GitHub Desktop.
[HACK] Dump AM387x/TI81848 PHY registers
#!/usr/bin/env python
"""
This is designed primarily for use with accessing /dev/mem on OMAP platforms.
It should work on other platforms and work to mmap() files rather then just
/dev/mem, but these use cases aren't well tested.
All file accesses are aligned to DevMem.word bytes, which is 4 bytes on ARM
platforms to avoid data abort faults when accessing peripheral registers.
References:
http://wiki.python.org/moin/PythonSpeed/PerformanceTips
http://www.python.org/dev/peps/pep-0008/
"""
import os
import sys
import mmap
import struct
import optparse
""" DevMemBuffer
This class holds data for objects returned from DevMem class
It allows an easy way to print hex data
"""
class DevMemBuffer:
def __init__(self, base_addr, data):
self.data = data
self.base_addr = base_addr
def __len__(self):
return len(self.data)
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, value):
self.data[key] = value
def hexdump(self, word_size = 4, words_per_row = 4):
# Build a list of strings and then join them in the last step.
# This is more efficient then concat'ing immutable strings.
d = self.data
dump = []
i = 0
while (i < len(d)):
dump.append('0x{0:02x}: '.format(self.base_addr + word_size * i))
max_col = i + words_per_row
if max_col > len(d): max_col = len(d)
while (i < max_col):
# If the word is 4 bytes, then handle it and continue the
# loop, this should be the normal case
if word_size == 4:
dump.append(" {0:08x} ".format(d[i]))
i += 1
continue
# Otherwise the word_size is not an int, pack it so it can be
# un-packed to the desired word size. This should blindly
# handle endian problems (Verify?)
packed = struct.pack('I',(d[i]))
i += 1
if word_size == 2:
dh = struct.unpack('HH', packed)
dump.append(" {0:04x}".format(dh[0]))
#dump.append(" {0:04x} ".format(dh[1]))
elif word_size == 1:
db = struct.unpack('BBBB', packed)
dump.append(" {0:02x}".format(db[0]))
dump.append(" {0:02x} ".format(db[1]))
dump.append(" {0:02x}".format(db[2]))
dump.append(" {0:02x} ".format(db[3]))
dump.append('\n')
# Chop off the last new line character and join the list of strings
# in to a single string
return ''.join(dump[:-1])
def __str__(self):
return self.hexdump()
""" DevMem
Class to read and write data aligned to word boundaries of /dev/mem
"""
class DevMem:
# Size of a word that will be used for reading/writing
word = 4
mask = ~(word - 1)
def __init__(self, base_addr, length = 1, filename = '/dev/mem',
debug = 0):
if base_addr < 0 or length < 0: raise AssertionError
self._debug = debug
self.base_addr = base_addr & ~(mmap.PAGESIZE - 1)
self.base_addr_offset = base_addr - self.base_addr
stop = base_addr + length * self.word
if (stop % self.mask):
stop = (stop + self.word) & ~(self.word - 1)
self.length = stop - self.base_addr
self.fname = filename
# Check filesize (doesn't work with /dev/mem)
#filesize = os.stat(self.fname).st_size
#if (self.base_addr + self.length) > filesize:
# self.length = filesize - self.base_addr
self.debug('init with base_addr = {0} and length = {1} on {2}'.
format(hex(self.base_addr), hex(self.length), self.fname))
# Open file and mmap
f = os.open(self.fname, os.O_RDWR | os.O_SYNC)
self.mem = mmap.mmap(f, self.length, mmap.MAP_SHARED,
mmap.PROT_READ | mmap.PROT_WRITE,
offset=self.base_addr)
"""
Read length number of words from offset
"""
def read(self, offset, length):
if offset < 0 or length < 0: raise AssertionError
# Make reading easier (and faster... won't resolve dot in loops)
mem = self.mem
self.debug('reading {0} bytes from offset {1}'.
format(length * self.word, hex(offset)))
# Compensate for the base_address not being what the user requested
# and then seek to the aligned offset.
virt_base_addr = self.base_addr_offset & self.mask
mem.seek(virt_base_addr + offset)
# Read length words of size self.word and return it
data = []
for i in range(length):
data.append(struct.unpack('I', mem.read(self.word))[0])
abs_addr = self.base_addr + virt_base_addr
return DevMemBuffer(abs_addr + offset, data)
"""
Write length number of words to offset
"""
def write(self, offset, din):
if offset < 0 or len(din) <= 0: raise AssertionError
self.debug('writing {0} bytes to offset {1}'.
format(len(din), hex(offset)))
# Compensate for the base_address not being what the user requested
offset += self.base_addr_offset
# Check that the operation is going write to an aligned location
if (offset & ~self.mask): raise AssertionError
# Seek to the aligned offset
self.mem.seek(offset)
# Read until the end of our aligned address
for i in range(0, len(din), self.word):
self.debug('writing at position = {0}: 0x{1:x}'.
format(self.mem.tell(), din[i]))
# Write one word at a time
self.mem.write(struct.pack('I', din[i]))
def debug_set(self, value):
self._debug = value
def debug(self, debug_str):
if self._debug: print 'DevMem Debug: {0}'.format(debug_str)
""" Main
If this is run as a script (rather then imported as a module) it provides
some basic functionality out of the box
"""
def main():
parser = optparse.OptionParser()
parser.add_option("-r", "--read", dest="read", metavar="ADDR",
type=int, help="read a value")
parser.add_option("-w", "--write", dest="write", help="write a value",
nargs=2, type=int, metavar="ADDR VALUE")
parser.add_option("-n", "--num", dest="num",
help="number of words to read",
type=int, default=1)
parser.add_option("-s", "--word-size", dest="word_size",
help="size of word when displayed",
type=int, default=4)
parser.add_option("-m", "--mmap", dest="mmap",
metavar="FILE",
help="file to open with mmap()",
type=str, default="/dev/mem")
parser.add_option("-v", action="store_true", dest="verbose",
help="provide more information regarding operation")
parser.add_option("-d", action="store_true", dest="debug",
help="provide debugging information")
(options, args) = parser.parse_args()
# Check for sane arguments
if options.write and options.read:
parser.print_help()
print "\nError: Both read and write are specified"
return -1
elif not options.write and not options.read:
parser.print_help()
print "\nError: Neither read or write are specified"
return -1
if options.num < 0:
parser.print_help()
print "\nError: Invalid num of words specified"
return -1
if (options.word_size != 1 and options.word_size != 2
and options.word_size != 4):
parser.print_help()
print "\nError: Invalid word size specified"
return -1
# Only support writing one word at a time, force this
if options.write and options.num != 1:
print "Warning: Forcing number of words to 1 for set operation\n"
options.num = 1
# Determine base address to operate on
addr = options.read
if options.write: addr = options.write[0]
# Create the Dev Mem object that does the magic
mem = DevMem(addr, length=options.num, filename=options.mmap,
debug=options.debug)
if options.debug:
mem.debug_set(1)
# Perform the actual read or write
if options.write:
if options.verbose:
print "Value before write:\t{0}".format(
mem.read(0x0, options.num).hexdump(options.word_size))
mem.write(0x0, [options.write[1]])
if options.verbose:
print "Value after write:\t{0}".format(
mem.read(0x0, options.num).hexdump(options.word_size))
else:
print mem.read(0x0, options.num).hexdump(options.word_size)
class PhyMDIO():
def __init__(self):
a = 1
def read_mdio(regaddr):
addr = 0x4a100880
mem = DevMem(addr, 0x100, "/dev/mem", 0)
reg_go = 1 << 31
reg_regaddr = regaddr << 21
reg = 0
reg = reg_go | reg_regaddr
mem.write(0x0, [reg])
buf = mem.read(0x0, 1)
while buf[0] & reg_go:
buf = mem.read(0x0, 1)
buf.base_addr = regaddr
buf[0] &= 0xffff
return buf
def dump_mdio():
addr = 0x4a100800
debug = 0
mem = DevMem(addr, 0x1000, "/dev/mem", 0)
print "MDIO Version Register: ", mem.read(0x00, 1)
print "MDIO Control Register: ", mem.read(0x04, 1)
print "PHY Alive Status Register:", mem.read(0x08, 1)
print "PHY Link Status Register: ", mem.read(0x10, 1)
for i in range(0x20):
print "Phy Register:", read_mdio(i).hexdump(2)
if __name__ == '__main__':
#sys.exit(main())
sys.exit(dump_mdio())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment