Created
June 22, 2012 20:16
-
-
Save kylemanna/2974939 to your computer and use it in GitHub Desktop.
[HACK] Dump AM387x/TI81848 PHY registers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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