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 + -
显示快捷键?