2008-07-28 01:00:59 +04:00
/* asm/floppy.h: Sparc specific parts of the Floppy driver.
2008-07-18 08:55:51 +04:00
*
* Copyright ( C ) 1995 David S . Miller ( davem @ davemloft . net )
*/
# ifndef __ASM_SPARC_FLOPPY_H
# define __ASM_SPARC_FLOPPY_H
2008-08-27 15:05:35 +04:00
# include <linux/of.h>
# include <linux/of_device.h>
2008-07-18 08:55:51 +04:00
# include <asm/page.h>
# include <asm/pgtable.h>
# include <asm/system.h>
# include <asm/idprom.h>
# include <asm/machines.h>
# include <asm/oplib.h>
# include <asm/auxio.h>
# include <asm/irq.h>
/* We don't need no stinkin' I/O port allocation crap. */
# undef release_region
# undef request_region
# define release_region(X, Y) do { } while(0)
# define request_region(X, Y, Z) (1)
/* References:
* 1 ) Netbsd Sun floppy driver .
* 2 ) NCR 82077 controller manual
* 3 ) Intel 82077 controller manual
*/
struct sun_flpy_controller {
volatile unsigned char status_82072 ; /* Main Status reg. */
# define dcr_82072 status_82072 /* Digital Control reg. */
# define status1_82077 status_82072 /* Auxiliary Status reg. 1 */
volatile unsigned char data_82072 ; /* Data fifo. */
# define status2_82077 data_82072 /* Auxiliary Status reg. 2 */
volatile unsigned char dor_82077 ; /* Digital Output reg. */
volatile unsigned char tapectl_82077 ; /* What the? Tape control reg? */
volatile unsigned char status_82077 ; /* Main Status Register. */
# define drs_82077 status_82077 /* Digital Rate Select reg. */
volatile unsigned char data_82077 ; /* Data fifo. */
volatile unsigned char ___unused ;
volatile unsigned char dir_82077 ; /* Digital Input reg. */
# define dcr_82077 dir_82077 /* Config Control reg. */
} ;
/* You'll only ever find one controller on a SparcStation anyways. */
static struct sun_flpy_controller * sun_fdc = NULL ;
extern volatile unsigned char * fdc_status ;
struct sun_floppy_ops {
unsigned char ( * fd_inb ) ( int port ) ;
void ( * fd_outb ) ( unsigned char value , int port ) ;
} ;
static struct sun_floppy_ops sun_fdops ;
# define fd_inb(port) sun_fdops.fd_inb(port)
# define fd_outb(value,port) sun_fdops.fd_outb(value,port)
# define fd_enable_dma() sun_fd_enable_dma()
# define fd_disable_dma() sun_fd_disable_dma()
# define fd_request_dma() (0) /* nothing... */
# define fd_free_dma() /* nothing... */
# define fd_clear_dma_ff() /* nothing... */
# define fd_set_dma_mode(mode) sun_fd_set_dma_mode(mode)
# define fd_set_dma_addr(addr) sun_fd_set_dma_addr(addr)
# define fd_set_dma_count(count) sun_fd_set_dma_count(count)
# define fd_enable_irq() /* nothing... */
# define fd_disable_irq() /* nothing... */
# define fd_cacheflush(addr, size) /* nothing... */
# define fd_request_irq() sun_fd_request_irq()
# define fd_free_irq() /* nothing... */
#if 0 /* P3: added by Alain, these cause a MMU corruption. 19960524 XXX */
# define fd_dma_mem_alloc(size) ((unsigned long) vmalloc(size))
# define fd_dma_mem_free(addr,size) (vfree((void *)(addr)))
# endif
/* XXX This isn't really correct. XXX */
# define get_dma_residue(x) (0)
# define FLOPPY0_TYPE 4
# define FLOPPY1_TYPE 0
/* Super paranoid... */
# undef HAVE_DISABLE_HLT
/* Here is where we catch the floppy driver trying to initialize,
* therefore this is where we call the PROM device tree probing
* routine etc . on the Sparc .
*/
# define FDC1 sun_floppy_init()
# define N_FDC 1
# define N_DRIVE 8
/* No 64k boundary crossing problems on the Sparc. */
# define CROSS_64KB(a,s) (0)
/* Routines unique to each controller type on a Sun. */
static void sun_set_dor ( unsigned char value , int fdc_82077 )
{
if ( sparc_cpu_model = = sun4c ) {
unsigned int bits = 0 ;
if ( value & 0x10 )
bits | = AUXIO_FLPY_DSEL ;
if ( ( value & 0x80 ) = = 0 )
bits | = AUXIO_FLPY_EJCT ;
set_auxio ( bits , ( ~ bits ) & ( AUXIO_FLPY_DSEL | AUXIO_FLPY_EJCT ) ) ;
}
if ( fdc_82077 ) {
sun_fdc - > dor_82077 = value ;
}
}
static unsigned char sun_read_dir ( void )
{
if ( sparc_cpu_model = = sun4c )
return ( get_auxio ( ) & AUXIO_FLPY_DCHG ) ? 0x80 : 0 ;
else
return sun_fdc - > dir_82077 ;
}
static unsigned char sun_82072_fd_inb ( int port )
{
udelay ( 5 ) ;
switch ( port & 7 ) {
default :
printk ( " floppy: Asked to read unknown port %d \n " , port ) ;
panic ( " floppy: Port bolixed. " ) ;
case 4 : /* FD_STATUS */
return sun_fdc - > status_82072 & ~ STATUS_DMA ;
case 5 : /* FD_DATA */
return sun_fdc - > data_82072 ;
case 7 : /* FD_DIR */
return sun_read_dir ( ) ;
} ;
panic ( " sun_82072_fd_inb: How did I get here? " ) ;
}
static void sun_82072_fd_outb ( unsigned char value , int port )
{
udelay ( 5 ) ;
switch ( port & 7 ) {
default :
printk ( " floppy: Asked to write to unknown port %d \n " , port ) ;
panic ( " floppy: Port bolixed. " ) ;
case 2 : /* FD_DOR */
sun_set_dor ( value , 0 ) ;
break ;
case 5 : /* FD_DATA */
sun_fdc - > data_82072 = value ;
break ;
case 7 : /* FD_DCR */
sun_fdc - > dcr_82072 = value ;
break ;
case 4 : /* FD_STATUS */
sun_fdc - > status_82072 = value ;
break ;
} ;
return ;
}
static unsigned char sun_82077_fd_inb ( int port )
{
udelay ( 5 ) ;
switch ( port & 7 ) {
default :
printk ( " floppy: Asked to read unknown port %d \n " , port ) ;
panic ( " floppy: Port bolixed. " ) ;
case 0 : /* FD_STATUS_0 */
return sun_fdc - > status1_82077 ;
case 1 : /* FD_STATUS_1 */
return sun_fdc - > status2_82077 ;
case 2 : /* FD_DOR */
return sun_fdc - > dor_82077 ;
case 3 : /* FD_TDR */
return sun_fdc - > tapectl_82077 ;
case 4 : /* FD_STATUS */
return sun_fdc - > status_82077 & ~ STATUS_DMA ;
case 5 : /* FD_DATA */
return sun_fdc - > data_82077 ;
case 7 : /* FD_DIR */
return sun_read_dir ( ) ;
} ;
panic ( " sun_82077_fd_inb: How did I get here? " ) ;
}
static void sun_82077_fd_outb ( unsigned char value , int port )
{
udelay ( 5 ) ;
switch ( port & 7 ) {
default :
printk ( " floppy: Asked to write to unknown port %d \n " , port ) ;
panic ( " floppy: Port bolixed. " ) ;
case 2 : /* FD_DOR */
sun_set_dor ( value , 1 ) ;
break ;
case 5 : /* FD_DATA */
sun_fdc - > data_82077 = value ;
break ;
case 7 : /* FD_DCR */
sun_fdc - > dcr_82077 = value ;
break ;
case 4 : /* FD_STATUS */
sun_fdc - > status_82077 = value ;
break ;
case 3 : /* FD_TDR */
sun_fdc - > tapectl_82077 = value ;
break ;
} ;
return ;
}
/* For pseudo-dma (Sun floppy drives have no real DMA available to
* them so we must eat the data fifo bytes directly ourselves ) we have
* three state variables . doing_pdma tells our inline low - level
* assembly floppy interrupt entry point whether it should sit and eat
* bytes from the fifo or just transfer control up to the higher level
* floppy interrupt c - code . I tried very hard but I could not get the
* pseudo - dma to work in c - code without getting many overruns and
* underruns . If non - zero , doing_pdma encodes the direction of
* the transfer for debugging . 1 = read 2 = write
*/
extern char * pdma_vaddr ;
extern unsigned long pdma_size ;
extern volatile int doing_pdma ;
/* This is software state */
extern char * pdma_base ;
extern unsigned long pdma_areasize ;
/* Common routines to all controller types on the Sparc. */
static inline void virtual_dma_init ( void )
{
/* nothing... */
}
static inline void sun_fd_disable_dma ( void )
{
doing_pdma = 0 ;
if ( pdma_base ) {
mmu_unlockarea ( pdma_base , pdma_areasize ) ;
pdma_base = NULL ;
}
}
static inline void sun_fd_set_dma_mode ( int mode )
{
switch ( mode ) {
case DMA_MODE_READ :
doing_pdma = 1 ;
break ;
case DMA_MODE_WRITE :
doing_pdma = 2 ;
break ;
default :
printk ( " Unknown dma mode %d \n " , mode ) ;
panic ( " floppy: Giving up... " ) ;
}
}
static inline void sun_fd_set_dma_addr ( char * buffer )
{
pdma_vaddr = buffer ;
}
static inline void sun_fd_set_dma_count ( int length )
{
pdma_size = length ;
}
static inline void sun_fd_enable_dma ( void )
{
pdma_vaddr = mmu_lockarea ( pdma_vaddr , pdma_size ) ;
pdma_base = pdma_vaddr ;
pdma_areasize = pdma_size ;
}
/* Our low-level entry point in arch/sparc/kernel/entry.S */
extern int sparc_floppy_request_irq ( int irq , unsigned long flags ,
irq_handler_t irq_handler ) ;
static int sun_fd_request_irq ( void )
{
static int once = 0 ;
int error ;
if ( ! once ) {
once = 1 ;
error = sparc_floppy_request_irq ( FLOPPY_IRQ ,
IRQF_DISABLED ,
floppy_interrupt ) ;
return ( ( error = = 0 ) ? 0 : - 1 ) ;
} else return 0 ;
}
static struct linux_prom_registers fd_regs [ 2 ] ;
static int sun_floppy_init ( void )
{
char state [ 128 ] ;
int tnode , fd_node , num_regs ;
struct resource r ;
use_virtual_dma = 1 ;
FLOPPY_IRQ = 11 ;
/* Forget it if we aren't on a machine that could possibly
* ever have a floppy drive .
*/
if ( ( sparc_cpu_model ! = sun4c & & sparc_cpu_model ! = sun4m ) | |
( ( idprom - > id_machtype = = ( SM_SUN4C | SM_4C_SLC ) ) | |
( idprom - > id_machtype = = ( SM_SUN4C | SM_4C_ELC ) ) ) ) {
/* We certainly don't have a floppy controller. */
goto no_sun_fdc ;
}
/* Well, try to find one. */
tnode = prom_getchild ( prom_root_node ) ;
fd_node = prom_searchsiblings ( tnode , " obio " ) ;
if ( fd_node ! = 0 ) {
tnode = prom_getchild ( fd_node ) ;
fd_node = prom_searchsiblings ( tnode , " SUNW,fdtwo " ) ;
} else {
fd_node = prom_searchsiblings ( tnode , " fd " ) ;
}
if ( fd_node = = 0 ) {
goto no_sun_fdc ;
}
/* The sun4m lets us know if the controller is actually usable. */
if ( sparc_cpu_model = = sun4m & &
prom_getproperty ( fd_node , " status " , state , sizeof ( state ) ) ! = - 1 ) {
if ( ! strcmp ( state , " disabled " ) ) {
goto no_sun_fdc ;
}
}
num_regs = prom_getproperty ( fd_node , " reg " , ( char * ) fd_regs , sizeof ( fd_regs ) ) ;
num_regs = ( num_regs / sizeof ( fd_regs [ 0 ] ) ) ;
prom_apply_obio_ranges ( fd_regs , num_regs ) ;
memset ( & r , 0 , sizeof ( r ) ) ;
r . flags = fd_regs [ 0 ] . which_io ;
r . start = fd_regs [ 0 ] . phys_addr ;
sun_fdc = ( struct sun_flpy_controller * )
2008-08-27 15:05:35 +04:00
of_ioremap ( & r , 0 , fd_regs [ 0 ] . reg_size , " floppy " ) ;
2008-07-18 08:55:51 +04:00
/* Last minute sanity check... */
if ( sun_fdc - > status_82072 = = 0xff ) {
sun_fdc = NULL ;
goto no_sun_fdc ;
}
sun_fdops . fd_inb = sun_82077_fd_inb ;
sun_fdops . fd_outb = sun_82077_fd_outb ;
fdc_status = & sun_fdc - > status_82077 ;
if ( sun_fdc - > dor_82077 = = 0x80 ) {
sun_fdc - > dor_82077 = 0x02 ;
if ( sun_fdc - > dor_82077 = = 0x80 ) {
sun_fdops . fd_inb = sun_82072_fd_inb ;
sun_fdops . fd_outb = sun_82072_fd_outb ;
fdc_status = & sun_fdc - > status_82072 ;
}
}
/* Success... */
allowed_drive_mask = 0x01 ;
return ( int ) sun_fdc ;
no_sun_fdc :
return - 1 ;
}
static int sparc_eject ( void )
{
set_dor ( 0x00 , 0xff , 0x90 ) ;
udelay ( 500 ) ;
set_dor ( 0x00 , 0x6f , 0x00 ) ;
udelay ( 500 ) ;
return 0 ;
}
# define fd_eject(drive) sparc_eject()
# define EXTRA_FLOPPY_PARAMS
2008-08-28 04:01:57 +04:00
static DEFINE_SPINLOCK ( dma_spin_lock ) ;
# define claim_dma_lock() \
( { unsigned long flags ; \
spin_lock_irqsave ( & dma_spin_lock , flags ) ; \
flags ; \
} )
# define release_dma_lock(__flags) \
spin_unlock_irqrestore ( & dma_spin_lock , __flags ) ;
2008-07-18 08:55:51 +04:00
# endif /* !(__ASM_SPARC_FLOPPY_H) */