Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6e35d5da authored by Benjamin Herrenschmidt's avatar Benjamin Herrenschmidt
Browse files

powerpc/powernv: Add support for instanciating OPAL v2 from Open Firmware



OPAL v2 is instantiated in a way similar to RTAS using Open Firmware
client interface calls, and the resulting address and entry point are
put in the device-tree

Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 14a43e69
Loading
Loading
Loading
Loading
+117 −19
Original line number Diff line number Diff line
@@ -140,7 +140,9 @@ struct mem_map_entry {

typedef u32 cell_t;

extern void __start(unsigned long r3, unsigned long r4, unsigned long r5);
extern void __start(unsigned long r3, unsigned long r4, unsigned long r5,
		    unsigned long r6, unsigned long r7, unsigned long r8,
		    unsigned long r9);

#ifdef CONFIG_PPC64
extern int enter_prom(struct prom_args *args, unsigned long entry);
@@ -1293,6 +1295,11 @@ static int __initdata prom_rtas_start_cpu;
static u64 __initdata prom_rtas_data;
static u64 __initdata prom_rtas_entry;

#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
static u64 __initdata prom_opal_base;
static u64 __initdata prom_opal_entry;
#endif

/* XXX Don't change this structure without updating opal-takeover.S */
static struct opal_secondary_data {
	s64				ack;	/*  0 */
@@ -1468,6 +1475,76 @@ static void prom_opal_takeover(void)
	for (;;)
		opal_do_takeover(args);
}

/*
 * Allocate room for and instantiate OPAL
 */
static void __init prom_instantiate_opal(void)
{
	phandle opal_node;
	ihandle opal_inst;
	u64 base, entry;
	u64 size = 0, align = 0x10000;
	u32 rets[2];

	prom_debug("prom_instantiate_opal: start...\n");

	opal_node = call_prom("finddevice", 1, 1, ADDR("/ibm,opal"));
	prom_debug("opal_node: %x\n", opal_node);
	if (!PHANDLE_VALID(opal_node))
		return;

	prom_getprop(opal_node, "opal-runtime-size", &size, sizeof(size));
	if (size == 0)
		return;
	prom_getprop(opal_node, "opal-runtime-alignment", &align,
		     sizeof(align));

	base = alloc_down(size, align, 0);
	if (base == 0) {
		prom_printf("OPAL allocation failed !\n");
		return;
	}

	opal_inst = call_prom("open", 1, 1, ADDR("/ibm,opal"));
	if (!IHANDLE_VALID(opal_inst)) {
		prom_printf("opening opal package failed (%x)\n", opal_inst);
		return;
	}

	prom_printf("instantiating opal at 0x%x...", base);

	if (call_prom_ret("call-method", 4, 3, rets,
			  ADDR("load-opal-runtime"),
			  opal_inst,
			  base >> 32, base & 0xffffffff) != 0
	    || (rets[0] == 0 && rets[1] == 0)) {
		prom_printf(" failed\n");
		return;
	}
	entry = (((u64)rets[0]) << 32) | rets[1];

	prom_printf(" done\n");

	reserve_mem(base, size);

	prom_debug("opal base     = 0x%x\n", base);
	prom_debug("opal align    = 0x%x\n", align);
	prom_debug("opal entry    = 0x%x\n", entry);
	prom_debug("opal size     = 0x%x\n", (long)size);

	prom_setprop(opal_node, "/ibm,opal", "opal-base-address",
		     &base, sizeof(base));
	prom_setprop(opal_node, "/ibm,opal", "opal-entry-address",
		     &entry, sizeof(entry));

#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
	RELOC(prom_opal_base) = base;
	RELOC(prom_opal_entry) = entry;
#endif
	prom_debug("prom_instantiate_opal: end...\n");
}

#endif /* CONFIG_PPC_POWERNV */

/*
@@ -1863,7 +1940,7 @@ static int __init prom_find_machine_type(void)
	int x;
#endif

	/* Look for a PowerMac */
	/* Look for a PowerMac or a Cell */
	len = prom_getprop(_prom->root, "compatible",
			   compat, sizeof(compat)-1);
	if (len > 0) {
@@ -1889,7 +1966,11 @@ static int __init prom_find_machine_type(void)
		}
	}
#ifdef CONFIG_PPC64
	/* If not a mac, try to figure out if it's an IBM pSeries or any other
	/* Try to detect OPAL */
	if (PHANDLE_VALID(call_prom("finddevice", 1, 1, ADDR("/ibm,opal"))))
		return PLATFORM_OPAL;

	/* Try to figure out if it's an IBM pSeries or any other
	 * PAPR compliant platform. We assume it is if :
	 *  - /device_type is "chrp" (please, do NOT use that for future
	 *    non-IBM designs !
@@ -2116,7 +2197,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
	unsigned long soff;
	unsigned char *valp;
	static char pname[MAX_PROPERTY_NAME];
	int l, room;
	int l, room, has_phandle = 0;

	dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end);

@@ -2200,9 +2281,15 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
		valp = make_room(mem_start, mem_end, l, 4);
		call_prom("getprop", 4, 1, node, RELOC(pname), valp, l);
		*mem_start = _ALIGN(*mem_start, 4);

		if (!strcmp(RELOC(pname), RELOC("phandle")))
			has_phandle = 1;
	}

	/* Add a "linux,phandle" property. */
	/* Add a "linux,phandle" property if no "phandle" property already
	 * existed (can happen with OPAL)
	 */
	if (!has_phandle) {
		soff = dt_find_string(RELOC("linux,phandle"));
		if (soff == 0)
			prom_printf("WARNING: Can't find string index for"
@@ -2214,6 +2301,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
			valp = make_room(mem_start, mem_end, 4, 4);
			*(u32 *)valp = node;
		}
	}

	/* do all our children */
	child = call_prom("child", 1, 1, node);
@@ -2746,6 +2834,7 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
	 * between pSeries SMP and pSeries LPAR
	 */
	RELOC(of_platform) = prom_find_machine_type();
	prom_printf("Detected machine type: %x\n", RELOC(of_platform));

#ifndef CONFIG_RELOCATABLE
	/* Bail if this is a kdump kernel. */
@@ -2807,7 +2896,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
	 * On non-powermacs, try to instantiate RTAS. PowerMacs don't
	 * have a usable RTAS implementation.
	 */
	if (RELOC(of_platform) != PLATFORM_POWERMAC)
	if (RELOC(of_platform) != PLATFORM_POWERMAC &&
	    RELOC(of_platform) != PLATFORM_OPAL)
		prom_instantiate_rtas();

#ifdef CONFIG_PPC_POWERNV
@@ -2818,7 +2908,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
			prom_opal_hold_cpus();
			prom_opal_takeover();
		}
	}
	} else if (RELOC(of_platform) == PLATFORM_OPAL)
		prom_instantiate_opal();
#endif

	/*
@@ -2826,7 +2917,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
	 *
	 * PowerMacs use a different mechanism to spin CPUs
	 */
	if (RELOC(of_platform) != PLATFORM_POWERMAC)
	if (RELOC(of_platform) != PLATFORM_POWERMAC &&
	    RELOC(of_platform) != PLATFORM_OPAL)
		prom_hold_cpus();

	/*
@@ -2894,7 +2986,13 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
	reloc_got2(-offset);
#endif

	__start(hdr, kbase, 0);
#ifdef CONFIG_PPC_EARLY_DEBUG_OPAL
	/* OPAL early debug gets the OPAL base & entry in r8 and r9 */
	__start(hdr, kbase, 0, 0, 0,
		RELOC(prom_opal_base), RELOC(prom_opal_entry));
#else
	__start(hdr, kbase, 0, 0, 0, 0, 0);
#endif

	return 0;
}