From mboxrd@z Thu Jan 1 00:00:00 1970 From: Sergey Matyukevich Subject: Re: [PATCH] PATA driver for CF interface on AT91SAM9260 SoC Date: Sat, 20 Jun 2009 16:54:39 +0400 Message-ID: <20090620165439.6314f9ef@realm> References: <1245181151-7040-1-git-send-email-geomatsi@gmail.com> <20090618002004.54701b40@realm> <20090617235351.1cb05c97@lxorguk.ukuu.org.uk> <20090618222401.462b2d44@realm> <20090618193720.26830bc8@lxorguk.ukuu.org.uk> <20090619082740.6986544a@realm> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: QUOTED-PRINTABLE Return-path: Received: from fg-out-1718.google.com ([72.14.220.154]:9579 "EHLO fg-out-1718.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752180AbZFTNHz convert rfc822-to-8bit (ORCPT ); Sat, 20 Jun 2009 09:07:55 -0400 Received: by fg-out-1718.google.com with SMTP id 16so741789fgg.17 for ; Sat, 20 Jun 2009 06:07:56 -0700 (PDT) In-Reply-To: <20090619082740.6986544a@realm> Sender: linux-ide-owner@vger.kernel.org List-Id: linux-ide@vger.kernel.org To: Sergey Matyukevich Cc: Alan Cox , linux-ide@vger.kernel.org, Andrew Victor , Sergey Lapin , Andrew Victor On Fri, 19 Jun 2009 08:27:40 +0400 Sergey Matyukevich wrote: > On Thu, 18 Jun 2009 19:37:20 +0100 > Alan Cox wrote: >=20 > > > Concerning the first point, this module parameter is used in > > > driver probing function:=20 > > > ap->pio_mask =3D pio_mask; > > >=20 > > > I would suggest to keep pio_mask as a module parameter, since it > > > might be useful to modify it in order to =D1=81ut down PIO speed,= e.g. > > > for testing purposes.=20 > >=20 > > Libata already has general support for that. (Arguably we should > > take it out of the pata_legacy driver in the same way) >=20 >=20 > Patch update: module param for pio_mask removed. >=20 >=20 Hello, Is there any chance for this driver to be accepted during current merge window ? Thanks,=20 Sergey > This patch provides PATA driver for CompactFlash interface in True ID= E > mode on AT91SAM9260 SoC. >=20 > Signed-off-by: Sergey Matyukevich > --- > drivers/ata/Kconfig | 8 + > drivers/ata/Makefile | 1 + > drivers/ata/pata_at91.c | 361 > +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 370 > insertions(+), 0 deletions(-) create mode 100644 > drivers/ata/pata_at91.c >=20 > diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig > index 2aa1908..b17c57f 100644 > --- a/drivers/ata/Kconfig > +++ b/drivers/ata/Kconfig > @@ -679,6 +679,14 @@ config PATA_PLATFORM > =20 > If unsure, say N. > =20 > +config PATA_AT91 > + tristate "PATA support for AT91SAM9260" > + depends on ARM && ARCH_AT91 > + help > + This option enables support for IDE devices on the Atmel > AT91SAM9260 SoC. + > + If unsure, say N. > + > config PATA_OF_PLATFORM > tristate "OpenFirmware platform device PATA support" > depends on PATA_PLATFORM && PPC_OF > diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile > index 1558059..38906f9 100644 > --- a/drivers/ata/Makefile > +++ b/drivers/ata/Makefile > @@ -72,6 +72,7 @@ obj-$(CONFIG_PATA_SCH) +=3D pata_sch.o > obj-$(CONFIG_PATA_BF54X) +=3D pata_bf54x.o > obj-$(CONFIG_PATA_OCTEON_CF) +=3D pata_octeon_cf.o > obj-$(CONFIG_PATA_PLATFORM) +=3D pata_platform.o > +obj-$(CONFIG_PATA_AT91) +=3D pata_at91.o > obj-$(CONFIG_PATA_OF_PLATFORM) +=3D pata_of_platform.o > obj-$(CONFIG_PATA_ICSIDE) +=3D pata_icside.o > # Should be last but two libata driver > diff --git a/drivers/ata/pata_at91.c b/drivers/ata/pata_at91.c > new file mode 100644 > index 0000000..4b27617 > --- /dev/null > +++ b/drivers/ata/pata_at91.c > @@ -0,0 +1,361 @@ > +/* > + * PATA driver for AT91SAM9260 Static Memory Controller > + * with CompactFlash interface in True IDE mode > + * > + * Copyright (C) 2009 Matyukevich Sergey > + * > + * Based on: > + * * generic platform driver by Paul Mundt: > drivers/ata/pata_platform.c > + * * pata_at32 driver by Kristoffer Nyborg Gregertsen > + * * at91_ide driver by Stanislaw Gruszka > + * > + * This program is free software; you can redistribute it and/or > modify it > + * under the terms of the GNU General Public License version 2 > + * as published by the Free Software Foundation. > + * > + */ > + > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > +#include > + > +#include > +#include > +#include > +#include > +#include > + > + > +#define DRV_NAME "pata_at91" > +#define DRV_VERSION "0.1" > + > +#define CF_IDE_OFFSET 0x00c00000 > +#define CF_ALT_IDE_OFFSET 0x00e00000 > +#define CF_IDE_RES_SIZE 0x08 > + > +struct at91_ide_info { > + unsigned long mode; > + unsigned int cs; > + > + void __iomem *ide_addr; > + void __iomem *alt_addr; > +}; > + > +const struct ata_timing initial_timing =3D > + {XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0}; > + > +static unsigned int calc_mck_cycles(unsigned int ns, unsigned int > mck_hz) +{ > + unsigned long mul; > + > + /* > + * cycles =3D x [nsec] * f [Hz] / 10^9 [ns in sec] =3D > + * x * (f / 1_000_000_000) =3D > + * x * ((f * 65536) / 1_000_000_000) / 65536 =3D > + * x * (((f / 10_000) * 65536) / 100_000) / 65536 =3D > + */ > + > + mul =3D (mck_hz / 10000) << 16; > + mul /=3D 100000; > + > + return (ns * mul + 65536) >> 16; /* rounding */ > +} > + > +static void set_smc_mode(struct at91_ide_info *info) > +{ > + at91_sys_write(AT91_SMC_MODE(info->cs), info->mode); > + return; > +} > + > +static void set_smc_timing(struct device *dev, > + struct at91_ide_info *info, const struct ata_timing > *ata) +{ > + int read_cycle, write_cycle, active, recover; > + int nrd_setup, nrd_pulse, nrd_recover; > + int nwe_setup, nwe_pulse; > + > + int ncs_write_setup, ncs_write_pulse; > + int ncs_read_setup, ncs_read_pulse; > + > + unsigned int mck_hz; > + struct clk *mck; > + > + read_cycle =3D ata->cyc8b; > + nrd_setup =3D ata->setup; > + nrd_pulse =3D ata->act8b; > + nrd_recover =3D ata->rec8b; > + > + mck =3D clk_get(NULL, "mck"); > + BUG_ON(IS_ERR(mck)); > + mck_hz =3D clk_get_rate(mck); > + > + read_cycle =3D calc_mck_cycles(read_cycle, mck_hz); > + nrd_setup =3D calc_mck_cycles(nrd_setup, mck_hz); > + nrd_pulse =3D calc_mck_cycles(nrd_pulse, mck_hz); > + nrd_recover =3D calc_mck_cycles(nrd_recover, mck_hz); > + > + clk_put(mck); > + > + active =3D nrd_setup + nrd_pulse; > + recover =3D read_cycle - active; > + > + /* Need at least two cycles recovery */ > + if (recover < 2) > + read_cycle =3D active + 2; > + > + /* (CS0, CS1, DIR, OE) <=3D (CFCE1, CFCE2, CFRNW, NCSX) > timings */ > + ncs_read_setup =3D 1; > + ncs_read_pulse =3D read_cycle - 2; > + > + /* Write timings same as read timings */ > + write_cycle =3D read_cycle; > + nwe_setup =3D nrd_setup; > + nwe_pulse =3D nrd_pulse; > + ncs_write_setup =3D ncs_read_setup; > + ncs_write_pulse =3D ncs_read_pulse; > + > + dev_dbg(dev, "ATA timings: nrd_setup =3D %d nrd_pulse =3D %d > nrd_cycle =3D %d\n", > + nrd_setup, nrd_pulse, read_cycle); > + dev_dbg(dev, "ATA timings: nwe_setup =3D %d nwe_pulse =3D %d > nwe_cycle =3D %d\n", > + nwe_setup, nwe_pulse, write_cycle); > + dev_dbg(dev, "ATA timings: ncs_read_setup =3D %d > ncs_read_pulse =3D %d\n", > + ncs_read_setup, ncs_read_pulse); > + dev_dbg(dev, "ATA timings: ncs_write_setup =3D %d > ncs_write_pulse =3D %d\n", > + ncs_write_setup, ncs_write_pulse); > + > + at91_sys_write(AT91_SMC_SETUP(info->cs), > + AT91_SMC_NWESETUP_(nwe_setup) | > + AT91_SMC_NRDSETUP_(nrd_setup) | > + AT91_SMC_NCS_WRSETUP_(ncs_write_setup) | > + AT91_SMC_NCS_RDSETUP_(ncs_read_setup)); > + > + at91_sys_write(AT91_SMC_PULSE(info->cs), > + AT91_SMC_NWEPULSE_(nwe_pulse) | > + AT91_SMC_NRDPULSE_(nrd_pulse) | > + AT91_SMC_NCS_WRPULSE_(ncs_write_pulse) | > + AT91_SMC_NCS_RDPULSE_(ncs_read_pulse)); > + > + at91_sys_write(AT91_SMC_CYCLE(info->cs), > + AT91_SMC_NWECYCLE_(write_cycle) | > + AT91_SMC_NRDCYCLE_(read_cycle)); > + > + return; > +} > + > +static void pata_at91_set_piomode(struct ata_port *ap, struct > ata_device *adev) +{ > + struct at91_ide_info *info =3D ap->host->private_data; > + struct ata_timing timing; > + int ret; > + > + /* Compute ATA timing and set it to SMC */ > + ret =3D ata_timing_compute(adev, adev->pio_mode, &timing, > 1000, 0); > + if (ret) { > + dev_warn(ap->dev, "Failed to compute ATA timing %d, \ > + set PIO_0 timing\n", ret); > + set_smc_timing(ap->dev, info, &initial_timing); > + } else { > + set_smc_timing(ap->dev, info, &timing); > + } > + > + /* Setup SMC mode */ > + set_smc_mode(info); > + > + return; > +} > + > +static unsigned int pata_at91_data_xfer_noirq(struct ata_device *dev= , > + unsigned char *buf, unsigned int buflen, int rw) > +{ > + struct at91_ide_info *info =3D > dev->link->ap->host->private_data; > + unsigned int consumed; > + unsigned long flags; > + unsigned int mode; > + > + local_irq_save(flags); > + mode =3D at91_sys_read(AT91_SMC_MODE(info->cs)); > + > + /* set 16bit mode before writing data */ > + at91_sys_write(AT91_SMC_MODE(info->cs), > + (mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_16); > + > + consumed =3D ata_sff_data_xfer(dev, buf, buflen, rw); > + > + /* restore 8bit mode after data is written */ > + at91_sys_write(AT91_SMC_MODE(info->cs), > + (mode & ~AT91_SMC_DBW) | AT91_SMC_DBW_8); > + > + local_irq_restore(flags); > + return consumed; > +} > + > +static struct scsi_host_template pata_at91_sht =3D { > + ATA_PIO_SHT(DRV_NAME), > +}; > + > +static struct ata_port_operations pata_at91_port_ops =3D { > + .inherits =3D &ata_sff_port_ops, > + > + .sff_data_xfer =3D pata_at91_data_xfer_noirq, > + .set_piomode =3D pata_at91_set_piomode, > + .cable_detect =3D ata_cable_40wire, > + .port_start =3D ATA_OP_NULL, > +}; > + > +static int __devinit pata_at91_probe(struct platform_device *pdev) > +{ > + struct at91_cf_data *board =3D pdev->dev.platform_data; > + struct device *dev =3D &pdev->dev; > + struct at91_ide_info *info; > + struct resource *mem_res; > + struct ata_host *host; > + struct ata_port *ap; > + int irq_flags =3D 0; > + int irq =3D 0; > + int ret; > + > + /* get platform resources: IO/CTL memories and irq/rst pins > */ + > + if (pdev->num_resources !=3D 1) { > + dev_err(&pdev->dev, "invalid number of resources\n"); > + return -EINVAL; > + } > + > + mem_res =3D platform_get_resource(pdev, IORESOURCE_MEM, 0); > + > + if (!mem_res) { > + dev_err(dev, "failed to get mem resource\n"); > + return -EINVAL; > + } > + > + irq =3D board->irq_pin; > + > + /* init ata host */ > + > + host =3D ata_host_alloc(dev, 1); > + > + if (!host) > + return -ENOMEM; > + > + ap =3D host->ports[0]; > + ap->ops =3D &pata_at91_port_ops; > + ap->flags |=3D ATA_FLAG_SLAVE_POSS; > + ap->pio_mask =3D ATA_PIO4; > + > + if (!irq) { > + ap->flags |=3D ATA_FLAG_PIO_POLLING; > + ata_port_desc(ap, "no IRQ, using PIO polling"); > + } > + > + info =3D kzalloc(sizeof(*info), GFP_KERNEL); > + > + if (!info) { > + dev_err(dev, "failed to allocate memory for private > data\n"); > + return -ENOMEM; > + } > + > + info->cs =3D board->chipselect; > + info->mode =3D AT91_SMC_READMODE | AT91_SMC_WRITEMODE | > + AT91_SMC_EXNWMODE_READY | AT91_SMC_BAT_SELECT | > + AT91_SMC_DBW_8 | AT91_SMC_TDF_(0); > + > + info->ide_addr =3D devm_ioremap(dev, > + mem_res->start + CF_IDE_OFFSET, > CF_IDE_RES_SIZE); + > + if (!info->ide_addr) { > + dev_err(dev, "failed to map IO base\n"); > + ret =3D -ENOMEM; > + goto err_ide_ioremap; > + } > + > + info->alt_addr =3D devm_ioremap(dev, > + mem_res->start + CF_ALT_IDE_OFFSET, > CF_IDE_RES_SIZE); + > + if (!info->alt_addr) { > + dev_err(dev, "failed to map CTL base\n"); > + ret =3D -ENOMEM; > + goto err_alt_ioremap; > + } > + > + ap->ioaddr.cmd_addr =3D info->ide_addr; > + ap->ioaddr.ctl_addr =3D info->alt_addr + 0x06; > + ap->ioaddr.altstatus_addr =3D ap->ioaddr.ctl_addr; > + > + ata_sff_std_ports(&ap->ioaddr); > + > + ata_port_desc(ap, "mmio cmd 0x%llx ctl 0x%llx", > + (unsigned long long)mem_res->start + > CF_IDE_OFFSET, > + (unsigned long long)mem_res->start + > CF_ALT_IDE_OFFSET); + > + host->private_data =3D info; > + > + return ata_host_activate(host, irq ? gpio_to_irq(irq) : 0, > + irq ? ata_sff_interrupt : NULL, > + irq_flags, &pata_at91_sht); > + > +err_alt_ioremap: > + devm_iounmap(dev, info->ide_addr); > + > +err_ide_ioremap: > + kfree(info); > + > + return ret; > +} > + > +static int __devexit pata_at91_remove(struct platform_device *pdev) > +{ > + struct ata_host *host =3D dev_get_drvdata(&pdev->dev); > + struct at91_ide_info *info =3D host->private_data; > + struct device *dev =3D &pdev->dev; > + > + if (!host) > + return 0; > + > + ata_host_detach(host); > + > + if (!info) > + return 0; > + > + devm_iounmap(dev, info->ide_addr); > + devm_iounmap(dev, info->alt_addr); > + > + kfree(info); > + return 0; > +} > + > +static struct platform_driver pata_at91_driver =3D { > + .probe =3D pata_at91_probe, > + .remove =3D __devexit_p(pata_at91_remove), > + .driver =3D { > + .name =3D DRV_NAME, > + .owner =3D THIS_MODULE, > + }, > +}; > + > +static int __init pata_at91_init(void) > +{ > + return platform_driver_register(&pata_at91_driver); > +} > + > +static void __exit pata_at91_exit(void) > +{ > + platform_driver_unregister(&pata_at91_driver); > +} > + > + > +module_init(pata_at91_init); > +module_exit(pata_at91_exit); > + > + > +MODULE_LICENSE("GPL"); > +MODULE_DESCRIPTION("Driver for CF in True IDE mode on AT91SAM9260 > SoC"); +MODULE_AUTHOR("Matyukevich Sergey"); > +MODULE_VERSION(DRV_VERSION); > +