2008-02-06 04:57:48 +03:00
/*
* Palmchip bk3710 IDE controller
*
* Copyright ( C ) 2006 Texas Instruments .
* Copyright ( C ) 2007 MontaVista Software , Inc . , < source @ mvista . com >
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* 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 .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
*/
# include <linux/types.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/ioport.h>
# include <linux/ide.h>
# include <linux/delay.h>
# include <linux/init.h>
# include <linux/clk.h>
# include <linux/platform_device.h>
/* Offset of the primary interface registers */
# define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0
/* Primary Control Offset */
# define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6
# define BK3710_BMICP 0x00
# define BK3710_BMISP 0x02
# define BK3710_BMIDTP 0x04
# define BK3710_IDETIMP 0x40
# define BK3710_IDESTATUS 0x47
# define BK3710_UDMACTL 0x48
# define BK3710_MISCCTL 0x50
# define BK3710_REGSTB 0x54
# define BK3710_REGRCVR 0x58
# define BK3710_DATSTB 0x5C
# define BK3710_DATRCVR 0x60
# define BK3710_DMASTB 0x64
# define BK3710_DMARCVR 0x68
# define BK3710_UDMASTB 0x6C
# define BK3710_UDMATRP 0x70
# define BK3710_UDMAENV 0x74
# define BK3710_IORDYTMP 0x78
2008-07-08 21:27:22 +04:00
static unsigned ideclk_period ; /* in nanoseconds */
2008-02-06 04:57:48 +03:00
2009-04-22 22:33:40 +04:00
struct palm_bk3710_udmatiming {
unsigned int rptime ; /* tRP -- Ready to pause time (nsec) */
unsigned int cycletime ; /* tCYCTYP2/2 -- avg Cycle Time (nsec) */
/* tENV is always a minimum of 20 nsec */
} ;
2008-02-06 04:57:48 +03:00
static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings [ 6 ] = {
2009-04-24 00:53:45 +04:00
{ 160 , 240 / 2 } , /* UDMA Mode 0 */
{ 125 , 160 / 2 } , /* UDMA Mode 1 */
{ 100 , 120 / 2 } , /* UDMA Mode 2 */
{ 100 , 90 / 2 } , /* UDMA Mode 3 */
{ 100 , 60 / 2 } , /* UDMA Mode 4 */
{ 85 , 40 / 2 } , /* UDMA Mode 5 */
2008-02-06 04:57:48 +03:00
} ;
static void palm_bk3710_setudmamode ( void __iomem * base , unsigned int dev ,
unsigned int mode )
{
u8 tenv , trp , t0 ;
u32 val32 ;
u16 val16 ;
/* DMA Data Setup */
2008-04-26 19:36:35 +04:00
t0 = DIV_ROUND_UP ( palm_bk3710_udmatimings [ mode ] . cycletime ,
2008-07-08 21:27:22 +04:00
ideclk_period ) - 1 ;
tenv = DIV_ROUND_UP ( 20 , ideclk_period ) - 1 ;
2008-04-26 19:36:35 +04:00
trp = DIV_ROUND_UP ( palm_bk3710_udmatimings [ mode ] . rptime ,
2008-07-08 21:27:22 +04:00
ideclk_period ) - 1 ;
2008-02-06 04:57:48 +03:00
/* udmastb Ultra DMA Access Strobe Width */
val32 = readl ( base + BK3710_UDMASTB ) & ( 0xFF < < ( dev ? 0 : 8 ) ) ;
val32 | = ( t0 < < ( dev ? 8 : 0 ) ) ;
writel ( val32 , base + BK3710_UDMASTB ) ;
/* udmatrp Ultra DMA Ready to Pause Time */
val32 = readl ( base + BK3710_UDMATRP ) & ( 0xFF < < ( dev ? 0 : 8 ) ) ;
val32 | = ( trp < < ( dev ? 8 : 0 ) ) ;
writel ( val32 , base + BK3710_UDMATRP ) ;
/* udmaenv Ultra DMA envelop Time */
val32 = readl ( base + BK3710_UDMAENV ) & ( 0xFF < < ( dev ? 0 : 8 ) ) ;
val32 | = ( tenv < < ( dev ? 8 : 0 ) ) ;
writel ( val32 , base + BK3710_UDMAENV ) ;
/* Enable UDMA for Device */
val16 = readw ( base + BK3710_UDMACTL ) | ( 1 < < dev ) ;
writew ( val16 , base + BK3710_UDMACTL ) ;
}
static void palm_bk3710_setdmamode ( void __iomem * base , unsigned int dev ,
unsigned short min_cycle ,
unsigned int mode )
{
u8 td , tkw , t0 ;
u32 val32 ;
u16 val16 ;
struct ide_timing * t ;
int cycletime ;
t = ide_timing_find_mode ( mode ) ;
cycletime = max_t ( int , t - > cycle , min_cycle ) ;
/* DMA Data Setup */
2008-07-08 21:27:22 +04:00
t0 = DIV_ROUND_UP ( cycletime , ideclk_period ) ;
td = DIV_ROUND_UP ( t - > active , ideclk_period ) ;
2008-02-06 04:57:48 +03:00
tkw = t0 - td - 1 ;
td - = 1 ;
val32 = readl ( base + BK3710_DMASTB ) & ( 0xFF < < ( dev ? 0 : 8 ) ) ;
val32 | = ( td < < ( dev ? 8 : 0 ) ) ;
writel ( val32 , base + BK3710_DMASTB ) ;
val32 = readl ( base + BK3710_DMARCVR ) & ( 0xFF < < ( dev ? 0 : 8 ) ) ;
val32 | = ( tkw < < ( dev ? 8 : 0 ) ) ;
writel ( val32 , base + BK3710_DMARCVR ) ;
/* Disable UDMA for Device */
val16 = readw ( base + BK3710_UDMACTL ) & ~ ( 1 < < dev ) ;
writew ( val16 , base + BK3710_UDMACTL ) ;
}
static void palm_bk3710_setpiomode ( void __iomem * base , ide_drive_t * mate ,
unsigned int dev , unsigned int cycletime ,
unsigned int mode )
{
u8 t2 , t2i , t0 ;
u32 val32 ;
struct ide_timing * t ;
2009-04-24 00:53:43 +04:00
t = ide_timing_find_mode ( XFER_PIO_0 + mode ) ;
2008-02-06 04:57:48 +03:00
/* PIO Data Setup */
2008-07-08 21:27:22 +04:00
t0 = DIV_ROUND_UP ( cycletime , ideclk_period ) ;
2009-04-24 00:53:43 +04:00
t2 = DIV_ROUND_UP ( t - > active , ideclk_period ) ;
2008-02-06 04:57:48 +03:00
t2i = t0 - t2 - 1 ;
t2 - = 1 ;
val32 = readl ( base + BK3710_DATSTB ) & ( 0xFF < < ( dev ? 0 : 8 ) ) ;
val32 | = ( t2 < < ( dev ? 8 : 0 ) ) ;
writel ( val32 , base + BK3710_DATSTB ) ;
val32 = readl ( base + BK3710_DATRCVR ) & ( 0xFF < < ( dev ? 0 : 8 ) ) ;
val32 | = ( t2i < < ( dev ? 8 : 0 ) ) ;
writel ( val32 , base + BK3710_DATRCVR ) ;
2008-10-11 00:39:26 +04:00
if ( mate ) {
2008-02-06 04:57:48 +03:00
u8 mode2 = ide_get_best_pio_mode ( mate , 255 , 4 ) ;
if ( mode2 < mode )
mode = mode2 ;
}
/* TASKFILE Setup */
2008-07-08 21:27:22 +04:00
t0 = DIV_ROUND_UP ( t - > cyc8b , ideclk_period ) ;
t2 = DIV_ROUND_UP ( t - > act8b , ideclk_period ) ;
2008-02-06 04:57:48 +03:00
t2i = t0 - t2 - 1 ;
t2 - = 1 ;
val32 = readl ( base + BK3710_REGSTB ) & ( 0xFF < < ( dev ? 0 : 8 ) ) ;
val32 | = ( t2 < < ( dev ? 8 : 0 ) ) ;
writel ( val32 , base + BK3710_REGSTB ) ;
val32 = readl ( base + BK3710_REGRCVR ) & ( 0xFF < < ( dev ? 0 : 8 ) ) ;
val32 | = ( t2i < < ( dev ? 8 : 0 ) ) ;
writel ( val32 , base + BK3710_REGRCVR ) ;
}
static void palm_bk3710_set_dma_mode ( ide_drive_t * drive , u8 xferspeed )
{
int is_slave = drive - > dn & 1 ;
void __iomem * base = ( void * ) drive - > hwif - > dma_base ;
if ( xferspeed > = XFER_UDMA_0 ) {
palm_bk3710_setudmamode ( base , is_slave ,
xferspeed - XFER_UDMA_0 ) ;
} else {
2008-10-11 00:39:19 +04:00
palm_bk3710_setdmamode ( base , is_slave ,
drive - > id [ ATA_ID_EIDE_DMA_MIN ] ,
2008-02-06 04:57:48 +03:00
xferspeed ) ;
}
}
static void palm_bk3710_set_pio_mode ( ide_drive_t * drive , u8 pio )
{
unsigned int cycle_time ;
int is_slave = drive - > dn & 1 ;
ide_drive_t * mate ;
void __iomem * base = ( void * ) drive - > hwif - > dma_base ;
/*
* Obtain the drive PIO data for tuning the Palm Chip registers
*/
cycle_time = ide_pio_cycle_time ( drive , pio ) ;
2008-10-11 00:39:26 +04:00
mate = ide_get_pair_dev ( drive ) ;
2008-02-06 04:57:48 +03:00
palm_bk3710_setpiomode ( base , mate , is_slave , cycle_time , pio ) ;
}
static void __devinit palm_bk3710_chipinit ( void __iomem * base )
{
/*
2009-04-24 00:53:43 +04:00
* REVISIT : the ATA reset signal needs to be managed through a
* GPIO , which means it should come from platform_data . Until
* we get and use such information , we have to trust that things
* have been reset before we get here .
2008-02-06 04:57:48 +03:00
*/
/*
* Program the IDETIMP Register Value based on the following assumptions
*
* ( ATA_IDETIMP_IDEEN , ENABLE ) |
* ( ATA_IDETIMP_PREPOST1 , DISABLE ) |
* ( ATA_IDETIMP_PREPOST0 , DISABLE ) |
2009-04-24 00:53:43 +04:00
*
* DM6446 silicon rev 2.1 and earlier have no observed net benefit
* from enabling prefetch / postwrite .
2008-02-06 04:57:48 +03:00
*/
2009-04-24 00:53:43 +04:00
writew ( BIT ( 15 ) , base + BK3710_IDETIMP ) ;
2008-02-06 04:57:48 +03:00
/*
* UDMACTL Ultra - ATA DMA Control
* ( ATA_UDMACTL_UDMAP1 , 0 ) |
* ( ATA_UDMACTL_UDMAP0 , 0 )
*
*/
writew ( 0 , base + BK3710_UDMACTL ) ;
/*
* MISCCTL Miscellaneous Conrol Register
2009-04-24 00:53:43 +04:00
* ( ATA_MISCCTL_HWNHLD1P , 1 cycle )
* ( ATA_MISCCTL_HWNHLD0P , 1 cycle )
2008-02-06 04:57:48 +03:00
* ( ATA_MISCCTL_TIMORIDE , 1 )
*/
2009-04-24 00:53:43 +04:00
writel ( 0x001 , base + BK3710_MISCCTL ) ;
2008-02-06 04:57:48 +03:00
/*
* IORDYTMP IORDY Timer for Primary Register
* ( ATA_IORDYTMP_IORDYTMP , 0xffff )
*/
writel ( 0xFFFF , base + BK3710_IORDYTMP ) ;
/*
* Configure BMISP Register
* ( ATA_BMISP_DMAEN1 , DISABLE ) |
* ( ATA_BMISP_DMAEN0 , DISABLE ) |
* ( ATA_BMISP_IORDYINT , CLEAR ) |
* ( ATA_BMISP_INTRSTAT , CLEAR ) |
* ( ATA_BMISP_DMAERROR , CLEAR )
*/
writew ( 0 , base + BK3710_BMISP ) ;
palm_bk3710_setpiomode ( base , NULL , 0 , 600 , 0 ) ;
palm_bk3710_setpiomode ( base , NULL , 1 , 600 , 0 ) ;
}
2008-02-11 02:32:13 +03:00
2008-08-05 20:17:04 +04:00
static u8 palm_bk3710_cable_detect ( ide_hwif_t * hwif )
2008-02-11 02:32:13 +03:00
{
return ATA_CBL_PATA80 ;
}
2008-04-27 00:25:23 +04:00
static int __devinit palm_bk3710_init_dma ( ide_hwif_t * hwif ,
const struct ide_port_info * d )
{
printk ( KERN_INFO " %s: MMIO-DMA \n " , hwif - > name ) ;
if ( ide_allocate_dma_engine ( hwif ) )
return - 1 ;
2008-07-23 21:55:51 +04:00
hwif - > dma_base = hwif - > io_ports . data_addr - IDE_PALM_ATA_PRI_REG_OFFSET ;
2008-04-27 00:25:23 +04:00
return 0 ;
}
2008-04-27 00:25:14 +04:00
static const struct ide_port_ops palm_bk3710_ports_ops = {
. set_pio_mode = palm_bk3710_set_pio_mode ,
. set_dma_mode = palm_bk3710_set_dma_mode ,
. cable_detect = palm_bk3710_cable_detect ,
} ;
2008-02-11 02:32:13 +03:00
2008-07-25 00:53:34 +04:00
static struct ide_port_info __devinitdata palm_bk3710_port_info = {
2008-04-27 00:25:23 +04:00
. init_dma = palm_bk3710_init_dma ,
2008-04-27 00:25:14 +04:00
. port_ops = & palm_bk3710_ports_ops ,
2009-01-06 19:21:01 +03:00
. dma_ops = & sff_dma_ops ,
2008-04-29 01:44:37 +04:00
. host_flags = IDE_HFLAG_MMIO ,
2008-02-11 02:32:13 +03:00
. pio_mask = ATA_PIO4 ,
. mwdma_mask = ATA_MWDMA2 ,
2009-05-17 21:12:22 +04:00
. chipset = ide_palm3710 ,
2008-02-11 02:32:13 +03:00
} ;
2008-09-02 22:18:47 +04:00
static int __init palm_bk3710_probe ( struct platform_device * pdev )
2008-02-06 04:57:48 +03:00
{
2008-07-08 21:27:22 +04:00
struct clk * clk ;
2008-02-06 04:57:48 +03:00
struct resource * mem , * irq ;
2009-01-19 15:46:57 +03:00
void __iomem * base ;
2009-01-30 22:59:27 +03:00
unsigned long rate , mem_size ;
ide: add ide_host_add() helper
Add ide_host_add() helper which does ide_host_alloc()+ide_host_register(),
then convert ide_setup_pci_device[s](), ide_legacy_device_add() and some
host drivers to use it.
While at it:
* Fix ide_setup_pci_device[s](), ide_arm.c, gayle.c, ide-4drives.c,
macide.c, q40ide.c, cmd640.c and cs5520.c to return correct error value.
* -ENOENT -> -ENOMEM in rapide.c, ide-h8300.c, ide-generic.c, au1xxx-ide.c
and pmac.c
* -ENODEV -> -ENOMEM in palm_bk3710.c, ide_platform.c and delkin_cb.c
* -1 -> -ENOMEM in ide-pnp.c
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-07-23 21:55:57 +04:00
int i , rc ;
2009-05-17 21:12:25 +04:00
struct ide_hw hw , * hws [ ] = { & hw } ;
2008-02-06 04:57:48 +03:00
2008-07-25 00:53:34 +04:00
clk = clk_get ( & pdev - > dev , " IDECLK " ) ;
2008-07-08 21:27:22 +04:00
if ( IS_ERR ( clk ) )
2008-02-06 04:57:48 +03:00
return - ENODEV ;
2008-07-08 21:27:22 +04:00
clk_enable ( clk ) ;
rate = clk_get_rate ( clk ) ;
2009-04-24 00:53:43 +04:00
/* NOTE: round *down* to meet minimum timings; we count in clocks */
ideclk_period = 1000000000UL / rate ;
2008-02-06 04:57:48 +03:00
mem = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( mem = = NULL ) {
printk ( KERN_ERR " failed to get memory region resource \n " ) ;
return - ENODEV ;
}
2008-06-20 22:53:32 +04:00
2008-02-06 04:57:48 +03:00
irq = platform_get_resource ( pdev , IORESOURCE_IRQ , 0 ) ;
if ( irq = = NULL ) {
printk ( KERN_ERR " failed to get IRQ resource \n " ) ;
return - ENODEV ;
}
2009-01-30 22:59:27 +03:00
mem_size = mem - > end - mem - > start + 1 ;
if ( request_mem_region ( mem - > start , mem_size , " palm_bk3710 " ) = = NULL ) {
2008-06-20 22:53:32 +04:00
printk ( KERN_ERR " failed to request memory region \n " ) ;
return - EBUSY ;
}
2009-01-30 22:59:27 +03:00
base = ioremap ( mem - > start , mem_size ) ;
if ( ! base ) {
printk ( KERN_ERR " failed to map IO memory \n " ) ;
release_mem_region ( mem - > start , mem_size ) ;
return - ENOMEM ;
}
2008-02-06 04:57:48 +03:00
/* Configure the Palm Chip controller */
2009-01-19 15:46:57 +03:00
palm_bk3710_chipinit ( base ) ;
2008-02-06 04:57:48 +03:00
2009-04-24 00:53:43 +04:00
memset ( & hw , 0 , sizeof ( hw ) ) ;
2008-02-11 02:32:12 +03:00
for ( i = 0 ; i < IDE_NR_PORTS - 2 ; i + + )
2009-01-19 15:46:57 +03:00
hw . io_ports_array [ i ] = ( unsigned long )
( base + IDE_PALM_ATA_PRI_REG_OFFSET + i ) ;
hw . io_ports . ctl_addr = ( unsigned long )
( base + IDE_PALM_ATA_PRI_CTL_OFFSET ) ;
2008-02-11 02:32:12 +03:00
hw . irq = irq - > start ;
2008-09-02 22:18:47 +04:00
hw . dev = & pdev - > dev ;
2008-02-06 04:57:48 +03:00
2008-07-25 00:53:34 +04:00
palm_bk3710_port_info . udma_mask = rate < 100000000 ? ATA_UDMA4 :
ATA_UDMA5 ;
2009-04-24 00:53:43 +04:00
/* Register the IDE interface with Linux */
2009-05-17 21:12:24 +04:00
rc = ide_host_add ( & palm_bk3710_port_info , hws , 1 , NULL ) ;
ide: add ide_host_add() helper
Add ide_host_add() helper which does ide_host_alloc()+ide_host_register(),
then convert ide_setup_pci_device[s](), ide_legacy_device_add() and some
host drivers to use it.
While at it:
* Fix ide_setup_pci_device[s](), ide_arm.c, gayle.c, ide-4drives.c,
macide.c, q40ide.c, cmd640.c and cs5520.c to return correct error value.
* -ENOENT -> -ENOMEM in rapide.c, ide-h8300.c, ide-generic.c, au1xxx-ide.c
and pmac.c
* -ENODEV -> -ENOMEM in palm_bk3710.c, ide_platform.c and delkin_cb.c
* -1 -> -ENOMEM in ide-pnp.c
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-07-23 21:55:57 +04:00
if ( rc )
2008-02-11 02:32:12 +03:00
goto out ;
2008-02-06 04:57:48 +03:00
return 0 ;
2008-02-11 02:32:12 +03:00
out :
printk ( KERN_WARNING " Palm Chip BK3710 IDE Register Fail \n " ) ;
ide: add ide_host_add() helper
Add ide_host_add() helper which does ide_host_alloc()+ide_host_register(),
then convert ide_setup_pci_device[s](), ide_legacy_device_add() and some
host drivers to use it.
While at it:
* Fix ide_setup_pci_device[s](), ide_arm.c, gayle.c, ide-4drives.c,
macide.c, q40ide.c, cmd640.c and cs5520.c to return correct error value.
* -ENOENT -> -ENOMEM in rapide.c, ide-h8300.c, ide-generic.c, au1xxx-ide.c
and pmac.c
* -ENODEV -> -ENOMEM in palm_bk3710.c, ide_platform.c and delkin_cb.c
* -1 -> -ENOMEM in ide-pnp.c
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
2008-07-23 21:55:57 +04:00
return rc ;
2008-02-06 04:57:48 +03:00
}
2008-04-19 00:41:57 +04:00
/* work with hotplug and coldplug */
MODULE_ALIAS ( " platform:palm_bk3710 " ) ;
2008-02-06 04:57:48 +03:00
static struct platform_driver platform_bk_driver = {
. driver = {
. name = " palm_bk3710 " ,
2008-04-19 00:41:57 +04:00
. owner = THIS_MODULE ,
2008-02-06 04:57:48 +03:00
} ,
} ;
static int __init palm_bk3710_init ( void )
{
2008-09-02 22:18:47 +04:00
return platform_driver_probe ( & platform_bk_driver , palm_bk3710_probe ) ;
2008-02-06 04:57:48 +03:00
}
module_init ( palm_bk3710_init ) ;
MODULE_LICENSE ( " GPL " ) ;