linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
To: Stanislaw Gruszka <stf_xl@wp.pl>
Cc: linux-ide@vger.kernel.org, Andrew Victor <linux@maxim.org.za>,
	linux-arm-kernel@lists.arm.linux.org.uk
Subject: Re: [PATCH 2/3] ide: add at91_ide driver
Date: Wed, 04 Feb 2009 15:19:50 +0300	[thread overview]
Message-ID: <498987E6.7040909@ru.mvista.com> (raw)
In-Reply-To: <200902031147.22827.stf_xl@wp.pl>

Hello.

Stanislaw Gruszka wrote:

> This is IDE host driver for AT91SAM9 Static Memory Controller with Compact
> Flash True IDE Mode logic.
>
> Driver have to switch 8/16 bit bus width when accessing Task Tile or Data
> Register. Moreover some extra things need to be done when setting PIO mode.
> Only PIO mode is used, hardware have no DMA support. If interrupt line is
> connected through GPIO extra quirk is needed to cope with fake interrupts.
>
> Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
>   
[...]
> diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
> index fb51f0e..6674b9b 100644
> --- a/arch/arm/mach-at91/include/mach/board.h
> +++ b/arch/arm/mach-at91/include/mach/board.h
> @@ -59,6 +59,18 @@ struct at91_cf_data {
>  };
>  extern void __init at91_add_device_cf(struct at91_cf_data *data);
>  
> + /* Compact Flash True IDE mode */
> +struct at91_ide_data {
> +	u8	irq_pin;		/* the same meaning as for CF */
>   

  I again have to express my dislike about not passing IRQ the usual 
way. Also, see my comments to the platform code.

> +	u8	det_pin;
> +	u8	rst_pin;
> +	u8	chipselect;
> +	u8	flags;
> +#define AT91_IDE_SWAP_A0_A2 0x01
> +};
> +
> +extern void __init at91_add_device_ide(struct at91_ide_data *data);
> +
>   /* MMC / SD */
>  struct at91_mmc_data {
>  	u8		det_pin;	/* card detect IRQ */
> diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
> index 3dad229..b11da5b 100644
> --- a/drivers/ide/Kconfig
> +++ b/drivers/ide/Kconfig
> @@ -721,6 +721,11 @@ config BLK_DEV_IDE_TX4939
>  	depends on SOC_TX4939
>  	select BLK_DEV_IDEDMA_SFF
>  
> +config BLK_DEV_IDE_AT91
> +	tristate "Atmel AT91 IDE support"
>   

   Please be more specific -- you can't drive AT91RM9200 SMC.

> +	depends on ARM && ARCH_AT91
>   

   Please add "&& !ARCH_AT91RM9200". And maybe "&& !ARCH_AT91X40" too...

> diff --git a/drivers/ide/at91_ide.c b/drivers/ide/at91_ide.c
> new file mode 100644
> index 0000000..3a1f7e0
> --- /dev/null
> +++ b/drivers/ide/at91_ide.c
> @@ -0,0 +1,496 @@
> +/*
> + * IDE host driver for AT91SAM9 Static Memory Controller
>   

   Why not call the driver 'at91sam9_ide'?

> +/*
> + * AT91 Static Memory Controller

  AT91SAM9.

> maps Task File and Data Register
>   
> + * at the same address. To distinguish access between these two

   It would have been strange if it did it otherwise...

> + * different bus data width is used: 8Bit for Task File, 16Bit for Data I/O
> + *
> + * After initialization we do 8/16 bit flipping (changes in SMC MODE register)
> + * only inside IDE callback routines which are serialized by IDE layer,
> + * so no additional locking needed.
> + */
> +
> +static void init_smc_mode(const u8 chipselect)
> +{
> +	at91_sys_write(AT91_SMC_MODE(chipselect), AT91_SMC_READMODE |
> +						  AT91_SMC_WRITEMODE |
> +						  AT91_SMC_BAT_SELECT |
> +						  AT91_SMC_TDF_(0));
>   

   I'm not sure why are you fixing the dataflow timing again, this time 
to 0...

> +}
> +
> +static inline void set_8bit_mode(const u8 chipselect)
> +{
> +	unsigned long mode = at91_sys_read(AT91_SMC_MODE(chipselect));
> +	mode &= ~AT91_SMC_DBW;
> +	mode |= AT91_SMC_DBW_8;
> +	at91_sys_write(AT91_SMC_MODE(chipselect), mode);
> +	pdbg("%u %08lx\n", chipselect, mode);
> +}
> +
> +static inline void set_16bit_mode(const u8 chipselect)
> +{
> +	unsigned long mode = at91_sys_read(AT91_SMC_MODE(chipselect));
> +	mode &= ~AT91_SMC_DBW;
> +	mode |= AT91_SMC_DBW_16;
> +	at91_sys_write(AT91_SMC_MODE(chipselect), mode);
> +	pdbg("%u %08lx\n", chipselect, mode);
> +}
>   

  I'd advice to make this single function because it looks like a code 
duplication too much.

> +static void set_smc_timings(const u8 chipselect, const u16 cycle,
> +			    const u16 setup, const u16 pulse,
> +			    const u16 data_float, int use_iordy)
>   

   Have you considered using already present sam9_smc_configure() 
instead to avoid the code duplication (it needs to be exported though)?

> +{
> +	unsigned long mode;
> +
> +	/* setup timings in SMC */
> +	at91_sys_write(AT91_SMC_SETUP(chipselect), AT91_SMC_NWESETUP_(setup) |
> +						   AT91_SMC_NCS_WRSETUP_(0) |
> +						   AT91_SMC_NRDSETUP_(setup) |
> +						   AT91_SMC_NCS_RDSETUP_(0));
> +	at91_sys_write(AT91_SMC_PULSE(chipselect), AT91_SMC_NWEPULSE_(pulse) |
> +						   AT91_SMC_NCS_WRPULSE_(cycle) |
> +						   AT91_SMC_NRDPULSE_(pulse) |
> +						   AT91_SMC_NCS_RDPULSE_(cycle));
> +	at91_sys_write(AT91_SMC_CYCLE(chipselect), AT91_SMC_NWECYCLE_(cycle) |
> +						   AT91_SMC_NRDCYCLE_(cycle));
> +
> +	mode = at91_sys_read(AT91_SMC_MODE(chipselect));
>   

   Frankly speaking, I don't see why you're reading this register back 
if you already know what needs to be set there -- as you've done it in 
init_smc_mode().

> +static unsigned int calc_mck_cycles(unsigned int ns, unsigned int mck_hz)
> +{
> +	u64 tmp = ns;
> +
> +	tmp *= mck_hz;
> +	tmp += 1000*1000*1000 - 1; /* round up */
> +	do_div(tmp, 1000*1000*1000);
> +	return (unsigned int) tmp;
> +}
> +
> +static void apply_timings(const u8 chipselect, const u8 pio,
> +			  const struct ide_timing *timing, const u16 *ata_id)
> +{
> +	unsigned int t0, t1, t2, t6z, th;
> +	unsigned int cycle, setup, pulse, data_float;
> +	unsigned int mck_hz;
> +	struct clk *mck;
> +	int use_iordy;
>   
[...]
> +
> +	use_iordy = 0;
>   

   Can be done in initializer...

> +	if (ata_id) {
> +		if (ata_id_is_cfa(ata_id)) {
> +			if (pio == 3 || pio == 4)
> +				use_iordy = 1;
>   
> +		} else if (pio >= 3 || ata_id_has_iordy(ata_id))
> +			use_iordy = 1;
>   


   No, you should check for IORDY regardless of CFA and using IORDY 
shouldn't be limeited to modes 3 and 4:

        if (ata_id_has_iordy(ata_id) && !(ata_id_is_cfa(ata_id) && pio > 4))
           use_iodry = 1;

> +static u8 ide_mm_inb(unsigned long port)
> +{
> +	return (u8) readb((void __iomem *) port);
>   

  Explict cast not needed here.

> +void at91_ide_tf_load(ide_drive_t *drive, ide_task_t *task)
> +{
> +	ide_hwif_t *hwif = drive->hwif;
> +	struct ide_io_ports *io_ports = &hwif->io_ports;
> +	struct ide_taskfile *tf = &task->tf;
> +	u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
> +
> +	if (task->tf_flags & IDE_TFLAG_FLAGGED)
> +		HIHI = 0xFF;
> +
> +	if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
>   

   Sigh. Bart, couldn't we drop that stupid flag? I bet nobody ever used it.

> +void at91_ide_tf_read(ide_drive_t *drive, ide_task_t *task)
> +{
> +	ide_hwif_t *hwif = drive->hwif;
> +	struct ide_io_ports *io_ports = &hwif->io_ports;
> +	struct ide_taskfile *tf = &task->tf;
> +
> +	if (task->tf_flags & IDE_TFLAG_IN_DATA) {
>   

   ... and this one too?

> +/*
> + * If interrupt is delivered through GPIO, IRQ are triggered on falling
> + * and raising edge of signal. Whereas IDE device request interrupt on high
> + * level (raising edge in our case). This mean we have fake interrupts, so
> + * we need to check interrupt pin and exit instantly from ISR when line
> + * is on low level.
> + */
> +
> +irqreturn_t at91_irq_handler(int irq, void *dev_id)
> +{
> +	int ntries = 8;
> +	int pin_val1, pin_val2;
> +
> +	/* additional deglitch, line can be noisy in badly designed PCB */
> +	do {
> +		pin_val1 = at91_get_gpio_value(irq);
> +		pin_val2 = at91_get_gpio_value(irq);
> +	} while (pin_val1 != pin_val2 && --ntries > 0);
>   

  I suggest a shorter code:

	do {
		pin_val = at91_get_gpio_value(irq);
	} while (pin_val != at91_get_gpio_value(irq) && --ntries > 0);


> +static int __init at91_ide_probe(struct platform_device *pdev)
> +{
>   
[...]
> +	host->ports[0]->extra_base = board->chipselect;
>   

   BTW, we have 2 fields in the struct hwif_s that fit this case better: 
config_data and select_data. It's a bit stange that you've selected 
extra_base...

MBR, Sergei



  reply	other threads:[~2009-02-04 12:19 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-02-03 10:47 [PATCH 2/3] ide: add at91_ide driver Stanislaw Gruszka
2009-02-04 12:19 ` Sergei Shtylyov [this message]
2009-02-04 14:47   ` Stanislaw Gruszka
2009-02-04 16:04     ` Sergei Shtylyov
2009-02-04 16:08       ` Sergei Shtylyov
2009-02-05 15:01       ` Stanislaw Gruszka
2009-02-05 16:09         ` Sergei Shtylyov
2009-02-05 20:00           ` Andrew Victor
2009-02-05 20:03             ` Sergei Shtylyov
2009-02-06  9:35           ` Stanislaw Gruszka
2009-02-06 10:55           ` Sergei Shtylyov
2009-02-06 16:50             ` Bartlomiej Zolnierkiewicz
2009-02-06 17:20               ` Sergei Shtylyov
2009-02-05 21:23   ` Bartlomiej Zolnierkiewicz
2009-02-05 23:31     ` Sergei Shtylyov
2009-02-06 16:36       ` Bartlomiej Zolnierkiewicz
2009-02-08  0:10         ` Sergei Shtylyov
2009-02-08 11:39           ` Sergei Shtylyov
2009-02-08 22:58             ` Sergei Shtylyov
2009-02-09 19:48               ` Bartlomiej Zolnierkiewicz
2009-02-06  9:30   ` Stanislaw Gruszka
2009-02-06 10:36     ` Sergei Shtylyov
2009-02-06 10:47       ` Stanislaw Gruszka

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=498987E6.7040909@ru.mvista.com \
    --to=sshtylyov@ru.mvista.com \
    --cc=linux-arm-kernel@lists.arm.linux.org.uk \
    --cc=linux-ide@vger.kernel.org \
    --cc=linux@maxim.org.za \
    --cc=stf_xl@wp.pl \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).