From: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
To: Russell King <rmk+kernel@armlinux.org.uk>, Tejun Heo <tj@kernel.org>
Cc: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>,
Sekhar Nori <nsekhar@ti.com>, Arnd Bergmann <arnd@arndb.de>,
Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>,
Kevin Hilman <khilman@baylibre.com>,
Olof Johansson <olof@lixom.net>,
linux-ide@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, b.zolnierkie@samsung.com
Subject: [PATCH] pata_pcmcia: add EBSA110's PCMCIA slot support
Date: Tue, 14 Mar 2017 18:50:43 +0100 [thread overview]
Message-ID: <3458240.9SL7iGif3L@amdc3058> (raw)
In-Reply-To: CGME20170314175046epcas1p43f98daad14a2bac7f314e7d39e120232@epcas1p4.samsung.com
Add EBSA110's PCMCIA slot support.
Cc: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
---
Cross compile tested only.
drivers/ata/pata_pcmcia.c | 297 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 294 insertions(+), 3 deletions(-)
Index: b/drivers/ata/pata_pcmcia.c
===================================================================
--- a/drivers/ata/pata_pcmcia.c 2017-03-14 18:32:21.667263033 +0100
+++ b/drivers/ata/pata_pcmcia.c 2017-03-14 18:41:48.995277320 +0100
@@ -164,6 +164,286 @@ static struct ata_port_operations pcmcia
.sff_drain_fifo = pcmcia_8bit_drain_fifo,
};
+#ifdef CONFIG_ARCH_EBSA110
+static void pmcmia_ebsa110_dev_select(struct ata_port *ap, unsigned int device)
+{
+ u8 tmp;
+
+ if (device == 0)
+ tmp = ATA_DEVICE_OBS;
+ else
+ tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+ __outb16(tmp, (unsigned long)ap->ioaddr.device_addr);
+ ata_sff_pause(ap); /* needed; also flushes, for mmio */
+}
+
+static void pcmcia_ebsa110_set_devctl(struct ata_port *ap, u8 ctl)
+{
+ __outb16(ctl, (unsigned long)ap->ioaddr.ctl_addr);
+}
+
+static u8 pcmcia_ebsa110_check_status(struct ata_port *ap)
+{
+ return __inb16((unsigned long)ap->ioaddr.status_addr);
+}
+
+static u8 pcmcia_ebsa110_check_altstatus(struct ata_port *ap)
+{
+ return __inb16((unsigned long)ap->ioaddr.altstatus_addr);
+}
+
+static void pcmcia_ebsa110_tf_load(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+ if (tf->ctl != ap->last_ctl) {
+ if (ioaddr->ctl_addr)
+ __outb16(tf->ctl, (unsigned long)ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ ata_wait_idle(ap);
+ }
+
+ if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+ WARN_ON_ONCE(!ioaddr->ctl_addr);
+ __outb16(tf->hob_feature, (unsigned long)ioaddr->feature_addr);
+ __outb16(tf->hob_nsect, (unsigned long)ioaddr->nsect_addr);
+ __outb16(tf->hob_lbal, (unsigned long)ioaddr->lbal_addr);
+ __outb16(tf->hob_lbam, (unsigned long)ioaddr->lbam_addr);
+ __outb16(tf->hob_lbah, (unsigned long)ioaddr->lbah_addr);
+ VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+ tf->hob_feature,
+ tf->hob_nsect,
+ tf->hob_lbal,
+ tf->hob_lbam,
+ tf->hob_lbah);
+ }
+
+ if (is_addr) {
+ __outb16(tf->feature, (unsigned long)ioaddr->feature_addr);
+ __outb16(tf->nsect, (unsigned long)ioaddr->nsect_addr);
+ __outb16(tf->lbal, (unsigned long)ioaddr->lbal_addr);
+ __outb16(tf->lbam, (unsigned long)ioaddr->lbam_addr);
+ __outb16(tf->lbah, (unsigned long)ioaddr->lbah_addr);
+ VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+ tf->feature,
+ tf->nsect,
+ tf->lbal,
+ tf->lbam,
+ tf->lbah);
+ }
+
+ if (tf->flags & ATA_TFLAG_DEVICE) {
+ __outb16(tf->device, (unsigned long)ioaddr->device_addr);
+ VPRINTK("device 0x%X\n", tf->device);
+ }
+
+ ata_wait_idle(ap);
+}
+
+static void pcmcia_ebsa110_tf_read(struct ata_port *ap,
+ struct ata_taskfile *tf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ tf->command = ata_sff_check_status(ap);
+ tf->feature = __inb16((unsigned long)ioaddr->error_addr);
+ tf->nsect = __inb16((unsigned long)ioaddr->nsect_addr);
+ tf->lbal = __inb16((unsigned long)ioaddr->lbal_addr);
+ tf->lbam = __inb16((unsigned long)ioaddr->lbam_addr);
+ tf->lbah = __inb16((unsigned long)ioaddr->lbah_addr);
+ tf->device = __inb16((unsigned long)ioaddr->device_addr);
+
+ if (tf->flags & ATA_TFLAG_LBA48) {
+ if (likely(ioaddr->ctl_addr)) {
+ __outb16(tf->ctl | ATA_HOB, (unsigned long)ioaddr->ctl_addr);
+ tf->hob_feature = __inb16((unsigned long)ioaddr->error_addr);
+ tf->hob_nsect = __inb16((unsigned long)ioaddr->nsect_addr);
+ tf->hob_lbal = __inb16((unsigned long)ioaddr->lbal_addr);
+ tf->hob_lbam = __inb16((unsigned long)ioaddr->lbam_addr);
+ tf->hob_lbah = __inb16((unsigned long)ioaddr->lbah_addr);
+ __outb16(tf->ctl, (unsigned long)ioaddr->ctl_addr);
+ ap->last_ctl = tf->ctl;
+ } else
+ WARN_ON_ONCE(1);
+ }
+}
+
+static void pcmcia_ebsa110_exec_command(struct ata_port *ap,
+ const struct ata_taskfile *tf)
+{
+ DPRINTK("ata%u: cmd 0x%X\n", ap->print_id, tf->command);
+
+ __outb16(tf->command, (unsigned long)ap->ioaddr.command_addr);
+ ata_sff_pause(ap);
+}
+
+static unsigned int pata_pcmcia_ebsa110_devchk(struct ata_port *ap,
+ unsigned int device)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ u8 nsect, lbal;
+
+ ap->ops->sff_dev_select(ap, device);
+
+ __outb16(0x55, (unsigned long)ioaddr->nsect_addr);
+ __outb16(0xaa, (unsigned long)ioaddr->lbal_addr);
+
+ __outb16(0xaa, (unsigned long)ioaddr->nsect_addr);
+ __outb16(0x55, (unsigned long)ioaddr->lbal_addr);
+
+ __outb16(0x55, (unsigned long)ioaddr->nsect_addr);
+ __outb16(0xaa, (unsigned long)ioaddr->lbal_addr);
+
+ nsect = __inb16((unsigned long)ioaddr->nsect_addr);
+ lbal = __inb16((unsigned long)ioaddr->lbal_addr);
+
+ if ((nsect == 0x55) && (lbal == 0xaa))
+ return 1; /* we found a device */
+
+ return 0; /* nothing found */
+}
+
+static int pata_pcmcia_ebsa110_wait_after_reset(struct ata_link *link,
+ unsigned int devmask,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+ unsigned int dev0 = devmask & (1 << 0);
+ unsigned int dev1 = devmask & (1 << 1);
+ int rc, ret = 0;
+
+ ata_msleep(ap, ATA_WAIT_AFTER_RESET);
+
+ /* always check readiness of the master device */
+ rc = ata_sff_wait_ready(link, deadline);
+ /* -ENODEV means the odd clown forgot the D7 pulldown resistor
+ * and TF status is 0xff, bail out on it too.
+ */
+ if (rc)
+ return rc;
+
+ /* if device 1 was found in ata_devchk, wait for register
+ * access briefly, then wait for BSY to clear.
+ */
+ if (dev1) {
+ int i;
+
+ ap->ops->sff_dev_select(ap, 1);
+
+ /* Wait for register access. Some ATAPI devices fail
+ * to set nsect/lbal after reset, so don't waste too
+ * much time on it. We're gonna wait for !BSY anyway.
+ */
+ for (i = 0; i < 2; i++) {
+ u8 nsect, lbal;
+
+ nsect = __inb16((unsigned long)ioaddr->nsect_addr);
+ lbal = __inb16((unsigned long)ioaddr->lbal_addr);
+ if ((nsect == 1) && (lbal == 1))
+ break;
+ ata_msleep(ap, 50); /* give drive a breather */
+ }
+
+ rc = ata_sff_wait_ready(link, deadline);
+ if (rc) {
+ if (rc != -ENODEV)
+ return rc;
+ ret = rc;
+ }
+ }
+
+ /* is all this really necessary? */
+ ap->ops->sff_dev_select(ap, 0);
+ if (dev1)
+ ap->ops->sff_dev_select(ap, 1);
+ if (dev0)
+ ap->ops->sff_dev_select(ap, 0);
+
+ return ret;
+}
+
+static int pata_pcmcia_ebsa110_bus_softreset(struct ata_port *ap,
+ unsigned int devmask,
+ unsigned long deadline)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ DPRINTK("ata%u: bus reset via SRST\n", ap->print_id);
+
+ /* software reset. causes dev0 to be selected */
+ __outb16(ap->ctl, (unsigned long)ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ __outb16(ap->ctl | ATA_SRST, (unsigned long)ioaddr->ctl_addr);
+ udelay(20); /* FIXME: flush */
+ __outb16(ap->ctl, (unsigned long)ioaddr->ctl_addr);
+ ap->last_ctl = ap->ctl;
+
+ /* wait the port to become ready */
+ return pata_pcmcia_ebsa110_wait_after_reset(&ap->link, devmask,
+ deadline);
+}
+
+static int pata_pcmcia_ebsa110_softreset(struct ata_link *link,
+ unsigned int *classes,
+ unsigned long deadline)
+{
+ struct ata_port *ap = link->ap;
+ unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+ unsigned int devmask = 0;
+ int rc;
+ u8 err;
+
+ DPRINTK("ENTER\n");
+
+ /* determine if device 0/1 are present */
+ if (pata_pcmcia_ebsa110_devchk(ap, 0))
+ devmask |= (1 << 0);
+ if (slave_possible && pata_pcmcia_ebsa110_devchk(ap, 1))
+ devmask |= (1 << 1);
+
+ /* select device 0 again */
+ ap->ops->sff_dev_select(ap, 0);
+
+ /* issue bus reset */
+ DPRINTK("about to softreset, devmask=%x\n", devmask);
+ rc = pata_pcmcia_ebsa110_bus_softreset(ap, devmask, deadline);
+ /* if link is occupied, -ENODEV too is an error */
+ if (rc && (rc != -ENODEV || sata_scr_valid(link))) {
+ ata_link_err(link, "SRST failed (errno=%d)\n", rc);
+ return rc;
+ }
+
+ /* determine by signature whether we have ATA or ATAPI devices */
+ classes[0] = ata_sff_dev_classify(&link->device[0],
+ devmask & (1 << 0), &err);
+ if (slave_possible && err != 0x81)
+ classes[1] = ata_sff_dev_classify(&link->device[1],
+ devmask & (1 << 1), &err);
+
+ DPRINTK("EXIT, classes[0]=%u [1]=%u\n", classes[0], classes[1]);
+ return 0;
+}
+
+static struct ata_port_operations pcmcia_ebsa110_port_ops = {
+ .inherits = &ata_sff_port_ops,
+ .sff_dev_select = pmcmia_ebsa110_dev_select,
+ .sff_set_devctl = pcmcia_ebsa110_set_devctl,
+ .sff_check_status = pcmcia_ebsa110_check_status,
+ .sff_check_altstatus = pcmcia_ebsa110_check_altstatus,
+ .sff_tf_load = pcmcia_ebsa110_tf_load,
+ .sff_tf_read = pcmcia_ebsa110_tf_read,
+ .sff_exec_command = pcmcia_ebsa110_exec_command,
+ .sff_data_xfer = ata_sff_data_xfer_noirq,
+ .softreset = pata_pcmcia_ebsa110_softreset,
+ .cable_detect = ata_cable_40wire,
+ .set_mode = pcmcia_set_mode,
+};
+#include <asm/mach-types.h>
+#endif
static int pcmcia_check_one_config(struct pcmcia_device *pdev, void *priv_data)
{
@@ -242,9 +522,20 @@ static int pcmcia_init_one(struct pcmcia
goto failed;
/* Success. Disable the IRQ nIEN line, do quirks */
- iowrite8(0x02, ctl_addr);
- if (is_kme)
- iowrite8(0x81, ctl_addr + 0x01);
+#ifdef CONFIG_ARCH_EBSA110
+ if (machine_is_ebsa110()) {
+ ops = &pcmcia_ebsa110_port_ops;
+
+ __outb16(0x02, (unsigned long)ctl_addr);
+ if (is_kme)
+ __outb16(0x81, (unsigned long)ctl_addr + 0x01);
+ } else
+#endif
+ {
+ iowrite8(0x02, ctl_addr);
+ if (is_kme)
+ iowrite8(0x81, ctl_addr + 0x01);
+ }
/* FIXME: Could be more ports at base + 0x10 but we only deal with
one right now */
next parent reply other threads:[~2017-03-14 17:50 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20170314175046epcas1p43f98daad14a2bac7f314e7d39e120232@epcas1p4.samsung.com>
2017-03-14 17:50 ` Bartlomiej Zolnierkiewicz [this message]
2017-03-16 21:26 ` [PATCH] pata_pcmcia: add EBSA110's PCMCIA slot support Tejun Heo
2017-03-17 11:59 ` Bartlomiej Zolnierkiewicz
2017-03-17 13:39 ` Tejun Heo
2017-03-17 14:08 ` Bartlomiej Zolnierkiewicz
2017-03-17 14:13 ` Tejun Heo
2017-03-17 15:51 ` Bartlomiej Zolnierkiewicz
2017-03-20 13:00 ` Bartlomiej Zolnierkiewicz
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=3458240.9SL7iGif3L@amdc3058 \
--to=b.zolnierkie@samsung.com \
--cc=arnd@arndb.de \
--cc=dbaryshkov@gmail.com \
--cc=khilman@baylibre.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-ide@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=nsekhar@ti.com \
--cc=olof@lixom.net \
--cc=rmk+kernel@armlinux.org.uk \
--cc=sergei.shtylyov@cogentembedded.com \
--cc=tj@kernel.org \
/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