pmac_feature.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 664 行 · 第 1/2 页
C
664 行
/* * arch/ppc/platforms/pmac_feature.c * * Copyright (C) 1996-2001 Paul Mackerras (paulus@cs.anu.edu.au) * Ben. Herrenschmidt (benh@kernel.crashing.org) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * TODO: * * - Replace mdelay with some schedule loop if possible * - Shorten some obfuscated delays on some routines (like modem * power) * - Refcount some clocks (see darwin) * - Split split split... * */#include <linux/config.h>#include <linux/types.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/spinlock.h>#include <linux/adb.h>#include <linux/pmu.h>#include <linux/ioport.h>#include <linux/pci.h>#include <asm/sections.h>#include <asm/errno.h>#include <asm/keylargo.h>#include <asm/uninorth.h>#include <asm/io.h>#include <asm/prom.h>#include <asm/machdep.h>#include <asm/pmac_feature.h>#include <asm/dbdma.h>#include <asm/pci-bridge.h>#include <asm/pmac_low_i2c.h>#undef DEBUG_FEATURE#ifdef DEBUG_FEATURE#define DBG(fmt...) printk(KERN_DEBUG fmt)#else#define DBG(fmt...)#endif/* * We use a single global lock to protect accesses. Each driver has * to take care of its own locking */static spinlock_t feature_lock __pmacdata = SPIN_LOCK_UNLOCKED;#define LOCK(flags) spin_lock_irqsave(&feature_lock, flags);#define UNLOCK(flags) spin_unlock_irqrestore(&feature_lock, flags);/* * Instance of some macio stuffs */struct macio_chip macio_chips[MAX_MACIO_CHIPS] __pmacdata;struct macio_chip* __pmacmacio_find(struct device_node* child, int type){ while(child) { int i; for (i=0; i < MAX_MACIO_CHIPS && macio_chips[i].of_node; i++) if (child == macio_chips[i].of_node && (!type || macio_chips[i].type == type)) return &macio_chips[i]; child = child->parent; } return NULL;}static const char* macio_names[] __pmacdata ={ "Unknown", "Grand Central", "OHare", "OHareII", "Heathrow", "Gatwick", "Paddington", "Keylargo", "Pangea", "Intrepid", "K2"};/* * Uninorth reg. access. Note that Uni-N regs are big endian */#define UN_REG(r) (uninorth_base + ((r) >> 2))#define UN_IN(r) (in_be32(UN_REG(r)))#define UN_OUT(r,v) (out_be32(UN_REG(r), (v)))#define UN_BIS(r,v) (UN_OUT((r), UN_IN(r) | (v)))#define UN_BIC(r,v) (UN_OUT((r), UN_IN(r) & ~(v)))static struct device_node* uninorth_node __pmacdata;static u32* uninorth_base __pmacdata;static u32 uninorth_rev __pmacdata;static void *u3_ht;extern struct pci_dev *k2_skiplist[2];/* * For each motherboard family, we have a table of functions pointers * that handle the various features. */typedef long (*feature_call)(struct device_node* node, long param, long value);struct feature_table_entry { unsigned int selector; feature_call function;};struct pmac_mb_def{ const char* model_string; const char* model_name; int model_id; struct feature_table_entry* features; unsigned long board_flags;};static struct pmac_mb_def pmac_mb __pmacdata;/* * Here are the chip specific feature functions */static long __pmac g5_read_gpio(struct device_node* node, long param, long value){ struct macio_chip* macio = &macio_chips[0]; return MACIO_IN8(param);}static long __pmac g5_write_gpio(struct device_node* node, long param, long value){ struct macio_chip* macio = &macio_chips[0]; MACIO_OUT8(param, (u8)(value & 0xff)); return 0;}static long __pmac g5_gmac_enable(struct device_node* node, long param, long value){ struct macio_chip* macio = &macio_chips[0]; unsigned long flags; struct pci_dev *pdev = NULL; if (node == NULL) return -ENODEV; /* XXX FIXME: We should fix pci_device_from_OF_node here, and * get to a real pci_dev or we'll get into trouble with PCI * domains the day we get overlapping numbers (like if we ever * decide to show the HT root. * Note that we only get the slot when value is 0. This is called * early during boot with value 1 to enable all devices, at which * point, we don't yet have probed pci_find_slot, so it would fail * to look for the slot at this point. */ if (!value) pdev = pci_find_slot(node->busno, node->devfn); LOCK(flags); if (value) { MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); mb(); k2_skiplist[0] = NULL; } else { k2_skiplist[0] = pdev; mb(); MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE); } UNLOCK(flags); mdelay(1); return 0;}static long __pmac g5_fw_enable(struct device_node* node, long param, long value){ struct macio_chip* macio = &macio_chips[0]; unsigned long flags; struct pci_dev *pdev = NULL; /* XXX FIXME: We should fix pci_device_from_OF_node here, and * get to a real pci_dev or we'll get into trouble with PCI * domains the day we get overlapping numbers (like if we ever * decide to show the HT root * Note that we only get the slot when value is 0. This is called * early during boot with value 1 to enable all devices, at which * point, we don't yet have probed pci_find_slot, so it would fail * to look for the slot at this point. */ if (node == NULL) return -ENODEV; if (!value) pdev = pci_find_slot(node->busno, node->devfn); LOCK(flags); if (value) { MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); mb(); k2_skiplist[1] = NULL; } else { k2_skiplist[1] = pdev; mb(); MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE); } UNLOCK(flags); mdelay(1); return 0;}static long __pmac g5_mpic_enable(struct device_node* node, long param, long value){ unsigned long flags; if (node->parent == NULL || strcmp(node->parent->name, "u3")) return 0; LOCK(flags); UN_BIS(U3_TOGGLE_REG, U3_MPIC_RESET | U3_MPIC_OUTPUT_ENABLE); UNLOCK(flags); return 0;}#ifdef CONFIG_SMPstatic long __pmac g5_reset_cpu(struct device_node* node, long param, long value){ unsigned int reset_io = 0; unsigned long flags; struct macio_chip* macio; struct device_node* np; macio = &macio_chips[0]; if (macio->type != macio_keylargo2) return -ENODEV; np = find_path_device("/cpus"); if (np == NULL) return -ENODEV; for (np = np->child; np != NULL; np = np->sibling) { u32* num = (u32 *)get_property(np, "reg", NULL); u32* rst = (u32 *)get_property(np, "soft-reset", NULL); if (num == NULL || rst == NULL) continue; if (param == *num) { reset_io = *rst; break; } } if (np == NULL || reset_io == 0) return -ENODEV; LOCK(flags); MACIO_OUT8(reset_io, KEYLARGO_GPIO_OUTPUT_ENABLE); (void)MACIO_IN8(reset_io); udelay(1); MACIO_OUT8(reset_io, 0); (void)MACIO_IN8(reset_io); UNLOCK(flags); return 0;}#endif /* CONFIG_SMP *//* * This can be called from pmac_smp so isn't static * * This takes the second CPU off the bus on dual CPU machines * running UP */void __pmac g5_phy_disable_cpu1(void){ UN_OUT(U3_API_PHY_CONFIG_1, 0);}static long __pmac generic_get_mb_info(struct device_node* node, long param, long value){ switch(param) { case PMAC_MB_INFO_MODEL: return pmac_mb.model_id; case PMAC_MB_INFO_FLAGS: return pmac_mb.board_flags; case PMAC_MB_INFO_NAME: /* hack hack hack... but should work */ *((const char **)value) = pmac_mb.model_name; return 0; } return -EINVAL;}/* * Table definitions *//* Used on any machine */static struct feature_table_entry any_features[] __pmacdata = { { PMAC_FTR_GET_MB_INFO, generic_get_mb_info }, { 0, NULL }};/* G5 features */static struct feature_table_entry g5_features[] __pmacdata = { { PMAC_FTR_GMAC_ENABLE, g5_gmac_enable }, { PMAC_FTR_1394_ENABLE, g5_fw_enable }, { PMAC_FTR_ENABLE_MPIC, g5_mpic_enable },
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?