Path: blob/master/arch/powerpc/platforms/powermac/feature.c
10818 views
/*1* Copyright (C) 1996-2001 Paul Mackerras ([email protected])2* Ben. Herrenschmidt ([email protected])3*4* This program is free software; you can redistribute it and/or5* modify it under the terms of the GNU General Public License6* as published by the Free Software Foundation; either version7* 2 of the License, or (at your option) any later version.8*9* TODO:10*11* - Replace mdelay with some schedule loop if possible12* - Shorten some obfuscated delays on some routines (like modem13* power)14* - Refcount some clocks (see darwin)15* - Split split split...16*17*/18#include <linux/types.h>19#include <linux/init.h>20#include <linux/delay.h>21#include <linux/kernel.h>22#include <linux/sched.h>23#include <linux/of.h>24#include <linux/of_address.h>25#include <linux/spinlock.h>26#include <linux/adb.h>27#include <linux/pmu.h>28#include <linux/ioport.h>29#include <linux/pci.h>30#include <asm/sections.h>31#include <asm/errno.h>32#include <asm/ohare.h>33#include <asm/heathrow.h>34#include <asm/keylargo.h>35#include <asm/uninorth.h>36#include <asm/io.h>37#include <asm/prom.h>38#include <asm/machdep.h>39#include <asm/pmac_feature.h>40#include <asm/dbdma.h>41#include <asm/pci-bridge.h>42#include <asm/pmac_low_i2c.h>4344#undef DEBUG_FEATURE4546#ifdef DEBUG_FEATURE47#define DBG(fmt...) printk(KERN_DEBUG fmt)48#else49#define DBG(fmt...)50#endif5152#ifdef CONFIG_6xx53extern int powersave_lowspeed;54#endif5556extern int powersave_nap;57extern struct device_node *k2_skiplist[2];5859/*60* We use a single global lock to protect accesses. Each driver has61* to take care of its own locking62*/63DEFINE_RAW_SPINLOCK(feature_lock);6465#define LOCK(flags) raw_spin_lock_irqsave(&feature_lock, flags);66#define UNLOCK(flags) raw_spin_unlock_irqrestore(&feature_lock, flags);676869/*70* Instance of some macio stuffs71*/72struct macio_chip macio_chips[MAX_MACIO_CHIPS];7374struct macio_chip *macio_find(struct device_node *child, int type)75{76while(child) {77int i;7879for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++)80if (child == macio_chips[i].of_node &&81(!type || macio_chips[i].type == type))82return &macio_chips[i];83child = child->parent;84}85return NULL;86}87EXPORT_SYMBOL_GPL(macio_find);8889static const char *macio_names[] =90{91"Unknown",92"Grand Central",93"OHare",94"OHareII",95"Heathrow",96"Gatwick",97"Paddington",98"Keylargo",99"Pangea",100"Intrepid",101"K2",102"Shasta",103};104105106struct device_node *uninorth_node;107u32 __iomem *uninorth_base;108109static u32 uninorth_rev;110static int uninorth_maj;111static void __iomem *u3_ht_base;112113/*114* For each motherboard family, we have a table of functions pointers115* that handle the various features.116*/117118typedef long (*feature_call)(struct device_node *node, long param, long value);119120struct feature_table_entry {121unsigned int selector;122feature_call function;123};124125struct pmac_mb_def126{127const char* model_string;128const char* model_name;129int model_id;130struct feature_table_entry* features;131unsigned long board_flags;132};133static struct pmac_mb_def pmac_mb;134135/*136* Here are the chip specific feature functions137*/138139static inline int simple_feature_tweak(struct device_node *node, int type,140int reg, u32 mask, int value)141{142struct macio_chip* macio;143unsigned long flags;144145macio = macio_find(node, type);146if (!macio)147return -ENODEV;148LOCK(flags);149if (value)150MACIO_BIS(reg, mask);151else152MACIO_BIC(reg, mask);153(void)MACIO_IN32(reg);154UNLOCK(flags);155156return 0;157}158159#ifndef CONFIG_POWER4160161static long ohare_htw_scc_enable(struct device_node *node, long param,162long value)163{164struct macio_chip* macio;165unsigned long chan_mask;166unsigned long fcr;167unsigned long flags;168int htw, trans;169unsigned long rmask;170171macio = macio_find(node, 0);172if (!macio)173return -ENODEV;174if (!strcmp(node->name, "ch-a"))175chan_mask = MACIO_FLAG_SCCA_ON;176else if (!strcmp(node->name, "ch-b"))177chan_mask = MACIO_FLAG_SCCB_ON;178else179return -ENODEV;180181htw = (macio->type == macio_heathrow || macio->type == macio_paddington182|| macio->type == macio_gatwick);183/* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */184trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&185pmac_mb.model_id != PMAC_TYPE_YIKES);186if (value) {187#ifdef CONFIG_ADB_PMU188if ((param & 0xfff) == PMAC_SCC_IRDA)189pmu_enable_irled(1);190#endif /* CONFIG_ADB_PMU */191LOCK(flags);192fcr = MACIO_IN32(OHARE_FCR);193/* Check if scc cell need enabling */194if (!(fcr & OH_SCC_ENABLE)) {195fcr |= OH_SCC_ENABLE;196if (htw) {197/* Side effect: this will also power up the198* modem, but it's too messy to figure out on which199* ports this controls the tranceiver and on which200* it controls the modem201*/202if (trans)203fcr &= ~HRW_SCC_TRANS_EN_N;204MACIO_OUT32(OHARE_FCR, fcr);205fcr |= (rmask = HRW_RESET_SCC);206MACIO_OUT32(OHARE_FCR, fcr);207} else {208fcr |= (rmask = OH_SCC_RESET);209MACIO_OUT32(OHARE_FCR, fcr);210}211UNLOCK(flags);212(void)MACIO_IN32(OHARE_FCR);213mdelay(15);214LOCK(flags);215fcr &= ~rmask;216MACIO_OUT32(OHARE_FCR, fcr);217}218if (chan_mask & MACIO_FLAG_SCCA_ON)219fcr |= OH_SCCA_IO;220if (chan_mask & MACIO_FLAG_SCCB_ON)221fcr |= OH_SCCB_IO;222MACIO_OUT32(OHARE_FCR, fcr);223macio->flags |= chan_mask;224UNLOCK(flags);225if (param & PMAC_SCC_FLAG_XMON)226macio->flags |= MACIO_FLAG_SCC_LOCKED;227} else {228if (macio->flags & MACIO_FLAG_SCC_LOCKED)229return -EPERM;230LOCK(flags);231fcr = MACIO_IN32(OHARE_FCR);232if (chan_mask & MACIO_FLAG_SCCA_ON)233fcr &= ~OH_SCCA_IO;234if (chan_mask & MACIO_FLAG_SCCB_ON)235fcr &= ~OH_SCCB_IO;236MACIO_OUT32(OHARE_FCR, fcr);237if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {238fcr &= ~OH_SCC_ENABLE;239if (htw && trans)240fcr |= HRW_SCC_TRANS_EN_N;241MACIO_OUT32(OHARE_FCR, fcr);242}243macio->flags &= ~(chan_mask);244UNLOCK(flags);245mdelay(10);246#ifdef CONFIG_ADB_PMU247if ((param & 0xfff) == PMAC_SCC_IRDA)248pmu_enable_irled(0);249#endif /* CONFIG_ADB_PMU */250}251return 0;252}253254static long ohare_floppy_enable(struct device_node *node, long param,255long value)256{257return simple_feature_tweak(node, macio_ohare,258OHARE_FCR, OH_FLOPPY_ENABLE, value);259}260261static long ohare_mesh_enable(struct device_node *node, long param, long value)262{263return simple_feature_tweak(node, macio_ohare,264OHARE_FCR, OH_MESH_ENABLE, value);265}266267static long ohare_ide_enable(struct device_node *node, long param, long value)268{269switch(param) {270case 0:271/* For some reason, setting the bit in set_initial_features()272* doesn't stick. I'm still investigating... --BenH.273*/274if (value)275simple_feature_tweak(node, macio_ohare,276OHARE_FCR, OH_IOBUS_ENABLE, 1);277return simple_feature_tweak(node, macio_ohare,278OHARE_FCR, OH_IDE0_ENABLE, value);279case 1:280return simple_feature_tweak(node, macio_ohare,281OHARE_FCR, OH_BAY_IDE_ENABLE, value);282default:283return -ENODEV;284}285}286287static long ohare_ide_reset(struct device_node *node, long param, long value)288{289switch(param) {290case 0:291return simple_feature_tweak(node, macio_ohare,292OHARE_FCR, OH_IDE0_RESET_N, !value);293case 1:294return simple_feature_tweak(node, macio_ohare,295OHARE_FCR, OH_IDE1_RESET_N, !value);296default:297return -ENODEV;298}299}300301static long ohare_sleep_state(struct device_node *node, long param, long value)302{303struct macio_chip* macio = &macio_chips[0];304305if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)306return -EPERM;307if (value == 1) {308MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);309} else if (value == 0) {310MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);311}312313return 0;314}315316static long heathrow_modem_enable(struct device_node *node, long param,317long value)318{319struct macio_chip* macio;320u8 gpio;321unsigned long flags;322323macio = macio_find(node, macio_unknown);324if (!macio)325return -ENODEV;326gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;327if (!value) {328LOCK(flags);329MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);330UNLOCK(flags);331(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);332mdelay(250);333}334if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&335pmac_mb.model_id != PMAC_TYPE_YIKES) {336LOCK(flags);337if (value)338MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);339else340MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);341UNLOCK(flags);342(void)MACIO_IN32(HEATHROW_FCR);343mdelay(250);344}345if (value) {346LOCK(flags);347MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);348(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);349UNLOCK(flags); mdelay(250); LOCK(flags);350MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);351(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);352UNLOCK(flags); mdelay(250); LOCK(flags);353MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);354(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);355UNLOCK(flags); mdelay(250);356}357return 0;358}359360static long heathrow_floppy_enable(struct device_node *node, long param,361long value)362{363return simple_feature_tweak(node, macio_unknown,364HEATHROW_FCR,365HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,366value);367}368369static long heathrow_mesh_enable(struct device_node *node, long param,370long value)371{372struct macio_chip* macio;373unsigned long flags;374375macio = macio_find(node, macio_unknown);376if (!macio)377return -ENODEV;378LOCK(flags);379/* Set clear mesh cell enable */380if (value)381MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);382else383MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);384(void)MACIO_IN32(HEATHROW_FCR);385udelay(10);386/* Set/Clear termination power */387if (value)388MACIO_BIC(HEATHROW_MBCR, 0x04000000);389else390MACIO_BIS(HEATHROW_MBCR, 0x04000000);391(void)MACIO_IN32(HEATHROW_MBCR);392udelay(10);393UNLOCK(flags);394395return 0;396}397398static long heathrow_ide_enable(struct device_node *node, long param,399long value)400{401switch(param) {402case 0:403return simple_feature_tweak(node, macio_unknown,404HEATHROW_FCR, HRW_IDE0_ENABLE, value);405case 1:406return simple_feature_tweak(node, macio_unknown,407HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);408default:409return -ENODEV;410}411}412413static long heathrow_ide_reset(struct device_node *node, long param,414long value)415{416switch(param) {417case 0:418return simple_feature_tweak(node, macio_unknown,419HEATHROW_FCR, HRW_IDE0_RESET_N, !value);420case 1:421return simple_feature_tweak(node, macio_unknown,422HEATHROW_FCR, HRW_IDE1_RESET_N, !value);423default:424return -ENODEV;425}426}427428static long heathrow_bmac_enable(struct device_node *node, long param,429long value)430{431struct macio_chip* macio;432unsigned long flags;433434macio = macio_find(node, 0);435if (!macio)436return -ENODEV;437if (value) {438LOCK(flags);439MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);440MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);441UNLOCK(flags);442(void)MACIO_IN32(HEATHROW_FCR);443mdelay(10);444LOCK(flags);445MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);446UNLOCK(flags);447(void)MACIO_IN32(HEATHROW_FCR);448mdelay(10);449} else {450LOCK(flags);451MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);452UNLOCK(flags);453}454return 0;455}456457static long heathrow_sound_enable(struct device_node *node, long param,458long value)459{460struct macio_chip* macio;461unsigned long flags;462463/* B&W G3 and Yikes don't support that properly (the464* sound appear to never come back after beeing shut down).465*/466if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||467pmac_mb.model_id == PMAC_TYPE_YIKES)468return 0;469470macio = macio_find(node, 0);471if (!macio)472return -ENODEV;473if (value) {474LOCK(flags);475MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);476MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);477UNLOCK(flags);478(void)MACIO_IN32(HEATHROW_FCR);479} else {480LOCK(flags);481MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);482MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);483UNLOCK(flags);484}485return 0;486}487488static u32 save_fcr[6];489static u32 save_mbcr;490static struct dbdma_regs save_dbdma[13];491static struct dbdma_regs save_alt_dbdma[13];492493static void dbdma_save(struct macio_chip *macio, struct dbdma_regs *save)494{495int i;496497/* Save state & config of DBDMA channels */498for (i = 0; i < 13; i++) {499volatile struct dbdma_regs __iomem * chan = (void __iomem *)500(macio->base + ((0x8000+i*0x100)>>2));501save[i].cmdptr_hi = in_le32(&chan->cmdptr_hi);502save[i].cmdptr = in_le32(&chan->cmdptr);503save[i].intr_sel = in_le32(&chan->intr_sel);504save[i].br_sel = in_le32(&chan->br_sel);505save[i].wait_sel = in_le32(&chan->wait_sel);506}507}508509static void dbdma_restore(struct macio_chip *macio, struct dbdma_regs *save)510{511int i;512513/* Save state & config of DBDMA channels */514for (i = 0; i < 13; i++) {515volatile struct dbdma_regs __iomem * chan = (void __iomem *)516(macio->base + ((0x8000+i*0x100)>>2));517out_le32(&chan->control, (ACTIVE|DEAD|WAKE|FLUSH|PAUSE|RUN)<<16);518while (in_le32(&chan->status) & ACTIVE)519mb();520out_le32(&chan->cmdptr_hi, save[i].cmdptr_hi);521out_le32(&chan->cmdptr, save[i].cmdptr);522out_le32(&chan->intr_sel, save[i].intr_sel);523out_le32(&chan->br_sel, save[i].br_sel);524out_le32(&chan->wait_sel, save[i].wait_sel);525}526}527528static void heathrow_sleep(struct macio_chip *macio, int secondary)529{530if (secondary) {531dbdma_save(macio, save_alt_dbdma);532save_fcr[2] = MACIO_IN32(0x38);533save_fcr[3] = MACIO_IN32(0x3c);534} else {535dbdma_save(macio, save_dbdma);536save_fcr[0] = MACIO_IN32(0x38);537save_fcr[1] = MACIO_IN32(0x3c);538save_mbcr = MACIO_IN32(0x34);539/* Make sure sound is shut down */540MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);541MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);542/* This seems to be necessary as well or the fan543* keeps coming up and battery drains fast */544MACIO_BIC(HEATHROW_FCR, HRW_IOBUS_ENABLE);545MACIO_BIC(HEATHROW_FCR, HRW_IDE0_RESET_N);546/* Make sure eth is down even if module or sleep547* won't work properly */548MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE | HRW_BMAC_RESET);549}550/* Make sure modem is shut down */551MACIO_OUT8(HRW_GPIO_MODEM_RESET,552MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1);553MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);554MACIO_BIC(HEATHROW_FCR, OH_SCCA_IO|OH_SCCB_IO|HRW_SCC_ENABLE);555556/* Let things settle */557(void)MACIO_IN32(HEATHROW_FCR);558}559560static void heathrow_wakeup(struct macio_chip *macio, int secondary)561{562if (secondary) {563MACIO_OUT32(0x38, save_fcr[2]);564(void)MACIO_IN32(0x38);565mdelay(1);566MACIO_OUT32(0x3c, save_fcr[3]);567(void)MACIO_IN32(0x38);568mdelay(10);569dbdma_restore(macio, save_alt_dbdma);570} else {571MACIO_OUT32(0x38, save_fcr[0] | HRW_IOBUS_ENABLE);572(void)MACIO_IN32(0x38);573mdelay(1);574MACIO_OUT32(0x3c, save_fcr[1]);575(void)MACIO_IN32(0x38);576mdelay(1);577MACIO_OUT32(0x34, save_mbcr);578(void)MACIO_IN32(0x38);579mdelay(10);580dbdma_restore(macio, save_dbdma);581}582}583584static long heathrow_sleep_state(struct device_node *node, long param,585long value)586{587if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)588return -EPERM;589if (value == 1) {590if (macio_chips[1].type == macio_gatwick)591heathrow_sleep(&macio_chips[0], 1);592heathrow_sleep(&macio_chips[0], 0);593} else if (value == 0) {594heathrow_wakeup(&macio_chips[0], 0);595if (macio_chips[1].type == macio_gatwick)596heathrow_wakeup(&macio_chips[0], 1);597}598return 0;599}600601static long core99_scc_enable(struct device_node *node, long param, long value)602{603struct macio_chip* macio;604unsigned long flags;605unsigned long chan_mask;606u32 fcr;607608macio = macio_find(node, 0);609if (!macio)610return -ENODEV;611if (!strcmp(node->name, "ch-a"))612chan_mask = MACIO_FLAG_SCCA_ON;613else if (!strcmp(node->name, "ch-b"))614chan_mask = MACIO_FLAG_SCCB_ON;615else616return -ENODEV;617618if (value) {619int need_reset_scc = 0;620int need_reset_irda = 0;621622LOCK(flags);623fcr = MACIO_IN32(KEYLARGO_FCR0);624/* Check if scc cell need enabling */625if (!(fcr & KL0_SCC_CELL_ENABLE)) {626fcr |= KL0_SCC_CELL_ENABLE;627need_reset_scc = 1;628}629if (chan_mask & MACIO_FLAG_SCCA_ON) {630fcr |= KL0_SCCA_ENABLE;631/* Don't enable line drivers for I2S modem */632if ((param & 0xfff) == PMAC_SCC_I2S1)633fcr &= ~KL0_SCC_A_INTF_ENABLE;634else635fcr |= KL0_SCC_A_INTF_ENABLE;636}637if (chan_mask & MACIO_FLAG_SCCB_ON) {638fcr |= KL0_SCCB_ENABLE;639/* Perform irda specific inits */640if ((param & 0xfff) == PMAC_SCC_IRDA) {641fcr &= ~KL0_SCC_B_INTF_ENABLE;642fcr |= KL0_IRDA_ENABLE;643fcr |= KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE;644fcr |= KL0_IRDA_SOURCE1_SEL;645fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);646fcr &= ~(KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);647need_reset_irda = 1;648} else649fcr |= KL0_SCC_B_INTF_ENABLE;650}651MACIO_OUT32(KEYLARGO_FCR0, fcr);652macio->flags |= chan_mask;653if (need_reset_scc) {654MACIO_BIS(KEYLARGO_FCR0, KL0_SCC_RESET);655(void)MACIO_IN32(KEYLARGO_FCR0);656UNLOCK(flags);657mdelay(15);658LOCK(flags);659MACIO_BIC(KEYLARGO_FCR0, KL0_SCC_RESET);660}661if (need_reset_irda) {662MACIO_BIS(KEYLARGO_FCR0, KL0_IRDA_RESET);663(void)MACIO_IN32(KEYLARGO_FCR0);664UNLOCK(flags);665mdelay(15);666LOCK(flags);667MACIO_BIC(KEYLARGO_FCR0, KL0_IRDA_RESET);668}669UNLOCK(flags);670if (param & PMAC_SCC_FLAG_XMON)671macio->flags |= MACIO_FLAG_SCC_LOCKED;672} else {673if (macio->flags & MACIO_FLAG_SCC_LOCKED)674return -EPERM;675LOCK(flags);676fcr = MACIO_IN32(KEYLARGO_FCR0);677if (chan_mask & MACIO_FLAG_SCCA_ON)678fcr &= ~KL0_SCCA_ENABLE;679if (chan_mask & MACIO_FLAG_SCCB_ON) {680fcr &= ~KL0_SCCB_ENABLE;681/* Perform irda specific clears */682if ((param & 0xfff) == PMAC_SCC_IRDA) {683fcr &= ~KL0_IRDA_ENABLE;684fcr &= ~(KL0_IRDA_CLK32_ENABLE | KL0_IRDA_CLK19_ENABLE);685fcr &= ~(KL0_IRDA_FAST_CONNECT|KL0_IRDA_DEFAULT1|KL0_IRDA_DEFAULT0);686fcr &= ~(KL0_IRDA_SOURCE1_SEL|KL0_IRDA_SOURCE2_SEL|KL0_IRDA_HIGH_BAND);687}688}689MACIO_OUT32(KEYLARGO_FCR0, fcr);690if ((fcr & (KL0_SCCA_ENABLE | KL0_SCCB_ENABLE)) == 0) {691fcr &= ~KL0_SCC_CELL_ENABLE;692MACIO_OUT32(KEYLARGO_FCR0, fcr);693}694macio->flags &= ~(chan_mask);695UNLOCK(flags);696mdelay(10);697}698return 0;699}700701static long702core99_modem_enable(struct device_node *node, long param, long value)703{704struct macio_chip* macio;705u8 gpio;706unsigned long flags;707708/* Hack for internal USB modem */709if (node == NULL) {710if (macio_chips[0].type != macio_keylargo)711return -ENODEV;712node = macio_chips[0].of_node;713}714macio = macio_find(node, 0);715if (!macio)716return -ENODEV;717gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);718gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;719gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;720721if (!value) {722LOCK(flags);723MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);724UNLOCK(flags);725(void)MACIO_IN8(KL_GPIO_MODEM_RESET);726mdelay(250);727}728LOCK(flags);729if (value) {730MACIO_BIC(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);731UNLOCK(flags);732(void)MACIO_IN32(KEYLARGO_FCR2);733mdelay(250);734} else {735MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);736UNLOCK(flags);737}738if (value) {739LOCK(flags);740MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);741(void)MACIO_IN8(KL_GPIO_MODEM_RESET);742UNLOCK(flags); mdelay(250); LOCK(flags);743MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);744(void)MACIO_IN8(KL_GPIO_MODEM_RESET);745UNLOCK(flags); mdelay(250); LOCK(flags);746MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);747(void)MACIO_IN8(KL_GPIO_MODEM_RESET);748UNLOCK(flags); mdelay(250);749}750return 0;751}752753static long754pangea_modem_enable(struct device_node *node, long param, long value)755{756struct macio_chip* macio;757u8 gpio;758unsigned long flags;759760/* Hack for internal USB modem */761if (node == NULL) {762if (macio_chips[0].type != macio_pangea &&763macio_chips[0].type != macio_intrepid)764return -ENODEV;765node = macio_chips[0].of_node;766}767macio = macio_find(node, 0);768if (!macio)769return -ENODEV;770gpio = MACIO_IN8(KL_GPIO_MODEM_RESET);771gpio |= KEYLARGO_GPIO_OUTPUT_ENABLE;772gpio &= ~KEYLARGO_GPIO_OUTOUT_DATA;773774if (!value) {775LOCK(flags);776MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);777UNLOCK(flags);778(void)MACIO_IN8(KL_GPIO_MODEM_RESET);779mdelay(250);780}781LOCK(flags);782if (value) {783MACIO_OUT8(KL_GPIO_MODEM_POWER,784KEYLARGO_GPIO_OUTPUT_ENABLE);785UNLOCK(flags);786(void)MACIO_IN32(KEYLARGO_FCR2);787mdelay(250);788} else {789MACIO_OUT8(KL_GPIO_MODEM_POWER,790KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);791UNLOCK(flags);792}793if (value) {794LOCK(flags);795MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);796(void)MACIO_IN8(KL_GPIO_MODEM_RESET);797UNLOCK(flags); mdelay(250); LOCK(flags);798MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio);799(void)MACIO_IN8(KL_GPIO_MODEM_RESET);800UNLOCK(flags); mdelay(250); LOCK(flags);801MACIO_OUT8(KL_GPIO_MODEM_RESET, gpio | KEYLARGO_GPIO_OUTOUT_DATA);802(void)MACIO_IN8(KL_GPIO_MODEM_RESET);803UNLOCK(flags); mdelay(250);804}805return 0;806}807808static long809core99_ata100_enable(struct device_node *node, long value)810{811unsigned long flags;812struct pci_dev *pdev = NULL;813u8 pbus, pid;814int rc;815816if (uninorth_rev < 0x24)817return -ENODEV;818819LOCK(flags);820if (value)821UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);822else823UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_ATA100);824(void)UN_IN(UNI_N_CLOCK_CNTL);825UNLOCK(flags);826udelay(20);827828if (value) {829if (pci_device_from_OF_node(node, &pbus, &pid) == 0)830pdev = pci_get_bus_and_slot(pbus, pid);831if (pdev == NULL)832return 0;833rc = pci_enable_device(pdev);834if (rc == 0)835pci_set_master(pdev);836pci_dev_put(pdev);837if (rc)838return rc;839}840return 0;841}842843static long844core99_ide_enable(struct device_node *node, long param, long value)845{846/* Bus ID 0 to 2 are KeyLargo based IDE, busID 3 is U2847* based ata-100848*/849switch(param) {850case 0:851return simple_feature_tweak(node, macio_unknown,852KEYLARGO_FCR1, KL1_EIDE0_ENABLE, value);853case 1:854return simple_feature_tweak(node, macio_unknown,855KEYLARGO_FCR1, KL1_EIDE1_ENABLE, value);856case 2:857return simple_feature_tweak(node, macio_unknown,858KEYLARGO_FCR1, KL1_UIDE_ENABLE, value);859case 3:860return core99_ata100_enable(node, value);861default:862return -ENODEV;863}864}865866static long867core99_ide_reset(struct device_node *node, long param, long value)868{869switch(param) {870case 0:871return simple_feature_tweak(node, macio_unknown,872KEYLARGO_FCR1, KL1_EIDE0_RESET_N, !value);873case 1:874return simple_feature_tweak(node, macio_unknown,875KEYLARGO_FCR1, KL1_EIDE1_RESET_N, !value);876case 2:877return simple_feature_tweak(node, macio_unknown,878KEYLARGO_FCR1, KL1_UIDE_RESET_N, !value);879default:880return -ENODEV;881}882}883884static long885core99_gmac_enable(struct device_node *node, long param, long value)886{887unsigned long flags;888889LOCK(flags);890if (value)891UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);892else893UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_GMAC);894(void)UN_IN(UNI_N_CLOCK_CNTL);895UNLOCK(flags);896udelay(20);897898return 0;899}900901static long902core99_gmac_phy_reset(struct device_node *node, long param, long value)903{904unsigned long flags;905struct macio_chip *macio;906907macio = &macio_chips[0];908if (macio->type != macio_keylargo && macio->type != macio_pangea &&909macio->type != macio_intrepid)910return -ENODEV;911912LOCK(flags);913MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, KEYLARGO_GPIO_OUTPUT_ENABLE);914(void)MACIO_IN8(KL_GPIO_ETH_PHY_RESET);915UNLOCK(flags);916mdelay(10);917LOCK(flags);918MACIO_OUT8(KL_GPIO_ETH_PHY_RESET, /*KEYLARGO_GPIO_OUTPUT_ENABLE | */919KEYLARGO_GPIO_OUTOUT_DATA);920UNLOCK(flags);921mdelay(10);922923return 0;924}925926static long927core99_sound_chip_enable(struct device_node *node, long param, long value)928{929struct macio_chip* macio;930unsigned long flags;931932macio = macio_find(node, 0);933if (!macio)934return -ENODEV;935936/* Do a better probe code, screamer G4 desktops &937* iMacs can do that too, add a recalibrate in938* the driver as well939*/940if (pmac_mb.model_id == PMAC_TYPE_PISMO ||941pmac_mb.model_id == PMAC_TYPE_TITANIUM) {942LOCK(flags);943if (value)944MACIO_OUT8(KL_GPIO_SOUND_POWER,945KEYLARGO_GPIO_OUTPUT_ENABLE |946KEYLARGO_GPIO_OUTOUT_DATA);947else948MACIO_OUT8(KL_GPIO_SOUND_POWER,949KEYLARGO_GPIO_OUTPUT_ENABLE);950(void)MACIO_IN8(KL_GPIO_SOUND_POWER);951UNLOCK(flags);952}953return 0;954}955956static long957core99_airport_enable(struct device_node *node, long param, long value)958{959struct macio_chip* macio;960unsigned long flags;961int state;962963macio = macio_find(node, 0);964if (!macio)965return -ENODEV;966967/* Hint: we allow passing of macio itself for the sake of the968* sleep code969*/970if (node != macio->of_node &&971(!node->parent || node->parent != macio->of_node))972return -ENODEV;973state = (macio->flags & MACIO_FLAG_AIRPORT_ON) != 0;974if (value == state)975return 0;976if (value) {977/* This code is a reproduction of OF enable-cardslot978* and init-wireless methods, slightly hacked until979* I got it working.980*/981LOCK(flags);982MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 5);983(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);984UNLOCK(flags);985mdelay(10);986LOCK(flags);987MACIO_OUT8(KEYLARGO_GPIO_0+0xf, 4);988(void)MACIO_IN8(KEYLARGO_GPIO_0+0xf);989UNLOCK(flags);990991mdelay(10);992993LOCK(flags);994MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);995(void)MACIO_IN32(KEYLARGO_FCR2);996udelay(10);997MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xb, 0);998(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xb);999udelay(10);1000MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xa, 0x28);1001(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xa);1002udelay(10);1003MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+0xd, 0x28);1004(void)MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+0xd);1005udelay(10);1006MACIO_OUT8(KEYLARGO_GPIO_0+0xd, 0x28);1007(void)MACIO_IN8(KEYLARGO_GPIO_0+0xd);1008udelay(10);1009MACIO_OUT8(KEYLARGO_GPIO_0+0xe, 0x28);1010(void)MACIO_IN8(KEYLARGO_GPIO_0+0xe);1011UNLOCK(flags);1012udelay(10);1013MACIO_OUT32(0x1c000, 0);1014mdelay(1);1015MACIO_OUT8(0x1a3e0, 0x41);1016(void)MACIO_IN8(0x1a3e0);1017udelay(10);1018LOCK(flags);1019MACIO_BIS(KEYLARGO_FCR2, KL2_CARDSEL_16);1020(void)MACIO_IN32(KEYLARGO_FCR2);1021UNLOCK(flags);1022mdelay(100);10231024macio->flags |= MACIO_FLAG_AIRPORT_ON;1025} else {1026LOCK(flags);1027MACIO_BIC(KEYLARGO_FCR2, KL2_CARDSEL_16);1028(void)MACIO_IN32(KEYLARGO_FCR2);1029MACIO_OUT8(KL_GPIO_AIRPORT_0, 0);1030MACIO_OUT8(KL_GPIO_AIRPORT_1, 0);1031MACIO_OUT8(KL_GPIO_AIRPORT_2, 0);1032MACIO_OUT8(KL_GPIO_AIRPORT_3, 0);1033MACIO_OUT8(KL_GPIO_AIRPORT_4, 0);1034(void)MACIO_IN8(KL_GPIO_AIRPORT_4);1035UNLOCK(flags);10361037macio->flags &= ~MACIO_FLAG_AIRPORT_ON;1038}1039return 0;1040}10411042#ifdef CONFIG_SMP1043static long1044core99_reset_cpu(struct device_node *node, long param, long value)1045{1046unsigned int reset_io = 0;1047unsigned long flags;1048struct macio_chip *macio;1049struct device_node *np;1050struct device_node *cpus;1051const int dflt_reset_lines[] = { KL_GPIO_RESET_CPU0,1052KL_GPIO_RESET_CPU1,1053KL_GPIO_RESET_CPU2,1054KL_GPIO_RESET_CPU3 };10551056macio = &macio_chips[0];1057if (macio->type != macio_keylargo)1058return -ENODEV;10591060cpus = of_find_node_by_path("/cpus");1061if (cpus == NULL)1062return -ENODEV;1063for (np = cpus->child; np != NULL; np = np->sibling) {1064const u32 *num = of_get_property(np, "reg", NULL);1065const u32 *rst = of_get_property(np, "soft-reset", NULL);1066if (num == NULL || rst == NULL)1067continue;1068if (param == *num) {1069reset_io = *rst;1070break;1071}1072}1073of_node_put(cpus);1074if (np == NULL || reset_io == 0)1075reset_io = dflt_reset_lines[param];10761077LOCK(flags);1078MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);1079(void)MACIO_IN8(reset_io);1080udelay(1);1081MACIO_OUT8(reset_io, 0);1082(void)MACIO_IN8(reset_io);1083UNLOCK(flags);10841085return 0;1086}1087#endif /* CONFIG_SMP */10881089static long1090core99_usb_enable(struct device_node *node, long param, long value)1091{1092struct macio_chip *macio;1093unsigned long flags;1094const char *prop;1095int number;1096u32 reg;10971098macio = &macio_chips[0];1099if (macio->type != macio_keylargo && macio->type != macio_pangea &&1100macio->type != macio_intrepid)1101return -ENODEV;11021103prop = of_get_property(node, "AAPL,clock-id", NULL);1104if (!prop)1105return -ENODEV;1106if (strncmp(prop, "usb0u048", 8) == 0)1107number = 0;1108else if (strncmp(prop, "usb1u148", 8) == 0)1109number = 2;1110else if (strncmp(prop, "usb2u248", 8) == 0)1111number = 4;1112else1113return -ENODEV;11141115/* Sorry for the brute-force locking, but this is only used during1116* sleep and the timing seem to be critical1117*/1118LOCK(flags);1119if (value) {1120/* Turn ON */1121if (number == 0) {1122MACIO_BIC(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));1123(void)MACIO_IN32(KEYLARGO_FCR0);1124UNLOCK(flags);1125mdelay(1);1126LOCK(flags);1127MACIO_BIS(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);1128} else if (number == 2) {1129MACIO_BIC(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));1130UNLOCK(flags);1131(void)MACIO_IN32(KEYLARGO_FCR0);1132mdelay(1);1133LOCK(flags);1134MACIO_BIS(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);1135} else if (number == 4) {1136MACIO_BIC(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));1137UNLOCK(flags);1138(void)MACIO_IN32(KEYLARGO_FCR1);1139mdelay(1);1140LOCK(flags);1141MACIO_BIS(KEYLARGO_FCR1, KL1_USB2_CELL_ENABLE);1142}1143if (number < 4) {1144reg = MACIO_IN32(KEYLARGO_FCR4);1145reg &= ~(KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |1146KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number));1147reg &= ~(KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |1148KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1));1149MACIO_OUT32(KEYLARGO_FCR4, reg);1150(void)MACIO_IN32(KEYLARGO_FCR4);1151udelay(10);1152} else {1153reg = MACIO_IN32(KEYLARGO_FCR3);1154reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |1155KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0));1156reg &= ~(KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |1157KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1));1158MACIO_OUT32(KEYLARGO_FCR3, reg);1159(void)MACIO_IN32(KEYLARGO_FCR3);1160udelay(10);1161}1162if (macio->type == macio_intrepid) {1163/* wait for clock stopped bits to clear */1164u32 test0 = 0, test1 = 0;1165u32 status0, status1;1166int timeout = 1000;11671168UNLOCK(flags);1169switch (number) {1170case 0:1171test0 = UNI_N_CLOCK_STOPPED_USB0;1172test1 = UNI_N_CLOCK_STOPPED_USB0PCI;1173break;1174case 2:1175test0 = UNI_N_CLOCK_STOPPED_USB1;1176test1 = UNI_N_CLOCK_STOPPED_USB1PCI;1177break;1178case 4:1179test0 = UNI_N_CLOCK_STOPPED_USB2;1180test1 = UNI_N_CLOCK_STOPPED_USB2PCI;1181break;1182}1183do {1184if (--timeout <= 0) {1185printk(KERN_ERR "core99_usb_enable: "1186"Timeout waiting for clocks\n");1187break;1188}1189mdelay(1);1190status0 = UN_IN(UNI_N_CLOCK_STOP_STATUS0);1191status1 = UN_IN(UNI_N_CLOCK_STOP_STATUS1);1192} while ((status0 & test0) | (status1 & test1));1193LOCK(flags);1194}1195} else {1196/* Turn OFF */1197if (number < 4) {1198reg = MACIO_IN32(KEYLARGO_FCR4);1199reg |= KL4_PORT_WAKEUP_ENABLE(number) | KL4_PORT_RESUME_WAKE_EN(number) |1200KL4_PORT_CONNECT_WAKE_EN(number) | KL4_PORT_DISCONNECT_WAKE_EN(number);1201reg |= KL4_PORT_WAKEUP_ENABLE(number+1) | KL4_PORT_RESUME_WAKE_EN(number+1) |1202KL4_PORT_CONNECT_WAKE_EN(number+1) | KL4_PORT_DISCONNECT_WAKE_EN(number+1);1203MACIO_OUT32(KEYLARGO_FCR4, reg);1204(void)MACIO_IN32(KEYLARGO_FCR4);1205udelay(1);1206} else {1207reg = MACIO_IN32(KEYLARGO_FCR3);1208reg |= KL3_IT_PORT_WAKEUP_ENABLE(0) | KL3_IT_PORT_RESUME_WAKE_EN(0) |1209KL3_IT_PORT_CONNECT_WAKE_EN(0) | KL3_IT_PORT_DISCONNECT_WAKE_EN(0);1210reg |= KL3_IT_PORT_WAKEUP_ENABLE(1) | KL3_IT_PORT_RESUME_WAKE_EN(1) |1211KL3_IT_PORT_CONNECT_WAKE_EN(1) | KL3_IT_PORT_DISCONNECT_WAKE_EN(1);1212MACIO_OUT32(KEYLARGO_FCR3, reg);1213(void)MACIO_IN32(KEYLARGO_FCR3);1214udelay(1);1215}1216if (number == 0) {1217if (macio->type != macio_intrepid)1218MACIO_BIC(KEYLARGO_FCR0, KL0_USB0_CELL_ENABLE);1219(void)MACIO_IN32(KEYLARGO_FCR0);1220udelay(1);1221MACIO_BIS(KEYLARGO_FCR0, (KL0_USB0_PAD_SUSPEND0 | KL0_USB0_PAD_SUSPEND1));1222(void)MACIO_IN32(KEYLARGO_FCR0);1223} else if (number == 2) {1224if (macio->type != macio_intrepid)1225MACIO_BIC(KEYLARGO_FCR0, KL0_USB1_CELL_ENABLE);1226(void)MACIO_IN32(KEYLARGO_FCR0);1227udelay(1);1228MACIO_BIS(KEYLARGO_FCR0, (KL0_USB1_PAD_SUSPEND0 | KL0_USB1_PAD_SUSPEND1));1229(void)MACIO_IN32(KEYLARGO_FCR0);1230} else if (number == 4) {1231udelay(1);1232MACIO_BIS(KEYLARGO_FCR1, (KL1_USB2_PAD_SUSPEND0 | KL1_USB2_PAD_SUSPEND1));1233(void)MACIO_IN32(KEYLARGO_FCR1);1234}1235udelay(1);1236}1237UNLOCK(flags);12381239return 0;1240}12411242static long1243core99_firewire_enable(struct device_node *node, long param, long value)1244{1245unsigned long flags;1246struct macio_chip *macio;12471248macio = &macio_chips[0];1249if (macio->type != macio_keylargo && macio->type != macio_pangea &&1250macio->type != macio_intrepid)1251return -ENODEV;1252if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))1253return -ENODEV;12541255LOCK(flags);1256if (value) {1257UN_BIS(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);1258(void)UN_IN(UNI_N_CLOCK_CNTL);1259} else {1260UN_BIC(UNI_N_CLOCK_CNTL, UNI_N_CLOCK_CNTL_FW);1261(void)UN_IN(UNI_N_CLOCK_CNTL);1262}1263UNLOCK(flags);1264mdelay(1);12651266return 0;1267}12681269static long1270core99_firewire_cable_power(struct device_node *node, long param, long value)1271{1272unsigned long flags;1273struct macio_chip *macio;12741275/* Trick: we allow NULL node */1276if ((pmac_mb.board_flags & PMAC_MB_HAS_FW_POWER) == 0)1277return -ENODEV;1278macio = &macio_chips[0];1279if (macio->type != macio_keylargo && macio->type != macio_pangea &&1280macio->type != macio_intrepid)1281return -ENODEV;1282if (!(macio->flags & MACIO_FLAG_FW_SUPPORTED))1283return -ENODEV;12841285LOCK(flags);1286if (value) {1287MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 0);1288MACIO_IN8(KL_GPIO_FW_CABLE_POWER);1289udelay(10);1290} else {1291MACIO_OUT8(KL_GPIO_FW_CABLE_POWER , 4);1292MACIO_IN8(KL_GPIO_FW_CABLE_POWER); udelay(10);1293}1294UNLOCK(flags);1295mdelay(1);12961297return 0;1298}12991300static long1301intrepid_aack_delay_enable(struct device_node *node, long param, long value)1302{1303unsigned long flags;13041305if (uninorth_rev < 0xd2)1306return -ENODEV;13071308LOCK(flags);1309if (param)1310UN_BIS(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);1311else1312UN_BIC(UNI_N_AACK_DELAY, UNI_N_AACK_DELAY_ENABLE);1313UNLOCK(flags);13141315return 0;1316}131713181319#endif /* CONFIG_POWER4 */13201321static long1322core99_read_gpio(struct device_node *node, long param, long value)1323{1324struct macio_chip *macio = &macio_chips[0];13251326return MACIO_IN8(param);1327}132813291330static long1331core99_write_gpio(struct device_node *node, long param, long value)1332{1333struct macio_chip *macio = &macio_chips[0];13341335MACIO_OUT8(param, (u8)(value & 0xff));1336return 0;1337}13381339#ifdef CONFIG_POWER41340static long g5_gmac_enable(struct device_node *node, long param, long value)1341{1342struct macio_chip *macio = &macio_chips[0];1343unsigned long flags;13441345if (node == NULL)1346return -ENODEV;13471348LOCK(flags);1349if (value) {1350MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);1351mb();1352k2_skiplist[0] = NULL;1353} else {1354k2_skiplist[0] = node;1355mb();1356MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);1357}13581359UNLOCK(flags);1360mdelay(1);13611362return 0;1363}13641365static long g5_fw_enable(struct device_node *node, long param, long value)1366{1367struct macio_chip *macio = &macio_chips[0];1368unsigned long flags;13691370if (node == NULL)1371return -ENODEV;13721373LOCK(flags);1374if (value) {1375MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);1376mb();1377k2_skiplist[1] = NULL;1378} else {1379k2_skiplist[1] = node;1380mb();1381MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);1382}13831384UNLOCK(flags);1385mdelay(1);13861387return 0;1388}13891390static long g5_mpic_enable(struct device_node *node, long param, long value)1391{1392unsigned long flags;1393struct device_node *parent = of_get_parent(node);1394int is_u3;13951396if (parent == NULL)1397return 0;1398is_u3 = strcmp(parent->name, "u3") == 0 ||1399strcmp(parent->name, "u4") == 0;1400of_node_put(parent);1401if (!is_u3)1402return 0;14031404LOCK(flags);1405UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE);1406UNLOCK(flags);14071408return 0;1409}14101411static long g5_eth_phy_reset(struct device_node *node, long param, long value)1412{1413struct macio_chip *macio = &macio_chips[0];1414struct device_node *phy;1415int need_reset;14161417/*1418* We must not reset the combo PHYs, only the BCM5221 found in1419* the iMac G5.1420*/1421phy = of_get_next_child(node, NULL);1422if (!phy)1423return -ENODEV;1424need_reset = of_device_is_compatible(phy, "B5221");1425of_node_put(phy);1426if (!need_reset)1427return 0;14281429/* PHY reset is GPIO 29, not in device-tree unfortunately */1430MACIO_OUT8(K2_GPIO_EXTINT_0 + 29,1431KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);1432/* Thankfully, this is now always called at a time when we can1433* schedule by sungem.1434*/1435msleep(10);1436MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0);14371438return 0;1439}14401441static long g5_i2s_enable(struct device_node *node, long param, long value)1442{1443/* Very crude implementation for now */1444struct macio_chip *macio = &macio_chips[0];1445unsigned long flags;1446int cell;1447u32 fcrs[3][3] = {1448{ 0,1449K2_FCR1_I2S0_CELL_ENABLE |1450K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE,1451KL3_I2S0_CLK18_ENABLE1452},1453{ KL0_SCC_A_INTF_ENABLE,1454K2_FCR1_I2S1_CELL_ENABLE |1455K2_FCR1_I2S1_CLK_ENABLE_BIT | K2_FCR1_I2S1_ENABLE,1456KL3_I2S1_CLK18_ENABLE1457},1458{ KL0_SCC_B_INTF_ENABLE,1459SH_FCR1_I2S2_CELL_ENABLE |1460SH_FCR1_I2S2_CLK_ENABLE_BIT | SH_FCR1_I2S2_ENABLE,1461SH_FCR3_I2S2_CLK18_ENABLE1462},1463};14641465if (macio->type != macio_keylargo2 && macio->type != macio_shasta)1466return -ENODEV;1467if (strncmp(node->name, "i2s-", 4))1468return -ENODEV;1469cell = node->name[4] - 'a';1470switch(cell) {1471case 0:1472case 1:1473break;1474case 2:1475if (macio->type == macio_shasta)1476break;1477default:1478return -ENODEV;1479}14801481LOCK(flags);1482if (value) {1483MACIO_BIC(KEYLARGO_FCR0, fcrs[cell][0]);1484MACIO_BIS(KEYLARGO_FCR1, fcrs[cell][1]);1485MACIO_BIS(KEYLARGO_FCR3, fcrs[cell][2]);1486} else {1487MACIO_BIC(KEYLARGO_FCR3, fcrs[cell][2]);1488MACIO_BIC(KEYLARGO_FCR1, fcrs[cell][1]);1489MACIO_BIS(KEYLARGO_FCR0, fcrs[cell][0]);1490}1491udelay(10);1492UNLOCK(flags);14931494return 0;1495}149614971498#ifdef CONFIG_SMP1499static long g5_reset_cpu(struct device_node *node, long param, long value)1500{1501unsigned int reset_io = 0;1502unsigned long flags;1503struct macio_chip *macio;1504struct device_node *np;1505struct device_node *cpus;15061507macio = &macio_chips[0];1508if (macio->type != macio_keylargo2 && macio->type != macio_shasta)1509return -ENODEV;15101511cpus = of_find_node_by_path("/cpus");1512if (cpus == NULL)1513return -ENODEV;1514for (np = cpus->child; np != NULL; np = np->sibling) {1515const u32 *num = of_get_property(np, "reg", NULL);1516const u32 *rst = of_get_property(np, "soft-reset", NULL);1517if (num == NULL || rst == NULL)1518continue;1519if (param == *num) {1520reset_io = *rst;1521break;1522}1523}1524of_node_put(cpus);1525if (np == NULL || reset_io == 0)1526return -ENODEV;15271528LOCK(flags);1529MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE);1530(void)MACIO_IN8(reset_io);1531udelay(1);1532MACIO_OUT8(reset_io, 0);1533(void)MACIO_IN8(reset_io);1534UNLOCK(flags);15351536return 0;1537}1538#endif /* CONFIG_SMP */15391540/*1541* This can be called from pmac_smp so isn't static1542*1543* This takes the second CPU off the bus on dual CPU machines1544* running UP1545*/1546void g5_phy_disable_cpu1(void)1547{1548if (uninorth_maj == 3)1549UN_OUT(U3_API_PHY_CONFIG_1, 0);1550}1551#endif /* CONFIG_POWER4 */15521553#ifndef CONFIG_POWER4155415551556#ifdef CONFIG_PM1557static u32 save_gpio_levels[2];1558static u8 save_gpio_extint[KEYLARGO_GPIO_EXTINT_CNT];1559static u8 save_gpio_normal[KEYLARGO_GPIO_CNT];1560static u32 save_unin_clock_ctl;15611562static void keylargo_shutdown(struct macio_chip *macio, int sleep_mode)1563{1564u32 temp;15651566if (sleep_mode) {1567mdelay(1);1568MACIO_BIS(KEYLARGO_FCR0, KL0_USB_REF_SUSPEND);1569(void)MACIO_IN32(KEYLARGO_FCR0);1570mdelay(1);1571}15721573MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |1574KL0_SCC_CELL_ENABLE |1575KL0_IRDA_ENABLE | KL0_IRDA_CLK32_ENABLE |1576KL0_IRDA_CLK19_ENABLE);15771578MACIO_BIC(KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK);1579MACIO_BIS(KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE);15801581MACIO_BIC(KEYLARGO_FCR1,1582KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |1583KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |1584KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |1585KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |1586KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |1587KL1_EIDE0_ENABLE | KL1_EIDE0_RESET_N |1588KL1_EIDE1_ENABLE | KL1_EIDE1_RESET_N |1589KL1_UIDE_ENABLE);15901591MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);1592MACIO_BIC(KEYLARGO_FCR2, KL2_IOBUS_ENABLE);15931594temp = MACIO_IN32(KEYLARGO_FCR3);1595if (macio->rev >= 2) {1596temp |= KL3_SHUTDOWN_PLL2X;1597if (sleep_mode)1598temp |= KL3_SHUTDOWN_PLL_TOTAL;1599}16001601temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |1602KL3_SHUTDOWN_PLLKW35;1603if (sleep_mode)1604temp |= KL3_SHUTDOWN_PLLKW12;1605temp &= ~(KL3_CLK66_ENABLE | KL3_CLK49_ENABLE | KL3_CLK45_ENABLE1606| KL3_CLK31_ENABLE | KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);1607if (sleep_mode)1608temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_VIA_CLK16_ENABLE);1609MACIO_OUT32(KEYLARGO_FCR3, temp);16101611/* Flush posted writes & wait a bit */1612(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);1613}16141615static void pangea_shutdown(struct macio_chip *macio, int sleep_mode)1616{1617u32 temp;16181619MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |1620KL0_SCC_CELL_ENABLE |1621KL0_USB0_CELL_ENABLE | KL0_USB1_CELL_ENABLE);16221623MACIO_BIC(KEYLARGO_FCR1,1624KL1_AUDIO_SEL_22MCLK | KL1_AUDIO_CLK_ENABLE_BIT |1625KL1_AUDIO_CLK_OUT_ENABLE | KL1_AUDIO_CELL_ENABLE |1626KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |1627KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |1628KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |1629KL1_UIDE_ENABLE);1630if (pmac_mb.board_flags & PMAC_MB_MOBILE)1631MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);16321633MACIO_BIS(KEYLARGO_FCR2, KL2_ALT_DATA_OUT);16341635temp = MACIO_IN32(KEYLARGO_FCR3);1636temp |= KL3_SHUTDOWN_PLLKW6 | KL3_SHUTDOWN_PLLKW4 |1637KL3_SHUTDOWN_PLLKW35;1638temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE | KL3_CLK31_ENABLE1639| KL3_I2S0_CLK18_ENABLE | KL3_I2S1_CLK18_ENABLE);1640if (sleep_mode)1641temp &= ~(KL3_VIA_CLK16_ENABLE | KL3_TIMER_CLK18_ENABLE);1642MACIO_OUT32(KEYLARGO_FCR3, temp);16431644/* Flush posted writes & wait a bit */1645(void)MACIO_IN32(KEYLARGO_FCR0); mdelay(1);1646}16471648static void intrepid_shutdown(struct macio_chip *macio, int sleep_mode)1649{1650u32 temp;16511652MACIO_BIC(KEYLARGO_FCR0,KL0_SCCA_ENABLE | KL0_SCCB_ENABLE |1653KL0_SCC_CELL_ENABLE);16541655MACIO_BIC(KEYLARGO_FCR1,1656KL1_I2S0_CELL_ENABLE | KL1_I2S0_CLK_ENABLE_BIT |1657KL1_I2S0_ENABLE | KL1_I2S1_CELL_ENABLE |1658KL1_I2S1_CLK_ENABLE_BIT | KL1_I2S1_ENABLE |1659KL1_EIDE0_ENABLE);1660if (pmac_mb.board_flags & PMAC_MB_MOBILE)1661MACIO_BIC(KEYLARGO_FCR1, KL1_UIDE_RESET_N);16621663temp = MACIO_IN32(KEYLARGO_FCR3);1664temp &= ~(KL3_CLK49_ENABLE | KL3_CLK45_ENABLE |1665KL3_I2S1_CLK18_ENABLE | KL3_I2S0_CLK18_ENABLE);1666if (sleep_mode)1667temp &= ~(KL3_TIMER_CLK18_ENABLE | KL3_IT_VIA_CLK32_ENABLE);1668MACIO_OUT32(KEYLARGO_FCR3, temp);16691670/* Flush posted writes & wait a bit */1671(void)MACIO_IN32(KEYLARGO_FCR0);1672mdelay(10);1673}167416751676static int1677core99_sleep(void)1678{1679struct macio_chip *macio;1680int i;16811682macio = &macio_chips[0];1683if (macio->type != macio_keylargo && macio->type != macio_pangea &&1684macio->type != macio_intrepid)1685return -ENODEV;16861687/* We power off the wireless slot in case it was not done1688* by the driver. We don't power it on automatically however1689*/1690if (macio->flags & MACIO_FLAG_AIRPORT_ON)1691core99_airport_enable(macio->of_node, 0, 0);16921693/* We power off the FW cable. Should be done by the driver... */1694if (macio->flags & MACIO_FLAG_FW_SUPPORTED) {1695core99_firewire_enable(NULL, 0, 0);1696core99_firewire_cable_power(NULL, 0, 0);1697}16981699/* We make sure int. modem is off (in case driver lost it) */1700if (macio->type == macio_keylargo)1701core99_modem_enable(macio->of_node, 0, 0);1702else1703pangea_modem_enable(macio->of_node, 0, 0);17041705/* We make sure the sound is off as well */1706core99_sound_chip_enable(macio->of_node, 0, 0);17071708/*1709* Save various bits of KeyLargo1710*/17111712/* Save the state of the various GPIOs */1713save_gpio_levels[0] = MACIO_IN32(KEYLARGO_GPIO_LEVELS0);1714save_gpio_levels[1] = MACIO_IN32(KEYLARGO_GPIO_LEVELS1);1715for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)1716save_gpio_extint[i] = MACIO_IN8(KEYLARGO_GPIO_EXTINT_0+i);1717for (i=0; i<KEYLARGO_GPIO_CNT; i++)1718save_gpio_normal[i] = MACIO_IN8(KEYLARGO_GPIO_0+i);17191720/* Save the FCRs */1721if (macio->type == macio_keylargo)1722save_mbcr = MACIO_IN32(KEYLARGO_MBCR);1723save_fcr[0] = MACIO_IN32(KEYLARGO_FCR0);1724save_fcr[1] = MACIO_IN32(KEYLARGO_FCR1);1725save_fcr[2] = MACIO_IN32(KEYLARGO_FCR2);1726save_fcr[3] = MACIO_IN32(KEYLARGO_FCR3);1727save_fcr[4] = MACIO_IN32(KEYLARGO_FCR4);1728if (macio->type == macio_pangea || macio->type == macio_intrepid)1729save_fcr[5] = MACIO_IN32(KEYLARGO_FCR5);17301731/* Save state & config of DBDMA channels */1732dbdma_save(macio, save_dbdma);17331734/*1735* Turn off as much as we can1736*/1737if (macio->type == macio_pangea)1738pangea_shutdown(macio, 1);1739else if (macio->type == macio_intrepid)1740intrepid_shutdown(macio, 1);1741else if (macio->type == macio_keylargo)1742keylargo_shutdown(macio, 1);17431744/*1745* Put the host bridge to sleep1746*/17471748save_unin_clock_ctl = UN_IN(UNI_N_CLOCK_CNTL);1749/* Note: do not switch GMAC off, driver does it when necessary, WOL must keep it1750* enabled !1751*/1752UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl &1753~(/*UNI_N_CLOCK_CNTL_GMAC|*/UNI_N_CLOCK_CNTL_FW/*|UNI_N_CLOCK_CNTL_PCI*/));1754udelay(100);1755UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);1756UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_SLEEP);1757mdelay(10);17581759/*1760* FIXME: A bit of black magic with OpenPIC (don't ask me why)1761*/1762if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {1763MACIO_BIS(0x506e0, 0x00400000);1764MACIO_BIS(0x506e0, 0x80000000);1765}1766return 0;1767}17681769static int1770core99_wake_up(void)1771{1772struct macio_chip *macio;1773int i;17741775macio = &macio_chips[0];1776if (macio->type != macio_keylargo && macio->type != macio_pangea &&1777macio->type != macio_intrepid)1778return -ENODEV;17791780/*1781* Wakeup the host bridge1782*/1783UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);1784udelay(10);1785UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);1786udelay(10);17871788/*1789* Restore KeyLargo1790*/17911792if (macio->type == macio_keylargo) {1793MACIO_OUT32(KEYLARGO_MBCR, save_mbcr);1794(void)MACIO_IN32(KEYLARGO_MBCR); udelay(10);1795}1796MACIO_OUT32(KEYLARGO_FCR0, save_fcr[0]);1797(void)MACIO_IN32(KEYLARGO_FCR0); udelay(10);1798MACIO_OUT32(KEYLARGO_FCR1, save_fcr[1]);1799(void)MACIO_IN32(KEYLARGO_FCR1); udelay(10);1800MACIO_OUT32(KEYLARGO_FCR2, save_fcr[2]);1801(void)MACIO_IN32(KEYLARGO_FCR2); udelay(10);1802MACIO_OUT32(KEYLARGO_FCR3, save_fcr[3]);1803(void)MACIO_IN32(KEYLARGO_FCR3); udelay(10);1804MACIO_OUT32(KEYLARGO_FCR4, save_fcr[4]);1805(void)MACIO_IN32(KEYLARGO_FCR4); udelay(10);1806if (macio->type == macio_pangea || macio->type == macio_intrepid) {1807MACIO_OUT32(KEYLARGO_FCR5, save_fcr[5]);1808(void)MACIO_IN32(KEYLARGO_FCR5); udelay(10);1809}18101811dbdma_restore(macio, save_dbdma);18121813MACIO_OUT32(KEYLARGO_GPIO_LEVELS0, save_gpio_levels[0]);1814MACIO_OUT32(KEYLARGO_GPIO_LEVELS1, save_gpio_levels[1]);1815for (i=0; i<KEYLARGO_GPIO_EXTINT_CNT; i++)1816MACIO_OUT8(KEYLARGO_GPIO_EXTINT_0+i, save_gpio_extint[i]);1817for (i=0; i<KEYLARGO_GPIO_CNT; i++)1818MACIO_OUT8(KEYLARGO_GPIO_0+i, save_gpio_normal[i]);18191820/* FIXME more black magic with OpenPIC ... */1821if (pmac_mb.model_id == PMAC_TYPE_SAWTOOTH) {1822MACIO_BIC(0x506e0, 0x00400000);1823MACIO_BIC(0x506e0, 0x80000000);1824}18251826UN_OUT(UNI_N_CLOCK_CNTL, save_unin_clock_ctl);1827udelay(100);18281829return 0;1830}18311832#endif /* CONFIG_PM */18331834static long1835core99_sleep_state(struct device_node *node, long param, long value)1836{1837/* Param == 1 means to enter the "fake sleep" mode that is1838* used for CPU speed switch1839*/1840if (param == 1) {1841if (value == 1) {1842UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_SLEEPING);1843UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_IDLE2);1844} else {1845UN_OUT(UNI_N_POWER_MGT, UNI_N_POWER_MGT_NORMAL);1846udelay(10);1847UN_OUT(UNI_N_HWINIT_STATE, UNI_N_HWINIT_STATE_RUNNING);1848udelay(10);1849}1850return 0;1851}1852if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)1853return -EPERM;18541855#ifdef CONFIG_PM1856if (value == 1)1857return core99_sleep();1858else if (value == 0)1859return core99_wake_up();18601861#endif /* CONFIG_PM */1862return 0;1863}18641865#endif /* CONFIG_POWER4 */18661867static long1868generic_dev_can_wake(struct device_node *node, long param, long value)1869{1870/* Todo: eventually check we are really dealing with on-board1871* video device ...1872*/18731874if (pmac_mb.board_flags & PMAC_MB_MAY_SLEEP)1875pmac_mb.board_flags |= PMAC_MB_CAN_SLEEP;1876return 0;1877}18781879static long generic_get_mb_info(struct device_node *node, long param, long value)1880{1881switch(param) {1882case PMAC_MB_INFO_MODEL:1883return pmac_mb.model_id;1884case PMAC_MB_INFO_FLAGS:1885return pmac_mb.board_flags;1886case PMAC_MB_INFO_NAME:1887/* hack hack hack... but should work */1888*((const char **)value) = pmac_mb.model_name;1889return 0;1890}1891return -EINVAL;1892}189318941895/*1896* Table definitions1897*/18981899/* Used on any machine1900*/1901static struct feature_table_entry any_features[] = {1902{ PMAC_FTR_GET_MB_INFO, generic_get_mb_info },1903{ PMAC_FTR_DEVICE_CAN_WAKE, generic_dev_can_wake },1904{ 0, NULL }1905};19061907#ifndef CONFIG_POWER419081909/* OHare based motherboards. Currently, we only use these on the1910* 2400,3400 and 3500 series powerbooks. Some older desktops seem1911* to have issues with turning on/off those asic cells1912*/1913static struct feature_table_entry ohare_features[] = {1914{ PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable },1915{ PMAC_FTR_SWIM3_ENABLE, ohare_floppy_enable },1916{ PMAC_FTR_MESH_ENABLE, ohare_mesh_enable },1917{ PMAC_FTR_IDE_ENABLE, ohare_ide_enable},1918{ PMAC_FTR_IDE_RESET, ohare_ide_reset},1919{ PMAC_FTR_SLEEP_STATE, ohare_sleep_state },1920{ 0, NULL }1921};19221923/* Heathrow desktop machines (Beige G3).1924* Separated as some features couldn't be properly tested1925* and the serial port control bits appear to confuse it.1926*/1927static struct feature_table_entry heathrow_desktop_features[] = {1928{ PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable },1929{ PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable },1930{ PMAC_FTR_IDE_ENABLE, heathrow_ide_enable },1931{ PMAC_FTR_IDE_RESET, heathrow_ide_reset },1932{ PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable },1933{ 0, NULL }1934};19351936/* Heathrow based laptop, that is the Wallstreet and mainstreet1937* powerbooks.1938*/1939static struct feature_table_entry heathrow_laptop_features[] = {1940{ PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable },1941{ PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable },1942{ PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable },1943{ PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable },1944{ PMAC_FTR_IDE_ENABLE, heathrow_ide_enable },1945{ PMAC_FTR_IDE_RESET, heathrow_ide_reset },1946{ PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable },1947{ PMAC_FTR_SOUND_CHIP_ENABLE, heathrow_sound_enable },1948{ PMAC_FTR_SLEEP_STATE, heathrow_sleep_state },1949{ 0, NULL }1950};19511952/* Paddington based machines1953* The lombard (101) powerbook, first iMac models, B&W G3 and Yikes G4.1954*/1955static struct feature_table_entry paddington_features[] = {1956{ PMAC_FTR_SCC_ENABLE, ohare_htw_scc_enable },1957{ PMAC_FTR_MODEM_ENABLE, heathrow_modem_enable },1958{ PMAC_FTR_SWIM3_ENABLE, heathrow_floppy_enable },1959{ PMAC_FTR_MESH_ENABLE, heathrow_mesh_enable },1960{ PMAC_FTR_IDE_ENABLE, heathrow_ide_enable },1961{ PMAC_FTR_IDE_RESET, heathrow_ide_reset },1962{ PMAC_FTR_BMAC_ENABLE, heathrow_bmac_enable },1963{ PMAC_FTR_SOUND_CHIP_ENABLE, heathrow_sound_enable },1964{ PMAC_FTR_SLEEP_STATE, heathrow_sleep_state },1965{ 0, NULL }1966};19671968/* Core99 & MacRISC 2 machines (all machines released since the1969* iBook (included), that is all AGP machines, except pangea1970* chipset. The pangea chipset is the "combo" UniNorth/KeyLargo1971* used on iBook2 & iMac "flow power".1972*/1973static struct feature_table_entry core99_features[] = {1974{ PMAC_FTR_SCC_ENABLE, core99_scc_enable },1975{ PMAC_FTR_MODEM_ENABLE, core99_modem_enable },1976{ PMAC_FTR_IDE_ENABLE, core99_ide_enable },1977{ PMAC_FTR_IDE_RESET, core99_ide_reset },1978{ PMAC_FTR_GMAC_ENABLE, core99_gmac_enable },1979{ PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset },1980{ PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable },1981{ PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable },1982{ PMAC_FTR_USB_ENABLE, core99_usb_enable },1983{ PMAC_FTR_1394_ENABLE, core99_firewire_enable },1984{ PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power },1985#ifdef CONFIG_PM1986{ PMAC_FTR_SLEEP_STATE, core99_sleep_state },1987#endif1988#ifdef CONFIG_SMP1989{ PMAC_FTR_RESET_CPU, core99_reset_cpu },1990#endif /* CONFIG_SMP */1991{ PMAC_FTR_READ_GPIO, core99_read_gpio },1992{ PMAC_FTR_WRITE_GPIO, core99_write_gpio },1993{ 0, NULL }1994};19951996/* RackMac1997*/1998static struct feature_table_entry rackmac_features[] = {1999{ PMAC_FTR_SCC_ENABLE, core99_scc_enable },2000{ PMAC_FTR_IDE_ENABLE, core99_ide_enable },2001{ PMAC_FTR_IDE_RESET, core99_ide_reset },2002{ PMAC_FTR_GMAC_ENABLE, core99_gmac_enable },2003{ PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset },2004{ PMAC_FTR_USB_ENABLE, core99_usb_enable },2005{ PMAC_FTR_1394_ENABLE, core99_firewire_enable },2006{ PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power },2007{ PMAC_FTR_SLEEP_STATE, core99_sleep_state },2008#ifdef CONFIG_SMP2009{ PMAC_FTR_RESET_CPU, core99_reset_cpu },2010#endif /* CONFIG_SMP */2011{ PMAC_FTR_READ_GPIO, core99_read_gpio },2012{ PMAC_FTR_WRITE_GPIO, core99_write_gpio },2013{ 0, NULL }2014};20152016/* Pangea features2017*/2018static struct feature_table_entry pangea_features[] = {2019{ PMAC_FTR_SCC_ENABLE, core99_scc_enable },2020{ PMAC_FTR_MODEM_ENABLE, pangea_modem_enable },2021{ PMAC_FTR_IDE_ENABLE, core99_ide_enable },2022{ PMAC_FTR_IDE_RESET, core99_ide_reset },2023{ PMAC_FTR_GMAC_ENABLE, core99_gmac_enable },2024{ PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset },2025{ PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable },2026{ PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable },2027{ PMAC_FTR_USB_ENABLE, core99_usb_enable },2028{ PMAC_FTR_1394_ENABLE, core99_firewire_enable },2029{ PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power },2030{ PMAC_FTR_SLEEP_STATE, core99_sleep_state },2031{ PMAC_FTR_READ_GPIO, core99_read_gpio },2032{ PMAC_FTR_WRITE_GPIO, core99_write_gpio },2033{ 0, NULL }2034};20352036/* Intrepid features2037*/2038static struct feature_table_entry intrepid_features[] = {2039{ PMAC_FTR_SCC_ENABLE, core99_scc_enable },2040{ PMAC_FTR_MODEM_ENABLE, pangea_modem_enable },2041{ PMAC_FTR_IDE_ENABLE, core99_ide_enable },2042{ PMAC_FTR_IDE_RESET, core99_ide_reset },2043{ PMAC_FTR_GMAC_ENABLE, core99_gmac_enable },2044{ PMAC_FTR_GMAC_PHY_RESET, core99_gmac_phy_reset },2045{ PMAC_FTR_SOUND_CHIP_ENABLE, core99_sound_chip_enable },2046{ PMAC_FTR_AIRPORT_ENABLE, core99_airport_enable },2047{ PMAC_FTR_USB_ENABLE, core99_usb_enable },2048{ PMAC_FTR_1394_ENABLE, core99_firewire_enable },2049{ PMAC_FTR_1394_CABLE_POWER, core99_firewire_cable_power },2050{ PMAC_FTR_SLEEP_STATE, core99_sleep_state },2051{ PMAC_FTR_READ_GPIO, core99_read_gpio },2052{ PMAC_FTR_WRITE_GPIO, core99_write_gpio },2053{ PMAC_FTR_AACK_DELAY_ENABLE, intrepid_aack_delay_enable },2054{ 0, NULL }2055};20562057#else /* CONFIG_POWER4 */20582059/* G5 features2060*/2061static struct feature_table_entry g5_features[] = {2062{ PMAC_FTR_GMAC_ENABLE, g5_gmac_enable },2063{ PMAC_FTR_1394_ENABLE, g5_fw_enable },2064{ PMAC_FTR_ENABLE_MPIC, g5_mpic_enable },2065{ PMAC_FTR_GMAC_PHY_RESET, g5_eth_phy_reset },2066{ PMAC_FTR_SOUND_CHIP_ENABLE, g5_i2s_enable },2067#ifdef CONFIG_SMP2068{ PMAC_FTR_RESET_CPU, g5_reset_cpu },2069#endif /* CONFIG_SMP */2070{ PMAC_FTR_READ_GPIO, core99_read_gpio },2071{ PMAC_FTR_WRITE_GPIO, core99_write_gpio },2072{ 0, NULL }2073};20742075#endif /* CONFIG_POWER4 */20762077static struct pmac_mb_def pmac_mb_defs[] = {2078#ifndef CONFIG_POWER42079/*2080* Desktops2081*/20822083{ "AAPL,8500", "PowerMac 8500/8600",2084PMAC_TYPE_PSURGE, NULL,208502086},2087{ "AAPL,9500", "PowerMac 9500/9600",2088PMAC_TYPE_PSURGE, NULL,208902090},2091{ "AAPL,7200", "PowerMac 7200",2092PMAC_TYPE_PSURGE, NULL,209302094},2095{ "AAPL,7300", "PowerMac 7200/7300",2096PMAC_TYPE_PSURGE, NULL,209702098},2099{ "AAPL,7500", "PowerMac 7500",2100PMAC_TYPE_PSURGE, NULL,210102102},2103{ "AAPL,ShinerESB", "Apple Network Server",2104PMAC_TYPE_ANS, NULL,210502106},2107{ "AAPL,e407", "Alchemy",2108PMAC_TYPE_ALCHEMY, NULL,210902110},2111{ "AAPL,e411", "Gazelle",2112PMAC_TYPE_GAZELLE, NULL,211302114},2115{ "AAPL,Gossamer", "PowerMac G3 (Gossamer)",2116PMAC_TYPE_GOSSAMER, heathrow_desktop_features,211702118},2119{ "AAPL,PowerMac G3", "PowerMac G3 (Silk)",2120PMAC_TYPE_SILK, heathrow_desktop_features,212102122},2123{ "PowerMac1,1", "Blue&White G3",2124PMAC_TYPE_YOSEMITE, paddington_features,212502126},2127{ "PowerMac1,2", "PowerMac G4 PCI Graphics",2128PMAC_TYPE_YIKES, paddington_features,212902130},2131{ "PowerMac2,1", "iMac FireWire",2132PMAC_TYPE_FW_IMAC, core99_features,2133PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE992134},2135{ "PowerMac2,2", "iMac FireWire",2136PMAC_TYPE_FW_IMAC, core99_features,2137PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE992138},2139{ "PowerMac3,1", "PowerMac G4 AGP Graphics",2140PMAC_TYPE_SAWTOOTH, core99_features,2141PMAC_MB_OLD_CORE992142},2143{ "PowerMac3,2", "PowerMac G4 AGP Graphics",2144PMAC_TYPE_SAWTOOTH, core99_features,2145PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE992146},2147{ "PowerMac3,3", "PowerMac G4 AGP Graphics",2148PMAC_TYPE_SAWTOOTH, core99_features,2149PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE992150},2151{ "PowerMac3,4", "PowerMac G4 Silver",2152PMAC_TYPE_QUICKSILVER, core99_features,2153PMAC_MB_MAY_SLEEP2154},2155{ "PowerMac3,5", "PowerMac G4 Silver",2156PMAC_TYPE_QUICKSILVER, core99_features,2157PMAC_MB_MAY_SLEEP2158},2159{ "PowerMac3,6", "PowerMac G4 Windtunnel",2160PMAC_TYPE_WINDTUNNEL, core99_features,2161PMAC_MB_MAY_SLEEP,2162},2163{ "PowerMac4,1", "iMac \"Flower Power\"",2164PMAC_TYPE_PANGEA_IMAC, pangea_features,2165PMAC_MB_MAY_SLEEP2166},2167{ "PowerMac4,2", "Flat panel iMac",2168PMAC_TYPE_FLAT_PANEL_IMAC, pangea_features,2169PMAC_MB_CAN_SLEEP2170},2171{ "PowerMac4,4", "eMac",2172PMAC_TYPE_EMAC, core99_features,2173PMAC_MB_MAY_SLEEP2174},2175{ "PowerMac5,1", "PowerMac G4 Cube",2176PMAC_TYPE_CUBE, core99_features,2177PMAC_MB_MAY_SLEEP | PMAC_MB_OLD_CORE992178},2179{ "PowerMac6,1", "Flat panel iMac",2180PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2181PMAC_MB_MAY_SLEEP,2182},2183{ "PowerMac6,3", "Flat panel iMac",2184PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2185PMAC_MB_MAY_SLEEP,2186},2187{ "PowerMac6,4", "eMac",2188PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2189PMAC_MB_MAY_SLEEP,2190},2191{ "PowerMac10,1", "Mac mini",2192PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2193PMAC_MB_MAY_SLEEP,2194},2195{ "PowerMac10,2", "Mac mini (Late 2005)",2196PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2197PMAC_MB_MAY_SLEEP,2198},2199{ "iMac,1", "iMac (first generation)",2200PMAC_TYPE_ORIG_IMAC, paddington_features,220102202},22032204/*2205* Xserve's2206*/22072208{ "RackMac1,1", "XServe",2209PMAC_TYPE_RACKMAC, rackmac_features,22100,2211},2212{ "RackMac1,2", "XServe rev. 2",2213PMAC_TYPE_RACKMAC, rackmac_features,22140,2215},22162217/*2218* Laptops2219*/22202221{ "AAPL,3400/2400", "PowerBook 3400",2222PMAC_TYPE_HOOPER, ohare_features,2223PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE2224},2225{ "AAPL,3500", "PowerBook 3500",2226PMAC_TYPE_KANGA, ohare_features,2227PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE2228},2229{ "AAPL,PowerBook1998", "PowerBook Wallstreet",2230PMAC_TYPE_WALLSTREET, heathrow_laptop_features,2231PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE2232},2233{ "PowerBook1,1", "PowerBook 101 (Lombard)",2234PMAC_TYPE_101_PBOOK, paddington_features,2235PMAC_MB_CAN_SLEEP | PMAC_MB_MOBILE2236},2237{ "PowerBook2,1", "iBook (first generation)",2238PMAC_TYPE_ORIG_IBOOK, core99_features,2239PMAC_MB_CAN_SLEEP | PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE2240},2241{ "PowerBook2,2", "iBook FireWire",2242PMAC_TYPE_FW_IBOOK, core99_features,2243PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |2244PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE2245},2246{ "PowerBook3,1", "PowerBook Pismo",2247PMAC_TYPE_PISMO, core99_features,2248PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER |2249PMAC_MB_OLD_CORE99 | PMAC_MB_MOBILE2250},2251{ "PowerBook3,2", "PowerBook Titanium",2252PMAC_TYPE_TITANIUM, core99_features,2253PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE2254},2255{ "PowerBook3,3", "PowerBook Titanium II",2256PMAC_TYPE_TITANIUM2, core99_features,2257PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE2258},2259{ "PowerBook3,4", "PowerBook Titanium III",2260PMAC_TYPE_TITANIUM3, core99_features,2261PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE2262},2263{ "PowerBook3,5", "PowerBook Titanium IV",2264PMAC_TYPE_TITANIUM4, core99_features,2265PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE2266},2267{ "PowerBook4,1", "iBook 2",2268PMAC_TYPE_IBOOK2, pangea_features,2269PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE2270},2271{ "PowerBook4,2", "iBook 2",2272PMAC_TYPE_IBOOK2, pangea_features,2273PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE2274},2275{ "PowerBook4,3", "iBook 2 rev. 2",2276PMAC_TYPE_IBOOK2, pangea_features,2277PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE2278},2279{ "PowerBook5,1", "PowerBook G4 17\"",2280PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2281PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2282},2283{ "PowerBook5,2", "PowerBook G4 15\"",2284PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2285PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2286},2287{ "PowerBook5,3", "PowerBook G4 17\"",2288PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2289PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2290},2291{ "PowerBook5,4", "PowerBook G4 15\"",2292PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2293PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2294},2295{ "PowerBook5,5", "PowerBook G4 17\"",2296PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2297PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2298},2299{ "PowerBook5,6", "PowerBook G4 15\"",2300PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2301PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2302},2303{ "PowerBook5,7", "PowerBook G4 17\"",2304PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2305PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2306},2307{ "PowerBook5,8", "PowerBook G4 15\"",2308PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2309PMAC_MB_MAY_SLEEP | PMAC_MB_MOBILE,2310},2311{ "PowerBook5,9", "PowerBook G4 17\"",2312PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2313PMAC_MB_MAY_SLEEP | PMAC_MB_MOBILE,2314},2315{ "PowerBook6,1", "PowerBook G4 12\"",2316PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2317PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2318},2319{ "PowerBook6,2", "PowerBook G4",2320PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2321PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2322},2323{ "PowerBook6,3", "iBook G4",2324PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2325PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2326},2327{ "PowerBook6,4", "PowerBook G4 12\"",2328PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2329PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2330},2331{ "PowerBook6,5", "iBook G4",2332PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2333PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2334},2335{ "PowerBook6,7", "iBook G4",2336PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2337PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2338},2339{ "PowerBook6,8", "PowerBook G4 12\"",2340PMAC_TYPE_UNKNOWN_INTREPID, intrepid_features,2341PMAC_MB_MAY_SLEEP | PMAC_MB_HAS_FW_POWER | PMAC_MB_MOBILE,2342},2343#else /* CONFIG_POWER4 */2344{ "PowerMac7,2", "PowerMac G5",2345PMAC_TYPE_POWERMAC_G5, g5_features,23460,2347},2348#ifdef CONFIG_PPC642349{ "PowerMac7,3", "PowerMac G5",2350PMAC_TYPE_POWERMAC_G5, g5_features,23510,2352},2353{ "PowerMac8,1", "iMac G5",2354PMAC_TYPE_IMAC_G5, g5_features,23550,2356},2357{ "PowerMac9,1", "PowerMac G5",2358PMAC_TYPE_POWERMAC_G5_U3L, g5_features,23590,2360},2361{ "PowerMac11,2", "PowerMac G5 Dual Core",2362PMAC_TYPE_POWERMAC_G5_U3L, g5_features,23630,2364},2365{ "PowerMac12,1", "iMac G5 (iSight)",2366PMAC_TYPE_POWERMAC_G5_U3L, g5_features,23670,2368},2369{ "RackMac3,1", "XServe G5",2370PMAC_TYPE_XSERVE_G5, g5_features,23710,2372},2373#endif /* CONFIG_PPC64 */2374#endif /* CONFIG_POWER4 */2375};23762377/*2378* The toplevel feature_call callback2379*/2380long pmac_do_feature_call(unsigned int selector, ...)2381{2382struct device_node *node;2383long param, value;2384int i;2385feature_call func = NULL;2386va_list args;23872388if (pmac_mb.features)2389for (i=0; pmac_mb.features[i].function; i++)2390if (pmac_mb.features[i].selector == selector) {2391func = pmac_mb.features[i].function;2392break;2393}2394if (!func)2395for (i=0; any_features[i].function; i++)2396if (any_features[i].selector == selector) {2397func = any_features[i].function;2398break;2399}2400if (!func)2401return -ENODEV;24022403va_start(args, selector);2404node = (struct device_node*)va_arg(args, void*);2405param = va_arg(args, long);2406value = va_arg(args, long);2407va_end(args);24082409return func(node, param, value);2410}24112412static int __init probe_motherboard(void)2413{2414int i;2415struct macio_chip *macio = &macio_chips[0];2416const char *model = NULL;2417struct device_node *dt;2418int ret = 0;24192420/* Lookup known motherboard type in device-tree. First try an2421* exact match on the "model" property, then try a "compatible"2422* match is none is found.2423*/2424dt = of_find_node_by_name(NULL, "device-tree");2425if (dt != NULL)2426model = of_get_property(dt, "model", NULL);2427for(i=0; model && i<ARRAY_SIZE(pmac_mb_defs); i++) {2428if (strcmp(model, pmac_mb_defs[i].model_string) == 0) {2429pmac_mb = pmac_mb_defs[i];2430goto found;2431}2432}2433for(i=0; i<ARRAY_SIZE(pmac_mb_defs); i++) {2434if (of_machine_is_compatible(pmac_mb_defs[i].model_string)) {2435pmac_mb = pmac_mb_defs[i];2436goto found;2437}2438}24392440/* Fallback to selection depending on mac-io chip type */2441switch(macio->type) {2442#ifndef CONFIG_POWER42443case macio_grand_central:2444pmac_mb.model_id = PMAC_TYPE_PSURGE;2445pmac_mb.model_name = "Unknown PowerSurge";2446break;2447case macio_ohare:2448pmac_mb.model_id = PMAC_TYPE_UNKNOWN_OHARE;2449pmac_mb.model_name = "Unknown OHare-based";2450break;2451case macio_heathrow:2452pmac_mb.model_id = PMAC_TYPE_UNKNOWN_HEATHROW;2453pmac_mb.model_name = "Unknown Heathrow-based";2454pmac_mb.features = heathrow_desktop_features;2455break;2456case macio_paddington:2457pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PADDINGTON;2458pmac_mb.model_name = "Unknown Paddington-based";2459pmac_mb.features = paddington_features;2460break;2461case macio_keylargo:2462pmac_mb.model_id = PMAC_TYPE_UNKNOWN_CORE99;2463pmac_mb.model_name = "Unknown Keylargo-based";2464pmac_mb.features = core99_features;2465break;2466case macio_pangea:2467pmac_mb.model_id = PMAC_TYPE_UNKNOWN_PANGEA;2468pmac_mb.model_name = "Unknown Pangea-based";2469pmac_mb.features = pangea_features;2470break;2471case macio_intrepid:2472pmac_mb.model_id = PMAC_TYPE_UNKNOWN_INTREPID;2473pmac_mb.model_name = "Unknown Intrepid-based";2474pmac_mb.features = intrepid_features;2475break;2476#else /* CONFIG_POWER4 */2477case macio_keylargo2:2478pmac_mb.model_id = PMAC_TYPE_UNKNOWN_K2;2479pmac_mb.model_name = "Unknown K2-based";2480pmac_mb.features = g5_features;2481break;2482case macio_shasta:2483pmac_mb.model_id = PMAC_TYPE_UNKNOWN_SHASTA;2484pmac_mb.model_name = "Unknown Shasta-based";2485pmac_mb.features = g5_features;2486break;2487#endif /* CONFIG_POWER4 */2488default:2489ret = -ENODEV;2490goto done;2491}2492found:2493#ifndef CONFIG_POWER42494/* Fixup Hooper vs. Comet */2495if (pmac_mb.model_id == PMAC_TYPE_HOOPER) {2496u32 __iomem * mach_id_ptr = ioremap(0xf3000034, 4);2497if (!mach_id_ptr) {2498ret = -ENODEV;2499goto done;2500}2501/* Here, I used to disable the media-bay on comet. It2502* appears this is wrong, the floppy connector is actually2503* a kind of media-bay and works with the current driver.2504*/2505if (__raw_readl(mach_id_ptr) & 0x20000000UL)2506pmac_mb.model_id = PMAC_TYPE_COMET;2507iounmap(mach_id_ptr);2508}25092510/* Set default value of powersave_nap on machines that support it.2511* It appears that uninorth rev 3 has a problem with it, we don't2512* enable it on those. In theory, the flush-on-lock property is2513* supposed to be set when not supported, but I'm not very confident2514* that all Apple OF revs did it properly, I do it the paranoid way.2515*/2516while (uninorth_base && uninorth_rev > 3) {2517struct device_node *cpus = of_find_node_by_path("/cpus");2518struct device_node *np;25192520if (!cpus || !cpus->child) {2521printk(KERN_WARNING "Can't find CPU(s) in device tree !\n");2522of_node_put(cpus);2523break;2524}2525np = cpus->child;2526/* Nap mode not supported on SMP */2527if (np->sibling) {2528of_node_put(cpus);2529break;2530}2531/* Nap mode not supported if flush-on-lock property is present */2532if (of_get_property(np, "flush-on-lock", NULL)) {2533of_node_put(cpus);2534break;2535}2536of_node_put(cpus);2537powersave_nap = 1;2538printk(KERN_DEBUG "Processor NAP mode on idle enabled.\n");2539break;2540}25412542/* On CPUs that support it (750FX), lowspeed by default during2543* NAP mode2544*/2545powersave_lowspeed = 1;25462547#else /* CONFIG_POWER4 */2548powersave_nap = 1;2549#endif /* CONFIG_POWER4 */25502551/* Check for "mobile" machine */2552if (model && (strncmp(model, "PowerBook", 9) == 02553|| strncmp(model, "iBook", 5) == 0))2554pmac_mb.board_flags |= PMAC_MB_MOBILE;255525562557printk(KERN_INFO "PowerMac motherboard: %s\n", pmac_mb.model_name);2558done:2559of_node_put(dt);2560return ret;2561}25622563/* Initialize the Core99 UniNorth host bridge and memory controller2564*/2565static void __init probe_uninorth(void)2566{2567const u32 *addrp;2568phys_addr_t address;2569unsigned long actrl;25702571/* Locate core99 Uni-N */2572uninorth_node = of_find_node_by_name(NULL, "uni-n");2573uninorth_maj = 1;25742575/* Locate G5 u3 */2576if (uninorth_node == NULL) {2577uninorth_node = of_find_node_by_name(NULL, "u3");2578uninorth_maj = 3;2579}2580/* Locate G5 u4 */2581if (uninorth_node == NULL) {2582uninorth_node = of_find_node_by_name(NULL, "u4");2583uninorth_maj = 4;2584}2585if (uninorth_node == NULL) {2586uninorth_maj = 0;2587return;2588}25892590addrp = of_get_property(uninorth_node, "reg", NULL);2591if (addrp == NULL)2592return;2593address = of_translate_address(uninorth_node, addrp);2594if (address == 0)2595return;2596uninorth_base = ioremap(address, 0x40000);2597if (uninorth_base == NULL)2598return;2599uninorth_rev = in_be32(UN_REG(UNI_N_VERSION));2600if (uninorth_maj == 3 || uninorth_maj == 4) {2601u3_ht_base = ioremap(address + U3_HT_CONFIG_BASE, 0x1000);2602if (u3_ht_base == NULL) {2603iounmap(uninorth_base);2604return;2605}2606}26072608printk(KERN_INFO "Found %s memory controller & host bridge"2609" @ 0x%08x revision: 0x%02x\n", uninorth_maj == 3 ? "U3" :2610uninorth_maj == 4 ? "U4" : "UniNorth",2611(unsigned int)address, uninorth_rev);2612printk(KERN_INFO "Mapped at 0x%08lx\n", (unsigned long)uninorth_base);26132614/* Set the arbitrer QAck delay according to what Apple does2615*/2616if (uninorth_rev < 0x11) {2617actrl = UN_IN(UNI_N_ARB_CTRL) & ~UNI_N_ARB_CTRL_QACK_DELAY_MASK;2618actrl |= ((uninorth_rev < 3) ? UNI_N_ARB_CTRL_QACK_DELAY105 :2619UNI_N_ARB_CTRL_QACK_DELAY) <<2620UNI_N_ARB_CTRL_QACK_DELAY_SHIFT;2621UN_OUT(UNI_N_ARB_CTRL, actrl);2622}26232624/* Some more magic as done by them in recent MacOS X on UniNorth2625* revs 1.5 to 2.O and Pangea. Seem to toggle the UniN Maxbus/PCI2626* memory timeout2627*/2628if ((uninorth_rev >= 0x11 && uninorth_rev <= 0x24) ||2629uninorth_rev == 0xc0)2630UN_OUT(0x2160, UN_IN(0x2160) & 0x00ffffff);2631}26322633static void __init probe_one_macio(const char *name, const char *compat, int type)2634{2635struct device_node* node;2636int i;2637volatile u32 __iomem *base;2638const u32 *addrp, *revp;2639phys_addr_t addr;2640u64 size;26412642for (node = NULL; (node = of_find_node_by_name(node, name)) != NULL;) {2643if (!compat)2644break;2645if (of_device_is_compatible(node, compat))2646break;2647}2648if (!node)2649return;2650for(i=0; i<MAX_MACIO_CHIPS; i++) {2651if (!macio_chips[i].of_node)2652break;2653if (macio_chips[i].of_node == node)2654return;2655}26562657if (i >= MAX_MACIO_CHIPS) {2658printk(KERN_ERR "pmac_feature: Please increase MAX_MACIO_CHIPS !\n");2659printk(KERN_ERR "pmac_feature: %s skipped\n", node->full_name);2660return;2661}2662addrp = of_get_pci_address(node, 0, &size, NULL);2663if (addrp == NULL) {2664printk(KERN_ERR "pmac_feature: %s: can't find base !\n",2665node->full_name);2666return;2667}2668addr = of_translate_address(node, addrp);2669if (addr == 0) {2670printk(KERN_ERR "pmac_feature: %s, can't translate base !\n",2671node->full_name);2672return;2673}2674base = ioremap(addr, (unsigned long)size);2675if (!base) {2676printk(KERN_ERR "pmac_feature: %s, can't map mac-io chip !\n",2677node->full_name);2678return;2679}2680if (type == macio_keylargo || type == macio_keylargo2) {2681const u32 *did = of_get_property(node, "device-id", NULL);2682if (*did == 0x00000025)2683type = macio_pangea;2684if (*did == 0x0000003e)2685type = macio_intrepid;2686if (*did == 0x0000004f)2687type = macio_shasta;2688}2689macio_chips[i].of_node = node;2690macio_chips[i].type = type;2691macio_chips[i].base = base;2692macio_chips[i].flags = MACIO_FLAG_SCCA_ON | MACIO_FLAG_SCCB_ON;2693macio_chips[i].name = macio_names[type];2694revp = of_get_property(node, "revision-id", NULL);2695if (revp)2696macio_chips[i].rev = *revp;2697printk(KERN_INFO "Found a %s mac-io controller, rev: %d, mapped at 0x%p\n",2698macio_names[type], macio_chips[i].rev, macio_chips[i].base);2699}27002701static int __init2702probe_macios(void)2703{2704/* Warning, ordering is important */2705probe_one_macio("gc", NULL, macio_grand_central);2706probe_one_macio("ohare", NULL, macio_ohare);2707probe_one_macio("pci106b,7", NULL, macio_ohareII);2708probe_one_macio("mac-io", "keylargo", macio_keylargo);2709probe_one_macio("mac-io", "paddington", macio_paddington);2710probe_one_macio("mac-io", "gatwick", macio_gatwick);2711probe_one_macio("mac-io", "heathrow", macio_heathrow);2712probe_one_macio("mac-io", "K2-Keylargo", macio_keylargo2);27132714/* Make sure the "main" macio chip appear first */2715if (macio_chips[0].type == macio_gatwick2716&& macio_chips[1].type == macio_heathrow) {2717struct macio_chip temp = macio_chips[0];2718macio_chips[0] = macio_chips[1];2719macio_chips[1] = temp;2720}2721if (macio_chips[0].type == macio_ohareII2722&& macio_chips[1].type == macio_ohare) {2723struct macio_chip temp = macio_chips[0];2724macio_chips[0] = macio_chips[1];2725macio_chips[1] = temp;2726}2727macio_chips[0].lbus.index = 0;2728macio_chips[1].lbus.index = 1;27292730return (macio_chips[0].of_node == NULL) ? -ENODEV : 0;2731}27322733static void __init2734initial_serial_shutdown(struct device_node *np)2735{2736int len;2737const struct slot_names_prop {2738int count;2739char name[1];2740} *slots;2741const char *conn;2742int port_type = PMAC_SCC_ASYNC;2743int modem = 0;27442745slots = of_get_property(np, "slot-names", &len);2746conn = of_get_property(np, "AAPL,connector", &len);2747if (conn && (strcmp(conn, "infrared") == 0))2748port_type = PMAC_SCC_IRDA;2749else if (of_device_is_compatible(np, "cobalt"))2750modem = 1;2751else if (slots && slots->count > 0) {2752if (strcmp(slots->name, "IrDA") == 0)2753port_type = PMAC_SCC_IRDA;2754else if (strcmp(slots->name, "Modem") == 0)2755modem = 1;2756}2757if (modem)2758pmac_call_feature(PMAC_FTR_MODEM_ENABLE, np, 0, 0);2759pmac_call_feature(PMAC_FTR_SCC_ENABLE, np, port_type, 0);2760}27612762static void __init2763set_initial_features(void)2764{2765struct device_node *np;27662767/* That hack appears to be necessary for some StarMax motherboards2768* but I'm not too sure it was audited for side-effects on other2769* ohare based machines...2770* Since I still have difficulties figuring the right way to2771* differenciate them all and since that hack was there for a long2772* time, I'll keep it around2773*/2774if (macio_chips[0].type == macio_ohare) {2775struct macio_chip *macio = &macio_chips[0];2776np = of_find_node_by_name(NULL, "via-pmu");2777if (np)2778MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);2779else2780MACIO_OUT32(OHARE_FCR, STARMAX_FEATURES);2781of_node_put(np);2782} else if (macio_chips[1].type == macio_ohare) {2783struct macio_chip *macio = &macio_chips[1];2784MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);2785}27862787#ifdef CONFIG_POWER42788if (macio_chips[0].type == macio_keylargo2 ||2789macio_chips[0].type == macio_shasta) {2790#ifndef CONFIG_SMP2791/* On SMP machines running UP, we have the second CPU eating2792* bus cycles. We need to take it off the bus. This is done2793* from pmac_smp for SMP kernels running on one CPU2794*/2795np = of_find_node_by_type(NULL, "cpu");2796if (np != NULL)2797np = of_find_node_by_type(np, "cpu");2798if (np != NULL) {2799g5_phy_disable_cpu1();2800of_node_put(np);2801}2802#endif /* CONFIG_SMP */2803/* Enable GMAC for now for PCI probing. It will be disabled2804* later on after PCI probe2805*/2806np = of_find_node_by_name(NULL, "ethernet");2807while(np) {2808if (of_device_is_compatible(np, "K2-GMAC"))2809g5_gmac_enable(np, 0, 1);2810np = of_find_node_by_name(np, "ethernet");2811}28122813/* Enable FW before PCI probe. Will be disabled later on2814* Note: We should have a batter way to check that we are2815* dealing with uninorth internal cell and not a PCI cell2816* on the external PCI. The code below works though.2817*/2818np = of_find_node_by_name(NULL, "firewire");2819while(np) {2820if (of_device_is_compatible(np, "pci106b,5811")) {2821macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;2822g5_fw_enable(np, 0, 1);2823}2824np = of_find_node_by_name(np, "firewire");2825}2826}2827#else /* CONFIG_POWER4 */28282829if (macio_chips[0].type == macio_keylargo ||2830macio_chips[0].type == macio_pangea ||2831macio_chips[0].type == macio_intrepid) {2832/* Enable GMAC for now for PCI probing. It will be disabled2833* later on after PCI probe2834*/2835np = of_find_node_by_name(NULL, "ethernet");2836while(np) {2837if (np->parent2838&& of_device_is_compatible(np->parent, "uni-north")2839&& of_device_is_compatible(np, "gmac"))2840core99_gmac_enable(np, 0, 1);2841np = of_find_node_by_name(np, "ethernet");2842}28432844/* Enable FW before PCI probe. Will be disabled later on2845* Note: We should have a batter way to check that we are2846* dealing with uninorth internal cell and not a PCI cell2847* on the external PCI. The code below works though.2848*/2849np = of_find_node_by_name(NULL, "firewire");2850while(np) {2851if (np->parent2852&& of_device_is_compatible(np->parent, "uni-north")2853&& (of_device_is_compatible(np, "pci106b,18") ||2854of_device_is_compatible(np, "pci106b,30") ||2855of_device_is_compatible(np, "pci11c1,5811"))) {2856macio_chips[0].flags |= MACIO_FLAG_FW_SUPPORTED;2857core99_firewire_enable(np, 0, 1);2858}2859np = of_find_node_by_name(np, "firewire");2860}28612862/* Enable ATA-100 before PCI probe. */2863np = of_find_node_by_name(NULL, "ata-6");2864while(np) {2865if (np->parent2866&& of_device_is_compatible(np->parent, "uni-north")2867&& of_device_is_compatible(np, "kauai-ata")) {2868core99_ata100_enable(np, 1);2869}2870np = of_find_node_by_name(np, "ata-6");2871}28722873/* Switch airport off */2874for_each_node_by_name(np, "radio") {2875if (np->parent == macio_chips[0].of_node) {2876macio_chips[0].flags |= MACIO_FLAG_AIRPORT_ON;2877core99_airport_enable(np, 0, 0);2878}2879}2880}28812882/* On all machines that support sound PM, switch sound off */2883if (macio_chips[0].of_node)2884pmac_do_feature_call(PMAC_FTR_SOUND_CHIP_ENABLE,2885macio_chips[0].of_node, 0, 0);28862887/* While on some desktop G3s, we turn it back on */2888if (macio_chips[0].of_node && macio_chips[0].type == macio_heathrow2889&& (pmac_mb.model_id == PMAC_TYPE_GOSSAMER ||2890pmac_mb.model_id == PMAC_TYPE_SILK)) {2891struct macio_chip *macio = &macio_chips[0];2892MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);2893MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);2894}28952896#endif /* CONFIG_POWER4 */28972898/* On all machines, switch modem & serial ports off */2899for_each_node_by_name(np, "ch-a")2900initial_serial_shutdown(np);2901of_node_put(np);2902for_each_node_by_name(np, "ch-b")2903initial_serial_shutdown(np);2904of_node_put(np);2905}29062907void __init2908pmac_feature_init(void)2909{2910/* Detect the UniNorth memory controller */2911probe_uninorth();29122913/* Probe mac-io controllers */2914if (probe_macios()) {2915printk(KERN_WARNING "No mac-io chip found\n");2916return;2917}29182919/* Probe machine type */2920if (probe_motherboard())2921printk(KERN_WARNING "Unknown PowerMac !\n");29222923/* Set some initial features (turn off some chips that will2924* be later turned on)2925*/2926set_initial_features();2927}29282929#if 02930static void dump_HT_speeds(char *name, u32 cfg, u32 frq)2931{2932int freqs[16] = { 200,300,400,500,600,800,1000,0,0,0,0,0,0,0,0,0 };2933int bits[8] = { 8,16,0,32,2,4,0,0 };2934int freq = (frq >> 8) & 0xf;29352936if (freqs[freq] == 0)2937printk("%s: Unknown HT link frequency %x\n", name, freq);2938else2939printk("%s: %d MHz on main link, (%d in / %d out) bits width\n",2940name, freqs[freq],2941bits[(cfg >> 28) & 0x7], bits[(cfg >> 24) & 0x7]);2942}29432944void __init pmac_check_ht_link(void)2945{2946u32 ufreq, freq, ucfg, cfg;2947struct device_node *pcix_node;2948u8 px_bus, px_devfn;2949struct pci_controller *px_hose;29502951(void)in_be32(u3_ht_base + U3_HT_LINK_COMMAND);2952ucfg = cfg = in_be32(u3_ht_base + U3_HT_LINK_CONFIG);2953ufreq = freq = in_be32(u3_ht_base + U3_HT_LINK_FREQ);2954dump_HT_speeds("U3 HyperTransport", cfg, freq);29552956pcix_node = of_find_compatible_node(NULL, "pci", "pci-x");2957if (pcix_node == NULL) {2958printk("No PCI-X bridge found\n");2959return;2960}2961if (pci_device_from_OF_node(pcix_node, &px_bus, &px_devfn) != 0) {2962printk("PCI-X bridge found but not matched to pci\n");2963return;2964}2965px_hose = pci_find_hose_for_OF_device(pcix_node);2966if (px_hose == NULL) {2967printk("PCI-X bridge found but not matched to host\n");2968return;2969}2970early_read_config_dword(px_hose, px_bus, px_devfn, 0xc4, &cfg);2971early_read_config_dword(px_hose, px_bus, px_devfn, 0xcc, &freq);2972dump_HT_speeds("PCI-X HT Uplink", cfg, freq);2973early_read_config_dword(px_hose, px_bus, px_devfn, 0xc8, &cfg);2974early_read_config_dword(px_hose, px_bus, px_devfn, 0xd0, &freq);2975dump_HT_speeds("PCI-X HT Downlink", cfg, freq);2976}2977#endif /* 0 */29782979/*2980* Early video resume hook2981*/29822983static void (*pmac_early_vresume_proc)(void *data);2984static void *pmac_early_vresume_data;29852986void pmac_set_early_video_resume(void (*proc)(void *data), void *data)2987{2988if (!machine_is(powermac))2989return;2990preempt_disable();2991pmac_early_vresume_proc = proc;2992pmac_early_vresume_data = data;2993preempt_enable();2994}2995EXPORT_SYMBOL(pmac_set_early_video_resume);29962997void pmac_call_early_video_resume(void)2998{2999if (pmac_early_vresume_proc)3000pmac_early_vresume_proc(pmac_early_vresume_data);3001}30023003/*3004* AGP related suspend/resume code3005*/30063007static struct pci_dev *pmac_agp_bridge;3008static int (*pmac_agp_suspend)(struct pci_dev *bridge);3009static int (*pmac_agp_resume)(struct pci_dev *bridge);30103011void pmac_register_agp_pm(struct pci_dev *bridge,3012int (*suspend)(struct pci_dev *bridge),3013int (*resume)(struct pci_dev *bridge))3014{3015if (suspend || resume) {3016pmac_agp_bridge = bridge;3017pmac_agp_suspend = suspend;3018pmac_agp_resume = resume;3019return;3020}3021if (bridge != pmac_agp_bridge)3022return;3023pmac_agp_suspend = pmac_agp_resume = NULL;3024return;3025}3026EXPORT_SYMBOL(pmac_register_agp_pm);30273028void pmac_suspend_agp_for_card(struct pci_dev *dev)3029{3030if (pmac_agp_bridge == NULL || pmac_agp_suspend == NULL)3031return;3032if (pmac_agp_bridge->bus != dev->bus)3033return;3034pmac_agp_suspend(pmac_agp_bridge);3035}3036EXPORT_SYMBOL(pmac_suspend_agp_for_card);30373038void pmac_resume_agp_for_card(struct pci_dev *dev)3039{3040if (pmac_agp_bridge == NULL || pmac_agp_resume == NULL)3041return;3042if (pmac_agp_bridge->bus != dev->bus)3043return;3044pmac_agp_resume(pmac_agp_bridge);3045}3046EXPORT_SYMBOL(pmac_resume_agp_for_card);30473048int pmac_get_uninorth_variant(void)3049{3050return uninorth_maj;3051}305230533054