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

📄 pmac_feature.c

📁 ARM 嵌入式 系统 设计与实例开发 实验教材 二源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * BK Id: %F% %I% %G% %U% %#% *//* *  arch/ppc/kernel/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) * */#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 <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>#undef DEBUG_FEATURE#ifdef DEBUG_FEATURE#define DBG(fmt,...) printk(KERN_DEBUG fmt)#else#define DBG(fmt,...)#endif/* Exported from arch/ppc/kernel/idle.c */extern unsigned long powersave_nap;/* * We use a single global lock to protect accesses. Each driver has * to take care of it's 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);/* * Helper functions regarding the various flavors of mac-io */ #define MAX_MACIO_CHIPS		2enum {	macio_unknown = 0,	macio_grand_central,	macio_ohare,	macio_ohareII,	macio_heathrow,	macio_gatwick,	macio_paddington,	macio_keylargo,	macio_pangea};static const char* macio_names[] __pmacdata = {	"Unknown",	"Grand Central",	"OHare",	"OHareII",	"Heathrow",	"Gatwick",	"Paddington",	"Keylargo",	"Pangea"};static struct macio_chip{	struct device_node*	of_node;	int			type;	int			rev;	volatile u32*		base;	unsigned long		flags;} macio_chips[MAX_MACIO_CHIPS]  __pmacdata;#define MACIO_FLAG_SCCA_ON	0x00000001#define MACIO_FLAG_SCCB_ON	0x00000002#define MACIO_FLAG_SCC_LOCKED	0x00000004#define MACIO_FLAG_AIRPORT_ON	0x00000010#define MACIO_FLAG_FW_SUPPORTED	0x00000020static 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;}#define MACIO_FCR32(macio, r)	((macio)->base + ((r) >> 2))#define MACIO_FCR8(macio, r)	(((volatile u8*)((macio)->base)) + (r))#define MACIO_IN32(r)		(in_le32(MACIO_FCR32(macio,r)))#define MACIO_OUT32(r,v)	(out_le32(MACIO_FCR32(macio,r), (v)))#define MACIO_BIS(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) | (v)))#define MACIO_BIC(r,v)		(MACIO_OUT32((r), MACIO_IN32(r) & ~(v)))#define MACIO_IN8(r)		(in_8(MACIO_FCR8(macio,r)))#define MACIO_OUT8(r,v)		(out_8(MACIO_FCR8(macio,r), (v)))/* * 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;/* * For each motherboard family, we have a table of functions pointers * that handle the various features. */typedef int (*feature_call)(struct device_node* node, int param, int 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 inline int __pmacsimple_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;}static int __pmacgeneric_scc_enable(struct device_node* node, u32 enable_mask, u32 reset_mask,	int param, int value){	struct macio_chip*	macio;	unsigned long		chan_mask;	unsigned long		fcr;	unsigned long		flags;		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;	if (value) {		LOCK(flags);		fcr = MACIO_IN32(OHARE_FCR);		/* Check if scc cell need enabling */		if (!(fcr & OH_SCC_ENABLE)) {			fcr |= enable_mask;			MACIO_OUT32(OHARE_FCR, fcr);			fcr |= reset_mask;			MACIO_OUT32(OHARE_FCR, fcr);			UNLOCK(flags);			(void)MACIO_IN32(OHARE_FCR);			mdelay(15);			LOCK(flags);			fcr &= ~reset_mask;			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 &= ~enable_mask;			MACIO_OUT32(OHARE_FCR, fcr);		}		macio->flags &= ~(chan_mask);		UNLOCK(flags);		mdelay(10);	}	return 0;}static int __pmacohare_scc_enable(struct device_node* node, int param, int value){	int rc;#ifdef CONFIG_ADB_PMU	if (value && (param & 0xfff) == PMAC_SCC_IRDA)		pmu_enable_irled(1);#endif /* CONFIG_ADB_PMU */			rc = generic_scc_enable(node, OH_SCC_ENABLE, OH_SCC_RESET, param, value);#ifdef CONFIG_ADB_PMU	if ((param & 0xfff) == PMAC_SCC_IRDA && (rc || !value))		pmu_enable_irled(0);#endif /* CONFIG_ADB_PMU */			return rc;}static int __pmacohare_floppy_enable(struct device_node* node, int param, int value){	return simple_feature_tweak(node, macio_ohare,		OHARE_FCR, OH_FLOPPY_ENABLE, value);}static int __pmacohare_mesh_enable(struct device_node* node, int param, int value){	return simple_feature_tweak(node, macio_ohare,		OHARE_FCR, OH_MESH_ENABLE, value);}static int __pmacohare_ide_enable(struct device_node* node, int param, int 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 int __pmacohare_ide_reset(struct device_node* node, int param, int 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 int __pmacohare_sleep_state(struct device_node* node, int param, int value){	struct macio_chip*	macio = &macio_chips[0];	if ((pmac_mb.board_flags & PMAC_MB_CAN_SLEEP) == 0)		return -EPERM;	if (value) {		MACIO_BIC(OHARE_FCR, OH_IOBUS_ENABLE);	} else {		MACIO_BIS(OHARE_FCR, OH_IOBUS_ENABLE);	}		return 0;}static int __pmacheathrow_scc_enable(struct device_node* node, int param, int value){	int rc;	#ifdef CONFIG_ADB_PMU	if (value && param == PMAC_SCC_IRDA)		pmu_enable_irled(1);#endif /* CONFIG_ADB_PMU */			/* Fixme: It's possible that wallstreet (heathrow) is different	 * than other paddington machines. I still have to figure that	 * out exactly, for now, the paddington values are used	 */	rc = generic_scc_enable(node, HRW_SCC_ENABLE, PADD_RESET_SCC, param, value);#ifdef CONFIG_ADB_PMU	if (param == PMAC_SCC_IRDA && (rc || !value))		pmu_enable_irled(0);#endif /* CONFIG_ADB_PMU */			return rc;}static int __pmacheathrow_modem_enable(struct device_node* node, int param, int 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);	    	/* We use the paddington values as they seem to work properly	    	 * on the wallstreet (heathrow) as well. I can't tell why we	    	 * had to flip them on older feature.c, the fact is that new	    	 * code uses the paddington values which are also the ones used	    	 * in Darwin, and that works on wallstreet !	    	 */	    	if (value)	    		MACIO_BIC(HEATHROW_FCR, PADD_MODEM_POWER_N);	    	else	    		MACIO_BIS(HEATHROW_FCR, PADD_MODEM_POWER_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); LOCK(flags);	}	return 0;}static int __pmacheathrow_floppy_enable(struct device_node* node, int param, int value){	return simple_feature_tweak(node, macio_unknown,		HEATHROW_FCR,		HRW_SWIM_ENABLE|HRW_BAY_FLOPPY_ENABLE,		value);}static int __pmacheathrow_mesh_enable(struct device_node* node, int param, int 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 (todo: test ! the bit value	 * used by Darwin doesn't seem to match what we used so	 * far. If you experience problems, turn #if 1 into #if 0	 * and tell me about it --BenH.	 */#if 1	if (value)		MACIO_BIC(HEATHROW_MBCR, 0x00000004);	else		MACIO_BIS(HEATHROW_MBCR, 0x00000004);#else	if (value)		MACIO_BIC(HEATHROW_MBCR, 0x00040000);	else		MACIO_BIS(HEATHROW_MBCR, 0x00040000);#endif			(void)MACIO_IN32(HEATHROW_MBCR);	udelay(10);	UNLOCK(flags);	return 0;}static int __pmacheathrow_ide_enable(struct device_node* node, int param, int 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 int __pmacheathrow_ide_reset(struct device_node* node, int param, int 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 int __pmacheathrow_bmac_enable(struct device_node* node, int param, int 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 int __pmacheathrow_sound_enable(struct device_node* node, int param, int 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 ||

⌨️ 快捷键说明

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