Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 /*
0004  * Amiga Gayle PATA controller driver
0005  *
0006  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
0007  *      http://www.samsung.com
0008  *
0009  * Based on gayle.c:
0010  *
0011  *     Created 12 Jul 1997 by Geert Uytterhoeven
0012  */
0013 
0014 #include <linux/ata.h>
0015 #include <linux/blkdev.h>
0016 #include <linux/delay.h>
0017 #include <linux/interrupt.h>
0018 #include <linux/kernel.h>
0019 #include <linux/libata.h>
0020 #include <linux/mm.h>
0021 #include <linux/module.h>
0022 #include <linux/platform_device.h>
0023 #include <linux/zorro.h>
0024 #include <scsi/scsi_cmnd.h>
0025 #include <scsi/scsi_host.h>
0026 
0027 #include <asm/amigahw.h>
0028 #include <asm/amigaints.h>
0029 #include <asm/amigayle.h>
0030 #include <asm/ide.h>
0031 #include <asm/setup.h>
0032 
0033 #define DRV_NAME "pata_gayle"
0034 #define DRV_VERSION "0.1.0"
0035 
0036 #define GAYLE_CONTROL   0x101a
0037 
0038 static struct scsi_host_template pata_gayle_sht = {
0039     ATA_PIO_SHT(DRV_NAME),
0040 };
0041 
0042 /* FIXME: is this needed? */
0043 static unsigned int pata_gayle_data_xfer(struct ata_queued_cmd *qc,
0044                      unsigned char *buf,
0045                      unsigned int buflen, int rw)
0046 {
0047     struct ata_device *dev = qc->dev;
0048     struct ata_port *ap = dev->link->ap;
0049     void __iomem *data_addr = ap->ioaddr.data_addr;
0050     unsigned int words = buflen >> 1;
0051 
0052     /* Transfer multiple of 2 bytes */
0053     if (rw == READ)
0054         raw_insw((u16 *)data_addr, (u16 *)buf, words);
0055     else
0056         raw_outsw((u16 *)data_addr, (u16 *)buf, words);
0057 
0058     /* Transfer trailing byte, if any. */
0059     if (unlikely(buflen & 0x01)) {
0060         unsigned char pad[2] = { };
0061 
0062         /* Point buf to the tail of buffer */
0063         buf += buflen - 1;
0064 
0065         if (rw == READ) {
0066             raw_insw((u16 *)data_addr, (u16 *)pad, 1);
0067             *buf = pad[0];
0068         } else {
0069             pad[0] = *buf;
0070             raw_outsw((u16 *)data_addr, (u16 *)pad, 1);
0071         }
0072         words++;
0073     }
0074 
0075     return words << 1;
0076 }
0077 
0078 /*
0079  * Provide our own set_mode() as we don't want to change anything that has
0080  * already been configured..
0081  */
0082 static int pata_gayle_set_mode(struct ata_link *link,
0083                    struct ata_device **unused)
0084 {
0085     struct ata_device *dev;
0086 
0087     ata_for_each_dev(dev, link, ENABLED) {
0088         /* We don't really care */
0089         dev->pio_mode = dev->xfer_mode = XFER_PIO_0;
0090         dev->xfer_shift = ATA_SHIFT_PIO;
0091         dev->flags |= ATA_DFLAG_PIO;
0092         ata_dev_info(dev, "configured for PIO\n");
0093     }
0094     return 0;
0095 }
0096 
0097 static bool pata_gayle_irq_check(struct ata_port *ap)
0098 {
0099     u8 ch;
0100 
0101     ch = z_readb((unsigned long)ap->private_data);
0102 
0103     return !!(ch & GAYLE_IRQ_IDE);
0104 }
0105 
0106 static void pata_gayle_irq_clear(struct ata_port *ap)
0107 {
0108     (void)z_readb((unsigned long)ap->ioaddr.status_addr);
0109     z_writeb(0x7c, (unsigned long)ap->private_data);
0110 }
0111 
0112 static struct ata_port_operations pata_gayle_a1200_ops = {
0113     .inherits   = &ata_sff_port_ops,
0114     .sff_data_xfer  = pata_gayle_data_xfer,
0115     .sff_irq_check  = pata_gayle_irq_check,
0116     .sff_irq_clear  = pata_gayle_irq_clear,
0117     .cable_detect   = ata_cable_unknown,
0118     .set_mode   = pata_gayle_set_mode,
0119 };
0120 
0121 static struct ata_port_operations pata_gayle_a4000_ops = {
0122     .inherits   = &ata_sff_port_ops,
0123     .sff_data_xfer  = pata_gayle_data_xfer,
0124     .cable_detect   = ata_cable_unknown,
0125     .set_mode   = pata_gayle_set_mode,
0126 };
0127 
0128 static int __init pata_gayle_init_one(struct platform_device *pdev)
0129 {
0130     struct resource *res;
0131     struct gayle_ide_platform_data *pdata;
0132     struct ata_host *host;
0133     struct ata_port *ap;
0134     void __iomem *base;
0135     int ret;
0136 
0137     pdata = dev_get_platdata(&pdev->dev);
0138 
0139     dev_info(&pdev->dev, "Amiga Gayle IDE controller (A%u style)\n",
0140         pdata->explicit_ack ? 1200 : 4000);
0141 
0142     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0143     if (!res)
0144         return -ENODEV;
0145 
0146     if (!devm_request_mem_region(&pdev->dev, res->start,
0147                      resource_size(res), DRV_NAME)) {
0148         pr_err(DRV_NAME ": resources busy\n");
0149         return -EBUSY;
0150     }
0151 
0152     /* allocate host */
0153     host = ata_host_alloc(&pdev->dev, 1);
0154     if (!host)
0155         return -ENOMEM;
0156 
0157     ap = host->ports[0];
0158 
0159     if (pdata->explicit_ack)
0160         ap->ops = &pata_gayle_a1200_ops;
0161     else
0162         ap->ops = &pata_gayle_a4000_ops;
0163 
0164     ap->pio_mask = ATA_PIO4;
0165     ap->flags |= ATA_FLAG_SLAVE_POSS | ATA_FLAG_NO_IORDY;
0166 
0167     base = ZTWO_VADDR(pdata->base);
0168     ap->ioaddr.data_addr        = base;
0169     ap->ioaddr.error_addr       = base + 2 + 1 * 4;
0170     ap->ioaddr.feature_addr     = base + 2 + 1 * 4;
0171     ap->ioaddr.nsect_addr       = base + 2 + 2 * 4;
0172     ap->ioaddr.lbal_addr        = base + 2 + 3 * 4;
0173     ap->ioaddr.lbam_addr        = base + 2 + 4 * 4;
0174     ap->ioaddr.lbah_addr        = base + 2 + 5 * 4;
0175     ap->ioaddr.device_addr      = base + 2 + 6 * 4;
0176     ap->ioaddr.status_addr      = base + 2 + 7 * 4;
0177     ap->ioaddr.command_addr     = base + 2 + 7 * 4;
0178 
0179     ap->ioaddr.altstatus_addr   = base + GAYLE_CONTROL;
0180     ap->ioaddr.ctl_addr     = base + GAYLE_CONTROL;
0181 
0182     ap->private_data = (void *)ZTWO_VADDR(pdata->irqport);
0183 
0184     ata_port_desc(ap, "cmd 0x%lx ctl 0x%lx", pdata->base,
0185               pdata->base + GAYLE_CONTROL);
0186 
0187     ret = ata_host_activate(host, IRQ_AMIGA_PORTS, ata_sff_interrupt,
0188                 IRQF_SHARED, &pata_gayle_sht);
0189     if (ret)
0190         return ret;
0191 
0192     platform_set_drvdata(pdev, host);
0193 
0194     return 0;
0195 }
0196 
0197 static int __exit pata_gayle_remove_one(struct platform_device *pdev)
0198 {
0199     struct ata_host *host = platform_get_drvdata(pdev);
0200 
0201     ata_host_detach(host);
0202 
0203     return 0;
0204 }
0205 
0206 static struct platform_driver pata_gayle_driver = {
0207     .remove = __exit_p(pata_gayle_remove_one),
0208     .driver   = {
0209         .name   = "amiga-gayle-ide",
0210     },
0211 };
0212 
0213 module_platform_driver_probe(pata_gayle_driver, pata_gayle_init_one);
0214 
0215 MODULE_AUTHOR("Bartlomiej Zolnierkiewicz");
0216 MODULE_DESCRIPTION("low-level driver for Amiga Gayle PATA");
0217 MODULE_LICENSE("GPL v2");
0218 MODULE_ALIAS("platform:amiga-gayle-ide");
0219 MODULE_VERSION(DRV_VERSION);