Hi Matthew,
On 06/08/2016 11:56 PM, mgerlach wrote:
> Hi Everyone,
>
> This discussion of creating device trees especially in the context of
> upgrading linux is extremely relevant. I have experienced my fair of pain
> debugging device trees during kernel upgrades, and this pain is a frequent
> topic
> at the various Linux conferences. It is safe to say, this problem is not
> unique to SOCFGPAs, but the FPGA can make the pain more acute.
>
> As some background, sopc2dts is an Open Source tool that can help make
> device
> trees based on a FPGA designs described in a "sopcinfo" file produced by
> Altera design tools. Sopc2dts predates SOCFPGAs and was created by
> Walter Goossen originally for Linux running on Nios-II. Sopc2dts can
> also be used to make device trees for SOCFPGAs, but as many folks have
> pointed out, the output of sopc2dts does not always produce suitable
> device
> trees for every version of the Linux kernel.
>
> The SoC Embedded Development Suite (SoCEDS) includes a snapshot of
> sopc2dts and
> a set of "board info" files that can be used to create device trees for
> the
> the reference designs using the kernel version shipped with that version
> of SoCEDS. Version 16.0 of SoCEDS shipped with linux-3.10-ltsi.
>
> When upgrading kernels, the process people have described by taking the
> base
> device tree found in the kernel version's source tree and merging it with
> the FPGA portion of the output to Sopc2dts is a perfectly reasonable work
> flow. Interestingly, this work flow has similarities to using dynamic
> device tree overlays in the boot flow.
>
> With dynamic device tree overlays, Linux could boot using the minimum
> device
> tree to get to user space. Once in user space, one or more overlays could
> be
> applied to the live device tree in order to enable more components on the
> SoC,
> program the FPGA, and instantiate necessary drivers for components in the
> FPGA.
> I think such a boot flow would be easier to debug and provide substantial
> flexibility to manage the overall boot flow. I would like to hear what
> other folks think about using dynamic device tree overlays.
I also think overlays are the way to go. I actually posted a patch to
sopc2dts a year ago with initial support for this. I currently have no
active projects in which I can easily try this, but if you or anyone
else has the time to look at it that would be awesome.
I'll attach the patch to this mail as well. I haven't tested it but it
still applies and nothing much has changed in the last year so I think
we should be good.
Let me know what you think!
Walter
> Matthew Gerlach
>
diff --git a/Sopc2DTS.java b/Sopc2DTS.java
index da701df..115d328 100644
--- a/Sopc2DTS.java
+++ b/Sopc2DTS.java
@@ -58,6 +58,7 @@ public class Sopc2DTS implements LogListener {
protected CLParameter bridgeRemoval = new CLParameter("balanced");
protected CLParameter outputFileName = new CLParameter("");
protected CLParameter outputType = new CLParameter("dts");
+ protected CLParameter overlayTarget = new CLParameter("");
protected CLParameter pov = new CLParameter("");
protected CLParameter povType = new CLParameter("cpu");
protected CLParameter bootargs = new CLParameter("");
@@ -114,8 +115,9 @@ public class Sopc2DTS implements LogListener {
vOptions.add(new CommandLineOption("no-timestamp", null, excludeTimeStamp, false, false, "Don't add a timestamp to generated files", null));
vOptions.add(new CommandLineOption("input", "i", inputFileName, true, true, "The sopcinfo file (optional in gui mode)", "sopcinfo file"));
vOptions.add(new CommandLineOption("output", "o", outputFileName, true, false,"The output filename","filename"));
+ vOptions.add(new CommandLineOption("overlay-target",null, overlayTarget,true, false,"Target node for dt-overlay","node-label"));
vOptions.add(new CommandLineOption("pov", "p", pov, true, false,"The point of view to generate from. Defaults to the first cpu found", "component name"));
- vOptions.add(new CommandLineOption("pov-type", null, povType, true, false,"The point of view device type", "{cpu,pci}"));
+ vOptions.add(new CommandLineOption("pov-type", null, povType, true, false,"The point of view device type", "{cpu,pci,overlay}"));
vOptions.add(new CommandLineOption("reset", null, showReset, false,false,"Show reset interfaces in graph", null));
vOptions.add(new CommandLineOption("sort", "s", sort, true, false,"Sort components by", "{none,address,name,label}"));
vOptions.add(new CommandLineOption("streaming", null, showStreaming, false,false,"Show streaming interfaces in graph", null));
@@ -154,6 +156,7 @@ public class Sopc2DTS implements LogListener {
bInfo = new BoardInfo();
}
SICBridge.setRemovalStrategy(bridgeRemoval.value);
+ bInfo.setOverlayTarget(overlayTarget.value);
if(pov.value.length()>0)
{
bInfo.setPov(pov.value);
diff --git a/sopc2dts/generators/DTGenerator.java b/sopc2dts/generators/DTGenerator.java
index b88450c..70cb599 100644
--- a/sopc2dts/generators/DTGenerator.java
+++ b/sopc2dts/generators/DTGenerator.java
@@ -21,6 +21,7 @@ package sopc2dts.generators;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.Vector;
import sopc2dts.Logger;
@@ -58,73 +59,60 @@ public abstract class DTGenerator extends AbstractSopcGenerator {
super(s, isText);
}
- protected synchronized DTNode getDTOutput(BoardInfo bi)
+ protected synchronized DTNode getDTOutput(BoardInfo bi) {
+ return getDTOutput(bi, bi.getPovType().equals(PovType.OVERLAY));
+ }
+
+ protected synchronized DTNode getDTOutput(BoardInfo bi, boolean doAddSymbolsNode)
{
vHandled = new Vector<BasicComponent>();
DTNode rootNode = new DTNode("/");
BasicComponent povComponent = getPovComponent(bi);
- DTNode sopcNode;
- DTNode chosenNode;
- DTNode clocksNode = null;
if(povComponent!=null)
{
+ DTNode sopcNode = null;
+ DTNode chosenNode = null;
+ DTNode clocksNode = null;
int addrCells = povComponent.getInterfaces(SystemDataType.MEMORY_MAPPED, true).firstElement().getPrimaryWidth();
int sizeCells = povComponent.getInterfaces(SystemDataType.MEMORY_MAPPED, true).firstElement().getSecondaryWidth();
- if(bi.getPovType().equals(PovType.CPU))
- {
- DTNode cpuNode = getCpuNodes(bi, povComponent);
- DTNode memNode = getMemoryNode(bi, povComponent, addrCells, sizeCells);
- DTNode aliasNode = null;
- sopcNode = new DTNode("sopc@0", "sopc0");
- chosenNode = getChosenNode(bi);
- clocksNode = getClocksNode(bi);
- rootNode.addProperty(new DTProperty("model","ALTR," + sys.getSystemName()));
- rootNode.addProperty(new DTProperty("compatible","ALTR," + sys.getSystemName()));
- rootNode.addProperty(new DTProperty("#address-cells", (long)addrCells));
- rootNode.addProperty(new DTProperty("#size-cells",(long)sizeCells));
- Vector<Parameter> vAliases = bi.getAliases();
- if (vAliases.size() > 0) {
- aliasNode = new DTNode("aliases");
- for (Parameter p : vAliases) {
- aliasNode.addProperty(new DTProperty(p.getName(),p.getValue()));
+ switch(bi.getPovType()) {
+ case CPU: {
+ DTNode cpuNode = getCpuNodes(bi, povComponent);
+ DTNode memNode = getMemoryNode(bi, povComponent, addrCells, sizeCells);
+ sopcNode = new DTNode("sopc@0", "sopc0");
+ DTNode aliasNode = getAliasNode(bi, povComponent,"/" + sopcNode.getName());
+ chosenNode = getChosenNode(bi);
+ clocksNode = getClocksNode(bi);
+ rootNode.addProperty(new DTProperty("model","ALTR," + sys.getSystemName()));
+ rootNode.addProperty(new DTProperty("compatible","ALTR," + sys.getSystemName()));
+ rootNode.addProperty(new DTProperty("#address-cells", (long)addrCells));
+ rootNode.addProperty(new DTProperty("#size-cells",(long)sizeCells));
+ if(aliasNode!=null) {
+ rootNode.addChild(aliasNode);
}
+ rootNode.addChild(cpuNode);
+ rootNode.addChild(memNode);
+ sopcNode.addProperty(new DTProperty("device_type", "soc"));
+ } break;
+ case OVERLAY: {
+ DTNode fragmentNode = new DTNode("fragment@0");
+ fragmentNode.addProperty(new DTProperty("target", new DTPropPHandleVal(bi.getOverlayTarget())));
+ sopcNode = new DTNode("__overlay__");
+ fragmentNode.addChild(sopcNode);
+ rootNode.addChild(fragmentNode);
+ } break;
+ case PCI: {
+ sopcNode = rootNode;
+ DTProperty rangeProp = new DTProperty("ranges");
+ rangeProp.addHexValues(new long[] {
+ 0x00000000,
+ 0x02000000, 0, 0x90000000,
+ 0x10000000,
+ });
+ sopcNode.addProperty(rangeProp);
}
- vAliases = bi.getAliasRefs();
- if (vAliases.size() > 0) {
- if(aliasNode==null) {
- aliasNode = new DTNode("aliases");
- }
- for (Parameter p : vAliases) {
- BasicComponent slave = sys.getComponentByName(p.getValue());
- if(slave!=null) {
- Vector<Connection> vConn = sys.getConnectionPath(povComponent, slave,SystemDataType.MEMORY_MAPPED);
- String path="/" + sopcNode.getName();
- for(Connection c : vConn) {
- path += "/" + c.getSlaveModule().getScd().getGroup() + "@" + DTHelper.longArrToHexString(c.getConnValue());
- }
- if(path.length()>0) {
- aliasNode.addProperty(new DTProperty(p.getName(),path));
- } else {
- Logger.logln(this, "Failed to find component '" + p.getValue() +"' path for alias: " + p.getName(), LogLevel.WARNING);
- }
- } else {
- Logger.logln(this, "Failed to find component '" + p.getValue() +"' for alias: " + p.getName(), LogLevel.WARNING);
- }
- }
- }
-
- if(aliasNode!=null) {
- rootNode.addChild(aliasNode);
- }
- rootNode.addChild(cpuNode);
- rootNode.addChild(memNode);
- sopcNode.addProperty(new DTProperty("device_type", "soc"));
- } else {
- sopcNode = rootNode;
- chosenNode = null;
}
sopcNode = getSlavesFor(bi, povComponent, sopcNode);
- sopcNode.addProperty(new DTProperty("ranges"));
sopcNode.addProperty(new DTProperty("#address-cells",(long)addrCells));
sopcNode.addProperty(new DTProperty("#size-cells",(long)sizeCells));
Vector<String> vCompat = new Vector<String>();
@@ -132,13 +120,21 @@ public abstract class DTGenerator extends AbstractSopcGenerator {
vCompat.add("simple-bus");
sopcNode.addProperty(new DTProperty("compatible", vCompat.toArray(new String[]{})));
sopcNode.addProperty(new DTProperty("bus-frequency", povComponent.getClockRate()));
+ rootNode.addChild(clocksNode);
if(bi.getPovType().equals(PovType.CPU))
{
- if(clocksNode!=null) {
- rootNode.addChild(clocksNode);
- }
rootNode.addChild(sopcNode);
- rootNode.addChild(chosenNode);
+ }
+ rootNode.addChild(chosenNode);
+ if(doAddSymbolsNode) {
+ HashMap<String,String> symbolMap = getSymbols(bi, rootNode, "");
+ if(!symbolMap.isEmpty()) {
+ DTNode symbolsNode = new DTNode("__symbols__");
+ for(String key : symbolMap.keySet()) {
+ symbolsNode.addProperty(new DTProperty(key, symbolMap.get(key)));
+ }
+ rootNode.addChild(symbolsNode);
+ }
}
}
doDTAppend(rootNode,bi);
@@ -251,6 +247,41 @@ public abstract class DTGenerator extends AbstractSopcGenerator {
}
}
+ DTNode getAliasNode(BoardInfo bi, BasicComponent povComp, String basePath)
+ {
+ DTNode aliasNode = null;
+ Vector<Parameter> vAliases = bi.getAliases();
+ if (vAliases.size() > 0) {
+ aliasNode = new DTNode("aliases");
+ for (Parameter p : vAliases) {
+ aliasNode.addProperty(new DTProperty(p.getName(),p.getValue()));
+ }
+ }
+ vAliases = bi.getAliasRefs();
+ if (vAliases.size() > 0) {
+ if(aliasNode==null) {
+ aliasNode = new DTNode("aliases");
+ }
+ for (Parameter p : vAliases) {
+ BasicComponent slave = sys.getComponentByName(p.getValue());
+ if(slave!=null) {
+ Vector<Connection> vConn = sys.getConnectionPath(povComp, slave,SystemDataType.MEMORY_MAPPED);
+ String path=basePath;
+ for(Connection c : vConn) {
+ path += "/" + c.getSlaveModule().getScd().getGroup() + "@" + DTHelper.longArrToHexString(c.getConnValue());
+ }
+ if(path.length()>0) {
+ aliasNode.addProperty(new DTProperty(p.getName(),path));
+ } else {
+ Logger.logln(this, "Failed to find component '" + p.getValue() +"' path for alias: " + p.getName(), LogLevel.WARNING);
+ }
+ } else {
+ Logger.logln(this, "Failed to find component '" + p.getValue() +"' for alias: " + p.getName(), LogLevel.WARNING);
+ }
+ }
+ }
+ return aliasNode;
+ }
DTNode getChosenNode(BoardInfo bi)
{
DTNode chosenNode = new DTNode("chosen");
@@ -395,7 +426,7 @@ public abstract class DTGenerator extends AbstractSopcGenerator {
return memNode;
}
}
-
+
DTNode getSlavesFor(BoardInfo bi, BasicComponent masterComp, DTNode masterNode)
{
if(masterComp!=null)
@@ -424,6 +455,19 @@ public abstract class DTGenerator extends AbstractSopcGenerator {
}
return masterNode;
}
+ HashMap<String,String> getSymbols(BoardInfo bi, DTNode rootNode, String basePath)
+ {
+ HashMap<String,String> symbolMap = new HashMap<String, String>();
+ for(DTNode child : rootNode.getChildren()) {
+ if(child.getLabel()!=null) {
+ symbolMap.put(child.getLabel(), basePath + "/" + child.getName());
+ }
+ if(!child.getChildren().isEmpty()) {
+ symbolMap.putAll(getSymbols(bi, child, basePath + "/" + child.getName()));
+ }
+ }
+ return symbolMap;
+ }
protected static void sortSlaves(Vector<Connection> vConn, final SortType sort) {
if(!sort.equals(SortType.NONE)) {
Collections.sort(vConn, new Comparator<Connection>() {
diff --git a/sopc2dts/generators/DTSGenerator2.java b/sopc2dts/generators/DTSGenerator2.java
index aa67ff1..ca53822 100644
--- a/sopc2dts/generators/DTSGenerator2.java
+++ b/sopc2dts/generators/DTSGenerator2.java
@@ -1,7 +1,7 @@
/*
sopc2dts - Devicetree generation for Altera systems
-Copyright (C) 2012 Walter Goossens <[email protected]>
+Copyright (C) 2012 - 2015 Walter Goossens <[email protected]>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -21,6 +21,7 @@ package sopc2dts.generators;
import sopc2dts.lib.AvalonSystem;
import sopc2dts.lib.BoardInfo;
+import sopc2dts.lib.BoardInfo.PovType;
import sopc2dts.lib.devicetree.DTNode;
public class DTSGenerator2 extends DTGenerator {
@@ -33,6 +34,9 @@ public class DTSGenerator2 extends DTGenerator {
public String getTextOutput(BoardInfo bi) {
String res = getSmallCopyRightNotice("devicetree", bi.isIncludeTime())
+ "/dts-v1/;\n";
+ if(bi.getPovType() == PovType.OVERLAY) {
+ res += "/plugin/;\n";
+ }
DTNode rootNode = getDTOutput(bi);
res += rootNode.toString();
return res;
diff --git a/sopc2dts/lib/BoardInfo.java b/sopc2dts/lib/BoardInfo.java
index 1c5093c..9e054f6 100644
--- a/sopc2dts/lib/BoardInfo.java
+++ b/sopc2dts/lib/BoardInfo.java
@@ -47,7 +47,7 @@ import sopc2dts.lib.components.BasicComponent;
import sopc2dts.lib.components.base.FlashPartition;
public class BoardInfo implements ContentHandler {
- public enum PovType { CPU, PCI };
+ public enum PovType { CPU, PCI, OVERLAY };
public enum SortType { NONE, ADDRESS, NAME, LABEL };
public enum RangesStyle { NONE, FOR_BRIDGE, FOR_EACH_CHILD };
public enum AltrStyle { AUTO, FORCE_UPPER, FORCE_LOWER };
@@ -71,6 +71,7 @@ public class BoardInfo implements ContentHandler {
String bootArgs;
BoardInfoComponent currBic;
private AltrStyle altrStyle = AltrStyle.AUTO;
+ private String overlayTarget = "";
private String pov = "";
private PovType povType = PovType.CPU;
private RangesStyle rangesStyle = RangesStyle.FOR_EACH_CHILD;
@@ -352,6 +353,8 @@ public class BoardInfo implements ContentHandler {
povTypeName.equalsIgnoreCase("pcie"))
{
setPovType(PovType.PCI);
+ } else if(povTypeName.equalsIgnoreCase("overlay")) {
+ setPovType(PovType.OVERLAY);
}
}
public void setRangesStyle(RangesStyle rangesStyle) {
@@ -382,6 +385,9 @@ public class BoardInfo implements ContentHandler {
setSortType(SortType.NONE);
}
}
+ public String getOverlayTarget() {
+ return overlayTarget;
+ }
public void setPartitionsForchip(String instanceName, Vector<FlashPartition> vParts) {
mFlashPartitions.put(instanceName, vParts);
}
@@ -541,4 +547,7 @@ public class BoardInfo implements ContentHandler {
public void setIncludeTime(boolean includeTime) {
this.includeTime = includeTime;
}
+ public void setOverlayTarget(String overlayTarget) {
+ this.overlayTarget = overlayTarget;
+ }
}
_______________________________________________
Rfi mailing list
[email protected]
http://lists.rocketboards.org/cgi-bin/mailman/listinfo/rfi