patch-2.3.43 linux/arch/ppc/kernel/feature.c
Next file: linux/arch/ppc/kernel/galaxy_pci.c
Previous file: linux/arch/ppc/kernel/entry.S
Back to the patch index
Back to the overall index
- Lines: 422
- Date:
Thu Feb 10 12:37:22 2000
- Orig file:
v2.3.42/linux/arch/ppc/kernel/feature.c
- Orig date:
Sat Oct 9 11:47:50 1999
diff -u --recursive --new-file v2.3.42/linux/arch/ppc/kernel/feature.c linux/arch/ppc/kernel/feature.c
@@ -8,85 +8,144 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
+ * BenH: Changed implementation to work on multiple registers
+ * polarity is also taken into account. Removed delay (now
+ * responsibility of the caller). Added spinlocks.
+ *
*/
+#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 <asm/errno.h>
#include <asm/ohare.h>
+#include <asm/heathrow.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/feature.h>
-#define MAX_FEATURE_REGS 2
#undef DEBUG_FEATURE
-static u32 feature_bits_pbook[] = {
- 0, /* FEATURE_null */
- OH_SCC_RESET, /* FEATURE_Serial_reset */
- OH_SCC_ENABLE, /* FEATURE_Serial_enable */
- OH_SCCA_IO, /* FEATURE_Serial_IO_A */
- OH_SCCB_IO, /* FEATURE_Serial_IO_B */
- OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */
- OH_MESH_ENABLE, /* FEATURE_MESH_enable */
- OH_IDE_ENABLE, /* FEATURE_IDE_enable */
- OH_VIA_ENABLE, /* FEATURE_VIA_enable */
- OH_IDECD_POWER, /* FEATURE_CD_power */
- OH_BAY_RESET, /* FEATURE_Mediabay_reset */
- OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */
- OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */
- OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */
- OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
- 0, /* FEATURE_BMac_reset */
- 0, /* FEATURE_BMac_IO_enable */
- 0, /* FEATURE_Modem_Reset -> guess... */
- OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */
- OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */
+#define MAX_FEATURE_CONTROLLERS 2
+#define MAX_FEATURE_OFFSET 0x50
+#define FREG(c,r) (&(((c)->reg)[(r)>>2]))
+
+typedef struct feature_bit {
+ int reg; /* reg. offset from mac-io base */
+ unsigned int polarity; /* 0 = normal, 1 = inverse */
+ unsigned int mask; /* bit mask */
+} fbit;
+
+/* I don't have an OHare machine to test with, so I left those as they
+ * were. Someone with such a machine chould check out what OF says and
+ * try too see if they match the heathrow ones and should be changed too
+ */
+static fbit feature_bits_ohare_pbook[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,OH_SCC_RESET}, /* FEATURE_Serial_reset */
+ {0x38,0,OH_SCC_ENABLE}, /* FEATURE_Serial_enable */
+ {0x38,0,OH_SCCA_IO}, /* FEATURE_Serial_IO_A */
+ {0x38,0,OH_SCCB_IO}, /* FEATURE_Serial_IO_B */
+ {0x38,0,OH_FLOPPY_ENABLE}, /* FEATURE_SWIM3_enable */
+ {0x38,0,OH_MESH_ENABLE}, /* FEATURE_MESH_enable */
+ {0x38,0,OH_IDE0_ENABLE}, /* FEATURE_IDE0_enable */
+ {0x38,1,OH_IDE0_RESET_N}, /* FEATURE_IDE0_reset */
+ {0x38,0,OH_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */
+ {0x38,1,OH_BAY_RESET_N}, /* FEATURE_Mediabay_reset */
+ {0x38,1,OH_BAY_POWER_N}, /* FEATURE_Mediabay_power */
+ {0x38,0,OH_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,OH_BAY_IDE_ENABLE}, /* FEATURE_Mediabay_IDE_enable */
+ {0x38,1,OH_IDE1_RESET_N}, /* FEATURE_Mediabay_IDE_reset */
+ {0x38,0,OH_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,0}, /* FEATURE_BMac_reset */
+ {0x38,0,0}, /* FEATURE_BMac_IO_enable */
+ {0x38,0,0}, /* FEATURE_Modem_power */
+ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,0,0}, /* FEATURE_Sound_Power */
+ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x38,0,0}, /* FEATURE_IDE2_reset */
};
-/* assume these are the same as the ohare until proven otherwise */
-static u32 feature_bits_heathrow[] = {
- 0, /* FEATURE_null */
- OH_SCC_RESET, /* FEATURE_Serial_reset */
- OH_SCC_ENABLE, /* FEATURE_Serial_enable */
- OH_SCCA_IO, /* FEATURE_Serial_IO_A */
- OH_SCCB_IO, /* FEATURE_Serial_IO_B */
- OH_FLOPPY_ENABLE, /* FEATURE_SWIM3_enable */
- OH_MESH_ENABLE, /* FEATURE_MESH_enable */
- OH_IDE_ENABLE, /* FEATURE_IDE_enable */
- OH_VIA_ENABLE, /* FEATURE_VIA_enable */
- OH_IDECD_POWER, /* FEATURE_CD_power */
- OH_BAY_RESET, /* FEATURE_Mediabay_reset */
- OH_BAY_ENABLE, /* FEATURE_Mediabay_enable */
- OH_BAY_PCI_ENABLE, /* FEATURE_Mediabay_PCI_enable */
- OH_BAY_IDE_ENABLE, /* FEATURE_Mediabay_IDE_enable */
- OH_BAY_FLOPPY_ENABLE, /* FEATURE_Mediabay_floppy_enable */
- 0x80000000, /* FEATURE_BMac_reset */
- 0x60000000, /* FEATURE_BMac_IO_enable */
- 0x02000000, /* FEATURE_Modem_Reset -> guess...*/
- OH_IDE_POWER, /* FEATURE_IDE_DiskPower -> guess... */
- OH_IDE_RESET /* FEATURE_IDE_Reset (0 based) -> guess... */
+/* Those bits are from a PowerBook. It's possible that desktop machines
+ * based on heathrow need a different definition or some bits removed
+ */
+static fbit feature_bits_heathrow[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,HRW_RESET_SCC}, /* FEATURE_Serial_reset */
+ {0x38,0,HRW_SCC_ENABLE}, /* FEATURE_Serial_enable */
+ {0x38,0,HRW_SCCA_IO}, /* FEATURE_Serial_IO_A */
+ {0x38,0,HRW_SCCB_IO}, /* FEATURE_Serial_IO_B */
+ {0x38,0,HRW_SWIM_ENABLE}, /* FEATURE_SWIM3_enable */
+ {0x38,0,HRW_MESH_ENABLE}, /* FEATURE_MESH_enable */
+ {0x38,0,HRW_IDE0_ENABLE}, /* FEATURE_IDE0_enable */
+ {0x38,1,HRW_IDE0_RESET_N}, /* FEATURE_IDE0_reset */
+ {0x38,0,HRW_IOBUS_ENABLE}, /* FEATURE_IOBUS_enable */
+ {0x38,1,HRW_BAY_RESET_N}, /* FEATURE_Mediabay_reset */
+ {0x38,1,HRW_BAY_POWER_N}, /* FEATURE_Mediabay_power */
+ {0x38,0,HRW_BAY_PCI_ENABLE}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,HRW_BAY_IDE_ENABLE}, /* FEATURE_Mediabay_IDE_enable */
+ {0x38,1,HRW_IDE1_RESET_N}, /* FEATURE_Mediabay_IDE_reset */
+ {0x38,0,HRW_BAY_FLOPPY_ENABLE}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,HRW_BMAC_RESET}, /* FEATURE_BMac_reset */
+ {0x38,0,HRW_BMAC_IO_ENABLE}, /* FEATURE_BMac_IO_enable */
+ {0x38,1,HRW_MODEM_POWER_N}, /* FEATURE_Modem_power */
+ {0x38,0,HRW_SLOW_SCC_PCLK}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,1,HRW_SOUND_POWER_N}, /* FEATURE_Sound_Power */
+ {0x38,0,HRW_SOUND_CLK_ENABLE}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x38,0,0}, /* FEATURE_IDE2_reset */
+};
+
+/* Those bits are from an iBook.
+ */
+static fbit feature_bits_keylargo[] = {
+ {0x38,0,0}, /* FEATURE_null */
+ {0x38,0,0}, /* FEATURE_Serial_reset */
+ {0x38,0,0x00000054}, /* FEATURE_Serial_enable */
+ {0x38,0,0}, /* FEATURE_Serial_IO_A */
+ {0x38,0,0}, /* FEATURE_Serial_IO_B */
+ {0x38,0,0}, /* FEATURE_SWIM3_enable */
+ {0x38,0,0}, /* FEATURE_MESH_enable */
+ {0x38,0,0}, /* FEATURE_IDE0_enable */
+ {0x3c,1,0x01000000}, /* FEATURE_IDE0_reset */
+ {0x38,0,0}, /* FEATURE_IOBUS_enable */
+ {0x38,0,0}, /* FEATURE_Mediabay_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_power */
+ {0x38,0,0}, /* FEATURE_Mediabay_PCI_enable */
+ {0x38,0,0}, /* FEATURE_Mediabay_IDE_enable */
+ {0x3c,1,0x08000000}, /* FEATURE_Mediabay_IDE_reset */
+ {0x38,0,0}, /* FEATURE_Mediabay_floppy_enable */
+ {0x38,0,0}, /* FEATURE_BMac_reset */
+ {0x38,0,0}, /* FEATURE_BMac_IO_enable */
+ {0x40,1,0x02000000}, /* FEATURE_Modem_power */
+ {0x38,0,0}, /* FEATURE_Slow_SCC_PCLK */
+ {0x38,0,0}, /* FEATURE_Sound_Power */
+ {0x38,0,0}, /* FEATURE_Sound_CLK_Enable */
+ {0x38,0,0}, /* FEATURE_IDE2_enable */
+ {0x3c,1,0x40000000}, /* FEATURE_IDE2_reset */
};
/* definition of a feature controller object */
-struct feature_controller
-{
- u32* bits;
+struct feature_controller {
+ fbit* bits;
volatile u32* reg;
struct device_node* device;
+ spinlock_t lock;
};
/* static functions */
static void
-feature_add_controller(struct device_node *controller_device, u32* bits);
+feature_add_controller(struct device_node *controller_device, fbit* bits);
-static int
+static struct feature_controller*
feature_lookup_controller(struct device_node *device);
/* static varialbles */
-static struct feature_controller controllers[MAX_FEATURE_REGS];
+static struct feature_controller controllers[MAX_FEATURE_CONTROLLERS];
static int controller_count = 0;
@@ -96,18 +155,23 @@
struct device_node *np;
np = find_devices("mac-io");
- while (np != NULL)
- {
- feature_add_controller(np, feature_bits_heathrow);
+ while (np != NULL) {
+ /* KeyLargo contains several (5 ?) FCR registers in mac-io,
+ * plus some gpio's which could eventually be handled here.
+ */
+ if (device_is_compatible(np, "Keylargo")) {
+ feature_add_controller(np, feature_bits_keylargo);
+ } else {
+ feature_add_controller(np, feature_bits_heathrow);
+ }
np = np->next;
}
if (controller_count == 0)
{
np = find_devices("ohare");
- if (np)
- {
+ if (np) {
if (find_devices("via-pmu") != NULL)
- feature_add_controller(np, feature_bits_pbook);
+ feature_add_controller(np, feature_bits_ohare_pbook);
else
/* else not sure; maybe this is a Starmax? */
feature_add_controller(np, NULL);
@@ -116,17 +180,26 @@
if (controller_count)
printk(KERN_INFO "Registered %d feature controller(s)\n", controller_count);
+
+#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_DMASOUND_MODULE
+ /* On PowerBooks, we disable the sound chip when dmasound is a module */
+ if (controller_count && find_devices("via-pmu") != NULL) {
+ feature_clear(controllers[0].device, FEATURE_Sound_power);
+ feature_clear(controllers[0].device, FEATURE_Sound_CLK_enable);
+ }
+#endif
+#endif
}
static void
-feature_add_controller(struct device_node *controller_device, u32* bits)
+feature_add_controller(struct device_node *controller_device, fbit* bits)
{
struct feature_controller* controller;
- if (controller_count >= MAX_FEATURE_REGS)
- {
+ if (controller_count >= MAX_FEATURE_CONTROLLERS) {
printk(KERN_INFO "Feature controller %s skipped(MAX:%d)\n",
- controller_device->full_name, MAX_FEATURE_REGS);
+ controller_device->full_name, MAX_FEATURE_CONTROLLERS);
return;
}
controller = &controllers[controller_count];
@@ -140,30 +213,32 @@
}
controller->reg = (volatile u32 *)ioremap(
- controller_device->addrs[0].address + OHARE_FEATURE_REG, 4);
+ controller_device->addrs[0].address, MAX_FEATURE_OFFSET);
if (bits == NULL) {
printk(KERN_INFO "Twiddling the magic ohare bits\n");
- out_le32(controller->reg, STARMAX_FEATURES);
+ out_le32(FREG(controller,OHARE_FEATURE_REG), STARMAX_FEATURES);
return;
}
+ spin_lock_init(&controller->lock);
+
controller_count++;
}
-static int
+static struct feature_controller*
feature_lookup_controller(struct device_node *device)
{
int i;
if (device == NULL)
- return -EINVAL;
+ return NULL;
while(device)
{
for (i=0; i<controller_count; i++)
if (device == controllers[i].device)
- return i;
+ return &controllers[i];
device = device->parent;
}
@@ -172,35 +247,36 @@
device->name);
#endif
- return -ENODEV;
+ return NULL;
}
int
feature_set(struct device_node* device, enum system_feature f)
{
- int controller;
- unsigned long flags;
+ struct feature_controller* controller;
+ unsigned long flags;
+ unsigned long value;
+ fbit* bit;
if (f >= FEATURE_last)
return -EINVAL;
controller = feature_lookup_controller(device);
- if (controller < 0)
- return controller;
+ if (!controller)
+ return -ENODEV;
+ bit = &controller->bits[f];
#ifdef DEBUG_FEATURE
printk("feature: <%s> setting feature %d in controller @0x%x\n",
- device->name, (int)f, (unsigned int)controllers[controller].reg);
+ device->name, (int)f, (unsigned int)controller->reg);
#endif
- save_flags(flags);
- cli();
- out_le32( controllers[controller].reg,
- in_le32(controllers[controller].reg) |
- controllers[controller].bits[f]);
- (void)in_le32(controllers[controller].reg);
- restore_flags(flags);
- udelay(10);
+ spin_lock_irqsave(&controller->lock, flags);
+ value = in_le32(FREG(controller, bit->reg));
+ value = bit->polarity ? (value & ~bit->mask) : (value | bit->mask);
+ out_le32(FREG(controller, bit->reg), value);
+ (void)in_le32(FREG(controller, bit->reg));
+ spin_unlock_irqrestore(&controller->lock, flags);
return 0;
}
@@ -208,29 +284,30 @@
int
feature_clear(struct device_node* device, enum system_feature f)
{
- int controller;
- unsigned long flags;
+ struct feature_controller* controller;
+ unsigned long flags;
+ unsigned long value;
+ fbit* bit;
if (f >= FEATURE_last)
return -EINVAL;
controller = feature_lookup_controller(device);
- if (controller < 0)
- return controller;
+ if (!controller)
+ return -ENODEV;
+ bit = &controller->bits[f];
#ifdef DEBUG_FEATURE
printk("feature: <%s> clearing feature %d in controller @0x%x\n",
- device->name, (int)f, (unsigned int)controllers[controller].reg);
+ device->name, (int)f, (unsigned int)controller->reg);
#endif
- save_flags(flags);
- cli();
- out_le32( controllers[controller].reg,
- in_le32(controllers[controller].reg) &
- ~(controllers[controller].bits[f]));
- (void)in_le32(controllers[controller].reg);
- restore_flags(flags);
- udelay(10);
+ spin_lock_irqsave(&controller->lock, flags);
+ value = in_le32(FREG(controller, bit->reg));
+ value = bit->polarity ? (value | bit->mask) : (value & ~bit->mask);
+ out_le32(FREG(controller, bit->reg), value);
+ (void)in_le32(FREG(controller, bit->reg));
+ spin_unlock_irqrestore(&controller->lock, flags);
return 0;
}
@@ -238,16 +315,27 @@
int
feature_test(struct device_node* device, enum system_feature f)
{
- int controller;
+ struct feature_controller* controller;
+ unsigned long value;
+ fbit* bit;
if (f >= FEATURE_last)
return -EINVAL;
controller = feature_lookup_controller(device);
- if (controller < 0)
- return controller;
+ if (!controller)
+ return -ENODEV;
+ bit = &controller->bits[f];
- return (in_le32(controllers[controller].reg) &
- controllers[controller].bits[f]) != 0;
+#ifdef DEBUG_FEATURE
+ printk("feature: <%s> clearing feature %d in controller @0x%x\n",
+ device->name, (int)f, (unsigned int)controller->reg);
+#endif
+ /* If one feature contains several bits, all of them must be set
+ * for value to be true, or all of them must be 0 if polarity is
+ * inverse
+ */
+ value = (in_le32(FREG(controller, bit->reg)) & bit->mask);
+ return bit->polarity ? (value == 0) : (value == bit->mask);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)