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/hdreg.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
/*
* PalmChip 3710 IDE Controller UDMA timing structure Definition
*/
struct palm_bk3710_udmatiming {
unsigned int rptime ; /* Ready to pause time */
unsigned int cycletime ; /* Cycle Time */
} ;
# define BK3710_BMICP 0x00
# define BK3710_BMISP 0x02
# define BK3710_BMIDTP 0x04
# define BK3710_BMICS 0x08
# define BK3710_BMISS 0x0A
# define BK3710_BMIDTS 0x0C
# define BK3710_IDETIMP 0x40
# define BK3710_IDETIMS 0x42
# define BK3710_SIDETIM 0x44
# define BK3710_SLEWCTL 0x45
# define BK3710_IDESTATUS 0x47
# define BK3710_UDMACTL 0x48
# define BK3710_UDMATIM 0x4A
# 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
# define BK3710_IORDYTMS 0x7C
2008-07-08 21:27:22 +04:00
static unsigned ideclk_period ; /* in nanoseconds */
2008-02-06 04:57:48 +03:00
static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings [ 6 ] = {
{ 160 , 240 } , /* UDMA Mode 0 */
{ 125 , 160 } , /* UDMA Mode 1 */
{ 100 , 120 } , /* UDMA Mode 2 */
{ 100 , 90 } , /* UDMA Mode 3 */
2008-07-15 23:21:40 +04:00
{ 100 , 60 } , /* UDMA Mode 4 */
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
/* udmatim Register */
val16 = readw ( base + BK3710_UDMATIM ) & ( dev ? 0xFF0F : 0xFFF0 ) ;
val16 | = ( mode < < ( dev ? 4 : 0 ) ) ;
writew ( val16 , base + BK3710_UDMATIM ) ;
/* 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 ;
/* PIO Data Setup */
2008-07-08 21:27:22 +04:00
t0 = DIV_ROUND_UP ( cycletime , ideclk_period ) ;
2008-04-26 19:36:35 +04:00
t2 = DIV_ROUND_UP ( ide_timing_find_mode ( XFER_PIO_0 + mode ) - > active ,
2008-07-08 21:27:22 +04:00
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 ) ;
if ( mate & & mate - > present ) {
u8 mode2 = ide_get_best_pio_mode ( mate , 255 , 4 ) ;
if ( mode2 < mode )
mode = mode2 ;
}
/* TASKFILE Setup */
t = ide_timing_find_mode ( XFER_PIO_0 + mode ) ;
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 {
palm_bk3710_setdmamode ( base , is_slave , drive - > id - > eide_dma_min ,
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 ) ;
mate = ide_get_paired_drive ( drive ) ;
palm_bk3710_setpiomode ( base , mate , is_slave , cycle_time , pio ) ;
}
static void __devinit palm_bk3710_chipinit ( void __iomem * base )
{
/*
* enable the reset_en of ATA controller so that when ata signals
* are brought out , by writing into device config . at that
* time por_n signal should not be ' Z ' and have a stable value .
*/
writel ( 0x0300 , base + BK3710_MISCCTL ) ;
/* wait for some time and deassert the reset of ATA Device. */
mdelay ( 100 ) ;
/* Deassert the Reset */
writel ( 0x0200 , base + BK3710_MISCCTL ) ;
/*
* Program the IDETIMP Register Value based on the following assumptions
*
* ( ATA_IDETIMP_IDEEN , ENABLE ) |
* ( ATA_IDETIMP_SLVTIMEN , DISABLE ) |
* ( ATA_IDETIMP_RDYSMPL , 70 NS ) |
* ( ATA_IDETIMP_RDYRCVRY , 50 NS ) |
* ( ATA_IDETIMP_DMAFTIM1 , PIOCOMP ) |
* ( ATA_IDETIMP_PREPOST1 , DISABLE ) |
* ( ATA_IDETIMP_RDYSEN1 , DISABLE ) |
* ( ATA_IDETIMP_PIOFTIM1 , DISABLE ) |
* ( ATA_IDETIMP_DMAFTIM0 , PIOCOMP ) |
* ( ATA_IDETIMP_PREPOST0 , DISABLE ) |
* ( ATA_IDETIMP_RDYSEN0 , DISABLE ) |
* ( ATA_IDETIMP_PIOFTIM0 , DISABLE )
*/
writew ( 0xB388 , base + BK3710_IDETIMP ) ;
/*
* Configure SIDETIM Register
* ( ATA_SIDETIM_RDYSMPS1 , 120 NS ) |
* ( ATA_SIDETIM_RDYRCYS1 , 120 NS )
*/
writeb ( 0 , base + BK3710_SIDETIM ) ;
/*
* UDMACTL Ultra - ATA DMA Control
* ( ATA_UDMACTL_UDMAP1 , 0 ) |
* ( ATA_UDMACTL_UDMAP0 , 0 )
*
*/
writew ( 0 , base + BK3710_UDMACTL ) ;
/*
* MISCCTL Miscellaneous Conrol Register
* ( ATA_MISCCTL_RSTMODEP , 1 ) |
* ( ATA_MISCCTL_RESETP , 0 ) |
* ( ATA_MISCCTL_TIMORIDE , 1 )
*/
writel ( 0x201 , base + BK3710_MISCCTL ) ;
/*
* 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
static u8 __devinit palm_bk3710_cable_detect ( ide_hwif_t * hwif )
{
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 ;
hwif - > dma_ops = & sff_dma_ops ;
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
static const 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 ,
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 ,
. udma_mask = ATA_UDMA4 , /* (input clk 99MHz) */
. mwdma_mask = ATA_MWDMA2 ,
} ;
2008-02-06 04:57:48 +03:00
static int __devinit palm_bk3710_probe ( struct platform_device * pdev )
{
2008-07-08 21:27:22 +04:00
struct clk * clk ;
2008-02-06 04:57:48 +03:00
struct resource * mem , * irq ;
2008-07-23 21:55:57 +04:00
struct ide_host * host ;
2008-07-08 21:27:22 +04:00
unsigned long base , rate ;
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 ;
2008-07-23 21:55:50 +04:00
hw_regs_t hw , * hws [ ] = { & hw , NULL , NULL , NULL } ;
2008-02-06 04:57:48 +03:00
2008-07-08 21:27:22 +04:00
clk = clk_get ( NULL , " IDECLK " ) ;
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 ) ;
ideclk_period = 1000000000UL / rate ;
2008-02-06 04:57:48 +03:00
/* Register the IDE interface with Linux ATA Interface */
2008-02-11 02:32:12 +03:00
memset ( & hw , 0 , sizeof ( hw ) ) ;
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 ;
}
2008-06-20 22:53:32 +04:00
if ( request_mem_region ( mem - > start , mem - > end - mem - > start + 1 ,
" palm_bk3710 " ) = = NULL ) {
printk ( KERN_ERR " failed to request memory region \n " ) ;
return - EBUSY ;
}
base = IO_ADDRESS ( mem - > start ) ;
2008-02-06 04:57:48 +03:00
/* Configure the Palm Chip controller */
2008-06-20 22:53:32 +04:00
palm_bk3710_chipinit ( ( void __iomem * ) base ) ;
2008-02-06 04:57:48 +03:00
2008-02-11 02:32:12 +03:00
for ( i = 0 ; i < IDE_NR_PORTS - 2 ; i + + )
2008-06-20 22:53:32 +04:00
hw . io_ports_array [ i ] = base + IDE_PALM_ATA_PRI_REG_OFFSET + i ;
hw . io_ports . ctl_addr = base + IDE_PALM_ATA_PRI_CTL_OFFSET ;
2008-02-11 02:32:12 +03:00
hw . irq = irq - > start ;
hw . chipset = ide_palm3710 ;
2008-02-06 04:57:48 +03:00
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
rc = ide_host_add ( & palm_bk3710_port_info , hws , NULL ) ;
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
} ,
. probe = palm_bk3710_probe ,
. remove = NULL ,
} ;
static int __init palm_bk3710_init ( void )
{
return platform_driver_register ( & platform_bk_driver ) ;
}
module_init ( palm_bk3710_init ) ;
MODULE_LICENSE ( " GPL " ) ;