powerpc: Run on old powermacs.
Old powermacs have a number of differences from current machines: - there is no interrupt tree in the device tree, just interrupt or AAPL,interrupt properties - the chosen node in the device tree is called /chosen@0 - the OF claim method doesn't map the memory, so we have to do an explicit map call as well - there is no /chosen/cpu property on SMP machines - the NVRAM isn't structured as a set of partitions. This adapts the merged powermac support code to cope with these issues. Signed-off-by: Paul Mackerras <paulus@samba.org>
This commit is contained in:
@@ -309,6 +309,37 @@ static int __devinit finish_node_interrupts(struct device_node *np,
|
|||||||
unsigned int *irq, virq;
|
unsigned int *irq, virq;
|
||||||
struct device_node *ic;
|
struct device_node *ic;
|
||||||
|
|
||||||
|
if (num_interrupt_controllers == 0) {
|
||||||
|
/*
|
||||||
|
* Old machines just have a list of interrupt numbers
|
||||||
|
* and no interrupt-controller nodes.
|
||||||
|
*/
|
||||||
|
ints = (unsigned int *) get_property(np, "AAPL,interrupts",
|
||||||
|
&intlen);
|
||||||
|
/* XXX old interpret_pci_props looked in parent too */
|
||||||
|
/* XXX old interpret_macio_props looked for interrupts
|
||||||
|
before AAPL,interrupts */
|
||||||
|
if (ints == NULL)
|
||||||
|
ints = (unsigned int *) get_property(np, "interrupts",
|
||||||
|
&intlen);
|
||||||
|
if (ints == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
np->n_intrs = intlen / sizeof(unsigned int);
|
||||||
|
np->intrs = prom_alloc(np->n_intrs * sizeof(np->intrs[0]),
|
||||||
|
mem_start);
|
||||||
|
if (!np->intrs)
|
||||||
|
return -ENOMEM;
|
||||||
|
if (measure_only)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (i = 0; i < np->n_intrs; ++i) {
|
||||||
|
np->intrs[i].line = *ints++;
|
||||||
|
np->intrs[i].sense = 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ints = (unsigned int *) get_property(np, "interrupts", &intlen);
|
ints = (unsigned int *) get_property(np, "interrupts", &intlen);
|
||||||
if (ints == NULL)
|
if (ints == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1024,6 +1055,8 @@ void __init unflatten_device_tree(void)
|
|||||||
|
|
||||||
/* Get pointer to OF "/chosen" node for use everywhere */
|
/* Get pointer to OF "/chosen" node for use everywhere */
|
||||||
of_chosen = of_find_node_by_path("/chosen");
|
of_chosen = of_find_node_by_path("/chosen");
|
||||||
|
if (of_chosen == NULL)
|
||||||
|
of_chosen = of_find_node_by_path("/chosen@0");
|
||||||
|
|
||||||
/* Retreive command line */
|
/* Retreive command line */
|
||||||
if (of_chosen != NULL) {
|
if (of_chosen != NULL) {
|
||||||
@@ -1123,7 +1156,8 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
|
|||||||
|
|
||||||
DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
|
DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
|
||||||
|
|
||||||
if (depth != 1 || strcmp(uname, "chosen") != 0)
|
if (depth != 1 ||
|
||||||
|
(strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* get platform type */
|
/* get platform type */
|
||||||
|
@@ -132,6 +132,7 @@ struct prom_t {
|
|||||||
ihandle chosen;
|
ihandle chosen;
|
||||||
int cpu;
|
int cpu;
|
||||||
ihandle stdout;
|
ihandle stdout;
|
||||||
|
ihandle mmumap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mem_map_entry {
|
struct mem_map_entry {
|
||||||
@@ -274,14 +275,6 @@ static int __init call_prom_ret(const char *service, int nargs, int nret,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
|
|
||||||
unsigned long align)
|
|
||||||
{
|
|
||||||
return (unsigned int)call_prom("claim", 3, 1,
|
|
||||||
(prom_arg_t)virt, (prom_arg_t)size,
|
|
||||||
(prom_arg_t)align);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __init prom_print(const char *msg)
|
static void __init prom_print(const char *msg)
|
||||||
{
|
{
|
||||||
const char *p, *q;
|
const char *p, *q;
|
||||||
@@ -363,6 +356,21 @@ static void __init prom_printf(const char *format, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned int __init prom_claim(unsigned long virt, unsigned long size,
|
||||||
|
unsigned long align)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct prom_t *_prom = &RELOC(prom);
|
||||||
|
|
||||||
|
ret = call_prom("claim", 3, 1, (prom_arg_t)virt, (prom_arg_t)size,
|
||||||
|
(prom_arg_t)align);
|
||||||
|
if (ret != -1 && _prom->mmumap != 0)
|
||||||
|
/* old pmacs need us to map as well */
|
||||||
|
call_prom("call-method", 6, 1,
|
||||||
|
ADDR("map"), _prom->mmumap, 0, size, virt, virt);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void __init __attribute__((noreturn)) prom_panic(const char *reason)
|
static void __init __attribute__((noreturn)) prom_panic(const char *reason)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
@@ -1323,8 +1331,38 @@ static void __init prom_init_client_services(unsigned long pp)
|
|||||||
_prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
|
_prom->root = call_prom("finddevice", 1, 1, ADDR("/"));
|
||||||
if (!PHANDLE_VALID(_prom->root))
|
if (!PHANDLE_VALID(_prom->root))
|
||||||
prom_panic("cannot find device tree root"); /* msg won't be printed :( */
|
prom_panic("cannot find device tree root"); /* msg won't be printed :( */
|
||||||
|
|
||||||
|
_prom->mmumap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PPC32
|
||||||
|
/*
|
||||||
|
* For really old powermacs, we need to map things we claim.
|
||||||
|
* For that, we need the ihandle of the mmu.
|
||||||
|
*/
|
||||||
|
static void __init prom_find_mmu(void)
|
||||||
|
{
|
||||||
|
struct prom_t *_prom = &RELOC(prom);
|
||||||
|
phandle oprom;
|
||||||
|
char version[64];
|
||||||
|
|
||||||
|
oprom = call_prom("finddevice", 1, 1, ADDR("/openprom"));
|
||||||
|
if (!PHANDLE_VALID(oprom))
|
||||||
|
return;
|
||||||
|
if (prom_getprop(oprom, "model", version, sizeof(version)) <= 0)
|
||||||
|
return;
|
||||||
|
version[sizeof(version) - 1] = 0;
|
||||||
|
prom_printf("OF version is '%s'\n", version);
|
||||||
|
/* XXX might need to add other versions here */
|
||||||
|
if (strcmp(version, "Open Firmware, 1.0.5") != 0)
|
||||||
|
return;
|
||||||
|
prom_getprop(_prom->chosen, "mmu", &_prom->mmumap,
|
||||||
|
sizeof(_prom->mmumap));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define prom_find_mmu()
|
||||||
|
#endif
|
||||||
|
|
||||||
static void __init prom_init_stdout(void)
|
static void __init prom_init_stdout(void)
|
||||||
{
|
{
|
||||||
struct prom_t *_prom = &RELOC(prom);
|
struct prom_t *_prom = &RELOC(prom);
|
||||||
@@ -1379,7 +1417,7 @@ static int __init prom_find_machine_type(void)
|
|||||||
if (sl == 0)
|
if (sl == 0)
|
||||||
break;
|
break;
|
||||||
if (strstr(p, RELOC("Power Macintosh")) ||
|
if (strstr(p, RELOC("Power Macintosh")) ||
|
||||||
strstr(p, RELOC("MacRISC4")))
|
strstr(p, RELOC("MacRISC")))
|
||||||
return PLATFORM_POWERMAC;
|
return PLATFORM_POWERMAC;
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
if (strstr(p, RELOC("Momentum,Maple")))
|
if (strstr(p, RELOC("Momentum,Maple")))
|
||||||
@@ -1618,22 +1656,17 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
|
|||||||
namep[l] = '\0';
|
namep[l] = '\0';
|
||||||
|
|
||||||
/* Fixup an Apple bug where they have bogus \0 chars in the
|
/* Fixup an Apple bug where they have bogus \0 chars in the
|
||||||
* middle of the path in some properties
|
* middle of the path in some properties, and extract
|
||||||
|
* the unit name (everything after the last '/').
|
||||||
*/
|
*/
|
||||||
for (p = namep, ep = namep + l; p < ep; p++)
|
for (lp = p = namep, ep = namep + l; p < ep; p++) {
|
||||||
if (*p == '\0') {
|
|
||||||
memmove(p, p+1, ep - p);
|
|
||||||
ep--; l--; p--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now try to extract the unit name in that mess */
|
|
||||||
for (p = namep, lp = NULL; *p; p++)
|
|
||||||
if (*p == '/')
|
if (*p == '/')
|
||||||
lp = p + 1;
|
lp = namep;
|
||||||
if (lp != NULL)
|
else if (*p != 0)
|
||||||
memmove(namep, lp, strlen(lp) + 1);
|
*lp++ = *p;
|
||||||
*mem_start = _ALIGN(((unsigned long) namep) +
|
}
|
||||||
strlen(namep) + 1, 4);
|
*lp = 0;
|
||||||
|
*mem_start = _ALIGN((unsigned long)lp + 1, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get it again for debugging */
|
/* get it again for debugging */
|
||||||
@@ -1858,8 +1891,9 @@ static void __init prom_find_boot_cpu(void)
|
|||||||
ihandle prom_cpu;
|
ihandle prom_cpu;
|
||||||
phandle cpu_pkg;
|
phandle cpu_pkg;
|
||||||
|
|
||||||
|
_prom->cpu = 0;
|
||||||
if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0)
|
if (prom_getprop(_prom->chosen, "cpu", &prom_cpu, sizeof(prom_cpu)) <= 0)
|
||||||
prom_panic("cannot find boot cpu");
|
return;
|
||||||
|
|
||||||
cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
|
cpu_pkg = call_prom("instance-to-package", 1, 1, prom_cpu);
|
||||||
|
|
||||||
@@ -1933,6 +1967,11 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
|
|||||||
*/
|
*/
|
||||||
prom_init_stdout();
|
prom_init_stdout();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See if this OF is old enough that we need to do explicit maps
|
||||||
|
*/
|
||||||
|
prom_find_mmu();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for an initrd
|
* Check for an initrd
|
||||||
*/
|
*/
|
||||||
|
@@ -225,7 +225,7 @@ int find_via_pmu(void)
|
|||||||
return 0;
|
return 0;
|
||||||
printk("WARNING ! Your machine is PMU-based but your kernel\n");
|
printk("WARNING ! Your machine is PMU-based but your kernel\n");
|
||||||
printk(" wasn't compiled with CONFIG_ADB_PMU option !\n");
|
printk(" wasn't compiled with CONFIG_ADB_PMU option !\n");
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ static void __init l2cr_init(void)
|
|||||||
|
|
||||||
void __init pmac_setup_arch(void)
|
void __init pmac_setup_arch(void)
|
||||||
{
|
{
|
||||||
struct device_node *cpu;
|
struct device_node *cpu, *ic;
|
||||||
int *fp;
|
int *fp;
|
||||||
unsigned long pvr;
|
unsigned long pvr;
|
||||||
|
|
||||||
@@ -319,6 +319,12 @@ void __init pmac_setup_arch(void)
|
|||||||
of_node_put(cpu);
|
of_node_put(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See if newworld or oldworld */
|
||||||
|
ic = of_find_node_by_name(NULL, "interrupt-controller");
|
||||||
|
pmac_newworld = (ic != NULL);
|
||||||
|
if (ic)
|
||||||
|
of_node_put(ic);
|
||||||
|
|
||||||
/* Lookup PCI hosts */
|
/* Lookup PCI hosts */
|
||||||
pmac_pci_init();
|
pmac_pci_init();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user