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