pmac_feature.c

来自「底层驱动开发」· C语言 代码 · 共 768 行 · 第 1/2 页

C
768
字号
/* *  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 DEFINE_SPINLOCK(feature_lock  __pmacdata);#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* __pmac macio_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;}EXPORT_SYMBOL_GPL(macio_find);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 device_node *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;	if (node == NULL)		return -ENODEV;	LOCK(flags);	if (value) {		MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_GMAC_CLK_ENABLE);		mb();		k2_skiplist[0] = NULL;	} else {		k2_skiplist[0] = node;		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;	if (node == NULL)		return -ENODEV;	LOCK(flags);	if (value) {		MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_FW_CLK_ENABLE);		mb();		k2_skiplist[1] = NULL;	} else {		k2_skiplist[1] = node;		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;}static long __pmac g5_eth_phy_reset(struct device_node* node, long param, long value){	struct macio_chip* macio = &macio_chips[0];	struct device_node *phy;	int need_reset;	/*	 * We must not reset the combo PHYs, only the BCM5221 found in	 * the iMac G5.	 */	phy = of_get_next_child(node, NULL);	if (!phy)		return -ENODEV;	need_reset = device_is_compatible(phy, "B5221");	of_node_put(phy);	if (!need_reset)		return 0;	/* PHY reset is GPIO 29, not in device-tree unfortunately */	MACIO_OUT8(K2_GPIO_EXTINT_0 + 29,		   KEYLARGO_GPIO_OUTPUT_ENABLE | KEYLARGO_GPIO_OUTOUT_DATA);	/* Thankfully, this is now always called at a time when we can	 * schedule by sungem.	 */	msleep(10);	MACIO_OUT8(K2_GPIO_EXTINT_0 + 29, 0);	return 0;}static long __pmac g5_i2s_enable(struct device_node *node, long param, long value){	/* Very crude implementation for now */	struct macio_chip* macio = &macio_chips[0];	unsigned long flags;	if (value == 0)		return 0; /* don't disable yet */	LOCK(flags);	MACIO_BIS(KEYLARGO_FCR3, KL3_CLK45_ENABLE | KL3_CLK49_ENABLE |		  KL3_I2S0_CLK18_ENABLE);	udelay(10);	MACIO_BIS(KEYLARGO_FCR1, K2_FCR1_I2S0_CELL_ENABLE |		  K2_FCR1_I2S0_CLK_ENABLE_BIT | K2_FCR1_I2S0_ENABLE);	udelay(10);	MACIO_BIC(KEYLARGO_FCR1, K2_FCR1_I2S0_RESET);	UNLOCK(flags);	udelay(10);	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 },	{ PMAC_FTR_READ_GPIO,		g5_read_gpio },	{ PMAC_FTR_WRITE_GPIO,		g5_write_gpio },	{ PMAC_FTR_GMAC_PHY_RESET,	g5_eth_phy_reset },	{ PMAC_FTR_SOUND_CHIP_ENABLE,	g5_i2s_enable },#ifdef CONFIG_SMP	{ PMAC_FTR_RESET_CPU,		g5_reset_cpu },#endif /* CONFIG_SMP */	{ 0, NULL }};static struct pmac_mb_def pmac_mb_defs[] __pmacdata = {	{	"PowerMac7,2",			"PowerMac G5",		PMAC_TYPE_POWERMAC_G5,		g5_features,		0,	},	{	"PowerMac7,3",			"PowerMac G5",		PMAC_TYPE_POWERMAC_G5,		g5_features,		0,	},	{	"PowerMac8,1",			"iMac G5",		PMAC_TYPE_IMAC_G5,		g5_features,		0,	},	{	"PowerMac9,1",			"PowerMac G5",

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?