18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Atari Falcon IDE Driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Created 12 Jul 1997 by Geert Uytterhoeven 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 78c2ecf20Sopenharmony_ci * License. See the file COPYING in the main directory of this archive for 88c2ecf20Sopenharmony_ci * more details. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/types.h> 138c2ecf20Sopenharmony_ci#include <linux/mm.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 168c2ecf20Sopenharmony_ci#include <linux/ide.h> 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <asm/setup.h> 218c2ecf20Sopenharmony_ci#include <asm/atarihw.h> 228c2ecf20Sopenharmony_ci#include <asm/atariints.h> 238c2ecf20Sopenharmony_ci#include <asm/atari_stdma.h> 248c2ecf20Sopenharmony_ci#include <asm/ide.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define DRV_NAME "falconide" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* 298c2ecf20Sopenharmony_ci * Offsets from base address 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define ATA_HD_CONTROL 0x39 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* 358c2ecf20Sopenharmony_ci * falconide_intr_lock is used to obtain access to the IDE interrupt, 368c2ecf20Sopenharmony_ci * which is shared between several drivers. 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic int falconide_intr_lock; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void falconide_release_lock(void) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci if (falconide_intr_lock == 0) { 448c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: bug\n", __func__); 458c2ecf20Sopenharmony_ci return; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci falconide_intr_lock = 0; 488c2ecf20Sopenharmony_ci stdma_release(); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void falconide_get_lock(irq_handler_t handler, void *data) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci if (falconide_intr_lock == 0) { 548c2ecf20Sopenharmony_ci if (in_interrupt() > 0) 558c2ecf20Sopenharmony_ci panic("Falcon IDE hasn't ST-DMA lock in interrupt"); 568c2ecf20Sopenharmony_ci stdma_lock(handler, data); 578c2ecf20Sopenharmony_ci falconide_intr_lock = 1; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic void falconide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, 628c2ecf20Sopenharmony_ci void *buf, unsigned int len) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci unsigned long data_addr = drive->hwif->io_ports.data_addr; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) { 678c2ecf20Sopenharmony_ci __ide_mm_insw(data_addr, buf, (len + 1) / 2); 688c2ecf20Sopenharmony_ci return; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic void falconide_output_data(ide_drive_t *drive, struct ide_cmd *cmd, 758c2ecf20Sopenharmony_ci void *buf, unsigned int len) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci unsigned long data_addr = drive->hwif->io_ports.data_addr; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) { 808c2ecf20Sopenharmony_ci __ide_mm_outsw(data_addr, buf, (len + 1) / 2); 818c2ecf20Sopenharmony_ci return; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* Atari has a byte-swapped IDE interface */ 888c2ecf20Sopenharmony_cistatic const struct ide_tp_ops falconide_tp_ops = { 898c2ecf20Sopenharmony_ci .exec_command = ide_exec_command, 908c2ecf20Sopenharmony_ci .read_status = ide_read_status, 918c2ecf20Sopenharmony_ci .read_altstatus = ide_read_altstatus, 928c2ecf20Sopenharmony_ci .write_devctl = ide_write_devctl, 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci .dev_select = ide_dev_select, 958c2ecf20Sopenharmony_ci .tf_load = ide_tf_load, 968c2ecf20Sopenharmony_ci .tf_read = ide_tf_read, 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci .input_data = falconide_input_data, 998c2ecf20Sopenharmony_ci .output_data = falconide_output_data, 1008c2ecf20Sopenharmony_ci}; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic const struct ide_port_info falconide_port_info = { 1038c2ecf20Sopenharmony_ci .get_lock = falconide_get_lock, 1048c2ecf20Sopenharmony_ci .release_lock = falconide_release_lock, 1058c2ecf20Sopenharmony_ci .tp_ops = &falconide_tp_ops, 1068c2ecf20Sopenharmony_ci .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE | 1078c2ecf20Sopenharmony_ci IDE_HFLAG_NO_DMA, 1088c2ecf20Sopenharmony_ci .irq_flags = IRQF_SHARED, 1098c2ecf20Sopenharmony_ci .chipset = ide_generic, 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic void __init falconide_setup_ports(struct ide_hw *hw, unsigned long base) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci int i; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci memset(hw, 0, sizeof(*hw)); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci hw->io_ports.data_addr = base; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci for (i = 1; i < 8; i++) 1218c2ecf20Sopenharmony_ci hw->io_ports_array[i] = base + 1 + i * 4; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci hw->io_ports.ctl_addr = base + ATA_HD_CONTROL; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci hw->irq = IRQ_MFP_IDE; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* 1298c2ecf20Sopenharmony_ci * Probe for a Falcon IDE interface 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int __init falconide_init(struct platform_device *pdev) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct resource *res; 1358c2ecf20Sopenharmony_ci struct ide_host *host; 1368c2ecf20Sopenharmony_ci struct ide_hw hw, *hws[] = { &hw }; 1378c2ecf20Sopenharmony_ci unsigned long base; 1388c2ecf20Sopenharmony_ci int rc; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "Atari Falcon IDE controller\n"); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1438c2ecf20Sopenharmony_ci if (!res) 1448c2ecf20Sopenharmony_ci return -ENODEV; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (!devm_request_mem_region(&pdev->dev, res->start, 1478c2ecf20Sopenharmony_ci resource_size(res), DRV_NAME)) { 1488c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "resources busy\n"); 1498c2ecf20Sopenharmony_ci return -EBUSY; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci base = (unsigned long)res->start; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci falconide_setup_ports(&hw, base); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci host = ide_host_alloc(&falconide_port_info, hws, 1); 1578c2ecf20Sopenharmony_ci if (host == NULL) { 1588c2ecf20Sopenharmony_ci rc = -ENOMEM; 1598c2ecf20Sopenharmony_ci goto err; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci falconide_get_lock(NULL, NULL); 1638c2ecf20Sopenharmony_ci rc = ide_host_register(host, &falconide_port_info, hws); 1648c2ecf20Sopenharmony_ci falconide_release_lock(); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci if (rc) 1678c2ecf20Sopenharmony_ci goto err_free; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, host); 1708c2ecf20Sopenharmony_ci return 0; 1718c2ecf20Sopenharmony_cierr_free: 1728c2ecf20Sopenharmony_ci ide_host_free(host); 1738c2ecf20Sopenharmony_cierr: 1748c2ecf20Sopenharmony_ci release_mem_region(res->start, resource_size(res)); 1758c2ecf20Sopenharmony_ci return rc; 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_cistatic int falconide_remove(struct platform_device *pdev) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci struct ide_host *host = platform_get_drvdata(pdev); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ide_host_remove(host); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic struct platform_driver ide_falcon_driver = { 1888c2ecf20Sopenharmony_ci .remove = falconide_remove, 1898c2ecf20Sopenharmony_ci .driver = { 1908c2ecf20Sopenharmony_ci .name = "atari-falcon-ide", 1918c2ecf20Sopenharmony_ci }, 1928c2ecf20Sopenharmony_ci}; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cimodule_platform_driver_probe(ide_falcon_driver, falconide_init); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ciMODULE_AUTHOR("Geert Uytterhoeven"); 1978c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("low-level driver for Atari Falcon IDE"); 1988c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1998c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:atari-falcon-ide"); 200