📄 pmac_feature.c
字号:
{ PMAC_FTR_IDE_RESET, core99_ide_reset }, { PMAC_FTR_GMAC_ENABLE, core99_gmac_enable }, { PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset }, { PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable }, { PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable }, { PMAC_FTR_USB_ENABLE, core99_usb_enable }, { PMAC_FTR_1394_ENABLE, core99_firewire_enable }, { PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power }, { PMAC_FTR_SLEEP_STATE, core99_sleep_state }, { PMAC_FTR_READ_GPIO, core99_read_gpio }, { PMAC_FTR_WRITE_GPIO, core99_write_gpio }, { 0, NULL }}; static struct pmac_mb_def pmac_mb_defs[] __pmacdata = { /* Warning: ordering is important as some models may claim * beeing compatible with several types */ { "AAPL,8500", "PowerMac 8500/8600", PMAC_TYPE_PSURGE, NULL, 0 }, { "AAPL,9500", "PowerMac 9500/9600", PMAC_TYPE_PSURGE, NULL, 0 }, { "AAPL,7500", "PowerMac 7500", PMAC_TYPE_PSURGE, NULL, 0 }, { "AAPL,e407", "Alchemy", PMAC_TYPE_ALCHEMY, NULL, 0 }, { "AAPL,e411", "Gazelle", PMAC_TYPE_GAZELLE, NULL, 0 }, { "AAPL,3400/2400", "PowerBook 3400", PMAC_TYPE_HOOPER, ohare_features, PMAC_MB_CAN_SLEEP }, { "AAPL,3500", "PowerBook 3500", PMAC_TYPE_KANGA, ohare_features, PMAC_MB_CAN_SLEEP }, { "AAPL,Gossamer", "PowerMac G3 (Gossamer)", PMAC_TYPE_GOSSAMER, heathrow_desktop_features, 0 }, { "AAPL,PowerMac G3", "PowerMac G3 (Silk)", PMAC_TYPE_SILK, heathrow_desktop_features, 0 }, { "AAPL,PowerBook1998", "PowerBook Wallstreet", PMAC_TYPE_WALLSTREET, heathrow_laptop_features, PMAC_MB_CAN_SLEEP }, { "AAPL,PowerBook1,1", "PowerBook 101 (Lombard)", PMAC_TYPE_101_PBOOK, paddington_features, PMAC_MB_CAN_SLEEP }, { "iMac,1", "iMac (first generation)", PMAC_TYPE_ORIG_IMAC, paddington_features, 0 }, { "PowerMac4,1", "iMac \"Flower Power\"", PMAC_TYPE_PANGEA_IMAC, pangea_features, PMAC_MB_CAN_SLEEP }, { "PowerBook4,1", "iBook 2", PMAC_TYPE_IBOOK2, pangea_features, PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER }, { "PowerMac1,1", "Blue&White G3", PMAC_TYPE_YOSEMITE, paddington_features, 0 }, { "PowerMac1,2", "PowerMac G4 PCI Graphics", PMAC_TYPE_YIKES, paddington_features, 0 }, { "PowerBook2,1", "iBook (first generation)", PMAC_TYPE_ORIG_IBOOK, core99_features, PMAC_MB_CAN_SLEEP }, { "PowerMac3,1", "PowerMac G4 AGP Graphics", PMAC_TYPE_SAWTOOTH, core99_features, 0 }, { "PowerMac3,2", "PowerMac G4 AGP Graphics", PMAC_TYPE_SAWTOOTH, core99_features, 0 }, { "PowerMac3,3", "PowerMac G4 AGP Graphics", PMAC_TYPE_SAWTOOTH, core99_features, 0 }, { "PowerMac2,1", "iMac FireWire", PMAC_TYPE_FW_IMAC, core99_features, PMAC_MB_CAN_SLEEP }, { "PowerMac2,2", "iMac FireWire", PMAC_TYPE_FW_IMAC, core99_features, PMAC_MB_CAN_SLEEP }, { "PowerBook2,2", "iBook FireWire", PMAC_TYPE_FW_IBOOK, core99_features, PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER }, { "PowerMac5,1", "PowerMac G4 Cube", PMAC_TYPE_CUBE, core99_features, }, { "PowerMac3,4", "PowerMac G4 Silver", PMAC_TYPE_QUICKSILVER, core99_features, 0 }, { "PowerMac3,5", "PowerMac G4 Silver", PMAC_TYPE_QUICKSILVER, core99_features, 0 }, { "PowerBook3,1", "PowerBook Pismo", PMAC_TYPE_PISMO, core99_features, PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER }, { "PowerBook3,2", "PowerBook Titanium", PMAC_TYPE_TITANIUM, core99_features, PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER }, { "PowerBook3,3", "PowerBook Titanium II", PMAC_TYPE_TITANIUM2, core99_features, PMAC_MB_CAN_SLEEP | PMAC_MB_HAS_FW_POWER },};/* * The toplevel feature_call callback */int __pmacpmac_do_feature_call(unsigned int selector, ...){ struct device_node* node; int param, value, i; feature_call func = NULL; va_list args; if (!pmac_mb.features) return -ENODEV; for (i=0; pmac_mb.features[i].function; i++) if (pmac_mb.features[i].selector == selector) { func = pmac_mb.features[i].function; break; } if (!func) for (i=0; any_features[i].function; i++) if (any_features[i].selector == selector) { func = any_features[i].function; break; } if (!func) return -ENODEV; va_start(args, selector); node = (struct device_node*)va_arg(args, void*); param = va_arg(args, int); value = va_arg(args, int); va_end(args); return func(node, param, value);}static int __initprobe_motherboard(void){ int i; struct macio_chip* macio = &macio_chips[0]; /* Lookup known motherboard type in device-tree */ for(i=0; i<(sizeof(pmac_mb_defs)/sizeof(struct pmac_mb_def)); i++) { if (machine_is_compatible(pmac_mb_defs[i].model_string)) { pmac_mb = pmac_mb_defs[i]; goto found; } } /* Fallback to selection depending on mac-io chip type */ switch(macio->type) { case macio_grand_central: pmac_mb.model_id = PMAC_TYPE_PSURGE; pmac_mb.model_name = "Unknown PowerSurge"; break; case macio_ohare: pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE; pmac_mb.model_name = "Unknown OHare-based"; break; case macio_heathrow: pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW; pmac_mb.model_name = "Unknown Heathrow-based"; pmac_mb.features = heathrow_desktop_features; break; case macio_paddington: pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON; pmac_mb.model_name = "Unknown Paddington-based"; pmac_mb.features = paddington_features; break; case macio_keylargo: pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99; pmac_mb.model_name = "Unknown Keylargo-based"; pmac_mb.features = core99_features; break; case macio_pangea: pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA; pmac_mb.model_name = "Unknown Pangea-based"; pmac_mb.features = pangea_features; break; default: return -ENODEV; }found: /* Fixup Hooper vs. Comet */ if (pmac_mb.model_id == PMAC_TYPE_HOOPER) { u32* mach_id_ptr = (u32*)ioremap(0xf3000034, 4); if (!mach_id_ptr) return -ENODEV; /* Here, I used to disable the media-bay on comet. It * appears this is wrong, the floppy connector is actually * a kind of media-bay and works with the current driver. */ if ((*mach_id_ptr) & 0x20000000UL) pmac_mb.model_id = PMAC_TYPE_COMET; iounmap(mach_id_ptr); } /* Set default value of powersave_nap on machines that support it. * It appears that uninorth rev 3 has a problem with it, we don't * enable it on those. In theory, the flush-on-lock property is * supposed to be set when not supported, but I'm not very confident * that all Apple OF revs did it properly, I do it the paranoid way. */ while (uninorth_base && uninorth_rev > 3) { struct device_node* np = find_path_device("/cpus"); u32 pvr = mfspr(PVR); if (!np || !np->child) { printk(KERN_WARNING "Can't find CPU(s) in device tree !\n"); break; } np = np->child; /* Nap mode not supported on SMP */ if (np->sibling) break; /* Nap mode not supported if flush-on-lock property is present */ if (get_property(np, "flush-on-lock", NULL)) break; /* Some 7450 may have problem with NAP mode too ... */ if (((pvr >> 16) == 0x8000) && ((pvr & 0xffff) < 0x0201)) break; powersave_nap = 1; printk(KERN_INFO "Processor NAP mode on idle enabled.\n"); break; } printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name); return 0;}/* Initialize the Core99 UniNorth host bridge and memory controller */static void __initprobe_uninorth(void){ unsigned long actrl; /* Locate core99 Uni-N */ uninorth_node = find_devices("uni-n"); if (uninorth_node && uninorth_node->n_addrs > 0) { uninorth_base = ioremap(uninorth_node->addrs[0].address, 0x1000); uninorth_rev = in_be32(UN_REG(UNI_N_VERSION)); } else uninorth_node = NULL; if (!uninorth_node) return; printk(KERN_INFO "Found Uninorth memory controller & host bridge, revision: %d\n", uninorth_rev); /* Set the arbitrer QAck delay according to what Apple does */ if (uninorth_rev < 0x10) { actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK; actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 : UNI_N_ARB_CTRL_QACK_DELAY) << UNI_N_ARB_CTRL_QACK_DELAY_SHIFT; UN_OUT(UNI_N_ARB_CTRL, actrl); }} static void __initprobe_one_macio(const char* name, const char* compat, int type){ struct device_node* node; int i; volatile u32* base; u32* revp; node = find_devices(name); if (!node || !node->n_addrs) return; if (compat) do { if (device_is_compatible(node, compat)) break; node = node->next; } while (node); if (!node) return; for(i=0; i<MAX_MACIO_CHIPS; i++) { if (!macio_chips[i].of_node) break; if (macio_chips[i].of_node == node) return; } if (i >= MAX_MACIO_CHIPS) { printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n"); printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name); return; } base = (volatile u32*)ioremap(node->addrs[0].address, node->addrs[0].size); if (!base) { printk(KERN_ERR "pmac_feature: Can't map mac-io chip !\n"); return; } if (type == macio_keylargo) { u32* did = (u32 *)get_property(node, "device-id", NULL); if (*did == 0x00000025) type = macio_pangea; } macio_chips[i].of_node = node; macio_chips[i].type = type; macio_chips[i].base = base; macio_chips[i].flags = MACIO_FLAG_SCCB_ON | MACIO_FLAG_SCCB_ON; revp = (u32 *)get_property(node, "revision-id", NULL); if (revp) macio_chips[i].rev = *revp; printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n", macio_names[type], macio_chips[i].rev, macio_chips[i].base);}static int __initprobe_macios(void){ /* Warning, ordering is important */ probe_one_macio("gc", NULL, macio_grand_central); probe_one_macio("ohare", NULL, macio_ohare); probe_one_macio("pci106b,7", NULL, macio_ohareII); probe_one_macio("mac-io", "keylargo", macio_keylargo); probe_one_macio("mac-io", "paddington", macio_paddington); probe_one_macio("mac-io", "gatwick", macio_gatwick); probe_one_macio("mac-io", "heathrow", macio_heathrow); /* Make sure the "main" macio chip appear first */ if (macio_chips[0].type == macio_gatwick && macio_chips[1].type == macio_heathrow) { struct macio_chip temp = macio_chips[0]; macio_chips[0] = macio_chips[1]; macio_chips[1] = temp; } if (macio_chips[0].type == macio_ohareII && macio_chips[1].type == macio_ohare) { struct macio_chip temp = macio_chips[0]; macio_chips[0] = macio_chips[1]; macio_chips[1] = temp; } return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;}static void __initinitial_serial_shutdown(struct device_node* np){ int len; struct slot_names_prop { int count; char name[1]; } *slots; char *conn; int port_type = PMAC_SCC_ASYNC; int modem = 0; slots = (struct slot_names_prop *)get_property(np, "slot-names", &len); conn = get_property(np, "AAPL,connector", &len); if (conn && (strcmp(conn, "infrared") == 0)) port_type = PMAC_SCC_IRDA; else if (device_is_compatible(np, "cobalt")) modem = 1; else if (slots && slots->count > 0) { if (strcmp(slots->name, "IrDA") == 0) port_type = PMAC_SCC_IRDA; else if (strcmp(slots->name, "Modem") == 0) modem = 1; } if (modem) pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0); pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);}static void __initset_initial_features(void){ struct device_node* np; /* That hack appears to be necessary for some StarMax motherboards * but I'm not too sure it was audited for side-effects on other * ohare based machines... * Since I still have difficulties figuring the right way to * differenciate them all and since that hack was there for a long * time, I'll keep it around */ if (macio_chips[0].type == macio_ohare && !find_devices("via-pmu")) { struct macio_chip* macio = &macio_chips[0]; MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES); } else if (macio_chips[0].type == macio_ohare) { struct macio_chip* macio = &macio_chips[0]; MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); } else if (macio_chips[1].type == macio_ohare) { struct macio_chip* macio = &macio_chips[1]; MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE); } if (macio_chips[0].type == macio_keylargo || macio_chips[0].type == macio_pangea) { /* Enable GMAC for now for PCI probing. It will be disabled * later on after PCI probe */ np = find_devices("ethernet"); while(np) { if (np->parent && device_is_compatible(np->parent, "uni-north") && device_is_compatible(np, "gmac")) core99_gmac_enable(np, 0, 1); np = np->next; } /* Enable FW before PCI probe. Will be disabled later on * Note: We should have a batter way to check that we are * dealing with uninorth internal cell and not a PCI cell * on the external PCI. The code below works though. */ np = find_devices("firewire"); while(np) { if (np->parent && device_is_compatible(np->parent, "uni-north") && (device_is_compatible(np, "pci106b,18") || device_is_compatible(np, "pci106b,30") || device_is_compatible(np, "pci11c1,5811"))) { macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED; core99_firewire_enable(np, 0, 1); } np = np->next; } /* Switch airport off */ np = find_devices("radio"); while(np) { if (np && np->parent == macio_chips[0].of_node) { macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON; core99_airport_enable(np, 0, 0); } np = np->next; } } /* On all machines, switch sound off */ if (macio_chips[0].of_node) pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE, macio_chips[0].of_node, 0, 0); /* On all machines, switch modem & serial ports off */ np = find_devices("ch-a"); while(np) { initial_serial_shutdown(np); np = np->next; } np = find_devices("ch-b"); while(np) { initial_serial_shutdown(np); np = np->next; } /* Let hardware settle down */ mdelay(10);}void __initpmac_feature_init(void){ /* Detect the UniNorth memory controller */ probe_uninorth(); /* Probe mac-io controllers */ if (probe_macios()) { printk(KERN_WARNING "No mac-io chip found\n"); return; } /* Probe machine type */ if (probe_motherboard()) printk(KERN_WARNING "Unknown PowerMac !\n"); /* Set some initial features (turn off some chips that will * be later turned on) */ set_initial_features();}void __initpmac_feature_late_init(void){ struct device_node* np; /* Request some resources late */ if (uninorth_node) request_OF_resource(uninorth_node, 0, NULL); np = find_devices("hammerhead"); if (np) request_OF_resource(np, 0, NULL); np = find_devices("interrupt-controller"); if (np) request_OF_resource(np, 0, NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -