summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDean Sanner <dsanner@us.ibm.com>2013-10-08 14:48:49 -0500
committerA. Patrick Williams III <iawillia@us.ibm.com>2013-10-10 21:53:56 -0500
commit4541c4a6046f2c8c325e4ef8b277b8da25bbec4e (patch)
tree83e6fac89ded5dd30496c7295aaa410645c44114 /src
parent1a6ffb4281f186e1b6d08aff1163f55770e7a810 (diff)
downloadtalos-hostboot-4541c4a6046f2c8c325e4ef8b277b8da25bbec4e.tar.gz
talos-hostboot-4541c4a6046f2c8c325e4ef8b277b8da25bbec4e.zip
Updates to devtree for Stradale BU
Change-Id: I5d38b819d50e2f68e2d3b0de5ec3f020c49a9fc6 Reviewed-on: http://gfw160.austin.ibm.com:8080/gerrit/6559 Tested-by: Jenkins Server Reviewed-by: A. Patrick Williams III <iawillia@us.ibm.com>
Diffstat (limited to 'src')
-rwxr-xr-xsrc/build/tools/addCopyright.pl18
-rw-r--r--src/usr/devtree/bld_devtree.C586
-rw-r--r--src/usr/devtree/devtree.C47
-rw-r--r--src/usr/devtree/devtree.H14
-rw-r--r--src/usr/devtree/dt_doc_v0.2.txt512
5 files changed, 998 insertions, 179 deletions
diff --git a/src/build/tools/addCopyright.pl b/src/build/tools/addCopyright.pl
index fd984a9ba..9b3107c72 100755
--- a/src/build/tools/addCopyright.pl
+++ b/src/build/tools/addCopyright.pl
@@ -259,6 +259,20 @@ foreach ( @Files )
next;
}
+ ##
+ ## text files are valid, but should generate a warning.
+ if ("txt" eq $filetype)
+ {
+ print STDOUT "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
+ print STDOUT "WARNING:: File $_ : Filetype: $filetype\n";
+ print STDOUT " Skipping this file and continuing.\n";
+ print STDOUT " If needed, Please add the copyright \n";
+ print STDOUT " prolog manually.\n";
+ print STDOUT "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
+
+ next;
+ }
+
## extract the existing copyright block
( $DelimiterBegin, $CopyrightBlock, $DelimiterEnd ) = extractCopyrightBlock( $_ );
@@ -415,6 +429,10 @@ sub filetype
{
return "xml"
}
+ if ( $filename =~ m/\.txt$/i )
+ {
+ return "txt"
+ }
if ( ( $filename =~ m/\.[cht]$/i )
||( $filename =~ m/\.[cht]\+\+$/i )
||( $filename =~ m/\.[cht]pp$/i )
diff --git a/src/usr/devtree/bld_devtree.C b/src/usr/devtree/bld_devtree.C
index 85d2d0773..3dc7f96d6 100644
--- a/src/usr/devtree/bld_devtree.C
+++ b/src/usr/devtree/bld_devtree.C
@@ -53,6 +53,9 @@ namespace DEVTREE
{
using namespace TARGETING;
+#define CHIPID_EXTRACT_NODE(i_chipid) (i_chipid >> CHIPID_NODE_SHIFT)
+#define CHIPID_EXTRACT_PROC(i_chipid) (i_chipid & CHIPID_PROC_MASK)
+
enum BuildConstants
{
DEVTREE_DATA_ADDR =0xFF00000, /* 256MB - 1MB*/
@@ -60,37 +63,225 @@ enum BuildConstants
XSCOM_NODE_SHIFT =38, /*Node pos is 25, so 63-25=38*/
XSCOM_CHIP_SHIFT =35, /*Chip pos is 28, so 63-28=35*/
CHIPID_NODE_SHIFT =3, /*CHIPID is NNNCCC, shift 3*/
+ CHIPID_PROC_MASK =0x7, /*CHIPID is NNNCCC, shift 3*/
PHB0_MASK =0x80,
- MAX_PHBs = 3, /*Max PHBs per chip is 3*/
+ MAX_PHBs =3, /*Max PHBs per chip is 3*/
+ THREADPERCORE =8, /*8 threads per core*/
+ MHZ =1000000,
+
+ /* The Cache unit address (and reg property) is mostly free-for-all
+ * as long as there is no collisions. On HDAT machines we use the
+ * following encoding which I encourage you to also follow to limit
+ * surprises:
+ *
+ * L2 : (0x20 << 24) | PIR (PIR is PIR value of thread 0 of core)
+ * L3 : (0x30 << 24) | PIR
+ * L3.5 : (0x35 << 24) | PIR */
+ L2_HDR = (0x20 << 24),
+ L3_HDR = (0x30 << 24),
};
-errlHndl_t bld_fdt_cpu(devTree * i_dt)
+
+uint32_t getProcChipId(const TARGETING::Target * i_pProc)
+{
+ uint32_t l_fabId = i_pProc->getAttr<TARGETING::ATTR_FABRIC_NODE_ID>();
+ uint32_t l_procPos = i_pProc->getAttr<TARGETING::ATTR_FABRIC_CHIP_ID>();
+ return ( (l_fabId << CHIPID_NODE_SHIFT) + l_procPos);
+}
+
+uint64_t getHomerPhysAddr(const TARGETING::Target * i_pProc)
+{
+ //If running Sapphire need to place this at the top of memory
+ uint64_t homerPhysAddrBase = VMM_HOMER_REGION_START_ADDR;
+ if(TARGETING::is_sapphire_load())
+ {
+ homerPhysAddrBase = TARGETING::get_top_mem_addr();
+ assert (homerPhysAddrBase != 0,
+ "bld_devtree: Top of memory was 0!");
+ homerPhysAddrBase -= VMM_ALL_HOMER_OCC_MEMORY_SIZE;
+ }
+
+ uint8_t tmpPos = i_pProc->getAttr<ATTR_POSITION>();
+ uint64_t tmpOffset = tmpPos*VMM_HOMER_INSTANCE_SIZE;
+ uint64_t targHomer = homerPhysAddrBase + tmpOffset;
+
+ TRACFCOMP( g_trac_devtree, "proc ChipID [%X] HOMER is at %.16X",
+ getProcChipId(i_pProc), targHomer );
+
+ return targHomer;
+}
+
+
+void bld_xscom_node(devTree * i_dt, dtOffset_t & i_parentNode,
+ const TARGETING::Target * i_pProc, uint32_t i_chipid)
{
- errlHndl_t errhdl = NULL;
- const char* cpuNodeName = "PowerPC,POWER8";
- const char* cpuIntrName = "interrupt-controller";
const char* xscomNodeName = "xscom";
const char* todNodeName = "chiptod";
const char* pciNodeName = "pbcq";
- const char* lpcNodeName = "lpc";
- const uint32_t THREADPERCORE = 8;
-
- /* Find the / node and add a cpus node under it. */
- dtOffset_t rootNode = i_dt->findNode("/");
- dtOffset_t cpusNode = i_dt->addNode(rootNode, "cpus");
// Grab a system object to work with
TARGETING::Target* sys = NULL;
TARGETING::targetService().getTopLevelTarget(sys);
+
uint64_t l_xscomBaseAddr =
sys->getAttr<TARGETING::ATTR_XSCOM_BASE_ADDRESS>();
+ /**********************************************************/
+ /* Xscom node */
+ /**********************************************************/
+ uint64_t l_xscomAddr = l_xscomBaseAddr +
+ (static_cast<uint64_t>(i_chipid) << XSCOM_CHIP_SHIFT);
+
+ dtOffset_t xscomNode = i_dt->addNode(i_parentNode, xscomNodeName,
+ l_xscomAddr);
+
+ i_dt->addPropertyCell32(xscomNode, "#address-cells", 1);
+ i_dt->addPropertyCell32(xscomNode, "#size-cells", 1);
+ i_dt->addProperty(xscomNode, "scom-controller");
+ const char* xscom_compatStrs[] = {"ibm,xscom","ibm,power8-xscom",NULL};
+ i_dt->addPropertyStrings(xscomNode, "compatible", xscom_compatStrs);
+
+ i_dt->addPropertyCell32(xscomNode, "ibm,chip-id", i_chipid);
+
+ uint64_t xscom_prop[2] = { l_xscomAddr, THIRTYTWO_GB};
+ i_dt->addPropertyCells64(xscomNode, "reg", xscom_prop, 2);
+
+ /*MVPD -- TODO RTC 88002 add full MVPD here*/
+ //i_dt->addPropertyBytes(xscomNode, "ibm,module-vpd", ....);
+
+ /*PSI Host Bridge*/
+ uint32_t l_psiInfo = 0x2010900; /*PSI Host Bridge Scom addr*/
+ dtOffset_t psiNode = i_dt->addNode(xscomNode, "psihb", l_psiInfo);
+ const char* psi_compatStrs[] = {"ibm,power8-psihb-x",
+ "ibm,psihb-x", NULL};
+ i_dt->addPropertyStrings(psiNode, "compatible", psi_compatStrs);
+ uint32_t psi_prop[2] = { l_psiInfo, 0x20 }; //# of scoms in range
+ i_dt->addPropertyCells32(psiNode, "reg", psi_prop, 2);
+ i_dt->addPropertyString(psiNode, "status", "ok");
+
+ /*ChipTod*/
+ uint32_t l_todInfo = 0x40000; /*Chip tod Scom addr*/
+ dtOffset_t todNode = i_dt->addNode(xscomNode, todNodeName, l_todInfo);
+ const char* tod_compatStrs[] = {"ibm,power-chiptod",
+ "ibm,power8-chiptod", NULL};
+ i_dt->addPropertyStrings(todNode, "compatible", tod_compatStrs);
+ uint32_t tod_prop[2] = { l_todInfo, 0x34 }; //# of scoms in range
+ i_dt->addPropertyCells32(todNode, "reg", tod_prop, 2);
+
+ if(i_chipid == 0x0) //Master chip
+ {
+ i_dt->addProperty(todNode, "primary"); //TODO RTC 88002
+
+ uint32_t l_lpcInfo = 0xB0020; /*ECCB FW addr*/
+ dtOffset_t lpcNode = i_dt->addNode(xscomNode,"lpc",l_lpcInfo);
+ i_dt->addPropertyString(lpcNode, "compatible", "ibm,power8-lpc");
+ uint32_t lpc_prop[2] = { l_lpcInfo, 0x4 }; //# of scoms in range
+ i_dt->addPropertyCells32(lpcNode, "reg", lpc_prop, 2);
+ i_dt->addPropertyCell32(lpcNode, "#address-cells", 2);
+ i_dt->addPropertyCell32(lpcNode, "#size-cells", 1);
+
+ }
+
+ /*NX*/
+ uint32_t l_nxInfo = 0x2010000; /*NX Scom addr*/
+ dtOffset_t nxNode = i_dt->addNode(xscomNode, "nx", l_nxInfo);
+ const char* nx_compatStrs[] = {"ibm,power-nx",
+ "ibm,power8-nx", NULL};
+ i_dt->addPropertyStrings(nxNode, "compatible", nx_compatStrs);
+ uint32_t nx_prop[2] = { l_nxInfo, 0x4000 }; //# of scoms in range
+ i_dt->addPropertyCells32(nxNode, "reg", nx_prop, 2);
- /* Add the # address & size cell properties to /cpus. */
- i_dt->addPropertyCell32(cpusNode, "#address-cells", 1);
- i_dt->addPropertyCell32(cpusNode, "#size-cells", 0);
+ /*PCIE*/
+ uint8_t l_phbActive =
+ i_pProc->getAttr<TARGETING::ATTR_PROC_PCIE_PHB_ACTIVE>();
+ //TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION_type l_laneEq =
+ // l_pProc->getAttr<TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION>();
+ uint32_t l_laneEq[] = {0,0,0,0};
+
+ TRACFCOMP( g_trac_devtree, "Chip %X PHB Active mask %X",
+ i_chipid, l_phbActive);
+
+ for(uint32_t l_phb =0; l_phb < MAX_PHBs; l_phb++)
+ {
+ if(!(l_phbActive & (PHB0_MASK>>l_phb)))
+ {
+ continue;
+ }
+
+ TRACFCOMP( g_trac_devtree, "Adding PHB %d", l_phb);
+
+ /*PHB is active, add to Xscom map*/
+ uint32_t l_peInfo = 0x02012000 + (l_phb * 0x400);
+ uint32_t l_pciInfo = 0x09012000 + (l_phb * 0x400);
+ uint32_t l_spciInfo = 0x09013c00 + (l_phb * 0x40);
+ dtOffset_t pcieNode = i_dt->addNode(xscomNode,pciNodeName,l_peInfo);
+ const char* pcie_compatStrs[] = {"ibm,power8-pbcq", NULL};
+ i_dt->addPropertyStrings(pcieNode, "compatible", pcie_compatStrs);
+ uint32_t pcie_prop[6] = { l_peInfo, 0x20, //# of scoms in range
+ l_pciInfo, 0x5, //# of scoms in range
+ l_spciInfo, 0x15}; //# of scoms in range
+ i_dt->addPropertyCells32(pcieNode, "reg", pcie_prop, 6);
+ i_dt->addPropertyCell32(pcieNode, "ibm,phb-index", l_phb);
+ i_dt->addProperty(pcieNode, "ibm,use-ab-detect");
+ i_dt->addPropertyCell32(pcieNode, "ibm,lane-eq", l_laneEq[l_phb]);
+ }
+}
+
+uint32_t bld_l3_node(devTree * i_dt, dtOffset_t & i_parentNode,
+ uint32_t i_pir)
+{
+ uint32_t l3Id = i_pir | L3_HDR;
+
+ /* Build L3 Cache information */
+ dtOffset_t l3Node = i_dt->addNode(i_parentNode, "l3-cache",l3Id);
+ i_dt->addPropertyString(l3Node, "device_type", "cache");
+ i_dt->addPropertyCell32(l3Node, "reg", l3Id);
+ i_dt->addProperty(l3Node, "cache-unified");
+ i_dt->addPropertyCell32(l3Node, "d-cache-sets", 0x8);
+ i_dt->addPropertyCell32(l3Node, "i-cache-sets", 0x8);
+ i_dt->addPropertyCell32(l3Node, "d-cache-size", 0x800000); //8MB
+ i_dt->addPropertyCell32(l3Node, "i-cache-size", 0x800000); //8MB
+ i_dt->addPropertyString(l3Node, "status", "okay");
+
+ return i_dt->getPhandle(l3Node);
+}
+
+uint32_t bld_l2_node(devTree * i_dt, dtOffset_t & i_parentNode,
+ uint32_t i_pir, uint32_t i_nextCacheHandle)
+{
+ uint32_t l2Id = i_pir | L2_HDR;
+
+ /* Build l2 Cache information */
+ dtOffset_t l2Node = i_dt->addNode(i_parentNode, "l2-cache",l2Id);
+ i_dt->addPropertyString(l2Node, "device_type", "cache");
+ i_dt->addPropertyCell32(l2Node, "reg", l2Id);
+ i_dt->addProperty(l2Node, "cache-unified");
+ i_dt->addPropertyCell32(l2Node, "d-cache-sets", 0x8);
+ i_dt->addPropertyCell32(l2Node, "i-cache-sets", 0x8);
+ i_dt->addPropertyCell32(l2Node, "d-cache-size", 0x80000); //512KB
+ i_dt->addPropertyCell32(l2Node, "i-cache-size", 0x80000); //512KB
+ i_dt->addPropertyString(l2Node, "status", "okay");
+ i_dt->addPropertyCell32(l2Node, "next-level-cache", i_nextCacheHandle);
+
+
+ return i_dt->getPhandle(l2Node);
+}
+
+uint32_t bld_cpu_node(devTree * i_dt, dtOffset_t & i_parentNode,
+ const TARGETING::Target * i_ex,
+ INTR::PIR_t i_pir, uint32_t i_chipId,
+ uint32_t i_nextCacheHandle)
+{
+ /*
+ * The following node must exist for each *core* in the system. The unit
+ * address (number after the @) is the hexadecimal HW CPU number (PIR value)
+ * of thread 0 of that core.
+ */
+
+ uint32_t paFeatures[8] = { 0x6, 0x0, 0xf6, 0x3f, 0xc7, 0x0, 0x80, 0xc0 };
+ uint32_t pageSizes[4] = { 0xc, 0x10, 0x18, 0x22 };
uint32_t segmentSizes[4] = { 0x1c, 0x28, 0xffffffff, 0xffffffff };
uint32_t segmentPageSizes[] =
{
@@ -110,87 +301,205 @@ errlHndl_t bld_fdt_cpu(devTree * i_dt)
};
- // Get all functional proc chip targets
- TARGETING::TargetHandleList l_cpuTargetList;
- getAllChips(l_cpuTargetList, TYPE_PROC);
+ dtOffset_t cpuNode = i_dt->addNode(i_parentNode, "PowerPC,POWER8",
+ i_pir.word);
+ i_dt->addPropertyString(cpuNode, "device_type", "cpu");
+ i_dt->addProperty(cpuNode, "64-bit");
+ i_dt->addProperty(cpuNode, "32-64-bridge");
+ i_dt->addProperty(cpuNode, "graphics");
+ i_dt->addProperty(cpuNode, "general-purpose");
+ i_dt->addPropertyString(cpuNode, "status", "okay");
+ i_dt->addPropertyCell32(cpuNode, "reg", i_pir.word);
+ i_dt->addPropertyCell32(cpuNode, "ibm,pir", i_pir.word);
+ i_dt->addPropertyCell32(cpuNode, "ibm,chip-id", i_chipId);
+
+ uint32_t interruptServerNum[THREADPERCORE];
+ for(size_t i = 0; i < THREADPERCORE ; i++)
+ {
+ i_pir.threadId = i;
+ interruptServerNum[i] = i_pir.word;
+ }
+ i_dt->addPropertyCells32(cpuNode, "ibm,ppc-interrupt-server#s",
+ interruptServerNum, THREADPERCORE);
+
+ /* This is the "architected processor version" as defined in PAPR. Just
+ * stick to 0x0f000004 for P8 and things will be fine */
+ i_dt->addPropertyCell32(cpuNode, "cpu-version", 0x0f000004);
+
+ i_dt->addPropertyCells32(cpuNode, "ibm,processor-segment-sizes",
+ segmentSizes,
+ sizeof(segmentSizes) / sizeof(uint32_t));
+ i_dt->addPropertyCells32(cpuNode, "ibm,processor-page-sizes",
+ pageSizes,
+ sizeof(pageSizes) / sizeof(uint32_t));
+ i_dt->addPropertyCells32(cpuNode, "ibm,segment-page-sizes",
+ segmentPageSizes,
+ sizeof(segmentPageSizes)/sizeof(uint32_t));
+ i_dt->addPropertyCells32(cpuNode, "ibm,pa-features",
+ paFeatures,
+ sizeof(paFeatures)/sizeof(uint32_t));
+
+ i_dt->addPropertyCell32(cpuNode, "ibm,slb-size", 32);
+ i_dt->addPropertyCell32(cpuNode, "ibm,dfp", 1);
+ i_dt->addPropertyCell32(cpuNode, "ibm,vmx", 2);
+ i_dt->addPropertyCell32(cpuNode, "ibm,purr", 1);
+ i_dt->addPropertyCell32(cpuNode, "ibm,spurr", 1);
+
+ //TODO RTC88002 -- move this to nominal once HB has nominal freq
+ TARGETING::Target* sys = NULL;
+ TARGETING::targetService().getTopLevelTarget(sys);
+ uint64_t freq = sys->getAttr<TARGETING::ATTR_BOOT_FREQ_MHZ>();
+ freq *= MHZ;
- for ( size_t proc = 0; (!errhdl) && (proc < l_cpuTargetList.size()); proc++)
+ uint32_t ex_freq[2] = {static_cast<uint32_t>(freq >> 32),
+ static_cast<uint32_t>(freq & 0xFFFFFFFF)};
+ if(ex_freq[0] == 0) //Only create if fits into 32 bits
{
- const TARGETING::Target * l_pProc = l_cpuTargetList[proc];
+ i_dt->addPropertyCell32(cpuNode, "clock-frequency", ex_freq[1]);
+ }
+ i_dt->addPropertyCells32(cpuNode, "ibm,extended-clock-frequency",
+ ex_freq, 2);
+
+ uint32_t timebase_freq[2] = {0, 512000000};
+ i_dt->addPropertyCell32(cpuNode, "timebase-frequency", timebase_freq[1]);
+ i_dt->addPropertyCells32(cpuNode, "ibm,extended-timebase-frequency",
+ timebase_freq, 2);
+
+
+ i_dt->addPropertyCell32(cpuNode, "reservation-granule-size", 0x80);
+ i_dt->addPropertyCell32(cpuNode, "d-tlb-size", 0x800);
+ i_dt->addPropertyCell32(cpuNode, "i-tlb-size", 0x0);
+ i_dt->addPropertyCell32(cpuNode, "tlb-size", 0x800);
+ i_dt->addPropertyCell32(cpuNode, "d-tlb-sets", 0x4);
+ i_dt->addPropertyCell32(cpuNode, "i-tlb-sets", 0x0);
+ i_dt->addPropertyCell32(cpuNode, "tlb-sets", 0x4);
+ i_dt->addPropertyCell32(cpuNode, "d-cache-block-size", 0x80);
+ i_dt->addPropertyCell32(cpuNode, "i-cache-block-size", 0x80);
+ i_dt->addPropertyCell32(cpuNode, "d-cache-size", 0x10000);
+ i_dt->addPropertyCell32(cpuNode, "i-cache-size", 0x8000);
+ i_dt->addPropertyCell32(cpuNode, "i-cache-sets", 0x4);
+ i_dt->addPropertyCell32(cpuNode, "d-cache-sets", 0x8);
+ i_dt->addPropertyCell64(cpuNode, "performance-monitor", 0x1);
+ i_dt->addPropertyCell32(cpuNode, "next-level-cache", i_nextCacheHandle);
+
+ return i_dt->getPhandle(cpuNode);
+}
- uint32_t l_fabId = l_pProc->getAttr<TARGETING::ATTR_FABRIC_NODE_ID>();
- uint32_t l_procPos = l_pProc->getAttr<TARGETING::ATTR_FABRIC_CHIP_ID>();
- uint32_t l_chipid = (l_fabId << CHIPID_NODE_SHIFT) + l_procPos;
+uint32_t bld_intr_node(devTree * i_dt, dtOffset_t & i_parentNode,
+ const TARGETING::Target * i_ex,
+ INTR::PIR_t i_pir)
- /* Find calculate the Xscom addr for this chip and add it */
- uint64_t l_xscomAddr = l_xscomBaseAddr +
- (static_cast<uint64_t>(l_chipid) << XSCOM_CHIP_SHIFT);
+{
+ /*
+ * Interrupt presentation controller (ICP) nodes
+ *
+ * There is some flexibility as to how many of these are presents since
+ * a given node can represent multiple ICPs. When generating from HDAT we
+ * chose to create one per core
+ */
+
+ uint64_t l_ibase = INTR::getIntpAddr(i_ex, 0); //IBASE ADDRESS
+
+ dtOffset_t intNode = i_dt->addNode(i_parentNode, "interrupt-controller",
+ l_ibase);
+
+ const char* intr_compatStrs[] = {"ibm,ppc-xicp", "ibm,power8-xicp",NULL};
+ i_dt->addPropertyStrings(intNode, "compatible", intr_compatStrs);
+ i_dt->addProperty(intNode,"interrupt-controller");
+ i_dt->addPropertyCell32(intNode, "#address-cells", 0);
+ i_dt->addPropertyCell32(intNode, "#interrupt-cells", 1);
+ i_dt->addPropertyString(intNode, "device_type",
+ "PowerPC-External-Interrupt-Presentation");
+
+ uint32_t int_serv[2] = { i_pir.word, THREADPERCORE};
+ i_dt->addPropertyCells32(intNode, "ibm,interrupt-server-ranges",
+ int_serv, 2);
+
+ uint64_t intr_prop[THREADPERCORE][2];
+ for(size_t i=0; i < THREADPERCORE; i++)
+ {
+ intr_prop[i][0] = INTR::getIntpAddr(i_ex, i);
+ intr_prop[i][1] = 0x1000;
+ }
+ i_dt->addPropertyCells64(intNode, "reg",
+ reinterpret_cast<uint64_t*>(intr_prop),
+ sizeof(intr_prop) / sizeof(uint64_t));
- dtOffset_t xscomNode = i_dt->addNode(rootNode, xscomNodeName,
- l_xscomAddr);
+ return i_dt->getPhandle(intNode);
+}
- uint64_t xscom_prop[2] = { l_xscomAddr, THIRTYTWO_GB};
- i_dt->addPropertyCells64(xscomNode, "reg", xscom_prop, 2);
- const char* xscom_compatStrs[] = {"ibm,xscom","ibm,power8-xscom",NULL};
- i_dt->addPropertyCell32(xscomNode, "#address-cells", 1);
- i_dt->addPropertyCell32(xscomNode, "#size-cells", 1);
- i_dt->addPropertyCell32(xscomNode, "ibm,chip-id", l_chipid);
- i_dt->addPropertyStrings(xscomNode, "compatible", xscom_compatStrs);
+void add_reserved_mem(devTree * i_dt, uint64_t i_homerAddr[], size_t i_num)
+{
+ /*
+ * The reserved-names and reserve-names properties work hand in hand.
+ * The first one is a list of strings providing a "name" for each entry
+ * in the second one using the traditional "vendor,name" format.
+ *
+ * The reserved-ranges property contains a list of ranges, each in the
+ * form of 2 cells of address and 2 cells of size (64-bit x2 so each
+ * entry is 4 cells) indicating regions of memory that are reserved
+ * and must not be overwritten by skiboot or subsequently by the Linux
+ * Kernel.
+ *
+ * Corresponding entries must also be created in the "reserved map" part
+ * of the flat device-tree (which is a binary list in the header of the
+ * fdt).
+ *
+ * Unless a component (skiboot or Linux) specifically knows about a region
+ * (usually based on its name) and decides to change or remove it, all
+ * these regions are passed as-is to Linux and to subsequent kernels
+ * accross kexec and are kept preserved.
+ */
+ dtOffset_t rootNode = i_dt->findNode("/");
- /*ChipTod*/
- uint32_t l_todInfo = 0x40000; /*Chip tod Scom addr*/
- dtOffset_t todNode = i_dt->addNode(xscomNode, todNodeName, l_todInfo);
- const char* tod_compatStrs[] = {"ibm,power-chiptod",
- "ibm,power8-chiptod", NULL};
- i_dt->addPropertyStrings(todNode, "compatible", tod_compatStrs);
- uint32_t tod_prop[2] = { l_todInfo, 0x34 }; //# of scoms in range
- i_dt->addPropertyCells32(todNode, "reg", tod_prop, 2);
+ const char* homerStr = "ibm,slw-occ-image";
+ const char* reserve_strs[i_num+1];
+ uint64_t homerRanges[i_num][2];
+ for(size_t i = 0; i<i_num; i++)
+ {
+ reserve_strs[i] = homerStr;
+ homerRanges[i][0] = i_homerAddr[i];
+ homerRanges[i][1] = VMM_HOMER_INSTANCE_SIZE;
+ }
- if(l_chipid == 0x0) //Master chip
- {
- i_dt->addProperty(todNode, "primary"); //TODO -- get from ATTR
+ reserve_strs[i_num] = NULL;
- uint32_t l_lpcInfo = 0xB0020; /*ECCB FW addr*/
- dtOffset_t lpcNode = i_dt->addNode(xscomNode,lpcNodeName,l_lpcInfo);
- i_dt->addPropertyString(lpcNode, "compatible", "ibm,power8-lpc");
- uint32_t lpc_prop[2] = { l_lpcInfo, 0x4 }; //# of scoms in range
- i_dt->addPropertyCells32(lpcNode, "reg", lpc_prop, 2);
- }
+ i_dt->addPropertyStrings(rootNode, "reserved-names", reserve_strs);
+ i_dt->addPropertyCells64(rootNode, "reserved-ranges",
+ reinterpret_cast<uint64_t*>(homerRanges),
+ sizeof(homerRanges) / sizeof(uint64_t));
+}
- /*PCIE*/
- uint8_t l_phbActive =
- l_pProc->getAttr<TARGETING::ATTR_PROC_PCIE_PHB_ACTIVE>();
- //TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION_type l_laneEq =
- // l_pProc->getAttr<TARGETING::ATTR_PROC_PCIE_LANE_EQUALIZATION>();
- uint32_t l_laneEq[] = {0,0,0,0};
- TRACFCOMP( g_trac_devtree, "Chip %X PHB Active mask %X",
- l_chipid, l_phbActive);
+errlHndl_t bld_fdt_cpu(devTree * i_dt)
+{
+ errlHndl_t errhdl = NULL;
- for(uint32_t l_phb =0; l_phb < MAX_PHBs; l_phb++)
- {
- if(!(l_phbActive & (PHB0_MASK>>l_phb)))
- {
- continue;
- }
+ /* Find the / node and add a cpus node under it. */
+ dtOffset_t rootNode = i_dt->findNode("/");
+ dtOffset_t cpusNode = i_dt->addNode(rootNode, "cpus");
- TRACFCOMP( g_trac_devtree, "Adding PHB %d", l_phb);
-
- /*PHB is active, add to Xscom map*/
- uint32_t l_peInfo = 0x02012000 + (l_phb * 0x400);
- uint32_t l_pciInfo = 0x09012000 + (l_phb * 0x400);
- uint32_t l_spciInfo = 0x09013c00 + (l_phb * 0x40);
- dtOffset_t pcieNode = i_dt->addNode(xscomNode,pciNodeName,l_peInfo);
- const char* pcie_compatStrs[] = {"ibm,power8-pbcq", NULL};
- i_dt->addPropertyStrings(pcieNode, "compatible", pcie_compatStrs);
- uint32_t pcie_prop[6] = { l_peInfo, 0x20, //# of scoms in range
- l_pciInfo, 0x5, //# of scoms in range
- l_spciInfo, 0x15}; //# of scoms in range
- i_dt->addPropertyCells32(pcieNode, "reg", pcie_prop, 6);
- i_dt->addPropertyCell32(pcieNode, "ibm,phb-index", l_phb);
- i_dt->addPropertyCell32(pcieNode, "ibm,lane-eq", l_laneEq[l_phb]);
- }
+ /* Add the # address & size cell properties to /cpus. */
+ i_dt->addPropertyCell32(cpusNode, "#address-cells", 1);
+ i_dt->addPropertyCell32(cpusNode, "#size-cells", 0);
+
+ // Get all functional proc chip targets
+ TARGETING::TargetHandleList l_cpuTargetList;
+ getAllChips(l_cpuTargetList, TYPE_PROC);
+ uint64_t l_homerAddr[l_cpuTargetList.size()];
+
+ for ( size_t proc = 0; (!errhdl) && (proc < l_cpuTargetList.size()); proc++)
+ {
+ const TARGETING::Target * l_pProc = l_cpuTargetList[proc];
+
+ uint32_t l_chipid = getProcChipId(l_pProc);
+
+ bld_xscom_node(i_dt, rootNode, l_pProc, l_chipid);
+
+ //Each processor will have a HOMER image that needs
+ //to be reserved -- save it away
+ l_homerAddr[proc] = getHomerPhysAddr(l_pProc);
TARGETING::TargetHandleList l_exlist;
getChildChiplets( l_exlist, l_pProc, TYPE_CORE );
@@ -202,12 +511,6 @@ errlHndl_t bld_fdt_cpu(devTree * i_dt)
continue; //Not functional
}
- /* TODO -- need to add cache info */
-
- /* Add a dev node for each cpu core. The unit address is the
- *interrupt server number of the first thread of the core.
- */
-
/* Proc ID Reg is N NNCC CPPP PTTT Where
NNN is node number
CCC is Chip
@@ -216,76 +519,28 @@ errlHndl_t bld_fdt_cpu(devTree * i_dt)
*/
uint32_t l_coreNum = l_ex->getAttr<TARGETING::ATTR_CHIP_UNIT>();
INTR::PIR_t pir(0);
- pir.nodeId = l_fabId;
- pir.chipId = l_procPos;
+ pir.nodeId = CHIPID_EXTRACT_NODE(l_chipid);
+ pir.chipId = CHIPID_EXTRACT_PROC(l_chipid);
pir.coreId = l_coreNum;
- TRACFCOMP( g_trac_devtree, "Added pir[%x] node %d proc %d core %d",
- pir.word, l_fabId, l_procPos, l_coreNum );
+ TRACFCOMP( g_trac_devtree, "Added pir[%x] chipid 0x%x core %d",
+ pir.word, l_chipid, l_coreNum );
cpusNode = i_dt->findNode("/cpus");
- dtOffset_t cpuNode = i_dt->addNode(cpusNode, cpuNodeName,
- pir.word);
- i_dt->addPropertyString(cpuNode, "device_type", "cpu");
- i_dt->addPropertyString(cpuNode, "status", "okay");
- i_dt->addPropertyCell32(cpuNode, "reg", pir.word);
- i_dt->addPropertyCell32(cpuNode, "d-cache-size", 0x10000);
- i_dt->addPropertyCell32(cpuNode, "i-cache-size", 0x8000);
- i_dt->addPropertyCell32(cpuNode, "d-cache-line-size", 128);
- i_dt->addPropertyCell32(cpuNode, "i-cache-line-size", 128);
- i_dt->addPropertyCell32(cpuNode, "ibm,dfp", 1);
- i_dt->addPropertyCell32(cpuNode, "ibm,vmx", 2);
- i_dt->addPropertyCell32(cpuNode, "timebase-frequency", 512000000);
- i_dt->addPropertyCell32(cpuNode, "clock-frequency", 2000000000);
- i_dt->addPropertyCell32(cpuNode, "ibm,pir", pir.word);
- i_dt->addPropertyCell32(cpuNode, "ibm,chip-id", l_chipid);
- i_dt->addPropertyCells32(cpuNode, "ibm,processor-segment-sizes",
- segmentSizes,
- sizeof(segmentSizes) / sizeof(uint32_t));
- i_dt->addPropertyCells32(cpuNode, "ibm,segment-page-sizes",
- segmentPageSizes,
- sizeof(segmentPageSizes)/sizeof(uint32_t));
- i_dt->addPropertyCell32(cpuNode, "ibm,slb-size", 32);
-
- uint32_t interruptServerNum[THREADPERCORE];
- for(size_t i = 0; i < THREADPERCORE ; i++)
- {
- pir.threadId = i;
- interruptServerNum[i] = pir.word;
- }
- i_dt->addPropertyCells32(cpuNode, "ibm,ppc-interrupt-server#s",
- interruptServerNum, THREADPERCORE);
-
- //IBASE ADDRESS
- uint64_t l_ibase = INTR::getIntpAddr(l_ex, 0);
+ uint32_t l3pHandle = bld_l3_node(i_dt, cpusNode, pir.word);
+ uint32_t l2pHandle = bld_l2_node(i_dt, cpusNode, pir.word,
+ l3pHandle);
+ bld_cpu_node(i_dt, cpusNode, l_ex, pir, l_chipid, l2pHandle);
rootNode = i_dt->findNode("/");
- dtOffset_t intNode = i_dt->addNode(rootNode, cpuIntrName, l_ibase);
- const char* intr_compatStrs[] = {"ibm,ppc-xicp", "ibm,power8-xicp",
- NULL};
- i_dt->addPropertyStrings(intNode, "compatible", intr_compatStrs);
- uint32_t int_serv[2] = { interruptServerNum[0], THREADPERCORE};
- i_dt->addPropertyCells32(intNode, "ibm,interrupt-server-ranges",
- int_serv, 2);
- i_dt->addPropertyCell32(intNode, "#address-cells", 0);
- i_dt->addPropertyCell32(intNode, "#interrupt-cells", 1);
- i_dt->addPropertyString(intNode, "device_type",
- "PowerPC-External-Interrupt-Presentation");
- uint64_t intr_prop[THREADPERCORE][2];
- for(size_t i=0; i < THREADPERCORE; i++)
- {
- intr_prop[i][0] = INTR::getIntpAddr(l_ex, i);
- intr_prop[i][1] = 0x1000;
- }
- i_dt->addPropertyCells64(intNode, "reg",
- reinterpret_cast<uint64_t*>(intr_prop),
- sizeof(intr_prop) / sizeof(uint64_t));
-
- /* TODO add associativity*/
+ bld_intr_node(i_dt, rootNode, l_ex, pir);
}
}
+ //Add in reserved memory for HOMER images
+ add_reserved_mem(i_dt, l_homerAddr, l_cpuTargetList.size());
+
return errhdl;
}
@@ -294,9 +549,24 @@ errlHndl_t bld_fdt_mem(devTree * i_dt)
errlHndl_t errhdl = NULL;
bool rc;
+ /*
+ * The "memory" nodes represent physical memory in the system. They
+ * do not represent DIMMs, memory controllers or Centaurs, thus will
+ * be expressed separately.
+ *
+ * In order to be able to handle affinity propertly, we require that
+ * a memory node is created for each range of memory that has a different
+ * "affinity", which in practice means for each chip since we don't
+ * support memory interleaved accross multiple chips on P8.
+ *
+ * Additionally, it is *not* required that one chip = one memory node,
+ * it is perfectly acceptable to break down the memory of one chip into
+ * multiple memory nodes (typically skiboot does that if the two MCs
+ * are not interlaved).
+ */
+
do
{
-
/* Find the / node and add a memory node(s) under it. */
dtOffset_t rootNode = i_dt->findNode("/");
@@ -363,9 +633,10 @@ errlHndl_t bld_fdt_mem(devTree * i_dt)
uint64_t propertyCells[2] = {l_bases[i],l_sizes[i]};
i_dt->addPropertyCells64(memNode, "reg", propertyCells, 2);
- /*TODO -- add core affinity*/
+ //Add the attached proc chip for affinity
+ i_dt->addPropertyCell32(memNode, "ibm,chip-id",
+ getProcChipId(l_pProc));
- /*TODO -- add VPD*/
}
}
}
@@ -373,15 +644,6 @@ errlHndl_t bld_fdt_mem(devTree * i_dt)
return errhdl;
}
-errlHndl_t bld_fdt_io(devTree * i_dt)
-{
- errlHndl_t errhdl = NULL;
-
-
-
- return errhdl;
-}
-
errlHndl_t build_flatdevtree( void )
{
errlHndl_t errhdl = NULL;
@@ -407,12 +669,6 @@ errlHndl_t build_flatdevtree( void )
break;
}
- TRACFCOMP( g_trac_devtree, "---devtree io ---" );
- errhdl = bld_fdt_io(dt);
- if(errhdl)
- {
- break;
- }
}while(0);
return errhdl;
diff --git a/src/usr/devtree/devtree.C b/src/usr/devtree/devtree.C
index 562bf876c..eac9f1b0e 100644
--- a/src/usr/devtree/devtree.C
+++ b/src/usr/devtree/devtree.C
@@ -69,7 +69,8 @@ void devTree::initialize(uint64_t i_addr, size_t i_maxSize)
TRACFCOMP( g_trac_devtree, "FDT located @ v:%p p:0x%x", mSpace, mPhysAddr);
mHeader->magicNumber = DT_MAGIC;
- mHeader->totalSize = sizeof(*mHeader) + (sizeof(dtReserveEntry_t) * 2);
+ mHeader->totalSize = (sizeof(*mHeader) +
+ (sizeof(dtReserveEntry_t) * DT_MAX_MEM_RESERVE));
mHeader->offsetStruct = mHeader->totalSize;
mHeader->offsetStrings = mHeader->totalSize;
mHeader->offsetReservedMemMap = sizeof(*mHeader);
@@ -92,26 +93,18 @@ void devTree::initialize(uint64_t i_addr, size_t i_maxSize)
mHeader->sizeStruct += structSizeAdded;
mHeader->totalSize += structSizeAdded;
- /* Setup the memory reserve map to include the region that
- Hostboot places the SLW and OCC images*/
- dtReserveEntry* reserveMemMap = (dtReserveEntry*)
- (mSpace + mHeader->offsetReservedMemMap);
- reserveMemMap->address = 0x0A000000; /*160MB-192MB*/;
- reserveMemMap->size = MEGABYTE * 32;
-
/* Add the standard root node properties. */
dtOffset_t rootNode = findNode("/");
addPropertyCell32(rootNode, "#address-cells", 2);
addPropertyCell32(rootNode, "#size-cells", 2);
addPropertyString(rootNode, "compatible", "ibm,powernv");
- addPropertyString(rootNode, "model", "P8_Sim");
-
- addNode(rootNode, "chosen");
+ //TODO RTC:88056 - store model type in attributes?
+ addPropertyString(rootNode, "model", "rhesus");
- // Add the initial vpd and location code nodes.
- addProperty(rootNode, "ibm,vpd");
- addProperty(rootNode, "ibm,loc-code");
+ //"Get" the phandle -- this will add one to root node as
+ //it doesn't already have one
+ getPhandle(rootNode);
}
void devTree::setBootCpu(uint32_t pir)
@@ -686,6 +679,32 @@ void devTree::appendPropertyBytes(dtOffset_t parentNode,
}
}
+int devTree::populateReservedMem(uint64_t i_addrs[],
+ uint64_t i_sizes[],
+ size_t i_num)
+{
+ int rc = 1;
+
+ //if requested num is less than max, update
+ if(i_num < DT_MAX_MEM_RESERVE)
+ {
+ dtReserveEntry* reserveMemMap = reinterpret_cast<dtReserveEntry*>
+ (mSpace + mHeader->offsetReservedMemMap);
+
+ for(size_t i=0; i<i_num; i++)
+ {
+ reserveMemMap->address = i_addrs[i];
+ reserveMemMap->size = i_sizes[i];
+
+ reserveMemMap++;
+ }
+
+ rc = 0;
+ }
+
+ return rc;
+}
+
/********************
Internal Methods
diff --git a/src/usr/devtree/devtree.H b/src/usr/devtree/devtree.H
index 1056ed304..42d4f0bd7 100644
--- a/src/usr/devtree/devtree.H
+++ b/src/usr/devtree/devtree.H
@@ -195,6 +195,17 @@ typedef size_t dtOffset_t;
const uint8_t* propertyData,
uint32_t numBytes);
+ /**
+ * Populate reserved memory regions
+ * @param[in] i_addrs Array of addresses to set in reserved memory
+ * @param[in] i_sizes Array of sizes to set in reserved memory
+ * @param[in] i_num Number of elements in the arrays
+ * @return int, zero on sucesses otherwise non zero
+ */
+ int populateReservedMem(uint64_t i_addrs[],
+ uint64_t i_sizes[],
+ size_t i_num);
+
/**
* Return the current size of the FDT (not max)
* @return uin32_t Size of the FDT
@@ -281,6 +292,9 @@ typedef size_t dtOffset_t;
DT_END =0x9,
DT_INVALID_OFFSET =0xFFFFFFFF,
+
+ DT_MAX_MEM_RESERVE =16,
+
};
diff --git a/src/usr/devtree/dt_doc_v0.2.txt b/src/usr/devtree/dt_doc_v0.2.txt
new file mode 100644
index 000000000..74167648b
--- /dev/null
+++ b/src/usr/devtree/dt_doc_v0.2.txt
@@ -0,0 +1,512 @@
+/*
+ * Sapphire device-tree requirements
+ *
+ * Version: 0.2
+ *
+ * This documents the generated device-tree requirements, this is based on
+ * a commented device-tree dump obtained from a DT generated by Sapphire
+ * itself from an HDAT.
+ */
+
+/*
+ * General comments:
+ *
+ * - skiboot does not require nodes to have phandle properties, but
+ * if you have them then *all* nodes must have them including the
+ * root of the device-tree (currently a HB bug !). It is recommended
+ * to have them since they are needed to represent the cache levels.
+ *
+ * NOTE: The example tree below only has phandle properties for
+ * nodes that are referenced by other nodes. This is *not* correct
+ * and is purely done for keeping this document smaller, make sure
+ * to follow the rule above.
+ *
+ * - Only the "phandle" property is required. Sapphire also generates
+ * a "linux,phandle" for backward compatibility but doesn't require
+ * it as an input
+ *
+ * - Any property not specifically documented must be put in "as is"
+ *
+ * - All ibm,chip-id properties contain a HW chip ID which correspond
+ * on P8 to the PIR value shifted right by 7 bits, ie. it's a 6-bit
+ * value made of a 3-bit node number and a 3-bit chip number.
+ *
+ * - Unit addresses (@xxxx part of node names) should if possible use
+ * lower case hexadecimal to be consistent with what skiboot does
+ * and to help some stupid parsers out there...
+ */
+
+/*
+ * Version history
+ *
+ * 2013/10/08 : Version 0.1
+ *
+ * 2013/10/09 : Version 0.2
+ *
+ * - Add comment about case of unit addresses
+ * - Add missing lpc node definition
+ * - Add example UART node on LPC
+ * - Remove "status" property from PSI xsco nodes
+ */
+
+/dts-v1/;
+
+
+/*
+ * Here are the reserve map entries. They should exactly match the
+ * reserved-ranges property of the root node (see documentation
+ * of that property)
+ */
+
+/memreserve/ 0x00000007fe600000 0x0000000000100000;
+/memreserve/ 0x00000007fe200000 0x0000000000100000;
+/memreserve/ 0x0000000031e00000 0x00000000003e0000;
+/memreserve/ 0x0000000031000000 0x0000000000e00000;
+/memreserve/ 0x0000000030400000 0x0000000000c00000;
+/memreserve/ 0x0000000030000000 0x0000000000400000;
+/memreserve/ 0x0000000400000000 0x0000000000600450;
+
+/* Root node */
+/ {
+ /*
+ * "compatible" properties are string lists (ASCII strings separated by
+ * \0 characters) indicating the overall compatibility from the more
+ * specific to the least specific.
+ *
+ * The root node compatible property *must* contain "ibm,powernv" for
+ * Linux to have the powernv platform match the machine. It is recommended
+ * to add a slightly more precise property (first in order) indicating more
+ * precisely the board type. We don't currently do that in HDAT based
+ * setups but will.
+ *
+ * The standard naming is "vendor,name" so in your case, something like
+ *
+ * compatible = "vend,demo","ibm,powernv";
+ *
+ * would work. Or even better:
+ *
+ * compatible = "vend,demo-v1","vend,demo","ibm,powernv";
+ */
+ compatible = "ibm,powernv";
+
+ /* mandatory */
+ #address-cells = <0x2>;
+ #size-cells = <0x2>;
+
+ /* User visible board name (will be shown in /proc/cpuinfo) */
+ model = "Machine Name";
+
+ /*
+ * The reserved-names and reserve-names properties work hand in hand. The first one
+ * is a list of strings providing a "name" for each entry in the second one using
+ * the traditional "vendor,name" format.
+ *
+ * The reserved-ranges property contains a list of ranges, each in the form of 2 cells
+ * of address and 2 cells of size (64-bit x2 so each entry is 4 cells) indicating
+ * regions of memory that are reserved and must not be overwritten by skiboot or
+ * subsequently by the Linux Kernel.
+ *
+ * Corresponding entries must also be created in the "reserved map" part of the flat
+ * device-tree (which is a binary list in the header of the fdt).
+ *
+ * Unless a component (skiboot or Linux) specifically knows about a region (usually
+ * based on its name) and decides to change or remove it, all these regions are
+ * passed as-is to Linux and to subsequent kernels accross kexec and are kept
+ * preserved.
+ *
+ * NOTE: Do *NOT* copy the entries below, they are just an example and are actually
+ * created by skiboot itself. They represent the SLW image as "detected" by reading
+ * the PBA BARs and skiboot own memory allocations.
+ *
+ * I would recommend that you put in there the SLW and OCC (or HOMER as one block
+ * if that's how you use it) and any additional memory you want to preserve such
+ * as FW log buffers etc...
+ */
+
+ reserved-names = "ibm,slw-image", "ibm,slw-image", "ibm,firmware-stacks", "ibm,firmware-data", "ibm,firmware-heap", "ibm,firmware-code", "memory@400000000";
+ reserved-ranges = <0x7 0xfe600000 0x0 0x100000 0x7 0xfe200000 0x0 0x100000 0x0 0x31e00000 0x0 0x3e0000 0x0 0x31000000 0x0 0xe00000 0x0 0x30400000 0x0 0xc00000 0x0 0x30000000 0x0 0x400000 0x4 0x0 0x0 0x600450>;
+
+ /* Mandatory */
+ cpus {
+ #address-cells = <0x1>;
+ #size-cells = <0x0>;
+
+ /*
+ * The following node must exist for each *core* in the system. The unit
+ * address (number after the @) is the hexadecimal HW CPU number (PIR value)
+ * of thread 0 of that core.
+ */
+ PowerPC,POWER8@20 {
+ /* mandatory/standard properties */
+ device_type = "cpu";
+ 64-bit;
+ 32-64-bridge;
+ graphics;
+ general-purpose;
+
+ /*
+ * The "status" property indicate whether the core is functional. It's
+ * a string containing "okay" for a good core or "bad" for a non-functional
+ * one. You can also just ommit the non-functional ones from the DT
+ */
+ status = "okay";
+
+ /*
+ * This is the same value as the PIR of thread 0 of that core
+ * (ie same as the @xx part of the node name)
+ */
+ reg = <0x20>;
+
+ /* same as above */
+ ibm,pir = <0x20>;
+
+ /* chip ID of this core */
+ ibm,chip-id = <0x0>;
+
+ /*
+ * interrupt server numbers (aka HW processor numbers) of all threads
+ * on that core. This should have 8 numbers and the first one should
+ * have the same value as the above ibm,pir and reg properties
+ */
+ ibm,ppc-interrupt-server#s = <0x20 0x21 0x22 0x23 0x24 0x25 0x26 0x27>;
+
+ /*
+ * This is the "architected processor version" as defined in PAPR. Just
+ * stick to 0x0f000004 for P8 and things will be fine
+ */
+ cpu-version = <0x0f000004>;
+
+ /*
+ * These are various definitions of the page sizes and segment sizes
+ * supported by the MMU, those values are fine for P8 for now
+ */
+ ibm,processor-segment-sizes = <0x1c 0x28 0xffffffff 0xffffffff>;
+ ibm,processor-page-sizes = <0xc 0x10 0x18 0x22>;
+ ibm,segment-page-sizes = <0xc 0x0 0x3 0xc 0x0 0x10 0x7 0x18 0x38 0x10 0x110 0x2 0x10 0x1 0x18 0x8 0x18 0x100 0x1 0x18 0x0 0x22 0x120 0x1 0x22 0x3>;
+
+ /*
+ * Similarily that might need to be reviewed later but will do for now...
+ */
+ ibm,pa-features = <0x6 0x0 0xf6 0x3f 0xc7 0x0 0x80 0xc0>;
+
+ /* SLB size, use as-is */
+ ibm,slb-size = <0x20>;
+
+ /* VSX support, use as-is */
+ ibm,vmx = <0x2>;
+
+ /* DFP support, use as-is */
+ ibm,dfp = <0x2>;
+
+ /* PURR/SPURR support, use as-is */
+ ibm,purr = <0x1>;
+ ibm,spurr = <0x1>;
+
+ /*
+ * Old-style core clock frequency. Only create this property if the frequency fits
+ * in a 32-bit number. Do not create it if it doesn't
+ */
+ clock-frequency = <0xf5552d00>;
+
+ /*
+ * mandatory: 64-bit version of the core clock frequency, always create this
+ * property.
+ */
+ ibm,extended-clock-frequency = <0x0 0xf5552d00>;
+
+ /* Timebase freq has a fixed value, always use that */
+ timebase-frequency = <0x1e848000>;
+
+ /* Same */
+ ibm,extended-timebase-frequency = <0x0 0x1e848000>;
+
+ /* Use as-is, values might need to be adjusted but that will do for now */
+ reservation-granule-size = <0x80>;
+ d-tlb-size = <0x800>;
+ i-tlb-size = <0x0>;
+ tlb-size = <0x800>;
+ d-tlb-sets = <0x4>;
+ i-tlb-sets = <0x0>;
+ tlb-sets = <0x4>;
+ d-cache-block-size = <0x80>;
+ i-cache-block-size = <0x80>;
+ d-cache-size = <0x10000>;
+ i-cache-size = <0x8000>;
+ i-cache-sets = <0x4>;
+ d-cache-sets = <0x8>;
+ performance-monitor = <0x0 0x1>;
+
+ /*
+ * optional: phandle of the node representing the L2 cache for this core,
+ * note: it can also be named "next-level-cache", Linux will support both
+ * and Sapphire doesn't currently use those properties, just passes them
+ * along to Linux
+ */
+ l2-cache = < 0x4 >;
+ };
+
+ /*
+ * Cache nodes. Those are siblings of the processor nodes under /cpus and
+ * represent the various level of caches.
+ *
+ * The unit address (and reg property) is mostly free-for-all as long as
+ * there is no collisions. On HDAT machines we use the following encoding
+ * which I encourage you to also follow to limit surprises:
+ *
+ * L2 : (0x20 << 24) | PIR (PIR is PIR value of thread 0 of core)
+ * L3 : (0x30 << 24) | PIR
+ * L3.5 : (0x35 << 24) | PIR
+ *
+ * In addition, each cache points to the next level cache via its
+ * own "l2-cache" (or "next-level-cache") property, so the core node
+ * points to the L2, the L2 points to the L3 etc...
+ */
+
+ l2-cache@20000020 {
+ phandle = <0x4>;
+ device_type = "cache";
+ reg = <0x20000020>;
+ status = "okay";
+ cache-unified;
+ d-cache-sets = <0x8>;
+ i-cache-sets = <0x8>;
+ d-cache-size = <0x80000>;
+ i-cache-size = <0x80000>;
+ l2-cache = <0x5>;
+ };
+
+ l3-cache@30000020 {
+ phandle = <0x5>;
+ device_type = "cache";
+ reg = <0x30000020>;
+ status = "bad";
+ cache-unified;
+ d-cache-sets = <0x8>;
+ i-cache-sets = <0x8>;
+ d-cache-size = <0x800000>;
+ i-cache-size = <0x800000>;
+ };
+
+ };
+
+ /*
+ * Interrupt presentation controller (ICP) nodes
+ *
+ * There is some flexibility as to how many of these are presents since
+ * a given node can represent multiple ICPs. When generating from HDAT we
+ * chose to create one per core
+ */
+ interrupt-controller@3ffff80020000 {
+ /* Mandatory */
+ compatible = "IBM,ppc-xicp", "IBM,power8-icp";
+ interrupt-controller;
+ #address-cells = <0x0>;
+ #interrupt-cells = <0x1>;
+ device_type = "PowerPC-External-Interrupt-Presentation";
+
+ /*
+ * Range of HW CPU IDs represented by that node. In this example
+ * the core starting at PIR 0x20 and 8 threads, which corresponds
+ * to the CPU node of the example above. The property in theory
+ * supports multiple ranges but Linux doesn't.
+ */
+ ibm,interrupt-server-ranges = <0x20 0x8>;
+
+ /*
+ * For each server in the above range, the physical address of the
+ * ICP register block and its size. Since the root node #address-cells
+ * and #size-cells properties are both "2", each entry is thus
+ * 2 cells address and 2 cells size (64-bit each).
+ */
+ reg = <0x3ffff 0x80020000 0x0 0x1000 0x3ffff 0x80021000 0x0 0x1000 0x3ffff 0x80022000 0x0 0x1000 0x3ffff 0x80023000 0x0 0x1000 0x3ffff 0x80024000 0x0 0x1000 0x3ffff 0x80025000 0x0 0x1000 0x3ffff 0x80026000 0x0 0x1000 0x3ffff 0x80027000 0x0 0x1000>;
+ };
+
+ /*
+ * The "memory" nodes represent physical memory in the system. They
+ * do not represent DIMMs, memory controllers or Centaurs, thus will
+ * be expressed separately.
+ *
+ * In order to be able to handle affinity propertly, we require that
+ * a memory node is created for each range of memory that has a different
+ * "affinity", which in practice means for each chip since we don't
+ * support memory interleaved accross multiple chips on P8.
+ *
+ * Additionally, it is *not* required that one chip = one memory node,
+ * it is perfectly acceptable to break down the memory of one chip into
+ * multiple memory nodes (typically skiboot does that if the two MCs
+ * are not interlaved).
+ */
+ memory@0 {
+ device_type = "memory";
+
+ /*
+ * We support multiple entries in the ibm,chip-id property for
+ * memory nodes in case the memory is interleaved accross multiple
+ * chips but that shouldn't happen on P8
+ */
+ ibm,chip-id = <0x0>;
+
+ /* The "reg" property is 4 cells, as usual for a child of
+ * the root node, 2 cells of address and 2 cells of size
+ */
+ reg = <0x0 0x0 0x4 0x0>;
+ };
+
+ /*
+ * The XSCOM node. This is the closest thing to a "chip" node we have.
+ * there must be one per chip in the system (thus a DCM has two) and
+ * while it represents the "parent" of various devices on the PIB/PCB
+ * that we want to expose, it is also used to store all sort of
+ * miscellaneous per-chip information on HDAT based systems (such
+ * as VPDs).
+ */
+ xscom@3fc0000000000 {
+ /* standard & mandatory */
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+ scom-controller;
+ compatible = "ibm,xscom", "ibm,power8-xscom";
+
+ /* The chip ID as usual ... */
+ ibm,chip-id = <0x0>;
+
+ /* The base address of xscom for that chip */
+ reg = <0x3fc00 0x0 0x8 0x0>;
+
+ /*
+ * This comes from HDAT and I *think* is the raw content of the
+ * module VPD eeprom (and thus doesn't have a standard ASCII keyword
+ * VPD format). We don't currently use it though ...
+ */
+ ibm,module-vpd = < ... big pile of binary data ... >;
+
+ /* PSI host bridge XSCOM register set */
+ psihb@2010900 {
+ reg = <0x2010900 0x20>;
+ compatible = "ibm,power8-psihb-x", "ibm,psihb-x";
+ };
+
+ /* Chip TOD XSCOM register set */
+ chiptod@40000 {
+ reg = <0x40000 0x34>;
+ compatible = "ibm,power-chiptod", "ibm,power8-chiptod";
+
+ /*
+ * Create that property with no value if this chip has
+ * the Primary TOD in the topology. If it has the secondary
+ * one (backup master ?) use "secondary".
+ */
+ primary;
+ };
+
+ /* NX XSCOM register set */
+ nx@2010000 {
+ reg = <0x2010000 0x4000>;
+ compatible = "ibm,power-nx", "ibm,power8-nx";
+ };
+
+ /*
+ * PCI "PE Master" XSCOM register set for each active PHB
+ *
+ * For now, do *not* create these if the PHB isn't connected,
+ * clocked, or the PHY/HSS not configured.
+ */
+ pbcq@2012000 {
+ reg = <0x2012000 0x20 0x9012000 0x5 0x9013c00 0x15>;
+ compatible = "ibm,power8-pbcq";
+
+ /* Indicate the PHB index on the chip, ie, 0,1 or 2 */
+ ibm,phb-index = <0x0>;
+
+ /* Create that property to use the IBM-style "A/B" dual input
+ * slot presence detect mechanism.
+ */
+ ibm,use-ab-detect;
+
+ /*
+ * TBD: Lane equalization values. Not currently used by
+ * skiboot but will have to be sorted out
+ */
+ ibm,lane_eq = <0x0>;
+ };
+
+ pbcq@2012400 {
+ reg = <0x2012400 0x20 0x9012400 0x5 0x9013c40 0x15>;
+ compatible = "ibm,power8-pbcq";
+ ibm,phb-index = <0x1>;
+ ibm,use-ab-detect;
+ ibm,lane_eq = <0x0>;
+ };
+
+ /*
+ * Here's the LPC bus. Ideally each chip has one but in
+ * practice it's ok to only populate the ones actually
+ * used for something. This is not an exact representation
+ * of HW, in that case we would have eccb -> opb -> lpc,
+ * but instead we just have an lpc node and the address is
+ * the base of the ECCB register set for it
+ *
+ * Devices on the LPC are represented as children nodes,
+ * see example below for a standard UART.
+ */
+ lpc@b0020 {
+ /*
+ * Empty property indicating this is the primary
+ * LPC bus. It will be used for the default UART
+ * if any and this is the bus that will be used
+ * by Linux as the virtual 64k of IO ports
+ */
+ primary;
+
+ /*
+ * 2 cells of address, the first one indicates the
+ * address type, see below
+ */
+ #address-cells = <0x2>;
+ #size-cells = <0x1>;
+ reg = <0xb0020 0x4>;
+ compatible = "ibm,power8-lpc";
+
+ /*
+ * Example device: a UART on IO ports.
+ *
+ * LPC address have 2 cells. The first cell is the
+ * address type as follow:
+ *
+ * 0 : LPC memory space
+ * 1 : LPC IO space
+ * 2: LPC FW space
+ *
+ * (This corresponds to the OPAL_LPC_* arguments
+ * passed to the opal_lpc_read/write functions)
+ *
+ * The unit address follows the old ISA convention
+ * for open firmware which prefixes IO ports with "i".
+ *
+ * (This is not critical and can be 1,3f8 if that's
+ * problematic to generate)
+ */
+ serial@i3f8 {
+ reg = <0x1 0x3f8 8>;
+ compatible = "ns16550", "pnpPNP,501";
+
+ /* Baud rate generator base frequency */
+ clock-frequency = < 1843200 >;
+
+ /* Default speed to use */
+ current-speed = < 115200 >;
+
+ /* Historical, helps Linux */
+ device_type = "serial";
+
+ /*
+ * Indicate which chip ID the interrupt
+ * is routed to (we assume it will always
+ * be the "host error interrupt" (aka
+ * "TPM interrupt" of that chip).
+ */
+ ibm,irq-chip-id = <0x0>;
+ }
+ };
+ };
+};
OpenPOWER on IntegriCloud