^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Amiga Gayle IDE Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Created 9 Jul 1997 by Geert Uytterhoeven
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * This file is subject to the terms and conditions of the GNU General Public
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * License. See the file COPYING in the main directory of this archive for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/blkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/ide.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/zorro.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/setup.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/amigahw.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <asm/amigaints.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <asm/amigayle.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) * Offsets from one of the above bases
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define GAYLE_CONTROL 0x101a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * These are at different offsets from the base
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define GAYLE_IRQ_4000 0xdd3020 /* MSB = 1, Harddisk is source of */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define GAYLE_IRQ_1200 0xda9000 /* interrupt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * Offset of the secondary port for IDE doublers
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * Note that GAYLE_CONTROL is NOT available then!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define GAYLE_NEXT_PORT 0x1000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define GAYLE_NUM_HWIFS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define GAYLE_NUM_PROBE_HWIFS (ide_doubler ? GAYLE_NUM_HWIFS : \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) GAYLE_NUM_HWIFS-1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define GAYLE_HAS_CONTROL_REG (!ide_doubler)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static bool ide_doubler;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) module_param_named(doubler, ide_doubler, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) MODULE_PARM_DESC(doubler, "enable support for IDE doublers");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * Check and acknowledge the interrupt status
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int gayle_test_irq(ide_hwif_t *hwif)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned char ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) ch = z_readb(hwif->io_ports.irq_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (!(ch & GAYLE_IRQ_IDE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) static void gayle_a1200_clear_irq(ide_drive_t *drive)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) ide_hwif_t *hwif = drive->hwif;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) (void)z_readb(hwif->io_ports.status_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) z_writeb(0x7c, hwif->io_ports.irq_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) unsigned long ctl, unsigned long irq_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) memset(hw, 0, sizeof(*hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) hw->io_ports.data_addr = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) for (i = 1; i < 8; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) hw->io_ports_array[i] = base + 2 + i * 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) hw->io_ports.ctl_addr = ctl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) hw->io_ports.irq_addr = irq_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) hw->irq = IRQ_AMIGA_PORTS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static const struct ide_port_ops gayle_a4000_port_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .test_irq = gayle_test_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static const struct ide_port_ops gayle_a1200_port_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .clear_irq = gayle_a1200_clear_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .test_irq = gayle_test_irq,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) static const struct ide_port_info gayle_port_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) IDE_HFLAG_NO_DMA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) .irq_flags = IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .chipset = ide_generic,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) * Probe for a Gayle IDE interface (and optionally for an IDE doubler)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) static int __init amiga_gayle_ide_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) struct gayle_ide_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) unsigned long base, ctrlport, irqport;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) int error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct ide_port_info d = gayle_port_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct ide_host *host;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (!request_mem_region(res->start, resource_size(res), "IDE"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) pdata = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) pr_info("ide: Gayle IDE controller (A%u style%s)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) pdata->explicit_ack ? 1200 : 4000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) ide_doubler ? ", IDE doubler" : "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) base = (unsigned long)ZTWO_VADDR(pdata->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ctrlport = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) irqport = (unsigned long)ZTWO_VADDR(pdata->irqport);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (pdata->explicit_ack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) d.port_ops = &gayle_a1200_port_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) d.port_ops = &gayle_a4000_port_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++, base += GAYLE_NEXT_PORT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (GAYLE_HAS_CONTROL_REG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) ctrlport = base + GAYLE_CONTROL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) gayle_setup_ports(&hw[i], base, ctrlport, irqport);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) hws[i] = &hw[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) error = ide_host_add(&d, hws, i, &host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) if (error)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) platform_set_drvdata(pdev, host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) release_mem_region(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return error;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) static int __exit amiga_gayle_ide_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct ide_host *host = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) ide_host_remove(host);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) release_mem_region(res->start, resource_size(res));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) static struct platform_driver amiga_gayle_ide_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .remove = __exit_p(amiga_gayle_ide_remove),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .name = "amiga-gayle-ide",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) module_platform_driver_probe(amiga_gayle_ide_driver, amiga_gayle_ide_probe);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) MODULE_ALIAS("platform:amiga-gayle-ide");