18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Generic platform device PATA driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2006 - 2007 Paul Mundt 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Based on pata_pcmcia: 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright 2005-2006 Red Hat Inc, all rights reserved. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 118c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 128c2ecf20Sopenharmony_ci * for more details. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 178c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 188c2ecf20Sopenharmony_ci#include <linux/ata.h> 198c2ecf20Sopenharmony_ci#include <linux/libata.h> 208c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 218c2ecf20Sopenharmony_ci#include <linux/ata_platform.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define DRV_NAME "pata_platform" 248c2ecf20Sopenharmony_ci#define DRV_VERSION "1.2" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int pio_mask = 1; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * Provide our own set_mode() as we don't want to change anything that has 308c2ecf20Sopenharmony_ci * already been configured.. 318c2ecf20Sopenharmony_ci */ 328c2ecf20Sopenharmony_cistatic int pata_platform_set_mode(struct ata_link *link, struct ata_device **unused) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct ata_device *dev; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci ata_for_each_dev(dev, link, ENABLED) { 378c2ecf20Sopenharmony_ci /* We don't really care */ 388c2ecf20Sopenharmony_ci dev->pio_mode = dev->xfer_mode = XFER_PIO_0; 398c2ecf20Sopenharmony_ci dev->xfer_shift = ATA_SHIFT_PIO; 408c2ecf20Sopenharmony_ci dev->flags |= ATA_DFLAG_PIO; 418c2ecf20Sopenharmony_ci ata_dev_info(dev, "configured for PIO\n"); 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci return 0; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic struct scsi_host_template pata_platform_sht = { 478c2ecf20Sopenharmony_ci ATA_PIO_SHT(DRV_NAME), 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void pata_platform_setup_port(struct ata_ioports *ioaddr, 518c2ecf20Sopenharmony_ci unsigned int shift) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci /* Fixup the port shift for platforms that need it */ 548c2ecf20Sopenharmony_ci ioaddr->data_addr = ioaddr->cmd_addr + (ATA_REG_DATA << shift); 558c2ecf20Sopenharmony_ci ioaddr->error_addr = ioaddr->cmd_addr + (ATA_REG_ERR << shift); 568c2ecf20Sopenharmony_ci ioaddr->feature_addr = ioaddr->cmd_addr + (ATA_REG_FEATURE << shift); 578c2ecf20Sopenharmony_ci ioaddr->nsect_addr = ioaddr->cmd_addr + (ATA_REG_NSECT << shift); 588c2ecf20Sopenharmony_ci ioaddr->lbal_addr = ioaddr->cmd_addr + (ATA_REG_LBAL << shift); 598c2ecf20Sopenharmony_ci ioaddr->lbam_addr = ioaddr->cmd_addr + (ATA_REG_LBAM << shift); 608c2ecf20Sopenharmony_ci ioaddr->lbah_addr = ioaddr->cmd_addr + (ATA_REG_LBAH << shift); 618c2ecf20Sopenharmony_ci ioaddr->device_addr = ioaddr->cmd_addr + (ATA_REG_DEVICE << shift); 628c2ecf20Sopenharmony_ci ioaddr->status_addr = ioaddr->cmd_addr + (ATA_REG_STATUS << shift); 638c2ecf20Sopenharmony_ci ioaddr->command_addr = ioaddr->cmd_addr + (ATA_REG_CMD << shift); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * __pata_platform_probe - attach a platform interface 688c2ecf20Sopenharmony_ci * @dev: device 698c2ecf20Sopenharmony_ci * @io_res: Resource representing I/O base 708c2ecf20Sopenharmony_ci * @ctl_res: Resource representing CTL base 718c2ecf20Sopenharmony_ci * @irq_res: Resource representing IRQ and its flags 728c2ecf20Sopenharmony_ci * @ioport_shift: I/O port shift 738c2ecf20Sopenharmony_ci * @__pio_mask: PIO mask 748c2ecf20Sopenharmony_ci * @sht: scsi_host_template to use when registering 758c2ecf20Sopenharmony_ci * @use16bit: Flag to indicate 16-bit IO instead of 32-bit 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * Register a platform bus IDE interface. Such interfaces are PIO and we 788c2ecf20Sopenharmony_ci * assume do not support IRQ sharing. 798c2ecf20Sopenharmony_ci * 808c2ecf20Sopenharmony_ci * Platform devices are expected to contain at least 2 resources per port: 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * - I/O Base (IORESOURCE_IO or IORESOURCE_MEM) 838c2ecf20Sopenharmony_ci * - CTL Base (IORESOURCE_IO or IORESOURCE_MEM) 848c2ecf20Sopenharmony_ci * 858c2ecf20Sopenharmony_ci * and optionally: 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * - IRQ (IORESOURCE_IRQ) 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * If the base resources are both mem types, the ioremap() is handled 908c2ecf20Sopenharmony_ci * here. For IORESOURCE_IO, it's assumed that there's no remapping 918c2ecf20Sopenharmony_ci * necessary. 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * If no IRQ resource is present, PIO polling mode is used instead. 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ciint __pata_platform_probe(struct device *dev, struct resource *io_res, 968c2ecf20Sopenharmony_ci struct resource *ctl_res, struct resource *irq_res, 978c2ecf20Sopenharmony_ci unsigned int ioport_shift, int __pio_mask, 988c2ecf20Sopenharmony_ci struct scsi_host_template *sht, bool use16bit) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct ata_host *host; 1018c2ecf20Sopenharmony_ci struct ata_port *ap; 1028c2ecf20Sopenharmony_ci unsigned int mmio; 1038c2ecf20Sopenharmony_ci int irq = 0; 1048c2ecf20Sopenharmony_ci int irq_flags = 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* 1078c2ecf20Sopenharmony_ci * Check for MMIO 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci mmio = (( io_res->flags == IORESOURCE_MEM) && 1108c2ecf20Sopenharmony_ci (ctl_res->flags == IORESOURCE_MEM)); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* 1138c2ecf20Sopenharmony_ci * And the IRQ 1148c2ecf20Sopenharmony_ci */ 1158c2ecf20Sopenharmony_ci if (irq_res && irq_res->start > 0) { 1168c2ecf20Sopenharmony_ci irq = irq_res->start; 1178c2ecf20Sopenharmony_ci irq_flags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * Now that that's out of the way, wire up the port.. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci host = ata_host_alloc(dev, 1); 1248c2ecf20Sopenharmony_ci if (!host) 1258c2ecf20Sopenharmony_ci return -ENOMEM; 1268c2ecf20Sopenharmony_ci ap = host->ports[0]; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ap->ops = devm_kzalloc(dev, sizeof(*ap->ops), GFP_KERNEL); 1298c2ecf20Sopenharmony_ci ap->ops->inherits = &ata_sff_port_ops; 1308c2ecf20Sopenharmony_ci ap->ops->cable_detect = ata_cable_unknown; 1318c2ecf20Sopenharmony_ci ap->ops->set_mode = pata_platform_set_mode; 1328c2ecf20Sopenharmony_ci if (use16bit) 1338c2ecf20Sopenharmony_ci ap->ops->sff_data_xfer = ata_sff_data_xfer; 1348c2ecf20Sopenharmony_ci else 1358c2ecf20Sopenharmony_ci ap->ops->sff_data_xfer = ata_sff_data_xfer32; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ap->pio_mask = __pio_mask; 1388c2ecf20Sopenharmony_ci ap->flags |= ATA_FLAG_SLAVE_POSS; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* 1418c2ecf20Sopenharmony_ci * Use polling mode if there's no IRQ 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci if (!irq) { 1448c2ecf20Sopenharmony_ci ap->flags |= ATA_FLAG_PIO_POLLING; 1458c2ecf20Sopenharmony_ci ata_port_desc(ap, "no IRQ, using PIO polling"); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* 1498c2ecf20Sopenharmony_ci * Handle the MMIO case 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci if (mmio) { 1528c2ecf20Sopenharmony_ci ap->ioaddr.cmd_addr = devm_ioremap(dev, io_res->start, 1538c2ecf20Sopenharmony_ci resource_size(io_res)); 1548c2ecf20Sopenharmony_ci ap->ioaddr.ctl_addr = devm_ioremap(dev, ctl_res->start, 1558c2ecf20Sopenharmony_ci resource_size(ctl_res)); 1568c2ecf20Sopenharmony_ci } else { 1578c2ecf20Sopenharmony_ci ap->ioaddr.cmd_addr = devm_ioport_map(dev, io_res->start, 1588c2ecf20Sopenharmony_ci resource_size(io_res)); 1598c2ecf20Sopenharmony_ci ap->ioaddr.ctl_addr = devm_ioport_map(dev, ctl_res->start, 1608c2ecf20Sopenharmony_ci resource_size(ctl_res)); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci if (!ap->ioaddr.cmd_addr || !ap->ioaddr.ctl_addr) { 1638c2ecf20Sopenharmony_ci dev_err(dev, "failed to map IO/CTL base\n"); 1648c2ecf20Sopenharmony_ci return -ENOMEM; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci ap->ioaddr.altstatus_addr = ap->ioaddr.ctl_addr; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci pata_platform_setup_port(&ap->ioaddr, ioport_shift); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci ata_port_desc(ap, "%s cmd 0x%llx ctl 0x%llx", mmio ? "mmio" : "ioport", 1728c2ecf20Sopenharmony_ci (unsigned long long)io_res->start, 1738c2ecf20Sopenharmony_ci (unsigned long long)ctl_res->start); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* activate */ 1768c2ecf20Sopenharmony_ci return ata_host_activate(host, irq, irq ? ata_sff_interrupt : NULL, 1778c2ecf20Sopenharmony_ci irq_flags, sht); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__pata_platform_probe); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int pata_platform_probe(struct platform_device *pdev) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct resource *io_res; 1848c2ecf20Sopenharmony_ci struct resource *ctl_res; 1858c2ecf20Sopenharmony_ci struct resource *irq_res; 1868c2ecf20Sopenharmony_ci struct pata_platform_info *pp_info = dev_get_platdata(&pdev->dev); 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* 1898c2ecf20Sopenharmony_ci * Simple resource validation .. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci if ((pdev->num_resources != 3) && (pdev->num_resources != 2)) { 1928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "invalid number of resources\n"); 1938c2ecf20Sopenharmony_ci return -EINVAL; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* 1978c2ecf20Sopenharmony_ci * Get the I/O base first 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci io_res = platform_get_resource(pdev, IORESOURCE_IO, 0); 2008c2ecf20Sopenharmony_ci if (io_res == NULL) { 2018c2ecf20Sopenharmony_ci io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 2028c2ecf20Sopenharmony_ci if (unlikely(io_res == NULL)) 2038c2ecf20Sopenharmony_ci return -EINVAL; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* 2078c2ecf20Sopenharmony_ci * Then the CTL base 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci ctl_res = platform_get_resource(pdev, IORESOURCE_IO, 1); 2108c2ecf20Sopenharmony_ci if (ctl_res == NULL) { 2118c2ecf20Sopenharmony_ci ctl_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 2128c2ecf20Sopenharmony_ci if (unlikely(ctl_res == NULL)) 2138c2ecf20Sopenharmony_ci return -EINVAL; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* 2178c2ecf20Sopenharmony_ci * And the IRQ 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci return __pata_platform_probe(&pdev->dev, io_res, ctl_res, irq_res, 2228c2ecf20Sopenharmony_ci pp_info ? pp_info->ioport_shift : 0, 2238c2ecf20Sopenharmony_ci pio_mask, &pata_platform_sht, false); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic struct platform_driver pata_platform_driver = { 2278c2ecf20Sopenharmony_ci .probe = pata_platform_probe, 2288c2ecf20Sopenharmony_ci .remove = ata_platform_remove_one, 2298c2ecf20Sopenharmony_ci .driver = { 2308c2ecf20Sopenharmony_ci .name = DRV_NAME, 2318c2ecf20Sopenharmony_ci }, 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cimodule_platform_driver(pata_platform_driver); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cimodule_param(pio_mask, int, 0); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Paul Mundt"); 2398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("low-level driver for platform device ATA"); 2408c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 2418c2ecf20Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 2428c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME); 243