From: Sergei Shtylyov <sshtylyov@ru.mvista.com>
To: Stanislaw Gruszka <stf_xl@wp.pl>
Cc: Andrew Victor <linux@maxim.org.za>,
Nicolas Ferre <nicolas.ferre@atmel.com>,
Haavard Skinnemoen <haavard.skinnemoen@atmel.com>,
linux-ide@vger.kernel.org
Subject: Re: [RFC][PATCH] at91_ide driver
Date: Tue, 20 Jan 2009 14:07:17 +0300 [thread overview]
Message-ID: <4975B065.6030705@ru.mvista.com> (raw)
In-Reply-To: <200901141345.42583.stf_xl@wp.pl>
Hello.
Stanislaw Gruszka wrote:
> I'm writting IDE host driver for AT91 Static Memory Controller with Compact Flash
> True IDE logic. My company - Kelvatek wants to add driver into the mainline,
> we think it can be usesfull for others and including driver will be also beneficial
> for us obviously.
If everybody looked at it that way...
> Some issues with driver:
>
> * Why not platform driver
But it is a platform driver. :-)
> Generic pata/ide_platform driver will not work with AT91 as we need to
>
Ah, why not generic...
> do special things before access Task File and Data Register (functions
> set_8bit_mode() and set_16bit_mode()).
That part really doesn't look well -- Atmel should have put more
though into it and make the register stride 2 bytes, so that 16-bit
access could alwys be used...
> * Tests
> We tested with our custom board which is slightly diffrent than
> Atmel Evaluation Kit. Pins settings in the patch are from Kelvatek's board,
> to run driver on sam9263ek board settings shall be changed.
I then don't understand how are you submitting this as a part of
SAM9623EK board code...
> We did not tests on Atmel sam9263ek board, because we have no proper connector
> for 1,8'' HDD.
Not sure I've understood that. You have 1,8'' drive and the board has
stndard IDE connector?
> * GPIO interrupt
> This is the most problem with the driver/hardware. Interrupt from device is
> delivered through GPIO. In AT91 GPIO interrupts are triggered on falling
> and raising edge of signal (this behaviour is not configured IIRC). Whereas
>
Ugh... what were they thinking?
> IDE device request interrupt on high level (raising edge in our case). This
>
The IDE interrupts historically trigger on rising edge.
> mean we have fake interrupts requests on cpu, which broke IDE layer.
> Problem can be solved in hardware: when device INTRQ line is connected
> to CPU through AIC controlled IRQ0 or IRQ1 lines with proper level configured.
> We probably do such things in our board, but it's is rather impossible
> for Atmel Evaluation Kit. Also there is workaround in software: check interrupt
> pin value and exit instantly from ISR when line is on low level. Such thing
> is done in the patch (AT91_GPIO_IRQ_HACK in drivers/ide/ide-io.c), but
> this is dirty hack and should implemented differently (I hope someone
> could give my good idea how).
>
We need to teach IDE core that IRQ handler can be different from the
default one.
> * Performance
> Driver works only in PIO mode, we have no hardware for DMA mode.
> Probably hardware support could be done using another Chip Select
> with Static Memory Controller and extra external logic. Maybe Atmel
> people could tell someting more about this issue?
I wouldn't hope on that... :-)
> On PIO4 mode I achieve 4,5MB/s
Seems a good result actually. How it was measured?
> Regards
> Stanislaw Gruszka
>
> Signed-off-by: Stanislaw Gruszka <stf_xl@wp.pl>
>
> ---
> arch/arm/mach-at91/at91sam9263_devices.c | 96 +++++++
> arch/arm/mach-at91/board-sam9263ek.c | 11 +
> arch/arm/mach-at91/include/mach/board.h | 9 +
>
This should probably go thru the ARM tree... though the maintainer
will decide.
> diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
> index 8b88408..976e228 100644
> --- a/arch/arm/mach-at91/at91sam9263_devices.c
> +++ b/arch/arm/mach-at91/at91sam9263_devices.c
> @@ -347,6 +347,102 @@ void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
> void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
> #endif
>
> +/* --------------------------------------------------------------------
> + * IDE
> + * -------------------------------------------------------------------- */
> +
> +#if defined(CONFIG_BLK_DEV_IDE_AT91) || defined(CONFIG_BLK_DEV_IDE_AT91_MODULE)
>
Welcome to the ARM #ifdef hell. :-)
> +/* Proper CS address space will be added */
> +#define AT91_IDE_TASK_FILE 0x00c00000
> +#define AT91_IDE_CTRL_REG 0x00e00000
>
Er, are you sure? Address lines should be 110 to address the device
control and alternate status registers, do they get asserted properly?
> +static struct resource ide_resources[] = {
> + [0] = {
> + .start = AT91_IDE_TASK_FILE,
> + .end = AT91_IDE_TASK_FILE + 8 - 1,
> + .flags = IORESOURCE_MEM,
> + },
> + [1] = {
> + .start = AT91_IDE_CTRL_REG,
> + .end = AT91_IDE_CTRL_REG, /* 1 byte */
> + .flags = IORESOURCE_MEM,
> + },
>
Er, why no IRQ resource?
> diff --git a/drivers/ide/at91_ide.c b/drivers/ide/at91_ide.c
> new file mode 100644
> index 0000000..f82ecb9
> --- /dev/null
> +++ b/drivers/ide/at91_ide.c
> @@ -0,0 +1,459 @@
> +/*
> + * IDE host driver for AT91 Static Memory Controler
>
I'm afraid you're being too generic here: e.g. AT91RM9200 has
incompatible SMC.
> +#define DEBUG 1
> +#define DRV_NAME "at91_ide"
> +
> +#define perr(fmt, args...) printk(KERN_ERR DRV_NAME ": " fmt, ##args)
> +
> +#ifdef DEBUG
> +#define pdbg(fmt, args...) printk(KERN_DEBUG "%s " fmt, __func__, ##args)
> +#else
> +#define pdbg(fmt, args...)
> +#endif
>
Consider using dev_err() and dev_dbg() instead...
> +/*
> + * AT91 Static Memory Controller maps Task File and Data Register
> + * at the same address. To distinguish access between these two
> + * different bus data width is used: 8Bit for Task File, 16Bit for Data I/O
> + */
> +
> +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_(2));
I'm not sure why you're fixing the data float timing to 2 cycles --
it correponds to the t6z timing which is 30 ns for ATA modes and 20 ns
for CF specific ones...
Why are you not using optimized data float mode?
> +static unsigned int calc_mck_cycles(unsigned int ns, unsigned int mck_hz)
> +{
> + u64 tmp = ns;
No empty line after declaration.
> + tmp *= mck_hz;
> + tmp += 1000*1000*1000 + 1; /* round up */
You probably mean -1 if you intend to just round up (so tmp +=
999999999).
> +static void set_ebi_timings(const u8 chipselect, const u8 pio)
> +{
> + /* Compact Flash True IDE mode timings, all values in nano seconds,
> + * see table 22 of standard 4.1 */
> + const struct { unsigned int t0, t1, t2, t2i, t9; } timings[7] = {
> + { .t0 = 600, .t1 = 70, .t2 = 290, .t2i = 0, .t9 = 20 }, /* PIO 0 */
> + { .t0 = 383, .t1 = 50, .t2 = 290, .t2i = 0, .t9 = 15 }, /* PIO 1 */
> + { .t0 = 240, .t1 = 30, .t2 = 290, .t2i = 0, .t9 = 10 }, /* PIO 2 */
> + { .t0 = 180, .t1 = 30, .t2 = 80, .t2i = 70, .t9 = 10 }, /* PIO 3 */
> + { .t0 = 120, .t1 = 25, .t2 = 70, .t2i = 25, .t9 = 10 }, /* PIO 4 */
> + { .t0 = 100, .t1 = 15, .t2 = 65, .t2i = 25, .t9 = 10 }, /* PIO 5 */
> + { .t0 = 80, .t1 = 10, .t2 = 55, .t2i = 20, .t9 = 10 }, /* PIO 6 */
> + };
Well, you've already received comments on this one...
I've already started the patch adding support of the CFA modes.
> + unsigned int t0, t1, t2, t2i, t9;
> + unsigned int mck_hz;
> + struct clk *mck;
> + unsigned long mode;
> +
> + BUG_ON(pio > 6);
> +
> + t0 = timings[pio].t0;
> + t1 = timings[pio].t1;
> + t2 = timings[pio].t2;
> + t2i = timings[pio].t2i;
> + t9 = timings[pio].t9;
> +
> + if (t2i > 0) {
> + /* t1 is the part of t2i, let's t9 be the rest of t2i */
> + WARN_ON(t2i < t1);
Doesn't happen.
> + if (t9 < t2i - t1)
> + t9 = t2i - t1;
>
It more sense to calculate such things *after* quantizing the
timings with calc_mck_cycles()...
> + mck = clk_get(NULL, "mck");
> + BUG_ON(IS_ERR(mck));
> + mck_hz = clk_get_rate(mck);
>
Why not call clk_get[_rate]() only once, at startup? It can change
dynamically?
> + t0 = calc_mck_cycles(t0, mck_hz);
> + t1 = calc_mck_cycles(t1, mck_hz);
> + t2 = calc_mck_cycles(t2, mck_hz);
> + t2i = calc_mck_cycles(t2i, mck_hz);
>
If you're not using t2i, why quantize it?
> + t9 = calc_mck_cycles(t9, mck_hz);
> + pdbg("t0=%u t1=%u t2=%u t2i=%u t9=%u\n", t0, t1, t2, t2i, t9);
>
Besides, we have ide_timing_compute() doing the same thing.
> + /* values are rounded up so we need to assure cycle is larger than pulse */
> + if (t0 < t1 + t2 + t9)
> + t0 = t1 + t2 + t9;
> +
> + /* setup calculated timings */
> + at91_sys_write(AT91_SMC_SETUP(chipselect), AT91_SMC_NWESETUP_(t1) |
> + AT91_SMC_NCS_WRSETUP_(0) |
> + AT91_SMC_NRDSETUP_(t1) |
> + AT91_SMC_NCS_RDSETUP_(0));
> + at91_sys_write(AT91_SMC_PULSE(chipselect), AT91_SMC_NWEPULSE_(t2) |
> + AT91_SMC_NCS_WRPULSE_(t1 + t2 + t9) |
>
With zero address to CS setup time it's the same as t0.
> + AT91_SMC_NRDPULSE_(t2) |
> + AT91_SMC_NCS_RDPULSE_(t1 + t2 + t9));
>
Same here.
> + /* disable or enable waiting for IORDY signal */
> + mode = at91_sys_read(AT91_SMC_MODE(chipselect));
> + mode &= ~AT91_SMC_EXNWMODE;
> + if (pio <= 4)
>
The IORDY loigic is not as simple -- you'd better use
ata_id_has_iordy() for PIO modes < 5.
> + mode |= AT91_SMC_EXNWMODE_FROZEN;
>
No, it should be READY mode.
> + else
> + mode |= AT91_SMC_EXNWMODE_DISABLE;
>
This constant is 0, so else branch can be skipped.
> +static void at91_ide_set_pio_mode(ide_drive_t *drive, const u8 pio)
> +{
> + u8 chipselect = drive->hwif->extra_base;
> +
> + pdbg("pio %u\n", pio);
> +
> + if (pio > 6) {
>
Can't happen.
> +static const struct ide_port_info at91_ide_port_info __initdata = {
> + .port_ops = &at91_ide_port_ops,
> + .tp_ops = &at91_ide_tp_ops,
> + .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA | IDE_HFLAG_SINGLE,
> + .pio_mask = ATA_PIO6,
>
No support for mode 6 yet, working on it.
> +static int __init at91_ide_probe(struct platform_device *pdev)
> +{
> + int ret = -ENOMEM;
> + hw_regs_t hw;
> + hw_regs_t *hws[] = { &hw, NULL, NULL, NULL };
> + struct resource *tf_res, *ctl_res;
> + unsigned long tf_base = 0, ctl_base = 0;
> + struct at91_ide_data *board = pdev->dev.platform_data;
> + struct ide_host *host;
> +
> + tf_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> + if (!ctl_res || !tf_res) {
> + perr("can't get memory resources\n");
> + goto err;
>
-ENODEV fits here better than -ENOMEM.
You also need to call request_mem_region()
> +#if 0
>
This is ghenerall frowned on...
> + /* In 12-0275-01 version of the PCB address
> + * lines CF_A0 and CF_A2 are swapped */
>
You should try to communicate such info to the driver via the
platfrom data...
> +#else
> + /* Proper lines addresses */
> + hw.io_ports.data_addr = tf_base + 0;
> + hw.io_ports.error_addr = tf_base + 1;
> + hw.io_ports.nsect_addr = tf_base + 2;
> + hw.io_ports.lbal_addr = tf_base + 3;
> + hw.io_ports.lbam_addr = tf_base + 4;
> + hw.io_ports.lbah_addr = tf_base + 5;
> + hw.io_ports.device_addr = tf_base + 6;
> + hw.io_ports.command_addr = tf_base + 7;
I suggest using hw.io_ports_array instead.
> + hw.irq = board->irq_pin;
>
Why not pass it normally, via the platform device's resource?
> diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
> index cc35d6d..6dba1fc 100644
> --- a/drivers/ide/ide-io.c
> +++ b/drivers/ide/ide-io.c
> @@ -1354,7 +1354,12 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
> * request completed. At this point we issue the next request
> * on the hwgroup and the process begins again.
> */
> -
> +#define AT91_GPIO_IRQ_HACK
> +
> +#ifdef AT91_GPIO_IRQ_HACK
> +#include <mach/gpio.h>
> +#endif
> +
> irqreturn_t ide_intr (int irq, void *dev_id)
> {
> unsigned long flags;
> @@ -1364,6 +1369,21 @@ irqreturn_t ide_intr (int irq, void *dev_id)
> ide_handler_t *handler;
> ide_startstop_t startstop;
>
> +#ifdef AT91_GPIO_IRQ_HACK
> +#define NR_TRIES 10
> + int ntries = 0;
> + int pin_val1, pin_val2;
> + do {
> + pin_val1 = at91_get_gpio_value(AT91_PIN_PB20);
> + pin_val2 = at91_get_gpio_value(AT91_PIN_PB20);
> + } while (pin_val1 != pin_val2 && ntries++ < NR_TRIES);
>
You need manual pin debouncing even after calling
at91_set_deglitch()? :-O
> + udelay(20); // XXX: this need to be here otherwise IDE layer losts interrups, don't know why !!!
>
Ugh...
MBR, Sergei
next prev parent reply other threads:[~2009-01-20 11:07 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-01-14 12:45 [RFC][PATCH] at91_ide driver Stanislaw Gruszka
2009-01-14 12:58 ` Haavard Skinnemoen
2009-01-14 13:21 ` Stanislaw Gruszka
2009-01-14 17:05 ` Sergei Shtylyov
2009-01-22 11:19 ` Stanislaw Gruszka
2009-01-14 13:17 ` Alan Cox
2009-01-14 14:35 ` Stanislaw Gruszka
2009-01-14 15:14 ` Alan Cox
2009-01-16 13:32 ` Sergei Shtylyov
2009-01-16 15:03 ` Stanislaw Gruszka
2009-01-16 15:34 ` Sergei Shtylyov
2009-01-16 16:13 ` Alan Cox
2009-01-17 20:08 ` Sergei Shtylyov
2009-01-17 20:20 ` Alan Cox
2009-01-18 10:58 ` Sergei Shtylyov
2009-01-18 15:29 ` Sergei Shtylyov
2009-01-19 11:51 ` Stanislaw Gruszka
2009-01-19 15:20 ` Sergei Shtylyov
2009-01-16 16:58 ` Bartlomiej Zolnierkiewicz
2009-01-17 16:45 ` Sergei Shtylyov
2009-01-19 22:50 ` Sergei Shtylyov
2009-01-27 15:31 ` Bartlomiej Zolnierkiewicz
2009-01-19 11:14 ` Stanislaw Gruszka
2009-01-19 12:52 ` Bartlomiej Zolnierkiewicz
2009-01-16 17:43 ` Bartlomiej Zolnierkiewicz
2009-01-19 11:20 ` Stanislaw Gruszka
2009-01-30 9:05 ` Stanislaw Gruszka
2009-02-01 17:13 ` Bartlomiej Zolnierkiewicz
2009-02-02 12:35 ` Stanislaw Gruszka
2009-01-20 11:07 ` Sergei Shtylyov [this message]
2009-01-20 14:49 ` Stanislaw Gruszka
2009-01-20 15:33 ` Sergei Shtylyov
2009-01-21 10:33 ` Stanislaw Gruszka
2009-01-22 9:44 ` Sergei Shtylyov
2009-01-22 10:15 ` Stanislaw Gruszka
2009-01-22 11:12 ` Stanislaw Gruszka
2009-01-22 12:06 ` Sergei Shtylyov
2009-01-22 12:16 ` Sergei Shtylyov
2009-01-22 12:24 ` Sergei Shtylyov
2009-01-22 12:57 ` Stanislaw Gruszka
2009-01-22 13:38 ` Sergei Shtylyov
2009-01-22 13:14 ` Stanislaw Gruszka
2009-01-22 13:48 ` Sergei Shtylyov
2009-01-22 14:13 ` Stanislaw Gruszka
2009-01-27 15:46 ` Sergei Shtylyov
2009-01-29 14:48 ` Stanislaw Gruszka
2009-01-29 15:22 ` Sergei Shtylyov
2009-01-22 14:39 ` 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=4975B065.6030705@ru.mvista.com \
--to=sshtylyov@ru.mvista.com \
--cc=haavard.skinnemoen@atmel.com \
--cc=linux-ide@vger.kernel.org \
--cc=linux@maxim.org.za \
--cc=nicolas.ferre@atmel.com \
--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).