1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * Driver for the media bay on the PowerBook 3400 and 2400. 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * Copyright (C) 1998 Paul Mackerras. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * Various evolutions by Benjamin Herrenschmidt & Henry Worth 7*1da177e4SLinus Torvalds * 8*1da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 9*1da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 10*1da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 11*1da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 12*1da177e4SLinus Torvalds */ 13*1da177e4SLinus Torvalds #include <linux/config.h> 14*1da177e4SLinus Torvalds #include <linux/types.h> 15*1da177e4SLinus Torvalds #include <linux/errno.h> 16*1da177e4SLinus Torvalds #include <linux/kernel.h> 17*1da177e4SLinus Torvalds #include <linux/delay.h> 18*1da177e4SLinus Torvalds #include <linux/sched.h> 19*1da177e4SLinus Torvalds #include <linux/timer.h> 20*1da177e4SLinus Torvalds #include <linux/hdreg.h> 21*1da177e4SLinus Torvalds #include <linux/stddef.h> 22*1da177e4SLinus Torvalds #include <linux/init.h> 23*1da177e4SLinus Torvalds #include <linux/ide.h> 24*1da177e4SLinus Torvalds #include <asm/prom.h> 25*1da177e4SLinus Torvalds #include <asm/pgtable.h> 26*1da177e4SLinus Torvalds #include <asm/io.h> 27*1da177e4SLinus Torvalds #include <asm/machdep.h> 28*1da177e4SLinus Torvalds #include <asm/pmac_feature.h> 29*1da177e4SLinus Torvalds #include <asm/mediabay.h> 30*1da177e4SLinus Torvalds #include <asm/sections.h> 31*1da177e4SLinus Torvalds #include <asm/ohare.h> 32*1da177e4SLinus Torvalds #include <asm/heathrow.h> 33*1da177e4SLinus Torvalds #include <asm/keylargo.h> 34*1da177e4SLinus Torvalds #include <linux/adb.h> 35*1da177e4SLinus Torvalds #include <linux/pmu.h> 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds 38*1da177e4SLinus Torvalds #define MB_DEBUG 39*1da177e4SLinus Torvalds #define MB_IGNORE_SIGNALS 40*1da177e4SLinus Torvalds 41*1da177e4SLinus Torvalds #ifdef MB_DEBUG 42*1da177e4SLinus Torvalds #define MBDBG(fmt, arg...) printk(KERN_INFO fmt , ## arg) 43*1da177e4SLinus Torvalds #else 44*1da177e4SLinus Torvalds #define MBDBG(fmt, arg...) do { } while (0) 45*1da177e4SLinus Torvalds #endif 46*1da177e4SLinus Torvalds 47*1da177e4SLinus Torvalds #define MB_FCR32(bay, r) ((bay)->base + ((r) >> 2)) 48*1da177e4SLinus Torvalds #define MB_FCR8(bay, r) (((volatile u8 __iomem *)((bay)->base)) + (r)) 49*1da177e4SLinus Torvalds 50*1da177e4SLinus Torvalds #define MB_IN32(bay,r) (in_le32(MB_FCR32(bay,r))) 51*1da177e4SLinus Torvalds #define MB_OUT32(bay,r,v) (out_le32(MB_FCR32(bay,r), (v))) 52*1da177e4SLinus Torvalds #define MB_BIS(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) | (v))) 53*1da177e4SLinus Torvalds #define MB_BIC(bay,r,v) (MB_OUT32((bay), (r), MB_IN32((bay), r) & ~(v))) 54*1da177e4SLinus Torvalds #define MB_IN8(bay,r) (in_8(MB_FCR8(bay,r))) 55*1da177e4SLinus Torvalds #define MB_OUT8(bay,r,v) (out_8(MB_FCR8(bay,r), (v))) 56*1da177e4SLinus Torvalds 57*1da177e4SLinus Torvalds struct media_bay_info; 58*1da177e4SLinus Torvalds 59*1da177e4SLinus Torvalds struct mb_ops { 60*1da177e4SLinus Torvalds char* name; 61*1da177e4SLinus Torvalds void (*init)(struct media_bay_info *bay); 62*1da177e4SLinus Torvalds u8 (*content)(struct media_bay_info *bay); 63*1da177e4SLinus Torvalds void (*power)(struct media_bay_info *bay, int on_off); 64*1da177e4SLinus Torvalds int (*setup_bus)(struct media_bay_info *bay, u8 device_id); 65*1da177e4SLinus Torvalds void (*un_reset)(struct media_bay_info *bay); 66*1da177e4SLinus Torvalds void (*un_reset_ide)(struct media_bay_info *bay); 67*1da177e4SLinus Torvalds }; 68*1da177e4SLinus Torvalds 69*1da177e4SLinus Torvalds struct media_bay_info { 70*1da177e4SLinus Torvalds u32 __iomem *base; 71*1da177e4SLinus Torvalds int content_id; 72*1da177e4SLinus Torvalds int state; 73*1da177e4SLinus Torvalds int last_value; 74*1da177e4SLinus Torvalds int value_count; 75*1da177e4SLinus Torvalds int timer; 76*1da177e4SLinus Torvalds struct macio_dev *mdev; 77*1da177e4SLinus Torvalds struct mb_ops* ops; 78*1da177e4SLinus Torvalds int index; 79*1da177e4SLinus Torvalds int cached_gpio; 80*1da177e4SLinus Torvalds int sleeping; 81*1da177e4SLinus Torvalds struct semaphore lock; 82*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 83*1da177e4SLinus Torvalds void __iomem *cd_base; 84*1da177e4SLinus Torvalds int cd_index; 85*1da177e4SLinus Torvalds int cd_irq; 86*1da177e4SLinus Torvalds int cd_retry; 87*1da177e4SLinus Torvalds #endif 88*1da177e4SLinus Torvalds }; 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds #define MAX_BAYS 2 91*1da177e4SLinus Torvalds 92*1da177e4SLinus Torvalds static struct media_bay_info media_bays[MAX_BAYS]; 93*1da177e4SLinus Torvalds int media_bay_count = 0; 94*1da177e4SLinus Torvalds 95*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 96*1da177e4SLinus Torvalds /* check the busy bit in the media-bay ide interface 97*1da177e4SLinus Torvalds (assumes the media-bay contains an ide device) */ 98*1da177e4SLinus Torvalds #define MB_IDE_READY(i) ((readb(media_bays[i].cd_base + 0x70) & 0x80) == 0) 99*1da177e4SLinus Torvalds #endif 100*1da177e4SLinus Torvalds 101*1da177e4SLinus Torvalds /* 102*1da177e4SLinus Torvalds * Wait that number of ms between each step in normal polling mode 103*1da177e4SLinus Torvalds */ 104*1da177e4SLinus Torvalds #define MB_POLL_DELAY 25 105*1da177e4SLinus Torvalds 106*1da177e4SLinus Torvalds /* 107*1da177e4SLinus Torvalds * Consider the media-bay ID value stable if it is the same for 108*1da177e4SLinus Torvalds * this number of milliseconds 109*1da177e4SLinus Torvalds */ 110*1da177e4SLinus Torvalds #define MB_STABLE_DELAY 100 111*1da177e4SLinus Torvalds 112*1da177e4SLinus Torvalds /* Wait after powering up the media bay this delay in ms 113*1da177e4SLinus Torvalds * timeout bumped for some powerbooks 114*1da177e4SLinus Torvalds */ 115*1da177e4SLinus Torvalds #define MB_POWER_DELAY 200 116*1da177e4SLinus Torvalds 117*1da177e4SLinus Torvalds /* 118*1da177e4SLinus Torvalds * Hold the media-bay reset signal true for this many ticks 119*1da177e4SLinus Torvalds * after a device is inserted before releasing it. 120*1da177e4SLinus Torvalds */ 121*1da177e4SLinus Torvalds #define MB_RESET_DELAY 50 122*1da177e4SLinus Torvalds 123*1da177e4SLinus Torvalds /* 124*1da177e4SLinus Torvalds * Wait this long after the reset signal is released and before doing 125*1da177e4SLinus Torvalds * further operations. After this delay, the IDE reset signal is released 126*1da177e4SLinus Torvalds * too for an IDE device 127*1da177e4SLinus Torvalds */ 128*1da177e4SLinus Torvalds #define MB_SETUP_DELAY 100 129*1da177e4SLinus Torvalds 130*1da177e4SLinus Torvalds /* 131*1da177e4SLinus Torvalds * Wait this many ticks after an IDE device (e.g. CD-ROM) is inserted 132*1da177e4SLinus Torvalds * (or until the device is ready) before waiting for busy bit to disappear 133*1da177e4SLinus Torvalds */ 134*1da177e4SLinus Torvalds #define MB_IDE_WAIT 1000 135*1da177e4SLinus Torvalds 136*1da177e4SLinus Torvalds /* 137*1da177e4SLinus Torvalds * Timeout waiting for busy bit of an IDE device to go down 138*1da177e4SLinus Torvalds */ 139*1da177e4SLinus Torvalds #define MB_IDE_TIMEOUT 5000 140*1da177e4SLinus Torvalds 141*1da177e4SLinus Torvalds /* 142*1da177e4SLinus Torvalds * Max retries of the full power up/down sequence for an IDE device 143*1da177e4SLinus Torvalds */ 144*1da177e4SLinus Torvalds #define MAX_CD_RETRIES 3 145*1da177e4SLinus Torvalds 146*1da177e4SLinus Torvalds /* 147*1da177e4SLinus Torvalds * States of a media bay 148*1da177e4SLinus Torvalds */ 149*1da177e4SLinus Torvalds enum { 150*1da177e4SLinus Torvalds mb_empty = 0, /* Idle */ 151*1da177e4SLinus Torvalds mb_powering_up, /* power bit set, waiting MB_POWER_DELAY */ 152*1da177e4SLinus Torvalds mb_enabling_bay, /* enable bits set, waiting MB_RESET_DELAY */ 153*1da177e4SLinus Torvalds mb_resetting, /* reset bit unset, waiting MB_SETUP_DELAY */ 154*1da177e4SLinus Torvalds mb_ide_resetting, /* IDE reset bit unser, waiting MB_IDE_WAIT */ 155*1da177e4SLinus Torvalds mb_ide_waiting, /* Waiting for BUSY bit to go away until MB_IDE_TIMEOUT */ 156*1da177e4SLinus Torvalds mb_up, /* Media bay full */ 157*1da177e4SLinus Torvalds mb_powering_down /* Powering down (avoid too fast down/up) */ 158*1da177e4SLinus Torvalds }; 159*1da177e4SLinus Torvalds 160*1da177e4SLinus Torvalds #define MB_POWER_SOUND 0x08 161*1da177e4SLinus Torvalds #define MB_POWER_FLOPPY 0x04 162*1da177e4SLinus Torvalds #define MB_POWER_ATA 0x02 163*1da177e4SLinus Torvalds #define MB_POWER_PCI 0x01 164*1da177e4SLinus Torvalds #define MB_POWER_OFF 0x00 165*1da177e4SLinus Torvalds 166*1da177e4SLinus Torvalds /* 167*1da177e4SLinus Torvalds * Functions for polling content of media bay 168*1da177e4SLinus Torvalds */ 169*1da177e4SLinus Torvalds 170*1da177e4SLinus Torvalds static u8 __pmac 171*1da177e4SLinus Torvalds ohare_mb_content(struct media_bay_info *bay) 172*1da177e4SLinus Torvalds { 173*1da177e4SLinus Torvalds return (MB_IN32(bay, OHARE_MBCR) >> 12) & 7; 174*1da177e4SLinus Torvalds } 175*1da177e4SLinus Torvalds 176*1da177e4SLinus Torvalds static u8 __pmac 177*1da177e4SLinus Torvalds heathrow_mb_content(struct media_bay_info *bay) 178*1da177e4SLinus Torvalds { 179*1da177e4SLinus Torvalds return (MB_IN32(bay, HEATHROW_MBCR) >> 12) & 7; 180*1da177e4SLinus Torvalds } 181*1da177e4SLinus Torvalds 182*1da177e4SLinus Torvalds static u8 __pmac 183*1da177e4SLinus Torvalds keylargo_mb_content(struct media_bay_info *bay) 184*1da177e4SLinus Torvalds { 185*1da177e4SLinus Torvalds int new_gpio; 186*1da177e4SLinus Torvalds 187*1da177e4SLinus Torvalds new_gpio = MB_IN8(bay, KL_GPIO_MEDIABAY_IRQ) & KEYLARGO_GPIO_INPUT_DATA; 188*1da177e4SLinus Torvalds if (new_gpio) { 189*1da177e4SLinus Torvalds bay->cached_gpio = new_gpio; 190*1da177e4SLinus Torvalds return MB_NO; 191*1da177e4SLinus Torvalds } else if (bay->cached_gpio != new_gpio) { 192*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); 193*1da177e4SLinus Torvalds (void)MB_IN32(bay, KEYLARGO_MBCR); 194*1da177e4SLinus Torvalds udelay(5); 195*1da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); 196*1da177e4SLinus Torvalds (void)MB_IN32(bay, KEYLARGO_MBCR); 197*1da177e4SLinus Torvalds udelay(5); 198*1da177e4SLinus Torvalds bay->cached_gpio = new_gpio; 199*1da177e4SLinus Torvalds } 200*1da177e4SLinus Torvalds return (MB_IN32(bay, KEYLARGO_MBCR) >> 4) & 7; 201*1da177e4SLinus Torvalds } 202*1da177e4SLinus Torvalds 203*1da177e4SLinus Torvalds /* 204*1da177e4SLinus Torvalds * Functions for powering up/down the bay, puts the bay device 205*1da177e4SLinus Torvalds * into reset state as well 206*1da177e4SLinus Torvalds */ 207*1da177e4SLinus Torvalds 208*1da177e4SLinus Torvalds static void __pmac 209*1da177e4SLinus Torvalds ohare_mb_power(struct media_bay_info* bay, int on_off) 210*1da177e4SLinus Torvalds { 211*1da177e4SLinus Torvalds if (on_off) { 212*1da177e4SLinus Torvalds /* Power up device, assert it's reset line */ 213*1da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_BAY_RESET_N); 214*1da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_BAY_POWER_N); 215*1da177e4SLinus Torvalds } else { 216*1da177e4SLinus Torvalds /* Disable all devices */ 217*1da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_BAY_DEV_MASK); 218*1da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_FLOPPY_ENABLE); 219*1da177e4SLinus Torvalds /* Cut power from bay, release reset line */ 220*1da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_POWER_N); 221*1da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); 222*1da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); 223*1da177e4SLinus Torvalds } 224*1da177e4SLinus Torvalds MB_BIC(bay, OHARE_MBCR, 0x00000F00); 225*1da177e4SLinus Torvalds } 226*1da177e4SLinus Torvalds 227*1da177e4SLinus Torvalds static void __pmac 228*1da177e4SLinus Torvalds heathrow_mb_power(struct media_bay_info* bay, int on_off) 229*1da177e4SLinus Torvalds { 230*1da177e4SLinus Torvalds if (on_off) { 231*1da177e4SLinus Torvalds /* Power up device, assert it's reset line */ 232*1da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_BAY_RESET_N); 233*1da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_BAY_POWER_N); 234*1da177e4SLinus Torvalds } else { 235*1da177e4SLinus Torvalds /* Disable all devices */ 236*1da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_BAY_DEV_MASK); 237*1da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); 238*1da177e4SLinus Torvalds /* Cut power from bay, release reset line */ 239*1da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_POWER_N); 240*1da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); 241*1da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); 242*1da177e4SLinus Torvalds } 243*1da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_MBCR, 0x00000F00); 244*1da177e4SLinus Torvalds } 245*1da177e4SLinus Torvalds 246*1da177e4SLinus Torvalds static void __pmac 247*1da177e4SLinus Torvalds keylargo_mb_power(struct media_bay_info* bay, int on_off) 248*1da177e4SLinus Torvalds { 249*1da177e4SLinus Torvalds if (on_off) { 250*1da177e4SLinus Torvalds /* Power up device, assert it's reset line */ 251*1da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); 252*1da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); 253*1da177e4SLinus Torvalds } else { 254*1da177e4SLinus Torvalds /* Disable all devices */ 255*1da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_MASK); 256*1da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); 257*1da177e4SLinus Torvalds /* Cut power from bay, release reset line */ 258*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_POWER); 259*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); 260*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); 261*1da177e4SLinus Torvalds } 262*1da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_MBCR, 0x0000000F); 263*1da177e4SLinus Torvalds } 264*1da177e4SLinus Torvalds 265*1da177e4SLinus Torvalds /* 266*1da177e4SLinus Torvalds * Functions for configuring the media bay for a given type of device, 267*1da177e4SLinus Torvalds * enable the related busses 268*1da177e4SLinus Torvalds */ 269*1da177e4SLinus Torvalds 270*1da177e4SLinus Torvalds static int __pmac 271*1da177e4SLinus Torvalds ohare_mb_setup_bus(struct media_bay_info* bay, u8 device_id) 272*1da177e4SLinus Torvalds { 273*1da177e4SLinus Torvalds switch(device_id) { 274*1da177e4SLinus Torvalds case MB_FD: 275*1da177e4SLinus Torvalds case MB_FD1: 276*1da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_FLOPPY_ENABLE); 277*1da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_FLOPPY_ENABLE); 278*1da177e4SLinus Torvalds return 0; 279*1da177e4SLinus Torvalds case MB_CD: 280*1da177e4SLinus Torvalds MB_BIC(bay, OHARE_FCR, OH_IDE1_RESET_N); 281*1da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_IDE_ENABLE); 282*1da177e4SLinus Torvalds return 0; 283*1da177e4SLinus Torvalds case MB_PCI: 284*1da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_PCI_ENABLE); 285*1da177e4SLinus Torvalds return 0; 286*1da177e4SLinus Torvalds } 287*1da177e4SLinus Torvalds return -ENODEV; 288*1da177e4SLinus Torvalds } 289*1da177e4SLinus Torvalds 290*1da177e4SLinus Torvalds static int __pmac 291*1da177e4SLinus Torvalds heathrow_mb_setup_bus(struct media_bay_info* bay, u8 device_id) 292*1da177e4SLinus Torvalds { 293*1da177e4SLinus Torvalds switch(device_id) { 294*1da177e4SLinus Torvalds case MB_FD: 295*1da177e4SLinus Torvalds case MB_FD1: 296*1da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_FLOPPY_ENABLE); 297*1da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_SWIM_ENABLE); 298*1da177e4SLinus Torvalds return 0; 299*1da177e4SLinus Torvalds case MB_CD: 300*1da177e4SLinus Torvalds MB_BIC(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); 301*1da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_IDE_ENABLE); 302*1da177e4SLinus Torvalds return 0; 303*1da177e4SLinus Torvalds case MB_PCI: 304*1da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_PCI_ENABLE); 305*1da177e4SLinus Torvalds return 0; 306*1da177e4SLinus Torvalds } 307*1da177e4SLinus Torvalds return -ENODEV; 308*1da177e4SLinus Torvalds } 309*1da177e4SLinus Torvalds 310*1da177e4SLinus Torvalds static int __pmac 311*1da177e4SLinus Torvalds keylargo_mb_setup_bus(struct media_bay_info* bay, u8 device_id) 312*1da177e4SLinus Torvalds { 313*1da177e4SLinus Torvalds switch(device_id) { 314*1da177e4SLinus Torvalds case MB_CD: 315*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_IDE_ENABLE); 316*1da177e4SLinus Torvalds MB_BIC(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); 317*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_ENABLE); 318*1da177e4SLinus Torvalds return 0; 319*1da177e4SLinus Torvalds case MB_PCI: 320*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_PCI_ENABLE); 321*1da177e4SLinus Torvalds return 0; 322*1da177e4SLinus Torvalds case MB_SOUND: 323*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_SOUND_ENABLE); 324*1da177e4SLinus Torvalds return 0; 325*1da177e4SLinus Torvalds } 326*1da177e4SLinus Torvalds return -ENODEV; 327*1da177e4SLinus Torvalds } 328*1da177e4SLinus Torvalds 329*1da177e4SLinus Torvalds /* 330*1da177e4SLinus Torvalds * Functions for tweaking resets 331*1da177e4SLinus Torvalds */ 332*1da177e4SLinus Torvalds 333*1da177e4SLinus Torvalds static void __pmac 334*1da177e4SLinus Torvalds ohare_mb_un_reset(struct media_bay_info* bay) 335*1da177e4SLinus Torvalds { 336*1da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_BAY_RESET_N); 337*1da177e4SLinus Torvalds } 338*1da177e4SLinus Torvalds 339*1da177e4SLinus Torvalds static void __pmac keylargo_mb_init(struct media_bay_info *bay) 340*1da177e4SLinus Torvalds { 341*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_ENABLE); 342*1da177e4SLinus Torvalds } 343*1da177e4SLinus Torvalds 344*1da177e4SLinus Torvalds static void __pmac heathrow_mb_un_reset(struct media_bay_info* bay) 345*1da177e4SLinus Torvalds { 346*1da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_BAY_RESET_N); 347*1da177e4SLinus Torvalds } 348*1da177e4SLinus Torvalds 349*1da177e4SLinus Torvalds static void __pmac keylargo_mb_un_reset(struct media_bay_info* bay) 350*1da177e4SLinus Torvalds { 351*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_MBCR, KL_MBCR_MB0_DEV_RESET); 352*1da177e4SLinus Torvalds } 353*1da177e4SLinus Torvalds 354*1da177e4SLinus Torvalds static void __pmac ohare_mb_un_reset_ide(struct media_bay_info* bay) 355*1da177e4SLinus Torvalds { 356*1da177e4SLinus Torvalds MB_BIS(bay, OHARE_FCR, OH_IDE1_RESET_N); 357*1da177e4SLinus Torvalds } 358*1da177e4SLinus Torvalds 359*1da177e4SLinus Torvalds static void __pmac heathrow_mb_un_reset_ide(struct media_bay_info* bay) 360*1da177e4SLinus Torvalds { 361*1da177e4SLinus Torvalds MB_BIS(bay, HEATHROW_FCR, HRW_IDE1_RESET_N); 362*1da177e4SLinus Torvalds } 363*1da177e4SLinus Torvalds 364*1da177e4SLinus Torvalds static void __pmac keylargo_mb_un_reset_ide(struct media_bay_info* bay) 365*1da177e4SLinus Torvalds { 366*1da177e4SLinus Torvalds MB_BIS(bay, KEYLARGO_FCR1, KL1_EIDE0_RESET_N); 367*1da177e4SLinus Torvalds } 368*1da177e4SLinus Torvalds 369*1da177e4SLinus Torvalds static inline void __pmac set_mb_power(struct media_bay_info* bay, int onoff) 370*1da177e4SLinus Torvalds { 371*1da177e4SLinus Torvalds /* Power up up and assert the bay reset line */ 372*1da177e4SLinus Torvalds if (onoff) { 373*1da177e4SLinus Torvalds bay->ops->power(bay, 1); 374*1da177e4SLinus Torvalds bay->state = mb_powering_up; 375*1da177e4SLinus Torvalds MBDBG("mediabay%d: powering up\n", bay->index); 376*1da177e4SLinus Torvalds } else { 377*1da177e4SLinus Torvalds /* Make sure everything is powered down & disabled */ 378*1da177e4SLinus Torvalds bay->ops->power(bay, 0); 379*1da177e4SLinus Torvalds bay->state = mb_powering_down; 380*1da177e4SLinus Torvalds MBDBG("mediabay%d: powering down\n", bay->index); 381*1da177e4SLinus Torvalds } 382*1da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_POWER_DELAY); 383*1da177e4SLinus Torvalds } 384*1da177e4SLinus Torvalds 385*1da177e4SLinus Torvalds static void __pmac poll_media_bay(struct media_bay_info* bay) 386*1da177e4SLinus Torvalds { 387*1da177e4SLinus Torvalds int id = bay->ops->content(bay); 388*1da177e4SLinus Torvalds 389*1da177e4SLinus Torvalds if (id == bay->last_value) { 390*1da177e4SLinus Torvalds if (id != bay->content_id) { 391*1da177e4SLinus Torvalds bay->value_count += msecs_to_jiffies(MB_POLL_DELAY); 392*1da177e4SLinus Torvalds if (bay->value_count >= msecs_to_jiffies(MB_STABLE_DELAY)) { 393*1da177e4SLinus Torvalds /* If the device type changes without going thru 394*1da177e4SLinus Torvalds * "MB_NO", we force a pass by "MB_NO" to make sure 395*1da177e4SLinus Torvalds * things are properly reset 396*1da177e4SLinus Torvalds */ 397*1da177e4SLinus Torvalds if ((id != MB_NO) && (bay->content_id != MB_NO)) { 398*1da177e4SLinus Torvalds id = MB_NO; 399*1da177e4SLinus Torvalds MBDBG("mediabay%d: forcing MB_NO\n", bay->index); 400*1da177e4SLinus Torvalds } 401*1da177e4SLinus Torvalds MBDBG("mediabay%d: switching to %d\n", bay->index, id); 402*1da177e4SLinus Torvalds set_mb_power(bay, id != MB_NO); 403*1da177e4SLinus Torvalds bay->content_id = id; 404*1da177e4SLinus Torvalds if (id == MB_NO) { 405*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 406*1da177e4SLinus Torvalds bay->cd_retry = 0; 407*1da177e4SLinus Torvalds #endif 408*1da177e4SLinus Torvalds printk(KERN_INFO "media bay %d is empty\n", bay->index); 409*1da177e4SLinus Torvalds } 410*1da177e4SLinus Torvalds } 411*1da177e4SLinus Torvalds } 412*1da177e4SLinus Torvalds } else { 413*1da177e4SLinus Torvalds bay->last_value = id; 414*1da177e4SLinus Torvalds bay->value_count = 0; 415*1da177e4SLinus Torvalds } 416*1da177e4SLinus Torvalds } 417*1da177e4SLinus Torvalds 418*1da177e4SLinus Torvalds int __pmac check_media_bay(struct device_node *which_bay, int what) 419*1da177e4SLinus Torvalds { 420*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 421*1da177e4SLinus Torvalds int i; 422*1da177e4SLinus Torvalds 423*1da177e4SLinus Torvalds for (i=0; i<media_bay_count; i++) 424*1da177e4SLinus Torvalds if (media_bays[i].mdev && which_bay == media_bays[i].mdev->ofdev.node) { 425*1da177e4SLinus Torvalds if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up) 426*1da177e4SLinus Torvalds return 0; 427*1da177e4SLinus Torvalds media_bays[i].cd_index = -1; 428*1da177e4SLinus Torvalds return -EINVAL; 429*1da177e4SLinus Torvalds } 430*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */ 431*1da177e4SLinus Torvalds return -ENODEV; 432*1da177e4SLinus Torvalds } 433*1da177e4SLinus Torvalds EXPORT_SYMBOL(check_media_bay); 434*1da177e4SLinus Torvalds 435*1da177e4SLinus Torvalds int __pmac check_media_bay_by_base(unsigned long base, int what) 436*1da177e4SLinus Torvalds { 437*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 438*1da177e4SLinus Torvalds int i; 439*1da177e4SLinus Torvalds 440*1da177e4SLinus Torvalds for (i=0; i<media_bay_count; i++) 441*1da177e4SLinus Torvalds if (media_bays[i].mdev && base == (unsigned long) media_bays[i].cd_base) { 442*1da177e4SLinus Torvalds if ((what == media_bays[i].content_id) && media_bays[i].state == mb_up) 443*1da177e4SLinus Torvalds return 0; 444*1da177e4SLinus Torvalds media_bays[i].cd_index = -1; 445*1da177e4SLinus Torvalds return -EINVAL; 446*1da177e4SLinus Torvalds } 447*1da177e4SLinus Torvalds #endif 448*1da177e4SLinus Torvalds 449*1da177e4SLinus Torvalds return -ENODEV; 450*1da177e4SLinus Torvalds } 451*1da177e4SLinus Torvalds 452*1da177e4SLinus Torvalds int __pmac media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, 453*1da177e4SLinus Torvalds int irq, int index) 454*1da177e4SLinus Torvalds { 455*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 456*1da177e4SLinus Torvalds int i; 457*1da177e4SLinus Torvalds 458*1da177e4SLinus Torvalds for (i=0; i<media_bay_count; i++) { 459*1da177e4SLinus Torvalds struct media_bay_info* bay = &media_bays[i]; 460*1da177e4SLinus Torvalds 461*1da177e4SLinus Torvalds if (bay->mdev && which_bay == bay->mdev->ofdev.node) { 462*1da177e4SLinus Torvalds int timeout = 5000; 463*1da177e4SLinus Torvalds 464*1da177e4SLinus Torvalds down(&bay->lock); 465*1da177e4SLinus Torvalds 466*1da177e4SLinus Torvalds bay->cd_base = (void __iomem *) base; 467*1da177e4SLinus Torvalds bay->cd_irq = irq; 468*1da177e4SLinus Torvalds 469*1da177e4SLinus Torvalds if ((MB_CD != bay->content_id) || bay->state != mb_up) { 470*1da177e4SLinus Torvalds up(&bay->lock); 471*1da177e4SLinus Torvalds return 0; 472*1da177e4SLinus Torvalds } 473*1da177e4SLinus Torvalds printk(KERN_DEBUG "Registered ide%d for media bay %d\n", index, i); 474*1da177e4SLinus Torvalds do { 475*1da177e4SLinus Torvalds if (MB_IDE_READY(i)) { 476*1da177e4SLinus Torvalds bay->cd_index = index; 477*1da177e4SLinus Torvalds up(&bay->lock); 478*1da177e4SLinus Torvalds return 0; 479*1da177e4SLinus Torvalds } 480*1da177e4SLinus Torvalds mdelay(1); 481*1da177e4SLinus Torvalds } while(--timeout); 482*1da177e4SLinus Torvalds printk(KERN_DEBUG "Timeount waiting IDE in bay %d\n", i); 483*1da177e4SLinus Torvalds up(&bay->lock); 484*1da177e4SLinus Torvalds return -ENODEV; 485*1da177e4SLinus Torvalds } 486*1da177e4SLinus Torvalds } 487*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */ 488*1da177e4SLinus Torvalds 489*1da177e4SLinus Torvalds return -ENODEV; 490*1da177e4SLinus Torvalds } 491*1da177e4SLinus Torvalds 492*1da177e4SLinus Torvalds static void __pmac media_bay_step(int i) 493*1da177e4SLinus Torvalds { 494*1da177e4SLinus Torvalds struct media_bay_info* bay = &media_bays[i]; 495*1da177e4SLinus Torvalds 496*1da177e4SLinus Torvalds /* We don't poll when powering down */ 497*1da177e4SLinus Torvalds if (bay->state != mb_powering_down) 498*1da177e4SLinus Torvalds poll_media_bay(bay); 499*1da177e4SLinus Torvalds 500*1da177e4SLinus Torvalds /* If timer expired or polling IDE busy, run state machine */ 501*1da177e4SLinus Torvalds if ((bay->state != mb_ide_waiting) && (bay->timer != 0)) { 502*1da177e4SLinus Torvalds bay->timer -= msecs_to_jiffies(MB_POLL_DELAY); 503*1da177e4SLinus Torvalds if (bay->timer > 0) 504*1da177e4SLinus Torvalds return; 505*1da177e4SLinus Torvalds bay->timer = 0; 506*1da177e4SLinus Torvalds } 507*1da177e4SLinus Torvalds 508*1da177e4SLinus Torvalds switch(bay->state) { 509*1da177e4SLinus Torvalds case mb_powering_up: 510*1da177e4SLinus Torvalds if (bay->ops->setup_bus(bay, bay->last_value) < 0) { 511*1da177e4SLinus Torvalds MBDBG("mediabay%d: device not supported (kind:%d)\n", i, bay->content_id); 512*1da177e4SLinus Torvalds set_mb_power(bay, 0); 513*1da177e4SLinus Torvalds break; 514*1da177e4SLinus Torvalds } 515*1da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_RESET_DELAY); 516*1da177e4SLinus Torvalds bay->state = mb_enabling_bay; 517*1da177e4SLinus Torvalds MBDBG("mediabay%d: enabling (kind:%d)\n", i, bay->content_id); 518*1da177e4SLinus Torvalds break; 519*1da177e4SLinus Torvalds case mb_enabling_bay: 520*1da177e4SLinus Torvalds bay->ops->un_reset(bay); 521*1da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_SETUP_DELAY); 522*1da177e4SLinus Torvalds bay->state = mb_resetting; 523*1da177e4SLinus Torvalds MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id); 524*1da177e4SLinus Torvalds break; 525*1da177e4SLinus Torvalds 526*1da177e4SLinus Torvalds case mb_resetting: 527*1da177e4SLinus Torvalds if (bay->content_id != MB_CD) { 528*1da177e4SLinus Torvalds MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id); 529*1da177e4SLinus Torvalds bay->state = mb_up; 530*1da177e4SLinus Torvalds break; 531*1da177e4SLinus Torvalds } 532*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 533*1da177e4SLinus Torvalds MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id); 534*1da177e4SLinus Torvalds bay->ops->un_reset_ide(bay); 535*1da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_IDE_WAIT); 536*1da177e4SLinus Torvalds bay->state = mb_ide_resetting; 537*1da177e4SLinus Torvalds #else 538*1da177e4SLinus Torvalds printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i); 539*1da177e4SLinus Torvalds set_mb_power(bay, 0); 540*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */ 541*1da177e4SLinus Torvalds break; 542*1da177e4SLinus Torvalds 543*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 544*1da177e4SLinus Torvalds case mb_ide_resetting: 545*1da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_IDE_TIMEOUT); 546*1da177e4SLinus Torvalds bay->state = mb_ide_waiting; 547*1da177e4SLinus Torvalds MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id); 548*1da177e4SLinus Torvalds break; 549*1da177e4SLinus Torvalds 550*1da177e4SLinus Torvalds case mb_ide_waiting: 551*1da177e4SLinus Torvalds if (bay->cd_base == NULL) { 552*1da177e4SLinus Torvalds bay->timer = 0; 553*1da177e4SLinus Torvalds bay->state = mb_up; 554*1da177e4SLinus Torvalds MBDBG("mediabay%d: up before IDE init\n", i); 555*1da177e4SLinus Torvalds break; 556*1da177e4SLinus Torvalds } else if (MB_IDE_READY(i)) { 557*1da177e4SLinus Torvalds bay->timer = 0; 558*1da177e4SLinus Torvalds bay->state = mb_up; 559*1da177e4SLinus Torvalds if (bay->cd_index < 0) { 560*1da177e4SLinus Torvalds hw_regs_t hw; 561*1da177e4SLinus Torvalds 562*1da177e4SLinus Torvalds printk("mediabay %d, registering IDE...\n", i); 563*1da177e4SLinus Torvalds pmu_suspend(); 564*1da177e4SLinus Torvalds ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL); 565*1da177e4SLinus Torvalds hw.irq = bay->cd_irq; 566*1da177e4SLinus Torvalds hw.chipset = ide_pmac; 567*1da177e4SLinus Torvalds bay->cd_index = ide_register_hw(&hw, NULL); 568*1da177e4SLinus Torvalds pmu_resume(); 569*1da177e4SLinus Torvalds } 570*1da177e4SLinus Torvalds if (bay->cd_index == -1) { 571*1da177e4SLinus Torvalds /* We eventually do a retry */ 572*1da177e4SLinus Torvalds bay->cd_retry++; 573*1da177e4SLinus Torvalds printk("IDE register error\n"); 574*1da177e4SLinus Torvalds set_mb_power(bay, 0); 575*1da177e4SLinus Torvalds } else { 576*1da177e4SLinus Torvalds printk(KERN_DEBUG "media-bay %d is ide%d\n", i, bay->cd_index); 577*1da177e4SLinus Torvalds MBDBG("mediabay %d IDE ready\n", i); 578*1da177e4SLinus Torvalds } 579*1da177e4SLinus Torvalds break; 580*1da177e4SLinus Torvalds } else if (bay->timer > 0) 581*1da177e4SLinus Torvalds bay->timer -= msecs_to_jiffies(MB_POLL_DELAY); 582*1da177e4SLinus Torvalds if (bay->timer <= 0) { 583*1da177e4SLinus Torvalds printk("\nIDE Timeout in bay %d !, IDE state is: 0x%02x\n", 584*1da177e4SLinus Torvalds i, readb(bay->cd_base + 0x70)); 585*1da177e4SLinus Torvalds MBDBG("mediabay%d: nIDE Timeout !\n", i); 586*1da177e4SLinus Torvalds set_mb_power(bay, 0); 587*1da177e4SLinus Torvalds bay->timer = 0; 588*1da177e4SLinus Torvalds } 589*1da177e4SLinus Torvalds break; 590*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */ 591*1da177e4SLinus Torvalds 592*1da177e4SLinus Torvalds case mb_powering_down: 593*1da177e4SLinus Torvalds bay->state = mb_empty; 594*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 595*1da177e4SLinus Torvalds if (bay->cd_index >= 0) { 596*1da177e4SLinus Torvalds printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, 597*1da177e4SLinus Torvalds bay->cd_index); 598*1da177e4SLinus Torvalds ide_unregister(bay->cd_index); 599*1da177e4SLinus Torvalds bay->cd_index = -1; 600*1da177e4SLinus Torvalds } 601*1da177e4SLinus Torvalds if (bay->cd_retry) { 602*1da177e4SLinus Torvalds if (bay->cd_retry > MAX_CD_RETRIES) { 603*1da177e4SLinus Torvalds /* Should add an error sound (sort of beep in dmasound) */ 604*1da177e4SLinus Torvalds printk("\nmedia-bay %d, IDE device badly inserted or unrecognised\n", i); 605*1da177e4SLinus Torvalds } else { 606*1da177e4SLinus Torvalds /* Force a new power down/up sequence */ 607*1da177e4SLinus Torvalds bay->content_id = MB_NO; 608*1da177e4SLinus Torvalds } 609*1da177e4SLinus Torvalds } 610*1da177e4SLinus Torvalds #endif /* CONFIG_BLK_DEV_IDE */ 611*1da177e4SLinus Torvalds MBDBG("mediabay%d: end of power down\n", i); 612*1da177e4SLinus Torvalds break; 613*1da177e4SLinus Torvalds } 614*1da177e4SLinus Torvalds } 615*1da177e4SLinus Torvalds 616*1da177e4SLinus Torvalds /* 617*1da177e4SLinus Torvalds * This procedure runs as a kernel thread to poll the media bay 618*1da177e4SLinus Torvalds * once each tick and register and unregister the IDE interface 619*1da177e4SLinus Torvalds * with the IDE driver. It needs to be a thread because 620*1da177e4SLinus Torvalds * ide_register can't be called from interrupt context. 621*1da177e4SLinus Torvalds */ 622*1da177e4SLinus Torvalds static int __pmac media_bay_task(void *x) 623*1da177e4SLinus Torvalds { 624*1da177e4SLinus Torvalds int i; 625*1da177e4SLinus Torvalds 626*1da177e4SLinus Torvalds strcpy(current->comm, "media-bay"); 627*1da177e4SLinus Torvalds #ifdef MB_IGNORE_SIGNALS 628*1da177e4SLinus Torvalds sigfillset(¤t->blocked); 629*1da177e4SLinus Torvalds #endif 630*1da177e4SLinus Torvalds 631*1da177e4SLinus Torvalds for (;;) { 632*1da177e4SLinus Torvalds for (i = 0; i < media_bay_count; ++i) { 633*1da177e4SLinus Torvalds down(&media_bays[i].lock); 634*1da177e4SLinus Torvalds if (!media_bays[i].sleeping) 635*1da177e4SLinus Torvalds media_bay_step(i); 636*1da177e4SLinus Torvalds up(&media_bays[i].lock); 637*1da177e4SLinus Torvalds } 638*1da177e4SLinus Torvalds 639*1da177e4SLinus Torvalds msleep_interruptible(MB_POLL_DELAY); 640*1da177e4SLinus Torvalds if (signal_pending(current)) 641*1da177e4SLinus Torvalds return 0; 642*1da177e4SLinus Torvalds } 643*1da177e4SLinus Torvalds } 644*1da177e4SLinus Torvalds 645*1da177e4SLinus Torvalds static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_match *match) 646*1da177e4SLinus Torvalds { 647*1da177e4SLinus Torvalds struct media_bay_info* bay; 648*1da177e4SLinus Torvalds u32 __iomem *regbase; 649*1da177e4SLinus Torvalds struct device_node *ofnode; 650*1da177e4SLinus Torvalds int i; 651*1da177e4SLinus Torvalds 652*1da177e4SLinus Torvalds ofnode = mdev->ofdev.node; 653*1da177e4SLinus Torvalds 654*1da177e4SLinus Torvalds if (macio_resource_count(mdev) < 1) 655*1da177e4SLinus Torvalds return -ENODEV; 656*1da177e4SLinus Torvalds if (macio_request_resources(mdev, "media-bay")) 657*1da177e4SLinus Torvalds return -EBUSY; 658*1da177e4SLinus Torvalds /* Media bay registers are located at the beginning of the 659*1da177e4SLinus Torvalds * mac-io chip, we get the parent address for now (hrm...) 660*1da177e4SLinus Torvalds */ 661*1da177e4SLinus Torvalds regbase = (u32 __iomem *) 662*1da177e4SLinus Torvalds ioremap(ofnode->parent->addrs[0].address, 0x100); 663*1da177e4SLinus Torvalds if (regbase == NULL) { 664*1da177e4SLinus Torvalds macio_release_resources(mdev); 665*1da177e4SLinus Torvalds return -ENOMEM; 666*1da177e4SLinus Torvalds } 667*1da177e4SLinus Torvalds 668*1da177e4SLinus Torvalds i = media_bay_count++; 669*1da177e4SLinus Torvalds bay = &media_bays[i]; 670*1da177e4SLinus Torvalds bay->mdev = mdev; 671*1da177e4SLinus Torvalds bay->base = regbase; 672*1da177e4SLinus Torvalds bay->index = i; 673*1da177e4SLinus Torvalds bay->ops = match->data; 674*1da177e4SLinus Torvalds bay->sleeping = 0; 675*1da177e4SLinus Torvalds init_MUTEX(&bay->lock); 676*1da177e4SLinus Torvalds 677*1da177e4SLinus Torvalds /* Init HW probing */ 678*1da177e4SLinus Torvalds if (bay->ops->init) 679*1da177e4SLinus Torvalds bay->ops->init(bay); 680*1da177e4SLinus Torvalds 681*1da177e4SLinus Torvalds printk(KERN_INFO "mediabay%d: Registered %s media-bay\n", i, bay->ops->name); 682*1da177e4SLinus Torvalds 683*1da177e4SLinus Torvalds /* Force an immediate detect */ 684*1da177e4SLinus Torvalds set_mb_power(bay, 0); 685*1da177e4SLinus Torvalds msleep(MB_POWER_DELAY); 686*1da177e4SLinus Torvalds bay->content_id = MB_NO; 687*1da177e4SLinus Torvalds bay->last_value = bay->ops->content(bay); 688*1da177e4SLinus Torvalds bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY); 689*1da177e4SLinus Torvalds bay->state = mb_empty; 690*1da177e4SLinus Torvalds do { 691*1da177e4SLinus Torvalds msleep(MB_POLL_DELAY); 692*1da177e4SLinus Torvalds media_bay_step(i); 693*1da177e4SLinus Torvalds } while((bay->state != mb_empty) && 694*1da177e4SLinus Torvalds (bay->state != mb_up)); 695*1da177e4SLinus Torvalds 696*1da177e4SLinus Torvalds /* Mark us ready by filling our mdev data */ 697*1da177e4SLinus Torvalds macio_set_drvdata(mdev, bay); 698*1da177e4SLinus Torvalds 699*1da177e4SLinus Torvalds /* Startup kernel thread */ 700*1da177e4SLinus Torvalds if (i == 0) 701*1da177e4SLinus Torvalds kernel_thread(media_bay_task, NULL, CLONE_KERNEL); 702*1da177e4SLinus Torvalds 703*1da177e4SLinus Torvalds return 0; 704*1da177e4SLinus Torvalds 705*1da177e4SLinus Torvalds } 706*1da177e4SLinus Torvalds 707*1da177e4SLinus Torvalds static int __pmac media_bay_suspend(struct macio_dev *mdev, u32 state) 708*1da177e4SLinus Torvalds { 709*1da177e4SLinus Torvalds struct media_bay_info *bay = macio_get_drvdata(mdev); 710*1da177e4SLinus Torvalds 711*1da177e4SLinus Torvalds if (state != mdev->ofdev.dev.power.power_state && state == PM_SUSPEND_MEM) { 712*1da177e4SLinus Torvalds down(&bay->lock); 713*1da177e4SLinus Torvalds bay->sleeping = 1; 714*1da177e4SLinus Torvalds set_mb_power(bay, 0); 715*1da177e4SLinus Torvalds up(&bay->lock); 716*1da177e4SLinus Torvalds msleep(MB_POLL_DELAY); 717*1da177e4SLinus Torvalds mdev->ofdev.dev.power.power_state = state; 718*1da177e4SLinus Torvalds } 719*1da177e4SLinus Torvalds return 0; 720*1da177e4SLinus Torvalds } 721*1da177e4SLinus Torvalds 722*1da177e4SLinus Torvalds static int __pmac media_bay_resume(struct macio_dev *mdev) 723*1da177e4SLinus Torvalds { 724*1da177e4SLinus Torvalds struct media_bay_info *bay = macio_get_drvdata(mdev); 725*1da177e4SLinus Torvalds 726*1da177e4SLinus Torvalds if (mdev->ofdev.dev.power.power_state != 0) { 727*1da177e4SLinus Torvalds mdev->ofdev.dev.power.power_state = 0; 728*1da177e4SLinus Torvalds 729*1da177e4SLinus Torvalds /* We re-enable the bay using it's previous content 730*1da177e4SLinus Torvalds only if it did not change. Note those bozo timings, 731*1da177e4SLinus Torvalds they seem to help the 3400 get it right. 732*1da177e4SLinus Torvalds */ 733*1da177e4SLinus Torvalds /* Force MB power to 0 */ 734*1da177e4SLinus Torvalds down(&bay->lock); 735*1da177e4SLinus Torvalds set_mb_power(bay, 0); 736*1da177e4SLinus Torvalds msleep(MB_POWER_DELAY); 737*1da177e4SLinus Torvalds if (bay->ops->content(bay) != bay->content_id) { 738*1da177e4SLinus Torvalds printk("mediabay%d: content changed during sleep...\n", bay->index); 739*1da177e4SLinus Torvalds up(&bay->lock); 740*1da177e4SLinus Torvalds return 0; 741*1da177e4SLinus Torvalds } 742*1da177e4SLinus Torvalds set_mb_power(bay, 1); 743*1da177e4SLinus Torvalds bay->last_value = bay->content_id; 744*1da177e4SLinus Torvalds bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY); 745*1da177e4SLinus Torvalds bay->timer = msecs_to_jiffies(MB_POWER_DELAY); 746*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 747*1da177e4SLinus Torvalds bay->cd_retry = 0; 748*1da177e4SLinus Torvalds #endif 749*1da177e4SLinus Torvalds do { 750*1da177e4SLinus Torvalds msleep(MB_POLL_DELAY); 751*1da177e4SLinus Torvalds media_bay_step(bay->index); 752*1da177e4SLinus Torvalds } while((bay->state != mb_empty) && 753*1da177e4SLinus Torvalds (bay->state != mb_up)); 754*1da177e4SLinus Torvalds bay->sleeping = 0; 755*1da177e4SLinus Torvalds up(&bay->lock); 756*1da177e4SLinus Torvalds } 757*1da177e4SLinus Torvalds return 0; 758*1da177e4SLinus Torvalds } 759*1da177e4SLinus Torvalds 760*1da177e4SLinus Torvalds 761*1da177e4SLinus Torvalds /* Definitions of "ops" structures. 762*1da177e4SLinus Torvalds */ 763*1da177e4SLinus Torvalds static struct mb_ops ohare_mb_ops __pmacdata = { 764*1da177e4SLinus Torvalds .name = "Ohare", 765*1da177e4SLinus Torvalds .content = ohare_mb_content, 766*1da177e4SLinus Torvalds .power = ohare_mb_power, 767*1da177e4SLinus Torvalds .setup_bus = ohare_mb_setup_bus, 768*1da177e4SLinus Torvalds .un_reset = ohare_mb_un_reset, 769*1da177e4SLinus Torvalds .un_reset_ide = ohare_mb_un_reset_ide, 770*1da177e4SLinus Torvalds }; 771*1da177e4SLinus Torvalds 772*1da177e4SLinus Torvalds static struct mb_ops heathrow_mb_ops __pmacdata = { 773*1da177e4SLinus Torvalds .name = "Heathrow", 774*1da177e4SLinus Torvalds .content = heathrow_mb_content, 775*1da177e4SLinus Torvalds .power = heathrow_mb_power, 776*1da177e4SLinus Torvalds .setup_bus = heathrow_mb_setup_bus, 777*1da177e4SLinus Torvalds .un_reset = heathrow_mb_un_reset, 778*1da177e4SLinus Torvalds .un_reset_ide = heathrow_mb_un_reset_ide, 779*1da177e4SLinus Torvalds }; 780*1da177e4SLinus Torvalds 781*1da177e4SLinus Torvalds static struct mb_ops keylargo_mb_ops __pmacdata = { 782*1da177e4SLinus Torvalds .name = "KeyLargo", 783*1da177e4SLinus Torvalds .init = keylargo_mb_init, 784*1da177e4SLinus Torvalds .content = keylargo_mb_content, 785*1da177e4SLinus Torvalds .power = keylargo_mb_power, 786*1da177e4SLinus Torvalds .setup_bus = keylargo_mb_setup_bus, 787*1da177e4SLinus Torvalds .un_reset = keylargo_mb_un_reset, 788*1da177e4SLinus Torvalds .un_reset_ide = keylargo_mb_un_reset_ide, 789*1da177e4SLinus Torvalds }; 790*1da177e4SLinus Torvalds 791*1da177e4SLinus Torvalds /* 792*1da177e4SLinus Torvalds * It seems that the bit for the media-bay interrupt in the IRQ_LEVEL 793*1da177e4SLinus Torvalds * register is always set when there is something in the media bay. 794*1da177e4SLinus Torvalds * This causes problems for the interrupt code if we attach an interrupt 795*1da177e4SLinus Torvalds * handler to the media-bay interrupt, because it tends to go into 796*1da177e4SLinus Torvalds * an infinite loop calling the media bay interrupt handler. 797*1da177e4SLinus Torvalds * Therefore we do it all by polling the media bay once each tick. 798*1da177e4SLinus Torvalds */ 799*1da177e4SLinus Torvalds 800*1da177e4SLinus Torvalds static struct of_match media_bay_match[] = 801*1da177e4SLinus Torvalds { 802*1da177e4SLinus Torvalds { 803*1da177e4SLinus Torvalds .name = "media-bay", 804*1da177e4SLinus Torvalds .type = OF_ANY_MATCH, 805*1da177e4SLinus Torvalds .compatible = "keylargo-media-bay", 806*1da177e4SLinus Torvalds .data = &keylargo_mb_ops, 807*1da177e4SLinus Torvalds }, 808*1da177e4SLinus Torvalds { 809*1da177e4SLinus Torvalds .name = "media-bay", 810*1da177e4SLinus Torvalds .type = OF_ANY_MATCH, 811*1da177e4SLinus Torvalds .compatible = "heathrow-media-bay", 812*1da177e4SLinus Torvalds .data = &heathrow_mb_ops, 813*1da177e4SLinus Torvalds }, 814*1da177e4SLinus Torvalds { 815*1da177e4SLinus Torvalds .name = "media-bay", 816*1da177e4SLinus Torvalds .type = OF_ANY_MATCH, 817*1da177e4SLinus Torvalds .compatible = "ohare-media-bay", 818*1da177e4SLinus Torvalds .data = &ohare_mb_ops, 819*1da177e4SLinus Torvalds }, 820*1da177e4SLinus Torvalds {}, 821*1da177e4SLinus Torvalds }; 822*1da177e4SLinus Torvalds 823*1da177e4SLinus Torvalds static struct macio_driver media_bay_driver = 824*1da177e4SLinus Torvalds { 825*1da177e4SLinus Torvalds .name = "media-bay", 826*1da177e4SLinus Torvalds .match_table = media_bay_match, 827*1da177e4SLinus Torvalds .probe = media_bay_attach, 828*1da177e4SLinus Torvalds .suspend = media_bay_suspend, 829*1da177e4SLinus Torvalds .resume = media_bay_resume 830*1da177e4SLinus Torvalds }; 831*1da177e4SLinus Torvalds 832*1da177e4SLinus Torvalds static int __init media_bay_init(void) 833*1da177e4SLinus Torvalds { 834*1da177e4SLinus Torvalds int i; 835*1da177e4SLinus Torvalds 836*1da177e4SLinus Torvalds for (i=0; i<MAX_BAYS; i++) { 837*1da177e4SLinus Torvalds memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info)); 838*1da177e4SLinus Torvalds media_bays[i].content_id = -1; 839*1da177e4SLinus Torvalds #ifdef CONFIG_BLK_DEV_IDE 840*1da177e4SLinus Torvalds media_bays[i].cd_index = -1; 841*1da177e4SLinus Torvalds #endif 842*1da177e4SLinus Torvalds } 843*1da177e4SLinus Torvalds if (_machine != _MACH_Pmac) 844*1da177e4SLinus Torvalds return -ENODEV; 845*1da177e4SLinus Torvalds 846*1da177e4SLinus Torvalds macio_register_driver(&media_bay_driver); 847*1da177e4SLinus Torvalds 848*1da177e4SLinus Torvalds return 0; 849*1da177e4SLinus Torvalds } 850*1da177e4SLinus Torvalds 851*1da177e4SLinus Torvalds device_initcall(media_bay_init); 852