⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 feature.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  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/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/ohare.h>#include <asm/heathrow.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#ifdef CONFIG_6xxextern int powersave_lowspeed;#endifextern int powersave_nap;extern struct device_node *k2_skiplist[2];/* * We use a single global lock to protect accesses. Each driver has * to take care of its own locking */DEFINE_SPINLOCK(feature_lock);#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];struct macio_chip *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[] ={	"Unknown",	"Grand Central",	"OHare",	"OHareII",	"Heathrow",	"Gatwick",	"Paddington",	"Keylargo",	"Pangea",	"Intrepid",	"K2",	"Shasta",};struct device_node *uninorth_node;u32 __iomem *uninorth_base;static u32 uninorth_rev;static int uninorth_maj;static void __iomem *u3_ht_base;/* * 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;/* * Here are the chip specific feature functions */static inline int simple_feature_tweak(struct device_node *node, int type,				       int reg, u32 mask, int value){	struct macio_chip*	macio;	unsigned long		flags;	macio = macio_find(node, type);	if (!macio)		return -ENODEV;	LOCK(flags);	if (value)		MACIO_BIS(reg, mask);	else		MACIO_BIC(reg, mask);	(void)MACIO_IN32(reg);	UNLOCK(flags);	return 0;}#ifndef CONFIG_POWER4static long ohare_htw_scc_enable(struct device_node *node, long param,				 long value){	struct macio_chip*	macio;	unsigned long		chan_mask;	unsigned long		fcr;	unsigned long		flags;	int			htw, trans;	unsigned long		rmask;	macio = macio_find(node, 0);	if (!macio)		return -ENODEV;	if (!strcmp(node->name, "ch-a"))		chan_mask = MACIO_FLAG_SCCA_ON;	else if (!strcmp(node->name, "ch-b"))		chan_mask = MACIO_FLAG_SCCB_ON;	else		return -ENODEV;	htw = (macio->type == macio_heathrow || macio->type == macio_paddington		|| macio->type == macio_gatwick);	/* On these machines, the HRW_SCC_TRANS_EN_N bit mustn't be touched */	trans = (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&		 pmac_mb.model_id != PMAC_TYPE_YIKES);	if (value) {#ifdef CONFIG_ADB_PMU		if ((param & 0xfff) == PMAC_SCC_IRDA)			pmu_enable_irled(1);#endif /* CONFIG_ADB_PMU */		LOCK(flags);		fcr = MACIO_IN32(OHARE_FCR);		/* Check if scc cell need enabling */		if (!(fcr & OH_SCC_ENABLE)) {			fcr |= OH_SCC_ENABLE;			if (htw) {				/* Side effect: this will also power up the				 * modem, but it's too messy to figure out on which				 * ports this controls the tranceiver and on which				 * it controls the modem				 */				if (trans)					fcr &= ~HRW_SCC_TRANS_EN_N;				MACIO_OUT32(OHARE_FCR, fcr);				fcr |= (rmask = HRW_RESET_SCC);				MACIO_OUT32(OHARE_FCR, fcr);			} else {				fcr |= (rmask = OH_SCC_RESET);				MACIO_OUT32(OHARE_FCR, fcr);			}			UNLOCK(flags);			(void)MACIO_IN32(OHARE_FCR);			mdelay(15);			LOCK(flags);			fcr &= ~rmask;			MACIO_OUT32(OHARE_FCR, fcr);		}		if (chan_mask & MACIO_FLAG_SCCA_ON)			fcr |= OH_SCCA_IO;		if (chan_mask & MACIO_FLAG_SCCB_ON)			fcr |= OH_SCCB_IO;		MACIO_OUT32(OHARE_FCR, fcr);		macio->flags |= chan_mask;		UNLOCK(flags);		if (param & PMAC_SCC_FLAG_XMON)			macio->flags |= MACIO_FLAG_SCC_LOCKED;	} else {		if (macio->flags & MACIO_FLAG_SCC_LOCKED)			return -EPERM;		LOCK(flags);		fcr = MACIO_IN32(OHARE_FCR);		if (chan_mask & MACIO_FLAG_SCCA_ON)			fcr &= ~OH_SCCA_IO;		if (chan_mask & MACIO_FLAG_SCCB_ON)			fcr &= ~OH_SCCB_IO;		MACIO_OUT32(OHARE_FCR, fcr);		if ((fcr & (OH_SCCA_IO | OH_SCCB_IO)) == 0) {			fcr &= ~OH_SCC_ENABLE;			if (htw && trans)				fcr |= HRW_SCC_TRANS_EN_N;			MACIO_OUT32(OHARE_FCR, fcr);		}		macio->flags &= ~(chan_mask);		UNLOCK(flags);		mdelay(10);#ifdef CONFIG_ADB_PMU		if ((param & 0xfff) == PMAC_SCC_IRDA)			pmu_enable_irled(0);#endif /* CONFIG_ADB_PMU */	}	return 0;}static long ohare_floppy_enable(struct device_node *node, long param,				long value){	return simple_feature_tweak(node, macio_ohare,		OHARE_FCR, OH_FLOPPY_ENABLE, value);}static long ohare_mesh_enable(struct device_node *node, long param, long value){	return simple_feature_tweak(node, macio_ohare,		OHARE_FCR, OH_MESH_ENABLE, value);}static long ohare_ide_enable(struct device_node *node, long param, long value){	switch(param) {	case 0:		/* For some reason, setting the bit in set_initial_features()		 * doesn't stick. I'm still investigating... --BenH.		 */		if (value)			simple_feature_tweak(node, macio_ohare,				OHARE_FCR, OH_IOBUS_ENABLE, 1);		return simple_feature_tweak(node, macio_ohare,			OHARE_FCR, OH_IDE0_ENABLE, value);	case 1:		return simple_feature_tweak(node, macio_ohare,			OHARE_FCR, OH_BAY_IDE_ENABLE, value);	default:		return -ENODEV;	}}static long ohare_ide_reset(struct device_node *node, long param, long value){	switch(param) {	case 0:		return simple_feature_tweak(node, macio_ohare,			OHARE_FCR, OH_IDE0_RESET_N, !value);	case 1:		return simple_feature_tweak(node, macio_ohare,			OHARE_FCR, OH_IDE1_RESET_N, !value);	default:		return -ENODEV;	}}static long ohare_sleep_state(struct device_node *node, long param, long value){	struct macio_chip*	macio = &macio_chips[0];	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)		return -EPERM;	if (value == 1) {		MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);	} else if (value == 0) {		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);	}	return 0;}static long heathrow_modem_enable(struct device_node *node, long param,				  long value){	struct macio_chip*	macio;	u8			gpio;	unsigned long		flags;	macio = macio_find(node, macio_unknown);	if (!macio)		return -ENODEV;	gpio = MACIO_IN8(HRW_GPIO_MODEM_RESET) & ~1;	if (!value) {		LOCK(flags);		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);		UNLOCK(flags);		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);		mdelay(250);	}	if (pmac_mb.model_id != PMAC_TYPE_YOSEMITE &&	    pmac_mb.model_id != PMAC_TYPE_YIKES) {		LOCK(flags);		if (value)			MACIO_BIC(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);		else			MACIO_BIS(HEATHROW_FCR, HRW_SCC_TRANS_EN_N);		UNLOCK(flags);		(void)MACIO_IN32(HEATHROW_FCR);		mdelay(250);	}	if (value) {		LOCK(flags);		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);		UNLOCK(flags); mdelay(250); LOCK(flags);		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio);		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);		UNLOCK(flags); mdelay(250); LOCK(flags);		MACIO_OUT8(HRW_GPIO_MODEM_RESET, gpio | 1);		(void)MACIO_IN8(HRW_GPIO_MODEM_RESET);		UNLOCK(flags); mdelay(250);	}	return 0;}static long heathrow_floppy_enable(struct device_node *node, long param,				   long value){	return simple_feature_tweak(node, macio_unknown,		HEATHROW_FCR,		HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,		value);}static long heathrow_mesh_enable(struct device_node *node, long param,				 long value){	struct macio_chip*	macio;	unsigned long		flags;	macio = macio_find(node, macio_unknown);	if (!macio)		return -ENODEV;	LOCK(flags);	/* Set clear mesh cell enable */	if (value)		MACIO_BIS(HEATHROW_FCR, HRW_MESH_ENABLE);	else		MACIO_BIC(HEATHROW_FCR, HRW_MESH_ENABLE);	(void)MACIO_IN32(HEATHROW_FCR);	udelay(10);	/* Set/Clear termination power */	if (value)		MACIO_BIC(HEATHROW_MBCR, 0x04000000);	else		MACIO_BIS(HEATHROW_MBCR, 0x04000000);	(void)MACIO_IN32(HEATHROW_MBCR);	udelay(10);	UNLOCK(flags);	return 0;}static long heathrow_ide_enable(struct device_node *node, long param,				long value){	switch(param) {	case 0:		return simple_feature_tweak(node, macio_unknown,			HEATHROW_FCR, HRW_IDE0_ENABLE, value);	case 1:		return simple_feature_tweak(node, macio_unknown,			HEATHROW_FCR, HRW_BAY_IDE_ENABLE, value);	default:		return -ENODEV;	}}static long heathrow_ide_reset(struct device_node *node, long param,			       long value){	switch(param) {	case 0:		return simple_feature_tweak(node, macio_unknown,			HEATHROW_FCR, HRW_IDE0_RESET_N, !value);	case 1:		return simple_feature_tweak(node, macio_unknown,			HEATHROW_FCR, HRW_IDE1_RESET_N, !value);	default:		return -ENODEV;	}}static long heathrow_bmac_enable(struct device_node *node, long param,				 long value){	struct macio_chip*	macio;	unsigned long		flags;	macio = macio_find(node, 0);	if (!macio)		return -ENODEV;	if (value) {		LOCK(flags);		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);		MACIO_BIS(HEATHROW_FCR, HRW_BMAC_RESET);		UNLOCK(flags);		(void)MACIO_IN32(HEATHROW_FCR);		mdelay(10);		LOCK(flags);		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_RESET);		UNLOCK(flags);		(void)MACIO_IN32(HEATHROW_FCR);		mdelay(10);	} else {		LOCK(flags);		MACIO_BIC(HEATHROW_FCR, HRW_BMAC_IO_ENABLE);		UNLOCK(flags);	}	return 0;}static long heathrow_sound_enable(struct device_node *node, long param,				  long value){	struct macio_chip*	macio;	unsigned long		flags;	/* B&W G3 and Yikes don't support that properly (the	 * sound appear to never come back after beeing shut down).	 */	if (pmac_mb.model_id == PMAC_TYPE_YOSEMITE ||	    pmac_mb.model_id == PMAC_TYPE_YIKES)		return 0;	macio = macio_find(node, 0);	if (!macio)		return -ENODEV;	if (value) {		LOCK(flags);		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_POWER_N);		UNLOCK(flags);		(void)MACIO_IN32(HEATHROW_FCR);	} else {		LOCK(flags);		MACIO_BIS(HEATHROW_FCR, HRW_SOUND_POWER_N);		MACIO_BIC(HEATHROW_FCR, HRW_SOUND_CLK_ENABLE);		UNLOCK(flags);	}	return 0;}static u32 save_fcr[6];static u32 save_mbcr;static struct dbdma_regs save_dbdma[13];static struct dbdma_regs save_alt_dbdma[13];static void dbdma_save(struct macio_chip *macio, struct dbdma_regs *save){

⌨️ 快捷键说明

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