2007-05-22 12:13:19 +04:00
/* jazz_esp.c: ESP front-end for MIPS JAZZ systems.
2005-04-17 02:20:36 +04:00
*
2007-05-22 12:13:19 +04:00
* Copyright ( C ) 2007 Thomas Bogend <EFBFBD> rfer ( tsbogend @ alpha . frankende )
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
# include <linux/types.h>
2007-05-22 12:13:19 +04:00
# include <linux/module.h>
# include <linux/init.h>
# include <linux/interrupt.h>
# include <linux/platform_device.h>
# include <linux/dma-mapping.h>
2005-04-17 02:20:36 +04:00
# include <asm/irq.h>
2007-05-22 12:13:19 +04:00
# include <asm/io.h>
# include <asm/dma.h>
2005-04-17 02:20:36 +04:00
# include <asm/jazz.h>
# include <asm/jazzdma.h>
2007-05-22 12:13:19 +04:00
# include <scsi/scsi_host.h>
2005-04-17 02:20:36 +04:00
2007-05-22 12:13:19 +04:00
# include "esp_scsi.h"
2005-04-17 02:20:36 +04:00
2007-05-22 12:13:19 +04:00
# define DRV_MODULE_NAME "jazz_esp"
# define PFX DRV_MODULE_NAME ": "
# define DRV_VERSION "1.000"
# define DRV_MODULE_RELDATE "May 19, 2007"
2005-04-17 02:20:36 +04:00
2007-05-22 12:13:19 +04:00
static void jazz_esp_write8 ( struct esp * esp , u8 val , unsigned long reg )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
* ( volatile u8 * ) ( esp - > regs + reg ) = val ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static u8 jazz_esp_read8 ( struct esp * esp , unsigned long reg )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
return * ( volatile u8 * ) ( esp - > regs + reg ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static dma_addr_t jazz_esp_map_single ( struct esp * esp , void * buf ,
size_t sz , int dir )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
return dma_map_single ( esp - > dev , buf , sz , dir ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static int jazz_esp_map_sg ( struct esp * esp , struct scatterlist * sg ,
int num_sg , int dir )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
return dma_map_sg ( esp - > dev , sg , num_sg , dir ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static void jazz_esp_unmap_single ( struct esp * esp , dma_addr_t addr ,
size_t sz , int dir )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
dma_unmap_single ( esp - > dev , addr , sz , dir ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static void jazz_esp_unmap_sg ( struct esp * esp , struct scatterlist * sg ,
int num_sg , int dir )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
dma_unmap_sg ( esp - > dev , sg , num_sg , dir ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static int jazz_esp_irq_pending ( struct esp * esp )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
if ( jazz_esp_read8 ( esp , ESP_STATUS ) & ESP_STAT_INTR )
return 1 ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static void jazz_esp_reset_dma ( struct esp * esp )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
vdma_disable ( ( int ) esp - > dma_regs ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static void jazz_esp_dma_drain ( struct esp * esp )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
/* nothing to do */
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static void jazz_esp_dma_invalidate ( struct esp * esp )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
vdma_disable ( ( int ) esp - > dma_regs ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static void jazz_esp_send_dma_cmd ( struct esp * esp , u32 addr , u32 esp_count ,
u32 dma_count , int write , u8 cmd )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
BUG_ON ( ! ( cmd & ESP_CMD_DMA ) ) ;
jazz_esp_write8 ( esp , ( esp_count > > 0 ) & 0xff , ESP_TCLOW ) ;
jazz_esp_write8 ( esp , ( esp_count > > 8 ) & 0xff , ESP_TCMED ) ;
vdma_disable ( ( int ) esp - > dma_regs ) ;
if ( write )
vdma_set_mode ( ( int ) esp - > dma_regs , DMA_MODE_READ ) ;
else
vdma_set_mode ( ( int ) esp - > dma_regs , DMA_MODE_WRITE ) ;
vdma_set_addr ( ( int ) esp - > dma_regs , addr ) ;
vdma_set_count ( ( int ) esp - > dma_regs , dma_count ) ;
vdma_enable ( ( int ) esp - > dma_regs ) ;
scsi_esp_cmd ( esp , cmd ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static int jazz_esp_dma_error ( struct esp * esp )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
u32 enable = vdma_get_enable ( ( int ) esp - > dma_regs ) ;
if ( enable & ( R4030_MEM_INTR | R4030_ADDR_INTR ) )
return 1 ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static const struct esp_driver_ops jazz_esp_ops = {
. esp_write8 = jazz_esp_write8 ,
. esp_read8 = jazz_esp_read8 ,
. map_single = jazz_esp_map_single ,
. map_sg = jazz_esp_map_sg ,
. unmap_single = jazz_esp_unmap_single ,
. unmap_sg = jazz_esp_unmap_sg ,
. irq_pending = jazz_esp_irq_pending ,
. reset_dma = jazz_esp_reset_dma ,
. dma_drain = jazz_esp_dma_drain ,
. dma_invalidate = jazz_esp_dma_invalidate ,
. send_dma_cmd = jazz_esp_send_dma_cmd ,
. dma_error = jazz_esp_dma_error ,
} ;
static int __devinit esp_jazz_probe ( struct platform_device * dev )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
struct scsi_host_template * tpnt = & scsi_esp_template ;
struct Scsi_Host * host ;
struct esp * esp ;
struct resource * res ;
int err ;
host = scsi_host_alloc ( tpnt , sizeof ( struct esp ) ) ;
err = - ENOMEM ;
if ( ! host )
goto fail ;
host - > max_id = 8 ;
2007-05-31 22:12:32 +04:00
esp = shost_priv ( host ) ;
2007-05-22 12:13:19 +04:00
esp - > host = host ;
esp - > dev = dev ;
esp - > ops = & jazz_esp_ops ;
res = platform_get_resource ( dev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
goto fail_unlink ;
esp - > regs = ( void __iomem * ) res - > start ;
if ( ! esp - > regs )
goto fail_unlink ;
res = platform_get_resource ( dev , IORESOURCE_MEM , 1 ) ;
if ( ! res )
goto fail_unlink ;
esp - > dma_regs = ( void __iomem * ) res - > start ;
esp - > command_block = dma_alloc_coherent ( esp - > dev , 16 ,
& esp - > command_block_dma ,
GFP_KERNEL ) ;
if ( ! esp - > command_block )
goto fail_unmap_regs ;
host - > irq = platform_get_irq ( dev , 0 ) ;
err = request_irq ( host - > irq , scsi_esp_intr , IRQF_SHARED , " ESP " , esp ) ;
if ( err < 0 )
goto fail_unmap_command_block ;
esp - > scsi_id = 7 ;
esp - > host - > this_id = esp - > scsi_id ;
esp - > scsi_id_mask = ( 1 < < esp - > scsi_id ) ;
esp - > cfreq = 40000000 ;
dev_set_drvdata ( & dev - > dev , esp ) ;
err = scsi_esp_register ( esp , & dev - > dev ) ;
if ( err )
goto fail_free_irq ;
return 0 ;
fail_free_irq :
free_irq ( host - > irq , esp ) ;
fail_unmap_command_block :
dma_free_coherent ( esp - > dev , 16 ,
esp - > command_block ,
esp - > command_block_dma ) ;
fail_unmap_regs :
fail_unlink :
scsi_host_put ( host ) ;
fail :
return err ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static int __devexit esp_jazz_remove ( struct platform_device * dev )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
struct esp * esp = dev_get_drvdata ( & dev - > dev ) ;
unsigned int irq = esp - > host - > irq ;
scsi_esp_unregister ( esp ) ;
free_irq ( irq , esp ) ;
dma_free_coherent ( esp - > dev , 16 ,
esp - > command_block ,
esp - > command_block_dma ) ;
scsi_host_put ( esp - > host ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2008-04-19 00:57:19 +04:00
/* work with hotplug and coldplug */
MODULE_ALIAS ( " platform:jazz_esp " ) ;
2007-05-22 12:13:19 +04:00
static struct platform_driver esp_jazz_driver = {
. probe = esp_jazz_probe ,
. remove = __devexit_p ( esp_jazz_remove ) ,
. driver = {
. name = " jazz_esp " ,
2008-04-19 00:57:19 +04:00
. owner = THIS_MODULE ,
2007-05-22 12:13:19 +04:00
} ,
} ;
2005-04-17 02:20:36 +04:00
2007-05-22 12:13:19 +04:00
static int __init jazz_esp_init ( void )
2005-04-17 02:20:36 +04:00
{
2007-05-22 12:13:19 +04:00
return platform_driver_register ( & esp_jazz_driver ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
static void __exit jazz_esp_exit ( void )
{
platform_driver_unregister ( & esp_jazz_driver ) ;
2005-04-17 02:20:36 +04:00
}
2007-05-22 12:13:19 +04:00
MODULE_DESCRIPTION ( " JAZZ ESP SCSI driver " ) ;
MODULE_AUTHOR ( " Thomas Bogendoerfer (tsbogend@alpha.franken.de) " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_VERSION ( DRV_VERSION ) ;
module_init ( jazz_esp_init ) ;
module_exit ( jazz_esp_exit ) ;