^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Q40 I/O port IDE Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * (c) Richard Zidlicky
^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) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/blkdev.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/ide.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)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/ide.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * Bases of the IDE interfaces
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define Q40IDE_NUM_HWIFS 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define PCIDE_BASE1 0x1f0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define PCIDE_BASE2 0x170
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define PCIDE_BASE3 0x1e8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define PCIDE_BASE4 0x168
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define PCIDE_BASE5 0x1e0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define PCIDE_BASE6 0x160
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static const unsigned long pcide_bases[Q40IDE_NUM_HWIFS] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) PCIDE_BASE1, PCIDE_BASE2, /* PCIDE_BASE3, PCIDE_BASE4 , PCIDE_BASE5,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) PCIDE_BASE6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static int q40ide_default_irq(unsigned long base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) switch (base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) case 0x1f0: return 14;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) case 0x170: return 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) case 0x1e8: return 11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * Addresses are pretranslated for Q40 ISA access.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, int irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) memset(hw, 0, sizeof(*hw));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* BIG FAT WARNING:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) assumption: only DATA port is ever used in 16 bit mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) hw->io_ports.data_addr = Q40_ISA_IO_W(base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) hw->io_ports.error_addr = Q40_ISA_IO_B(base + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) hw->io_ports.nsect_addr = Q40_ISA_IO_B(base + 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) hw->io_ports.lbal_addr = Q40_ISA_IO_B(base + 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) hw->io_ports.lbam_addr = Q40_ISA_IO_B(base + 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) hw->io_ports.lbah_addr = Q40_ISA_IO_B(base + 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) hw->io_ports.device_addr = Q40_ISA_IO_B(base + 6);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) hw->io_ports.status_addr = Q40_ISA_IO_B(base + 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) hw->irq = irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) void *buf, unsigned int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) unsigned long data_addr = drive->hwif->io_ports.data_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) __ide_mm_insw(data_addr, buf, (len + 1) / 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) raw_insw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) static void q40ide_output_data(ide_drive_t *drive, struct ide_cmd *cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) void *buf, unsigned int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned long data_addr = drive->hwif->io_ports.data_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) if (drive->media == ide_disk && cmd && (cmd->tf_flags & IDE_TFLAG_FS)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) __ide_mm_outsw(data_addr, buf, (len + 1) / 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) raw_outsw_swapw((u16 *)data_addr, buf, (len + 1) / 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) /* Q40 has a byte-swapped IDE interface */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static const struct ide_tp_ops q40ide_tp_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .exec_command = ide_exec_command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .read_status = ide_read_status,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .read_altstatus = ide_read_altstatus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .write_devctl = ide_write_devctl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) .dev_select = ide_dev_select,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .tf_load = ide_tf_load,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) .tf_read = ide_tf_read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) .input_data = q40ide_input_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) .output_data = q40ide_output_data,
^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) static const struct ide_port_info q40ide_port_info = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) .tp_ops = &q40ide_tp_ops,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) .irq_flags = IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) .chipset = ide_generic,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) * the static array is needed to have the name reported in /proc/ioports,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) * hwif->name unfortunately isn't available yet
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static const char *q40_ide_names[Q40IDE_NUM_HWIFS]={
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) "ide0", "ide1"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * Probe for Q40 IDE interfaces
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static int __init q40ide_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct ide_hw hw[Q40IDE_NUM_HWIFS], *hws[] = { NULL, NULL };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (!MACH_IS_Q40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) printk(KERN_INFO "ide: Q40 IDE controller\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) for (i = 0; i < Q40IDE_NUM_HWIFS; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) const char *name = q40_ide_names[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) if (!request_region(pcide_bases[i], 8, name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) printk("could not reserve ports %lx-%lx for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) pcide_bases[i],pcide_bases[i]+8,name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (!request_region(pcide_bases[i]+0x206, 1, name)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) printk("could not reserve port %lx for %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) pcide_bases[i]+0x206,name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) release_region(pcide_bases[i], 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) q40_ide_setup_ports(&hw[i], pcide_bases[i],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) q40ide_default_irq(pcide_bases[i]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) hws[i] = &hw[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return ide_host_add(&q40ide_port_info, hws, Q40IDE_NUM_HWIFS, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) module_init(q40ide_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) MODULE_LICENSE("GPL");