ppx4xx support in arch/powerpc is still off in the distance, but here
is a proof of concept device tree generator for Xilinx virtex designs.
You pass the tool a .mhs file, and it spits out a .dts file.
Generated dts output is accepted by the dtc parser.  I've tested
against the ml403 reference designs and a custom design.

This code can also be viewed at:
http://git.secretlab.ca/cgi-bin/gitweb.cgi?p=gen_mhs_devtree.git;a=summary

Cheers,
g.

--
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
[EMAIL PROTECTED]
(403) 399-0195
#!/usr/bin/env python
#
# Author: Grant Likely <[EMAIL PROTECTED]>
#
# Copyright (C) Secret Lab Technologies Ltd. 2006. All rights reserved.
#
# This source code is licensed under version 2 of the GNU General Public
# License,

from string import upper, strip
from pprint import pprint
from sys import argv


class mhs_file(object):
	def __init__(self, filename=None):
		self.clear()
		if filename:
			self.parsefile(filename)
	
	def clear(self):
		self.blocks = []
		self.buses = {}
		self.ports = {}

	def _add_to_port(self, port, block):
		port = port.upper()
		if port not in self.ports:
			self.ports[port] = []
		self.ports[port].append(block)

	def _add_to_bus(self, bus, block):
		bus = bus.upper()
		if bus not in self.buses:
			self.buses[bus] = []
		self.buses[bus].append(block)

	def _add_property(self, type, key, value):
		type = type.upper()
		if type not in self._curr_block:
			self._curr_block[type] = {}
		self._curr_block[type][key] = value

		if type == 'PARAMETER' and key == 'INSTANCE':
			self._curr_block['name'] = value
		if type == 'PORT':
			self._add_to_port(value, self._curr_block)
		if type == 'BUS_INTERFACE':
			self._add_to_bus(value, self._curr_block)

	def parse(self, file):
		state = "idle"
		for l in file:
			toks = l.split('#')[0].strip().split(None, 3)
			if not toks:
				continue
			if state == 'idle':
				if toks[0].upper() == 'BEGIN':
					state = 'block'
					self._curr_block = {'type': toks[1]}
			elif state == 'block':
				if toks[0].upper() == 'END':
					state = 'idle'
					self.blocks.append(self._curr_block)
					del self._curr_block
					continue
				self._add_property(toks[0], toks[1], toks[3])

	def parsefile(self, filename):
		f = open(filename)
		self.parse(f)
		f.close()

	_cpu_types = ('ppc405_virtex4', 'ppc405_virtex2pro')
	def find_root_cpu(self, name=None):
		for block in self.blocks:
			if block['type'] not in self._cpu_types:
				continue
			if name and name != block['name']:
				continue
			return block
		return None

	def find_root_bus(self):
		root_cpu = self.find_root_cpu()
		
		dplb_name = root_cpu['BUS_INTERFACE']['DPLB']
		iplb_name = root_cpu['BUS_INTERFACE']['IPLB']
		if (dplb_name != iplb_name):
			print "seperate instr and data busses, " + \
			      "I don't know what to do with this"
			return None

		dplb_data = self.find_instance(dplb_name)
		if not dplb_data:
			print 'Could not find bus \'%s\''%dplb_name

		return dplb_data

	def find_instance(self, name):
		for block in self.blocks:
			if name == block['name']:
				return block
		return None

	def find_types(self, type):
		bl = []
		for block in self.blocks:
			if type == block['type']:
				bl.append(block)
		return bl

	def find_port(self, port):
		bl = []
		for block in self.blocks:
			if 'PORT' not in block:
				continue
			for p in block['PORT']:
				if block['PORT'][p] == port:
					bl.append(block)
					break
		return bl

	def find_bus_attachments(self, bus):
		blocks = []
		for block in self.blocks:
			if 'BUS_INTERFACE' not in block:
				continue
			for bk in block['BUS_INTERFACE'].keys():
				if block['BUS_INTERFACE'][bk] == bus:
					blocks.append(block)
					break
		return blocks

def of_add_cpu(of_node, mhs, cpu_data):
	cpu_node = {'device_type': 'cpu', 'reg': 0,
	           'd-cache-line-size': 0x20, 'd-cache-size': 0x4000,
	           'i-cache-line-size': 0x20, 'i-cache-size': 0x4000,
	           '32-bit': None}
	#cpu_node['.mhs-private-data'] = cpu_data
	cpu_name = cpu_data['name'] + ',405'
	of_node[cpu_name + '@%s'%of_node['#cpus']] = cpu_node
	of_node['#cpus'] = of_node['#cpus'] + 1

def of_add_device(of_node, mhs, dev_data):
	if 'of_node' in dev_data.keys():
		return
	dev_node = {'device_type': dev_data['type'] }
	params = dev_data['PARAMETER']

	# Construct compatible property
	compat = []
	compat.append(dev_data['type'] + '_' + params['HW_VER'])
	compat.append(dev_data['type'])
	if dev_data['type'] in ('opb_uart16550', 'plb_opb_uart16550'):
		compat.append('ns16550')
	dev_node['compatible'] = "\\0".join(compat)

	# Get address ranges
	for key in params.keys():
		if key.upper().endswith('_BASEADDR'):
			basekey = key
		if key.upper().endswith('_HIGHADDR'):
			highkey = key
	if not basekey or not highkey:
		pprint(dev_data)
		return
	start = int(params[basekey], 16)
	end = int(params[highkey], 16)

	if 'ranges' in of_node.keys():
		start = start - of_node['ranges'][1] + of_node['ranges'][0]

	# Hack to only use sane ranges
	if start > 0 and end > 0 and start < 0x100000000:
		dev_node['reg'] = (start, end - start + 1)

	# Add the node
	if start < 0 or start >= 0x100000000:
		start = 0

	# *HACK* Some node names are too long; don't use the address for now...
	#of_node[dev_data['name'] + '@%x'%start] = dev_node
	of_node[dev_data['name']] = dev_node

	dev_data['of_node'] = dev_node

def of_add_opb_bridge(of_node, mhs, bridge_data):
	if 'of_node' in bridge_data.keys():
		return
	bridge_node = {}

	# Get translation address ranges
	params = bridge_data['PARAMETER']
	for key in params.keys():
		if key.upper().endswith('_BASEADDR'):
			basekey = key
		if key.upper().endswith('_HIGHADDR'):
			highkey = key
	if not basekey or not highkey:
		pprint(dev_data)
		return
	start = int(params[basekey], 0)
	end = int(params[highkey], 0)
	bridge_node['ranges'] = (0, start, end - start + 1)

	bus_name = bridge_data['BUS_INTERFACE']['MOPB']
	bus_data = mhs.find_instance(bus_name)

	of_node[bridge_data['name'] + '@%x'%start] = bridge_node
	bridge_data['of_node'] = bridge_node

	of_add_bus(bridge_node, mhs, bus_data)

def of_add_bus(of_node, mhs, bus_data):
	bus_name = bus_data['name']
	for block in mhs.find_bus_attachments(bus_name):
		if block['type'] in ('ppc405_virtex4', 'ppc405_virtex2pro'):
			of_add_cpu(of_node['cpus'], mhs, block)
		elif block['type'] in ('plb2opb_bridge',):
			of_add_opb_bridge(of_node, mhs, block)
		else:
			of_add_device(of_node, mhs, block)

def of_link_interrupts(of_node, mhs):
	phandle = 0x100
	for block in mhs.find_types('opb_intc'):
		phandle = phandle + 1
		if 'of_node' not in block:
			continue

		block['of_node']['linux,phandle'] = phandle
		irqnum = 0
		for irq_line in block['PORT']['Intr'].split('&'):
			devices = mhs.find_port(irq_line.strip())
			for b in devices:
				if 'of_node' not in b:
					continue
				b['of_node']['interrupt-parent'] = phandle
				b['of_node']['interrupts'] = (irqnum, 0)
			irqnum = irqnum + 1

def of_build_tree (mhs, mhs_root_bus):
	cpus_node = {'#cpus': (0), '#address-cells': (1), '#size-cells': (0)}
	of_tree = {'#address-cells': (1), '#size-cells': (1), 'cpus': cpus_node}

	of_add_bus(of_tree, mhs, mhs_root_bus)

	of_link_interrupts(of_tree, mhs)

	return of_tree

def of_print_tree (of_node, name = '/', indent=0):
	prefix = '\t'*indent
	print prefix + name, '{'

	# Print properties first
	for key in of_node.keys():
		val = of_node[key]
		if type(val) == str:
			print prefix + '\t' + key, '= "'+val+'" ;'
		if type(val) == int:
			print prefix + '\t' + key, '=', '<%x>;'%val
		if type(val) == list or type(val) == tuple:
			print prefix + '\t' + key, '=', '<',
			for i in val:
				print '%x'%i,
			print '>;'

	# print sub nodes second
	for key in of_node.keys():
		val = of_node[key]
		if type(val) == dict:
			of_print_tree(val, key, indent+1)
	print prefix + '} ;'

mhs = mhs_file(argv[1])
root = mhs.find_root_bus()
of_tree = of_build_tree(mhs, root)
#pprint(of_tree)
of_print_tree(of_tree)

_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

Reply via email to